diff options
Diffstat (limited to 'src/responder/kcm/kcmsrv_ccache_secdb.c')
-rw-r--r-- | src/responder/kcm/kcmsrv_ccache_secdb.c | 1671 |
1 files changed, 1671 insertions, 0 deletions
diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c new file mode 100644 index 0000000..ff5e6e2 --- /dev/null +++ b/src/responder/kcm/kcmsrv_ccache_secdb.c @@ -0,0 +1,1671 @@ +/* + SSSD + + KCM Server - ccache storage using libsss_secrets + + Copyright (C) Red Hat, 2016 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "config.h" + +#include <talloc.h> +#include <stdio.h> + +#include "util/util.h" +#include "secrets/secrets.h" +#include "util/crypto/sss_crypto.h" +#include "util/sss_krb5.h" +#include "util/strtonum.h" +#include "responder/kcm/kcmsrv_ccache_pvt.h" +#include "responder/kcm/kcmsrv_ccache_be.h" +#include "responder/kcm/kcm_renew.h" +#include "providers/krb5/krb5_ccache.h" + +#define KCM_SECDB_URL "persistent" +#define KCM_SECDB_BASE_FMT KCM_SECDB_URL"/%"SPRIuid"/" +#define KCM_SECDB_CCACHE_FMT KCM_SECDB_BASE_FMT"ccache/" +#define KCM_SECDB_DFL_FMT KCM_SECDB_BASE_FMT"default" + +static errno_t sec_get(TALLOC_CTX *mem_ctx, + struct sss_sec_req *req, + struct sss_iobuf **_buf) +{ + errno_t ret; + TALLOC_CTX *tmp_ctx; + uint8_t *data; + size_t len; + struct sss_iobuf *buf; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ret = sss_sec_get(tmp_ctx, req, &data, &len); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Cannot retrieve the secret [%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + + buf = sss_iobuf_init_steal(tmp_ctx, data, len); + if (buf == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init the iobuf\n"); + ret = EIO; + goto done; + } + + *_buf = talloc_steal(mem_ctx, buf); + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t sec_put(TALLOC_CTX *mem_ctx, + struct sss_sec_req *req, + struct sss_iobuf *buf) +{ + errno_t ret; + + ret = sss_sec_put(req, sss_iobuf_get_data(buf), sss_iobuf_get_size(buf)); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot write the secret [%d]: %s\n", ret, sss_strerror(ret)); + } + + return ret; +} + +static errno_t sec_update(TALLOC_CTX *mem_ctx, + struct sss_sec_req *req, + struct sss_iobuf *buf) +{ + errno_t ret; + + ret = sss_sec_update(req, sss_iobuf_get_data(buf), sss_iobuf_get_size(buf)); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot write the secret [%d]: %s\n", ret, sss_strerror(ret)); + } + + return ret; +} + +static const char *secdb_container_url_create(TALLOC_CTX *mem_ctx, + struct cli_creds *client) +{ + return talloc_asprintf(mem_ctx, + KCM_SECDB_CCACHE_FMT, + cli_creds_get_uid(client)); +} + +static const char *secdb_cc_url_create(TALLOC_CTX *mem_ctx, + struct cli_creds *client, + const char *secdb_key) +{ + return talloc_asprintf(mem_ctx, + KCM_SECDB_CCACHE_FMT"%s", + cli_creds_get_uid(client), + secdb_key); +} + +static const char *secdb_dfl_url_create(TALLOC_CTX *mem_ctx, + struct cli_creds *client) +{ + return talloc_asprintf(mem_ctx, + KCM_SECDB_DFL_FMT, + cli_creds_get_uid(client)); +} + +static errno_t kcm_ccache_to_secdb_kv(TALLOC_CTX *mem_ctx, + struct kcm_ccache *cc, + struct cli_creds *client, + const char **_url, + struct sss_iobuf **_payload) +{ + errno_t ret; + const char *url; + const char *key; + TALLOC_CTX *tmp_ctx; + struct sss_iobuf *payload; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + key = sec_key_create(tmp_ctx, cc->name, cc->uuid); + if (key == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create key for %s\n", cc->name); + ret = ENOMEM; + goto done; + } + + url = secdb_cc_url_create(tmp_ctx, client, key); + if (url == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create URL from %s\n", key); + ret = ENOMEM; + goto done; + } + + ret = kcm_ccache_to_sec_input_binary(mem_ctx, cc, &payload); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot convert ccache to a secret [%d][%s]\n", ret, sss_strerror(ret)); + goto done; + } + + ret = EOK; + DEBUG(SSSDBG_TRACE_INTERNAL, "Created URL %s\n", url); + *_url = talloc_steal(mem_ctx, url); + *_payload = talloc_steal(mem_ctx, payload); +done: + talloc_free(tmp_ctx); + return ret; +} + +struct ccdb_secdb { + struct sss_sec_ctx *sctx; +}; + +/* Since with the synchronous database, the database operations are just + * fake-async wrappers around otherwise sync operations, we don't often + * need any state structure, unless the _recv() function returns anything, + * so we use this empty structure instead + */ +struct ccdb_secdb_state { +}; + +static errno_t secdb_container_url_req(TALLOC_CTX *mem_ctx, + struct sss_sec_ctx *sctx, + struct cli_creds *client, + struct sss_sec_req **_sreq) +{ + const char *url; + struct sss_sec_req *sreq; + errno_t ret; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + url = secdb_container_url_create(tmp_ctx, client); + if (url == NULL) { + ret = ENOMEM; + goto done; + } + + ret = sss_sec_new_req(tmp_ctx, sctx, url, geteuid(), &sreq); + if (ret != EOK) { + goto done; + } + + ret = EOK; + DEBUG(SSSDBG_TRACE_INTERNAL, "Created request for URL %s\n", url); + *_sreq = talloc_steal(mem_ctx, sreq); +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t secdb_cc_url_req(TALLOC_CTX *mem_ctx, + struct sss_sec_ctx *sctx, + struct cli_creds *client, + const char *secdb_url, + struct sss_sec_req **_sreq) +{ + struct sss_sec_req *sreq; + errno_t ret; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ret = sss_sec_new_req(tmp_ctx, sctx, secdb_url, geteuid(), &sreq); + if (ret != EOK) { + goto done; + } + + ret = EOK; + DEBUG(SSSDBG_TRACE_INTERNAL, "Created request for URL %s\n", secdb_url); + *_sreq = talloc_steal(mem_ctx, sreq); +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t secdb_cc_key_req(TALLOC_CTX *mem_ctx, + struct sss_sec_ctx *sctx, + struct cli_creds *client, + const char *secdb_key, + struct sss_sec_req **_sreq) +{ + const char *url; + struct sss_sec_req *sreq; + errno_t ret; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + url = secdb_cc_url_create(tmp_ctx, client, secdb_key); + if (url == NULL) { + ret = ENOMEM; + goto done; + } + + ret = secdb_cc_url_req(tmp_ctx, sctx, client, url, &sreq); + if (ret != EOK) { + goto done; + } + + ret = EOK; + DEBUG(SSSDBG_TRACE_INTERNAL, "Created request for URL %s\n", url); + *_sreq = talloc_steal(mem_ctx, sreq); +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t secdb_dfl_url_req(TALLOC_CTX *mem_ctx, + struct sss_sec_ctx *sctx, + struct cli_creds *client, + struct sss_sec_req **_sreq) +{ + const char *url; + struct sss_sec_req *sreq; + errno_t ret; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + url = secdb_dfl_url_create(tmp_ctx, client); + if (url == NULL) { + ret = ENOMEM; + goto done; + } + + ret = sss_sec_new_req(tmp_ctx, sctx, url, geteuid(), &sreq); + if (ret != EOK) { + goto done; + } + + ret = EOK; + DEBUG(SSSDBG_TRACE_INTERNAL, "Created request for URL %s\n", url); + *_sreq = talloc_steal(mem_ctx, sreq); +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t key_by_uuid(TALLOC_CTX *mem_ctx, + struct sss_sec_ctx *sctx, + struct cli_creds *client, + uuid_t uuid, + char **_key) +{ + TALLOC_CTX *tmp_ctx; + errno_t ret; + char *key_match = NULL; + char **keys = NULL; + size_t nkeys; + struct sss_sec_req *sreq = NULL; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ret = secdb_container_url_req(tmp_ctx, sctx, client, &sreq); + if (ret != EOK) { + goto done; + } + + ret = sss_sec_list(tmp_ctx, sreq, &keys, &nkeys); + if (ret == ENOENT) { + DEBUG(SSSDBG_MINOR_FAILURE, "The container was not found\n"); + goto done; + } else if (ret != EOK) { + goto done; + } + + for (size_t i = 0; i < nkeys; i++) { + if (sec_key_match_uuid(keys[i], uuid)) { + key_match = keys[i]; + break; + } + } + + if (key_match == NULL) { + DEBUG(SSSDBG_TRACE_INTERNAL, "No key matched\n"); + ret = ENOENT; + goto done; + } + + ret = EOK; + DEBUG(SSSDBG_TRACE_INTERNAL, "Found key %s\n", key_match); + *_key = talloc_steal(mem_ctx, key_match); +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t key_by_name(TALLOC_CTX *mem_ctx, + struct sss_sec_ctx *sctx, + struct cli_creds *client, + const char *name, + char **_key) +{ + TALLOC_CTX *tmp_ctx; + errno_t ret; + char *key_match = NULL; + char **keys = NULL; + size_t nkeys; + struct sss_sec_req *sreq = NULL; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ret = secdb_container_url_req(tmp_ctx, sctx, client, &sreq); + if (ret != EOK) { + goto done; + } + + ret = sss_sec_list(tmp_ctx, sreq, &keys, &nkeys); + if (ret == ENOENT) { + DEBUG(SSSDBG_MINOR_FAILURE, "The container was not found\n"); + goto done; + } else if (ret != EOK) { + goto done; + } + + for (size_t i = 0; i < nkeys; i++) { + if (sec_key_match_name(keys[i], name)) { + key_match = keys[i]; + break; + } + } + + if (key_match == NULL) { + DEBUG(SSSDBG_TRACE_INTERNAL, "No key matched\n"); + ret = ENOENT; + goto done; + } + + ret = EOK; + DEBUG(SSSDBG_TRACE_INTERNAL, "Found key %s\n", key_match); + *_key = talloc_steal(mem_ctx, key_match); +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t secdb_get_cc(TALLOC_CTX *mem_ctx, + struct sss_sec_ctx *sctx, + const char *secdb_key, + struct cli_creds *client, + struct kcm_ccache **_cc) +{ + errno_t ret; + TALLOC_CTX *tmp_ctx = NULL; + struct kcm_ccache *cc = NULL; + struct sss_sec_req *sreq = NULL; + struct sss_iobuf *ccbuf; + + tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ret = secdb_cc_key_req(tmp_ctx, sctx, client, secdb_key, &sreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot create secdb request [%d][%s]\n", ret, sss_strerror(ret)); + goto done; + } + + ret = sec_get(tmp_ctx, sreq, &ccbuf); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot get the secret [%d][%s]\n", ret, sss_strerror(ret)); + goto done; + } + + ret = sec_kv_to_ccache_binary(tmp_ctx, secdb_key, ccbuf, client, &cc); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot convert data to ccache [%d]: %s, " + "deleting this entry\n", ret, sss_strerror(ret)); + ret = sss_sec_delete(sreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to delete entry: [%d]: %s", + ret, sss_strerror(ret)); + } + ret = ENOENT; + goto done; + } + + ret = EOK; + DEBUG(SSSDBG_TRACE_INTERNAL, "Fetched the ccache\n"); + *_cc = talloc_steal(mem_ctx, cc); +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t ccdb_secdb_init(struct kcm_ccdb *db, + struct confdb_ctx *cdb, + const char *confdb_service_path) +{ + struct ccdb_secdb *secdb = NULL; + errno_t ret; + struct sss_sec_quota *kcm_quota; + struct sss_sec_quota_opt dfl_kcm_nest_level = { + .opt_name = CONFDB_KCM_CONTAINERS_NEST_LEVEL, + .default_value = DEFAULT_SEC_CONTAINERS_NEST_LEVEL, + }; + struct sss_sec_quota_opt dfl_kcm_max_secrets = { + .opt_name = CONFDB_KCM_MAX_CCACHES, + .default_value = DEFAULT_SEC_KCM_MAX_SECRETS, + }; + struct sss_sec_quota_opt dfl_kcm_max_uid_secrets = { + .opt_name = CONFDB_KCM_MAX_UID_CCACHES, + .default_value = DEFAULT_SEC_KCM_MAX_UID_SECRETS, + }; + struct sss_sec_quota_opt dfl_kcm_max_payload_size = { + .opt_name = CONFDB_KCM_MAX_CCACHE_SIZE, + .default_value = DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE, + }; + + + secdb = talloc_zero(db, struct ccdb_secdb); + if (secdb == NULL) { + return ENOMEM; + } + + kcm_quota = talloc_zero(secdb, struct sss_sec_quota); + if (kcm_quota == NULL) { + talloc_free(secdb); + return ENOMEM; + } + + ret = sss_sec_get_quota(cdb, + confdb_service_path, + &dfl_kcm_nest_level, + &dfl_kcm_max_secrets, + &dfl_kcm_max_uid_secrets, + &dfl_kcm_max_payload_size, + kcm_quota); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to get KCM global quotas [%d]: %s\n", + ret, sss_strerror(ret)); + talloc_free(secdb); + return ret; + } + + if (kcm_quota->max_uid_secrets > 0) { + kcm_quota->max_uid_secrets += KCM_MAX_UID_EXTRA_SECRETS; + } + + ret = sss_sec_init(db, kcm_quota, &secdb->sctx); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot initialize the security database\n"); + talloc_free(secdb); + return ret; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, "secdb initialized\n"); + db->db_handle = secdb; + return EOK; +} + +struct ccdb_secdb_nextid_state { + unsigned int nextid; +}; + +static bool is_in_use(char **keys, size_t nkeys, const char *nextid_name) +{ + for (size_t i = 0; i < nkeys; i++) { + if (sec_key_match_name(keys[i], nextid_name) == true) { + return true; + } + } + + return false; +} + +static struct tevent_req *ccdb_secdb_nextid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct cli_creds *client) +{ + struct tevent_req *req = NULL; + struct ccdb_secdb_nextid_state *state = NULL; + struct ccdb_secdb *secdb = NULL; + const int maxtries = 3; + int numtry; + errno_t ret; + struct sss_sec_req *sreq = NULL; + char **keys = NULL; + size_t nkeys; + char *nextid_name = NULL; + + DEBUG(SSSDBG_TRACE_LIBS, "Generating a new ID\n"); + + req = tevent_req_create(mem_ctx, &state, struct ccdb_secdb_nextid_state); + if (req == NULL) { + return NULL; + } + + secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + if (secdb == NULL) { + ret = EIO; + goto immediate; + } + + ret = secdb_container_url_req(state, secdb->sctx, client, &sreq); + if (ret != EOK) { + goto immediate; + } + + ret = sss_sec_list(state, sreq, &keys, &nkeys); + if (ret == ENOENT) { + keys = NULL; + nkeys = 0; + } else if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot list keys [%d]: %s\n", + ret, sss_strerror(ret)); + goto immediate; + } + + for (numtry = 0; numtry < maxtries; numtry++) { + state->nextid = sss_rand() % MAX_CC_NUM; + nextid_name = talloc_asprintf(state, "%"SPRIuid":%u", + cli_creds_get_uid(client), + state->nextid); + if (nextid_name == NULL) { + ret = ENOMEM; + goto immediate; + } + + if (!is_in_use(keys, nkeys, nextid_name)) { + break; + } + } + + if (numtry >= maxtries) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to find a random ccache in %d tries\n", numtry); + ret = EBUSY; + goto immediate; + } + + ret = EOK; + DEBUG(SSSDBG_TRACE_LIBS, "Generated next ID %d\n", state->nextid); +immediate: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + return req; +} + +static errno_t ccdb_secdb_nextid_recv(struct tevent_req *req, + unsigned int *_nextid) +{ + struct ccdb_secdb_nextid_state *state = tevent_req_data(req, + struct ccdb_secdb_nextid_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + *_nextid = state->nextid; + return EOK; +} + +static struct tevent_req *ccdb_secdb_set_default_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct cli_creds *client, + uuid_t uuid) +{ + struct tevent_req *req = NULL; + struct ccdb_secdb_state *state = NULL; + struct ccdb_secdb *secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + errno_t ret; + char uuid_str[UUID_STR_SIZE]; + struct sss_sec_req *sreq = NULL; + struct sss_iobuf *iobuf; + char *cur_default; + + uuid_unparse(uuid, uuid_str); + DEBUG(SSSDBG_TRACE_INTERNAL, + "Setting the default ccache to %s\n", uuid_str); + + req = tevent_req_create(mem_ctx, &state, struct ccdb_secdb_state); + if (req == NULL) { + return NULL; + } + + ret = secdb_dfl_url_req(state, secdb->sctx, client, &sreq); + if (ret != EOK) { + goto immediate; + } + + iobuf = sss_iobuf_init_readonly(state, + (const uint8_t *) uuid_str, + UUID_STR_SIZE); + if (iobuf == NULL) { + ret = ENOMEM; + goto immediate; + } + + ret = sss_sec_get(state, sreq, (uint8_t**)&cur_default, NULL); + if (ret == ENOENT) { + ret = sec_put(state, sreq, iobuf); + } else if (ret == EOK) { + ret = sec_update(state, sreq, iobuf); + } + + if (ret != EOK) { + goto immediate; + } + + ret = EOK; + DEBUG(SSSDBG_TRACE_INTERNAL, "Set the default ccache\n"); +immediate: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + return req; +} + +static errno_t ccdb_secdb_set_default_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + return EOK; +} + +struct ccdb_secdb_get_default_state { + uuid_t uuid; +}; + +static struct tevent_req *ccdb_secdb_get_default_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct cli_creds *client) +{ + struct ccdb_secdb *secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + struct tevent_req *req = NULL; + struct ccdb_secdb_get_default_state *state = NULL; + errno_t ret; + struct sss_sec_req *sreq = NULL; + struct sss_iobuf *dfl_iobuf = NULL; + size_t uuid_size; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Getting the default ccache\n"); + + req = tevent_req_create(mem_ctx, &state, struct ccdb_secdb_get_default_state); + if (req == NULL) { + return NULL; + } + + ret = secdb_dfl_url_req(state, secdb->sctx, client, &sreq); + if (ret != EOK) { + goto immediate; + } + + ret = sec_get(state, sreq, &dfl_iobuf); + if (ret == ENOENT) { + uuid_clear(state->uuid); + ret = EOK; + goto immediate; + } else if (ret != EOK) { + goto immediate; + } + + uuid_size = sss_iobuf_get_size(dfl_iobuf); + if (uuid_size != UUID_STR_SIZE) { + DEBUG(SSSDBG_OP_FAILURE, + "Unexpected UUID size %zu, deleting this entry\n", uuid_size); + ret = sss_sec_delete(sreq); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to delete entry: [%d]: %s, " + "consider manual removal of "SECRETS_DB_PATH"/secrets.ldb\n", + ret, sss_strerror(ret)); + sss_log(SSS_LOG_CRIT, + "Can't delete an entry from "SECRETS_DB_PATH"/secrets.ldb, " + "content seems to be corrupted. Consider file removal. " + "(Take a note, this will delete all credentials managed " + "via sssd_kcm)"); + } + uuid_clear(state->uuid); + ret = EOK; + goto immediate; + } + + uuid_parse((const char *) sss_iobuf_get_data(dfl_iobuf), state->uuid); + DEBUG(SSSDBG_TRACE_INTERNAL, "Got the default ccache\n"); + ret = EOK; +immediate: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + return req; +} + +static errno_t ccdb_secdb_get_default_recv(struct tevent_req *req, + uuid_t uuid) +{ + struct ccdb_secdb_get_default_state *state = tevent_req_data(req, + struct ccdb_secdb_get_default_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + uuid_copy(uuid, state->uuid); + return EOK; +} + +static errno_t ccdb_secdb_get_cc_for_uuid(TALLOC_CTX *mem_ctx, + size_t uuid_list_count, + const char **uuid_list, + const char **uid_list, + struct ccdb_secdb *secdb, + struct kcm_ccache ***_cc_list) +{ + TALLOC_CTX *tmp_ctx; + errno_t ret; + uid_t uid; + char **list; + uuid_t uuid; + char *uuid_str; + char *secdb_key; + struct cli_creds cli_cred; + struct kcm_ccache **cc_list; + int real_count = 0; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + ret = ENOMEM; + return ret; + } + + cc_list = talloc_zero_array(tmp_ctx, struct kcm_ccache *, uuid_list_count + 1); + if (cc_list == NULL) { + ret = ENOMEM; + goto done; + } + + for (size_t i = 0; i < uuid_list_count; i++) { + struct passwd *pwd; + + ret = split_on_separator(tmp_ctx, uuid_list[i], ':', true, true, + &list, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "split on separator failed [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + + uuid_str = list[0]; + uuid_str[UUID_STR_SIZE - 1] = '\0'; + ret = uuid_parse(uuid_str, uuid); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "uuid parse of [%s] failed [%d]: %s\n", + list[0], ret, sss_strerror(ret)); + goto done; + } + uid = strtouint32(uid_list[i], NULL, 10); + ret = errno; + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid UID [%s] conversion to uint32 " + "[%d]: %s\n", uid_list[i], ret, + sss_strerror(ret)); + goto done; + } + + errno = 0; + pwd = getpwuid(uid); + if (pwd == NULL) { + ret = errno; + DEBUG(SSSDBG_MINOR_FAILURE, "Unable to resolve user [%d] who " + "is the owner of an existing ccache [%d]: %s\n", + uid, ret, sss_strerror(ret)); + /* Not fatal */ + continue; + } + + cli_cred.ucred.uid = pwd->pw_uid; + cli_cred.ucred.gid = pwd->pw_gid; + + ret = key_by_uuid(tmp_ctx, secdb->sctx, &cli_cred, uuid, &secdb_key); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "key_by_uuid() failed for uuid = '%s'", uuid_str); + goto done; + } + + ret = secdb_get_cc(cc_list, secdb->sctx, secdb_key, &cli_cred, + &cc_list[real_count]); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Failed to get ccache [%d]: %s\n", ret, sss_strerror(ret)); + /* probably ccache in old format was met and purged, just skip */ + continue; + } + + if (cc_list[real_count] == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to get cc for uuid = '%s' and uid = %s\n", + uuid_list[i], uid_list[i]); + ret = EIO; + goto done; + } + DEBUG(SSSDBG_TRACE_INTERNAL, + "Retrieved ccache [%s]\n", cc_list[real_count]->name); + real_count++; + } + + cc_list = talloc_realloc(tmp_ctx, cc_list, struct kcm_ccache *, + real_count + 1); + if (cc_list == NULL) { + ret = ENOMEM; + goto done; + } + + cc_list[real_count] = NULL; + *_cc_list = talloc_steal(mem_ctx, cc_list); + + return EOK; +done: + talloc_free(tmp_ctx); + return ret; +} + +struct ccdb_secdb_list_state { + uuid_t *uuid_list; +}; + +static errno_t ccdb_secdb_list_all_cc(TALLOC_CTX *mem_ctx, + struct krb5_ctx *krb5_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct kcm_ccache ***_cc_list) +{ + struct ccdb_secdb *secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + TALLOC_CTX *tmp_ctx; + errno_t ret; + const char **uid_list; + const char **uuid_list; + size_t uuid_list_count; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Retrieving all ccaches\n"); + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + ret = ENOMEM; + return ret; + } + + ret = sss_sec_list_cc_uuids(tmp_ctx, secdb->sctx, &uuid_list, &uid_list, &uuid_list_count); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_TRACE_INTERNAL, "Error retrieving ccache uuid list " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } else if (ret == ENOENT) { + goto done; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, "Found [%zu] ccache uuids\n", uuid_list_count); + + /* New count is full cc list size minus getpwuid() failures */ + ret = ccdb_secdb_get_cc_for_uuid(mem_ctx, uuid_list_count, uuid_list, + uid_list, secdb, _cc_list); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_INTERNAL, "Error getting cc list from uuid list " + "[%d]: %s\n", ret, sss_strerror(ret)); + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Retrieving all caches done\n"); + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +static struct tevent_req *ccdb_secdb_list_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct cli_creds *client) +{ + struct ccdb_secdb *secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + struct tevent_req *req = NULL; + struct ccdb_secdb_list_state *state = NULL; + errno_t ret; + char **keys = NULL; + size_t nkeys; + struct sss_sec_req *sreq = NULL; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Listing all ccaches\n"); + + req = tevent_req_create(mem_ctx, &state, struct ccdb_secdb_list_state); + if (req == NULL) { + return NULL; + } + + ret = secdb_container_url_req(state, secdb->sctx, client, &sreq); + if (ret != EOK) { + goto immediate; + } + + ret = sss_sec_list(state, sreq, &keys, &nkeys); + if (ret == ENOENT) { + nkeys = 0; + /* Fall through and return an empty list */ + } else if (ret != EOK) { + goto immediate; + } + DEBUG(SSSDBG_TRACE_INTERNAL, "Found %zu ccaches\n", nkeys); + + state->uuid_list = talloc_array(state, uuid_t, nkeys + 1); + if (state->uuid_list == NULL) { + ret = ENOMEM; + goto immediate; + } + + for (size_t i = 0; i < nkeys; i++) { + ret = sec_key_get_uuid(keys[i], + state->uuid_list[i]); + if (ret != EOK) { + goto immediate; + } + } + /* Sentinel */ + uuid_clear(state->uuid_list[nkeys]); + + DEBUG(SSSDBG_TRACE_INTERNAL, "Listing all caches done\n"); + ret = EOK; +immediate: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + return req; +} + +static errno_t ccdb_secdb_list_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + uuid_t **_uuid_list) +{ + struct ccdb_secdb_list_state *state = tevent_req_data(req, + struct ccdb_secdb_list_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + *_uuid_list = talloc_steal(mem_ctx, state->uuid_list); + return EOK; +} + +struct ccdb_secdb_getbyuuid_state { + struct kcm_ccache *cc; +}; + +static struct tevent_req *ccdb_secdb_getbyuuid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct cli_creds *client, + uuid_t uuid) +{ + struct ccdb_secdb *secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + struct tevent_req *req = NULL; + struct ccdb_secdb_getbyuuid_state *state = NULL; + errno_t ret; + char *secdb_key = NULL; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Getting ccache by UUID\n"); + + req = tevent_req_create(mem_ctx, &state, struct ccdb_secdb_getbyuuid_state); + if (req == NULL) { + return NULL; + } + + ret = key_by_uuid(state, secdb->sctx, client, uuid, &secdb_key); + if (ret == ENOENT) { + state->cc = NULL; + ret = EOK; + goto immediate; + } else if (ret != EOK) { + goto immediate; + } + + ret = secdb_get_cc(state, secdb->sctx, secdb_key, client, &state->cc); + if (ret == ENOENT) { + state->cc = NULL; + ret = EOK; + goto immediate; + } else if (ret != EOK) { + goto immediate; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, "Got ccache by UUID\n"); + ret = EOK; +immediate: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + return req; +} + +static errno_t ccdb_secdb_getbyuuid_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct kcm_ccache **_cc) +{ + struct ccdb_secdb_getbyuuid_state *state = tevent_req_data(req, + struct ccdb_secdb_getbyuuid_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + *_cc = talloc_steal(mem_ctx, state->cc); + return EOK; +} + +struct ccdb_secdb_getbyname_state { + struct kcm_ccache *cc; +}; + +static struct tevent_req *ccdb_secdb_getbyname_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct cli_creds *client, + const char *name) +{ + struct ccdb_secdb *secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + struct tevent_req *req = NULL; + struct ccdb_secdb_getbyname_state *state = NULL; + errno_t ret; + char *secdb_key = NULL; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Getting ccache by name\n"); + + req = tevent_req_create(mem_ctx, &state, struct ccdb_secdb_getbyname_state); + if (req == NULL) { + return NULL; + } + + ret = key_by_name(state, secdb->sctx, client, name, &secdb_key); + if (ret == ENOENT) { + state->cc = NULL; + ret = EOK; + goto immediate; + } else if (ret != EOK) { + goto immediate; + } + + ret = secdb_get_cc(state, secdb->sctx, secdb_key, client, &state->cc); + if (ret == ENOENT) { + state->cc = NULL; + ret = EOK; + goto immediate; + } else if (ret != EOK) { + goto immediate; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, "Got ccache by name\n"); + ret = EOK; +immediate: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + return req; +} + +static errno_t ccdb_secdb_getbyname_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct kcm_ccache **_cc) +{ + struct ccdb_secdb_getbyname_state *state = tevent_req_data(req, + struct ccdb_secdb_getbyname_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + *_cc = talloc_steal(mem_ctx, state->cc); + return EOK; +} + + +struct ccdb_secdb_name_by_uuid_state { + const char *name; +}; + +struct tevent_req *ccdb_secdb_name_by_uuid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct cli_creds *client, + uuid_t uuid) +{ + struct ccdb_secdb *secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + struct tevent_req *req = NULL; + struct ccdb_secdb_name_by_uuid_state *state = NULL; + errno_t ret; + char *key; + const char *name; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Translating UUID to name\n"); + + req = tevent_req_create(mem_ctx, &state, struct ccdb_secdb_name_by_uuid_state); + if (req == NULL) { + return NULL; + } + + ret = key_by_uuid(state, secdb->sctx, client, uuid, &key); + if (ret == ENOENT) { + ret = ERR_NO_CREDS; + goto immediate; + } else if (ret != EOK) { + goto immediate; + } + + name = sec_key_get_name(key); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Malformed key, cannot get name\n"); + goto immediate; + } + + state->name = talloc_strdup(state, name); + if (state->name == NULL) { + ret = ENOMEM; + goto immediate; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, "Got ccache by UUID\n"); + ret = EOK; +immediate: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + return req; +} + +errno_t ccdb_secdb_name_by_uuid_recv(struct tevent_req *req, + TALLOC_CTX *sec_ctx, + const char **_name) +{ + struct ccdb_secdb_name_by_uuid_state *state = tevent_req_data(req, + struct ccdb_secdb_name_by_uuid_state); + TEVENT_REQ_RETURN_ON_ERROR(req); + *_name = talloc_steal(sec_ctx, state->name); + return EOK; +} + +struct ccdb_secdb_uuid_by_name_state { + uuid_t uuid; +}; + +struct tevent_req *ccdb_secdb_uuid_by_name_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct cli_creds *client, + const char *name) +{ + struct ccdb_secdb *secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + struct tevent_req *req = NULL; + struct ccdb_secdb_uuid_by_name_state *state = NULL; + errno_t ret; + char *key; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Translating name to UUID\n"); + + req = tevent_req_create(mem_ctx, &state, struct ccdb_secdb_uuid_by_name_state); + if (req == NULL) { + return NULL; + } + + ret = key_by_name(state, secdb->sctx, client, name, &key); + if (ret == ENOENT) { + ret = ERR_NO_CREDS; + goto immediate; + } else if (ret != EOK) { + goto immediate; + } + + ret = sec_key_get_uuid(key, state->uuid); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Malformed key, cannot get UUID\n"); + goto immediate; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, "Got ccache by UUID\n"); + ret = EOK; +immediate: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + return req; +} + +static errno_t ccdb_secdb_uuid_by_name_recv(struct tevent_req *req, + TALLOC_CTX *sec_ctx, + uuid_t _uuid) +{ + struct ccdb_secdb_uuid_by_name_state *state = tevent_req_data(req, + struct ccdb_secdb_uuid_by_name_state); + TEVENT_REQ_RETURN_ON_ERROR(req); + uuid_copy(_uuid, state->uuid); + return EOK; +} + + +static struct tevent_req *ccdb_secdb_create_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct cli_creds *client, + struct kcm_ccache *cc) +{ + struct ccdb_secdb *secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + struct tevent_req *req = NULL; + struct ccdb_secdb_state *state = NULL; + errno_t ret; + struct sss_sec_req *container_req = NULL; + struct sss_sec_req *ccache_req = NULL; + const char *url; + struct sss_iobuf *ccache_payload; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Creating ccache storage for %s\n", cc->name); + + req = tevent_req_create(mem_ctx, &state, struct ccdb_secdb_state); + if (req == NULL) { + return NULL; + } + + /* Do the encoding asap so that if we fail, we don't even attempt any + * writes */ + ret = kcm_ccache_to_secdb_kv(state, cc, client, &url, &ccache_payload); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot convert cache %s to JSON [%d]: %s\n", + cc->name, ret, sss_strerror(ret)); + goto immediate; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, "Creating the ccache container\n"); + ret = secdb_container_url_req(state, secdb->sctx, client, &container_req); + if (ret != EOK) { + goto immediate; + } + + ret = sss_sec_create_container(container_req); + if (ret == EEXIST) { + DEBUG(SSSDBG_TRACE_INTERNAL, "Container already exists, ignoring\n"); + } else if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to create the ccache container\n"); + goto immediate; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, "ccache container created\n"); + DEBUG(SSSDBG_TRACE_INTERNAL, "creating empty ccache payload\n"); + + ret = secdb_cc_url_req(state, secdb->sctx, client, url, &ccache_req); + if (ret != EOK) { + goto immediate; + } + + ret = sec_put(state, ccache_req, ccache_payload); + if (ret != EOK) { + goto immediate; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, "payload created\n"); + ret = EOK; +immediate: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + return req; +} + +static errno_t ccdb_secdb_create_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + return EOK; +} + +static struct tevent_req *ccdb_secdb_mod_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct cli_creds *client, + uuid_t uuid, + struct kcm_mod_ctx *mod_cc) +{ + struct ccdb_secdb *secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + struct tevent_req *req = NULL; + struct ccdb_secdb_state *state = NULL; + errno_t ret; + char *secdb_key = NULL; + struct kcm_ccache *cc = NULL; + struct sss_iobuf *payload = NULL; + struct sss_sec_req *sreq = NULL; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Modifying ccache\n"); + + req = tevent_req_create(mem_ctx, &state, struct ccdb_secdb_state); + if (req == NULL) { + return NULL; + } + + ret = key_by_uuid(state, secdb->sctx, client, uuid, &secdb_key); + if (ret == ENOENT) { + ret = ERR_NO_CREDS; + goto immediate; + } else if (ret != EOK) { + goto immediate; + } + + ret = secdb_get_cc(state, secdb->sctx, secdb_key, client, &cc); + if (ret == ENOENT) { + ret = ERR_NO_CREDS; + goto immediate; + } else if (ret != EOK) { + goto immediate; + } + + ret = kcm_mod_cc(cc, mod_cc); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot modify ccache [%d]: %s\n", + ret, sss_strerror(ret)); + goto immediate; + } + + ret = kcm_ccache_to_sec_input_binary(state, cc, &payload); + if (ret != EOK) { + goto immediate; + } + + ret = secdb_cc_key_req(state, secdb->sctx, client, secdb_key, &sreq); + if (ret != EOK) { + goto immediate; + } + + ret = sec_update(state, sreq, payload); + if (ret != EOK) { + goto immediate; + } + + ret = EOK; +immediate: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + return req; +} + +static errno_t ccdb_secdb_mod_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + return EOK; +} + +static struct tevent_req *ccdb_secdb_store_cred_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct cli_creds *client, + uuid_t uuid, + struct sss_iobuf *cred_blob) +{ + struct ccdb_secdb *secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + struct tevent_req *req = NULL; + struct ccdb_secdb_state *state = NULL; + char *secdb_key = NULL; + struct kcm_ccache *cc = NULL; + struct sss_iobuf *payload = NULL; + struct sss_sec_req *sreq = NULL; + errno_t ret; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Storing creds in ccache\n"); + + req = tevent_req_create(mem_ctx, &state, struct ccdb_secdb_state); + if (req == NULL) { + return NULL; + } + + ret = key_by_uuid(state, secdb->sctx, client, uuid, &secdb_key); + if (ret == ENOENT) { + ret = ERR_NO_CREDS; + goto immediate; + } else if (ret != EOK) { + goto immediate; + } + + ret = secdb_get_cc(state, secdb->sctx, secdb_key, client, &cc); + if (ret == ENOENT) { + ret = ERR_NO_CREDS; + goto immediate; + } else if (ret != EOK) { + goto immediate; + } + + ret = kcm_cc_store_cred_blob(cc, cred_blob); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot store credentials to ccache [%d]: %s\n", + ret, sss_strerror(ret)); + goto immediate; + } + + ret = kcm_ccache_to_sec_input_binary(state, cc, &payload); + if (ret != EOK) { + goto immediate; + } + + ret = secdb_cc_key_req(state, secdb->sctx, client, secdb_key, &sreq); + if (ret != EOK) { + goto immediate; + } + + ret = sec_update(state, sreq, payload); + if (ret != EOK) { + goto immediate; + } + + ret = EOK; +immediate: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + return req; +} + +static errno_t ccdb_secdb_store_cred_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + return EOK; +} + +static struct tevent_req *ccdb_secdb_delete_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct kcm_ccdb *db, + struct cli_creds *client, + uuid_t uuid) +{ + struct tevent_req *req = NULL; + struct ccdb_secdb_state *state = NULL; + struct ccdb_secdb *secdb = talloc_get_type(db->db_handle, struct ccdb_secdb); + struct sss_sec_req *container_req = NULL; + struct sss_sec_req *sreq = NULL; + char *secdb_key = NULL; + char **keys = NULL; + size_t nkeys; + errno_t ret; + + DEBUG(SSSDBG_TRACE_INTERNAL, "Deleting ccache\n"); + + req = tevent_req_create(mem_ctx, &state, struct ccdb_secdb_state); + if (req == NULL) { + return NULL; + } + + ret = secdb_container_url_req(state, secdb->sctx, client, &container_req); + if (ret != EOK) { + goto immediate; + } + + ret = sss_sec_list(state, container_req, &keys, &nkeys); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, "No ccaches to delete\n"); + goto immediate; + } + DEBUG(SSSDBG_TRACE_INTERNAL, "Found %zu ccaches\n", nkeys); + + if (nkeys == 0) { + ret = EOK; + goto immediate; + } + + ret = key_by_uuid(state, secdb->sctx, client, uuid, &secdb_key); + if (ret == ENOENT) { + ret = ERR_NO_CREDS; + goto immediate; + } else if (ret != EOK) { + goto immediate; + } + + ret = secdb_cc_key_req(state, secdb->sctx, client, secdb_key, &sreq); + if (ret != EOK) { + goto immediate; + } + + ret = sss_sec_delete(sreq); + if (ret != EOK) { + goto immediate; + } + + if (nkeys > 1) { + DEBUG(SSSDBG_TRACE_INTERNAL, "There are other ccaches, done\n"); + ret = EOK; + goto immediate; + } + DEBUG(SSSDBG_TRACE_INTERNAL, "Removing ccache container\n"); + + ret = sss_sec_delete(container_req); + if (ret != EOK) { + goto immediate; + } + + ret = EOK; +immediate: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + return req; +} + +static errno_t ccdb_secdb_delete_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + return EOK; +} + +const struct kcm_ccdb_ops ccdb_secdb_ops = { + .init = ccdb_secdb_init, + + .nextid_send = ccdb_secdb_nextid_send, + .nextid_recv = ccdb_secdb_nextid_recv, + + .set_default_send = ccdb_secdb_set_default_send, + .set_default_recv = ccdb_secdb_set_default_recv, + + .get_default_send = ccdb_secdb_get_default_send, + .get_default_recv = ccdb_secdb_get_default_recv, + + .list_send = ccdb_secdb_list_send, + .list_recv = ccdb_secdb_list_recv, + + .list_all_cc = ccdb_secdb_list_all_cc, + + .getbyname_send = ccdb_secdb_getbyname_send, + .getbyname_recv = ccdb_secdb_getbyname_recv, + + .getbyuuid_send = ccdb_secdb_getbyuuid_send, + .getbyuuid_recv = ccdb_secdb_getbyuuid_recv, + + .name_by_uuid_send = ccdb_secdb_name_by_uuid_send, + .name_by_uuid_recv = ccdb_secdb_name_by_uuid_recv, + + .uuid_by_name_send = ccdb_secdb_uuid_by_name_send, + .uuid_by_name_recv = ccdb_secdb_uuid_by_name_recv, + + .create_send = ccdb_secdb_create_send, + .create_recv = ccdb_secdb_create_recv, + + .mod_send = ccdb_secdb_mod_send, + .mod_recv = ccdb_secdb_mod_recv, + + .store_cred_send = ccdb_secdb_store_cred_send, + .store_cred_recv = ccdb_secdb_store_cred_recv, + + .delete_send = ccdb_secdb_delete_send, + .delete_recv = ccdb_secdb_delete_recv, +}; |