xref: /netbsd-src/sys/miscfs/genfs/genfs_vnops.c (revision a04395531661c5e8d314125d5ae77d4cbedd5d73)
1 /*	$NetBSD: genfs_vnops.c,v 1.211 2021/06/29 22:34:08 dholland 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.211 2021/06/29 22:34:08 dholland 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_impl.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 #include <sys/extattr.h>
78 
79 #include <miscfs/genfs/genfs.h>
80 #include <miscfs/genfs/genfs_node.h>
81 #include <miscfs/specfs/specdev.h>
82 
83 static void filt_genfsdetach(struct knote *);
84 static int filt_genfsread(struct knote *, long);
85 static int filt_genfsvnode(struct knote *, long);
86 
87 /*
88  * Find the end of the first path component in NAME and return its
89  * length.
90  */
91 int
92 genfs_parsepath(void *v)
93 {
94 	struct vop_parsepath_args /* {
95 		struct vnode *a_dvp;
96 		const char *a_name;
97 		size_t *a_ret;
98 	} */ *ap = v;
99 	const char *name = ap->a_name;
100 	size_t pos;
101 
102 	(void)ap->a_dvp;
103 
104 	pos = 0;
105 	while (name[pos] != '\0' && name[pos] != '/') {
106 		pos++;
107 	}
108 	*ap->a_retval = pos;
109 	return 0;
110 }
111 
112 int
113 genfs_poll(void *v)
114 {
115 	struct vop_poll_args /* {
116 		struct vnode *a_vp;
117 		int a_events;
118 		struct lwp *a_l;
119 	} */ *ap = v;
120 
121 	return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
122 }
123 
124 int
125 genfs_seek(void *v)
126 {
127 	struct vop_seek_args /* {
128 		struct vnode *a_vp;
129 		off_t a_oldoff;
130 		off_t a_newoff;
131 		kauth_cred_t cred;
132 	} */ *ap = v;
133 
134 	if (ap->a_newoff < 0)
135 		return (EINVAL);
136 
137 	return (0);
138 }
139 
140 int
141 genfs_abortop(void *v)
142 {
143 	struct vop_abortop_args /* {
144 		struct vnode *a_dvp;
145 		struct componentname *a_cnp;
146 	} */ *ap = v;
147 
148 	(void)ap;
149 
150 	return (0);
151 }
152 
153 int
154 genfs_fcntl(void *v)
155 {
156 	struct vop_fcntl_args /* {
157 		struct vnode *a_vp;
158 		u_int a_command;
159 		void *a_data;
160 		int a_fflag;
161 		kauth_cred_t a_cred;
162 		struct lwp *a_l;
163 	} */ *ap = v;
164 
165 	if (ap->a_command == F_SETFL)
166 		return (0);
167 	else
168 		return (EOPNOTSUPP);
169 }
170 
171 /*ARGSUSED*/
172 int
173 genfs_badop(void *v)
174 {
175 
176 	panic("genfs: bad op");
177 }
178 
179 /*ARGSUSED*/
180 int
181 genfs_nullop(void *v)
182 {
183 
184 	return (0);
185 }
186 
187 /*ARGSUSED*/
188 int
189 genfs_einval(void *v)
190 {
191 
192 	return (EINVAL);
193 }
194 
195 /*
196  * Called when an fs doesn't support a particular vop.
197  * This takes care to vrele, vput, or vunlock passed in vnodes
198  * and calls VOP_ABORTOP for a componentname (in non-rename VOP).
199  */
200 int
201 genfs_eopnotsupp(void *v)
202 {
203 	struct vop_generic_args /*
204 		struct vnodeop_desc *a_desc;
205 		/ * other random data follows, presumably * /
206 	} */ *ap = v;
207 	struct vnodeop_desc *desc = ap->a_desc;
208 	struct vnode *vp, *vp_last = NULL;
209 	int flags, i, j, offset_cnp, offset_vp;
210 
211 	KASSERT(desc->vdesc_offset != VOP_LOOKUP_DESCOFFSET);
212 	KASSERT(desc->vdesc_offset != VOP_ABORTOP_DESCOFFSET);
213 
214 	/*
215 	 * Abort any componentname that lookup potentially left state in.
216 	 *
217 	 * As is logical, componentnames for VOP_RENAME are handled by
218 	 * the caller of VOP_RENAME.  Yay, rename!
219 	 */
220 	if (desc->vdesc_offset != VOP_RENAME_DESCOFFSET &&
221 	    (offset_vp = desc->vdesc_vp_offsets[0]) != VDESC_NO_OFFSET &&
222 	    (offset_cnp = desc->vdesc_componentname_offset) != VDESC_NO_OFFSET){
223 		struct componentname *cnp;
224 		struct vnode *dvp;
225 
226 		dvp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap);
227 		cnp = *VOPARG_OFFSETTO(struct componentname **, offset_cnp, ap);
228 
229 		VOP_ABORTOP(dvp, cnp);
230 	}
231 
232 	flags = desc->vdesc_flags;
233 	for (i = 0; i < VDESC_MAX_VPS; flags >>=1, i++) {
234 		if ((offset_vp = desc->vdesc_vp_offsets[i]) == VDESC_NO_OFFSET)
235 			break;	/* stop at end of list */
236 		if ((j = flags & VDESC_VP0_WILLPUT)) {
237 			vp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap);
238 
239 			/* Skip if NULL */
240 			if (!vp)
241 				continue;
242 
243 			switch (j) {
244 			case VDESC_VP0_WILLPUT:
245 				/* Check for dvp == vp cases */
246 				if (vp == vp_last)
247 					vrele(vp);
248 				else {
249 					vput(vp);
250 					vp_last = vp;
251 				}
252 				break;
253 			case VDESC_VP0_WILLRELE:
254 				vrele(vp);
255 				break;
256 			}
257 		}
258 	}
259 
260 	return (EOPNOTSUPP);
261 }
262 
263 /*ARGSUSED*/
264 int
265 genfs_ebadf(void *v)
266 {
267 
268 	return (EBADF);
269 }
270 
271 /* ARGSUSED */
272 int
273 genfs_enoioctl(void *v)
274 {
275 
276 	return (EPASSTHROUGH);
277 }
278 
279 
280 /*
281  * Eliminate all activity associated with the requested vnode
282  * and with all vnodes aliased to the requested vnode.
283  */
284 int
285 genfs_revoke(void *v)
286 {
287 	struct vop_revoke_args /* {
288 		struct vnode *a_vp;
289 		int a_flags;
290 	} */ *ap = v;
291 
292 #ifdef DIAGNOSTIC
293 	if ((ap->a_flags & REVOKEALL) == 0)
294 		panic("genfs_revoke: not revokeall");
295 #endif
296 	vrevoke(ap->a_vp);
297 	return (0);
298 }
299 
300 /*
301  * Lock the node (for deadfs).
302  */
303 int
304 genfs_deadlock(void *v)
305 {
306 	struct vop_lock_args /* {
307 		struct vnode *a_vp;
308 		int a_flags;
309 	} */ *ap = v;
310 	vnode_t *vp = ap->a_vp;
311 	vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
312 	int flags = ap->a_flags;
313 	krw_t op;
314 
315 	if (! ISSET(flags, LK_RETRY))
316 		return ENOENT;
317 
318 	if (ISSET(flags, LK_DOWNGRADE)) {
319 		rw_downgrade(&vip->vi_lock);
320 	} else if (ISSET(flags, LK_UPGRADE)) {
321 		KASSERT(ISSET(flags, LK_NOWAIT));
322 		if (!rw_tryupgrade(&vip->vi_lock)) {
323 			return EBUSY;
324 		}
325 	} else if ((flags & (LK_EXCLUSIVE | LK_SHARED)) != 0) {
326 		op = (ISSET(flags, LK_EXCLUSIVE) ? RW_WRITER : RW_READER);
327 		if (ISSET(flags, LK_NOWAIT)) {
328 			if (!rw_tryenter(&vip->vi_lock, op))
329 				return EBUSY;
330 		} else {
331 			rw_enter(&vip->vi_lock, op);
332 		}
333 	}
334 	VSTATE_ASSERT_UNLOCKED(vp, VS_RECLAIMED);
335 	return 0;
336 }
337 
338 /*
339  * Unlock the node (for deadfs).
340  */
341 int
342 genfs_deadunlock(void *v)
343 {
344 	struct vop_unlock_args /* {
345 		struct vnode *a_vp;
346 	} */ *ap = v;
347 	vnode_t *vp = ap->a_vp;
348 	vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
349 
350 	rw_exit(&vip->vi_lock);
351 
352 	return 0;
353 }
354 
355 /*
356  * Lock the node.
357  */
358 int
359 genfs_lock(void *v)
360 {
361 	struct vop_lock_args /* {
362 		struct vnode *a_vp;
363 		int a_flags;
364 	} */ *ap = v;
365 	vnode_t *vp = ap->a_vp;
366 	vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
367 	int flags = ap->a_flags;
368 	krw_t op;
369 
370 	if (ISSET(flags, LK_DOWNGRADE)) {
371 		rw_downgrade(&vip->vi_lock);
372 	} else if (ISSET(flags, LK_UPGRADE)) {
373 		KASSERT(ISSET(flags, LK_NOWAIT));
374 		if (!rw_tryupgrade(&vip->vi_lock)) {
375 			return EBUSY;
376 		}
377 	} else if ((flags & (LK_EXCLUSIVE | LK_SHARED)) != 0) {
378 		op = (ISSET(flags, LK_EXCLUSIVE) ? RW_WRITER : RW_READER);
379 		if (ISSET(flags, LK_NOWAIT)) {
380 			if (!rw_tryenter(&vip->vi_lock, op))
381 				return EBUSY;
382 		} else {
383 			rw_enter(&vip->vi_lock, op);
384 		}
385 	}
386 	VSTATE_ASSERT_UNLOCKED(vp, VS_ACTIVE);
387 	return 0;
388 }
389 
390 /*
391  * Unlock the node.
392  */
393 int
394 genfs_unlock(void *v)
395 {
396 	struct vop_unlock_args /* {
397 		struct vnode *a_vp;
398 	} */ *ap = v;
399 	vnode_t *vp = ap->a_vp;
400 	vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
401 
402 	rw_exit(&vip->vi_lock);
403 
404 	return 0;
405 }
406 
407 /*
408  * Return whether or not the node is locked.
409  */
410 int
411 genfs_islocked(void *v)
412 {
413 	struct vop_islocked_args /* {
414 		struct vnode *a_vp;
415 	} */ *ap = v;
416 	vnode_t *vp = ap->a_vp;
417 	vnode_impl_t *vip = VNODE_TO_VIMPL(vp);
418 
419 	if (rw_write_held(&vip->vi_lock))
420 		return LK_EXCLUSIVE;
421 
422 	if (rw_read_held(&vip->vi_lock))
423 		return LK_SHARED;
424 
425 	return 0;
426 }
427 
428 /*
429  * Stubs to use when there is no locking to be done on the underlying object.
430  */
431 int
432 genfs_nolock(void *v)
433 {
434 
435 	return (0);
436 }
437 
438 int
439 genfs_nounlock(void *v)
440 {
441 
442 	return (0);
443 }
444 
445 int
446 genfs_noislocked(void *v)
447 {
448 
449 	return (0);
450 }
451 
452 int
453 genfs_mmap(void *v)
454 {
455 
456 	return (0);
457 }
458 
459 /*
460  * VOP_PUTPAGES() for vnodes which never have pages.
461  */
462 
463 int
464 genfs_null_putpages(void *v)
465 {
466 	struct vop_putpages_args /* {
467 		struct vnode *a_vp;
468 		voff_t a_offlo;
469 		voff_t a_offhi;
470 		int a_flags;
471 	} */ *ap = v;
472 	struct vnode *vp = ap->a_vp;
473 
474 	KASSERT(vp->v_uobj.uo_npages == 0);
475 	rw_exit(vp->v_uobj.vmobjlock);
476 	return (0);
477 }
478 
479 void
480 genfs_node_init(struct vnode *vp, const struct genfs_ops *ops)
481 {
482 	struct genfs_node *gp = VTOG(vp);
483 
484 	rw_init(&gp->g_glock);
485 	gp->g_op = ops;
486 }
487 
488 void
489 genfs_node_destroy(struct vnode *vp)
490 {
491 	struct genfs_node *gp = VTOG(vp);
492 
493 	rw_destroy(&gp->g_glock);
494 }
495 
496 void
497 genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
498 {
499 	int bsize;
500 
501 	bsize = 1 << vp->v_mount->mnt_fs_bshift;
502 	*eobp = (size + bsize - 1) & ~(bsize - 1);
503 }
504 
505 static void
506 filt_genfsdetach(struct knote *kn)
507 {
508 	struct vnode *vp = (struct vnode *)kn->kn_hook;
509 
510 	mutex_enter(vp->v_interlock);
511 	SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext);
512 	mutex_exit(vp->v_interlock);
513 }
514 
515 static int
516 filt_genfsread(struct knote *kn, long hint)
517 {
518 	struct vnode *vp = (struct vnode *)kn->kn_hook;
519 	int rv;
520 
521 	/*
522 	 * filesystem is gone, so set the EOF flag and schedule
523 	 * the knote for deletion.
524 	 */
525 	switch (hint) {
526 	case NOTE_REVOKE:
527 		KASSERT(mutex_owned(vp->v_interlock));
528 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
529 		return (1);
530 	case 0:
531 		mutex_enter(vp->v_interlock);
532 		kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
533 		rv = (kn->kn_data != 0);
534 		mutex_exit(vp->v_interlock);
535 		return rv;
536 	default:
537 		KASSERT(mutex_owned(vp->v_interlock));
538 		kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
539 		return (kn->kn_data != 0);
540 	}
541 }
542 
543 static int
544 filt_genfswrite(struct knote *kn, long hint)
545 {
546 	struct vnode *vp = (struct vnode *)kn->kn_hook;
547 
548 	/*
549 	 * filesystem is gone, so set the EOF flag and schedule
550 	 * the knote for deletion.
551 	 */
552 	switch (hint) {
553 	case NOTE_REVOKE:
554 		KASSERT(mutex_owned(vp->v_interlock));
555 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
556 		return (1);
557 	case 0:
558 		mutex_enter(vp->v_interlock);
559 		kn->kn_data = 0;
560 		mutex_exit(vp->v_interlock);
561 		return 1;
562 	default:
563 		KASSERT(mutex_owned(vp->v_interlock));
564 		kn->kn_data = 0;
565 		return 1;
566 	}
567 }
568 
569 static int
570 filt_genfsvnode(struct knote *kn, long hint)
571 {
572 	struct vnode *vp = (struct vnode *)kn->kn_hook;
573 	int fflags;
574 
575 	switch (hint) {
576 	case NOTE_REVOKE:
577 		KASSERT(mutex_owned(vp->v_interlock));
578 		kn->kn_flags |= EV_EOF;
579 		if ((kn->kn_sfflags & hint) != 0)
580 			kn->kn_fflags |= hint;
581 		return (1);
582 	case 0:
583 		mutex_enter(vp->v_interlock);
584 		fflags = kn->kn_fflags;
585 		mutex_exit(vp->v_interlock);
586 		break;
587 	default:
588 		KASSERT(mutex_owned(vp->v_interlock));
589 		if ((kn->kn_sfflags & hint) != 0)
590 			kn->kn_fflags |= hint;
591 		fflags = kn->kn_fflags;
592 		break;
593 	}
594 
595 	return (fflags != 0);
596 }
597 
598 static const struct filterops genfsread_filtops = {
599 	.f_isfd = 1,
600 	.f_attach = NULL,
601 	.f_detach = filt_genfsdetach,
602 	.f_event = filt_genfsread,
603 };
604 
605 static const struct filterops genfswrite_filtops = {
606 	.f_isfd = 1,
607 	.f_attach = NULL,
608 	.f_detach = filt_genfsdetach,
609 	.f_event = filt_genfswrite,
610 };
611 
612 static const struct filterops genfsvnode_filtops = {
613 	.f_isfd = 1,
614 	.f_attach = NULL,
615 	.f_detach = filt_genfsdetach,
616 	.f_event = filt_genfsvnode,
617 };
618 
619 int
620 genfs_kqfilter(void *v)
621 {
622 	struct vop_kqfilter_args /* {
623 		struct vnode	*a_vp;
624 		struct knote	*a_kn;
625 	} */ *ap = v;
626 	struct vnode *vp;
627 	struct knote *kn;
628 
629 	vp = ap->a_vp;
630 	kn = ap->a_kn;
631 	switch (kn->kn_filter) {
632 	case EVFILT_READ:
633 		kn->kn_fop = &genfsread_filtops;
634 		break;
635 	case EVFILT_WRITE:
636 		kn->kn_fop = &genfswrite_filtops;
637 		break;
638 	case EVFILT_VNODE:
639 		kn->kn_fop = &genfsvnode_filtops;
640 		break;
641 	default:
642 		return (EINVAL);
643 	}
644 
645 	kn->kn_hook = vp;
646 
647 	mutex_enter(vp->v_interlock);
648 	SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext);
649 	mutex_exit(vp->v_interlock);
650 
651 	return (0);
652 }
653 
654 void
655 genfs_node_wrlock(struct vnode *vp)
656 {
657 	struct genfs_node *gp = VTOG(vp);
658 
659 	rw_enter(&gp->g_glock, RW_WRITER);
660 }
661 
662 void
663 genfs_node_rdlock(struct vnode *vp)
664 {
665 	struct genfs_node *gp = VTOG(vp);
666 
667 	rw_enter(&gp->g_glock, RW_READER);
668 }
669 
670 int
671 genfs_node_rdtrylock(struct vnode *vp)
672 {
673 	struct genfs_node *gp = VTOG(vp);
674 
675 	return rw_tryenter(&gp->g_glock, RW_READER);
676 }
677 
678 void
679 genfs_node_unlock(struct vnode *vp)
680 {
681 	struct genfs_node *gp = VTOG(vp);
682 
683 	rw_exit(&gp->g_glock);
684 }
685 
686 int
687 genfs_node_wrlocked(struct vnode *vp)
688 {
689 	struct genfs_node *gp = VTOG(vp);
690 
691 	return rw_write_held(&gp->g_glock);
692 }
693 
694 static int
695 groupmember(gid_t gid, kauth_cred_t cred)
696 {
697 	int ismember;
698 	int error = kauth_cred_ismember_gid(cred, gid, &ismember);
699 	if (error)
700 		return error;
701 	if (kauth_cred_getegid(cred) == gid || ismember)
702 		return 0;
703 	return -1;
704 }
705 
706 /*
707  * Common filesystem object access control check routine.  Accepts a
708  * vnode, cred, uid, gid, mode, acl, requested access mode.
709  * Returns 0 on success, or an errno on failure.
710  */
711 int
712 genfs_can_access(vnode_t *vp, kauth_cred_t cred, uid_t file_uid, gid_t file_gid,
713     mode_t file_mode, struct acl *acl, accmode_t accmode)
714 {
715 	accmode_t dac_granted;
716 	int error;
717 
718 	KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0);
719 	KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE));
720 
721 	/*
722 	 * Look for a normal, non-privileged way to access the file/directory
723 	 * as requested.  If it exists, go with that.
724 	 */
725 
726 	dac_granted = 0;
727 
728 	/* Check the owner. */
729 	if (kauth_cred_geteuid(cred) == file_uid) {
730 		dac_granted |= VADMIN;
731 		if (file_mode & S_IXUSR)
732 			dac_granted |= VEXEC;
733 		if (file_mode & S_IRUSR)
734 			dac_granted |= VREAD;
735 		if (file_mode & S_IWUSR)
736 			dac_granted |= (VWRITE | VAPPEND);
737 
738 		goto privchk;
739 	}
740 
741 	/* Otherwise, check the groups (first match) */
742 	/* Otherwise, check the groups. */
743 	error = groupmember(file_gid, cred);
744 	if (error > 0)
745 		return error;
746 	if (error == 0) {
747 		if (file_mode & S_IXGRP)
748 			dac_granted |= VEXEC;
749 		if (file_mode & S_IRGRP)
750 			dac_granted |= VREAD;
751 		if (file_mode & S_IWGRP)
752 			dac_granted |= (VWRITE | VAPPEND);
753 
754 		goto privchk;
755 	}
756 
757 	/* Otherwise, check everyone else. */
758 	if (file_mode & S_IXOTH)
759 		dac_granted |= VEXEC;
760 	if (file_mode & S_IROTH)
761 		dac_granted |= VREAD;
762 	if (file_mode & S_IWOTH)
763 		dac_granted |= (VWRITE | VAPPEND);
764 
765 privchk:
766 	if ((accmode & dac_granted) == accmode)
767 		return 0;
768 
769 	return (accmode & VADMIN) ? EPERM : EACCES;
770 }
771 
772 /*
773  * Implement a version of genfs_can_access() that understands POSIX.1e ACL
774  * semantics;
775  * the access ACL has already been prepared for evaluation by the file system
776  * and is passed via 'uid', 'gid', and 'acl'.  Return 0 on success, else an
777  * errno value.
778  */
779 int
780 genfs_can_access_acl_posix1e(vnode_t *vp, kauth_cred_t cred, uid_t file_uid,
781     gid_t file_gid, mode_t file_mode, struct acl *acl, accmode_t accmode)
782 {
783 	struct acl_entry *acl_other, *acl_mask;
784 	accmode_t dac_granted;
785 	accmode_t acl_mask_granted;
786 	int group_matched, i;
787 	int error;
788 
789 	KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND)) == 0);
790 	KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE));
791 
792 	/*
793 	 * The owner matches if the effective uid associated with the
794 	 * credential matches that of the ACL_USER_OBJ entry.  While we're
795 	 * doing the first scan, also cache the location of the ACL_MASK and
796 	 * ACL_OTHER entries, preventing some future iterations.
797 	 */
798 	acl_mask = acl_other = NULL;
799 	for (i = 0; i < acl->acl_cnt; i++) {
800 		struct acl_entry *ae = &acl->acl_entry[i];
801 		switch (ae->ae_tag) {
802 		case ACL_USER_OBJ:
803 			if (kauth_cred_geteuid(cred) != file_uid)
804 				break;
805 			dac_granted = 0;
806 			dac_granted |= VADMIN;
807 			if (ae->ae_perm & ACL_EXECUTE)
808 				dac_granted |= VEXEC;
809 			if (ae->ae_perm & ACL_READ)
810 				dac_granted |= VREAD;
811 			if (ae->ae_perm & ACL_WRITE)
812 				dac_granted |= (VWRITE | VAPPEND);
813 			goto out;
814 
815 		case ACL_MASK:
816 			acl_mask = ae;
817 			break;
818 
819 		case ACL_OTHER:
820 			acl_other = ae;
821 			break;
822 
823 		default:
824 			break;
825 		}
826 	}
827 
828 	/*
829 	 * An ACL_OTHER entry should always exist in a valid access ACL.  If
830 	 * it doesn't, then generate a serious failure.	 For now, this means
831 	 * a debugging message and EPERM, but in the future should probably
832 	 * be a panic.
833 	 */
834 	if (acl_other == NULL) {
835 		/*
836 		 * XXX This should never happen
837 		 */
838 		printf("%s: ACL_OTHER missing\n", __func__);
839 		return EPERM;
840 	}
841 
842 	/*
843 	 * Checks against ACL_USER, ACL_GROUP_OBJ, and ACL_GROUP fields are
844 	 * masked by an ACL_MASK entry, if any.	 As such, first identify the
845 	 * ACL_MASK field, then iterate through identifying potential user
846 	 * matches, then group matches.	 If there is no ACL_MASK, assume that
847 	 * the mask allows all requests to succeed.
848 	 */
849 	if (acl_mask != NULL) {
850 		acl_mask_granted = 0;
851 		if (acl_mask->ae_perm & ACL_EXECUTE)
852 			acl_mask_granted |= VEXEC;
853 		if (acl_mask->ae_perm & ACL_READ)
854 			acl_mask_granted |= VREAD;
855 		if (acl_mask->ae_perm & ACL_WRITE)
856 			acl_mask_granted |= (VWRITE | VAPPEND);
857 	} else
858 		acl_mask_granted = VEXEC | VREAD | VWRITE | VAPPEND;
859 
860 	/*
861 	 * Check ACL_USER ACL entries.	There will either be one or no
862 	 * matches; if there is one, we accept or rejected based on the
863 	 * match; otherwise, we continue on to groups.
864 	 */
865 	for (i = 0; i < acl->acl_cnt; i++) {
866 		struct acl_entry *ae = &acl->acl_entry[i];
867 		switch (ae->ae_tag) {
868 		case ACL_USER:
869 			if (kauth_cred_geteuid(cred) != ae->ae_id)
870 				break;
871 			dac_granted = 0;
872 			if (ae->ae_perm & ACL_EXECUTE)
873 				dac_granted |= VEXEC;
874 			if (ae->ae_perm & ACL_READ)
875 				dac_granted |= VREAD;
876 			if (ae->ae_perm & ACL_WRITE)
877 				dac_granted |= (VWRITE | VAPPEND);
878 			dac_granted &= acl_mask_granted;
879 			goto out;
880 		}
881 	}
882 
883 	/*
884 	 * Group match is best-match, not first-match, so find a "best"
885 	 * match.  Iterate across, testing each potential group match.	Make
886 	 * sure we keep track of whether we found a match or not, so that we
887 	 * know if we should try again with any available privilege, or if we
888 	 * should move on to ACL_OTHER.
889 	 */
890 	group_matched = 0;
891 	for (i = 0; i < acl->acl_cnt; i++) {
892 		struct acl_entry *ae = &acl->acl_entry[i];
893 		switch (ae->ae_tag) {
894 		case ACL_GROUP_OBJ:
895 			error = groupmember(file_gid, cred);
896 			if (error > 0)
897 				return error;
898 			if (error)
899 				break;
900 			dac_granted = 0;
901 			if (ae->ae_perm & ACL_EXECUTE)
902 				dac_granted |= VEXEC;
903 			if (ae->ae_perm & ACL_READ)
904 				dac_granted |= VREAD;
905 			if (ae->ae_perm & ACL_WRITE)
906 				dac_granted |= (VWRITE | VAPPEND);
907 			dac_granted  &= acl_mask_granted;
908 
909 			if ((accmode & dac_granted) == accmode)
910 				return 0;
911 
912 			group_matched = 1;
913 			break;
914 
915 		case ACL_GROUP:
916 			error = groupmember(ae->ae_id, cred);
917 			if (error > 0)
918 				return error;
919 			if (error)
920 				break;
921 			dac_granted = 0;
922 			if (ae->ae_perm & ACL_EXECUTE)
923 				dac_granted |= VEXEC;
924 			if (ae->ae_perm & ACL_READ)
925 				dac_granted |= VREAD;
926 			if (ae->ae_perm & ACL_WRITE)
927 				dac_granted |= (VWRITE | VAPPEND);
928 			dac_granted  &= acl_mask_granted;
929 
930 			if ((accmode & dac_granted) == accmode)
931 				return 0;
932 
933 			group_matched = 1;
934 			break;
935 
936 		default:
937 			break;
938 		}
939 	}
940 
941 	if (group_matched == 1) {
942 		/*
943 		 * There was a match, but it did not grant rights via pure
944 		 * DAC.	 Try again, this time with privilege.
945 		 */
946 		for (i = 0; i < acl->acl_cnt; i++) {
947 			struct acl_entry *ae = &acl->acl_entry[i];
948 			switch (ae->ae_tag) {
949 			case ACL_GROUP_OBJ:
950 				error = groupmember(file_gid, cred);
951 				if (error > 0)
952 					return error;
953 				if (error)
954 					break;
955 				dac_granted = 0;
956 				if (ae->ae_perm & ACL_EXECUTE)
957 					dac_granted |= VEXEC;
958 				if (ae->ae_perm & ACL_READ)
959 					dac_granted |= VREAD;
960 				if (ae->ae_perm & ACL_WRITE)
961 					dac_granted |= (VWRITE | VAPPEND);
962 				dac_granted &= acl_mask_granted;
963 				goto out;
964 
965 			case ACL_GROUP:
966 				error = groupmember(ae->ae_id, cred);
967 				if (error > 0)
968 					return error;
969 				if (error)
970 					break;
971 				dac_granted = 0;
972 				if (ae->ae_perm & ACL_EXECUTE)
973 				dac_granted |= VEXEC;
974 				if (ae->ae_perm & ACL_READ)
975 					dac_granted |= VREAD;
976 				if (ae->ae_perm & ACL_WRITE)
977 					dac_granted |= (VWRITE | VAPPEND);
978 				dac_granted &= acl_mask_granted;
979 
980 				goto out;
981 			default:
982 				break;
983 			}
984 		}
985 		/*
986 		 * Even with privilege, group membership was not sufficient.
987 		 * Return failure.
988 		 */
989 		dac_granted = 0;
990 		goto out;
991 	}
992 
993 	/*
994 	 * Fall back on ACL_OTHER.  ACL_MASK is not applied to ACL_OTHER.
995 	 */
996 	dac_granted = 0;
997 	if (acl_other->ae_perm & ACL_EXECUTE)
998 		dac_granted |= VEXEC;
999 	if (acl_other->ae_perm & ACL_READ)
1000 		dac_granted |= VREAD;
1001 	if (acl_other->ae_perm & ACL_WRITE)
1002 		dac_granted |= (VWRITE | VAPPEND);
1003 
1004 out:
1005 	if ((accmode & dac_granted) == accmode)
1006 		return 0;
1007 	return (accmode & VADMIN) ? EPERM : EACCES;
1008 }
1009 
1010 static struct {
1011 	accmode_t accmode;
1012 	int mask;
1013 } accmode2mask[] = {
1014 	{ VREAD, ACL_READ_DATA },
1015 	{ VWRITE, ACL_WRITE_DATA },
1016 	{ VAPPEND, ACL_APPEND_DATA },
1017 	{ VEXEC, ACL_EXECUTE },
1018 	{ VREAD_NAMED_ATTRS, ACL_READ_NAMED_ATTRS },
1019 	{ VWRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS },
1020 	{ VDELETE_CHILD, ACL_DELETE_CHILD },
1021 	{ VREAD_ATTRIBUTES, ACL_READ_ATTRIBUTES },
1022 	{ VWRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES },
1023 	{ VDELETE, ACL_DELETE },
1024 	{ VREAD_ACL, ACL_READ_ACL },
1025 	{ VWRITE_ACL, ACL_WRITE_ACL },
1026 	{ VWRITE_OWNER, ACL_WRITE_OWNER },
1027 	{ VSYNCHRONIZE, ACL_SYNCHRONIZE },
1028 	{ 0, 0 },
1029 };
1030 
1031 static int
1032 _access_mask_from_accmode(accmode_t accmode)
1033 {
1034 	int access_mask = 0, i;
1035 
1036 	for (i = 0; accmode2mask[i].accmode != 0; i++) {
1037 		if (accmode & accmode2mask[i].accmode)
1038 			access_mask |= accmode2mask[i].mask;
1039 	}
1040 
1041 	/*
1042 	 * VAPPEND is just a modifier for VWRITE; if the caller asked
1043 	 * for 'VAPPEND | VWRITE', we want to check for ACL_APPEND_DATA only.
1044 	 */
1045 	if (access_mask & ACL_APPEND_DATA)
1046 		access_mask &= ~ACL_WRITE_DATA;
1047 
1048 	return (access_mask);
1049 }
1050 
1051 /*
1052  * Return 0, iff access is allowed, 1 otherwise.
1053  */
1054 static int
1055 _acl_denies(const struct acl *aclp, int access_mask, kauth_cred_t cred,
1056     int file_uid, int file_gid, int *denied_explicitly)
1057 {
1058 	int i, error;
1059 	const struct acl_entry *ae;
1060 
1061 	if (denied_explicitly != NULL)
1062 		*denied_explicitly = 0;
1063 
1064 	KASSERT(aclp->acl_cnt <= ACL_MAX_ENTRIES);
1065 
1066 	for (i = 0; i < aclp->acl_cnt; i++) {
1067 		ae = &(aclp->acl_entry[i]);
1068 
1069 		if (ae->ae_entry_type != ACL_ENTRY_TYPE_ALLOW &&
1070 		    ae->ae_entry_type != ACL_ENTRY_TYPE_DENY)
1071 			continue;
1072 		if (ae->ae_flags & ACL_ENTRY_INHERIT_ONLY)
1073 			continue;
1074 		switch (ae->ae_tag) {
1075 		case ACL_USER_OBJ:
1076 			if (kauth_cred_geteuid(cred) != file_uid)
1077 				continue;
1078 			break;
1079 		case ACL_USER:
1080 			if (kauth_cred_geteuid(cred) != ae->ae_id)
1081 				continue;
1082 			break;
1083 		case ACL_GROUP_OBJ:
1084 			error = groupmember(file_gid, cred);
1085 			if (error > 0)
1086 				return error;
1087 			if (error != 0)
1088 				continue;
1089 			break;
1090 		case ACL_GROUP:
1091 			error = groupmember(ae->ae_id, cred);
1092 			if (error > 0)
1093 				return error;
1094 			if (error != 0)
1095 				continue;
1096 			break;
1097 		default:
1098 			KASSERT(ae->ae_tag == ACL_EVERYONE);
1099 		}
1100 
1101 		if (ae->ae_entry_type == ACL_ENTRY_TYPE_DENY) {
1102 			if (ae->ae_perm & access_mask) {
1103 				if (denied_explicitly != NULL)
1104 					*denied_explicitly = 1;
1105 				return (1);
1106 			}
1107 		}
1108 
1109 		access_mask &= ~(ae->ae_perm);
1110 		if (access_mask == 0)
1111 			return (0);
1112 	}
1113 
1114 	if (access_mask == 0)
1115 		return (0);
1116 
1117 	return (1);
1118 }
1119 
1120 int
1121 genfs_can_access_acl_nfs4(vnode_t *vp, kauth_cred_t cred, uid_t file_uid,
1122     gid_t file_gid, mode_t file_mode, struct acl *aclp, accmode_t accmode)
1123 {
1124 	int denied, explicitly_denied, access_mask, is_directory,
1125 	    must_be_owner = 0;
1126 	file_mode = 0;
1127 
1128 	KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND |
1129 	    VEXPLICIT_DENY | VREAD_NAMED_ATTRS | VWRITE_NAMED_ATTRS |
1130 	    VDELETE_CHILD | VREAD_ATTRIBUTES | VWRITE_ATTRIBUTES | VDELETE |
1131 	    VREAD_ACL | VWRITE_ACL | VWRITE_OWNER | VSYNCHRONIZE)) == 0);
1132 	KASSERT((accmode & VAPPEND) == 0 || (accmode & VWRITE));
1133 
1134 	if (accmode & VADMIN)
1135 		must_be_owner = 1;
1136 
1137 	/*
1138 	 * Ignore VSYNCHRONIZE permission.
1139 	 */
1140 	accmode &= ~VSYNCHRONIZE;
1141 
1142 	access_mask = _access_mask_from_accmode(accmode);
1143 
1144 	if (vp && vp->v_type == VDIR)
1145 		is_directory = 1;
1146 	else
1147 		is_directory = 0;
1148 
1149 	/*
1150 	 * File owner is always allowed to read and write the ACL
1151 	 * and basic attributes.  This is to prevent a situation
1152 	 * where user would change ACL in a way that prevents him
1153 	 * from undoing the change.
1154 	 */
1155 	if (kauth_cred_geteuid(cred) == file_uid)
1156 		access_mask &= ~(ACL_READ_ACL | ACL_WRITE_ACL |
1157 		    ACL_READ_ATTRIBUTES | ACL_WRITE_ATTRIBUTES);
1158 
1159 	/*
1160 	 * Ignore append permission for regular files; use write
1161 	 * permission instead.
1162 	 */
1163 	if (!is_directory && (access_mask & ACL_APPEND_DATA)) {
1164 		access_mask &= ~ACL_APPEND_DATA;
1165 		access_mask |= ACL_WRITE_DATA;
1166 	}
1167 
1168 	denied = _acl_denies(aclp, access_mask, cred, file_uid, file_gid,
1169 	    &explicitly_denied);
1170 
1171 	if (must_be_owner) {
1172 		if (kauth_cred_geteuid(cred) != file_uid)
1173 			denied = EPERM;
1174 	}
1175 
1176 	/*
1177 	 * For VEXEC, ensure that at least one execute bit is set for
1178 	 * non-directories. We have to check the mode here to stay
1179 	 * consistent with execve(2). See the test in
1180 	 * exec_check_permissions().
1181 	 */
1182 	__acl_nfs4_sync_mode_from_acl(&file_mode, aclp);
1183 	if (!denied && !is_directory && (accmode & VEXEC) &&
1184 	    (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)
1185 		denied = EACCES;
1186 
1187 	if (!denied)
1188 		return (0);
1189 
1190 	/*
1191 	 * Access failed.  Iff it was not denied explicitly and
1192 	 * VEXPLICIT_DENY flag was specified, allow access.
1193 	 */
1194 	if ((accmode & VEXPLICIT_DENY) && explicitly_denied == 0)
1195 		return (0);
1196 
1197 	accmode &= ~VEXPLICIT_DENY;
1198 
1199 	if (accmode & (VADMIN_PERMS | VDELETE_CHILD | VDELETE))
1200 		denied = EPERM;
1201 	else
1202 		denied = EACCES;
1203 
1204 	return (denied);
1205 }
1206 
1207 /*
1208  * Common routine to check if chmod() is allowed.
1209  *
1210  * Policy:
1211  *   - You must own the file, and
1212  *     - You must not set the "sticky" bit (meaningless, see chmod(2))
1213  *     - You must be a member of the group if you're trying to set the
1214  *	 SGIDf bit
1215  *
1216  * vp - vnode of the file-system object
1217  * cred - credentials of the invoker
1218  * cur_uid, cur_gid - current uid/gid of the file-system object
1219  * new_mode - new mode for the file-system object
1220  *
1221  * Returns 0 if the change is allowed, or an error value otherwise.
1222  */
1223 int
1224 genfs_can_chmod(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid,
1225     gid_t cur_gid, mode_t new_mode)
1226 {
1227 	int error;
1228 
1229 	/*
1230 	 * To modify the permissions on a file, must possess VADMIN
1231 	 * for that file.
1232 	 */
1233 	if ((error = VOP_ACCESSX(vp, VWRITE_ACL, cred)) != 0)
1234 		return (error);
1235 
1236 	/*
1237 	 * Unprivileged users can't set the sticky bit on files.
1238 	 */
1239 	if ((vp->v_type != VDIR) && (new_mode & S_ISTXT))
1240 		return (EFTYPE);
1241 
1242 	/*
1243 	 * If the invoker is trying to set the SGID bit on the file,
1244 	 * check group membership.
1245 	 */
1246 	if (new_mode & S_ISGID) {
1247 		int ismember;
1248 
1249 		error = kauth_cred_ismember_gid(cred, cur_gid,
1250 		    &ismember);
1251 		if (error || !ismember)
1252 			return (EPERM);
1253 	}
1254 
1255 	/*
1256 	 * Deny setting setuid if we are not the file owner.
1257 	 */
1258 	if ((new_mode & S_ISUID) && cur_uid != kauth_cred_geteuid(cred))
1259 		return (EPERM);
1260 
1261 	return (0);
1262 }
1263 
1264 /*
1265  * Common routine to check if chown() is allowed.
1266  *
1267  * Policy:
1268  *   - You must own the file, and
1269  *     - You must not try to change ownership, and
1270  *     - You must be member of the new group
1271  *
1272  * vp - vnode
1273  * cred - credentials of the invoker
1274  * cur_uid, cur_gid - current uid/gid of the file-system object
1275  * new_uid, new_gid - target uid/gid of the file-system object
1276  *
1277  * Returns 0 if the change is allowed, or an error value otherwise.
1278  */
1279 int
1280 genfs_can_chown(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid,
1281     gid_t cur_gid, uid_t new_uid, gid_t new_gid)
1282 {
1283 	int error, ismember;
1284 
1285 	/*
1286 	 * To modify the ownership of a file, must possess VADMIN for that
1287 	 * file.
1288 	 */
1289 	if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred)) != 0)
1290 		return (error);
1291 
1292 	/*
1293 	 * You can only change ownership of a file if:
1294 	 * You own the file and...
1295 	 */
1296 	if (kauth_cred_geteuid(cred) == cur_uid) {
1297 		/*
1298 		 * You don't try to change ownership, and...
1299 		 */
1300 		if (new_uid != cur_uid)
1301 			return (EPERM);
1302 
1303 		/*
1304 		 * You don't try to change group (no-op), or...
1305 		 */
1306 		if (new_gid == cur_gid)
1307 			return (0);
1308 
1309 		/*
1310 		 * Your effective gid is the new gid, or...
1311 		 */
1312 		if (kauth_cred_getegid(cred) == new_gid)
1313 			return (0);
1314 
1315 		/*
1316 		 * The new gid is one you're a member of.
1317 		 */
1318 		ismember = 0;
1319 		error = kauth_cred_ismember_gid(cred, new_gid,
1320 		    &ismember);
1321 		if (!error && ismember)
1322 			return (0);
1323 	}
1324 
1325 	return (EPERM);
1326 }
1327 
1328 int
1329 genfs_can_chtimes(vnode_t *vp, kauth_cred_t cred, uid_t owner_uid,
1330     u_int vaflags)
1331 {
1332 	int error;
1333 	/*
1334 	 * Grant permission if the caller is the owner of the file, or
1335 	 * the super-user, or has ACL_WRITE_ATTRIBUTES permission on
1336 	 * on the file.	 If the time pointer is null, then write
1337 	 * permission on the file is also sufficient.
1338 	 *
1339 	 * From NFSv4.1, draft 21, 6.2.1.3.1, Discussion of Mask Attributes:
1340 	 * A user having ACL_WRITE_DATA or ACL_WRITE_ATTRIBUTES
1341 	 * will be allowed to set the times [..] to the current
1342 	 * server time.
1343 	 */
1344 	if ((error = VOP_ACCESSX(vp, VWRITE_ATTRIBUTES, cred)) != 0)
1345 		return (vaflags & VA_UTIMES_NULL) == 0 ? EPERM : EACCES;
1346 
1347 	/* Must be owner, or... */
1348 	if (kauth_cred_geteuid(cred) == owner_uid)
1349 		return (0);
1350 
1351 	/* set the times to the current time, and... */
1352 	if ((vaflags & VA_UTIMES_NULL) == 0)
1353 		return (EPERM);
1354 
1355 	/* have write access. */
1356 	error = VOP_ACCESS(vp, VWRITE, cred);
1357 	if (error)
1358 		return (error);
1359 
1360 	return (0);
1361 }
1362 
1363 /*
1364  * Common routine to check if chflags() is allowed.
1365  *
1366  * Policy:
1367  *   - You must own the file, and
1368  *   - You must not change system flags, and
1369  *   - You must not change flags on character/block devices.
1370  *
1371  * vp - vnode
1372  * cred - credentials of the invoker
1373  * owner_uid - uid of the file-system object
1374  * changing_sysflags - true if the invoker wants to change system flags
1375  */
1376 int
1377 genfs_can_chflags(vnode_t *vp, kauth_cred_t cred,
1378      uid_t owner_uid, bool changing_sysflags)
1379 {
1380 
1381 	/* The user must own the file. */
1382 	if (kauth_cred_geteuid(cred) != owner_uid) {
1383 		return EPERM;
1384 	}
1385 
1386 	if (changing_sysflags) {
1387 		return EPERM;
1388 	}
1389 
1390 	/*
1391 	 * Unprivileged users cannot change the flags on devices, even if they
1392 	 * own them.
1393 	 */
1394 	if (vp->v_type == VCHR || vp->v_type == VBLK) {
1395 		return EPERM;
1396 	}
1397 
1398 	return 0;
1399 }
1400 
1401 /*
1402  * Common "sticky" policy.
1403  *
1404  * When a directory is "sticky" (as determined by the caller), this
1405  * function may help implementing the following policy:
1406  * - Renaming a file in it is only possible if the user owns the directory
1407  *   or the file being renamed.
1408  * - Deleting a file from it is only possible if the user owns the
1409  *   directory or the file being deleted.
1410  */
1411 int
1412 genfs_can_sticky(vnode_t *vp, kauth_cred_t cred, uid_t dir_uid, uid_t file_uid)
1413 {
1414 	if (kauth_cred_geteuid(cred) != dir_uid &&
1415 	    kauth_cred_geteuid(cred) != file_uid)
1416 		return EPERM;
1417 
1418 	return 0;
1419 }
1420 
1421 int
1422 genfs_can_extattr(vnode_t *vp, kauth_cred_t cred, accmode_t accmode,
1423     int attrnamespace)
1424 {
1425 	/*
1426 	 * Kernel-invoked always succeeds.
1427 	 */
1428 	if (cred == NOCRED)
1429 		return 0;
1430 
1431 	switch (attrnamespace) {
1432 	case EXTATTR_NAMESPACE_SYSTEM:
1433 		return kauth_authorize_system(cred, KAUTH_SYSTEM_FS_EXTATTR,
1434 		    0, vp->v_mount, NULL, NULL);
1435 	case EXTATTR_NAMESPACE_USER:
1436 		return VOP_ACCESS(vp, accmode, cred);
1437 	default:
1438 		return EPERM;
1439 	}
1440 }
1441 
1442 int
1443 genfs_access(void *v)
1444 {
1445 	struct vop_access_args *ap = v;
1446 
1447 	KASSERT((ap->a_accmode & ~(VEXEC | VWRITE | VREAD | VADMIN |
1448 	    VAPPEND)) == 0);
1449 
1450 	return VOP_ACCESSX(ap->a_vp, ap->a_accmode, ap->a_cred);
1451 }
1452 
1453 int
1454 genfs_accessx(void *v)
1455 {
1456 	struct vop_accessx_args *ap = v;
1457 	int error;
1458 	accmode_t accmode = ap->a_accmode;
1459 	error = vfs_unixify_accmode(&accmode);
1460 	if (error != 0)
1461 		return error;
1462 
1463 	if (accmode == 0)
1464 		return 0;
1465 
1466 	return VOP_ACCESS(ap->a_vp, accmode, ap->a_cred);
1467 }
1468 
1469 /*
1470  * genfs_pathconf:
1471  *
1472  * Standard implementation of POSIX pathconf, to get information about limits
1473  * for a filesystem.
1474  * Override per filesystem for the case where the filesystem has smaller
1475  * limits.
1476  */
1477 int
1478 genfs_pathconf(void *v)
1479 {
1480 	struct vop_pathconf_args *ap = v;
1481 
1482 	switch (ap->a_name) {
1483 	case _PC_PATH_MAX:
1484 		*ap->a_retval = PATH_MAX;
1485 		return 0;
1486 	case _PC_ACL_EXTENDED:
1487 	case _PC_ACL_NFS4:
1488 		*ap->a_retval = 0;
1489 		return 0;
1490 	default:
1491 		return EINVAL;
1492 	}
1493 }
1494