]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/acls.c
Merge from 2-1
[netatalk.git] / etc / afpd / acls.c
1 /*
2   Copyright (c) 2008, 2009, 2010 Frank Lahm <franklahm@gmail.com>
3
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.
8
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.
13 */
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif /* HAVE_CONFIG_H */
18
19 #include <string.h>
20 #include <strings.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <grp.h>
24 #include <pwd.h>
25 #include <errno.h>
26 #ifdef HAVE_SOLARIS_ACLS
27 #include <sys/acl.h>
28 #endif
29 #ifdef HAVE_POSIX_ACLS
30 #include <sys/acl.h>
31 #include <acl/libacl.h>
32 #endif
33
34 #include <atalk/adouble.h>
35 #include <atalk/vfs.h>
36 #include <atalk/afp.h>
37 #include <atalk/util.h>
38 #include <atalk/cnid.h>
39 #include <atalk/logger.h>
40 #include <atalk/uuid.h>
41 #include <atalk/acl.h>
42
43 #include "directory.h"
44 #include "desktop.h"
45 #include "volume.h"
46 #include "fork.h"
47
48 #include "acls.h"
49 #include "acl_mappings.h"
50
51 /* for map_acl() */
52 #define SOLARIS_2_DARWIN       1
53 #define DARWIN_2_SOLARIS       2
54 #define POSIX_DEFAULT_2_DARWIN 3
55 #define POSIX_ACCESS_2_DARWIN  4
56 #define DARWIN_2_POSIX         5
57
58 #define MAP_MASK               31
59 #define IS_DIR                 32
60
61 /********************************************************
62  * Basic and helper funcs
63  ********************************************************/
64
65 /*
66   Takes a users name, uid and primary gid and checks if user is member of any group
67   Returns -1 if no or error, 0 if yes
68 */
69 static int check_group(char *name, uid_t uid _U_, gid_t pgid, gid_t path_gid)
70 {
71     int i;
72     struct group *grp;
73
74     if (pgid == path_gid)
75         return 0;
76
77     grp = getgrgid(path_gid);
78     if (!grp)
79         return -1;
80
81     i = 0;
82     while (grp->gr_mem[i] != NULL) {
83         if ( (strcmp(grp->gr_mem[i], name)) == 0 ) {
84             LOG(log_debug, logtype_afpd, "check_group: requested user:%s is member of: %s", name, grp->gr_name);
85             return 0;
86         }
87         i++;
88     }
89
90     return -1;
91 }
92
93 /********************************************************
94  * Solaris funcs
95  ********************************************************/
96
97 #ifdef HAVE_SOLARIS_ACLS
98 /*
99   Remove any trivial ACE "in-place". Returns no of non-trivial ACEs
100 */
101 static int strip_trivial_aces(ace_t **saces, int sacecount)
102 {
103     int i,j;
104     int nontrivaces = 0;
105     ace_t *aces = *saces;
106     ace_t *new_aces;
107
108     /* Count non-trivial ACEs */
109     for (i=0; i < sacecount; ) {
110         if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
111             nontrivaces++;
112         i++;
113     }
114     /* malloc buffer for new ACL */
115     if ((new_aces = malloc(nontrivaces * sizeof(ace_t))) == NULL) {
116         LOG(log_error, logtype_afpd, "strip_trivial_aces: malloc %s", strerror(errno));
117         return -1;
118     }
119
120     /* Copy non-trivial ACEs */
121     for (i=0, j=0; i < sacecount; ) {
122         if ( ! (aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
123             memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
124             j++;
125         }
126         i++;
127     }
128
129     free(aces);
130     *saces = new_aces;
131
132     LOG(log_debug7, logtype_afpd, "strip_trivial_aces: non-trivial ACEs: %d", nontrivaces);
133
134     return nontrivaces;
135 }
136
137 /*
138   Remove non-trivial ACEs "in-place". Returns no of trivial ACEs.
139 */
140 static int strip_nontrivial_aces(ace_t **saces, int sacecount)
141 {
142     int i,j;
143     int trivaces = 0;
144     ace_t *aces = *saces;
145     ace_t *new_aces;
146
147     /* Count trivial ACEs */
148     for (i=0; i < sacecount; ) {
149         if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)))
150             trivaces++;
151         i++;
152     }
153     /* malloc buffer for new ACL */
154     if ((new_aces = malloc(trivaces * sizeof(ace_t))) == NULL) {
155         LOG(log_error, logtype_afpd, "strip_nontrivial_aces: malloc %s", strerror(errno));
156         return -1;
157     }
158
159     /* Copy trivial ACEs */
160     for (i=0, j=0; i < sacecount; ) {
161         if ((aces[i].a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE))) {
162             memcpy(&new_aces[j], &aces[i], sizeof(ace_t));
163             j++;
164         }
165         i++;
166     }
167     /* Free old ACEs */
168     free(aces);
169     *saces = new_aces;
170
171     LOG(log_debug7, logtype_afpd, "strip_nontrivial_aces: trivial ACEs: %d", trivaces);
172
173     return trivaces;
174 }
175
176 /*
177   Concatenate ACEs
178 */
179 static ace_t *concat_aces(ace_t *aces1, int ace1count, ace_t *aces2, int ace2count)
180 {
181     ace_t *new_aces;
182     int i, j;
183
184     /* malloc buffer for new ACL */
185     if ((new_aces = malloc((ace1count + ace2count) * sizeof(ace_t))) == NULL) {
186         LOG(log_error, logtype_afpd, "combine_aces: malloc %s", strerror(errno));
187         return NULL;
188     }
189
190     /* Copy ACEs from buf1 */
191     for (i=0; i < ace1count; ) {
192         memcpy(&new_aces[i], &aces1[i], sizeof(ace_t));
193         i++;
194     }
195
196     j = i;
197
198     /* Copy ACEs from buf2 */
199     for (i=0; i < ace2count; ) {
200         memcpy(&new_aces[j], &aces2[i], sizeof(ace_t));
201         i++;
202         j++;
203     }
204     return new_aces;
205 }
206
207
208 /*
209   Maps ACE array from Solaris to Darwin. Darwin ACEs are stored in network byte order.
210   Return numer of mapped ACEs or -1 on error.
211   All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
212 */
213 static int map_aces_solaris_to_darwin(ace_t *aces, darwin_ace_t *darwin_aces, int ace_count)
214 {
215     int i, count = 0;
216     uint32_t flags;
217     uint32_t rights;
218     struct passwd *pwd = NULL;
219     struct group *grp = NULL;
220
221     LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing %d ACES", ace_count);
222
223     while(ace_count--) {
224         LOG(log_debug7, logtype_afpd, "map_aces_solaris_to_darwin: parsing ACE No. %d", ace_count + 1);
225         /* if its a ACE resulting from nfsv4 mode mapping, discard it */
226         if (aces->a_flags & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
227             LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: trivial ACE");
228             aces++;
229             continue;
230         }
231
232         if ( ! (aces->a_flags & ACE_IDENTIFIER_GROUP) ) {
233             /* its a user ace */
234             LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found user ACE with uid: %d", aces->a_who);
235             pwd = getpwuid(aces->a_who);
236             if (!pwd) {
237                 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getpwuid error: %s", strerror(errno));
238                 return -1;
239             }
240             LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: uid: %d -> name: %s", aces->a_who, pwd->pw_name);
241             if ( (getuuidfromname(pwd->pw_name, UUID_USER, darwin_aces->darwin_ace_uuid)) != 0) {
242                 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
243                 return -1;
244             }
245         } else {
246             /* its a group ace */
247             LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: found group ACE with gid: %d", aces->a_who);
248             grp = getgrgid(aces->a_who);
249             if (!grp) {
250                 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getgrgid error: %s", strerror(errno));
251                 return -1;
252             }
253             LOG(log_debug, logtype_afpd, "map_aces_solaris_to_darwin: gid: %d -> name: %s", aces->a_who, grp->gr_name);
254             if ( (getuuidfromname(grp->gr_name, UUID_GROUP, darwin_aces->darwin_ace_uuid)) != 0) {
255                 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
256                 return -1;
257             }
258         }
259
260         /* map flags */
261         if (aces->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE)
262             flags = DARWIN_ACE_FLAGS_PERMIT;
263         else if (aces->a_type == ACE_ACCESS_DENIED_ACE_TYPE)
264             flags = DARWIN_ACE_FLAGS_DENY;
265         else {          /* unsupported type */
266             aces++;
267             continue;
268         }
269         for(i=0; nfsv4_to_darwin_flags[i].from != 0; i++) {
270             if (aces->a_flags & nfsv4_to_darwin_flags[i].from)
271                 flags |= nfsv4_to_darwin_flags[i].to;
272         }
273         darwin_aces->darwin_ace_flags = htonl(flags);
274
275         /* map rights */
276         rights = 0;
277         for (i=0; nfsv4_to_darwin_rights[i].from != 0; i++) {
278             if (aces->a_access_mask & nfsv4_to_darwin_rights[i].from)
279                 rights |= nfsv4_to_darwin_rights[i].to;
280         }
281         darwin_aces->darwin_ace_rights = htonl(rights);
282
283         count++;
284         aces++;
285         darwin_aces++;
286     }
287
288     return count;
289 }
290
291 /*
292   Maps ACE array from Darwin to Solaris. Darwin ACEs are expected in network byte order.
293   Return numer of mapped ACEs or -1 on error.
294   All errors while mapping (e.g. getting UUIDs from LDAP) are fatal.
295 */
296 int map_aces_darwin_to_solaris(darwin_ace_t *darwin_aces, ace_t *nfsv4_aces, int ace_count)
297 {
298     int i, mapped_aces = 0;
299     uint32_t darwin_ace_flags;
300     uint32_t darwin_ace_rights;
301     uint16_t nfsv4_ace_flags;
302     uint32_t nfsv4_ace_rights;
303     char *name;
304     uuidtype_t uuidtype;
305     struct passwd *pwd;
306     struct group *grp;
307
308     while(ace_count--) {
309         nfsv4_ace_flags = 0;
310         nfsv4_ace_rights = 0;
311
312         /* uid/gid first */
313         if ( (getnamefromuuid(darwin_aces->darwin_ace_uuid, &name, &uuidtype)) != 0)
314             return -1;
315         if (uuidtype == UUID_USER) {
316             pwd = getpwnam(name);
317             if (!pwd) {
318                 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getpwnam: %s", strerror(errno));
319                 return -1;
320             }
321             nfsv4_aces->a_who = pwd->pw_uid;
322         } else { /* hopefully UUID_GROUP*/
323             grp = getgrnam(name);
324             if (!grp) {
325                 LOG(log_error, logtype_afpd, "map_aces_darwin_to_solaris: getgrnam: %s", strerror(errno));
326                 return -1;
327             }
328             nfsv4_aces->a_who = (uid_t)(grp->gr_gid);
329             nfsv4_ace_flags |= ACE_IDENTIFIER_GROUP;
330         }
331         free(name);
332         name = NULL;
333
334         /* now type: allow/deny */
335         darwin_ace_flags = ntohl(darwin_aces->darwin_ace_flags);
336         if (darwin_ace_flags & DARWIN_ACE_FLAGS_PERMIT)
337             nfsv4_aces->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
338         else if (darwin_ace_flags & DARWIN_ACE_FLAGS_DENY)
339             nfsv4_aces->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
340         else { /* unsupported type */
341             darwin_aces++;
342             continue;
343         }
344         /* map flags */
345         for(i=0; darwin_to_nfsv4_flags[i].from != 0; i++) {
346             if (darwin_ace_flags & darwin_to_nfsv4_flags[i].from)
347                 nfsv4_ace_flags |= darwin_to_nfsv4_flags[i].to;
348         }
349
350         /* map rights */
351         darwin_ace_rights = ntohl(darwin_aces->darwin_ace_rights);
352         for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
353             if (darwin_ace_rights & darwin_to_nfsv4_rights[i].from)
354                 nfsv4_ace_rights |= darwin_to_nfsv4_rights[i].to;
355         }
356
357         LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE flags: Darwin:%08x -> NFSv4:%04x", darwin_ace_flags, nfsv4_ace_flags);
358         LOG(log_debug9, logtype_afpd, "map_aces_darwin_to_solaris: ACE rights: Darwin:%08x -> NFSv4:%08x", darwin_ace_rights, nfsv4_ace_rights);
359
360         nfsv4_aces->a_flags = nfsv4_ace_flags;
361         nfsv4_aces->a_access_mask = nfsv4_ace_rights;
362
363         mapped_aces++;
364         darwin_aces++;
365         nfsv4_aces++;
366     }
367
368     return mapped_aces;
369 }
370 #endif /* HAVE_SOLARIS_ACLS */
371
372 /*
373  * Map ACEs from POSIX to Darwin.
374  * type is either POSIX_DEFAULT_2_DARWIN or POSIX_ACCESS_2_DARWIN, cf. acl_get_file.
375  * Return number of mapped ACES, -1 on error.
376  */
377 #ifdef HAVE_POSIX_ACLS
378 static int map_acl_posix_to_darwin(int type, const acl_t acl, darwin_ace_t *darwin_aces)
379 {
380     int mapped_aces = 0;
381     int havemask = 0;
382     int entry_id = ACL_FIRST_ENTRY;
383     acl_entry_t e;
384     acl_tag_t tag;
385     acl_permset_t permset, mask;
386     uid_t *uid = NULL;
387     gid_t *gid = NULL;
388     struct passwd *pwd = NULL;
389     struct group *grp = NULL;
390     uint32_t flags;
391     uint32_t rights;
392     darwin_ace_t *saved_darwin_aces = darwin_aces;
393
394     LOG(log_maxdebug, logtype_afpd, "map_aces_posix_to_darwin(%s)",
395         (type & MAP_MASK) == POSIX_DEFAULT_2_DARWIN ?
396         "POSIX_DEFAULT_2_DARWIN" : "POSIX_ACCESS_2_DARWIN");
397
398     /* itereate through all ACEs */
399     while (acl_get_entry(acl, entry_id, &e) == 1) {
400         entry_id = ACL_NEXT_ENTRY;
401
402         /* get ACE type */
403         if (acl_get_tag_type(e, &tag) != 0) {
404             LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: acl_get_tag_type: %s", strerror(errno));
405             mapped_aces = -1;
406             goto exit;
407         }
408
409         /* we return user and group ACE */
410         switch (tag) {
411         case ACL_USER:
412             if ((uid = (uid_t *)acl_get_qualifier(e)) == NULL) {
413                 LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: acl_get_qualifier: %s",
414                     strerror(errno));
415                 mapped_aces = -1;
416                 goto exit;
417             }
418             if ((pwd = getpwuid(*uid)) == NULL) {
419                 LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: getpwuid error: %s",
420                     strerror(errno));
421                 mapped_aces = -1;
422                 goto exit;
423             }
424             LOG(log_debug, logtype_afpd, "map_aces_posix_to_darwin: uid: %d -> name: %s",
425                 *uid, pwd->pw_name);
426             if (getuuidfromname(pwd->pw_name, UUID_USER, darwin_aces->darwin_ace_uuid) != 0) {
427                 LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: getuuidfromname error");
428                 mapped_aces = -1;
429                 goto exit;
430             }
431             acl_free(uid);
432             uid = NULL;
433             break;
434
435         case ACL_GROUP:
436             if ((gid = (gid_t *)acl_get_qualifier(e)) == NULL) {
437                 LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: acl_get_qualifier: %s",
438                     strerror(errno));
439                 mapped_aces = -1;
440                 goto exit;
441             }
442             if ((grp = getgrgid(*gid)) == NULL) {
443                 LOG(log_error, logtype_afpd, "map_aces_posix_to_darwin: getgrgid error: %s",
444                     strerror(errno));
445                 mapped_aces = -1;
446                 goto exit;
447             }
448             LOG(log_debug, logtype_afpd, "map_aces_posix_to_darwin: gid: %d -> name: %s",
449                 *gid, grp->gr_name);
450             if (getuuidfromname(grp->gr_name, UUID_GROUP, darwin_aces->darwin_ace_uuid) != 0) {
451                 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: getuuidfromname error");
452                 mapped_aces = -1;
453                 goto exit;
454             }
455             acl_free(gid);
456             gid = NULL;
457             break;
458
459             /* store mask so we can apply it later in a second loop */
460         case ACL_MASK:
461             if (acl_get_permset(e, &mask) != 0) {
462                 LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: acl_get_permset: %s", strerror(errno));
463                 return -1;
464             }
465             havemask = 1;
466             continue;
467
468         default:
469             continue;
470         }
471
472         /* flags */
473         flags = DARWIN_ACE_FLAGS_PERMIT;
474         if ((type & MAP_MASK) == POSIX_DEFAULT_2_DARWIN)
475             flags |= DARWIN_ACE_FLAGS_FILE_INHERIT
476                 | DARWIN_ACE_FLAGS_DIRECTORY_INHERIT
477                 | DARWIN_ACE_FLAGS_ONLY_INHERIT;
478         darwin_aces->darwin_ace_flags = htonl(flags);
479
480         /* rights */
481         if (acl_get_permset(e, &permset) != 0) {
482             LOG(log_error, logtype_afpd, "map_aces_solaris_to_darwin: acl_get_permset: %s", strerror(errno));
483             return -1;
484         }
485
486         rights = 0;
487         if (acl_get_perm(permset, ACL_READ))
488             rights = DARWIN_ACE_READ_DATA
489                 | DARWIN_ACE_READ_EXTATTRIBUTES
490                 | DARWIN_ACE_READ_ATTRIBUTES
491                 | DARWIN_ACE_READ_SECURITY;
492         if (acl_get_perm(permset, ACL_WRITE)) {
493             rights |= DARWIN_ACE_WRITE_DATA
494                 | DARWIN_ACE_APPEND_DATA
495                 | DARWIN_ACE_WRITE_EXTATTRIBUTES
496                 | DARWIN_ACE_WRITE_ATTRIBUTES;
497             if ((type & ~MAP_MASK) == IS_DIR)
498                 rights |= DARWIN_ACE_DELETE;
499         }
500         if (acl_get_perm(permset, ACL_EXECUTE))
501             rights |= DARWIN_ACE_EXECUTE;
502
503         darwin_aces->darwin_ace_rights = htonl(rights);
504
505         darwin_aces++;
506         mapped_aces++;
507     } /* while */
508
509     if (havemask) {
510         /* Loop through the mapped ACE buffer once again, applying the mask */
511         /* Map the mask to Darwin ACE rights first */
512         rights = 0;
513         if (acl_get_perm(mask, ACL_READ))
514             rights = DARWIN_ACE_READ_DATA
515                 | DARWIN_ACE_READ_EXTATTRIBUTES
516                 | DARWIN_ACE_READ_ATTRIBUTES
517                 | DARWIN_ACE_READ_SECURITY;
518         if (acl_get_perm(mask, ACL_WRITE)) {
519             rights |= DARWIN_ACE_WRITE_DATA
520                 | DARWIN_ACE_APPEND_DATA
521                 | DARWIN_ACE_WRITE_EXTATTRIBUTES
522                 | DARWIN_ACE_WRITE_ATTRIBUTES;
523             if ((type & ~MAP_MASK) == IS_DIR)
524                 rights |= DARWIN_ACE_DELETE;
525         }
526         if (acl_get_perm(mask, ACL_EXECUTE))
527             rights |= DARWIN_ACE_EXECUTE;
528         for (int i = mapped_aces; i > 0; i--) {
529             saved_darwin_aces->darwin_ace_rights &= htonl(rights);
530             saved_darwin_aces++;
531         }
532     }
533
534 exit:
535     if (uid) acl_free(uid);
536     if (gid) acl_free(gid);
537
538     return mapped_aces;
539 }
540 #endif
541
542 /*
543  * Multiplex ACL mapping (SOLARIS_2_DARWIN, DARWIN_2_SOLARIS, POSIX_2_DARWIN, DARWIN_2_POSIX).
544  * Reads from 'aces' buffer, writes to 'rbuf' buffer.
545  * Caller must provide buffer.
546  * Darwin ACEs are read and written in network byte order.
547  * Needs to know how many ACEs are in the ACL (ace_count) for Solaris ACLs.
548  * Ignores trivial ACEs.
549  * Return no of mapped ACEs or -1 on error.
550  */
551 static int map_acl(int type, const void *acl, darwin_ace_t *buf, int ace_count)
552 {
553     int mapped_aces;
554
555     LOG(log_debug9, logtype_afpd, "map_acl: BEGIN");
556
557     switch (type & MAP_MASK) {
558
559 #ifdef HAVE_SOLARIS_ACLS
560     case SOLARIS_2_DARWIN:
561         mapped_aces = map_aces_solaris_to_darwin( acl, buf, ace_count);
562         break;
563
564     case DARWIN_2_SOLARIS:
565         mapped_aces = map_aces_darwin_to_solaris( buf, acl, ace_count);
566         break;
567 #endif /* HAVE_SOLARIS_ACLS */
568
569 #ifdef HAVE_POSIX_ACLS
570     case POSIX_DEFAULT_2_DARWIN:
571         mapped_aces = map_acl_posix_to_darwin(type, (const acl_t)acl, buf);
572         break;
573
574     case POSIX_ACCESS_2_DARWIN:
575         mapped_aces = map_acl_posix_to_darwin(type, (const acl_t)acl, buf);
576         break;
577
578     case DARWIN_2_POSIX:
579         break;
580 #endif /* HAVE_POSIX_ACLS */
581
582     default:
583         mapped_aces = -1;
584         break;
585     }
586
587     LOG(log_debug9, logtype_afpd, "map_acl: END");
588     return mapped_aces;
589 }
590
591 /* Get ACL from object omitting trivial ACEs. Map to Darwin ACL style and
592    store Darwin ACL at rbuf. Add length of ACL written to rbuf to *rbuflen.
593    Returns 0 on success, -1 on error. */
594 static int get_and_map_acl(char *name, char *rbuf, size_t *rbuflen)
595 {
596     int ace_count = 0;
597     int mapped_aces = 0;
598     int err, dirflag;
599     uint32_t *darwin_ace_count = (u_int32_t *)rbuf;
600 #ifdef HAVE_SOLARIS_ACLS
601     ace_t *aces;
602 #endif
603 #ifdef HAVE_POSIX_ACLS
604     struct stat st;
605 #endif
606     LOG(log_debug9, logtype_afpd, "get_and_map_acl: BEGIN");
607
608     /* Skip length and flags */
609     rbuf += 4;
610     *rbuf = 0;
611     rbuf += 4;
612
613 #ifdef HAVE_SOLARIS_ACLS
614     if ( (ace_count = get_nfsv4_acl(name, &aces)) == -1) {
615         LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get ACL");
616         return -1;
617     }
618
619     if ( (mapped_aces = map_acl(SOLARIS_2_DARWIN, aces, (darwin_ace_t *)rbuf, ace_count)) == -1) {
620         err = -1;
621         goto cleanup;
622     }
623 #endif /* HAVE_SOLARIS_ACLS */
624
625 #ifdef HAVE_POSIX_ACLS
626     acl_t defacl = NULL , accacl = NULL;
627
628     /* stat to check if its a dir */
629     if (stat(name, &st) != 0) {
630         LOG(log_error, logtype_afpd, "get_and_map_acl: stat: %s", strerror(errno));
631         err = -1;
632         goto cleanup;
633     }
634
635     /* if its a dir, check for default acl too */
636     dirflag = 0;
637     if (S_ISDIR(st.st_mode)) {
638         dirflag = IS_DIR;
639         if ((defacl = acl_get_file(name, ACL_TYPE_DEFAULT)) == NULL) {
640             LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get default ACL"); err = -1; goto cleanup;
641         }        
642         if (defacl && (mapped_aces = map_acl(POSIX_DEFAULT_2_DARWIN | dirflag,
643                                              defacl,
644                                              (darwin_ace_t *)rbuf,
645                                              0)) == -1) {
646             err = -1; goto cleanup;
647         }
648     }
649
650     if ((accacl = acl_get_file(name, ACL_TYPE_ACCESS)) == NULL) {
651         LOG(log_error, logtype_afpd, "get_and_map_acl: couldnt get access ACL"); err = -1; goto cleanup;
652     }
653
654     if (accacl && (mapped_aces += map_acl(POSIX_ACCESS_2_DARWIN | dirflag,
655                                           accacl,
656                                           (darwin_ace_t *)(rbuf + mapped_aces * sizeof(darwin_ace_t)),
657                                           0)) == -1) {
658         err = -1; goto cleanup;
659     }
660 #endif /* HAVE_POSIX_ACLS */
661
662     LOG(log_debug, logtype_afpd, "get_and_map_acl: mapped %d ACEs", mapped_aces);
663
664     err = 0;
665     *darwin_ace_count = htonl(mapped_aces);
666     *rbuflen += sizeof(darwin_acl_header_t) + (mapped_aces * sizeof(darwin_ace_t));
667
668 cleanup:
669 #ifdef HAVE_SOLARIS_ACLS
670     free(aces);
671 #endif
672 #ifdef HAVE_POSIX_ACLS
673     if (defacl) acl_free(defacl);
674     if (accacl) acl_free(accacl);
675 #endif /* HAVE_POSIX_ACLS */
676
677     LOG(log_debug9, logtype_afpd, "get_and_map_acl: END");
678     return err;
679 }
680
681 /* Removes all non-trivial ACLs from object. Returns full AFPERR code. */
682 static int remove_acl(const struct vol *vol,const char *path, int dir)
683 {
684     int ret;
685
686     /* Ressource etc. first */
687     if ((ret = vol->vfs->vfs_remove_acl(vol, path, dir)) != AFP_OK)
688         return ret;
689     /* now the data fork or dir */
690     return (remove_acl_vfs(path));
691 }
692
693 /*
694   Set ACL. Subtleties:
695   - the client sends a complete list of ACEs, not only new ones. So we dont need to do
696   any combination business (one exception being 'kFileSec_Inherit': see next)
697   - client might request that we add inherited ACEs via 'kFileSec_Inherit'.
698   We will store inherited ACEs first, which is Darwins canonical order.
699   - returns AFPerror code
700 */
701 #ifdef HAVE_SOLARIS_ACLS
702 static int set_acl(const struct vol *vol, char *name, int inherit, char *ibuf)
703 {
704     int ret, i, nfsv4_ace_count, tocopy_aces_count = 0, new_aces_count = 0, trivial_ace_count = 0;
705     ace_t *old_aces, *new_aces = NULL;
706     uint16_t flags;
707     uint32_t ace_count;
708
709     LOG(log_debug9, logtype_afpd, "set_acl: BEGIN");
710
711     /*  Get no of ACEs the client put on the wire */
712     ace_count = htonl(*((uint32_t *)ibuf));
713     ibuf += 8;      /* skip ACL flags (see acls.h) */
714
715     if (inherit)
716         /* inherited + trivial ACEs */
717         flags = ACE_INHERITED_ACE | ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
718     else
719         /* only trivial ACEs */
720         flags = ACE_OWNER | ACE_GROUP | ACE_EVERYONE;
721
722     /* Get existing ACL and count ACEs which have to be copied */
723     if ((nfsv4_ace_count = get_nfsv4_acl(name, &old_aces)) == -1)
724         return AFPERR_MISC;
725     for ( i=0; i < nfsv4_ace_count; i++) {
726         if (old_aces[i].a_flags & flags)
727             tocopy_aces_count++;
728     }
729
730     /* Now malloc buffer exactly sized to fit all new ACEs */
731     new_aces = malloc( (ace_count + tocopy_aces_count) * sizeof(ace_t) );
732     if (new_aces == NULL) {
733         LOG(log_error, logtype_afpd, "set_acl: malloc %s", strerror(errno));
734         ret = AFPERR_MISC;
735         goto cleanup;
736     }
737
738     /* Start building new ACL */
739
740     /* Copy local inherited ACEs. Therefore we have 'Darwin canonical order' (see chmod there):
741        inherited ACEs first. */
742     if (inherit) {
743         for (i=0; i < nfsv4_ace_count; i++) {
744             if (old_aces[i].a_flags & ACE_INHERITED_ACE) {
745                 memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
746                 new_aces_count++;
747             }
748         }
749     }
750     LOG(log_debug7, logtype_afpd, "set_acl: copied %d inherited ACEs", new_aces_count);
751
752     /* Now the ACEs from the client */
753     ret = map_acl(DARWIN_2_SOLARIS, &new_aces[new_aces_count], (darwin_ace_t *)ibuf, ace_count);
754     if (ret == -1) {
755         ret = AFPERR_PARAM;
756         goto cleanup;
757     }
758     new_aces_count += ace_count;
759     LOG(log_debug7, logtype_afpd, "set_acl: mapped %d ACEs from client", ace_count);
760
761     /* Now copy the trivial ACEs */
762     for (i=0; i < nfsv4_ace_count; i++) {
763         if (old_aces[i].a_flags  & (ACE_OWNER | ACE_GROUP | ACE_EVERYONE)) {
764             memcpy(&new_aces[new_aces_count], &old_aces[i], sizeof(ace_t));
765             new_aces_count++;
766             trivial_ace_count++;
767         }
768     }
769     LOG(log_debug7, logtype_afpd, "set_acl: copied %d trivial ACEs", trivial_ace_count);
770
771     /* Ressourcefork first.
772        Note: for dirs we set the same ACL on the .AppleDouble/.Parent _file_. This
773        might be strange for ACE_DELETE_CHILD and for inheritance flags. */
774     if ( (ret = vol->vfs->vfs_acl(vol, name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
775         LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
776         if (errno == (EACCES | EPERM))
777             ret = AFPERR_ACCESS;
778         else if (errno == ENOENT)
779             ret = AFPERR_NOITEM;
780         else
781             ret = AFPERR_MISC;
782         goto cleanup;
783     }
784     if ( (ret = acl(name, ACE_SETACL, new_aces_count, new_aces)) != 0) {
785         LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno));
786         if (errno == (EACCES | EPERM))
787             ret = AFPERR_ACCESS;
788         else if (errno == ENOENT)
789             ret = AFPERR_NOITEM;
790         else
791             ret = AFPERR_MISC;
792         goto cleanup;
793     }
794
795     ret = AFP_OK;
796
797 cleanup:
798     free(old_aces);
799     free(new_aces);
800
801     LOG(log_debug9, logtype_afpd, "set_acl: END");
802     return ret;
803 }
804 #endif /* HAVE_SOLARIS_ACLS */
805
806 #ifdef HAVE_POSIX_ACLS
807 static int set_acl(const struct vol *vol, char *name, int inherit, char *ibuf)
808 {
809     return AFP_OK;
810 }
811 #endif /* HAVE_POSIX_ACLS */
812
813 /*
814   Checks if a given UUID has requested_rights(type darwin_ace_rights) for path.
815   Note: this gets called frequently and is a good place for optimizations !
816 */
817 #ifdef HAVE_SOLARIS_ACLS
818 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
819 {
820     int                 ret, i, ace_count, dir, checkgroup;
821     char                *username; /* might be group too */
822     uuidtype_t          uuidtype;
823     uid_t               uid;
824     gid_t               pgid;
825     uint32_t            requested_rights = 0, allowed_rights = 0, denied_rights = 0;
826     ace_t               *aces;
827     struct passwd       *pwd;
828     struct stat         st;
829     int                 check_user_trivace = 0, check_group_trivace = 0;
830     uid_t               who;
831     uint16_t            flags;
832     uint16_t            type;
833     uint32_t            rights;
834
835 #ifdef DEBUG
836     LOG(log_debug9, logtype_afpd, "check_access: BEGIN. Request: %08x", requested_darwin_rights);
837 #endif
838     /* Get uid or gid from UUID */
839     if ( (getnamefromuuid(uuid, &username, &uuidtype)) != 0) {
840         LOG(log_error, logtype_afpd, "check_access: error getting name from UUID");
841         return AFPERR_PARAM;
842     }
843
844     /* File or dir */
845     if ((lstat(path, &st)) != 0) {
846         LOG(log_error, logtype_afpd, "check_access: stat: %s", strerror(errno));
847         ret = AFPERR_PARAM;
848         goto exit;
849     }
850     dir = S_ISDIR(st.st_mode);
851
852     if (uuidtype == UUID_USER) {
853         pwd = getpwnam(username);
854         if (!pwd) {
855             LOG(log_error, logtype_afpd, "check_access: getpwnam: %s", strerror(errno));
856             ret = AFPERR_MISC;
857             goto exit;
858         }
859         uid = pwd->pw_uid;
860         pgid = pwd->pw_gid;
861
862         /* If user is file/dir owner we must check the user trivial ACE */
863         if (uid == st.st_uid) {
864             LOG(log_debug, logtype_afpd, "check_access: user: %s is files owner. Must check trivial user ACE", username);
865             check_user_trivace = 1;
866         }
867
868         /* Now check if requested user is files owning group. If yes we must check the group trivial ACE */
869         if ( (check_group(username, uid, pgid, st.st_gid)) == 0) {
870             LOG(log_debug, logtype_afpd, "check_access: user: %s is in group: %d. Must check trivial group ACE", username, st.st_gid);
871             check_group_trivace = 1;
872         }
873     } else { /* hopefully UUID_GROUP*/
874         LOG(log_error, logtype_afpd, "check_access: afp_access for UUID of groups not supported!");
875 #if 0
876         grp = getgrnam(username);
877         if (!grp) {
878             LOG(log_error, logtype_afpd, "check_access: getgrnam: %s", strerror(errno));
879             return -1;
880         }
881         if (st.st_gid == grp->gr_gid )
882             check_group_trivace = 1;
883 #endif
884     }
885
886     /* Map requested rights to Solaris style. */
887     for (i=0; darwin_to_nfsv4_rights[i].from != 0; i++) {
888         if (requested_darwin_rights & darwin_to_nfsv4_rights[i].from)
889             requested_rights |= darwin_to_nfsv4_rights[i].to;
890     }
891
892     /* Get ACL from file/dir */
893     if ( (ace_count = get_nfsv4_acl(path, &aces)) == -1) {
894         LOG(log_error, logtype_afpd, "check_access: error getting ACEs");
895         ret = AFPERR_MISC;
896         goto exit;
897     }
898     /* Now check requested rights */
899     ret = AFPERR_ACCESS;
900     i = 0;
901     do { /* Loop through ACEs */
902         who = aces[i].a_who;
903         flags = aces[i].a_flags;
904         type = aces[i].a_type;
905         rights = aces[i].a_access_mask;
906
907         if (flags & ACE_INHERIT_ONLY_ACE)
908             continue;
909
910         /* Check if its a group ACE and set checkgroup to 1 if yes */
911         checkgroup = 0;
912         if ( (flags & ACE_IDENTIFIER_GROUP) && !(flags & ACE_GROUP) ) {
913             if ( (check_group(username, uid, pgid, who)) == 0)
914                 checkgroup = 1;
915             else
916                 continue;
917         }
918
919         /* Now the tricky part: decide if ACE effects our user. I'll explain:
920            if its a dedicated (non trivial) ACE for the user
921            OR
922            if its a ACE for a group we're member of
923            OR
924            if its a trivial ACE_OWNER ACE and requested UUID is the owner
925            OR
926            if its a trivial ACE_GROUP ACE and requested UUID is group
927            OR
928            if its a trivial ACE_EVERYONE ACE
929            THEN
930            process ACE */
931         if (
932             ( (who == uid) && !(flags & (ACE_TRIVIAL|ACE_IDENTIFIER_GROUP)) ) ||
933             (checkgroup) ||
934             ( (flags & ACE_OWNER) && check_user_trivace ) ||
935             ( (flags & ACE_GROUP) && check_group_trivace ) ||
936             ( flags & ACE_EVERYONE )
937             ) {
938             /* Found an applicable ACE */
939             if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
940                 allowed_rights |= rights;
941             else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
942                 /* Only or to denied rights if not previously allowed !! */
943                 denied_rights |= ((!allowed_rights) & rights);
944         }
945     } while (++i < ace_count);
946
947
948     /* Darwin likes to ask for "delete_child" on dir,
949        "write_data" is actually the same, so we add that for dirs */
950     if (dir && (allowed_rights & ACE_WRITE_DATA))
951         allowed_rights |= ACE_DELETE_CHILD;
952
953     if (requested_rights & denied_rights) {
954         LOG(log_debug, logtype_afpd, "check_access: some requested right was denied:");
955         ret = AFPERR_ACCESS;
956     } else if ((requested_rights & allowed_rights) != requested_rights) {
957         LOG(log_debug, logtype_afpd, "check_access: some requested right wasn't allowed:");
958         ret = AFPERR_ACCESS;
959     } else {
960         LOG(log_debug, logtype_afpd, "check_access: all requested rights are allowed:");
961         ret = AFP_OK;
962     }
963
964     LOG(log_debug, logtype_afpd, "check_access: Requested rights: %08x, allowed_rights: %08x, denied_rights: %08x, Result: %d",
965         requested_rights, allowed_rights, denied_rights, ret);
966
967 exit:
968     free(aces);
969     free(username);
970 #ifdef DEBUG
971     LOG(log_debug9, logtype_afpd, "check_access: END");
972 #endif
973     return ret;
974 }
975 #endif /* HAVE_SOLARIS_ACLS */
976
977 #ifdef HAVE_POSIX_ACLS
978 static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t requested_darwin_rights)
979 {
980     /*
981      * FIXME: for OS X >= 10.6 it seems fp_access isn't called anymore, instead
982      * the client just tries to perform any action, relying on the server
983      * to enforce permission (which the OS does for us), returning appropiate
984      * error codes in case the action failed.
985      * So to summarize: I think it's safe to not implement this function and
986      * just always return AFP_OK.
987      */
988     return AFP_OK;
989 }
990 #endif /* HAVE_POSIX_ACLS */
991
992 /********************************************************
993  * Interface
994  ********************************************************/
995
996 int afp_access(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
997 {
998     int         ret;
999     struct vol      *vol;
1000     struct dir      *dir;
1001     uint32_t            did, darwin_ace_rights;
1002     uint16_t        vid;
1003     struct path         *s_path;
1004     uuidp_t             uuid;
1005
1006     LOG(log_debug9, logtype_afpd, "afp_access: BEGIN");
1007
1008     *rbuflen = 0;
1009     ibuf += 2;
1010
1011     memcpy(&vid, ibuf, sizeof( vid ));
1012     ibuf += sizeof(vid);
1013     if (NULL == ( vol = getvolbyvid( vid ))) {
1014         LOG(log_error, logtype_afpd, "afp_access: error getting volid:%d", vid);
1015         return AFPERR_NOOBJ;
1016     }
1017
1018     memcpy(&did, ibuf, sizeof( did ));
1019     ibuf += sizeof( did );
1020     if (NULL == ( dir = dirlookup( vol, did ))) {
1021         LOG(log_error, logtype_afpd, "afp_access: error getting did:%d", did);
1022         return afp_errno;
1023     }
1024
1025     /* Skip bitmap */
1026     ibuf += 2;
1027
1028     /* Store UUID address */
1029     uuid = (uuidp_t)ibuf;
1030     ibuf += UUID_BINSIZE;
1031
1032     /* Store ACE rights */
1033     memcpy(&darwin_ace_rights, ibuf, 4);
1034     darwin_ace_rights = ntohl(darwin_ace_rights);
1035     ibuf += 4;
1036
1037     /* get full path and handle file/dir subtleties in netatalk code*/
1038     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
1039         LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
1040         return AFPERR_NOOBJ;
1041     }
1042     if (!s_path->st_valid)
1043         of_statdir(vol, s_path);
1044     if ( s_path->st_errno != 0 ) {
1045         LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
1046         return AFPERR_NOOBJ;
1047     }
1048
1049     ret = check_acl_access(s_path->u_name, uuid, darwin_ace_rights);
1050
1051     LOG(log_debug9, logtype_afpd, "afp_access: END");
1052     return ret;
1053 }
1054
1055 int afp_getacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1056 {
1057     struct vol      *vol;
1058     struct dir      *dir;
1059     int         ret;
1060     uint32_t           did;
1061     uint16_t        vid, bitmap;
1062     struct path         *s_path;
1063     struct passwd       *pw;
1064     struct group        *gr;
1065
1066     LOG(log_debug9, logtype_afpd, "afp_getacl: BEGIN");
1067     *rbuflen = 0;
1068     ibuf += 2;
1069
1070     memcpy(&vid, ibuf, sizeof( vid ));
1071     ibuf += sizeof(vid);
1072     if (NULL == ( vol = getvolbyvid( vid ))) {
1073         LOG(log_error, logtype_afpd, "afp_getacl: error getting volid:%d", vid);
1074         return AFPERR_NOOBJ;
1075     }
1076
1077     memcpy(&did, ibuf, sizeof( did ));
1078     ibuf += sizeof( did );
1079     if (NULL == ( dir = dirlookup( vol, did ))) {
1080         LOG(log_error, logtype_afpd, "afp_getacl: error getting did:%d", did);
1081         return afp_errno;
1082     }
1083
1084     memcpy(&bitmap, ibuf, sizeof( bitmap ));
1085     memcpy(rbuf, ibuf, sizeof( bitmap ));
1086     bitmap = ntohs( bitmap );
1087     ibuf += sizeof( bitmap );
1088     rbuf += sizeof( bitmap );
1089     *rbuflen += sizeof( bitmap );
1090
1091     /* skip maxreplysize */
1092     ibuf += 4;
1093
1094     /* get full path and handle file/dir subtleties in netatalk code*/
1095     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
1096         LOG(log_error, logtype_afpd, "afp_getacl: cname got an error!");
1097         return AFPERR_NOOBJ;
1098     }
1099     if (!s_path->st_valid)
1100         of_statdir(vol, s_path);
1101     if ( s_path->st_errno != 0 ) {
1102         LOG(log_error, logtype_afpd, "afp_getacl: cant stat");
1103         return AFPERR_NOOBJ;
1104     }
1105
1106     /* Shall we return owner UUID ? */
1107     if (bitmap & kFileSec_UUID) {
1108         LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner user UUID");
1109         if (NULL == (pw = getpwuid(s_path->st.st_uid)))
1110             return AFPERR_MISC;
1111         LOG(log_debug, logtype_afpd, "afp_getacl: got uid: %d, name: %s", s_path->st.st_uid, pw->pw_name);
1112         if ((ret = getuuidfromname(pw->pw_name, UUID_USER, rbuf)) != 0)
1113             return AFPERR_MISC;
1114         rbuf += UUID_BINSIZE;
1115         *rbuflen += UUID_BINSIZE;
1116     }
1117
1118     /* Shall we return group UUID ? */
1119     if (bitmap & kFileSec_GRPUUID) {
1120         LOG(log_debug, logtype_afpd, "afp_getacl: client requested files owner group UUID");
1121         if (NULL == (gr = getgrgid(s_path->st.st_gid)))
1122             return AFPERR_MISC;
1123         LOG(log_debug, logtype_afpd, "afp_getacl: got gid: %d, name: %s", s_path->st.st_gid, gr->gr_name);
1124         if ((ret = getuuidfromname(gr->gr_name, UUID_GROUP, rbuf)) != 0)
1125             return AFPERR_MISC;
1126         rbuf += UUID_BINSIZE;
1127         *rbuflen += UUID_BINSIZE;
1128     }
1129
1130     /* Shall we return ACL ? */
1131     if (bitmap & kFileSec_ACL) {
1132         LOG(log_debug, logtype_afpd, "afp_getacl: client requested files ACL");
1133         get_and_map_acl(s_path->u_name, rbuf, rbuflen);
1134     }
1135
1136     LOG(log_debug9, logtype_afpd, "afp_getacl: END");
1137     return AFP_OK;
1138 }
1139
1140 int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1141 {
1142     struct vol      *vol;
1143     struct dir      *dir;
1144     int         ret;
1145     uint32_t            did;
1146     uint16_t        vid, bitmap;
1147     struct path         *s_path;
1148
1149     LOG(log_debug9, logtype_afpd, "afp_setacl: BEGIN");
1150     *rbuflen = 0;
1151     ibuf += 2;
1152
1153     memcpy(&vid, ibuf, sizeof( vid ));
1154     ibuf += sizeof(vid);
1155     if (NULL == ( vol = getvolbyvid( vid ))) {
1156         LOG(log_error, logtype_afpd, "afp_setacl: error getting volid:%d", vid);
1157         return AFPERR_NOOBJ;
1158     }
1159
1160     memcpy(&did, ibuf, sizeof( did ));
1161     ibuf += sizeof( did );
1162     if (NULL == ( dir = dirlookup( vol, did ))) {
1163         LOG(log_error, logtype_afpd, "afp_setacl: error getting did:%d", did);
1164         return afp_errno;
1165     }
1166
1167     memcpy(&bitmap, ibuf, sizeof( bitmap ));
1168     bitmap = ntohs( bitmap );
1169     ibuf += sizeof( bitmap );
1170
1171     /* get full path and handle file/dir subtleties in netatalk code*/
1172     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
1173         LOG(log_error, logtype_afpd, "afp_setacl: cname got an error!");
1174         return AFPERR_NOOBJ;
1175     }
1176     if (!s_path->st_valid)
1177         of_statdir(vol, s_path);
1178     if ( s_path->st_errno != 0 ) {
1179         LOG(log_error, logtype_afpd, "afp_setacl: cant stat");
1180         return AFPERR_NOOBJ;
1181     }
1182     LOG(log_debug, logtype_afpd, "afp_setacl: unixname: %s", s_path->u_name);
1183
1184     /* Padding? */
1185     if ((unsigned long)ibuf & 1)
1186         ibuf++;
1187
1188     /* Start processing request */
1189
1190     /* Change owner: dont even try */
1191     if (bitmap & kFileSec_UUID) {
1192         LOG(log_debug, logtype_afpd, "afp_setacl: change owner request. discarded.");
1193         ret = AFPERR_ACCESS;
1194         ibuf += UUID_BINSIZE;
1195     }
1196
1197     /* Change group: certain changes might be allowed, so try it. FIXME: not implemented yet. */
1198     if (bitmap & kFileSec_UUID) {
1199         LOG(log_debug, logtype_afpd, "afp_setacl: change group request. not supported this time.");
1200         ret = AFPERR_PARAM;
1201         ibuf += UUID_BINSIZE;
1202     }
1203
1204     /* Remove ACL ? */
1205     if (bitmap & kFileSec_REMOVEACL) {
1206         LOG(log_debug, logtype_afpd, "afp_setacl: Remove ACL request.");
1207         if ((ret = remove_acl(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
1208             LOG(log_error, logtype_afpd, "afp_setacl: error from remove_acl");
1209     }
1210
1211     /* Change ACL ? */
1212     if (bitmap & kFileSec_ACL) {
1213         LOG(log_debug, logtype_afpd, "afp_setacl: Change ACL request.");
1214
1215         /* Check if its our job to preserve inherited ACEs */
1216         if (bitmap & kFileSec_Inherit)
1217             ret = set_acl(vol, s_path->u_name, 1, ibuf);
1218         else
1219             ret = set_acl(vol, s_path->u_name, 0, ibuf);
1220         if (ret == 0)
1221             ret = AFP_OK;
1222         else
1223             ret = AFPERR_MISC;
1224     }
1225
1226     LOG(log_debug9, logtype_afpd, "afp_setacl: END");
1227     return ret;
1228 }
1229
1230 /*
1231   unix.c/accessmode calls this: map ACL to OS 9 mode
1232 */
1233 void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma)
1234 {
1235     struct passwd *pw;
1236     atalk_uuid_t uuid;
1237     int r_ok, w_ok, x_ok;
1238
1239     if ( ! (AFPobj->options.flags & OPTION_UUID) || ! (AFPobj->options.flags & OPTION_ACL2OS9MODE))
1240         return;
1241
1242     LOG(log_maxdebug, logtype_afpd, "acltoownermode('%s')", path);
1243
1244     if ((pw = getpwuid(uid)) == NULL) {
1245         LOG(log_error, logtype_afpd, "acltoownermode: %s", strerror(errno));
1246         return;
1247     }
1248
1249     /* We need the UUID for check_acl_access */
1250     if ((getuuidfromname(pw->pw_name, UUID_USER, uuid)) != 0)
1251         return;
1252
1253     /* These work for files and dirs */
1254     r_ok = check_acl_access(path, uuid, DARWIN_ACE_READ_DATA);
1255     w_ok = check_acl_access(path, uuid, (DARWIN_ACE_WRITE_DATA|DARWIN_ACE_APPEND_DATA));
1256     x_ok = check_acl_access(path, uuid, DARWIN_ACE_EXECUTE);
1257
1258     LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user before: %04o",ma->ma_user);
1259     if (r_ok == 0)
1260         ma->ma_user |= AR_UREAD;
1261     if (w_ok == 0)
1262         ma->ma_user |= AR_UWRITE;
1263     if (x_ok == 0)
1264         ma->ma_user |= AR_USEARCH;
1265     LOG(log_debug7, logtype_afpd, "acltoownermode: ma_user after: %04o", ma->ma_user);
1266
1267     return;
1268 }
1269
1270 /*
1271   We're being called at the end of afp_createdir. We're (hopefully) inside dir
1272   and ".AppleDouble" and ".AppleDouble/.Parent" should have already been created.
1273   We then inherit any explicit ACE from "." to ".AppleDouble" and ".AppleDouble/.Parent".
1274   FIXME: add to VFS layer ?
1275 */
1276 #ifdef HAVE_SOLARIS_ACLS
1277 void addir_inherit_acl(const struct vol *vol)
1278 {
1279     ace_t *diraces = NULL, *adaces = NULL, *combinedaces = NULL;
1280     int diracecount, adacecount;
1281
1282     LOG(log_debug9, logtype_afpd, "addir_inherit_acl: BEGIN");
1283
1284     /* Check if ACLs are enabled for the volume */
1285     if (vol->v_flags & AFPVOL_ACLS) {
1286
1287         if ((diracecount = get_nfsv4_acl(".", &diraces)) <= 0)
1288             goto cleanup;
1289         /* Remove any trivial ACE from "." */
1290         if ((diracecount = strip_trivial_aces(&diraces, diracecount)) <= 0)
1291             goto cleanup;
1292
1293         /*
1294           Inherit to ".AppleDouble"
1295         */
1296
1297         if ((adacecount = get_nfsv4_acl(".AppleDouble", &adaces)) <= 0)
1298             goto cleanup;
1299         /* Remove any non-trivial ACE from ".AppleDouble" */
1300         if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1301             goto cleanup;
1302
1303         /* Combine ACEs */
1304         if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1305             goto cleanup;
1306
1307         /* Now set new acl */
1308         if ((acl(".AppleDouble", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1309             LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1310
1311         free(adaces);
1312         adaces = NULL;
1313         free(combinedaces);
1314         combinedaces = NULL;
1315
1316         /*
1317           Inherit to ".AppleDouble/.Parent"
1318         */
1319
1320         if ((adacecount = get_nfsv4_acl(".AppleDouble/.Parent", &adaces)) <= 0)
1321             goto cleanup;
1322         if ((adacecount = strip_nontrivial_aces(&adaces, adacecount)) <= 0)
1323             goto cleanup;
1324
1325         /* Combine ACEs */
1326         if ((combinedaces = concat_aces(diraces, diracecount, adaces, adacecount)) == NULL)
1327             goto cleanup;
1328
1329         /* Now set new acl */
1330         if ((acl(".AppleDouble/.Parent", ACE_SETACL, diracecount + adacecount, combinedaces)) != 0)
1331             LOG(log_error, logtype_afpd, "addir_inherit_acl: acl: %s", strerror(errno));
1332
1333
1334     }
1335
1336 cleanup:
1337     LOG(log_debug9, logtype_afpd, "addir_inherit_acl: END");
1338
1339     free(diraces);
1340     free(adaces);
1341     free(combinedaces);
1342 }
1343 #endif /* HAVE_SOLARIS_ACLS */
1344
1345 #ifdef HAVE_POSIX_ACLS
1346 void addir_inherit_acl(const struct vol *vol)
1347 {
1348     return;
1349 }
1350 #endif /* HAVE_POSIX_ACLS */