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 buf[6] = '\0'; 544 *endp = buf + 6; 545 } else { 546 if (iflags & ACE_FILE_INHERIT_ACE) { 547 strcpy(lend, "file_inherit/"); 548 lend += sizeof ("file_inherit/") - 1; 549 } 550 if (iflags & ACE_DIRECTORY_INHERIT_ACE) { 551 strcpy(lend, "dir_inherit/"); 552 lend += sizeof ("dir_inherit/") - 1; 553 } 554 if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE) { 555 strcpy(lend, "no_propagate/"); 556 lend += sizeof ("no_propagate/") - 1; 557 } 558 if (iflags & ACE_INHERIT_ONLY_ACE) { 559 strcpy(lend, "inherit_only/"); 560 lend += sizeof ("inherit_only/") - 1; 561 } 562 563 if (*(lend - 1) == '/') 564 *--lend = '\0'; 565 *endp = lend; 566 } 567 568 return (buf); 569 } 570 571 /* 572 * Convert internal acl representation to external representation. 573 * 574 * The length of a non-owning user name or non-owning group name ie entries 575 * of type DEF_USER, USER, DEF_GROUP or GROUP, can exceed LOGNAME_MAX. We 576 * thus check the length of these entries, and if greater than LOGNAME_MAX, 577 * we realloc() via increase_length(). 578 * 579 * The LOGNAME_MAX, ENTRYTYPELEN and PERMS limits are otherwise always 580 * adhered to. 581 */ 582 583 /* 584 * acltotext() converts each ACL entry to look like this: 585 * 586 * entry_type:uid^gid^name:perms[:id] 587 * 588 * The maximum length of entry_type is 14 ("defaultgroup::" and 589 * "defaultother::") hence ENTRYTYPELEN is set to 14. 590 * 591 * The max length of a uid^gid^name entry (in theory) is 8, hence we use, 592 * however the ID could be a number so we therefore use ID_STR_MAX 593 * 594 * The length of a perms entry is 4 to allow for the comma appended to each 595 * to each acl entry. Hence PERMS is set to 4. 596 */ 597 598 #define ENTRYTYPELEN 14 599 #define PERMS 4 600 #define ACL_ENTRY_SIZE (ENTRYTYPELEN + ID_STR_MAX + PERMS + APPENDED_ID_MAX) 601 #define UPDATE_WHERE where = dstr->aclexport + strlen(dstr->aclexport) 602 603 char * 604 aclent_acltotext(aclent_t *aclp, int aclcnt, int flags) 605 { 606 char *aclexport; 607 char *where; 608 struct group *groupp = NULL; 609 struct passwd *passwdp = NULL; 610 struct dynaclstr *dstr; 611 int i, rtn; 612 size_t excess = 0; 613 char id[ID_STR_MAX], *idstr; 614 615 if (aclp == NULL) 616 return (NULL); 617 if ((dstr = malloc(sizeof (struct dynaclstr))) == NULL) 618 return (NULL); 619 dstr->bufsize = aclcnt * ACL_ENTRY_SIZE; 620 if ((dstr->aclexport = malloc(dstr->bufsize)) == NULL) { 621 free(dstr); 622 return (NULL); 623 } 624 *dstr->aclexport = '\0'; 625 where = dstr->aclexport; 626 627 for (i = 0; i < aclcnt; i++, aclp++) { 628 switch (aclp->a_type) { 629 case DEF_USER_OBJ: 630 case USER_OBJ: 631 if (aclp->a_type == USER_OBJ) 632 where = strappend(where, "user::"); 633 else 634 where = strappend(where, "defaultuser::"); 635 where = convert_perm(where, aclp->a_perm); 636 break; 637 case DEF_USER: 638 case USER: 639 if (aclp->a_type == USER) 640 where = strappend(where, "user:"); 641 else 642 where = strappend(where, "defaultuser:"); 643 if ((flags & ACL_NORESOLVE) == 0) 644 passwdp = getpwuid(aclp->a_id); 645 if (passwdp == (struct passwd *)NULL) { 646 /* put in uid instead */ 647 (void) sprintf(where, "%d", aclp->a_id); 648 UPDATE_WHERE; 649 } else { 650 excess = strlen(passwdp->pw_name) - LOGNAME_MAX; 651 if (excess > 0) { 652 rtn = increase_length(dstr, excess); 653 if (rtn == 1) { 654 UPDATE_WHERE; 655 } else { 656 free(dstr->aclexport); 657 free(dstr); 658 return (NULL); 659 } 660 } 661 where = strappend(where, passwdp->pw_name); 662 } 663 where = strappend(where, ":"); 664 where = convert_perm(where, aclp->a_perm); 665 break; 666 case DEF_GROUP_OBJ: 667 case GROUP_OBJ: 668 if (aclp->a_type == GROUP_OBJ) 669 where = strappend(where, "group::"); 670 else 671 where = strappend(where, "defaultgroup::"); 672 where = convert_perm(where, aclp->a_perm); 673 break; 674 case DEF_GROUP: 675 case GROUP: 676 if (aclp->a_type == GROUP) 677 where = strappend(where, "group:"); 678 else 679 where = strappend(where, "defaultgroup:"); 680 if ((flags & ACL_NORESOLVE) == 0) 681 groupp = getgrgid(aclp->a_id); 682 if (groupp == (struct group *)NULL) { 683 /* put in gid instead */ 684 (void) sprintf(where, "%d", aclp->a_id); 685 UPDATE_WHERE; 686 } else { 687 excess = strlen(groupp->gr_name) - LOGNAME_MAX; 688 if (excess > 0) { 689 rtn = increase_length(dstr, excess); 690 if (rtn == 1) { 691 UPDATE_WHERE; 692 } else { 693 free(dstr->aclexport); 694 free(dstr); 695 return (NULL); 696 } 697 } 698 where = strappend(where, groupp->gr_name); 699 } 700 where = strappend(where, ":"); 701 where = convert_perm(where, aclp->a_perm); 702 break; 703 case DEF_CLASS_OBJ: 704 case CLASS_OBJ: 705 if (aclp->a_type == CLASS_OBJ) 706 where = strappend(where, "mask:"); 707 else 708 where = strappend(where, "defaultmask:"); 709 where = convert_perm(where, aclp->a_perm); 710 break; 711 case DEF_OTHER_OBJ: 712 case OTHER_OBJ: 713 if (aclp->a_type == OTHER_OBJ) 714 where = strappend(where, "other:"); 715 else 716 where = strappend(where, "defaultother:"); 717 where = convert_perm(where, aclp->a_perm); 718 break; 719 default: 720 free(dstr->aclexport); 721 free(dstr); 722 return (NULL); 723 724 } 725 726 if ((flags & ACL_APPEND_ID) && ((aclp->a_type == USER) || 727 (aclp->a_type == DEF_USER) || (aclp->a_type == GROUP) || 728 (aclp->a_type == DEF_GROUP))) { 729 where = strappend(where, ":"); 730 id[ID_STR_MAX - 1] = '\0'; /* null terminate buffer */ 731 idstr = lltostr(aclp->a_id, &id[ID_STR_MAX - 1]); 732 where = strappend(where, idstr); 733 } 734 if (i < aclcnt - 1) 735 where = strappend(where, ","); 736 } 737 aclexport = dstr->aclexport; 738 free(dstr); 739 return (aclexport); 740 741 742 743 744 } 745 746 char * 747 acltotext(aclent_t *aclp, int aclcnt) 748 { 749 return (aclent_acltotext(aclp, aclcnt, 0)); 750 } 751 752 753 aclent_t * 754 aclfromtext(char *aclstr, int *aclcnt) 755 { 756 acl_t *aclp; 757 aclent_t *aclentp; 758 int error; 759 760 error = acl_fromtext(aclstr, &aclp); 761 if (error) 762 return (NULL); 763 764 aclentp = aclp->acl_aclp; 765 aclp->acl_aclp = NULL; 766 *aclcnt = aclp->acl_cnt; 767 768 acl_free(aclp); 769 return (aclentp); 770 } 771 772 773 static char * 774 strappend(char *where, char *newstr) 775 { 776 (void) strcat(where, newstr); 777 return (where + strlen(newstr)); 778 } 779 780 static char * 781 convert_perm(char *where, o_mode_t perm) 782 { 783 if (perm & S_IROTH) 784 where = strappend(where, "r"); 785 else 786 where = strappend(where, "-"); 787 if (perm & S_IWOTH) 788 where = strappend(where, "w"); 789 else 790 where = strappend(where, "-"); 791 if (perm & S_IXOTH) 792 where = strappend(where, "x"); 793 else 794 where = strappend(where, "-"); 795 /* perm is the last field */ 796 return (where); 797 } 798 799 /* 800 * Callers should check the return code as this routine may change the string 801 * pointer in dynaclstr. 802 */ 803 static int 804 increase_length(struct dynaclstr *dacl, size_t increase) 805 { 806 char *tptr; 807 size_t newsize; 808 809 newsize = dacl->bufsize + increase; 810 tptr = realloc(dacl->aclexport, newsize); 811 if (tptr != NULL) { 812 dacl->aclexport = tptr; 813 dacl->bufsize = newsize; 814 return (1); 815 } else 816 return (0); 817 } 818 819 /* 820 * ace_acltotext() convert each ace formatted acl to look like this: 821 * 822 * entry_type:uid^gid^name:perms[:flags]:<allow|deny>[:id][,] 823 * 824 * The maximum length of entry_type is 5 ("group") 825 * 826 * The max length of a uid^gid^name entry (in theory) is 8, 827 * however id could be a number so we therefore use ID_STR_MAX 828 * 829 * The length of a perms entry is 144 i.e read_data/write_data... 830 * to each acl entry. 831 * 832 * iflags: file_inherit/dir_inherit/inherit_only/no_propagate 833 * 834 */ 835 836 #define ACE_ENTRYTYPLEN 6 837 #define IFLAGS_SIZE 51 838 #define ACCESS_TYPE_SIZE 7 /* if unknown */ 839 #define COLON_CNT 3 840 #define PERMS_LEN 216 841 #define ACE_ENTRY_SIZE (ACE_ENTRYTYPLEN + ID_STR_MAX + PERMS_LEN +\ 842 ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT + APPENDED_ID_MAX) 843 844 static char * 845 ace_acltotext(acl_t *aceaclp, int flags) 846 { 847 ace_t *aclp = aceaclp->acl_aclp; 848 int aclcnt = aceaclp->acl_cnt; 849 char *aclexport; 850 char *endp; 851 int i; 852 char id[ID_STR_MAX], *idstr; 853 int isdir = (aceaclp->acl_flags & ACL_IS_DIR); 854 855 if (aclp == NULL) 856 return (NULL); 857 if ((aclexport = malloc(aclcnt * ACE_ENTRY_SIZE)) == NULL) 858 return (NULL); 859 860 aclexport[0] = '\0'; 861 endp = aclexport; 862 for (i = 0; i < aclcnt; i++, aclp++) { 863 864 (void) ace_type_txt(endp, &endp, aclp, flags); 865 *endp++ = ':'; 866 *endp = '\0'; 867 (void) ace_perm_txt(endp, &endp, aclp->a_access_mask, 868 aclp->a_flags, isdir, flags); 869 *endp++ = ':'; 870 *endp = '\0'; 871 (void) ace_inherit_txt(endp, &endp, aclp->a_flags, flags); 872 if (flags & ACL_COMPACT_FMT || aclp->a_flags & 873 (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE | 874 (ACE_INHERIT_ONLY_ACE | ACE_NO_PROPAGATE_INHERIT_ACE))) { 875 *endp++ = ':'; 876 *endp = '\0'; 877 } 878 (void) ace_access_txt(endp, &endp, aclp->a_type); 879 880 if ((flags & ACL_APPEND_ID) && 881 (((aclp->a_flags & ACE_TYPE_FLAGS) == 0) || 882 ((aclp->a_flags & ACE_TYPE_FLAGS) == 883 ACE_IDENTIFIER_GROUP))) { 884 *endp++ = ':'; 885 *endp = '\0'; 886 id[ID_STR_MAX -1] = '\0'; /* null terminate buffer */ 887 idstr = lltostr(aclp->a_who, &id[ID_STR_MAX - 1]); 888 strcpy(endp, idstr); 889 endp += strlen(idstr); 890 } 891 if (i < aclcnt - 1) { 892 *endp++ = ','; 893 *(endp + 1) = '\0'; 894 } 895 } 896 return (aclexport); 897 } 898 899 char * 900 acl_totext(acl_t *aclp, int flags) 901 { 902 903 char *txtp; 904 905 if (aclp == NULL) 906 return (NULL); 907 908 switch (aclp->acl_type) { 909 case ACE_T: 910 txtp = ace_acltotext(aclp, flags); 911 break; 912 case ACLENT_T: 913 txtp = aclent_acltotext(aclp->acl_aclp, aclp->acl_cnt, flags); 914 break; 915 } 916 917 return (txtp); 918 } 919 920 int 921 acl_fromtext(const char *acltextp, acl_t **ret_aclp) 922 { 923 int error; 924 char *buf; 925 926 buf = malloc(strlen(acltextp) + 2); 927 if (buf == NULL) 928 return (EACL_MEM_ERROR); 929 strcpy(buf, acltextp); 930 strcat(buf, "\n"); 931 yybuf = buf; 932 yyreset(); 933 error = yyparse(); 934 free(buf); 935 936 if (yyacl) { 937 if (error == 0) 938 *ret_aclp = yyacl; 939 else { 940 acl_free(yyacl); 941 } 942 yyacl = NULL; 943 } 944 return (error); 945 } 946 947 int 948 acl_parse(const char *acltextp, acl_t **aclp) 949 { 950 int error; 951 952 yyinteractive = 1; 953 error = acl_fromtext(acltextp, aclp); 954 yyinteractive = 0; 955 return (error); 956 } 957 958 static void 959 ace_compact_printacl(acl_t *aclp) 960 { 961 int cnt; 962 ace_t *acep; 963 char *endp; 964 char buf[ACE_ENTRY_SIZE]; 965 966 for (cnt = 0, acep = aclp->acl_aclp; 967 cnt != aclp->acl_cnt; cnt++, acep++) { 968 buf[0] = '\0'; 969 (void) printf(" %14s:", ace_type_txt(buf, &endp, acep, 0)); 970 (void) printf("%s:", ace_perm_txt(endp, &endp, 971 acep->a_access_mask, acep->a_flags, 972 aclp->acl_flags & ACL_IS_DIR, ACL_COMPACT_FMT)); 973 (void) printf("%s:", 974 ace_inherit_txt(endp, &endp, acep->a_flags, 975 ACL_COMPACT_FMT)); 976 (void) printf("%s\n", ace_access_txt(endp, &endp, 977 acep->a_type)); 978 } 979 } 980 981 static void 982 ace_printacl(acl_t *aclp, int cols, int compact) 983 { 984 int slot = 0; 985 char *token; 986 char *acltext; 987 988 if (compact) { 989 ace_compact_printacl(aclp); 990 return; 991 } 992 993 acltext = acl_totext(aclp, 0); 994 995 if (acltext == NULL) 996 return; 997 998 token = strtok(acltext, ","); 999 if (token == NULL) { 1000 free(acltext); 1001 return; 1002 } 1003 1004 do { 1005 (void) printf(" %d:", slot++); 1006 split_line(token, cols - 5); 1007 } while (token = strtok(NULL, ",")); 1008 free(acltext); 1009 } 1010 1011 /* 1012 * pretty print an ACL. 1013 * For aclent_t ACL's the format is 1014 * similar to the old format used by getfacl, 1015 * with the addition of adding a "slot" number 1016 * before each entry. 1017 * 1018 * for ace_t ACL's the cols variable will break up 1019 * the long lines into multiple lines and will also 1020 * print a "slot" number. 1021 */ 1022 void 1023 acl_printacl(acl_t *aclp, int cols, int compact) 1024 { 1025 1026 switch (aclp->acl_type) { 1027 case ACLENT_T: 1028 aclent_printacl(aclp); 1029 break; 1030 case ACE_T: 1031 ace_printacl(aclp, cols, compact); 1032 break; 1033 } 1034 } 1035 1036 typedef struct value_table { 1037 char p_letter; /* perm letter such as 'r' */ 1038 uint32_t p_value; /* value for perm when pletter found */ 1039 } value_table_t; 1040 1041 #define ACE_PERM_COUNT 14 1042 1043 /* 1044 * The permission tables are layed out in positional order 1045 * a '-' character will indicate a permission at a given 1046 * position is not specified. The '-' is not part of the 1047 * table, but will be checked for in the permission computation 1048 * routine. 1049 */ 1050 value_table_t ace_perm_table[ACE_PERM_COUNT] = { 1051 { 'r', ACE_READ_DATA}, 1052 { 'w', ACE_WRITE_DATA}, 1053 { 'x', ACE_EXECUTE}, 1054 { 'p', ACE_APPEND_DATA}, 1055 { 'd', ACE_DELETE}, 1056 { 'D', ACE_DELETE_CHILD}, 1057 { 'a', ACE_READ_ATTRIBUTES}, 1058 { 'A', ACE_WRITE_ATTRIBUTES}, 1059 { 'R', ACE_READ_NAMED_ATTRS}, 1060 { 'W', ACE_WRITE_NAMED_ATTRS}, 1061 { 'c', ACE_READ_ACL}, 1062 { 'C', ACE_WRITE_ACL}, 1063 { 'o', ACE_WRITE_OWNER}, 1064 { 's', ACE_SYNCHRONIZE} 1065 }; 1066 1067 #define ACLENT_PERM_COUNT 3 1068 1069 value_table_t aclent_perm_table[ACLENT_PERM_COUNT] = { 1070 { 'r', S_IROTH}, 1071 { 'w', S_IWOTH}, 1072 { 'x', S_IXOTH} 1073 }; 1074 1075 #define IFLAG_COUNT 6 1076 value_table_t inherit_table[IFLAG_COUNT] = { 1077 {'f', ACE_FILE_INHERIT_ACE}, 1078 {'d', ACE_DIRECTORY_INHERIT_ACE}, 1079 {'i', ACE_INHERIT_ONLY_ACE}, 1080 {'n', ACE_NO_PROPAGATE_INHERIT_ACE}, 1081 {'S', ACE_SUCCESSFUL_ACCESS_ACE_FLAG}, 1082 {'F', ACE_FAILED_ACCESS_ACE_FLAG} 1083 }; 1084 1085 /* 1086 * compute value from a permission table or inheritance table 1087 * based on string passed in. If positional is set then 1088 * string must match order in permtab, otherwise any order 1089 * is allowed. 1090 */ 1091 int 1092 compute_values(value_table_t *permtab, int count, 1093 char *permstr, int positional, uint32_t *mask) 1094 { 1095 uint32_t perm_val = 0; 1096 char *pstr; 1097 int i, found; 1098 1099 if (count < 0) 1100 return (1); 1101 1102 if (positional) { 1103 for (i = 0, pstr = permstr; i != count && pstr && 1104 *pstr; i++, pstr++) { 1105 if (*pstr == permtab[i].p_letter) { 1106 perm_val |= permtab[i].p_value; 1107 } else if (*pstr != '-') { 1108 return (1); 1109 } 1110 } 1111 } else { /* random order single letters with no '-' */ 1112 for (pstr = permstr; pstr && *pstr; pstr++) { 1113 for (found = 0, i = 0; i != count; i++) { 1114 if (*pstr == permtab[i].p_letter) { 1115 perm_val |= permtab[i].p_value; 1116 found = 1; 1117 break; 1118 } 1119 } 1120 if (found == 0) 1121 return (1); 1122 } 1123 } 1124 1125 *mask = perm_val; 1126 return (0); 1127 } 1128 1129 /* 1130 * compute value for inheritance flags. 1131 */ 1132 int 1133 compute_ace_inherit(char *str, uint32_t *imask) 1134 { 1135 int error; 1136 int positional = 0; 1137 1138 if (strlen(str) == IFLAG_COUNT) 1139 positional = 1; 1140 1141 error = compute_values(inherit_table, IFLAG_COUNT, 1142 str, positional, imask); 1143 1144 if (error) 1145 return (EACL_INHERIT_ERROR); 1146 1147 return (error); 1148 } 1149 1150 1151 /* 1152 * compute value for ACE permissions. 1153 */ 1154 int 1155 compute_ace_perms(char *str, uint32_t *mask) 1156 { 1157 int positional = 0; 1158 int error; 1159 1160 if (strlen(str) == ACE_PERM_COUNT) 1161 positional = 1; 1162 1163 error = compute_values(ace_perm_table, ACE_PERM_COUNT, 1164 str, positional, mask); 1165 1166 if (error && positional) { 1167 /* 1168 * If positional was set, then make sure permissions 1169 * aren't actually valid in non positional case where 1170 * all permissions are specified, just in random order. 1171 */ 1172 error = compute_values(ace_perm_table, 1173 ACE_PERM_COUNT, str, 0, mask); 1174 } 1175 if (error) 1176 error = EACL_PERM_MASK_ERROR; 1177 1178 return (error); 1179 } 1180 1181 1182 1183 /* 1184 * compute values for aclent permissions. 1185 */ 1186 int 1187 compute_aclent_perms(char *str, o_mode_t *mask) 1188 { 1189 int error; 1190 uint32_t pmask; 1191 1192 if (strlen(str) != ACLENT_PERM_COUNT) 1193 return (EACL_PERM_MASK_ERROR); 1194 1195 *mask = 0; 1196 error = compute_values(aclent_perm_table, ACLENT_PERM_COUNT, 1197 str, 1, &pmask); 1198 if (error == 0) { 1199 *mask = (o_mode_t)pmask; 1200 } else 1201 error = EACL_PERM_MASK_ERROR; 1202 return (error); 1203 } 1204 1205 /* 1206 * determine ACE permissions. 1207 */ 1208 int 1209 ace_perm_mask(struct acl_perm_type *aclperm, uint32_t *mask) 1210 { 1211 int error; 1212 1213 if (aclperm->perm_style == PERM_TYPE_EMPTY) { 1214 *mask = 0; 1215 return (0); 1216 } 1217 1218 if (aclperm->perm_style == PERM_TYPE_ACE) { 1219 *mask = aclperm->perm_val; 1220 return (0); 1221 } 1222 1223 error = compute_ace_perms(aclperm->perm_str, mask); 1224 if (error) { 1225 acl_error(dgettext(TEXT_DOMAIN, 1226 "Invalid permission(s) '%s' specified\n"), 1227 aclperm->perm_str); 1228 return (EACL_PERM_MASK_ERROR); 1229 } 1230 1231 return (0); 1232 } 1233