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