xref: /illumos-gate/usr/src/lib/libsec/common/acltext.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
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 2007 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, "%u", 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, "%u", 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 		if (iflags & ACE_INHERITED_ACE)
544 			buf[6] = 'I';
545 		else
546 			buf[6] = '-';
547 		buf[7] = '\0';
548 		*endp = buf + 7;
549 	} else {
550 		if (iflags & ACE_FILE_INHERIT_ACE) {
551 			strcpy(lend, "file_inherit/");
552 			lend += sizeof ("file_inherit/") - 1;
553 		}
554 		if (iflags & ACE_DIRECTORY_INHERIT_ACE) {
555 			strcpy(lend, "dir_inherit/");
556 			lend += sizeof ("dir_inherit/") - 1;
557 		}
558 		if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE) {
559 			strcpy(lend, "no_propagate/");
560 			lend += sizeof ("no_propagate/") - 1;
561 		}
562 		if (iflags & ACE_INHERIT_ONLY_ACE) {
563 			strcpy(lend, "inherit_only/");
564 			lend += sizeof ("inherit_only/") - 1;
565 		}
566 		if (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG) {
567 			strcpy(lend, "successful_access/");
568 			lend += sizeof ("successful_access/") - 1;
569 		}
570 		if (iflags & ACE_FAILED_ACCESS_ACE_FLAG) {
571 			strcpy(lend, "failed_access/");
572 			lend += sizeof ("failed_access/") - 1;
573 		}
574 		if (iflags & ACE_INHERITED_ACE) {
575 			strcpy(lend, "inherited/");
576 			lend += sizeof ("inherited/") - 1;
577 		}
578 
579 		if (*(lend - 1) == '/')
580 			*--lend = '\0';
581 		*endp = lend;
582 	}
583 
584 	return (buf);
585 }
586 
587 /*
588  * Convert internal acl representation to external representation.
589  *
590  * The length of a non-owning user name or non-owning group name ie entries
591  * of type DEF_USER, USER, DEF_GROUP or GROUP, can exceed LOGNAME_MAX.  We
592  * thus check the length of these entries, and if greater than LOGNAME_MAX,
593  * we realloc() via increase_length().
594  *
595  * The LOGNAME_MAX, ENTRYTYPELEN and PERMS limits are otherwise always
596  * adhered to.
597  */
598 
599 /*
600  * acltotext() converts each ACL entry to look like this:
601  *
602  *    entry_type:uid^gid^name:perms[:id]
603  *
604  * The maximum length of entry_type is 14 ("defaultgroup::" and
605  * "defaultother::") hence ENTRYTYPELEN is set to 14.
606  *
607  * The max length of a uid^gid^name entry (in theory) is 8, hence we use,
608  * however the ID could be a number so we therefore use ID_STR_MAX
609  *
610  * The length of a perms entry is 4 to allow for the comma appended to each
611  * to each acl entry.  Hence PERMS is set to 4.
612  */
613 
614 #define	ENTRYTYPELEN	14
615 #define	PERMS		4
616 #define	ACL_ENTRY_SIZE	(ENTRYTYPELEN + ID_STR_MAX + PERMS + APPENDED_ID_MAX)
617 #define	UPDATE_WHERE	where = dstr->aclexport + strlen(dstr->aclexport)
618 
619 char *
620 aclent_acltotext(aclent_t  *aclp, int aclcnt, int flags)
621 {
622 	char		*aclexport;
623 	char		*where;
624 	struct group	*groupp = NULL;
625 	struct passwd	*passwdp = NULL;
626 	struct dynaclstr *dstr;
627 	int		i, rtn;
628 	size_t		excess = 0;
629 	char		id[ID_STR_MAX], *idstr;
630 
631 	if (aclp == NULL)
632 		return (NULL);
633 	if ((dstr = malloc(sizeof (struct dynaclstr))) == NULL)
634 		return (NULL);
635 	dstr->bufsize = aclcnt * ACL_ENTRY_SIZE;
636 	if ((dstr->aclexport = malloc(dstr->bufsize)) == NULL) {
637 		free(dstr);
638 		return (NULL);
639 	}
640 	*dstr->aclexport = '\0';
641 	where = dstr->aclexport;
642 
643 	for (i = 0; i < aclcnt; i++, aclp++) {
644 		switch (aclp->a_type) {
645 		case DEF_USER_OBJ:
646 		case USER_OBJ:
647 			if (aclp->a_type == USER_OBJ)
648 				where = strappend(where, "user::");
649 			else
650 				where = strappend(where, "defaultuser::");
651 			where = convert_perm(where, aclp->a_perm);
652 			break;
653 		case DEF_USER:
654 		case USER:
655 			if (aclp->a_type == USER)
656 				where = strappend(where, "user:");
657 			else
658 				where = strappend(where, "defaultuser:");
659 			if ((flags & ACL_NORESOLVE) == 0)
660 				passwdp = getpwuid(aclp->a_id);
661 			if (passwdp == (struct passwd *)NULL) {
662 				/* put in uid instead */
663 				(void) sprintf(where, "%d", aclp->a_id);
664 				UPDATE_WHERE;
665 			} else {
666 				excess = strlen(passwdp->pw_name) - LOGNAME_MAX;
667 				if (excess > 0) {
668 					rtn = increase_length(dstr, excess);
669 					if (rtn == 1) {
670 						UPDATE_WHERE;
671 					} else {
672 						free(dstr->aclexport);
673 						free(dstr);
674 						return (NULL);
675 					}
676 				}
677 				where = strappend(where, passwdp->pw_name);
678 			}
679 			where = strappend(where, ":");
680 			where = convert_perm(where, aclp->a_perm);
681 			break;
682 		case DEF_GROUP_OBJ:
683 		case GROUP_OBJ:
684 			if (aclp->a_type == GROUP_OBJ)
685 				where = strappend(where, "group::");
686 			else
687 				where = strappend(where, "defaultgroup::");
688 			where = convert_perm(where, aclp->a_perm);
689 			break;
690 		case DEF_GROUP:
691 		case GROUP:
692 			if (aclp->a_type == GROUP)
693 				where = strappend(where, "group:");
694 			else
695 				where = strappend(where, "defaultgroup:");
696 			if ((flags & ACL_NORESOLVE) == 0)
697 				groupp = getgrgid(aclp->a_id);
698 			if (groupp == (struct group *)NULL) {
699 				/* put in gid instead */
700 				(void) sprintf(where, "%d", aclp->a_id);
701 				UPDATE_WHERE;
702 			} else {
703 				excess = strlen(groupp->gr_name) - LOGNAME_MAX;
704 				if (excess > 0) {
705 					rtn = increase_length(dstr, excess);
706 					if (rtn == 1) {
707 						UPDATE_WHERE;
708 					} else {
709 						free(dstr->aclexport);
710 						free(dstr);
711 						return (NULL);
712 					}
713 				}
714 				where = strappend(where, groupp->gr_name);
715 			}
716 			where = strappend(where, ":");
717 			where = convert_perm(where, aclp->a_perm);
718 			break;
719 		case DEF_CLASS_OBJ:
720 		case CLASS_OBJ:
721 			if (aclp->a_type == CLASS_OBJ)
722 				where = strappend(where, "mask:");
723 			else
724 				where = strappend(where, "defaultmask:");
725 			where = convert_perm(where, aclp->a_perm);
726 			break;
727 		case DEF_OTHER_OBJ:
728 		case OTHER_OBJ:
729 			if (aclp->a_type == OTHER_OBJ)
730 				where = strappend(where, "other:");
731 			else
732 				where = strappend(where, "defaultother:");
733 			where = convert_perm(where, aclp->a_perm);
734 			break;
735 		default:
736 			free(dstr->aclexport);
737 			free(dstr);
738 			return (NULL);
739 
740 		}
741 
742 		if ((flags & ACL_APPEND_ID) && ((aclp->a_type == USER) ||
743 		    (aclp->a_type == DEF_USER) || (aclp->a_type == GROUP) ||
744 		    (aclp->a_type == DEF_GROUP))) {
745 			where = strappend(where, ":");
746 			id[ID_STR_MAX - 1] = '\0'; /* null terminate buffer */
747 			idstr = lltostr(aclp->a_id, &id[ID_STR_MAX - 1]);
748 			where = strappend(where, idstr);
749 		}
750 		if (i < aclcnt - 1)
751 			where = strappend(where, ",");
752 	}
753 	aclexport = dstr->aclexport;
754 	free(dstr);
755 	return (aclexport);
756 
757 
758 
759 
760 }
761 
762 char *
763 acltotext(aclent_t *aclp, int aclcnt)
764 {
765 	return (aclent_acltotext(aclp, aclcnt, 0));
766 }
767 
768 
769 aclent_t *
770 aclfromtext(char *aclstr, int *aclcnt)
771 {
772 	acl_t *aclp;
773 	aclent_t *aclentp;
774 	int error;
775 
776 	error = acl_fromtext(aclstr, &aclp);
777 	if (error)
778 		return (NULL);
779 
780 	aclentp = aclp->acl_aclp;
781 	aclp->acl_aclp = NULL;
782 	*aclcnt = aclp->acl_cnt;
783 
784 	acl_free(aclp);
785 	return (aclentp);
786 }
787 
788 
789 static char *
790 strappend(char *where, char *newstr)
791 {
792 	(void) strcat(where, newstr);
793 	return (where + strlen(newstr));
794 }
795 
796 static char *
797 convert_perm(char *where, o_mode_t perm)
798 {
799 	if (perm & S_IROTH)
800 		where = strappend(where, "r");
801 	else
802 		where = strappend(where, "-");
803 	if (perm & S_IWOTH)
804 		where = strappend(where, "w");
805 	else
806 		where = strappend(where, "-");
807 	if (perm & S_IXOTH)
808 		where = strappend(where, "x");
809 	else
810 		where = strappend(where, "-");
811 	/* perm is the last field */
812 	return (where);
813 }
814 
815 /*
816  * Callers should check the return code as this routine may change the string
817  * pointer in dynaclstr.
818  */
819 static int
820 increase_length(struct dynaclstr *dacl, size_t increase)
821 {
822 	char *tptr;
823 	size_t newsize;
824 
825 	newsize = dacl->bufsize + increase;
826 	tptr = realloc(dacl->aclexport, newsize);
827 	if (tptr != NULL) {
828 		dacl->aclexport = tptr;
829 		dacl->bufsize = newsize;
830 		return (1);
831 	} else
832 		return (0);
833 }
834 
835 /*
836  * ace_acltotext() convert each ace formatted acl to look like this:
837  *
838  * entry_type:uid^gid^name:perms[:flags]:<allow|deny>[:id][,]
839  *
840  * The maximum length of entry_type is 5 ("group")
841  *
842  * The max length of a uid^gid^name entry (in theory) is 8,
843  * however id could be a number so we therefore use ID_STR_MAX
844  *
845  * The length of a perms entry is 144 i.e read_data/write_data...
846  * to each acl entry.
847  *
848  * iflags: file_inherit/dir_inherit/inherit_only/no_propagate/successful_access
849  *         /failed_access
850  *
851  */
852 
853 #define	ACE_ENTRYTYPLEN		6
854 #define	IFLAGS_STR "file_inherit/dir_inherit/inherit_only/no_propagate/" \
855 	"successful_access/failed_access/inherited"
856 #define	IFLAGS_SIZE		(sizeof (IFLAGS_STR) - 1)
857 #define	ACCESS_TYPE_SIZE	7	/* if unknown */
858 #define	COLON_CNT		3
859 #define	PERMS_LEN		216
860 #define	ACE_ENTRY_SIZE	(ACE_ENTRYTYPLEN + ID_STR_MAX + PERMS_LEN + \
861     ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT + APPENDED_ID_MAX)
862 
863 static char *
864 ace_acltotext(acl_t *aceaclp, int flags)
865 {
866 	ace_t		*aclp = aceaclp->acl_aclp;
867 	int		aclcnt = aceaclp->acl_cnt;
868 	char		*aclexport;
869 	char		*endp;
870 	int		i;
871 	char		id[ID_STR_MAX], *idstr;
872 	int		isdir = (aceaclp->acl_flags & ACL_IS_DIR);
873 
874 	if (aclp == NULL)
875 		return (NULL);
876 	if ((aclexport = malloc(aclcnt * ACE_ENTRY_SIZE)) == NULL)
877 		return (NULL);
878 
879 	aclexport[0] = '\0';
880 	endp = aclexport;
881 	for (i = 0; i < aclcnt; i++, aclp++) {
882 
883 		(void) ace_type_txt(endp, &endp, aclp, flags);
884 		*endp++ = ':';
885 		*endp = '\0';
886 		(void) ace_perm_txt(endp, &endp, aclp->a_access_mask,
887 		    aclp->a_flags, isdir, flags);
888 		*endp++ = ':';
889 		*endp = '\0';
890 		(void) ace_inherit_txt(endp, &endp, aclp->a_flags, flags);
891 		if (flags & ACL_COMPACT_FMT || aclp->a_flags &
892 		    (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE |
893 		    (ACE_INHERIT_ONLY_ACE | ACE_NO_PROPAGATE_INHERIT_ACE |
894 		    ACE_INHERITED_ACE | ACE_SUCCESSFUL_ACCESS_ACE_FLAG |
895 		    ACE_FAILED_ACCESS_ACE_FLAG))) {
896 			*endp++ = ':';
897 			*endp = '\0';
898 		}
899 		(void) ace_access_txt(endp, &endp, aclp->a_type);
900 
901 		if ((flags & ACL_APPEND_ID) &&
902 		    (((aclp->a_flags & ACE_TYPE_FLAGS) == 0) ||
903 		    ((aclp->a_flags & ACE_TYPE_FLAGS) ==
904 		    ACE_IDENTIFIER_GROUP))) {
905 			*endp++ = ':';
906 			*endp = '\0';
907 			id[ID_STR_MAX -1] = '\0'; /* null terminate buffer */
908 			idstr = lltostr(aclp->a_who, &id[ID_STR_MAX - 1]);
909 			strcpy(endp, idstr);
910 			endp += strlen(idstr);
911 		}
912 		if (i < aclcnt - 1) {
913 			*endp++ = ',';
914 			*(endp + 1) = '\0';
915 		}
916 	}
917 	return (aclexport);
918 }
919 
920 char *
921 acl_totext(acl_t *aclp, int flags)
922 {
923 
924 	char *txtp;
925 
926 	if (aclp == NULL)
927 		return (NULL);
928 
929 	switch (aclp->acl_type) {
930 	case ACE_T:
931 		txtp = ace_acltotext(aclp, flags);
932 		break;
933 	case ACLENT_T:
934 		txtp = aclent_acltotext(aclp->acl_aclp, aclp->acl_cnt, flags);
935 		break;
936 	}
937 
938 	return (txtp);
939 }
940 
941 int
942 acl_fromtext(const char *acltextp, acl_t **ret_aclp)
943 {
944 	int error;
945 	char *buf;
946 
947 	buf = malloc(strlen(acltextp) + 2);
948 	if (buf == NULL)
949 		return (EACL_MEM_ERROR);
950 	strcpy(buf, acltextp);
951 	strcat(buf, "\n");
952 	yybuf = buf;
953 	yyreset();
954 	error = yyparse();
955 	free(buf);
956 
957 	if (yyacl) {
958 		if (error == 0)
959 			*ret_aclp = yyacl;
960 		else {
961 			acl_free(yyacl);
962 		}
963 		yyacl = NULL;
964 	}
965 	return (error);
966 }
967 
968 int
969 acl_parse(const char *acltextp, acl_t **aclp)
970 {
971 	int error;
972 
973 	yyinteractive = 1;
974 	error = acl_fromtext(acltextp, aclp);
975 	yyinteractive = 0;
976 	return (error);
977 }
978 
979 static void
980 ace_compact_printacl(acl_t *aclp)
981 {
982 	int cnt;
983 	ace_t *acep;
984 	char *endp;
985 	char buf[ACE_ENTRY_SIZE];
986 
987 	for (cnt = 0, acep = aclp->acl_aclp;
988 	    cnt != aclp->acl_cnt; cnt++, acep++) {
989 		buf[0] = '\0';
990 		(void) printf("    %14s:", ace_type_txt(buf, &endp, acep, 0));
991 		(void) printf("%s:", ace_perm_txt(endp, &endp,
992 		    acep->a_access_mask, acep->a_flags,
993 		    aclp->acl_flags & ACL_IS_DIR, ACL_COMPACT_FMT));
994 		(void) printf("%s:",
995 		    ace_inherit_txt(endp, &endp, acep->a_flags,
996 		    ACL_COMPACT_FMT));
997 		(void) printf("%s\n", ace_access_txt(endp, &endp,
998 		    acep->a_type));
999 	}
1000 }
1001 
1002 static void
1003 ace_printacl(acl_t *aclp, int cols, int compact)
1004 {
1005 	int  slot = 0;
1006 	char *token;
1007 	char *acltext;
1008 
1009 	if (compact) {
1010 		ace_compact_printacl(aclp);
1011 		return;
1012 	}
1013 
1014 	acltext = acl_totext(aclp, 0);
1015 
1016 	if (acltext == NULL)
1017 		return;
1018 
1019 	token = strtok(acltext, ",");
1020 	if (token == NULL) {
1021 		free(acltext);
1022 		return;
1023 	}
1024 
1025 	do {
1026 		(void) printf("     %d:", slot++);
1027 		split_line(token, cols - 5);
1028 	} while (token = strtok(NULL, ","));
1029 	free(acltext);
1030 }
1031 
1032 /*
1033  * pretty print an ACL.
1034  * For aclent_t ACL's the format is
1035  * similar to the old format used by getfacl,
1036  * with the addition of adding a "slot" number
1037  * before each entry.
1038  *
1039  * for ace_t ACL's the cols variable will break up
1040  * the long lines into multiple lines and will also
1041  * print a "slot" number.
1042  */
1043 void
1044 acl_printacl(acl_t *aclp, int cols, int compact)
1045 {
1046 
1047 	switch (aclp->acl_type) {
1048 	case ACLENT_T:
1049 		aclent_printacl(aclp);
1050 		break;
1051 	case ACE_T:
1052 		ace_printacl(aclp, cols, compact);
1053 		break;
1054 	}
1055 }
1056 
1057 typedef struct value_table {
1058 	char		p_letter; /* perm letter such as 'r' */
1059 	uint32_t	p_value; /* value for perm when pletter found */
1060 } value_table_t;
1061 
1062 /*
1063  * The permission tables are laid out in positional order
1064  * a '-' character will indicate a permission at a given
1065  * position is not specified.  The '-' is not part of the
1066  * table, but will be checked for in the permission computation
1067  * routine.
1068  */
1069 value_table_t ace_perm_table[] = {
1070 	{ 'r', ACE_READ_DATA},
1071 	{ 'w', ACE_WRITE_DATA},
1072 	{ 'x', ACE_EXECUTE},
1073 	{ 'p', ACE_APPEND_DATA},
1074 	{ 'd', ACE_DELETE},
1075 	{ 'D', ACE_DELETE_CHILD},
1076 	{ 'a', ACE_READ_ATTRIBUTES},
1077 	{ 'A', ACE_WRITE_ATTRIBUTES},
1078 	{ 'R', ACE_READ_NAMED_ATTRS},
1079 	{ 'W', ACE_WRITE_NAMED_ATTRS},
1080 	{ 'c', ACE_READ_ACL},
1081 	{ 'C', ACE_WRITE_ACL},
1082 	{ 'o', ACE_WRITE_OWNER},
1083 	{ 's', ACE_SYNCHRONIZE}
1084 };
1085 
1086 #define	ACE_PERM_COUNT (sizeof (ace_perm_table) / sizeof (value_table_t))
1087 
1088 value_table_t aclent_perm_table[] = {
1089 	{ 'r', S_IROTH},
1090 	{ 'w', S_IWOTH},
1091 	{ 'x', S_IXOTH}
1092 };
1093 
1094 #define	ACLENT_PERM_COUNT (sizeof (aclent_perm_table) / sizeof (value_table_t))
1095 
1096 value_table_t inherit_table[] = {
1097 	{'f', ACE_FILE_INHERIT_ACE},
1098 	{'d', ACE_DIRECTORY_INHERIT_ACE},
1099 	{'i', ACE_INHERIT_ONLY_ACE},
1100 	{'n', ACE_NO_PROPAGATE_INHERIT_ACE},
1101 	{'S', ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
1102 	{'F', ACE_FAILED_ACCESS_ACE_FLAG},
1103 	{'I', ACE_INHERITED_ACE}
1104 };
1105 
1106 #define	IFLAG_COUNT (sizeof (inherit_table) / sizeof (value_table_t))
1107 
1108 /*
1109  * compute value from a permission table or inheritance table
1110  * based on string passed in.  If positional is set then
1111  * string must match order in permtab, otherwise any order
1112  * is allowed.
1113  */
1114 int
1115 compute_values(value_table_t *permtab, int count,
1116     char *permstr, int positional, uint32_t *mask)
1117 {
1118 	uint32_t perm_val = 0;
1119 	char *pstr;
1120 	int i, found;
1121 
1122 	if (count < 0)
1123 		return (1);
1124 
1125 	if (positional) {
1126 		for (i = 0, pstr = permstr; i != count && pstr &&
1127 		    *pstr; i++, pstr++) {
1128 			if (*pstr == permtab[i].p_letter) {
1129 				perm_val |= permtab[i].p_value;
1130 			} else if (*pstr != '-') {
1131 				return (1);
1132 			}
1133 		}
1134 	} else {  /* random order single letters with no '-' */
1135 		for (pstr = permstr; pstr && *pstr; pstr++) {
1136 			for (found = 0, i = 0; i != count; i++) {
1137 				if (*pstr == permtab[i].p_letter) {
1138 					perm_val |= permtab[i].p_value;
1139 					found = 1;
1140 					break;
1141 				}
1142 			}
1143 			if (found == 0)
1144 				return (1);
1145 		}
1146 	}
1147 
1148 	*mask = perm_val;
1149 	return (0);
1150 }
1151 
1152 /*
1153  * compute value for inheritance flags.
1154  */
1155 int
1156 compute_ace_inherit(char *str, uint32_t *imask)
1157 {
1158 	int error;
1159 	int positional = 0;
1160 
1161 	if (strlen(str) == IFLAG_COUNT)
1162 		positional = 1;
1163 
1164 	error = compute_values(inherit_table, IFLAG_COUNT,
1165 	    str, positional, imask);
1166 
1167 	if (error)
1168 		return (EACL_INHERIT_ERROR);
1169 
1170 	return (error);
1171 }
1172 
1173 
1174 /*
1175  * compute value for ACE permissions.
1176  */
1177 int
1178 compute_ace_perms(char *str, uint32_t *mask)
1179 {
1180 	int positional = 0;
1181 	int error;
1182 
1183 	if (strlen(str) == ACE_PERM_COUNT)
1184 		positional = 1;
1185 
1186 	error = compute_values(ace_perm_table, ACE_PERM_COUNT,
1187 	    str, positional, mask);
1188 
1189 	if (error && positional) {
1190 		/*
1191 		 * If positional was set, then make sure permissions
1192 		 * aren't actually valid in non positional case where
1193 		 * all permissions are specified, just in random order.
1194 		 */
1195 		error = compute_values(ace_perm_table,
1196 		    ACE_PERM_COUNT, str, 0, mask);
1197 	}
1198 	if (error)
1199 		error = EACL_PERM_MASK_ERROR;
1200 
1201 	return (error);
1202 }
1203 
1204 
1205 
1206 /*
1207  * compute values for aclent permissions.
1208  */
1209 int
1210 compute_aclent_perms(char *str, o_mode_t *mask)
1211 {
1212 	int error;
1213 	uint32_t pmask;
1214 
1215 	if (strlen(str) != ACLENT_PERM_COUNT)
1216 		return (EACL_PERM_MASK_ERROR);
1217 
1218 	*mask = 0;
1219 	error = compute_values(aclent_perm_table, ACLENT_PERM_COUNT,
1220 	    str, 1, &pmask);
1221 	if (error == 0) {
1222 		*mask = (o_mode_t)pmask;
1223 	} else
1224 		error = EACL_PERM_MASK_ERROR;
1225 	return (error);
1226 }
1227 
1228 /*
1229  * determine ACE permissions.
1230  */
1231 int
1232 ace_perm_mask(struct acl_perm_type *aclperm, uint32_t *mask)
1233 {
1234 	int error;
1235 
1236 	if (aclperm->perm_style == PERM_TYPE_EMPTY) {
1237 		*mask = 0;
1238 		return (0);
1239 	}
1240 
1241 	if (aclperm->perm_style == PERM_TYPE_ACE) {
1242 		*mask = aclperm->perm_val;
1243 		return (0);
1244 	}
1245 
1246 	error = compute_ace_perms(aclperm->perm_str, mask);
1247 	if (error) {
1248 		acl_error(dgettext(TEXT_DOMAIN,
1249 		    "Invalid permission(s) '%s' specified\n"),
1250 		    aclperm->perm_str);
1251 		return (EACL_PERM_MASK_ERROR);
1252 	}
1253 
1254 	return (0);
1255 }
1256