diff options
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 60 |
1 files changed, 58 insertions, 2 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 982aba697e4d..17d460f85f0e 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -57,6 +57,7 @@ | |||
57 | static const struct rpc_authops authgss_ops; | 57 | static const struct rpc_authops authgss_ops; |
58 | 58 | ||
59 | static const struct rpc_credops gss_credops; | 59 | static const struct rpc_credops gss_credops; |
60 | static const struct rpc_credops gss_nullops; | ||
60 | 61 | ||
61 | #ifdef RPC_DEBUG | 62 | #ifdef RPC_DEBUG |
62 | # define RPCDBG_FACILITY RPCDBG_AUTH | 63 | # define RPCDBG_FACILITY RPCDBG_AUTH |
@@ -695,7 +696,39 @@ gss_destroy(struct rpc_auth *auth) | |||
695 | kref_put(&gss_auth->kref, gss_free_callback); | 696 | kref_put(&gss_auth->kref, gss_free_callback); |
696 | } | 697 | } |
697 | 698 | ||
698 | /* gss_destroy_cred (and gss_destroy_ctx) are used to clean up after failure | 699 | /* |
700 | * gss_destroying_context will cause the RPCSEC_GSS to send a NULL RPC call | ||
701 | * to the server with the GSS control procedure field set to | ||
702 | * RPC_GSS_PROC_DESTROY. This should normally cause the server to release | ||
703 | * all RPCSEC_GSS state associated with that context. | ||
704 | */ | ||
705 | static int | ||
706 | gss_destroying_context(struct rpc_cred *cred) | ||
707 | { | ||
708 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | ||
709 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); | ||
710 | struct rpc_task *task; | ||
711 | |||
712 | if (gss_cred->gc_ctx == NULL || | ||
713 | gss_cred->gc_ctx->gc_proc == RPC_GSS_PROC_DESTROY) | ||
714 | return 0; | ||
715 | |||
716 | gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY; | ||
717 | cred->cr_ops = &gss_nullops; | ||
718 | |||
719 | /* Take a reference to ensure the cred will be destroyed either | ||
720 | * by the RPC call or by the put_rpccred() below */ | ||
721 | get_rpccred(cred); | ||
722 | |||
723 | task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC); | ||
724 | if (!IS_ERR(task)) | ||
725 | rpc_put_task(task); | ||
726 | |||
727 | put_rpccred(cred); | ||
728 | return 1; | ||
729 | } | ||
730 | |||
731 | /* gss_destroy_cred (and gss_free_ctx) are used to clean up after failure | ||
699 | * to create a new cred or context, so they check that things have been | 732 | * to create a new cred or context, so they check that things have been |
700 | * allocated before freeing them. */ | 733 | * allocated before freeing them. */ |
701 | static void | 734 | static void |
@@ -744,6 +777,8 @@ gss_destroy_cred(struct rpc_cred *cred) | |||
744 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); | 777 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); |
745 | struct gss_cl_ctx *ctx = gss_cred->gc_ctx; | 778 | struct gss_cl_ctx *ctx = gss_cred->gc_ctx; |
746 | 779 | ||
780 | if (gss_destroying_context(cred)) | ||
781 | return; | ||
747 | rcu_assign_pointer(gss_cred->gc_ctx, NULL); | 782 | rcu_assign_pointer(gss_cred->gc_ctx, NULL); |
748 | call_rcu(&cred->cr_rcu, gss_free_cred_callback); | 783 | call_rcu(&cred->cr_rcu, gss_free_cred_callback); |
749 | if (ctx) | 784 | if (ctx) |
@@ -892,6 +927,13 @@ gss_refresh(struct rpc_task *task) | |||
892 | return 0; | 927 | return 0; |
893 | } | 928 | } |
894 | 929 | ||
930 | /* Dummy refresh routine: used only when destroying the context */ | ||
931 | static int | ||
932 | gss_refresh_null(struct rpc_task *task) | ||
933 | { | ||
934 | return -EACCES; | ||
935 | } | ||
936 | |||
895 | static __be32 * | 937 | static __be32 * |
896 | gss_validate(struct rpc_task *task, __be32 *p) | 938 | gss_validate(struct rpc_task *task, __be32 *p) |
897 | { | 939 | { |
@@ -921,8 +963,11 @@ gss_validate(struct rpc_task *task, __be32 *p) | |||
921 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic); | 963 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic); |
922 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | 964 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) |
923 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 965 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
924 | if (maj_stat) | 966 | if (maj_stat) { |
967 | dprintk("RPC: %5u gss_validate: gss_verify_mic returned" | ||
968 | "error 0x%08x\n", task->tk_pid, maj_stat); | ||
925 | goto out_bad; | 969 | goto out_bad; |
970 | } | ||
926 | /* We leave it to unwrap to calculate au_rslack. For now we just | 971 | /* We leave it to unwrap to calculate au_rslack. For now we just |
927 | * calculate the length of the verifier: */ | 972 | * calculate the length of the verifier: */ |
928 | cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2; | 973 | cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2; |
@@ -1260,6 +1305,17 @@ static const struct rpc_credops gss_credops = { | |||
1260 | .crunwrap_resp = gss_unwrap_resp, | 1305 | .crunwrap_resp = gss_unwrap_resp, |
1261 | }; | 1306 | }; |
1262 | 1307 | ||
1308 | static const struct rpc_credops gss_nullops = { | ||
1309 | .cr_name = "AUTH_GSS", | ||
1310 | .crdestroy = gss_destroy_cred, | ||
1311 | .crmatch = gss_match, | ||
1312 | .crmarshal = gss_marshal, | ||
1313 | .crrefresh = gss_refresh_null, | ||
1314 | .crvalidate = gss_validate, | ||
1315 | .crwrap_req = gss_wrap_req, | ||
1316 | .crunwrap_resp = gss_unwrap_resp, | ||
1317 | }; | ||
1318 | |||
1263 | static struct rpc_pipe_ops gss_upcall_ops = { | 1319 | static struct rpc_pipe_ops gss_upcall_ops = { |
1264 | .upcall = gss_pipe_upcall, | 1320 | .upcall = gss_pipe_upcall, |
1265 | .downcall = gss_pipe_downcall, | 1321 | .downcall = gss_pipe_downcall, |