2 $Id: acls.c,v 1.3 2009-02-26 14:00:18 franklahm Exp $
3 Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
18 #endif /* HAVE_CONFIG_H */
29 #include <atalk/adouble.h>
30 #include <atalk/afp.h>
31 #include <atalk/util.h>
32 #include <atalk/cnid.h>
33 #include <atalk/logger.h>
34 #include <atalk/uuid.h>
36 #include "directory.h"
42 #include "acl_mappings.h"
45 #define SOLARIS_2_DARWIN 1
46 #define DARWIN_2_SOLARIS 2
48 /********************************************************
49 * Basic and helper funcs
50 ********************************************************/
52 /* Get ACL. Allocates storage as needed. Caller must free.
53 * Returns no of ACEs or -1 on error. */
54 static int get_nfsv4_acl(const char *name, ace_t **retAces)
60 ace_count = acl(name, ACE_GETACLCNT, 0, NULL);
62 LOG(log_error, logtype_afpd, "get_nfsv4_acl: acl(ACE_GETACLCNT) error");
66 aces = malloc(ace_count * sizeof(ace_t));
68 LOG(log_error, logtype_afpd, "get_nfsv4_acl: malloc error");
72 if ( (acl(name, ACE_GETACL, ace_count, aces)) == -1 ) {
73 LOG(log_error, logtype_afpd, "get_nfsv4_acl: acl(ACE_GETACL) error");
78 LOG(log_debug9, logtype_afpd, "get_nfsv4_acl: file: %s -> No. of ACEs: %d", name, ace_count);
85 Takes a users name, uid and primary gid and checks if user is member of any group
86 Returns -1 if no or error, 0 if yes
88 static int check_group(char *name, uid_t uid, gid_t pgid, gid_t path_gid)
96 grp = getgrgid(path_gid);
101 while (grp->gr_mem[i] != NULL) {
102 if ( (strcmp(grp->gr_mem[i], name)) == 0 ) {
103 LOG(log_debug, logtype_afpd, "check_group: requested user:%s is member of: %s", name, grp->gr_name);
113 Remove any trivial ACE "in-place". Returns no of non-trivial ACEs
115 static int strip_trivial_aces(ace_t **saces, int sacecount)
119 ace_t *aces = *saces;
122 /* Count non-trivial ACEs */
123 for (i=0; i < sacecount; ) {
124 if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
128 /* malloc buffer for new ACL */
129 if ((new_aces = malloc(nontrivaces * sizeof(ace_t))) == NULL) {
130 LOG(log_error, logtype_afpd, "strip_trivial_aces: malloc %s", strerror(errno));
134 /* Copy non-trivial ACEs */
135 for (i=0, j=0; i < sacecount; ) {
136 if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
137 memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
146 LOG(log_debug7, logtype_afpd, "strip_trivial_aces: non-trivial ACEs: %d", nontrivaces);
152 Remove non-trivial ACEs "in-place". Returns no of trivial ACEs.
154 static int strip_nontrivial_aces(ace_t **saces, int sacecount)
158 ace_t *aces = *saces;
161 /* Count trivial ACEs */
162 for (i=0; i < sacecount; ) {
163 if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
167 /* malloc buffer for new ACL */
168 if ((new_aces = malloc(trivaces * sizeof(ace_t))) == NULL) {
169 LOG(log_error, logtype_afpd, "strip_nontrivial_aces: malloc %s", strerror(errno));
173 /* Copy trivial ACEs */
174 for (i=0, j=0; i < sacecount; ) {
175 if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
176 memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
185 LOG(log_debug7, logtype_afpd, "strip_nontrivial_aces: trivial ACEs: %d", trivaces);
193 static ace_t *concat_aces(ace_t *aces1, int ace1count, ace_t *aces2, int ace2count)
198 /* malloc buffer for new ACL */
199 if ((new_aces = malloc((ace1count + ace2count) * sizeof(ace_t))) == NULL) {
200 LOG(log_error, logtype_afpd, "combine_aces: malloc %s", strerror(errno));
204 /* Copy ACEs from buf1 */
205 for (i=0; i < ace1count; ) {
206 memcpy(&new_aces[i], &aces1[i], sizeof(ace_t));
212 /* Copy ACEs from buf2 */
213 for (i=0; i < ace2count; ) {
214 memcpy(&new_aces[j], &aces2[i], sizeof(ace_t));
223 Maps ACE array from Solaris to Darwin. Darwin ACEs are stored in network byte order.
224 Return numer of mapped ACEs or -1 on error.
225 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
227 static int map_aces_solaris_to_darwin(ace_t *aces, darwin_ace_t *darwin_aces, int ace_count)
232 struct passwd *pwd = NULL;
233 struct group *grp = NULL;
235 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing %d ACES", ace_count);
238 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing ACE No. %d", ace_count + 1);
239 /* if its a ACE resulting from nfsv4 mode mapping, discard it */
240 if (aces->a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
241 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: trivial ACE");
246 if ( ! (aces->a_flags & ACE_IDENTIFIER_GROUP) ) {
248 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found user ACE with uid: %d", aces->a_who);
249 pwd = getpwuid(aces->a_who);
251 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getpwuid error: %s", strerror(errno));
254 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: uid: %d -> name: %s", aces->a_who, pwd->pw_name);
255 if ( (getuuidfromname(pwd->pw_name, UUID_USER, darwin_aces->darwin_ace_uuid)) != 0) {
256 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
260 /* its a group ace */
261 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found group ACE with gid: %d", aces->a_who);
262 grp = getgrgid(aces->a_who);
264 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getgrgid error: %s", strerror(errno));
267 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: gid: %d -> name: %s", aces->a_who, grp->gr_name);
268 if ( (getuuidfromname(grp->gr_name, UUID_GROUP, darwin_aces->darwin_ace_uuid)) != 0) {
269 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
275 if (aces->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE)
276 flags = DARWIN_ACE_FLAGS_PERMIT;
277 else if (aces->a_type == ACE_ACCESS_DENIED_ACE_TYPE)
278 flags = DARWIN_ACE_FLAGS_DENY;
279 else { /* unsupported type */
283 for(i=0; nfsv4_to_darwin_flags[i].from != 0; i++) {
284 if (aces->a_flags & nfsv4_to_darwin_flags[i].from)
285 flags |= nfsv4_to_darwin_flags[i].to;
287 darwin_aces->darwin_ace_flags = htonl(flags);
291 for (i=0; nfsv4_to_darwin_rights[i].from != 0; i++) {
292 if (aces->a_access_mask & nfsv4_to_darwin_rights[i].from)
293 rights |= nfsv4_to_darwin_rights[i].to;
295 darwin_aces->darwin_ace_rights = htonl(rights);
306 Maps ACE array from Darwin to Solaris. Darwin ACEs are expected in network byte order.
307 Return numer of mapped ACEs or -1 on error.
308 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
310 int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int ace_count)
312 int i, mapped_aces = 0;
313 uint32_t darwin_ace_flags;
314 uint32_t darwin_ace_rights;
315 uint16_t nfsv4_ace_flags;
316 uint32_t nfsv4_ace_rights;
324 nfsv4_ace_rights = 0;
327 if ( (getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype)) != 0)
329 if (uuidtype == UUID_USER) {
330 pwd = getpwnam(name);
332 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getpwnam: %s", strerror(errno));
335 nfsv4_aces->a_who = pwd->pw_uid;
336 } else { /* hopefully UUID_GROUP*/
337 grp = getgrnam(name);
339 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getgrnam: %s", strerror(errno));
342 nfsv4_aces->a_who = (uid_t)(grp->gr_gid);
343 nfsv4_ace_flags |= ACE_IDENTIFIER_GROUP;
348 /* now type: allow/deny */
349 darwin_ace_flags = ntohl(darwin_aces->darwin_ace_flags);
350 if (darwin_ace_flags & DARWIN_ACE_FLAGS_PERMIT)
351 nfsv4_aces->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
352 else if (darwin_ace_flags & DARWIN_ACE_FLAGS_DENY)
353 nfsv4_aces->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
354 else { /* unsupported type */
359 for(i=0; darwin_to_nfsv4_flags[i].from != 0; i++) {
360 if (darwin_ace_flags & darwin_to_nfsv4_flags[i].from)
361 nfsv4_ace_flags |= darwin_to_nfsv4_flags[i].to;
365 darwin_ace_rights = ntohl(darwin_aces->darwin_ace_rights);
366 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
367 if (darwin_ace_rights & darwin_to_nfsv4_rights[i].from)
368 nfsv4_ace_rights |= darwin_to_nfsv4_rights[i].to;
371 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE flags: Darwin:%08x -> NFSv4:%04x", darwin_ace_flags, nfsv4_ace_flags);
372 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE rights: Darwin:%08x -> NFSv4:%08x", darwin_ace_rights, nfsv4_ace_rights);
374 nfsv4_aces->a_flags = nfsv4_ace_flags;
375 nfsv4_aces->a_access_mask = nfsv4_ace_rights;
385 /********************************************************
387 ********************************************************/
389 /* Map between ACL styles (SOLARIS_2_DARWIN, DARWIN_2_SOLARIS).
390 Reads from 'aces' buffer, writes to 'rbuf' buffer.
391 Caller must provide buffer.
392 Darwin ACEs are read and written in network byte order.
393 Needs to know how many ACEs are in the ACL (ace_count). Ignores trivial ACEs.
394 Return no of mapped ACEs or -1 on error. */
395 static int map_acl(int type, ace_t *nfsv4_aces, darwin_ace_t *buf, int ace_count)
399 LOG(log_debug9, logtype_afpd, "map_acl: BEGIN");
402 case SOLARIS_2_DARWIN:
403 mapped_aces = map_aces_solaris_to_darwin( nfsv4_aces, buf, ace_count);
406 case DARWIN_2_SOLARIS:
407 mapped_aces = map_aces_darwin_to_solaris( buf, nfsv4_aces, ace_count);
415 LOG(log_debug9, logtype_afpd, "map_acl: END");
419 /********************************************************
421 ********************************************************/
424 /* Get ACL from object omitting trivial ACEs. Map to Darwin ACL style and
425 store Darwin ACL at rbuf. Add length of ACL written to rbuf to *rbuflen.
426 Returns 0 on success, -1 on error. */
427 static int get_and_map_acl(char *name, char *rbuf, int *rbuflen)
429 int ace_count, mapped_aces, err;
431 uint32_t *darwin_ace_count = (u_int32_t *)rbuf;
433 LOG(log_debug9, logtype_afpd, "get_and_map_acl: BEGIN");
435 /* Skip length and flags */
440 if ( (ace_count = get_nfsv4_acl(name, &aces)) == -1) {
441 LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get ACL");
445 if ( (mapped_aces = map_acl(SOLARIS_2_DARWIN, aces, (darwin_ace_t *)rbuf, ace_count)) == -1) {
449 LOG(log_debug, logtype_afpd, "get_and_map_acl: mapped %d ACEs", mapped_aces);
452 *darwin_ace_count = htonl(mapped_aces);
453 *rbuflen += sizeof(darwin_acl_header_t) + (mapped_aces * sizeof(darwin_ace_t));
458 LOG(log_debug9, logtype_afpd, "get_and_map_acl: END");
462 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
463 int remove_acl(const char *name)
465 int ret,i, ace_count, trivial_aces, new_aces_count;
466 ace_t *old_aces = NULL;
467 ace_t *new_aces = NULL;
469 LOG(log_debug9, logtype_afpd, "remove_acl: BEGIN");
471 /* Get existing ACL and count trivial ACEs */
472 if ((ace_count = get_nfsv4_acl(name, &old_aces)) == -1)
475 for ( i=0; i < ace_count; i++) {
476 if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))
480 /* malloc buffer for new ACL */
481 if ((new_aces = malloc(trivial_aces * sizeof(ace_t))) == NULL) {
482 LOG(log_error, logtype_afpd, "remove_acl: malloc %s", strerror(errno));
487 /* Now copy the trivial ACEs */
489 for (i=0; i < ace_count; i++) {
490 if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
491 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
496 if ( (acl(name, ACE_SETACL, trivial_aces, new_aces)) == 0)
499 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
500 if (errno == (EACCES | EPERM))
502 else if (errno == ENOENT)
512 LOG(log_debug9, logtype_afpd, "remove_acl: END");
516 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
517 static int remove_acl_vfs(const struct vol *vol,const char *path, int dir)
521 /* Ressource etc. first */
522 if ((ret = vol->vfs->rf_remove_acl(vol, path, dir)) != AFP_OK)
524 /* now the data fork or dir */
525 return (remove_acl(path));
530 - the client sends a complete list of ACEs, not only new ones. So we dont need to do
531 any combination business (one exception being 'kFileSec_Inherit': see next)
532 - client might request that we add inherited ACEs via 'kFileSec_Inherit'.
533 We will store inherited ACEs first, which is Darwins canonical order.
534 - returns AFPerror code
536 static int set_acl_vfs(const struct vol *vol, char *name, int inherit, char *ibuf)
538 int ret, i, nfsv4_ace_count, tocopy_aces_count = 0, new_aces_count = 0, trivial_ace_count = 0;
539 ace_t *old_aces, *new_aces = NULL;
543 LOG(log_debug9, logtype_afpd, "set_acl: BEGIN");
545 /* Get no of ACEs the client put on the wire */
546 ace_count = htonl(*((uint32_t *)ibuf));
547 ibuf += 8; /* skip ACL flags (see acls.h) */
550 /* inherited + trivial ACEs */
551 flags = ACE_INHERITED_ACE | ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
553 /* only trivial ACEs */
554 flags = ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
556 /* Get existing ACL and count ACEs which have to be copied */
557 if ((nfsv4_ace_count = get_nfsv4_acl(name, &old_aces)) == -1)
559 for ( i=0; i < nfsv4_ace_count; i++) {
560 if (old_aces[i].a_flags & flags)
564 /* Now malloc buffer exactly sized to fit all new ACEs */
565 new_aces = malloc( (ace_count + tocopy_aces_count) * sizeof(ace_t) );
566 if (new_aces == NULL) {
567 LOG(log_error, logtype_afpd, "set_acl: malloc %s", strerror(errno));
572 /* Start building new ACL */
574 /* Copy local inherited ACEs. Therefore we have 'Darwin canonical order' (see chmod there):
575 inherited ACEs first. */
577 for (i=0; i < nfsv4_ace_count; i++) {
578 if (old_aces[i].a_flags & ACE_INHERITED_ACE) {
579 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
584 LOG(log_debug7, logtype_afpd, "set_acl: copied %d inherited ACEs", new_aces_count);
586 /* Now the ACEs from the client */
587 ret = map_acl(DARWIN_2_SOLARIS, &new_aces[new_aces_count], (darwin_ace_t *)ibuf, ace_count);
592 new_aces_count += ace_count;
593 LOG(log_debug7, logtype_afpd, "set_acl: mapped %d ACEs from client", ace_count);
595 /* Now copy the trivial ACEs */
596 for (i=0; i < nfsv4_ace_count; i++) {
597 if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
598 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
603 LOG(log_debug7, logtype_afpd, "set_acl: copied %d trivial ACEs", trivial_ace_count);
605 /* Ressourcefork first.
606 Note: for dirs we set the same ACL on the .AppleDouble/.Parent _file_. This
607 might be strange for ACE_DELETE_CHILD and for inheritance flags. */
608 if ( (ret = vol->vfs->rf_acl(vol, name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
609 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
610 if (errno == (EACCES | EPERM))
612 else if (errno == ENOENT)
618 if ( (ret = acl(name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
619 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
620 if (errno == (EACCES | EPERM))
622 else if (errno == ENOENT)
635 LOG(log_debug9, logtype_afpd, "set_acl: END");
640 Checks if a given UUID has requested_rights(type darwin_ace_rights) for path.
641 Note: this gets called frequently and is a good place for optimizations !
643 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
645 int ret, i, ace_count, dir, checkgroup;
646 char *username; /* might be group too */
650 uint32_t requested_rights = 0, allowed_rights = 0, denied_rights = 0;
654 int check_user_trivace = 0, check_group_trivace = 0;
661 LOG(log_debug9, logtype_afpd, "check_access: BEGIN. Request: %08x", requested_darwin_rights);
663 /* Get uid or gid from UUID */
664 if ( (getnamefromuuid(uuid, &username, &uuidtype)) != 0) {
665 LOG(log_error, logtype_afpd, "check_access: error getting name from UUID");
670 if ((stat(path, &st)) != 0) {
671 LOG(log_error, logtype_afpd, "check_access: stat: %s", strerror(errno));
675 dir = S_ISDIR(st.st_mode);
677 if (uuidtype == UUID_USER) {
678 pwd = getpwnam(username);
680 LOG(log_error, logtype_afpd, "check_access: getpwnam: %s", strerror(errno));
687 /* If user is file/dir owner we must check the user trivial ACE */
688 if (uid == st.st_uid) {
689 LOG(log_debug, logtype_afpd, "check_access: user: %s is files owner. Must check trivial user ACE", username);
690 check_user_trivace = 1;
693 /* Now check if requested user is files owning group. If yes we must check the group trivial ACE */
694 if ( (check_group(username, uid, pgid, st.st_gid)) == 0) {
695 LOG(log_debug, logtype_afpd, "check_access: user: %s is in group: %d. Must check trivial group ACE", username, st.st_gid);
696 check_group_trivace = 1;
698 } else { /* hopefully UUID_GROUP*/
699 LOG(log_error, logtype_afpd, "check_access: afp_access for UUID of groups not supported!");
701 grp = getgrnam(username);
703 LOG(log_error, logtype_afpd, "check_access: getgrnam: %s", strerror(errno));
706 if (st.st_gid == grp->gr_gid )
707 check_group_trivace = 1;
711 /* Map requested rights to Solaris style. */
712 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
713 if (requested_darwin_rights & darwin_to_nfsv4_rights[i].from)
714 requested_rights |= darwin_to_nfsv4_rights[i].to;
717 /* Get ACL from file/dir */
718 if ( (ace_count = get_nfsv4_acl(path, &aces)) == -1) {
719 LOG(log_error, logtype_afpd, "check_access: error getting ACEs");
723 /* Now check requested rights */
726 do { /* Loop through ACEs */
728 flags = aces[i].a_flags;
729 type = aces[i].a_type;
730 rights = aces[i].a_access_mask;
732 if (flags & ACE_INHERIT_ONLY_ACE)
735 /* Check if its a group ACE and set checkgroup to 1 if yes */
737 if ( (flags & ACE_IDENTIFIER_GROUP) && !(flags & ACE_GROUP) ) {
738 if ( (check_group(username, uid, pgid, who)) == 0)
744 /* Now the tricky part: decide if ACE effects our user. I'll explain:
745 if its a dedicated (non trivial) ACE for the user
747 if its a ACE for a group we're member of
749 if its a trivial ACE_OWNER ACE and requested UUID is the owner
751 if its a trivial ACE_GROUP ACE and requested UUID is group
753 if its a trivial ACE_EVERYONE ACE
757 ( (who == uid) && !(flags & (ACE_TRIVIAL|ACE_IDENTIFIER_GROUP)) ) ||
759 ( (flags & ACE_OWNER) && check_user_trivace ) ||
760 ( (flags & ACE_GROUP) && check_group_trivace ) ||
761 ( flags & ACE_EVERYONE )
763 /* Found an applicable ACE */
764 if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
765 allowed_rights |= rights;
766 else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
767 /* Only or to denied rights if not previously allowed !! */
768 denied_rights |= ((!allowed_rights) & rights);
770 } while (++i < ace_count);
773 /* Darwin likes to ask for "delete_child" on dir,
774 "write_data" is actually the same, so we add that for dirs */
775 if (dir && (allowed_rights & ACE_WRITE_DATA))
776 allowed_rights |= ACE_DELETE_CHILD;
778 if (requested_rights & denied_rights) {
779 LOG(log_debug, logtype_afpd, "check_access: some requested right was denied:");
781 } else if ((requested_rights & allowed_rights) != requested_rights) {
782 LOG(log_debug, logtype_afpd, "check_access: some requested right wasn't allowed:");
785 LOG(log_debug, logtype_afpd, "check_access: all requested rights are allowed:");
789 LOG(log_debug, logtype_afpd, "check_access: Requested rights: %08x, allowed_rights: %08x, denied_rights: %08x, Result: %d",
790 requested_rights, allowed_rights, denied_rights, ret);
796 LOG(log_debug9, logtype_afpd, "check_access: END");
801 /********************************************************
803 ********************************************************/
805 int afp_access(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf _U_, int *rbuflen)
810 uint32_t did, darwin_ace_rights;
815 LOG(log_debug9, logtype_afpd, "afp_access: BEGIN");
820 memcpy(&vid, ibuf, sizeof( vid ));
822 if (NULL == ( vol = getvolbyvid( vid ))) {
823 LOG(log_error, logtype_afpd, "afp_access: error getting volid:%d", vid);
827 memcpy(&did, ibuf, sizeof( did ));
828 ibuf += sizeof( did );
829 if (NULL == ( dir = dirlookup( vol, did ))) {
830 LOG(log_error, logtype_afpd, "afp_access: error getting did:%d", did);
837 /* Store UUID address */
838 uuid = (uuidp_t)ibuf;
839 ibuf += UUID_BINSIZE;
841 /* Store ACE rights */
842 memcpy(&darwin_ace_rights, ibuf, 4);
843 darwin_ace_rights = ntohl(darwin_ace_rights);
846 /* get full path and handle file/dir subtleties in netatalk code*/
847 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
848 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
851 if (!s_path->st_valid)
852 of_statdir(vol, s_path);
853 if ( s_path->st_errno != 0 ) {
854 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
858 ret = check_acl_access(s_path->u_name, uuid, darwin_ace_rights);
860 LOG(log_debug9, logtype_afpd, "afp_access: END");
864 int afp_getacl(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf _U_, int *rbuflen)
870 uint16_t vid, bitmap;
875 LOG(log_debug9, logtype_afpd, "afp_getacl: BEGIN");
879 memcpy(&vid, ibuf, sizeof( vid ));
881 if (NULL == ( vol = getvolbyvid( vid ))) {
882 LOG(log_error, logtype_afpd, "afp_getacl: error getting volid:%d", vid);
886 memcpy(&did, ibuf, sizeof( did ));
887 ibuf += sizeof( did );
888 if (NULL == ( dir = dirlookup( vol, did ))) {
889 LOG(log_error, logtype_afpd, "afp_getacl: error getting did:%d", did);
893 memcpy(&bitmap, ibuf, sizeof( bitmap ));
894 memcpy(rbuf, ibuf, sizeof( bitmap ));
895 bitmap = ntohs( bitmap );
896 ibuf += sizeof( bitmap );
897 rbuf += sizeof( bitmap );
898 *rbuflen += sizeof( bitmap );
900 /* skip maxreplysize */
903 /* get full path and handle file/dir subtleties in netatalk code*/
904 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
905 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
908 if (!s_path->st_valid)
909 of_statdir(vol, s_path);
910 if ( s_path->st_errno != 0 ) {
911 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
915 /* Shall we return owner UUID ? */
916 if (bitmap & kFileSec_UUID) {
917 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner user UUID");
918 if (NULL == (pw = getpwuid(s_path->st.st_uid)))
920 LOG(log_debug, logtype_afpd, "afp_getacl: got uid: %d, name: %s", s_path->st.st_uid, pw->pw_name);
921 if ((ret = getuuidfromname(pw->pw_name, UUID_USER, rbuf)) != 0)
923 rbuf += UUID_BINSIZE;
924 *rbuflen += UUID_BINSIZE;
927 /* Shall we return group UUID ? */
928 if (bitmap & kFileSec_GRPUUID) {
929 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner group UUID");
930 if (NULL == (gr = getgrgid(s_path->st.st_gid)))
932 LOG(log_debug, logtype_afpd, "afp_getacl: got gid: %d, name: %s", s_path->st.st_gid, gr->gr_name);
933 if ((ret = getuuidfromname(gr->gr_name, UUID_GROUP, rbuf)) != 0)
935 rbuf += UUID_BINSIZE;
936 *rbuflen += UUID_BINSIZE;
939 /* Shall we return ACL ? */
940 if (bitmap & kFileSec_ACL) {
941 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files ACL");
942 get_and_map_acl(s_path->u_name, rbuf, rbuflen);
945 LOG(log_debug9, logtype_afpd, "afp_getacl: END");
949 int afp_setacl(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf _U_, int *rbuflen)
955 uint16_t vid, bitmap;
958 LOG(log_debug9, logtype_afpd, "afp_setacl: BEGIN");
962 memcpy(&vid, ibuf, sizeof( vid ));
964 if (NULL == ( vol = getvolbyvid( vid ))) {
965 LOG(log_error, logtype_afpd, "afp_setacl: error getting volid:%d", vid);
969 memcpy(&did, ibuf, sizeof( did ));
970 ibuf += sizeof( did );
971 if (NULL == ( dir = dirlookup( vol, did ))) {
972 LOG(log_error, logtype_afpd, "afp_setacl: error getting did:%d", did);
976 memcpy(&bitmap, ibuf, sizeof( bitmap ));
977 bitmap = ntohs( bitmap );
978 ibuf += sizeof( bitmap );
980 /* get full path and handle file/dir subtleties in netatalk code*/
981 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
982 LOG(log_error, logtype_afpd, "afp_setacl: cname got an error!");
985 if (!s_path->st_valid)
986 of_statdir(vol, s_path);
987 if ( s_path->st_errno != 0 ) {
988 LOG(log_error, logtype_afpd, "afp_setacl: cant stat");
991 LOG(log_debug, logtype_afpd, "afp_setacl: unixname: %s", s_path->u_name);
994 if ((unsigned long)ibuf & 1)
997 /* Start processing request */
999 /* Change owner: dont even try */
1000 if (bitmap & kFileSec_UUID) {
1001 LOG(log_debug, logtype_afpd, "afp_setacl: change owner request. discarded.");
1002 ret = AFPERR_ACCESS;
1003 ibuf += UUID_BINSIZE;
1006 /* Change group: certain changes might be allowed, so try it. FIXME: not implemented yet. */
1007 if (bitmap & kFileSec_UUID) {
1008 LOG(log_debug, logtype_afpd, "afp_setacl: change group request. not supported this time.");
1010 ibuf += UUID_BINSIZE;
1014 if (bitmap & kFileSec_REMOVEACL) {
1015 LOG(log_debug, logtype_afpd, "afp_setacl: Remove ACL request.");
1016 if ((ret = remove_acl_vfs(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
1017 LOG(log_error, logtype_afpd, "afp_setacl: error from remove_acl");
1021 if (bitmap & kFileSec_ACL) {
1022 LOG(log_debug, logtype_afpd, "afp_setacl: Change ACL request.");
1024 /* Check if its our job to preserve inherited ACEs */
1025 if (bitmap & kFileSec_Inherit)
1026 ret = set_acl_vfs(vol, s_path->u_name, 1, ibuf);
1028 ret = set_acl_vfs(vol, s_path->u_name, 0, ibuf);
1035 LOG(log_debug9, logtype_afpd, "afp_setacl: END");
1040 unix.c/accessmode calls this: map ACL to OS 9 mode
1042 void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma)
1046 int dir, r_ok, w_ok, x_ok;
1048 if ((pw = getpwuid(uid)) == NULL) {
1049 LOG(log_error, logtype_afpd, "acltoownermode: %s", strerror(errno));
1053 /* We need the UUID for check_acl_access */
1054 if ((getuuidfromname(pw->pw_name, UUID_USER, uuid)) != 0)
1057 /* These work for files and dirs */
1058 r_ok = check_acl_access(path, uuid, DARWIN_ACE_READ_DATA);
1059 w_ok = check_acl_access(path, uuid, (DARWIN_ACE_WRITE_DATA|DARWIN_ACE_APPEND_DATA));
1060 x_ok = check_acl_access(path, uuid, DARWIN_ACE_EXECUTE);
1062 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user before: %04o",ma->ma_user);
1064 ma->ma_user |= AR_UREAD;
1066 ma->ma_user |= AR_UWRITE;
1068 ma->ma_user |= AR_USEARCH;
1069 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user after: %04o", ma->ma_user);
1075 We're being called at the end of afp_createdir. We're (hopefully) inside dir
1076 and ".AppleDouble" and ".AppleDouble/.Parent" should have already been created.
1077 We then inherit any explicit ACE from "." to ".AppleDouble" and ".AppleDouble/.Parent".
1078 FIXME: add to VFS layer ?
1080 void addir_inherit_acl(const struct vol *vol)
1082 ace_t *diraces = NULL, *adaces = NULL, *combinedaces = NULL;
1083 int diracecount, adacecount;
1085 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: BEGIN");
1087 /* Check if ACLs are enabled for the volume */
1088 if (vol->v_flags & AFPVOL_ACLS) {
1090 if ((diracecount = get_nfsv4_acl(".", &diraces)) <= 0)
1092 /* Remove any trivial ACE from "." */
1093 if ((diracecount = strip_trivial_aces(&diraces, diracecount)) <= 0)
1097 Inherit to ".AppleDouble"
1100 if ((adacecount = get_nfsv4_acl(".AppleDouble", &adaces)) <= 0)
1102 /* Remove any non-trivial ACE from ".AppleDouble" */
1103 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1107 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1110 /* Now set new acl */
1111 if ((acl(".AppleDouble", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1112 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1117 combinedaces = NULL;
1120 Inherit to ".AppleDouble/.Parent"
1123 if ((adacecount = get_nfsv4_acl(".AppleDouble/.Parent", &adaces)) <= 0)
1125 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1129 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1132 /* Now set new acl */
1133 if ((acl(".AppleDouble/.Parent", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1134 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1140 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: END");