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