2 $Id: acls.c,v 1.7 2009-11-28 13:06:30 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/vfs.h>
31 #include <atalk/afp.h>
32 #include <atalk/util.h>
33 #include <atalk/cnid.h>
34 #include <atalk/logger.h>
35 #include <atalk/uuid.h>
36 #include <atalk/acl.h>
38 #include "directory.h"
44 #include "acl_mappings.h"
47 #define SOLARIS_2_DARWIN 1
48 #define DARWIN_2_SOLARIS 2
50 /********************************************************
51 * Basic and helper funcs
52 ********************************************************/
55 Takes a users name, uid and primary gid and checks if user is member of any group
56 Returns -1 if no or error, 0 if yes
58 static int check_group(char *name, uid_t uid, gid_t pgid, gid_t path_gid)
66 grp = getgrgid(path_gid);
71 while (grp->gr_mem[i] != NULL) {
72 if ( (strcmp(grp->gr_mem[i], name)) == 0 ) {
73 LOG(log_debug, logtype_afpd, "check_group: requested user:%s is member of: %s", name, grp->gr_name);
83 Remove any trivial ACE "in-place". Returns no of non-trivial ACEs
85 static int strip_trivial_aces(ace_t **saces, int sacecount)
92 /* Count non-trivial ACEs */
93 for (i=0; i < sacecount; ) {
94 if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
98 /* malloc buffer for new ACL */
99 if ((new_aces = malloc(nontrivaces * sizeof(ace_t))) == NULL) {
100 LOG(log_error, logtype_afpd, "strip_trivial_aces: malloc %s", strerror(errno));
104 /* Copy non-trivial ACEs */
105 for (i=0, j=0; i < sacecount; ) {
106 if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
107 memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
116 LOG(log_debug7, logtype_afpd, "strip_trivial_aces: non-trivial ACEs: %d", nontrivaces);
122 Remove non-trivial ACEs "in-place". Returns no of trivial ACEs.
124 static int strip_nontrivial_aces(ace_t **saces, int sacecount)
128 ace_t *aces = *saces;
131 /* Count trivial ACEs */
132 for (i=0; i < sacecount; ) {
133 if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
137 /* malloc buffer for new ACL */
138 if ((new_aces = malloc(trivaces * sizeof(ace_t))) == NULL) {
139 LOG(log_error, logtype_afpd, "strip_nontrivial_aces: malloc %s", strerror(errno));
143 /* Copy trivial ACEs */
144 for (i=0, j=0; i < sacecount; ) {
145 if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
146 memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
155 LOG(log_debug7, logtype_afpd, "strip_nontrivial_aces: trivial ACEs: %d", trivaces);
163 static ace_t *concat_aces(ace_t *aces1, int ace1count, ace_t *aces2, int ace2count)
168 /* malloc buffer for new ACL */
169 if ((new_aces = malloc((ace1count + ace2count) * sizeof(ace_t))) == NULL) {
170 LOG(log_error, logtype_afpd, "combine_aces: malloc %s", strerror(errno));
174 /* Copy ACEs from buf1 */
175 for (i=0; i < ace1count; ) {
176 memcpy(&new_aces[i], &aces1[i], sizeof(ace_t));
182 /* Copy ACEs from buf2 */
183 for (i=0; i < ace2count; ) {
184 memcpy(&new_aces[j], &aces2[i], sizeof(ace_t));
193 Maps ACE array from Solaris to Darwin. Darwin ACEs are stored in network byte order.
194 Return numer of mapped ACEs or -1 on error.
195 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
197 static int map_aces_solaris_to_darwin(ace_t *aces, darwin_ace_t *darwin_aces, int ace_count)
202 struct passwd *pwd = NULL;
203 struct group *grp = NULL;
205 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing %d ACES", ace_count);
208 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing ACE No. %d", ace_count + 1);
209 /* if its a ACE resulting from nfsv4 mode mapping, discard it */
210 if (aces->a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
211 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: trivial ACE");
216 if ( ! (aces->a_flags & ACE_IDENTIFIER_GROUP) ) {
218 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found user ACE with uid: %d", aces->a_who);
219 pwd = getpwuid(aces->a_who);
221 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getpwuid error: %s", strerror(errno));
224 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: uid: %d -> name: %s", aces->a_who, pwd->pw_name);
225 if ( (getuuidfromname(pwd->pw_name, UUID_USER, darwin_aces->darwin_ace_uuid)) != 0) {
226 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
230 /* its a group ace */
231 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found group ACE with gid: %d", aces->a_who);
232 grp = getgrgid(aces->a_who);
234 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getgrgid error: %s", strerror(errno));
237 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: gid: %d -> name: %s", aces->a_who, grp->gr_name);
238 if ( (getuuidfromname(grp->gr_name, UUID_GROUP, darwin_aces->darwin_ace_uuid)) != 0) {
239 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
245 if (aces->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE)
246 flags = DARWIN_ACE_FLAGS_PERMIT;
247 else if (aces->a_type == ACE_ACCESS_DENIED_ACE_TYPE)
248 flags = DARWIN_ACE_FLAGS_DENY;
249 else { /* unsupported type */
253 for(i=0; nfsv4_to_darwin_flags[i].from != 0; i++) {
254 if (aces->a_flags & nfsv4_to_darwin_flags[i].from)
255 flags |= nfsv4_to_darwin_flags[i].to;
257 darwin_aces->darwin_ace_flags = htonl(flags);
261 for (i=0; nfsv4_to_darwin_rights[i].from != 0; i++) {
262 if (aces->a_access_mask & nfsv4_to_darwin_rights[i].from)
263 rights |= nfsv4_to_darwin_rights[i].to;
265 darwin_aces->darwin_ace_rights = htonl(rights);
276 Maps ACE array from Darwin to Solaris. Darwin ACEs are expected in network byte order.
277 Return numer of mapped ACEs or -1 on error.
278 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
280 int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int ace_count)
282 int i, mapped_aces = 0;
283 uint32_t darwin_ace_flags;
284 uint32_t darwin_ace_rights;
285 uint16_t nfsv4_ace_flags;
286 uint32_t nfsv4_ace_rights;
294 nfsv4_ace_rights = 0;
297 if ( (getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype)) != 0)
299 if (uuidtype == UUID_USER) {
300 pwd = getpwnam(name);
302 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getpwnam: %s", strerror(errno));
305 nfsv4_aces->a_who = pwd->pw_uid;
306 } else { /* hopefully UUID_GROUP*/
307 grp = getgrnam(name);
309 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getgrnam: %s", strerror(errno));
312 nfsv4_aces->a_who = (uid_t)(grp->gr_gid);
313 nfsv4_ace_flags |= ACE_IDENTIFIER_GROUP;
318 /* now type: allow/deny */
319 darwin_ace_flags = ntohl(darwin_aces->darwin_ace_flags);
320 if (darwin_ace_flags & DARWIN_ACE_FLAGS_PERMIT)
321 nfsv4_aces->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
322 else if (darwin_ace_flags & DARWIN_ACE_FLAGS_DENY)
323 nfsv4_aces->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
324 else { /* unsupported type */
329 for(i=0; darwin_to_nfsv4_flags[i].from != 0; i++) {
330 if (darwin_ace_flags & darwin_to_nfsv4_flags[i].from)
331 nfsv4_ace_flags |= darwin_to_nfsv4_flags[i].to;
335 darwin_ace_rights = ntohl(darwin_aces->darwin_ace_rights);
336 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
337 if (darwin_ace_rights & darwin_to_nfsv4_rights[i].from)
338 nfsv4_ace_rights |= darwin_to_nfsv4_rights[i].to;
341 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE flags: Darwin:%08x -> NFSv4:%04x", darwin_ace_flags, nfsv4_ace_flags);
342 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE rights: Darwin:%08x -> NFSv4:%08x", darwin_ace_rights, nfsv4_ace_rights);
344 nfsv4_aces->a_flags = nfsv4_ace_flags;
345 nfsv4_aces->a_access_mask = nfsv4_ace_rights;
355 /********************************************************
357 ********************************************************/
359 /* Map between ACL styles (SOLARIS_2_DARWIN, DARWIN_2_SOLARIS).
360 Reads from 'aces' buffer, writes to 'rbuf' buffer.
361 Caller must provide buffer.
362 Darwin ACEs are read and written in network byte order.
363 Needs to know how many ACEs are in the ACL (ace_count). Ignores trivial ACEs.
364 Return no of mapped ACEs or -1 on error. */
365 static int map_acl(int type, ace_t *nfsv4_aces, darwin_ace_t *buf, int ace_count)
369 LOG(log_debug9, logtype_afpd, "map_acl: BEGIN");
372 case SOLARIS_2_DARWIN:
373 mapped_aces = map_aces_solaris_to_darwin( nfsv4_aces, buf, ace_count);
376 case DARWIN_2_SOLARIS:
377 mapped_aces = map_aces_darwin_to_solaris( buf, nfsv4_aces, ace_count);
385 LOG(log_debug9, logtype_afpd, "map_acl: END");
389 /********************************************************
391 ********************************************************/
394 /* Get ACL from object omitting trivial ACEs. Map to Darwin ACL style and
395 store Darwin ACL at rbuf. Add length of ACL written to rbuf to *rbuflen.
396 Returns 0 on success, -1 on error. */
397 static int get_and_map_acl(char *name, char *rbuf, size_t *rbuflen)
399 int ace_count, mapped_aces, err;
401 uint32_t *darwin_ace_count = (u_int32_t *)rbuf;
403 LOG(log_debug9, logtype_afpd, "get_and_map_acl: BEGIN");
405 /* Skip length and flags */
410 if ( (ace_count = get_nfsv4_acl(name, &aces)) == -1) {
411 LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get ACL");
415 if ( (mapped_aces = map_acl(SOLARIS_2_DARWIN, aces, (darwin_ace_t *)rbuf, ace_count)) == -1) {
419 LOG(log_debug, logtype_afpd, "get_and_map_acl: mapped %d ACEs", mapped_aces);
422 *darwin_ace_count = htonl(mapped_aces);
423 *rbuflen += sizeof(darwin_acl_header_t) + (mapped_aces * sizeof(darwin_ace_t));
428 LOG(log_debug9, logtype_afpd, "get_and_map_acl: END");
432 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
433 static int remove_acl_vfs(const struct vol *vol,const char *path, int dir)
437 /* Ressource etc. first */
438 if ((ret = vol->vfs->vfs_remove_acl(vol, path, dir)) != AFP_OK)
440 /* now the data fork or dir */
441 return (remove_acl(path));
446 - the client sends a complete list of ACEs, not only new ones. So we dont need to do
447 any combination business (one exception being 'kFileSec_Inherit': see next)
448 - client might request that we add inherited ACEs via 'kFileSec_Inherit'.
449 We will store inherited ACEs first, which is Darwins canonical order.
450 - returns AFPerror code
452 static int set_acl_vfs(const struct vol *vol, char *name, int inherit, char *ibuf)
454 int ret, i, nfsv4_ace_count, tocopy_aces_count = 0, new_aces_count = 0, trivial_ace_count = 0;
455 ace_t *old_aces, *new_aces = NULL;
459 LOG(log_debug9, logtype_afpd, "set_acl: BEGIN");
461 /* Get no of ACEs the client put on the wire */
462 ace_count = htonl(*((uint32_t *)ibuf));
463 ibuf += 8; /* skip ACL flags (see acls.h) */
466 /* inherited + trivial ACEs */
467 flags = ACE_INHERITED_ACE | ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
469 /* only trivial ACEs */
470 flags = ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
472 /* Get existing ACL and count ACEs which have to be copied */
473 if ((nfsv4_ace_count = get_nfsv4_acl(name, &old_aces)) == -1)
475 for ( i=0; i < nfsv4_ace_count; i++) {
476 if (old_aces[i].a_flags & flags)
480 /* Now malloc buffer exactly sized to fit all new ACEs */
481 new_aces = malloc( (ace_count + tocopy_aces_count) * sizeof(ace_t) );
482 if (new_aces == NULL) {
483 LOG(log_error, logtype_afpd, "set_acl: malloc %s", strerror(errno));
488 /* Start building new ACL */
490 /* Copy local inherited ACEs. Therefore we have 'Darwin canonical order' (see chmod there):
491 inherited ACEs first. */
493 for (i=0; i < nfsv4_ace_count; i++) {
494 if (old_aces[i].a_flags & ACE_INHERITED_ACE) {
495 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
500 LOG(log_debug7, logtype_afpd, "set_acl: copied %d inherited ACEs", new_aces_count);
502 /* Now the ACEs from the client */
503 ret = map_acl(DARWIN_2_SOLARIS, &new_aces[new_aces_count], (darwin_ace_t *)ibuf, ace_count);
508 new_aces_count += ace_count;
509 LOG(log_debug7, logtype_afpd, "set_acl: mapped %d ACEs from client", ace_count);
511 /* Now copy the trivial ACEs */
512 for (i=0; i < nfsv4_ace_count; i++) {
513 if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
514 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
519 LOG(log_debug7, logtype_afpd, "set_acl: copied %d trivial ACEs", trivial_ace_count);
521 /* Ressourcefork first.
522 Note: for dirs we set the same ACL on the .AppleDouble/.Parent _file_. This
523 might be strange for ACE_DELETE_CHILD and for inheritance flags. */
524 if ( (ret = vol->vfs->vfs_acl(vol, name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
525 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
526 if (errno == (EACCES | EPERM))
528 else if (errno == ENOENT)
534 if ( (ret = acl(name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
535 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
536 if (errno == (EACCES | EPERM))
538 else if (errno == ENOENT)
551 LOG(log_debug9, logtype_afpd, "set_acl: END");
556 Checks if a given UUID has requested_rights(type darwin_ace_rights) for path.
557 Note: this gets called frequently and is a good place for optimizations !
559 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
561 int ret, i, ace_count, dir, checkgroup;
562 char *username; /* might be group too */
566 uint32_t requested_rights = 0, allowed_rights = 0, denied_rights = 0;
570 int check_user_trivace = 0, check_group_trivace = 0;
577 LOG(log_debug9, logtype_afpd, "check_access: BEGIN. Request: %08x", requested_darwin_rights);
579 /* Get uid or gid from UUID */
580 if ( (getnamefromuuid(uuid, &username, &uuidtype)) != 0) {
581 LOG(log_error, logtype_afpd, "check_access: error getting name from UUID");
586 if ((stat(path, &st)) != 0) {
587 LOG(log_error, logtype_afpd, "check_access: stat: %s", strerror(errno));
591 dir = S_ISDIR(st.st_mode);
593 if (uuidtype == UUID_USER) {
594 pwd = getpwnam(username);
596 LOG(log_error, logtype_afpd, "check_access: getpwnam: %s", strerror(errno));
603 /* If user is file/dir owner we must check the user trivial ACE */
604 if (uid == st.st_uid) {
605 LOG(log_debug, logtype_afpd, "check_access: user: %s is files owner. Must check trivial user ACE", username);
606 check_user_trivace = 1;
609 /* Now check if requested user is files owning group. If yes we must check the group trivial ACE */
610 if ( (check_group(username, uid, pgid, st.st_gid)) == 0) {
611 LOG(log_debug, logtype_afpd, "check_access: user: %s is in group: %d. Must check trivial group ACE", username, st.st_gid);
612 check_group_trivace = 1;
614 } else { /* hopefully UUID_GROUP*/
615 LOG(log_error, logtype_afpd, "check_access: afp_access for UUID of groups not supported!");
617 grp = getgrnam(username);
619 LOG(log_error, logtype_afpd, "check_access: getgrnam: %s", strerror(errno));
622 if (st.st_gid == grp->gr_gid )
623 check_group_trivace = 1;
627 /* Map requested rights to Solaris style. */
628 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
629 if (requested_darwin_rights & darwin_to_nfsv4_rights[i].from)
630 requested_rights |= darwin_to_nfsv4_rights[i].to;
633 /* Get ACL from file/dir */
634 if ( (ace_count = get_nfsv4_acl(path, &aces)) == -1) {
635 LOG(log_error, logtype_afpd, "check_access: error getting ACEs");
639 /* Now check requested rights */
642 do { /* Loop through ACEs */
644 flags = aces[i].a_flags;
645 type = aces[i].a_type;
646 rights = aces[i].a_access_mask;
648 if (flags & ACE_INHERIT_ONLY_ACE)
651 /* Check if its a group ACE and set checkgroup to 1 if yes */
653 if ( (flags & ACE_IDENTIFIER_GROUP) && !(flags & ACE_GROUP) ) {
654 if ( (check_group(username, uid, pgid, who)) == 0)
660 /* Now the tricky part: decide if ACE effects our user. I'll explain:
661 if its a dedicated (non trivial) ACE for the user
663 if its a ACE for a group we're member of
665 if its a trivial ACE_OWNER ACE and requested UUID is the owner
667 if its a trivial ACE_GROUP ACE and requested UUID is group
669 if its a trivial ACE_EVERYONE ACE
673 ( (who == uid) && !(flags & (ACE_TRIVIAL|ACE_IDENTIFIER_GROUP)) ) ||
675 ( (flags & ACE_OWNER) && check_user_trivace ) ||
676 ( (flags & ACE_GROUP) && check_group_trivace ) ||
677 ( flags & ACE_EVERYONE )
679 /* Found an applicable ACE */
680 if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
681 allowed_rights |= rights;
682 else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
683 /* Only or to denied rights if not previously allowed !! */
684 denied_rights |= ((!allowed_rights) & rights);
686 } while (++i < ace_count);
689 /* Darwin likes to ask for "delete_child" on dir,
690 "write_data" is actually the same, so we add that for dirs */
691 if (dir && (allowed_rights & ACE_WRITE_DATA))
692 allowed_rights |= ACE_DELETE_CHILD;
694 if (requested_rights & denied_rights) {
695 LOG(log_debug, logtype_afpd, "check_access: some requested right was denied:");
697 } else if ((requested_rights & allowed_rights) != requested_rights) {
698 LOG(log_debug, logtype_afpd, "check_access: some requested right wasn't allowed:");
701 LOG(log_debug, logtype_afpd, "check_access: all requested rights are allowed:");
705 LOG(log_debug, logtype_afpd, "check_access: Requested rights: %08x, allowed_rights: %08x, denied_rights: %08x, Result: %d",
706 requested_rights, allowed_rights, denied_rights, ret);
712 LOG(log_debug9, logtype_afpd, "check_access: END");
717 /********************************************************
719 ********************************************************/
721 int afp_access(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
726 uint32_t did, darwin_ace_rights;
731 LOG(log_debug9, logtype_afpd, "afp_access: BEGIN");
736 memcpy(&vid, ibuf, sizeof( vid ));
738 if (NULL == ( vol = getvolbyvid( vid ))) {
739 LOG(log_error, logtype_afpd, "afp_access: error getting volid:%d", vid);
743 memcpy(&did, ibuf, sizeof( did ));
744 ibuf += sizeof( did );
745 if (NULL == ( dir = dirlookup( vol, did ))) {
746 LOG(log_error, logtype_afpd, "afp_access: error getting did:%d", did);
753 /* Store UUID address */
754 uuid = (uuidp_t)ibuf;
755 ibuf += UUID_BINSIZE;
757 /* Store ACE rights */
758 memcpy(&darwin_ace_rights, ibuf, 4);
759 darwin_ace_rights = ntohl(darwin_ace_rights);
762 /* get full path and handle file/dir subtleties in netatalk code*/
763 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
764 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
767 if (!s_path->st_valid)
768 of_statdir(vol, s_path);
769 if ( s_path->st_errno != 0 ) {
770 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
774 ret = check_acl_access(s_path->u_name, uuid, darwin_ace_rights);
776 LOG(log_debug9, logtype_afpd, "afp_access: END");
780 int afp_getacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
786 uint16_t vid, bitmap;
791 LOG(log_debug9, logtype_afpd, "afp_getacl: BEGIN");
795 memcpy(&vid, ibuf, sizeof( vid ));
797 if (NULL == ( vol = getvolbyvid( vid ))) {
798 LOG(log_error, logtype_afpd, "afp_getacl: error getting volid:%d", vid);
802 memcpy(&did, ibuf, sizeof( did ));
803 ibuf += sizeof( did );
804 if (NULL == ( dir = dirlookup( vol, did ))) {
805 LOG(log_error, logtype_afpd, "afp_getacl: error getting did:%d", did);
809 memcpy(&bitmap, ibuf, sizeof( bitmap ));
810 memcpy(rbuf, ibuf, sizeof( bitmap ));
811 bitmap = ntohs( bitmap );
812 ibuf += sizeof( bitmap );
813 rbuf += sizeof( bitmap );
814 *rbuflen += sizeof( bitmap );
816 /* skip maxreplysize */
819 /* get full path and handle file/dir subtleties in netatalk code*/
820 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
821 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
824 if (!s_path->st_valid)
825 of_statdir(vol, s_path);
826 if ( s_path->st_errno != 0 ) {
827 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
831 /* Shall we return owner UUID ? */
832 if (bitmap & kFileSec_UUID) {
833 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner user UUID");
834 if (NULL == (pw = getpwuid(s_path->st.st_uid)))
836 LOG(log_debug, logtype_afpd, "afp_getacl: got uid: %d, name: %s", s_path->st.st_uid, pw->pw_name);
837 if ((ret = getuuidfromname(pw->pw_name, UUID_USER, rbuf)) != 0)
839 rbuf += UUID_BINSIZE;
840 *rbuflen += UUID_BINSIZE;
843 /* Shall we return group UUID ? */
844 if (bitmap & kFileSec_GRPUUID) {
845 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner group UUID");
846 if (NULL == (gr = getgrgid(s_path->st.st_gid)))
848 LOG(log_debug, logtype_afpd, "afp_getacl: got gid: %d, name: %s", s_path->st.st_gid, gr->gr_name);
849 if ((ret = getuuidfromname(gr->gr_name, UUID_GROUP, rbuf)) != 0)
851 rbuf += UUID_BINSIZE;
852 *rbuflen += UUID_BINSIZE;
855 /* Shall we return ACL ? */
856 if (bitmap & kFileSec_ACL) {
857 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files ACL");
858 get_and_map_acl(s_path->u_name, rbuf, rbuflen);
861 LOG(log_debug9, logtype_afpd, "afp_getacl: END");
865 int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
871 uint16_t vid, bitmap;
874 LOG(log_debug9, logtype_afpd, "afp_setacl: BEGIN");
878 memcpy(&vid, ibuf, sizeof( vid ));
880 if (NULL == ( vol = getvolbyvid( vid ))) {
881 LOG(log_error, logtype_afpd, "afp_setacl: error getting volid:%d", vid);
885 memcpy(&did, ibuf, sizeof( did ));
886 ibuf += sizeof( did );
887 if (NULL == ( dir = dirlookup( vol, did ))) {
888 LOG(log_error, logtype_afpd, "afp_setacl: error getting did:%d", did);
892 memcpy(&bitmap, ibuf, sizeof( bitmap ));
893 bitmap = ntohs( bitmap );
894 ibuf += sizeof( bitmap );
896 /* get full path and handle file/dir subtleties in netatalk code*/
897 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
898 LOG(log_error, logtype_afpd, "afp_setacl: cname got an error!");
901 if (!s_path->st_valid)
902 of_statdir(vol, s_path);
903 if ( s_path->st_errno != 0 ) {
904 LOG(log_error, logtype_afpd, "afp_setacl: cant stat");
907 LOG(log_debug, logtype_afpd, "afp_setacl: unixname: %s", s_path->u_name);
910 if ((unsigned long)ibuf & 1)
913 /* Start processing request */
915 /* Change owner: dont even try */
916 if (bitmap & kFileSec_UUID) {
917 LOG(log_debug, logtype_afpd, "afp_setacl: change owner request. discarded.");
919 ibuf += UUID_BINSIZE;
922 /* Change group: certain changes might be allowed, so try it. FIXME: not implemented yet. */
923 if (bitmap & kFileSec_UUID) {
924 LOG(log_debug, logtype_afpd, "afp_setacl: change group request. not supported this time.");
926 ibuf += UUID_BINSIZE;
930 if (bitmap & kFileSec_REMOVEACL) {
931 LOG(log_debug, logtype_afpd, "afp_setacl: Remove ACL request.");
932 if ((ret = remove_acl_vfs(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
933 LOG(log_error, logtype_afpd, "afp_setacl: error from remove_acl");
937 if (bitmap & kFileSec_ACL) {
938 LOG(log_debug, logtype_afpd, "afp_setacl: Change ACL request.");
940 /* Check if its our job to preserve inherited ACEs */
941 if (bitmap & kFileSec_Inherit)
942 ret = set_acl_vfs(vol, s_path->u_name, 1, ibuf);
944 ret = set_acl_vfs(vol, s_path->u_name, 0, ibuf);
951 LOG(log_debug9, logtype_afpd, "afp_setacl: END");
956 unix.c/accessmode calls this: map ACL to OS 9 mode
958 void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma)
962 int dir, r_ok, w_ok, x_ok;
964 if ((pw = getpwuid(uid)) == NULL) {
965 LOG(log_error, logtype_afpd, "acltoownermode: %s", strerror(errno));
969 /* We need the UUID for check_acl_access */
970 if ((getuuidfromname(pw->pw_name, UUID_USER, uuid)) != 0)
973 /* These work for files and dirs */
974 r_ok = check_acl_access(path, uuid, DARWIN_ACE_READ_DATA);
975 w_ok = check_acl_access(path, uuid, (DARWIN_ACE_WRITE_DATA|DARWIN_ACE_APPEND_DATA));
976 x_ok = check_acl_access(path, uuid, DARWIN_ACE_EXECUTE);
978 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user before: %04o",ma->ma_user);
980 ma->ma_user |= AR_UREAD;
982 ma->ma_user |= AR_UWRITE;
984 ma->ma_user |= AR_USEARCH;
985 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user after: %04o", ma->ma_user);
991 We're being called at the end of afp_createdir. We're (hopefully) inside dir
992 and ".AppleDouble" and ".AppleDouble/.Parent" should have already been created.
993 We then inherit any explicit ACE from "." to ".AppleDouble" and ".AppleDouble/.Parent".
994 FIXME: add to VFS layer ?
996 void addir_inherit_acl(const struct vol *vol)
998 ace_t *diraces = NULL, *adaces = NULL, *combinedaces = NULL;
999 int diracecount, adacecount;
1001 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: BEGIN");
1003 /* Check if ACLs are enabled for the volume */
1004 if (vol->v_flags & AFPVOL_ACLS) {
1006 if ((diracecount = get_nfsv4_acl(".", &diraces)) <= 0)
1008 /* Remove any trivial ACE from "." */
1009 if ((diracecount = strip_trivial_aces(&diraces, diracecount)) <= 0)
1013 Inherit to ".AppleDouble"
1016 if ((adacecount = get_nfsv4_acl(".AppleDouble", &adaces)) <= 0)
1018 /* Remove any non-trivial ACE from ".AppleDouble" */
1019 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1023 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1026 /* Now set new acl */
1027 if ((acl(".AppleDouble", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1028 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1033 combinedaces = NULL;
1036 Inherit to ".AppleDouble/.Parent"
1039 if ((adacecount = get_nfsv4_acl(".AppleDouble/.Parent", &adaces)) <= 0)
1041 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1045 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1048 /* Now set new acl */
1049 if ((acl(".AppleDouble/.Parent", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1050 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1056 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: END");