summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2013-08-28 15:26:25 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-09-02 12:48:40 -0400
commiteb6dc19d8e72ce3a957af5511d20c0db0a8bd007 (patch)
tree2ada89273b3417e2fb5d50f3e2456441ba3ae76f /net
parent414a629598409497c05f2387c22c77dee143b4ff (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.c92
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
75static DEFINE_HASHTABLE(gss_auth_hash_table, 16);
76static DEFINE_SPINLOCK(gss_auth_hash_lock);
77
74struct gss_pipe { 78struct 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
82struct gss_auth { 86struct 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 */
943static struct rpc_auth * 948static struct gss_auth *
944gss_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) 949gss_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;
1008err_destroy_pipe_1: 1014err_destroy_pipe_1:
1009 gss_pipe_free(gss_auth->gss_pipe[1]); 1015 gss_pipe_free(gss_auth->gss_pipe[1]);
1010err_destroy_credcache: 1016err_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
1075static struct gss_auth *
1076gss_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;
1105out:
1106 spin_unlock(&gss_auth_hash_lock);
1107 return gss_auth;
1108}
1109
1110static struct gss_auth *
1111gss_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);
1125out:
1126 return gss_auth;
1127}
1128
1129static struct rpc_auth *
1130gss_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