]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/nfsserver/nfs_srvsubs.c
add -n option to suppress clearing the build tree and add -DNO_CLEAN
[FreeBSD/FreeBSD.git] / sys / nfsserver / nfs_srvsubs.c
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$");
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  */
82 u_int32_t nfsrv_nfs_xdrneg1;
83 u_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;
86 u_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false;
87
88 /* And other global data */
89 static 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
94 int nfsrv_ticks;
95
96 struct nfssvc_sockhead nfssvc_sockhead;
97 int nfssvc_sockhead_flag;
98 struct nfsd_head nfsd_head;
99 int nfsd_head_flag;
100
101 static int nfssvc_offset = SYS_nfssvc;
102 static struct sysent nfssvc_prev_sysent;
103 MAKE_SYSENT(nfssvc);
104
105 struct mtx nfsd_mtx;
106
107 /*
108  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
109  */
110 const 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  */
139 const 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  */
170 static 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  */
199 static const short nfsv3err_null[] = {
200         0,
201         0,
202 };
203
204 static const short nfsv3err_getattr[] = {
205         NFSERR_IO,
206         NFSERR_IO,
207         NFSERR_STALE,
208         NFSERR_BADHANDLE,
209         NFSERR_SERVERFAULT,
210         0,
211 };
212
213 static 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
229 static 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
242 static const short nfsv3err_access[] = {
243         NFSERR_IO,
244         NFSERR_IO,
245         NFSERR_STALE,
246         NFSERR_BADHANDLE,
247         NFSERR_SERVERFAULT,
248         0,
249 };
250
251 static 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
263 static 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
275 static 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
290 static 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
307 static 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
324 static 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
341 static 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
359 static 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
373 static 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
391 static 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
414 static 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
434 static 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
447 static 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
461 static const short nfsv3err_fsstat[] = {
462         NFSERR_IO,
463         NFSERR_IO,
464         NFSERR_STALE,
465         NFSERR_BADHANDLE,
466         NFSERR_SERVERFAULT,
467         0,
468 };
469
470 static const short nfsv3err_fsinfo[] = {
471         NFSERR_STALE,
472         NFSERR_STALE,
473         NFSERR_BADHANDLE,
474         NFSERR_SERVERFAULT,
475         0,
476 };
477
478 static const short nfsv3err_pathconf[] = {
479         NFSERR_STALE,
480         NFSERR_STALE,
481         NFSERR_BADHANDLE,
482         NFSERR_SERVERFAULT,
483         0,
484 };
485
486 static const short nfsv3err_commit[] = {
487         NFSERR_IO,
488         NFSERR_IO,
489         NFSERR_STALE,
490         NFSERR_BADHANDLE,
491         NFSERR_SERVERFAULT,
492         0,
493 };
494
495 static 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  */
523 static int
524 nfsrv_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                 mtx_destroy(&nfsd_mtx);
573                 break;
574         default:
575                 error = EOPNOTSUPP;
576                 break;
577         }
578         return error;
579 }
580 static moduledata_t nfsserver_mod = {
581         "nfsserver",
582         nfsrv_modevent,
583         NULL,
584 };
585 DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
586
587 /* So that loader and kldload(2) can find us, wherever we are.. */
588 MODULE_VERSION(nfsserver, 1);
589
590 /*
591  * Set up nameidata for a lookup() call and do it.
592  *
593  * If pubflag is set, this call is done for a lookup operation on the
594  * public filehandle. In that case we allow crossing mountpoints and
595  * absolute pathnames. However, the caller is expected to check that
596  * the lookup result is within the public fs, and deny access if
597  * it is not.
598  *
599  * nfs_namei() clears out garbage fields that namei() might leave garbage.
600  * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
601  * error occurs but the parent was not requested.
602  *
603  * dirp may be set whether an error is returned or not, and must be
604  * released by the caller.
605  */
606 int
607 nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
608     struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp,
609     caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp,
610     int *retdirattr_retp, int pubflag)
611 {
612         int i, rem;
613         struct mbuf *md;
614         char *fromcp, *tocp, *cp;
615         struct iovec aiov;
616         struct uio auio;
617         struct vnode *dp;
618         int error, rdonly, linklen;
619         struct componentname *cnp = &ndp->ni_cnd;
620         int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0;
621         int dvfslocked;
622         int vfslocked;
623
624         vfslocked = 0;
625         dvfslocked = 0;
626         *retdirp = NULL;
627         cnp->cn_flags |= NOMACCHECK;
628         cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
629
630         /*
631          * Copy the name from the mbuf list to ndp->ni_pnbuf
632          * and set the various ndp fields appropriately.
633          */
634         fromcp = *dposp;
635         tocp = cnp->cn_pnbuf;
636         md = *mdp;
637         rem = mtod(md, caddr_t) + md->m_len - fromcp;
638         for (i = 0; i < len; i++) {
639                 while (rem == 0) {
640                         md = md->m_next;
641                         if (md == NULL) {
642                                 error = EBADRPC;
643                                 goto out;
644                         }
645                         fromcp = mtod(md, caddr_t);
646                         rem = md->m_len;
647                 }
648                 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
649                         error = EACCES;
650                         goto out;
651                 }
652                 *tocp++ = *fromcp++;
653                 rem--;
654         }
655         *tocp = '\0';
656         *mdp = md;
657         *dposp = fromcp;
658         len = nfsm_rndup(len)-len;
659         if (len > 0) {
660                 if (rem >= len)
661                         *dposp += len;
662                 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
663                         goto out;
664         }
665
666         /*
667          * Extract and set starting directory.
668          */
669         error = nfsrv_fhtovp(fhp, FALSE, &dp, &dvfslocked,
670             ndp->ni_cnd.cn_cred, slp, nam, &rdonly, pubflag);
671         if (error)
672                 goto out;
673         vfslocked = VFS_LOCK_GIANT(dp->v_mount);
674         if (dp->v_type != VDIR) {
675                 vrele(dp);
676                 error = ENOTDIR;
677                 goto out;
678         }
679
680         if (rdonly)
681                 cnp->cn_flags |= RDONLY;
682
683         /*
684          * Set return directory.  Reference to dp is implicitly transfered
685          * to the returned pointer
686          */
687         *retdirp = dp;
688         if (v3) {
689                 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
690                 *retdirattr_retp = VOP_GETATTR(dp, retdirattrp,
691                         ndp->ni_cnd.cn_cred);
692                 VOP_UNLOCK(dp, 0);
693         }
694
695         if (pubflag) {
696                 /*
697                  * Oh joy. For WebNFS, handle those pesky '%' escapes,
698                  * and the 'native path' indicator.
699                  */
700                 cp = uma_zalloc(namei_zone, M_WAITOK);
701                 fromcp = cnp->cn_pnbuf;
702                 tocp = cp;
703                 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
704                         switch ((unsigned char)*fromcp) {
705                         case WEBNFS_NATIVE_CHAR:
706                                 /*
707                                  * 'Native' path for us is the same
708                                  * as a path according to the NFS spec,
709                                  * just skip the escape char.
710                                  */
711                                 fromcp++;
712                                 break;
713                         /*
714                          * More may be added in the future, range 0x80-0xff
715                          */
716                         default:
717                                 error = EIO;
718                                 uma_zfree(namei_zone, cp);
719                                 goto out;
720                         }
721                 }
722                 /*
723                  * Translate the '%' escapes, URL-style.
724                  */
725                 while (*fromcp != '\0') {
726                         if (*fromcp == WEBNFS_ESC_CHAR) {
727                                 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
728                                         fromcp++;
729                                         *tocp++ = HEXSTRTOI(fromcp);
730                                         fromcp += 2;
731                                         continue;
732                                 } else {
733                                         error = ENOENT;
734                                         uma_zfree(namei_zone, cp);
735                                         goto out;
736                                 }
737                         } else
738                                 *tocp++ = *fromcp++;
739                 }
740                 *tocp = '\0';
741                 uma_zfree(namei_zone, cnp->cn_pnbuf);
742                 cnp->cn_pnbuf = cp;
743         }
744
745         ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
746         ndp->ni_segflg = UIO_SYSSPACE;
747
748         if (pubflag) {
749                 ndp->ni_rootdir = rootvnode;
750                 ndp->ni_loopcnt = 0;
751                 if (cnp->cn_pnbuf[0] == '/') {
752                         int tvfslocked;
753
754                         tvfslocked = VFS_LOCK_GIANT(rootvnode->v_mount);
755                         VFS_UNLOCK_GIANT(vfslocked);
756                         dp = rootvnode;
757                         vfslocked = tvfslocked;
758                 }
759         } else {
760                 cnp->cn_flags |= NOCROSSMOUNT;
761         }
762
763         /*
764          * Initialize for scan, set ni_startdir and bump ref on dp again
765          * because lookup() will dereference ni_startdir.
766          */
767
768         cnp->cn_thread = curthread;
769         VREF(dp);
770         ndp->ni_startdir = dp;
771
772         if (!lockleaf)
773                 cnp->cn_flags |= LOCKLEAF;
774         for (;;) {
775                 cnp->cn_nameptr = cnp->cn_pnbuf;
776                 /*
777                  * Call lookup() to do the real work.  If an error occurs,
778                  * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
779                  * we do not have to dereference anything before returning.
780                  * In either case ni_startdir will be dereferenced and NULLed
781                  * out.
782                  */
783                 if (vfslocked)
784                         ndp->ni_cnd.cn_flags |= GIANTHELD;
785                 error = lookup(ndp);
786                 vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
787                 ndp->ni_cnd.cn_flags &= ~GIANTHELD;
788                 if (error)
789                         break;
790
791                 /*
792                  * Check for encountering a symbolic link.  Trivial
793                  * termination occurs if no symlink encountered.
794                  * Note: zfree is safe because error is 0, so we will
795                  * not zfree it again when we break.
796                  */
797                 if ((cnp->cn_flags & ISSYMLINK) == 0) {
798                         if (cnp->cn_flags & (SAVENAME | SAVESTART))
799                                 cnp->cn_flags |= HASBUF;
800                         else
801                                 uma_zfree(namei_zone, cnp->cn_pnbuf);
802                         if (ndp->ni_vp && !lockleaf)
803                                 VOP_UNLOCK(ndp->ni_vp, 0);
804                         break;
805                 }
806
807                 /*
808                  * Validate symlink
809                  */
810                 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
811                         VOP_UNLOCK(ndp->ni_dvp, 0);
812                 if (!pubflag) {
813                         error = EINVAL;
814                         goto badlink2;
815                 }
816
817                 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
818                         error = ELOOP;
819                         goto badlink2;
820                 }
821                 if (ndp->ni_pathlen > 1)
822                         cp = uma_zalloc(namei_zone, M_WAITOK);
823                 else
824                         cp = cnp->cn_pnbuf;
825                 aiov.iov_base = cp;
826                 aiov.iov_len = MAXPATHLEN;
827                 auio.uio_iov = &aiov;
828                 auio.uio_iovcnt = 1;
829                 auio.uio_offset = 0;
830                 auio.uio_rw = UIO_READ;
831                 auio.uio_segflg = UIO_SYSSPACE;
832                 auio.uio_td = NULL;
833                 auio.uio_resid = MAXPATHLEN;
834                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
835                 if (error) {
836                 badlink1:
837                         if (ndp->ni_pathlen > 1)
838                                 uma_zfree(namei_zone, cp);
839                 badlink2:
840                         vput(ndp->ni_vp);
841                         vrele(ndp->ni_dvp);
842                         break;
843                 }
844                 linklen = MAXPATHLEN - auio.uio_resid;
845                 if (linklen == 0) {
846                         error = ENOENT;
847                         goto badlink1;
848                 }
849                 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
850                         error = ENAMETOOLONG;
851                         goto badlink1;
852                 }
853
854                 /*
855                  * Adjust or replace path
856                  */
857                 if (ndp->ni_pathlen > 1) {
858                         bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
859                         uma_zfree(namei_zone, cnp->cn_pnbuf);
860                         cnp->cn_pnbuf = cp;
861                 } else
862                         cnp->cn_pnbuf[linklen] = '\0';
863                 ndp->ni_pathlen += linklen;
864
865                 /*
866                  * Cleanup refs for next loop and check if root directory
867                  * should replace current directory.  Normally ni_dvp
868                  * becomes the new base directory and is cleaned up when
869                  * we loop.  Explicitly null pointers after invalidation
870                  * to clarify operation.
871                  */
872                 vput(ndp->ni_vp);
873                 ndp->ni_vp = NULL;
874
875                 if (cnp->cn_pnbuf[0] == '/') {
876                         vrele(ndp->ni_dvp);
877                         ndp->ni_dvp = ndp->ni_rootdir;
878                         VREF(ndp->ni_dvp);
879                 }
880                 ndp->ni_startdir = ndp->ni_dvp;
881                 ndp->ni_dvp = NULL;
882         }
883         if (!lockleaf)
884                 cnp->cn_flags &= ~LOCKLEAF;
885         if (cnp->cn_flags & GIANTHELD) {
886                 mtx_unlock(&Giant);
887                 cnp->cn_flags &= ~GIANTHELD;
888         }
889
890         /*
891          * nfs_namei() guarentees that fields will not contain garbage
892          * whether an error occurs or not.  This allows the caller to track
893          * cleanup state trivially.
894          */
895 out:
896         if (error) {
897                 uma_zfree(namei_zone, cnp->cn_pnbuf);
898                 ndp->ni_vp = NULL;
899                 ndp->ni_dvp = NULL;
900                 ndp->ni_startdir = NULL;
901                 cnp->cn_flags &= ~HASBUF;
902                 VFS_UNLOCK_GIANT(vfslocked);
903                 vfslocked = 0;
904         } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
905                 ndp->ni_dvp = NULL;
906         }
907         /*
908          * This differs from normal namei() in that even on failure we may
909          * return with Giant held due to the dirp return.  Make sure we only
910          * have not recursed however.  The calling code only expects to drop
911          * one acquire.
912          */
913         if (vfslocked || dvfslocked)
914                 ndp->ni_cnd.cn_flags |= GIANTHELD;
915         if (vfslocked && dvfslocked)
916                 VFS_UNLOCK_GIANT(vfslocked);
917         return (error);
918 }
919
920 /*
921  * A fiddled version of m_adj() that ensures null fill to a long
922  * boundary and only trims off the back end
923  */
924 void
925 nfsm_adj(struct mbuf *mp, int len, int nul)
926 {
927         struct mbuf *m;
928         int count, i;
929         char *cp;
930
931         /*
932          * Trim from tail.  Scan the mbuf chain,
933          * calculating its length and finding the last mbuf.
934          * If the adjustment only affects this mbuf, then just
935          * adjust and return.  Otherwise, rescan and truncate
936          * after the remaining size.
937          */
938         count = 0;
939         m = mp;
940         for (;;) {
941                 count += m->m_len;
942                 if (m->m_next == NULL)
943                         break;
944                 m = m->m_next;
945         }
946         if (m->m_len > len) {
947                 m->m_len -= len;
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                 return;
954         }
955         count -= len;
956         if (count < 0)
957                 count = 0;
958         /*
959          * Correct length for chain is "count".
960          * Find the mbuf with last data, adjust its length,
961          * and toss data from remaining mbufs on chain.
962          */
963         for (m = mp; m; m = m->m_next) {
964                 if (m->m_len >= count) {
965                         m->m_len = count;
966                         if (nul > 0) {
967                                 cp = mtod(m, caddr_t)+m->m_len-nul;
968                                 for (i = 0; i < nul; i++)
969                                         *cp++ = '\0';
970                         }
971                         if (m->m_next != NULL) {
972                                 m_freem(m->m_next);
973                                 m->m_next = NULL;
974                         }
975                         break;
976                 }
977                 count -= m->m_len;
978         }
979 }
980
981 /*
982  * Make these functions instead of macros, so that the kernel text size
983  * doesn't get too big...
984  */
985 void
986 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
987     struct vattr *before_vap, int after_ret, struct vattr *after_vap,
988     struct mbuf **mbp, char **bposp)
989 {
990         struct mbuf *mb = *mbp;
991         char *bpos = *bposp;
992         u_int32_t *tl;
993
994         if (before_ret) {
995                 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
996                 *tl = nfsrv_nfs_false;
997         } else {
998                 tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
999                 *tl++ = nfsrv_nfs_true;
1000                 txdr_hyper(before_vap->va_size, tl);
1001                 tl += 2;
1002                 txdr_nfsv3time(&(before_vap->va_mtime), tl);
1003                 tl += 2;
1004                 txdr_nfsv3time(&(before_vap->va_ctime), tl);
1005         }
1006         *bposp = bpos;
1007         *mbp = mb;
1008         nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1009 }
1010
1011 void
1012 nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
1013     struct vattr *after_vap, struct mbuf **mbp, char **bposp)
1014 {
1015         struct mbuf *mb = *mbp;
1016         char *bpos = *bposp;
1017         u_int32_t *tl;
1018         struct nfs_fattr *fp;
1019
1020         if (after_ret) {
1021                 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
1022                 *tl = nfsrv_nfs_false;
1023         } else {
1024                 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1025                 *tl++ = nfsrv_nfs_true;
1026                 fp = (struct nfs_fattr *)tl;
1027                 nfsm_srvfattr(nfsd, after_vap, fp);
1028         }
1029         *mbp = mb;
1030         *bposp = bpos;
1031 }
1032
1033 void
1034 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1035     struct nfs_fattr *fp)
1036 {
1037
1038         fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1039         fp->fa_uid = txdr_unsigned(vap->va_uid);
1040         fp->fa_gid = txdr_unsigned(vap->va_gid);
1041         if (nfsd->nd_flag & ND_NFSV3) {
1042                 fp->fa_type = vtonfsv3_type(vap->va_type);
1043                 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1044                 txdr_hyper(vap->va_size, &fp->fa3_size);
1045                 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1046                 fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
1047                 fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
1048                 fp->fa3_fsid.nfsuquad[0] = 0;
1049                 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1050                 fp->fa3_fileid.nfsuquad[0] = 0;
1051                 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1052                 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1053                 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1054                 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1055         } else {
1056                 fp->fa_type = vtonfsv2_type(vap->va_type);
1057                 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1058                 fp->fa2_size = txdr_unsigned(vap->va_size);
1059                 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1060                 if (vap->va_type == VFIFO)
1061                         fp->fa2_rdev = 0xffffffff;
1062                 else
1063                         fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1064                 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1065                 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1066                 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1067                 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1068                 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1069                 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1070         }
1071 }
1072
1073 /*
1074  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1075  *      - look up fsid in mount list (if not found ret error)
1076  *      - get vp and export rights by calling VFS_FHTOVP()
1077  *      - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1078  *      - if not lockflag unlock it with VOP_UNLOCK()
1079  */
1080 int
1081 nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, int *vfslockedp,
1082     struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
1083     int *rdonlyp, int pubflag)
1084 {
1085         struct mount *mp;
1086         int i;
1087         struct ucred *credanon;
1088         int error, exflags;
1089 #ifdef MNT_EXNORESPORT          /* XXX needs mountd and /etc/exports help yet */
1090         struct sockaddr_int *saddr;
1091 #endif
1092         int vfslocked;
1093
1094         *vfslockedp = 0;
1095         *vpp = NULL;
1096
1097         if (nfs_ispublicfh(fhp)) {
1098                 if (!pubflag || !nfs_pub.np_valid)
1099                         return (ESTALE);
1100                 fhp = &nfs_pub.np_handle;
1101         }
1102
1103         mp = vfs_getvfs(&fhp->fh_fsid);
1104         if (!mp)
1105                 return (ESTALE);
1106         vfslocked = VFS_LOCK_GIANT(mp);
1107         error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1108         if (error)
1109                 goto out;
1110         error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1111         if (error)
1112                 goto out;
1113 #ifdef MNT_EXNORESPORT
1114         if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1115                 saddr = (struct sockaddr_in *)nam;
1116                 if ((saddr->sin_family == AF_INET ||
1117                      saddr->sin_family == AF_INET6) &&
1118         /* same code for INET and INET6: sin*_port at same offet */
1119                     ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1120                         vput(*vpp);
1121                         *vpp = NULL;
1122                         error = NFSERR_AUTHERR | AUTH_TOOWEAK;
1123                 }
1124         }
1125 #endif
1126         /*
1127          * Check/setup credentials.
1128          */
1129         if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1130                 cred->cr_uid = credanon->cr_uid;
1131                 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1132                         cred->cr_groups[i] = credanon->cr_groups[i];
1133                 cred->cr_ngroups = i;
1134         }
1135         if (exflags & MNT_EXRDONLY)
1136                 *rdonlyp = 1;
1137         else
1138                 *rdonlyp = 0;
1139
1140         if (!lockflag)
1141                 VOP_UNLOCK(*vpp, 0);
1142 out:
1143         vfs_rel(mp);
1144         if (error) {
1145                 VFS_UNLOCK_GIANT(vfslocked);
1146         } else
1147                 *vfslockedp = vfslocked;
1148         return (error);
1149 }
1150
1151
1152 /*
1153  * WebNFS: check if a filehandle is a public filehandle. For v3, this
1154  * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1155  * transformed this to all zeroes in both cases, so check for it.
1156  */
1157 int
1158 nfs_ispublicfh(fhandle_t *fhp)
1159 {
1160         char *cp = (char *)fhp;
1161         int i;
1162
1163         NFSD_LOCK_DONTCARE();
1164
1165         for (i = 0; i < NFSX_V3FH; i++)
1166                 if (*cp++ != 0)
1167                         return (FALSE);
1168         return (TRUE);
1169 }
1170
1171 /*
1172  * This function compares two net addresses by family and returns TRUE
1173  * if they are the same host.
1174  * If there is any doubt, return FALSE.
1175  * The AF_INET family is handled as a special case so that address mbufs
1176  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1177  */
1178 int
1179 netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
1180 {
1181         struct sockaddr_in *inetaddr;
1182
1183         NFSD_LOCK_DONTCARE();
1184
1185         switch (family) {
1186         case AF_INET:
1187                 inetaddr = (struct sockaddr_in *)nam;
1188                 if (inetaddr->sin_family == AF_INET &&
1189                     inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1190                         return (1);
1191                 break;
1192 #ifdef INET6
1193         case AF_INET6:
1194         {
1195                 register struct sockaddr_in6 *inet6addr1, *inet6addr2;
1196
1197                 inet6addr1 = (struct sockaddr_in6 *)nam;
1198                 inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam;
1199         /* XXX - should test sin6_scope_id ? */
1200                 if (inet6addr1->sin6_family == AF_INET6 &&
1201                     IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1202                                        &inet6addr2->sin6_addr))
1203                         return (1);
1204                 break;
1205         }
1206 #endif
1207         default:
1208                 break;
1209         };
1210         return (0);
1211 }
1212
1213 /*
1214  * Map errnos to NFS error numbers. For Version 3 also filter out error
1215  * numbers not specified for the associated procedure.
1216  */
1217 int
1218 nfsrv_errmap(struct nfsrv_descript *nd, int err)
1219 {
1220         const short *defaulterrp, *errp;
1221         int e;
1222
1223
1224         if (nd->nd_flag & ND_NFSV3) {
1225             if (nd->nd_procnum <= NFSPROC_COMMIT) {
1226                 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1227                 while (*++errp) {
1228                         if (*errp == err)
1229                                 return (err);
1230                         else if (*errp > err)
1231                                 break;
1232                 }
1233                 return ((int)*defaulterrp);
1234             } else
1235                 return (err & 0xffff);
1236         }
1237         e = 0;
1238         if (err <= ELAST)
1239                 e = nfsrv_v2errmap[err - 1];
1240         if (e != 0)
1241                 return (e);
1242         return (NFSERR_IO);
1243 }
1244
1245 /*
1246  * Sort the group list in increasing numerical order.
1247  * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1248  *  that used to be here.)
1249  */
1250 void
1251 nfsrvw_sort(gid_t *list, int num)
1252 {
1253         int i, j;
1254         gid_t v;
1255
1256         /* Insertion sort. */
1257         for (i = 1; i < num; i++) {
1258                 v = list[i];
1259                 /* find correct slot for value v, moving others up */
1260                 for (j = i; --j >= 0 && v < list[j];)
1261                         list[j + 1] = list[j];
1262                 list[j + 1] = v;
1263         }
1264 }
1265
1266 /*
1267  * Helper functions for macros.
1268  */
1269
1270 void
1271 nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
1272 {
1273         u_int32_t *tl;
1274
1275         if (v3) {
1276                 tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1277                 *tl++ = txdr_unsigned(NFSX_V3FH);
1278                 bcopy(f, tl, NFSX_V3FH);
1279         } else {
1280                 tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1281                 bcopy(f, tl, NFSX_V2FH);
1282         }
1283 }
1284
1285 void
1286 nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
1287 {
1288         u_int32_t *tl;
1289
1290         tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1291         *tl++ = nfsrv_nfs_true;
1292         *tl++ = txdr_unsigned(NFSX_V3FH);
1293         bcopy(f, tl, NFSX_V3FH);
1294 }
1295
1296 int
1297 nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1298 {
1299         u_int32_t *tl;
1300
1301         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1302         if (tl == NULL)
1303                 return EBADRPC;
1304         *s = fxdr_unsigned(int32_t, *tl);
1305         if (*s > m || *s <= 0)
1306                 return EBADRPC;
1307         return 0;
1308 }
1309
1310 int
1311 nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1312 {
1313         u_int32_t *tl;
1314
1315         NFSD_LOCK_DONTCARE();
1316
1317         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1318         if (tl == NULL)
1319                 return EBADRPC;
1320         *s = fxdr_unsigned(int32_t, *tl);
1321         if (*s > m)
1322                 return NFSERR_NAMETOL;
1323         if (*s <= 0)
1324                 return EBADRPC;
1325         return 0;
1326 }
1327
1328 int
1329 nfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1330 {
1331         u_int32_t *tl;
1332
1333         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1334         if (tl == NULL)
1335                 return EBADRPC;
1336         *s = fxdr_unsigned(int32_t, *tl);
1337         if (*s > m)
1338                 return NFSERR_NAMETOL;
1339         if (*s < 0)
1340                 return EBADRPC;
1341         return 0;
1342 }
1343
1344 void
1345 nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
1346     char **bp, char **be, caddr_t bpos)
1347 {
1348         struct mbuf *nmp;
1349
1350         NFSD_UNLOCK_ASSERT();
1351
1352         if (*bp >= *be) {
1353                 if (*mp == mb)
1354                         (*mp)->m_len += *bp - bpos;
1355                 MGET(nmp, M_WAIT, MT_DATA);
1356                 MCLGET(nmp, M_WAIT);
1357                 nmp->m_len = NFSMSIZ(nmp);
1358                 (*mp)->m_next = nmp;
1359                 *mp = nmp;
1360                 *bp = mtod(*mp, caddr_t);
1361                 *be = *bp + (*mp)->m_len;
1362         }
1363         *tl = (u_int32_t *)*bp;
1364 }
1365
1366 int
1367 nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
1368     caddr_t *dpos)
1369 {
1370         u_int32_t *tl;
1371         int fhlen;
1372
1373         if (nfsd->nd_flag & ND_NFSV3) {
1374                 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1375                 if (tl == NULL)
1376                         return EBADRPC;
1377                 fhlen = fxdr_unsigned(int, *tl);
1378                 if (fhlen != 0 && fhlen != NFSX_V3FH)
1379                         return EBADRPC;
1380         } else {
1381                 fhlen = NFSX_V2FH;
1382         }
1383         if (fhlen != 0) {
1384                 tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos);
1385                 if (tl == NULL)
1386                         return EBADRPC;
1387                 bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
1388         } else {
1389                 bzero((caddr_t)(f), NFSX_V3FH);
1390         }
1391         return 0;
1392 }
1393
1394 int
1395 nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
1396 {
1397         u_int32_t *tl;
1398         int toclient = 0;
1399
1400         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1401         if (tl == NULL)
1402                 return EBADRPC;
1403         if (*tl == nfsrv_nfs_true) {
1404                 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1405                 if (tl == NULL)
1406                         return EBADRPC;
1407                 (a)->va_mode = nfstov_mode(*tl);
1408         }
1409         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1410         if (tl == NULL)
1411                 return EBADRPC;
1412         if (*tl == nfsrv_nfs_true) {
1413                 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1414                 if (tl == NULL)
1415                         return EBADRPC;
1416                 (a)->va_uid = fxdr_unsigned(uid_t, *tl);
1417         }
1418         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1419         if (tl == NULL)
1420                 return EBADRPC;
1421         if (*tl == nfsrv_nfs_true) {
1422                 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1423                 if (tl == NULL)
1424                         return EBADRPC;
1425                 (a)->va_gid = fxdr_unsigned(gid_t, *tl);
1426         }
1427         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1428         if (tl == NULL)
1429                 return EBADRPC;
1430         if (*tl == nfsrv_nfs_true) {
1431                 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1432                 if (tl == NULL)
1433                         return EBADRPC;
1434                 (a)->va_size = fxdr_hyper(tl);
1435         }
1436         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1437         if (tl == NULL)
1438                 return EBADRPC;
1439         switch (fxdr_unsigned(int, *tl)) {
1440         case NFSV3SATTRTIME_TOCLIENT:
1441                 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1442                 if (tl == NULL)
1443                         return EBADRPC;
1444                 fxdr_nfsv3time(tl, &(a)->va_atime);
1445                 toclient = 1;
1446                 break;
1447         case NFSV3SATTRTIME_TOSERVER:
1448                 getnanotime(&(a)->va_atime);
1449                 a->va_vaflags |= VA_UTIMES_NULL;
1450                 break;
1451         }
1452         tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1453         if (tl == NULL)
1454                 return EBADRPC;
1455         switch (fxdr_unsigned(int, *tl)) {
1456         case NFSV3SATTRTIME_TOCLIENT:
1457                 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1458                 if (tl == NULL)
1459                         return EBADRPC;
1460                 fxdr_nfsv3time(tl, &(a)->va_mtime);
1461                 a->va_vaflags &= ~VA_UTIMES_NULL;
1462                 break;
1463         case NFSV3SATTRTIME_TOSERVER:
1464                 getnanotime(&(a)->va_mtime);
1465                 if (toclient == 0)
1466                         a->va_vaflags |= VA_UTIMES_NULL;
1467                 break;
1468         }
1469         return 0;
1470 }