nfs_srvsubs.c revision 171613
1/*-
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *	@(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 171613 2007-07-27 11:59:57Z rwatson $");
37
38/*
39 * These functions support the macros and help fiddle mbuf chains for
40 * the nfs op functions. They do things like create the rpc header and
41 * copy data between mbuf chains and uio lists.
42 */
43
44#include "opt_inet6.h"
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/kernel.h>
49#include <sys/bio.h>
50#include <sys/buf.h>
51#include <sys/proc.h>
52#include <sys/mount.h>
53#include <sys/vnode.h>
54#include <sys/namei.h>
55#include <sys/mbuf.h>
56#include <sys/refcount.h>
57#include <sys/socket.h>
58#include <sys/stat.h>
59#include <sys/malloc.h>
60#include <sys/module.h>
61#include <sys/sysent.h>
62#include <sys/syscall.h>
63#include <sys/sysproto.h>
64
65#include <vm/vm.h>
66#include <vm/vm_object.h>
67#include <vm/vm_extern.h>
68#include <vm/uma.h>
69
70#include <nfs/rpcv2.h>
71#include <nfs/nfsproto.h>
72#include <nfsserver/nfs.h>
73#include <nfs/xdr_subs.h>
74#include <nfsserver/nfsm_subs.h>
75
76#include <netinet/in.h>
77
78/*
79 * Data items converted to xdr at startup, since they are constant
80 * This is kinda hokey, but may save a little time doing byte swaps
81 */
82u_int32_t nfsrv_nfs_xdrneg1;
83u_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply,
84	nfsrv_rpc_msgdenied, nfsrv_rpc_autherr,
85	nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted;
86u_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false;
87
88/* And other global data */
89static const nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR,
90				       NFLNK, NFNON, NFCHR, NFNON };
91#define vtonfsv2_type(a)	txdr_unsigned(nfsv2_type[((int32_t)(a))])
92#define vtonfsv3_mode(m)	txdr_unsigned((m) & ALLPERMS)
93
94int nfsrv_ticks;
95
96struct nfssvc_sockhead nfssvc_sockhead;
97int nfssvc_sockhead_flag;
98struct nfsd_head nfsd_head;
99int nfsd_head_flag;
100
101static int nfssvc_offset = SYS_nfssvc;
102static struct sysent nfssvc_prev_sysent;
103MAKE_SYSENT(nfssvc);
104
105struct mtx nfsd_mtx;
106
107/*
108 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
109 */
110const int nfsrv_nfsv3_procid[NFS_NPROCS] = {
111	NFSPROC_NULL,
112	NFSPROC_GETATTR,
113	NFSPROC_SETATTR,
114	NFSPROC_NOOP,
115	NFSPROC_LOOKUP,
116	NFSPROC_READLINK,
117	NFSPROC_READ,
118	NFSPROC_NOOP,
119	NFSPROC_WRITE,
120	NFSPROC_CREATE,
121	NFSPROC_REMOVE,
122	NFSPROC_RENAME,
123	NFSPROC_LINK,
124	NFSPROC_SYMLINK,
125	NFSPROC_MKDIR,
126	NFSPROC_RMDIR,
127	NFSPROC_READDIR,
128	NFSPROC_FSSTAT,
129	NFSPROC_NOOP,
130	NFSPROC_NOOP,
131	NFSPROC_NOOP,
132	NFSPROC_NOOP,
133	NFSPROC_NOOP,
134};
135
136/*
137 * and the reverse mapping from generic to Version 2 procedure numbers
138 */
139const int nfsrvv2_procid[NFS_NPROCS] = {
140	NFSV2PROC_NULL,
141	NFSV2PROC_GETATTR,
142	NFSV2PROC_SETATTR,
143	NFSV2PROC_LOOKUP,
144	NFSV2PROC_NOOP,
145	NFSV2PROC_READLINK,
146	NFSV2PROC_READ,
147	NFSV2PROC_WRITE,
148	NFSV2PROC_CREATE,
149	NFSV2PROC_MKDIR,
150	NFSV2PROC_SYMLINK,
151	NFSV2PROC_CREATE,
152	NFSV2PROC_REMOVE,
153	NFSV2PROC_RMDIR,
154	NFSV2PROC_RENAME,
155	NFSV2PROC_LINK,
156	NFSV2PROC_READDIR,
157	NFSV2PROC_NOOP,
158	NFSV2PROC_STATFS,
159	NFSV2PROC_NOOP,
160	NFSV2PROC_NOOP,
161	NFSV2PROC_NOOP,
162	NFSV2PROC_NOOP,
163};
164
165/*
166 * Maps errno values to nfs error numbers.
167 * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not
168 * specifically defined in RFC 1094.
169 */
170static const u_char nfsrv_v2errmap[ELAST] = {
171  NFSERR_PERM,	NFSERR_NOENT,	0,		0,		0,
172  NFSERR_NXIO,	0,		0,		0,		0,
173  0,		0,		NFSERR_ACCES,	0,		0,
174  0,		NFSERR_EXIST,	0,		NFSERR_NODEV,	NFSERR_NOTDIR,
175  NFSERR_ISDIR,	0,		0,		0,		0,
176  0,		NFSERR_FBIG,	NFSERR_NOSPC,	0,		NFSERR_ROFS,
177  0,		0,		0,		0,		0,
178  0,		0,		0,		0,		0,
179  0,		0,		0,		0,		0,
180  0,		0,		0,		0,		0,
181  0,		0,		0,		0,		0,
182  0,		0,		0,		0,		0,
183  0,		0,		NFSERR_NAMETOL,	0,		0,
184  NFSERR_NOTEMPTY, 0,		0,		NFSERR_DQUOT,	NFSERR_STALE,
185  0
186};
187
188/*
189 * Maps errno values to nfs error numbers.
190 * Although it is not obvious whether or not NFS clients really care if
191 * a returned error value is in the specified list for the procedure, the
192 * safest thing to do is filter them appropriately. For Version 2, the
193 * X/Open XNFS document is the only specification that defines error values
194 * for each RPC (The RFC simply lists all possible error values for all RPCs),
195 * so I have decided to not do this for Version 2.
196 * The first entry is the default error return and the rest are the valid
197 * errors for that RPC in increasing numeric order.
198 */
199static const short nfsv3err_null[] = {
200	0,
201	0,
202};
203
204static const short nfsv3err_getattr[] = {
205	NFSERR_IO,
206	NFSERR_IO,
207	NFSERR_STALE,
208	NFSERR_BADHANDLE,
209	NFSERR_SERVERFAULT,
210	0,
211};
212
213static const short nfsv3err_setattr[] = {
214	NFSERR_IO,
215	NFSERR_PERM,
216	NFSERR_IO,
217	NFSERR_ACCES,
218	NFSERR_INVAL,
219	NFSERR_NOSPC,
220	NFSERR_ROFS,
221	NFSERR_DQUOT,
222	NFSERR_STALE,
223	NFSERR_BADHANDLE,
224	NFSERR_NOT_SYNC,
225	NFSERR_SERVERFAULT,
226	0,
227};
228
229static const short nfsv3err_lookup[] = {
230	NFSERR_IO,
231	NFSERR_NOENT,
232	NFSERR_IO,
233	NFSERR_ACCES,
234	NFSERR_NOTDIR,
235	NFSERR_NAMETOL,
236	NFSERR_STALE,
237	NFSERR_BADHANDLE,
238	NFSERR_SERVERFAULT,
239	0,
240};
241
242static const short nfsv3err_access[] = {
243	NFSERR_IO,
244	NFSERR_IO,
245	NFSERR_STALE,
246	NFSERR_BADHANDLE,
247	NFSERR_SERVERFAULT,
248	0,
249};
250
251static const short nfsv3err_readlink[] = {
252	NFSERR_IO,
253	NFSERR_IO,
254	NFSERR_ACCES,
255	NFSERR_INVAL,
256	NFSERR_STALE,
257	NFSERR_BADHANDLE,
258	NFSERR_NOTSUPP,
259	NFSERR_SERVERFAULT,
260	0,
261};
262
263static const short nfsv3err_read[] = {
264	NFSERR_IO,
265	NFSERR_IO,
266	NFSERR_NXIO,
267	NFSERR_ACCES,
268	NFSERR_INVAL,
269	NFSERR_STALE,
270	NFSERR_BADHANDLE,
271	NFSERR_SERVERFAULT,
272	0,
273};
274
275static const short nfsv3err_write[] = {
276	NFSERR_IO,
277	NFSERR_IO,
278	NFSERR_ACCES,
279	NFSERR_INVAL,
280	NFSERR_FBIG,
281	NFSERR_NOSPC,
282	NFSERR_ROFS,
283	NFSERR_DQUOT,
284	NFSERR_STALE,
285	NFSERR_BADHANDLE,
286	NFSERR_SERVERFAULT,
287	0,
288};
289
290static const short nfsv3err_create[] = {
291	NFSERR_IO,
292	NFSERR_IO,
293	NFSERR_ACCES,
294	NFSERR_EXIST,
295	NFSERR_NOTDIR,
296	NFSERR_NOSPC,
297	NFSERR_ROFS,
298	NFSERR_NAMETOL,
299	NFSERR_DQUOT,
300	NFSERR_STALE,
301	NFSERR_BADHANDLE,
302	NFSERR_NOTSUPP,
303	NFSERR_SERVERFAULT,
304	0,
305};
306
307static const short nfsv3err_mkdir[] = {
308	NFSERR_IO,
309	NFSERR_IO,
310	NFSERR_ACCES,
311	NFSERR_EXIST,
312	NFSERR_NOTDIR,
313	NFSERR_NOSPC,
314	NFSERR_ROFS,
315	NFSERR_NAMETOL,
316	NFSERR_DQUOT,
317	NFSERR_STALE,
318	NFSERR_BADHANDLE,
319	NFSERR_NOTSUPP,
320	NFSERR_SERVERFAULT,
321	0,
322};
323
324static const short nfsv3err_symlink[] = {
325	NFSERR_IO,
326	NFSERR_IO,
327	NFSERR_ACCES,
328	NFSERR_EXIST,
329	NFSERR_NOTDIR,
330	NFSERR_NOSPC,
331	NFSERR_ROFS,
332	NFSERR_NAMETOL,
333	NFSERR_DQUOT,
334	NFSERR_STALE,
335	NFSERR_BADHANDLE,
336	NFSERR_NOTSUPP,
337	NFSERR_SERVERFAULT,
338	0,
339};
340
341static const short nfsv3err_mknod[] = {
342	NFSERR_IO,
343	NFSERR_IO,
344	NFSERR_ACCES,
345	NFSERR_EXIST,
346	NFSERR_NOTDIR,
347	NFSERR_NOSPC,
348	NFSERR_ROFS,
349	NFSERR_NAMETOL,
350	NFSERR_DQUOT,
351	NFSERR_STALE,
352	NFSERR_BADHANDLE,
353	NFSERR_NOTSUPP,
354	NFSERR_SERVERFAULT,
355	NFSERR_BADTYPE,
356	0,
357};
358
359static const short nfsv3err_remove[] = {
360	NFSERR_IO,
361	NFSERR_NOENT,
362	NFSERR_IO,
363	NFSERR_ACCES,
364	NFSERR_NOTDIR,
365	NFSERR_ROFS,
366	NFSERR_NAMETOL,
367	NFSERR_STALE,
368	NFSERR_BADHANDLE,
369	NFSERR_SERVERFAULT,
370	0,
371};
372
373static const short nfsv3err_rmdir[] = {
374	NFSERR_IO,
375	NFSERR_NOENT,
376	NFSERR_IO,
377	NFSERR_ACCES,
378	NFSERR_EXIST,
379	NFSERR_NOTDIR,
380	NFSERR_INVAL,
381	NFSERR_ROFS,
382	NFSERR_NAMETOL,
383	NFSERR_NOTEMPTY,
384	NFSERR_STALE,
385	NFSERR_BADHANDLE,
386	NFSERR_NOTSUPP,
387	NFSERR_SERVERFAULT,
388	0,
389};
390
391static const short nfsv3err_rename[] = {
392	NFSERR_IO,
393	NFSERR_NOENT,
394	NFSERR_IO,
395	NFSERR_ACCES,
396	NFSERR_EXIST,
397	NFSERR_XDEV,
398	NFSERR_NOTDIR,
399	NFSERR_ISDIR,
400	NFSERR_INVAL,
401	NFSERR_NOSPC,
402	NFSERR_ROFS,
403	NFSERR_MLINK,
404	NFSERR_NAMETOL,
405	NFSERR_NOTEMPTY,
406	NFSERR_DQUOT,
407	NFSERR_STALE,
408	NFSERR_BADHANDLE,
409	NFSERR_NOTSUPP,
410	NFSERR_SERVERFAULT,
411	0,
412};
413
414static const short nfsv3err_link[] = {
415	NFSERR_IO,
416	NFSERR_IO,
417	NFSERR_ACCES,
418	NFSERR_EXIST,
419	NFSERR_XDEV,
420	NFSERR_NOTDIR,
421	NFSERR_INVAL,
422	NFSERR_NOSPC,
423	NFSERR_ROFS,
424	NFSERR_MLINK,
425	NFSERR_NAMETOL,
426	NFSERR_DQUOT,
427	NFSERR_STALE,
428	NFSERR_BADHANDLE,
429	NFSERR_NOTSUPP,
430	NFSERR_SERVERFAULT,
431	0,
432};
433
434static const short nfsv3err_readdir[] = {
435	NFSERR_IO,
436	NFSERR_IO,
437	NFSERR_ACCES,
438	NFSERR_NOTDIR,
439	NFSERR_STALE,
440	NFSERR_BADHANDLE,
441	NFSERR_BAD_COOKIE,
442	NFSERR_TOOSMALL,
443	NFSERR_SERVERFAULT,
444	0,
445};
446
447static const short nfsv3err_readdirplus[] = {
448	NFSERR_IO,
449	NFSERR_IO,
450	NFSERR_ACCES,
451	NFSERR_NOTDIR,
452	NFSERR_STALE,
453	NFSERR_BADHANDLE,
454	NFSERR_BAD_COOKIE,
455	NFSERR_NOTSUPP,
456	NFSERR_TOOSMALL,
457	NFSERR_SERVERFAULT,
458	0,
459};
460
461static const short nfsv3err_fsstat[] = {
462	NFSERR_IO,
463	NFSERR_IO,
464	NFSERR_STALE,
465	NFSERR_BADHANDLE,
466	NFSERR_SERVERFAULT,
467	0,
468};
469
470static const short nfsv3err_fsinfo[] = {
471	NFSERR_STALE,
472	NFSERR_STALE,
473	NFSERR_BADHANDLE,
474	NFSERR_SERVERFAULT,
475	0,
476};
477
478static const short nfsv3err_pathconf[] = {
479	NFSERR_STALE,
480	NFSERR_STALE,
481	NFSERR_BADHANDLE,
482	NFSERR_SERVERFAULT,
483	0,
484};
485
486static const short nfsv3err_commit[] = {
487	NFSERR_IO,
488	NFSERR_IO,
489	NFSERR_STALE,
490	NFSERR_BADHANDLE,
491	NFSERR_SERVERFAULT,
492	0,
493};
494
495static const short *nfsrv_v3errmap[] = {
496	nfsv3err_null,
497	nfsv3err_getattr,
498	nfsv3err_setattr,
499	nfsv3err_lookup,
500	nfsv3err_access,
501	nfsv3err_readlink,
502	nfsv3err_read,
503	nfsv3err_write,
504	nfsv3err_create,
505	nfsv3err_mkdir,
506	nfsv3err_symlink,
507	nfsv3err_mknod,
508	nfsv3err_remove,
509	nfsv3err_rmdir,
510	nfsv3err_rename,
511	nfsv3err_link,
512	nfsv3err_readdir,
513	nfsv3err_readdirplus,
514	nfsv3err_fsstat,
515	nfsv3err_fsinfo,
516	nfsv3err_pathconf,
517	nfsv3err_commit,
518};
519
520/*
521 * Called once to initialize data structures...
522 */
523static int
524nfsrv_modevent(module_t mod, int type, void *data)
525{
526	static int registered;
527	int error = 0;
528
529	NET_LOCK_GIANT();
530	switch (type) {
531	case MOD_LOAD:
532		mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF);
533		nfsrv_rpc_vers = txdr_unsigned(RPC_VER2);
534		nfsrv_rpc_call = txdr_unsigned(RPC_CALL);
535		nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY);
536		nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
537		nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
538		nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
539		nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR);
540		nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
541		nfsrv_nfs_prog = txdr_unsigned(NFS_PROG);
542		nfsrv_nfs_true = txdr_unsigned(TRUE);
543		nfsrv_nfs_false = txdr_unsigned(FALSE);
544		nfsrv_nfs_xdrneg1 = txdr_unsigned(-1);
545		nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
546		if (nfsrv_ticks < 1)
547			nfsrv_ticks = 1;
548
549		nfsrv_initcache();	/* Init the server request cache */
550		NFSD_LOCK();
551		nfsrv_init(0);		/* Init server data structures */
552		callout_init(&nfsrv_callout, CALLOUT_MPSAFE);
553		NFSD_UNLOCK();
554		nfsrv_timer(0);
555
556		error = syscall_register(&nfssvc_offset, &nfssvc_sysent,
557		    &nfssvc_prev_sysent);
558		if (error)
559			break;
560		registered = 1;
561		break;
562
563	case MOD_UNLOAD:
564		if (nfsrv_numnfsd != 0) {
565			error = EBUSY;
566			break;
567		}
568
569		if (registered)
570			syscall_deregister(&nfssvc_offset, &nfssvc_prev_sysent);
571		callout_drain(&nfsrv_callout);
572		nfsrv_destroycache();	/* Free the server request cache */
573		nfsrv_destroycache();	/* Free the server request cache */
574		mtx_destroy(&nfsd_mtx);
575		break;
576	default:
577		error = EOPNOTSUPP;
578		break;
579	}
580	NET_UNLOCK_GIANT();
581	return error;
582}
583static moduledata_t nfsserver_mod = {
584	"nfsserver",
585	nfsrv_modevent,
586	NULL,
587};
588DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
589
590/* So that loader and kldload(2) can find us, wherever we are.. */
591MODULE_VERSION(nfsserver, 1);
592
593/*
594 * Set up nameidata for a lookup() call and do it.
595 *
596 * If pubflag is set, this call is done for a lookup operation on the
597 * public filehandle. In that case we allow crossing mountpoints and
598 * absolute pathnames. However, the caller is expected to check that
599 * the lookup result is within the public fs, and deny access if
600 * it is not.
601 *
602 * nfs_namei() clears out garbage fields that namei() might leave garbage.
603 * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
604 * error occurs but the parent was not requested.
605 *
606 * dirp may be set whether an error is returned or not, and must be
607 * released by the caller.
608 */
609int
610nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
611    struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp,
612    caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp,
613    int *retdirattr_retp, struct thread *td, int pubflag)
614{
615	int i, rem;
616	struct mbuf *md;
617	char *fromcp, *tocp, *cp;
618	struct iovec aiov;
619	struct uio auio;
620	struct vnode *dp;
621	int error, rdonly, linklen;
622	struct componentname *cnp = &ndp->ni_cnd;
623	int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0;
624	int dvfslocked;
625	int vfslocked;
626
627	vfslocked = 0;
628	dvfslocked = 0;
629	*retdirp = NULL;
630	cnp->cn_flags |= NOMACCHECK;
631	cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
632
633	/*
634	 * Copy the name from the mbuf list to ndp->ni_pnbuf
635	 * and set the various ndp fields appropriately.
636	 */
637	fromcp = *dposp;
638	tocp = cnp->cn_pnbuf;
639	md = *mdp;
640	rem = mtod(md, caddr_t) + md->m_len - fromcp;
641	for (i = 0; i < len; i++) {
642		while (rem == 0) {
643			md = md->m_next;
644			if (md == NULL) {
645				error = EBADRPC;
646				goto out;
647			}
648			fromcp = mtod(md, caddr_t);
649			rem = md->m_len;
650		}
651		if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
652			error = EACCES;
653			goto out;
654		}
655		*tocp++ = *fromcp++;
656		rem--;
657	}
658	*tocp = '\0';
659	*mdp = md;
660	*dposp = fromcp;
661	len = nfsm_rndup(len)-len;
662	if (len > 0) {
663		if (rem >= len)
664			*dposp += len;
665		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
666			goto out;
667	}
668
669	/*
670	 * Extract and set starting directory.
671	 */
672	error = nfsrv_fhtovp(fhp, FALSE, &dp, &dvfslocked,
673	    ndp->ni_cnd.cn_cred, slp, nam, &rdonly, pubflag);
674	if (error)
675		goto out;
676	vfslocked = VFS_LOCK_GIANT(dp->v_mount);
677	if (dp->v_type != VDIR) {
678		vrele(dp);
679		error = ENOTDIR;
680		goto out;
681	}
682
683	if (rdonly)
684		cnp->cn_flags |= RDONLY;
685
686	/*
687	 * Set return directory.  Reference to dp is implicitly transfered
688	 * to the returned pointer
689	 */
690	*retdirp = dp;
691	if (v3) {
692		vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
693		*retdirattr_retp = VOP_GETATTR(dp, retdirattrp,
694			ndp->ni_cnd.cn_cred, td);
695		VOP_UNLOCK(dp, 0, td);
696	}
697
698	if (pubflag) {
699		/*
700		 * Oh joy. For WebNFS, handle those pesky '%' escapes,
701		 * and the 'native path' indicator.
702		 */
703		cp = uma_zalloc(namei_zone, M_WAITOK);
704		fromcp = cnp->cn_pnbuf;
705		tocp = cp;
706		if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
707			switch ((unsigned char)*fromcp) {
708			case WEBNFS_NATIVE_CHAR:
709				/*
710				 * 'Native' path for us is the same
711				 * as a path according to the NFS spec,
712				 * just skip the escape char.
713				 */
714				fromcp++;
715				break;
716			/*
717			 * More may be added in the future, range 0x80-0xff
718			 */
719			default:
720				error = EIO;
721				uma_zfree(namei_zone, cp);
722				goto out;
723			}
724		}
725		/*
726		 * Translate the '%' escapes, URL-style.
727		 */
728		while (*fromcp != '\0') {
729			if (*fromcp == WEBNFS_ESC_CHAR) {
730				if (fromcp[1] != '\0' && fromcp[2] != '\0') {
731					fromcp++;
732					*tocp++ = HEXSTRTOI(fromcp);
733					fromcp += 2;
734					continue;
735				} else {
736					error = ENOENT;
737					uma_zfree(namei_zone, cp);
738					goto out;
739				}
740			} else
741				*tocp++ = *fromcp++;
742		}
743		*tocp = '\0';
744		uma_zfree(namei_zone, cnp->cn_pnbuf);
745		cnp->cn_pnbuf = cp;
746	}
747
748	ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
749	ndp->ni_segflg = UIO_SYSSPACE;
750
751	if (pubflag) {
752		ndp->ni_rootdir = rootvnode;
753		ndp->ni_loopcnt = 0;
754		if (cnp->cn_pnbuf[0] == '/') {
755			int tvfslocked;
756
757			tvfslocked = VFS_LOCK_GIANT(rootvnode->v_mount);
758			VFS_UNLOCK_GIANT(vfslocked);
759			dp = rootvnode;
760			vfslocked = tvfslocked;
761		}
762	} else {
763		cnp->cn_flags |= NOCROSSMOUNT;
764	}
765
766	/*
767	 * Initialize for scan, set ni_startdir and bump ref on dp again
768	 * because lookup() will dereference ni_startdir.
769	 */
770
771	cnp->cn_thread = td;
772	VREF(dp);
773	ndp->ni_startdir = dp;
774
775	if (!lockleaf)
776		cnp->cn_flags |= LOCKLEAF;
777	for (;;) {
778		cnp->cn_nameptr = cnp->cn_pnbuf;
779		/*
780		 * Call lookup() to do the real work.  If an error occurs,
781		 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
782		 * we do not have to dereference anything before returning.
783		 * In either case ni_startdir will be dereferenced and NULLed
784		 * out.
785		 */
786		if (vfslocked)
787			ndp->ni_cnd.cn_flags |= GIANTHELD;
788		error = lookup(ndp);
789		vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
790		ndp->ni_cnd.cn_flags &= ~GIANTHELD;
791		if (error)
792			break;
793
794		/*
795		 * Check for encountering a symbolic link.  Trivial
796		 * termination occurs if no symlink encountered.
797		 * Note: zfree is safe because error is 0, so we will
798		 * not zfree it again when we break.
799		 */
800		if ((cnp->cn_flags & ISSYMLINK) == 0) {
801			if (cnp->cn_flags & (SAVENAME | SAVESTART))
802				cnp->cn_flags |= HASBUF;
803			else
804				uma_zfree(namei_zone, cnp->cn_pnbuf);
805			if (ndp->ni_vp && !lockleaf)
806				VOP_UNLOCK(ndp->ni_vp, 0, td);
807			break;
808		}
809
810		/*
811		 * Validate symlink
812		 */
813		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
814			VOP_UNLOCK(ndp->ni_dvp, 0, td);
815		if (!pubflag) {
816			error = EINVAL;
817			goto badlink2;
818		}
819
820		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
821			error = ELOOP;
822			goto badlink2;
823		}
824		if (ndp->ni_pathlen > 1)
825			cp = uma_zalloc(namei_zone, M_WAITOK);
826		else
827			cp = cnp->cn_pnbuf;
828		aiov.iov_base = cp;
829		aiov.iov_len = MAXPATHLEN;
830		auio.uio_iov = &aiov;
831		auio.uio_iovcnt = 1;
832		auio.uio_offset = 0;
833		auio.uio_rw = UIO_READ;
834		auio.uio_segflg = UIO_SYSSPACE;
835		auio.uio_td = NULL;
836		auio.uio_resid = MAXPATHLEN;
837		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
838		if (error) {
839		badlink1:
840			if (ndp->ni_pathlen > 1)
841				uma_zfree(namei_zone, cp);
842		badlink2:
843			vput(ndp->ni_vp);
844			vrele(ndp->ni_dvp);
845			break;
846		}
847		linklen = MAXPATHLEN - auio.uio_resid;
848		if (linklen == 0) {
849			error = ENOENT;
850			goto badlink1;
851		}
852		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
853			error = ENAMETOOLONG;
854			goto badlink1;
855		}
856
857		/*
858		 * Adjust or replace path
859		 */
860		if (ndp->ni_pathlen > 1) {
861			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
862			uma_zfree(namei_zone, cnp->cn_pnbuf);
863			cnp->cn_pnbuf = cp;
864		} else
865			cnp->cn_pnbuf[linklen] = '\0';
866		ndp->ni_pathlen += linklen;
867
868		/*
869		 * Cleanup refs for next loop and check if root directory
870		 * should replace current directory.  Normally ni_dvp
871		 * becomes the new base directory and is cleaned up when
872		 * we loop.  Explicitly null pointers after invalidation
873		 * to clarify operation.
874		 */
875		vput(ndp->ni_vp);
876		ndp->ni_vp = NULL;
877
878		if (cnp->cn_pnbuf[0] == '/') {
879			vrele(ndp->ni_dvp);
880			ndp->ni_dvp = ndp->ni_rootdir;
881			VREF(ndp->ni_dvp);
882		}
883		ndp->ni_startdir = ndp->ni_dvp;
884		ndp->ni_dvp = NULL;
885	}
886	if (!lockleaf)
887		cnp->cn_flags &= ~LOCKLEAF;
888	if (cnp->cn_flags & GIANTHELD) {
889		mtx_unlock(&Giant);
890		cnp->cn_flags &= ~GIANTHELD;
891	}
892
893	/*
894	 * nfs_namei() guarentees that fields will not contain garbage
895	 * whether an error occurs or not.  This allows the caller to track
896	 * cleanup state trivially.
897	 */
898out:
899	if (error) {
900		uma_zfree(namei_zone, cnp->cn_pnbuf);
901		ndp->ni_vp = NULL;
902		ndp->ni_dvp = NULL;
903		ndp->ni_startdir = NULL;
904		cnp->cn_flags &= ~HASBUF;
905		VFS_UNLOCK_GIANT(vfslocked);
906		vfslocked = 0;
907	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
908		ndp->ni_dvp = NULL;
909	}
910	/*
911	 * This differs from normal namei() in that even on failure we may
912	 * return with Giant held due to the dirp return.  Make sure we only
913	 * have not recursed however.  The calling code only expects to drop
914	 * one acquire.
915	 */
916	if (vfslocked || dvfslocked)
917		ndp->ni_cnd.cn_flags |= GIANTHELD;
918	if (vfslocked && dvfslocked)
919		VFS_UNLOCK_GIANT(vfslocked);
920	return (error);
921}
922
923/*
924 * A fiddled version of m_adj() that ensures null fill to a long
925 * boundary and only trims off the back end
926 */
927void
928nfsm_adj(struct mbuf *mp, int len, int nul)
929{
930	struct mbuf *m;
931	int count, i;
932	char *cp;
933
934	/*
935	 * Trim from tail.  Scan the mbuf chain,
936	 * calculating its length and finding the last mbuf.
937	 * If the adjustment only affects this mbuf, then just
938	 * adjust and return.  Otherwise, rescan and truncate
939	 * after the remaining size.
940	 */
941	count = 0;
942	m = mp;
943	for (;;) {
944		count += m->m_len;
945		if (m->m_next == NULL)
946			break;
947		m = m->m_next;
948	}
949	if (m->m_len > len) {
950		m->m_len -= len;
951		if (nul > 0) {
952			cp = mtod(m, caddr_t)+m->m_len-nul;
953			for (i = 0; i < nul; i++)
954				*cp++ = '\0';
955		}
956		return;
957	}
958	count -= len;
959	if (count < 0)
960		count = 0;
961	/*
962	 * Correct length for chain is "count".
963	 * Find the mbuf with last data, adjust its length,
964	 * and toss data from remaining mbufs on chain.
965	 */
966	for (m = mp; m; m = m->m_next) {
967		if (m->m_len >= count) {
968			m->m_len = count;
969			if (nul > 0) {
970				cp = mtod(m, caddr_t)+m->m_len-nul;
971				for (i = 0; i < nul; i++)
972					*cp++ = '\0';
973			}
974			if (m->m_next != NULL) {
975				m_freem(m->m_next);
976				m->m_next = NULL;
977			}
978			break;
979		}
980		count -= m->m_len;
981	}
982}
983
984/*
985 * Make these functions instead of macros, so that the kernel text size
986 * doesn't get too big...
987 */
988void
989nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
990    struct vattr *before_vap, int after_ret, struct vattr *after_vap,
991    struct mbuf **mbp, char **bposp)
992{
993	struct mbuf *mb = *mbp;
994	char *bpos = *bposp;
995	u_int32_t *tl;
996
997	if (before_ret) {
998		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
999		*tl = nfsrv_nfs_false;
1000	} else {
1001		tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
1002		*tl++ = nfsrv_nfs_true;
1003		txdr_hyper(before_vap->va_size, tl);
1004		tl += 2;
1005		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1006		tl += 2;
1007		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1008	}
1009	*bposp = bpos;
1010	*mbp = mb;
1011	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1012}
1013
1014void
1015nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
1016    struct vattr *after_vap, struct mbuf **mbp, char **bposp)
1017{
1018	struct mbuf *mb = *mbp;
1019	char *bpos = *bposp;
1020	u_int32_t *tl;
1021	struct nfs_fattr *fp;
1022
1023	if (after_ret) {
1024		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
1025		*tl = nfsrv_nfs_false;
1026	} else {
1027		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1028		*tl++ = nfsrv_nfs_true;
1029		fp = (struct nfs_fattr *)tl;
1030		nfsm_srvfattr(nfsd, after_vap, fp);
1031	}
1032	*mbp = mb;
1033	*bposp = bpos;
1034}
1035
1036void
1037nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1038    struct nfs_fattr *fp)
1039{
1040
1041	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1042	fp->fa_uid = txdr_unsigned(vap->va_uid);
1043	fp->fa_gid = txdr_unsigned(vap->va_gid);
1044	if (nfsd->nd_flag & ND_NFSV3) {
1045		fp->fa_type = vtonfsv3_type(vap->va_type);
1046		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1047		txdr_hyper(vap->va_size, &fp->fa3_size);
1048		txdr_hyper(vap->va_bytes, &fp->fa3_used);
1049		fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
1050		fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
1051		fp->fa3_fsid.nfsuquad[0] = 0;
1052		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1053		fp->fa3_fileid.nfsuquad[0] = 0;
1054		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1055		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1056		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1057		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1058	} else {
1059		fp->fa_type = vtonfsv2_type(vap->va_type);
1060		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1061		fp->fa2_size = txdr_unsigned(vap->va_size);
1062		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1063		if (vap->va_type == VFIFO)
1064			fp->fa2_rdev = 0xffffffff;
1065		else
1066			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1067		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1068		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1069		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1070		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1071		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1072		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1073	}
1074}
1075
1076/*
1077 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1078 * 	- look up fsid in mount list (if not found ret error)
1079 *	- get vp and export rights by calling VFS_FHTOVP()
1080 *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1081 *	- if not lockflag unlock it with VOP_UNLOCK()
1082 */
1083int
1084nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, int *vfslockedp,
1085    struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
1086    int *rdonlyp, int pubflag)
1087{
1088	struct thread *td = curthread; /* XXX */
1089	struct mount *mp;
1090	int i;
1091	struct ucred *credanon;
1092	int error, exflags;
1093#ifdef MNT_EXNORESPORT		/* XXX needs mountd and /etc/exports help yet */
1094	struct sockaddr_int *saddr;
1095#endif
1096	int vfslocked;
1097
1098	*vfslockedp = 0;
1099	*vpp = NULL;
1100
1101	if (nfs_ispublicfh(fhp)) {
1102		if (!pubflag || !nfs_pub.np_valid)
1103			return (ESTALE);
1104		fhp = &nfs_pub.np_handle;
1105	}
1106
1107	mp = vfs_getvfs(&fhp->fh_fsid);
1108	if (!mp)
1109		return (ESTALE);
1110	vfslocked = VFS_LOCK_GIANT(mp);
1111	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1112	if (error)
1113		goto out;
1114	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1115	if (error)
1116		goto out;
1117#ifdef MNT_EXNORESPORT
1118	if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1119		saddr = (struct sockaddr_in *)nam;
1120		if ((saddr->sin_family == AF_INET ||
1121		     saddr->sin_family == AF_INET6) &&
1122	/* same code for INET and INET6: sin*_port at same offet */
1123		    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1124			vput(*vpp);
1125			*vpp = NULL;
1126			error = NFSERR_AUTHERR | AUTH_TOOWEAK;
1127		}
1128	}
1129#endif
1130	/*
1131	 * Check/setup credentials.
1132	 */
1133	if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1134		cred->cr_uid = credanon->cr_uid;
1135		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1136			cred->cr_groups[i] = credanon->cr_groups[i];
1137		cred->cr_ngroups = i;
1138	}
1139	if (exflags & MNT_EXRDONLY)
1140		*rdonlyp = 1;
1141	else
1142		*rdonlyp = 0;
1143
1144	if (!lockflag)
1145		VOP_UNLOCK(*vpp, 0, td);
1146out:
1147	vfs_rel(mp);
1148	if (error) {
1149		VFS_UNLOCK_GIANT(vfslocked);
1150	} else
1151		*vfslockedp = vfslocked;
1152	return (error);
1153}
1154
1155
1156/*
1157 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1158 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1159 * transformed this to all zeroes in both cases, so check for it.
1160 */
1161int
1162nfs_ispublicfh(fhandle_t *fhp)
1163{
1164	char *cp = (char *)fhp;
1165	int i;
1166
1167	NFSD_LOCK_DONTCARE();
1168
1169	for (i = 0; i < NFSX_V3FH; i++)
1170		if (*cp++ != 0)
1171			return (FALSE);
1172	return (TRUE);
1173}
1174
1175/*
1176 * This function compares two net addresses by family and returns TRUE
1177 * if they are the same host.
1178 * If there is any doubt, return FALSE.
1179 * The AF_INET family is handled as a special case so that address mbufs
1180 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1181 */
1182int
1183netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
1184{
1185	struct sockaddr_in *inetaddr;
1186
1187	NFSD_LOCK_DONTCARE();
1188
1189	switch (family) {
1190	case AF_INET:
1191		inetaddr = (struct sockaddr_in *)nam;
1192		if (inetaddr->sin_family == AF_INET &&
1193		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1194			return (1);
1195		break;
1196#ifdef INET6
1197	case AF_INET6:
1198	{
1199		register struct sockaddr_in6 *inet6addr1, *inet6addr2;
1200
1201		inet6addr1 = (struct sockaddr_in6 *)nam;
1202		inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam;
1203	/* XXX - should test sin6_scope_id ? */
1204		if (inet6addr1->sin6_family == AF_INET6 &&
1205		    IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1206				       &inet6addr2->sin6_addr))
1207			return (1);
1208		break;
1209	}
1210#endif
1211	default:
1212		break;
1213	};
1214	return (0);
1215}
1216
1217/*
1218 * Map errnos to NFS error numbers. For Version 3 also filter out error
1219 * numbers not specified for the associated procedure.
1220 */
1221int
1222nfsrv_errmap(struct nfsrv_descript *nd, int err)
1223{
1224	const short *defaulterrp, *errp;
1225	int e;
1226
1227
1228	if (nd->nd_flag & ND_NFSV3) {
1229	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
1230		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1231		while (*++errp) {
1232			if (*errp == err)
1233				return (err);
1234			else if (*errp > err)
1235				break;
1236		}
1237		return ((int)*defaulterrp);
1238	    } else
1239		return (err & 0xffff);
1240	}
1241	e = 0;
1242	if (err <= ELAST)
1243		e = nfsrv_v2errmap[err - 1];
1244	if (e != 0)
1245		return (e);
1246	return (NFSERR_IO);
1247}
1248
1249/*
1250 * Sort the group list in increasing numerical order.
1251 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1252 *  that used to be here.)
1253 */
1254void
1255nfsrvw_sort(gid_t *list, int num)
1256{
1257	int i, j;
1258	gid_t v;
1259
1260	/* Insertion sort. */
1261	for (i = 1; i < num; i++) {
1262		v = list[i];
1263		/* find correct slot for value v, moving others up */
1264		for (j = i; --j >= 0 && v < list[j];)
1265			list[j + 1] = list[j];
1266		list[j + 1] = v;
1267	}
1268}
1269
1270/*
1271 * copy credentials making sure that the result can be compared with bcmp().
1272 */
1273void
1274nfsrv_setcred(struct ucred *incred, struct ucred *outcred)
1275{
1276	int i;
1277
1278	bzero((caddr_t)outcred, sizeof (struct ucred));
1279	refcount_init(&outcred->cr_ref, 1);
1280	outcred->cr_uid = incred->cr_uid;
1281	outcred->cr_ngroups = incred->cr_ngroups;
1282	for (i = 0; i < incred->cr_ngroups; i++)
1283		outcred->cr_groups[i] = incred->cr_groups[i];
1284	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1285}
1286
1287/*
1288 * Helper functions for macros.
1289 */
1290
1291void
1292nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
1293{
1294	u_int32_t *tl;
1295
1296	if (v3) {
1297		tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1298		*tl++ = txdr_unsigned(NFSX_V3FH);
1299		bcopy(f, tl, NFSX_V3FH);
1300	} else {
1301		tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1302		bcopy(f, tl, NFSX_V2FH);
1303	}
1304}
1305
1306void
1307nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
1308{
1309	u_int32_t *tl;
1310
1311	tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1312	*tl++ = nfsrv_nfs_true;
1313	*tl++ = txdr_unsigned(NFSX_V3FH);
1314	bcopy(f, tl, NFSX_V3FH);
1315}
1316
1317int
1318nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1319{
1320	u_int32_t *tl;
1321
1322	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1323	if (tl == NULL)
1324		return EBADRPC;
1325	*s = fxdr_unsigned(int32_t, *tl);
1326	if (*s > m || *s <= 0)
1327		return EBADRPC;
1328	return 0;
1329}
1330
1331int
1332nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1333{
1334	u_int32_t *tl;
1335
1336	NFSD_LOCK_DONTCARE();
1337
1338	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1339	if (tl == NULL)
1340		return EBADRPC;
1341	*s = fxdr_unsigned(int32_t, *tl);
1342	if (*s > m)
1343		return NFSERR_NAMETOL;
1344	if (*s <= 0)
1345		return EBADRPC;
1346	return 0;
1347}
1348
1349int
1350nfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1351{
1352	u_int32_t *tl;
1353
1354	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1355	if (tl == NULL)
1356		return EBADRPC;
1357	*s = fxdr_unsigned(int32_t, *tl);
1358	if (*s > m)
1359		return NFSERR_NAMETOL;
1360	if (*s < 0)
1361		return EBADRPC;
1362	return 0;
1363}
1364
1365void
1366nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
1367    char **bp, char **be, caddr_t bpos)
1368{
1369	struct mbuf *nmp;
1370
1371	NFSD_UNLOCK_ASSERT();
1372
1373	if (*bp >= *be) {
1374		if (*mp == mb)
1375			(*mp)->m_len += *bp - bpos;
1376		MGET(nmp, M_TRYWAIT, MT_DATA);
1377		MCLGET(nmp, M_TRYWAIT);
1378		nmp->m_len = NFSMSIZ(nmp);
1379		(*mp)->m_next = nmp;
1380		*mp = nmp;
1381		*bp = mtod(*mp, caddr_t);
1382		*be = *bp + (*mp)->m_len;
1383	}
1384	*tl = (u_int32_t *)*bp;
1385}
1386
1387int
1388nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
1389    caddr_t *dpos)
1390{
1391	u_int32_t *tl;
1392	int fhlen;
1393
1394	if (nfsd->nd_flag & ND_NFSV3) {
1395		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1396		if (tl == NULL)
1397			return EBADRPC;
1398		fhlen = fxdr_unsigned(int, *tl);
1399		if (fhlen != 0 && fhlen != NFSX_V3FH)
1400			return EBADRPC;
1401	} else {
1402		fhlen = NFSX_V2FH;
1403	}
1404	if (fhlen != 0) {
1405		tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos);
1406		if (tl == NULL)
1407			return EBADRPC;
1408		bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
1409	} else {
1410		bzero((caddr_t)(f), NFSX_V3FH);
1411	}
1412	return 0;
1413}
1414
1415int
1416nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
1417{
1418	u_int32_t *tl;
1419	int toclient = 0;
1420
1421	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1422	if (tl == NULL)
1423		return EBADRPC;
1424	if (*tl == nfsrv_nfs_true) {
1425		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1426		if (tl == NULL)
1427			return EBADRPC;
1428		(a)->va_mode = nfstov_mode(*tl);
1429	}
1430	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1431	if (tl == NULL)
1432		return EBADRPC;
1433	if (*tl == nfsrv_nfs_true) {
1434		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1435		if (tl == NULL)
1436			return EBADRPC;
1437		(a)->va_uid = fxdr_unsigned(uid_t, *tl);
1438	}
1439	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1440	if (tl == NULL)
1441		return EBADRPC;
1442	if (*tl == nfsrv_nfs_true) {
1443		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1444		if (tl == NULL)
1445			return EBADRPC;
1446		(a)->va_gid = fxdr_unsigned(gid_t, *tl);
1447	}
1448	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1449	if (tl == NULL)
1450		return EBADRPC;
1451	if (*tl == nfsrv_nfs_true) {
1452		tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1453		if (tl == NULL)
1454			return EBADRPC;
1455		(a)->va_size = fxdr_hyper(tl);
1456	}
1457	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1458	if (tl == NULL)
1459		return EBADRPC;
1460	switch (fxdr_unsigned(int, *tl)) {
1461	case NFSV3SATTRTIME_TOCLIENT:
1462		tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1463		if (tl == NULL)
1464			return EBADRPC;
1465		fxdr_nfsv3time(tl, &(a)->va_atime);
1466		toclient = 1;
1467		break;
1468	case NFSV3SATTRTIME_TOSERVER:
1469		getnanotime(&(a)->va_atime);
1470		a->va_vaflags |= VA_UTIMES_NULL;
1471		break;
1472	}
1473	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1474	if (tl == NULL)
1475		return EBADRPC;
1476	switch (fxdr_unsigned(int, *tl)) {
1477	case NFSV3SATTRTIME_TOCLIENT:
1478		tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1479		if (tl == NULL)
1480			return EBADRPC;
1481		fxdr_nfsv3time(tl, &(a)->va_mtime);
1482		a->va_vaflags &= ~VA_UTIMES_NULL;
1483		break;
1484	case NFSV3SATTRTIME_TOSERVER:
1485		getnanotime(&(a)->va_mtime);
1486		if (toclient == 0)
1487			a->va_vaflags |= VA_UTIMES_NULL;
1488		break;
1489	}
1490	return 0;
1491}
1492