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