diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-08-28 15:26:25 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-09-02 12:48:40 -0400 |
commit | eb6dc19d8e72ce3a957af5511d20c0db0a8bd007 (patch) | |
tree | 2ada89273b3417e2fb5d50f3e2456441ba3ae76f /net | |
parent | 414a629598409497c05f2387c22c77dee143b4ff (diff) |
RPCSEC_GSS: Share all credential caches on a per-transport basis
Ensure that all struct rpc_clnt for any given socket/rdma channel
share the same RPCSEC_GSS/krb5,krb5i,krb5p caches.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 92 |
1 files changed, 89 insertions, 3 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 5ec15bb43e83..dc4b449d3680 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/sunrpc/rpc_pipe_fs.h> | 51 | #include <linux/sunrpc/rpc_pipe_fs.h> |
52 | #include <linux/sunrpc/gss_api.h> | 52 | #include <linux/sunrpc/gss_api.h> |
53 | #include <asm/uaccess.h> | 53 | #include <asm/uaccess.h> |
54 | #include <linux/hashtable.h> | ||
54 | 55 | ||
55 | #include "../netns.h" | 56 | #include "../netns.h" |
56 | 57 | ||
@@ -71,6 +72,9 @@ static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED; | |||
71 | * using integrity (two 4-byte integers): */ | 72 | * using integrity (two 4-byte integers): */ |
72 | #define GSS_VERF_SLACK 100 | 73 | #define GSS_VERF_SLACK 100 |
73 | 74 | ||
75 | static DEFINE_HASHTABLE(gss_auth_hash_table, 16); | ||
76 | static DEFINE_SPINLOCK(gss_auth_hash_lock); | ||
77 | |||
74 | struct gss_pipe { | 78 | struct gss_pipe { |
75 | struct rpc_pipe_dir_object pdo; | 79 | struct rpc_pipe_dir_object pdo; |
76 | struct rpc_pipe *pipe; | 80 | struct rpc_pipe *pipe; |
@@ -81,6 +85,7 @@ struct gss_pipe { | |||
81 | 85 | ||
82 | struct gss_auth { | 86 | struct gss_auth { |
83 | struct kref kref; | 87 | struct kref kref; |
88 | struct hlist_node hash; | ||
84 | struct rpc_auth rpc_auth; | 89 | struct rpc_auth rpc_auth; |
85 | struct gss_api_mech *mech; | 90 | struct gss_api_mech *mech; |
86 | enum rpc_gss_svc service; | 91 | enum rpc_gss_svc service; |
@@ -940,8 +945,8 @@ static void gss_pipe_free(struct gss_pipe *p) | |||
940 | * NOTE: we have the opportunity to use different | 945 | * NOTE: we have the opportunity to use different |
941 | * parameters based on the input flavor (which must be a pseudoflavor) | 946 | * parameters based on the input flavor (which must be a pseudoflavor) |
942 | */ | 947 | */ |
943 | static struct rpc_auth * | 948 | static struct gss_auth * |
944 | gss_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | 949 | gss_create_new(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) |
945 | { | 950 | { |
946 | rpc_authflavor_t flavor = args->pseudoflavor; | 951 | rpc_authflavor_t flavor = args->pseudoflavor; |
947 | struct gss_auth *gss_auth; | 952 | struct gss_auth *gss_auth; |
@@ -955,6 +960,7 @@ gss_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | |||
955 | return ERR_PTR(err); | 960 | return ERR_PTR(err); |
956 | if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL))) | 961 | if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL))) |
957 | goto out_dec; | 962 | goto out_dec; |
963 | INIT_HLIST_NODE(&gss_auth->hash); | ||
958 | gss_auth->target_name = NULL; | 964 | gss_auth->target_name = NULL; |
959 | if (args->target_name) { | 965 | if (args->target_name) { |
960 | gss_auth->target_name = kstrdup(args->target_name, GFP_KERNEL); | 966 | gss_auth->target_name = kstrdup(args->target_name, GFP_KERNEL); |
@@ -1004,7 +1010,7 @@ gss_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | |||
1004 | } | 1010 | } |
1005 | gss_auth->gss_pipe[0] = gss_pipe; | 1011 | gss_auth->gss_pipe[0] = gss_pipe; |
1006 | 1012 | ||
1007 | return auth; | 1013 | return gss_auth; |
1008 | err_destroy_pipe_1: | 1014 | err_destroy_pipe_1: |
1009 | gss_pipe_free(gss_auth->gss_pipe[1]); | 1015 | gss_pipe_free(gss_auth->gss_pipe[1]); |
1010 | err_destroy_credcache: | 1016 | err_destroy_credcache: |
@@ -1051,6 +1057,12 @@ gss_destroy(struct rpc_auth *auth) | |||
1051 | dprintk("RPC: destroying GSS authenticator %p flavor %d\n", | 1057 | dprintk("RPC: destroying GSS authenticator %p flavor %d\n", |
1052 | auth, auth->au_flavor); | 1058 | auth, auth->au_flavor); |
1053 | 1059 | ||
1060 | if (hash_hashed(&gss_auth->hash)) { | ||
1061 | spin_lock(&gss_auth_hash_lock); | ||
1062 | hash_del(&gss_auth->hash); | ||
1063 | spin_unlock(&gss_auth_hash_lock); | ||
1064 | } | ||
1065 | |||
1054 | gss_pipe_free(gss_auth->gss_pipe[0]); | 1066 | gss_pipe_free(gss_auth->gss_pipe[0]); |
1055 | gss_auth->gss_pipe[0] = NULL; | 1067 | gss_auth->gss_pipe[0] = NULL; |
1056 | gss_pipe_free(gss_auth->gss_pipe[1]); | 1068 | gss_pipe_free(gss_auth->gss_pipe[1]); |
@@ -1060,6 +1072,80 @@ gss_destroy(struct rpc_auth *auth) | |||
1060 | kref_put(&gss_auth->kref, gss_free_callback); | 1072 | kref_put(&gss_auth->kref, gss_free_callback); |
1061 | } | 1073 | } |
1062 | 1074 | ||
1075 | static struct gss_auth * | ||
1076 | gss_auth_find_or_add_hashed(struct rpc_auth_create_args *args, | ||
1077 | struct rpc_clnt *clnt, | ||
1078 | struct gss_auth *new) | ||
1079 | { | ||
1080 | struct gss_auth *gss_auth; | ||
1081 | unsigned long hashval = (unsigned long)clnt; | ||
1082 | |||
1083 | spin_lock(&gss_auth_hash_lock); | ||
1084 | hash_for_each_possible(gss_auth_hash_table, | ||
1085 | gss_auth, | ||
1086 | hash, | ||
1087 | hashval) { | ||
1088 | if (gss_auth->rpc_auth.au_flavor != args->pseudoflavor) | ||
1089 | continue; | ||
1090 | if (gss_auth->target_name != args->target_name) { | ||
1091 | if (gss_auth->target_name == NULL) | ||
1092 | continue; | ||
1093 | if (args->target_name == NULL) | ||
1094 | continue; | ||
1095 | if (strcmp(gss_auth->target_name, args->target_name)) | ||
1096 | continue; | ||
1097 | } | ||
1098 | if (!atomic_inc_not_zero(&gss_auth->rpc_auth.au_count)) | ||
1099 | continue; | ||
1100 | goto out; | ||
1101 | } | ||
1102 | if (new) | ||
1103 | hash_add(gss_auth_hash_table, &new->hash, hashval); | ||
1104 | gss_auth = new; | ||
1105 | out: | ||
1106 | spin_unlock(&gss_auth_hash_lock); | ||
1107 | return gss_auth; | ||
1108 | } | ||
1109 | |||
1110 | static struct gss_auth * | ||
1111 | gss_create_hashed(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | ||
1112 | { | ||
1113 | struct gss_auth *gss_auth; | ||
1114 | struct gss_auth *new; | ||
1115 | |||
1116 | gss_auth = gss_auth_find_or_add_hashed(args, clnt, NULL); | ||
1117 | if (gss_auth != NULL) | ||
1118 | goto out; | ||
1119 | new = gss_create_new(args, clnt); | ||
1120 | if (IS_ERR(new)) | ||
1121 | return new; | ||
1122 | gss_auth = gss_auth_find_or_add_hashed(args, clnt, new); | ||
1123 | if (gss_auth != new) | ||
1124 | gss_destroy(&new->rpc_auth); | ||
1125 | out: | ||
1126 | return gss_auth; | ||
1127 | } | ||
1128 | |||
1129 | static struct rpc_auth * | ||
1130 | gss_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | ||
1131 | { | ||
1132 | struct gss_auth *gss_auth; | ||
1133 | struct rpc_xprt *xprt = rcu_access_pointer(clnt->cl_xprt); | ||
1134 | |||
1135 | while (clnt != clnt->cl_parent) { | ||
1136 | struct rpc_clnt *parent = clnt->cl_parent; | ||
1137 | /* Find the original parent for this transport */ | ||
1138 | if (rcu_access_pointer(parent->cl_xprt) != xprt) | ||
1139 | break; | ||
1140 | clnt = parent; | ||
1141 | } | ||
1142 | |||
1143 | gss_auth = gss_create_hashed(args, clnt); | ||
1144 | if (IS_ERR(gss_auth)) | ||
1145 | return ERR_CAST(gss_auth); | ||
1146 | return &gss_auth->rpc_auth; | ||
1147 | } | ||
1148 | |||
1063 | /* | 1149 | /* |
1064 | * gss_destroying_context will cause the RPCSEC_GSS to send a NULL RPC call | 1150 | * gss_destroying_context will cause the RPCSEC_GSS to send a NULL RPC call |
1065 | * to the server with the GSS control procedure field set to | 1151 | * to the server with the GSS control procedure field set to |