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: stable/10/sys/nfsserver/nfs_srvsubs.c 245611 2013-01-18 18:43:38Z jhb $");
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
nfsrv_modevent(module_t mod,int type,void * data)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
nfs_namei(struct nameidata * ndp,struct nfsrv_descript * nfsd,fhandle_t * fhp,int len,struct nfssvc_sock * slp,struct sockaddr * nam,struct mbuf ** mdp,caddr_t * dposp,struct vnode ** retdirp,int v3,struct vattr * retdirattrp,int * retdirattr_retp,int pubflag)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 
598 	*retdirp = NULL;
599 	cnp->cn_flags |= NOMACCHECK;
600 	cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
601 
602 	/*
603 	 * Copy the name from the mbuf list to ndp->ni_pnbuf
604 	 * and set the various ndp fields appropriately.
605 	 */
606 	fromcp = *dposp;
607 	tocp = cnp->cn_pnbuf;
608 	md = *mdp;
609 	rem = mtod(md, caddr_t) + md->m_len - fromcp;
610 	for (i = 0; i < len; i++) {
611 		while (rem == 0) {
612 			md = md->m_next;
613 			if (md == NULL) {
614 				error = EBADRPC;
615 				goto out;
616 			}
617 			fromcp = mtod(md, caddr_t);
618 			rem = md->m_len;
619 		}
620 		if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
621 			error = EACCES;
622 			goto out;
623 		}
624 		*tocp++ = *fromcp++;
625 		rem--;
626 	}
627 	*tocp = '\0';
628 	*mdp = md;
629 	*dposp = fromcp;
630 	len = nfsm_rndup(len)-len;
631 	if (len > 0) {
632 		if (rem >= len)
633 			*dposp += len;
634 		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
635 			goto out;
636 	}
637 
638 	if (!pubflag && nfs_ispublicfh(fhp))
639 		return (ESTALE);
640 
641 	/*
642 	 * Extract and set starting directory.
643 	 */
644 	error = nfsrv_fhtovp(fhp, 0, &dp, nfsd, slp, nam, &rdonly);
645 	if (error)
646 		goto out;
647 	if (dp->v_type != VDIR) {
648 		vput(dp);
649 		error = ENOTDIR;
650 		goto out;
651 	}
652 
653 	if (rdonly)
654 		cnp->cn_flags |= RDONLY;
655 
656 	/*
657 	 * Set return directory.  Reference to dp is implicitly transfered
658 	 * to the returned pointer
659 	 */
660 	*retdirp = dp;
661 	if (v3) {
662 		*retdirattr_retp = VOP_GETATTR(dp, retdirattrp,
663 			ndp->ni_cnd.cn_cred);
664 	}
665 
666 	VOP_UNLOCK(dp, 0);
667 
668 	if (pubflag) {
669 		/*
670 		 * Oh joy. For WebNFS, handle those pesky '%' escapes,
671 		 * and the 'native path' indicator.
672 		 */
673 		cp = uma_zalloc(namei_zone, M_WAITOK);
674 		fromcp = cnp->cn_pnbuf;
675 		tocp = cp;
676 		if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
677 			switch ((unsigned char)*fromcp) {
678 			case WEBNFS_NATIVE_CHAR:
679 				/*
680 				 * 'Native' path for us is the same
681 				 * as a path according to the NFS spec,
682 				 * just skip the escape char.
683 				 */
684 				fromcp++;
685 				break;
686 			/*
687 			 * More may be added in the future, range 0x80-0xff
688 			 */
689 			default:
690 				error = EIO;
691 				uma_zfree(namei_zone, cp);
692 				goto out;
693 			}
694 		}
695 		/*
696 		 * Translate the '%' escapes, URL-style.
697 		 */
698 		while (*fromcp != '\0') {
699 			if (*fromcp == WEBNFS_ESC_CHAR) {
700 				if (fromcp[1] != '\0' && fromcp[2] != '\0') {
701 					fromcp++;
702 					*tocp++ = HEXSTRTOI(fromcp);
703 					fromcp += 2;
704 					continue;
705 				} else {
706 					error = ENOENT;
707 					uma_zfree(namei_zone, cp);
708 					goto out;
709 				}
710 			} else
711 				*tocp++ = *fromcp++;
712 		}
713 		*tocp = '\0';
714 		uma_zfree(namei_zone, cnp->cn_pnbuf);
715 		cnp->cn_pnbuf = cp;
716 	}
717 
718 	ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
719 	ndp->ni_segflg = UIO_SYSSPACE;
720 
721 	if (pubflag) {
722 		ndp->ni_rootdir = rootvnode;
723 		ndp->ni_loopcnt = 0;
724 
725 		if (cnp->cn_pnbuf[0] == '/')
726 			dp = rootvnode;
727 	} else {
728 		cnp->cn_flags |= NOCROSSMOUNT;
729 	}
730 
731 	/*
732 	 * Initialize for scan, set ni_startdir and bump ref on dp again
733 	 * because lookup() will dereference ni_startdir.
734 	 */
735 
736 	cnp->cn_thread = curthread;
737 	VREF(dp);
738 	ndp->ni_startdir = dp;
739 
740 	if (!lockleaf)
741 		cnp->cn_flags |= LOCKLEAF;
742 	for (;;) {
743 		cnp->cn_nameptr = cnp->cn_pnbuf;
744 		/*
745 		 * Call lookup() to do the real work.  If an error occurs,
746 		 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
747 		 * we do not have to dereference anything before returning.
748 		 * In either case ni_startdir will be dereferenced and NULLed
749 		 * out.
750 		 */
751 		error = lookup(ndp);
752 		if (error)
753 			break;
754 
755 		/*
756 		 * Check for encountering a symbolic link.  Trivial
757 		 * termination occurs if no symlink encountered.
758 		 * Note: zfree is safe because error is 0, so we will
759 		 * not zfree it again when we break.
760 		 */
761 		if ((cnp->cn_flags & ISSYMLINK) == 0) {
762 			if (cnp->cn_flags & (SAVENAME | SAVESTART))
763 				cnp->cn_flags |= HASBUF;
764 			else
765 				uma_zfree(namei_zone, cnp->cn_pnbuf);
766 			if (ndp->ni_vp && !lockleaf)
767 				VOP_UNLOCK(ndp->ni_vp, 0);
768 			break;
769 		}
770 
771 		/*
772 		 * Validate symlink
773 		 */
774 		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
775 			VOP_UNLOCK(ndp->ni_dvp, 0);
776 		if (!pubflag) {
777 			error = EINVAL;
778 			goto badlink2;
779 		}
780 
781 		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
782 			error = ELOOP;
783 			goto badlink2;
784 		}
785 		if (ndp->ni_pathlen > 1)
786 			cp = uma_zalloc(namei_zone, M_WAITOK);
787 		else
788 			cp = cnp->cn_pnbuf;
789 		aiov.iov_base = cp;
790 		aiov.iov_len = MAXPATHLEN;
791 		auio.uio_iov = &aiov;
792 		auio.uio_iovcnt = 1;
793 		auio.uio_offset = 0;
794 		auio.uio_rw = UIO_READ;
795 		auio.uio_segflg = UIO_SYSSPACE;
796 		auio.uio_td = NULL;
797 		auio.uio_resid = MAXPATHLEN;
798 		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
799 		if (error) {
800 		badlink1:
801 			if (ndp->ni_pathlen > 1)
802 				uma_zfree(namei_zone, cp);
803 		badlink2:
804 			vput(ndp->ni_vp);
805 			vrele(ndp->ni_dvp);
806 			break;
807 		}
808 		linklen = MAXPATHLEN - auio.uio_resid;
809 		if (linklen == 0) {
810 			error = ENOENT;
811 			goto badlink1;
812 		}
813 		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
814 			error = ENAMETOOLONG;
815 			goto badlink1;
816 		}
817 
818 		/*
819 		 * Adjust or replace path
820 		 */
821 		if (ndp->ni_pathlen > 1) {
822 			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
823 			uma_zfree(namei_zone, cnp->cn_pnbuf);
824 			cnp->cn_pnbuf = cp;
825 		} else
826 			cnp->cn_pnbuf[linklen] = '\0';
827 		ndp->ni_pathlen += linklen;
828 
829 		/*
830 		 * Cleanup refs for next loop and check if root directory
831 		 * should replace current directory.  Normally ni_dvp
832 		 * becomes the new base directory and is cleaned up when
833 		 * we loop.  Explicitly null pointers after invalidation
834 		 * to clarify operation.
835 		 */
836 		vput(ndp->ni_vp);
837 		ndp->ni_vp = NULL;
838 
839 		if (cnp->cn_pnbuf[0] == '/') {
840 			vrele(ndp->ni_dvp);
841 			ndp->ni_dvp = ndp->ni_rootdir;
842 			VREF(ndp->ni_dvp);
843 		}
844 		ndp->ni_startdir = ndp->ni_dvp;
845 		ndp->ni_dvp = NULL;
846 	}
847 	if (!lockleaf)
848 		cnp->cn_flags &= ~LOCKLEAF;
849 
850 	/*
851 	 * nfs_namei() guarentees that fields will not contain garbage
852 	 * whether an error occurs or not.  This allows the caller to track
853 	 * cleanup state trivially.
854 	 */
855 out:
856 	if (error) {
857 		uma_zfree(namei_zone, cnp->cn_pnbuf);
858 		ndp->ni_vp = NULL;
859 		ndp->ni_dvp = NULL;
860 		ndp->ni_startdir = NULL;
861 		cnp->cn_flags &= ~HASBUF;
862 	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
863 		ndp->ni_dvp = NULL;
864 	}
865 	return (error);
866 }
867 
868 /*
869  * A fiddled version of m_adj() that ensures null fill to a long
870  * boundary and only trims off the back end
871  */
872 void
nfsm_adj(struct mbuf * mp,int len,int nul)873 nfsm_adj(struct mbuf *mp, int len, int nul)
874 {
875 	struct mbuf *m;
876 	int count, i;
877 	char *cp;
878 
879 	/*
880 	 * Trim from tail.  Scan the mbuf chain,
881 	 * calculating its length and finding the last mbuf.
882 	 * If the adjustment only affects this mbuf, then just
883 	 * adjust and return.  Otherwise, rescan and truncate
884 	 * after the remaining size.
885 	 */
886 	count = 0;
887 	m = mp;
888 	for (;;) {
889 		count += m->m_len;
890 		if (m->m_next == NULL)
891 			break;
892 		m = m->m_next;
893 	}
894 	if (m->m_len > len) {
895 		m->m_len -= len;
896 		if (nul > 0) {
897 			cp = mtod(m, caddr_t)+m->m_len-nul;
898 			for (i = 0; i < nul; i++)
899 				*cp++ = '\0';
900 		}
901 		return;
902 	}
903 	count -= len;
904 	if (count < 0)
905 		count = 0;
906 	/*
907 	 * Correct length for chain is "count".
908 	 * Find the mbuf with last data, adjust its length,
909 	 * and toss data from remaining mbufs on chain.
910 	 */
911 	for (m = mp; m; m = m->m_next) {
912 		if (m->m_len >= count) {
913 			m->m_len = count;
914 			if (nul > 0) {
915 				cp = mtod(m, caddr_t)+m->m_len-nul;
916 				for (i = 0; i < nul; i++)
917 					*cp++ = '\0';
918 			}
919 			if (m->m_next != NULL) {
920 				m_freem(m->m_next);
921 				m->m_next = NULL;
922 			}
923 			break;
924 		}
925 		count -= m->m_len;
926 	}
927 }
928 
929 /*
930  * Make these functions instead of macros, so that the kernel text size
931  * doesn't get too big...
932  */
933 void
nfsm_srvwcc(struct nfsrv_descript * nfsd,int before_ret,struct vattr * before_vap,int after_ret,struct vattr * after_vap,struct mbuf ** mbp,char ** bposp)934 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
935     struct vattr *before_vap, int after_ret, struct vattr *after_vap,
936     struct mbuf **mbp, char **bposp)
937 {
938 	struct mbuf *mb = *mbp;
939 	char *bpos = *bposp;
940 	u_int32_t *tl;
941 
942 	if (before_ret) {
943 		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
944 		*tl = nfsrv_nfs_false;
945 	} else {
946 		tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
947 		*tl++ = nfsrv_nfs_true;
948 		txdr_hyper(before_vap->va_size, tl);
949 		tl += 2;
950 		txdr_nfsv3time(&(before_vap->va_mtime), tl);
951 		tl += 2;
952 		txdr_nfsv3time(&(before_vap->va_ctime), tl);
953 	}
954 	*bposp = bpos;
955 	*mbp = mb;
956 	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
957 }
958 
959 void
nfsm_srvpostopattr(struct nfsrv_descript * nfsd,int after_ret,struct vattr * after_vap,struct mbuf ** mbp,char ** bposp)960 nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
961     struct vattr *after_vap, struct mbuf **mbp, char **bposp)
962 {
963 	struct mbuf *mb = *mbp;
964 	char *bpos = *bposp;
965 	u_int32_t *tl;
966 	struct nfs_fattr *fp;
967 
968 	if (after_ret) {
969 		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
970 		*tl = nfsrv_nfs_false;
971 	} else {
972 		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
973 		*tl++ = nfsrv_nfs_true;
974 		fp = (struct nfs_fattr *)tl;
975 		nfsm_srvfattr(nfsd, after_vap, fp);
976 	}
977 	*mbp = mb;
978 	*bposp = bpos;
979 }
980 
981 void
nfsm_srvfattr(struct nfsrv_descript * nfsd,struct vattr * vap,struct nfs_fattr * fp)982 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
983     struct nfs_fattr *fp)
984 {
985 
986 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
987 	fp->fa_uid = txdr_unsigned(vap->va_uid);
988 	fp->fa_gid = txdr_unsigned(vap->va_gid);
989 	if (nfsd->nd_flag & ND_NFSV3) {
990 		fp->fa_type = vtonfsv3_type(vap->va_type);
991 		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
992 		txdr_hyper(vap->va_size, &fp->fa3_size);
993 		txdr_hyper(vap->va_bytes, &fp->fa3_used);
994 		fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
995 		fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
996 		fp->fa3_fsid.nfsuquad[0] = 0;
997 		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
998 		fp->fa3_fileid.nfsuquad[0] = 0;
999 		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1000 		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1001 		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1002 		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1003 	} else {
1004 		fp->fa_type = vtonfsv2_type(vap->va_type);
1005 		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1006 		fp->fa2_size = txdr_unsigned(vap->va_size);
1007 		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1008 		if (vap->va_type == VFIFO)
1009 			fp->fa2_rdev = 0xffffffff;
1010 		else
1011 			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1012 		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1013 		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1014 		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1015 		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1016 		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1017 		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1018 	}
1019 }
1020 
1021 /*
1022  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1023  * 	- look up fsid in mount list (if not found ret error)
1024  *	- get vp and export rights by calling VFS_FHTOVP()
1025  *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1026  */
1027 int
nfsrv_fhtovp(fhandle_t * fhp,int flags,struct vnode ** vpp,struct nfsrv_descript * nfsd,struct nfssvc_sock * slp,struct sockaddr * nam,int * rdonlyp)1028 nfsrv_fhtovp(fhandle_t *fhp, int flags, struct vnode **vpp,
1029     struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1030     struct sockaddr *nam, int *rdonlyp)
1031 {
1032 	struct mount *mp;
1033 	int i;
1034 	struct ucred *cred, *credanon;
1035 	int error, exflags;
1036 #ifdef MNT_EXNORESPORT		/* XXX needs mountd and /etc/exports help yet */
1037 	struct sockaddr_int *saddr;
1038 #endif
1039 	int credflavor;
1040 	int numsecflavors, *secflavors;
1041 	int authsys;
1042 	int v3 = nfsd->nd_flag & ND_NFSV3;
1043 	int mountreq;
1044 
1045 	*vpp = NULL;
1046 
1047 	if (nfs_ispublicfh(fhp)) {
1048 		if (!nfs_pub.np_valid)
1049 			return (ESTALE);
1050 		fhp = &nfs_pub.np_handle;
1051 	}
1052 
1053 	mp = vfs_busyfs(&fhp->fh_fsid);
1054 	if (!mp)
1055 		return (ESTALE);
1056 	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon,
1057 	    &numsecflavors, &secflavors);
1058 	if (error) {
1059 		vfs_unbusy(mp);
1060 		goto out;
1061 	}
1062 	if (numsecflavors == 0) {
1063 		/*
1064 		 * This can happen if the system is running with an
1065 		 * old mountd that doesn't pass in a secflavor list.
1066 		 */
1067 		numsecflavors = 1;
1068 		authsys = AUTH_SYS;
1069 		secflavors = &authsys;
1070 	}
1071 	credflavor = nfsd->nd_credflavor;
1072 	for (i = 0; i < numsecflavors; i++) {
1073 		if (secflavors[i] == credflavor)
1074 			break;
1075 	}
1076 	if (i == numsecflavors) {
1077 		/*
1078 		 * RFC 2623 section 2.3.2 - allow certain procedures
1079 		 * used at NFS client mount time even if they have
1080 		 * weak authentication.
1081 		 */
1082 		mountreq = FALSE;
1083 		if (v3) {
1084 			if (nfsd->nd_procnum == NFSPROC_FSINFO
1085 			    || nfsd->nd_procnum == NFSPROC_GETATTR)
1086 				mountreq = TRUE;
1087 		} else {
1088 			if (nfsd->nd_procnum == NFSPROC_FSSTAT
1089 			    || nfsd->nd_procnum == NFSPROC_GETATTR)
1090 				mountreq = TRUE;
1091 		}
1092 		if (!mountreq) {
1093 			error = NFSERR_AUTHERR | AUTH_TOOWEAK;
1094 			vfs_unbusy(mp);
1095 			goto out;
1096 		}
1097 	}
1098 	error = VFS_FHTOVP(mp, &fhp->fh_fid, LK_EXCLUSIVE, vpp);
1099 	if (error) {
1100 		/* Make sure the server replies ESTALE to the client. */
1101 		error = ESTALE;
1102 		vfs_unbusy(mp);
1103 		goto out;
1104 	}
1105 #ifdef MNT_EXNORESPORT
1106 	if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1107 		saddr = (struct sockaddr_in *)nam;
1108 		if ((saddr->sin_family == AF_INET ||
1109 		     saddr->sin_family == AF_INET6) &&
1110 	/* same code for INET and INET6: sin*_port at same offet */
1111 		    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1112 			vput(*vpp);
1113 			*vpp = NULL;
1114 			error = NFSERR_AUTHERR | AUTH_TOOWEAK;
1115 			vfs_unbusy(mp);
1116 			goto out;
1117 		}
1118 	}
1119 #endif
1120 	/*
1121 	 * Check/setup credentials.
1122 	 */
1123 	cred = nfsd->nd_cr;
1124 	if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1125 		cred->cr_uid = credanon->cr_uid;
1126 		crsetgroups(cred, credanon->cr_ngroups, credanon->cr_groups);
1127 	}
1128 	if (exflags & MNT_EXRDONLY)
1129 		*rdonlyp = 1;
1130 	else
1131 		*rdonlyp = 0;
1132 
1133 	if (!(flags & NFSRV_FLAG_BUSY))
1134 		vfs_unbusy(mp);
1135 out:
1136 	if (credanon != NULL)
1137 		crfree(credanon);
1138 
1139 	return (error);
1140 }
1141 
1142 
1143 /*
1144  * WebNFS: check if a filehandle is a public filehandle. For v3, this
1145  * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1146  * transformed this to all zeroes in both cases, so check for it.
1147  */
1148 int
nfs_ispublicfh(fhandle_t * fhp)1149 nfs_ispublicfh(fhandle_t *fhp)
1150 {
1151 	char *cp = (char *)fhp;
1152 	int i;
1153 
1154 	NFSD_LOCK_DONTCARE();
1155 
1156 	for (i = 0; i < NFSX_V3FH; i++)
1157 		if (*cp++ != 0)
1158 			return (FALSE);
1159 	return (TRUE);
1160 }
1161 
1162 /*
1163  * Map errnos to NFS error numbers. For Version 3 also filter out error
1164  * numbers not specified for the associated procedure.
1165  */
1166 int
nfsrv_errmap(struct nfsrv_descript * nd,int err)1167 nfsrv_errmap(struct nfsrv_descript *nd, int err)
1168 {
1169 	const short *defaulterrp, *errp;
1170 	int e;
1171 
1172 
1173 	if (nd->nd_flag & ND_NFSV3) {
1174 	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
1175 		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1176 		while (*++errp) {
1177 			if (*errp == err)
1178 				return (err);
1179 			else if (*errp > err)
1180 				break;
1181 		}
1182 		return ((int)*defaulterrp);
1183 	    } else
1184 		return (err & 0xffff);
1185 	}
1186 	e = 0;
1187 	if (err <= ELAST)
1188 		e = nfsrv_v2errmap[err - 1];
1189 	if (e != 0)
1190 		return (e);
1191 	return (NFSERR_IO);
1192 }
1193 
1194 /*
1195  * Sort the group list in increasing numerical order.
1196  * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1197  *  that used to be here.)
1198  */
1199 void
nfsrvw_sort(gid_t * list,int num)1200 nfsrvw_sort(gid_t *list, int num)
1201 {
1202 	int i, j;
1203 	gid_t v;
1204 
1205 	/* Insertion sort. */
1206 	for (i = 1; i < num; i++) {
1207 		v = list[i];
1208 		/* find correct slot for value v, moving others up */
1209 		for (j = i; --j >= 0 && v < list[j];)
1210 			list[j + 1] = list[j];
1211 		list[j + 1] = v;
1212 	}
1213 }
1214 
1215 /*
1216  * Helper functions for macros.
1217  */
1218 
1219 void
nfsm_srvfhtom_xx(fhandle_t * f,int v3,struct mbuf ** mb,caddr_t * bpos)1220 nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
1221 {
1222 	u_int32_t *tl;
1223 
1224 	if (v3) {
1225 		tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1226 		*tl++ = txdr_unsigned(NFSX_V3FH);
1227 		bcopy(f, tl, NFSX_V3FH);
1228 	} else {
1229 		tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1230 		bcopy(f, tl, NFSX_V2FH);
1231 	}
1232 }
1233 
1234 void
nfsm_srvpostop_fh_xx(fhandle_t * f,struct mbuf ** mb,caddr_t * bpos)1235 nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
1236 {
1237 	u_int32_t *tl;
1238 
1239 	tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1240 	*tl++ = nfsrv_nfs_true;
1241 	*tl++ = txdr_unsigned(NFSX_V3FH);
1242 	bcopy(f, tl, NFSX_V3FH);
1243 }
1244 
1245 int
nfsm_srvstrsiz_xx(int * s,int m,struct mbuf ** md,caddr_t * dpos)1246 nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1247 {
1248 	u_int32_t *tl;
1249 
1250 	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1251 	if (tl == NULL)
1252 		return EBADRPC;
1253 	*s = fxdr_unsigned(int32_t, *tl);
1254 	if (*s > m || *s <= 0)
1255 		return EBADRPC;
1256 	return 0;
1257 }
1258 
1259 int
nfsm_srvnamesiz_xx(int * s,int m,struct mbuf ** md,caddr_t * dpos)1260 nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1261 {
1262 	u_int32_t *tl;
1263 
1264 	NFSD_LOCK_DONTCARE();
1265 
1266 	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1267 	if (tl == NULL)
1268 		return EBADRPC;
1269 	*s = fxdr_unsigned(int32_t, *tl);
1270 	if (*s > m)
1271 		return NFSERR_NAMETOL;
1272 	if (*s <= 0)
1273 		return EBADRPC;
1274 	return 0;
1275 }
1276 
1277 int
nfsm_srvnamesiz0_xx(int * s,int m,struct mbuf ** md,caddr_t * dpos)1278 nfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1279 {
1280 	u_int32_t *tl;
1281 
1282 	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1283 	if (tl == NULL)
1284 		return EBADRPC;
1285 	*s = fxdr_unsigned(int32_t, *tl);
1286 	if (*s > m)
1287 		return NFSERR_NAMETOL;
1288 	if (*s < 0)
1289 		return EBADRPC;
1290 	return 0;
1291 }
1292 
1293 void
nfsm_clget_xx(u_int32_t ** tl,struct mbuf * mb,struct mbuf ** mp,char ** bp,char ** be,caddr_t bpos)1294 nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
1295     char **bp, char **be, caddr_t bpos)
1296 {
1297 	struct mbuf *nmp;
1298 
1299 	NFSD_UNLOCK_ASSERT();
1300 
1301 	if (*bp >= *be) {
1302 		if (*mp == mb)
1303 			(*mp)->m_len += *bp - bpos;
1304 		MGET(nmp, M_WAITOK, MT_DATA);
1305 		MCLGET(nmp, M_WAITOK);
1306 		nmp->m_len = NFSMSIZ(nmp);
1307 		(*mp)->m_next = nmp;
1308 		*mp = nmp;
1309 		*bp = mtod(*mp, caddr_t);
1310 		*be = *bp + (*mp)->m_len;
1311 	}
1312 	*tl = (u_int32_t *)*bp;
1313 }
1314 
1315 int
nfsm_srvmtofh_xx(fhandle_t * f,int v3,struct mbuf ** md,caddr_t * dpos)1316 nfsm_srvmtofh_xx(fhandle_t *f, int v3, struct mbuf **md, caddr_t *dpos)
1317 {
1318 	u_int32_t *tl;
1319 	int fhlen;
1320 
1321 	if (v3) {
1322 		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1323 		if (tl == NULL)
1324 			return EBADRPC;
1325 		fhlen = fxdr_unsigned(int, *tl);
1326 		if (fhlen != 0 && fhlen != NFSX_V3FH)
1327 			return EBADRPC;
1328 	} else {
1329 		fhlen = NFSX_V2FH;
1330 	}
1331 	if (fhlen != 0) {
1332 		tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos);
1333 		if (tl == NULL)
1334 			return EBADRPC;
1335 		bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
1336 	} else {
1337 		bzero((caddr_t)(f), NFSX_V3FH);
1338 	}
1339 	return 0;
1340 }
1341 
1342 int
nfsm_srvsattr_xx(struct vattr * a,struct mbuf ** md,caddr_t * dpos)1343 nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
1344 {
1345 	u_int32_t *tl;
1346 	int toclient = 0;
1347 
1348 	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1349 	if (tl == NULL)
1350 		return EBADRPC;
1351 	if (*tl == nfsrv_nfs_true) {
1352 		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1353 		if (tl == NULL)
1354 			return EBADRPC;
1355 		(a)->va_mode = nfstov_mode(*tl);
1356 	}
1357 	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1358 	if (tl == NULL)
1359 		return EBADRPC;
1360 	if (*tl == nfsrv_nfs_true) {
1361 		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1362 		if (tl == NULL)
1363 			return EBADRPC;
1364 		(a)->va_uid = fxdr_unsigned(uid_t, *tl);
1365 	}
1366 	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1367 	if (tl == NULL)
1368 		return EBADRPC;
1369 	if (*tl == nfsrv_nfs_true) {
1370 		tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1371 		if (tl == NULL)
1372 			return EBADRPC;
1373 		(a)->va_gid = fxdr_unsigned(gid_t, *tl);
1374 	}
1375 	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1376 	if (tl == NULL)
1377 		return EBADRPC;
1378 	if (*tl == nfsrv_nfs_true) {
1379 		tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1380 		if (tl == NULL)
1381 			return EBADRPC;
1382 		(a)->va_size = fxdr_hyper(tl);
1383 	}
1384 	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1385 	if (tl == NULL)
1386 		return EBADRPC;
1387 	switch (fxdr_unsigned(int, *tl)) {
1388 	case NFSV3SATTRTIME_TOCLIENT:
1389 		tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1390 		if (tl == NULL)
1391 			return EBADRPC;
1392 		fxdr_nfsv3time(tl, &(a)->va_atime);
1393 		toclient = 1;
1394 		break;
1395 	case NFSV3SATTRTIME_TOSERVER:
1396 		vfs_timestamp(&a->va_atime);
1397 		a->va_vaflags |= VA_UTIMES_NULL;
1398 		break;
1399 	}
1400 	tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1401 	if (tl == NULL)
1402 		return EBADRPC;
1403 	switch (fxdr_unsigned(int, *tl)) {
1404 	case NFSV3SATTRTIME_TOCLIENT:
1405 		tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1406 		if (tl == NULL)
1407 			return EBADRPC;
1408 		fxdr_nfsv3time(tl, &(a)->va_mtime);
1409 		a->va_vaflags &= ~VA_UTIMES_NULL;
1410 		break;
1411 	case NFSV3SATTRTIME_TOSERVER:
1412 		vfs_timestamp(&a->va_mtime);
1413 		if (toclient == 0)
1414 			a->va_vaflags |= VA_UTIMES_NULL;
1415 		break;
1416 	}
1417 	return 0;
1418 }
1419