1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24 */
25
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
46
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)
50
51
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
56
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
61
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
66
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
71
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
76
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
81
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
86
87
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)
106
107 #define ACE_MASK_UNDEFINED 0x80000000
108
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)
114
115 /*
116 * ACL conversion helpers
117 */
118
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;
126
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;
135
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;
150
151 /*
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
158 */
159 void
ksort(caddr_t v,int n,int s,int (* f)(void *,void *))160 ksort(caddr_t v, int n, int s, int (*f)(void *, void *))
161 {
162 int g, i, j, ii;
163 unsigned int *p1, *p2;
164 unsigned int tmp;
165
166 /* No work to do */
167 if (v == NULL || n <= 1)
168 return;
169
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;
185 }
186 }
187 }
188 }
189 }
190
191 /*
192 * Compare two acls, all fields. Returns:
193 * -1 (less than)
194 * 0 (equal)
195 * +1 (greater than)
196 */
197 int
cmp2acls(void * a,void * b)198 cmp2acls(void *a, void *b)
199 {
200 aclent_t *x = (aclent_t *)a;
201 aclent_t *y = (aclent_t *)b;
202
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);
220 }
221
222 static int
cacl_malloc(void ** ptr,size_t size)223 cacl_malloc(void **ptr, size_t size)
224 {
225 *ptr = kmem_zalloc(size, KM_SLEEP);
226 return (0);
227 }
228
229
230 #if !defined(_KERNEL)
231 acl_t *
acl_alloc(enum acl_type type)232 acl_alloc(enum acl_type type)
233 {
234 acl_t *aclp;
235
236 if (cacl_malloc((void **)&aclp, sizeof (acl_t)) != 0)
237 return (NULL);
238
239 aclp->acl_aclp = NULL;
240 aclp->acl_cnt = 0;
241
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;
254 }
255 return (aclp);
256 }
257
258 /*
259 * Free acl_t structure
260 */
261 void
acl_free(acl_t * aclp)262 acl_free(acl_t *aclp)
263 {
264 int acl_size;
265
266 if (aclp == NULL)
267 return;
268
269 if (aclp->acl_aclp) {
270 acl_size = aclp->acl_cnt * aclp->acl_entry_size;
271 cacl_free(aclp->acl_aclp, acl_size);
272 }
273
274 cacl_free(aclp, sizeof (acl_t));
275 }
276
277 static uint32_t
access_mask_set(int haswriteperm,int hasreadperm,int isowner,int isallow)278 access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow)
279 {
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;
285
286 acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW |
287 ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
288 ACL_WRITE_ATTRS_WRITER_SET_DENY);
289
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 {
303
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
316 /*
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.
320 */
321 access_mask |= ACE_WRITE_ATTRIBUTES;
322 }
323
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;
336
337 return (access_mask);
338 }
339
340 /*
341 * Given an mode_t, convert it into an access_mask as used
342 * by nfsace, assuming aclent_t -> nfsace semantics.
343 */
344 static uint32_t
mode_to_ace_access(mode_t mode,boolean_t isdir,int isowner,int isallow)345 mode_to_ace_access(mode_t mode, boolean_t isdir, int isowner, int isallow)
346 {
347 uint32_t access = 0;
348 int haswriteperm = 0;
349 int hasreadperm = 0;
350
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);
357 }
358
359 /*
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
364 */
365 access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow);
366
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;
374 }
375
376 /* read */
377 if (mode & S_IROTH) {
378 access |= ACE_READ_DATA;
379 }
380 /* write */
381 if (mode & S_IWOTH) {
382 access |= ACE_WRITE_DATA |
383 ACE_APPEND_DATA;
384 if (isdir)
385 access |= ACE_DELETE_CHILD;
386 }
387 /* exec */
388 if (mode & S_IXOTH) {
389 access |= ACE_EXECUTE;
390 }
391
392 return (access);
393 }
394
395 /*
396 * Given an nfsace (presumably an ALLOW entry), make a
397 * corresponding DENY entry at the address given.
398 */
399 static void
ace_make_deny(ace_t * allow,ace_t * deny,int isdir,int isowner)400 ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner)
401 {
402 (void) memcpy(deny, allow, sizeof (ace_t));
403
404 deny->a_who = allow->a_who;
405
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;
410
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);
417 }
418 /*
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.
422 */
423 static int
ln_aent_preprocess(aclent_t * aclent,int n,int * hasmask,mode_t * mask,int * numuser,int * numgroup,int * needsort)424 ln_aent_preprocess(aclent_t *aclent, int n,
425 int *hasmask, mode_t *mask,
426 int *numuser, int *numgroup, int *needsort)
427 {
428 int error = 0;
429 int i;
430 int curtype = 0;
431
432 *hasmask = 0;
433 *mask = 07;
434 *needsort = 0;
435 *numuser = 0;
436 *numgroup = 0;
437
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;
454 }
455 }
456 }
457
458 if ((! *hasmask) && (*numuser + *numgroup > 1)) {
459 error = EINVAL;
460 goto out;
461 }
462
463 out:
464 return (error);
465 }
466
467 /*
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.
471 */
472 static int
ln_aent_to_ace(aclent_t * aclent,int n,ace_t ** acepp,int * rescount,int isdir)473 ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir)
474 {
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;
482
483 error = ln_aent_preprocess(aclent, n, &hasmask, &mask,
484 &numuser, &numgroup, &needsort);
485 if (error != 0)
486 goto out;
487
488 /* allow + deny for each aclent */
489 resultsize = n * 2;
490 if (hasmask) {
491 /*
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)
495 */
496 resultsize += numuser + numgroup;
497 /* ... and don't count the mask itself */
498 resultsize -= 2;
499 }
500
501 /* sort the source if necessary */
502 if (needsort)
503 ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls);
504
505 if (cacl_malloc((void **)&result, resultsize * sizeof (ace_t)) != 0)
506 goto out;
507
508 acep = result;
509
510 for (i = 0; i < n; i++) {
511 /*
512 * don't process CLASS_OBJ (mask); mask was grabbed in
513 * ln_aent_preprocess()
514 */
515 if (aclent[i].a_type & CLASS_OBJ)
516 continue;
517
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;
532 }
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;
537 }
538 /*
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.
543 */
544 acep->a_access_mask = mode_to_ace_access((mask ^ 07),
545 isdir, 0, 0);
546 acep += 1;
547 }
548
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);
552
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;
558 }
559
560 /*
561 * handle a_perm and a_id
562 *
563 * this must be done last, since it involves the
564 * corresponding deny aces, which are handled
565 * differently for each different a_type.
566 */
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;
582 }
583 acep->a_flags |= ACE_IDENTIFIER_GROUP;
584 /*
585 * Set the corresponding deny for the group ace.
586 *
587 * The deny aces go after all of the groups, unlike
588 * everything else, where they immediately follow
589 * the allow ace.
590 *
591 * We calculate "skip", the number of slots to
592 * skip ahead for the deny ace, here.
593 *
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.
603 */
604 skip = (2 * numgroup) - 1 - groupi;
605 ace_make_deny(acep, acep + skip, isdir, B_FALSE);
606 /*
607 * If we just did the last group, skip acep past
608 * all of the denies; else, just move ahead one.
609 */
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;
622 }
623 }
624
625 *acepp = result;
626 *rescount = resultsize;
627
628 out:
629 if (error != 0) {
630 if ((result != NULL) && (resultsize > 0)) {
631 cacl_free(result, resultsize * sizeof (ace_t));
632 }
633 }
634
635 return (error);
636 }
637
638 static int
convert_aent_to_ace(aclent_t * aclentp,int aclcnt,boolean_t isdir,ace_t ** retacep,int * retacecnt)639 convert_aent_to_ace(aclent_t *aclentp, int aclcnt, boolean_t isdir,
640 ace_t **retacep, int *retacecnt)
641 {
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;
652
653 ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls);
654
655 for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) {
656 if (aclp->a_type & ACL_DEFAULT)
657 break;
658 }
659
660 if (i < aclcnt) {
661 dfaclstart = i;
662 dfaclcnt = aclcnt - i;
663 }
664
665 if (dfaclcnt && !isdir) {
666 return (EINVAL);
667 }
668
669 error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir);
670 if (error)
671 return (error);
672
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));
679 }
680 return (error);
681 }
682 }
683
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);
692 }
693 }
694 if (dfaclcnt)
695 cacl_free(dfacep, dfacecnt * sizeof (ace_t));
696
697 *retacecnt = acecnt + dfacecnt;
698 *retacep = acep;
699 return (0);
700 }
701
702 static int
ace_mask_to_mode(uint32_t mask,o_mode_t * modep,boolean_t isdir)703 ace_mask_to_mode(uint32_t mask, o_mode_t *modep, boolean_t isdir)
704 {
705 int error = 0;
706 o_mode_t mode = 0;
707 uint32_t bits, wantbits;
708
709 /* read */
710 if (mask & ACE_READ_DATA)
711 mode |= S_IROTH;
712
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;
722 }
723 mode |= S_IWOTH;
724 }
725
726 /* exec */
727 if (mask & ACE_EXECUTE) {
728 mode |= S_IXOTH;
729 }
730
731 *modep = mode;
732
733 out:
734 return (error);
735 }
736
737 static void
acevals_init(acevals_t * vals,uid_t key)738 acevals_init(acevals_t *vals, uid_t key)
739 {
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;
745 }
746
747 static void
ace_list_init(ace_list_t * al,int dfacl_flag)748 ace_list_init(ace_list_t *al, int dfacl_flag)
749 {
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;
760 }
761
762 /*
763 * Find or create an acevals holder for a given id and avl tree.
764 *
765 * Note that only one thread will ever touch these avl trees, so
766 * there is no need for locking.
767 */
768 static acevals_t *
acevals_find(ace_t * ace,avl_tree_t * avl,int * num)769 acevals_find(ace_t *ace, avl_tree_t *avl, int *num)
770 {
771 acevals_t key, *rc;
772 avl_index_t where;
773
774 key.key = ace->a_who;
775 rc = avl_find(avl, &key, &where);
776 if (rc != NULL)
777 return (rc);
778
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);
782
783 acevals_init(rc, ace->a_who);
784 avl_insert(avl, rc, where);
785 (*num)++;
786
787 return (rc);
788 }
789
790 static int
access_mask_check(ace_t * acep,int mask_bit,int isowner)791 access_mask_check(ace_t *acep, int mask_bit, int isowner)
792 {
793 int set_deny, err_deny;
794 int set_allow, err_allow;
795 int acl_consume;
796 int haswriteperm, hasreadperm;
797
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;
804 }
805
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);
816
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);
847 }
848 return (0);
849 }
850 } else if (mask_bit == ACE_READ_NAMED_ATTRS) {
851 if (!hasreadperm)
852 return (0);
853
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);
861
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);
868 }
869
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);
874 }
875 } else if (acl_consume & err_deny) {
876 if (acep->a_access_mask & mask_bit) {
877 return (ENOTSUP);
878 }
879 }
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);
885 }
886 } else if (acl_consume & err_allow) {
887 if (acep->a_access_mask & mask_bit) {
888 return (ENOTSUP);
889 }
890 }
891 }
892 return (0);
893 }
894
895 static int
ace_to_aent_legal(ace_t * acep)896 ace_to_aent_legal(ace_t *acep)
897 {
898 int error = 0;
899 int isowner;
900
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;
906 }
907
908 /* check for invalid flags */
909 if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) {
910 error = EINVAL;
911 goto out;
912 }
913
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;
920 }
921
922 /* check for invalid masks */
923 if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) {
924 error = EINVAL;
925 goto out;
926 }
927
928 if ((acep->a_flags & ACE_OWNER)) {
929 isowner = 1;
930 } else {
931 isowner = 0;
932 }
933
934 error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner);
935 if (error)
936 goto out;
937
938 error = access_mask_check(acep, ACE_WRITE_OWNER, isowner);
939 if (error)
940 goto out;
941
942 error = access_mask_check(acep, ACE_DELETE, isowner);
943 if (error)
944 goto out;
945
946 error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner);
947 if (error)
948 goto out;
949
950 error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner);
951 if (error)
952 goto out;
953
954 error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner);
955 if (error)
956 goto out;
957
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;
963 }
964 if ((acep->a_access_mask & ACE_WRITE_DATA) &&
965 (! (acep->a_access_mask & ACE_APPEND_DATA))) {
966 error = ENOTSUP;
967 goto out;
968 }
969 if ((! (acep->a_access_mask & ACE_WRITE_DATA)) &&
970 (acep->a_access_mask & ACE_APPEND_DATA)) {
971 error = ENOTSUP;
972 goto out;
973 }
974 }
975
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;
981 }
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;
987 }
988 if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) &&
989 (! isowner)) {
990 error = ENOTSUP;
991 goto out;
992 }
993 }
994
995 out:
996 return (error);
997 }
998
999 static int
ace_allow_to_mode(uint32_t mask,o_mode_t * modep,boolean_t isdir)1000 ace_allow_to_mode(uint32_t mask, o_mode_t *modep, boolean_t isdir)
1001 {
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);
1006 }
1007
1008 return (ace_mask_to_mode(mask, modep, isdir));
1009 }
1010
1011 static int
acevals_to_aent(acevals_t * vals,aclent_t * dest,ace_list_t * list,uid_t owner,gid_t group,boolean_t isdir)1012 acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list,
1013 uid_t owner, gid_t group, boolean_t isdir)
1014 {
1015 int error;
1016 uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
1017
1018 if (isdir)
1019 flips |= ACE_DELETE_CHILD;
1020 if (vals->allowed != (vals->denied ^ flips)) {
1021 error = ENOTSUP;
1022 goto out;
1023 }
1024 if ((list->hasmask) && (list->acl_mask != vals->mask) &&
1025 (vals->aent_type & (USER | GROUP | GROUP_OBJ))) {
1026 error = ENOTSUP;
1027 goto out;
1028 }
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;
1044 }
1045
1046 out:
1047 return (error);
1048 }
1049
1050
1051 static int
ace_list_to_aent(ace_list_t * list,aclent_t ** aclentp,int * aclcnt,uid_t owner,gid_t group,boolean_t isdir)1052 ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt,
1053 uid_t owner, gid_t group, boolean_t isdir)
1054 {
1055 int error = 0;
1056 aclent_t *aent, *result = NULL;
1057 acevals_t *vals;
1058 int resultcount;
1059
1060 if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) !=
1061 (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) {
1062 error = ENOTSUP;
1063 goto out;
1064 }
1065 if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) {
1066 error = ENOTSUP;
1067 goto out;
1068 }
1069
1070 resultcount = 3 + list->numusers + list->numgroups;
1071 /*
1072 * This must be the same condition as below, when we add the CLASS_OBJ
1073 * (aka ACL mask)
1074 */
1075 if ((list->hasmask) || (! list->dfacl_flag))
1076 resultcount += 1;
1077
1078 if (cacl_malloc((void **)&result,
1079 resultcount * sizeof (aclent_t)) != 0) {
1080 error = ENOMEM;
1081 goto out;
1082 }
1083 aent = result;
1084
1085 /* USER_OBJ */
1086 if (!(list->user_obj.aent_type & USER_OBJ)) {
1087 error = EINVAL;
1088 goto out;
1089 }
1090
1091 error = acevals_to_aent(&list->user_obj, aent, list, owner, group,
1092 isdir);
1093
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;
1104 }
1105 error = acevals_to_aent(vals, aent, list, owner, group,
1106 isdir);
1107 if (error != 0)
1108 goto out;
1109 ++aent;
1110 }
1111 /* GROUP_OBJ */
1112 if (!(list->group_obj.aent_type & GROUP_OBJ)) {
1113 error = EINVAL;
1114 goto out;
1115 }
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;
1128 }
1129 error = acevals_to_aent(vals, aent, list, owner, group,
1130 isdir);
1131 if (error != 0)
1132 goto out;
1133 ++aent;
1134 }
1135 /*
1136 * CLASS_OBJ (aka ACL_MASK)
1137 *
1138 * An ACL_MASK is not fabricated if the ACL is a default ACL.
1139 * This is to follow UFS's behavior.
1140 */
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;
1156 }
1157 aent->a_id = 0;
1158 aent->a_type = CLASS_OBJ | list->dfacl_flag;
1159 ++aent;
1160 }
1161 /* OTHER_OBJ */
1162 if (!(list->other_obj.aent_type & OTHER_OBJ)) {
1163 error = EINVAL;
1164 goto out;
1165 }
1166 error = acevals_to_aent(&list->other_obj, aent, list, owner, group,
1167 isdir);
1168 if (error != 0)
1169 goto out;
1170 ++aent;
1171
1172 *aclentp = result;
1173 *aclcnt = resultcount;
1174
1175 out:
1176 if (error != 0) {
1177 if (result != NULL)
1178 cacl_free(result, resultcount * sizeof (aclent_t));
1179 }
1180
1181 return (error);
1182 }
1183
1184
1185 /*
1186 * free all data associated with an ace_list
1187 */
1188 static void
ace_list_free(ace_list_t * al)1189 ace_list_free(ace_list_t *al)
1190 {
1191 acevals_t *node;
1192 void *cookie;
1193
1194 if (al == NULL)
1195 return;
1196
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));
1203
1204 avl_destroy(&al->user);
1205 avl_destroy(&al->group);
1206
1207 /* free the container itself */
1208 cacl_free(al, sizeof (ace_list_t));
1209 }
1210
1211 static int
acevals_compare(const void * va,const void * vb)1212 acevals_compare(const void *va, const void *vb)
1213 {
1214 const acevals_t *a = va, *b = vb;
1215
1216 if (a->key == b->key)
1217 return (0);
1218
1219 if (a->key > b->key)
1220 return (1);
1221
1222 else
1223 return (-1);
1224 }
1225
1226 /*
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.
1229 */
1230 static int
ln_ace_to_aent(ace_t * ace,int n,uid_t owner,gid_t group,aclent_t ** aclentp,int * aclcnt,aclent_t ** dfaclentp,int * dfaclcnt,boolean_t isdir)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)
1234 {
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;
1241
1242 *aclentp = NULL;
1243 *aclcnt = 0;
1244 *dfaclentp = NULL;
1245 *dfaclcnt = 0;
1246
1247 /* we need at least user_obj, group_obj, and other_obj */
1248 if (n < 6) {
1249 error = ENOTSUP;
1250 goto out;
1251 }
1252 if (ace == NULL) {
1253 error = EINVAL;
1254 goto out;
1255 }
1256
1257 error = cacl_malloc((void **)&normacl, sizeof (ace_list_t));
1258 if (error != 0)
1259 goto out;
1260
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));
1265
1266 ace_list_init(normacl, 0);
1267
1268 error = cacl_malloc((void **)&dfacl, sizeof (ace_list_t));
1269 if (error != 0)
1270 goto out;
1271
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);
1277
1278 /* process every ace_t... */
1279 for (i = 0; i < n; i++) {
1280 acep = &ace[i];
1281
1282 /* rule out certain cases quickly */
1283 error = ace_to_aent_legal(acep);
1284 if (error != 0)
1285 goto out;
1286
1287 /*
1288 * Turn off these bits in order to not have to worry about
1289 * them when doing the checks for compliments.
1290 */
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);
1294
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;
1307 }
1308 acl = dfacl;
1309 } else {
1310 acl = normacl;
1311 }
1312
1313 if ((acep->a_flags & ACE_OWNER)) {
1314 if (acl->state > ace_user_obj) {
1315 error = ENOTSUP;
1316 goto out;
1317 }
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;
1331 }
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;
1343 }
1344 vals->aent_type = GROUP | acl->dfacl_flag;
1345 }
1346 acl->state = ace_group;
1347 } else {
1348 if (acl->state > ace_user) {
1349 error = ENOTSUP;
1350 goto out;
1351 }
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;
1359 }
1360 vals->aent_type = USER | acl->dfacl_flag;
1361 }
1362
1363 if (!(acl->state > ace_unused)) {
1364 error = EINVAL;
1365 goto out;
1366 }
1367
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;
1373 }
1374 vals->allowed = acep->a_access_mask;
1375 } else {
1376 /*
1377 * it's a DENY; if there was a previous DENY, it
1378 * must have been an ACL_MASK.
1379 */
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;
1386 }
1387
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;
1395 }
1396 vals->mask = vals->denied;
1397 }
1398 vals->denied = acep->a_access_mask;
1399 }
1400 }
1401
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;
1408 }
1409 }
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;
1415 }
1416 }
1417
1418 out:
1419 if (normacl != NULL)
1420 ace_list_free(normacl);
1421 if (dfacl != NULL)
1422 ace_list_free(dfacl);
1423
1424 return (error);
1425 }
1426
1427 static int
convert_ace_to_aent(ace_t * acebufp,int acecnt,boolean_t isdir,uid_t owner,gid_t group,aclent_t ** retaclentp,int * retaclcnt)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)
1430 {
1431 int error = 0;
1432 aclent_t *aclentp, *dfaclentp;
1433 int aclcnt, dfaclcnt;
1434 int aclsz, dfaclsz;
1435
1436 error = ln_ace_to_aent(acebufp, acecnt, owner, group,
1437 &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir);
1438
1439 if (error)
1440 return (error);
1441
1442
1443 if (dfaclcnt != 0) {
1444 /*
1445 * Slap aclentp and dfaclentp into a single array.
1446 */
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;
1454 }
1455 }
1456
1457 if (aclentp) {
1458 *retaclentp = aclentp;
1459 *retaclcnt = aclcnt + dfaclcnt;
1460 }
1461
1462 if (dfaclentp)
1463 cacl_free(dfaclentp, dfaclsz);
1464
1465 return (error);
1466 }
1467
1468
1469 int
acl_translate(acl_t * aclp,int target_flavor,boolean_t isdir,uid_t owner,gid_t group)1470 acl_translate(acl_t *aclp, int target_flavor, boolean_t isdir, uid_t owner,
1471 gid_t group)
1472 {
1473 int aclcnt;
1474 void *acldata;
1475 int error;
1476
1477 /*
1478 * See if we need to translate
1479 */
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);
1484
1485 if (target_flavor == -1) {
1486 error = EINVAL;
1487 goto out;
1488 }
1489
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;
1496
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;
1506 }
1507
1508 /*
1509 * replace old acl with newly translated acl
1510 */
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);
1520 }
1521 return (0);
1522
1523 out:
1524
1525 #if !defined(_KERNEL)
1526 errno = error;
1527 return (-1);
1528 #else
1529 return (error);
1530 #endif
1531 }
1532 #endif /* !_KERNEL */
1533
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; \
1539 }
1540
1541 void
acl_trivial_access_masks(mode_t mode,boolean_t isdir,trivial_acl_t * masks)1542 acl_trivial_access_masks(mode_t mode, boolean_t isdir, trivial_acl_t *masks)
1543 {
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;
1547
1548 (void) isdir; /* will need this later */
1549
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;
1557
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;
1565
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;
1573
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;
1583
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;
1592
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;
1601 }
1602
1603 int
acl_trivial_create(mode_t mode,boolean_t isdir,ace_t ** acl,int * count)1604 acl_trivial_create(mode_t mode, boolean_t isdir, ace_t **acl, int *count)
1605 {
1606 int index = 0;
1607 int error;
1608 trivial_acl_t masks;
1609
1610 *count = 3;
1611 acl_trivial_access_masks(mode, isdir, &masks);
1612
1613 if (masks.allow0)
1614 (*count)++;
1615 if (masks.deny1)
1616 (*count)++;
1617 if (masks.deny2)
1618 (*count)++;
1619
1620 if ((error = cacl_malloc((void **)acl, *count * sizeof (ace_t))) != 0)
1621 return (error);
1622
1623 if (masks.allow0) {
1624 SET_ACE(acl, index, -1, masks.allow0,
1625 ACE_ACCESS_ALLOWED_ACE_TYPE, ACE_OWNER);
1626 }
1627 if (masks.deny1) {
1628 SET_ACE(acl, index, -1, masks.deny1,
1629 ACE_ACCESS_DENIED_ACE_TYPE, ACE_OWNER);
1630 }
1631 if (masks.deny2) {
1632 SET_ACE(acl, index, -1, masks.deny2,
1633 ACE_ACCESS_DENIED_ACE_TYPE, ACE_GROUP|ACE_IDENTIFIER_GROUP);
1634 }
1635
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);
1642
1643 return (0);
1644 }
1645
1646 /*
1647 * ace_trivial:
1648 * determine whether an ace_t acl is trivial
1649 *
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.
1654 */
1655 int
ace_trivial_common(void * acep,int aclcnt,uintptr_t (* walk)(void *,uintptr_t,int aclcnt,uint16_t *,uint16_t *,uint32_t *))1656 ace_trivial_common(void *acep, int aclcnt,
1657 uintptr_t (*walk)(void *, uintptr_t, int aclcnt,
1658 uint16_t *, uint16_t *, uint32_t *))
1659 {
1660 uint16_t flags;
1661 uint32_t mask;
1662 uint16_t type;
1663 uintptr_t cookie = 0;
1664
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);
1673
1674 }
1675
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);
1680
1681 /*
1682 * Special check for some special bits
1683 *
1684 * Don't allow anybody to deny reading basic
1685 * attributes or a files ACL.
1686 */
1687 if ((mask & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) &&
1688 (type == ACE_ACCESS_DENIED_ACE_TYPE))
1689 return (1);
1690
1691 /*
1692 * Delete permissions are never set by default
1693 */
1694 if (mask & (ACE_DELETE|ACE_DELETE_CHILD))
1695 return (1);
1696 /*
1697 * only allow owner@ to have
1698 * write_acl/write_owner/write_attributes/write_xattr/
1699 */
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);
1705
1706 }
1707 return (0);
1708 }
1709