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