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