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