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