From: Andy Adamson <andros@xxxxxxxxxx> the gc_serial will be used to find gss_cred's associated with the gss-ctx key which in turn is associated with the user kerberos credentials. Add the ccname to the gssd upcall. Gssd uses this name to locate the principals' Kerbeos credential cache which helps gssd to stop rooting around the file system. Signed-off-by: Andy Adamson <andros@xxxxxxxxxx> --- include/linux/sunrpc/auth_gss.h | 1 + net/sunrpc/auth_gss/auth_gss.c | 91 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h index f1cfd4c..4b20b53 100644 --- a/include/linux/sunrpc/auth_gss.h +++ b/include/linux/sunrpc/auth_gss.h @@ -79,6 +79,7 @@ struct gss_cl_ctx { struct gss_upcall_msg; struct gss_cred { struct rpc_cred gc_base; + key_serial_t gc_serial; enum rpc_gss_svc gc_service; struct gss_cl_ctx __rcu *gc_ctx; struct gss_upcall_msg *gc_upcall; diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index ae42a83..10d6e53 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -161,13 +161,19 @@ gss_put_ctx(struct gss_cl_ctx *ctx) * and a new one is protected by the pipe->lock. */ static void -gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) +gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx, struct key *key) { struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)) return; gss_get_ctx(ctx); + if (key != NULL) + gss_cred->gc_serial = key->serial; + else + pr_warn_ratelimited("RPC no gss-ctx key for uid %d " + "gss_cred and context will not be destroyed " + " upon kdestroy\n", cred->cr_uid); rcu_assign_pointer(gss_cred->gc_ctx, ctx); set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); smp_mb__before_clear_bit(); @@ -302,6 +308,8 @@ err: struct gss_upcall_msg { atomic_t count; kuid_t uid; + struct key *key; + char *cc_name; struct rpc_pipe_msg msg; struct list_head list; struct gss_auth *auth; @@ -347,7 +355,11 @@ gss_release_msg(struct gss_upcall_msg *gss_msg) BUG_ON(!list_empty(&gss_msg->list)); if (gss_msg->ctx != NULL) gss_put_ctx(gss_msg->ctx); + if (gss_msg->key != NULL) + /* balance key_get in keyring_search */ + key_put(gss_msg->key); rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue); + kfree(gss_msg->cc_name); kfree(gss_msg); } @@ -417,7 +429,8 @@ gss_handle_downcall_result(struct gss_cred *gss_cred, struct gss_upcall_msg *gss if (gss_msg->ctx == NULL) break; clear_bit(RPCAUTH_CRED_NEGATIVE, &gss_cred->gc_base.cr_flags); - gss_cred_set_ctx(&gss_cred->gc_base, gss_msg->ctx); + gss_cred_set_ctx(&gss_cred->gc_base, gss_msg->ctx, + gss_msg->key); break; case -EKEYEXPIRED: set_bit(RPCAUTH_CRED_NEGATIVE, &gss_cred->gc_base.cr_flags); @@ -427,6 +440,67 @@ gss_handle_downcall_result(struct gss_cred *gss_cred, struct gss_upcall_msg *gss rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); } + +#define GSS_CTX_ID_MAXLEN 20 /* "gss-ctx_" + NFS_UINT_MAXLEN + 1 */ + +static void +gss_find_ctx_key(uid_t uid, struct gss_upcall_msg *msg) +{ + key_ref_t rkey; + struct key *key; + struct user_key_payload *payload; + char *id; + const struct cred *cred = get_current_cred(); + int ret; + + if (!cred->user->session_keyring) + goto out; + + id = kzalloc(GSS_CTX_ID_MAXLEN, GFP_NOFS); + if (!id) + goto out; + + snprintf(id, GSS_CTX_ID_MAXLEN, "gss-ctx_%d", uid); + + /* Search the session keyring. Note that the user key create + * needs to also use the same keyring. */ + rkey = keyring_search(make_key_ref(cred->user->session_keyring, 1), + &key_type_gss_ctx, id); + kfree(id); + + if (IS_ERR(rkey)) + goto out; + + key = key_ref_to_ptr(rkey); + + rcu_read_lock(); + key->perm |= KEY_USR_VIEW; + + ret = key_validate(key); + if (ret < 0) + goto out_unlock; + + payload = rcu_dereference(key->payload.data); + if (IS_ERR_OR_NULL(payload)) + goto out_unlock; + + if (key->uid != uid || payload->datalen <= 0) + goto out_unlock; + + msg->cc_name = kzalloc(payload->datalen + 1, GFP_NOFS); + if (!msg->cc_name) + goto out_unlock; + + memcpy(msg->cc_name, payload->data, payload->datalen); + msg->key = key; + dprintk("RPC krb5 ccache %s has gss-ctx key with serial %u \n", + msg->cc_name, msg->key->serial); +out_unlock: + rcu_read_unlock(); +out: + return; +} + static void gss_upcall_callback(struct rpc_task *task) { @@ -478,6 +552,11 @@ static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, p += len; gss_msg->msg.len += len; } + if (gss_msg->cc_name != NULL) { + len = sprintf(p, "ccache=%s ", gss_msg->cc_name); + p += len; + gss_msg->msg.len += len; + } len = sprintf(p, "\n"); gss_msg->msg.len += len; @@ -500,6 +579,9 @@ gss_alloc_msg(struct gss_auth *gss_auth, kfree(gss_msg); return ERR_PTR(vers); } + /* Use a gss-ctx key if available */ + gss_find_ctx_key(uid, gss_msg); + gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe; INIT_LIST_HEAD(&gss_msg->list); rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); @@ -532,6 +614,9 @@ gss_setup_upcall(struct gss_auth *gss_auth, struct rpc_cred *cred) int res = rpc_queue_upcall(gss_new->pipe, &gss_new->msg); if (res) { gss_unhash_msg(gss_new); + if (gss_new->key) + /* balance key_get in keyring_search */ + key_put(gss_new->key); gss_msg = ERR_PTR(res); } } else @@ -654,7 +739,7 @@ retry: schedule(); } if (gss_msg->ctx) - gss_cred_set_ctx(cred, gss_msg->ctx); + gss_cred_set_ctx(cred, gss_msg->ctx, gss_msg->key); else err = gss_msg->msg.errno; spin_unlock(&pipe->lock); -- 1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html