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