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