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