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
598 *retdirp = NULL;
599 cnp->cn_flags |= NOMACCHECK;
600 cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
601
602 /*
603 * Copy the name from the mbuf list to ndp->ni_pnbuf
604 * and set the various ndp fields appropriately.
605 */
606 fromcp = *dposp;
607 tocp = cnp->cn_pnbuf;
608 md = *mdp;
609 rem = mtod(md, caddr_t) + md->m_len - fromcp;
610 for (i = 0; i < len; i++) {
611 while (rem == 0) {
612 md = md->m_next;
613 if (md == NULL) {
614 error = EBADRPC;
615 goto out;
616 }
617 fromcp = mtod(md, caddr_t);
618 rem = md->m_len;
619 }
620 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
621 error = EACCES;
622 goto out;
623 }
624 *tocp++ = *fromcp++;
625 rem--;
626 }
627 *tocp = '\0';
628 *mdp = md;
629 *dposp = fromcp;
630 len = nfsm_rndup(len)-len;
631 if (len > 0) {
632 if (rem >= len)
633 *dposp += len;
634 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
635 goto out;
636 }
637
638 if (!pubflag && nfs_ispublicfh(fhp))
639 return (ESTALE);
640
641 /*
642 * Extract and set starting directory.
643 */
644 error = nfsrv_fhtovp(fhp, 0, &dp, nfsd, slp, nam, &rdonly);
645 if (error)
646 goto out;
647 if (dp->v_type != VDIR) {
648 vput(dp);
649 error = ENOTDIR;
650 goto out;
651 }
652
653 if (rdonly)
654 cnp->cn_flags |= RDONLY;
655
656 /*
657 * Set return directory. Reference to dp is implicitly transfered
658 * to the returned pointer
659 */
660 *retdirp = dp;
661 if (v3) {
662 *retdirattr_retp = VOP_GETATTR(dp, retdirattrp,
663 ndp->ni_cnd.cn_cred);
664 }
665
666 VOP_UNLOCK(dp, 0);
667
668 if (pubflag) {
669 /*
670 * Oh joy. For WebNFS, handle those pesky '%' escapes,
671 * and the 'native path' indicator.
672 */
673 cp = uma_zalloc(namei_zone, M_WAITOK);
674 fromcp = cnp->cn_pnbuf;
675 tocp = cp;
676 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
677 switch ((unsigned char)*fromcp) {
678 case WEBNFS_NATIVE_CHAR:
679 /*
680 * 'Native' path for us is the same
681 * as a path according to the NFS spec,
682 * just skip the escape char.
683 */
684 fromcp++;
685 break;
686 /*
687 * More may be added in the future, range 0x80-0xff
688 */
689 default:
690 error = EIO;
691 uma_zfree(namei_zone, cp);
692 goto out;
693 }
694 }
695 /*
696 * Translate the '%' escapes, URL-style.
697 */
698 while (*fromcp != '\0') {
699 if (*fromcp == WEBNFS_ESC_CHAR) {
700 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
701 fromcp++;
702 *tocp++ = HEXSTRTOI(fromcp);
703 fromcp += 2;
704 continue;
705 } else {
706 error = ENOENT;
707 uma_zfree(namei_zone, cp);
708 goto out;
709 }
710 } else
711 *tocp++ = *fromcp++;
712 }
713 *tocp = '\0';
714 uma_zfree(namei_zone, cnp->cn_pnbuf);
715 cnp->cn_pnbuf = cp;
716 }
717
718 ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
719 ndp->ni_segflg = UIO_SYSSPACE;
720
721 if (pubflag) {
722 ndp->ni_rootdir = rootvnode;
723 ndp->ni_loopcnt = 0;
724
725 if (cnp->cn_pnbuf[0] == '/')
726 dp = rootvnode;
727 } else {
728 cnp->cn_flags |= NOCROSSMOUNT;
729 }
730
731 /*
732 * Initialize for scan, set ni_startdir and bump ref on dp again
733 * because lookup() will dereference ni_startdir.
734 */
735
736 cnp->cn_thread = curthread;
737 VREF(dp);
738 ndp->ni_startdir = dp;
739
740 if (!lockleaf)
741 cnp->cn_flags |= LOCKLEAF;
742 for (;;) {
743 cnp->cn_nameptr = cnp->cn_pnbuf;
744 /*
745 * Call lookup() to do the real work. If an error occurs,
746 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
747 * we do not have to dereference anything before returning.
748 * In either case ni_startdir will be dereferenced and NULLed
749 * out.
750 */
751 error = lookup(ndp);
752 if (error)
753 break;
754
755 /*
756 * Check for encountering a symbolic link. Trivial
757 * termination occurs if no symlink encountered.
758 * Note: zfree is safe because error is 0, so we will
759 * not zfree it again when we break.
760 */
761 if ((cnp->cn_flags & ISSYMLINK) == 0) {
762 if (cnp->cn_flags & (SAVENAME | SAVESTART))
763 cnp->cn_flags |= HASBUF;
764 else
765 uma_zfree(namei_zone, cnp->cn_pnbuf);
766 if (ndp->ni_vp && !lockleaf)
767 VOP_UNLOCK(ndp->ni_vp, 0);
768 break;
769 }
770
771 /*
772 * Validate symlink
773 */
774 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
775 VOP_UNLOCK(ndp->ni_dvp, 0);
776 if (!pubflag) {
777 error = EINVAL;
778 goto badlink2;
779 }
780
781 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
782 error = ELOOP;
783 goto badlink2;
784 }
785 if (ndp->ni_pathlen > 1)
786 cp = uma_zalloc(namei_zone, M_WAITOK);
787 else
788 cp = cnp->cn_pnbuf;
789 aiov.iov_base = cp;
790 aiov.iov_len = MAXPATHLEN;
791 auio.uio_iov = &aiov;
792 auio.uio_iovcnt = 1;
793 auio.uio_offset = 0;
794 auio.uio_rw = UIO_READ;
795 auio.uio_segflg = UIO_SYSSPACE;
796 auio.uio_td = NULL;
797 auio.uio_resid = MAXPATHLEN;
798 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
799 if (error) {
800 badlink1:
801 if (ndp->ni_pathlen > 1)
802 uma_zfree(namei_zone, cp);
803 badlink2:
804 vput(ndp->ni_vp);
805 vrele(ndp->ni_dvp);
806 break;
807 }
808 linklen = MAXPATHLEN - auio.uio_resid;
809 if (linklen == 0) {
810 error = ENOENT;
811 goto badlink1;
812 }
813 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
814 error = ENAMETOOLONG;
815 goto badlink1;
816 }
817
818 /*
819 * Adjust or replace path
820 */
821 if (ndp->ni_pathlen > 1) {
822 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
823 uma_zfree(namei_zone, cnp->cn_pnbuf);
824 cnp->cn_pnbuf = cp;
825 } else
826 cnp->cn_pnbuf[linklen] = '\0';
827 ndp->ni_pathlen += linklen;
828
829 /*
830 * Cleanup refs for next loop and check if root directory
831 * should replace current directory. Normally ni_dvp
832 * becomes the new base directory and is cleaned up when
833 * we loop. Explicitly null pointers after invalidation
834 * to clarify operation.
835 */
836 vput(ndp->ni_vp);
837 ndp->ni_vp = NULL;
838
839 if (cnp->cn_pnbuf[0] == '/') {
840 vrele(ndp->ni_dvp);
841 ndp->ni_dvp = ndp->ni_rootdir;
842 VREF(ndp->ni_dvp);
843 }
844 ndp->ni_startdir = ndp->ni_dvp;
845 ndp->ni_dvp = NULL;
846 }
847 if (!lockleaf)
848 cnp->cn_flags &= ~LOCKLEAF;
849
850 /*
851 * nfs_namei() guarentees that fields will not contain garbage
852 * whether an error occurs or not. This allows the caller to track
853 * cleanup state trivially.
854 */
855 out:
856 if (error) {
857 uma_zfree(namei_zone, cnp->cn_pnbuf);
858 ndp->ni_vp = NULL;
859 ndp->ni_dvp = NULL;
860 ndp->ni_startdir = NULL;
861 cnp->cn_flags &= ~HASBUF;
862 } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
863 ndp->ni_dvp = NULL;
864 }
865 return (error);
866 }
867
868 /*
869 * A fiddled version of m_adj() that ensures null fill to a long
870 * boundary and only trims off the back end
871 */
872 void
873 nfsm_adj(struct mbuf *mp, int len, int nul)
874 {
875 struct mbuf *m;
876 int count, i;
877 char *cp;
878
879 /*
880 * Trim from tail. Scan the mbuf chain,
881 * calculating its length and finding the last mbuf.
882 * If the adjustment only affects this mbuf, then just
883 * adjust and return. Otherwise, rescan and truncate
884 * after the remaining size.
885 */
886 count = 0;
887 m = mp;
888 for (;;) {
889 count += m->m_len;
890 if (m->m_next == NULL)
891 break;
892 m = m->m_next;
893 }
894 if (m->m_len > len) {
895 m->m_len -= len;
896 if (nul > 0) {
897 cp = mtod(m, caddr_t)+m->m_len-nul;
898 for (i = 0; i < nul; i++)
899 *cp++ = '\0';
900 }
901 return;
902 }
903 count -= len;
904 if (count < 0)
905 count = 0;
906 /*
907 * Correct length for chain is "count".
908 * Find the mbuf with last data, adjust its length,
909 * and toss data from remaining mbufs on chain.
910 */
911 for (m = mp; m; m = m->m_next) {
912 if (m->m_len >= count) {
913 m->m_len = count;
914 if (nul > 0) {
915 cp = mtod(m, caddr_t)+m->m_len-nul;
916 for (i = 0; i < nul; i++)
917 *cp++ = '\0';
918 }
919 if (m->m_next != NULL) {
920 m_freem(m->m_next);
921 m->m_next = NULL;
922 }
923 break;
924 }
925 count -= m->m_len;
926 }
927 }
928
929 /*
930 * Make these functions instead of macros, so that the kernel text size
931 * doesn't get too big...
932 */
933 void
934 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
935 struct vattr *before_vap, int after_ret, struct vattr *after_vap,
936 struct mbuf **mbp, char **bposp)
937 {
938 struct mbuf *mb = *mbp;
939 char *bpos = *bposp;
940 u_int32_t *tl;
941
942 if (before_ret) {
943 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
944 *tl = nfsrv_nfs_false;
945 } else {
946 tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
947 *tl++ = nfsrv_nfs_true;
948 txdr_hyper(before_vap->va_size, tl);
949 tl += 2;
950 txdr_nfsv3time(&(before_vap->va_mtime), tl);
951 tl += 2;
952 txdr_nfsv3time(&(before_vap->va_ctime), tl);
953 }
954 *bposp = bpos;
955 *mbp = mb;
956 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
957 }
958
959 void
960 nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
961 struct vattr *after_vap, struct mbuf **mbp, char **bposp)
962 {
963 struct mbuf *mb = *mbp;
964 char *bpos = *bposp;
965 u_int32_t *tl;
966 struct nfs_fattr *fp;
967
968 if (after_ret) {
969 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
970 *tl = nfsrv_nfs_false;
971 } else {
972 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
973 *tl++ = nfsrv_nfs_true;
974 fp = (struct nfs_fattr *)tl;
975 nfsm_srvfattr(nfsd, after_vap, fp);
976 }
977 *mbp = mb;
978 *bposp = bpos;
979 }
980
981 void
982 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
983 struct nfs_fattr *fp)
984 {
985
986 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
987 fp->fa_uid = txdr_unsigned(vap->va_uid);
988 fp->fa_gid = txdr_unsigned(vap->va_gid);
989 if (nfsd->nd_flag & ND_NFSV3) {
990 fp->fa_type = vtonfsv3_type(vap->va_type);
991 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
992 txdr_hyper(vap->va_size, &fp->fa3_size);
993 txdr_hyper(vap->va_bytes, &fp->fa3_used);
994 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
995 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
996 fp->fa3_fsid.nfsuquad[0] = 0;
997 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
998 fp->fa3_fileid.nfsuquad[0] = 0;
999 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1000 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1001 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1002 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1003 } else {
1004 fp->fa_type = vtonfsv2_type(vap->va_type);
1005 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1006 fp->fa2_size = txdr_unsigned(vap->va_size);
1007 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1008 if (vap->va_type == VFIFO)
1009 fp->fa2_rdev = 0xffffffff;
1010 else
1011 fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1012 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1013 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1014 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1015 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1016 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1017 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1018 }
1019 }
1020
1021 /*
1022 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1023 * - look up fsid in mount list (if not found ret error)
1024 * - get vp and export rights by calling VFS_FHTOVP()
1025 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1026 */
1027 int
1028 nfsrv_fhtovp(fhandle_t *fhp, int flags, struct vnode **vpp,
1029 struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1030 struct sockaddr *nam, int *rdonlyp)
1031 {
1032 struct mount *mp;
1033 int i;
1034 struct ucred *cred, *credanon;
1035 int error, exflags;
1036 #ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */
1037 struct sockaddr_int *saddr;
1038 #endif
1039 int credflavor;
1040 int numsecflavors, *secflavors;
1041 int authsys;
1042 int v3 = nfsd->nd_flag & ND_NFSV3;
1043 int mountreq;
1044
1045 *vpp = NULL;
1046
1047 if (nfs_ispublicfh(fhp)) {
1048 if (!nfs_pub.np_valid)
1049 return (ESTALE);
1050 fhp = &nfs_pub.np_handle;
1051 }
1052
1053 mp = vfs_busyfs(&fhp->fh_fsid);
1054 if (!mp)
1055 return (ESTALE);
1056 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon,
1057 &numsecflavors, &secflavors);
1058 if (error) {
1059 vfs_unbusy(mp);
1060 goto out;
1061 }
1062 if (numsecflavors == 0) {
1063 /*
1064 * This can happen if the system is running with an
1065 * old mountd that doesn't pass in a secflavor list.
1066 */
1067 numsecflavors = 1;
1068 authsys = AUTH_SYS;
1069 secflavors = &authsys;
1070 }
1071 credflavor = nfsd->nd_credflavor;
1072 for (i = 0; i < numsecflavors; i++) {
1073 if (secflavors[i] == credflavor)
1074 break;
1075 }
1076 if (i == numsecflavors) {
1077 /*
1078 * RFC 2623 section 2.3.2 - allow certain procedures
1079 * used at NFS client mount time even if they have
1080 * weak authentication.
1081 */
1082 mountreq = FALSE;
1083 if (v3) {
1084 if (nfsd->nd_procnum == NFSPROC_FSINFO
1085 || nfsd->nd_procnum == NFSPROC_GETATTR)
1086 mountreq = TRUE;
1087 } else {
1088 if (nfsd->nd_procnum == NFSPROC_FSSTAT
1089 || nfsd->nd_procnum == NFSPROC_GETATTR)
1090 mountreq = TRUE;
1091 }
1092 if (!mountreq) {
1093 error = NFSERR_AUTHERR | AUTH_TOOWEAK;
1094 vfs_unbusy(mp);
1095 goto out;
1096 }
1097 }
1098 error = VFS_FHTOVP(mp, &fhp->fh_fid, LK_EXCLUSIVE, vpp);
1099 if (error) {
1100 /* Make sure the server replies ESTALE to the client. */
1101 error = ESTALE;
1102 vfs_unbusy(mp);
1103 goto out;
1104 }
1105 #ifdef MNT_EXNORESPORT
1106 if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1107 saddr = (struct sockaddr_in *)nam;
1108 if ((saddr->sin_family == AF_INET ||
1109 saddr->sin_family == AF_INET6) &&
1110 /* same code for INET and INET6: sin*_port at same offet */
1111 ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1112 vput(*vpp);
1113 *vpp = NULL;
1114 error = NFSERR_AUTHERR | AUTH_TOOWEAK;
1115 vfs_unbusy(mp);
1116 goto out;
1117 }
1118 }
1119 #endif
1120 /*
1121 * Check/setup credentials.
1122 */
1123 cred = nfsd->nd_cr;
1124 if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1125 cred->cr_uid = credanon->cr_uid;
1126 crsetgroups(cred, credanon->cr_ngroups, credanon->cr_groups);
1127 }
1128 if (exflags & MNT_EXRDONLY)
1129 *rdonlyp = 1;
1130 else
1131 *rdonlyp = 0;
1132
1133 if (!(flags & NFSRV_FLAG_BUSY))
1134 vfs_unbusy(mp);
1135 out:
1136 if (credanon != NULL)
1137 crfree(credanon);
1138
1139 return (error);
1140 }
1141
1142
1143 /*
1144 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1145 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1146 * transformed this to all zeroes in both cases, so check for it.
1147 */
1148 int
1149 nfs_ispublicfh(fhandle_t *fhp)
1150 {
1151 char *cp = (char *)fhp;
1152 int i;
1153
1154 NFSD_LOCK_DONTCARE();
1155
1156 for (i = 0; i < NFSX_V3FH; i++)
1157 if (*cp++ != 0)
1158 return (FALSE);
1159 return (TRUE);
1160 }
1161
1162 /*
1163 * Map errnos to NFS error numbers. For Version 3 also filter out error
1164 * numbers not specified for the associated procedure.
1165 */
1166 int
1167 nfsrv_errmap(struct nfsrv_descript *nd, int err)
1168 {
1169 const short *defaulterrp, *errp;
1170 int e;
1171
1172
1173 if (nd->nd_flag & ND_NFSV3) {
1174 if (nd->nd_procnum <= NFSPROC_COMMIT) {
1175 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1176 while (*++errp) {
1177 if (*errp == err)
1178 return (err);
1179 else if (*errp > err)
1180 break;
1181 }
1182 return ((int)*defaulterrp);
1183 } else
1184 return (err & 0xffff);
1185 }
1186 e = 0;
1187 if (err <= ELAST)
1188 e = nfsrv_v2errmap[err - 1];
1189 if (e != 0)
1190 return (e);
1191 return (NFSERR_IO);
1192 }
1193
1194 /*
1195 * Sort the group list in increasing numerical order.
1196 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1197 * that used to be here.)
1198 */
1199 void
1200 nfsrvw_sort(gid_t *list, int num)
1201 {
1202 int i, j;
1203 gid_t v;
1204
1205 /* Insertion sort. */
1206 for (i = 1; i < num; i++) {
1207 v = list[i];
1208 /* find correct slot for value v, moving others up */
1209 for (j = i; --j >= 0 && v < list[j];)
1210 list[j + 1] = list[j];
1211 list[j + 1] = v;
1212 }
1213 }
1214
1215 /*
1216 * Helper functions for macros.
1217 */
1218
1219 void
1220 nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
1221 {
1222 u_int32_t *tl;
1223
1224 if (v3) {
1225 tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1226 *tl++ = txdr_unsigned(NFSX_V3FH);
1227 bcopy(f, tl, NFSX_V3FH);
1228 } else {
1229 tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1230 bcopy(f, tl, NFSX_V2FH);
1231 }
1232 }
1233
1234 void
1235 nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
1236 {
1237 u_int32_t *tl;
1238
1239 tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1240 *tl++ = nfsrv_nfs_true;
1241 *tl++ = txdr_unsigned(NFSX_V3FH);
1242 bcopy(f, tl, NFSX_V3FH);
1243 }
1244
1245 int
1246 nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1247 {
1248 u_int32_t *tl;
1249
1250 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1251 if (tl == NULL)
1252 return EBADRPC;
1253 *s = fxdr_unsigned(int32_t, *tl);
1254 if (*s > m || *s <= 0)
1255 return EBADRPC;
1256 return 0;
1257 }
1258
1259 int
1260 nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1261 {
1262 u_int32_t *tl;
1263
1264 NFSD_LOCK_DONTCARE();
1265
1266 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1267 if (tl == NULL)
1268 return EBADRPC;
1269 *s = fxdr_unsigned(int32_t, *tl);
1270 if (*s > m)
1271 return NFSERR_NAMETOL;
1272 if (*s <= 0)
1273 return EBADRPC;
1274 return 0;
1275 }
1276
1277 int
1278 nfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1279 {
1280 u_int32_t *tl;
1281
1282 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1283 if (tl == NULL)
1284 return EBADRPC;
1285 *s = fxdr_unsigned(int32_t, *tl);
1286 if (*s > m)
1287 return NFSERR_NAMETOL;
1288 if (*s < 0)
1289 return EBADRPC;
1290 return 0;
1291 }
1292
1293 void
1294 nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
1295 char **bp, char **be, caddr_t bpos)
1296 {
1297 struct mbuf *nmp;
1298
1299 NFSD_UNLOCK_ASSERT();
1300
1301 if (*bp >= *be) {
1302 if (*mp == mb)
1303 (*mp)->m_len += *bp - bpos;
1304 MGET(nmp, M_WAITOK, MT_DATA);
1305 MCLGET(nmp, M_WAITOK);
1306 nmp->m_len = NFSMSIZ(nmp);
1307 (*mp)->m_next = nmp;
1308 *mp = nmp;
1309 *bp = mtod(*mp, caddr_t);
1310 *be = *bp + (*mp)->m_len;
1311 }
1312 *tl = (u_int32_t *)*bp;
1313 }
1314
1315 int
1316 nfsm_srvmtofh_xx(fhandle_t *f, int v3, struct mbuf **md, caddr_t *dpos)
1317 {
1318 u_int32_t *tl;
1319 int fhlen;
1320
1321 if (v3) {
1322 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1323 if (tl == NULL)
1324 return EBADRPC;
1325 fhlen = fxdr_unsigned(int, *tl);
1326 if (fhlen != 0 && fhlen != NFSX_V3FH)
1327 return EBADRPC;
1328 } else {
1329 fhlen = NFSX_V2FH;
1330 }
1331 if (fhlen != 0) {
1332 tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos);
1333 if (tl == NULL)
1334 return EBADRPC;
1335 bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
1336 } else {
1337 bzero((caddr_t)(f), NFSX_V3FH);
1338 }
1339 return 0;
1340 }
1341
1342 int
1343 nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
1344 {
1345 u_int32_t *tl;
1346 int toclient = 0;
1347
1348 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1349 if (tl == NULL)
1350 return EBADRPC;
1351 if (*tl == nfsrv_nfs_true) {
1352 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1353 if (tl == NULL)
1354 return EBADRPC;
1355 (a)->va_mode = nfstov_mode(*tl);
1356 }
1357 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1358 if (tl == NULL)
1359 return EBADRPC;
1360 if (*tl == nfsrv_nfs_true) {
1361 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1362 if (tl == NULL)
1363 return EBADRPC;
1364 (a)->va_uid = fxdr_unsigned(uid_t, *tl);
1365 }
1366 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1367 if (tl == NULL)
1368 return EBADRPC;
1369 if (*tl == nfsrv_nfs_true) {
1370 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1371 if (tl == NULL)
1372 return EBADRPC;
1373 (a)->va_gid = fxdr_unsigned(gid_t, *tl);
1374 }
1375 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1376 if (tl == NULL)
1377 return EBADRPC;
1378 if (*tl == nfsrv_nfs_true) {
1379 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1380 if (tl == NULL)
1381 return EBADRPC;
1382 (a)->va_size = fxdr_hyper(tl);
1383 }
1384 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1385 if (tl == NULL)
1386 return EBADRPC;
1387 switch (fxdr_unsigned(int, *tl)) {
1388 case NFSV3SATTRTIME_TOCLIENT:
1389 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1390 if (tl == NULL)
1391 return EBADRPC;
1392 fxdr_nfsv3time(tl, &(a)->va_atime);
1393 toclient = 1;
1394 break;
1395 case NFSV3SATTRTIME_TOSERVER:
1396 vfs_timestamp(&a->va_atime);
1397 a->va_vaflags |= VA_UTIMES_NULL;
1398 break;
1399 }
1400 tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos);
1401 if (tl == NULL)
1402 return EBADRPC;
1403 switch (fxdr_unsigned(int, *tl)) {
1404 case NFSV3SATTRTIME_TOCLIENT:
1405 tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos);
1406 if (tl == NULL)
1407 return EBADRPC;
1408 fxdr_nfsv3time(tl, &(a)->va_mtime);
1409 a->va_vaflags &= ~VA_UTIMES_NULL;
1410 break;
1411 case NFSV3SATTRTIME_TOSERVER:
1412 vfs_timestamp(&a->va_mtime);
1413 if (toclient == 0)
1414 a->va_vaflags |= VA_UTIMES_NULL;
1415 break;
1416 }
1417 return 0;
1418 }
Cache object: 3e044eca8f93f441918f55554bb6f60e
|