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