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