nfs_export.c revision 1.2 1 /* $NetBSD: nfs_export.c,v 1.2 2005/09/23 19:39:15 jmmv Exp $ */
2
3 /*-
4 * Copyright (c) 1997, 1998, 2004, 2005 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by Charles M. Hannum.
12 * This code is derived from software contributed to The NetBSD Foundation
13 * by Julio M. Merino Vidal.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. All advertising materials mentioning features or use of this software
24 * must display the following acknowledgement:
25 * This product includes software developed by the NetBSD
26 * Foundation, Inc. and its contributors.
27 * 4. Neither the name of The NetBSD Foundation nor the names of its
28 * contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
32 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
33 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
35 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGE.
42 */
43
44 /*
45 * Copyright (c) 1989, 1993
46 * The Regents of the University of California. All rights reserved.
47 * (c) UNIX System Laboratories, Inc.
48 * All or some portions of this file are derived from material licensed
49 * to the University of California by American Telephone and Telegraph
50 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
51 * the permission of UNIX System Laboratories, Inc.
52 *
53 * Redistribution and use in source and binary forms, with or without
54 * modification, are permitted provided that the following conditions
55 * are met:
56 * 1. Redistributions of source code must retain the above copyright
57 * notice, this list of conditions and the following disclaimer.
58 * 2. Redistributions in binary form must reproduce the above copyright
59 * notice, this list of conditions and the following disclaimer in the
60 * documentation and/or other materials provided with the distribution.
61 * 3. Neither the name of the University nor the names of its contributors
62 * may be used to endorse or promote products derived from this software
63 * without specific prior written permission.
64 *
65 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
66 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
67 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
68 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
69 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
70 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
71 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
72 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
73 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
74 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
75 * SUCH DAMAGE.
76 *
77 * @(#)vfs_subr.c 8.13 (Berkeley) 4/18/94
78 */
79
80 /*
81 * VFS exports list management.
82 */
83
84 #include <sys/cdefs.h>
85 __KERNEL_RCSID(0, "$NetBSD: nfs_export.c,v 1.2 2005/09/23 19:39:15 jmmv Exp $");
86
87 #include "opt_inet.h"
88
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/queue.h>
92 #include <sys/proc.h>
93 #include <sys/mount.h>
94 #include <sys/vnode.h>
95 #include <sys/namei.h>
96 #include <sys/errno.h>
97 #include <sys/malloc.h>
98 #include <sys/domain.h>
99 #include <sys/mbuf.h>
100 #include <sys/dirent.h>
101 #include <sys/socket.h> /* XXX for AF_MAX */
102
103 #include <net/radix.h>
104
105 #include <netinet/in.h>
106
107 #include <nfs/rpcv2.h>
108 #include <nfs/nfsproto.h>
109 #include <nfs/nfs.h>
110 #include <nfs/nfs_var.h>
111
112 /*
113 * Network address lookup element.
114 */
115 struct netcred {
116 struct radix_node netc_rnodes[2];
117 int netc_refcnt;
118 int netc_exflags;
119 struct ucred netc_anon;
120 };
121
122 /*
123 * Network export information.
124 */
125 struct netexport {
126 struct netcred ne_defexported; /* Default export */
127 struct radix_node_head *ne_rtable[AF_MAX+1]; /* Individual exports */
128 };
129
130 /*
131 * Structures to map between standard mount points to their corresponding
132 * network export information.
133 */
134 struct mount_netexport_pair {
135 CIRCLEQ_ENTRY(mount_netexport_pair) mnp_entries;
136 const struct mount *mnp_mount;
137 struct netexport mnp_netexport;
138 };
139 CIRCLEQ_HEAD(mount_netexport_map, mount_netexport_pair)
140 mount_netexport_map = CIRCLEQ_HEAD_INITIALIZER(mount_netexport_map);
141
142 /* Malloc type used by the mount<->netexport map. */
143 MALLOC_DEFINE(M_NFS_EXPORT, "nfs_export", "NFS export data");
144
145 /* Publicly exported file system. */
146 struct nfs_public nfs_pub;
147
148 /*
149 * Local prototypes.
150 */
151 static int init_exports(struct mount *, struct mount_netexport_pair **);
152 static int hang_addrlist(struct mount *, struct netexport *,
153 const struct export_args *);
154 static int sacheck(struct sockaddr *);
155 static int free_netcred(struct radix_node *, void *);
156 static void clear_exports(struct mount *, struct netexport *);
157 static int export(struct mount *, struct netexport *,
158 const struct export_args *);
159 static int setpublicfs(struct mount *, struct netexport *,
160 const struct export_args *);
161 static struct netcred *export_lookup(struct mount *, struct netexport *,
162 struct mbuf *);
163
164 /*
165 * PUBLIC INTERFACE
166 */
167
168 /*
169 * Declare and initialize the file system export hooks.
170 */
171 static void nfs_export_unmount(struct mount *);
172
173 struct vfs_hooks nfs_export_hooks = {
174 nfs_export_unmount
175 };
176 VFS_HOOKS_ATTACH(nfs_export_hooks);
177
178 /*
179 * VFS unmount hook for NFS exports.
180 *
181 * Releases NFS exports list resources if the given mount point has some.
182 * As allocation happens lazily, it may be that it doesn't has this
183 * information, although it theorically should.
184 */
185 static void
186 nfs_export_unmount(struct mount *mp)
187 {
188 boolean_t found;
189 struct mount_netexport_pair *mnp;
190
191 KASSERT(mp != NULL);
192
193 found = FALSE;
194 CIRCLEQ_FOREACH(mnp, &mount_netexport_map, mnp_entries) {
195 if (mnp->mnp_mount == mp) {
196 found = TRUE;
197 break;
198 }
199 }
200
201 if (mp->mnt_op->vfs_vptofh == NULL || mp->mnt_op->vfs_fhtovp == NULL)
202 KASSERT(!found);
203 else if (found) {
204 if (mp->mnt_flag & MNT_EXPUBLIC)
205 setpublicfs(NULL, NULL, NULL);
206
207 CIRCLEQ_REMOVE(&mount_netexport_map, mnp, mnp_entries);
208
209 free(mnp, M_NFS_EXPORT);
210 }
211 }
212
213 /*
214 * Atomically set the NFS exports list of the given file system, replacing
215 * it with a new list of entries.
216 *
217 * Returns zero on success or an appropriate error code otherwise.
218 *
219 * Helper function for the nfssvc(2) system call (NFSSVC_SETEXPORTSLIST
220 * command).
221 */
222 int
223 mountd_set_exports_list(const struct mountd_exports_list *mel, struct proc *p)
224 {
225 boolean_t found;
226 int error;
227 #ifdef notyet
228 /* XXX: See below to see the reason why this is disabled. */
229 size_t i;
230 #endif
231 struct mount *mp;
232 struct mount_netexport_pair *mnp;
233 struct nameidata nd;
234 struct vnode *vp;
235
236 if (suser(p->p_ucred, &p->p_acflag) != 0)
237 return EPERM;
238
239 /* Lookup the file system path. */
240 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, mel->mel_path, p);
241 error = namei(&nd);
242 if (error != 0)
243 return error;
244 vp = (struct vnode *)nd.ni_vp;
245 mp = (struct mount *)vp->v_mount;
246
247 /* The selected file system may not support NFS exports, so ensure
248 * it does. */
249 if (mp->mnt_op->vfs_vptofh == NULL && mp->mnt_op->vfs_fhtovp == NULL) {
250 error = EOPNOTSUPP;
251 goto out_locked;
252 }
253 KASSERT(mp->mnt_op->vfs_vptofh != NULL &&
254 mp->mnt_op->vfs_fhtovp != NULL);
255
256 /* Mark the file system busy. */
257 error = vfs_busy(mp, LK_NOWAIT, NULL);
258 if (error != 0)
259 goto out_locked;
260
261 found = FALSE;
262 CIRCLEQ_FOREACH(mnp, &mount_netexport_map, mnp_entries) {
263 if (mnp->mnp_mount == mp) {
264 found = TRUE;
265 break;
266 }
267 }
268 if (!found) {
269 error = init_exports(mp, &mnp);
270 if (error != 0) {
271 vfs_unbusy(mp);
272 goto out_locked;
273 }
274 }
275
276 /*
277 * XXX: The part marked as 'notyet' works fine from the kernel's
278 * point of view, in the sense that it is able to atomically update
279 * the complete exports list for a file system. However, supporting
280 * this in mountd(8) requires a lot of work; so, for now, keep the
281 * old behavior of updating a single entry per call.
282 *
283 * When mountd(8) is fixed, just remove the second branch of this
284 * preprocessor conditional and enable the first one.
285 */
286 #ifdef notyet
287 clear_exports(mp, &mnp->mnp_netexport);
288 for (i = 0; error == 0 && i < mel->mel_nexports; i++)
289 error = export(mp, &mnp->mnp_netexport, &mel->mel_exports[i]);
290 #else
291 if (mel->mel_nexports == 0)
292 clear_exports(mp, &mnp->mnp_netexport);
293 else if (mel->mel_nexports == 1)
294 error = export(mp, &mnp->mnp_netexport, &mel->mel_exports[0]);
295 else {
296 printf("mountd_set_exports_list: Cannot set more than one "
297 "entry at once (unimplemented)\n");
298 error = EOPNOTSUPP;
299 }
300 #endif
301
302 vfs_unbusy(mp);
303
304 out_locked:
305 vput(vp);
306
307 return 0;
308 }
309
310 /*
311 * Check if the file system specified by the 'mp' mount structure is
312 * exported to a client with 'anon' anonymous credentials. The 'mb'
313 * argument is an mbuf containing the network address of the client.
314 * The return parameters for the export flags for the client are returned
315 * in the address specified by 'wh'.
316 *
317 * This function is used exclusively by the NFS server. It is generally
318 * invoked before VFS_FHTOVP to validate that client has access to the
319 * file system.
320 */
321 int
322 nfs_check_export(struct mount *mp, struct mbuf *mb, int *wh,
323 struct ucred **anon)
324 {
325 boolean_t found;
326 struct mount_netexport_pair *mnp;
327 struct netcred *np;
328
329 found = FALSE;
330 CIRCLEQ_FOREACH(mnp, &mount_netexport_map, mnp_entries) {
331 if (mnp->mnp_mount == mp) {
332 found = TRUE;
333 break;
334 }
335 }
336 if (!found)
337 return EACCES;
338
339 np = export_lookup(mp, &mnp->mnp_netexport, mb);
340 if (np != NULL) {
341 *wh = np->netc_exflags;
342 *anon = &np->netc_anon;
343 }
344
345 return np == NULL ? EACCES : 0;
346 }
347
348 /*
349 * INTERNAL FUNCTIONS
350 */
351
352 /*
353 * Initializes NFS exports for the file system given in 'mp' if it supports
354 * file handles; this is determined by checking whether mp's vfs_vptofh and
355 * vfs_fhtovp operations are NULL or not.
356 *
357 * If successful, returns 0 and sets *mnpp to the address of the new
358 * mount_netexport_pair item; otherwise returns and appropriate error code
359 * and *mnpp remains unmodified.
360 */
361 static int
362 init_exports(struct mount *mp, struct mount_netexport_pair **mnpp)
363 {
364 int error;
365 struct export_args ea;
366 struct mount_netexport_pair *mnp;
367
368 KASSERT(mp != NULL);
369 KASSERT(mp->mnt_op->vfs_vptofh != NULL &&
370 mp->mnt_op->vfs_fhtovp != NULL);
371
372 #ifdef DIAGNOSTIC
373 /* Ensure that we do not already have this mount point. */
374 CIRCLEQ_FOREACH(mnp, &mount_netexport_map, mnp_entries) {
375 if (mnp->mnp_mount == mp)
376 KASSERT(0);
377 }
378 #endif
379
380 mnp = (struct mount_netexport_pair *)
381 malloc(sizeof(struct mount_netexport_pair), M_NFS_EXPORT, M_WAITOK);
382 KASSERT(mnp != NULL);
383 mnp->mnp_mount = mp;
384 memset(&mnp->mnp_netexport, 0, sizeof(mnp->mnp_netexport));
385
386 /* Set the default export entry. Handled internally by export upon
387 * first call. */
388 memset(&ea, 0, sizeof(ea));
389 ea.ex_root = -2;
390 if (mp->mnt_flag & MNT_RDONLY)
391 ea.ex_flags |= MNT_EXRDONLY;
392 error = export(mp, &mnp->mnp_netexport, &ea);
393 if (error != 0)
394 free(mnp, M_NFS_EXPORT);
395 else {
396 CIRCLEQ_INSERT_TAIL(&mount_netexport_map, mnp, mnp_entries);
397 *mnpp = mnp;
398 }
399
400 return error;
401 }
402
403 /*
404 * Build hash lists of net addresses and hang them off the mount point.
405 * Called by export() to set up a new entry in the lists of export
406 * addresses.
407 */
408 static int
409 hang_addrlist(struct mount *mp, struct netexport *nep,
410 const struct export_args *argp)
411 {
412 int error, i;
413 struct netcred *np, *enp;
414 struct radix_node_head *rnh;
415 struct sockaddr *saddr, *smask;
416 struct domain *dom;
417
418 smask = NULL;
419
420 if (argp->ex_addrlen == 0) {
421 if (mp->mnt_flag & MNT_DEFEXPORTED)
422 return EPERM;
423 np = &nep->ne_defexported;
424 np->netc_exflags = argp->ex_flags;
425 crcvt(&np->netc_anon, &argp->ex_anon);
426 np->netc_anon.cr_ref = 1;
427 mp->mnt_flag |= MNT_DEFEXPORTED;
428 return 0;
429 }
430
431 if (argp->ex_addrlen > MLEN || argp->ex_masklen > MLEN)
432 return EINVAL;
433
434 i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen;
435 np = (struct netcred *)malloc(i, M_NETADDR, M_WAITOK);
436 memset((caddr_t)np, 0, i);
437 saddr = (struct sockaddr *)(np + 1);
438 error = copyin(argp->ex_addr, (caddr_t)saddr, argp->ex_addrlen);
439 if (error)
440 goto out;
441 if (saddr->sa_len > argp->ex_addrlen)
442 saddr->sa_len = argp->ex_addrlen;
443 if (sacheck(saddr) == -1)
444 return EINVAL;
445 if (argp->ex_masklen) {
446 smask = (struct sockaddr *)((caddr_t)saddr + argp->ex_addrlen);
447 error = copyin(argp->ex_mask, (caddr_t)smask, argp->ex_masklen);
448 if (error)
449 goto out;
450 if (smask->sa_len > argp->ex_masklen)
451 smask->sa_len = argp->ex_masklen;
452 if (smask->sa_family != saddr->sa_family)
453 return EINVAL;
454 if (sacheck(smask) == -1)
455 return EINVAL;
456 }
457 i = saddr->sa_family;
458 if ((rnh = nep->ne_rtable[i]) == 0) {
459 /*
460 * Seems silly to initialize every AF when most are not
461 * used, do so on demand here
462 */
463 DOMAIN_FOREACH(dom) {
464 if (dom->dom_family == i && dom->dom_rtattach) {
465 dom->dom_rtattach((void **)&nep->ne_rtable[i],
466 dom->dom_rtoffset);
467 break;
468 }
469 }
470 if ((rnh = nep->ne_rtable[i]) == 0) {
471 error = ENOBUFS;
472 goto out;
473 }
474 }
475
476 enp = (struct netcred *)(*rnh->rnh_addaddr)(saddr, smask, rnh,
477 np->netc_rnodes);
478 if (enp != np) {
479 if (enp == NULL) {
480 enp = (struct netcred *)(*rnh->rnh_lookup)(saddr,
481 smask, rnh);
482 if (enp == NULL) {
483 error = EPERM;
484 goto out;
485 }
486 } else
487 enp->netc_refcnt++;
488
489 goto check;
490 } else
491 enp->netc_refcnt = 1;
492
493 np->netc_exflags = argp->ex_flags;
494 crcvt(&np->netc_anon, &argp->ex_anon);
495 np->netc_anon.cr_ref = 1;
496 return 0;
497 check:
498 if (enp->netc_exflags != argp->ex_flags ||
499 crcmp(&enp->netc_anon, &argp->ex_anon) != 0)
500 error = EPERM;
501 else
502 error = 0;
503 out:
504 free(np, M_NETADDR);
505 return error;
506 }
507
508 /*
509 * Ensure that the address stored in 'sa' is valid.
510 * Returns zero on success, otherwise -1.
511 */
512 static int
513 sacheck(struct sockaddr *sa)
514 {
515
516 switch (sa->sa_family) {
517 #ifdef INET
518 case AF_INET: {
519 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
520 char *p = (char *)sin->sin_zero;
521 size_t i;
522
523 if (sin->sin_len != sizeof(*sin))
524 return -1;
525 if (sin->sin_port != 0)
526 return -1;
527 for (i = 0; i < sizeof(sin->sin_zero); i++)
528 if (*p++ != '\0')
529 return -1;
530 return 0;
531 }
532 #endif
533 #ifdef INET6
534 case AF_INET6: {
535 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
536
537 if (sin6->sin6_len != sizeof(*sin6))
538 return -1;
539 if (sin6->sin6_port != 0)
540 return -1;
541 return 0;
542 }
543 #endif
544 default:
545 return -1;
546 }
547 }
548
549 /*
550 * Free the netcred object pointed to by the 'rn' radix node.
551 * 'w' holds a pointer to the radix tree head.
552 */
553 static int
554 free_netcred(struct radix_node *rn, void *w)
555 {
556 struct radix_node_head *rnh = (struct radix_node_head *)w;
557 struct netcred *np = (struct netcred *)(void *)rn;
558
559 (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh);
560 if (--(np->netc_refcnt) <= 0)
561 free(np, M_NETADDR);
562 return 0;
563 }
564
565 /*
566 * Clears the exports list for a given file system.
567 */
568 static void
569 clear_exports(struct mount *mp, struct netexport *nep)
570 {
571 int i;
572 struct radix_node_head *rnh;
573
574 if (mp->mnt_flag & MNT_EXPUBLIC) {
575 setpublicfs(NULL, NULL, NULL);
576 mp->mnt_flag &= ~MNT_EXPUBLIC;
577 }
578
579 for (i = 0; i <= AF_MAX; i++) {
580 if ((rnh = nep->ne_rtable[i]) != NULL) {
581 (*rnh->rnh_walktree)(rnh, free_netcred, rnh);
582 free((caddr_t)rnh, M_RTABLE);
583 nep->ne_rtable[i] = 0;
584 }
585 }
586
587 mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED);
588 }
589
590 /*
591 * Add a new export entry (described by an export_args structure) to the
592 * given file system.
593 */
594 static int
595 export(struct mount *mp, struct netexport *nep, const struct export_args *argp)
596 {
597 int error;
598
599 if (argp->ex_flags & MNT_EXPORTED) {
600 if (argp->ex_flags & MNT_EXPUBLIC) {
601 if ((error = setpublicfs(mp, nep, argp)) != 0)
602 return error;
603 mp->mnt_flag |= MNT_EXPUBLIC;
604 }
605 if ((error = hang_addrlist(mp, nep, argp)) != 0)
606 return error;
607 mp->mnt_flag |= MNT_EXPORTED;
608 }
609 return 0;
610 }
611
612 /*
613 * Set the publicly exported filesystem (WebNFS). Currently, only
614 * one public filesystem is possible in the spec (RFC 2054 and 2055)
615 */
616 static int
617 setpublicfs(struct mount *mp, struct netexport *nep,
618 const struct export_args *argp)
619 {
620 char *cp;
621 int error;
622 struct vnode *rvp;
623
624 /*
625 * mp == NULL -> invalidate the current info, the FS is
626 * no longer exported. May be called from either export
627 * or unmount, so check if it hasn't already been done.
628 */
629 if (mp == NULL) {
630 if (nfs_pub.np_valid) {
631 nfs_pub.np_valid = 0;
632 if (nfs_pub.np_index != NULL) {
633 FREE(nfs_pub.np_index, M_TEMP);
634 nfs_pub.np_index = NULL;
635 }
636 }
637 return 0;
638 }
639
640 /*
641 * Only one allowed at a time.
642 */
643 if (nfs_pub.np_valid != 0 && mp != nfs_pub.np_mount)
644 return EBUSY;
645
646 /*
647 * Get real filehandle for root of exported FS.
648 */
649 memset((caddr_t)&nfs_pub.np_handle, 0, sizeof(nfs_pub.np_handle));
650 nfs_pub.np_handle.fh_fsid = mp->mnt_stat.f_fsidx;
651
652 if ((error = VFS_ROOT(mp, &rvp)))
653 return error;
654
655 if ((error = VFS_VPTOFH(rvp, &nfs_pub.np_handle.fh_fid)))
656 return error;
657
658 vput(rvp);
659
660 /*
661 * If an indexfile was specified, pull it in.
662 */
663 if (argp->ex_indexfile != NULL) {
664 MALLOC(nfs_pub.np_index, char *, MAXNAMLEN + 1, M_TEMP,
665 M_WAITOK);
666 error = copyinstr(argp->ex_indexfile, nfs_pub.np_index,
667 MAXNAMLEN, (size_t *)0);
668 if (!error) {
669 /*
670 * Check for illegal filenames.
671 */
672 for (cp = nfs_pub.np_index; *cp; cp++) {
673 if (*cp == '/') {
674 error = EINVAL;
675 break;
676 }
677 }
678 }
679 if (error) {
680 FREE(nfs_pub.np_index, M_TEMP);
681 return error;
682 }
683 }
684
685 nfs_pub.np_mount = mp;
686 nfs_pub.np_valid = 1;
687 return 0;
688 }
689
690 /*
691 * Lookup an export entry in the exports list that matches the address
692 * stored in 'nam'. If no entry is found, the default one is used instead
693 * (if available).
694 */
695 static struct netcred *
696 export_lookup(struct mount *mp, struct netexport *nep, struct mbuf *nam)
697 {
698 struct netcred *np;
699 struct radix_node_head *rnh;
700 struct sockaddr *saddr;
701
702 np = NULL;
703 if (mp->mnt_flag & MNT_EXPORTED) {
704 /*
705 * Lookup in the export list first.
706 */
707 if (nam != NULL) {
708 saddr = mtod(nam, struct sockaddr *);
709 rnh = nep->ne_rtable[saddr->sa_family];
710 if (rnh != NULL) {
711 np = (struct netcred *)
712 (*rnh->rnh_matchaddr)((caddr_t)saddr,
713 rnh);
714 if (np && np->netc_rnodes->rn_flags & RNF_ROOT)
715 np = NULL;
716 }
717 }
718 /*
719 * If no address match, use the default if it exists.
720 */
721 if (np == NULL && mp->mnt_flag & MNT_DEFEXPORTED)
722 np = &nep->ne_defexported;
723 }
724 return np;
725 }
726