Blob Blame History Raw
From dbcd8411643a641316696f221860517ab06879ba Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 28 Aug 2019 14:23:18 +0200
Subject: [PATCH 55/55] KCM: Fill empty cache, do not initialize a new one
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Related:
https://pagure.io/SSSD/sssd/issue/4017

openssh uses this sequence of calls:
    gen_new()
    switch()
    initialize()

What happened before was that if there was already some cache, gen_new
would create a new empty cache, then switch would set it as the default.
But then, during the initialize call, the cache that used to be the
default was deleted, another one created and used as the default. This
meant. Afterwards, KCM would store the credentials in the previous
cache, which would no longer be the default.

The logic behind was that KCM didn't anticipate the client generating
the new and setting the default on its own.

Reviewed-by: Michal Židek <mzidek@redhat.com>
---
 src/responder/kcm/kcmsrv_ops.c | 84 +++++++++++++++++++++++++++++++++-
 1 file changed, 82 insertions(+), 2 deletions(-)

diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
index 8bd63165b..2181ec6e6 100644
--- a/src/responder/kcm/kcmsrv_ops.c
+++ b/src/responder/kcm/kcmsrv_ops.c
@@ -367,6 +367,8 @@ struct kcm_op_initialize_state {
 static void kcm_op_initialize_got_byname(struct tevent_req *subreq);
 static void kcm_op_initialize_cc_create_done(struct tevent_req *subreq);
 static void kcm_op_initialize_cc_delete_done(struct tevent_req *subreq);
+static void kcm_op_initialize_fill_princ_step(struct tevent_req *req);
+static void kcm_op_initialize_fill_princ_done(struct tevent_req *subreq);
 static void kcm_op_initialize_create_step(struct tevent_req *req);
 static void kcm_op_initialize_got_default(struct tevent_req *subreq);
 static void kcm_op_initialize_set_default_done(struct tevent_req *subreq);
@@ -450,6 +452,15 @@ static void kcm_op_initialize_got_byname(struct tevent_req *subreq)
     }
 
     if (state->new_cc != NULL) {
+        if (kcm_cc_get_client_principal(state->new_cc) == NULL) {
+            /* This is a cache that was pre-created w/o a principal (sshd does this),
+             * let's fill in the principal and set the cache as default if not
+             * already
+             */
+            kcm_op_initialize_fill_princ_step(req);
+            return;
+        }
+
         ok = kcm_cc_access(state->new_cc, state->op_ctx->client);
         if (!ok) {
             state->op_ret = EACCES;
@@ -501,6 +512,70 @@ static void kcm_op_initialize_cc_delete_done(struct tevent_req *subreq)
     kcm_op_initialize_create_step(req);
 }
 
+static void kcm_op_initialize_fill_princ_step(struct tevent_req *req)
+{
+    struct tevent_req *subreq;
+    struct kcm_op_initialize_state *state = tevent_req_data(req,
+                                            struct kcm_op_initialize_state);
+    errno_t ret;
+    struct kcm_mod_ctx *mod_ctx;
+    uuid_t uuid;
+
+    mod_ctx = kcm_mod_ctx_new(state);
+    if (mod_ctx == NULL) {
+        tevent_req_error(req, ENOMEM);
+        return;
+    }
+    mod_ctx->client = state->princ;
+
+    ret = kcm_cc_get_uuid(state->new_cc, uuid);
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    subreq = kcm_ccdb_mod_cc_send(state,
+                                  state->ev,
+                                  state->op_ctx->kcm_data->db,
+                                  state->op_ctx->client,
+                                  uuid,
+                                  mod_ctx);
+    if (subreq == NULL) {
+        tevent_req_error(req, ENOMEM);
+        return;
+    }
+    tevent_req_set_callback(subreq, kcm_op_initialize_fill_princ_done, req);
+}
+
+static void kcm_op_initialize_fill_princ_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct kcm_op_initialize_state *state = tevent_req_data(req,
+                                            struct kcm_op_initialize_state);
+    errno_t ret;
+
+    ret = kcm_ccdb_mod_cc_recv(subreq);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              "Cannot modify ccache [%d]: %s\n",
+              ret, sss_strerror(ret));
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    /* Make sure the cache we just initialized is the default one */
+    subreq = kcm_ccdb_get_default_send(state, state->ev,
+                                       state->op_ctx->kcm_data->db,
+                                       state->op_ctx->client);
+    if (subreq == NULL) {
+        tevent_req_error(req, ret);
+        return;
+    }
+    tevent_req_set_callback(subreq, kcm_op_initialize_got_default, req);
+}
+
 static void kcm_op_initialize_create_step(struct tevent_req *req)
 {
     struct tevent_req *subreq;
@@ -588,11 +663,14 @@ static void kcm_op_initialize_got_default(struct tevent_req *subreq)
         ret = kcm_cc_get_uuid(state->new_cc, dfl_uuid);
         if (ret != EOK) {
             DEBUG(SSSDBG_OP_FAILURE,
-              "Cannot get new ccache UUID [%d]: %s\n",
-              ret, sss_strerror(ret));
+                  "Cannot get new ccache UUID [%d]: %s\n",
+                  ret, sss_strerror(ret));
             return;
         }
 
+        DEBUG(SSSDBG_TRACE_FUNC,
+              "The default ccached was not set, switching to the "
+              "initialized\n");
         subreq = kcm_ccdb_set_default_send(state,
                                            state->ev,
                                            state->op_ctx->kcm_data->db,
@@ -1756,6 +1834,8 @@ static void kcm_op_set_default_create_step_done(struct tevent_req *subreq)
         return;
     }
 
+    DEBUG(SSSDBG_TRACE_FUNC, "The ccache was created, switching to it");
+
     ret = kcm_cc_get_uuid(state->new_cc, state->dfl_uuid);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE,
-- 
2.20.1