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