1 /*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
33 */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD: releng/6.2/sys/nfsserver/nfs_srvsubs.c 165860 2007-01-07 13:22:49Z hrs $");
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_drain(&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 nfsrv_destroycache(); /* Free the server request cache */
572 mtx_destroy(&nfsd_mtx);
573 break;
574 default:
575 error = EOPNOTSUPP;
576 break;
577 }
578 NET_UNLOCK_GIANT();
579 return error;
580 }
581 static moduledata_t nfsserver_mod = {
582 "nfsserver",
583 nfsrv_modevent,
584 NULL,
585 };
586 DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
587
588 /* So that loader and kldload(2) can find us, wherever we are.. */
589 MODULE_VERSION(nfsserver, 1);
590
591 /*
592 * Set up nameidata for a lookup() call and do it.
593 *
594 * If pubflag is set, this call is done for a lookup operation on the
595 * public filehandle. In that case we allow crossing mountpoints and
596 * absolute pathnames. However, the caller is expected to check that
597 * the lookup result is within the public fs, and deny access if
598 * it is not.
599 *
600 * nfs_namei() clears out garbage fields that namei() might leave garbage.
601 * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
602 * error occurs but the parent was not requested.
603 *
604 * dirp may be set whether an error is returned or not, and must be
605 * released by the caller.
606 */
607 int
608 nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
609 struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp,
610 caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp,
611 int *retdirattr_retp, struct thread *td, int pubflag)
612 {
613 int i, rem;
614 struct mbuf *md;
615 char *fromcp, *tocp, *cp;
616 struct iovec aiov;
617 struct uio auio;
618 struct vnode *dp;
619 int error, rdonly, linklen;
620 struct componentname *cnp = &ndp->ni_cnd;
621 int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0;
622
623 NFSD_LOCK_ASSERT();
624 NFSD_UNLOCK();
625 mtx_lock(&Giant); /* VFS */
626
627 *retdirp = NULL;
628 cnp->cn_flags |= NOMACCHECK;
629 cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
630
631 /*
632 * Copy the name from the mbuf list to ndp->ni_pnbuf
633 * and set the various ndp fields appropriately.
634 */
635 fromcp = *dposp;
636 tocp = cnp->cn_pnbuf;
637 md = *mdp;
638 rem = mtod(md, caddr_t) + md->m_len - fromcp;
639 for (i = 0; i < len; i++) {
640 while (rem == 0) {
641 md = md->m_next;
642 if (md == NULL) {
643 error = EBADRPC;
644 goto out;
645 }
646 fromcp = mtod(md, caddr_t);
647 rem = md->m_len;
648 }
649 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
650 error = EACCES;
651 goto out;
652 }
653 *tocp++ = *fromcp++;
654 rem--;
655 }
656 *tocp = '\0';
657 *mdp = md;
658 *dposp = fromcp;
659 len = nfsm_rndup(len)-len;
660 if (len > 0) {
661 if (rem >= len)
662 *dposp += len;
663 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
664 goto out;
665 }
666
667 /*
668 * Extract and set starting directory.
669 */
670 mtx_unlock(&Giant); /* VFS */
671 NFSD_LOCK();
672 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
673 nam, &rdonly, pubflag);
674 NFSD_UNLOCK();
675 mtx_lock(&Giant); /* VFS */
676 if (error)
677 goto out;
678 if (dp->v_type != VDIR) {
679 vrele(dp);
680 error = ENOTDIR;
681 goto out;
682 }
683
684 if (rdonly)
685 cnp->cn_flags |= RDONLY;
686
687 /*
688 * Set return directory. Reference to dp is implicitly transfered
689 * to the returned pointer
690 */
691 *retdirp = dp;
692 if (v3) {
693 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td);
694 *retdirattr_retp = VOP_GETATTR(dp, retdirattrp,
695 ndp->ni_cnd.cn_cred, td);
696 VOP_UNLOCK(dp, 0, td);
697 }
698
699 if (pubflag) {
700 /*
701 * Oh joy. For WebNFS, handle those pesky '%' escapes,
702 * and the 'native path' indicator.
703 */
704 cp = uma_zalloc(namei_zone, M_WAITOK);
705 fromcp = cnp->cn_pnbuf;
706 tocp = cp;
707 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
708 switch ((unsigned char)*fromcp) {
709 case WEBNFS_NATIVE_CHAR:
710 /*
711 * 'Native' path for us is the same
712 * as a path according to the NFS spec,
713 * just skip the escape char.
714 */
715 fromcp++;
716 break;
717 /*
718 * More may be added in the future, range 0x80-0xff
719 */
720 default:
721 error = EIO;
722 uma_zfree(namei_zone, cp);
723 goto out;
724 }
725 }
726 /*
727 * Translate the '%' escapes, URL-style.
728 */
729 while (*fromcp != '\0') {
730 if (*fromcp == WEBNFS_ESC_CHAR) {
731 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
732 fromcp++;
733 *tocp++ = HEXSTRTOI(fromcp);
734 fromcp += 2;
735 continue;
736 } else {
737 error = ENOENT;
738 uma_zfree(namei_zone, cp);
739 goto out;
740 }
741 } else
742 *tocp++ = *fromcp++;
743 }
744 *tocp = '\0';
745 uma_zfree(namei_zone, cnp->cn_pnbuf);
746 cnp->cn_pnbuf = cp;
747 }
748
749 ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
750 ndp->ni_segflg = UIO_SYSSPACE;
751
752 if (pubflag) {
753 ndp->ni_rootdir = rootvnode;
754 ndp->ni_loopcnt = 0;
755 if (cnp->cn_pnbuf[0] == '/')
756 dp = rootvnode;
757 } else {
758 cnp->cn_flags |= NOCROSSMOUNT;
759 }
760
761 /*
762 * Initialize for scan, set ni_startdir and bump ref on dp again
763 * because lookup() will dereference ni_startdir.
764 */
765
766 cnp->cn_thread = td;
767 VREF(dp);
768 ndp->ni_startdir = dp;
769
770 if (!lockleaf)
771 cnp->cn_flags |= LOCKLEAF;
772 for (;;) {
773 cnp->cn_nameptr = cnp->cn_pnbuf;
774 /*
775 * Call lookup() to do the real work. If an error occurs,
776 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
777 * we do not have to dereference anything before returning.
778 * In either case ni_startdir will be dereferenced and NULLed
779 * out.
780 */
781 error = lookup(ndp);
782 if (error)
783 break;
784
785 /*
786 * Check for encountering a symbolic link. Trivial
787 * termination occurs if no symlink encountered.
788 * Note: zfree is safe because error is 0, so we will
789 * not zfree it again when we break.
790 */
791 if ((cnp->cn_flags & ISSYMLINK) == 0) {
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 vput(ndp->ni_vp);
835 vrele(ndp->ni_dvp);
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 if (cnp->cn_flags & GIANTHELD) {
880 mtx_unlock(&Giant);
881 cnp->cn_flags &= ~GIANTHELD;
882 }
883
884 /*
885 * nfs_namei() guarentees that fields will not contain garbage
886 * whether an error occurs or not. This allows the caller to track
887 * cleanup state trivially.
888 */
889 out:
890 if (error) {
891 uma_zfree(namei_zone, cnp->cn_pnbuf);
892 ndp->ni_vp = NULL;
893 ndp->ni_dvp = NULL;
894 ndp->ni_startdir = NULL;
895 cnp->cn_flags &= ~HASBUF;
896 } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
897 ndp->ni_dvp = NULL;
898 }
899 mtx_unlock(&Giant); /* VFS */
900 NFSD_LOCK();
901 return (error);
902 }
903
904 /*
905 * A fiddled version of m_adj() that ensures null fill to a long
906 * boundary and only trims off the back end
907 */
908 void
909 nfsm_adj(struct mbuf *mp, int len, int nul)
910 {
911 struct mbuf *m;
912 int count, i;
913 char *cp;
914
915 NFSD_LOCK_DONTCARE();
916
917 /*
918 * Trim from tail. Scan the mbuf chain,
919 * calculating its length and finding the last mbuf.
920 * If the adjustment only affects this mbuf, then just
921 * adjust and return. Otherwise, rescan and truncate
922 * after the remaining size.
923 */
924 count = 0;
925 m = mp;
926 for (;;) {
927 count += m->m_len;
928 if (m->m_next == NULL)
929 break;
930 m = m->m_next;
931 }
932 if (m->m_len > len) {
933 m->m_len -= len;
934 if (nul > 0) {
935 cp = mtod(m, caddr_t)+m->m_len-nul;
936 for (i = 0; i < nul; i++)
937 *cp++ = '\0';
938 }
939 return;
940 }
941 count -= len;
942 if (count < 0)
943 count = 0;
944 /*
945 * Correct length for chain is "count".
946 * Find the mbuf with last data, adjust its length,
947 * and toss data from remaining mbufs on chain.
948 */
949 for (m = mp; m; m = m->m_next) {
950 if (m->m_len >= count) {
951 m->m_len = count;
952 if (nul > 0) {
953 cp = mtod(m, caddr_t)+m->m_len-nul;
954 for (i = 0; i < nul; i++)
955 *cp++ = '\0';
956 }
957 if (m->m_next != NULL) {
958 m_freem(m->m_next);
959 m->m_next = NULL;
960 }
961 break;
962 }
963 count -= m->m_len;
964 }
965 }
966
967 /*
968 * Make these functions instead of macros, so that the kernel text size
969 * doesn't get too big...
970 */
971 void
972 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
973 struct vattr *before_vap, int after_ret, struct vattr *after_vap,
974 struct mbuf **mbp, char **bposp)
975 {
976 struct mbuf *mb = *mbp;
977 char *bpos = *bposp;
978 u_int32_t *tl;
979
980 if (before_ret) {
981 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
982 *tl = nfsrv_nfs_false;
983 } else {
984 tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
985 *tl++ = nfsrv_nfs_true;
986 txdr_hyper(before_vap->va_size, tl);
987 tl += 2;
988 txdr_nfsv3time(&(before_vap->va_mtime), tl);
989 tl += 2;
990 txdr_nfsv3time(&(before_vap->va_ctime), tl);
991 }
992 *bposp = bpos;
993 *mbp = mb;
994 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
995 }
996
997 void
998 nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
999 struct vattr *after_vap, struct mbuf **mbp, char **bposp)
1000 {
1001 struct mbuf *mb = *mbp;
1002 char *bpos = *bposp;
1003 u_int32_t *tl;
1004 struct nfs_fattr *fp;
1005
1006 if (after_ret) {
1007 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
1008 *tl = nfsrv_nfs_false;
1009 } else {
1010 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1011 *tl++ = nfsrv_nfs_true;
1012 fp = (struct nfs_fattr *)tl;
1013 nfsm_srvfattr(nfsd, after_vap, fp);
1014 }
1015 *mbp = mb;
1016 *bposp = bpos;
1017 }
1018
1019 void
1020 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1021 struct nfs_fattr *fp)
1022 {
1023
1024 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1025 fp->fa_uid = txdr_unsigned(vap->va_uid);
1026 fp->fa_gid = txdr_unsigned(vap->va_gid);
1027 if (nfsd->nd_flag & ND_NFSV3) {
1028 fp->fa_type = vtonfsv3_type(vap->va_type);
1029 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1030 txdr_hyper(vap->va_size, &fp->fa3_size);
1031 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1032 fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
1033 fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
1034 fp->fa3_fsid.nfsuquad[0] = 0;
1035 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1036 fp->fa3_fileid.nfsuquad[0] = 0;
1037 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1038 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1039 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1040 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1041 } else {
1042 fp->fa_type = vtonfsv2_type(vap->va_type);
1043 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1044 fp->fa2_size = txdr_unsigned(vap->va_size);
1045 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1046 if (vap->va_type == VFIFO)
1047 fp->fa2_rdev = 0xffffffff;
1048 else
1049 fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1050 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1051 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1052 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1053 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1054 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1055 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1056 }
1057 }
1058
1059 /*
1060 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1061 * - look up fsid in mount list (if not found ret error)
1062 * - get vp and export rights by calling VFS_FHTOVP()
1063 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1064 * - if not lockflag unlock it with VOP_UNLOCK()
1065 */
1066 int
1067 nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
1068 struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
1069 int *rdonlyp, int pubflag)
1070 {
1071 struct thread *td = curthread; /* XXX */
1072 struct mount *mp;
1073 int i;
1074 struct ucred *credanon;
1075 int error, exflags;
1076 int vfslocked;
1077 #ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */
1078 struct sockaddr_int *saddr;
1079 #endif
1080
1081 NFSD_LOCK_ASSERT();
1082
1083 *vpp = NULL;
1084
1085 if (nfs_ispublicfh(fhp)) {
1086 if (!pubflag || !nfs_pub.np_valid)
1087 return (ESTALE);
1088 fhp = &nfs_pub.np_handle;
1089 }
1090
1091 mp = vfs_getvfs(&fhp->fh_fsid);
1092 if (!mp)
1093 return (ESTALE);
1094 NFSD_UNLOCK();
1095 vfslocked = VFS_LOCK_GIANT(mp);
1096 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1097 if (error)
1098 goto out;
1099 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1100 if (error)
1101 goto out;
1102 #ifdef MNT_EXNORESPORT
1103 if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1104 saddr = (struct sockaddr_in *)nam;
1105 if ((saddr->sin_family == AF_INET ||
1106 saddr->sin_family == AF_INET6) &&
1107 /* same code for INET and INET6: sin*_port at same offet */
1108 ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1109 vput(*vpp);
1110 *vpp = NULL;
1111 error = NFSERR_AUTHERR | AUTH_TOOWEAK;
1112 }
1113 }
1114 #endif
1115 /*
1116 * Check/setup credentials.
1117 */
1118 if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1119 cred->cr_uid = credanon->cr_uid;
1120 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1121 cred->cr_groups[i] = credanon->cr_groups[i];
1122 cred->cr_ngroups = i;
1123 }
1124 if (exflags & MNT_EXRDONLY)
1125 *rdonlyp = 1;
1126 else
1127 *rdonlyp = 0;
1128
1129 if (!lockflag)
1130 VOP_UNLOCK(*vpp, 0, td);
1131 out:
1132 vfs_rel(mp);
1133 VFS_UNLOCK_GIANT(vfslocked);
1134 NFSD_LOCK();
1135 return (error);
1136 }
1137
1138
1139 /*
1140 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1141 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1142 * transformed this to all zeroes in both cases, so check for it.
1143 */
1144 int
1145 nfs_ispublicfh(fhandle_t *fhp)
1146 {
1147 char *cp = (char *)fhp;
1148 int i;
1149
1150 NFSD_LOCK_DONTCARE();
1151
1152 for (i = 0; i < NFSX_V3FH; i++)
1153 if (*cp++ != 0)
1154 return (FALSE);
1155 return (TRUE);
1156 }
1157
1158 /*
1159 * This function compares two net addresses by family and returns TRUE
1160 * if they are the same host.
1161 * If there is any doubt, return FALSE.
1162 * The AF_INET family is handled as a special case so that address mbufs
1163 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1164 */
1165 int
1166 netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
1167 {
1168 struct sockaddr_in *inetaddr;
1169
1170 NFSD_LOCK_DONTCARE();
1171
1172 switch (family) {
1173 case AF_INET:
1174 inetaddr = (struct sockaddr_in *)nam;
1175 if (inetaddr->sin_family == AF_INET &&
1176 inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1177 return (1);
1178 break;
1179 #ifdef INET6
1180 case AF_INET6:
1181 {
1182 register struct sockaddr_in6 *inet6addr1, *inet6addr2;
1183
1184 inet6addr1 = (struct sockaddr_in6 *)nam;
1185 inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam;
1186 /* XXX - should test sin6_scope_id ? */
1187 if (inet6addr1->sin6_family == AF_INET6 &&
1188 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1189 &inet6addr2->sin6_addr))
1190 return (1);
1191 break;
1192 }
1193 #endif
1194 default:
1195 break;
1196 };
1197 return (0);
1198 }
1199
1200 /*
1201 * Map errnos to NFS error numbers. For Version 3 also filter out error
1202 * numbers not specified for the associated procedure.
1203 */
1204 int
1205 nfsrv_errmap(struct nfsrv_descript *nd, int err)
1206 {
1207 const short *defaulterrp, *errp;
1208 int e;
1209
1210 NFSD_LOCK_DONTCARE();
1211
1212 if (nd->nd_flag & ND_NFSV3) {
1213 if (nd->nd_procnum <= NFSPROC_COMMIT) {
1214 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1215 while (*++errp) {
1216 if (*errp == err)
1217 return (err);
1218 else if (*errp > err)
1219 break;
1220 }
1221 return ((int)*defaulterrp);
1222 } else
1223 return (err & 0xffff);
1224 }
1225 e = 0;
1226 if (err <= ELAST)
1227 e = nfsrv_v2errmap[err - 1];
1228 if (e != 0)
1229 return (e);
1230 return (NFSERR_IO);
1231 }
1232
1233 /*
1234 * Sort the group list in increasing numerical order.
1235 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1236 * that used to be here.)
1237 */
1238 void
1239 nfsrvw_sort(gid_t *list, int num)
1240 {
1241 int i, j;
1242 gid_t v;
1243
1244 NFSD_LOCK_DONTCARE();
1245
1246 /* Insertion sort. */
1247 for (i = 1; i < num; i++) {
1248 v = list[i];
1249 /* find correct slot for value v, moving others up */
1250 for (j = i; --j >= 0 && v < list[j];)
1251 list[j + 1] = list[j];
1252 list[j + 1] = v;
1253 }
1254 }
1255
1256 /*
1257 * copy credentials making sure that the result can be compared with bcmp().
1258 */
1259 void
1260 nfsrv_setcred(struct ucred *incred, struct ucred *outcred)
1261 {
1262 int i;
1263
1264 NFSD_LOCK_DONTCARE();
1265
1266 bzero((caddr_t)outcred, sizeof (struct ucred));
1267 outcred->cr_ref = 1;
1268 outcred->cr_uid = incred->cr_uid;
1269 outcred->cr_ngroups = incred->cr_ngroups;
1270 for (i = 0; i < incred->cr_ngroups; i++)
1271 outcred->cr_groups[i] = incred->cr_groups[i];
1272 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1273 }
1274
1275 /*
1276 * Helper functions for macros.
1277 */
1278
1279 void
1280 nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
1281 {
1282 u_int32_t *tl;
1283
1284 NFSD_LOCK_DONTCARE();
1285
1286 if (v3) {
1287 tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1288 *tl++ = txdr_unsigned(NFSX_V3FH);
1289 bcopy(f, tl, NFSX_V3FH);
1290 } else {
1291 tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1292 bcopy(f, tl, NFSX_V2FH);
1293 }
1294 }
1295
1296 void
1297 nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
1298 {
1299 u_int32_t *tl;
1300
1301 tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1302 *tl++ = nfsrv_nfs_true;
1303 *tl++ = txdr_unsigned(NFSX_V3FH);
1304 bcopy(f, tl, NFSX_V3FH);
1305 }
1306
1307 int
1308 nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1309 {
1310 u_int32_t *tl;
1311
1312 NFSD_LOCK_DONTCARE();
1313
1314 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1315 if (tl == NULL)
1316 return EBADRPC;
1317 *s = fxdr_unsigned(int32_t, *tl);
1318 if (*s > m || *s <= 0)
1319 return EBADRPC;
1320 return 0;
1321 }
1322
1323 int
1324 nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1325 {
1326 u_int32_t *tl;
1327
1328 NFSD_LOCK_DONTCARE();
1329
1330 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1331 if (tl == NULL)
1332 return EBADRPC;
1333 *s = fxdr_unsigned(int32_t, *tl);
1334 if (*s > m)
1335 return NFSERR_NAMETOL;
1336 if (*s <= 0)
1337 return EBADRPC;
1338 return 0;
1339 }
1340
1341 int
1342 nfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1343 {
1344 u_int32_t *tl;
1345
1346 NFSD_LOCK_DONTCARE();
1347
1348 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1349 if (tl == NULL)
1350 return EBADRPC;
1351 *s = fxdr_unsigned(int32_t, *tl);
1352 if (*s > m)
1353 return NFSERR_NAMETOL;
1354 if (*s < 0)
1355 return EBADRPC;
1356 return 0;
1357 }
1358
1359 void
1360 nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
1361 char **bp, char **be, caddr_t bpos, int droplock)
1362 {
1363 struct mbuf *nmp;
1364
1365 NFSD_LOCK_DONTCARE();
1366
1367 if (droplock)
1368 NFSD_LOCK_ASSERT();
1369 else
1370 NFSD_UNLOCK_ASSERT();
1371
1372 if (*bp >= *be) {
1373 if (*mp == mb)
1374 (*mp)->m_len += *bp - bpos;
1375 if (droplock)
1376 NFSD_UNLOCK();
1377 MGET(nmp, M_TRYWAIT, MT_DATA);
1378 MCLGET(nmp, M_TRYWAIT);
1379 if (droplock)
1380 NFSD_LOCK();
1381 nmp->m_len = NFSMSIZ(nmp);
1382 (*mp)->m_next = nmp;
1383 *mp = nmp;
1384 *bp = mtod(*mp, caddr_t);
1385 *be = *bp + (*mp)->m_len;
1386 }
1387 *tl = (u_int32_t *)*bp;
1388 }
1389
1390 int
1391 nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
1392 caddr_t *dpos)
1393 {
1394 u_int32_t *tl;
1395 int fhlen;
1396
1397 NFSD_LOCK_DONTCARE();
1398
1399 if (nfsd->nd_flag & ND_NFSV3) {
1400 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1401 if (tl == NULL)
1402 return EBADRPC;
1403 fhlen = fxdr_unsigned(int, *tl);
1404 if (fhlen != 0 && fhlen != NFSX_V3FH)
1405 return EBADRPC;
1406 } else {
1407 fhlen = NFSX_V2FH;
1408 }
1409 if (fhlen != 0) {
1410 tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos);
1411 if (tl == NULL)
1412 return EBADRPC;
1413 bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
1414 } else {
1415 bzero((caddr_t)(f), NFSX_V3FH);
1416 }
1417 return 0;
1418 }
1419
1420 int
1421 nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
1422 {
1423 u_int32_t *tl;
1424 int toclient = 0;
1425
1426 NFSD_LOCK_DONTCARE();
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(NFSX_UNSIGNED, md, dpos);
1433 if (tl == NULL)
1434 return EBADRPC;
1435 (a)->va_mode = nfstov_mode(*tl);
1436 }
1437 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1438 if (tl == NULL)
1439 return EBADRPC;
1440 if (*tl == nfsrv_nfs_true) {
1441 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1442 if (tl == NULL)
1443 return EBADRPC;
1444 (a)->va_uid = fxdr_unsigned(uid_t, *tl);
1445 }
1446 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1447 if (tl == NULL)
1448 return EBADRPC;
1449 if (*tl == nfsrv_nfs_true) {
1450 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1451 if (tl == NULL)
1452 return EBADRPC;
1453 (a)->va_gid = fxdr_unsigned(gid_t, *tl);
1454 }
1455 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1456 if (tl == NULL)
1457 return EBADRPC;
1458 if (*tl == nfsrv_nfs_true) {
1459 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1460 if (tl == NULL)
1461 return EBADRPC;
1462 (a)->va_size = fxdr_hyper(tl);
1463 }
1464 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1465 if (tl == NULL)
1466 return EBADRPC;
1467 switch (fxdr_unsigned(int, *tl)) {
1468 case NFSV3SATTRTIME_TOCLIENT:
1469 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1470 if (tl == NULL)
1471 return EBADRPC;
1472 fxdr_nfsv3time(tl, &(a)->va_atime);
1473 toclient = 1;
1474 break;
1475 case NFSV3SATTRTIME_TOSERVER:
1476 getnanotime(&(a)->va_atime);
1477 a->va_vaflags |= VA_UTIMES_NULL;
1478 break;
1479 }
1480 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1481 if (tl == NULL)
1482 return EBADRPC;
1483 switch (fxdr_unsigned(int, *tl)) {
1484 case NFSV3SATTRTIME_TOCLIENT:
1485 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1486 if (tl == NULL)
1487 return EBADRPC;
1488 fxdr_nfsv3time(tl, &(a)->va_mtime);
1489 a->va_vaflags &= ~VA_UTIMES_NULL;
1490 break;
1491 case NFSV3SATTRTIME_TOSERVER:
1492 getnanotime(&(a)->va_mtime);
1493 if (toclient == 0)
1494 a->va_vaflags |= VA_UTIMES_NULL;
1495 break;
1496 }
1497 return 0;
1498 }
Cache object: 789cfef5407876a0c5f374be1893ef6f
|