Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / cddl / osnet / dist / common / acl / acl_common.c
bloba01d244529254779bd14ae55e643e7c4773f68dd
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 http://www.opensolaris.org/os/licensing.
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 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/avl.h>
31 #if defined(_KERNEL)
32 #include <sys/systm.h>
33 #include <sys/sysmacros.h>
34 #include <acl/acl_common.h>
35 #include <sys/kmem.h>
36 #else
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <stddef.h>
40 #include <strings.h>
41 #include <unistd.h>
42 #include <assert.h>
43 #include <grp.h>
44 #include <pwd.h>
45 #include <acl_common.h>
46 #define ASSERT assert
47 #endif
49 #define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \
50 ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \
51 ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL)
54 #define ACL_SYNCHRONIZE_SET_DENY 0x0000001
55 #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002
56 #define ACL_SYNCHRONIZE_ERR_DENY 0x0000004
57 #define ACL_SYNCHRONIZE_ERR_ALLOW 0x0000008
59 #define ACL_WRITE_OWNER_SET_DENY 0x0000010
60 #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020
61 #define ACL_WRITE_OWNER_ERR_DENY 0x0000040
62 #define ACL_WRITE_OWNER_ERR_ALLOW 0x0000080
64 #define ACL_DELETE_SET_DENY 0x0000100
65 #define ACL_DELETE_SET_ALLOW 0x0000200
66 #define ACL_DELETE_ERR_DENY 0x0000400
67 #define ACL_DELETE_ERR_ALLOW 0x0000800
69 #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000
70 #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000
71 #define ACL_WRITE_ATTRS_OWNER_ERR_DENY 0x0004000
72 #define ACL_WRITE_ATTRS_OWNER_ERR_ALLOW 0x0008000
74 #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000
75 #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000
76 #define ACL_WRITE_ATTRS_WRITER_ERR_DENY 0x0040000
77 #define ACL_WRITE_ATTRS_WRITER_ERR_ALLOW 0x0080000
79 #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000
80 #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000
81 #define ACL_WRITE_NAMED_WRITER_ERR_DENY 0x0400000
82 #define ACL_WRITE_NAMED_WRITER_ERR_ALLOW 0x0800000
84 #define ACL_READ_NAMED_READER_SET_DENY 0x1000000
85 #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000
86 #define ACL_READ_NAMED_READER_ERR_DENY 0x4000000
87 #define ACL_READ_NAMED_READER_ERR_ALLOW 0x8000000
90 #define ACE_VALID_MASK_BITS (\
91 ACE_READ_DATA | \
92 ACE_LIST_DIRECTORY | \
93 ACE_WRITE_DATA | \
94 ACE_ADD_FILE | \
95 ACE_APPEND_DATA | \
96 ACE_ADD_SUBDIRECTORY | \
97 ACE_READ_NAMED_ATTRS | \
98 ACE_WRITE_NAMED_ATTRS | \
99 ACE_EXECUTE | \
100 ACE_DELETE_CHILD | \
101 ACE_READ_ATTRIBUTES | \
102 ACE_WRITE_ATTRIBUTES | \
103 ACE_DELETE | \
104 ACE_READ_ACL | \
105 ACE_WRITE_ACL | \
106 ACE_WRITE_OWNER | \
107 ACE_SYNCHRONIZE)
109 #define ACE_MASK_UNDEFINED 0x80000000
111 #define ACE_VALID_FLAG_BITS (ACE_FILE_INHERIT_ACE | \
112 ACE_DIRECTORY_INHERIT_ACE | \
113 ACE_NO_PROPAGATE_INHERIT_ACE | ACE_INHERIT_ONLY_ACE | \
114 ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \
115 ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE)
118 * ACL conversion helpers
121 typedef enum {
122 ace_unused,
123 ace_user_obj,
124 ace_user,
125 ace_group, /* includes GROUP and GROUP_OBJ */
126 ace_other_obj
127 } ace_to_aent_state_t;
129 typedef struct acevals {
130 uid_t key;
131 avl_node_t avl;
132 uint32_t mask;
133 uint32_t allowed;
134 uint32_t denied;
135 int aent_type;
136 } acevals_t;
138 typedef struct ace_list {
139 acevals_t user_obj;
140 avl_tree_t user;
141 int numusers;
142 acevals_t group_obj;
143 avl_tree_t group;
144 int numgroups;
145 acevals_t other_obj;
146 uint32_t acl_mask;
147 int hasmask;
148 int dfacl_flag;
149 ace_to_aent_state_t state;
150 int seen; /* bitmask of all aclent_t a_type values seen */
151 } ace_list_t;
153 ace_t trivial_acl[] = {
154 {(uid_t)-1, 0, ACE_OWNER, ACE_ACCESS_DENIED_ACE_TYPE},
155 {(uid_t)-1, ACE_WRITE_ACL|ACE_WRITE_OWNER|ACE_WRITE_ATTRIBUTES|
156 ACE_WRITE_NAMED_ATTRS, ACE_OWNER, ACE_ACCESS_ALLOWED_ACE_TYPE},
157 {(uid_t)-1, 0, ACE_GROUP|ACE_IDENTIFIER_GROUP,
158 ACE_ACCESS_DENIED_ACE_TYPE},
159 {(uid_t)-1, 0, ACE_GROUP|ACE_IDENTIFIER_GROUP,
160 ACE_ACCESS_ALLOWED_ACE_TYPE},
161 {(uid_t)-1, ACE_WRITE_ACL|ACE_WRITE_OWNER| ACE_WRITE_ATTRIBUTES|
162 ACE_WRITE_NAMED_ATTRS, ACE_EVERYONE, ACE_ACCESS_DENIED_ACE_TYPE},
163 {(uid_t)-1, ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_READ_NAMED_ATTRS|
164 ACE_SYNCHRONIZE, ACE_EVERYONE, ACE_ACCESS_ALLOWED_ACE_TYPE}
168 void
169 adjust_ace_pair_common(void *pair, size_t access_off,
170 size_t pairsize, mode_t mode)
172 char *datap = (char *)pair;
173 uint32_t *amask0 = (uint32_t *)(uintptr_t)(datap + access_off);
174 uint32_t *amask1 = (uint32_t *)(uintptr_t)(datap + pairsize +
175 access_off);
176 if (mode & S_IROTH)
177 *amask1 |= ACE_READ_DATA;
178 else
179 *amask0 |= ACE_READ_DATA;
180 if (mode & S_IWOTH)
181 *amask1 |= ACE_WRITE_DATA|ACE_APPEND_DATA;
182 else
183 *amask0 |= ACE_WRITE_DATA|ACE_APPEND_DATA;
184 if (mode & S_IXOTH)
185 *amask1 |= ACE_EXECUTE;
186 else
187 *amask0 |= ACE_EXECUTE;
190 void
191 adjust_ace_pair(ace_t *pair, mode_t mode)
193 adjust_ace_pair_common(pair, offsetof(ace_t, a_access_mask),
194 sizeof (ace_t), mode);
197 static void
198 ace_allow_deny_helper(uint16_t type, boolean_t *allow, boolean_t *deny)
200 if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
201 *allow = B_TRUE;
202 else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
203 *deny = B_TRUE;
207 * ace_trivial:
208 * determine whether an ace_t acl is trivial
210 * Trivialness implies that the acl is composed of only
211 * owner, group, everyone entries. ACL can't
212 * have read_acl denied, and write_owner/write_acl/write_attributes
213 * can only be owner@ entry.
216 ace_trivial_common(void *acep, int aclcnt,
217 uint64_t (*walk)(void *, uint64_t, int aclcnt,
218 uint16_t *, uint16_t *, uint32_t *))
220 boolean_t owner_allow = B_FALSE;
221 boolean_t group_allow = B_FALSE;
222 boolean_t everyone_allow = B_FALSE;
223 boolean_t owner_deny = B_FALSE;
224 boolean_t group_deny = B_FALSE;
225 boolean_t everyone_deny = B_FALSE;
226 uint16_t flags;
227 uint32_t mask;
228 uint16_t type;
229 uint64_t cookie = 0;
231 while (cookie = walk(acep, cookie, aclcnt, &flags, &type, &mask)) {
232 switch (flags & ACE_TYPE_FLAGS) {
233 case ACE_OWNER:
234 if (group_allow || group_deny || everyone_allow ||
235 everyone_deny)
236 return (1);
237 ace_allow_deny_helper(type, &owner_allow, &owner_deny);
238 break;
239 case ACE_GROUP|ACE_IDENTIFIER_GROUP:
240 if (everyone_allow || everyone_deny &&
241 (!owner_allow && !owner_deny))
242 return (1);
243 ace_allow_deny_helper(type, &group_allow, &group_deny);
244 break;
246 case ACE_EVERYONE:
247 if (!owner_allow && !owner_deny &&
248 !group_allow && !group_deny)
249 return (1);
250 ace_allow_deny_helper(type,
251 &everyone_allow, &everyone_deny);
252 break;
253 default:
254 return (1);
258 if (flags & (ACE_FILE_INHERIT_ACE|
259 ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE|
260 ACE_INHERIT_ONLY_ACE))
261 return (1);
264 * Special check for some special bits
266 * Don't allow anybody to deny reading basic
267 * attributes or a files ACL.
269 if ((mask & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
270 (type == ACE_ACCESS_DENIED_ACE_TYPE))
271 return (1);
274 * Allow on owner@ to allow
275 * write_acl/write_owner/write_attributes
277 if (type == ACE_ACCESS_ALLOWED_ACE_TYPE &&
278 (!(flags & ACE_OWNER) && (mask &
279 (ACE_WRITE_OWNER|ACE_WRITE_ACL|ACE_WRITE_ATTRIBUTES))))
280 return (1);
284 if (!owner_allow || !owner_deny || !group_allow || !group_deny ||
285 !everyone_allow || !everyone_deny)
286 return (1);
288 return (0);
291 uint64_t
292 ace_walk(void *datap, uint64_t cookie, int aclcnt, uint16_t *flags,
293 uint16_t *type, uint32_t *mask)
295 ace_t *acep = datap;
297 if (cookie >= aclcnt)
298 return (0);
300 *flags = acep[cookie].a_flags;
301 *type = acep[cookie].a_type;
302 *mask = acep[cookie++].a_access_mask;
304 return (cookie);
308 ace_trivial(ace_t *acep, int aclcnt)
310 return (ace_trivial_common(acep, aclcnt, ace_walk));
314 * Generic shellsort, from K&R (1st ed, p 58.), somewhat modified.
315 * v = Ptr to array/vector of objs
316 * n = # objs in the array
317 * s = size of each obj (must be multiples of a word size)
318 * f = ptr to function to compare two objs
319 * returns (-1 = less than, 0 = equal, 1 = greater than
321 void
322 ksort(caddr_t v, int n, int s, int (*f)())
324 int g, i, j, ii;
325 unsigned int *p1, *p2;
326 unsigned int tmp;
328 /* No work to do */
329 if (v == NULL || n <= 1)
330 return;
332 /* Sanity check on arguments */
333 ASSERT(((uintptr_t)v & 0x3) == 0 && (s & 0x3) == 0);
334 ASSERT(s > 0);
335 for (g = n / 2; g > 0; g /= 2) {
336 for (i = g; i < n; i++) {
337 for (j = i - g; j >= 0 &&
338 (*f)(v + j * s, v + (j + g) * s) == 1;
339 j -= g) {
340 p1 = (void *)(v + j * s);
341 p2 = (void *)(v + (j + g) * s);
342 for (ii = 0; ii < s / 4; ii++) {
343 tmp = *p1;
344 *p1++ = *p2;
345 *p2++ = tmp;
353 * Compare two acls, all fields. Returns:
354 * -1 (less than)
355 * 0 (equal)
356 * +1 (greater than)
359 cmp2acls(void *a, void *b)
361 aclent_t *x = (aclent_t *)a;
362 aclent_t *y = (aclent_t *)b;
364 /* Compare types */
365 if (x->a_type < y->a_type)
366 return (-1);
367 if (x->a_type > y->a_type)
368 return (1);
369 /* Equal types; compare id's */
370 if (x->a_id < y->a_id)
371 return (-1);
372 if (x->a_id > y->a_id)
373 return (1);
374 /* Equal ids; compare perms */
375 if (x->a_perm < y->a_perm)
376 return (-1);
377 if (x->a_perm > y->a_perm)
378 return (1);
379 /* Totally equal */
380 return (0);
383 /*ARGSUSED*/
384 static void *
385 cacl_realloc(void *ptr, size_t size, size_t new_size)
387 #if defined(_KERNEL)
388 void *tmp;
390 tmp = kmem_alloc(new_size, KM_SLEEP);
391 (void) memcpy(tmp, ptr, (size < new_size) ? size : new_size);
392 kmem_free(ptr, size);
393 return (tmp);
394 #else
395 return (realloc(ptr, new_size));
396 #endif
399 static int
400 cacl_malloc(void **ptr, size_t size)
402 #if defined(_KERNEL)
403 *ptr = kmem_zalloc(size, KM_SLEEP);
404 return (0);
405 #else
406 *ptr = calloc(1, size);
407 if (*ptr == NULL)
408 return (errno);
410 return (0);
411 #endif
414 /*ARGSUSED*/
415 static void
416 cacl_free(void *ptr, size_t size)
418 #if defined(_KERNEL)
419 kmem_free(ptr, size);
420 #else
421 free(ptr);
422 #endif
425 acl_t *
426 acl_alloc(enum acl_type type)
428 acl_t *aclp;
430 if (cacl_malloc((void **)&aclp, sizeof (acl_t)) != 0)
431 return (NULL);
433 aclp->acl_aclp = NULL;
434 aclp->acl_cnt = 0;
436 switch (type) {
437 case ACE_T:
438 aclp->acl_type = ACE_T;
439 aclp->acl_entry_size = sizeof (ace_t);
440 break;
441 case ACLENT_T:
442 aclp->acl_type = ACLENT_T;
443 aclp->acl_entry_size = sizeof (aclent_t);
444 break;
445 default:
446 acl_free(aclp);
447 aclp = NULL;
449 return (aclp);
453 * Free acl_t structure
455 void
456 acl_free(acl_t *aclp)
458 int acl_size;
460 if (aclp == NULL)
461 return;
463 if (aclp->acl_aclp) {
464 acl_size = aclp->acl_cnt * aclp->acl_entry_size;
465 cacl_free(aclp->acl_aclp, acl_size);
468 cacl_free(aclp, sizeof (acl_t));
471 static uint32_t
472 access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow)
474 uint32_t access_mask = 0;
475 int acl_produce;
476 int synchronize_set = 0, write_owner_set = 0;
477 int delete_set = 0, write_attrs_set = 0;
478 int read_named_set = 0, write_named_set = 0;
480 acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW |
481 ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
482 ACL_WRITE_ATTRS_WRITER_SET_DENY);
484 if (isallow) {
485 synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW;
486 write_owner_set = ACL_WRITE_OWNER_SET_ALLOW;
487 delete_set = ACL_DELETE_SET_ALLOW;
488 if (hasreadperm)
489 read_named_set = ACL_READ_NAMED_READER_SET_ALLOW;
490 if (haswriteperm)
491 write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
492 if (isowner)
493 write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
494 else if (haswriteperm)
495 write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
496 } else {
498 synchronize_set = ACL_SYNCHRONIZE_SET_DENY;
499 write_owner_set = ACL_WRITE_OWNER_SET_DENY;
500 delete_set = ACL_DELETE_SET_DENY;
501 if (hasreadperm)
502 read_named_set = ACL_READ_NAMED_READER_SET_DENY;
503 if (haswriteperm)
504 write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY;
505 if (isowner)
506 write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY;
507 else if (haswriteperm)
508 write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY;
509 else
511 * If the entity is not the owner and does not
512 * have write permissions ACE_WRITE_ATTRIBUTES will
513 * always go in the DENY ACE.
515 access_mask |= ACE_WRITE_ATTRIBUTES;
518 if (acl_produce & synchronize_set)
519 access_mask |= ACE_SYNCHRONIZE;
520 if (acl_produce & write_owner_set)
521 access_mask |= ACE_WRITE_OWNER;
522 if (acl_produce & delete_set)
523 access_mask |= ACE_DELETE;
524 if (acl_produce & write_attrs_set)
525 access_mask |= ACE_WRITE_ATTRIBUTES;
526 if (acl_produce & read_named_set)
527 access_mask |= ACE_READ_NAMED_ATTRS;
528 if (acl_produce & write_named_set)
529 access_mask |= ACE_WRITE_NAMED_ATTRS;
531 return (access_mask);
535 * Given an mode_t, convert it into an access_mask as used
536 * by nfsace, assuming aclent_t -> nfsace semantics.
538 static uint32_t
539 mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow)
541 uint32_t access = 0;
542 int haswriteperm = 0;
543 int hasreadperm = 0;
545 if (isallow) {
546 haswriteperm = (mode & S_IWOTH);
547 hasreadperm = (mode & S_IROTH);
548 } else {
549 haswriteperm = !(mode & S_IWOTH);
550 hasreadperm = !(mode & S_IROTH);
554 * The following call takes care of correctly setting the following
555 * mask bits in the access_mask:
556 * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE,
557 * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS
559 access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow);
561 if (isallow) {
562 access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES;
563 if (isowner)
564 access |= ACE_WRITE_ACL;
565 } else {
566 if (! isowner)
567 access |= ACE_WRITE_ACL;
570 /* read */
571 if (mode & S_IROTH) {
572 access |= ACE_READ_DATA;
574 /* write */
575 if (mode & S_IWOTH) {
576 access |= ACE_WRITE_DATA |
577 ACE_APPEND_DATA;
578 if (isdir)
579 access |= ACE_DELETE_CHILD;
581 /* exec */
582 if (mode & 01) {
583 access |= ACE_EXECUTE;
586 return (access);
590 * Given an nfsace (presumably an ALLOW entry), make a
591 * corresponding DENY entry at the address given.
593 static void
594 ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner)
596 (void) memcpy(deny, allow, sizeof (ace_t));
598 deny->a_who = allow->a_who;
600 deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
601 deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS;
602 if (isdir)
603 deny->a_access_mask ^= ACE_DELETE_CHILD;
605 deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER |
606 ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
607 ACE_WRITE_NAMED_ATTRS);
608 deny->a_access_mask |= access_mask_set((allow->a_access_mask &
609 ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner,
610 B_FALSE);
613 * Make an initial pass over an array of aclent_t's. Gather
614 * information such as an ACL_MASK (if any), number of users,
615 * number of groups, and whether the array needs to be sorted.
617 static int
618 ln_aent_preprocess(aclent_t *aclent, int n,
619 int *hasmask, mode_t *mask,
620 int *numuser, int *numgroup, int *needsort)
622 int error = 0;
623 int i;
624 int curtype = 0;
626 *hasmask = 0;
627 *mask = 07;
628 *needsort = 0;
629 *numuser = 0;
630 *numgroup = 0;
632 for (i = 0; i < n; i++) {
633 if (aclent[i].a_type < curtype)
634 *needsort = 1;
635 else if (aclent[i].a_type > curtype)
636 curtype = aclent[i].a_type;
637 if (aclent[i].a_type & USER)
638 (*numuser)++;
639 if (aclent[i].a_type & (GROUP | GROUP_OBJ))
640 (*numgroup)++;
641 if (aclent[i].a_type & CLASS_OBJ) {
642 if (*hasmask) {
643 error = EINVAL;
644 goto out;
645 } else {
646 *hasmask = 1;
647 *mask = aclent[i].a_perm;
652 if ((! *hasmask) && (*numuser + *numgroup > 1)) {
653 error = EINVAL;
654 goto out;
657 out:
658 return (error);
662 * Convert an array of aclent_t into an array of nfsace entries,
663 * following POSIX draft -> nfsv4 conversion semantics as outlined in
664 * the IETF draft.
666 static int
667 ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir)
669 int error = 0;
670 mode_t mask;
671 int numuser, numgroup, needsort;
672 int resultsize = 0;
673 int i, groupi = 0, skip;
674 ace_t *acep, *result = NULL;
675 int hasmask;
677 error = ln_aent_preprocess(aclent, n, &hasmask, &mask,
678 &numuser, &numgroup, &needsort);
679 if (error != 0)
680 goto out;
682 /* allow + deny for each aclent */
683 resultsize = n * 2;
684 if (hasmask) {
686 * stick extra deny on the group_obj and on each
687 * user|group for the mask (the group_obj was added
688 * into the count for numgroup)
690 resultsize += numuser + numgroup;
691 /* ... and don't count the mask itself */
692 resultsize -= 2;
695 /* sort the source if necessary */
696 if (needsort)
697 ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls);
699 if (cacl_malloc((void **)&result, resultsize * sizeof (ace_t)) != 0)
700 goto out;
702 acep = result;
704 for (i = 0; i < n; i++) {
706 * don't process CLASS_OBJ (mask); mask was grabbed in
707 * ln_aent_preprocess()
709 if (aclent[i].a_type & CLASS_OBJ)
710 continue;
712 /* If we need an ACL_MASK emulator, prepend it now */
713 if ((hasmask) &&
714 (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) {
715 acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
716 acep->a_flags = 0;
717 if (aclent[i].a_type & GROUP_OBJ) {
718 acep->a_who = (uid_t)-1;
719 acep->a_flags |=
720 (ACE_IDENTIFIER_GROUP|ACE_GROUP);
721 } else if (aclent[i].a_type & USER) {
722 acep->a_who = aclent[i].a_id;
723 } else {
724 acep->a_who = aclent[i].a_id;
725 acep->a_flags |= ACE_IDENTIFIER_GROUP;
727 if (aclent[i].a_type & ACL_DEFAULT) {
728 acep->a_flags |= ACE_INHERIT_ONLY_ACE |
729 ACE_FILE_INHERIT_ACE |
730 ACE_DIRECTORY_INHERIT_ACE;
733 * Set the access mask for the prepended deny
734 * ace. To do this, we invert the mask (found
735 * in ln_aent_preprocess()) then convert it to an
736 * DENY ace access_mask.
738 acep->a_access_mask = mode_to_ace_access((mask ^ 07),
739 isdir, 0, 0);
740 acep += 1;
743 /* handle a_perm -> access_mask */
744 acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm,
745 isdir, aclent[i].a_type & USER_OBJ, 1);
747 /* emulate a default aclent */
748 if (aclent[i].a_type & ACL_DEFAULT) {
749 acep->a_flags |= ACE_INHERIT_ONLY_ACE |
750 ACE_FILE_INHERIT_ACE |
751 ACE_DIRECTORY_INHERIT_ACE;
755 * handle a_perm and a_id
757 * this must be done last, since it involves the
758 * corresponding deny aces, which are handled
759 * differently for each different a_type.
761 if (aclent[i].a_type & USER_OBJ) {
762 acep->a_who = (uid_t)-1;
763 acep->a_flags |= ACE_OWNER;
764 ace_make_deny(acep, acep + 1, isdir, B_TRUE);
765 acep += 2;
766 } else if (aclent[i].a_type & USER) {
767 acep->a_who = aclent[i].a_id;
768 ace_make_deny(acep, acep + 1, isdir, B_FALSE);
769 acep += 2;
770 } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) {
771 if (aclent[i].a_type & GROUP_OBJ) {
772 acep->a_who = (uid_t)-1;
773 acep->a_flags |= ACE_GROUP;
774 } else {
775 acep->a_who = aclent[i].a_id;
777 acep->a_flags |= ACE_IDENTIFIER_GROUP;
779 * Set the corresponding deny for the group ace.
781 * The deny aces go after all of the groups, unlike
782 * everything else, where they immediately follow
783 * the allow ace.
785 * We calculate "skip", the number of slots to
786 * skip ahead for the deny ace, here.
788 * The pattern is:
789 * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3
790 * thus, skip is
791 * (2 * numgroup) - 1 - groupi
792 * (2 * numgroup) to account for MD + A
793 * - 1 to account for the fact that we're on the
794 * access (A), not the mask (MD)
795 * - groupi to account for the fact that we have
796 * passed up groupi number of MD's.
798 skip = (2 * numgroup) - 1 - groupi;
799 ace_make_deny(acep, acep + skip, isdir, B_FALSE);
801 * If we just did the last group, skip acep past
802 * all of the denies; else, just move ahead one.
804 if (++groupi >= numgroup)
805 acep += numgroup + 1;
806 else
807 acep += 1;
808 } else if (aclent[i].a_type & OTHER_OBJ) {
809 acep->a_who = (uid_t)-1;
810 acep->a_flags |= ACE_EVERYONE;
811 ace_make_deny(acep, acep + 1, isdir, B_FALSE);
812 acep += 2;
813 } else {
814 error = EINVAL;
815 goto out;
819 *acepp = result;
820 *rescount = resultsize;
822 out:
823 if (error != 0) {
824 if ((result != NULL) && (resultsize > 0)) {
825 cacl_free(result, resultsize * sizeof (ace_t));
829 return (error);
832 static int
833 convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir,
834 ace_t **retacep, int *retacecnt)
836 ace_t *acep;
837 ace_t *dfacep;
838 int acecnt = 0;
839 int dfacecnt = 0;
840 int dfaclstart = 0;
841 int dfaclcnt = 0;
842 aclent_t *aclp;
843 int i;
844 int error;
845 int acesz, dfacesz;
847 ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls);
849 for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) {
850 if (aclp->a_type & ACL_DEFAULT)
851 break;
854 if (i < aclcnt) {
855 dfaclstart = i;
856 dfaclcnt = aclcnt - i;
859 if (dfaclcnt && isdir == 0) {
860 return (EINVAL);
863 error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir);
864 if (error)
865 return (error);
867 if (dfaclcnt) {
868 error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt,
869 &dfacep, &dfacecnt, isdir);
870 if (error) {
871 if (acep) {
872 cacl_free(acep, acecnt * sizeof (ace_t));
874 return (error);
878 if (dfacecnt != 0) {
879 acesz = sizeof (ace_t) * acecnt;
880 dfacesz = sizeof (ace_t) * dfacecnt;
881 acep = cacl_realloc(acep, acesz, acesz + dfacesz);
882 if (acep == NULL)
883 return (ENOMEM);
884 if (dfaclcnt) {
885 (void) memcpy(acep + acecnt, dfacep, dfacesz);
888 if (dfaclcnt)
889 cacl_free(dfacep, dfacecnt * sizeof (ace_t));
891 *retacecnt = acecnt + dfacecnt;
892 *retacep = acep;
893 return (0);
896 static int
897 ace_mask_to_mode(uint32_t mask, o_mode_t *modep, int isdir)
899 int error = 0;
900 o_mode_t mode = 0;
901 uint32_t bits, wantbits;
903 /* read */
904 if (mask & ACE_READ_DATA)
905 mode |= S_IROTH;
907 /* write */
908 wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA);
909 if (isdir)
910 wantbits |= ACE_DELETE_CHILD;
911 bits = mask & wantbits;
912 if (bits != 0) {
913 if (bits != wantbits) {
914 error = ENOTSUP;
915 goto out;
917 mode |= S_IWOTH;
920 /* exec */
921 if (mask & ACE_EXECUTE) {
922 mode |= S_IXOTH;
925 *modep = mode;
927 out:
928 return (error);
931 static void
932 acevals_init(acevals_t *vals, uid_t key)
934 bzero(vals, sizeof (*vals));
935 vals->allowed = ACE_MASK_UNDEFINED;
936 vals->denied = ACE_MASK_UNDEFINED;
937 vals->mask = ACE_MASK_UNDEFINED;
938 vals->key = key;
941 static void
942 ace_list_init(ace_list_t *al, int dfacl_flag)
944 acevals_init(&al->user_obj, NULL);
945 acevals_init(&al->group_obj, NULL);
946 acevals_init(&al->other_obj, NULL);
947 al->numusers = 0;
948 al->numgroups = 0;
949 al->acl_mask = 0;
950 al->hasmask = 0;
951 al->state = ace_unused;
952 al->seen = 0;
953 al->dfacl_flag = dfacl_flag;
957 * Find or create an acevals holder for a given id and avl tree.
959 * Note that only one thread will ever touch these avl trees, so
960 * there is no need for locking.
962 static acevals_t *
963 acevals_find(ace_t *ace, avl_tree_t *avl, int *num)
965 acevals_t key, *rc;
966 avl_index_t where;
968 key.key = ace->a_who;
969 rc = avl_find(avl, &key, &where);
970 if (rc != NULL)
971 return (rc);
973 /* this memory is freed by ln_ace_to_aent()->ace_list_free() */
974 if (cacl_malloc((void **)&rc, sizeof (acevals_t)) != 0)
975 return (NULL);
977 acevals_init(rc, ace->a_who);
978 avl_insert(avl, rc, where);
979 (*num)++;
981 return (rc);
984 static int
985 access_mask_check(ace_t *acep, int mask_bit, int isowner)
987 int set_deny, err_deny;
988 int set_allow, err_allow;
989 int acl_consume;
990 int haswriteperm, hasreadperm;
992 if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
993 haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1;
994 hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1;
995 } else {
996 haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0;
997 hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0;
1000 acl_consume = (ACL_SYNCHRONIZE_ERR_DENY |
1001 ACL_DELETE_ERR_DENY |
1002 ACL_WRITE_OWNER_ERR_DENY |
1003 ACL_WRITE_OWNER_ERR_ALLOW |
1004 ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
1005 ACL_WRITE_ATTRS_OWNER_ERR_DENY |
1006 ACL_WRITE_ATTRS_WRITER_SET_DENY |
1007 ACL_WRITE_ATTRS_WRITER_ERR_ALLOW |
1008 ACL_WRITE_NAMED_WRITER_ERR_DENY |
1009 ACL_READ_NAMED_READER_ERR_DENY);
1011 if (mask_bit == ACE_SYNCHRONIZE) {
1012 set_deny = ACL_SYNCHRONIZE_SET_DENY;
1013 err_deny = ACL_SYNCHRONIZE_ERR_DENY;
1014 set_allow = ACL_SYNCHRONIZE_SET_ALLOW;
1015 err_allow = ACL_SYNCHRONIZE_ERR_ALLOW;
1016 } else if (mask_bit == ACE_WRITE_OWNER) {
1017 set_deny = ACL_WRITE_OWNER_SET_DENY;
1018 err_deny = ACL_WRITE_OWNER_ERR_DENY;
1019 set_allow = ACL_WRITE_OWNER_SET_ALLOW;
1020 err_allow = ACL_WRITE_OWNER_ERR_ALLOW;
1021 } else if (mask_bit == ACE_DELETE) {
1022 set_deny = ACL_DELETE_SET_DENY;
1023 err_deny = ACL_DELETE_ERR_DENY;
1024 set_allow = ACL_DELETE_SET_ALLOW;
1025 err_allow = ACL_DELETE_ERR_ALLOW;
1026 } else if (mask_bit == ACE_WRITE_ATTRIBUTES) {
1027 if (isowner) {
1028 set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY;
1029 err_deny = ACL_WRITE_ATTRS_OWNER_ERR_DENY;
1030 set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
1031 err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW;
1032 } else if (haswriteperm) {
1033 set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY;
1034 err_deny = ACL_WRITE_ATTRS_WRITER_ERR_DENY;
1035 set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
1036 err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW;
1037 } else {
1038 if ((acep->a_access_mask & mask_bit) &&
1039 (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) {
1040 return (ENOTSUP);
1042 return (0);
1044 } else if (mask_bit == ACE_READ_NAMED_ATTRS) {
1045 if (!hasreadperm)
1046 return (0);
1048 set_deny = ACL_READ_NAMED_READER_SET_DENY;
1049 err_deny = ACL_READ_NAMED_READER_ERR_DENY;
1050 set_allow = ACL_READ_NAMED_READER_SET_ALLOW;
1051 err_allow = ACL_READ_NAMED_READER_ERR_ALLOW;
1052 } else if (mask_bit == ACE_WRITE_NAMED_ATTRS) {
1053 if (!haswriteperm)
1054 return (0);
1056 set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY;
1057 err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY;
1058 set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
1059 err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW;
1060 } else {
1061 return (EINVAL);
1064 if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
1065 if (acl_consume & set_deny) {
1066 if (!(acep->a_access_mask & mask_bit)) {
1067 return (ENOTSUP);
1069 } else if (acl_consume & err_deny) {
1070 if (acep->a_access_mask & mask_bit) {
1071 return (ENOTSUP);
1074 } else {
1075 /* ACE_ACCESS_ALLOWED_ACE_TYPE */
1076 if (acl_consume & set_allow) {
1077 if (!(acep->a_access_mask & mask_bit)) {
1078 return (ENOTSUP);
1080 } else if (acl_consume & err_allow) {
1081 if (acep->a_access_mask & mask_bit) {
1082 return (ENOTSUP);
1086 return (0);
1089 static int
1090 ace_to_aent_legal(ace_t *acep)
1092 int error = 0;
1093 int isowner;
1095 /* only ALLOW or DENY */
1096 if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) &&
1097 (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) {
1098 error = ENOTSUP;
1099 goto out;
1102 /* check for invalid flags */
1103 if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) {
1104 error = EINVAL;
1105 goto out;
1108 /* some flags are illegal */
1109 if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG |
1110 ACE_FAILED_ACCESS_ACE_FLAG |
1111 ACE_NO_PROPAGATE_INHERIT_ACE)) {
1112 error = ENOTSUP;
1113 goto out;
1116 /* check for invalid masks */
1117 if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) {
1118 error = EINVAL;
1119 goto out;
1122 if ((acep->a_flags & ACE_OWNER)) {
1123 isowner = 1;
1124 } else {
1125 isowner = 0;
1128 error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner);
1129 if (error)
1130 goto out;
1132 error = access_mask_check(acep, ACE_WRITE_OWNER, isowner);
1133 if (error)
1134 goto out;
1136 error = access_mask_check(acep, ACE_DELETE, isowner);
1137 if (error)
1138 goto out;
1140 error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner);
1141 if (error)
1142 goto out;
1144 error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner);
1145 if (error)
1146 goto out;
1148 error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner);
1149 if (error)
1150 goto out;
1152 /* more detailed checking of masks */
1153 if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
1154 if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) {
1155 error = ENOTSUP;
1156 goto out;
1158 if ((acep->a_access_mask & ACE_WRITE_DATA) &&
1159 (! (acep->a_access_mask & ACE_APPEND_DATA))) {
1160 error = ENOTSUP;
1161 goto out;
1163 if ((! (acep->a_access_mask & ACE_WRITE_DATA)) &&
1164 (acep->a_access_mask & ACE_APPEND_DATA)) {
1165 error = ENOTSUP;
1166 goto out;
1170 /* ACL enforcement */
1171 if ((acep->a_access_mask & ACE_READ_ACL) &&
1172 (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) {
1173 error = ENOTSUP;
1174 goto out;
1176 if (acep->a_access_mask & ACE_WRITE_ACL) {
1177 if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) &&
1178 (isowner)) {
1179 error = ENOTSUP;
1180 goto out;
1182 if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) &&
1183 (! isowner)) {
1184 error = ENOTSUP;
1185 goto out;
1189 out:
1190 return (error);
1193 static int
1194 ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir)
1196 /* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */
1197 if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) !=
1198 (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) {
1199 return (ENOTSUP);
1202 return (ace_mask_to_mode(mask, modep, isdir));
1205 static int
1206 acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list,
1207 uid_t owner, gid_t group, int isdir)
1209 int error;
1210 uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
1212 if (isdir)
1213 flips |= ACE_DELETE_CHILD;
1214 if (vals->allowed != (vals->denied ^ flips)) {
1215 error = ENOTSUP;
1216 goto out;
1218 if ((list->hasmask) && (list->acl_mask != vals->mask) &&
1219 (vals->aent_type & (USER | GROUP | GROUP_OBJ))) {
1220 error = ENOTSUP;
1221 goto out;
1223 error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir);
1224 if (error != 0)
1225 goto out;
1226 dest->a_type = vals->aent_type;
1227 if (dest->a_type & (USER | GROUP)) {
1228 dest->a_id = vals->key;
1229 } else if (dest->a_type & USER_OBJ) {
1230 dest->a_id = owner;
1231 } else if (dest->a_type & GROUP_OBJ) {
1232 dest->a_id = group;
1233 } else if (dest->a_type & OTHER_OBJ) {
1234 dest->a_id = 0;
1235 } else {
1236 error = EINVAL;
1237 goto out;
1240 out:
1241 return (error);
1245 static int
1246 ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt,
1247 uid_t owner, gid_t group, int isdir)
1249 int error = 0;
1250 aclent_t *aent, *result = NULL;
1251 acevals_t *vals;
1252 int resultcount;
1254 if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) !=
1255 (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) {
1256 error = ENOTSUP;
1257 goto out;
1259 if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) {
1260 error = ENOTSUP;
1261 goto out;
1264 resultcount = 3 + list->numusers + list->numgroups;
1266 * This must be the same condition as below, when we add the CLASS_OBJ
1267 * (aka ACL mask)
1269 if ((list->hasmask) || (! list->dfacl_flag))
1270 resultcount += 1;
1272 if (cacl_malloc((void **)&result,
1273 resultcount * sizeof (aclent_t)) != 0) {
1274 error = ENOMEM;
1275 goto out;
1277 aent = result;
1279 /* USER_OBJ */
1280 if (!(list->user_obj.aent_type & USER_OBJ)) {
1281 error = EINVAL;
1282 goto out;
1285 error = acevals_to_aent(&list->user_obj, aent, list, owner, group,
1286 isdir);
1288 if (error != 0)
1289 goto out;
1290 ++aent;
1291 /* USER */
1292 vals = NULL;
1293 for (vals = avl_first(&list->user); vals != NULL;
1294 vals = AVL_NEXT(&list->user, vals)) {
1295 if (!(vals->aent_type & USER)) {
1296 error = EINVAL;
1297 goto out;
1299 error = acevals_to_aent(vals, aent, list, owner, group,
1300 isdir);
1301 if (error != 0)
1302 goto out;
1303 ++aent;
1305 /* GROUP_OBJ */
1306 if (!(list->group_obj.aent_type & GROUP_OBJ)) {
1307 error = EINVAL;
1308 goto out;
1310 error = acevals_to_aent(&list->group_obj, aent, list, owner, group,
1311 isdir);
1312 if (error != 0)
1313 goto out;
1314 ++aent;
1315 /* GROUP */
1316 vals = NULL;
1317 for (vals = avl_first(&list->group); vals != NULL;
1318 vals = AVL_NEXT(&list->group, vals)) {
1319 if (!(vals->aent_type & GROUP)) {
1320 error = EINVAL;
1321 goto out;
1323 error = acevals_to_aent(vals, aent, list, owner, group,
1324 isdir);
1325 if (error != 0)
1326 goto out;
1327 ++aent;
1330 * CLASS_OBJ (aka ACL_MASK)
1332 * An ACL_MASK is not fabricated if the ACL is a default ACL.
1333 * This is to follow UFS's behavior.
1335 if ((list->hasmask) || (! list->dfacl_flag)) {
1336 if (list->hasmask) {
1337 uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
1338 if (isdir)
1339 flips |= ACE_DELETE_CHILD;
1340 error = ace_mask_to_mode(list->acl_mask ^ flips,
1341 &aent->a_perm, isdir);
1342 if (error != 0)
1343 goto out;
1344 } else {
1345 /* fabricate the ACL_MASK from the group permissions */
1346 error = ace_mask_to_mode(list->group_obj.allowed,
1347 &aent->a_perm, isdir);
1348 if (error != 0)
1349 goto out;
1351 aent->a_id = 0;
1352 aent->a_type = CLASS_OBJ | list->dfacl_flag;
1353 ++aent;
1355 /* OTHER_OBJ */
1356 if (!(list->other_obj.aent_type & OTHER_OBJ)) {
1357 error = EINVAL;
1358 goto out;
1360 error = acevals_to_aent(&list->other_obj, aent, list, owner, group,
1361 isdir);
1362 if (error != 0)
1363 goto out;
1364 ++aent;
1366 *aclentp = result;
1367 *aclcnt = resultcount;
1369 out:
1370 if (error != 0) {
1371 if (result != NULL)
1372 cacl_free(result, resultcount * sizeof (aclent_t));
1375 return (error);
1380 * free all data associated with an ace_list
1382 static void
1383 ace_list_free(ace_list_t *al)
1385 acevals_t *node;
1386 void *cookie;
1388 if (al == NULL)
1389 return;
1391 cookie = NULL;
1392 while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL)
1393 cacl_free(node, sizeof (acevals_t));
1394 cookie = NULL;
1395 while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL)
1396 cacl_free(node, sizeof (acevals_t));
1398 avl_destroy(&al->user);
1399 avl_destroy(&al->group);
1401 /* free the container itself */
1402 cacl_free(al, sizeof (ace_list_t));
1405 static int
1406 acevals_compare(const void *va, const void *vb)
1408 const acevals_t *a = va, *b = vb;
1410 if (a->key == b->key)
1411 return (0);
1413 if (a->key > b->key)
1414 return (1);
1416 else
1417 return (-1);
1421 * Convert a list of ace_t entries to equivalent regular and default
1422 * aclent_t lists. Return error (ENOTSUP) when conversion is not possible.
1424 static int
1425 ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group,
1426 aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt,
1427 int isdir)
1429 int error = 0;
1430 ace_t *acep;
1431 uint32_t bits;
1432 int i;
1433 ace_list_t *normacl = NULL, *dfacl = NULL, *acl;
1434 acevals_t *vals;
1436 *aclentp = NULL;
1437 *aclcnt = 0;
1438 *dfaclentp = NULL;
1439 *dfaclcnt = 0;
1441 /* we need at least user_obj, group_obj, and other_obj */
1442 if (n < 6) {
1443 error = ENOTSUP;
1444 goto out;
1446 if (ace == NULL) {
1447 error = EINVAL;
1448 goto out;
1451 error = cacl_malloc((void **)&normacl, sizeof (ace_list_t));
1452 if (error != 0)
1453 goto out;
1455 avl_create(&normacl->user, acevals_compare, sizeof (acevals_t),
1456 offsetof(acevals_t, avl));
1457 avl_create(&normacl->group, acevals_compare, sizeof (acevals_t),
1458 offsetof(acevals_t, avl));
1460 ace_list_init(normacl, 0);
1462 error = cacl_malloc((void **)&dfacl, sizeof (ace_list_t));
1463 if (error != 0)
1464 goto out;
1466 avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t),
1467 offsetof(acevals_t, avl));
1468 avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t),
1469 offsetof(acevals_t, avl));
1470 ace_list_init(dfacl, ACL_DEFAULT);
1472 /* process every ace_t... */
1473 for (i = 0; i < n; i++) {
1474 acep = &ace[i];
1476 /* rule out certain cases quickly */
1477 error = ace_to_aent_legal(acep);
1478 if (error != 0)
1479 goto out;
1482 * Turn off these bits in order to not have to worry about
1483 * them when doing the checks for compliments.
1485 acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE |
1486 ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES |
1487 ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS);
1489 /* see if this should be a regular or default acl */
1490 bits = acep->a_flags &
1491 (ACE_INHERIT_ONLY_ACE |
1492 ACE_FILE_INHERIT_ACE |
1493 ACE_DIRECTORY_INHERIT_ACE);
1494 if (bits != 0) {
1495 /* all or nothing on these inherit bits */
1496 if (bits != (ACE_INHERIT_ONLY_ACE |
1497 ACE_FILE_INHERIT_ACE |
1498 ACE_DIRECTORY_INHERIT_ACE)) {
1499 error = ENOTSUP;
1500 goto out;
1502 acl = dfacl;
1503 } else {
1504 acl = normacl;
1507 if ((acep->a_flags & ACE_OWNER)) {
1508 if (acl->state > ace_user_obj) {
1509 error = ENOTSUP;
1510 goto out;
1512 acl->state = ace_user_obj;
1513 acl->seen |= USER_OBJ;
1514 vals = &acl->user_obj;
1515 vals->aent_type = USER_OBJ | acl->dfacl_flag;
1516 } else if ((acep->a_flags & ACE_EVERYONE)) {
1517 acl->state = ace_other_obj;
1518 acl->seen |= OTHER_OBJ;
1519 vals = &acl->other_obj;
1520 vals->aent_type = OTHER_OBJ | acl->dfacl_flag;
1521 } else if (acep->a_flags & ACE_IDENTIFIER_GROUP) {
1522 if (acl->state > ace_group) {
1523 error = ENOTSUP;
1524 goto out;
1526 if ((acep->a_flags & ACE_GROUP)) {
1527 acl->seen |= GROUP_OBJ;
1528 vals = &acl->group_obj;
1529 vals->aent_type = GROUP_OBJ | acl->dfacl_flag;
1530 } else {
1531 acl->seen |= GROUP;
1532 vals = acevals_find(acep, &acl->group,
1533 &acl->numgroups);
1534 if (vals == NULL) {
1535 error = ENOMEM;
1536 goto out;
1538 vals->aent_type = GROUP | acl->dfacl_flag;
1540 acl->state = ace_group;
1541 } else {
1542 if (acl->state > ace_user) {
1543 error = ENOTSUP;
1544 goto out;
1546 acl->state = ace_user;
1547 acl->seen |= USER;
1548 vals = acevals_find(acep, &acl->user,
1549 &acl->numusers);
1550 if (vals == NULL) {
1551 error = ENOMEM;
1552 goto out;
1554 vals->aent_type = USER | acl->dfacl_flag;
1557 if (!(acl->state > ace_unused)) {
1558 error = EINVAL;
1559 goto out;
1562 if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
1563 /* no more than one allowed per aclent_t */
1564 if (vals->allowed != ACE_MASK_UNDEFINED) {
1565 error = ENOTSUP;
1566 goto out;
1568 vals->allowed = acep->a_access_mask;
1569 } else {
1571 * it's a DENY; if there was a previous DENY, it
1572 * must have been an ACL_MASK.
1574 if (vals->denied != ACE_MASK_UNDEFINED) {
1575 /* ACL_MASK is for USER and GROUP only */
1576 if ((acl->state != ace_user) &&
1577 (acl->state != ace_group)) {
1578 error = ENOTSUP;
1579 goto out;
1582 if (! acl->hasmask) {
1583 acl->hasmask = 1;
1584 acl->acl_mask = vals->denied;
1585 /* check for mismatched ACL_MASK emulations */
1586 } else if (acl->acl_mask != vals->denied) {
1587 error = ENOTSUP;
1588 goto out;
1590 vals->mask = vals->denied;
1592 vals->denied = acep->a_access_mask;
1596 /* done collating; produce the aclent_t lists */
1597 if (normacl->state != ace_unused) {
1598 error = ace_list_to_aent(normacl, aclentp, aclcnt,
1599 owner, group, isdir);
1600 if (error != 0) {
1601 goto out;
1604 if (dfacl->state != ace_unused) {
1605 error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt,
1606 owner, group, isdir);
1607 if (error != 0) {
1608 goto out;
1612 out:
1613 if (normacl != NULL)
1614 ace_list_free(normacl);
1615 if (dfacl != NULL)
1616 ace_list_free(dfacl);
1618 return (error);
1621 static int
1622 convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir,
1623 uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt)
1625 int error = 0;
1626 aclent_t *aclentp, *dfaclentp;
1627 int aclcnt, dfaclcnt;
1628 int aclsz, dfaclsz;
1630 error = ln_ace_to_aent(acebufp, acecnt, owner, group,
1631 &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir);
1633 if (error)
1634 return (error);
1637 if (dfaclcnt != 0) {
1639 * Slap aclentp and dfaclentp into a single array.
1641 aclsz = sizeof (aclent_t) * aclcnt;
1642 dfaclsz = sizeof (aclent_t) * dfaclcnt;
1643 aclentp = cacl_realloc(aclentp, aclsz, aclsz + dfaclsz);
1644 if (aclentp != NULL) {
1645 (void) memcpy(aclentp + aclcnt, dfaclentp, dfaclsz);
1646 } else {
1647 error = ENOMEM;
1651 if (aclentp) {
1652 *retaclentp = aclentp;
1653 *retaclcnt = aclcnt + dfaclcnt;
1656 if (dfaclentp)
1657 cacl_free(dfaclentp, dfaclsz);
1659 return (error);
1664 acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner,
1665 gid_t group)
1667 int aclcnt;
1668 void *acldata;
1669 int error;
1672 * See if we need to translate
1674 if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) ||
1675 (target_flavor == _ACL_ACLENT_ENABLED &&
1676 aclp->acl_type == ACLENT_T))
1677 return (0);
1679 if (target_flavor == -1) {
1680 error = EINVAL;
1681 goto out;
1684 if (target_flavor == _ACL_ACE_ENABLED &&
1685 aclp->acl_type == ACLENT_T) {
1686 error = convert_aent_to_ace(aclp->acl_aclp,
1687 aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt);
1688 if (error)
1689 goto out;
1691 } else if (target_flavor == _ACL_ACLENT_ENABLED &&
1692 aclp->acl_type == ACE_T) {
1693 error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt,
1694 isdir, owner, group, (aclent_t **)&acldata, &aclcnt);
1695 if (error)
1696 goto out;
1697 } else {
1698 error = ENOTSUP;
1699 goto out;
1703 * replace old acl with newly translated acl
1705 cacl_free(aclp->acl_aclp, aclp->acl_cnt * aclp->acl_entry_size);
1706 aclp->acl_aclp = acldata;
1707 aclp->acl_cnt = aclcnt;
1708 if (target_flavor == _ACL_ACE_ENABLED) {
1709 aclp->acl_type = ACE_T;
1710 aclp->acl_entry_size = sizeof (ace_t);
1711 } else {
1712 aclp->acl_type = ACLENT_T;
1713 aclp->acl_entry_size = sizeof (aclent_t);
1715 return (0);
1717 out:
1719 #if !defined(_KERNEL)
1720 errno = error;
1721 return (-1);
1722 #else
1723 return (error);
1724 #endif