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