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