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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 #include <limits.h> 33 #include <grp.h> 34 #include <pwd.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 44 #define ACL_PATH 0 45 #define ACL_FD 1 46 47 #define ACE_POSIX_SUPPORTED_BITS (ACE_READ_DATA | \ 48 ACE_WRITE_DATA | ACE_APPEND_DATA | ACE_EXECUTE | \ 49 ACE_READ_ATTRIBUTES | ACE_READ_ACL | ACE_WRITE_ACL) 50 51 52 #define ACL_SYNCHRONIZE_SET_ALLOW 0x0000002 53 #define ACL_SYNCHRONIZE_SET_DENY 0x0000001 54 55 #define ACL_WRITE_OWNER_SET_ALLOW 0x0000020 56 #define ACL_WRITE_OWNER_SET_DENY 0x0000010 57 58 #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000 59 #define ACL_WRITE_ATTRS_OWNER_SET_DENY 0x0001000 60 61 #define ACL_WRITE_ATTRS_WRITER_SET_DENY 0x0010000 62 63 #define ACL_DELETE_SET_ALLOW 0x0000200 64 #define ACL_DELETE_SET_DENY 0x0000100 65 66 #define ACL_READ_NAMED_READER_SET_ALLOW 0x2000000 67 68 #define ACL_WRITE_NAMED_WRITER_SET_ALLOW 0x0200000 69 #define ACL_WRITE_NAMED_WRITER_SET_DENY 0x0100000 70 71 #define ACL_WRITE_ATTRS_OWNER_SET_ALLOW 0x0002000 72 #define ACL_WRITE_ATTRS_WRITER_SET_ALLOW 0x0020000 73 74 #define ACL_WRITE_OWNER_ERR_DENY 0x0000040 75 #define ACL_READ_NAMED_READER_SET_DENY 0x1000000 76 77 typedef union { 78 const char *file; 79 int fd; 80 } acl_inp; 81 82 acl_t * 83 acl_alloc(enum acl_type type) 84 { 85 acl_t *aclp; 86 87 aclp = malloc(sizeof (acl_t)); 88 89 if (aclp == NULL) 90 return (NULL); 91 92 aclp->acl_aclp = NULL; 93 aclp->acl_cnt = 0; 94 95 switch (type) { 96 case ACE_T: 97 aclp->acl_type = ACE_T; 98 aclp->acl_entry_size = sizeof (ace_t); 99 break; 100 case ACLENT_T: 101 aclp->acl_type = ACLENT_T; 102 aclp->acl_entry_size = sizeof (aclent_t); 103 break; 104 default: 105 acl_free(aclp); 106 aclp = NULL; 107 } 108 return (aclp); 109 } 110 111 /* 112 * Free acl_t structure 113 */ 114 void 115 acl_free(acl_t *aclp) 116 { 117 if (aclp == NULL) 118 return; 119 120 if (aclp->acl_aclp) 121 free(aclp->acl_aclp); 122 free(aclp); 123 } 124 125 /* 126 * Determine whether a file has a trivial ACL 127 * returns: 0 = trivial 128 * 1 = nontrivial 129 * <0 some other system failure, such as ENOENT or EPERM 130 */ 131 int 132 acl_trivial(const char *filename) 133 { 134 int acl_flavor; 135 int aclcnt; 136 int cntcmd; 137 int val = 0; 138 ace_t *acep; 139 140 acl_flavor = pathconf(filename, _PC_ACL_ENABLED); 141 if (acl_flavor == -1) 142 return (-1); 143 144 if (acl_flavor == _ACL_ACE_ENABLED) 145 cntcmd = ACE_GETACLCNT; 146 else 147 cntcmd = GETACLCNT; 148 149 aclcnt = acl(filename, cntcmd, 0, NULL); 150 if (aclcnt > 0) { 151 if (acl_flavor == _ACL_ACE_ENABLED) { 152 acep = malloc(sizeof (ace_t) * aclcnt); 153 if (acep == NULL) 154 return (-1); 155 if (acl(filename, ACE_GETACL, 156 aclcnt, acep) < 0) { 157 free(acep); 158 return (-1); 159 } 160 161 val = ace_trivial(acep, aclcnt); 162 free(acep); 163 164 } else if (aclcnt > MIN_ACL_ENTRIES) 165 val = 1; 166 } 167 return (val); 168 } 169 170 static uint32_t 171 access_mask_set(int haswriteperm, int hasreadperm, int isowner, int isallow) 172 { 173 uint32_t access_mask = 0; 174 int acl_produce; 175 int synchronize_set = 0, write_owner_set = 0; 176 int delete_set = 0, write_attrs_set = 0; 177 int read_named_set = 0, write_named_set = 0; 178 179 acl_produce = (ACL_SYNCHRONIZE_SET_ALLOW | 180 ACL_WRITE_ATTRS_OWNER_SET_ALLOW | 181 ACL_WRITE_ATTRS_WRITER_SET_DENY); 182 183 if (isallow) { 184 synchronize_set = ACL_SYNCHRONIZE_SET_ALLOW; 185 write_owner_set = ACL_WRITE_OWNER_SET_ALLOW; 186 delete_set = ACL_DELETE_SET_ALLOW; 187 if (hasreadperm) 188 read_named_set = ACL_READ_NAMED_READER_SET_ALLOW; 189 if (haswriteperm) 190 write_named_set = ACL_WRITE_NAMED_WRITER_SET_ALLOW; 191 if (isowner) 192 write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_ALLOW; 193 else if (haswriteperm) 194 write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_ALLOW; 195 } else { 196 197 synchronize_set = ACL_SYNCHRONIZE_SET_DENY; 198 write_owner_set = ACL_WRITE_OWNER_SET_DENY; 199 delete_set = ACL_DELETE_SET_DENY; 200 if (hasreadperm) 201 read_named_set = ACL_READ_NAMED_READER_SET_DENY; 202 if (haswriteperm) 203 write_named_set = ACL_WRITE_NAMED_WRITER_SET_DENY; 204 if (isowner) 205 write_attrs_set = ACL_WRITE_ATTRS_OWNER_SET_DENY; 206 else if (haswriteperm) 207 write_attrs_set = ACL_WRITE_ATTRS_WRITER_SET_DENY; 208 else 209 /* 210 * If the entity is not the owner and does not 211 * have write permissions ACE_WRITE_ATTRIBUTES will 212 * always go in the DENY ACE. 213 */ 214 access_mask |= ACE_WRITE_ATTRIBUTES; 215 } 216 217 if (acl_produce & synchronize_set) 218 access_mask |= ACE_SYNCHRONIZE; 219 if (acl_produce & write_owner_set) 220 access_mask |= ACE_WRITE_OWNER; 221 if (acl_produce & delete_set) 222 access_mask |= ACE_DELETE; 223 if (acl_produce & write_attrs_set) 224 access_mask |= ACE_WRITE_ATTRIBUTES; 225 if (acl_produce & read_named_set) 226 access_mask |= ACE_READ_NAMED_ATTRS; 227 if (acl_produce & write_named_set) 228 access_mask |= ACE_WRITE_NAMED_ATTRS; 229 230 return (access_mask); 231 } 232 233 /* 234 * Given an mode_t, convert it into an access_mask as used 235 * by nfsace, assuming aclent_t -> nfsace semantics. 236 */ 237 static uint32_t 238 mode_to_ace_access(mode_t mode, int isdir, int isowner, int isallow) 239 { 240 uint32_t access = 0; 241 int haswriteperm = 0; 242 int hasreadperm = 0; 243 244 if (isallow) { 245 haswriteperm = (mode & 02); 246 hasreadperm = (mode & 04); 247 } else { 248 haswriteperm = !(mode & 02); 249 hasreadperm = !(mode & 04); 250 } 251 252 /* 253 * The following call takes care of correctly setting the following 254 * mask bits in the access_mask: 255 * ACE_SYNCHRONIZE, ACE_WRITE_OWNER, ACE_DELETE, 256 * ACE_WRITE_ATTRIBUTES, ACE_WRITE_NAMED_ATTRS, ACE_READ_NAMED_ATTRS 257 */ 258 access = access_mask_set(haswriteperm, hasreadperm, isowner, isallow); 259 260 if (isallow) { 261 access |= ACE_READ_ACL | ACE_READ_ATTRIBUTES; 262 if (isowner) 263 access |= ACE_WRITE_ACL; 264 } else { 265 if (! isowner) 266 access |= ACE_WRITE_ACL; 267 } 268 269 /* read */ 270 if (mode & 04) { 271 access |= ACE_READ_DATA; 272 } 273 /* write */ 274 if (mode & 02) { 275 access |= ACE_WRITE_DATA | 276 ACE_APPEND_DATA; 277 if (isdir) 278 access |= ACE_DELETE_CHILD; 279 } 280 /* exec */ 281 if (mode & 01) { 282 access |= ACE_EXECUTE; 283 } 284 285 return (access); 286 } 287 288 /* 289 * Given an nfsace (presumably an ALLOW entry), make a 290 * corresponding DENY entry at the address given. 291 */ 292 static void 293 ace_make_deny(ace_t *allow, ace_t *deny, int isdir, int isowner) 294 { 295 (void) memcpy(deny, allow, sizeof (ace_t)); 296 297 deny->a_who = allow->a_who; 298 299 deny->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 300 deny->a_access_mask ^= ACE_POSIX_SUPPORTED_BITS; 301 if (isdir) 302 deny->a_access_mask ^= ACE_DELETE_CHILD; 303 304 deny->a_access_mask &= ~(ACE_SYNCHRONIZE | ACE_WRITE_OWNER | 305 ACE_DELETE | ACE_WRITE_ATTRIBUTES | ACE_READ_NAMED_ATTRS | 306 ACE_WRITE_NAMED_ATTRS); 307 deny->a_access_mask |= access_mask_set((allow->a_access_mask & 308 ACE_WRITE_DATA), (allow->a_access_mask & ACE_READ_DATA), isowner, 309 B_FALSE); 310 } 311 /* 312 * Make an initial pass over an array of aclent_t's. Gather 313 * information such as an ACL_MASK (if any), number of users, 314 * number of groups, and whether the array needs to be sorted. 315 */ 316 static int 317 ln_aent_preprocess(aclent_t *aclent, int n, 318 int *hasmask, mode_t *mask, 319 int *numuser, int *numgroup, int *needsort) 320 { 321 int error = 0; 322 int i; 323 int curtype = 0; 324 325 *hasmask = 0; 326 *mask = 07; 327 *needsort = 0; 328 *numuser = 0; 329 *numgroup = 0; 330 331 for (i = 0; i < n; i++) { 332 if (aclent[i].a_type < curtype) 333 *needsort = 1; 334 else if (aclent[i].a_type > curtype) 335 curtype = aclent[i].a_type; 336 if (aclent[i].a_type & USER) 337 (*numuser)++; 338 if (aclent[i].a_type & (GROUP | GROUP_OBJ)) 339 (*numgroup)++; 340 if (aclent[i].a_type & CLASS_OBJ) { 341 if (*hasmask) { 342 error = EINVAL; 343 goto out; 344 } else { 345 *hasmask = 1; 346 *mask = aclent[i].a_perm; 347 } 348 } 349 } 350 351 if ((! *hasmask) && (*numuser + *numgroup > 1)) { 352 error = EINVAL; 353 goto out; 354 } 355 356 out: 357 return (error); 358 } 359 360 /* 361 * Convert an array of aclent_t into an array of nfsace entries, 362 * following POSIX draft -> nfsv4 conversion semantics as outlined in 363 * the IETF draft. 364 */ 365 static int 366 ln_aent_to_ace(aclent_t *aclent, int n, ace_t **acepp, int *rescount, int isdir) 367 { 368 int error = 0; 369 mode_t mask; 370 int numuser, numgroup, needsort; 371 int resultsize = 0; 372 int i, groupi = 0, skip; 373 ace_t *acep, *result = NULL; 374 int hasmask; 375 376 error = ln_aent_preprocess(aclent, n, &hasmask, &mask, 377 &numuser, &numgroup, &needsort); 378 if (error != 0) 379 goto out; 380 381 /* allow + deny for each aclent */ 382 resultsize = n * 2; 383 if (hasmask) { 384 /* 385 * stick extra deny on the group_obj and on each 386 * user|group for the mask (the group_obj was added 387 * into the count for numgroup) 388 */ 389 resultsize += numuser + numgroup; 390 /* ... and don't count the mask itself */ 391 resultsize -= 2; 392 } 393 394 /* sort the source if necessary */ 395 if (needsort) 396 ksort((caddr_t)aclent, n, sizeof (aclent_t), cmp2acls); 397 398 result = acep = calloc(1, resultsize * sizeof (ace_t)); 399 if (result == NULL) 400 goto out; 401 402 for (i = 0; i < n; i++) { 403 /* 404 * don't process CLASS_OBJ (mask); mask was grabbed in 405 * ln_aent_preprocess() 406 */ 407 if (aclent[i].a_type & CLASS_OBJ) 408 continue; 409 410 /* If we need an ACL_MASK emulator, prepend it now */ 411 if ((hasmask) && 412 (aclent[i].a_type & (USER | GROUP | GROUP_OBJ))) { 413 acep->a_type = ACE_ACCESS_DENIED_ACE_TYPE; 414 acep->a_flags = 0; 415 if (aclent[i].a_type & GROUP_OBJ) { 416 acep->a_who = -1; 417 acep->a_flags |= 418 (ACE_IDENTIFIER_GROUP|ACE_GROUP); 419 } else if (aclent[i].a_type & USER) { 420 acep->a_who = aclent[i].a_id; 421 } else { 422 acep->a_who = aclent[i].a_id; 423 acep->a_flags |= ACE_IDENTIFIER_GROUP; 424 } 425 if (aclent[i].a_type & ACL_DEFAULT) { 426 acep->a_flags |= ACE_INHERIT_ONLY_ACE | 427 ACE_FILE_INHERIT_ACE | 428 ACE_DIRECTORY_INHERIT_ACE; 429 } 430 /* 431 * Set the access mask for the prepended deny 432 * ace. To do this, we invert the mask (found 433 * in ln_aent_preprocess()) then convert it to an 434 * DENY ace access_mask. 435 */ 436 acep->a_access_mask = mode_to_ace_access((mask ^ 07), 437 isdir, 0, 0); 438 acep += 1; 439 } 440 441 /* handle a_perm -> access_mask */ 442 acep->a_access_mask = mode_to_ace_access(aclent[i].a_perm, 443 isdir, aclent[i].a_type & USER_OBJ, 1); 444 445 /* emulate a default aclent */ 446 if (aclent[i].a_type & ACL_DEFAULT) { 447 acep->a_flags |= ACE_INHERIT_ONLY_ACE | 448 ACE_FILE_INHERIT_ACE | 449 ACE_DIRECTORY_INHERIT_ACE; 450 } 451 452 /* 453 * handle a_perm and a_id 454 * 455 * this must be done last, since it involves the 456 * corresponding deny aces, which are handled 457 * differently for each different a_type. 458 */ 459 if (aclent[i].a_type & USER_OBJ) { 460 acep->a_who = -1; 461 acep->a_flags |= ACE_OWNER; 462 ace_make_deny(acep, acep + 1, isdir, B_TRUE); 463 acep += 2; 464 } else if (aclent[i].a_type & USER) { 465 acep->a_who = aclent[i].a_id; 466 ace_make_deny(acep, acep + 1, isdir, B_FALSE); 467 acep += 2; 468 } else if (aclent[i].a_type & (GROUP_OBJ | GROUP)) { 469 if (aclent[i].a_type & GROUP_OBJ) { 470 acep->a_who = -1; 471 acep->a_flags |= ACE_GROUP; 472 } else { 473 acep->a_who = aclent[i].a_id; 474 } 475 acep->a_flags |= ACE_IDENTIFIER_GROUP; 476 /* 477 * Set the corresponding deny for the group ace. 478 * 479 * The deny aces go after all of the groups, unlike 480 * everything else, where they immediately follow 481 * the allow ace. 482 * 483 * We calculate "skip", the number of slots to 484 * skip ahead for the deny ace, here. 485 * 486 * The pattern is: 487 * MD1 A1 MD2 A2 MD3 A3 D1 D2 D3 488 * thus, skip is 489 * (2 * numgroup) - 1 - groupi 490 * (2 * numgroup) to account for MD + A 491 * - 1 to account for the fact that we're on the 492 * access (A), not the mask (MD) 493 * - groupi to account for the fact that we have 494 * passed up groupi number of MD's. 495 */ 496 skip = (2 * numgroup) - 1 - groupi; 497 ace_make_deny(acep, acep + skip, isdir, B_FALSE); 498 /* 499 * If we just did the last group, skip acep past 500 * all of the denies; else, just move ahead one. 501 */ 502 if (++groupi >= numgroup) 503 acep += numgroup + 1; 504 else 505 acep += 1; 506 } else if (aclent[i].a_type & OTHER_OBJ) { 507 acep->a_who = -1; 508 acep->a_flags |= ACE_EVERYONE; 509 ace_make_deny(acep, acep + 1, isdir, B_FALSE); 510 acep += 2; 511 } else { 512 error = EINVAL; 513 goto out; 514 } 515 } 516 517 *acepp = result; 518 *rescount = resultsize; 519 520 out: 521 if (error != 0) { 522 if ((result != NULL) && (resultsize > 0)) { 523 free(result); 524 } 525 } 526 527 return (error); 528 } 529 530 static int 531 convert_aent_to_ace(aclent_t *aclentp, int aclcnt, int isdir, 532 ace_t **retacep, int *retacecnt) 533 { 534 ace_t *acep; 535 ace_t *dfacep; 536 ace_t *newacep; 537 int acecnt = 0; 538 int dfacecnt = 0; 539 int dfaclstart = 0; 540 int dfaclcnt = 0; 541 aclent_t *aclp; 542 int i; 543 int error; 544 545 ksort((caddr_t)aclentp, aclcnt, sizeof (aclent_t), cmp2acls); 546 547 for (i = 0, aclp = aclentp; i < aclcnt; aclp++, i++) { 548 if (aclp->a_type & ACL_DEFAULT) 549 break; 550 } 551 552 if (i < aclcnt) { 553 dfaclstart = aclcnt - i; 554 dfaclcnt = i; 555 } 556 557 if (dfaclcnt && isdir == 0) { 558 return (-1); 559 } 560 561 error = ln_aent_to_ace(aclentp, i, &acep, &acecnt, isdir); 562 if (error) 563 return (-1); 564 565 if (dfaclcnt) { 566 error = ln_aent_to_ace(&aclentp[dfaclstart], dfaclcnt, 567 &dfacep, &dfacecnt, isdir); 568 if (error) { 569 if (acep) { 570 free(acep); 571 } 572 return (-1); 573 } 574 } 575 576 newacep = malloc(sizeof (ace_t) * (acecnt + dfacecnt)); 577 if (newacep == NULL) 578 return (-1); 579 580 (void) memcpy(newacep, acep, sizeof (ace_t) * acecnt); 581 if (dfaclcnt) { 582 (void) memcpy(newacep + acecnt, dfacep, 583 sizeof (ace_t) * dfacecnt); 584 } 585 free(acep); 586 if (dfaclcnt) 587 free(dfacep); 588 589 *retacecnt = acecnt + dfacecnt; 590 *retacep = newacep; 591 return (0); 592 } 593 594 595 static int 596 cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp) 597 { 598 const char *fname; 599 int fd; 600 int ace_acl = 0; 601 int error; 602 int getcmd, cntcmd; 603 acl_t *acl_info; 604 int save_errno; 605 int stat_error; 606 struct stat64 statbuf; 607 608 *aclp = NULL; 609 if (type == ACL_PATH) { 610 fname = inp.file; 611 ace_acl = pathconf(fname, _PC_ACL_ENABLED); 612 } else { 613 fd = inp.fd; 614 ace_acl = fpathconf(fd, _PC_ACL_ENABLED); 615 } 616 617 if (ace_acl == -1) 618 return (-1); 619 620 /* 621 * if acl's aren't supported then 622 * send it through the old GETACL interface 623 */ 624 if (ace_acl == 0) { 625 ace_acl = _ACL_ACLENT_ENABLED; 626 } 627 628 if (ace_acl & _ACL_ACE_ENABLED) { 629 cntcmd = ACE_GETACLCNT; 630 getcmd = ACE_GETACL; 631 acl_info = acl_alloc(ACE_T); 632 } else { 633 cntcmd = GETACLCNT; 634 getcmd = GETACL; 635 acl_info = acl_alloc(ACLENT_T); 636 } 637 638 if (acl_info == NULL) 639 return (-1); 640 641 if (type == ACL_PATH) { 642 acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL); 643 } else { 644 acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL); 645 } 646 647 save_errno = errno; 648 if (acl_info->acl_cnt < 0) { 649 acl_free(acl_info); 650 errno = save_errno; 651 return (-1); 652 } 653 654 if (acl_info->acl_cnt == 0) { 655 acl_free(acl_info); 656 errno = save_errno; 657 return (0); 658 } 659 660 acl_info->acl_aclp = 661 malloc(acl_info->acl_cnt * acl_info->acl_entry_size); 662 save_errno = errno; 663 664 if (acl_info->acl_aclp == NULL) { 665 acl_free(acl_info); 666 errno = save_errno; 667 return (-1); 668 } 669 670 if (type == ACL_PATH) { 671 stat_error = stat64(fname, &statbuf); 672 error = acl(fname, getcmd, acl_info->acl_cnt, 673 acl_info->acl_aclp); 674 } else { 675 stat_error = fstat64(fd, &statbuf); 676 error = facl(fd, getcmd, acl_info->acl_cnt, 677 acl_info->acl_aclp); 678 } 679 680 save_errno = errno; 681 if (error == -1) { 682 acl_free(acl_info); 683 errno = save_errno; 684 return (-1); 685 } 686 687 688 if (stat_error == 0) { 689 acl_info->acl_flags = 690 (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0); 691 } else 692 acl_info->acl_flags = 0; 693 694 switch (acl_info->acl_type) { 695 case ACLENT_T: 696 if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 697 acl_info->acl_flags |= ACL_IS_TRIVIAL; 698 break; 699 case ACE_T: 700 if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 701 acl_info->acl_flags |= ACL_IS_TRIVIAL; 702 break; 703 default: 704 errno = EINVAL; 705 acl_free(acl_info); 706 return (-1); 707 } 708 709 if ((acl_info->acl_flags & ACL_IS_TRIVIAL) && 710 (get_flag & ACL_NO_TRIVIAL)) { 711 acl_free(acl_info); 712 errno = 0; 713 return (0); 714 } 715 716 *aclp = acl_info; 717 return (0); 718 } 719 720 /* 721 * return -1 on failure, otherwise the number of acl 722 * entries is returned 723 */ 724 int 725 acl_get(const char *path, int get_flag, acl_t **aclp) 726 { 727 acl_inp acl_inp; 728 acl_inp.file = path; 729 730 return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp)); 731 } 732 733 int 734 facl_get(int fd, int get_flag, acl_t **aclp) 735 { 736 737 acl_inp acl_inp; 738 acl_inp.fd = fd; 739 740 return (cacl_get(acl_inp, get_flag, ACL_FD, aclp)); 741 } 742 743 /* 744 * Set an ACL, translates acl to ace_t when appropriate. 745 */ 746 static int 747 cacl_set(acl_inp *acl_inp, acl_t *aclp, int type) 748 { 749 int error = 0; 750 int acl_flavor_target; 751 ace_t *acep = NULL; 752 int acecnt; 753 struct stat64 statbuf; 754 int stat_error; 755 int isdir; 756 757 758 if (type == ACL_PATH) { 759 stat_error = stat64(acl_inp->file, &statbuf); 760 if (stat_error) 761 return (-1); 762 acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED); 763 } else { 764 stat_error = fstat64(acl_inp->fd, &statbuf); 765 if (stat_error) 766 return (-1); 767 acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED); 768 } 769 770 isdir = S_ISDIR(statbuf.st_mode); 771 772 if (acl_flavor_target == -1) 773 return (-1); 774 775 /* 776 * Translate aclent_t ACL's to ACE ACL's. 777 */ 778 if (acl_flavor_target == _ACL_ACE_ENABLED && 779 aclp->acl_type == ACLENT_T) { 780 error = convert_aent_to_ace(aclp->acl_aclp, 781 aclp->acl_cnt, isdir, &acep, &acecnt); 782 if (error) { 783 errno = ENOTSUP; 784 return (-1); 785 } 786 /* 787 * replace old acl with newly translated acl 788 */ 789 free(aclp->acl_aclp); 790 aclp->acl_aclp = acep; 791 aclp->acl_cnt = acecnt; 792 aclp->acl_type = ACE_T; 793 } 794 795 if (type == ACL_PATH) { 796 error = acl(acl_inp->file, 797 (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 798 aclp->acl_cnt, aclp->acl_aclp); 799 } else { 800 error = facl(acl_inp->fd, 801 (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL, 802 aclp->acl_cnt, aclp->acl_aclp); 803 } 804 805 return (error); 806 } 807 808 int 809 acl_set(const char *path, acl_t *aclp) 810 { 811 acl_inp acl_inp; 812 813 acl_inp.file = path; 814 815 return (cacl_set(&acl_inp, aclp, ACL_PATH)); 816 } 817 818 int 819 facl_set(int fd, acl_t *aclp) 820 { 821 acl_inp acl_inp; 822 823 acl_inp.fd = fd; 824 825 return (cacl_set(&acl_inp, aclp, ACL_FD)); 826 } 827 828 int 829 acl_cnt(acl_t *aclp) 830 { 831 return (aclp->acl_cnt); 832 } 833 834 int 835 acl_type(acl_t *aclp) 836 { 837 return (aclp->acl_type); 838 } 839 840 acl_t * 841 acl_dup(acl_t *aclp) 842 { 843 acl_t *newaclp; 844 845 newaclp = acl_alloc(aclp->acl_type); 846 if (newaclp == NULL) 847 return (NULL); 848 849 newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt); 850 if (newaclp->acl_aclp == NULL) { 851 acl_free(newaclp); 852 return (NULL); 853 } 854 855 (void) memcpy(newaclp->acl_aclp, 856 aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt); 857 newaclp->acl_cnt = aclp->acl_cnt; 858 859 return (newaclp); 860 } 861 862 int 863 acl_flags(acl_t *aclp) 864 { 865 return (aclp->acl_flags); 866 } 867 868 void * 869 acl_data(acl_t *aclp) 870 { 871 return (aclp->acl_aclp); 872 } 873 874 /* 875 * Remove an ACL from a file and create a trivial ACL based 876 * off of the mode argument. After acl has been set owner/group 877 * are updated to match owner,group arguments 878 */ 879 int 880 acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode) 881 { 882 int error = 0; 883 aclent_t min_acl[MIN_ACL_ENTRIES]; 884 ace_t min_ace_acl[6]; /* owner, group, everyone + complement denies */ 885 int acl_flavor; 886 int aclcnt; 887 888 acl_flavor = pathconf(file, _PC_ACL_ENABLED); 889 890 if (acl_flavor == -1) 891 return (-1); 892 /* 893 * force it through aclent flavor when file system doesn't 894 * understand question 895 */ 896 if (acl_flavor == 0) 897 acl_flavor = _ACL_ACLENT_ENABLED; 898 899 if (acl_flavor & _ACL_ACLENT_ENABLED) { 900 min_acl[0].a_type = USER_OBJ; 901 min_acl[0].a_id = owner; 902 min_acl[0].a_perm = ((mode & 0700) >> 6); 903 min_acl[1].a_type = GROUP_OBJ; 904 min_acl[1].a_id = group; 905 min_acl[1].a_perm = ((mode & 0070) >> 3); 906 min_acl[2].a_type = CLASS_OBJ; 907 min_acl[2].a_id = (uid_t)-1; 908 min_acl[2].a_perm = ((mode & 0070) >> 3); 909 min_acl[3].a_type = OTHER_OBJ; 910 min_acl[3].a_id = (uid_t)-1; 911 min_acl[3].a_perm = (mode & 0007); 912 aclcnt = 4; 913 error = acl(file, SETACL, aclcnt, min_acl); 914 } else if (acl_flavor & _ACL_ACE_ENABLED) { 915 (void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6); 916 917 /* 918 * Make aces match request mode 919 */ 920 adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6); 921 adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3); 922 adjust_ace_pair(&min_ace_acl[4], mode & 0007); 923 924 error = acl(file, ACE_SETACL, 6, min_ace_acl); 925 } else { 926 errno = EINVAL; 927 error = 1; 928 } 929 930 if (error == 0) 931 error = chown(file, owner, group); 932 return (error); 933 } 934 935 static int 936 ace_match(void *entry1, void *entry2) 937 { 938 ace_t *p1 = (ace_t *)entry1; 939 ace_t *p2 = (ace_t *)entry2; 940 ace_t ace1, ace2; 941 942 ace1 = *p1; 943 ace2 = *p2; 944 945 /* 946 * Need to fixup who field for abstrations for 947 * accurate comparison, since field is undefined. 948 */ 949 if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 950 ace1.a_who = -1; 951 if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE)) 952 ace2.a_who = -1; 953 return (memcmp(&ace1, &ace2, sizeof (ace_t))); 954 } 955 956 static int 957 aclent_match(void *entry1, void *entry2) 958 { 959 aclent_t *aclent1 = (aclent_t *)entry1; 960 aclent_t *aclent2 = (aclent_t *)entry2; 961 962 return (memcmp(aclent1, aclent2, sizeof (aclent_t))); 963 } 964 965 /* 966 * Find acl entries in acl that correspond to removeacl. Search 967 * is started from slot. The flag argument indicates whether to 968 * remove all matches or just the first match. 969 */ 970 int 971 acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag) 972 { 973 int i, j; 974 int match; 975 int (*acl_match)(void *acl1, void *acl2); 976 void *acl_entry, *remove_entry; 977 void *start; 978 int found = 0; 979 980 if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST) 981 flag = ACL_REMOVE_FIRST; 982 983 if (acl == NULL || removeacl == NULL) 984 return (EACL_NO_ACL_ENTRY); 985 986 if (acl->acl_type != removeacl->acl_type) 987 return (EACL_DIFF_TYPE); 988 989 if (acl->acl_type == ACLENT_T) 990 acl_match = aclent_match; 991 else 992 acl_match = ace_match; 993 994 for (i = 0, remove_entry = removeacl->acl_aclp; 995 i != removeacl->acl_cnt; i++) { 996 997 j = 0; 998 acl_entry = (char *)acl->acl_aclp + 999 (acl->acl_entry_size * start_slot); 1000 for (;;) { 1001 match = acl_match(acl_entry, remove_entry); 1002 if (match == 0) { 1003 found++; 1004 start = (char *)acl_entry + 1005 acl->acl_entry_size; 1006 (void) memmove(acl_entry, start, 1007 acl->acl_entry_size * 1008 acl->acl_cnt-- - (j + 1)); 1009 1010 if (flag == ACL_REMOVE_FIRST) 1011 break; 1012 /* 1013 * List has changed, restart search from 1014 * beginning. 1015 */ 1016 acl_entry = acl->acl_aclp; 1017 j = 0; 1018 continue; 1019 } 1020 acl_entry = ((char *)acl_entry + acl->acl_entry_size); 1021 if (++j >= acl->acl_cnt) { 1022 break; 1023 } 1024 } 1025 } 1026 1027 return ((found == 0) ? EACL_NO_ACL_ENTRY : 0); 1028 } 1029 1030 /* 1031 * Replace entires entries in acl1 with the corresponding entries 1032 * in newentries. The where argument specifies where to begin 1033 * the replacement. If the where argument is 1 greater than the 1034 * number of acl entries in acl1 then they are appended. If the 1035 * where argument is 2+ greater than the number of acl entries then 1036 * EACL_INVALID_SLOT is returned. 1037 */ 1038 int 1039 acl_modifyentries(acl_t *acl1, acl_t *newentries, int where) 1040 { 1041 1042 int slot; 1043 int slots_needed; 1044 int slots_left; 1045 int newsize; 1046 1047 if (acl1 == NULL || newentries == NULL) 1048 return (EACL_NO_ACL_ENTRY); 1049 1050 if (where < 0 || where >= acl1->acl_cnt) 1051 return (EACL_INVALID_SLOT); 1052 1053 if (acl1->acl_type != newentries->acl_type) 1054 return (EACL_DIFF_TYPE); 1055 1056 slot = where; 1057 1058 slots_left = acl1->acl_cnt - slot + 1; 1059 if (slots_left < newentries->acl_cnt) { 1060 slots_needed = newentries->acl_cnt - slots_left; 1061 newsize = (acl1->acl_entry_size * acl1->acl_cnt) + 1062 (acl1->acl_entry_size * slots_needed); 1063 acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1064 if (acl1->acl_aclp == NULL) 1065 return (-1); 1066 } 1067 (void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot), 1068 newentries->acl_aclp, 1069 newentries->acl_entry_size * newentries->acl_cnt); 1070 1071 /* 1072 * Did ACL grow? 1073 */ 1074 1075 if ((slot + newentries->acl_cnt) > acl1->acl_cnt) { 1076 acl1->acl_cnt = slot + newentries->acl_cnt; 1077 } 1078 1079 return (0); 1080 } 1081 1082 /* 1083 * Add acl2 entries into acl1. The where argument specifies where 1084 * to add the entries. 1085 */ 1086 int 1087 acl_addentries(acl_t *acl1, acl_t *acl2, int where) 1088 { 1089 1090 int newsize; 1091 int len; 1092 void *start; 1093 void *to; 1094 1095 if (acl1 == NULL || acl2 == NULL) 1096 return (EACL_NO_ACL_ENTRY); 1097 1098 if (acl1->acl_type != acl2->acl_type) 1099 return (EACL_DIFF_TYPE); 1100 1101 /* 1102 * allow where to specify 1 past last slot for an append operation 1103 * but anything greater is an error. 1104 */ 1105 if (where < 0 || where > acl1->acl_cnt) 1106 return (EACL_INVALID_SLOT); 1107 1108 newsize = (acl2->acl_entry_size * acl2->acl_cnt) + 1109 (acl1->acl_entry_size * acl1->acl_cnt); 1110 acl1->acl_aclp = realloc(acl1->acl_aclp, newsize); 1111 if (acl1->acl_aclp == NULL) 1112 return (-1); 1113 1114 /* 1115 * first push down entries where new ones will be inserted 1116 */ 1117 1118 to = (void *)((char *)acl1->acl_aclp + 1119 ((where + acl2->acl_cnt) * acl1->acl_entry_size)); 1120 1121 start = (void *)((char *)acl1->acl_aclp + 1122 where * acl1->acl_entry_size); 1123 1124 if (where < acl1->acl_cnt) { 1125 len = (acl1->acl_cnt - where) * acl1->acl_entry_size; 1126 (void) memmove(to, start, len); 1127 } 1128 1129 /* 1130 * now stick in new entries. 1131 */ 1132 1133 (void) memmove(start, acl2->acl_aclp, 1134 acl2->acl_cnt * acl2->acl_entry_size); 1135 1136 acl1->acl_cnt += acl2->acl_cnt; 1137 return (0); 1138 } 1139 1140 /* 1141 * return text for an ACL error. 1142 */ 1143 char * 1144 acl_strerror(int errnum) 1145 { 1146 switch (errnum) { 1147 case EACL_GRP_ERROR: 1148 return (dgettext(TEXT_DOMAIN, 1149 "There is more than one group or default group entry")); 1150 case EACL_USER_ERROR: 1151 return (dgettext(TEXT_DOMAIN, 1152 "There is more than one user or default user entry")); 1153 case EACL_OTHER_ERROR: 1154 return (dgettext(TEXT_DOMAIN, 1155 "There is more than one other entry")); 1156 case EACL_CLASS_ERROR: 1157 return (dgettext(TEXT_DOMAIN, 1158 "There is more than one mask entry")); 1159 case EACL_DUPLICATE_ERROR: 1160 return (dgettext(TEXT_DOMAIN, 1161 "Duplicate user or group entries")); 1162 case EACL_MISS_ERROR: 1163 return (dgettext(TEXT_DOMAIN, 1164 "Missing user/group owner, other, mask entry")); 1165 case EACL_MEM_ERROR: 1166 return (dgettext(TEXT_DOMAIN, 1167 "Memory error")); 1168 case EACL_ENTRY_ERROR: 1169 return (dgettext(TEXT_DOMAIN, 1170 "Unrecognized entry type")); 1171 case EACL_INHERIT_ERROR: 1172 return (dgettext(TEXT_DOMAIN, 1173 "Invalid inheritance flags")); 1174 case EACL_FLAGS_ERROR: 1175 return (dgettext(TEXT_DOMAIN, 1176 "Unrecognized entry flags")); 1177 case EACL_PERM_MASK_ERROR: 1178 return (dgettext(TEXT_DOMAIN, 1179 "Invalid ACL permissions")); 1180 case EACL_COUNT_ERROR: 1181 return (dgettext(TEXT_DOMAIN, 1182 "Invalid ACL count")); 1183 case EACL_INVALID_SLOT: 1184 return (dgettext(TEXT_DOMAIN, 1185 "Invalid ACL entry number specified")); 1186 case EACL_NO_ACL_ENTRY: 1187 return (dgettext(TEXT_DOMAIN, 1188 "ACL entry doesn't exist")); 1189 case EACL_DIFF_TYPE: 1190 return (dgettext(TEXT_DOMAIN, 1191 "ACL type's are different")); 1192 case EACL_INVALID_USER_GROUP: 1193 return (dgettext(TEXT_DOMAIN, "Invalid user or group")); 1194 case EACL_INVALID_STR: 1195 return (dgettext(TEXT_DOMAIN, "ACL string is invalid")); 1196 case EACL_FIELD_NOT_BLANK: 1197 return (dgettext(TEXT_DOMAIN, "Field expected to be blank")); 1198 case EACL_INVALID_ACCESS_TYPE: 1199 return (dgettext(TEXT_DOMAIN, "Invalid access type")); 1200 case EACL_UNKNOWN_DATA: 1201 return (dgettext(TEXT_DOMAIN, "Unrecognized entry")); 1202 case EACL_MISSING_FIELDS: 1203 return (dgettext(TEXT_DOMAIN, 1204 "ACL specification missing required fields")); 1205 case EACL_INHERIT_NOTDIR: 1206 return (dgettext(TEXT_DOMAIN, 1207 "Inheritance flags are only allowed on directories")); 1208 case -1: 1209 return (strerror(errno)); 1210 default: 1211 errno = EINVAL; 1212 return (dgettext(TEXT_DOMAIN, "Unknown error")); 1213 } 1214 } 1215 1216 extern int yyinteractive; 1217 1218 /* PRINTFLIKE1 */ 1219 void 1220 acl_error(const char *fmt, ...) 1221 { 1222 va_list va; 1223 1224 if (yyinteractive == 0) 1225 return; 1226 1227 va_start(va, fmt); 1228 (void) vfprintf(stderr, fmt, va); 1229 va_end(va); 1230 } 1231