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