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