]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_subs.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_subs.c
1 /*
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23 /*
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * This code is derived from software contributed to Berkeley by
28 * Rick Macklem at The University of Guelph.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 *
58 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
59 * FreeBSD-Id: nfs_subs.c,v 1.47 1997/11/07 08:53:24 phk Exp $
60 */
61
62 /*
63 * These functions support the macros and help fiddle mbuf chains for
64 * the nfs op functions. They do things like create the rpc header and
65 * copy data between mbuf chains and uio lists.
66 */
67 #include <sys/param.h>
68 #include <sys/proc.h>
69 #include <sys/kauth.h>
70 #include <sys/systm.h>
71 #include <sys/kernel.h>
72 #include <sys/mount_internal.h>
73 #include <sys/vnode_internal.h>
74 #include <sys/kpi_mbuf.h>
75 #include <sys/socket.h>
76 #include <sys/stat.h>
77 #include <sys/malloc.h>
78 #include <sys/syscall.h>
79 #include <sys/sysctl.h>
80 #include <sys/ubc_internal.h>
81 #include <sys/fcntl.h>
82 #include <sys/uio_internal.h>
83 #include <sys/domain.h>
84 #include <libkern/OSAtomic.h>
85
86 #include <sys/vm.h>
87 #include <sys/vmparam.h>
88
89 #include <sys/time.h>
90 #include <kern/clock.h>
91
92 #include <nfs/rpcv2.h>
93 #include <nfs/nfsproto.h>
94 #include <nfs/nfs.h>
95 #include <nfs/nfsnode.h>
96 #include <nfs/xdr_subs.h>
97 #include <nfs/nfsm_subs.h>
98 #include <nfs/nfsmount.h>
99 #include <nfs/nfsrtt.h>
100 #include <nfs/nfs_lock.h>
101
102 #include <miscfs/specfs/specdev.h>
103
104 #include <netinet/in.h>
105 #if ISO
106 #include <netiso/iso.h>
107 #endif
108
109 #include <sys/kdebug.h>
110
111 SYSCTL_DECL(_vfs_generic);
112 SYSCTL_NODE(_vfs_generic, OID_AUTO, nfs, CTLFLAG_RW, 0, "nfs hinge");
113
114 #define FSDBG(A, B, C, D, E) \
115 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_NONE, \
116 (int)(B), (int)(C), (int)(D), (int)(E), 0)
117 #define FSDBG_TOP(A, B, C, D, E) \
118 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_START, \
119 (int)(B), (int)(C), (int)(D), (int)(E), 0)
120 #define FSDBG_BOT(A, B, C, D, E) \
121 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_END, \
122 (int)(B), (int)(C), (int)(D), (int)(E), 0)
123 /*
124 * Data items converted to xdr at startup, since they are constant
125 * This is kinda hokey, but may save a little time doing byte swaps
126 */
127 u_long nfs_xdrneg1;
128 u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
129 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
130 rpc_auth_kerb;
131 u_long nfs_prog, nfs_true, nfs_false;
132 __private_extern__ int nfs_mbuf_mlen = 0, nfs_mbuf_mhlen = 0,
133 nfs_mbuf_minclsize = 0, nfs_mbuf_mclbytes = 0;
134
135 /* And other global data */
136 static u_long nfs_xid = 0;
137 u_long nfs_xidwrap = 0; /* to build a (non-wwrapping) 64 bit xid */
138 static enum vtype nv2tov_type[8]= {
139 VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON
140 };
141 enum vtype nv3tov_type[8]= {
142 VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
143 };
144
145 int nfs_mount_type;
146 int nfs_ticks;
147
148 lck_grp_t *nfsd_lck_grp;
149 lck_grp_attr_t *nfsd_lck_grp_attr;
150 lck_attr_t *nfsd_lck_attr;
151 lck_mtx_t *nfsd_mutex;
152
153 lck_grp_attr_t *nfs_slp_group_attr;
154 lck_attr_t *nfs_slp_lock_attr;
155 lck_grp_t *nfs_slp_rwlock_group;
156 lck_grp_t *nfs_slp_mutex_group;
157
158 struct nfs_reqq nfs_reqq;
159 struct nfssvc_sockhead nfssvc_sockhead, nfssvc_deadsockhead;
160 struct nfsd_head nfsd_head;
161 int nfsd_head_flag;
162
163 struct nfsexpfslist nfs_exports;
164 struct nfsexphashhead *nfsexphashtbl;
165 u_long nfsexphash;
166 lck_grp_attr_t *nfs_export_group_attr;
167 lck_attr_t *nfs_export_lock_attr;
168 lck_grp_t *nfs_export_rwlock_group;
169 lck_rw_t nfs_export_rwlock;
170
171 #ifndef NFS_NOSERVER
172 /*
173 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
174 */
175 int nfsv3_procid[NFS_NPROCS] = {
176 NFSPROC_NULL,
177 NFSPROC_GETATTR,
178 NFSPROC_SETATTR,
179 NFSPROC_NOOP,
180 NFSPROC_LOOKUP,
181 NFSPROC_READLINK,
182 NFSPROC_READ,
183 NFSPROC_NOOP,
184 NFSPROC_WRITE,
185 NFSPROC_CREATE,
186 NFSPROC_REMOVE,
187 NFSPROC_RENAME,
188 NFSPROC_LINK,
189 NFSPROC_SYMLINK,
190 NFSPROC_MKDIR,
191 NFSPROC_RMDIR,
192 NFSPROC_READDIR,
193 NFSPROC_FSSTAT,
194 NFSPROC_NOOP,
195 NFSPROC_NOOP,
196 NFSPROC_NOOP,
197 NFSPROC_NOOP,
198 NFSPROC_NOOP
199 };
200
201 #endif /* NFS_NOSERVER */
202 /*
203 * and the reverse mapping from generic to Version 2 procedure numbers
204 */
205 int nfsv2_procid[NFS_NPROCS] = {
206 NFSV2PROC_NULL,
207 NFSV2PROC_GETATTR,
208 NFSV2PROC_SETATTR,
209 NFSV2PROC_LOOKUP,
210 NFSV2PROC_NOOP,
211 NFSV2PROC_READLINK,
212 NFSV2PROC_READ,
213 NFSV2PROC_WRITE,
214 NFSV2PROC_CREATE,
215 NFSV2PROC_MKDIR,
216 NFSV2PROC_SYMLINK,
217 NFSV2PROC_CREATE,
218 NFSV2PROC_REMOVE,
219 NFSV2PROC_RMDIR,
220 NFSV2PROC_RENAME,
221 NFSV2PROC_LINK,
222 NFSV2PROC_READDIR,
223 NFSV2PROC_NOOP,
224 NFSV2PROC_STATFS,
225 NFSV2PROC_NOOP,
226 NFSV2PROC_NOOP,
227 NFSV2PROC_NOOP,
228 NFSV2PROC_NOOP
229 };
230
231 #ifndef NFS_NOSERVER
232 /*
233 * Maps errno values to nfs error numbers.
234 * Use NFSERR_IO as the catch all for ones not specifically defined in
235 * RFC 1094.
236 */
237 static u_char nfsrv_v2errmap[ELAST] = {
238 NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
239 NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
240 NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
241 NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
242 NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
243 NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
244 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
245 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
246 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
247 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
248 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
249 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
250 NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
251 NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
252 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
253 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
254 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
255 };
256
257 /*
258 * Maps errno values to nfs error numbers.
259 * Although it is not obvious whether or not NFS clients really care if
260 * a returned error value is in the specified list for the procedure, the
261 * safest thing to do is filter them appropriately. For Version 2, the
262 * X/Open XNFS document is the only specification that defines error values
263 * for each RPC (The RFC simply lists all possible error values for all RPCs),
264 * so I have decided to not do this for Version 2.
265 * The first entry is the default error return and the rest are the valid
266 * errors for that RPC in increasing numeric order.
267 */
268 static short nfsv3err_null[] = {
269 0,
270 0,
271 };
272
273 static short nfsv3err_getattr[] = {
274 NFSERR_IO,
275 NFSERR_IO,
276 NFSERR_STALE,
277 NFSERR_BADHANDLE,
278 NFSERR_SERVERFAULT,
279 0,
280 };
281
282 static short nfsv3err_setattr[] = {
283 NFSERR_IO,
284 NFSERR_PERM,
285 NFSERR_IO,
286 NFSERR_ACCES,
287 NFSERR_INVAL,
288 NFSERR_NOSPC,
289 NFSERR_ROFS,
290 NFSERR_DQUOT,
291 NFSERR_STALE,
292 NFSERR_BADHANDLE,
293 NFSERR_NOT_SYNC,
294 NFSERR_SERVERFAULT,
295 0,
296 };
297
298 static short nfsv3err_lookup[] = {
299 NFSERR_IO,
300 NFSERR_NOENT,
301 NFSERR_IO,
302 NFSERR_ACCES,
303 NFSERR_NOTDIR,
304 NFSERR_NAMETOL,
305 NFSERR_STALE,
306 NFSERR_BADHANDLE,
307 NFSERR_SERVERFAULT,
308 0,
309 };
310
311 static short nfsv3err_access[] = {
312 NFSERR_IO,
313 NFSERR_IO,
314 NFSERR_STALE,
315 NFSERR_BADHANDLE,
316 NFSERR_SERVERFAULT,
317 0,
318 };
319
320 static short nfsv3err_readlink[] = {
321 NFSERR_IO,
322 NFSERR_IO,
323 NFSERR_ACCES,
324 NFSERR_INVAL,
325 NFSERR_STALE,
326 NFSERR_BADHANDLE,
327 NFSERR_NOTSUPP,
328 NFSERR_SERVERFAULT,
329 0,
330 };
331
332 static short nfsv3err_read[] = {
333 NFSERR_IO,
334 NFSERR_IO,
335 NFSERR_NXIO,
336 NFSERR_ACCES,
337 NFSERR_INVAL,
338 NFSERR_STALE,
339 NFSERR_BADHANDLE,
340 NFSERR_SERVERFAULT,
341 0,
342 };
343
344 static short nfsv3err_write[] = {
345 NFSERR_IO,
346 NFSERR_IO,
347 NFSERR_ACCES,
348 NFSERR_INVAL,
349 NFSERR_FBIG,
350 NFSERR_NOSPC,
351 NFSERR_ROFS,
352 NFSERR_DQUOT,
353 NFSERR_STALE,
354 NFSERR_BADHANDLE,
355 NFSERR_SERVERFAULT,
356 0,
357 };
358
359 static short nfsv3err_create[] = {
360 NFSERR_IO,
361 NFSERR_IO,
362 NFSERR_ACCES,
363 NFSERR_EXIST,
364 NFSERR_NOTDIR,
365 NFSERR_NOSPC,
366 NFSERR_ROFS,
367 NFSERR_NAMETOL,
368 NFSERR_DQUOT,
369 NFSERR_STALE,
370 NFSERR_BADHANDLE,
371 NFSERR_NOTSUPP,
372 NFSERR_SERVERFAULT,
373 0,
374 };
375
376 static short nfsv3err_mkdir[] = {
377 NFSERR_IO,
378 NFSERR_IO,
379 NFSERR_ACCES,
380 NFSERR_EXIST,
381 NFSERR_NOTDIR,
382 NFSERR_NOSPC,
383 NFSERR_ROFS,
384 NFSERR_NAMETOL,
385 NFSERR_DQUOT,
386 NFSERR_STALE,
387 NFSERR_BADHANDLE,
388 NFSERR_NOTSUPP,
389 NFSERR_SERVERFAULT,
390 0,
391 };
392
393 static short nfsv3err_symlink[] = {
394 NFSERR_IO,
395 NFSERR_IO,
396 NFSERR_ACCES,
397 NFSERR_EXIST,
398 NFSERR_NOTDIR,
399 NFSERR_NOSPC,
400 NFSERR_ROFS,
401 NFSERR_NAMETOL,
402 NFSERR_DQUOT,
403 NFSERR_STALE,
404 NFSERR_BADHANDLE,
405 NFSERR_NOTSUPP,
406 NFSERR_SERVERFAULT,
407 0,
408 };
409
410 static short nfsv3err_mknod[] = {
411 NFSERR_IO,
412 NFSERR_IO,
413 NFSERR_ACCES,
414 NFSERR_EXIST,
415 NFSERR_NOTDIR,
416 NFSERR_NOSPC,
417 NFSERR_ROFS,
418 NFSERR_NAMETOL,
419 NFSERR_DQUOT,
420 NFSERR_STALE,
421 NFSERR_BADHANDLE,
422 NFSERR_NOTSUPP,
423 NFSERR_SERVERFAULT,
424 NFSERR_BADTYPE,
425 0,
426 };
427
428 static short nfsv3err_remove[] = {
429 NFSERR_IO,
430 NFSERR_NOENT,
431 NFSERR_IO,
432 NFSERR_ACCES,
433 NFSERR_NOTDIR,
434 NFSERR_ROFS,
435 NFSERR_NAMETOL,
436 NFSERR_STALE,
437 NFSERR_BADHANDLE,
438 NFSERR_SERVERFAULT,
439 0,
440 };
441
442 static short nfsv3err_rmdir[] = {
443 NFSERR_IO,
444 NFSERR_NOENT,
445 NFSERR_IO,
446 NFSERR_ACCES,
447 NFSERR_EXIST,
448 NFSERR_NOTDIR,
449 NFSERR_INVAL,
450 NFSERR_ROFS,
451 NFSERR_NAMETOL,
452 NFSERR_NOTEMPTY,
453 NFSERR_STALE,
454 NFSERR_BADHANDLE,
455 NFSERR_NOTSUPP,
456 NFSERR_SERVERFAULT,
457 0,
458 };
459
460 static short nfsv3err_rename[] = {
461 NFSERR_IO,
462 NFSERR_NOENT,
463 NFSERR_IO,
464 NFSERR_ACCES,
465 NFSERR_EXIST,
466 NFSERR_XDEV,
467 NFSERR_NOTDIR,
468 NFSERR_ISDIR,
469 NFSERR_INVAL,
470 NFSERR_NOSPC,
471 NFSERR_ROFS,
472 NFSERR_MLINK,
473 NFSERR_NAMETOL,
474 NFSERR_NOTEMPTY,
475 NFSERR_DQUOT,
476 NFSERR_STALE,
477 NFSERR_BADHANDLE,
478 NFSERR_NOTSUPP,
479 NFSERR_SERVERFAULT,
480 0,
481 };
482
483 static short nfsv3err_link[] = {
484 NFSERR_IO,
485 NFSERR_IO,
486 NFSERR_ACCES,
487 NFSERR_EXIST,
488 NFSERR_XDEV,
489 NFSERR_NOTDIR,
490 NFSERR_INVAL,
491 NFSERR_NOSPC,
492 NFSERR_ROFS,
493 NFSERR_MLINK,
494 NFSERR_NAMETOL,
495 NFSERR_DQUOT,
496 NFSERR_STALE,
497 NFSERR_BADHANDLE,
498 NFSERR_NOTSUPP,
499 NFSERR_SERVERFAULT,
500 0,
501 };
502
503 static short nfsv3err_readdir[] = {
504 NFSERR_IO,
505 NFSERR_IO,
506 NFSERR_ACCES,
507 NFSERR_NOTDIR,
508 NFSERR_STALE,
509 NFSERR_BADHANDLE,
510 NFSERR_BAD_COOKIE,
511 NFSERR_TOOSMALL,
512 NFSERR_SERVERFAULT,
513 0,
514 };
515
516 static short nfsv3err_readdirplus[] = {
517 NFSERR_IO,
518 NFSERR_IO,
519 NFSERR_ACCES,
520 NFSERR_NOTDIR,
521 NFSERR_STALE,
522 NFSERR_BADHANDLE,
523 NFSERR_BAD_COOKIE,
524 NFSERR_NOTSUPP,
525 NFSERR_TOOSMALL,
526 NFSERR_SERVERFAULT,
527 0,
528 };
529
530 static short nfsv3err_fsstat[] = {
531 NFSERR_IO,
532 NFSERR_IO,
533 NFSERR_STALE,
534 NFSERR_BADHANDLE,
535 NFSERR_SERVERFAULT,
536 0,
537 };
538
539 static short nfsv3err_fsinfo[] = {
540 NFSERR_STALE,
541 NFSERR_STALE,
542 NFSERR_BADHANDLE,
543 NFSERR_SERVERFAULT,
544 0,
545 };
546
547 static short nfsv3err_pathconf[] = {
548 NFSERR_STALE,
549 NFSERR_STALE,
550 NFSERR_BADHANDLE,
551 NFSERR_SERVERFAULT,
552 0,
553 };
554
555 static short nfsv3err_commit[] = {
556 NFSERR_IO,
557 NFSERR_IO,
558 NFSERR_STALE,
559 NFSERR_BADHANDLE,
560 NFSERR_SERVERFAULT,
561 0,
562 };
563
564 static short *nfsrv_v3errmap[] = {
565 nfsv3err_null,
566 nfsv3err_getattr,
567 nfsv3err_setattr,
568 nfsv3err_lookup,
569 nfsv3err_access,
570 nfsv3err_readlink,
571 nfsv3err_read,
572 nfsv3err_write,
573 nfsv3err_create,
574 nfsv3err_mkdir,
575 nfsv3err_symlink,
576 nfsv3err_mknod,
577 nfsv3err_remove,
578 nfsv3err_rmdir,
579 nfsv3err_rename,
580 nfsv3err_link,
581 nfsv3err_readdir,
582 nfsv3err_readdirplus,
583 nfsv3err_fsstat,
584 nfsv3err_fsinfo,
585 nfsv3err_pathconf,
586 nfsv3err_commit,
587 };
588
589 #endif /* NFS_NOSERVER */
590
591 extern struct nfsrtt nfsrtt;
592 extern struct nfsstats nfsstats;
593 extern nfstype nfsv2_type[9];
594 extern nfstype nfsv3_type[9];
595 extern struct nfsnodehashhead *nfsnodehashtbl;
596 extern u_long nfsnodehash;
597
598
599 LIST_HEAD(nfsnodehashhead, nfsnode);
600
601 /*
602 * Create the header for an rpc request packet
603 * The hsiz is the size of the rest of the nfs request header.
604 * (just used to decide if a cluster is a good idea)
605 */
606 int
607 nfsm_reqh(int hsiz, caddr_t *bposp, mbuf_t *mbp)
608 {
609 int error;
610
611 *mbp = NULL;
612 if (hsiz >= nfs_mbuf_minclsize)
613 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, mbp);
614 else
615 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, mbp);
616 if (error)
617 return (error);
618 *bposp = mbuf_data(*mbp);
619 return (0);
620 }
621
622 /*
623 * Build the RPC header and fill in the authorization info.
624 * The authorization string argument is only used when the credentials
625 * come from outside of the kernel.
626 * Returns the head of the mbuf list.
627 */
628 int
629 nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
630 verf_str, mrest, mrest_len, mbp, xidp, mreqp)
631 kauth_cred_t cr;
632 int nmflag;
633 int procid;
634 int auth_type;
635 int auth_len;
636 char *auth_str;
637 int verf_len;
638 char *verf_str;
639 mbuf_t mrest;
640 int mrest_len;
641 mbuf_t *mbp;
642 u_long *xidp;
643 mbuf_t *mreqp;
644 {
645 mbuf_t mb;
646 u_long *tl;
647 caddr_t bpos;
648 int i, error, len;
649 mbuf_t mreq, mb2;
650 int siz, grpsiz, authsiz, mlen;
651 struct timeval tv;
652
653 authsiz = nfsm_rndup(auth_len);
654 len = authsiz + 10 * NFSX_UNSIGNED;
655 if (len >= nfs_mbuf_minclsize) {
656 error = mbuf_getpacket(MBUF_WAITOK, &mb);
657 } else {
658 error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &mb);
659 if (!error) {
660 if (len < nfs_mbuf_mhlen)
661 mbuf_align_32(mb, len);
662 else
663 mbuf_align_32(mb, 8 * NFSX_UNSIGNED);
664 }
665 }
666 if (error) {
667 /* unable to allocate packet */
668 /* XXX nfsstat? */
669 return (error);
670 }
671 mreq = mb;
672 bpos = mbuf_data(mb);
673
674 /*
675 * First the RPC header.
676 */
677 nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED);
678
679 /*
680 * derive initial xid from system time
681 */
682 if (!nfs_xid) {
683 /*
684 * Note: it's OK if this code inits nfs_xid to 0 (for example,
685 * due to a broken clock) because we immediately increment it
686 * and we guarantee to never use xid 0. So, nfs_xid should only
687 * ever be 0 the first time this function is called.
688 */
689 microtime(&tv);
690 nfs_xid = tv.tv_sec << 12;
691 }
692 /*
693 * Skip zero xid if it should ever happen.
694 */
695 if (++nfs_xid == 0) {
696 nfs_xidwrap++;
697 nfs_xid++;
698 }
699
700 *tl++ = *xidp = txdr_unsigned(nfs_xid);
701 *tl++ = rpc_call;
702 *tl++ = rpc_vers;
703 *tl++ = txdr_unsigned(NFS_PROG);
704 if (nmflag & NFSMNT_NFSV3)
705 *tl++ = txdr_unsigned(NFS_VER3);
706 else
707 *tl++ = txdr_unsigned(NFS_VER2);
708 if (nmflag & NFSMNT_NFSV3)
709 *tl++ = txdr_unsigned(procid);
710 else
711 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
712
713 /*
714 * And then the authorization cred.
715 */
716 *tl++ = txdr_unsigned(auth_type);
717 *tl = txdr_unsigned(authsiz);
718 switch (auth_type) {
719 case RPCAUTH_UNIX:
720 nfsm_build(tl, u_long *, auth_len);
721 *tl++ = 0; /* stamp ?? */
722 *tl++ = 0; /* NULL hostname */
723 *tl++ = txdr_unsigned(kauth_cred_getuid(cr));
724 *tl++ = txdr_unsigned(cr->cr_groups[0]);
725 grpsiz = (auth_len >> 2) - 5;
726 *tl++ = txdr_unsigned(grpsiz);
727 for (i = 1; i <= grpsiz; i++)
728 *tl++ = txdr_unsigned(cr->cr_groups[i]);
729 break;
730 case RPCAUTH_KERB4:
731 siz = auth_len;
732 mlen = mbuf_len(mb);
733 while (siz > 0) {
734 if (mbuf_trailingspace(mb) == 0) {
735 mb2 = NULL;
736 if (siz >= nfs_mbuf_minclsize)
737 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, &mb2);
738 else
739 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &mb2);
740 if (!error)
741 error = mbuf_setnext(mb, mb2);
742 if (error) {
743 mbuf_freem(mreq);
744 return (error);
745 }
746 mb = mb2;
747 mlen = 0;
748 bpos = mbuf_data(mb);
749 }
750 i = min(siz, mbuf_trailingspace(mb));
751 bcopy(auth_str, bpos, i);
752 mlen += i;
753 mbuf_setlen(mb, mlen);
754 auth_str += i;
755 bpos += i;
756 siz -= i;
757 }
758 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
759 for (i = 0; i < siz; i++)
760 *bpos++ = '\0';
761 mlen += siz;
762 mbuf_setlen(mb, mlen);
763 }
764 break;
765 };
766
767 /*
768 * And the verifier...
769 */
770 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
771 if (verf_str) {
772 mlen = mbuf_len(mb);
773 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
774 *tl = txdr_unsigned(verf_len);
775 siz = verf_len;
776 while (siz > 0) {
777 if (mbuf_trailingspace(mb) == 0) {
778 mb2 = NULL;
779 if (siz >= nfs_mbuf_minclsize)
780 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, &mb2);
781 else
782 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &mb2);
783 if (!error)
784 error = mbuf_setnext(mb, mb2);
785 if (error) {
786 mbuf_freem(mreq);
787 return (error);
788 }
789 mb = mb2;
790 mlen = 0;
791 bpos = mbuf_data(mb);
792 }
793 i = min(siz, mbuf_trailingspace(mb));
794 bcopy(verf_str, bpos, i);
795 mlen += i;
796 mbuf_setlen(mb, mlen);
797 verf_str += i;
798 bpos += i;
799 siz -= i;
800 }
801 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
802 for (i = 0; i < siz; i++)
803 *bpos++ = '\0';
804 mlen += siz;
805 mbuf_setlen(mb, mlen);
806 }
807 } else {
808 *tl++ = txdr_unsigned(RPCAUTH_NULL);
809 *tl = 0;
810 }
811 error = mbuf_pkthdr_setrcvif(mreq, 0);
812 if (!error)
813 error = mbuf_setnext(mb, mrest);
814 if (error) {
815 mbuf_freem(mreq);
816 return (error);
817 }
818 mbuf_pkthdr_setlen(mreq, authsiz + 10 * NFSX_UNSIGNED + mrest_len);
819 *mbp = mb;
820 *mreqp = mreq;
821 return (0);
822 }
823
824 /*
825 * copies mbuf chain to the uio scatter/gather list
826 */
827 int
828 nfsm_mbuftouio(mrep, uiop, siz, dpos)
829 mbuf_t *mrep;
830 struct uio *uiop;
831 int siz;
832 caddr_t *dpos;
833 {
834 char *mbufcp, *uiocp;
835 int xfer, left, len;
836 mbuf_t mp;
837 long uiosiz, rem;
838 int error = 0;
839
840 mp = *mrep;
841 mbufcp = *dpos;
842 len = (caddr_t)mbuf_data(mp) + mbuf_len(mp) - mbufcp;
843 rem = nfsm_rndup(siz)-siz;
844 while (siz > 0) {
845 if (uiop->uio_iovcnt <= 0 || uiop->uio_iovs.iov32p == NULL)
846 return (EFBIG);
847 // LP64todo - fix this!
848 left = uio_iov_len(uiop);
849 uiocp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
850 if (left > siz)
851 left = siz;
852 uiosiz = left;
853 while (left > 0) {
854 while (len == 0) {
855 mp = mbuf_next(mp);
856 if (mp == NULL)
857 return (EBADRPC);
858 mbufcp = mbuf_data(mp);
859 len = mbuf_len(mp);
860 }
861 xfer = (left > len) ? len : left;
862 if (UIO_SEG_IS_USER_SPACE(uiop->uio_segflg))
863 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
864 else
865 bcopy(mbufcp, uiocp, xfer);
866 left -= xfer;
867 len -= xfer;
868 mbufcp += xfer;
869 uiocp += xfer;
870 uiop->uio_offset += xfer;
871 uio_uio_resid_add(uiop, -xfer);
872 }
873 if (uio_iov_len(uiop) <= (size_t)siz) {
874 uiop->uio_iovcnt--;
875 uio_next_iov(uiop);
876 } else {
877 uio_iov_base_add(uiop, uiosiz);
878 uio_iov_len_add(uiop, -uiosiz);
879 }
880 siz -= uiosiz;
881 }
882 *dpos = mbufcp;
883 *mrep = mp;
884 if (rem > 0) {
885 if (len < rem)
886 error = nfs_adv(mrep, dpos, rem, len);
887 else
888 *dpos += rem;
889 }
890 return (error);
891 }
892
893 /*
894 * copies a uio scatter/gather list to an mbuf chain.
895 * NOTE: can ony handle iovcnt == 1
896 */
897 int
898 nfsm_uiotombuf(uiop, mq, siz, bpos)
899 struct uio *uiop;
900 mbuf_t *mq;
901 int siz;
902 caddr_t *bpos;
903 {
904 char *uiocp;
905 mbuf_t mp, mp2;
906 int xfer, left, mlen, mplen;
907 int uiosiz, clflg, rem, error;
908 char *cp;
909
910 if (uiop->uio_iovcnt != 1)
911 panic("nfsm_uiotombuf: iovcnt != 1");
912
913 if (siz > nfs_mbuf_mlen) /* or should it >= MCLBYTES ?? */
914 clflg = 1;
915 else
916 clflg = 0;
917 rem = nfsm_rndup(siz)-siz;
918 mp = mp2 = *mq;
919 mplen = mbuf_len(mp);
920 while (siz > 0) {
921 // LP64todo - fix this!
922 left = uio_iov_len(uiop);
923 uiocp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
924 if (left > siz)
925 left = siz;
926 uiosiz = left;
927 while (left > 0) {
928 mlen = mbuf_trailingspace(mp);
929 if (mlen == 0) {
930 mp = NULL;
931 if (clflg)
932 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, &mp);
933 else
934 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &mp);
935 if (!error)
936 error = mbuf_setnext(mp2, mp);
937 if (error)
938 return (error);
939 mplen = 0;
940 mp2 = mp;
941 mlen = mbuf_trailingspace(mp);
942 }
943 xfer = (left > mlen) ? mlen : left;
944 if (UIO_SEG_IS_USER_SPACE(uiop->uio_segflg))
945 copyin(CAST_USER_ADDR_T(uiocp), (caddr_t)mbuf_data(mp) + mplen, xfer);
946 else
947 bcopy(uiocp, (caddr_t)mbuf_data(mp) + mplen, xfer);
948 mplen += xfer;
949 mbuf_setlen(mp, mplen);
950 left -= xfer;
951 uiocp += xfer;
952 uiop->uio_offset += xfer;
953 uio_uio_resid_add(uiop, -xfer);
954 }
955 uio_iov_base_add(uiop, uiosiz);
956 uio_iov_len_add(uiop, -uiosiz);
957 siz -= uiosiz;
958 }
959 if (rem > 0) {
960 if (rem > mbuf_trailingspace(mp)) {
961 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &mp);
962 if (!error)
963 error = mbuf_setnext(mp2, mp);
964 if (error)
965 return (error);
966 mplen = 0;
967 }
968 cp = (caddr_t)mbuf_data(mp) + mplen;
969 for (left = 0; left < rem; left++)
970 *cp++ = '\0';
971 mplen += rem;
972 mbuf_setlen(mp, mplen);
973 *bpos = cp;
974 } else {
975 *bpos = (caddr_t)mbuf_data(mp) + mplen;
976 }
977 *mq = mp;
978 return (0);
979 }
980
981 /*
982 * Help break down an mbuf chain by setting the first siz bytes contiguous
983 * pointed to by returned val.
984 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
985 * cases. (The macros use the vars. dpos and dpos2)
986 */
987 int
988 nfsm_disct(mdp, dposp, siz, left, cp2)
989 mbuf_t *mdp;
990 caddr_t *dposp;
991 int siz;
992 int left;
993 caddr_t *cp2;
994 {
995 mbuf_t mp, mp2;
996 int siz2, xfer, error, mp2len;
997 caddr_t p, mp2data;
998
999 mp = *mdp;
1000 while (left == 0) {
1001 *mdp = mp = mbuf_next(mp);
1002 if (mp == NULL)
1003 return (EBADRPC);
1004 left = mbuf_len(mp);
1005 *dposp = mbuf_data(mp);
1006 }
1007 if (left >= siz) {
1008 *cp2 = *dposp;
1009 *dposp += siz;
1010 } else if (mbuf_next(mp) == NULL) {
1011 return (EBADRPC);
1012 } else if (siz > nfs_mbuf_mhlen) {
1013 panic("nfs S too big");
1014 } else {
1015 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &mp2);
1016 if (error)
1017 return (error);
1018 error = mbuf_setnext(mp2, mbuf_next(mp));
1019 if (!error)
1020 error = mbuf_setnext(mp, mp2);
1021 if (error) {
1022 mbuf_free(mp2);
1023 return (error);
1024 }
1025 mbuf_setlen(mp, mbuf_len(mp) - left);
1026 mp = mp2;
1027 *cp2 = p = mbuf_data(mp);
1028 bcopy(*dposp, p, left); /* Copy what was left */
1029 siz2 = siz-left;
1030 p += left;
1031 mp2 = mbuf_next(mp);
1032 mp2data = mbuf_data(mp2);
1033 mp2len = mbuf_len(mp2);
1034 /* Loop around copying up the siz2 bytes */
1035 while (siz2 > 0) {
1036 if (mp2 == NULL)
1037 return (EBADRPC);
1038 xfer = (siz2 > mp2len) ? mp2len : siz2;
1039 if (xfer > 0) {
1040 bcopy(mp2data, p, xfer);
1041 mp2data += xfer;
1042 mp2len -= xfer;
1043 mbuf_setdata(mp2, mp2data, mp2len);
1044 p += xfer;
1045 siz2 -= xfer;
1046 }
1047 if (siz2 > 0) {
1048 mp2 = mbuf_next(mp2);
1049 mp2data = mbuf_data(mp2);
1050 mp2len = mbuf_len(mp2);
1051 }
1052 }
1053 mbuf_setlen(mp, siz);
1054 *mdp = mp2;
1055 *dposp = mp2data;
1056 }
1057 return (0);
1058 }
1059
1060 /*
1061 * Advance the position in the mbuf chain.
1062 */
1063 int
1064 nfs_adv(mdp, dposp, offs, left)
1065 mbuf_t *mdp;
1066 caddr_t *dposp;
1067 int offs;
1068 int left;
1069 {
1070 mbuf_t m;
1071 int s;
1072
1073 m = *mdp;
1074 s = left;
1075 while (s < offs) {
1076 offs -= s;
1077 m = mbuf_next(m);
1078 if (m == NULL)
1079 return (EBADRPC);
1080 s = mbuf_len(m);
1081 }
1082 *mdp = m;
1083 *dposp = (caddr_t)mbuf_data(m) + offs;
1084 return (0);
1085 }
1086
1087 /*
1088 * Copy a string into mbufs for the hard cases...
1089 */
1090 int
1091 nfsm_strtmbuf(mb, bpos, cp, siz)
1092 mbuf_t *mb;
1093 char **bpos;
1094 char *cp;
1095 long siz;
1096 {
1097 mbuf_t m1 = NULL, m2;
1098 long left, xfer, len, tlen, mlen;
1099 u_long *tl;
1100 int putsize, error;
1101
1102 putsize = 1;
1103 m2 = *mb;
1104 left = mbuf_trailingspace(m2);
1105 if (left >= NFSX_UNSIGNED) {
1106 tl = ((u_long *)(*bpos));
1107 *tl++ = txdr_unsigned(siz);
1108 putsize = 0;
1109 left -= NFSX_UNSIGNED;
1110 len = mbuf_len(m2);
1111 len += NFSX_UNSIGNED;
1112 mbuf_setlen(m2, len);
1113 if (left > 0) {
1114 bcopy(cp, (caddr_t) tl, left);
1115 siz -= left;
1116 cp += left;
1117 len += left;
1118 mbuf_setlen(m2, len);
1119 left = 0;
1120 }
1121 }
1122 /* Loop around adding mbufs */
1123 while (siz > 0) {
1124 m1 = NULL;
1125 if (siz > nfs_mbuf_mlen)
1126 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, &m1);
1127 else
1128 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &m1);
1129 if (!error)
1130 error = mbuf_setnext(m2, m1);
1131 if (error)
1132 return (error);
1133 mlen = mbuf_maxlen(m1);
1134 mbuf_setlen(m1, mlen);
1135 m2 = m1;
1136 tl = mbuf_data(m1);
1137 tlen = 0;
1138 if (putsize) {
1139 *tl++ = txdr_unsigned(siz);
1140 mlen -= NFSX_UNSIGNED;
1141 mbuf_setlen(m1, mlen);
1142 tlen = NFSX_UNSIGNED;
1143 putsize = 0;
1144 }
1145 if (siz < mlen) {
1146 len = nfsm_rndup(siz);
1147 xfer = siz;
1148 if (xfer < len)
1149 *(tl+(xfer>>2)) = 0;
1150 } else {
1151 xfer = len = mlen;
1152 }
1153 bcopy(cp, (caddr_t) tl, xfer);
1154 mbuf_setlen(m1, len + tlen);
1155 siz -= xfer;
1156 cp += xfer;
1157 }
1158 *mb = m1;
1159 *bpos = (caddr_t)mbuf_data(m1) + mbuf_len(m1);
1160 return (0);
1161 }
1162
1163 /*
1164 * Called once to initialize data structures...
1165 */
1166 int
1167 nfs_init(struct vfsconf *vfsp)
1168 {
1169 int i;
1170
1171 /*
1172 * Check to see if major data structures haven't bloated.
1173 */
1174 if (sizeof (struct nfsnode) > NFS_NODEALLOC) {
1175 printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC);
1176 printf("Try reducing NFS_SMALLFH\n");
1177 }
1178 if (sizeof (struct nfsmount) > NFS_MNTALLOC) {
1179 printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC);
1180 printf("Try reducing NFS_MUIDHASHSIZ\n");
1181 }
1182 if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) {
1183 printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC);
1184 printf("Try reducing NFS_UIDHASHSIZ\n");
1185 }
1186 if (sizeof (struct nfsuid) > NFS_UIDALLOC) {
1187 printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC);
1188 printf("Try unionizing the nu_nickname and nu_flag fields\n");
1189 }
1190
1191 nfs_mount_type = vfsp->vfc_typenum;
1192 nfsrtt.pos = 0;
1193 rpc_vers = txdr_unsigned(RPC_VER2);
1194 rpc_call = txdr_unsigned(RPC_CALL);
1195 rpc_reply = txdr_unsigned(RPC_REPLY);
1196 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
1197 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
1198 rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1199 rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1200 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1201 rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1202 nfs_prog = txdr_unsigned(NFS_PROG);
1203 nfs_true = txdr_unsigned(TRUE);
1204 nfs_false = txdr_unsigned(FALSE);
1205 nfs_xdrneg1 = txdr_unsigned(-1);
1206
1207 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1208 if (nfs_ticks < 1)
1209 nfs_ticks = 1;
1210 /* Ensure async daemons disabled */
1211 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
1212 nfs_iodwant[i] = NULL;
1213 nfs_iodmount[i] = (struct nfsmount *)0;
1214 }
1215 /* init nfsiod mutex */
1216 nfs_iod_lck_grp_attr = lck_grp_attr_alloc_init();
1217 nfs_iod_lck_grp = lck_grp_alloc_init("nfs_iod", nfs_iod_lck_grp_attr);
1218 nfs_iod_lck_attr = lck_attr_alloc_init();
1219 nfs_iod_mutex = lck_mtx_alloc_init(nfs_iod_lck_grp, nfs_iod_lck_attr);
1220
1221 nfs_nbinit(); /* Init the nfsbuf table */
1222 nfs_nhinit(); /* Init the nfsnode table */
1223 nfs_lockinit(); /* Init the nfs lock state */
1224
1225 #ifndef NFS_NOSERVER
1226 /* init nfsd mutex */
1227 nfsd_lck_grp_attr = lck_grp_attr_alloc_init();
1228 nfsd_lck_grp = lck_grp_alloc_init("nfsd", nfsd_lck_grp_attr);
1229 nfsd_lck_attr = lck_attr_alloc_init();
1230 nfsd_mutex = lck_mtx_alloc_init(nfsd_lck_grp, nfsd_lck_attr);
1231
1232 /* init slp rwlock */
1233 nfs_slp_lock_attr = lck_attr_alloc_init();
1234 nfs_slp_group_attr = lck_grp_attr_alloc_init();
1235 nfs_slp_rwlock_group = lck_grp_alloc_init("nfs-slp-rwlock", nfs_slp_group_attr);
1236 nfs_slp_mutex_group = lck_grp_alloc_init("nfs-slp-mutex", nfs_slp_group_attr);
1237
1238 /* init export data structures */
1239 nfsexphashtbl = hashinit(8, M_TEMP, &nfsexphash);
1240 LIST_INIT(&nfs_exports);
1241 nfs_export_lock_attr = lck_attr_alloc_init();
1242 nfs_export_group_attr = lck_grp_attr_alloc_init();
1243 nfs_export_rwlock_group = lck_grp_alloc_init("nfs-export-rwlock", nfs_export_group_attr);
1244 lck_rw_init(&nfs_export_rwlock, nfs_export_rwlock_group, nfs_export_lock_attr);
1245
1246 lck_mtx_lock(nfsd_mutex);
1247 nfsrv_init(0); /* Init server data structures */
1248 nfsrv_initcache(); /* Init the server request cache */
1249 lck_mtx_unlock(nfsd_mutex);
1250 #endif
1251
1252 /*
1253 * Initialize reply list and start timer
1254 */
1255 TAILQ_INIT(&nfs_reqq);
1256
1257 nfs_timer(0);
1258
1259 vfsp->vfc_refcount++; /* make us non-unloadable */
1260 return (0);
1261 }
1262
1263 /*
1264 * initialize NFS's cache of mbuf constants
1265 */
1266 void
1267 nfs_mbuf_init(void)
1268 {
1269 struct mbuf_stat ms;
1270
1271 mbuf_stats(&ms);
1272 nfs_mbuf_mlen = ms.mlen;
1273 nfs_mbuf_mhlen = ms.mhlen;
1274 nfs_mbuf_minclsize = ms.minclsize;
1275 nfs_mbuf_mclbytes = ms.mclbytes;
1276 }
1277
1278 /*
1279 * Parse the attributes that are in the mbuf list and store them in *nvap.
1280 */
1281 int
1282 nfs_parsefattr(mbuf_t *mdp, caddr_t *dposp, int v3, struct nfs_vattr *nvap)
1283 {
1284 struct nfs_fattr *fp;
1285 long t1;
1286 caddr_t cp2;
1287 int error = 0, rdev;
1288 mbuf_t md;
1289 enum vtype vtype;
1290 u_short vmode;
1291
1292 md = *mdp;
1293 t1 = ((caddr_t)mbuf_data(md) + mbuf_len(md)) - *dposp;
1294 if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2))) {
1295 return (error);
1296 }
1297 fp = (struct nfs_fattr *)cp2;
1298 if (v3) {
1299 vtype = nfsv3tov_type(fp->fa_type);
1300 vmode = fxdr_unsigned(u_short, fp->fa_mode);
1301 rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
1302 fxdr_unsigned(int, fp->fa3_rdev.specdata2));
1303 } else {
1304 vtype = nfsv2tov_type(fp->fa_type);
1305 vmode = fxdr_unsigned(u_short, fp->fa_mode);
1306 /*
1307 * XXX
1308 *
1309 * The duplicate information returned in fa_type and fa_mode
1310 * is an ambiguity in the NFS version 2 protocol.
1311 *
1312 * VREG should be taken literally as a regular file. If a
1313 * server intents to return some type information differently
1314 * in the upper bits of the mode field (e.g. for sockets, or
1315 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
1316 * leave the examination of the mode bits even in the VREG
1317 * case to avoid breakage for bogus servers, but we make sure
1318 * that there are actually type bits set in the upper part of
1319 * fa_mode (and failing that, trust the va_type field).
1320 *
1321 * NFSv3 cleared the issue, and requires fa_mode to not
1322 * contain any type information (while also introduing sockets
1323 * and FIFOs for fa_type).
1324 */
1325 if (vtype == VNON || (vtype == VREG && (vmode & S_IFMT) != 0))
1326 vtype = IFTOVT(vmode);
1327 rdev = fxdr_unsigned(long, fp->fa2_rdev);
1328 /*
1329 * Really ugly NFSv2 kludge.
1330 */
1331 if (vtype == VCHR && rdev == (int)0xffffffff)
1332 vtype = VFIFO;
1333 }
1334
1335 nvap->nva_type = vtype;
1336 nvap->nva_mode = (vmode & 07777);
1337 nvap->nva_rdev = (dev_t)rdev;
1338 nvap->nva_nlink = (uint64_t)fxdr_unsigned(u_long, fp->fa_nlink);
1339 nvap->nva_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1340 nvap->nva_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1341 if (v3) {
1342 fxdr_hyper(&fp->fa3_size, &nvap->nva_size);
1343 nvap->nva_blocksize = 16*1024;
1344 fxdr_hyper(&fp->fa3_used, &nvap->nva_bytes);
1345 fxdr_hyper(&fp->fa3_fileid, &nvap->nva_fileid);
1346 fxdr_nfsv3time(&fp->fa3_atime, &nvap->nva_atime);
1347 fxdr_nfsv3time(&fp->fa3_mtime, &nvap->nva_mtime);
1348 fxdr_nfsv3time(&fp->fa3_ctime, &nvap->nva_ctime);
1349 } else {
1350 nvap->nva_size = fxdr_unsigned(u_long, fp->fa2_size);
1351 nvap->nva_blocksize = fxdr_unsigned(long, fp->fa2_blocksize);
1352 nvap->nva_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE;
1353 nvap->nva_fileid = (uint64_t)fxdr_unsigned(u_long, fp->fa2_fileid);
1354 fxdr_nfsv2time(&fp->fa2_atime, &nvap->nva_atime);
1355 fxdr_nfsv2time(&fp->fa2_mtime, &nvap->nva_mtime);
1356 fxdr_nfsv2time(&fp->fa2_ctime, &nvap->nva_ctime);
1357 }
1358
1359 return (0);
1360 }
1361
1362 /*
1363 * Load the attribute cache (that lives in the nfsnode entry) with
1364 * the value pointed to by nvap, unless the file type in the attribute
1365 * cache doesn't match the file type in the nvap, in which case log a
1366 * warning and return ESTALE.
1367 *
1368 * If the dontshrink flag is set, then it's not safe to call ubc_setsize()
1369 * to shrink the size of the file.
1370 */
1371 int
1372 nfs_loadattrcache(
1373 struct nfsnode *np,
1374 struct nfs_vattr *nvap,
1375 u_int64_t *xidp,
1376 int dontshrink)
1377 {
1378 mount_t mp;
1379 vnode_t vp;
1380 struct timeval now;
1381 struct nfs_vattr *npnvap;
1382
1383 if (np->n_flag & NINIT) {
1384 vp = NULL;
1385 mp = np->n_mount;
1386 } else {
1387 vp = NFSTOV(np);
1388 mp = vnode_mount(vp);
1389 }
1390
1391 FSDBG_TOP(527, vp, np, *xidp >> 32, *xidp);
1392
1393 if (!VFSTONFS(mp)) {
1394 FSDBG_BOT(527, ENXIO, 1, 0, *xidp);
1395 return (ENXIO);
1396 }
1397
1398 if (*xidp < np->n_xid) {
1399 /*
1400 * We have already updated attributes with a response from
1401 * a later request. The attributes we have here are probably
1402 * stale so we drop them (just return). However, our
1403 * out-of-order receipt could be correct - if the requests were
1404 * processed out of order at the server. Given the uncertainty
1405 * we invalidate our cached attributes. *xidp is zeroed here
1406 * to indicate the attributes were dropped - only getattr
1407 * cares - it needs to retry the rpc.
1408 */
1409 NATTRINVALIDATE(np);
1410 FSDBG_BOT(527, 0, np, np->n_xid, *xidp);
1411 *xidp = 0;
1412 return (0);
1413 }
1414
1415 if (vp && (nvap->nva_type != vnode_vtype(vp))) {
1416 /*
1417 * The filehandle has changed type on us. This can be
1418 * caused by either the server not having unique filehandles
1419 * or because another client has removed the previous
1420 * filehandle and a new object (of a different type)
1421 * has been created with the same filehandle.
1422 *
1423 * We can't simply switch the type on the vnode because
1424 * there may be type-specific fields that need to be
1425 * cleaned up or set up.
1426 *
1427 * So, what should we do with this vnode?
1428 *
1429 * About the best we can do is log a warning and return
1430 * an error. ESTALE is about the closest error, but it
1431 * is a little strange that we come up with this error
1432 * internally instead of simply passing it through from
1433 * the server. Hopefully, the vnode will be reclaimed
1434 * soon so the filehandle can be reincarnated as the new
1435 * object type.
1436 */
1437 printf("nfs loadattrcache vnode changed type, was %d now %d\n",
1438 vnode_vtype(vp), nvap->nva_type);
1439 FSDBG_BOT(527, ESTALE, 3, 0, *xidp);
1440 return (ESTALE);
1441 }
1442
1443 microuptime(&now);
1444 np->n_attrstamp = now.tv_sec;
1445 np->n_xid = *xidp;
1446
1447 npnvap = &np->n_vattr;
1448 nvap->nva_fsid = vfs_statfs(mp)->f_fsid.val[0];
1449 bcopy((caddr_t)nvap, (caddr_t)npnvap, sizeof(*nvap));
1450
1451 if (vp) {
1452 if (nvap->nva_size != np->n_size) {
1453 FSDBG(527, vp, nvap->nva_size, np->n_size,
1454 (nvap->nva_type == VREG) |
1455 (np->n_flag & NMODIFIED ? 6 : 4));
1456 if (nvap->nva_type == VREG) {
1457 u_quad_t orig_size = np->n_size;
1458 if (np->n_flag & NMODIFIED) {
1459 if (nvap->nva_size < np->n_size)
1460 nvap->nva_size = np->n_size;
1461 else
1462 np->n_size = nvap->nva_size;
1463 } else
1464 np->n_size = nvap->nva_size;
1465 if (!UBCINFOEXISTS(vp) ||
1466 (dontshrink && np->n_size < (u_quad_t)ubc_getsize(vp))) {
1467 nvap->nva_size = np->n_size = orig_size;
1468 NATTRINVALIDATE(np);
1469 } else {
1470 ubc_setsize(vp, (off_t)np->n_size); /* XXX */
1471 }
1472 } else
1473 np->n_size = nvap->nva_size;
1474 }
1475 } else {
1476 np->n_size = nvap->nva_size;
1477 }
1478
1479 if (np->n_flag & NCHG) {
1480 if (np->n_flag & NACC)
1481 nvap->nva_atime = np->n_atim;
1482 if (np->n_flag & NUPD)
1483 nvap->nva_mtime = np->n_mtim;
1484 }
1485
1486 FSDBG_BOT(527, 0, np, 0, *xidp);
1487 return (0);
1488 }
1489
1490 /*
1491 * Calculate the attribute timeout based on
1492 * how recently the file has been modified.
1493 */
1494 int
1495 nfs_attrcachetimeout(vnode_t vp)
1496 {
1497 struct nfsnode *np = VTONFS(vp);
1498 struct nfsmount *nmp;
1499 struct timeval now;
1500 int isdir, timeo;
1501
1502 if (!(nmp = VFSTONFS(vnode_mount(vp))))
1503 return (0);
1504
1505 isdir = vnode_isdir(vp);
1506
1507 if ((np)->n_flag & NMODIFIED)
1508 timeo = isdir ? nmp->nm_acdirmin : nmp->nm_acregmin;
1509 else {
1510 /* Note that if the client and server clocks are way out of sync, */
1511 /* timeout will probably get clamped to a min or max value */
1512 microtime(&now);
1513 timeo = (now.tv_sec - (np)->n_mtime.tv_sec) / 10;
1514 if (isdir) {
1515 if (timeo < nmp->nm_acdirmin)
1516 timeo = nmp->nm_acdirmin;
1517 else if (timeo > nmp->nm_acdirmax)
1518 timeo = nmp->nm_acdirmax;
1519 } else {
1520 if (timeo < nmp->nm_acregmin)
1521 timeo = nmp->nm_acregmin;
1522 else if (timeo > nmp->nm_acregmax)
1523 timeo = nmp->nm_acregmax;
1524 }
1525 }
1526
1527 return (timeo);
1528 }
1529
1530 /*
1531 * Check the time stamp
1532 * If the cache is valid, copy contents to *nvaper and return 0
1533 * otherwise return an error
1534 */
1535 int
1536 nfs_getattrcache(vp, nvaper)
1537 vnode_t vp;
1538 struct nfs_vattr *nvaper;
1539 {
1540 struct nfsnode *np = VTONFS(vp);
1541 struct nfs_vattr *nvap;
1542 struct timeval nowup;
1543 int32_t timeo;
1544
1545 if (!NATTRVALID(np)) {
1546 FSDBG(528, vp, 0, 0, 0);
1547 OSAddAtomic(1, (SInt32*)&nfsstats.attrcache_misses);
1548 return (ENOENT);
1549 }
1550
1551 timeo = nfs_attrcachetimeout(vp);
1552
1553 microuptime(&nowup);
1554 if ((nowup.tv_sec - np->n_attrstamp) >= timeo) {
1555 FSDBG(528, vp, 0, 0, 1);
1556 OSAddAtomic(1, (SInt32*)&nfsstats.attrcache_misses);
1557 return (ENOENT);
1558 }
1559 FSDBG(528, vp, 0, 0, 2);
1560 OSAddAtomic(1, (SInt32*)&nfsstats.attrcache_hits);
1561 nvap = &np->n_vattr;
1562
1563 if (nvap->nva_size != np->n_size) {
1564 FSDBG(528, vp, nvap->nva_size, np->n_size,
1565 (nvap->nva_type == VREG) |
1566 (np->n_flag & NMODIFIED ? 6 : 4));
1567 if (nvap->nva_type == VREG) {
1568 if (np->n_flag & NMODIFIED) {
1569 if (nvap->nva_size < np->n_size)
1570 nvap->nva_size = np->n_size;
1571 else
1572 np->n_size = nvap->nva_size;
1573 } else
1574 np->n_size = nvap->nva_size;
1575 ubc_setsize(vp, (off_t)np->n_size); /* XXX */
1576 } else
1577 np->n_size = nvap->nva_size;
1578 }
1579
1580 bcopy((caddr_t)nvap, (caddr_t)nvaper, sizeof(struct nfs_vattr));
1581 if (np->n_flag & NCHG) {
1582 if (np->n_flag & NACC)
1583 nvaper->nva_atime = np->n_atim;
1584 if (np->n_flag & NUPD)
1585 nvaper->nva_mtime = np->n_mtim;
1586 }
1587 return (0);
1588 }
1589
1590 #ifndef NFS_NOSERVER
1591 /*
1592 * Extract a lookup path from the given mbufs and store it in
1593 * a newly allocated buffer saved in the given nameidata structure.
1594 * exptected string length given as *lenp and final string length
1595 * (after any WebNFS processing) is returned in *lenp.
1596 */
1597 int
1598 nfsm_path_mbuftond(
1599 mbuf_t *mdp,
1600 caddr_t *dposp,
1601 __unused int v3,
1602 __unused int pubflag,
1603 int* lenp,
1604 struct nameidata *ndp)
1605 {
1606 int i, len, len2, rem, error = 0;
1607 mbuf_t md;
1608 char *fromcp, *tocp;
1609 struct componentname *cnp = &ndp->ni_cnd;
1610 /* XXX Revisit when enabling WebNFS */
1611 #ifdef WEBNFS_ENABLED
1612 int webcnt = 0, digitcnt = 0;
1613 char hexdigits[2];
1614 #endif
1615
1616 len = *lenp;
1617 if (len > (MAXPATHLEN - 1))
1618 return (ENAMETOOLONG);
1619
1620 /*
1621 * Get a buffer for the name to be translated, and copy the
1622 * name into the buffer.
1623 */
1624 MALLOC_ZONE(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
1625 if (!cnp->cn_pnbuf)
1626 return (ENOMEM);
1627 cnp->cn_pnlen = MAXPATHLEN;
1628 cnp->cn_flags |= HASBUF;
1629
1630 /*
1631 * Copy the name from the mbuf list to the string
1632 *
1633 * Along the way, take note of any WebNFS characters
1634 * and convert any % escapes.
1635 */
1636 fromcp = *dposp;
1637 tocp = cnp->cn_pnbuf;
1638 md = *mdp;
1639 rem = (caddr_t)mbuf_data(md) + mbuf_len(md) - fromcp;
1640 for (i = 1; i <= len; i++) {
1641 while (rem == 0) {
1642 md = mbuf_next(md);
1643 if (md == NULL) {
1644 error = EBADRPC;
1645 goto out;
1646 }
1647 fromcp = mbuf_data(md);
1648 rem = mbuf_len(md);
1649 }
1650 /* XXX Revisit when enabling WebNFS */
1651 #ifdef WEBNFS_ENABLED
1652 if (pubflag) {
1653 if ((i == 1) && ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START)) {
1654 switch ((unsigned char)*fromcp) {
1655 case WEBNFS_NATIVE_CHAR:
1656 /*
1657 * 'Native' path for us is the same
1658 * as a path according to the NFS spec,
1659 * just skip the escape char.
1660 */
1661 webcnt++;
1662 fromcp++;
1663 rem--;
1664 /* next iteration of for loop */
1665 continue;
1666 /*
1667 * More may be added in the future, range 0x80-0xff.
1668 * Don't currently support security query lookup (0x81).
1669 */
1670 default:
1671 error = EIO;
1672 goto out;
1673 }
1674 }
1675 if (digitcnt) {
1676 /* We're expecting hex digits */
1677 if (!ISHEX(*fromcp)) {
1678 error = ENOENT;
1679 goto out;
1680 }
1681 digitcnt--;
1682 hexdigits[digitcnt ? 0 : 1] = *fromcp++;
1683 if (!digitcnt)
1684 *tocp++ = HEXSTRTOI(hexdigits);
1685 rem--;
1686 /* next iteration of for loop */
1687 continue;
1688 } else if (*fromcp == WEBNFS_ESC_CHAR) {
1689 /*
1690 * We can't really look at the next couple
1691 * bytes here safely/easily, so we note that
1692 * the next two characters should be hex
1693 * digits and later save them in hexdigits[].
1694 * When we've got both, we'll convert it.
1695 */
1696 digitcnt = 2;
1697 webcnt += 2;
1698 fromcp++;
1699 rem--;
1700 /* next iteration of for loop */
1701 continue;
1702 }
1703 }
1704 if (*fromcp == '\0' || (!pubflag && *fromcp == '/'))
1705 #else
1706 if (*fromcp == '\0' || *fromcp == '/')
1707 #endif
1708 {
1709 error = EACCES;
1710 goto out;
1711 }
1712 *tocp++ = *fromcp++;
1713 rem--;
1714 }
1715 *tocp = '\0';
1716 *mdp = md;
1717 *dposp = fromcp;
1718 len2 = nfsm_rndup(len)-len;
1719 if (len2 > 0) {
1720 if (rem >= len2)
1721 *dposp += len2;
1722 else if ((error = nfs_adv(mdp, dposp, len2, rem)) != 0)
1723 goto out;
1724 }
1725
1726 /* XXX Revisit when enabling WebNFS */
1727 #ifdef WEBNFS_ENABLED
1728 if (pubflag) {
1729 if (digitcnt) {
1730 /* The string ended in the middle of an escape! */
1731 error = ENOENT;
1732 goto out;
1733 }
1734 len -= webcnt;
1735 }
1736 #endif
1737
1738 out:
1739 if (error) {
1740 if (cnp->cn_pnbuf)
1741 FREE_ZONE(cnp->cn_pnbuf, MAXPATHLEN, M_NAMEI);
1742 cnp->cn_flags &= ~HASBUF;
1743 } else {
1744 ndp->ni_pathlen = len;
1745 *lenp = len;
1746 }
1747 return (error);
1748 }
1749
1750 /*
1751 * Set up nameidata for a lookup() call and do it.
1752 *
1753 * If pubflag is set, this call is done for a lookup operation on the
1754 * public filehandle. In that case we allow crossing mountpoints and
1755 * absolute pathnames. However, the caller is expected to check that
1756 * the lookup result is within the public fs, and deny access if
1757 * it is not.
1758 */
1759 int
1760 nfs_namei(
1761 struct nfsrv_descript *nfsd,
1762 struct vfs_context *ctx,
1763 struct nameidata *ndp,
1764 struct nfs_filehandle *nfhp,
1765 mbuf_t nam,
1766 int pubflag,
1767 vnode_t *retdirp,
1768 struct nfs_export **nxp,
1769 struct nfs_export_options **nxop)
1770 {
1771 /* XXX Revisit when enabling WebNFS */
1772 #ifdef WEBNFS_ENABLED
1773 char *cp;
1774 uio_t auio;
1775 char uio_buf[ UIO_SIZEOF(1) ];
1776 int linklen, olen = ndp->ni_pathlen;
1777 #endif
1778 vnode_t dp;
1779 int error;
1780 struct componentname *cnp = &ndp->ni_cnd;
1781 char *tmppn;
1782
1783 *retdirp = NULL;
1784
1785 /*
1786 * Extract and set starting directory.
1787 */
1788 error = nfsrv_fhtovp(nfhp, nam, pubflag, &dp, nxp, nxop);
1789 if (error)
1790 goto out;
1791 error = nfsrv_credcheck(nfsd, *nxp, *nxop);
1792 if (error || (vnode_vtype(dp) != VDIR)) {
1793 vnode_put(dp);
1794 error = ENOTDIR;
1795 goto out;
1796 }
1797
1798 ctx->vc_ucred = nfsd->nd_cr;
1799 ndp->ni_cnd.cn_context = ctx;
1800
1801 if (*nxop && ((*nxop)->nxo_flags & NX_READONLY))
1802 cnp->cn_flags |= RDONLY;
1803
1804 *retdirp = dp;
1805
1806 /* XXX Revisit when enabling WebNFS */
1807 #ifdef WEBNFS_ENABLED
1808 if (pubflag) {
1809 ndp->ni_rootdir = rootvnode;
1810 ndp->ni_loopcnt = 0;
1811 if (cnp->cn_pnbuf[0] == '/') {
1812 vnode_put(dp);
1813 dp = rootvnode;
1814 error = vnode_get(dp);
1815 if (error) {
1816 *retdirp = NULL;
1817 goto out;
1818 }
1819 }
1820 } else {
1821 cnp->cn_flags |= NOCROSSMOUNT;
1822 }
1823 #else
1824 cnp->cn_flags |= NOCROSSMOUNT;
1825 #endif
1826
1827 ndp->ni_usedvp = dp;
1828
1829 for (;;) {
1830 cnp->cn_nameptr = cnp->cn_pnbuf;
1831 ndp->ni_startdir = dp;
1832 /*
1833 * And call lookup() to do the real work
1834 */
1835 error = lookup(ndp);
1836 if (error)
1837 break;
1838 /*
1839 * Check for encountering a symbolic link
1840 */
1841 if ((cnp->cn_flags & ISSYMLINK) == 0) {
1842 return (0);
1843 } else {
1844 if ((cnp->cn_flags & FSNODELOCKHELD)) {
1845 cnp->cn_flags &= ~FSNODELOCKHELD;
1846 unlock_fsnode(ndp->ni_dvp, NULL);
1847 }
1848 /* XXX Revisit when enabling WebNFS */
1849 #ifdef WEBNFS_ENABLED
1850 if (!pubflag) {
1851 #endif
1852 if (cnp->cn_flags & (LOCKPARENT | WANTPARENT))
1853 vnode_put(ndp->ni_dvp);
1854 if (ndp->ni_vp) {
1855 vnode_put(ndp->ni_vp);
1856 ndp->ni_vp = NULL;
1857 }
1858 error = EINVAL;
1859 break;
1860 /* XXX Revisit when enabling WebNFS */
1861 #ifdef WEBNFS_ENABLED
1862 }
1863
1864 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
1865 vnode_put(ndp->ni_vp);
1866 ndp->ni_vp = NULL;
1867 error = ELOOP;
1868 break;
1869 }
1870 /* XXX assert(olen <= MAXPATHLEN - 1); */
1871 if (ndp->ni_pathlen > 1) {
1872 MALLOC_ZONE(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
1873 if (!cp) {
1874 vnode_put(ndp->ni_vp);
1875 ndp->ni_vp = NULL;
1876 error = ENOMEM;
1877 break;
1878 }
1879 } else {
1880 cp = cnp->cn_pnbuf;
1881 }
1882 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
1883 &uio_buf[0], sizeof(uio_buf));
1884 if (!auio) {
1885 vnode_put(ndp->ni_vp);
1886 ndp->ni_vp = NULL;
1887 if (ndp->ni_pathlen > 1)
1888 FREE_ZONE(cp, MAXPATHLEN, M_NAMEI);
1889 error = ENOMEM;
1890 break;
1891 }
1892 uio_addiov(auio, CAST_USER_ADDR_T(cp), MAXPATHLEN);
1893 error = VNOP_READLINK(ndp->ni_vp, auio, cnp->cn_context);
1894 if (error) {
1895 badlink:
1896 vnode_put(ndp->ni_vp);
1897 ndp->ni_vp = NULL;
1898 if (ndp->ni_pathlen > 1)
1899 FREE_ZONE(cp, MAXPATHLEN, M_NAMEI);
1900 break;
1901 }
1902 linklen = MAXPATHLEN - uio_resid(auio);
1903 if (linklen == 0) {
1904 error = ENOENT;
1905 goto badlink;
1906 }
1907 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
1908 error = ENAMETOOLONG;
1909 goto badlink;
1910 }
1911 if (ndp->ni_pathlen > 1) {
1912 long len = cnp->cn_pnlen;
1913 tmppn = cnp->cn_pnbuf;
1914 cnp->cn_pnbuf = cp;
1915 cnp->cn_pnlen = olen + 1;
1916 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
1917 FREE_ZONE(tmppn, len, M_NAMEI);
1918 } else
1919 cnp->cn_pnbuf[linklen] = '\0';
1920 ndp->ni_pathlen += linklen;
1921
1922 vnode_put(ndp->ni_vp);
1923 dp = ndp->ni_dvp;
1924 ndp->ni_dvp = NULL;
1925
1926 /*
1927 * Check if root directory should replace current directory.
1928 */
1929 if (cnp->cn_pnbuf[0] == '/') {
1930 vnode_put(dp);
1931 dp = ndp->ni_rootdir;
1932 error = vnode_get(dp);
1933 if (error)
1934 break;
1935 }
1936 #endif
1937 }
1938 }
1939 out:
1940 tmppn = cnp->cn_pnbuf;
1941 cnp->cn_pnbuf = NULL;
1942 cnp->cn_flags &= ~HASBUF;
1943 FREE_ZONE(tmppn, cnp->cn_pnlen, M_NAMEI);
1944
1945 return (error);
1946 }
1947
1948 /*
1949 * A fiddled version of m_adj() that ensures null fill to a long
1950 * boundary and only trims off the back end
1951 */
1952 void
1953 nfsm_adj(mp, len, nul)
1954 mbuf_t mp;
1955 int len;
1956 int nul;
1957 {
1958 mbuf_t m, mnext;
1959 int count, i, mlen;
1960 char *cp;
1961
1962 /*
1963 * Trim from tail. Scan the mbuf chain,
1964 * calculating its length and finding the last mbuf.
1965 * If the adjustment only affects this mbuf, then just
1966 * adjust and return. Otherwise, rescan and truncate
1967 * after the remaining size.
1968 */
1969 count = 0;
1970 m = mp;
1971 for (;;) {
1972 mlen = mbuf_len(m);
1973 count += mlen;
1974 mnext = mbuf_next(m);
1975 if (mnext == NULL)
1976 break;
1977 m = mnext;
1978 }
1979 if (mlen > len) {
1980 mlen -= len;
1981 mbuf_setlen(m, mlen);
1982 if (nul > 0) {
1983 cp = (caddr_t)mbuf_data(m) + mlen - nul;
1984 for (i = 0; i < nul; i++)
1985 *cp++ = '\0';
1986 }
1987 return;
1988 }
1989 count -= len;
1990 if (count < 0)
1991 count = 0;
1992 /*
1993 * Correct length for chain is "count".
1994 * Find the mbuf with last data, adjust its length,
1995 * and toss data from remaining mbufs on chain.
1996 */
1997 for (m = mp; m; m = mbuf_next(m)) {
1998 mlen = mbuf_len(m);
1999 if (mlen >= count) {
2000 mlen = count;
2001 mbuf_setlen(m, count);
2002 if (nul > 0) {
2003 cp = (caddr_t)mbuf_data(m) + mlen - nul;
2004 for (i = 0; i < nul; i++)
2005 *cp++ = '\0';
2006 }
2007 break;
2008 }
2009 count -= mlen;
2010 }
2011 for (m = mbuf_next(m); m; m = mbuf_next(m))
2012 mbuf_setlen(m, 0);
2013 }
2014
2015 /*
2016 * Make these functions instead of macros, so that the kernel text size
2017 * doesn't get too big...
2018 */
2019 void
2020 nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
2021 struct nfsrv_descript *nfsd;
2022 int before_ret;
2023 struct vnode_attr *before_vap;
2024 int after_ret;
2025 struct vnode_attr *after_vap;
2026 mbuf_t *mbp;
2027 char **bposp;
2028 {
2029 mbuf_t mb = *mbp, mb2;
2030 char *bpos = *bposp;
2031 u_long *tl;
2032
2033 if (before_ret) {
2034 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
2035 *tl = nfs_false;
2036 } else {
2037 nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED);
2038 *tl++ = nfs_true;
2039 txdr_hyper(&(before_vap->va_data_size), tl);
2040 tl += 2;
2041 txdr_nfsv3time(&(before_vap->va_modify_time), tl);
2042 tl += 2;
2043 txdr_nfsv3time(&(before_vap->va_change_time), tl);
2044 }
2045 *bposp = bpos;
2046 *mbp = mb;
2047 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
2048 }
2049
2050 void
2051 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
2052 struct nfsrv_descript *nfsd;
2053 int after_ret;
2054 struct vnode_attr *after_vap;
2055 mbuf_t *mbp;
2056 char **bposp;
2057 {
2058 mbuf_t mb = *mbp, mb2;
2059 char *bpos = *bposp;
2060 u_long *tl;
2061 struct nfs_fattr *fp;
2062
2063 if (after_ret) {
2064 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
2065 *tl = nfs_false;
2066 } else {
2067 nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR);
2068 *tl++ = nfs_true;
2069 fp = (struct nfs_fattr *)tl;
2070 nfsm_srvfattr(nfsd, after_vap, fp);
2071 }
2072 *mbp = mb;
2073 *bposp = bpos;
2074 }
2075
2076 void
2077 nfsm_srvfattr(nfsd, vap, fp)
2078 struct nfsrv_descript *nfsd;
2079 struct vnode_attr *vap;
2080 struct nfs_fattr *fp;
2081 {
2082
2083 // XXX Should we assert here that all fields are supported?
2084
2085 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
2086 fp->fa_uid = txdr_unsigned(vap->va_uid);
2087 fp->fa_gid = txdr_unsigned(vap->va_gid);
2088 if (nfsd->nd_flag & ND_NFSV3) {
2089 fp->fa_type = vtonfsv3_type(vap->va_type);
2090 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
2091 txdr_hyper(&vap->va_data_size, &fp->fa3_size);
2092 txdr_hyper(&vap->va_data_alloc, &fp->fa3_used);
2093 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
2094 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
2095 fp->fa3_fsid.nfsuquad[0] = 0;
2096 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
2097 txdr_hyper(&vap->va_fileid, &fp->fa3_fileid);
2098 txdr_nfsv3time(&vap->va_access_time, &fp->fa3_atime);
2099 txdr_nfsv3time(&vap->va_modify_time, &fp->fa3_mtime);
2100 txdr_nfsv3time(&vap->va_change_time, &fp->fa3_ctime);
2101 } else {
2102 fp->fa_type = vtonfsv2_type(vap->va_type);
2103 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
2104 fp->fa2_size = txdr_unsigned(vap->va_data_size);
2105 fp->fa2_blocksize = txdr_unsigned(vap->va_iosize);
2106 if (vap->va_type == VFIFO)
2107 fp->fa2_rdev = 0xffffffff;
2108 else
2109 fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
2110 fp->fa2_blocks = txdr_unsigned(vap->va_data_alloc / NFS_FABLKSIZE);
2111 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
2112 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
2113 txdr_nfsv2time(&vap->va_access_time, &fp->fa2_atime);
2114 txdr_nfsv2time(&vap->va_modify_time, &fp->fa2_mtime);
2115 txdr_nfsv2time(&vap->va_change_time, &fp->fa2_ctime);
2116 }
2117 }
2118
2119 /*
2120 * Build hash lists of net addresses and hang them off the NFS export.
2121 * Called by nfsrv_export() to set up the lists of export addresses.
2122 */
2123 static int
2124 nfsrv_hang_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa)
2125 {
2126 struct nfs_export_net_args nxna;
2127 struct nfs_netopt *no;
2128 struct radix_node_head *rnh;
2129 struct radix_node *rn;
2130 struct sockaddr *saddr, *smask;
2131 struct domain *dom;
2132 int i, error;
2133 unsigned int net;
2134 user_addr_t uaddr;
2135 kauth_cred_t cred;
2136 struct ucred temp_cred;
2137
2138 uaddr = unxa->nxa_nets;
2139 for (net = 0; net < unxa->nxa_netcount; net++, uaddr += sizeof(nxna)) {
2140 error = copyin(uaddr, &nxna, sizeof(nxna));
2141 if (error)
2142 return (error);
2143
2144 if (nxna.nxna_flags & (NX_MAPROOT|NX_MAPALL)) {
2145 bzero(&temp_cred, sizeof(temp_cred));
2146 temp_cred.cr_uid = nxna.nxna_cred.cr_uid;
2147 temp_cred.cr_ngroups = nxna.nxna_cred.cr_ngroups;
2148 for (i=0; i < nxna.nxna_cred.cr_ngroups && i < NGROUPS; i++)
2149 temp_cred.cr_groups[i] = nxna.nxna_cred.cr_groups[i];
2150
2151 cred = kauth_cred_create(&temp_cred);
2152 if (!cred)
2153 return (ENOMEM);
2154 } else {
2155 cred = NULL;
2156 }
2157
2158 if (nxna.nxna_addr.ss_len == 0) {
2159 /* No address means this is a default/world export */
2160 if (nx->nx_flags & NX_DEFAULTEXPORT)
2161 return (EEXIST);
2162 nx->nx_flags |= NX_DEFAULTEXPORT;
2163 nx->nx_defopt.nxo_flags = nxna.nxna_flags;
2164 nx->nx_defopt.nxo_cred = cred;
2165 nx->nx_expcnt++;
2166 continue;
2167 }
2168
2169 i = sizeof(struct nfs_netopt);
2170 i += nxna.nxna_addr.ss_len + nxna.nxna_mask.ss_len;
2171 MALLOC(no, struct nfs_netopt *, i, M_NETADDR, M_WAITOK);
2172 if (!no)
2173 return (ENOMEM);
2174 bzero(no, sizeof(struct nfs_netopt));
2175 no->no_opt.nxo_flags = nxna.nxna_flags;
2176 no->no_opt.nxo_cred = cred;
2177
2178 saddr = (struct sockaddr *)(no + 1);
2179 bcopy(&nxna.nxna_addr, saddr, nxna.nxna_addr.ss_len);
2180 if (nxna.nxna_mask.ss_len) {
2181 smask = (struct sockaddr *)((caddr_t)saddr + nxna.nxna_addr.ss_len);
2182 bcopy(&nxna.nxna_mask, smask, nxna.nxna_mask.ss_len);
2183 } else {
2184 smask = NULL;
2185 }
2186 i = saddr->sa_family;
2187 if ((rnh = nx->nx_rtable[i]) == 0) {
2188 /*
2189 * Seems silly to initialize every AF when most are not
2190 * used, do so on demand here
2191 */
2192 for (dom = domains; dom; dom = dom->dom_next)
2193 if (dom->dom_family == i && dom->dom_rtattach) {
2194 dom->dom_rtattach((void **)&nx->nx_rtable[i],
2195 dom->dom_rtoffset);
2196 break;
2197 }
2198 if ((rnh = nx->nx_rtable[i]) == 0) {
2199 kauth_cred_rele(cred);
2200 _FREE(no, M_NETADDR);
2201 return (ENOBUFS);
2202 }
2203 }
2204 rn = (*rnh->rnh_addaddr)((caddr_t)saddr, (caddr_t)smask, rnh, no->no_rnodes);
2205 if (rn == 0) {
2206 /*
2207 * One of the reasons that rnh_addaddr may fail is that
2208 * the entry already exists. To check for this case, we
2209 * look up the entry to see if it is there. If so, we
2210 * do not need to make a new entry but do continue.
2211 */
2212 int matched = 0;
2213 rn = (*rnh->rnh_matchaddr)((caddr_t)saddr, rnh);
2214 if (rn != 0 && (rn->rn_flags & RNF_ROOT) == 0 &&
2215 (((struct nfs_netopt *)rn)->no_opt.nxo_flags == nxna.nxna_flags)) {
2216 kauth_cred_t cred2 = ((struct nfs_netopt *)rn)->no_opt.nxo_cred;
2217 if (cred && cred2 && (cred->cr_uid == cred2->cr_uid) &&
2218 (cred->cr_ngroups == cred2->cr_ngroups)) {
2219 for (i=0; i < cred2->cr_ngroups && i < NGROUPS; i++)
2220 if (cred->cr_groups[i] != cred2->cr_groups[i])
2221 break;
2222 if (i >= cred2->cr_ngroups || i >= NGROUPS)
2223 matched = 1;
2224 }
2225 }
2226 kauth_cred_rele(cred);
2227 _FREE(no, M_NETADDR);
2228 if (matched)
2229 continue;
2230 return (EPERM);
2231 }
2232 nx->nx_expcnt++;
2233 }
2234
2235 return (0);
2236 }
2237
2238 /*
2239 * In order to properly track an export's netopt count, we need to pass
2240 * an additional argument to nfsrv_free_netopt() so that it can decrement
2241 * the export's netopt count.
2242 */
2243 struct nfsrv_free_netopt_arg {
2244 uint32_t *cnt;
2245 struct radix_node_head *rnh;
2246 };
2247
2248 static int
2249 nfsrv_free_netopt(struct radix_node *rn, void *w)
2250 {
2251 struct nfsrv_free_netopt_arg *fna = (struct nfsrv_free_netopt_arg *)w;
2252 struct radix_node_head *rnh = fna->rnh;
2253 uint32_t *cnt = fna->cnt;
2254 struct nfs_netopt *nno = (struct nfs_netopt *)rn;
2255
2256 (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh);
2257 if (nno->no_opt.nxo_cred)
2258 kauth_cred_rele(nno->no_opt.nxo_cred);
2259 _FREE((caddr_t)rn, M_NETADDR);
2260 *cnt -= 1;
2261 return (0);
2262 }
2263
2264 /*
2265 * Free the net address hash lists that are hanging off the mount points.
2266 */
2267 static void
2268 nfsrv_free_addrlist(struct nfs_export *nx)
2269 {
2270 int i;
2271 struct radix_node_head *rnh;
2272 struct nfsrv_free_netopt_arg fna;
2273
2274 for (i = 0; i <= AF_MAX; i++)
2275 if ( (rnh = nx->nx_rtable[i]) ) {
2276 fna.rnh = rnh;
2277 fna.cnt = &nx->nx_expcnt;
2278 (*rnh->rnh_walktree)(rnh, nfsrv_free_netopt, (caddr_t)&fna);
2279 _FREE((caddr_t)rnh, M_RTABLE);
2280 nx->nx_rtable[i] = 0;
2281 }
2282 }
2283
2284 void enablequotas(struct mount *mp, vfs_context_t ctx); // XXX
2285
2286 int
2287 nfsrv_export(struct user_nfs_export_args *unxa, struct vfs_context *ctx)
2288 {
2289 int error = 0, pathlen;
2290 struct nfs_exportfs *nxfs, *nxfs2, *nxfs3;
2291 struct nfs_export *nx, *nx2, *nx3;
2292 struct nfs_filehandle nfh;
2293 struct nameidata mnd, xnd;
2294 vnode_t mvp = NULL, xvp = NULL;
2295 mount_t mp;
2296 char path[MAXPATHLEN];
2297 int expisroot;
2298
2299 if (unxa->nxa_flags & NXA_DELETE_ALL) {
2300 /* delete all exports on all file systems */
2301 lck_rw_lock_exclusive(&nfs_export_rwlock);
2302 while ((nxfs = LIST_FIRST(&nfs_exports))) {
2303 mp = vfs_getvfs_by_mntonname(nxfs->nxfs_path);
2304 if (mp)
2305 mp->mnt_flag &= ~MNT_EXPORTED;
2306 /* delete all exports on this file system */
2307 while ((nx = LIST_FIRST(&nxfs->nxfs_exports))) {
2308 LIST_REMOVE(nx, nx_next);
2309 LIST_REMOVE(nx, nx_hash);
2310 /* delete all netopts for this export */
2311 nfsrv_free_addrlist(nx);
2312 nx->nx_flags &= ~NX_DEFAULTEXPORT;
2313 if (nx->nx_defopt.nxo_cred) {
2314 kauth_cred_rele(nx->nx_defopt.nxo_cred);
2315 nx->nx_defopt.nxo_cred = NULL;
2316 }
2317 FREE(nx->nx_path, M_TEMP);
2318 FREE(nx, M_TEMP);
2319 }
2320 LIST_REMOVE(nxfs, nxfs_next);
2321 FREE(nxfs->nxfs_path, M_TEMP);
2322 FREE(nxfs, M_TEMP);
2323 }
2324 lck_rw_done(&nfs_export_rwlock);
2325 return (0);
2326 }
2327
2328 error = copyinstr(unxa->nxa_fspath, path, MAXPATHLEN, (size_t *)&pathlen);
2329 if (error)
2330 return (error);
2331
2332 lck_rw_lock_exclusive(&nfs_export_rwlock);
2333
2334 // first check if we've already got an exportfs with the given ID
2335 LIST_FOREACH(nxfs, &nfs_exports, nxfs_next) {
2336 if (nxfs->nxfs_id == unxa->nxa_fsid)
2337 break;
2338 }
2339 if (nxfs) {
2340 /* verify exported FS path matches given path */
2341 if (strcmp(path, nxfs->nxfs_path)) {
2342 error = EEXIST;
2343 goto unlock_out;
2344 }
2345 mp = vfs_getvfs_by_mntonname(nxfs->nxfs_path);
2346 /* find exported FS root vnode */
2347 NDINIT(&mnd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
2348 UIO_SYSSPACE, nxfs->nxfs_path, ctx);
2349 error = namei(&mnd);
2350 if (error)
2351 goto unlock_out;
2352 mvp = mnd.ni_vp;
2353 /* make sure it's (still) the root of a file system */
2354 if ((mvp->v_flag & VROOT) == 0) {
2355 error = EINVAL;
2356 goto out;
2357 }
2358 /* sanity check: this should be same mount */
2359 if (mp != vnode_mount(mvp)) {
2360 error = EINVAL;
2361 goto out;
2362 }
2363 } else {
2364 /* no current exported file system with that ID */
2365 if (!(unxa->nxa_flags & NXA_ADD)) {
2366 error = ENOENT;
2367 goto unlock_out;
2368 }
2369
2370 /* find exported FS root vnode */
2371 NDINIT(&mnd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
2372 UIO_SYSSPACE, path, ctx);
2373 error = namei(&mnd);
2374 if (error)
2375 goto unlock_out;
2376 mvp = mnd.ni_vp;
2377 /* make sure it's the root of a file system */
2378 if ((mvp->v_flag & VROOT) == 0) {
2379 error = EINVAL;
2380 goto out;
2381 }
2382 mp = vnode_mount(mvp);
2383
2384 /* make sure the file system is NFS-exportable */
2385 nfh.nfh_len = NFS_MAX_FID_SIZE;
2386 error = VFS_VPTOFH(mvp, &nfh.nfh_len, &nfh.nfh_fid[0], NULL);
2387 if (!error && (nfh.nfh_len > (int)NFS_MAX_FID_SIZE))
2388 error = EIO;
2389 if (error)
2390 goto out;
2391
2392 /* add an exportfs for it */
2393 MALLOC(nxfs, struct nfs_exportfs *, sizeof(struct nfs_exportfs), M_TEMP, M_WAITOK);
2394 if (!nxfs) {
2395 error = ENOMEM;
2396 goto out;
2397 }
2398 bzero(nxfs, sizeof(struct nfs_exportfs));
2399 nxfs->nxfs_id = unxa->nxa_fsid;
2400 MALLOC(nxfs->nxfs_path, char*, pathlen, M_TEMP, M_WAITOK);
2401 if (!nxfs->nxfs_path) {
2402 FREE(nxfs, M_TEMP);
2403 error = ENOMEM;
2404 goto out;
2405 }
2406 bcopy(path, nxfs->nxfs_path, pathlen);
2407 /* insert into list in reverse-sorted order */
2408 nxfs3 = NULL;
2409 LIST_FOREACH(nxfs2, &nfs_exports, nxfs_next) {
2410 if (strcmp(nxfs->nxfs_path, nxfs2->nxfs_path) > 0)
2411 break;
2412 nxfs3 = nxfs2;
2413 }
2414 if (nxfs2)
2415 LIST_INSERT_BEFORE(nxfs2, nxfs, nxfs_next);
2416 else if (nxfs3)
2417 LIST_INSERT_AFTER(nxfs3, nxfs, nxfs_next);
2418 else
2419 LIST_INSERT_HEAD(&nfs_exports, nxfs, nxfs_next);
2420
2421 /* make sure any quotas are enabled before we export the file system */
2422 enablequotas(mp, ctx);
2423 }
2424
2425 if (unxa->nxa_exppath) {
2426 error = copyinstr(unxa->nxa_exppath, path, MAXPATHLEN, (size_t *)&pathlen);
2427 if (error)
2428 goto out;
2429 LIST_FOREACH(nx, &nxfs->nxfs_exports, nx_next) {
2430 if (nx->nx_id == unxa->nxa_expid)
2431 break;
2432 }
2433 if (nx) {
2434 /* verify exported FS path matches given path */
2435 if (strcmp(path, nx->nx_path)) {
2436 error = EEXIST;
2437 goto out;
2438 }
2439 } else {
2440 /* no current export with that ID */
2441 if (!(unxa->nxa_flags & NXA_ADD)) {
2442 error = ENOENT;
2443 goto out;
2444 }
2445 /* add an export for it */
2446 MALLOC(nx, struct nfs_export *, sizeof(struct nfs_export), M_TEMP, M_WAITOK);
2447 if (!nx) {
2448 error = ENOMEM;
2449 goto out1;
2450 }
2451 bzero(nx, sizeof(struct nfs_export));
2452 nx->nx_id = unxa->nxa_expid;
2453 nx->nx_fs = nxfs;
2454 MALLOC(nx->nx_path, char*, pathlen, M_TEMP, M_WAITOK);
2455 if (!nx->nx_path) {
2456 error = ENOMEM;
2457 FREE(nx, M_TEMP);
2458 nx = NULL;
2459 goto out1;
2460 }
2461 bcopy(path, nx->nx_path, pathlen);
2462 /* insert into list in reverse-sorted order */
2463 nx3 = NULL;
2464 LIST_FOREACH(nx2, &nxfs->nxfs_exports, nx_next) {
2465 if (strcmp(nx->nx_path, nx2->nx_path) > 0)
2466 break;
2467 nx3 = nx2;
2468 }
2469 if (nx2)
2470 LIST_INSERT_BEFORE(nx2, nx, nx_next);
2471 else if (nx3)
2472 LIST_INSERT_AFTER(nx3, nx, nx_next);
2473 else
2474 LIST_INSERT_HEAD(&nxfs->nxfs_exports, nx, nx_next);
2475 /* insert into hash */
2476 LIST_INSERT_HEAD(NFSEXPHASH(nxfs->nxfs_id, nx->nx_id), nx, nx_hash);
2477
2478 /*
2479 * We don't allow nested exports. Check if the new entry
2480 * nests with the entries before and after or if there's an
2481 * entry for the file system root and subdirs.
2482 */
2483 error = 0;
2484 if ((nx3 && !strncmp(nx3->nx_path, nx->nx_path, pathlen - 1) &&
2485 (nx3->nx_path[pathlen-1] == '/')) ||
2486 (nx2 && !strncmp(nx2->nx_path, nx->nx_path, strlen(nx2->nx_path)) &&
2487 (nx->nx_path[strlen(nx2->nx_path)] == '/')))
2488 error = EINVAL;
2489 if (!error) {
2490 /* check export conflict with fs root export and vice versa */
2491 expisroot = !nx->nx_path[0] ||
2492 ((nx->nx_path[0] == '.') && !nx->nx_path[1]);
2493 LIST_FOREACH(nx2, &nxfs->nxfs_exports, nx_next) {
2494 if (expisroot) {
2495 if (nx2 != nx)
2496 break;
2497 } else if (!nx2->nx_path[0])
2498 break;
2499 else if ((nx2->nx_path[0] == '.') && !nx2->nx_path[1])
2500 break;
2501 }
2502 if (nx2)
2503 error = EINVAL;
2504 }
2505 if (error) {
2506 printf("nfsrv_export: attempt to register nested exports: %s/%s\n",
2507 nxfs->nxfs_path, nx->nx_path);
2508 goto out1;
2509 }
2510
2511 /* find export root vnode */
2512 if (!nx->nx_path[0] || ((nx->nx_path[0] == '.') && !nx->nx_path[1])) {
2513 /* exporting file system's root directory */
2514 xvp = mvp;
2515 vnode_get(xvp);
2516 } else {
2517 xnd.ni_cnd.cn_nameiop = LOOKUP;
2518 xnd.ni_cnd.cn_flags = LOCKLEAF;
2519 xnd.ni_pathlen = pathlen - 1;
2520 xnd.ni_cnd.cn_nameptr = xnd.ni_cnd.cn_pnbuf = path;
2521 xnd.ni_startdir = mvp;
2522 xnd.ni_usedvp = mvp;
2523 xnd.ni_cnd.cn_context = ctx;
2524 error = lookup(&xnd);
2525 if (error)
2526 goto out1;
2527 xvp = xnd.ni_vp;
2528 }
2529
2530 if (vnode_vtype(xvp) != VDIR) {
2531 error = EINVAL;
2532 vnode_put(xvp);
2533 goto out1;
2534 }
2535
2536 /* grab file handle */
2537 nx->nx_fh.nfh_xh.nxh_version = htonl(NFS_FH_VERSION);
2538 nx->nx_fh.nfh_xh.nxh_fsid = htonl(nx->nx_fs->nxfs_id);
2539 nx->nx_fh.nfh_xh.nxh_expid = htonl(nx->nx_id);
2540 nx->nx_fh.nfh_xh.nxh_flags = 0;
2541 nx->nx_fh.nfh_xh.nxh_reserved = 0;
2542 nx->nx_fh.nfh_len = NFS_MAX_FID_SIZE;
2543 error = VFS_VPTOFH(xvp, &nx->nx_fh.nfh_len, &nx->nx_fh.nfh_fid[0], NULL);
2544 if (!error && (nx->nx_fh.nfh_len > (int)NFS_MAX_FID_SIZE)) {
2545 error = EIO;
2546 } else {
2547 nx->nx_fh.nfh_xh.nxh_fidlen = nx->nx_fh.nfh_len;
2548 nx->nx_fh.nfh_len += sizeof(nx->nx_fh.nfh_xh);
2549 }
2550
2551 vnode_put(xvp);
2552 if (error)
2553 goto out1;
2554 }
2555 } else {
2556 nx = NULL;
2557 }
2558
2559 /* perform the export changes */
2560 if (unxa->nxa_flags & NXA_DELETE) {
2561 if (!nx) {
2562 /* delete all exports on this file system */
2563 while ((nx = LIST_FIRST(&nxfs->nxfs_exports))) {
2564 LIST_REMOVE(nx, nx_next);
2565 LIST_REMOVE(nx, nx_hash);
2566 /* delete all netopts for this export */
2567 nfsrv_free_addrlist(nx);
2568 nx->nx_flags &= ~NX_DEFAULTEXPORT;
2569 if (nx->nx_defopt.nxo_cred) {
2570 kauth_cred_rele(nx->nx_defopt.nxo_cred);
2571 nx->nx_defopt.nxo_cred = NULL;
2572 }
2573 FREE(nx->nx_path, M_TEMP);
2574 FREE(nx, M_TEMP);
2575 }
2576 goto out1;
2577 } else {
2578 /* delete all netopts for this export */
2579 nfsrv_free_addrlist(nx);
2580 nx->nx_flags &= ~NX_DEFAULTEXPORT;
2581 if (nx->nx_defopt.nxo_cred) {
2582 kauth_cred_rele(nx->nx_defopt.nxo_cred);
2583 nx->nx_defopt.nxo_cred = NULL;
2584 }
2585 }
2586 }
2587 if (unxa->nxa_flags & NXA_ADD) {
2588 error = nfsrv_hang_addrlist(nx, unxa);
2589 if (!error)
2590 mp->mnt_flag |= MNT_EXPORTED;
2591 }
2592
2593 out1:
2594 if (nx && !nx->nx_expcnt) {
2595 /* export has no export options */
2596 LIST_REMOVE(nx, nx_next);
2597 LIST_REMOVE(nx, nx_hash);
2598 FREE(nx->nx_path, M_TEMP);
2599 FREE(nx, M_TEMP);
2600 }
2601 if (LIST_EMPTY(&nxfs->nxfs_exports)) {
2602 /* exported file system has no more exports */
2603 LIST_REMOVE(nxfs, nxfs_next);
2604 FREE(nxfs->nxfs_path, M_TEMP);
2605 FREE(nxfs, M_TEMP);
2606 mp->mnt_flag &= ~MNT_EXPORTED;
2607 }
2608
2609 out:
2610 if (mvp) {
2611 vnode_put(mvp);
2612 nameidone(&mnd);
2613 }
2614 unlock_out:
2615 lck_rw_done(&nfs_export_rwlock);
2616 return (error);
2617 }
2618
2619 static struct nfs_export_options *
2620 nfsrv_export_lookup(struct nfs_export *nx, mbuf_t nam)
2621 {
2622 struct nfs_export_options *nxo = NULL;
2623 struct nfs_netopt *no = NULL;
2624 struct radix_node_head *rnh;
2625 struct sockaddr *saddr;
2626
2627 /* Lookup in the export list first. */
2628 if (nam != NULL) {
2629 saddr = mbuf_data(nam);
2630 rnh = nx->nx_rtable[saddr->sa_family];
2631 if (rnh != NULL) {
2632 no = (struct nfs_netopt *)
2633 (*rnh->rnh_matchaddr)((caddr_t)saddr, rnh);
2634 if (no && no->no_rnodes->rn_flags & RNF_ROOT)
2635 no = NULL;
2636 if (no)
2637 nxo = &no->no_opt;
2638 }
2639 }
2640 /* If no address match, use the default if it exists. */
2641 if ((nxo == NULL) && (nx->nx_flags & NX_DEFAULTEXPORT))
2642 nxo = &nx->nx_defopt;
2643 return (nxo);
2644 }
2645
2646 /* find an export for the given handle */
2647 static struct nfs_export *
2648 nfsrv_fhtoexport(struct nfs_filehandle *nfhp)
2649 {
2650 struct nfs_export *nx;
2651 uint32_t fsid, expid;
2652
2653 fsid = ntohl(nfhp->nfh_xh.nxh_fsid);
2654 expid = ntohl(nfhp->nfh_xh.nxh_expid);
2655 nx = NFSEXPHASH(fsid, expid)->lh_first;
2656 for (; nx; nx = LIST_NEXT(nx, nx_hash)) {
2657 if (nx->nx_fs->nxfs_id != fsid)
2658 continue;
2659 if (nx->nx_id != expid)
2660 continue;
2661 break;
2662 }
2663 return nx;
2664 }
2665
2666 /*
2667 * nfsrv_fhtovp() - convert FH to vnode and export info
2668 */
2669 int
2670 nfsrv_fhtovp(
2671 struct nfs_filehandle *nfhp,
2672 mbuf_t nam,
2673 __unused int pubflag,
2674 vnode_t *vpp,
2675 struct nfs_export **nxp,
2676 struct nfs_export_options **nxop)
2677 {
2678 int error;
2679 struct mount *mp;
2680 uint32_t v;
2681
2682 *vpp = NULL;
2683 *nxp = NULL;
2684 *nxop = NULL;
2685
2686 v = ntohl(nfhp->nfh_xh.nxh_version);
2687 if (v != NFS_FH_VERSION) {
2688 /* file handle format not supported */
2689 return (ESTALE);
2690 }
2691 if (nfhp->nfh_len > NFS_MAX_FH_SIZE)
2692 return (EBADRPC);
2693 if (nfhp->nfh_len < (int)sizeof(nfhp->nfh_xh))
2694 return (ESTALE);
2695 v = ntohs(nfhp->nfh_xh.nxh_flags);
2696 if (v & NXHF_INVALIDFH)
2697 return (ESTALE);
2698
2699 /* XXX Revisit when enabling WebNFS */
2700 #ifdef WEBNFS_ENABLED
2701 if (nfs_ispublicfh(nfhp)) {
2702 if (!pubflag || !nfs_pub.np_valid)
2703 return (ESTALE);
2704 nfhp = &nfs_pub.np_handle;
2705 }
2706 #endif
2707
2708 *nxp = nfsrv_fhtoexport(nfhp);
2709 if (!*nxp)
2710 return (ESTALE);
2711
2712 /* Get the export option structure for this <export, client> tuple. */
2713 *nxop = nfsrv_export_lookup(*nxp, nam);
2714 if (nam && (*nxop == NULL))
2715 return (EACCES);
2716
2717 /* find mount structure */
2718 mp = vfs_getvfs_by_mntonname((*nxp)->nx_fs->nxfs_path);
2719 if (!mp)
2720 return (ESTALE);
2721
2722 error = VFS_FHTOVP(mp, nfhp->nfh_xh.nxh_fidlen, &nfhp->nfh_fid[0], vpp, NULL);
2723 if (error)
2724 return (error);
2725 /* vnode pointer should be good at this point or ... */
2726 if (*vpp == NULL)
2727 return (ESTALE);
2728 return (0);
2729 }
2730
2731 /*
2732 * nfsrv_credcheck() - check/map credentials according to given export options
2733 */
2734 int
2735 nfsrv_credcheck(
2736 struct nfsrv_descript *nfsd,
2737 __unused struct nfs_export *nx,
2738 struct nfs_export_options *nxo)
2739 {
2740 if (nxo && nxo->nxo_cred) {
2741 if ((nxo->nxo_flags & NX_MAPALL) ||
2742 ((nxo->nxo_flags & NX_MAPROOT) && !suser(nfsd->nd_cr, NULL))) {
2743 kauth_cred_rele(nfsd->nd_cr);
2744 nfsd->nd_cr = nxo->nxo_cred;
2745 kauth_cred_ref(nfsd->nd_cr);
2746 }
2747 }
2748 return (0);
2749 }
2750
2751
2752 /*
2753 * WebNFS: check if a filehandle is a public filehandle. For v3, this
2754 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
2755 * transformed this to all zeroes in both cases, so check for it.
2756 */
2757 int
2758 nfs_ispublicfh(struct nfs_filehandle *nfhp)
2759 {
2760 char *cp = (char *)nfhp;
2761 unsigned int i;
2762
2763 if (nfhp->nfh_len == 0)
2764 return (TRUE);
2765 if (nfhp->nfh_len != NFSX_V2FH)
2766 return (FALSE);
2767 for (i = 0; i < NFSX_V2FH; i++)
2768 if (*cp++ != 0)
2769 return (FALSE);
2770 return (TRUE);
2771 }
2772
2773 /*
2774 * nfsrv_vptofh() - convert vnode to file handle for given export
2775 *
2776 * If the caller is passing in a vnode for a ".." directory entry,
2777 * they can pass a directory NFS file handle (dnfhp) which will be
2778 * checked against the root export file handle. If it matches, we
2779 * refuse to provide the file handle for the out-of-export directory.
2780 */
2781 int
2782 nfsrv_vptofh(
2783 struct nfs_export *nx,
2784 int v2,
2785 struct nfs_filehandle *dnfhp,
2786 vnode_t vp,
2787 struct vfs_context *ctx,
2788 struct nfs_filehandle *nfhp)
2789 {
2790 int error;
2791
2792 nfhp->nfh_xh.nxh_version = htonl(NFS_FH_VERSION);
2793 nfhp->nfh_xh.nxh_fsid = htonl(nx->nx_fs->nxfs_id);
2794 nfhp->nfh_xh.nxh_expid = htonl(nx->nx_id);
2795 nfhp->nfh_xh.nxh_flags = 0;
2796 nfhp->nfh_xh.nxh_reserved = 0;
2797
2798 if (v2)
2799 bzero(&nfhp->nfh_fid[0], NFSV2_MAX_FID_SIZE);
2800
2801 /* if directory FH matches export root, return invalid FH */
2802 if (dnfhp && nfsrv_fhmatch(dnfhp, &nx->nx_fh)) {
2803 nfhp->nfh_len = v2 ? NFSX_V2FH : sizeof(nfhp->nfh_xh);
2804 nfhp->nfh_xh.nxh_fidlen = 0;
2805 nfhp->nfh_xh.nxh_flags = htons(NXHF_INVALIDFH);
2806 return (0);
2807 }
2808
2809 nfhp->nfh_len = v2 ? NFSV2_MAX_FID_SIZE : NFS_MAX_FID_SIZE;
2810 error = VFS_VPTOFH(vp, &nfhp->nfh_len, &nfhp->nfh_fid[0], ctx);
2811 if (error)
2812 return (error);
2813 if (nfhp->nfh_len > (int)(v2 ? NFSV2_MAX_FID_SIZE : NFS_MAX_FID_SIZE))
2814 return (EOVERFLOW);
2815 nfhp->nfh_xh.nxh_fidlen = nfhp->nfh_len;
2816 nfhp->nfh_len += sizeof(nfhp->nfh_xh);
2817 if (v2 && (nfhp->nfh_len < NFSX_V2FH))
2818 nfhp->nfh_len = NFSX_V2FH;
2819
2820 return (0);
2821 }
2822
2823 int
2824 nfsrv_fhmatch(struct nfs_filehandle *fh1, struct nfs_filehandle *fh2)
2825 {
2826 int len1, len2;
2827
2828 len1 = sizeof(fh1->nfh_xh) + fh1->nfh_xh.nxh_fidlen;
2829 len2 = sizeof(fh2->nfh_xh) + fh2->nfh_xh.nxh_fidlen;
2830 if (len1 != len2)
2831 return (0);
2832 if (bcmp(&fh1->nfh_xh, &fh2->nfh_xh, len1))
2833 return (0);
2834 return (1);
2835 }
2836
2837 #endif /* NFS_NOSERVER */
2838 /*
2839 * This function compares two net addresses by family and returns TRUE
2840 * if they are the same host.
2841 * If there is any doubt, return FALSE.
2842 * The AF_INET family is handled as a special case so that address mbufs
2843 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
2844 */
2845 int
2846 netaddr_match(family, haddr, nam)
2847 int family;
2848 union nethostaddr *haddr;
2849 mbuf_t nam;
2850 {
2851 struct sockaddr_in *inetaddr;
2852
2853 switch (family) {
2854 case AF_INET:
2855 inetaddr = mbuf_data(nam);
2856 if (inetaddr->sin_family == AF_INET &&
2857 inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
2858 return (1);
2859 break;
2860 #if ISO
2861 case AF_ISO:
2862 {
2863 struct sockaddr_iso *isoaddr1, *isoaddr2;
2864
2865 isoaddr1 = mbuf_data(nam);
2866 isoaddr2 = mbuf_data(haddr->had_nam);
2867 if (isoaddr1->siso_family == AF_ISO &&
2868 isoaddr1->siso_nlen > 0 &&
2869 isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
2870 SAME_ISOADDR(isoaddr1, isoaddr2))
2871 return (1);
2872 break;
2873 }
2874 #endif /* ISO */
2875 default:
2876 break;
2877 };
2878 return (0);
2879 }
2880
2881 static nfsuint64 nfs_nullcookie = { { 0, 0 } };
2882 /*
2883 * This function finds the directory cookie that corresponds to the
2884 * logical byte offset given.
2885 */
2886 nfsuint64 *
2887 nfs_getcookie(np, off, add)
2888 struct nfsnode *np;
2889 off_t off;
2890 int add;
2891 {
2892 struct nfsdmap *dp, *dp2;
2893 int pos;
2894
2895 pos = off / NFS_DIRBLKSIZ;
2896 if (pos == 0) {
2897 #if DIAGNOSTIC
2898 if (add)
2899 panic("nfs getcookie add at 0");
2900 #endif
2901 return (&nfs_nullcookie);
2902 }
2903 pos--;
2904 dp = np->n_cookies.lh_first;
2905 if (!dp) {
2906 if (add) {
2907 MALLOC_ZONE(dp, struct nfsdmap *, sizeof(struct nfsdmap),
2908 M_NFSDIROFF, M_WAITOK);
2909 if (!dp)
2910 return ((nfsuint64 *)0);
2911 dp->ndm_eocookie = 0;
2912 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
2913 } else
2914 return ((nfsuint64 *)0);
2915 }
2916 while (pos >= NFSNUMCOOKIES) {
2917 pos -= NFSNUMCOOKIES;
2918 if (dp->ndm_list.le_next) {
2919 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
2920 pos >= dp->ndm_eocookie)
2921 return ((nfsuint64 *)0);
2922 dp = dp->ndm_list.le_next;
2923 } else if (add) {
2924 MALLOC_ZONE(dp2, struct nfsdmap *, sizeof(struct nfsdmap),
2925 M_NFSDIROFF, M_WAITOK);
2926 if (!dp2)
2927 return ((nfsuint64 *)0);
2928 dp2->ndm_eocookie = 0;
2929 LIST_INSERT_AFTER(dp, dp2, ndm_list);
2930 dp = dp2;
2931 } else
2932 return ((nfsuint64 *)0);
2933 }
2934 if (pos >= dp->ndm_eocookie) {
2935 if (add)
2936 dp->ndm_eocookie = pos + 1;
2937 else
2938 return ((nfsuint64 *)0);
2939 }
2940 return (&dp->ndm_cookies[pos]);
2941 }
2942
2943 /*
2944 * Invalidate cached directory information, except for the actual directory
2945 * blocks (which are invalidated separately).
2946 * Done mainly to avoid the use of stale offset cookies.
2947 */
2948 void
2949 nfs_invaldir(vp)
2950 vnode_t vp;
2951 {
2952 struct nfsnode *np = VTONFS(vp);
2953
2954 #if DIAGNOSTIC
2955 if (vnode_vtype(vp) != VDIR)
2956 panic("nfs: invaldir not dir");
2957 #endif
2958 np->n_direofoffset = 0;
2959 np->n_cookieverf.nfsuquad[0] = 0;
2960 np->n_cookieverf.nfsuquad[1] = 0;
2961 if (np->n_cookies.lh_first)
2962 np->n_cookies.lh_first->ndm_eocookie = 0;
2963 }
2964
2965 /*
2966 * The write verifier has changed (probably due to a server reboot), so all
2967 * NB_NEEDCOMMIT blocks will have to be written again. Since they are on the
2968 * dirty block list as NB_DELWRI, all this takes is clearing the NB_NEEDCOMMIT
2969 * flag. Once done the new write verifier can be set for the mount point.
2970 */
2971 static int
2972 nfs_clearcommit_callout(vnode_t vp, __unused void *arg)
2973 {
2974 struct nfsnode *np = VTONFS(vp);
2975 struct nfsbuflists blist;
2976 struct nfsbuf *bp;
2977
2978 lck_mtx_lock(nfs_buf_mutex);
2979 if (nfs_buf_iterprepare(np, &blist, NBI_DIRTY)) {
2980 lck_mtx_unlock(nfs_buf_mutex);
2981 return (VNODE_RETURNED);
2982 }
2983 LIST_FOREACH(bp, &blist, nb_vnbufs) {
2984 if (nfs_buf_acquire(bp, NBAC_NOWAIT, 0, 0))
2985 continue;
2986 if ((bp->nb_flags & (NB_DELWRI | NB_NEEDCOMMIT))
2987 == (NB_DELWRI | NB_NEEDCOMMIT)) {
2988 bp->nb_flags &= ~NB_NEEDCOMMIT;
2989 np->n_needcommitcnt--;
2990 }
2991 nfs_buf_drop(bp);
2992 }
2993 CHECK_NEEDCOMMITCNT(np);
2994 nfs_buf_itercomplete(np, &blist, NBI_DIRTY);
2995 lck_mtx_unlock(nfs_buf_mutex);
2996 return (VNODE_RETURNED);
2997 }
2998
2999 void
3000 nfs_clearcommit(mount_t mp)
3001 {
3002 vnode_iterate(mp, VNODE_NOLOCK_INTERNAL, nfs_clearcommit_callout, NULL);
3003 }
3004
3005 #ifndef NFS_NOSERVER
3006 /*
3007 * Map errnos to NFS error numbers. For Version 3 also filter out error
3008 * numbers not specified for the associated procedure.
3009 */
3010 int
3011 nfsrv_errmap(nd, err)
3012 struct nfsrv_descript *nd;
3013 int err;
3014 {
3015 short *defaulterrp, *errp;
3016
3017 if (nd->nd_flag & ND_NFSV3) {
3018 if (nd->nd_procnum <= NFSPROC_COMMIT) {
3019 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
3020 while (*++errp) {
3021 if (*errp == err)
3022 return (err);
3023 else if (*errp > err)
3024 break;
3025 }
3026 return ((int)*defaulterrp);
3027 } else
3028 return (err & 0xffff);
3029 }
3030 if (err <= ELAST)
3031 return ((int)nfsrv_v2errmap[err - 1]);
3032 return (NFSERR_IO);
3033 }
3034
3035 #endif /* NFS_NOSERVER */
3036