nfs_srvsubs.c revision 171744
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 171744 2007-08-06 14:26:03Z 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	switch (type) {
530	case MOD_LOAD:
531		mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF);
532		nfsrv_rpc_vers = txdr_unsigned(RPC_VER2);
533		nfsrv_rpc_call = txdr_unsigned(RPC_CALL);
534		nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY);
535		nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
536		nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
537		nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
538		nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR);
539		nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
540		nfsrv_nfs_prog = txdr_unsigned(NFS_PROG);
541		nfsrv_nfs_true = txdr_unsigned(TRUE);
542		nfsrv_nfs_false = txdr_unsigned(FALSE);
543		nfsrv_nfs_xdrneg1 = txdr_unsigned(-1);
544		nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
545		if (nfsrv_ticks < 1)
546			nfsrv_ticks = 1;
547
548		nfsrv_initcache();	/* Init the server request cache */
549		NFSD_LOCK();
550		nfsrv_init(0);		/* Init server data structures */
551		callout_init(&nfsrv_callout, CALLOUT_MPSAFE);
552		NFSD_UNLOCK();
553		nfsrv_timer(0);
554
555		error = syscall_register(&nfssvc_offset, &nfssvc_sysent,
556		    &nfssvc_prev_sysent);
557		if (error)
558			break;
559		registered = 1;
560		break;
561
562	case MOD_UNLOAD:
563		if (nfsrv_numnfsd != 0) {
564			error = EBUSY;
565			break;
566		}
567
568		if (registered)
569			syscall_deregister(&nfssvc_offset, &nfssvc_prev_sysent);
570		callout_drain(&nfsrv_callout);
571		nfsrv_destroycache();	/* Free the server request cache */
572		nfsrv_destroycache();	/* Free the server request cache */
573		mtx_destroy(&nfsd_mtx);
574		break;
575	default:
576		error = EOPNOTSUPP;
577		break;
578	}
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	int dvfslocked;
623	int vfslocked;
624
625	vfslocked = 0;
626	dvfslocked = 0;
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	error = nfsrv_fhtovp(fhp, FALSE, &dp, &dvfslocked,
671	    ndp->ni_cnd.cn_cred, slp, nam, &rdonly, pubflag);
672	if (error)
673		goto out;
674	vfslocked = VFS_LOCK_GIANT(dp->v_mount);
675	if (dp->v_type != VDIR) {
676		vrele(dp);
677		error = ENOTDIR;
678		goto out;
679	}
680
681	if (rdonly)
682		cnp->cn_flags |= RDONLY;
683
684	/*
685	 * Set return directory.  Reference to dp is implicitly transfered
686	 * to the returned pointer
687	 */
688	*retdirp = dp;
689	if (v3) {
690		vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
691		*retdirattr_retp = VOP_GETATTR(dp, retdirattrp,
692			ndp->ni_cnd.cn_cred, td);
693		VOP_UNLOCK(dp, 0, td);
694	}
695
696	if (pubflag) {
697		/*
698		 * Oh joy. For WebNFS, handle those pesky '%' escapes,
699		 * and the 'native path' indicator.
700		 */
701		cp = uma_zalloc(namei_zone, M_WAITOK);
702		fromcp = cnp->cn_pnbuf;
703		tocp = cp;
704		if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
705			switch ((unsigned char)*fromcp) {
706			case WEBNFS_NATIVE_CHAR:
707				/*
708				 * 'Native' path for us is the same
709				 * as a path according to the NFS spec,
710				 * just skip the escape char.
711				 */
712				fromcp++;
713				break;
714			/*
715			 * More may be added in the future, range 0x80-0xff
716			 */
717			default:
718				error = EIO;
719				uma_zfree(namei_zone, cp);
720				goto out;
721			}
722		}
723		/*
724		 * Translate the '%' escapes, URL-style.
725		 */
726		while (*fromcp != '\0') {
727			if (*fromcp == WEBNFS_ESC_CHAR) {
728				if (fromcp[1] != '\0' && fromcp[2] != '\0') {
729					fromcp++;
730					*tocp++ = HEXSTRTOI(fromcp);
731					fromcp += 2;
732					continue;
733				} else {
734					error = ENOENT;
735					uma_zfree(namei_zone, cp);
736					goto out;
737				}
738			} else
739				*tocp++ = *fromcp++;
740		}
741		*tocp = '\0';
742		uma_zfree(namei_zone, cnp->cn_pnbuf);
743		cnp->cn_pnbuf = cp;
744	}
745
746	ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
747	ndp->ni_segflg = UIO_SYSSPACE;
748
749	if (pubflag) {
750		ndp->ni_rootdir = rootvnode;
751		ndp->ni_loopcnt = 0;
752		if (cnp->cn_pnbuf[0] == '/') {
753			int tvfslocked;
754
755			tvfslocked = VFS_LOCK_GIANT(rootvnode->v_mount);
756			VFS_UNLOCK_GIANT(vfslocked);
757			dp = rootvnode;
758			vfslocked = tvfslocked;
759		}
760	} else {
761		cnp->cn_flags |= NOCROSSMOUNT;
762	}
763
764	/*
765	 * Initialize for scan, set ni_startdir and bump ref on dp again
766	 * because lookup() will dereference ni_startdir.
767	 */
768
769	cnp->cn_thread = td;
770	VREF(dp);
771	ndp->ni_startdir = dp;
772
773	if (!lockleaf)
774		cnp->cn_flags |= LOCKLEAF;
775	for (;;) {
776		cnp->cn_nameptr = cnp->cn_pnbuf;
777		/*
778		 * Call lookup() to do the real work.  If an error occurs,
779		 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
780		 * we do not have to dereference anything before returning.
781		 * In either case ni_startdir will be dereferenced and NULLed
782		 * out.
783		 */
784		if (vfslocked)
785			ndp->ni_cnd.cn_flags |= GIANTHELD;
786		error = lookup(ndp);
787		vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
788		ndp->ni_cnd.cn_flags &= ~GIANTHELD;
789		if (error)
790			break;
791
792		/*
793		 * Check for encountering a symbolic link.  Trivial
794		 * termination occurs if no symlink encountered.
795		 * Note: zfree is safe because error is 0, so we will
796		 * not zfree it again when we break.
797		 */
798		if ((cnp->cn_flags & ISSYMLINK) == 0) {
799			if (cnp->cn_flags & (SAVENAME | SAVESTART))
800				cnp->cn_flags |= HASBUF;
801			else
802				uma_zfree(namei_zone, cnp->cn_pnbuf);
803			if (ndp->ni_vp && !lockleaf)
804				VOP_UNLOCK(ndp->ni_vp, 0, td);
805			break;
806		}
807
808		/*
809		 * Validate symlink
810		 */
811		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
812			VOP_UNLOCK(ndp->ni_dvp, 0, td);
813		if (!pubflag) {
814			error = EINVAL;
815			goto badlink2;
816		}
817
818		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
819			error = ELOOP;
820			goto badlink2;
821		}
822		if (ndp->ni_pathlen > 1)
823			cp = uma_zalloc(namei_zone, M_WAITOK);
824		else
825			cp = cnp->cn_pnbuf;
826		aiov.iov_base = cp;
827		aiov.iov_len = MAXPATHLEN;
828		auio.uio_iov = &aiov;
829		auio.uio_iovcnt = 1;
830		auio.uio_offset = 0;
831		auio.uio_rw = UIO_READ;
832		auio.uio_segflg = UIO_SYSSPACE;
833		auio.uio_td = NULL;
834		auio.uio_resid = MAXPATHLEN;
835		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
836		if (error) {
837		badlink1:
838			if (ndp->ni_pathlen > 1)
839				uma_zfree(namei_zone, cp);
840		badlink2:
841			vput(ndp->ni_vp);
842			vrele(ndp->ni_dvp);
843			break;
844		}
845		linklen = MAXPATHLEN - auio.uio_resid;
846		if (linklen == 0) {
847			error = ENOENT;
848			goto badlink1;
849		}
850		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
851			error = ENAMETOOLONG;
852			goto badlink1;
853		}
854
855		/*
856		 * Adjust or replace path
857		 */
858		if (ndp->ni_pathlen > 1) {
859			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
860			uma_zfree(namei_zone, cnp->cn_pnbuf);
861			cnp->cn_pnbuf = cp;
862		} else
863			cnp->cn_pnbuf[linklen] = '\0';
864		ndp->ni_pathlen += linklen;
865
866		/*
867		 * Cleanup refs for next loop and check if root directory
868		 * should replace current directory.  Normally ni_dvp
869		 * becomes the new base directory and is cleaned up when
870		 * we loop.  Explicitly null pointers after invalidation
871		 * to clarify operation.
872		 */
873		vput(ndp->ni_vp);
874		ndp->ni_vp = NULL;
875
876		if (cnp->cn_pnbuf[0] == '/') {
877			vrele(ndp->ni_dvp);
878			ndp->ni_dvp = ndp->ni_rootdir;
879			VREF(ndp->ni_dvp);
880		}
881		ndp->ni_startdir = ndp->ni_dvp;
882		ndp->ni_dvp = NULL;
883	}
884	if (!lockleaf)
885		cnp->cn_flags &= ~LOCKLEAF;
886	if (cnp->cn_flags & GIANTHELD) {
887		mtx_unlock(&Giant);
888		cnp->cn_flags &= ~GIANTHELD;
889	}
890
891	/*
892	 * nfs_namei() guarentees that fields will not contain garbage
893	 * whether an error occurs or not.  This allows the caller to track
894	 * cleanup state trivially.
895	 */
896out:
897	if (error) {
898		uma_zfree(namei_zone, cnp->cn_pnbuf);
899		ndp->ni_vp = NULL;
900		ndp->ni_dvp = NULL;
901		ndp->ni_startdir = NULL;
902		cnp->cn_flags &= ~HASBUF;
903		VFS_UNLOCK_GIANT(vfslocked);
904		vfslocked = 0;
905	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
906		ndp->ni_dvp = NULL;
907	}
908	/*
909	 * This differs from normal namei() in that even on failure we may
910	 * return with Giant held due to the dirp return.  Make sure we only
911	 * have not recursed however.  The calling code only expects to drop
912	 * one acquire.
913	 */
914	if (vfslocked || dvfslocked)
915		ndp->ni_cnd.cn_flags |= GIANTHELD;
916	if (vfslocked && dvfslocked)
917		VFS_UNLOCK_GIANT(vfslocked);
918	return (error);
919}
920
921/*
922 * A fiddled version of m_adj() that ensures null fill to a long
923 * boundary and only trims off the back end
924 */
925void
926nfsm_adj(struct mbuf *mp, int len, int nul)
927{
928	struct mbuf *m;
929	int count, i;
930	char *cp;
931
932	/*
933	 * Trim from tail.  Scan the mbuf chain,
934	 * calculating its length and finding the last mbuf.
935	 * If the adjustment only affects this mbuf, then just
936	 * adjust and return.  Otherwise, rescan and truncate
937	 * after the remaining size.
938	 */
939	count = 0;
940	m = mp;
941	for (;;) {
942		count += m->m_len;
943		if (m->m_next == NULL)
944			break;
945		m = m->m_next;
946	}
947	if (m->m_len > len) {
948		m->m_len -= len;
949		if (nul > 0) {
950			cp = mtod(m, caddr_t)+m->m_len-nul;
951			for (i = 0; i < nul; i++)
952				*cp++ = '\0';
953		}
954		return;
955	}
956	count -= len;
957	if (count < 0)
958		count = 0;
959	/*
960	 * Correct length for chain is "count".
961	 * Find the mbuf with last data, adjust its length,
962	 * and toss data from remaining mbufs on chain.
963	 */
964	for (m = mp; m; m = m->m_next) {
965		if (m->m_len >= count) {
966			m->m_len = count;
967			if (nul > 0) {
968				cp = mtod(m, caddr_t)+m->m_len-nul;
969				for (i = 0; i < nul; i++)
970					*cp++ = '\0';
971			}
972			if (m->m_next != NULL) {
973				m_freem(m->m_next);
974				m->m_next = NULL;
975			}
976			break;
977		}
978		count -= m->m_len;
979	}
980}
981
982/*
983 * Make these functions instead of macros, so that the kernel text size
984 * doesn't get too big...
985 */
986void
987nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
988    struct vattr *before_vap, int after_ret, struct vattr *after_vap,
989    struct mbuf **mbp, char **bposp)
990{
991	struct mbuf *mb = *mbp;
992	char *bpos = *bposp;
993	u_int32_t *tl;
994
995	if (before_ret) {
996		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
997		*tl = nfsrv_nfs_false;
998	} else {
999		tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
1000		*tl++ = nfsrv_nfs_true;
1001		txdr_hyper(before_vap->va_size, tl);
1002		tl += 2;
1003		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1004		tl += 2;
1005		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1006	}
1007	*bposp = bpos;
1008	*mbp = mb;
1009	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1010}
1011
1012void
1013nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
1014    struct vattr *after_vap, struct mbuf **mbp, char **bposp)
1015{
1016	struct mbuf *mb = *mbp;
1017	char *bpos = *bposp;
1018	u_int32_t *tl;
1019	struct nfs_fattr *fp;
1020
1021	if (after_ret) {
1022		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
1023		*tl = nfsrv_nfs_false;
1024	} else {
1025		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1026		*tl++ = nfsrv_nfs_true;
1027		fp = (struct nfs_fattr *)tl;
1028		nfsm_srvfattr(nfsd, after_vap, fp);
1029	}
1030	*mbp = mb;
1031	*bposp = bpos;
1032}
1033
1034void
1035nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1036    struct nfs_fattr *fp)
1037{
1038
1039	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1040	fp->fa_uid = txdr_unsigned(vap->va_uid);
1041	fp->fa_gid = txdr_unsigned(vap->va_gid);
1042	if (nfsd->nd_flag & ND_NFSV3) {
1043		fp->fa_type = vtonfsv3_type(vap->va_type);
1044		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1045		txdr_hyper(vap->va_size, &fp->fa3_size);
1046		txdr_hyper(vap->va_bytes, &fp->fa3_used);
1047		fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
1048		fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
1049		fp->fa3_fsid.nfsuquad[0] = 0;
1050		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1051		fp->fa3_fileid.nfsuquad[0] = 0;
1052		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1053		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1054		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1055		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1056	} else {
1057		fp->fa_type = vtonfsv2_type(vap->va_type);
1058		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1059		fp->fa2_size = txdr_unsigned(vap->va_size);
1060		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1061		if (vap->va_type == VFIFO)
1062			fp->fa2_rdev = 0xffffffff;
1063		else
1064			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1065		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1066		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1067		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1068		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1069		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1070		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1071	}
1072}
1073
1074/*
1075 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1076 * 	- look up fsid in mount list (if not found ret error)
1077 *	- get vp and export rights by calling VFS_FHTOVP()
1078 *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1079 *	- if not lockflag unlock it with VOP_UNLOCK()
1080 */
1081int
1082nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, int *vfslockedp,
1083    struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
1084    int *rdonlyp, int pubflag)
1085{
1086	struct thread *td = curthread; /* XXX */
1087	struct mount *mp;
1088	int i;
1089	struct ucred *credanon;
1090	int error, exflags;
1091#ifdef MNT_EXNORESPORT		/* XXX needs mountd and /etc/exports help yet */
1092	struct sockaddr_int *saddr;
1093#endif
1094	int vfslocked;
1095
1096	*vfslockedp = 0;
1097	*vpp = NULL;
1098
1099	if (nfs_ispublicfh(fhp)) {
1100		if (!pubflag || !nfs_pub.np_valid)
1101			return (ESTALE);
1102		fhp = &nfs_pub.np_handle;
1103	}
1104
1105	mp = vfs_getvfs(&fhp->fh_fsid);
1106	if (!mp)
1107		return (ESTALE);
1108	vfslocked = VFS_LOCK_GIANT(mp);
1109	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1110	if (error)
1111		goto out;
1112	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1113	if (error)
1114		goto out;
1115#ifdef MNT_EXNORESPORT
1116	if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1117		saddr = (struct sockaddr_in *)nam;
1118		if ((saddr->sin_family == AF_INET ||
1119		     saddr->sin_family == AF_INET6) &&
1120	/* same code for INET and INET6: sin*_port at same offet */
1121		    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1122			vput(*vpp);
1123			*vpp = NULL;
1124			error = NFSERR_AUTHERR | AUTH_TOOWEAK;
1125		}
1126	}
1127#endif
1128	/*
1129	 * Check/setup credentials.
1130	 */
1131	if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1132		cred->cr_uid = credanon->cr_uid;
1133		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1134			cred->cr_groups[i] = credanon->cr_groups[i];
1135		cred->cr_ngroups = i;
1136	}
1137	if (exflags & MNT_EXRDONLY)
1138		*rdonlyp = 1;
1139	else
1140		*rdonlyp = 0;
1141
1142	if (!lockflag)
1143		VOP_UNLOCK(*vpp, 0, td);
1144out:
1145	vfs_rel(mp);
1146	if (error) {
1147		VFS_UNLOCK_GIANT(vfslocked);
1148	} else
1149		*vfslockedp = vfslocked;
1150	return (error);
1151}
1152
1153
1154/*
1155 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1156 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1157 * transformed this to all zeroes in both cases, so check for it.
1158 */
1159int
1160nfs_ispublicfh(fhandle_t *fhp)
1161{
1162	char *cp = (char *)fhp;
1163	int i;
1164
1165	NFSD_LOCK_DONTCARE();
1166
1167	for (i = 0; i < NFSX_V3FH; i++)
1168		if (*cp++ != 0)
1169			return (FALSE);
1170	return (TRUE);
1171}
1172
1173/*
1174 * This function compares two net addresses by family and returns TRUE
1175 * if they are the same host.
1176 * If there is any doubt, return FALSE.
1177 * The AF_INET family is handled as a special case so that address mbufs
1178 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1179 */
1180int
1181netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
1182{
1183	struct sockaddr_in *inetaddr;
1184
1185	NFSD_LOCK_DONTCARE();
1186
1187	switch (family) {
1188	case AF_INET:
1189		inetaddr = (struct sockaddr_in *)nam;
1190		if (inetaddr->sin_family == AF_INET &&
1191		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1192			return (1);
1193		break;
1194#ifdef INET6
1195	case AF_INET6:
1196	{
1197		register struct sockaddr_in6 *inet6addr1, *inet6addr2;
1198
1199		inet6addr1 = (struct sockaddr_in6 *)nam;
1200		inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam;
1201	/* XXX - should test sin6_scope_id ? */
1202		if (inet6addr1->sin6_family == AF_INET6 &&
1203		    IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1204				       &inet6addr2->sin6_addr))
1205			return (1);
1206		break;
1207	}
1208#endif
1209	default:
1210		break;
1211	};
1212	return (0);
1213}
1214
1215/*
1216 * Map errnos to NFS error numbers. For Version 3 also filter out error
1217 * numbers not specified for the associated procedure.
1218 */
1219int
1220nfsrv_errmap(struct nfsrv_descript *nd, int err)
1221{
1222	const short *defaulterrp, *errp;
1223	int e;
1224
1225
1226	if (nd->nd_flag & ND_NFSV3) {
1227	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
1228		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1229		while (*++errp) {
1230			if (*errp == err)
1231				return (err);
1232			else if (*errp > err)
1233				break;
1234		}
1235		return ((int)*defaulterrp);
1236	    } else
1237		return (err & 0xffff);
1238	}
1239	e = 0;
1240	if (err <= ELAST)
1241		e = nfsrv_v2errmap[err - 1];
1242	if (e != 0)
1243		return (e);
1244	return (NFSERR_IO);
1245}
1246
1247/*
1248 * Sort the group list in increasing numerical order.
1249 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1250 *  that used to be here.)
1251 */
1252void
1253nfsrvw_sort(gid_t *list, int num)
1254{
1255	int i, j;
1256	gid_t v;
1257
1258	/* Insertion sort. */
1259	for (i = 1; i < num; i++) {
1260		v = list[i];
1261		/* find correct slot for value v, moving others up */
1262		for (j = i; --j >= 0 && v < list[j];)
1263			list[j + 1] = list[j];
1264		list[j + 1] = v;
1265	}
1266}
1267
1268/*
1269 * copy credentials making sure that the result can be compared with bcmp().
1270 */
1271void
1272nfsrv_setcred(struct ucred *incred, struct ucred *outcred)
1273{
1274	int i;
1275
1276	bzero((caddr_t)outcred, sizeof (struct ucred));
1277	refcount_init(&outcred->cr_ref, 1);
1278	outcred->cr_uid = incred->cr_uid;
1279	outcred->cr_ngroups = incred->cr_ngroups;
1280	for (i = 0; i < incred->cr_ngroups; i++)
1281		outcred->cr_groups[i] = incred->cr_groups[i];
1282	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1283}
1284
1285/*
1286 * Helper functions for macros.
1287 */
1288
1289void
1290nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
1291{
1292	u_int32_t *tl;
1293
1294	if (v3) {
1295		tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1296		*tl++ = txdr_unsigned(NFSX_V3FH);
1297		bcopy(f, tl, NFSX_V3FH);
1298	} else {
1299		tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1300		bcopy(f, tl, NFSX_V2FH);
1301	}
1302}
1303
1304void
1305nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
1306{
1307	u_int32_t *tl;
1308
1309	tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1310	*tl++ = nfsrv_nfs_true;
1311	*tl++ = txdr_unsigned(NFSX_V3FH);
1312	bcopy(f, tl, NFSX_V3FH);
1313}
1314
1315int
1316nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1317{
1318	u_int32_t *tl;
1319
1320	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1321	if (tl == NULL)
1322		return EBADRPC;
1323	*s = fxdr_unsigned(int32_t, *tl);
1324	if (*s > m || *s <= 0)
1325		return EBADRPC;
1326	return 0;
1327}
1328
1329int
1330nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1331{
1332	u_int32_t *tl;
1333
1334	NFSD_LOCK_DONTCARE();
1335
1336	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1337	if (tl == NULL)
1338		return EBADRPC;
1339	*s = fxdr_unsigned(int32_t, *tl);
1340	if (*s > m)
1341		return NFSERR_NAMETOL;
1342	if (*s <= 0)
1343		return EBADRPC;
1344	return 0;
1345}
1346
1347int
1348nfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1349{
1350	u_int32_t *tl;
1351
1352	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1353	if (tl == NULL)
1354		return EBADRPC;
1355	*s = fxdr_unsigned(int32_t, *tl);
1356	if (*s > m)
1357		return NFSERR_NAMETOL;
1358	if (*s < 0)
1359		return EBADRPC;
1360	return 0;
1361}
1362
1363void
1364nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
1365    char **bp, char **be, caddr_t bpos)
1366{
1367	struct mbuf *nmp;
1368
1369	NFSD_UNLOCK_ASSERT();
1370
1371	if (*bp >= *be) {
1372		if (*mp == mb)
1373			(*mp)->m_len += *bp - bpos;
1374		MGET(nmp, M_TRYWAIT, MT_DATA);
1375		MCLGET(nmp, M_TRYWAIT);
1376		nmp->m_len = NFSMSIZ(nmp);
1377		(*mp)->m_next = nmp;
1378		*mp = nmp;
1379		*bp = mtod(*mp, caddr_t);
1380		*be = *bp + (*mp)->m_len;
1381	}
1382	*tl = (u_int32_t *)*bp;
1383}
1384
1385int
1386nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
1387    caddr_t *dpos)
1388{
1389	u_int32_t *tl;
1390	int fhlen;
1391
1392	if (nfsd->nd_flag & ND_NFSV3) {
1393		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1394		if (tl == NULL)
1395			return EBADRPC;
1396		fhlen = fxdr_unsigned(int, *tl);
1397		if (fhlen != 0 && fhlen != NFSX_V3FH)
1398			return EBADRPC;
1399	} else {
1400		fhlen = NFSX_V2FH;
1401	}
1402	if (fhlen != 0) {
1403		tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos);
1404		if (tl == NULL)
1405			return EBADRPC;
1406		bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
1407	} else {
1408		bzero((caddr_t)(f), NFSX_V3FH);
1409	}
1410	return 0;
1411}
1412
1413int
1414nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
1415{
1416	u_int32_t *tl;
1417	int toclient = 0;
1418
1419	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1420	if (tl == NULL)
1421		return EBADRPC;
1422	if (*tl == nfsrv_nfs_true) {
1423		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1424		if (tl == NULL)
1425			return EBADRPC;
1426		(a)->va_mode = nfstov_mode(*tl);
1427	}
1428	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1429	if (tl == NULL)
1430		return EBADRPC;
1431	if (*tl == nfsrv_nfs_true) {
1432		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1433		if (tl == NULL)
1434			return EBADRPC;
1435		(a)->va_uid = fxdr_unsigned(uid_t, *tl);
1436	}
1437	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1438	if (tl == NULL)
1439		return EBADRPC;
1440	if (*tl == nfsrv_nfs_true) {
1441		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1442		if (tl == NULL)
1443			return EBADRPC;
1444		(a)->va_gid = fxdr_unsigned(gid_t, *tl);
1445	}
1446	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1447	if (tl == NULL)
1448		return EBADRPC;
1449	if (*tl == nfsrv_nfs_true) {
1450		tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1451		if (tl == NULL)
1452			return EBADRPC;
1453		(a)->va_size = fxdr_hyper(tl);
1454	}
1455	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1456	if (tl == NULL)
1457		return EBADRPC;
1458	switch (fxdr_unsigned(int, *tl)) {
1459	case NFSV3SATTRTIME_TOCLIENT:
1460		tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1461		if (tl == NULL)
1462			return EBADRPC;
1463		fxdr_nfsv3time(tl, &(a)->va_atime);
1464		toclient = 1;
1465		break;
1466	case NFSV3SATTRTIME_TOSERVER:
1467		getnanotime(&(a)->va_atime);
1468		a->va_vaflags |= VA_UTIMES_NULL;
1469		break;
1470	}
1471	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1472	if (tl == NULL)
1473		return EBADRPC;
1474	switch (fxdr_unsigned(int, *tl)) {
1475	case NFSV3SATTRTIME_TOCLIENT:
1476		tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1477		if (tl == NULL)
1478			return EBADRPC;
1479		fxdr_nfsv3time(tl, &(a)->va_mtime);
1480		a->va_vaflags &= ~VA_UTIMES_NULL;
1481		break;
1482	case NFSV3SATTRTIME_TOSERVER:
1483		getnanotime(&(a)->va_mtime);
1484		if (toclient == 0)
1485			a->va_vaflags |= VA_UTIMES_NULL;
1486		break;
1487	}
1488	return 0;
1489}
1490