diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-06-26 17:04:57 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-10 23:40:37 -0400 |
| commit | 0df7fb74fbb709591301871a38aac7735a1d6583 (patch) | |
| tree | a5fc18f5aa581a7e8591551f17e86902b5a7e6b3 /net/sunrpc | |
| parent | 0285ed1f12298e5304f0f2642e2cf31a5f302e61 (diff) | |
SUNRPC: Ensure RPCSEC_GSS destroys the security context when freeing a cred
Do so by set the gc_proc field to RPC_GSS_PROC_DESTROY, and then sending a
NULL RPC call.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc')
| -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, |
