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  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: nfs_export.c,v 1.22.2.1 2007/02/17 23:27:51 tron 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.22.2.1 2007/02/17 23:27:51 tron Exp $");
   86 
   87 #include "opt_compat_netbsd.h"
   88 #include "opt_inet.h"
   89 
   90 #include <sys/param.h>
   91 #include <sys/systm.h>
   92 #include <sys/queue.h>
   93 #include <sys/proc.h>
   94 #include <sys/mount.h>
   95 #include <sys/vnode.h>
   96 #include <sys/namei.h>
   97 #include <sys/errno.h>
   98 #include <sys/malloc.h>
   99 #include <sys/domain.h>
  100 #include <sys/mbuf.h>
  101 #include <sys/dirent.h>
  102 #include <sys/socket.h>         /* XXX for AF_MAX */
  103 #include <sys/kauth.h>
  104 
  105 #include <net/radix.h>
  106 
  107 #include <netinet/in.h>
  108 
  109 #include <nfs/rpcv2.h>
  110 #include <nfs/nfsproto.h>
  111 #include <nfs/nfs.h>
  112 #include <nfs/nfs_var.h>
  113 
  114 /*
  115  * Network address lookup element.
  116  */
  117 struct netcred {
  118         struct  radix_node netc_rnodes[2];
  119         int     netc_refcnt;
  120         int     netc_exflags;
  121         kauth_cred_t netc_anon;
  122 };
  123 
  124 /*
  125  * Network export information.
  126  */
  127 struct netexport {
  128         CIRCLEQ_ENTRY(netexport) ne_list;
  129         struct mount *ne_mount;
  130         struct netcred ne_defexported;                /* Default export */
  131         struct radix_node_head *ne_rtable[AF_MAX+1]; /* Individual exports */
  132 };
  133 CIRCLEQ_HEAD(, netexport) netexport_list =
  134     CIRCLEQ_HEAD_INITIALIZER(netexport_list);
  135 
  136 /* Malloc type used by the mount<->netexport map. */
  137 MALLOC_DEFINE(M_NFS_EXPORT, "nfs_export", "NFS export data");
  138 
  139 /* Publicly exported file system. */
  140 struct nfs_public nfs_pub;
  141 
  142 /*
  143  * Local prototypes.
  144  */
  145 static int init_exports(struct mount *, struct netexport **);
  146 static int hang_addrlist(struct mount *, struct netexport *,
  147     const struct export_args *);
  148 static int sacheck(struct sockaddr *);
  149 static int free_netcred(struct radix_node *, void *);
  150 static int export(struct netexport *, const struct export_args *);
  151 static int setpublicfs(struct mount *, struct netexport *,
  152     const struct export_args *);
  153 static struct netcred *netcred_lookup(struct netexport *, struct mbuf *);
  154 static struct netexport *netexport_lookup(const struct mount *);
  155 static struct netexport *netexport_lookup_byfsid(const fsid_t *);
  156 static void netexport_clear(struct netexport *);
  157 static void netexport_insert(struct netexport *);
  158 static void netexport_remove(struct netexport *);
  159 static void netexport_wrlock(void);
  160 static void netexport_wrunlock(void);
  161 
  162 /*
  163  * PUBLIC INTERFACE
  164  */
  165 
  166 /*
  167  * Declare and initialize the file system export hooks.
  168  */
  169 static void nfs_export_unmount(struct mount *);
  170 
  171 struct vfs_hooks nfs_export_hooks = {
  172         nfs_export_unmount
  173 };
  174 VFS_HOOKS_ATTACH(nfs_export_hooks);
  175 
  176 /*
  177  * VFS unmount hook for NFS exports.
  178  *
  179  * Releases NFS exports list resources if the given mount point has some.
  180  * As allocation happens lazily, it may be that it doesn't has this
  181  * information, although it theorically should.
  182  */
  183 static void
  184 nfs_export_unmount(struct mount *mp)
  185 {
  186         struct netexport *ne;
  187 
  188         KASSERT(mp != NULL);
  189 
  190         netexport_wrlock();
  191         ne = netexport_lookup(mp);
  192         if (ne == NULL) {
  193                 netexport_wrunlock();
  194                 return;
  195         }
  196         netexport_clear(ne);
  197         netexport_remove(ne);
  198         netexport_wrunlock();
  199         free(ne, M_NFS_EXPORT);
  200 }
  201 
  202 /*
  203  * Atomically set the NFS exports list of the given file system, replacing
  204  * it with a new list of entries.
  205  *
  206  * Returns zero on success or an appropriate error code otherwise.
  207  *
  208  * Helper function for the nfssvc(2) system call (NFSSVC_SETEXPORTSLIST
  209  * command).
  210  */
  211 int
  212 mountd_set_exports_list(const struct mountd_exports_list *mel, struct lwp *l)
  213 {
  214         int error;
  215 #ifdef notyet
  216         /* XXX: See below to see the reason why this is disabled. */
  217         size_t i;
  218 #endif
  219         struct mount *mp;
  220         struct netexport *ne;
  221         struct nameidata nd;
  222         struct vnode *vp;
  223         struct fid *fid;
  224         size_t fid_size;
  225 
  226         if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
  227             &l->l_acflag) != 0)
  228                 return EPERM;
  229 
  230         /* Lookup the file system path. */
  231         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, mel->mel_path, l);
  232         error = namei(&nd);
  233         if (error != 0)
  234                 return error;
  235         vp = nd.ni_vp;
  236         mp = vp->v_mount;
  237 
  238         fid_size = 0;
  239         if ((error = VFS_VPTOFH(vp, NULL, &fid_size)) == E2BIG) {
  240                 fid = malloc(fid_size, M_TEMP, M_NOWAIT);
  241                 if (fid != NULL) {
  242                         error = VFS_VPTOFH(vp, fid, &fid_size);
  243                         free(fid, M_TEMP);
  244                 }
  245         }
  246         if (error != 0) {
  247                 vput(vp);
  248                 return EOPNOTSUPP;
  249         }
  250 
  251         /* Mark the file system busy. */
  252         error = vfs_busy(mp, LK_NOWAIT, NULL);
  253         vput(vp);
  254         if (error != 0)
  255                 return error;
  256 
  257         netexport_wrlock();
  258         ne = netexport_lookup(mp);
  259         if (ne == NULL) {
  260                 error = init_exports(mp, &ne);
  261                 if (error != 0) {
  262                         goto out;
  263                 }
  264         }
  265 
  266         KASSERT(ne != NULL);
  267         KASSERT(ne->ne_mount == mp);
  268 
  269         /*
  270          * XXX: The part marked as 'notyet' works fine from the kernel's
  271          * point of view, in the sense that it is able to atomically update
  272          * the complete exports list for a file system.  However, supporting
  273          * this in mountd(8) requires a lot of work; so, for now, keep the
  274          * old behavior of updating a single entry per call.
  275          *
  276          * When mountd(8) is fixed, just remove the second branch of this
  277          * preprocessor conditional and enable the first one.
  278          */
  279 #ifdef notyet
  280         netexport_clear(ne);
  281         for (i = 0; error == 0 && i < mel->mel_nexports; i++)
  282                 error = export(ne, &mel->mel_exports[i]);
  283 #else
  284         if (mel->mel_nexports == 0)
  285                 netexport_clear(ne);
  286         else if (mel->mel_nexports == 1)
  287                 error = export(ne, &mel->mel_exports[0]);
  288         else {
  289                 printf("mountd_set_exports_list: Cannot set more than one "
  290                     "entry at once (unimplemented)\n");
  291                 error = EOPNOTSUPP;
  292         }
  293 #endif
  294 
  295 out:
  296         netexport_wrunlock();
  297         vfs_unbusy(mp);
  298         return error;
  299 }
  300 
  301 static void
  302 netexport_insert(struct netexport *ne)
  303 {
  304 
  305         CIRCLEQ_INSERT_HEAD(&netexport_list, ne, ne_list);
  306 }
  307 
  308 static void
  309 netexport_remove(struct netexport *ne)
  310 {
  311 
  312         CIRCLEQ_REMOVE(&netexport_list, ne, ne_list);
  313 }
  314 
  315 static struct netexport *
  316 netexport_lookup(const struct mount *mp)
  317 {
  318         struct netexport *ne;
  319 
  320         CIRCLEQ_FOREACH(ne, &netexport_list, ne_list) {
  321                 if (ne->ne_mount == mp) {
  322                         goto done;
  323                 }
  324         }
  325         ne = NULL;
  326 done:
  327         return ne;
  328 }
  329 
  330 static struct netexport *
  331 netexport_lookup_byfsid(const fsid_t *fsid)
  332 {
  333         struct netexport *ne;
  334 
  335         CIRCLEQ_FOREACH(ne, &netexport_list, ne_list) {
  336                 const struct mount *mp = ne->ne_mount;
  337 
  338                 if (mp->mnt_stat.f_fsidx.__fsid_val[0] == fsid->__fsid_val[0] &&
  339                     mp->mnt_stat.f_fsidx.__fsid_val[1] == fsid->__fsid_val[1]) {
  340                         goto done;
  341                 }
  342         }
  343         ne = NULL;
  344 done:
  345 
  346         return ne;
  347 }
  348 
  349 /*
  350  * Check if the file system specified by the 'mp' mount structure is
  351  * exported to a client with 'anon' anonymous credentials.  The 'mb'
  352  * argument is an mbuf containing the network address of the client.
  353  * The return parameters for the export flags for the client are returned
  354  * in the address specified by 'wh'.
  355  *
  356  * This function is used exclusively by the NFS server.  It is generally
  357  * invoked before VFS_FHTOVP to validate that client has access to the
  358  * file system.
  359  */
  360 
  361 int
  362 netexport_check(const fsid_t *fsid, struct mbuf *mb, struct mount **mpp,
  363     int *wh, kauth_cred_t *anon)
  364 {
  365         struct netexport *ne;
  366         struct netcred *np;
  367 
  368         ne = netexport_lookup_byfsid(fsid);
  369         if (ne == NULL) {
  370                 return EACCES;
  371         }
  372         np = netcred_lookup(ne, mb);
  373         if (np == NULL) {
  374                 return EACCES;
  375         }
  376 
  377         *mpp = ne->ne_mount;
  378         *wh = np->netc_exflags;
  379         *anon = np->netc_anon;
  380 
  381         return 0;
  382 }
  383 
  384 #ifdef COMPAT_30
  385 /*
  386  * Handles legacy export requests.  In this case, the export information
  387  * is hardcoded in a specific place of the mount arguments structure (given
  388  * in data); the request for an update is given through the fspec field
  389  * (also in a known location), which must be a null pointer.
  390  *
  391  * Returns EJUSTRETURN if the given command was not a export request.
  392  * Otherwise, returns 0 on success or an appropriate error code otherwise.
  393  */
  394 int
  395 nfs_update_exports_30(struct mount *mp, const char *path, void *data,
  396     struct lwp *l)
  397 {
  398         int error;
  399         struct {
  400                 const char *fspec;
  401                 struct export_args30 eargs;
  402         } args;
  403         struct mountd_exports_list mel;
  404 
  405         mel.mel_path = path;
  406 
  407         error = copyin(data, &args, sizeof(args));
  408         if (error != 0)
  409                 return EJUSTRETURN;
  410 
  411         if (args.fspec != NULL)
  412                 return EJUSTRETURN;
  413 
  414         if (args.eargs.ex_flags & 0x00020000) {
  415                 /* Request to delete exports.  The mask above holds the
  416                  * value that used to be in MNT_DELEXPORT. */
  417                 mel.mel_nexports = 0;
  418         } else {
  419                 struct export_args eargs;
  420 
  421                 /* The following assumes export_args has not changed since
  422                  * export_args30. */
  423                 memcpy(&eargs, &args.eargs, sizeof(struct export_args));
  424 
  425                 mel.mel_nexports = 1;
  426                 mel.mel_exports = &eargs;
  427         }
  428 
  429         return mountd_set_exports_list(&mel, l);
  430 }
  431 #endif
  432 
  433 /*
  434  * INTERNAL FUNCTIONS
  435  */
  436 
  437 /*
  438  * Initializes NFS exports for the file system given in 'mp' if it supports
  439  * file handles; this is determined by checking whether mp's vfs_vptofh and
  440  * vfs_fhtovp operations are NULL or not.
  441  *
  442  * If successful, returns 0 and sets *mnpp to the address of the new
  443  * mount_netexport_pair item; otherwise returns an appropriate error code
  444  * and *mnpp remains unmodified.
  445  */
  446 static int
  447 init_exports(struct mount *mp, struct netexport **nep)
  448 {
  449         int error;
  450         struct export_args ea;
  451         struct netexport *ne;
  452 
  453         KASSERT(mp != NULL);
  454 
  455         /* Ensure that we do not already have this mount point. */
  456         KASSERT(netexport_lookup(mp) == NULL);
  457 
  458         ne = malloc(sizeof(*ne), M_NFS_EXPORT, M_WAITOK | M_ZERO);
  459         ne->ne_mount = mp;
  460 
  461         /* Set the default export entry.  Handled internally by export upon
  462          * first call. */
  463         memset(&ea, 0, sizeof(ea));
  464         ea.ex_root = -2;
  465         if (mp->mnt_flag & MNT_RDONLY)
  466                 ea.ex_flags |= MNT_EXRDONLY;
  467         error = export(ne, &ea);
  468         if (error != 0) {
  469                 free(ne, M_NFS_EXPORT);
  470         } else {
  471                 netexport_insert(ne);
  472                 *nep = ne;
  473         }
  474 
  475         return error;
  476 }
  477 
  478 /*
  479  * Build hash lists of net addresses and hang them off the mount point.
  480  * Called by export() to set up a new entry in the lists of export
  481  * addresses.
  482  */
  483 static int
  484 hang_addrlist(struct mount *mp, struct netexport *nep,
  485     const struct export_args *argp)
  486 {
  487         int error, i;
  488         struct netcred *np, *enp;
  489         struct radix_node_head *rnh;
  490         struct sockaddr *saddr, *smask;
  491         struct domain *dom;
  492 
  493         smask = NULL;
  494 
  495         if (argp->ex_addrlen == 0) {
  496                 if (mp->mnt_flag & MNT_DEFEXPORTED)
  497                         return EPERM;
  498                 np = &nep->ne_defexported;
  499                 KASSERT(np->netc_anon == NULL);
  500                 np->netc_anon = kauth_cred_alloc();
  501                 np->netc_exflags = argp->ex_flags;
  502                 kauth_uucred_to_cred(np->netc_anon, &argp->ex_anon);
  503                 mp->mnt_flag |= MNT_DEFEXPORTED;
  504                 return 0;
  505         }
  506 
  507         if (argp->ex_addrlen > MLEN || argp->ex_masklen > MLEN)
  508                 return EINVAL;
  509 
  510         i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen;
  511         np = malloc(i, M_NETADDR, M_WAITOK | M_ZERO);
  512         np->netc_anon = kauth_cred_alloc();
  513         saddr = (struct sockaddr *)(np + 1);
  514         error = copyin(argp->ex_addr, saddr, argp->ex_addrlen);
  515         if (error)
  516                 goto out;
  517         if (saddr->sa_len > argp->ex_addrlen)
  518                 saddr->sa_len = argp->ex_addrlen;
  519         if (sacheck(saddr) == -1)
  520                 return EINVAL;
  521         if (argp->ex_masklen) {
  522                 smask = (struct sockaddr *)((caddr_t)saddr + argp->ex_addrlen);
  523                 error = copyin(argp->ex_mask, smask, argp->ex_masklen);
  524                 if (error)
  525                         goto out;
  526                 if (smask->sa_len > argp->ex_masklen)
  527                         smask->sa_len = argp->ex_masklen;
  528                 if (smask->sa_family != saddr->sa_family)
  529                         return EINVAL;
  530                 if (sacheck(smask) == -1)
  531                         return EINVAL;
  532         }
  533         i = saddr->sa_family;
  534         if ((rnh = nep->ne_rtable[i]) == 0) {
  535                 /*
  536                  * Seems silly to initialize every AF when most are not
  537                  * used, do so on demand here
  538                  */
  539                 DOMAIN_FOREACH(dom) {
  540                         if (dom->dom_family == i && dom->dom_rtattach) {
  541                                 dom->dom_rtattach((void **)&nep->ne_rtable[i],
  542                                         dom->dom_rtoffset);
  543                                 break;
  544                         }
  545                 }
  546                 if ((rnh = nep->ne_rtable[i]) == 0) {
  547                         error = ENOBUFS;
  548                         goto out;
  549                 }
  550         }
  551 
  552         enp = (struct netcred *)(*rnh->rnh_addaddr)(saddr, smask, rnh,
  553             np->netc_rnodes);
  554         if (enp != np) {
  555                 if (enp == NULL) {
  556                         enp = (struct netcred *)(*rnh->rnh_lookup)(saddr,
  557                             smask, rnh);
  558                         if (enp == NULL) {
  559                                 error = EPERM;
  560                                 goto out;
  561                         }
  562                 } else
  563                         enp->netc_refcnt++;
  564 
  565                 goto check;
  566         } else
  567                 enp->netc_refcnt = 1;
  568 
  569         np->netc_exflags = argp->ex_flags;
  570         kauth_uucred_to_cred(np->netc_anon, &argp->ex_anon);
  571         return 0;
  572 check:
  573         if (enp->netc_exflags != argp->ex_flags ||
  574             kauth_cred_uucmp(enp->netc_anon, &argp->ex_anon) != 0)
  575                 error = EPERM;
  576         else
  577                 error = 0;
  578 out:
  579         KASSERT(np->netc_anon != NULL);
  580         kauth_cred_free(np->netc_anon);
  581         free(np, M_NETADDR);
  582         return error;
  583 }
  584 
  585 /*
  586  * Ensure that the address stored in 'sa' is valid.
  587  * Returns zero on success, otherwise -1.
  588  */
  589 static int
  590 sacheck(struct sockaddr *sa)
  591 {
  592 
  593         switch (sa->sa_family) {
  594 #ifdef INET
  595         case AF_INET: {
  596                 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
  597                 char *p = (char *)sin->sin_zero;
  598                 size_t i;
  599 
  600                 if (sin->sin_len != sizeof(*sin))
  601                         return -1;
  602                 if (sin->sin_port != 0)
  603                         return -1;
  604                 for (i = 0; i < sizeof(sin->sin_zero); i++)
  605                         if (*p++ != '\0')
  606                                 return -1;
  607                 return 0;
  608         }
  609 #endif
  610 #ifdef INET6
  611         case AF_INET6: {
  612                 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
  613 
  614                 if (sin6->sin6_len != sizeof(*sin6))
  615                         return -1;
  616                 if (sin6->sin6_port != 0)
  617                         return -1;
  618                 return 0;
  619         }
  620 #endif
  621         default:
  622                 return -1;
  623         }
  624 }
  625 
  626 /*
  627  * Free the netcred object pointed to by the 'rn' radix node.
  628  * 'w' holds a pointer to the radix tree head.
  629  */
  630 static int
  631 free_netcred(struct radix_node *rn, void *w)
  632 {
  633         struct radix_node_head *rnh = (struct radix_node_head *)w;
  634         struct netcred *np = (struct netcred *)(void *)rn;
  635 
  636         (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh);
  637         if (--(np->netc_refcnt) <= 0) {
  638                 KASSERT(np->netc_anon != NULL);
  639                 kauth_cred_free(np->netc_anon);
  640                 free(np, M_NETADDR);
  641         }
  642         return 0;
  643 }
  644 
  645 /*
  646  * Clears the exports list for a given file system.
  647  */
  648 static void
  649 netexport_clear(struct netexport *ne)
  650 {
  651         struct radix_node_head *rnh;
  652         struct mount *mp = ne->ne_mount;
  653         int i;
  654 
  655         if (mp->mnt_flag & MNT_EXPUBLIC) {
  656                 setpublicfs(NULL, NULL, NULL);
  657                 mp->mnt_flag &= ~MNT_EXPUBLIC;
  658         }
  659 
  660         for (i = 0; i <= AF_MAX; i++) {
  661                 if ((rnh = ne->ne_rtable[i]) != NULL) {
  662                         (*rnh->rnh_walktree)(rnh, free_netcred, rnh);
  663                         free(rnh, M_RTABLE);
  664                         ne->ne_rtable[i] = NULL;
  665                 }
  666         }
  667 
  668         if ((mp->mnt_flag & MNT_DEFEXPORTED) != 0) {
  669                 struct netcred *np = &ne->ne_defexported;
  670 
  671                 KASSERT(np->netc_anon != NULL);
  672                 kauth_cred_free(np->netc_anon);
  673                 np->netc_anon = NULL;
  674         } else {
  675                 KASSERT(ne->ne_defexported.netc_anon == NULL);
  676         }
  677 
  678         mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED);
  679 }
  680 
  681 /*
  682  * Add a new export entry (described by an export_args structure) to the
  683  * given file system.
  684  */
  685 static int
  686 export(struct netexport *nep, const struct export_args *argp)
  687 {
  688         struct mount *mp = nep->ne_mount;
  689         int error;
  690 
  691         if (argp->ex_flags & MNT_EXPORTED) {
  692                 if (argp->ex_flags & MNT_EXPUBLIC) {
  693                         if ((error = setpublicfs(mp, nep, argp)) != 0)
  694                                 return error;
  695                         mp->mnt_flag |= MNT_EXPUBLIC;
  696                 }
  697                 if ((error = hang_addrlist(mp, nep, argp)) != 0)
  698                         return error;
  699                 mp->mnt_flag |= MNT_EXPORTED;
  700         }
  701         return 0;
  702 }
  703 
  704 /*
  705  * Set the publicly exported filesystem (WebNFS).  Currently, only
  706  * one public filesystem is possible in the spec (RFC 2054 and 2055)
  707  */
  708 static int
  709 setpublicfs(struct mount *mp, struct netexport *nep,
  710     const struct export_args *argp)
  711 {
  712         char *cp;
  713         int error;
  714         struct vnode *rvp;
  715         size_t fhsize;
  716 
  717         /*
  718          * mp == NULL -> invalidate the current info, the FS is
  719          * no longer exported. May be called from either export
  720          * or unmount, so check if it hasn't already been done.
  721          */
  722         if (mp == NULL) {
  723                 if (nfs_pub.np_valid) {
  724                         nfs_pub.np_valid = 0;
  725                         if (nfs_pub.np_handle != NULL) {
  726                                 free(nfs_pub.np_handle, M_TEMP);
  727                                 nfs_pub.np_handle = NULL;
  728                         }
  729                         if (nfs_pub.np_index != NULL) {
  730                                 FREE(nfs_pub.np_index, M_TEMP);
  731                                 nfs_pub.np_index = NULL;
  732                         }
  733                 }
  734                 return 0;
  735         }
  736 
  737         /*
  738          * Only one allowed at a time.
  739          */
  740         if (nfs_pub.np_valid != 0 && mp != nfs_pub.np_mount)
  741                 return EBUSY;
  742 
  743         /*
  744          * Get real filehandle for root of exported FS.
  745          */
  746         if ((error = VFS_ROOT(mp, &rvp)))
  747                 return error;
  748 
  749         fhsize = 0;
  750         error = vfs_composefh(rvp, NULL, &fhsize);
  751         if (error != E2BIG)
  752                 return error;
  753         nfs_pub.np_handle = malloc(fhsize, M_TEMP, M_NOWAIT);
  754         if (nfs_pub.np_handle == NULL)
  755                 error = ENOMEM;
  756         else
  757                 error = vfs_composefh(rvp, nfs_pub.np_handle, &fhsize);
  758         if (error)
  759                 return error;
  760 
  761         vput(rvp);
  762 
  763         /*
  764          * If an indexfile was specified, pull it in.
  765          */
  766         if (argp->ex_indexfile != NULL) {
  767                 MALLOC(nfs_pub.np_index, char *, MAXNAMLEN + 1, M_TEMP,
  768                     M_WAITOK);
  769                 error = copyinstr(argp->ex_indexfile, nfs_pub.np_index,
  770                     MAXNAMLEN, (size_t *)0);
  771                 if (!error) {
  772                         /*
  773                          * Check for illegal filenames.
  774                          */
  775                         for (cp = nfs_pub.np_index; *cp; cp++) {
  776                                 if (*cp == '/') {
  777                                         error = EINVAL;
  778                                         break;
  779                                 }
  780                         }
  781                 }
  782                 if (error) {
  783                         FREE(nfs_pub.np_index, M_TEMP);
  784                         return error;
  785                 }
  786         }
  787 
  788         nfs_pub.np_mount = mp;
  789         nfs_pub.np_valid = 1;
  790         return 0;
  791 }
  792 
  793 /*
  794  * Lookup an export entry in the exports list that matches the address
  795  * stored in 'nam'.  If no entry is found, the default one is used instead
  796  * (if available).
  797  */
  798 static struct netcred *
  799 netcred_lookup(struct netexport *ne, struct mbuf *nam)
  800 {
  801         struct netcred *np;
  802         struct radix_node_head *rnh;
  803         struct sockaddr *saddr;
  804 
  805         if ((ne->ne_mount->mnt_flag & MNT_EXPORTED) == 0) {
  806                 return NULL;
  807         }
  808 
  809         /*
  810          * Lookup in the export list first.
  811          */
  812         np = NULL;
  813         if (nam != NULL) {
  814                 saddr = mtod(nam, struct sockaddr *);
  815                 rnh = ne->ne_rtable[saddr->sa_family];
  816                 if (rnh != NULL) {
  817                         np = (struct netcred *)
  818                                 (*rnh->rnh_matchaddr)((caddr_t)saddr,
  819                                                       rnh);
  820                         if (np && np->netc_rnodes->rn_flags & RNF_ROOT)
  821                                 np = NULL;
  822                 }
  823         }
  824         /*
  825          * If no address match, use the default if it exists.
  826          */
  827         if (np == NULL && ne->ne_mount->mnt_flag & MNT_DEFEXPORTED)
  828                 np = &ne->ne_defexported;
  829 
  830         return np;
  831 }
  832 
  833 static struct lock netexport_lock = LOCK_INITIALIZER(PVFS, "netexp", 0, 0);
  834 
  835 void
  836 netexport_rdlock(void)
  837 {
  838 
  839         lockmgr(&netexport_lock, LK_SHARED, NULL);
  840 }
  841 
  842 void
  843 netexport_rdunlock(void)
  844 {
  845 
  846         lockmgr(&netexport_lock, LK_RELEASE, NULL);
  847 }
  848 
  849 static void
  850 netexport_wrlock(void)
  851 {
  852 
  853         lockmgr(&netexport_lock, LK_EXCLUSIVE, NULL);
  854 }
  855 
  856 static void
  857 netexport_wrunlock(void)
  858 {
  859 
  860         lockmgr(&netexport_lock, LK_RELEASE, NULL);
  861 }

Cache object: c438932d6599b73e28a7dcde2562c71b


[ 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.