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