10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*1420Smarks  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate /*LINTLIBRARY*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <grp.h>
310Sstevel@tonic-gate #include <pwd.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include <limits.h>
340Sstevel@tonic-gate #include <stdlib.h>
35789Sahrens #include <errno.h>
360Sstevel@tonic-gate #include <sys/param.h>
370Sstevel@tonic-gate #include <sys/types.h>
38*1420Smarks #include <sys/stat.h>
390Sstevel@tonic-gate #include <sys/acl.h>
40789Sahrens #include <aclutils.h>
41*1420Smarks 
42*1420Smarks #define	ID_STR_MAX	20	/* digits in LONG_MAX */
43789Sahrens 
44*1420Smarks #define	APPENDED_ID_MAX	ID_STR_MAX + 1		/* id + colon */
45*1420Smarks /*
46*1420Smarks  * yyinteractive controls whether yyparse should print out
47*1420Smarks  * error messages to stderr, and whether or not id's should be
48*1420Smarks  * allowed from acl_fromtext().
49*1420Smarks  */
50*1420Smarks int	yyinteractive;
51*1420Smarks acl_t	*yyacl;
52*1420Smarks char	*yybuf;
53789Sahrens 
54789Sahrens extern acl_t *acl_alloc(enum acl_type);
550Sstevel@tonic-gate 
56922Shm123892 
570Sstevel@tonic-gate struct dynaclstr {
580Sstevel@tonic-gate 	size_t bufsize;		/* current size of aclexport */
590Sstevel@tonic-gate 	char *aclexport;
600Sstevel@tonic-gate };
610Sstevel@tonic-gate 
620Sstevel@tonic-gate static char *strappend(char *, char *);
630Sstevel@tonic-gate static char *convert_perm(char *, o_mode_t);
640Sstevel@tonic-gate static int increase_length(struct dynaclstr *, size_t);
650Sstevel@tonic-gate 
66*1420Smarks static void
67*1420Smarks aclent_perms(int perm, char *txt_perms)
68*1420Smarks {
69*1420Smarks 	if (perm & S_IROTH)
70*1420Smarks 		txt_perms[0] = 'r';
71*1420Smarks 	else
72*1420Smarks 		txt_perms[0] = '-';
73*1420Smarks 	if (perm & S_IWOTH)
74*1420Smarks 		txt_perms[1] = 'w';
75*1420Smarks 	else
76*1420Smarks 		txt_perms[1] = '-';
77*1420Smarks 	if (perm & S_IXOTH)
78*1420Smarks 		txt_perms[2] = 'x';
79*1420Smarks 	else
80*1420Smarks 		txt_perms[2] = '-';
81*1420Smarks 	txt_perms[3] = '\0';
82*1420Smarks }
83*1420Smarks 
84*1420Smarks static char *
85*1420Smarks pruname(uid_t uid, char *uidp)
86*1420Smarks {
87*1420Smarks 	struct passwd	*passwdp;
88*1420Smarks 
89*1420Smarks 	passwdp = getpwuid(uid);
90*1420Smarks 	if (passwdp == (struct passwd *)NULL) {
91*1420Smarks 		/* could not get passwd information: display uid instead */
92*1420Smarks 		(void) sprintf(uidp, "%ld", (long)uid);
93*1420Smarks 		return (uidp);
94*1420Smarks 	} else
95*1420Smarks 		return (passwdp->pw_name);
96*1420Smarks }
97*1420Smarks 
98*1420Smarks static char *
99*1420Smarks prgname(gid_t gid, char *gidp)
100*1420Smarks {
101*1420Smarks 	struct group	*groupp;
102*1420Smarks 
103*1420Smarks 	groupp = getgrgid(gid);
104*1420Smarks 	if (groupp == (struct group *)NULL) {
105*1420Smarks 		/* could not get group information: display gid instead */
106*1420Smarks 		(void) sprintf(gidp, "%ld", (long)gid);
107*1420Smarks 		return (gidp);
108*1420Smarks 	} else
109*1420Smarks 		return (groupp->gr_name);
110*1420Smarks }
111*1420Smarks static void
112*1420Smarks aclent_printacl(acl_t *aclp)
113789Sahrens {
114*1420Smarks 	aclent_t *tp;
115*1420Smarks 	int aclcnt;
116*1420Smarks 	int mask;
117*1420Smarks 	int slot = 0;
118*1420Smarks 	char perm[4];
119*1420Smarks 	char uidp[10];
120*1420Smarks 	char gidp[10];
121*1420Smarks 
122*1420Smarks 	/* display ACL: assume it is sorted. */
123*1420Smarks 	aclcnt = aclp->acl_cnt;
124*1420Smarks 	for (tp = aclp->acl_aclp; tp && aclcnt--; tp++) {
125*1420Smarks 		if (tp->a_type == CLASS_OBJ)
126*1420Smarks 			mask = tp->a_perm;
127*1420Smarks 	}
128*1420Smarks 	aclcnt = aclp->acl_cnt;
129*1420Smarks 	for (tp = aclp->acl_aclp; aclcnt--; tp++) {
130*1420Smarks 		(void) printf("     %d:", slot++);
131*1420Smarks 		switch (tp->a_type) {
132*1420Smarks 		case USER:
133*1420Smarks 			aclent_perms(tp->a_perm, perm);
134*1420Smarks 			(void) printf("user:%s:%s\t\t",
135*1420Smarks 			    pruname(tp->a_id, uidp), perm);
136*1420Smarks 			aclent_perms((tp->a_perm & mask), perm);
137*1420Smarks 			(void) printf("#effective:%s\n", perm);
138*1420Smarks 			break;
139*1420Smarks 		case USER_OBJ:
140*1420Smarks 			/* no need to display uid */
141*1420Smarks 			aclent_perms(tp->a_perm, perm);
142*1420Smarks 			(void) printf("user::%s\n", perm);
143*1420Smarks 			break;
144*1420Smarks 		case GROUP:
145*1420Smarks 			aclent_perms(tp->a_perm, perm);
146*1420Smarks 			(void) printf("group:%s:%s\t\t",
147*1420Smarks 			    prgname(tp->a_id, gidp), perm);
148*1420Smarks 			aclent_perms(tp->a_perm & mask, perm);
149*1420Smarks 			(void) printf("#effective:%s\n", perm);
150*1420Smarks 			break;
151*1420Smarks 		case GROUP_OBJ:
152*1420Smarks 			aclent_perms(tp->a_perm, perm);
153*1420Smarks 			(void) printf("group::%s\t\t", perm);
154*1420Smarks 			aclent_perms(tp->a_perm & mask, perm);
155*1420Smarks 			(void) printf("#effective:%s\n", perm);
156*1420Smarks 			break;
157*1420Smarks 		case CLASS_OBJ:
158*1420Smarks 			aclent_perms(tp->a_perm, perm);
159*1420Smarks 			(void) printf("mask:%s\n", perm);
160*1420Smarks 			break;
161*1420Smarks 		case OTHER_OBJ:
162*1420Smarks 			aclent_perms(tp->a_perm, perm);
163*1420Smarks 			(void) printf("other:%s\n", perm);
164*1420Smarks 			break;
165*1420Smarks 		case DEF_USER:
166*1420Smarks 			aclent_perms(tp->a_perm, perm);
167*1420Smarks 			(void) printf("default:user:%s:%s\n",
168*1420Smarks 			    pruname(tp->a_id, uidp), perm);
169*1420Smarks 			break;
170*1420Smarks 		case DEF_USER_OBJ:
171*1420Smarks 			aclent_perms(tp->a_perm, perm);
172*1420Smarks 			(void) printf("default:user::%s\n", perm);
173*1420Smarks 			break;
174*1420Smarks 		case DEF_GROUP:
175*1420Smarks 			aclent_perms(tp->a_perm, perm);
176*1420Smarks 			(void) printf("default:group:%s:%s\n",
177*1420Smarks 			    prgname(tp->a_id, gidp), perm);
178*1420Smarks 			break;
179*1420Smarks 		case DEF_GROUP_OBJ:
180*1420Smarks 			aclent_perms(tp->a_perm, perm);
181*1420Smarks 			(void) printf("default:group::%s\n", perm);
182*1420Smarks 			break;
183*1420Smarks 		case DEF_CLASS_OBJ:
184*1420Smarks 			aclent_perms(tp->a_perm, perm);
185*1420Smarks 			(void) printf("default:mask:%s\n", perm);
186*1420Smarks 			break;
187*1420Smarks 		case DEF_OTHER_OBJ:
188*1420Smarks 			aclent_perms(tp->a_perm, perm);
189*1420Smarks 			(void) printf("default:other:%s\n", perm);
190*1420Smarks 			break;
191*1420Smarks 		default:
192*1420Smarks 			(void) fprintf(stderr,
193*1420Smarks 			    gettext("unrecognized entry\n"));
194*1420Smarks 			break;
195*1420Smarks 		}
196*1420Smarks 	}
197*1420Smarks }
198*1420Smarks 
199*1420Smarks static void
200*1420Smarks split_line(char *str, int cols)
201*1420Smarks {
202*1420Smarks 	char *ptr;
203*1420Smarks 	int len;
204*1420Smarks 	int i;
205*1420Smarks 	int last_split;
206*1420Smarks 	char *pad = "";
207*1420Smarks 	int pad_len;
208*1420Smarks 
209*1420Smarks 	len = strlen(str);
210*1420Smarks 	ptr = str;
211*1420Smarks 	pad_len = 0;
212*1420Smarks 
213*1420Smarks 	ptr = str;
214*1420Smarks 	last_split = 0;
215*1420Smarks 	for (i = 0; i != len; i++) {
216*1420Smarks 		if ((i + pad_len + 4) >= cols) {
217*1420Smarks 			(void) printf("%s%.*s\n", pad, last_split, ptr);
218*1420Smarks 			ptr = &ptr[last_split];
219*1420Smarks 			len = strlen(ptr);
220*1420Smarks 			i = 0;
221*1420Smarks 			pad_len = 4;
222*1420Smarks 			pad = "         ";
223*1420Smarks 		} else {
224*1420Smarks 			if (ptr[i] == '/' || ptr[i] == ':') {
225*1420Smarks 				last_split = i;
226*1420Smarks 			}
227*1420Smarks 		}
228*1420Smarks 	}
229*1420Smarks 	if (i == len) {
230*1420Smarks 		(void) printf("%s%s\n", pad, ptr);
231*1420Smarks 	}
232*1420Smarks }
233*1420Smarks 
234*1420Smarks #define	OWNERAT_TXT	"owner@"
235*1420Smarks #define	GROUPAT_TXT	"group@"
236*1420Smarks #define	EVERYONEAT_TXT	"everyone@"
237*1420Smarks #define	GROUP_TXT	"group:"
238*1420Smarks #define	USER_TXT	"user:"
239*1420Smarks 
240*1420Smarks char *
241*1420Smarks ace_type_txt(char *buf, char **endp, ace_t *acep)
242*1420Smarks {
243*1420Smarks 
244*1420Smarks 	char idp[10];
245*1420Smarks 
246*1420Smarks 	if (buf == NULL)
247*1420Smarks 		return (NULL);
248*1420Smarks 
249*1420Smarks 	switch (acep->a_flags & ACE_TYPE_FLAGS) {
250*1420Smarks 	case ACE_OWNER:
251*1420Smarks 		strcpy(buf, OWNERAT_TXT);
252*1420Smarks 		*endp = buf + sizeof (OWNERAT_TXT) - 1;
253*1420Smarks 		break;
254*1420Smarks 
255*1420Smarks 	case ACE_GROUP|ACE_IDENTIFIER_GROUP:
256*1420Smarks 		strcpy(buf, GROUPAT_TXT);
257*1420Smarks 		*endp = buf + sizeof (GROUPAT_TXT) - 1;
258*1420Smarks 		break;
259*1420Smarks 
260*1420Smarks 	case ACE_IDENTIFIER_GROUP:
261*1420Smarks 		strcpy(buf, GROUP_TXT);
262*1420Smarks 		strcat(buf, prgname(acep->a_who, idp));
263*1420Smarks 		*endp = buf + strlen(buf);
264*1420Smarks 		break;
265*1420Smarks 
266*1420Smarks 	case ACE_EVERYONE:
267*1420Smarks 		strcpy(buf, EVERYONEAT_TXT);
268*1420Smarks 		*endp = buf + sizeof (EVERYONEAT_TXT) - 1;
269*1420Smarks 		break;
270*1420Smarks 
271*1420Smarks 	case 0:
272*1420Smarks 		strcpy(buf, USER_TXT);
273*1420Smarks 		strcat(buf, pruname(acep->a_who, idp));
274*1420Smarks 		*endp = buf + strlen(buf);
275*1420Smarks 		break;
276*1420Smarks 	}
277*1420Smarks 
278*1420Smarks 	return (buf);
279*1420Smarks }
280*1420Smarks 
281*1420Smarks #define	READ_DATA_TXT	"read_data/"
282*1420Smarks #define	WRITE_DATA_TXT	"write_data/"
283*1420Smarks #define	EXECUTE_TXT	"execute/"
284*1420Smarks #define	READ_XATTR_TXT	"read_xattr/"
285*1420Smarks #define	WRITE_XATTR_TXT	"write_xattr/"
286*1420Smarks #define	READ_ATTRIBUTES_TXT "read_attributes/"
287*1420Smarks #define	WRITE_ATTRIBUTES_TXT "write_attributes/"
288*1420Smarks #define	DELETE_TXT	"delete/"
289*1420Smarks #define	DELETE_CHILD_TXT "delete_child/"
290*1420Smarks #define	WRITE_OWNER_TXT "write_owner/"
291*1420Smarks #define	READ_ACL_TXT	"read_acl/"
292*1420Smarks #define	WRITE_ACL_TXT	"write_acl/"
293*1420Smarks #define	APPEND_DATA_TXT "append_data/"
294*1420Smarks #define	READ_DIR_TXT	"list_directory/read_data/"
295*1420Smarks #define	ADD_DIR_TXT	"add_subdirectory/append_data/"
296*1420Smarks #define	ADD_FILE_TXT	"add_file/write_data/"
297*1420Smarks #define	SYNCHRONIZE_TXT "synchronize"	/* not slash on this one */
298*1420Smarks 
299*1420Smarks char *
300*1420Smarks ace_perm_txt(char *buf, char **endp, uint32_t mask,
301*1420Smarks     uint32_t iflags, int isdir, int flags)
302*1420Smarks {
303*1420Smarks 	char *lend = buf;		/* local end */
304*1420Smarks 
305*1420Smarks 	if (buf == NULL)
306*1420Smarks 		return (NULL);
307*1420Smarks 
308*1420Smarks 	if (flags & ACL_COMPACT_FMT) {
309789Sahrens 
310*1420Smarks 		if (mask & ACE_READ_DATA)
311*1420Smarks 			buf[0] = 'r';
312*1420Smarks 		else
313*1420Smarks 			buf[0] = '-';
314*1420Smarks 		if (mask & ACE_WRITE_DATA)
315*1420Smarks 			buf[1] = 'w';
316*1420Smarks 		else
317*1420Smarks 			buf[1] = '-';
318*1420Smarks 		if (mask & ACE_EXECUTE)
319*1420Smarks 			buf[2] = 'x';
320*1420Smarks 		else
321*1420Smarks 			buf[2] = '-';
322*1420Smarks 		if (mask & ACE_APPEND_DATA)
323*1420Smarks 			buf[3] = 'p';
324*1420Smarks 		else
325*1420Smarks 			buf[3] = '-';
326*1420Smarks 		if (mask & ACE_DELETE)
327*1420Smarks 			buf[4] = 'd';
328*1420Smarks 		else
329*1420Smarks 			buf[4] = '-';
330*1420Smarks 		if (mask & ACE_DELETE_CHILD)
331*1420Smarks 			buf[5] = 'D';
332*1420Smarks 		else
333*1420Smarks 			buf[5] = '-';
334*1420Smarks 		if (mask & ACE_READ_ATTRIBUTES)
335*1420Smarks 			buf[6] = 'a';
336*1420Smarks 		else
337*1420Smarks 			buf[6] = '-';
338*1420Smarks 		if (mask & ACE_WRITE_ATTRIBUTES)
339*1420Smarks 			buf[7] = 'A';
340*1420Smarks 		else
341*1420Smarks 			buf[7] = '-';
342*1420Smarks 		if (mask & ACE_READ_NAMED_ATTRS)
343*1420Smarks 			buf[8] = 'R';
344*1420Smarks 		else
345*1420Smarks 			buf[8] = '-';
346*1420Smarks 		if (mask & ACE_WRITE_NAMED_ATTRS)
347*1420Smarks 			buf[9] = 'W';
348*1420Smarks 		else
349*1420Smarks 			buf[9] = '-';
350*1420Smarks 		if (mask & ACE_READ_ACL)
351*1420Smarks 			buf[10] = 'c';
352*1420Smarks 		else
353*1420Smarks 			buf[10] = '-';
354*1420Smarks 		if (mask & ACE_WRITE_ACL)
355*1420Smarks 			buf[11] = 'C';
356*1420Smarks 		else
357*1420Smarks 			buf[11] = '-';
358*1420Smarks 		if (mask & ACE_WRITE_OWNER)
359*1420Smarks 			buf[12] = 'o';
360*1420Smarks 		else
361*1420Smarks 			buf[12] = '-';
362*1420Smarks 		if (mask & ACE_SYNCHRONIZE)
363*1420Smarks 			buf[13] = 's';
364*1420Smarks 		else
365*1420Smarks 			buf[13] = '-';
366*1420Smarks 		buf[14] = '\0';
367*1420Smarks 		*endp = buf + 14;
368*1420Smarks 		return (buf);
369*1420Smarks 	} else {
370*1420Smarks 		/*
371*1420Smarks 		 * If ACE is a directory, but inheritance indicates its
372*1420Smarks 		 * for a file then print permissions for file rather than
373*1420Smarks 		 * dir.
374*1420Smarks 		 */
375*1420Smarks 		if (isdir) {
376*1420Smarks 			if (mask & ACE_LIST_DIRECTORY) {
377*1420Smarks 				if (iflags == ACE_FILE_INHERIT_ACE) {
378*1420Smarks 					strcpy(lend, READ_DATA_TXT);
379*1420Smarks 					lend += sizeof (READ_DATA_TXT) - 1;
380*1420Smarks 				} else {
381*1420Smarks 					strcpy(lend, READ_DIR_TXT);
382*1420Smarks 					lend += sizeof (READ_DIR_TXT) - 1;
383*1420Smarks 				}
384*1420Smarks 			}
385*1420Smarks 			if (mask & ACE_ADD_FILE) {
386*1420Smarks 				if (iflags == ACE_FILE_INHERIT_ACE) {
387*1420Smarks 					strcpy(lend, WRITE_DATA_TXT);
388*1420Smarks 					lend += sizeof (WRITE_DATA_TXT) - 1;
389*1420Smarks 				} else {
390*1420Smarks 					strcpy(lend, ADD_FILE_TXT);
391*1420Smarks 					lend +=
392*1420Smarks 					    sizeof (ADD_FILE_TXT) -1;
393*1420Smarks 				}
394*1420Smarks 			}
395*1420Smarks 			if (mask & ACE_ADD_SUBDIRECTORY) {
396*1420Smarks 				if (iflags == ACE_FILE_INHERIT_ACE) {
397*1420Smarks 					strcpy(lend, APPEND_DATA_TXT);
398*1420Smarks 					lend += sizeof (APPEND_DATA_TXT) - 1;
399*1420Smarks 				} else {
400*1420Smarks 					strcpy(lend, ADD_DIR_TXT);
401*1420Smarks 					lend += sizeof (ADD_DIR_TXT) - 1;
402*1420Smarks 				}
403*1420Smarks 			}
404*1420Smarks 		} else {
405*1420Smarks 			if (mask & ACE_READ_DATA) {
406*1420Smarks 				strcpy(lend, READ_DATA_TXT);
407*1420Smarks 				lend += sizeof (READ_DATA_TXT) - 1;
408*1420Smarks 			}
409*1420Smarks 			if (mask & ACE_WRITE_DATA) {
410*1420Smarks 				strcpy(lend, WRITE_DATA_TXT);
411*1420Smarks 				lend += sizeof (WRITE_DATA_TXT) - 1;
412*1420Smarks 			}
413*1420Smarks 			if (mask & ACE_APPEND_DATA) {
414*1420Smarks 				strcpy(lend, APPEND_DATA_TXT);
415*1420Smarks 				lend += sizeof (APPEND_DATA_TXT) - 1;
416*1420Smarks 			}
417*1420Smarks 		}
418*1420Smarks 		if (mask & ACE_READ_NAMED_ATTRS) {
419*1420Smarks 			strcpy(lend, READ_XATTR_TXT);
420*1420Smarks 			lend += sizeof (READ_XATTR_TXT) - 1;
421*1420Smarks 		}
422*1420Smarks 		if (mask & ACE_WRITE_NAMED_ATTRS) {
423*1420Smarks 			strcpy(lend, WRITE_XATTR_TXT);
424*1420Smarks 			lend += sizeof (WRITE_XATTR_TXT) - 1;
425*1420Smarks 		}
426*1420Smarks 		if (mask & ACE_EXECUTE) {
427*1420Smarks 			strcpy(lend, EXECUTE_TXT);
428*1420Smarks 			lend += sizeof (EXECUTE_TXT) - 1;
429*1420Smarks 		}
430*1420Smarks 		if (mask & ACE_DELETE_CHILD) {
431*1420Smarks 			strcpy(lend, DELETE_CHILD_TXT);
432*1420Smarks 			lend += sizeof (DELETE_CHILD_TXT) - 1;
433*1420Smarks 		}
434*1420Smarks 		if (mask & ACE_READ_ATTRIBUTES) {
435*1420Smarks 			strcpy(lend, READ_ATTRIBUTES_TXT);
436*1420Smarks 			lend += sizeof (READ_ATTRIBUTES_TXT) - 1;
437*1420Smarks 		}
438*1420Smarks 		if (mask & ACE_WRITE_ATTRIBUTES) {
439*1420Smarks 			strcpy(lend, WRITE_ATTRIBUTES_TXT);
440*1420Smarks 			lend += sizeof (WRITE_ATTRIBUTES_TXT) - 1;
441*1420Smarks 		}
442*1420Smarks 		if (mask & ACE_DELETE) {
443*1420Smarks 			strcpy(lend, DELETE_TXT);
444*1420Smarks 			lend += sizeof (DELETE_TXT) - 1;
445*1420Smarks 		}
446*1420Smarks 		if (mask & ACE_READ_ACL) {
447*1420Smarks 			strcpy(lend, READ_ACL_TXT);
448*1420Smarks 			lend += sizeof (READ_ACL_TXT) - 1;
449*1420Smarks 		}
450*1420Smarks 		if (mask & ACE_WRITE_ACL) {
451*1420Smarks 			strcpy(lend, WRITE_ACL_TXT);
452*1420Smarks 			lend += sizeof (WRITE_ACL_TXT) - 1;
453*1420Smarks 		}
454*1420Smarks 		if (mask & ACE_WRITE_OWNER) {
455*1420Smarks 			strcpy(lend, WRITE_OWNER_TXT);
456*1420Smarks 			lend += sizeof (WRITE_OWNER_TXT) - 1;
457*1420Smarks 		}
458*1420Smarks 		if (mask & ACE_SYNCHRONIZE) {
459*1420Smarks 			strcpy(lend, SYNCHRONIZE_TXT);
460*1420Smarks 			lend += sizeof (SYNCHRONIZE_TXT) - 1;
461*1420Smarks 		}
462789Sahrens 
463*1420Smarks 		if (*(lend - 1) == '/')
464*1420Smarks 			*--lend = '\0';
465*1420Smarks 	}
466*1420Smarks 
467*1420Smarks 	*endp = lend;
468*1420Smarks 	return (buf);
469*1420Smarks }
470*1420Smarks 
471*1420Smarks #define	ALLOW_TXT	"allow"
472*1420Smarks #define	DENY_TXT	"deny"
473*1420Smarks #define	ALARM_TXT	"alarm"
474*1420Smarks #define	AUDIT_TXT	"audit"
475*1420Smarks #define	UNKNOWN_TXT	"unknown"
476*1420Smarks char *
477*1420Smarks ace_access_txt(char *buf, char **endp, int type)
478*1420Smarks {
479*1420Smarks 
480*1420Smarks 	if (buf == NULL)
481*1420Smarks 		return (NULL);
482*1420Smarks 
483*1420Smarks 	if (type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
484*1420Smarks 		strcpy(buf, ALLOW_TXT);
485*1420Smarks 		*endp += sizeof (ALLOW_TXT) - 1;
486*1420Smarks 	} else if (type == ACE_ACCESS_DENIED_ACE_TYPE) {
487*1420Smarks 		strcpy(buf, DENY_TXT);
488*1420Smarks 		*endp += sizeof (DENY_TXT) - 1;
489*1420Smarks 	} else if (type == ACE_SYSTEM_AUDIT_ACE_TYPE) {
490*1420Smarks 		strcpy(buf, AUDIT_TXT);
491*1420Smarks 		*endp += sizeof (AUDIT_TXT) - 1;
492*1420Smarks 	} else if (type == ACE_SYSTEM_ALARM_ACE_TYPE) {
493*1420Smarks 		strcpy(buf, ALARM_TXT);
494*1420Smarks 		*endp += sizeof (ALARM_TXT) - 1;
495*1420Smarks 	} else {
496*1420Smarks 		strcpy(buf, UNKNOWN_TXT);
497*1420Smarks 		*endp += sizeof (UNKNOWN_TXT) - 1;
498*1420Smarks 	}
499*1420Smarks 
500*1420Smarks 	return (buf);
501*1420Smarks }
502*1420Smarks 
503*1420Smarks static char *
504*1420Smarks ace_inherit_txt(char *buf, char **endp, uint32_t iflags, int flags)
505*1420Smarks {
506*1420Smarks 
507*1420Smarks 	char *lend = buf;
508*1420Smarks 
509*1420Smarks 	if (buf == NULL) {
510*1420Smarks 		return (NULL);
511*1420Smarks 	}
512789Sahrens 
513*1420Smarks 	if (flags & ACL_COMPACT_FMT) {
514*1420Smarks 		if (iflags & ACE_FILE_INHERIT_ACE)
515*1420Smarks 			buf[0] = 'f';
516*1420Smarks 		else
517*1420Smarks 			buf[0] = '-';
518*1420Smarks 		if (iflags & ACE_DIRECTORY_INHERIT_ACE)
519*1420Smarks 			buf[1] = 'd';
520*1420Smarks 		else
521*1420Smarks 			buf[1] = '-';
522*1420Smarks 		if (iflags & ACE_INHERIT_ONLY_ACE)
523*1420Smarks 			buf[2] = 'i';
524*1420Smarks 		else
525*1420Smarks 			buf[2] = '-';
526*1420Smarks 		if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)
527*1420Smarks 			buf[3] = 'n';
528*1420Smarks 		else
529*1420Smarks 			buf[3] = '-';
530*1420Smarks 		if (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
531*1420Smarks 			buf[4] = 'S';
532*1420Smarks 		else
533*1420Smarks 			buf[4] = '-';
534*1420Smarks 		if (iflags & ACE_FAILED_ACCESS_ACE_FLAG)
535*1420Smarks 			buf[5] = 'F';
536*1420Smarks 		else
537*1420Smarks 			buf[5] = '-';
538*1420Smarks 		buf[6] = '\0';
539*1420Smarks 		*endp = buf + 6;
540*1420Smarks 	} else {
541*1420Smarks 		if (iflags & ACE_FILE_INHERIT_ACE) {
542*1420Smarks 			strcpy(lend, "file_inherit/");
543*1420Smarks 			lend += sizeof ("file_inherit/") - 1;
544*1420Smarks 		}
545*1420Smarks 		if (iflags & ACE_DIRECTORY_INHERIT_ACE) {
546*1420Smarks 			strcpy(lend, "dir_inherit/");
547*1420Smarks 			lend += sizeof ("dir_inherit/") - 1;
548*1420Smarks 		}
549*1420Smarks 		if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE) {
550*1420Smarks 			strcpy(lend, "no_propagate/");
551*1420Smarks 			lend += sizeof ("no_propagate/") - 1;
552*1420Smarks 		}
553*1420Smarks 		if (iflags & ACE_INHERIT_ONLY_ACE) {
554*1420Smarks 			strcpy(lend, "inherit_only/");
555*1420Smarks 			lend += sizeof ("inherit_only/") - 1;
556*1420Smarks 		}
557789Sahrens 
558*1420Smarks 		if (*(lend - 1) == '/')
559*1420Smarks 			*--lend = '\0';
560*1420Smarks 		*endp = lend;
561*1420Smarks 	}
562*1420Smarks 
563*1420Smarks 	return (buf);
564789Sahrens }
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate /*
5670Sstevel@tonic-gate  * Convert internal acl representation to external representation.
5680Sstevel@tonic-gate  *
5690Sstevel@tonic-gate  * The length of a non-owning user name or non-owning group name ie entries
5700Sstevel@tonic-gate  * of type DEF_USER, USER, DEF_GROUP or GROUP, can exceed LOGNAME_MAX.  We
5710Sstevel@tonic-gate  * thus check the length of these entries, and if greater than LOGNAME_MAX,
5720Sstevel@tonic-gate  * we realloc() via increase_length().
5730Sstevel@tonic-gate  *
5740Sstevel@tonic-gate  * The LOGNAME_MAX, ENTRYTYPELEN and PERMS limits are otherwise always
5750Sstevel@tonic-gate  * adhered to.
5760Sstevel@tonic-gate  */
577*1420Smarks 
578*1420Smarks /*
579*1420Smarks  * acltotext() converts each ACL entry to look like this:
580*1420Smarks  *
581*1420Smarks  *    entry_type:uid^gid^name:perms[:id]
582*1420Smarks  *
583*1420Smarks  * The maximum length of entry_type is 14 ("defaultgroup::" and
584*1420Smarks  * "defaultother::") hence ENTRYTYPELEN is set to 14.
585*1420Smarks  *
586*1420Smarks  * The max length of a uid^gid^name entry (in theory) is 8, hence we use,
587*1420Smarks  * however the ID could be a number so we therefore use ID_STR_MAX
588*1420Smarks  *
589*1420Smarks  * The length of a perms entry is 4 to allow for the comma appended to each
590*1420Smarks  * to each acl entry.  Hence PERMS is set to 4.
591*1420Smarks  */
592*1420Smarks 
593*1420Smarks #define	ENTRYTYPELEN	14
594*1420Smarks #define	PERMS		4
595*1420Smarks #define	ACL_ENTRY_SIZE	(ENTRYTYPELEN + ID_STR_MAX + PERMS + APPENDED_ID_MAX)
596*1420Smarks #define	UPDATE_WHERE	where = dstr->aclexport + strlen(dstr->aclexport)
597*1420Smarks 
5980Sstevel@tonic-gate char *
599*1420Smarks aclent_acltotext(aclent_t  *aclp, int aclcnt, int flags)
6000Sstevel@tonic-gate {
6010Sstevel@tonic-gate 	char		*aclexport;
6020Sstevel@tonic-gate 	char		*where;
6030Sstevel@tonic-gate 	struct group	*groupp;
6040Sstevel@tonic-gate 	struct passwd	*passwdp;
6050Sstevel@tonic-gate 	struct dynaclstr *dstr;
6060Sstevel@tonic-gate 	int		i, rtn;
6070Sstevel@tonic-gate 	size_t		excess = 0;
608*1420Smarks 	char		id[20], *idstr;
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	if (aclp == NULL)
6110Sstevel@tonic-gate 		return (NULL);
6120Sstevel@tonic-gate 	if ((dstr = malloc(sizeof (struct dynaclstr))) == NULL)
6130Sstevel@tonic-gate 		return (NULL);
6140Sstevel@tonic-gate 	dstr->bufsize = aclcnt * ACL_ENTRY_SIZE;
6150Sstevel@tonic-gate 	if ((dstr->aclexport = malloc(dstr->bufsize)) == NULL) {
6160Sstevel@tonic-gate 		free(dstr);
6170Sstevel@tonic-gate 		return (NULL);
6180Sstevel@tonic-gate 	}
6190Sstevel@tonic-gate 	*dstr->aclexport = '\0';
6200Sstevel@tonic-gate 	where = dstr->aclexport;
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	for (i = 0; i < aclcnt; i++, aclp++) {
6230Sstevel@tonic-gate 		switch (aclp->a_type) {
6240Sstevel@tonic-gate 		case DEF_USER_OBJ:
6250Sstevel@tonic-gate 		case USER_OBJ:
6260Sstevel@tonic-gate 			if (aclp->a_type == USER_OBJ)
6270Sstevel@tonic-gate 				where = strappend(where, "user::");
6280Sstevel@tonic-gate 			else
6290Sstevel@tonic-gate 				where = strappend(where, "defaultuser::");
6300Sstevel@tonic-gate 			where = convert_perm(where, aclp->a_perm);
6310Sstevel@tonic-gate 			break;
6320Sstevel@tonic-gate 		case DEF_USER:
6330Sstevel@tonic-gate 		case USER:
6340Sstevel@tonic-gate 			if (aclp->a_type == USER)
6350Sstevel@tonic-gate 				where = strappend(where, "user:");
6360Sstevel@tonic-gate 			else
6370Sstevel@tonic-gate 				where = strappend(where, "defaultuser:");
6380Sstevel@tonic-gate 			passwdp = getpwuid(aclp->a_id);
6390Sstevel@tonic-gate 			if (passwdp == (struct passwd *)NULL) {
6400Sstevel@tonic-gate 				/* put in uid instead */
6410Sstevel@tonic-gate 				(void) sprintf(where, "%d", aclp->a_id);
642922Shm123892 				UPDATE_WHERE;
6430Sstevel@tonic-gate 			} else {
6440Sstevel@tonic-gate 				excess = strlen(passwdp->pw_name) - LOGNAME_MAX;
6450Sstevel@tonic-gate 				if (excess > 0) {
6460Sstevel@tonic-gate 					rtn = increase_length(dstr, excess);
6470Sstevel@tonic-gate 					if (rtn == 1) {
648922Shm123892 						UPDATE_WHERE;
6490Sstevel@tonic-gate 					} else {
6500Sstevel@tonic-gate 						free(dstr->aclexport);
6510Sstevel@tonic-gate 						free(dstr);
6520Sstevel@tonic-gate 						return (NULL);
6530Sstevel@tonic-gate 					}
6540Sstevel@tonic-gate 				}
6550Sstevel@tonic-gate 				where = strappend(where, passwdp->pw_name);
6560Sstevel@tonic-gate 			}
6570Sstevel@tonic-gate 			where = strappend(where, ":");
6580Sstevel@tonic-gate 			where = convert_perm(where, aclp->a_perm);
6590Sstevel@tonic-gate 			break;
6600Sstevel@tonic-gate 		case DEF_GROUP_OBJ:
6610Sstevel@tonic-gate 		case GROUP_OBJ:
6620Sstevel@tonic-gate 			if (aclp->a_type == GROUP_OBJ)
6630Sstevel@tonic-gate 				where = strappend(where, "group::");
6640Sstevel@tonic-gate 			else
6650Sstevel@tonic-gate 				where = strappend(where, "defaultgroup::");
6660Sstevel@tonic-gate 			where = convert_perm(where, aclp->a_perm);
6670Sstevel@tonic-gate 			break;
6680Sstevel@tonic-gate 		case DEF_GROUP:
6690Sstevel@tonic-gate 		case GROUP:
6700Sstevel@tonic-gate 			if (aclp->a_type == GROUP)
6710Sstevel@tonic-gate 				where = strappend(where, "group:");
6720Sstevel@tonic-gate 			else
6730Sstevel@tonic-gate 				where = strappend(where, "defaultgroup:");
6740Sstevel@tonic-gate 			groupp = getgrgid(aclp->a_id);
6750Sstevel@tonic-gate 			if (groupp == (struct group *)NULL) {
6760Sstevel@tonic-gate 				/* put in gid instead */
6770Sstevel@tonic-gate 				(void) sprintf(where, "%d", aclp->a_id);
678922Shm123892 				UPDATE_WHERE;
6790Sstevel@tonic-gate 			} else {
6800Sstevel@tonic-gate 				excess = strlen(groupp->gr_name) - LOGNAME_MAX;
6810Sstevel@tonic-gate 				if (excess > 0) {
6820Sstevel@tonic-gate 					rtn = increase_length(dstr, excess);
6830Sstevel@tonic-gate 					if (rtn == 1) {
684922Shm123892 						UPDATE_WHERE;
6850Sstevel@tonic-gate 					} else {
6860Sstevel@tonic-gate 						free(dstr->aclexport);
6870Sstevel@tonic-gate 						free(dstr);
6880Sstevel@tonic-gate 						return (NULL);
6890Sstevel@tonic-gate 					}
6900Sstevel@tonic-gate 				}
6910Sstevel@tonic-gate 				where = strappend(where, groupp->gr_name);
6920Sstevel@tonic-gate 			}
6930Sstevel@tonic-gate 			where = strappend(where, ":");
6940Sstevel@tonic-gate 			where = convert_perm(where, aclp->a_perm);
6950Sstevel@tonic-gate 			break;
6960Sstevel@tonic-gate 		case DEF_CLASS_OBJ:
6970Sstevel@tonic-gate 		case CLASS_OBJ:
6980Sstevel@tonic-gate 			if (aclp->a_type == CLASS_OBJ)
6990Sstevel@tonic-gate 				where = strappend(where, "mask:");
7000Sstevel@tonic-gate 			else
7010Sstevel@tonic-gate 				where = strappend(where, "defaultmask:");
7020Sstevel@tonic-gate 			where = convert_perm(where, aclp->a_perm);
7030Sstevel@tonic-gate 			break;
7040Sstevel@tonic-gate 		case DEF_OTHER_OBJ:
7050Sstevel@tonic-gate 		case OTHER_OBJ:
7060Sstevel@tonic-gate 			if (aclp->a_type == OTHER_OBJ)
7070Sstevel@tonic-gate 				where = strappend(where, "other:");
7080Sstevel@tonic-gate 			else
7090Sstevel@tonic-gate 				where = strappend(where, "defaultother:");
7100Sstevel@tonic-gate 			where = convert_perm(where, aclp->a_perm);
7110Sstevel@tonic-gate 			break;
7120Sstevel@tonic-gate 		default:
7130Sstevel@tonic-gate 			free(dstr->aclexport);
7140Sstevel@tonic-gate 			free(dstr);
7150Sstevel@tonic-gate 			return (NULL);
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 		}
718*1420Smarks 
719*1420Smarks 		if ((flags & ACL_APPEND_ID) && ((aclp->a_type == USER) ||
720*1420Smarks 		    (aclp->a_type == DEF_USER) || (aclp->a_type == GROUP) ||
721*1420Smarks 		    (aclp->a_type == DEF_GROUP))) {
722*1420Smarks 			where = strappend(where, ":");
723*1420Smarks 			id[ID_STR_MAX - 1] = '\0'; /* null terminate buffer */
724*1420Smarks 			idstr = lltostr(aclp->a_id, &id[ID_STR_MAX - 1]);
725*1420Smarks 			where = strappend(where, idstr);
726*1420Smarks 		}
7270Sstevel@tonic-gate 		if (i < aclcnt - 1)
7280Sstevel@tonic-gate 			where = strappend(where, ",");
7290Sstevel@tonic-gate 	}
7300Sstevel@tonic-gate 	aclexport = dstr->aclexport;
7310Sstevel@tonic-gate 	free(dstr);
7320Sstevel@tonic-gate 	return (aclexport);
733*1420Smarks 
734*1420Smarks 
735*1420Smarks 
736*1420Smarks 
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate 
739*1420Smarks char *
740*1420Smarks acltotext(aclent_t *aclp, int aclcnt)
7410Sstevel@tonic-gate {
742*1420Smarks 	return (aclent_acltotext(aclp, aclcnt, 0));
743*1420Smarks }
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 
746789Sahrens aclent_t *
747789Sahrens aclfromtext(char *aclstr, int *aclcnt)
748789Sahrens {
749789Sahrens 	acl_t *aclp;
750789Sahrens 	aclent_t *aclentp;
751789Sahrens 	int error;
752789Sahrens 
753*1420Smarks 	error = acl_fromtext(aclstr, &aclp);
754789Sahrens 	if (error)
755789Sahrens 		return (NULL);
756789Sahrens 
757789Sahrens 	aclentp = aclp->acl_aclp;
758789Sahrens 	aclp->acl_aclp = NULL;
759*1420Smarks 	*aclcnt = aclp->acl_cnt;
760789Sahrens 
761*1420Smarks 	acl_free(aclp);
762789Sahrens 	return (aclentp);
763789Sahrens }
764789Sahrens 
765789Sahrens 
7660Sstevel@tonic-gate static char *
7670Sstevel@tonic-gate strappend(char *where, char *newstr)
7680Sstevel@tonic-gate {
7690Sstevel@tonic-gate 	(void) strcat(where, newstr);
7700Sstevel@tonic-gate 	return (where + strlen(newstr));
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate static char *
7740Sstevel@tonic-gate convert_perm(char *where, o_mode_t perm)
7750Sstevel@tonic-gate {
776*1420Smarks 	if (perm & S_IROTH)
7770Sstevel@tonic-gate 		where = strappend(where, "r");
7780Sstevel@tonic-gate 	else
7790Sstevel@tonic-gate 		where = strappend(where, "-");
780*1420Smarks 	if (perm & S_IWOTH)
7810Sstevel@tonic-gate 		where = strappend(where, "w");
7820Sstevel@tonic-gate 	else
7830Sstevel@tonic-gate 		where = strappend(where, "-");
784*1420Smarks 	if (perm & S_IXOTH)
7850Sstevel@tonic-gate 		where = strappend(where, "x");
7860Sstevel@tonic-gate 	else
7870Sstevel@tonic-gate 		where = strappend(where, "-");
7880Sstevel@tonic-gate 	/* perm is the last field */
7890Sstevel@tonic-gate 	return (where);
7900Sstevel@tonic-gate }
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate /*
7930Sstevel@tonic-gate  * Callers should check the return code as this routine may change the string
7940Sstevel@tonic-gate  * pointer in dynaclstr.
7950Sstevel@tonic-gate  */
7960Sstevel@tonic-gate static int
7970Sstevel@tonic-gate increase_length(struct dynaclstr *dacl, size_t increase)
7980Sstevel@tonic-gate {
7990Sstevel@tonic-gate 	char *tptr;
8000Sstevel@tonic-gate 	size_t newsize;
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	newsize = dacl->bufsize + increase;
8030Sstevel@tonic-gate 	tptr = realloc(dacl->aclexport, newsize);
8040Sstevel@tonic-gate 	if (tptr != NULL) {
8050Sstevel@tonic-gate 		dacl->aclexport = tptr;
8060Sstevel@tonic-gate 		dacl->bufsize = newsize;
8070Sstevel@tonic-gate 		return (1);
8080Sstevel@tonic-gate 	} else
8090Sstevel@tonic-gate 		return (0);
8100Sstevel@tonic-gate }
811789Sahrens 
812789Sahrens /*
813*1420Smarks  * ace_acltotext() convert each ace formatted acl to look like this:
814789Sahrens  *
815*1420Smarks  * entry_type:uid^gid^name:perms[:flags]:<allow|deny>[:id][,]
816789Sahrens  *
817789Sahrens  * The maximum length of entry_type is 5 ("group")
818789Sahrens  *
819*1420Smarks  * The max length of a uid^gid^name entry (in theory) is 8,
820*1420Smarks  * however id could be a number so we therefore use ID_STR_MAX
821789Sahrens  *
822789Sahrens  * The length of a perms entry is 144 i.e read_data/write_data...
823789Sahrens  * to each acl entry.
824789Sahrens  *
825789Sahrens  * iflags: file_inherit/dir_inherit/inherit_only/no_propagate
826789Sahrens  *
827789Sahrens  */
828789Sahrens 
829789Sahrens #define	ACE_ENTRYTYPLEN		6
830789Sahrens #define	IFLAGS_SIZE		51
831*1420Smarks #define	ACCESS_TYPE_SIZE	7	/* if unknown */
832789Sahrens #define	COLON_CNT		3
833789Sahrens #define	PERMS_LEN		216
834*1420Smarks #define	ACE_ENTRY_SIZE	(ACE_ENTRYTYPLEN + ID_STR_MAX + PERMS_LEN +\
835*1420Smarks     ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT + APPENDED_ID_MAX)
836789Sahrens 
837789Sahrens static char *
838*1420Smarks ace_acltotext(acl_t *aceaclp, int flags)
839789Sahrens {
840789Sahrens 	ace_t		*aclp = aceaclp->acl_aclp;
841789Sahrens 	int		aclcnt = aceaclp->acl_cnt;
842789Sahrens 	char		*aclexport;
843*1420Smarks 	char		*endp;
844*1420Smarks 	int		i;
845*1420Smarks 	char		id[ID_STR_MAX], *idstr;
846789Sahrens 	int		isdir = (aceaclp->acl_flags & ACL_IS_DIR);
847789Sahrens 
848789Sahrens 	if (aclp == NULL)
849789Sahrens 		return (NULL);
850*1420Smarks 	if ((aclexport = malloc(aclcnt * ACE_ENTRY_SIZE)) == NULL)
851789Sahrens 		return (NULL);
852789Sahrens 
853*1420Smarks 	aclexport[0] = '\0';
854*1420Smarks 	endp = aclexport;
855789Sahrens 	for (i = 0; i < aclcnt; i++, aclp++) {
856*1420Smarks 
857*1420Smarks 		(void) ace_type_txt(endp, &endp, aclp);
858*1420Smarks 		*endp++ = ':';
859*1420Smarks 		*endp = '\0';
860*1420Smarks 		(void) ace_perm_txt(endp, &endp, aclp->a_access_mask,
861*1420Smarks 		    aclp->a_flags, isdir, flags);
862*1420Smarks 		*endp++ = ':';
863*1420Smarks 		*endp = '\0';
864*1420Smarks 		(void) ace_inherit_txt(endp, &endp, aclp->a_flags, flags);
865*1420Smarks 		if (flags & ACL_COMPACT_FMT || aclp->a_flags &
866*1420Smarks 		    (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE |
867*1420Smarks 		    (ACE_INHERIT_ONLY_ACE | ACE_NO_PROPAGATE_INHERIT_ACE))) {
868*1420Smarks 			*endp++ = ':';
869*1420Smarks 			*endp = '\0';
870*1420Smarks 		}
871*1420Smarks 		(void) ace_access_txt(endp, &endp, aclp->a_type);
872789Sahrens 
873*1420Smarks 		if ((flags & ACL_APPEND_ID) &&
874*1420Smarks 		    (((aclp->a_flags & ACE_TYPE_FLAGS) == 0) ||
875*1420Smarks 		    ((aclp->a_flags & ACE_TYPE_FLAGS) ==
876*1420Smarks 		    ACE_IDENTIFIER_GROUP))) {
877*1420Smarks 			*endp++ = ':';
878*1420Smarks 			*endp = '\0';
879*1420Smarks 			id[ID_STR_MAX -1] = '\0'; /* null terminate buffer */
880*1420Smarks 			idstr = lltostr(aclp->a_who, &id[ID_STR_MAX - 1]);
881*1420Smarks 			strcpy(endp, idstr);
882*1420Smarks 			endp += strlen(idstr);
883789Sahrens 		}
884*1420Smarks 		if (i < aclcnt - 1) {
885*1420Smarks 			*endp++ = ',';
886*1420Smarks 			*(endp + 1) = '\0';
887789Sahrens 		}
888789Sahrens 	}
889789Sahrens 	return (aclexport);
890789Sahrens }
891789Sahrens 
892*1420Smarks char *
893*1420Smarks acl_totext(acl_t *aclp, int flags)
894789Sahrens {
895789Sahrens 
896*1420Smarks 	char *txtp;
897789Sahrens 
898789Sahrens 	if (aclp == NULL)
899789Sahrens 		return (NULL);
900789Sahrens 
901789Sahrens 	switch (aclp->acl_type) {
902789Sahrens 	case ACE_T:
903*1420Smarks 		txtp = ace_acltotext(aclp, flags);
904*1420Smarks 		break;
905789Sahrens 	case ACLENT_T:
906*1420Smarks 		txtp = aclent_acltotext(aclp->acl_aclp, aclp->acl_cnt, flags);
907*1420Smarks 		break;
908789Sahrens 	}
909*1420Smarks 
910*1420Smarks 	return (txtp);
911789Sahrens }
912789Sahrens 
913789Sahrens int
914789Sahrens acl_fromtext(const char *acltextp, acl_t **ret_aclp)
915789Sahrens {
916*1420Smarks 	int error;
917*1420Smarks 	char *buf;
918*1420Smarks 
919*1420Smarks 	buf = malloc(strlen(acltextp) + 2);
920*1420Smarks 	if (buf == NULL)
921*1420Smarks 		return (EACL_MEM_ERROR);
922*1420Smarks 	strcpy(buf, acltextp);
923*1420Smarks 	strcat(buf, "\n");
924*1420Smarks 	yybuf = buf;
925*1420Smarks 	yyreset();
926*1420Smarks 	error = yyparse();
927*1420Smarks 	free(buf);
928*1420Smarks 
929*1420Smarks 	if (yyacl) {
930*1420Smarks 		if (error == 0)
931*1420Smarks 			*ret_aclp = yyacl;
932*1420Smarks 		else {
933*1420Smarks 			acl_free(yyacl);
934*1420Smarks 		}
935*1420Smarks 		yyacl = NULL;
936*1420Smarks 	}
937*1420Smarks 	return (error);
938*1420Smarks }
939*1420Smarks 
940*1420Smarks int
941*1420Smarks acl_parse(const char *acltextp, acl_t **aclp)
942*1420Smarks {
943789Sahrens 	int error;
944789Sahrens 
945*1420Smarks 	yyinteractive = 1;
946*1420Smarks 	error = acl_fromtext(acltextp, aclp);
947*1420Smarks 	yyinteractive = 0;
948*1420Smarks 	return (error);
949*1420Smarks }
950*1420Smarks 
951*1420Smarks static void
952*1420Smarks ace_compact_printacl(acl_t *aclp)
953*1420Smarks {
954*1420Smarks 	int cnt;
955*1420Smarks 	ace_t *acep;
956*1420Smarks 	char *endp;
957*1420Smarks 	char buf[ACE_ENTRY_SIZE];
958789Sahrens 
959*1420Smarks 	for (cnt = 0, acep = aclp->acl_aclp;
960*1420Smarks 	    cnt != aclp->acl_cnt; cnt++, acep++) {
961*1420Smarks 		buf[0] = '\0';
962*1420Smarks 		(void) printf("    %14s:", ace_type_txt(buf, &endp, acep));
963*1420Smarks 		(void) printf("%s:", ace_perm_txt(endp, &endp,
964*1420Smarks 		    acep->a_access_mask, acep->a_flags,
965*1420Smarks 		    aclp->acl_flags & ACL_IS_DIR, ACL_COMPACT_FMT));
966*1420Smarks 		(void) printf("%s:",
967*1420Smarks 		    ace_inherit_txt(endp, &endp, acep->a_flags,
968*1420Smarks 			ACL_COMPACT_FMT));
969*1420Smarks 		(void) printf("%s\n", ace_access_txt(endp, &endp,
970*1420Smarks 		    acep->a_type));
971*1420Smarks 	}
972*1420Smarks }
973789Sahrens 
974*1420Smarks static void
975*1420Smarks ace_printacl(acl_t *aclp, int cols, int compact)
976*1420Smarks {
977*1420Smarks 	int  slot = 0;
978*1420Smarks 	char *token;
979*1420Smarks 	char *acltext;
980*1420Smarks 
981*1420Smarks 	if (compact) {
982*1420Smarks 		ace_compact_printacl(aclp);
983*1420Smarks 		return;
984789Sahrens 	}
985789Sahrens 
986*1420Smarks 	acltext = acl_totext(aclp, 0);
987*1420Smarks 
988*1420Smarks 	if (acltext == NULL)
989*1420Smarks 		return;
990*1420Smarks 
991*1420Smarks 	token = strtok(acltext, ",");
992*1420Smarks 	if (token == NULL) {
993*1420Smarks 		free(acltext);
994*1420Smarks 		return;
995789Sahrens 	}
996789Sahrens 
997*1420Smarks 	do {
998*1420Smarks 		(void) printf("     %d:", slot++);
999*1420Smarks 		split_line(token, cols - 5);
1000*1420Smarks 	} while (token = strtok(NULL, ","));
1001*1420Smarks 	free(acltext);
1002*1420Smarks }
1003*1420Smarks 
1004*1420Smarks /*
1005*1420Smarks  * pretty print an ACL.
1006*1420Smarks  * For aclent_t ACL's the format is
1007*1420Smarks  * similar to the old format used by getfacl,
1008*1420Smarks  * with the addition of adding a "slot" number
1009*1420Smarks  * before each entry.
1010*1420Smarks  *
1011*1420Smarks  * for ace_t ACL's the cols variable will break up
1012*1420Smarks  * the long lines into multiple lines and will also
1013*1420Smarks  * print a "slot" number.
1014*1420Smarks  */
1015*1420Smarks void
1016*1420Smarks acl_printacl(acl_t *aclp, int cols, int compact)
1017*1420Smarks {
1018*1420Smarks 
1019*1420Smarks 	switch (aclp->acl_type) {
1020*1420Smarks 	case ACLENT_T:
1021*1420Smarks 		aclent_printacl(aclp);
1022*1420Smarks 		break;
1023*1420Smarks 	case ACE_T:
1024*1420Smarks 		ace_printacl(aclp, cols, compact);
1025*1420Smarks 		break;
1026*1420Smarks 	}
1027*1420Smarks }
1028*1420Smarks 
1029*1420Smarks typedef struct value_table {
1030*1420Smarks 	char		p_letter; /* perm letter such as 'r' */
1031*1420Smarks 	uint32_t	p_value; /* value for perm when pletter found */
1032*1420Smarks } value_table_t;
1033*1420Smarks 
1034*1420Smarks #define	ACE_PERM_COUNT 14
1035*1420Smarks 
1036*1420Smarks /*
1037*1420Smarks  * The permission tables are layed out in positional order
1038*1420Smarks  * a '-' character will indicate a permission at a given
1039*1420Smarks  * position is not specified.  The '-' is not part of the
1040*1420Smarks  * table, but will be checked for in the permission computation
1041*1420Smarks  * routine.
1042*1420Smarks  */
1043*1420Smarks value_table_t ace_perm_table[ACE_PERM_COUNT] = {
1044*1420Smarks 	{ 'r', ACE_READ_DATA},
1045*1420Smarks 	{ 'w', ACE_WRITE_DATA},
1046*1420Smarks 	{ 'x', ACE_EXECUTE},
1047*1420Smarks 	{ 'p', ACE_APPEND_DATA},
1048*1420Smarks 	{ 'd', ACE_DELETE},
1049*1420Smarks 	{ 'D', ACE_DELETE_CHILD},
1050*1420Smarks 	{ 'a', ACE_READ_ATTRIBUTES},
1051*1420Smarks 	{ 'A', ACE_WRITE_ATTRIBUTES},
1052*1420Smarks 	{ 'R', ACE_READ_NAMED_ATTRS},
1053*1420Smarks 	{ 'W', ACE_WRITE_NAMED_ATTRS},
1054*1420Smarks 	{ 'c', ACE_READ_ACL},
1055*1420Smarks 	{ 'C', ACE_WRITE_ACL},
1056*1420Smarks 	{ 'o', ACE_WRITE_OWNER},
1057*1420Smarks 	{ 's', ACE_SYNCHRONIZE}
1058*1420Smarks };
1059*1420Smarks 
1060*1420Smarks #define	ACLENT_PERM_COUNT 3
1061*1420Smarks 
1062*1420Smarks value_table_t aclent_perm_table[ACLENT_PERM_COUNT] = {
1063*1420Smarks 	{ 'r', S_IROTH},
1064*1420Smarks 	{ 'w', S_IWOTH},
1065*1420Smarks 	{ 'x', S_IXOTH}
1066*1420Smarks };
1067*1420Smarks 
1068*1420Smarks #define	IFLAG_COUNT	6
1069*1420Smarks value_table_t inherit_table[IFLAG_COUNT] = {
1070*1420Smarks 	{'f', ACE_FILE_INHERIT_ACE},
1071*1420Smarks 	{'d', ACE_DIRECTORY_INHERIT_ACE},
1072*1420Smarks 	{'i', ACE_INHERIT_ONLY_ACE},
1073*1420Smarks 	{'n', ACE_NO_PROPAGATE_INHERIT_ACE},
1074*1420Smarks 	{'S', ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
1075*1420Smarks 	{'F', ACE_FAILED_ACCESS_ACE_FLAG}
1076*1420Smarks };
1077*1420Smarks 
1078*1420Smarks /*
1079*1420Smarks  * compute value from a permission table or inheritance table
1080*1420Smarks  * based on string passed in.  If positional is set then
1081*1420Smarks  * string must match order in permtab, otherwise any order
1082*1420Smarks  * is allowed.
1083*1420Smarks  */
1084*1420Smarks int
1085*1420Smarks compute_values(value_table_t *permtab, int count,
1086*1420Smarks     char *permstr, int positional, uint32_t *mask)
1087*1420Smarks {
1088*1420Smarks 	uint32_t perm_val = 0;
1089*1420Smarks 	char *pstr;
1090*1420Smarks 	int i, found;
1091*1420Smarks 
1092*1420Smarks 	if (count < 0)
1093*1420Smarks 		return (1);
1094*1420Smarks 
1095*1420Smarks 	if (positional) {
1096*1420Smarks 		for (i = 0, pstr = permstr; i != count && pstr &&
1097*1420Smarks 		    *pstr; i++, pstr++) {
1098*1420Smarks 			if (*pstr == permtab[i].p_letter) {
1099*1420Smarks 				perm_val |= permtab[i].p_value;
1100*1420Smarks 			} else if (*pstr != '-') {
1101*1420Smarks 				return (1);
1102*1420Smarks 			}
1103789Sahrens 		}
1104*1420Smarks 	} else {  /* random order single letters with no '-' */
1105*1420Smarks 		for (pstr = permstr; pstr && *pstr; pstr++) {
1106*1420Smarks 			for (found = 0, i = 0; i != count; i++) {
1107*1420Smarks 				if (*pstr == permtab[i].p_letter) {
1108*1420Smarks 					perm_val |= permtab[i].p_value;
1109*1420Smarks 					found = 1;
1110*1420Smarks 					break;
1111*1420Smarks 				}
1112*1420Smarks 			}
1113*1420Smarks 			if (found == 0)
1114*1420Smarks 				return (1);
1115*1420Smarks 		}
1116789Sahrens 	}
1117789Sahrens 
1118*1420Smarks 	*mask = perm_val;
1119*1420Smarks 	return (0);
1120*1420Smarks }
1121789Sahrens 
1122*1420Smarks /*
1123*1420Smarks  * compute value for inheritance flags.
1124*1420Smarks  */
1125*1420Smarks int
1126*1420Smarks compute_ace_inherit(char *str, uint32_t *imask)
1127*1420Smarks {
1128*1420Smarks 	int error;
1129*1420Smarks 	int positional = 0;
1130789Sahrens 
1131*1420Smarks 	if (strlen(str) == IFLAG_COUNT)
1132*1420Smarks 		positional = 1;
1133*1420Smarks 
1134*1420Smarks 	error = compute_values(inherit_table, IFLAG_COUNT,
1135*1420Smarks 	    str, positional, imask);
1136*1420Smarks 
1137*1420Smarks 	if (error)
1138*1420Smarks 		return (EACL_INHERIT_ERROR);
1139*1420Smarks 
1140789Sahrens 	return (error);
1141789Sahrens }
1142*1420Smarks 
1143*1420Smarks 
1144*1420Smarks /*
1145*1420Smarks  * compute value for ACE permissions.
1146*1420Smarks  */
1147*1420Smarks int
1148*1420Smarks compute_ace_perms(char *str, uint32_t *mask)
1149*1420Smarks {
1150*1420Smarks 	int positional = 0;
1151*1420Smarks 	int error;
1152*1420Smarks 
1153*1420Smarks 	if (strlen(str) == ACE_PERM_COUNT)
1154*1420Smarks 		positional = 1;
1155*1420Smarks 
1156*1420Smarks 	error = compute_values(ace_perm_table, ACE_PERM_COUNT,
1157*1420Smarks 	    str, positional, mask);
1158*1420Smarks 
1159*1420Smarks 	if (error && positional) {
1160*1420Smarks 		/*
1161*1420Smarks 		 * If positional was set, then make sure permissions
1162*1420Smarks 		 * aren't actually valid in non positional case where
1163*1420Smarks 		 * all permissions are specified, just in random order.
1164*1420Smarks 		 */
1165*1420Smarks 		error = compute_values(ace_perm_table,
1166*1420Smarks 		    ACE_PERM_COUNT, str, 0, mask);
1167*1420Smarks 	}
1168*1420Smarks 	if (error)
1169*1420Smarks 		error = EACL_PERM_MASK_ERROR;
1170*1420Smarks 
1171*1420Smarks 	return (error);
1172*1420Smarks }
1173*1420Smarks 
1174*1420Smarks 
1175*1420Smarks 
1176*1420Smarks /*
1177*1420Smarks  * compute values for aclent permissions.
1178*1420Smarks  */
1179*1420Smarks int
1180*1420Smarks compute_aclent_perms(char *str, o_mode_t *mask)
1181*1420Smarks {
1182*1420Smarks 	int error;
1183*1420Smarks 	uint32_t pmask;
1184*1420Smarks 
1185*1420Smarks 	if (strlen(str) != ACLENT_PERM_COUNT)
1186*1420Smarks 		return (EACL_PERM_MASK_ERROR);
1187*1420Smarks 
1188*1420Smarks 	*mask = 0;
1189*1420Smarks 	error = compute_values(aclent_perm_table, ACLENT_PERM_COUNT,
1190*1420Smarks 	    str, 1, &pmask);
1191*1420Smarks 	if (error == 0) {
1192*1420Smarks 		*mask = (o_mode_t)pmask;
1193*1420Smarks 	} else
1194*1420Smarks 		error = EACL_PERM_MASK_ERROR;
1195*1420Smarks 	return (error);
1196*1420Smarks }
1197*1420Smarks 
1198*1420Smarks /*
1199*1420Smarks  * determine ACE permissions.
1200*1420Smarks  */
1201*1420Smarks int
1202*1420Smarks ace_perm_mask(struct acl_perm_type *aclperm, uint32_t *mask)
1203*1420Smarks {
1204*1420Smarks 	int error;
1205*1420Smarks 
1206*1420Smarks 	if (aclperm->perm_style == PERM_TYPE_EMPTY) {
1207*1420Smarks 		*mask = 0;
1208*1420Smarks 		return (0);
1209*1420Smarks 	}
1210*1420Smarks 
1211*1420Smarks 	if (aclperm->perm_style == PERM_TYPE_ACE) {
1212*1420Smarks 		*mask = aclperm->perm_val;
1213*1420Smarks 		return (0);
1214*1420Smarks 	}
1215*1420Smarks 
1216*1420Smarks 	error = compute_ace_perms(aclperm->perm_str, mask);
1217*1420Smarks 	if (error) {
1218*1420Smarks 		acl_error(gettext("Invalid permission(s) '%s' specified\n"),
1219*1420Smarks 		    aclperm->perm_str);
1220*1420Smarks 		return (EACL_PERM_MASK_ERROR);
1221*1420Smarks 	}
1222*1420Smarks 
1223*1420Smarks 	return (0);
1224*1420Smarks }
1225