Blame SOURCES/0025-KCM-Add-a-in-memory-credential-storage.patch

bb7cd1
From e7aa9061532b1ac139e155e7e9881c2447675e3c Mon Sep 17 00:00:00 2001
bb7cd1
From: Jakub Hrozek <jhrozek@redhat.com>
bb7cd1
Date: Tue, 7 Mar 2017 13:49:43 +0100
bb7cd1
Subject: [PATCH 25/36] KCM: Add a in-memory credential storage
bb7cd1
MIME-Version: 1.0
bb7cd1
Content-Type: text/plain; charset=UTF-8
bb7cd1
Content-Transfer-Encoding: 8bit
bb7cd1
bb7cd1
Implements a simple back end for the ccache module that lets the KCM
bb7cd1
server store credentials directly in memory.
bb7cd1
bb7cd1
Reviewed-by: Michal Židek <mzidek@redhat.com>
bb7cd1
Reviewed-by: Simo Sorce <simo@redhat.com>
bb7cd1
---
bb7cd1
 Makefile.am                           |   1 +
bb7cd1
 src/responder/kcm/kcm.c               |  13 +-
bb7cd1
 src/responder/kcm/kcmsrv_ccache.c     |   2 +-
bb7cd1
 src/responder/kcm/kcmsrv_ccache_mem.c | 805 ++++++++++++++++++++++++++++++++++
bb7cd1
 4 files changed, 817 insertions(+), 4 deletions(-)
bb7cd1
 create mode 100644 src/responder/kcm/kcmsrv_ccache_mem.c
bb7cd1
bb7cd1
diff --git a/Makefile.am b/Makefile.am
bb7cd1
index a2b9dc49e95fa2d025f5174d2902866fab180a78..5605c1a53c44fd9e83394e80b7f71828df1d39b6 100644
bb7cd1
--- a/Makefile.am
bb7cd1
+++ b/Makefile.am
bb7cd1
@@ -1492,6 +1492,7 @@ sssd_kcm_SOURCES = \
bb7cd1
     src/responder/kcm/kcm.c \
bb7cd1
     src/responder/kcm/kcmsrv_cmd.c \
bb7cd1
     src/responder/kcm/kcmsrv_ccache.c \
bb7cd1
+    src/responder/kcm/kcmsrv_ccache_mem.c \
bb7cd1
     src/util/sss_sockets.c \
bb7cd1
     src/util/sss_krb5.c \
bb7cd1
     src/util/sss_iobuf.c \
bb7cd1
diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c
bb7cd1
index 90a6999c5e39d48a1a2ea8168d171612a65077d5..2c12ef215ce3967df183e51c20590c5f439d278f 100644
bb7cd1
--- a/src/responder/kcm/kcm.c
bb7cd1
+++ b/src/responder/kcm/kcm.c
bb7cd1
@@ -22,9 +22,9 @@
bb7cd1
 #include "config.h"
bb7cd1
 
bb7cd1
 #include <popt.h>
bb7cd1
-#include <krb5/krb5.h>
bb7cd1
 
bb7cd1
 #include "responder/kcm/kcm.h"
bb7cd1
+#include "responder/kcm/kcmsrv_ccache.h"
bb7cd1
 #include "responder/kcm/kcmsrv_pvt.h"
bb7cd1
 #include "responder/common/responder.h"
bb7cd1
 #include "util/util.h"
bb7cd1
@@ -110,7 +110,8 @@ static int kcm_data_destructor(void *ptr)
bb7cd1
     return 0;
bb7cd1
 }
bb7cd1
 
bb7cd1
-static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx)
bb7cd1
+static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx,
bb7cd1
+                                           struct tevent_context *ev)
bb7cd1
 {
bb7cd1
     struct kcm_resp_ctx *kcm_data;
bb7cd1
     krb5_error_code kret;
bb7cd1
@@ -121,6 +122,12 @@ static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx)
bb7cd1
         return NULL;
bb7cd1
     }
bb7cd1
 
bb7cd1
+    kcm_data->db = kcm_ccdb_init(kcm_data, ev, CCDB_BE_MEMORY);
bb7cd1
+    if (kcm_data->db == NULL) {
bb7cd1
+        talloc_free(kcm_data);
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
     kret = krb5_init_context(&kcm_data->k5c);
bb7cd1
     if (kret != EOK) {
bb7cd1
         talloc_free(kcm_data);
bb7cd1
@@ -169,7 +176,7 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx,
bb7cd1
         goto fail;
bb7cd1
     }
bb7cd1
 
bb7cd1
-    kctx->kcm_data = kcm_data_setup(kctx);
bb7cd1
+    kctx->kcm_data = kcm_data_setup(kctx, ev);
bb7cd1
     if (kctx->kcm_data == NULL) {
bb7cd1
         DEBUG(SSSDBG_FATAL_FAILURE,
bb7cd1
               "fatal error initializing responder data\n");
bb7cd1
diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c
bb7cd1
index 2c565b8378e3ec297faf655d3c48d7ab902713d3..2ae120269b0c62275ba2acdff6d6daa8b7077708 100644
bb7cd1
--- a/src/responder/kcm/kcmsrv_ccache.c
bb7cd1
+++ b/src/responder/kcm/kcmsrv_ccache.c
bb7cd1
@@ -240,7 +240,7 @@ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx,
bb7cd1
     switch (cc_be) {
bb7cd1
     case CCDB_BE_MEMORY:
bb7cd1
         DEBUG(SSSDBG_FUNC_DATA, "KCM back end: memory\n");
bb7cd1
-        /* Not implemented yet */
bb7cd1
+        ccdb->ops = &ccdb_mem_ops;
bb7cd1
         break;
bb7cd1
     case CCDB_BE_SECRETS:
bb7cd1
         DEBUG(SSSDBG_FUNC_DATA, "KCM back end: sssd-secrets\n");
bb7cd1
diff --git a/src/responder/kcm/kcmsrv_ccache_mem.c b/src/responder/kcm/kcmsrv_ccache_mem.c
bb7cd1
new file mode 100644
bb7cd1
index 0000000000000000000000000000000000000000..1c4f3df8d3b35b0428a143d4b545562d9cc0e574
bb7cd1
--- /dev/null
bb7cd1
+++ b/src/responder/kcm/kcmsrv_ccache_mem.c
bb7cd1
@@ -0,0 +1,805 @@
bb7cd1
+/*
bb7cd1
+   SSSD
bb7cd1
+
bb7cd1
+   KCM Server - ccache in-memory storage
bb7cd1
+
bb7cd1
+   Copyright (C) Red Hat, 2016
bb7cd1
+
bb7cd1
+   This program is free software; you can redistribute it and/or modify
bb7cd1
+   it under the terms of the GNU General Public License as published by
bb7cd1
+   the Free Software Foundation; either version 3 of the License, or
bb7cd1
+   (at your option) any later version.
bb7cd1
+
bb7cd1
+   This program is distributed in the hope that it will be useful,
bb7cd1
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
bb7cd1
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
bb7cd1
+   GNU General Public License for more details.
bb7cd1
+
bb7cd1
+   You should have received a copy of the GNU General Public License
bb7cd1
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
bb7cd1
+*/
bb7cd1
+
bb7cd1
+#include "config.h"
bb7cd1
+
bb7cd1
+#include <talloc.h>
bb7cd1
+#include <stdio.h>
bb7cd1
+
bb7cd1
+#include "util/util.h"
bb7cd1
+#include "responder/kcm/kcmsrv_ccache_pvt.h"
bb7cd1
+#include "responder/kcm/kcmsrv_ccache_be.h"
bb7cd1
+
bb7cd1
+struct ccdb_mem;
bb7cd1
+
bb7cd1
+/*
bb7cd1
+ * The KCM memory database is just a double-linked list of kcm_ccache structures
bb7cd1
+ */
bb7cd1
+struct ccache_mem_wrap {
bb7cd1
+    struct kcm_ccache *cc;
bb7cd1
+    bool is_default;
bb7cd1
+
bb7cd1
+    struct ccache_mem_wrap *next;
bb7cd1
+    struct ccache_mem_wrap *prev;
bb7cd1
+
bb7cd1
+    struct ccdb_mem *mem_be;
bb7cd1
+};
bb7cd1
+
bb7cd1
+struct ccdb_mem {
bb7cd1
+    /* Both ccaches and the next-id are kept in memory */
bb7cd1
+    struct ccache_mem_wrap *head;
bb7cd1
+    unsigned int nextid;
bb7cd1
+};
bb7cd1
+
bb7cd1
+/* In order to provide a consistent interface, we need to let the caller
bb7cd1
+ * of getbyXXX own the ccache, therefore the memory back end returns a shallow
bb7cd1
+ * copy of the ccache
bb7cd1
+ */
bb7cd1
+static struct kcm_ccache *kcm_ccache_dup(TALLOC_CTX *mem_ctx,
bb7cd1
+                                         struct kcm_ccache *in)
bb7cd1
+{
bb7cd1
+    struct kcm_ccache *out;
bb7cd1
+
bb7cd1
+    out = talloc_zero(mem_ctx, struct kcm_ccache);
bb7cd1
+    if (out == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+    memcpy(out, in, sizeof(struct kcm_ccache));
bb7cd1
+
bb7cd1
+    return out;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static struct ccache_mem_wrap *memdb_get_by_uuid(struct ccdb_mem *memdb,
bb7cd1
+                                                 struct cli_creds *client,
bb7cd1
+                                                 uuid_t uuid)
bb7cd1
+{
bb7cd1
+    uid_t uid;
bb7cd1
+    struct ccache_mem_wrap *ccwrap = NULL;
bb7cd1
+    struct ccache_mem_wrap *out = NULL;
bb7cd1
+
bb7cd1
+    uid = cli_creds_get_uid(client);
bb7cd1
+
bb7cd1
+    DLIST_FOR_EACH(ccwrap, memdb->head) {
bb7cd1
+        if (ccwrap->cc == NULL) {
bb7cd1
+            /* since KCM stores ccaches, better not crash.. */
bb7cd1
+            DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n");
bb7cd1
+            continue;
bb7cd1
+        }
bb7cd1
+
bb7cd1
+        if (ccwrap->cc->owner.uid == uid) {
bb7cd1
+            if (uuid_compare(uuid, ccwrap->cc->uuid) == 0) {
bb7cd1
+                out = ccwrap;
bb7cd1
+                break;
bb7cd1
+            }
bb7cd1
+        }
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    return out;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static struct ccache_mem_wrap *memdb_get_by_name(struct ccdb_mem *memdb,
bb7cd1
+                                                 struct cli_creds *client,
bb7cd1
+                                                 const char *name)
bb7cd1
+{
bb7cd1
+    uid_t uid;
bb7cd1
+    struct ccache_mem_wrap *ccwrap = NULL;
bb7cd1
+    struct ccache_mem_wrap *out = NULL;
bb7cd1
+
bb7cd1
+    uid = cli_creds_get_uid(client);
bb7cd1
+
bb7cd1
+    DLIST_FOR_EACH(ccwrap, memdb->head) {
bb7cd1
+        if (ccwrap->cc == NULL) {
bb7cd1
+            /* since KCM stores ccaches, better not crash.. */
bb7cd1
+            DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n");
bb7cd1
+            continue;
bb7cd1
+        }
bb7cd1
+
bb7cd1
+        if (ccwrap->cc->owner.uid == uid) {
bb7cd1
+            if (strcmp(ccwrap->cc->name, name) == 0) {
bb7cd1
+                out = ccwrap;
bb7cd1
+                break;
bb7cd1
+            }
bb7cd1
+        }
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    return out;
bb7cd1
+}
bb7cd1
+
bb7cd1
+/* Since with the in-memory database, the database operations are just
bb7cd1
+ * fake-async wrappers around otherwise sync operations, we don't often
bb7cd1
+ * need any state, so we use this empty structure instead
bb7cd1
+ */
bb7cd1
+struct ccdb_mem_dummy_state {
bb7cd1
+};
bb7cd1
+
bb7cd1
+static int ccwrap_destructor(void *ptr)
bb7cd1
+{
bb7cd1
+    struct ccache_mem_wrap *ccwrap = talloc_get_type(ptr, struct ccache_mem_wrap);
bb7cd1
+
bb7cd1
+    if (ccwrap == NULL) {
bb7cd1
+        return 0;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    if (ccwrap->cc != NULL) {
bb7cd1
+        if (ccwrap->cc->creds) {
bb7cd1
+            safezero(sss_iobuf_get_data(ccwrap->cc->creds->cred_blob),
bb7cd1
+                     sss_iobuf_get_size(ccwrap->cc->creds->cred_blob));
bb7cd1
+        }
bb7cd1
+    }
bb7cd1
+
bb7cd1
+
bb7cd1
+    DLIST_REMOVE(ccwrap->mem_be->head, ccwrap);
bb7cd1
+
bb7cd1
+    return 0;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static errno_t ccdb_mem_init(struct kcm_ccdb *db)
bb7cd1
+{
bb7cd1
+    struct ccdb_mem *memdb = NULL;
bb7cd1
+
bb7cd1
+    memdb = talloc_zero(db, struct ccdb_mem);
bb7cd1
+    if (memdb == NULL) {
bb7cd1
+        return ENOMEM;
bb7cd1
+    }
bb7cd1
+    db->db_handle = memdb;
bb7cd1
+
bb7cd1
+    return EOK;
bb7cd1
+}
bb7cd1
+
bb7cd1
+struct ccdb_mem_nextid_state {
bb7cd1
+    unsigned int nextid;
bb7cd1
+};
bb7cd1
+
bb7cd1
+static struct tevent_req *ccdb_mem_nextid_send(TALLOC_CTX *mem_ctx,
bb7cd1
+                                               struct tevent_context *ev,
bb7cd1
+                                               struct kcm_ccdb *db,
bb7cd1
+                                               struct cli_creds *client)
bb7cd1
+{
bb7cd1
+    struct tevent_req *req = NULL;
bb7cd1
+    struct ccdb_mem_nextid_state *state = NULL;
bb7cd1
+    struct ccdb_mem *memdb = NULL;
bb7cd1
+    errno_t ret;
bb7cd1
+
bb7cd1
+    req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_nextid_state);
bb7cd1
+    if (req == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
bb7cd1
+    if (memdb == NULL) {
bb7cd1
+        ret = EIO;
bb7cd1
+        goto immediate;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    state->nextid = memdb->nextid++;
bb7cd1
+
bb7cd1
+    ret = EOK;
bb7cd1
+immediate:
bb7cd1
+    if (ret == EOK) {
bb7cd1
+        tevent_req_done(req);
bb7cd1
+    } else {
bb7cd1
+        tevent_req_error(req, ret);
bb7cd1
+    }
bb7cd1
+    tevent_req_post(req, ev);
bb7cd1
+    return req;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static errno_t ccdb_mem_nextid_recv(struct tevent_req *req,
bb7cd1
+                                    unsigned int *_nextid)
bb7cd1
+{
bb7cd1
+    struct ccdb_mem_nextid_state *state = tevent_req_data(req,
bb7cd1
+                                                struct ccdb_mem_nextid_state);
bb7cd1
+
bb7cd1
+    TEVENT_REQ_RETURN_ON_ERROR(req);
bb7cd1
+    *_nextid = state->nextid;
bb7cd1
+    return EOK;
bb7cd1
+}
bb7cd1
+
bb7cd1
+struct ccdb_mem_list_state {
bb7cd1
+    uuid_t *uuid_list;
bb7cd1
+};
bb7cd1
+
bb7cd1
+static struct tevent_req *ccdb_mem_list_send(TALLOC_CTX *mem_ctx,
bb7cd1
+                                             struct tevent_context *ev,
bb7cd1
+                                             struct kcm_ccdb *db,
bb7cd1
+                                             struct cli_creds *client)
bb7cd1
+{
bb7cd1
+    struct tevent_req *req = NULL;
bb7cd1
+    struct ccache_mem_wrap *ccwrap = NULL;
bb7cd1
+    struct ccdb_mem_list_state *state = NULL;
bb7cd1
+    struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
bb7cd1
+    size_t num_ccaches = 0;
bb7cd1
+    size_t cc_index = 0;
bb7cd1
+    errno_t ret;
bb7cd1
+    uid_t uid;
bb7cd1
+
bb7cd1
+    req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_list_state);
bb7cd1
+    if (req == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    uid = cli_creds_get_uid(client);
bb7cd1
+
bb7cd1
+    DLIST_FOR_EACH(ccwrap, memdb->head) {
bb7cd1
+        if (ccwrap->cc->owner.uid == uid) {
bb7cd1
+            num_ccaches++;
bb7cd1
+        }
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    state->uuid_list = talloc_zero_array(state, uuid_t, num_ccaches+1);
bb7cd1
+    if (state->uuid_list == NULL) {
bb7cd1
+        ret = ENOMEM;
bb7cd1
+        goto immediate;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    cc_index = 0;
bb7cd1
+    DLIST_FOR_EACH(ccwrap, memdb->head) {
bb7cd1
+        if (ccwrap->cc->owner.uid == uid) {
bb7cd1
+            uuid_copy(state->uuid_list[cc_index], ccwrap->cc->uuid);
bb7cd1
+            cc_index++;
bb7cd1
+        }
bb7cd1
+    }
bb7cd1
+    uuid_clear(state->uuid_list[num_ccaches]);
bb7cd1
+
bb7cd1
+    ret = EOK;
bb7cd1
+immediate:
bb7cd1
+    if (ret == EOK) {
bb7cd1
+        tevent_req_done(req);
bb7cd1
+    } else {
bb7cd1
+        tevent_req_error(req, ret);
bb7cd1
+    }
bb7cd1
+    tevent_req_post(req, ev);
bb7cd1
+    return req;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static errno_t ccdb_mem_list_recv(struct tevent_req *req,
bb7cd1
+                                  TALLOC_CTX *mem_ctx,
bb7cd1
+                                  uuid_t **_uuid_list)
bb7cd1
+{
bb7cd1
+    struct ccdb_mem_list_state *state = tevent_req_data(req,
bb7cd1
+                                                struct ccdb_mem_list_state);
bb7cd1
+
bb7cd1
+    TEVENT_REQ_RETURN_ON_ERROR(req);
bb7cd1
+    *_uuid_list = talloc_steal(mem_ctx, state->uuid_list);
bb7cd1
+    return EOK;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static struct tevent_req *ccdb_mem_set_default_send(TALLOC_CTX *mem_ctx,
bb7cd1
+                                                    struct tevent_context *ev,
bb7cd1
+                                                    struct kcm_ccdb *db,
bb7cd1
+                                                    struct cli_creds *client,
bb7cd1
+                                                    uuid_t uuid)
bb7cd1
+{
bb7cd1
+    struct tevent_req *req = NULL;
bb7cd1
+    struct ccdb_mem_dummy_state *state = NULL;
bb7cd1
+    struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
bb7cd1
+    struct ccache_mem_wrap *ccwrap = NULL;
bb7cd1
+    uid_t uid = cli_creds_get_uid(client);
bb7cd1
+
bb7cd1
+    req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state);
bb7cd1
+    if (req == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    /* Reset all ccache defaults first */
bb7cd1
+    DLIST_FOR_EACH(ccwrap, memdb->head) {
bb7cd1
+        if (ccwrap->cc == NULL) {
bb7cd1
+            /* since KCM stores ccaches, better not crash.. */
bb7cd1
+            DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n");
bb7cd1
+            continue;
bb7cd1
+        }
bb7cd1
+
bb7cd1
+        if (ccwrap->cc->owner.uid == uid) {
bb7cd1
+            ccwrap->is_default = false;
bb7cd1
+        }
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    /* Then set the default for the right ccache. This also allows to
bb7cd1
+     * pass a null uuid to just reset the old ccache (for example after
bb7cd1
+     * deleting the default
bb7cd1
+     */
bb7cd1
+    ccwrap = memdb_get_by_uuid(memdb, client, uuid);
bb7cd1
+    if (ccwrap != NULL) {
bb7cd1
+        ccwrap->is_default = true;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    tevent_req_done(req);
bb7cd1
+    tevent_req_post(req, ev);
bb7cd1
+    return req;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static errno_t ccdb_mem_set_default_recv(struct tevent_req *req)
bb7cd1
+{
bb7cd1
+    TEVENT_REQ_RETURN_ON_ERROR(req);
bb7cd1
+    return EOK;
bb7cd1
+}
bb7cd1
+
bb7cd1
+struct ccdb_mem_get_default_state {
bb7cd1
+    uuid_t dfl_uuid;
bb7cd1
+};
bb7cd1
+
bb7cd1
+static struct tevent_req *ccdb_mem_get_default_send(TALLOC_CTX *mem_ctx,
bb7cd1
+                                                    struct tevent_context *ev,
bb7cd1
+                                                    struct kcm_ccdb *db,
bb7cd1
+                                                    struct cli_creds *client)
bb7cd1
+{
bb7cd1
+    struct tevent_req *req = NULL;
bb7cd1
+    struct ccdb_mem_get_default_state *state = NULL;
bb7cd1
+    struct ccache_mem_wrap *ccwrap = NULL;
bb7cd1
+    struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
bb7cd1
+    uid_t uid = cli_creds_get_uid(client);
bb7cd1
+
bb7cd1
+    req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_get_default_state);
bb7cd1
+    if (req == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+
bb7cd1
+    /* Reset all ccache defaults first */
bb7cd1
+    DLIST_FOR_EACH(ccwrap, memdb->head) {
bb7cd1
+        if (ccwrap->cc == NULL) {
bb7cd1
+            /* since KCM stores ccaches, better not crash.. */
bb7cd1
+            DEBUG(SSSDBG_CRIT_FAILURE, "BUG: ccwrap contains NULL cc\n");
bb7cd1
+            continue;
bb7cd1
+        }
bb7cd1
+
bb7cd1
+        if (ccwrap->cc->owner.uid == uid && ccwrap->is_default == true) {
bb7cd1
+            break;
bb7cd1
+        }
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    if (ccwrap == NULL) {
bb7cd1
+        DEBUG(SSSDBG_TRACE_FUNC,
bb7cd1
+               "No ccache marked as default, returning null ccache\n");
bb7cd1
+        uuid_clear(state->dfl_uuid);
bb7cd1
+    } else {
bb7cd1
+        uuid_copy(state->dfl_uuid, ccwrap->cc->uuid);
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    tevent_req_done(req);
bb7cd1
+    tevent_req_post(req, ev);
bb7cd1
+    return req;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static errno_t ccdb_mem_get_default_recv(struct tevent_req *req,
bb7cd1
+                                         uuid_t dfl)
bb7cd1
+{
bb7cd1
+    struct ccdb_mem_get_default_state *state = tevent_req_data(req,
bb7cd1
+                                                struct ccdb_mem_get_default_state);
bb7cd1
+
bb7cd1
+    TEVENT_REQ_RETURN_ON_ERROR(req);
bb7cd1
+
bb7cd1
+    uuid_copy(dfl, state->dfl_uuid);
bb7cd1
+    return EOK;
bb7cd1
+}
bb7cd1
+
bb7cd1
+struct ccdb_mem_getbyuuid_state {
bb7cd1
+    struct kcm_ccache *cc;
bb7cd1
+};
bb7cd1
+
bb7cd1
+static struct tevent_req *ccdb_mem_getbyuuid_send(TALLOC_CTX *mem_ctx,
bb7cd1
+                                                  struct tevent_context *ev,
bb7cd1
+                                                  struct kcm_ccdb *db,
bb7cd1
+                                                  struct cli_creds *client,
bb7cd1
+                                                  uuid_t uuid)
bb7cd1
+{
bb7cd1
+    struct tevent_req *req = NULL;
bb7cd1
+    struct ccdb_mem_getbyuuid_state *state = NULL;
bb7cd1
+    struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
bb7cd1
+    struct ccache_mem_wrap *ccwrap = NULL;
bb7cd1
+
bb7cd1
+    req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_getbyuuid_state);
bb7cd1
+    if (req == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ccwrap = memdb_get_by_uuid(memdb, client, uuid);
bb7cd1
+    if (ccwrap != NULL) {
bb7cd1
+        state->cc = kcm_ccache_dup(state, ccwrap->cc);
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    tevent_req_done(req);
bb7cd1
+    tevent_req_post(req, ev);
bb7cd1
+    return req;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static errno_t ccdb_mem_getbyuuid_recv(struct tevent_req *req,
bb7cd1
+                                       TALLOC_CTX *mem_ctx,
bb7cd1
+                                       struct kcm_ccache **_cc)
bb7cd1
+{
bb7cd1
+    struct ccdb_mem_getbyuuid_state *state = tevent_req_data(req,
bb7cd1
+                                                struct ccdb_mem_getbyuuid_state);
bb7cd1
+
bb7cd1
+    TEVENT_REQ_RETURN_ON_ERROR(req);
bb7cd1
+    *_cc = talloc_steal(mem_ctx, state->cc);
bb7cd1
+    return EOK;
bb7cd1
+}
bb7cd1
+
bb7cd1
+struct ccdb_mem_getbyname_state {
bb7cd1
+    struct kcm_ccache *cc;
bb7cd1
+};
bb7cd1
+
bb7cd1
+static struct tevent_req *ccdb_mem_getbyname_send(TALLOC_CTX *mem_ctx,
bb7cd1
+                                                  struct tevent_context *ev,
bb7cd1
+                                                  struct kcm_ccdb *db,
bb7cd1
+                                                  struct cli_creds *client,
bb7cd1
+                                                  const char *name)
bb7cd1
+{
bb7cd1
+    struct tevent_req *req = NULL;
bb7cd1
+    struct ccdb_mem_getbyname_state *state = NULL;
bb7cd1
+    struct ccache_mem_wrap *ccwrap = NULL;
bb7cd1
+    struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
bb7cd1
+
bb7cd1
+    req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_getbyname_state);
bb7cd1
+    if (req == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ccwrap = memdb_get_by_name(memdb, client, name);
bb7cd1
+    if (ccwrap != NULL) {
bb7cd1
+        state->cc = kcm_ccache_dup(state, ccwrap->cc);
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    tevent_req_done(req);
bb7cd1
+    tevent_req_post(req, ev);
bb7cd1
+    return req;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static errno_t ccdb_mem_getbyname_recv(struct tevent_req *req,
bb7cd1
+                                       TALLOC_CTX *mem_ctx,
bb7cd1
+                                       struct kcm_ccache **_cc)
bb7cd1
+{
bb7cd1
+    struct ccdb_mem_getbyname_state *state = tevent_req_data(req,
bb7cd1
+                                                struct ccdb_mem_getbyname_state);
bb7cd1
+
bb7cd1
+    TEVENT_REQ_RETURN_ON_ERROR(req);
bb7cd1
+    *_cc = talloc_steal(mem_ctx, state->cc);
bb7cd1
+    return EOK;
bb7cd1
+}
bb7cd1
+
bb7cd1
+struct ccdb_mem_name_by_uuid_state {
bb7cd1
+    const char *name;
bb7cd1
+};
bb7cd1
+
bb7cd1
+struct tevent_req *ccdb_mem_name_by_uuid_send(TALLOC_CTX *mem_ctx,
bb7cd1
+                                              struct tevent_context *ev,
bb7cd1
+                                              struct kcm_ccdb *db,
bb7cd1
+                                              struct cli_creds *client,
bb7cd1
+                                              uuid_t uuid)
bb7cd1
+{
bb7cd1
+    struct tevent_req *req = NULL;
bb7cd1
+    struct ccdb_mem_name_by_uuid_state *state = NULL;
bb7cd1
+    struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
bb7cd1
+    struct ccache_mem_wrap *ccwrap = NULL;
bb7cd1
+    errno_t ret;
bb7cd1
+
bb7cd1
+    req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_name_by_uuid_state);
bb7cd1
+    if (req == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ccwrap = memdb_get_by_uuid(memdb, client, uuid);
bb7cd1
+    if (ccwrap == NULL) {
bb7cd1
+        ret = ERR_KCM_CC_END;
bb7cd1
+        goto immediate;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    state->name = talloc_strdup(state, ccwrap->cc->name);
bb7cd1
+    if (state->name == NULL) {
bb7cd1
+        ret = ENOMEM;
bb7cd1
+        goto immediate;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ret = EOK;
bb7cd1
+immediate:
bb7cd1
+    if (ret == EOK) {
bb7cd1
+        tevent_req_done(req);
bb7cd1
+    } else {
bb7cd1
+        tevent_req_error(req, ret);
bb7cd1
+    }
bb7cd1
+    tevent_req_post(req, ev);
bb7cd1
+    return req;
bb7cd1
+}
bb7cd1
+
bb7cd1
+errno_t ccdb_mem_name_by_uuid_recv(struct tevent_req *req,
bb7cd1
+                                   TALLOC_CTX *mem_ctx,
bb7cd1
+                                   const char **_name)
bb7cd1
+{
bb7cd1
+    struct ccdb_mem_name_by_uuid_state *state = tevent_req_data(req,
bb7cd1
+                                                struct ccdb_mem_name_by_uuid_state);
bb7cd1
+    TEVENT_REQ_RETURN_ON_ERROR(req);
bb7cd1
+    *_name = talloc_steal(mem_ctx, state->name);
bb7cd1
+    return EOK;
bb7cd1
+}
bb7cd1
+
bb7cd1
+struct ccdb_mem_uuid_by_name_state {
bb7cd1
+    uuid_t uuid;
bb7cd1
+};
bb7cd1
+
bb7cd1
+struct tevent_req *ccdb_mem_uuid_by_name_send(TALLOC_CTX *mem_ctx,
bb7cd1
+                                              struct tevent_context *ev,
bb7cd1
+                                              struct kcm_ccdb *db,
bb7cd1
+                                              struct cli_creds *client,
bb7cd1
+                                              const char *name)
bb7cd1
+{
bb7cd1
+    struct tevent_req *req = NULL;
bb7cd1
+    struct ccdb_mem_uuid_by_name_state *state = NULL;
bb7cd1
+    struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
bb7cd1
+    struct ccache_mem_wrap *ccwrap = NULL;
bb7cd1
+    errno_t ret;
bb7cd1
+
bb7cd1
+    req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_uuid_by_name_state);
bb7cd1
+    if (req == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ccwrap = memdb_get_by_name(memdb, client, name);
bb7cd1
+    if (ccwrap == NULL) {
bb7cd1
+        ret = ERR_KCM_CC_END;
bb7cd1
+        goto immediate;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    uuid_copy(state->uuid, ccwrap->cc->uuid);
bb7cd1
+
bb7cd1
+    ret = EOK;
bb7cd1
+immediate:
bb7cd1
+    if (ret == EOK) {
bb7cd1
+        tevent_req_done(req);
bb7cd1
+    } else {
bb7cd1
+        tevent_req_error(req, ret);
bb7cd1
+    }
bb7cd1
+    tevent_req_post(req, ev);
bb7cd1
+    return req;
bb7cd1
+}
bb7cd1
+
bb7cd1
+errno_t ccdb_mem_uuid_by_name_recv(struct tevent_req *req,
bb7cd1
+                                   TALLOC_CTX *mem_ctx,
bb7cd1
+                                   uuid_t _uuid)
bb7cd1
+{
bb7cd1
+    struct ccdb_mem_uuid_by_name_state *state = tevent_req_data(req,
bb7cd1
+                                                struct ccdb_mem_uuid_by_name_state);
bb7cd1
+    TEVENT_REQ_RETURN_ON_ERROR(req);
bb7cd1
+    uuid_copy(_uuid, state->uuid);
bb7cd1
+    return EOK;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static struct tevent_req *ccdb_mem_create_send(TALLOC_CTX *mem_ctx,
bb7cd1
+                                               struct tevent_context *ev,
bb7cd1
+                                               struct kcm_ccdb *db,
bb7cd1
+                                               struct cli_creds *client,
bb7cd1
+                                               struct kcm_ccache *cc)
bb7cd1
+{
bb7cd1
+    struct tevent_req *req = NULL;
bb7cd1
+    struct ccdb_mem_dummy_state *state = NULL;
bb7cd1
+    struct ccache_mem_wrap *ccwrap;
bb7cd1
+    struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
bb7cd1
+    errno_t ret;
bb7cd1
+
bb7cd1
+    req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state);
bb7cd1
+    if (req == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ccwrap = talloc_zero(memdb, struct ccache_mem_wrap);
bb7cd1
+    if (ccwrap == NULL) {
bb7cd1
+        ret = ENOMEM;
bb7cd1
+        goto immediate;
bb7cd1
+    }
bb7cd1
+    ccwrap->cc = cc;
bb7cd1
+    ccwrap->mem_be = memdb;
bb7cd1
+    talloc_steal(ccwrap, cc);
bb7cd1
+
bb7cd1
+    DLIST_ADD(memdb->head, ccwrap);
bb7cd1
+    talloc_set_destructor((TALLOC_CTX *) ccwrap, ccwrap_destructor);
bb7cd1
+
bb7cd1
+    ret = EOK;
bb7cd1
+immediate:
bb7cd1
+    if (ret == EOK) {
bb7cd1
+        tevent_req_done(req);
bb7cd1
+    } else {
bb7cd1
+        tevent_req_error(req, ret);
bb7cd1
+    }
bb7cd1
+    tevent_req_post(req, ev);
bb7cd1
+    return req;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static errno_t ccdb_mem_create_recv(struct tevent_req *req)
bb7cd1
+{
bb7cd1
+    TEVENT_REQ_RETURN_ON_ERROR(req);
bb7cd1
+    return EOK;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static struct tevent_req *ccdb_mem_mod_send(TALLOC_CTX *mem_ctx,
bb7cd1
+                                            struct tevent_context *ev,
bb7cd1
+                                            struct kcm_ccdb *db,
bb7cd1
+                                            struct cli_creds *client,
bb7cd1
+                                            uuid_t uuid,
bb7cd1
+                                            struct kcm_mod_ctx *mod_cc)
bb7cd1
+{
bb7cd1
+    errno_t ret;
bb7cd1
+    struct tevent_req *req = NULL;
bb7cd1
+    struct ccdb_mem_dummy_state *state = NULL;
bb7cd1
+    struct ccache_mem_wrap *ccwrap = NULL;
bb7cd1
+    struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
bb7cd1
+
bb7cd1
+    req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state);
bb7cd1
+    if (req == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    /* UUID is immutable, so search by that */
bb7cd1
+    ccwrap = memdb_get_by_uuid(memdb, client, uuid);
bb7cd1
+    if (ccwrap == NULL) {
bb7cd1
+        ret = ERR_KCM_CC_END;
bb7cd1
+        goto immediate;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    kcm_mod_cc(ccwrap->cc, mod_cc);
bb7cd1
+
bb7cd1
+    ret = EOK;
bb7cd1
+immediate:
bb7cd1
+    if (ret == EOK) {
bb7cd1
+        tevent_req_done(req);
bb7cd1
+    } else {
bb7cd1
+        tevent_req_error(req, ret);
bb7cd1
+    }
bb7cd1
+    tevent_req_post(req, ev);
bb7cd1
+    return req;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static errno_t ccdb_mem_mod_recv(struct tevent_req *req)
bb7cd1
+{
bb7cd1
+    TEVENT_REQ_RETURN_ON_ERROR(req);
bb7cd1
+    return EOK;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static struct tevent_req *ccdb_mem_store_cred_send(TALLOC_CTX *mem_ctx,
bb7cd1
+                                                   struct tevent_context *ev,
bb7cd1
+                                                   struct kcm_ccdb *db,
bb7cd1
+                                                   struct cli_creds *client,
bb7cd1
+                                                   uuid_t uuid,
bb7cd1
+                                                   struct sss_iobuf *cred_blob)
bb7cd1
+{
bb7cd1
+    struct tevent_req *req = NULL;
bb7cd1
+    struct ccdb_mem_dummy_state *state = NULL;
bb7cd1
+    struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
bb7cd1
+    struct ccache_mem_wrap *ccwrap = NULL;
bb7cd1
+    errno_t ret;
bb7cd1
+
bb7cd1
+    req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state);
bb7cd1
+    if (req == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ccwrap = memdb_get_by_uuid(memdb, client, uuid);
bb7cd1
+    if (ccwrap == NULL) {
bb7cd1
+        ret = ERR_KCM_CC_END;
bb7cd1
+        goto immediate;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ret = kcm_cc_store_cred_blob(ccwrap->cc, cred_blob);
bb7cd1
+    if (ret != EOK) {
bb7cd1
+        DEBUG(SSSDBG_OP_FAILURE,
bb7cd1
+              "Cannot store credentials to ccache [%d]: %s\n",
bb7cd1
+              ret, sss_strerror(ret));
bb7cd1
+        goto immediate;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ret = EOK;
bb7cd1
+immediate:
bb7cd1
+    if (ret == EOK) {
bb7cd1
+        tevent_req_done(req);
bb7cd1
+    } else {
bb7cd1
+        tevent_req_error(req, ret);
bb7cd1
+    }
bb7cd1
+    tevent_req_post(req, ev);
bb7cd1
+    return req;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static errno_t ccdb_mem_store_cred_recv(struct tevent_req *req)
bb7cd1
+{
bb7cd1
+    TEVENT_REQ_RETURN_ON_ERROR(req);
bb7cd1
+    return EOK;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static struct tevent_req *ccdb_mem_delete_send(TALLOC_CTX *mem_ctx,
bb7cd1
+                                               struct tevent_context *ev,
bb7cd1
+                                               struct kcm_ccdb *db,
bb7cd1
+                                               struct cli_creds *client,
bb7cd1
+                                               uuid_t uuid)
bb7cd1
+{
bb7cd1
+    struct tevent_req *req = NULL;
bb7cd1
+    struct ccdb_mem_dummy_state *state = NULL;
bb7cd1
+    struct ccache_mem_wrap *ccwrap;
bb7cd1
+    struct ccdb_mem *memdb = talloc_get_type(db->db_handle, struct ccdb_mem);
bb7cd1
+    errno_t ret;
bb7cd1
+
bb7cd1
+    req = tevent_req_create(mem_ctx, &state, struct ccdb_mem_dummy_state);
bb7cd1
+    if (req == NULL) {
bb7cd1
+        return NULL;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ccwrap = memdb_get_by_uuid(memdb, client, uuid);
bb7cd1
+    if (ccwrap == NULL) {
bb7cd1
+        DEBUG(SSSDBG_MINOR_FAILURE,
bb7cd1
+              "BUG: Attempting to free unknown ccache\n");
bb7cd1
+        ret = ERR_KCM_CC_END;
bb7cd1
+        goto immediate;
bb7cd1
+    }
bb7cd1
+
bb7cd1
+    ret = EOK;
bb7cd1
+    /* Destructor takes care of everything */
bb7cd1
+    talloc_free(ccwrap);
bb7cd1
+immediate:
bb7cd1
+    if (ret == EOK) {
bb7cd1
+        tevent_req_done(req);
bb7cd1
+    } else {
bb7cd1
+        tevent_req_error(req, ret);
bb7cd1
+    }
bb7cd1
+    tevent_req_post(req, ev);
bb7cd1
+    return req;
bb7cd1
+}
bb7cd1
+
bb7cd1
+static errno_t ccdb_mem_delete_recv(struct tevent_req *req)
bb7cd1
+{
bb7cd1
+    TEVENT_REQ_RETURN_ON_ERROR(req);
bb7cd1
+    return EOK;
bb7cd1
+}
bb7cd1
+
bb7cd1
+const struct kcm_ccdb_ops ccdb_mem_ops = {
bb7cd1
+    .init = ccdb_mem_init,
bb7cd1
+
bb7cd1
+    .nextid_send = ccdb_mem_nextid_send,
bb7cd1
+    .nextid_recv = ccdb_mem_nextid_recv,
bb7cd1
+
bb7cd1
+    .set_default_send = ccdb_mem_set_default_send,
bb7cd1
+    .set_default_recv = ccdb_mem_set_default_recv,
bb7cd1
+
bb7cd1
+    .get_default_send = ccdb_mem_get_default_send,
bb7cd1
+    .get_default_recv = ccdb_mem_get_default_recv,
bb7cd1
+
bb7cd1
+    .list_send = ccdb_mem_list_send,
bb7cd1
+    .list_recv = ccdb_mem_list_recv,
bb7cd1
+
bb7cd1
+    .getbyname_send = ccdb_mem_getbyname_send,
bb7cd1
+    .getbyname_recv = ccdb_mem_getbyname_recv,
bb7cd1
+
bb7cd1
+    .getbyuuid_send = ccdb_mem_getbyuuid_send,
bb7cd1
+    .getbyuuid_recv = ccdb_mem_getbyuuid_recv,
bb7cd1
+
bb7cd1
+    .name_by_uuid_send = ccdb_mem_name_by_uuid_send,
bb7cd1
+    .name_by_uuid_recv = ccdb_mem_name_by_uuid_recv,
bb7cd1
+
bb7cd1
+    .uuid_by_name_send = ccdb_mem_uuid_by_name_send,
bb7cd1
+    .uuid_by_name_recv = ccdb_mem_uuid_by_name_recv,
bb7cd1
+
bb7cd1
+    .create_send = ccdb_mem_create_send,
bb7cd1
+    .create_recv = ccdb_mem_create_recv,
bb7cd1
+
bb7cd1
+    .mod_send = ccdb_mem_mod_send,
bb7cd1
+    .mod_recv = ccdb_mem_mod_recv,
bb7cd1
+
bb7cd1
+    .store_cred_send = ccdb_mem_store_cred_send,
bb7cd1
+    .store_cred_recv = ccdb_mem_store_cred_recv,
bb7cd1
+
bb7cd1
+    .delete_send = ccdb_mem_delete_send,
bb7cd1
+    .delete_recv = ccdb_mem_delete_recv,
bb7cd1
+};
bb7cd1
-- 
bb7cd1
2.9.3
bb7cd1