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