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