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