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