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))) {
732 LOG(log_debug, logtype_afpd, "afp_getacl: local uid: %u", s_path->st.st_uid);
733 localuuid_from_id(rbuf, UUID_USER, s_path->st.st_uid);
735 LOG(log_debug, logtype_afpd, "afp_getacl: got uid: %d, name: %s", s_path->st.st_uid, pw->pw_name);
736 if ((ret = getuuidfromname(pw->pw_name, UUID_USER, rbuf)) != 0)
739 rbuf += UUID_BINSIZE;
740 *rbuflen += UUID_BINSIZE;
743 /* Shall we return group UUID ? */
744 if (bitmap & kFileSec_GRPUUID) {
745 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner group UUID");
746 if (NULL == (gr = getgrgid(s_path->st.st_gid))) {
747 LOG(log_debug, logtype_afpd, "afp_getacl: local gid: %u", s_path->st.st_gid);
748 localuuid_from_id(rbuf, UUID_GROUP, s_path->st.st_gid);
750 LOG(log_debug, logtype_afpd, "afp_getacl: got gid: %d, name: %s", s_path->st.st_gid, gr->gr_name);
751 if ((ret = getuuidfromname(gr->gr_name, UUID_GROUP, rbuf)) != 0)
754 rbuf += UUID_BINSIZE;
755 *rbuflen += UUID_BINSIZE;
758 /* Shall we return ACL ? */
759 if (bitmap & kFileSec_ACL) {
760 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files ACL");
761 get_and_map_acl(s_path->u_name, rbuf, rbuflen);
764 LOG(log_debug9, logtype_afpd, "afp_getacl: END");
768 int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
774 uint16_t vid, bitmap;
777 LOG(log_debug9, logtype_afpd, "afp_setacl: BEGIN");
781 memcpy(&vid, ibuf, sizeof( vid ));
783 if (NULL == ( vol = getvolbyvid( vid ))) {
784 LOG(log_error, logtype_afpd, "afp_setacl: error getting volid:%d", vid);
788 memcpy(&did, ibuf, sizeof( did ));
789 ibuf += sizeof( did );
790 if (NULL == ( dir = dirlookup( vol, did ))) {
791 LOG(log_error, logtype_afpd, "afp_setacl: error getting did:%d", did);
795 memcpy(&bitmap, ibuf, sizeof( bitmap ));
796 bitmap = ntohs( bitmap );
797 ibuf += sizeof( bitmap );
799 /* get full path and handle file/dir subtleties in netatalk code*/
800 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
801 LOG(log_error, logtype_afpd, "afp_setacl: cname got an error!");
804 if (!s_path->st_valid)
805 of_statdir(vol, s_path);
806 if ( s_path->st_errno != 0 ) {
807 LOG(log_error, logtype_afpd, "afp_setacl: cant stat");
810 LOG(log_debug, logtype_afpd, "afp_setacl: unixname: %s", s_path->u_name);
813 if ((unsigned long)ibuf & 1)
816 /* Start processing request */
818 /* Change owner: dont even try */
819 if (bitmap & kFileSec_UUID) {
820 LOG(log_debug, logtype_afpd, "afp_setacl: change owner request. discarded.");
822 ibuf += UUID_BINSIZE;
825 /* Change group: certain changes might be allowed, so try it. FIXME: not implemented yet. */
826 if (bitmap & kFileSec_UUID) {
827 LOG(log_debug, logtype_afpd, "afp_setacl: change group request. not supported this time.");
829 ibuf += UUID_BINSIZE;
833 if (bitmap & kFileSec_REMOVEACL) {
834 LOG(log_debug, logtype_afpd, "afp_setacl: Remove ACL request.");
835 if ((ret = remove_acl_vfs(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
836 LOG(log_error, logtype_afpd, "afp_setacl: error from remove_acl");
840 if (bitmap & kFileSec_ACL) {
841 LOG(log_debug, logtype_afpd, "afp_setacl: Change ACL request.");
843 /* Check if its our job to preserve inherited ACEs */
844 if (bitmap & kFileSec_Inherit)
845 ret = set_acl_vfs(vol, s_path->u_name, 1, ibuf);
847 ret = set_acl_vfs(vol, s_path->u_name, 0, ibuf);
851 LOG(log_warning, logtype_afpd, "afp_setacl(\"%s/%s\"): error",
852 getcwdpath(), s_path->u_name);
857 LOG(log_debug9, logtype_afpd, "afp_setacl: END");
862 unix.c/accessmode calls this: map ACL to OS 9 mode
864 void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma)
868 int dir, r_ok, w_ok, x_ok;
870 if ( ! (AFPobj->options.flags & OPTION_UUID))
873 LOG(log_maxdebug, logtype_afpd, "acltoownermode('%s')", path);
875 if ((pw = getpwuid(uid)) == NULL) {
876 LOG(log_error, logtype_afpd, "acltoownermode: %s", strerror(errno));
880 /* We need the UUID for check_acl_access */
881 if ((getuuidfromname(pw->pw_name, UUID_USER, uuid)) != 0)
884 /* These work for files and dirs */
885 r_ok = check_acl_access(path, uuid, DARWIN_ACE_READ_DATA);
886 w_ok = check_acl_access(path, uuid, (DARWIN_ACE_WRITE_DATA|DARWIN_ACE_APPEND_DATA));
887 x_ok = check_acl_access(path, uuid, DARWIN_ACE_EXECUTE);
889 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user before: %04o",ma->ma_user);
891 ma->ma_user |= AR_UREAD;
893 ma->ma_user |= AR_UWRITE;
895 ma->ma_user |= AR_USEARCH;
896 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user after: %04o", ma->ma_user);
902 We're being called at the end of afp_createdir. We're (hopefully) inside dir
903 and ".AppleDouble" and ".AppleDouble/.Parent" should have already been created.
904 We then inherit any explicit ACE from "." to ".AppleDouble" and ".AppleDouble/.Parent".
905 FIXME: add to VFS layer ?
907 void addir_inherit_acl(const struct vol *vol)
909 ace_t *diraces = NULL, *adaces = NULL, *combinedaces = NULL;
910 int diracecount, adacecount;
912 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: BEGIN");
914 /* Check if ACLs are enabled for the volume */
915 if (vol->v_flags & AFPVOL_ACLS) {
917 if ((diracecount = get_nfsv4_acl(".", &diraces)) <= 0)
919 /* Remove any trivial ACE from "." */
920 if ((diracecount = strip_trivial_aces(&diraces, diracecount)) <= 0)
924 Inherit to ".AppleDouble"
927 if ((adacecount = get_nfsv4_acl(".AppleDouble", &adaces)) <= 0)
929 /* Remove any non-trivial ACE from ".AppleDouble" */
930 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
934 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
937 /* Now set new acl */
938 if ((acl(".AppleDouble", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
939 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
947 Inherit to ".AppleDouble/.Parent"
950 if ((adacecount = get_nfsv4_acl(".AppleDouble/.Parent", &adaces)) <= 0)
952 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
956 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
959 /* Now set new acl */
960 if ((acl(".AppleDouble/.Parent", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
961 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
967 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: END");