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