2 Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
17 #endif /* HAVE_CONFIG_H */
28 #include <atalk/adouble.h>
29 #include <atalk/vfs.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>
35 #include <atalk/acl.h>
37 #include "directory.h"
43 #include "acl_mappings.h"
46 #define SOLARIS_2_DARWIN 1
47 #define DARWIN_2_SOLARIS 2
49 /********************************************************
50 * Basic and helper funcs
51 ********************************************************/
54 Takes a users name, uid and primary gid and checks if user is member of any group
55 Returns -1 if no or error, 0 if yes
57 static int check_group(char *name, uid_t uid, gid_t pgid, gid_t path_gid)
65 grp = getgrgid(path_gid);
70 while (grp->gr_mem[i] != NULL) {
71 if ( (strcmp(grp->gr_mem[i], name)) == 0 ) {
72 LOG(log_debug, logtype_afpd, "check_group: requested user:%s is member of: %s", name, grp->gr_name);
82 Maps ACE array from Solaris to Darwin. Darwin ACEs are stored in network byte order.
83 Return numer of mapped ACEs or -1 on error.
84 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
86 static int map_aces_solaris_to_darwin(ace_t *aces, darwin_ace_t *darwin_aces, int ace_count)
91 struct passwd *pwd = NULL;
92 struct group *grp = NULL;
94 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing %d ACES", ace_count);
97 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing ACE No. %d", ace_count + 1);
98 /* if its a ACE resulting from nfsv4 mode mapping, discard it */
99 if (aces->a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
100 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: trivial ACE");
105 if ( ! (aces->a_flags & ACE_IDENTIFIER_GROUP) ) {
107 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found user ACE with uid: %d", aces->a_who);
108 pwd = getpwuid(aces->a_who);
110 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getpwuid error: %s", strerror(errno));
113 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: uid: %d -> name: %s", aces->a_who, pwd->pw_name);
114 if ( (getuuidfromname(pwd->pw_name, UUID_USER, darwin_aces->darwin_ace_uuid)) != 0) {
115 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
119 /* its a group ace */
120 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found group ACE with gid: %d", aces->a_who);
121 grp = getgrgid(aces->a_who);
123 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getgrgid error: %s", strerror(errno));
126 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: gid: %d -> name: %s", aces->a_who, grp->gr_name);
127 if ( (getuuidfromname(grp->gr_name, UUID_GROUP, darwin_aces->darwin_ace_uuid)) != 0) {
128 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
134 if (aces->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE)
135 flags = DARWIN_ACE_FLAGS_PERMIT;
136 else if (aces->a_type == ACE_ACCESS_DENIED_ACE_TYPE)
137 flags = DARWIN_ACE_FLAGS_DENY;
138 else { /* unsupported type */
142 for(i=0; nfsv4_to_darwin_flags[i].from != 0; i++) {
143 if (aces->a_flags & nfsv4_to_darwin_flags[i].from)
144 flags |= nfsv4_to_darwin_flags[i].to;
146 darwin_aces->darwin_ace_flags = htonl(flags);
150 for (i=0; nfsv4_to_darwin_rights[i].from != 0; i++) {
151 if (aces->a_access_mask & nfsv4_to_darwin_rights[i].from)
152 rights |= nfsv4_to_darwin_rights[i].to;
154 darwin_aces->darwin_ace_rights = htonl(rights);
165 Maps ACE array from Darwin to Solaris. Darwin ACEs are expected in network byte order.
166 Return numer of mapped ACEs or -1 on error.
167 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
169 int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int ace_count)
171 int i, mapped_aces = 0;
172 uint32_t darwin_ace_flags;
173 uint32_t darwin_ace_rights;
174 uint16_t nfsv4_ace_flags;
175 uint32_t nfsv4_ace_rights;
183 nfsv4_ace_rights = 0;
186 if ( (getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype)) != 0)
188 if (uuidtype == UUID_USER) {
189 pwd = getpwnam(name);
191 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getpwnam: %s", strerror(errno));
195 nfsv4_aces->a_who = pwd->pw_uid;
196 } else { /* hopefully UUID_GROUP*/
197 grp = getgrnam(name);
199 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getgrnam: %s", strerror(errno));
203 nfsv4_aces->a_who = (uid_t)(grp->gr_gid);
204 nfsv4_ace_flags |= ACE_IDENTIFIER_GROUP;
209 /* now type: allow/deny */
210 darwin_ace_flags = ntohl(darwin_aces->darwin_ace_flags);
211 if (darwin_ace_flags & DARWIN_ACE_FLAGS_PERMIT)
212 nfsv4_aces->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
213 else if (darwin_ace_flags & DARWIN_ACE_FLAGS_DENY)
214 nfsv4_aces->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
215 else { /* unsupported type */
220 for(i=0; darwin_to_nfsv4_flags[i].from != 0; i++) {
221 if (darwin_ace_flags & darwin_to_nfsv4_flags[i].from)
222 nfsv4_ace_flags |= darwin_to_nfsv4_flags[i].to;
226 darwin_ace_rights = ntohl(darwin_aces->darwin_ace_rights);
227 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
228 if (darwin_ace_rights & darwin_to_nfsv4_rights[i].from)
229 nfsv4_ace_rights |= darwin_to_nfsv4_rights[i].to;
232 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE flags: Darwin:%08x -> NFSv4:%04x", darwin_ace_flags, nfsv4_ace_flags);
233 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE rights: Darwin:%08x -> NFSv4:%08x", darwin_ace_rights, nfsv4_ace_rights);
235 nfsv4_aces->a_flags = nfsv4_ace_flags;
236 nfsv4_aces->a_access_mask = nfsv4_ace_rights;
246 /********************************************************
248 ********************************************************/
250 /* Map between ACL styles (SOLARIS_2_DARWIN, DARWIN_2_SOLARIS).
251 Reads from 'aces' buffer, writes to 'rbuf' buffer.
252 Caller must provide buffer.
253 Darwin ACEs are read and written in network byte order.
254 Needs to know how many ACEs are in the ACL (ace_count). Ignores trivial ACEs.
255 Return no of mapped ACEs or -1 on error. */
256 static int map_acl(int type, ace_t *nfsv4_aces, darwin_ace_t *buf, int ace_count)
260 LOG(log_debug9, logtype_afpd, "map_acl: BEGIN");
263 case SOLARIS_2_DARWIN:
264 mapped_aces = map_aces_solaris_to_darwin( nfsv4_aces, buf, ace_count);
267 case DARWIN_2_SOLARIS:
268 mapped_aces = map_aces_darwin_to_solaris( buf, nfsv4_aces, ace_count);
276 LOG(log_debug9, logtype_afpd, "map_acl: END");
280 /********************************************************
282 ********************************************************/
285 /* Get ACL from object omitting trivial ACEs. Map to Darwin ACL style and
286 store Darwin ACL at rbuf. Add length of ACL written to rbuf to *rbuflen.
287 Returns 0 on success, -1 on error. */
288 static int get_and_map_acl(char *name, char *rbuf, size_t *rbuflen)
290 int ace_count, mapped_aces, err;
292 uint32_t *darwin_ace_count = (u_int32_t *)rbuf;
294 LOG(log_debug9, logtype_afpd, "get_and_map_acl: BEGIN");
296 /* Skip length and flags */
301 if ( (ace_count = get_nfsv4_acl(name, &aces)) == -1) {
302 LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get ACL");
306 if ( (mapped_aces = map_acl(SOLARIS_2_DARWIN, aces, (darwin_ace_t *)rbuf, ace_count)) == -1) {
310 LOG(log_debug, logtype_afpd, "get_and_map_acl: mapped %d ACEs", mapped_aces);
313 *darwin_ace_count = htonl(mapped_aces);
314 *rbuflen += sizeof(darwin_acl_header_t) + (mapped_aces * sizeof(darwin_ace_t));
319 LOG(log_debug9, logtype_afpd, "get_and_map_acl: END");
323 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
324 static int remove_acl_vfs(const struct vol *vol,const char *path, int dir)
328 /* Ressource etc. first */
329 if ((ret = vol->vfs->vfs_remove_acl(vol, path, dir)) != AFP_OK)
331 /* now the data fork or dir */
332 return (remove_acl(path));
337 - the client sends a complete list of ACEs, not only new ones. So we dont need to do
338 any combination business (one exception being 'kFileSec_Inherit': see next)
339 - client might request that we add inherited ACEs via 'kFileSec_Inherit'.
340 We will store inherited ACEs first, which is Darwins canonical order.
341 - returns AFPerror code
343 static int set_acl_vfs(const struct vol *vol, char *name, int inherit, char *ibuf)
345 int ret, i, nfsv4_ace_count, tocopy_aces_count = 0, new_aces_count = 0, trivial_ace_count = 0;
346 ace_t *old_aces, *new_aces = NULL;
350 LOG(log_debug9, logtype_afpd, "set_acl: BEGIN");
352 /* Get no of ACEs the client put on the wire */
353 ace_count = htonl(*((uint32_t *)ibuf));
354 ibuf += 8; /* skip ACL flags (see acls.h) */
357 /* inherited + trivial ACEs */
358 flags = ACE_INHERITED_ACE | ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
360 /* only trivial ACEs */
361 flags = ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
363 /* Get existing ACL and count ACEs which have to be copied */
364 if ((nfsv4_ace_count = get_nfsv4_acl(name, &old_aces)) == -1)
366 for ( i=0; i < nfsv4_ace_count; i++) {
367 if (old_aces[i].a_flags & flags)
371 /* Now malloc buffer exactly sized to fit all new ACEs */
372 new_aces = malloc( (ace_count + tocopy_aces_count) * sizeof(ace_t) );
373 if (new_aces == NULL) {
374 LOG(log_error, logtype_afpd, "set_acl: malloc %s", strerror(errno));
379 /* Start building new ACL */
381 /* Copy local inherited ACEs. Therefore we have 'Darwin canonical order' (see chmod there):
382 inherited ACEs first. */
384 for (i=0; i < nfsv4_ace_count; i++) {
385 if (old_aces[i].a_flags & ACE_INHERITED_ACE) {
386 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
391 LOG(log_debug7, logtype_afpd, "set_acl: copied %d inherited ACEs", new_aces_count);
393 /* Now the ACEs from the client */
394 ret = map_acl(DARWIN_2_SOLARIS, &new_aces[new_aces_count], (darwin_ace_t *)ibuf, ace_count);
399 new_aces_count += ace_count;
400 LOG(log_debug7, logtype_afpd, "set_acl: mapped %d ACEs from client", ace_count);
402 /* Now copy the trivial ACEs */
403 for (i=0; i < nfsv4_ace_count; i++) {
404 if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
405 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
410 LOG(log_debug7, logtype_afpd, "set_acl: copied %d trivial ACEs", trivial_ace_count);
412 /* Ressourcefork first.
413 Note: for dirs we set the same ACL on the .AppleDouble/.Parent _file_. This
414 might be strange for ACE_DELETE_CHILD and for inheritance flags. */
415 if ( (ret = vol->vfs->vfs_acl(vol, name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
416 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
417 if (errno == (EACCES | EPERM))
419 else if (errno == ENOENT)
425 if ( (ret = acl(name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
426 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
427 if (errno == (EACCES | EPERM))
429 else if (errno == ENOENT)
442 LOG(log_debug9, logtype_afpd, "set_acl: END");
447 Checks if a given UUID has requested_rights(type darwin_ace_rights) for path.
448 Note: this gets called frequently and is a good place for optimizations !
450 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
452 int ret, i, ace_count, dir, checkgroup;
453 char *username = NULL; /* might be group too */
457 uint32_t requested_rights = 0, allowed_rights = 0, denied_rights = 0;
461 int check_user_trivace = 0, check_group_trivace = 0;
468 LOG(log_debug9, logtype_afpd, "check_access: BEGIN. Request: %08x", requested_darwin_rights);
470 /* Get uid or gid from UUID */
471 if ( (getnamefromuuid(uuid, &username, &uuidtype)) != 0) {
472 LOG(log_error, logtype_afpd, "check_access: error getting name from UUID");
477 if ((lstat(path, &st)) != 0) {
478 LOG(log_error, logtype_afpd, "check_access: stat: %s", strerror(errno));
482 dir = S_ISDIR(st.st_mode);
484 if (uuidtype == UUID_USER) {
485 pwd = getpwnam(username);
487 LOG(log_error, logtype_afpd, "check_access: getpwnam: %s", strerror(errno));
494 /* If user is file/dir owner we must check the user trivial ACE */
495 if (uid == st.st_uid) {
496 LOG(log_debug, logtype_afpd, "check_access: user: %s is files owner. Must check trivial user ACE", username);
497 check_user_trivace = 1;
500 /* Now check if requested user is files owning group. If yes we must check the group trivial ACE */
501 if ( (check_group(username, uid, pgid, st.st_gid)) == 0) {
502 LOG(log_debug, logtype_afpd, "check_access: user: %s is in group: %d. Must check trivial group ACE", username, st.st_gid);
503 check_group_trivace = 1;
505 } else { /* hopefully UUID_GROUP*/
506 LOG(log_error, logtype_afpd, "check_access: afp_access for UUID of groups not supported!");
508 grp = getgrnam(username);
510 LOG(log_error, logtype_afpd, "check_access: getgrnam: %s", strerror(errno));
513 if (st.st_gid == grp->gr_gid )
514 check_group_trivace = 1;
518 /* Map requested rights to Solaris style. */
519 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
520 if (requested_darwin_rights & darwin_to_nfsv4_rights[i].from)
521 requested_rights |= darwin_to_nfsv4_rights[i].to;
524 /* Get ACL from file/dir */
525 if ( (ace_count = get_nfsv4_acl(path, &aces)) == -1) {
526 LOG(log_error, logtype_afpd, "check_access: error getting ACEs");
530 if (ace_count == 0) {
531 LOG(log_debug, logtype_afpd, "check_access: 0 ACEs from get_nfsv4_acl");
536 /* Now check requested rights */
539 do { /* Loop through ACEs */
541 flags = aces[i].a_flags;
542 type = aces[i].a_type;
543 rights = aces[i].a_access_mask;
545 if (flags & ACE_INHERIT_ONLY_ACE)
548 /* Check if its a group ACE and set checkgroup to 1 if yes */
550 if ( (flags & ACE_IDENTIFIER_GROUP) && !(flags & ACE_GROUP) ) {
551 if ( (check_group(username, uid, pgid, who)) == 0)
557 /* Now the tricky part: decide if ACE effects our user. I'll explain:
558 if its a dedicated (non trivial) ACE for the user
560 if its a ACE for a group we're member of
562 if its a trivial ACE_OWNER ACE and requested UUID is the owner
564 if its a trivial ACE_GROUP ACE and requested UUID is group
566 if its a trivial ACE_EVERYONE ACE
570 ( (who == uid) && !(flags & (ACE_TRIVIAL|ACE_IDENTIFIER_GROUP)) ) ||
572 ( (flags & ACE_OWNER) && check_user_trivace ) ||
573 ( (flags & ACE_GROUP) && check_group_trivace ) ||
574 ( flags & ACE_EVERYONE )
576 /* Found an applicable ACE */
577 if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
578 allowed_rights |= rights;
579 else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
580 /* Only or to denied rights if not previously allowed !! */
581 denied_rights |= ((!allowed_rights) & rights);
583 } while (++i < ace_count);
586 /* Darwin likes to ask for "delete_child" on dir,
587 "write_data" is actually the same, so we add that for dirs */
588 if (dir && (allowed_rights & ACE_WRITE_DATA))
589 allowed_rights |= ACE_DELETE_CHILD;
591 if (requested_rights & denied_rights) {
592 LOG(log_debug, logtype_afpd, "check_access: some requested right was denied:");
594 } else if ((requested_rights & allowed_rights) != requested_rights) {
595 LOG(log_debug, logtype_afpd, "check_access: some requested right wasn't allowed:");
598 LOG(log_debug, logtype_afpd, "check_access: all requested rights are allowed:");
602 LOG(log_debug, logtype_afpd, "check_access: Requested rights: %08x, allowed_rights: %08x, denied_rights: %08x, Result: %d",
603 requested_rights, allowed_rights, denied_rights, ret);
609 LOG(log_debug9, logtype_afpd, "check_access: END");
614 /********************************************************
616 ********************************************************/
618 int afp_access(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
623 uint32_t did, darwin_ace_rights;
628 LOG(log_debug9, logtype_afpd, "afp_access: BEGIN");
633 memcpy(&vid, ibuf, sizeof( vid ));
635 if (NULL == ( vol = getvolbyvid( vid ))) {
636 LOG(log_error, logtype_afpd, "afp_access: error getting volid:%d", vid);
640 memcpy(&did, ibuf, sizeof( did ));
641 ibuf += sizeof( did );
642 if (NULL == ( dir = dirlookup( vol, did ))) {
643 LOG(log_error, logtype_afpd, "afp_access: error getting did:%d", did);
650 /* Store UUID address */
651 uuid = (uuidp_t)ibuf;
652 ibuf += UUID_BINSIZE;
654 /* Store ACE rights */
655 memcpy(&darwin_ace_rights, ibuf, 4);
656 darwin_ace_rights = ntohl(darwin_ace_rights);
659 /* get full path and handle file/dir subtleties in netatalk code*/
660 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
661 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
664 if (!s_path->st_valid)
665 of_statdir(vol, s_path);
666 if ( s_path->st_errno != 0 ) {
667 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
671 ret = check_acl_access(s_path->u_name, uuid, darwin_ace_rights);
673 LOG(log_debug9, logtype_afpd, "afp_access: END");
677 int afp_getacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
683 uint16_t vid, bitmap;
688 LOG(log_debug9, logtype_afpd, "afp_getacl: BEGIN");
692 memcpy(&vid, ibuf, sizeof( vid ));
694 if (NULL == ( vol = getvolbyvid( vid ))) {
695 LOG(log_error, logtype_afpd, "afp_getacl: error getting volid:%d", vid);
699 memcpy(&did, ibuf, sizeof( did ));
700 ibuf += sizeof( did );
701 if (NULL == ( dir = dirlookup( vol, did ))) {
702 LOG(log_error, logtype_afpd, "afp_getacl: error getting did:%d", did);
706 memcpy(&bitmap, ibuf, sizeof( bitmap ));
707 memcpy(rbuf, ibuf, sizeof( bitmap ));
708 bitmap = ntohs( bitmap );
709 ibuf += sizeof( bitmap );
710 rbuf += sizeof( bitmap );
711 *rbuflen += sizeof( bitmap );
713 /* skip maxreplysize */
716 /* get full path and handle file/dir subtleties in netatalk code*/
717 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
718 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
721 if (!s_path->st_valid)
722 of_statdir(vol, s_path);
723 if ( s_path->st_errno != 0 ) {
724 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
728 /* Shall we return owner UUID ? */
729 if (bitmap & kFileSec_UUID) {
730 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner user UUID");
731 if (NULL == (pw = getpwuid(s_path->st.st_uid)))
733 LOG(log_debug, logtype_afpd, "afp_getacl: got uid: %d, name: %s", s_path->st.st_uid, pw->pw_name);
734 if ((ret = getuuidfromname(pw->pw_name, UUID_USER, rbuf)) != 0)
736 rbuf += UUID_BINSIZE;
737 *rbuflen += UUID_BINSIZE;
740 /* Shall we return group UUID ? */
741 if (bitmap & kFileSec_GRPUUID) {
742 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner group UUID");
743 if (NULL == (gr = getgrgid(s_path->st.st_gid)))
745 LOG(log_debug, logtype_afpd, "afp_getacl: got gid: %d, name: %s", s_path->st.st_gid, gr->gr_name);
746 if ((ret = getuuidfromname(gr->gr_name, UUID_GROUP, rbuf)) != 0)
748 rbuf += UUID_BINSIZE;
749 *rbuflen += UUID_BINSIZE;
752 /* Shall we return ACL ? */
753 if (bitmap & kFileSec_ACL) {
754 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files ACL");
755 get_and_map_acl(s_path->u_name, rbuf, rbuflen);
758 LOG(log_debug9, logtype_afpd, "afp_getacl: END");
762 int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
768 uint16_t vid, bitmap;
771 LOG(log_debug9, logtype_afpd, "afp_setacl: BEGIN");
775 memcpy(&vid, ibuf, sizeof( vid ));
777 if (NULL == ( vol = getvolbyvid( vid ))) {
778 LOG(log_error, logtype_afpd, "afp_setacl: error getting volid:%d", vid);
782 memcpy(&did, ibuf, sizeof( did ));
783 ibuf += sizeof( did );
784 if (NULL == ( dir = dirlookup( vol, did ))) {
785 LOG(log_error, logtype_afpd, "afp_setacl: error getting did:%d", did);
789 memcpy(&bitmap, ibuf, sizeof( bitmap ));
790 bitmap = ntohs( bitmap );
791 ibuf += sizeof( bitmap );
793 /* get full path and handle file/dir subtleties in netatalk code*/
794 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
795 LOG(log_error, logtype_afpd, "afp_setacl: cname got an error!");
798 if (!s_path->st_valid)
799 of_statdir(vol, s_path);
800 if ( s_path->st_errno != 0 ) {
801 LOG(log_error, logtype_afpd, "afp_setacl: cant stat");
804 LOG(log_debug, logtype_afpd, "afp_setacl: unixname: %s", s_path->u_name);
807 if ((unsigned long)ibuf & 1)
810 /* Start processing request */
812 /* Change owner: dont even try */
813 if (bitmap & kFileSec_UUID) {
814 LOG(log_debug, logtype_afpd, "afp_setacl: change owner request. discarded.");
816 ibuf += UUID_BINSIZE;
819 /* Change group: certain changes might be allowed, so try it. FIXME: not implemented yet. */
820 if (bitmap & kFileSec_UUID) {
821 LOG(log_debug, logtype_afpd, "afp_setacl: change group request. not supported this time.");
823 ibuf += UUID_BINSIZE;
827 if (bitmap & kFileSec_REMOVEACL) {
828 LOG(log_debug, logtype_afpd, "afp_setacl: Remove ACL request.");
829 if ((ret = remove_acl_vfs(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
830 LOG(log_error, logtype_afpd, "afp_setacl: error from remove_acl");
834 if (bitmap & kFileSec_ACL) {
835 LOG(log_debug, logtype_afpd, "afp_setacl: Change ACL request.");
837 /* Check if its our job to preserve inherited ACEs */
838 if (bitmap & kFileSec_Inherit)
839 ret = set_acl_vfs(vol, s_path->u_name, 1, ibuf);
841 ret = set_acl_vfs(vol, s_path->u_name, 0, ibuf);
845 LOG(log_warning, logtype_afpd, "afp_setacl(\"%s/%s\"): error",
846 getcwdpath(), s_path->u_name);
851 LOG(log_debug9, logtype_afpd, "afp_setacl: END");
856 unix.c/accessmode calls this: map ACL to OS 9 mode
858 void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma)
862 int dir, r_ok, w_ok, x_ok;
864 if ( ! (AFPobj->options.flags & OPTION_UUID))
867 LOG(log_maxdebug, logtype_afpd, "acltoownermode('%s')", path);
869 if ((pw = getpwuid(uid)) == NULL) {
870 LOG(log_error, logtype_afpd, "acltoownermode: %s", strerror(errno));
874 /* We need the UUID for check_acl_access */
875 if ((getuuidfromname(pw->pw_name, UUID_USER, uuid)) != 0)
878 /* These work for files and dirs */
879 r_ok = check_acl_access(path, uuid, DARWIN_ACE_READ_DATA);
880 w_ok = check_acl_access(path, uuid, (DARWIN_ACE_WRITE_DATA|DARWIN_ACE_APPEND_DATA));
881 x_ok = check_acl_access(path, uuid, DARWIN_ACE_EXECUTE);
883 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user before: %04o",ma->ma_user);
885 ma->ma_user |= AR_UREAD;
887 ma->ma_user |= AR_UWRITE;
889 ma->ma_user |= AR_USEARCH;
890 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user after: %04o", ma->ma_user);
896 We're being called at the end of afp_createdir. We're (hopefully) inside dir
897 and ".AppleDouble" and ".AppleDouble/.Parent" should have already been created.
898 We then inherit any explicit ACE from "." to ".AppleDouble" and ".AppleDouble/.Parent".
899 FIXME: add to VFS layer ?
901 void addir_inherit_acl(const struct vol *vol)
903 ace_t *diraces = NULL, *adaces = NULL, *combinedaces = NULL;
904 int diracecount, adacecount;
906 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: BEGIN");
908 /* Check if ACLs are enabled for the volume */
909 if (vol->v_flags & AFPVOL_ACLS) {
911 if ((diracecount = get_nfsv4_acl(".", &diraces)) <= 0)
913 /* Remove any trivial ACE from "." */
914 if ((diracecount = strip_trivial_aces(&diraces, diracecount)) <= 0)
918 Inherit to ".AppleDouble"
921 if ((adacecount = get_nfsv4_acl(".AppleDouble", &adaces)) <= 0)
923 /* Remove any non-trivial ACE from ".AppleDouble" */
924 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
928 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
931 /* Now set new acl */
932 if ((acl(".AppleDouble", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
933 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
941 Inherit to ".AppleDouble/.Parent"
944 if ((adacecount = get_nfsv4_acl(".AppleDouble/.Parent", &adaces)) <= 0)
946 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
950 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
953 /* Now set new acl */
954 if ((acl(".AppleDouble/.Parent", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
955 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
961 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: END");