aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-04-17 17:03:58 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-04-19 16:55:19 -0400
commitcd019f7517206a74d8cdb64d5c82b1f76be608cc (patch)
treeac5e563e23a26519ac5b48f0c2a46cc0f8a3c7cf
parent7b6962b0a6000df48c8a5fd967d262f77704101b (diff)
SUNRPC: Don't change the RPCSEC_GSS context on a credential that is in use
When a server rejects our credential with an AUTH_REJECTEDCRED or similar, we need to refresh the credential and then retry the request. However, we do want to allow any requests that are in flight to finish executing, so that we can at least attempt to process the replies that depend on this instance of the credential. The solution is to ensure that gss_refresh() looks up an entirely new RPCSEC_GSS credential instead of attempting to create a context for the existing invalid credential. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c69
1 files changed, 42 insertions, 27 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 6f1b4e2f5e81..621c07f322c4 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -114,28 +114,14 @@ static void
114gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) 114gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
115{ 115{
116 struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); 116 struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
117 struct gss_cl_ctx *old;
118 117
119 old = gss_cred->gc_ctx; 118 if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
119 return;
120 gss_get_ctx(ctx); 120 gss_get_ctx(ctx);
121 rcu_assign_pointer(gss_cred->gc_ctx, ctx); 121 rcu_assign_pointer(gss_cred->gc_ctx, ctx);
122 set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); 122 set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
123 smp_mb__before_clear_bit();
123 clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); 124 clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
124 if (old)
125 gss_put_ctx(old);
126}
127
128static int
129gss_cred_is_uptodate_ctx(struct rpc_cred *cred)
130{
131 struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
132 int res = 0;
133
134 rcu_read_lock();
135 if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx)
136 res = 1;
137 rcu_read_unlock();
138 return res;
139} 125}
140 126
141static const void * 127static const void *
@@ -857,15 +843,12 @@ gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
857{ 843{
858 struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); 844 struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
859 845
860 /* 846 if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
861 * If the searchflags have set RPCAUTH_LOOKUP_NEW, then
862 * we don't really care if the credential has expired or not,
863 * since the caller should be prepared to reinitialise it.
864 */
865 if ((flags & RPCAUTH_LOOKUP_NEW) && test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
866 goto out; 847 goto out;
867 /* Don't match with creds that have expired. */ 848 /* Don't match with creds that have expired. */
868 if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) 849 if (time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
850 return 0;
851 if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags))
869 return 0; 852 return 0;
870out: 853out:
871 if (acred->machine_cred != gss_cred->gc_machine_cred) 854 if (acred->machine_cred != gss_cred->gc_machine_cred)
@@ -933,16 +916,48 @@ out_put_ctx:
933 return NULL; 916 return NULL;
934} 917}
935 918
919static int gss_renew_cred(struct rpc_task *task)
920{
921 struct rpc_cred *oldcred = task->tk_msg.rpc_cred;
922 struct gss_cred *gss_cred = container_of(oldcred,
923 struct gss_cred,
924 gc_base);
925 struct rpc_auth *auth = oldcred->cr_auth;
926 struct auth_cred acred = {
927 .uid = oldcred->cr_uid,
928 .machine_cred = gss_cred->gc_machine_cred,
929 };
930 struct rpc_cred *new;
931
932 new = gss_lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW);
933 if (IS_ERR(new))
934 return PTR_ERR(new);
935 task->tk_msg.rpc_cred = new;
936 put_rpccred(oldcred);
937 return 0;
938}
939
936/* 940/*
937* Refresh credentials. XXX - finish 941* Refresh credentials. XXX - finish
938*/ 942*/
939static int 943static int
940gss_refresh(struct rpc_task *task) 944gss_refresh(struct rpc_task *task)
941{ 945{
946 struct rpc_cred *cred = task->tk_msg.rpc_cred;
947 int ret = 0;
948
949 if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
950 !test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) {
951 ret = gss_renew_cred(task);
952 if (ret < 0)
953 goto out;
954 cred = task->tk_msg.rpc_cred;
955 }
942 956
943 if (!gss_cred_is_uptodate_ctx(task->tk_msg.rpc_cred)) 957 if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags))
944 return gss_refresh_upcall(task); 958 ret = gss_refresh_upcall(task);
945 return 0; 959out:
960 return ret;
946} 961}
947 962
948/* Dummy refresh routine: used only when destroying the context */ 963/* Dummy refresh routine: used only when destroying the context */