From d0eae0598cfb37e1e5aca10a0827b912f707d783 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek 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 Reviewed-by: Michal Židek --- 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