From d0eae0598cfb37e1e5aca10a0827b912f707d783 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 16 Jan 2019 13:06:15 +0100
Subject: [PATCH 98/99] KCM: Create an empty ccache on switch to a non-existing
one
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Related:
https://pagure.io/SSSD/sssd/issue/3873
We need to make it possible to create an internal ccache representation
without passing in a principal. The principal is only assigned to the
ccache with krb5_cc_initialize(), but some programs like openssh use the
following sequence of calls:
cc = krb5_cc_new_unique
krb5_cc_switch(cc)
krb5_cc_initialize(cc, principal)
Since switch changes the default ccache, we create a 'dummy' ccache with
krb5_cc_switch() and then the initialize call just fills in the details.
Reviewed-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Michal Židek <mzidek@redhat.com>
---
src/responder/kcm/kcmsrv_ops.c | 133 +++++++++++++++++++++++++++++----
1 file changed, 118 insertions(+), 15 deletions(-)
diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
index 60b5677e9..6544c4ed0 100644
--- a/src/responder/kcm/kcmsrv_ops.c
+++ b/src/responder/kcm/kcmsrv_ops.c
@@ -1601,8 +1601,21 @@ static errno_t kcm_op_get_default_ccache_recv(struct tevent_req *req,
/* (name) -> () */
static void kcm_op_set_default_ccache_getbyname_done(struct tevent_req *subreq);
+static void kcm_op_set_default_create_step(struct tevent_req *req);
+static void kcm_op_set_default_create_step_done(struct tevent_req *subreq);
+static void kcm_op_set_default_step(struct tevent_req *req);
static void kcm_op_set_default_done(struct tevent_req *subreq);
+struct kcm_op_set_default_ccache_state {
+ uint32_t op_ret;
+ struct kcm_op_ctx *op_ctx;
+ struct tevent_context *ev;
+
+ const char *name;
+ uuid_t dfl_uuid;
+ struct kcm_ccache *new_cc;
+};
+
static struct tevent_req *
kcm_op_set_default_ccache_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
@@ -1610,30 +1623,31 @@ kcm_op_set_default_ccache_send(TALLOC_CTX *mem_ctx,
{
struct tevent_req *req = NULL;
struct tevent_req *subreq = NULL;
- struct kcm_op_common_state *state = NULL;
+ struct kcm_op_set_default_ccache_state *state = NULL;
errno_t ret;
- const char *name;
- req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state);
+ req = tevent_req_create(mem_ctx,
+ &state,
+ struct kcm_op_set_default_ccache_state);
if (req == NULL) {
return NULL;
}
state->op_ctx = op_ctx;
state->ev = ev;
- ret = sss_iobuf_read_stringz(op_ctx->input, &name);
+ ret = sss_iobuf_read_stringz(op_ctx->input, &state->name);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Cannot read input name [%d]: %s\n",
ret, sss_strerror(ret));
goto immediate;
}
- DEBUG(SSSDBG_TRACE_LIBS, "Setting default ccache %s\n", name);
+ DEBUG(SSSDBG_TRACE_LIBS, "Setting default ccache %s\n", state->name);
subreq = kcm_ccdb_uuid_by_name_send(state, ev,
op_ctx->kcm_data->db,
op_ctx->client,
- name);
+ state->name);
if (subreq == NULL) {
ret = ENOMEM;
goto immediate;
@@ -1652,13 +1666,16 @@ static void kcm_op_set_default_ccache_getbyname_done(struct tevent_req *subreq)
errno_t ret;
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
- struct kcm_op_common_state *state = tevent_req_data(req,
- struct kcm_op_common_state);
- uuid_t dfl_uuid;
+ struct kcm_op_set_default_ccache_state *state = tevent_req_data(req,
+ struct kcm_op_set_default_ccache_state);
- ret = kcm_ccdb_uuid_by_name_recv(subreq, state, dfl_uuid);
+ ret = kcm_ccdb_uuid_by_name_recv(subreq, state, state->dfl_uuid);
talloc_zfree(subreq);
- if (ret != EOK) {
+ if (ret == ERR_NO_CREDS) {
+ DEBUG(SSSDBG_TRACE_LIBS,
+ "The ccache does not exist, creating a new one\n");
+ kcm_op_set_default_create_step(req);
+ } else if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot get ccache by name [%d]: %s\n",
ret, sss_strerror(ret));
@@ -1666,11 +1683,91 @@ static void kcm_op_set_default_ccache_getbyname_done(struct tevent_req *subreq)
return;
}
+ kcm_op_set_default_step(req);
+}
+
+static void kcm_op_set_default_create_step(struct tevent_req *req)
+{
+ errno_t ret;
+ struct tevent_req *subreq;
+ struct kcm_op_set_default_ccache_state *state = tevent_req_data(req,
+ struct kcm_op_set_default_ccache_state);
+
+ /* Only allow to create ccaches for 'self' */
+ ret = kcm_check_name(state->name, state->op_ctx->client);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Name %s is malformed [%d]: %s\n",
+ state->name, ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ ret = kcm_cc_new(state->op_ctx,
+ state->op_ctx->kcm_data->k5c,
+ state->op_ctx->client,
+ state->name,
+ NULL,
+ &state->new_cc);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot create new ccache %d: %s\n", ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ subreq = kcm_ccdb_create_cc_send(state,
+ state->ev,
+ state->op_ctx->kcm_data->db,
+ state->op_ctx->client,
+ state->new_cc);
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, kcm_op_set_default_create_step_done, req);
+}
+
+static void kcm_op_set_default_create_step_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct kcm_op_set_default_ccache_state *state = tevent_req_data(req,
+ struct kcm_op_set_default_ccache_state);
+
+ ret = kcm_ccdb_create_cc_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot add ccache to db %d: %s\n", ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ ret = kcm_cc_get_uuid(state->new_cc, state->dfl_uuid);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot get new ccache UUID [%d]: %s\n",
+ ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ kcm_op_set_default_step(req);
+}
+
+static void kcm_op_set_default_step(struct tevent_req *req)
+{
+ struct kcm_op_set_default_ccache_state *state = tevent_req_data(req,
+ struct kcm_op_set_default_ccache_state);
+ struct tevent_req *subreq;
+
subreq = kcm_ccdb_set_default_send(state,
state->ev,
state->op_ctx->kcm_data->db,
state->op_ctx->client,
- dfl_uuid);
+ state->dfl_uuid);
if (subreq == NULL) {
tevent_req_error(req, ENOMEM);
return;
@@ -1684,8 +1781,8 @@ static void kcm_op_set_default_done(struct tevent_req *subreq)
errno_t ret;
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
- struct kcm_op_common_state *state = tevent_req_data(req,
- struct kcm_op_common_state);
+ struct kcm_op_set_default_ccache_state *state = tevent_req_data(req,
+ struct kcm_op_set_default_ccache_state);
ret = kcm_ccdb_set_default_recv(subreq);
talloc_zfree(subreq);
@@ -1700,6 +1797,12 @@ static void kcm_op_set_default_done(struct tevent_req *subreq)
tevent_req_done(req);
}
+static errno_t kcm_op_set_default_ccache_recv(struct tevent_req *req,
+ uint32_t *_op_ret)
+{
+ KCM_OP_RET_FROM_TYPE(req, struct kcm_op_set_default_ccache_state, _op_ret);
+}
+
/* (name) -> (offset) */
static void kcm_op_get_kdc_offset_getbyname_done(struct tevent_req *subreq);
@@ -1948,7 +2051,7 @@ static struct kcm_op kcm_optable[] = {
{ "GET_CACHE_UUID_LIST", kcm_op_get_cache_uuid_list_send, NULL },
{ "GET_CACHE_BY_UUID", kcm_op_get_cache_by_uuid_send, NULL },
{ "GET_DEFAULT_CACHE", kcm_op_get_default_ccache_send, kcm_op_get_default_ccache_recv },
- { "SET_DEFAULT_CACHE", kcm_op_set_default_ccache_send, NULL },
+ { "SET_DEFAULT_CACHE", kcm_op_set_default_ccache_send, kcm_op_set_default_ccache_recv },
{ "GET_KDC_OFFSET", kcm_op_get_kdc_offset_send, NULL },
{ "SET_KDC_OFFSET", kcm_op_set_kdc_offset_send, kcm_op_set_kdc_offset_recv },
{ "ADD_NTLM_CRED", NULL, NULL },
--
2.19.1