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