1 /* $NetBSD: genfs_vnops.c,v 1.177 2010/04/08 15:56:26 pooka 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.177 2010/04/08 15:56:26 pooka 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, 0); 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 292 if ((flags & LK_INTERLOCK) != 0) { 293 flags &= ~LK_INTERLOCK; 294 mutex_exit(&vp->v_interlock); 295 } 296 297 return (vlockmgr(vp->v_vnlock, flags)); 298 } 299 300 /* 301 * Unlock the node. 302 */ 303 int 304 genfs_unlock(void *v) 305 { 306 struct vop_unlock_args /* { 307 struct vnode *a_vp; 308 int a_flags; 309 } */ *ap = v; 310 struct vnode *vp = ap->a_vp; 311 312 KASSERT(ap->a_flags == 0); 313 314 return (vlockmgr(vp->v_vnlock, LK_RELEASE)); 315 } 316 317 /* 318 * Return whether or not the node is locked. 319 */ 320 int 321 genfs_islocked(void *v) 322 { 323 struct vop_islocked_args /* { 324 struct vnode *a_vp; 325 } */ *ap = v; 326 struct vnode *vp = ap->a_vp; 327 328 return (vlockstatus(vp->v_vnlock)); 329 } 330 331 /* 332 * Stubs to use when there is no locking to be done on the underlying object. 333 */ 334 int 335 genfs_nolock(void *v) 336 { 337 struct vop_lock_args /* { 338 struct vnode *a_vp; 339 int a_flags; 340 struct lwp *a_l; 341 } */ *ap = v; 342 343 /* 344 * Since we are not using the lock manager, we must clear 345 * the interlock here. 346 */ 347 if (ap->a_flags & LK_INTERLOCK) 348 mutex_exit(&ap->a_vp->v_interlock); 349 return (0); 350 } 351 352 int 353 genfs_nounlock(void *v) 354 { 355 356 return (0); 357 } 358 359 int 360 genfs_noislocked(void *v) 361 { 362 363 return (0); 364 } 365 366 int 367 genfs_mmap(void *v) 368 { 369 370 return (0); 371 } 372 373 /* 374 * VOP_PUTPAGES() for vnodes which never have pages. 375 */ 376 377 int 378 genfs_null_putpages(void *v) 379 { 380 struct vop_putpages_args /* { 381 struct vnode *a_vp; 382 voff_t a_offlo; 383 voff_t a_offhi; 384 int a_flags; 385 } */ *ap = v; 386 struct vnode *vp = ap->a_vp; 387 388 KASSERT(vp->v_uobj.uo_npages == 0); 389 mutex_exit(&vp->v_interlock); 390 return (0); 391 } 392 393 void 394 genfs_node_init(struct vnode *vp, const struct genfs_ops *ops) 395 { 396 struct genfs_node *gp = VTOG(vp); 397 398 rw_init(&gp->g_glock); 399 gp->g_op = ops; 400 } 401 402 void 403 genfs_node_destroy(struct vnode *vp) 404 { 405 struct genfs_node *gp = VTOG(vp); 406 407 rw_destroy(&gp->g_glock); 408 } 409 410 void 411 genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 412 { 413 int bsize; 414 415 bsize = 1 << vp->v_mount->mnt_fs_bshift; 416 *eobp = (size + bsize - 1) & ~(bsize - 1); 417 } 418 419 static void 420 filt_genfsdetach(struct knote *kn) 421 { 422 struct vnode *vp = (struct vnode *)kn->kn_hook; 423 424 mutex_enter(&vp->v_interlock); 425 SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext); 426 mutex_exit(&vp->v_interlock); 427 } 428 429 static int 430 filt_genfsread(struct knote *kn, long hint) 431 { 432 struct vnode *vp = (struct vnode *)kn->kn_hook; 433 int rv; 434 435 /* 436 * filesystem is gone, so set the EOF flag and schedule 437 * the knote for deletion. 438 */ 439 switch (hint) { 440 case NOTE_REVOKE: 441 KASSERT(mutex_owned(&vp->v_interlock)); 442 kn->kn_flags |= (EV_EOF | EV_ONESHOT); 443 return (1); 444 case 0: 445 mutex_enter(&vp->v_interlock); 446 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 447 rv = (kn->kn_data != 0); 448 mutex_exit(&vp->v_interlock); 449 return rv; 450 default: 451 KASSERT(mutex_owned(&vp->v_interlock)); 452 kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset; 453 return (kn->kn_data != 0); 454 } 455 } 456 457 static int 458 filt_genfsvnode(struct knote *kn, long hint) 459 { 460 struct vnode *vp = (struct vnode *)kn->kn_hook; 461 int fflags; 462 463 switch (hint) { 464 case NOTE_REVOKE: 465 KASSERT(mutex_owned(&vp->v_interlock)); 466 kn->kn_flags |= EV_EOF; 467 if ((kn->kn_sfflags & hint) != 0) 468 kn->kn_fflags |= hint; 469 return (1); 470 case 0: 471 mutex_enter(&vp->v_interlock); 472 fflags = kn->kn_fflags; 473 mutex_exit(&vp->v_interlock); 474 break; 475 default: 476 KASSERT(mutex_owned(&vp->v_interlock)); 477 if ((kn->kn_sfflags & hint) != 0) 478 kn->kn_fflags |= hint; 479 fflags = kn->kn_fflags; 480 break; 481 } 482 483 return (fflags != 0); 484 } 485 486 static const struct filterops genfsread_filtops = 487 { 1, NULL, filt_genfsdetach, filt_genfsread }; 488 static const struct filterops genfsvnode_filtops = 489 { 1, NULL, filt_genfsdetach, filt_genfsvnode }; 490 491 int 492 genfs_kqfilter(void *v) 493 { 494 struct vop_kqfilter_args /* { 495 struct vnode *a_vp; 496 struct knote *a_kn; 497 } */ *ap = v; 498 struct vnode *vp; 499 struct knote *kn; 500 501 vp = ap->a_vp; 502 kn = ap->a_kn; 503 switch (kn->kn_filter) { 504 case EVFILT_READ: 505 kn->kn_fop = &genfsread_filtops; 506 break; 507 case EVFILT_VNODE: 508 kn->kn_fop = &genfsvnode_filtops; 509 break; 510 default: 511 return (EINVAL); 512 } 513 514 kn->kn_hook = vp; 515 516 mutex_enter(&vp->v_interlock); 517 SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext); 518 mutex_exit(&vp->v_interlock); 519 520 return (0); 521 } 522 523 void 524 genfs_node_wrlock(struct vnode *vp) 525 { 526 struct genfs_node *gp = VTOG(vp); 527 528 rw_enter(&gp->g_glock, RW_WRITER); 529 } 530 531 void 532 genfs_node_rdlock(struct vnode *vp) 533 { 534 struct genfs_node *gp = VTOG(vp); 535 536 rw_enter(&gp->g_glock, RW_READER); 537 } 538 539 int 540 genfs_node_rdtrylock(struct vnode *vp) 541 { 542 struct genfs_node *gp = VTOG(vp); 543 544 return rw_tryenter(&gp->g_glock, RW_READER); 545 } 546 547 void 548 genfs_node_unlock(struct vnode *vp) 549 { 550 struct genfs_node *gp = VTOG(vp); 551 552 rw_exit(&gp->g_glock); 553 } 554 555 /* 556 * Do the usual access checking. 557 * file_mode, uid and gid are from the vnode in question, 558 * while acc_mode and cred are from the VOP_ACCESS parameter list 559 */ 560 int 561 genfs_can_access(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid, 562 mode_t acc_mode, kauth_cred_t cred) 563 { 564 mode_t mask; 565 int error, ismember; 566 567 /* 568 * Super-user always gets read/write access, but execute access depends 569 * on at least one execute bit being set. 570 */ 571 if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) == 0) { 572 if ((acc_mode & VEXEC) && type != VDIR && 573 (file_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) 574 return (EACCES); 575 return (0); 576 } 577 578 mask = 0; 579 580 /* Otherwise, check the owner. */ 581 if (kauth_cred_geteuid(cred) == uid) { 582 if (acc_mode & VEXEC) 583 mask |= S_IXUSR; 584 if (acc_mode & VREAD) 585 mask |= S_IRUSR; 586 if (acc_mode & VWRITE) 587 mask |= S_IWUSR; 588 return ((file_mode & mask) == mask ? 0 : EACCES); 589 } 590 591 /* Otherwise, check the groups. */ 592 error = kauth_cred_ismember_gid(cred, gid, &ismember); 593 if (error) 594 return (error); 595 if (kauth_cred_getegid(cred) == gid || ismember) { 596 if (acc_mode & VEXEC) 597 mask |= S_IXGRP; 598 if (acc_mode & VREAD) 599 mask |= S_IRGRP; 600 if (acc_mode & VWRITE) 601 mask |= S_IWGRP; 602 return ((file_mode & mask) == mask ? 0 : EACCES); 603 } 604 605 /* Otherwise, check everyone else. */ 606 if (acc_mode & VEXEC) 607 mask |= S_IXOTH; 608 if (acc_mode & VREAD) 609 mask |= S_IROTH; 610 if (acc_mode & VWRITE) 611 mask |= S_IWOTH; 612 return ((file_mode & mask) == mask ? 0 : EACCES); 613 } 614 615 /* 616 * Common routine to check if chmod() is allowed. 617 * 618 * Policy: 619 * - You must be root, or 620 * - You must own the file, and 621 * - You must not set the "sticky" bit (meaningless, see chmod(2)) 622 * - You must be a member of the group if you're trying to set the 623 * SGIDf bit 624 * 625 * cred - credentials of the invoker 626 * vp - vnode of the file-system object 627 * cur_uid, cur_gid - current uid/gid of the file-system object 628 * new_mode - new mode for the file-system object 629 * 630 * Returns 0 if the change is allowed, or an error value otherwise. 631 */ 632 int 633 genfs_can_chmod(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid, 634 gid_t cur_gid, mode_t new_mode) 635 { 636 int error; 637 638 /* Superuser can always change mode. */ 639 error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, 640 NULL); 641 if (!error) 642 return (0); 643 644 /* Otherwise, user must own the file. */ 645 if (kauth_cred_geteuid(cred) != cur_uid) 646 return (EPERM); 647 648 /* 649 * Non-root users can't set the sticky bit on files. 650 */ 651 if ((vp->v_type != VDIR) && (new_mode & S_ISTXT)) 652 return (EFTYPE); 653 654 /* 655 * If the invoker is trying to set the SGID bit on the file, 656 * check group membership. 657 */ 658 if (new_mode & S_ISGID) { 659 int ismember; 660 661 error = kauth_cred_ismember_gid(cred, cur_gid, 662 &ismember); 663 if (error || !ismember) 664 return (EPERM); 665 } 666 667 return (0); 668 } 669 670 /* 671 * Common routine to check if chown() is allowed. 672 * 673 * Policy: 674 * - You must be root, or 675 * - You must own the file, and 676 * - You must not try to change ownership, and 677 * - You must be member of the new group 678 * 679 * cred - credentials of the invoker 680 * cur_uid, cur_gid - current uid/gid of the file-system object 681 * new_uid, new_gid - target uid/gid of the file-system object 682 * 683 * Returns 0 if the change is allowed, or an error value otherwise. 684 */ 685 int 686 genfs_can_chown(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid, 687 gid_t cur_gid, uid_t new_uid, gid_t new_gid) 688 { 689 int error, ismember; 690 691 /* 692 * You can only change ownership of a file if: 693 * You are the superuser, or... 694 */ 695 error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, 696 NULL); 697 if (!error) 698 return (0); 699 700 /* 701 * You own the file and... 702 */ 703 if (kauth_cred_geteuid(cred) == cur_uid) { 704 /* 705 * You don't try to change ownership, and... 706 */ 707 if (new_uid != cur_uid) 708 return (EPERM); 709 710 /* 711 * You don't try to change group (no-op), or... 712 */ 713 if (new_gid == cur_gid) 714 return (0); 715 716 /* 717 * Your effective gid is the new gid, or... 718 */ 719 if (kauth_cred_getegid(cred) == new_gid) 720 return (0); 721 722 /* 723 * The new gid is one you're a member of. 724 */ 725 ismember = 0; 726 error = kauth_cred_ismember_gid(cred, new_gid, 727 &ismember); 728 if (!error && ismember) 729 return (0); 730 } 731 732 return (EPERM); 733 } 734 735 /* 736 * Common routine to check if the device can be mounted. 737 * 738 * devvp - the locked vnode of the device 739 * cred - credentials of the invoker 740 * accessmode - the accessmode (VREAD, VWRITE) 741 * 742 * Returns 0 if the mount is allowed, or an error value otherwise. 743 */ 744 int 745 genfs_can_mount(vnode_t *devvp, mode_t accessmode, kauth_cred_t cred) 746 { 747 int error; 748 749 /* Always allow for root. */ 750 error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 751 if (!error) 752 return (0); 753 754 error = VOP_ACCESS(devvp, accessmode, cred); 755 756 return (error); 757 } 758 759 int 760 genfs_can_chtimes(vnode_t *vp, u_int vaflags, uid_t owner_uid, 761 kauth_cred_t cred) 762 { 763 int error; 764 765 /* Must be root, or... */ 766 error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 767 if (!error) 768 return (0); 769 770 /* must be owner, or... */ 771 if (kauth_cred_geteuid(cred) == owner_uid) 772 return (0); 773 774 /* set the times to the current time, and... */ 775 if ((vaflags & VA_UTIMES_NULL) == 0) 776 return (EPERM); 777 778 /* have write access. */ 779 error = VOP_ACCESS(vp, VWRITE, cred); 780 if (error) 781 return (error); 782 783 return (0); 784 } 785 786