Blame SOURCES/0024-KCM-Implement-an-internal-ccache-storage-and-retriev.patch

ecf709
From 79f6ccd2dc3f0c1369d5a93678c88ee76ec761e0 Mon Sep 17 00:00:00 2001
ecf709
From: Jakub Hrozek <jhrozek@redhat.com>
ecf709
Date: Tue, 7 Mar 2017 13:49:21 +0100
ecf709
Subject: [PATCH 24/36] KCM: Implement an internal ccache storage and retrieval
ecf709
 API
ecf709
MIME-Version: 1.0
ecf709
Content-Type: text/plain; charset=UTF-8
ecf709
Content-Transfer-Encoding: 8bit
ecf709
ecf709
In order for the KCM server to work with ccaches stored in different
ecf709
locations, implement a middle-man between the KCM server and the ccache
ecf709
storage.
ecf709
ecf709
This module has asynchronous API because we can't assume anything about
ecf709
where the ccaches are stored.
ecf709
ecf709
Reviewed-by: Michal Židek <mzidek@redhat.com>
ecf709
Reviewed-by: Simo Sorce <simo@redhat.com>
ecf709
---
ecf709
 Makefile.am                           |    9 +
ecf709
 configure.ac                          |    1 +
ecf709
 contrib/sssd.spec.in                  |    1 +
ecf709
 src/external/libuuid.m4               |   17 +
ecf709
 src/responder/kcm/kcmsrv_ccache.c     | 1423 +++++++++++++++++++++++++++++++++
ecf709
 src/responder/kcm/kcmsrv_ccache.h     |  306 +++++++
ecf709
 src/responder/kcm/kcmsrv_ccache_be.h  |  204 +++++
ecf709
 src/responder/kcm/kcmsrv_ccache_pvt.h |   62 ++
ecf709
 src/responder/kcm/kcmsrv_pvt.h        |    1 +
ecf709
 9 files changed, 2024 insertions(+)
ecf709
 create mode 100644 src/external/libuuid.m4
ecf709
 create mode 100644 src/responder/kcm/kcmsrv_ccache.c
ecf709
 create mode 100644 src/responder/kcm/kcmsrv_ccache.h
ecf709
 create mode 100644 src/responder/kcm/kcmsrv_ccache_be.h
ecf709
 create mode 100644 src/responder/kcm/kcmsrv_ccache_pvt.h
ecf709
ecf709
diff --git a/Makefile.am b/Makefile.am
ecf709
index 4248536e90370c1aab59549a9c18408ef314e6d4..a2b9dc49e95fa2d025f5174d2902866fab180a78 100644
ecf709
--- a/Makefile.am
ecf709
+++ b/Makefile.am
ecf709
@@ -711,6 +711,9 @@ dist_noinst_HEADERS = \
ecf709
     src/responder/secrets/secsrv_proxy.h \
ecf709
     src/responder/kcm/kcm.h \
ecf709
     src/responder/kcm/kcmsrv_pvt.h \
ecf709
+    src/responder/kcm/kcmsrv_ccache.h \
ecf709
+    src/responder/kcm/kcmsrv_ccache_pvt.h \
ecf709
+    src/responder/kcm/kcmsrv_ccache_be.h \
ecf709
     src/sbus/sbus_client.h \
ecf709
     src/sbus/sssd_dbus.h \
ecf709
     src/sbus/sssd_dbus_meta.h \
ecf709
@@ -1488,16 +1491,22 @@ if BUILD_KCM
ecf709
 sssd_kcm_SOURCES = \
ecf709
     src/responder/kcm/kcm.c \
ecf709
     src/responder/kcm/kcmsrv_cmd.c \
ecf709
+    src/responder/kcm/kcmsrv_ccache.c \
ecf709
     src/util/sss_sockets.c \
ecf709
+    src/util/sss_krb5.c \
ecf709
+    src/util/sss_iobuf.c \
ecf709
     $(SSSD_RESPONDER_OBJ) \
ecf709
     $(NULL)
ecf709
 sssd_kcm_CFLAGS = \
ecf709
     $(AM_CFLAGS) \
ecf709
     $(KRB5_CFLAGS) \
ecf709
+    $(UUID_CFLAGS) \
ecf709
     $(NULL)
ecf709
 sssd_kcm_LDADD = \
ecf709
     $(KRB5_LIBS) \
ecf709
     $(SSSD_LIBS) \
ecf709
+    $(UUID_LIBS) \
ecf709
+    $(SYSTEMD_DAEMON_LIBS) \
ecf709
     $(SSSD_INTERNAL_LTLIBS) \
ecf709
     $(NULL)
ecf709
 endif
ecf709
diff --git a/configure.ac b/configure.ac
ecf709
index c363d48a806cc1998e85779a92b6b59b0e2a5c9c..cf5e2557ef0a1bd6374200aa33abea6c509d03aa 100644
ecf709
--- a/configure.ac
ecf709
+++ b/configure.ac
ecf709
@@ -202,6 +202,7 @@ fi
ecf709
 
ecf709
 if test x$with_kcm = xyes; then
ecf709
     m4_include([src/external/libcurl.m4])
ecf709
+    m4_include([src/external/libuuid.m4])
ecf709
 fi
ecf709
 # This variable is defined by external/libcurl.m4, but conditionals
ecf709
 # must be always evaluated
ecf709
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
ecf709
index 5c7c2af521a84ef2ca6cca7b2d6cd1f9b3057056..52d33b4de281dc1d91a9027ac1c8c878e66fb396 100644
ecf709
--- a/contrib/sssd.spec.in
ecf709
+++ b/contrib/sssd.spec.in
ecf709
@@ -222,6 +222,7 @@ BuildRequires: systemtap-sdt-devel
ecf709
 %endif
ecf709
 BuildRequires: http-parser-devel
ecf709
 BuildRequires: jansson-devel
ecf709
+BuildRequires: libuuid-devel
ecf709
 
ecf709
 %description
ecf709
 Provides a set of daemons to manage access to remote directories and
ecf709
diff --git a/src/external/libuuid.m4 b/src/external/libuuid.m4
ecf709
new file mode 100644
ecf709
index 0000000000000000000000000000000000000000..55411a2118bd787c9d50ba61f9cb791e1c76088d
ecf709
--- /dev/null
ecf709
+++ b/src/external/libuuid.m4
ecf709
@@ -0,0 +1,17 @@
ecf709
+AC_SUBST(UUID_LIBS)
ecf709
+AC_SUBST(UUID_CFLAGS)
ecf709
+
ecf709
+PKG_CHECK_MODULES([UUID], [uuid], [found_uuid=yes], [found_uuid=no])
ecf709
+
ecf709
+SSS_AC_EXPAND_LIB_DIR()
ecf709
+AS_IF([test x"$found_uuid" = xyes],
ecf709
+    [AC_CHECK_HEADERS([uuid/uuid.h],
ecf709
+        [AC_CHECK_LIB([uuid],
ecf709
+                      [uuid_generate],
ecf709
+                      [UUID_LIBS="-L$sss_extra_libdir -luuid"],
ecf709
+                      [AC_MSG_ERROR([libuuid missing uuid_generate])],
ecf709
+                      [-L$sss_extra_libdir -luuid])],
ecf709
+        [AC_MSG_ERROR([
ecf709
+You must have the header file uuid.h installed to build sssd
ecf709
+with KCM responder. If you want to build sssd without KCM responder
ecf709
+then specify --without-kcm when running configure.])])])
ecf709
diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c
ecf709
new file mode 100644
ecf709
index 0000000000000000000000000000000000000000..2c565b8378e3ec297faf655d3c48d7ab902713d3
ecf709
--- /dev/null
ecf709
+++ b/src/responder/kcm/kcmsrv_ccache.c
ecf709
@@ -0,0 +1,1423 @@
ecf709
+/*
ecf709
+   SSSD
ecf709
+
ecf709
+   KCM Server - the KCM ccache operations
ecf709
+
ecf709
+   Copyright (C) Red Hat, 2016
ecf709
+
ecf709
+   This program is free software; you can redistribute it and/or modify
ecf709
+   it under the terms of the GNU General Public License as published by
ecf709
+   the Free Software Foundation; either version 3 of the License, or
ecf709
+   (at your option) any later version.
ecf709
+
ecf709
+   This program is distributed in the hope that it will be useful,
ecf709
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
ecf709
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ecf709
+   GNU General Public License for more details.
ecf709
+
ecf709
+   You should have received a copy of the GNU General Public License
ecf709
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
ecf709
+*/
ecf709
+
ecf709
+#include "config.h"
ecf709
+
ecf709
+#include "util/crypto/sss_crypto.h"
ecf709
+#include "util/util.h"
ecf709
+#include "util/sss_krb5.h"
ecf709
+#include "responder/kcm/kcmsrv_ccache.h"
ecf709
+#include "responder/kcm/kcmsrv_ccache_pvt.h"
ecf709
+#include "responder/kcm/kcmsrv_ccache_be.h"
ecf709
+
ecf709
+static int kcm_cc_destructor(struct kcm_ccache *cc)
ecf709
+{
ecf709
+    if (cc == NULL) {
ecf709
+        return 0;
ecf709
+    }
ecf709
+
ecf709
+    krb5_free_principal(NULL, cc->client);
ecf709
+    return 0;
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_cc_new(TALLOC_CTX *mem_ctx,
ecf709
+                   krb5_context k5c,
ecf709
+                   struct cli_creds *owner,
ecf709
+                   const char *name,
ecf709
+                   krb5_principal princ,
ecf709
+                   struct kcm_ccache **_cc)
ecf709
+{
ecf709
+    struct kcm_ccache *cc;
ecf709
+    krb5_error_code kret;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    cc = talloc_zero(mem_ctx, struct kcm_ccache);
ecf709
+    if (cc == NULL) {
ecf709
+        return ENOMEM;
ecf709
+    }
ecf709
+
ecf709
+    ret = kcm_check_name(name, owner);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_CRIT_FAILURE, "Name %s is malformed\n", name);
ecf709
+        return ret;
ecf709
+    }
ecf709
+
ecf709
+    cc->name = talloc_strdup(cc, name);
ecf709
+    if (cc->name == NULL) {
ecf709
+        talloc_free(cc);
ecf709
+        return ENOMEM;
ecf709
+    }
ecf709
+
ecf709
+    uuid_generate(cc->uuid);
ecf709
+
ecf709
+    kret = krb5_copy_principal(k5c, princ, &cc->client);
ecf709
+    if (kret != 0) {
ecf709
+        const char *err_msg = sss_krb5_get_error_message(k5c, kret);
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "krb5_copy_principal failed: [%d][%s]\n", kret, err_msg);
ecf709
+        sss_krb5_free_error_message(k5c, err_msg);
ecf709
+        talloc_free(cc);
ecf709
+        return ERR_INTERNAL;
ecf709
+    }
ecf709
+
ecf709
+    cc->owner.uid = cli_creds_get_uid(owner);
ecf709
+    cc->owner.gid = cli_creds_get_gid(owner);
ecf709
+    cc->kdc_offset = INT32_MAX;
ecf709
+
ecf709
+    talloc_set_destructor(cc, kcm_cc_destructor);
ecf709
+    *_cc = cc;
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+const char *kcm_cc_get_name(struct kcm_ccache *cc)
ecf709
+{
ecf709
+    return cc ? cc->name : NULL;
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_cc_get_uuid(struct kcm_ccache *cc, uuid_t _uuid)
ecf709
+{
ecf709
+    if (cc == NULL) {
ecf709
+        return EINVAL;
ecf709
+    }
ecf709
+    uuid_copy(_uuid, cc->uuid);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+krb5_principal kcm_cc_get_client_principal(struct kcm_ccache *cc)
ecf709
+{
ecf709
+    return cc ? cc->client : NULL;
ecf709
+}
ecf709
+
ecf709
+bool kcm_cc_access(struct kcm_ccache *cc,
ecf709
+                   struct cli_creds *client)
ecf709
+{
ecf709
+    bool ok;
ecf709
+    uid_t uid = cli_creds_get_uid(client);
ecf709
+    gid_t gid = cli_creds_get_gid(client);
ecf709
+
ecf709
+    if (cc == NULL) {
ecf709
+        return false;
ecf709
+    }
ecf709
+
ecf709
+    if (uid == 0 && gid == 0) {
ecf709
+        /* root can access any ccache */
ecf709
+        return true;
ecf709
+    }
ecf709
+
ecf709
+    ok = ((cc->owner.uid == uid) && (cc->owner.gid == gid));
ecf709
+    if (!ok) {
ecf709
+        DEBUG(SSSDBG_MINOR_FAILURE,
ecf709
+              "Client %"SPRIuid":%"SPRIgid" has no access to ccache %s\n",
ecf709
+              cli_creds_get_uid(client),
ecf709
+              cli_creds_get_gid(client),
ecf709
+              cc->name);
ecf709
+    }
ecf709
+    return ok;
ecf709
+}
ecf709
+
ecf709
+int32_t kcm_cc_get_offset(struct kcm_ccache *cc)
ecf709
+{
ecf709
+    return cc ? cc->kdc_offset : INT32_MAX;
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_cc_store_cred_blob(struct kcm_ccache *cc,
ecf709
+                               struct sss_iobuf *cred_blob)
ecf709
+{
ecf709
+    struct kcm_cred *kcreds;
ecf709
+    uuid_t uuid;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    if (cc == NULL || cred_blob == NULL) {
ecf709
+        return EINVAL;
ecf709
+    }
ecf709
+
ecf709
+    uuid_generate(uuid);
ecf709
+    kcreds = kcm_cred_new(cc, uuid, cred_blob);
ecf709
+    if (kcreds == NULL) {
ecf709
+        return ENOMEM;
ecf709
+    }
ecf709
+
ecf709
+    ret = kcm_cc_store_creds(cc, kcreds);
ecf709
+    if (ret != EOK) {
ecf709
+        return ret;
ecf709
+    }
ecf709
+
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+struct kcm_cred *kcm_cc_get_cred(struct kcm_ccache *cc)
ecf709
+{
ecf709
+    if (cc == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+
ecf709
+    return cc->creds;
ecf709
+}
ecf709
+
ecf709
+struct kcm_cred *kcm_cc_next_cred(struct kcm_cred *crd)
ecf709
+{
ecf709
+    if (crd == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+
ecf709
+    return crd->next;
ecf709
+}
ecf709
+
ecf709
+struct kcm_cred *kcm_cred_new(TALLOC_CTX *mem_ctx,
ecf709
+                              uuid_t uuid,
ecf709
+                              struct sss_iobuf *cred_blob)
ecf709
+{
ecf709
+    struct kcm_cred *kcreds;
ecf709
+
ecf709
+    kcreds = talloc_zero(mem_ctx, struct kcm_cred);
ecf709
+    if (kcreds == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+
ecf709
+    uuid_copy(kcreds->uuid, uuid);
ecf709
+    kcreds->cred_blob = talloc_steal(kcreds, cred_blob);
ecf709
+    return kcreds;
ecf709
+}
ecf709
+
ecf709
+/* Add a cred to ccache */
ecf709
+errno_t kcm_cc_store_creds(struct kcm_ccache *cc,
ecf709
+                           struct kcm_cred *crd)
ecf709
+{
ecf709
+    DLIST_ADD(cc->creds, crd);
ecf709
+    talloc_steal(cc, crd);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_cred_get_uuid(struct kcm_cred *crd, uuid_t _uuid)
ecf709
+{
ecf709
+    if (crd == NULL) {
ecf709
+        return EINVAL;
ecf709
+    }
ecf709
+    uuid_copy(_uuid, crd->uuid);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+struct sss_iobuf *kcm_cred_get_creds(struct kcm_cred *crd)
ecf709
+{
ecf709
+    return crd ? crd->cred_blob : NULL;
ecf709
+}
ecf709
+
ecf709
+struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx,
ecf709
+                               struct tevent_context *ev,
ecf709
+                               enum kcm_ccdb_be cc_be)
ecf709
+{
ecf709
+    errno_t ret;
ecf709
+    struct kcm_ccdb *ccdb = NULL;
ecf709
+
ecf709
+    if (ev == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+
ecf709
+    ccdb = talloc_zero(mem_ctx, struct kcm_ccdb);
ecf709
+    if (ccdb == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+    ccdb->ev = ev;
ecf709
+
ecf709
+    switch (cc_be) {
ecf709
+    case CCDB_BE_MEMORY:
ecf709
+        DEBUG(SSSDBG_FUNC_DATA, "KCM back end: memory\n");
ecf709
+        /* Not implemented yet */
ecf709
+        break;
ecf709
+    case CCDB_BE_SECRETS:
ecf709
+        DEBUG(SSSDBG_FUNC_DATA, "KCM back end: sssd-secrets\n");
ecf709
+        /* Not implemented yet */
ecf709
+        break;
ecf709
+    default:
ecf709
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unknown ccache database\n");
ecf709
+        break;
ecf709
+    }
ecf709
+
ecf709
+    if (ccdb->ops == NULL) {
ecf709
+        DEBUG(SSSDBG_CRIT_FAILURE, "Ccache database not initialized\n");
ecf709
+        talloc_free(ccdb);
ecf709
+        return NULL;
ecf709
+    }
ecf709
+
ecf709
+    ret = ccdb->ops->init(ccdb);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize ccache database\n");
ecf709
+        talloc_free(ccdb);
ecf709
+        return NULL;
ecf709
+    }
ecf709
+
ecf709
+    return ccdb;
ecf709
+}
ecf709
+
ecf709
+struct kcm_ccdb_nextid_state {
ecf709
+    char *next_cc;
ecf709
+    struct kcm_ccdb *db;
ecf709
+    struct cli_creds *client;
ecf709
+};
ecf709
+
ecf709
+static void kcm_ccdb_nextid_done(struct tevent_req *subreq);
ecf709
+
ecf709
+struct tevent_req *kcm_ccdb_nextid_send(TALLOC_CTX *mem_ctx,
ecf709
+                                        struct tevent_context *ev,
ecf709
+                                        struct kcm_ccdb *db,
ecf709
+                                        struct cli_creds *client)
ecf709
+{
ecf709
+    struct tevent_req *req = NULL;
ecf709
+    struct tevent_req *subreq = NULL;
ecf709
+    struct kcm_ccdb_nextid_state *state = NULL;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_nextid_state);
ecf709
+    if (req == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+    state->db = db;
ecf709
+    state->client = client;
ecf709
+
ecf709
+    if (ev == NULL || db == NULL || client == NULL) {
ecf709
+        ret = EINVAL;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+
ecf709
+    subreq = state->db->ops->nextid_send(mem_ctx, ev, state->db, client);
ecf709
+    if (subreq == NULL) {
ecf709
+        ret = ENOMEM;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_nextid_done, req);
ecf709
+    return req;
ecf709
+
ecf709
+immediate:
ecf709
+    tevent_req_error(req, ret);
ecf709
+    tevent_req_post(req, ev);
ecf709
+    return req;
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_nextid_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_nextid_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_nextid_state);
ecf709
+    errno_t ret;
ecf709
+    unsigned int nextid;
ecf709
+
ecf709
+    ret = state->db->ops->nextid_recv(subreq, &nextid);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to generate next UID [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    state->next_cc = talloc_asprintf(state, "%"SPRIuid":%u",
ecf709
+                                     cli_creds_get_uid(state->client),
ecf709
+                                     nextid);
ecf709
+    if (state->next_cc == NULL) {
ecf709
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed\n");
ecf709
+        tevent_req_error(req, ENOMEM);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    DEBUG(SSSDBG_TRACE_LIBS, "generated %s\n", state->next_cc);
ecf709
+    tevent_req_done(req);
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_ccdb_nextid_recv(struct tevent_req *req,
ecf709
+                             TALLOC_CTX *mem_ctx,
ecf709
+                             char **_next_cc)
ecf709
+{
ecf709
+    struct kcm_ccdb_nextid_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_nextid_state);
ecf709
+    TEVENT_REQ_RETURN_ON_ERROR(req);
ecf709
+    *_next_cc = talloc_steal(mem_ctx, state->next_cc);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+struct kcm_ccdb_list_state {
ecf709
+    struct kcm_ccdb *db;
ecf709
+    struct cli_creds *client;
ecf709
+
ecf709
+    uuid_t *uuid_list;
ecf709
+};
ecf709
+
ecf709
+static void kcm_ccdb_list_done(struct tevent_req *subreq);
ecf709
+
ecf709
+struct tevent_req *kcm_ccdb_list_send(TALLOC_CTX *mem_ctx,
ecf709
+                                      struct tevent_context *ev,
ecf709
+                                      struct kcm_ccdb *db,
ecf709
+                                      struct cli_creds *client)
ecf709
+{
ecf709
+    struct tevent_req *req = NULL;
ecf709
+    struct tevent_req *subreq = NULL;
ecf709
+    struct kcm_ccdb_list_state *state = NULL;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_list_state);
ecf709
+    if (req == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+    state->db = db;
ecf709
+    state->client = client;
ecf709
+
ecf709
+    if (ev == NULL || db == NULL || client == NULL) {
ecf709
+        ret = EINVAL;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+
ecf709
+    subreq = state->db->ops->list_send(mem_ctx,
ecf709
+                                       ev,
ecf709
+                                       state->db,
ecf709
+                                       client);
ecf709
+    if (subreq == NULL) {
ecf709
+        ret = ENOMEM;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_list_done, req);
ecf709
+    return req;
ecf709
+
ecf709
+immediate:
ecf709
+    tevent_req_error(req, ret);
ecf709
+    tevent_req_post(req, ev);
ecf709
+    return req;
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_list_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_list_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_list_state);
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    ret = state->db->ops->list_recv(subreq, state, &state->uuid_list);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to list all ccaches [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    tevent_req_done(req);
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_ccdb_list_recv(struct tevent_req *req,
ecf709
+                           TALLOC_CTX *mem_ctx,
ecf709
+                           uuid_t **_uuid_list)
ecf709
+{
ecf709
+    struct kcm_ccdb_list_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_list_state);
ecf709
+    TEVENT_REQ_RETURN_ON_ERROR(req);
ecf709
+    *_uuid_list = talloc_steal(mem_ctx, state->uuid_list);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+struct kcm_ccdb_get_default_state {
ecf709
+    struct kcm_ccdb *db;
ecf709
+    uuid_t uuid;
ecf709
+};
ecf709
+
ecf709
+static void kcm_ccdb_get_default_done(struct tevent_req *subreq);
ecf709
+
ecf709
+struct tevent_req *kcm_ccdb_get_default_send(TALLOC_CTX *mem_ctx,
ecf709
+                                             struct tevent_context *ev,
ecf709
+                                             struct kcm_ccdb *db,
ecf709
+                                             struct cli_creds *client)
ecf709
+{
ecf709
+    struct tevent_req *req = NULL;
ecf709
+    struct tevent_req *subreq = NULL;
ecf709
+    struct kcm_ccdb_get_default_state *state = NULL;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_get_default_state);
ecf709
+    if (req == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+    state->db = db;
ecf709
+
ecf709
+    if (ev == NULL || db == NULL || client == NULL) {
ecf709
+        ret = EINVAL;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+
ecf709
+    subreq = db->ops->get_default_send(mem_ctx, ev, db, client);
ecf709
+    if (subreq == NULL) {
ecf709
+        ret = ENOMEM;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_get_default_done, req);
ecf709
+    return req;
ecf709
+
ecf709
+immediate:
ecf709
+    tevent_req_error(req, ret);
ecf709
+    tevent_req_post(req, ev);
ecf709
+    return req;
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_get_default_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_get_default_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_get_default_state);
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    ret = state->db->ops->get_default_recv(subreq, state->uuid);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to get the default ccache [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    tevent_req_done(req);
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_ccdb_get_default_recv(struct tevent_req *req,
ecf709
+                                  uuid_t *uuid)
ecf709
+{
ecf709
+    struct kcm_ccdb_get_default_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_get_default_state);
ecf709
+    TEVENT_REQ_RETURN_ON_ERROR(req);
ecf709
+
ecf709
+    if (uuid != NULL) {
ecf709
+        /* The caller might supply a NULL dfl to just check if there is
ecf709
+         * some default ccache
ecf709
+         */
ecf709
+        uuid_copy(*uuid, state->uuid);
ecf709
+    }
ecf709
+
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+struct kcm_ccdb_set_default_state {
ecf709
+    struct tevent_context *ev;
ecf709
+    struct kcm_ccdb *db;
ecf709
+    struct cli_creds *client;
ecf709
+    uuid_t uuid;
ecf709
+};
ecf709
+
ecf709
+static void kcm_ccdb_set_default_uuid_resolved(struct tevent_req *subreq);
ecf709
+static void kcm_ccdb_set_default_done(struct tevent_req *subreq);
ecf709
+
ecf709
+struct tevent_req *kcm_ccdb_set_default_send(TALLOC_CTX *mem_ctx,
ecf709
+                                             struct tevent_context *ev,
ecf709
+                                             struct kcm_ccdb *db,
ecf709
+                                             struct cli_creds *client,
ecf709
+                                             uuid_t uuid)
ecf709
+{
ecf709
+    struct tevent_req *req = NULL;
ecf709
+    struct tevent_req *subreq = NULL;
ecf709
+    struct kcm_ccdb_set_default_state *state = NULL;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_set_default_state);
ecf709
+    if (req == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+    state->db = db;
ecf709
+    state->ev = ev;
ecf709
+    state->client = client;
ecf709
+    uuid_copy(state->uuid, uuid);
ecf709
+
ecf709
+    if (ev == NULL || db == NULL || client == NULL) {
ecf709
+        ret = EINVAL;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+
ecf709
+    if (uuid_is_null(uuid)) {
ecf709
+        /* NULL UUID means to just reset the default to 'no default' */
ecf709
+        subreq = state->db->ops->set_default_send(state,
ecf709
+                                                state->ev,
ecf709
+                                                state->db,
ecf709
+                                                state->client,
ecf709
+                                                state->uuid);
ecf709
+        if (subreq == NULL) {
ecf709
+            ret = ENOMEM;
ecf709
+            goto immediate;
ecf709
+        }
ecf709
+        tevent_req_set_callback(subreq, kcm_ccdb_set_default_done, req);
ecf709
+    } else {
ecf709
+        /* Otherwise we need to check if the client can access the UUID
ecf709
+         * about to be set as default
ecf709
+         */
ecf709
+        subreq = db->ops->getbyuuid_send(state, ev, db, client, uuid);
ecf709
+        if (subreq == NULL) {
ecf709
+            ret = ENOMEM;
ecf709
+            goto immediate;
ecf709
+        }
ecf709
+        tevent_req_set_callback(subreq, kcm_ccdb_set_default_uuid_resolved, req);
ecf709
+    }
ecf709
+
ecf709
+    return req;
ecf709
+
ecf709
+immediate:
ecf709
+    tevent_req_error(req, ret);
ecf709
+    tevent_req_post(req, ev);
ecf709
+    return req;
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_set_default_uuid_resolved(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_set_default_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_set_default_state);
ecf709
+    errno_t ret;
ecf709
+    bool ok;
ecf709
+    struct kcm_ccache *cc;
ecf709
+
ecf709
+    ret = state->db->ops->getbyuuid_recv(subreq, state, &cc);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to get cache by UUID [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    if (cc == NULL) {
ecf709
+        DEBUG(SSSDBG_TRACE_LIBS, "No cache found by UUID\n");
ecf709
+        tevent_req_error(req, ERR_KCM_CC_END);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    ok = kcm_cc_access(cc, state->client);
ecf709
+    if (!ok) {
ecf709
+        tevent_req_error(req, EACCES);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    subreq = state->db->ops->set_default_send(state,
ecf709
+                                              state->ev,
ecf709
+                                              state->db,
ecf709
+                                              state->client,
ecf709
+                                              state->uuid);
ecf709
+    if (subreq == NULL) {
ecf709
+        tevent_req_error(req, ENOMEM);
ecf709
+        return;
ecf709
+    }
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_set_default_done, req);
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_set_default_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_set_default_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_set_default_state);
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    ret = state->db->ops->set_default_recv(subreq);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to set the default ccache [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    tevent_req_done(req);
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_ccdb_set_default_recv(struct tevent_req *req)
ecf709
+{
ecf709
+    TEVENT_REQ_RETURN_ON_ERROR(req);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+struct kcm_ccdb_getbyname_state {
ecf709
+    struct kcm_ccdb *db;
ecf709
+    struct cli_creds *client;
ecf709
+
ecf709
+    struct kcm_ccache *cc;
ecf709
+};
ecf709
+
ecf709
+static void kcm_ccdb_getbyname_done(struct tevent_req *subreq);
ecf709
+
ecf709
+struct tevent_req *kcm_ccdb_getbyname_send(TALLOC_CTX *mem_ctx,
ecf709
+                                           struct tevent_context *ev,
ecf709
+                                           struct kcm_ccdb *db,
ecf709
+                                           struct cli_creds *client,
ecf709
+                                           const char *name)
ecf709
+{
ecf709
+    struct tevent_req *req = NULL;
ecf709
+    struct tevent_req *subreq = NULL;
ecf709
+    struct kcm_ccdb_getbyname_state *state = NULL;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_getbyname_state);
ecf709
+    if (req == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+    state->db = db;
ecf709
+    state->client = client;
ecf709
+
ecf709
+    if (ev == NULL || db == NULL || client == NULL || name == NULL) {
ecf709
+        ret = EINVAL;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+
ecf709
+    subreq = db->ops->getbyname_send(state, ev, db, client, name);
ecf709
+    if (subreq == NULL) {
ecf709
+        ret = ENOMEM;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_getbyname_done, req);
ecf709
+    return req;
ecf709
+
ecf709
+immediate:
ecf709
+    tevent_req_error(req, ret);
ecf709
+    tevent_req_post(req, ev);
ecf709
+    return req;
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_getbyname_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_getbyname_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_getbyname_state);
ecf709
+    errno_t ret;
ecf709
+    bool ok;
ecf709
+
ecf709
+    ret = state->db->ops->getbyname_recv(subreq, state, &state->cc);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to get cache by name [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    if (state->cc == NULL) {
ecf709
+        DEBUG(SSSDBG_TRACE_LIBS, "No cache found by name\n");
ecf709
+        tevent_req_done(req);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    ok = kcm_cc_access(state->cc, state->client);
ecf709
+    if (!ok) {
ecf709
+        tevent_req_error(req, EACCES);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    tevent_req_done(req);
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_ccdb_getbyname_recv(struct tevent_req *req,
ecf709
+                                TALLOC_CTX *mem_ctx,
ecf709
+                                struct kcm_ccache **_cc)
ecf709
+{
ecf709
+    struct kcm_ccdb_getbyname_state *state = tevent_req_data(req,
ecf709
+                                            struct kcm_ccdb_getbyname_state);
ecf709
+    TEVENT_REQ_RETURN_ON_ERROR(req);
ecf709
+    *_cc = talloc_steal(mem_ctx, state->cc);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+struct kcm_ccdb_getbyuuid_state {
ecf709
+    struct kcm_ccdb *db;
ecf709
+    struct cli_creds *client;
ecf709
+
ecf709
+    struct kcm_ccache *cc;
ecf709
+};
ecf709
+
ecf709
+static void kcm_ccdb_getbyuuid_done(struct tevent_req *subreq);
ecf709
+
ecf709
+struct tevent_req *kcm_ccdb_getbyuuid_send(TALLOC_CTX *mem_ctx,
ecf709
+                                           struct tevent_context *ev,
ecf709
+                                           struct kcm_ccdb *db,
ecf709
+                                           struct cli_creds *client,
ecf709
+                                           uuid_t uuid)
ecf709
+{
ecf709
+    struct tevent_req *req = NULL;
ecf709
+    struct tevent_req *subreq = NULL;
ecf709
+    struct kcm_ccdb_getbyuuid_state *state = NULL;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_getbyuuid_state);
ecf709
+    if (req == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+    state->db = db;
ecf709
+    state->client = client;
ecf709
+
ecf709
+    if (ev == NULL || db == NULL || client == NULL) {
ecf709
+        ret = EINVAL;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+
ecf709
+    subreq = db->ops->getbyuuid_send(state, ev, db, client, uuid);
ecf709
+    if (subreq == NULL) {
ecf709
+        ret = ENOMEM;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_getbyuuid_done, req);
ecf709
+    return req;
ecf709
+
ecf709
+immediate:
ecf709
+    tevent_req_error(req, ret);
ecf709
+    tevent_req_post(req, ev);
ecf709
+    return req;
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_getbyuuid_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_getbyuuid_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_getbyuuid_state);
ecf709
+    errno_t ret;
ecf709
+    bool ok;
ecf709
+
ecf709
+    ret = state->db->ops->getbyuuid_recv(subreq, state, &state->cc);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to get cache by UUID [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    if (state->cc == NULL) {
ecf709
+        DEBUG(SSSDBG_TRACE_LIBS, "No cache found by UUID\n");
ecf709
+        tevent_req_done(req);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    ok = kcm_cc_access(state->cc, state->client);
ecf709
+    if (!ok) {
ecf709
+        tevent_req_error(req, EACCES);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    tevent_req_done(req);
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_ccdb_getbyuuid_recv(struct tevent_req *req,
ecf709
+                                TALLOC_CTX *mem_ctx,
ecf709
+                                struct kcm_ccache **_cc)
ecf709
+{
ecf709
+    struct kcm_ccdb_getbyuuid_state *state = tevent_req_data(req,
ecf709
+                                            struct kcm_ccdb_getbyuuid_state);
ecf709
+    TEVENT_REQ_RETURN_ON_ERROR(req);
ecf709
+    *_cc = talloc_steal(mem_ctx, state->cc);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+struct kcm_ccdb_name_by_uuid_state {
ecf709
+    struct kcm_ccdb *db;
ecf709
+    struct cli_creds *client;
ecf709
+
ecf709
+    const char *name;
ecf709
+};
ecf709
+
ecf709
+static void kcm_ccdb_name_by_uuid_done(struct tevent_req *subreq);
ecf709
+
ecf709
+struct tevent_req *kcm_ccdb_name_by_uuid_send(TALLOC_CTX *mem_ctx,
ecf709
+                                              struct tevent_context *ev,
ecf709
+                                              struct kcm_ccdb *db,
ecf709
+                                              struct cli_creds *client,
ecf709
+                                              uuid_t uuid)
ecf709
+{
ecf709
+    struct tevent_req *req = NULL;
ecf709
+    struct tevent_req *subreq = NULL;
ecf709
+    struct kcm_ccdb_name_by_uuid_state *state = NULL;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    req = tevent_req_create(mem_ctx,
ecf709
+                            &state,
ecf709
+                            struct kcm_ccdb_name_by_uuid_state);
ecf709
+    if (req == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+    state->db = db;
ecf709
+    state->client = client;
ecf709
+
ecf709
+    if (ev == NULL || db == NULL || client == NULL || uuid_is_null(uuid)) {
ecf709
+        ret = EINVAL;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+
ecf709
+    subreq = db->ops->name_by_uuid_send(state, ev, db, client, uuid);
ecf709
+    if (subreq == NULL) {
ecf709
+        ret = ENOMEM;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_name_by_uuid_done, req);
ecf709
+    return req;
ecf709
+
ecf709
+immediate:
ecf709
+    tevent_req_error(req, ret);
ecf709
+    tevent_req_post(req, ev);
ecf709
+    return req;
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_name_by_uuid_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_name_by_uuid_state *state = tevent_req_data(req,
ecf709
+                                        struct kcm_ccdb_name_by_uuid_state);
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    ret = state->db->ops->name_by_uuid_recv(subreq, state, &state->name);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to resolve cache by UUID [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    tevent_req_done(req);
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_ccdb_name_by_uuid_recv(struct tevent_req *req,
ecf709
+                                   TALLOC_CTX *mem_ctx,
ecf709
+                                   const char **_name)
ecf709
+{
ecf709
+    struct kcm_ccdb_name_by_uuid_state *state = tevent_req_data(req,
ecf709
+                                        struct kcm_ccdb_name_by_uuid_state);
ecf709
+    TEVENT_REQ_RETURN_ON_ERROR(req);
ecf709
+    *_name = talloc_steal(mem_ctx, state->name);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+struct kcm_ccdb_uuid_by_name_state {
ecf709
+    struct kcm_ccdb *db;
ecf709
+    struct cli_creds *client;
ecf709
+
ecf709
+    uuid_t uuid;
ecf709
+};
ecf709
+
ecf709
+static void kcm_ccdb_uuid_by_name_done(struct tevent_req *subreq);
ecf709
+
ecf709
+struct tevent_req *kcm_ccdb_uuid_by_name_send(TALLOC_CTX *mem_ctx,
ecf709
+                                              struct tevent_context *ev,
ecf709
+                                              struct kcm_ccdb *db,
ecf709
+                                              struct cli_creds *client,
ecf709
+                                              const char *name)
ecf709
+{
ecf709
+    struct tevent_req *req = NULL;
ecf709
+    struct tevent_req *subreq = NULL;
ecf709
+    struct kcm_ccdb_uuid_by_name_state *state = NULL;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    req = tevent_req_create(mem_ctx,
ecf709
+                            &state,
ecf709
+                            struct kcm_ccdb_uuid_by_name_state);
ecf709
+    if (req == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+    state->db = db;
ecf709
+    state->client = client;
ecf709
+
ecf709
+    if (ev == NULL || db == NULL || client == NULL || name == NULL) {
ecf709
+        ret = EINVAL;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+
ecf709
+    subreq = db->ops->uuid_by_name_send(state, ev, db, client, name);
ecf709
+    if (subreq == NULL) {
ecf709
+        ret = ENOMEM;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_uuid_by_name_done, req);
ecf709
+    return req;
ecf709
+
ecf709
+immediate:
ecf709
+    tevent_req_error(req, ret);
ecf709
+    tevent_req_post(req, ev);
ecf709
+    return req;
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_uuid_by_name_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_uuid_by_name_state *state = tevent_req_data(req,
ecf709
+                                        struct kcm_ccdb_uuid_by_name_state);
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    ret = state->db->ops->uuid_by_name_recv(subreq, state, state->uuid);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to resolve cache by UUID [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    tevent_req_done(req);
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_ccdb_uuid_by_name_recv(struct tevent_req *req,
ecf709
+                                   TALLOC_CTX *mem_ctx,
ecf709
+                                   uuid_t _uuid)
ecf709
+{
ecf709
+    struct kcm_ccdb_uuid_by_name_state *state = tevent_req_data(req,
ecf709
+                                        struct kcm_ccdb_uuid_by_name_state);
ecf709
+    TEVENT_REQ_RETURN_ON_ERROR(req);
ecf709
+    uuid_copy(_uuid, state->uuid);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+struct kcm_ccdb_create_cc_state {
ecf709
+    struct kcm_ccdb *db;
ecf709
+};
ecf709
+
ecf709
+static void kcm_ccdb_create_done(struct tevent_req *subreq);
ecf709
+
ecf709
+struct tevent_req *kcm_ccdb_create_cc_send(TALLOC_CTX *mem_ctx,
ecf709
+                                           struct tevent_context *ev,
ecf709
+                                           struct kcm_ccdb *db,
ecf709
+                                           struct cli_creds *client,
ecf709
+                                           struct kcm_ccache *cc)
ecf709
+{
ecf709
+    struct tevent_req *req = NULL;
ecf709
+    struct tevent_req *subreq = NULL;
ecf709
+    struct kcm_ccdb_create_cc_state *state = NULL;
ecf709
+    errno_t ret;
ecf709
+    bool ok;
ecf709
+
ecf709
+    req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_create_cc_state);
ecf709
+    if (req == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+    state->db = db;
ecf709
+
ecf709
+    if (ev == NULL || db == NULL || client == NULL || cc == NULL) {
ecf709
+        ret = EINVAL;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+
ecf709
+    ok = kcm_cc_access(cc, client);
ecf709
+    if (!ok) {
ecf709
+        ret = EACCES;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+
ecf709
+    subreq = state->db->ops->create_send(mem_ctx,
ecf709
+                                         ev,
ecf709
+                                         state->db,
ecf709
+                                         client,
ecf709
+                                         cc);
ecf709
+    if (subreq == NULL) {
ecf709
+        ret = ENOMEM;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_create_done, req);
ecf709
+    return req;
ecf709
+
ecf709
+immediate:
ecf709
+    tevent_req_error(req, ret);
ecf709
+    tevent_req_post(req, ev);
ecf709
+    return req;
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_create_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_create_cc_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_create_cc_state);
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    ret = state->db->ops->create_recv(subreq);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to create ccache [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    tevent_req_done(req);
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_ccdb_create_cc_recv(struct tevent_req *req)
ecf709
+{
ecf709
+    TEVENT_REQ_RETURN_ON_ERROR(req);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+void kcm_mod_ctx_clear(struct kcm_mod_ctx *mod_ctx)
ecf709
+{
ecf709
+    if (mod_ctx == NULL) {
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    mod_ctx->kdc_offset = INT32_MAX;
ecf709
+}
ecf709
+
ecf709
+void kcm_mod_cc(struct kcm_ccache *cc, struct kcm_mod_ctx *mod_ctx)
ecf709
+{
ecf709
+    if (cc == NULL || mod_ctx == NULL) {
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    if (mod_ctx->kdc_offset != INT32_MAX) {
ecf709
+        cc->kdc_offset = mod_ctx->kdc_offset;
ecf709
+    }
ecf709
+
ecf709
+}
ecf709
+
ecf709
+struct kcm_ccdb_mod_cc_state {
ecf709
+    struct kcm_ccdb *db;
ecf709
+};
ecf709
+
ecf709
+static void kcm_ccdb_mod_done(struct tevent_req *subreq);
ecf709
+
ecf709
+struct tevent_req *kcm_ccdb_mod_cc_send(TALLOC_CTX *mem_ctx,
ecf709
+                                        struct tevent_context *ev,
ecf709
+                                        struct kcm_ccdb *db,
ecf709
+                                        struct cli_creds *client,
ecf709
+                                        uuid_t uuid,
ecf709
+                                        struct kcm_mod_ctx *mod_cc)
ecf709
+{
ecf709
+    struct tevent_req *req = NULL;
ecf709
+    struct tevent_req *subreq = NULL;
ecf709
+    struct kcm_ccdb_mod_cc_state *state = NULL;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_mod_cc_state);
ecf709
+    if (req == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+    state->db = db;
ecf709
+
ecf709
+    if (ev == NULL || db == NULL || client == NULL || mod_cc == NULL) {
ecf709
+        ret = EINVAL;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+
ecf709
+    subreq = state->db->ops->mod_send(mem_ctx,
ecf709
+                                      ev,
ecf709
+                                      state->db,
ecf709
+                                      client,
ecf709
+                                      uuid,
ecf709
+                                      mod_cc);
ecf709
+    if (subreq == NULL) {
ecf709
+        ret = ENOMEM;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_mod_done, req);
ecf709
+    return req;
ecf709
+
ecf709
+immediate:
ecf709
+    tevent_req_error(req, ret);
ecf709
+    tevent_req_post(req, ev);
ecf709
+    return req;
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_mod_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_mod_cc_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_mod_cc_state);
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    ret = state->db->ops->mod_recv(subreq);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to create ccache [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    tevent_req_done(req);
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_ccdb_mod_cc_recv(struct tevent_req *req)
ecf709
+{
ecf709
+    TEVENT_REQ_RETURN_ON_ERROR(req);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+struct kcm_ccdb_store_cred_blob_state {
ecf709
+    struct kcm_ccdb *db;
ecf709
+};
ecf709
+
ecf709
+static void kcm_ccdb_store_cred_blob_done(struct tevent_req *subreq);
ecf709
+
ecf709
+struct tevent_req *kcm_ccdb_store_cred_blob_send(TALLOC_CTX *mem_ctx,
ecf709
+                                                 struct tevent_context *ev,
ecf709
+                                                 struct kcm_ccdb *db,
ecf709
+                                                 struct cli_creds *client,
ecf709
+                                                 uuid_t uuid,
ecf709
+                                                 struct sss_iobuf *cred_blob)
ecf709
+{
ecf709
+    struct tevent_req *req = NULL;
ecf709
+    struct tevent_req *subreq = NULL;
ecf709
+    struct kcm_ccdb_store_cred_blob_state *state = NULL;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_store_cred_blob_state);
ecf709
+    if (req == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+    state->db = db;
ecf709
+
ecf709
+    if (ev == NULL || db == NULL || client == NULL || cred_blob == NULL) {
ecf709
+        ret = EINVAL;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+
ecf709
+    subreq = state->db->ops->store_cred_send(mem_ctx,
ecf709
+                                             ev,
ecf709
+                                             state->db,
ecf709
+                                             client,
ecf709
+                                             uuid,
ecf709
+                                             cred_blob);
ecf709
+    if (subreq == NULL) {
ecf709
+        ret = ENOMEM;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_store_cred_blob_done, req);
ecf709
+    return req;
ecf709
+
ecf709
+immediate:
ecf709
+    tevent_req_error(req, ret);
ecf709
+    tevent_req_post(req, ev);
ecf709
+    return req;
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_store_cred_blob_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_store_cred_blob_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_store_cred_blob_state);
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    ret = state->db->ops->store_cred_recv(subreq);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to create ccache [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    tevent_req_done(req);
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_ccdb_store_cred_blob_recv(struct tevent_req *req)
ecf709
+{
ecf709
+    TEVENT_REQ_RETURN_ON_ERROR(req);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+struct kcm_ccdb_delete_cc_state {
ecf709
+    struct tevent_context *ev;
ecf709
+    struct kcm_ccdb *db;
ecf709
+    struct cli_creds *client;
ecf709
+    uuid_t uuid;
ecf709
+};
ecf709
+
ecf709
+static void kcm_ccdb_delete_done(struct tevent_req *subreq);
ecf709
+static void kcm_ccdb_delete_get_default_done(struct tevent_req *subreq);
ecf709
+static void kcm_ccdb_delete_default_reset_done(struct tevent_req *subreq);
ecf709
+
ecf709
+struct tevent_req *kcm_ccdb_delete_cc_send(TALLOC_CTX *mem_ctx,
ecf709
+                                           struct tevent_context *ev,
ecf709
+                                           struct kcm_ccdb *db,
ecf709
+                                           struct cli_creds *client,
ecf709
+                                           uuid_t uuid)
ecf709
+{
ecf709
+    struct tevent_req *req = NULL;
ecf709
+    struct tevent_req *subreq = NULL;
ecf709
+    struct kcm_ccdb_delete_cc_state *state = NULL;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    req = tevent_req_create(mem_ctx, &state, struct kcm_ccdb_delete_cc_state);
ecf709
+    if (req == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+    state->db = db;
ecf709
+    state->ev = ev;
ecf709
+    state->client = client;
ecf709
+    uuid_copy(state->uuid, uuid);
ecf709
+
ecf709
+    if (ev == NULL || db == NULL || client == NULL) {
ecf709
+        ret = EINVAL;
ecf709
+        goto immediate;
ecf709
+    }
ecf709
+
ecf709
+    subreq = state->db->ops->delete_send(state,
ecf709
+                                         state->ev,
ecf709
+                                         state->db,
ecf709
+                                         state->client,
ecf709
+                                         state->uuid);
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_delete_done, req);
ecf709
+
ecf709
+    return req;
ecf709
+
ecf709
+immediate:
ecf709
+    tevent_req_error(req, ret);
ecf709
+    tevent_req_post(req, ev);
ecf709
+    return req;
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_delete_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_delete_cc_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_delete_cc_state);
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    ret = state->db->ops->delete_recv(subreq);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to delete ccache [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    /* The delete operation must also check if the deleted ccache was
ecf709
+     * the default and reset the default if it was
ecf709
+     */
ecf709
+    subreq = state->db->ops->get_default_send(state,
ecf709
+                                              state->ev,
ecf709
+                                              state->db,
ecf709
+                                              state->client);
ecf709
+    if (subreq == NULL) {
ecf709
+        tevent_req_error(req, ENOMEM);
ecf709
+        return;
ecf709
+    }
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_delete_get_default_done, req);
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_delete_get_default_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_delete_cc_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_delete_cc_state);
ecf709
+    errno_t ret;
ecf709
+    uuid_t dfl_uuid;
ecf709
+    uuid_t null_uuid;
ecf709
+
ecf709
+    ret = state->db->ops->get_default_recv(subreq, dfl_uuid);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to get the default ccache [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    if (uuid_compare(dfl_uuid, state->uuid) != 0) {
ecf709
+        /* The ccache about to be deleted was not the default, quit */
ecf709
+        tevent_req_done(req);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    /* If we deleted the default ccache, reset the default ccache to 'none' */
ecf709
+    uuid_clear(null_uuid);
ecf709
+
ecf709
+    subreq = state->db->ops->set_default_send(state,
ecf709
+                                              state->ev,
ecf709
+                                              state->db,
ecf709
+                                              state->client,
ecf709
+                                              null_uuid);
ecf709
+    if (subreq == NULL) {
ecf709
+        tevent_req_error(req, ENOMEM);
ecf709
+        return;
ecf709
+    }
ecf709
+    tevent_req_set_callback(subreq, kcm_ccdb_delete_default_reset_done, req);
ecf709
+}
ecf709
+
ecf709
+static void kcm_ccdb_delete_default_reset_done(struct tevent_req *subreq)
ecf709
+{
ecf709
+    struct tevent_req *req = tevent_req_callback_data(subreq,
ecf709
+                                                      struct tevent_req);
ecf709
+    struct kcm_ccdb_delete_cc_state *state = tevent_req_data(req,
ecf709
+                                                struct kcm_ccdb_delete_cc_state);
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    ret = state->db->ops->set_default_recv(subreq);
ecf709
+    talloc_zfree(subreq);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_OP_FAILURE,
ecf709
+              "Failed to NULL the default ccache [%d]: %s\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        tevent_req_error(req, ret);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    tevent_req_done(req);
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_ccdb_delete_cc_recv(struct tevent_req *req)
ecf709
+{
ecf709
+    TEVENT_REQ_RETURN_ON_ERROR(req);
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+void kcm_debug_uuid(uuid_t uuid)
ecf709
+{
ecf709
+    char dbgbuf[UUID_STR_SIZE];
ecf709
+
ecf709
+    if (!(debug_level & SSSDBG_TRACE_ALL) || uuid == NULL) {
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    uuid_unparse(uuid, dbgbuf);
ecf709
+    DEBUG(SSSDBG_TRACE_ALL, "UUID: %s\n", dbgbuf);
ecf709
+}
ecf709
+
ecf709
+errno_t kcm_check_name(const char *name, struct cli_creds *client)
ecf709
+{
ecf709
+    char prefix[64];
ecf709
+    size_t prefix_len;
ecf709
+
ecf709
+    prefix_len = snprintf(prefix, sizeof(prefix),
ecf709
+                          "%"SPRIuid, cli_creds_get_uid(client));
ecf709
+
ecf709
+    if (strncmp(name, prefix, prefix_len) != 0) {
ecf709
+        return ERR_KCM_WRONG_CCNAME_FORMAT;
ecf709
+    }
ecf709
+    return EOK;
ecf709
+}
ecf709
diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h
ecf709
new file mode 100644
ecf709
index 0000000000000000000000000000000000000000..130ae48ae30d5e1e2ab238a647a9b9dc76cc4945
ecf709
--- /dev/null
ecf709
+++ b/src/responder/kcm/kcmsrv_ccache.h
ecf709
@@ -0,0 +1,306 @@
ecf709
+/*
ecf709
+   SSSD
ecf709
+
ecf709
+   KCM Server - the KCM ccache operations
ecf709
+
ecf709
+   Copyright (C) Red Hat, 2016
ecf709
+
ecf709
+   This program is free software; you can redistribute it and/or modify
ecf709
+   it under the terms of the GNU General Public License as published by
ecf709
+   the Free Software Foundation; either version 3 of the License, or
ecf709
+   (at your option) any later version.
ecf709
+
ecf709
+   This program is distributed in the hope that it will be useful,
ecf709
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
ecf709
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ecf709
+   GNU General Public License for more details.
ecf709
+
ecf709
+   You should have received a copy of the GNU General Public License
ecf709
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
ecf709
+*/
ecf709
+#ifndef _KCMSRV_CCACHE_H_
ecf709
+#define _KCMSRV_CCACHE_H_
ecf709
+
ecf709
+#include "config.h"
ecf709
+
ecf709
+#include <krb5/krb5.h>
ecf709
+#include <uuid/uuid.h>
ecf709
+
ecf709
+#include "util/util.h"
ecf709
+#include "util/sss_iobuf.h"
ecf709
+#include "util/util_creds.h"
ecf709
+
ecf709
+#define UUID_BYTES    16
ecf709
+#define UUID_STR_SIZE 37
ecf709
+
ecf709
+/*
ecf709
+ * Credentials are opaque to the KCM server
ecf709
+ *
ecf709
+ * Each ccache has a unique UUID.
ecf709
+ */
ecf709
+struct kcm_cred;
ecf709
+
ecf709
+/*
ecf709
+ * An opaque ccache type and its operations
ecf709
+ *
ecf709
+ * Contains zero or some KCM credentials. One credential in the cache
ecf709
+ * is marked as the default one. The client can set and get the default
ecf709
+ * cache (e.g. with kswitch) but one cache is always the default -- we
ecf709
+ * fall back to the one created first.
ecf709
+ *
ecf709
+ * Each cache has a name and a UUID. Heimdal allows the name to be changed,
ecf709
+ * we don't (yet, because the MIT client doesn't allow that either)
ecf709
+ *
ecf709
+ * Each ccache also stores a client principal.
ecf709
+ */
ecf709
+struct kcm_ccache;
ecf709
+
ecf709
+/*
ecf709
+ * Create a new KCM ccache owned by mem_ctx on the
ecf709
+ * memory level.
ecf709
+ *
ecf709
+ * When created, the ccache contains no credendials
ecf709
+ */
ecf709
+errno_t kcm_cc_new(TALLOC_CTX *mem_ctx,
ecf709
+                   krb5_context k5c,
ecf709
+                   struct cli_creds *owner,
ecf709
+                   const char *name,
ecf709
+                   krb5_principal princ,
ecf709
+                   struct kcm_ccache **_cc);
ecf709
+
ecf709
+/*
ecf709
+ * Returns true if a client can access a ccache.
ecf709
+ *
ecf709
+ * Note that root can access any ccache */
ecf709
+bool kcm_cc_access(struct kcm_ccache *cc,
ecf709
+                   struct cli_creds *client);
ecf709
+
ecf709
+/*
ecf709
+ * Since the kcm_ccache structure is opaque, the kcmsrv_ccache
ecf709
+ * layer contains a number of getsetters to read and write
ecf709
+ * properties of the kcm_ccache structure
ecf709
+ */
ecf709
+const char *kcm_cc_get_name(struct kcm_ccache *cc);
ecf709
+errno_t kcm_cc_get_uuid(struct kcm_ccache *cc, uuid_t _uuid);
ecf709
+krb5_principal kcm_cc_get_client_principal(struct kcm_ccache *cc);
ecf709
+int32_t kcm_cc_get_offset(struct kcm_ccache *cc);
ecf709
+
ecf709
+/* Mainly useful for creating a cred structure from a persistent
ecf709
+ * storage
ecf709
+ */
ecf709
+struct kcm_cred *kcm_cred_new(TALLOC_CTX *mem_ctx,
ecf709
+                              uuid_t uuid,
ecf709
+                              struct sss_iobuf *cred_blob);
ecf709
+
ecf709
+/* Add a cred to ccache */
ecf709
+errno_t kcm_cc_store_creds(struct kcm_ccache *cc,
ecf709
+                           struct kcm_cred *crd);
ecf709
+
ecf709
+errno_t kcm_cred_get_uuid(struct kcm_cred *crd, uuid_t uuid);
ecf709
+
ecf709
+/*
ecf709
+ * At the moment, the credentials are stored without unmarshalling
ecf709
+ * them, just as the clients sends the credentials.
ecf709
+ */
ecf709
+struct sss_iobuf *kcm_cred_get_creds(struct kcm_cred *crd);
ecf709
+errno_t kcm_cc_store_cred_blob(struct kcm_ccache *cc,
ecf709
+                               struct sss_iobuf *cred_blob);
ecf709
+ /*
ecf709
+ * The KCM server can call kcm_cred_get_creds to fetch the first
ecf709
+ * credential, then iterate over the credentials with
ecf709
+ * kcm_cc_next_cred until it returns NULL
ecf709
+ */
ecf709
+struct kcm_cred *kcm_cc_get_cred(struct kcm_ccache *cc);
ecf709
+struct kcm_cred *kcm_cc_next_cred(struct kcm_cred *crd);
ecf709
+
ecf709
+enum kcm_ccdb_be {
ecf709
+    CCDB_BE_MEMORY,
ecf709
+    CCDB_BE_SECRETS,
ecf709
+};
ecf709
+
ecf709
+/* An opaque database that contains all the ccaches */
ecf709
+struct kcm_ccdb;
ecf709
+
ecf709
+/*
ecf709
+ * Initialize a ccache database of type cc_be
ecf709
+ */
ecf709
+struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx,
ecf709
+                               struct tevent_context *ev,
ecf709
+                               enum kcm_ccdb_be cc_be);
ecf709
+
ecf709
+/*
ecf709
+ * In KCM, each ccache name is usually in the form of "UID:<num>
ecf709
+ *
ecf709
+ * The <num> is generated by the KCM ccache database. Use this function
ecf709
+ * to retrieve the next number
ecf709
+ */
ecf709
+struct tevent_req *kcm_ccdb_nextid_send(TALLOC_CTX *mem_ctx,
ecf709
+                                        struct tevent_context *ev,
ecf709
+                                        struct kcm_ccdb *db,
ecf709
+                                        struct cli_creds *client);
ecf709
+errno_t kcm_ccdb_nextid_recv(struct tevent_req *req,
ecf709
+                             TALLOC_CTX *mem_ctx,
ecf709
+                             char **_nextid);
ecf709
+
ecf709
+/*
ecf709
+ * List all ccaches that belong to a given client
ecf709
+ *
ecf709
+ * The cc_list the recv function returns is NULL-terminated.
ecf709
+ *
ecf709
+ * NOTE: Contrary to how Heimdal behaves, root CAN NOT list all ccaches
ecf709
+ * of all users. This is a deliberate decision to treat root as any other
ecf709
+ * user, except it can access a ccache of another user by name, just not
ecf709
+ * list them.
ecf709
+ *
ecf709
+ * If a client has no ccaches, the function returns OK, but an empty list
ecf709
+ * containing just the NULL sentinel.
ecf709
+ */
ecf709
+struct tevent_req *kcm_ccdb_list_send(TALLOC_CTX *mem_ctx,
ecf709
+                                      struct tevent_context *ev,
ecf709
+                                      struct kcm_ccdb *db,
ecf709
+                                      struct cli_creds *client);
ecf709
+errno_t kcm_ccdb_list_recv(struct tevent_req *req,
ecf709
+                           TALLOC_CTX *mem_ctx,
ecf709
+                           uuid_t **_uuid_list);
ecf709
+
ecf709
+/*
ecf709
+ * Retrieve a ccache by name.
ecf709
+ *
ecf709
+ * If there is no such ccache, return EOK, but a NULL _cc pointer
ecf709
+ */
ecf709
+struct tevent_req *kcm_ccdb_getbyname_send(TALLOC_CTX *mem_ctx,
ecf709
+                                           struct tevent_context *ev,
ecf709
+                                           struct kcm_ccdb *db,
ecf709
+                                           struct cli_creds *client,
ecf709
+                                           const char *name);
ecf709
+errno_t kcm_ccdb_getbyname_recv(struct tevent_req *req,
ecf709
+                                TALLOC_CTX *mem_ctx,
ecf709
+                                struct kcm_ccache **_cc);
ecf709
+
ecf709
+/*
ecf709
+ * Retrieve a ccache by UUID
ecf709
+ *
ecf709
+ * If there is no such ccache, return EOK, but a NULL _cc pointer
ecf709
+ */
ecf709
+struct tevent_req *kcm_ccdb_getbyuuid_send(TALLOC_CTX *mem_ctx,
ecf709
+                                           struct tevent_context *ev,
ecf709
+                                           struct kcm_ccdb *db,
ecf709
+                                           struct cli_creds *client,
ecf709
+                                           uuid_t uuid);
ecf709
+errno_t kcm_ccdb_getbyuuid_recv(struct tevent_req *req,
ecf709
+                                TALLOC_CTX *mem_ctx,
ecf709
+                                struct kcm_ccache **_cc);
ecf709
+
ecf709
+/*
ecf709
+ * Retrieve the default ccache. If there is no default cache,
ecf709
+ * return EOK, but a NULL UUID.
ecf709
+ */
ecf709
+struct tevent_req *kcm_ccdb_get_default_send(TALLOC_CTX *mem_ctx,
ecf709
+                                             struct tevent_context *ev,
ecf709
+                                             struct kcm_ccdb *db,
ecf709
+                                             struct cli_creds *client);
ecf709
+errno_t kcm_ccdb_get_default_recv(struct tevent_req *req,
ecf709
+                                  uuid_t *uuid);
ecf709
+
ecf709
+/*
ecf709
+ * Translating name to UUID is often considerably faster than doing a full
ecf709
+ * CC retrieval, hence this function and the converse. If the UUID cannot
ecf709
+ * be found in the database, return ERR_KCM_CC_END
ecf709
+ */
ecf709
+struct tevent_req *kcm_ccdb_name_by_uuid_send(TALLOC_CTX *mem_ctx,
ecf709
+                                              struct tevent_context *ev,
ecf709
+                                              struct kcm_ccdb *db,
ecf709
+                                              struct cli_creds *client,
ecf709
+                                              uuid_t uuid);
ecf709
+errno_t kcm_ccdb_name_by_uuid_recv(struct tevent_req *req,
ecf709
+                                   TALLOC_CTX *mem_ctx,
ecf709
+                                   const char **_name);
ecf709
+
ecf709
+/*
ecf709
+ * Translating UUID to name is often considerably faster than doing a full
ecf709
+ * CC retrieval, hence this function and the converse. If the UUID cannot
ecf709
+ * be found in the database, return ERR_KCM_CC_END
ecf709
+ */
ecf709
+struct tevent_req *kcm_ccdb_uuid_by_name_send(TALLOC_CTX *mem_ctx,
ecf709
+                                              struct tevent_context *ev,
ecf709
+                                              struct kcm_ccdb *db,
ecf709
+                                              struct cli_creds *client,
ecf709
+                                              const char *name);
ecf709
+errno_t kcm_ccdb_uuid_by_name_recv(struct tevent_req *req,
ecf709
+                                   TALLOC_CTX *mem_ctx,
ecf709
+                                   uuid_t _uuid);
ecf709
+
ecf709
+/*
ecf709
+ * Set the default ccache. Passing a NULL UUID is a legal operation
ecf709
+ * that 'unsets' the default ccache.
ecf709
+ */
ecf709
+struct tevent_req *kcm_ccdb_set_default_send(TALLOC_CTX *mem_ctx,
ecf709
+                                             struct tevent_context *ev,
ecf709
+                                             struct kcm_ccdb *db,
ecf709
+                                             struct cli_creds *client,
ecf709
+                                             uuid_t uuid);
ecf709
+errno_t kcm_ccdb_set_default_recv(struct tevent_req *req);
ecf709
+
ecf709
+/*
ecf709
+ * Add a ccache to the database.
ecf709
+ */
ecf709
+struct tevent_req *kcm_ccdb_create_cc_send(TALLOC_CTX *mem_ctx,
ecf709
+                                           struct tevent_context *ev,
ecf709
+                                           struct kcm_ccdb *db,
ecf709
+                                           struct cli_creds *client,
ecf709
+                                           struct kcm_ccache *cc);
ecf709
+errno_t kcm_ccdb_create_cc_recv(struct tevent_req *req);
ecf709
+
ecf709
+/*
ecf709
+ * Modify cache properties in a db
ecf709
+ */
ecf709
+struct kcm_mod_ctx {
ecf709
+    int32_t kdc_offset;
ecf709
+    /* More settable properties (like name, when we support renames
ecf709
+     * will be added later
ecf709
+     */
ecf709
+};
ecf709
+
ecf709
+void kcm_mod_ctx_clear(struct kcm_mod_ctx *mod_ctx);
ecf709
+void kcm_mod_cc(struct kcm_ccache *cc, struct kcm_mod_ctx *mod_ctx);
ecf709
+
ecf709
+struct tevent_req *kcm_ccdb_mod_cc_send(TALLOC_CTX *mem_ctx,
ecf709
+                                        struct tevent_context *ev,
ecf709
+                                        struct kcm_ccdb *db,
ecf709
+                                        struct cli_creds *client,
ecf709
+                                        uuid_t uuid,
ecf709
+                                        struct kcm_mod_ctx *mod_cc);
ecf709
+errno_t kcm_ccdb_mod_cc_recv(struct tevent_req *req);
ecf709
+
ecf709
+/*
ecf709
+ * Store a credential in a cache
ecf709
+ */
ecf709
+struct tevent_req *kcm_ccdb_store_cred_blob_send(TALLOC_CTX *mem_ctx,
ecf709
+                                                 struct tevent_context *ev,
ecf709
+                                                 struct kcm_ccdb *db,
ecf709
+                                                 struct cli_creds *client,
ecf709
+                                                 uuid_t uuid,
ecf709
+                                                 struct sss_iobuf *cred_blob);
ecf709
+errno_t kcm_ccdb_store_cred_blob_recv(struct tevent_req *req);
ecf709
+
ecf709
+/*
ecf709
+ * Delete a ccache from the database
ecf709
+ */
ecf709
+struct tevent_req *kcm_ccdb_delete_cc_send(TALLOC_CTX *mem_ctx,
ecf709
+                                           struct tevent_context *ev,
ecf709
+                                           struct kcm_ccdb *db,
ecf709
+                                           struct cli_creds *client,
ecf709
+                                           uuid_t uuid);
ecf709
+errno_t kcm_ccdb_delete_cc_recv(struct tevent_req *req);
ecf709
+
ecf709
+void kcm_debug_uuid(uuid_t uuid);
ecf709
+
ecf709
+/*
ecf709
+ * The KCM clients are not allowed (except root) to create ccaches
ecf709
+ * with arbitrary names. Instead, we assert that the ccache name
ecf709
+ * begins with UID where UID is the stringified representation of
ecf709
+ * the client's UID number
ecf709
+ */
ecf709
+errno_t kcm_check_name(const char *name, struct cli_creds *client);
ecf709
+
ecf709
+#endif /* _KCMSRV_CCACHE_H_ */
ecf709
diff --git a/src/responder/kcm/kcmsrv_ccache_be.h b/src/responder/kcm/kcmsrv_ccache_be.h
ecf709
new file mode 100644
ecf709
index 0000000000000000000000000000000000000000..1bd2b6981e227675866e82e0a5389445cac4df66
ecf709
--- /dev/null
ecf709
+++ b/src/responder/kcm/kcmsrv_ccache_be.h
ecf709
@@ -0,0 +1,204 @@
ecf709
+/*
ecf709
+   SSSD
ecf709
+
ecf709
+   KCM Server - the KCM ccache database interface
ecf709
+
ecf709
+   This file should only be included from the ccache.c module.
ecf709
+
ecf709
+   Copyright (C) Red Hat, 2016
ecf709
+
ecf709
+   This program is free software; you can redistribute it and/or modify
ecf709
+   it under the terms of the GNU General Public License as published by
ecf709
+   the Free Software Foundation; either version 3 of the License, or
ecf709
+   (at your option) any later version.
ecf709
+
ecf709
+   This program is distributed in the hope that it will be useful,
ecf709
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
ecf709
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ecf709
+   GNU General Public License for more details.
ecf709
+
ecf709
+   You should have received a copy of the GNU General Public License
ecf709
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
ecf709
+*/
ecf709
+
ecf709
+#ifndef _KCMSRV_CCACHE_BE_
ecf709
+#define _KCMSRV_CCACHE_BE_
ecf709
+
ecf709
+#include "config.h"
ecf709
+
ecf709
+#include <talloc.h>
ecf709
+#include "responder/kcm/kcmsrv_ccache.h"
ecf709
+
ecf709
+typedef errno_t
ecf709
+(*ccdb_init_fn)(struct kcm_ccdb *db);
ecf709
+
ecf709
+typedef struct tevent_req *
ecf709
+(*ccdb_nextid_send_fn)(TALLOC_CTX *mem_ctx,
ecf709
+                       struct tevent_context *ev,
ecf709
+                       struct kcm_ccdb *db,
ecf709
+                       struct cli_creds *client);
ecf709
+typedef errno_t
ecf709
+(*ccdb_nextid_recv_fn)(struct tevent_req *req,
ecf709
+                       unsigned int *_nextid);
ecf709
+
ecf709
+typedef struct tevent_req *
ecf709
+(*ccdb_set_default_send_fn)(TALLOC_CTX *mem_ctx,
ecf709
+                            struct tevent_context *ev,
ecf709
+                            struct kcm_ccdb *db,
ecf709
+                            struct cli_creds *client,
ecf709
+                            uuid_t uuid);
ecf709
+typedef errno_t
ecf709
+(*ccdb_set_default_recv_fn)(struct tevent_req *req);
ecf709
+
ecf709
+typedef struct tevent_req *
ecf709
+(*ccdb_get_default_send_fn)(TALLOC_CTX *mem_ctx,
ecf709
+                            struct tevent_context *ev,
ecf709
+                            struct kcm_ccdb *db,
ecf709
+                            struct cli_creds *client);
ecf709
+typedef errno_t
ecf709
+(*ccdb_get_default_recv_fn)(struct tevent_req *req,
ecf709
+                            uuid_t dfl);
ecf709
+
ecf709
+
ecf709
+typedef struct tevent_req *
ecf709
+(*ccdb_list_send_fn)(TALLOC_CTX *mem_ctx,
ecf709
+                     struct tevent_context *ev,
ecf709
+                     struct kcm_ccdb *db,
ecf709
+                     struct cli_creds *client);
ecf709
+typedef errno_t
ecf709
+(*ccdb_list_recv_fn)(struct tevent_req *req,
ecf709
+                     TALLOC_CTX *mem_ctx,
ecf709
+                     uuid_t **_uuid_list);
ecf709
+
ecf709
+typedef struct tevent_req *
ecf709
+(*ccdb_getbyname_send_fn)(TALLOC_CTX *mem_ctx,
ecf709
+                          struct tevent_context *ev,
ecf709
+                          struct kcm_ccdb *db,
ecf709
+                          struct cli_creds *client,
ecf709
+                          const char *name);
ecf709
+typedef errno_t
ecf709
+(*ccdb_getbyname_recv_fn)(struct tevent_req *req,
ecf709
+                          TALLOC_CTX *mem_ctx,
ecf709
+                          struct kcm_ccache **_cc);
ecf709
+
ecf709
+typedef struct tevent_req *
ecf709
+(*ccdb_getbyuuid_send_fn)(TALLOC_CTX *mem_ctx,
ecf709
+                          struct tevent_context *ev,
ecf709
+                          struct kcm_ccdb *db,
ecf709
+                          struct cli_creds *client,
ecf709
+                          uuid_t uuid);
ecf709
+typedef errno_t
ecf709
+(*ccdb_getbyuuid_recv_fn)(struct tevent_req *req,
ecf709
+                          TALLOC_CTX *mem_ctx,
ecf709
+                          struct kcm_ccache **_cc);
ecf709
+
ecf709
+typedef struct tevent_req *
ecf709
+(*ccdb_name_by_uuid_send_fn)(TALLOC_CTX *mem_ctx,
ecf709
+                             struct tevent_context *ev,
ecf709
+                             struct kcm_ccdb *db,
ecf709
+                             struct cli_creds *client,
ecf709
+                             uuid_t uuid);
ecf709
+typedef errno_t
ecf709
+(*ccdb_name_by_uuid_recv_fn)(struct tevent_req *req,
ecf709
+                             TALLOC_CTX *mem_ctx,
ecf709
+                             const char **_name);
ecf709
+
ecf709
+typedef struct tevent_req *
ecf709
+(*ccdb_uuid_by_name_send_fn)(TALLOC_CTX *mem_ctx,
ecf709
+                             struct tevent_context *ev,
ecf709
+                             struct kcm_ccdb *db,
ecf709
+                             struct cli_creds *client,
ecf709
+                             const char *name);
ecf709
+typedef errno_t
ecf709
+(*ccdb_uuid_by_name_recv_fn)(struct tevent_req *req,
ecf709
+                             TALLOC_CTX *mem_ctx,
ecf709
+                             uuid_t _uuid);
ecf709
+
ecf709
+typedef struct tevent_req *
ecf709
+(*ccdb_create_send_fn)(TALLOC_CTX *mem_ctx,
ecf709
+                       struct tevent_context *ev,
ecf709
+                       struct kcm_ccdb *db,
ecf709
+                       struct cli_creds *client,
ecf709
+                       struct kcm_ccache *cc);
ecf709
+typedef errno_t
ecf709
+(*ccdb_create_recv_fn)(struct tevent_req *req);
ecf709
+
ecf709
+typedef struct tevent_req *
ecf709
+(*ccdb_mod_send_fn)(TALLOC_CTX *mem_ctx,
ecf709
+                    struct tevent_context *ev,
ecf709
+                    struct kcm_ccdb *db,
ecf709
+                    struct cli_creds *client,
ecf709
+                    uuid_t uuid,
ecf709
+                    struct kcm_mod_ctx *mod_cc);
ecf709
+typedef errno_t
ecf709
+(*ccdb_mod_recv_fn)(struct tevent_req *req);
ecf709
+
ecf709
+typedef struct tevent_req *
ecf709
+(*kcm_ccdb_store_cred_blob_send_fn)(TALLOC_CTX *mem_ctx,
ecf709
+                                    struct tevent_context *ev,
ecf709
+                                    struct kcm_ccdb *db,
ecf709
+                                    struct cli_creds *client,
ecf709
+                                    uuid_t uuid,
ecf709
+                                    struct sss_iobuf *cred_blob);
ecf709
+typedef errno_t
ecf709
+(*kcm_ccdb_store_cred_blob_recv_fn)(struct tevent_req *req);
ecf709
+
ecf709
+typedef struct tevent_req *
ecf709
+(*ccdb_delete_send_fn)(TALLOC_CTX *mem_ctx,
ecf709
+                      struct tevent_context *ev,
ecf709
+                      struct kcm_ccdb *db,
ecf709
+                      struct cli_creds *client,
ecf709
+                      uuid_t uuid);
ecf709
+typedef errno_t
ecf709
+(*ccdb_delete_recv_fn)(struct tevent_req *req);
ecf709
+
ecf709
+/*
ecf709
+ * Each ccache back end (for example memory or secrets) must implement
ecf709
+ * all these functions. The functions are wrapped by the kcm_ccdb
ecf709
+ * interface that performs additional sanity checks or contains shared
ecf709
+ * logic such as access checks but in general doesn't assume anything
ecf709
+ * about how the operations work.
ecf709
+ */
ecf709
+struct kcm_ccdb_ops {
ecf709
+    ccdb_init_fn init;
ecf709
+
ecf709
+    ccdb_nextid_send_fn nextid_send;
ecf709
+    ccdb_nextid_recv_fn nextid_recv;
ecf709
+
ecf709
+    ccdb_set_default_send_fn set_default_send;
ecf709
+    ccdb_set_default_recv_fn set_default_recv;
ecf709
+
ecf709
+    ccdb_get_default_send_fn get_default_send;
ecf709
+    ccdb_get_default_recv_fn get_default_recv;
ecf709
+
ecf709
+    ccdb_list_send_fn list_send;
ecf709
+    ccdb_list_recv_fn list_recv;
ecf709
+
ecf709
+    ccdb_getbyname_send_fn getbyname_send;
ecf709
+    ccdb_getbyname_recv_fn getbyname_recv;
ecf709
+
ecf709
+    ccdb_getbyuuid_send_fn getbyuuid_send;
ecf709
+    ccdb_getbyuuid_recv_fn getbyuuid_recv;
ecf709
+
ecf709
+    ccdb_name_by_uuid_send_fn name_by_uuid_send;
ecf709
+    ccdb_name_by_uuid_recv_fn name_by_uuid_recv;
ecf709
+
ecf709
+    ccdb_uuid_by_name_send_fn uuid_by_name_send;
ecf709
+    ccdb_uuid_by_name_recv_fn uuid_by_name_recv;
ecf709
+
ecf709
+    ccdb_create_send_fn create_send;
ecf709
+    ccdb_create_recv_fn create_recv;
ecf709
+
ecf709
+    ccdb_mod_send_fn mod_send;
ecf709
+    ccdb_mod_recv_fn mod_recv;
ecf709
+
ecf709
+    kcm_ccdb_store_cred_blob_send_fn store_cred_send;
ecf709
+    kcm_ccdb_store_cred_blob_recv_fn store_cred_recv;
ecf709
+
ecf709
+    ccdb_delete_send_fn delete_send;
ecf709
+    ccdb_delete_recv_fn delete_recv;
ecf709
+};
ecf709
+
ecf709
+extern const struct kcm_ccdb_ops ccdb_mem_ops;
ecf709
+
ecf709
+#endif /* _KCMSRV_CCACHE_BE_ */
ecf709
diff --git a/src/responder/kcm/kcmsrv_ccache_pvt.h b/src/responder/kcm/kcmsrv_ccache_pvt.h
ecf709
new file mode 100644
ecf709
index 0000000000000000000000000000000000000000..0cc24c2b8cd4d44080d2aa4384f7b2a73520c5a0
ecf709
--- /dev/null
ecf709
+++ b/src/responder/kcm/kcmsrv_ccache_pvt.h
ecf709
@@ -0,0 +1,62 @@
ecf709
+/*
ecf709
+   SSSD
ecf709
+
ecf709
+   KCM Server - the KCM ccache operations - private structures
ecf709
+
ecf709
+   Should be accessed only from the ccache layer.
ecf709
+
ecf709
+   Copyright (C) Red Hat, 2016
ecf709
+
ecf709
+   This program is free software; you can redistribute it and/or modify
ecf709
+   it under the terms of the GNU General Public License as published by
ecf709
+   the Free Software Foundation; either version 3 of the License, or
ecf709
+   (at your option) any later version.
ecf709
+
ecf709
+   This program is distributed in the hope that it will be useful,
ecf709
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
ecf709
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ecf709
+   GNU General Public License for more details.
ecf709
+
ecf709
+   You should have received a copy of the GNU General Public License
ecf709
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
ecf709
+*/
ecf709
+#ifndef _KCMSRV_CCACHE_PVT_H
ecf709
+#define _KCMSRV_CCACHE_PVT_H
ecf709
+
ecf709
+#include "responder/kcm/kcmsrv_ccache.h"
ecf709
+#include "responder/kcm/kcmsrv_ccache_be.h"
ecf709
+
ecf709
+struct kcm_ccache_owner {
ecf709
+    uid_t uid;
ecf709
+    gid_t gid;
ecf709
+};
ecf709
+
ecf709
+struct kcm_cred {
ecf709
+    struct sss_iobuf *cred_blob;
ecf709
+    /* Randomly generated 16 bytes */
ecf709
+    uuid_t uuid;
ecf709
+
ecf709
+    struct kcm_cred *next;
ecf709
+    struct kcm_cred *prev;
ecf709
+};
ecf709
+
ecf709
+struct kcm_ccdb {
ecf709
+    enum kcm_ccdb_be cc_be_type;
ecf709
+    struct tevent_context *ev;
ecf709
+
ecf709
+    void *db_handle;
ecf709
+    const struct kcm_ccdb_ops *ops;
ecf709
+};
ecf709
+
ecf709
+struct kcm_ccache {
ecf709
+    const char *name;
ecf709
+    struct kcm_ccache_owner owner;
ecf709
+    uuid_t uuid;
ecf709
+
ecf709
+    krb5_principal client;
ecf709
+    int32_t kdc_offset;
ecf709
+
ecf709
+    struct kcm_cred *creds;
ecf709
+};
ecf709
+
ecf709
+#endif /* _KCMSRV_CCACHE_PVT_H */
ecf709
diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h
ecf709
index fd1fd9fa32d59a323d465def68999f24f84e3923..a29680246c1e616da75e1bbff951ce2fad66fb65 100644
ecf709
--- a/src/responder/kcm/kcmsrv_pvt.h
ecf709
+++ b/src/responder/kcm/kcmsrv_pvt.h
ecf709
@@ -46,6 +46,7 @@ struct kcm_data {
ecf709
  */
ecf709
 struct kcm_resp_ctx {
ecf709
     krb5_context k5c;
ecf709
+    struct kcm_ccdb *db;
ecf709
 };
ecf709
 
ecf709
 /*
ecf709
-- 
ecf709
2.9.3
ecf709