2 $Id: acls.c,v 1.5 2009-10-15 10:43:13 didg 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>
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 Remove any trivial ACE "in-place". Returns no of non-trivial ACEs
84 static int strip_trivial_aces(ace_t **saces, int sacecount)
91 /* Count non-trivial ACEs */
92 for (i=0; i < sacecount; ) {
93 if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
97 /* malloc buffer for new ACL */
98 if ((new_aces = malloc(nontrivaces * sizeof(ace_t))) == NULL) {
99 LOG(log_error, logtype_afpd, "strip_trivial_aces: malloc %s", strerror(errno));
103 /* Copy non-trivial ACEs */
104 for (i=0, j=0; i < sacecount; ) {
105 if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
106 memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
115 LOG(log_debug7, logtype_afpd, "strip_trivial_aces: non-trivial ACEs: %d", nontrivaces);
121 Remove non-trivial ACEs "in-place". Returns no of trivial ACEs.
123 static int strip_nontrivial_aces(ace_t **saces, int sacecount)
127 ace_t *aces = *saces;
130 /* Count trivial ACEs */
131 for (i=0; i < sacecount; ) {
132 if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
136 /* malloc buffer for new ACL */
137 if ((new_aces = malloc(trivaces * sizeof(ace_t))) == NULL) {
138 LOG(log_error, logtype_afpd, "strip_nontrivial_aces: malloc %s", strerror(errno));
142 /* Copy trivial ACEs */
143 for (i=0, j=0; i < sacecount; ) {
144 if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
145 memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
154 LOG(log_debug7, logtype_afpd, "strip_nontrivial_aces: trivial ACEs: %d", trivaces);
162 static ace_t *concat_aces(ace_t *aces1, int ace1count, ace_t *aces2, int ace2count)
167 /* malloc buffer for new ACL */
168 if ((new_aces = malloc((ace1count + ace2count) * sizeof(ace_t))) == NULL) {
169 LOG(log_error, logtype_afpd, "combine_aces: malloc %s", strerror(errno));
173 /* Copy ACEs from buf1 */
174 for (i=0; i < ace1count; ) {
175 memcpy(&new_aces[i], &aces1[i], sizeof(ace_t));
181 /* Copy ACEs from buf2 */
182 for (i=0; i < ace2count; ) {
183 memcpy(&new_aces[j], &aces2[i], sizeof(ace_t));
192 Maps ACE array from Solaris to Darwin. Darwin ACEs are stored in network byte order.
193 Return numer of mapped ACEs or -1 on error.
194 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
196 static int map_aces_solaris_to_darwin(ace_t *aces, darwin_ace_t *darwin_aces, int ace_count)
201 struct passwd *pwd = NULL;
202 struct group *grp = NULL;
204 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing %d ACES", ace_count);
207 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing ACE No. %d", ace_count + 1);
208 /* if its a ACE resulting from nfsv4 mode mapping, discard it */
209 if (aces->a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
210 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: trivial ACE");
215 if ( ! (aces->a_flags & ACE_IDENTIFIER_GROUP) ) {
217 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found user ACE with uid: %d", aces->a_who);
218 pwd = getpwuid(aces->a_who);
220 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getpwuid error: %s", strerror(errno));
223 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: uid: %d -> name: %s", aces->a_who, pwd->pw_name);
224 if ( (getuuidfromname(pwd->pw_name, UUID_USER, darwin_aces->darwin_ace_uuid)) != 0) {
225 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
229 /* its a group ace */
230 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found group ACE with gid: %d", aces->a_who);
231 grp = getgrgid(aces->a_who);
233 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getgrgid error: %s", strerror(errno));
236 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: gid: %d -> name: %s", aces->a_who, grp->gr_name);
237 if ( (getuuidfromname(grp->gr_name, UUID_GROUP, darwin_aces->darwin_ace_uuid)) != 0) {
238 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
244 if (aces->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE)
245 flags = DARWIN_ACE_FLAGS_PERMIT;
246 else if (aces->a_type == ACE_ACCESS_DENIED_ACE_TYPE)
247 flags = DARWIN_ACE_FLAGS_DENY;
248 else { /* unsupported type */
252 for(i=0; nfsv4_to_darwin_flags[i].from != 0; i++) {
253 if (aces->a_flags & nfsv4_to_darwin_flags[i].from)
254 flags |= nfsv4_to_darwin_flags[i].to;
256 darwin_aces->darwin_ace_flags = htonl(flags);
260 for (i=0; nfsv4_to_darwin_rights[i].from != 0; i++) {
261 if (aces->a_access_mask & nfsv4_to_darwin_rights[i].from)
262 rights |= nfsv4_to_darwin_rights[i].to;
264 darwin_aces->darwin_ace_rights = htonl(rights);
275 Maps ACE array from Darwin to Solaris. Darwin ACEs are expected in network byte order.
276 Return numer of mapped ACEs or -1 on error.
277 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
279 int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int ace_count)
281 int i, mapped_aces = 0;
282 uint32_t darwin_ace_flags;
283 uint32_t darwin_ace_rights;
284 uint16_t nfsv4_ace_flags;
285 uint32_t nfsv4_ace_rights;
293 nfsv4_ace_rights = 0;
296 if ( (getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype)) != 0)
298 if (uuidtype == UUID_USER) {
299 pwd = getpwnam(name);
301 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getpwnam: %s", strerror(errno));
304 nfsv4_aces->a_who = pwd->pw_uid;
305 } else { /* hopefully UUID_GROUP*/
306 grp = getgrnam(name);
308 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getgrnam: %s", strerror(errno));
311 nfsv4_aces->a_who = (uid_t)(grp->gr_gid);
312 nfsv4_ace_flags |= ACE_IDENTIFIER_GROUP;
317 /* now type: allow/deny */
318 darwin_ace_flags = ntohl(darwin_aces->darwin_ace_flags);
319 if (darwin_ace_flags & DARWIN_ACE_FLAGS_PERMIT)
320 nfsv4_aces->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
321 else if (darwin_ace_flags & DARWIN_ACE_FLAGS_DENY)
322 nfsv4_aces->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
323 else { /* unsupported type */
328 for(i=0; darwin_to_nfsv4_flags[i].from != 0; i++) {
329 if (darwin_ace_flags & darwin_to_nfsv4_flags[i].from)
330 nfsv4_ace_flags |= darwin_to_nfsv4_flags[i].to;
334 darwin_ace_rights = ntohl(darwin_aces->darwin_ace_rights);
335 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
336 if (darwin_ace_rights & darwin_to_nfsv4_rights[i].from)
337 nfsv4_ace_rights |= darwin_to_nfsv4_rights[i].to;
340 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE flags: Darwin:%08x -> NFSv4:%04x", darwin_ace_flags, nfsv4_ace_flags);
341 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE rights: Darwin:%08x -> NFSv4:%08x", darwin_ace_rights, nfsv4_ace_rights);
343 nfsv4_aces->a_flags = nfsv4_ace_flags;
344 nfsv4_aces->a_access_mask = nfsv4_ace_rights;
354 /********************************************************
356 ********************************************************/
358 /* Map between ACL styles (SOLARIS_2_DARWIN, DARWIN_2_SOLARIS).
359 Reads from 'aces' buffer, writes to 'rbuf' buffer.
360 Caller must provide buffer.
361 Darwin ACEs are read and written in network byte order.
362 Needs to know how many ACEs are in the ACL (ace_count). Ignores trivial ACEs.
363 Return no of mapped ACEs or -1 on error. */
364 static int map_acl(int type, ace_t *nfsv4_aces, darwin_ace_t *buf, int ace_count)
368 LOG(log_debug9, logtype_afpd, "map_acl: BEGIN");
371 case SOLARIS_2_DARWIN:
372 mapped_aces = map_aces_solaris_to_darwin( nfsv4_aces, buf, ace_count);
375 case DARWIN_2_SOLARIS:
376 mapped_aces = map_aces_darwin_to_solaris( buf, nfsv4_aces, ace_count);
384 LOG(log_debug9, logtype_afpd, "map_acl: END");
388 /********************************************************
390 ********************************************************/
393 /* Get ACL from object omitting trivial ACEs. Map to Darwin ACL style and
394 store Darwin ACL at rbuf. Add length of ACL written to rbuf to *rbuflen.
395 Returns 0 on success, -1 on error. */
396 static int get_and_map_acl(char *name, char *rbuf, size_t *rbuflen)
398 int ace_count, mapped_aces, err;
400 uint32_t *darwin_ace_count = (u_int32_t *)rbuf;
402 LOG(log_debug9, logtype_afpd, "get_and_map_acl: BEGIN");
404 /* Skip length and flags */
409 if ( (ace_count = get_nfsv4_acl(name, &aces)) == -1) {
410 LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get ACL");
414 if ( (mapped_aces = map_acl(SOLARIS_2_DARWIN, aces, (darwin_ace_t *)rbuf, ace_count)) == -1) {
418 LOG(log_debug, logtype_afpd, "get_and_map_acl: mapped %d ACEs", mapped_aces);
421 *darwin_ace_count = htonl(mapped_aces);
422 *rbuflen += sizeof(darwin_acl_header_t) + (mapped_aces * sizeof(darwin_ace_t));
427 LOG(log_debug9, logtype_afpd, "get_and_map_acl: END");
431 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
432 static int remove_acl_vfs(const struct vol *vol,const char *path, int dir)
436 /* Ressource etc. first */
437 if ((ret = vol->vfs->rf_remove_acl(vol, path, dir)) != AFP_OK)
439 /* now the data fork or dir */
440 return (remove_acl(path));
445 - the client sends a complete list of ACEs, not only new ones. So we dont need to do
446 any combination business (one exception being 'kFileSec_Inherit': see next)
447 - client might request that we add inherited ACEs via 'kFileSec_Inherit'.
448 We will store inherited ACEs first, which is Darwins canonical order.
449 - returns AFPerror code
451 static int set_acl_vfs(const struct vol *vol, char *name, int inherit, char *ibuf)
453 int ret, i, nfsv4_ace_count, tocopy_aces_count = 0, new_aces_count = 0, trivial_ace_count = 0;
454 ace_t *old_aces, *new_aces = NULL;
458 LOG(log_debug9, logtype_afpd, "set_acl: BEGIN");
460 /* Get no of ACEs the client put on the wire */
461 ace_count = htonl(*((uint32_t *)ibuf));
462 ibuf += 8; /* skip ACL flags (see acls.h) */
465 /* inherited + trivial ACEs */
466 flags = ACE_INHERITED_ACE | ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
468 /* only trivial ACEs */
469 flags = ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
471 /* Get existing ACL and count ACEs which have to be copied */
472 if ((nfsv4_ace_count = get_nfsv4_acl(name, &old_aces)) == -1)
474 for ( i=0; i < nfsv4_ace_count; i++) {
475 if (old_aces[i].a_flags & flags)
479 /* Now malloc buffer exactly sized to fit all new ACEs */
480 new_aces = malloc( (ace_count + tocopy_aces_count) * sizeof(ace_t) );
481 if (new_aces == NULL) {
482 LOG(log_error, logtype_afpd, "set_acl: malloc %s", strerror(errno));
487 /* Start building new ACL */
489 /* Copy local inherited ACEs. Therefore we have 'Darwin canonical order' (see chmod there):
490 inherited ACEs first. */
492 for (i=0; i < nfsv4_ace_count; i++) {
493 if (old_aces[i].a_flags & ACE_INHERITED_ACE) {
494 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
499 LOG(log_debug7, logtype_afpd, "set_acl: copied %d inherited ACEs", new_aces_count);
501 /* Now the ACEs from the client */
502 ret = map_acl(DARWIN_2_SOLARIS, &new_aces[new_aces_count], (darwin_ace_t *)ibuf, ace_count);
507 new_aces_count += ace_count;
508 LOG(log_debug7, logtype_afpd, "set_acl: mapped %d ACEs from client", ace_count);
510 /* Now copy the trivial ACEs */
511 for (i=0; i < nfsv4_ace_count; i++) {
512 if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
513 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
518 LOG(log_debug7, logtype_afpd, "set_acl: copied %d trivial ACEs", trivial_ace_count);
520 /* Ressourcefork first.
521 Note: for dirs we set the same ACL on the .AppleDouble/.Parent _file_. This
522 might be strange for ACE_DELETE_CHILD and for inheritance flags. */
523 if ( (ret = vol->vfs->rf_acl(vol, name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
524 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
525 if (errno == (EACCES | EPERM))
527 else if (errno == ENOENT)
533 if ( (ret = acl(name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
534 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
535 if (errno == (EACCES | EPERM))
537 else if (errno == ENOENT)
550 LOG(log_debug9, logtype_afpd, "set_acl: END");
555 Checks if a given UUID has requested_rights(type darwin_ace_rights) for path.
556 Note: this gets called frequently and is a good place for optimizations !
558 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
560 int ret, i, ace_count, dir, checkgroup;
561 char *username; /* might be group too */
565 uint32_t requested_rights = 0, allowed_rights = 0, denied_rights = 0;
569 int check_user_trivace = 0, check_group_trivace = 0;
576 LOG(log_debug9, logtype_afpd, "check_access: BEGIN. Request: %08x", requested_darwin_rights);
578 /* Get uid or gid from UUID */
579 if ( (getnamefromuuid(uuid, &username, &uuidtype)) != 0) {
580 LOG(log_error, logtype_afpd, "check_access: error getting name from UUID");
585 if ((stat(path, &st)) != 0) {
586 LOG(log_error, logtype_afpd, "check_access: stat: %s", strerror(errno));
590 dir = S_ISDIR(st.st_mode);
592 if (uuidtype == UUID_USER) {
593 pwd = getpwnam(username);
595 LOG(log_error, logtype_afpd, "check_access: getpwnam: %s", strerror(errno));
602 /* If user is file/dir owner we must check the user trivial ACE */
603 if (uid == st.st_uid) {
604 LOG(log_debug, logtype_afpd, "check_access: user: %s is files owner. Must check trivial user ACE", username);
605 check_user_trivace = 1;
608 /* Now check if requested user is files owning group. If yes we must check the group trivial ACE */
609 if ( (check_group(username, uid, pgid, st.st_gid)) == 0) {
610 LOG(log_debug, logtype_afpd, "check_access: user: %s is in group: %d. Must check trivial group ACE", username, st.st_gid);
611 check_group_trivace = 1;
613 } else { /* hopefully UUID_GROUP*/
614 LOG(log_error, logtype_afpd, "check_access: afp_access for UUID of groups not supported!");
616 grp = getgrnam(username);
618 LOG(log_error, logtype_afpd, "check_access: getgrnam: %s", strerror(errno));
621 if (st.st_gid == grp->gr_gid )
622 check_group_trivace = 1;
626 /* Map requested rights to Solaris style. */
627 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
628 if (requested_darwin_rights & darwin_to_nfsv4_rights[i].from)
629 requested_rights |= darwin_to_nfsv4_rights[i].to;
632 /* Get ACL from file/dir */
633 if ( (ace_count = get_nfsv4_acl(path, &aces)) == -1) {
634 LOG(log_error, logtype_afpd, "check_access: error getting ACEs");
638 /* Now check requested rights */
641 do { /* Loop through ACEs */
643 flags = aces[i].a_flags;
644 type = aces[i].a_type;
645 rights = aces[i].a_access_mask;
647 if (flags & ACE_INHERIT_ONLY_ACE)
650 /* Check if its a group ACE and set checkgroup to 1 if yes */
652 if ( (flags & ACE_IDENTIFIER_GROUP) && !(flags & ACE_GROUP) ) {
653 if ( (check_group(username, uid, pgid, who)) == 0)
659 /* Now the tricky part: decide if ACE effects our user. I'll explain:
660 if its a dedicated (non trivial) ACE for the user
662 if its a ACE for a group we're member of
664 if its a trivial ACE_OWNER ACE and requested UUID is the owner
666 if its a trivial ACE_GROUP ACE and requested UUID is group
668 if its a trivial ACE_EVERYONE ACE
672 ( (who == uid) && !(flags & (ACE_TRIVIAL|ACE_IDENTIFIER_GROUP)) ) ||
674 ( (flags & ACE_OWNER) && check_user_trivace ) ||
675 ( (flags & ACE_GROUP) && check_group_trivace ) ||
676 ( flags & ACE_EVERYONE )
678 /* Found an applicable ACE */
679 if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
680 allowed_rights |= rights;
681 else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
682 /* Only or to denied rights if not previously allowed !! */
683 denied_rights |= ((!allowed_rights) & rights);
685 } while (++i < ace_count);
688 /* Darwin likes to ask for "delete_child" on dir,
689 "write_data" is actually the same, so we add that for dirs */
690 if (dir && (allowed_rights & ACE_WRITE_DATA))
691 allowed_rights |= ACE_DELETE_CHILD;
693 if (requested_rights & denied_rights) {
694 LOG(log_debug, logtype_afpd, "check_access: some requested right was denied:");
696 } else if ((requested_rights & allowed_rights) != requested_rights) {
697 LOG(log_debug, logtype_afpd, "check_access: some requested right wasn't allowed:");
700 LOG(log_debug, logtype_afpd, "check_access: all requested rights are allowed:");
704 LOG(log_debug, logtype_afpd, "check_access: Requested rights: %08x, allowed_rights: %08x, denied_rights: %08x, Result: %d",
705 requested_rights, allowed_rights, denied_rights, ret);
711 LOG(log_debug9, logtype_afpd, "check_access: END");
716 /********************************************************
718 ********************************************************/
720 int afp_access(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
725 uint32_t did, darwin_ace_rights;
730 LOG(log_debug9, logtype_afpd, "afp_access: BEGIN");
735 memcpy(&vid, ibuf, sizeof( vid ));
737 if (NULL == ( vol = getvolbyvid( vid ))) {
738 LOG(log_error, logtype_afpd, "afp_access: error getting volid:%d", vid);
742 memcpy(&did, ibuf, sizeof( did ));
743 ibuf += sizeof( did );
744 if (NULL == ( dir = dirlookup( vol, did ))) {
745 LOG(log_error, logtype_afpd, "afp_access: error getting did:%d", did);
752 /* Store UUID address */
753 uuid = (uuidp_t)ibuf;
754 ibuf += UUID_BINSIZE;
756 /* Store ACE rights */
757 memcpy(&darwin_ace_rights, ibuf, 4);
758 darwin_ace_rights = ntohl(darwin_ace_rights);
761 /* get full path and handle file/dir subtleties in netatalk code*/
762 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
763 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
766 if (!s_path->st_valid)
767 of_statdir(vol, s_path);
768 if ( s_path->st_errno != 0 ) {
769 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
773 ret = check_acl_access(s_path->u_name, uuid, darwin_ace_rights);
775 LOG(log_debug9, logtype_afpd, "afp_access: END");
779 int afp_getacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
785 uint16_t vid, bitmap;
790 LOG(log_debug9, logtype_afpd, "afp_getacl: BEGIN");
794 memcpy(&vid, ibuf, sizeof( vid ));
796 if (NULL == ( vol = getvolbyvid( vid ))) {
797 LOG(log_error, logtype_afpd, "afp_getacl: error getting volid:%d", vid);
801 memcpy(&did, ibuf, sizeof( did ));
802 ibuf += sizeof( did );
803 if (NULL == ( dir = dirlookup( vol, did ))) {
804 LOG(log_error, logtype_afpd, "afp_getacl: error getting did:%d", did);
808 memcpy(&bitmap, ibuf, sizeof( bitmap ));
809 memcpy(rbuf, ibuf, sizeof( bitmap ));
810 bitmap = ntohs( bitmap );
811 ibuf += sizeof( bitmap );
812 rbuf += sizeof( bitmap );
813 *rbuflen += sizeof( bitmap );
815 /* skip maxreplysize */
818 /* get full path and handle file/dir subtleties in netatalk code*/
819 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
820 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
823 if (!s_path->st_valid)
824 of_statdir(vol, s_path);
825 if ( s_path->st_errno != 0 ) {
826 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
830 /* Shall we return owner UUID ? */
831 if (bitmap & kFileSec_UUID) {
832 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner user UUID");
833 if (NULL == (pw = getpwuid(s_path->st.st_uid)))
835 LOG(log_debug, logtype_afpd, "afp_getacl: got uid: %d, name: %s", s_path->st.st_uid, pw->pw_name);
836 if ((ret = getuuidfromname(pw->pw_name, UUID_USER, rbuf)) != 0)
838 rbuf += UUID_BINSIZE;
839 *rbuflen += UUID_BINSIZE;
842 /* Shall we return group UUID ? */
843 if (bitmap & kFileSec_GRPUUID) {
844 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner group UUID");
845 if (NULL == (gr = getgrgid(s_path->st.st_gid)))
847 LOG(log_debug, logtype_afpd, "afp_getacl: got gid: %d, name: %s", s_path->st.st_gid, gr->gr_name);
848 if ((ret = getuuidfromname(gr->gr_name, UUID_GROUP, rbuf)) != 0)
850 rbuf += UUID_BINSIZE;
851 *rbuflen += UUID_BINSIZE;
854 /* Shall we return ACL ? */
855 if (bitmap & kFileSec_ACL) {
856 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files ACL");
857 get_and_map_acl(s_path->u_name, rbuf, rbuflen);
860 LOG(log_debug9, logtype_afpd, "afp_getacl: END");
864 int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
870 uint16_t vid, bitmap;
873 LOG(log_debug9, logtype_afpd, "afp_setacl: BEGIN");
877 memcpy(&vid, ibuf, sizeof( vid ));
879 if (NULL == ( vol = getvolbyvid( vid ))) {
880 LOG(log_error, logtype_afpd, "afp_setacl: error getting volid:%d", vid);
884 memcpy(&did, ibuf, sizeof( did ));
885 ibuf += sizeof( did );
886 if (NULL == ( dir = dirlookup( vol, did ))) {
887 LOG(log_error, logtype_afpd, "afp_setacl: error getting did:%d", did);
891 memcpy(&bitmap, ibuf, sizeof( bitmap ));
892 bitmap = ntohs( bitmap );
893 ibuf += sizeof( bitmap );
895 /* get full path and handle file/dir subtleties in netatalk code*/
896 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
897 LOG(log_error, logtype_afpd, "afp_setacl: cname got an error!");
900 if (!s_path->st_valid)
901 of_statdir(vol, s_path);
902 if ( s_path->st_errno != 0 ) {
903 LOG(log_error, logtype_afpd, "afp_setacl: cant stat");
906 LOG(log_debug, logtype_afpd, "afp_setacl: unixname: %s", s_path->u_name);
909 if ((unsigned long)ibuf & 1)
912 /* Start processing request */
914 /* Change owner: dont even try */
915 if (bitmap & kFileSec_UUID) {
916 LOG(log_debug, logtype_afpd, "afp_setacl: change owner request. discarded.");
918 ibuf += UUID_BINSIZE;
921 /* Change group: certain changes might be allowed, so try it. FIXME: not implemented yet. */
922 if (bitmap & kFileSec_UUID) {
923 LOG(log_debug, logtype_afpd, "afp_setacl: change group request. not supported this time.");
925 ibuf += UUID_BINSIZE;
929 if (bitmap & kFileSec_REMOVEACL) {
930 LOG(log_debug, logtype_afpd, "afp_setacl: Remove ACL request.");
931 if ((ret = remove_acl_vfs(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
932 LOG(log_error, logtype_afpd, "afp_setacl: error from remove_acl");
936 if (bitmap & kFileSec_ACL) {
937 LOG(log_debug, logtype_afpd, "afp_setacl: Change ACL request.");
939 /* Check if its our job to preserve inherited ACEs */
940 if (bitmap & kFileSec_Inherit)
941 ret = set_acl_vfs(vol, s_path->u_name, 1, ibuf);
943 ret = set_acl_vfs(vol, s_path->u_name, 0, ibuf);
950 LOG(log_debug9, logtype_afpd, "afp_setacl: END");
955 unix.c/accessmode calls this: map ACL to OS 9 mode
957 void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma)
961 int dir, r_ok, w_ok, x_ok;
963 if ((pw = getpwuid(uid)) == NULL) {
964 LOG(log_error, logtype_afpd, "acltoownermode: %s", strerror(errno));
968 /* We need the UUID for check_acl_access */
969 if ((getuuidfromname(pw->pw_name, UUID_USER, uuid)) != 0)
972 /* These work for files and dirs */
973 r_ok = check_acl_access(path, uuid, DARWIN_ACE_READ_DATA);
974 w_ok = check_acl_access(path, uuid, (DARWIN_ACE_WRITE_DATA|DARWIN_ACE_APPEND_DATA));
975 x_ok = check_acl_access(path, uuid, DARWIN_ACE_EXECUTE);
977 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user before: %04o",ma->ma_user);
979 ma->ma_user |= AR_UREAD;
981 ma->ma_user |= AR_UWRITE;
983 ma->ma_user |= AR_USEARCH;
984 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user after: %04o", ma->ma_user);
990 We're being called at the end of afp_createdir. We're (hopefully) inside dir
991 and ".AppleDouble" and ".AppleDouble/.Parent" should have already been created.
992 We then inherit any explicit ACE from "." to ".AppleDouble" and ".AppleDouble/.Parent".
993 FIXME: add to VFS layer ?
995 void addir_inherit_acl(const struct vol *vol)
997 ace_t *diraces = NULL, *adaces = NULL, *combinedaces = NULL;
998 int diracecount, adacecount;
1000 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: BEGIN");
1002 /* Check if ACLs are enabled for the volume */
1003 if (vol->v_flags & AFPVOL_ACLS) {
1005 if ((diracecount = get_nfsv4_acl(".", &diraces)) <= 0)
1007 /* Remove any trivial ACE from "." */
1008 if ((diracecount = strip_trivial_aces(&diraces, diracecount)) <= 0)
1012 Inherit to ".AppleDouble"
1015 if ((adacecount = get_nfsv4_acl(".AppleDouble", &adaces)) <= 0)
1017 /* Remove any non-trivial ACE from ".AppleDouble" */
1018 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1022 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1025 /* Now set new acl */
1026 if ((acl(".AppleDouble", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1027 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1032 combinedaces = NULL;
1035 Inherit to ".AppleDouble/.Parent"
1038 if ((adacecount = get_nfsv4_acl(".AppleDouble/.Parent", &adaces)) <= 0)
1040 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1044 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1047 /* Now set new acl */
1048 if ((acl(".AppleDouble/.Parent", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1049 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1055 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: END");