1 /* $NetBSD: genfs_vnops.c,v 1.183 2010/09/01 16:56:19 chs 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.183 2010/09/01 16:56:19 chs 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/namei.h> 68 #include <sys/vnode.h> 69 #include <sys/fcntl.h> 70 #include <sys/kmem.h> 71 #include <sys/poll.h> 72 #include <sys/mman.h> 73 #include <sys/file.h> 74 #include <sys/kauth.h> 75 #include <sys/stat.h> 76 77 #include <miscfs/genfs/genfs.h> 78 #include <miscfs/genfs/genfs_node.h> 79 #include <miscfs/specfs/specdev.h> 80 81 #include <uvm/uvm.h> 82 #include <uvm/uvm_pager.h> 83 84 static void filt_genfsdetach(struct knote *); 85 static int filt_genfsread(struct knote *, long); 86 static int filt_genfsvnode(struct knote *, long); 87 88 int 89 genfs_poll(void *v) 90 { 91 struct vop_poll_args /* { 92 struct vnode *a_vp; 93 int a_events; 94 struct lwp *a_l; 95 } */ *ap = v; 96 97 return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 98 } 99 100 int 101 genfs_seek(void *v) 102 { 103 struct vop_seek_args /* { 104 struct vnode *a_vp; 105 off_t a_oldoff; 106 off_t a_newoff; 107 kauth_cred_t cred; 108 } */ *ap = v; 109 110 if (ap->a_newoff < 0) 111 return (EINVAL); 112 113 return (0); 114 } 115 116 int 117 genfs_abortop(void *v) 118 { 119 struct vop_abortop_args /* { 120 struct vnode *a_dvp; 121 struct componentname *a_cnp; 122 } */ *ap = v; 123 124 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 125 PNBUF_PUT(ap->a_cnp->cn_pnbuf); 126 return (0); 127 } 128 129 int 130 genfs_fcntl(void *v) 131 { 132 struct vop_fcntl_args /* { 133 struct vnode *a_vp; 134 u_int a_command; 135 void *a_data; 136 int a_fflag; 137 kauth_cred_t a_cred; 138 struct lwp *a_l; 139 } */ *ap = v; 140 141 if (ap->a_command == F_SETFL) 142 return (0); 143 else 144 return (EOPNOTSUPP); 145 } 146 147 /*ARGSUSED*/ 148 int 149 genfs_badop(void *v) 150 { 151 152 panic("genfs: bad op"); 153 } 154 155 /*ARGSUSED*/ 156 int 157 genfs_nullop(void *v) 158 { 159 160 return (0); 161 } 162 163 /*ARGSUSED*/ 164 int 165 genfs_einval(void *v) 166 { 167 168 return (EINVAL); 169 } 170 171 /* 172 * Called when an fs doesn't support a particular vop. 173 * This takes care to vrele, vput, or vunlock passed in vnodes 174 * and calls VOP_ABORTOP for a componentname (in non-rename VOP). 175 */ 176 int 177 genfs_eopnotsupp(void *v) 178 { 179 struct vop_generic_args /* 180 struct vnodeop_desc *a_desc; 181 / * other random data follows, presumably * / 182 } */ *ap = v; 183 struct vnodeop_desc *desc = ap->a_desc; 184 struct vnode *vp, *vp_last = NULL; 185 int flags, i, j, offset_cnp, offset_vp; 186 187 KASSERT(desc->vdesc_offset != VOP_LOOKUP_DESCOFFSET); 188 KASSERT(desc->vdesc_offset != VOP_ABORTOP_DESCOFFSET); 189 190 /* 191 * Free componentname that lookup potentially SAVENAMEd. 192 * 193 * As is logical, componentnames for VOP_RENAME are handled by 194 * the caller of VOP_RENAME. Yay, rename! 195 */ 196 if (desc->vdesc_offset != VOP_RENAME_DESCOFFSET && 197 (offset_vp = desc->vdesc_vp_offsets[0]) != VDESC_NO_OFFSET && 198 (offset_cnp = desc->vdesc_componentname_offset) != VDESC_NO_OFFSET){ 199 struct componentname *cnp; 200 struct vnode *dvp; 201 202 dvp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap); 203 cnp = *VOPARG_OFFSETTO(struct componentname **, offset_cnp, ap); 204 205 VOP_ABORTOP(dvp, cnp); 206 } 207 208 flags = desc->vdesc_flags; 209 for (i = 0; i < VDESC_MAX_VPS; flags >>=1, i++) { 210 if ((offset_vp = desc->vdesc_vp_offsets[i]) == VDESC_NO_OFFSET) 211 break; /* stop at end of list */ 212 if ((j = flags & VDESC_VP0_WILLPUT)) { 213 vp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap); 214 215 /* Skip if NULL */ 216 if (!vp) 217 continue; 218 219 switch (j) { 220 case VDESC_VP0_WILLPUT: 221 /* Check for dvp == vp cases */ 222 if (vp == vp_last) 223 vrele(vp); 224 else { 225 vput(vp); 226 vp_last = vp; 227 } 228 break; 229 case VDESC_VP0_WILLUNLOCK: 230 VOP_UNLOCK(vp); 231 break; 232 case VDESC_VP0_WILLRELE: 233 vrele(vp); 234 break; 235 } 236 } 237 } 238 239 return (EOPNOTSUPP); 240 } 241 242 /*ARGSUSED*/ 243 int 244 genfs_ebadf(void *v) 245 { 246 247 return (EBADF); 248 } 249 250 /* ARGSUSED */ 251 int 252 genfs_enoioctl(void *v) 253 { 254 255 return (EPASSTHROUGH); 256 } 257 258 259 /* 260 * Eliminate all activity associated with the requested vnode 261 * and with all vnodes aliased to the requested vnode. 262 */ 263 int 264 genfs_revoke(void *v) 265 { 266 struct vop_revoke_args /* { 267 struct vnode *a_vp; 268 int a_flags; 269 } */ *ap = v; 270 271 #ifdef DIAGNOSTIC 272 if ((ap->a_flags & REVOKEALL) == 0) 273 panic("genfs_revoke: not revokeall"); 274 #endif 275 vrevoke(ap->a_vp); 276 return (0); 277 } 278 279 /* 280 * Lock the node. 281 */ 282 int 283 genfs_lock(void *v) 284 { 285 struct vop_lock_args /* { 286 struct vnode *a_vp; 287 int a_flags; 288 } */ *ap = v; 289 struct vnode *vp = ap->a_vp; 290 int flags = ap->a_flags; 291 krw_t op; 292 293 KASSERT((flags & ~(LK_EXCLUSIVE | LK_SHARED | LK_NOWAIT)) == 0); 294 295 op = ((flags & LK_EXCLUSIVE) != 0 ? RW_WRITER : RW_READER); 296 297 if ((flags & LK_NOWAIT) != 0) 298 return (rw_tryenter(&vp->v_lock, op) ? 0 : EBUSY); 299 300 rw_enter(&vp->v_lock, op); 301 302 return 0; 303 } 304 305 /* 306 * Unlock the node. 307 */ 308 int 309 genfs_unlock(void *v) 310 { 311 struct vop_unlock_args /* { 312 struct vnode *a_vp; 313 } */ *ap = v; 314 struct vnode *vp = ap->a_vp; 315 316 rw_exit(&vp->v_lock); 317 318 return 0; 319 } 320 321 /* 322 * Return whether or not the node is locked. 323 */ 324 int 325 genfs_islocked(void *v) 326 { 327 struct vop_islocked_args /* { 328 struct vnode *a_vp; 329 } */ *ap = v; 330 struct vnode *vp = ap->a_vp; 331 332 if (rw_write_held(&vp->v_lock)) 333 return LK_EXCLUSIVE; 334 335 if (rw_read_held(&vp->v_lock)) 336 return LK_SHARED; 337 338 return 0; 339 } 340 341 /* 342 * Stubs to use when there is no locking to be done on the underlying object. 343 */ 344 int 345 genfs_nolock(void *v) 346 { 347 348 return (0); 349 } 350 351 int 352 genfs_nounlock(void *v) 353 { 354 355 return (0); 356 } 357 358 int 359 genfs_noislocked(void *v) 360 { 361 362 return (0); 363 } 364 365 int 366 genfs_mmap(void *v) 367 { 368 369 return (0); 370 } 371 372 /* 373 * VOP_PUTPAGES() for vnodes which never have pages. 374 */ 375 376 int 377 genfs_null_putpages(void *v) 378 { 379 struct vop_putpages_args /* { 380 struct vnode *a_vp; 381 voff_t a_offlo; 382 voff_t a_offhi; 383 int a_flags; 384 } */ *ap = v; 385 struct vnode *vp = ap->a_vp; 386 387 KASSERT(vp->v_uobj.uo_npages == 0); 388 mutex_exit(&vp->v_interlock); 389 return (0); 390 } 391 392 void 393 genfs_node_init(struct vnode *vp, const struct genfs_ops *ops) 394 { 395 struct genfs_node *gp = VTOG(vp); 396 397 rw_init(&gp->g_glock); 398 gp->g_op = ops; 399 } 400 401 void 402 genfs_node_destroy(struct vnode *vp) 403 { 404 struct genfs_node *gp = VTOG(vp); 405 406 rw_destroy(&gp->g_glock); 407 } 408 409 void 410 genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 411 { 412 int bsize; 413 414 bsize = 1 << vp->v_mount->mnt_fs_bshift; 415 *eobp = (size + bsize - 1) & ~(bsize - 1); 416 } 417 418 static void 419 filt_genfsdetach(struct knote *kn) 420 { 421 struct vnode *vp = (struct vnode *)kn->kn_hook; 422 423 mutex_enter(&vp->v_interlock); 424 SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext); 425 mutex_exit(&vp->v_interlock); 426 } 427 428 static int 429 filt_genfsread(struct knote *kn, long hint) 430 { 431 struct vnode *vp = (struct vnode *)kn->kn_hook; 432 int rv; 433 434 /* 435 * filesystem is gone, so set the EOF flag and schedule 436 * the knote for deletion. 437 */ 438 switch (hint) { 439 case NOTE_REVOKE: 440 KASSERT(mutex_owned(&vp->v_interlock)); 441 kn->kn_flags |= (EV_EOF | EV_ONESHOT); 442 return (1); 443 case 0: 444 mutex_enter(&vp->v_interlock); 445 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 446 rv = (kn->kn_data != 0); 447 mutex_exit(&vp->v_interlock); 448 return rv; 449 default: 450 KASSERT(mutex_owned(&vp->v_interlock)); 451 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 452 return (kn->kn_data != 0); 453 } 454 } 455 456 static int 457 filt_genfsvnode(struct knote *kn, long hint) 458 { 459 struct vnode *vp = (struct vnode *)kn->kn_hook; 460 int fflags; 461 462 switch (hint) { 463 case NOTE_REVOKE: 464 KASSERT(mutex_owned(&vp->v_interlock)); 465 kn->kn_flags |= EV_EOF; 466 if ((kn->kn_sfflags & hint) != 0) 467 kn->kn_fflags |= hint; 468 return (1); 469 case 0: 470 mutex_enter(&vp->v_interlock); 471 fflags = kn->kn_fflags; 472 mutex_exit(&vp->v_interlock); 473 break; 474 default: 475 KASSERT(mutex_owned(&vp->v_interlock)); 476 if ((kn->kn_sfflags & hint) != 0) 477 kn->kn_fflags |= hint; 478 fflags = kn->kn_fflags; 479 break; 480 } 481 482 return (fflags != 0); 483 } 484 485 static const struct filterops genfsread_filtops = 486 { 1, NULL, filt_genfsdetach, filt_genfsread }; 487 static const struct filterops genfsvnode_filtops = 488 { 1, NULL, filt_genfsdetach, filt_genfsvnode }; 489 490 int 491 genfs_kqfilter(void *v) 492 { 493 struct vop_kqfilter_args /* { 494 struct vnode *a_vp; 495 struct knote *a_kn; 496 } */ *ap = v; 497 struct vnode *vp; 498 struct knote *kn; 499 500 vp = ap->a_vp; 501 kn = ap->a_kn; 502 switch (kn->kn_filter) { 503 case EVFILT_READ: 504 kn->kn_fop = &genfsread_filtops; 505 break; 506 case EVFILT_VNODE: 507 kn->kn_fop = &genfsvnode_filtops; 508 break; 509 default: 510 return (EINVAL); 511 } 512 513 kn->kn_hook = vp; 514 515 mutex_enter(&vp->v_interlock); 516 SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext); 517 mutex_exit(&vp->v_interlock); 518 519 return (0); 520 } 521 522 void 523 genfs_node_wrlock(struct vnode *vp) 524 { 525 struct genfs_node *gp = VTOG(vp); 526 527 rw_enter(&gp->g_glock, RW_WRITER); 528 } 529 530 void 531 genfs_node_rdlock(struct vnode *vp) 532 { 533 struct genfs_node *gp = VTOG(vp); 534 535 rw_enter(&gp->g_glock, RW_READER); 536 } 537 538 int 539 genfs_node_rdtrylock(struct vnode *vp) 540 { 541 struct genfs_node *gp = VTOG(vp); 542 543 return rw_tryenter(&gp->g_glock, RW_READER); 544 } 545 546 void 547 genfs_node_unlock(struct vnode *vp) 548 { 549 struct genfs_node *gp = VTOG(vp); 550 551 rw_exit(&gp->g_glock); 552 } 553 554 int 555 genfs_node_wrlocked(struct vnode *vp) 556 { 557 struct genfs_node *gp = VTOG(vp); 558 559 return rw_write_held(&gp->g_glock); 560 } 561 562 /* 563 * Do the usual access checking. 564 * file_mode, uid and gid are from the vnode in question, 565 * while acc_mode and cred are from the VOP_ACCESS parameter list 566 */ 567 int 568 genfs_can_access(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid, 569 mode_t acc_mode, kauth_cred_t cred) 570 { 571 mode_t mask; 572 int error, ismember; 573 574 /* 575 * Super-user always gets read/write access, but execute access depends 576 * on at least one execute bit being set. 577 */ 578 if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) == 0) { 579 if ((acc_mode & VEXEC) && type != VDIR && 580 (file_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) 581 return (EACCES); 582 return (0); 583 } 584 585 mask = 0; 586 587 /* Otherwise, check the owner. */ 588 if (kauth_cred_geteuid(cred) == uid) { 589 if (acc_mode & VEXEC) 590 mask |= S_IXUSR; 591 if (acc_mode & VREAD) 592 mask |= S_IRUSR; 593 if (acc_mode & VWRITE) 594 mask |= S_IWUSR; 595 return ((file_mode & mask) == mask ? 0 : EACCES); 596 } 597 598 /* Otherwise, check the groups. */ 599 error = kauth_cred_ismember_gid(cred, gid, &ismember); 600 if (error) 601 return (error); 602 if (kauth_cred_getegid(cred) == gid || ismember) { 603 if (acc_mode & VEXEC) 604 mask |= S_IXGRP; 605 if (acc_mode & VREAD) 606 mask |= S_IRGRP; 607 if (acc_mode & VWRITE) 608 mask |= S_IWGRP; 609 return ((file_mode & mask) == mask ? 0 : EACCES); 610 } 611 612 /* Otherwise, check everyone else. */ 613 if (acc_mode & VEXEC) 614 mask |= S_IXOTH; 615 if (acc_mode & VREAD) 616 mask |= S_IROTH; 617 if (acc_mode & VWRITE) 618 mask |= S_IWOTH; 619 return ((file_mode & mask) == mask ? 0 : EACCES); 620 } 621 622 /* 623 * Common routine to check if chmod() is allowed. 624 * 625 * Policy: 626 * - You must be root, or 627 * - You must own the file, and 628 * - You must not set the "sticky" bit (meaningless, see chmod(2)) 629 * - You must be a member of the group if you're trying to set the 630 * SGIDf bit 631 * 632 * cred - credentials of the invoker 633 * vp - vnode of the file-system object 634 * cur_uid, cur_gid - current uid/gid of the file-system object 635 * new_mode - new mode for the file-system object 636 * 637 * Returns 0 if the change is allowed, or an error value otherwise. 638 */ 639 int 640 genfs_can_chmod(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid, 641 gid_t cur_gid, mode_t new_mode) 642 { 643 int error; 644 645 /* Superuser can always change mode. */ 646 error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, 647 NULL); 648 if (!error) 649 return (0); 650 651 /* Otherwise, user must own the file. */ 652 if (kauth_cred_geteuid(cred) != cur_uid) 653 return (EPERM); 654 655 /* 656 * Non-root users can't set the sticky bit on files. 657 */ 658 if ((vp->v_type != VDIR) && (new_mode & S_ISTXT)) 659 return (EFTYPE); 660 661 /* 662 * If the invoker is trying to set the SGID bit on the file, 663 * check group membership. 664 */ 665 if (new_mode & S_ISGID) { 666 int ismember; 667 668 error = kauth_cred_ismember_gid(cred, cur_gid, 669 &ismember); 670 if (error || !ismember) 671 return (EPERM); 672 } 673 674 return (0); 675 } 676 677 /* 678 * Common routine to check if chown() is allowed. 679 * 680 * Policy: 681 * - You must be root, or 682 * - You must own the file, and 683 * - You must not try to change ownership, and 684 * - You must be member of the new group 685 * 686 * cred - credentials of the invoker 687 * cur_uid, cur_gid - current uid/gid of the file-system object 688 * new_uid, new_gid - target uid/gid of the file-system object 689 * 690 * Returns 0 if the change is allowed, or an error value otherwise. 691 */ 692 int 693 genfs_can_chown(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid, 694 gid_t cur_gid, uid_t new_uid, gid_t new_gid) 695 { 696 int error, ismember; 697 698 /* 699 * You can only change ownership of a file if: 700 * You are the superuser, or... 701 */ 702 error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, 703 NULL); 704 if (!error) 705 return (0); 706 707 /* 708 * You own the file and... 709 */ 710 if (kauth_cred_geteuid(cred) == cur_uid) { 711 /* 712 * You don't try to change ownership, and... 713 */ 714 if (new_uid != cur_uid) 715 return (EPERM); 716 717 /* 718 * You don't try to change group (no-op), or... 719 */ 720 if (new_gid == cur_gid) 721 return (0); 722 723 /* 724 * Your effective gid is the new gid, or... 725 */ 726 if (kauth_cred_getegid(cred) == new_gid) 727 return (0); 728 729 /* 730 * The new gid is one you're a member of. 731 */ 732 ismember = 0; 733 error = kauth_cred_ismember_gid(cred, new_gid, 734 &ismember); 735 if (!error && ismember) 736 return (0); 737 } 738 739 return (EPERM); 740 } 741 742 /* 743 * Common routine to check if the device can be mounted. 744 * 745 * devvp - the locked vnode of the device 746 * cred - credentials of the invoker 747 * accessmode - the accessmode (VREAD, VWRITE) 748 * 749 * Returns 0 if the mount is allowed, or an error value otherwise. 750 */ 751 int 752 genfs_can_mount(vnode_t *devvp, mode_t accessmode, kauth_cred_t cred) 753 { 754 int error; 755 756 /* Always allow for root. */ 757 error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 758 if (!error) 759 return (0); 760 761 error = VOP_ACCESS(devvp, accessmode, cred); 762 763 return (error); 764 } 765 766 int 767 genfs_can_chtimes(vnode_t *vp, u_int vaflags, uid_t owner_uid, 768 kauth_cred_t cred) 769 { 770 int error; 771 772 /* Must be root, or... */ 773 error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 774 if (!error) 775 return (0); 776 777 /* must be owner, or... */ 778 if (kauth_cred_geteuid(cred) == owner_uid) 779 return (0); 780 781 /* set the times to the current time, and... */ 782 if ((vaflags & VA_UTIMES_NULL) == 0) 783 return (EPERM); 784 785 /* have write access. */ 786 error = VOP_ACCESS(vp, VWRITE, cred); 787 if (error) 788 return (error); 789 790 return (0); 791 } 792 793