Deleted Added
sdiff udiff text old ( 157325 ) new ( 157391 )
full compact
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: head/sys/nfsserver/nfs_srvsubs.c 157325 2006-03-31 03:54:20Z jeff $");
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 */
82u_int32_t nfsrv_nfs_xdrneg1;
83u_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;
86u_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false;
87
88/* And other global data */
89static 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
94int nfsrv_ticks;
95
96struct nfssvc_sockhead nfssvc_sockhead;
97int nfssvc_sockhead_flag;
98struct nfsd_head nfsd_head;
99int nfsd_head_flag;
100
101static int nfs_prev_nfssvc_sy_narg;
102static sy_call_t *nfs_prev_nfssvc_sy_call;
103
104struct mtx nfsd_mtx;
105
106/*
107 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
108 */
109const int nfsrv_nfsv3_procid[NFS_NPROCS] = {
110 NFSPROC_NULL,
111 NFSPROC_GETATTR,
112 NFSPROC_SETATTR,
113 NFSPROC_NOOP,
114 NFSPROC_LOOKUP,
115 NFSPROC_READLINK,
116 NFSPROC_READ,
117 NFSPROC_NOOP,
118 NFSPROC_WRITE,
119 NFSPROC_CREATE,
120 NFSPROC_REMOVE,
121 NFSPROC_RENAME,
122 NFSPROC_LINK,
123 NFSPROC_SYMLINK,
124 NFSPROC_MKDIR,
125 NFSPROC_RMDIR,
126 NFSPROC_READDIR,
127 NFSPROC_FSSTAT,
128 NFSPROC_NOOP,
129 NFSPROC_NOOP,
130 NFSPROC_NOOP,
131 NFSPROC_NOOP,
132 NFSPROC_NOOP,
133};
134
135/*
136 * and the reverse mapping from generic to Version 2 procedure numbers
137 */
138const int nfsrvv2_procid[NFS_NPROCS] = {
139 NFSV2PROC_NULL,
140 NFSV2PROC_GETATTR,
141 NFSV2PROC_SETATTR,
142 NFSV2PROC_LOOKUP,
143 NFSV2PROC_NOOP,
144 NFSV2PROC_READLINK,
145 NFSV2PROC_READ,
146 NFSV2PROC_WRITE,
147 NFSV2PROC_CREATE,
148 NFSV2PROC_MKDIR,
149 NFSV2PROC_SYMLINK,
150 NFSV2PROC_CREATE,
151 NFSV2PROC_REMOVE,
152 NFSV2PROC_RMDIR,
153 NFSV2PROC_RENAME,
154 NFSV2PROC_LINK,
155 NFSV2PROC_READDIR,
156 NFSV2PROC_NOOP,
157 NFSV2PROC_STATFS,
158 NFSV2PROC_NOOP,
159 NFSV2PROC_NOOP,
160 NFSV2PROC_NOOP,
161 NFSV2PROC_NOOP,
162};
163
164/*
165 * Maps errno values to nfs error numbers.
166 * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not
167 * specifically defined in RFC 1094.
168 */
169static const u_char nfsrv_v2errmap[ELAST] = {
170 NFSERR_PERM, NFSERR_NOENT, 0, 0, 0,
171 NFSERR_NXIO, 0, 0, 0, 0,
172 0, 0, NFSERR_ACCES, 0, 0,
173 0, NFSERR_EXIST, 0, NFSERR_NODEV, NFSERR_NOTDIR,
174 NFSERR_ISDIR, 0, 0, 0, 0,
175 0, NFSERR_FBIG, NFSERR_NOSPC, 0, NFSERR_ROFS,
176 0, 0, 0, 0, 0,
177 0, 0, 0, 0, 0,
178 0, 0, 0, 0, 0,
179 0, 0, 0, 0, 0,
180 0, 0, 0, 0, 0,
181 0, 0, 0, 0, 0,
182 0, 0, NFSERR_NAMETOL, 0, 0,
183 NFSERR_NOTEMPTY, 0, 0, NFSERR_DQUOT, NFSERR_STALE,
184 0
185};
186
187/*
188 * Maps errno values to nfs error numbers.
189 * Although it is not obvious whether or not NFS clients really care if
190 * a returned error value is in the specified list for the procedure, the
191 * safest thing to do is filter them appropriately. For Version 2, the
192 * X/Open XNFS document is the only specification that defines error values
193 * for each RPC (The RFC simply lists all possible error values for all RPCs),
194 * so I have decided to not do this for Version 2.
195 * The first entry is the default error return and the rest are the valid
196 * errors for that RPC in increasing numeric order.
197 */
198static const short nfsv3err_null[] = {
199 0,
200 0,
201};
202
203static const short nfsv3err_getattr[] = {
204 NFSERR_IO,
205 NFSERR_IO,
206 NFSERR_STALE,
207 NFSERR_BADHANDLE,
208 NFSERR_SERVERFAULT,
209 0,
210};
211
212static const short nfsv3err_setattr[] = {
213 NFSERR_IO,
214 NFSERR_PERM,
215 NFSERR_IO,
216 NFSERR_ACCES,
217 NFSERR_INVAL,
218 NFSERR_NOSPC,
219 NFSERR_ROFS,
220 NFSERR_DQUOT,
221 NFSERR_STALE,
222 NFSERR_BADHANDLE,
223 NFSERR_NOT_SYNC,
224 NFSERR_SERVERFAULT,
225 0,
226};
227
228static const short nfsv3err_lookup[] = {
229 NFSERR_IO,
230 NFSERR_NOENT,
231 NFSERR_IO,
232 NFSERR_ACCES,
233 NFSERR_NOTDIR,
234 NFSERR_NAMETOL,
235 NFSERR_STALE,
236 NFSERR_BADHANDLE,
237 NFSERR_SERVERFAULT,
238 0,
239};
240
241static const short nfsv3err_access[] = {
242 NFSERR_IO,
243 NFSERR_IO,
244 NFSERR_STALE,
245 NFSERR_BADHANDLE,
246 NFSERR_SERVERFAULT,
247 0,
248};
249
250static const short nfsv3err_readlink[] = {
251 NFSERR_IO,
252 NFSERR_IO,
253 NFSERR_ACCES,
254 NFSERR_INVAL,
255 NFSERR_STALE,
256 NFSERR_BADHANDLE,
257 NFSERR_NOTSUPP,
258 NFSERR_SERVERFAULT,
259 0,
260};
261
262static const short nfsv3err_read[] = {
263 NFSERR_IO,
264 NFSERR_IO,
265 NFSERR_NXIO,
266 NFSERR_ACCES,
267 NFSERR_INVAL,
268 NFSERR_STALE,
269 NFSERR_BADHANDLE,
270 NFSERR_SERVERFAULT,
271 0,
272};
273
274static const short nfsv3err_write[] = {
275 NFSERR_IO,
276 NFSERR_IO,
277 NFSERR_ACCES,
278 NFSERR_INVAL,
279 NFSERR_FBIG,
280 NFSERR_NOSPC,
281 NFSERR_ROFS,
282 NFSERR_DQUOT,
283 NFSERR_STALE,
284 NFSERR_BADHANDLE,
285 NFSERR_SERVERFAULT,
286 0,
287};
288
289static const short nfsv3err_create[] = {
290 NFSERR_IO,
291 NFSERR_IO,
292 NFSERR_ACCES,
293 NFSERR_EXIST,
294 NFSERR_NOTDIR,
295 NFSERR_NOSPC,
296 NFSERR_ROFS,
297 NFSERR_NAMETOL,
298 NFSERR_DQUOT,
299 NFSERR_STALE,
300 NFSERR_BADHANDLE,
301 NFSERR_NOTSUPP,
302 NFSERR_SERVERFAULT,
303 0,
304};
305
306static const short nfsv3err_mkdir[] = {
307 NFSERR_IO,
308 NFSERR_IO,
309 NFSERR_ACCES,
310 NFSERR_EXIST,
311 NFSERR_NOTDIR,
312 NFSERR_NOSPC,
313 NFSERR_ROFS,
314 NFSERR_NAMETOL,
315 NFSERR_DQUOT,
316 NFSERR_STALE,
317 NFSERR_BADHANDLE,
318 NFSERR_NOTSUPP,
319 NFSERR_SERVERFAULT,
320 0,
321};
322
323static const short nfsv3err_symlink[] = {
324 NFSERR_IO,
325 NFSERR_IO,
326 NFSERR_ACCES,
327 NFSERR_EXIST,
328 NFSERR_NOTDIR,
329 NFSERR_NOSPC,
330 NFSERR_ROFS,
331 NFSERR_NAMETOL,
332 NFSERR_DQUOT,
333 NFSERR_STALE,
334 NFSERR_BADHANDLE,
335 NFSERR_NOTSUPP,
336 NFSERR_SERVERFAULT,
337 0,
338};
339
340static const short nfsv3err_mknod[] = {
341 NFSERR_IO,
342 NFSERR_IO,
343 NFSERR_ACCES,
344 NFSERR_EXIST,
345 NFSERR_NOTDIR,
346 NFSERR_NOSPC,
347 NFSERR_ROFS,
348 NFSERR_NAMETOL,
349 NFSERR_DQUOT,
350 NFSERR_STALE,
351 NFSERR_BADHANDLE,
352 NFSERR_NOTSUPP,
353 NFSERR_SERVERFAULT,
354 NFSERR_BADTYPE,
355 0,
356};
357
358static const short nfsv3err_remove[] = {
359 NFSERR_IO,
360 NFSERR_NOENT,
361 NFSERR_IO,
362 NFSERR_ACCES,
363 NFSERR_NOTDIR,
364 NFSERR_ROFS,
365 NFSERR_NAMETOL,
366 NFSERR_STALE,
367 NFSERR_BADHANDLE,
368 NFSERR_SERVERFAULT,
369 0,
370};
371
372static const short nfsv3err_rmdir[] = {
373 NFSERR_IO,
374 NFSERR_NOENT,
375 NFSERR_IO,
376 NFSERR_ACCES,
377 NFSERR_EXIST,
378 NFSERR_NOTDIR,
379 NFSERR_INVAL,
380 NFSERR_ROFS,
381 NFSERR_NAMETOL,
382 NFSERR_NOTEMPTY,
383 NFSERR_STALE,
384 NFSERR_BADHANDLE,
385 NFSERR_NOTSUPP,
386 NFSERR_SERVERFAULT,
387 0,
388};
389
390static const short nfsv3err_rename[] = {
391 NFSERR_IO,
392 NFSERR_NOENT,
393 NFSERR_IO,
394 NFSERR_ACCES,
395 NFSERR_EXIST,
396 NFSERR_XDEV,
397 NFSERR_NOTDIR,
398 NFSERR_ISDIR,
399 NFSERR_INVAL,
400 NFSERR_NOSPC,
401 NFSERR_ROFS,
402 NFSERR_MLINK,
403 NFSERR_NAMETOL,
404 NFSERR_NOTEMPTY,
405 NFSERR_DQUOT,
406 NFSERR_STALE,
407 NFSERR_BADHANDLE,
408 NFSERR_NOTSUPP,
409 NFSERR_SERVERFAULT,
410 0,
411};
412
413static const short nfsv3err_link[] = {
414 NFSERR_IO,
415 NFSERR_IO,
416 NFSERR_ACCES,
417 NFSERR_EXIST,
418 NFSERR_XDEV,
419 NFSERR_NOTDIR,
420 NFSERR_INVAL,
421 NFSERR_NOSPC,
422 NFSERR_ROFS,
423 NFSERR_MLINK,
424 NFSERR_NAMETOL,
425 NFSERR_DQUOT,
426 NFSERR_STALE,
427 NFSERR_BADHANDLE,
428 NFSERR_NOTSUPP,
429 NFSERR_SERVERFAULT,
430 0,
431};
432
433static const short nfsv3err_readdir[] = {
434 NFSERR_IO,
435 NFSERR_IO,
436 NFSERR_ACCES,
437 NFSERR_NOTDIR,
438 NFSERR_STALE,
439 NFSERR_BADHANDLE,
440 NFSERR_BAD_COOKIE,
441 NFSERR_TOOSMALL,
442 NFSERR_SERVERFAULT,
443 0,
444};
445
446static const short nfsv3err_readdirplus[] = {
447 NFSERR_IO,
448 NFSERR_IO,
449 NFSERR_ACCES,
450 NFSERR_NOTDIR,
451 NFSERR_STALE,
452 NFSERR_BADHANDLE,
453 NFSERR_BAD_COOKIE,
454 NFSERR_NOTSUPP,
455 NFSERR_TOOSMALL,
456 NFSERR_SERVERFAULT,
457 0,
458};
459
460static const short nfsv3err_fsstat[] = {
461 NFSERR_IO,
462 NFSERR_IO,
463 NFSERR_STALE,
464 NFSERR_BADHANDLE,
465 NFSERR_SERVERFAULT,
466 0,
467};
468
469static const short nfsv3err_fsinfo[] = {
470 NFSERR_STALE,
471 NFSERR_STALE,
472 NFSERR_BADHANDLE,
473 NFSERR_SERVERFAULT,
474 0,
475};
476
477static const short nfsv3err_pathconf[] = {
478 NFSERR_STALE,
479 NFSERR_STALE,
480 NFSERR_BADHANDLE,
481 NFSERR_SERVERFAULT,
482 0,
483};
484
485static const short nfsv3err_commit[] = {
486 NFSERR_IO,
487 NFSERR_IO,
488 NFSERR_STALE,
489 NFSERR_BADHANDLE,
490 NFSERR_SERVERFAULT,
491 0,
492};
493
494static const short *nfsrv_v3errmap[] = {
495 nfsv3err_null,
496 nfsv3err_getattr,
497 nfsv3err_setattr,
498 nfsv3err_lookup,
499 nfsv3err_access,
500 nfsv3err_readlink,
501 nfsv3err_read,
502 nfsv3err_write,
503 nfsv3err_create,
504 nfsv3err_mkdir,
505 nfsv3err_symlink,
506 nfsv3err_mknod,
507 nfsv3err_remove,
508 nfsv3err_rmdir,
509 nfsv3err_rename,
510 nfsv3err_link,
511 nfsv3err_readdir,
512 nfsv3err_readdirplus,
513 nfsv3err_fsstat,
514 nfsv3err_fsinfo,
515 nfsv3err_pathconf,
516 nfsv3err_commit,
517};
518
519/*
520 * Called once to initialize data structures...
521 */
522static int
523nfsrv_modevent(module_t mod, int type, void *data)
524{
525 int error = 0;
526
527 NET_LOCK_GIANT();
528 switch (type) {
529 case MOD_LOAD:
530 mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF);
531 nfsrv_rpc_vers = txdr_unsigned(RPC_VER2);
532 nfsrv_rpc_call = txdr_unsigned(RPC_CALL);
533 nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY);
534 nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
535 nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
536 nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
537 nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR);
538 nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
539 nfsrv_nfs_prog = txdr_unsigned(NFS_PROG);
540 nfsrv_nfs_true = txdr_unsigned(TRUE);
541 nfsrv_nfs_false = txdr_unsigned(FALSE);
542 nfsrv_nfs_xdrneg1 = txdr_unsigned(-1);
543 nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
544 if (nfsrv_ticks < 1)
545 nfsrv_ticks = 1;
546
547 nfsrv_initcache(); /* Init the server request cache */
548 NFSD_LOCK();
549 nfsrv_init(0); /* Init server data structures */
550 if (debug_mpsafenet)
551 callout_init(&nfsrv_callout, CALLOUT_MPSAFE);
552 else
553 callout_init(&nfsrv_callout, 0);
554 NFSD_UNLOCK();
555 nfsrv_timer(0);
556
557 nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
558 sysent[SYS_nfssvc].sy_narg = 2 | SYF_MPSAFE;
559 nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
560 sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
561 break;
562
563 case MOD_UNLOAD:
564 if (nfsrv_numnfsd != 0) {
565 error = EBUSY;
566 break;
567 }
568
569 callout_stop(&nfsrv_callout);
570 sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
571 sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
572 mtx_destroy(&nfsd_mtx);
573 break;
574 default:
575 error = EOPNOTSUPP;
576 break;
577 }
578 NET_UNLOCK_GIANT();
579 return error;
580}
581static moduledata_t nfsserver_mod = {
582 "nfsserver",
583 nfsrv_modevent,
584 NULL,
585};
586DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
587
588/* So that loader and kldload(2) can find us, wherever we are.. */
589MODULE_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 */
607int
608nfs_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
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 */
885out:
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 */
904void
905nfsm_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 if (m->m_next != NULL) {
954 m_freem(m->m_next);
955 m->m_next = NULL;
956 }
957 break;
958 }
959 count -= m->m_len;
960 }
961}
962
963/*
964 * Make these functions instead of macros, so that the kernel text size
965 * doesn't get too big...
966 */
967void
968nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
969 struct vattr *before_vap, int after_ret, struct vattr *after_vap,
970 struct mbuf **mbp, char **bposp)
971{
972 struct mbuf *mb = *mbp;
973 char *bpos = *bposp;
974 u_int32_t *tl;
975
976 if (before_ret) {
977 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
978 *tl = nfsrv_nfs_false;
979 } else {
980 tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
981 *tl++ = nfsrv_nfs_true;
982 txdr_hyper(before_vap->va_size, tl);
983 tl += 2;
984 txdr_nfsv3time(&(before_vap->va_mtime), tl);
985 tl += 2;
986 txdr_nfsv3time(&(before_vap->va_ctime), tl);
987 }
988 *bposp = bpos;
989 *mbp = mb;
990 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
991}
992
993void
994nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
995 struct vattr *after_vap, struct mbuf **mbp, char **bposp)
996{
997 struct mbuf *mb = *mbp;
998 char *bpos = *bposp;
999 u_int32_t *tl;
1000 struct nfs_fattr *fp;
1001
1002 if (after_ret) {
1003 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
1004 *tl = nfsrv_nfs_false;
1005 } else {
1006 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1007 *tl++ = nfsrv_nfs_true;
1008 fp = (struct nfs_fattr *)tl;
1009 nfsm_srvfattr(nfsd, after_vap, fp);
1010 }
1011 *mbp = mb;
1012 *bposp = bpos;
1013}
1014
1015void
1016nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1017 struct nfs_fattr *fp)
1018{
1019
1020 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1021 fp->fa_uid = txdr_unsigned(vap->va_uid);
1022 fp->fa_gid = txdr_unsigned(vap->va_gid);
1023 if (nfsd->nd_flag & ND_NFSV3) {
1024 fp->fa_type = vtonfsv3_type(vap->va_type);
1025 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1026 txdr_hyper(vap->va_size, &fp->fa3_size);
1027 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1028 fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
1029 fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
1030 fp->fa3_fsid.nfsuquad[0] = 0;
1031 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1032 fp->fa3_fileid.nfsuquad[0] = 0;
1033 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1034 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1035 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1036 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1037 } else {
1038 fp->fa_type = vtonfsv2_type(vap->va_type);
1039 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1040 fp->fa2_size = txdr_unsigned(vap->va_size);
1041 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1042 if (vap->va_type == VFIFO)
1043 fp->fa2_rdev = 0xffffffff;
1044 else
1045 fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1046 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1047 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1048 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1049 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1050 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1051 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1052 }
1053}
1054
1055/*
1056 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1057 * - look up fsid in mount list (if not found ret error)
1058 * - get vp and export rights by calling VFS_FHTOVP()
1059 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1060 * - if not lockflag unlock it with VOP_UNLOCK()
1061 */
1062int
1063nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
1064 struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
1065 int *rdonlyp, int pubflag)
1066{
1067 struct thread *td = curthread; /* XXX */
1068 struct mount *mp;
1069 int i;
1070 struct ucred *credanon;
1071 int error, exflags;
1072 int vfslocked;
1073#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */
1074 struct sockaddr_int *saddr;
1075#endif
1076
1077 NFSD_LOCK_ASSERT();
1078
1079 *vpp = NULL;
1080
1081 if (nfs_ispublicfh(fhp)) {
1082 if (!pubflag || !nfs_pub.np_valid)
1083 return (ESTALE);
1084 fhp = &nfs_pub.np_handle;
1085 }
1086
1087 mp = vfs_getvfs(&fhp->fh_fsid);
1088 if (!mp)
1089 return (ESTALE);
1090 NFSD_UNLOCK();
1091 vfslocked = VFS_LOCK_GIANT(mp);
1092 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1093 if (error)
1094 goto out;
1095 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1096 if (error)
1097 goto out;
1098#ifdef MNT_EXNORESPORT
1099 if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1100 saddr = (struct sockaddr_in *)nam;
1101 if ((saddr->sin_family == AF_INET ||
1102 saddr->sin_family == AF_INET6) &&
1103 /* same code for INET and INET6: sin*_port at same offet */
1104 ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1105 vput(*vpp);
1106 *vpp = NULL;
1107 error = NFSERR_AUTHERR | AUTH_TOOWEAK;
1108 }
1109 }
1110#endif
1111 /*
1112 * Check/setup credentials.
1113 */
1114 if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1115 cred->cr_uid = credanon->cr_uid;
1116 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1117 cred->cr_groups[i] = credanon->cr_groups[i];
1118 cred->cr_ngroups = i;
1119 }
1120 if (exflags & MNT_EXRDONLY)
1121 *rdonlyp = 1;
1122 else
1123 *rdonlyp = 0;
1124
1125 if (!lockflag)
1126 VOP_UNLOCK(*vpp, 0, td);
1127out:
1128 vfs_rel(mp);
1129 VFS_UNLOCK_GIANT(vfslocked);
1130 NFSD_LOCK();
1131 return (error);
1132}
1133
1134
1135/*
1136 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1137 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1138 * transformed this to all zeroes in both cases, so check for it.
1139 */
1140int
1141nfs_ispublicfh(fhandle_t *fhp)
1142{
1143 char *cp = (char *)fhp;
1144 int i;
1145
1146 NFSD_LOCK_DONTCARE();
1147
1148 for (i = 0; i < NFSX_V3FH; i++)
1149 if (*cp++ != 0)
1150 return (FALSE);
1151 return (TRUE);
1152}
1153
1154/*
1155 * This function compares two net addresses by family and returns TRUE
1156 * if they are the same host.
1157 * If there is any doubt, return FALSE.
1158 * The AF_INET family is handled as a special case so that address mbufs
1159 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1160 */
1161int
1162netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
1163{
1164 struct sockaddr_in *inetaddr;
1165
1166 NFSD_LOCK_DONTCARE();
1167
1168 switch (family) {
1169 case AF_INET:
1170 inetaddr = (struct sockaddr_in *)nam;
1171 if (inetaddr->sin_family == AF_INET &&
1172 inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1173 return (1);
1174 break;
1175#ifdef INET6
1176 case AF_INET6:
1177 {
1178 register struct sockaddr_in6 *inet6addr1, *inet6addr2;
1179
1180 inet6addr1 = (struct sockaddr_in6 *)nam;
1181 inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam;
1182 /* XXX - should test sin6_scope_id ? */
1183 if (inet6addr1->sin6_family == AF_INET6 &&
1184 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1185 &inet6addr2->sin6_addr))
1186 return (1);
1187 break;
1188 }
1189#endif
1190 default:
1191 break;
1192 };
1193 return (0);
1194}
1195
1196/*
1197 * Map errnos to NFS error numbers. For Version 3 also filter out error
1198 * numbers not specified for the associated procedure.
1199 */
1200int
1201nfsrv_errmap(struct nfsrv_descript *nd, int err)
1202{
1203 const short *defaulterrp, *errp;
1204 int e;
1205
1206 NFSD_LOCK_DONTCARE();
1207
1208 if (nd->nd_flag & ND_NFSV3) {
1209 if (nd->nd_procnum <= NFSPROC_COMMIT) {
1210 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1211 while (*++errp) {
1212 if (*errp == err)
1213 return (err);
1214 else if (*errp > err)
1215 break;
1216 }
1217 return ((int)*defaulterrp);
1218 } else
1219 return (err & 0xffff);
1220 }
1221 e = 0;
1222 if (err <= ELAST)
1223 e = nfsrv_v2errmap[err - 1];
1224 if (e != 0)
1225 return (e);
1226 return (NFSERR_IO);
1227}
1228
1229/*
1230 * Sort the group list in increasing numerical order.
1231 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1232 * that used to be here.)
1233 */
1234void
1235nfsrvw_sort(gid_t *list, int num)
1236{
1237 int i, j;
1238 gid_t v;
1239
1240 NFSD_LOCK_DONTCARE();
1241
1242 /* Insertion sort. */
1243 for (i = 1; i < num; i++) {
1244 v = list[i];
1245 /* find correct slot for value v, moving others up */
1246 for (j = i; --j >= 0 && v < list[j];)
1247 list[j + 1] = list[j];
1248 list[j + 1] = v;
1249 }
1250}
1251
1252/*
1253 * copy credentials making sure that the result can be compared with bcmp().
1254 */
1255void
1256nfsrv_setcred(struct ucred *incred, struct ucred *outcred)
1257{
1258 int i;
1259
1260 NFSD_LOCK_DONTCARE();
1261
1262 bzero((caddr_t)outcred, sizeof (struct ucred));
1263 refcount_init(&outcred->cr_ref, 1);
1264 outcred->cr_uid = incred->cr_uid;
1265 outcred->cr_ngroups = incred->cr_ngroups;
1266 for (i = 0; i < incred->cr_ngroups; i++)
1267 outcred->cr_groups[i] = incred->cr_groups[i];
1268 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1269}
1270
1271/*
1272 * Helper functions for macros.
1273 */
1274
1275void
1276nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
1277{
1278 u_int32_t *tl;
1279
1280 NFSD_LOCK_DONTCARE();
1281
1282 if (v3) {
1283 tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1284 *tl++ = txdr_unsigned(NFSX_V3FH);
1285 bcopy(f, tl, NFSX_V3FH);
1286 } else {
1287 tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1288 bcopy(f, tl, NFSX_V2FH);
1289 }
1290}
1291
1292void
1293nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
1294{
1295 u_int32_t *tl;
1296
1297 tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1298 *tl++ = nfsrv_nfs_true;
1299 *tl++ = txdr_unsigned(NFSX_V3FH);
1300 bcopy(f, tl, NFSX_V3FH);
1301}
1302
1303int
1304nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1305{
1306 u_int32_t *tl;
1307
1308 NFSD_LOCK_DONTCARE();
1309
1310 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1311 if (tl == NULL)
1312 return EBADRPC;
1313 *s = fxdr_unsigned(int32_t, *tl);
1314 if (*s > m || *s <= 0)
1315 return EBADRPC;
1316 return 0;
1317}
1318
1319int
1320nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1321{
1322 u_int32_t *tl;
1323
1324 NFSD_LOCK_DONTCARE();
1325
1326 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1327 if (tl == NULL)
1328 return EBADRPC;
1329 *s = fxdr_unsigned(int32_t, *tl);
1330 if (*s > m)
1331 return NFSERR_NAMETOL;
1332 if (*s <= 0)
1333 return EBADRPC;
1334 return 0;
1335}
1336
1337void
1338nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
1339 char **bp, char **be, caddr_t bpos, int droplock)
1340{
1341 struct mbuf *nmp;
1342
1343 NFSD_LOCK_DONTCARE();
1344
1345 if (droplock)
1346 NFSD_LOCK_ASSERT();
1347 else
1348 NFSD_UNLOCK_ASSERT();
1349
1350 if (*bp >= *be) {
1351 if (*mp == mb)
1352 (*mp)->m_len += *bp - bpos;
1353 if (droplock)
1354 NFSD_UNLOCK();
1355 MGET(nmp, M_TRYWAIT, MT_DATA);
1356 MCLGET(nmp, M_TRYWAIT);
1357 if (droplock)
1358 NFSD_LOCK();
1359 nmp->m_len = NFSMSIZ(nmp);
1360 (*mp)->m_next = nmp;
1361 *mp = nmp;
1362 *bp = mtod(*mp, caddr_t);
1363 *be = *bp + (*mp)->m_len;
1364 }
1365 *tl = (u_int32_t *)*bp;
1366}
1367
1368int
1369nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
1370 caddr_t *dpos)
1371{
1372 u_int32_t *tl;
1373 int fhlen;
1374
1375 NFSD_LOCK_DONTCARE();
1376
1377 if (nfsd->nd_flag & ND_NFSV3) {
1378 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1379 if (tl == NULL)
1380 return EBADRPC;
1381 fhlen = fxdr_unsigned(int, *tl);
1382 if (fhlen != 0 && fhlen != NFSX_V3FH)
1383 return EBADRPC;
1384 } else {
1385 fhlen = NFSX_V2FH;
1386 }
1387 if (fhlen != 0) {
1388 tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos);
1389 if (tl == NULL)
1390 return EBADRPC;
1391 bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
1392 } else {
1393 bzero((caddr_t)(f), NFSX_V3FH);
1394 }
1395 return 0;
1396}
1397
1398int
1399nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
1400{
1401 u_int32_t *tl;
1402
1403 NFSD_LOCK_DONTCARE();
1404
1405 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1406 if (tl == NULL)
1407 return EBADRPC;
1408 if (*tl == nfsrv_nfs_true) {
1409 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1410 if (tl == NULL)
1411 return EBADRPC;
1412 (a)->va_mode = nfstov_mode(*tl);
1413 }
1414 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1415 if (tl == NULL)
1416 return EBADRPC;
1417 if (*tl == nfsrv_nfs_true) {
1418 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1419 if (tl == NULL)
1420 return EBADRPC;
1421 (a)->va_uid = fxdr_unsigned(uid_t, *tl);
1422 }
1423 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1424 if (tl == NULL)
1425 return EBADRPC;
1426 if (*tl == nfsrv_nfs_true) {
1427 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1428 if (tl == NULL)
1429 return EBADRPC;
1430 (a)->va_gid = fxdr_unsigned(gid_t, *tl);
1431 }
1432 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1433 if (tl == NULL)
1434 return EBADRPC;
1435 if (*tl == nfsrv_nfs_true) {
1436 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1437 if (tl == NULL)
1438 return EBADRPC;
1439 (a)->va_size = fxdr_hyper(tl);
1440 }
1441 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1442 if (tl == NULL)
1443 return EBADRPC;
1444 switch (fxdr_unsigned(int, *tl)) {
1445 case NFSV3SATTRTIME_TOCLIENT:
1446 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1447 if (tl == NULL)
1448 return EBADRPC;
1449 fxdr_nfsv3time(tl, &(a)->va_atime);
1450 break;
1451 case NFSV3SATTRTIME_TOSERVER:
1452 getnanotime(&(a)->va_atime);
1453 break;
1454 }
1455 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1456 if (tl == NULL)
1457 return EBADRPC;
1458 switch (fxdr_unsigned(int, *tl)) {
1459 case NFSV3SATTRTIME_TOCLIENT:
1460 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1461 if (tl == NULL)
1462 return EBADRPC;
1463 fxdr_nfsv3time(tl, &(a)->va_mtime);
1464 break;
1465 case NFSV3SATTRTIME_TOSERVER:
1466 getnanotime(&(a)->va_mtime);
1467 break;
1468 }
1469 return 0;
1470}