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 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 * 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 * 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 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 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 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 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 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 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 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 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 * 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 * 782 acltotext(aclent_t *aclp, int aclcnt) 783 { 784 return (aclent_acltotext(aclp, aclcnt, 0)); 785 } 786 787 788 aclent_t * 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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