acl_common.c revision 191931
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
427#ifndef __FreeBSD__
428acl_t *
429acl_alloc(enum acl_type type)
430{
431	acl_t *aclp;
432
433	if (cacl_malloc((void **)&aclp, sizeof (acl_t)) != 0)
434		return (NULL);
435
436	aclp->acl_aclp = NULL;
437	aclp->acl_cnt = 0;
438
439	switch (type) {
440	case ACE_T:
441		aclp->acl_type = ACE_T;
442		aclp->acl_entry_size = sizeof (ace_t);
443		break;
444	case ACLENT_T:
445		aclp->acl_type = ACLENT_T;
446		aclp->acl_entry_size = sizeof (aclent_t);
447		break;
448	default:
449		acl_free(aclp);
450		aclp = NULL;
451	}
452	return (aclp);
453}
454
455/*
456 * Free acl_t structure
457 */
458void
459acl_free(acl_t *aclp)
460{
461	int acl_size;
462
463	if (aclp == NULL)
464		return;
465
466	if (aclp->acl_aclp) {
467		acl_size = aclp->acl_cnt * aclp->acl_entry_size;
468		cacl_free(aclp->acl_aclp, acl_size);
469	}
470
471	cacl_free(aclp, sizeof (acl_t));
472}
473#endif
474
475static uint32_t
476access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow)
477{
478	uint32_t access_mask = 0;
479	int acl_produce;
480	int synchronize_set = 0, write_owner_set = 0;
481	int delete_set = 0, write_attrs_set = 0;
482	int read_named_set = 0, write_named_set = 0;
483
484	acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW |
485	    ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
486	    ACL_WRITE_ATTRS_WRITER_SET_DENY);
487
488	if (isallow) {
489		synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW;
490		write_owner_set = ACL_WRITE_OWNER_SET_ALLOW;
491		delete_set = ACL_DELETE_SET_ALLOW;
492		if (hasreadperm)
493			read_named_set = ACL_READ_NAMED_READER_SET_ALLOW;
494		if (haswriteperm)
495			write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
496		if (isowner)
497			write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
498		else if (haswriteperm)
499			write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
500	} else {
501
502		synchronize_set = ACL_SYNCHRONIZE_SET_DENY;
503		write_owner_set = ACL_WRITE_OWNER_SET_DENY;
504		delete_set = ACL_DELETE_SET_DENY;
505		if (hasreadperm)
506			read_named_set = ACL_READ_NAMED_READER_SET_DENY;
507		if (haswriteperm)
508			write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY;
509		if (isowner)
510			write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY;
511		else if (haswriteperm)
512			write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY;
513		else
514			/*
515			 * If the entity is not the owner and does not
516			 * have write permissions ACE_WRITE_ATTRIBUTES will
517			 * always go in the DENY ACE.
518			 */
519			access_mask |= ACE_WRITE_ATTRIBUTES;
520	}
521
522	if (acl_produce & synchronize_set)
523		access_mask |= ACE_SYNCHRONIZE;
524	if (acl_produce & write_owner_set)
525		access_mask |= ACE_WRITE_OWNER;
526	if (acl_produce & delete_set)
527		access_mask |= ACE_DELETE;
528	if (acl_produce & write_attrs_set)
529		access_mask |= ACE_WRITE_ATTRIBUTES;
530	if (acl_produce & read_named_set)
531		access_mask |= ACE_READ_NAMED_ATTRS;
532	if (acl_produce & write_named_set)
533		access_mask |= ACE_WRITE_NAMED_ATTRS;
534
535	return (access_mask);
536}
537
538/*
539 * Given an mode_t, convert it into an access_mask as used
540 * by nfsace, assuming aclent_t -> nfsace semantics.
541 */
542static uint32_t
543mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow)
544{
545	uint32_t access = 0;
546	int haswriteperm = 0;
547	int hasreadperm = 0;
548
549	if (isallow) {
550		haswriteperm = (mode & S_IWOTH);
551		hasreadperm = (mode & S_IROTH);
552	} else {
553		haswriteperm = !(mode & S_IWOTH);
554		hasreadperm = !(mode & S_IROTH);
555	}
556
557	/*
558	 * The following call takes care of correctly setting the following
559	 * mask bits in the access_mask:
560	 * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE,
561	 * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS
562	 */
563	access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow);
564
565	if (isallow) {
566		access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES;
567		if (isowner)
568			access |= ACE_WRITE_ACL;
569	} else {
570		if (! isowner)
571			access |= ACE_WRITE_ACL;
572	}
573
574	/* read */
575	if (mode & S_IROTH) {
576		access |= ACE_READ_DATA;
577	}
578	/* write */
579	if (mode & S_IWOTH) {
580		access |= ACE_WRITE_DATA |
581		    ACE_APPEND_DATA;
582		if (isdir)
583			access |= ACE_DELETE_CHILD;
584	}
585	/* exec */
586	if (mode & 01) {
587		access |= ACE_EXECUTE;
588	}
589
590	return (access);
591}
592
593/*
594 * Given an nfsace (presumably an ALLOW entry), make a
595 * corresponding DENY entry at the address given.
596 */
597static void
598ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner)
599{
600	(void) memcpy(deny, allow, sizeof (ace_t));
601
602	deny->a_who = allow->a_who;
603
604	deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
605	deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS;
606	if (isdir)
607		deny->a_access_mask ^= ACE_DELETE_CHILD;
608
609	deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER |
610	    ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
611	    ACE_WRITE_NAMED_ATTRS);
612	deny->a_access_mask |= access_mask_set((allow->a_access_mask &
613	    ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner,
614	    B_FALSE);
615}
616/*
617 * Make an initial pass over an array of aclent_t's.  Gather
618 * information such as an ACL_MASK (if any), number of users,
619 * number of groups, and whether the array needs to be sorted.
620 */
621static int
622ln_aent_preprocess(aclent_t *aclent, int n,
623    int *hasmask, mode_t *mask,
624    int *numuser, int *numgroup, int *needsort)
625{
626	int error = 0;
627	int i;
628	int curtype = 0;
629
630	*hasmask = 0;
631	*mask = 07;
632	*needsort = 0;
633	*numuser = 0;
634	*numgroup = 0;
635
636	for (i = 0; i < n; i++) {
637		if (aclent[i].a_type < curtype)
638			*needsort = 1;
639		else if (aclent[i].a_type > curtype)
640			curtype = aclent[i].a_type;
641		if (aclent[i].a_type & USER)
642			(*numuser)++;
643		if (aclent[i].a_type & (GROUP | GROUP_OBJ))
644			(*numgroup)++;
645		if (aclent[i].a_type & CLASS_OBJ) {
646			if (*hasmask) {
647				error = EINVAL;
648				goto out;
649			} else {
650				*hasmask = 1;
651				*mask = aclent[i].a_perm;
652			}
653		}
654	}
655
656	if ((! *hasmask) && (*numuser + *numgroup > 1)) {
657		error = EINVAL;
658		goto out;
659	}
660
661out:
662	return (error);
663}
664
665/*
666 * Convert an array of aclent_t into an array of nfsace entries,
667 * following POSIX draft -> nfsv4 conversion semantics as outlined in
668 * the IETF draft.
669 */
670static int
671ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir)
672{
673	int error = 0;
674	mode_t mask;
675	int numuser, numgroup, needsort;
676	int resultsize = 0;
677	int i, groupi = 0, skip;
678	ace_t *acep, *result = NULL;
679	int hasmask;
680
681	error = ln_aent_preprocess(aclent, n, &hasmask, &mask,
682	    &numuser, &numgroup, &needsort);
683	if (error != 0)
684		goto out;
685
686	/* allow + deny for each aclent */
687	resultsize = n * 2;
688	if (hasmask) {
689		/*
690		 * stick extra deny on the group_obj and on each
691		 * user|group for the mask (the group_obj was added
692		 * into the count for numgroup)
693		 */
694		resultsize += numuser + numgroup;
695		/* ... and don't count the mask itself */
696		resultsize -= 2;
697	}
698
699	/* sort the source if necessary */
700	if (needsort)
701		ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls);
702
703	if (cacl_malloc((void **)&result, resultsize * sizeof (ace_t)) != 0)
704		goto out;
705
706	acep = result;
707
708	for (i = 0; i < n; i++) {
709		/*
710		 * don't process CLASS_OBJ (mask); mask was grabbed in
711		 * ln_aent_preprocess()
712		 */
713		if (aclent[i].a_type & CLASS_OBJ)
714			continue;
715
716		/* If we need an ACL_MASK emulator, prepend it now */
717		if ((hasmask) &&
718		    (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) {
719			acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
720			acep->a_flags = 0;
721			if (aclent[i].a_type & GROUP_OBJ) {
722				acep->a_who = (uid_t)-1;
723				acep->a_flags |=
724				    (ACE_IDENTIFIER_GROUP|ACE_GROUP);
725			} else if (aclent[i].a_type & USER) {
726				acep->a_who = aclent[i].a_id;
727			} else {
728				acep->a_who = aclent[i].a_id;
729				acep->a_flags |= ACE_IDENTIFIER_GROUP;
730			}
731			if (aclent[i].a_type & ACL_DEFAULT) {
732				acep->a_flags |= ACE_INHERIT_ONLY_ACE |
733				    ACE_FILE_INHERIT_ACE |
734				    ACE_DIRECTORY_INHERIT_ACE;
735			}
736			/*
737			 * Set the access mask for the prepended deny
738			 * ace.  To do this, we invert the mask (found
739			 * in ln_aent_preprocess()) then convert it to an
740			 * DENY ace access_mask.
741			 */
742			acep->a_access_mask = mode_to_ace_access((mask ^ 07),
743			    isdir, 0, 0);
744			acep += 1;
745		}
746
747		/* handle a_perm -> access_mask */
748		acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm,
749		    isdir, aclent[i].a_type & USER_OBJ, 1);
750
751		/* emulate a default aclent */
752		if (aclent[i].a_type & ACL_DEFAULT) {
753			acep->a_flags |= ACE_INHERIT_ONLY_ACE |
754			    ACE_FILE_INHERIT_ACE |
755			    ACE_DIRECTORY_INHERIT_ACE;
756		}
757
758		/*
759		 * handle a_perm and a_id
760		 *
761		 * this must be done last, since it involves the
762		 * corresponding deny aces, which are handled
763		 * differently for each different a_type.
764		 */
765		if (aclent[i].a_type & USER_OBJ) {
766			acep->a_who = (uid_t)-1;
767			acep->a_flags |= ACE_OWNER;
768			ace_make_deny(acep, acep + 1, isdir, B_TRUE);
769			acep += 2;
770		} else if (aclent[i].a_type & USER) {
771			acep->a_who = aclent[i].a_id;
772			ace_make_deny(acep, acep + 1, isdir, B_FALSE);
773			acep += 2;
774		} else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) {
775			if (aclent[i].a_type & GROUP_OBJ) {
776				acep->a_who = (uid_t)-1;
777				acep->a_flags |= ACE_GROUP;
778			} else {
779				acep->a_who = aclent[i].a_id;
780			}
781			acep->a_flags |= ACE_IDENTIFIER_GROUP;
782			/*
783			 * Set the corresponding deny for the group ace.
784			 *
785			 * The deny aces go after all of the groups, unlike
786			 * everything else, where they immediately follow
787			 * the allow ace.
788			 *
789			 * We calculate "skip", the number of slots to
790			 * skip ahead for the deny ace, here.
791			 *
792			 * The pattern is:
793			 * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3
794			 * thus, skip is
795			 * (2 * numgroup) - 1 - groupi
796			 * (2 * numgroup) to account for MD + A
797			 * - 1 to account for the fact that we're on the
798			 * access (A), not the mask (MD)
799			 * - groupi to account for the fact that we have
800			 * passed up groupi number of MD's.
801			 */
802			skip = (2 * numgroup) - 1 - groupi;
803			ace_make_deny(acep, acep + skip, isdir, B_FALSE);
804			/*
805			 * If we just did the last group, skip acep past
806			 * all of the denies; else, just move ahead one.
807			 */
808			if (++groupi >= numgroup)
809				acep += numgroup + 1;
810			else
811				acep += 1;
812		} else if (aclent[i].a_type & OTHER_OBJ) {
813			acep->a_who = (uid_t)-1;
814			acep->a_flags |= ACE_EVERYONE;
815			ace_make_deny(acep, acep + 1, isdir, B_FALSE);
816			acep += 2;
817		} else {
818			error = EINVAL;
819			goto out;
820		}
821	}
822
823	*acepp = result;
824	*rescount = resultsize;
825
826out:
827	if (error != 0) {
828		if ((result != NULL) && (resultsize > 0)) {
829			cacl_free(result, resultsize * sizeof (ace_t));
830		}
831	}
832
833	return (error);
834}
835
836static int
837convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir,
838    ace_t **retacep, int *retacecnt)
839{
840	ace_t *acep;
841	ace_t *dfacep;
842	int acecnt = 0;
843	int dfacecnt = 0;
844	int dfaclstart = 0;
845	int dfaclcnt = 0;
846	aclent_t *aclp;
847	int i;
848	int error;
849	int acesz, dfacesz;
850
851	ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls);
852
853	for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) {
854		if (aclp->a_type & ACL_DEFAULT)
855			break;
856	}
857
858	if (i < aclcnt) {
859		dfaclstart = i;
860		dfaclcnt = aclcnt - i;
861	}
862
863	if (dfaclcnt && isdir == 0) {
864		return (EINVAL);
865	}
866
867	error = ln_aent_to_ace(aclentp, i,  &acep, &acecnt, isdir);
868	if (error)
869		return (error);
870
871	if (dfaclcnt) {
872		error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt,
873		    &dfacep, &dfacecnt, isdir);
874		if (error) {
875			if (acep) {
876				cacl_free(acep, acecnt * sizeof (ace_t));
877			}
878			return (error);
879		}
880	}
881
882	if (dfacecnt != 0) {
883		acesz = sizeof (ace_t) * acecnt;
884		dfacesz = sizeof (ace_t) * dfacecnt;
885		acep = cacl_realloc(acep, acesz, acesz + dfacesz);
886		if (acep == NULL)
887			return (ENOMEM);
888		if (dfaclcnt) {
889			(void) memcpy(acep + acecnt, dfacep, dfacesz);
890		}
891	}
892	if (dfaclcnt)
893		cacl_free(dfacep, dfacecnt * sizeof (ace_t));
894
895	*retacecnt = acecnt + dfacecnt;
896	*retacep = acep;
897	return (0);
898}
899
900static int
901ace_mask_to_mode(uint32_t  mask, o_mode_t *modep, int isdir)
902{
903	int error = 0;
904	o_mode_t mode = 0;
905	uint32_t bits, wantbits;
906
907	/* read */
908	if (mask & ACE_READ_DATA)
909		mode |= S_IROTH;
910
911	/* write */
912	wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA);
913	if (isdir)
914		wantbits |= ACE_DELETE_CHILD;
915	bits = mask & wantbits;
916	if (bits != 0) {
917		if (bits != wantbits) {
918			error = ENOTSUP;
919			goto out;
920		}
921		mode |= S_IWOTH;
922	}
923
924	/* exec */
925	if (mask & ACE_EXECUTE) {
926		mode |= S_IXOTH;
927	}
928
929	*modep = mode;
930
931out:
932	return (error);
933}
934
935static void
936acevals_init(acevals_t *vals, uid_t key)
937{
938	bzero(vals, sizeof (*vals));
939	vals->allowed = ACE_MASK_UNDEFINED;
940	vals->denied = ACE_MASK_UNDEFINED;
941	vals->mask = ACE_MASK_UNDEFINED;
942	vals->key = key;
943}
944
945static void
946ace_list_init(ace_list_t *al, int dfacl_flag)
947{
948	acevals_init(&al->user_obj, 0);
949	acevals_init(&al->group_obj, 0);
950	acevals_init(&al->other_obj, 0);
951	al->numusers = 0;
952	al->numgroups = 0;
953	al->acl_mask = 0;
954	al->hasmask = 0;
955	al->state = ace_unused;
956	al->seen = 0;
957	al->dfacl_flag = dfacl_flag;
958}
959
960/*
961 * Find or create an acevals holder for a given id and avl tree.
962 *
963 * Note that only one thread will ever touch these avl trees, so
964 * there is no need for locking.
965 */
966static acevals_t *
967acevals_find(ace_t *ace, avl_tree_t *avl, int *num)
968{
969	acevals_t key, *rc;
970	avl_index_t where;
971
972	key.key = ace->a_who;
973	rc = avl_find(avl, &key, &where);
974	if (rc != NULL)
975		return (rc);
976
977	/* this memory is freed by ln_ace_to_aent()->ace_list_free() */
978	if (cacl_malloc((void **)&rc, sizeof (acevals_t)) != 0)
979		return (NULL);
980
981	acevals_init(rc, ace->a_who);
982	avl_insert(avl, rc, where);
983	(*num)++;
984
985	return (rc);
986}
987
988static int
989access_mask_check(ace_t *acep, int mask_bit, int isowner)
990{
991	int set_deny, err_deny;
992	int set_allow, err_allow;
993	int acl_consume;
994	int haswriteperm, hasreadperm;
995
996	if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
997		haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1;
998		hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1;
999	} else {
1000		haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0;
1001		hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0;
1002	}
1003
1004	acl_consume = (ACL_SYNCHRONIZE_ERR_DENY |
1005	    ACL_DELETE_ERR_DENY |
1006	    ACL_WRITE_OWNER_ERR_DENY |
1007	    ACL_WRITE_OWNER_ERR_ALLOW |
1008	    ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
1009	    ACL_WRITE_ATTRS_OWNER_ERR_DENY |
1010	    ACL_WRITE_ATTRS_WRITER_SET_DENY |
1011	    ACL_WRITE_ATTRS_WRITER_ERR_ALLOW |
1012	    ACL_WRITE_NAMED_WRITER_ERR_DENY |
1013	    ACL_READ_NAMED_READER_ERR_DENY);
1014
1015	if (mask_bit == ACE_SYNCHRONIZE) {
1016		set_deny = ACL_SYNCHRONIZE_SET_DENY;
1017		err_deny =  ACL_SYNCHRONIZE_ERR_DENY;
1018		set_allow = ACL_SYNCHRONIZE_SET_ALLOW;
1019		err_allow = ACL_SYNCHRONIZE_ERR_ALLOW;
1020	} else if (mask_bit == ACE_WRITE_OWNER) {
1021		set_deny = ACL_WRITE_OWNER_SET_DENY;
1022		err_deny =  ACL_WRITE_OWNER_ERR_DENY;
1023		set_allow = ACL_WRITE_OWNER_SET_ALLOW;
1024		err_allow = ACL_WRITE_OWNER_ERR_ALLOW;
1025	} else if (mask_bit == ACE_DELETE) {
1026		set_deny = ACL_DELETE_SET_DENY;
1027		err_deny =  ACL_DELETE_ERR_DENY;
1028		set_allow = ACL_DELETE_SET_ALLOW;
1029		err_allow = ACL_DELETE_ERR_ALLOW;
1030	} else if (mask_bit == ACE_WRITE_ATTRIBUTES) {
1031		if (isowner) {
1032			set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY;
1033			err_deny =  ACL_WRITE_ATTRS_OWNER_ERR_DENY;
1034			set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
1035			err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW;
1036		} else if (haswriteperm) {
1037			set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY;
1038			err_deny =  ACL_WRITE_ATTRS_WRITER_ERR_DENY;
1039			set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
1040			err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW;
1041		} else {
1042			if ((acep->a_access_mask & mask_bit) &&
1043			    (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) {
1044				return (ENOTSUP);
1045			}
1046			return (0);
1047		}
1048	} else if (mask_bit == ACE_READ_NAMED_ATTRS) {
1049		if (!hasreadperm)
1050			return (0);
1051
1052		set_deny = ACL_READ_NAMED_READER_SET_DENY;
1053		err_deny = ACL_READ_NAMED_READER_ERR_DENY;
1054		set_allow = ACL_READ_NAMED_READER_SET_ALLOW;
1055		err_allow = ACL_READ_NAMED_READER_ERR_ALLOW;
1056	} else if (mask_bit == ACE_WRITE_NAMED_ATTRS) {
1057		if (!haswriteperm)
1058			return (0);
1059
1060		set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY;
1061		err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY;
1062		set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
1063		err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW;
1064	} else {
1065		return (EINVAL);
1066	}
1067
1068	if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
1069		if (acl_consume & set_deny) {
1070			if (!(acep->a_access_mask & mask_bit)) {
1071				return (ENOTSUP);
1072			}
1073		} else if (acl_consume & err_deny) {
1074			if (acep->a_access_mask & mask_bit) {
1075				return (ENOTSUP);
1076			}
1077		}
1078	} else {
1079		/* ACE_ACCESS_ALLOWED_ACE_TYPE */
1080		if (acl_consume & set_allow) {
1081			if (!(acep->a_access_mask & mask_bit)) {
1082				return (ENOTSUP);
1083			}
1084		} else if (acl_consume & err_allow) {
1085			if (acep->a_access_mask & mask_bit) {
1086				return (ENOTSUP);
1087			}
1088		}
1089	}
1090	return (0);
1091}
1092
1093static int
1094ace_to_aent_legal(ace_t *acep)
1095{
1096	int error = 0;
1097	int isowner;
1098
1099	/* only ALLOW or DENY */
1100	if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) &&
1101	    (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) {
1102		error = ENOTSUP;
1103		goto out;
1104	}
1105
1106	/* check for invalid flags */
1107	if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) {
1108		error = EINVAL;
1109		goto out;
1110	}
1111
1112	/* some flags are illegal */
1113	if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG |
1114	    ACE_FAILED_ACCESS_ACE_FLAG |
1115	    ACE_NO_PROPAGATE_INHERIT_ACE)) {
1116		error = ENOTSUP;
1117		goto out;
1118	}
1119
1120	/* check for invalid masks */
1121	if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) {
1122		error = EINVAL;
1123		goto out;
1124	}
1125
1126	if ((acep->a_flags & ACE_OWNER)) {
1127		isowner = 1;
1128	} else {
1129		isowner = 0;
1130	}
1131
1132	error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner);
1133	if (error)
1134		goto out;
1135
1136	error = access_mask_check(acep, ACE_WRITE_OWNER, isowner);
1137	if (error)
1138		goto out;
1139
1140	error = access_mask_check(acep, ACE_DELETE, isowner);
1141	if (error)
1142		goto out;
1143
1144	error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner);
1145	if (error)
1146		goto out;
1147
1148	error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner);
1149	if (error)
1150		goto out;
1151
1152	error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner);
1153	if (error)
1154		goto out;
1155
1156	/* more detailed checking of masks */
1157	if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
1158		if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) {
1159			error = ENOTSUP;
1160			goto out;
1161		}
1162		if ((acep->a_access_mask & ACE_WRITE_DATA) &&
1163		    (! (acep->a_access_mask & ACE_APPEND_DATA))) {
1164			error = ENOTSUP;
1165			goto out;
1166		}
1167		if ((! (acep->a_access_mask & ACE_WRITE_DATA)) &&
1168		    (acep->a_access_mask & ACE_APPEND_DATA)) {
1169			error = ENOTSUP;
1170			goto out;
1171		}
1172	}
1173
1174	/* ACL enforcement */
1175	if ((acep->a_access_mask & ACE_READ_ACL) &&
1176	    (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) {
1177		error = ENOTSUP;
1178		goto out;
1179	}
1180	if (acep->a_access_mask & ACE_WRITE_ACL) {
1181		if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) &&
1182		    (isowner)) {
1183			error = ENOTSUP;
1184			goto out;
1185		}
1186		if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) &&
1187		    (! isowner)) {
1188			error = ENOTSUP;
1189			goto out;
1190		}
1191	}
1192
1193out:
1194	return (error);
1195}
1196
1197static int
1198ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir)
1199{
1200	/* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */
1201	if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) !=
1202	    (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) {
1203		return (ENOTSUP);
1204	}
1205
1206	return (ace_mask_to_mode(mask, modep, isdir));
1207}
1208
1209static int
1210acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list,
1211    uid_t owner, gid_t group, int isdir)
1212{
1213	int error;
1214	uint32_t  flips = ACE_POSIX_SUPPORTED_BITS;
1215
1216	if (isdir)
1217		flips |= ACE_DELETE_CHILD;
1218	if (vals->allowed != (vals->denied ^ flips)) {
1219		error = ENOTSUP;
1220		goto out;
1221	}
1222	if ((list->hasmask) && (list->acl_mask != vals->mask) &&
1223	    (vals->aent_type & (USER | GROUP | GROUP_OBJ))) {
1224		error = ENOTSUP;
1225		goto out;
1226	}
1227	error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir);
1228	if (error != 0)
1229		goto out;
1230	dest->a_type = vals->aent_type;
1231	if (dest->a_type & (USER | GROUP)) {
1232		dest->a_id = vals->key;
1233	} else if (dest->a_type & USER_OBJ) {
1234		dest->a_id = owner;
1235	} else if (dest->a_type & GROUP_OBJ) {
1236		dest->a_id = group;
1237	} else if (dest->a_type & OTHER_OBJ) {
1238		dest->a_id = 0;
1239	} else {
1240		error = EINVAL;
1241		goto out;
1242	}
1243
1244out:
1245	return (error);
1246}
1247
1248
1249static int
1250ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt,
1251    uid_t owner, gid_t group, int isdir)
1252{
1253	int error = 0;
1254	aclent_t *aent, *result = NULL;
1255	acevals_t *vals;
1256	int resultcount;
1257
1258	if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) !=
1259	    (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) {
1260		error = ENOTSUP;
1261		goto out;
1262	}
1263	if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) {
1264		error = ENOTSUP;
1265		goto out;
1266	}
1267
1268	resultcount = 3 + list->numusers + list->numgroups;
1269	/*
1270	 * This must be the same condition as below, when we add the CLASS_OBJ
1271	 * (aka ACL mask)
1272	 */
1273	if ((list->hasmask) || (! list->dfacl_flag))
1274		resultcount += 1;
1275
1276	if (cacl_malloc((void **)&result,
1277	    resultcount * sizeof (aclent_t)) != 0) {
1278		error = ENOMEM;
1279		goto out;
1280	}
1281	aent = result;
1282
1283	/* USER_OBJ */
1284	if (!(list->user_obj.aent_type & USER_OBJ)) {
1285		error = EINVAL;
1286		goto out;
1287	}
1288
1289	error = acevals_to_aent(&list->user_obj, aent, list, owner, group,
1290	    isdir);
1291
1292	if (error != 0)
1293		goto out;
1294	++aent;
1295	/* USER */
1296	vals = NULL;
1297	for (vals = avl_first(&list->user); vals != NULL;
1298	    vals = AVL_NEXT(&list->user, vals)) {
1299		if (!(vals->aent_type & USER)) {
1300			error = EINVAL;
1301			goto out;
1302		}
1303		error = acevals_to_aent(vals, aent, list, owner, group,
1304		    isdir);
1305		if (error != 0)
1306			goto out;
1307		++aent;
1308	}
1309	/* GROUP_OBJ */
1310	if (!(list->group_obj.aent_type & GROUP_OBJ)) {
1311		error = EINVAL;
1312		goto out;
1313	}
1314	error = acevals_to_aent(&list->group_obj, aent, list, owner, group,
1315	    isdir);
1316	if (error != 0)
1317		goto out;
1318	++aent;
1319	/* GROUP */
1320	vals = NULL;
1321	for (vals = avl_first(&list->group); vals != NULL;
1322	    vals = AVL_NEXT(&list->group, vals)) {
1323		if (!(vals->aent_type & GROUP)) {
1324			error = EINVAL;
1325			goto out;
1326		}
1327		error = acevals_to_aent(vals, aent, list, owner, group,
1328		    isdir);
1329		if (error != 0)
1330			goto out;
1331		++aent;
1332	}
1333	/*
1334	 * CLASS_OBJ (aka ACL_MASK)
1335	 *
1336	 * An ACL_MASK is not fabricated if the ACL is a default ACL.
1337	 * This is to follow UFS's behavior.
1338	 */
1339	if ((list->hasmask) || (! list->dfacl_flag)) {
1340		if (list->hasmask) {
1341			uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
1342			if (isdir)
1343				flips |= ACE_DELETE_CHILD;
1344			error = ace_mask_to_mode(list->acl_mask ^ flips,
1345			    &aent->a_perm, isdir);
1346			if (error != 0)
1347				goto out;
1348		} else {
1349			/* fabricate the ACL_MASK from the group permissions */
1350			error = ace_mask_to_mode(list->group_obj.allowed,
1351			    &aent->a_perm, isdir);
1352			if (error != 0)
1353				goto out;
1354		}
1355		aent->a_id = 0;
1356		aent->a_type = CLASS_OBJ | list->dfacl_flag;
1357		++aent;
1358	}
1359	/* OTHER_OBJ */
1360	if (!(list->other_obj.aent_type & OTHER_OBJ)) {
1361		error = EINVAL;
1362		goto out;
1363	}
1364	error = acevals_to_aent(&list->other_obj, aent, list, owner, group,
1365	    isdir);
1366	if (error != 0)
1367		goto out;
1368	++aent;
1369
1370	*aclentp = result;
1371	*aclcnt = resultcount;
1372
1373out:
1374	if (error != 0) {
1375		if (result != NULL)
1376			cacl_free(result, resultcount * sizeof (aclent_t));
1377	}
1378
1379	return (error);
1380}
1381
1382
1383/*
1384 * free all data associated with an ace_list
1385 */
1386static void
1387ace_list_free(ace_list_t *al)
1388{
1389	acevals_t *node;
1390	void *cookie;
1391
1392	if (al == NULL)
1393		return;
1394
1395	cookie = NULL;
1396	while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL)
1397		cacl_free(node, sizeof (acevals_t));
1398	cookie = NULL;
1399	while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL)
1400		cacl_free(node, sizeof (acevals_t));
1401
1402	avl_destroy(&al->user);
1403	avl_destroy(&al->group);
1404
1405	/* free the container itself */
1406	cacl_free(al, sizeof (ace_list_t));
1407}
1408
1409static int
1410acevals_compare(const void *va, const void *vb)
1411{
1412	const acevals_t *a = va, *b = vb;
1413
1414	if (a->key == b->key)
1415		return (0);
1416
1417	if (a->key > b->key)
1418		return (1);
1419
1420	else
1421		return (-1);
1422}
1423
1424/*
1425 * Convert a list of ace_t entries to equivalent regular and default
1426 * aclent_t lists.  Return error (ENOTSUP) when conversion is not possible.
1427 */
1428static int
1429ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group,
1430    aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt,
1431    int isdir)
1432{
1433	int error = 0;
1434	ace_t *acep;
1435	uint32_t bits;
1436	int i;
1437	ace_list_t *normacl = NULL, *dfacl = NULL, *acl;
1438	acevals_t *vals;
1439
1440	*aclentp = NULL;
1441	*aclcnt = 0;
1442	*dfaclentp = NULL;
1443	*dfaclcnt = 0;
1444
1445	/* we need at least user_obj, group_obj, and other_obj */
1446	if (n < 6) {
1447		error = ENOTSUP;
1448		goto out;
1449	}
1450	if (ace == NULL) {
1451		error = EINVAL;
1452		goto out;
1453	}
1454
1455	error = cacl_malloc((void **)&normacl, sizeof (ace_list_t));
1456	if (error != 0)
1457		goto out;
1458
1459	avl_create(&normacl->user, acevals_compare, sizeof (acevals_t),
1460	    offsetof(acevals_t, avl));
1461	avl_create(&normacl->group, acevals_compare, sizeof (acevals_t),
1462	    offsetof(acevals_t, avl));
1463
1464	ace_list_init(normacl, 0);
1465
1466	error = cacl_malloc((void **)&dfacl, sizeof (ace_list_t));
1467	if (error != 0)
1468		goto out;
1469
1470	avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t),
1471	    offsetof(acevals_t, avl));
1472	avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t),
1473	    offsetof(acevals_t, avl));
1474	ace_list_init(dfacl, ACL_DEFAULT);
1475
1476	/* process every ace_t... */
1477	for (i = 0; i < n; i++) {
1478		acep = &ace[i];
1479
1480		/* rule out certain cases quickly */
1481		error = ace_to_aent_legal(acep);
1482		if (error != 0)
1483			goto out;
1484
1485		/*
1486		 * Turn off these bits in order to not have to worry about
1487		 * them when doing the checks for compliments.
1488		 */
1489		acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE |
1490		    ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES |
1491		    ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS);
1492
1493		/* see if this should be a regular or default acl */
1494		bits = acep->a_flags &
1495		    (ACE_INHERIT_ONLY_ACE |
1496		    ACE_FILE_INHERIT_ACE |
1497		    ACE_DIRECTORY_INHERIT_ACE);
1498		if (bits != 0) {
1499			/* all or nothing on these inherit bits */
1500			if (bits != (ACE_INHERIT_ONLY_ACE |
1501			    ACE_FILE_INHERIT_ACE |
1502			    ACE_DIRECTORY_INHERIT_ACE)) {
1503				error = ENOTSUP;
1504				goto out;
1505			}
1506			acl = dfacl;
1507		} else {
1508			acl = normacl;
1509		}
1510
1511		if ((acep->a_flags & ACE_OWNER)) {
1512			if (acl->state > ace_user_obj) {
1513				error = ENOTSUP;
1514				goto out;
1515			}
1516			acl->state = ace_user_obj;
1517			acl->seen |= USER_OBJ;
1518			vals = &acl->user_obj;
1519			vals->aent_type = USER_OBJ | acl->dfacl_flag;
1520		} else if ((acep->a_flags & ACE_EVERYONE)) {
1521			acl->state = ace_other_obj;
1522			acl->seen |= OTHER_OBJ;
1523			vals = &acl->other_obj;
1524			vals->aent_type = OTHER_OBJ | acl->dfacl_flag;
1525		} else if (acep->a_flags & ACE_IDENTIFIER_GROUP) {
1526			if (acl->state > ace_group) {
1527				error = ENOTSUP;
1528				goto out;
1529			}
1530			if ((acep->a_flags & ACE_GROUP)) {
1531				acl->seen |= GROUP_OBJ;
1532				vals = &acl->group_obj;
1533				vals->aent_type = GROUP_OBJ | acl->dfacl_flag;
1534			} else {
1535				acl->seen |= GROUP;
1536				vals = acevals_find(acep, &acl->group,
1537				    &acl->numgroups);
1538				if (vals == NULL) {
1539					error = ENOMEM;
1540					goto out;
1541				}
1542				vals->aent_type = GROUP | acl->dfacl_flag;
1543			}
1544			acl->state = ace_group;
1545		} else {
1546			if (acl->state > ace_user) {
1547				error = ENOTSUP;
1548				goto out;
1549			}
1550			acl->state = ace_user;
1551			acl->seen |= USER;
1552			vals = acevals_find(acep, &acl->user,
1553			    &acl->numusers);
1554			if (vals == NULL) {
1555				error = ENOMEM;
1556				goto out;
1557			}
1558			vals->aent_type = USER | acl->dfacl_flag;
1559		}
1560
1561		if (!(acl->state > ace_unused)) {
1562			error = EINVAL;
1563			goto out;
1564		}
1565
1566		if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
1567			/* no more than one allowed per aclent_t */
1568			if (vals->allowed != ACE_MASK_UNDEFINED) {
1569				error = ENOTSUP;
1570				goto out;
1571			}
1572			vals->allowed = acep->a_access_mask;
1573		} else {
1574			/*
1575			 * it's a DENY; if there was a previous DENY, it
1576			 * must have been an ACL_MASK.
1577			 */
1578			if (vals->denied != ACE_MASK_UNDEFINED) {
1579				/* ACL_MASK is for USER and GROUP only */
1580				if ((acl->state != ace_user) &&
1581				    (acl->state != ace_group)) {
1582					error = ENOTSUP;
1583					goto out;
1584				}
1585
1586				if (! acl->hasmask) {
1587					acl->hasmask = 1;
1588					acl->acl_mask = vals->denied;
1589				/* check for mismatched ACL_MASK emulations */
1590				} else if (acl->acl_mask != vals->denied) {
1591					error = ENOTSUP;
1592					goto out;
1593				}
1594				vals->mask = vals->denied;
1595			}
1596			vals->denied = acep->a_access_mask;
1597		}
1598	}
1599
1600	/* done collating; produce the aclent_t lists */
1601	if (normacl->state != ace_unused) {
1602		error = ace_list_to_aent(normacl, aclentp, aclcnt,
1603		    owner, group, isdir);
1604		if (error != 0) {
1605			goto out;
1606		}
1607	}
1608	if (dfacl->state != ace_unused) {
1609		error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt,
1610		    owner, group, isdir);
1611		if (error != 0) {
1612			goto out;
1613		}
1614	}
1615
1616out:
1617	if (normacl != NULL)
1618		ace_list_free(normacl);
1619	if (dfacl != NULL)
1620		ace_list_free(dfacl);
1621
1622	return (error);
1623}
1624
1625static int
1626convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir,
1627    uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt)
1628{
1629	int error = 0;
1630	aclent_t *aclentp, *dfaclentp;
1631	int aclcnt, dfaclcnt;
1632	int aclsz, dfaclsz;
1633
1634	error = ln_ace_to_aent(acebufp, acecnt, owner, group,
1635	    &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir);
1636
1637	if (error)
1638		return (error);
1639
1640
1641	if (dfaclcnt != 0) {
1642		/*
1643		 * Slap aclentp and dfaclentp into a single array.
1644		 */
1645		aclsz = sizeof (aclent_t) * aclcnt;
1646		dfaclsz = sizeof (aclent_t) * dfaclcnt;
1647		aclentp = cacl_realloc(aclentp, aclsz, aclsz + dfaclsz);
1648		if (aclentp != NULL) {
1649			(void) memcpy(aclentp + aclcnt, dfaclentp, dfaclsz);
1650		} else {
1651			error = ENOMEM;
1652		}
1653	}
1654
1655	if (aclentp) {
1656		*retaclentp = aclentp;
1657		*retaclcnt = aclcnt + dfaclcnt;
1658	}
1659
1660	if (dfaclentp)
1661		cacl_free(dfaclentp, dfaclsz);
1662
1663	return (error);
1664}
1665
1666
1667int
1668acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner,
1669    gid_t group)
1670{
1671	int aclcnt;
1672	void *acldata;
1673	int error;
1674
1675	/*
1676	 * See if we need to translate
1677	 */
1678	if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) ||
1679	    (target_flavor == _ACL_ACLENT_ENABLED &&
1680	    aclp->acl_type == ACLENT_T))
1681		return (0);
1682
1683	if (target_flavor == -1) {
1684		error = EINVAL;
1685		goto out;
1686	}
1687
1688	if (target_flavor ==  _ACL_ACE_ENABLED &&
1689	    aclp->acl_type == ACLENT_T) {
1690		error = convert_aent_to_ace(aclp->acl_aclp,
1691		    aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt);
1692		if (error)
1693			goto out;
1694
1695	} else if (target_flavor == _ACL_ACLENT_ENABLED &&
1696	    aclp->acl_type == ACE_T) {
1697		error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt,
1698		    isdir, owner, group, (aclent_t **)&acldata, &aclcnt);
1699		if (error)
1700			goto out;
1701	} else {
1702		error = ENOTSUP;
1703		goto out;
1704	}
1705
1706	/*
1707	 * replace old acl with newly translated acl
1708	 */
1709	cacl_free(aclp->acl_aclp, aclp->acl_cnt * aclp->acl_entry_size);
1710	aclp->acl_aclp = acldata;
1711	aclp->acl_cnt = aclcnt;
1712	if (target_flavor == _ACL_ACE_ENABLED) {
1713		aclp->acl_type = ACE_T;
1714		aclp->acl_entry_size = sizeof (ace_t);
1715	} else {
1716		aclp->acl_type = ACLENT_T;
1717		aclp->acl_entry_size = sizeof (aclent_t);
1718	}
1719	return (0);
1720
1721out:
1722
1723#if !defined(_KERNEL)
1724	errno = error;
1725	return (-1);
1726#else
1727	return (error);
1728#endif
1729}
1730