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