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