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