2 Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
17 #endif /* HAVE_CONFIG_H */
28 #include <atalk/adouble.h>
29 #include <atalk/vfs.h>
30 #include <atalk/afp.h>
31 #include <atalk/util.h>
32 #include <atalk/cnid.h>
33 #include <atalk/logger.h>
34 #include <atalk/uuid.h>
35 #include <atalk/acl.h>
37 #include "directory.h"
43 #include "acl_mappings.h"
46 #define SOLARIS_2_DARWIN 1
47 #define DARWIN_2_SOLARIS 2
49 /********************************************************
50 * Basic and helper funcs
51 ********************************************************/
54 Takes a users name, uid and primary gid and checks if user is member of any group
55 Returns -1 if no or error, 0 if yes
57 static int check_group(char *name, uid_t uid, gid_t pgid, gid_t path_gid)
65 grp = getgrgid(path_gid);
70 while (grp->gr_mem[i] != NULL) {
71 if ( (strcmp(grp->gr_mem[i], name)) == 0 ) {
72 LOG(log_debug, logtype_afpd, "check_group: requested user:%s is member of: %s", name, grp->gr_name);
82 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));
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));
313 nfsv4_aces->a_who = (uid_t)(grp->gr_gid);
314 nfsv4_ace_flags |= ACE_IDENTIFIER_GROUP;
319 /* now type: allow/deny */
320 darwin_ace_flags = ntohl(darwin_aces->darwin_ace_flags);
321 if (darwin_ace_flags & DARWIN_ACE_FLAGS_PERMIT)
322 nfsv4_aces->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
323 else if (darwin_ace_flags & DARWIN_ACE_FLAGS_DENY)
324 nfsv4_aces->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
325 else { /* unsupported type */
330 for(i=0; darwin_to_nfsv4_flags[i].from != 0; i++) {
331 if (darwin_ace_flags & darwin_to_nfsv4_flags[i].from)
332 nfsv4_ace_flags |= darwin_to_nfsv4_flags[i].to;
336 darwin_ace_rights = ntohl(darwin_aces->darwin_ace_rights);
337 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
338 if (darwin_ace_rights & darwin_to_nfsv4_rights[i].from)
339 nfsv4_ace_rights |= darwin_to_nfsv4_rights[i].to;
342 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE flags: Darwin:%08x -> NFSv4:%04x", darwin_ace_flags, nfsv4_ace_flags);
343 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE rights: Darwin:%08x -> NFSv4:%08x", darwin_ace_rights, nfsv4_ace_rights);
345 nfsv4_aces->a_flags = nfsv4_ace_flags;
346 nfsv4_aces->a_access_mask = nfsv4_ace_rights;
356 /********************************************************
358 ********************************************************/
360 /* Map between ACL styles (SOLARIS_2_DARWIN, DARWIN_2_SOLARIS).
361 Reads from 'aces' buffer, writes to 'rbuf' buffer.
362 Caller must provide buffer.
363 Darwin ACEs are read and written in network byte order.
364 Needs to know how many ACEs are in the ACL (ace_count). Ignores trivial ACEs.
365 Return no of mapped ACEs or -1 on error. */
366 static int map_acl(int type, ace_t *nfsv4_aces, darwin_ace_t *buf, int ace_count)
370 LOG(log_debug9, logtype_afpd, "map_acl: BEGIN");
373 case SOLARIS_2_DARWIN:
374 mapped_aces = map_aces_solaris_to_darwin( nfsv4_aces, buf, ace_count);
377 case DARWIN_2_SOLARIS:
378 mapped_aces = map_aces_darwin_to_solaris( buf, nfsv4_aces, ace_count);
386 LOG(log_debug9, logtype_afpd, "map_acl: END");
390 /********************************************************
392 ********************************************************/
395 /* Get ACL from object omitting trivial ACEs. Map to Darwin ACL style and
396 store Darwin ACL at rbuf. Add length of ACL written to rbuf to *rbuflen.
397 Returns 0 on success, -1 on error. */
398 static int get_and_map_acl(char *name, char *rbuf, size_t *rbuflen)
400 int ace_count, mapped_aces, err;
402 uint32_t *darwin_ace_count = (u_int32_t *)rbuf;
404 LOG(log_debug9, logtype_afpd, "get_and_map_acl: BEGIN");
406 /* Skip length and flags */
411 if ( (ace_count = get_nfsv4_acl(name, &aces)) == -1) {
412 LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get ACL");
416 if ( (mapped_aces = map_acl(SOLARIS_2_DARWIN, aces, (darwin_ace_t *)rbuf, ace_count)) == -1) {
420 LOG(log_debug, logtype_afpd, "get_and_map_acl: mapped %d ACEs", mapped_aces);
423 *darwin_ace_count = htonl(mapped_aces);
424 *rbuflen += sizeof(darwin_acl_header_t) + (mapped_aces * sizeof(darwin_ace_t));
429 LOG(log_debug9, logtype_afpd, "get_and_map_acl: END");
433 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
434 static int remove_acl_vfs(const struct vol *vol,const char *path, int dir)
438 /* Ressource etc. first */
439 if ((ret = vol->vfs->vfs_remove_acl(vol, path, dir)) != AFP_OK)
441 /* now the data fork or dir */
442 return (remove_acl(path));
447 - the client sends a complete list of ACEs, not only new ones. So we dont need to do
448 any combination business (one exception being 'kFileSec_Inherit': see next)
449 - client might request that we add inherited ACEs via 'kFileSec_Inherit'.
450 We will store inherited ACEs first, which is Darwins canonical order.
451 - returns AFPerror code
453 static int set_acl_vfs(const struct vol *vol, char *name, int inherit, char *ibuf)
455 int ret, i, nfsv4_ace_count, tocopy_aces_count = 0, new_aces_count = 0, trivial_ace_count = 0;
456 ace_t *old_aces, *new_aces = NULL;
460 LOG(log_debug9, logtype_afpd, "set_acl: BEGIN");
462 /* Get no of ACEs the client put on the wire */
463 ace_count = htonl(*((uint32_t *)ibuf));
464 ibuf += 8; /* skip ACL flags (see acls.h) */
467 /* inherited + trivial ACEs */
468 flags = ACE_INHERITED_ACE | ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
470 /* only trivial ACEs */
471 flags = ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
473 /* Get existing ACL and count ACEs which have to be copied */
474 if ((nfsv4_ace_count = get_nfsv4_acl(name, &old_aces)) == -1)
476 for ( i=0; i < nfsv4_ace_count; i++) {
477 if (old_aces[i].a_flags & flags)
481 /* Now malloc buffer exactly sized to fit all new ACEs */
482 new_aces = malloc( (ace_count + tocopy_aces_count) * sizeof(ace_t) );
483 if (new_aces == NULL) {
484 LOG(log_error, logtype_afpd, "set_acl: malloc %s", strerror(errno));
489 /* Start building new ACL */
491 /* Copy local inherited ACEs. Therefore we have 'Darwin canonical order' (see chmod there):
492 inherited ACEs first. */
494 for (i=0; i < nfsv4_ace_count; i++) {
495 if (old_aces[i].a_flags & ACE_INHERITED_ACE) {
496 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
501 LOG(log_debug7, logtype_afpd, "set_acl: copied %d inherited ACEs", new_aces_count);
503 /* Now the ACEs from the client */
504 ret = map_acl(DARWIN_2_SOLARIS, &new_aces[new_aces_count], (darwin_ace_t *)ibuf, ace_count);
509 new_aces_count += ace_count;
510 LOG(log_debug7, logtype_afpd, "set_acl: mapped %d ACEs from client", ace_count);
512 /* Now copy the trivial ACEs */
513 for (i=0; i < nfsv4_ace_count; i++) {
514 if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
515 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
520 LOG(log_debug7, logtype_afpd, "set_acl: copied %d trivial ACEs", trivial_ace_count);
522 /* Ressourcefork first.
523 Note: for dirs we set the same ACL on the .AppleDouble/.Parent _file_. This
524 might be strange for ACE_DELETE_CHILD and for inheritance flags. */
525 if ( (ret = vol->vfs->vfs_acl(vol, name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
526 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
527 if (errno == (EACCES | EPERM))
529 else if (errno == ENOENT)
535 if ( (ret = acl(name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
536 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
537 if (errno == (EACCES | EPERM))
539 else if (errno == ENOENT)
552 LOG(log_debug9, logtype_afpd, "set_acl: END");
557 Checks if a given UUID has requested_rights(type darwin_ace_rights) for path.
558 Note: this gets called frequently and is a good place for optimizations !
560 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
562 int ret, i, ace_count, dir, checkgroup;
563 char *username = NULL; /* might be group too */
567 uint32_t requested_rights = 0, allowed_rights = 0, denied_rights = 0;
571 int check_user_trivace = 0, check_group_trivace = 0;
578 LOG(log_debug9, logtype_afpd, "check_access: BEGIN. Request: %08x", requested_darwin_rights);
580 /* Get uid or gid from UUID */
581 if ( (getnamefromuuid(uuid, &username, &uuidtype)) != 0) {
582 LOG(log_error, logtype_afpd, "check_access: error getting name from UUID");
587 if ((lstat(path, &st)) != 0) {
588 LOG(log_error, logtype_afpd, "check_access: stat: %s", strerror(errno));
592 dir = S_ISDIR(st.st_mode);
594 if (uuidtype == UUID_USER) {
595 pwd = getpwnam(username);
597 LOG(log_error, logtype_afpd, "check_access: getpwnam: %s", strerror(errno));
604 /* If user is file/dir owner we must check the user trivial ACE */
605 if (uid == st.st_uid) {
606 LOG(log_debug, logtype_afpd, "check_access: user: %s is files owner. Must check trivial user ACE", username);
607 check_user_trivace = 1;
610 /* Now check if requested user is files owning group. If yes we must check the group trivial ACE */
611 if ( (check_group(username, uid, pgid, st.st_gid)) == 0) {
612 LOG(log_debug, logtype_afpd, "check_access: user: %s is in group: %d. Must check trivial group ACE", username, st.st_gid);
613 check_group_trivace = 1;
615 } else { /* hopefully UUID_GROUP*/
616 LOG(log_error, logtype_afpd, "check_access: afp_access for UUID of groups not supported!");
618 grp = getgrnam(username);
620 LOG(log_error, logtype_afpd, "check_access: getgrnam: %s", strerror(errno));
623 if (st.st_gid == grp->gr_gid )
624 check_group_trivace = 1;
628 /* Map requested rights to Solaris style. */
629 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
630 if (requested_darwin_rights & darwin_to_nfsv4_rights[i].from)
631 requested_rights |= darwin_to_nfsv4_rights[i].to;
634 /* Get ACL from file/dir */
635 if ( (ace_count = get_nfsv4_acl(path, &aces)) == -1) {
636 LOG(log_error, logtype_afpd, "check_access: error getting ACEs");
640 if (ace_count == 0) {
641 LOG(log_debug, logtype_afpd, "check_access: 0 ACEs from get_nfsv4_acl");
646 /* Now check requested rights */
649 do { /* Loop through ACEs */
651 flags = aces[i].a_flags;
652 type = aces[i].a_type;
653 rights = aces[i].a_access_mask;
655 if (flags & ACE_INHERIT_ONLY_ACE)
658 /* Check if its a group ACE and set checkgroup to 1 if yes */
660 if ( (flags & ACE_IDENTIFIER_GROUP) && !(flags & ACE_GROUP) ) {
661 if ( (check_group(username, uid, pgid, who)) == 0)
667 /* Now the tricky part: decide if ACE effects our user. I'll explain:
668 if its a dedicated (non trivial) ACE for the user
670 if its a ACE for a group we're member of
672 if its a trivial ACE_OWNER ACE and requested UUID is the owner
674 if its a trivial ACE_GROUP ACE and requested UUID is group
676 if its a trivial ACE_EVERYONE ACE
680 ( (who == uid) && !(flags & (ACE_TRIVIAL|ACE_IDENTIFIER_GROUP)) ) ||
682 ( (flags & ACE_OWNER) && check_user_trivace ) ||
683 ( (flags & ACE_GROUP) && check_group_trivace ) ||
684 ( flags & ACE_EVERYONE )
686 /* Found an applicable ACE */
687 if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
688 allowed_rights |= rights;
689 else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
690 /* Only or to denied rights if not previously allowed !! */
691 denied_rights |= ((!allowed_rights) & rights);
693 } while (++i < ace_count);
696 /* Darwin likes to ask for "delete_child" on dir,
697 "write_data" is actually the same, so we add that for dirs */
698 if (dir && (allowed_rights & ACE_WRITE_DATA))
699 allowed_rights |= ACE_DELETE_CHILD;
701 if (requested_rights & denied_rights) {
702 LOG(log_debug, logtype_afpd, "check_access: some requested right was denied:");
704 } else if ((requested_rights & allowed_rights) != requested_rights) {
705 LOG(log_debug, logtype_afpd, "check_access: some requested right wasn't allowed:");
708 LOG(log_debug, logtype_afpd, "check_access: all requested rights are allowed:");
712 LOG(log_debug, logtype_afpd, "check_access: Requested rights: %08x, allowed_rights: %08x, denied_rights: %08x, Result: %d",
713 requested_rights, allowed_rights, denied_rights, ret);
719 LOG(log_debug9, logtype_afpd, "check_access: END");
724 /********************************************************
726 ********************************************************/
728 int afp_access(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
733 uint32_t did, darwin_ace_rights;
738 LOG(log_debug9, logtype_afpd, "afp_access: BEGIN");
743 memcpy(&vid, ibuf, sizeof( vid ));
745 if (NULL == ( vol = getvolbyvid( vid ))) {
746 LOG(log_error, logtype_afpd, "afp_access: error getting volid:%d", vid);
750 memcpy(&did, ibuf, sizeof( did ));
751 ibuf += sizeof( did );
752 if (NULL == ( dir = dirlookup( vol, did ))) {
753 LOG(log_error, logtype_afpd, "afp_access: error getting did:%d", did);
760 /* Store UUID address */
761 uuid = (uuidp_t)ibuf;
762 ibuf += UUID_BINSIZE;
764 /* Store ACE rights */
765 memcpy(&darwin_ace_rights, ibuf, 4);
766 darwin_ace_rights = ntohl(darwin_ace_rights);
769 /* get full path and handle file/dir subtleties in netatalk code*/
770 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
771 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
774 if (!s_path->st_valid)
775 of_statdir(vol, s_path);
776 if ( s_path->st_errno != 0 ) {
777 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
781 ret = check_acl_access(s_path->u_name, uuid, darwin_ace_rights);
783 LOG(log_debug9, logtype_afpd, "afp_access: END");
787 int afp_getacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
793 uint16_t vid, bitmap;
798 LOG(log_debug9, logtype_afpd, "afp_getacl: BEGIN");
802 memcpy(&vid, ibuf, sizeof( vid ));
804 if (NULL == ( vol = getvolbyvid( vid ))) {
805 LOG(log_error, logtype_afpd, "afp_getacl: error getting volid:%d", vid);
809 memcpy(&did, ibuf, sizeof( did ));
810 ibuf += sizeof( did );
811 if (NULL == ( dir = dirlookup( vol, did ))) {
812 LOG(log_error, logtype_afpd, "afp_getacl: error getting did:%d", did);
816 memcpy(&bitmap, ibuf, sizeof( bitmap ));
817 memcpy(rbuf, ibuf, sizeof( bitmap ));
818 bitmap = ntohs( bitmap );
819 ibuf += sizeof( bitmap );
820 rbuf += sizeof( bitmap );
821 *rbuflen += sizeof( bitmap );
823 /* skip maxreplysize */
826 /* get full path and handle file/dir subtleties in netatalk code*/
827 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
828 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
831 if (!s_path->st_valid)
832 of_statdir(vol, s_path);
833 if ( s_path->st_errno != 0 ) {
834 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
838 /* Shall we return owner UUID ? */
839 if (bitmap & kFileSec_UUID) {
840 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner user UUID");
841 if (NULL == (pw = getpwuid(s_path->st.st_uid)))
843 LOG(log_debug, logtype_afpd, "afp_getacl: got uid: %d, name: %s", s_path->st.st_uid, pw->pw_name);
844 if ((ret = getuuidfromname(pw->pw_name, UUID_USER, rbuf)) != 0)
846 rbuf += UUID_BINSIZE;
847 *rbuflen += UUID_BINSIZE;
850 /* Shall we return group UUID ? */
851 if (bitmap & kFileSec_GRPUUID) {
852 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner group UUID");
853 if (NULL == (gr = getgrgid(s_path->st.st_gid)))
855 LOG(log_debug, logtype_afpd, "afp_getacl: got gid: %d, name: %s", s_path->st.st_gid, gr->gr_name);
856 if ((ret = getuuidfromname(gr->gr_name, UUID_GROUP, rbuf)) != 0)
858 rbuf += UUID_BINSIZE;
859 *rbuflen += UUID_BINSIZE;
862 /* Shall we return ACL ? */
863 if (bitmap & kFileSec_ACL) {
864 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files ACL");
865 get_and_map_acl(s_path->u_name, rbuf, rbuflen);
868 LOG(log_debug9, logtype_afpd, "afp_getacl: END");
872 int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
878 uint16_t vid, bitmap;
881 LOG(log_debug9, logtype_afpd, "afp_setacl: BEGIN");
885 memcpy(&vid, ibuf, sizeof( vid ));
887 if (NULL == ( vol = getvolbyvid( vid ))) {
888 LOG(log_error, logtype_afpd, "afp_setacl: error getting volid:%d", vid);
892 memcpy(&did, ibuf, sizeof( did ));
893 ibuf += sizeof( did );
894 if (NULL == ( dir = dirlookup( vol, did ))) {
895 LOG(log_error, logtype_afpd, "afp_setacl: error getting did:%d", did);
899 memcpy(&bitmap, ibuf, sizeof( bitmap ));
900 bitmap = ntohs( bitmap );
901 ibuf += sizeof( bitmap );
903 /* get full path and handle file/dir subtleties in netatalk code*/
904 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
905 LOG(log_error, logtype_afpd, "afp_setacl: cname got an error!");
908 if (!s_path->st_valid)
909 of_statdir(vol, s_path);
910 if ( s_path->st_errno != 0 ) {
911 LOG(log_error, logtype_afpd, "afp_setacl: cant stat");
914 LOG(log_debug, logtype_afpd, "afp_setacl: unixname: %s", s_path->u_name);
917 if ((unsigned long)ibuf & 1)
920 /* Start processing request */
922 /* Change owner: dont even try */
923 if (bitmap & kFileSec_UUID) {
924 LOG(log_debug, logtype_afpd, "afp_setacl: change owner request. discarded.");
926 ibuf += UUID_BINSIZE;
929 /* Change group: certain changes might be allowed, so try it. FIXME: not implemented yet. */
930 if (bitmap & kFileSec_UUID) {
931 LOG(log_debug, logtype_afpd, "afp_setacl: change group request. not supported this time.");
933 ibuf += UUID_BINSIZE;
937 if (bitmap & kFileSec_REMOVEACL) {
938 LOG(log_debug, logtype_afpd, "afp_setacl: Remove ACL request.");
939 if ((ret = remove_acl_vfs(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
940 LOG(log_error, logtype_afpd, "afp_setacl: error from remove_acl");
944 if (bitmap & kFileSec_ACL) {
945 LOG(log_debug, logtype_afpd, "afp_setacl: Change ACL request.");
947 /* Check if its our job to preserve inherited ACEs */
948 if (bitmap & kFileSec_Inherit)
949 ret = set_acl_vfs(vol, s_path->u_name, 1, ibuf);
951 ret = set_acl_vfs(vol, s_path->u_name, 0, ibuf);
958 LOG(log_debug9, logtype_afpd, "afp_setacl: END");
963 unix.c/accessmode calls this: map ACL to OS 9 mode
965 void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma)
969 int dir, r_ok, w_ok, x_ok;
971 if ( ! (AFPobj->options.flags & OPTION_UUID))
974 LOG(log_maxdebug, logtype_afpd, "acltoownermode('%s')", path);
976 if ((pw = getpwuid(uid)) == NULL) {
977 LOG(log_error, logtype_afpd, "acltoownermode: %s", strerror(errno));
981 /* We need the UUID for check_acl_access */
982 if ((getuuidfromname(pw->pw_name, UUID_USER, uuid)) != 0)
985 /* These work for files and dirs */
986 r_ok = check_acl_access(path, uuid, DARWIN_ACE_READ_DATA);
987 w_ok = check_acl_access(path, uuid, (DARWIN_ACE_WRITE_DATA|DARWIN_ACE_APPEND_DATA));
988 x_ok = check_acl_access(path, uuid, DARWIN_ACE_EXECUTE);
990 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user before: %04o",ma->ma_user);
992 ma->ma_user |= AR_UREAD;
994 ma->ma_user |= AR_UWRITE;
996 ma->ma_user |= AR_USEARCH;
997 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user after: %04o", ma->ma_user);
1003 We're being called at the end of afp_createdir. We're (hopefully) inside dir
1004 and ".AppleDouble" and ".AppleDouble/.Parent" should have already been created.
1005 We then inherit any explicit ACE from "." to ".AppleDouble" and ".AppleDouble/.Parent".
1006 FIXME: add to VFS layer ?
1008 void addir_inherit_acl(const struct vol *vol)
1010 ace_t *diraces = NULL, *adaces = NULL, *combinedaces = NULL;
1011 int diracecount, adacecount;
1013 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: BEGIN");
1015 /* Check if ACLs are enabled for the volume */
1016 if (vol->v_flags & AFPVOL_ACLS) {
1018 if ((diracecount = get_nfsv4_acl(".", &diraces)) <= 0)
1020 /* Remove any trivial ACE from "." */
1021 if ((diracecount = strip_trivial_aces(&diraces, diracecount)) <= 0)
1025 Inherit to ".AppleDouble"
1028 if ((adacecount = get_nfsv4_acl(".AppleDouble", &adaces)) <= 0)
1030 /* Remove any non-trivial ACE from ".AppleDouble" */
1031 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1035 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1038 /* Now set new acl */
1039 if ((acl(".AppleDouble", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1040 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1045 combinedaces = NULL;
1048 Inherit to ".AppleDouble/.Parent"
1051 if ((adacecount = get_nfsv4_acl(".AppleDouble/.Parent", &adaces)) <= 0)
1053 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1057 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1060 /* Now set new acl */
1061 if ((acl(".AppleDouble/.Parent", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1062 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1068 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: END");