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 static int 1437 cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp) 1438 { 1439 const char *fname; 1440 int fd; 1441 int ace_acl = 0; 1442 int error; 1443 int getcmd, cntcmd; 1444 acl_t *acl_info; 1445 int save_errno; 1446 int stat_error; 1447 struct stat64 statbuf; 1448 1449 *aclp = NULL; 1450 if (type == ACL_PATH) { 1451 fname = inp.file; 1452 ace_acl = pathconf(fname, _PC_ACL_ENABLED); 1453 } else { 1454 fd = inp.fd; 1455 ace_acl = fpathconf(fd, _PC_ACL_ENABLED); 1456 } 1457 1458 if (ace_acl == -1) 1459 return (-1); 1460 1461 /* 1462 * if acl's aren't supported then 1463 * send it through the old GETACL interface 1464 */ 1465 if (ace_acl == 0) { 1466 ace_acl = _ACL_ACLENT_ENABLED; 1467 } 1468 1469 if (ace_acl & _ACL_ACE_ENABLED) { 1470 cntcmd = ACE_GETACLCNT; 1471 getcmd = ACE_GETACL; 1472 acl_info = acl_alloc(ACE_T); 1473 } else { 1474 cntcmd = GETACLCNT; 1475 getcmd = GETACL; 1476 acl_info = acl_alloc(ACLENT_T); 1477 } 1478 1479 if (acl_info == NULL) 1480 return (-1); 1481 1482 if (type == ACL_PATH) { 1483 acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL); 1484 } else { 1485 acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL); 1486 } 1487 1488 save_errno = errno; 1489 if (acl_info->acl_cnt < 0) { 1490 acl_free(acl_info); 1491 errno = save_errno; 1492 return (-1); 1493 } 1494 1495 if (acl_info->acl_cnt == 0) { 1496 acl_free(acl_info); 1497 errno = save_errno; 1498 return (0); 1499 } 1500 1501 acl_info->acl_aclp = 1502 malloc(acl_info->acl_cnt * acl_info->acl_entry_size); 1503 save_errno = errno; 1504 1505 if (acl_info->acl_aclp == NULL) { 1506 acl_free(acl_info); 1507 errno = save_errno; 1508 return (-1); 1509 } 1510 1511 if (type == ACL_PATH) { 1512 stat_error = stat64(fname, &statbuf); 1513 error = acl(fname, getcmd, acl_info->acl_cnt, 1514 acl_info->acl_aclp); 1515 } else { 1516 stat_error = fstat64(fd, &statbuf); 1517 error = facl(fd, getcmd, acl_info->acl_cnt, 1518 acl_info->acl_aclp); 1519 } 1520 1521 save_errno = errno; 1522 if (error == -1) { 1523 acl_free(acl_info); 1524 errno = save_errno; 1525 return (-1); 1526 } 1527 1528 1529 if (stat_error == 0) { 1530 acl_info->acl_flags = 1531 (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0); 1532 } else 1533 acl_info->acl_flags = 0; 1534 1535 switch (acl_info->acl_type) { 1536 case ACLENT_T: 1537 if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 1538 acl_info->acl_flags |= ACL_IS_TRIVIAL; 1539 break; 1540 case ACE_T: 1541 if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 1542 acl_info->acl_flags |= ACL_IS_TRIVIAL; 1543 break; 1544 default: 1545 errno = EINVAL; 1546 acl_free(acl_info); 1547 return (-1); 1548 } 1549 1550 if ((acl_info->acl_flags & ACL_IS_TRIVIAL) && 1551 (get_flag & ACL_NO_TRIVIAL)) { 1552 acl_free(acl_info); 1553 errno = 0; 1554 return (0); 1555 } 1556 1557 *aclp = acl_info; 1558 return (0); 1559 } 1560 1561 /* 1562 * return -1 on failure, otherwise the number of acl 1563 * entries is returned 1564 */ 1565 int 1566 acl_get(const char *path, int get_flag, acl_t **aclp) 1567 { 1568 acl_inp acl_inp; 1569 acl_inp.file = path; 1570 1571 return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp)); 1572 } 1573 1574 int 1575 facl_get(int fd, int get_flag, acl_t **aclp) 1576 { 1577 1578 acl_inp acl_inp; 1579 acl_inp.fd = fd; 1580 1581 return (cacl_get(acl_inp, get_flag, ACL_FD, aclp)); 1582 } 1583 1584 static int 1585 acl_translate(acl_t *aclp, int target_flavor, int isdir, uid_t owner, 1586 gid_t group) 1587 { 1588 int aclcnt; 1589 void *acldata; 1590 int error; 1591 1592 /* 1593 * See if we need to translate 1594 */ 1595 if ((target_flavor == _ACL_ACE_ENABLED && aclp->acl_type == ACE_T) || 1596 (target_flavor == _ACL_ACLENT_ENABLED && 1597 aclp->acl_type == ACLENT_T)) 1598 return (0); 1599 1600 if (target_flavor == -1) 1601 return (-1); 1602 1603 if (target_flavor == _ACL_ACE_ENABLED && 1604 aclp->acl_type == ACLENT_T) { 1605 error = convert_aent_to_ace(aclp->acl_aclp, 1606 aclp->acl_cnt, isdir, (ace_t **)&acldata, &aclcnt); 1607 if (error) { 1608 errno = error; 1609 return (-1); 1610 } 1611 } else if (target_flavor == _ACL_ACLENT_ENABLED && 1612 aclp->acl_type == ACE_T) { 1613 error = convert_ace_to_aent(aclp->acl_aclp, aclp->acl_cnt, 1614 isdir, owner, group, (aclent_t **)&acldata, &aclcnt); 1615 if (error) { 1616 errno = error; 1617 return (-1); 1618 } 1619 } else { 1620 errno = ENOTSUP; 1621 return (-1); 1622 } 1623 1624 /* 1625 * replace old acl with newly translated acl 1626 */ 1627 free(aclp->acl_aclp); 1628 aclp->acl_aclp = acldata; 1629 aclp->acl_cnt = aclcnt; 1630 aclp->acl_type = (target_flavor == _ACL_ACE_ENABLED) ? ACE_T : ACLENT_T; 1631 return (0); 1632 } 1633 1634 /* 1635 * Set an ACL, translates acl to ace_t when appropriate. 1636 */ 1637 static int 1638 cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) 1639 { 1640 int error = 0; 1641 int acl_flavor_target; 1642 struct stat64 statbuf; 1643 int stat_error; 1644 int isdir; 1645 1646 1647 if (type == ACL_PATH) { 1648 stat_error = stat64(acl_inp->file, &statbuf); 1649 if (stat_error) 1650 return (-1); 1651 acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); 1652 } else { 1653 stat_error = fstat64(acl_inp->fd, &statbuf); 1654 if (stat_error) 1655 return (-1); 1656 acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); 1657 } 1658 1659 isdir = S_ISDIR(statbuf.st_mode); 1660 1661 if ((error = acl_translate(aclp, acl_flavor_target, isdir, 1662 statbuf.st_uid, statbuf.st_gid)) != 0) { 1663 return (error); 1664 } 1665 1666 if (type == ACL_PATH) { 1667 error = acl(acl_inp->file, 1668 (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 1669 aclp->acl_cnt, aclp->acl_aclp); 1670 } else { 1671 error = facl(acl_inp->fd, 1672 (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 1673 aclp->acl_cnt, aclp->acl_aclp); 1674 } 1675 1676 return (error); 1677 } 1678 1679 int 1680 acl_set(const char *path, acl_t *aclp) 1681 { 1682 acl_inp acl_inp; 1683 1684 acl_inp.file = path; 1685 1686 return (cacl_set(&acl_inp, aclp, ACL_PATH)); 1687 } 1688 1689 int 1690 facl_set(int fd, acl_t *aclp) 1691 { 1692 acl_inp acl_inp; 1693 1694 acl_inp.fd = fd; 1695 1696 return (cacl_set(&acl_inp, aclp, ACL_FD)); 1697 } 1698 1699 int 1700 acl_cnt(acl_t *aclp) 1701 { 1702 return (aclp->acl_cnt); 1703 } 1704 1705 int 1706 acl_type(acl_t *aclp) 1707 { 1708 return (aclp->acl_type); 1709 } 1710 1711 acl_t * 1712 acl_dup(acl_t *aclp) 1713 { 1714 acl_t *newaclp; 1715 1716 newaclp = acl_alloc(aclp->acl_type); 1717 if (newaclp == NULL) 1718 return (NULL); 1719 1720 newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt); 1721 if (newaclp->acl_aclp == NULL) { 1722 acl_free(newaclp); 1723 return (NULL); 1724 } 1725 1726 (void) memcpy(newaclp->acl_aclp, 1727 aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt); 1728 newaclp->acl_cnt = aclp->acl_cnt; 1729 1730 return (newaclp); 1731 } 1732 1733 int 1734 acl_flags(acl_t *aclp) 1735 { 1736 return (aclp->acl_flags); 1737 } 1738 1739 void * 1740 acl_data(acl_t *aclp) 1741 { 1742 return (aclp->acl_aclp); 1743 } 1744 1745 /* 1746 * Remove an ACL from a file and create a trivial ACL based 1747 * off of the mode argument. After acl has been set owner/group 1748 * are updated to match owner,group arguments 1749 */ 1750 int 1751 acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) 1752 { 1753 int error = 0; 1754 aclent_t min_acl[MIN_ACL_ENTRIES]; 1755 ace_t min_ace_acl[6]; /* owner, group, everyone + complement denies */ 1756 int acl_flavor; 1757 int aclcnt; 1758 1759 acl_flavor = pathconf(file, _PC_ACL_ENABLED); 1760 1761 if (acl_flavor == -1) 1762 return (-1); 1763 /* 1764 * force it through aclent flavor when file system doesn't 1765 * understand question 1766 */ 1767 if (acl_flavor == 0) 1768 acl_flavor = _ACL_ACLENT_ENABLED; 1769 1770 if (acl_flavor & _ACL_ACLENT_ENABLED) { 1771 min_acl[0].a_type = USER_OBJ; 1772 min_acl[0].a_id = owner; 1773 min_acl[0].a_perm = ((mode & 0700) >> 6); 1774 min_acl[1].a_type = GROUP_OBJ; 1775 min_acl[1].a_id = group; 1776 min_acl[1].a_perm = ((mode & 0070) >> 3); 1777 min_acl[2].a_type = CLASS_OBJ; 1778 min_acl[2].a_id = (uid_t)-1; 1779 min_acl[2].a_perm = ((mode & 0070) >> 3); 1780 min_acl[3].a_type = OTHER_OBJ; 1781 min_acl[3].a_id = (uid_t)-1; 1782 min_acl[3].a_perm = (mode & 0007); 1783 aclcnt = 4; 1784 error = acl(file, SETACL, aclcnt, min_acl); 1785 } else if (acl_flavor & _ACL_ACE_ENABLED) { 1786 (void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6); 1787 1788 /* 1789 * Make aces match request mode 1790 */ 1791 adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6); 1792 adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3); 1793 adjust_ace_pair(&min_ace_acl[4], mode & 0007); 1794 1795 error = acl(file, ACE_SETACL, 6, min_ace_acl); 1796 } else { 1797 errno = EINVAL; 1798 error = 1; 1799 } 1800 1801 if (error == 0) 1802 error = chown(file, owner, group); 1803 return (error); 1804 } 1805 1806 static int 1807 ace_match(void *entry1, void *entry2) 1808 { 1809 ace_t *p1 = (ace_t *)entry1; 1810 ace_t *p2 = (ace_t *)entry2; 1811 ace_t ace1, ace2; 1812 1813 ace1 = *p1; 1814 ace2 = *p2; 1815 1816 /* 1817 * Need to fixup who field for abstrations for 1818 * accurate comparison, since field is undefined. 1819 */ 1820 if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 1821 ace1.a_who = -1; 1822 if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 1823 ace2.a_who = -1; 1824 return (memcmp(&ace1, &ace2, sizeof (ace_t))); 1825 } 1826 1827 static int 1828 aclent_match(void *entry1, void *entry2) 1829 { 1830 aclent_t *aclent1 = (aclent_t *)entry1; 1831 aclent_t *aclent2 = (aclent_t *)entry2; 1832 1833 return (memcmp(aclent1, aclent2, sizeof (aclent_t))); 1834 } 1835 1836 /* 1837 * Find acl entries in acl that correspond to removeacl. Search 1838 * is started from slot. The flag argument indicates whether to 1839 * remove all matches or just the first match. 1840 */ 1841 int 1842 acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag) 1843 { 1844 int i, j; 1845 int match; 1846 int (*acl_match)(void *acl1, void *acl2); 1847 void *acl_entry, *remove_entry; 1848 void *start; 1849 int found = 0; 1850 1851 if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST) 1852 flag = ACL_REMOVE_FIRST; 1853 1854 if (acl == NULL || removeacl == NULL) 1855 return (EACL_NO_ACL_ENTRY); 1856 1857 if (acl->acl_type != removeacl->acl_type) 1858 return (EACL_DIFF_TYPE); 1859 1860 if (acl->acl_type == ACLENT_T) 1861 acl_match = aclent_match; 1862 else 1863 acl_match = ace_match; 1864 1865 for (i = 0, remove_entry = removeacl->acl_aclp; 1866 i != removeacl->acl_cnt; i++) { 1867 1868 j = 0; 1869 acl_entry = (char *)acl->acl_aclp + 1870 (acl->acl_entry_size * start_slot); 1871 for (;;) { 1872 match = acl_match(acl_entry, remove_entry); 1873 if (match == 0) { 1874 found++; 1875 start = (char *)acl_entry + 1876 acl->acl_entry_size; 1877 (void) memmove(acl_entry, start, 1878 acl->acl_entry_size * 1879 acl->acl_cnt-- - (j + 1)); 1880 1881 if (flag == ACL_REMOVE_FIRST) 1882 break; 1883 /* 1884 * List has changed, restart search from 1885 * beginning. 1886 */ 1887 acl_entry = acl->acl_aclp; 1888 j = 0; 1889 continue; 1890 } 1891 acl_entry = ((char *)acl_entry + acl->acl_entry_size); 1892 if (++j >= acl->acl_cnt) { 1893 break; 1894 } 1895 } 1896 } 1897 1898 return ((found == 0) ? EACL_NO_ACL_ENTRY : 0); 1899 } 1900 1901 /* 1902 * Replace entires entries in acl1 with the corresponding entries 1903 * in newentries. The where argument specifies where to begin 1904 * the replacement. If the where argument is 1 greater than the 1905 * number of acl entries in acl1 then they are appended. If the 1906 * where argument is 2+ greater than the number of acl entries then 1907 * EACL_INVALID_SLOT is returned. 1908 */ 1909 int 1910 acl_modifyentries(acl_t *acl1, acl_t *newentries, int where) 1911 { 1912 1913 int slot; 1914 int slots_needed; 1915 int slots_left; 1916 int newsize; 1917 1918 if (acl1 == NULL || newentries == NULL) 1919 return (EACL_NO_ACL_ENTRY); 1920 1921 if (where < 0 || where >= acl1->acl_cnt) 1922 return (EACL_INVALID_SLOT); 1923 1924 if (acl1->acl_type != newentries->acl_type) 1925 return (EACL_DIFF_TYPE); 1926 1927 slot = where; 1928 1929 slots_left = acl1->acl_cnt - slot + 1; 1930 if (slots_left < newentries->acl_cnt) { 1931 slots_needed = newentries->acl_cnt - slots_left; 1932 newsize = (acl1->acl_entry_size * acl1->acl_cnt) + 1933 (acl1->acl_entry_size * slots_needed); 1934 acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1935 if (acl1->acl_aclp == NULL) 1936 return (-1); 1937 } 1938 (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot), 1939 newentries->acl_aclp, 1940 newentries->acl_entry_size * newentries->acl_cnt); 1941 1942 /* 1943 * Did ACL grow? 1944 */ 1945 1946 if ((slot + newentries->acl_cnt) > acl1->acl_cnt) { 1947 acl1->acl_cnt = slot + newentries->acl_cnt; 1948 } 1949 1950 return (0); 1951 } 1952 1953 /* 1954 * Add acl2 entries into acl1. The where argument specifies where 1955 * to add the entries. 1956 */ 1957 int 1958 acl_addentries(acl_t *acl1, acl_t *acl2, int where) 1959 { 1960 1961 int newsize; 1962 int len; 1963 void *start; 1964 void *to; 1965 1966 if (acl1 == NULL || acl2 == NULL) 1967 return (EACL_NO_ACL_ENTRY); 1968 1969 if (acl1->acl_type != acl2->acl_type) 1970 return (EACL_DIFF_TYPE); 1971 1972 /* 1973 * allow where to specify 1 past last slot for an append operation 1974 * but anything greater is an error. 1975 */ 1976 if (where < 0 || where > acl1->acl_cnt) 1977 return (EACL_INVALID_SLOT); 1978 1979 newsize = (acl2->acl_entry_size * acl2->acl_cnt) + 1980 (acl1->acl_entry_size * acl1->acl_cnt); 1981 acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1982 if (acl1->acl_aclp == NULL) 1983 return (-1); 1984 1985 /* 1986 * first push down entries where new ones will be inserted 1987 */ 1988 1989 to = (void *)((char *)acl1->acl_aclp + 1990 ((where + acl2->acl_cnt) * acl1->acl_entry_size)); 1991 1992 start = (void *)((char *)acl1->acl_aclp + 1993 where * acl1->acl_entry_size); 1994 1995 if (where < acl1->acl_cnt) { 1996 len = (acl1->acl_cnt - where) * acl1->acl_entry_size; 1997 (void) memmove(to, start, len); 1998 } 1999 2000 /* 2001 * now stick in new entries. 2002 */ 2003 2004 (void) memmove(start, acl2->acl_aclp, 2005 acl2->acl_cnt * acl2->acl_entry_size); 2006 2007 acl1->acl_cnt += acl2->acl_cnt; 2008 return (0); 2009 } 2010 2011 /* 2012 * return text for an ACL error. 2013 */ 2014 char * 2015 acl_strerror(int errnum) 2016 { 2017 switch (errnum) { 2018 case EACL_GRP_ERROR: 2019 return (dgettext(TEXT_DOMAIN, 2020 "There is more than one group or default group entry")); 2021 case EACL_USER_ERROR: 2022 return (dgettext(TEXT_DOMAIN, 2023 "There is more than one user or default user entry")); 2024 case EACL_OTHER_ERROR: 2025 return (dgettext(TEXT_DOMAIN, 2026 "There is more than one other entry")); 2027 case EACL_CLASS_ERROR: 2028 return (dgettext(TEXT_DOMAIN, 2029 "There is more than one mask entry")); 2030 case EACL_DUPLICATE_ERROR: 2031 return (dgettext(TEXT_DOMAIN, 2032 "Duplicate user or group entries")); 2033 case EACL_MISS_ERROR: 2034 return (dgettext(TEXT_DOMAIN, 2035 "Missing user/group owner, other, mask entry")); 2036 case EACL_MEM_ERROR: 2037 return (dgettext(TEXT_DOMAIN, 2038 "Memory error")); 2039 case EACL_ENTRY_ERROR: 2040 return (dgettext(TEXT_DOMAIN, 2041 "Unrecognized entry type")); 2042 case EACL_INHERIT_ERROR: 2043 return (dgettext(TEXT_DOMAIN, 2044 "Invalid inheritance flags")); 2045 case EACL_FLAGS_ERROR: 2046 return (dgettext(TEXT_DOMAIN, 2047 "Unrecognized entry flags")); 2048 case EACL_PERM_MASK_ERROR: 2049 return (dgettext(TEXT_DOMAIN, 2050 "Invalid ACL permissions")); 2051 case EACL_COUNT_ERROR: 2052 return (dgettext(TEXT_DOMAIN, 2053 "Invalid ACL count")); 2054 case EACL_INVALID_SLOT: 2055 return (dgettext(TEXT_DOMAIN, 2056 "Invalid ACL entry number specified")); 2057 case EACL_NO_ACL_ENTRY: 2058 return (dgettext(TEXT_DOMAIN, 2059 "ACL entry doesn't exist")); 2060 case EACL_DIFF_TYPE: 2061 return (dgettext(TEXT_DOMAIN, 2062 "ACL type's are different")); 2063 case EACL_INVALID_USER_GROUP: 2064 return (dgettext(TEXT_DOMAIN, "Invalid user or group")); 2065 case EACL_INVALID_STR: 2066 return (dgettext(TEXT_DOMAIN, "ACL string is invalid")); 2067 case EACL_FIELD_NOT_BLANK: 2068 return (dgettext(TEXT_DOMAIN, "Field expected to be blank")); 2069 case EACL_INVALID_ACCESS_TYPE: 2070 return (dgettext(TEXT_DOMAIN, "Invalid access type")); 2071 case EACL_UNKNOWN_DATA: 2072 return (dgettext(TEXT_DOMAIN, "Unrecognized entry")); 2073 case EACL_MISSING_FIELDS: 2074 return (dgettext(TEXT_DOMAIN, 2075 "ACL specification missing required fields")); 2076 case EACL_INHERIT_NOTDIR: 2077 return (dgettext(TEXT_DOMAIN, 2078 "Inheritance flags are only allowed on directories")); 2079 case -1: 2080 return (strerror(errno)); 2081 default: 2082 errno = EINVAL; 2083 return (dgettext(TEXT_DOMAIN, "Unknown error")); 2084 } 2085 } 2086 2087 extern int yyinteractive; 2088 2089 /* PRINTFLIKE1 */ 2090 void 2091 acl_error(const char *fmt, ...) 2092 { 2093 va_list va; 2094 2095 if (yyinteractive == 0) 2096 return; 2097 2098 va_start(va, fmt); 2099 (void) vfprintf(stderr, fmt, va); 2100 va_end(va); 2101 } 2102