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 /*
|