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