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