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/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 nfsrv_object_create(ndp->ni_vp);
792 if (cnp->cn_flags & (SAVENAME | SAVESTART))
793 cnp->cn_flags |= HASBUF;
794 else
795 uma_zfree(namei_zone, cnp->cn_pnbuf);
796 if (ndp->ni_vp && !lockleaf)
797 VOP_UNLOCK(ndp->ni_vp, 0, td);
798 break;
799 }
800
801 /*
802 * Validate symlink
803 */
804 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
805 VOP_UNLOCK(ndp->ni_dvp, 0, td);
806 if (!pubflag) {
807 error = EINVAL;
808 goto badlink2;
809 }
810
811 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
812 error = ELOOP;
813 goto badlink2;
814 }
815 if (ndp->ni_pathlen > 1)
816 cp = uma_zalloc(namei_zone, M_WAITOK);
817 else
818 cp = cnp->cn_pnbuf;
819 aiov.iov_base = cp;
820 aiov.iov_len = MAXPATHLEN;
821 auio.uio_iov = &aiov;
822 auio.uio_iovcnt = 1;
823 auio.uio_offset = 0;
824 auio.uio_rw = UIO_READ;
825 auio.uio_segflg = UIO_SYSSPACE;
826 auio.uio_td = NULL;
827 auio.uio_resid = MAXPATHLEN;
828 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
829 if (error) {
830 badlink1:
831 if (ndp->ni_pathlen > 1)
832 uma_zfree(namei_zone, cp);
833 badlink2:
834 vrele(ndp->ni_dvp);
835 vput(ndp->ni_vp);
836 break;
837 }
838 linklen = MAXPATHLEN - auio.uio_resid;
839 if (linklen == 0) {
840 error = ENOENT;
841 goto badlink1;
842 }
843 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
844 error = ENAMETOOLONG;
845 goto badlink1;
846 }
847
848 /*
849 * Adjust or replace path
850 */
851 if (ndp->ni_pathlen > 1) {
852 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
853 uma_zfree(namei_zone, cnp->cn_pnbuf);
854 cnp->cn_pnbuf = cp;
855 } else
856 cnp->cn_pnbuf[linklen] = '\0';
857 ndp->ni_pathlen += linklen;
858
859 /*
860 * Cleanup refs for next loop and check if root directory
861 * should replace current directory. Normally ni_dvp
862 * becomes the new base directory and is cleaned up when
863 * we loop. Explicitly null pointers after invalidation
864 * to clarify operation.
865 */
866 vput(ndp->ni_vp);
867 ndp->ni_vp = NULL;
868
869 if (cnp->cn_pnbuf[0] == '/') {
870 vrele(ndp->ni_dvp);
871 ndp->ni_dvp = ndp->ni_rootdir;
872 VREF(ndp->ni_dvp);
873 }
874 ndp->ni_startdir = ndp->ni_dvp;
875 ndp->ni_dvp = NULL;
876 }
877 if (!lockleaf)
878 cnp->cn_flags &= ~LOCKLEAF;
879
880 /*
881 * nfs_namei() guarentees that fields will not contain garbage
882 * whether an error occurs or not. This allows the caller to track
883 * cleanup state trivially.
884 */
885 out:
886 if (error) {
887 uma_zfree(namei_zone, cnp->cn_pnbuf);
888 ndp->ni_vp = NULL;
889 ndp->ni_dvp = NULL;
890 ndp->ni_startdir = NULL;
891 cnp->cn_flags &= ~HASBUF;
892 } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
893 ndp->ni_dvp = NULL;
894 }
895 mtx_unlock(&Giant); /* VFS */
896 NFSD_LOCK();
897 return (error);
898 }
899
900 /*
901 * A fiddled version of m_adj() that ensures null fill to a long
902 * boundary and only trims off the back end
903 */
904 void
905 nfsm_adj(struct mbuf *mp, int len, int nul)
906 {
907 struct mbuf *m;
908 int count, i;
909 char *cp;
910
911 NFSD_LOCK_DONTCARE();
912
913 /*
914 * Trim from tail. Scan the mbuf chain,
915 * calculating its length and finding the last mbuf.
916 * If the adjustment only affects this mbuf, then just
917 * adjust and return. Otherwise, rescan and truncate
918 * after the remaining size.
919 */
920 count = 0;
921 m = mp;
922 for (;;) {
923 count += m->m_len;
924 if (m->m_next == NULL)
925 break;
926 m = m->m_next;
927 }
928 if (m->m_len > len) {
929 m->m_len -= len;
930 if (nul > 0) {
931 cp = mtod(m, caddr_t)+m->m_len-nul;
932 for (i = 0; i < nul; i++)
933 *cp++ = '\0';
934 }
935 return;
936 }
937 count -= len;
938 if (count < 0)
939 count = 0;
940 /*
941 * Correct length for chain is "count".
942 * Find the mbuf with last data, adjust its length,
943 * and toss data from remaining mbufs on chain.
944 */
945 for (m = mp; m; m = m->m_next) {
946 if (m->m_len >= count) {
947 m->m_len = count;
948 if (nul > 0) {
949 cp = mtod(m, caddr_t)+m->m_len-nul;
950 for (i = 0; i < nul; i++)
951 *cp++ = '\0';
952 }
953 break;
954 }
955 count -= m->m_len;
956 }
957 for (m = m->m_next;m;m = m->m_next)
958 m->m_len = 0;
959 }
960
961 /*
962 * Make these functions instead of macros, so that the kernel text size
963 * doesn't get too big...
964 */
965 void
966 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
967 struct vattr *before_vap, int after_ret, struct vattr *after_vap,
968 struct mbuf **mbp, char **bposp)
969 {
970 struct mbuf *mb = *mbp;
971 char *bpos = *bposp;
972 u_int32_t *tl;
973
974 if (before_ret) {
975 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
976 *tl = nfsrv_nfs_false;
977 } else {
978 tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
979 *tl++ = nfsrv_nfs_true;
980 txdr_hyper(before_vap->va_size, tl);
981 tl += 2;
982 txdr_nfsv3time(&(before_vap->va_mtime), tl);
983 tl += 2;
984 txdr_nfsv3time(&(before_vap->va_ctime), tl);
985 }
986 *bposp = bpos;
987 *mbp = mb;
988 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
989 }
990
991 void
992 nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
993 struct vattr *after_vap, struct mbuf **mbp, char **bposp)
994 {
995 struct mbuf *mb = *mbp;
996 char *bpos = *bposp;
997 u_int32_t *tl;
998 struct nfs_fattr *fp;
999
1000 if (after_ret) {
1001 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
1002 *tl = nfsrv_nfs_false;
1003 } else {
1004 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1005 *tl++ = nfsrv_nfs_true;
1006 fp = (struct nfs_fattr *)tl;
1007 nfsm_srvfattr(nfsd, after_vap, fp);
1008 }
1009 *mbp = mb;
1010 *bposp = bpos;
1011 }
1012
1013 void
1014 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1015 struct nfs_fattr *fp)
1016 {
1017
1018 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1019 fp->fa_uid = txdr_unsigned(vap->va_uid);
1020 fp->fa_gid = txdr_unsigned(vap->va_gid);
1021 if (nfsd->nd_flag & ND_NFSV3) {
1022 fp->fa_type = vtonfsv3_type(vap->va_type);
1023 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1024 txdr_hyper(vap->va_size, &fp->fa3_size);
1025 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1026 fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
1027 fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
1028 fp->fa3_fsid.nfsuquad[0] = 0;
1029 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1030 fp->fa3_fileid.nfsuquad[0] = 0;
1031 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1032 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1033 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1034 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1035 } else {
1036 fp->fa_type = vtonfsv2_type(vap->va_type);
1037 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1038 fp->fa2_size = txdr_unsigned(vap->va_size);
1039 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1040 if (vap->va_type == VFIFO)
1041 fp->fa2_rdev = 0xffffffff;
1042 else
1043 fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1044 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1045 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1046 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1047 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1048 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1049 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1050 }
1051 }
1052
1053 /*
1054 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1055 * - look up fsid in mount list (if not found ret error)
1056 * - get vp and export rights by calling VFS_FHTOVP()
1057 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1058 * - if not lockflag unlock it with VOP_UNLOCK()
1059 */
1060 int
1061 nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
1062 struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
1063 int *rdonlyp, int pubflag)
1064 {
1065 struct thread *td = curthread; /* XXX */
1066 struct mount *mp;
1067 int i;
1068 struct ucred *credanon;
1069 int error, exflags;
1070 #ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */
1071 struct sockaddr_int *saddr;
1072 #endif
1073
1074 NFSD_LOCK_ASSERT();
1075
1076 *vpp = NULL;
1077
1078 if (nfs_ispublicfh(fhp)) {
1079 if (!pubflag || !nfs_pub.np_valid)
1080 return (ESTALE);
1081 fhp = &nfs_pub.np_handle;
1082 }
1083
1084 mp = vfs_getvfs(&fhp->fh_fsid);
1085 if (!mp)
1086 return (ESTALE);
1087 NFSD_UNLOCK();
1088 mtx_lock(&Giant); /* VFS */
1089 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1090 if (error)
1091 goto out;
1092 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1093 if (error)
1094 goto out;
1095 #ifdef MNT_EXNORESPORT
1096 if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1097 saddr = (struct sockaddr_in *)nam;
1098 if ((saddr->sin_family == AF_INET ||
1099 saddr->sin_family == AF_INET6) &&
1100 /* same code for INET and INET6: sin*_port at same offet */
1101 ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1102 vput(*vpp);
1103 *vpp = NULL;
1104 error = NFSERR_AUTHERR | AUTH_TOOWEAK;
1105 }
1106 }
1107 #endif
1108 /*
1109 * Check/setup credentials.
1110 */
1111 if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1112 cred->cr_uid = credanon->cr_uid;
1113 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1114 cred->cr_groups[i] = credanon->cr_groups[i];
1115 cred->cr_ngroups = i;
1116 }
1117 if (exflags & MNT_EXRDONLY)
1118 *rdonlyp = 1;
1119 else
1120 *rdonlyp = 0;
1121
1122 nfsrv_object_create(*vpp);
1123
1124 if (!lockflag)
1125 VOP_UNLOCK(*vpp, 0, td);
1126 out:
1127 mtx_unlock(&Giant); /* VFS */
1128 NFSD_LOCK();
1129 return (error);
1130 }
1131
1132
1133 /*
1134 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1135 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1136 * transformed this to all zeroes in both cases, so check for it.
1137 */
1138 int
1139 nfs_ispublicfh(fhandle_t *fhp)
1140 {
1141 char *cp = (char *)fhp;
1142 int i;
1143
1144 NFSD_LOCK_DONTCARE();
1145
1146 for (i = 0; i < NFSX_V3FH; i++)
1147 if (*cp++ != 0)
1148 return (FALSE);
1149 return (TRUE);
1150 }
1151
1152 /*
1153 * This function compares two net addresses by family and returns TRUE
1154 * if they are the same host.
1155 * If there is any doubt, return FALSE.
1156 * The AF_INET family is handled as a special case so that address mbufs
1157 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1158 */
1159 int
1160 netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
1161 {
1162 struct sockaddr_in *inetaddr;
1163
1164 NFSD_LOCK_DONTCARE();
1165
1166 switch (family) {
1167 case AF_INET:
1168 inetaddr = (struct sockaddr_in *)nam;
1169 if (inetaddr->sin_family == AF_INET &&
1170 inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1171 return (1);
1172 break;
1173 #ifdef INET6
1174 case AF_INET6:
1175 {
1176 register struct sockaddr_in6 *inet6addr1, *inet6addr2;
1177
1178 inet6addr1 = (struct sockaddr_in6 *)nam;
1179 inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam;
1180 /* XXX - should test sin6_scope_id ? */
1181 if (inet6addr1->sin6_family == AF_INET6 &&
1182 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1183 &inet6addr2->sin6_addr))
1184 return (1);
1185 break;
1186 }
1187 #endif
1188 default:
1189 break;
1190 };
1191 return (0);
1192 }
1193
1194 /*
1195 * Map errnos to NFS error numbers. For Version 3 also filter out error
1196 * numbers not specified for the associated procedure.
1197 */
1198 int
1199 nfsrv_errmap(struct nfsrv_descript *nd, int err)
1200 {
1201 const short *defaulterrp, *errp;
1202 int e;
1203
1204 NFSD_LOCK_DONTCARE();
1205
1206 if (nd->nd_flag & ND_NFSV3) {
1207 if (nd->nd_procnum <= NFSPROC_COMMIT) {
1208 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1209 while (*++errp) {
1210 if (*errp == err)
1211 return (err);
1212 else if (*errp > err)
1213 break;
1214 }
1215 return ((int)*defaulterrp);
1216 } else
1217 return (err & 0xffff);
1218 }
1219 e = 0;
1220 if (err <= ELAST)
1221 e = nfsrv_v2errmap[err - 1];
1222 if (e != 0)
1223 return (e);
1224 return (NFSERR_IO);
1225 }
1226
1227 int
1228 nfsrv_object_create(struct vnode *vp)
1229 {
1230
1231 GIANT_REQUIRED;
1232 NFSD_UNLOCK_ASSERT();
1233
1234 if (vp == NULL || vp->v_type != VREG)
1235 return (1);
1236 return (vfs_object_create(vp, curthread, curthread->td_ucred));
1237 }
1238
1239 /*
1240 * Sort the group list in increasing numerical order.
1241 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1242 * that used to be here.)
1243 */
1244 void
1245 nfsrvw_sort(gid_t *list, int num)
1246 {
1247 int i, j;
1248 gid_t v;
1249
1250 NFSD_LOCK_DONTCARE();
1251
1252 /* Insertion sort. */
1253 for (i = 1; i < num; i++) {
1254 v = list[i];
1255 /* find correct slot for value v, moving others up */
1256 for (j = i; --j >= 0 && v < list[j];)
1257 list[j + 1] = list[j];
1258 list[j + 1] = v;
1259 }
1260 }
1261
1262 /*
1263 * copy credentials making sure that the result can be compared with bcmp().
1264 */
1265 void
1266 nfsrv_setcred(struct ucred *incred, struct ucred *outcred)
1267 {
1268 int i;
1269
1270 NFSD_LOCK_DONTCARE();
1271
1272 bzero((caddr_t)outcred, sizeof (struct ucred));
1273 outcred->cr_ref = 1;
1274 outcred->cr_uid = incred->cr_uid;
1275 outcred->cr_ngroups = incred->cr_ngroups;
1276 for (i = 0; i < incred->cr_ngroups; i++)
1277 outcred->cr_groups[i] = incred->cr_groups[i];
1278 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1279 }
1280
1281 /*
1282 * Helper functions for macros.
1283 */
1284
1285 void
1286 nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
1287 {
1288 u_int32_t *tl;
1289
1290 NFSD_LOCK_DONTCARE();
1291
1292 if (v3) {
1293 tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1294 *tl++ = txdr_unsigned(NFSX_V3FH);
1295 bcopy(f, tl, NFSX_V3FH);
1296 } else {
1297 tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1298 bcopy(f, tl, NFSX_V2FH);
1299 }
1300 }
1301
1302 void
1303 nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
1304 {
1305 u_int32_t *tl;
1306
1307 tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1308 *tl++ = nfsrv_nfs_true;
1309 *tl++ = txdr_unsigned(NFSX_V3FH);
1310 bcopy(f, tl, NFSX_V3FH);
1311 }
1312
1313 int
1314 nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1315 {
1316 u_int32_t *tl;
1317
1318 NFSD_LOCK_DONTCARE();
1319
1320 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1321 if (tl == NULL)
1322 return EBADRPC;
1323 *s = fxdr_unsigned(int32_t, *tl);
1324 if (*s > m || *s <= 0)
1325 return EBADRPC;
1326 return 0;
1327 }
1328
1329 int
1330 nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1331 {
1332 u_int32_t *tl;
1333
1334 NFSD_LOCK_DONTCARE();
1335
1336 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1337 if (tl == NULL)
1338 return EBADRPC;
1339 *s = fxdr_unsigned(int32_t, *tl);
1340 if (*s > m)
1341 return NFSERR_NAMETOL;
1342 if (*s <= 0)
1343 return EBADRPC;
1344 return 0;
1345 }
1346
1347 void
1348 nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
1349 char **bp, char **be, caddr_t bpos, int droplock)
1350 {
1351 struct mbuf *nmp;
1352
1353 NFSD_LOCK_DONTCARE();
1354
1355 if (droplock)
1356 NFSD_LOCK_ASSERT();
1357 else
1358 NFSD_UNLOCK_ASSERT();
1359
1360 if (*bp >= *be) {
1361 if (*mp == mb)
1362 (*mp)->m_len += *bp - bpos;
1363 if (droplock)
1364 NFSD_UNLOCK();
1365 MGET(nmp, M_TRYWAIT, MT_DATA);
1366 MCLGET(nmp, M_TRYWAIT);
1367 if (droplock)
1368 NFSD_LOCK();
1369 nmp->m_len = NFSMSIZ(nmp);
1370 (*mp)->m_next = nmp;
1371 *mp = nmp;
1372 *bp = mtod(*mp, caddr_t);
1373 *be = *bp + (*mp)->m_len;
1374 }
1375 *tl = (u_int32_t *)*bp;
1376 }
1377
1378 int
1379 nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
1380 caddr_t *dpos)
1381 {
1382 u_int32_t *tl;
1383 int fhlen;
1384
1385 NFSD_LOCK_DONTCARE();
1386
1387 if (nfsd->nd_flag & ND_NFSV3) {
1388 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1389 if (tl == NULL)
1390 return EBADRPC;
1391 fhlen = fxdr_unsigned(int, *tl);
1392 if (fhlen != 0 && fhlen != NFSX_V3FH)
1393 return EBADRPC;
1394 } else {
1395 fhlen = NFSX_V2FH;
1396 }
1397 if (fhlen != 0) {
1398 tl = nfsm_dissect_xx(fhlen, md, dpos);
1399 if (tl == NULL)
1400 return EBADRPC;
1401 bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
1402 } else {
1403 bzero((caddr_t)(f), NFSX_V3FH);
1404 }
1405 return 0;
1406 }
1407
1408 int
1409 nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
1410 {
1411 u_int32_t *tl;
1412 int toclient = 0;
1413
1414 NFSD_LOCK_DONTCARE();
1415
1416 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1417 if (tl == NULL)
1418 return EBADRPC;
1419 if (*tl == nfsrv_nfs_true) {
1420 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1421 if (tl == NULL)
1422 return EBADRPC;
1423 (a)->va_mode = nfstov_mode(*tl);
1424 }
1425 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1426 if (tl == NULL)
1427 return EBADRPC;
1428 if (*tl == nfsrv_nfs_true) {
1429 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1430 if (tl == NULL)
1431 return EBADRPC;
1432 (a)->va_uid = fxdr_unsigned(uid_t, *tl);
1433 }
1434 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1435 if (tl == NULL)
1436 return EBADRPC;
1437 if (*tl == nfsrv_nfs_true) {
1438 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1439 if (tl == NULL)
1440 return EBADRPC;
1441 (a)->va_gid = fxdr_unsigned(gid_t, *tl);
1442 }
1443 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1444 if (tl == NULL)
1445 return EBADRPC;
1446 if (*tl == nfsrv_nfs_true) {
1447 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1448 if (tl == NULL)
1449 return EBADRPC;
1450 (a)->va_size = fxdr_hyper(tl);
1451 }
1452 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1453 if (tl == NULL)
1454 return EBADRPC;
1455 switch (fxdr_unsigned(int, *tl)) {
1456 case NFSV3SATTRTIME_TOCLIENT:
1457 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1458 if (tl == NULL)
1459 return EBADRPC;
1460 fxdr_nfsv3time(tl, &(a)->va_atime);
1461 toclient = 1;
1462 break;
1463 case NFSV3SATTRTIME_TOSERVER:
1464 getnanotime(&(a)->va_atime);
1465 a->va_vaflags |= VA_UTIMES_NULL;
1466 break;
1467 }
1468 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1469 if (tl == NULL)
1470 return EBADRPC;
1471 switch (fxdr_unsigned(int, *tl)) {
1472 case NFSV3SATTRTIME_TOCLIENT:
1473 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1474 if (tl == NULL)
1475 return EBADRPC;
1476 fxdr_nfsv3time(tl, &(a)->va_mtime);
1477 a->va_vaflags &= ~VA_UTIMES_NULL;
1478 break;
1479 case NFSV3SATTRTIME_TOSERVER:
1480 getnanotime(&(a)->va_mtime);
1481 if (toclient == 0)
1482 a->va_vaflags |= VA_UTIMES_NULL;
1483 break;
1484 }
1485 return 0;
1486 }
Cache object: b5c557fb1ab94d9b1bd31c5e065d836c
|