1 /*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
33 */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 /*
39 * These functions support the macros and help fiddle mbuf chains for
40 * the nfs op functions. They do things like create the rpc header and
41 * copy data between mbuf chains and uio lists.
42 */
43
44 #include "opt_inet6.h"
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/bio.h>
50 #include <sys/buf.h>
51 #include <sys/proc.h>
52 #include <sys/mount.h>
53 #include <sys/vnode.h>
54 #include <sys/namei.h>
55 #include <sys/mbuf.h>
56 #include <sys/refcount.h>
57 #include <sys/socket.h>
58 #include <sys/stat.h>
59 #include <sys/malloc.h>
60 #include <sys/module.h>
61 #include <sys/sysent.h>
62 #include <sys/syscall.h>
63 #include <sys/sysproto.h>
64
65 #include <vm/vm.h>
66 #include <vm/vm_object.h>
67 #include <vm/vm_extern.h>
68 #include <vm/uma.h>
69
70 #include <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 */
83 u_int32_t nfsrv_nfs_xdrneg1;
84 u_int32_t nfsrv_nfs_true, nfsrv_nfs_false;
85
86 /* And other global data */
87 static 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
92 int nfsrv_ticks;
93
94 struct mtx nfsd_mtx;
95
96 /*
97 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
98 */
99 const 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 */
128 const 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 */
159 static 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 */
188 static const short nfsv3err_null[] = {
189 0,
190 0,
191 };
192
193 static const short nfsv3err_getattr[] = {
194 NFSERR_IO,
195 NFSERR_IO,
196 NFSERR_STALE,
197 NFSERR_BADHANDLE,
198 NFSERR_SERVERFAULT,
199 0,
200 };
201
202 static 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
218 static 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
231 static const short nfsv3err_access[] = {
232 NFSERR_IO,
233 NFSERR_IO,
234 NFSERR_STALE,
235 NFSERR_BADHANDLE,
236 NFSERR_SERVERFAULT,
237 0,
238 };
239
240 static 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
252 static 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
264 static 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
279 static 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
296 static 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
313 static 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
330 static 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
348 static 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
362 static 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
380 static 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
403 static 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
423 static 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
436 static 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
450 static const short nfsv3err_fsstat[] = {
451 NFSERR_IO,
452 NFSERR_IO,
453 NFSERR_STALE,
454 NFSERR_BADHANDLE,
455 NFSERR_SERVERFAULT,
456 0,
457 };
458
459 static const short nfsv3err_fsinfo[] = {
460 NFSERR_STALE,
461 NFSERR_STALE,
462 NFSERR_BADHANDLE,
463 NFSERR_SERVERFAULT,
464 0,
465 };
466
467 static const short nfsv3err_pathconf[] = {
468 NFSERR_STALE,
469 NFSERR_STALE,
470 NFSERR_BADHANDLE,
471 NFSERR_SERVERFAULT,
472 0,
473 };
474
475 static const short nfsv3err_commit[] = {
476 NFSERR_IO,
477 NFSERR_IO,
478 NFSERR_STALE,
479 NFSERR_BADHANDLE,
480 NFSERR_SERVERFAULT,
481 0,
482 };
483
484 static 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
509 extern int (*nfsd_call_nfsserver)(struct thread *, struct nfssvc_args *);
510
511 /*
512 * Called once to initialize data structures...
513 */
514 static int
515 nfsrv_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 }
552 static moduledata_t nfsserver_mod = {
553 "nfsserver",
554 nfsrv_modevent,
555 NULL,
556 };
557 DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
558
559 /* So that loader and kldload(2) can find us, wherever we are.. */
560 MODULE_VERSION(nfsserver, 1);
561 MODULE_DEPEND(nfsserver, nfssvc, 1, 1, 1);
562 MODULE_DEPEND(nfsserver, krpc, 1, 1, 1);
563 MODULE_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 */
581 int
582 nfs_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 if (!pubflag && nfs_ispublicfh(fhp))
643 return (ESTALE);
644
645 /*
646 * Extract and set starting directory.
647 */
648 error = nfsrv_fhtovp(fhp, 0, &dp, &dvfslocked, nfsd, slp, nam, &rdonly);
649 if (error)
650 goto out;
651 vfslocked = VFS_LOCK_GIANT(dp->v_mount);
652 if (dp->v_type != VDIR) {
653 vput(dp);
654 error = ENOTDIR;
655 goto out;
656 }
657
658 if (rdonly)
659 cnp->cn_flags |= RDONLY;
660
661 /*
662 * Set return directory. Reference to dp is implicitly transfered
663 * to the returned pointer
664 */
665 *retdirp = dp;
666 if (v3) {
667 *retdirattr_retp = VOP_GETATTR(dp, retdirattrp,
668 ndp->ni_cnd.cn_cred);
669 }
670
671 VOP_UNLOCK(dp, 0);
672
673 if (pubflag) {
674 /*
675 * Oh joy. For WebNFS, handle those pesky '%' escapes,
676 * and the 'native path' indicator.
677 */
678 cp = uma_zalloc(namei_zone, M_WAITOK);
679 fromcp = cnp->cn_pnbuf;
680 tocp = cp;
681 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
682 switch ((unsigned char)*fromcp) {
683 case WEBNFS_NATIVE_CHAR:
684 /*
685 * 'Native' path for us is the same
686 * as a path according to the NFS spec,
687 * just skip the escape char.
688 */
689 fromcp++;
690 break;
691 /*
692 * More may be added in the future, range 0x80-0xff
693 */
694 default:
695 error = EIO;
696 uma_zfree(namei_zone, cp);
697 goto out;
698 }
699 }
700 /*
701 * Translate the '%' escapes, URL-style.
702 */
703 while (*fromcp != '\0') {
704 if (*fromcp == WEBNFS_ESC_CHAR) {
705 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
706 fromcp++;
707 *tocp++ = HEXSTRTOI(fromcp);
708 fromcp += 2;
709 continue;
710 } else {
711 error = ENOENT;
712 uma_zfree(namei_zone, cp);
713 goto out;
714 }
715 } else
716 *tocp++ = *fromcp++;
717 }
718 *tocp = '\0';
719 uma_zfree(namei_zone, cnp->cn_pnbuf);
720 cnp->cn_pnbuf = cp;
721 }
722
723 ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
724 ndp->ni_segflg = UIO_SYSSPACE;
725
726 if (pubflag) {
727 ndp->ni_rootdir = rootvnode;
728 ndp->ni_loopcnt = 0;
729 if (cnp->cn_pnbuf[0] == '/') {
730 int tvfslocked;
731
732 tvfslocked = VFS_LOCK_GIANT(rootvnode->v_mount);
733 VFS_UNLOCK_GIANT(vfslocked);
734 dp = rootvnode;
735 vfslocked = tvfslocked;
736 }
737 } else {
738 cnp->cn_flags |= NOCROSSMOUNT;
739 }
740
741 /*
742 * Initialize for scan, set ni_startdir and bump ref on dp again
743 * because lookup() will dereference ni_startdir.
744 */
745
746 cnp->cn_thread = curthread;
747 VREF(dp);
748 ndp->ni_startdir = dp;
749
750 if (!lockleaf)
751 cnp->cn_flags |= LOCKLEAF;
752 for (;;) {
753 cnp->cn_nameptr = cnp->cn_pnbuf;
754 /*
755 * Call lookup() to do the real work. If an error occurs,
756 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
757 * we do not have to dereference anything before returning.
758 * In either case ni_startdir will be dereferenced and NULLed
759 * out.
760 */
761 if (vfslocked)
762 ndp->ni_cnd.cn_flags |= GIANTHELD;
763 error = lookup(ndp);
764 vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
765 ndp->ni_cnd.cn_flags &= ~GIANTHELD;
766 if (error)
767 break;
768
769 /*
770 * Check for encountering a symbolic link. Trivial
771 * termination occurs if no symlink encountered.
772 * Note: zfree is safe because error is 0, so we will
773 * not zfree it again when we break.
774 */
775 if ((cnp->cn_flags & ISSYMLINK) == 0) {
776 if (cnp->cn_flags & (SAVENAME | SAVESTART))
777 cnp->cn_flags |= HASBUF;
778 else
779 uma_zfree(namei_zone, cnp->cn_pnbuf);
780 if (ndp->ni_vp && !lockleaf)
781 VOP_UNLOCK(ndp->ni_vp, 0);
782 break;
783 }
784
785 /*
786 * Validate symlink
787 */
788 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
789 VOP_UNLOCK(ndp->ni_dvp, 0);
790 if (!pubflag) {
791 error = EINVAL;
792 goto badlink2;
793 }
794
795 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
796 error = ELOOP;
797 goto badlink2;
798 }
799 if (ndp->ni_pathlen > 1)
800 cp = uma_zalloc(namei_zone, M_WAITOK);
801 else
802 cp = cnp->cn_pnbuf;
803 aiov.iov_base = cp;
804 aiov.iov_len = MAXPATHLEN;
805 auio.uio_iov = &aiov;
806 auio.uio_iovcnt = 1;
807 auio.uio_offset = 0;
808 auio.uio_rw = UIO_READ;
809 auio.uio_segflg = UIO_SYSSPACE;
810 auio.uio_td = NULL;
811 auio.uio_resid = MAXPATHLEN;
812 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
813 if (error) {
814 badlink1:
815 if (ndp->ni_pathlen > 1)
816 uma_zfree(namei_zone, cp);
817 badlink2:
818 vput(ndp->ni_vp);
819 vrele(ndp->ni_dvp);
820 break;
821 }
822 linklen = MAXPATHLEN - auio.uio_resid;
823 if (linklen == 0) {
824 error = ENOENT;
825 goto badlink1;
826 }
827 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
828 error = ENAMETOOLONG;
829 goto badlink1;
830 }
831
832 /*
833 * Adjust or replace path
834 */
835 if (ndp->ni_pathlen > 1) {
836 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
837 uma_zfree(namei_zone, cnp->cn_pnbuf);
838 cnp->cn_pnbuf = cp;
839 } else
840 cnp->cn_pnbuf[linklen] = '\0';
841 ndp->ni_pathlen += linklen;
842
843 /*
844 * Cleanup refs for next loop and check if root directory
845 * should replace current directory. Normally ni_dvp
846 * becomes the new base directory and is cleaned up when
847 * we loop. Explicitly null pointers after invalidation
848 * to clarify operation.
849 */
850 vput(ndp->ni_vp);
851 ndp->ni_vp = NULL;
852
853 if (cnp->cn_pnbuf[0] == '/') {
854 vrele(ndp->ni_dvp);
855 ndp->ni_dvp = ndp->ni_rootdir;
856 VREF(ndp->ni_dvp);
857 }
858 ndp->ni_startdir = ndp->ni_dvp;
859 ndp->ni_dvp = NULL;
860 }
861 if (!lockleaf)
862 cnp->cn_flags &= ~LOCKLEAF;
863 if (cnp->cn_flags & GIANTHELD) {
864 mtx_unlock(&Giant);
865 cnp->cn_flags &= ~GIANTHELD;
866 }
867
868 /*
869 * nfs_namei() guarentees that fields will not contain garbage
870 * whether an error occurs or not. This allows the caller to track
871 * cleanup state trivially.
872 */
873 out:
874 if (error) {
875 uma_zfree(namei_zone, cnp->cn_pnbuf);
876 ndp->ni_vp = NULL;
877 ndp->ni_dvp = NULL;
878 ndp->ni_startdir = NULL;
879 cnp->cn_flags &= ~HASBUF;
880 VFS_UNLOCK_GIANT(vfslocked);
881 vfslocked = 0;
882 } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
883 ndp->ni_dvp = NULL;
884 }
885 /*
886 * This differs from normal namei() in that even on failure we may
887 * return with Giant held due to the dirp return. Make sure we only
888 * have not recursed however. The calling code only expects to drop
889 * one acquire.
890 */
891 if (vfslocked || dvfslocked)
892 ndp->ni_cnd.cn_flags |= GIANTHELD;
893 if (vfslocked && dvfslocked)
894 VFS_UNLOCK_GIANT(vfslocked);
895 return (error);
896 }
897
898 /*
899 * A fiddled version of m_adj() that ensures null fill to a long
900 * boundary and only trims off the back end
901 */
902 void
903 nfsm_adj(struct mbuf *mp, int len, int nul)
904 {
905 struct mbuf *m;
906 int count, i;
907 char *cp;
908
909 /*
910 * Trim from tail. Scan the mbuf chain,
911 * calculating its length and finding the last mbuf.
912 * If the adjustment only affects this mbuf, then just
913 * adjust and return. Otherwise, rescan and truncate
914 * after the remaining size.
915 */
916 count = 0;
917 m = mp;
918 for (;;) {
919 count += m->m_len;
920 if (m->m_next == NULL)
921 break;
922 m = m->m_next;
923 }
924 if (m->m_len > len) {
925 m->m_len -= len;
926 if (nul > 0) {
927 cp = mtod(m, caddr_t)+m->m_len-nul;
928 for (i = 0; i < nul; i++)
929 *cp++ = '\0';
930 }
931 return;
932 }
933 count -= len;
934 if (count < 0)
935 count = 0;
936 /*
937 * Correct length for chain is "count".
938 * Find the mbuf with last data, adjust its length,
939 * and toss data from remaining mbufs on chain.
940 */
941 for (m = mp; m; m = m->m_next) {
942 if (m->m_len >= count) {
943 m->m_len = count;
944 if (nul > 0) {
945 cp = mtod(m, caddr_t)+m->m_len-nul;
946 for (i = 0; i < nul; i++)
947 *cp++ = '\0';
948 }
949 if (m->m_next != NULL) {
950 m_freem(m->m_next);
951 m->m_next = NULL;
952 }
953 break;
954 }
955 count -= m->m_len;
956 }
957 }
958
959 /*
960 * Make these functions instead of macros, so that the kernel text size
961 * doesn't get too big...
962 */
963 void
964 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
965 struct vattr *before_vap, int after_ret, struct vattr *after_vap,
966 struct mbuf **mbp, char **bposp)
967 {
968 struct mbuf *mb = *mbp;
969 char *bpos = *bposp;
970 u_int32_t *tl;
971
972 if (before_ret) {
973 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
974 *tl = nfsrv_nfs_false;
975 } else {
976 tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
977 *tl++ = nfsrv_nfs_true;
978 txdr_hyper(before_vap->va_size, tl);
979 tl += 2;
980 txdr_nfsv3time(&(before_vap->va_mtime), tl);
981 tl += 2;
982 txdr_nfsv3time(&(before_vap->va_ctime), tl);
983 }
984 *bposp = bpos;
985 *mbp = mb;
986 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
987 }
988
989 void
990 nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
991 struct vattr *after_vap, struct mbuf **mbp, char **bposp)
992 {
993 struct mbuf *mb = *mbp;
994 char *bpos = *bposp;
995 u_int32_t *tl;
996 struct nfs_fattr *fp;
997
998 if (after_ret) {
999 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
1000 *tl = nfsrv_nfs_false;
1001 } else {
1002 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1003 *tl++ = nfsrv_nfs_true;
1004 fp = (struct nfs_fattr *)tl;
1005 nfsm_srvfattr(nfsd, after_vap, fp);
1006 }
1007 *mbp = mb;
1008 *bposp = bpos;
1009 }
1010
1011 void
1012 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
1013 struct nfs_fattr *fp)
1014 {
1015
1016 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1017 fp->fa_uid = txdr_unsigned(vap->va_uid);
1018 fp->fa_gid = txdr_unsigned(vap->va_gid);
1019 if (nfsd->nd_flag & ND_NFSV3) {
1020 fp->fa_type = vtonfsv3_type(vap->va_type);
1021 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1022 txdr_hyper(vap->va_size, &fp->fa3_size);
1023 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1024 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
1025 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
1026 fp->fa3_fsid.nfsuquad[0] = 0;
1027 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1028 fp->fa3_fileid.nfsuquad[0] = 0;
1029 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1030 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1031 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1032 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1033 } else {
1034 fp->fa_type = vtonfsv2_type(vap->va_type);
1035 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1036 fp->fa2_size = txdr_unsigned(vap->va_size);
1037 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1038 if (vap->va_type == VFIFO)
1039 fp->fa2_rdev = 0xffffffff;
1040 else
1041 fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1042 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1043 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1044 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1045 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1046 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1047 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1048 }
1049 }
1050
1051 /*
1052 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1053 * - look up fsid in mount list (if not found ret error)
1054 * - get vp and export rights by calling VFS_FHTOVP()
1055 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1056 */
1057 int
1058 nfsrv_fhtovp(fhandle_t *fhp, int flags, struct vnode **vpp, int *vfslockedp,
1059 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1060 struct sockaddr *nam, int *rdonlyp)
1061 {
1062 struct mount *mp;
1063 int i;
1064 struct ucred *cred, *credanon;
1065 int error, exflags;
1066 #ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */
1067 struct sockaddr_int *saddr;
1068 #endif
1069 int credflavor;
1070 int vfslocked;
1071 int numsecflavors, *secflavors;
1072 int authsys;
1073 int v3 = nfsd->nd_flag & ND_NFSV3;
1074 int mountreq;
1075
1076 *vfslockedp = 0;
1077 *vpp = NULL;
1078
1079 if (nfs_ispublicfh(fhp)) {
1080 if (!nfs_pub.np_valid)
1081 return (ESTALE);
1082 fhp = &nfs_pub.np_handle;
1083 }
1084
1085 mp = vfs_busyfs(&fhp->fh_fsid);
1086 if (!mp)
1087 return (ESTALE);
1088 vfslocked = VFS_LOCK_GIANT(mp);
1089 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon,
1090 &numsecflavors, &secflavors);
1091 if (error) {
1092 vfs_unbusy(mp);
1093 goto out;
1094 }
1095 if (numsecflavors == 0) {
1096 /*
1097 * This can happen if the system is running with an
1098 * old mountd that doesn't pass in a secflavor list.
1099 */
1100 numsecflavors = 1;
1101 authsys = AUTH_SYS;
1102 secflavors = &authsys;
1103 }
1104 credflavor = nfsd->nd_credflavor;
1105 for (i = 0; i < numsecflavors; i++) {
1106 if (secflavors[i] == credflavor)
1107 break;
1108 }
1109 if (i == numsecflavors) {
1110 /*
1111 * RFC 2623 section 2.3.2 - allow certain procedures
1112 * used at NFS client mount time even if they have
1113 * weak authentication.
1114 */
1115 mountreq = FALSE;
1116 if (v3) {
1117 if (nfsd->nd_procnum == NFSPROC_FSINFO
1118 || nfsd->nd_procnum == NFSPROC_GETATTR)
1119 mountreq = TRUE;
1120 } else {
1121 if (nfsd->nd_procnum == NFSPROC_FSSTAT
1122 || nfsd->nd_procnum == NFSPROC_GETATTR)
1123 mountreq = TRUE;
1124 }
1125 if (!mountreq) {
1126 error = NFSERR_AUTHERR | AUTH_TOOWEAK;
1127 vfs_unbusy(mp);
1128 goto out;
1129 }
1130 }
1131 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1132 if (error) {
1133 /* Make sure the server replies ESTALE to the client. */
1134 error = ESTALE;
1135 vfs_unbusy(mp);
1136 goto out;
1137 }
1138 #ifdef MNT_EXNORESPORT
1139 if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1140 saddr = (struct sockaddr_in *)nam;
1141 if ((saddr->sin_family == AF_INET ||
1142 saddr->sin_family == AF_INET6) &&
1143 /* same code for INET and INET6: sin*_port at same offet */
1144 ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1145 vput(*vpp);
1146 *vpp = NULL;
1147 error = NFSERR_AUTHERR | AUTH_TOOWEAK;
1148 vfs_unbusy(mp);
1149 goto out;
1150 }
1151 }
1152 #endif
1153 /*
1154 * Check/setup credentials.
1155 */
1156 cred = nfsd->nd_cr;
1157 if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1158 cred->cr_uid = credanon->cr_uid;
1159 crsetgroups(cred, credanon->cr_ngroups, credanon->cr_groups);
1160 }
1161 if (exflags & MNT_EXRDONLY)
1162 *rdonlyp = 1;
1163 else
1164 *rdonlyp = 0;
1165
1166 if (!(flags & NFSRV_FLAG_BUSY))
1167 vfs_unbusy(mp);
1168 out:
1169 if (credanon != NULL)
1170 crfree(credanon);
1171
1172 if (error) {
1173 VFS_UNLOCK_GIANT(vfslocked);
1174 } else
1175 *vfslockedp = vfslocked;
1176 return (error);
1177 }
1178
1179
1180 /*
1181 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1182 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1183 * transformed this to all zeroes in both cases, so check for it.
1184 */
1185 int
1186 nfs_ispublicfh(fhandle_t *fhp)
1187 {
1188 char *cp = (char *)fhp;
1189 int i;
1190
1191 NFSD_LOCK_DONTCARE();
1192
1193 for (i = 0; i < NFSX_V3FH; i++)
1194 if (*cp++ != 0)
1195 return (FALSE);
1196 return (TRUE);
1197 }
1198
1199 /*
1200 * Map errnos to NFS error numbers. For Version 3 also filter out error
1201 * numbers not specified for the associated procedure.
1202 */
1203 int
1204 nfsrv_errmap(struct nfsrv_descript *nd, int err)
1205 {
1206 const short *defaulterrp, *errp;
1207 int e;
1208
1209
1210 if (nd->nd_flag & ND_NFSV3) {
1211 if (nd->nd_procnum <= NFSPROC_COMMIT) {
1212 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1213 while (*++errp) {
1214 if (*errp == err)
1215 return (err);
1216 else if (*errp > err)
1217 break;
1218 }
1219 return ((int)*defaulterrp);
1220 } else
1221 return (err & 0xffff);
1222 }
1223 e = 0;
1224 if (err <= ELAST)
1225 e = nfsrv_v2errmap[err - 1];
1226 if (e != 0)
1227 return (e);
1228 return (NFSERR_IO);
1229 }
1230
1231 /*
1232 * Sort the group list in increasing numerical order.
1233 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1234 * that used to be here.)
1235 */
1236 void
1237 nfsrvw_sort(gid_t *list, int num)
1238 {
1239 int i, j;
1240 gid_t v;
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 * Helper functions for macros.
1254 */
1255
1256 void
1257 nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
1258 {
1259 u_int32_t *tl;
1260
1261 if (v3) {
1262 tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1263 *tl++ = txdr_unsigned(NFSX_V3FH);
1264 bcopy(f, tl, NFSX_V3FH);
1265 } else {
1266 tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1267 bcopy(f, tl, NFSX_V2FH);
1268 }
1269 }
1270
1271 void
1272 nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
1273 {
1274 u_int32_t *tl;
1275
1276 tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1277 *tl++ = nfsrv_nfs_true;
1278 *tl++ = txdr_unsigned(NFSX_V3FH);
1279 bcopy(f, tl, NFSX_V3FH);
1280 }
1281
1282 int
1283 nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1284 {
1285 u_int32_t *tl;
1286
1287 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1288 if (tl == NULL)
1289 return EBADRPC;
1290 *s = fxdr_unsigned(int32_t, *tl);
1291 if (*s > m || *s <= 0)
1292 return EBADRPC;
1293 return 0;
1294 }
1295
1296 int
1297 nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1298 {
1299 u_int32_t *tl;
1300
1301 NFSD_LOCK_DONTCARE();
1302
1303 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1304 if (tl == NULL)
1305 return EBADRPC;
1306 *s = fxdr_unsigned(int32_t, *tl);
1307 if (*s > m)
1308 return NFSERR_NAMETOL;
1309 if (*s <= 0)
1310 return EBADRPC;
1311 return 0;
1312 }
1313
1314 int
1315 nfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1316 {
1317 u_int32_t *tl;
1318
1319 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1320 if (tl == NULL)
1321 return EBADRPC;
1322 *s = fxdr_unsigned(int32_t, *tl);
1323 if (*s > m)
1324 return NFSERR_NAMETOL;
1325 if (*s < 0)
1326 return EBADRPC;
1327 return 0;
1328 }
1329
1330 void
1331 nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
1332 char **bp, char **be, caddr_t bpos)
1333 {
1334 struct mbuf *nmp;
1335
1336 NFSD_UNLOCK_ASSERT();
1337
1338 if (*bp >= *be) {
1339 if (*mp == mb)
1340 (*mp)->m_len += *bp - bpos;
1341 MGET(nmp, M_WAIT, MT_DATA);
1342 MCLGET(nmp, M_WAIT);
1343 nmp->m_len = NFSMSIZ(nmp);
1344 (*mp)->m_next = nmp;
1345 *mp = nmp;
1346 *bp = mtod(*mp, caddr_t);
1347 *be = *bp + (*mp)->m_len;
1348 }
1349 *tl = (u_int32_t *)*bp;
1350 }
1351
1352 int
1353 nfsm_srvmtofh_xx(fhandle_t *f, int v3, struct mbuf **md, caddr_t *dpos)
1354 {
1355 u_int32_t *tl;
1356 int fhlen;
1357
1358 if (v3) {
1359 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1360 if (tl == NULL)
1361 return EBADRPC;
1362 fhlen = fxdr_unsigned(int, *tl);
1363 if (fhlen != 0 && fhlen != NFSX_V3FH)
1364 return EBADRPC;
1365 } else {
1366 fhlen = NFSX_V2FH;
1367 }
1368 if (fhlen != 0) {
1369 tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos);
1370 if (tl == NULL)
1371 return EBADRPC;
1372 bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
1373 } else {
1374 bzero((caddr_t)(f), NFSX_V3FH);
1375 }
1376 return 0;
1377 }
1378
1379 int
1380 nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
1381 {
1382 u_int32_t *tl;
1383 int toclient = 0;
1384
1385 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1386 if (tl == NULL)
1387 return EBADRPC;
1388 if (*tl == nfsrv_nfs_true) {
1389 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1390 if (tl == NULL)
1391 return EBADRPC;
1392 (a)->va_mode = nfstov_mode(*tl);
1393 }
1394 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1395 if (tl == NULL)
1396 return EBADRPC;
1397 if (*tl == nfsrv_nfs_true) {
1398 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1399 if (tl == NULL)
1400 return EBADRPC;
1401 (a)->va_uid = fxdr_unsigned(uid_t, *tl);
1402 }
1403 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1404 if (tl == NULL)
1405 return EBADRPC;
1406 if (*tl == nfsrv_nfs_true) {
1407 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1408 if (tl == NULL)
1409 return EBADRPC;
1410 (a)->va_gid = fxdr_unsigned(gid_t, *tl);
1411 }
1412 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1413 if (tl == NULL)
1414 return EBADRPC;
1415 if (*tl == nfsrv_nfs_true) {
1416 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1417 if (tl == NULL)
1418 return EBADRPC;
1419 (a)->va_size = fxdr_hyper(tl);
1420 }
1421 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1422 if (tl == NULL)
1423 return EBADRPC;
1424 switch (fxdr_unsigned(int, *tl)) {
1425 case NFSV3SATTRTIME_TOCLIENT:
1426 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1427 if (tl == NULL)
1428 return EBADRPC;
1429 fxdr_nfsv3time(tl, &(a)->va_atime);
1430 toclient = 1;
1431 break;
1432 case NFSV3SATTRTIME_TOSERVER:
1433 vfs_timestamp(&a->va_atime);
1434 a->va_vaflags |= VA_UTIMES_NULL;
1435 break;
1436 }
1437 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1438 if (tl == NULL)
1439 return EBADRPC;
1440 switch (fxdr_unsigned(int, *tl)) {
1441 case NFSV3SATTRTIME_TOCLIENT:
1442 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1443 if (tl == NULL)
1444 return EBADRPC;
1445 fxdr_nfsv3time(tl, &(a)->va_mtime);
1446 a->va_vaflags &= ~VA_UTIMES_NULL;
1447 break;
1448 case NFSV3SATTRTIME_TOSERVER:
1449 vfs_timestamp(&a->va_mtime);
1450 if (toclient == 0)
1451 a->va_vaflags |= VA_UTIMES_NULL;
1452 break;
1453 }
1454 return 0;
1455 }
Cache object: 01bab879fa3ef069d55de6fe692aaa33
|