xref: /titanic_44/usr/src/lib/libsec/common/aclutils.c (revision 3eb3c57322eccc9d4c2880c26f57ceb5a85c2491)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5*3eb3c573Smarks  * Common Development and Distribution License (the "License").
6*3eb3c573Smarks  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
21fa9e4066Sahrens /*
22d2443e76Smarks  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23fa9e4066Sahrens  * Use is subject to license terms.
24fa9e4066Sahrens  */
25fa9e4066Sahrens 
26fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
27fa9e4066Sahrens 
28fa9e4066Sahrens #include <stdlib.h>
29fa9e4066Sahrens #include <string.h>
30fa9e4066Sahrens #include <unistd.h>
31fa9e4066Sahrens #include <limits.h>
32fa9e4066Sahrens #include <grp.h>
33fa9e4066Sahrens #include <pwd.h>
34*3eb3c573Smarks #include <strings.h>
35fa9e4066Sahrens #include <sys/types.h>
36fa9e4066Sahrens #include <sys/acl.h>
37fa9e4066Sahrens #include <errno.h>
38fa9e4066Sahrens #include <sys/stat.h>
395a5eeccaSmarks #include <sys/varargs.h>
40fa9e4066Sahrens #include <locale.h>
41fa9e4066Sahrens #include <aclutils.h>
42fa9e4066Sahrens #include <acl_common.h>
43*3eb3c573Smarks #include <sys/avl.h>
44*3eb3c573Smarks 
45*3eb3c573Smarks #define	offsetof(s, m)	((size_t)(&(((s *)0)->m)))
46fa9e4066Sahrens 
47fa9e4066Sahrens #define	ACL_PATH	0
48fa9e4066Sahrens #define	ACL_FD		1
49fa9e4066Sahrens 
50fa9e4066Sahrens #define	ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \
51fa9e4066Sahrens     ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \
52fa9e4066Sahrens     ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL)
53fa9e4066Sahrens 
54fa9e4066Sahrens 
55fa9e4066Sahrens #define	ACL_SYNCHRONIZE_SET_DENY		0x0000001
56*3eb3c573Smarks #define	ACL_SYNCHRONIZE_SET_ALLOW		0x0000002
57*3eb3c573Smarks #define	ACL_SYNCHRONIZE_ERR_DENY		0x0000004
58*3eb3c573Smarks #define	ACL_SYNCHRONIZE_ERR_ALLOW		0x0000008
59fa9e4066Sahrens 
60fa9e4066Sahrens #define	ACL_WRITE_OWNER_SET_DENY		0x0000010
61*3eb3c573Smarks #define	ACL_WRITE_OWNER_SET_ALLOW		0x0000020
62*3eb3c573Smarks #define	ACL_WRITE_OWNER_ERR_DENY		0x0000040
63*3eb3c573Smarks #define	ACL_WRITE_OWNER_ERR_ALLOW		0x0000080
64fa9e4066Sahrens 
65*3eb3c573Smarks #define	ACL_DELETE_SET_DENY			0x0000100
66*3eb3c573Smarks #define	ACL_DELETE_SET_ALLOW			0x0000200
67*3eb3c573Smarks #define	ACL_DELETE_ERR_DENY			0x0000400
68*3eb3c573Smarks #define	ACL_DELETE_ERR_ALLOW			0x0000800
69*3eb3c573Smarks 
70fa9e4066Sahrens #define	ACL_WRITE_ATTRS_OWNER_SET_DENY		0x0001000
71*3eb3c573Smarks #define	ACL_WRITE_ATTRS_OWNER_SET_ALLOW		0x0002000
72*3eb3c573Smarks #define	ACL_WRITE_ATTRS_OWNER_ERR_DENY		0x0004000
73*3eb3c573Smarks #define	ACL_WRITE_ATTRS_OWNER_ERR_ALLOW		0x0008000
74fa9e4066Sahrens 
75fa9e4066Sahrens #define	ACL_WRITE_ATTRS_WRITER_SET_DENY		0x0010000
76fa9e4066Sahrens #define	ACL_WRITE_ATTRS_WRITER_SET_ALLOW	0x0020000
77*3eb3c573Smarks #define	ACL_WRITE_ATTRS_WRITER_ERR_DENY		0x0040000
78*3eb3c573Smarks #define	ACL_WRITE_ATTRS_WRITER_ERR_ALLOW	0x0080000
79fa9e4066Sahrens 
80*3eb3c573Smarks #define	ACL_WRITE_NAMED_WRITER_SET_DENY		0x0100000
81*3eb3c573Smarks #define	ACL_WRITE_NAMED_WRITER_SET_ALLOW	0x0200000
82*3eb3c573Smarks #define	ACL_WRITE_NAMED_WRITER_ERR_DENY		0x0400000
83*3eb3c573Smarks #define	ACL_WRITE_NAMED_WRITER_ERR_ALLOW	0x0800000
84*3eb3c573Smarks 
85fa9e4066Sahrens #define	ACL_READ_NAMED_READER_SET_DENY		0x1000000
86*3eb3c573Smarks #define	ACL_READ_NAMED_READER_SET_ALLOW		0x2000000
87*3eb3c573Smarks #define	ACL_READ_NAMED_READER_ERR_DENY		0x4000000
88*3eb3c573Smarks #define	ACL_READ_NAMED_READER_ERR_ALLOW		0x8000000
89*3eb3c573Smarks 
90*3eb3c573Smarks 
91*3eb3c573Smarks #define	ACE_VALID_MASK_BITS (\
92*3eb3c573Smarks     ACE_READ_DATA | \
93*3eb3c573Smarks     ACE_LIST_DIRECTORY | \
94*3eb3c573Smarks     ACE_WRITE_DATA | \
95*3eb3c573Smarks     ACE_ADD_FILE | \
96*3eb3c573Smarks     ACE_APPEND_DATA | \
97*3eb3c573Smarks     ACE_ADD_SUBDIRECTORY | \
98*3eb3c573Smarks     ACE_READ_NAMED_ATTRS | \
99*3eb3c573Smarks     ACE_WRITE_NAMED_ATTRS | \
100*3eb3c573Smarks     ACE_EXECUTE | \
101*3eb3c573Smarks     ACE_DELETE_CHILD | \
102*3eb3c573Smarks     ACE_READ_ATTRIBUTES | \
103*3eb3c573Smarks     ACE_WRITE_ATTRIBUTES | \
104*3eb3c573Smarks     ACE_DELETE | \
105*3eb3c573Smarks     ACE_READ_ACL | \
106*3eb3c573Smarks     ACE_WRITE_ACL | \
107*3eb3c573Smarks     ACE_WRITE_OWNER | \
108*3eb3c573Smarks     ACE_SYNCHRONIZE)
109*3eb3c573Smarks 
110*3eb3c573Smarks #define	ACE_MASK_UNDEFINED			0x80000000
111*3eb3c573Smarks 
112*3eb3c573Smarks #define	ACE_VALID_FLAG_BITS (ACE_FILE_INHERIT_ACE | \
113*3eb3c573Smarks     ACE_DIRECTORY_INHERIT_ACE | \
114*3eb3c573Smarks     ACE_NO_PROPAGATE_INHERIT_ACE | ACE_INHERIT_ONLY_ACE | \
115*3eb3c573Smarks     ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \
116*3eb3c573Smarks     ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE)
117*3eb3c573Smarks 
118*3eb3c573Smarks /*
119*3eb3c573Smarks  * ACL conversion helpers
120*3eb3c573Smarks  */
121*3eb3c573Smarks 
122*3eb3c573Smarks typedef enum {
123*3eb3c573Smarks 	ace_unused,
124*3eb3c573Smarks 	ace_user_obj,
125*3eb3c573Smarks 	ace_user,
126*3eb3c573Smarks 	ace_group, /* includes GROUP and GROUP_OBJ */
127*3eb3c573Smarks 	ace_other_obj
128*3eb3c573Smarks } ace_to_aent_state_t;
129*3eb3c573Smarks 
130*3eb3c573Smarks typedef struct acevals {
131*3eb3c573Smarks 	uid_t key;
132*3eb3c573Smarks 	avl_node_t avl;
133*3eb3c573Smarks 	uint32_t mask;
134*3eb3c573Smarks 	uint32_t allowed;
135*3eb3c573Smarks 	uint32_t denied;
136*3eb3c573Smarks 	int aent_type;
137*3eb3c573Smarks } acevals_t;
138*3eb3c573Smarks 
139*3eb3c573Smarks typedef struct ace_list {
140*3eb3c573Smarks 	acevals_t user_obj;
141*3eb3c573Smarks 	avl_tree_t user;
142*3eb3c573Smarks 	int numusers;
143*3eb3c573Smarks 	acevals_t group_obj;
144*3eb3c573Smarks 	avl_tree_t group;
145*3eb3c573Smarks 	int numgroups;
146*3eb3c573Smarks 	acevals_t other_obj;
147*3eb3c573Smarks 	uint32_t acl_mask;
148*3eb3c573Smarks 	int hasmask;
149*3eb3c573Smarks 	int dfacl_flag;
150*3eb3c573Smarks 	ace_to_aent_state_t state;
151*3eb3c573Smarks 	int seen; /* bitmask of all aclent_t a_type values seen */
152*3eb3c573Smarks } ace_list_t;
153d2443e76Smarks 
154fa9e4066Sahrens typedef union {
155fa9e4066Sahrens 	const char *file;
156fa9e4066Sahrens 	int  fd;
157fa9e4066Sahrens } acl_inp;
158fa9e4066Sahrens 
159fa9e4066Sahrens acl_t *
160fa9e4066Sahrens acl_alloc(enum acl_type type)
161fa9e4066Sahrens {
162fa9e4066Sahrens 	acl_t *aclp;
163fa9e4066Sahrens 
164fa9e4066Sahrens 	aclp = malloc(sizeof (acl_t));
165fa9e4066Sahrens 
166fa9e4066Sahrens 	if (aclp == NULL)
167fa9e4066Sahrens 		return (NULL);
168fa9e4066Sahrens 
169fa9e4066Sahrens 	aclp->acl_aclp = NULL;
170fa9e4066Sahrens 	aclp->acl_cnt = 0;
171fa9e4066Sahrens 
172fa9e4066Sahrens 	switch (type) {
173fa9e4066Sahrens 	case ACE_T:
174fa9e4066Sahrens 		aclp->acl_type = ACE_T;
175fa9e4066Sahrens 		aclp->acl_entry_size = sizeof (ace_t);
176fa9e4066Sahrens 		break;
177fa9e4066Sahrens 	case ACLENT_T:
178fa9e4066Sahrens 		aclp->acl_type = ACLENT_T;
179fa9e4066Sahrens 		aclp->acl_entry_size = sizeof (aclent_t);
180fa9e4066Sahrens 		break;
181fa9e4066Sahrens 	default:
182fa9e4066Sahrens 		acl_free(aclp);
183fa9e4066Sahrens 		aclp = NULL;
184fa9e4066Sahrens 	}
185fa9e4066Sahrens 	return (aclp);
186fa9e4066Sahrens }
187fa9e4066Sahrens 
188fa9e4066Sahrens /*
189fa9e4066Sahrens  * Free acl_t structure
190fa9e4066Sahrens  */
191fa9e4066Sahrens void
192fa9e4066Sahrens acl_free(acl_t *aclp)
193fa9e4066Sahrens {
194fa9e4066Sahrens 	if (aclp == NULL)
195fa9e4066Sahrens 		return;
196fa9e4066Sahrens 
197fa9e4066Sahrens 	if (aclp->acl_aclp)
198fa9e4066Sahrens 		free(aclp->acl_aclp);
199fa9e4066Sahrens 	free(aclp);
200fa9e4066Sahrens }
201fa9e4066Sahrens 
202fa9e4066Sahrens /*
203fa9e4066Sahrens  * Determine whether a file has a trivial ACL
204fa9e4066Sahrens  * returns: 	0 = trivial
205fa9e4066Sahrens  *		1 = nontrivial
206fa9e4066Sahrens  *		<0 some other system failure, such as ENOENT or EPERM
207fa9e4066Sahrens  */
208fa9e4066Sahrens int
209fa9e4066Sahrens acl_trivial(const char *filename)
210fa9e4066Sahrens {
211fa9e4066Sahrens 	int acl_flavor;
212fa9e4066Sahrens 	int aclcnt;
213fa9e4066Sahrens 	int cntcmd;
214fa9e4066Sahrens 	int val = 0;
215fa9e4066Sahrens 	ace_t *acep;
216fa9e4066Sahrens 
217fa9e4066Sahrens 	acl_flavor = pathconf(filename, _PC_ACL_ENABLED);
218fa9e4066Sahrens 	if (acl_flavor == -1)
219fa9e4066Sahrens 		return (-1);
220fa9e4066Sahrens 
221fa9e4066Sahrens 	if (acl_flavor == _ACL_ACE_ENABLED)
222fa9e4066Sahrens 		cntcmd = ACE_GETACLCNT;
223fa9e4066Sahrens 	else
224fa9e4066Sahrens 		cntcmd = GETACLCNT;
225fa9e4066Sahrens 
226fa9e4066Sahrens 	aclcnt = acl(filename, cntcmd, 0, NULL);
227fa9e4066Sahrens 	if (aclcnt > 0) {
228fa9e4066Sahrens 		if (acl_flavor == _ACL_ACE_ENABLED) {
229fa9e4066Sahrens 			acep = malloc(sizeof (ace_t) * aclcnt);
230fa9e4066Sahrens 			if (acep == NULL)
231fa9e4066Sahrens 				return (-1);
232fa9e4066Sahrens 			if (acl(filename, ACE_GETACL,
233fa9e4066Sahrens 			    aclcnt, acep) < 0) {
234fa9e4066Sahrens 				free(acep);
235fa9e4066Sahrens 				return (-1);
236fa9e4066Sahrens 			}
237fa9e4066Sahrens 
238fa9e4066Sahrens 			val = ace_trivial(acep, aclcnt);
239fa9e4066Sahrens 			free(acep);
240d2443e76Smarks 
241fa9e4066Sahrens 		} else if (aclcnt > MIN_ACL_ENTRIES)
242fa9e4066Sahrens 			val = 1;
243fa9e4066Sahrens 	}
244fa9e4066Sahrens 	return (val);
245fa9e4066Sahrens }
246fa9e4066Sahrens 
247fa9e4066Sahrens static uint32_t
248fa9e4066Sahrens access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow)
249fa9e4066Sahrens {
250fa9e4066Sahrens 	uint32_t access_mask = 0;
251fa9e4066Sahrens 	int acl_produce;
252fa9e4066Sahrens 	int synchronize_set = 0, write_owner_set = 0;
253fa9e4066Sahrens 	int delete_set = 0, write_attrs_set = 0;
254fa9e4066Sahrens 	int read_named_set = 0, write_named_set = 0;
255fa9e4066Sahrens 
256fa9e4066Sahrens 	acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW |
257fa9e4066Sahrens 	    ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
258fa9e4066Sahrens 	    ACL_WRITE_ATTRS_WRITER_SET_DENY);
259fa9e4066Sahrens 
260fa9e4066Sahrens 	if (isallow) {
261fa9e4066Sahrens 		synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW;
262fa9e4066Sahrens 		write_owner_set = ACL_WRITE_OWNER_SET_ALLOW;
263fa9e4066Sahrens 		delete_set = ACL_DELETE_SET_ALLOW;
264fa9e4066Sahrens 		if (hasreadperm)
265fa9e4066Sahrens 			read_named_set = ACL_READ_NAMED_READER_SET_ALLOW;
266fa9e4066Sahrens 		if (haswriteperm)
267fa9e4066Sahrens 			write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
268fa9e4066Sahrens 		if (isowner)
269fa9e4066Sahrens 			write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
270fa9e4066Sahrens 		else if (haswriteperm)
271fa9e4066Sahrens 			write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
272fa9e4066Sahrens 	} else {
273fa9e4066Sahrens 
274fa9e4066Sahrens 		synchronize_set = ACL_SYNCHRONIZE_SET_DENY;
275fa9e4066Sahrens 		write_owner_set = ACL_WRITE_OWNER_SET_DENY;
276fa9e4066Sahrens 		delete_set = ACL_DELETE_SET_DENY;
277fa9e4066Sahrens 		if (hasreadperm)
278fa9e4066Sahrens 			read_named_set = ACL_READ_NAMED_READER_SET_DENY;
279fa9e4066Sahrens 		if (haswriteperm)
280fa9e4066Sahrens 			write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY;
281fa9e4066Sahrens 		if (isowner)
282fa9e4066Sahrens 			write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY;
283fa9e4066Sahrens 		else if (haswriteperm)
284fa9e4066Sahrens 			write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY;
285fa9e4066Sahrens 		else
286fa9e4066Sahrens 			/*
287fa9e4066Sahrens 			 * If the entity is not the owner and does not
288fa9e4066Sahrens 			 * have write permissions ACE_WRITE_ATTRIBUTES will
289fa9e4066Sahrens 			 * always go in the DENY ACE.
290fa9e4066Sahrens 			 */
291fa9e4066Sahrens 			access_mask |= ACE_WRITE_ATTRIBUTES;
292fa9e4066Sahrens 	}
293fa9e4066Sahrens 
294fa9e4066Sahrens 	if (acl_produce & synchronize_set)
295fa9e4066Sahrens 		access_mask |= ACE_SYNCHRONIZE;
296fa9e4066Sahrens 	if (acl_produce & write_owner_set)
297fa9e4066Sahrens 		access_mask |= ACE_WRITE_OWNER;
298fa9e4066Sahrens 	if (acl_produce & delete_set)
299fa9e4066Sahrens 		access_mask |= ACE_DELETE;
300fa9e4066Sahrens 	if (acl_produce & write_attrs_set)
301fa9e4066Sahrens 		access_mask |= ACE_WRITE_ATTRIBUTES;
302fa9e4066Sahrens 	if (acl_produce & read_named_set)
303fa9e4066Sahrens 		access_mask |= ACE_READ_NAMED_ATTRS;
304fa9e4066Sahrens 	if (acl_produce & write_named_set)
305fa9e4066Sahrens 		access_mask |= ACE_WRITE_NAMED_ATTRS;
306fa9e4066Sahrens 
307fa9e4066Sahrens 	return (access_mask);
308fa9e4066Sahrens }
309fa9e4066Sahrens 
310fa9e4066Sahrens /*
311fa9e4066Sahrens  * Given an mode_t, convert it into an access_mask as used
312fa9e4066Sahrens  * by nfsace, assuming aclent_t -> nfsace semantics.
313fa9e4066Sahrens  */
314fa9e4066Sahrens static uint32_t
315fa9e4066Sahrens mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow)
316fa9e4066Sahrens {
317fa9e4066Sahrens 	uint32_t access = 0;
318fa9e4066Sahrens 	int haswriteperm = 0;
319fa9e4066Sahrens 	int hasreadperm = 0;
320fa9e4066Sahrens 
321fa9e4066Sahrens 	if (isallow) {
322fa9e4066Sahrens 		haswriteperm = (mode & 02);
323fa9e4066Sahrens 		hasreadperm = (mode & 04);
324fa9e4066Sahrens 	} else {
325fa9e4066Sahrens 		haswriteperm = !(mode & 02);
326fa9e4066Sahrens 		hasreadperm = !(mode & 04);
327fa9e4066Sahrens 	}
328fa9e4066Sahrens 
329fa9e4066Sahrens 	/*
330fa9e4066Sahrens 	 * The following call takes care of correctly setting the following
331fa9e4066Sahrens 	 * mask bits in the access_mask:
332fa9e4066Sahrens 	 * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE,
333fa9e4066Sahrens 	 * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS
334fa9e4066Sahrens 	 */
335fa9e4066Sahrens 	access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow);
336fa9e4066Sahrens 
337fa9e4066Sahrens 	if (isallow) {
338fa9e4066Sahrens 		access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES;
339fa9e4066Sahrens 		if (isowner)
340fa9e4066Sahrens 			access |= ACE_WRITE_ACL;
341fa9e4066Sahrens 	} else {
342fa9e4066Sahrens 		if (! isowner)
343fa9e4066Sahrens 			access |= ACE_WRITE_ACL;
344fa9e4066Sahrens 	}
345fa9e4066Sahrens 
346fa9e4066Sahrens 	/* read */
347fa9e4066Sahrens 	if (mode & 04) {
348fa9e4066Sahrens 		access |= ACE_READ_DATA;
349fa9e4066Sahrens 	}
350fa9e4066Sahrens 	/* write */
351fa9e4066Sahrens 	if (mode & 02) {
352fa9e4066Sahrens 		access |= ACE_WRITE_DATA |
353fa9e4066Sahrens 		    ACE_APPEND_DATA;
354fa9e4066Sahrens 		if (isdir)
355fa9e4066Sahrens 			access |= ACE_DELETE_CHILD;
356fa9e4066Sahrens 	}
357fa9e4066Sahrens 	/* exec */
358fa9e4066Sahrens 	if (mode & 01) {
359fa9e4066Sahrens 		access |= ACE_EXECUTE;
360fa9e4066Sahrens 	}
361fa9e4066Sahrens 
362fa9e4066Sahrens 	return (access);
363fa9e4066Sahrens }
364fa9e4066Sahrens 
365fa9e4066Sahrens /*
366fa9e4066Sahrens  * Given an nfsace (presumably an ALLOW entry), make a
367fa9e4066Sahrens  * corresponding DENY entry at the address given.
368fa9e4066Sahrens  */
369fa9e4066Sahrens static void
370fa9e4066Sahrens ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner)
371fa9e4066Sahrens {
372fa9e4066Sahrens 	(void) memcpy(deny, allow, sizeof (ace_t));
373fa9e4066Sahrens 
374fa9e4066Sahrens 	deny->a_who = allow->a_who;
375fa9e4066Sahrens 
376fa9e4066Sahrens 	deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
377fa9e4066Sahrens 	deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS;
378fa9e4066Sahrens 	if (isdir)
379fa9e4066Sahrens 		deny->a_access_mask ^= ACE_DELETE_CHILD;
380fa9e4066Sahrens 
381fa9e4066Sahrens 	deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER |
382fa9e4066Sahrens 	    ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
383fa9e4066Sahrens 	    ACE_WRITE_NAMED_ATTRS);
384fa9e4066Sahrens 	deny->a_access_mask |= access_mask_set((allow->a_access_mask &
385fa9e4066Sahrens 	    ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner,
386fa9e4066Sahrens 	    B_FALSE);
387fa9e4066Sahrens }
388fa9e4066Sahrens /*
389fa9e4066Sahrens  * Make an initial pass over an array of aclent_t's.  Gather
390fa9e4066Sahrens  * information such as an ACL_MASK (if any), number of users,
391fa9e4066Sahrens  * number of groups, and whether the array needs to be sorted.
392fa9e4066Sahrens  */
393fa9e4066Sahrens static int
394fa9e4066Sahrens ln_aent_preprocess(aclent_t *aclent, int n,
395fa9e4066Sahrens     int *hasmask, mode_t *mask,
396fa9e4066Sahrens     int *numuser, int *numgroup, int *needsort)
397fa9e4066Sahrens {
398fa9e4066Sahrens 	int error = 0;
399fa9e4066Sahrens 	int i;
400fa9e4066Sahrens 	int curtype = 0;
401fa9e4066Sahrens 
402fa9e4066Sahrens 	*hasmask = 0;
403fa9e4066Sahrens 	*mask = 07;
404fa9e4066Sahrens 	*needsort = 0;
405fa9e4066Sahrens 	*numuser = 0;
406fa9e4066Sahrens 	*numgroup = 0;
407fa9e4066Sahrens 
408fa9e4066Sahrens 	for (i = 0; i < n; i++) {
409fa9e4066Sahrens 		if (aclent[i].a_type < curtype)
410fa9e4066Sahrens 			*needsort = 1;
411fa9e4066Sahrens 		else if (aclent[i].a_type > curtype)
412fa9e4066Sahrens 			curtype = aclent[i].a_type;
413fa9e4066Sahrens 		if (aclent[i].a_type & USER)
414fa9e4066Sahrens 			(*numuser)++;
415fa9e4066Sahrens 		if (aclent[i].a_type & (GROUP | GROUP_OBJ))
416fa9e4066Sahrens 			(*numgroup)++;
417fa9e4066Sahrens 		if (aclent[i].a_type & CLASS_OBJ) {
418fa9e4066Sahrens 			if (*hasmask) {
419fa9e4066Sahrens 				error = EINVAL;
420fa9e4066Sahrens 				goto out;
421fa9e4066Sahrens 			} else {
422fa9e4066Sahrens 				*hasmask = 1;
423fa9e4066Sahrens 				*mask = aclent[i].a_perm;
424fa9e4066Sahrens 			}
425fa9e4066Sahrens 		}
426fa9e4066Sahrens 	}
427fa9e4066Sahrens 
428fa9e4066Sahrens 	if ((! *hasmask) && (*numuser + *numgroup > 1)) {
429fa9e4066Sahrens 		error = EINVAL;
430fa9e4066Sahrens 		goto out;
431fa9e4066Sahrens 	}
432fa9e4066Sahrens 
433fa9e4066Sahrens out:
434fa9e4066Sahrens 	return (error);
435fa9e4066Sahrens }
436fa9e4066Sahrens 
437fa9e4066Sahrens /*
438fa9e4066Sahrens  * Convert an array of aclent_t into an array of nfsace entries,
439fa9e4066Sahrens  * following POSIX draft -> nfsv4 conversion semantics as outlined in
440fa9e4066Sahrens  * the IETF draft.
441fa9e4066Sahrens  */
442fa9e4066Sahrens static int
443fa9e4066Sahrens ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir)
444fa9e4066Sahrens {
445fa9e4066Sahrens 	int error = 0;
446fa9e4066Sahrens 	mode_t mask;
447fa9e4066Sahrens 	int numuser, numgroup, needsort;
448fa9e4066Sahrens 	int resultsize = 0;
449fa9e4066Sahrens 	int i, groupi = 0, skip;
450fa9e4066Sahrens 	ace_t *acep, *result = NULL;
451fa9e4066Sahrens 	int hasmask;
452fa9e4066Sahrens 
453fa9e4066Sahrens 	error = ln_aent_preprocess(aclent, n, &hasmask, &mask,
454fa9e4066Sahrens 	    &numuser, &numgroup, &needsort);
455fa9e4066Sahrens 	if (error != 0)
456fa9e4066Sahrens 		goto out;
457fa9e4066Sahrens 
458fa9e4066Sahrens 	/* allow + deny for each aclent */
459fa9e4066Sahrens 	resultsize = n * 2;
460fa9e4066Sahrens 	if (hasmask) {
461fa9e4066Sahrens 		/*
462fa9e4066Sahrens 		 * stick extra deny on the group_obj and on each
463fa9e4066Sahrens 		 * user|group for the mask (the group_obj was added
464fa9e4066Sahrens 		 * into the count for numgroup)
465fa9e4066Sahrens 		 */
466fa9e4066Sahrens 		resultsize += numuser + numgroup;
467fa9e4066Sahrens 		/* ... and don't count the mask itself */
468fa9e4066Sahrens 		resultsize -= 2;
469fa9e4066Sahrens 	}
470fa9e4066Sahrens 
471fa9e4066Sahrens 	/* sort the source if necessary */
472fa9e4066Sahrens 	if (needsort)
473fa9e4066Sahrens 		ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls);
474fa9e4066Sahrens 
475fa9e4066Sahrens 	result = acep = calloc(1, resultsize * sizeof (ace_t));
476fa9e4066Sahrens 	if (result == NULL)
477fa9e4066Sahrens 		goto out;
478fa9e4066Sahrens 
479fa9e4066Sahrens 	for (i = 0; i < n; i++) {
480fa9e4066Sahrens 		/*
481fa9e4066Sahrens 		 * don't process CLASS_OBJ (mask); mask was grabbed in
482fa9e4066Sahrens 		 * ln_aent_preprocess()
483fa9e4066Sahrens 		 */
484fa9e4066Sahrens 		if (aclent[i].a_type & CLASS_OBJ)
485fa9e4066Sahrens 			continue;
486fa9e4066Sahrens 
487fa9e4066Sahrens 		/* If we need an ACL_MASK emulator, prepend it now */
488fa9e4066Sahrens 		if ((hasmask) &&
489fa9e4066Sahrens 		    (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) {
490fa9e4066Sahrens 			acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
491fa9e4066Sahrens 			acep->a_flags = 0;
492fa9e4066Sahrens 			if (aclent[i].a_type & GROUP_OBJ) {
493fa9e4066Sahrens 				acep->a_who = -1;
494fa9e4066Sahrens 				acep->a_flags |=
495fa9e4066Sahrens 				    (ACE_IDENTIFIER_GROUP|ACE_GROUP);
496fa9e4066Sahrens 			} else if (aclent[i].a_type & USER) {
497fa9e4066Sahrens 				acep->a_who = aclent[i].a_id;
498fa9e4066Sahrens 			} else {
499fa9e4066Sahrens 				acep->a_who = aclent[i].a_id;
500fa9e4066Sahrens 				acep->a_flags |= ACE_IDENTIFIER_GROUP;
501fa9e4066Sahrens 			}
502fa9e4066Sahrens 			if (aclent[i].a_type & ACL_DEFAULT) {
503fa9e4066Sahrens 				acep->a_flags |= ACE_INHERIT_ONLY_ACE |
504fa9e4066Sahrens 				    ACE_FILE_INHERIT_ACE |
505fa9e4066Sahrens 				    ACE_DIRECTORY_INHERIT_ACE;
506fa9e4066Sahrens 			}
507fa9e4066Sahrens 			/*
508fa9e4066Sahrens 			 * Set the access mask for the prepended deny
509fa9e4066Sahrens 			 * ace.  To do this, we invert the mask (found
510fa9e4066Sahrens 			 * in ln_aent_preprocess()) then convert it to an
511fa9e4066Sahrens 			 * DENY ace access_mask.
512fa9e4066Sahrens 			 */
513fa9e4066Sahrens 			acep->a_access_mask = mode_to_ace_access((mask ^ 07),
514fa9e4066Sahrens 			    isdir, 0, 0);
515fa9e4066Sahrens 			acep += 1;
516fa9e4066Sahrens 		}
517fa9e4066Sahrens 
518fa9e4066Sahrens 		/* handle a_perm -> access_mask */
519fa9e4066Sahrens 		acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm,
520fa9e4066Sahrens 		    isdir, aclent[i].a_type & USER_OBJ, 1);
521fa9e4066Sahrens 
522fa9e4066Sahrens 		/* emulate a default aclent */
523fa9e4066Sahrens 		if (aclent[i].a_type & ACL_DEFAULT) {
524fa9e4066Sahrens 			acep->a_flags |= ACE_INHERIT_ONLY_ACE |
525fa9e4066Sahrens 			    ACE_FILE_INHERIT_ACE |
526fa9e4066Sahrens 			    ACE_DIRECTORY_INHERIT_ACE;
527fa9e4066Sahrens 		}
528fa9e4066Sahrens 
529fa9e4066Sahrens 		/*
530fa9e4066Sahrens 		 * handle a_perm and a_id
531fa9e4066Sahrens 		 *
532fa9e4066Sahrens 		 * this must be done last, since it involves the
533fa9e4066Sahrens 		 * corresponding deny aces, which are handled
534fa9e4066Sahrens 		 * differently for each different a_type.
535fa9e4066Sahrens 		 */
536fa9e4066Sahrens 		if (aclent[i].a_type & USER_OBJ) {
537fa9e4066Sahrens 			acep->a_who = -1;
538fa9e4066Sahrens 			acep->a_flags |= ACE_OWNER;
539fa9e4066Sahrens 			ace_make_deny(acep, acep + 1, isdir, B_TRUE);
540fa9e4066Sahrens 			acep += 2;
541fa9e4066Sahrens 		} else if (aclent[i].a_type & USER) {
542fa9e4066Sahrens 			acep->a_who = aclent[i].a_id;
543fa9e4066Sahrens 			ace_make_deny(acep, acep + 1, isdir, B_FALSE);
544fa9e4066Sahrens 			acep += 2;
545fa9e4066Sahrens 		} else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) {
546fa9e4066Sahrens 			if (aclent[i].a_type & GROUP_OBJ) {
547fa9e4066Sahrens 				acep->a_who = -1;
548fa9e4066Sahrens 				acep->a_flags |= ACE_GROUP;
549fa9e4066Sahrens 			} else {
550fa9e4066Sahrens 				acep->a_who = aclent[i].a_id;
551fa9e4066Sahrens 			}
552fa9e4066Sahrens 			acep->a_flags |= ACE_IDENTIFIER_GROUP;
553fa9e4066Sahrens 			/*
554fa9e4066Sahrens 			 * Set the corresponding deny for the group ace.
555fa9e4066Sahrens 			 *
556fa9e4066Sahrens 			 * The deny aces go after all of the groups, unlike
557fa9e4066Sahrens 			 * everything else, where they immediately follow
558fa9e4066Sahrens 			 * the allow ace.
559fa9e4066Sahrens 			 *
560fa9e4066Sahrens 			 * We calculate "skip", the number of slots to
561fa9e4066Sahrens 			 * skip ahead for the deny ace, here.
562fa9e4066Sahrens 			 *
563fa9e4066Sahrens 			 * The pattern is:
564fa9e4066Sahrens 			 * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3
565fa9e4066Sahrens 			 * thus, skip is
566fa9e4066Sahrens 			 * (2 * numgroup) - 1 - groupi
567fa9e4066Sahrens 			 * (2 * numgroup) to account for MD + A
568fa9e4066Sahrens 			 * - 1 to account for the fact that we're on the
569fa9e4066Sahrens 			 * access (A), not the mask (MD)
570fa9e4066Sahrens 			 * - groupi to account for the fact that we have
571fa9e4066Sahrens 			 * passed up groupi number of MD's.
572fa9e4066Sahrens 			 */
573fa9e4066Sahrens 			skip = (2 * numgroup) - 1 - groupi;
574fa9e4066Sahrens 			ace_make_deny(acep, acep + skip, isdir, B_FALSE);
575fa9e4066Sahrens 			/*
576fa9e4066Sahrens 			 * If we just did the last group, skip acep past
577fa9e4066Sahrens 			 * all of the denies; else, just move ahead one.
578fa9e4066Sahrens 			 */
579fa9e4066Sahrens 			if (++groupi >= numgroup)
580fa9e4066Sahrens 				acep += numgroup + 1;
581fa9e4066Sahrens 			else
582fa9e4066Sahrens 				acep += 1;
583fa9e4066Sahrens 		} else if (aclent[i].a_type & OTHER_OBJ) {
584fa9e4066Sahrens 			acep->a_who = -1;
585fa9e4066Sahrens 			acep->a_flags |= ACE_EVERYONE;
586fa9e4066Sahrens 			ace_make_deny(acep, acep + 1, isdir, B_FALSE);
587fa9e4066Sahrens 			acep += 2;
588fa9e4066Sahrens 		} else {
589fa9e4066Sahrens 			error = EINVAL;
590fa9e4066Sahrens 			goto out;
591fa9e4066Sahrens 		}
592fa9e4066Sahrens 	}
593fa9e4066Sahrens 
594fa9e4066Sahrens 	*acepp = result;
595fa9e4066Sahrens 	*rescount = resultsize;
596fa9e4066Sahrens 
597fa9e4066Sahrens out:
598fa9e4066Sahrens 	if (error != 0) {
599fa9e4066Sahrens 		if ((result != NULL) && (resultsize > 0)) {
600fa9e4066Sahrens 			free(result);
601fa9e4066Sahrens 		}
602fa9e4066Sahrens 	}
603fa9e4066Sahrens 
604fa9e4066Sahrens 	return (error);
605fa9e4066Sahrens }
606fa9e4066Sahrens 
607fa9e4066Sahrens static int
608fa9e4066Sahrens convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir,
609fa9e4066Sahrens     ace_t **retacep, int *retacecnt)
610fa9e4066Sahrens {
611fa9e4066Sahrens 	ace_t *acep;
612fa9e4066Sahrens 	ace_t *dfacep;
613fa9e4066Sahrens 	int acecnt = 0;
614fa9e4066Sahrens 	int dfacecnt = 0;
615fa9e4066Sahrens 	int dfaclstart = 0;
616fa9e4066Sahrens 	int dfaclcnt = 0;
617fa9e4066Sahrens 	aclent_t *aclp;
618fa9e4066Sahrens 	int i;
619fa9e4066Sahrens 	int error;
620fa9e4066Sahrens 
621fa9e4066Sahrens 	ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls);
622fa9e4066Sahrens 
623fa9e4066Sahrens 	for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) {
624fa9e4066Sahrens 		if (aclp->a_type & ACL_DEFAULT)
625fa9e4066Sahrens 			break;
626fa9e4066Sahrens 	}
627fa9e4066Sahrens 
628fa9e4066Sahrens 	if (i < aclcnt) {
629*3eb3c573Smarks 		dfaclstart = i;
630*3eb3c573Smarks 		dfaclcnt = aclcnt - i;
631fa9e4066Sahrens 	}
632fa9e4066Sahrens 
633fa9e4066Sahrens 	if (dfaclcnt && isdir == 0) {
634fa9e4066Sahrens 		return (-1);
635fa9e4066Sahrens 	}
636fa9e4066Sahrens 
637fa9e4066Sahrens 	error = ln_aent_to_ace(aclentp, i,  &acep, &acecnt, isdir);
638fa9e4066Sahrens 	if (error)
639fa9e4066Sahrens 		return (-1);
640fa9e4066Sahrens 
641fa9e4066Sahrens 	if (dfaclcnt) {
642fa9e4066Sahrens 		error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt,
643fa9e4066Sahrens 		    &dfacep, &dfacecnt, isdir);
644fa9e4066Sahrens 		if (error) {
645fa9e4066Sahrens 			if (acep) {
646fa9e4066Sahrens 				free(acep);
647fa9e4066Sahrens 			}
648fa9e4066Sahrens 			return (-1);
649fa9e4066Sahrens 		}
650fa9e4066Sahrens 	}
651fa9e4066Sahrens 
652*3eb3c573Smarks 	if (dfacecnt != 0) {
653*3eb3c573Smarks 		acep = realloc(acep, sizeof (ace_t) * (acecnt + dfacecnt));
654*3eb3c573Smarks 		if (acep == NULL)
655fa9e4066Sahrens 			return (-1);
656fa9e4066Sahrens 		if (dfaclcnt) {
657*3eb3c573Smarks 			(void) memcpy(acep + acecnt, dfacep,
658fa9e4066Sahrens 			    sizeof (ace_t) * dfacecnt);
659fa9e4066Sahrens 		}
660*3eb3c573Smarks 	}
661fa9e4066Sahrens 	if (dfaclcnt)
662fa9e4066Sahrens 		free(dfacep);
663fa9e4066Sahrens 
664fa9e4066Sahrens 	*retacecnt = acecnt + dfacecnt;
665*3eb3c573Smarks 	*retacep = acep;
666fa9e4066Sahrens 	return (0);
667fa9e4066Sahrens }
668fa9e4066Sahrens 
669*3eb3c573Smarks static void
670*3eb3c573Smarks acevals_init(acevals_t *vals, uid_t key)
671*3eb3c573Smarks {
672*3eb3c573Smarks 	bzero(vals, sizeof (*vals));
673*3eb3c573Smarks 	vals->allowed = ACE_MASK_UNDEFINED;
674*3eb3c573Smarks 	vals->denied = ACE_MASK_UNDEFINED;
675*3eb3c573Smarks 	vals->mask = ACE_MASK_UNDEFINED;
676*3eb3c573Smarks 	vals->key = key;
677*3eb3c573Smarks }
678*3eb3c573Smarks 
679*3eb3c573Smarks static void
680*3eb3c573Smarks ace_list_init(ace_list_t *al, int dfacl_flag)
681*3eb3c573Smarks {
682*3eb3c573Smarks 	acevals_init(&al->user_obj, NULL);
683*3eb3c573Smarks 	acevals_init(&al->group_obj, NULL);
684*3eb3c573Smarks 	acevals_init(&al->other_obj, NULL);
685*3eb3c573Smarks 	al->numusers = 0;
686*3eb3c573Smarks 	al->numgroups = 0;
687*3eb3c573Smarks 	al->acl_mask = 0;
688*3eb3c573Smarks 	al->hasmask = 0;
689*3eb3c573Smarks 	al->state = ace_unused;
690*3eb3c573Smarks 	al->seen = 0;
691*3eb3c573Smarks 	al->dfacl_flag = dfacl_flag;
692*3eb3c573Smarks }
693*3eb3c573Smarks 
694*3eb3c573Smarks /*
695*3eb3c573Smarks  * Find or create an acevals holder for a given id and avl tree.
696*3eb3c573Smarks  *
697*3eb3c573Smarks  * Note that only one thread will ever touch these avl trees, so
698*3eb3c573Smarks  * there is no need for locking.
699*3eb3c573Smarks  */
700*3eb3c573Smarks static acevals_t *
701*3eb3c573Smarks acevals_find(ace_t *ace, avl_tree_t *avl, int *num)
702*3eb3c573Smarks {
703*3eb3c573Smarks 	acevals_t key, *rc;
704*3eb3c573Smarks 	avl_index_t where;
705*3eb3c573Smarks 
706*3eb3c573Smarks 	key.key = ace->a_who;
707*3eb3c573Smarks 	rc = avl_find(avl, &key, &where);
708*3eb3c573Smarks 	if (rc != NULL)
709*3eb3c573Smarks 		return (rc);
710*3eb3c573Smarks 
711*3eb3c573Smarks 	/* this memory is freed by ln_ace_to_aent()->ace_list_free() */
712*3eb3c573Smarks 	rc = calloc(1, sizeof (acevals_t));
713*3eb3c573Smarks 	if (rc == NULL)
714*3eb3c573Smarks 		return (rc);
715*3eb3c573Smarks 	acevals_init(rc, ace->a_who);
716*3eb3c573Smarks 	avl_insert(avl, rc, where);
717*3eb3c573Smarks 	(*num)++;
718*3eb3c573Smarks 
719*3eb3c573Smarks 	return (rc);
720*3eb3c573Smarks }
721fa9e4066Sahrens 
722fa9e4066Sahrens static int
723*3eb3c573Smarks access_mask_check(ace_t *acep, int mask_bit, int isowner)
724*3eb3c573Smarks {
725*3eb3c573Smarks 	int set_deny, err_deny;
726*3eb3c573Smarks 	int set_allow, err_allow;
727*3eb3c573Smarks 	int acl_consume;
728*3eb3c573Smarks 	int haswriteperm, hasreadperm;
729*3eb3c573Smarks 
730*3eb3c573Smarks 	if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
731*3eb3c573Smarks 		haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1;
732*3eb3c573Smarks 		hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1;
733*3eb3c573Smarks 	} else {
734*3eb3c573Smarks 		haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0;
735*3eb3c573Smarks 		hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0;
736*3eb3c573Smarks 	}
737*3eb3c573Smarks 
738*3eb3c573Smarks 	acl_consume = (ACL_SYNCHRONIZE_ERR_DENY |
739*3eb3c573Smarks 	    ACL_DELETE_ERR_DENY |
740*3eb3c573Smarks 	    ACL_WRITE_OWNER_ERR_DENY |
741*3eb3c573Smarks 	    ACL_WRITE_OWNER_ERR_ALLOW |
742*3eb3c573Smarks 	    ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
743*3eb3c573Smarks 	    ACL_WRITE_ATTRS_OWNER_ERR_DENY |
744*3eb3c573Smarks 	    ACL_WRITE_ATTRS_WRITER_SET_DENY |
745*3eb3c573Smarks 	    ACL_WRITE_ATTRS_WRITER_ERR_ALLOW |
746*3eb3c573Smarks 	    ACL_WRITE_NAMED_WRITER_ERR_DENY |
747*3eb3c573Smarks 	    ACL_READ_NAMED_READER_ERR_DENY);
748*3eb3c573Smarks 
749*3eb3c573Smarks 	if (mask_bit == ACE_SYNCHRONIZE) {
750*3eb3c573Smarks 		set_deny = ACL_SYNCHRONIZE_SET_DENY;
751*3eb3c573Smarks 		err_deny =  ACL_SYNCHRONIZE_ERR_DENY;
752*3eb3c573Smarks 		set_allow = ACL_SYNCHRONIZE_SET_ALLOW;
753*3eb3c573Smarks 		err_allow = ACL_SYNCHRONIZE_ERR_ALLOW;
754*3eb3c573Smarks 	} else if (mask_bit == ACE_WRITE_OWNER) {
755*3eb3c573Smarks 		set_deny = ACL_WRITE_OWNER_SET_DENY;
756*3eb3c573Smarks 		err_deny =  ACL_WRITE_OWNER_ERR_DENY;
757*3eb3c573Smarks 		set_allow = ACL_WRITE_OWNER_SET_ALLOW;
758*3eb3c573Smarks 		err_allow = ACL_WRITE_OWNER_ERR_ALLOW;
759*3eb3c573Smarks 	} else if (mask_bit == ACE_DELETE) {
760*3eb3c573Smarks 		set_deny = ACL_DELETE_SET_DENY;
761*3eb3c573Smarks 		err_deny =  ACL_DELETE_ERR_DENY;
762*3eb3c573Smarks 		set_allow = ACL_DELETE_SET_ALLOW;
763*3eb3c573Smarks 		err_allow = ACL_DELETE_ERR_ALLOW;
764*3eb3c573Smarks 	} else if (mask_bit == ACE_WRITE_ATTRIBUTES) {
765*3eb3c573Smarks 		if (isowner) {
766*3eb3c573Smarks 			set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY;
767*3eb3c573Smarks 			err_deny =  ACL_WRITE_ATTRS_OWNER_ERR_DENY;
768*3eb3c573Smarks 			set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
769*3eb3c573Smarks 			err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW;
770*3eb3c573Smarks 		} else if (haswriteperm) {
771*3eb3c573Smarks 			set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY;
772*3eb3c573Smarks 			err_deny =  ACL_WRITE_ATTRS_WRITER_ERR_DENY;
773*3eb3c573Smarks 			set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
774*3eb3c573Smarks 			err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW;
775*3eb3c573Smarks 		} else {
776*3eb3c573Smarks 			if ((acep->a_access_mask & mask_bit) &&
777*3eb3c573Smarks 			    (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) {
778*3eb3c573Smarks 				return (ENOTSUP);
779*3eb3c573Smarks 			}
780*3eb3c573Smarks 			return (0);
781*3eb3c573Smarks 		}
782*3eb3c573Smarks 	} else if (mask_bit == ACE_READ_NAMED_ATTRS) {
783*3eb3c573Smarks 		if (!hasreadperm)
784*3eb3c573Smarks 			return (0);
785*3eb3c573Smarks 
786*3eb3c573Smarks 		set_deny = ACL_READ_NAMED_READER_SET_DENY;
787*3eb3c573Smarks 		err_deny = ACL_READ_NAMED_READER_ERR_DENY;
788*3eb3c573Smarks 		set_allow = ACL_READ_NAMED_READER_SET_ALLOW;
789*3eb3c573Smarks 		err_allow = ACL_READ_NAMED_READER_ERR_ALLOW;
790*3eb3c573Smarks 	} else if (mask_bit == ACE_WRITE_NAMED_ATTRS) {
791*3eb3c573Smarks 		if (!haswriteperm)
792*3eb3c573Smarks 			return (0);
793*3eb3c573Smarks 
794*3eb3c573Smarks 		set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY;
795*3eb3c573Smarks 		err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY;
796*3eb3c573Smarks 		set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
797*3eb3c573Smarks 		err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW;
798*3eb3c573Smarks 	} else {
799*3eb3c573Smarks 		return (EINVAL);
800*3eb3c573Smarks 	}
801*3eb3c573Smarks 
802*3eb3c573Smarks 	if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
803*3eb3c573Smarks 		if (acl_consume & set_deny) {
804*3eb3c573Smarks 			if (!(acep->a_access_mask & mask_bit)) {
805*3eb3c573Smarks 				return (ENOTSUP);
806*3eb3c573Smarks 			}
807*3eb3c573Smarks 		} else if (acl_consume & err_deny) {
808*3eb3c573Smarks 			if (acep->a_access_mask & mask_bit) {
809*3eb3c573Smarks 				return (ENOTSUP);
810*3eb3c573Smarks 			}
811*3eb3c573Smarks 		}
812*3eb3c573Smarks 	} else {
813*3eb3c573Smarks 		/* ACE_ACCESS_ALLOWED_ACE_TYPE */
814*3eb3c573Smarks 		if (acl_consume & set_allow) {
815*3eb3c573Smarks 			if (!(acep->a_access_mask & mask_bit)) {
816*3eb3c573Smarks 				return (ENOTSUP);
817*3eb3c573Smarks 			}
818*3eb3c573Smarks 		} else if (acl_consume & err_allow) {
819*3eb3c573Smarks 			if (acep->a_access_mask & mask_bit) {
820*3eb3c573Smarks 				return (ENOTSUP);
821*3eb3c573Smarks 			}
822*3eb3c573Smarks 		}
823*3eb3c573Smarks 	}
824*3eb3c573Smarks 	return (0);
825*3eb3c573Smarks }
826*3eb3c573Smarks 
827*3eb3c573Smarks static int
828*3eb3c573Smarks ace_to_aent_legal(ace_t *acep)
829*3eb3c573Smarks {
830*3eb3c573Smarks 	int error = 0;
831*3eb3c573Smarks 	int isowner;
832*3eb3c573Smarks 
833*3eb3c573Smarks 	/* only ALLOW or DENY */
834*3eb3c573Smarks 	if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) &&
835*3eb3c573Smarks 	    (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) {
836*3eb3c573Smarks 		error = ENOTSUP;
837*3eb3c573Smarks 		goto out;
838*3eb3c573Smarks 	}
839*3eb3c573Smarks 
840*3eb3c573Smarks 	/* check for invalid flags */
841*3eb3c573Smarks 	if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) {
842*3eb3c573Smarks 		error = EINVAL;
843*3eb3c573Smarks 		goto out;
844*3eb3c573Smarks 	}
845*3eb3c573Smarks 
846*3eb3c573Smarks 	/* some flags are illegal */
847*3eb3c573Smarks 	if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG |
848*3eb3c573Smarks 	    ACE_FAILED_ACCESS_ACE_FLAG |
849*3eb3c573Smarks 	    ACE_NO_PROPAGATE_INHERIT_ACE)) {
850*3eb3c573Smarks 		error = ENOTSUP;
851*3eb3c573Smarks 		goto out;
852*3eb3c573Smarks 	}
853*3eb3c573Smarks 
854*3eb3c573Smarks 	/* check for invalid masks */
855*3eb3c573Smarks 	if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) {
856*3eb3c573Smarks 		error = EINVAL;
857*3eb3c573Smarks 		goto out;
858*3eb3c573Smarks 	}
859*3eb3c573Smarks 
860*3eb3c573Smarks 	if ((acep->a_flags & ACE_OWNER)) {
861*3eb3c573Smarks 		isowner = 1;
862*3eb3c573Smarks 	} else {
863*3eb3c573Smarks 		isowner = 0;
864*3eb3c573Smarks 	}
865*3eb3c573Smarks 
866*3eb3c573Smarks 	error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner);
867*3eb3c573Smarks 	if (error)
868*3eb3c573Smarks 		goto out;
869*3eb3c573Smarks 
870*3eb3c573Smarks 	error = access_mask_check(acep, ACE_WRITE_OWNER, isowner);
871*3eb3c573Smarks 	if (error)
872*3eb3c573Smarks 		goto out;
873*3eb3c573Smarks 
874*3eb3c573Smarks 	error = access_mask_check(acep, ACE_DELETE, isowner);
875*3eb3c573Smarks 	if (error)
876*3eb3c573Smarks 		goto out;
877*3eb3c573Smarks 
878*3eb3c573Smarks 	error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner);
879*3eb3c573Smarks 	if (error)
880*3eb3c573Smarks 		goto out;
881*3eb3c573Smarks 
882*3eb3c573Smarks 	error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner);
883*3eb3c573Smarks 	if (error)
884*3eb3c573Smarks 		goto out;
885*3eb3c573Smarks 
886*3eb3c573Smarks 	error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner);
887*3eb3c573Smarks 	if (error)
888*3eb3c573Smarks 		goto out;
889*3eb3c573Smarks 
890*3eb3c573Smarks 	/* more detailed checking of masks */
891*3eb3c573Smarks 	if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
892*3eb3c573Smarks 		if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) {
893*3eb3c573Smarks 			error = ENOTSUP;
894*3eb3c573Smarks 			goto out;
895*3eb3c573Smarks 		}
896*3eb3c573Smarks 		if ((acep->a_access_mask & ACE_WRITE_DATA) &&
897*3eb3c573Smarks 		    (! (acep->a_access_mask & ACE_APPEND_DATA))) {
898*3eb3c573Smarks 			error = ENOTSUP;
899*3eb3c573Smarks 			goto out;
900*3eb3c573Smarks 		}
901*3eb3c573Smarks 		if ((! (acep->a_access_mask & ACE_WRITE_DATA)) &&
902*3eb3c573Smarks 		    (acep->a_access_mask & ACE_APPEND_DATA)) {
903*3eb3c573Smarks 			error = ENOTSUP;
904*3eb3c573Smarks 			goto out;
905*3eb3c573Smarks 		}
906*3eb3c573Smarks 	}
907*3eb3c573Smarks 
908*3eb3c573Smarks 	/* ACL enforcement */
909*3eb3c573Smarks 	if ((acep->a_access_mask & ACE_READ_ACL) &&
910*3eb3c573Smarks 	    (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) {
911*3eb3c573Smarks 		error = ENOTSUP;
912*3eb3c573Smarks 		goto out;
913*3eb3c573Smarks 	}
914*3eb3c573Smarks 	if (acep->a_access_mask & ACE_WRITE_ACL) {
915*3eb3c573Smarks 		if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) &&
916*3eb3c573Smarks 		    (isowner)) {
917*3eb3c573Smarks 			error = ENOTSUP;
918*3eb3c573Smarks 			goto out;
919*3eb3c573Smarks 		}
920*3eb3c573Smarks 		if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) &&
921*3eb3c573Smarks 		    (! isowner)) {
922*3eb3c573Smarks 			error = ENOTSUP;
923*3eb3c573Smarks 			goto out;
924*3eb3c573Smarks 		}
925*3eb3c573Smarks 	}
926*3eb3c573Smarks 
927*3eb3c573Smarks out:
928*3eb3c573Smarks 	return (error);
929*3eb3c573Smarks }
930*3eb3c573Smarks 
931*3eb3c573Smarks static int
932*3eb3c573Smarks ace_mask_to_mode(uint32_t  mask, o_mode_t *modep, int isdir)
933*3eb3c573Smarks {
934*3eb3c573Smarks 	int error = 0;
935*3eb3c573Smarks 	o_mode_t mode = 0;
936*3eb3c573Smarks 	uint32_t bits, wantbits;
937*3eb3c573Smarks 
938*3eb3c573Smarks 	/* read */
939*3eb3c573Smarks 	if (mask & ACE_READ_DATA)
940*3eb3c573Smarks 		mode |= 04;
941*3eb3c573Smarks 
942*3eb3c573Smarks 	/* write */
943*3eb3c573Smarks 	wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA);
944*3eb3c573Smarks 	if (isdir)
945*3eb3c573Smarks 		wantbits |= ACE_DELETE_CHILD;
946*3eb3c573Smarks 	bits = mask & wantbits;
947*3eb3c573Smarks 	if (bits != 0) {
948*3eb3c573Smarks 		if (bits != wantbits) {
949*3eb3c573Smarks 			error = ENOTSUP;
950*3eb3c573Smarks 			goto out;
951*3eb3c573Smarks 		}
952*3eb3c573Smarks 		mode |= 02;
953*3eb3c573Smarks 	}
954*3eb3c573Smarks 
955*3eb3c573Smarks 	/* exec */
956*3eb3c573Smarks 	if (mask & ACE_EXECUTE) {
957*3eb3c573Smarks 		mode |= 01;
958*3eb3c573Smarks 	}
959*3eb3c573Smarks 
960*3eb3c573Smarks 	*modep = mode;
961*3eb3c573Smarks 
962*3eb3c573Smarks out:
963*3eb3c573Smarks 	return (error);
964*3eb3c573Smarks }
965*3eb3c573Smarks 
966*3eb3c573Smarks static int
967*3eb3c573Smarks ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir)
968*3eb3c573Smarks {
969*3eb3c573Smarks 	/* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */
970*3eb3c573Smarks 	if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) !=
971*3eb3c573Smarks 	    (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) {
972*3eb3c573Smarks 		return (ENOTSUP);
973*3eb3c573Smarks 	}
974*3eb3c573Smarks 
975*3eb3c573Smarks 	return (ace_mask_to_mode(mask, modep, isdir));
976*3eb3c573Smarks }
977*3eb3c573Smarks 
978*3eb3c573Smarks static int
979*3eb3c573Smarks acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list,
980*3eb3c573Smarks     uid_t owner, gid_t group, int isdir)
981*3eb3c573Smarks {
982*3eb3c573Smarks 	int error;
983*3eb3c573Smarks 	uint32_t  flips = ACE_POSIX_SUPPORTED_BITS;
984*3eb3c573Smarks 
985*3eb3c573Smarks 	if (isdir)
986*3eb3c573Smarks 		flips |= ACE_DELETE_CHILD;
987*3eb3c573Smarks 	if (vals->allowed != (vals->denied ^ flips)) {
988*3eb3c573Smarks 		error = ENOTSUP;
989*3eb3c573Smarks 		goto out;
990*3eb3c573Smarks 	}
991*3eb3c573Smarks 	if ((list->hasmask) && (list->acl_mask != vals->mask) &&
992*3eb3c573Smarks 	    (vals->aent_type & (USER | GROUP | GROUP_OBJ))) {
993*3eb3c573Smarks 		error = ENOTSUP;
994*3eb3c573Smarks 		goto out;
995*3eb3c573Smarks 	}
996*3eb3c573Smarks 	error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir);
997*3eb3c573Smarks 	if (error != 0)
998*3eb3c573Smarks 		goto out;
999*3eb3c573Smarks 	dest->a_type = vals->aent_type;
1000*3eb3c573Smarks 	if (dest->a_type & (USER | GROUP)) {
1001*3eb3c573Smarks 		dest->a_id = vals->key;
1002*3eb3c573Smarks 	} else if (dest->a_type & USER_OBJ) {
1003*3eb3c573Smarks 		dest->a_id = owner;
1004*3eb3c573Smarks 	} else if (dest->a_type & GROUP_OBJ) {
1005*3eb3c573Smarks 		dest->a_id = group;
1006*3eb3c573Smarks 	} else if (dest->a_type & OTHER_OBJ) {
1007*3eb3c573Smarks 		dest->a_id = 0;
1008*3eb3c573Smarks 	} else {
1009*3eb3c573Smarks 		error = EINVAL;
1010*3eb3c573Smarks 		goto out;
1011*3eb3c573Smarks 	}
1012*3eb3c573Smarks 
1013*3eb3c573Smarks out:
1014*3eb3c573Smarks 	return (error);
1015*3eb3c573Smarks }
1016*3eb3c573Smarks 
1017*3eb3c573Smarks static int
1018*3eb3c573Smarks ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt,
1019*3eb3c573Smarks     uid_t owner, gid_t group, int isdir)
1020*3eb3c573Smarks {
1021*3eb3c573Smarks 	int error = 0;
1022*3eb3c573Smarks 	aclent_t *aent, *result = NULL;
1023*3eb3c573Smarks 	acevals_t *vals;
1024*3eb3c573Smarks 	int resultcount;
1025*3eb3c573Smarks 
1026*3eb3c573Smarks 	if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) !=
1027*3eb3c573Smarks 	    (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) {
1028*3eb3c573Smarks 		error = ENOTSUP;
1029*3eb3c573Smarks 		goto out;
1030*3eb3c573Smarks 	}
1031*3eb3c573Smarks 	if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) {
1032*3eb3c573Smarks 		error = ENOTSUP;
1033*3eb3c573Smarks 		goto out;
1034*3eb3c573Smarks 	}
1035*3eb3c573Smarks 
1036*3eb3c573Smarks 	resultcount = 3 + list->numusers + list->numgroups;
1037*3eb3c573Smarks 	/*
1038*3eb3c573Smarks 	 * This must be the same condition as below, when we add the CLASS_OBJ
1039*3eb3c573Smarks 	 * (aka ACL mask)
1040*3eb3c573Smarks 	 */
1041*3eb3c573Smarks 	if ((list->hasmask) || (! list->dfacl_flag))
1042*3eb3c573Smarks 		resultcount += 1;
1043*3eb3c573Smarks 
1044*3eb3c573Smarks 	result = aent = calloc(1, resultcount * sizeof (aclent_t));
1045*3eb3c573Smarks 
1046*3eb3c573Smarks 	if (result == NULL) {
1047*3eb3c573Smarks 		error = ENOMEM;
1048*3eb3c573Smarks 		goto out;
1049*3eb3c573Smarks 	}
1050*3eb3c573Smarks 
1051*3eb3c573Smarks 	/* USER_OBJ */
1052*3eb3c573Smarks 	if (!(list->user_obj.aent_type & USER_OBJ)) {
1053*3eb3c573Smarks 		error = EINVAL;
1054*3eb3c573Smarks 		goto out;
1055*3eb3c573Smarks 	}
1056*3eb3c573Smarks 
1057*3eb3c573Smarks 	error = acevals_to_aent(&list->user_obj, aent, list, owner, group,
1058*3eb3c573Smarks 	    isdir);
1059*3eb3c573Smarks 
1060*3eb3c573Smarks 	if (error != 0)
1061*3eb3c573Smarks 		goto out;
1062*3eb3c573Smarks 	++aent;
1063*3eb3c573Smarks 	/* USER */
1064*3eb3c573Smarks 	vals = NULL;
1065*3eb3c573Smarks 	for (vals = avl_first(&list->user); vals != NULL;
1066*3eb3c573Smarks 	    vals = AVL_NEXT(&list->user, vals)) {
1067*3eb3c573Smarks 		if (!(vals->aent_type & USER)) {
1068*3eb3c573Smarks 			error = EINVAL;
1069*3eb3c573Smarks 			goto out;
1070*3eb3c573Smarks 		}
1071*3eb3c573Smarks 		error = acevals_to_aent(vals, aent, list, owner, group,
1072*3eb3c573Smarks 		    isdir);
1073*3eb3c573Smarks 		if (error != 0)
1074*3eb3c573Smarks 			goto out;
1075*3eb3c573Smarks 		++aent;
1076*3eb3c573Smarks 	}
1077*3eb3c573Smarks 	/* GROUP_OBJ */
1078*3eb3c573Smarks 	if (!(list->group_obj.aent_type & GROUP_OBJ)) {
1079*3eb3c573Smarks 		error = EINVAL;
1080*3eb3c573Smarks 		goto out;
1081*3eb3c573Smarks 	}
1082*3eb3c573Smarks 	error = acevals_to_aent(&list->group_obj, aent, list, owner, group,
1083*3eb3c573Smarks 	    isdir);
1084*3eb3c573Smarks 	if (error != 0)
1085*3eb3c573Smarks 		goto out;
1086*3eb3c573Smarks 	++aent;
1087*3eb3c573Smarks 	/* GROUP */
1088*3eb3c573Smarks 	vals = NULL;
1089*3eb3c573Smarks 	for (vals = avl_first(&list->group); vals != NULL;
1090*3eb3c573Smarks 	    vals = AVL_NEXT(&list->group, vals)) {
1091*3eb3c573Smarks 		if (!(vals->aent_type & GROUP)) {
1092*3eb3c573Smarks 			error = EINVAL;
1093*3eb3c573Smarks 			goto out;
1094*3eb3c573Smarks 		}
1095*3eb3c573Smarks 		error = acevals_to_aent(vals, aent, list, owner, group,
1096*3eb3c573Smarks 		    isdir);
1097*3eb3c573Smarks 		if (error != 0)
1098*3eb3c573Smarks 			goto out;
1099*3eb3c573Smarks 		++aent;
1100*3eb3c573Smarks 	}
1101*3eb3c573Smarks 	/*
1102*3eb3c573Smarks 	 * CLASS_OBJ (aka ACL_MASK)
1103*3eb3c573Smarks 	 *
1104*3eb3c573Smarks 	 * An ACL_MASK is not fabricated if the ACL is a default ACL.
1105*3eb3c573Smarks 	 * This is to follow UFS's behavior.
1106*3eb3c573Smarks 	 */
1107*3eb3c573Smarks 	if ((list->hasmask) || (! list->dfacl_flag)) {
1108*3eb3c573Smarks 		if (list->hasmask) {
1109*3eb3c573Smarks 			uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
1110*3eb3c573Smarks 			if (isdir)
1111*3eb3c573Smarks 				flips |= ACE_DELETE_CHILD;
1112*3eb3c573Smarks 			error = ace_mask_to_mode(list->acl_mask ^ flips,
1113*3eb3c573Smarks 			    &aent->a_perm, isdir);
1114*3eb3c573Smarks 			if (error != 0)
1115*3eb3c573Smarks 				goto out;
1116*3eb3c573Smarks 		} else {
1117*3eb3c573Smarks 			/* fabricate the ACL_MASK from the group permissions */
1118*3eb3c573Smarks 			error = ace_mask_to_mode(list->group_obj.allowed,
1119*3eb3c573Smarks 			    &aent->a_perm, isdir);
1120*3eb3c573Smarks 			if (error != 0)
1121*3eb3c573Smarks 				goto out;
1122*3eb3c573Smarks 		}
1123*3eb3c573Smarks 		aent->a_id = 0;
1124*3eb3c573Smarks 		aent->a_type = CLASS_OBJ | list->dfacl_flag;
1125*3eb3c573Smarks 		++aent;
1126*3eb3c573Smarks 	}
1127*3eb3c573Smarks 	/* OTHER_OBJ */
1128*3eb3c573Smarks 	if (!(list->other_obj.aent_type & OTHER_OBJ)) {
1129*3eb3c573Smarks 		error = EINVAL;
1130*3eb3c573Smarks 		goto out;
1131*3eb3c573Smarks 	}
1132*3eb3c573Smarks 	error = acevals_to_aent(&list->other_obj, aent, list, owner, group,
1133*3eb3c573Smarks 	    isdir);
1134*3eb3c573Smarks 	if (error != 0)
1135*3eb3c573Smarks 		goto out;
1136*3eb3c573Smarks 	++aent;
1137*3eb3c573Smarks 
1138*3eb3c573Smarks 	*aclentp = result;
1139*3eb3c573Smarks 	*aclcnt = resultcount;
1140*3eb3c573Smarks 
1141*3eb3c573Smarks out:
1142*3eb3c573Smarks 	if (error != 0) {
1143*3eb3c573Smarks 		if (result != NULL)
1144*3eb3c573Smarks 			free(result);
1145*3eb3c573Smarks 	}
1146*3eb3c573Smarks 
1147*3eb3c573Smarks 	return (error);
1148*3eb3c573Smarks }
1149*3eb3c573Smarks 
1150*3eb3c573Smarks /*
1151*3eb3c573Smarks  * free all data associated with an ace_list
1152*3eb3c573Smarks  */
1153*3eb3c573Smarks static void
1154*3eb3c573Smarks ace_list_free(ace_list_t *al)
1155*3eb3c573Smarks {
1156*3eb3c573Smarks 	acevals_t *node;
1157*3eb3c573Smarks 	void *cookie;
1158*3eb3c573Smarks 
1159*3eb3c573Smarks 	if (al == NULL)
1160*3eb3c573Smarks 		return;
1161*3eb3c573Smarks 
1162*3eb3c573Smarks 	cookie = NULL;
1163*3eb3c573Smarks 	while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL)
1164*3eb3c573Smarks 		free(node);
1165*3eb3c573Smarks 	cookie = NULL;
1166*3eb3c573Smarks 	while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL)
1167*3eb3c573Smarks 		free(node);
1168*3eb3c573Smarks 
1169*3eb3c573Smarks 	avl_destroy(&al->user);
1170*3eb3c573Smarks 	avl_destroy(&al->group);
1171*3eb3c573Smarks 
1172*3eb3c573Smarks 	/* free the container itself */
1173*3eb3c573Smarks 	free(al);
1174*3eb3c573Smarks }
1175*3eb3c573Smarks 
1176*3eb3c573Smarks static int
1177*3eb3c573Smarks acevals_compare(const void *va, const void *vb)
1178*3eb3c573Smarks {
1179*3eb3c573Smarks 	const acevals_t *a = va, *b = vb;
1180*3eb3c573Smarks 
1181*3eb3c573Smarks 	if (a->key == b->key)
1182*3eb3c573Smarks 		return (0);
1183*3eb3c573Smarks 
1184*3eb3c573Smarks 	if (a->key > b->key)
1185*3eb3c573Smarks 		return (1);
1186*3eb3c573Smarks 
1187*3eb3c573Smarks 	else
1188*3eb3c573Smarks 		return (-1);
1189*3eb3c573Smarks }
1190*3eb3c573Smarks 
1191*3eb3c573Smarks /*
1192*3eb3c573Smarks  * Convert a list of ace_t entries to equivalent regular and default
1193*3eb3c573Smarks  * aclent_t lists.  Return error (ENOTSUP) when conversion is not possible.
1194*3eb3c573Smarks  */
1195*3eb3c573Smarks static int
1196*3eb3c573Smarks ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group,
1197*3eb3c573Smarks     aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt,
1198*3eb3c573Smarks     int isdir)
1199*3eb3c573Smarks {
1200*3eb3c573Smarks 	int error = 0;
1201*3eb3c573Smarks 	ace_t *acep;
1202*3eb3c573Smarks 	uint32_t bits;
1203*3eb3c573Smarks 	int i;
1204*3eb3c573Smarks 	ace_list_t *normacl = NULL, *dfacl = NULL, *acl;
1205*3eb3c573Smarks 	acevals_t *vals;
1206*3eb3c573Smarks 
1207*3eb3c573Smarks 	*aclentp = NULL;
1208*3eb3c573Smarks 	*aclcnt = 0;
1209*3eb3c573Smarks 	*dfaclentp = NULL;
1210*3eb3c573Smarks 	*dfaclcnt = 0;
1211*3eb3c573Smarks 
1212*3eb3c573Smarks 	/* we need at least user_obj, group_obj, and other_obj */
1213*3eb3c573Smarks 	if (n < 6) {
1214*3eb3c573Smarks 		error = ENOTSUP;
1215*3eb3c573Smarks 		goto out;
1216*3eb3c573Smarks 	}
1217*3eb3c573Smarks 	if (ace == NULL) {
1218*3eb3c573Smarks 		error = EINVAL;
1219*3eb3c573Smarks 		goto out;
1220*3eb3c573Smarks 	}
1221*3eb3c573Smarks 
1222*3eb3c573Smarks 	normacl = calloc(1, sizeof (ace_list_t));
1223*3eb3c573Smarks 
1224*3eb3c573Smarks 	if (normacl == NULL) {
1225*3eb3c573Smarks 		error = errno;
1226*3eb3c573Smarks 		goto out;
1227*3eb3c573Smarks 	}
1228*3eb3c573Smarks 
1229*3eb3c573Smarks 	avl_create(&normacl->user, acevals_compare, sizeof (acevals_t),
1230*3eb3c573Smarks 	    offsetof(acevals_t, avl));
1231*3eb3c573Smarks 	avl_create(&normacl->group, acevals_compare, sizeof (acevals_t),
1232*3eb3c573Smarks 	    offsetof(acevals_t, avl));
1233*3eb3c573Smarks 
1234*3eb3c573Smarks 	ace_list_init(normacl, 0);
1235*3eb3c573Smarks 
1236*3eb3c573Smarks 	dfacl = calloc(1, sizeof (ace_list_t));
1237*3eb3c573Smarks 	if (dfacl == NULL) {
1238*3eb3c573Smarks 		error = errno;
1239*3eb3c573Smarks 		goto out;
1240*3eb3c573Smarks 	}
1241*3eb3c573Smarks 	avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t),
1242*3eb3c573Smarks 	    offsetof(acevals_t, avl));
1243*3eb3c573Smarks 	avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t),
1244*3eb3c573Smarks 	    offsetof(acevals_t, avl));
1245*3eb3c573Smarks 	ace_list_init(dfacl, ACL_DEFAULT);
1246*3eb3c573Smarks 
1247*3eb3c573Smarks 	/* process every ace_t... */
1248*3eb3c573Smarks 	for (i = 0; i < n; i++) {
1249*3eb3c573Smarks 		acep = &ace[i];
1250*3eb3c573Smarks 
1251*3eb3c573Smarks 		/* rule out certain cases quickly */
1252*3eb3c573Smarks 		error = ace_to_aent_legal(acep);
1253*3eb3c573Smarks 		if (error != 0)
1254*3eb3c573Smarks 			goto out;
1255*3eb3c573Smarks 
1256*3eb3c573Smarks 		/*
1257*3eb3c573Smarks 		 * Turn off these bits in order to not have to worry about
1258*3eb3c573Smarks 		 * them when doing the checks for compliments.
1259*3eb3c573Smarks 		 */
1260*3eb3c573Smarks 		acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE |
1261*3eb3c573Smarks 		    ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES |
1262*3eb3c573Smarks 		    ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS);
1263*3eb3c573Smarks 
1264*3eb3c573Smarks 		/* see if this should be a regular or default acl */
1265*3eb3c573Smarks 		bits = acep->a_flags &
1266*3eb3c573Smarks 		    (ACE_INHERIT_ONLY_ACE |
1267*3eb3c573Smarks 		    ACE_FILE_INHERIT_ACE |
1268*3eb3c573Smarks 		    ACE_DIRECTORY_INHERIT_ACE);
1269*3eb3c573Smarks 		if (bits != 0) {
1270*3eb3c573Smarks 			/* all or nothing on these inherit bits */
1271*3eb3c573Smarks 			if (bits != (ACE_INHERIT_ONLY_ACE |
1272*3eb3c573Smarks 			    ACE_FILE_INHERIT_ACE |
1273*3eb3c573Smarks 			    ACE_DIRECTORY_INHERIT_ACE)) {
1274*3eb3c573Smarks 				error = ENOTSUP;
1275*3eb3c573Smarks 				goto out;
1276*3eb3c573Smarks 			}
1277*3eb3c573Smarks 			acl = dfacl;
1278*3eb3c573Smarks 		} else {
1279*3eb3c573Smarks 			acl = normacl;
1280*3eb3c573Smarks 		}
1281*3eb3c573Smarks 
1282*3eb3c573Smarks 		if ((acep->a_flags & ACE_OWNER)) {
1283*3eb3c573Smarks 			if (acl->state > ace_user_obj) {
1284*3eb3c573Smarks 				error = ENOTSUP;
1285*3eb3c573Smarks 				goto out;
1286*3eb3c573Smarks 			}
1287*3eb3c573Smarks 			acl->state = ace_user_obj;
1288*3eb3c573Smarks 			acl->seen |= USER_OBJ;
1289*3eb3c573Smarks 			vals = &acl->user_obj;
1290*3eb3c573Smarks 			vals->aent_type = USER_OBJ | acl->dfacl_flag;
1291*3eb3c573Smarks 		} else if ((acep->a_flags & ACE_EVERYONE)) {
1292*3eb3c573Smarks 			acl->state = ace_other_obj;
1293*3eb3c573Smarks 			acl->seen |= OTHER_OBJ;
1294*3eb3c573Smarks 			vals = &acl->other_obj;
1295*3eb3c573Smarks 			vals->aent_type = OTHER_OBJ | acl->dfacl_flag;
1296*3eb3c573Smarks 		} else if (acep->a_flags & ACE_IDENTIFIER_GROUP) {
1297*3eb3c573Smarks 			if (acl->state > ace_group) {
1298*3eb3c573Smarks 				error = ENOTSUP;
1299*3eb3c573Smarks 				goto out;
1300*3eb3c573Smarks 			}
1301*3eb3c573Smarks 			if ((acep->a_flags & ACE_GROUP)) {
1302*3eb3c573Smarks 				acl->seen |= GROUP_OBJ;
1303*3eb3c573Smarks 				vals = &acl->group_obj;
1304*3eb3c573Smarks 				vals->aent_type = GROUP_OBJ | acl->dfacl_flag;
1305*3eb3c573Smarks 			} else {
1306*3eb3c573Smarks 				acl->seen |= GROUP;
1307*3eb3c573Smarks 				vals = acevals_find(acep, &acl->group,
1308*3eb3c573Smarks 				    &acl->numgroups);
1309*3eb3c573Smarks 				if (vals == NULL) {
1310*3eb3c573Smarks 					error = ENOMEM;
1311*3eb3c573Smarks 					goto out;
1312*3eb3c573Smarks 				}
1313*3eb3c573Smarks 				vals->aent_type = GROUP | acl->dfacl_flag;
1314*3eb3c573Smarks 			}
1315*3eb3c573Smarks 			acl->state = ace_group;
1316*3eb3c573Smarks 		} else {
1317*3eb3c573Smarks 			if (acl->state > ace_user) {
1318*3eb3c573Smarks 				error = ENOTSUP;
1319*3eb3c573Smarks 				goto out;
1320*3eb3c573Smarks 			}
1321*3eb3c573Smarks 			acl->state = ace_user;
1322*3eb3c573Smarks 			acl->seen |= USER;
1323*3eb3c573Smarks 			vals = acevals_find(acep, &acl->user,
1324*3eb3c573Smarks 			    &acl->numusers);
1325*3eb3c573Smarks 			if (vals == NULL) {
1326*3eb3c573Smarks 				error = ENOMEM;
1327*3eb3c573Smarks 				goto out;
1328*3eb3c573Smarks 			}
1329*3eb3c573Smarks 			vals->aent_type = USER | acl->dfacl_flag;
1330*3eb3c573Smarks 		}
1331*3eb3c573Smarks 
1332*3eb3c573Smarks 		if (!(acl->state > ace_unused)) {
1333*3eb3c573Smarks 			error = EINVAL;
1334*3eb3c573Smarks 			goto out;
1335*3eb3c573Smarks 		}
1336*3eb3c573Smarks 
1337*3eb3c573Smarks 		if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
1338*3eb3c573Smarks 			/* no more than one allowed per aclent_t */
1339*3eb3c573Smarks 			if (vals->allowed != ACE_MASK_UNDEFINED) {
1340*3eb3c573Smarks 				error = ENOTSUP;
1341*3eb3c573Smarks 				goto out;
1342*3eb3c573Smarks 			}
1343*3eb3c573Smarks 			vals->allowed = acep->a_access_mask;
1344*3eb3c573Smarks 		} else {
1345*3eb3c573Smarks 			/*
1346*3eb3c573Smarks 			 * it's a DENY; if there was a previous DENY, it
1347*3eb3c573Smarks 			 * must have been an ACL_MASK.
1348*3eb3c573Smarks 			 */
1349*3eb3c573Smarks 			if (vals->denied != ACE_MASK_UNDEFINED) {
1350*3eb3c573Smarks 				/* ACL_MASK is for USER and GROUP only */
1351*3eb3c573Smarks 				if ((acl->state != ace_user) &&
1352*3eb3c573Smarks 				    (acl->state != ace_group)) {
1353*3eb3c573Smarks 					error = ENOTSUP;
1354*3eb3c573Smarks 					goto out;
1355*3eb3c573Smarks 				}
1356*3eb3c573Smarks 
1357*3eb3c573Smarks 				if (! acl->hasmask) {
1358*3eb3c573Smarks 					acl->hasmask = 1;
1359*3eb3c573Smarks 					acl->acl_mask = vals->denied;
1360*3eb3c573Smarks 				/* check for mismatched ACL_MASK emulations */
1361*3eb3c573Smarks 				} else if (acl->acl_mask != vals->denied) {
1362*3eb3c573Smarks 					error = ENOTSUP;
1363*3eb3c573Smarks 					goto out;
1364*3eb3c573Smarks 				}
1365*3eb3c573Smarks 				vals->mask = vals->denied;
1366*3eb3c573Smarks 			}
1367*3eb3c573Smarks 			vals->denied = acep->a_access_mask;
1368*3eb3c573Smarks 		}
1369*3eb3c573Smarks 	}
1370*3eb3c573Smarks 
1371*3eb3c573Smarks 	/* done collating; produce the aclent_t lists */
1372*3eb3c573Smarks 	if (normacl->state != ace_unused) {
1373*3eb3c573Smarks 		error = ace_list_to_aent(normacl, aclentp, aclcnt,
1374*3eb3c573Smarks 		    owner, group, isdir);
1375*3eb3c573Smarks 		if (error != 0) {
1376*3eb3c573Smarks 			goto out;
1377*3eb3c573Smarks 		}
1378*3eb3c573Smarks 	}
1379*3eb3c573Smarks 	if (dfacl->state != ace_unused) {
1380*3eb3c573Smarks 		error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt,
1381*3eb3c573Smarks 		    owner, group, isdir);
1382*3eb3c573Smarks 		if (error != 0) {
1383*3eb3c573Smarks 			goto out;
1384*3eb3c573Smarks 		}
1385*3eb3c573Smarks 	}
1386*3eb3c573Smarks 
1387*3eb3c573Smarks out:
1388*3eb3c573Smarks 	if (normacl != NULL)
1389*3eb3c573Smarks 		ace_list_free(normacl);
1390*3eb3c573Smarks 	if (dfacl != NULL)
1391*3eb3c573Smarks 		ace_list_free(dfacl);
1392*3eb3c573Smarks 
1393*3eb3c573Smarks 	return (error);
1394*3eb3c573Smarks }
1395*3eb3c573Smarks 
1396*3eb3c573Smarks static int
1397*3eb3c573Smarks convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir,
1398*3eb3c573Smarks     uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt)
1399*3eb3c573Smarks {
1400*3eb3c573Smarks 	int error;
1401*3eb3c573Smarks 	aclent_t *aclentp, *dfaclentp;
1402*3eb3c573Smarks 	int aclcnt, dfaclcnt;
1403*3eb3c573Smarks 
1404*3eb3c573Smarks 	error = ln_ace_to_aent(acebufp, acecnt, owner, group,
1405*3eb3c573Smarks 	    &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir);
1406*3eb3c573Smarks 
1407*3eb3c573Smarks 	if (error)
1408*3eb3c573Smarks 		return (error);
1409*3eb3c573Smarks 
1410*3eb3c573Smarks 
1411*3eb3c573Smarks 	if (dfaclcnt != 0) {
1412*3eb3c573Smarks 		/*
1413*3eb3c573Smarks 		 * Slap aclentp and dfaclentp into a single array.
1414*3eb3c573Smarks 		 */
1415*3eb3c573Smarks 		aclentp = realloc(aclentp, (sizeof (aclent_t) * aclcnt) +
1416*3eb3c573Smarks 		    (sizeof (aclent_t) * dfaclcnt));
1417*3eb3c573Smarks 		if (aclentp != NULL) {
1418*3eb3c573Smarks 			(void) memcpy(aclentp + aclcnt,
1419*3eb3c573Smarks 			    dfaclentp, sizeof (aclent_t) * dfaclcnt);
1420*3eb3c573Smarks 		} else {
1421*3eb3c573Smarks 			error = -1;
1422*3eb3c573Smarks 		}
1423*3eb3c573Smarks 	}
1424*3eb3c573Smarks 
1425*3eb3c573Smarks 	if (aclentp) {
1426*3eb3c573Smarks 		*retaclentp = aclentp;
1427*3eb3c573Smarks 		*retaclcnt = aclcnt + dfaclcnt;
1428*3eb3c573Smarks 	}
1429*3eb3c573Smarks 
1430*3eb3c573Smarks 	if (dfaclentp)
1431*3eb3c573Smarks 		free(dfaclentp);
1432*3eb3c573Smarks 
1433*3eb3c573Smarks 	return (error);
1434*3eb3c573Smarks }
1435*3eb3c573Smarks 
1436fa9e4066Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp)
1437fa9e4066Sahrens {
1438fa9e4066Sahrens 	const char *fname;
1439fa9e4066Sahrens 	int fd;
1440fa9e4066Sahrens 	int ace_acl = 0;
1441fa9e4066Sahrens 	int error;
1442fa9e4066Sahrens 	int getcmd, cntcmd;
1443fa9e4066Sahrens 	acl_t *acl_info;
1444fa9e4066Sahrens 	int	save_errno;
1445fa9e4066Sahrens 	int	stat_error;
1446fa9e4066Sahrens 	struct stat64 statbuf;
1447fa9e4066Sahrens 
1448fa9e4066Sahrens 	*aclp = NULL;
1449fa9e4066Sahrens 	if (type == ACL_PATH) {
1450fa9e4066Sahrens 		fname = inp.file;
1451fa9e4066Sahrens 		ace_acl = pathconf(fname, _PC_ACL_ENABLED);
1452fa9e4066Sahrens 	} else {
1453fa9e4066Sahrens 		fd = inp.fd;
1454fa9e4066Sahrens 		ace_acl = fpathconf(fd, _PC_ACL_ENABLED);
1455fa9e4066Sahrens 	}
1456fa9e4066Sahrens 
1457fa9e4066Sahrens 	if (ace_acl == -1)
1458fa9e4066Sahrens 		return (-1);
1459fa9e4066Sahrens 
1460fa9e4066Sahrens 	/*
1461fa9e4066Sahrens 	 * if acl's aren't supported then
1462fa9e4066Sahrens 	 * send it through the old GETACL interface
1463fa9e4066Sahrens 	 */
1464fa9e4066Sahrens 	if (ace_acl == 0) {
1465fa9e4066Sahrens 		ace_acl = _ACL_ACLENT_ENABLED;
1466fa9e4066Sahrens 	}
1467fa9e4066Sahrens 
1468fa9e4066Sahrens 	if (ace_acl & _ACL_ACE_ENABLED) {
1469fa9e4066Sahrens 		cntcmd = ACE_GETACLCNT;
1470fa9e4066Sahrens 		getcmd = ACE_GETACL;
1471fa9e4066Sahrens 		acl_info = acl_alloc(ACE_T);
1472fa9e4066Sahrens 	} else {
1473fa9e4066Sahrens 		cntcmd = GETACLCNT;
1474fa9e4066Sahrens 		getcmd = GETACL;
1475fa9e4066Sahrens 		acl_info = acl_alloc(ACLENT_T);
1476fa9e4066Sahrens 	}
1477fa9e4066Sahrens 
1478fa9e4066Sahrens 	if (acl_info == NULL)
1479fa9e4066Sahrens 		return (-1);
1480fa9e4066Sahrens 
1481fa9e4066Sahrens 	if (type == ACL_PATH) {
1482fa9e4066Sahrens 		acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL);
1483fa9e4066Sahrens 	} else {
1484fa9e4066Sahrens 		acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL);
1485fa9e4066Sahrens 	}
1486fa9e4066Sahrens 
1487fa9e4066Sahrens 	save_errno = errno;
1488fa9e4066Sahrens 	if (acl_info->acl_cnt < 0) {
1489fa9e4066Sahrens 		acl_free(acl_info);
1490fa9e4066Sahrens 		errno = save_errno;
1491fa9e4066Sahrens 		return (-1);
1492fa9e4066Sahrens 	}
1493fa9e4066Sahrens 
1494fa9e4066Sahrens 	if (acl_info->acl_cnt == 0) {
1495fa9e4066Sahrens 		acl_free(acl_info);
1496fa9e4066Sahrens 		errno = save_errno;
1497fa9e4066Sahrens 		return (0);
1498fa9e4066Sahrens 	}
1499fa9e4066Sahrens 
1500fa9e4066Sahrens 	acl_info->acl_aclp =
1501fa9e4066Sahrens 	    malloc(acl_info->acl_cnt * acl_info->acl_entry_size);
1502fa9e4066Sahrens 	save_errno = errno;
1503fa9e4066Sahrens 
1504fa9e4066Sahrens 	if (acl_info->acl_aclp == NULL) {
1505fa9e4066Sahrens 		acl_free(acl_info);
1506fa9e4066Sahrens 		errno = save_errno;
1507fa9e4066Sahrens 		return (-1);
1508fa9e4066Sahrens 	}
1509fa9e4066Sahrens 
1510fa9e4066Sahrens 	if (type == ACL_PATH) {
1511fa9e4066Sahrens 		stat_error = stat64(fname, &statbuf);
1512fa9e4066Sahrens 		error = acl(fname, getcmd, acl_info->acl_cnt,
1513fa9e4066Sahrens 		    acl_info->acl_aclp);
1514fa9e4066Sahrens 	} else {
1515fa9e4066Sahrens 		stat_error = fstat64(fd, &statbuf);
1516fa9e4066Sahrens 		error = facl(fd, getcmd, acl_info->acl_cnt,
1517fa9e4066Sahrens 		    acl_info->acl_aclp);
1518fa9e4066Sahrens 	}
1519fa9e4066Sahrens 
1520fa9e4066Sahrens 	save_errno = errno;
1521fa9e4066Sahrens 	if (error == -1) {
1522fa9e4066Sahrens 		acl_free(acl_info);
1523fa9e4066Sahrens 		errno = save_errno;
1524fa9e4066Sahrens 		return (-1);
1525fa9e4066Sahrens 	}
1526fa9e4066Sahrens 
1527fa9e4066Sahrens 
1528fa9e4066Sahrens 	if (stat_error == 0) {
1529fa9e4066Sahrens 		acl_info->acl_flags =
1530fa9e4066Sahrens 		    (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0);
1531fa9e4066Sahrens 	} else
1532fa9e4066Sahrens 		acl_info->acl_flags = 0;
1533fa9e4066Sahrens 
1534fa9e4066Sahrens 	switch (acl_info->acl_type) {
1535fa9e4066Sahrens 	case ACLENT_T:
1536fa9e4066Sahrens 		if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
1537fa9e4066Sahrens 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
1538fa9e4066Sahrens 		break;
1539fa9e4066Sahrens 	case ACE_T:
1540fa9e4066Sahrens 		if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
1541fa9e4066Sahrens 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
1542fa9e4066Sahrens 		break;
1543fa9e4066Sahrens 	default:
1544fa9e4066Sahrens 		errno = EINVAL;
1545fa9e4066Sahrens 		acl_free(acl_info);
1546fa9e4066Sahrens 		return (-1);
1547fa9e4066Sahrens 	}
1548fa9e4066Sahrens 
1549fa9e4066Sahrens 	if ((acl_info->acl_flags & ACL_IS_TRIVIAL) &&
1550fa9e4066Sahrens 	    (get_flag & ACL_NO_TRIVIAL)) {
1551fa9e4066Sahrens 		acl_free(acl_info);
1552fa9e4066Sahrens 		errno = 0;
1553fa9e4066Sahrens 		return (0);
1554fa9e4066Sahrens 	}
1555fa9e4066Sahrens 
1556fa9e4066Sahrens 	*aclp = acl_info;
1557fa9e4066Sahrens 	return (0);
1558fa9e4066Sahrens }
1559fa9e4066Sahrens 
1560fa9e4066Sahrens /*
1561fa9e4066Sahrens  * return -1 on failure, otherwise the number of acl
1562fa9e4066Sahrens  * entries is returned
1563fa9e4066Sahrens  */
1564fa9e4066Sahrens int
1565fa9e4066Sahrens acl_get(const char *path, int get_flag, acl_t **aclp)
1566fa9e4066Sahrens {
1567fa9e4066Sahrens 	acl_inp acl_inp;
1568fa9e4066Sahrens 	acl_inp.file = path;
1569fa9e4066Sahrens 
1570fa9e4066Sahrens 	return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp));
1571fa9e4066Sahrens }
1572fa9e4066Sahrens 
1573fa9e4066Sahrens int
1574fa9e4066Sahrens facl_get(int fd, int get_flag, acl_t **aclp)
1575fa9e4066Sahrens {
1576fa9e4066Sahrens 
1577fa9e4066Sahrens 	acl_inp acl_inp;
1578fa9e4066Sahrens 	acl_inp.fd = fd;
1579fa9e4066Sahrens 
1580fa9e4066Sahrens 	return (cacl_get(acl_inp, get_flag, ACL_FD, aclp));
1581fa9e4066Sahrens }
1582fa9e4066Sahrens 
1583*3eb3c573Smarks static int
1584*3eb3c573Smarks acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner,
1585*3eb3c573Smarks     gid_t group)
1586*3eb3c573Smarks {
1587*3eb3c573Smarks 	int aclcnt;
1588*3eb3c573Smarks 	void *acldata;
1589*3eb3c573Smarks 	int error;
1590*3eb3c573Smarks 
1591*3eb3c573Smarks 	/*
1592*3eb3c573Smarks 	 * See if we need to translate
1593*3eb3c573Smarks 	 */
1594*3eb3c573Smarks 	if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) ||
1595*3eb3c573Smarks 	    (target_flavor == _ACL_ACLENT_ENABLED &&
1596*3eb3c573Smarks 	    aclp->acl_type == ACLENT_T))
1597*3eb3c573Smarks 		return (0);
1598*3eb3c573Smarks 
1599*3eb3c573Smarks 	if (target_flavor == -1)
1600*3eb3c573Smarks 		return (-1);
1601*3eb3c573Smarks 
1602*3eb3c573Smarks 	if (target_flavor ==  _ACL_ACE_ENABLED &&
1603*3eb3c573Smarks 	    aclp->acl_type == ACLENT_T) {
1604*3eb3c573Smarks 		error = convert_aent_to_ace(aclp->acl_aclp,
1605*3eb3c573Smarks 		    aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt);
1606*3eb3c573Smarks 		if (error) {
1607*3eb3c573Smarks 			errno = error;
1608*3eb3c573Smarks 			return (-1);
1609*3eb3c573Smarks 		}
1610*3eb3c573Smarks 	} else if (target_flavor == _ACL_ACLENT_ENABLED &&
1611*3eb3c573Smarks 	    aclp->acl_type == ACE_T) {
1612*3eb3c573Smarks 		error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt,
1613*3eb3c573Smarks 		    isdir, owner, group, (aclent_t **)&acldata, &aclcnt);
1614*3eb3c573Smarks 		if (error) {
1615*3eb3c573Smarks 			errno = error;
1616*3eb3c573Smarks 			return (-1);
1617*3eb3c573Smarks 		}
1618*3eb3c573Smarks 	} else {
1619*3eb3c573Smarks 		errno = ENOTSUP;
1620*3eb3c573Smarks 		return (-1);
1621*3eb3c573Smarks 	}
1622*3eb3c573Smarks 
1623*3eb3c573Smarks 	/*
1624*3eb3c573Smarks 	 * replace old acl with newly translated acl
1625*3eb3c573Smarks 	 */
1626*3eb3c573Smarks 	free(aclp->acl_aclp);
1627*3eb3c573Smarks 	aclp->acl_aclp = acldata;
1628*3eb3c573Smarks 	aclp->acl_cnt = aclcnt;
1629*3eb3c573Smarks 	aclp->acl_type = (target_flavor == _ACL_ACE_ENABLED) ? ACE_T : ACLENT_T;
1630*3eb3c573Smarks 	return (0);
1631*3eb3c573Smarks }
1632*3eb3c573Smarks 
1633fa9e4066Sahrens /*
1634fa9e4066Sahrens  * Set an ACL, translates acl to ace_t when appropriate.
1635fa9e4066Sahrens  */
1636fa9e4066Sahrens static int
1637fa9e4066Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type)
1638fa9e4066Sahrens {
1639fa9e4066Sahrens 	int error = 0;
1640fa9e4066Sahrens 	int acl_flavor_target;
1641fa9e4066Sahrens 	struct stat64 statbuf;
1642fa9e4066Sahrens 	int stat_error;
1643fa9e4066Sahrens 	int isdir;
1644fa9e4066Sahrens 
1645fa9e4066Sahrens 
1646fa9e4066Sahrens 	if (type == ACL_PATH) {
1647fa9e4066Sahrens 		stat_error = stat64(acl_inp->file, &statbuf);
1648fa9e4066Sahrens 		if (stat_error)
1649fa9e4066Sahrens 			return (-1);
1650fa9e4066Sahrens 		acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED);
1651fa9e4066Sahrens 	} else {
1652fa9e4066Sahrens 		stat_error = fstat64(acl_inp->fd, &statbuf);
1653fa9e4066Sahrens 		if (stat_error)
1654fa9e4066Sahrens 			return (-1);
1655fa9e4066Sahrens 		acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED);
1656fa9e4066Sahrens 	}
1657fa9e4066Sahrens 
1658fa9e4066Sahrens 	isdir = S_ISDIR(statbuf.st_mode);
1659fa9e4066Sahrens 
1660*3eb3c573Smarks 	if ((error = acl_translate(aclp, acl_flavor_target, isdir,
1661*3eb3c573Smarks 	    statbuf.st_uid, statbuf.st_gid)) != 0) {
1662*3eb3c573Smarks 		return (error);
1663fa9e4066Sahrens 	}
1664fa9e4066Sahrens 
1665fa9e4066Sahrens 	if (type == ACL_PATH) {
1666fa9e4066Sahrens 		error = acl(acl_inp->file,
1667fa9e4066Sahrens 		    (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL,
1668fa9e4066Sahrens 		    aclp->acl_cnt, aclp->acl_aclp);
1669fa9e4066Sahrens 	} else {
1670fa9e4066Sahrens 		error = facl(acl_inp->fd,
1671fa9e4066Sahrens 		    (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL,
1672fa9e4066Sahrens 		    aclp->acl_cnt, aclp->acl_aclp);
1673fa9e4066Sahrens 	}
1674fa9e4066Sahrens 
1675fa9e4066Sahrens 	return (error);
1676fa9e4066Sahrens }
1677fa9e4066Sahrens 
1678fa9e4066Sahrens int
1679fa9e4066Sahrens acl_set(const char *path, acl_t *aclp)
1680fa9e4066Sahrens {
1681fa9e4066Sahrens 	acl_inp acl_inp;
1682fa9e4066Sahrens 
1683fa9e4066Sahrens 	acl_inp.file = path;
1684fa9e4066Sahrens 
1685fa9e4066Sahrens 	return (cacl_set(&acl_inp, aclp, ACL_PATH));
1686fa9e4066Sahrens }
1687fa9e4066Sahrens 
1688fa9e4066Sahrens int
1689fa9e4066Sahrens facl_set(int fd, acl_t *aclp)
1690fa9e4066Sahrens {
1691fa9e4066Sahrens 	acl_inp acl_inp;
1692fa9e4066Sahrens 
1693fa9e4066Sahrens 	acl_inp.fd = fd;
1694fa9e4066Sahrens 
1695fa9e4066Sahrens 	return (cacl_set(&acl_inp, aclp, ACL_FD));
1696fa9e4066Sahrens }
1697fa9e4066Sahrens 
1698fa9e4066Sahrens int
1699fa9e4066Sahrens acl_cnt(acl_t *aclp)
1700fa9e4066Sahrens {
1701fa9e4066Sahrens 	return (aclp->acl_cnt);
1702fa9e4066Sahrens }
1703fa9e4066Sahrens 
1704fa9e4066Sahrens int
1705fa9e4066Sahrens acl_type(acl_t *aclp)
1706fa9e4066Sahrens {
1707fa9e4066Sahrens 	return (aclp->acl_type);
1708fa9e4066Sahrens }
1709fa9e4066Sahrens 
1710fa9e4066Sahrens acl_t *
1711fa9e4066Sahrens acl_dup(acl_t *aclp)
1712fa9e4066Sahrens {
1713fa9e4066Sahrens 	acl_t *newaclp;
1714fa9e4066Sahrens 
1715fa9e4066Sahrens 	newaclp = acl_alloc(aclp->acl_type);
1716fa9e4066Sahrens 	if (newaclp == NULL)
1717fa9e4066Sahrens 		return (NULL);
1718fa9e4066Sahrens 
1719fa9e4066Sahrens 	newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt);
1720fa9e4066Sahrens 	if (newaclp->acl_aclp == NULL) {
1721fa9e4066Sahrens 		acl_free(newaclp);
1722fa9e4066Sahrens 		return (NULL);
1723fa9e4066Sahrens 	}
1724fa9e4066Sahrens 
1725fa9e4066Sahrens 	(void) memcpy(newaclp->acl_aclp,
1726fa9e4066Sahrens 	    aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt);
1727fa9e4066Sahrens 	newaclp->acl_cnt = aclp->acl_cnt;
1728fa9e4066Sahrens 
1729fa9e4066Sahrens 	return (newaclp);
1730fa9e4066Sahrens }
1731fa9e4066Sahrens 
1732fa9e4066Sahrens int
1733fa9e4066Sahrens acl_flags(acl_t *aclp)
1734fa9e4066Sahrens {
1735fa9e4066Sahrens 	return (aclp->acl_flags);
1736fa9e4066Sahrens }
1737fa9e4066Sahrens 
1738fa9e4066Sahrens void *
1739fa9e4066Sahrens acl_data(acl_t *aclp)
1740fa9e4066Sahrens {
1741fa9e4066Sahrens 	return (aclp->acl_aclp);
1742fa9e4066Sahrens }
1743fa9e4066Sahrens 
1744fa9e4066Sahrens /*
1745fa9e4066Sahrens  * Remove an ACL from a file and create a trivial ACL based
1746fa9e4066Sahrens  * off of the mode argument.  After acl has been set owner/group
1747fa9e4066Sahrens  * are updated to match owner,group arguments
1748fa9e4066Sahrens  */
1749fa9e4066Sahrens int
1750fa9e4066Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode)
1751fa9e4066Sahrens {
1752fa9e4066Sahrens 	int	error = 0;
1753fa9e4066Sahrens 	aclent_t min_acl[MIN_ACL_ENTRIES];
1754fa9e4066Sahrens 	ace_t	min_ace_acl[6];	/* owner, group, everyone + complement denies */
1755fa9e4066Sahrens 	int	acl_flavor;
1756fa9e4066Sahrens 	int	aclcnt;
1757fa9e4066Sahrens 
1758fa9e4066Sahrens 	acl_flavor = pathconf(file, _PC_ACL_ENABLED);
1759fa9e4066Sahrens 
1760fa9e4066Sahrens 	if (acl_flavor == -1)
1761fa9e4066Sahrens 		return (-1);
1762fa9e4066Sahrens 	/*
1763fa9e4066Sahrens 	 * force it through aclent flavor when file system doesn't
1764fa9e4066Sahrens 	 * understand question
1765fa9e4066Sahrens 	 */
1766fa9e4066Sahrens 	if (acl_flavor == 0)
1767fa9e4066Sahrens 		acl_flavor = _ACL_ACLENT_ENABLED;
1768fa9e4066Sahrens 
1769fa9e4066Sahrens 	if (acl_flavor & _ACL_ACLENT_ENABLED) {
1770fa9e4066Sahrens 		min_acl[0].a_type = USER_OBJ;
1771fa9e4066Sahrens 		min_acl[0].a_id   = owner;
1772fa9e4066Sahrens 		min_acl[0].a_perm = ((mode & 0700) >> 6);
1773fa9e4066Sahrens 		min_acl[1].a_type = GROUP_OBJ;
1774fa9e4066Sahrens 		min_acl[1].a_id   = group;
1775fa9e4066Sahrens 		min_acl[1].a_perm = ((mode & 0070) >> 3);
1776fa9e4066Sahrens 		min_acl[2].a_type = CLASS_OBJ;
1777fa9e4066Sahrens 		min_acl[2].a_id   = (uid_t)-1;
1778fa9e4066Sahrens 		min_acl[2].a_perm = ((mode & 0070) >> 3);
1779fa9e4066Sahrens 		min_acl[3].a_type = OTHER_OBJ;
1780fa9e4066Sahrens 		min_acl[3].a_id   = (uid_t)-1;
1781fa9e4066Sahrens 		min_acl[3].a_perm = (mode & 0007);
1782fa9e4066Sahrens 		aclcnt = 4;
1783fa9e4066Sahrens 		error = acl(file, SETACL, aclcnt, min_acl);
1784fa9e4066Sahrens 	} else if (acl_flavor & _ACL_ACE_ENABLED) {
1785fa9e4066Sahrens 		(void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6);
1786fa9e4066Sahrens 
1787fa9e4066Sahrens 		/*
1788fa9e4066Sahrens 		 * Make aces match request mode
1789fa9e4066Sahrens 		 */
1790fa9e4066Sahrens 		adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6);
1791fa9e4066Sahrens 		adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3);
1792fa9e4066Sahrens 		adjust_ace_pair(&min_ace_acl[4], mode & 0007);
1793fa9e4066Sahrens 
1794fa9e4066Sahrens 		error = acl(file, ACE_SETACL, 6, min_ace_acl);
1795fa9e4066Sahrens 	} else {
1796fa9e4066Sahrens 		errno = EINVAL;
1797fa9e4066Sahrens 		error = 1;
1798fa9e4066Sahrens 	}
1799fa9e4066Sahrens 
1800fa9e4066Sahrens 	if (error == 0)
1801fa9e4066Sahrens 		error = chown(file, owner, group);
1802fa9e4066Sahrens 	return (error);
1803fa9e4066Sahrens }
1804fa9e4066Sahrens 
1805fa9e4066Sahrens static int
1806fa9e4066Sahrens ace_match(void *entry1, void *entry2)
1807fa9e4066Sahrens {
1808fa9e4066Sahrens 	ace_t *p1 = (ace_t *)entry1;
1809fa9e4066Sahrens 	ace_t *p2 = (ace_t *)entry2;
1810fa9e4066Sahrens 	ace_t ace1, ace2;
1811fa9e4066Sahrens 
1812fa9e4066Sahrens 	ace1 = *p1;
1813fa9e4066Sahrens 	ace2 = *p2;
1814fa9e4066Sahrens 
1815fa9e4066Sahrens 	/*
1816fa9e4066Sahrens 	 * Need to fixup who field for abstrations for
1817fa9e4066Sahrens 	 * accurate comparison, since field is undefined.
1818fa9e4066Sahrens 	 */
1819fa9e4066Sahrens 	if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
1820fa9e4066Sahrens 		ace1.a_who = -1;
1821fa9e4066Sahrens 	if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
1822fa9e4066Sahrens 		ace2.a_who = -1;
1823fa9e4066Sahrens 	return (memcmp(&ace1, &ace2, sizeof (ace_t)));
1824fa9e4066Sahrens }
1825fa9e4066Sahrens 
1826fa9e4066Sahrens static int
1827fa9e4066Sahrens aclent_match(void *entry1, void *entry2)
1828fa9e4066Sahrens {
1829fa9e4066Sahrens 	aclent_t *aclent1 = (aclent_t *)entry1;
1830fa9e4066Sahrens 	aclent_t *aclent2 = (aclent_t *)entry2;
1831fa9e4066Sahrens 
1832fa9e4066Sahrens 	return (memcmp(aclent1, aclent2, sizeof (aclent_t)));
1833fa9e4066Sahrens }
1834fa9e4066Sahrens 
1835fa9e4066Sahrens /*
1836fa9e4066Sahrens  * Find acl entries in acl that correspond to removeacl.  Search
1837fa9e4066Sahrens  * is started from slot.  The flag argument indicates whether to
1838fa9e4066Sahrens  * remove all matches or just the first match.
1839fa9e4066Sahrens  */
1840fa9e4066Sahrens int
1841fa9e4066Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag)
1842fa9e4066Sahrens {
1843fa9e4066Sahrens 	int i, j;
1844fa9e4066Sahrens 	int match;
1845fa9e4066Sahrens 	int (*acl_match)(void *acl1, void *acl2);
1846fa9e4066Sahrens 	void *acl_entry, *remove_entry;
1847fa9e4066Sahrens 	void *start;
1848fa9e4066Sahrens 	int found = 0;
1849fa9e4066Sahrens 
1850fa9e4066Sahrens 	if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST)
1851fa9e4066Sahrens 		flag = ACL_REMOVE_FIRST;
1852fa9e4066Sahrens 
1853fa9e4066Sahrens 	if (acl == NULL || removeacl == NULL)
1854fa9e4066Sahrens 		return (EACL_NO_ACL_ENTRY);
1855fa9e4066Sahrens 
1856fa9e4066Sahrens 	if (acl->acl_type != removeacl->acl_type)
1857fa9e4066Sahrens 		return (EACL_DIFF_TYPE);
1858fa9e4066Sahrens 
1859fa9e4066Sahrens 	if (acl->acl_type == ACLENT_T)
1860fa9e4066Sahrens 		acl_match = aclent_match;
1861fa9e4066Sahrens 	else
1862fa9e4066Sahrens 		acl_match = ace_match;
1863fa9e4066Sahrens 
1864fa9e4066Sahrens 	for (i = 0, remove_entry = removeacl->acl_aclp;
1865fa9e4066Sahrens 	    i != removeacl->acl_cnt; i++) {
1866fa9e4066Sahrens 
1867fa9e4066Sahrens 		j = 0;
1868fa9e4066Sahrens 		acl_entry = (char *)acl->acl_aclp +
1869fa9e4066Sahrens 		    (acl->acl_entry_size * start_slot);
1870fa9e4066Sahrens 		for (;;) {
1871fa9e4066Sahrens 			match = acl_match(acl_entry, remove_entry);
1872fa9e4066Sahrens 			if (match == 0)  {
1873fa9e4066Sahrens 				found++;
1874fa9e4066Sahrens 				start = (char *)acl_entry +
1875fa9e4066Sahrens 				    acl->acl_entry_size;
1876fa9e4066Sahrens 				(void) memmove(acl_entry, start,
1877fa9e4066Sahrens 				    acl->acl_entry_size *
1878fa9e4066Sahrens 				    acl->acl_cnt-- - (j + 1));
1879fa9e4066Sahrens 
1880fa9e4066Sahrens 				if (flag == ACL_REMOVE_FIRST)
1881fa9e4066Sahrens 					break;
1882fa9e4066Sahrens 				/*
1883fa9e4066Sahrens 				 * List has changed, restart search from
1884fa9e4066Sahrens 				 * beginning.
1885fa9e4066Sahrens 				 */
1886fa9e4066Sahrens 				acl_entry = acl->acl_aclp;
1887fa9e4066Sahrens 				j = 0;
1888fa9e4066Sahrens 				continue;
1889fa9e4066Sahrens 			}
1890fa9e4066Sahrens 			acl_entry = ((char *)acl_entry + acl->acl_entry_size);
1891fa9e4066Sahrens 			if (++j >= acl->acl_cnt) {
1892fa9e4066Sahrens 				break;
1893fa9e4066Sahrens 			}
1894fa9e4066Sahrens 		}
1895fa9e4066Sahrens 	}
1896fa9e4066Sahrens 
1897fa9e4066Sahrens 	return ((found == 0) ? EACL_NO_ACL_ENTRY : 0);
1898fa9e4066Sahrens }
1899fa9e4066Sahrens 
1900fa9e4066Sahrens /*
1901fa9e4066Sahrens  * Replace entires entries in acl1 with the corresponding entries
1902fa9e4066Sahrens  * in newentries.  The where argument specifies where to begin
1903fa9e4066Sahrens  * the replacement.  If the where argument is 1 greater than the
1904fa9e4066Sahrens  * number of acl entries in acl1 then they are appended.  If the
1905fa9e4066Sahrens  * where argument is 2+ greater than the number of acl entries then
1906fa9e4066Sahrens  * EACL_INVALID_SLOT is returned.
1907fa9e4066Sahrens  */
1908fa9e4066Sahrens int
1909fa9e4066Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where)
1910fa9e4066Sahrens {
1911fa9e4066Sahrens 
1912fa9e4066Sahrens 	int slot;
1913fa9e4066Sahrens 	int slots_needed;
1914fa9e4066Sahrens 	int slots_left;
1915fa9e4066Sahrens 	int newsize;
1916fa9e4066Sahrens 
1917fa9e4066Sahrens 	if (acl1 == NULL || newentries == NULL)
1918fa9e4066Sahrens 		return (EACL_NO_ACL_ENTRY);
1919fa9e4066Sahrens 
1920fa9e4066Sahrens 	if (where < 0 || where >= acl1->acl_cnt)
1921fa9e4066Sahrens 		return (EACL_INVALID_SLOT);
1922fa9e4066Sahrens 
1923fa9e4066Sahrens 	if (acl1->acl_type != newentries->acl_type)
1924fa9e4066Sahrens 		return (EACL_DIFF_TYPE);
1925fa9e4066Sahrens 
1926fa9e4066Sahrens 	slot = where;
1927fa9e4066Sahrens 
1928fa9e4066Sahrens 	slots_left = acl1->acl_cnt - slot + 1;
1929fa9e4066Sahrens 	if (slots_left < newentries->acl_cnt) {
1930fa9e4066Sahrens 		slots_needed = newentries->acl_cnt - slots_left;
1931fa9e4066Sahrens 		newsize = (acl1->acl_entry_size * acl1->acl_cnt) +
1932fa9e4066Sahrens 		    (acl1->acl_entry_size * slots_needed);
1933fa9e4066Sahrens 		acl1->acl_aclp = realloc(acl1->acl_aclp, newsize);
1934fa9e4066Sahrens 		if (acl1->acl_aclp == NULL)
1935fa9e4066Sahrens 			return (-1);
1936fa9e4066Sahrens 	}
1937fa9e4066Sahrens 	(void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot),
1938fa9e4066Sahrens 	    newentries->acl_aclp,
1939fa9e4066Sahrens 	    newentries->acl_entry_size * newentries->acl_cnt);
1940fa9e4066Sahrens 
1941fa9e4066Sahrens 	/*
1942fa9e4066Sahrens 	 * Did ACL grow?
1943fa9e4066Sahrens 	 */
1944fa9e4066Sahrens 
1945fa9e4066Sahrens 	if ((slot + newentries->acl_cnt) > acl1->acl_cnt) {
1946fa9e4066Sahrens 		acl1->acl_cnt = slot + newentries->acl_cnt;
1947fa9e4066Sahrens 	}
1948fa9e4066Sahrens 
1949fa9e4066Sahrens 	return (0);
1950fa9e4066Sahrens }
1951fa9e4066Sahrens 
1952fa9e4066Sahrens /*
1953fa9e4066Sahrens  * Add acl2 entries into acl1.  The where argument specifies where
1954fa9e4066Sahrens  * to add the entries.
1955fa9e4066Sahrens  */
1956fa9e4066Sahrens int
1957fa9e4066Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where)
1958fa9e4066Sahrens {
1959fa9e4066Sahrens 
1960fa9e4066Sahrens 	int newsize;
1961fa9e4066Sahrens 	int len;
1962fa9e4066Sahrens 	void *start;
1963fa9e4066Sahrens 	void *to;
1964fa9e4066Sahrens 
1965fa9e4066Sahrens 	if (acl1 == NULL || acl2 == NULL)
1966fa9e4066Sahrens 		return (EACL_NO_ACL_ENTRY);
1967fa9e4066Sahrens 
1968fa9e4066Sahrens 	if (acl1->acl_type != acl2->acl_type)
1969fa9e4066Sahrens 		return (EACL_DIFF_TYPE);
1970fa9e4066Sahrens 
1971fa9e4066Sahrens 	/*
1972fa9e4066Sahrens 	 * allow where to specify 1 past last slot for an append operation
1973fa9e4066Sahrens 	 * but anything greater is an error.
1974fa9e4066Sahrens 	 */
1975fa9e4066Sahrens 	if (where < 0 || where > acl1->acl_cnt)
1976fa9e4066Sahrens 		return (EACL_INVALID_SLOT);
1977fa9e4066Sahrens 
1978fa9e4066Sahrens 	newsize = (acl2->acl_entry_size * acl2->acl_cnt) +
1979fa9e4066Sahrens 	    (acl1->acl_entry_size * acl1->acl_cnt);
1980fa9e4066Sahrens 	acl1->acl_aclp = realloc(acl1->acl_aclp, newsize);
1981fa9e4066Sahrens 	if (acl1->acl_aclp == NULL)
1982fa9e4066Sahrens 		return (-1);
1983fa9e4066Sahrens 
1984fa9e4066Sahrens 	/*
1985fa9e4066Sahrens 	 * first push down entries where new ones will be inserted
1986fa9e4066Sahrens 	 */
1987fa9e4066Sahrens 
1988fa9e4066Sahrens 	to = (void *)((char *)acl1->acl_aclp +
1989fa9e4066Sahrens 	    ((where + acl2->acl_cnt) * acl1->acl_entry_size));
1990fa9e4066Sahrens 
1991fa9e4066Sahrens 	start = (void *)((char *)acl1->acl_aclp +
1992fa9e4066Sahrens 	    where * acl1->acl_entry_size);
1993fa9e4066Sahrens 
1994fa9e4066Sahrens 	if (where < acl1->acl_cnt) {
1995fa9e4066Sahrens 		len = (acl1->acl_cnt - where) * acl1->acl_entry_size;
1996fa9e4066Sahrens 		(void) memmove(to, start, len);
1997fa9e4066Sahrens 	}
1998fa9e4066Sahrens 
1999fa9e4066Sahrens 	/*
2000fa9e4066Sahrens 	 * now stick in new entries.
2001fa9e4066Sahrens 	 */
2002fa9e4066Sahrens 
2003fa9e4066Sahrens 	(void) memmove(start, acl2->acl_aclp,
2004fa9e4066Sahrens 	    acl2->acl_cnt * acl2->acl_entry_size);
2005fa9e4066Sahrens 
2006fa9e4066Sahrens 	acl1->acl_cnt += acl2->acl_cnt;
2007fa9e4066Sahrens 	return (0);
2008fa9e4066Sahrens }
2009fa9e4066Sahrens 
2010fa9e4066Sahrens /*
2011fa9e4066Sahrens  * return text for an ACL error.
2012fa9e4066Sahrens  */
2013fa9e4066Sahrens char *
2014fa9e4066Sahrens acl_strerror(int errnum)
2015fa9e4066Sahrens {
2016fa9e4066Sahrens 	switch (errnum) {
2017fa9e4066Sahrens 	case EACL_GRP_ERROR:
2018fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
20195a5eeccaSmarks 		    "There is more than one group or default group entry"));
2020fa9e4066Sahrens 	case EACL_USER_ERROR:
2021fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
20225a5eeccaSmarks 		    "There is more than one user or default user entry"));
2023fa9e4066Sahrens 	case EACL_OTHER_ERROR:
2024fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2025fa9e4066Sahrens 		    "There is more than one other entry"));
2026fa9e4066Sahrens 	case EACL_CLASS_ERROR:
2027fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2028fa9e4066Sahrens 		    "There is more than one mask entry"));
2029fa9e4066Sahrens 	case EACL_DUPLICATE_ERROR:
2030fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2031fa9e4066Sahrens 		    "Duplicate user or group entries"));
2032fa9e4066Sahrens 	case EACL_MISS_ERROR:
2033fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2034fa9e4066Sahrens 		    "Missing user/group owner, other, mask entry"));
2035fa9e4066Sahrens 	case EACL_MEM_ERROR:
2036fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2037fa9e4066Sahrens 		    "Memory error"));
2038fa9e4066Sahrens 	case EACL_ENTRY_ERROR:
2039fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2040fa9e4066Sahrens 		    "Unrecognized entry type"));
2041fa9e4066Sahrens 	case EACL_INHERIT_ERROR:
2042fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2043fa9e4066Sahrens 		    "Invalid inheritance flags"));
2044fa9e4066Sahrens 	case EACL_FLAGS_ERROR:
2045fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2046fa9e4066Sahrens 		    "Unrecognized entry flags"));
2047fa9e4066Sahrens 	case EACL_PERM_MASK_ERROR:
2048fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2049fa9e4066Sahrens 		    "Invalid ACL permissions"));
2050fa9e4066Sahrens 	case EACL_COUNT_ERROR:
2051fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2052fa9e4066Sahrens 		    "Invalid ACL count"));
2053fa9e4066Sahrens 	case EACL_INVALID_SLOT:
2054fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2055fa9e4066Sahrens 		    "Invalid ACL entry number specified"));
2056fa9e4066Sahrens 	case EACL_NO_ACL_ENTRY:
2057fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2058fa9e4066Sahrens 		    "ACL entry doesn't exist"));
2059fa9e4066Sahrens 	case EACL_DIFF_TYPE:
2060fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2061fa9e4066Sahrens 		    "ACL type's are different"));
2062fa9e4066Sahrens 	case EACL_INVALID_USER_GROUP:
2063fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Invalid user or group"));
2064fa9e4066Sahrens 	case EACL_INVALID_STR:
2065fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "ACL string is invalid"));
2066fa9e4066Sahrens 	case EACL_FIELD_NOT_BLANK:
2067fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Field expected to be blank"));
2068fa9e4066Sahrens 	case EACL_INVALID_ACCESS_TYPE:
2069fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Invalid access type"));
2070fa9e4066Sahrens 	case EACL_UNKNOWN_DATA:
2071fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Unrecognized entry"));
2072fa9e4066Sahrens 	case EACL_MISSING_FIELDS:
2073fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2074fa9e4066Sahrens 		    "ACL specification missing required fields"));
2075fa9e4066Sahrens 	case EACL_INHERIT_NOTDIR:
2076fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2077fa9e4066Sahrens 		    "Inheritance flags are only allowed on directories"));
2078fa9e4066Sahrens 	case -1:
2079fa9e4066Sahrens 		return (strerror(errno));
2080fa9e4066Sahrens 	default:
2081fa9e4066Sahrens 		errno = EINVAL;
2082fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Unknown error"));
2083fa9e4066Sahrens 	}
2084fa9e4066Sahrens }
20855a5eeccaSmarks 
20865a5eeccaSmarks extern int yyinteractive;
20875a5eeccaSmarks 
20885a5eeccaSmarks /* PRINTFLIKE1 */
20895a5eeccaSmarks void
20905a5eeccaSmarks acl_error(const char *fmt, ...)
20915a5eeccaSmarks {
20925a5eeccaSmarks 	va_list va;
20935a5eeccaSmarks 
20945a5eeccaSmarks 	if (yyinteractive == 0)
20955a5eeccaSmarks 		return;
20965a5eeccaSmarks 
20975a5eeccaSmarks 	va_start(va, fmt);
20985a5eeccaSmarks 	(void) vfprintf(stderr, fmt, va);
20995a5eeccaSmarks 	va_end(va);
21005a5eeccaSmarks }
2101