2 Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
3 Copyright (c) 2010 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 _U_, 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);
82 /********************************************************
84 ********************************************************/
86 #ifdef HAVE_SOLARIS_ACLS
88 Remove any trivial ACE "in-place". Returns no of non-trivial ACEs
90 static int strip_trivial_aces(ace_t **saces, int sacecount)
97 /* Count non-trivial ACEs */
98 for (i=0; i < sacecount; ) {
99 if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
103 /* malloc buffer for new ACL */
104 if ((new_aces = malloc(nontrivaces * sizeof(ace_t))) == NULL) {
105 LOG(log_error, logtype_afpd, "strip_trivial_aces: malloc %s", strerror(errno));
109 /* Copy non-trivial ACEs */
110 for (i=0, j=0; i < sacecount; ) {
111 if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
112 memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
121 LOG(log_debug7, logtype_afpd, "strip_trivial_aces: non-trivial ACEs: %d", nontrivaces);
127 Remove non-trivial ACEs "in-place". Returns no of trivial ACEs.
129 static int strip_nontrivial_aces(ace_t **saces, int sacecount)
133 ace_t *aces = *saces;
136 /* Count trivial ACEs */
137 for (i=0; i < sacecount; ) {
138 if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
142 /* malloc buffer for new ACL */
143 if ((new_aces = malloc(trivaces * sizeof(ace_t))) == NULL) {
144 LOG(log_error, logtype_afpd, "strip_nontrivial_aces: malloc %s", strerror(errno));
148 /* Copy trivial ACEs */
149 for (i=0, j=0; i < sacecount; ) {
150 if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
151 memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
160 LOG(log_debug7, logtype_afpd, "strip_nontrivial_aces: trivial ACEs: %d", trivaces);
168 static ace_t *concat_aces(ace_t *aces1, int ace1count, ace_t *aces2, int ace2count)
173 /* malloc buffer for new ACL */
174 if ((new_aces = malloc((ace1count + ace2count) * sizeof(ace_t))) == NULL) {
175 LOG(log_error, logtype_afpd, "combine_aces: malloc %s", strerror(errno));
179 /* Copy ACEs from buf1 */
180 for (i=0; i < ace1count; ) {
181 memcpy(&new_aces[i], &aces1[i], sizeof(ace_t));
187 /* Copy ACEs from buf2 */
188 for (i=0; i < ace2count; ) {
189 memcpy(&new_aces[j], &aces2[i], sizeof(ace_t));
198 Maps ACE array from Solaris to Darwin. Darwin ACEs are stored in network byte order.
199 Return numer of mapped ACEs or -1 on error.
200 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
202 static int map_aces_solaris_to_darwin(ace_t *aces, darwin_ace_t *darwin_aces, int ace_count)
207 struct passwd *pwd = NULL;
208 struct group *grp = NULL;
210 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing %d ACES", ace_count);
213 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing ACE No. %d", ace_count + 1);
214 /* if its a ACE resulting from nfsv4 mode mapping, discard it */
215 if (aces->a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
216 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: trivial ACE");
221 if ( ! (aces->a_flags & ACE_IDENTIFIER_GROUP) ) {
223 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found user ACE with uid: %d", aces->a_who);
224 pwd = getpwuid(aces->a_who);
226 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getpwuid error: %s", strerror(errno));
229 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: uid: %d -> name: %s", aces->a_who, pwd->pw_name);
230 if ( (getuuidfromname(pwd->pw_name, UUID_USER, darwin_aces->darwin_ace_uuid)) != 0) {
231 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
235 /* its a group ace */
236 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found group ACE with gid: %d", aces->a_who);
237 grp = getgrgid(aces->a_who);
239 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getgrgid error: %s", strerror(errno));
242 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: gid: %d -> name: %s", aces->a_who, grp->gr_name);
243 if ( (getuuidfromname(grp->gr_name, UUID_GROUP, darwin_aces->darwin_ace_uuid)) != 0) {
244 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
250 if (aces->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE)
251 flags = DARWIN_ACE_FLAGS_PERMIT;
252 else if (aces->a_type == ACE_ACCESS_DENIED_ACE_TYPE)
253 flags = DARWIN_ACE_FLAGS_DENY;
254 else { /* unsupported type */
258 for(i=0; nfsv4_to_darwin_flags[i].from != 0; i++) {
259 if (aces->a_flags & nfsv4_to_darwin_flags[i].from)
260 flags |= nfsv4_to_darwin_flags[i].to;
262 darwin_aces->darwin_ace_flags = htonl(flags);
266 for (i=0; nfsv4_to_darwin_rights[i].from != 0; i++) {
267 if (aces->a_access_mask & nfsv4_to_darwin_rights[i].from)
268 rights |= nfsv4_to_darwin_rights[i].to;
270 darwin_aces->darwin_ace_rights = htonl(rights);
281 Maps ACE array from Darwin to Solaris. Darwin ACEs are expected in network byte order.
282 Return numer of mapped ACEs or -1 on error.
283 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
285 int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int ace_count)
287 int i, mapped_aces = 0;
288 uint32_t darwin_ace_flags;
289 uint32_t darwin_ace_rights;
290 uint16_t nfsv4_ace_flags;
291 uint32_t nfsv4_ace_rights;
299 nfsv4_ace_rights = 0;
302 if ( (getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype)) != 0)
304 if (uuidtype == UUID_USER) {
305 pwd = getpwnam(name);
307 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getpwnam: %s", strerror(errno));
310 nfsv4_aces->a_who = pwd->pw_uid;
311 } else { /* hopefully UUID_GROUP*/
312 grp = getgrnam(name);
314 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getgrnam: %s", strerror(errno));
317 nfsv4_aces->a_who = (uid_t)(grp->gr_gid);
318 nfsv4_ace_flags |= ACE_IDENTIFIER_GROUP;
323 /* now type: allow/deny */
324 darwin_ace_flags = ntohl(darwin_aces->darwin_ace_flags);
325 if (darwin_ace_flags & DARWIN_ACE_FLAGS_PERMIT)
326 nfsv4_aces->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
327 else if (darwin_ace_flags & DARWIN_ACE_FLAGS_DENY)
328 nfsv4_aces->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
329 else { /* unsupported type */
334 for(i=0; darwin_to_nfsv4_flags[i].from != 0; i++) {
335 if (darwin_ace_flags & darwin_to_nfsv4_flags[i].from)
336 nfsv4_ace_flags |= darwin_to_nfsv4_flags[i].to;
340 darwin_ace_rights = ntohl(darwin_aces->darwin_ace_rights);
341 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
342 if (darwin_ace_rights & darwin_to_nfsv4_rights[i].from)
343 nfsv4_ace_rights |= darwin_to_nfsv4_rights[i].to;
346 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE flags: Darwin:%08x -> NFSv4:%04x", darwin_ace_flags, nfsv4_ace_flags);
347 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE rights: Darwin:%08x -> NFSv4:%08x", darwin_ace_rights, nfsv4_ace_rights);
349 nfsv4_aces->a_flags = nfsv4_ace_flags;
350 nfsv4_aces->a_access_mask = nfsv4_ace_rights;
361 /* Map between ACL styles (SOLARIS_2_DARWIN, DARWIN_2_SOLARIS).
362 Reads from 'aces' buffer, writes to 'rbuf' buffer.
363 Caller must provide buffer.
364 Darwin ACEs are read and written in network byte order.
365 Needs to know how many ACEs are in the ACL (ace_count). Ignores trivial ACEs.
366 Return no of mapped ACEs or -1 on error. */
367 static int map_acl(int type, ace_t *nfsv4_aces, darwin_ace_t *buf, int ace_count)
371 LOG(log_debug9, logtype_afpd, "map_acl: BEGIN");
374 case SOLARIS_2_DARWIN:
375 mapped_aces = map_aces_solaris_to_darwin( nfsv4_aces, buf, ace_count);
378 case DARWIN_2_SOLARIS:
379 mapped_aces = map_aces_darwin_to_solaris( buf, nfsv4_aces, ace_count);
387 LOG(log_debug9, logtype_afpd, "map_acl: END");
390 #endif /* HAVE_SOLARIS_ACLS */
392 /* Get ACL from object omitting trivial ACEs. Map to Darwin ACL style and
393 store Darwin ACL at rbuf. Add length of ACL written to rbuf to *rbuflen.
394 Returns 0 on success, -1 on error. */
395 static int get_and_map_acl(char *name, char *rbuf, size_t *rbuflen)
397 int ace_count = 0, mapped_aces = 0, err;
398 uint32_t *darwin_ace_count = (u_int32_t *)rbuf;
399 #ifdef HAVE_SOLARIS_ACLS
403 LOG(log_debug9, logtype_afpd, "get_and_map_acl: BEGIN");
405 /* Skip length and flags */
410 #ifdef HAVE_SOLARIS_ACLS
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 #endif /* HAVE_SOLARIS_ACLS */
422 LOG(log_debug, logtype_afpd, "get_and_map_acl: mapped %d ACEs", mapped_aces);
425 *darwin_ace_count = htonl(mapped_aces);
426 *rbuflen += sizeof(darwin_acl_header_t) + (mapped_aces * sizeof(darwin_ace_t));
428 #ifdef HAVE_SOLARIS_ACLS
433 LOG(log_debug9, logtype_afpd, "get_and_map_acl: END");
437 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
438 static int remove_acl(const struct vol *vol,const char *path, int dir)
442 /* Ressource etc. first */
443 if ((ret = vol->vfs->vfs_remove_acl(vol, path, dir)) != AFP_OK)
445 /* now the data fork or dir */
446 return (remove_acl_vfs(path));
451 - the client sends a complete list of ACEs, not only new ones. So we dont need to do
452 any combination business (one exception being 'kFileSec_Inherit': see next)
453 - client might request that we add inherited ACEs via 'kFileSec_Inherit'.
454 We will store inherited ACEs first, which is Darwins canonical order.
455 - returns AFPerror code
457 #ifdef HAVE_SOLARIS_ACLS
458 static int set_acl(const struct vol *vol, char *name, int inherit, char *ibuf)
460 int ret, i, nfsv4_ace_count, tocopy_aces_count = 0, new_aces_count = 0, trivial_ace_count = 0;
461 ace_t *old_aces, *new_aces = NULL;
465 LOG(log_debug9, logtype_afpd, "set_acl: BEGIN");
467 /* Get no of ACEs the client put on the wire */
468 ace_count = htonl(*((uint32_t *)ibuf));
469 ibuf += 8; /* skip ACL flags (see acls.h) */
472 /* inherited + trivial ACEs */
473 flags = ACE_INHERITED_ACE | ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
475 /* only trivial ACEs */
476 flags = ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
478 /* Get existing ACL and count ACEs which have to be copied */
479 if ((nfsv4_ace_count = get_nfsv4_acl(name, &old_aces)) == -1)
481 for ( i=0; i < nfsv4_ace_count; i++) {
482 if (old_aces[i].a_flags & flags)
486 /* Now malloc buffer exactly sized to fit all new ACEs */
487 new_aces = malloc( (ace_count + tocopy_aces_count) * sizeof(ace_t) );
488 if (new_aces == NULL) {
489 LOG(log_error, logtype_afpd, "set_acl: malloc %s", strerror(errno));
494 /* Start building new ACL */
496 /* Copy local inherited ACEs. Therefore we have 'Darwin canonical order' (see chmod there):
497 inherited ACEs first. */
499 for (i=0; i < nfsv4_ace_count; i++) {
500 if (old_aces[i].a_flags & ACE_INHERITED_ACE) {
501 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
506 LOG(log_debug7, logtype_afpd, "set_acl: copied %d inherited ACEs", new_aces_count);
508 /* Now the ACEs from the client */
509 ret = map_acl(DARWIN_2_SOLARIS, &new_aces[new_aces_count], (darwin_ace_t *)ibuf, ace_count);
514 new_aces_count += ace_count;
515 LOG(log_debug7, logtype_afpd, "set_acl: mapped %d ACEs from client", ace_count);
517 /* Now copy the trivial ACEs */
518 for (i=0; i < nfsv4_ace_count; i++) {
519 if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
520 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
525 LOG(log_debug7, logtype_afpd, "set_acl: copied %d trivial ACEs", trivial_ace_count);
527 /* Ressourcefork first.
528 Note: for dirs we set the same ACL on the .AppleDouble/.Parent _file_. This
529 might be strange for ACE_DELETE_CHILD and for inheritance flags. */
530 if ( (ret = vol->vfs->vfs_acl(vol, name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
531 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
532 if (errno == (EACCES | EPERM))
534 else if (errno == ENOENT)
540 if ( (ret = acl(name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
541 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
542 if (errno == (EACCES | EPERM))
544 else if (errno == ENOENT)
557 LOG(log_debug9, logtype_afpd, "set_acl: END");
560 #endif /* HAVE_SOLARIS_ACLS */
562 #ifdef HAVE_POSIX_ACLS
563 static int set_acl(const struct vol *vol, char *name, int inherit, char *ibuf)
567 #endif /* HAVE_POSIX_ACLS */
570 Checks if a given UUID has requested_rights(type darwin_ace_rights) for path.
571 Note: this gets called frequently and is a good place for optimizations !
573 #ifdef HAVE_SOLARIS_ACLS
574 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
576 int ret, i, ace_count, dir, checkgroup;
577 char *username; /* might be group too */
581 uint32_t requested_rights = 0, allowed_rights = 0, denied_rights = 0;
585 int check_user_trivace = 0, check_group_trivace = 0;
592 LOG(log_debug9, logtype_afpd, "check_access: BEGIN. Request: %08x", requested_darwin_rights);
594 /* Get uid or gid from UUID */
595 if ( (getnamefromuuid(uuid, &username, &uuidtype)) != 0) {
596 LOG(log_error, logtype_afpd, "check_access: error getting name from UUID");
601 if ((lstat(path, &st)) != 0) {
602 LOG(log_error, logtype_afpd, "check_access: stat: %s", strerror(errno));
606 dir = S_ISDIR(st.st_mode);
608 if (uuidtype == UUID_USER) {
609 pwd = getpwnam(username);
611 LOG(log_error, logtype_afpd, "check_access: getpwnam: %s", strerror(errno));
618 /* If user is file/dir owner we must check the user trivial ACE */
619 if (uid == st.st_uid) {
620 LOG(log_debug, logtype_afpd, "check_access: user: %s is files owner. Must check trivial user ACE", username);
621 check_user_trivace = 1;
624 /* Now check if requested user is files owning group. If yes we must check the group trivial ACE */
625 if ( (check_group(username, uid, pgid, st.st_gid)) == 0) {
626 LOG(log_debug, logtype_afpd, "check_access: user: %s is in group: %d. Must check trivial group ACE", username, st.st_gid);
627 check_group_trivace = 1;
629 } else { /* hopefully UUID_GROUP*/
630 LOG(log_error, logtype_afpd, "check_access: afp_access for UUID of groups not supported!");
632 grp = getgrnam(username);
634 LOG(log_error, logtype_afpd, "check_access: getgrnam: %s", strerror(errno));
637 if (st.st_gid == grp->gr_gid )
638 check_group_trivace = 1;
642 /* Map requested rights to Solaris style. */
643 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
644 if (requested_darwin_rights & darwin_to_nfsv4_rights[i].from)
645 requested_rights |= darwin_to_nfsv4_rights[i].to;
648 /* Get ACL from file/dir */
649 if ( (ace_count = get_nfsv4_acl(path, &aces)) == -1) {
650 LOG(log_error, logtype_afpd, "check_access: error getting ACEs");
654 /* Now check requested rights */
657 do { /* Loop through ACEs */
659 flags = aces[i].a_flags;
660 type = aces[i].a_type;
661 rights = aces[i].a_access_mask;
663 if (flags & ACE_INHERIT_ONLY_ACE)
666 /* Check if its a group ACE and set checkgroup to 1 if yes */
668 if ( (flags & ACE_IDENTIFIER_GROUP) && !(flags & ACE_GROUP) ) {
669 if ( (check_group(username, uid, pgid, who)) == 0)
675 /* Now the tricky part: decide if ACE effects our user. I'll explain:
676 if its a dedicated (non trivial) ACE for the user
678 if its a ACE for a group we're member of
680 if its a trivial ACE_OWNER ACE and requested UUID is the owner
682 if its a trivial ACE_GROUP ACE and requested UUID is group
684 if its a trivial ACE_EVERYONE ACE
688 ( (who == uid) && !(flags & (ACE_TRIVIAL|ACE_IDENTIFIER_GROUP)) ) ||
690 ( (flags & ACE_OWNER) && check_user_trivace ) ||
691 ( (flags & ACE_GROUP) && check_group_trivace ) ||
692 ( flags & ACE_EVERYONE )
694 /* Found an applicable ACE */
695 if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
696 allowed_rights |= rights;
697 else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
698 /* Only or to denied rights if not previously allowed !! */
699 denied_rights |= ((!allowed_rights) & rights);
701 } while (++i < ace_count);
704 /* Darwin likes to ask for "delete_child" on dir,
705 "write_data" is actually the same, so we add that for dirs */
706 if (dir && (allowed_rights & ACE_WRITE_DATA))
707 allowed_rights |= ACE_DELETE_CHILD;
709 if (requested_rights & denied_rights) {
710 LOG(log_debug, logtype_afpd, "check_access: some requested right was denied:");
712 } else if ((requested_rights & allowed_rights) != requested_rights) {
713 LOG(log_debug, logtype_afpd, "check_access: some requested right wasn't allowed:");
716 LOG(log_debug, logtype_afpd, "check_access: all requested rights are allowed:");
720 LOG(log_debug, logtype_afpd, "check_access: Requested rights: %08x, allowed_rights: %08x, denied_rights: %08x, Result: %d",
721 requested_rights, allowed_rights, denied_rights, ret);
727 LOG(log_debug9, logtype_afpd, "check_access: END");
731 #endif /* HAVE_SOLARIS_ACLS */
733 #ifdef HAVE_POSIX_ACLS
734 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
738 #endif /* HAVE_POSIX_ACLS */
740 /********************************************************
742 ********************************************************/
744 int afp_access(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
749 uint32_t did, darwin_ace_rights;
754 LOG(log_debug9, logtype_afpd, "afp_access: BEGIN");
759 memcpy(&vid, ibuf, sizeof( vid ));
761 if (NULL == ( vol = getvolbyvid( vid ))) {
762 LOG(log_error, logtype_afpd, "afp_access: error getting volid:%d", vid);
766 memcpy(&did, ibuf, sizeof( did ));
767 ibuf += sizeof( did );
768 if (NULL == ( dir = dirlookup( vol, did ))) {
769 LOG(log_error, logtype_afpd, "afp_access: error getting did:%d", did);
776 /* Store UUID address */
777 uuid = (uuidp_t)ibuf;
778 ibuf += UUID_BINSIZE;
780 /* Store ACE rights */
781 memcpy(&darwin_ace_rights, ibuf, 4);
782 darwin_ace_rights = ntohl(darwin_ace_rights);
785 /* get full path and handle file/dir subtleties in netatalk code*/
786 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
787 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
790 if (!s_path->st_valid)
791 of_statdir(vol, s_path);
792 if ( s_path->st_errno != 0 ) {
793 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
797 ret = check_acl_access(s_path->u_name, uuid, darwin_ace_rights);
799 LOG(log_debug9, logtype_afpd, "afp_access: END");
803 int afp_getacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
809 uint16_t vid, bitmap;
814 LOG(log_debug9, logtype_afpd, "afp_getacl: BEGIN");
818 memcpy(&vid, ibuf, sizeof( vid ));
820 if (NULL == ( vol = getvolbyvid( vid ))) {
821 LOG(log_error, logtype_afpd, "afp_getacl: error getting volid:%d", vid);
825 memcpy(&did, ibuf, sizeof( did ));
826 ibuf += sizeof( did );
827 if (NULL == ( dir = dirlookup( vol, did ))) {
828 LOG(log_error, logtype_afpd, "afp_getacl: error getting did:%d", did);
832 memcpy(&bitmap, ibuf, sizeof( bitmap ));
833 memcpy(rbuf, ibuf, sizeof( bitmap ));
834 bitmap = ntohs( bitmap );
835 ibuf += sizeof( bitmap );
836 rbuf += sizeof( bitmap );
837 *rbuflen += sizeof( bitmap );
839 /* skip maxreplysize */
842 /* get full path and handle file/dir subtleties in netatalk code*/
843 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
844 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
847 if (!s_path->st_valid)
848 of_statdir(vol, s_path);
849 if ( s_path->st_errno != 0 ) {
850 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
854 /* Shall we return owner UUID ? */
855 if (bitmap & kFileSec_UUID) {
856 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner user UUID");
857 if (NULL == (pw = getpwuid(s_path->st.st_uid)))
859 LOG(log_debug, logtype_afpd, "afp_getacl: got uid: %d, name: %s", s_path->st.st_uid, pw->pw_name);
860 if ((ret = getuuidfromname(pw->pw_name, UUID_USER, rbuf)) != 0)
862 rbuf += UUID_BINSIZE;
863 *rbuflen += UUID_BINSIZE;
866 /* Shall we return group UUID ? */
867 if (bitmap & kFileSec_GRPUUID) {
868 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner group UUID");
869 if (NULL == (gr = getgrgid(s_path->st.st_gid)))
871 LOG(log_debug, logtype_afpd, "afp_getacl: got gid: %d, name: %s", s_path->st.st_gid, gr->gr_name);
872 if ((ret = getuuidfromname(gr->gr_name, UUID_GROUP, rbuf)) != 0)
874 rbuf += UUID_BINSIZE;
875 *rbuflen += UUID_BINSIZE;
878 /* Shall we return ACL ? */
879 if (bitmap & kFileSec_ACL) {
880 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files ACL");
881 get_and_map_acl(s_path->u_name, rbuf, rbuflen);
884 LOG(log_debug9, logtype_afpd, "afp_getacl: END");
888 int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
894 uint16_t vid, bitmap;
897 LOG(log_debug9, logtype_afpd, "afp_setacl: BEGIN");
901 memcpy(&vid, ibuf, sizeof( vid ));
903 if (NULL == ( vol = getvolbyvid( vid ))) {
904 LOG(log_error, logtype_afpd, "afp_setacl: error getting volid:%d", vid);
908 memcpy(&did, ibuf, sizeof( did ));
909 ibuf += sizeof( did );
910 if (NULL == ( dir = dirlookup( vol, did ))) {
911 LOG(log_error, logtype_afpd, "afp_setacl: error getting did:%d", did);
915 memcpy(&bitmap, ibuf, sizeof( bitmap ));
916 bitmap = ntohs( bitmap );
917 ibuf += sizeof( bitmap );
919 /* get full path and handle file/dir subtleties in netatalk code*/
920 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
921 LOG(log_error, logtype_afpd, "afp_setacl: cname got an error!");
924 if (!s_path->st_valid)
925 of_statdir(vol, s_path);
926 if ( s_path->st_errno != 0 ) {
927 LOG(log_error, logtype_afpd, "afp_setacl: cant stat");
930 LOG(log_debug, logtype_afpd, "afp_setacl: unixname: %s", s_path->u_name);
933 if ((unsigned long)ibuf & 1)
936 /* Start processing request */
938 /* Change owner: dont even try */
939 if (bitmap & kFileSec_UUID) {
940 LOG(log_debug, logtype_afpd, "afp_setacl: change owner request. discarded.");
942 ibuf += UUID_BINSIZE;
945 /* Change group: certain changes might be allowed, so try it. FIXME: not implemented yet. */
946 if (bitmap & kFileSec_UUID) {
947 LOG(log_debug, logtype_afpd, "afp_setacl: change group request. not supported this time.");
949 ibuf += UUID_BINSIZE;
953 if (bitmap & kFileSec_REMOVEACL) {
954 LOG(log_debug, logtype_afpd, "afp_setacl: Remove ACL request.");
955 if ((ret = remove_acl(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
956 LOG(log_error, logtype_afpd, "afp_setacl: error from remove_acl");
960 if (bitmap & kFileSec_ACL) {
961 LOG(log_debug, logtype_afpd, "afp_setacl: Change ACL request.");
963 /* Check if its our job to preserve inherited ACEs */
964 if (bitmap & kFileSec_Inherit)
965 ret = set_acl(vol, s_path->u_name, 1, ibuf);
967 ret = set_acl(vol, s_path->u_name, 0, ibuf);
974 LOG(log_debug9, logtype_afpd, "afp_setacl: END");
979 unix.c/accessmode calls this: map ACL to OS 9 mode
981 void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma)
985 int r_ok, w_ok, x_ok;
987 if ( ! (AFPobj->options.flags & OPTION_UUID) || ! (AFPobj->options.flags & OPTION_ACL2OS9MODE))
990 LOG(log_maxdebug, logtype_afpd, "acltoownermode('%s')", path);
992 if ((pw = getpwuid(uid)) == NULL) {
993 LOG(log_error, logtype_afpd, "acltoownermode: %s", strerror(errno));
997 /* We need the UUID for check_acl_access */
998 if ((getuuidfromname(pw->pw_name, UUID_USER, uuid)) != 0)
1001 /* These work for files and dirs */
1002 r_ok = check_acl_access(path, uuid, DARWIN_ACE_READ_DATA);
1003 w_ok = check_acl_access(path, uuid, (DARWIN_ACE_WRITE_DATA|DARWIN_ACE_APPEND_DATA));
1004 x_ok = check_acl_access(path, uuid, DARWIN_ACE_EXECUTE);
1006 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user before: %04o",ma->ma_user);
1008 ma->ma_user |= AR_UREAD;
1010 ma->ma_user |= AR_UWRITE;
1012 ma->ma_user |= AR_USEARCH;
1013 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user after: %04o", ma->ma_user);
1019 We're being called at the end of afp_createdir. We're (hopefully) inside dir
1020 and ".AppleDouble" and ".AppleDouble/.Parent" should have already been created.
1021 We then inherit any explicit ACE from "." to ".AppleDouble" and ".AppleDouble/.Parent".
1022 FIXME: add to VFS layer ?
1024 #ifdef HAVE_SOLARIS_ACLS
1025 void addir_inherit_acl(const struct vol *vol)
1027 ace_t *diraces = NULL, *adaces = NULL, *combinedaces = NULL;
1028 int diracecount, adacecount;
1030 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: BEGIN");
1032 /* Check if ACLs are enabled for the volume */
1033 if (vol->v_flags & AFPVOL_ACLS) {
1035 if ((diracecount = get_nfsv4_acl(".", &diraces)) <= 0)
1037 /* Remove any trivial ACE from "." */
1038 if ((diracecount = strip_trivial_aces(&diraces, diracecount)) <= 0)
1042 Inherit to ".AppleDouble"
1045 if ((adacecount = get_nfsv4_acl(".AppleDouble", &adaces)) <= 0)
1047 /* Remove any non-trivial ACE from ".AppleDouble" */
1048 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1052 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1055 /* Now set new acl */
1056 if ((acl(".AppleDouble", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1057 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1062 combinedaces = NULL;
1065 Inherit to ".AppleDouble/.Parent"
1068 if ((adacecount = get_nfsv4_acl(".AppleDouble/.Parent", &adaces)) <= 0)
1070 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1074 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1077 /* Now set new acl */
1078 if ((acl(".AppleDouble/.Parent", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1079 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1085 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: END");
1091 #endif /* HAVE_SOLARIS_ACLS */
1093 #ifdef HAVE_POSIX_ACLS
1094 void addir_inherit_acl(const struct vol *vol)
1098 #endif /* HAVE_POSIX_ACLS */