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