The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/nfs/nfs_export.c

Version: -  FREEBSD  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: nfs_export.c,v 1.50 2011/03/31 19:40:53 dyoung Exp $   */
    2 
    3 /*-
    4  * Copyright (c) 1997, 1998, 2004, 2005, 2008 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  *
   24  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   27  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   28  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   32  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   34  * POSSIBILITY OF SUCH DAMAGE.
   35  */
   36 
   37 /*
   38  * Copyright (c) 1989, 1993
   39  *      The Regents of the University of California.  All rights reserved.
   40  * (c) UNIX System Laboratories, Inc.
   41  * All or some portions of this file are derived from material licensed
   42  * to the University of California by American Telephone and Telegraph
   43  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   44  * the permission of UNIX System Laboratories, Inc.
   45  *
   46  * Redistribution and use in source and binary forms, with or without
   47  * modification, are permitted provided that the following conditions
   48  * are met:
   49  * 1. Redistributions of source code must retain the above copyright
   50  *    notice, this list of conditions and the following disclaimer.
   51  * 2. Redistributions in binary form must reproduce the above copyright
   52  *    notice, this list of conditions and the following disclaimer in the
   53  *    documentation and/or other materials provided with the distribution.
   54  * 3. Neither the name of the University nor the names of its contributors
   55  *    may be used to endorse or promote products derived from this software
   56  *    without specific prior written permission.
   57  *
   58  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   59  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   64  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   65  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   66  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   67  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   68  * SUCH DAMAGE.
   69  *
   70  *      @(#)vfs_subr.c  8.13 (Berkeley) 4/18/94
   71  */
   72 
   73 /*
   74  * VFS exports list management.
   75  *
   76  * Lock order: vfs_busy -> mnt_updating -> netexport_lock.
   77  */
   78 
   79 #include <sys/cdefs.h>
   80 __KERNEL_RCSID(0, "$NetBSD: nfs_export.c,v 1.50 2011/03/31 19:40:53 dyoung Exp $");
   81 
   82 #include <sys/param.h>
   83 #include <sys/systm.h>
   84 #include <sys/kernel.h>
   85 #include <sys/queue.h>
   86 #include <sys/proc.h>
   87 #include <sys/mount.h>
   88 #include <sys/vnode.h>
   89 #include <sys/namei.h>
   90 #include <sys/errno.h>
   91 #include <sys/malloc.h>
   92 #include <sys/domain.h>
   93 #include <sys/mbuf.h>
   94 #include <sys/dirent.h>
   95 #include <sys/socket.h>         /* XXX for AF_MAX */
   96 #include <sys/kauth.h>
   97 
   98 #include <net/radix.h>
   99 
  100 #include <netinet/in.h>
  101 
  102 #include <nfs/rpcv2.h>
  103 #include <nfs/nfsproto.h>
  104 #include <nfs/nfs.h>
  105 #include <nfs/nfs_var.h>
  106 
  107 /*
  108  * Network address lookup element.
  109  */
  110 struct netcred {
  111         struct  radix_node netc_rnodes[2];
  112         int     netc_refcnt;
  113         int     netc_exflags;
  114         kauth_cred_t netc_anon;
  115 };
  116 
  117 /*
  118  * Network export information.
  119  */
  120 struct netexport {
  121         CIRCLEQ_ENTRY(netexport) ne_list;
  122         struct mount *ne_mount;
  123         struct netcred ne_defexported;                /* Default export */
  124         struct radix_node_head *ne_rtable[AF_MAX+1]; /* Individual exports */
  125 };
  126 CIRCLEQ_HEAD(, netexport) netexport_list =
  127     CIRCLEQ_HEAD_INITIALIZER(netexport_list);
  128 
  129 /* Publicly exported file system. */
  130 struct nfs_public nfs_pub;
  131 
  132 /*
  133  * Local prototypes.
  134  */
  135 static int init_exports(struct mount *, struct netexport **);
  136 static int hang_addrlist(struct mount *, struct netexport *,
  137     const struct export_args *);
  138 static int sacheck(struct sockaddr *);
  139 static int free_netcred(struct radix_node *, void *);
  140 static int export(struct netexport *, const struct export_args *);
  141 static int setpublicfs(struct mount *, struct netexport *,
  142     const struct export_args *);
  143 static struct netcred *netcred_lookup(struct netexport *, struct mbuf *);
  144 static struct netexport *netexport_lookup(const struct mount *);
  145 static struct netexport *netexport_lookup_byfsid(const fsid_t *);
  146 static void netexport_clear(struct netexport *);
  147 static void netexport_insert(struct netexport *);
  148 static void netexport_remove(struct netexport *);
  149 static void netexport_wrlock(void);
  150 static void netexport_wrunlock(void);
  151 static int nfs_export_update_30(struct mount *mp, const char *path, void *);
  152 
  153 static krwlock_t netexport_lock;
  154 
  155 /*
  156  * PUBLIC INTERFACE
  157  */
  158 
  159 /*
  160  * Declare and initialize the file system export hooks.
  161  */
  162 static void netexport_unmount(struct mount *);
  163 
  164 struct vfs_hooks nfs_export_hooks = {
  165         { NULL, NULL },
  166         .vh_unmount = netexport_unmount,
  167         .vh_reexport = nfs_export_update_30,
  168 };
  169 
  170 /*
  171  * VFS unmount hook for NFS exports.
  172  *
  173  * Releases NFS exports list resources if the given mount point has some.
  174  * As allocation happens lazily, it may be that it doesn't has this
  175  * information, although it theorically should.
  176  */
  177 static void
  178 netexport_unmount(struct mount *mp)
  179 {
  180         struct netexport *ne;
  181 
  182         KASSERT(mp != NULL);
  183 
  184         netexport_wrlock();
  185         ne = netexport_lookup(mp);
  186         if (ne == NULL) {
  187                 netexport_wrunlock();
  188                 return;
  189         }
  190         netexport_clear(ne);
  191         netexport_remove(ne);
  192         netexport_wrunlock();
  193         kmem_free(ne, sizeof(*ne));
  194 }
  195 
  196 void
  197 netexport_init(void)
  198 {
  199 
  200         rw_init(&netexport_lock);
  201 }
  202 
  203 void
  204 netexport_fini(void)
  205 {
  206         struct netexport *ne;
  207         struct mount *mp;
  208         int error;
  209 
  210         while (!CIRCLEQ_EMPTY(&netexport_list)) {
  211                 netexport_wrlock();
  212                 ne = CIRCLEQ_FIRST(&netexport_list);
  213                 mp = ne->ne_mount;
  214                 error = vfs_busy(mp, NULL);
  215                 netexport_wrunlock();
  216                 if (error != 0) {
  217                         kpause("nfsfini", false, hz, NULL);
  218                         continue;
  219                 }
  220                 mutex_enter(&mp->mnt_updating); /* mnt_flag */
  221                 netexport_unmount(mp);
  222                 mutex_exit(&mp->mnt_updating);  /* mnt_flag */
  223                 vfs_unbusy(mp, false, NULL);
  224         }
  225         rw_destroy(&netexport_lock);
  226 }
  227 
  228 
  229 /*
  230  * Atomically set the NFS exports list of the given file system, replacing
  231  * it with a new list of entries.
  232  *
  233  * Returns zero on success or an appropriate error code otherwise.
  234  *
  235  * Helper function for the nfssvc(2) system call (NFSSVC_SETEXPORTSLIST
  236  * command).
  237  */
  238 int
  239 mountd_set_exports_list(const struct mountd_exports_list *mel, struct lwp *l,
  240     struct mount *nmp)
  241 {
  242         int error;
  243 #ifdef notyet
  244         /* XXX: See below to see the reason why this is disabled. */
  245         size_t i;
  246 #endif
  247         struct mount *mp;
  248         struct netexport *ne;
  249         struct pathbuf *pb;
  250         struct nameidata nd;
  251         struct vnode *vp;
  252         size_t fid_size;
  253 
  254         if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_NFS,
  255             KAUTH_REQ_NETWORK_NFS_EXPORT, NULL, NULL, NULL) != 0)
  256                 return EPERM;
  257 
  258         /* Lookup the file system path. */
  259         error = pathbuf_copyin(mel->mel_path, &pb);
  260         if (error) {
  261                 return error;
  262         }
  263         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, pb);
  264         error = namei(&nd);
  265         if (error != 0) {
  266                 pathbuf_destroy(pb);
  267                 return error;
  268         }
  269         vp = nd.ni_vp;
  270         mp = vp->v_mount;
  271         KASSERT(nmp == NULL || nmp == mp);
  272         pathbuf_destroy(pb);
  273 
  274         /*
  275          * Make sure the file system can do vptofh.  If the file system
  276          * knows the handle's size, just trust it's able to do the
  277          * actual translation also (otherwise we should check fhtovp
  278          * also, and that's getting a wee bit ridiculous).
  279          */
  280         fid_size = 0;
  281         if ((error = VFS_VPTOFH(vp, NULL, &fid_size)) != E2BIG) {
  282                 vput(vp);
  283                 return EOPNOTSUPP;
  284         }
  285 
  286         /* Mark the file system busy. */
  287         error = vfs_busy(mp, NULL);
  288         vput(vp);
  289         if (error != 0)
  290                 return error;
  291         if (nmp == NULL)
  292                 mutex_enter(&mp->mnt_updating); /* mnt_flag */
  293         netexport_wrlock();
  294         ne = netexport_lookup(mp);
  295         if (ne == NULL) {
  296                 error = init_exports(mp, &ne);
  297                 if (error != 0) {
  298                         goto out;
  299                 }
  300         }
  301 
  302         KASSERT(ne != NULL);
  303         KASSERT(ne->ne_mount == mp);
  304 
  305         /*
  306          * XXX: The part marked as 'notyet' works fine from the kernel's
  307          * point of view, in the sense that it is able to atomically update
  308          * the complete exports list for a file system.  However, supporting
  309          * this in mountd(8) requires a lot of work; so, for now, keep the
  310          * old behavior of updating a single entry per call.
  311          *
  312          * When mountd(8) is fixed, just remove the second branch of this
  313          * preprocessor conditional and enable the first one.
  314          */
  315 #ifdef notyet
  316         netexport_clear(ne);
  317         for (i = 0; error == 0 && i < mel->mel_nexports; i++)
  318                 error = export(ne, &mel->mel_exports[i]);
  319 #else
  320         if (mel->mel_nexports == 0)
  321                 netexport_clear(ne);
  322         else if (mel->mel_nexports == 1)
  323                 error = export(ne, &mel->mel_exports[0]);
  324         else {
  325                 printf("%s: Cannot set more than one "
  326                     "entry at once (unimplemented)\n", __func__);
  327                 error = EOPNOTSUPP;
  328         }
  329 #endif
  330 
  331 out:
  332         netexport_wrunlock();
  333         if (nmp == NULL)
  334                 mutex_exit(&mp->mnt_updating);  /* mnt_flag */
  335         vfs_unbusy(mp, false, NULL);
  336         return error;
  337 }
  338 
  339 static void
  340 netexport_insert(struct netexport *ne)
  341 {
  342 
  343         CIRCLEQ_INSERT_HEAD(&netexport_list, ne, ne_list);
  344 }
  345 
  346 static void
  347 netexport_remove(struct netexport *ne)
  348 {
  349 
  350         CIRCLEQ_REMOVE(&netexport_list, ne, ne_list);
  351 }
  352 
  353 static struct netexport *
  354 netexport_lookup(const struct mount *mp)
  355 {
  356         struct netexport *ne;
  357 
  358         CIRCLEQ_FOREACH(ne, &netexport_list, ne_list) {
  359                 if (ne->ne_mount == mp) {
  360                         goto done;
  361                 }
  362         }
  363         ne = NULL;
  364 done:
  365         return ne;
  366 }
  367 
  368 static struct netexport *
  369 netexport_lookup_byfsid(const fsid_t *fsid)
  370 {
  371         struct netexport *ne;
  372 
  373         CIRCLEQ_FOREACH(ne, &netexport_list, ne_list) {
  374                 const struct mount *mp = ne->ne_mount;
  375 
  376                 if (mp->mnt_stat.f_fsidx.__fsid_val[0] == fsid->__fsid_val[0] &&
  377                     mp->mnt_stat.f_fsidx.__fsid_val[1] == fsid->__fsid_val[1]) {
  378                         goto done;
  379                 }
  380         }
  381         ne = NULL;
  382 done:
  383 
  384         return ne;
  385 }
  386 
  387 /*
  388  * Check if the file system specified by the 'mp' mount structure is
  389  * exported to a client with 'anon' anonymous credentials.  The 'mb'
  390  * argument is an mbuf containing the network address of the client.
  391  * The return parameters for the export flags for the client are returned
  392  * in the address specified by 'wh'.
  393  *
  394  * This function is used exclusively by the NFS server.  It is generally
  395  * invoked before VFS_FHTOVP to validate that client has access to the
  396  * file system.
  397  */
  398 
  399 int
  400 netexport_check(const fsid_t *fsid, struct mbuf *mb, struct mount **mpp,
  401     int *wh, kauth_cred_t *anon)
  402 {
  403         struct netexport *ne;
  404         struct netcred *np;
  405 
  406         ne = netexport_lookup_byfsid(fsid);
  407         if (ne == NULL) {
  408                 return EACCES;
  409         }
  410         np = netcred_lookup(ne, mb);
  411         if (np == NULL) {
  412                 return EACCES;
  413         }
  414 
  415         *mpp = ne->ne_mount;
  416         *wh = np->netc_exflags;
  417         *anon = np->netc_anon;
  418 
  419         return 0;
  420 }
  421 
  422 /*
  423  * Handles legacy export requests.  In this case, the export information
  424  * is hardcoded in a specific place of the mount arguments structure (given
  425  * in data); the request for an update is given through the fspec field
  426  * (also in a known location), which must be a null pointer.
  427  *
  428  * Returns EJUSTRETURN if the given command was not a export request.
  429  * Otherwise, returns 0 on success or an appropriate error code otherwise.
  430  */
  431 static int
  432 nfs_export_update_30(struct mount *mp, const char *path, void *data)
  433 {
  434         struct mountd_exports_list mel;
  435         struct mnt_export_args30 *args;
  436 
  437         args = data;
  438         mel.mel_path = path;
  439 
  440         if (args->fspec != NULL)
  441                 return EJUSTRETURN;
  442 
  443         if (args->eargs.ex_flags & 0x00020000) {
  444                 /* Request to delete exports.  The mask above holds the
  445                  * value that used to be in MNT_DELEXPORT. */
  446                 mel.mel_nexports = 0;
  447         } else {
  448                 /* The following assumes export_args has not changed since
  449                  * export_args30 - typedef checks sizes. */
  450                 typedef char x[sizeof args->eargs == sizeof *mel.mel_exports ? 1 : -1];
  451 
  452                 mel.mel_nexports = 1;
  453                 mel.mel_exports = (void *)&args->eargs;
  454         }
  455 
  456         return mountd_set_exports_list(&mel, curlwp, mp);
  457 }
  458 
  459 /*
  460  * INTERNAL FUNCTIONS
  461  */
  462 
  463 /*
  464  * Initializes NFS exports for the mountpoint given in 'mp'.
  465  * If successful, returns 0 and sets *nep to the address of the new
  466  * netexport item; otherwise returns an appropriate error code
  467  * and *nep remains unmodified.
  468  */
  469 static int
  470 init_exports(struct mount *mp, struct netexport **nep)
  471 {
  472         int error;
  473         struct export_args ea;
  474         struct netexport *ne;
  475 
  476         KASSERT(mp != NULL);
  477 
  478         /* Ensure that we do not already have this mount point. */
  479         KASSERT(netexport_lookup(mp) == NULL);
  480 
  481         ne = kmem_zalloc(sizeof(*ne), KM_SLEEP);
  482         ne->ne_mount = mp;
  483 
  484         /* Set the default export entry.  Handled internally by export upon
  485          * first call. */
  486         memset(&ea, 0, sizeof(ea));
  487         ea.ex_root = -2;
  488         if (mp->mnt_flag & MNT_RDONLY)
  489                 ea.ex_flags |= MNT_EXRDONLY;
  490         error = export(ne, &ea);
  491         if (error != 0) {
  492                 kmem_free(ne, sizeof(*ne));
  493         } else {
  494                 netexport_insert(ne);
  495                 *nep = ne;
  496         }
  497 
  498         return error;
  499 }
  500 
  501 /*
  502  * Build hash lists of net addresses and hang them off the mount point.
  503  * Called by export() to set up a new entry in the lists of export
  504  * addresses.
  505  */
  506 static int
  507 hang_addrlist(struct mount *mp, struct netexport *nep,
  508     const struct export_args *argp)
  509 {
  510         int error, i;
  511         struct netcred *np, *enp;
  512         struct radix_node_head *rnh;
  513         struct sockaddr *saddr, *smask;
  514         struct domain *dom;
  515 
  516         smask = NULL;
  517 
  518         if (argp->ex_addrlen == 0) {
  519                 if (mp->mnt_flag & MNT_DEFEXPORTED)
  520                         return EPERM;
  521                 np = &nep->ne_defexported;
  522                 KASSERT(np->netc_anon == NULL);
  523                 np->netc_anon = kauth_cred_alloc();
  524                 np->netc_exflags = argp->ex_flags;
  525                 kauth_uucred_to_cred(np->netc_anon, &argp->ex_anon);
  526                 mp->mnt_flag |= MNT_DEFEXPORTED;
  527                 return 0;
  528         }
  529 
  530         if (argp->ex_addrlen > MLEN || argp->ex_masklen > MLEN)
  531                 return EINVAL;
  532 
  533         i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen;
  534         np = malloc(i, M_NETADDR, M_WAITOK | M_ZERO);
  535         np->netc_anon = kauth_cred_alloc();
  536         saddr = (struct sockaddr *)(np + 1);
  537         error = copyin(argp->ex_addr, saddr, argp->ex_addrlen);
  538         if (error)
  539                 goto out;
  540         if (saddr->sa_len > argp->ex_addrlen)
  541                 saddr->sa_len = argp->ex_addrlen;
  542         if (sacheck(saddr) == -1)
  543                 return EINVAL;
  544         if (argp->ex_masklen) {
  545                 smask = (struct sockaddr *)((char *)saddr + argp->ex_addrlen);
  546                 error = copyin(argp->ex_mask, smask, argp->ex_masklen);
  547                 if (error)
  548                         goto out;
  549                 if (smask->sa_len > argp->ex_masklen)
  550                         smask->sa_len = argp->ex_masklen;
  551                 if (smask->sa_family != saddr->sa_family)
  552                         return EINVAL;
  553                 if (sacheck(smask) == -1)
  554                         return EINVAL;
  555         }
  556         i = saddr->sa_family;
  557         if ((rnh = nep->ne_rtable[i]) == 0) {
  558                 /*
  559                  * Seems silly to initialize every AF when most are not
  560                  * used, do so on demand here
  561                  */
  562                 DOMAIN_FOREACH(dom) {
  563                         if (dom->dom_family == i && dom->dom_rtattach) {
  564                                 rn_inithead((void **)&nep->ne_rtable[i],
  565                                         dom->dom_rtoffset);
  566                                 break;
  567                         }
  568                 }
  569                 if ((rnh = nep->ne_rtable[i]) == 0) {
  570                         error = ENOBUFS;
  571                         goto out;
  572                 }
  573         }
  574 
  575         enp = (struct netcred *)(*rnh->rnh_addaddr)(saddr, smask, rnh,
  576             np->netc_rnodes);
  577         if (enp != np) {
  578                 if (enp == NULL) {
  579                         enp = (struct netcred *)(*rnh->rnh_lookup)(saddr,
  580                             smask, rnh);
  581                         if (enp == NULL) {
  582                                 error = EPERM;
  583                                 goto out;
  584                         }
  585                 } else
  586                         enp->netc_refcnt++;
  587 
  588                 goto check;
  589         } else
  590                 enp->netc_refcnt = 1;
  591 
  592         np->netc_exflags = argp->ex_flags;
  593         kauth_uucred_to_cred(np->netc_anon, &argp->ex_anon);
  594         return 0;
  595 check:
  596         if (enp->netc_exflags != argp->ex_flags ||
  597             kauth_cred_uucmp(enp->netc_anon, &argp->ex_anon) != 0)
  598                 error = EPERM;
  599         else
  600                 error = 0;
  601 out:
  602         KASSERT(np->netc_anon != NULL);
  603         kauth_cred_free(np->netc_anon);
  604         free(np, M_NETADDR);
  605         return error;
  606 }
  607 
  608 /*
  609  * Ensure that the address stored in 'sa' is valid.
  610  * Returns zero on success, otherwise -1.
  611  */
  612 static int
  613 sacheck(struct sockaddr *sa)
  614 {
  615 
  616         switch (sa->sa_family) {
  617         case AF_INET: {
  618                 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
  619                 char *p = (char *)sin->sin_zero;
  620                 size_t i;
  621 
  622                 if (sin->sin_len != sizeof(*sin))
  623                         return -1;
  624                 if (sin->sin_port != 0)
  625                         return -1;
  626                 for (i = 0; i < sizeof(sin->sin_zero); i++)
  627                         if (*p++ != '\0')
  628                                 return -1;
  629                 return 0;
  630         }
  631         case AF_INET6: {
  632                 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
  633 
  634                 if (sin6->sin6_len != sizeof(*sin6))
  635                         return -1;
  636                 if (sin6->sin6_port != 0)
  637                         return -1;
  638                 return 0;
  639         }
  640         default:
  641                 return -1;
  642         }
  643 }
  644 
  645 /*
  646  * Free the netcred object pointed to by the 'rn' radix node.
  647  * 'w' holds a pointer to the radix tree head.
  648  */
  649 static int
  650 free_netcred(struct radix_node *rn, void *w)
  651 {
  652         struct radix_node_head *rnh = (struct radix_node_head *)w;
  653         struct netcred *np = (struct netcred *)(void *)rn;
  654 
  655         (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh);
  656         if (--(np->netc_refcnt) <= 0) {
  657                 KASSERT(np->netc_anon != NULL);
  658                 kauth_cred_free(np->netc_anon);
  659                 free(np, M_NETADDR);
  660         }
  661         return 0;
  662 }
  663 
  664 /*
  665  * Clears the exports list for a given file system.
  666  */
  667 static void
  668 netexport_clear(struct netexport *ne)
  669 {
  670         struct radix_node_head *rnh;
  671         struct mount *mp = ne->ne_mount;
  672         int i;
  673 
  674         if (mp->mnt_flag & MNT_EXPUBLIC) {
  675                 setpublicfs(NULL, NULL, NULL);
  676                 mp->mnt_flag &= ~MNT_EXPUBLIC;
  677         }
  678 
  679         for (i = 0; i <= AF_MAX; i++) {
  680                 if ((rnh = ne->ne_rtable[i]) != NULL) {
  681                         rn_walktree(rnh, free_netcred, rnh);
  682                         free(rnh, M_RTABLE);
  683                         ne->ne_rtable[i] = NULL;
  684                 }
  685         }
  686 
  687         if ((mp->mnt_flag & MNT_DEFEXPORTED) != 0) {
  688                 struct netcred *np = &ne->ne_defexported;
  689 
  690                 KASSERT(np->netc_anon != NULL);
  691                 kauth_cred_free(np->netc_anon);
  692                 np->netc_anon = NULL;
  693         } else {
  694                 KASSERT(ne->ne_defexported.netc_anon == NULL);
  695         }
  696 
  697         mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED);
  698 }
  699 
  700 /*
  701  * Add a new export entry (described by an export_args structure) to the
  702  * given file system.
  703  */
  704 static int
  705 export(struct netexport *nep, const struct export_args *argp)
  706 {
  707         struct mount *mp = nep->ne_mount;
  708         int error;
  709 
  710         if (argp->ex_flags & MNT_EXPORTED) {
  711                 if (argp->ex_flags & MNT_EXPUBLIC) {
  712                         if ((error = setpublicfs(mp, nep, argp)) != 0)
  713                                 return error;
  714                         mp->mnt_flag |= MNT_EXPUBLIC;
  715                 }
  716                 if ((error = hang_addrlist(mp, nep, argp)) != 0)
  717                         return error;
  718                 mp->mnt_flag |= MNT_EXPORTED;
  719         }
  720         return 0;
  721 }
  722 
  723 /*
  724  * Set the publicly exported filesystem (WebNFS).  Currently, only
  725  * one public filesystem is possible in the spec (RFC 2054 and 2055)
  726  */
  727 static int
  728 setpublicfs(struct mount *mp, struct netexport *nep,
  729     const struct export_args *argp)
  730 {
  731         char *cp;
  732         int error;
  733         struct vnode *rvp;
  734         size_t fhsize;
  735 
  736         /*
  737          * mp == NULL -> invalidate the current info, the FS is
  738          * no longer exported. May be called from either export
  739          * or unmount, so check if it hasn't already been done.
  740          */
  741         if (mp == NULL) {
  742                 if (nfs_pub.np_valid) {
  743                         nfs_pub.np_valid = 0;
  744                         if (nfs_pub.np_handle != NULL) {
  745                                 free(nfs_pub.np_handle, M_TEMP);
  746                                 nfs_pub.np_handle = NULL;
  747                         }
  748                         if (nfs_pub.np_index != NULL) {
  749                                 free(nfs_pub.np_index, M_TEMP);
  750                                 nfs_pub.np_index = NULL;
  751                         }
  752                 }
  753                 return 0;
  754         }
  755 
  756         /*
  757          * Only one allowed at a time.
  758          */
  759         if (nfs_pub.np_valid != 0 && mp != nfs_pub.np_mount)
  760                 return EBUSY;
  761 
  762         /*
  763          * Get real filehandle for root of exported FS.
  764          */
  765         if ((error = VFS_ROOT(mp, &rvp)))
  766                 return error;
  767 
  768         fhsize = 0;
  769         error = vfs_composefh(rvp, NULL, &fhsize);
  770         if (error != E2BIG)
  771                 return error;
  772         nfs_pub.np_handle = malloc(fhsize, M_TEMP, M_NOWAIT);
  773         if (nfs_pub.np_handle == NULL)
  774                 error = ENOMEM;
  775         else
  776                 error = vfs_composefh(rvp, nfs_pub.np_handle, &fhsize);
  777         if (error)
  778                 return error;
  779 
  780         vput(rvp);
  781 
  782         /*
  783          * If an indexfile was specified, pull it in.
  784          */
  785         if (argp->ex_indexfile != NULL) {
  786                 nfs_pub.np_index = malloc(MAXNAMLEN + 1, M_TEMP, M_WAITOK);
  787                 error = copyinstr(argp->ex_indexfile, nfs_pub.np_index,
  788                     MAXNAMLEN, (size_t *)0);
  789                 if (!error) {
  790                         /*
  791                          * Check for illegal filenames.
  792                          */
  793                         for (cp = nfs_pub.np_index; *cp; cp++) {
  794                                 if (*cp == '/') {
  795                                         error = EINVAL;
  796                                         break;
  797                                 }
  798                         }
  799                 }
  800                 if (error) {
  801                         free(nfs_pub.np_index, M_TEMP);
  802                         return error;
  803                 }
  804         }
  805 
  806         nfs_pub.np_mount = mp;
  807         nfs_pub.np_valid = 1;
  808         return 0;
  809 }
  810 
  811 /*
  812  * Lookup an export entry in the exports list that matches the address
  813  * stored in 'nam'.  If no entry is found, the default one is used instead
  814  * (if available).
  815  */
  816 static struct netcred *
  817 netcred_lookup(struct netexport *ne, struct mbuf *nam)
  818 {
  819         struct netcred *np;
  820         struct radix_node_head *rnh;
  821         struct sockaddr *saddr;
  822 
  823         if ((ne->ne_mount->mnt_flag & MNT_EXPORTED) == 0) {
  824                 return NULL;
  825         }
  826 
  827         /*
  828          * Lookup in the export list first.
  829          */
  830         np = NULL;
  831         if (nam != NULL) {
  832                 saddr = mtod(nam, struct sockaddr *);
  833                 rnh = ne->ne_rtable[saddr->sa_family];
  834                 if (rnh != NULL) {
  835                         np = (struct netcred *)
  836                                 (*rnh->rnh_matchaddr)((void *)saddr,
  837                                                       rnh);
  838                         if (np && np->netc_rnodes->rn_flags & RNF_ROOT)
  839                                 np = NULL;
  840                 }
  841         }
  842         /*
  843          * If no address match, use the default if it exists.
  844          */
  845         if (np == NULL && ne->ne_mount->mnt_flag & MNT_DEFEXPORTED)
  846                 np = &ne->ne_defexported;
  847 
  848         return np;
  849 }
  850 
  851 void
  852 netexport_rdlock(void)
  853 {
  854 
  855         rw_enter(&netexport_lock, RW_READER);
  856 }
  857 
  858 void
  859 netexport_rdunlock(void)
  860 {
  861 
  862         rw_exit(&netexport_lock);
  863 }
  864 
  865 static void
  866 netexport_wrlock(void)
  867 {
  868 
  869         rw_enter(&netexport_lock, RW_WRITER);
  870 }
  871 
  872 static void
  873 netexport_wrunlock(void)
  874 {
  875 
  876         rw_exit(&netexport_lock);
  877 }

Cache object: b317bc53684c65587c1cb6aff4efde43


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.