xref: /titanic_53/usr/src/lib/libsec/common/aclutils.c (revision 5a5eeccada4b11bc692e9a5015d5f4a4f188226c)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5fa9e4066Sahrens  * Common Development and Distribution License, Version 1.0 only
6fa9e4066Sahrens  * (the "License").  You may not use this file except in compliance
7fa9e4066Sahrens  * with the License.
8fa9e4066Sahrens  *
9fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
11fa9e4066Sahrens  * See the License for the specific language governing permissions
12fa9e4066Sahrens  * and limitations under the License.
13fa9e4066Sahrens  *
14fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
15fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
17fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
18fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
19fa9e4066Sahrens  *
20fa9e4066Sahrens  * CDDL HEADER END
21fa9e4066Sahrens  */
22fa9e4066Sahrens /*
23d2443e76Smarks  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28fa9e4066Sahrens 
29fa9e4066Sahrens #include <stdlib.h>
30fa9e4066Sahrens #include <string.h>
31fa9e4066Sahrens #include <unistd.h>
32fa9e4066Sahrens #include <limits.h>
33fa9e4066Sahrens #include <grp.h>
34fa9e4066Sahrens #include <pwd.h>
35fa9e4066Sahrens #include <sys/types.h>
36fa9e4066Sahrens #include <sys/acl.h>
37fa9e4066Sahrens #include <errno.h>
38fa9e4066Sahrens #include <sys/stat.h>
39*5a5eeccaSmarks #include <sys/varargs.h>
40fa9e4066Sahrens #include <locale.h>
41fa9e4066Sahrens #include <aclutils.h>
42fa9e4066Sahrens #include <acl_common.h>
43fa9e4066Sahrens 
44fa9e4066Sahrens #define	ACL_PATH	0
45fa9e4066Sahrens #define	ACL_FD		1
46fa9e4066Sahrens 
47fa9e4066Sahrens #define	ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \
48fa9e4066Sahrens     ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \
49fa9e4066Sahrens     ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL)
50fa9e4066Sahrens 
51fa9e4066Sahrens 
52fa9e4066Sahrens #define	ACL_SYNCHRONIZE_SET_ALLOW		0x0000002
53fa9e4066Sahrens #define	ACL_SYNCHRONIZE_SET_DENY		0x0000001
54fa9e4066Sahrens 
55fa9e4066Sahrens #define	ACL_WRITE_OWNER_SET_ALLOW		0x0000020
56fa9e4066Sahrens #define	ACL_WRITE_OWNER_SET_DENY		0x0000010
57fa9e4066Sahrens 
58fa9e4066Sahrens #define	ACL_WRITE_ATTRS_OWNER_SET_ALLOW		0x0002000
59fa9e4066Sahrens #define	ACL_WRITE_ATTRS_OWNER_SET_DENY		0x0001000
60fa9e4066Sahrens 
61fa9e4066Sahrens #define	ACL_WRITE_ATTRS_WRITER_SET_DENY		0x0010000
62fa9e4066Sahrens 
63fa9e4066Sahrens #define	ACL_DELETE_SET_ALLOW			0x0000200
64fa9e4066Sahrens #define	ACL_DELETE_SET_DENY			0x0000100
65fa9e4066Sahrens 
66fa9e4066Sahrens #define	ACL_READ_NAMED_READER_SET_ALLOW		0x2000000
67fa9e4066Sahrens 
68fa9e4066Sahrens #define	ACL_WRITE_NAMED_WRITER_SET_ALLOW	0x0200000
69fa9e4066Sahrens #define	ACL_WRITE_NAMED_WRITER_SET_DENY		0x0100000
70fa9e4066Sahrens 
71fa9e4066Sahrens #define	ACL_WRITE_ATTRS_OWNER_SET_ALLOW		0x0002000
72fa9e4066Sahrens #define	ACL_WRITE_ATTRS_WRITER_SET_ALLOW	0x0020000
73fa9e4066Sahrens 
74fa9e4066Sahrens #define	ACL_WRITE_OWNER_ERR_DENY		0x0000040
75fa9e4066Sahrens #define	ACL_READ_NAMED_READER_SET_DENY		0x1000000
76d2443e76Smarks 
77fa9e4066Sahrens typedef union {
78fa9e4066Sahrens 	const char *file;
79fa9e4066Sahrens 	int  fd;
80fa9e4066Sahrens } acl_inp;
81fa9e4066Sahrens 
82fa9e4066Sahrens acl_t *
83fa9e4066Sahrens acl_alloc(enum acl_type type)
84fa9e4066Sahrens {
85fa9e4066Sahrens 	acl_t *aclp;
86fa9e4066Sahrens 
87fa9e4066Sahrens 	aclp = malloc(sizeof (acl_t));
88fa9e4066Sahrens 
89fa9e4066Sahrens 	if (aclp == NULL)
90fa9e4066Sahrens 		return (NULL);
91fa9e4066Sahrens 
92fa9e4066Sahrens 	aclp->acl_aclp = NULL;
93fa9e4066Sahrens 	aclp->acl_cnt = 0;
94fa9e4066Sahrens 
95fa9e4066Sahrens 	switch (type) {
96fa9e4066Sahrens 	case ACE_T:
97fa9e4066Sahrens 		aclp->acl_type = ACE_T;
98fa9e4066Sahrens 		aclp->acl_entry_size = sizeof (ace_t);
99fa9e4066Sahrens 		break;
100fa9e4066Sahrens 	case ACLENT_T:
101fa9e4066Sahrens 		aclp->acl_type = ACLENT_T;
102fa9e4066Sahrens 		aclp->acl_entry_size = sizeof (aclent_t);
103fa9e4066Sahrens 		break;
104fa9e4066Sahrens 	default:
105fa9e4066Sahrens 		acl_free(aclp);
106fa9e4066Sahrens 		aclp = NULL;
107fa9e4066Sahrens 	}
108fa9e4066Sahrens 	return (aclp);
109fa9e4066Sahrens }
110fa9e4066Sahrens 
111fa9e4066Sahrens /*
112fa9e4066Sahrens  * Free acl_t structure
113fa9e4066Sahrens  */
114fa9e4066Sahrens void
115fa9e4066Sahrens acl_free(acl_t *aclp)
116fa9e4066Sahrens {
117fa9e4066Sahrens 	if (aclp == NULL)
118fa9e4066Sahrens 		return;
119fa9e4066Sahrens 
120fa9e4066Sahrens 	if (aclp->acl_aclp)
121fa9e4066Sahrens 		free(aclp->acl_aclp);
122fa9e4066Sahrens 	free(aclp);
123fa9e4066Sahrens }
124fa9e4066Sahrens 
125fa9e4066Sahrens /*
126fa9e4066Sahrens  * Determine whether a file has a trivial ACL
127fa9e4066Sahrens  * returns: 	0 = trivial
128fa9e4066Sahrens  *		1 = nontrivial
129fa9e4066Sahrens  *		<0 some other system failure, such as ENOENT or EPERM
130fa9e4066Sahrens  */
131fa9e4066Sahrens int
132fa9e4066Sahrens acl_trivial(const char *filename)
133fa9e4066Sahrens {
134fa9e4066Sahrens 	int acl_flavor;
135fa9e4066Sahrens 	int aclcnt;
136fa9e4066Sahrens 	int cntcmd;
137fa9e4066Sahrens 	int val = 0;
138fa9e4066Sahrens 	ace_t *acep;
139fa9e4066Sahrens 
140fa9e4066Sahrens 	acl_flavor = pathconf(filename, _PC_ACL_ENABLED);
141fa9e4066Sahrens 	if (acl_flavor == -1)
142fa9e4066Sahrens 		return (-1);
143fa9e4066Sahrens 
144fa9e4066Sahrens 	if (acl_flavor == _ACL_ACE_ENABLED)
145fa9e4066Sahrens 		cntcmd = ACE_GETACLCNT;
146fa9e4066Sahrens 	else
147fa9e4066Sahrens 		cntcmd = GETACLCNT;
148fa9e4066Sahrens 
149fa9e4066Sahrens 	aclcnt = acl(filename, cntcmd, 0, NULL);
150fa9e4066Sahrens 	if (aclcnt > 0) {
151fa9e4066Sahrens 		if (acl_flavor == _ACL_ACE_ENABLED) {
152fa9e4066Sahrens 			acep = malloc(sizeof (ace_t) * aclcnt);
153fa9e4066Sahrens 			if (acep == NULL)
154fa9e4066Sahrens 				return (-1);
155fa9e4066Sahrens 			if (acl(filename, ACE_GETACL,
156fa9e4066Sahrens 			    aclcnt, acep) < 0) {
157fa9e4066Sahrens 				free(acep);
158fa9e4066Sahrens 				return (-1);
159fa9e4066Sahrens 			}
160fa9e4066Sahrens 
161fa9e4066Sahrens 			val = ace_trivial(acep, aclcnt);
162fa9e4066Sahrens 			free(acep);
163d2443e76Smarks 
164fa9e4066Sahrens 		} else if (aclcnt > MIN_ACL_ENTRIES)
165fa9e4066Sahrens 			val = 1;
166fa9e4066Sahrens 	}
167fa9e4066Sahrens 	return (val);
168fa9e4066Sahrens }
169fa9e4066Sahrens 
170fa9e4066Sahrens static uint32_t
171fa9e4066Sahrens access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow)
172fa9e4066Sahrens {
173fa9e4066Sahrens 	uint32_t access_mask = 0;
174fa9e4066Sahrens 	int acl_produce;
175fa9e4066Sahrens 	int synchronize_set = 0, write_owner_set = 0;
176fa9e4066Sahrens 	int delete_set = 0, write_attrs_set = 0;
177fa9e4066Sahrens 	int read_named_set = 0, write_named_set = 0;
178fa9e4066Sahrens 
179fa9e4066Sahrens 	acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW |
180fa9e4066Sahrens 	    ACL_WRITE_ATTRS_OWNER_SET_ALLOW |
181fa9e4066Sahrens 	    ACL_WRITE_ATTRS_WRITER_SET_DENY);
182fa9e4066Sahrens 
183fa9e4066Sahrens 	if (isallow) {
184fa9e4066Sahrens 		synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW;
185fa9e4066Sahrens 		write_owner_set = ACL_WRITE_OWNER_SET_ALLOW;
186fa9e4066Sahrens 		delete_set = ACL_DELETE_SET_ALLOW;
187fa9e4066Sahrens 		if (hasreadperm)
188fa9e4066Sahrens 			read_named_set = ACL_READ_NAMED_READER_SET_ALLOW;
189fa9e4066Sahrens 		if (haswriteperm)
190fa9e4066Sahrens 			write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW;
191fa9e4066Sahrens 		if (isowner)
192fa9e4066Sahrens 			write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW;
193fa9e4066Sahrens 		else if (haswriteperm)
194fa9e4066Sahrens 			write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW;
195fa9e4066Sahrens 	} else {
196fa9e4066Sahrens 
197fa9e4066Sahrens 		synchronize_set = ACL_SYNCHRONIZE_SET_DENY;
198fa9e4066Sahrens 		write_owner_set = ACL_WRITE_OWNER_SET_DENY;
199fa9e4066Sahrens 		delete_set = ACL_DELETE_SET_DENY;
200fa9e4066Sahrens 		if (hasreadperm)
201fa9e4066Sahrens 			read_named_set = ACL_READ_NAMED_READER_SET_DENY;
202fa9e4066Sahrens 		if (haswriteperm)
203fa9e4066Sahrens 			write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY;
204fa9e4066Sahrens 		if (isowner)
205fa9e4066Sahrens 			write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY;
206fa9e4066Sahrens 		else if (haswriteperm)
207fa9e4066Sahrens 			write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY;
208fa9e4066Sahrens 		else
209fa9e4066Sahrens 			/*
210fa9e4066Sahrens 			 * If the entity is not the owner and does not
211fa9e4066Sahrens 			 * have write permissions ACE_WRITE_ATTRIBUTES will
212fa9e4066Sahrens 			 * always go in the DENY ACE.
213fa9e4066Sahrens 			 */
214fa9e4066Sahrens 			access_mask |= ACE_WRITE_ATTRIBUTES;
215fa9e4066Sahrens 	}
216fa9e4066Sahrens 
217fa9e4066Sahrens 	if (acl_produce & synchronize_set)
218fa9e4066Sahrens 		access_mask |= ACE_SYNCHRONIZE;
219fa9e4066Sahrens 	if (acl_produce & write_owner_set)
220fa9e4066Sahrens 		access_mask |= ACE_WRITE_OWNER;
221fa9e4066Sahrens 	if (acl_produce & delete_set)
222fa9e4066Sahrens 		access_mask |= ACE_DELETE;
223fa9e4066Sahrens 	if (acl_produce & write_attrs_set)
224fa9e4066Sahrens 		access_mask |= ACE_WRITE_ATTRIBUTES;
225fa9e4066Sahrens 	if (acl_produce & read_named_set)
226fa9e4066Sahrens 		access_mask |= ACE_READ_NAMED_ATTRS;
227fa9e4066Sahrens 	if (acl_produce & write_named_set)
228fa9e4066Sahrens 		access_mask |= ACE_WRITE_NAMED_ATTRS;
229fa9e4066Sahrens 
230fa9e4066Sahrens 	return (access_mask);
231fa9e4066Sahrens }
232fa9e4066Sahrens 
233fa9e4066Sahrens /*
234fa9e4066Sahrens  * Given an mode_t, convert it into an access_mask as used
235fa9e4066Sahrens  * by nfsace, assuming aclent_t -> nfsace semantics.
236fa9e4066Sahrens  */
237fa9e4066Sahrens static uint32_t
238fa9e4066Sahrens mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow)
239fa9e4066Sahrens {
240fa9e4066Sahrens 	uint32_t access = 0;
241fa9e4066Sahrens 	int haswriteperm = 0;
242fa9e4066Sahrens 	int hasreadperm = 0;
243fa9e4066Sahrens 
244fa9e4066Sahrens 	if (isallow) {
245fa9e4066Sahrens 		haswriteperm = (mode & 02);
246fa9e4066Sahrens 		hasreadperm = (mode & 04);
247fa9e4066Sahrens 	} else {
248fa9e4066Sahrens 		haswriteperm = !(mode & 02);
249fa9e4066Sahrens 		hasreadperm = !(mode & 04);
250fa9e4066Sahrens 	}
251fa9e4066Sahrens 
252fa9e4066Sahrens 	/*
253fa9e4066Sahrens 	 * The following call takes care of correctly setting the following
254fa9e4066Sahrens 	 * mask bits in the access_mask:
255fa9e4066Sahrens 	 * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE,
256fa9e4066Sahrens 	 * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS
257fa9e4066Sahrens 	 */
258fa9e4066Sahrens 	access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow);
259fa9e4066Sahrens 
260fa9e4066Sahrens 	if (isallow) {
261fa9e4066Sahrens 		access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES;
262fa9e4066Sahrens 		if (isowner)
263fa9e4066Sahrens 			access |= ACE_WRITE_ACL;
264fa9e4066Sahrens 	} else {
265fa9e4066Sahrens 		if (! isowner)
266fa9e4066Sahrens 			access |= ACE_WRITE_ACL;
267fa9e4066Sahrens 	}
268fa9e4066Sahrens 
269fa9e4066Sahrens 	/* read */
270fa9e4066Sahrens 	if (mode & 04) {
271fa9e4066Sahrens 		access |= ACE_READ_DATA;
272fa9e4066Sahrens 	}
273fa9e4066Sahrens 	/* write */
274fa9e4066Sahrens 	if (mode & 02) {
275fa9e4066Sahrens 		access |= ACE_WRITE_DATA |
276fa9e4066Sahrens 		    ACE_APPEND_DATA;
277fa9e4066Sahrens 		if (isdir)
278fa9e4066Sahrens 			access |= ACE_DELETE_CHILD;
279fa9e4066Sahrens 	}
280fa9e4066Sahrens 	/* exec */
281fa9e4066Sahrens 	if (mode & 01) {
282fa9e4066Sahrens 		access |= ACE_EXECUTE;
283fa9e4066Sahrens 	}
284fa9e4066Sahrens 
285fa9e4066Sahrens 	return (access);
286fa9e4066Sahrens }
287fa9e4066Sahrens 
288fa9e4066Sahrens /*
289fa9e4066Sahrens  * Given an nfsace (presumably an ALLOW entry), make a
290fa9e4066Sahrens  * corresponding DENY entry at the address given.
291fa9e4066Sahrens  */
292fa9e4066Sahrens static void
293fa9e4066Sahrens ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner)
294fa9e4066Sahrens {
295fa9e4066Sahrens 	(void) memcpy(deny, allow, sizeof (ace_t));
296fa9e4066Sahrens 
297fa9e4066Sahrens 	deny->a_who = allow->a_who;
298fa9e4066Sahrens 
299fa9e4066Sahrens 	deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
300fa9e4066Sahrens 	deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS;
301fa9e4066Sahrens 	if (isdir)
302fa9e4066Sahrens 		deny->a_access_mask ^= ACE_DELETE_CHILD;
303fa9e4066Sahrens 
304fa9e4066Sahrens 	deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER |
305fa9e4066Sahrens 	    ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
306fa9e4066Sahrens 	    ACE_WRITE_NAMED_ATTRS);
307fa9e4066Sahrens 	deny->a_access_mask |= access_mask_set((allow->a_access_mask &
308fa9e4066Sahrens 	    ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner,
309fa9e4066Sahrens 	    B_FALSE);
310fa9e4066Sahrens }
311fa9e4066Sahrens /*
312fa9e4066Sahrens  * Make an initial pass over an array of aclent_t's.  Gather
313fa9e4066Sahrens  * information such as an ACL_MASK (if any), number of users,
314fa9e4066Sahrens  * number of groups, and whether the array needs to be sorted.
315fa9e4066Sahrens  */
316fa9e4066Sahrens static int
317fa9e4066Sahrens ln_aent_preprocess(aclent_t *aclent, int n,
318fa9e4066Sahrens     int *hasmask, mode_t *mask,
319fa9e4066Sahrens     int *numuser, int *numgroup, int *needsort)
320fa9e4066Sahrens {
321fa9e4066Sahrens 	int error = 0;
322fa9e4066Sahrens 	int i;
323fa9e4066Sahrens 	int curtype = 0;
324fa9e4066Sahrens 
325fa9e4066Sahrens 	*hasmask = 0;
326fa9e4066Sahrens 	*mask = 07;
327fa9e4066Sahrens 	*needsort = 0;
328fa9e4066Sahrens 	*numuser = 0;
329fa9e4066Sahrens 	*numgroup = 0;
330fa9e4066Sahrens 
331fa9e4066Sahrens 	for (i = 0; i < n; i++) {
332fa9e4066Sahrens 		if (aclent[i].a_type < curtype)
333fa9e4066Sahrens 			*needsort = 1;
334fa9e4066Sahrens 		else if (aclent[i].a_type > curtype)
335fa9e4066Sahrens 			curtype = aclent[i].a_type;
336fa9e4066Sahrens 		if (aclent[i].a_type & USER)
337fa9e4066Sahrens 			(*numuser)++;
338fa9e4066Sahrens 		if (aclent[i].a_type & (GROUP | GROUP_OBJ))
339fa9e4066Sahrens 			(*numgroup)++;
340fa9e4066Sahrens 		if (aclent[i].a_type & CLASS_OBJ) {
341fa9e4066Sahrens 			if (*hasmask) {
342fa9e4066Sahrens 				error = EINVAL;
343fa9e4066Sahrens 				goto out;
344fa9e4066Sahrens 			} else {
345fa9e4066Sahrens 				*hasmask = 1;
346fa9e4066Sahrens 				*mask = aclent[i].a_perm;
347fa9e4066Sahrens 			}
348fa9e4066Sahrens 		}
349fa9e4066Sahrens 	}
350fa9e4066Sahrens 
351fa9e4066Sahrens 	if ((! *hasmask) && (*numuser + *numgroup > 1)) {
352fa9e4066Sahrens 		error = EINVAL;
353fa9e4066Sahrens 		goto out;
354fa9e4066Sahrens 	}
355fa9e4066Sahrens 
356fa9e4066Sahrens out:
357fa9e4066Sahrens 	return (error);
358fa9e4066Sahrens }
359fa9e4066Sahrens 
360fa9e4066Sahrens /*
361fa9e4066Sahrens  * Convert an array of aclent_t into an array of nfsace entries,
362fa9e4066Sahrens  * following POSIX draft -> nfsv4 conversion semantics as outlined in
363fa9e4066Sahrens  * the IETF draft.
364fa9e4066Sahrens  */
365fa9e4066Sahrens static int
366fa9e4066Sahrens ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir)
367fa9e4066Sahrens {
368fa9e4066Sahrens 	int error = 0;
369fa9e4066Sahrens 	mode_t mask;
370fa9e4066Sahrens 	int numuser, numgroup, needsort;
371fa9e4066Sahrens 	int resultsize = 0;
372fa9e4066Sahrens 	int i, groupi = 0, skip;
373fa9e4066Sahrens 	ace_t *acep, *result = NULL;
374fa9e4066Sahrens 	int hasmask;
375fa9e4066Sahrens 
376fa9e4066Sahrens 	error = ln_aent_preprocess(aclent, n, &hasmask, &mask,
377fa9e4066Sahrens 	    &numuser, &numgroup, &needsort);
378fa9e4066Sahrens 	if (error != 0)
379fa9e4066Sahrens 		goto out;
380fa9e4066Sahrens 
381fa9e4066Sahrens 	/* allow + deny for each aclent */
382fa9e4066Sahrens 	resultsize = n * 2;
383fa9e4066Sahrens 	if (hasmask) {
384fa9e4066Sahrens 		/*
385fa9e4066Sahrens 		 * stick extra deny on the group_obj and on each
386fa9e4066Sahrens 		 * user|group for the mask (the group_obj was added
387fa9e4066Sahrens 		 * into the count for numgroup)
388fa9e4066Sahrens 		 */
389fa9e4066Sahrens 		resultsize += numuser + numgroup;
390fa9e4066Sahrens 		/* ... and don't count the mask itself */
391fa9e4066Sahrens 		resultsize -= 2;
392fa9e4066Sahrens 	}
393fa9e4066Sahrens 
394fa9e4066Sahrens 	/* sort the source if necessary */
395fa9e4066Sahrens 	if (needsort)
396fa9e4066Sahrens 		ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls);
397fa9e4066Sahrens 
398fa9e4066Sahrens 	result = acep = calloc(1, resultsize * sizeof (ace_t));
399fa9e4066Sahrens 	if (result == NULL)
400fa9e4066Sahrens 		goto out;
401fa9e4066Sahrens 
402fa9e4066Sahrens 	for (i = 0; i < n; i++) {
403fa9e4066Sahrens 		/*
404fa9e4066Sahrens 		 * don't process CLASS_OBJ (mask); mask was grabbed in
405fa9e4066Sahrens 		 * ln_aent_preprocess()
406fa9e4066Sahrens 		 */
407fa9e4066Sahrens 		if (aclent[i].a_type & CLASS_OBJ)
408fa9e4066Sahrens 			continue;
409fa9e4066Sahrens 
410fa9e4066Sahrens 		/* If we need an ACL_MASK emulator, prepend it now */
411fa9e4066Sahrens 		if ((hasmask) &&
412fa9e4066Sahrens 		    (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) {
413fa9e4066Sahrens 			acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
414fa9e4066Sahrens 			acep->a_flags = 0;
415fa9e4066Sahrens 			if (aclent[i].a_type & GROUP_OBJ) {
416fa9e4066Sahrens 				acep->a_who = -1;
417fa9e4066Sahrens 				acep->a_flags |=
418fa9e4066Sahrens 				    (ACE_IDENTIFIER_GROUP|ACE_GROUP);
419fa9e4066Sahrens 			} else if (aclent[i].a_type & USER) {
420fa9e4066Sahrens 				acep->a_who = aclent[i].a_id;
421fa9e4066Sahrens 			} else {
422fa9e4066Sahrens 				acep->a_who = aclent[i].a_id;
423fa9e4066Sahrens 				acep->a_flags |= ACE_IDENTIFIER_GROUP;
424fa9e4066Sahrens 			}
425fa9e4066Sahrens 			if (aclent[i].a_type & ACL_DEFAULT) {
426fa9e4066Sahrens 				acep->a_flags |= ACE_INHERIT_ONLY_ACE |
427fa9e4066Sahrens 				    ACE_FILE_INHERIT_ACE |
428fa9e4066Sahrens 				    ACE_DIRECTORY_INHERIT_ACE;
429fa9e4066Sahrens 			}
430fa9e4066Sahrens 			/*
431fa9e4066Sahrens 			 * Set the access mask for the prepended deny
432fa9e4066Sahrens 			 * ace.  To do this, we invert the mask (found
433fa9e4066Sahrens 			 * in ln_aent_preprocess()) then convert it to an
434fa9e4066Sahrens 			 * DENY ace access_mask.
435fa9e4066Sahrens 			 */
436fa9e4066Sahrens 			acep->a_access_mask = mode_to_ace_access((mask ^ 07),
437fa9e4066Sahrens 			    isdir, 0, 0);
438fa9e4066Sahrens 			acep += 1;
439fa9e4066Sahrens 		}
440fa9e4066Sahrens 
441fa9e4066Sahrens 		/* handle a_perm -> access_mask */
442fa9e4066Sahrens 		acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm,
443fa9e4066Sahrens 		    isdir, aclent[i].a_type & USER_OBJ, 1);
444fa9e4066Sahrens 
445fa9e4066Sahrens 		/* emulate a default aclent */
446fa9e4066Sahrens 		if (aclent[i].a_type & ACL_DEFAULT) {
447fa9e4066Sahrens 			acep->a_flags |= ACE_INHERIT_ONLY_ACE |
448fa9e4066Sahrens 			    ACE_FILE_INHERIT_ACE |
449fa9e4066Sahrens 			    ACE_DIRECTORY_INHERIT_ACE;
450fa9e4066Sahrens 		}
451fa9e4066Sahrens 
452fa9e4066Sahrens 		/*
453fa9e4066Sahrens 		 * handle a_perm and a_id
454fa9e4066Sahrens 		 *
455fa9e4066Sahrens 		 * this must be done last, since it involves the
456fa9e4066Sahrens 		 * corresponding deny aces, which are handled
457fa9e4066Sahrens 		 * differently for each different a_type.
458fa9e4066Sahrens 		 */
459fa9e4066Sahrens 		if (aclent[i].a_type & USER_OBJ) {
460fa9e4066Sahrens 			acep->a_who = -1;
461fa9e4066Sahrens 			acep->a_flags |= ACE_OWNER;
462fa9e4066Sahrens 			ace_make_deny(acep, acep + 1, isdir, B_TRUE);
463fa9e4066Sahrens 			acep += 2;
464fa9e4066Sahrens 		} else if (aclent[i].a_type & USER) {
465fa9e4066Sahrens 			acep->a_who = aclent[i].a_id;
466fa9e4066Sahrens 			ace_make_deny(acep, acep + 1, isdir, B_FALSE);
467fa9e4066Sahrens 			acep += 2;
468fa9e4066Sahrens 		} else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) {
469fa9e4066Sahrens 			if (aclent[i].a_type & GROUP_OBJ) {
470fa9e4066Sahrens 				acep->a_who = -1;
471fa9e4066Sahrens 				acep->a_flags |= ACE_GROUP;
472fa9e4066Sahrens 			} else {
473fa9e4066Sahrens 				acep->a_who = aclent[i].a_id;
474fa9e4066Sahrens 			}
475fa9e4066Sahrens 			acep->a_flags |= ACE_IDENTIFIER_GROUP;
476fa9e4066Sahrens 			/*
477fa9e4066Sahrens 			 * Set the corresponding deny for the group ace.
478fa9e4066Sahrens 			 *
479fa9e4066Sahrens 			 * The deny aces go after all of the groups, unlike
480fa9e4066Sahrens 			 * everything else, where they immediately follow
481fa9e4066Sahrens 			 * the allow ace.
482fa9e4066Sahrens 			 *
483fa9e4066Sahrens 			 * We calculate "skip", the number of slots to
484fa9e4066Sahrens 			 * skip ahead for the deny ace, here.
485fa9e4066Sahrens 			 *
486fa9e4066Sahrens 			 * The pattern is:
487fa9e4066Sahrens 			 * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3
488fa9e4066Sahrens 			 * thus, skip is
489fa9e4066Sahrens 			 * (2 * numgroup) - 1 - groupi
490fa9e4066Sahrens 			 * (2 * numgroup) to account for MD + A
491fa9e4066Sahrens 			 * - 1 to account for the fact that we're on the
492fa9e4066Sahrens 			 * access (A), not the mask (MD)
493fa9e4066Sahrens 			 * - groupi to account for the fact that we have
494fa9e4066Sahrens 			 * passed up groupi number of MD's.
495fa9e4066Sahrens 			 */
496fa9e4066Sahrens 			skip = (2 * numgroup) - 1 - groupi;
497fa9e4066Sahrens 			ace_make_deny(acep, acep + skip, isdir, B_FALSE);
498fa9e4066Sahrens 			/*
499fa9e4066Sahrens 			 * If we just did the last group, skip acep past
500fa9e4066Sahrens 			 * all of the denies; else, just move ahead one.
501fa9e4066Sahrens 			 */
502fa9e4066Sahrens 			if (++groupi >= numgroup)
503fa9e4066Sahrens 				acep += numgroup + 1;
504fa9e4066Sahrens 			else
505fa9e4066Sahrens 				acep += 1;
506fa9e4066Sahrens 		} else if (aclent[i].a_type & OTHER_OBJ) {
507fa9e4066Sahrens 			acep->a_who = -1;
508fa9e4066Sahrens 			acep->a_flags |= ACE_EVERYONE;
509fa9e4066Sahrens 			ace_make_deny(acep, acep + 1, isdir, B_FALSE);
510fa9e4066Sahrens 			acep += 2;
511fa9e4066Sahrens 		} else {
512fa9e4066Sahrens 			error = EINVAL;
513fa9e4066Sahrens 			goto out;
514fa9e4066Sahrens 		}
515fa9e4066Sahrens 	}
516fa9e4066Sahrens 
517fa9e4066Sahrens 	*acepp = result;
518fa9e4066Sahrens 	*rescount = resultsize;
519fa9e4066Sahrens 
520fa9e4066Sahrens out:
521fa9e4066Sahrens 	if (error != 0) {
522fa9e4066Sahrens 		if ((result != NULL) && (resultsize > 0)) {
523fa9e4066Sahrens 			free(result);
524fa9e4066Sahrens 		}
525fa9e4066Sahrens 	}
526fa9e4066Sahrens 
527fa9e4066Sahrens 	return (error);
528fa9e4066Sahrens }
529fa9e4066Sahrens 
530fa9e4066Sahrens static int
531fa9e4066Sahrens convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir,
532fa9e4066Sahrens     ace_t **retacep, int *retacecnt)
533fa9e4066Sahrens {
534fa9e4066Sahrens 	ace_t *acep;
535fa9e4066Sahrens 	ace_t *dfacep;
536fa9e4066Sahrens 	ace_t *newacep;
537fa9e4066Sahrens 	int acecnt = 0;
538fa9e4066Sahrens 	int dfacecnt = 0;
539fa9e4066Sahrens 	int dfaclstart = 0;
540fa9e4066Sahrens 	int dfaclcnt = 0;
541fa9e4066Sahrens 	aclent_t *aclp;
542fa9e4066Sahrens 	int i;
543fa9e4066Sahrens 	int error;
544fa9e4066Sahrens 
545fa9e4066Sahrens 	ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls);
546fa9e4066Sahrens 
547fa9e4066Sahrens 	for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) {
548fa9e4066Sahrens 		if (aclp->a_type & ACL_DEFAULT)
549fa9e4066Sahrens 			break;
550fa9e4066Sahrens 	}
551fa9e4066Sahrens 
552fa9e4066Sahrens 	if (i < aclcnt) {
553fa9e4066Sahrens 		dfaclstart = aclcnt - i;
554fa9e4066Sahrens 		dfaclcnt = i;
555fa9e4066Sahrens 	}
556fa9e4066Sahrens 
557fa9e4066Sahrens 	if (dfaclcnt && isdir == 0) {
558fa9e4066Sahrens 		return (-1);
559fa9e4066Sahrens 	}
560fa9e4066Sahrens 
561fa9e4066Sahrens 	error = ln_aent_to_ace(aclentp, i,  &acep, &acecnt, isdir);
562fa9e4066Sahrens 	if (error)
563fa9e4066Sahrens 		return (-1);
564fa9e4066Sahrens 
565fa9e4066Sahrens 	if (dfaclcnt) {
566fa9e4066Sahrens 		error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt,
567fa9e4066Sahrens 		    &dfacep, &dfacecnt, isdir);
568fa9e4066Sahrens 		if (error) {
569fa9e4066Sahrens 			if (acep) {
570fa9e4066Sahrens 				free(acep);
571fa9e4066Sahrens 			}
572fa9e4066Sahrens 			return (-1);
573fa9e4066Sahrens 		}
574fa9e4066Sahrens 	}
575fa9e4066Sahrens 
576fa9e4066Sahrens 	newacep = malloc(sizeof (ace_t) * (acecnt + dfacecnt));
577fa9e4066Sahrens 	if (newacep == NULL)
578fa9e4066Sahrens 		return (-1);
579fa9e4066Sahrens 
580fa9e4066Sahrens 	(void) memcpy(newacep, acep, sizeof (ace_t) * acecnt);
581fa9e4066Sahrens 	if (dfaclcnt) {
582fa9e4066Sahrens 		(void) memcpy(newacep + acecnt, dfacep,
583fa9e4066Sahrens 		    sizeof (ace_t) * dfacecnt);
584fa9e4066Sahrens 	}
585fa9e4066Sahrens 	free(acep);
586fa9e4066Sahrens 	if (dfaclcnt)
587fa9e4066Sahrens 		free(dfacep);
588fa9e4066Sahrens 
589fa9e4066Sahrens 	*retacecnt = acecnt + dfacecnt;
590fa9e4066Sahrens 	*retacep = newacep;
591fa9e4066Sahrens 	return (0);
592fa9e4066Sahrens }
593fa9e4066Sahrens 
594fa9e4066Sahrens 
595fa9e4066Sahrens static int
596fa9e4066Sahrens cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp)
597fa9e4066Sahrens {
598fa9e4066Sahrens 	const char *fname;
599fa9e4066Sahrens 	int fd;
600fa9e4066Sahrens 	int ace_acl = 0;
601fa9e4066Sahrens 	int error;
602fa9e4066Sahrens 	int getcmd, cntcmd;
603fa9e4066Sahrens 	acl_t *acl_info;
604fa9e4066Sahrens 	int	save_errno;
605fa9e4066Sahrens 	int	stat_error;
606fa9e4066Sahrens 	struct stat64 statbuf;
607fa9e4066Sahrens 
608fa9e4066Sahrens 	*aclp = NULL;
609fa9e4066Sahrens 	if (type == ACL_PATH) {
610fa9e4066Sahrens 		fname = inp.file;
611fa9e4066Sahrens 		ace_acl = pathconf(fname, _PC_ACL_ENABLED);
612fa9e4066Sahrens 	} else {
613fa9e4066Sahrens 		fd = inp.fd;
614fa9e4066Sahrens 		ace_acl = fpathconf(fd, _PC_ACL_ENABLED);
615fa9e4066Sahrens 	}
616fa9e4066Sahrens 
617fa9e4066Sahrens 	if (ace_acl == -1)
618fa9e4066Sahrens 		return (-1);
619fa9e4066Sahrens 
620fa9e4066Sahrens 	/*
621fa9e4066Sahrens 	 * if acl's aren't supported then
622fa9e4066Sahrens 	 * send it through the old GETACL interface
623fa9e4066Sahrens 	 */
624fa9e4066Sahrens 	if (ace_acl == 0) {
625fa9e4066Sahrens 		ace_acl = _ACL_ACLENT_ENABLED;
626fa9e4066Sahrens 	}
627fa9e4066Sahrens 
628fa9e4066Sahrens 	if (ace_acl & _ACL_ACE_ENABLED) {
629fa9e4066Sahrens 		cntcmd = ACE_GETACLCNT;
630fa9e4066Sahrens 		getcmd = ACE_GETACL;
631fa9e4066Sahrens 		acl_info = acl_alloc(ACE_T);
632fa9e4066Sahrens 	} else {
633fa9e4066Sahrens 		cntcmd = GETACLCNT;
634fa9e4066Sahrens 		getcmd = GETACL;
635fa9e4066Sahrens 		acl_info = acl_alloc(ACLENT_T);
636fa9e4066Sahrens 	}
637fa9e4066Sahrens 
638fa9e4066Sahrens 	if (acl_info == NULL)
639fa9e4066Sahrens 		return (-1);
640fa9e4066Sahrens 
641fa9e4066Sahrens 	if (type == ACL_PATH) {
642fa9e4066Sahrens 		acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL);
643fa9e4066Sahrens 	} else {
644fa9e4066Sahrens 		acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL);
645fa9e4066Sahrens 	}
646fa9e4066Sahrens 
647fa9e4066Sahrens 	save_errno = errno;
648fa9e4066Sahrens 	if (acl_info->acl_cnt < 0) {
649fa9e4066Sahrens 		acl_free(acl_info);
650fa9e4066Sahrens 		errno = save_errno;
651fa9e4066Sahrens 		return (-1);
652fa9e4066Sahrens 	}
653fa9e4066Sahrens 
654fa9e4066Sahrens 	if (acl_info->acl_cnt == 0) {
655fa9e4066Sahrens 		acl_free(acl_info);
656fa9e4066Sahrens 		errno = save_errno;
657fa9e4066Sahrens 		return (0);
658fa9e4066Sahrens 	}
659fa9e4066Sahrens 
660fa9e4066Sahrens 	acl_info->acl_aclp =
661fa9e4066Sahrens 	    malloc(acl_info->acl_cnt * acl_info->acl_entry_size);
662fa9e4066Sahrens 	save_errno = errno;
663fa9e4066Sahrens 
664fa9e4066Sahrens 	if (acl_info->acl_aclp == NULL) {
665fa9e4066Sahrens 		acl_free(acl_info);
666fa9e4066Sahrens 		errno = save_errno;
667fa9e4066Sahrens 		return (-1);
668fa9e4066Sahrens 	}
669fa9e4066Sahrens 
670fa9e4066Sahrens 	if (type == ACL_PATH) {
671fa9e4066Sahrens 		stat_error = stat64(fname, &statbuf);
672fa9e4066Sahrens 		error = acl(fname, getcmd, acl_info->acl_cnt,
673fa9e4066Sahrens 		    acl_info->acl_aclp);
674fa9e4066Sahrens 	} else {
675fa9e4066Sahrens 		stat_error = fstat64(fd, &statbuf);
676fa9e4066Sahrens 		error = facl(fd, getcmd, acl_info->acl_cnt,
677fa9e4066Sahrens 		    acl_info->acl_aclp);
678fa9e4066Sahrens 	}
679fa9e4066Sahrens 
680fa9e4066Sahrens 	save_errno = errno;
681fa9e4066Sahrens 	if (error == -1) {
682fa9e4066Sahrens 		acl_free(acl_info);
683fa9e4066Sahrens 		errno = save_errno;
684fa9e4066Sahrens 		return (-1);
685fa9e4066Sahrens 	}
686fa9e4066Sahrens 
687fa9e4066Sahrens 
688fa9e4066Sahrens 	if (stat_error == 0) {
689fa9e4066Sahrens 		acl_info->acl_flags =
690fa9e4066Sahrens 		    (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0);
691fa9e4066Sahrens 	} else
692fa9e4066Sahrens 		acl_info->acl_flags = 0;
693fa9e4066Sahrens 
694fa9e4066Sahrens 	switch (acl_info->acl_type) {
695fa9e4066Sahrens 	case ACLENT_T:
696fa9e4066Sahrens 		if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
697fa9e4066Sahrens 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
698fa9e4066Sahrens 		break;
699fa9e4066Sahrens 	case ACE_T:
700fa9e4066Sahrens 		if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
701fa9e4066Sahrens 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
702fa9e4066Sahrens 		break;
703fa9e4066Sahrens 	default:
704fa9e4066Sahrens 		errno = EINVAL;
705fa9e4066Sahrens 		acl_free(acl_info);
706fa9e4066Sahrens 		return (-1);
707fa9e4066Sahrens 	}
708fa9e4066Sahrens 
709fa9e4066Sahrens 	if ((acl_info->acl_flags & ACL_IS_TRIVIAL) &&
710fa9e4066Sahrens 	    (get_flag & ACL_NO_TRIVIAL)) {
711fa9e4066Sahrens 		acl_free(acl_info);
712fa9e4066Sahrens 		errno = 0;
713fa9e4066Sahrens 		return (0);
714fa9e4066Sahrens 	}
715fa9e4066Sahrens 
716fa9e4066Sahrens 	*aclp = acl_info;
717fa9e4066Sahrens 	return (0);
718fa9e4066Sahrens }
719fa9e4066Sahrens 
720fa9e4066Sahrens /*
721fa9e4066Sahrens  * return -1 on failure, otherwise the number of acl
722fa9e4066Sahrens  * entries is returned
723fa9e4066Sahrens  */
724fa9e4066Sahrens int
725fa9e4066Sahrens acl_get(const char *path, int get_flag, acl_t **aclp)
726fa9e4066Sahrens {
727fa9e4066Sahrens 	acl_inp acl_inp;
728fa9e4066Sahrens 	acl_inp.file = path;
729fa9e4066Sahrens 
730fa9e4066Sahrens 	return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp));
731fa9e4066Sahrens }
732fa9e4066Sahrens 
733fa9e4066Sahrens int
734fa9e4066Sahrens facl_get(int fd, int get_flag, acl_t **aclp)
735fa9e4066Sahrens {
736fa9e4066Sahrens 
737fa9e4066Sahrens 	acl_inp acl_inp;
738fa9e4066Sahrens 	acl_inp.fd = fd;
739fa9e4066Sahrens 
740fa9e4066Sahrens 	return (cacl_get(acl_inp, get_flag, ACL_FD, aclp));
741fa9e4066Sahrens }
742fa9e4066Sahrens 
743fa9e4066Sahrens /*
744fa9e4066Sahrens  * Set an ACL, translates acl to ace_t when appropriate.
745fa9e4066Sahrens  */
746fa9e4066Sahrens static int
747fa9e4066Sahrens cacl_set(acl_inp *acl_inp, acl_t *aclp, int type)
748fa9e4066Sahrens {
749fa9e4066Sahrens 	int error = 0;
750fa9e4066Sahrens 	int acl_flavor_target;
751fa9e4066Sahrens 	ace_t *acep = NULL;
752fa9e4066Sahrens 	int acecnt;
753fa9e4066Sahrens 	struct stat64 statbuf;
754fa9e4066Sahrens 	int stat_error;
755fa9e4066Sahrens 	int isdir;
756fa9e4066Sahrens 
757fa9e4066Sahrens 
758fa9e4066Sahrens 	if (type == ACL_PATH) {
759fa9e4066Sahrens 		stat_error = stat64(acl_inp->file, &statbuf);
760fa9e4066Sahrens 		if (stat_error)
761fa9e4066Sahrens 			return (-1);
762fa9e4066Sahrens 		acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED);
763fa9e4066Sahrens 	} else {
764fa9e4066Sahrens 		stat_error = fstat64(acl_inp->fd, &statbuf);
765fa9e4066Sahrens 		if (stat_error)
766fa9e4066Sahrens 			return (-1);
767fa9e4066Sahrens 		acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED);
768fa9e4066Sahrens 	}
769fa9e4066Sahrens 
770fa9e4066Sahrens 	isdir = S_ISDIR(statbuf.st_mode);
771fa9e4066Sahrens 
772fa9e4066Sahrens 	if (acl_flavor_target == -1)
773fa9e4066Sahrens 		return (-1);
774fa9e4066Sahrens 
775fa9e4066Sahrens 	/*
776fa9e4066Sahrens 	 * Translate aclent_t ACL's to ACE ACL's.
777fa9e4066Sahrens 	 */
778fa9e4066Sahrens 	if (acl_flavor_target ==  _ACL_ACE_ENABLED &&
779fa9e4066Sahrens 	    aclp->acl_type == ACLENT_T) {
780fa9e4066Sahrens 		error = convert_aent_to_ace(aclp->acl_aclp,
781fa9e4066Sahrens 		    aclp->acl_cnt, isdir, &acep, &acecnt);
782fa9e4066Sahrens 		if (error) {
783fa9e4066Sahrens 			errno = ENOTSUP;
784fa9e4066Sahrens 			return (-1);
785fa9e4066Sahrens 		}
786fa9e4066Sahrens 		/*
787fa9e4066Sahrens 		 * replace old acl with newly translated acl
788fa9e4066Sahrens 		 */
789fa9e4066Sahrens 		free(aclp->acl_aclp);
790fa9e4066Sahrens 		aclp->acl_aclp = acep;
791fa9e4066Sahrens 		aclp->acl_cnt = acecnt;
792fa9e4066Sahrens 		aclp->acl_type = ACE_T;
793fa9e4066Sahrens 	}
794fa9e4066Sahrens 
795fa9e4066Sahrens 	if (type == ACL_PATH) {
796fa9e4066Sahrens 		error = acl(acl_inp->file,
797fa9e4066Sahrens 		    (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL,
798fa9e4066Sahrens 		    aclp->acl_cnt, aclp->acl_aclp);
799fa9e4066Sahrens 	} else {
800fa9e4066Sahrens 		error = facl(acl_inp->fd,
801fa9e4066Sahrens 		    (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL,
802fa9e4066Sahrens 		    aclp->acl_cnt, aclp->acl_aclp);
803fa9e4066Sahrens 	}
804fa9e4066Sahrens 
805fa9e4066Sahrens 	return (error);
806fa9e4066Sahrens }
807fa9e4066Sahrens 
808fa9e4066Sahrens int
809fa9e4066Sahrens acl_set(const char *path, acl_t *aclp)
810fa9e4066Sahrens {
811fa9e4066Sahrens 	acl_inp acl_inp;
812fa9e4066Sahrens 
813fa9e4066Sahrens 	acl_inp.file = path;
814fa9e4066Sahrens 
815fa9e4066Sahrens 	return (cacl_set(&acl_inp, aclp, ACL_PATH));
816fa9e4066Sahrens }
817fa9e4066Sahrens 
818fa9e4066Sahrens int
819fa9e4066Sahrens facl_set(int fd, acl_t *aclp)
820fa9e4066Sahrens {
821fa9e4066Sahrens 	acl_inp acl_inp;
822fa9e4066Sahrens 
823fa9e4066Sahrens 	acl_inp.fd = fd;
824fa9e4066Sahrens 
825fa9e4066Sahrens 	return (cacl_set(&acl_inp, aclp, ACL_FD));
826fa9e4066Sahrens }
827fa9e4066Sahrens 
828fa9e4066Sahrens int
829fa9e4066Sahrens acl_cnt(acl_t *aclp)
830fa9e4066Sahrens {
831fa9e4066Sahrens 	return (aclp->acl_cnt);
832fa9e4066Sahrens }
833fa9e4066Sahrens 
834fa9e4066Sahrens int
835fa9e4066Sahrens acl_type(acl_t *aclp)
836fa9e4066Sahrens {
837fa9e4066Sahrens 	return (aclp->acl_type);
838fa9e4066Sahrens }
839fa9e4066Sahrens 
840fa9e4066Sahrens acl_t *
841fa9e4066Sahrens acl_dup(acl_t *aclp)
842fa9e4066Sahrens {
843fa9e4066Sahrens 	acl_t *newaclp;
844fa9e4066Sahrens 
845fa9e4066Sahrens 	newaclp = acl_alloc(aclp->acl_type);
846fa9e4066Sahrens 	if (newaclp == NULL)
847fa9e4066Sahrens 		return (NULL);
848fa9e4066Sahrens 
849fa9e4066Sahrens 	newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt);
850fa9e4066Sahrens 	if (newaclp->acl_aclp == NULL) {
851fa9e4066Sahrens 		acl_free(newaclp);
852fa9e4066Sahrens 		return (NULL);
853fa9e4066Sahrens 	}
854fa9e4066Sahrens 
855fa9e4066Sahrens 	(void) memcpy(newaclp->acl_aclp,
856fa9e4066Sahrens 	    aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt);
857fa9e4066Sahrens 	newaclp->acl_cnt = aclp->acl_cnt;
858fa9e4066Sahrens 
859fa9e4066Sahrens 	return (newaclp);
860fa9e4066Sahrens }
861fa9e4066Sahrens 
862fa9e4066Sahrens int
863fa9e4066Sahrens acl_flags(acl_t *aclp)
864fa9e4066Sahrens {
865fa9e4066Sahrens 	return (aclp->acl_flags);
866fa9e4066Sahrens }
867fa9e4066Sahrens 
868fa9e4066Sahrens void *
869fa9e4066Sahrens acl_data(acl_t *aclp)
870fa9e4066Sahrens {
871fa9e4066Sahrens 	return (aclp->acl_aclp);
872fa9e4066Sahrens }
873fa9e4066Sahrens 
874fa9e4066Sahrens /*
875fa9e4066Sahrens  * Remove an ACL from a file and create a trivial ACL based
876fa9e4066Sahrens  * off of the mode argument.  After acl has been set owner/group
877fa9e4066Sahrens  * are updated to match owner,group arguments
878fa9e4066Sahrens  */
879fa9e4066Sahrens int
880fa9e4066Sahrens acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode)
881fa9e4066Sahrens {
882fa9e4066Sahrens 	int	error = 0;
883fa9e4066Sahrens 	aclent_t min_acl[MIN_ACL_ENTRIES];
884fa9e4066Sahrens 	ace_t	min_ace_acl[6];	/* owner, group, everyone + complement denies */
885fa9e4066Sahrens 	int	acl_flavor;
886fa9e4066Sahrens 	int	aclcnt;
887fa9e4066Sahrens 
888fa9e4066Sahrens 	acl_flavor = pathconf(file, _PC_ACL_ENABLED);
889fa9e4066Sahrens 
890fa9e4066Sahrens 	if (acl_flavor == -1)
891fa9e4066Sahrens 		return (-1);
892fa9e4066Sahrens 	/*
893fa9e4066Sahrens 	 * force it through aclent flavor when file system doesn't
894fa9e4066Sahrens 	 * understand question
895fa9e4066Sahrens 	 */
896fa9e4066Sahrens 	if (acl_flavor == 0)
897fa9e4066Sahrens 		acl_flavor = _ACL_ACLENT_ENABLED;
898fa9e4066Sahrens 
899fa9e4066Sahrens 	if (acl_flavor & _ACL_ACLENT_ENABLED) {
900fa9e4066Sahrens 		min_acl[0].a_type = USER_OBJ;
901fa9e4066Sahrens 		min_acl[0].a_id   = owner;
902fa9e4066Sahrens 		min_acl[0].a_perm = ((mode & 0700) >> 6);
903fa9e4066Sahrens 		min_acl[1].a_type = GROUP_OBJ;
904fa9e4066Sahrens 		min_acl[1].a_id   = group;
905fa9e4066Sahrens 		min_acl[1].a_perm = ((mode & 0070) >> 3);
906fa9e4066Sahrens 		min_acl[2].a_type = CLASS_OBJ;
907fa9e4066Sahrens 		min_acl[2].a_id   = (uid_t)-1;
908fa9e4066Sahrens 		min_acl[2].a_perm = ((mode & 0070) >> 3);
909fa9e4066Sahrens 		min_acl[3].a_type = OTHER_OBJ;
910fa9e4066Sahrens 		min_acl[3].a_id   = (uid_t)-1;
911fa9e4066Sahrens 		min_acl[3].a_perm = (mode & 0007);
912fa9e4066Sahrens 		aclcnt = 4;
913fa9e4066Sahrens 		error = acl(file, SETACL, aclcnt, min_acl);
914fa9e4066Sahrens 	} else if (acl_flavor & _ACL_ACE_ENABLED) {
915fa9e4066Sahrens 		(void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6);
916fa9e4066Sahrens 
917fa9e4066Sahrens 		/*
918fa9e4066Sahrens 		 * Make aces match request mode
919fa9e4066Sahrens 		 */
920fa9e4066Sahrens 		adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6);
921fa9e4066Sahrens 		adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3);
922fa9e4066Sahrens 		adjust_ace_pair(&min_ace_acl[4], mode & 0007);
923fa9e4066Sahrens 
924fa9e4066Sahrens 		error = acl(file, ACE_SETACL, 6, min_ace_acl);
925fa9e4066Sahrens 	} else {
926fa9e4066Sahrens 		errno = EINVAL;
927fa9e4066Sahrens 		error = 1;
928fa9e4066Sahrens 	}
929fa9e4066Sahrens 
930fa9e4066Sahrens 	if (error == 0)
931fa9e4066Sahrens 		error = chown(file, owner, group);
932fa9e4066Sahrens 	return (error);
933fa9e4066Sahrens }
934fa9e4066Sahrens 
935fa9e4066Sahrens static int
936fa9e4066Sahrens ace_match(void *entry1, void *entry2)
937fa9e4066Sahrens {
938fa9e4066Sahrens 	ace_t *p1 = (ace_t *)entry1;
939fa9e4066Sahrens 	ace_t *p2 = (ace_t *)entry2;
940fa9e4066Sahrens 	ace_t ace1, ace2;
941fa9e4066Sahrens 
942fa9e4066Sahrens 	ace1 = *p1;
943fa9e4066Sahrens 	ace2 = *p2;
944fa9e4066Sahrens 
945fa9e4066Sahrens 	/*
946fa9e4066Sahrens 	 * Need to fixup who field for abstrations for
947fa9e4066Sahrens 	 * accurate comparison, since field is undefined.
948fa9e4066Sahrens 	 */
949fa9e4066Sahrens 	if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
950fa9e4066Sahrens 		ace1.a_who = -1;
951fa9e4066Sahrens 	if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
952fa9e4066Sahrens 		ace2.a_who = -1;
953fa9e4066Sahrens 	return (memcmp(&ace1, &ace2, sizeof (ace_t)));
954fa9e4066Sahrens }
955fa9e4066Sahrens 
956fa9e4066Sahrens static int
957fa9e4066Sahrens aclent_match(void *entry1, void *entry2)
958fa9e4066Sahrens {
959fa9e4066Sahrens 	aclent_t *aclent1 = (aclent_t *)entry1;
960fa9e4066Sahrens 	aclent_t *aclent2 = (aclent_t *)entry2;
961fa9e4066Sahrens 
962fa9e4066Sahrens 	return (memcmp(aclent1, aclent2, sizeof (aclent_t)));
963fa9e4066Sahrens }
964fa9e4066Sahrens 
965fa9e4066Sahrens /*
966fa9e4066Sahrens  * Find acl entries in acl that correspond to removeacl.  Search
967fa9e4066Sahrens  * is started from slot.  The flag argument indicates whether to
968fa9e4066Sahrens  * remove all matches or just the first match.
969fa9e4066Sahrens  */
970fa9e4066Sahrens int
971fa9e4066Sahrens acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag)
972fa9e4066Sahrens {
973fa9e4066Sahrens 	int i, j;
974fa9e4066Sahrens 	int match;
975fa9e4066Sahrens 	int (*acl_match)(void *acl1, void *acl2);
976fa9e4066Sahrens 	void *acl_entry, *remove_entry;
977fa9e4066Sahrens 	void *start;
978fa9e4066Sahrens 	int found = 0;
979fa9e4066Sahrens 
980fa9e4066Sahrens 	if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST)
981fa9e4066Sahrens 		flag = ACL_REMOVE_FIRST;
982fa9e4066Sahrens 
983fa9e4066Sahrens 	if (acl == NULL || removeacl == NULL)
984fa9e4066Sahrens 		return (EACL_NO_ACL_ENTRY);
985fa9e4066Sahrens 
986fa9e4066Sahrens 	if (acl->acl_type != removeacl->acl_type)
987fa9e4066Sahrens 		return (EACL_DIFF_TYPE);
988fa9e4066Sahrens 
989fa9e4066Sahrens 	if (acl->acl_type == ACLENT_T)
990fa9e4066Sahrens 		acl_match = aclent_match;
991fa9e4066Sahrens 	else
992fa9e4066Sahrens 		acl_match = ace_match;
993fa9e4066Sahrens 
994fa9e4066Sahrens 	for (i = 0, remove_entry = removeacl->acl_aclp;
995fa9e4066Sahrens 	    i != removeacl->acl_cnt; i++) {
996fa9e4066Sahrens 
997fa9e4066Sahrens 		j = 0;
998fa9e4066Sahrens 		acl_entry = (char *)acl->acl_aclp +
999fa9e4066Sahrens 		    (acl->acl_entry_size * start_slot);
1000fa9e4066Sahrens 		for (;;) {
1001fa9e4066Sahrens 			match = acl_match(acl_entry, remove_entry);
1002fa9e4066Sahrens 			if (match == 0)  {
1003fa9e4066Sahrens 				found++;
1004fa9e4066Sahrens 				start = (char *)acl_entry +
1005fa9e4066Sahrens 				    acl->acl_entry_size;
1006fa9e4066Sahrens 				(void) memmove(acl_entry, start,
1007fa9e4066Sahrens 				    acl->acl_entry_size *
1008fa9e4066Sahrens 				    acl->acl_cnt-- - (j + 1));
1009fa9e4066Sahrens 
1010fa9e4066Sahrens 				if (flag == ACL_REMOVE_FIRST)
1011fa9e4066Sahrens 					break;
1012fa9e4066Sahrens 				/*
1013fa9e4066Sahrens 				 * List has changed, restart search from
1014fa9e4066Sahrens 				 * beginning.
1015fa9e4066Sahrens 				 */
1016fa9e4066Sahrens 				acl_entry = acl->acl_aclp;
1017fa9e4066Sahrens 				j = 0;
1018fa9e4066Sahrens 				continue;
1019fa9e4066Sahrens 			}
1020fa9e4066Sahrens 			acl_entry = ((char *)acl_entry + acl->acl_entry_size);
1021fa9e4066Sahrens 			if (++j >= acl->acl_cnt) {
1022fa9e4066Sahrens 				break;
1023fa9e4066Sahrens 			}
1024fa9e4066Sahrens 		}
1025fa9e4066Sahrens 	}
1026fa9e4066Sahrens 
1027fa9e4066Sahrens 	return ((found == 0) ? EACL_NO_ACL_ENTRY : 0);
1028fa9e4066Sahrens }
1029fa9e4066Sahrens 
1030fa9e4066Sahrens /*
1031fa9e4066Sahrens  * Replace entires entries in acl1 with the corresponding entries
1032fa9e4066Sahrens  * in newentries.  The where argument specifies where to begin
1033fa9e4066Sahrens  * the replacement.  If the where argument is 1 greater than the
1034fa9e4066Sahrens  * number of acl entries in acl1 then they are appended.  If the
1035fa9e4066Sahrens  * where argument is 2+ greater than the number of acl entries then
1036fa9e4066Sahrens  * EACL_INVALID_SLOT is returned.
1037fa9e4066Sahrens  */
1038fa9e4066Sahrens int
1039fa9e4066Sahrens acl_modifyentries(acl_t *acl1, acl_t *newentries, int where)
1040fa9e4066Sahrens {
1041fa9e4066Sahrens 
1042fa9e4066Sahrens 	int slot;
1043fa9e4066Sahrens 	int slots_needed;
1044fa9e4066Sahrens 	int slots_left;
1045fa9e4066Sahrens 	int newsize;
1046fa9e4066Sahrens 
1047fa9e4066Sahrens 	if (acl1 == NULL || newentries == NULL)
1048fa9e4066Sahrens 		return (EACL_NO_ACL_ENTRY);
1049fa9e4066Sahrens 
1050fa9e4066Sahrens 	if (where < 0 || where >= acl1->acl_cnt)
1051fa9e4066Sahrens 		return (EACL_INVALID_SLOT);
1052fa9e4066Sahrens 
1053fa9e4066Sahrens 	if (acl1->acl_type != newentries->acl_type)
1054fa9e4066Sahrens 		return (EACL_DIFF_TYPE);
1055fa9e4066Sahrens 
1056fa9e4066Sahrens 	slot = where;
1057fa9e4066Sahrens 
1058fa9e4066Sahrens 	slots_left = acl1->acl_cnt - slot + 1;
1059fa9e4066Sahrens 	if (slots_left < newentries->acl_cnt) {
1060fa9e4066Sahrens 		slots_needed = newentries->acl_cnt - slots_left;
1061fa9e4066Sahrens 		newsize = (acl1->acl_entry_size * acl1->acl_cnt) +
1062fa9e4066Sahrens 		    (acl1->acl_entry_size * slots_needed);
1063fa9e4066Sahrens 		acl1->acl_aclp = realloc(acl1->acl_aclp, newsize);
1064fa9e4066Sahrens 		if (acl1->acl_aclp == NULL)
1065fa9e4066Sahrens 			return (-1);
1066fa9e4066Sahrens 	}
1067fa9e4066Sahrens 	(void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot),
1068fa9e4066Sahrens 	    newentries->acl_aclp,
1069fa9e4066Sahrens 	    newentries->acl_entry_size * newentries->acl_cnt);
1070fa9e4066Sahrens 
1071fa9e4066Sahrens 	/*
1072fa9e4066Sahrens 	 * Did ACL grow?
1073fa9e4066Sahrens 	 */
1074fa9e4066Sahrens 
1075fa9e4066Sahrens 	if ((slot + newentries->acl_cnt) > acl1->acl_cnt) {
1076fa9e4066Sahrens 		acl1->acl_cnt = slot + newentries->acl_cnt;
1077fa9e4066Sahrens 	}
1078fa9e4066Sahrens 
1079fa9e4066Sahrens 	return (0);
1080fa9e4066Sahrens }
1081fa9e4066Sahrens 
1082fa9e4066Sahrens /*
1083fa9e4066Sahrens  * Add acl2 entries into acl1.  The where argument specifies where
1084fa9e4066Sahrens  * to add the entries.
1085fa9e4066Sahrens  */
1086fa9e4066Sahrens int
1087fa9e4066Sahrens acl_addentries(acl_t *acl1, acl_t *acl2, int where)
1088fa9e4066Sahrens {
1089fa9e4066Sahrens 
1090fa9e4066Sahrens 	int newsize;
1091fa9e4066Sahrens 	int len;
1092fa9e4066Sahrens 	void *start;
1093fa9e4066Sahrens 	void *to;
1094fa9e4066Sahrens 
1095fa9e4066Sahrens 	if (acl1 == NULL || acl2 == NULL)
1096fa9e4066Sahrens 		return (EACL_NO_ACL_ENTRY);
1097fa9e4066Sahrens 
1098fa9e4066Sahrens 	if (acl1->acl_type != acl2->acl_type)
1099fa9e4066Sahrens 		return (EACL_DIFF_TYPE);
1100fa9e4066Sahrens 
1101fa9e4066Sahrens 	/*
1102fa9e4066Sahrens 	 * allow where to specify 1 past last slot for an append operation
1103fa9e4066Sahrens 	 * but anything greater is an error.
1104fa9e4066Sahrens 	 */
1105fa9e4066Sahrens 	if (where < 0 || where > acl1->acl_cnt)
1106fa9e4066Sahrens 		return (EACL_INVALID_SLOT);
1107fa9e4066Sahrens 
1108fa9e4066Sahrens 	newsize = (acl2->acl_entry_size * acl2->acl_cnt) +
1109fa9e4066Sahrens 	    (acl1->acl_entry_size * acl1->acl_cnt);
1110fa9e4066Sahrens 	acl1->acl_aclp = realloc(acl1->acl_aclp, newsize);
1111fa9e4066Sahrens 	if (acl1->acl_aclp == NULL)
1112fa9e4066Sahrens 		return (-1);
1113fa9e4066Sahrens 
1114fa9e4066Sahrens 	/*
1115fa9e4066Sahrens 	 * first push down entries where new ones will be inserted
1116fa9e4066Sahrens 	 */
1117fa9e4066Sahrens 
1118fa9e4066Sahrens 	to = (void *)((char *)acl1->acl_aclp +
1119fa9e4066Sahrens 	    ((where + acl2->acl_cnt) * acl1->acl_entry_size));
1120fa9e4066Sahrens 
1121fa9e4066Sahrens 	start = (void *)((char *)acl1->acl_aclp +
1122fa9e4066Sahrens 	    where * acl1->acl_entry_size);
1123fa9e4066Sahrens 
1124fa9e4066Sahrens 	if (where < acl1->acl_cnt) {
1125fa9e4066Sahrens 		len = (acl1->acl_cnt - where) * acl1->acl_entry_size;
1126fa9e4066Sahrens 		(void) memmove(to, start, len);
1127fa9e4066Sahrens 	}
1128fa9e4066Sahrens 
1129fa9e4066Sahrens 	/*
1130fa9e4066Sahrens 	 * now stick in new entries.
1131fa9e4066Sahrens 	 */
1132fa9e4066Sahrens 
1133fa9e4066Sahrens 	(void) memmove(start, acl2->acl_aclp,
1134fa9e4066Sahrens 	    acl2->acl_cnt * acl2->acl_entry_size);
1135fa9e4066Sahrens 
1136fa9e4066Sahrens 	acl1->acl_cnt += acl2->acl_cnt;
1137fa9e4066Sahrens 	return (0);
1138fa9e4066Sahrens }
1139fa9e4066Sahrens 
1140fa9e4066Sahrens /*
1141fa9e4066Sahrens  * return text for an ACL error.
1142fa9e4066Sahrens  */
1143fa9e4066Sahrens char *
1144fa9e4066Sahrens acl_strerror(int errnum)
1145fa9e4066Sahrens {
1146fa9e4066Sahrens 	switch (errnum) {
1147fa9e4066Sahrens 	case EACL_GRP_ERROR:
1148fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1149*5a5eeccaSmarks 		    "There is more than one group or default group entry"));
1150fa9e4066Sahrens 	case EACL_USER_ERROR:
1151fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1152*5a5eeccaSmarks 		    "There is more than one user or default user entry"));
1153fa9e4066Sahrens 	case EACL_OTHER_ERROR:
1154fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1155fa9e4066Sahrens 		    "There is more than one other entry"));
1156fa9e4066Sahrens 	case EACL_CLASS_ERROR:
1157fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1158fa9e4066Sahrens 		    "There is more than one mask entry"));
1159fa9e4066Sahrens 	case EACL_DUPLICATE_ERROR:
1160fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1161fa9e4066Sahrens 		    "Duplicate user or group entries"));
1162fa9e4066Sahrens 	case EACL_MISS_ERROR:
1163fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1164fa9e4066Sahrens 		    "Missing user/group owner, other, mask entry"));
1165fa9e4066Sahrens 	case EACL_MEM_ERROR:
1166fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1167fa9e4066Sahrens 		    "Memory error"));
1168fa9e4066Sahrens 	case EACL_ENTRY_ERROR:
1169fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1170fa9e4066Sahrens 		    "Unrecognized entry type"));
1171fa9e4066Sahrens 	case EACL_INHERIT_ERROR:
1172fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1173fa9e4066Sahrens 		    "Invalid inheritance flags"));
1174fa9e4066Sahrens 	case EACL_FLAGS_ERROR:
1175fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1176fa9e4066Sahrens 		    "Unrecognized entry flags"));
1177fa9e4066Sahrens 	case EACL_PERM_MASK_ERROR:
1178fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1179fa9e4066Sahrens 		    "Invalid ACL permissions"));
1180fa9e4066Sahrens 	case EACL_COUNT_ERROR:
1181fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1182fa9e4066Sahrens 		    "Invalid ACL count"));
1183fa9e4066Sahrens 	case EACL_INVALID_SLOT:
1184fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1185fa9e4066Sahrens 		    "Invalid ACL entry number specified"));
1186fa9e4066Sahrens 	case EACL_NO_ACL_ENTRY:
1187fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1188fa9e4066Sahrens 		    "ACL entry doesn't exist"));
1189fa9e4066Sahrens 	case EACL_DIFF_TYPE:
1190fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1191fa9e4066Sahrens 		    "ACL type's are different"));
1192fa9e4066Sahrens 	case EACL_INVALID_USER_GROUP:
1193fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Invalid user or group"));
1194fa9e4066Sahrens 	case EACL_INVALID_STR:
1195fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "ACL string is invalid"));
1196fa9e4066Sahrens 	case EACL_FIELD_NOT_BLANK:
1197fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Field expected to be blank"));
1198fa9e4066Sahrens 	case EACL_INVALID_ACCESS_TYPE:
1199fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Invalid access type"));
1200fa9e4066Sahrens 	case EACL_UNKNOWN_DATA:
1201fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Unrecognized entry"));
1202fa9e4066Sahrens 	case EACL_MISSING_FIELDS:
1203fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1204fa9e4066Sahrens 		    "ACL specification missing required fields"));
1205fa9e4066Sahrens 	case EACL_INHERIT_NOTDIR:
1206fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN,
1207fa9e4066Sahrens 		    "Inheritance flags are only allowed on directories"));
1208fa9e4066Sahrens 	case -1:
1209fa9e4066Sahrens 		return (strerror(errno));
1210fa9e4066Sahrens 	default:
1211fa9e4066Sahrens 		errno = EINVAL;
1212fa9e4066Sahrens 		return (dgettext(TEXT_DOMAIN, "Unknown error"));
1213fa9e4066Sahrens 	}
1214fa9e4066Sahrens }
1215*5a5eeccaSmarks 
1216*5a5eeccaSmarks extern int yyinteractive;
1217*5a5eeccaSmarks 
1218*5a5eeccaSmarks /* PRINTFLIKE1 */
1219*5a5eeccaSmarks void
1220*5a5eeccaSmarks acl_error(const char *fmt, ...)
1221*5a5eeccaSmarks {
1222*5a5eeccaSmarks 	va_list va;
1223*5a5eeccaSmarks 
1224*5a5eeccaSmarks 	if (yyinteractive == 0)
1225*5a5eeccaSmarks 		return;
1226*5a5eeccaSmarks 
1227*5a5eeccaSmarks 	va_start(va, fmt);
1228*5a5eeccaSmarks 	(void) vfprintf(stderr, fmt, va);
1229*5a5eeccaSmarks 	va_end(va);
1230*5a5eeccaSmarks }
1231