xref: /netbsd-src/sys/miscfs/genfs/genfs_vnops.c (revision 7f21db1c0118155e0dd40b75182e30c589d9f63e)
1 /*	$NetBSD: genfs_vnops.c,v 1.176 2010/01/27 15:52:31 uebayasi 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.176 2010/01/27 15:52:31 uebayasi 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  */
175 int
176 genfs_eopnotsupp(void *v)
177 {
178 	struct vop_generic_args /*
179 		struct vnodeop_desc *a_desc;
180 		/ * other random data follows, presumably * /
181 	} */ *ap = v;
182 	struct vnodeop_desc *desc = ap->a_desc;
183 	struct vnode *vp, *vp_last = NULL;
184 	int flags, i, j, offset;
185 
186 	flags = desc->vdesc_flags;
187 	for (i = 0; i < VDESC_MAX_VPS; flags >>=1, i++) {
188 		if ((offset = desc->vdesc_vp_offsets[i]) == VDESC_NO_OFFSET)
189 			break;	/* stop at end of list */
190 		if ((j = flags & VDESC_VP0_WILLPUT)) {
191 			vp = *VOPARG_OFFSETTO(struct vnode **, offset, ap);
192 
193 			/* Skip if NULL */
194 			if (!vp)
195 				continue;
196 
197 			switch (j) {
198 			case VDESC_VP0_WILLPUT:
199 				/* Check for dvp == vp cases */
200 				if (vp == vp_last)
201 					vrele(vp);
202 				else {
203 					vput(vp);
204 					vp_last = vp;
205 				}
206 				break;
207 			case VDESC_VP0_WILLUNLOCK:
208 				VOP_UNLOCK(vp, 0);
209 				break;
210 			case VDESC_VP0_WILLRELE:
211 				vrele(vp);
212 				break;
213 			}
214 		}
215 	}
216 
217 	return (EOPNOTSUPP);
218 }
219 
220 /*ARGSUSED*/
221 int
222 genfs_ebadf(void *v)
223 {
224 
225 	return (EBADF);
226 }
227 
228 /* ARGSUSED */
229 int
230 genfs_enoioctl(void *v)
231 {
232 
233 	return (EPASSTHROUGH);
234 }
235 
236 
237 /*
238  * Eliminate all activity associated with the requested vnode
239  * and with all vnodes aliased to the requested vnode.
240  */
241 int
242 genfs_revoke(void *v)
243 {
244 	struct vop_revoke_args /* {
245 		struct vnode *a_vp;
246 		int a_flags;
247 	} */ *ap = v;
248 
249 #ifdef DIAGNOSTIC
250 	if ((ap->a_flags & REVOKEALL) == 0)
251 		panic("genfs_revoke: not revokeall");
252 #endif
253 	vrevoke(ap->a_vp);
254 	return (0);
255 }
256 
257 /*
258  * Lock the node.
259  */
260 int
261 genfs_lock(void *v)
262 {
263 	struct vop_lock_args /* {
264 		struct vnode *a_vp;
265 		int a_flags;
266 	} */ *ap = v;
267 	struct vnode *vp = ap->a_vp;
268 	int flags = ap->a_flags;
269 
270 	if ((flags & LK_INTERLOCK) != 0) {
271 		flags &= ~LK_INTERLOCK;
272 		mutex_exit(&vp->v_interlock);
273 	}
274 
275 	return (vlockmgr(vp->v_vnlock, flags));
276 }
277 
278 /*
279  * Unlock the node.
280  */
281 int
282 genfs_unlock(void *v)
283 {
284 	struct vop_unlock_args /* {
285 		struct vnode *a_vp;
286 		int a_flags;
287 	} */ *ap = v;
288 	struct vnode *vp = ap->a_vp;
289 
290 	KASSERT(ap->a_flags == 0);
291 
292 	return (vlockmgr(vp->v_vnlock, LK_RELEASE));
293 }
294 
295 /*
296  * Return whether or not the node is locked.
297  */
298 int
299 genfs_islocked(void *v)
300 {
301 	struct vop_islocked_args /* {
302 		struct vnode *a_vp;
303 	} */ *ap = v;
304 	struct vnode *vp = ap->a_vp;
305 
306 	return (vlockstatus(vp->v_vnlock));
307 }
308 
309 /*
310  * Stubs to use when there is no locking to be done on the underlying object.
311  */
312 int
313 genfs_nolock(void *v)
314 {
315 	struct vop_lock_args /* {
316 		struct vnode *a_vp;
317 		int a_flags;
318 		struct lwp *a_l;
319 	} */ *ap = v;
320 
321 	/*
322 	 * Since we are not using the lock manager, we must clear
323 	 * the interlock here.
324 	 */
325 	if (ap->a_flags & LK_INTERLOCK)
326 		mutex_exit(&ap->a_vp->v_interlock);
327 	return (0);
328 }
329 
330 int
331 genfs_nounlock(void *v)
332 {
333 
334 	return (0);
335 }
336 
337 int
338 genfs_noislocked(void *v)
339 {
340 
341 	return (0);
342 }
343 
344 int
345 genfs_mmap(void *v)
346 {
347 
348 	return (0);
349 }
350 
351 /*
352  * VOP_PUTPAGES() for vnodes which never have pages.
353  */
354 
355 int
356 genfs_null_putpages(void *v)
357 {
358 	struct vop_putpages_args /* {
359 		struct vnode *a_vp;
360 		voff_t a_offlo;
361 		voff_t a_offhi;
362 		int a_flags;
363 	} */ *ap = v;
364 	struct vnode *vp = ap->a_vp;
365 
366 	KASSERT(vp->v_uobj.uo_npages == 0);
367 	mutex_exit(&vp->v_interlock);
368 	return (0);
369 }
370 
371 void
372 genfs_node_init(struct vnode *vp, const struct genfs_ops *ops)
373 {
374 	struct genfs_node *gp = VTOG(vp);
375 
376 	rw_init(&gp->g_glock);
377 	gp->g_op = ops;
378 }
379 
380 void
381 genfs_node_destroy(struct vnode *vp)
382 {
383 	struct genfs_node *gp = VTOG(vp);
384 
385 	rw_destroy(&gp->g_glock);
386 }
387 
388 void
389 genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
390 {
391 	int bsize;
392 
393 	bsize = 1 << vp->v_mount->mnt_fs_bshift;
394 	*eobp = (size + bsize - 1) & ~(bsize - 1);
395 }
396 
397 static void
398 filt_genfsdetach(struct knote *kn)
399 {
400 	struct vnode *vp = (struct vnode *)kn->kn_hook;
401 
402 	mutex_enter(&vp->v_interlock);
403 	SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext);
404 	mutex_exit(&vp->v_interlock);
405 }
406 
407 static int
408 filt_genfsread(struct knote *kn, long hint)
409 {
410 	struct vnode *vp = (struct vnode *)kn->kn_hook;
411 	int rv;
412 
413 	/*
414 	 * filesystem is gone, so set the EOF flag and schedule
415 	 * the knote for deletion.
416 	 */
417 	switch (hint) {
418 	case NOTE_REVOKE:
419 		KASSERT(mutex_owned(&vp->v_interlock));
420 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
421 		return (1);
422 	case 0:
423 		mutex_enter(&vp->v_interlock);
424 		kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
425 		rv = (kn->kn_data != 0);
426 		mutex_exit(&vp->v_interlock);
427 		return rv;
428 	default:
429 		KASSERT(mutex_owned(&vp->v_interlock));
430 		kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
431 		return (kn->kn_data != 0);
432 	}
433 }
434 
435 static int
436 filt_genfsvnode(struct knote *kn, long hint)
437 {
438 	struct vnode *vp = (struct vnode *)kn->kn_hook;
439 	int fflags;
440 
441 	switch (hint) {
442 	case NOTE_REVOKE:
443 		KASSERT(mutex_owned(&vp->v_interlock));
444 		kn->kn_flags |= EV_EOF;
445 		if ((kn->kn_sfflags & hint) != 0)
446 			kn->kn_fflags |= hint;
447 		return (1);
448 	case 0:
449 		mutex_enter(&vp->v_interlock);
450 		fflags = kn->kn_fflags;
451 		mutex_exit(&vp->v_interlock);
452 		break;
453 	default:
454 		KASSERT(mutex_owned(&vp->v_interlock));
455 		if ((kn->kn_sfflags & hint) != 0)
456 			kn->kn_fflags |= hint;
457 		fflags = kn->kn_fflags;
458 		break;
459 	}
460 
461 	return (fflags != 0);
462 }
463 
464 static const struct filterops genfsread_filtops =
465 	{ 1, NULL, filt_genfsdetach, filt_genfsread };
466 static const struct filterops genfsvnode_filtops =
467 	{ 1, NULL, filt_genfsdetach, filt_genfsvnode };
468 
469 int
470 genfs_kqfilter(void *v)
471 {
472 	struct vop_kqfilter_args /* {
473 		struct vnode	*a_vp;
474 		struct knote	*a_kn;
475 	} */ *ap = v;
476 	struct vnode *vp;
477 	struct knote *kn;
478 
479 	vp = ap->a_vp;
480 	kn = ap->a_kn;
481 	switch (kn->kn_filter) {
482 	case EVFILT_READ:
483 		kn->kn_fop = &genfsread_filtops;
484 		break;
485 	case EVFILT_VNODE:
486 		kn->kn_fop = &genfsvnode_filtops;
487 		break;
488 	default:
489 		return (EINVAL);
490 	}
491 
492 	kn->kn_hook = vp;
493 
494 	mutex_enter(&vp->v_interlock);
495 	SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext);
496 	mutex_exit(&vp->v_interlock);
497 
498 	return (0);
499 }
500 
501 void
502 genfs_node_wrlock(struct vnode *vp)
503 {
504 	struct genfs_node *gp = VTOG(vp);
505 
506 	rw_enter(&gp->g_glock, RW_WRITER);
507 }
508 
509 void
510 genfs_node_rdlock(struct vnode *vp)
511 {
512 	struct genfs_node *gp = VTOG(vp);
513 
514 	rw_enter(&gp->g_glock, RW_READER);
515 }
516 
517 int
518 genfs_node_rdtrylock(struct vnode *vp)
519 {
520 	struct genfs_node *gp = VTOG(vp);
521 
522 	return rw_tryenter(&gp->g_glock, RW_READER);
523 }
524 
525 void
526 genfs_node_unlock(struct vnode *vp)
527 {
528 	struct genfs_node *gp = VTOG(vp);
529 
530 	rw_exit(&gp->g_glock);
531 }
532 
533 /*
534  * Do the usual access checking.
535  * file_mode, uid and gid are from the vnode in question,
536  * while acc_mode and cred are from the VOP_ACCESS parameter list
537  */
538 int
539 genfs_can_access(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid,
540     mode_t acc_mode, kauth_cred_t cred)
541 {
542 	mode_t mask;
543 	int error, ismember;
544 
545 	/*
546 	 * Super-user always gets read/write access, but execute access depends
547 	 * on at least one execute bit being set.
548 	 */
549 	if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) == 0) {
550 		if ((acc_mode & VEXEC) && type != VDIR &&
551 		    (file_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)
552 			return (EACCES);
553 		return (0);
554 	}
555 
556 	mask = 0;
557 
558 	/* Otherwise, check the owner. */
559 	if (kauth_cred_geteuid(cred) == uid) {
560 		if (acc_mode & VEXEC)
561 			mask |= S_IXUSR;
562 		if (acc_mode & VREAD)
563 			mask |= S_IRUSR;
564 		if (acc_mode & VWRITE)
565 			mask |= S_IWUSR;
566 		return ((file_mode & mask) == mask ? 0 : EACCES);
567 	}
568 
569 	/* Otherwise, check the groups. */
570 	error = kauth_cred_ismember_gid(cred, gid, &ismember);
571 	if (error)
572 		return (error);
573 	if (kauth_cred_getegid(cred) == gid || ismember) {
574 		if (acc_mode & VEXEC)
575 			mask |= S_IXGRP;
576 		if (acc_mode & VREAD)
577 			mask |= S_IRGRP;
578 		if (acc_mode & VWRITE)
579 			mask |= S_IWGRP;
580 		return ((file_mode & mask) == mask ? 0 : EACCES);
581 	}
582 
583 	/* Otherwise, check everyone else. */
584 	if (acc_mode & VEXEC)
585 		mask |= S_IXOTH;
586 	if (acc_mode & VREAD)
587 		mask |= S_IROTH;
588 	if (acc_mode & VWRITE)
589 		mask |= S_IWOTH;
590 	return ((file_mode & mask) == mask ? 0 : EACCES);
591 }
592 
593 /*
594  * Common routine to check if chmod() is allowed.
595  *
596  * Policy:
597  *   - You must be root, or
598  *   - You must own the file, and
599  *     - You must not set the "sticky" bit (meaningless, see chmod(2))
600  *     - You must be a member of the group if you're trying to set the
601  *       SGIDf bit
602  *
603  * cred - credentials of the invoker
604  * vp - vnode of the file-system object
605  * cur_uid, cur_gid - current uid/gid of the file-system object
606  * new_mode - new mode for the file-system object
607  *
608  * Returns 0 if the change is allowed, or an error value otherwise.
609  */
610 int
611 genfs_can_chmod(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid,
612     gid_t cur_gid, mode_t new_mode)
613 {
614 	int error;
615 
616 	/* Superuser can always change mode. */
617 	error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
618 	    NULL);
619 	if (!error)
620 		return (0);
621 
622 	/* Otherwise, user must own the file. */
623 	if (kauth_cred_geteuid(cred) != cur_uid)
624 		return (EPERM);
625 
626 	/*
627 	 * Non-root users can't set the sticky bit on files.
628 	 */
629 	if ((vp->v_type != VDIR) && (new_mode & S_ISTXT))
630 		return (EFTYPE);
631 
632 	/*
633 	 * If the invoker is trying to set the SGID bit on the file,
634 	 * check group membership.
635 	 */
636 	if (new_mode & S_ISGID) {
637 		int ismember;
638 
639 		error = kauth_cred_ismember_gid(cred, cur_gid,
640 		    &ismember);
641 		if (error || !ismember)
642 			return (EPERM);
643 	}
644 
645 	return (0);
646 }
647 
648 /*
649  * Common routine to check if chown() is allowed.
650  *
651  * Policy:
652  *   - You must be root, or
653  *   - You must own the file, and
654  *     - You must not try to change ownership, and
655  *     - You must be member of the new group
656  *
657  * cred - credentials of the invoker
658  * cur_uid, cur_gid - current uid/gid of the file-system object
659  * new_uid, new_gid - target uid/gid of the file-system object
660  *
661  * Returns 0 if the change is allowed, or an error value otherwise.
662  */
663 int
664 genfs_can_chown(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid,
665     gid_t cur_gid, uid_t new_uid, gid_t new_gid)
666 {
667 	int error, ismember;
668 
669 	/*
670 	 * You can only change ownership of a file if:
671 	 * You are the superuser, or...
672 	 */
673 	error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
674 	    NULL);
675 	if (!error)
676 		return (0);
677 
678 	/*
679 	 * You own the file and...
680 	 */
681 	if (kauth_cred_geteuid(cred) == cur_uid) {
682 		/*
683 		 * You don't try to change ownership, and...
684 		 */
685 		if (new_uid != cur_uid)
686 			return (EPERM);
687 
688 		/*
689 		 * You don't try to change group (no-op), or...
690 		 */
691 		if (new_gid == cur_gid)
692 			return (0);
693 
694 		/*
695 		 * Your effective gid is the new gid, or...
696 		 */
697 		if (kauth_cred_getegid(cred) == new_gid)
698 			return (0);
699 
700 		/*
701 		 * The new gid is one you're a member of.
702 		 */
703 		ismember = 0;
704 		error = kauth_cred_ismember_gid(cred, new_gid,
705 		    &ismember);
706 		if (!error && ismember)
707 			return (0);
708 	}
709 
710 	return (EPERM);
711 }
712 
713 /*
714  * Common routine to check if the device can be mounted.
715  *
716  * devvp - the locked vnode of the device
717  * cred - credentials of the invoker
718  * accessmode - the accessmode (VREAD, VWRITE)
719  *
720  * Returns 0 if the mount is allowed, or an error value otherwise.
721  */
722 int
723 genfs_can_mount(vnode_t *devvp, mode_t accessmode, kauth_cred_t cred)
724 {
725 	int error;
726 
727 	/* Always allow for root. */
728 	error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
729 	if (!error)
730 		return (0);
731 
732 	error = VOP_ACCESS(devvp, accessmode, cred);
733 
734 	return (error);
735 }
736 
737 int
738 genfs_can_chtimes(vnode_t *vp, u_int vaflags, uid_t owner_uid,
739     kauth_cred_t cred)
740 {
741 	int error;
742 
743 	/* Must be root, or... */
744 	error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
745 	if (!error)
746 		return (0);
747 
748 	/* must be owner, or... */
749 	if (kauth_cred_geteuid(cred) == owner_uid)
750 		return (0);
751 
752 	/* set the times to the current time, and... */
753 	if ((vaflags & VA_UTIMES_NULL) == 0)
754 		return (EPERM);
755 
756 	/* have write access. */
757 	error = VOP_ACCESS(vp, VWRITE, cred);
758 	if (error)
759 		return (error);
760 
761 	return (0);
762 }
763 
764