11541Srgrimes/*-
21541Srgrimes * Copyright (c) 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes * (c) UNIX System Laboratories, Inc.
551138Salfred * All or some portions of this file are derived from material licensed
6191675Sjamie * to the University of California by American Telephone and Telegraph
71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
81541Srgrimes * the permission of UNIX System Laboratories, Inc.
91541Srgrimes *
1064002Speter * Redistribution and use in source and binary forms, with or without
111541Srgrimes * modification, are permitted provided that the following conditions
121541Srgrimes * are met:
131541Srgrimes * 1. Redistributions of source code must retain the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer.
151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161541Srgrimes *    notice, this list of conditions and the following disclaimer in the
171541Srgrimes *    documentation and/or other materials provided with the distribution.
181541Srgrimes * 4. Neither the name of the University nor the names of its contributors
191541Srgrimes *    may be used to endorse or promote products derived from this software
201541Srgrimes *    without specific prior written permission.
211541Srgrimes *
221541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27171210Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321541Srgrimes * SUCH DAMAGE.
331541Srgrimes *
341541Srgrimes *	@(#)vfs_subr.c	8.31 (Berkeley) 5/26/95
351541Srgrimes */
361541Srgrimes
371541Srgrimes#include <sys/cdefs.h>
381541Srgrimes__FBSDID("$FreeBSD$");
391541Srgrimes
401541Srgrimes#include <sys/param.h>
411541Srgrimes#include <sys/dirent.h>
421541Srgrimes#include <sys/domain.h>
431541Srgrimes#include <sys/jail.h>
441541Srgrimes#include <sys/kernel.h>
451541Srgrimes#include <sys/lock.h>
461541Srgrimes#include <sys/malloc.h>
471541Srgrimes#include <sys/mbuf.h>
481541Srgrimes#include <sys/mount.h>
491541Srgrimes#include <sys/mutex.h>
501541Srgrimes#include <sys/rwlock.h>
511541Srgrimes#include <sys/refcount.h>
521541Srgrimes#include <sys/signalvar.h>
531541Srgrimes#include <sys/socket.h>
541541Srgrimes#include <sys/systm.h>
5552150Smarcel#include <sys/vnode.h>
561541Srgrimes
5752150Smarcel#include <net/radix.h>
581541Srgrimes
591541Srgrimesstatic MALLOC_DEFINE(M_NETADDR, "export_host", "Export host address structure");
601541Srgrimes
6152150Smarcelstatic void	vfs_free_addrlist(struct netexport *nep);
621541Srgrimesstatic int	vfs_free_netcred(struct radix_node *rn, void *w);
631541Srgrimesstatic int	vfs_hang_addrlist(struct mount *mp, struct netexport *nep,
641541Srgrimes		    struct export_args *argp);
651541Srgrimesstatic struct netcred *vfs_export_lookup(struct mount *, struct sockaddr *);
661541Srgrimes
671541Srgrimes/*
681541Srgrimes * Network address lookup element
691541Srgrimes */
701541Srgrimesstruct netcred {
711541Srgrimes	struct	radix_node netc_rnodes[2];
721541Srgrimes	int	netc_exflags;
731541Srgrimes	struct	ucred *netc_anon;
741541Srgrimes	int	netc_numsecflavors;
751541Srgrimes	int	netc_secflavors[MAXSECFLAVORS];
761541Srgrimes};
771541Srgrimes
781541Srgrimes/*
791541Srgrimes * Network export information
801541Srgrimes */
811541Srgrimesstruct netexport {
821541Srgrimes	struct	netcred ne_defexported;		      /* Default export */
831541Srgrimes	struct	radix_node_head *ne_rtable[AF_MAX+1]; /* Individual exports */
841541Srgrimes};
851541Srgrimes
861541Srgrimes/*
871541Srgrimes * Build hash lists of net addresses and hang them off the mount point.
881541Srgrimes * Called by vfs_export() to set up the lists of export addresses.
891541Srgrimes */
901541Srgrimesstatic int
911541Srgrimesvfs_hang_addrlist(struct mount *mp, struct netexport *nep,
921541Srgrimes    struct export_args *argp)
931541Srgrimes{
941541Srgrimes	register struct netcred *np;
951541Srgrimes	register struct radix_node_head *rnh;
961541Srgrimes	register int i;
971541Srgrimes	struct radix_node *rn;
981541Srgrimes	struct sockaddr *saddr, *smask = 0;
991541Srgrimes	struct domain *dom;
1001541Srgrimes	int error;
1011541Srgrimes
1021541Srgrimes	/*
1031541Srgrimes	 * XXX: This routine converts from a `struct xucred'
1041541Srgrimes	 * (argp->ex_anon) to a `struct ucred' (np->netc_anon).  This
1051541Srgrimes	 * operation is questionable; for example, what should be done
1061541Srgrimes	 * with fields like cr_uidinfo and cr_prison?  Currently, this
1071541Srgrimes	 * routine does not touch them (leaves them as NULL).
1081541Srgrimes	 */
1091541Srgrimes	if (argp->ex_anon.cr_version != XUCRED_VERSION) {
110105950Speter		vfs_mount_error(mp, "ex_anon.cr_version: %d != %d",
1111541Srgrimes		    argp->ex_anon.cr_version, XUCRED_VERSION);
1121541Srgrimes		return (EINVAL);
1131541Srgrimes	}
1141541Srgrimes
1151541Srgrimes	if (argp->ex_addrlen == 0) {
1161541Srgrimes		if (mp->mnt_flag & MNT_DEFEXPORTED) {
1171541Srgrimes			vfs_mount_error(mp,
11852150Smarcel			    "MNT_DEFEXPORTED already set for mount %p", mp);
1191541Srgrimes			return (EPERM);
1201541Srgrimes		}
1211541Srgrimes		np = &nep->ne_defexported;
1221541Srgrimes		np->netc_exflags = argp->ex_flags;
1231541Srgrimes		np->netc_anon = crget();
1241541Srgrimes		np->netc_anon->cr_uid = argp->ex_anon.cr_uid;
1251541Srgrimes		crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups,
1261541Srgrimes		    argp->ex_anon.cr_groups);
1271541Srgrimes		np->netc_anon->cr_prison = &prison0;
1281541Srgrimes		prison_hold(np->netc_anon->cr_prison);
1291541Srgrimes		np->netc_numsecflavors = argp->ex_numsecflavors;
1301541Srgrimes		bcopy(argp->ex_secflavors, np->netc_secflavors,
1311541Srgrimes		    sizeof(np->netc_secflavors));
1328019Sache		MNT_ILOCK(mp);
1338019Sache		mp->mnt_flag |= MNT_DEFEXPORTED;
1341541Srgrimes		MNT_IUNLOCK(mp);
1351541Srgrimes		return (0);
1361541Srgrimes	}
1371541Srgrimes
1381541Srgrimes#if MSIZE <= 256
1391541Srgrimes	if (argp->ex_addrlen > MLEN) {
1401541Srgrimes		vfs_mount_error(mp, "ex_addrlen %d is greater than %d",
1411541Srgrimes		    argp->ex_addrlen, MLEN);
1421541Srgrimes		return (EINVAL);
1431541Srgrimes	}
1441541Srgrimes#endif
1451541Srgrimes
1461541Srgrimes	i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen;
1471541Srgrimes	np = (struct netcred *) malloc(i, M_NETADDR, M_WAITOK | M_ZERO);
1481541Srgrimes	saddr = (struct sockaddr *) (np + 1);
1491541Srgrimes	if ((error = copyin(argp->ex_addr, saddr, argp->ex_addrlen)))
1501541Srgrimes		goto out;
1511541Srgrimes	if (saddr->sa_family == AF_UNSPEC || saddr->sa_family > AF_MAX) {
1521541Srgrimes		error = EINVAL;
1531541Srgrimes		vfs_mount_error(mp, "Invalid saddr->sa_family: %d");
1541541Srgrimes		goto out;
1551541Srgrimes	}
1561541Srgrimes	if (saddr->sa_len > argp->ex_addrlen)
157177634Sdfr		saddr->sa_len = argp->ex_addrlen;
1581541Srgrimes	if (argp->ex_masklen) {
1591541Srgrimes		smask = (struct sockaddr *)((caddr_t)saddr + argp->ex_addrlen);
160171210Speter		error = copyin(argp->ex_mask, smask, argp->ex_masklen);
161171210Speter		if (error)
162127891Sdfr			goto out;
1631541Srgrimes		if (smask->sa_len > argp->ex_masklen)
164184790Sed			smask->sa_len = argp->ex_masklen;
165184790Sed	}
166184790Sed	i = saddr->sa_family;
1671549Srgrimes	if ((rnh = nep->ne_rtable[i]) == NULL) {
1682442Sdg		/*
1692729Sdfr		 * Seems silly to initialize every AF when most are not used,
1702729Sdfr		 * do so on demand here
1711541Srgrimes		 */
172171210Speter		for (dom = domains; dom; dom = dom->dom_next) {
173171210Speter			KASSERT(((i == AF_INET) || (i == AF_INET6)),
174178888Sjulian			    ("unexpected protocol in vfs_hang_addrlist"));
1752297Swollman			if (dom->dom_family == i && dom->dom_rtattach) {
1761541Srgrimes				/*
1771541Srgrimes				 * XXX MRT
1781541Srgrimes				 * The INET and INET6 domains know the
1791541Srgrimes				 * offset already. We don't need to send it
1801541Srgrimes				 * So we just use it as a flag to say that
1811541Srgrimes				 * we are or are not setting up a real routing
1821541Srgrimes				 * table. Only IP and IPV6 need have this
1831541Srgrimes				 * be 0 so all other protocols can stay the
1841541Srgrimes				 * same (ABI compatible).
1851541Srgrimes				 */
1861541Srgrimes				dom->dom_rtattach(
187171210Speter				    (void **) &nep->ne_rtable[i], 0);
1881541Srgrimes				break;
189171210Speter			}
190171210Speter		}
191171210Speter		if ((rnh = nep->ne_rtable[i]) == NULL) {
1921541Srgrimes			error = ENOBUFS;
1931541Srgrimes			vfs_mount_error(mp, "%s %s %d",
1941541Srgrimes			    "Unable to initialize radix node head ",
19535938Sdyson			    "for address family", i);
19635938Sdyson			goto out;
19728400Speter		}
19829349Speter	}
19912865Speter	RADIX_NODE_HEAD_LOCK(rnh);
20012865Speter	rn = (*rnh->rnh_addaddr)(saddr, smask, rnh, np->netc_rnodes);
20112865Speter	RADIX_NODE_HEAD_UNLOCK(rnh);
20212865Speter	if (rn == NULL || np != (struct netcred *)rn) {	/* already exists */
20312865Speter		error = EPERM;
20412865Speter		vfs_mount_error(mp, "Invalid radix node head, rn: %p %p",
20512865Speter		    rn, np);
20612865Speter		goto out;
20712865Speter	}
20812865Speter	np->netc_exflags = argp->ex_flags;
20912865Speter	np->netc_anon = crget();
21025582Speter	np->netc_anon->cr_uid = argp->ex_anon.cr_uid;
21125582Speter	crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups,
21225582Speter	    argp->ex_anon.cr_groups);
213156138Sdavidxu	np->netc_anon->cr_prison = &prison0;
214156138Sdavidxu	prison_hold(np->netc_anon->cr_prison);
215156138Sdavidxu	np->netc_numsecflavors = argp->ex_numsecflavors;
216156138Sdavidxu	bcopy(argp->ex_secflavors, np->netc_secflavors,
217156138Sdavidxu	    sizeof(np->netc_secflavors));
21825582Speter	return (0);
219137875Smarksout:
22014220Speter	free(np, M_NETADDR);
22114220Speter	return (error);
22229349Speter}
22324452Speter
22424440Speter/* Helper for vfs_free_addrlist. */
225151868Sdavidxu/* ARGSUSED */
226151868Sdavidxustatic int
227151868Sdavidxuvfs_free_netcred(struct radix_node *rn, void *w)
22835938Sdyson{
22935938Sdyson	struct radix_node_head *rnh = (struct radix_node_head *) w;
23035938Sdyson	struct ucred *cred;
23135938Sdyson
23235938Sdyson	(*rnh->rnh_deladdr) (rn->rn_key, rn->rn_mask, rnh);
23335938Sdyson	cred = ((struct netcred *)rn)->netc_anon;
23435938Sdyson	if (cred != NULL)
23535938Sdyson		crfree(cred);
236147814Sjhb	free(rn, M_NETADDR);
237147814Sjhb	return (0);
238171210Speter}
23951138Salfred
24051138Salfred/*
24125537Sdfr * Free the net address hash lists that are hanging off the mount points.
24225537Sdfr */
24325537Sdfrstatic void
24425537Sdfrvfs_free_addrlist(struct netexport *nep)
24525537Sdfr{
24625537Sdfr	int i;
24725537Sdfr	struct radix_node_head *rnh;
24825537Sdfr	struct ucred *cred;
24925537Sdfr
25025537Sdfr	for (i = 0; i <= AF_MAX; i++) {
25128400Speter		if ((rnh = nep->ne_rtable[i])) {
25256115Speter			RADIX_NODE_HEAD_LOCK(rnh);
25356115Speter			(*rnh->rnh_walktree) (rnh, vfs_free_netcred, rnh);
25436034Speter			RADIX_NODE_HEAD_UNLOCK(rnh);
25526671Sdyson			RADIX_NODE_HEAD_DESTROY(rnh);
25626671Sdyson			free(rnh, M_RTABLE);
25726671Sdyson			nep->ne_rtable[i] = NULL;	/* not SMP safe XXX */
25826671Sdyson		}
259151868Sdavidxu	}
260151868Sdavidxu	cred = nep->ne_defexported.netc_anon;
261151868Sdavidxu	if (cred != NULL)
26226671Sdyson		crfree(cred);
26369514Sjake
26469514Sjake}
26526671Sdyson
26626671Sdyson/*
26729391Sphk * High level function to manipulate export options on a mount point
26834925Sdufault * and the passed in netexport.
26934925Sdufault * Struct export_args *argp is the variable used to twiddle options,
27034925Sdufault * the structure is described in sys/mount.h
27134925Sdufault */
27234925Sdufaultint
27334925Sdufaultvfs_export(struct mount *mp, struct export_args *argp)
27434925Sdufault{
27534925Sdufault	struct netexport *nep;
27635938Sdyson	int error;
277171210Speter
27841089Speter	if (argp->ex_numsecflavors < 0
27946155Sphk	    || argp->ex_numsecflavors >= MAXSECFLAVORS)
28051791Smarcel		return (EINVAL);
28151791Smarcel
282171210Speter	error = 0;
28351791Smarcel	lockmgr(&mp->mnt_explock, LK_EXCLUSIVE, NULL);
284171210Speter	nep = mp->mnt_export;
285112895Sjeff	if (argp->ex_flags & MNT_DELEXPORT) {
286112895Sjeff		if (nep == NULL) {
28756271Srwatson			error = ENOENT;
28856271Srwatson			goto out;
28956271Srwatson		}
29056271Srwatson		if (mp->mnt_flag & MNT_EXPUBLIC) {
29156271Srwatson			vfs_setpublicfs(NULL, NULL, NULL);
29256271Srwatson			MNT_ILOCK(mp);
29356271Srwatson			mp->mnt_flag &= ~MNT_EXPUBLIC;
29456271Srwatson			MNT_IUNLOCK(mp);
29554803Srwatson		}
29654803Srwatson		vfs_free_addrlist(nep);
29754803Srwatson		mp->mnt_export = NULL;
29854803Srwatson		free(nep, M_MOUNT);
29955943Sjasone		nep = NULL;
30056115Speter		MNT_ILOCK(mp);
30156115Speter		mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED);
30259288Sjlemon		MNT_IUNLOCK(mp);
30359288Sjlemon	}
30475039Srwatson	if (argp->ex_flags & MNT_EXPORTED) {
30575039Srwatson		if (nep == NULL) {
30675039Srwatson			nep = malloc(sizeof(struct netexport), M_MOUNT, M_WAITOK | M_ZERO);
30775427Srwatson			mp->mnt_export = nep;
30883652Speter		}
30983796Srwatson		if (argp->ex_flags & MNT_EXPUBLIC) {
31085891Sphk			if ((error = vfs_setpublicfs(mp, nep, argp)) != 0)
311100897Srwatson				goto out;
312100897Srwatson			MNT_ILOCK(mp);
313100897Srwatson			mp->mnt_flag |= MNT_EXPUBLIC;
314100897Srwatson			MNT_IUNLOCK(mp);
315100897Srwatson		}
316100897Srwatson		if ((error = vfs_hang_addrlist(mp, nep, argp)))
31794936Smux			goto out;
31896084Smux		MNT_ILOCK(mp);
31997372Smarcel		mp->mnt_flag |= MNT_EXPORTED;
32099856Salfred		MNT_IUNLOCK(mp);
321101426Srwatson	}
322122540Smckusick
323122540Smckusickout:
324122540Smckusick	lockmgr(&mp->mnt_explock, LK_RELEASE, NULL);
325122540Smckusick	/*
326103575Salfred	 * Once we have executed the vfs_export() command, we do
327103575Salfred	 * not want to keep the "export" option around in the
328103575Salfred	 * options list, since that will cause subsequent MNT_UPDATE
329103575Salfred	 * calls to fail.  The export information is saved in
330103575Salfred	 * mp->mnt_export, so we can safely delete the "export" mount option
331103575Salfred	 * here.
332103575Salfred	 */
333103575Salfred	vfs_deleteopt(mp->mnt_optnew, "export");
334103575Salfred	vfs_deleteopt(mp->mnt_opt, "export");
335105692Srwatson	return (error);
336105692Srwatson}
337105692Srwatson
338104731Srwatson/*
339104731Srwatson * Set the publicly exported filesystem (WebNFS). Currently, only
340104731Srwatson * one public filesystem is possible in the spec (RFC 2054 and 2055)
341106467Srwatson */
342105950Speterint
343105950Spetervfs_setpublicfs(struct mount *mp, struct netexport *nep,
344106978Sdeischen    struct export_args *argp)
345106978Sdeischen{
346106978Sdeischen	int error;
347107914Sdillon	struct vnode *rvp;
348108406Srwatson	char *cp;
349108406Srwatson
350108406Srwatson	/*
351108406Srwatson	 * mp == NULL -> invalidate the current info, the FS is
352112895Sjeff	 * no longer exported. May be called from either vfs_export
353112902Sjeff	 * or unmount, so check if it hasn't already been done.
354112902Sjeff	 */
355112902Sjeff	if (mp == NULL) {
356112902Sjeff		if (nfs_pub.np_valid) {
357112909Sjeff			nfs_pub.np_valid = 0;
358112909Sjeff			if (nfs_pub.np_index != NULL) {
359113276Smike				free(nfs_pub.np_index, M_TEMP);
360115800Srwatson				nfs_pub.np_index = NULL;
361115800Srwatson			}
362115800Srwatson		}
363125369Sdeischen		return (0);
364127484Smtm	}
365127484Smtm
366132117Sphk	/*
367136831Srwatson	 * Only one allowed at a time.
368136831Srwatson	 */
369136831Srwatson	if (nfs_pub.np_valid != 0 && mp != nfs_pub.np_mount)
370136831Srwatson		return (EBUSY);
371136831Srwatson
372136831Srwatson	/*
373136831Srwatson	 * Get real filehandle for root of exported FS.
374136831Srwatson	 */
375136831Srwatson	bzero(&nfs_pub.np_handle, sizeof(nfs_pub.np_handle));
376139013Sdavidxu	nfs_pub.np_handle.fh_fsid = mp->mnt_stat.f_fsid;
377145435Sdavidxu
378151317Sdavidxu	if ((error = VFS_ROOT(mp, LK_EXCLUSIVE, &rvp)))
379156138Sdavidxu		return (error);
380156138Sdavidxu
381156138Sdavidxu	if ((error = VOP_VPTOFH(rvp, &nfs_pub.np_handle.fh_fid)))
382156138Sdavidxu		return (error);
383156138Sdavidxu
384156138Sdavidxu	vput(rvp);
385153681Sphk
386155328Sdavidxu	/*
387157039Sdavidxu	 * If an indexfile was specified, pull it in.
388162498Sdavidxu	 */
389163953Srrs	if (argp->ex_indexfile != NULL) {
390163953Srrs		if (nfs_pub.np_index != NULL)
391163953Srrs			nfs_pub.np_index = malloc(MAXNAMLEN + 1, M_TEMP,
392163953Srrs			    M_WAITOK);
393171210Speter		error = copyinstr(argp->ex_indexfile, nfs_pub.np_index,
394171210Speter		    MAXNAMLEN, (size_t *)0);
395171210Speter		if (!error) {
396171210Speter			/*
397171210Speter			 * Check for illegal filenames.
398171210Speter			 */
399171861Sdavidxu			for (cp = nfs_pub.np_index; *cp; cp++) {
400175165Sjhb				if (*cp == '/') {
401175165Sjhb					error = EINVAL;
402176731Sjeff					break;
403176731Sjeff				}
404176731Sjeff			}
405176731Sjeff		}
406176731Sjeff		if (error) {
407177790Skib			free(nfs_pub.np_index, M_TEMP);
408177790Skib			nfs_pub.np_index = NULL;
409177790Skib			return (error);
410177790Skib		}
411177790Skib	}
412177790Skib
413177790Skib	nfs_pub.np_mount = mp;
414177790Skib	nfs_pub.np_valid = 1;
415177790Skib	return (0);
416177790Skib}
417177790Skib
418177790Skib/*
419177790Skib * Used by the filesystems to determine if a given network address
420177790Skib * (passed in 'nam') is present in their exports list, returns a pointer
421177790Skib * to struct netcred so that the filesystem can examine it for
422181905Sed * access rights (read/write/etc).
423184589Sdfr */
424191675Sjamiestatic struct netcred *
425191675Sjamievfs_export_lookup(struct mount *mp, struct sockaddr *nam)
426191675Sjamie{
427191675Sjamie	struct netexport *nep;
428	register struct netcred *np;
429	register struct radix_node_head *rnh;
430	struct sockaddr *saddr;
431
432	nep = mp->mnt_export;
433	if (nep == NULL)
434		return (NULL);
435	np = NULL;
436	if (mp->mnt_flag & MNT_EXPORTED) {
437		/*
438		 * Lookup in the export list first.
439		 */
440		if (nam != NULL) {
441			saddr = nam;
442			rnh = nep->ne_rtable[saddr->sa_family];
443			if (rnh != NULL) {
444				RADIX_NODE_HEAD_RLOCK(rnh);
445				np = (struct netcred *)
446				    (*rnh->rnh_matchaddr)(saddr, rnh);
447				RADIX_NODE_HEAD_RUNLOCK(rnh);
448				if (np && np->netc_rnodes->rn_flags & RNF_ROOT)
449					np = NULL;
450			}
451		}
452		/*
453		 * If no address match, use the default if it exists.
454		 */
455		if (np == NULL && mp->mnt_flag & MNT_DEFEXPORTED)
456			np = &nep->ne_defexported;
457	}
458	return (np);
459}
460
461/*
462 * XXX: This comment comes from the deprecated ufs_check_export()
463 * XXX: and may not entirely apply, but lacking something better:
464 * This is the generic part of fhtovp called after the underlying
465 * filesystem has validated the file handle.
466 *
467 * Verify that a host should have access to a filesystem.
468 */
469
470int
471vfs_stdcheckexp(struct mount *mp, struct sockaddr *nam, int *extflagsp,
472    struct ucred **credanonp, int *numsecflavors, int **secflavors)
473{
474	struct netcred *np;
475
476	lockmgr(&mp->mnt_explock, LK_SHARED, NULL);
477	np = vfs_export_lookup(mp, nam);
478	if (np == NULL) {
479		lockmgr(&mp->mnt_explock, LK_RELEASE, NULL);
480		*credanonp = NULL;
481		return (EACCES);
482	}
483	*extflagsp = np->netc_exflags;
484	if ((*credanonp = np->netc_anon) != NULL)
485		crhold(*credanonp);
486	if (numsecflavors)
487		*numsecflavors = np->netc_numsecflavors;
488	if (secflavors)
489		*secflavors = np->netc_secflavors;
490	lockmgr(&mp->mnt_explock, LK_RELEASE, NULL);
491	return (0);
492}
493
494