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 */
27 #if defined HAVE_SOLARIS_ACLS || defined HAVE_POSIX_ACLS
31 #include <atalk/adouble.h>
32 #include <atalk/vfs.h>
33 #include <atalk/afp.h>
34 #include <atalk/util.h>
35 #include <atalk/cnid.h>
36 #include <atalk/logger.h>
37 #include <atalk/uuid.h>
38 #include <atalk/acl.h>
40 #include "directory.h"
46 #include "acl_mappings.h"
49 #define SOLARIS_2_DARWIN 1
50 #define DARWIN_2_SOLARIS 2
51 #define POSIX_2_DARWIN 3
52 #define DARWIN_2_POSIX 4
54 /********************************************************
55 * Basic and helper funcs
56 ********************************************************/
59 Takes a users name, uid and primary gid and checks if user is member of any group
60 Returns -1 if no or error, 0 if yes
62 static int check_group(char *name, uid_t uid _U_, gid_t pgid, gid_t path_gid)
70 grp = getgrgid(path_gid);
75 while (grp->gr_mem[i] != NULL) {
76 if ( (strcmp(grp->gr_mem[i], name)) == 0 ) {
77 LOG(log_debug, logtype_afpd, "check_group: requested user:%s is member of: %s", name, grp->gr_name);
86 /********************************************************
88 ********************************************************/
90 #ifdef HAVE_SOLARIS_ACLS
92 Remove any trivial ACE "in-place". Returns no of non-trivial ACEs
94 static int strip_trivial_aces(ace_t **saces, int sacecount)
101 /* Count non-trivial ACEs */
102 for (i=0; i < sacecount; ) {
103 if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
107 /* malloc buffer for new ACL */
108 if ((new_aces = malloc(nontrivaces * sizeof(ace_t))) == NULL) {
109 LOG(log_error, logtype_afpd, "strip_trivial_aces: malloc %s", strerror(errno));
113 /* Copy non-trivial ACEs */
114 for (i=0, j=0; i < sacecount; ) {
115 if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
116 memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
125 LOG(log_debug7, logtype_afpd, "strip_trivial_aces: non-trivial ACEs: %d", nontrivaces);
131 Remove non-trivial ACEs "in-place". Returns no of trivial ACEs.
133 static int strip_nontrivial_aces(ace_t **saces, int sacecount)
137 ace_t *aces = *saces;
140 /* Count 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(trivaces * sizeof(ace_t))) == NULL) {
148 LOG(log_error, logtype_afpd, "strip_nontrivial_aces: malloc %s", strerror(errno));
152 /* Copy 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_nontrivial_aces: trivial ACEs: %d", trivaces);
172 static ace_t *concat_aces(ace_t *aces1, int ace1count, ace_t *aces2, int ace2count)
177 /* malloc buffer for new ACL */
178 if ((new_aces = malloc((ace1count + ace2count) * sizeof(ace_t))) == NULL) {
179 LOG(log_error, logtype_afpd, "combine_aces: malloc %s", strerror(errno));
183 /* Copy ACEs from buf1 */
184 for (i=0; i < ace1count; ) {
185 memcpy(&new_aces[i], &aces1[i], sizeof(ace_t));
191 /* Copy ACEs from buf2 */
192 for (i=0; i < ace2count; ) {
193 memcpy(&new_aces[j], &aces2[i], sizeof(ace_t));
202 Maps ACE array from Solaris to Darwin. Darwin ACEs are stored in network byte order.
203 Return numer of mapped ACEs or -1 on error.
204 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
206 static int map_aces_solaris_to_darwin(ace_t *aces, darwin_ace_t *darwin_aces, int ace_count)
211 struct passwd *pwd = NULL;
212 struct group *grp = NULL;
214 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing %d ACES", ace_count);
217 LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing ACE No. %d", ace_count + 1);
218 /* if its a ACE resulting from nfsv4 mode mapping, discard it */
219 if (aces->a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
220 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: trivial ACE");
225 if ( ! (aces->a_flags & ACE_IDENTIFIER_GROUP) ) {
227 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found user ACE with uid: %d", aces->a_who);
228 pwd = getpwuid(aces->a_who);
230 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getpwuid error: %s", strerror(errno));
233 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: uid: %d -> name: %s", aces->a_who, pwd->pw_name);
234 if ( (getuuidfromname(pwd->pw_name, UUID_USER, darwin_aces->darwin_ace_uuid)) != 0) {
235 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
239 /* its a group ace */
240 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found group ACE with gid: %d", aces->a_who);
241 grp = getgrgid(aces->a_who);
243 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getgrgid error: %s", strerror(errno));
246 LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: gid: %d -> name: %s", aces->a_who, grp->gr_name);
247 if ( (getuuidfromname(grp->gr_name, UUID_GROUP, darwin_aces->darwin_ace_uuid)) != 0) {
248 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
254 if (aces->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE)
255 flags = DARWIN_ACE_FLAGS_PERMIT;
256 else if (aces->a_type == ACE_ACCESS_DENIED_ACE_TYPE)
257 flags = DARWIN_ACE_FLAGS_DENY;
258 else { /* unsupported type */
262 for(i=0; nfsv4_to_darwin_flags[i].from != 0; i++) {
263 if (aces->a_flags & nfsv4_to_darwin_flags[i].from)
264 flags |= nfsv4_to_darwin_flags[i].to;
266 darwin_aces->darwin_ace_flags = htonl(flags);
270 for (i=0; nfsv4_to_darwin_rights[i].from != 0; i++) {
271 if (aces->a_access_mask & nfsv4_to_darwin_rights[i].from)
272 rights |= nfsv4_to_darwin_rights[i].to;
274 darwin_aces->darwin_ace_rights = htonl(rights);
285 Maps ACE array from Darwin to Solaris. Darwin ACEs are expected in network byte order.
286 Return numer of mapped ACEs or -1 on error.
287 All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
289 int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int ace_count)
291 int i, mapped_aces = 0;
292 uint32_t darwin_ace_flags;
293 uint32_t darwin_ace_rights;
294 uint16_t nfsv4_ace_flags;
295 uint32_t nfsv4_ace_rights;
303 nfsv4_ace_rights = 0;
306 if ( (getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype)) != 0)
308 if (uuidtype == UUID_USER) {
309 pwd = getpwnam(name);
311 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getpwnam: %s", strerror(errno));
314 nfsv4_aces->a_who = pwd->pw_uid;
315 } else { /* hopefully UUID_GROUP*/
316 grp = getgrnam(name);
318 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getgrnam: %s", strerror(errno));
321 nfsv4_aces->a_who = (uid_t)(grp->gr_gid);
322 nfsv4_ace_flags |= ACE_IDENTIFIER_GROUP;
327 /* now type: allow/deny */
328 darwin_ace_flags = ntohl(darwin_aces->darwin_ace_flags);
329 if (darwin_ace_flags & DARWIN_ACE_FLAGS_PERMIT)
330 nfsv4_aces->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
331 else if (darwin_ace_flags & DARWIN_ACE_FLAGS_DENY)
332 nfsv4_aces->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
333 else { /* unsupported type */
338 for(i=0; darwin_to_nfsv4_flags[i].from != 0; i++) {
339 if (darwin_ace_flags & darwin_to_nfsv4_flags[i].from)
340 nfsv4_ace_flags |= darwin_to_nfsv4_flags[i].to;
344 darwin_ace_rights = ntohl(darwin_aces->darwin_ace_rights);
345 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
346 if (darwin_ace_rights & darwin_to_nfsv4_rights[i].from)
347 nfsv4_ace_rights |= darwin_to_nfsv4_rights[i].to;
350 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE flags: Darwin:%08x -> NFSv4:%04x", darwin_ace_flags, nfsv4_ace_flags);
351 LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE rights: Darwin:%08x -> NFSv4:%08x", darwin_ace_rights, nfsv4_ace_rights);
353 nfsv4_aces->a_flags = nfsv4_ace_flags;
354 nfsv4_aces->a_access_mask = nfsv4_ace_rights;
363 #endif /* HAVE_SOLARIS_ACLS */
365 /* Map between ACL styles (SOLARIS_2_DARWIN, DARWIN_2_SOLARIS, POSIX_2_DARWIN, DARWIN_2_POSIX).
366 Reads from 'aces' buffer, writes to 'rbuf' buffer.
367 Caller must provide buffer.
368 Darwin ACEs are read and written in network byte order.
369 Needs to know how many ACEs are in the ACL (ace_count). Ignores trivial ACEs.
370 Return no of mapped ACEs or -1 on error. */
371 static int map_acl(int type, const void *aces, darwin_ace_t *buf, int ace_count)
374 #ifdef HAVE_SOLARIS_ACLS
375 ace_t *nfsv4_aces = (ace_t *)aces;
377 LOG(log_debug9, logtype_afpd, "map_acl: BEGIN");
381 #ifdef HAVE_SOLARIS_ACLS
382 case SOLARIS_2_DARWIN:
383 mapped_aces = map_aces_solaris_to_darwin( nfsv4_aces, buf, ace_count);
386 case DARWIN_2_SOLARIS:
387 mapped_aces = map_aces_darwin_to_solaris( buf, nfsv4_aces, ace_count);
389 #endif /* HAVE_SOLARIS_ACLS */
391 #ifdef HAVE_POSIX_ACLS
397 #endif /* HAVE_POSIX_ACLS */
404 LOG(log_debug9, logtype_afpd, "map_acl: END");
408 /* Get ACL from object omitting trivial ACEs. Map to Darwin ACL style and
409 store Darwin ACL at rbuf. Add length of ACL written to rbuf to *rbuflen.
410 Returns 0 on success, -1 on error. */
411 static int get_and_map_acl(char *name, char *rbuf, size_t *rbuflen)
413 int ace_count = 0, mapped_aces = 0, err;
414 uint32_t *darwin_ace_count = (u_int32_t *)rbuf;
415 #ifdef HAVE_SOLARIS_ACLS
419 LOG(log_debug9, logtype_afpd, "get_and_map_acl: BEGIN");
421 /* Skip length and flags */
426 #ifdef HAVE_SOLARIS_ACLS
427 if ( (ace_count = get_nfsv4_acl(name, &aces)) == -1) {
428 LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get ACL");
432 if ( (mapped_aces = map_acl(SOLARIS_2_DARWIN, aces, (darwin_ace_t *)rbuf, ace_count)) == -1) {
436 #endif /* HAVE_SOLARIS_ACLS */
438 #ifdef HAVE_POSIX_ACLS
439 acl_t defacl = NULL , accacl = NULL;
440 if ((defacl = acl_get_file(name, ACL_TYPE_DEFAULT)) == NULL && errno != ENOTDIR) {
441 LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get default ACL");
446 if (defacl && (mapped_aces = map_acl(POSIX_2_DARWIN,
448 (darwin_ace_t *)rbuf,
454 if ((accacl = acl_get_file(name, ACL_TYPE_ACCESS)) == NULL) {
455 LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get access ACL");
460 if (accacl && (mapped_aces += map_acl(POSIX_2_DARWIN,
462 (darwin_ace_t *)rbuf + mapped_aces * sizeof(darwin_ace_t),
467 #endif /* HAVE_POSIX_ACLS */
469 LOG(log_debug, logtype_afpd, "get_and_map_acl: mapped %d ACEs", mapped_aces);
472 *darwin_ace_count = htonl(mapped_aces);
473 *rbuflen += sizeof(darwin_acl_header_t) + (mapped_aces * sizeof(darwin_ace_t));
476 #ifdef HAVE_SOLARIS_ACLS
479 #ifdef HAVE_POSIX_ACLS
480 if (defacl) acl_free(defacl);
481 if (accacl) acl_free(accacl);
482 #endif /* HAVE_POSIX_ACLS */
484 LOG(log_debug9, logtype_afpd, "get_and_map_acl: END");
488 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
489 static int remove_acl(const struct vol *vol,const char *path, int dir)
493 /* Ressource etc. first */
494 if ((ret = vol->vfs->vfs_remove_acl(vol, path, dir)) != AFP_OK)
496 /* now the data fork or dir */
497 return (remove_acl_vfs(path));
502 - the client sends a complete list of ACEs, not only new ones. So we dont need to do
503 any combination business (one exception being 'kFileSec_Inherit': see next)
504 - client might request that we add inherited ACEs via 'kFileSec_Inherit'.
505 We will store inherited ACEs first, which is Darwins canonical order.
506 - returns AFPerror code
508 #ifdef HAVE_SOLARIS_ACLS
509 static int set_acl(const struct vol *vol, char *name, int inherit, char *ibuf)
511 int ret, i, nfsv4_ace_count, tocopy_aces_count = 0, new_aces_count = 0, trivial_ace_count = 0;
512 ace_t *old_aces, *new_aces = NULL;
516 LOG(log_debug9, logtype_afpd, "set_acl: BEGIN");
518 /* Get no of ACEs the client put on the wire */
519 ace_count = htonl(*((uint32_t *)ibuf));
520 ibuf += 8; /* skip ACL flags (see acls.h) */
523 /* inherited + trivial ACEs */
524 flags = ACE_INHERITED_ACE | ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
526 /* only trivial ACEs */
527 flags = ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
529 /* Get existing ACL and count ACEs which have to be copied */
530 if ((nfsv4_ace_count = get_nfsv4_acl(name, &old_aces)) == -1)
532 for ( i=0; i < nfsv4_ace_count; i++) {
533 if (old_aces[i].a_flags & flags)
537 /* Now malloc buffer exactly sized to fit all new ACEs */
538 new_aces = malloc( (ace_count + tocopy_aces_count) * sizeof(ace_t) );
539 if (new_aces == NULL) {
540 LOG(log_error, logtype_afpd, "set_acl: malloc %s", strerror(errno));
545 /* Start building new ACL */
547 /* Copy local inherited ACEs. Therefore we have 'Darwin canonical order' (see chmod there):
548 inherited ACEs first. */
550 for (i=0; i < nfsv4_ace_count; i++) {
551 if (old_aces[i].a_flags & ACE_INHERITED_ACE) {
552 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
557 LOG(log_debug7, logtype_afpd, "set_acl: copied %d inherited ACEs", new_aces_count);
559 /* Now the ACEs from the client */
560 ret = map_acl(DARWIN_2_SOLARIS, &new_aces[new_aces_count], (darwin_ace_t *)ibuf, ace_count);
565 new_aces_count += ace_count;
566 LOG(log_debug7, logtype_afpd, "set_acl: mapped %d ACEs from client", ace_count);
568 /* Now copy the trivial ACEs */
569 for (i=0; i < nfsv4_ace_count; i++) {
570 if (old_aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
571 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
576 LOG(log_debug7, logtype_afpd, "set_acl: copied %d trivial ACEs", trivial_ace_count);
578 /* Ressourcefork first.
579 Note: for dirs we set the same ACL on the .AppleDouble/.Parent _file_. This
580 might be strange for ACE_DELETE_CHILD and for inheritance flags. */
581 if ( (ret = vol->vfs->vfs_acl(vol, name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
582 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
583 if (errno == (EACCES | EPERM))
585 else if (errno == ENOENT)
591 if ( (ret = acl(name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
592 LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
593 if (errno == (EACCES | EPERM))
595 else if (errno == ENOENT)
608 LOG(log_debug9, logtype_afpd, "set_acl: END");
611 #endif /* HAVE_SOLARIS_ACLS */
613 #ifdef HAVE_POSIX_ACLS
614 static int set_acl(const struct vol *vol, char *name, int inherit, char *ibuf)
618 #endif /* HAVE_POSIX_ACLS */
621 Checks if a given UUID has requested_rights(type darwin_ace_rights) for path.
622 Note: this gets called frequently and is a good place for optimizations !
624 #ifdef HAVE_SOLARIS_ACLS
625 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
627 int ret, i, ace_count, dir, checkgroup;
628 char *username; /* might be group too */
632 uint32_t requested_rights = 0, allowed_rights = 0, denied_rights = 0;
636 int check_user_trivace = 0, check_group_trivace = 0;
643 LOG(log_debug9, logtype_afpd, "check_access: BEGIN. Request: %08x", requested_darwin_rights);
645 /* Get uid or gid from UUID */
646 if ( (getnamefromuuid(uuid, &username, &uuidtype)) != 0) {
647 LOG(log_error, logtype_afpd, "check_access: error getting name from UUID");
652 if ((lstat(path, &st)) != 0) {
653 LOG(log_error, logtype_afpd, "check_access: stat: %s", strerror(errno));
657 dir = S_ISDIR(st.st_mode);
659 if (uuidtype == UUID_USER) {
660 pwd = getpwnam(username);
662 LOG(log_error, logtype_afpd, "check_access: getpwnam: %s", strerror(errno));
669 /* If user is file/dir owner we must check the user trivial ACE */
670 if (uid == st.st_uid) {
671 LOG(log_debug, logtype_afpd, "check_access: user: %s is files owner. Must check trivial user ACE", username);
672 check_user_trivace = 1;
675 /* Now check if requested user is files owning group. If yes we must check the group trivial ACE */
676 if ( (check_group(username, uid, pgid, st.st_gid)) == 0) {
677 LOG(log_debug, logtype_afpd, "check_access: user: %s is in group: %d. Must check trivial group ACE", username, st.st_gid);
678 check_group_trivace = 1;
680 } else { /* hopefully UUID_GROUP*/
681 LOG(log_error, logtype_afpd, "check_access: afp_access for UUID of groups not supported!");
683 grp = getgrnam(username);
685 LOG(log_error, logtype_afpd, "check_access: getgrnam: %s", strerror(errno));
688 if (st.st_gid == grp->gr_gid )
689 check_group_trivace = 1;
693 /* Map requested rights to Solaris style. */
694 for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
695 if (requested_darwin_rights & darwin_to_nfsv4_rights[i].from)
696 requested_rights |= darwin_to_nfsv4_rights[i].to;
699 /* Get ACL from file/dir */
700 if ( (ace_count = get_nfsv4_acl(path, &aces)) == -1) {
701 LOG(log_error, logtype_afpd, "check_access: error getting ACEs");
705 /* Now check requested rights */
708 do { /* Loop through ACEs */
710 flags = aces[i].a_flags;
711 type = aces[i].a_type;
712 rights = aces[i].a_access_mask;
714 if (flags & ACE_INHERIT_ONLY_ACE)
717 /* Check if its a group ACE and set checkgroup to 1 if yes */
719 if ( (flags & ACE_IDENTIFIER_GROUP) && !(flags & ACE_GROUP) ) {
720 if ( (check_group(username, uid, pgid, who)) == 0)
726 /* Now the tricky part: decide if ACE effects our user. I'll explain:
727 if its a dedicated (non trivial) ACE for the user
729 if its a ACE for a group we're member of
731 if its a trivial ACE_OWNER ACE and requested UUID is the owner
733 if its a trivial ACE_GROUP ACE and requested UUID is group
735 if its a trivial ACE_EVERYONE ACE
739 ( (who == uid) && !(flags & (ACE_TRIVIAL|ACE_IDENTIFIER_GROUP)) ) ||
741 ( (flags & ACE_OWNER) && check_user_trivace ) ||
742 ( (flags & ACE_GROUP) && check_group_trivace ) ||
743 ( flags & ACE_EVERYONE )
745 /* Found an applicable ACE */
746 if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
747 allowed_rights |= rights;
748 else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
749 /* Only or to denied rights if not previously allowed !! */
750 denied_rights |= ((!allowed_rights) & rights);
752 } while (++i < ace_count);
755 /* Darwin likes to ask for "delete_child" on dir,
756 "write_data" is actually the same, so we add that for dirs */
757 if (dir && (allowed_rights & ACE_WRITE_DATA))
758 allowed_rights |= ACE_DELETE_CHILD;
760 if (requested_rights & denied_rights) {
761 LOG(log_debug, logtype_afpd, "check_access: some requested right was denied:");
763 } else if ((requested_rights & allowed_rights) != requested_rights) {
764 LOG(log_debug, logtype_afpd, "check_access: some requested right wasn't allowed:");
767 LOG(log_debug, logtype_afpd, "check_access: all requested rights are allowed:");
771 LOG(log_debug, logtype_afpd, "check_access: Requested rights: %08x, allowed_rights: %08x, denied_rights: %08x, Result: %d",
772 requested_rights, allowed_rights, denied_rights, ret);
778 LOG(log_debug9, logtype_afpd, "check_access: END");
782 #endif /* HAVE_SOLARIS_ACLS */
784 #ifdef HAVE_POSIX_ACLS
785 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
789 #endif /* HAVE_POSIX_ACLS */
791 /********************************************************
793 ********************************************************/
795 int afp_access(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
800 uint32_t did, darwin_ace_rights;
805 LOG(log_debug9, logtype_afpd, "afp_access: BEGIN");
810 memcpy(&vid, ibuf, sizeof( vid ));
812 if (NULL == ( vol = getvolbyvid( vid ))) {
813 LOG(log_error, logtype_afpd, "afp_access: error getting volid:%d", vid);
817 memcpy(&did, ibuf, sizeof( did ));
818 ibuf += sizeof( did );
819 if (NULL == ( dir = dirlookup( vol, did ))) {
820 LOG(log_error, logtype_afpd, "afp_access: error getting did:%d", did);
827 /* Store UUID address */
828 uuid = (uuidp_t)ibuf;
829 ibuf += UUID_BINSIZE;
831 /* Store ACE rights */
832 memcpy(&darwin_ace_rights, ibuf, 4);
833 darwin_ace_rights = ntohl(darwin_ace_rights);
836 /* get full path and handle file/dir subtleties in netatalk code*/
837 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
838 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
841 if (!s_path->st_valid)
842 of_statdir(vol, s_path);
843 if ( s_path->st_errno != 0 ) {
844 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
848 ret = check_acl_access(s_path->u_name, uuid, darwin_ace_rights);
850 LOG(log_debug9, logtype_afpd, "afp_access: END");
854 int afp_getacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
860 uint16_t vid, bitmap;
865 LOG(log_debug9, logtype_afpd, "afp_getacl: BEGIN");
869 memcpy(&vid, ibuf, sizeof( vid ));
871 if (NULL == ( vol = getvolbyvid( vid ))) {
872 LOG(log_error, logtype_afpd, "afp_getacl: error getting volid:%d", vid);
876 memcpy(&did, ibuf, sizeof( did ));
877 ibuf += sizeof( did );
878 if (NULL == ( dir = dirlookup( vol, did ))) {
879 LOG(log_error, logtype_afpd, "afp_getacl: error getting did:%d", did);
883 memcpy(&bitmap, ibuf, sizeof( bitmap ));
884 memcpy(rbuf, ibuf, sizeof( bitmap ));
885 bitmap = ntohs( bitmap );
886 ibuf += sizeof( bitmap );
887 rbuf += sizeof( bitmap );
888 *rbuflen += sizeof( bitmap );
890 /* skip maxreplysize */
893 /* get full path and handle file/dir subtleties in netatalk code*/
894 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
895 LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
898 if (!s_path->st_valid)
899 of_statdir(vol, s_path);
900 if ( s_path->st_errno != 0 ) {
901 LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
905 /* Shall we return owner UUID ? */
906 if (bitmap & kFileSec_UUID) {
907 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner user UUID");
908 if (NULL == (pw = getpwuid(s_path->st.st_uid)))
910 LOG(log_debug, logtype_afpd, "afp_getacl: got uid: %d, name: %s", s_path->st.st_uid, pw->pw_name);
911 if ((ret = getuuidfromname(pw->pw_name, UUID_USER, rbuf)) != 0)
913 rbuf += UUID_BINSIZE;
914 *rbuflen += UUID_BINSIZE;
917 /* Shall we return group UUID ? */
918 if (bitmap & kFileSec_GRPUUID) {
919 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner group UUID");
920 if (NULL == (gr = getgrgid(s_path->st.st_gid)))
922 LOG(log_debug, logtype_afpd, "afp_getacl: got gid: %d, name: %s", s_path->st.st_gid, gr->gr_name);
923 if ((ret = getuuidfromname(gr->gr_name, UUID_GROUP, rbuf)) != 0)
925 rbuf += UUID_BINSIZE;
926 *rbuflen += UUID_BINSIZE;
929 /* Shall we return ACL ? */
930 if (bitmap & kFileSec_ACL) {
931 LOG(log_debug, logtype_afpd, "afp_getacl: client requested files ACL");
932 get_and_map_acl(s_path->u_name, rbuf, rbuflen);
935 LOG(log_debug9, logtype_afpd, "afp_getacl: END");
939 int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
945 uint16_t vid, bitmap;
948 LOG(log_debug9, logtype_afpd, "afp_setacl: BEGIN");
952 memcpy(&vid, ibuf, sizeof( vid ));
954 if (NULL == ( vol = getvolbyvid( vid ))) {
955 LOG(log_error, logtype_afpd, "afp_setacl: error getting volid:%d", vid);
959 memcpy(&did, ibuf, sizeof( did ));
960 ibuf += sizeof( did );
961 if (NULL == ( dir = dirlookup( vol, did ))) {
962 LOG(log_error, logtype_afpd, "afp_setacl: error getting did:%d", did);
966 memcpy(&bitmap, ibuf, sizeof( bitmap ));
967 bitmap = ntohs( bitmap );
968 ibuf += sizeof( bitmap );
970 /* get full path and handle file/dir subtleties in netatalk code*/
971 if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
972 LOG(log_error, logtype_afpd, "afp_setacl: cname got an error!");
975 if (!s_path->st_valid)
976 of_statdir(vol, s_path);
977 if ( s_path->st_errno != 0 ) {
978 LOG(log_error, logtype_afpd, "afp_setacl: cant stat");
981 LOG(log_debug, logtype_afpd, "afp_setacl: unixname: %s", s_path->u_name);
984 if ((unsigned long)ibuf & 1)
987 /* Start processing request */
989 /* Change owner: dont even try */
990 if (bitmap & kFileSec_UUID) {
991 LOG(log_debug, logtype_afpd, "afp_setacl: change owner request. discarded.");
993 ibuf += UUID_BINSIZE;
996 /* Change group: certain changes might be allowed, so try it. FIXME: not implemented yet. */
997 if (bitmap & kFileSec_UUID) {
998 LOG(log_debug, logtype_afpd, "afp_setacl: change group request. not supported this time.");
1000 ibuf += UUID_BINSIZE;
1004 if (bitmap & kFileSec_REMOVEACL) {
1005 LOG(log_debug, logtype_afpd, "afp_setacl: Remove ACL request.");
1006 if ((ret = remove_acl(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
1007 LOG(log_error, logtype_afpd, "afp_setacl: error from remove_acl");
1011 if (bitmap & kFileSec_ACL) {
1012 LOG(log_debug, logtype_afpd, "afp_setacl: Change ACL request.");
1014 /* Check if its our job to preserve inherited ACEs */
1015 if (bitmap & kFileSec_Inherit)
1016 ret = set_acl(vol, s_path->u_name, 1, ibuf);
1018 ret = set_acl(vol, s_path->u_name, 0, ibuf);
1025 LOG(log_debug9, logtype_afpd, "afp_setacl: END");
1030 unix.c/accessmode calls this: map ACL to OS 9 mode
1032 void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma)
1036 int r_ok, w_ok, x_ok;
1038 if ( ! (AFPobj->options.flags & OPTION_UUID) || ! (AFPobj->options.flags & OPTION_ACL2OS9MODE))
1041 LOG(log_maxdebug, logtype_afpd, "acltoownermode('%s')", path);
1043 if ((pw = getpwuid(uid)) == NULL) {
1044 LOG(log_error, logtype_afpd, "acltoownermode: %s", strerror(errno));
1048 /* We need the UUID for check_acl_access */
1049 if ((getuuidfromname(pw->pw_name, UUID_USER, uuid)) != 0)
1052 /* These work for files and dirs */
1053 r_ok = check_acl_access(path, uuid, DARWIN_ACE_READ_DATA);
1054 w_ok = check_acl_access(path, uuid, (DARWIN_ACE_WRITE_DATA|DARWIN_ACE_APPEND_DATA));
1055 x_ok = check_acl_access(path, uuid, DARWIN_ACE_EXECUTE);
1057 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user before: %04o",ma->ma_user);
1059 ma->ma_user |= AR_UREAD;
1061 ma->ma_user |= AR_UWRITE;
1063 ma->ma_user |= AR_USEARCH;
1064 LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user after: %04o", ma->ma_user);
1070 We're being called at the end of afp_createdir. We're (hopefully) inside dir
1071 and ".AppleDouble" and ".AppleDouble/.Parent" should have already been created.
1072 We then inherit any explicit ACE from "." to ".AppleDouble" and ".AppleDouble/.Parent".
1073 FIXME: add to VFS layer ?
1075 #ifdef HAVE_SOLARIS_ACLS
1076 void addir_inherit_acl(const struct vol *vol)
1078 ace_t *diraces = NULL, *adaces = NULL, *combinedaces = NULL;
1079 int diracecount, adacecount;
1081 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: BEGIN");
1083 /* Check if ACLs are enabled for the volume */
1084 if (vol->v_flags & AFPVOL_ACLS) {
1086 if ((diracecount = get_nfsv4_acl(".", &diraces)) <= 0)
1088 /* Remove any trivial ACE from "." */
1089 if ((diracecount = strip_trivial_aces(&diraces, diracecount)) <= 0)
1093 Inherit to ".AppleDouble"
1096 if ((adacecount = get_nfsv4_acl(".AppleDouble", &adaces)) <= 0)
1098 /* Remove any non-trivial ACE from ".AppleDouble" */
1099 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1103 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1106 /* Now set new acl */
1107 if ((acl(".AppleDouble", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1108 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1113 combinedaces = NULL;
1116 Inherit to ".AppleDouble/.Parent"
1119 if ((adacecount = get_nfsv4_acl(".AppleDouble/.Parent", &adaces)) <= 0)
1121 if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1125 if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1128 /* Now set new acl */
1129 if ((acl(".AppleDouble/.Parent", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1130 LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1136 LOG(log_debug9, logtype_afpd, "addir_inherit_acl: END");
1142 #endif /* HAVE_SOLARIS_ACLS */
1144 #ifdef HAVE_POSIX_ACLS
1145 void addir_inherit_acl(const struct vol *vol)
1149 #endif /* HAVE_POSIX_ACLS */