2 $Id: acls.c,v 1.2 2009-02-08 11:13:01 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/afp.h>
31 #include <atalk/util.h>
32 #include <atalk/cnid.h>
33 #include <atalk/logger.h>
34 #include <atalk/uuid.h>
36 #include "directory.h"
42 #include "acl_mappings.h"
45 #define SOLARIS_2_DARWIN 1
46 #define DARWIN_2_SOLARIS 2
48 /********************************************************
49 * Basic and helper funcs
50 ********************************************************/
52 static void hexdump(char *o, void *buf, size_t l) {
54 unsigned char *p = (unsigned char *)buf;
57 if ((count % 16) == 0) {
58 len = sprintf(o, "\n%p: ", p);
61 len = sprintf(o, "%02x ", *p);
70 /* Get ACL. Allocates storage as needed. Caller must free.
71 * Returns no of ACEs or -1 on error. */
72 static int get_nfsv4_acl(const char *name, ace_t **retAces)
78 ace_count = acl(name, ACE_GETACLCNT, 0, NULL);
80 LOG(log_error, logtype_afpd, "get_nfsv4_acl: acl(ACE_GETACLCNT) error");
84 aces = malloc(ace_count * sizeof(ace_t));
86 LOG(log_error, logtype_afpd, "get_nfsv4_acl: malloc error");
90 if ( (acl(name, ACE_GETACL, ace_count, aces)) == -1 ) {
91 LOG(log_error, logtype_afpd, "get_nfsv4_acl: acl(ACE_GETACL) error");
96 LOG(log_debug9, logtype_afpd, "get_nfsv4_acl: file: %s -> No. of ACEs: %d", name, ace_count);
103 Takes a users name, uid and primary gid and checks if user is member of any group
104 Returns -1 if no or error, 0 if yes
106 static int check_group(char *name, uid_t uid, gid_t pgid, gid_t path_gid)
111 if (pgid == path_gid)
114 grp = getgrgid(path_gid);
119 while (grp->gr_mem[i] != NULL) {
120 if ( (strcmp(grp->gr_mem[i], name)) == 0 ) {
121 LOG(log_debug, logtype_afpd, "check_group: requested user:%s is member of: %s", name, grp->gr_name);
131 Remove any trivial ACE "in-place". Returns no of non-trivial ACEs
133 static int strip_trivial_aces(ace_t **saces, int sacecount)
137 ace_t *aces = *saces;
140 /* Count non-trivial ACEs */
141 for (i=0; i < sacecount; ) {
142 if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
146 /* malloc buffer for new ACL */
147 if ((new_aces = malloc(nontrivaces * sizeof(ace_t))) == NULL) {
148 LOG(log_error, logtype_afpd, "strip_trivial_aces: malloc %s", strerror(errno));
152 /* Copy non-trivial ACEs */
153 for (i=0, j=0; i < sacecount; ) {
154 if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
155 memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
164 LOG(log_debug7, logtype_afpd, "strip_trivial_aces: non-trivial ACEs: %d", nontrivaces);
170 Remove non-trivial ACEs "in-place". Returns no of trivial ACEs.
172 static int strip_nontrivial_aces(ace_t **saces, int sacecount)
176 ace_t *aces = *saces;
179 /* Count trivial ACEs */
180 for (i=0; i < sacecount; ) {
181 if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
185 /* malloc buffer for new ACL */
186 if ((new_aces = malloc(trivaces * sizeof(ace_t))) == NULL) {
187 LOG(log_error, logtype_afpd, "strip_nontrivial_aces: malloc %s", strerror(errno));
191 /* Copy trivial ACEs */
192 for (i=0, j=0; i < sacecount; ) {
193 if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
194 memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
203 LOG(log_debug7, logtype_afpd, "strip_nontrivial_aces: trivial ACEs: %d", trivaces);
211 static ace_t *concat_aces(ace_t *aces1, int ace1count, ace_t *aces2, int ace2count)
216 /* malloc buffer for new ACL */
217 if ((new_aces = malloc((ace1count + ace2count) * sizeof(ace_t))) == NULL) {
218 LOG(log_error, logtype_afpd, "combine_aces: malloc %s", strerror(errno));
222 /* Copy ACEs from buf1 */
223 for (i=0; i < ace1count; ) {
224 memcpy(&new_aces[i], &aces1[i], sizeof(ace_t));
230 /* Copy ACEs from buf2 */
231 for (i=0; i < ace2count; ) {
232 memcpy(&new_aces[j], &aces2[i], sizeof(ace_t));
241 Maps ACE array from Solaris to Darwin. Darwin ACEs are stored in network byte order.
242 Return numer of mapped ACEs or -1 on error.
243 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
245 static int map_aces_solaris_to_darwin(ace_t *aces, darwin_ace_t *darwin_aces, int ace_count)
250 struct passwd *pwd = NULL;
251 struct group *grp = NULL;
253 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing %d ACES", ace_count);
256 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing ACE No. %d", ace_count + 1);
257 /* if its a ACE resulting from nfsv4 mode mapping, discard it */
258 if (aces->a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
259 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: trivial ACE");
264 if ( ! (aces->a_flags & ACE_IDENTIFIER_GROUP) ) {
266 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found user ACE with uid: %d", aces->a_who);
267 pwd = getpwuid(aces->a_who);
269 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getpwuid error: %s", strerror(errno));
272 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: uid: %d -> name: %s", aces->a_who, pwd->pw_name);
273 if ( (getuuidfromname(pwd->pw_name, UUID_USER, darwin_aces->darwin_ace_uuid)) != 0) {
274 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
278 /* its a group ace */
279 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found group ACE with gid: %d", aces->a_who);
280 grp = getgrgid(aces->a_who);
282 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getgrgid error: %s", strerror(errno));
285 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: gid: %d -> name: %s", aces->a_who, grp->gr_name);
286 if ( (getuuidfromname(grp->gr_name, UUID_GROUP, darwin_aces->darwin_ace_uuid)) != 0) {
287 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
293 if (aces->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE)
294 flags = DARWIN_ACE_FLAGS_PERMIT;
295 else if (aces->a_type == ACE_ACCESS_DENIED_ACE_TYPE)
296 flags = DARWIN_ACE_FLAGS_DENY;
297 else { /* unsupported type */
301 for(i=0; nfsv4_to_darwin_flags[i].from != 0; i++) {
302 if (aces->a_flags & nfsv4_to_darwin_flags[i].from)
303 flags |= nfsv4_to_darwin_flags[i].to;
305 darwin_aces->darwin_ace_flags = htonl(flags);
309 for (i=0; nfsv4_to_darwin_rights[i].from != 0; i++) {
310 if (aces->a_access_mask & nfsv4_to_darwin_rights[i].from)
311 rights |= nfsv4_to_darwin_rights[i].to;
313 darwin_aces->darwin_ace_rights = htonl(rights);
324 Maps ACE array from Darwin to Solaris. Darwin ACEs are expected in network byte order.
325 Return numer of mapped ACEs or -1 on error.
326 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
328 int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int ace_count)
330 int i, mapped_aces = 0;
331 uint32_t darwin_ace_flags;
332 uint32_t darwin_ace_rights;
333 uint16_t nfsv4_ace_flags;
334 uint32_t nfsv4_ace_rights;
342 nfsv4_ace_rights = 0;
345 if ( (getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype)) != 0)
347 if (uuidtype == UUID_USER) {
348 pwd = getpwnam(name);
350 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getpwnam: %s", strerror(errno));
353 nfsv4_aces->a_who = pwd->pw_uid;
354 } else { /* hopefully UUID_GROUP*/
355 grp = getgrnam(name);
357 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getgrnam: %s", strerror(errno));
360 nfsv4_aces->a_who = (uid_t)(grp->gr_gid);
361 nfsv4_ace_flags |= ACE_IDENTIFIER_GROUP;
366 /* now type: allow/deny */
367 darwin_ace_flags = ntohl(darwin_aces->darwin_ace_flags);
368 if (darwin_ace_flags & DARWIN_ACE_FLAGS_PERMIT)
369 nfsv4_aces->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
370 else if (darwin_ace_flags & DARWIN_ACE_FLAGS_DENY)
371 nfsv4_aces->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
372 else { /* unsupported type */
377 for(i=0; darwin_to_nfsv4_flags[i].from != 0; i++) {
378 if (darwin_ace_flags & darwin_to_nfsv4_flags[i].from)
379 nfsv4_ace_flags |= darwin_to_nfsv4_flags[i].to;
383 darwin_ace_rights = ntohl(darwin_aces->darwin_ace_rights);
384 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
385 if (darwin_ace_rights & darwin_to_nfsv4_rights[i].from)
386 nfsv4_ace_rights |= darwin_to_nfsv4_rights[i].to;
389 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE flags: Darwin:%08x -> NFSv4:%04x", darwin_ace_flags, nfsv4_ace_flags);
390 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE rights: Darwin:%08x -> NFSv4:%08x", darwin_ace_rights, nfsv4_ace_rights);
392 nfsv4_aces->a_flags = nfsv4_ace_flags;
393 nfsv4_aces->a_access_mask = nfsv4_ace_rights;
403 /********************************************************
405 ********************************************************/
407 /* Map between ACL styles (SOLARIS_2_DARWIN, DARWIN_2_SOLARIS).
408 Reads from 'aces' buffer, writes to 'rbuf' buffer.
409 Caller must provide buffer.
410 Darwin ACEs are read and written in network byte order.
411 Needs to know how many ACEs are in the ACL (ace_count). Ignores trivial ACEs.
412 Return no of mapped ACEs or -1 on error. */
413 static int map_acl(int type, ace_t *nfsv4_aces, darwin_ace_t *buf, int ace_count)
417 LOG(log_debug9, logtype_afpd, "map_acl: BEGIN");
420 case SOLARIS_2_DARWIN:
421 mapped_aces = map_aces_solaris_to_darwin( nfsv4_aces, buf, ace_count);
424 case DARWIN_2_SOLARIS:
425 mapped_aces = map_aces_darwin_to_solaris( buf, nfsv4_aces, ace_count);
433 LOG(log_debug9, logtype_afpd, "map_acl: END");
437 /********************************************************
439 ********************************************************/
442 /* Get ACL from object omitting trivial ACEs. Map to Darwin ACL style and
443 store Darwin ACL at rbuf. Add length of ACL written to rbuf to *rbuflen.
444 Returns 0 on success, -1 on error. */
445 static int get_and_map_acl(char *name, char *rbuf, int *rbuflen)
447 int ace_count, mapped_aces, err;
449 uint32_t *darwin_ace_count = (u_int32_t *)rbuf;
451 LOG(log_debug9, logtype_afpd, "get_and_map_acl: BEGIN");
453 /* Skip length and flags */
458 if ( (ace_count = get_nfsv4_acl(name, &aces)) == -1) {
459 LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get ACL");
463 if ( (mapped_aces = map_acl(SOLARIS_2_DARWIN, aces, (darwin_ace_t *)rbuf, ace_count)) == -1) {
467 LOG(log_debug, logtype_afpd, "get_and_map_acl: mapped %d ACEs", mapped_aces);
470 *darwin_ace_count = htonl(mapped_aces);
471 *rbuflen += sizeof(darwin_acl_header_t) + (mapped_aces * sizeof(darwin_ace_t));
476 LOG(log_debug9, logtype_afpd, "get_and_map_acl: END");
480 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
481 int remove_acl(const char *name)
483 int ret,i, ace_count, trivial_aces, new_aces_count;
484 ace_t *old_aces = NULL;
485 ace_t *new_aces = NULL;
487 LOG(log_debug9, logtype_afpd, "remove_acl: BEGIN");
489 /* Get existing ACL and count trivial ACEs */
490 if ((ace_count = get_nfsv4_acl(name, &old_aces)) == -1)
493 for ( i=0; i < ace_count; i++) {
494 if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))
498 /* malloc buffer for new ACL */
499 if ((new_aces = malloc(trivial_aces * sizeof(ace_t))) == NULL) {
500 LOG(log_error, logtype_afpd, "remove_acl: malloc %s", strerror(errno));
505 /* Now copy the trivial ACEs */
507 for (i=0; i < ace_count; i++) {
508 if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
509 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
514 if ( (acl(name, ACE_SETACL, trivial_aces, new_aces)) == 0)
517 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
518 if (errno == (EACCES | EPERM))
520 else if (errno == ENOENT)
530 LOG(log_debug9, logtype_afpd, "remove_acl: END");
534 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
535 static int remove_acl_vfs(const struct vol *vol,const char *path, int dir)
539 /* Ressource etc. first */
540 if ((ret = vol->vfs->rf_remove_acl(vol, path, dir)) != AFP_OK)
542 /* now the data fork or dir */
543 return (remove_acl(path));
548 - the client sends a complete list of ACEs, not only new ones. So we dont need to do
549 any combination business (one exception being 'kFileSec_Inherit': see next)
550 - client might request that we add inherited ACEs via 'kFileSec_Inherit'.
551 We will store inherited ACEs first, which is Darwins canonical order.
552 - returns AFPerror code
554 static int set_acl_vfs(const struct vol *vol, char *name, int inherit, char *ibuf)
556 int ret, i, nfsv4_ace_count, tocopy_aces_count = 0, new_aces_count = 0, trivial_ace_count = 0;
557 ace_t *old_aces, *new_aces = NULL;
561 LOG(log_debug9, logtype_afpd, "set_acl: BEGIN");
563 /* Get no of ACEs the client put on the wire */
564 ace_count = htonl(*((uint32_t *)ibuf));
565 ibuf += 8; /* skip ACL flags (see acls.h) */
568 /* inherited + trivial ACEs */
569 flags = ACE_INHERITED_ACE | ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
571 /* only trivial ACEs */
572 flags = ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
574 /* Get existing ACL and count ACEs which have to be copied */
575 if ((nfsv4_ace_count = get_nfsv4_acl(name, &old_aces)) == -1)
577 for ( i=0; i < nfsv4_ace_count; i++) {
578 if (old_aces[i].a_flags & flags)
582 /* Now malloc buffer exactly sized to fit all new ACEs */
583 new_aces = malloc( (ace_count + tocopy_aces_count) * sizeof(ace_t) );
584 if (new_aces == NULL) {
585 LOG(log_error, logtype_afpd, "set_acl: malloc %s", strerror(errno));
590 /* Start building new ACL */
592 /* Copy local inherited ACEs. Therefore we have 'Darwin canonical order' (see chmod there):
593 inherited ACEs first. */
595 for (i=0; i < nfsv4_ace_count; i++) {
596 if (old_aces[i].a_flags & ACE_INHERITED_ACE) {
597 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
602 LOG(log_debug7, logtype_afpd, "set_acl: copied %d inherited ACEs", new_aces_count);
604 /* Now the ACEs from the client */
605 ret = map_acl(DARWIN_2_SOLARIS, &new_aces[new_aces_count], (darwin_ace_t *)ibuf, ace_count);
610 new_aces_count += ace_count;
611 LOG(log_debug7, logtype_afpd, "set_acl: mapped %d ACEs from client", ace_count);
613 /* Now copy the trivial ACEs */
614 for (i=0; i < nfsv4_ace_count; i++) {
615 if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
616 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
621 LOG(log_debug7, logtype_afpd, "set_acl: copied %d trivial ACEs", trivial_ace_count);
623 /* Ressourcefork first.
624 Note: for dirs we set the same ACL on the .AppleDouble/.Parent _file_. This
625 might be strange for ACE_DELETE_CHILD and for inheritance flags. */
626 if ( (ret = vol->vfs->rf_acl(vol, name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
627 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
628 if (errno == (EACCES | EPERM))
630 else if (errno == ENOENT)
636 if ( (ret = acl(name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
637 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
638 if (errno == (EACCES | EPERM))
640 else if (errno == ENOENT)
653 LOG(log_debug9, logtype_afpd, "set_acl: END");
658 Checks if a given UUID has requested_rights(type darwin_ace_rights) for path.
659 Note: this gets called frequently and is a good place for optimizations !
661 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
663 int ret, i, ace_count, dir, checkgroup;
664 char *username; /* might be group too */
668 uint32_t requested_rights = 0, allowed_rights = 0, denied_rights = 0;
672 int check_user_trivace = 0, check_group_trivace = 0;
679 LOG(log_debug9, logtype_afpd, "check_access: BEGIN. Request: %08x", requested_darwin_rights);
681 /* Get uid or gid from UUID */
682 if ( (getnamefromuuid(uuid, &username, &uuidtype)) != 0) {
683 LOG(log_error, logtype_afpd, "check_access: error getting name from UUID");
688 if ((stat(path, &st)) != 0) {
689 LOG(log_error, logtype_afpd, "check_access: stat: %s", strerror(errno));
693 dir = S_ISDIR(st.st_mode);
695 if (uuidtype == UUID_USER) {
696 pwd = getpwnam(username);
698 LOG(log_error, logtype_afpd, "check_access: getpwnam: %s", strerror(errno));
705 /* If user is file/dir owner we must check the user trivial ACE */
706 if (uid == st.st_uid) {
707 LOG(log_debug, logtype_afpd, "check_access: user: %s is files owner. Must check trivial user ACE", username);
708 check_user_trivace = 1;
711 /* Now check if requested user is files owning group. If yes we must check the group trivial ACE */
712 if ( (check_group(username, uid, pgid, st.st_gid)) == 0) {
713 LOG(log_debug, logtype_afpd, "check_access: user: %s is in group: %d. Must check trivial group ACE", username, st.st_gid);
714 check_group_trivace = 1;
716 } else { /* hopefully UUID_GROUP*/
717 LOG(log_error, logtype_afpd, "check_access: afp_access for UUID of groups not supported!");
719 grp = getgrnam(username);
721 LOG(log_error, logtype_afpd, "check_access: getgrnam: %s", strerror(errno));
724 if (st.st_gid == grp->gr_gid )
725 check_group_trivace = 1;
729 /* Map requested rights to Solaris style. */
730 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
731 if (requested_darwin_rights & darwin_to_nfsv4_rights[i].from)
732 requested_rights |= darwin_to_nfsv4_rights[i].to;
735 /* Get ACL from file/dir */
736 if ( (ace_count = get_nfsv4_acl(path, &aces)) == -1) {
737 LOG(log_error, logtype_afpd, "check_access: error getting ACEs");
741 /* Now check requested rights */
744 do { /* Loop through ACEs */
746 flags = aces[i].a_flags;
747 type = aces[i].a_type;
748 rights = aces[i].a_access_mask;
750 if (flags & ACE_INHERIT_ONLY_ACE)
753 /* Check if its a group ACE and set checkgroup to 1 if yes */
755 if ( (flags & ACE_IDENTIFIER_GROUP) && !(flags & ACE_GROUP) ) {
756 if ( (check_group(username, uid, pgid, who)) == 0)
762 /* Now the tricky part: decide if ACE effects our user. I'll explain:
763 if its a dedicated (non trivial) ACE for the user
765 if its a ACE for a group we're member of
767 if its a trivial ACE_OWNER ACE and requested UUID is the owner
769 if its a trivial ACE_GROUP ACE and requested UUID is group
771 if its a trivial ACE_EVERYONE ACE
775 ( (who == uid) && !(flags & (ACE_TRIVIAL|ACE_IDENTIFIER_GROUP)) ) ||
777 ( (flags & ACE_OWNER) && check_user_trivace ) ||
778 ( (flags & ACE_GROUP) && check_group_trivace ) ||
779 ( flags & ACE_EVERYONE )
781 /* Found an applicable ACE */
782 if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
783 allowed_rights |= rights;
784 else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
785 /* Only or to denied rights if not previously allowed !! */
786 denied_rights |= ((!allowed_rights) & rights);
788 } while (++i < ace_count);
791 /* Darwin likes to ask for "delete_child" on dir,
792 "write_data" is actually the same, so we add that for dirs */
793 if (dir && (allowed_rights & ACE_WRITE_DATA))
794 allowed_rights |= ACE_DELETE_CHILD;
796 if (requested_rights & denied_rights) {
797 LOG(log_debug, logtype_afpd, "check_access: some requested right was denied:");
799 } else if ((requested_rights & allowed_rights) != requested_rights) {
800 LOG(log_debug, logtype_afpd, "check_access: some requested right wasn't allowed:");
803 LOG(log_debug, logtype_afpd, "check_access: all requested rights are allowed:");
807 LOG(log_debug, logtype_afpd, "check_access: Requested rights: %08x, allowed_rights: %08x, denied_rights: %08x, Result: %d",
808 requested_rights, allowed_rights, denied_rights, ret);
814 LOG(log_debug9, logtype_afpd, "check_access: END");
819 /********************************************************
821 ********************************************************/
823 int afp_access(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf _U_, int *rbuflen)
828 uint32_t did, darwin_ace_rights;
833 LOG(log_debug9, logtype_afpd, "afp_access: BEGIN");
838 memcpy(&vid, ibuf, sizeof( vid ));
840 if (NULL == ( vol = getvolbyvid( vid ))) {
841 LOG(log_error, logtype_afpd, "afp_access: error getting volid:%d", vid);
845 memcpy(&did, ibuf, sizeof( did ));
846 ibuf += sizeof( did );
847 if (NULL == ( dir = dirlookup( vol, did ))) {
848 LOG(log_error, logtype_afpd, "afp_access: error getting did:%d", did);
855 /* Store UUID address */
856 uuid = (uuidp_t)ibuf;
857 ibuf += UUID_BINSIZE;
859 /* Store ACE rights */
860 memcpy(&darwin_ace_rights, ibuf, 4);
861 darwin_ace_rights = ntohl(darwin_ace_rights);
864 /* get full path and handle file/dir subtleties in netatalk code*/
865 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
866 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
869 if (!s_path->st_valid)
870 of_statdir(vol, s_path);
871 if ( s_path->st_errno != 0 ) {
872 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
876 ret = check_acl_access(s_path->u_name, uuid, darwin_ace_rights);
878 LOG(log_debug9, logtype_afpd, "afp_access: END");
882 int afp_getacl(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf _U_, int *rbuflen)
888 uint16_t vid, bitmap;
893 LOG(log_debug9, logtype_afpd, "afp_getacl: BEGIN");
897 memcpy(&vid, ibuf, sizeof( vid ));
899 if (NULL == ( vol = getvolbyvid( vid ))) {
900 LOG(log_error, logtype_afpd, "afp_getacl: error getting volid:%d", vid);
904 memcpy(&did, ibuf, sizeof( did ));
905 ibuf += sizeof( did );
906 if (NULL == ( dir = dirlookup( vol, did ))) {
907 LOG(log_error, logtype_afpd, "afp_getacl: error getting did:%d", did);
911 memcpy(&bitmap, ibuf, sizeof( bitmap ));
912 memcpy(rbuf, ibuf, sizeof( bitmap ));
913 bitmap = ntohs( bitmap );
914 ibuf += sizeof( bitmap );
915 rbuf += sizeof( bitmap );
916 *rbuflen += sizeof( bitmap );
918 /* skip maxreplysize */
921 /* get full path and handle file/dir subtleties in netatalk code*/
922 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
923 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
926 if (!s_path->st_valid)
927 of_statdir(vol, s_path);
928 if ( s_path->st_errno != 0 ) {
929 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
933 /* Shall we return owner UUID ? */
934 if (bitmap & kFileSec_UUID) {
935 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner user UUID");
936 if (NULL == (pw = getpwuid(s_path->st.st_uid)))
938 LOG(log_debug, logtype_afpd, "afp_getacl: got uid: %d, name: %s", s_path->st.st_uid, pw->pw_name);
939 if ((ret = getuuidfromname(pw->pw_name, UUID_USER, rbuf)) != 0)
941 rbuf += UUID_BINSIZE;
942 *rbuflen += UUID_BINSIZE;
945 /* Shall we return group UUID ? */
946 if (bitmap & kFileSec_GRPUUID) {
947 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner group UUID");
948 if (NULL == (gr = getgrgid(s_path->st.st_gid)))
950 LOG(log_debug, logtype_afpd, "afp_getacl: got gid: %d, name: %s", s_path->st.st_gid, gr->gr_name);
951 if ((ret = getuuidfromname(gr->gr_name, UUID_GROUP, rbuf)) != 0)
953 rbuf += UUID_BINSIZE;
954 *rbuflen += UUID_BINSIZE;
957 /* Shall we return ACL ? */
958 if (bitmap & kFileSec_ACL) {
959 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files ACL");
960 get_and_map_acl(s_path->u_name, rbuf, rbuflen);
963 LOG(log_debug9, logtype_afpd, "afp_getacl: END");
967 int afp_setacl(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf _U_, int *rbuflen)
973 uint16_t vid, bitmap;
976 LOG(log_debug9, logtype_afpd, "afp_setacl: BEGIN");
980 memcpy(&vid, ibuf, sizeof( vid ));
982 if (NULL == ( vol = getvolbyvid( vid ))) {
983 LOG(log_error, logtype_afpd, "afp_setacl: error getting volid:%d", vid);
987 memcpy(&did, ibuf, sizeof( did ));
988 ibuf += sizeof( did );
989 if (NULL == ( dir = dirlookup( vol, did ))) {
990 LOG(log_error, logtype_afpd, "afp_setacl: error getting did:%d", did);
994 memcpy(&bitmap, ibuf, sizeof( bitmap ));
995 bitmap = ntohs( bitmap );
996 ibuf += sizeof( bitmap );
998 /* get full path and handle file/dir subtleties in netatalk code*/
999 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
1000 LOG(log_error, logtype_afpd, "afp_setacl: cname got an error!");
1001 return AFPERR_NOOBJ;
1003 if (!s_path->st_valid)
1004 of_statdir(vol, s_path);
1005 if ( s_path->st_errno != 0 ) {
1006 LOG(log_error, logtype_afpd, "afp_setacl: cant stat");
1007 return AFPERR_NOOBJ;
1009 LOG(log_debug, logtype_afpd, "afp_setacl: unixname: %s", s_path->u_name);
1012 if ((unsigned long)ibuf & 1)
1015 /* Start processing request */
1017 /* Change owner: dont even try */
1018 if (bitmap & kFileSec_UUID) {
1019 LOG(log_debug, logtype_afpd, "afp_setacl: change owner request. discarded.");
1020 ret = AFPERR_ACCESS;
1021 ibuf += UUID_BINSIZE;
1024 /* Change group: certain changes might be allowed, so try it. FIXME: not implemented yet. */
1025 if (bitmap & kFileSec_UUID) {
1026 LOG(log_debug, logtype_afpd, "afp_setacl: change group request. not supported this time.");
1028 ibuf += UUID_BINSIZE;
1032 if (bitmap & kFileSec_REMOVEACL) {
1033 LOG(log_debug, logtype_afpd, "afp_setacl: Remove ACL request.");
1034 if ((ret = remove_acl_vfs(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
1035 LOG(log_error, logtype_afpd, "afp_setacl: error from remove_acl");
1039 if (bitmap & kFileSec_ACL) {
1040 LOG(log_debug, logtype_afpd, "afp_setacl: Change ACL request.");
1042 /* Check if its our job to preserve inherited ACEs */
1043 if (bitmap & kFileSec_Inherit)
1044 ret = set_acl_vfs(vol, s_path->u_name, 1, ibuf);
1046 ret = set_acl_vfs(vol, s_path->u_name, 0, ibuf);
1053 LOG(log_debug9, logtype_afpd, "afp_setacl: END");
1058 unix.c/accessmode calls this: map ACL to OS 9 mode
1060 void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma)
1064 int dir, r_ok, w_ok, x_ok;
1066 dir = S_ISDIR(st->st_mode);
1068 if ((pw = getpwuid(uid)) == NULL) {
1069 LOG(log_error, logtype_afpd, "acltoownermode: %s", strerror(errno));
1073 /* We need the UUID for check_acl_access */
1074 if ((getuuidfromname(pw->pw_name, UUID_USER, uuid)) != 0)
1077 /* These work for files and dirs */
1078 r_ok = check_acl_access(path, uuid, DARWIN_ACE_READ_DATA);
1079 w_ok = check_acl_access(path, uuid, (DARWIN_ACE_WRITE_DATA|DARWIN_ACE_APPEND_DATA));
1080 x_ok = check_acl_access(path, uuid, DARWIN_ACE_EXECUTE);
1082 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user before: %04o",ma->ma_user);
1084 ma->ma_user |= AR_UREAD;
1086 ma->ma_user |= AR_UWRITE;
1088 ma->ma_user |= AR_USEARCH;
1089 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user after: %04o", ma->ma_user);
1095 We're being called at the end of afp_createdir. We're (hopefully) inside dir
1096 and ".AppleDouble" and ".AppleDouble/.Parent" should have already been created.
1097 We then inherit any explicit ACE from "." to ".AppleDouble" and ".AppleDouble/.Parent".
1098 FIXME: add to VFS layer ?
1100 void addir_inherit_acl(const struct vol *vol)
1102 ace_t *diraces = NULL, *adaces = NULL, *combinedaces = NULL;
1103 int diracecount, adacecount;
1105 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: BEGIN");
1107 /* Check if ACLs are enabled for the volume */
1108 if (vol->v_flags & AFPVOL_ACLS) {
1110 if ((diracecount = get_nfsv4_acl(".", &diraces)) <= 0)
1112 /* Remove any trivial ACE from "." */
1113 if ((diracecount = strip_trivial_aces(&diraces, diracecount)) <= 0)
1117 Inherit to ".AppleDouble"
1120 if ((adacecount = get_nfsv4_acl(".AppleDouble", &adaces)) <= 0)
1122 /* Remove any non-trivial ACE from ".AppleDouble" */
1123 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1127 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1130 /* Now set new acl */
1131 if ((acl(".AppleDouble", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1132 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1137 combinedaces = NULL;
1140 Inherit to ".AppleDouble/.Parent"
1143 if ((adacecount = get_nfsv4_acl(".AppleDouble/.Parent", &adaces)) <= 0)
1145 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1149 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1152 /* Now set new acl */
1153 if ((acl(".AppleDouble/.Parent", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1154 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1160 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: END");