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