3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  25  */
  26 
  27 /*
  28  *      Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989  AT&T.
  29  *              All rights reserved.
  30  */
  31 
  32 
  33 #include <sys/types.h>
  34 #include <sys/param.h>
  35 #include <sys/time.h>
  36 #include <sys/vfs.h>
  37 #include <sys/vnode.h>
  38 #include <sys/socket.h>
  39 #include <sys/errno.h>
  40 #include <sys/uio.h>
  41 #include <sys/proc.h>
  42 #include <sys/user.h>
  43 #include <sys/file.h>
  44 #include <sys/tiuser.h>
  45 #include <sys/kmem.h>
  46 #include <sys/pathname.h>
  47 #include <sys/debug.h>
  48 #include <sys/vtrace.h>
  49 #include <sys/cmn_err.h>
  50 #include <sys/acl.h>
  51 #include <sys/utsname.h>
  52 #include <sys/sdt.h>
  53 #include <netinet/in.h>
  54 #include <sys/avl.h>
  55 
  56 #include <rpc/types.h>
  57 #include <rpc/auth.h>
  58 #include <rpc/svc.h>
  59 
  60 #include <nfs/nfs.h>
  61 #include <nfs/export.h>
  62 #include <nfs/nfssys.h>
  63 #include <nfs/nfs_clnt.h>
  64 #include <nfs/nfs_acl.h>
  65 #include <nfs/nfs_log.h>
  66 #include <nfs/lm.h>
  67 #include <sys/sunddi.h>
  68 #include <sys/pkp_hash.h>
  69 
  70 treenode_t *ns_root;
  71 
  72 struct exportinfo *exptable_path_hash[PKP_HASH_SIZE];
  73 struct exportinfo *exptable[EXPTABLESIZE];
  74 
  75 static int      unexport(exportinfo_t *);
  76 static void     exportfree(exportinfo_t *);
  77 static int      loadindex(exportdata_t *);
  78 
  79 extern void     nfsauth_cache_free(exportinfo_t *);
  80 extern int      sec_svc_loadrootnames(int, int, caddr_t **, model_t);
  81 extern void     sec_svc_freerootnames(int, int, caddr_t *);
  82 
  83 static int build_seclist_nodups(exportdata_t *, secinfo_t *, int);
  84 static void srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
  85 static void srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
  86 static void srv_secinfo_treeclimb(exportinfo_t *, secinfo_t *, int, bool_t);
  87 
  88 #ifdef VOLATILE_FH_TEST
  89 static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
  90 static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *);
  91 static void free_volrnm_list(exportinfo_t *);
  92 #endif /* VOLATILE_FH_TEST */
  93 
  94 /*
  95  * exported_lock        Read/Write lock that protects the exportinfo list.
  96  *                      This lock must be held when searching or modifiying
  97  *                      the exportinfo list.
  98  */
  99 krwlock_t exported_lock;
 100 
 101 /*
 102  * "public" and default (root) location for public filehandle
 103  */
 104 struct exportinfo *exi_public, *exi_root;
 105 
 106 fid_t exi_rootfid;      /* for checking the default public file handle */
 107 
 108 fhandle_t nullfh2;      /* for comparing V2 filehandles */
 109 
 110 /*
 111  * macro for static dtrace probes to trace server namespace ref count mods.
 112  */
 113 #define SECREF_TRACE(seclist, tag, flav, aftcnt) \
 114         DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
 115                 char *, (tag), int, (int)(flav), int, (int)(aftcnt))
 116 
 117 
 118 #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
 119 
 120 static uint8_t
 121 xor_hash(uint8_t *data, int len)
 122 {
 123         uint8_t h = 0;
 124 
 125         while (len--)
 126                 h ^= *data++;
 127 
 128         return (h);
 129 }
 130 
 131 /*
 132  * File handle hash function, XOR over all bytes in fsid and fid.
 133  */
 134 static unsigned
 135 nfs_fhhash(fsid_t *fsid, fid_t *fid)
 136 {
 137         int len;
 138         uint8_t h;
 139 
 
 676  * Find for given treenode the exportinfo which has its
 677  * exp_visible linked on its exi_visible list.
 678  *
 679  * Note: We could add new pointer either to treenode or
 680  * to exp_visible, which will point there directly.
 681  * This would buy some speed for some memory.
 682  */
 683 exportinfo_t *
 684 vis2exi(treenode_t *tnode)
 685 {
 686         exportinfo_t *exi_ret = NULL;
 687 
 688         for (;;) {
 689                 tnode = tnode->tree_parent;
 690                 if (TREE_ROOT(tnode)) {
 691                         exi_ret = tnode->tree_exi;
 692                         break;
 693                 }
 694         }
 695 
 696         ASSERT(exi_ret); /* Every visible should have its home exportinfo */
 697         return (exi_ret);
 698 }
 699 
 700 /*
 701  * For NFS V4.
 702  * Add or remove the newly exported or unexported security flavors of the
 703  * given exportinfo from its ancestors upto the system root.
 704  */
 705 void
 706 srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt,
 707     bool_t isadd)
 708 {
 709         treenode_t *tnode = exip->exi_tree;
 710 
 711         ASSERT(RW_WRITE_HELD(&exported_lock));
 712         ASSERT(tnode != NULL);
 713 
 714         if (seccnt == 0)
 715                 return;
 716 
 717         /*
 718          * If flavors are being added and the new export root isn't
 719          * also VROOT, its implicitly allowed flavors are inherited from
 720          * its pseudonode.
 721          * Note - for VROOT exports the implicitly allowed flavors were
 722          * transferred from the PSEUDO export in exportfs()
 723          */
 724         if (isadd && !(exip->exi_vp->v_flag & VROOT) &&
 725             tnode->tree_vis->vis_seccnt > 0) {
 726                 srv_secinfo_add(&exip->exi_export.ex_secinfo,
 727                     &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
 728                     tnode->tree_vis->vis_seccnt, FALSE);
 729         }
 730 
 731         /*
 732          * Move to parent node and propagate sec flavor
 733          * to exportinfo and to visible structures.
 734          */
 735         tnode = tnode->tree_parent;
 736 
 737         while (tnode != NULL) {
 738 
 739                 /* If there is exportinfo, update it */
 740                 if (tnode->tree_exi != NULL) {
 741                         secinfo_t **pxsec =
 742                             &tnode->tree_exi->exi_export.ex_secinfo;
 743                         int *pxcnt = &tnode->tree_exi->exi_export.ex_seccnt;
 744                         int is_pseudo = PSEUDO(tnode->tree_exi);
 
 765 
 766 /* hash_name is a text substitution for either fid_hash or path_hash */
 767 #define exp_hash_unlink(exi, hash_name) \
 768         if (*(exi)->hash_name.bckt == (exi)) \
 769                 *(exi)->hash_name.bckt = (exi)->hash_name.next; \
 770         if ((exi)->hash_name.prev) \
 771                 (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
 772         if ((exi)->hash_name.next) \
 773                 (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
 774         (exi)->hash_name.bckt = NULL;
 775 
 776 #define exp_hash_link(exi, hash_name, bucket) \
 777         (exi)->hash_name.bckt = (bucket); \
 778         (exi)->hash_name.prev = NULL; \
 779         (exi)->hash_name.next = *(bucket); \
 780         if ((exi)->hash_name.next) \
 781                 (exi)->hash_name.next->hash_name.prev = (exi); \
 782         *(bucket) = (exi);
 783 
 784 void
 785 export_link(exportinfo_t *exi)
 786 {
 787         exportinfo_t **bckt;
 788 
 789         bckt = &exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
 790         exp_hash_link(exi, fid_hash, bckt);
 791 
 792         bckt = &exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
 793             strlen(exi->exi_export.ex_path))];
 794         exp_hash_link(exi, path_hash, bckt);
 795 }
 796 
 797 /*
 798  * Initialization routine for export routines. Should only be called once.
 799  */
 800 int
 801 nfs_exportinit(void)
 802 {
 803         int error;
 804         int i;
 805 
 806         rw_init(&exported_lock, NULL, RW_DEFAULT, NULL);
 807 
 808         /*
 809          * Allocate the place holder for the public file handle, which
 810          * is all zeroes. It is initially set to the root filesystem.
 811          */
 812         exi_root = kmem_zalloc(sizeof (*exi_root), KM_SLEEP);
 813         exi_public = exi_root;
 814 
 815         exi_root->exi_export.ex_flags = EX_PUBLIC;
 816         exi_root->exi_export.ex_pathlen = 1; /* length of "/" */
 817         exi_root->exi_export.ex_path =
 818             kmem_alloc(exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
 819         exi_root->exi_export.ex_path[0] = '/';
 820         exi_root->exi_export.ex_path[1] = '\0';
 821 
 822         exi_root->exi_count = 1;
 823         mutex_init(&exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 824 
 825         exi_root->exi_vp = rootdir;
 826         exi_rootfid.fid_len = MAXFIDSZ;
 827         error = vop_fid_pseudo(exi_root->exi_vp, &exi_rootfid);
 828         if (error) {
 829                 mutex_destroy(&exi_root->exi_lock);
 830                 kmem_free(exi_root, sizeof (*exi_root));
 831                 return (error);
 832         }
 833 
 834         /*
 835          * Initialize auth cache and auth cache lock
 836          */
 837         for (i = 0; i < AUTH_TABLESIZE; i++) {
 838                 exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
 839                     KM_SLEEP);
 840                 avl_create(exi_root->exi_cache[i], nfsauth_cache_clnt_compar,
 841                     sizeof (struct auth_cache_clnt),
 842                     offsetof(struct auth_cache_clnt, authc_link));
 843         }
 844         rw_init(&exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 845 
 846         /* setup the fhandle template */
 847         exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
 848         exi_root->exi_fh.fh_xlen = exi_rootfid.fid_len;
 849         bcopy(exi_rootfid.fid_data, exi_root->exi_fh.fh_xdata,
 850             exi_rootfid.fid_len);
 851         exi_root->exi_fh.fh_len = sizeof (exi_root->exi_fh.fh_data);
 852 
 853         /*
 854          * Publish the exportinfo in the hash table
 855          */
 856         export_link(exi_root);
 857 
 858         nfslog_init();
 859         ns_root = NULL;
 860 
 861         return (0);
 862 }
 863 
 864 /*
 865  * Finalization routine for export routines. Called to cleanup previously
 866  * initialization work when the NFS server module could not be loaded correctly.
 867  */
 868 void
 869 nfs_exportfini(void)
 870 {
 871         int i;
 872 
 873         /*
 874          * Deallocate the place holder for the public file handle.
 875          */
 876         srv_secinfo_list_free(exi_root->exi_export.ex_secinfo,
 877             exi_root->exi_export.ex_seccnt);
 878         mutex_destroy(&exi_root->exi_lock);
 879         rw_destroy(&exi_root->exi_cache_lock);
 880         for (i = 0; i < AUTH_TABLESIZE; i++) {
 881                 avl_destroy(exi_root->exi_cache[i]);
 882                 kmem_free(exi_root->exi_cache[i], sizeof (avl_tree_t));
 883         }
 884         kmem_free(exi_root, sizeof (*exi_root));
 885 
 886         rw_destroy(&exported_lock);
 887 }
 888 
 889 /*
 890  *  Check if 2 gss mechanism identifiers are the same.
 891  *
 892  *  return FALSE if not the same.
 893  *  return TRUE if the same.
 894  */
 895 static bool_t
 896 nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
 897 {
 898         if ((mech1->length == 0) && (mech2->length == 0))
 899                 return (TRUE);
 900 
 901         if (mech1->length != mech2->length)
 902                 return (FALSE);
 903 
 904         return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0);
 905 }
 906 
 907 /*
 908  *  This routine is used by rpc to map rpc security number
 909  *  to nfs specific security flavor number.
 910  *
 911  *  The gss callback prototype is
 912  *  callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *,
 913  *                              rpc_gss_lock_t *, void **),
 914  *  since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments
 915  *  we cast them to void.
 916  */
 917 /*ARGSUSED*/
 918 bool_t
 919 rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context,
 920     rpc_gss_lock_t *lock, void **cookie)
 921 {
 922         int i, j;
 923         rpc_gss_rawcred_t *raw_cred;
 924         struct exportinfo *exi;
 925 
 926         /*
 927          * We don't deal with delegated credentials.
 928          */
 929         if (deleg != GSS_C_NO_CREDENTIAL)
 930                 return (FALSE);
 931 
 932         raw_cred = lock->raw_cred;
 933         *cookie = NULL;
 934 
 935         rw_enter(&exported_lock, RW_READER);
 936         for (i = 0; i < EXPTABLESIZE; i++) {
 937                 exi = exptable[i];
 938                 while (exi) {
 939                         if (exi->exi_export.ex_seccnt > 0) {
 940                                 struct secinfo *secp;
 941                                 seconfig_t *se;
 942                                 int seccnt;
 943 
 944                                 secp = exi->exi_export.ex_secinfo;
 945                                 seccnt = exi->exi_export.ex_seccnt;
 946                                 for (j = 0; j < seccnt; j++) {
 947                                         /*
 948                                          *  If there is a map of the triplet
 949                                          *  (mechanism, service, qop) between
 950                                          *  raw_cred and the exported flavor,
 951                                          *  get the psudo flavor number.
 952                                          *  Also qop should not be NULL, it
 953                                          *  should be "default" or something
 954                                          *  else.
 955                                          */
 956                                         se = &secp[j].s_secinfo;
 957                                         if ((se->sc_rpcnum == RPCSEC_GSS) &&
 958 
 959                                             (nfs_mech_equal(
 960                                             se->sc_gss_mech_type,
 961                                             raw_cred->mechanism)) &&
 962 
 963                                             (se->sc_service ==
 964                                             raw_cred->service) &&
 965                                             (raw_cred->qop == se->sc_qop)) {
 966 
 967                                                 *cookie = (void *)(uintptr_t)
 968                                                     se->sc_nfsnum;
 969                                                 goto done;
 970                                         }
 971                                 }
 972                         }
 973                         exi = exi->fid_hash.next;
 974                 }
 975         }
 976 done:
 977         rw_exit(&exported_lock);
 978 
 979         /*
 980          * If no nfs pseudo number mapping can be found in the export
 981          * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
 982          * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
 983          *
 984          * For example:
 985          *      server first shares with krb5i;
 986          *      client mounts with krb5i;
 987          *      server re-shares with krb5p;
 988          *      client tries with krb5i, but no mapping can be found;
 989          *      rpcsec_gss module calls this routine to do the mapping,
 990          *              if this routine fails, request is rejected from
 991          *              the rpc layer.
 992          *      What we need is to let the nfs layer rejects the request.
 993          *      For V4, we can reject with NFS4ERR_WRONGSEC and the client
 994          *      may recover from it by getting the new flavor via SECINFO.
 995          *
 996          * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf)
 997          * is owned by IANA (see RFC 2623).
 
1024         fid_t fid;
1025         fsid_t fsid;
1026         int error;
1027         size_t allocsize;
1028         struct secinfo *sp;
1029         struct secinfo *exs;
1030         rpc_gss_callback_t cb;
1031         char *pathbuf;
1032         char *log_buffer;
1033         char *tagbuf;
1034         int callback;
1035         int allocd_seccnt;
1036         STRUCT_HANDLE(exportfs_args, uap);
1037         STRUCT_DECL(exportdata, uexi);
1038         struct secinfo newsec[MAX_FLAVORS];
1039         int newcnt;
1040         struct secinfo oldsec[MAX_FLAVORS];
1041         int oldcnt;
1042         int i;
1043         struct pathname lookpn;
1044 
1045         STRUCT_SET_HANDLE(uap, model, args);
1046 
1047         /* Read in pathname from userspace */
1048         if (error = pn_get(STRUCT_FGETP(uap, dname), UIO_USERSPACE, &lookpn))
1049                 return (error);
1050 
1051         /* Walk the export list looking for that pathname */
1052         rw_enter(&exported_lock, RW_READER);
1053         DTRACE_PROBE(nfss__i__exported_lock1_start);
1054         for (ex1 = exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
1055             strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) {
1056                 if (ex1 != exi_root && 0 ==
1057                     strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) {
1058                         exi_hold(ex1);
1059                         break;
1060                 }
1061         }
1062         DTRACE_PROBE(nfss__i__exported_lock1_stop);
1063         rw_exit(&exported_lock);
1064 
1065         /* Is this an unshare? */
1066         if (STRUCT_FGETP(uap, uex) == NULL) {
1067                 pn_free(&lookpn);
1068                 if (ex1 == NULL)
1069                         return (EINVAL);
1070                 error = unexport(ex1);
1071                 exi_rele(ex1);
1072                 return (error);
1073         }
1074 
1075         /* It is a share or a re-share */
1076         error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1077             FOLLOW, &dvp, &vp);
1078         if (error == EINVAL) {
1079                 /*
1080                  * if fname resolves to / we get EINVAL error
1081                  * since we wanted the parent vnode. Try again
1082                  * with NULL dvp.
1083                  */
1084                 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1085                     FOLLOW, NULL, &vp);
1086                 dvp = NULL;
1087         }
1088         if (!error && vp == NULL) {
1089                 /* Last component of fname not found */
1090                 if (dvp != NULL)
 
1146         fsid = vp->v_vfsp->vfs_fsid;
1147 
1148         if (error) {
1149                 VN_RELE(vp);
1150                 if (dvp != NULL)
1151                         VN_RELE(dvp);
1152                 /*
1153                  * If VOP_FID returns ENOSPC then the fid supplied
1154                  * is too small.  For now we simply return EREMOTE.
1155                  */
1156                 if (error == ENOSPC)
1157                         error = EREMOTE;
1158                 pn_free(&lookpn);
1159                 return (error);
1160         }
1161 
1162         /*
1163          * Do not allow re-sharing a shared vnode under a different path
1164          * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it.
1165          */
1166         rw_enter(&exported_lock, RW_READER);
1167         DTRACE_PROBE(nfss__i__exported_lock2_start);
1168         for (ex2 = exptable[exptablehash(&fsid, &fid)]; ex2;
1169             ex2 = ex2->fid_hash.next) {
1170                 if (ex2 != exi_root && !PSEUDO(ex2) &&
1171                     VN_CMP(ex2->exi_vp, vp) &&
1172                     strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) {
1173                         DTRACE_PROBE(nfss__i__exported_lock2_stop);
1174                         rw_exit(&exported_lock);
1175                         VN_RELE(vp);
1176                         if (dvp != NULL)
1177                                 VN_RELE(dvp);
1178                         pn_free(&lookpn);
1179                         return (EEXIST);
1180                 }
1181         }
1182         DTRACE_PROBE(nfss__i__exported_lock2_stop);
1183         rw_exit(&exported_lock);
1184         pn_free(&lookpn);
1185 
1186         exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
1187         exi->exi_fsid = fsid;
1188         exi->exi_fid = fid;
1189         exi->exi_vp = vp;
1190         exi->exi_count = 1;
1191         exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1192             VSW_VOLATILEDEV) ? 1 : 0;
1193         mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
1194         exi->exi_dvp = dvp;
1195 
1196         /*
1197          * Initialize auth cache and auth cache lock
1198          */
1199         for (i = 0; i < AUTH_TABLESIZE; i++) {
1200                 exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
1201                 avl_create(exi->exi_cache[i], nfsauth_cache_clnt_compar,
1202                     sizeof (struct auth_cache_clnt),
1203                     offsetof(struct auth_cache_clnt, authc_link));
1204         }
1205         rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
1206 
1207         /*
1208          * Build up the template fhandle
1209          */
1210         exi->exi_fh.fh_fsid = fsid;
 
1444          * lock while dealing with the index option (as we do with
1445          * the public option).
1446          */
1447         if (kex->ex_flags & EX_INDEX) {
1448                 if (!kex->ex_index) {        /* sanity check */
1449                         error = EINVAL;
1450                         goto out5;
1451                 }
1452                 if (error = loadindex(kex))
1453                         goto out5;
1454         }
1455 
1456         if (kex->ex_flags & EX_LOG) {
1457                 if (error = nfslog_setup(exi))
1458                         goto out6;
1459         }
1460 
1461         /*
1462          * Insert the new entry at the front of the export list
1463          */
1464         rw_enter(&exported_lock, RW_WRITER);
1465         DTRACE_PROBE(nfss__i__exported_lock3_start);
1466 
1467         export_link(exi);
1468 
1469         /*
1470          * Check the rest of the list for an old entry for the fs.
1471          * If one is found then unlink it, wait until this is the
1472          * only reference and then free it.
1473          */
1474         for (ex = exi->fid_hash.next; ex != NULL; ex = ex->fid_hash.next) {
1475                 if (ex != exi_root && VN_CMP(ex->exi_vp, vp)) {
1476                         export_unlink(ex);
1477                         break;
1478                 }
1479         }
1480 
1481         /*
1482          * If the public filehandle is pointing at the
1483          * old entry, then point it back at the root.
1484          */
1485         if (ex != NULL && ex == exi_public)
1486                 exi_public = exi_root;
1487 
1488         /*
1489          * If the public flag is on, make the global exi_public
1490          * point to this entry and turn off the public bit so that
1491          * we can distinguish it from the place holder export.
1492          */
1493         if (kex->ex_flags & EX_PUBLIC) {
1494                 exi_public = exi;
1495                 kex->ex_flags &= ~EX_PUBLIC;
1496         }
1497 
1498 #ifdef VOLATILE_FH_TEST
1499         /*
1500          * Set up the volatile_id value if volatile on share.
1501          * The list of volatile renamed filehandles is always destroyed,
1502          * if the fs was reshared.
1503          */
1504         if (kex->ex_flags & EX_VOLFH)
1505                 exi->exi_volatile_id = gethrestime_sec();
1506 
1507         mutex_init(&exi->exi_vol_rename_lock, NULL, MUTEX_DEFAULT, NULL);
1508 #endif /* VOLATILE_FH_TEST */
1509 
1510         /*
1511          * If this is a new export, then climb up
1512          * the tree and check if any pseudo exports
1513          * need to be created to provide a path for
1514          * NFS v4 clients.
1515          */
1516         if (ex == NULL) {
1517                 error = treeclimb_export(exi);
1518                 if (error)
1519                         goto out7;
1520         } else {
1521                 /* If it's a re-export update namespace tree */
1522                 exi->exi_tree = ex->exi_tree;
1523                 exi->exi_tree->tree_exi = exi;
1524 
1525                 /* Update the change timestamp */
1526                 tree_update_change(exi->exi_tree, NULL);
1527         }
1528 
1529         /*
1530          * build a unique flavor list from the flavors specified
1531          * in the share cmd.  unique means that each flavor only
1532          * appears once in the secinfo list -- no duplicates allowed.
1533          */
1534         newcnt = build_seclist_nodups(&exi->exi_export, newsec, FALSE);
1535 
1536         srv_secinfo_treeclimb(exi, newsec, newcnt, TRUE);
1537 
1538         /*
1539          * If re-sharing an old export entry, update the secinfo data
1540          * depending on if the old entry is a pseudo node or not.
1541          */
1542         if (ex != NULL) {
1543                 oldcnt = build_seclist_nodups(&ex->exi_export, oldsec, FALSE);
1544                 if (PSEUDO(ex)) {
1545                         /*
1546                          * The dir being shared is a pseudo export root (which
1547                          * will be transformed into a real export root).  The
1548                          * flavor(s) of the new share were propagated to the
1549                          * ancestors by srv_secinfo_treeclimb() above.  Now
1550                          * transfer the implicit flavor refs from the old
1551                          * pseudo exprot root to the new (real) export root.
1552                          */
1553                         srv_secinfo_add(&exi->exi_export.ex_secinfo,
1554                             &exi->exi_export.ex_seccnt, oldsec, oldcnt, TRUE);
1555                 } else {
1556                         /*
1557                          * First transfer implicit flavor refs to new export.
1558                          * Remove old flavor refs last.
1559                          */
1560                         srv_secinfo_exp2exp(&exi->exi_export, oldsec, oldcnt);
1561                         srv_secinfo_treeclimb(ex, oldsec, oldcnt, FALSE);
1562                 }
1563         }
1564 
1565         /*
1566          * If it's a re-export and the old entry has a pseudonode list,
1567          * transfer it to the new export.
1568          */
1569         if (ex != NULL && (ex->exi_visible != NULL)) {
1570                 exi->exi_visible = ex->exi_visible;
1571                 ex->exi_visible = NULL;
1572         }
1573 
1574         DTRACE_PROBE(nfss__i__exported_lock3_stop);
1575         rw_exit(&exported_lock);
1576 
1577         if (exi_public == exi || kex->ex_flags & EX_LOG) {
1578                 /*
1579                  * Log share operation to this buffer only.
1580                  */
1581                 nfslog_share_record(exi, cr);
1582         }
1583 
1584         if (ex != NULL)
1585                 exi_rele(ex);
1586 
1587         return (0);
1588 
1589 out7:
1590         /* Unlink the new export in exptable. */
1591         export_unlink(exi);
1592         DTRACE_PROBE(nfss__i__exported_lock3_stop);
1593         rw_exit(&exported_lock);
1594 out6:
1595         if (kex->ex_flags & EX_INDEX)
1596                 kmem_free(kex->ex_index, strlen(kex->ex_index) + 1);
1597 out5:
1598         /* free partially completed allocation */
1599         while (--allocd_seccnt >= 0) {
1600                 exs = &kex->ex_secinfo[allocd_seccnt];
1601                 srv_secinfo_entry_free(exs);
1602         }
1603 
1604         if (kex->ex_secinfo) {
1605                 kmem_free(kex->ex_secinfo,
1606                     kex->ex_seccnt * sizeof (struct secinfo));
1607         }
1608 
1609 out4:
1610         if ((kex->ex_flags & EX_LOG) && kex->ex_tag != NULL)
1611                 kmem_free(kex->ex_tag, kex->ex_taglen + 1);
1612 out3:
1613         if ((kex->ex_flags & EX_LOG) && kex->ex_log_buffer != NULL)
 
1617 out1:
1618         VN_RELE(vp);
1619         if (dvp != NULL)
1620                 VN_RELE(dvp);
1621         mutex_destroy(&exi->exi_lock);
1622         rw_destroy(&exi->exi_cache_lock);
1623         for (i = 0; i < AUTH_TABLESIZE; i++) {
1624                 avl_destroy(exi->exi_cache[i]);
1625                 kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
1626         }
1627 
1628         kmem_free(exi, sizeof (*exi));
1629 
1630         return (error);
1631 }
1632 
1633 /*
1634  * Remove the exportinfo from the export list
1635  */
1636 void
1637 export_unlink(struct exportinfo *exi)
1638 {
1639         ASSERT(RW_WRITE_HELD(&exported_lock));
1640 
1641         exp_hash_unlink(exi, fid_hash);
1642         exp_hash_unlink(exi, path_hash);
1643 }
1644 
1645 /*
1646  * Unexport an exported filesystem
1647  */
1648 static int
1649 unexport(struct exportinfo *exi)
1650 {
1651         struct secinfo cursec[MAX_FLAVORS];
1652         int curcnt;
1653 
1654         rw_enter(&exported_lock, RW_WRITER);
1655 
1656         /* Check if exi is still linked in the export table */
1657         if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1658                 rw_exit(&exported_lock);
1659                 return (EINVAL);
1660         }
1661 
1662         export_unlink(exi);
1663 
1664         /*
1665          * Remove security flavors before treeclimb_unexport() is called
1666          * because srv_secinfo_treeclimb needs the namespace tree
1667          */
1668         curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
1669 
1670         srv_secinfo_treeclimb(exi, cursec, curcnt, FALSE);
1671 
1672         /*
1673          * If there's a visible list, then need to leave
1674          * a pseudo export here to retain the visible list
1675          * for paths to exports below.
1676          */
1677         if (exi->exi_visible != NULL) {
1678                 struct exportinfo *newexi;
1679 
1680                 newexi = pseudo_exportfs(exi->exi_vp, &exi->exi_fid,
1681                     exi->exi_visible, &exi->exi_export);
1682                 exi->exi_visible = NULL;
1683 
1684                 /* interconnect the existing treenode with the new exportinfo */
1685                 newexi->exi_tree = exi->exi_tree;
1686                 newexi->exi_tree->tree_exi = newexi;
1687 
1688                 /* Update the change timestamp */
1689                 tree_update_change(exi->exi_tree, NULL);
1690         } else {
1691                 treeclimb_unexport(exi);
1692         }
1693 
1694         rw_exit(&exported_lock);
1695 
1696         /*
1697          * Need to call into the NFSv4 server and release all data
1698          * held on this particular export.  This is important since
1699          * the v4 server may be holding file locks or vnodes under
1700          * this export.
1701          */
1702         rfs4_clean_state_exi(exi);
1703 
1704         /*
1705          * Notify the lock manager that the filesystem is being
1706          * unexported.
1707          */
1708         lm_unexport(exi);
1709 
1710         /*
1711          * If this was a public export, restore
1712          * the public filehandle to the root.
1713          */
1714         if (exi == exi_public) {
1715                 exi_public = exi_root;
1716 
1717                 nfslog_share_record(exi_public, CRED());
1718         }
1719 
1720         if (exi->exi_export.ex_flags & EX_LOG) {
1721                 nfslog_unshare_record(exi, CRED());
1722         }
1723 
1724         exi_rele(exi);
1725         return (0);
1726 }
1727 
1728 /*
1729  * Get file handle system call.
1730  * Takes file name and returns a file handle for it.
1731  * Credentials must be verified before calling.
1732  */
1733 int
1734 nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
1735 {
1736         nfs_fh3 fh;
1737         char buf[NFS3_MAXFHSIZE];
1738         char *logptr, logbuf[NFS3_MAXFHSIZE];
1739         int l = NFS3_MAXFHSIZE;
1740         vnode_t *vp;
1741         vnode_t *dvp;
1742         struct exportinfo *exi;
 
1929                         break;
1930                 }
1931 
1932                 if (v4srv)
1933                         exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
1934                 else
1935                         exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
1936 
1937                 if (exi != NULL) {
1938                         /*
1939                          * Found the export info
1940                          */
1941                         break;
1942                 }
1943 
1944                 /*
1945                  * We have just failed finding a matching export.
1946                  * If we're at the root of this filesystem, then
1947                  * it's time to stop (with failure).
1948                  */
1949                 if (vp->v_flag & VROOT) {
1950                         error = EINVAL;
1951                         break;
1952                 }
1953 
1954                 if (walk != NULL)
1955                         (*walk)++;
1956 
1957                 /*
1958                  * Now, do a ".." up vp. If dvp is supplied, use it,
1959                  * otherwise, look it up.
1960                  */
1961                 if (dvp == NULL) {
1962                         error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
1963                             NULL, NULL, NULL);
1964                         if (error)
1965                                 break;
1966                 }
1967                 VN_RELE(vp);
1968                 vp = dvp;
1969                 dvp = NULL;
 
2429 
2430         if (error || vp == NULL) {
2431                 *statp = NFS4ERR_STALE;
2432                 return (NULL);
2433         }
2434         /* XXX - disgusting hack */
2435         if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR)
2436                 vp->v_type = VDIR;
2437         *statp = NFS4_OK;
2438         return (vp);
2439 }
2440 
2441 /*
2442  * Find the export structure associated with the given filesystem.
2443  * If found, then increment the ref count (exi_count).
2444  */
2445 struct exportinfo *
2446 checkexport(fsid_t *fsid, fid_t *fid)
2447 {
2448         struct exportinfo *exi;
2449 
2450         rw_enter(&exported_lock, RW_READER);
2451         for (exi = exptable[exptablehash(fsid, fid)];
2452             exi != NULL;
2453             exi = exi->fid_hash.next) {
2454                 if (exportmatch(exi, fsid, fid)) {
2455                         /*
2456                          * If this is the place holder for the
2457                          * public file handle, then return the
2458                          * real export entry for the public file
2459                          * handle.
2460                          */
2461                         if (exi->exi_export.ex_flags & EX_PUBLIC) {
2462                                 exi = exi_public;
2463                         }
2464 
2465                         exi_hold(exi);
2466                         rw_exit(&exported_lock);
2467                         return (exi);
2468                 }
2469         }
2470         rw_exit(&exported_lock);
2471         return (NULL);
2472 }
2473 
2474 
2475 /*
2476  * "old school" version of checkexport() for NFS4.  NFS4
2477  * rfs4_compound holds exported_lock for duration of compound
2478  * processing.  This version doesn't manipulate exi_count
2479  * since NFS4 breaks fundamental assumptions in the exi_count
2480  * design.
2481  */
2482 struct exportinfo *
2483 checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp)
2484 {
2485         struct exportinfo *exi;
2486 
2487         ASSERT(RW_LOCK_HELD(&exported_lock));
2488 
2489         for (exi = exptable[exptablehash(fsid, fid)];
2490             exi != NULL;
2491             exi = exi->fid_hash.next) {
2492                 if (exportmatch(exi, fsid, fid)) {
2493                         /*
2494                          * If this is the place holder for the
2495                          * public file handle, then return the
2496                          * real export entry for the public file
2497                          * handle.
2498                          */
2499                         if (exi->exi_export.ex_flags & EX_PUBLIC) {
2500                                 exi = exi_public;
2501                         }
2502 
2503                         /*
2504                          * If vp is given, check if vp is the
2505                          * same vnode as the exported node.
2506                          *
2507                          * Since VOP_FID of a lofs node returns the
2508                          * fid of its real node (ufs), the exported
2509                          * node for lofs and (pseudo) ufs may have
2510                          * the same fsid and fid.
2511                          */
2512                         if (vp == NULL || vp == exi->exi_vp)
2513                                 return (exi);
2514                 }
2515         }
2516 
2517         return (NULL);
2518 }
2519 
2520 /*
 
 | 
 
 
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  *      Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989  AT&T.
  28  *              All rights reserved.
  29  */
  30 
  31 /*
  32  * Copyright 2018 Nexenta Systems, Inc.
  33  */
  34 
  35 #include <sys/types.h>
  36 #include <sys/param.h>
  37 #include <sys/time.h>
  38 #include <sys/vfs.h>
  39 #include <sys/vnode.h>
  40 #include <sys/socket.h>
  41 #include <sys/errno.h>
  42 #include <sys/uio.h>
  43 #include <sys/proc.h>
  44 #include <sys/user.h>
  45 #include <sys/file.h>
  46 #include <sys/tiuser.h>
  47 #include <sys/kmem.h>
  48 #include <sys/pathname.h>
  49 #include <sys/debug.h>
  50 #include <sys/vtrace.h>
  51 #include <sys/cmn_err.h>
  52 #include <sys/acl.h>
  53 #include <sys/utsname.h>
  54 #include <sys/sdt.h>
  55 #include <netinet/in.h>
  56 #include <sys/avl.h>
  57 
  58 #include <rpc/types.h>
  59 #include <rpc/auth.h>
  60 #include <rpc/svc.h>
  61 
  62 #include <nfs/nfs.h>
  63 #include <nfs/export.h>
  64 #include <nfs/nfssys.h>
  65 #include <nfs/nfs_clnt.h>
  66 #include <nfs/nfs_acl.h>
  67 #include <nfs/nfs_log.h>
  68 #include <nfs/lm.h>
  69 #include <sys/sunddi.h>
  70 
  71 /*
  72  * exi_id support
  73  *
  74  * exi_id_next          The next exi_id available.
  75  * exi_id_overflow      The exi_id_next already overflowed, so we should
  76  *                      thoroughly check for duplicates.
  77  * exi_id_tree          AVL tree indexed by exi_id.
  78  * nfs_exi_id_lock      Lock to protect the export ID list
  79  *
  80  * All exi_id_next, exi_id_overflow, and exi_id_tree are protected by
  81  * nfs_exi_id_lock.
  82  */
  83 static int exi_id_next;
  84 static bool_t exi_id_overflow;
  85 avl_tree_t exi_id_tree;
  86 kmutex_t nfs_exi_id_lock;
  87 
  88 static int      unexport(nfs_export_t *, exportinfo_t *);
  89 static void     exportfree(exportinfo_t *);
  90 static int      loadindex(exportdata_t *);
  91 
  92 extern void     nfsauth_cache_free(exportinfo_t *);
  93 extern int      sec_svc_loadrootnames(int, int, caddr_t **, model_t);
  94 extern void     sec_svc_freerootnames(int, int, caddr_t *);
  95 
  96 static int      build_seclist_nodups(exportdata_t *, secinfo_t *, int);
  97 static void     srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
  98 static void     srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
  99 static void     srv_secinfo_treeclimb(nfs_export_t *, exportinfo_t *,
 100                     secinfo_t *, int, bool_t);
 101 
 102 #ifdef VOLATILE_FH_TEST
 103 static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
 104 static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *);
 105 static void     free_volrnm_list(exportinfo_t *);
 106 #endif /* VOLATILE_FH_TEST */
 107 
 108 fhandle_t nullfh2;      /* for comparing V2 filehandles */
 109 
 110 /*
 111  * macro for static dtrace probes to trace server namespace ref count mods.
 112  */
 113 #define SECREF_TRACE(seclist, tag, flav, aftcnt) \
 114         DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
 115                 char *, (tag), int, (int)(flav), int, (int)(aftcnt))
 116 
 117 
 118 #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
 119 
 120 extern nfs_export_t *
 121 nfs_get_export(void)
 122 {
 123         nfs_globals_t *ng = nfs_srv_getzg();
 124         nfs_export_t *ne = ng->nfs_export;
 125         ASSERT(ne != NULL);
 126         return (ne);
 127 }
 128 
 129 static uint8_t
 130 xor_hash(uint8_t *data, int len)
 131 {
 132         uint8_t h = 0;
 133 
 134         while (len--)
 135                 h ^= *data++;
 136 
 137         return (h);
 138 }
 139 
 140 /*
 141  * File handle hash function, XOR over all bytes in fsid and fid.
 142  */
 143 static unsigned
 144 nfs_fhhash(fsid_t *fsid, fid_t *fid)
 145 {
 146         int len;
 147         uint8_t h;
 148 
 
 685  * Find for given treenode the exportinfo which has its
 686  * exp_visible linked on its exi_visible list.
 687  *
 688  * Note: We could add new pointer either to treenode or
 689  * to exp_visible, which will point there directly.
 690  * This would buy some speed for some memory.
 691  */
 692 exportinfo_t *
 693 vis2exi(treenode_t *tnode)
 694 {
 695         exportinfo_t *exi_ret = NULL;
 696 
 697         for (;;) {
 698                 tnode = tnode->tree_parent;
 699                 if (TREE_ROOT(tnode)) {
 700                         exi_ret = tnode->tree_exi;
 701                         break;
 702                 }
 703         }
 704 
 705         /* Every visible should have its home exportinfo */
 706         ASSERT(exi_ret != NULL);
 707         return (exi_ret);
 708 }
 709 
 710 /*
 711  * For NFS V4.
 712  * Add or remove the newly exported or unexported security flavors of the
 713  * given exportinfo from its ancestors upto the system root.
 714  */
 715 static void
 716 srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
 717     int seccnt, bool_t isadd)
 718 {
 719         treenode_t *tnode;
 720 
 721         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 722 
 723         /*
 724          * exi_tree can be null for the zone root
 725          * which means we're already at the "top"
 726          * and there's nothing more to "climb".
 727          */
 728         tnode = exip->exi_tree;
 729         if (tnode == NULL) {
 730                 /* Should only happen for... */
 731                 ASSERT(exip == ne->exi_root);
 732                 return;
 733         }
 734 
 735         if (seccnt == 0)
 736                 return;
 737 
 738         /*
 739          * If flavors are being added and the new export root isn't
 740          * also VROOT, its implicitly allowed flavors are inherited from
 741          * its pseudonode.
 742          * Note - for VROOT exports the implicitly allowed flavors were
 743          * transferred from the PSEUDO export in exportfs()
 744          */
 745         if (isadd && !(exip->exi_vp->v_flag & VROOT) &&
 746             !VN_CMP(exip->exi_vp, EXI_TO_ZONEROOTVP(exip)) &&
 747             tnode->tree_vis->vis_seccnt > 0) {
 748                 srv_secinfo_add(&exip->exi_export.ex_secinfo,
 749                     &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
 750                     tnode->tree_vis->vis_seccnt, FALSE);
 751         }
 752 
 753         /*
 754          * Move to parent node and propagate sec flavor
 755          * to exportinfo and to visible structures.
 756          */
 757         tnode = tnode->tree_parent;
 758 
 759         while (tnode != NULL) {
 760 
 761                 /* If there is exportinfo, update it */
 762                 if (tnode->tree_exi != NULL) {
 763                         secinfo_t **pxsec =
 764                             &tnode->tree_exi->exi_export.ex_secinfo;
 765                         int *pxcnt = &tnode->tree_exi->exi_export.ex_seccnt;
 766                         int is_pseudo = PSEUDO(tnode->tree_exi);
 
 787 
 788 /* hash_name is a text substitution for either fid_hash or path_hash */
 789 #define exp_hash_unlink(exi, hash_name) \
 790         if (*(exi)->hash_name.bckt == (exi)) \
 791                 *(exi)->hash_name.bckt = (exi)->hash_name.next; \
 792         if ((exi)->hash_name.prev) \
 793                 (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
 794         if ((exi)->hash_name.next) \
 795                 (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
 796         (exi)->hash_name.bckt = NULL;
 797 
 798 #define exp_hash_link(exi, hash_name, bucket) \
 799         (exi)->hash_name.bckt = (bucket); \
 800         (exi)->hash_name.prev = NULL; \
 801         (exi)->hash_name.next = *(bucket); \
 802         if ((exi)->hash_name.next) \
 803                 (exi)->hash_name.next->hash_name.prev = (exi); \
 804         *(bucket) = (exi);
 805 
 806 void
 807 export_link(nfs_export_t *ne, exportinfo_t *exi)
 808 {
 809         exportinfo_t **bckt;
 810 
 811         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 812 
 813         bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
 814         exp_hash_link(exi, fid_hash, bckt);
 815 
 816         bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
 817             strlen(exi->exi_export.ex_path))];
 818         exp_hash_link(exi, path_hash, bckt);
 819         exi->exi_ne = ne;
 820 }
 821 
 822 /*
 823  * Helper functions for exi_id handling
 824  */
 825 static int
 826 exi_id_compar(const void *v1, const void *v2)
 827 {
 828         const struct exportinfo *e1 = v1;
 829         const struct exportinfo *e2 = v2;
 830 
 831         if (e1->exi_id < e2->exi_id)
 832                 return (-1);
 833         if (e1->exi_id > e2->exi_id)
 834                 return (1);
 835 
 836         return (0);
 837 }
 838 
 839 int
 840 exi_id_get_next()
 841 {
 842         struct exportinfo e;
 843         int ret = exi_id_next;
 844 
 845         ASSERT(MUTEX_HELD(&nfs_exi_id_lock));
 846 
 847         do {
 848                 exi_id_next++;
 849                 if (exi_id_next == 0)
 850                         exi_id_overflow = TRUE;
 851 
 852                 if (!exi_id_overflow)
 853                         break;
 854 
 855                 if (exi_id_next == ret)
 856                         cmn_err(CE_PANIC, "exi_id exhausted");
 857 
 858                 e.exi_id = exi_id_next;
 859         } while (avl_find(&exi_id_tree, &e, NULL) != NULL);
 860 
 861         return (ret);
 862 }
 863 
 864 /*
 865  * Get the root file handle for this zone.
 866  * Called when nfs_svc() starts
 867  */
 868 int
 869 nfs_export_get_rootfh(nfs_globals_t *g)
 870 {
 871         nfs_export_t *ne = g->nfs_export;
 872         int err;
 873 
 874         ne->exi_rootfid.fid_len = MAXFIDSZ;
 875         err = vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid);
 876         if (err != 0) {
 877                 ne->exi_rootfid.fid_len = 0;
 878                 return (err);
 879         }
 880 
 881         /* Setup the fhandle template exi_fh */
 882         ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
 883         ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
 884         bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
 885             ne->exi_rootfid.fid_len);
 886         ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
 887 
 888         return (0);
 889 }
 890 
 891 void
 892 nfs_export_zone_init(nfs_globals_t *ng)
 893 {
 894         int i;
 895         nfs_export_t *ne;
 896         zone_t *zone;
 897 
 898         ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
 899 
 900         rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
 901 
 902         ne->ne_globals = ng; /* "up" pointer */
 903 
 904         /*
 905          * Allocate the place holder for the public file handle, which
 906          * is all zeroes. It is initially set to the root filesystem.
 907          */
 908         ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
 909         ne->exi_public = ne->exi_root;
 910 
 911         ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
 912         ne->exi_root->exi_export.ex_pathlen = 1;  /* length of "/" */
 913         ne->exi_root->exi_export.ex_path =
 914             kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
 915         ne->exi_root->exi_export.ex_path[0] = '/';
 916         ne->exi_root->exi_export.ex_path[1] = '\0';
 917 
 918         ne->exi_root->exi_count = 1;
 919         mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 920 
 921         /*
 922          * Because we cannot:
 923          *      ASSERT(curzone->zone_id == ng->nfs_zoneid);
 924          * We grab the zone pointer explicitly (like netstacks do) and
 925          * set the rootvp here.
 926          *
 927          * Subsequent exportinfo_t's that get export_link()ed to "ne" also
 928          * will backpoint to "ne" such that exi->exi_ne->exi_root->exi_vp
 929          * will get the zone's rootvp for a given exportinfo_t.
 930          */
 931         zone = zone_find_by_id_nolock(ng->nfs_zoneid);
 932         ne->exi_root->exi_vp = zone->zone_rootvp;
 933         ne->exi_root->exi_zoneid = ng->nfs_zoneid;
 934 
 935         /*
 936          * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
 937          * because we can't correctly return errors here.
 938          */
 939 
 940         /* Initialize auth cache and auth cache lock */
 941         for (i = 0; i < AUTH_TABLESIZE; i++) {
 942                 ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
 943                     KM_SLEEP);
 944                 avl_create(ne->exi_root->exi_cache[i],
 945                     nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
 946                     offsetof(struct auth_cache_clnt, authc_link));
 947         }
 948         rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 949 
 950         /* setup exi_fh later, in nfs_export_get_rootfid */
 951 
 952         rw_enter(&ne->exported_lock, RW_WRITER);
 953 
 954         /* Publish the exportinfo in the hash table */
 955         export_link(ne, ne->exi_root);
 956 
 957         /* Initialize exi_id and exi_kstats */
 958         mutex_enter(&nfs_exi_id_lock);
 959         ne->exi_root->exi_id = exi_id_get_next();
 960         avl_add(&exi_id_tree, ne->exi_root);
 961         mutex_exit(&nfs_exi_id_lock);
 962 
 963         rw_exit(&ne->exported_lock);
 964         ne->ns_root = NULL;
 965 
 966         ng->nfs_export = ne;
 967 }
 968 
 969 /*
 970  * During zone shutdown, remove exports
 971  */
 972 void
 973 nfs_export_zone_shutdown(nfs_globals_t *ng)
 974 {
 975         nfs_export_t *ne = ng->nfs_export;
 976         struct exportinfo *exi, *nexi;
 977         int i, errors;
 978 
 979         rw_enter(&ne->exported_lock, RW_READER);
 980 
 981         errors = 0;
 982         for (i = 0; i < EXPTABLESIZE; i++) {
 983 
 984                 exi = ne->exptable[i];
 985                 if (exi != NULL)
 986                         exi_hold(exi);
 987 
 988                 while (exi != NULL) {
 989 
 990                         /*
 991                          * Get and hold next export before
 992                          * dropping the rwlock and unexport
 993                          */
 994                         nexi = exi->fid_hash.next;
 995                         if (nexi != NULL)
 996                                 exi_hold(nexi);
 997 
 998                         rw_exit(&ne->exported_lock);
 999 
1000                         /*
1001                          * Skip ne->exi_root which gets special
1002                          * create/destroy handling.
1003                          */
1004                         if (exi != ne->exi_root &&
1005                             unexport(ne, exi) != 0)
1006                                 errors++;
1007                         exi_rele(exi);
1008 
1009                         rw_enter(&ne->exported_lock, RW_READER);
1010                         exi = nexi;
1011                 }
1012         }
1013         if (errors > 0) {
1014                 cmn_err(CE_NOTE, "NFS: failed un-exports in zone %d",
1015                     (int)ng->nfs_zoneid);
1016         }
1017 
1018         rw_exit(&ne->exported_lock);
1019 }
1020 
1021 void
1022 nfs_export_zone_fini(nfs_globals_t *ng)
1023 {
1024         int i;
1025         nfs_export_t *ne = ng->nfs_export;
1026         struct exportinfo *exi;
1027 
1028         ng->nfs_export = NULL;
1029 
1030         rw_enter(&ne->exported_lock, RW_WRITER);
1031 
1032         mutex_enter(&nfs_exi_id_lock);
1033         avl_remove(&exi_id_tree, ne->exi_root);
1034         mutex_exit(&nfs_exi_id_lock);
1035 
1036         export_unlink(ne, ne->exi_root);
1037 
1038         rw_exit(&ne->exported_lock);
1039 
1040         /* Deallocate the place holder for the public file handle */
1041         srv_secinfo_list_free(ne->exi_root->exi_export.ex_secinfo,
1042             ne->exi_root->exi_export.ex_seccnt);
1043         mutex_destroy(&ne->exi_root->exi_lock);
1044 
1045         rw_destroy(&ne->exi_root->exi_cache_lock);
1046         for (i = 0; i < AUTH_TABLESIZE; i++) {
1047                 avl_destroy(ne->exi_root->exi_cache[i]);
1048                 kmem_free(ne->exi_root->exi_cache[i], sizeof (avl_tree_t));
1049         }
1050 
1051         kmem_free(ne->exi_root->exi_export.ex_path,
1052             ne->exi_root->exi_export.ex_pathlen + 1);
1053         kmem_free(ne->exi_root, sizeof (*ne->exi_root));
1054 
1055         /*
1056          * The shutdown hook should have left the exi_id_tree
1057          * with nothing belonging to this zone.
1058          */
1059         mutex_enter(&nfs_exi_id_lock);
1060         i = 0;
1061         exi = avl_first(&exi_id_tree);
1062         while (exi != NULL) {
1063                 if (exi->exi_zoneid == ng->nfs_zoneid)
1064                         i++;
1065                 exi = AVL_NEXT(&exi_id_tree, exi);
1066         }
1067         mutex_exit(&nfs_exi_id_lock);
1068         if (i > 0) {
1069                 cmn_err(CE_NOTE,
1070                     "NFS: zone %d has %d export IDs left after shutdown",
1071                     (int)ng->nfs_zoneid, i);
1072         }
1073         rw_destroy(&ne->exported_lock);
1074         kmem_free(ne, sizeof (*ne));
1075 }
1076 
1077 /*
1078  * Initialization routine for export routines.
1079  * Should only be called once.
1080  */
1081 void
1082 nfs_exportinit(void)
1083 {
1084         mutex_init(&nfs_exi_id_lock, NULL, MUTEX_DEFAULT, NULL);
1085 
1086         /* exi_id handling initialization */
1087         exi_id_next = 0;
1088         exi_id_overflow = FALSE;
1089         avl_create(&exi_id_tree, exi_id_compar, sizeof (struct exportinfo),
1090             offsetof(struct exportinfo, exi_id_link));
1091 
1092         nfslog_init();
1093 }
1094 
1095 /*
1096  * Finalization routine for export routines.
1097  */
1098 void
1099 nfs_exportfini(void)
1100 {
1101         avl_destroy(&exi_id_tree);
1102         mutex_destroy(&nfs_exi_id_lock);
1103 }
1104 
1105 /*
1106  *  Check if 2 gss mechanism identifiers are the same.
1107  *
1108  *  return FALSE if not the same.
1109  *  return TRUE if the same.
1110  */
1111 static bool_t
1112 nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
1113 {
1114         if ((mech1->length == 0) && (mech2->length == 0))
1115                 return (TRUE);
1116 
1117         if (mech1->length != mech2->length)
1118                 return (FALSE);
1119 
1120         return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0);
1121 }
1122 
1123 /*
1124  *  This routine is used by rpc to map rpc security number
1125  *  to nfs specific security flavor number.
1126  *
1127  *  The gss callback prototype is
1128  *  callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *,
1129  *                              rpc_gss_lock_t *, void **),
1130  *  since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments
1131  *  we cast them to void.
1132  */
1133 /*ARGSUSED*/
1134 bool_t
1135 rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context,
1136     rpc_gss_lock_t *lock, void **cookie)
1137 {
1138         int i, j;
1139         rpc_gss_rawcred_t *raw_cred;
1140         struct exportinfo *exi;
1141         nfs_export_t *ne = nfs_get_export();
1142 
1143         /*
1144          * We don't deal with delegated credentials.
1145          */
1146         if (deleg != GSS_C_NO_CREDENTIAL)
1147                 return (FALSE);
1148 
1149         raw_cred = lock->raw_cred;
1150         *cookie = NULL;
1151 
1152         rw_enter(&ne->exported_lock, RW_READER);
1153 
1154         for (i = 0; i < EXPTABLESIZE; i++) {
1155                 exi = ne->exptable[i];
1156                 while (exi) {
1157                         if (exi->exi_export.ex_seccnt > 0) {
1158                                 struct secinfo *secp;
1159                                 seconfig_t *se;
1160                                 int seccnt;
1161 
1162                                 secp = exi->exi_export.ex_secinfo;
1163                                 seccnt = exi->exi_export.ex_seccnt;
1164                                 for (j = 0; j < seccnt; j++) {
1165                                         /*
1166                                          *  If there is a map of the triplet
1167                                          *  (mechanism, service, qop) between
1168                                          *  raw_cred and the exported flavor,
1169                                          *  get the psudo flavor number.
1170                                          *  Also qop should not be NULL, it
1171                                          *  should be "default" or something
1172                                          *  else.
1173                                          */
1174                                         se = &secp[j].s_secinfo;
1175                                         if ((se->sc_rpcnum == RPCSEC_GSS) &&
1176 
1177                                             (nfs_mech_equal(
1178                                             se->sc_gss_mech_type,
1179                                             raw_cred->mechanism)) &&
1180 
1181                                             (se->sc_service ==
1182                                             raw_cred->service) &&
1183                                             (raw_cred->qop == se->sc_qop)) {
1184 
1185                                                 *cookie = (void *)(uintptr_t)
1186                                                     se->sc_nfsnum;
1187                                                 goto done;
1188                                         }
1189                                 }
1190                         }
1191                         exi = exi->fid_hash.next;
1192                 }
1193         }
1194 done:
1195         rw_exit(&ne->exported_lock);
1196 
1197         /*
1198          * If no nfs pseudo number mapping can be found in the export
1199          * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
1200          * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
1201          *
1202          * For example:
1203          *      server first shares with krb5i;
1204          *      client mounts with krb5i;
1205          *      server re-shares with krb5p;
1206          *      client tries with krb5i, but no mapping can be found;
1207          *      rpcsec_gss module calls this routine to do the mapping,
1208          *              if this routine fails, request is rejected from
1209          *              the rpc layer.
1210          *      What we need is to let the nfs layer rejects the request.
1211          *      For V4, we can reject with NFS4ERR_WRONGSEC and the client
1212          *      may recover from it by getting the new flavor via SECINFO.
1213          *
1214          * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf)
1215          * is owned by IANA (see RFC 2623).
 
1242         fid_t fid;
1243         fsid_t fsid;
1244         int error;
1245         size_t allocsize;
1246         struct secinfo *sp;
1247         struct secinfo *exs;
1248         rpc_gss_callback_t cb;
1249         char *pathbuf;
1250         char *log_buffer;
1251         char *tagbuf;
1252         int callback;
1253         int allocd_seccnt;
1254         STRUCT_HANDLE(exportfs_args, uap);
1255         STRUCT_DECL(exportdata, uexi);
1256         struct secinfo newsec[MAX_FLAVORS];
1257         int newcnt;
1258         struct secinfo oldsec[MAX_FLAVORS];
1259         int oldcnt;
1260         int i;
1261         struct pathname lookpn;
1262         nfs_export_t *ne = nfs_get_export();
1263 
1264         STRUCT_SET_HANDLE(uap, model, args);
1265 
1266         /* Read in pathname from userspace */
1267         if (error = pn_get(STRUCT_FGETP(uap, dname), UIO_USERSPACE, &lookpn))
1268                 return (error);
1269 
1270         /* Walk the export list looking for that pathname */
1271         rw_enter(&ne->exported_lock, RW_READER);
1272         DTRACE_PROBE(nfss__i__exported_lock1_start);
1273         for (ex1 = ne->exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
1274             strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) {
1275                 if (ex1 != ne->exi_root && 0 ==
1276                     strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) {
1277                         exi_hold(ex1);
1278                         break;
1279                 }
1280         }
1281         DTRACE_PROBE(nfss__i__exported_lock1_stop);
1282         rw_exit(&ne->exported_lock);
1283 
1284         /* Is this an unshare? */
1285         if (STRUCT_FGETP(uap, uex) == NULL) {
1286                 pn_free(&lookpn);
1287                 if (ex1 == NULL)
1288                         return (EINVAL);
1289                 error = unexport(ne, ex1);
1290                 exi_rele(ex1);
1291                 return (error);
1292         }
1293 
1294         /* It is a share or a re-share */
1295         error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1296             FOLLOW, &dvp, &vp);
1297         if (error == EINVAL) {
1298                 /*
1299                  * if fname resolves to / we get EINVAL error
1300                  * since we wanted the parent vnode. Try again
1301                  * with NULL dvp.
1302                  */
1303                 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1304                     FOLLOW, NULL, &vp);
1305                 dvp = NULL;
1306         }
1307         if (!error && vp == NULL) {
1308                 /* Last component of fname not found */
1309                 if (dvp != NULL)
 
1365         fsid = vp->v_vfsp->vfs_fsid;
1366 
1367         if (error) {
1368                 VN_RELE(vp);
1369                 if (dvp != NULL)
1370                         VN_RELE(dvp);
1371                 /*
1372                  * If VOP_FID returns ENOSPC then the fid supplied
1373                  * is too small.  For now we simply return EREMOTE.
1374                  */
1375                 if (error == ENOSPC)
1376                         error = EREMOTE;
1377                 pn_free(&lookpn);
1378                 return (error);
1379         }
1380 
1381         /*
1382          * Do not allow re-sharing a shared vnode under a different path
1383          * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it.
1384          */
1385         rw_enter(&ne->exported_lock, RW_READER);
1386         DTRACE_PROBE(nfss__i__exported_lock2_start);
1387         for (ex2 = ne->exptable[exptablehash(&fsid, &fid)]; ex2;
1388             ex2 = ex2->fid_hash.next) {
1389                 if (ex2 != ne->exi_root && !PSEUDO(ex2) &&
1390                     VN_CMP(ex2->exi_vp, vp) &&
1391                     strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) {
1392                         DTRACE_PROBE(nfss__i__exported_lock2_stop);
1393                         rw_exit(&ne->exported_lock);
1394                         VN_RELE(vp);
1395                         if (dvp != NULL)
1396                                 VN_RELE(dvp);
1397                         pn_free(&lookpn);
1398                         return (EEXIST);
1399                 }
1400         }
1401         DTRACE_PROBE(nfss__i__exported_lock2_stop);
1402         rw_exit(&ne->exported_lock);
1403         pn_free(&lookpn);
1404 
1405         exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
1406         exi->exi_fsid = fsid;
1407         exi->exi_fid = fid;
1408         exi->exi_vp = vp;
1409         exi->exi_count = 1;
1410         exi->exi_zoneid = crgetzoneid(cr);
1411         ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
1412         exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1413             VSW_VOLATILEDEV) ? 1 : 0;
1414         mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
1415         exi->exi_dvp = dvp;
1416 
1417         /*
1418          * Initialize auth cache and auth cache lock
1419          */
1420         for (i = 0; i < AUTH_TABLESIZE; i++) {
1421                 exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
1422                 avl_create(exi->exi_cache[i], nfsauth_cache_clnt_compar,
1423                     sizeof (struct auth_cache_clnt),
1424                     offsetof(struct auth_cache_clnt, authc_link));
1425         }
1426         rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
1427 
1428         /*
1429          * Build up the template fhandle
1430          */
1431         exi->exi_fh.fh_fsid = fsid;
 
1665          * lock while dealing with the index option (as we do with
1666          * the public option).
1667          */
1668         if (kex->ex_flags & EX_INDEX) {
1669                 if (!kex->ex_index) {        /* sanity check */
1670                         error = EINVAL;
1671                         goto out5;
1672                 }
1673                 if (error = loadindex(kex))
1674                         goto out5;
1675         }
1676 
1677         if (kex->ex_flags & EX_LOG) {
1678                 if (error = nfslog_setup(exi))
1679                         goto out6;
1680         }
1681 
1682         /*
1683          * Insert the new entry at the front of the export list
1684          */
1685         rw_enter(&ne->exported_lock, RW_WRITER);
1686         DTRACE_PROBE(nfss__i__exported_lock3_start);
1687 
1688         export_link(ne, exi);
1689 
1690         /*
1691          * Check the rest of the list for an old entry for the fs.
1692          * If one is found then unlink it, wait until this is the
1693          * only reference and then free it.
1694          */
1695         for (ex = exi->fid_hash.next; ex != NULL; ex = ex->fid_hash.next) {
1696                 if (ex != ne->exi_root && VN_CMP(ex->exi_vp, vp)) {
1697                         mutex_enter(&nfs_exi_id_lock);
1698                         avl_remove(&exi_id_tree, ex);
1699                         mutex_exit(&nfs_exi_id_lock);
1700                         export_unlink(ne, ex);
1701                         break;
1702                 }
1703         }
1704 
1705         /*
1706          * If the public filehandle is pointing at the
1707          * old entry, then point it back at the root.
1708          */
1709         if (ex != NULL && ex == ne->exi_public)
1710                 ne->exi_public = ne->exi_root;
1711 
1712         /*
1713          * If the public flag is on, make the global exi_public
1714          * point to this entry and turn off the public bit so that
1715          * we can distinguish it from the place holder export.
1716          */
1717         if (kex->ex_flags & EX_PUBLIC) {
1718                 ne->exi_public = exi;
1719                 kex->ex_flags &= ~EX_PUBLIC;
1720         }
1721 
1722 #ifdef VOLATILE_FH_TEST
1723         /*
1724          * Set up the volatile_id value if volatile on share.
1725          * The list of volatile renamed filehandles is always destroyed,
1726          * if the fs was reshared.
1727          */
1728         if (kex->ex_flags & EX_VOLFH)
1729                 exi->exi_volatile_id = gethrestime_sec();
1730 
1731         mutex_init(&exi->exi_vol_rename_lock, NULL, MUTEX_DEFAULT, NULL);
1732 #endif /* VOLATILE_FH_TEST */
1733 
1734         /*
1735          * If this is a new export, then climb up
1736          * the tree and check if any pseudo exports
1737          * need to be created to provide a path for
1738          * NFS v4 clients.
1739          */
1740         if (ex == NULL) {
1741                 error = treeclimb_export(exi);
1742                 if (error)
1743                         goto out7;
1744         } else {
1745                 /* If it's a re-export update namespace tree */
1746                 exi->exi_tree = ex->exi_tree;
1747                 exi->exi_tree->tree_exi = exi;
1748 
1749                 /* Update the change timestamp */
1750                 tree_update_change(ne, exi->exi_tree, NULL);
1751         }
1752 
1753         /*
1754          * build a unique flavor list from the flavors specified
1755          * in the share cmd.  unique means that each flavor only
1756          * appears once in the secinfo list -- no duplicates allowed.
1757          */
1758         newcnt = build_seclist_nodups(&exi->exi_export, newsec, FALSE);
1759 
1760         srv_secinfo_treeclimb(ne, exi, newsec, newcnt, TRUE);
1761 
1762         /*
1763          * If re-sharing an old export entry, update the secinfo data
1764          * depending on if the old entry is a pseudo node or not.
1765          */
1766         if (ex != NULL) {
1767                 oldcnt = build_seclist_nodups(&ex->exi_export, oldsec, FALSE);
1768                 if (PSEUDO(ex)) {
1769                         /*
1770                          * The dir being shared is a pseudo export root (which
1771                          * will be transformed into a real export root).  The
1772                          * flavor(s) of the new share were propagated to the
1773                          * ancestors by srv_secinfo_treeclimb() above.  Now
1774                          * transfer the implicit flavor refs from the old
1775                          * pseudo exprot root to the new (real) export root.
1776                          */
1777                         srv_secinfo_add(&exi->exi_export.ex_secinfo,
1778                             &exi->exi_export.ex_seccnt, oldsec, oldcnt, TRUE);
1779                 } else {
1780                         /*
1781                          * First transfer implicit flavor refs to new export.
1782                          * Remove old flavor refs last.
1783                          */
1784                         srv_secinfo_exp2exp(&exi->exi_export, oldsec, oldcnt);
1785                         srv_secinfo_treeclimb(ne, ex, oldsec, oldcnt, FALSE);
1786                 }
1787         }
1788 
1789         /*
1790          * If it's a re-export and the old entry has a pseudonode list,
1791          * transfer it to the new export.
1792          */
1793         if (ex != NULL && (ex->exi_visible != NULL)) {
1794                 exi->exi_visible = ex->exi_visible;
1795                 ex->exi_visible = NULL;
1796         }
1797 
1798         /*
1799          * Initialize exi_id and exi_kstats
1800          */
1801         if (ex != NULL) {
1802                 exi->exi_id = ex->exi_id;
1803         } else {
1804                 mutex_enter(&nfs_exi_id_lock);
1805                 exi->exi_id = exi_id_get_next();
1806                 mutex_exit(&nfs_exi_id_lock);
1807         }
1808         mutex_enter(&nfs_exi_id_lock);
1809         avl_add(&exi_id_tree, exi);
1810         mutex_exit(&nfs_exi_id_lock);
1811 
1812         DTRACE_PROBE(nfss__i__exported_lock3_stop);
1813         rw_exit(&ne->exported_lock);
1814 
1815         if (ne->exi_public == exi || kex->ex_flags & EX_LOG) {
1816                 /*
1817                  * Log share operation to this buffer only.
1818                  */
1819                 nfslog_share_record(exi, cr);
1820         }
1821 
1822         if (ex != NULL)
1823                 exi_rele(ex);
1824 
1825         return (0);
1826 
1827 out7:
1828         /* Unlink the new export in exptable. */
1829         export_unlink(ne, exi);
1830         DTRACE_PROBE(nfss__i__exported_lock3_stop);
1831         rw_exit(&ne->exported_lock);
1832 out6:
1833         if (kex->ex_flags & EX_INDEX)
1834                 kmem_free(kex->ex_index, strlen(kex->ex_index) + 1);
1835 out5:
1836         /* free partially completed allocation */
1837         while (--allocd_seccnt >= 0) {
1838                 exs = &kex->ex_secinfo[allocd_seccnt];
1839                 srv_secinfo_entry_free(exs);
1840         }
1841 
1842         if (kex->ex_secinfo) {
1843                 kmem_free(kex->ex_secinfo,
1844                     kex->ex_seccnt * sizeof (struct secinfo));
1845         }
1846 
1847 out4:
1848         if ((kex->ex_flags & EX_LOG) && kex->ex_tag != NULL)
1849                 kmem_free(kex->ex_tag, kex->ex_taglen + 1);
1850 out3:
1851         if ((kex->ex_flags & EX_LOG) && kex->ex_log_buffer != NULL)
 
1855 out1:
1856         VN_RELE(vp);
1857         if (dvp != NULL)
1858                 VN_RELE(dvp);
1859         mutex_destroy(&exi->exi_lock);
1860         rw_destroy(&exi->exi_cache_lock);
1861         for (i = 0; i < AUTH_TABLESIZE; i++) {
1862                 avl_destroy(exi->exi_cache[i]);
1863                 kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
1864         }
1865 
1866         kmem_free(exi, sizeof (*exi));
1867 
1868         return (error);
1869 }
1870 
1871 /*
1872  * Remove the exportinfo from the export list
1873  */
1874 void
1875 export_unlink(nfs_export_t *ne, struct exportinfo *exi)
1876 {
1877         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
1878 
1879         exp_hash_unlink(exi, fid_hash);
1880         exp_hash_unlink(exi, path_hash);
1881         ASSERT3P(exi->exi_ne, ==, ne);
1882         exi->exi_ne = NULL;
1883 }
1884 
1885 /*
1886  * Unexport an exported filesystem
1887  */
1888 static int
1889 unexport(nfs_export_t *ne, struct exportinfo *exi)
1890 {
1891         struct secinfo cursec[MAX_FLAVORS];
1892         int curcnt;
1893 
1894         rw_enter(&ne->exported_lock, RW_WRITER);
1895 
1896         /* Check if exi is still linked in the export table */
1897         if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1898                 rw_exit(&ne->exported_lock);
1899                 return (EINVAL);
1900         }
1901 
1902         mutex_enter(&nfs_exi_id_lock);
1903         avl_remove(&exi_id_tree, exi);
1904         mutex_exit(&nfs_exi_id_lock);
1905         export_unlink(ne, exi);
1906 
1907         /*
1908          * Remove security flavors before treeclimb_unexport() is called
1909          * because srv_secinfo_treeclimb needs the namespace tree
1910          */
1911         curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
1912         srv_secinfo_treeclimb(ne, exi, cursec, curcnt, FALSE);
1913 
1914         /*
1915          * If there's a visible list, then need to leave
1916          * a pseudo export here to retain the visible list
1917          * for paths to exports below.
1918          */
1919         if (exi->exi_visible != NULL) {
1920                 struct exportinfo *newexi;
1921 
1922                 newexi = pseudo_exportfs(ne, exi->exi_vp, &exi->exi_fid,
1923                     exi->exi_visible, &exi->exi_export);
1924                 exi->exi_visible = NULL;
1925 
1926                 /* interconnect the existing treenode with the new exportinfo */
1927                 newexi->exi_tree = exi->exi_tree;
1928                 newexi->exi_tree->tree_exi = newexi;
1929 
1930                 /* Update the change timestamp */
1931                 tree_update_change(ne, exi->exi_tree, NULL);
1932         } else {
1933                 treeclimb_unexport(ne, exi);
1934         }
1935 
1936         rw_exit(&ne->exported_lock);
1937 
1938         /*
1939          * Need to call into the NFSv4 server and release all data
1940          * held on this particular export.  This is important since
1941          * the v4 server may be holding file locks or vnodes under
1942          * this export.
1943          */
1944         rfs4_clean_state_exi(ne, exi);
1945 
1946         /*
1947          * Notify the lock manager that the filesystem is being
1948          * unexported.
1949          */
1950         lm_unexport(exi);
1951 
1952         /*
1953          * If this was a public export, restore
1954          * the public filehandle to the root.
1955          */
1956 
1957         /*
1958          * XXX KEBE ASKS --> Should CRED() instead be
1959          * exi->exi_zone->zone_kcred?
1960          */
1961         if (exi == ne->exi_public) {
1962                 ne->exi_public = ne->exi_root;
1963 
1964                 nfslog_share_record(ne->exi_public, CRED());
1965         }
1966 
1967         if (exi->exi_export.ex_flags & EX_LOG)
1968                 nfslog_unshare_record(exi, CRED());
1969 
1970         exi_rele(exi);
1971         return (0);
1972 }
1973 
1974 /*
1975  * Get file handle system call.
1976  * Takes file name and returns a file handle for it.
1977  * Credentials must be verified before calling.
1978  */
1979 int
1980 nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
1981 {
1982         nfs_fh3 fh;
1983         char buf[NFS3_MAXFHSIZE];
1984         char *logptr, logbuf[NFS3_MAXFHSIZE];
1985         int l = NFS3_MAXFHSIZE;
1986         vnode_t *vp;
1987         vnode_t *dvp;
1988         struct exportinfo *exi;
 
2175                         break;
2176                 }
2177 
2178                 if (v4srv)
2179                         exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
2180                 else
2181                         exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
2182 
2183                 if (exi != NULL) {
2184                         /*
2185                          * Found the export info
2186                          */
2187                         break;
2188                 }
2189 
2190                 /*
2191                  * We have just failed finding a matching export.
2192                  * If we're at the root of this filesystem, then
2193                  * it's time to stop (with failure).
2194                  */
2195                 ASSERT3P(vp->v_vfsp->vfs_zone, ==, curzone);
2196                 if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
2197                         error = EINVAL;
2198                         break;
2199                 }
2200 
2201                 if (walk != NULL)
2202                         (*walk)++;
2203 
2204                 /*
2205                  * Now, do a ".." up vp. If dvp is supplied, use it,
2206                  * otherwise, look it up.
2207                  */
2208                 if (dvp == NULL) {
2209                         error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
2210                             NULL, NULL, NULL);
2211                         if (error)
2212                                 break;
2213                 }
2214                 VN_RELE(vp);
2215                 vp = dvp;
2216                 dvp = NULL;
 
2676 
2677         if (error || vp == NULL) {
2678                 *statp = NFS4ERR_STALE;
2679                 return (NULL);
2680         }
2681         /* XXX - disgusting hack */
2682         if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR)
2683                 vp->v_type = VDIR;
2684         *statp = NFS4_OK;
2685         return (vp);
2686 }
2687 
2688 /*
2689  * Find the export structure associated with the given filesystem.
2690  * If found, then increment the ref count (exi_count).
2691  */
2692 struct exportinfo *
2693 checkexport(fsid_t *fsid, fid_t *fid)
2694 {
2695         struct exportinfo *exi;
2696         nfs_export_t *ne = nfs_get_export();
2697 
2698         rw_enter(&ne->exported_lock, RW_READER);
2699         for (exi = ne->exptable[exptablehash(fsid, fid)];
2700             exi != NULL;
2701             exi = exi->fid_hash.next) {
2702                 if (exportmatch(exi, fsid, fid)) {
2703                         /*
2704                          * If this is the place holder for the
2705                          * public file handle, then return the
2706                          * real export entry for the public file
2707                          * handle.
2708                          */
2709                         if (exi->exi_export.ex_flags & EX_PUBLIC) {
2710                                 exi = ne->exi_public;
2711                         }
2712 
2713                         exi_hold(exi);
2714                         rw_exit(&ne->exported_lock);
2715                         return (exi);
2716                 }
2717         }
2718         rw_exit(&ne->exported_lock);
2719         return (NULL);
2720 }
2721 
2722 
2723 /*
2724  * "old school" version of checkexport() for NFS4.  NFS4
2725  * rfs4_compound holds exported_lock for duration of compound
2726  * processing.  This version doesn't manipulate exi_count
2727  * since NFS4 breaks fundamental assumptions in the exi_count
2728  * design.
2729  */
2730 struct exportinfo *
2731 checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp)
2732 {
2733         struct exportinfo *exi;
2734         nfs_export_t *ne = nfs_get_export();
2735 
2736         ASSERT(RW_LOCK_HELD(&ne->exported_lock));
2737 
2738         for (exi = ne->exptable[exptablehash(fsid, fid)];
2739             exi != NULL;
2740             exi = exi->fid_hash.next) {
2741                 if (exportmatch(exi, fsid, fid)) {
2742                         /*
2743                          * If this is the place holder for the
2744                          * public file handle, then return the
2745                          * real export entry for the public file
2746                          * handle.
2747                          */
2748                         if (exi->exi_export.ex_flags & EX_PUBLIC) {
2749                                 exi = ne->exi_public;
2750                         }
2751 
2752                         /*
2753                          * If vp is given, check if vp is the
2754                          * same vnode as the exported node.
2755                          *
2756                          * Since VOP_FID of a lofs node returns the
2757                          * fid of its real node (ufs), the exported
2758                          * node for lofs and (pseudo) ufs may have
2759                          * the same fsid and fid.
2760                          */
2761                         if (vp == NULL || vp == exi->exi_vp)
2762                                 return (exi);
2763                 }
2764         }
2765 
2766         return (NULL);
2767 }
2768 
2769 /*
 
 |