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