Blame SOURCES/0098-KCM-Create-an-empty-ccache-on-switch-to-a-non-existi.patch

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