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