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