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 
1187057Smarks static char *
1197057Smarks prsidname(uid_t who, boolean_t user, char **sidp, int 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;
1257057Smarks 	int error = 1;
1267057Smarks 	int len;
1277057Smarks 	char *domain;
1287057Smarks 	char *name;
1297057Smarks 
1307057Smarks 	if (noresolve) {
1317057Smarks 		len = snprintf(NULL, 0, "%u", who);
1327057Smarks 		*sidp = malloc(len + 1);
1337057Smarks 		(void) snprintf(*sidp, len + 1, "%u", who);
1347057Smarks 		return (*sidp);
1357057Smarks 	}
1367057Smarks 
1377057Smarks 	/*
1387057Smarks 	 * First try and get windows name
1397057Smarks 	 */
1407057Smarks 
1417057Smarks 	if (user)
142*7369SJulian.Pullen@Sun.COM 		error = idmap_getwinnamebyuid(who, IDMAP_REQ_FLG_USE_CACHE,
143*7369SJulian.Pullen@Sun.COM 		    &name, &domain);
1447057Smarks 	else
145*7369SJulian.Pullen@Sun.COM 		error = idmap_getwinnamebygid(who, IDMAP_REQ_FLG_USE_CACHE,
146*7369SJulian.Pullen@Sun.COM 		    &name, &domain);
1477057Smarks 
1487057Smarks 	if (error) {
1497057Smarks 		if (idmap_init(&idmap_hdl) == 0 &&
1507057Smarks 		    idmap_get_create(idmap_hdl, &get_hdl) == 0) {
1517057Smarks 			if (user)
1527057Smarks 				error = idmap_get_sidbyuid(get_hdl, who,
153*7369SJulian.Pullen@Sun.COM 				    IDMAP_REQ_FLG_USE_CACHE, &domain, &rid,
154*7369SJulian.Pullen@Sun.COM 				    &status);
1557057Smarks 			else
1567057Smarks 				error = idmap_get_sidbygid(get_hdl, who,
157*7369SJulian.Pullen@Sun.COM 				    IDMAP_REQ_FLG_USE_CACHE, &domain, &rid,
158*7369SJulian.Pullen@Sun.COM 				    &status);
1597057Smarks 			if (error == 0)
1607057Smarks 				error = idmap_get_mappings(get_hdl);
1617057Smarks 		}
1627057Smarks 		if (error == 0) {
1637057Smarks 			len = snprintf(NULL, 0, "%s-%d", domain, rid);
1647057Smarks 			*sidp = malloc(len + 1);
1657057Smarks 			(void) snprintf(*sidp, len + 1, "%s-%d", domain, rid);
1667057Smarks 		} else {
1677057Smarks 			*sidp = NULL;
1687057Smarks 		}
1697057Smarks 		if (get_hdl)
1707057Smarks 			idmap_get_destroy(get_hdl);
1717057Smarks 		if (idmap_hdl)
1727057Smarks 			(void) idmap_fini(idmap_hdl);
1737057Smarks 	} else {
1747057Smarks 		int len;
1757057Smarks 		len = snprintf(NULL, 0, "%s@%d", name, domain);
1767057Smarks 		*sidp = malloc(len + 1);
1777057Smarks 		(void) snprintf(*sidp, len + 1, "%s@%s", name, domain);
1787057Smarks 	}
1797057Smarks 	return (*sidp);
1807057Smarks }
1817057Smarks 
1821420Smarks static void
1831420Smarks aclent_printacl(acl_t *aclp)
184789Sahrens {
1851420Smarks 	aclent_t *tp;
1861420Smarks 	int aclcnt;
1871420Smarks 	int mask;
1881420Smarks 	int slot = 0;
1891420Smarks 	char perm[4];
1901535Smarks 	char uidp[ID_STR_MAX];
1911535Smarks 	char gidp[ID_STR_MAX];
1921420Smarks 
1931420Smarks 	/* display ACL: assume it is sorted. */
1941420Smarks 	aclcnt = aclp->acl_cnt;
1951420Smarks 	for (tp = aclp->acl_aclp; tp && aclcnt--; tp++) {
1961420Smarks 		if (tp->a_type == CLASS_OBJ)
1971420Smarks 			mask = tp->a_perm;
1981420Smarks 	}
1991420Smarks 	aclcnt = aclp->acl_cnt;
2001420Smarks 	for (tp = aclp->acl_aclp; aclcnt--; tp++) {
2011420Smarks 		(void) printf("     %d:", slot++);
2021420Smarks 		switch (tp->a_type) {
2031420Smarks 		case USER:
2041420Smarks 			aclent_perms(tp->a_perm, perm);
2051420Smarks 			(void) printf("user:%s:%s\t\t",
2061535Smarks 			    pruname(tp->a_id, uidp, sizeof (uidp), 0), perm);
2071420Smarks 			aclent_perms((tp->a_perm & mask), perm);
2081420Smarks 			(void) printf("#effective:%s\n", perm);
2091420Smarks 			break;
2101420Smarks 		case USER_OBJ:
2111420Smarks 			/* no need to display uid */
2121420Smarks 			aclent_perms(tp->a_perm, perm);
2131420Smarks 			(void) printf("user::%s\n", perm);
2141420Smarks 			break;
2151420Smarks 		case GROUP:
2161420Smarks 			aclent_perms(tp->a_perm, perm);
2171420Smarks 			(void) printf("group:%s:%s\t\t",
2181535Smarks 			    prgname(tp->a_id, gidp, sizeof (gidp), 0), perm);
2191420Smarks 			aclent_perms(tp->a_perm & mask, perm);
2201420Smarks 			(void) printf("#effective:%s\n", perm);
2211420Smarks 			break;
2221420Smarks 		case GROUP_OBJ:
2231420Smarks 			aclent_perms(tp->a_perm, perm);
2241420Smarks 			(void) printf("group::%s\t\t", perm);
2251420Smarks 			aclent_perms(tp->a_perm & mask, perm);
2261420Smarks 			(void) printf("#effective:%s\n", perm);
2271420Smarks 			break;
2281420Smarks 		case CLASS_OBJ:
2291420Smarks 			aclent_perms(tp->a_perm, perm);
2301420Smarks 			(void) printf("mask:%s\n", perm);
2311420Smarks 			break;
2321420Smarks 		case OTHER_OBJ:
2331420Smarks 			aclent_perms(tp->a_perm, perm);
2341420Smarks 			(void) printf("other:%s\n", perm);
2351420Smarks 			break;
2361420Smarks 		case DEF_USER:
2371420Smarks 			aclent_perms(tp->a_perm, perm);
2381420Smarks 			(void) printf("default:user:%s:%s\n",
2391535Smarks 			    pruname(tp->a_id, uidp, sizeof (uidp), 0), perm);
2401420Smarks 			break;
2411420Smarks 		case DEF_USER_OBJ:
2421420Smarks 			aclent_perms(tp->a_perm, perm);
2431420Smarks 			(void) printf("default:user::%s\n", perm);
2441420Smarks 			break;
2451420Smarks 		case DEF_GROUP:
2461420Smarks 			aclent_perms(tp->a_perm, perm);
2471420Smarks 			(void) printf("default:group:%s:%s\n",
2481535Smarks 			    prgname(tp->a_id, gidp, sizeof (gidp), 0), perm);
2491420Smarks 			break;
2501420Smarks 		case DEF_GROUP_OBJ:
2511420Smarks 			aclent_perms(tp->a_perm, perm);
2521420Smarks 			(void) printf("default:group::%s\n", perm);
2531420Smarks 			break;
2541420Smarks 		case DEF_CLASS_OBJ:
2551420Smarks 			aclent_perms(tp->a_perm, perm);
2561420Smarks 			(void) printf("default:mask:%s\n", perm);
2571420Smarks 			break;
2581420Smarks 		case DEF_OTHER_OBJ:
2591420Smarks 			aclent_perms(tp->a_perm, perm);
2601420Smarks 			(void) printf("default:other:%s\n", perm);
2611420Smarks 			break;
2621420Smarks 		default:
2631420Smarks 			(void) fprintf(stderr,
2641567Smarks 			    dgettext(TEXT_DOMAIN, "unrecognized entry\n"));
2651420Smarks 			break;
2661420Smarks 		}
2671420Smarks 	}
2681420Smarks }
2691420Smarks 
2701420Smarks static void
2711420Smarks split_line(char *str, int cols)
2721420Smarks {
2731420Smarks 	char *ptr;
2741420Smarks 	int len;
2751420Smarks 	int i;
2761420Smarks 	int last_split;
2771420Smarks 	char *pad = "";
2781420Smarks 	int pad_len;
2791420Smarks 
2801420Smarks 	len = strlen(str);
2811420Smarks 	ptr = str;
2821420Smarks 	pad_len = 0;
2831420Smarks 
2841420Smarks 	ptr = str;
2851420Smarks 	last_split = 0;
2861420Smarks 	for (i = 0; i != len; i++) {
2871420Smarks 		if ((i + pad_len + 4) >= cols) {
2881420Smarks 			(void) printf("%s%.*s\n", pad, last_split, ptr);
2891420Smarks 			ptr = &ptr[last_split];
2901420Smarks 			len = strlen(ptr);
2911420Smarks 			i = 0;
2921420Smarks 			pad_len = 4;
2931420Smarks 			pad = "         ";
2941420Smarks 		} else {
2951420Smarks 			if (ptr[i] == '/' || ptr[i] == ':') {
2961420Smarks 				last_split = i;
2971420Smarks 			}
2981420Smarks 		}
2991420Smarks 	}
3001420Smarks 	if (i == len) {
3011420Smarks 		(void) printf("%s%s\n", pad, ptr);
3021420Smarks 	}
3031420Smarks }
3041420Smarks 
3057057Smarks /*
3067057Smarks  * compute entry type string, such as user:joe, group:staff,...
3077057Smarks  */
3087057Smarks static int
3097057Smarks aclent_type_txt(dynaclstr_t *dstr, aclent_t *aclp, int flags)
3101420Smarks {
3117057Smarks 	char idp[ID_STR_MAX];
3127057Smarks 	int error;
3137057Smarks 
3147057Smarks 	switch (aclp->a_type) {
3157057Smarks 	case DEF_USER_OBJ:
3167057Smarks 	case USER_OBJ:
3177057Smarks 		if (aclp->a_type == USER_OBJ)
3187057Smarks 			error = str_append(dstr, "user::");
3197057Smarks 		else
3207057Smarks 			error = str_append(dstr, "defaultuser::");
3217057Smarks 		break;
3227057Smarks 
3237057Smarks 	case DEF_USER:
3247057Smarks 	case USER:
3257057Smarks 		if (aclp->a_type == USER)
3267057Smarks 			error = str_append(dstr, "user:");
3277057Smarks 		else
3287057Smarks 			error = str_append(dstr, "defaultuser:");
3297057Smarks 		if (error)
3307057Smarks 			break;
3317057Smarks 		error = str_append(dstr, pruname(aclp->a_id, idp,
3327057Smarks 		    sizeof (idp), flags & ACL_NORESOLVE));
3337057Smarks 		if (error == 0)
3347057Smarks 			error = str_append(dstr, ":");
3357057Smarks 		break;
3367057Smarks 
3377057Smarks 	case DEF_GROUP_OBJ:
3387057Smarks 	case GROUP_OBJ:
3397057Smarks 		if (aclp->a_type == GROUP_OBJ)
3407057Smarks 			error = str_append(dstr, "group::");
3417057Smarks 		else
3427057Smarks 			error = str_append(dstr, "defaultgroup::");
3437057Smarks 		break;
3441420Smarks 
3457057Smarks 	case DEF_GROUP:
3467057Smarks 	case GROUP:
3477057Smarks 		if (aclp->a_type == GROUP)
3487057Smarks 			error = str_append(dstr, "group:");
3497057Smarks 		else
3507057Smarks 			error = str_append(dstr, "defaultgroup:");
3517057Smarks 		if (error)
3527057Smarks 			break;
3537057Smarks 		error = str_append(dstr, prgname(aclp->a_id, idp,
3547057Smarks 		    sizeof (idp), flags & ACL_NORESOLVE));
3557057Smarks 		if (error == 0)
3567057Smarks 			error = str_append(dstr, ":");
3577057Smarks 		break;
3587057Smarks 
3597057Smarks 	case DEF_CLASS_OBJ:
3607057Smarks 	case CLASS_OBJ:
3617057Smarks 		if (aclp->a_type == CLASS_OBJ)
3627057Smarks 			error = str_append(dstr, "mask:");
3637057Smarks 		else
3647057Smarks 			error = str_append(dstr, "defaultmask:");
3657057Smarks 		break;
3661420Smarks 
3677057Smarks 	case DEF_OTHER_OBJ:
3687057Smarks 	case OTHER_OBJ:
3697057Smarks 		if (aclp->a_type == OTHER_OBJ)
3707057Smarks 			error = str_append(dstr, "other:");
3717057Smarks 		else
3727057Smarks 			error = str_append(dstr, "defaultother:");
3737057Smarks 		break;
3747057Smarks 
3757057Smarks 	default:
3767057Smarks 		error = 1;
3777057Smarks 		break;
3787057Smarks 	}
3797057Smarks 
3807057Smarks 	return (error);
3817057Smarks }
3827057Smarks 
3837057Smarks /*
3847057Smarks  * compute entry type string such as, owner@:, user:joe, group:staff,...
3857057Smarks  */
3867057Smarks static int
3877057Smarks ace_type_txt(dynaclstr_t *dynstr, ace_t *acep, int flags)
3887057Smarks {
3897057Smarks 	char idp[ID_STR_MAX];
3907057Smarks 	int error;
3917057Smarks 	char *sidp = NULL;
3921420Smarks 
3931420Smarks 	switch (acep->a_flags & ACE_TYPE_FLAGS) {
3941420Smarks 	case ACE_OWNER:
3957057Smarks 		error = str_append(dynstr, OWNERAT_TXT);
3961420Smarks 		break;
3971420Smarks 
3981420Smarks 	case ACE_GROUP|ACE_IDENTIFIER_GROUP:
3997057Smarks 		error = str_append(dynstr, GROUPAT_TXT);
4001420Smarks 		break;
4011420Smarks 
4021420Smarks 	case ACE_IDENTIFIER_GROUP:
4037057Smarks 		if ((flags & ACL_SID_FMT) && acep->a_who > MAXUID) {
4047057Smarks 			if (error = str_append(dynstr,
4057057Smarks 			    GROUPSID_TXT))
4067057Smarks 				break;
4077057Smarks 			error = str_append(dynstr, prsidname(acep->a_who,
4087057Smarks 			    B_FALSE, &sidp, flags & ACL_NORESOLVE));
4097057Smarks 		} else {
4107057Smarks 			if (error = str_append(dynstr, GROUP_TXT))
4117057Smarks 				break;
4127057Smarks 			error = str_append(dynstr, prgname(acep->a_who, idp,
4137057Smarks 			    sizeof (idp), flags & ACL_NORESOLVE));
4147057Smarks 		}
4157057Smarks 		if (error == 0)
4167057Smarks 			error = str_append(dynstr, ":");
4171420Smarks 		break;
4181420Smarks 
4191420Smarks 	case ACE_EVERYONE:
4207057Smarks 		error = str_append(dynstr, EVERYONEAT_TXT);
4211420Smarks 		break;
4221420Smarks 
4231420Smarks 	case 0:
4247057Smarks 		if ((flags & ACL_SID_FMT) && acep->a_who > MAXUID) {
4257057Smarks 			if (error = str_append(dynstr, USERSID_TXT))
4267057Smarks 				break;
4277057Smarks 			error = str_append(dynstr, prsidname(acep->a_who,
4287057Smarks 			    B_TRUE, &sidp, flags & ACL_NORESOLVE));
4297057Smarks 		} else {
4307057Smarks 			if (error = str_append(dynstr, USER_TXT))
4317057Smarks 				break;
4327057Smarks 			error = str_append(dynstr, pruname(acep->a_who, idp,
4337057Smarks 			    sizeof (idp), flags & ACL_NORESOLVE));
4347057Smarks 		}
4357057Smarks 		if (error == 0)
4367057Smarks 			error = str_append(dynstr, ":");
4377057Smarks 		break;
4387057Smarks 	default:
4397057Smarks 		error = 0;
4401420Smarks 		break;
4411420Smarks 	}
4421420Smarks 
4437057Smarks 	if (sidp)
4447057Smarks 		free(sidp);
4457057Smarks 	return (error);
4461420Smarks }
4471420Smarks 
4487057Smarks /*
4497057Smarks  * compute string of permissions, such as read_data/write_data or
4507057Smarks  * rwxp,...
4517057Smarks  * The format depends on the flags field which indicates whether the compact
4527057Smarks  * or verbose format should be used.
4537057Smarks  */
4547057Smarks static int
4557057Smarks ace_perm_txt(dynaclstr_t *dstr, uint32_t mask,
4561420Smarks     uint32_t iflags, int isdir, int flags)
4571420Smarks {
4587057Smarks 	int error = 0;
4591420Smarks 
4601420Smarks 	if (flags & ACL_COMPACT_FMT) {
4617057Smarks 		char buf[16];
462789Sahrens 
4631420Smarks 		if (mask & ACE_READ_DATA)
4641420Smarks 			buf[0] = 'r';
4651420Smarks 		else
4661420Smarks 			buf[0] = '-';
4671420Smarks 		if (mask & ACE_WRITE_DATA)
4681420Smarks 			buf[1] = 'w';
4691420Smarks 		else
4701420Smarks 			buf[1] = '-';
4711420Smarks 		if (mask & ACE_EXECUTE)
4721420Smarks 			buf[2] = 'x';
4731420Smarks 		else
4741420Smarks 			buf[2] = '-';
4751420Smarks 		if (mask & ACE_APPEND_DATA)
4761420Smarks 			buf[3] = 'p';
4771420Smarks 		else
4781420Smarks 			buf[3] = '-';
4791420Smarks 		if (mask & ACE_DELETE)
4801420Smarks 			buf[4] = 'd';
4811420Smarks 		else
4821420Smarks 			buf[4] = '-';
4831420Smarks 		if (mask & ACE_DELETE_CHILD)
4841420Smarks 			buf[5] = 'D';
4851420Smarks 		else
4861420Smarks 			buf[5] = '-';
4871420Smarks 		if (mask & ACE_READ_ATTRIBUTES)
4881420Smarks 			buf[6] = 'a';
4891420Smarks 		else
4901420Smarks 			buf[6] = '-';
4911420Smarks 		if (mask & ACE_WRITE_ATTRIBUTES)
4921420Smarks 			buf[7] = 'A';
4931420Smarks 		else
4941420Smarks 			buf[7] = '-';
4951420Smarks 		if (mask & ACE_READ_NAMED_ATTRS)
4961420Smarks 			buf[8] = 'R';
4971420Smarks 		else
4981420Smarks 			buf[8] = '-';
4991420Smarks 		if (mask & ACE_WRITE_NAMED_ATTRS)
5001420Smarks 			buf[9] = 'W';
5011420Smarks 		else
5021420Smarks 			buf[9] = '-';
5031420Smarks 		if (mask & ACE_READ_ACL)
5041420Smarks 			buf[10] = 'c';
5051420Smarks 		else
5061420Smarks 			buf[10] = '-';
5071420Smarks 		if (mask & ACE_WRITE_ACL)
5081420Smarks 			buf[11] = 'C';
5091420Smarks 		else
5101420Smarks 			buf[11] = '-';
5111420Smarks 		if (mask & ACE_WRITE_OWNER)
5121420Smarks 			buf[12] = 'o';
5131420Smarks 		else
5141420Smarks 			buf[12] = '-';
5151420Smarks 		if (mask & ACE_SYNCHRONIZE)
5161420Smarks 			buf[13] = 's';
5171420Smarks 		else
5181420Smarks 			buf[13] = '-';
5197057Smarks 		buf[14] = ':';
5207057Smarks 		buf[15] = '\0';
5217057Smarks 		error = str_append(dstr, buf);
5221420Smarks 	} else {
5231420Smarks 		/*
5241420Smarks 		 * If ACE is a directory, but inheritance indicates its
5251420Smarks 		 * for a file then print permissions for file rather than
5261420Smarks 		 * dir.
5271420Smarks 		 */
5281420Smarks 		if (isdir) {
5291420Smarks 			if (mask & ACE_LIST_DIRECTORY) {
5301420Smarks 				if (iflags == ACE_FILE_INHERIT_ACE) {
5317057Smarks 					error = str_append(dstr,
5327057Smarks 					    READ_DATA_TXT);
5331420Smarks 				} else {
5347057Smarks 					error =
5357057Smarks 					    str_append(dstr, READ_DIR_TXT);
5361420Smarks 				}
5371420Smarks 			}
5387057Smarks 			if (error == 0 && (mask & ACE_ADD_FILE)) {
5391420Smarks 				if (iflags == ACE_FILE_INHERIT_ACE) {
5407057Smarks 					error =
5417057Smarks 					    str_append(dstr, WRITE_DATA_TXT);
5421420Smarks 				} else {
5437057Smarks 					error =
5447057Smarks 					    str_append(dstr, ADD_FILE_TXT);
5451420Smarks 				}
5461420Smarks 			}
5477057Smarks 			if (error == 0 && (mask & ACE_ADD_SUBDIRECTORY)) {
5481420Smarks 				if (iflags == ACE_FILE_INHERIT_ACE) {
5497057Smarks 					error = str_append(dstr,
5507057Smarks 					    APPEND_DATA_TXT);
5511420Smarks 				} else {
5527057Smarks 					error = str_append(dstr,
5537057Smarks 					    ADD_DIR_TXT);
5541420Smarks 				}
5551420Smarks 			}
5561420Smarks 		} else {
5571420Smarks 			if (mask & ACE_READ_DATA) {
5587057Smarks 				error = str_append(dstr, READ_DATA_TXT);
5591420Smarks 			}
5607057Smarks 			if (error == 0 && (mask & ACE_WRITE_DATA)) {
5617057Smarks 				error = str_append(dstr, WRITE_DATA_TXT);
5621420Smarks 			}
5637057Smarks 			if (error == 0 && (mask & ACE_APPEND_DATA)) {
5647057Smarks 				error = str_append(dstr, APPEND_DATA_TXT);
5651420Smarks 			}
5661420Smarks 		}
5677057Smarks 		if (error == 0 && (mask & ACE_READ_NAMED_ATTRS)) {
5687057Smarks 			error = str_append(dstr, READ_XATTR_TXT);
5691420Smarks 		}
5707057Smarks 		if (error == 0 && (mask & ACE_WRITE_NAMED_ATTRS)) {
5717057Smarks 			error = str_append(dstr, WRITE_XATTR_TXT);
5721420Smarks 		}
5737057Smarks 		if (error == 0 && (mask & ACE_EXECUTE)) {
5747057Smarks 			error = str_append(dstr, EXECUTE_TXT);
5751420Smarks 		}
5767057Smarks 		if (error == 0 && (mask & ACE_DELETE_CHILD)) {
5777057Smarks 			error = str_append(dstr, DELETE_CHILD_TXT);
5781420Smarks 		}
5797057Smarks 		if (error == 0 && (mask & ACE_READ_ATTRIBUTES)) {
5807057Smarks 			error = str_append(dstr, READ_ATTRIBUTES_TXT);
5811420Smarks 		}
5827057Smarks 		if (error == 0 && (mask & ACE_WRITE_ATTRIBUTES)) {
5837057Smarks 			error = str_append(dstr, WRITE_ATTRIBUTES_TXT);
5841420Smarks 		}
5857057Smarks 		if (error == 0 && (mask & ACE_DELETE)) {
5867057Smarks 			error = str_append(dstr, DELETE_TXT);
5871420Smarks 		}
5887057Smarks 		if (error == 0 && (mask & ACE_READ_ACL)) {
5897057Smarks 			error = str_append(dstr, READ_ACL_TXT);
5901420Smarks 		}
5917057Smarks 		if (error == 0 && (mask & ACE_WRITE_ACL)) {
5927057Smarks 			error = str_append(dstr, WRITE_ACL_TXT);
5931420Smarks 		}
5947057Smarks 		if (error == 0 && (mask & ACE_WRITE_OWNER)) {
5957057Smarks 			error = str_append(dstr, WRITE_OWNER_TXT);
5961420Smarks 		}
5977057Smarks 		if (error == 0 && (mask & ACE_SYNCHRONIZE)) {
5987057Smarks 			error = str_append(dstr, SYNCHRONIZE_TXT);
5991420Smarks 		}
6007057Smarks 		if (error == 0 && dstr->d_aclexport[dstr->d_pos-1] == '/') {
6017057Smarks 			dstr->d_aclexport[--dstr->d_pos] = '\0';
6027057Smarks 		}
6037057Smarks 		if (error == 0)
6047057Smarks 			error = str_append(dstr, ":");
6051420Smarks 	}
6067057Smarks 	return (error);
6071420Smarks }
6081420Smarks 
6097057Smarks /*
6107057Smarks  * compute string of access type, such as allow, deny, ...
6117057Smarks  */
6127057Smarks static int
6137057Smarks ace_access_txt(dynaclstr_t *dstr, int type)
6141420Smarks {
6157057Smarks 	int error;
6161420Smarks 
6177057Smarks 	if (type == ACE_ACCESS_ALLOWED_ACE_TYPE)
6187057Smarks 		error = str_append(dstr, ALLOW_TXT);
6197057Smarks 	else if (type == ACE_ACCESS_DENIED_ACE_TYPE)
6207057Smarks 		error = str_append(dstr, DENY_TXT);
6217057Smarks 	else if (type == ACE_SYSTEM_AUDIT_ACE_TYPE)
6227057Smarks 		error = str_append(dstr, AUDIT_TXT);
6237057Smarks 	else if (type == ACE_SYSTEM_ALARM_ACE_TYPE)
6247057Smarks 		error = str_append(dstr, ALARM_TXT);
6257057Smarks 	else
6267057Smarks 		error = str_append(dstr, UNKNOWN_TXT);
6271420Smarks 
6287057Smarks 	return (error);
6291420Smarks }
6301420Smarks 
6317057Smarks static int
6327057Smarks ace_inherit_txt(dynaclstr_t *dstr, uint32_t iflags, int flags)
6331420Smarks {
6347057Smarks 	int error = 0;
635789Sahrens 
6361420Smarks 	if (flags & ACL_COMPACT_FMT) {
6377057Smarks 		char buf[9];
6387057Smarks 
6391420Smarks 		if (iflags & ACE_FILE_INHERIT_ACE)
6401420Smarks 			buf[0] = 'f';
6411420Smarks 		else
6421420Smarks 			buf[0] = '-';
6431420Smarks 		if (iflags & ACE_DIRECTORY_INHERIT_ACE)
6441420Smarks 			buf[1] = 'd';
6451420Smarks 		else
6461420Smarks 			buf[1] = '-';
6471420Smarks 		if (iflags & ACE_INHERIT_ONLY_ACE)
6481420Smarks 			buf[2] = 'i';
6491420Smarks 		else
6501420Smarks 			buf[2] = '-';
6511420Smarks 		if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)
6521420Smarks 			buf[3] = 'n';
6531420Smarks 		else
6541420Smarks 			buf[3] = '-';
6551420Smarks 		if (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
6561420Smarks 			buf[4] = 'S';
6571420Smarks 		else
6581420Smarks 			buf[4] = '-';
6591420Smarks 		if (iflags & ACE_FAILED_ACCESS_ACE_FLAG)
6601420Smarks 			buf[5] = 'F';
6611420Smarks 		else
6621420Smarks 			buf[5] = '-';
6635331Samw 		if (iflags & ACE_INHERITED_ACE)
6645331Samw 			buf[6] = 'I';
6655331Samw 		else
6665331Samw 			buf[6] = '-';
6677057Smarks 		buf[7] = ':';
6687057Smarks 		buf[8] = '\0';
6697057Smarks 		error = str_append(dstr, buf);
6701420Smarks 	} else {
6711420Smarks 		if (iflags & ACE_FILE_INHERIT_ACE) {
6727057Smarks 			error = str_append(dstr, FILE_INHERIT_TXT);
6731420Smarks 		}
6747057Smarks 		if (error == 0 && (iflags & ACE_DIRECTORY_INHERIT_ACE)) {
6757057Smarks 			error = str_append(dstr, DIR_INHERIT_TXT);
6761420Smarks 		}
6777057Smarks 		if (error == 0 && (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)) {
6787057Smarks 			error = str_append(dstr, NO_PROPAGATE_TXT);
6791420Smarks 		}
6807057Smarks 		if (error == 0 && (iflags & ACE_INHERIT_ONLY_ACE)) {
6817057Smarks 			error = str_append(dstr, INHERIT_ONLY_TXT);
6821420Smarks 		}
6837057Smarks 		if (error == 0 && (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)) {
6847057Smarks 			error = str_append(dstr, SUCCESSFUL_ACCESS_TXT);
6855331Samw 		}
6867057Smarks 		if (error == 0 && (iflags & ACE_FAILED_ACCESS_ACE_FLAG)) {
6877057Smarks 			error = str_append(dstr, FAILED_ACCESS_TXT);
6885331Samw 		}
6897057Smarks 		if (error == 0 && (iflags & ACE_INHERITED_ACE)) {
6907057Smarks 			error = str_append(dstr, INHERITED_ACE_TXT);
6915331Samw 		}
6927057Smarks 		if (error == 0 && dstr->d_aclexport[dstr->d_pos-1] == '/') {
6937057Smarks 			dstr->d_aclexport[--dstr->d_pos] = '\0';
6947057Smarks 			error = str_append(dstr, ":");
6957057Smarks 		}
6961420Smarks 	}
6971420Smarks 
6987057Smarks 	return (error);
699789Sahrens }
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate /*
7020Sstevel@tonic-gate  * Convert internal acl representation to external representation.
7030Sstevel@tonic-gate  *
7040Sstevel@tonic-gate  * The length of a non-owning user name or non-owning group name ie entries
7050Sstevel@tonic-gate  * of type DEF_USER, USER, DEF_GROUP or GROUP, can exceed LOGNAME_MAX.  We
7060Sstevel@tonic-gate  * thus check the length of these entries, and if greater than LOGNAME_MAX,
7070Sstevel@tonic-gate  * we realloc() via increase_length().
7080Sstevel@tonic-gate  *
7090Sstevel@tonic-gate  * The LOGNAME_MAX, ENTRYTYPELEN and PERMS limits are otherwise always
7100Sstevel@tonic-gate  * adhered to.
7110Sstevel@tonic-gate  */
7121420Smarks 
7131420Smarks /*
7141420Smarks  * acltotext() converts each ACL entry to look like this:
7151420Smarks  *
7161420Smarks  *    entry_type:uid^gid^name:perms[:id]
7171420Smarks  *
7181420Smarks  * The maximum length of entry_type is 14 ("defaultgroup::" and
7191420Smarks  * "defaultother::") hence ENTRYTYPELEN is set to 14.
7201420Smarks  *
7211420Smarks  * The max length of a uid^gid^name entry (in theory) is 8, hence we use,
7221420Smarks  * however the ID could be a number so we therefore use ID_STR_MAX
7231420Smarks  *
7241420Smarks  * The length of a perms entry is 4 to allow for the comma appended to each
7251420Smarks  * to each acl entry.  Hence PERMS is set to 4.
7261420Smarks  */
7271420Smarks 
7281420Smarks #define	ENTRYTYPELEN	14
7291420Smarks #define	PERMS		4
7301420Smarks #define	ACL_ENTRY_SIZE	(ENTRYTYPELEN + ID_STR_MAX + PERMS + APPENDED_ID_MAX)
7311420Smarks 
7320Sstevel@tonic-gate char *
7331420Smarks aclent_acltotext(aclent_t  *aclp, int aclcnt, int flags)
7340Sstevel@tonic-gate {
7357057Smarks 	dynaclstr_t 	*dstr;
7360Sstevel@tonic-gate 	char		*aclexport;
7377057Smarks 	int		i;
7387057Smarks 	int 		error = 0;
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	if (aclp == NULL)
7410Sstevel@tonic-gate 		return (NULL);
7427057Smarks 	if ((dstr = malloc(sizeof (dynaclstr_t))) == NULL)
7430Sstevel@tonic-gate 		return (NULL);
7447057Smarks 	dstr->d_bufsize = aclcnt * ACL_ENTRY_SIZE;
7457057Smarks 	if ((dstr->d_aclexport = malloc(dstr->d_bufsize)) == NULL) {
7460Sstevel@tonic-gate 		free(dstr);
7470Sstevel@tonic-gate 		return (NULL);
7480Sstevel@tonic-gate 	}
7497057Smarks 	*dstr->d_aclexport = '\0';
7507057Smarks 	dstr->d_pos = 0;
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	for (i = 0; i < aclcnt; i++, aclp++) {
7537057Smarks 		if (error = aclent_type_txt(dstr, aclp, flags))
7540Sstevel@tonic-gate 			break;
7557057Smarks 		if (error = aclent_perm_txt(dstr, aclp->a_perm))
7560Sstevel@tonic-gate 			break;
7571420Smarks 
7581420Smarks 		if ((flags & ACL_APPEND_ID) && ((aclp->a_type == USER) ||
7591420Smarks 		    (aclp->a_type == DEF_USER) || (aclp->a_type == GROUP) ||
7601420Smarks 		    (aclp->a_type == DEF_GROUP))) {
7617057Smarks 			char id[ID_STR_MAX], *idstr;
7627057Smarks 
7637057Smarks 			if (error = str_append(dstr, ":"))
7647057Smarks 				break;
7651420Smarks 			id[ID_STR_MAX - 1] = '\0'; /* null terminate buffer */
7661420Smarks 			idstr = lltostr(aclp->a_id, &id[ID_STR_MAX - 1]);
7677057Smarks 			if (error = str_append(dstr, idstr))
7687057Smarks 				break;
7691420Smarks 		}
7700Sstevel@tonic-gate 		if (i < aclcnt - 1)
7717057Smarks 			if (error = str_append(dstr, ","))
7727057Smarks 				break;
7730Sstevel@tonic-gate 	}
7747057Smarks 	if (error) {
7757057Smarks 		if (dstr->d_aclexport)
7767057Smarks 			free(dstr->d_aclexport);
7777057Smarks 	} else {
7787057Smarks 		aclexport = dstr->d_aclexport;
7797057Smarks 	}
7800Sstevel@tonic-gate 	free(dstr);
7810Sstevel@tonic-gate 	return (aclexport);
7820Sstevel@tonic-gate }
7830Sstevel@tonic-gate 
7841420Smarks char *
7851420Smarks acltotext(aclent_t *aclp, int aclcnt)
7860Sstevel@tonic-gate {
7871420Smarks 	return (aclent_acltotext(aclp, aclcnt, 0));
7881420Smarks }
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 
791789Sahrens aclent_t *
792789Sahrens aclfromtext(char *aclstr, int *aclcnt)
793789Sahrens {
794789Sahrens 	acl_t *aclp;
795789Sahrens 	aclent_t *aclentp;
796789Sahrens 	int error;
797789Sahrens 
7981420Smarks 	error = acl_fromtext(aclstr, &aclp);
799789Sahrens 	if (error)
800789Sahrens 		return (NULL);
801789Sahrens 
802789Sahrens 	aclentp = aclp->acl_aclp;
803789Sahrens 	aclp->acl_aclp = NULL;
8041420Smarks 	*aclcnt = aclp->acl_cnt;
805789Sahrens 
8061420Smarks 	acl_free(aclp);
807789Sahrens 	return (aclentp);
808789Sahrens }
809789Sahrens 
810789Sahrens 
8117057Smarks /*
8127057Smarks  * returns a character position index of the start of the newly
8137057Smarks  * appended string.  Returns -1 if operation couldn't be completed.
8147057Smarks  */
8157057Smarks static int
8167057Smarks str_append(dynaclstr_t *dstr, char *newstr)
8170Sstevel@tonic-gate {
8187057Smarks 	size_t len = strlen(newstr);
8197057Smarks 
8207057Smarks 	if ((len + dstr->d_pos) >= dstr->d_bufsize) {
8217057Smarks 		dstr->d_aclexport = realloc(dstr->d_aclexport,
8227057Smarks 		    dstr->d_bufsize + len + 1);
8237057Smarks 		if (dstr->d_aclexport == NULL)
8247057Smarks 			return (1);
8257057Smarks 		dstr->d_bufsize += len;
8267057Smarks 	}
8277057Smarks 	(void) strcat(&dstr->d_aclexport[dstr->d_pos], newstr);
8287057Smarks 	dstr->d_pos += len;
8297057Smarks 	return (0);
8300Sstevel@tonic-gate }
8310Sstevel@tonic-gate 
8327057Smarks static int
8337057Smarks aclent_perm_txt(dynaclstr_t *dstr, o_mode_t perm)
8340Sstevel@tonic-gate {
8357057Smarks 	char buf[4];
8360Sstevel@tonic-gate 
8377057Smarks 	if (perm & S_IROTH)
8387057Smarks 		buf[0] = 'r';
8397057Smarks 	else
8407057Smarks 		buf[0] = '-';
8417057Smarks 	if (perm & S_IWOTH)
8427057Smarks 		buf[1] = 'w';
8437057Smarks 	else
8447057Smarks 		buf[1] = '-';
8457057Smarks 	if (perm & S_IXOTH)
8467057Smarks 		buf[2] = 'x';
8477057Smarks 	else
8487057Smarks 		buf[2] = '-';
8497057Smarks 	buf[3] = '\0';
8507057Smarks 	return (str_append(dstr, buf));
8510Sstevel@tonic-gate }
852789Sahrens 
853789Sahrens /*
8541420Smarks  * ace_acltotext() convert each ace formatted acl to look like this:
855789Sahrens  *
8561420Smarks  * entry_type:uid^gid^name:perms[:flags]:<allow|deny>[:id][,]
857789Sahrens  *
858789Sahrens  * The maximum length of entry_type is 5 ("group")
859789Sahrens  *
8601420Smarks  * The max length of a uid^gid^name entry (in theory) is 8,
8611420Smarks  * however id could be a number so we therefore use ID_STR_MAX
862789Sahrens  *
863789Sahrens  * The length of a perms entry is 144 i.e read_data/write_data...
864789Sahrens  * to each acl entry.
865789Sahrens  *
8665331Samw  * iflags: file_inherit/dir_inherit/inherit_only/no_propagate/successful_access
8675331Samw  *         /failed_access
868789Sahrens  *
869789Sahrens  */
870789Sahrens 
871789Sahrens #define	ACE_ENTRYTYPLEN		6
8725331Samw #define	IFLAGS_STR "file_inherit/dir_inherit/inherit_only/no_propagate/" \
8735331Samw 	"successful_access/failed_access/inherited"
8745331Samw #define	IFLAGS_SIZE		(sizeof (IFLAGS_STR) - 1)
8751420Smarks #define	ACCESS_TYPE_SIZE	7	/* if unknown */
876789Sahrens #define	COLON_CNT		3
877789Sahrens #define	PERMS_LEN		216
8785331Samw #define	ACE_ENTRY_SIZE	(ACE_ENTRYTYPLEN + ID_STR_MAX + PERMS_LEN + \
8791420Smarks     ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT + APPENDED_ID_MAX)
880789Sahrens 
881789Sahrens static char *
8821420Smarks ace_acltotext(acl_t *aceaclp, int flags)
883789Sahrens {
884789Sahrens 	ace_t		*aclp = aceaclp->acl_aclp;
885789Sahrens 	int		aclcnt = aceaclp->acl_cnt;
8867057Smarks 	int		i;
8877057Smarks 	int		error = 0;
8887057Smarks 	int		isdir = (aceaclp->acl_flags & ACL_IS_DIR);
8897057Smarks 	dynaclstr_t 	*dstr;
890789Sahrens 	char		*aclexport;
891789Sahrens 
892789Sahrens 	if (aclp == NULL)
893789Sahrens 		return (NULL);
894789Sahrens 
8957057Smarks 	if ((dstr = malloc(sizeof (dynaclstr_t))) == NULL)
8967057Smarks 		return (NULL);
8977057Smarks 	dstr->d_bufsize = aclcnt * ACL_ENTRY_SIZE;
8987057Smarks 	if ((dstr->d_aclexport = malloc(dstr->d_bufsize)) == NULL) {
8997057Smarks 		free(dstr);
9007057Smarks 		return (NULL);
9017057Smarks 	}
9027057Smarks 	*dstr->d_aclexport = '\0';
9037057Smarks 	dstr->d_pos = 0;
9047057Smarks 
905789Sahrens 	for (i = 0; i < aclcnt; i++, aclp++) {
9061420Smarks 
9077057Smarks 		if (error = ace_type_txt(dstr, aclp, flags))
9087057Smarks 			break;
9097057Smarks 		if (error = ace_perm_txt(dstr, aclp->a_access_mask,
9107057Smarks 		    aclp->a_flags, isdir, flags))
9117057Smarks 			break;
9127057Smarks 		if (error = ace_inherit_txt(dstr, aclp->a_flags, flags))
9137057Smarks 			break;
9147057Smarks 		if (error = ace_access_txt(dstr, aclp->a_type))
9157057Smarks 			break;
916789Sahrens 
9171420Smarks 		if ((flags & ACL_APPEND_ID) &&
9181420Smarks 		    (((aclp->a_flags & ACE_TYPE_FLAGS) == 0) ||
9191420Smarks 		    ((aclp->a_flags & ACE_TYPE_FLAGS) ==
9201420Smarks 		    ACE_IDENTIFIER_GROUP))) {
9217057Smarks 			char id[ID_STR_MAX], *idstr;
9227057Smarks 
9237057Smarks 			if (error = str_append(dstr, ":"))
9247057Smarks 				break;
9251420Smarks 			id[ID_STR_MAX -1] = '\0'; /* null terminate buffer */
9267057Smarks 			idstr = lltostr((aclp->a_who > MAXUID &&
9277057Smarks 			    !(flags & ACL_NORESOLVE)) ? UID_NOBODY :
9287057Smarks 			    aclp->a_who, &id[ID_STR_MAX - 1]);
9297057Smarks 			if (error = str_append(dstr, idstr))
9307057Smarks 				break;
931789Sahrens 		}
9321420Smarks 		if (i < aclcnt - 1) {
9337057Smarks 			if (error = str_append(dstr, ","))
9347057Smarks 				break;
935789Sahrens 		}
936789Sahrens 	}
9377057Smarks 	if (error) {
9387057Smarks 		if (dstr->d_aclexport)
9397057Smarks 			free(dstr->d_aclexport);
9407057Smarks 	} else {
9417057Smarks 		aclexport = dstr->d_aclexport;
9427057Smarks 	}
9437057Smarks 	free(dstr);
944789Sahrens 	return (aclexport);
945789Sahrens }
946789Sahrens 
9471420Smarks char *
9481420Smarks acl_totext(acl_t *aclp, int flags)
949789Sahrens {
9501420Smarks 	char *txtp;
951789Sahrens 
952789Sahrens 	if (aclp == NULL)
953789Sahrens 		return (NULL);
954789Sahrens 
955789Sahrens 	switch (aclp->acl_type) {
956789Sahrens 	case ACE_T:
9571420Smarks 		txtp = ace_acltotext(aclp, flags);
9581420Smarks 		break;
959789Sahrens 	case ACLENT_T:
9601420Smarks 		txtp = aclent_acltotext(aclp->acl_aclp, aclp->acl_cnt, flags);
9611420Smarks 		break;
962789Sahrens 	}
9631420Smarks 
9641420Smarks 	return (txtp);
965789Sahrens }
966789Sahrens 
967789Sahrens int
968789Sahrens acl_fromtext(const char *acltextp, acl_t **ret_aclp)
969789Sahrens {
9701420Smarks 	int error;
9711420Smarks 	char *buf;
9721420Smarks 
9731420Smarks 	buf = malloc(strlen(acltextp) + 2);
9741420Smarks 	if (buf == NULL)
9751420Smarks 		return (EACL_MEM_ERROR);
9761420Smarks 	strcpy(buf, acltextp);
9771420Smarks 	strcat(buf, "\n");
9781420Smarks 	yybuf = buf;
9791420Smarks 	yyreset();
9801420Smarks 	error = yyparse();
9811420Smarks 	free(buf);
9821420Smarks 
9831420Smarks 	if (yyacl) {
9841420Smarks 		if (error == 0)
9851420Smarks 			*ret_aclp = yyacl;
9861420Smarks 		else {
9871420Smarks 			acl_free(yyacl);
9881420Smarks 		}
9891420Smarks 		yyacl = NULL;
9901420Smarks 	}
9911420Smarks 	return (error);
9921420Smarks }
9931420Smarks 
9941420Smarks int
9951420Smarks acl_parse(const char *acltextp, acl_t **aclp)
9961420Smarks {
997789Sahrens 	int error;
998789Sahrens 
9991420Smarks 	yyinteractive = 1;
10001420Smarks 	error = acl_fromtext(acltextp, aclp);
10011420Smarks 	yyinteractive = 0;
10021420Smarks 	return (error);
10031420Smarks }
10041420Smarks 
10051420Smarks static void
10061420Smarks ace_compact_printacl(acl_t *aclp)
10071420Smarks {
10081420Smarks 	int cnt;
10091420Smarks 	ace_t *acep;
10107057Smarks 	dynaclstr_t *dstr;
10117057Smarks 	int len;
1012789Sahrens 
10137057Smarks 	if ((dstr = malloc(sizeof (dynaclstr_t))) == NULL)
10147057Smarks 		return;
10157057Smarks 	dstr->d_bufsize = ACE_ENTRY_SIZE;
10167057Smarks 	if ((dstr->d_aclexport = malloc(dstr->d_bufsize)) == NULL) {
10177057Smarks 		free(dstr);
10187057Smarks 		return;
10197057Smarks 	}
10207057Smarks 	*dstr->d_aclexport = '\0';
10217057Smarks 
10227057Smarks 	dstr->d_pos = 0;
10231420Smarks 	for (cnt = 0, acep = aclp->acl_aclp;
10241420Smarks 	    cnt != aclp->acl_cnt; cnt++, acep++) {
10257057Smarks 		dstr->d_aclexport[0] = '\0';
10267057Smarks 		dstr->d_pos = 0;
10277057Smarks 
10287057Smarks 		if (ace_type_txt(dstr, acep, 0))
10297057Smarks 			break;
10307057Smarks 		len = strlen(&dstr->d_aclexport[0]);
10317057Smarks 		if (ace_perm_txt(dstr, acep->a_access_mask, acep->a_flags,
10327057Smarks 		    aclp->acl_flags & ACL_IS_DIR, ACL_COMPACT_FMT))
10337057Smarks 			break;
10347057Smarks 		if (ace_inherit_txt(dstr, acep->a_flags, ACL_COMPACT_FMT))
10357057Smarks 			break;
10367057Smarks 		if (ace_access_txt(dstr, acep->a_type) == -1)
10377057Smarks 			break;
10387057Smarks 		(void) printf("    %20.*s%s\n", len, dstr->d_aclexport,
10397057Smarks 		    &dstr->d_aclexport[len]);
10401420Smarks 	}
10417057Smarks 
10427057Smarks 	if (dstr->d_aclexport)
10437057Smarks 		free(dstr->d_aclexport);
10447057Smarks 	free(dstr);
10451420Smarks }
1046789Sahrens 
10471420Smarks static void
10481420Smarks ace_printacl(acl_t *aclp, int cols, int compact)
10491420Smarks {
10501420Smarks 	int  slot = 0;
10511420Smarks 	char *token;
10521420Smarks 	char *acltext;
10531420Smarks 
10541420Smarks 	if (compact) {
10551420Smarks 		ace_compact_printacl(aclp);
10561420Smarks 		return;
1057789Sahrens 	}
1058789Sahrens 
10591420Smarks 	acltext = acl_totext(aclp, 0);
10601420Smarks 
10611420Smarks 	if (acltext == NULL)
10621420Smarks 		return;
10631420Smarks 
10641420Smarks 	token = strtok(acltext, ",");
10651420Smarks 	if (token == NULL) {
10661420Smarks 		free(acltext);
10671420Smarks 		return;
1068789Sahrens 	}
1069789Sahrens 
10701420Smarks 	do {
10711420Smarks 		(void) printf("     %d:", slot++);
10721420Smarks 		split_line(token, cols - 5);
10731420Smarks 	} while (token = strtok(NULL, ","));
10741420Smarks 	free(acltext);
10751420Smarks }
10761420Smarks 
10771420Smarks /*
10781420Smarks  * pretty print an ACL.
10791420Smarks  * For aclent_t ACL's the format is
10801420Smarks  * similar to the old format used by getfacl,
10811420Smarks  * with the addition of adding a "slot" number
10821420Smarks  * before each entry.
10831420Smarks  *
10841420Smarks  * for ace_t ACL's the cols variable will break up
10851420Smarks  * the long lines into multiple lines and will also
10861420Smarks  * print a "slot" number.
10871420Smarks  */
10881420Smarks void
10891420Smarks acl_printacl(acl_t *aclp, int cols, int compact)
10901420Smarks {
10911420Smarks 
10921420Smarks 	switch (aclp->acl_type) {
10931420Smarks 	case ACLENT_T:
10941420Smarks 		aclent_printacl(aclp);
10951420Smarks 		break;
10961420Smarks 	case ACE_T:
10971420Smarks 		ace_printacl(aclp, cols, compact);
10981420Smarks 		break;
10991420Smarks 	}
11001420Smarks }
11011420Smarks 
11021420Smarks typedef struct value_table {
11031420Smarks 	char		p_letter; /* perm letter such as 'r' */
11041420Smarks 	uint32_t	p_value; /* value for perm when pletter found */
11051420Smarks } value_table_t;
11061420Smarks 
11071420Smarks /*
11085331Samw  * The permission tables are laid out in positional order
11091420Smarks  * a '-' character will indicate a permission at a given
11101420Smarks  * position is not specified.  The '-' is not part of the
11111420Smarks  * table, but will be checked for in the permission computation
11121420Smarks  * routine.
11131420Smarks  */
11145331Samw value_table_t ace_perm_table[] = {
11151420Smarks 	{ 'r', ACE_READ_DATA},
11161420Smarks 	{ 'w', ACE_WRITE_DATA},
11171420Smarks 	{ 'x', ACE_EXECUTE},
11181420Smarks 	{ 'p', ACE_APPEND_DATA},
11191420Smarks 	{ 'd', ACE_DELETE},
11201420Smarks 	{ 'D', ACE_DELETE_CHILD},
11211420Smarks 	{ 'a', ACE_READ_ATTRIBUTES},
11221420Smarks 	{ 'A', ACE_WRITE_ATTRIBUTES},
11231420Smarks 	{ 'R', ACE_READ_NAMED_ATTRS},
11241420Smarks 	{ 'W', ACE_WRITE_NAMED_ATTRS},
11251420Smarks 	{ 'c', ACE_READ_ACL},
11261420Smarks 	{ 'C', ACE_WRITE_ACL},
11271420Smarks 	{ 'o', ACE_WRITE_OWNER},
11281420Smarks 	{ 's', ACE_SYNCHRONIZE}
11291420Smarks };
11301420Smarks 
11315331Samw #define	ACE_PERM_COUNT (sizeof (ace_perm_table) / sizeof (value_table_t))
11321420Smarks 
11335331Samw value_table_t aclent_perm_table[] = {
11341420Smarks 	{ 'r', S_IROTH},
11351420Smarks 	{ 'w', S_IWOTH},
11361420Smarks 	{ 'x', S_IXOTH}
11371420Smarks };
11381420Smarks 
11395331Samw #define	ACLENT_PERM_COUNT (sizeof (aclent_perm_table) / sizeof (value_table_t))
11405331Samw 
11415331Samw value_table_t inherit_table[] = {
11421420Smarks 	{'f', ACE_FILE_INHERIT_ACE},
11431420Smarks 	{'d', ACE_DIRECTORY_INHERIT_ACE},
11441420Smarks 	{'i', ACE_INHERIT_ONLY_ACE},
11451420Smarks 	{'n', ACE_NO_PROPAGATE_INHERIT_ACE},
11461420Smarks 	{'S', ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
11475331Samw 	{'F', ACE_FAILED_ACCESS_ACE_FLAG},
11485331Samw 	{'I', ACE_INHERITED_ACE}
11491420Smarks };
11501420Smarks 
11515331Samw #define	IFLAG_COUNT (sizeof (inherit_table) / sizeof (value_table_t))
11526269Smarks #define	IFLAG_COUNT_V1 6 /* Older version compatibility */
11535331Samw 
11541420Smarks /*
11551420Smarks  * compute value from a permission table or inheritance table
11561420Smarks  * based on string passed in.  If positional is set then
11571420Smarks  * string must match order in permtab, otherwise any order
11581420Smarks  * is allowed.
11591420Smarks  */
11601420Smarks int
11611420Smarks compute_values(value_table_t *permtab, int count,
11621420Smarks     char *permstr, int positional, uint32_t *mask)
11631420Smarks {
11641420Smarks 	uint32_t perm_val = 0;
11651420Smarks 	char *pstr;
11661420Smarks 	int i, found;
11671420Smarks 
11681420Smarks 	if (count < 0)
11691420Smarks 		return (1);
11701420Smarks 
11711420Smarks 	if (positional) {
11721420Smarks 		for (i = 0, pstr = permstr; i != count && pstr &&
11731420Smarks 		    *pstr; i++, pstr++) {
11741420Smarks 			if (*pstr == permtab[i].p_letter) {
11751420Smarks 				perm_val |= permtab[i].p_value;
11761420Smarks 			} else if (*pstr != '-') {
11771420Smarks 				return (1);
11781420Smarks 			}
1179789Sahrens 		}
11801420Smarks 	} else {  /* random order single letters with no '-' */
11811420Smarks 		for (pstr = permstr; pstr && *pstr; pstr++) {
11821420Smarks 			for (found = 0, i = 0; i != count; i++) {
11831420Smarks 				if (*pstr == permtab[i].p_letter) {
11841420Smarks 					perm_val |= permtab[i].p_value;
11851420Smarks 					found = 1;
11861420Smarks 					break;
11871420Smarks 				}
11881420Smarks 			}
11891420Smarks 			if (found == 0)
11901420Smarks 				return (1);
11911420Smarks 		}
1192789Sahrens 	}
1193789Sahrens 
11941420Smarks 	*mask = perm_val;
11951420Smarks 	return (0);
11961420Smarks }
1197789Sahrens 
11986269Smarks 
11996269Smarks int
12006269Smarks ace_inherit_helper(char *str, uint32_t *imask, int table_length)
12016269Smarks {
12026269Smarks 	int rc = 0;
12036269Smarks 
12046269Smarks 	if (strlen(str) == table_length) {
12056269Smarks 		/*
12066269Smarks 		 * If the string == table_length then first check to see it's
12076269Smarks 		 * in positional format.  If that fails then see if it's in
12086269Smarks 		 * non-positional format.
12096269Smarks 		 */
12106269Smarks 		if (compute_values(inherit_table, table_length, str,
12116269Smarks 		    1, imask) && compute_values(inherit_table,
12126269Smarks 		    table_length, str, 0, imask)) {
12136269Smarks 			rc = 1;
12146269Smarks 		}
12156269Smarks 	} else {
12166269Smarks 		rc = compute_values(inherit_table, table_length, str, 0, imask);
12176269Smarks 	}
12186269Smarks 
12196269Smarks 	return (rc ? EACL_INHERIT_ERROR : 0);
12206269Smarks }
12216269Smarks 
12221420Smarks /*
12231420Smarks  * compute value for inheritance flags.
12241420Smarks  */
12251420Smarks int
12261420Smarks compute_ace_inherit(char *str, uint32_t *imask)
12271420Smarks {
12286269Smarks 	int rc = 0;
1229789Sahrens 
12306269Smarks 	rc = ace_inherit_helper(str, imask, IFLAG_COUNT);
12316269Smarks 
12326269Smarks 	if (rc && strlen(str) != IFLAG_COUNT) {
12331420Smarks 
12346269Smarks 		/* is it an old formatted inherit string? */
12356269Smarks 		rc = ace_inherit_helper(str, imask, IFLAG_COUNT_V1);
12366269Smarks 	}
12371420Smarks 
12386269Smarks 	return (rc);
1239789Sahrens }
12401420Smarks 
12411420Smarks 
12421420Smarks /*
12431420Smarks  * compute value for ACE permissions.
12441420Smarks  */
12451420Smarks int
12461420Smarks compute_ace_perms(char *str, uint32_t *mask)
12471420Smarks {
12481420Smarks 	int positional = 0;
12491420Smarks 	int error;
12501420Smarks 
12511420Smarks 	if (strlen(str) == ACE_PERM_COUNT)
12521420Smarks 		positional = 1;
12531420Smarks 
12541420Smarks 	error = compute_values(ace_perm_table, ACE_PERM_COUNT,
12551420Smarks 	    str, positional, mask);
12561420Smarks 
12571420Smarks 	if (error && positional) {
12581420Smarks 		/*
12591420Smarks 		 * If positional was set, then make sure permissions
12601420Smarks 		 * aren't actually valid in non positional case where
12611420Smarks 		 * all permissions are specified, just in random order.
12621420Smarks 		 */
12631420Smarks 		error = compute_values(ace_perm_table,
12641420Smarks 		    ACE_PERM_COUNT, str, 0, mask);
12651420Smarks 	}
12661420Smarks 	if (error)
12671420Smarks 		error = EACL_PERM_MASK_ERROR;
12681420Smarks 
12691420Smarks 	return (error);
12701420Smarks }
12711420Smarks 
12721420Smarks 
12731420Smarks 
12741420Smarks /*
12751420Smarks  * compute values for aclent permissions.
12761420Smarks  */
12771420Smarks int
12781420Smarks compute_aclent_perms(char *str, o_mode_t *mask)
12791420Smarks {
12801420Smarks 	int error;
12811420Smarks 	uint32_t pmask;
12821420Smarks 
12831420Smarks 	if (strlen(str) != ACLENT_PERM_COUNT)
12841420Smarks 		return (EACL_PERM_MASK_ERROR);
12851420Smarks 
12861420Smarks 	*mask = 0;
12871420Smarks 	error = compute_values(aclent_perm_table, ACLENT_PERM_COUNT,
12881420Smarks 	    str, 1, &pmask);
12891420Smarks 	if (error == 0) {
12901420Smarks 		*mask = (o_mode_t)pmask;
12911420Smarks 	} else
12921420Smarks 		error = EACL_PERM_MASK_ERROR;
12931420Smarks 	return (error);
12941420Smarks }
12951420Smarks 
12961420Smarks /*
12971420Smarks  * determine ACE permissions.
12981420Smarks  */
12991420Smarks int
13001420Smarks ace_perm_mask(struct acl_perm_type *aclperm, uint32_t *mask)
13011420Smarks {
13021420Smarks 	int error;
13031420Smarks 
13041420Smarks 	if (aclperm->perm_style == PERM_TYPE_EMPTY) {
13051420Smarks 		*mask = 0;
13061420Smarks 		return (0);
13071420Smarks 	}
13081420Smarks 
13091420Smarks 	if (aclperm->perm_style == PERM_TYPE_ACE) {
13101420Smarks 		*mask = aclperm->perm_val;
13111420Smarks 		return (0);
13121420Smarks 	}
13131420Smarks 
13141420Smarks 	error = compute_ace_perms(aclperm->perm_str, mask);
13151420Smarks 	if (error) {
13161567Smarks 		acl_error(dgettext(TEXT_DOMAIN,
13171567Smarks 		    "Invalid permission(s) '%s' specified\n"),
13181420Smarks 		    aclperm->perm_str);
13191420Smarks 		return (EACL_PERM_MASK_ERROR);
13201420Smarks 	}
13211420Smarks 
13221420Smarks 	return (0);
13231420Smarks }
1324