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 28 #include <stdlib.h> 29 #include <string.h> 30 #include <unistd.h> 31 #include <limits.h> 32 #include <grp.h> 33 #include <pwd.h> 34 #include <strings.h> 35 #include <sys/types.h> 36 #include <sys/acl.h> 37 #include <errno.h> 38 #include <sys/stat.h> 39 #include <sys/varargs.h> 40 #include <locale.h> 41 #include <aclutils.h> 42 #include <acl_common.h> 43 #include <sys/avl.h> 44 45 #define offsetof(s, m) ((size_t)(&(((s *)0)->m))) 46 47 #define ACL_PATH 0 48 #define ACL_FD 1 49 50 #define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \ 51 ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \ 52 ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL) 53 54 55 #define ACL_SYNCHRONIZE_SET_DENY 0x0000001 56 #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002 57 #define ACL_SYNCHRONIZE_ERR_DENY 0x0000004 58 #define ACL_SYNCHRONIZE_ERR_ALLOW 0x0000008 59 60 #define ACL_WRITE_OWNER_SET_DENY 0x0000010 61 #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020 62 #define ACL_WRITE_OWNER_ERR_DENY 0x0000040 63 #define ACL_WRITE_OWNER_ERR_ALLOW 0x0000080 64 65 #define ACL_DELETE_SET_DENY 0x0000100 66 #define ACL_DELETE_SET_ALLOW 0x0000200 67 #define ACL_DELETE_ERR_DENY 0x0000400 68 #define ACL_DELETE_ERR_ALLOW 0x0000800 69 70 #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000 71 #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000 72 #define ACL_WRITE_ATTRS_OWNER_ERR_DENY 0x0004000 73 #define ACL_WRITE_ATTRS_OWNER_ERR_ALLOW 0x0008000 74 75 #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000 76 #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000 77 #define ACL_WRITE_ATTRS_WRITER_ERR_DENY 0x0040000 78 #define ACL_WRITE_ATTRS_WRITER_ERR_ALLOW 0x0080000 79 80 #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000 81 #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000 82 #define ACL_WRITE_NAMED_WRITER_ERR_DENY 0x0400000 83 #define ACL_WRITE_NAMED_WRITER_ERR_ALLOW 0x0800000 84 85 #define ACL_READ_NAMED_READER_SET_DENY 0x1000000 86 #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000 87 #define ACL_READ_NAMED_READER_ERR_DENY 0x4000000 88 #define ACL_READ_NAMED_READER_ERR_ALLOW 0x8000000 89 90 91 #define ACE_VALID_MASK_BITS (\ 92 ACE_READ_DATA | \ 93 ACE_LIST_DIRECTORY | \ 94 ACE_WRITE_DATA | \ 95 ACE_ADD_FILE | \ 96 ACE_APPEND_DATA | \ 97 ACE_ADD_SUBDIRECTORY | \ 98 ACE_READ_NAMED_ATTRS | \ 99 ACE_WRITE_NAMED_ATTRS | \ 100 ACE_EXECUTE | \ 101 ACE_DELETE_CHILD | \ 102 ACE_READ_ATTRIBUTES | \ 103 ACE_WRITE_ATTRIBUTES | \ 104 ACE_DELETE | \ 105 ACE_READ_ACL | \ 106 ACE_WRITE_ACL | \ 107 ACE_WRITE_OWNER | \ 108 ACE_SYNCHRONIZE) 109 110 #define ACE_MASK_UNDEFINED 0x80000000 111 112 #define ACE_VALID_FLAG_BITS (ACE_FILE_INHERIT_ACE | \ 113 ACE_DIRECTORY_INHERIT_ACE | \ 114 ACE_NO_PROPAGATE_INHERIT_ACE | ACE_INHERIT_ONLY_ACE | \ 115 ACE_SUCCESSFUL_ACCESS_ACE_FLAG | ACE_FAILED_ACCESS_ACE_FLAG | \ 116 ACE_IDENTIFIER_GROUP | ACE_OWNER | ACE_GROUP | ACE_EVERYONE) 117 118 /* 119 * ACL conversion helpers 120 */ 121 122 typedef enum { 123 ace_unused, 124 ace_user_obj, 125 ace_user, 126 ace_group, /* includes GROUP and GROUP_OBJ */ 127 ace_other_obj 128 } ace_to_aent_state_t; 129 130 typedef struct acevals { 131 uid_t key; 132 avl_node_t avl; 133 uint32_t mask; 134 uint32_t allowed; 135 uint32_t denied; 136 int aent_type; 137 } acevals_t; 138 139 typedef struct ace_list { 140 acevals_t user_obj; 141 avl_tree_t user; 142 int numusers; 143 acevals_t group_obj; 144 avl_tree_t group; 145 int numgroups; 146 acevals_t other_obj; 147 uint32_t acl_mask; 148 int hasmask; 149 int dfacl_flag; 150 ace_to_aent_state_t state; 151 int seen; /* bitmask of all aclent_t a_type values seen */ 152 } ace_list_t; 153 154 typedef union { 155 const char *file; 156 int fd; 157 } acl_inp; 158 159 acl_t * 160 acl_alloc(enum acl_type type) 161 { 162 acl_t *aclp; 163 164 aclp = malloc(sizeof (acl_t)); 165 166 if (aclp == NULL) 167 return (NULL); 168 169 aclp->acl_aclp = NULL; 170 aclp->acl_cnt = 0; 171 172 switch (type) { 173 case ACE_T: 174 aclp->acl_type = ACE_T; 175 aclp->acl_entry_size = sizeof (ace_t); 176 break; 177 case ACLENT_T: 178 aclp->acl_type = ACLENT_T; 179 aclp->acl_entry_size = sizeof (aclent_t); 180 break; 181 default: 182 acl_free(aclp); 183 aclp = NULL; 184 } 185 return (aclp); 186 } 187 188 /* 189 * Free acl_t structure 190 */ 191 void 192 acl_free(acl_t *aclp) 193 { 194 if (aclp == NULL) 195 return; 196 197 if (aclp->acl_aclp) 198 free(aclp->acl_aclp); 199 free(aclp); 200 } 201 202 /* 203 * Determine whether a file has a trivial ACL 204 * returns: 0 = trivial 205 * 1 = nontrivial 206 * <0 some other system failure, such as ENOENT or EPERM 207 */ 208 int 209 acl_trivial(const char *filename) 210 { 211 int acl_flavor; 212 int aclcnt; 213 int cntcmd; 214 int val = 0; 215 ace_t *acep; 216 217 acl_flavor = pathconf(filename, _PC_ACL_ENABLED); 218 219 if (acl_flavor == _ACL_ACE_ENABLED) 220 cntcmd = ACE_GETACLCNT; 221 else 222 cntcmd = GETACLCNT; 223 224 aclcnt = acl(filename, cntcmd, 0, NULL); 225 if (aclcnt > 0) { 226 if (acl_flavor == _ACL_ACE_ENABLED) { 227 acep = malloc(sizeof (ace_t) * aclcnt); 228 if (acep == NULL) 229 return (-1); 230 if (acl(filename, ACE_GETACL, 231 aclcnt, acep) < 0) { 232 free(acep); 233 return (-1); 234 } 235 236 val = ace_trivial(acep, aclcnt); 237 free(acep); 238 239 } else if (aclcnt > MIN_ACL_ENTRIES) 240 val = 1; 241 } 242 return (val); 243 } 244 245 static uint32_t 246 access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow) 247 { 248 uint32_t access_mask = 0; 249 int acl_produce; 250 int synchronize_set = 0, write_owner_set = 0; 251 int delete_set = 0, write_attrs_set = 0; 252 int read_named_set = 0, write_named_set = 0; 253 254 acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW | 255 ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 256 ACL_WRITE_ATTRS_WRITER_SET_DENY); 257 258 if (isallow) { 259 synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW; 260 write_owner_set = ACL_WRITE_OWNER_SET_ALLOW; 261 delete_set = ACL_DELETE_SET_ALLOW; 262 if (hasreadperm) 263 read_named_set = ACL_READ_NAMED_READER_SET_ALLOW; 264 if (haswriteperm) 265 write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 266 if (isowner) 267 write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 268 else if (haswriteperm) 269 write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 270 } else { 271 272 synchronize_set = ACL_SYNCHRONIZE_SET_DENY; 273 write_owner_set = ACL_WRITE_OWNER_SET_DENY; 274 delete_set = ACL_DELETE_SET_DENY; 275 if (hasreadperm) 276 read_named_set = ACL_READ_NAMED_READER_SET_DENY; 277 if (haswriteperm) 278 write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY; 279 if (isowner) 280 write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY; 281 else if (haswriteperm) 282 write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY; 283 else 284 /* 285 * If the entity is not the owner and does not 286 * have write permissions ACE_WRITE_ATTRIBUTES will 287 * always go in the DENY ACE. 288 */ 289 access_mask |= ACE_WRITE_ATTRIBUTES; 290 } 291 292 if (acl_produce & synchronize_set) 293 access_mask |= ACE_SYNCHRONIZE; 294 if (acl_produce & write_owner_set) 295 access_mask |= ACE_WRITE_OWNER; 296 if (acl_produce & delete_set) 297 access_mask |= ACE_DELETE; 298 if (acl_produce & write_attrs_set) 299 access_mask |= ACE_WRITE_ATTRIBUTES; 300 if (acl_produce & read_named_set) 301 access_mask |= ACE_READ_NAMED_ATTRS; 302 if (acl_produce & write_named_set) 303 access_mask |= ACE_WRITE_NAMED_ATTRS; 304 305 return (access_mask); 306 } 307 308 /* 309 * Given an mode_t, convert it into an access_mask as used 310 * by nfsace, assuming aclent_t -> nfsace semantics. 311 */ 312 static uint32_t 313 mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow) 314 { 315 uint32_t access = 0; 316 int haswriteperm = 0; 317 int hasreadperm = 0; 318 319 if (isallow) { 320 haswriteperm = (mode & 02); 321 hasreadperm = (mode & 04); 322 } else { 323 haswriteperm = !(mode & 02); 324 hasreadperm = !(mode & 04); 325 } 326 327 /* 328 * The following call takes care of correctly setting the following 329 * mask bits in the access_mask: 330 * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE, 331 * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS 332 */ 333 access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow); 334 335 if (isallow) { 336 access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES; 337 if (isowner) 338 access |= ACE_WRITE_ACL; 339 } else { 340 if (! isowner) 341 access |= ACE_WRITE_ACL; 342 } 343 344 /* read */ 345 if (mode & 04) { 346 access |= ACE_READ_DATA; 347 } 348 /* write */ 349 if (mode & 02) { 350 access |= ACE_WRITE_DATA | 351 ACE_APPEND_DATA; 352 if (isdir) 353 access |= ACE_DELETE_CHILD; 354 } 355 /* exec */ 356 if (mode & 01) { 357 access |= ACE_EXECUTE; 358 } 359 360 return (access); 361 } 362 363 /* 364 * Given an nfsace (presumably an ALLOW entry), make a 365 * corresponding DENY entry at the address given. 366 */ 367 static void 368 ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner) 369 { 370 (void) memcpy(deny, allow, sizeof (ace_t)); 371 372 deny->a_who = allow->a_who; 373 374 deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 375 deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS; 376 if (isdir) 377 deny->a_access_mask ^= ACE_DELETE_CHILD; 378 379 deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER | 380 ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS | 381 ACE_WRITE_NAMED_ATTRS); 382 deny->a_access_mask |= access_mask_set((allow->a_access_mask & 383 ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner, 384 B_FALSE); 385 } 386 /* 387 * Make an initial pass over an array of aclent_t's. Gather 388 * information such as an ACL_MASK (if any), number of users, 389 * number of groups, and whether the array needs to be sorted. 390 */ 391 static int 392 ln_aent_preprocess(aclent_t *aclent, int n, 393 int *hasmask, mode_t *mask, 394 int *numuser, int *numgroup, int *needsort) 395 { 396 int error = 0; 397 int i; 398 int curtype = 0; 399 400 *hasmask = 0; 401 *mask = 07; 402 *needsort = 0; 403 *numuser = 0; 404 *numgroup = 0; 405 406 for (i = 0; i < n; i++) { 407 if (aclent[i].a_type < curtype) 408 *needsort = 1; 409 else if (aclent[i].a_type > curtype) 410 curtype = aclent[i].a_type; 411 if (aclent[i].a_type & USER) 412 (*numuser)++; 413 if (aclent[i].a_type & (GROUP | GROUP_OBJ)) 414 (*numgroup)++; 415 if (aclent[i].a_type & CLASS_OBJ) { 416 if (*hasmask) { 417 error = EINVAL; 418 goto out; 419 } else { 420 *hasmask = 1; 421 *mask = aclent[i].a_perm; 422 } 423 } 424 } 425 426 if ((! *hasmask) && (*numuser + *numgroup > 1)) { 427 error = EINVAL; 428 goto out; 429 } 430 431 out: 432 return (error); 433 } 434 435 /* 436 * Convert an array of aclent_t into an array of nfsace entries, 437 * following POSIX draft -> nfsv4 conversion semantics as outlined in 438 * the IETF draft. 439 */ 440 static int 441 ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir) 442 { 443 int error = 0; 444 mode_t mask; 445 int numuser, numgroup, needsort; 446 int resultsize = 0; 447 int i, groupi = 0, skip; 448 ace_t *acep, *result = NULL; 449 int hasmask; 450 451 error = ln_aent_preprocess(aclent, n, &hasmask, &mask, 452 &numuser, &numgroup, &needsort); 453 if (error != 0) 454 goto out; 455 456 /* allow + deny for each aclent */ 457 resultsize = n * 2; 458 if (hasmask) { 459 /* 460 * stick extra deny on the group_obj and on each 461 * user|group for the mask (the group_obj was added 462 * into the count for numgroup) 463 */ 464 resultsize += numuser + numgroup; 465 /* ... and don't count the mask itself */ 466 resultsize -= 2; 467 } 468 469 /* sort the source if necessary */ 470 if (needsort) 471 ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls); 472 473 result = acep = calloc(1, resultsize * sizeof (ace_t)); 474 if (result == NULL) 475 goto out; 476 477 for (i = 0; i < n; i++) { 478 /* 479 * don't process CLASS_OBJ (mask); mask was grabbed in 480 * ln_aent_preprocess() 481 */ 482 if (aclent[i].a_type & CLASS_OBJ) 483 continue; 484 485 /* If we need an ACL_MASK emulator, prepend it now */ 486 if ((hasmask) && 487 (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) { 488 acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 489 acep->a_flags = 0; 490 if (aclent[i].a_type & GROUP_OBJ) { 491 acep->a_who = -1; 492 acep->a_flags |= 493 (ACE_IDENTIFIER_GROUP|ACE_GROUP); 494 } else if (aclent[i].a_type & USER) { 495 acep->a_who = aclent[i].a_id; 496 } else { 497 acep->a_who = aclent[i].a_id; 498 acep->a_flags |= ACE_IDENTIFIER_GROUP; 499 } 500 if (aclent[i].a_type & ACL_DEFAULT) { 501 acep->a_flags |= ACE_INHERIT_ONLY_ACE | 502 ACE_FILE_INHERIT_ACE | 503 ACE_DIRECTORY_INHERIT_ACE; 504 } 505 /* 506 * Set the access mask for the prepended deny 507 * ace. To do this, we invert the mask (found 508 * in ln_aent_preprocess()) then convert it to an 509 * DENY ace access_mask. 510 */ 511 acep->a_access_mask = mode_to_ace_access((mask ^ 07), 512 isdir, 0, 0); 513 acep += 1; 514 } 515 516 /* handle a_perm -> access_mask */ 517 acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm, 518 isdir, aclent[i].a_type & USER_OBJ, 1); 519 520 /* emulate a default aclent */ 521 if (aclent[i].a_type & ACL_DEFAULT) { 522 acep->a_flags |= ACE_INHERIT_ONLY_ACE | 523 ACE_FILE_INHERIT_ACE | 524 ACE_DIRECTORY_INHERIT_ACE; 525 } 526 527 /* 528 * handle a_perm and a_id 529 * 530 * this must be done last, since it involves the 531 * corresponding deny aces, which are handled 532 * differently for each different a_type. 533 */ 534 if (aclent[i].a_type & USER_OBJ) { 535 acep->a_who = -1; 536 acep->a_flags |= ACE_OWNER; 537 ace_make_deny(acep, acep + 1, isdir, B_TRUE); 538 acep += 2; 539 } else if (aclent[i].a_type & USER) { 540 acep->a_who = aclent[i].a_id; 541 ace_make_deny(acep, acep + 1, isdir, B_FALSE); 542 acep += 2; 543 } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) { 544 if (aclent[i].a_type & GROUP_OBJ) { 545 acep->a_who = -1; 546 acep->a_flags |= ACE_GROUP; 547 } else { 548 acep->a_who = aclent[i].a_id; 549 } 550 acep->a_flags |= ACE_IDENTIFIER_GROUP; 551 /* 552 * Set the corresponding deny for the group ace. 553 * 554 * The deny aces go after all of the groups, unlike 555 * everything else, where they immediately follow 556 * the allow ace. 557 * 558 * We calculate "skip", the number of slots to 559 * skip ahead for the deny ace, here. 560 * 561 * The pattern is: 562 * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3 563 * thus, skip is 564 * (2 * numgroup) - 1 - groupi 565 * (2 * numgroup) to account for MD + A 566 * - 1 to account for the fact that we're on the 567 * access (A), not the mask (MD) 568 * - groupi to account for the fact that we have 569 * passed up groupi number of MD's. 570 */ 571 skip = (2 * numgroup) - 1 - groupi; 572 ace_make_deny(acep, acep + skip, isdir, B_FALSE); 573 /* 574 * If we just did the last group, skip acep past 575 * all of the denies; else, just move ahead one. 576 */ 577 if (++groupi >= numgroup) 578 acep += numgroup + 1; 579 else 580 acep += 1; 581 } else if (aclent[i].a_type & OTHER_OBJ) { 582 acep->a_who = -1; 583 acep->a_flags |= ACE_EVERYONE; 584 ace_make_deny(acep, acep + 1, isdir, B_FALSE); 585 acep += 2; 586 } else { 587 error = EINVAL; 588 goto out; 589 } 590 } 591 592 *acepp = result; 593 *rescount = resultsize; 594 595 out: 596 if (error != 0) { 597 if ((result != NULL) && (resultsize > 0)) { 598 free(result); 599 } 600 } 601 602 return (error); 603 } 604 605 static int 606 convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir, 607 ace_t **retacep, int *retacecnt) 608 { 609 ace_t *acep; 610 ace_t *dfacep; 611 int acecnt = 0; 612 int dfacecnt = 0; 613 int dfaclstart = 0; 614 int dfaclcnt = 0; 615 aclent_t *aclp; 616 int i; 617 int error; 618 619 ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls); 620 621 for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) { 622 if (aclp->a_type & ACL_DEFAULT) 623 break; 624 } 625 626 if (i < aclcnt) { 627 dfaclstart = i; 628 dfaclcnt = aclcnt - i; 629 } 630 631 if (dfaclcnt && isdir == 0) { 632 return (-1); 633 } 634 635 error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir); 636 if (error) 637 return (-1); 638 639 if (dfaclcnt) { 640 error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt, 641 &dfacep, &dfacecnt, isdir); 642 if (error) { 643 if (acep) { 644 free(acep); 645 } 646 return (-1); 647 } 648 } 649 650 if (dfacecnt != 0) { 651 acep = realloc(acep, sizeof (ace_t) * (acecnt + dfacecnt)); 652 if (acep == NULL) 653 return (-1); 654 if (dfaclcnt) { 655 (void) memcpy(acep + acecnt, dfacep, 656 sizeof (ace_t) * dfacecnt); 657 } 658 } 659 if (dfaclcnt) 660 free(dfacep); 661 662 *retacecnt = acecnt + dfacecnt; 663 *retacep = acep; 664 return (0); 665 } 666 667 static void 668 acevals_init(acevals_t *vals, uid_t key) 669 { 670 bzero(vals, sizeof (*vals)); 671 vals->allowed = ACE_MASK_UNDEFINED; 672 vals->denied = ACE_MASK_UNDEFINED; 673 vals->mask = ACE_MASK_UNDEFINED; 674 vals->key = key; 675 } 676 677 static void 678 ace_list_init(ace_list_t *al, int dfacl_flag) 679 { 680 acevals_init(&al->user_obj, NULL); 681 acevals_init(&al->group_obj, NULL); 682 acevals_init(&al->other_obj, NULL); 683 al->numusers = 0; 684 al->numgroups = 0; 685 al->acl_mask = 0; 686 al->hasmask = 0; 687 al->state = ace_unused; 688 al->seen = 0; 689 al->dfacl_flag = dfacl_flag; 690 } 691 692 /* 693 * Find or create an acevals holder for a given id and avl tree. 694 * 695 * Note that only one thread will ever touch these avl trees, so 696 * there is no need for locking. 697 */ 698 static acevals_t * 699 acevals_find(ace_t *ace, avl_tree_t *avl, int *num) 700 { 701 acevals_t key, *rc; 702 avl_index_t where; 703 704 key.key = ace->a_who; 705 rc = avl_find(avl, &key, &where); 706 if (rc != NULL) 707 return (rc); 708 709 /* this memory is freed by ln_ace_to_aent()->ace_list_free() */ 710 rc = calloc(1, sizeof (acevals_t)); 711 if (rc == NULL) 712 return (rc); 713 acevals_init(rc, ace->a_who); 714 avl_insert(avl, rc, where); 715 (*num)++; 716 717 return (rc); 718 } 719 720 static int 721 access_mask_check(ace_t *acep, int mask_bit, int isowner) 722 { 723 int set_deny, err_deny; 724 int set_allow, err_allow; 725 int acl_consume; 726 int haswriteperm, hasreadperm; 727 728 if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) { 729 haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 0 : 1; 730 hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 0 : 1; 731 } else { 732 haswriteperm = (acep->a_access_mask & ACE_WRITE_DATA) ? 1 : 0; 733 hasreadperm = (acep->a_access_mask & ACE_READ_DATA) ? 1 : 0; 734 } 735 736 acl_consume = (ACL_SYNCHRONIZE_ERR_DENY | 737 ACL_DELETE_ERR_DENY | 738 ACL_WRITE_OWNER_ERR_DENY | 739 ACL_WRITE_OWNER_ERR_ALLOW | 740 ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 741 ACL_WRITE_ATTRS_OWNER_ERR_DENY | 742 ACL_WRITE_ATTRS_WRITER_SET_DENY | 743 ACL_WRITE_ATTRS_WRITER_ERR_ALLOW | 744 ACL_WRITE_NAMED_WRITER_ERR_DENY | 745 ACL_READ_NAMED_READER_ERR_DENY); 746 747 if (mask_bit == ACE_SYNCHRONIZE) { 748 set_deny = ACL_SYNCHRONIZE_SET_DENY; 749 err_deny = ACL_SYNCHRONIZE_ERR_DENY; 750 set_allow = ACL_SYNCHRONIZE_SET_ALLOW; 751 err_allow = ACL_SYNCHRONIZE_ERR_ALLOW; 752 } else if (mask_bit == ACE_WRITE_OWNER) { 753 set_deny = ACL_WRITE_OWNER_SET_DENY; 754 err_deny = ACL_WRITE_OWNER_ERR_DENY; 755 set_allow = ACL_WRITE_OWNER_SET_ALLOW; 756 err_allow = ACL_WRITE_OWNER_ERR_ALLOW; 757 } else if (mask_bit == ACE_DELETE) { 758 set_deny = ACL_DELETE_SET_DENY; 759 err_deny = ACL_DELETE_ERR_DENY; 760 set_allow = ACL_DELETE_SET_ALLOW; 761 err_allow = ACL_DELETE_ERR_ALLOW; 762 } else if (mask_bit == ACE_WRITE_ATTRIBUTES) { 763 if (isowner) { 764 set_deny = ACL_WRITE_ATTRS_OWNER_SET_DENY; 765 err_deny = ACL_WRITE_ATTRS_OWNER_ERR_DENY; 766 set_allow = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 767 err_allow = ACL_WRITE_ATTRS_OWNER_ERR_ALLOW; 768 } else if (haswriteperm) { 769 set_deny = ACL_WRITE_ATTRS_WRITER_SET_DENY; 770 err_deny = ACL_WRITE_ATTRS_WRITER_ERR_DENY; 771 set_allow = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 772 err_allow = ACL_WRITE_ATTRS_WRITER_ERR_ALLOW; 773 } else { 774 if ((acep->a_access_mask & mask_bit) && 775 (acep->a_type & ACE_ACCESS_ALLOWED_ACE_TYPE)) { 776 return (ENOTSUP); 777 } 778 return (0); 779 } 780 } else if (mask_bit == ACE_READ_NAMED_ATTRS) { 781 if (!hasreadperm) 782 return (0); 783 784 set_deny = ACL_READ_NAMED_READER_SET_DENY; 785 err_deny = ACL_READ_NAMED_READER_ERR_DENY; 786 set_allow = ACL_READ_NAMED_READER_SET_ALLOW; 787 err_allow = ACL_READ_NAMED_READER_ERR_ALLOW; 788 } else if (mask_bit == ACE_WRITE_NAMED_ATTRS) { 789 if (!haswriteperm) 790 return (0); 791 792 set_deny = ACL_WRITE_NAMED_WRITER_SET_DENY; 793 err_deny = ACL_WRITE_NAMED_WRITER_ERR_DENY; 794 set_allow = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 795 err_allow = ACL_WRITE_NAMED_WRITER_ERR_ALLOW; 796 } else { 797 return (EINVAL); 798 } 799 800 if (acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) { 801 if (acl_consume & set_deny) { 802 if (!(acep->a_access_mask & mask_bit)) { 803 return (ENOTSUP); 804 } 805 } else if (acl_consume & err_deny) { 806 if (acep->a_access_mask & mask_bit) { 807 return (ENOTSUP); 808 } 809 } 810 } else { 811 /* ACE_ACCESS_ALLOWED_ACE_TYPE */ 812 if (acl_consume & set_allow) { 813 if (!(acep->a_access_mask & mask_bit)) { 814 return (ENOTSUP); 815 } 816 } else if (acl_consume & err_allow) { 817 if (acep->a_access_mask & mask_bit) { 818 return (ENOTSUP); 819 } 820 } 821 } 822 return (0); 823 } 824 825 static int 826 ace_to_aent_legal(ace_t *acep) 827 { 828 int error = 0; 829 int isowner; 830 831 /* only ALLOW or DENY */ 832 if ((acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE) && 833 (acep->a_type != ACE_ACCESS_DENIED_ACE_TYPE)) { 834 error = ENOTSUP; 835 goto out; 836 } 837 838 /* check for invalid flags */ 839 if (acep->a_flags & ~(ACE_VALID_FLAG_BITS)) { 840 error = EINVAL; 841 goto out; 842 } 843 844 /* some flags are illegal */ 845 if (acep->a_flags & (ACE_SUCCESSFUL_ACCESS_ACE_FLAG | 846 ACE_FAILED_ACCESS_ACE_FLAG | 847 ACE_NO_PROPAGATE_INHERIT_ACE)) { 848 error = ENOTSUP; 849 goto out; 850 } 851 852 /* check for invalid masks */ 853 if (acep->a_access_mask & ~(ACE_VALID_MASK_BITS)) { 854 error = EINVAL; 855 goto out; 856 } 857 858 if ((acep->a_flags & ACE_OWNER)) { 859 isowner = 1; 860 } else { 861 isowner = 0; 862 } 863 864 error = access_mask_check(acep, ACE_SYNCHRONIZE, isowner); 865 if (error) 866 goto out; 867 868 error = access_mask_check(acep, ACE_WRITE_OWNER, isowner); 869 if (error) 870 goto out; 871 872 error = access_mask_check(acep, ACE_DELETE, isowner); 873 if (error) 874 goto out; 875 876 error = access_mask_check(acep, ACE_WRITE_ATTRIBUTES, isowner); 877 if (error) 878 goto out; 879 880 error = access_mask_check(acep, ACE_READ_NAMED_ATTRS, isowner); 881 if (error) 882 goto out; 883 884 error = access_mask_check(acep, ACE_WRITE_NAMED_ATTRS, isowner); 885 if (error) 886 goto out; 887 888 /* more detailed checking of masks */ 889 if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) { 890 if (! (acep->a_access_mask & ACE_READ_ATTRIBUTES)) { 891 error = ENOTSUP; 892 goto out; 893 } 894 if ((acep->a_access_mask & ACE_WRITE_DATA) && 895 (! (acep->a_access_mask & ACE_APPEND_DATA))) { 896 error = ENOTSUP; 897 goto out; 898 } 899 if ((! (acep->a_access_mask & ACE_WRITE_DATA)) && 900 (acep->a_access_mask & ACE_APPEND_DATA)) { 901 error = ENOTSUP; 902 goto out; 903 } 904 } 905 906 /* ACL enforcement */ 907 if ((acep->a_access_mask & ACE_READ_ACL) && 908 (acep->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE)) { 909 error = ENOTSUP; 910 goto out; 911 } 912 if (acep->a_access_mask & ACE_WRITE_ACL) { 913 if ((acep->a_type == ACE_ACCESS_DENIED_ACE_TYPE) && 914 (isowner)) { 915 error = ENOTSUP; 916 goto out; 917 } 918 if ((acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) && 919 (! isowner)) { 920 error = ENOTSUP; 921 goto out; 922 } 923 } 924 925 out: 926 return (error); 927 } 928 929 static int 930 ace_mask_to_mode(uint32_t mask, o_mode_t *modep, int isdir) 931 { 932 int error = 0; 933 o_mode_t mode = 0; 934 uint32_t bits, wantbits; 935 936 /* read */ 937 if (mask & ACE_READ_DATA) 938 mode |= 04; 939 940 /* write */ 941 wantbits = (ACE_WRITE_DATA | ACE_APPEND_DATA); 942 if (isdir) 943 wantbits |= ACE_DELETE_CHILD; 944 bits = mask & wantbits; 945 if (bits != 0) { 946 if (bits != wantbits) { 947 error = ENOTSUP; 948 goto out; 949 } 950 mode |= 02; 951 } 952 953 /* exec */ 954 if (mask & ACE_EXECUTE) { 955 mode |= 01; 956 } 957 958 *modep = mode; 959 960 out: 961 return (error); 962 } 963 964 static int 965 ace_allow_to_mode(uint32_t mask, o_mode_t *modep, int isdir) 966 { 967 /* ACE_READ_ACL and ACE_READ_ATTRIBUTES must both be set */ 968 if ((mask & (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) != 969 (ACE_READ_ACL | ACE_READ_ATTRIBUTES)) { 970 return (ENOTSUP); 971 } 972 973 return (ace_mask_to_mode(mask, modep, isdir)); 974 } 975 976 static int 977 acevals_to_aent(acevals_t *vals, aclent_t *dest, ace_list_t *list, 978 uid_t owner, gid_t group, int isdir) 979 { 980 int error; 981 uint32_t flips = ACE_POSIX_SUPPORTED_BITS; 982 983 if (isdir) 984 flips |= ACE_DELETE_CHILD; 985 if (vals->allowed != (vals->denied ^ flips)) { 986 error = ENOTSUP; 987 goto out; 988 } 989 if ((list->hasmask) && (list->acl_mask != vals->mask) && 990 (vals->aent_type & (USER | GROUP | GROUP_OBJ))) { 991 error = ENOTSUP; 992 goto out; 993 } 994 error = ace_allow_to_mode(vals->allowed, &dest->a_perm, isdir); 995 if (error != 0) 996 goto out; 997 dest->a_type = vals->aent_type; 998 if (dest->a_type & (USER | GROUP)) { 999 dest->a_id = vals->key; 1000 } else if (dest->a_type & USER_OBJ) { 1001 dest->a_id = owner; 1002 } else if (dest->a_type & GROUP_OBJ) { 1003 dest->a_id = group; 1004 } else if (dest->a_type & OTHER_OBJ) { 1005 dest->a_id = 0; 1006 } else { 1007 error = EINVAL; 1008 goto out; 1009 } 1010 1011 out: 1012 return (error); 1013 } 1014 1015 static int 1016 ace_list_to_aent(ace_list_t *list, aclent_t **aclentp, int *aclcnt, 1017 uid_t owner, gid_t group, int isdir) 1018 { 1019 int error = 0; 1020 aclent_t *aent, *result = NULL; 1021 acevals_t *vals; 1022 int resultcount; 1023 1024 if ((list->seen & (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) != 1025 (USER_OBJ | GROUP_OBJ | OTHER_OBJ)) { 1026 error = ENOTSUP; 1027 goto out; 1028 } 1029 if ((! list->hasmask) && (list->numusers + list->numgroups > 0)) { 1030 error = ENOTSUP; 1031 goto out; 1032 } 1033 1034 resultcount = 3 + list->numusers + list->numgroups; 1035 /* 1036 * This must be the same condition as below, when we add the CLASS_OBJ 1037 * (aka ACL mask) 1038 */ 1039 if ((list->hasmask) || (! list->dfacl_flag)) 1040 resultcount += 1; 1041 1042 result = aent = calloc(1, resultcount * sizeof (aclent_t)); 1043 1044 if (result == NULL) { 1045 error = ENOMEM; 1046 goto out; 1047 } 1048 1049 /* USER_OBJ */ 1050 if (!(list->user_obj.aent_type & USER_OBJ)) { 1051 error = EINVAL; 1052 goto out; 1053 } 1054 1055 error = acevals_to_aent(&list->user_obj, aent, list, owner, group, 1056 isdir); 1057 1058 if (error != 0) 1059 goto out; 1060 ++aent; 1061 /* USER */ 1062 vals = NULL; 1063 for (vals = avl_first(&list->user); vals != NULL; 1064 vals = AVL_NEXT(&list->user, vals)) { 1065 if (!(vals->aent_type & USER)) { 1066 error = EINVAL; 1067 goto out; 1068 } 1069 error = acevals_to_aent(vals, aent, list, owner, group, 1070 isdir); 1071 if (error != 0) 1072 goto out; 1073 ++aent; 1074 } 1075 /* GROUP_OBJ */ 1076 if (!(list->group_obj.aent_type & GROUP_OBJ)) { 1077 error = EINVAL; 1078 goto out; 1079 } 1080 error = acevals_to_aent(&list->group_obj, aent, list, owner, group, 1081 isdir); 1082 if (error != 0) 1083 goto out; 1084 ++aent; 1085 /* GROUP */ 1086 vals = NULL; 1087 for (vals = avl_first(&list->group); vals != NULL; 1088 vals = AVL_NEXT(&list->group, vals)) { 1089 if (!(vals->aent_type & GROUP)) { 1090 error = EINVAL; 1091 goto out; 1092 } 1093 error = acevals_to_aent(vals, aent, list, owner, group, 1094 isdir); 1095 if (error != 0) 1096 goto out; 1097 ++aent; 1098 } 1099 /* 1100 * CLASS_OBJ (aka ACL_MASK) 1101 * 1102 * An ACL_MASK is not fabricated if the ACL is a default ACL. 1103 * This is to follow UFS's behavior. 1104 */ 1105 if ((list->hasmask) || (! list->dfacl_flag)) { 1106 if (list->hasmask) { 1107 uint32_t flips = ACE_POSIX_SUPPORTED_BITS; 1108 if (isdir) 1109 flips |= ACE_DELETE_CHILD; 1110 error = ace_mask_to_mode(list->acl_mask ^ flips, 1111 &aent->a_perm, isdir); 1112 if (error != 0) 1113 goto out; 1114 } else { 1115 /* fabricate the ACL_MASK from the group permissions */ 1116 error = ace_mask_to_mode(list->group_obj.allowed, 1117 &aent->a_perm, isdir); 1118 if (error != 0) 1119 goto out; 1120 } 1121 aent->a_id = 0; 1122 aent->a_type = CLASS_OBJ | list->dfacl_flag; 1123 ++aent; 1124 } 1125 /* OTHER_OBJ */ 1126 if (!(list->other_obj.aent_type & OTHER_OBJ)) { 1127 error = EINVAL; 1128 goto out; 1129 } 1130 error = acevals_to_aent(&list->other_obj, aent, list, owner, group, 1131 isdir); 1132 if (error != 0) 1133 goto out; 1134 ++aent; 1135 1136 *aclentp = result; 1137 *aclcnt = resultcount; 1138 1139 out: 1140 if (error != 0) { 1141 if (result != NULL) 1142 free(result); 1143 } 1144 1145 return (error); 1146 } 1147 1148 /* 1149 * free all data associated with an ace_list 1150 */ 1151 static void 1152 ace_list_free(ace_list_t *al) 1153 { 1154 acevals_t *node; 1155 void *cookie; 1156 1157 if (al == NULL) 1158 return; 1159 1160 cookie = NULL; 1161 while ((node = avl_destroy_nodes(&al->user, &cookie)) != NULL) 1162 free(node); 1163 cookie = NULL; 1164 while ((node = avl_destroy_nodes(&al->group, &cookie)) != NULL) 1165 free(node); 1166 1167 avl_destroy(&al->user); 1168 avl_destroy(&al->group); 1169 1170 /* free the container itself */ 1171 free(al); 1172 } 1173 1174 static int 1175 acevals_compare(const void *va, const void *vb) 1176 { 1177 const acevals_t *a = va, *b = vb; 1178 1179 if (a->key == b->key) 1180 return (0); 1181 1182 if (a->key > b->key) 1183 return (1); 1184 1185 else 1186 return (-1); 1187 } 1188 1189 /* 1190 * Convert a list of ace_t entries to equivalent regular and default 1191 * aclent_t lists. Return error (ENOTSUP) when conversion is not possible. 1192 */ 1193 static int 1194 ln_ace_to_aent(ace_t *ace, int n, uid_t owner, gid_t group, 1195 aclent_t **aclentp, int *aclcnt, aclent_t **dfaclentp, int *dfaclcnt, 1196 int isdir) 1197 { 1198 int error = 0; 1199 ace_t *acep; 1200 uint32_t bits; 1201 int i; 1202 ace_list_t *normacl = NULL, *dfacl = NULL, *acl; 1203 acevals_t *vals; 1204 1205 *aclentp = NULL; 1206 *aclcnt = 0; 1207 *dfaclentp = NULL; 1208 *dfaclcnt = 0; 1209 1210 /* we need at least user_obj, group_obj, and other_obj */ 1211 if (n < 6) { 1212 error = ENOTSUP; 1213 goto out; 1214 } 1215 if (ace == NULL) { 1216 error = EINVAL; 1217 goto out; 1218 } 1219 1220 normacl = calloc(1, sizeof (ace_list_t)); 1221 1222 if (normacl == NULL) { 1223 error = errno; 1224 goto out; 1225 } 1226 1227 avl_create(&normacl->user, acevals_compare, sizeof (acevals_t), 1228 offsetof(acevals_t, avl)); 1229 avl_create(&normacl->group, acevals_compare, sizeof (acevals_t), 1230 offsetof(acevals_t, avl)); 1231 1232 ace_list_init(normacl, 0); 1233 1234 dfacl = calloc(1, sizeof (ace_list_t)); 1235 if (dfacl == NULL) { 1236 error = errno; 1237 goto out; 1238 } 1239 avl_create(&dfacl->user, acevals_compare, sizeof (acevals_t), 1240 offsetof(acevals_t, avl)); 1241 avl_create(&dfacl->group, acevals_compare, sizeof (acevals_t), 1242 offsetof(acevals_t, avl)); 1243 ace_list_init(dfacl, ACL_DEFAULT); 1244 1245 /* process every ace_t... */ 1246 for (i = 0; i < n; i++) { 1247 acep = &ace[i]; 1248 1249 /* rule out certain cases quickly */ 1250 error = ace_to_aent_legal(acep); 1251 if (error != 0) 1252 goto out; 1253 1254 /* 1255 * Turn off these bits in order to not have to worry about 1256 * them when doing the checks for compliments. 1257 */ 1258 acep->a_access_mask &= ~(ACE_WRITE_OWNER | ACE_DELETE | 1259 ACE_SYNCHRONIZE | ACE_WRITE_ATTRIBUTES | 1260 ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS); 1261 1262 /* see if this should be a regular or default acl */ 1263 bits = acep->a_flags & 1264 (ACE_INHERIT_ONLY_ACE | 1265 ACE_FILE_INHERIT_ACE | 1266 ACE_DIRECTORY_INHERIT_ACE); 1267 if (bits != 0) { 1268 /* all or nothing on these inherit bits */ 1269 if (bits != (ACE_INHERIT_ONLY_ACE | 1270 ACE_FILE_INHERIT_ACE | 1271 ACE_DIRECTORY_INHERIT_ACE)) { 1272 error = ENOTSUP; 1273 goto out; 1274 } 1275 acl = dfacl; 1276 } else { 1277 acl = normacl; 1278 } 1279 1280 if ((acep->a_flags & ACE_OWNER)) { 1281 if (acl->state > ace_user_obj) { 1282 error = ENOTSUP; 1283 goto out; 1284 } 1285 acl->state = ace_user_obj; 1286 acl->seen |= USER_OBJ; 1287 vals = &acl->user_obj; 1288 vals->aent_type = USER_OBJ | acl->dfacl_flag; 1289 } else if ((acep->a_flags & ACE_EVERYONE)) { 1290 acl->state = ace_other_obj; 1291 acl->seen |= OTHER_OBJ; 1292 vals = &acl->other_obj; 1293 vals->aent_type = OTHER_OBJ | acl->dfacl_flag; 1294 } else if (acep->a_flags & ACE_IDENTIFIER_GROUP) { 1295 if (acl->state > ace_group) { 1296 error = ENOTSUP; 1297 goto out; 1298 } 1299 if ((acep->a_flags & ACE_GROUP)) { 1300 acl->seen |= GROUP_OBJ; 1301 vals = &acl->group_obj; 1302 vals->aent_type = GROUP_OBJ | acl->dfacl_flag; 1303 } else { 1304 acl->seen |= GROUP; 1305 vals = acevals_find(acep, &acl->group, 1306 &acl->numgroups); 1307 if (vals == NULL) { 1308 error = ENOMEM; 1309 goto out; 1310 } 1311 vals->aent_type = GROUP | acl->dfacl_flag; 1312 } 1313 acl->state = ace_group; 1314 } else { 1315 if (acl->state > ace_user) { 1316 error = ENOTSUP; 1317 goto out; 1318 } 1319 acl->state = ace_user; 1320 acl->seen |= USER; 1321 vals = acevals_find(acep, &acl->user, 1322 &acl->numusers); 1323 if (vals == NULL) { 1324 error = ENOMEM; 1325 goto out; 1326 } 1327 vals->aent_type = USER | acl->dfacl_flag; 1328 } 1329 1330 if (!(acl->state > ace_unused)) { 1331 error = EINVAL; 1332 goto out; 1333 } 1334 1335 if (acep->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) { 1336 /* no more than one allowed per aclent_t */ 1337 if (vals->allowed != ACE_MASK_UNDEFINED) { 1338 error = ENOTSUP; 1339 goto out; 1340 } 1341 vals->allowed = acep->a_access_mask; 1342 } else { 1343 /* 1344 * it's a DENY; if there was a previous DENY, it 1345 * must have been an ACL_MASK. 1346 */ 1347 if (vals->denied != ACE_MASK_UNDEFINED) { 1348 /* ACL_MASK is for USER and GROUP only */ 1349 if ((acl->state != ace_user) && 1350 (acl->state != ace_group)) { 1351 error = ENOTSUP; 1352 goto out; 1353 } 1354 1355 if (! acl->hasmask) { 1356 acl->hasmask = 1; 1357 acl->acl_mask = vals->denied; 1358 /* check for mismatched ACL_MASK emulations */ 1359 } else if (acl->acl_mask != vals->denied) { 1360 error = ENOTSUP; 1361 goto out; 1362 } 1363 vals->mask = vals->denied; 1364 } 1365 vals->denied = acep->a_access_mask; 1366 } 1367 } 1368 1369 /* done collating; produce the aclent_t lists */ 1370 if (normacl->state != ace_unused) { 1371 error = ace_list_to_aent(normacl, aclentp, aclcnt, 1372 owner, group, isdir); 1373 if (error != 0) { 1374 goto out; 1375 } 1376 } 1377 if (dfacl->state != ace_unused) { 1378 error = ace_list_to_aent(dfacl, dfaclentp, dfaclcnt, 1379 owner, group, isdir); 1380 if (error != 0) { 1381 goto out; 1382 } 1383 } 1384 1385 out: 1386 if (normacl != NULL) 1387 ace_list_free(normacl); 1388 if (dfacl != NULL) 1389 ace_list_free(dfacl); 1390 1391 return (error); 1392 } 1393 1394 static int 1395 convert_ace_to_aent(ace_t *acebufp, int acecnt, int isdir, 1396 uid_t owner, gid_t group, aclent_t **retaclentp, int *retaclcnt) 1397 { 1398 int error; 1399 aclent_t *aclentp, *dfaclentp; 1400 int aclcnt, dfaclcnt; 1401 1402 error = ln_ace_to_aent(acebufp, acecnt, owner, group, 1403 &aclentp, &aclcnt, &dfaclentp, &dfaclcnt, isdir); 1404 1405 if (error) 1406 return (error); 1407 1408 1409 if (dfaclcnt != 0) { 1410 /* 1411 * Slap aclentp and dfaclentp into a single array. 1412 */ 1413 aclentp = realloc(aclentp, (sizeof (aclent_t) * aclcnt) + 1414 (sizeof (aclent_t) * dfaclcnt)); 1415 if (aclentp != NULL) { 1416 (void) memcpy(aclentp + aclcnt, 1417 dfaclentp, sizeof (aclent_t) * dfaclcnt); 1418 } else { 1419 error = -1; 1420 } 1421 } 1422 1423 if (aclentp) { 1424 *retaclentp = aclentp; 1425 *retaclcnt = aclcnt + dfaclcnt; 1426 } 1427 1428 if (dfaclentp) 1429 free(dfaclentp); 1430 1431 return (error); 1432 } 1433 1434 static int 1435 cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp) 1436 { 1437 const char *fname; 1438 int fd; 1439 int ace_acl = 0; 1440 int error; 1441 int getcmd, cntcmd; 1442 acl_t *acl_info; 1443 int save_errno; 1444 int stat_error; 1445 struct stat64 statbuf; 1446 1447 *aclp = NULL; 1448 if (type == ACL_PATH) { 1449 fname = inp.file; 1450 ace_acl = pathconf(fname, _PC_ACL_ENABLED); 1451 } else { 1452 fd = inp.fd; 1453 ace_acl = fpathconf(fd, _PC_ACL_ENABLED); 1454 } 1455 1456 /* 1457 * if acl's aren't supported then 1458 * send it through the old GETACL interface 1459 */ 1460 if (ace_acl == 0 || ace_acl == -1) { 1461 ace_acl = _ACL_ACLENT_ENABLED; 1462 } 1463 1464 if (ace_acl & _ACL_ACE_ENABLED) { 1465 cntcmd = ACE_GETACLCNT; 1466 getcmd = ACE_GETACL; 1467 acl_info = acl_alloc(ACE_T); 1468 } else { 1469 cntcmd = GETACLCNT; 1470 getcmd = GETACL; 1471 acl_info = acl_alloc(ACLENT_T); 1472 } 1473 1474 if (acl_info == NULL) 1475 return (-1); 1476 1477 if (type == ACL_PATH) { 1478 acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL); 1479 } else { 1480 acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL); 1481 } 1482 1483 save_errno = errno; 1484 if (acl_info->acl_cnt < 0) { 1485 acl_free(acl_info); 1486 errno = save_errno; 1487 return (-1); 1488 } 1489 1490 if (acl_info->acl_cnt == 0) { 1491 acl_free(acl_info); 1492 errno = save_errno; 1493 return (0); 1494 } 1495 1496 acl_info->acl_aclp = 1497 malloc(acl_info->acl_cnt * acl_info->acl_entry_size); 1498 save_errno = errno; 1499 1500 if (acl_info->acl_aclp == NULL) { 1501 acl_free(acl_info); 1502 errno = save_errno; 1503 return (-1); 1504 } 1505 1506 if (type == ACL_PATH) { 1507 stat_error = stat64(fname, &statbuf); 1508 error = acl(fname, getcmd, acl_info->acl_cnt, 1509 acl_info->acl_aclp); 1510 } else { 1511 stat_error = fstat64(fd, &statbuf); 1512 error = facl(fd, getcmd, acl_info->acl_cnt, 1513 acl_info->acl_aclp); 1514 } 1515 1516 save_errno = errno; 1517 if (error == -1) { 1518 acl_free(acl_info); 1519 errno = save_errno; 1520 return (-1); 1521 } 1522 1523 1524 if (stat_error == 0) { 1525 acl_info->acl_flags = 1526 (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0); 1527 } else 1528 acl_info->acl_flags = 0; 1529 1530 switch (acl_info->acl_type) { 1531 case ACLENT_T: 1532 if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 1533 acl_info->acl_flags |= ACL_IS_TRIVIAL; 1534 break; 1535 case ACE_T: 1536 if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 1537 acl_info->acl_flags |= ACL_IS_TRIVIAL; 1538 break; 1539 default: 1540 errno = EINVAL; 1541 acl_free(acl_info); 1542 return (-1); 1543 } 1544 1545 if ((acl_info->acl_flags & ACL_IS_TRIVIAL) && 1546 (get_flag & ACL_NO_TRIVIAL)) { 1547 acl_free(acl_info); 1548 errno = 0; 1549 return (0); 1550 } 1551 1552 *aclp = acl_info; 1553 return (0); 1554 } 1555 1556 /* 1557 * return -1 on failure, otherwise the number of acl 1558 * entries is returned 1559 */ 1560 int 1561 acl_get(const char *path, int get_flag, acl_t **aclp) 1562 { 1563 acl_inp acl_inp; 1564 acl_inp.file = path; 1565 1566 return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp)); 1567 } 1568 1569 int 1570 facl_get(int fd, int get_flag, acl_t **aclp) 1571 { 1572 1573 acl_inp acl_inp; 1574 acl_inp.fd = fd; 1575 1576 return (cacl_get(acl_inp, get_flag, ACL_FD, aclp)); 1577 } 1578 1579 static int 1580 acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner, 1581 gid_t group) 1582 { 1583 int aclcnt; 1584 void *acldata; 1585 int error; 1586 1587 /* 1588 * See if we need to translate 1589 */ 1590 if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) || 1591 (target_flavor == _ACL_ACLENT_ENABLED && 1592 aclp->acl_type == ACLENT_T)) 1593 return (0); 1594 1595 if (target_flavor == -1) 1596 return (-1); 1597 1598 if (target_flavor == _ACL_ACE_ENABLED && 1599 aclp->acl_type == ACLENT_T) { 1600 error = convert_aent_to_ace(aclp->acl_aclp, 1601 aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt); 1602 if (error) { 1603 errno = error; 1604 return (-1); 1605 } 1606 } else if (target_flavor == _ACL_ACLENT_ENABLED && 1607 aclp->acl_type == ACE_T) { 1608 error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt, 1609 isdir, owner, group, (aclent_t **)&acldata, &aclcnt); 1610 if (error) { 1611 errno = error; 1612 return (-1); 1613 } 1614 } else { 1615 errno = ENOTSUP; 1616 return (-1); 1617 } 1618 1619 /* 1620 * replace old acl with newly translated acl 1621 */ 1622 free(aclp->acl_aclp); 1623 aclp->acl_aclp = acldata; 1624 aclp->acl_cnt = aclcnt; 1625 aclp->acl_type = (target_flavor == _ACL_ACE_ENABLED) ? ACE_T : ACLENT_T; 1626 return (0); 1627 } 1628 1629 /* 1630 * Set an ACL, translates acl to ace_t when appropriate. 1631 */ 1632 static int 1633 cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) 1634 { 1635 int error = 0; 1636 int acl_flavor_target; 1637 struct stat64 statbuf; 1638 int stat_error; 1639 int isdir; 1640 1641 1642 if (type == ACL_PATH) { 1643 stat_error = stat64(acl_inp->file, &statbuf); 1644 if (stat_error) 1645 return (-1); 1646 acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); 1647 } else { 1648 stat_error = fstat64(acl_inp->fd, &statbuf); 1649 if (stat_error) 1650 return (-1); 1651 acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); 1652 } 1653 1654 /* 1655 * If target returns an error or 0 from pathconf call then 1656 * fall back to UFS/POSIX Draft interface. 1657 * In the case of 0 we will then fail in either acl(2) or 1658 * acl_translate(). We could erroneously get 0 back from 1659 * a file system that is using fs_pathconf() and not answering 1660 * the _PC_ACL_ENABLED question itself. 1661 */ 1662 if (acl_flavor_target == 0 || acl_flavor_target == -1) 1663 acl_flavor_target = _ACL_ACLENT_ENABLED; 1664 1665 isdir = S_ISDIR(statbuf.st_mode); 1666 1667 if ((error = acl_translate(aclp, acl_flavor_target, isdir, 1668 statbuf.st_uid, statbuf.st_gid)) != 0) { 1669 return (error); 1670 } 1671 1672 if (type == ACL_PATH) { 1673 error = acl(acl_inp->file, 1674 (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 1675 aclp->acl_cnt, aclp->acl_aclp); 1676 } else { 1677 error = facl(acl_inp->fd, 1678 (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 1679 aclp->acl_cnt, aclp->acl_aclp); 1680 } 1681 1682 return (error); 1683 } 1684 1685 int 1686 acl_set(const char *path, acl_t *aclp) 1687 { 1688 acl_inp acl_inp; 1689 1690 acl_inp.file = path; 1691 1692 return (cacl_set(&acl_inp, aclp, ACL_PATH)); 1693 } 1694 1695 int 1696 facl_set(int fd, acl_t *aclp) 1697 { 1698 acl_inp acl_inp; 1699 1700 acl_inp.fd = fd; 1701 1702 return (cacl_set(&acl_inp, aclp, ACL_FD)); 1703 } 1704 1705 int 1706 acl_cnt(acl_t *aclp) 1707 { 1708 return (aclp->acl_cnt); 1709 } 1710 1711 int 1712 acl_type(acl_t *aclp) 1713 { 1714 return (aclp->acl_type); 1715 } 1716 1717 acl_t * 1718 acl_dup(acl_t *aclp) 1719 { 1720 acl_t *newaclp; 1721 1722 newaclp = acl_alloc(aclp->acl_type); 1723 if (newaclp == NULL) 1724 return (NULL); 1725 1726 newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt); 1727 if (newaclp->acl_aclp == NULL) { 1728 acl_free(newaclp); 1729 return (NULL); 1730 } 1731 1732 (void) memcpy(newaclp->acl_aclp, 1733 aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt); 1734 newaclp->acl_cnt = aclp->acl_cnt; 1735 1736 return (newaclp); 1737 } 1738 1739 int 1740 acl_flags(acl_t *aclp) 1741 { 1742 return (aclp->acl_flags); 1743 } 1744 1745 void * 1746 acl_data(acl_t *aclp) 1747 { 1748 return (aclp->acl_aclp); 1749 } 1750 1751 /* 1752 * Remove an ACL from a file and create a trivial ACL based 1753 * off of the mode argument. After acl has been set owner/group 1754 * are updated to match owner,group arguments 1755 */ 1756 int 1757 acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) 1758 { 1759 int error = 0; 1760 aclent_t min_acl[MIN_ACL_ENTRIES]; 1761 ace_t min_ace_acl[6]; /* owner, group, everyone + complement denies */ 1762 int acl_flavor; 1763 int aclcnt; 1764 1765 acl_flavor = pathconf(file, _PC_ACL_ENABLED); 1766 1767 /* 1768 * force it through aclent flavor when file system doesn't 1769 * understand question 1770 */ 1771 if (acl_flavor == 0 || acl_flavor == -1) 1772 acl_flavor = _ACL_ACLENT_ENABLED; 1773 1774 if (acl_flavor & _ACL_ACLENT_ENABLED) { 1775 min_acl[0].a_type = USER_OBJ; 1776 min_acl[0].a_id = owner; 1777 min_acl[0].a_perm = ((mode & 0700) >> 6); 1778 min_acl[1].a_type = GROUP_OBJ; 1779 min_acl[1].a_id = group; 1780 min_acl[1].a_perm = ((mode & 0070) >> 3); 1781 min_acl[2].a_type = CLASS_OBJ; 1782 min_acl[2].a_id = (uid_t)-1; 1783 min_acl[2].a_perm = ((mode & 0070) >> 3); 1784 min_acl[3].a_type = OTHER_OBJ; 1785 min_acl[3].a_id = (uid_t)-1; 1786 min_acl[3].a_perm = (mode & 0007); 1787 aclcnt = 4; 1788 error = acl(file, SETACL, aclcnt, min_acl); 1789 } else if (acl_flavor & _ACL_ACE_ENABLED) { 1790 (void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6); 1791 1792 /* 1793 * Make aces match request mode 1794 */ 1795 adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6); 1796 adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3); 1797 adjust_ace_pair(&min_ace_acl[4], mode & 0007); 1798 1799 error = acl(file, ACE_SETACL, 6, min_ace_acl); 1800 } else { 1801 errno = EINVAL; 1802 error = 1; 1803 } 1804 1805 if (error == 0) 1806 error = chown(file, owner, group); 1807 return (error); 1808 } 1809 1810 static int 1811 ace_match(void *entry1, void *entry2) 1812 { 1813 ace_t *p1 = (ace_t *)entry1; 1814 ace_t *p2 = (ace_t *)entry2; 1815 ace_t ace1, ace2; 1816 1817 ace1 = *p1; 1818 ace2 = *p2; 1819 1820 /* 1821 * Need to fixup who field for abstrations for 1822 * accurate comparison, since field is undefined. 1823 */ 1824 if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 1825 ace1.a_who = -1; 1826 if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 1827 ace2.a_who = -1; 1828 return (memcmp(&ace1, &ace2, sizeof (ace_t))); 1829 } 1830 1831 static int 1832 aclent_match(void *entry1, void *entry2) 1833 { 1834 aclent_t *aclent1 = (aclent_t *)entry1; 1835 aclent_t *aclent2 = (aclent_t *)entry2; 1836 1837 return (memcmp(aclent1, aclent2, sizeof (aclent_t))); 1838 } 1839 1840 /* 1841 * Find acl entries in acl that correspond to removeacl. Search 1842 * is started from slot. The flag argument indicates whether to 1843 * remove all matches or just the first match. 1844 */ 1845 int 1846 acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag) 1847 { 1848 int i, j; 1849 int match; 1850 int (*acl_match)(void *acl1, void *acl2); 1851 void *acl_entry, *remove_entry; 1852 void *start; 1853 int found = 0; 1854 1855 if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST) 1856 flag = ACL_REMOVE_FIRST; 1857 1858 if (acl == NULL || removeacl == NULL) 1859 return (EACL_NO_ACL_ENTRY); 1860 1861 if (acl->acl_type != removeacl->acl_type) 1862 return (EACL_DIFF_TYPE); 1863 1864 if (acl->acl_type == ACLENT_T) 1865 acl_match = aclent_match; 1866 else 1867 acl_match = ace_match; 1868 1869 for (i = 0, remove_entry = removeacl->acl_aclp; 1870 i != removeacl->acl_cnt; i++) { 1871 1872 j = 0; 1873 acl_entry = (char *)acl->acl_aclp + 1874 (acl->acl_entry_size * start_slot); 1875 for (;;) { 1876 match = acl_match(acl_entry, remove_entry); 1877 if (match == 0) { 1878 found++; 1879 start = (char *)acl_entry + 1880 acl->acl_entry_size; 1881 (void) memmove(acl_entry, start, 1882 acl->acl_entry_size * 1883 acl->acl_cnt-- - (j + 1)); 1884 1885 if (flag == ACL_REMOVE_FIRST) 1886 break; 1887 /* 1888 * List has changed, restart search from 1889 * beginning. 1890 */ 1891 acl_entry = acl->acl_aclp; 1892 j = 0; 1893 continue; 1894 } 1895 acl_entry = ((char *)acl_entry + acl->acl_entry_size); 1896 if (++j >= acl->acl_cnt) { 1897 break; 1898 } 1899 } 1900 } 1901 1902 return ((found == 0) ? EACL_NO_ACL_ENTRY : 0); 1903 } 1904 1905 /* 1906 * Replace entires entries in acl1 with the corresponding entries 1907 * in newentries. The where argument specifies where to begin 1908 * the replacement. If the where argument is 1 greater than the 1909 * number of acl entries in acl1 then they are appended. If the 1910 * where argument is 2+ greater than the number of acl entries then 1911 * EACL_INVALID_SLOT is returned. 1912 */ 1913 int 1914 acl_modifyentries(acl_t *acl1, acl_t *newentries, int where) 1915 { 1916 1917 int slot; 1918 int slots_needed; 1919 int slots_left; 1920 int newsize; 1921 1922 if (acl1 == NULL || newentries == NULL) 1923 return (EACL_NO_ACL_ENTRY); 1924 1925 if (where < 0 || where >= acl1->acl_cnt) 1926 return (EACL_INVALID_SLOT); 1927 1928 if (acl1->acl_type != newentries->acl_type) 1929 return (EACL_DIFF_TYPE); 1930 1931 slot = where; 1932 1933 slots_left = acl1->acl_cnt - slot + 1; 1934 if (slots_left < newentries->acl_cnt) { 1935 slots_needed = newentries->acl_cnt - slots_left; 1936 newsize = (acl1->acl_entry_size * acl1->acl_cnt) + 1937 (acl1->acl_entry_size * slots_needed); 1938 acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1939 if (acl1->acl_aclp == NULL) 1940 return (-1); 1941 } 1942 (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot), 1943 newentries->acl_aclp, 1944 newentries->acl_entry_size * newentries->acl_cnt); 1945 1946 /* 1947 * Did ACL grow? 1948 */ 1949 1950 if ((slot + newentries->acl_cnt) > acl1->acl_cnt) { 1951 acl1->acl_cnt = slot + newentries->acl_cnt; 1952 } 1953 1954 return (0); 1955 } 1956 1957 /* 1958 * Add acl2 entries into acl1. The where argument specifies where 1959 * to add the entries. 1960 */ 1961 int 1962 acl_addentries(acl_t *acl1, acl_t *acl2, int where) 1963 { 1964 1965 int newsize; 1966 int len; 1967 void *start; 1968 void *to; 1969 1970 if (acl1 == NULL || acl2 == NULL) 1971 return (EACL_NO_ACL_ENTRY); 1972 1973 if (acl1->acl_type != acl2->acl_type) 1974 return (EACL_DIFF_TYPE); 1975 1976 /* 1977 * allow where to specify 1 past last slot for an append operation 1978 * but anything greater is an error. 1979 */ 1980 if (where < 0 || where > acl1->acl_cnt) 1981 return (EACL_INVALID_SLOT); 1982 1983 newsize = (acl2->acl_entry_size * acl2->acl_cnt) + 1984 (acl1->acl_entry_size * acl1->acl_cnt); 1985 acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1986 if (acl1->acl_aclp == NULL) 1987 return (-1); 1988 1989 /* 1990 * first push down entries where new ones will be inserted 1991 */ 1992 1993 to = (void *)((char *)acl1->acl_aclp + 1994 ((where + acl2->acl_cnt) * acl1->acl_entry_size)); 1995 1996 start = (void *)((char *)acl1->acl_aclp + 1997 where * acl1->acl_entry_size); 1998 1999 if (where < acl1->acl_cnt) { 2000 len = (acl1->acl_cnt - where) * acl1->acl_entry_size; 2001 (void) memmove(to, start, len); 2002 } 2003 2004 /* 2005 * now stick in new entries. 2006 */ 2007 2008 (void) memmove(start, acl2->acl_aclp, 2009 acl2->acl_cnt * acl2->acl_entry_size); 2010 2011 acl1->acl_cnt += acl2->acl_cnt; 2012 return (0); 2013 } 2014 2015 /* 2016 * return text for an ACL error. 2017 */ 2018 char * 2019 acl_strerror(int errnum) 2020 { 2021 switch (errnum) { 2022 case EACL_GRP_ERROR: 2023 return (dgettext(TEXT_DOMAIN, 2024 "There is more than one group or default group entry")); 2025 case EACL_USER_ERROR: 2026 return (dgettext(TEXT_DOMAIN, 2027 "There is more than one user or default user entry")); 2028 case EACL_OTHER_ERROR: 2029 return (dgettext(TEXT_DOMAIN, 2030 "There is more than one other entry")); 2031 case EACL_CLASS_ERROR: 2032 return (dgettext(TEXT_DOMAIN, 2033 "There is more than one mask entry")); 2034 case EACL_DUPLICATE_ERROR: 2035 return (dgettext(TEXT_DOMAIN, 2036 "Duplicate user or group entries")); 2037 case EACL_MISS_ERROR: 2038 return (dgettext(TEXT_DOMAIN, 2039 "Missing user/group owner, other, mask entry")); 2040 case EACL_MEM_ERROR: 2041 return (dgettext(TEXT_DOMAIN, 2042 "Memory error")); 2043 case EACL_ENTRY_ERROR: 2044 return (dgettext(TEXT_DOMAIN, 2045 "Unrecognized entry type")); 2046 case EACL_INHERIT_ERROR: 2047 return (dgettext(TEXT_DOMAIN, 2048 "Invalid inheritance flags")); 2049 case EACL_FLAGS_ERROR: 2050 return (dgettext(TEXT_DOMAIN, 2051 "Unrecognized entry flags")); 2052 case EACL_PERM_MASK_ERROR: 2053 return (dgettext(TEXT_DOMAIN, 2054 "Invalid ACL permissions")); 2055 case EACL_COUNT_ERROR: 2056 return (dgettext(TEXT_DOMAIN, 2057 "Invalid ACL count")); 2058 case EACL_INVALID_SLOT: 2059 return (dgettext(TEXT_DOMAIN, 2060 "Invalid ACL entry number specified")); 2061 case EACL_NO_ACL_ENTRY: 2062 return (dgettext(TEXT_DOMAIN, 2063 "ACL entry doesn't exist")); 2064 case EACL_DIFF_TYPE: 2065 return (dgettext(TEXT_DOMAIN, 2066 "ACL type's are different")); 2067 case EACL_INVALID_USER_GROUP: 2068 return (dgettext(TEXT_DOMAIN, "Invalid user or group")); 2069 case EACL_INVALID_STR: 2070 return (dgettext(TEXT_DOMAIN, "ACL string is invalid")); 2071 case EACL_FIELD_NOT_BLANK: 2072 return (dgettext(TEXT_DOMAIN, "Field expected to be blank")); 2073 case EACL_INVALID_ACCESS_TYPE: 2074 return (dgettext(TEXT_DOMAIN, "Invalid access type")); 2075 case EACL_UNKNOWN_DATA: 2076 return (dgettext(TEXT_DOMAIN, "Unrecognized entry")); 2077 case EACL_MISSING_FIELDS: 2078 return (dgettext(TEXT_DOMAIN, 2079 "ACL specification missing required fields")); 2080 case EACL_INHERIT_NOTDIR: 2081 return (dgettext(TEXT_DOMAIN, 2082 "Inheritance flags are only allowed on directories")); 2083 case -1: 2084 return (strerror(errno)); 2085 default: 2086 errno = EINVAL; 2087 return (dgettext(TEXT_DOMAIN, "Unknown error")); 2088 } 2089 } 2090 2091 extern int yyinteractive; 2092 2093 /* PRINTFLIKE1 */ 2094 void 2095 acl_error(const char *fmt, ...) 2096 { 2097 va_list va; 2098 2099 if (yyinteractive == 0) 2100 return; 2101 2102 va_start(va, fmt); 2103 (void) vfprintf(stderr, fmt, va); 2104 va_end(va); 2105 } 2106