2 $Id: acls.c,v 1.9 2010-03-08 19:49:59 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 ((lstat(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 if (ace_count == 0) {
640 LOG(log_debug, logtype_afpd, "check_access: 0 ACEs from get_nfsv4_acl");
645 /* Now check requested rights */
648 do { /* Loop through ACEs */
650 flags = aces[i].a_flags;
651 type = aces[i].a_type;
652 rights = aces[i].a_access_mask;
654 if (flags & ACE_INHERIT_ONLY_ACE)
657 /* Check if its a group ACE and set checkgroup to 1 if yes */
659 if ( (flags & ACE_IDENTIFIER_GROUP) && !(flags & ACE_GROUP) ) {
660 if ( (check_group(username, uid, pgid, who)) == 0)
666 /* Now the tricky part: decide if ACE effects our user. I'll explain:
667 if its a dedicated (non trivial) ACE for the user
669 if its a ACE for a group we're member of
671 if its a trivial ACE_OWNER ACE and requested UUID is the owner
673 if its a trivial ACE_GROUP ACE and requested UUID is group
675 if its a trivial ACE_EVERYONE ACE
679 ( (who == uid) && !(flags & (ACE_TRIVIAL|ACE_IDENTIFIER_GROUP)) ) ||
681 ( (flags & ACE_OWNER) && check_user_trivace ) ||
682 ( (flags & ACE_GROUP) && check_group_trivace ) ||
683 ( flags & ACE_EVERYONE )
685 /* Found an applicable ACE */
686 if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
687 allowed_rights |= rights;
688 else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
689 /* Only or to denied rights if not previously allowed !! */
690 denied_rights |= ((!allowed_rights) & rights);
692 } while (++i < ace_count);
695 /* Darwin likes to ask for "delete_child" on dir,
696 "write_data" is actually the same, so we add that for dirs */
697 if (dir && (allowed_rights & ACE_WRITE_DATA))
698 allowed_rights |= ACE_DELETE_CHILD;
700 if (requested_rights & denied_rights) {
701 LOG(log_debug, logtype_afpd, "check_access: some requested right was denied:");
703 } else if ((requested_rights & allowed_rights) != requested_rights) {
704 LOG(log_debug, logtype_afpd, "check_access: some requested right wasn't allowed:");
707 LOG(log_debug, logtype_afpd, "check_access: all requested rights are allowed:");
711 LOG(log_debug, logtype_afpd, "check_access: Requested rights: %08x, allowed_rights: %08x, denied_rights: %08x, Result: %d",
712 requested_rights, allowed_rights, denied_rights, ret);
718 LOG(log_debug9, logtype_afpd, "check_access: END");
723 /********************************************************
725 ********************************************************/
727 int afp_access(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
732 uint32_t did, darwin_ace_rights;
737 LOG(log_debug9, logtype_afpd, "afp_access: BEGIN");
742 memcpy(&vid, ibuf, sizeof( vid ));
744 if (NULL == ( vol = getvolbyvid( vid ))) {
745 LOG(log_error, logtype_afpd, "afp_access: error getting volid:%d", vid);
749 memcpy(&did, ibuf, sizeof( did ));
750 ibuf += sizeof( did );
751 if (NULL == ( dir = dirlookup( vol, did ))) {
752 LOG(log_error, logtype_afpd, "afp_access: error getting did:%d", did);
759 /* Store UUID address */
760 uuid = (uuidp_t)ibuf;
761 ibuf += UUID_BINSIZE;
763 /* Store ACE rights */
764 memcpy(&darwin_ace_rights, ibuf, 4);
765 darwin_ace_rights = ntohl(darwin_ace_rights);
768 /* get full path and handle file/dir subtleties in netatalk code*/
769 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
770 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
773 if (!s_path->st_valid)
774 of_statdir(vol, s_path);
775 if ( s_path->st_errno != 0 ) {
776 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
780 ret = check_acl_access(s_path->u_name, uuid, darwin_ace_rights);
782 LOG(log_debug9, logtype_afpd, "afp_access: END");
786 int afp_getacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
792 uint16_t vid, bitmap;
797 LOG(log_debug9, logtype_afpd, "afp_getacl: BEGIN");
801 memcpy(&vid, ibuf, sizeof( vid ));
803 if (NULL == ( vol = getvolbyvid( vid ))) {
804 LOG(log_error, logtype_afpd, "afp_getacl: error getting volid:%d", vid);
808 memcpy(&did, ibuf, sizeof( did ));
809 ibuf += sizeof( did );
810 if (NULL == ( dir = dirlookup( vol, did ))) {
811 LOG(log_error, logtype_afpd, "afp_getacl: error getting did:%d", did);
815 memcpy(&bitmap, ibuf, sizeof( bitmap ));
816 memcpy(rbuf, ibuf, sizeof( bitmap ));
817 bitmap = ntohs( bitmap );
818 ibuf += sizeof( bitmap );
819 rbuf += sizeof( bitmap );
820 *rbuflen += sizeof( bitmap );
822 /* skip maxreplysize */
825 /* get full path and handle file/dir subtleties in netatalk code*/
826 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
827 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
830 if (!s_path->st_valid)
831 of_statdir(vol, s_path);
832 if ( s_path->st_errno != 0 ) {
833 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
837 /* Shall we return owner UUID ? */
838 if (bitmap & kFileSec_UUID) {
839 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner user UUID");
840 if (NULL == (pw = getpwuid(s_path->st.st_uid)))
842 LOG(log_debug, logtype_afpd, "afp_getacl: got uid: %d, name: %s", s_path->st.st_uid, pw->pw_name);
843 if ((ret = getuuidfromname(pw->pw_name, UUID_USER, rbuf)) != 0)
845 rbuf += UUID_BINSIZE;
846 *rbuflen += UUID_BINSIZE;
849 /* Shall we return group UUID ? */
850 if (bitmap & kFileSec_GRPUUID) {
851 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner group UUID");
852 if (NULL == (gr = getgrgid(s_path->st.st_gid)))
854 LOG(log_debug, logtype_afpd, "afp_getacl: got gid: %d, name: %s", s_path->st.st_gid, gr->gr_name);
855 if ((ret = getuuidfromname(gr->gr_name, UUID_GROUP, rbuf)) != 0)
857 rbuf += UUID_BINSIZE;
858 *rbuflen += UUID_BINSIZE;
861 /* Shall we return ACL ? */
862 if (bitmap & kFileSec_ACL) {
863 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files ACL");
864 get_and_map_acl(s_path->u_name, rbuf, rbuflen);
867 LOG(log_debug9, logtype_afpd, "afp_getacl: END");
871 int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
877 uint16_t vid, bitmap;
880 LOG(log_debug9, logtype_afpd, "afp_setacl: BEGIN");
884 memcpy(&vid, ibuf, sizeof( vid ));
886 if (NULL == ( vol = getvolbyvid( vid ))) {
887 LOG(log_error, logtype_afpd, "afp_setacl: error getting volid:%d", vid);
891 memcpy(&did, ibuf, sizeof( did ));
892 ibuf += sizeof( did );
893 if (NULL == ( dir = dirlookup( vol, did ))) {
894 LOG(log_error, logtype_afpd, "afp_setacl: error getting did:%d", did);
898 memcpy(&bitmap, ibuf, sizeof( bitmap ));
899 bitmap = ntohs( bitmap );
900 ibuf += sizeof( bitmap );
902 /* get full path and handle file/dir subtleties in netatalk code*/
903 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
904 LOG(log_error, logtype_afpd, "afp_setacl: cname got an error!");
907 if (!s_path->st_valid)
908 of_statdir(vol, s_path);
909 if ( s_path->st_errno != 0 ) {
910 LOG(log_error, logtype_afpd, "afp_setacl: cant stat");
913 LOG(log_debug, logtype_afpd, "afp_setacl: unixname: %s", s_path->u_name);
916 if ((unsigned long)ibuf & 1)
919 /* Start processing request */
921 /* Change owner: dont even try */
922 if (bitmap & kFileSec_UUID) {
923 LOG(log_debug, logtype_afpd, "afp_setacl: change owner request. discarded.");
925 ibuf += UUID_BINSIZE;
928 /* Change group: certain changes might be allowed, so try it. FIXME: not implemented yet. */
929 if (bitmap & kFileSec_UUID) {
930 LOG(log_debug, logtype_afpd, "afp_setacl: change group request. not supported this time.");
932 ibuf += UUID_BINSIZE;
936 if (bitmap & kFileSec_REMOVEACL) {
937 LOG(log_debug, logtype_afpd, "afp_setacl: Remove ACL request.");
938 if ((ret = remove_acl_vfs(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
939 LOG(log_error, logtype_afpd, "afp_setacl: error from remove_acl");
943 if (bitmap & kFileSec_ACL) {
944 LOG(log_debug, logtype_afpd, "afp_setacl: Change ACL request.");
946 /* Check if its our job to preserve inherited ACEs */
947 if (bitmap & kFileSec_Inherit)
948 ret = set_acl_vfs(vol, s_path->u_name, 1, ibuf);
950 ret = set_acl_vfs(vol, s_path->u_name, 0, ibuf);
957 LOG(log_debug9, logtype_afpd, "afp_setacl: END");
962 unix.c/accessmode calls this: map ACL to OS 9 mode
964 void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma)
968 int dir, r_ok, w_ok, x_ok;
970 if ( ! (AFPobj->options.flags & OPTION_UUID))
973 LOG(log_maxdebug, logtype_afpd, "acltoownermode('%s')", path);
975 if ((pw = getpwuid(uid)) == NULL) {
976 LOG(log_error, logtype_afpd, "acltoownermode: %s", strerror(errno));
980 /* We need the UUID for check_acl_access */
981 if ((getuuidfromname(pw->pw_name, UUID_USER, uuid)) != 0)
984 /* These work for files and dirs */
985 r_ok = check_acl_access(path, uuid, DARWIN_ACE_READ_DATA);
986 w_ok = check_acl_access(path, uuid, (DARWIN_ACE_WRITE_DATA|DARWIN_ACE_APPEND_DATA));
987 x_ok = check_acl_access(path, uuid, DARWIN_ACE_EXECUTE);
989 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user before: %04o",ma->ma_user);
991 ma->ma_user |= AR_UREAD;
993 ma->ma_user |= AR_UWRITE;
995 ma->ma_user |= AR_USEARCH;
996 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user after: %04o", ma->ma_user);
1002 We're being called at the end of afp_createdir. We're (hopefully) inside dir
1003 and ".AppleDouble" and ".AppleDouble/.Parent" should have already been created.
1004 We then inherit any explicit ACE from "." to ".AppleDouble" and ".AppleDouble/.Parent".
1005 FIXME: add to VFS layer ?
1007 void addir_inherit_acl(const struct vol *vol)
1009 ace_t *diraces = NULL, *adaces = NULL, *combinedaces = NULL;
1010 int diracecount, adacecount;
1012 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: BEGIN");
1014 /* Check if ACLs are enabled for the volume */
1015 if (vol->v_flags & AFPVOL_ACLS) {
1017 if ((diracecount = get_nfsv4_acl(".", &diraces)) <= 0)
1019 /* Remove any trivial ACE from "." */
1020 if ((diracecount = strip_trivial_aces(&diraces, diracecount)) <= 0)
1024 Inherit to ".AppleDouble"
1027 if ((adacecount = get_nfsv4_acl(".AppleDouble", &adaces)) <= 0)
1029 /* Remove any non-trivial ACE from ".AppleDouble" */
1030 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1034 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1037 /* Now set new acl */
1038 if ((acl(".AppleDouble", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1039 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1044 combinedaces = NULL;
1047 Inherit to ".AppleDouble/.Parent"
1050 if ((adacecount = get_nfsv4_acl(".AppleDouble/.Parent", &adaces)) <= 0)
1052 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1056 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1059 /* Now set new acl */
1060 if ((acl(".AppleDouble/.Parent", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1061 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1067 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: END");