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