xref: /titanic_50/usr/src/lib/libsec/common/aclutils.c (revision a222db82aa8aaee84f3cba02cf799fe851fa7ac3)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
53eb3c573Smarks  * Common Development and Distribution License (the "License").
63eb3c573Smarks  * 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>
343eb3c573Smarks #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>
433eb3c573Smarks #include <sys/avl.h>
443eb3c573Smarks 
453eb3c573Smarks #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
563eb3c573Smarks #define	ACL_SYNCHRONIZE_SET_ALLOW		0x0000002
573eb3c573Smarks #define	ACL_SYNCHRONIZE_ERR_DENY		0x0000004
583eb3c573Smarks #define	ACL_SYNCHRONIZE_ERR_ALLOW		0x0000008
59fa9e4066Sahrens 
60fa9e4066Sahrens #define	ACL_WRITE_OWNER_SET_DENY		0x0000010
613eb3c573Smarks #define	ACL_WRITE_OWNER_SET_ALLOW		0x0000020
623eb3c573Smarks #define	ACL_WRITE_OWNER_ERR_DENY		0x0000040
633eb3c573Smarks #define	ACL_WRITE_OWNER_ERR_ALLOW		0x0000080
64fa9e4066Sahrens 
653eb3c573Smarks #define	ACL_DELETE_SET_DENY			0x0000100
663eb3c573Smarks #define	ACL_DELETE_SET_ALLOW			0x0000200
673eb3c573Smarks #define	ACL_DELETE_ERR_DENY			0x0000400
683eb3c573Smarks #define	ACL_DELETE_ERR_ALLOW			0x0000800
693eb3c573Smarks 
70fa9e4066Sahrens #define	ACL_WRITE_ATTRS_OWNER_SET_DENY		0x0001000
713eb3c573Smarks #define	ACL_WRITE_ATTRS_OWNER_SET_ALLOW		0x0002000
723eb3c573Smarks #define	ACL_WRITE_ATTRS_OWNER_ERR_DENY		0x0004000
733eb3c573Smarks #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
773eb3c573Smarks #define	ACL_WRITE_ATTRS_WRITER_ERR_DENY		0x0040000
783eb3c573Smarks #define	ACL_WRITE_ATTRS_WRITER_ERR_ALLOW	0x0080000
79fa9e4066Sahrens 
803eb3c573Smarks #define	ACL_WRITE_NAMED_WRITER_SET_DENY		0x0100000
813eb3c573Smarks #define	ACL_WRITE_NAMED_WRITER_SET_ALLOW	0x0200000
823eb3c573Smarks #define	ACL_WRITE_NAMED_WRITER_ERR_DENY		0x0400000
833eb3c573Smarks #define	ACL_WRITE_NAMED_WRITER_ERR_ALLOW	0x0800000
843eb3c573Smarks 
85fa9e4066Sahrens #define	ACL_READ_NAMED_READER_SET_DENY		0x1000000
863eb3c573Smarks #define	ACL_READ_NAMED_READER_SET_ALLOW		0x2000000
873eb3c573Smarks #define	ACL_READ_NAMED_READER_ERR_DENY		0x4000000
883eb3c573Smarks #define	ACL_READ_NAMED_READER_ERR_ALLOW		0x8000000
893eb3c573Smarks 
903eb3c573Smarks 
913eb3c573Smarks #define	ACE_VALID_MASK_BITS (\
923eb3c573Smarks     ACE_READ_DATA | \
933eb3c573Smarks     ACE_LIST_DIRECTORY | \
943eb3c573Smarks     ACE_WRITE_DATA | \
953eb3c573Smarks     ACE_ADD_FILE | \
963eb3c573Smarks     ACE_APPEND_DATA | \
973eb3c573Smarks     ACE_ADD_SUBDIRECTORY | \
983eb3c573Smarks     ACE_READ_NAMED_ATTRS | \
993eb3c573Smarks     ACE_WRITE_NAMED_ATTRS | \
1003eb3c573Smarks     ACE_EXECUTE | \
1013eb3c573Smarks     ACE_DELETE_CHILD | \
1023eb3c573Smarks     ACE_READ_ATTRIBUTES | \
1033eb3c573Smarks     ACE_WRITE_ATTRIBUTES | \
1043eb3c573Smarks     ACE_DELETE | \
1053eb3c573Smarks     ACE_READ_ACL | \
1063eb3c573Smarks     ACE_WRITE_ACL | \
1073eb3c573Smarks     ACE_WRITE_OWNER | \
1083eb3c573Smarks     ACE_SYNCHRONIZE)
1093eb3c573Smarks 
1103eb3c573Smarks #define	ACE_MASK_UNDEFINED			0x80000000
1113eb3c573Smarks 
1123eb3c573Smarks #define	ACE_VALID_FLAG_BITS (ACE_FILE_INHERIT_ACE | \
1133eb3c573Smarks     ACE_DIRECTORY_INHERIT_ACE | \
1143eb3c573Smarks     ACE_NO_PROPAGATE_INHERIT_ACE | ACE_INHERIT_ONLY_ACE | \
1153eb3c573Smarks     ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \
1163eb3c573Smarks     ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE)
1173eb3c573Smarks 
1183eb3c573Smarks /*
1193eb3c573Smarks  * ACL conversion helpers
1203eb3c573Smarks  */
1213eb3c573Smarks 
1223eb3c573Smarks typedef enum {
1233eb3c573Smarks 	ace_unused,
1243eb3c573Smarks 	ace_user_obj,
1253eb3c573Smarks 	ace_user,
1263eb3c573Smarks 	ace_group, /* includes GROUP and GROUP_OBJ */
1273eb3c573Smarks 	ace_other_obj
1283eb3c573Smarks } ace_to_aent_state_t;
1293eb3c573Smarks 
1303eb3c573Smarks typedef struct acevals {
1313eb3c573Smarks 	uid_t key;
1323eb3c573Smarks 	avl_node_t avl;
1333eb3c573Smarks 	uint32_t mask;
1343eb3c573Smarks 	uint32_t allowed;
1353eb3c573Smarks 	uint32_t denied;
1363eb3c573Smarks 	int aent_type;
1373eb3c573Smarks } acevals_t;
1383eb3c573Smarks 
1393eb3c573Smarks typedef struct ace_list {
1403eb3c573Smarks 	acevals_t user_obj;
1413eb3c573Smarks 	avl_tree_t user;
1423eb3c573Smarks 	int numusers;
1433eb3c573Smarks 	acevals_t group_obj;
1443eb3c573Smarks 	avl_tree_t group;
1453eb3c573Smarks 	int numgroups;
1463eb3c573Smarks 	acevals_t other_obj;
1473eb3c573Smarks 	uint32_t acl_mask;
1483eb3c573Smarks 	int hasmask;
1493eb3c573Smarks 	int dfacl_flag;
1503eb3c573Smarks 	ace_to_aent_state_t state;
1513eb3c573Smarks 	int seen; /* bitmask of all aclent_t a_type values seen */
1523eb3c573Smarks } 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 
219fa9e4066Sahrens 	if (acl_flavor == _ACL_ACE_ENABLED)
220fa9e4066Sahrens 		cntcmd = ACE_GETACLCNT;
221fa9e4066Sahrens 	else
222fa9e4066Sahrens 		cntcmd = GETACLCNT;
223fa9e4066Sahrens 
224fa9e4066Sahrens 	aclcnt = acl(filename, cntcmd, 0, NULL);
225fa9e4066Sahrens 	if (aclcnt > 0) {
226fa9e4066Sahrens 		if (acl_flavor == _ACL_ACE_ENABLED) {
227fa9e4066Sahrens 			acep = malloc(sizeof (ace_t) * aclcnt);
228fa9e4066Sahrens 			if (acep == NULL)
229fa9e4066Sahrens 				return (-1);
230fa9e4066Sahrens 			if (acl(filename, ACE_GETACL,
231fa9e4066Sahrens 			    aclcnt, acep) < 0) {
232fa9e4066Sahrens 				free(acep);
233fa9e4066Sahrens 				return (-1);
234fa9e4066Sahrens 			}
235fa9e4066Sahrens 
236fa9e4066Sahrens 			val = ace_trivial(acep, aclcnt);
237fa9e4066Sahrens 			free(acep);
238d2443e76Smarks 
239fa9e4066Sahrens 		} else if (aclcnt > MIN_ACL_ENTRIES)
240fa9e4066Sahrens 			val = 1;
241fa9e4066Sahrens 	}
242fa9e4066Sahrens 	return (val);
243fa9e4066Sahrens }
244fa9e4066Sahrens 
245fa9e4066Sahrens static uint32_t
246fa9e4066Sahrens access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow)
247fa9e4066Sahrens {
248fa9e4066Sahrens 	uint32_t access_mask = 0;
249fa9e4066Sahrens 	int acl_produce;
250fa9e4066Sahrens 	int synchronize_set = 0, write_owner_set = 0;
251fa9e4066Sahrens 	int delete_set = 0, write_attrs_set = 0;
252fa9e4066Sahrens 	int read_named_set = 0, write_named_set = 0;
253fa9e4066Sahrens 
254fa9e4066Sahrens 	acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW |
255fa9e4066Sahrens 	    ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
256fa9e4066Sahrens 	    ACL_WRITE_ATTRS_WRITER_SET_DENY);
257fa9e4066Sahrens 
258fa9e4066Sahrens 	if (isallow) {
259fa9e4066Sahrens 		synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW;
260fa9e4066Sahrens 		write_owner_set = ACL_WRITE_OWNER_SET_ALLOW;
261fa9e4066Sahrens 		delete_set = ACL_DELETE_SET_ALLOW;
262fa9e4066Sahrens 		if (hasreadperm)
263fa9e4066Sahrens 			read_named_set = ACL_READ_NAMED_READER_SET_ALLOW;
264fa9e4066Sahrens 		if (haswriteperm)
265fa9e4066Sahrens 			write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
266fa9e4066Sahrens 		if (isowner)
267fa9e4066Sahrens 			write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
268fa9e4066Sahrens 		else if (haswriteperm)
269fa9e4066Sahrens 			write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
270fa9e4066Sahrens 	} else {
271fa9e4066Sahrens 
272fa9e4066Sahrens 		synchronize_set = ACL_SYNCHRONIZE_SET_DENY;
273fa9e4066Sahrens 		write_owner_set = ACL_WRITE_OWNER_SET_DENY;
274fa9e4066Sahrens 		delete_set = ACL_DELETE_SET_DENY;
275fa9e4066Sahrens 		if (hasreadperm)
276fa9e4066Sahrens 			read_named_set = ACL_READ_NAMED_READER_SET_DENY;
277fa9e4066Sahrens 		if (haswriteperm)
278fa9e4066Sahrens 			write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY;
279fa9e4066Sahrens 		if (isowner)
280fa9e4066Sahrens 			write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY;
281fa9e4066Sahrens 		else if (haswriteperm)
282fa9e4066Sahrens 			write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY;
283fa9e4066Sahrens 		else
284fa9e4066Sahrens 			/*
285fa9e4066Sahrens 			 * If the entity is not the owner and does not
286fa9e4066Sahrens 			 * have write permissions ACE_WRITE_ATTRIBUTES will
287fa9e4066Sahrens 			 * always go in the DENY ACE.
288fa9e4066Sahrens 			 */
289fa9e4066Sahrens 			access_mask |= ACE_WRITE_ATTRIBUTES;
290fa9e4066Sahrens 	}
291fa9e4066Sahrens 
292fa9e4066Sahrens 	if (acl_produce & synchronize_set)
293fa9e4066Sahrens 		access_mask |= ACE_SYNCHRONIZE;
294fa9e4066Sahrens 	if (acl_produce & write_owner_set)
295fa9e4066Sahrens 		access_mask |= ACE_WRITE_OWNER;
296fa9e4066Sahrens 	if (acl_produce & delete_set)
297fa9e4066Sahrens 		access_mask |= ACE_DELETE;
298fa9e4066Sahrens 	if (acl_produce & write_attrs_set)
299fa9e4066Sahrens 		access_mask |= ACE_WRITE_ATTRIBUTES;
300fa9e4066Sahrens 	if (acl_produce & read_named_set)
301fa9e4066Sahrens 		access_mask |= ACE_READ_NAMED_ATTRS;
302fa9e4066Sahrens 	if (acl_produce & write_named_set)
303fa9e4066Sahrens 		access_mask |= ACE_WRITE_NAMED_ATTRS;
304fa9e4066Sahrens 
305fa9e4066Sahrens 	return (access_mask);
306fa9e4066Sahrens }
307fa9e4066Sahrens 
308fa9e4066Sahrens /*
309fa9e4066Sahrens  * Given an mode_t, convert it into an access_mask as used
310fa9e4066Sahrens  * by nfsace, assuming aclent_t -> nfsace semantics.
311fa9e4066Sahrens  */
312fa9e4066Sahrens static uint32_t
313fa9e4066Sahrens mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow)
314fa9e4066Sahrens {
315fa9e4066Sahrens 	uint32_t access = 0;
316fa9e4066Sahrens 	int haswriteperm = 0;
317fa9e4066Sahrens 	int hasreadperm = 0;
318fa9e4066Sahrens 
319fa9e4066Sahrens 	if (isallow) {
320fa9e4066Sahrens 		haswriteperm = (mode & 02);
321fa9e4066Sahrens 		hasreadperm = (mode & 04);
322fa9e4066Sahrens 	} else {
323fa9e4066Sahrens 		haswriteperm = !(mode & 02);
324fa9e4066Sahrens 		hasreadperm = !(mode & 04);
325fa9e4066Sahrens 	}
326fa9e4066Sahrens 
327fa9e4066Sahrens 	/*
328fa9e4066Sahrens 	 * The following call takes care of correctly setting the following
329fa9e4066Sahrens 	 * mask bits in the access_mask:
330fa9e4066Sahrens 	 * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE,
331fa9e4066Sahrens 	 * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS
332fa9e4066Sahrens 	 */
333fa9e4066Sahrens 	access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow);
334fa9e4066Sahrens 
335fa9e4066Sahrens 	if (isallow) {
336fa9e4066Sahrens 		access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES;
337fa9e4066Sahrens 		if (isowner)
338fa9e4066Sahrens 			access |= ACE_WRITE_ACL;
339fa9e4066Sahrens 	} else {
340fa9e4066Sahrens 		if (! isowner)
341fa9e4066Sahrens 			access |= ACE_WRITE_ACL;
342fa9e4066Sahrens 	}
343fa9e4066Sahrens 
344fa9e4066Sahrens 	/* read */
345fa9e4066Sahrens 	if (mode & 04) {
346fa9e4066Sahrens 		access |= ACE_READ_DATA;
347fa9e4066Sahrens 	}
348fa9e4066Sahrens 	/* write */
349fa9e4066Sahrens 	if (mode & 02) {
350fa9e4066Sahrens 		access |= ACE_WRITE_DATA |
351fa9e4066Sahrens 		    ACE_APPEND_DATA;
352fa9e4066Sahrens 		if (isdir)
353fa9e4066Sahrens 			access |= ACE_DELETE_CHILD;
354fa9e4066Sahrens 	}
355fa9e4066Sahrens 	/* exec */
356fa9e4066Sahrens 	if (mode & 01) {
357fa9e4066Sahrens 		access |= ACE_EXECUTE;
358fa9e4066Sahrens 	}
359fa9e4066Sahrens 
360fa9e4066Sahrens 	return (access);
361fa9e4066Sahrens }
362fa9e4066Sahrens 
363fa9e4066Sahrens /*
364fa9e4066Sahrens  * Given an nfsace (presumably an ALLOW entry), make a
365fa9e4066Sahrens  * corresponding DENY entry at the address given.
366fa9e4066Sahrens  */
367fa9e4066Sahrens static void
368fa9e4066Sahrens ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner)
369fa9e4066Sahrens {
370fa9e4066Sahrens 	(void) memcpy(deny, allow, sizeof (ace_t));
371fa9e4066Sahrens 
372fa9e4066Sahrens 	deny->a_who = allow->a_who;
373fa9e4066Sahrens 
374fa9e4066Sahrens 	deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
375fa9e4066Sahrens 	deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS;
376fa9e4066Sahrens 	if (isdir)
377fa9e4066Sahrens 		deny->a_access_mask ^= ACE_DELETE_CHILD;
378fa9e4066Sahrens 
379fa9e4066Sahrens 	deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER |
380fa9e4066Sahrens 	    ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
381fa9e4066Sahrens 	    ACE_WRITE_NAMED_ATTRS);
382fa9e4066Sahrens 	deny->a_access_mask |= access_mask_set((allow->a_access_mask &
383fa9e4066Sahrens 	    ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner,
384fa9e4066Sahrens 	    B_FALSE);
385fa9e4066Sahrens }
386fa9e4066Sahrens /*
387fa9e4066Sahrens  * Make an initial pass over an array of aclent_t's.  Gather
388fa9e4066Sahrens  * information such as an ACL_MASK (if any), number of users,
389fa9e4066Sahrens  * number of groups, and whether the array needs to be sorted.
390fa9e4066Sahrens  */
391fa9e4066Sahrens static int
392fa9e4066Sahrens ln_aent_preprocess(aclent_t *aclent, int n,
393fa9e4066Sahrens     int *hasmask, mode_t *mask,
394fa9e4066Sahrens     int *numuser, int *numgroup, int *needsort)
395fa9e4066Sahrens {
396fa9e4066Sahrens 	int error = 0;
397fa9e4066Sahrens 	int i;
398fa9e4066Sahrens 	int curtype = 0;
399fa9e4066Sahrens 
400fa9e4066Sahrens 	*hasmask = 0;
401fa9e4066Sahrens 	*mask = 07;
402fa9e4066Sahrens 	*needsort = 0;
403fa9e4066Sahrens 	*numuser = 0;
404fa9e4066Sahrens 	*numgroup = 0;
405fa9e4066Sahrens 
406fa9e4066Sahrens 	for (i = 0; i < n; i++) {
407fa9e4066Sahrens 		if (aclent[i].a_type < curtype)
408fa9e4066Sahrens 			*needsort = 1;
409fa9e4066Sahrens 		else if (aclent[i].a_type > curtype)
410fa9e4066Sahrens 			curtype = aclent[i].a_type;
411fa9e4066Sahrens 		if (aclent[i].a_type & USER)
412fa9e4066Sahrens 			(*numuser)++;
413fa9e4066Sahrens 		if (aclent[i].a_type & (GROUP | GROUP_OBJ))
414fa9e4066Sahrens 			(*numgroup)++;
415fa9e4066Sahrens 		if (aclent[i].a_type & CLASS_OBJ) {
416fa9e4066Sahrens 			if (*hasmask) {
417fa9e4066Sahrens 				error = EINVAL;
418fa9e4066Sahrens 				goto out;
419fa9e4066Sahrens 			} else {
420fa9e4066Sahrens 				*hasmask = 1;
421fa9e4066Sahrens 				*mask = aclent[i].a_perm;
422fa9e4066Sahrens 			}
423fa9e4066Sahrens 		}
424fa9e4066Sahrens 	}
425fa9e4066Sahrens 
426fa9e4066Sahrens 	if ((! *hasmask) && (*numuser + *numgroup > 1)) {
427fa9e4066Sahrens 		error = EINVAL;
428fa9e4066Sahrens 		goto out;
429fa9e4066Sahrens 	}
430fa9e4066Sahrens 
431fa9e4066Sahrens out:
432fa9e4066Sahrens 	return (error);
433fa9e4066Sahrens }
434fa9e4066Sahrens 
435fa9e4066Sahrens /*
436fa9e4066Sahrens  * Convert an array of aclent_t into an array of nfsace entries,
437fa9e4066Sahrens  * following POSIX draft -> nfsv4 conversion semantics as outlined in
438fa9e4066Sahrens  * the IETF draft.
439fa9e4066Sahrens  */
440fa9e4066Sahrens static int
441fa9e4066Sahrens ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir)
442fa9e4066Sahrens {
443fa9e4066Sahrens 	int error = 0;
444fa9e4066Sahrens 	mode_t mask;
445fa9e4066Sahrens 	int numuser, numgroup, needsort;
446fa9e4066Sahrens 	int resultsize = 0;
447fa9e4066Sahrens 	int i, groupi = 0, skip;
448fa9e4066Sahrens 	ace_t *acep, *result = NULL;
449fa9e4066Sahrens 	int hasmask;
450fa9e4066Sahrens 
451fa9e4066Sahrens 	error = ln_aent_preprocess(aclent, n, &hasmask, &mask,
452fa9e4066Sahrens 	    &numuser, &numgroup, &needsort);
453fa9e4066Sahrens 	if (error != 0)
454fa9e4066Sahrens 		goto out;
455fa9e4066Sahrens 
456fa9e4066Sahrens 	/* allow + deny for each aclent */
457fa9e4066Sahrens 	resultsize = n * 2;
458fa9e4066Sahrens 	if (hasmask) {
459fa9e4066Sahrens 		/*
460fa9e4066Sahrens 		 * stick extra deny on the group_obj and on each
461fa9e4066Sahrens 		 * user|group for the mask (the group_obj was added
462fa9e4066Sahrens 		 * into the count for numgroup)
463fa9e4066Sahrens 		 */
464fa9e4066Sahrens 		resultsize += numuser + numgroup;
465fa9e4066Sahrens 		/* ... and don't count the mask itself */
466fa9e4066Sahrens 		resultsize -= 2;
467fa9e4066Sahrens 	}
468fa9e4066Sahrens 
469fa9e4066Sahrens 	/* sort the source if necessary */
470fa9e4066Sahrens 	if (needsort)
471fa9e4066Sahrens 		ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls);
472fa9e4066Sahrens 
473fa9e4066Sahrens 	result = acep = calloc(1, resultsize * sizeof (ace_t));
474fa9e4066Sahrens 	if (result == NULL)
475fa9e4066Sahrens 		goto out;
476fa9e4066Sahrens 
477fa9e4066Sahrens 	for (i = 0; i < n; i++) {
478fa9e4066Sahrens 		/*
479fa9e4066Sahrens 		 * don't process CLASS_OBJ (mask); mask was grabbed in
480fa9e4066Sahrens 		 * ln_aent_preprocess()
481fa9e4066Sahrens 		 */
482fa9e4066Sahrens 		if (aclent[i].a_type & CLASS_OBJ)
483fa9e4066Sahrens 			continue;
484fa9e4066Sahrens 
485fa9e4066Sahrens 		/* If we need an ACL_MASK emulator, prepend it now */
486fa9e4066Sahrens 		if ((hasmask) &&
487fa9e4066Sahrens 		    (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) {
488fa9e4066Sahrens 			acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
489fa9e4066Sahrens 			acep->a_flags = 0;
490fa9e4066Sahrens 			if (aclent[i].a_type & GROUP_OBJ) {
491fa9e4066Sahrens 				acep->a_who = -1;
492fa9e4066Sahrens 				acep->a_flags |=
493fa9e4066Sahrens 				    (ACE_IDENTIFIER_GROUP|ACE_GROUP);
494fa9e4066Sahrens 			} else if (aclent[i].a_type & USER) {
495fa9e4066Sahrens 				acep->a_who = aclent[i].a_id;
496fa9e4066Sahrens 			} else {
497fa9e4066Sahrens 				acep->a_who = aclent[i].a_id;
498fa9e4066Sahrens 				acep->a_flags |= ACE_IDENTIFIER_GROUP;
499fa9e4066Sahrens 			}
500fa9e4066Sahrens 			if (aclent[i].a_type & ACL_DEFAULT) {
501fa9e4066Sahrens 				acep->a_flags |= ACE_INHERIT_ONLY_ACE |
502fa9e4066Sahrens 				    ACE_FILE_INHERIT_ACE |
503fa9e4066Sahrens 				    ACE_DIRECTORY_INHERIT_ACE;
504fa9e4066Sahrens 			}
505fa9e4066Sahrens 			/*
506fa9e4066Sahrens 			 * Set the access mask for the prepended deny
507fa9e4066Sahrens 			 * ace.  To do this, we invert the mask (found
508fa9e4066Sahrens 			 * in ln_aent_preprocess()) then convert it to an
509fa9e4066Sahrens 			 * DENY ace access_mask.
510fa9e4066Sahrens 			 */
511fa9e4066Sahrens 			acep->a_access_mask = mode_to_ace_access((mask ^ 07),
512fa9e4066Sahrens 			    isdir, 0, 0);
513fa9e4066Sahrens 			acep += 1;
514fa9e4066Sahrens 		}
515fa9e4066Sahrens 
516fa9e4066Sahrens 		/* handle a_perm -> access_mask */
517fa9e4066Sahrens 		acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm,
518fa9e4066Sahrens 		    isdir, aclent[i].a_type & USER_OBJ, 1);
519fa9e4066Sahrens 
520fa9e4066Sahrens 		/* emulate a default aclent */
521fa9e4066Sahrens 		if (aclent[i].a_type & ACL_DEFAULT) {
522fa9e4066Sahrens 			acep->a_flags |= ACE_INHERIT_ONLY_ACE |
523fa9e4066Sahrens 			    ACE_FILE_INHERIT_ACE |
524fa9e4066Sahrens 			    ACE_DIRECTORY_INHERIT_ACE;
525fa9e4066Sahrens 		}
526fa9e4066Sahrens 
527fa9e4066Sahrens 		/*
528fa9e4066Sahrens 		 * handle a_perm and a_id
529fa9e4066Sahrens 		 *
530fa9e4066Sahrens 		 * this must be done last, since it involves the
531fa9e4066Sahrens 		 * corresponding deny aces, which are handled
532fa9e4066Sahrens 		 * differently for each different a_type.
533fa9e4066Sahrens 		 */
534fa9e4066Sahrens 		if (aclent[i].a_type & USER_OBJ) {
535fa9e4066Sahrens 			acep->a_who = -1;
536fa9e4066Sahrens 			acep->a_flags |= ACE_OWNER;
537fa9e4066Sahrens 			ace_make_deny(acep, acep + 1, isdir, B_TRUE);
538fa9e4066Sahrens 			acep += 2;
539fa9e4066Sahrens 		} else if (aclent[i].a_type & USER) {
540fa9e4066Sahrens 			acep->a_who = aclent[i].a_id;
541fa9e4066Sahrens 			ace_make_deny(acep, acep + 1, isdir, B_FALSE);
542fa9e4066Sahrens 			acep += 2;
543fa9e4066Sahrens 		} else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) {
544fa9e4066Sahrens 			if (aclent[i].a_type & GROUP_OBJ) {
545fa9e4066Sahrens 				acep->a_who = -1;
546fa9e4066Sahrens 				acep->a_flags |= ACE_GROUP;
547fa9e4066Sahrens 			} else {
548fa9e4066Sahrens 				acep->a_who = aclent[i].a_id;
549fa9e4066Sahrens 			}
550fa9e4066Sahrens 			acep->a_flags |= ACE_IDENTIFIER_GROUP;
551fa9e4066Sahrens 			/*
552fa9e4066Sahrens 			 * Set the corresponding deny for the group ace.
553fa9e4066Sahrens 			 *
554fa9e4066Sahrens 			 * The deny aces go after all of the groups, unlike
555fa9e4066Sahrens 			 * everything else, where they immediately follow
556fa9e4066Sahrens 			 * the allow ace.
557fa9e4066Sahrens 			 *
558fa9e4066Sahrens 			 * We calculate "skip", the number of slots to
559fa9e4066Sahrens 			 * skip ahead for the deny ace, here.
560fa9e4066Sahrens 			 *
561fa9e4066Sahrens 			 * The pattern is:
562fa9e4066Sahrens 			 * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3
563fa9e4066Sahrens 			 * thus, skip is
564fa9e4066Sahrens 			 * (2 * numgroup) - 1 - groupi
565fa9e4066Sahrens 			 * (2 * numgroup) to account for MD + A
566fa9e4066Sahrens 			 * - 1 to account for the fact that we're on the
567fa9e4066Sahrens 			 * access (A), not the mask (MD)
568fa9e4066Sahrens 			 * - groupi to account for the fact that we have
569fa9e4066Sahrens 			 * passed up groupi number of MD's.
570fa9e4066Sahrens 			 */
571fa9e4066Sahrens 			skip = (2 * numgroup) - 1 - groupi;
572fa9e4066Sahrens 			ace_make_deny(acep, acep + skip, isdir, B_FALSE);
573fa9e4066Sahrens 			/*
574fa9e4066Sahrens 			 * If we just did the last group, skip acep past
575fa9e4066Sahrens 			 * all of the denies; else, just move ahead one.
576fa9e4066Sahrens 			 */
577fa9e4066Sahrens 			if (++groupi >= numgroup)
578fa9e4066Sahrens 				acep += numgroup + 1;
579fa9e4066Sahrens 			else
580fa9e4066Sahrens 				acep += 1;
581fa9e4066Sahrens 		} else if (aclent[i].a_type & OTHER_OBJ) {
582fa9e4066Sahrens 			acep->a_who = -1;
583fa9e4066Sahrens 			acep->a_flags |= ACE_EVERYONE;
584fa9e4066Sahrens 			ace_make_deny(acep, acep + 1, isdir, B_FALSE);
585fa9e4066Sahrens 			acep += 2;
586fa9e4066Sahrens 		} else {
587fa9e4066Sahrens 			error = EINVAL;
588fa9e4066Sahrens 			goto out;
589fa9e4066Sahrens 		}
590fa9e4066Sahrens 	}
591fa9e4066Sahrens 
592fa9e4066Sahrens 	*acepp = result;
593fa9e4066Sahrens 	*rescount = resultsize;
594fa9e4066Sahrens 
595fa9e4066Sahrens out:
596fa9e4066Sahrens 	if (error != 0) {
597fa9e4066Sahrens 		if ((result != NULL) && (resultsize > 0)) {
598fa9e4066Sahrens 			free(result);
599fa9e4066Sahrens 		}
600fa9e4066Sahrens 	}
601fa9e4066Sahrens 
602fa9e4066Sahrens 	return (error);
603fa9e4066Sahrens }
604fa9e4066Sahrens 
605fa9e4066Sahrens static int
606fa9e4066Sahrens convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir,
607fa9e4066Sahrens     ace_t **retacep, int *retacecnt)
608fa9e4066Sahrens {
609fa9e4066Sahrens 	ace_t *acep;
610fa9e4066Sahrens 	ace_t *dfacep;
611fa9e4066Sahrens 	int acecnt = 0;
612fa9e4066Sahrens 	int dfacecnt = 0;
613fa9e4066Sahrens 	int dfaclstart = 0;
614fa9e4066Sahrens 	int dfaclcnt = 0;
615fa9e4066Sahrens 	aclent_t *aclp;
616fa9e4066Sahrens 	int i;
617fa9e4066Sahrens 	int error;
618fa9e4066Sahrens 
619fa9e4066Sahrens 	ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls);
620fa9e4066Sahrens 
621fa9e4066Sahrens 	for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) {
622fa9e4066Sahrens 		if (aclp->a_type & ACL_DEFAULT)
623fa9e4066Sahrens 			break;
624fa9e4066Sahrens 	}
625fa9e4066Sahrens 
626fa9e4066Sahrens 	if (i < aclcnt) {
6273eb3c573Smarks 		dfaclstart = i;
6283eb3c573Smarks 		dfaclcnt = aclcnt - i;
629fa9e4066Sahrens 	}
630fa9e4066Sahrens 
631fa9e4066Sahrens 	if (dfaclcnt && isdir == 0) {
632fa9e4066Sahrens 		return (-1);
633fa9e4066Sahrens 	}
634fa9e4066Sahrens 
635fa9e4066Sahrens 	error = ln_aent_to_ace(aclentp, i,  &acep, &acecnt, isdir);
636fa9e4066Sahrens 	if (error)
637fa9e4066Sahrens 		return (-1);
638fa9e4066Sahrens 
639fa9e4066Sahrens 	if (dfaclcnt) {
640fa9e4066Sahrens 		error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt,
641fa9e4066Sahrens 		    &dfacep, &dfacecnt, isdir);
642fa9e4066Sahrens 		if (error) {
643fa9e4066Sahrens 			if (acep) {
644fa9e4066Sahrens 				free(acep);
645fa9e4066Sahrens 			}
646fa9e4066Sahrens 			return (-1);
647fa9e4066Sahrens 		}
648fa9e4066Sahrens 	}
649fa9e4066Sahrens 
6503eb3c573Smarks 	if (dfacecnt != 0) {
6513eb3c573Smarks 		acep = realloc(acep, sizeof (ace_t) * (acecnt + dfacecnt));
6523eb3c573Smarks 		if (acep == NULL)
653fa9e4066Sahrens 			return (-1);
654fa9e4066Sahrens 		if (dfaclcnt) {
6553eb3c573Smarks 			(void) memcpy(acep + acecnt, dfacep,
656fa9e4066Sahrens 			    sizeof (ace_t) * dfacecnt);
657fa9e4066Sahrens 		}
6583eb3c573Smarks 	}
659fa9e4066Sahrens 	if (dfaclcnt)
660fa9e4066Sahrens 		free(dfacep);
661fa9e4066Sahrens 
662fa9e4066Sahrens 	*retacecnt = acecnt + dfacecnt;
6633eb3c573Smarks 	*retacep = acep;
664fa9e4066Sahrens 	return (0);
665fa9e4066Sahrens }
666fa9e4066Sahrens 
6673eb3c573Smarks static void
6683eb3c573Smarks acevals_init(acevals_t *vals, uid_t key)
6693eb3c573Smarks {
6703eb3c573Smarks 	bzero(vals, sizeof (*vals));
6713eb3c573Smarks 	vals->allowed = ACE_MASK_UNDEFINED;
6723eb3c573Smarks 	vals->denied = ACE_MASK_UNDEFINED;
6733eb3c573Smarks 	vals->mask = ACE_MASK_UNDEFINED;
6743eb3c573Smarks 	vals->key = key;
6753eb3c573Smarks }
6763eb3c573Smarks 
6773eb3c573Smarks static void
6783eb3c573Smarks ace_list_init(ace_list_t *al, int dfacl_flag)
6793eb3c573Smarks {
6803eb3c573Smarks 	acevals_init(&al->user_obj, NULL);
6813eb3c573Smarks 	acevals_init(&al->group_obj, NULL);
6823eb3c573Smarks 	acevals_init(&al->other_obj, NULL);
6833eb3c573Smarks 	al->numusers = 0;
6843eb3c573Smarks 	al->numgroups = 0;
6853eb3c573Smarks 	al->acl_mask = 0;
6863eb3c573Smarks 	al->hasmask = 0;
6873eb3c573Smarks 	al->state = ace_unused;
6883eb3c573Smarks 	al->seen = 0;
6893eb3c573Smarks 	al->dfacl_flag = dfacl_flag;
6903eb3c573Smarks }
6913eb3c573Smarks 
6923eb3c573Smarks /*
6933eb3c573Smarks  * Find or create an acevals holder for a given id and avl tree.
6943eb3c573Smarks  *
6953eb3c573Smarks  * Note that only one thread will ever touch these avl trees, so
6963eb3c573Smarks  * there is no need for locking.
6973eb3c573Smarks  */
6983eb3c573Smarks static acevals_t *
6993eb3c573Smarks acevals_find(ace_t *ace, avl_tree_t *avl, int *num)
7003eb3c573Smarks {
7013eb3c573Smarks 	acevals_t key, *rc;
7023eb3c573Smarks 	avl_index_t where;
7033eb3c573Smarks 
7043eb3c573Smarks 	key.key = ace->a_who;
7053eb3c573Smarks 	rc = avl_find(avl, &key, &where);
7063eb3c573Smarks 	if (rc != NULL)
7073eb3c573Smarks 		return (rc);
7083eb3c573Smarks 
7093eb3c573Smarks 	/* this memory is freed by ln_ace_to_aent()->ace_list_free() */
7103eb3c573Smarks 	rc = calloc(1, sizeof (acevals_t));
7113eb3c573Smarks 	if (rc == NULL)
7123eb3c573Smarks 		return (rc);
7133eb3c573Smarks 	acevals_init(rc, ace->a_who);
7143eb3c573Smarks 	avl_insert(avl, rc, where);
7153eb3c573Smarks 	(*num)++;
7163eb3c573Smarks 
7173eb3c573Smarks 	return (rc);
7183eb3c573Smarks }
719fa9e4066Sahrens 
720fa9e4066Sahrens static int
7213eb3c573Smarks access_mask_check(ace_t *acep, int mask_bit, int isowner)
7223eb3c573Smarks {
7233eb3c573Smarks 	int set_deny, err_deny;
7243eb3c573Smarks 	int set_allow, err_allow;
7253eb3c573Smarks 	int acl_consume;
7263eb3c573Smarks 	int haswriteperm, hasreadperm;
7273eb3c573Smarks 
7283eb3c573Smarks 	if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
7293eb3c573Smarks 		haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1;
7303eb3c573Smarks 		hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1;
7313eb3c573Smarks 	} else {
7323eb3c573Smarks 		haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0;
7333eb3c573Smarks 		hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0;
7343eb3c573Smarks 	}
7353eb3c573Smarks 
7363eb3c573Smarks 	acl_consume = (ACL_SYNCHRONIZE_ERR_DENY |
7373eb3c573Smarks 	    ACL_DELETE_ERR_DENY |
7383eb3c573Smarks 	    ACL_WRITE_OWNER_ERR_DENY |
7393eb3c573Smarks 	    ACL_WRITE_OWNER_ERR_ALLOW |
7403eb3c573Smarks 	    ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
7413eb3c573Smarks 	    ACL_WRITE_ATTRS_OWNER_ERR_DENY |
7423eb3c573Smarks 	    ACL_WRITE_ATTRS_WRITER_SET_DENY |
7433eb3c573Smarks 	    ACL_WRITE_ATTRS_WRITER_ERR_ALLOW |
7443eb3c573Smarks 	    ACL_WRITE_NAMED_WRITER_ERR_DENY |
7453eb3c573Smarks 	    ACL_READ_NAMED_READER_ERR_DENY);
7463eb3c573Smarks 
7473eb3c573Smarks 	if (mask_bit == ACE_SYNCHRONIZE) {
7483eb3c573Smarks 		set_deny = ACL_SYNCHRONIZE_SET_DENY;
7493eb3c573Smarks 		err_deny =  ACL_SYNCHRONIZE_ERR_DENY;
7503eb3c573Smarks 		set_allow = ACL_SYNCHRONIZE_SET_ALLOW;
7513eb3c573Smarks 		err_allow = ACL_SYNCHRONIZE_ERR_ALLOW;
7523eb3c573Smarks 	} else if (mask_bit == ACE_WRITE_OWNER) {
7533eb3c573Smarks 		set_deny = ACL_WRITE_OWNER_SET_DENY;
7543eb3c573Smarks 		err_deny =  ACL_WRITE_OWNER_ERR_DENY;
7553eb3c573Smarks 		set_allow = ACL_WRITE_OWNER_SET_ALLOW;
7563eb3c573Smarks 		err_allow = ACL_WRITE_OWNER_ERR_ALLOW;
7573eb3c573Smarks 	} else if (mask_bit == ACE_DELETE) {
7583eb3c573Smarks 		set_deny = ACL_DELETE_SET_DENY;
7593eb3c573Smarks 		err_deny =  ACL_DELETE_ERR_DENY;
7603eb3c573Smarks 		set_allow = ACL_DELETE_SET_ALLOW;
7613eb3c573Smarks 		err_allow = ACL_DELETE_ERR_ALLOW;
7623eb3c573Smarks 	} else if (mask_bit == ACE_WRITE_ATTRIBUTES) {
7633eb3c573Smarks 		if (isowner) {
7643eb3c573Smarks 			set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY;
7653eb3c573Smarks 			err_deny =  ACL_WRITE_ATTRS_OWNER_ERR_DENY;
7663eb3c573Smarks 			set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
7673eb3c573Smarks 			err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW;
7683eb3c573Smarks 		} else if (haswriteperm) {
7693eb3c573Smarks 			set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY;
7703eb3c573Smarks 			err_deny =  ACL_WRITE_ATTRS_WRITER_ERR_DENY;
7713eb3c573Smarks 			set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
7723eb3c573Smarks 			err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW;
7733eb3c573Smarks 		} else {
7743eb3c573Smarks 			if ((acep->a_access_mask & mask_bit) &&
7753eb3c573Smarks 			    (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) {
7763eb3c573Smarks 				return (ENOTSUP);
7773eb3c573Smarks 			}
7783eb3c573Smarks 			return (0);
7793eb3c573Smarks 		}
7803eb3c573Smarks 	} else if (mask_bit == ACE_READ_NAMED_ATTRS) {
7813eb3c573Smarks 		if (!hasreadperm)
7823eb3c573Smarks 			return (0);
7833eb3c573Smarks 
7843eb3c573Smarks 		set_deny = ACL_READ_NAMED_READER_SET_DENY;
7853eb3c573Smarks 		err_deny = ACL_READ_NAMED_READER_ERR_DENY;
7863eb3c573Smarks 		set_allow = ACL_READ_NAMED_READER_SET_ALLOW;
7873eb3c573Smarks 		err_allow = ACL_READ_NAMED_READER_ERR_ALLOW;
7883eb3c573Smarks 	} else if (mask_bit == ACE_WRITE_NAMED_ATTRS) {
7893eb3c573Smarks 		if (!haswriteperm)
7903eb3c573Smarks 			return (0);
7913eb3c573Smarks 
7923eb3c573Smarks 		set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY;
7933eb3c573Smarks 		err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY;
7943eb3c573Smarks 		set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
7953eb3c573Smarks 		err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW;
7963eb3c573Smarks 	} else {
7973eb3c573Smarks 		return (EINVAL);
7983eb3c573Smarks 	}
7993eb3c573Smarks 
8003eb3c573Smarks 	if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
8013eb3c573Smarks 		if (acl_consume & set_deny) {
8023eb3c573Smarks 			if (!(acep->a_access_mask & mask_bit)) {
8033eb3c573Smarks 				return (ENOTSUP);
8043eb3c573Smarks 			}
8053eb3c573Smarks 		} else if (acl_consume & err_deny) {
8063eb3c573Smarks 			if (acep->a_access_mask & mask_bit) {
8073eb3c573Smarks 				return (ENOTSUP);
8083eb3c573Smarks 			}
8093eb3c573Smarks 		}
8103eb3c573Smarks 	} else {
8113eb3c573Smarks 		/* ACE_ACCESS_ALLOWED_ACE_TYPE */
8123eb3c573Smarks 		if (acl_consume & set_allow) {
8133eb3c573Smarks 			if (!(acep->a_access_mask & mask_bit)) {
8143eb3c573Smarks 				return (ENOTSUP);
8153eb3c573Smarks 			}
8163eb3c573Smarks 		} else if (acl_consume & err_allow) {
8173eb3c573Smarks 			if (acep->a_access_mask & mask_bit) {
8183eb3c573Smarks 				return (ENOTSUP);
8193eb3c573Smarks 			}
8203eb3c573Smarks 		}
8213eb3c573Smarks 	}
8223eb3c573Smarks 	return (0);
8233eb3c573Smarks }
8243eb3c573Smarks 
8253eb3c573Smarks static int
8263eb3c573Smarks ace_to_aent_legal(ace_t *acep)
8273eb3c573Smarks {
8283eb3c573Smarks 	int error = 0;
8293eb3c573Smarks 	int isowner;
8303eb3c573Smarks 
8313eb3c573Smarks 	/* only ALLOW or DENY */
8323eb3c573Smarks 	if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) &&
8333eb3c573Smarks 	    (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) {
8343eb3c573Smarks 		error = ENOTSUP;
8353eb3c573Smarks 		goto out;
8363eb3c573Smarks 	}
8373eb3c573Smarks 
8383eb3c573Smarks 	/* check for invalid flags */
8393eb3c573Smarks 	if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) {
8403eb3c573Smarks 		error = EINVAL;
8413eb3c573Smarks 		goto out;
8423eb3c573Smarks 	}
8433eb3c573Smarks 
8443eb3c573Smarks 	/* some flags are illegal */
8453eb3c573Smarks 	if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG |
8463eb3c573Smarks 	    ACE_FAILED_ACCESS_ACE_FLAG |
8473eb3c573Smarks 	    ACE_NO_PROPAGATE_INHERIT_ACE)) {
8483eb3c573Smarks 		error = ENOTSUP;
8493eb3c573Smarks 		goto out;
8503eb3c573Smarks 	}
8513eb3c573Smarks 
8523eb3c573Smarks 	/* check for invalid masks */
8533eb3c573Smarks 	if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) {
8543eb3c573Smarks 		error = EINVAL;
8553eb3c573Smarks 		goto out;
8563eb3c573Smarks 	}
8573eb3c573Smarks 
8583eb3c573Smarks 	if ((acep->a_flags & ACE_OWNER)) {
8593eb3c573Smarks 		isowner = 1;
8603eb3c573Smarks 	} else {
8613eb3c573Smarks 		isowner = 0;
8623eb3c573Smarks 	}
8633eb3c573Smarks 
8643eb3c573Smarks 	error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner);
8653eb3c573Smarks 	if (error)
8663eb3c573Smarks 		goto out;
8673eb3c573Smarks 
8683eb3c573Smarks 	error = access_mask_check(acep, ACE_WRITE_OWNER, isowner);
8693eb3c573Smarks 	if (error)
8703eb3c573Smarks 		goto out;
8713eb3c573Smarks 
8723eb3c573Smarks 	error = access_mask_check(acep, ACE_DELETE, isowner);
8733eb3c573Smarks 	if (error)
8743eb3c573Smarks 		goto out;
8753eb3c573Smarks 
8763eb3c573Smarks 	error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner);
8773eb3c573Smarks 	if (error)
8783eb3c573Smarks 		goto out;
8793eb3c573Smarks 
8803eb3c573Smarks 	error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner);
8813eb3c573Smarks 	if (error)
8823eb3c573Smarks 		goto out;
8833eb3c573Smarks 
8843eb3c573Smarks 	error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner);
8853eb3c573Smarks 	if (error)
8863eb3c573Smarks 		goto out;
8873eb3c573Smarks 
8883eb3c573Smarks 	/* more detailed checking of masks */
8893eb3c573Smarks 	if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
8903eb3c573Smarks 		if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) {
8913eb3c573Smarks 			error = ENOTSUP;
8923eb3c573Smarks 			goto out;
8933eb3c573Smarks 		}
8943eb3c573Smarks 		if ((acep->a_access_mask & ACE_WRITE_DATA) &&
8953eb3c573Smarks 		    (! (acep->a_access_mask & ACE_APPEND_DATA))) {
8963eb3c573Smarks 			error = ENOTSUP;
8973eb3c573Smarks 			goto out;
8983eb3c573Smarks 		}
8993eb3c573Smarks 		if ((! (acep->a_access_mask & ACE_WRITE_DATA)) &&
9003eb3c573Smarks 		    (acep->a_access_mask & ACE_APPEND_DATA)) {
9013eb3c573Smarks 			error = ENOTSUP;
9023eb3c573Smarks 			goto out;
9033eb3c573Smarks 		}
9043eb3c573Smarks 	}
9053eb3c573Smarks 
9063eb3c573Smarks 	/* ACL enforcement */
9073eb3c573Smarks 	if ((acep->a_access_mask & ACE_READ_ACL) &&
9083eb3c573Smarks 	    (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) {
9093eb3c573Smarks 		error = ENOTSUP;
9103eb3c573Smarks 		goto out;
9113eb3c573Smarks 	}
9123eb3c573Smarks 	if (acep->a_access_mask & ACE_WRITE_ACL) {
9133eb3c573Smarks 		if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) &&
9143eb3c573Smarks 		    (isowner)) {
9153eb3c573Smarks 			error = ENOTSUP;
9163eb3c573Smarks 			goto out;
9173eb3c573Smarks 		}
9183eb3c573Smarks 		if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) &&
9193eb3c573Smarks 		    (! isowner)) {
9203eb3c573Smarks 			error = ENOTSUP;
9213eb3c573Smarks 			goto out;
9223eb3c573Smarks 		}
9233eb3c573Smarks 	}
9243eb3c573Smarks 
9253eb3c573Smarks out:
9263eb3c573Smarks 	return (error);
9273eb3c573Smarks }
9283eb3c573Smarks 
9293eb3c573Smarks static int
9303eb3c573Smarks ace_mask_to_mode(uint32_t  mask, o_mode_t *modep, int isdir)
9313eb3c573Smarks {
9323eb3c573Smarks 	int error = 0;
9333eb3c573Smarks 	o_mode_t mode = 0;
9343eb3c573Smarks 	uint32_t bits, wantbits;
9353eb3c573Smarks 
9363eb3c573Smarks 	/* read */
9373eb3c573Smarks 	if (mask & ACE_READ_DATA)
9383eb3c573Smarks 		mode |= 04;
9393eb3c573Smarks 
9403eb3c573Smarks 	/* write */
9413eb3c573Smarks 	wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA);
9423eb3c573Smarks 	if (isdir)
9433eb3c573Smarks 		wantbits |= ACE_DELETE_CHILD;
9443eb3c573Smarks 	bits = mask & wantbits;
9453eb3c573Smarks 	if (bits != 0) {
9463eb3c573Smarks 		if (bits != wantbits) {
9473eb3c573Smarks 			error = ENOTSUP;
9483eb3c573Smarks 			goto out;
9493eb3c573Smarks 		}
9503eb3c573Smarks 		mode |= 02;
9513eb3c573Smarks 	}
9523eb3c573Smarks 
9533eb3c573Smarks 	/* exec */
9543eb3c573Smarks 	if (mask & ACE_EXECUTE) {
9553eb3c573Smarks 		mode |= 01;
9563eb3c573Smarks 	}
9573eb3c573Smarks 
9583eb3c573Smarks 	*modep = mode;
9593eb3c573Smarks 
9603eb3c573Smarks out:
9613eb3c573Smarks 	return (error);
9623eb3c573Smarks }
9633eb3c573Smarks 
9643eb3c573Smarks static int
9653eb3c573Smarks ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir)
9663eb3c573Smarks {
9673eb3c573Smarks 	/* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */
9683eb3c573Smarks 	if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) !=
9693eb3c573Smarks 	    (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) {
9703eb3c573Smarks 		return (ENOTSUP);
9713eb3c573Smarks 	}
9723eb3c573Smarks 
9733eb3c573Smarks 	return (ace_mask_to_mode(mask, modep, isdir));
9743eb3c573Smarks }
9753eb3c573Smarks 
9763eb3c573Smarks static int
9773eb3c573Smarks acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list,
9783eb3c573Smarks     uid_t owner, gid_t group, int isdir)
9793eb3c573Smarks {
9803eb3c573Smarks 	int error;
9813eb3c573Smarks 	uint32_t  flips = ACE_POSIX_SUPPORTED_BITS;
9823eb3c573Smarks 
9833eb3c573Smarks 	if (isdir)
9843eb3c573Smarks 		flips |= ACE_DELETE_CHILD;
9853eb3c573Smarks 	if (vals->allowed != (vals->denied ^ flips)) {
9863eb3c573Smarks 		error = ENOTSUP;
9873eb3c573Smarks 		goto out;
9883eb3c573Smarks 	}
9893eb3c573Smarks 	if ((list->hasmask) && (list->acl_mask != vals->mask) &&
9903eb3c573Smarks 	    (vals->aent_type & (USER | GROUP | GROUP_OBJ))) {
9913eb3c573Smarks 		error = ENOTSUP;
9923eb3c573Smarks 		goto out;
9933eb3c573Smarks 	}
9943eb3c573Smarks 	error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir);
9953eb3c573Smarks 	if (error != 0)
9963eb3c573Smarks 		goto out;
9973eb3c573Smarks 	dest->a_type = vals->aent_type;
9983eb3c573Smarks 	if (dest->a_type & (USER | GROUP)) {
9993eb3c573Smarks 		dest->a_id = vals->key;
10003eb3c573Smarks 	} else if (dest->a_type & USER_OBJ) {
10013eb3c573Smarks 		dest->a_id = owner;
10023eb3c573Smarks 	} else if (dest->a_type & GROUP_OBJ) {
10033eb3c573Smarks 		dest->a_id = group;
10043eb3c573Smarks 	} else if (dest->a_type & OTHER_OBJ) {
10053eb3c573Smarks 		dest->a_id = 0;
10063eb3c573Smarks 	} else {
10073eb3c573Smarks 		error = EINVAL;
10083eb3c573Smarks 		goto out;
10093eb3c573Smarks 	}
10103eb3c573Smarks 
10113eb3c573Smarks out:
10123eb3c573Smarks 	return (error);
10133eb3c573Smarks }
10143eb3c573Smarks 
10153eb3c573Smarks static int
10163eb3c573Smarks ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt,
10173eb3c573Smarks     uid_t owner, gid_t group, int isdir)
10183eb3c573Smarks {
10193eb3c573Smarks 	int error = 0;
10203eb3c573Smarks 	aclent_t *aent, *result = NULL;
10213eb3c573Smarks 	acevals_t *vals;
10223eb3c573Smarks 	int resultcount;
10233eb3c573Smarks 
10243eb3c573Smarks 	if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) !=
10253eb3c573Smarks 	    (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) {
10263eb3c573Smarks 		error = ENOTSUP;
10273eb3c573Smarks 		goto out;
10283eb3c573Smarks 	}
10293eb3c573Smarks 	if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) {
10303eb3c573Smarks 		error = ENOTSUP;
10313eb3c573Smarks 		goto out;
10323eb3c573Smarks 	}
10333eb3c573Smarks 
10343eb3c573Smarks 	resultcount = 3 + list->numusers + list->numgroups;
10353eb3c573Smarks 	/*
10363eb3c573Smarks 	 * This must be the same condition as below, when we add the CLASS_OBJ
10373eb3c573Smarks 	 * (aka ACL mask)
10383eb3c573Smarks 	 */
10393eb3c573Smarks 	if ((list->hasmask) || (! list->dfacl_flag))
10403eb3c573Smarks 		resultcount += 1;
10413eb3c573Smarks 
10423eb3c573Smarks 	result = aent = calloc(1, resultcount * sizeof (aclent_t));
10433eb3c573Smarks 
10443eb3c573Smarks 	if (result == NULL) {
10453eb3c573Smarks 		error = ENOMEM;
10463eb3c573Smarks 		goto out;
10473eb3c573Smarks 	}
10483eb3c573Smarks 
10493eb3c573Smarks 	/* USER_OBJ */
10503eb3c573Smarks 	if (!(list->user_obj.aent_type & USER_OBJ)) {
10513eb3c573Smarks 		error = EINVAL;
10523eb3c573Smarks 		goto out;
10533eb3c573Smarks 	}
10543eb3c573Smarks 
10553eb3c573Smarks 	error = acevals_to_aent(&list->user_obj, aent, list, owner, group,
10563eb3c573Smarks 	    isdir);
10573eb3c573Smarks 
10583eb3c573Smarks 	if (error != 0)
10593eb3c573Smarks 		goto out;
10603eb3c573Smarks 	++aent;
10613eb3c573Smarks 	/* USER */
10623eb3c573Smarks 	vals = NULL;
10633eb3c573Smarks 	for (vals = avl_first(&list->user); vals != NULL;
10643eb3c573Smarks 	    vals = AVL_NEXT(&list->user, vals)) {
10653eb3c573Smarks 		if (!(vals->aent_type & USER)) {
10663eb3c573Smarks 			error = EINVAL;
10673eb3c573Smarks 			goto out;
10683eb3c573Smarks 		}
10693eb3c573Smarks 		error = acevals_to_aent(vals, aent, list, owner, group,
10703eb3c573Smarks 		    isdir);
10713eb3c573Smarks 		if (error != 0)
10723eb3c573Smarks 			goto out;
10733eb3c573Smarks 		++aent;
10743eb3c573Smarks 	}
10753eb3c573Smarks 	/* GROUP_OBJ */
10763eb3c573Smarks 	if (!(list->group_obj.aent_type & GROUP_OBJ)) {
10773eb3c573Smarks 		error = EINVAL;
10783eb3c573Smarks 		goto out;
10793eb3c573Smarks 	}
10803eb3c573Smarks 	error = acevals_to_aent(&list->group_obj, aent, list, owner, group,
10813eb3c573Smarks 	    isdir);
10823eb3c573Smarks 	if (error != 0)
10833eb3c573Smarks 		goto out;
10843eb3c573Smarks 	++aent;
10853eb3c573Smarks 	/* GROUP */
10863eb3c573Smarks 	vals = NULL;
10873eb3c573Smarks 	for (vals = avl_first(&list->group); vals != NULL;
10883eb3c573Smarks 	    vals = AVL_NEXT(&list->group, vals)) {
10893eb3c573Smarks 		if (!(vals->aent_type & GROUP)) {
10903eb3c573Smarks 			error = EINVAL;
10913eb3c573Smarks 			goto out;
10923eb3c573Smarks 		}
10933eb3c573Smarks 		error = acevals_to_aent(vals, aent, list, owner, group,
10943eb3c573Smarks 		    isdir);
10953eb3c573Smarks 		if (error != 0)
10963eb3c573Smarks 			goto out;
10973eb3c573Smarks 		++aent;
10983eb3c573Smarks 	}
10993eb3c573Smarks 	/*
11003eb3c573Smarks 	 * CLASS_OBJ (aka ACL_MASK)
11013eb3c573Smarks 	 *
11023eb3c573Smarks 	 * An ACL_MASK is not fabricated if the ACL is a default ACL.
11033eb3c573Smarks 	 * This is to follow UFS's behavior.
11043eb3c573Smarks 	 */
11053eb3c573Smarks 	if ((list->hasmask) || (! list->dfacl_flag)) {
11063eb3c573Smarks 		if (list->hasmask) {
11073eb3c573Smarks 			uint32_t flips = ACE_POSIX_SUPPORTED_BITS;
11083eb3c573Smarks 			if (isdir)
11093eb3c573Smarks 				flips |= ACE_DELETE_CHILD;
11103eb3c573Smarks 			error = ace_mask_to_mode(list->acl_mask ^ flips,
11113eb3c573Smarks 			    &aent->a_perm, isdir);
11123eb3c573Smarks 			if (error != 0)
11133eb3c573Smarks 				goto out;
11143eb3c573Smarks 		} else {
11153eb3c573Smarks 			/* fabricate the ACL_MASK from the group permissions */
11163eb3c573Smarks 			error = ace_mask_to_mode(list->group_obj.allowed,
11173eb3c573Smarks 			    &aent->a_perm, isdir);
11183eb3c573Smarks 			if (error != 0)
11193eb3c573Smarks 				goto out;
11203eb3c573Smarks 		}
11213eb3c573Smarks 		aent->a_id = 0;
11223eb3c573Smarks 		aent->a_type = CLASS_OBJ | list->dfacl_flag;
11233eb3c573Smarks 		++aent;
11243eb3c573Smarks 	}
11253eb3c573Smarks 	/* OTHER_OBJ */
11263eb3c573Smarks 	if (!(list->other_obj.aent_type & OTHER_OBJ)) {
11273eb3c573Smarks 		error = EINVAL;
11283eb3c573Smarks 		goto out;
11293eb3c573Smarks 	}
11303eb3c573Smarks 	error = acevals_to_aent(&list->other_obj, aent, list, owner, group,
11313eb3c573Smarks 	    isdir);
11323eb3c573Smarks 	if (error != 0)
11333eb3c573Smarks 		goto out;
11343eb3c573Smarks 	++aent;
11353eb3c573Smarks 
11363eb3c573Smarks 	*aclentp = result;
11373eb3c573Smarks 	*aclcnt = resultcount;
11383eb3c573Smarks 
11393eb3c573Smarks out:
11403eb3c573Smarks 	if (error != 0) {
11413eb3c573Smarks 		if (result != NULL)
11423eb3c573Smarks 			free(result);
11433eb3c573Smarks 	}
11443eb3c573Smarks 
11453eb3c573Smarks 	return (error);
11463eb3c573Smarks }
11473eb3c573Smarks 
11483eb3c573Smarks /*
11493eb3c573Smarks  * free all data associated with an ace_list
11503eb3c573Smarks  */
11513eb3c573Smarks static void
11523eb3c573Smarks ace_list_free(ace_list_t *al)
11533eb3c573Smarks {
11543eb3c573Smarks 	acevals_t *node;
11553eb3c573Smarks 	void *cookie;
11563eb3c573Smarks 
11573eb3c573Smarks 	if (al == NULL)
11583eb3c573Smarks 		return;
11593eb3c573Smarks 
11603eb3c573Smarks 	cookie = NULL;
11613eb3c573Smarks 	while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL)
11623eb3c573Smarks 		free(node);
11633eb3c573Smarks 	cookie = NULL;
11643eb3c573Smarks 	while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL)
11653eb3c573Smarks 		free(node);
11663eb3c573Smarks 
11673eb3c573Smarks 	avl_destroy(&al->user);
11683eb3c573Smarks 	avl_destroy(&al->group);
11693eb3c573Smarks 
11703eb3c573Smarks 	/* free the container itself */
11713eb3c573Smarks 	free(al);
11723eb3c573Smarks }
11733eb3c573Smarks 
11743eb3c573Smarks static int
11753eb3c573Smarks acevals_compare(const void *va, const void *vb)
11763eb3c573Smarks {
11773eb3c573Smarks 	const acevals_t *a = va, *b = vb;
11783eb3c573Smarks 
11793eb3c573Smarks 	if (a->key == b->key)
11803eb3c573Smarks 		return (0);
11813eb3c573Smarks 
11823eb3c573Smarks 	if (a->key > b->key)
11833eb3c573Smarks 		return (1);
11843eb3c573Smarks 
11853eb3c573Smarks 	else
11863eb3c573Smarks 		return (-1);
11873eb3c573Smarks }
11883eb3c573Smarks 
11893eb3c573Smarks /*
11903eb3c573Smarks  * Convert a list of ace_t entries to equivalent regular and default
11913eb3c573Smarks  * aclent_t lists.  Return error (ENOTSUP) when conversion is not possible.
11923eb3c573Smarks  */
11933eb3c573Smarks static int
11943eb3c573Smarks ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group,
11953eb3c573Smarks     aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt,
11963eb3c573Smarks     int isdir)
11973eb3c573Smarks {
11983eb3c573Smarks 	int error = 0;
11993eb3c573Smarks 	ace_t *acep;
12003eb3c573Smarks 	uint32_t bits;
12013eb3c573Smarks 	int i;
12023eb3c573Smarks 	ace_list_t *normacl = NULL, *dfacl = NULL, *acl;
12033eb3c573Smarks 	acevals_t *vals;
12043eb3c573Smarks 
12053eb3c573Smarks 	*aclentp = NULL;
12063eb3c573Smarks 	*aclcnt = 0;
12073eb3c573Smarks 	*dfaclentp = NULL;
12083eb3c573Smarks 	*dfaclcnt = 0;
12093eb3c573Smarks 
12103eb3c573Smarks 	/* we need at least user_obj, group_obj, and other_obj */
12113eb3c573Smarks 	if (n < 6) {
12123eb3c573Smarks 		error = ENOTSUP;
12133eb3c573Smarks 		goto out;
12143eb3c573Smarks 	}
12153eb3c573Smarks 	if (ace == NULL) {
12163eb3c573Smarks 		error = EINVAL;
12173eb3c573Smarks 		goto out;
12183eb3c573Smarks 	}
12193eb3c573Smarks 
12203eb3c573Smarks 	normacl = calloc(1, sizeof (ace_list_t));
12213eb3c573Smarks 
12223eb3c573Smarks 	if (normacl == NULL) {
12233eb3c573Smarks 		error = errno;
12243eb3c573Smarks 		goto out;
12253eb3c573Smarks 	}
12263eb3c573Smarks 
12273eb3c573Smarks 	avl_create(&normacl->user, acevals_compare, sizeof (acevals_t),
12283eb3c573Smarks 	    offsetof(acevals_t, avl));
12293eb3c573Smarks 	avl_create(&normacl->group, acevals_compare, sizeof (acevals_t),
12303eb3c573Smarks 	    offsetof(acevals_t, avl));
12313eb3c573Smarks 
12323eb3c573Smarks 	ace_list_init(normacl, 0);
12333eb3c573Smarks 
12343eb3c573Smarks 	dfacl = calloc(1, sizeof (ace_list_t));
12353eb3c573Smarks 	if (dfacl == NULL) {
12363eb3c573Smarks 		error = errno;
12373eb3c573Smarks 		goto out;
12383eb3c573Smarks 	}
12393eb3c573Smarks 	avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t),
12403eb3c573Smarks 	    offsetof(acevals_t, avl));
12413eb3c573Smarks 	avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t),
12423eb3c573Smarks 	    offsetof(acevals_t, avl));
12433eb3c573Smarks 	ace_list_init(dfacl, ACL_DEFAULT);
12443eb3c573Smarks 
12453eb3c573Smarks 	/* process every ace_t... */
12463eb3c573Smarks 	for (i = 0; i < n; i++) {
12473eb3c573Smarks 		acep = &ace[i];
12483eb3c573Smarks 
12493eb3c573Smarks 		/* rule out certain cases quickly */
12503eb3c573Smarks 		error = ace_to_aent_legal(acep);
12513eb3c573Smarks 		if (error != 0)
12523eb3c573Smarks 			goto out;
12533eb3c573Smarks 
12543eb3c573Smarks 		/*
12553eb3c573Smarks 		 * Turn off these bits in order to not have to worry about
12563eb3c573Smarks 		 * them when doing the checks for compliments.
12573eb3c573Smarks 		 */
12583eb3c573Smarks 		acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE |
12593eb3c573Smarks 		    ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES |
12603eb3c573Smarks 		    ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS);
12613eb3c573Smarks 
12623eb3c573Smarks 		/* see if this should be a regular or default acl */
12633eb3c573Smarks 		bits = acep->a_flags &
12643eb3c573Smarks 		    (ACE_INHERIT_ONLY_ACE |
12653eb3c573Smarks 		    ACE_FILE_INHERIT_ACE |
12663eb3c573Smarks 		    ACE_DIRECTORY_INHERIT_ACE);
12673eb3c573Smarks 		if (bits != 0) {
12683eb3c573Smarks 			/* all or nothing on these inherit bits */
12693eb3c573Smarks 			if (bits != (ACE_INHERIT_ONLY_ACE |
12703eb3c573Smarks 			    ACE_FILE_INHERIT_ACE |
12713eb3c573Smarks 			    ACE_DIRECTORY_INHERIT_ACE)) {
12723eb3c573Smarks 				error = ENOTSUP;
12733eb3c573Smarks 				goto out;
12743eb3c573Smarks 			}
12753eb3c573Smarks 			acl = dfacl;
12763eb3c573Smarks 		} else {
12773eb3c573Smarks 			acl = normacl;
12783eb3c573Smarks 		}
12793eb3c573Smarks 
12803eb3c573Smarks 		if ((acep->a_flags & ACE_OWNER)) {
12813eb3c573Smarks 			if (acl->state > ace_user_obj) {
12823eb3c573Smarks 				error = ENOTSUP;
12833eb3c573Smarks 				goto out;
12843eb3c573Smarks 			}
12853eb3c573Smarks 			acl->state = ace_user_obj;
12863eb3c573Smarks 			acl->seen |= USER_OBJ;
12873eb3c573Smarks 			vals = &acl->user_obj;
12883eb3c573Smarks 			vals->aent_type = USER_OBJ | acl->dfacl_flag;
12893eb3c573Smarks 		} else if ((acep->a_flags & ACE_EVERYONE)) {
12903eb3c573Smarks 			acl->state = ace_other_obj;
12913eb3c573Smarks 			acl->seen |= OTHER_OBJ;
12923eb3c573Smarks 			vals = &acl->other_obj;
12933eb3c573Smarks 			vals->aent_type = OTHER_OBJ | acl->dfacl_flag;
12943eb3c573Smarks 		} else if (acep->a_flags & ACE_IDENTIFIER_GROUP) {
12953eb3c573Smarks 			if (acl->state > ace_group) {
12963eb3c573Smarks 				error = ENOTSUP;
12973eb3c573Smarks 				goto out;
12983eb3c573Smarks 			}
12993eb3c573Smarks 			if ((acep->a_flags & ACE_GROUP)) {
13003eb3c573Smarks 				acl->seen |= GROUP_OBJ;
13013eb3c573Smarks 				vals = &acl->group_obj;
13023eb3c573Smarks 				vals->aent_type = GROUP_OBJ | acl->dfacl_flag;
13033eb3c573Smarks 			} else {
13043eb3c573Smarks 				acl->seen |= GROUP;
13053eb3c573Smarks 				vals = acevals_find(acep, &acl->group,
13063eb3c573Smarks 				    &acl->numgroups);
13073eb3c573Smarks 				if (vals == NULL) {
13083eb3c573Smarks 					error = ENOMEM;
13093eb3c573Smarks 					goto out;
13103eb3c573Smarks 				}
13113eb3c573Smarks 				vals->aent_type = GROUP | acl->dfacl_flag;
13123eb3c573Smarks 			}
13133eb3c573Smarks 			acl->state = ace_group;
13143eb3c573Smarks 		} else {
13153eb3c573Smarks 			if (acl->state > ace_user) {
13163eb3c573Smarks 				error = ENOTSUP;
13173eb3c573Smarks 				goto out;
13183eb3c573Smarks 			}
13193eb3c573Smarks 			acl->state = ace_user;
13203eb3c573Smarks 			acl->seen |= USER;
13213eb3c573Smarks 			vals = acevals_find(acep, &acl->user,
13223eb3c573Smarks 			    &acl->numusers);
13233eb3c573Smarks 			if (vals == NULL) {
13243eb3c573Smarks 				error = ENOMEM;
13253eb3c573Smarks 				goto out;
13263eb3c573Smarks 			}
13273eb3c573Smarks 			vals->aent_type = USER | acl->dfacl_flag;
13283eb3c573Smarks 		}
13293eb3c573Smarks 
13303eb3c573Smarks 		if (!(acl->state > ace_unused)) {
13313eb3c573Smarks 			error = EINVAL;
13323eb3c573Smarks 			goto out;
13333eb3c573Smarks 		}
13343eb3c573Smarks 
13353eb3c573Smarks 		if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
13363eb3c573Smarks 			/* no more than one allowed per aclent_t */
13373eb3c573Smarks 			if (vals->allowed != ACE_MASK_UNDEFINED) {
13383eb3c573Smarks 				error = ENOTSUP;
13393eb3c573Smarks 				goto out;
13403eb3c573Smarks 			}
13413eb3c573Smarks 			vals->allowed = acep->a_access_mask;
13423eb3c573Smarks 		} else {
13433eb3c573Smarks 			/*
13443eb3c573Smarks 			 * it's a DENY; if there was a previous DENY, it
13453eb3c573Smarks 			 * must have been an ACL_MASK.
13463eb3c573Smarks 			 */
13473eb3c573Smarks 			if (vals->denied != ACE_MASK_UNDEFINED) {
13483eb3c573Smarks 				/* ACL_MASK is for USER and GROUP only */
13493eb3c573Smarks 				if ((acl->state != ace_user) &&
13503eb3c573Smarks 				    (acl->state != ace_group)) {
13513eb3c573Smarks 					error = ENOTSUP;
13523eb3c573Smarks 					goto out;
13533eb3c573Smarks 				}
13543eb3c573Smarks 
13553eb3c573Smarks 				if (! acl->hasmask) {
13563eb3c573Smarks 					acl->hasmask = 1;
13573eb3c573Smarks 					acl->acl_mask = vals->denied;
13583eb3c573Smarks 				/* check for mismatched ACL_MASK emulations */
13593eb3c573Smarks 				} else if (acl->acl_mask != vals->denied) {
13603eb3c573Smarks 					error = ENOTSUP;
13613eb3c573Smarks 					goto out;
13623eb3c573Smarks 				}
13633eb3c573Smarks 				vals->mask = vals->denied;
13643eb3c573Smarks 			}
13653eb3c573Smarks 			vals->denied = acep->a_access_mask;
13663eb3c573Smarks 		}
13673eb3c573Smarks 	}
13683eb3c573Smarks 
13693eb3c573Smarks 	/* done collating; produce the aclent_t lists */
13703eb3c573Smarks 	if (normacl->state != ace_unused) {
13713eb3c573Smarks 		error = ace_list_to_aent(normacl, aclentp, aclcnt,
13723eb3c573Smarks 		    owner, group, isdir);
13733eb3c573Smarks 		if (error != 0) {
13743eb3c573Smarks 			goto out;
13753eb3c573Smarks 		}
13763eb3c573Smarks 	}
13773eb3c573Smarks 	if (dfacl->state != ace_unused) {
13783eb3c573Smarks 		error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt,
13793eb3c573Smarks 		    owner, group, isdir);
13803eb3c573Smarks 		if (error != 0) {
13813eb3c573Smarks 			goto out;
13823eb3c573Smarks 		}
13833eb3c573Smarks 	}
13843eb3c573Smarks 
13853eb3c573Smarks out:
13863eb3c573Smarks 	if (normacl != NULL)
13873eb3c573Smarks 		ace_list_free(normacl);
13883eb3c573Smarks 	if (dfacl != NULL)
13893eb3c573Smarks 		ace_list_free(dfacl);
13903eb3c573Smarks 
13913eb3c573Smarks 	return (error);
13923eb3c573Smarks }
13933eb3c573Smarks 
13943eb3c573Smarks static int
13953eb3c573Smarks convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir,
13963eb3c573Smarks     uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt)
13973eb3c573Smarks {
13983eb3c573Smarks 	int error;
13993eb3c573Smarks 	aclent_t *aclentp, *dfaclentp;
14003eb3c573Smarks 	int aclcnt, dfaclcnt;
14013eb3c573Smarks 
14023eb3c573Smarks 	error = ln_ace_to_aent(acebufp, acecnt, owner, group,
14033eb3c573Smarks 	    &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir);
14043eb3c573Smarks 
14053eb3c573Smarks 	if (error)
14063eb3c573Smarks 		return (error);
14073eb3c573Smarks 
14083eb3c573Smarks 
14093eb3c573Smarks 	if (dfaclcnt != 0) {
14103eb3c573Smarks 		/*
14113eb3c573Smarks 		 * Slap aclentp and dfaclentp into a single array.
14123eb3c573Smarks 		 */
14133eb3c573Smarks 		aclentp = realloc(aclentp, (sizeof (aclent_t) * aclcnt) +
14143eb3c573Smarks 		    (sizeof (aclent_t) * dfaclcnt));
14153eb3c573Smarks 		if (aclentp != NULL) {
14163eb3c573Smarks 			(void) memcpy(aclentp + aclcnt,
14173eb3c573Smarks 			    dfaclentp, sizeof (aclent_t) * dfaclcnt);
14183eb3c573Smarks 		} else {
14193eb3c573Smarks 			error = -1;
14203eb3c573Smarks 		}
14213eb3c573Smarks 	}
14223eb3c573Smarks 
14233eb3c573Smarks 	if (aclentp) {
14243eb3c573Smarks 		*retaclentp = aclentp;
14253eb3c573Smarks 		*retaclcnt = aclcnt + dfaclcnt;
14263eb3c573Smarks 	}
14273eb3c573Smarks 
14283eb3c573Smarks 	if (dfaclentp)
14293eb3c573Smarks 		free(dfaclentp);
14303eb3c573Smarks 
14313eb3c573Smarks 	return (error);
14323eb3c573Smarks }
14333eb3c573Smarks 
14340157963dSmarks static int
1435fa9e4066Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp)
1436fa9e4066Sahrens {
1437fa9e4066Sahrens 	const char *fname;
1438fa9e4066Sahrens 	int fd;
1439fa9e4066Sahrens 	int ace_acl = 0;
1440fa9e4066Sahrens 	int error;
1441fa9e4066Sahrens 	int getcmd, cntcmd;
1442fa9e4066Sahrens 	acl_t *acl_info;
1443fa9e4066Sahrens 	int	save_errno;
1444fa9e4066Sahrens 	int	stat_error;
1445fa9e4066Sahrens 	struct stat64 statbuf;
1446fa9e4066Sahrens 
1447fa9e4066Sahrens 	*aclp = NULL;
1448fa9e4066Sahrens 	if (type == ACL_PATH) {
1449fa9e4066Sahrens 		fname = inp.file;
1450fa9e4066Sahrens 		ace_acl = pathconf(fname, _PC_ACL_ENABLED);
1451fa9e4066Sahrens 	} else {
1452fa9e4066Sahrens 		fd = inp.fd;
1453fa9e4066Sahrens 		ace_acl = fpathconf(fd, _PC_ACL_ENABLED);
1454fa9e4066Sahrens 	}
1455fa9e4066Sahrens 
1456fa9e4066Sahrens 	/*
1457fa9e4066Sahrens 	 * if acl's aren't supported then
1458fa9e4066Sahrens 	 * send it through the old GETACL interface
1459fa9e4066Sahrens 	 */
1460*a222db82Smarks 	if (ace_acl == 0 || ace_acl == -1) {
1461fa9e4066Sahrens 		ace_acl = _ACL_ACLENT_ENABLED;
1462fa9e4066Sahrens 	}
1463fa9e4066Sahrens 
1464fa9e4066Sahrens 	if (ace_acl & _ACL_ACE_ENABLED) {
1465fa9e4066Sahrens 		cntcmd = ACE_GETACLCNT;
1466fa9e4066Sahrens 		getcmd = ACE_GETACL;
1467fa9e4066Sahrens 		acl_info = acl_alloc(ACE_T);
1468fa9e4066Sahrens 	} else {
1469fa9e4066Sahrens 		cntcmd = GETACLCNT;
1470fa9e4066Sahrens 		getcmd = GETACL;
1471fa9e4066Sahrens 		acl_info = acl_alloc(ACLENT_T);
1472fa9e4066Sahrens 	}
1473fa9e4066Sahrens 
1474fa9e4066Sahrens 	if (acl_info == NULL)
1475fa9e4066Sahrens 		return (-1);
1476fa9e4066Sahrens 
1477fa9e4066Sahrens 	if (type == ACL_PATH) {
1478fa9e4066Sahrens 		acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL);
1479fa9e4066Sahrens 	} else {
1480fa9e4066Sahrens 		acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL);
1481fa9e4066Sahrens 	}
1482fa9e4066Sahrens 
1483fa9e4066Sahrens 	save_errno = errno;
1484fa9e4066Sahrens 	if (acl_info->acl_cnt < 0) {
1485fa9e4066Sahrens 		acl_free(acl_info);
1486fa9e4066Sahrens 		errno = save_errno;
1487fa9e4066Sahrens 		return (-1);
1488fa9e4066Sahrens 	}
1489fa9e4066Sahrens 
1490fa9e4066Sahrens 	if (acl_info->acl_cnt == 0) {
1491fa9e4066Sahrens 		acl_free(acl_info);
1492fa9e4066Sahrens 		errno = save_errno;
1493fa9e4066Sahrens 		return (0);
1494fa9e4066Sahrens 	}
1495fa9e4066Sahrens 
1496fa9e4066Sahrens 	acl_info->acl_aclp =
1497fa9e4066Sahrens 	    malloc(acl_info->acl_cnt * acl_info->acl_entry_size);
1498fa9e4066Sahrens 	save_errno = errno;
1499fa9e4066Sahrens 
1500fa9e4066Sahrens 	if (acl_info->acl_aclp == NULL) {
1501fa9e4066Sahrens 		acl_free(acl_info);
1502fa9e4066Sahrens 		errno = save_errno;
1503fa9e4066Sahrens 		return (-1);
1504fa9e4066Sahrens 	}
1505fa9e4066Sahrens 
1506fa9e4066Sahrens 	if (type == ACL_PATH) {
1507fa9e4066Sahrens 		stat_error = stat64(fname, &statbuf);
1508fa9e4066Sahrens 		error = acl(fname, getcmd, acl_info->acl_cnt,
1509fa9e4066Sahrens 		    acl_info->acl_aclp);
1510fa9e4066Sahrens 	} else {
1511fa9e4066Sahrens 		stat_error = fstat64(fd, &statbuf);
1512fa9e4066Sahrens 		error = facl(fd, getcmd, acl_info->acl_cnt,
1513fa9e4066Sahrens 		    acl_info->acl_aclp);
1514fa9e4066Sahrens 	}
1515fa9e4066Sahrens 
1516fa9e4066Sahrens 	save_errno = errno;
1517fa9e4066Sahrens 	if (error == -1) {
1518fa9e4066Sahrens 		acl_free(acl_info);
1519fa9e4066Sahrens 		errno = save_errno;
1520fa9e4066Sahrens 		return (-1);
1521fa9e4066Sahrens 	}
1522fa9e4066Sahrens 
1523fa9e4066Sahrens 
1524fa9e4066Sahrens 	if (stat_error == 0) {
1525fa9e4066Sahrens 		acl_info->acl_flags =
1526fa9e4066Sahrens 		    (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0);
1527fa9e4066Sahrens 	} else
1528fa9e4066Sahrens 		acl_info->acl_flags = 0;
1529fa9e4066Sahrens 
1530fa9e4066Sahrens 	switch (acl_info->acl_type) {
1531fa9e4066Sahrens 	case ACLENT_T:
1532fa9e4066Sahrens 		if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
1533fa9e4066Sahrens 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
1534fa9e4066Sahrens 		break;
1535fa9e4066Sahrens 	case ACE_T:
1536fa9e4066Sahrens 		if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
1537fa9e4066Sahrens 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
1538fa9e4066Sahrens 		break;
1539fa9e4066Sahrens 	default:
1540fa9e4066Sahrens 		errno = EINVAL;
1541fa9e4066Sahrens 		acl_free(acl_info);
1542fa9e4066Sahrens 		return (-1);
1543fa9e4066Sahrens 	}
1544fa9e4066Sahrens 
1545fa9e4066Sahrens 	if ((acl_info->acl_flags & ACL_IS_TRIVIAL) &&
1546fa9e4066Sahrens 	    (get_flag & ACL_NO_TRIVIAL)) {
1547fa9e4066Sahrens 		acl_free(acl_info);
1548fa9e4066Sahrens 		errno = 0;
1549fa9e4066Sahrens 		return (0);
1550fa9e4066Sahrens 	}
1551fa9e4066Sahrens 
1552fa9e4066Sahrens 	*aclp = acl_info;
1553fa9e4066Sahrens 	return (0);
1554fa9e4066Sahrens }
1555fa9e4066Sahrens 
1556fa9e4066Sahrens /*
1557fa9e4066Sahrens  * return -1 on failure, otherwise the number of acl
1558fa9e4066Sahrens  * entries is returned
1559fa9e4066Sahrens  */
1560fa9e4066Sahrens int
1561fa9e4066Sahrens acl_get(const char *path, int get_flag, acl_t **aclp)
1562fa9e4066Sahrens {
1563fa9e4066Sahrens 	acl_inp acl_inp;
1564fa9e4066Sahrens 	acl_inp.file = path;
1565fa9e4066Sahrens 
1566fa9e4066Sahrens 	return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp));
1567fa9e4066Sahrens }
1568fa9e4066Sahrens 
1569fa9e4066Sahrens int
1570fa9e4066Sahrens facl_get(int fd, int get_flag, acl_t **aclp)
1571fa9e4066Sahrens {
1572fa9e4066Sahrens 
1573fa9e4066Sahrens 	acl_inp acl_inp;
1574fa9e4066Sahrens 	acl_inp.fd = fd;
1575fa9e4066Sahrens 
1576fa9e4066Sahrens 	return (cacl_get(acl_inp, get_flag, ACL_FD, aclp));
1577fa9e4066Sahrens }
1578fa9e4066Sahrens 
15793eb3c573Smarks static int
15803eb3c573Smarks acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner,
15813eb3c573Smarks     gid_t group)
15823eb3c573Smarks {
15833eb3c573Smarks 	int aclcnt;
15843eb3c573Smarks 	void *acldata;
15853eb3c573Smarks 	int error;
15863eb3c573Smarks 
15873eb3c573Smarks 	/*
15883eb3c573Smarks 	 * See if we need to translate
15893eb3c573Smarks 	 */
15903eb3c573Smarks 	if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) ||
15913eb3c573Smarks 	    (target_flavor == _ACL_ACLENT_ENABLED &&
15923eb3c573Smarks 	    aclp->acl_type == ACLENT_T))
15933eb3c573Smarks 		return (0);
15943eb3c573Smarks 
15953eb3c573Smarks 	if (target_flavor == -1)
15963eb3c573Smarks 		return (-1);
15973eb3c573Smarks 
15983eb3c573Smarks 	if (target_flavor ==  _ACL_ACE_ENABLED &&
15993eb3c573Smarks 	    aclp->acl_type == ACLENT_T) {
16003eb3c573Smarks 		error = convert_aent_to_ace(aclp->acl_aclp,
16013eb3c573Smarks 		    aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt);
16023eb3c573Smarks 		if (error) {
16033eb3c573Smarks 			errno = error;
16043eb3c573Smarks 			return (-1);
16053eb3c573Smarks 		}
16063eb3c573Smarks 	} else if (target_flavor == _ACL_ACLENT_ENABLED &&
16073eb3c573Smarks 	    aclp->acl_type == ACE_T) {
16083eb3c573Smarks 		error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt,
16093eb3c573Smarks 		    isdir, owner, group, (aclent_t **)&acldata, &aclcnt);
16103eb3c573Smarks 		if (error) {
16113eb3c573Smarks 			errno = error;
16123eb3c573Smarks 			return (-1);
16133eb3c573Smarks 		}
16143eb3c573Smarks 	} else {
16153eb3c573Smarks 		errno = ENOTSUP;
16163eb3c573Smarks 		return (-1);
16173eb3c573Smarks 	}
16183eb3c573Smarks 
16193eb3c573Smarks 	/*
16203eb3c573Smarks 	 * replace old acl with newly translated acl
16213eb3c573Smarks 	 */
16223eb3c573Smarks 	free(aclp->acl_aclp);
16233eb3c573Smarks 	aclp->acl_aclp = acldata;
16243eb3c573Smarks 	aclp->acl_cnt = aclcnt;
16253eb3c573Smarks 	aclp->acl_type = (target_flavor == _ACL_ACE_ENABLED) ? ACE_T : ACLENT_T;
16263eb3c573Smarks 	return (0);
16273eb3c573Smarks }
16283eb3c573Smarks 
1629fa9e4066Sahrens /*
1630fa9e4066Sahrens  * Set an ACL, translates acl to ace_t when appropriate.
1631fa9e4066Sahrens  */
1632fa9e4066Sahrens static int
1633fa9e4066Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type)
1634fa9e4066Sahrens {
1635fa9e4066Sahrens 	int error = 0;
1636fa9e4066Sahrens 	int acl_flavor_target;
1637fa9e4066Sahrens 	struct stat64 statbuf;
1638fa9e4066Sahrens 	int stat_error;
1639fa9e4066Sahrens 	int isdir;
1640fa9e4066Sahrens 
1641fa9e4066Sahrens 
1642fa9e4066Sahrens 	if (type == ACL_PATH) {
1643fa9e4066Sahrens 		stat_error = stat64(acl_inp->file, &statbuf);
1644fa9e4066Sahrens 		if (stat_error)
1645fa9e4066Sahrens 			return (-1);
1646fa9e4066Sahrens 		acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED);
1647fa9e4066Sahrens 	} else {
1648fa9e4066Sahrens 		stat_error = fstat64(acl_inp->fd, &statbuf);
1649fa9e4066Sahrens 		if (stat_error)
1650fa9e4066Sahrens 			return (-1);
1651fa9e4066Sahrens 		acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED);
1652fa9e4066Sahrens 	}
1653fa9e4066Sahrens 
1654*a222db82Smarks 	/*
1655*a222db82Smarks 	 * If target returns an error or 0 from pathconf call then
1656*a222db82Smarks 	 * fall back to UFS/POSIX Draft interface.
1657*a222db82Smarks 	 * In the case of 0 we will then fail in either acl(2) or
1658*a222db82Smarks 	 * acl_translate().  We could erroneously get 0 back from
1659*a222db82Smarks 	 * a file system that is using fs_pathconf() and not answering
1660*a222db82Smarks 	 * the _PC_ACL_ENABLED question itself.
1661*a222db82Smarks 	 */
1662*a222db82Smarks 	if (acl_flavor_target == 0 || acl_flavor_target == -1)
1663*a222db82Smarks 		acl_flavor_target = _ACL_ACLENT_ENABLED;
1664*a222db82Smarks 
1665fa9e4066Sahrens 	isdir = S_ISDIR(statbuf.st_mode);
1666fa9e4066Sahrens 
16673eb3c573Smarks 	if ((error = acl_translate(aclp, acl_flavor_target, isdir,
16683eb3c573Smarks 	    statbuf.st_uid, statbuf.st_gid)) != 0) {
16693eb3c573Smarks 		return (error);
1670fa9e4066Sahrens 	}
1671fa9e4066Sahrens 
1672fa9e4066Sahrens 	if (type == ACL_PATH) {
1673fa9e4066Sahrens 		error = acl(acl_inp->file,
1674fa9e4066Sahrens 		    (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL,
1675fa9e4066Sahrens 		    aclp->acl_cnt, aclp->acl_aclp);
1676fa9e4066Sahrens 	} else {
1677fa9e4066Sahrens 		error = facl(acl_inp->fd,
1678fa9e4066Sahrens 		    (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL,
1679fa9e4066Sahrens 		    aclp->acl_cnt, aclp->acl_aclp);
1680fa9e4066Sahrens 	}
1681fa9e4066Sahrens 
1682fa9e4066Sahrens 	return (error);
1683fa9e4066Sahrens }
1684fa9e4066Sahrens 
1685fa9e4066Sahrens int
1686fa9e4066Sahrens acl_set(const char *path, acl_t *aclp)
1687fa9e4066Sahrens {
1688fa9e4066Sahrens 	acl_inp acl_inp;
1689fa9e4066Sahrens 
1690fa9e4066Sahrens 	acl_inp.file = path;
1691fa9e4066Sahrens 
1692fa9e4066Sahrens 	return (cacl_set(&acl_inp, aclp, ACL_PATH));
1693fa9e4066Sahrens }
1694fa9e4066Sahrens 
1695fa9e4066Sahrens int
1696fa9e4066Sahrens facl_set(int fd, acl_t *aclp)
1697fa9e4066Sahrens {
1698fa9e4066Sahrens 	acl_inp acl_inp;
1699fa9e4066Sahrens 
1700fa9e4066Sahrens 	acl_inp.fd = fd;
1701fa9e4066Sahrens 
1702fa9e4066Sahrens 	return (cacl_set(&acl_inp, aclp, ACL_FD));
1703fa9e4066Sahrens }
1704fa9e4066Sahrens 
1705fa9e4066Sahrens int
1706fa9e4066Sahrens acl_cnt(acl_t *aclp)
1707fa9e4066Sahrens {
1708fa9e4066Sahrens 	return (aclp->acl_cnt);
1709fa9e4066Sahrens }
1710fa9e4066Sahrens 
1711fa9e4066Sahrens int
1712fa9e4066Sahrens acl_type(acl_t *aclp)
1713fa9e4066Sahrens {
1714fa9e4066Sahrens 	return (aclp->acl_type);
1715fa9e4066Sahrens }
1716fa9e4066Sahrens 
1717fa9e4066Sahrens acl_t *
1718fa9e4066Sahrens acl_dup(acl_t *aclp)
1719fa9e4066Sahrens {
1720fa9e4066Sahrens 	acl_t *newaclp;
1721fa9e4066Sahrens 
1722fa9e4066Sahrens 	newaclp = acl_alloc(aclp->acl_type);
1723fa9e4066Sahrens 	if (newaclp == NULL)
1724fa9e4066Sahrens 		return (NULL);
1725fa9e4066Sahrens 
1726fa9e4066Sahrens 	newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt);
1727fa9e4066Sahrens 	if (newaclp->acl_aclp == NULL) {
1728fa9e4066Sahrens 		acl_free(newaclp);
1729fa9e4066Sahrens 		return (NULL);
1730fa9e4066Sahrens 	}
1731fa9e4066Sahrens 
1732fa9e4066Sahrens 	(void) memcpy(newaclp->acl_aclp,
1733fa9e4066Sahrens 	    aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt);
1734fa9e4066Sahrens 	newaclp->acl_cnt = aclp->acl_cnt;
1735fa9e4066Sahrens 
1736fa9e4066Sahrens 	return (newaclp);
1737fa9e4066Sahrens }
1738fa9e4066Sahrens 
1739fa9e4066Sahrens int
1740fa9e4066Sahrens acl_flags(acl_t *aclp)
1741fa9e4066Sahrens {
1742fa9e4066Sahrens 	return (aclp->acl_flags);
1743fa9e4066Sahrens }
1744fa9e4066Sahrens 
1745fa9e4066Sahrens void *
1746fa9e4066Sahrens acl_data(acl_t *aclp)
1747fa9e4066Sahrens {
1748fa9e4066Sahrens 	return (aclp->acl_aclp);
1749fa9e4066Sahrens }
1750fa9e4066Sahrens 
1751fa9e4066Sahrens /*
1752fa9e4066Sahrens  * Remove an ACL from a file and create a trivial ACL based
1753fa9e4066Sahrens  * off of the mode argument.  After acl has been set owner/group
1754fa9e4066Sahrens  * are updated to match owner,group arguments
1755fa9e4066Sahrens  */
1756fa9e4066Sahrens int
1757fa9e4066Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode)
1758fa9e4066Sahrens {
1759fa9e4066Sahrens 	int	error = 0;
1760fa9e4066Sahrens 	aclent_t min_acl[MIN_ACL_ENTRIES];
1761fa9e4066Sahrens 	ace_t	min_ace_acl[6];	/* owner, group, everyone + complement denies */
1762fa9e4066Sahrens 	int	acl_flavor;
1763fa9e4066Sahrens 	int	aclcnt;
1764fa9e4066Sahrens 
1765fa9e4066Sahrens 	acl_flavor = pathconf(file, _PC_ACL_ENABLED);
1766fa9e4066Sahrens 
1767fa9e4066Sahrens 	/*
1768fa9e4066Sahrens 	 * force it through aclent flavor when file system doesn't
1769fa9e4066Sahrens 	 * understand question
1770fa9e4066Sahrens 	 */
1771*a222db82Smarks 	if (acl_flavor == 0 || acl_flavor == -1)
1772fa9e4066Sahrens 		acl_flavor = _ACL_ACLENT_ENABLED;
1773fa9e4066Sahrens 
1774fa9e4066Sahrens 	if (acl_flavor & _ACL_ACLENT_ENABLED) {
1775fa9e4066Sahrens 		min_acl[0].a_type = USER_OBJ;
1776fa9e4066Sahrens 		min_acl[0].a_id   = owner;
1777fa9e4066Sahrens 		min_acl[0].a_perm = ((mode & 0700) >> 6);
1778fa9e4066Sahrens 		min_acl[1].a_type = GROUP_OBJ;
1779fa9e4066Sahrens 		min_acl[1].a_id   = group;
1780fa9e4066Sahrens 		min_acl[1].a_perm = ((mode & 0070) >> 3);
1781fa9e4066Sahrens 		min_acl[2].a_type = CLASS_OBJ;
1782fa9e4066Sahrens 		min_acl[2].a_id   = (uid_t)-1;
1783fa9e4066Sahrens 		min_acl[2].a_perm = ((mode & 0070) >> 3);
1784fa9e4066Sahrens 		min_acl[3].a_type = OTHER_OBJ;
1785fa9e4066Sahrens 		min_acl[3].a_id   = (uid_t)-1;
1786fa9e4066Sahrens 		min_acl[3].a_perm = (mode & 0007);
1787fa9e4066Sahrens 		aclcnt = 4;
1788fa9e4066Sahrens 		error = acl(file, SETACL, aclcnt, min_acl);
1789fa9e4066Sahrens 	} else if (acl_flavor & _ACL_ACE_ENABLED) {
1790fa9e4066Sahrens 		(void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6);
1791fa9e4066Sahrens 
1792fa9e4066Sahrens 		/*
1793fa9e4066Sahrens 		 * Make aces match request mode
1794fa9e4066Sahrens 		 */
1795fa9e4066Sahrens 		adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6);
1796fa9e4066Sahrens 		adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3);
1797fa9e4066Sahrens 		adjust_ace_pair(&min_ace_acl[4], mode & 0007);
1798fa9e4066Sahrens 
1799fa9e4066Sahrens 		error = acl(file, ACE_SETACL, 6, min_ace_acl);
1800fa9e4066Sahrens 	} else {
1801fa9e4066Sahrens 		errno = EINVAL;
1802fa9e4066Sahrens 		error = 1;
1803fa9e4066Sahrens 	}
1804fa9e4066Sahrens 
1805fa9e4066Sahrens 	if (error == 0)
1806fa9e4066Sahrens 		error = chown(file, owner, group);
1807fa9e4066Sahrens 	return (error);
1808fa9e4066Sahrens }
1809fa9e4066Sahrens 
1810fa9e4066Sahrens static int
1811fa9e4066Sahrens ace_match(void *entry1, void *entry2)
1812fa9e4066Sahrens {
1813fa9e4066Sahrens 	ace_t *p1 = (ace_t *)entry1;
1814fa9e4066Sahrens 	ace_t *p2 = (ace_t *)entry2;
1815fa9e4066Sahrens 	ace_t ace1, ace2;
1816fa9e4066Sahrens 
1817fa9e4066Sahrens 	ace1 = *p1;
1818fa9e4066Sahrens 	ace2 = *p2;
1819fa9e4066Sahrens 
1820fa9e4066Sahrens 	/*
1821fa9e4066Sahrens 	 * Need to fixup who field for abstrations for
1822fa9e4066Sahrens 	 * accurate comparison, since field is undefined.
1823fa9e4066Sahrens 	 */
1824fa9e4066Sahrens 	if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
1825fa9e4066Sahrens 		ace1.a_who = -1;
1826fa9e4066Sahrens 	if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
1827fa9e4066Sahrens 		ace2.a_who = -1;
1828fa9e4066Sahrens 	return (memcmp(&ace1, &ace2, sizeof (ace_t)));
1829fa9e4066Sahrens }
1830fa9e4066Sahrens 
1831fa9e4066Sahrens static int
1832fa9e4066Sahrens aclent_match(void *entry1, void *entry2)
1833fa9e4066Sahrens {
1834fa9e4066Sahrens 	aclent_t *aclent1 = (aclent_t *)entry1;
1835fa9e4066Sahrens 	aclent_t *aclent2 = (aclent_t *)entry2;
1836fa9e4066Sahrens 
1837fa9e4066Sahrens 	return (memcmp(aclent1, aclent2, sizeof (aclent_t)));
1838fa9e4066Sahrens }
1839fa9e4066Sahrens 
1840fa9e4066Sahrens /*
1841fa9e4066Sahrens  * Find acl entries in acl that correspond to removeacl.  Search
1842fa9e4066Sahrens  * is started from slot.  The flag argument indicates whether to
1843fa9e4066Sahrens  * remove all matches or just the first match.
1844fa9e4066Sahrens  */
1845fa9e4066Sahrens int
1846fa9e4066Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag)
1847fa9e4066Sahrens {
1848fa9e4066Sahrens 	int i, j;
1849fa9e4066Sahrens 	int match;
1850fa9e4066Sahrens 	int (*acl_match)(void *acl1, void *acl2);
1851fa9e4066Sahrens 	void *acl_entry, *remove_entry;
1852fa9e4066Sahrens 	void *start;
1853fa9e4066Sahrens 	int found = 0;
1854fa9e4066Sahrens 
1855fa9e4066Sahrens 	if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST)
1856fa9e4066Sahrens 		flag = ACL_REMOVE_FIRST;
1857fa9e4066Sahrens 
1858fa9e4066Sahrens 	if (acl == NULL || removeacl == NULL)
1859fa9e4066Sahrens 		return (EACL_NO_ACL_ENTRY);
1860fa9e4066Sahrens 
1861fa9e4066Sahrens 	if (acl->acl_type != removeacl->acl_type)
1862fa9e4066Sahrens 		return (EACL_DIFF_TYPE);
1863fa9e4066Sahrens 
1864fa9e4066Sahrens 	if (acl->acl_type == ACLENT_T)
1865fa9e4066Sahrens 		acl_match = aclent_match;
1866fa9e4066Sahrens 	else
1867fa9e4066Sahrens 		acl_match = ace_match;
1868fa9e4066Sahrens 
1869fa9e4066Sahrens 	for (i = 0, remove_entry = removeacl->acl_aclp;
1870fa9e4066Sahrens 	    i != removeacl->acl_cnt; i++) {
1871fa9e4066Sahrens 
1872fa9e4066Sahrens 		j = 0;
1873fa9e4066Sahrens 		acl_entry = (char *)acl->acl_aclp +
1874fa9e4066Sahrens 		    (acl->acl_entry_size * start_slot);
1875fa9e4066Sahrens 		for (;;) {
1876fa9e4066Sahrens 			match = acl_match(acl_entry, remove_entry);
1877fa9e4066Sahrens 			if (match == 0)  {
1878fa9e4066Sahrens 				found++;
1879fa9e4066Sahrens 				start = (char *)acl_entry +
1880fa9e4066Sahrens 				    acl->acl_entry_size;
1881fa9e4066Sahrens 				(void) memmove(acl_entry, start,
1882fa9e4066Sahrens 				    acl->acl_entry_size *
1883fa9e4066Sahrens 				    acl->acl_cnt-- - (j + 1));
1884fa9e4066Sahrens 
1885fa9e4066Sahrens 				if (flag == ACL_REMOVE_FIRST)
1886fa9e4066Sahrens 					break;
1887fa9e4066Sahrens 				/*
1888fa9e4066Sahrens 				 * List has changed, restart search from
1889fa9e4066Sahrens 				 * beginning.
1890fa9e4066Sahrens 				 */
1891fa9e4066Sahrens 				acl_entry = acl->acl_aclp;
1892fa9e4066Sahrens 				j = 0;
1893fa9e4066Sahrens 				continue;
1894fa9e4066Sahrens 			}
1895fa9e4066Sahrens 			acl_entry = ((char *)acl_entry + acl->acl_entry_size);
1896fa9e4066Sahrens 			if (++j >= acl->acl_cnt) {
1897fa9e4066Sahrens 				break;
1898fa9e4066Sahrens 			}
1899fa9e4066Sahrens 		}
1900fa9e4066Sahrens 	}
1901fa9e4066Sahrens 
1902fa9e4066Sahrens 	return ((found == 0) ? EACL_NO_ACL_ENTRY : 0);
1903fa9e4066Sahrens }
1904fa9e4066Sahrens 
1905fa9e4066Sahrens /*
1906fa9e4066Sahrens  * Replace entires entries in acl1 with the corresponding entries
1907fa9e4066Sahrens  * in newentries.  The where argument specifies where to begin
1908fa9e4066Sahrens  * the replacement.  If the where argument is 1 greater than the
1909fa9e4066Sahrens  * number of acl entries in acl1 then they are appended.  If the
1910fa9e4066Sahrens  * where argument is 2+ greater than the number of acl entries then
1911fa9e4066Sahrens  * EACL_INVALID_SLOT is returned.
1912fa9e4066Sahrens  */
1913fa9e4066Sahrens int
1914fa9e4066Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where)
1915fa9e4066Sahrens {
1916fa9e4066Sahrens 
1917fa9e4066Sahrens 	int slot;
1918fa9e4066Sahrens 	int slots_needed;
1919fa9e4066Sahrens 	int slots_left;
1920fa9e4066Sahrens 	int newsize;
1921fa9e4066Sahrens 
1922fa9e4066Sahrens 	if (acl1 == NULL || newentries == NULL)
1923fa9e4066Sahrens 		return (EACL_NO_ACL_ENTRY);
1924fa9e4066Sahrens 
1925fa9e4066Sahrens 	if (where < 0 || where >= acl1->acl_cnt)
1926fa9e4066Sahrens 		return (EACL_INVALID_SLOT);
1927fa9e4066Sahrens 
1928fa9e4066Sahrens 	if (acl1->acl_type != newentries->acl_type)
1929fa9e4066Sahrens 		return (EACL_DIFF_TYPE);
1930fa9e4066Sahrens 
1931fa9e4066Sahrens 	slot = where;
1932fa9e4066Sahrens 
1933fa9e4066Sahrens 	slots_left = acl1->acl_cnt - slot + 1;
1934fa9e4066Sahrens 	if (slots_left < newentries->acl_cnt) {
1935fa9e4066Sahrens 		slots_needed = newentries->acl_cnt - slots_left;
1936fa9e4066Sahrens 		newsize = (acl1->acl_entry_size * acl1->acl_cnt) +
1937fa9e4066Sahrens 		    (acl1->acl_entry_size * slots_needed);
1938fa9e4066Sahrens 		acl1->acl_aclp = realloc(acl1->acl_aclp, newsize);
1939fa9e4066Sahrens 		if (acl1->acl_aclp == NULL)
1940fa9e4066Sahrens 			return (-1);
1941fa9e4066Sahrens 	}
1942fa9e4066Sahrens 	(void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot),
1943fa9e4066Sahrens 	    newentries->acl_aclp,
1944fa9e4066Sahrens 	    newentries->acl_entry_size * newentries->acl_cnt);
1945fa9e4066Sahrens 
1946fa9e4066Sahrens 	/*
1947fa9e4066Sahrens 	 * Did ACL grow?
1948fa9e4066Sahrens 	 */
1949fa9e4066Sahrens 
1950fa9e4066Sahrens 	if ((slot + newentries->acl_cnt) > acl1->acl_cnt) {
1951fa9e4066Sahrens 		acl1->acl_cnt = slot + newentries->acl_cnt;
1952fa9e4066Sahrens 	}
1953fa9e4066Sahrens 
1954fa9e4066Sahrens 	return (0);
1955fa9e4066Sahrens }
1956fa9e4066Sahrens 
1957fa9e4066Sahrens /*
1958fa9e4066Sahrens  * Add acl2 entries into acl1.  The where argument specifies where
1959fa9e4066Sahrens  * to add the entries.
1960fa9e4066Sahrens  */
1961fa9e4066Sahrens int
1962fa9e4066Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where)
1963fa9e4066Sahrens {
1964fa9e4066Sahrens 
1965fa9e4066Sahrens 	int newsize;
1966fa9e4066Sahrens 	int len;
1967fa9e4066Sahrens 	void *start;
1968fa9e4066Sahrens 	void *to;
1969fa9e4066Sahrens 
1970fa9e4066Sahrens 	if (acl1 == NULL || acl2 == NULL)
1971fa9e4066Sahrens 		return (EACL_NO_ACL_ENTRY);
1972fa9e4066Sahrens 
1973fa9e4066Sahrens 	if (acl1->acl_type != acl2->acl_type)
1974fa9e4066Sahrens 		return (EACL_DIFF_TYPE);
1975fa9e4066Sahrens 
1976fa9e4066Sahrens 	/*
1977fa9e4066Sahrens 	 * allow where to specify 1 past last slot for an append operation
1978fa9e4066Sahrens 	 * but anything greater is an error.
1979fa9e4066Sahrens 	 */
1980fa9e4066Sahrens 	if (where < 0 || where > acl1->acl_cnt)
1981fa9e4066Sahrens 		return (EACL_INVALID_SLOT);
1982fa9e4066Sahrens 
1983fa9e4066Sahrens 	newsize = (acl2->acl_entry_size * acl2->acl_cnt) +
1984fa9e4066Sahrens 	    (acl1->acl_entry_size * acl1->acl_cnt);
1985fa9e4066Sahrens 	acl1->acl_aclp = realloc(acl1->acl_aclp, newsize);
1986fa9e4066Sahrens 	if (acl1->acl_aclp == NULL)
1987fa9e4066Sahrens 		return (-1);
1988fa9e4066Sahrens 
1989fa9e4066Sahrens 	/*
1990fa9e4066Sahrens 	 * first push down entries where new ones will be inserted
1991fa9e4066Sahrens 	 */
1992fa9e4066Sahrens 
1993fa9e4066Sahrens 	to = (void *)((char *)acl1->acl_aclp +
1994fa9e4066Sahrens 	    ((where + acl2->acl_cnt) * acl1->acl_entry_size));
1995fa9e4066Sahrens 
1996fa9e4066Sahrens 	start = (void *)((char *)acl1->acl_aclp +
1997fa9e4066Sahrens 	    where * acl1->acl_entry_size);
1998fa9e4066Sahrens 
1999fa9e4066Sahrens 	if (where < acl1->acl_cnt) {
2000fa9e4066Sahrens 		len = (acl1->acl_cnt - where) * acl1->acl_entry_size;
2001fa9e4066Sahrens 		(void) memmove(to, start, len);
2002fa9e4066Sahrens 	}
2003fa9e4066Sahrens 
2004fa9e4066Sahrens 	/*
2005fa9e4066Sahrens 	 * now stick in new entries.
2006fa9e4066Sahrens 	 */
2007fa9e4066Sahrens 
2008fa9e4066Sahrens 	(void) memmove(start, acl2->acl_aclp,
2009fa9e4066Sahrens 	    acl2->acl_cnt * acl2->acl_entry_size);
2010fa9e4066Sahrens 
2011fa9e4066Sahrens 	acl1->acl_cnt += acl2->acl_cnt;
2012fa9e4066Sahrens 	return (0);
2013fa9e4066Sahrens }
2014fa9e4066Sahrens 
2015fa9e4066Sahrens /*
2016fa9e4066Sahrens  * return text for an ACL error.
2017fa9e4066Sahrens  */
2018fa9e4066Sahrens char *
2019fa9e4066Sahrens acl_strerror(int errnum)
2020fa9e4066Sahrens {
2021fa9e4066Sahrens 	switch (errnum) {
2022fa9e4066Sahrens 	case EACL_GRP_ERROR:
2023fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
20245a5eeccaSmarks 		    "There is more than one group or default group entry"));
2025fa9e4066Sahrens 	case EACL_USER_ERROR:
2026fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
20275a5eeccaSmarks 		    "There is more than one user or default user entry"));
2028fa9e4066Sahrens 	case EACL_OTHER_ERROR:
2029fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2030fa9e4066Sahrens 		    "There is more than one other entry"));
2031fa9e4066Sahrens 	case EACL_CLASS_ERROR:
2032fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2033fa9e4066Sahrens 		    "There is more than one mask entry"));
2034fa9e4066Sahrens 	case EACL_DUPLICATE_ERROR:
2035fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2036fa9e4066Sahrens 		    "Duplicate user or group entries"));
2037fa9e4066Sahrens 	case EACL_MISS_ERROR:
2038fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2039fa9e4066Sahrens 		    "Missing user/group owner, other, mask entry"));
2040fa9e4066Sahrens 	case EACL_MEM_ERROR:
2041fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2042fa9e4066Sahrens 		    "Memory error"));
2043fa9e4066Sahrens 	case EACL_ENTRY_ERROR:
2044fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2045fa9e4066Sahrens 		    "Unrecognized entry type"));
2046fa9e4066Sahrens 	case EACL_INHERIT_ERROR:
2047fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2048fa9e4066Sahrens 		    "Invalid inheritance flags"));
2049fa9e4066Sahrens 	case EACL_FLAGS_ERROR:
2050fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2051fa9e4066Sahrens 		    "Unrecognized entry flags"));
2052fa9e4066Sahrens 	case EACL_PERM_MASK_ERROR:
2053fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2054fa9e4066Sahrens 		    "Invalid ACL permissions"));
2055fa9e4066Sahrens 	case EACL_COUNT_ERROR:
2056fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2057fa9e4066Sahrens 		    "Invalid ACL count"));
2058fa9e4066Sahrens 	case EACL_INVALID_SLOT:
2059fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2060fa9e4066Sahrens 		    "Invalid ACL entry number specified"));
2061fa9e4066Sahrens 	case EACL_NO_ACL_ENTRY:
2062fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2063fa9e4066Sahrens 		    "ACL entry doesn't exist"));
2064fa9e4066Sahrens 	case EACL_DIFF_TYPE:
2065fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2066fa9e4066Sahrens 		    "ACL type's are different"));
2067fa9e4066Sahrens 	case EACL_INVALID_USER_GROUP:
2068fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Invalid user or group"));
2069fa9e4066Sahrens 	case EACL_INVALID_STR:
2070fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "ACL string is invalid"));
2071fa9e4066Sahrens 	case EACL_FIELD_NOT_BLANK:
2072fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Field expected to be blank"));
2073fa9e4066Sahrens 	case EACL_INVALID_ACCESS_TYPE:
2074fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Invalid access type"));
2075fa9e4066Sahrens 	case EACL_UNKNOWN_DATA:
2076fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Unrecognized entry"));
2077fa9e4066Sahrens 	case EACL_MISSING_FIELDS:
2078fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2079fa9e4066Sahrens 		    "ACL specification missing required fields"));
2080fa9e4066Sahrens 	case EACL_INHERIT_NOTDIR:
2081fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
2082fa9e4066Sahrens 		    "Inheritance flags are only allowed on directories"));
2083fa9e4066Sahrens 	case -1:
2084fa9e4066Sahrens 		return (strerror(errno));
2085fa9e4066Sahrens 	default:
2086fa9e4066Sahrens 		errno = EINVAL;
2087fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Unknown error"));
2088fa9e4066Sahrens 	}
2089fa9e4066Sahrens }
20905a5eeccaSmarks 
20915a5eeccaSmarks extern int yyinteractive;
20925a5eeccaSmarks 
20935a5eeccaSmarks /* PRINTFLIKE1 */
20945a5eeccaSmarks void
20955a5eeccaSmarks acl_error(const char *fmt, ...)
20965a5eeccaSmarks {
20975a5eeccaSmarks 	va_list va;
20985a5eeccaSmarks 
20995a5eeccaSmarks 	if (yyinteractive == 0)
21005a5eeccaSmarks 		return;
21015a5eeccaSmarks 
21025a5eeccaSmarks 	va_start(va, fmt);
21035a5eeccaSmarks 	(void) vfprintf(stderr, fmt, va);
21045a5eeccaSmarks 	va_end(va);
21055a5eeccaSmarks }
2106