xref: /illumos-gate/usr/src/lib/libsec/common/acltext.c (revision 445f2479fe3d7435daab18bf2cdc310b86cd6738)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 /*LINTLIBRARY*/
28 
29 #include <grp.h>
30 #include <pwd.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/acl.h>
39 #include <aclutils.h>
40 
41 #define	ID_STR_MAX	20	/* digits in LONG_MAX */
42 
43 #define	APPENDED_ID_MAX	ID_STR_MAX + 1		/* id + colon */
44 /*
45  * yyinteractive controls whether yyparse should print out
46  * error messages to stderr, and whether or not id's should be
47  * allowed from acl_fromtext().
48  */
49 int	yyinteractive;
50 acl_t	*yyacl;
51 char	*yybuf;
52 
53 extern acl_t *acl_alloc(enum acl_type);
54 
55 
56 struct dynaclstr {
57 	size_t bufsize;		/* current size of aclexport */
58 	char *aclexport;
59 };
60 
61 static char *strappend(char *, char *);
62 static char *convert_perm(char *, o_mode_t);
63 static int increase_length(struct dynaclstr *, size_t);
64 
65 static void
66 aclent_perms(int perm, char *txt_perms)
67 {
68 	if (perm & S_IROTH)
69 		txt_perms[0] = 'r';
70 	else
71 		txt_perms[0] = '-';
72 	if (perm & S_IWOTH)
73 		txt_perms[1] = 'w';
74 	else
75 		txt_perms[1] = '-';
76 	if (perm & S_IXOTH)
77 		txt_perms[2] = 'x';
78 	else
79 		txt_perms[2] = '-';
80 	txt_perms[3] = '\0';
81 }
82 
83 static char *
84 pruname(uid_t uid, char *uidp, size_t buflen, int noresolve)
85 {
86 	struct passwd	*passwdp = NULL;
87 
88 	if (noresolve == 0)
89 		passwdp = getpwuid(uid);
90 	if (passwdp == (struct passwd *)NULL) {
91 		/* could not get passwd information: display uid instead */
92 		(void) snprintf(uidp, buflen, "%ld", (long)uid);
93 	} else {
94 		(void) strlcpy(uidp, passwdp->pw_name, buflen);
95 	}
96 	return (uidp);
97 }
98 
99 static char *
100 prgname(gid_t gid, char *gidp, size_t buflen, int noresolve)
101 {
102 	struct group	*groupp = NULL;
103 
104 	if (noresolve == 0)
105 		groupp = getgrgid(gid);
106 	if (groupp == (struct group *)NULL) {
107 		/* could not get group information: display gid instead */
108 		(void) snprintf(gidp, buflen, "%ld", (long)gid);
109 	} else {
110 		(void) strlcpy(gidp, groupp->gr_name, buflen);
111 	}
112 	return (gidp);
113 }
114 static void
115 aclent_printacl(acl_t *aclp)
116 {
117 	aclent_t *tp;
118 	int aclcnt;
119 	int mask;
120 	int slot = 0;
121 	char perm[4];
122 	char uidp[ID_STR_MAX];
123 	char gidp[ID_STR_MAX];
124 
125 	/* display ACL: assume it is sorted. */
126 	aclcnt = aclp->acl_cnt;
127 	for (tp = aclp->acl_aclp; tp && aclcnt--; tp++) {
128 		if (tp->a_type == CLASS_OBJ)
129 			mask = tp->a_perm;
130 	}
131 	aclcnt = aclp->acl_cnt;
132 	for (tp = aclp->acl_aclp; aclcnt--; tp++) {
133 		(void) printf("     %d:", slot++);
134 		switch (tp->a_type) {
135 		case USER:
136 			aclent_perms(tp->a_perm, perm);
137 			(void) printf("user:%s:%s\t\t",
138 			    pruname(tp->a_id, uidp, sizeof (uidp), 0), perm);
139 			aclent_perms((tp->a_perm & mask), perm);
140 			(void) printf("#effective:%s\n", perm);
141 			break;
142 		case USER_OBJ:
143 			/* no need to display uid */
144 			aclent_perms(tp->a_perm, perm);
145 			(void) printf("user::%s\n", perm);
146 			break;
147 		case GROUP:
148 			aclent_perms(tp->a_perm, perm);
149 			(void) printf("group:%s:%s\t\t",
150 			    prgname(tp->a_id, gidp, sizeof (gidp), 0), perm);
151 			aclent_perms(tp->a_perm & mask, perm);
152 			(void) printf("#effective:%s\n", perm);
153 			break;
154 		case GROUP_OBJ:
155 			aclent_perms(tp->a_perm, perm);
156 			(void) printf("group::%s\t\t", perm);
157 			aclent_perms(tp->a_perm & mask, perm);
158 			(void) printf("#effective:%s\n", perm);
159 			break;
160 		case CLASS_OBJ:
161 			aclent_perms(tp->a_perm, perm);
162 			(void) printf("mask:%s\n", perm);
163 			break;
164 		case OTHER_OBJ:
165 			aclent_perms(tp->a_perm, perm);
166 			(void) printf("other:%s\n", perm);
167 			break;
168 		case DEF_USER:
169 			aclent_perms(tp->a_perm, perm);
170 			(void) printf("default:user:%s:%s\n",
171 			    pruname(tp->a_id, uidp, sizeof (uidp), 0), perm);
172 			break;
173 		case DEF_USER_OBJ:
174 			aclent_perms(tp->a_perm, perm);
175 			(void) printf("default:user::%s\n", perm);
176 			break;
177 		case DEF_GROUP:
178 			aclent_perms(tp->a_perm, perm);
179 			(void) printf("default:group:%s:%s\n",
180 			    prgname(tp->a_id, gidp, sizeof (gidp), 0), perm);
181 			break;
182 		case DEF_GROUP_OBJ:
183 			aclent_perms(tp->a_perm, perm);
184 			(void) printf("default:group::%s\n", perm);
185 			break;
186 		case DEF_CLASS_OBJ:
187 			aclent_perms(tp->a_perm, perm);
188 			(void) printf("default:mask:%s\n", perm);
189 			break;
190 		case DEF_OTHER_OBJ:
191 			aclent_perms(tp->a_perm, perm);
192 			(void) printf("default:other:%s\n", perm);
193 			break;
194 		default:
195 			(void) fprintf(stderr,
196 			    dgettext(TEXT_DOMAIN, "unrecognized entry\n"));
197 			break;
198 		}
199 	}
200 }
201 
202 static void
203 split_line(char *str, int cols)
204 {
205 	char *ptr;
206 	int len;
207 	int i;
208 	int last_split;
209 	char *pad = "";
210 	int pad_len;
211 
212 	len = strlen(str);
213 	ptr = str;
214 	pad_len = 0;
215 
216 	ptr = str;
217 	last_split = 0;
218 	for (i = 0; i != len; i++) {
219 		if ((i + pad_len + 4) >= cols) {
220 			(void) printf("%s%.*s\n", pad, last_split, ptr);
221 			ptr = &ptr[last_split];
222 			len = strlen(ptr);
223 			i = 0;
224 			pad_len = 4;
225 			pad = "         ";
226 		} else {
227 			if (ptr[i] == '/' || ptr[i] == ':') {
228 				last_split = i;
229 			}
230 		}
231 	}
232 	if (i == len) {
233 		(void) printf("%s%s\n", pad, ptr);
234 	}
235 }
236 
237 #define	OWNERAT_TXT	"owner@"
238 #define	GROUPAT_TXT	"group@"
239 #define	EVERYONEAT_TXT	"everyone@"
240 #define	GROUP_TXT	"group:"
241 #define	USER_TXT	"user:"
242 
243 char *
244 ace_type_txt(char *buf, char **endp, ace_t *acep, int flags)
245 {
246 
247 	char idp[ID_STR_MAX];
248 
249 	if (buf == NULL)
250 		return (NULL);
251 
252 	switch (acep->a_flags & ACE_TYPE_FLAGS) {
253 	case ACE_OWNER:
254 		strcpy(buf, OWNERAT_TXT);
255 		*endp = buf + sizeof (OWNERAT_TXT) - 1;
256 		break;
257 
258 	case ACE_GROUP|ACE_IDENTIFIER_GROUP:
259 		strcpy(buf, GROUPAT_TXT);
260 		*endp = buf + sizeof (GROUPAT_TXT) - 1;
261 		break;
262 
263 	case ACE_IDENTIFIER_GROUP:
264 		strcpy(buf, GROUP_TXT);
265 		strcat(buf, prgname(acep->a_who, idp,
266 		    sizeof (idp), flags & ACL_NORESOLVE));
267 		*endp = buf + strlen(buf);
268 		break;
269 
270 	case ACE_EVERYONE:
271 		strcpy(buf, EVERYONEAT_TXT);
272 		*endp = buf + sizeof (EVERYONEAT_TXT) - 1;
273 		break;
274 
275 	case 0:
276 		strcpy(buf, USER_TXT);
277 		strcat(buf, pruname(acep->a_who, idp,
278 		    sizeof (idp), flags & ACL_NORESOLVE));
279 		*endp = buf + strlen(buf);
280 		break;
281 	}
282 
283 	return (buf);
284 }
285 
286 #define	READ_DATA_TXT	"read_data/"
287 #define	WRITE_DATA_TXT	"write_data/"
288 #define	EXECUTE_TXT	"execute/"
289 #define	READ_XATTR_TXT	"read_xattr/"
290 #define	WRITE_XATTR_TXT	"write_xattr/"
291 #define	READ_ATTRIBUTES_TXT "read_attributes/"
292 #define	WRITE_ATTRIBUTES_TXT "write_attributes/"
293 #define	DELETE_TXT	"delete/"
294 #define	DELETE_CHILD_TXT "delete_child/"
295 #define	WRITE_OWNER_TXT "write_owner/"
296 #define	READ_ACL_TXT	"read_acl/"
297 #define	WRITE_ACL_TXT	"write_acl/"
298 #define	APPEND_DATA_TXT "append_data/"
299 #define	READ_DIR_TXT	"list_directory/read_data/"
300 #define	ADD_DIR_TXT	"add_subdirectory/append_data/"
301 #define	ADD_FILE_TXT	"add_file/write_data/"
302 #define	SYNCHRONIZE_TXT "synchronize"	/* not slash on this one */
303 
304 char *
305 ace_perm_txt(char *buf, char **endp, uint32_t mask,
306     uint32_t iflags, int isdir, int flags)
307 {
308 	char *lend = buf;		/* local end */
309 
310 	if (buf == NULL)
311 		return (NULL);
312 
313 	if (flags & ACL_COMPACT_FMT) {
314 
315 		if (mask & ACE_READ_DATA)
316 			buf[0] = 'r';
317 		else
318 			buf[0] = '-';
319 		if (mask & ACE_WRITE_DATA)
320 			buf[1] = 'w';
321 		else
322 			buf[1] = '-';
323 		if (mask & ACE_EXECUTE)
324 			buf[2] = 'x';
325 		else
326 			buf[2] = '-';
327 		if (mask & ACE_APPEND_DATA)
328 			buf[3] = 'p';
329 		else
330 			buf[3] = '-';
331 		if (mask & ACE_DELETE)
332 			buf[4] = 'd';
333 		else
334 			buf[4] = '-';
335 		if (mask & ACE_DELETE_CHILD)
336 			buf[5] = 'D';
337 		else
338 			buf[5] = '-';
339 		if (mask & ACE_READ_ATTRIBUTES)
340 			buf[6] = 'a';
341 		else
342 			buf[6] = '-';
343 		if (mask & ACE_WRITE_ATTRIBUTES)
344 			buf[7] = 'A';
345 		else
346 			buf[7] = '-';
347 		if (mask & ACE_READ_NAMED_ATTRS)
348 			buf[8] = 'R';
349 		else
350 			buf[8] = '-';
351 		if (mask & ACE_WRITE_NAMED_ATTRS)
352 			buf[9] = 'W';
353 		else
354 			buf[9] = '-';
355 		if (mask & ACE_READ_ACL)
356 			buf[10] = 'c';
357 		else
358 			buf[10] = '-';
359 		if (mask & ACE_WRITE_ACL)
360 			buf[11] = 'C';
361 		else
362 			buf[11] = '-';
363 		if (mask & ACE_WRITE_OWNER)
364 			buf[12] = 'o';
365 		else
366 			buf[12] = '-';
367 		if (mask & ACE_SYNCHRONIZE)
368 			buf[13] = 's';
369 		else
370 			buf[13] = '-';
371 		buf[14] = '\0';
372 		*endp = buf + 14;
373 		return (buf);
374 	} else {
375 		/*
376 		 * If ACE is a directory, but inheritance indicates its
377 		 * for a file then print permissions for file rather than
378 		 * dir.
379 		 */
380 		if (isdir) {
381 			if (mask & ACE_LIST_DIRECTORY) {
382 				if (iflags == ACE_FILE_INHERIT_ACE) {
383 					strcpy(lend, READ_DATA_TXT);
384 					lend += sizeof (READ_DATA_TXT) - 1;
385 				} else {
386 					strcpy(lend, READ_DIR_TXT);
387 					lend += sizeof (READ_DIR_TXT) - 1;
388 				}
389 			}
390 			if (mask & ACE_ADD_FILE) {
391 				if (iflags == ACE_FILE_INHERIT_ACE) {
392 					strcpy(lend, WRITE_DATA_TXT);
393 					lend += sizeof (WRITE_DATA_TXT) - 1;
394 				} else {
395 					strcpy(lend, ADD_FILE_TXT);
396 					lend +=
397 					    sizeof (ADD_FILE_TXT) -1;
398 				}
399 			}
400 			if (mask & ACE_ADD_SUBDIRECTORY) {
401 				if (iflags == ACE_FILE_INHERIT_ACE) {
402 					strcpy(lend, APPEND_DATA_TXT);
403 					lend += sizeof (APPEND_DATA_TXT) - 1;
404 				} else {
405 					strcpy(lend, ADD_DIR_TXT);
406 					lend += sizeof (ADD_DIR_TXT) - 1;
407 				}
408 			}
409 		} else {
410 			if (mask & ACE_READ_DATA) {
411 				strcpy(lend, READ_DATA_TXT);
412 				lend += sizeof (READ_DATA_TXT) - 1;
413 			}
414 			if (mask & ACE_WRITE_DATA) {
415 				strcpy(lend, WRITE_DATA_TXT);
416 				lend += sizeof (WRITE_DATA_TXT) - 1;
417 			}
418 			if (mask & ACE_APPEND_DATA) {
419 				strcpy(lend, APPEND_DATA_TXT);
420 				lend += sizeof (APPEND_DATA_TXT) - 1;
421 			}
422 		}
423 		if (mask & ACE_READ_NAMED_ATTRS) {
424 			strcpy(lend, READ_XATTR_TXT);
425 			lend += sizeof (READ_XATTR_TXT) - 1;
426 		}
427 		if (mask & ACE_WRITE_NAMED_ATTRS) {
428 			strcpy(lend, WRITE_XATTR_TXT);
429 			lend += sizeof (WRITE_XATTR_TXT) - 1;
430 		}
431 		if (mask & ACE_EXECUTE) {
432 			strcpy(lend, EXECUTE_TXT);
433 			lend += sizeof (EXECUTE_TXT) - 1;
434 		}
435 		if (mask & ACE_DELETE_CHILD) {
436 			strcpy(lend, DELETE_CHILD_TXT);
437 			lend += sizeof (DELETE_CHILD_TXT) - 1;
438 		}
439 		if (mask & ACE_READ_ATTRIBUTES) {
440 			strcpy(lend, READ_ATTRIBUTES_TXT);
441 			lend += sizeof (READ_ATTRIBUTES_TXT) - 1;
442 		}
443 		if (mask & ACE_WRITE_ATTRIBUTES) {
444 			strcpy(lend, WRITE_ATTRIBUTES_TXT);
445 			lend += sizeof (WRITE_ATTRIBUTES_TXT) - 1;
446 		}
447 		if (mask & ACE_DELETE) {
448 			strcpy(lend, DELETE_TXT);
449 			lend += sizeof (DELETE_TXT) - 1;
450 		}
451 		if (mask & ACE_READ_ACL) {
452 			strcpy(lend, READ_ACL_TXT);
453 			lend += sizeof (READ_ACL_TXT) - 1;
454 		}
455 		if (mask & ACE_WRITE_ACL) {
456 			strcpy(lend, WRITE_ACL_TXT);
457 			lend += sizeof (WRITE_ACL_TXT) - 1;
458 		}
459 		if (mask & ACE_WRITE_OWNER) {
460 			strcpy(lend, WRITE_OWNER_TXT);
461 			lend += sizeof (WRITE_OWNER_TXT) - 1;
462 		}
463 		if (mask & ACE_SYNCHRONIZE) {
464 			strcpy(lend, SYNCHRONIZE_TXT);
465 			lend += sizeof (SYNCHRONIZE_TXT) - 1;
466 		}
467 
468 		if (*(lend - 1) == '/')
469 			*--lend = '\0';
470 	}
471 
472 	*endp = lend;
473 	return (buf);
474 }
475 
476 #define	ALLOW_TXT	"allow"
477 #define	DENY_TXT	"deny"
478 #define	ALARM_TXT	"alarm"
479 #define	AUDIT_TXT	"audit"
480 #define	UNKNOWN_TXT	"unknown"
481 char *
482 ace_access_txt(char *buf, char **endp, int type)
483 {
484 
485 	if (buf == NULL)
486 		return (NULL);
487 
488 	if (type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
489 		strcpy(buf, ALLOW_TXT);
490 		*endp += sizeof (ALLOW_TXT) - 1;
491 	} else if (type == ACE_ACCESS_DENIED_ACE_TYPE) {
492 		strcpy(buf, DENY_TXT);
493 		*endp += sizeof (DENY_TXT) - 1;
494 	} else if (type == ACE_SYSTEM_AUDIT_ACE_TYPE) {
495 		strcpy(buf, AUDIT_TXT);
496 		*endp += sizeof (AUDIT_TXT) - 1;
497 	} else if (type == ACE_SYSTEM_ALARM_ACE_TYPE) {
498 		strcpy(buf, ALARM_TXT);
499 		*endp += sizeof (ALARM_TXT) - 1;
500 	} else {
501 		strcpy(buf, UNKNOWN_TXT);
502 		*endp += sizeof (UNKNOWN_TXT) - 1;
503 	}
504 
505 	return (buf);
506 }
507 
508 static char *
509 ace_inherit_txt(char *buf, char **endp, uint32_t iflags, int flags)
510 {
511 
512 	char *lend = buf;
513 
514 	if (buf == NULL) {
515 		return (NULL);
516 	}
517 
518 	if (flags & ACL_COMPACT_FMT) {
519 		if (iflags & ACE_FILE_INHERIT_ACE)
520 			buf[0] = 'f';
521 		else
522 			buf[0] = '-';
523 		if (iflags & ACE_DIRECTORY_INHERIT_ACE)
524 			buf[1] = 'd';
525 		else
526 			buf[1] = '-';
527 		if (iflags & ACE_INHERIT_ONLY_ACE)
528 			buf[2] = 'i';
529 		else
530 			buf[2] = '-';
531 		if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)
532 			buf[3] = 'n';
533 		else
534 			buf[3] = '-';
535 		if (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
536 			buf[4] = 'S';
537 		else
538 			buf[4] = '-';
539 		if (iflags & ACE_FAILED_ACCESS_ACE_FLAG)
540 			buf[5] = 'F';
541 		else
542 			buf[5] = '-';
543 		buf[6] = '\0';
544 		*endp = buf + 6;
545 	} else {
546 		if (iflags & ACE_FILE_INHERIT_ACE) {
547 			strcpy(lend, "file_inherit/");
548 			lend += sizeof ("file_inherit/") - 1;
549 		}
550 		if (iflags & ACE_DIRECTORY_INHERIT_ACE) {
551 			strcpy(lend, "dir_inherit/");
552 			lend += sizeof ("dir_inherit/") - 1;
553 		}
554 		if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE) {
555 			strcpy(lend, "no_propagate/");
556 			lend += sizeof ("no_propagate/") - 1;
557 		}
558 		if (iflags & ACE_INHERIT_ONLY_ACE) {
559 			strcpy(lend, "inherit_only/");
560 			lend += sizeof ("inherit_only/") - 1;
561 		}
562 
563 		if (*(lend - 1) == '/')
564 			*--lend = '\0';
565 		*endp = lend;
566 	}
567 
568 	return (buf);
569 }
570 
571 /*
572  * Convert internal acl representation to external representation.
573  *
574  * The length of a non-owning user name or non-owning group name ie entries
575  * of type DEF_USER, USER, DEF_GROUP or GROUP, can exceed LOGNAME_MAX.  We
576  * thus check the length of these entries, and if greater than LOGNAME_MAX,
577  * we realloc() via increase_length().
578  *
579  * The LOGNAME_MAX, ENTRYTYPELEN and PERMS limits are otherwise always
580  * adhered to.
581  */
582 
583 /*
584  * acltotext() converts each ACL entry to look like this:
585  *
586  *    entry_type:uid^gid^name:perms[:id]
587  *
588  * The maximum length of entry_type is 14 ("defaultgroup::" and
589  * "defaultother::") hence ENTRYTYPELEN is set to 14.
590  *
591  * The max length of a uid^gid^name entry (in theory) is 8, hence we use,
592  * however the ID could be a number so we therefore use ID_STR_MAX
593  *
594  * The length of a perms entry is 4 to allow for the comma appended to each
595  * to each acl entry.  Hence PERMS is set to 4.
596  */
597 
598 #define	ENTRYTYPELEN	14
599 #define	PERMS		4
600 #define	ACL_ENTRY_SIZE	(ENTRYTYPELEN + ID_STR_MAX + PERMS + APPENDED_ID_MAX)
601 #define	UPDATE_WHERE	where = dstr->aclexport + strlen(dstr->aclexport)
602 
603 char *
604 aclent_acltotext(aclent_t  *aclp, int aclcnt, int flags)
605 {
606 	char		*aclexport;
607 	char		*where;
608 	struct group	*groupp = NULL;
609 	struct passwd	*passwdp = NULL;
610 	struct dynaclstr *dstr;
611 	int		i, rtn;
612 	size_t		excess = 0;
613 	char		id[ID_STR_MAX], *idstr;
614 
615 	if (aclp == NULL)
616 		return (NULL);
617 	if ((dstr = malloc(sizeof (struct dynaclstr))) == NULL)
618 		return (NULL);
619 	dstr->bufsize = aclcnt * ACL_ENTRY_SIZE;
620 	if ((dstr->aclexport = malloc(dstr->bufsize)) == NULL) {
621 		free(dstr);
622 		return (NULL);
623 	}
624 	*dstr->aclexport = '\0';
625 	where = dstr->aclexport;
626 
627 	for (i = 0; i < aclcnt; i++, aclp++) {
628 		switch (aclp->a_type) {
629 		case DEF_USER_OBJ:
630 		case USER_OBJ:
631 			if (aclp->a_type == USER_OBJ)
632 				where = strappend(where, "user::");
633 			else
634 				where = strappend(where, "defaultuser::");
635 			where = convert_perm(where, aclp->a_perm);
636 			break;
637 		case DEF_USER:
638 		case USER:
639 			if (aclp->a_type == USER)
640 				where = strappend(where, "user:");
641 			else
642 				where = strappend(where, "defaultuser:");
643 			if ((flags & ACL_NORESOLVE) == 0)
644 				passwdp = getpwuid(aclp->a_id);
645 			if (passwdp == (struct passwd *)NULL) {
646 				/* put in uid instead */
647 				(void) sprintf(where, "%d", aclp->a_id);
648 				UPDATE_WHERE;
649 			} else {
650 				excess = strlen(passwdp->pw_name) - LOGNAME_MAX;
651 				if (excess > 0) {
652 					rtn = increase_length(dstr, excess);
653 					if (rtn == 1) {
654 						UPDATE_WHERE;
655 					} else {
656 						free(dstr->aclexport);
657 						free(dstr);
658 						return (NULL);
659 					}
660 				}
661 				where = strappend(where, passwdp->pw_name);
662 			}
663 			where = strappend(where, ":");
664 			where = convert_perm(where, aclp->a_perm);
665 			break;
666 		case DEF_GROUP_OBJ:
667 		case GROUP_OBJ:
668 			if (aclp->a_type == GROUP_OBJ)
669 				where = strappend(where, "group::");
670 			else
671 				where = strappend(where, "defaultgroup::");
672 			where = convert_perm(where, aclp->a_perm);
673 			break;
674 		case DEF_GROUP:
675 		case GROUP:
676 			if (aclp->a_type == GROUP)
677 				where = strappend(where, "group:");
678 			else
679 				where = strappend(where, "defaultgroup:");
680 			if ((flags & ACL_NORESOLVE) == 0)
681 				groupp = getgrgid(aclp->a_id);
682 			if (groupp == (struct group *)NULL) {
683 				/* put in gid instead */
684 				(void) sprintf(where, "%d", aclp->a_id);
685 				UPDATE_WHERE;
686 			} else {
687 				excess = strlen(groupp->gr_name) - LOGNAME_MAX;
688 				if (excess > 0) {
689 					rtn = increase_length(dstr, excess);
690 					if (rtn == 1) {
691 						UPDATE_WHERE;
692 					} else {
693 						free(dstr->aclexport);
694 						free(dstr);
695 						return (NULL);
696 					}
697 				}
698 				where = strappend(where, groupp->gr_name);
699 			}
700 			where = strappend(where, ":");
701 			where = convert_perm(where, aclp->a_perm);
702 			break;
703 		case DEF_CLASS_OBJ:
704 		case CLASS_OBJ:
705 			if (aclp->a_type == CLASS_OBJ)
706 				where = strappend(where, "mask:");
707 			else
708 				where = strappend(where, "defaultmask:");
709 			where = convert_perm(where, aclp->a_perm);
710 			break;
711 		case DEF_OTHER_OBJ:
712 		case OTHER_OBJ:
713 			if (aclp->a_type == OTHER_OBJ)
714 				where = strappend(where, "other:");
715 			else
716 				where = strappend(where, "defaultother:");
717 			where = convert_perm(where, aclp->a_perm);
718 			break;
719 		default:
720 			free(dstr->aclexport);
721 			free(dstr);
722 			return (NULL);
723 
724 		}
725 
726 		if ((flags & ACL_APPEND_ID) && ((aclp->a_type == USER) ||
727 		    (aclp->a_type == DEF_USER) || (aclp->a_type == GROUP) ||
728 		    (aclp->a_type == DEF_GROUP))) {
729 			where = strappend(where, ":");
730 			id[ID_STR_MAX - 1] = '\0'; /* null terminate buffer */
731 			idstr = lltostr(aclp->a_id, &id[ID_STR_MAX - 1]);
732 			where = strappend(where, idstr);
733 		}
734 		if (i < aclcnt - 1)
735 			where = strappend(where, ",");
736 	}
737 	aclexport = dstr->aclexport;
738 	free(dstr);
739 	return (aclexport);
740 
741 
742 
743 
744 }
745 
746 char *
747 acltotext(aclent_t *aclp, int aclcnt)
748 {
749 	return (aclent_acltotext(aclp, aclcnt, 0));
750 }
751 
752 
753 aclent_t *
754 aclfromtext(char *aclstr, int *aclcnt)
755 {
756 	acl_t *aclp;
757 	aclent_t *aclentp;
758 	int error;
759 
760 	error = acl_fromtext(aclstr, &aclp);
761 	if (error)
762 		return (NULL);
763 
764 	aclentp = aclp->acl_aclp;
765 	aclp->acl_aclp = NULL;
766 	*aclcnt = aclp->acl_cnt;
767 
768 	acl_free(aclp);
769 	return (aclentp);
770 }
771 
772 
773 static char *
774 strappend(char *where, char *newstr)
775 {
776 	(void) strcat(where, newstr);
777 	return (where + strlen(newstr));
778 }
779 
780 static char *
781 convert_perm(char *where, o_mode_t perm)
782 {
783 	if (perm & S_IROTH)
784 		where = strappend(where, "r");
785 	else
786 		where = strappend(where, "-");
787 	if (perm & S_IWOTH)
788 		where = strappend(where, "w");
789 	else
790 		where = strappend(where, "-");
791 	if (perm & S_IXOTH)
792 		where = strappend(where, "x");
793 	else
794 		where = strappend(where, "-");
795 	/* perm is the last field */
796 	return (where);
797 }
798 
799 /*
800  * Callers should check the return code as this routine may change the string
801  * pointer in dynaclstr.
802  */
803 static int
804 increase_length(struct dynaclstr *dacl, size_t increase)
805 {
806 	char *tptr;
807 	size_t newsize;
808 
809 	newsize = dacl->bufsize + increase;
810 	tptr = realloc(dacl->aclexport, newsize);
811 	if (tptr != NULL) {
812 		dacl->aclexport = tptr;
813 		dacl->bufsize = newsize;
814 		return (1);
815 	} else
816 		return (0);
817 }
818 
819 /*
820  * ace_acltotext() convert each ace formatted acl to look like this:
821  *
822  * entry_type:uid^gid^name:perms[:flags]:<allow|deny>[:id][,]
823  *
824  * The maximum length of entry_type is 5 ("group")
825  *
826  * The max length of a uid^gid^name entry (in theory) is 8,
827  * however id could be a number so we therefore use ID_STR_MAX
828  *
829  * The length of a perms entry is 144 i.e read_data/write_data...
830  * to each acl entry.
831  *
832  * iflags: file_inherit/dir_inherit/inherit_only/no_propagate
833  *
834  */
835 
836 #define	ACE_ENTRYTYPLEN		6
837 #define	IFLAGS_SIZE		51
838 #define	ACCESS_TYPE_SIZE	7	/* if unknown */
839 #define	COLON_CNT		3
840 #define	PERMS_LEN		216
841 #define	ACE_ENTRY_SIZE	(ACE_ENTRYTYPLEN + ID_STR_MAX + PERMS_LEN +\
842     ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT + APPENDED_ID_MAX)
843 
844 static char *
845 ace_acltotext(acl_t *aceaclp, int flags)
846 {
847 	ace_t		*aclp = aceaclp->acl_aclp;
848 	int		aclcnt = aceaclp->acl_cnt;
849 	char		*aclexport;
850 	char		*endp;
851 	int		i;
852 	char		id[ID_STR_MAX], *idstr;
853 	int		isdir = (aceaclp->acl_flags & ACL_IS_DIR);
854 
855 	if (aclp == NULL)
856 		return (NULL);
857 	if ((aclexport = malloc(aclcnt * ACE_ENTRY_SIZE)) == NULL)
858 		return (NULL);
859 
860 	aclexport[0] = '\0';
861 	endp = aclexport;
862 	for (i = 0; i < aclcnt; i++, aclp++) {
863 
864 		(void) ace_type_txt(endp, &endp, aclp, flags);
865 		*endp++ = ':';
866 		*endp = '\0';
867 		(void) ace_perm_txt(endp, &endp, aclp->a_access_mask,
868 		    aclp->a_flags, isdir, flags);
869 		*endp++ = ':';
870 		*endp = '\0';
871 		(void) ace_inherit_txt(endp, &endp, aclp->a_flags, flags);
872 		if (flags & ACL_COMPACT_FMT || aclp->a_flags &
873 		    (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE |
874 		    (ACE_INHERIT_ONLY_ACE | ACE_NO_PROPAGATE_INHERIT_ACE))) {
875 			*endp++ = ':';
876 			*endp = '\0';
877 		}
878 		(void) ace_access_txt(endp, &endp, aclp->a_type);
879 
880 		if ((flags & ACL_APPEND_ID) &&
881 		    (((aclp->a_flags & ACE_TYPE_FLAGS) == 0) ||
882 		    ((aclp->a_flags & ACE_TYPE_FLAGS) ==
883 		    ACE_IDENTIFIER_GROUP))) {
884 			*endp++ = ':';
885 			*endp = '\0';
886 			id[ID_STR_MAX -1] = '\0'; /* null terminate buffer */
887 			idstr = lltostr(aclp->a_who, &id[ID_STR_MAX - 1]);
888 			strcpy(endp, idstr);
889 			endp += strlen(idstr);
890 		}
891 		if (i < aclcnt - 1) {
892 			*endp++ = ',';
893 			*(endp + 1) = '\0';
894 		}
895 	}
896 	return (aclexport);
897 }
898 
899 char *
900 acl_totext(acl_t *aclp, int flags)
901 {
902 
903 	char *txtp;
904 
905 	if (aclp == NULL)
906 		return (NULL);
907 
908 	switch (aclp->acl_type) {
909 	case ACE_T:
910 		txtp = ace_acltotext(aclp, flags);
911 		break;
912 	case ACLENT_T:
913 		txtp = aclent_acltotext(aclp->acl_aclp, aclp->acl_cnt, flags);
914 		break;
915 	}
916 
917 	return (txtp);
918 }
919 
920 int
921 acl_fromtext(const char *acltextp, acl_t **ret_aclp)
922 {
923 	int error;
924 	char *buf;
925 
926 	buf = malloc(strlen(acltextp) + 2);
927 	if (buf == NULL)
928 		return (EACL_MEM_ERROR);
929 	strcpy(buf, acltextp);
930 	strcat(buf, "\n");
931 	yybuf = buf;
932 	yyreset();
933 	error = yyparse();
934 	free(buf);
935 
936 	if (yyacl) {
937 		if (error == 0)
938 			*ret_aclp = yyacl;
939 		else {
940 			acl_free(yyacl);
941 		}
942 		yyacl = NULL;
943 	}
944 	return (error);
945 }
946 
947 int
948 acl_parse(const char *acltextp, acl_t **aclp)
949 {
950 	int error;
951 
952 	yyinteractive = 1;
953 	error = acl_fromtext(acltextp, aclp);
954 	yyinteractive = 0;
955 	return (error);
956 }
957 
958 static void
959 ace_compact_printacl(acl_t *aclp)
960 {
961 	int cnt;
962 	ace_t *acep;
963 	char *endp;
964 	char buf[ACE_ENTRY_SIZE];
965 
966 	for (cnt = 0, acep = aclp->acl_aclp;
967 	    cnt != aclp->acl_cnt; cnt++, acep++) {
968 		buf[0] = '\0';
969 		(void) printf("    %14s:", ace_type_txt(buf, &endp, acep, 0));
970 		(void) printf("%s:", ace_perm_txt(endp, &endp,
971 		    acep->a_access_mask, acep->a_flags,
972 		    aclp->acl_flags & ACL_IS_DIR, ACL_COMPACT_FMT));
973 		(void) printf("%s:",
974 		    ace_inherit_txt(endp, &endp, acep->a_flags,
975 			ACL_COMPACT_FMT));
976 		(void) printf("%s\n", ace_access_txt(endp, &endp,
977 		    acep->a_type));
978 	}
979 }
980 
981 static void
982 ace_printacl(acl_t *aclp, int cols, int compact)
983 {
984 	int  slot = 0;
985 	char *token;
986 	char *acltext;
987 
988 	if (compact) {
989 		ace_compact_printacl(aclp);
990 		return;
991 	}
992 
993 	acltext = acl_totext(aclp, 0);
994 
995 	if (acltext == NULL)
996 		return;
997 
998 	token = strtok(acltext, ",");
999 	if (token == NULL) {
1000 		free(acltext);
1001 		return;
1002 	}
1003 
1004 	do {
1005 		(void) printf("     %d:", slot++);
1006 		split_line(token, cols - 5);
1007 	} while (token = strtok(NULL, ","));
1008 	free(acltext);
1009 }
1010 
1011 /*
1012  * pretty print an ACL.
1013  * For aclent_t ACL's the format is
1014  * similar to the old format used by getfacl,
1015  * with the addition of adding a "slot" number
1016  * before each entry.
1017  *
1018  * for ace_t ACL's the cols variable will break up
1019  * the long lines into multiple lines and will also
1020  * print a "slot" number.
1021  */
1022 void
1023 acl_printacl(acl_t *aclp, int cols, int compact)
1024 {
1025 
1026 	switch (aclp->acl_type) {
1027 	case ACLENT_T:
1028 		aclent_printacl(aclp);
1029 		break;
1030 	case ACE_T:
1031 		ace_printacl(aclp, cols, compact);
1032 		break;
1033 	}
1034 }
1035 
1036 typedef struct value_table {
1037 	char		p_letter; /* perm letter such as 'r' */
1038 	uint32_t	p_value; /* value for perm when pletter found */
1039 } value_table_t;
1040 
1041 #define	ACE_PERM_COUNT 14
1042 
1043 /*
1044  * The permission tables are layed out in positional order
1045  * a '-' character will indicate a permission at a given
1046  * position is not specified.  The '-' is not part of the
1047  * table, but will be checked for in the permission computation
1048  * routine.
1049  */
1050 value_table_t ace_perm_table[ACE_PERM_COUNT] = {
1051 	{ 'r', ACE_READ_DATA},
1052 	{ 'w', ACE_WRITE_DATA},
1053 	{ 'x', ACE_EXECUTE},
1054 	{ 'p', ACE_APPEND_DATA},
1055 	{ 'd', ACE_DELETE},
1056 	{ 'D', ACE_DELETE_CHILD},
1057 	{ 'a', ACE_READ_ATTRIBUTES},
1058 	{ 'A', ACE_WRITE_ATTRIBUTES},
1059 	{ 'R', ACE_READ_NAMED_ATTRS},
1060 	{ 'W', ACE_WRITE_NAMED_ATTRS},
1061 	{ 'c', ACE_READ_ACL},
1062 	{ 'C', ACE_WRITE_ACL},
1063 	{ 'o', ACE_WRITE_OWNER},
1064 	{ 's', ACE_SYNCHRONIZE}
1065 };
1066 
1067 #define	ACLENT_PERM_COUNT 3
1068 
1069 value_table_t aclent_perm_table[ACLENT_PERM_COUNT] = {
1070 	{ 'r', S_IROTH},
1071 	{ 'w', S_IWOTH},
1072 	{ 'x', S_IXOTH}
1073 };
1074 
1075 #define	IFLAG_COUNT	6
1076 value_table_t inherit_table[IFLAG_COUNT] = {
1077 	{'f', ACE_FILE_INHERIT_ACE},
1078 	{'d', ACE_DIRECTORY_INHERIT_ACE},
1079 	{'i', ACE_INHERIT_ONLY_ACE},
1080 	{'n', ACE_NO_PROPAGATE_INHERIT_ACE},
1081 	{'S', ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
1082 	{'F', ACE_FAILED_ACCESS_ACE_FLAG}
1083 };
1084 
1085 /*
1086  * compute value from a permission table or inheritance table
1087  * based on string passed in.  If positional is set then
1088  * string must match order in permtab, otherwise any order
1089  * is allowed.
1090  */
1091 int
1092 compute_values(value_table_t *permtab, int count,
1093     char *permstr, int positional, uint32_t *mask)
1094 {
1095 	uint32_t perm_val = 0;
1096 	char *pstr;
1097 	int i, found;
1098 
1099 	if (count < 0)
1100 		return (1);
1101 
1102 	if (positional) {
1103 		for (i = 0, pstr = permstr; i != count && pstr &&
1104 		    *pstr; i++, pstr++) {
1105 			if (*pstr == permtab[i].p_letter) {
1106 				perm_val |= permtab[i].p_value;
1107 			} else if (*pstr != '-') {
1108 				return (1);
1109 			}
1110 		}
1111 	} else {  /* random order single letters with no '-' */
1112 		for (pstr = permstr; pstr && *pstr; pstr++) {
1113 			for (found = 0, i = 0; i != count; i++) {
1114 				if (*pstr == permtab[i].p_letter) {
1115 					perm_val |= permtab[i].p_value;
1116 					found = 1;
1117 					break;
1118 				}
1119 			}
1120 			if (found == 0)
1121 				return (1);
1122 		}
1123 	}
1124 
1125 	*mask = perm_val;
1126 	return (0);
1127 }
1128 
1129 /*
1130  * compute value for inheritance flags.
1131  */
1132 int
1133 compute_ace_inherit(char *str, uint32_t *imask)
1134 {
1135 	int error;
1136 	int positional = 0;
1137 
1138 	if (strlen(str) == IFLAG_COUNT)
1139 		positional = 1;
1140 
1141 	error = compute_values(inherit_table, IFLAG_COUNT,
1142 	    str, positional, imask);
1143 
1144 	if (error)
1145 		return (EACL_INHERIT_ERROR);
1146 
1147 	return (error);
1148 }
1149 
1150 
1151 /*
1152  * compute value for ACE permissions.
1153  */
1154 int
1155 compute_ace_perms(char *str, uint32_t *mask)
1156 {
1157 	int positional = 0;
1158 	int error;
1159 
1160 	if (strlen(str) == ACE_PERM_COUNT)
1161 		positional = 1;
1162 
1163 	error = compute_values(ace_perm_table, ACE_PERM_COUNT,
1164 	    str, positional, mask);
1165 
1166 	if (error && positional) {
1167 		/*
1168 		 * If positional was set, then make sure permissions
1169 		 * aren't actually valid in non positional case where
1170 		 * all permissions are specified, just in random order.
1171 		 */
1172 		error = compute_values(ace_perm_table,
1173 		    ACE_PERM_COUNT, str, 0, mask);
1174 	}
1175 	if (error)
1176 		error = EACL_PERM_MASK_ERROR;
1177 
1178 	return (error);
1179 }
1180 
1181 
1182 
1183 /*
1184  * compute values for aclent permissions.
1185  */
1186 int
1187 compute_aclent_perms(char *str, o_mode_t *mask)
1188 {
1189 	int error;
1190 	uint32_t pmask;
1191 
1192 	if (strlen(str) != ACLENT_PERM_COUNT)
1193 		return (EACL_PERM_MASK_ERROR);
1194 
1195 	*mask = 0;
1196 	error = compute_values(aclent_perm_table, ACLENT_PERM_COUNT,
1197 	    str, 1, &pmask);
1198 	if (error == 0) {
1199 		*mask = (o_mode_t)pmask;
1200 	} else
1201 		error = EACL_PERM_MASK_ERROR;
1202 	return (error);
1203 }
1204 
1205 /*
1206  * determine ACE permissions.
1207  */
1208 int
1209 ace_perm_mask(struct acl_perm_type *aclperm, uint32_t *mask)
1210 {
1211 	int error;
1212 
1213 	if (aclperm->perm_style == PERM_TYPE_EMPTY) {
1214 		*mask = 0;
1215 		return (0);
1216 	}
1217 
1218 	if (aclperm->perm_style == PERM_TYPE_ACE) {
1219 		*mask = aclperm->perm_val;
1220 		return (0);
1221 	}
1222 
1223 	error = compute_ace_perms(aclperm->perm_str, mask);
1224 	if (error) {
1225 		acl_error(dgettext(TEXT_DOMAIN,
1226 		    "Invalid permission(s) '%s' specified\n"),
1227 		    aclperm->perm_str);
1228 		return (EACL_PERM_MASK_ERROR);
1229 	}
1230 
1231 	return (0);
1232 }
1233