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