]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/nfsserver/nfs_srvsubs.c
This commit was generated by cvs2svn to compensate for changes in r173143,
[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                 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 }
581 static moduledata_t nfsserver_mod = {
582         "nfsserver",
583         nfsrv_modevent,
584         NULL,
585 };
586 DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
587
588 /* So that loader and kldload(2) can find us, wherever we are.. */
589 MODULE_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  */
607 int
608 nfs_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          */
896 out:
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  */
925 void
926 nfsm_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  */
986 void
987 nfsm_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
1012 void
1013 nfsm_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
1034 void
1035 nfsm_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  */
1081 int
1082 nfsrv_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);
1144 out:
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  */
1159 int
1160 nfs_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  */
1180 int
1181 netaddr_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  */
1219 int
1220 nfsrv_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  */
1252 void
1253 nfsrvw_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  */
1271 void
1272 nfsrv_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
1289 void
1290 nfsm_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
1304 void
1305 nfsm_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
1315 int
1316 nfsm_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
1329 int
1330 nfsm_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
1347 int
1348 nfsm_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
1363 void
1364 nfsm_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
1385 int
1386 nfsm_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
1413 int
1414 nfsm_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 }