fix: make zfs_strerror really thread-safe and portable
[zfs.git] / module / os / freebsd / spl / acl_common.c
blob04a5d2869d1b08de37b9ea877004e88b83f2ae5c
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/avl.h>
29 #include <sys/misc.h>
30 #if defined(_KERNEL)
31 #include <sys/kmem.h>
32 #include <sys/systm.h>
33 #include <sys/sysmacros.h>
34 #include <acl/acl_common.h>
35 #include <sys/debug.h>
36 #else
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <stddef.h>
40 #include <unistd.h>
41 #include <assert.h>
42 #include <grp.h>
43 #include <pwd.h>
44 #include <acl_common.h>
45 #endif
47 #define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \
48 ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \
49 ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL)
52 #define ACL_SYNCHRONIZE_SET_DENY 0x0000001
53 #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002
54 #define ACL_SYNCHRONIZE_ERR_DENY 0x0000004
55 #define ACL_SYNCHRONIZE_ERR_ALLOW 0x0000008
57 #define ACL_WRITE_OWNER_SET_DENY 0x0000010
58 #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020
59 #define ACL_WRITE_OWNER_ERR_DENY 0x0000040
60 #define ACL_WRITE_OWNER_ERR_ALLOW 0x0000080
62 #define ACL_DELETE_SET_DENY 0x0000100
63 #define ACL_DELETE_SET_ALLOW 0x0000200
64 #define ACL_DELETE_ERR_DENY 0x0000400
65 #define ACL_DELETE_ERR_ALLOW 0x0000800
67 #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000
68 #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000
69 #define ACL_WRITE_ATTRS_OWNER_ERR_DENY 0x0004000
70 #define ACL_WRITE_ATTRS_OWNER_ERR_ALLOW 0x0008000
72 #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000
73 #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000
74 #define ACL_WRITE_ATTRS_WRITER_ERR_DENY 0x0040000
75 #define ACL_WRITE_ATTRS_WRITER_ERR_ALLOW 0x0080000
77 #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000
78 #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000
79 #define ACL_WRITE_NAMED_WRITER_ERR_DENY 0x0400000
80 #define ACL_WRITE_NAMED_WRITER_ERR_ALLOW 0x0800000
82 #define ACL_READ_NAMED_READER_SET_DENY 0x1000000
83 #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000
84 #define ACL_READ_NAMED_READER_ERR_DENY 0x4000000
85 #define ACL_READ_NAMED_READER_ERR_ALLOW 0x8000000
88 #define ACE_VALID_MASK_BITS (\
89 ACE_READ_DATA | \
90 ACE_LIST_DIRECTORY | \
91 ACE_WRITE_DATA | \
92 ACE_ADD_FILE | \
93 ACE_APPEND_DATA | \
94 ACE_ADD_SUBDIRECTORY | \
95 ACE_READ_NAMED_ATTRS | \
96 ACE_WRITE_NAMED_ATTRS | \
97 ACE_EXECUTE | \
98 ACE_DELETE_CHILD | \
99 ACE_READ_ATTRIBUTES | \
100 ACE_WRITE_ATTRIBUTES | \
101 ACE_DELETE | \
102 ACE_READ_ACL | \
103 ACE_WRITE_ACL | \
104 ACE_WRITE_OWNER | \
105 ACE_SYNCHRONIZE)
107 #define ACE_MASK_UNDEFINED 0x80000000
109 #define ACE_VALID_FLAG_BITS (ACE_FILE_INHERIT_ACE | \
110 ACE_DIRECTORY_INHERIT_ACE | \
111 ACE_NO_PROPAGATE_INHERIT_ACE | ACE_INHERIT_ONLY_ACE | \
112 ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \
113 ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE)
116 * ACL conversion helpers
119 typedef enum {
120 ace_unused,
121 ace_user_obj,
122 ace_user,
123 ace_group, /* includes GROUP and GROUP_OBJ */
124 ace_other_obj
125 } ace_to_aent_state_t;
127 typedef struct acevals {
128 uid_t key;
129 avl_node_t avl;
130 uint32_t mask;
131 uint32_t allowed;
132 uint32_t denied;
133 int aent_type;
134 } acevals_t;
136 typedef struct ace_list {
137 acevals_t user_obj;
138 avl_tree_t user;
139 int numusers;
140 acevals_t group_obj;
141 avl_tree_t group;
142 int numgroups;
143 acevals_t other_obj;
144 uint32_t acl_mask;
145 int hasmask;
146 int dfacl_flag;
147 ace_to_aent_state_t state;
148 int seen; /* bitmask of all aclent_t a_type values seen */
149 } ace_list_t;
152 * Generic shellsort, from K&R (1st ed, p 58.), somewhat modified.
153 * v = Ptr to array/vector of objs
154 * n = # objs in the array
155 * s = size of each obj (must be multiples of a word size)
156 * f = ptr to function to compare two objs
157 * returns (-1 = less than, 0 = equal, 1 = greater than
159 void
160 ksort(caddr_t v, int n, int s, int (*f)(void *, void *))
162 int g, i, j, ii;
163 unsigned int *p1, *p2;
164 unsigned int tmp;
166 /* No work to do */
167 if (v == NULL || n <= 1)
168 return;
170 /* Sanity check on arguments */
171 ASSERT3U(((uintptr_t)v & 0x3), ==, 0);
172 ASSERT3S((s & 0x3), ==, 0);
173 ASSERT3S(s, >, 0);
174 for (g = n / 2; g > 0; g /= 2) {
175 for (i = g; i < n; i++) {
176 for (j = i - g; j >= 0 &&
177 (*f)(v + j * s, v + (j + g) * s) == 1;
178 j -= g) {
179 p1 = (void *)(v + j * s);
180 p2 = (void *)(v + (j + g) * s);
181 for (ii = 0; ii < s / 4; ii++) {
182 tmp = *p1;
183 *p1++ = *p2;
184 *p2++ = tmp;
192 * Compare two acls, all fields. Returns:
193 * -1 (less than)
194 * 0 (equal)
195 * +1 (greater than)
198 cmp2acls(void *a, void *b)
200 aclent_t *x = (aclent_t *)a;
201 aclent_t *y = (aclent_t *)b;
203 /* Compare types */
204 if (x->a_type < y->a_type)
205 return (-1);
206 if (x->a_type > y->a_type)
207 return (1);
208 /* Equal types; compare id's */
209 if (x->a_id < y->a_id)
210 return (-1);
211 if (x->a_id > y->a_id)
212 return (1);
213 /* Equal ids; compare perms */
214 if (x->a_perm < y->a_perm)
215 return (-1);
216 if (x->a_perm > y->a_perm)
217 return (1);
218 /* Totally equal */
219 return (0);
222 static int
223 cacl_malloc(void **ptr, size_t size)
225 *ptr = kmem_zalloc(size, KM_SLEEP);
226 return (0);
230 #if !defined(_KERNEL)
231 acl_t *
232 acl_alloc(enum acl_type type)
234 acl_t *aclp;
236 if (cacl_malloc((void **)&aclp, sizeof (acl_t)) != 0)
237 return (NULL);
239 aclp->acl_aclp = NULL;
240 aclp->acl_cnt = 0;
242 switch (type) {
243 case ACE_T:
244 aclp->acl_type = ACE_T;
245 aclp->acl_entry_size = sizeof (ace_t);
246 break;
247 case ACLENT_T:
248 aclp->acl_type = ACLENT_T;
249 aclp->acl_entry_size = sizeof (aclent_t);
250 break;
251 default:
252 acl_free(aclp);
253 aclp = NULL;
255 return (aclp);
259 * Free acl_t structure
261 void
262 acl_free(acl_t *aclp)
264 int acl_size;
266 if (aclp == NULL)
267 return;
269 if (aclp->acl_aclp) {
270 acl_size = aclp->acl_cnt * aclp->acl_entry_size;
271 cacl_free(aclp->acl_aclp, acl_size);
274 cacl_free(aclp, sizeof (acl_t));
277 static uint32_t
278 access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow)
280 uint32_t access_mask = 0;
281 int acl_produce;
282 int synchronize_set = 0, write_owner_set = 0;
283 int delete_set = 0, write_attrs_set = 0;
284 int read_named_set = 0, write_named_set = 0;
286 acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW |
287 ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
288 ACL_WRITE_ATTRS_WRITER_SET_DENY);
290 if (isallow) {
291 synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW;
292 write_owner_set = ACL_WRITE_OWNER_SET_ALLOW;
293 delete_set = ACL_DELETE_SET_ALLOW;
294 if (hasreadperm)
295 read_named_set = ACL_READ_NAMED_READER_SET_ALLOW;
296 if (haswriteperm)
297 write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
298 if (isowner)
299 write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
300 else if (haswriteperm)
301 write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
302 } else {
304 synchronize_set = ACL_SYNCHRONIZE_SET_DENY;
305 write_owner_set = ACL_WRITE_OWNER_SET_DENY;
306 delete_set = ACL_DELETE_SET_DENY;
307 if (hasreadperm)
308 read_named_set = ACL_READ_NAMED_READER_SET_DENY;
309 if (haswriteperm)
310 write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY;
311 if (isowner)
312 write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY;
313 else if (haswriteperm)
314 write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY;
315 else
317 * If the entity is not the owner and does not
318 * have write permissions ACE_WRITE_ATTRIBUTES will
319 * always go in the DENY ACE.
321 access_mask |= ACE_WRITE_ATTRIBUTES;
324 if (acl_produce & synchronize_set)
325 access_mask |= ACE_SYNCHRONIZE;
326 if (acl_produce & write_owner_set)
327 access_mask |= ACE_WRITE_OWNER;
328 if (acl_produce & delete_set)
329 access_mask |= ACE_DELETE;
330 if (acl_produce & write_attrs_set)
331 access_mask |= ACE_WRITE_ATTRIBUTES;
332 if (acl_produce & read_named_set)
333 access_mask |= ACE_READ_NAMED_ATTRS;
334 if (acl_produce & write_named_set)
335 access_mask |= ACE_WRITE_NAMED_ATTRS;
337 return (access_mask);
341 * Given an mode_t, convert it into an access_mask as used
342 * by nfsace, assuming aclent_t -> nfsace semantics.
344 static uint32_t
345 mode_to_ace_access(mode_t mode, boolean_t isdir, int isowner, int isallow)
347 uint32_t access = 0;
348 int haswriteperm = 0;
349 int hasreadperm = 0;
351 if (isallow) {
352 haswriteperm = (mode & S_IWOTH);
353 hasreadperm = (mode & S_IROTH);
354 } else {
355 haswriteperm = !(mode & S_IWOTH);
356 hasreadperm = !(mode & S_IROTH);
360 * The following call takes care of correctly setting the following
361 * mask bits in the access_mask:
362 * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE,
363 * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS
365 access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow);
367 if (isallow) {
368 access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES;
369 if (isowner)
370 access |= ACE_WRITE_ACL;
371 } else {
372 if (! isowner)
373 access |= ACE_WRITE_ACL;
376 /* read */
377 if (mode & S_IROTH) {
378 access |= ACE_READ_DATA;
380 /* write */
381 if (mode & S_IWOTH) {
382 access |= ACE_WRITE_DATA |
383 ACE_APPEND_DATA;
384 if (isdir)
385 access |= ACE_DELETE_CHILD;
387 /* exec */
388 if (mode & S_IXOTH) {
389 access |= ACE_EXECUTE;
392 return (access);
396 * Given an nfsace (presumably an ALLOW entry), make a
397 * corresponding DENY entry at the address given.
399 static void
400 ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner)
402 (void) memcpy(deny, allow, sizeof (ace_t));
404 deny->a_who = allow->a_who;
406 deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
407 deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS;
408 if (isdir)
409 deny->a_access_mask ^= ACE_DELETE_CHILD;
411 deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER |
412 ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
413 ACE_WRITE_NAMED_ATTRS);
414 deny->a_access_mask |= access_mask_set((allow->a_access_mask &
415 ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner,
416 B_FALSE);
419 * Make an initial pass over an array of aclent_t's. Gather
420 * information such as an ACL_MASK (if any), number of users,
421 * number of groups, and whether the array needs to be sorted.
423 static int
424 ln_aent_preprocess(aclent_t *aclent, int n,
425 int *hasmask, mode_t *mask,
426 int *numuser, int *numgroup, int *needsort)
428 int error = 0;
429 int i;
430 int curtype = 0;
432 *hasmask = 0;
433 *mask = 07;
434 *needsort = 0;
435 *numuser = 0;
436 *numgroup = 0;
438 for (i = 0; i < n; i++) {
439 if (aclent[i].a_type < curtype)
440 *needsort = 1;
441 else if (aclent[i].a_type > curtype)
442 curtype = aclent[i].a_type;
443 if (aclent[i].a_type & USER)
444 (*numuser)++;
445 if (aclent[i].a_type & (GROUP | GROUP_OBJ))
446 (*numgroup)++;
447 if (aclent[i].a_type & CLASS_OBJ) {
448 if (*hasmask) {
449 error = EINVAL;
450 goto out;
451 } else {
452 *hasmask = 1;
453 *mask = aclent[i].a_perm;
458 if ((! *hasmask) && (*numuser + *numgroup > 1)) {
459 error = EINVAL;
460 goto out;
463 out:
464 return (error);
468 * Convert an array of aclent_t into an array of nfsace entries,
469 * following POSIX draft -> nfsv4 conversion semantics as outlined in
470 * the IETF draft.
472 static int
473 ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir)
475 int error = 0;
476 mode_t mask;
477 int numuser, numgroup, needsort;
478 int resultsize = 0;
479 int i, groupi = 0, skip;
480 ace_t *acep, *result = NULL;
481 int hasmask;
483 error = ln_aent_preprocess(aclent, n, &hasmask, &mask,
484 &numuser, &numgroup, &needsort);
485 if (error != 0)
486 goto out;
488 /* allow + deny for each aclent */
489 resultsize = n * 2;
490 if (hasmask) {
492 * stick extra deny on the group_obj and on each
493 * user|group for the mask (the group_obj was added
494 * into the count for numgroup)
496 resultsize += numuser + numgroup;
497 /* ... and don't count the mask itself */
498 resultsize -= 2;
501 /* sort the source if necessary */
502 if (needsort)
503 ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls);
505 if (cacl_malloc((void **)&result, resultsize * sizeof (ace_t)) != 0)
506 goto out;
508 acep = result;
510 for (i = 0; i < n; i++) {
512 * don't process CLASS_OBJ (mask); mask was grabbed in
513 * ln_aent_preprocess()
515 if (aclent[i].a_type & CLASS_OBJ)
516 continue;
518 /* If we need an ACL_MASK emulator, prepend it now */
519 if ((hasmask) &&
520 (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) {
521 acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
522 acep->a_flags = 0;
523 if (aclent[i].a_type & GROUP_OBJ) {
524 acep->a_who = (uid_t)-1;
525 acep->a_flags |=
526 (ACE_IDENTIFIER_GROUP|ACE_GROUP);
527 } else if (aclent[i].a_type & USER) {
528 acep->a_who = aclent[i].a_id;
529 } else {
530 acep->a_who = aclent[i].a_id;
531 acep->a_flags |= ACE_IDENTIFIER_GROUP;
533 if (aclent[i].a_type & ACL_DEFAULT) {
534 acep->a_flags |= ACE_INHERIT_ONLY_ACE |
535 ACE_FILE_INHERIT_ACE |
536 ACE_DIRECTORY_INHERIT_ACE;
539 * Set the access mask for the prepended deny
540 * ace. To do this, we invert the mask (found
541 * in ln_aent_preprocess()) then convert it to an
542 * DENY ace access_mask.
544 acep->a_access_mask = mode_to_ace_access((mask ^ 07),
545 isdir, 0, 0);
546 acep += 1;
549 /* handle a_perm -> access_mask */
550 acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm,
551 isdir, aclent[i].a_type & USER_OBJ, 1);
553 /* emulate a default aclent */
554 if (aclent[i].a_type & ACL_DEFAULT) {
555 acep->a_flags |= ACE_INHERIT_ONLY_ACE |
556 ACE_FILE_INHERIT_ACE |
557 ACE_DIRECTORY_INHERIT_ACE;
561 * handle a_perm and a_id
563 * this must be done last, since it involves the
564 * corresponding deny aces, which are handled
565 * differently for each different a_type.
567 if (aclent[i].a_type & USER_OBJ) {
568 acep->a_who = (uid_t)-1;
569 acep->a_flags |= ACE_OWNER;
570 ace_make_deny(acep, acep + 1, isdir, B_TRUE);
571 acep += 2;
572 } else if (aclent[i].a_type & USER) {
573 acep->a_who = aclent[i].a_id;
574 ace_make_deny(acep, acep + 1, isdir, B_FALSE);
575 acep += 2;
576 } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) {
577 if (aclent[i].a_type & GROUP_OBJ) {
578 acep->a_who = (uid_t)-1;
579 acep->a_flags |= ACE_GROUP;
580 } else {
581 acep->a_who = aclent[i].a_id;
583 acep->a_flags |= ACE_IDENTIFIER_GROUP;
585 * Set the corresponding deny for the group ace.
587 * The deny aces go after all of the groups, unlike
588 * everything else, where they immediately follow
589 * the allow ace.
591 * We calculate "skip", the number of slots to
592 * skip ahead for the deny ace, here.
594 * The pattern is:
595 * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3
596 * thus, skip is
597 * (2 * numgroup) - 1 - groupi
598 * (2 * numgroup) to account for MD + A
599 * - 1 to account for the fact that we're on the
600 * access (A), not the mask (MD)
601 * - groupi to account for the fact that we have
602 * passed up groupi number of MD's.
604 skip = (2 * numgroup) - 1 - groupi;
605 ace_make_deny(acep, acep + skip, isdir, B_FALSE);
607 * If we just did the last group, skip acep past
608 * all of the denies; else, just move ahead one.
610 if (++groupi >= numgroup)
611 acep += numgroup + 1;
612 else
613 acep += 1;
614 } else if (aclent[i].a_type & OTHER_OBJ) {
615 acep->a_who = (uid_t)-1;
616 acep->a_flags |= ACE_EVERYONE;
617 ace_make_deny(acep, acep + 1, isdir, B_FALSE);
618 acep += 2;
619 } else {
620 error = EINVAL;
621 goto out;
625 *acepp = result;
626 *rescount = resultsize;
628 out:
629 if (error != 0) {
630 if ((result != NULL) && (resultsize > 0)) {
631 cacl_free(result, resultsize * sizeof (ace_t));
635 return (error);
638 static int
639 convert_aent_to_ace(aclent_t *aclentp, int aclcnt, boolean_t isdir,
640 ace_t **retacep, int *retacecnt)
642 ace_t *acep;
643 ace_t *dfacep;
644 int acecnt = 0;
645 int dfacecnt = 0;
646 int dfaclstart = 0;
647 int dfaclcnt = 0;
648 aclent_t *aclp;
649 int i;
650 int error;
651 int acesz, dfacesz;
653 ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls);
655 for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) {
656 if (aclp->a_type & ACL_DEFAULT)
657 break;
660 if (i < aclcnt) {
661 dfaclstart = i;
662 dfaclcnt = aclcnt - i;
665 if (dfaclcnt && !isdir) {
666 return (EINVAL);
669 error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir);
670 if (error)
671 return (error);
673 if (dfaclcnt) {
674 error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt,
675 &dfacep, &dfacecnt, isdir);
676 if (error) {
677 if (acep) {
678 cacl_free(acep, acecnt * sizeof (ace_t));
680 return (error);
684 if (dfacecnt != 0) {
685 acesz = sizeof (ace_t) * acecnt;
686 dfacesz = sizeof (ace_t) * dfacecnt;
687 acep = cacl_realloc(acep, acesz, acesz + dfacesz);
688 if (acep == NULL)
689 return (ENOMEM);
690 if (dfaclcnt) {
691 (void) memcpy(acep + acecnt, dfacep, dfacesz);
694 if (dfaclcnt)
695 cacl_free(dfacep, dfacecnt * sizeof (ace_t));
697 *retacecnt = acecnt + dfacecnt;
698 *retacep = acep;
699 return (0);
702 static int
703 ace_mask_to_mode(uint32_t mask, o_mode_t *modep, boolean_t isdir)
705 int error = 0;
706 o_mode_t mode = 0;
707 uint32_t bits, wantbits;
709 /* read */
710 if (mask & ACE_READ_DATA)
711 mode |= S_IROTH;
713 /* write */
714 wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA);
715 if (isdir)
716 wantbits |= ACE_DELETE_CHILD;
717 bits = mask & wantbits;
718 if (bits != 0) {
719 if (bits != wantbits) {
720 error = ENOTSUP;
721 goto out;
723 mode |= S_IWOTH;
726 /* exec */
727 if (mask & ACE_EXECUTE) {
728 mode |= S_IXOTH;
731 *modep = mode;
733 out:
734 return (error);
737 static void
738 acevals_init(acevals_t *vals, uid_t key)
740 memset(vals, 0, sizeof (*vals));
741 vals->allowed = ACE_MASK_UNDEFINED;
742 vals->denied = ACE_MASK_UNDEFINED;
743 vals->mask = ACE_MASK_UNDEFINED;
744 vals->key = key;
747 static void
748 ace_list_init(ace_list_t *al, int dfacl_flag)
750 acevals_init(&al->user_obj, 0);
751 acevals_init(&al->group_obj, 0);
752 acevals_init(&al->other_obj, 0);
753 al->numusers = 0;
754 al->numgroups = 0;
755 al->acl_mask = 0;
756 al->hasmask = 0;
757 al->state = ace_unused;
758 al->seen = 0;
759 al->dfacl_flag = dfacl_flag;
763 * Find or create an acevals holder for a given id and avl tree.
765 * Note that only one thread will ever touch these avl trees, so
766 * there is no need for locking.
768 static acevals_t *
769 acevals_find(ace_t *ace, avl_tree_t *avl, int *num)
771 acevals_t key, *rc;
772 avl_index_t where;
774 key.key = ace->a_who;
775 rc = avl_find(avl, &key, &where);
776 if (rc != NULL)
777 return (rc);
779 /* this memory is freed by ln_ace_to_aent()->ace_list_free() */
780 if (cacl_malloc((void **)&rc, sizeof (acevals_t)) != 0)
781 return (NULL);
783 acevals_init(rc, ace->a_who);
784 avl_insert(avl, rc, where);
785 (*num)++;
787 return (rc);
790 static int
791 access_mask_check(ace_t *acep, int mask_bit, int isowner)
793 int set_deny, err_deny;
794 int set_allow, err_allow;
795 int acl_consume;
796 int haswriteperm, hasreadperm;
798 if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
799 haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1;
800 hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1;
801 } else {
802 haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0;
803 hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0;
806 acl_consume = (ACL_SYNCHRONIZE_ERR_DENY |
807 ACL_DELETE_ERR_DENY |
808 ACL_WRITE_OWNER_ERR_DENY |
809 ACL_WRITE_OWNER_ERR_ALLOW |
810 ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
811 ACL_WRITE_ATTRS_OWNER_ERR_DENY |
812 ACL_WRITE_ATTRS_WRITER_SET_DENY |
813 ACL_WRITE_ATTRS_WRITER_ERR_ALLOW |
814 ACL_WRITE_NAMED_WRITER_ERR_DENY |
815 ACL_READ_NAMED_READER_ERR_DENY);
817 if (mask_bit == ACE_SYNCHRONIZE) {
818 set_deny = ACL_SYNCHRONIZE_SET_DENY;
819 err_deny = ACL_SYNCHRONIZE_ERR_DENY;
820 set_allow = ACL_SYNCHRONIZE_SET_ALLOW;
821 err_allow = ACL_SYNCHRONIZE_ERR_ALLOW;
822 } else if (mask_bit == ACE_WRITE_OWNER) {
823 set_deny = ACL_WRITE_OWNER_SET_DENY;
824 err_deny = ACL_WRITE_OWNER_ERR_DENY;
825 set_allow = ACL_WRITE_OWNER_SET_ALLOW;
826 err_allow = ACL_WRITE_OWNER_ERR_ALLOW;
827 } else if (mask_bit == ACE_DELETE) {
828 set_deny = ACL_DELETE_SET_DENY;
829 err_deny = ACL_DELETE_ERR_DENY;
830 set_allow = ACL_DELETE_SET_ALLOW;
831 err_allow = ACL_DELETE_ERR_ALLOW;
832 } else if (mask_bit == ACE_WRITE_ATTRIBUTES) {
833 if (isowner) {
834 set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY;
835 err_deny = ACL_WRITE_ATTRS_OWNER_ERR_DENY;
836 set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
837 err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW;
838 } else if (haswriteperm) {
839 set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY;
840 err_deny = ACL_WRITE_ATTRS_WRITER_ERR_DENY;
841 set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
842 err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW;
843 } else {
844 if ((acep->a_access_mask & mask_bit) &&
845 (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) {
846 return (ENOTSUP);
848 return (0);
850 } else if (mask_bit == ACE_READ_NAMED_ATTRS) {
851 if (!hasreadperm)
852 return (0);
854 set_deny = ACL_READ_NAMED_READER_SET_DENY;
855 err_deny = ACL_READ_NAMED_READER_ERR_DENY;
856 set_allow = ACL_READ_NAMED_READER_SET_ALLOW;
857 err_allow = ACL_READ_NAMED_READER_ERR_ALLOW;
858 } else if (mask_bit == ACE_WRITE_NAMED_ATTRS) {
859 if (!haswriteperm)
860 return (0);
862 set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY;
863 err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY;
864 set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
865 err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW;
866 } else {
867 return (EINVAL);
870 if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
871 if (acl_consume & set_deny) {
872 if (!(acep->a_access_mask & mask_bit)) {
873 return (ENOTSUP);
875 } else if (acl_consume & err_deny) {
876 if (acep->a_access_mask & mask_bit) {
877 return (ENOTSUP);
880 } else {
881 /* ACE_ACCESS_ALLOWED_ACE_TYPE */
882 if (acl_consume & set_allow) {
883 if (!(acep->a_access_mask & mask_bit)) {
884 return (ENOTSUP);
886 } else if (acl_consume & err_allow) {
887 if (acep->a_access_mask & mask_bit) {
888 return (ENOTSUP);
892 return (0);
895 static int
896 ace_to_aent_legal(ace_t *acep)
898 int error = 0;
899 int isowner;
901 /* only ALLOW or DENY */
902 if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) &&
903 (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) {
904 error = ENOTSUP;
905 goto out;
908 /* check for invalid flags */
909 if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) {
910 error = EINVAL;
911 goto out;
914 /* some flags are illegal */
915 if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG |
916 ACE_FAILED_ACCESS_ACE_FLAG |
917 ACE_NO_PROPAGATE_INHERIT_ACE)) {
918 error = ENOTSUP;
919 goto out;
922 /* check for invalid masks */
923 if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) {
924 error = EINVAL;
925 goto out;
928 if ((acep->a_flags & ACE_OWNER)) {
929 isowner = 1;
930 } else {
931 isowner = 0;
934 error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner);
935 if (error)
936 goto out;
938 error = access_mask_check(acep, ACE_WRITE_OWNER, isowner);
939 if (error)
940 goto out;
942 error = access_mask_check(acep, ACE_DELETE, isowner);
943 if (error)
944 goto out;
946 error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner);
947 if (error)
948 goto out;
950 error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner);
951 if (error)
952 goto out;
954 error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner);
955 if (error)
956 goto out;
958 /* more detailed checking of masks */
959 if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
960 if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) {
961 error = ENOTSUP;
962 goto out;
964 if ((acep->a_access_mask & ACE_WRITE_DATA) &&
965 (! (acep->a_access_mask & ACE_APPEND_DATA))) {
966 error = ENOTSUP;
967 goto out;
969 if ((! (acep->a_access_mask & ACE_WRITE_DATA)) &&
970 (acep->a_access_mask & ACE_APPEND_DATA)) {
971 error = ENOTSUP;
972 goto out;
976 /* ACL enforcement */
977 if ((acep->a_access_mask & ACE_READ_ACL) &&
978 (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) {
979 error = ENOTSUP;
980 goto out;
982 if (acep->a_access_mask & ACE_WRITE_ACL) {
983 if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) &&
984 (isowner)) {
985 error = ENOTSUP;
986 goto out;
988 if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) &&
989 (! isowner)) {
990 error = ENOTSUP;
991 goto out;
995 out:
996 return (error);
999 static int
1000 ace_allow_to_mode(uint32_t mask, o_mode_t *modep, boolean_t isdir)
1002 /* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */
1003 if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) !=
1004 (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) {
1005 return (ENOTSUP);
1008 return (ace_mask_to_mode(mask, modep, isdir));
1011 static int
1012 acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list,
1013 uid_t owner, gid_t group, boolean_t isdir)
1015 int error;
1016 uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
1018 if (isdir)
1019 flips |= ACE_DELETE_CHILD;
1020 if (vals->allowed != (vals->denied ^ flips)) {
1021 error = ENOTSUP;
1022 goto out;
1024 if ((list->hasmask) && (list->acl_mask != vals->mask) &&
1025 (vals->aent_type & (USER | GROUP | GROUP_OBJ))) {
1026 error = ENOTSUP;
1027 goto out;
1029 error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir);
1030 if (error != 0)
1031 goto out;
1032 dest->a_type = vals->aent_type;
1033 if (dest->a_type & (USER | GROUP)) {
1034 dest->a_id = vals->key;
1035 } else if (dest->a_type & USER_OBJ) {
1036 dest->a_id = owner;
1037 } else if (dest->a_type & GROUP_OBJ) {
1038 dest->a_id = group;
1039 } else if (dest->a_type & OTHER_OBJ) {
1040 dest->a_id = 0;
1041 } else {
1042 error = EINVAL;
1043 goto out;
1046 out:
1047 return (error);
1051 static int
1052 ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt,
1053 uid_t owner, gid_t group, boolean_t isdir)
1055 int error = 0;
1056 aclent_t *aent, *result = NULL;
1057 acevals_t *vals;
1058 int resultcount;
1060 if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) !=
1061 (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) {
1062 error = ENOTSUP;
1063 goto out;
1065 if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) {
1066 error = ENOTSUP;
1067 goto out;
1070 resultcount = 3 + list->numusers + list->numgroups;
1072 * This must be the same condition as below, when we add the CLASS_OBJ
1073 * (aka ACL mask)
1075 if ((list->hasmask) || (! list->dfacl_flag))
1076 resultcount += 1;
1078 if (cacl_malloc((void **)&result,
1079 resultcount * sizeof (aclent_t)) != 0) {
1080 error = ENOMEM;
1081 goto out;
1083 aent = result;
1085 /* USER_OBJ */
1086 if (!(list->user_obj.aent_type & USER_OBJ)) {
1087 error = EINVAL;
1088 goto out;
1091 error = acevals_to_aent(&list->user_obj, aent, list, owner, group,
1092 isdir);
1094 if (error != 0)
1095 goto out;
1096 ++aent;
1097 /* USER */
1098 vals = NULL;
1099 for (vals = avl_first(&list->user); vals != NULL;
1100 vals = AVL_NEXT(&list->user, vals)) {
1101 if (!(vals->aent_type & USER)) {
1102 error = EINVAL;
1103 goto out;
1105 error = acevals_to_aent(vals, aent, list, owner, group,
1106 isdir);
1107 if (error != 0)
1108 goto out;
1109 ++aent;
1111 /* GROUP_OBJ */
1112 if (!(list->group_obj.aent_type & GROUP_OBJ)) {
1113 error = EINVAL;
1114 goto out;
1116 error = acevals_to_aent(&list->group_obj, aent, list, owner, group,
1117 isdir);
1118 if (error != 0)
1119 goto out;
1120 ++aent;
1121 /* GROUP */
1122 vals = NULL;
1123 for (vals = avl_first(&list->group); vals != NULL;
1124 vals = AVL_NEXT(&list->group, vals)) {
1125 if (!(vals->aent_type & GROUP)) {
1126 error = EINVAL;
1127 goto out;
1129 error = acevals_to_aent(vals, aent, list, owner, group,
1130 isdir);
1131 if (error != 0)
1132 goto out;
1133 ++aent;
1136 * CLASS_OBJ (aka ACL_MASK)
1138 * An ACL_MASK is not fabricated if the ACL is a default ACL.
1139 * This is to follow UFS's behavior.
1141 if ((list->hasmask) || (! list->dfacl_flag)) {
1142 if (list->hasmask) {
1143 uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
1144 if (isdir)
1145 flips |= ACE_DELETE_CHILD;
1146 error = ace_mask_to_mode(list->acl_mask ^ flips,
1147 &aent->a_perm, isdir);
1148 if (error != 0)
1149 goto out;
1150 } else {
1151 /* fabricate the ACL_MASK from the group permissions */
1152 error = ace_mask_to_mode(list->group_obj.allowed,
1153 &aent->a_perm, isdir);
1154 if (error != 0)
1155 goto out;
1157 aent->a_id = 0;
1158 aent->a_type = CLASS_OBJ | list->dfacl_flag;
1159 ++aent;
1161 /* OTHER_OBJ */
1162 if (!(list->other_obj.aent_type & OTHER_OBJ)) {
1163 error = EINVAL;
1164 goto out;
1166 error = acevals_to_aent(&list->other_obj, aent, list, owner, group,
1167 isdir);
1168 if (error != 0)
1169 goto out;
1170 ++aent;
1172 *aclentp = result;
1173 *aclcnt = resultcount;
1175 out:
1176 if (error != 0) {
1177 if (result != NULL)
1178 cacl_free(result, resultcount * sizeof (aclent_t));
1181 return (error);
1186 * free all data associated with an ace_list
1188 static void
1189 ace_list_free(ace_list_t *al)
1191 acevals_t *node;
1192 void *cookie;
1194 if (al == NULL)
1195 return;
1197 cookie = NULL;
1198 while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL)
1199 cacl_free(node, sizeof (acevals_t));
1200 cookie = NULL;
1201 while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL)
1202 cacl_free(node, sizeof (acevals_t));
1204 avl_destroy(&al->user);
1205 avl_destroy(&al->group);
1207 /* free the container itself */
1208 cacl_free(al, sizeof (ace_list_t));
1211 static int
1212 acevals_compare(const void *va, const void *vb)
1214 const acevals_t *a = va, *b = vb;
1216 if (a->key == b->key)
1217 return (0);
1219 if (a->key > b->key)
1220 return (1);
1222 else
1223 return (-1);
1227 * Convert a list of ace_t entries to equivalent regular and default
1228 * aclent_t lists. Return error (ENOTSUP) when conversion is not possible.
1230 static int
1231 ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group,
1232 aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt,
1233 boolean_t isdir)
1235 int error = 0;
1236 ace_t *acep;
1237 uint32_t bits;
1238 int i;
1239 ace_list_t *normacl = NULL, *dfacl = NULL, *acl;
1240 acevals_t *vals;
1242 *aclentp = NULL;
1243 *aclcnt = 0;
1244 *dfaclentp = NULL;
1245 *dfaclcnt = 0;
1247 /* we need at least user_obj, group_obj, and other_obj */
1248 if (n < 6) {
1249 error = ENOTSUP;
1250 goto out;
1252 if (ace == NULL) {
1253 error = EINVAL;
1254 goto out;
1257 error = cacl_malloc((void **)&normacl, sizeof (ace_list_t));
1258 if (error != 0)
1259 goto out;
1261 avl_create(&normacl->user, acevals_compare, sizeof (acevals_t),
1262 offsetof(acevals_t, avl));
1263 avl_create(&normacl->group, acevals_compare, sizeof (acevals_t),
1264 offsetof(acevals_t, avl));
1266 ace_list_init(normacl, 0);
1268 error = cacl_malloc((void **)&dfacl, sizeof (ace_list_t));
1269 if (error != 0)
1270 goto out;
1272 avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t),
1273 offsetof(acevals_t, avl));
1274 avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t),
1275 offsetof(acevals_t, avl));
1276 ace_list_init(dfacl, ACL_DEFAULT);
1278 /* process every ace_t... */
1279 for (i = 0; i < n; i++) {
1280 acep = &ace[i];
1282 /* rule out certain cases quickly */
1283 error = ace_to_aent_legal(acep);
1284 if (error != 0)
1285 goto out;
1288 * Turn off these bits in order to not have to worry about
1289 * them when doing the checks for compliments.
1291 acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE |
1292 ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES |
1293 ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS);
1295 /* see if this should be a regular or default acl */
1296 bits = acep->a_flags &
1297 (ACE_INHERIT_ONLY_ACE |
1298 ACE_FILE_INHERIT_ACE |
1299 ACE_DIRECTORY_INHERIT_ACE);
1300 if (bits != 0) {
1301 /* all or nothing on these inherit bits */
1302 if (bits != (ACE_INHERIT_ONLY_ACE |
1303 ACE_FILE_INHERIT_ACE |
1304 ACE_DIRECTORY_INHERIT_ACE)) {
1305 error = ENOTSUP;
1306 goto out;
1308 acl = dfacl;
1309 } else {
1310 acl = normacl;
1313 if ((acep->a_flags & ACE_OWNER)) {
1314 if (acl->state > ace_user_obj) {
1315 error = ENOTSUP;
1316 goto out;
1318 acl->state = ace_user_obj;
1319 acl->seen |= USER_OBJ;
1320 vals = &acl->user_obj;
1321 vals->aent_type = USER_OBJ | acl->dfacl_flag;
1322 } else if ((acep->a_flags & ACE_EVERYONE)) {
1323 acl->state = ace_other_obj;
1324 acl->seen |= OTHER_OBJ;
1325 vals = &acl->other_obj;
1326 vals->aent_type = OTHER_OBJ | acl->dfacl_flag;
1327 } else if (acep->a_flags & ACE_IDENTIFIER_GROUP) {
1328 if (acl->state > ace_group) {
1329 error = ENOTSUP;
1330 goto out;
1332 if ((acep->a_flags & ACE_GROUP)) {
1333 acl->seen |= GROUP_OBJ;
1334 vals = &acl->group_obj;
1335 vals->aent_type = GROUP_OBJ | acl->dfacl_flag;
1336 } else {
1337 acl->seen |= GROUP;
1338 vals = acevals_find(acep, &acl->group,
1339 &acl->numgroups);
1340 if (vals == NULL) {
1341 error = ENOMEM;
1342 goto out;
1344 vals->aent_type = GROUP | acl->dfacl_flag;
1346 acl->state = ace_group;
1347 } else {
1348 if (acl->state > ace_user) {
1349 error = ENOTSUP;
1350 goto out;
1352 acl->state = ace_user;
1353 acl->seen |= USER;
1354 vals = acevals_find(acep, &acl->user,
1355 &acl->numusers);
1356 if (vals == NULL) {
1357 error = ENOMEM;
1358 goto out;
1360 vals->aent_type = USER | acl->dfacl_flag;
1363 if (!(acl->state > ace_unused)) {
1364 error = EINVAL;
1365 goto out;
1368 if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
1369 /* no more than one allowed per aclent_t */
1370 if (vals->allowed != ACE_MASK_UNDEFINED) {
1371 error = ENOTSUP;
1372 goto out;
1374 vals->allowed = acep->a_access_mask;
1375 } else {
1377 * it's a DENY; if there was a previous DENY, it
1378 * must have been an ACL_MASK.
1380 if (vals->denied != ACE_MASK_UNDEFINED) {
1381 /* ACL_MASK is for USER and GROUP only */
1382 if ((acl->state != ace_user) &&
1383 (acl->state != ace_group)) {
1384 error = ENOTSUP;
1385 goto out;
1388 if (! acl->hasmask) {
1389 acl->hasmask = 1;
1390 acl->acl_mask = vals->denied;
1391 /* check for mismatched ACL_MASK emulations */
1392 } else if (acl->acl_mask != vals->denied) {
1393 error = ENOTSUP;
1394 goto out;
1396 vals->mask = vals->denied;
1398 vals->denied = acep->a_access_mask;
1402 /* done collating; produce the aclent_t lists */
1403 if (normacl->state != ace_unused) {
1404 error = ace_list_to_aent(normacl, aclentp, aclcnt,
1405 owner, group, isdir);
1406 if (error != 0) {
1407 goto out;
1410 if (dfacl->state != ace_unused) {
1411 error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt,
1412 owner, group, isdir);
1413 if (error != 0) {
1414 goto out;
1418 out:
1419 if (normacl != NULL)
1420 ace_list_free(normacl);
1421 if (dfacl != NULL)
1422 ace_list_free(dfacl);
1424 return (error);
1427 static int
1428 convert_ace_to_aent(ace_t *acebufp, int acecnt, boolean_t isdir,
1429 uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt)
1431 int error = 0;
1432 aclent_t *aclentp, *dfaclentp;
1433 int aclcnt, dfaclcnt;
1434 int aclsz, dfaclsz;
1436 error = ln_ace_to_aent(acebufp, acecnt, owner, group,
1437 &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir);
1439 if (error)
1440 return (error);
1443 if (dfaclcnt != 0) {
1445 * Slap aclentp and dfaclentp into a single array.
1447 aclsz = sizeof (aclent_t) * aclcnt;
1448 dfaclsz = sizeof (aclent_t) * dfaclcnt;
1449 aclentp = cacl_realloc(aclentp, aclsz, aclsz + dfaclsz);
1450 if (aclentp != NULL) {
1451 (void) memcpy(aclentp + aclcnt, dfaclentp, dfaclsz);
1452 } else {
1453 error = ENOMEM;
1457 if (aclentp) {
1458 *retaclentp = aclentp;
1459 *retaclcnt = aclcnt + dfaclcnt;
1462 if (dfaclentp)
1463 cacl_free(dfaclentp, dfaclsz);
1465 return (error);
1470 acl_translate(acl_t *aclp, int target_flavor, boolean_t isdir, uid_t owner,
1471 gid_t group)
1473 int aclcnt;
1474 void *acldata;
1475 int error;
1478 * See if we need to translate
1480 if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) ||
1481 (target_flavor == _ACL_ACLENT_ENABLED &&
1482 aclp->acl_type == ACLENT_T))
1483 return (0);
1485 if (target_flavor == -1) {
1486 error = EINVAL;
1487 goto out;
1490 if (target_flavor == _ACL_ACE_ENABLED &&
1491 aclp->acl_type == ACLENT_T) {
1492 error = convert_aent_to_ace(aclp->acl_aclp,
1493 aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt);
1494 if (error)
1495 goto out;
1497 } else if (target_flavor == _ACL_ACLENT_ENABLED &&
1498 aclp->acl_type == ACE_T) {
1499 error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt,
1500 isdir, owner, group, (aclent_t **)&acldata, &aclcnt);
1501 if (error)
1502 goto out;
1503 } else {
1504 error = ENOTSUP;
1505 goto out;
1509 * replace old acl with newly translated acl
1511 cacl_free(aclp->acl_aclp, aclp->acl_cnt * aclp->acl_entry_size);
1512 aclp->acl_aclp = acldata;
1513 aclp->acl_cnt = aclcnt;
1514 if (target_flavor == _ACL_ACE_ENABLED) {
1515 aclp->acl_type = ACE_T;
1516 aclp->acl_entry_size = sizeof (ace_t);
1517 } else {
1518 aclp->acl_type = ACLENT_T;
1519 aclp->acl_entry_size = sizeof (aclent_t);
1521 return (0);
1523 out:
1525 #if !defined(_KERNEL)
1526 errno = error;
1527 return (-1);
1528 #else
1529 return (error);
1530 #endif
1532 #endif /* !_KERNEL */
1534 #define SET_ACE(acl, index, who, mask, type, flags) { \
1535 acl[0][index].a_who = (uint32_t)who; \
1536 acl[0][index].a_type = type; \
1537 acl[0][index].a_flags = flags; \
1538 acl[0][index++].a_access_mask = mask; \
1541 void
1542 acl_trivial_access_masks(mode_t mode, boolean_t isdir, trivial_acl_t *masks)
1544 uint32_t read_mask = ACE_READ_DATA;
1545 uint32_t write_mask = ACE_WRITE_DATA|ACE_APPEND_DATA;
1546 uint32_t execute_mask = ACE_EXECUTE;
1548 (void) isdir; /* will need this later */
1550 masks->deny1 = 0;
1551 if (!(mode & S_IRUSR) && (mode & (S_IRGRP|S_IROTH)))
1552 masks->deny1 |= read_mask;
1553 if (!(mode & S_IWUSR) && (mode & (S_IWGRP|S_IWOTH)))
1554 masks->deny1 |= write_mask;
1555 if (!(mode & S_IXUSR) && (mode & (S_IXGRP|S_IXOTH)))
1556 masks->deny1 |= execute_mask;
1558 masks->deny2 = 0;
1559 if (!(mode & S_IRGRP) && (mode & S_IROTH))
1560 masks->deny2 |= read_mask;
1561 if (!(mode & S_IWGRP) && (mode & S_IWOTH))
1562 masks->deny2 |= write_mask;
1563 if (!(mode & S_IXGRP) && (mode & S_IXOTH))
1564 masks->deny2 |= execute_mask;
1566 masks->allow0 = 0;
1567 if ((mode & S_IRUSR) && (!(mode & S_IRGRP) && (mode & S_IROTH)))
1568 masks->allow0 |= read_mask;
1569 if ((mode & S_IWUSR) && (!(mode & S_IWGRP) && (mode & S_IWOTH)))
1570 masks->allow0 |= write_mask;
1571 if ((mode & S_IXUSR) && (!(mode & S_IXGRP) && (mode & S_IXOTH)))
1572 masks->allow0 |= execute_mask;
1574 masks->owner = ACE_WRITE_ATTRIBUTES|ACE_WRITE_OWNER|ACE_WRITE_ACL|
1575 ACE_WRITE_NAMED_ATTRS|ACE_READ_ACL|ACE_READ_ATTRIBUTES|
1576 ACE_READ_NAMED_ATTRS|ACE_SYNCHRONIZE;
1577 if (mode & S_IRUSR)
1578 masks->owner |= read_mask;
1579 if (mode & S_IWUSR)
1580 masks->owner |= write_mask;
1581 if (mode & S_IXUSR)
1582 masks->owner |= execute_mask;
1584 masks->group = ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_NAMED_ATTRS|
1585 ACE_SYNCHRONIZE;
1586 if (mode & S_IRGRP)
1587 masks->group |= read_mask;
1588 if (mode & S_IWGRP)
1589 masks->group |= write_mask;
1590 if (mode & S_IXGRP)
1591 masks->group |= execute_mask;
1593 masks->everyone = ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_NAMED_ATTRS|
1594 ACE_SYNCHRONIZE;
1595 if (mode & S_IROTH)
1596 masks->everyone |= read_mask;
1597 if (mode & S_IWOTH)
1598 masks->everyone |= write_mask;
1599 if (mode & S_IXOTH)
1600 masks->everyone |= execute_mask;
1604 acl_trivial_create(mode_t mode, boolean_t isdir, ace_t **acl, int *count)
1606 int index = 0;
1607 int error;
1608 trivial_acl_t masks;
1610 *count = 3;
1611 acl_trivial_access_masks(mode, isdir, &masks);
1613 if (masks.allow0)
1614 (*count)++;
1615 if (masks.deny1)
1616 (*count)++;
1617 if (masks.deny2)
1618 (*count)++;
1620 if ((error = cacl_malloc((void **)acl, *count * sizeof (ace_t))) != 0)
1621 return (error);
1623 if (masks.allow0) {
1624 SET_ACE(acl, index, -1, masks.allow0,
1625 ACE_ACCESS_ALLOWED_ACE_TYPE, ACE_OWNER);
1627 if (masks.deny1) {
1628 SET_ACE(acl, index, -1, masks.deny1,
1629 ACE_ACCESS_DENIED_ACE_TYPE, ACE_OWNER);
1631 if (masks.deny2) {
1632 SET_ACE(acl, index, -1, masks.deny2,
1633 ACE_ACCESS_DENIED_ACE_TYPE, ACE_GROUP|ACE_IDENTIFIER_GROUP);
1636 SET_ACE(acl, index, -1, masks.owner, ACE_ACCESS_ALLOWED_ACE_TYPE,
1637 ACE_OWNER);
1638 SET_ACE(acl, index, -1, masks.group, ACE_ACCESS_ALLOWED_ACE_TYPE,
1639 ACE_IDENTIFIER_GROUP|ACE_GROUP);
1640 SET_ACE(acl, index, -1, masks.everyone, ACE_ACCESS_ALLOWED_ACE_TYPE,
1641 ACE_EVERYONE);
1643 return (0);
1647 * ace_trivial:
1648 * determine whether an ace_t acl is trivial
1650 * Trivialness implies that the acl is composed of only
1651 * owner, group, everyone entries. ACL can't
1652 * have read_acl denied, and write_owner/write_acl/write_attributes
1653 * can only be owner@ entry.
1656 ace_trivial_common(void *acep, int aclcnt,
1657 uintptr_t (*walk)(void *, uintptr_t, int aclcnt,
1658 uint16_t *, uint16_t *, uint32_t *))
1660 uint16_t flags;
1661 uint32_t mask;
1662 uint16_t type;
1663 uintptr_t cookie = 0;
1665 while ((cookie = walk(acep, cookie, aclcnt, &flags, &type, &mask))) {
1666 switch (flags & ACE_TYPE_FLAGS) {
1667 case ACE_OWNER:
1668 case ACE_GROUP|ACE_IDENTIFIER_GROUP:
1669 case ACE_EVERYONE:
1670 break;
1671 default:
1672 return (1);
1676 if (flags & (ACE_FILE_INHERIT_ACE|
1677 ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE|
1678 ACE_INHERIT_ONLY_ACE))
1679 return (1);
1682 * Special check for some special bits
1684 * Don't allow anybody to deny reading basic
1685 * attributes or a files ACL.
1687 if ((mask & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
1688 (type == ACE_ACCESS_DENIED_ACE_TYPE))
1689 return (1);
1692 * Delete permissions are never set by default
1694 if (mask & (ACE_DELETE|ACE_DELETE_CHILD))
1695 return (1);
1697 * only allow owner@ to have
1698 * write_acl/write_owner/write_attributes/write_xattr/
1700 if (type == ACE_ACCESS_ALLOWED_ACE_TYPE &&
1701 (!(flags & ACE_OWNER) && (mask &
1702 (ACE_WRITE_OWNER|ACE_WRITE_ACL| ACE_WRITE_ATTRIBUTES|
1703 ACE_WRITE_NAMED_ATTRS))))
1704 return (1);
1707 return (0);