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: src/sys/nfsserver/nfs_srvsubs.c,v 1.161 2008/11/12 09:36:35 dfr Exp $");
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 <nfs/rpcv2.h>
71 #include <nfs/nfsproto.h>
72 #include <nfsserver/nfs.h>
73 #include <nfs/xdr_subs.h>
74 #include <nfsserver/nfsm_subs.h>
75
76 #include <netinet/in.h>
77
78 /*
79 * Data items converted to xdr at startup, since they are constant
80 * This is kinda hokey, but may save a little time doing byte swaps
81 */
82 u_int32_t nfsrv_nfs_xdrneg1;
83 u_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply,
84 nfsrv_rpc_msgdenied, nfsrv_rpc_autherr,
85 nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted;
86 u_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false;
87
88 /* And other global data */
89 static const nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR,
90 NFLNK, NFNON, NFCHR, NFNON };
91 #define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((int32_t)(a))])
92 #define vtonfsv3_mode(m) txdr_unsigned((m) & ALLPERMS)
93
94 int nfsrv_ticks;
95
96 #ifdef NFS_LEGACYRPC
97 struct nfssvc_sockhead nfssvc_sockhead;
98 int nfssvc_sockhead_flag;
99 struct nfsd_head nfsd_head;
100 int nfsd_head_flag;
101 #endif
102
103 static int nfssvc_offset = SYS_nfssvc;
104 static struct sysent nfssvc_prev_sysent;
105 MAKE_SYSENT(nfssvc);
106
107 struct mtx nfsd_mtx;
108
109 /*
110 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
111 */
112 const int nfsrv_nfsv3_procid[NFS_NPROCS] = {
113 NFSPROC_NULL,
114 NFSPROC_GETATTR,
115 NFSPROC_SETATTR,
116 NFSPROC_NOOP,
117 NFSPROC_LOOKUP,
118 NFSPROC_READLINK,
119 NFSPROC_READ,
120 NFSPROC_NOOP,
121 NFSPROC_WRITE,
122 NFSPROC_CREATE,
123 NFSPROC_REMOVE,
124 NFSPROC_RENAME,
125 NFSPROC_LINK,
126 NFSPROC_SYMLINK,
127 NFSPROC_MKDIR,
128 NFSPROC_RMDIR,
129 NFSPROC_READDIR,
130 NFSPROC_FSSTAT,
131 NFSPROC_NOOP,
132 NFSPROC_NOOP,
133 NFSPROC_NOOP,
134 NFSPROC_NOOP,
135 NFSPROC_NOOP,
136 };
137
138 /*
139 * and the reverse mapping from generic to Version 2 procedure numbers
140 */
141 const int nfsrvv2_procid[NFS_NPROCS] = {
142 NFSV2PROC_NULL,
143 NFSV2PROC_GETATTR,
144 NFSV2PROC_SETATTR,
145 NFSV2PROC_LOOKUP,
146 NFSV2PROC_NOOP,
147 NFSV2PROC_READLINK,
148 NFSV2PROC_READ,
149 NFSV2PROC_WRITE,
150 NFSV2PROC_CREATE,
151 NFSV2PROC_MKDIR,
152 NFSV2PROC_SYMLINK,
153 NFSV2PROC_CREATE,
154 NFSV2PROC_REMOVE,
155 NFSV2PROC_RMDIR,
156 NFSV2PROC_RENAME,
157 NFSV2PROC_LINK,
158 NFSV2PROC_READDIR,
159 NFSV2PROC_NOOP,
160 NFSV2PROC_STATFS,
161 NFSV2PROC_NOOP,
162 NFSV2PROC_NOOP,
163 NFSV2PROC_NOOP,
164 NFSV2PROC_NOOP,
165 };
166
167 /*
168 * Maps errno values to nfs error numbers.
169 * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not
170 * specifically defined in RFC 1094.
171 */
172 static const u_char nfsrv_v2errmap[ELAST] = {
173 NFSERR_PERM, NFSERR_NOENT, 0, 0, 0,
174 NFSERR_NXIO, 0, 0, 0, 0,
175 0, 0, NFSERR_ACCES, 0, 0,
176 0, NFSERR_EXIST, 0, NFSERR_NODEV, NFSERR_NOTDIR,
177 NFSERR_ISDIR, 0, 0, 0, 0,
178 0, NFSERR_FBIG, NFSERR_NOSPC, 0, NFSERR_ROFS,
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, 0, 0, 0,
185 0, 0, NFSERR_NAMETOL, 0, 0,
186 NFSERR_NOTEMPTY, 0, 0, NFSERR_DQUOT, NFSERR_STALE,
187 0
188 };
189
190 /*
191 * Maps errno values to nfs error numbers.
192 * Although it is not obvious whether or not NFS clients really care if
193 * a returned error value is in the specified list for the procedure, the
194 * safest thing to do is filter them appropriately. For Version 2, the
195 * X/Open XNFS document is the only specification that defines error values
196 * for each RPC (The RFC simply lists all possible error values for all RPCs),
197 * so I have decided to not do this for Version 2.
198 * The first entry is the default error return and the rest are the valid
199 * errors for that RPC in increasing numeric order.
200 */
201 static const short nfsv3err_null[] = {
202 0,
203 0,
204 };
205
206 static const short nfsv3err_getattr[] = {
207 NFSERR_IO,
208 NFSERR_IO,
209 NFSERR_STALE,
210 NFSERR_BADHANDLE,
211 NFSERR_SERVERFAULT,
212 0,
213 };
214
215 static const short nfsv3err_setattr[] = {
216 NFSERR_IO,
217 NFSERR_PERM,
218 NFSERR_IO,
219 NFSERR_ACCES,
220 NFSERR_INVAL,
221 NFSERR_NOSPC,
222 NFSERR_ROFS,
223 NFSERR_DQUOT,
224 NFSERR_STALE,
225 NFSERR_BADHANDLE,
226 NFSERR_NOT_SYNC,
227 NFSERR_SERVERFAULT,
228 0,
229 };
230
231 static const short nfsv3err_lookup[] = {
232 NFSERR_IO,
233 NFSERR_NOENT,
234 NFSERR_IO,
235 NFSERR_ACCES,
236 NFSERR_NOTDIR,
237 NFSERR_NAMETOL,
238 NFSERR_STALE,
239 NFSERR_BADHANDLE,
240 NFSERR_SERVERFAULT,
241 0,
242 };
243
244 static const short nfsv3err_access[] = {
245 NFSERR_IO,
246 NFSERR_IO,
247 NFSERR_STALE,
248 NFSERR_BADHANDLE,
249 NFSERR_SERVERFAULT,
250 0,
251 };
252
253 static const short nfsv3err_readlink[] = {
254 NFSERR_IO,
255 NFSERR_IO,
256 NFSERR_ACCES,
257 NFSERR_INVAL,
258 NFSERR_STALE,
259 NFSERR_BADHANDLE,
260 NFSERR_NOTSUPP,
261 NFSERR_SERVERFAULT,
262 0,
263 };
264
265 static const short nfsv3err_read[] = {
266 NFSERR_IO,
267 NFSERR_IO,
268 NFSERR_NXIO,
269 NFSERR_ACCES,
270 NFSERR_INVAL,
271 NFSERR_STALE,
272 NFSERR_BADHANDLE,
273 NFSERR_SERVERFAULT,
274 0,
275 };
276
277 static const short nfsv3err_write[] = {
278 NFSERR_IO,
279 NFSERR_IO,
280 NFSERR_ACCES,
281 NFSERR_INVAL,
282 NFSERR_FBIG,
283 NFSERR_NOSPC,
284 NFSERR_ROFS,
285 NFSERR_DQUOT,
286 NFSERR_STALE,
287 NFSERR_BADHANDLE,
288 NFSERR_SERVERFAULT,
289 0,
290 };
291
292 static const short nfsv3err_create[] = {
293 NFSERR_IO,
294 NFSERR_IO,
295 NFSERR_ACCES,
296 NFSERR_EXIST,
297 NFSERR_NOTDIR,
298 NFSERR_NOSPC,
299 NFSERR_ROFS,
300 NFSERR_NAMETOL,
301 NFSERR_DQUOT,
302 NFSERR_STALE,
303 NFSERR_BADHANDLE,
304 NFSERR_NOTSUPP,
305 NFSERR_SERVERFAULT,
306 0,
307 };
308
309 static const short nfsv3err_mkdir[] = {
310 NFSERR_IO,
311 NFSERR_IO,
312 NFSERR_ACCES,
313 NFSERR_EXIST,
314 NFSERR_NOTDIR,
315 NFSERR_NOSPC,
316 NFSERR_ROFS,
317 NFSERR_NAMETOL,
318 NFSERR_DQUOT,
319 NFSERR_STALE,
320 NFSERR_BADHANDLE,
321 NFSERR_NOTSUPP,
322 NFSERR_SERVERFAULT,
323 0,
324 };
325
326 static const short nfsv3err_symlink[] = {
327 NFSERR_IO,
328 NFSERR_IO,
329 NFSERR_ACCES,
330 NFSERR_EXIST,
331 NFSERR_NOTDIR,
332 NFSERR_NOSPC,
333 NFSERR_ROFS,
334 NFSERR_NAMETOL,
335 NFSERR_DQUOT,
336 NFSERR_STALE,
337 NFSERR_BADHANDLE,
338 NFSERR_NOTSUPP,
339 NFSERR_SERVERFAULT,
340 0,
341 };
342
343 static const short nfsv3err_mknod[] = {
344 NFSERR_IO,
345 NFSERR_IO,
346 NFSERR_ACCES,
347 NFSERR_EXIST,
348 NFSERR_NOTDIR,
349 NFSERR_NOSPC,
350 NFSERR_ROFS,
351 NFSERR_NAMETOL,
352 NFSERR_DQUOT,
353 NFSERR_STALE,
354 NFSERR_BADHANDLE,
355 NFSERR_NOTSUPP,
356 NFSERR_SERVERFAULT,
357 NFSERR_BADTYPE,
358 0,
359 };
360
361 static const short nfsv3err_remove[] = {
362 NFSERR_IO,
363 NFSERR_NOENT,
364 NFSERR_IO,
365 NFSERR_ACCES,
366 NFSERR_NOTDIR,
367 NFSERR_ROFS,
368 NFSERR_NAMETOL,
369 NFSERR_STALE,
370 NFSERR_BADHANDLE,
371 NFSERR_SERVERFAULT,
372 0,
373 };
374
375 static const short nfsv3err_rmdir[] = {
376 NFSERR_IO,
377 NFSERR_NOENT,
378 NFSERR_IO,
379 NFSERR_ACCES,
380 NFSERR_EXIST,
381 NFSERR_NOTDIR,
382 NFSERR_INVAL,
383 NFSERR_ROFS,
384 NFSERR_NAMETOL,
385 NFSERR_NOTEMPTY,
386 NFSERR_STALE,
387 NFSERR_BADHANDLE,
388 NFSERR_NOTSUPP,
389 NFSERR_SERVERFAULT,
390 0,
391 };
392
393 static const short nfsv3err_rename[] = {
394 NFSERR_IO,
395 NFSERR_NOENT,
396 NFSERR_IO,
397 NFSERR_ACCES,
398 NFSERR_EXIST,
399 NFSERR_XDEV,
400 NFSERR_NOTDIR,
401 NFSERR_ISDIR,
402 NFSERR_INVAL,
403 NFSERR_NOSPC,
404 NFSERR_ROFS,
405 NFSERR_MLINK,
406 NFSERR_NAMETOL,
407 NFSERR_NOTEMPTY,
408 NFSERR_DQUOT,
409 NFSERR_STALE,
410 NFSERR_BADHANDLE,
411 NFSERR_NOTSUPP,
412 NFSERR_SERVERFAULT,
413 0,
414 };
415
416 static const short nfsv3err_link[] = {
417 NFSERR_IO,
418 NFSERR_IO,
419 NFSERR_ACCES,
420 NFSERR_EXIST,
421 NFSERR_XDEV,
422 NFSERR_NOTDIR,
423 NFSERR_INVAL,
424 NFSERR_NOSPC,
425 NFSERR_ROFS,
426 NFSERR_MLINK,
427 NFSERR_NAMETOL,
428 NFSERR_DQUOT,
429 NFSERR_STALE,
430 NFSERR_BADHANDLE,
431 NFSERR_NOTSUPP,
432 NFSERR_SERVERFAULT,
433 0,
434 };
435
436 static const short nfsv3err_readdir[] = {
437 NFSERR_IO,
438 NFSERR_IO,
439 NFSERR_ACCES,
440 NFSERR_NOTDIR,
441 NFSERR_STALE,
442 NFSERR_BADHANDLE,
443 NFSERR_BAD_COOKIE,
444 NFSERR_TOOSMALL,
445 NFSERR_SERVERFAULT,
446 0,
447 };
448
449 static const short nfsv3err_readdirplus[] = {
450 NFSERR_IO,
451 NFSERR_IO,
452 NFSERR_ACCES,
453 NFSERR_NOTDIR,
454 NFSERR_STALE,
455 NFSERR_BADHANDLE,
456 NFSERR_BAD_COOKIE,
457 NFSERR_NOTSUPP,
458 NFSERR_TOOSMALL,
459 NFSERR_SERVERFAULT,
460 0,
461 };
462
463 static const short nfsv3err_fsstat[] = {
464 NFSERR_IO,
465 NFSERR_IO,
466 NFSERR_STALE,
467 NFSERR_BADHANDLE,
468 NFSERR_SERVERFAULT,
469 0,
470 };
471
472 static const short nfsv3err_fsinfo[] = {
473 NFSERR_STALE,
474 NFSERR_STALE,
475 NFSERR_BADHANDLE,
476 NFSERR_SERVERFAULT,
477 0,
478 };
479
480 static const short nfsv3err_pathconf[] = {
481 NFSERR_STALE,
482 NFSERR_STALE,
483 NFSERR_BADHANDLE,
484 NFSERR_SERVERFAULT,
485 0,
486 };
487
488 static const short nfsv3err_commit[] = {
489 NFSERR_IO,
490 NFSERR_IO,
491 NFSERR_STALE,
492 NFSERR_BADHANDLE,
493 NFSERR_SERVERFAULT,
494 0,
495 };
496
497 static const short *nfsrv_v3errmap[] = {
498 nfsv3err_null,
499 nfsv3err_getattr,
500 nfsv3err_setattr,
501 nfsv3err_lookup,
502 nfsv3err_access,
503 nfsv3err_readlink,
504 nfsv3err_read,
505 nfsv3err_write,
506 nfsv3err_create,
507 nfsv3err_mkdir,
508 nfsv3err_symlink,
509 nfsv3err_mknod,
510 nfsv3err_remove,
511 nfsv3err_rmdir,
512 nfsv3err_rename,
513 nfsv3err_link,
514 nfsv3err_readdir,
515 nfsv3err_readdirplus,
516 nfsv3err_fsstat,
517 nfsv3err_fsinfo,
518 nfsv3err_pathconf,
519 nfsv3err_commit,
520 };
521
522 /*
523 * Called once to initialize data structures...
524 */
525 static int
526 nfsrv_modevent(module_t mod, int type, void *data)
527 {
528 static int registered;
529 int error = 0;
530
531 switch (type) {
532 case MOD_LOAD:
533 mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF);
534 nfsrv_rpc_vers = txdr_unsigned(RPC_VER2);
535 nfsrv_rpc_call = txdr_unsigned(RPC_CALL);
536 nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY);
537 nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
538 nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
539 nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
540 nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR);
541 nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
542 nfsrv_nfs_prog = txdr_unsigned(NFS_PROG);
543 nfsrv_nfs_true = txdr_unsigned(TRUE);
544 nfsrv_nfs_false = txdr_unsigned(FALSE);
545 nfsrv_nfs_xdrneg1 = txdr_unsigned(-1);
546 nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
547 if (nfsrv_ticks < 1)
548 nfsrv_ticks = 1;
549
550 #ifdef NFS_LEGACYRPC
551 nfsrv_initcache(); /* Init the server request cache */
552 NFSD_LOCK();
553 nfsrv_init(0); /* Init server data structures */
554 callout_init(&nfsrv_callout, CALLOUT_MPSAFE);
555 NFSD_UNLOCK();
556 nfsrv_timer(0);
557 #else
558 NFSD_LOCK();
559 nfsrv_init(0); /* Init server data structures */
560 NFSD_UNLOCK();
561 #endif
562
563 error = syscall_register(&nfssvc_offset, &nfssvc_sysent,
564 &nfssvc_prev_sysent);
565 if (error)
566 break;
567 registered = 1;
568 break;
569
570 case MOD_UNLOAD:
571 if (nfsrv_numnfsd != 0) {
572 error = EBUSY;
573 break;
574 }
575
576 if (registered)
577 syscall_deregister(&nfssvc_offset, &nfssvc_prev_sysent);
578 callout_drain(&nfsrv_callout);
579 #ifdef NFS_LEGACYRPC
580 nfsrv_destroycache(); /* Free the server request cache */
581 #endif
582 mtx_destroy(&nfsd_mtx);
583 break;
584 default:
585 error = EOPNOTSUPP;
586 break;
587 }
588 return error;
589 }
590 static moduledata_t nfsserver_mod = {
591 "nfsserver",
592 nfsrv_modevent,
593 NULL,
594 };
595 DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
596
597 /* So that loader and kldload(2) can find us, wherever we are.. */
598 MODULE_VERSION(nfsserver, 1);
599 #ifndef NFS_LEGACYRPC
600 MODULE_DEPEND(nfsserver, krpc, 1, 1, 1);
601 #endif
602
603 /*
604 * Set up nameidata for a lookup() call and do it.
605 *
606 * If pubflag is set, this call is done for a lookup operation on the
607 * public filehandle. In that case we allow crossing mountpoints and
608 * absolute pathnames. However, the caller is expected to check that
609 * the lookup result is within the public fs, and deny access if
610 * it is not.
611 *
612 * nfs_namei() clears out garbage fields that namei() might leave garbage.
613 * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
614 * error occurs but the parent was not requested.
615 *
616 * dirp may be set whether an error is returned or not, and must be
617 * released by the caller.
618 */
619 int
620 nfs_namei(struct nameidata *ndp, struct nfsrv_descript *nfsd,
621 fhandle_t *fhp, int len, struct nfssvc_sock *slp,
622 struct sockaddr *nam, struct mbuf **mdp,
623 caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp,
624 int *retdirattr_retp, int pubflag)
625 {
626 int i, rem;
627 struct mbuf *md;
628 char *fromcp, *tocp, *cp;
629 struct iovec aiov;
630 struct uio auio;
631 struct vnode *dp;
632 int error, rdonly, linklen;
633 struct componentname *cnp = &ndp->ni_cnd;
634 int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0;
635 int dvfslocked;
636 int vfslocked;
637
638 vfslocked = 0;
639 dvfslocked = 0;
640 *retdirp = NULL;
641 cnp->cn_flags |= NOMACCHECK;
642 cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
643
644 /*
645 * Copy the name from the mbuf list to ndp->ni_pnbuf
646 * and set the various ndp fields appropriately.
647 */
648 fromcp = *dposp;
649 tocp = cnp->cn_pnbuf;
650 md = *mdp;
651 rem = mtod(md, caddr_t) + md->m_len - fromcp;
652 for (i = 0; i < len; i++) {
653 while (rem == 0) {
654 md = md->m_next;
655 if (md == NULL) {
656 error = EBADRPC;
657 goto out;
658 }
659 fromcp = mtod(md, caddr_t);
660 rem = md->m_len;
661 }
662 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
663 error = EACCES;
664 goto out;
665 }
666 *tocp++ = *fromcp++;
667 rem--;
668 }
669 *tocp = '\0';
670 *mdp = md;
671 *dposp = fromcp;
672 len = nfsm_rndup(len)-len;
673 if (len > 0) {
674 if (rem >= len)
675 *dposp += len;
676 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
677 goto out;
678 }
679
680 /*
681 * Extract and set starting directory.
682 */
683 error = nfsrv_fhtovp(fhp, FALSE, &dp, &dvfslocked,
684 nfsd, slp, nam, &rdonly, pubflag);
685 if (error)
686 goto out;
687 vfslocked = VFS_LOCK_GIANT(dp->v_mount);
688 if (dp->v_type != VDIR) {
689 vrele(dp);
690 error = ENOTDIR;
691 goto out;
692 }
693
694 if (rdonly)
695 cnp->cn_flags |= RDONLY;
696
697 /*
698 * Set return directory. Reference to dp is implicitly transfered
699 * to the returned pointer
700 */
701 *retdirp = dp;
702 if (v3) {
703 vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
704 *retdirattr_retp = VOP_GETATTR(dp, retdirattrp,
705 ndp->ni_cnd.cn_cred);
706 VOP_UNLOCK(dp, 0);
707 }
708
709 if (pubflag) {
710 /*
711 * Oh joy. For WebNFS, handle those pesky '%' escapes,
712 * and the 'native path' indicator.
713 */
714 cp = uma_zalloc(namei_zone, M_WAITOK);
715 fromcp = cnp->cn_pnbuf;
716 tocp = cp;
717 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
718 switch ((unsigned char)*fromcp) {
719 case WEBNFS_NATIVE_CHAR:
720 /*
721 * 'Native' path for us is the same
722 * as a path according to the NFS spec,
723 * just skip the escape char.
724 */
725 fromcp++;
726 break;
727 /*
728 * More may be added in the future, range 0x80-0xff
729 */
730 default:
731 error = EIO;
732 uma_zfree(namei_zone, cp);
733 goto out;
734 }
735 }
736 /*
737 * Translate the '%' escapes, URL-style.
738 */
739 while (*fromcp != '\0') {
740 if (*fromcp == WEBNFS_ESC_CHAR) {
741 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
742 fromcp++;
743 *tocp++ = HEXSTRTOI(fromcp);
744 fromcp += 2;
745 continue;
746 } else {
747 error = ENOENT;
748 uma_zfree(namei_zone, cp);
749 goto out;
750 }
751 } else
752 *tocp++ = *fromcp++;
753 }
754 *tocp = '\0';
755 uma_zfree(namei_zone, cnp->cn_pnbuf);
756 cnp->cn_pnbuf = cp;
757 }
758
759 ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
760 ndp->ni_segflg = UIO_SYSSPACE;
761
762 if (pubflag) {
763 ndp->ni_rootdir = rootvnode;
764 ndp->ni_loopcnt = 0;
765 if (cnp->cn_pnbuf[0] == '/') {
766 int tvfslocked;
767
768 tvfslocked = VFS_LOCK_GIANT(rootvnode->v_mount);
769 VFS_UNLOCK_GIANT(vfslocked);
770 dp = rootvnode;
771 vfslocked = tvfslocked;
772 }
773 } else {
774 cnp->cn_flags |= NOCROSSMOUNT;
775 }
776
777 /*
778 * Initialize for scan, set ni_startdir and bump ref on dp again
779 * because lookup() will dereference ni_startdir.
780 */
781
782 cnp->cn_thread = curthread;
783 VREF(dp);
784 ndp->ni_startdir = dp;
785
786 if (!lockleaf)
787 cnp->cn_flags |= LOCKLEAF;
788 for (;;) {
789 cnp->cn_nameptr = cnp->cn_pnbuf;
790 /*
791 * Call lookup() to do the real work. If an error occurs,
792 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
793 * we do not have to dereference anything before returning.
794 * In either case ni_startdir will be dereferenced and NULLed
795 * out.
796 */
797 if (vfslocked)
798 ndp->ni_cnd.cn_flags |= GIANTHELD;
799 error = lookup(ndp);
800 vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
801 ndp->ni_cnd.cn_flags &= ~GIANTHELD;
802 if (error)
803 break;
804
805 /*
806 * Check for encountering a symbolic link. Trivial
807 * termination occurs if no symlink encountered.
808 * Note: zfree is safe because error is 0, so we will
809 * not zfree it again when we break.
810 */
811 if ((cnp->cn_flags & ISSYMLINK) == 0) {
812 if (cnp->cn_flags & (SAVENAME | SAVESTART))
813 cnp->cn_flags |= HASBUF;
814 else
815 uma_zfree(namei_zone, cnp->cn_pnbuf);
816 if (ndp->ni_vp && !lockleaf)
817 VOP_UNLOCK(ndp->ni_vp, 0);
818 break;
819 }
820
821 /*
822 * Validate symlink
823 */
824 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
825 VOP_UNLOCK(ndp->ni_dvp, 0);
826 if (!pubflag) {
827 error = EINVAL;
828 goto badlink2;
829 }
830
831 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
832 error = ELOOP;
833 goto badlink2;
834 }
835 if (ndp->ni_pathlen > 1)
836 cp = uma_zalloc(namei_zone, M_WAITOK);
837 else
838 cp = cnp->cn_pnbuf;
839 aiov.iov_base = cp;
840 aiov.iov_len = MAXPATHLEN;
841 auio.uio_iov = &aiov;
842 auio.uio_iovcnt = 1;
843 auio.uio_offset = 0;
844 auio.uio_rw = UIO_READ;
845 auio.uio_segflg = UIO_SYSSPACE;
846 auio.uio_td = NULL;
847 auio.uio_resid = MAXPATHLEN;
848 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
849 if (error) {
850 badlink1:
851 if (ndp->ni_pathlen > 1)
852 uma_zfree(namei_zone, cp);
853 badlink2:
854 vput(ndp->ni_vp);
855 vrele(ndp->ni_dvp);
856 break;
857 }
858 linklen = MAXPATHLEN - auio.uio_resid;
859 if (linklen == 0) {
860 error = ENOENT;
861 goto badlink1;
862 }
863 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
864 error = ENAMETOOLONG;
865 goto badlink1;
866 }
867
868 /*
869 * Adjust or replace path
870 */
871 if (ndp->ni_pathlen > 1) {
872 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
873 uma_zfree(namei_zone, cnp->cn_pnbuf);
874 cnp->cn_pnbuf = cp;
875 } else
876 cnp->cn_pnbuf[linklen] = '\0';
877 ndp->ni_pathlen += linklen;
878
879 /*
880 * Cleanup refs for next loop and check if root directory
881 * should replace current directory. Normally ni_dvp
882 * becomes the new base directory and is cleaned up when
883 * we loop. Explicitly null pointers after invalidation
884 * to clarify operation.
885 */
886 vput(ndp->ni_vp);
887 ndp->ni_vp = NULL;
888
889 if (cnp->cn_pnbuf[0] == '/') {
890 vrele(ndp->ni_dvp);
891 ndp->ni_dvp = ndp->ni_rootdir;
892 VREF(ndp->ni_dvp);
893 }
894 ndp->ni_startdir = ndp->ni_dvp;
895 ndp->ni_dvp = NULL;
896 }
897 if (!lockleaf)
898 cnp->cn_flags &= ~LOCKLEAF;
899 if (cnp->cn_flags & GIANTHELD) {
900 mtx_unlock(&Giant);
901 cnp->cn_flags &= ~GIANTHELD;
902 }
903
904 /*
905 * nfs_namei() guarentees that fields will not contain garbage
906 * whether an error occurs or not. This allows the caller to track
907 * cleanup state trivially.
908 */
909 out:
910 if (error) {
911 uma_zfree(namei_zone, cnp->cn_pnbuf);
912 ndp->ni_vp = NULL;
913 ndp->ni_dvp = NULL;
914 ndp->ni_startdir = NULL;
915 cnp->cn_flags &= ~HASBUF;
916 VFS_UNLOCK_GIANT(vfslocked);
917 vfslocked = 0;
918 } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
919 ndp->ni_dvp = NULL;
920 }
921 /*
922 * This differs from normal namei() in that even on failure we may
923 * return with Giant held due to the dirp return. Make sure we only
924 * have not recursed however. The calling code only expects to drop
925 * one acquire.
926 */
927 if (vfslocked || dvfslocked)
928 ndp->ni_cnd.cn_flags |= GIANTHELD;
929 if (vfslocked && dvfslocked)
930 VFS_UNLOCK_GIANT(vfslocked);
931 return (error);
932 }
933
934 /*
935 * A fiddled version of m_adj() that ensures null fill to a long
936 * boundary and only trims off the back end
937 */
938 void
939 nfsm_adj(struct mbuf *mp, int len, int nul)
940 {
941 struct mbuf *m;
942 int count, i;
943 char *cp;
944
945 /*
946 * Trim from tail. Scan the mbuf chain,
947 * calculating its length and finding the last mbuf.
948 * If the adjustment only affects this mbuf, then just
949 * adjust and return. Otherwise, rescan and truncate
950 * after the remaining size.
951 */
952 count = 0;
953 m = mp;
954 for (;;) {
955 count += m->m_len;
956 if (m->m_next == NULL)
957 break;
958 m = m->m_next;
959 }
960 if (m->m_len > len) {
961 m->m_len -= len;
962 if (nul > 0) {
963 cp = mtod(m, caddr_t)+m->m_len-nul;
964 for (i = 0; i < nul; i++)
965 *cp++ = '\0';
966 }
967 return;
968 }
969 count -= len;
970 if (count < 0)
971 count = 0;
972 /*
973 * Correct length for chain is "count".
974 * Find the mbuf with last data, adjust its length,
975 * and toss data from remaining mbufs on chain.
976 */
977 for (m = mp; m; m = m->m_next) {
978 if (m->m_len >= count) {
979 m->m_len = count;
980 if (nul > 0) {
981 cp = mtod(m, caddr_t)+m->m_len-nul;
982 for (i = 0; i < nul; i++)
983 *cp++ = '\0';
984 }
985 if (m->m_next != NULL) {
986 m_freem(m->m_next);
987 m->m_next = NULL;
988 }
989 break;
990 }
991 count -= m->m_len;
992 }
993 }
994
995 /*
996 * Make these functions instead of macros, so that the kernel text size
997 * doesn't get too big...
998 */
999 void
1000 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
1001 struct vattr *before_vap, int after_ret, struct vattr *after_vap,
1002 struct mbuf **mbp, char **bposp)
1003 {
1004 struct mbuf *mb = *mbp;
1005 char *bpos = *bposp;
1006 u_int32_t *tl;
1007
1008 |