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