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