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