Home | History | Annotate | Line # | Download | only in genfs
genfs_vnops.c revision 1.209
      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