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
51507Sgjelinek  * Common Development and Distribution License (the "License").
61507Sgjelinek  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
226269Smarks  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate /*LINTLIBRARY*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <grp.h>
300Sstevel@tonic-gate #include <pwd.h>
310Sstevel@tonic-gate #include <string.h>
320Sstevel@tonic-gate #include <limits.h>
330Sstevel@tonic-gate #include <stdlib.h>
34789Sahrens #include <errno.h>
350Sstevel@tonic-gate #include <sys/param.h>
360Sstevel@tonic-gate #include <sys/types.h>
371420Smarks #include <sys/stat.h>
380Sstevel@tonic-gate #include <sys/acl.h>
39789Sahrens #include <aclutils.h>
40*7057Smarks #include <idmap.h>
411420Smarks 
421420Smarks #define	ID_STR_MAX	20	/* digits in LONG_MAX */
43789Sahrens 
441420Smarks #define	APPENDED_ID_MAX	ID_STR_MAX + 1		/* id + colon */
451420Smarks /*
461420Smarks  * yyinteractive controls whether yyparse should print out
471420Smarks  * error messages to stderr, and whether or not id's should be
481420Smarks  * allowed from acl_fromtext().
491420Smarks  */
501420Smarks int	yyinteractive;
511420Smarks acl_t	*yyacl;
521420Smarks char	*yybuf;
53789Sahrens 
54789Sahrens extern acl_t *acl_alloc(enum acl_type);
550Sstevel@tonic-gate 
56*7057Smarks /*
57*7057Smarks  * dynamic string that will increase in size on an
58*7057Smarks  * as needed basis.
59*7057Smarks  */
60*7057Smarks typedef struct dynaclstr {
61*7057Smarks 	size_t d_bufsize;		/* current size of aclexport */
62*7057Smarks 	char *d_aclexport;
63*7057Smarks 	int d_pos;
64*7057Smarks } dynaclstr_t;
65922Shm123892 
66*7057Smarks static int str_append(dynaclstr_t *, char *);
67*7057Smarks static int aclent_perm_txt(dynaclstr_t *, o_mode_t);
680Sstevel@tonic-gate 
691420Smarks static void
701420Smarks aclent_perms(int perm, char *txt_perms)
711420Smarks {
721420Smarks 	if (perm & S_IROTH)
731420Smarks 		txt_perms[0] = 'r';
741420Smarks 	else
751420Smarks 		txt_perms[0] = '-';
761420Smarks 	if (perm & S_IWOTH)
771420Smarks 		txt_perms[1] = 'w';
781420Smarks 	else
791420Smarks 		txt_perms[1] = '-';
801420Smarks 	if (perm & S_IXOTH)
811420Smarks 		txt_perms[2] = 'x';
821420Smarks 	else
831420Smarks 		txt_perms[2] = '-';
841420Smarks 	txt_perms[3] = '\0';
851420Smarks }
861420Smarks 
871420Smarks static char *
881535Smarks pruname(uid_t uid, char *uidp, size_t buflen, int noresolve)
891420Smarks {
901515Sgjelinek 	struct passwd	*passwdp = NULL;
911420Smarks 
921515Sgjelinek 	if (noresolve == 0)
931515Sgjelinek 		passwdp = getpwuid(uid);
941420Smarks 	if (passwdp == (struct passwd *)NULL) {
951420Smarks 		/* could not get passwd information: display uid instead */
964321Scasper 		(void) snprintf(uidp, buflen, "%u", uid);
971535Smarks 	} else {
981535Smarks 		(void) strlcpy(uidp, passwdp->pw_name, buflen);
991535Smarks 	}
1001535Smarks 	return (uidp);
1011420Smarks }
1021420Smarks 
1031420Smarks static char *
1041535Smarks prgname(gid_t gid, char *gidp, size_t buflen, int noresolve)
1051420Smarks {
1061515Sgjelinek 	struct group	*groupp = NULL;
1071420Smarks 
1081515Sgjelinek 	if (noresolve == 0)
1091515Sgjelinek 		groupp = getgrgid(gid);
1101420Smarks 	if (groupp == (struct group *)NULL) {
1111420Smarks 		/* could not get group information: display gid instead */
1124321Scasper 		(void) snprintf(gidp, buflen, "%u", gid);
1131535Smarks 	} else {
1141535Smarks 		(void) strlcpy(gidp, groupp->gr_name, buflen);
1151535Smarks 	}
1161535Smarks 	return (gidp);
1171420Smarks }
118*7057Smarks 
119*7057Smarks static char *
120*7057Smarks prsidname(uid_t who, boolean_t user, char **sidp, int noresolve)
121*7057Smarks {
122*7057Smarks 	idmap_handle_t *idmap_hdl = NULL;
123*7057Smarks 	idmap_get_handle_t *get_hdl = NULL;
124*7057Smarks 	idmap_stat status;
125*7057Smarks 	idmap_rid_t rid;
126*7057Smarks 	int error = 1;
127*7057Smarks 	int len;
128*7057Smarks 	char *domain;
129*7057Smarks 	char *name;
130*7057Smarks 
131*7057Smarks 	if (noresolve) {
132*7057Smarks 		len = snprintf(NULL, 0, "%u", who);
133*7057Smarks 		*sidp = malloc(len + 1);
134*7057Smarks 		(void) snprintf(*sidp, len + 1, "%u", who);
135*7057Smarks 		return (*sidp);
136*7057Smarks 	}
137*7057Smarks 
138*7057Smarks 	/*
139*7057Smarks 	 * First try and get windows name
140*7057Smarks 	 */
141*7057Smarks 
142*7057Smarks 	if (user)
143*7057Smarks 		error = idmap_getwinnamebyuid(who, &name, &domain);
144*7057Smarks 	else
145*7057Smarks 		error = idmap_getwinnamebygid(who, &name, &domain);
146*7057Smarks 
147*7057Smarks 	if (error) {
148*7057Smarks 		if (idmap_init(&idmap_hdl) == 0 &&
149*7057Smarks 		    idmap_get_create(idmap_hdl, &get_hdl) == 0) {
150*7057Smarks 			if (user)
151*7057Smarks 				error = idmap_get_sidbyuid(get_hdl, who,
152*7057Smarks 				    0, &domain, &rid, &status);
153*7057Smarks 			else
154*7057Smarks 				error = idmap_get_sidbygid(get_hdl, who,
155*7057Smarks 				    0, &domain, &rid, &status);
156*7057Smarks 			if (error == 0)
157*7057Smarks 				error = idmap_get_mappings(get_hdl);
158*7057Smarks 		}
159*7057Smarks 		if (error == 0) {
160*7057Smarks 			len = snprintf(NULL, 0, "%s-%d", domain, rid);
161*7057Smarks 			*sidp = malloc(len + 1);
162*7057Smarks 			(void) snprintf(*sidp, len + 1, "%s-%d", domain, rid);
163*7057Smarks 		} else {
164*7057Smarks 			*sidp = NULL;
165*7057Smarks 		}
166*7057Smarks 		if (get_hdl)
167*7057Smarks 			idmap_get_destroy(get_hdl);
168*7057Smarks 		if (idmap_hdl)
169*7057Smarks 			(void) idmap_fini(idmap_hdl);
170*7057Smarks 	} else {
171*7057Smarks 		int len;
172*7057Smarks 		len = snprintf(NULL, 0, "%s@%d", name, domain);
173*7057Smarks 		*sidp = malloc(len + 1);
174*7057Smarks 		(void) snprintf(*sidp, len + 1, "%s@%s", name, domain);
175*7057Smarks 	}
176*7057Smarks 	return (*sidp);
177*7057Smarks }
178*7057Smarks 
1791420Smarks static void
1801420Smarks aclent_printacl(acl_t *aclp)
181789Sahrens {
1821420Smarks 	aclent_t *tp;
1831420Smarks 	int aclcnt;
1841420Smarks 	int mask;
1851420Smarks 	int slot = 0;
1861420Smarks 	char perm[4];
1871535Smarks 	char uidp[ID_STR_MAX];
1881535Smarks 	char gidp[ID_STR_MAX];
1891420Smarks 
1901420Smarks 	/* display ACL: assume it is sorted. */
1911420Smarks 	aclcnt = aclp->acl_cnt;
1921420Smarks 	for (tp = aclp->acl_aclp; tp && aclcnt--; tp++) {
1931420Smarks 		if (tp->a_type == CLASS_OBJ)
1941420Smarks 			mask = tp->a_perm;
1951420Smarks 	}
1961420Smarks 	aclcnt = aclp->acl_cnt;
1971420Smarks 	for (tp = aclp->acl_aclp; aclcnt--; tp++) {
1981420Smarks 		(void) printf("     %d:", slot++);
1991420Smarks 		switch (tp->a_type) {
2001420Smarks 		case USER:
2011420Smarks 			aclent_perms(tp->a_perm, perm);
2021420Smarks 			(void) printf("user:%s:%s\t\t",
2031535Smarks 			    pruname(tp->a_id, uidp, sizeof (uidp), 0), perm);
2041420Smarks 			aclent_perms((tp->a_perm & mask), perm);
2051420Smarks 			(void) printf("#effective:%s\n", perm);
2061420Smarks 			break;
2071420Smarks 		case USER_OBJ:
2081420Smarks 			/* no need to display uid */
2091420Smarks 			aclent_perms(tp->a_perm, perm);
2101420Smarks 			(void) printf("user::%s\n", perm);
2111420Smarks 			break;
2121420Smarks 		case GROUP:
2131420Smarks 			aclent_perms(tp->a_perm, perm);
2141420Smarks 			(void) printf("group:%s:%s\t\t",
2151535Smarks 			    prgname(tp->a_id, gidp, sizeof (gidp), 0), perm);
2161420Smarks 			aclent_perms(tp->a_perm & mask, perm);
2171420Smarks 			(void) printf("#effective:%s\n", perm);
2181420Smarks 			break;
2191420Smarks 		case GROUP_OBJ:
2201420Smarks 			aclent_perms(tp->a_perm, perm);
2211420Smarks 			(void) printf("group::%s\t\t", perm);
2221420Smarks 			aclent_perms(tp->a_perm & mask, perm);
2231420Smarks 			(void) printf("#effective:%s\n", perm);
2241420Smarks 			break;
2251420Smarks 		case CLASS_OBJ:
2261420Smarks 			aclent_perms(tp->a_perm, perm);
2271420Smarks 			(void) printf("mask:%s\n", perm);
2281420Smarks 			break;
2291420Smarks 		case OTHER_OBJ:
2301420Smarks 			aclent_perms(tp->a_perm, perm);
2311420Smarks 			(void) printf("other:%s\n", perm);
2321420Smarks 			break;
2331420Smarks 		case DEF_USER:
2341420Smarks 			aclent_perms(tp->a_perm, perm);
2351420Smarks 			(void) printf("default:user:%s:%s\n",
2361535Smarks 			    pruname(tp->a_id, uidp, sizeof (uidp), 0), perm);
2371420Smarks 			break;
2381420Smarks 		case DEF_USER_OBJ:
2391420Smarks 			aclent_perms(tp->a_perm, perm);
2401420Smarks 			(void) printf("default:user::%s\n", perm);
2411420Smarks 			break;
2421420Smarks 		case DEF_GROUP:
2431420Smarks 			aclent_perms(tp->a_perm, perm);
2441420Smarks 			(void) printf("default:group:%s:%s\n",
2451535Smarks 			    prgname(tp->a_id, gidp, sizeof (gidp), 0), perm);
2461420Smarks 			break;
2471420Smarks 		case DEF_GROUP_OBJ:
2481420Smarks 			aclent_perms(tp->a_perm, perm);
2491420Smarks 			(void) printf("default:group::%s\n", perm);
2501420Smarks 			break;
2511420Smarks 		case DEF_CLASS_OBJ:
2521420Smarks 			aclent_perms(tp->a_perm, perm);
2531420Smarks 			(void) printf("default:mask:%s\n", perm);
2541420Smarks 			break;
2551420Smarks 		case DEF_OTHER_OBJ:
2561420Smarks 			aclent_perms(tp->a_perm, perm);
2571420Smarks 			(void) printf("default:other:%s\n", perm);
2581420Smarks 			break;
2591420Smarks 		default:
2601420Smarks 			(void) fprintf(stderr,
2611567Smarks 			    dgettext(TEXT_DOMAIN, "unrecognized entry\n"));
2621420Smarks 			break;
2631420Smarks 		}
2641420Smarks 	}
2651420Smarks }
2661420Smarks 
2671420Smarks static void
2681420Smarks split_line(char *str, int cols)
2691420Smarks {
2701420Smarks 	char *ptr;
2711420Smarks 	int len;
2721420Smarks 	int i;
2731420Smarks 	int last_split;
2741420Smarks 	char *pad = "";
2751420Smarks 	int pad_len;
2761420Smarks 
2771420Smarks 	len = strlen(str);
2781420Smarks 	ptr = str;
2791420Smarks 	pad_len = 0;
2801420Smarks 
2811420Smarks 	ptr = str;
2821420Smarks 	last_split = 0;
2831420Smarks 	for (i = 0; i != len; i++) {
2841420Smarks 		if ((i + pad_len + 4) >= cols) {
2851420Smarks 			(void) printf("%s%.*s\n", pad, last_split, ptr);
2861420Smarks 			ptr = &ptr[last_split];
2871420Smarks 			len = strlen(ptr);
2881420Smarks 			i = 0;
2891420Smarks 			pad_len = 4;
2901420Smarks 			pad = "         ";
2911420Smarks 		} else {
2921420Smarks 			if (ptr[i] == '/' || ptr[i] == ':') {
2931420Smarks 				last_split = i;
2941420Smarks 			}
2951420Smarks 		}
2961420Smarks 	}
2971420Smarks 	if (i == len) {
2981420Smarks 		(void) printf("%s%s\n", pad, ptr);
2991420Smarks 	}
3001420Smarks }
3011420Smarks 
302*7057Smarks /*
303*7057Smarks  * compute entry type string, such as user:joe, group:staff,...
304*7057Smarks  */
305*7057Smarks static int
306*7057Smarks aclent_type_txt(dynaclstr_t *dstr, aclent_t *aclp, int flags)
3071420Smarks {
308*7057Smarks 	char idp[ID_STR_MAX];
309*7057Smarks 	int error;
310*7057Smarks 
311*7057Smarks 	switch (aclp->a_type) {
312*7057Smarks 	case DEF_USER_OBJ:
313*7057Smarks 	case USER_OBJ:
314*7057Smarks 		if (aclp->a_type == USER_OBJ)
315*7057Smarks 			error = str_append(dstr, "user::");
316*7057Smarks 		else
317*7057Smarks 			error = str_append(dstr, "defaultuser::");
318*7057Smarks 		break;
319*7057Smarks 
320*7057Smarks 	case DEF_USER:
321*7057Smarks 	case USER:
322*7057Smarks 		if (aclp->a_type == USER)
323*7057Smarks 			error = str_append(dstr, "user:");
324*7057Smarks 		else
325*7057Smarks 			error = str_append(dstr, "defaultuser:");
326*7057Smarks 		if (error)
327*7057Smarks 			break;
328*7057Smarks 		error = str_append(dstr, pruname(aclp->a_id, idp,
329*7057Smarks 		    sizeof (idp), flags & ACL_NORESOLVE));
330*7057Smarks 		if (error == 0)
331*7057Smarks 			error = str_append(dstr, ":");
332*7057Smarks 		break;
333*7057Smarks 
334*7057Smarks 	case DEF_GROUP_OBJ:
335*7057Smarks 	case GROUP_OBJ:
336*7057Smarks 		if (aclp->a_type == GROUP_OBJ)
337*7057Smarks 			error = str_append(dstr, "group::");
338*7057Smarks 		else
339*7057Smarks 			error = str_append(dstr, "defaultgroup::");
340*7057Smarks 		break;
3411420Smarks 
342*7057Smarks 	case DEF_GROUP:
343*7057Smarks 	case GROUP:
344*7057Smarks 		if (aclp->a_type == GROUP)
345*7057Smarks 			error = str_append(dstr, "group:");
346*7057Smarks 		else
347*7057Smarks 			error = str_append(dstr, "defaultgroup:");
348*7057Smarks 		if (error)
349*7057Smarks 			break;
350*7057Smarks 		error = str_append(dstr, prgname(aclp->a_id, idp,
351*7057Smarks 		    sizeof (idp), flags & ACL_NORESOLVE));
352*7057Smarks 		if (error == 0)
353*7057Smarks 			error = str_append(dstr, ":");
354*7057Smarks 		break;
355*7057Smarks 
356*7057Smarks 	case DEF_CLASS_OBJ:
357*7057Smarks 	case CLASS_OBJ:
358*7057Smarks 		if (aclp->a_type == CLASS_OBJ)
359*7057Smarks 			error = str_append(dstr, "mask:");
360*7057Smarks 		else
361*7057Smarks 			error = str_append(dstr, "defaultmask:");
362*7057Smarks 		break;
3631420Smarks 
364*7057Smarks 	case DEF_OTHER_OBJ:
365*7057Smarks 	case OTHER_OBJ:
366*7057Smarks 		if (aclp->a_type == OTHER_OBJ)
367*7057Smarks 			error = str_append(dstr, "other:");
368*7057Smarks 		else
369*7057Smarks 			error = str_append(dstr, "defaultother:");
370*7057Smarks 		break;
371*7057Smarks 
372*7057Smarks 	default:
373*7057Smarks 		error = 1;
374*7057Smarks 		break;
375*7057Smarks 	}
376*7057Smarks 
377*7057Smarks 	return (error);
378*7057Smarks }
379*7057Smarks 
380*7057Smarks /*
381*7057Smarks  * compute entry type string such as, owner@:, user:joe, group:staff,...
382*7057Smarks  */
383*7057Smarks static int
384*7057Smarks ace_type_txt(dynaclstr_t *dynstr, ace_t *acep, int flags)
385*7057Smarks {
386*7057Smarks 	char idp[ID_STR_MAX];
387*7057Smarks 	int error;
388*7057Smarks 	char *sidp = NULL;
3891420Smarks 
3901420Smarks 	switch (acep->a_flags & ACE_TYPE_FLAGS) {
3911420Smarks 	case ACE_OWNER:
392*7057Smarks 		error = str_append(dynstr, OWNERAT_TXT);
3931420Smarks 		break;
3941420Smarks 
3951420Smarks 	case ACE_GROUP|ACE_IDENTIFIER_GROUP:
396*7057Smarks 		error = str_append(dynstr, GROUPAT_TXT);
3971420Smarks 		break;
3981420Smarks 
3991420Smarks 	case ACE_IDENTIFIER_GROUP:
400*7057Smarks 		if ((flags & ACL_SID_FMT) && acep->a_who > MAXUID) {
401*7057Smarks 			if (error = str_append(dynstr,
402*7057Smarks 			    GROUPSID_TXT))
403*7057Smarks 				break;
404*7057Smarks 			error = str_append(dynstr, prsidname(acep->a_who,
405*7057Smarks 			    B_FALSE, &sidp, flags & ACL_NORESOLVE));
406*7057Smarks 		} else {
407*7057Smarks 			if (error = str_append(dynstr, GROUP_TXT))
408*7057Smarks 				break;
409*7057Smarks 			error = str_append(dynstr, prgname(acep->a_who, idp,
410*7057Smarks 			    sizeof (idp), flags & ACL_NORESOLVE));
411*7057Smarks 		}
412*7057Smarks 		if (error == 0)
413*7057Smarks 			error = str_append(dynstr, ":");
4141420Smarks 		break;
4151420Smarks 
4161420Smarks 	case ACE_EVERYONE:
417*7057Smarks 		error = str_append(dynstr, EVERYONEAT_TXT);
4181420Smarks 		break;
4191420Smarks 
4201420Smarks 	case 0:
421*7057Smarks 		if ((flags & ACL_SID_FMT) && acep->a_who > MAXUID) {
422*7057Smarks 			if (error = str_append(dynstr, USERSID_TXT))
423*7057Smarks 				break;
424*7057Smarks 			error = str_append(dynstr, prsidname(acep->a_who,
425*7057Smarks 			    B_TRUE, &sidp, flags & ACL_NORESOLVE));
426*7057Smarks 		} else {
427*7057Smarks 			if (error = str_append(dynstr, USER_TXT))
428*7057Smarks 				break;
429*7057Smarks 			error = str_append(dynstr, pruname(acep->a_who, idp,
430*7057Smarks 			    sizeof (idp), flags & ACL_NORESOLVE));
431*7057Smarks 		}
432*7057Smarks 		if (error == 0)
433*7057Smarks 			error = str_append(dynstr, ":");
434*7057Smarks 		break;
435*7057Smarks 	default:
436*7057Smarks 		error = 0;
4371420Smarks 		break;
4381420Smarks 	}
4391420Smarks 
440*7057Smarks 	if (sidp)
441*7057Smarks 		free(sidp);
442*7057Smarks 	return (error);
4431420Smarks }
4441420Smarks 
445*7057Smarks /*
446*7057Smarks  * compute string of permissions, such as read_data/write_data or
447*7057Smarks  * rwxp,...
448*7057Smarks  * The format depends on the flags field which indicates whether the compact
449*7057Smarks  * or verbose format should be used.
450*7057Smarks  */
451*7057Smarks static int
452*7057Smarks ace_perm_txt(dynaclstr_t *dstr, uint32_t mask,
4531420Smarks     uint32_t iflags, int isdir, int flags)
4541420Smarks {
455*7057Smarks 	int error = 0;
4561420Smarks 
4571420Smarks 	if (flags & ACL_COMPACT_FMT) {
458*7057Smarks 		char buf[16];
459789Sahrens 
4601420Smarks 		if (mask & ACE_READ_DATA)
4611420Smarks 			buf[0] = 'r';
4621420Smarks 		else
4631420Smarks 			buf[0] = '-';
4641420Smarks 		if (mask & ACE_WRITE_DATA)
4651420Smarks 			buf[1] = 'w';
4661420Smarks 		else
4671420Smarks 			buf[1] = '-';
4681420Smarks 		if (mask & ACE_EXECUTE)
4691420Smarks 			buf[2] = 'x';
4701420Smarks 		else
4711420Smarks 			buf[2] = '-';
4721420Smarks 		if (mask & ACE_APPEND_DATA)
4731420Smarks 			buf[3] = 'p';
4741420Smarks 		else
4751420Smarks 			buf[3] = '-';
4761420Smarks 		if (mask & ACE_DELETE)
4771420Smarks 			buf[4] = 'd';
4781420Smarks 		else
4791420Smarks 			buf[4] = '-';
4801420Smarks 		if (mask & ACE_DELETE_CHILD)
4811420Smarks 			buf[5] = 'D';
4821420Smarks 		else
4831420Smarks 			buf[5] = '-';
4841420Smarks 		if (mask & ACE_READ_ATTRIBUTES)
4851420Smarks 			buf[6] = 'a';
4861420Smarks 		else
4871420Smarks 			buf[6] = '-';
4881420Smarks 		if (mask & ACE_WRITE_ATTRIBUTES)
4891420Smarks 			buf[7] = 'A';
4901420Smarks 		else
4911420Smarks 			buf[7] = '-';
4921420Smarks 		if (mask & ACE_READ_NAMED_ATTRS)
4931420Smarks 			buf[8] = 'R';
4941420Smarks 		else
4951420Smarks 			buf[8] = '-';
4961420Smarks 		if (mask & ACE_WRITE_NAMED_ATTRS)
4971420Smarks 			buf[9] = 'W';
4981420Smarks 		else
4991420Smarks 			buf[9] = '-';
5001420Smarks 		if (mask & ACE_READ_ACL)
5011420Smarks 			buf[10] = 'c';
5021420Smarks 		else
5031420Smarks 			buf[10] = '-';
5041420Smarks 		if (mask & ACE_WRITE_ACL)
5051420Smarks 			buf[11] = 'C';
5061420Smarks 		else
5071420Smarks 			buf[11] = '-';
5081420Smarks 		if (mask & ACE_WRITE_OWNER)
5091420Smarks 			buf[12] = 'o';
5101420Smarks 		else
5111420Smarks 			buf[12] = '-';
5121420Smarks 		if (mask & ACE_SYNCHRONIZE)
5131420Smarks 			buf[13] = 's';
5141420Smarks 		else
5151420Smarks 			buf[13] = '-';
516*7057Smarks 		buf[14] = ':';
517*7057Smarks 		buf[15] = '\0';
518*7057Smarks 		error = str_append(dstr, buf);
5191420Smarks 	} else {
5201420Smarks 		/*
5211420Smarks 		 * If ACE is a directory, but inheritance indicates its
5221420Smarks 		 * for a file then print permissions for file rather than
5231420Smarks 		 * dir.
5241420Smarks 		 */
5251420Smarks 		if (isdir) {
5261420Smarks 			if (mask & ACE_LIST_DIRECTORY) {
5271420Smarks 				if (iflags == ACE_FILE_INHERIT_ACE) {
528*7057Smarks 					error = str_append(dstr,
529*7057Smarks 					    READ_DATA_TXT);
5301420Smarks 				} else {
531*7057Smarks 					error =
532*7057Smarks 					    str_append(dstr, READ_DIR_TXT);
5331420Smarks 				}
5341420Smarks 			}
535*7057Smarks 			if (error == 0 && (mask & ACE_ADD_FILE)) {
5361420Smarks 				if (iflags == ACE_FILE_INHERIT_ACE) {
537*7057Smarks 					error =
538*7057Smarks 					    str_append(dstr, WRITE_DATA_TXT);
5391420Smarks 				} else {
540*7057Smarks 					error =
541*7057Smarks 					    str_append(dstr, ADD_FILE_TXT);
5421420Smarks 				}
5431420Smarks 			}
544*7057Smarks 			if (error == 0 && (mask & ACE_ADD_SUBDIRECTORY)) {
5451420Smarks 				if (iflags == ACE_FILE_INHERIT_ACE) {
546*7057Smarks 					error = str_append(dstr,
547*7057Smarks 					    APPEND_DATA_TXT);
5481420Smarks 				} else {
549*7057Smarks 					error = str_append(dstr,
550*7057Smarks 					    ADD_DIR_TXT);
5511420Smarks 				}
5521420Smarks 			}
5531420Smarks 		} else {
5541420Smarks 			if (mask & ACE_READ_DATA) {
555*7057Smarks 				error = str_append(dstr, READ_DATA_TXT);
5561420Smarks 			}
557*7057Smarks 			if (error == 0 && (mask & ACE_WRITE_DATA)) {
558*7057Smarks 				error = str_append(dstr, WRITE_DATA_TXT);
5591420Smarks 			}
560*7057Smarks 			if (error == 0 && (mask & ACE_APPEND_DATA)) {
561*7057Smarks 				error = str_append(dstr, APPEND_DATA_TXT);
5621420Smarks 			}
5631420Smarks 		}
564*7057Smarks 		if (error == 0 && (mask & ACE_READ_NAMED_ATTRS)) {
565*7057Smarks 			error = str_append(dstr, READ_XATTR_TXT);
5661420Smarks 		}
567*7057Smarks 		if (error == 0 && (mask & ACE_WRITE_NAMED_ATTRS)) {
568*7057Smarks 			error = str_append(dstr, WRITE_XATTR_TXT);
5691420Smarks 		}
570*7057Smarks 		if (error == 0 && (mask & ACE_EXECUTE)) {
571*7057Smarks 			error = str_append(dstr, EXECUTE_TXT);
5721420Smarks 		}
573*7057Smarks 		if (error == 0 && (mask & ACE_DELETE_CHILD)) {
574*7057Smarks 			error = str_append(dstr, DELETE_CHILD_TXT);
5751420Smarks 		}
576*7057Smarks 		if (error == 0 && (mask & ACE_READ_ATTRIBUTES)) {
577*7057Smarks 			error = str_append(dstr, READ_ATTRIBUTES_TXT);
5781420Smarks 		}
579*7057Smarks 		if (error == 0 && (mask & ACE_WRITE_ATTRIBUTES)) {
580*7057Smarks 			error = str_append(dstr, WRITE_ATTRIBUTES_TXT);
5811420Smarks 		}
582*7057Smarks 		if (error == 0 && (mask & ACE_DELETE)) {
583*7057Smarks 			error = str_append(dstr, DELETE_TXT);
5841420Smarks 		}
585*7057Smarks 		if (error == 0 && (mask & ACE_READ_ACL)) {
586*7057Smarks 			error = str_append(dstr, READ_ACL_TXT);
5871420Smarks 		}
588*7057Smarks 		if (error == 0 && (mask & ACE_WRITE_ACL)) {
589*7057Smarks 			error = str_append(dstr, WRITE_ACL_TXT);
5901420Smarks 		}
591*7057Smarks 		if (error == 0 && (mask & ACE_WRITE_OWNER)) {
592*7057Smarks 			error = str_append(dstr, WRITE_OWNER_TXT);
5931420Smarks 		}
594*7057Smarks 		if (error == 0 && (mask & ACE_SYNCHRONIZE)) {
595*7057Smarks 			error = str_append(dstr, SYNCHRONIZE_TXT);
5961420Smarks 		}
597*7057Smarks 		if (error == 0 && dstr->d_aclexport[dstr->d_pos-1] == '/') {
598*7057Smarks 			dstr->d_aclexport[--dstr->d_pos] = '\0';
599*7057Smarks 		}
600*7057Smarks 		if (error == 0)
601*7057Smarks 			error = str_append(dstr, ":");
6021420Smarks 	}
603*7057Smarks 	return (error);
6041420Smarks }
6051420Smarks 
606*7057Smarks /*
607*7057Smarks  * compute string of access type, such as allow, deny, ...
608*7057Smarks  */
609*7057Smarks static int
610*7057Smarks ace_access_txt(dynaclstr_t *dstr, int type)
6111420Smarks {
612*7057Smarks 	int error;
6131420Smarks 
614*7057Smarks 	if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
615*7057Smarks 		error = str_append(dstr, ALLOW_TXT);
616*7057Smarks 	else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
617*7057Smarks 		error = str_append(dstr, DENY_TXT);
618*7057Smarks 	else if (type == ACE_SYSTEM_AUDIT_ACE_TYPE)
619*7057Smarks 		error = str_append(dstr, AUDIT_TXT);
620*7057Smarks 	else if (type == ACE_SYSTEM_ALARM_ACE_TYPE)
621*7057Smarks 		error = str_append(dstr, ALARM_TXT);
622*7057Smarks 	else
623*7057Smarks 		error = str_append(dstr, UNKNOWN_TXT);
6241420Smarks 
625*7057Smarks 	return (error);
6261420Smarks }
6271420Smarks 
628*7057Smarks static int
629*7057Smarks ace_inherit_txt(dynaclstr_t *dstr, uint32_t iflags, int flags)
6301420Smarks {
631*7057Smarks 	int error = 0;
632789Sahrens 
6331420Smarks 	if (flags & ACL_COMPACT_FMT) {
634*7057Smarks 		char buf[9];
635*7057Smarks 
6361420Smarks 		if (iflags & ACE_FILE_INHERIT_ACE)
6371420Smarks 			buf[0] = 'f';
6381420Smarks 		else
6391420Smarks 			buf[0] = '-';
6401420Smarks 		if (iflags & ACE_DIRECTORY_INHERIT_ACE)
6411420Smarks 			buf[1] = 'd';
6421420Smarks 		else
6431420Smarks 			buf[1] = '-';
6441420Smarks 		if (iflags & ACE_INHERIT_ONLY_ACE)
6451420Smarks 			buf[2] = 'i';
6461420Smarks 		else
6471420Smarks 			buf[2] = '-';
6481420Smarks 		if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)
6491420Smarks 			buf[3] = 'n';
6501420Smarks 		else
6511420Smarks 			buf[3] = '-';
6521420Smarks 		if (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
6531420Smarks 			buf[4] = 'S';
6541420Smarks 		else
6551420Smarks 			buf[4] = '-';
6561420Smarks 		if (iflags & ACE_FAILED_ACCESS_ACE_FLAG)
6571420Smarks 			buf[5] = 'F';
6581420Smarks 		else
6591420Smarks 			buf[5] = '-';
6605331Samw 		if (iflags & ACE_INHERITED_ACE)
6615331Samw 			buf[6] = 'I';
6625331Samw 		else
6635331Samw 			buf[6] = '-';
664*7057Smarks 		buf[7] = ':';
665*7057Smarks 		buf[8] = '\0';
666*7057Smarks 		error = str_append(dstr, buf);
6671420Smarks 	} else {
6681420Smarks 		if (iflags & ACE_FILE_INHERIT_ACE) {
669*7057Smarks 			error = str_append(dstr, FILE_INHERIT_TXT);
6701420Smarks 		}
671*7057Smarks 		if (error == 0 && (iflags & ACE_DIRECTORY_INHERIT_ACE)) {
672*7057Smarks 			error = str_append(dstr, DIR_INHERIT_TXT);
6731420Smarks 		}
674*7057Smarks 		if (error == 0 && (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)) {
675*7057Smarks 			error = str_append(dstr, NO_PROPAGATE_TXT);
6761420Smarks 		}
677*7057Smarks 		if (error == 0 && (iflags & ACE_INHERIT_ONLY_ACE)) {
678*7057Smarks 			error = str_append(dstr, INHERIT_ONLY_TXT);
6791420Smarks 		}
680*7057Smarks 		if (error == 0 && (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)) {
681*7057Smarks 			error = str_append(dstr, SUCCESSFUL_ACCESS_TXT);
6825331Samw 		}
683*7057Smarks 		if (error == 0 && (iflags & ACE_FAILED_ACCESS_ACE_FLAG)) {
684*7057Smarks 			error = str_append(dstr, FAILED_ACCESS_TXT);
6855331Samw 		}
686*7057Smarks 		if (error == 0 && (iflags & ACE_INHERITED_ACE)) {
687*7057Smarks 			error = str_append(dstr, INHERITED_ACE_TXT);
6885331Samw 		}
689*7057Smarks 		if (error == 0 && dstr->d_aclexport[dstr->d_pos-1] == '/') {
690*7057Smarks 			dstr->d_aclexport[--dstr->d_pos] = '\0';
691*7057Smarks 			error = str_append(dstr, ":");
692*7057Smarks 		}
6931420Smarks 	}
6941420Smarks 
695*7057Smarks 	return (error);
696789Sahrens }
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate /*
6990Sstevel@tonic-gate  * Convert internal acl representation to external representation.
7000Sstevel@tonic-gate  *
7010Sstevel@tonic-gate  * The length of a non-owning user name or non-owning group name ie entries
7020Sstevel@tonic-gate  * of type DEF_USER, USER, DEF_GROUP or GROUP, can exceed LOGNAME_MAX.  We
7030Sstevel@tonic-gate  * thus check the length of these entries, and if greater than LOGNAME_MAX,
7040Sstevel@tonic-gate  * we realloc() via increase_length().
7050Sstevel@tonic-gate  *
7060Sstevel@tonic-gate  * The LOGNAME_MAX, ENTRYTYPELEN and PERMS limits are otherwise always
7070Sstevel@tonic-gate  * adhered to.
7080Sstevel@tonic-gate  */
7091420Smarks 
7101420Smarks /*
7111420Smarks  * acltotext() converts each ACL entry to look like this:
7121420Smarks  *
7131420Smarks  *    entry_type:uid^gid^name:perms[:id]
7141420Smarks  *
7151420Smarks  * The maximum length of entry_type is 14 ("defaultgroup::" and
7161420Smarks  * "defaultother::") hence ENTRYTYPELEN is set to 14.
7171420Smarks  *
7181420Smarks  * The max length of a uid^gid^name entry (in theory) is 8, hence we use,
7191420Smarks  * however the ID could be a number so we therefore use ID_STR_MAX
7201420Smarks  *
7211420Smarks  * The length of a perms entry is 4 to allow for the comma appended to each
7221420Smarks  * to each acl entry.  Hence PERMS is set to 4.
7231420Smarks  */
7241420Smarks 
7251420Smarks #define	ENTRYTYPELEN	14
7261420Smarks #define	PERMS		4
7271420Smarks #define	ACL_ENTRY_SIZE	(ENTRYTYPELEN + ID_STR_MAX + PERMS + APPENDED_ID_MAX)
7281420Smarks 
7290Sstevel@tonic-gate char *
7301420Smarks aclent_acltotext(aclent_t  *aclp, int aclcnt, int flags)
7310Sstevel@tonic-gate {
732*7057Smarks 	dynaclstr_t 	*dstr;
7330Sstevel@tonic-gate 	char		*aclexport;
734*7057Smarks 	int		i;
735*7057Smarks 	int 		error = 0;
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	if (aclp == NULL)
7380Sstevel@tonic-gate 		return (NULL);
739*7057Smarks 	if ((dstr = malloc(sizeof (dynaclstr_t))) == NULL)
7400Sstevel@tonic-gate 		return (NULL);
741*7057Smarks 	dstr->d_bufsize = aclcnt * ACL_ENTRY_SIZE;
742*7057Smarks 	if ((dstr->d_aclexport = malloc(dstr->d_bufsize)) == NULL) {
7430Sstevel@tonic-gate 		free(dstr);
7440Sstevel@tonic-gate 		return (NULL);
7450Sstevel@tonic-gate 	}
746*7057Smarks 	*dstr->d_aclexport = '\0';
747*7057Smarks 	dstr->d_pos = 0;
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	for (i = 0; i < aclcnt; i++, aclp++) {
750*7057Smarks 		if (error = aclent_type_txt(dstr, aclp, flags))
7510Sstevel@tonic-gate 			break;
752*7057Smarks 		if (error = aclent_perm_txt(dstr, aclp->a_perm))
7530Sstevel@tonic-gate 			break;
7541420Smarks 
7551420Smarks 		if ((flags & ACL_APPEND_ID) && ((aclp->a_type == USER) ||
7561420Smarks 		    (aclp->a_type == DEF_USER) || (aclp->a_type == GROUP) ||
7571420Smarks 		    (aclp->a_type == DEF_GROUP))) {
758*7057Smarks 			char id[ID_STR_MAX], *idstr;
759*7057Smarks 
760*7057Smarks 			if (error = str_append(dstr, ":"))
761*7057Smarks 				break;
7621420Smarks 			id[ID_STR_MAX - 1] = '\0'; /* null terminate buffer */
7631420Smarks 			idstr = lltostr(aclp->a_id, &id[ID_STR_MAX - 1]);
764*7057Smarks 			if (error = str_append(dstr, idstr))
765*7057Smarks 				break;
7661420Smarks 		}
7670Sstevel@tonic-gate 		if (i < aclcnt - 1)
768*7057Smarks 			if (error = str_append(dstr, ","))
769*7057Smarks 				break;
7700Sstevel@tonic-gate 	}
771*7057Smarks 	if (error) {
772*7057Smarks 		if (dstr->d_aclexport)
773*7057Smarks 			free(dstr->d_aclexport);
774*7057Smarks 	} else {
775*7057Smarks 		aclexport = dstr->d_aclexport;
776*7057Smarks 	}
7770Sstevel@tonic-gate 	free(dstr);
7780Sstevel@tonic-gate 	return (aclexport);
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate 
7811420Smarks char *
7821420Smarks acltotext(aclent_t *aclp, int aclcnt)
7830Sstevel@tonic-gate {
7841420Smarks 	return (aclent_acltotext(aclp, aclcnt, 0));
7851420Smarks }
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 
788789Sahrens aclent_t *
789789Sahrens aclfromtext(char *aclstr, int *aclcnt)
790789Sahrens {
791789Sahrens 	acl_t *aclp;
792789Sahrens 	aclent_t *aclentp;
793789Sahrens 	int error;
794789Sahrens 
7951420Smarks 	error = acl_fromtext(aclstr, &aclp);
796789Sahrens 	if (error)
797789Sahrens 		return (NULL);
798789Sahrens 
799789Sahrens 	aclentp = aclp->acl_aclp;
800789Sahrens 	aclp->acl_aclp = NULL;
8011420Smarks 	*aclcnt = aclp->acl_cnt;
802789Sahrens 
8031420Smarks 	acl_free(aclp);
804789Sahrens 	return (aclentp);
805789Sahrens }
806789Sahrens 
807789Sahrens 
808*7057Smarks /*
809*7057Smarks  * returns a character position index of the start of the newly
810*7057Smarks  * appended string.  Returns -1 if operation couldn't be completed.
811*7057Smarks  */
812*7057Smarks static int
813*7057Smarks str_append(dynaclstr_t *dstr, char *newstr)
8140Sstevel@tonic-gate {
815*7057Smarks 	size_t len = strlen(newstr);
816*7057Smarks 
817*7057Smarks 	if ((len + dstr->d_pos) >= dstr->d_bufsize) {
818*7057Smarks 		dstr->d_aclexport = realloc(dstr->d_aclexport,
819*7057Smarks 		    dstr->d_bufsize + len + 1);
820*7057Smarks 		if (dstr->d_aclexport == NULL)
821*7057Smarks 			return (1);
822*7057Smarks 		dstr->d_bufsize += len;
823*7057Smarks 	}
824*7057Smarks 	(void) strcat(&dstr->d_aclexport[dstr->d_pos], newstr);
825*7057Smarks 	dstr->d_pos += len;
826*7057Smarks 	return (0);
8270Sstevel@tonic-gate }
8280Sstevel@tonic-gate 
829*7057Smarks static int
830*7057Smarks aclent_perm_txt(dynaclstr_t *dstr, o_mode_t perm)
8310Sstevel@tonic-gate {
832*7057Smarks 	char buf[4];
8330Sstevel@tonic-gate 
834*7057Smarks 	if (perm & S_IROTH)
835*7057Smarks 		buf[0] = 'r';
836*7057Smarks 	else
837*7057Smarks 		buf[0] = '-';
838*7057Smarks 	if (perm & S_IWOTH)
839*7057Smarks 		buf[1] = 'w';
840*7057Smarks 	else
841*7057Smarks 		buf[1] = '-';
842*7057Smarks 	if (perm & S_IXOTH)
843*7057Smarks 		buf[2] = 'x';
844*7057Smarks 	else
845*7057Smarks 		buf[2] = '-';
846*7057Smarks 	buf[3] = '\0';
847*7057Smarks 	return (str_append(dstr, buf));
8480Sstevel@tonic-gate }
849789Sahrens 
850789Sahrens /*
8511420Smarks  * ace_acltotext() convert each ace formatted acl to look like this:
852789Sahrens  *
8531420Smarks  * entry_type:uid^gid^name:perms[:flags]:<allow|deny>[:id][,]
854789Sahrens  *
855789Sahrens  * The maximum length of entry_type is 5 ("group")
856789Sahrens  *
8571420Smarks  * The max length of a uid^gid^name entry (in theory) is 8,
8581420Smarks  * however id could be a number so we therefore use ID_STR_MAX
859789Sahrens  *
860789Sahrens  * The length of a perms entry is 144 i.e read_data/write_data...
861789Sahrens  * to each acl entry.
862789Sahrens  *
8635331Samw  * iflags: file_inherit/dir_inherit/inherit_only/no_propagate/successful_access
8645331Samw  *         /failed_access
865789Sahrens  *
866789Sahrens  */
867789Sahrens 
868789Sahrens #define	ACE_ENTRYTYPLEN		6
8695331Samw #define	IFLAGS_STR "file_inherit/dir_inherit/inherit_only/no_propagate/" \
8705331Samw 	"successful_access/failed_access/inherited"
8715331Samw #define	IFLAGS_SIZE		(sizeof (IFLAGS_STR) - 1)
8721420Smarks #define	ACCESS_TYPE_SIZE	7	/* if unknown */
873789Sahrens #define	COLON_CNT		3
874789Sahrens #define	PERMS_LEN		216
8755331Samw #define	ACE_ENTRY_SIZE	(ACE_ENTRYTYPLEN + ID_STR_MAX + PERMS_LEN + \
8761420Smarks     ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT + APPENDED_ID_MAX)
877789Sahrens 
878789Sahrens static char *
8791420Smarks ace_acltotext(acl_t *aceaclp, int flags)
880789Sahrens {
881789Sahrens 	ace_t		*aclp = aceaclp->acl_aclp;
882789Sahrens 	int		aclcnt = aceaclp->acl_cnt;
883*7057Smarks 	int		i;
884*7057Smarks 	int		error = 0;
885*7057Smarks 	int		isdir = (aceaclp->acl_flags & ACL_IS_DIR);
886*7057Smarks 	dynaclstr_t 	*dstr;
887789Sahrens 	char		*aclexport;
888789Sahrens 
889789Sahrens 	if (aclp == NULL)
890789Sahrens 		return (NULL);
891789Sahrens 
892*7057Smarks 	if ((dstr = malloc(sizeof (dynaclstr_t))) == NULL)
893*7057Smarks 		return (NULL);
894*7057Smarks 	dstr->d_bufsize = aclcnt * ACL_ENTRY_SIZE;
895*7057Smarks 	if ((dstr->d_aclexport = malloc(dstr->d_bufsize)) == NULL) {
896*7057Smarks 		free(dstr);
897*7057Smarks 		return (NULL);
898*7057Smarks 	}
899*7057Smarks 	*dstr->d_aclexport = '\0';
900*7057Smarks 	dstr->d_pos = 0;
901*7057Smarks 
902789Sahrens 	for (i = 0; i < aclcnt; i++, aclp++) {
9031420Smarks 
904*7057Smarks 		if (error = ace_type_txt(dstr, aclp, flags))
905*7057Smarks 			break;
906*7057Smarks 		if (error = ace_perm_txt(dstr, aclp->a_access_mask,
907*7057Smarks 		    aclp->a_flags, isdir, flags))
908*7057Smarks 			break;
909*7057Smarks 		if (error = ace_inherit_txt(dstr, aclp->a_flags, flags))
910*7057Smarks 			break;
911*7057Smarks 		if (error = ace_access_txt(dstr, aclp->a_type))
912*7057Smarks 			break;
913789Sahrens 
9141420Smarks 		if ((flags & ACL_APPEND_ID) &&
9151420Smarks 		    (((aclp->a_flags & ACE_TYPE_FLAGS) == 0) ||
9161420Smarks 		    ((aclp->a_flags & ACE_TYPE_FLAGS) ==
9171420Smarks 		    ACE_IDENTIFIER_GROUP))) {
918*7057Smarks 			char id[ID_STR_MAX], *idstr;
919*7057Smarks 
920*7057Smarks 			if (error = str_append(dstr, ":"))
921*7057Smarks 				break;
9221420Smarks 			id[ID_STR_MAX -1] = '\0'; /* null terminate buffer */
923*7057Smarks 			idstr = lltostr((aclp->a_who > MAXUID &&
924*7057Smarks 			    !(flags & ACL_NORESOLVE)) ? UID_NOBODY :
925*7057Smarks 			    aclp->a_who, &id[ID_STR_MAX - 1]);
926*7057Smarks 			if (error = str_append(dstr, idstr))
927*7057Smarks 				break;
928789Sahrens 		}
9291420Smarks 		if (i < aclcnt - 1) {
930*7057Smarks 			if (error = str_append(dstr, ","))
931*7057Smarks 				break;
932789Sahrens 		}
933789Sahrens 	}
934*7057Smarks 	if (error) {
935*7057Smarks 		if (dstr->d_aclexport)
936*7057Smarks 			free(dstr->d_aclexport);
937*7057Smarks 	} else {
938*7057Smarks 		aclexport = dstr->d_aclexport;
939*7057Smarks 	}
940*7057Smarks 	free(dstr);
941789Sahrens 	return (aclexport);
942789Sahrens }
943789Sahrens 
9441420Smarks char *
9451420Smarks acl_totext(acl_t *aclp, int flags)
946789Sahrens {
9471420Smarks 	char *txtp;
948789Sahrens 
949789Sahrens 	if (aclp == NULL)
950789Sahrens 		return (NULL);
951789Sahrens 
952789Sahrens 	switch (aclp->acl_type) {
953789Sahrens 	case ACE_T:
9541420Smarks 		txtp = ace_acltotext(aclp, flags);
9551420Smarks 		break;
956789Sahrens 	case ACLENT_T:
9571420Smarks 		txtp = aclent_acltotext(aclp->acl_aclp, aclp->acl_cnt, flags);
9581420Smarks 		break;
959789Sahrens 	}
9601420Smarks 
9611420Smarks 	return (txtp);
962789Sahrens }
963789Sahrens 
964789Sahrens int
965789Sahrens acl_fromtext(const char *acltextp, acl_t **ret_aclp)
966789Sahrens {
9671420Smarks 	int error;
9681420Smarks 	char *buf;
9691420Smarks 
9701420Smarks 	buf = malloc(strlen(acltextp) + 2);
9711420Smarks 	if (buf == NULL)
9721420Smarks 		return (EACL_MEM_ERROR);
9731420Smarks 	strcpy(buf, acltextp);
9741420Smarks 	strcat(buf, "\n");
9751420Smarks 	yybuf = buf;
9761420Smarks 	yyreset();
9771420Smarks 	error = yyparse();
9781420Smarks 	free(buf);
9791420Smarks 
9801420Smarks 	if (yyacl) {
9811420Smarks 		if (error == 0)
9821420Smarks 			*ret_aclp = yyacl;
9831420Smarks 		else {
9841420Smarks 			acl_free(yyacl);
9851420Smarks 		}
9861420Smarks 		yyacl = NULL;
9871420Smarks 	}
9881420Smarks 	return (error);
9891420Smarks }
9901420Smarks 
9911420Smarks int
9921420Smarks acl_parse(const char *acltextp, acl_t **aclp)
9931420Smarks {
994789Sahrens 	int error;
995789Sahrens 
9961420Smarks 	yyinteractive = 1;
9971420Smarks 	error = acl_fromtext(acltextp, aclp);
9981420Smarks 	yyinteractive = 0;
9991420Smarks 	return (error);
10001420Smarks }
10011420Smarks 
10021420Smarks static void
10031420Smarks ace_compact_printacl(acl_t *aclp)
10041420Smarks {
10051420Smarks 	int cnt;
10061420Smarks 	ace_t *acep;
1007*7057Smarks 	dynaclstr_t *dstr;
1008*7057Smarks 	int len;
1009789Sahrens 
1010*7057Smarks 	if ((dstr = malloc(sizeof (dynaclstr_t))) == NULL)
1011*7057Smarks 		return;
1012*7057Smarks 	dstr->d_bufsize = ACE_ENTRY_SIZE;
1013*7057Smarks 	if ((dstr->d_aclexport = malloc(dstr->d_bufsize)) == NULL) {
1014*7057Smarks 		free(dstr);
1015*7057Smarks 		return;
1016*7057Smarks 	}
1017*7057Smarks 	*dstr->d_aclexport = '\0';
1018*7057Smarks 
1019*7057Smarks 	dstr->d_pos = 0;
10201420Smarks 	for (cnt = 0, acep = aclp->acl_aclp;
10211420Smarks 	    cnt != aclp->acl_cnt; cnt++, acep++) {
1022*7057Smarks 		dstr->d_aclexport[0] = '\0';
1023*7057Smarks 		dstr->d_pos = 0;
1024*7057Smarks 
1025*7057Smarks 		if (ace_type_txt(dstr, acep, 0))
1026*7057Smarks 			break;
1027*7057Smarks 		len = strlen(&dstr->d_aclexport[0]);
1028*7057Smarks 		if (ace_perm_txt(dstr, acep->a_access_mask, acep->a_flags,
1029*7057Smarks 		    aclp->acl_flags & ACL_IS_DIR, ACL_COMPACT_FMT))
1030*7057Smarks 			break;
1031*7057Smarks 		if (ace_inherit_txt(dstr, acep->a_flags, ACL_COMPACT_FMT))
1032*7057Smarks 			break;
1033*7057Smarks 		if (ace_access_txt(dstr, acep->a_type) == -1)
1034*7057Smarks 			break;
1035*7057Smarks 		(void) printf("    %20.*s%s\n", len, dstr->d_aclexport,
1036*7057Smarks 		    &dstr->d_aclexport[len]);
10371420Smarks 	}
1038*7057Smarks 
1039*7057Smarks 	if (dstr->d_aclexport)
1040*7057Smarks 		free(dstr->d_aclexport);
1041*7057Smarks 	free(dstr);
10421420Smarks }
1043789Sahrens 
10441420Smarks static void
10451420Smarks ace_printacl(acl_t *aclp, int cols, int compact)
10461420Smarks {
10471420Smarks 	int  slot = 0;
10481420Smarks 	char *token;
10491420Smarks 	char *acltext;
10501420Smarks 
10511420Smarks 	if (compact) {
10521420Smarks 		ace_compact_printacl(aclp);
10531420Smarks 		return;
1054789Sahrens 	}
1055789Sahrens 
10561420Smarks 	acltext = acl_totext(aclp, 0);
10571420Smarks 
10581420Smarks 	if (acltext == NULL)
10591420Smarks 		return;
10601420Smarks 
10611420Smarks 	token = strtok(acltext, ",");
10621420Smarks 	if (token == NULL) {
10631420Smarks 		free(acltext);
10641420Smarks 		return;
1065789Sahrens 	}
1066789Sahrens 
10671420Smarks 	do {
10681420Smarks 		(void) printf("     %d:", slot++);
10691420Smarks 		split_line(token, cols - 5);
10701420Smarks 	} while (token = strtok(NULL, ","));
10711420Smarks 	free(acltext);
10721420Smarks }
10731420Smarks 
10741420Smarks /*
10751420Smarks  * pretty print an ACL.
10761420Smarks  * For aclent_t ACL's the format is
10771420Smarks  * similar to the old format used by getfacl,
10781420Smarks  * with the addition of adding a "slot" number
10791420Smarks  * before each entry.
10801420Smarks  *
10811420Smarks  * for ace_t ACL's the cols variable will break up
10821420Smarks  * the long lines into multiple lines and will also
10831420Smarks  * print a "slot" number.
10841420Smarks  */
10851420Smarks void
10861420Smarks acl_printacl(acl_t *aclp, int cols, int compact)
10871420Smarks {
10881420Smarks 
10891420Smarks 	switch (aclp->acl_type) {
10901420Smarks 	case ACLENT_T:
10911420Smarks 		aclent_printacl(aclp);
10921420Smarks 		break;
10931420Smarks 	case ACE_T:
10941420Smarks 		ace_printacl(aclp, cols, compact);
10951420Smarks 		break;
10961420Smarks 	}
10971420Smarks }
10981420Smarks 
10991420Smarks typedef struct value_table {
11001420Smarks 	char		p_letter; /* perm letter such as 'r' */
11011420Smarks 	uint32_t	p_value; /* value for perm when pletter found */
11021420Smarks } value_table_t;
11031420Smarks 
11041420Smarks /*
11055331Samw  * The permission tables are laid out in positional order
11061420Smarks  * a '-' character will indicate a permission at a given
11071420Smarks  * position is not specified.  The '-' is not part of the
11081420Smarks  * table, but will be checked for in the permission computation
11091420Smarks  * routine.
11101420Smarks  */
11115331Samw value_table_t ace_perm_table[] = {
11121420Smarks 	{ 'r', ACE_READ_DATA},
11131420Smarks 	{ 'w', ACE_WRITE_DATA},
11141420Smarks 	{ 'x', ACE_EXECUTE},
11151420Smarks 	{ 'p', ACE_APPEND_DATA},
11161420Smarks 	{ 'd', ACE_DELETE},
11171420Smarks 	{ 'D', ACE_DELETE_CHILD},
11181420Smarks 	{ 'a', ACE_READ_ATTRIBUTES},
11191420Smarks 	{ 'A', ACE_WRITE_ATTRIBUTES},
11201420Smarks 	{ 'R', ACE_READ_NAMED_ATTRS},
11211420Smarks 	{ 'W', ACE_WRITE_NAMED_ATTRS},
11221420Smarks 	{ 'c', ACE_READ_ACL},
11231420Smarks 	{ 'C', ACE_WRITE_ACL},
11241420Smarks 	{ 'o', ACE_WRITE_OWNER},
11251420Smarks 	{ 's', ACE_SYNCHRONIZE}
11261420Smarks };
11271420Smarks 
11285331Samw #define	ACE_PERM_COUNT (sizeof (ace_perm_table) / sizeof (value_table_t))
11291420Smarks 
11305331Samw value_table_t aclent_perm_table[] = {
11311420Smarks 	{ 'r', S_IROTH},
11321420Smarks 	{ 'w', S_IWOTH},
11331420Smarks 	{ 'x', S_IXOTH}
11341420Smarks };
11351420Smarks 
11365331Samw #define	ACLENT_PERM_COUNT (sizeof (aclent_perm_table) / sizeof (value_table_t))
11375331Samw 
11385331Samw value_table_t inherit_table[] = {
11391420Smarks 	{'f', ACE_FILE_INHERIT_ACE},
11401420Smarks 	{'d', ACE_DIRECTORY_INHERIT_ACE},
11411420Smarks 	{'i', ACE_INHERIT_ONLY_ACE},
11421420Smarks 	{'n', ACE_NO_PROPAGATE_INHERIT_ACE},
11431420Smarks 	{'S', ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
11445331Samw 	{'F', ACE_FAILED_ACCESS_ACE_FLAG},
11455331Samw 	{'I', ACE_INHERITED_ACE}
11461420Smarks };
11471420Smarks 
11485331Samw #define	IFLAG_COUNT (sizeof (inherit_table) / sizeof (value_table_t))
11496269Smarks #define	IFLAG_COUNT_V1 6 /* Older version compatibility */
11505331Samw 
11511420Smarks /*
11521420Smarks  * compute value from a permission table or inheritance table
11531420Smarks  * based on string passed in.  If positional is set then
11541420Smarks  * string must match order in permtab, otherwise any order
11551420Smarks  * is allowed.
11561420Smarks  */
11571420Smarks int
11581420Smarks compute_values(value_table_t *permtab, int count,
11591420Smarks     char *permstr, int positional, uint32_t *mask)
11601420Smarks {
11611420Smarks 	uint32_t perm_val = 0;
11621420Smarks 	char *pstr;
11631420Smarks 	int i, found;
11641420Smarks 
11651420Smarks 	if (count < 0)
11661420Smarks 		return (1);
11671420Smarks 
11681420Smarks 	if (positional) {
11691420Smarks 		for (i = 0, pstr = permstr; i != count && pstr &&
11701420Smarks 		    *pstr; i++, pstr++) {
11711420Smarks 			if (*pstr == permtab[i].p_letter) {
11721420Smarks 				perm_val |= permtab[i].p_value;
11731420Smarks 			} else if (*pstr != '-') {
11741420Smarks 				return (1);
11751420Smarks 			}
1176789Sahrens 		}
11771420Smarks 	} else {  /* random order single letters with no '-' */
11781420Smarks 		for (pstr = permstr; pstr && *pstr; pstr++) {
11791420Smarks 			for (found = 0, i = 0; i != count; i++) {
11801420Smarks 				if (*pstr == permtab[i].p_letter) {
11811420Smarks 					perm_val |= permtab[i].p_value;
11821420Smarks 					found = 1;
11831420Smarks 					break;
11841420Smarks 				}
11851420Smarks 			}
11861420Smarks 			if (found == 0)
11871420Smarks 				return (1);
11881420Smarks 		}
1189789Sahrens 	}
1190789Sahrens 
11911420Smarks 	*mask = perm_val;
11921420Smarks 	return (0);
11931420Smarks }
1194789Sahrens 
11956269Smarks 
11966269Smarks int
11976269Smarks ace_inherit_helper(char *str, uint32_t *imask, int table_length)
11986269Smarks {
11996269Smarks 	int rc = 0;
12006269Smarks 
12016269Smarks 	if (strlen(str) == table_length) {
12026269Smarks 		/*
12036269Smarks 		 * If the string == table_length then first check to see it's
12046269Smarks 		 * in positional format.  If that fails then see if it's in
12056269Smarks 		 * non-positional format.
12066269Smarks 		 */
12076269Smarks 		if (compute_values(inherit_table, table_length, str,
12086269Smarks 		    1, imask) && compute_values(inherit_table,
12096269Smarks 		    table_length, str, 0, imask)) {
12106269Smarks 			rc = 1;
12116269Smarks 		}
12126269Smarks 	} else {
12136269Smarks 		rc = compute_values(inherit_table, table_length, str, 0, imask);
12146269Smarks 	}
12156269Smarks 
12166269Smarks 	return (rc ? EACL_INHERIT_ERROR : 0);
12176269Smarks }
12186269Smarks 
12191420Smarks /*
12201420Smarks  * compute value for inheritance flags.
12211420Smarks  */
12221420Smarks int
12231420Smarks compute_ace_inherit(char *str, uint32_t *imask)
12241420Smarks {
12256269Smarks 	int rc = 0;
1226789Sahrens 
12276269Smarks 	rc = ace_inherit_helper(str, imask, IFLAG_COUNT);
12286269Smarks 
12296269Smarks 	if (rc && strlen(str) != IFLAG_COUNT) {
12301420Smarks 
12316269Smarks 		/* is it an old formatted inherit string? */
12326269Smarks 		rc = ace_inherit_helper(str, imask, IFLAG_COUNT_V1);
12336269Smarks 	}
12341420Smarks 
12356269Smarks 	return (rc);
1236789Sahrens }
12371420Smarks 
12381420Smarks 
12391420Smarks /*
12401420Smarks  * compute value for ACE permissions.
12411420Smarks  */
12421420Smarks int
12431420Smarks compute_ace_perms(char *str, uint32_t *mask)
12441420Smarks {
12451420Smarks 	int positional = 0;
12461420Smarks 	int error;
12471420Smarks 
12481420Smarks 	if (strlen(str) == ACE_PERM_COUNT)
12491420Smarks 		positional = 1;
12501420Smarks 
12511420Smarks 	error = compute_values(ace_perm_table, ACE_PERM_COUNT,
12521420Smarks 	    str, positional, mask);
12531420Smarks 
12541420Smarks 	if (error && positional) {
12551420Smarks 		/*
12561420Smarks 		 * If positional was set, then make sure permissions
12571420Smarks 		 * aren't actually valid in non positional case where
12581420Smarks 		 * all permissions are specified, just in random order.
12591420Smarks 		 */
12601420Smarks 		error = compute_values(ace_perm_table,
12611420Smarks 		    ACE_PERM_COUNT, str, 0, mask);
12621420Smarks 	}
12631420Smarks 	if (error)
12641420Smarks 		error = EACL_PERM_MASK_ERROR;
12651420Smarks 
12661420Smarks 	return (error);
12671420Smarks }
12681420Smarks 
12691420Smarks 
12701420Smarks 
12711420Smarks /*
12721420Smarks  * compute values for aclent permissions.
12731420Smarks  */
12741420Smarks int
12751420Smarks compute_aclent_perms(char *str, o_mode_t *mask)
12761420Smarks {
12771420Smarks 	int error;
12781420Smarks 	uint32_t pmask;
12791420Smarks 
12801420Smarks 	if (strlen(str) != ACLENT_PERM_COUNT)
12811420Smarks 		return (EACL_PERM_MASK_ERROR);
12821420Smarks 
12831420Smarks 	*mask = 0;
12841420Smarks 	error = compute_values(aclent_perm_table, ACLENT_PERM_COUNT,
12851420Smarks 	    str, 1, &pmask);
12861420Smarks 	if (error == 0) {
12871420Smarks 		*mask = (o_mode_t)pmask;
12881420Smarks 	} else
12891420Smarks 		error = EACL_PERM_MASK_ERROR;
12901420Smarks 	return (error);
12911420Smarks }
12921420Smarks 
12931420Smarks /*
12941420Smarks  * determine ACE permissions.
12951420Smarks  */
12961420Smarks int
12971420Smarks ace_perm_mask(struct acl_perm_type *aclperm, uint32_t *mask)
12981420Smarks {
12991420Smarks 	int error;
13001420Smarks 
13011420Smarks 	if (aclperm->perm_style == PERM_TYPE_EMPTY) {
13021420Smarks 		*mask = 0;
13031420Smarks 		return (0);
13041420Smarks 	}
13051420Smarks 
13061420Smarks 	if (aclperm->perm_style == PERM_TYPE_ACE) {
13071420Smarks 		*mask = aclperm->perm_val;
13081420Smarks 		return (0);
13091420Smarks 	}
13101420Smarks 
13111420Smarks 	error = compute_ace_perms(aclperm->perm_str, mask);
13121420Smarks 	if (error) {
13131567Smarks 		acl_error(dgettext(TEXT_DOMAIN,
13141567Smarks 		    "Invalid permission(s) '%s' specified\n"),
13151420Smarks 		    aclperm->perm_str);
13161420Smarks 		return (EACL_PERM_MASK_ERROR);
13171420Smarks 	}
13181420Smarks 
13191420Smarks 	return (0);
13201420Smarks }
1321