1 /* $NetBSD: genfs_vnops.c,v 1.186 2010/12/27 18:49:42 hannken 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.186 2010/12/27 18:49:42 hannken 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 /* 584 * Super-user always gets read/write access, but execute access depends 585 * on at least one execute bit being set. 586 */ 587 if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) == 0) { 588 if ((acc_mode & VEXEC) && type != VDIR && 589 (file_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) 590 return (EACCES); 591 return (0); 592 } 593 594 mask = 0; 595 596 /* Otherwise, check the owner. */ 597 if (kauth_cred_geteuid(cred) == uid) { 598 if (acc_mode & VEXEC) 599 mask |= S_IXUSR; 600 if (acc_mode & VREAD) 601 mask |= S_IRUSR; 602 if (acc_mode & VWRITE) 603 mask |= S_IWUSR; 604 return ((file_mode & mask) == mask ? 0 : EACCES); 605 } 606 607 /* Otherwise, check the groups. */ 608 error = kauth_cred_ismember_gid(cred, gid, &ismember); 609 if (error) 610 return (error); 611 if (kauth_cred_getegid(cred) == gid || ismember) { 612 if (acc_mode & VEXEC) 613 mask |= S_IXGRP; 614 if (acc_mode & VREAD) 615 mask |= S_IRGRP; 616 if (acc_mode & VWRITE) 617 mask |= S_IWGRP; 618 return ((file_mode & mask) == mask ? 0 : EACCES); 619 } 620 621 /* Otherwise, check everyone else. */ 622 if (acc_mode & VEXEC) 623 mask |= S_IXOTH; 624 if (acc_mode & VREAD) 625 mask |= S_IROTH; 626 if (acc_mode & VWRITE) 627 mask |= S_IWOTH; 628 return ((file_mode & mask) == mask ? 0 : EACCES); 629 } 630 631 /* 632 * Common routine to check if chmod() is allowed. 633 * 634 * Policy: 635 * - You must be root, or 636 * - You must own the file, and 637 * - You must not set the "sticky" bit (meaningless, see chmod(2)) 638 * - You must be a member of the group if you're trying to set the 639 * SGIDf bit 640 * 641 * cred - credentials of the invoker 642 * vp - vnode of the file-system object 643 * cur_uid, cur_gid - current uid/gid of the file-system object 644 * new_mode - new mode for the file-system object 645 * 646 * Returns 0 if the change is allowed, or an error value otherwise. 647 */ 648 int 649 genfs_can_chmod(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid, 650 gid_t cur_gid, mode_t new_mode) 651 { 652 int error; 653 654 /* Superuser can always change mode. */ 655 error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, 656 NULL); 657 if (!error) 658 return (0); 659 660 /* Otherwise, user must own the file. */ 661 if (kauth_cred_geteuid(cred) != cur_uid) 662 return (EPERM); 663 664 /* 665 * Non-root users can't set the sticky bit on files. 666 */ 667 if ((vp->v_type != VDIR) && (new_mode & S_ISTXT)) 668 return (EFTYPE); 669 670 /* 671 * If the invoker is trying to set the SGID bit on the file, 672 * check group membership. 673 */ 674 if (new_mode & S_ISGID) { 675 int ismember; 676 677 error = kauth_cred_ismember_gid(cred, cur_gid, 678 &ismember); 679 if (error || !ismember) 680 return (EPERM); 681 } 682 683 return (0); 684 } 685 686 /* 687 * Common routine to check if chown() is allowed. 688 * 689 * Policy: 690 * - You must be root, or 691 * - You must own the file, and 692 * - You must not try to change ownership, and 693 * - You must be member of the new group 694 * 695 * cred - credentials of the invoker 696 * cur_uid, cur_gid - current uid/gid of the file-system object 697 * new_uid, new_gid - target uid/gid of the file-system object 698 * 699 * Returns 0 if the change is allowed, or an error value otherwise. 700 */ 701 int 702 genfs_can_chown(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid, 703 gid_t cur_gid, uid_t new_uid, gid_t new_gid) 704 { 705 int error, ismember; 706 707 /* 708 * You can only change ownership of a file if: 709 * You are the superuser, or... 710 */ 711 error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, 712 NULL); 713 if (!error) 714 return (0); 715 716 /* 717 * You own the file and... 718 */ 719 if (kauth_cred_geteuid(cred) == cur_uid) { 720 /* 721 * You don't try to change ownership, and... 722 */ 723 if (new_uid != cur_uid) 724 return (EPERM); 725 726 /* 727 * You don't try to change group (no-op), or... 728 */ 729 if (new_gid == cur_gid) 730 return (0); 731 732 /* 733 * Your effective gid is the new gid, or... 734 */ 735 if (kauth_cred_getegid(cred) == new_gid) 736 return (0); 737 738 /* 739 * The new gid is one you're a member of. 740 */ 741 ismember = 0; 742 error = kauth_cred_ismember_gid(cred, new_gid, 743 &ismember); 744 if (!error && ismember) 745 return (0); 746 } 747 748 return (EPERM); 749 } 750 751 /* 752 * Common routine to check if the device can be mounted. 753 * 754 * devvp - the locked vnode of the device 755 * cred - credentials of the invoker 756 * accessmode - the accessmode (VREAD, VWRITE) 757 * 758 * Returns 0 if the mount is allowed, or an error value otherwise. 759 */ 760 int 761 genfs_can_mount(vnode_t *devvp, mode_t accessmode, kauth_cred_t cred) 762 { 763 int error; 764 765 /* Always allow for root. */ 766 error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 767 if (!error) 768 return (0); 769 770 error = VOP_ACCESS(devvp, accessmode, cred); 771 772 return (error); 773 } 774 775 int 776 genfs_can_chtimes(vnode_t *vp, u_int vaflags, uid_t owner_uid, 777 kauth_cred_t cred) 778 { 779 int error; 780 781 /* Must be root, or... */ 782 error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); 783 if (!error) 784 return (0); 785 786 /* must be owner, or... */ 787 if (kauth_cred_geteuid(cred) == owner_uid) 788 return (0); 789 790 /* set the times to the current time, and... */ 791 if ((vaflags & VA_UTIMES_NULL) == 0) 792 return (EPERM); 793 794 /* have write access. */ 795 error = VOP_ACCESS(vp, VWRITE, cred); 796 if (error) 797 return (error); 798 799 return (0); 800 } 801 802