1 /* $NetBSD: genfs_vnops.c,v 1.189 2012/03/30 18:24:08 njoly Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Copyright (c) 1982, 1986, 1989, 1993 31 * The Regents of the University of California. All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. Neither the name of the University nor the names of its contributors 42 * may be used to endorse or promote products derived from this software 43 * without specific prior written permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 * 57 */ 58 59 #include <sys/cdefs.h> 60 __KERNEL_RCSID(0, "$NetBSD: genfs_vnops.c,v 1.189 2012/03/30 18:24:08 njoly Exp $"); 61 62 #include <sys/param.h> 63 #include <sys/systm.h> 64 #include <sys/proc.h> 65 #include <sys/kernel.h> 66 #include <sys/mount.h> 67 #include <sys/fstrans.h> 68 #include <sys/namei.h> 69 #include <sys/vnode.h> 70 #include <sys/fcntl.h> 71 #include <sys/kmem.h> 72 #include <sys/poll.h> 73 #include <sys/mman.h> 74 #include <sys/file.h> 75 #include <sys/kauth.h> 76 #include <sys/stat.h> 77 78 #include <miscfs/genfs/genfs.h> 79 #include <miscfs/genfs/genfs_node.h> 80 #include <miscfs/specfs/specdev.h> 81 82 #include <uvm/uvm.h> 83 #include <uvm/uvm_pager.h> 84 85 static void filt_genfsdetach(struct knote *); 86 static int filt_genfsread(struct knote *, long); 87 static int filt_genfsvnode(struct knote *, long); 88 89 int 90 genfs_poll(void *v) 91 { 92 struct vop_poll_args /* { 93 struct vnode *a_vp; 94 int a_events; 95 struct lwp *a_l; 96 } */ *ap = v; 97 98 return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 99 } 100 101 int 102 genfs_seek(void *v) 103 { 104 struct vop_seek_args /* { 105 struct vnode *a_vp; 106 off_t a_oldoff; 107 off_t a_newoff; 108 kauth_cred_t cred; 109 } */ *ap = v; 110 111 if (ap->a_newoff < 0) 112 return (EINVAL); 113 114 return (0); 115 } 116 117 int 118 genfs_abortop(void *v) 119 { 120 struct vop_abortop_args /* { 121 struct vnode *a_dvp; 122 struct componentname *a_cnp; 123 } */ *ap = v; 124 125 (void)ap; 126 127 return (0); 128 } 129 130 int 131 genfs_fcntl(void *v) 132 { 133 struct vop_fcntl_args /* { 134 struct vnode *a_vp; 135 u_int a_command; 136 void *a_data; 137 int a_fflag; 138 kauth_cred_t a_cred; 139 struct lwp *a_l; 140 } */ *ap = v; 141 142 if (ap->a_command == F_SETFL) 143 return (0); 144 else 145 return (EOPNOTSUPP); 146 } 147 148 /*ARGSUSED*/ 149 int 150 genfs_badop(void *v) 151 { 152 153 panic("genfs: bad op"); 154 } 155 156 /*ARGSUSED*/ 157 int 158 genfs_nullop(void *v) 159 { 160 161 return (0); 162 } 163 164 /*ARGSUSED*/ 165 int 166 genfs_einval(void *v) 167 { 168 169 return (EINVAL); 170 } 171 172 /* 173 * Called when an fs doesn't support a particular vop. 174 * This takes care to vrele, vput, or vunlock passed in vnodes 175 * and calls VOP_ABORTOP for a componentname (in non-rename VOP). 176 */ 177 int 178 genfs_eopnotsupp(void *v) 179 { 180 struct vop_generic_args /* 181 struct vnodeop_desc *a_desc; 182 / * other random data follows, presumably * / 183 } */ *ap = v; 184 struct vnodeop_desc *desc = ap->a_desc; 185 struct vnode *vp, *vp_last = NULL; 186 int flags, i, j, offset_cnp, offset_vp; 187 188 KASSERT(desc->vdesc_offset != VOP_LOOKUP_DESCOFFSET); 189 KASSERT(desc->vdesc_offset != VOP_ABORTOP_DESCOFFSET); 190 191 /* 192 * Abort any componentname that lookup potentially left state in. 193 * 194 * As is logical, componentnames for VOP_RENAME are handled by 195 * the caller of VOP_RENAME. Yay, rename! 196 */ 197 if (desc->vdesc_offset != VOP_RENAME_DESCOFFSET && 198 (offset_vp = desc->vdesc_vp_offsets[0]) != VDESC_NO_OFFSET && 199 (offset_cnp = desc->vdesc_componentname_offset) != VDESC_NO_OFFSET){ 200 struct componentname *cnp; 201 struct vnode *dvp; 202 203 dvp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap); 204 cnp = *VOPARG_OFFSETTO(struct componentname **, offset_cnp, ap); 205 206 VOP_ABORTOP(dvp, cnp); 207 } 208 209 flags = desc->vdesc_flags; 210 for (i = 0; i < VDESC_MAX_VPS; flags >>=1, i++) { 211 if ((offset_vp = desc->vdesc_vp_offsets[i]) == VDESC_NO_OFFSET) 212 break; /* stop at end of list */ 213 if ((j = flags & VDESC_VP0_WILLPUT)) { 214 vp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap); 215 216 /* Skip if NULL */ 217 if (!vp) 218 continue; 219 220 switch (j) { 221 case VDESC_VP0_WILLPUT: 222 /* Check for dvp == vp cases */ 223 if (vp == vp_last) 224 vrele(vp); 225 else { 226 vput(vp); 227 vp_last = vp; 228 } 229 break; 230 case VDESC_VP0_WILLUNLOCK: 231 VOP_UNLOCK(vp); 232 break; 233 case VDESC_VP0_WILLRELE: 234 vrele(vp); 235 break; 236 } 237 } 238 } 239 240 return (EOPNOTSUPP); 241 } 242 243 /*ARGSUSED*/ 244 int 245 genfs_ebadf(void *v) 246 { 247 248 return (EBADF); 249 } 250 251 /* ARGSUSED */ 252 int 253 genfs_enoioctl(void *v) 254 { 255 256 return (EPASSTHROUGH); 257 } 258 259 260 /* 261 * Eliminate all activity associated with the requested vnode 262 * and with all vnodes aliased to the requested vnode. 263 */ 264 int 265 genfs_revoke(void *v) 266 { 267 struct vop_revoke_args /* { 268 struct vnode *a_vp; 269 int a_flags; 270 } */ *ap = v; 271 272 #ifdef DIAGNOSTIC 273 if ((ap->a_flags & REVOKEALL) == 0) 274 panic("genfs_revoke: not revokeall"); 275 #endif 276 vrevoke(ap->a_vp); 277 return (0); 278 } 279 280 /* 281 * Lock the node. 282 */ 283 int 284 genfs_lock(void *v) 285 { 286 struct vop_lock_args /* { 287 struct vnode *a_vp; 288 int a_flags; 289 } */ *ap = v; 290 struct vnode *vp = ap->a_vp; 291 int flags = ap->a_flags; 292 krw_t op; 293 294 KASSERT((flags & ~(LK_EXCLUSIVE | LK_SHARED | LK_NOWAIT)) == 0); 295 296 op = ((flags & LK_EXCLUSIVE) != 0 ? RW_WRITER : RW_READER); 297 if ((flags & LK_NOWAIT) != 0) { 298 if (fstrans_start_nowait(vp->v_mount, FSTRANS_SHARED)) 299 return EBUSY; 300 if (! rw_tryenter(&vp->v_lock, op)) { 301 fstrans_done(vp->v_mount); 302 return EBUSY; 303 } 304 return 0; 305 } 306 307 fstrans_start(vp->v_mount, FSTRANS_SHARED); 308 rw_enter(&vp->v_lock, op); 309 310 return 0; 311 } 312 313 /* 314 * Unlock the node. 315 */ 316 int 317 genfs_unlock(void *v) 318 { 319 struct vop_unlock_args /* { 320 struct vnode *a_vp; 321 } */ *ap = v; 322 struct vnode *vp = ap->a_vp; 323 324 rw_exit(&vp->v_lock); 325 fstrans_done(vp->v_mount); 326 327 return 0; 328 } 329 330 /* 331 * Return whether or not the node is locked. 332 */ 333 int 334 genfs_islocked(void *v) 335 { 336 struct vop_islocked_args /* { 337 struct vnode *a_vp; 338 } */ *ap = v; 339 struct vnode *vp = ap->a_vp; 340 341 if (rw_write_held(&vp->v_lock)) 342 return LK_EXCLUSIVE; 343 344 if (rw_read_held(&vp->v_lock)) 345 return LK_SHARED; 346 347 return 0; 348 } 349 350 /* 351 * Stubs to use when there is no locking to be done on the underlying object. 352 */ 353 int 354 genfs_nolock(void *v) 355 { 356 357 return (0); 358 } 359 360 int 361 genfs_nounlock(void *v) 362 { 363 364 return (0); 365 } 366 367 int 368 genfs_noislocked(void *v) 369 { 370 371 return (0); 372 } 373 374 int 375 genfs_mmap(void *v) 376 { 377 378 return (0); 379 } 380 381 /* 382 * VOP_PUTPAGES() for vnodes which never have pages. 383 */ 384 385 int 386 genfs_null_putpages(void *v) 387 { 388 struct vop_putpages_args /* { 389 struct vnode *a_vp; 390 voff_t a_offlo; 391 voff_t a_offhi; 392 int a_flags; 393 } */ *ap = v; 394 struct vnode *vp = ap->a_vp; 395 396 KASSERT(vp->v_uobj.uo_npages == 0); 397 mutex_exit(vp->v_interlock); 398 return (0); 399 } 400 401 void 402 genfs_node_init(struct vnode *vp, const struct genfs_ops *ops) 403 { 404 struct genfs_node *gp = VTOG(vp); 405 406 rw_init(&gp->g_glock); 407 gp->g_op = ops; 408 } 409 410 void 411 genfs_node_destroy(struct vnode *vp) 412 { 413 struct genfs_node *gp = VTOG(vp); 414 415 rw_destroy(&gp->g_glock); 416 } 417 418 void 419 genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 420 { 421 int bsize; 422 423 bsize = 1 << vp->v_mount->mnt_fs_bshift; 424 *eobp = (size + bsize - 1) & ~(bsize - 1); 425 } 426 427 static void 428 filt_genfsdetach(struct knote *kn) 429 { 430 struct vnode *vp = (struct vnode *)kn->kn_hook; 431 432 mutex_enter(vp->v_interlock); 433 SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext); 434 mutex_exit(vp->v_interlock); 435 } 436 437 static int 438 filt_genfsread(struct knote *kn, long hint) 439 { 440 struct vnode *vp = (struct vnode *)kn->kn_hook; 441 int rv; 442 443 /* 444 * filesystem is gone, so set the EOF flag and schedule 445 * the knote for deletion. 446 */ 447 switch (hint) { 448 case NOTE_REVOKE: 449 KASSERT(mutex_owned(vp->v_interlock)); 450 kn->kn_flags |= (EV_EOF | EV_ONESHOT); 451 return (1); 452 case 0: 453 mutex_enter(vp->v_interlock); 454 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 455 rv = (kn->kn_data != 0); 456 mutex_exit(vp->v_interlock); 457 return rv; 458 default: 459 KASSERT(mutex_owned(vp->v_interlock)); 460 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 461 return (kn->kn_data != 0); 462 } 463 } 464 465 static int 466 filt_genfsvnode(struct knote *kn, long hint) 467 { 468 struct vnode *vp = (struct vnode *)kn->kn_hook; 469 int fflags; 470 471 switch (hint) { 472 case NOTE_REVOKE: 473 KASSERT(mutex_owned(vp->v_interlock)); 474 kn->kn_flags |= EV_EOF; 475 if ((kn->kn_sfflags & hint) != 0) 476 kn->kn_fflags |= hint; 477 return (1); 478 case 0: 479 mutex_enter(vp->v_interlock); 480 fflags = kn->kn_fflags; 481 mutex_exit(vp->v_interlock); 482 break; 483 default: 484 KASSERT(mutex_owned(vp->v_interlock)); 485 if ((kn->kn_sfflags & hint) != 0) 486 kn->kn_fflags |= hint; 487 fflags = kn->kn_fflags; 488 break; 489 } 490 491 return (fflags != 0); 492 } 493 494 static const struct filterops genfsread_filtops = 495 { 1, NULL, filt_genfsdetach, filt_genfsread }; 496 static const struct filterops genfsvnode_filtops = 497 { 1, NULL, filt_genfsdetach, filt_genfsvnode }; 498 499 int 500 genfs_kqfilter(void *v) 501 { 502 struct vop_kqfilter_args /* { 503 struct vnode *a_vp; 504 struct knote *a_kn; 505 } */ *ap = v; 506 struct vnode *vp; 507 struct knote *kn; 508 509 vp = ap->a_vp; 510 kn = ap->a_kn; 511 switch (kn->kn_filter) { 512 case EVFILT_READ: 513 kn->kn_fop = &genfsread_filtops; 514 break; 515 case EVFILT_VNODE: 516 kn->kn_fop = &genfsvnode_filtops; 517 break; 518 default: 519 return (EINVAL); 520 } 521 522 kn->kn_hook = vp; 523 524 mutex_enter(vp->v_interlock); 525 SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext); 526 mutex_exit(vp->v_interlock); 527 528 return (0); 529 } 530 531 void 532 genfs_node_wrlock(struct vnode *vp) 533 { 534 struct genfs_node *gp = VTOG(vp); 535 536 rw_enter(&gp->g_glock, RW_WRITER); 537 } 538 539 void 540 genfs_node_rdlock(struct vnode *vp) 541 { 542 struct genfs_node *gp = VTOG(vp); 543 544 rw_enter(&gp->g_glock, RW_READER); 545 } 546 547 int 548 genfs_node_rdtrylock(struct vnode *vp) 549 { 550 struct genfs_node *gp = VTOG(vp); 551 552 return rw_tryenter(&gp->g_glock, RW_READER); 553 } 554 555 void 556 genfs_node_unlock(struct vnode *vp) 557 { 558 struct genfs_node *gp = VTOG(vp); 559 560 rw_exit(&gp->g_glock); 561 } 562 563 int 564 genfs_node_wrlocked(struct vnode *vp) 565 { 566 struct genfs_node *gp = VTOG(vp); 567 568 return rw_write_held(&gp->g_glock); 569 } 570 571 /* 572 * Do the usual access checking. 573 * file_mode, uid and gid are from the vnode in question, 574 * while acc_mode and cred are from the VOP_ACCESS parameter list 575 */ 576 int 577 genfs_can_access(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid, 578 mode_t acc_mode, kauth_cred_t cred) 579 { 580 mode_t mask; 581 int error, ismember; 582 583 mask = 0; 584 585 /* Otherwise, check the owner. */ 586 if (kauth_cred_geteuid(cred) == uid) { 587 if (acc_mode & VEXEC) 588 mask |= S_IXUSR; 589 if (acc_mode & VREAD) 590 mask |= S_IRUSR; 591 if (acc_mode & VWRITE) 592 mask |= S_IWUSR; 593 return ((file_mode & mask) == mask ? 0 : EACCES); 594 } 595 596 /* Otherwise, check the groups. */ 597 error = kauth_cred_ismember_gid(cred, gid, &ismember); 598 if (error) 599 return (error); 600 if (kauth_cred_getegid(cred) == gid || ismember) { 601 if (acc_mode & VEXEC) 602 mask |= S_IXGRP; 603 if (acc_mode & VREAD) 604 mask |= S_IRGRP; 605 if (acc_mode & VWRITE) 606 mask |= S_IWGRP; 607 return ((file_mode & mask) == mask ? 0 : EACCES); 608 } 609 610 /* Otherwise, check everyone else. */ 611 if (acc_mode & VEXEC) 612 mask |= S_IXOTH; 613 if (acc_mode & VREAD) 614 mask |= S_IROTH; 615 if (acc_mode & VWRITE) 616 mask |= S_IWOTH; 617 return ((file_mode & mask) == mask ? 0 : EACCES); 618 } 619 620 /* 621 * Common routine to check if chmod() is allowed. 622 * 623 * Policy: 624 * - You must own the file, and 625 * - You must not set the "sticky" bit (meaningless, see chmod(2)) 626 * - You must be a member of the group if you're trying to set the 627 * SGIDf bit 628 * 629 * cred - credentials of the invoker 630 * vp - vnode of the file-system object 631 * cur_uid, cur_gid - current uid/gid of the file-system object 632 * new_mode - new mode for the file-system object 633 * 634 * Returns 0 if the change is allowed, or an error value otherwise. 635 */ 636 int 637 genfs_can_chmod(enum vtype type, kauth_cred_t cred, uid_t cur_uid, 638 gid_t cur_gid, mode_t new_mode) 639 { 640 int error; 641 642 /* The user must own the file. */ 643 if (kauth_cred_geteuid(cred) != cur_uid) 644 return (EPERM); 645 646 /* 647 * Unprivileged users can't set the sticky bit on files. 648 */ 649 if ((type != VDIR) && (new_mode & S_ISTXT)) 650 return (EFTYPE); 651 652 /* 653 * If the invoker is trying to set the SGID bit on the file, 654 * check group membership. 655 */ 656 if (new_mode & S_ISGID) { 657 int ismember; 658 659 error = kauth_cred_ismember_gid(cred, cur_gid, 660 &ismember); 661 if (error || !ismember) 662 return (EPERM); 663 } 664 665 return (0); 666 } 667 668 /* 669 * Common routine to check if chown() is allowed. 670 * 671 * Policy: 672 * - You must own the file, and 673 * - You must not try to change ownership, and 674 * - You must be member of the new group 675 * 676 * cred - credentials of the invoker 677 * cur_uid, cur_gid - current uid/gid of the file-system object 678 * new_uid, new_gid - target uid/gid of the file-system object 679 * 680 * Returns 0 if the change is allowed, or an error value otherwise. 681 */ 682 int 683 genfs_can_chown(kauth_cred_t cred, uid_t cur_uid, 684 gid_t cur_gid, uid_t new_uid, gid_t new_gid) 685 { 686 int error, ismember; 687 688 /* 689 * You can only change ownership of a file if: 690 * You own the file and... 691 */ 692 if (kauth_cred_geteuid(cred) == cur_uid) { 693 /* 694 * You don't try to change ownership, and... 695 */ 696 if (new_uid != cur_uid) 697 return (EPERM); 698 699 /* 700 * You don't try to change group (no-op), or... 701 */ 702 if (new_gid == cur_gid) 703 return (0); 704 705 /* 706 * Your effective gid is the new gid, or... 707 */ 708 if (kauth_cred_getegid(cred) == new_gid) 709 return (0); 710 711 /* 712 * The new gid is one you're a member of. 713 */ 714 ismember = 0; 715 error = kauth_cred_ismember_gid(cred, new_gid, 716 &ismember); 717 if (!error && ismember) 718 return (0); 719 } 720 721 return (EPERM); 722 } 723 724 int 725 genfs_can_chtimes(vnode_t *vp, u_int vaflags, uid_t owner_uid, 726 kauth_cred_t cred) 727 { 728 int error; 729 730 /* Must be owner, or... */ 731 if (kauth_cred_geteuid(cred) == owner_uid) 732 return (0); 733 734 /* set the times to the current time, and... */ 735 if ((vaflags & VA_UTIMES_NULL) == 0) 736 return (EPERM); 737 738 /* have write access. */ 739 error = VOP_ACCESS(vp, VWRITE, cred); 740 if (error) 741 return (error); 742 743 return (0); 744 } 745 746 /* 747 * Common routine to check if chflags() is allowed. 748 * 749 * Policy: 750 * - You must own the file, and 751 * - You must not change system flags, and 752 * - You must not change flags on character/block devices. 753 * 754 * cred - credentials of the invoker 755 * owner_uid - uid of the file-system object 756 * changing_sysflags - true if the invoker wants to change system flags 757 */ 758 int 759 genfs_can_chflags(kauth_cred_t cred, enum vtype type, uid_t owner_uid, 760 bool changing_sysflags) 761 { 762 763 /* The user must own the file. */ 764 if (kauth_cred_geteuid(cred) != owner_uid) { 765 return EPERM; 766 } 767 768 if (changing_sysflags) { 769 return EPERM; 770 } 771 772 /* 773 * Unprivileged users cannot change the flags on devices, even if they 774 * own them. 775 */ 776 if (type == VCHR || type == VBLK) { 777 return EPERM; 778 } 779 780 return 0; 781 } 782 783 /* 784 * Common "sticky" policy. 785 * 786 * When a directory is "sticky" (as determined by the caller), this 787 * function may help implementing the following policy: 788 * - Renaming a file in it is only possible if the user owns the directory 789 * or the file being renamed. 790 * - Deleting a file from it is only possible if the user owns the 791 * directory or the file being deleted. 792 */ 793 int 794 genfs_can_sticky(kauth_cred_t cred, uid_t dir_uid, uid_t file_uid) 795 { 796 if (kauth_cred_geteuid(cred) != dir_uid && 797 kauth_cred_geteuid(cred) != file_uid) 798 return EPERM; 799 800 return 0; 801 } 802 803 int 804 genfs_can_extattr(kauth_cred_t cred, int access_mode, vnode_t *vp, 805 const char *attr) 806 { 807 /* We can't allow privileged namespaces. */ 808 if (strncasecmp(attr, "system", 6) == 0) 809 return EPERM; 810 811 return VOP_ACCESS(vp, access_mode, cred); 812 } 813