xref: /openbsd-src/sys/nfs/nfs_srvsubs.c (revision 8d80561b3414d96641f904d5806a441a772c963c)
1*8d80561bSjsg /*	$OpenBSD: nfs_srvsubs.c,v 1.2 2024/09/18 05:21:19 jsg Exp $	*/
2d2b6e45eSjsg /*	$NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $	*/
3d2b6e45eSjsg 
4d2b6e45eSjsg /*
5d2b6e45eSjsg  * Copyright (c) 1989, 1993
6d2b6e45eSjsg  *	The Regents of the University of California.  All rights reserved.
7d2b6e45eSjsg  *
8d2b6e45eSjsg  * This code is derived from software contributed to Berkeley by
9d2b6e45eSjsg  * Rick Macklem at The University of Guelph.
10d2b6e45eSjsg  *
11d2b6e45eSjsg  * Redistribution and use in source and binary forms, with or without
12d2b6e45eSjsg  * modification, are permitted provided that the following conditions
13d2b6e45eSjsg  * are met:
14d2b6e45eSjsg  * 1. Redistributions of source code must retain the above copyright
15d2b6e45eSjsg  *    notice, this list of conditions and the following disclaimer.
16d2b6e45eSjsg  * 2. Redistributions in binary form must reproduce the above copyright
17d2b6e45eSjsg  *    notice, this list of conditions and the following disclaimer in the
18d2b6e45eSjsg  *    documentation and/or other materials provided with the distribution.
19d2b6e45eSjsg  * 3. Neither the name of the University nor the names of its contributors
20d2b6e45eSjsg  *    may be used to endorse or promote products derived from this software
21d2b6e45eSjsg  *    without specific prior written permission.
22d2b6e45eSjsg  *
23d2b6e45eSjsg  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24d2b6e45eSjsg  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25d2b6e45eSjsg  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26d2b6e45eSjsg  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27d2b6e45eSjsg  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28d2b6e45eSjsg  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29d2b6e45eSjsg  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30d2b6e45eSjsg  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31d2b6e45eSjsg  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32d2b6e45eSjsg  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33d2b6e45eSjsg  * SUCH DAMAGE.
34d2b6e45eSjsg  *
35d2b6e45eSjsg  *	@(#)nfs_subs.c	8.8 (Berkeley) 5/22/95
36d2b6e45eSjsg  */
37d2b6e45eSjsg 
38d2b6e45eSjsg 
39d2b6e45eSjsg /*
40d2b6e45eSjsg  * These functions support the nfsm_subs.h inline functions and help fiddle
41d2b6e45eSjsg  * mbuf chains for the nfs op functions. They do things such as creating the
42d2b6e45eSjsg  * rpc header and copying data between mbuf chains and uio lists.
43d2b6e45eSjsg  */
44d2b6e45eSjsg #include <sys/param.h>
45d2b6e45eSjsg #include <sys/systm.h>
46d2b6e45eSjsg #include <sys/mount.h>
47d2b6e45eSjsg #include <sys/vnode.h>
48d2b6e45eSjsg #include <sys/namei.h>
49d2b6e45eSjsg #include <sys/mbuf.h>
50d2b6e45eSjsg #include <sys/socket.h>
51d2b6e45eSjsg #include <sys/socketvar.h>
52d2b6e45eSjsg #include <sys/pool.h>
53d2b6e45eSjsg 
54d2b6e45eSjsg #include <nfs/rpcv2.h>
55d2b6e45eSjsg #include <nfs/nfsproto.h>
56d2b6e45eSjsg #include <nfs/nfs.h>
57d2b6e45eSjsg #include <nfs/xdr_subs.h>
58d2b6e45eSjsg #include <nfs/nfs_var.h>
59d2b6e45eSjsg #include <nfs/nfsm_subs.h>
60d2b6e45eSjsg 
61d2b6e45eSjsg #include <netinet/in.h>
62d2b6e45eSjsg 
63d2b6e45eSjsg /* Global vars */
64d2b6e45eSjsg extern u_int32_t nfs_false, nfs_true;
65d2b6e45eSjsg extern const nfstype nfsv2_type[9];
66d2b6e45eSjsg extern const nfstype nfsv3_type[9];
67d2b6e45eSjsg 
68d2b6e45eSjsg /*
69d2b6e45eSjsg  * Set up nameidata for a lookup() call and do it
70d2b6e45eSjsg  */
71d2b6e45eSjsg int
72d2b6e45eSjsg nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
73d2b6e45eSjsg     struct nfssvc_sock *slp, struct mbuf *nam, struct mbuf **mdp,
74d2b6e45eSjsg     caddr_t *dposp, struct vnode **retdirp, struct proc *p)
75d2b6e45eSjsg {
76d2b6e45eSjsg 	int i, rem;
77d2b6e45eSjsg 	struct mbuf *md;
78d2b6e45eSjsg 	char *fromcp, *tocp;
79d2b6e45eSjsg 	struct vnode *dp;
80d2b6e45eSjsg 	int error, rdonly;
81d2b6e45eSjsg 	struct componentname *cnp = &ndp->ni_cnd;
82d2b6e45eSjsg 
83d2b6e45eSjsg 	*retdirp = NULL;
84d2b6e45eSjsg 	cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
85d2b6e45eSjsg 	/*
86d2b6e45eSjsg 	 * Copy the name from the mbuf list to ndp->ni_pnbuf
87d2b6e45eSjsg 	 * and set the various ndp fields appropriately.
88d2b6e45eSjsg 	 */
89d2b6e45eSjsg 	fromcp = *dposp;
90d2b6e45eSjsg 	tocp = cnp->cn_pnbuf;
91d2b6e45eSjsg 	md = *mdp;
92d2b6e45eSjsg 	rem = mtod(md, caddr_t) + md->m_len - fromcp;
93d2b6e45eSjsg 	for (i = 0; i < len; i++) {
94d2b6e45eSjsg 		while (rem == 0) {
95d2b6e45eSjsg 			md = md->m_next;
96d2b6e45eSjsg 			if (md == NULL) {
97d2b6e45eSjsg 				error = EBADRPC;
98d2b6e45eSjsg 				goto out;
99d2b6e45eSjsg 			}
100d2b6e45eSjsg 			fromcp = mtod(md, caddr_t);
101d2b6e45eSjsg 			rem = md->m_len;
102d2b6e45eSjsg 		}
103d2b6e45eSjsg 		if (*fromcp == '\0' || *fromcp == '/') {
104d2b6e45eSjsg 			error = EACCES;
105d2b6e45eSjsg 			goto out;
106d2b6e45eSjsg 		}
107d2b6e45eSjsg 		*tocp++ = *fromcp++;
108d2b6e45eSjsg 		rem--;
109d2b6e45eSjsg 	}
110d2b6e45eSjsg 	*tocp = '\0';
111d2b6e45eSjsg 	*mdp = md;
112d2b6e45eSjsg 	*dposp = fromcp;
113d2b6e45eSjsg 	len = nfsm_padlen(len);
114d2b6e45eSjsg 	if (len > 0) {
115d2b6e45eSjsg 		if (rem >= len)
116d2b6e45eSjsg 			*dposp += len;
117d2b6e45eSjsg 		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
118d2b6e45eSjsg 			goto out;
119d2b6e45eSjsg 	}
120d2b6e45eSjsg 	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
121d2b6e45eSjsg 	cnp->cn_nameptr = cnp->cn_pnbuf;
122d2b6e45eSjsg 	/*
123d2b6e45eSjsg 	 * Extract and set starting directory.
124d2b6e45eSjsg 	 */
125d2b6e45eSjsg 	error = nfsrv_fhtovp(fhp, 0, &dp, ndp->ni_cnd.cn_cred, slp,
126d2b6e45eSjsg 	    nam, &rdonly);
127d2b6e45eSjsg 	if (error)
128d2b6e45eSjsg 		goto out;
129d2b6e45eSjsg 	if (dp->v_type != VDIR) {
130d2b6e45eSjsg 		vrele(dp);
131d2b6e45eSjsg 		error = ENOTDIR;
132d2b6e45eSjsg 		goto out;
133d2b6e45eSjsg 	}
134d2b6e45eSjsg 	vref(dp);
135d2b6e45eSjsg 	*retdirp = dp;
136d2b6e45eSjsg 	ndp->ni_startdir = dp;
137d2b6e45eSjsg 	if (rdonly)
138d2b6e45eSjsg 		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
139d2b6e45eSjsg 	else
140d2b6e45eSjsg 		cnp->cn_flags |= NOCROSSMOUNT;
141d2b6e45eSjsg 
142d2b6e45eSjsg 	/*
143d2b6e45eSjsg 	 * And call lookup() to do the real work
144d2b6e45eSjsg 	 */
145d2b6e45eSjsg 	cnp->cn_proc = p;
146d2b6e45eSjsg 	error = vfs_lookup(ndp);
147d2b6e45eSjsg 	if (error)
148d2b6e45eSjsg 		goto out;
149d2b6e45eSjsg 	/*
150d2b6e45eSjsg 	 * Check for encountering a symbolic link
151d2b6e45eSjsg 	 */
152d2b6e45eSjsg 	if (cnp->cn_flags & ISSYMLINK) {
153d2b6e45eSjsg 		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
154d2b6e45eSjsg 			vput(ndp->ni_dvp);
155d2b6e45eSjsg 		else
156d2b6e45eSjsg 			vrele(ndp->ni_dvp);
157d2b6e45eSjsg 		vput(ndp->ni_vp);
158d2b6e45eSjsg 		ndp->ni_vp = NULL;
159d2b6e45eSjsg 		error = EINVAL;
160d2b6e45eSjsg 		goto out;
161d2b6e45eSjsg 	}
162d2b6e45eSjsg 	/*
163d2b6e45eSjsg 	 * Check for saved name request
164d2b6e45eSjsg 	 */
165d2b6e45eSjsg 	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
166d2b6e45eSjsg 		cnp->cn_flags |= HASBUF;
167d2b6e45eSjsg 		return (0);
168d2b6e45eSjsg 	}
169d2b6e45eSjsg out:
170d2b6e45eSjsg 	pool_put(&namei_pool, cnp->cn_pnbuf);
171d2b6e45eSjsg 	return (error);
172d2b6e45eSjsg }
173d2b6e45eSjsg 
174d2b6e45eSjsg /*
175d2b6e45eSjsg  * A fiddled version of m_adj() that ensures null fill to a long
176d2b6e45eSjsg  * boundary and only trims off the back end
177d2b6e45eSjsg  */
178d2b6e45eSjsg void
179d2b6e45eSjsg nfsm_adj(struct mbuf *mp, int len, int nul)
180d2b6e45eSjsg {
181d2b6e45eSjsg 	struct mbuf *m;
182d2b6e45eSjsg 	int count, i;
183d2b6e45eSjsg 	char *cp;
184d2b6e45eSjsg 
185d2b6e45eSjsg 	/*
186d2b6e45eSjsg 	 * Trim from tail.  Scan the mbuf chain,
187d2b6e45eSjsg 	 * calculating its length and finding the last mbuf.
188d2b6e45eSjsg 	 * If the adjustment only affects this mbuf, then just
189d2b6e45eSjsg 	 * adjust and return.  Otherwise, rescan and truncate
190d2b6e45eSjsg 	 * after the remaining size.
191d2b6e45eSjsg 	 */
192d2b6e45eSjsg 	count = 0;
193d2b6e45eSjsg 	m = mp;
194d2b6e45eSjsg 	for (;;) {
195d2b6e45eSjsg 		count += m->m_len;
196d2b6e45eSjsg 		if (m->m_next == NULL)
197d2b6e45eSjsg 			break;
198d2b6e45eSjsg 		m = m->m_next;
199d2b6e45eSjsg 	}
200d2b6e45eSjsg 	if (m->m_len > len) {
201d2b6e45eSjsg 		m->m_len -= len;
202d2b6e45eSjsg 		if (nul > 0) {
203d2b6e45eSjsg 			cp = mtod(m, caddr_t)+m->m_len-nul;
204d2b6e45eSjsg 			for (i = 0; i < nul; i++)
205d2b6e45eSjsg 				*cp++ = '\0';
206d2b6e45eSjsg 		}
207d2b6e45eSjsg 		return;
208d2b6e45eSjsg 	}
209d2b6e45eSjsg 	count -= len;
210d2b6e45eSjsg 	if (count < 0)
211d2b6e45eSjsg 		count = 0;
212d2b6e45eSjsg 	/*
213d2b6e45eSjsg 	 * Correct length for chain is "count".
214d2b6e45eSjsg 	 * Find the mbuf with last data, adjust its length,
215d2b6e45eSjsg 	 * and toss data from remaining mbufs on chain.
216d2b6e45eSjsg 	 */
217d2b6e45eSjsg 	for (m = mp; m; m = m->m_next) {
218d2b6e45eSjsg 		if (m->m_len >= count) {
219d2b6e45eSjsg 			m->m_len = count;
220d2b6e45eSjsg 			if (nul > 0) {
221d2b6e45eSjsg 				cp = mtod(m, caddr_t)+m->m_len-nul;
222d2b6e45eSjsg 				for (i = 0; i < nul; i++)
223d2b6e45eSjsg 					*cp++ = '\0';
224d2b6e45eSjsg 			}
225d2b6e45eSjsg 			break;
226d2b6e45eSjsg 		}
227d2b6e45eSjsg 		count -= m->m_len;
228d2b6e45eSjsg 	}
229d2b6e45eSjsg 	for (m = m->m_next;m;m = m->m_next)
230d2b6e45eSjsg 		m->m_len = 0;
231d2b6e45eSjsg }
232d2b6e45eSjsg 
233d2b6e45eSjsg /*
234d2b6e45eSjsg  * Make these non-inline functions, so that the kernel text size
235d2b6e45eSjsg  * doesn't get too big...
236d2b6e45eSjsg  */
237d2b6e45eSjsg void
238d2b6e45eSjsg nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
239d2b6e45eSjsg     struct vattr *before_vap, int after_ret, struct vattr *after_vap,
240d2b6e45eSjsg     struct nfsm_info *info)
241d2b6e45eSjsg {
242d2b6e45eSjsg 	u_int32_t *tl;
243d2b6e45eSjsg 
244d2b6e45eSjsg 	if (before_ret) {
245d2b6e45eSjsg 		tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED);
246d2b6e45eSjsg 		*tl = nfs_false;
247d2b6e45eSjsg 	} else {
248d2b6e45eSjsg 		tl = nfsm_build(&info->nmi_mb, 7 * NFSX_UNSIGNED);
249d2b6e45eSjsg 		*tl++ = nfs_true;
250d2b6e45eSjsg 		txdr_hyper(before_vap->va_size, tl);
251d2b6e45eSjsg 		tl += 2;
252d2b6e45eSjsg 		txdr_nfsv3time(&(before_vap->va_mtime), tl);
253d2b6e45eSjsg 		tl += 2;
254d2b6e45eSjsg 		txdr_nfsv3time(&(before_vap->va_ctime), tl);
255d2b6e45eSjsg 	}
256d2b6e45eSjsg 	nfsm_srvpostop_attr(nfsd, after_ret, after_vap, info);
257d2b6e45eSjsg }
258d2b6e45eSjsg 
259d2b6e45eSjsg void
260d2b6e45eSjsg nfsm_srvpostop_attr(struct nfsrv_descript *nfsd, int after_ret,
261d2b6e45eSjsg     struct vattr *after_vap, struct nfsm_info *info)
262d2b6e45eSjsg {
263d2b6e45eSjsg 	u_int32_t *tl;
264d2b6e45eSjsg 	struct nfs_fattr *fp;
265d2b6e45eSjsg 
266d2b6e45eSjsg 	if (after_ret) {
267d2b6e45eSjsg 		tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED);
268d2b6e45eSjsg 		*tl = nfs_false;
269d2b6e45eSjsg 	} else {
270d2b6e45eSjsg 		tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED + NFSX_V3FATTR);
271d2b6e45eSjsg 		*tl++ = nfs_true;
272d2b6e45eSjsg 		fp = (struct nfs_fattr *)tl;
273d2b6e45eSjsg 		nfsm_srvfattr(nfsd, after_vap, fp);
274d2b6e45eSjsg 	}
275d2b6e45eSjsg }
276d2b6e45eSjsg 
277d2b6e45eSjsg void
278d2b6e45eSjsg nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
279d2b6e45eSjsg     struct nfs_fattr *fp)
280d2b6e45eSjsg {
281d2b6e45eSjsg 
282d2b6e45eSjsg 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
283d2b6e45eSjsg 	fp->fa_uid = txdr_unsigned(vap->va_uid);
284d2b6e45eSjsg 	fp->fa_gid = txdr_unsigned(vap->va_gid);
285d2b6e45eSjsg 	if (nfsd->nd_flag & ND_NFSV3) {
286d2b6e45eSjsg 		fp->fa_type = vtonfsv3_type(vap->va_type);
287d2b6e45eSjsg 		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
288d2b6e45eSjsg 		txdr_hyper(vap->va_size, &fp->fa3_size);
289d2b6e45eSjsg 		txdr_hyper(vap->va_bytes, &fp->fa3_used);
290d2b6e45eSjsg 		fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
291d2b6e45eSjsg 		fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
292d2b6e45eSjsg 		fp->fa3_fsid.nfsuquad[0] = 0;
293d2b6e45eSjsg 		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
294d2b6e45eSjsg 		txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
295d2b6e45eSjsg 		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
296d2b6e45eSjsg 		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
297d2b6e45eSjsg 		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
298d2b6e45eSjsg 	} else {
299d2b6e45eSjsg 		fp->fa_type = vtonfsv2_type(vap->va_type);
300d2b6e45eSjsg 		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
301d2b6e45eSjsg 		fp->fa2_size = txdr_unsigned(vap->va_size);
302d2b6e45eSjsg 		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
303d2b6e45eSjsg 		if (vap->va_type == VFIFO)
304d2b6e45eSjsg 			fp->fa2_rdev = 0xffffffff;
305d2b6e45eSjsg 		else
306d2b6e45eSjsg 			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
307d2b6e45eSjsg 		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
308d2b6e45eSjsg 		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
309d2b6e45eSjsg 		fp->fa2_fileid = txdr_unsigned((u_int32_t)vap->va_fileid);
310d2b6e45eSjsg 		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
311d2b6e45eSjsg 		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
312d2b6e45eSjsg 		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
313d2b6e45eSjsg 	}
314d2b6e45eSjsg }
315d2b6e45eSjsg 
316d2b6e45eSjsg /*
317d2b6e45eSjsg  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
318d2b6e45eSjsg  * 	- look up fsid in mount list (if not found ret error)
319d2b6e45eSjsg  *	- get vp and export rights by calling VFS_FHTOVP() and VFS_CHECKEXP()
320d2b6e45eSjsg  *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
321d2b6e45eSjsg  *	- if not lockflag unlock it with VOP_UNLOCK()
322d2b6e45eSjsg  */
323d2b6e45eSjsg int
324d2b6e45eSjsg nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
325d2b6e45eSjsg     struct ucred *cred, struct nfssvc_sock *slp, struct mbuf *nam,
326d2b6e45eSjsg     int *rdonlyp)
327d2b6e45eSjsg {
328d2b6e45eSjsg 	struct mount *mp;
329d2b6e45eSjsg 	int i;
330d2b6e45eSjsg 	struct ucred *credanon;
331d2b6e45eSjsg 	int error, exflags;
332d2b6e45eSjsg 	struct sockaddr_in *saddr;
333d2b6e45eSjsg 
334d2b6e45eSjsg 	*vpp = NULL;
335d2b6e45eSjsg 	mp = vfs_getvfs(&fhp->fh_fsid);
336d2b6e45eSjsg 
337d2b6e45eSjsg 	if (!mp)
338d2b6e45eSjsg 		return (ESTALE);
339d2b6e45eSjsg 	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
340d2b6e45eSjsg 	if (error)
341d2b6e45eSjsg 		return (error);
342d2b6e45eSjsg 	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
343d2b6e45eSjsg 	if (error)
344d2b6e45eSjsg 		return (error);
345d2b6e45eSjsg 
346d2b6e45eSjsg 	saddr = mtod(nam, struct sockaddr_in *);
347d2b6e45eSjsg 	if (saddr->sin_family == AF_INET &&
348d2b6e45eSjsg 	    (ntohs(saddr->sin_port) >= IPPORT_RESERVED ||
349d2b6e45eSjsg 	    (slp->ns_so->so_type == SOCK_STREAM && ntohs(saddr->sin_port) == 20))) {
350d2b6e45eSjsg 		vput(*vpp);
351d2b6e45eSjsg 		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
352d2b6e45eSjsg 	}
353d2b6e45eSjsg 
354d2b6e45eSjsg 	/* Check/setup credentials. */
355d2b6e45eSjsg 	if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
356d2b6e45eSjsg 		cred->cr_uid = credanon->cr_uid;
357d2b6e45eSjsg 		cred->cr_gid = credanon->cr_gid;
358d2b6e45eSjsg 		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS_MAX; i++)
359d2b6e45eSjsg 			cred->cr_groups[i] = credanon->cr_groups[i];
360d2b6e45eSjsg 		cred->cr_ngroups = i;
361d2b6e45eSjsg 	}
362d2b6e45eSjsg 	if (exflags & MNT_EXRDONLY)
363d2b6e45eSjsg 		*rdonlyp = 1;
364d2b6e45eSjsg 	else
365d2b6e45eSjsg 		*rdonlyp = 0;
366d2b6e45eSjsg 	if (!lockflag)
367d2b6e45eSjsg 		VOP_UNLOCK(*vpp);
368d2b6e45eSjsg 
369d2b6e45eSjsg 	return (0);
370d2b6e45eSjsg }
371d2b6e45eSjsg 
372d2b6e45eSjsg /*
373d2b6e45eSjsg  * This function compares two net addresses by family and returns non zero
374d2b6e45eSjsg  * if they are the same host, or if there is any doubt it returns 0.
375d2b6e45eSjsg  * The AF_INET family is handled as a special case so that address mbufs
376d2b6e45eSjsg  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
377d2b6e45eSjsg  */
378d2b6e45eSjsg int
379d2b6e45eSjsg netaddr_match(int family, union nethostaddr *haddr, struct mbuf *nam)
380d2b6e45eSjsg {
381d2b6e45eSjsg 	struct sockaddr_in *inetaddr;
382d2b6e45eSjsg 
383d2b6e45eSjsg 	switch (family) {
384d2b6e45eSjsg 	case AF_INET:
385d2b6e45eSjsg 		inetaddr = mtod(nam, struct sockaddr_in *);
386d2b6e45eSjsg 		if (inetaddr->sin_family == AF_INET &&
387d2b6e45eSjsg 		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
388d2b6e45eSjsg 			return (1);
389d2b6e45eSjsg 		break;
390d2b6e45eSjsg 	default:
391d2b6e45eSjsg 		break;
392*8d80561bSjsg 	}
393d2b6e45eSjsg 	return (0);
394d2b6e45eSjsg }
395d2b6e45eSjsg 
396d2b6e45eSjsg int
397d2b6e45eSjsg nfsm_srvsattr(struct mbuf **mp, struct vattr *va, struct mbuf *mrep,
398d2b6e45eSjsg     caddr_t *dposp)
399d2b6e45eSjsg {
400d2b6e45eSjsg 	struct nfsm_info	info;
401d2b6e45eSjsg 	int error = 0;
402d2b6e45eSjsg 	uint32_t *tl;
403d2b6e45eSjsg 
404d2b6e45eSjsg 	info.nmi_md = *mp;
405d2b6e45eSjsg 	info.nmi_dpos = *dposp;
406d2b6e45eSjsg 	info.nmi_mrep = mrep;
407d2b6e45eSjsg 	info.nmi_errorp = &error;
408d2b6e45eSjsg 
409d2b6e45eSjsg 	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
410d2b6e45eSjsg 	if (tl == NULL)
411d2b6e45eSjsg 		return error;
412d2b6e45eSjsg 	if (*tl == nfs_true) {
413d2b6e45eSjsg 		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
414d2b6e45eSjsg 		if (tl == NULL)
415d2b6e45eSjsg 			return error;
416d2b6e45eSjsg 		va->va_mode = nfstov_mode(*tl);
417d2b6e45eSjsg 	}
418d2b6e45eSjsg 
419d2b6e45eSjsg 	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
420d2b6e45eSjsg 	if (tl == NULL)
421d2b6e45eSjsg 		return error;
422d2b6e45eSjsg 	if (*tl == nfs_true) {
423d2b6e45eSjsg 		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
424d2b6e45eSjsg 		if (tl == NULL)
425d2b6e45eSjsg 			return error;
426d2b6e45eSjsg 		va->va_uid = fxdr_unsigned(uid_t, *tl);
427d2b6e45eSjsg 	}
428d2b6e45eSjsg 
429d2b6e45eSjsg 	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
430d2b6e45eSjsg 	if (tl == NULL)
431d2b6e45eSjsg 		return error;
432d2b6e45eSjsg 	if (*tl == nfs_true) {
433d2b6e45eSjsg 		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
434d2b6e45eSjsg 		if (tl == NULL)
435d2b6e45eSjsg 			return error;
436d2b6e45eSjsg 		va->va_gid = fxdr_unsigned(gid_t, *tl);
437d2b6e45eSjsg 	}
438d2b6e45eSjsg 
439d2b6e45eSjsg 	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
440d2b6e45eSjsg 	if (tl == NULL)
441d2b6e45eSjsg 		return error;
442d2b6e45eSjsg 	if (*tl == nfs_true) {
443d2b6e45eSjsg 		tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
444d2b6e45eSjsg 		if (tl == NULL)
445d2b6e45eSjsg 			return error;
446d2b6e45eSjsg 		va->va_size = fxdr_hyper(tl);
447d2b6e45eSjsg 	}
448d2b6e45eSjsg 
449d2b6e45eSjsg 	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
450d2b6e45eSjsg 	if (tl == NULL)
451d2b6e45eSjsg 		return error;
452d2b6e45eSjsg 	switch (fxdr_unsigned(int, *tl)) {
453d2b6e45eSjsg 	case NFSV3SATTRTIME_TOCLIENT:
454d2b6e45eSjsg 		va->va_vaflags |= VA_UTIMES_CHANGE;
455d2b6e45eSjsg 		va->va_vaflags &= ~VA_UTIMES_NULL;
456d2b6e45eSjsg 		tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
457d2b6e45eSjsg 		if (tl == NULL)
458d2b6e45eSjsg 			return error;
459d2b6e45eSjsg 		fxdr_nfsv3time(tl, &va->va_atime);
460d2b6e45eSjsg 		break;
461d2b6e45eSjsg 	case NFSV3SATTRTIME_TOSERVER:
462d2b6e45eSjsg 		va->va_vaflags |= VA_UTIMES_CHANGE;
463d2b6e45eSjsg 		getnanotime(&va->va_atime);
464d2b6e45eSjsg 		break;
465*8d80561bSjsg 	}
466d2b6e45eSjsg 
467d2b6e45eSjsg 	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
468d2b6e45eSjsg 	if (tl == NULL)
469d2b6e45eSjsg 		return error;
470d2b6e45eSjsg 	switch (fxdr_unsigned(int, *tl)) {
471d2b6e45eSjsg 	case NFSV3SATTRTIME_TOCLIENT:
472d2b6e45eSjsg 		va->va_vaflags |= VA_UTIMES_CHANGE;
473d2b6e45eSjsg 		va->va_vaflags &= ~VA_UTIMES_NULL;
474d2b6e45eSjsg 		tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
475d2b6e45eSjsg 		if (tl == NULL)
476d2b6e45eSjsg 			return error;
477d2b6e45eSjsg 		fxdr_nfsv3time(tl, &va->va_mtime);
478d2b6e45eSjsg 		break;
479d2b6e45eSjsg 	case NFSV3SATTRTIME_TOSERVER:
480d2b6e45eSjsg 		va->va_vaflags |= VA_UTIMES_CHANGE;
481d2b6e45eSjsg 		getnanotime(&va->va_mtime);
482d2b6e45eSjsg 		break;
483*8d80561bSjsg 	}
484d2b6e45eSjsg 
485d2b6e45eSjsg 	*dposp = info.nmi_dpos;
486d2b6e45eSjsg 	*mp = info.nmi_md;
487d2b6e45eSjsg 	return 0;
488d2b6e45eSjsg }
489