1a9148abdSDoug Rabson /*- 2d4468577SJamie Gritton * Copyright (c) 1989, 1993 3d4468577SJamie Gritton * The Regents of the University of California. All rights reserved. 4d4468577SJamie Gritton * (c) UNIX System Laboratories, Inc. 5d4468577SJamie Gritton * All or some portions of this file are derived from material licensed 6d4468577SJamie Gritton * to the University of California by American Telephone and Telegraph 7d4468577SJamie Gritton * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8d4468577SJamie Gritton * the permission of UNIX System Laboratories, Inc. 9a9148abdSDoug Rabson * 10a9148abdSDoug Rabson * Redistribution and use in source and binary forms, with or without 11a9148abdSDoug Rabson * modification, are permitted provided that the following conditions 12a9148abdSDoug Rabson * are met: 13a9148abdSDoug Rabson * 1. Redistributions of source code must retain the above copyright 14a9148abdSDoug Rabson * notice, this list of conditions and the following disclaimer. 15a9148abdSDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 16a9148abdSDoug Rabson * notice, this list of conditions and the following disclaimer in the 17a9148abdSDoug Rabson * documentation and/or other materials provided with the distribution. 18d4468577SJamie Gritton * 4. Neither the name of the University nor the names of its contributors 19d4468577SJamie Gritton * may be used to endorse or promote products derived from this software 20d4468577SJamie Gritton * without specific prior written permission. 21a9148abdSDoug Rabson * 22d4468577SJamie Gritton * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23a9148abdSDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24a9148abdSDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25d4468577SJamie Gritton * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26a9148abdSDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27a9148abdSDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28a9148abdSDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29a9148abdSDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30a9148abdSDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31a9148abdSDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32a9148abdSDoug Rabson * SUCH DAMAGE. 33d4468577SJamie Gritton * 34d4468577SJamie Gritton * @(#)vfs_subr.c 8.31 (Berkeley) 5/26/95 35a9148abdSDoug Rabson */ 36a9148abdSDoug Rabson 37a9148abdSDoug Rabson #include <sys/cdefs.h> 38a9148abdSDoug Rabson __FBSDID("$FreeBSD$"); 39a9148abdSDoug Rabson 40a9148abdSDoug Rabson #include <sys/param.h> 41d4468577SJamie Gritton #include <sys/dirent.h> 42d4468577SJamie Gritton #include <sys/domain.h> 43ae883d55SRick Macklem #include <sys/jail.h> 44a9148abdSDoug Rabson #include <sys/kernel.h> 45a9148abdSDoug Rabson #include <sys/lock.h> 46a9148abdSDoug Rabson #include <sys/malloc.h> 47a9148abdSDoug Rabson #include <sys/mbuf.h> 48d4468577SJamie Gritton #include <sys/mount.h> 49a9148abdSDoug Rabson #include <sys/mutex.h> 50d4468577SJamie Gritton #include <sys/rwlock.h> 51d4468577SJamie Gritton #include <sys/refcount.h> 52d4468577SJamie Gritton #include <sys/socket.h> 53d4468577SJamie Gritton #include <sys/systm.h> 54d4468577SJamie Gritton #include <sys/vnode.h> 55a9148abdSDoug Rabson 56d4468577SJamie Gritton #include <net/radix.h> 57a9148abdSDoug Rabson 58d4468577SJamie Gritton static MALLOC_DEFINE(M_NETADDR, "export_host", "Export host address structure"); 59a9148abdSDoug Rabson 60d4468577SJamie Gritton static void vfs_free_addrlist(struct netexport *nep); 61d4468577SJamie Gritton static int vfs_free_netcred(struct radix_node *rn, void *w); 62d4468577SJamie Gritton static int vfs_hang_addrlist(struct mount *mp, struct netexport *nep, 63d4468577SJamie Gritton struct export_args *argp); 64d4468577SJamie Gritton static struct netcred *vfs_export_lookup(struct mount *, struct sockaddr *); 65a9148abdSDoug Rabson 66a9148abdSDoug Rabson /* 67d4468577SJamie Gritton * Network address lookup element 68a9148abdSDoug Rabson */ 69d4468577SJamie Gritton struct netcred { 70d4468577SJamie Gritton struct radix_node netc_rnodes[2]; 71d4468577SJamie Gritton int netc_exflags; 72d4468577SJamie Gritton struct ucred *netc_anon; 73d4468577SJamie Gritton int netc_numsecflavors; 74d4468577SJamie Gritton int netc_secflavors[MAXSECFLAVORS]; 75a9148abdSDoug Rabson }; 76a9148abdSDoug Rabson 77a9148abdSDoug Rabson /* 78d4468577SJamie Gritton * Network export information 79a9148abdSDoug Rabson */ 80d4468577SJamie Gritton struct netexport { 81d4468577SJamie Gritton struct netcred ne_defexported; /* Default export */ 82d4468577SJamie Gritton struct radix_node_head *ne_rtable[AF_MAX+1]; /* Individual exports */ 83d4468577SJamie Gritton }; 84a9148abdSDoug Rabson 85a9148abdSDoug Rabson /* 86d4468577SJamie Gritton * Build hash lists of net addresses and hang them off the mount point. 87d4468577SJamie Gritton * Called by vfs_export() to set up the lists of export addresses. 88a9148abdSDoug Rabson */ 89a9148abdSDoug Rabson static int 90d4468577SJamie Gritton vfs_hang_addrlist(struct mount *mp, struct netexport *nep, 91d4468577SJamie Gritton struct export_args *argp) 92a9148abdSDoug Rabson { 93d4468577SJamie Gritton register struct netcred *np; 94d4468577SJamie Gritton register struct radix_node_head *rnh; 95d4468577SJamie Gritton register int i; 96d4468577SJamie Gritton struct radix_node *rn; 97d4468577SJamie Gritton struct sockaddr *saddr, *smask = 0; 98d4468577SJamie Gritton struct domain *dom; 99d4468577SJamie Gritton int error; 100a9148abdSDoug Rabson 101d4468577SJamie Gritton /* 102d4468577SJamie Gritton * XXX: This routine converts from a `struct xucred' 103d4468577SJamie Gritton * (argp->ex_anon) to a `struct ucred' (np->netc_anon). This 104d4468577SJamie Gritton * operation is questionable; for example, what should be done 105d4468577SJamie Gritton * with fields like cr_uidinfo and cr_prison? Currently, this 106d4468577SJamie Gritton * routine does not touch them (leaves them as NULL). 107d4468577SJamie Gritton */ 108d4468577SJamie Gritton if (argp->ex_anon.cr_version != XUCRED_VERSION) { 109d4468577SJamie Gritton vfs_mount_error(mp, "ex_anon.cr_version: %d != %d", 110d4468577SJamie Gritton argp->ex_anon.cr_version, XUCRED_VERSION); 111d4468577SJamie Gritton return (EINVAL); 112a9148abdSDoug Rabson } 113a9148abdSDoug Rabson 114d4468577SJamie Gritton if (argp->ex_addrlen == 0) { 115d4468577SJamie Gritton if (mp->mnt_flag & MNT_DEFEXPORTED) { 116d4468577SJamie Gritton vfs_mount_error(mp, 117d4468577SJamie Gritton "MNT_DEFEXPORTED already set for mount %p", mp); 118d4468577SJamie Gritton return (EPERM); 119a9148abdSDoug Rabson } 120d4468577SJamie Gritton np = &nep->ne_defexported; 121d4468577SJamie Gritton np->netc_exflags = argp->ex_flags; 122d4468577SJamie Gritton np->netc_anon = crget(); 123d4468577SJamie Gritton np->netc_anon->cr_uid = argp->ex_anon.cr_uid; 124d4468577SJamie Gritton crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups, 125d4468577SJamie Gritton argp->ex_anon.cr_groups); 126d4468577SJamie Gritton np->netc_anon->cr_prison = &prison0; 127d4468577SJamie Gritton prison_hold(np->netc_anon->cr_prison); 128d4468577SJamie Gritton np->netc_numsecflavors = argp->ex_numsecflavors; 129d4468577SJamie Gritton bcopy(argp->ex_secflavors, np->netc_secflavors, 130d4468577SJamie Gritton sizeof(np->netc_secflavors)); 131d4468577SJamie Gritton MNT_ILOCK(mp); 132d4468577SJamie Gritton mp->mnt_flag |= MNT_DEFEXPORTED; 133d4468577SJamie Gritton MNT_IUNLOCK(mp); 134a9148abdSDoug Rabson return (0); 135a9148abdSDoug Rabson } 136a9148abdSDoug Rabson 137d4468577SJamie Gritton #if MSIZE <= 256 138d4468577SJamie Gritton if (argp->ex_addrlen > MLEN) { 139d4468577SJamie Gritton vfs_mount_error(mp, "ex_addrlen %d is greater than %d", 140d4468577SJamie Gritton argp->ex_addrlen, MLEN); 141d4468577SJamie Gritton return (EINVAL); 142a9148abdSDoug Rabson } 143a9148abdSDoug Rabson #endif 144a9148abdSDoug Rabson 145d4468577SJamie Gritton i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen; 146d4468577SJamie Gritton np = (struct netcred *) malloc(i, M_NETADDR, M_WAITOK | M_ZERO); 147d4468577SJamie Gritton saddr = (struct sockaddr *) (np + 1); 148d4468577SJamie Gritton if ((error = copyin(argp->ex_addr, saddr, argp->ex_addrlen))) 149d4468577SJamie Gritton goto out; 150d4468577SJamie Gritton if (saddr->sa_family == AF_UNSPEC || saddr->sa_family > AF_MAX) { 151d4468577SJamie Gritton error = EINVAL; 152d4468577SJamie Gritton vfs_mount_error(mp, "Invalid saddr->sa_family: %d"); 153a9148abdSDoug Rabson goto out; 154a9148abdSDoug Rabson } 155d4468577SJamie Gritton if (saddr->sa_len > argp->ex_addrlen) 156d4468577SJamie Gritton saddr->sa_len = argp->ex_addrlen; 157d4468577SJamie Gritton if (argp->ex_masklen) { 158d4468577SJamie Gritton smask = (struct sockaddr *)((caddr_t)saddr + argp->ex_addrlen); 159d4468577SJamie Gritton error = copyin(argp->ex_mask, smask, argp->ex_masklen); 160d4468577SJamie Gritton if (error) 161d4468577SJamie Gritton goto out; 162d4468577SJamie Gritton if (smask->sa_len > argp->ex_masklen) 163d4468577SJamie Gritton smask->sa_len = argp->ex_masklen; 164d4468577SJamie Gritton } 165d4468577SJamie Gritton i = saddr->sa_family; 166d4468577SJamie Gritton if ((rnh = nep->ne_rtable[i]) == NULL) { 167d4468577SJamie Gritton /* 168d4468577SJamie Gritton * Seems silly to initialize every AF when most are not used, 169d4468577SJamie Gritton * do so on demand here 170d4468577SJamie Gritton */ 171d4468577SJamie Gritton for (dom = domains; dom; dom = dom->dom_next) { 172d4468577SJamie Gritton KASSERT(((i == AF_INET) || (i == AF_INET6)), 173d4468577SJamie Gritton ("unexpected protocol in vfs_hang_addrlist")); 174d4468577SJamie Gritton if (dom->dom_family == i && dom->dom_rtattach) { 175d4468577SJamie Gritton /* 176d4468577SJamie Gritton * XXX MRT 177d4468577SJamie Gritton * The INET and INET6 domains know the 178d4468577SJamie Gritton * offset already. We don't need to send it 179d4468577SJamie Gritton * So we just use it as a flag to say that 180d4468577SJamie Gritton * we are or are not setting up a real routing 181d4468577SJamie Gritton * table. Only IP and IPV6 need have this 182d4468577SJamie Gritton * be 0 so all other protocols can stay the 183d4468577SJamie Gritton * same (ABI compatible). 184d4468577SJamie Gritton */ 185d4468577SJamie Gritton dom->dom_rtattach( 186d4468577SJamie Gritton (void **) &nep->ne_rtable[i], 0); 187d4468577SJamie Gritton break; 188d4468577SJamie Gritton } 189d4468577SJamie Gritton } 190d4468577SJamie Gritton if ((rnh = nep->ne_rtable[i]) == NULL) { 191d4468577SJamie Gritton error = ENOBUFS; 192d4468577SJamie Gritton vfs_mount_error(mp, "%s %s %d", 193d4468577SJamie Gritton "Unable to initialize radix node head ", 194d4468577SJamie Gritton "for address family", i); 195a9148abdSDoug Rabson goto out; 196a9148abdSDoug Rabson } 197a9148abdSDoug Rabson } 198d4468577SJamie Gritton RADIX_NODE_HEAD_LOCK(rnh); 199d4468577SJamie Gritton rn = (*rnh->rnh_addaddr)(saddr, smask, rnh, np->netc_rnodes); 200d4468577SJamie Gritton RADIX_NODE_HEAD_UNLOCK(rnh); 201d4468577SJamie Gritton if (rn == NULL || np != (struct netcred *)rn) { /* already exists */ 202d4468577SJamie Gritton error = EPERM; 203d4468577SJamie Gritton vfs_mount_error(mp, "Invalid radix node head, rn: %p %p", 204d4468577SJamie Gritton rn, np); 205d4468577SJamie Gritton goto out; 206d4468577SJamie Gritton } 207d4468577SJamie Gritton np->netc_exflags = argp->ex_flags; 208d4468577SJamie Gritton np->netc_anon = crget(); 209d4468577SJamie Gritton np->netc_anon->cr_uid = argp->ex_anon.cr_uid; 210d4468577SJamie Gritton crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups, 211d4468577SJamie Gritton np->netc_anon->cr_groups); 212d4468577SJamie Gritton np->netc_anon->cr_prison = &prison0; 213d4468577SJamie Gritton prison_hold(np->netc_anon->cr_prison); 214d4468577SJamie Gritton np->netc_numsecflavors = argp->ex_numsecflavors; 215d4468577SJamie Gritton bcopy(argp->ex_secflavors, np->netc_secflavors, 216d4468577SJamie Gritton sizeof(np->netc_secflavors)); 217d4468577SJamie Gritton return (0); 218a9148abdSDoug Rabson out: 219d4468577SJamie Gritton free(np, M_NETADDR); 220d4468577SJamie Gritton return (error); 221a9148abdSDoug Rabson } 222a9148abdSDoug Rabson 223d4468577SJamie Gritton /* Helper for vfs_free_addrlist. */ 224d4468577SJamie Gritton /* ARGSUSED */ 225d4468577SJamie Gritton static int 226d4468577SJamie Gritton vfs_free_netcred(struct radix_node *rn, void *w) 227d4468577SJamie Gritton { 228d4468577SJamie Gritton struct radix_node_head *rnh = (struct radix_node_head *) w; 229d4468577SJamie Gritton struct ucred *cred; 230d4468577SJamie Gritton 231d4468577SJamie Gritton (*rnh->rnh_deladdr) (rn->rn_key, rn->rn_mask, rnh); 232d4468577SJamie Gritton cred = ((struct netcred *)rn)->netc_anon; 233d4468577SJamie Gritton if (cred != NULL) 234d4468577SJamie Gritton crfree(cred); 235d4468577SJamie Gritton free(rn, M_NETADDR); 236d4468577SJamie Gritton return (0); 237d4468577SJamie Gritton } 238d4468577SJamie Gritton 239d4468577SJamie Gritton /* 240d4468577SJamie Gritton * Free the net address hash lists that are hanging off the mount points. 241d4468577SJamie Gritton */ 242a9148abdSDoug Rabson static void 243d4468577SJamie Gritton vfs_free_addrlist(struct netexport *nep) 244a9148abdSDoug Rabson { 245d4468577SJamie Gritton int i; 246d4468577SJamie Gritton struct radix_node_head *rnh; 247d4468577SJamie Gritton struct ucred *cred; 248a9148abdSDoug Rabson 249d4468577SJamie Gritton for (i = 0; i <= AF_MAX; i++) { 250d4468577SJamie Gritton if ((rnh = nep->ne_rtable[i])) { 251d4468577SJamie Gritton RADIX_NODE_HEAD_LOCK(rnh); 252d4468577SJamie Gritton (*rnh->rnh_walktree) (rnh, vfs_free_netcred, rnh); 253d4468577SJamie Gritton RADIX_NODE_HEAD_UNLOCK(rnh); 254d4468577SJamie Gritton RADIX_NODE_HEAD_DESTROY(rnh); 255d4468577SJamie Gritton free(rnh, M_RTABLE); 256d4468577SJamie Gritton nep->ne_rtable[i] = NULL; /* not SMP safe XXX */ 257d4468577SJamie Gritton } 258d4468577SJamie Gritton } 259d4468577SJamie Gritton cred = nep->ne_defexported.netc_anon; 260d4468577SJamie Gritton if (cred != NULL) 261d4468577SJamie Gritton crfree(cred); 262d4468577SJamie Gritton 263d4468577SJamie Gritton } 264d4468577SJamie Gritton 265a9148abdSDoug Rabson /* 266d4468577SJamie Gritton * High level function to manipulate export options on a mount point 267d4468577SJamie Gritton * and the passed in netexport. 268d4468577SJamie Gritton * Struct export_args *argp is the variable used to twiddle options, 269d4468577SJamie Gritton * the structure is described in sys/mount.h 270a9148abdSDoug Rabson */ 271d4468577SJamie Gritton int 272d4468577SJamie Gritton vfs_export(struct mount *mp, struct export_args *argp) 273a9148abdSDoug Rabson { 274d4468577SJamie Gritton struct netexport *nep; 275d4468577SJamie Gritton int error; 276a9148abdSDoug Rabson 277d4468577SJamie Gritton if (argp->ex_numsecflavors < 0 278d4468577SJamie Gritton || argp->ex_numsecflavors >= MAXSECFLAVORS) 279d4468577SJamie Gritton return (EINVAL); 280a9148abdSDoug Rabson 281d4468577SJamie Gritton error = 0; 282d4468577SJamie Gritton lockmgr(&mp->mnt_explock, LK_EXCLUSIVE, NULL); 283d4468577SJamie Gritton nep = mp->mnt_export; 284d4468577SJamie Gritton if (argp->ex_flags & MNT_DELEXPORT) { 285d4468577SJamie Gritton if (nep == NULL) { 286d4468577SJamie Gritton error = ENOENT; 287a9148abdSDoug Rabson goto out; 288a9148abdSDoug Rabson } 289d4468577SJamie Gritton if (mp->mnt_flag & MNT_EXPUBLIC) { 290d4468577SJamie Gritton vfs_setpublicfs(NULL, NULL, NULL); 291d4468577SJamie Gritton MNT_ILOCK(mp); 292d4468577SJamie Gritton mp->mnt_flag &= ~MNT_EXPUBLIC; 293d4468577SJamie Gritton MNT_IUNLOCK(mp); 294d4468577SJamie Gritton } 295d4468577SJamie Gritton vfs_free_addrlist(nep); 296d4468577SJamie Gritton mp->mnt_export = NULL; 297d4468577SJamie Gritton free(nep, M_MOUNT); 298d4468577SJamie Gritton nep = NULL; 299d4468577SJamie Gritton MNT_ILOCK(mp); 300d4468577SJamie Gritton mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED); 301d4468577SJamie Gritton MNT_IUNLOCK(mp); 302d4468577SJamie Gritton } 303d4468577SJamie Gritton if (argp->ex_flags & MNT_EXPORTED) { 304d4468577SJamie Gritton if (nep == NULL) { 305d4468577SJamie Gritton nep = malloc(sizeof(struct netexport), M_MOUNT, M_WAITOK | M_ZERO); 306d4468577SJamie Gritton mp->mnt_export = nep; 307d4468577SJamie Gritton } 308d4468577SJamie Gritton if (argp->ex_flags & MNT_EXPUBLIC) { 309d4468577SJamie Gritton if ((error = vfs_setpublicfs(mp, nep, argp)) != 0) 310a9148abdSDoug Rabson goto out; 311d4468577SJamie Gritton MNT_ILOCK(mp); 312d4468577SJamie Gritton mp->mnt_flag |= MNT_EXPUBLIC; 313d4468577SJamie Gritton MNT_IUNLOCK(mp); 314a9148abdSDoug Rabson } 315d4468577SJamie Gritton if ((error = vfs_hang_addrlist(mp, nep, argp))) 316a9148abdSDoug Rabson goto out; 317d4468577SJamie Gritton MNT_ILOCK(mp); 318d4468577SJamie Gritton mp->mnt_flag |= MNT_EXPORTED; 319d4468577SJamie Gritton MNT_IUNLOCK(mp); 320a9148abdSDoug Rabson } 321a9148abdSDoug Rabson 322a9148abdSDoug Rabson out: 323d4468577SJamie Gritton lockmgr(&mp->mnt_explock, LK_RELEASE, NULL); 324d4468577SJamie Gritton /* 325d4468577SJamie Gritton * Once we have executed the vfs_export() command, we do 326d4468577SJamie Gritton * not want to keep the "export" option around in the 327d4468577SJamie Gritton * options list, since that will cause subsequent MNT_UPDATE 328d4468577SJamie Gritton * calls to fail. The export information is saved in 329d4468577SJamie Gritton * mp->mnt_export, so we can safely delete the "export" mount option 330d4468577SJamie Gritton * here. 331d4468577SJamie Gritton */ 332d4468577SJamie Gritton vfs_deleteopt(mp->mnt_optnew, "export"); 333d4468577SJamie Gritton vfs_deleteopt(mp->mnt_opt, "export"); 334d4468577SJamie Gritton return (error); 335a9148abdSDoug Rabson } 336a9148abdSDoug Rabson 337d4468577SJamie Gritton /* 338d4468577SJamie Gritton * Set the publicly exported filesystem (WebNFS). Currently, only 339d4468577SJamie Gritton * one public filesystem is possible in the spec (RFC 2054 and 2055) 340d4468577SJamie Gritton */ 341d4468577SJamie Gritton int 342d4468577SJamie Gritton vfs_setpublicfs(struct mount *mp, struct netexport *nep, 343d4468577SJamie Gritton struct export_args *argp) 344a9148abdSDoug Rabson { 345d4468577SJamie Gritton int error; 346d4468577SJamie Gritton struct vnode *rvp; 347d4468577SJamie Gritton char *cp; 348a9148abdSDoug Rabson 349d4468577SJamie Gritton /* 350d4468577SJamie Gritton * mp == NULL -> invalidate the current info, the FS is 351d4468577SJamie Gritton * no longer exported. May be called from either vfs_export 352d4468577SJamie Gritton * or unmount, so check if it hasn't already been done. 353d4468577SJamie Gritton */ 354d4468577SJamie Gritton if (mp == NULL) { 355d4468577SJamie Gritton if (nfs_pub.np_valid) { 356d4468577SJamie Gritton nfs_pub.np_valid = 0; 357d4468577SJamie Gritton if (nfs_pub.np_index != NULL) { 358d4468577SJamie Gritton free(nfs_pub.np_index, M_TEMP); 359d4468577SJamie Gritton nfs_pub.np_index = NULL; 360d4468577SJamie Gritton } 361d4468577SJamie Gritton } 362d4468577SJamie Gritton return (0); 363a9148abdSDoug Rabson } 364a9148abdSDoug Rabson 365d4468577SJamie Gritton /* 366d4468577SJamie Gritton * Only one allowed at a time. 367d4468577SJamie Gritton */ 368d4468577SJamie Gritton if (nfs_pub.np_valid != 0 && mp != nfs_pub.np_mount) 369d4468577SJamie Gritton return (EBUSY); 370d4468577SJamie Gritton 371d4468577SJamie Gritton /* 372d4468577SJamie Gritton * Get real filehandle for root of exported FS. 373d4468577SJamie Gritton */ 374d4468577SJamie Gritton bzero(&nfs_pub.np_handle, sizeof(nfs_pub.np_handle)); 375d4468577SJamie Gritton nfs_pub.np_handle.fh_fsid = mp->mnt_stat.f_fsid; 376d4468577SJamie Gritton 377d4468577SJamie Gritton if ((error = VFS_ROOT(mp, LK_EXCLUSIVE, &rvp))) 378d4468577SJamie Gritton return (error); 379d4468577SJamie Gritton 380d4468577SJamie Gritton if ((error = VOP_VPTOFH(rvp, &nfs_pub.np_handle.fh_fid))) 381d4468577SJamie Gritton return (error); 382d4468577SJamie Gritton 383d4468577SJamie Gritton vput(rvp); 384d4468577SJamie Gritton 385d4468577SJamie Gritton /* 386d4468577SJamie Gritton * If an indexfile was specified, pull it in. 387d4468577SJamie Gritton */ 388d4468577SJamie Gritton if (argp->ex_indexfile != NULL) { 389d4468577SJamie Gritton if (nfs_pub.np_index != NULL) 390d4468577SJamie Gritton nfs_pub.np_index = malloc(MAXNAMLEN + 1, M_TEMP, 391d4468577SJamie Gritton M_WAITOK); 392d4468577SJamie Gritton error = copyinstr(argp->ex_indexfile, nfs_pub.np_index, 393d4468577SJamie Gritton MAXNAMLEN, (size_t *)0); 394d4468577SJamie Gritton if (!error) { 395d4468577SJamie Gritton /* 396d4468577SJamie Gritton * Check for illegal filenames. 397d4468577SJamie Gritton */ 398d4468577SJamie Gritton for (cp = nfs_pub.np_index; *cp; cp++) { 399d4468577SJamie Gritton if (*cp == '/') { 400d4468577SJamie Gritton error = EINVAL; 401d4468577SJamie Gritton break; 402d4468577SJamie Gritton } 403d4468577SJamie Gritton } 404d4468577SJamie Gritton } 405d4468577SJamie Gritton if (error) { 406d4468577SJamie Gritton free(nfs_pub.np_index, M_TEMP); 407d4468577SJamie Gritton nfs_pub.np_index = NULL; 408d4468577SJamie Gritton return (error); 409d4468577SJamie Gritton } 410a9148abdSDoug Rabson } 411a9148abdSDoug Rabson 412d4468577SJamie Gritton nfs_pub.np_mount = mp; 413d4468577SJamie Gritton nfs_pub.np_valid = 1; 414d4468577SJamie Gritton return (0); 415d4468577SJamie Gritton } 416d4468577SJamie Gritton 417d4468577SJamie Gritton /* 418d4468577SJamie Gritton * Used by the filesystems to determine if a given network address 419d4468577SJamie Gritton * (passed in 'nam') is present in their exports list, returns a pointer 420d4468577SJamie Gritton * to struct netcred so that the filesystem can examine it for 421d4468577SJamie Gritton * access rights (read/write/etc). 422d4468577SJamie Gritton */ 423d4468577SJamie Gritton static struct netcred * 424d4468577SJamie Gritton vfs_export_lookup(struct mount *mp, struct sockaddr *nam) 425a9148abdSDoug Rabson { 426d4468577SJamie Gritton struct netexport *nep; 427d4468577SJamie Gritton register struct netcred *np; 428d4468577SJamie Gritton register struct radix_node_head *rnh; 429d4468577SJamie Gritton struct sockaddr *saddr; 430a9148abdSDoug Rabson 431d4468577SJamie Gritton nep = mp->mnt_export; 432d4468577SJamie Gritton if (nep == NULL) 433d4468577SJamie Gritton return (NULL); 434d4468577SJamie Gritton np = NULL; 435d4468577SJamie Gritton if (mp->mnt_flag & MNT_EXPORTED) { 436d4468577SJamie Gritton /* 437d4468577SJamie Gritton * Lookup in the export list first. 438d4468577SJamie Gritton */ 439d4468577SJamie Gritton if (nam != NULL) { 440d4468577SJamie Gritton saddr = nam; 441d4468577SJamie Gritton rnh = nep->ne_rtable[saddr->sa_family]; 442d4468577SJamie Gritton if (rnh != NULL) { 443d4468577SJamie Gritton RADIX_NODE_HEAD_RLOCK(rnh); 444d4468577SJamie Gritton np = (struct netcred *) 445d4468577SJamie Gritton (*rnh->rnh_matchaddr)(saddr, rnh); 446d4468577SJamie Gritton RADIX_NODE_HEAD_RUNLOCK(rnh); 447d4468577SJamie Gritton if (np && np->netc_rnodes->rn_flags & RNF_ROOT) 448d4468577SJamie Gritton np = NULL; 449d4468577SJamie Gritton } 450d4468577SJamie Gritton } 451d4468577SJamie Gritton /* 452d4468577SJamie Gritton * If no address match, use the default if it exists. 453d4468577SJamie Gritton */ 454d4468577SJamie Gritton if (np == NULL && mp->mnt_flag & MNT_DEFEXPORTED) 455d4468577SJamie Gritton np = &nep->ne_defexported; 456d4468577SJamie Gritton } 457d4468577SJamie Gritton return (np); 458a9148abdSDoug Rabson } 459a9148abdSDoug Rabson 460d4468577SJamie Gritton /* 461d4468577SJamie Gritton * XXX: This comment comes from the deprecated ufs_check_export() 462d4468577SJamie Gritton * XXX: and may not entirely apply, but lacking something better: 463d4468577SJamie Gritton * This is the generic part of fhtovp called after the underlying 464d4468577SJamie Gritton * filesystem has validated the file handle. 465d4468577SJamie Gritton * 466d4468577SJamie Gritton * Verify that a host should have access to a filesystem. 467d4468577SJamie Gritton */ 468a9148abdSDoug Rabson 469d4468577SJamie Gritton int 470d4468577SJamie Gritton vfs_stdcheckexp(struct mount *mp, struct sockaddr *nam, int *extflagsp, 471d4468577SJamie Gritton struct ucred **credanonp, int *numsecflavors, int **secflavors) 472a9148abdSDoug Rabson { 473d4468577SJamie Gritton struct netcred *np; 474a9148abdSDoug Rabson 475d4468577SJamie Gritton lockmgr(&mp->mnt_explock, LK_SHARED, NULL); 476d4468577SJamie Gritton np = vfs_export_lookup(mp, nam); 477d4468577SJamie Gritton if (np == NULL) { 478d4468577SJamie Gritton lockmgr(&mp->mnt_explock, LK_RELEASE, NULL); 479d4468577SJamie Gritton *credanonp = NULL; 480d4468577SJamie Gritton return (EACCES); 481a9148abdSDoug Rabson } 482d4468577SJamie Gritton *extflagsp = np->netc_exflags; 483d4468577SJamie Gritton if ((*credanonp = np->netc_anon) != NULL) 484d4468577SJamie Gritton crhold(*credanonp); 485d4468577SJamie Gritton if (numsecflavors) 486d4468577SJamie Gritton *numsecflavors = np->netc_numsecflavors; 487d4468577SJamie Gritton if (secflavors) 488d4468577SJamie Gritton *secflavors = np->netc_secflavors; 489d4468577SJamie Gritton lockmgr(&mp->mnt_explock, LK_RELEASE, NULL); 490d4468577SJamie Gritton return (0); 491d4468577SJamie Gritton } 492d4468577SJamie Gritton 493