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 /*LINTLIBRARY*/
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <grp.h>
290Sstevel@tonic-gate #include <pwd.h>
300Sstevel@tonic-gate #include <string.h>
310Sstevel@tonic-gate #include <limits.h>
320Sstevel@tonic-gate #include <stdlib.h>
33789Sahrens #include <errno.h>
340Sstevel@tonic-gate #include <sys/param.h>
350Sstevel@tonic-gate #include <sys/types.h>
361420Smarks #include <sys/stat.h>
370Sstevel@tonic-gate #include <sys/acl.h>
38789Sahrens #include <aclutils.h>
397057Smarks #include <idmap.h>
401420Smarks 
411420Smarks #define	ID_STR_MAX	20	/* digits in LONG_MAX */
42789Sahrens 
431420Smarks #define	APPENDED_ID_MAX	ID_STR_MAX + 1		/* id + colon */
441420Smarks /*
451420Smarks  * yyinteractive controls whether yyparse should print out
461420Smarks  * error messages to stderr, and whether or not id's should be
471420Smarks  * allowed from acl_fromtext().
481420Smarks  */
491420Smarks int	yyinteractive;
501420Smarks acl_t	*yyacl;
511420Smarks char	*yybuf;
52789Sahrens 
53789Sahrens extern acl_t *acl_alloc(enum acl_type);
540Sstevel@tonic-gate 
557057Smarks /*
567057Smarks  * dynamic string that will increase in size on an
577057Smarks  * as needed basis.
587057Smarks  */
597057Smarks typedef struct dynaclstr {
607057Smarks 	size_t d_bufsize;		/* current size of aclexport */
617057Smarks 	char *d_aclexport;
627057Smarks 	int d_pos;
637057Smarks } dynaclstr_t;
64922Shm123892 
657057Smarks static int str_append(dynaclstr_t *, char *);
667057Smarks static int aclent_perm_txt(dynaclstr_t *, o_mode_t);
670Sstevel@tonic-gate 
681420Smarks static void
691420Smarks aclent_perms(int perm, char *txt_perms)
701420Smarks {
711420Smarks 	if (perm & S_IROTH)
721420Smarks 		txt_perms[0] = 'r';
731420Smarks 	else
741420Smarks 		txt_perms[0] = '-';
751420Smarks 	if (perm & S_IWOTH)
761420Smarks 		txt_perms[1] = 'w';
771420Smarks 	else
781420Smarks 		txt_perms[1] = '-';
791420Smarks 	if (perm & S_IXOTH)
801420Smarks 		txt_perms[2] = 'x';
811420Smarks 	else
821420Smarks 		txt_perms[2] = '-';
831420Smarks 	txt_perms[3] = '\0';
841420Smarks }
851420Smarks 
861420Smarks static char *
871535Smarks pruname(uid_t uid, char *uidp, size_t buflen, int noresolve)
881420Smarks {
891515Sgjelinek 	struct passwd	*passwdp = NULL;
901420Smarks 
911515Sgjelinek 	if (noresolve == 0)
921515Sgjelinek 		passwdp = getpwuid(uid);
931420Smarks 	if (passwdp == (struct passwd *)NULL) {
941420Smarks 		/* could not get passwd information: display uid instead */
954321Scasper 		(void) snprintf(uidp, buflen, "%u", uid);
961535Smarks 	} else {
971535Smarks 		(void) strlcpy(uidp, passwdp->pw_name, buflen);
981535Smarks 	}
991535Smarks 	return (uidp);
1001420Smarks }
1011420Smarks 
1021420Smarks static char *
1031535Smarks prgname(gid_t gid, char *gidp, size_t buflen, int noresolve)
1041420Smarks {
1051515Sgjelinek 	struct group	*groupp = NULL;
1061420Smarks 
1071515Sgjelinek 	if (noresolve == 0)
1081515Sgjelinek 		groupp = getgrgid(gid);
1091420Smarks 	if (groupp == (struct group *)NULL) {
1101420Smarks 		/* could not get group information: display gid instead */
1114321Scasper 		(void) snprintf(gidp, buflen, "%u", gid);
1121535Smarks 	} else {
1131535Smarks 		(void) strlcpy(gidp, groupp->gr_name, buflen);
1141535Smarks 	}
1151535Smarks 	return (gidp);
1161420Smarks }
1177057Smarks 
118*7680SMark.Shellenbaum@Sun.COM static int
119*7680SMark.Shellenbaum@Sun.COM getsidname(uid_t who, boolean_t user, char **sidp, boolean_t noresolve)
1207057Smarks {
1217057Smarks 	idmap_handle_t *idmap_hdl = NULL;
1227057Smarks 	idmap_get_handle_t *get_hdl = NULL;
1237057Smarks 	idmap_stat status;
1247057Smarks 	idmap_rid_t rid;
125*7680SMark.Shellenbaum@Sun.COM 	int error = IDMAP_ERR_NORESULT;
1267057Smarks 	int len;
1277057Smarks 	char *domain;
1287057Smarks 	char *name;
1297057Smarks 
130*7680SMark.Shellenbaum@Sun.COM 	*sidp = NULL;
1317057Smarks 
1327057Smarks 	/*
1337057Smarks 	 * First try and get windows name
1347057Smarks 	 */
1357057Smarks 
136*7680SMark.Shellenbaum@Sun.COM 	if (!noresolve) {
137*7680SMark.Shellenbaum@Sun.COM 		if (user)
138*7680SMark.Shellenbaum@Sun.COM 			error = idmap_getwinnamebyuid(who,
139*7680SMark.Shellenbaum@Sun.COM 			    IDMAP_REQ_FLG_USE_CACHE, &name, &domain);
140*7680SMark.Shellenbaum@Sun.COM 		else
141*7680SMark.Shellenbaum@Sun.COM 			error = idmap_getwinnamebygid(who,
142*7680SMark.Shellenbaum@Sun.COM 			    IDMAP_REQ_FLG_USE_CACHE, &name, &domain);
143*7680SMark.Shellenbaum@Sun.COM 	}
144*7680SMark.Shellenbaum@Sun.COM 	if (error != IDMAP_SUCCESS) {
145*7680SMark.Shellenbaum@Sun.COM 		if (idmap_init(&idmap_hdl) == IDMAP_SUCCESS &&
146*7680SMark.Shellenbaum@Sun.COM 		    idmap_get_create(idmap_hdl, &get_hdl) == IDMAP_SUCCESS) {
1477057Smarks 			if (user)
1487057Smarks 				error = idmap_get_sidbyuid(get_hdl, who,
1497369SJulian.Pullen@Sun.COM 				    IDMAP_REQ_FLG_USE_CACHE, &domain, &rid,
1507369SJulian.Pullen@Sun.COM 				    &status);
1517057Smarks 			else
1527057Smarks 				error = idmap_get_sidbygid(get_hdl, who,
1537369SJulian.Pullen@Sun.COM 				    IDMAP_REQ_FLG_USE_CACHE, &domain, &rid,
1547369SJulian.Pullen@Sun.COM 				    &status);
155*7680SMark.Shellenbaum@Sun.COM 			if (error == IDMAP_SUCCESS &&
156*7680SMark.Shellenbaum@Sun.COM 			    idmap_get_mappings(get_hdl) == 0) {
157*7680SMark.Shellenbaum@Sun.COM 				if (status == IDMAP_SUCCESS) {
158*7680SMark.Shellenbaum@Sun.COM 					len = snprintf(NULL, 0,
159*7680SMark.Shellenbaum@Sun.COM 					    "%s-%d", domain, rid);
160*7680SMark.Shellenbaum@Sun.COM 					if (*sidp = malloc(len + 1)) {
161*7680SMark.Shellenbaum@Sun.COM 						(void) snprintf(*sidp, len + 1,
162*7680SMark.Shellenbaum@Sun.COM 						    "%s-%d", domain, rid);
163*7680SMark.Shellenbaum@Sun.COM 					}
164*7680SMark.Shellenbaum@Sun.COM 				}
165*7680SMark.Shellenbaum@Sun.COM 			}
1667057Smarks 		}
1677057Smarks 		if (get_hdl)
1687057Smarks 			idmap_get_destroy(get_hdl);
1697057Smarks 		if (idmap_hdl)
1707057Smarks 			(void) idmap_fini(idmap_hdl);
1717057Smarks 	} else {
1727057Smarks 		int len;
173*7680SMark.Shellenbaum@Sun.COM 
1747057Smarks 		len = snprintf(NULL, 0, "%s@%d", name, domain);
175*7680SMark.Shellenbaum@Sun.COM 		if (*sidp = malloc(len + 1))
176*7680SMark.Shellenbaum@Sun.COM 			(void) snprintf(*sidp, len + 1, "%s@%s", name, domain);
1777057Smarks 	}
178*7680SMark.Shellenbaum@Sun.COM 	return (*sidp ? 0 : 1);
1797057Smarks }
1807057Smarks 
1811420Smarks static void
1821420Smarks aclent_printacl(acl_t *aclp)
183789Sahrens {
1841420Smarks 	aclent_t *tp;
1851420Smarks 	int aclcnt;
1861420Smarks 	int mask;
1871420Smarks 	int slot = 0;
1881420Smarks 	char perm[4];
1891535Smarks 	char uidp[ID_STR_MAX];
1901535Smarks 	char gidp[ID_STR_MAX];
1911420Smarks 
1921420Smarks 	/* display ACL: assume it is sorted. */
1931420Smarks 	aclcnt = aclp->acl_cnt;
1941420Smarks 	for (tp = aclp->acl_aclp; tp && aclcnt--; tp++) {
1951420Smarks 		if (tp->a_type == CLASS_OBJ)
1961420Smarks 			mask = tp->a_perm;
1971420Smarks 	}
1981420Smarks 	aclcnt = aclp->acl_cnt;
1991420Smarks 	for (tp = aclp->acl_aclp; aclcnt--; tp++) {
2001420Smarks 		(void) printf("     %d:", slot++);
2011420Smarks 		switch (tp->a_type) {
2021420Smarks 		case USER:
2031420Smarks 			aclent_perms(tp->a_perm, perm);
2041420Smarks 			(void) printf("user:%s:%s\t\t",
2051535Smarks 			    pruname(tp->a_id, uidp, sizeof (uidp), 0), perm);
2061420Smarks 			aclent_perms((tp->a_perm & mask), perm);
2071420Smarks 			(void) printf("#effective:%s\n", perm);
2081420Smarks 			break;
2091420Smarks 		case USER_OBJ:
2101420Smarks 			/* no need to display uid */
2111420Smarks 			aclent_perms(tp->a_perm, perm);
2121420Smarks 			(void) printf("user::%s\n", perm);
2131420Smarks 			break;
2141420Smarks 		case GROUP:
2151420Smarks 			aclent_perms(tp->a_perm, perm);
2161420Smarks 			(void) printf("group:%s:%s\t\t",
2171535Smarks 			    prgname(tp->a_id, gidp, sizeof (gidp), 0), perm);
2181420Smarks 			aclent_perms(tp->a_perm & mask, perm);
2191420Smarks 			(void) printf("#effective:%s\n", perm);
2201420Smarks 			break;
2211420Smarks 		case GROUP_OBJ:
2221420Smarks 			aclent_perms(tp->a_perm, perm);
2231420Smarks 			(void) printf("group::%s\t\t", perm);
2241420Smarks 			aclent_perms(tp->a_perm & mask, perm);
2251420Smarks 			(void) printf("#effective:%s\n", perm);
2261420Smarks 			break;
2271420Smarks 		case CLASS_OBJ:
2281420Smarks 			aclent_perms(tp->a_perm, perm);
2291420Smarks 			(void) printf("mask:%s\n", perm);
2301420Smarks 			break;
2311420Smarks 		case OTHER_OBJ:
2321420Smarks 			aclent_perms(tp->a_perm, perm);
2331420Smarks 			(void) printf("other:%s\n", perm);
2341420Smarks 			break;
2351420Smarks 		case DEF_USER:
2361420Smarks 			aclent_perms(tp->a_perm, perm);
2371420Smarks 			(void) printf("default:user:%s:%s\n",
2381535Smarks 			    pruname(tp->a_id, uidp, sizeof (uidp), 0), perm);
2391420Smarks 			break;
2401420Smarks 		case DEF_USER_OBJ:
2411420Smarks 			aclent_perms(tp->a_perm, perm);
2421420Smarks 			(void) printf("default:user::%s\n", perm);
2431420Smarks 			break;
2441420Smarks 		case DEF_GROUP:
2451420Smarks 			aclent_perms(tp->a_perm, perm);
2461420Smarks 			(void) printf("default:group:%s:%s\n",
2471535Smarks 			    prgname(tp->a_id, gidp, sizeof (gidp), 0), perm);
2481420Smarks 			break;
2491420Smarks 		case DEF_GROUP_OBJ:
2501420Smarks 			aclent_perms(tp->a_perm, perm);
2511420Smarks 			(void) printf("default:group::%s\n", perm);
2521420Smarks 			break;
2531420Smarks 		case DEF_CLASS_OBJ:
2541420Smarks 			aclent_perms(tp->a_perm, perm);
2551420Smarks 			(void) printf("default:mask:%s\n", perm);
2561420Smarks 			break;
2571420Smarks 		case DEF_OTHER_OBJ:
2581420Smarks 			aclent_perms(tp->a_perm, perm);
2591420Smarks 			(void) printf("default:other:%s\n", perm);
2601420Smarks 			break;
2611420Smarks 		default:
2621420Smarks 			(void) fprintf(stderr,
2631567Smarks 			    dgettext(TEXT_DOMAIN, "unrecognized entry\n"));
2641420Smarks 			break;
2651420Smarks 		}
2661420Smarks 	}
2671420Smarks }
2681420Smarks 
2691420Smarks static void
2701420Smarks split_line(char *str, int cols)
2711420Smarks {
2721420Smarks 	char *ptr;
2731420Smarks 	int len;
2741420Smarks 	int i;
2751420Smarks 	int last_split;
2761420Smarks 	char *pad = "";
2771420Smarks 	int pad_len;
2781420Smarks 
2791420Smarks 	len = strlen(str);
2801420Smarks 	ptr = str;
2811420Smarks 	pad_len = 0;
2821420Smarks 
2831420Smarks 	ptr = str;
2841420Smarks 	last_split = 0;
2851420Smarks 	for (i = 0; i != len; i++) {
2861420Smarks 		if ((i + pad_len + 4) >= cols) {
2871420Smarks 			(void) printf("%s%.*s\n", pad, last_split, ptr);
2881420Smarks 			ptr = &ptr[last_split];
2891420Smarks 			len = strlen(ptr);
2901420Smarks 			i = 0;
2911420Smarks 			pad_len = 4;
2921420Smarks 			pad = "         ";
2931420Smarks 		} else {
2941420Smarks 			if (ptr[i] == '/' || ptr[i] == ':') {
2951420Smarks 				last_split = i;
2961420Smarks 			}
2971420Smarks 		}
2981420Smarks 	}
2991420Smarks 	if (i == len) {
3001420Smarks 		(void) printf("%s%s\n", pad, ptr);
3011420Smarks 	}
3021420Smarks }
3031420Smarks 
3047057Smarks /*
3057057Smarks  * compute entry type string, such as user:joe, group:staff,...
3067057Smarks  */
3077057Smarks static int
3087057Smarks aclent_type_txt(dynaclstr_t *dstr, aclent_t *aclp, int flags)
3091420Smarks {
3107057Smarks 	char idp[ID_STR_MAX];
3117057Smarks 	int error;
3127057Smarks 
3137057Smarks 	switch (aclp->a_type) {
3147057Smarks 	case DEF_USER_OBJ:
3157057Smarks 	case USER_OBJ:
3167057Smarks 		if (aclp->a_type == USER_OBJ)
3177057Smarks 			error = str_append(dstr, "user::");
3187057Smarks 		else
3197057Smarks 			error = str_append(dstr, "defaultuser::");
3207057Smarks 		break;
3217057Smarks 
3227057Smarks 	case DEF_USER:
3237057Smarks 	case USER:
3247057Smarks 		if (aclp->a_type == USER)
3257057Smarks 			error = str_append(dstr, "user:");
3267057Smarks 		else
3277057Smarks 			error = str_append(dstr, "defaultuser:");
3287057Smarks 		if (error)
3297057Smarks 			break;
3307057Smarks 		error = str_append(dstr, pruname(aclp->a_id, idp,
3317057Smarks 		    sizeof (idp), flags & ACL_NORESOLVE));
3327057Smarks 		if (error == 0)
3337057Smarks 			error = str_append(dstr, ":");
3347057Smarks 		break;
3357057Smarks 
3367057Smarks 	case DEF_GROUP_OBJ:
3377057Smarks 	case GROUP_OBJ:
3387057Smarks 		if (aclp->a_type == GROUP_OBJ)
3397057Smarks 			error = str_append(dstr, "group::");
3407057Smarks 		else
3417057Smarks 			error = str_append(dstr, "defaultgroup::");
3427057Smarks 		break;
3431420Smarks 
3447057Smarks 	case DEF_GROUP:
3457057Smarks 	case GROUP:
3467057Smarks 		if (aclp->a_type == GROUP)
3477057Smarks 			error = str_append(dstr, "group:");
3487057Smarks 		else
3497057Smarks 			error = str_append(dstr, "defaultgroup:");
3507057Smarks 		if (error)
3517057Smarks 			break;
3527057Smarks 		error = str_append(dstr, prgname(aclp->a_id, idp,
3537057Smarks 		    sizeof (idp), flags & ACL_NORESOLVE));
3547057Smarks 		if (error == 0)
3557057Smarks 			error = str_append(dstr, ":");
3567057Smarks 		break;
3577057Smarks 
3587057Smarks 	case DEF_CLASS_OBJ:
3597057Smarks 	case CLASS_OBJ:
3607057Smarks 		if (aclp->a_type == CLASS_OBJ)
3617057Smarks 			error = str_append(dstr, "mask:");
3627057Smarks 		else
3637057Smarks 			error = str_append(dstr, "defaultmask:");
3647057Smarks 		break;
3651420Smarks 
3667057Smarks 	case DEF_OTHER_OBJ:
3677057Smarks 	case OTHER_OBJ:
3687057Smarks 		if (aclp->a_type == OTHER_OBJ)
3697057Smarks 			error = str_append(dstr, "other:");
3707057Smarks 		else
3717057Smarks 			error = str_append(dstr, "defaultother:");
3727057Smarks 		break;
3737057Smarks 
3747057Smarks 	default:
3757057Smarks 		error = 1;
3767057Smarks 		break;
3777057Smarks 	}
3787057Smarks 
3797057Smarks 	return (error);
3807057Smarks }
3817057Smarks 
3827057Smarks /*
3837057Smarks  * compute entry type string such as, owner@:, user:joe, group:staff,...
3847057Smarks  */
3857057Smarks static int
3867057Smarks ace_type_txt(dynaclstr_t *dynstr, ace_t *acep, int flags)
3877057Smarks {
3887057Smarks 	char idp[ID_STR_MAX];
3897057Smarks 	int error;
3907057Smarks 	char *sidp = NULL;
3911420Smarks 
3921420Smarks 	switch (acep->a_flags & ACE_TYPE_FLAGS) {
3931420Smarks 	case ACE_OWNER:
3947057Smarks 		error = str_append(dynstr, OWNERAT_TXT);
3951420Smarks 		break;
3961420Smarks 
3971420Smarks 	case ACE_GROUP|ACE_IDENTIFIER_GROUP:
3987057Smarks 		error = str_append(dynstr, GROUPAT_TXT);
3991420Smarks 		break;
4001420Smarks 
4011420Smarks 	case ACE_IDENTIFIER_GROUP:
4027057Smarks 		if ((flags & ACL_SID_FMT) && acep->a_who > MAXUID) {
4037057Smarks 			if (error = str_append(dynstr,
4047057Smarks 			    GROUPSID_TXT))
4057057Smarks 				break;
406*7680SMark.Shellenbaum@Sun.COM 			if (error = getsidname(acep->a_who, B_FALSE,
407*7680SMark.Shellenbaum@Sun.COM 			    &sidp, flags & ACL_NORESOLVE))
408*7680SMark.Shellenbaum@Sun.COM 				break;
409*7680SMark.Shellenbaum@Sun.COM 			error = str_append(dynstr, sidp);
4107057Smarks 		} else {
4117057Smarks 			if (error = str_append(dynstr, GROUP_TXT))
4127057Smarks 				break;
4137057Smarks 			error = str_append(dynstr, prgname(acep->a_who, idp,
4147057Smarks 			    sizeof (idp), flags & ACL_NORESOLVE));
4157057Smarks 		}
4167057Smarks 		if (error == 0)
4177057Smarks 			error = str_append(dynstr, ":");
4181420Smarks 		break;
4191420Smarks 
4201420Smarks 	case ACE_EVERYONE:
4217057Smarks 		error = str_append(dynstr, EVERYONEAT_TXT);
4221420Smarks 		break;
4231420Smarks 
4241420Smarks 	case 0:
4257057Smarks 		if ((flags & ACL_SID_FMT) && acep->a_who > MAXUID) {
4267057Smarks 			if (error = str_append(dynstr, USERSID_TXT))
4277057Smarks 				break;
428*7680SMark.Shellenbaum@Sun.COM 			if (error = getsidname(acep->a_who, B_TRUE,
429*7680SMark.Shellenbaum@Sun.COM 			    &sidp, flags & ACL_NORESOLVE))
430*7680SMark.Shellenbaum@Sun.COM 				break;
431*7680SMark.Shellenbaum@Sun.COM 			error = str_append(dynstr, sidp);
4327057Smarks 		} else {
4337057Smarks 			if (error = str_append(dynstr, USER_TXT))
4347057Smarks 				break;
4357057Smarks 			error = str_append(dynstr, pruname(acep->a_who, idp,
4367057Smarks 			    sizeof (idp), flags & ACL_NORESOLVE));
4377057Smarks 		}
4387057Smarks 		if (error == 0)
4397057Smarks 			error = str_append(dynstr, ":");
4407057Smarks 		break;
4417057Smarks 	default:
4427057Smarks 		error = 0;
4431420Smarks 		break;
4441420Smarks 	}
4451420Smarks 
4467057Smarks 	if (sidp)
4477057Smarks 		free(sidp);
4487057Smarks 	return (error);
4491420Smarks }
4501420Smarks 
4517057Smarks /*
4527057Smarks  * compute string of permissions, such as read_data/write_data or
4537057Smarks  * rwxp,...
4547057Smarks  * The format depends on the flags field which indicates whether the compact
4557057Smarks  * or verbose format should be used.
4567057Smarks  */
4577057Smarks static int
4587057Smarks ace_perm_txt(dynaclstr_t *dstr, uint32_t mask,
4591420Smarks     uint32_t iflags, int isdir, int flags)
4601420Smarks {
4617057Smarks 	int error = 0;
4621420Smarks 
4631420Smarks 	if (flags & ACL_COMPACT_FMT) {
4647057Smarks 		char buf[16];
465789Sahrens 
4661420Smarks 		if (mask & ACE_READ_DATA)
4671420Smarks 			buf[0] = 'r';
4681420Smarks 		else
4691420Smarks 			buf[0] = '-';
4701420Smarks 		if (mask & ACE_WRITE_DATA)
4711420Smarks 			buf[1] = 'w';
4721420Smarks 		else
4731420Smarks 			buf[1] = '-';
4741420Smarks 		if (mask & ACE_EXECUTE)
4751420Smarks 			buf[2] = 'x';
4761420Smarks 		else
4771420Smarks 			buf[2] = '-';
4781420Smarks 		if (mask & ACE_APPEND_DATA)
4791420Smarks 			buf[3] = 'p';
4801420Smarks 		else
4811420Smarks 			buf[3] = '-';
4821420Smarks 		if (mask & ACE_DELETE)
4831420Smarks 			buf[4] = 'd';
4841420Smarks 		else
4851420Smarks 			buf[4] = '-';
4861420Smarks 		if (mask & ACE_DELETE_CHILD)
4871420Smarks 			buf[5] = 'D';
4881420Smarks 		else
4891420Smarks 			buf[5] = '-';
4901420Smarks 		if (mask & ACE_READ_ATTRIBUTES)
4911420Smarks 			buf[6] = 'a';
4921420Smarks 		else
4931420Smarks 			buf[6] = '-';
4941420Smarks 		if (mask & ACE_WRITE_ATTRIBUTES)
4951420Smarks 			buf[7] = 'A';
4961420Smarks 		else
4971420Smarks 			buf[7] = '-';
4981420Smarks 		if (mask & ACE_READ_NAMED_ATTRS)
4991420Smarks 			buf[8] = 'R';
5001420Smarks 		else
5011420Smarks 			buf[8] = '-';
5021420Smarks 		if (mask & ACE_WRITE_NAMED_ATTRS)
5031420Smarks 			buf[9] = 'W';
5041420Smarks 		else
5051420Smarks 			buf[9] = '-';
5061420Smarks 		if (mask & ACE_READ_ACL)
5071420Smarks 			buf[10] = 'c';
5081420Smarks 		else
5091420Smarks 			buf[10] = '-';
5101420Smarks 		if (mask & ACE_WRITE_ACL)
5111420Smarks 			buf[11] = 'C';
5121420Smarks 		else
5131420Smarks 			buf[11] = '-';
5141420Smarks 		if (mask & ACE_WRITE_OWNER)
5151420Smarks 			buf[12] = 'o';
5161420Smarks 		else
5171420Smarks 			buf[12] = '-';
5181420Smarks 		if (mask & ACE_SYNCHRONIZE)
5191420Smarks 			buf[13] = 's';
5201420Smarks 		else
5211420Smarks 			buf[13] = '-';
5227057Smarks 		buf[14] = ':';
5237057Smarks 		buf[15] = '\0';
5247057Smarks 		error = str_append(dstr, buf);
5251420Smarks 	} else {
5261420Smarks 		/*
5271420Smarks 		 * If ACE is a directory, but inheritance indicates its
5281420Smarks 		 * for a file then print permissions for file rather than
5291420Smarks 		 * dir.
5301420Smarks 		 */
5311420Smarks 		if (isdir) {
5321420Smarks 			if (mask & ACE_LIST_DIRECTORY) {
5331420Smarks 				if (iflags == ACE_FILE_INHERIT_ACE) {
5347057Smarks 					error = str_append(dstr,
5357057Smarks 					    READ_DATA_TXT);
5361420Smarks 				} else {
5377057Smarks 					error =
5387057Smarks 					    str_append(dstr, READ_DIR_TXT);
5391420Smarks 				}
5401420Smarks 			}
5417057Smarks 			if (error == 0 && (mask & ACE_ADD_FILE)) {
5421420Smarks 				if (iflags == ACE_FILE_INHERIT_ACE) {
5437057Smarks 					error =
5447057Smarks 					    str_append(dstr, WRITE_DATA_TXT);
5451420Smarks 				} else {
5467057Smarks 					error =
5477057Smarks 					    str_append(dstr, ADD_FILE_TXT);
5481420Smarks 				}
5491420Smarks 			}
5507057Smarks 			if (error == 0 && (mask & ACE_ADD_SUBDIRECTORY)) {
5511420Smarks 				if (iflags == ACE_FILE_INHERIT_ACE) {
5527057Smarks 					error = str_append(dstr,
5537057Smarks 					    APPEND_DATA_TXT);
5541420Smarks 				} else {
5557057Smarks 					error = str_append(dstr,
5567057Smarks 					    ADD_DIR_TXT);
5571420Smarks 				}
5581420Smarks 			}
5591420Smarks 		} else {
5601420Smarks 			if (mask & ACE_READ_DATA) {
5617057Smarks 				error = str_append(dstr, READ_DATA_TXT);
5621420Smarks 			}
5637057Smarks 			if (error == 0 && (mask & ACE_WRITE_DATA)) {
5647057Smarks 				error = str_append(dstr, WRITE_DATA_TXT);
5651420Smarks 			}
5667057Smarks 			if (error == 0 && (mask & ACE_APPEND_DATA)) {
5677057Smarks 				error = str_append(dstr, APPEND_DATA_TXT);
5681420Smarks 			}
5691420Smarks 		}
5707057Smarks 		if (error == 0 && (mask & ACE_READ_NAMED_ATTRS)) {
5717057Smarks 			error = str_append(dstr, READ_XATTR_TXT);
5721420Smarks 		}
5737057Smarks 		if (error == 0 && (mask & ACE_WRITE_NAMED_ATTRS)) {
5747057Smarks 			error = str_append(dstr, WRITE_XATTR_TXT);
5751420Smarks 		}
5767057Smarks 		if (error == 0 && (mask & ACE_EXECUTE)) {
5777057Smarks 			error = str_append(dstr, EXECUTE_TXT);
5781420Smarks 		}
5797057Smarks 		if (error == 0 && (mask & ACE_DELETE_CHILD)) {
5807057Smarks 			error = str_append(dstr, DELETE_CHILD_TXT);
5811420Smarks 		}
5827057Smarks 		if (error == 0 && (mask & ACE_READ_ATTRIBUTES)) {
5837057Smarks 			error = str_append(dstr, READ_ATTRIBUTES_TXT);
5841420Smarks 		}
5857057Smarks 		if (error == 0 && (mask & ACE_WRITE_ATTRIBUTES)) {
5867057Smarks 			error = str_append(dstr, WRITE_ATTRIBUTES_TXT);
5871420Smarks 		}
5887057Smarks 		if (error == 0 && (mask & ACE_DELETE)) {
5897057Smarks 			error = str_append(dstr, DELETE_TXT);
5901420Smarks 		}
5917057Smarks 		if (error == 0 && (mask & ACE_READ_ACL)) {
5927057Smarks 			error = str_append(dstr, READ_ACL_TXT);
5931420Smarks 		}
5947057Smarks 		if (error == 0 && (mask & ACE_WRITE_ACL)) {
5957057Smarks 			error = str_append(dstr, WRITE_ACL_TXT);
5961420Smarks 		}
5977057Smarks 		if (error == 0 && (mask & ACE_WRITE_OWNER)) {
5987057Smarks 			error = str_append(dstr, WRITE_OWNER_TXT);
5991420Smarks 		}
6007057Smarks 		if (error == 0 && (mask & ACE_SYNCHRONIZE)) {
6017057Smarks 			error = str_append(dstr, SYNCHRONIZE_TXT);
6021420Smarks 		}
6037057Smarks 		if (error == 0 && dstr->d_aclexport[dstr->d_pos-1] == '/') {
6047057Smarks 			dstr->d_aclexport[--dstr->d_pos] = '\0';
6057057Smarks 		}
6067057Smarks 		if (error == 0)
6077057Smarks 			error = str_append(dstr, ":");
6081420Smarks 	}
6097057Smarks 	return (error);
6101420Smarks }
6111420Smarks 
6127057Smarks /*
6137057Smarks  * compute string of access type, such as allow, deny, ...
6147057Smarks  */
6157057Smarks static int
6167057Smarks ace_access_txt(dynaclstr_t *dstr, int type)
6171420Smarks {
6187057Smarks 	int error;
6191420Smarks 
6207057Smarks 	if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
6217057Smarks 		error = str_append(dstr, ALLOW_TXT);
6227057Smarks 	else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
6237057Smarks 		error = str_append(dstr, DENY_TXT);
6247057Smarks 	else if (type == ACE_SYSTEM_AUDIT_ACE_TYPE)
6257057Smarks 		error = str_append(dstr, AUDIT_TXT);
6267057Smarks 	else if (type == ACE_SYSTEM_ALARM_ACE_TYPE)
6277057Smarks 		error = str_append(dstr, ALARM_TXT);
6287057Smarks 	else
6297057Smarks 		error = str_append(dstr, UNKNOWN_TXT);
6301420Smarks 
6317057Smarks 	return (error);
6321420Smarks }
6331420Smarks 
6347057Smarks static int
6357057Smarks ace_inherit_txt(dynaclstr_t *dstr, uint32_t iflags, int flags)
6361420Smarks {
6377057Smarks 	int error = 0;
638789Sahrens 
6391420Smarks 	if (flags & ACL_COMPACT_FMT) {
6407057Smarks 		char buf[9];
6417057Smarks 
6421420Smarks 		if (iflags & ACE_FILE_INHERIT_ACE)
6431420Smarks 			buf[0] = 'f';
6441420Smarks 		else
6451420Smarks 			buf[0] = '-';
6461420Smarks 		if (iflags & ACE_DIRECTORY_INHERIT_ACE)
6471420Smarks 			buf[1] = 'd';
6481420Smarks 		else
6491420Smarks 			buf[1] = '-';
6501420Smarks 		if (iflags & ACE_INHERIT_ONLY_ACE)
6511420Smarks 			buf[2] = 'i';
6521420Smarks 		else
6531420Smarks 			buf[2] = '-';
6541420Smarks 		if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)
6551420Smarks 			buf[3] = 'n';
6561420Smarks 		else
6571420Smarks 			buf[3] = '-';
6581420Smarks 		if (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
6591420Smarks 			buf[4] = 'S';
6601420Smarks 		else
6611420Smarks 			buf[4] = '-';
6621420Smarks 		if (iflags & ACE_FAILED_ACCESS_ACE_FLAG)
6631420Smarks 			buf[5] = 'F';
6641420Smarks 		else
6651420Smarks 			buf[5] = '-';
6665331Samw 		if (iflags & ACE_INHERITED_ACE)
6675331Samw 			buf[6] = 'I';
6685331Samw 		else
6695331Samw 			buf[6] = '-';
6707057Smarks 		buf[7] = ':';
6717057Smarks 		buf[8] = '\0';
6727057Smarks 		error = str_append(dstr, buf);
6731420Smarks 	} else {
6741420Smarks 		if (iflags & ACE_FILE_INHERIT_ACE) {
6757057Smarks 			error = str_append(dstr, FILE_INHERIT_TXT);
6761420Smarks 		}
6777057Smarks 		if (error == 0 && (iflags & ACE_DIRECTORY_INHERIT_ACE)) {
6787057Smarks 			error = str_append(dstr, DIR_INHERIT_TXT);
6791420Smarks 		}
6807057Smarks 		if (error == 0 && (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)) {
6817057Smarks 			error = str_append(dstr, NO_PROPAGATE_TXT);
6821420Smarks 		}
6837057Smarks 		if (error == 0 && (iflags & ACE_INHERIT_ONLY_ACE)) {
6847057Smarks 			error = str_append(dstr, INHERIT_ONLY_TXT);
6851420Smarks 		}
6867057Smarks 		if (error == 0 && (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)) {
6877057Smarks 			error = str_append(dstr, SUCCESSFUL_ACCESS_TXT);
6885331Samw 		}
6897057Smarks 		if (error == 0 && (iflags & ACE_FAILED_ACCESS_ACE_FLAG)) {
6907057Smarks 			error = str_append(dstr, FAILED_ACCESS_TXT);
6915331Samw 		}
6927057Smarks 		if (error == 0 && (iflags & ACE_INHERITED_ACE)) {
6937057Smarks 			error = str_append(dstr, INHERITED_ACE_TXT);
6945331Samw 		}
6957057Smarks 		if (error == 0 && dstr->d_aclexport[dstr->d_pos-1] == '/') {
6967057Smarks 			dstr->d_aclexport[--dstr->d_pos] = '\0';
6977057Smarks 			error = str_append(dstr, ":");
6987057Smarks 		}
6991420Smarks 	}
7001420Smarks 
7017057Smarks 	return (error);
702789Sahrens }
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate /*
7050Sstevel@tonic-gate  * Convert internal acl representation to external representation.
7060Sstevel@tonic-gate  *
7070Sstevel@tonic-gate  * The length of a non-owning user name or non-owning group name ie entries
7080Sstevel@tonic-gate  * of type DEF_USER, USER, DEF_GROUP or GROUP, can exceed LOGNAME_MAX.  We
7090Sstevel@tonic-gate  * thus check the length of these entries, and if greater than LOGNAME_MAX,
7100Sstevel@tonic-gate  * we realloc() via increase_length().
7110Sstevel@tonic-gate  *
7120Sstevel@tonic-gate  * The LOGNAME_MAX, ENTRYTYPELEN and PERMS limits are otherwise always
7130Sstevel@tonic-gate  * adhered to.
7140Sstevel@tonic-gate  */
7151420Smarks 
7161420Smarks /*
7171420Smarks  * acltotext() converts each ACL entry to look like this:
7181420Smarks  *
7191420Smarks  *    entry_type:uid^gid^name:perms[:id]
7201420Smarks  *
7211420Smarks  * The maximum length of entry_type is 14 ("defaultgroup::" and
7221420Smarks  * "defaultother::") hence ENTRYTYPELEN is set to 14.
7231420Smarks  *
7241420Smarks  * The max length of a uid^gid^name entry (in theory) is 8, hence we use,
7251420Smarks  * however the ID could be a number so we therefore use ID_STR_MAX
7261420Smarks  *
7271420Smarks  * The length of a perms entry is 4 to allow for the comma appended to each
7281420Smarks  * to each acl entry.  Hence PERMS is set to 4.
7291420Smarks  */
7301420Smarks 
7311420Smarks #define	ENTRYTYPELEN	14
7321420Smarks #define	PERMS		4
7331420Smarks #define	ACL_ENTRY_SIZE	(ENTRYTYPELEN + ID_STR_MAX + PERMS + APPENDED_ID_MAX)
7341420Smarks 
7350Sstevel@tonic-gate char *
7361420Smarks aclent_acltotext(aclent_t  *aclp, int aclcnt, int flags)
7370Sstevel@tonic-gate {
7387057Smarks 	dynaclstr_t 	*dstr;
739*7680SMark.Shellenbaum@Sun.COM 	char		*aclexport = NULL;
7407057Smarks 	int		i;
7417057Smarks 	int 		error = 0;
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	if (aclp == NULL)
7440Sstevel@tonic-gate 		return (NULL);
7457057Smarks 	if ((dstr = malloc(sizeof (dynaclstr_t))) == NULL)
7460Sstevel@tonic-gate 		return (NULL);
7477057Smarks 	dstr->d_bufsize = aclcnt * ACL_ENTRY_SIZE;
7487057Smarks 	if ((dstr->d_aclexport = malloc(dstr->d_bufsize)) == NULL) {
7490Sstevel@tonic-gate 		free(dstr);
7500Sstevel@tonic-gate 		return (NULL);
7510Sstevel@tonic-gate 	}
7527057Smarks 	*dstr->d_aclexport = '\0';
7537057Smarks 	dstr->d_pos = 0;
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	for (i = 0; i < aclcnt; i++, aclp++) {
7567057Smarks 		if (error = aclent_type_txt(dstr, aclp, flags))
7570Sstevel@tonic-gate 			break;
7587057Smarks 		if (error = aclent_perm_txt(dstr, aclp->a_perm))
7590Sstevel@tonic-gate 			break;
7601420Smarks 
7611420Smarks 		if ((flags & ACL_APPEND_ID) && ((aclp->a_type == USER) ||
7621420Smarks 		    (aclp->a_type == DEF_USER) || (aclp->a_type == GROUP) ||
7631420Smarks 		    (aclp->a_type == DEF_GROUP))) {
7647057Smarks 			char id[ID_STR_MAX], *idstr;
7657057Smarks 
7667057Smarks 			if (error = str_append(dstr, ":"))
7677057Smarks 				break;
7681420Smarks 			id[ID_STR_MAX - 1] = '\0'; /* null terminate buffer */
7691420Smarks 			idstr = lltostr(aclp->a_id, &id[ID_STR_MAX - 1]);
7707057Smarks 			if (error = str_append(dstr, idstr))
7717057Smarks 				break;
7721420Smarks 		}
7730Sstevel@tonic-gate 		if (i < aclcnt - 1)
7747057Smarks 			if (error = str_append(dstr, ","))
7757057Smarks 				break;
7760Sstevel@tonic-gate 	}
7777057Smarks 	if (error) {
7787057Smarks 		if (dstr->d_aclexport)
7797057Smarks 			free(dstr->d_aclexport);
7807057Smarks 	} else {
7817057Smarks 		aclexport = dstr->d_aclexport;
7827057Smarks 	}
7830Sstevel@tonic-gate 	free(dstr);
7840Sstevel@tonic-gate 	return (aclexport);
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate 
7871420Smarks char *
7881420Smarks acltotext(aclent_t *aclp, int aclcnt)
7890Sstevel@tonic-gate {
7901420Smarks 	return (aclent_acltotext(aclp, aclcnt, 0));
7911420Smarks }
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 
794789Sahrens aclent_t *
795789Sahrens aclfromtext(char *aclstr, int *aclcnt)
796789Sahrens {
797789Sahrens 	acl_t *aclp;
798789Sahrens 	aclent_t *aclentp;
799789Sahrens 	int error;
800789Sahrens 
8011420Smarks 	error = acl_fromtext(aclstr, &aclp);
802789Sahrens 	if (error)
803789Sahrens 		return (NULL);
804789Sahrens 
805789Sahrens 	aclentp = aclp->acl_aclp;
806789Sahrens 	aclp->acl_aclp = NULL;
8071420Smarks 	*aclcnt = aclp->acl_cnt;
808789Sahrens 
8091420Smarks 	acl_free(aclp);
810789Sahrens 	return (aclentp);
811789Sahrens }
812789Sahrens 
813789Sahrens 
8147057Smarks /*
815*7680SMark.Shellenbaum@Sun.COM  * Append string onto dynaclstr_t.
816*7680SMark.Shellenbaum@Sun.COM  *
817*7680SMark.Shellenbaum@Sun.COM  * Return 0 on success, 1 for failure.
8187057Smarks  */
8197057Smarks static int
8207057Smarks str_append(dynaclstr_t *dstr, char *newstr)
8210Sstevel@tonic-gate {
8227057Smarks 	size_t len = strlen(newstr);
8237057Smarks 
8247057Smarks 	if ((len + dstr->d_pos) >= dstr->d_bufsize) {
8257057Smarks 		dstr->d_aclexport = realloc(dstr->d_aclexport,
8267057Smarks 		    dstr->d_bufsize + len + 1);
8277057Smarks 		if (dstr->d_aclexport == NULL)
8287057Smarks 			return (1);
8297057Smarks 		dstr->d_bufsize += len;
8307057Smarks 	}
8317057Smarks 	(void) strcat(&dstr->d_aclexport[dstr->d_pos], newstr);
8327057Smarks 	dstr->d_pos += len;
8337057Smarks 	return (0);
8340Sstevel@tonic-gate }
8350Sstevel@tonic-gate 
8367057Smarks static int
8377057Smarks aclent_perm_txt(dynaclstr_t *dstr, o_mode_t perm)
8380Sstevel@tonic-gate {
8397057Smarks 	char buf[4];
8400Sstevel@tonic-gate 
8417057Smarks 	if (perm & S_IROTH)
8427057Smarks 		buf[0] = 'r';
8437057Smarks 	else
8447057Smarks 		buf[0] = '-';
8457057Smarks 	if (perm & S_IWOTH)
8467057Smarks 		buf[1] = 'w';
8477057Smarks 	else
8487057Smarks 		buf[1] = '-';
8497057Smarks 	if (perm & S_IXOTH)
8507057Smarks 		buf[2] = 'x';
8517057Smarks 	else
8527057Smarks 		buf[2] = '-';
8537057Smarks 	buf[3] = '\0';
8547057Smarks 	return (str_append(dstr, buf));
8550Sstevel@tonic-gate }
856789Sahrens 
857789Sahrens /*
8581420Smarks  * ace_acltotext() convert each ace formatted acl to look like this:
859789Sahrens  *
8601420Smarks  * entry_type:uid^gid^name:perms[:flags]:<allow|deny>[:id][,]
861789Sahrens  *
862789Sahrens  * The maximum length of entry_type is 5 ("group")
863789Sahrens  *
8641420Smarks  * The max length of a uid^gid^name entry (in theory) is 8,
8651420Smarks  * however id could be a number so we therefore use ID_STR_MAX
866789Sahrens  *
867789Sahrens  * The length of a perms entry is 144 i.e read_data/write_data...
868789Sahrens  * to each acl entry.
869789Sahrens  *
8705331Samw  * iflags: file_inherit/dir_inherit/inherit_only/no_propagate/successful_access
8715331Samw  *         /failed_access
872789Sahrens  *
873789Sahrens  */
874789Sahrens 
875789Sahrens #define	ACE_ENTRYTYPLEN		6
8765331Samw #define	IFLAGS_STR "file_inherit/dir_inherit/inherit_only/no_propagate/" \
8775331Samw 	"successful_access/failed_access/inherited"
8785331Samw #define	IFLAGS_SIZE		(sizeof (IFLAGS_STR) - 1)
8791420Smarks #define	ACCESS_TYPE_SIZE	7	/* if unknown */
880789Sahrens #define	COLON_CNT		3
881789Sahrens #define	PERMS_LEN		216
8825331Samw #define	ACE_ENTRY_SIZE	(ACE_ENTRYTYPLEN + ID_STR_MAX + PERMS_LEN + \
8831420Smarks     ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT + APPENDED_ID_MAX)
884789Sahrens 
885789Sahrens static char *
8861420Smarks ace_acltotext(acl_t *aceaclp, int flags)
887789Sahrens {
888789Sahrens 	ace_t		*aclp = aceaclp->acl_aclp;
889789Sahrens 	int		aclcnt = aceaclp->acl_cnt;
8907057Smarks 	int		i;
8917057Smarks 	int		error = 0;
8927057Smarks 	int		isdir = (aceaclp->acl_flags & ACL_IS_DIR);
8937057Smarks 	dynaclstr_t 	*dstr;
894*7680SMark.Shellenbaum@Sun.COM 	char		*aclexport = NULL;
895789Sahrens 
896789Sahrens 	if (aclp == NULL)
897789Sahrens 		return (NULL);
898789Sahrens 
8997057Smarks 	if ((dstr = malloc(sizeof (dynaclstr_t))) == NULL)
9007057Smarks 		return (NULL);
9017057Smarks 	dstr->d_bufsize = aclcnt * ACL_ENTRY_SIZE;
9027057Smarks 	if ((dstr->d_aclexport = malloc(dstr->d_bufsize)) == NULL) {
9037057Smarks 		free(dstr);
9047057Smarks 		return (NULL);
9057057Smarks 	}
9067057Smarks 	*dstr->d_aclexport = '\0';
9077057Smarks 	dstr->d_pos = 0;
9087057Smarks 
909789Sahrens 	for (i = 0; i < aclcnt; i++, aclp++) {
9101420Smarks 
9117057Smarks 		if (error = ace_type_txt(dstr, aclp, flags))
9127057Smarks 			break;
9137057Smarks 		if (error = ace_perm_txt(dstr, aclp->a_access_mask,
9147057Smarks 		    aclp->a_flags, isdir, flags))
9157057Smarks 			break;
9167057Smarks 		if (error = ace_inherit_txt(dstr, aclp->a_flags, flags))
9177057Smarks 			break;
9187057Smarks 		if (error = ace_access_txt(dstr, aclp->a_type))
9197057Smarks 			break;
920789Sahrens 
9211420Smarks 		if ((flags & ACL_APPEND_ID) &&
9221420Smarks 		    (((aclp->a_flags & ACE_TYPE_FLAGS) == 0) ||
9231420Smarks 		    ((aclp->a_flags & ACE_TYPE_FLAGS) ==
9241420Smarks 		    ACE_IDENTIFIER_GROUP))) {
9257057Smarks 			char id[ID_STR_MAX], *idstr;
9267057Smarks 
9277057Smarks 			if (error = str_append(dstr, ":"))
9287057Smarks 				break;
9291420Smarks 			id[ID_STR_MAX -1] = '\0'; /* null terminate buffer */
9307057Smarks 			idstr = lltostr((aclp->a_who > MAXUID &&
9317057Smarks 			    !(flags & ACL_NORESOLVE)) ? UID_NOBODY :
9327057Smarks 			    aclp->a_who, &id[ID_STR_MAX - 1]);
9337057Smarks 			if (error = str_append(dstr, idstr))
9347057Smarks 				break;
935789Sahrens 		}
9361420Smarks 		if (i < aclcnt - 1) {
9377057Smarks 			if (error = str_append(dstr, ","))
9387057Smarks 				break;
939789Sahrens 		}
940789Sahrens 	}
9417057Smarks 	if (error) {
9427057Smarks 		if (dstr->d_aclexport)
9437057Smarks 			free(dstr->d_aclexport);
9447057Smarks 	} else {
9457057Smarks 		aclexport = dstr->d_aclexport;
9467057Smarks 	}
9477057Smarks 	free(dstr);
948789Sahrens 	return (aclexport);
949789Sahrens }
950789Sahrens 
9511420Smarks char *
9521420Smarks acl_totext(acl_t *aclp, int flags)
953789Sahrens {
9541420Smarks 	char *txtp;
955789Sahrens 
956789Sahrens 	if (aclp == NULL)
957789Sahrens 		return (NULL);
958789Sahrens 
959789Sahrens 	switch (aclp->acl_type) {
960789Sahrens 	case ACE_T:
9611420Smarks 		txtp = ace_acltotext(aclp, flags);
9621420Smarks 		break;
963789Sahrens 	case ACLENT_T:
9641420Smarks 		txtp = aclent_acltotext(aclp->acl_aclp, aclp->acl_cnt, flags);
9651420Smarks 		break;
966789Sahrens 	}
9671420Smarks 
9681420Smarks 	return (txtp);
969789Sahrens }
970789Sahrens 
971789Sahrens int
972789Sahrens acl_fromtext(const char *acltextp, acl_t **ret_aclp)
973789Sahrens {
9741420Smarks 	int error;
9751420Smarks 	char *buf;
9761420Smarks 
9771420Smarks 	buf = malloc(strlen(acltextp) + 2);
9781420Smarks 	if (buf == NULL)
9791420Smarks 		return (EACL_MEM_ERROR);
9801420Smarks 	strcpy(buf, acltextp);
9811420Smarks 	strcat(buf, "\n");
9821420Smarks 	yybuf = buf;
9831420Smarks 	yyreset();
9841420Smarks 	error = yyparse();
9851420Smarks 	free(buf);
9861420Smarks 
9871420Smarks 	if (yyacl) {
9881420Smarks 		if (error == 0)
9891420Smarks 			*ret_aclp = yyacl;
9901420Smarks 		else {
9911420Smarks 			acl_free(yyacl);
9921420Smarks 		}
9931420Smarks 		yyacl = NULL;
9941420Smarks 	}
9951420Smarks 	return (error);
9961420Smarks }
9971420Smarks 
9981420Smarks int
9991420Smarks acl_parse(const char *acltextp, acl_t **aclp)
10001420Smarks {
1001789Sahrens 	int error;
1002789Sahrens 
10031420Smarks 	yyinteractive = 1;
10041420Smarks 	error = acl_fromtext(acltextp, aclp);
10051420Smarks 	yyinteractive = 0;
10061420Smarks 	return (error);
10071420Smarks }
10081420Smarks 
10091420Smarks static void
10101420Smarks ace_compact_printacl(acl_t *aclp)
10111420Smarks {
10121420Smarks 	int cnt;
10131420Smarks 	ace_t *acep;
10147057Smarks 	dynaclstr_t *dstr;
10157057Smarks 	int len;
1016789Sahrens 
10177057Smarks 	if ((dstr = malloc(sizeof (dynaclstr_t))) == NULL)
10187057Smarks 		return;
10197057Smarks 	dstr->d_bufsize = ACE_ENTRY_SIZE;
10207057Smarks 	if ((dstr->d_aclexport = malloc(dstr->d_bufsize)) == NULL) {
10217057Smarks 		free(dstr);
10227057Smarks 		return;
10237057Smarks 	}
10247057Smarks 	*dstr->d_aclexport = '\0';
10257057Smarks 
10267057Smarks 	dstr->d_pos = 0;
10271420Smarks 	for (cnt = 0, acep = aclp->acl_aclp;
10281420Smarks 	    cnt != aclp->acl_cnt; cnt++, acep++) {
10297057Smarks 		dstr->d_aclexport[0] = '\0';
10307057Smarks 		dstr->d_pos = 0;
10317057Smarks 
10327057Smarks 		if (ace_type_txt(dstr, acep, 0))
10337057Smarks 			break;
10347057Smarks 		len = strlen(&dstr->d_aclexport[0]);
10357057Smarks 		if (ace_perm_txt(dstr, acep->a_access_mask, acep->a_flags,
10367057Smarks 		    aclp->acl_flags & ACL_IS_DIR, ACL_COMPACT_FMT))
10377057Smarks 			break;
10387057Smarks 		if (ace_inherit_txt(dstr, acep->a_flags, ACL_COMPACT_FMT))
10397057Smarks 			break;
10407057Smarks 		if (ace_access_txt(dstr, acep->a_type) == -1)
10417057Smarks 			break;
10427057Smarks 		(void) printf("    %20.*s%s\n", len, dstr->d_aclexport,
10437057Smarks 		    &dstr->d_aclexport[len]);
10441420Smarks 	}
10457057Smarks 
10467057Smarks 	if (dstr->d_aclexport)
10477057Smarks 		free(dstr->d_aclexport);
10487057Smarks 	free(dstr);
10491420Smarks }
1050789Sahrens 
10511420Smarks static void
10521420Smarks ace_printacl(acl_t *aclp, int cols, int compact)
10531420Smarks {
10541420Smarks 	int  slot = 0;
10551420Smarks 	char *token;
10561420Smarks 	char *acltext;
10571420Smarks 
10581420Smarks 	if (compact) {
10591420Smarks 		ace_compact_printacl(aclp);
10601420Smarks 		return;
1061789Sahrens 	}
1062789Sahrens 
10631420Smarks 	acltext = acl_totext(aclp, 0);
10641420Smarks 
10651420Smarks 	if (acltext == NULL)
10661420Smarks 		return;
10671420Smarks 
10681420Smarks 	token = strtok(acltext, ",");
10691420Smarks 	if (token == NULL) {
10701420Smarks 		free(acltext);
10711420Smarks 		return;
1072789Sahrens 	}
1073789Sahrens 
10741420Smarks 	do {
10751420Smarks 		(void) printf("     %d:", slot++);
10761420Smarks 		split_line(token, cols - 5);
10771420Smarks 	} while (token = strtok(NULL, ","));
10781420Smarks 	free(acltext);
10791420Smarks }
10801420Smarks 
10811420Smarks /*
10821420Smarks  * pretty print an ACL.
10831420Smarks  * For aclent_t ACL's the format is
10841420Smarks  * similar to the old format used by getfacl,
10851420Smarks  * with the addition of adding a "slot" number
10861420Smarks  * before each entry.
10871420Smarks  *
10881420Smarks  * for ace_t ACL's the cols variable will break up
10891420Smarks  * the long lines into multiple lines and will also
10901420Smarks  * print a "slot" number.
10911420Smarks  */
10921420Smarks void
10931420Smarks acl_printacl(acl_t *aclp, int cols, int compact)
10941420Smarks {
10951420Smarks 
10961420Smarks 	switch (aclp->acl_type) {
10971420Smarks 	case ACLENT_T:
10981420Smarks 		aclent_printacl(aclp);
10991420Smarks 		break;
11001420Smarks 	case ACE_T:
11011420Smarks 		ace_printacl(aclp, cols, compact);
11021420Smarks 		break;
11031420Smarks 	}
11041420Smarks }
11051420Smarks 
11061420Smarks typedef struct value_table {
11071420Smarks 	char		p_letter; /* perm letter such as 'r' */
11081420Smarks 	uint32_t	p_value; /* value for perm when pletter found */
11091420Smarks } value_table_t;
11101420Smarks 
11111420Smarks /*
11125331Samw  * The permission tables are laid out in positional order
11131420Smarks  * a '-' character will indicate a permission at a given
11141420Smarks  * position is not specified.  The '-' is not part of the
11151420Smarks  * table, but will be checked for in the permission computation
11161420Smarks  * routine.
11171420Smarks  */
11185331Samw value_table_t ace_perm_table[] = {
11191420Smarks 	{ 'r', ACE_READ_DATA},
11201420Smarks 	{ 'w', ACE_WRITE_DATA},
11211420Smarks 	{ 'x', ACE_EXECUTE},
11221420Smarks 	{ 'p', ACE_APPEND_DATA},
11231420Smarks 	{ 'd', ACE_DELETE},
11241420Smarks 	{ 'D', ACE_DELETE_CHILD},
11251420Smarks 	{ 'a', ACE_READ_ATTRIBUTES},
11261420Smarks 	{ 'A', ACE_WRITE_ATTRIBUTES},
11271420Smarks 	{ 'R', ACE_READ_NAMED_ATTRS},
11281420Smarks 	{ 'W', ACE_WRITE_NAMED_ATTRS},
11291420Smarks 	{ 'c', ACE_READ_ACL},
11301420Smarks 	{ 'C', ACE_WRITE_ACL},
11311420Smarks 	{ 'o', ACE_WRITE_OWNER},
11321420Smarks 	{ 's', ACE_SYNCHRONIZE}
11331420Smarks };
11341420Smarks 
11355331Samw #define	ACE_PERM_COUNT (sizeof (ace_perm_table) / sizeof (value_table_t))
11361420Smarks 
11375331Samw value_table_t aclent_perm_table[] = {
11381420Smarks 	{ 'r', S_IROTH},
11391420Smarks 	{ 'w', S_IWOTH},
11401420Smarks 	{ 'x', S_IXOTH}
11411420Smarks };
11421420Smarks 
11435331Samw #define	ACLENT_PERM_COUNT (sizeof (aclent_perm_table) / sizeof (value_table_t))
11445331Samw 
11455331Samw value_table_t inherit_table[] = {
11461420Smarks 	{'f', ACE_FILE_INHERIT_ACE},
11471420Smarks 	{'d', ACE_DIRECTORY_INHERIT_ACE},
11481420Smarks 	{'i', ACE_INHERIT_ONLY_ACE},
11491420Smarks 	{'n', ACE_NO_PROPAGATE_INHERIT_ACE},
11501420Smarks 	{'S', ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
11515331Samw 	{'F', ACE_FAILED_ACCESS_ACE_FLAG},
11525331Samw 	{'I', ACE_INHERITED_ACE}
11531420Smarks };
11541420Smarks 
11555331Samw #define	IFLAG_COUNT (sizeof (inherit_table) / sizeof (value_table_t))
11566269Smarks #define	IFLAG_COUNT_V1 6 /* Older version compatibility */
11575331Samw 
11581420Smarks /*
11591420Smarks  * compute value from a permission table or inheritance table
11601420Smarks  * based on string passed in.  If positional is set then
11611420Smarks  * string must match order in permtab, otherwise any order
11621420Smarks  * is allowed.
11631420Smarks  */
11641420Smarks int
11651420Smarks compute_values(value_table_t *permtab, int count,
11661420Smarks     char *permstr, int positional, uint32_t *mask)
11671420Smarks {
11681420Smarks 	uint32_t perm_val = 0;
11691420Smarks 	char *pstr;
11701420Smarks 	int i, found;
11711420Smarks 
11721420Smarks 	if (count < 0)
11731420Smarks 		return (1);
11741420Smarks 
11751420Smarks 	if (positional) {
11761420Smarks 		for (i = 0, pstr = permstr; i != count && pstr &&
11771420Smarks 		    *pstr; i++, pstr++) {
11781420Smarks 			if (*pstr == permtab[i].p_letter) {
11791420Smarks 				perm_val |= permtab[i].p_value;
11801420Smarks 			} else if (*pstr != '-') {
11811420Smarks 				return (1);
11821420Smarks 			}
1183789Sahrens 		}
11841420Smarks 	} else {  /* random order single letters with no '-' */
11851420Smarks 		for (pstr = permstr; pstr && *pstr; pstr++) {
11861420Smarks 			for (found = 0, i = 0; i != count; i++) {
11871420Smarks 				if (*pstr == permtab[i].p_letter) {
11881420Smarks 					perm_val |= permtab[i].p_value;
11891420Smarks 					found = 1;
11901420Smarks 					break;
11911420Smarks 				}
11921420Smarks 			}
11931420Smarks 			if (found == 0)
11941420Smarks 				return (1);
11951420Smarks 		}
1196789Sahrens 	}
1197789Sahrens 
11981420Smarks 	*mask = perm_val;
11991420Smarks 	return (0);
12001420Smarks }
1201789Sahrens 
12026269Smarks 
12036269Smarks int
12046269Smarks ace_inherit_helper(char *str, uint32_t *imask, int table_length)
12056269Smarks {
12066269Smarks 	int rc = 0;
12076269Smarks 
12086269Smarks 	if (strlen(str) == table_length) {
12096269Smarks 		/*
12106269Smarks 		 * If the string == table_length then first check to see it's
12116269Smarks 		 * in positional format.  If that fails then see if it's in
12126269Smarks 		 * non-positional format.
12136269Smarks 		 */
12146269Smarks 		if (compute_values(inherit_table, table_length, str,
12156269Smarks 		    1, imask) && compute_values(inherit_table,
12166269Smarks 		    table_length, str, 0, imask)) {
12176269Smarks 			rc = 1;
12186269Smarks 		}
12196269Smarks 	} else {
12206269Smarks 		rc = compute_values(inherit_table, table_length, str, 0, imask);
12216269Smarks 	}
12226269Smarks 
12236269Smarks 	return (rc ? EACL_INHERIT_ERROR : 0);
12246269Smarks }
12256269Smarks 
12261420Smarks /*
12271420Smarks  * compute value for inheritance flags.
12281420Smarks  */
12291420Smarks int
12301420Smarks compute_ace_inherit(char *str, uint32_t *imask)
12311420Smarks {
12326269Smarks 	int rc = 0;
1233789Sahrens 
12346269Smarks 	rc = ace_inherit_helper(str, imask, IFLAG_COUNT);
12356269Smarks 
12366269Smarks 	if (rc && strlen(str) != IFLAG_COUNT) {
12371420Smarks 
12386269Smarks 		/* is it an old formatted inherit string? */
12396269Smarks 		rc = ace_inherit_helper(str, imask, IFLAG_COUNT_V1);
12406269Smarks 	}
12411420Smarks 
12426269Smarks 	return (rc);
1243789Sahrens }
12441420Smarks 
12451420Smarks 
12461420Smarks /*
12471420Smarks  * compute value for ACE permissions.
12481420Smarks  */
12491420Smarks int
12501420Smarks compute_ace_perms(char *str, uint32_t *mask)
12511420Smarks {
12521420Smarks 	int positional = 0;
12531420Smarks 	int error;
12541420Smarks 
12551420Smarks 	if (strlen(str) == ACE_PERM_COUNT)
12561420Smarks 		positional = 1;
12571420Smarks 
12581420Smarks 	error = compute_values(ace_perm_table, ACE_PERM_COUNT,
12591420Smarks 	    str, positional, mask);
12601420Smarks 
12611420Smarks 	if (error && positional) {
12621420Smarks 		/*
12631420Smarks 		 * If positional was set, then make sure permissions
12641420Smarks 		 * aren't actually valid in non positional case where
12651420Smarks 		 * all permissions are specified, just in random order.
12661420Smarks 		 */
12671420Smarks 		error = compute_values(ace_perm_table,
12681420Smarks 		    ACE_PERM_COUNT, str, 0, mask);
12691420Smarks 	}
12701420Smarks 	if (error)
12711420Smarks 		error = EACL_PERM_MASK_ERROR;
12721420Smarks 
12731420Smarks 	return (error);
12741420Smarks }
12751420Smarks 
12761420Smarks 
12771420Smarks 
12781420Smarks /*
12791420Smarks  * compute values for aclent permissions.
12801420Smarks  */
12811420Smarks int
12821420Smarks compute_aclent_perms(char *str, o_mode_t *mask)
12831420Smarks {
12841420Smarks 	int error;
12851420Smarks 	uint32_t pmask;
12861420Smarks 
12871420Smarks 	if (strlen(str) != ACLENT_PERM_COUNT)
12881420Smarks 		return (EACL_PERM_MASK_ERROR);
12891420Smarks 
12901420Smarks 	*mask = 0;
12911420Smarks 	error = compute_values(aclent_perm_table, ACLENT_PERM_COUNT,
12921420Smarks 	    str, 1, &pmask);
12931420Smarks 	if (error == 0) {
12941420Smarks 		*mask = (o_mode_t)pmask;
12951420Smarks 	} else
12961420Smarks 		error = EACL_PERM_MASK_ERROR;
12971420Smarks 	return (error);
12981420Smarks }
12991420Smarks 
13001420Smarks /*
13011420Smarks  * determine ACE permissions.
13021420Smarks  */
13031420Smarks int
13041420Smarks ace_perm_mask(struct acl_perm_type *aclperm, uint32_t *mask)
13051420Smarks {
13061420Smarks 	int error;
13071420Smarks 
13081420Smarks 	if (aclperm->perm_style == PERM_TYPE_EMPTY) {
13091420Smarks 		*mask = 0;
13101420Smarks 		return (0);
13111420Smarks 	}
13121420Smarks 
13131420Smarks 	if (aclperm->perm_style == PERM_TYPE_ACE) {
13141420Smarks 		*mask = aclperm->perm_val;
13151420Smarks 		return (0);
13161420Smarks 	}
13171420Smarks 
13181420Smarks 	error = compute_ace_perms(aclperm->perm_str, mask);
13191420Smarks 	if (error) {
13201567Smarks 		acl_error(dgettext(TEXT_DOMAIN,
13211567Smarks 		    "Invalid permission(s) '%s' specified\n"),
13221420Smarks 		    aclperm->perm_str);
13231420Smarks 		return (EACL_PERM_MASK_ERROR);
13241420Smarks 	}
13251420Smarks 
13261420Smarks 	return (0);
13271420Smarks }
1328