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