1 /*- 2 * Copyright (c) 1999-2003 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * This software was developed by Robert Watson for the TrustedBSD Project. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 /* 29 * Developed by the TrustedBSD Project. 30 * Support for POSIX.1e access control lists. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include "opt_mac.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/sysproto.h> 41 #include <sys/kernel.h> 42 #include <sys/mac.h> 43 #include <sys/malloc.h> 44 #include <sys/vnode.h> 45 #include <sys/lock.h> 46 #include <sys/mutex.h> 47 #include <sys/namei.h> 48 #include <sys/file.h> 49 #include <sys/filedesc.h> 50 #include <sys/proc.h> 51 #include <sys/sysent.h> 52 #include <sys/errno.h> 53 #include <sys/stat.h> 54 #include <sys/acl.h> 55 56 #include <vm/uma.h> 57 58 uma_zone_t acl_zone; 59 static int vacl_set_acl(struct thread *td, struct vnode *vp, 60 acl_type_t type, struct acl *aclp); 61 static int vacl_get_acl(struct thread *td, struct vnode *vp, 62 acl_type_t type, struct acl *aclp); 63 static int vacl_aclcheck(struct thread *td, struct vnode *vp, 64 acl_type_t type, struct acl *aclp); 65 66 /* 67 * Implement a version of vaccess() that understands POSIX.1e ACL semantics. 68 * Return 0 on success, else an errno value. Should be merged into 69 * vaccess() eventually. 70 */ 71 int 72 vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid, 73 struct acl *acl, mode_t acc_mode, struct ucred *cred, int *privused) 74 { 75 struct acl_entry *acl_other, *acl_mask; 76 mode_t dac_granted; 77 mode_t cap_granted; 78 mode_t acl_mask_granted; 79 int group_matched, i; 80 81 /* 82 * Look for a normal, non-privileged way to access the file/directory 83 * as requested. If it exists, go with that. Otherwise, attempt 84 * to use privileges granted via cap_granted. In some cases, 85 * which privileges to use may be ambiguous due to "best match", 86 * in which case fall back on first match for the time being. 87 */ 88 if (privused != NULL) 89 *privused = 0; 90 91 /* 92 * Determine privileges now, but don't apply until we've found 93 * a DAC entry that matches but has failed to allow access. 94 */ 95 #ifndef CAPABILITIES 96 if (suser_cred(cred, SUSER_ALLOWJAIL) == 0) 97 cap_granted = VALLPERM; 98 else 99 cap_granted = 0; 100 #else 101 cap_granted = 0; 102 103 if (type == VDIR) { 104 if ((acc_mode & VEXEC) && !cap_check(cred, NULL, 105 CAP_DAC_READ_SEARCH, SUSER_ALLOWJAIL)) 106 cap_granted |= VEXEC; 107 } else { 108 if ((acc_mode & VEXEC) && !cap_check(cred, NULL, 109 CAP_DAC_EXECUTE, SUSER_ALLOWJAIL)) 110 cap_granted |= VEXEC; 111 } 112 113 if ((acc_mode & VREAD) && !cap_check(cred, NULL, CAP_DAC_READ_SEARCH, 114 SUSER_ALLOWJAIL)) 115 cap_granted |= VREAD; 116 117 if (((acc_mode & VWRITE) || (acc_mode & VAPPEND)) && 118 !cap_check(cred, NULL, CAP_DAC_WRITE, SUSER_ALLOWJAIL)) 119 cap_granted |= (VWRITE | VAPPEND); 120 121 if ((acc_mode & VADMIN) && !cap_check(cred, NULL, CAP_FOWNER, 122 SUSER_ALLOWJAIL)) 123 cap_granted |= VADMIN; 124 #endif /* CAPABILITIES */ 125 126 /* 127 * The owner matches if the effective uid associated with the 128 * credential matches that of the ACL_USER_OBJ entry. While we're 129 * doing the first scan, also cache the location of the ACL_MASK 130 * and ACL_OTHER entries, preventing some future iterations. 131 */ 132 acl_mask = acl_other = NULL; 133 for (i = 0; i < acl->acl_cnt; i++) { 134 switch (acl->acl_entry[i].ae_tag) { 135 case ACL_USER_OBJ: 136 if (file_uid != cred->cr_uid) 137 break; 138 dac_granted = 0; 139 dac_granted |= VADMIN; 140 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE) 141 dac_granted |= VEXEC; 142 if (acl->acl_entry[i].ae_perm & ACL_READ) 143 dac_granted |= VREAD; 144 if (acl->acl_entry[i].ae_perm & ACL_WRITE) 145 dac_granted |= (VWRITE | VAPPEND); 146 if ((acc_mode & dac_granted) == acc_mode) 147 return (0); 148 if ((acc_mode & (dac_granted | cap_granted)) == 149 acc_mode) { 150 if (privused != NULL) 151 *privused = 1; 152 return (0); 153 } 154 goto error; 155 156 case ACL_MASK: 157 acl_mask = &acl->acl_entry[i]; 158 break; 159 160 case ACL_OTHER: 161 acl_other = &acl->acl_entry[i]; 162 break; 163 164 default: 165 break; 166 } 167 } 168 169 /* 170 * An ACL_OTHER entry should always exist in a valid access 171 * ACL. If it doesn't, then generate a serious failure. For now, 172 * this means a debugging message and EPERM, but in the future 173 * should probably be a panic. 174 */ 175 if (acl_other == NULL) { 176 /* 177 * XXX This should never happen 178 */ 179 printf("vaccess_acl_posix1e: ACL_OTHER missing\n"); 180 return (EPERM); 181 } 182 183 /* 184 * Checks against ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP fields 185 * are masked by an ACL_MASK entry, if any. As such, first identify 186 * the ACL_MASK field, then iterate through identifying potential 187 * user matches, then group matches. If there is no ACL_MASK, 188 * assume that the mask allows all requests to succeed. 189 */ 190 if (acl_mask != NULL) { 191 acl_mask_granted = 0; 192 if (acl_mask->ae_perm & ACL_EXECUTE) 193 acl_mask_granted |= VEXEC; 194 if (acl_mask->ae_perm & ACL_READ) 195 acl_mask_granted |= VREAD; 196 if (acl_mask->ae_perm & ACL_WRITE) 197 acl_mask_granted |= (VWRITE | VAPPEND); 198 } else 199 acl_mask_granted = VEXEC | VREAD | VWRITE | VAPPEND; 200 201 /* 202 * Iterate through user ACL entries. Do checks twice, first 203 * without privilege, and then if a match is found but failed, 204 * a second time with privilege. 205 */ 206 207 /* 208 * Check ACL_USER ACL entries. 209 */ 210 for (i = 0; i < acl->acl_cnt; i++) { 211 switch (acl->acl_entry[i].ae_tag) { 212 case ACL_USER: 213 if (acl->acl_entry[i].ae_id != cred->cr_uid) 214 break; 215 dac_granted = 0; 216 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE) 217 dac_granted |= VEXEC; 218 if (acl->acl_entry[i].ae_perm & ACL_READ) 219 dac_granted |= VREAD; 220 if (acl->acl_entry[i].ae_perm & ACL_WRITE) 221 dac_granted |= (VWRITE | VAPPEND); 222 dac_granted &= acl_mask_granted; 223 if ((acc_mode & dac_granted) == acc_mode) 224 return (0); 225 if ((acc_mode & (dac_granted | cap_granted)) != 226 acc_mode) 227 goto error; 228 229 if (privused != NULL) 230 *privused = 1; 231 return (0); 232 } 233 } 234 235 /* 236 * Group match is best-match, not first-match, so find a 237 * "best" match. Iterate across, testing each potential group 238 * match. Make sure we keep track of whether we found a match 239 * or not, so that we know if we should try again with any 240 * available privilege, or if we should move on to ACL_OTHER. 241 */ 242 group_matched = 0; 243 for (i = 0; i < acl->acl_cnt; i++) { 244 switch (acl->acl_entry[i].ae_tag) { 245 case ACL_GROUP_OBJ: 246 if (!groupmember(file_gid, cred)) 247 break; 248 dac_granted = 0; 249 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE) 250 dac_granted |= VEXEC; 251 if (acl->acl_entry[i].ae_perm & ACL_READ) 252 dac_granted |= VREAD; 253 if (acl->acl_entry[i].ae_perm & ACL_WRITE) 254 dac_granted |= (VWRITE | VAPPEND); 255 dac_granted &= acl_mask_granted; 256 257 if ((acc_mode & dac_granted) == acc_mode) 258 return (0); 259 260 group_matched = 1; 261 break; 262 263 case ACL_GROUP: 264 if (!groupmember(acl->acl_entry[i].ae_id, cred)) 265 break; 266 dac_granted = 0; 267 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE) 268 dac_granted |= VEXEC; 269 if (acl->acl_entry[i].ae_perm & ACL_READ) 270 dac_granted |= VREAD; 271 if (acl->acl_entry[i].ae_perm & ACL_WRITE) 272 dac_granted |= (VWRITE | VAPPEND); 273 dac_granted &= acl_mask_granted; 274 275 if ((acc_mode & dac_granted) == acc_mode) 276 return (0); 277 278 group_matched = 1; 279 break; 280 281 default: 282 break; 283 } 284 } 285 286 if (group_matched == 1) { 287 /* 288 * There was a match, but it did not grant rights via 289 * pure DAC. Try again, this time with privilege. 290 */ 291 for (i = 0; i < acl->acl_cnt; i++) { 292 switch (acl->acl_entry[i].ae_tag) { 293 case ACL_GROUP_OBJ: 294 if (!groupmember(file_gid, cred)) 295 break; 296 dac_granted = 0; 297 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE) 298 dac_granted |= VEXEC; 299 if (acl->acl_entry[i].ae_perm & ACL_READ) 300 dac_granted |= VREAD; 301 if (acl->acl_entry[i].ae_perm & ACL_WRITE) 302 dac_granted |= (VWRITE | VAPPEND); 303 dac_granted &= acl_mask_granted; 304 305 if ((acc_mode & (dac_granted | cap_granted)) != 306 acc_mode) 307 break; 308 309 if (privused != NULL) 310 *privused = 1; 311 return (0); 312 313 case ACL_GROUP: 314 if (!groupmember(acl->acl_entry[i].ae_id, 315 cred)) 316 break; 317 dac_granted = 0; 318 if (acl->acl_entry[i].ae_perm & ACL_EXECUTE) 319 dac_granted |= VEXEC; 320 if (acl->acl_entry[i].ae_perm & ACL_READ) 321 dac_granted |= VREAD; 322 if (acl->acl_entry[i].ae_perm & ACL_WRITE) 323 dac_granted |= (VWRITE | VAPPEND); 324 dac_granted &= acl_mask_granted; 325 326 if ((acc_mode & (dac_granted | cap_granted)) != 327 acc_mode) 328 break; 329 330 if (privused != NULL) 331 *privused = 1; 332 return (0); 333 334 default: 335 break; 336 } 337 } 338 /* 339 * Even with privilege, group membership was not sufficient. 340 * Return failure. 341 */ 342 goto error; 343 } 344 345 /* 346 * Fall back on ACL_OTHER. ACL_MASK is not applied to ACL_OTHER. 347 */ 348 dac_granted = 0; 349 if (acl_other->ae_perm & ACL_EXECUTE) 350 dac_granted |= VEXEC; 351 if (acl_other->ae_perm & ACL_READ) 352 dac_granted |= VREAD; 353 if (acl_other->ae_perm & ACL_WRITE) 354 dac_granted |= (VWRITE | VAPPEND); 355 356 if ((acc_mode & dac_granted) == acc_mode) 357 return (0); 358 if ((acc_mode & (dac_granted | cap_granted)) == acc_mode) { 359 if (privused != NULL) 360 *privused = 1; 361 return (0); 362 } 363 364 error: 365 return ((acc_mode & VADMIN) ? EPERM : EACCES); 366 } 367 368 /* 369 * For the purposes of filesystems maintaining the _OBJ entries in an 370 * inode with a mode_t field, this routine converts a mode_t entry 371 * to an acl_perm_t. 372 */ 373 acl_perm_t 374 acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode) 375 { 376 acl_perm_t perm = 0; 377 378 switch(tag) { 379 case ACL_USER_OBJ: 380 if (mode & S_IXUSR) 381 perm |= ACL_EXECUTE; 382 if (mode & S_IRUSR) 383 perm |= ACL_READ; 384 if (mode & S_IWUSR) 385 perm |= ACL_WRITE; 386 return (perm); 387 388 case ACL_GROUP_OBJ: 389 if (mode & S_IXGRP) 390 perm |= ACL_EXECUTE; 391 if (mode & S_IRGRP) 392 perm |= ACL_READ; 393 if (mode & S_IWGRP) 394 perm |= ACL_WRITE; 395 return (perm); 396 397 case ACL_OTHER: 398 if (mode & S_IXOTH) 399 perm |= ACL_EXECUTE; 400 if (mode & S_IROTH) 401 perm |= ACL_READ; 402 if (mode & S_IWOTH) 403 perm |= ACL_WRITE; 404 return (perm); 405 406 default: 407 printf("acl_posix1e_mode_to_perm: invalid tag (%d)\n", tag); 408 return (0); 409 } 410 } 411 412 /* 413 * Given inode information (uid, gid, mode), return an acl entry of the 414 * appropriate type. 415 */ 416 struct acl_entry 417 acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode) 418 { 419 struct acl_entry acl_entry; 420 421 acl_entry.ae_tag = tag; 422 acl_entry.ae_perm = acl_posix1e_mode_to_perm(tag, mode); 423 switch(tag) { 424 case ACL_USER_OBJ: 425 acl_entry.ae_id = uid; 426 break; 427 428 case ACL_GROUP_OBJ: 429 acl_entry.ae_id = gid; 430 break; 431 432 case ACL_OTHER: 433 acl_entry.ae_id = ACL_UNDEFINED_ID; 434 break; 435 436 default: 437 acl_entry.ae_id = ACL_UNDEFINED_ID; 438 printf("acl_posix1e_mode_to_entry: invalid tag (%d)\n", tag); 439 } 440 441 return (acl_entry); 442 } 443 444 /* 445 * Utility function to generate a file mode given appropriate ACL entries. 446 */ 447 mode_t 448 acl_posix1e_perms_to_mode(struct acl_entry *acl_user_obj_entry, 449 struct acl_entry *acl_group_obj_entry, struct acl_entry *acl_other_entry) 450 { 451 mode_t mode; 452 453 mode = 0; 454 if (acl_user_obj_entry->ae_perm & ACL_EXECUTE) 455 mode |= S_IXUSR; 456 if (acl_user_obj_entry->ae_perm & ACL_READ) 457 mode |= S_IRUSR; 458 if (acl_user_obj_entry->ae_perm & ACL_WRITE) 459 mode |= S_IWUSR; 460 if (acl_group_obj_entry->ae_perm & ACL_EXECUTE) 461 mode |= S_IXGRP; 462 if (acl_group_obj_entry->ae_perm & ACL_READ) 463 mode |= S_IRGRP; 464 if (acl_group_obj_entry->ae_perm & ACL_WRITE) 465 mode |= S_IWGRP; 466 if (acl_other_entry->ae_perm & ACL_EXECUTE) 467 mode |= S_IXOTH; 468 if (acl_other_entry->ae_perm & ACL_READ) 469 mode |= S_IROTH; 470 if (acl_other_entry->ae_perm & ACL_WRITE) 471 mode |= S_IWOTH; 472 473 return (mode); 474 } 475 476 /* 477 * Utility function to generate a file mode given a complete POSIX.1e 478 * access ACL. Note that if the ACL is improperly formed, this may 479 * result in a panic. 480 */ 481 mode_t 482 acl_posix1e_acl_to_mode(struct acl *acl) 483 { 484 struct acl_entry *acl_mask, *acl_user_obj, *acl_group_obj, *acl_other; 485 int i; 486 487 /* 488 * Find the ACL entries relevant to a POSIX permission mode. 489 */ 490 acl_user_obj = acl_group_obj = acl_other = acl_mask = NULL; 491 for (i = 0; i < acl->acl_cnt; i++) { 492 switch (acl->acl_entry[i].ae_tag) { 493 case ACL_USER_OBJ: 494 acl_user_obj = &acl->acl_entry[i]; 495 break; 496 497 case ACL_GROUP_OBJ: 498 acl_group_obj = &acl->acl_entry[i]; 499 break; 500 501 case ACL_OTHER: 502 acl_other = &acl->acl_entry[i]; 503 break; 504 505 case ACL_MASK: 506 acl_mask = &acl->acl_entry[i]; 507 break; 508 509 case ACL_USER: 510 case ACL_GROUP: 511 break; 512 513 default: 514 panic("acl_posix1e_acl_to_mode: bad ae_tag"); 515 } 516 } 517 518 if (acl_user_obj == NULL || acl_group_obj == NULL || acl_other == NULL) 519 panic("acl_posix1e_acl_to_mode: missing base ae_tags"); 520 521 /* 522 * POSIX.1e specifies that if there is an ACL_MASK entry, we replace 523 * the mode "group" bits with its permissions. If there isn't, we 524 * use the ACL_GROUP_OBJ permissions. 525 */ 526 if (acl_mask != NULL) 527 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_mask, 528 acl_other)); 529 else 530 return (acl_posix1e_perms_to_mode(acl_user_obj, acl_group_obj, 531 acl_other)); 532 } 533 534 /* 535 * Perform a syntactic check of the ACL, sufficient to allow an 536 * implementing filesystem to determine if it should accept this and 537 * rely on the POSIX.1e ACL properties. 538 */ 539 int 540 acl_posix1e_check(struct acl *acl) 541 { 542 int num_acl_user_obj, num_acl_user, num_acl_group_obj, num_acl_group; 543 int num_acl_mask, num_acl_other, i; 544 545 /* 546 * Verify that the number of entries does not exceed the maximum 547 * defined for acl_t. 548 * Verify that the correct number of various sorts of ae_tags are 549 * present: 550 * Exactly one ACL_USER_OBJ 551 * Exactly one ACL_GROUP_OBJ 552 * Exactly one ACL_OTHER 553 * If any ACL_USER or ACL_GROUP entries appear, then exactly one 554 * ACL_MASK entry must also appear. 555 * Verify that all ae_perm entries are in ACL_PERM_BITS. 556 * Verify all ae_tag entries are understood by this implementation. 557 * Note: Does not check for uniqueness of qualifier (ae_id) field. 558 */ 559 num_acl_user_obj = num_acl_user = num_acl_group_obj = num_acl_group = 560 num_acl_mask = num_acl_other = 0; 561 if (acl->acl_cnt > ACL_MAX_ENTRIES || acl->acl_cnt < 0) 562 return (EINVAL); 563 for (i = 0; i < acl->acl_cnt; i++) { 564 /* 565 * Check for a valid tag. 566 */ 567 switch(acl->acl_entry[i].ae_tag) { 568 case ACL_USER_OBJ: 569 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */ 570 if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID) 571 return (EINVAL); 572 num_acl_user_obj++; 573 break; 574 case ACL_GROUP_OBJ: 575 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */ 576 if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID) 577 return (EINVAL); 578 num_acl_group_obj++; 579 break; 580 case ACL_USER: 581 if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID) 582 return (EINVAL); 583 num_acl_user++; 584 break; 585 case ACL_GROUP: 586 if (acl->acl_entry[i].ae_id == ACL_UNDEFINED_ID) 587 return (EINVAL); 588 num_acl_group++; 589 break; 590 case ACL_OTHER: 591 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */ 592 if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID) 593 return (EINVAL); 594 num_acl_other++; 595 break; 596 case ACL_MASK: 597 acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; /* XXX */ 598 if (acl->acl_entry[i].ae_id != ACL_UNDEFINED_ID) 599 return (EINVAL); 600 num_acl_mask++; 601 break; 602 default: 603 return (EINVAL); 604 } 605 /* 606 * Check for valid perm entries. 607 */ 608 if ((acl->acl_entry[i].ae_perm | ACL_PERM_BITS) != 609 ACL_PERM_BITS) 610 return (EINVAL); 611 } 612 if ((num_acl_user_obj != 1) || (num_acl_group_obj != 1) || 613 (num_acl_other != 1) || (num_acl_mask != 0 && num_acl_mask != 1)) 614 return (EINVAL); 615 if (((num_acl_group != 0) || (num_acl_user != 0)) && 616 (num_acl_mask != 1)) 617 return (EINVAL); 618 return (0); 619 } 620 621 /* 622 * Given a requested mode for a new object, and a default ACL, combine 623 * the two to produce a new mode. Be careful not to clear any bits that 624 * aren't intended to be affected by the POSIX.1e ACL. Eventually, 625 * this might also take the cmask as an argument, if we push that down 626 * into per-filesystem-code. 627 */ 628 mode_t 629 acl_posix1e_newfilemode(mode_t cmode, struct acl *dacl) 630 { 631 mode_t mode; 632 633 mode = cmode; 634 /* 635 * The current composition policy is that a permission bit must 636 * be set in *both* the ACL and the requested creation mode for 637 * it to appear in the resulting mode/ACL. First clear any 638 * possibly effected bits, then reconstruct. 639 */ 640 mode &= ACL_PRESERVE_MASK; 641 mode |= (ACL_OVERRIDE_MASK & cmode & acl_posix1e_acl_to_mode(dacl)); 642 643 return (mode); 644 } 645 646 /* 647 * These calls wrap the real vnode operations, and are called by the 648 * syscall code once the syscall has converted the path or file 649 * descriptor to a vnode (unlocked). The aclp pointer is assumed 650 * still to point to userland, so this should not be consumed within 651 * the kernel except by syscall code. Other code should directly 652 * invoke VOP_{SET,GET}ACL. 653 */ 654 655 /* 656 * Given a vnode, set its ACL. 657 */ 658 static int 659 vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type, 660 struct acl *aclp) 661 { 662 struct acl inkernacl; 663 struct mount *mp; 664 int error; 665 666 error = copyin(aclp, &inkernacl, sizeof(struct acl)); 667 if (error) 668 return(error); 669 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 670 if (error != 0) 671 return (error); 672 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 673 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 674 #ifdef MAC 675 error = mac_check_vnode_setacl(td->td_ucred, vp, type, &inkernacl); 676 if (error != 0) 677 goto out; 678 #endif 679 error = VOP_SETACL(vp, type, &inkernacl, td->td_ucred, td); 680 #ifdef MAC 681 out: 682 #endif 683 VOP_UNLOCK(vp, 0, td); 684 vn_finished_write(mp); 685 return(error); 686 } 687 688 /* 689 * Given a vnode, get its ACL. 690 */ 691 static int 692 vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type, 693 struct acl *aclp) 694 { 695 struct acl inkernelacl; 696 int error; 697 698 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 699 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 700 #ifdef MAC 701 error = mac_check_vnode_getacl(td->td_ucred, vp, type); 702 if (error != 0) 703 goto out; 704 #endif 705 error = VOP_GETACL(vp, type, &inkernelacl, td->td_ucred, td); 706 #ifdef MAC 707 out: 708 #endif 709 VOP_UNLOCK(vp, 0, td); 710 if (error == 0) 711 error = copyout(&inkernelacl, aclp, sizeof(struct acl)); 712 return (error); 713 } 714 715 /* 716 * Given a vnode, delete its ACL. 717 */ 718 static int 719 vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type) 720 { 721 struct mount *mp; 722 int error; 723 724 error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 725 if (error) 726 return (error); 727 VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 728 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 729 #ifdef MAC 730 error = mac_check_vnode_deleteacl(td->td_ucred, vp, type); 731 if (error) 732 goto out; 733 #endif 734 error = VOP_SETACL(vp, type, 0, td->td_ucred, td); 735 #ifdef MAC 736 out: 737 #endif 738 VOP_UNLOCK(vp, 0, td); 739 vn_finished_write(mp); 740 return (error); 741 } 742 743 /* 744 * Given a vnode, check whether an ACL is appropriate for it 745 */ 746 static int 747 vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type, 748 struct acl *aclp) 749 { 750 struct acl inkernelacl; 751 int error; 752 753 error = copyin(aclp, &inkernelacl, sizeof(struct acl)); 754 if (error) 755 return(error); 756 error = VOP_ACLCHECK(vp, type, &inkernelacl, td->td_ucred, td); 757 return (error); 758 } 759 760 /* 761 * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. 762 * Don't need to lock, as the vacl_ code will get/release any locks 763 * required. 764 */ 765 766 /* 767 * Given a file path, get an ACL for it 768 * 769 * MPSAFE 770 */ 771 int 772 __acl_get_file(struct thread *td, struct __acl_get_file_args *uap) 773 { 774 struct nameidata nd; 775 int error; 776 777 mtx_lock(&Giant); 778 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td); 779 error = namei(&nd); 780 if (error == 0) { 781 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp); 782 NDFREE(&nd, 0); 783 } 784 mtx_unlock(&Giant); 785 return (error); 786 } 787 788 /* 789 * Given a file path, get an ACL for it; don't follow links. 790 * 791 * MPSAFE 792 */ 793 int 794 __acl_get_link(struct thread *td, struct __acl_get_link_args *uap) 795 { 796 struct nameidata nd; 797 int error; 798 799 mtx_lock(&Giant); 800 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td); 801 error = namei(&nd); 802 if (error == 0) { 803 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp); 804 NDFREE(&nd, 0); 805 } 806 mtx_unlock(&Giant); 807 return (error); 808 } 809 810 /* 811 * Given a file path, set an ACL for it 812 * 813 * MPSAFE 814 */ 815 int 816 __acl_set_file(struct thread *td, struct __acl_set_file_args *uap) 817 { 818 struct nameidata nd; 819 int error; 820 821 mtx_lock(&Giant); 822 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td); 823 error = namei(&nd); 824 if (error == 0) { 825 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp); 826 NDFREE(&nd, 0); 827 } 828 mtx_unlock(&Giant); 829 return (error); 830 } 831 832 /* 833 * Given a file path, set an ACL for it; don't follow links. 834 * 835 * MPSAFE 836 */ 837 int 838 __acl_set_link(struct thread *td, struct __acl_set_link_args *uap) 839 { 840 struct nameidata nd; 841 int error; 842 843 mtx_lock(&Giant); 844 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td); 845 error = namei(&nd); 846 if (error == 0) { 847 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp); 848 NDFREE(&nd, 0); 849 } 850 mtx_unlock(&Giant); 851 return (error); 852 } 853 854 /* 855 * Given a file descriptor, get an ACL for it 856 * 857 * MPSAFE 858 */ 859 int 860 __acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap) 861 { 862 struct file *fp; 863 int error; 864 865 mtx_lock(&Giant); 866 error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 867 if (error == 0) { 868 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp); 869 fdrop(fp, td); 870 } 871 mtx_unlock(&Giant); 872 return (error); 873 } 874 875 /* 876 * Given a file descriptor, set an ACL for it 877 * 878 * MPSAFE 879 */ 880 int 881 __acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap) 882 { 883 struct file *fp; 884 int error; 885 886 mtx_lock(&Giant); 887 error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 888 if (error == 0) { 889 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp); 890 fdrop(fp, td); 891 } 892 mtx_unlock(&Giant); 893 return (error); 894 } 895 896 /* 897 * Given a file path, delete an ACL from it. 898 * 899 * MPSAFE 900 */ 901 int 902 __acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap) 903 { 904 struct nameidata nd; 905 int error; 906 907 mtx_lock(&Giant); 908 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td); 909 error = namei(&nd); 910 if (error == 0) { 911 error = vacl_delete(td, nd.ni_vp, uap->type); 912 NDFREE(&nd, 0); 913 } 914 mtx_unlock(&Giant); 915 return (error); 916 } 917 918 /* 919 * Given a file path, delete an ACL from it; don't follow links. 920 * 921 * MPSAFE 922 */ 923 int 924 __acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap) 925 { 926 struct nameidata nd; 927 int error; 928 929 mtx_lock(&Giant); 930 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td); 931 error = namei(&nd); 932 if (error == 0) { 933 error = vacl_delete(td, nd.ni_vp, uap->type); 934 NDFREE(&nd, 0); 935 } 936 mtx_unlock(&Giant); 937 return (error); 938 } 939 940 /* 941 * Given a file path, delete an ACL from it. 942 * 943 * MPSAFE 944 */ 945 int 946 __acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap) 947 { 948 struct file *fp; 949 int error; 950 951 mtx_lock(&Giant); 952 error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 953 if (error == 0) { 954 error = vacl_delete(td, fp->f_vnode, uap->type); 955 fdrop(fp, td); 956 } 957 mtx_unlock(&Giant); 958 return (error); 959 } 960 961 /* 962 * Given a file path, check an ACL for it 963 * 964 * MPSAFE 965 */ 966 int 967 __acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap) 968 { 969 struct nameidata nd; 970 int error; 971 972 mtx_lock(&Giant); 973 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td); 974 error = namei(&nd); 975 if (error == 0) { 976 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp); 977 NDFREE(&nd, 0); 978 } 979 mtx_unlock(&Giant); 980 return (error); 981 } 982 983 /* 984 * Given a file path, check an ACL for it; don't follow links. 985 * 986 * MPSAFE 987 */ 988 int 989 __acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap) 990 { 991 struct nameidata nd; 992 int error; 993 994 mtx_lock(&Giant); 995 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td); 996 error = namei(&nd); 997 if (error == 0) { 998 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp); 999 NDFREE(&nd, 0); 1000 } 1001 mtx_unlock(&Giant); 1002 return (error); 1003 } 1004 1005 /* 1006 * Given a file descriptor, check an ACL for it 1007 * 1008 * MPSAFE 1009 */ 1010 int 1011 __acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap) 1012 { 1013 struct file *fp; 1014 int error; 1015 1016 mtx_lock(&Giant); 1017 error = getvnode(td->td_proc->p_fd, uap->filedes, &fp); 1018 if (error == 0) { 1019 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp); 1020 fdrop(fp, td); 1021 } 1022 mtx_unlock(&Giant); 1023 return (error); 1024 } 1025 1026 /* ARGUSED */ 1027 1028 static void 1029 aclinit(void *dummy __unused) 1030 { 1031 1032 acl_zone = uma_zcreate("ACL UMA zone", sizeof(struct acl), 1033 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 1034 } 1035 SYSINIT(acls, SI_SUB_ACL, SI_ORDER_FIRST, aclinit, NULL) 1036