387014f928
required for building freeipa-4.5.x in rawhide
2327 lines
74 KiB
Diff
2327 lines
74 KiB
Diff
From 1ec4198f38d34a1f82a2db55d8c9782a434fb55f Mon Sep 17 00:00:00 2001
|
|
From: Jakub Hrozek <jhrozek@redhat.com>
|
|
Date: Fri, 23 Sep 2016 14:49:09 +0200
|
|
Subject: [PATCH 28/97] KCM: Implement KCM server operations
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Implements the actual KCM server operations. On a high level, each
|
|
operation unmarhalls the needed data from the input buffer, calls into
|
|
the ccache db and marshalls a response.
|
|
|
|
Only the operations that are also implemented by the MIT client are
|
|
implemented by our KCM server.
|
|
|
|
Resolves:
|
|
https://pagure.io/SSSD/sssd/issue/2887
|
|
|
|
Reviewed-by: Michal Židek <mzidek@redhat.com>
|
|
Reviewed-by: Simo Sorce <simo@redhat.com>
|
|
---
|
|
Makefile.am | 2 +
|
|
src/responder/kcm/kcmsrv_cmd.c | 151 +++-
|
|
src/responder/kcm/kcmsrv_ops.c | 1954 ++++++++++++++++++++++++++++++++++++++++
|
|
src/responder/kcm/kcmsrv_ops.h | 45 +
|
|
4 files changed, 2143 insertions(+), 9 deletions(-)
|
|
create mode 100644 src/responder/kcm/kcmsrv_ops.c
|
|
create mode 100644 src/responder/kcm/kcmsrv_ops.h
|
|
|
|
diff --git a/Makefile.am b/Makefile.am
|
|
index 5605c1a53c44fd9e83394e80b7f71828df1d39b6..49b4cabf9ee3ce1417f955c972376894f3709b33 100644
|
|
--- a/Makefile.am
|
|
+++ b/Makefile.am
|
|
@@ -714,6 +714,7 @@ dist_noinst_HEADERS = \
|
|
src/responder/kcm/kcmsrv_ccache.h \
|
|
src/responder/kcm/kcmsrv_ccache_pvt.h \
|
|
src/responder/kcm/kcmsrv_ccache_be.h \
|
|
+ src/responder/kcm/kcmsrv_ops.h \
|
|
src/sbus/sbus_client.h \
|
|
src/sbus/sssd_dbus.h \
|
|
src/sbus/sssd_dbus_meta.h \
|
|
@@ -1493,6 +1494,7 @@ sssd_kcm_SOURCES = \
|
|
src/responder/kcm/kcmsrv_cmd.c \
|
|
src/responder/kcm/kcmsrv_ccache.c \
|
|
src/responder/kcm/kcmsrv_ccache_mem.c \
|
|
+ src/responder/kcm/kcmsrv_ops.c \
|
|
src/util/sss_sockets.c \
|
|
src/util/sss_krb5.c \
|
|
src/util/sss_iobuf.c \
|
|
diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c
|
|
index cbf70353730d8a4e03d8f75c97395f4ef007e77f..537e88953fd1a190a9a73bcdd430d8e0db8f9291 100644
|
|
--- a/src/responder/kcm/kcmsrv_cmd.c
|
|
+++ b/src/responder/kcm/kcmsrv_cmd.c
|
|
@@ -23,10 +23,10 @@
|
|
|
|
#include "config.h"
|
|
#include "util/util.h"
|
|
-#include "util/sss_iobuf.h"
|
|
#include "responder/common/responder.h"
|
|
#include "responder/kcm/kcmsrv_pvt.h"
|
|
#include "responder/kcm/kcm.h"
|
|
+#include "responder/kcm/kcmsrv_ops.h"
|
|
|
|
/* The first four bytes of a message is always the size */
|
|
#define KCM_MSG_LEN_SIZE 4
|
|
@@ -133,7 +133,6 @@ static errno_t kcm_input_parse(struct kcm_reqbuf *reqbuf,
|
|
{
|
|
size_t lc = 0;
|
|
size_t mc = 0;
|
|
- uint16_t opcode = 0;
|
|
uint16_t opcode_be = 0;
|
|
uint32_t len_be = 0;
|
|
uint32_t msglen;
|
|
@@ -162,7 +161,7 @@ static errno_t kcm_input_parse(struct kcm_reqbuf *reqbuf,
|
|
return EBADMSG;
|
|
}
|
|
|
|
- /* First 16 bits are 8 bit major and 8bit major protocol version */
|
|
+ /* First 16 bits are 8 bit major and 8bit minor protocol version */
|
|
SAFEALIGN_COPY_UINT8_CHECK(&proto_maj,
|
|
reqbuf->v_msg.kiov_base + mc,
|
|
reqbuf->v_msg.kiov_len,
|
|
@@ -191,8 +190,16 @@ static errno_t kcm_input_parse(struct kcm_reqbuf *reqbuf,
|
|
reqbuf->v_msg.kiov_len,
|
|
&mc);
|
|
|
|
- opcode = be16toh(opcode_be);
|
|
- DEBUG(SSSDBG_TRACE_LIBS, "Received operation code %"PRIu16"\n", opcode);
|
|
+ op_io->op = kcm_get_opt(be16toh(opcode_be));
|
|
+ if (op_io->op == NULL) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
+ "Did not find a KCM operation handler for the requested opcode\n");
|
|
+ return ERR_KCM_MALFORMED_IN_PKT;
|
|
+ }
|
|
+
|
|
+ /* The operation only receives the payload, not the opcode or the protocol info */
|
|
+ op_io->request.data = reqbuf->v_msg.kiov_base + mc;
|
|
+ op_io->request.length = reqbuf->v_msg.nprocessed - mc;
|
|
|
|
return EOK;
|
|
}
|
|
@@ -240,6 +247,46 @@ static errno_t kcm_failbuf_construct(errno_t ret,
|
|
c = 0;
|
|
SAFEALIGN_SETMEM_UINT32(repbuf->rcbuf, htobe32(ret), &c);
|
|
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Sent reply with error %d\n", ret);
|
|
+ return EOK;
|
|
+}
|
|
+
|
|
+/* retcode is 0 if the operation at least ran, non-zero if there
|
|
+ * was some kind of internal KCM error, like input couldn't be parsed
|
|
+ */
|
|
+static errno_t kcm_output_construct(struct kcm_op_io *op_io,
|
|
+ struct kcm_repbuf *repbuf)
|
|
+{
|
|
+ size_t c;
|
|
+ size_t replen;
|
|
+
|
|
+ replen = sss_iobuf_get_len(op_io->reply);
|
|
+ if (replen > KCM_PACKET_MAX_SIZE) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
+ "Reply exceeds the KCM protocol limit, aborting\n");
|
|
+ return E2BIG;
|
|
+ }
|
|
+
|
|
+ DEBUG(SSSDBG_TRACE_LIBS,
|
|
+ "Sending a reply with %zu bytes of payload\n", replen);
|
|
+ c = 0;
|
|
+ SAFEALIGN_SETMEM_UINT32(repbuf->lenbuf, htobe32(replen), &c);
|
|
+
|
|
+ c = 0;
|
|
+ SAFEALIGN_SETMEM_UINT32(repbuf->rcbuf, 0, &c);
|
|
+
|
|
+ if (replen > 0) {
|
|
+ c = 0;
|
|
+ SAFEALIGN_MEMCPY_CHECK(repbuf->msgbuf,
|
|
+ sss_iobuf_get_data(op_io->reply),
|
|
+ replen,
|
|
+ repbuf->v_msg.kiov_len,
|
|
+ &c);
|
|
+
|
|
+ /* Length of the buffer to send to KCM client */
|
|
+ repbuf->v_msg.kiov_len = replen;
|
|
+ }
|
|
+
|
|
return EOK;
|
|
}
|
|
|
|
@@ -260,7 +307,8 @@ static void kcm_reply_error(struct cli_ctx *cctx,
|
|
|
|
ret = kcm_failbuf_construct(kerr, repbuf);
|
|
if (ret != EOK) {
|
|
- /* If we can't construct the reply buffer, just terminate the client */
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
+ "Cannot construct the reply buffer, terminating client\n");
|
|
talloc_free(cctx);
|
|
return;
|
|
}
|
|
@@ -268,6 +316,24 @@ static void kcm_reply_error(struct cli_ctx *cctx,
|
|
TEVENT_FD_WRITEABLE(cctx->cfde);
|
|
}
|
|
|
|
+static void kcm_send_reply(struct cli_ctx *cctx,
|
|
+ struct kcm_op_io *op_io,
|
|
+ struct kcm_repbuf *repbuf)
|
|
+{
|
|
+ errno_t ret;
|
|
+
|
|
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Sending a reply\n");
|
|
+ ret = kcm_output_construct(op_io, repbuf);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
+ "Cannot construct the reply buffer, terminating client\n");
|
|
+ kcm_reply_error(cctx, ret, repbuf);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ TEVENT_FD_WRITEABLE(cctx->cfde);
|
|
+}
|
|
+
|
|
/**
|
|
* Request-reply dispatcher
|
|
*/
|
|
@@ -285,17 +351,67 @@ struct kcm_req_ctx {
|
|
struct kcm_op_io op_io;
|
|
};
|
|
|
|
+static void kcm_cmd_request_done(struct tevent_req *req);
|
|
+
|
|
+static errno_t kcm_cmd_dispatch(struct kcm_req_ctx *req_ctx)
|
|
+{
|
|
+ struct tevent_req *req;
|
|
+ struct cli_ctx *cctx;
|
|
+
|
|
+ cctx = req_ctx->cctx;
|
|
+
|
|
+ req = kcm_cmd_send(req_ctx, cctx->ev, req_ctx->kctx->kcm_data,
|
|
+ req_ctx->cctx->creds,
|
|
+ &req_ctx->op_io.request,
|
|
+ req_ctx->op_io.op);
|
|
+ if (req == NULL) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to schedule KCM operation.\n");
|
|
+ return ENOMEM;
|
|
+ }
|
|
+
|
|
+ tevent_req_set_callback(req, kcm_cmd_request_done, req_ctx);
|
|
+ return EOK;
|
|
+}
|
|
+
|
|
+static void kcm_cmd_request_done(struct tevent_req *req)
|
|
+{
|
|
+ struct kcm_req_ctx *req_ctx;
|
|
+ struct cli_ctx *cctx;
|
|
+ errno_t ret;
|
|
+
|
|
+ req_ctx = tevent_req_callback_data(req, struct kcm_req_ctx);
|
|
+ cctx = req_ctx->cctx;
|
|
+
|
|
+ ret = kcm_cmd_recv(req_ctx, req,
|
|
+ &req_ctx->op_io.reply);
|
|
+ talloc_free(req);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "KCM operation failed [%d]: %s\n", ret, sss_strerror(ret));
|
|
+ kcm_reply_error(cctx, ret, &req_ctx->repbuf);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ kcm_send_reply(cctx, &req_ctx->op_io, &req_ctx->repbuf);
|
|
+}
|
|
+
|
|
static errno_t kcm_recv_data(int fd, struct kcm_reqbuf *reqbuf)
|
|
{
|
|
errno_t ret;
|
|
|
|
ret = kcm_read_iovec(fd, &reqbuf->v_len);
|
|
if (ret != EOK) {
|
|
+ /* Not all errors are fatal, hence we don't print DEBUG messages
|
|
+ * here, but in the caller
|
|
+ */
|
|
return ret;
|
|
}
|
|
|
|
ret = kcm_read_iovec(fd, &reqbuf->v_msg);
|
|
if (ret != EOK) {
|
|
+ /* Not all errors are fatal, hence we don't print DEBUG messages
|
|
+ * here, but in the caller
|
|
+ */
|
|
return ret;
|
|
}
|
|
|
|
@@ -389,7 +505,15 @@ static void kcm_recv(struct cli_ctx *cctx)
|
|
/* do not read anymore, client is done sending */
|
|
TEVENT_FD_NOT_READABLE(cctx->cfde);
|
|
|
|
- kcm_reply_error(cctx, ret, &req->repbuf);
|
|
+ ret = kcm_cmd_dispatch(req);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_FATAL_FAILURE,
|
|
+ "Failed to dispatch KCM operation [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ /* Dispatched request resumes in kcm_cmd_request_done */
|
|
return;
|
|
|
|
fail:
|
|
@@ -406,16 +530,25 @@ static int kcm_send_data(struct cli_ctx *cctx)
|
|
|
|
ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_len);
|
|
if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
+ "Failed to write the length iovec [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
return ret;
|
|
}
|
|
|
|
ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_rc);
|
|
if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
+ "Failed to write the retcode iovec [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
return ret;
|
|
}
|
|
|
|
ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_msg);
|
|
if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
+ "Failed to write the msg iovec [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
return ret;
|
|
}
|
|
|
|
@@ -428,7 +561,7 @@ static void kcm_send(struct cli_ctx *cctx)
|
|
|
|
ret = kcm_send_data(cctx);
|
|
if (ret == EAGAIN) {
|
|
- /* not all data was sent, loop again */
|
|
+ DEBUG(SSSDBG_TRACE_ALL, "Sending data again..\n");
|
|
return;
|
|
} else if (ret != EOK) {
|
|
DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting client!\n");
|
|
@@ -436,7 +569,7 @@ static void kcm_send(struct cli_ctx *cctx)
|
|
return;
|
|
}
|
|
|
|
- /* ok all sent */
|
|
+ DEBUG(SSSDBG_TRACE_INTERNAL, "All data sent!\n");
|
|
TEVENT_FD_NOT_WRITEABLE(cctx->cfde);
|
|
TEVENT_FD_READABLE(cctx->cfde);
|
|
talloc_zfree(cctx->state_ctx);
|
|
diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..50e8cc635424e15d53e3c8d122c5525044f59c8a
|
|
--- /dev/null
|
|
+++ b/src/responder/kcm/kcmsrv_ops.c
|
|
@@ -0,0 +1,1954 @@
|
|
+/*
|
|
+ SSSD
|
|
+
|
|
+ KCM Server - the KCM server operations
|
|
+
|
|
+ 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 <krb5/krb5.h>
|
|
+
|
|
+#include "util/sss_iobuf.h"
|
|
+#include "util/sss_krb5.h"
|
|
+#include "util/util_creds.h"
|
|
+#include "responder/kcm/kcm.h"
|
|
+#include "responder/kcm/kcmsrv_pvt.h"
|
|
+#include "responder/kcm/kcmsrv_ops.h"
|
|
+#include "responder/kcm/kcmsrv_ccache.h"
|
|
+
|
|
+#define KCM_REPLY_MAX 2048
|
|
+
|
|
+struct kcm_op_ctx {
|
|
+ struct kcm_resp_ctx *kcm_data;
|
|
+ struct cli_creds *client;
|
|
+
|
|
+ struct sss_iobuf *input;
|
|
+ struct sss_iobuf *reply;
|
|
+};
|
|
+
|
|
+/* Each operation follows the same pattern and is implemented using
|
|
+ * functions with this prototype. The operation receives an op_ctx
|
|
+ * that serves as a state of the operation and can be used to keep
|
|
+ * track of any temporary data. The operation writes its output data
|
|
+ * into the op_ctx reply IO buffer and returns the op_ret status code
|
|
+ * separately.
|
|
+ *
|
|
+ * The operation always returns EOK unless an internal error occurs,
|
|
+ * the result of the operation is stored in the op_ret variable
|
|
+ */
|
|
+typedef struct tevent_req*
|
|
+(*kcm_srv_send_method)(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx);
|
|
+typedef errno_t
|
|
+(*kcm_srv_recv_method)(struct tevent_req *req,
|
|
+ uint32_t *_op_ret);
|
|
+
|
|
+struct kcm_op {
|
|
+ const char *name;
|
|
+ kcm_srv_send_method fn_send;
|
|
+ kcm_srv_recv_method fn_recv;
|
|
+};
|
|
+
|
|
+struct kcm_cmd_state {
|
|
+ struct kcm_op *op;
|
|
+
|
|
+ struct kcm_op_ctx *op_ctx;
|
|
+ struct sss_iobuf *reply;
|
|
+
|
|
+ uint32_t op_ret;
|
|
+};
|
|
+
|
|
+static void kcm_cmd_done(struct tevent_req *subreq);
|
|
+
|
|
+struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_resp_ctx *kcm_data,
|
|
+ struct cli_creds *client,
|
|
+ struct kcm_data *input,
|
|
+ struct kcm_op *op)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_cmd_state *state = NULL;
|
|
+ errno_t ret;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_cmd_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op = op;
|
|
+
|
|
+ if (op == NULL) {
|
|
+ ret = EINVAL;
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ DEBUG(SSSDBG_TRACE_FUNC, "KCM operation %s\n", op->name);
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "%zu bytes on KCM input\n", input->length);
|
|
+
|
|
+ state->reply = sss_iobuf_init_empty(state,
|
|
+ KCM_REPLY_MAX,
|
|
+ KCM_REPLY_MAX);
|
|
+ if (state->reply == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ if (op->fn_send == NULL) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
+ "KCM op %s has no handler\n", kcm_opt_name(op));
|
|
+ ret = ERR_KCM_OP_NOT_IMPLEMENTED;
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ /* Allocating op_ctx on the heap makes it possible for operations to use
|
|
+ * op_ctx as their temporary context and avoid tmp_ctx altogether
|
|
+ */
|
|
+ state->op_ctx = talloc_zero(state, struct kcm_op_ctx);
|
|
+ if (state->op_ctx == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ state->op_ctx->kcm_data = kcm_data;
|
|
+ state->op_ctx->client = client;
|
|
+
|
|
+ state->op_ctx->input = sss_iobuf_init_readonly(state->op_ctx,
|
|
+ input->data,
|
|
+ input->length);
|
|
+ if (state->op_ctx->input == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * The internal operation returns the opcode and the buffer separately.
|
|
+ * The KCM server reply to the client also always contains zero if the
|
|
+ * operation ran to completion, both are uint32_t.
|
|
+ * FIXME:
|
|
+ * Alternatively, we could extend iobuf API so that we can just pass
|
|
+ * the reply's buffer+sizeof(2*uint32_t) and avoid the useless allocations
|
|
+ */
|
|
+ state->op_ctx->reply = sss_iobuf_init_empty(
|
|
+ state,
|
|
+ KCM_REPLY_MAX - 2*sizeof(uint32_t),
|
|
+ KCM_REPLY_MAX - 2*sizeof(uint32_t));
|
|
+ if (state->reply == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ subreq = op->fn_send(state, ev, state->op_ctx);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_cmd_done, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_cmd_done(struct tevent_req *subreq)
|
|
+{
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
|
|
+ struct kcm_cmd_state *state = tevent_req_data(req, struct kcm_cmd_state);
|
|
+ errno_t ret;
|
|
+ krb5_error_code kerr;
|
|
+
|
|
+ ret = state->op->fn_recv(subreq, &state->op_ret);
|
|
+ talloc_free(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "op receive function failed [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ DEBUG(SSSDBG_TRACE_FUNC,
|
|
+ "KCM operation %s returned [%d]: %s\n",
|
|
+ kcm_opt_name(state->op), state->op_ret, sss_strerror(state->op_ret));
|
|
+
|
|
+ kerr = sss2krb5_error(state->op_ret);
|
|
+
|
|
+ /* The first four bytes of the reply is the operation status code */
|
|
+ ret = sss_iobuf_write_uint32(state->reply, htobe32(kerr));
|
|
+ if (ret != EOK) {
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = sss_iobuf_write_len(state->reply,
|
|
+ sss_iobuf_get_data(state->op_ctx->reply),
|
|
+ sss_iobuf_get_len(state->op_ctx->reply));
|
|
+ if (ret != EOK) {
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+errno_t kcm_cmd_recv(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_req *req,
|
|
+ struct sss_iobuf **_reply)
|
|
+{
|
|
+ struct kcm_cmd_state *state = NULL;
|
|
+
|
|
+ TEVENT_REQ_RETURN_ON_ERROR(req);
|
|
+
|
|
+ state = tevent_req_data(req, struct kcm_cmd_state);
|
|
+
|
|
+ *_reply = talloc_steal(mem_ctx, state->reply);
|
|
+ return EOK;
|
|
+}
|
|
+
|
|
+/* ======= KCM operations ======= */
|
|
+
|
|
+/* Operations that don't return any extra information except for the op_ret
|
|
+ * can use this macro in the _recv function to avoid code duplication
|
|
+ */
|
|
+#define KCM_OP_RET_FROM_TYPE(req, state_type, _op_ret_out) do { \
|
|
+ state_type *state = NULL; \
|
|
+ state = tevent_req_data(req, state_type); \
|
|
+ TEVENT_REQ_RETURN_ON_ERROR(req); \
|
|
+ *_op_ret_out = state->op_ret; \
|
|
+ return EOK; \
|
|
+} while(0);
|
|
+
|
|
+struct kcm_op_common_state {
|
|
+ uint32_t op_ret;
|
|
+ struct kcm_op_ctx *op_ctx;
|
|
+ struct tevent_context *ev;
|
|
+};
|
|
+
|
|
+static errno_t kcm_op_common_recv(struct tevent_req *req,
|
|
+ uint32_t *_op_ret)
|
|
+{
|
|
+ struct kcm_op_common_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_common_state);
|
|
+ TEVENT_REQ_RETURN_ON_ERROR(req);
|
|
+ *_op_ret = state->op_ret;
|
|
+ return EOK;
|
|
+}
|
|
+
|
|
+/* () -> (name) */
|
|
+static void kcm_op_gen_new_done(struct tevent_req *subreq);
|
|
+
|
|
+static struct tevent_req *kcm_op_gen_new_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_op_common_state *state = NULL;
|
|
+ errno_t ret;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+
|
|
+ subreq = kcm_ccdb_nextid_send(state, ev,
|
|
+ op_ctx->kcm_data->db,
|
|
+ op_ctx->client);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_gen_new_done, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_op_gen_new_done(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ char *newid;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_common_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_common_state);
|
|
+
|
|
+ ret = kcm_ccdb_nextid_recv(subreq, state, &newid);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot generate a new ID [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Generated a new ID %s\n", newid);
|
|
+
|
|
+ ret = sss_iobuf_write_stringz(state->op_ctx->reply, newid);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot write generated ID %d: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ state->op_ret = EOK;
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+/* (princ) -> () */
|
|
+struct kcm_op_initialize_state {
|
|
+ uint32_t op_ret;
|
|
+ struct kcm_op_ctx *op_ctx;
|
|
+ struct tevent_context *ev;
|
|
+
|
|
+ struct kcm_ccache *new_cc;
|
|
+ const char *name;
|
|
+ krb5_principal princ;
|
|
+};
|
|
+
|
|
+static void kcm_op_initialize_got_byname(struct tevent_req *subreq);
|
|
+static void kcm_op_initialize_cc_create_done(struct tevent_req *subreq);
|
|
+static void kcm_op_initialize_cc_delete_done(struct tevent_req *subreq);
|
|
+static void kcm_op_initialize_create_step(struct tevent_req *req);
|
|
+static void kcm_op_initialize_got_default(struct tevent_req *subreq);
|
|
+static void kcm_op_initialize_set_default_done(struct tevent_req *subreq);
|
|
+
|
|
+static struct tevent_req *kcm_op_initialize_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_op_initialize_state *state = NULL;
|
|
+ errno_t ret;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_initialize_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+ state->ev = ev;
|
|
+
|
|
+ ret = sss_iobuf_read_stringz(op_ctx->input, &state->name);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
+ "Cannot read input name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto immediate;
|
|
+ }
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Initializing ccache %s\n", state->name);
|
|
+
|
|
+ ret = kcm_check_name(state->name, op_ctx->client);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
+ "Name %s is malformed [%d]: %s\n",
|
|
+ state->name, ret, sss_strerror(ret));
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ ret = sss_krb5_unmarshal_princ(op_ctx, op_ctx->input, &state->princ);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
+ "Cannot unmarshal principal [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ subreq = kcm_ccdb_getbyname_send(state, ev,
|
|
+ op_ctx->kcm_data->db,
|
|
+ op_ctx->client,
|
|
+ state->name);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_initialize_got_byname, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_op_initialize_got_byname(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_initialize_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_initialize_state);
|
|
+ bool ok;
|
|
+ uuid_t uuid;
|
|
+
|
|
+ ret = kcm_ccdb_getbyname_recv(subreq, state, &state->new_cc);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get ccache by name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (state->new_cc != NULL) {
|
|
+ ok = kcm_cc_access(state->new_cc, state->op_ctx->client);
|
|
+ if (!ok) {
|
|
+ state->op_ret = EACCES;
|
|
+ tevent_req_done(req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = kcm_cc_get_uuid(state->new_cc, uuid);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get new ccache UUID [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Nuke any previous cache and its contents during initialization */
|
|
+ subreq = kcm_ccdb_delete_cc_send(state,
|
|
+ state->ev,
|
|
+ state->op_ctx->kcm_data->db,
|
|
+ state->op_ctx->client,
|
|
+ uuid);
|
|
+ if (subreq == NULL) {
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_initialize_cc_delete_done, req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ kcm_op_initialize_create_step(req);
|
|
+}
|
|
+
|
|
+static void kcm_op_initialize_cc_delete_done(struct tevent_req *subreq)
|
|
+{
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ errno_t ret;
|
|
+
|
|
+ ret = kcm_ccdb_delete_cc_recv(subreq);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot delete ccache from the db %d: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ kcm_op_initialize_create_step(req);
|
|
+}
|
|
+
|
|
+static void kcm_op_initialize_create_step(struct tevent_req *req)
|
|
+{
|
|
+ struct tevent_req *subreq;
|
|
+ struct kcm_op_initialize_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_initialize_state);
|
|
+ errno_t ret;
|
|
+
|
|
+ ret = kcm_cc_new(state->op_ctx,
|
|
+ state->op_ctx->kcm_data->k5c,
|
|
+ state->op_ctx->client,
|
|
+ state->name,
|
|
+ state->princ,
|
|
+ &state->new_cc);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot create new ccache %d: %s\n", ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ subreq = kcm_ccdb_create_cc_send(state,
|
|
+ state->ev,
|
|
+ state->op_ctx->kcm_data->db,
|
|
+ state->op_ctx->client,
|
|
+ state->new_cc);
|
|
+ if (subreq == NULL) {
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_initialize_cc_create_done, req);
|
|
+}
|
|
+
|
|
+static void kcm_op_initialize_cc_create_done(struct tevent_req *subreq)
|
|
+{
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_initialize_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_initialize_state);
|
|
+ errno_t ret;
|
|
+
|
|
+ ret = kcm_ccdb_create_cc_recv(subreq);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot add ccache to db %d: %s\n", ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* If there was no previous default ccache, set this one as default */
|
|
+ subreq = kcm_ccdb_get_default_send(state, state->ev,
|
|
+ state->op_ctx->kcm_data->db,
|
|
+ state->op_ctx->client);
|
|
+ if (subreq == NULL) {
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_initialize_got_default, req);
|
|
+}
|
|
+
|
|
+static void kcm_op_initialize_got_default(struct tevent_req *subreq)
|
|
+{
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_initialize_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_initialize_state);
|
|
+ errno_t ret;
|
|
+ uuid_t dfl_uuid;
|
|
+ uuid_t old_dfl_uuid;
|
|
+
|
|
+ ret = kcm_ccdb_get_default_recv(subreq, &old_dfl_uuid);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get default ccache [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (uuid_is_null(old_dfl_uuid) == false) {
|
|
+ /* If there was a previous default ccache, switch to the initialized
|
|
+ * one by default
|
|
+ */
|
|
+ ret = kcm_cc_get_uuid(state->new_cc, dfl_uuid);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get new ccache UUID [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ subreq = kcm_ccdb_set_default_send(state,
|
|
+ state->ev,
|
|
+ state->op_ctx->kcm_data->db,
|
|
+ state->op_ctx->client,
|
|
+ dfl_uuid);
|
|
+ if (subreq == NULL) {
|
|
+ tevent_req_error(req, ENOMEM);
|
|
+ return;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_initialize_set_default_done, req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* ENOENT, done */
|
|
+ state->op_ret = EOK;
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+static void kcm_op_initialize_set_default_done(struct tevent_req *subreq)
|
|
+{
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_initialize_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_initialize_state);
|
|
+ errno_t ret;
|
|
+
|
|
+ ret = kcm_ccdb_set_default_recv(subreq);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot set default ccache %d: %s\n", ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ state->op_ret = EOK;
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+static errno_t kcm_op_initialize_recv(struct tevent_req *req,
|
|
+ uint32_t *_op_ret)
|
|
+{
|
|
+ KCM_OP_RET_FROM_TYPE(req, struct kcm_op_initialize_state, _op_ret);
|
|
+}
|
|
+
|
|
+/* (name) -> () */
|
|
+static void kcm_op_destroy_getbyname_done(struct tevent_req *subreq);
|
|
+static void kcm_op_destroy_delete_done(struct tevent_req *subreq);
|
|
+
|
|
+static struct tevent_req *kcm_op_destroy_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_op_common_state *state = NULL;
|
|
+ errno_t ret;
|
|
+ const char *name;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+ state->ev = ev;
|
|
+
|
|
+ ret = sss_iobuf_read_stringz(op_ctx->input, &name);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot unmarshall input name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Destroying credentials of %s\n", name);
|
|
+
|
|
+ subreq = kcm_ccdb_uuid_by_name_send(state, ev,
|
|
+ op_ctx->kcm_data->db,
|
|
+ op_ctx->client,
|
|
+ name);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_destroy_getbyname_done, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_op_destroy_getbyname_done(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_common_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_common_state);
|
|
+ uuid_t uuid;
|
|
+
|
|
+ ret = kcm_ccdb_uuid_by_name_recv(subreq, state, uuid);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get matching ccache [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ subreq = kcm_ccdb_delete_cc_send(state,
|
|
+ state->ev,
|
|
+ state->op_ctx->kcm_data->db,
|
|
+ state->op_ctx->client,
|
|
+ uuid);
|
|
+ if (subreq == NULL) {
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_destroy_delete_done, req);
|
|
+}
|
|
+
|
|
+static void kcm_op_destroy_delete_done(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_common_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_common_state);
|
|
+
|
|
+ ret = kcm_ccdb_delete_cc_recv(subreq);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot delete ccache from the db [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ state->op_ret = EOK;
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+/* (name, cred) -> () */
|
|
+struct kcm_op_store_state {
|
|
+ uint32_t op_ret;
|
|
+ struct kcm_op_ctx *op_ctx;
|
|
+ struct tevent_context *ev;
|
|
+
|
|
+ struct sss_iobuf *cred_blob;
|
|
+};
|
|
+
|
|
+static void kcm_op_store_getbyname_done(struct tevent_req *subreq);
|
|
+static void kcm_op_store_done(struct tevent_req *subreq);
|
|
+
|
|
+static struct tevent_req *kcm_op_store_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_op_store_state *state = NULL;
|
|
+ errno_t ret;
|
|
+ const char *name;
|
|
+ size_t creds_len;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_store_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+ state->ev = ev;
|
|
+
|
|
+ ret = sss_iobuf_read_stringz(op_ctx->input, &name);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot unmarshall input name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Storing credentials for %s\n", name);
|
|
+
|
|
+ creds_len = sss_iobuf_get_size(op_ctx->input) - strlen(name) -1;
|
|
+ if (creds_len > KCM_REPLY_MAX) {
|
|
+ /* Protects against underflows and in general adds sanity */
|
|
+ ret = E2BIG;
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ state->cred_blob = sss_iobuf_init_empty(state,
|
|
+ creds_len,
|
|
+ creds_len);
|
|
+ if (state->cred_blob == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ ret = sss_iobuf_read(op_ctx->input,
|
|
+ creds_len,
|
|
+ sss_iobuf_get_data(state->cred_blob),
|
|
+ NULL);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot unmarshall input cred blob [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ subreq = kcm_ccdb_uuid_by_name_send(state, ev,
|
|
+ op_ctx->kcm_data->db,
|
|
+ op_ctx->client,
|
|
+ name);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_store_getbyname_done, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_op_store_getbyname_done(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_store_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_store_state);
|
|
+ uuid_t uuid;
|
|
+
|
|
+ ret = kcm_ccdb_uuid_by_name_recv(subreq, state, uuid);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get ccache by name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ subreq = kcm_ccdb_store_cred_blob_send(state, state->ev,
|
|
+ state->op_ctx->kcm_data->db,
|
|
+ state->op_ctx->client,
|
|
+ uuid,
|
|
+ state->cred_blob);
|
|
+ if (subreq == NULL) {
|
|
+ tevent_req_error(req, ENOMEM);
|
|
+ return;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_store_done, req);
|
|
+}
|
|
+
|
|
+static void kcm_op_store_done(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_store_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_store_state);
|
|
+
|
|
+ ret = kcm_ccdb_store_cred_blob_recv(subreq);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot store credentials [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ state->op_ret = EOK;
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+static errno_t kcm_op_store_recv(struct tevent_req *req,
|
|
+ uint32_t *_op_ret)
|
|
+{
|
|
+ KCM_OP_RET_FROM_TYPE(req, struct kcm_op_store_state, _op_ret);
|
|
+}
|
|
+
|
|
+/* (name) -> (princ) */
|
|
+static void kcm_op_get_principal_getbyname_done(struct tevent_req *subreq);
|
|
+
|
|
+static struct tevent_req *kcm_op_get_principal_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_op_common_state *state = NULL;
|
|
+ errno_t ret;
|
|
+ const char *name;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+
|
|
+ ret = sss_iobuf_read_stringz(op_ctx->input, &name);
|
|
+ if (ret != EOK) {
|
|
+ goto immediate;
|
|
+ }
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Requested principal %s\n", name);
|
|
+
|
|
+ subreq = kcm_ccdb_getbyname_send(state, ev,
|
|
+ op_ctx->kcm_data->db,
|
|
+ op_ctx->client,
|
|
+ name);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_get_principal_getbyname_done, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_op_get_principal_getbyname_done(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ struct kcm_ccache *cc;
|
|
+ krb5_principal princ;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_common_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_common_state);
|
|
+
|
|
+ ret = kcm_ccdb_getbyname_recv(subreq, state, &cc);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get ccache by name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (cc == NULL) {
|
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that name\n");
|
|
+ state->op_ret = ERR_NO_MATCHING_CREDS;
|
|
+ tevent_req_done(req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Marshall the principal to the reply */
|
|
+ princ = kcm_cc_get_client_principal(cc);
|
|
+ if (princ == NULL) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Credentials with no principal?\n");
|
|
+ tevent_req_error(req, EIO);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = sss_krb5_marshal_princ(princ, state->op_ctx->reply);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot marshall principal [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ state->op_ret = EOK;
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+/* (name) -> (uuid, ...) */
|
|
+static void kcm_op_get_cred_uuid_getbyname_done(struct tevent_req *subreq);
|
|
+
|
|
+static struct tevent_req *
|
|
+kcm_op_get_cred_uuid_list_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_op_common_state *state = NULL;
|
|
+ errno_t ret;
|
|
+ const char *name;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+
|
|
+ ret = sss_iobuf_read_stringz(op_ctx->input, &name);
|
|
+ if (ret != EOK) {
|
|
+ goto immediate;
|
|
+ }
|
|
+
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Returning UUID list for %s\n", name);
|
|
+
|
|
+ subreq = kcm_ccdb_getbyname_send(state, ev,
|
|
+ op_ctx->kcm_data->db,
|
|
+ op_ctx->client,
|
|
+ name);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_get_cred_uuid_getbyname_done, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_op_get_cred_uuid_getbyname_done(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ struct kcm_ccache *cc;
|
|
+ struct kcm_cred *crd;
|
|
+ uuid_t uuid;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_common_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_common_state);
|
|
+
|
|
+ ret = kcm_ccdb_getbyname_recv(subreq, state, &cc);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get ccache by name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (cc == NULL) {
|
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that UUID\n");
|
|
+ state->op_ret = ERR_NO_CREDS;
|
|
+ tevent_req_done(req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (crd = kcm_cc_get_cred(cc);
|
|
+ crd != NULL;
|
|
+ crd = kcm_cc_next_cred(crd)) {
|
|
+ ret = kcm_cred_get_uuid(crd, uuid);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "Credential has no UUID, skipping\n");
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ kcm_debug_uuid(uuid);
|
|
+
|
|
+ ret = sss_iobuf_write_len(state->op_ctx->reply,
|
|
+ uuid, UUID_BYTES);
|
|
+ if (ret != EOK) {
|
|
+ char uuid_errbuf[UUID_STR_SIZE];
|
|
+ uuid_parse(uuid_errbuf, uuid);
|
|
+ DEBUG(SSSDBG_MINOR_FAILURE,
|
|
+ "Cannot marshall UUID %s [%d]: %s\n",
|
|
+ uuid_errbuf, ret, sss_strerror(ret));
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ state->op_ret = EOK;
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+/* (name, uuid) -> (cred) */
|
|
+static void kcm_op_get_cred_by_uuid_getbyname_done(struct tevent_req *subreq);
|
|
+
|
|
+static struct tevent_req *
|
|
+kcm_op_get_cred_by_uuid_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_op_common_state *state = NULL;
|
|
+ errno_t ret;
|
|
+ const char *name;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+
|
|
+ ret = sss_iobuf_read_stringz(op_ctx->input, &name);
|
|
+ if (ret != EOK) {
|
|
+ goto immediate;
|
|
+ }
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Returning creds by UUID for %s\n", name);
|
|
+
|
|
+ subreq = kcm_ccdb_getbyname_send(state, ev,
|
|
+ op_ctx->kcm_data->db,
|
|
+ op_ctx->client,
|
|
+ name);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_get_cred_by_uuid_getbyname_done, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_op_get_cred_by_uuid_getbyname_done(struct tevent_req *subreq)
|
|
+{
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_common_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_common_state);
|
|
+ errno_t ret;
|
|
+ struct kcm_ccache *cc;
|
|
+ struct kcm_cred *crd;
|
|
+ uuid_t uuid_in;
|
|
+ uuid_t uuid;
|
|
+ struct sss_iobuf *cred_blob;
|
|
+
|
|
+ ret = kcm_ccdb_getbyname_recv(subreq, state, &cc);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get ccache by name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (cc == NULL) {
|
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that name\n");
|
|
+ state->op_ret = ERR_NO_MATCHING_CREDS;
|
|
+ tevent_req_done(req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = sss_iobuf_read_len(state->op_ctx->input,
|
|
+ UUID_BYTES, uuid_in);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot read input UUID [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (crd = kcm_cc_get_cred(cc);
|
|
+ crd != NULL;
|
|
+ crd = kcm_cc_next_cred(crd)) {
|
|
+ ret = kcm_cred_get_uuid(crd, uuid);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_MINOR_FAILURE,
|
|
+ "Cannot get UUID from creds, skipping\n");
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (uuid_compare(uuid, uuid_in) == 0) {
|
|
+ break;
|
|
+ }
|
|
+ kcm_debug_uuid(uuid);
|
|
+ }
|
|
+
|
|
+ if (crd == NULL) {
|
|
+ state->op_ret = ERR_KCM_CC_END;
|
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that UUID\n");
|
|
+ tevent_req_done(req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ cred_blob = kcm_cred_get_creds(crd);
|
|
+ if (cred_blob == NULL) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE, "Credentials lack the creds blob\n");
|
|
+ state->op_ret = ERR_NO_CREDS;
|
|
+ tevent_req_done(req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = sss_iobuf_write_len(state->op_ctx->reply,
|
|
+ sss_iobuf_get_data(cred_blob),
|
|
+ sss_iobuf_get_size(cred_blob));
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot write ccache blob [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ state->op_ret = EOK;
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+/* (name, flags, credtag) -> () */
|
|
+/* FIXME */
|
|
+static struct tevent_req *
|
|
+kcm_op_remove_cred_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct kcm_op_common_state *state = NULL;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+
|
|
+ state->op_ret = ERR_KCM_OP_NOT_IMPLEMENTED;
|
|
+ tevent_req_post(req, ev);
|
|
+ tevent_req_done(req);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+/* () -> (uuid, ...) */
|
|
+static void kcm_op_get_cache_uuid_list_done(struct tevent_req *subreq);
|
|
+
|
|
+static struct tevent_req *
|
|
+kcm_op_get_cache_uuid_list_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_op_common_state *state = NULL;
|
|
+ errno_t ret;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Returning full UUID list\n");
|
|
+
|
|
+ subreq = kcm_ccdb_list_send(state, ev,
|
|
+ op_ctx->kcm_data->db,
|
|
+ op_ctx->client);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_get_cache_uuid_list_done, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_op_get_cache_uuid_list_done(struct tevent_req *subreq)
|
|
+{
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_common_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_common_state);
|
|
+ errno_t ret;
|
|
+ uuid_t *uuid_list;
|
|
+
|
|
+ ret = kcm_ccdb_list_recv(subreq, state, &uuid_list);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot list the ccache DB [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (uuid_list == NULL || uuid_list[0] == NULL) {
|
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "Nothing to list\n");
|
|
+ state->op_ret = ERR_NO_MATCHING_CREDS;
|
|
+ tevent_req_done(req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (int i = 0;
|
|
+ uuid_is_null(uuid_list[i]) == false;
|
|
+ i++) {
|
|
+ kcm_debug_uuid(uuid_list[i]);
|
|
+
|
|
+ ret = sss_iobuf_write_len(state->op_ctx->reply,
|
|
+ uuid_list[i],
|
|
+ UUID_BYTES);
|
|
+ if (ret != EOK) {
|
|
+ char uuid_errbuf[UUID_STR_SIZE];
|
|
+ uuid_parse(uuid_errbuf, uuid_list[i]);
|
|
+ DEBUG(SSSDBG_MINOR_FAILURE,
|
|
+ "Cannot marshall UUID %s [%d]: %s\n",
|
|
+ uuid_errbuf, ret, sss_strerror(ret));
|
|
+ tevent_req_done(req);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+/* (uuid) -> (name) */
|
|
+static void kcm_op_get_cache_by_uuid_done(struct tevent_req *subreq);
|
|
+
|
|
+static struct tevent_req *
|
|
+kcm_op_get_cache_by_uuid_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_op_common_state *state = NULL;
|
|
+ errno_t ret;
|
|
+ uuid_t uuid_in;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Retrieving cache by UUID\n");
|
|
+
|
|
+ ret = sss_iobuf_read_len(op_ctx->input,
|
|
+ UUID_BYTES, uuid_in);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot read input UUID [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto immediate;
|
|
+ }
|
|
+ kcm_debug_uuid(uuid_in);
|
|
+
|
|
+ subreq = kcm_ccdb_getbyuuid_send(state, ev,
|
|
+ op_ctx->kcm_data->db,
|
|
+ op_ctx->client,
|
|
+ uuid_in);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_get_cache_by_uuid_done, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_op_get_cache_by_uuid_done(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ struct kcm_ccache *cc;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_common_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_common_state);
|
|
+ const char *name;
|
|
+
|
|
+ ret = kcm_ccdb_getbyuuid_recv(subreq, state, &cc);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get ccahe by UUID [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (cc == NULL) {
|
|
+ state->op_ret = ERR_KCM_CC_END;
|
|
+ tevent_req_done(req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ name = kcm_cc_get_name(cc);
|
|
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Found %s by UUID\n", name);
|
|
+
|
|
+ ret = sss_iobuf_write_stringz(state->op_ctx->reply,
|
|
+ name);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot write output name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ state->op_ret = EOK;
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+/* () -> (name) */
|
|
+struct kcm_op_get_default_ccache_state {
|
|
+ uint32_t op_ret;
|
|
+ struct kcm_op_ctx *op_ctx;
|
|
+ struct tevent_context *ev;
|
|
+
|
|
+ const char *name;
|
|
+};
|
|
+
|
|
+static void kcm_op_get_get_default_done(struct tevent_req *subreq);
|
|
+static void kcm_op_get_default_ccache_byuuid_done(struct tevent_req *subreq);
|
|
+static void kcm_op_get_default_ccache_list_done(struct tevent_req *subreq);
|
|
+static errno_t
|
|
+kcm_op_get_default_ccache_reply_step(struct kcm_op_get_default_ccache_state *state);
|
|
+
|
|
+static struct tevent_req *
|
|
+kcm_op_get_default_ccache_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_op_get_default_ccache_state *state = NULL;
|
|
+ errno_t ret;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state,
|
|
+ struct kcm_op_get_default_ccache_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+ state->ev = ev;
|
|
+
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Getting client's default ccache\n");
|
|
+
|
|
+ subreq = kcm_ccdb_get_default_send(state, ev,
|
|
+ state->op_ctx->kcm_data->db,
|
|
+ state->op_ctx->client);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_get_get_default_done, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_op_get_get_default_done(struct tevent_req *subreq)
|
|
+{
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
|
|
+ struct kcm_op_get_default_ccache_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_get_default_ccache_state);
|
|
+ errno_t ret;
|
|
+ uuid_t dfl_uuid;
|
|
+
|
|
+ ret = kcm_ccdb_get_default_recv(subreq, &dfl_uuid);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get default ccache [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (uuid_is_null(dfl_uuid) == true) {
|
|
+ /* No cache marked as default -- get an existing ccache for ID
|
|
+ * and treat the default as simply the first one
|
|
+ */
|
|
+ subreq = kcm_ccdb_list_send(state, state->ev,
|
|
+ state->op_ctx->kcm_data->db,
|
|
+ state->op_ctx->client);
|
|
+ if (subreq == NULL) {
|
|
+ tevent_req_error(req, ENOMEM);
|
|
+ return;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_get_default_ccache_list_done, req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Existing default */
|
|
+ subreq = kcm_ccdb_name_by_uuid_send(state,
|
|
+ state->ev,
|
|
+ state->op_ctx->kcm_data->db,
|
|
+ state->op_ctx->client,
|
|
+ dfl_uuid);
|
|
+ if (subreq == NULL) {
|
|
+ tevent_req_error(req, ENOMEM);
|
|
+ return;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_get_default_ccache_byuuid_done, req);
|
|
+ return;
|
|
+}
|
|
+
|
|
+static void kcm_op_get_default_ccache_byuuid_done(struct tevent_req *subreq)
|
|
+{
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
|
|
+ struct kcm_op_get_default_ccache_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_get_default_ccache_state);
|
|
+ errno_t ret;
|
|
+
|
|
+ ret = kcm_ccdb_name_by_uuid_recv(subreq, state, &state->name);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get ccahe by UUID [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = kcm_op_get_default_ccache_reply_step(state);
|
|
+ if (ret != EOK) {
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+static void kcm_op_get_default_ccache_list_done(struct tevent_req *subreq)
|
|
+{
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);
|
|
+ struct kcm_op_get_default_ccache_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_get_default_ccache_state);
|
|
+ errno_t ret;
|
|
+ uuid_t *uuid_list;
|
|
+
|
|
+ ret = kcm_ccdb_list_recv(subreq, state, &uuid_list);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot list ccaches [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (uuid_list == NULL || uuid_is_null(uuid_list[0])) {
|
|
+ /* No cache at all, just send back a reply */
|
|
+ ret = kcm_op_get_default_ccache_reply_step(state);
|
|
+ if (ret != EOK) {
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ tevent_req_done(req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Otherwise resolve the first cache and use it as a default */
|
|
+ subreq = kcm_ccdb_name_by_uuid_send(state,
|
|
+ state->ev,
|
|
+ state->op_ctx->kcm_data->db,
|
|
+ state->op_ctx->client,
|
|
+ uuid_list[0]);
|
|
+ if (subreq == NULL) {
|
|
+ tevent_req_error(req, ENOMEM);
|
|
+ return;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_get_default_ccache_byuuid_done, req);
|
|
+ return;
|
|
+}
|
|
+
|
|
+static errno_t
|
|
+kcm_op_get_default_ccache_reply_step(struct kcm_op_get_default_ccache_state *state)
|
|
+{
|
|
+ errno_t ret;
|
|
+
|
|
+ if (state->name == NULL) {
|
|
+ state->name = talloc_asprintf(state,
|
|
+ "%"SPRIuid,
|
|
+ cli_creds_get_uid(state->op_ctx->client));
|
|
+ if (state->name == NULL) {
|
|
+ return ENOMEM;
|
|
+ }
|
|
+ }
|
|
+ DEBUG(SSSDBG_TRACE_INTERNAL, "The default ccache is %s\n", state->name);
|
|
+
|
|
+ ret = sss_iobuf_write_stringz(state->op_ctx->reply, state->name);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot write output name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return EOK;
|
|
+}
|
|
+
|
|
+static errno_t kcm_op_get_default_ccache_recv(struct tevent_req *req,
|
|
+ uint32_t *_op_ret)
|
|
+{
|
|
+ KCM_OP_RET_FROM_TYPE(req, struct kcm_op_get_default_ccache_state, _op_ret);
|
|
+}
|
|
+
|
|
+/* (name) -> () */
|
|
+static void kcm_op_set_default_ccache_getbyname_done(struct tevent_req *subreq);
|
|
+static void kcm_op_set_default_done(struct tevent_req *subreq);
|
|
+
|
|
+static struct tevent_req *
|
|
+kcm_op_set_default_ccache_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_op_common_state *state = NULL;
|
|
+ errno_t ret;
|
|
+ const char *name;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+ state->ev = ev;
|
|
+
|
|
+ ret = sss_iobuf_read_stringz(op_ctx->input, &name);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
+ "Cannot read input name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto immediate;
|
|
+ }
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Setting default ccache %s\n", name);
|
|
+
|
|
+ subreq = kcm_ccdb_uuid_by_name_send(state, ev,
|
|
+ op_ctx->kcm_data->db,
|
|
+ op_ctx->client,
|
|
+ name);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_set_default_ccache_getbyname_done, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_op_set_default_ccache_getbyname_done(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_common_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_common_state);
|
|
+ uuid_t dfl_uuid;
|
|
+
|
|
+ ret = kcm_ccdb_uuid_by_name_recv(subreq, state, dfl_uuid);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get ccache by name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ subreq = kcm_ccdb_set_default_send(state,
|
|
+ state->ev,
|
|
+ state->op_ctx->kcm_data->db,
|
|
+ state->op_ctx->client,
|
|
+ dfl_uuid);
|
|
+ if (subreq == NULL) {
|
|
+ tevent_req_error(req, ENOMEM);
|
|
+ return;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_set_default_done, req);
|
|
+ return;
|
|
+}
|
|
+
|
|
+static void kcm_op_set_default_done(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_common_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_common_state);
|
|
+
|
|
+ ret = kcm_ccdb_set_default_recv(subreq);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot set default ccache %d: %s\n", ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ state->op_ret = EOK;
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+/* (name) -> (offset) */
|
|
+static void kcm_op_get_kdc_offset_getbyname_done(struct tevent_req *subreq);
|
|
+
|
|
+static struct tevent_req *
|
|
+kcm_op_get_kdc_offset_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_op_common_state *state = NULL;
|
|
+ errno_t ret;
|
|
+ const char *name;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+
|
|
+ ret = sss_iobuf_read_stringz(op_ctx->input, &name);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot read input name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto immediate;
|
|
+ }
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Requested offset for principal %s\n", name);
|
|
+
|
|
+ subreq = kcm_ccdb_getbyname_send(state, ev,
|
|
+ op_ctx->kcm_data->db,
|
|
+ op_ctx->client,
|
|
+ name);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_get_kdc_offset_getbyname_done, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_op_get_kdc_offset_getbyname_done(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ struct kcm_ccache *cc;
|
|
+ int32_t offset;
|
|
+ int32_t offset_be;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_common_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_common_state);
|
|
+
|
|
+ ret = kcm_ccdb_getbyname_recv(subreq, state, &cc);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get matching ccache [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (cc == NULL) {
|
|
+ DEBUG(SSSDBG_MINOR_FAILURE, "No matching credentials\n");
|
|
+ state->op_ret = ERR_NO_MATCHING_CREDS;
|
|
+ tevent_req_done(req);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ offset = kcm_cc_get_offset(cc);
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "KDC offset: %"PRIu32"\n", offset);
|
|
+
|
|
+ offset_be = htobe32(offset);
|
|
+ ret = sss_iobuf_write_int32(state->op_ctx->reply, offset_be);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot write KDC offset [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ state->op_ret = EOK;
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+/* (name, offset) -> () */
|
|
+/* () -> (name) */
|
|
+struct kcm_op_set_kdc_offset_state {
|
|
+ uint32_t op_ret;
|
|
+ struct kcm_op_ctx *op_ctx;
|
|
+ struct tevent_context *ev;
|
|
+};
|
|
+
|
|
+static void kcm_op_set_kdc_offset_getbyname_done(struct tevent_req *subreq);
|
|
+static void kcm_op_set_kdc_offset_mod_done(struct tevent_req *subreq);
|
|
+
|
|
+static struct tevent_req *
|
|
+kcm_op_set_kdc_offset_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_op_ctx *op_ctx)
|
|
+{
|
|
+ struct tevent_req *req = NULL;
|
|
+ struct tevent_req *subreq = NULL;
|
|
+ struct kcm_op_set_kdc_offset_state *state = NULL;
|
|
+ errno_t ret;
|
|
+ const char *name;
|
|
+
|
|
+ req = tevent_req_create(mem_ctx, &state, struct kcm_op_set_kdc_offset_state);
|
|
+ if (req == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ state->op_ctx = op_ctx;
|
|
+ state->ev = ev;
|
|
+
|
|
+ ret = sss_iobuf_read_stringz(op_ctx->input, &name);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot read input name [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ goto immediate;
|
|
+ }
|
|
+ DEBUG(SSSDBG_TRACE_LIBS, "Setting offset for principal %s\n", name);
|
|
+
|
|
+ subreq = kcm_ccdb_uuid_by_name_send(state, ev,
|
|
+ op_ctx->kcm_data->db,
|
|
+ op_ctx->client,
|
|
+ name);
|
|
+ if (subreq == NULL) {
|
|
+ ret = ENOMEM;
|
|
+ goto immediate;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_set_kdc_offset_getbyname_done, req);
|
|
+ return req;
|
|
+
|
|
+immediate:
|
|
+ tevent_req_error(req, ret);
|
|
+ tevent_req_post(req, ev);
|
|
+ return req;
|
|
+}
|
|
+
|
|
+static void kcm_op_set_kdc_offset_getbyname_done(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ struct kcm_mod_ctx *mod_ctx;
|
|
+ int32_t offset_be;
|
|
+ uuid_t uuid;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_set_kdc_offset_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_set_kdc_offset_state);
|
|
+
|
|
+ ret = kcm_ccdb_uuid_by_name_recv(subreq, state, uuid);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot get matching ccache [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = sss_iobuf_read_int32(state->op_ctx->input, &offset_be);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot read KDC offset [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ mod_ctx = talloc(state, struct kcm_mod_ctx);
|
|
+ if (mod_ctx == NULL) {
|
|
+ tevent_req_error(req, ENOMEM);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ kcm_mod_ctx_clear(mod_ctx);
|
|
+ mod_ctx->kdc_offset = be32toh(offset_be);
|
|
+
|
|
+ subreq = kcm_ccdb_mod_cc_send(state,
|
|
+ state->ev,
|
|
+ state->op_ctx->kcm_data->db,
|
|
+ state->op_ctx->client,
|
|
+ uuid,
|
|
+ mod_ctx);
|
|
+ if (subreq == NULL) {
|
|
+ tevent_req_error(req, ENOMEM);
|
|
+ return;
|
|
+ }
|
|
+ tevent_req_set_callback(subreq, kcm_op_set_kdc_offset_mod_done, req);
|
|
+}
|
|
+
|
|
+static void kcm_op_set_kdc_offset_mod_done(struct tevent_req *subreq)
|
|
+{
|
|
+ errno_t ret;
|
|
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
+ struct tevent_req);
|
|
+ struct kcm_op_set_kdc_offset_state *state = tevent_req_data(req,
|
|
+ struct kcm_op_set_kdc_offset_state);
|
|
+
|
|
+ ret = kcm_ccdb_mod_cc_recv(subreq);
|
|
+ talloc_zfree(subreq);
|
|
+ if (ret != EOK) {
|
|
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
+ "Cannot modify ccache [%d]: %s\n",
|
|
+ ret, sss_strerror(ret));
|
|
+ tevent_req_error(req, ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ state->op_ret = EOK;
|
|
+ tevent_req_done(req);
|
|
+}
|
|
+
|
|
+static errno_t kcm_op_set_kdc_offset_recv(struct tevent_req *req,
|
|
+ uint32_t *_op_ret)
|
|
+{
|
|
+ KCM_OP_RET_FROM_TYPE(req, struct kcm_op_set_kdc_offset_state, _op_ret);
|
|
+}
|
|
+
|
|
+static struct kcm_op kcm_optable[] = {
|
|
+ { "NOOP", NULL, NULL },
|
|
+ { "GET_NAME", NULL, NULL },
|
|
+ { "RESOLVE", NULL, NULL },
|
|
+ { "GEN_NEW", kcm_op_gen_new_send, NULL },
|
|
+ { "INITIALIZE", kcm_op_initialize_send, kcm_op_initialize_recv },
|
|
+ { "DESTROY", kcm_op_destroy_send, NULL },
|
|
+ { "STORE", kcm_op_store_send, kcm_op_store_recv },
|
|
+ { "RETRIEVE", NULL, NULL },
|
|
+ { "GET_PRINCIPAL", kcm_op_get_principal_send, NULL },
|
|
+ { "GET_CRED_UUID_LIST", kcm_op_get_cred_uuid_list_send, NULL },
|
|
+ { "GET_CRED_BY_UUID", kcm_op_get_cred_by_uuid_send, NULL },
|
|
+ { "REMOVE_CRED", kcm_op_remove_cred_send, NULL },
|
|
+ { "SET_FLAGS", NULL, NULL },
|
|
+ { "CHOWN", NULL, NULL },
|
|
+ { "CHMOD", NULL, NULL },
|
|
+ { "GET_INITIAL_TICKET", NULL, NULL },
|
|
+ { "GET_TICKET", NULL, NULL },
|
|
+ { "MOVE_CACHE", NULL, NULL },
|
|
+ { "GET_CACHE_UUID_LIST", kcm_op_get_cache_uuid_list_send, NULL },
|
|
+ { "GET_CACHE_BY_UUID", kcm_op_get_cache_by_uuid_send, NULL },
|
|
+ { "GET_DEFAULT_CACHE", kcm_op_get_default_ccache_send, kcm_op_get_default_ccache_recv },
|
|
+ { "SET_DEFAULT_CACHE", kcm_op_set_default_ccache_send, NULL },
|
|
+ { "GET_KDC_OFFSET", kcm_op_get_kdc_offset_send, NULL },
|
|
+ { "SET_KDC_OFFSET", kcm_op_set_kdc_offset_send, kcm_op_set_kdc_offset_recv },
|
|
+ { "ADD_NTLM_CRED", NULL, NULL },
|
|
+ { "HAVE_NTLM_CRED", NULL, NULL },
|
|
+ { "DEL_NTLM_CRED", NULL, NULL },
|
|
+ { "DO_NTLM_AUTH", NULL, NULL },
|
|
+ { "GET_NTLM_USER_LIST", NULL, NULL },
|
|
+
|
|
+ { NULL, NULL, NULL }
|
|
+};
|
|
+
|
|
+struct kcm_op *kcm_get_opt(uint16_t opcode)
|
|
+{
|
|
+ struct kcm_op *op;
|
|
+
|
|
+ DEBUG(SSSDBG_TRACE_INTERNAL,
|
|
+ "The client requested operation %"PRIu16"\n", opcode);
|
|
+
|
|
+ if (opcode >= KCM_OP_SENTINEL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ op = &kcm_optable[opcode];
|
|
+ if (op->fn_recv == NULL) {
|
|
+ op->fn_recv = kcm_op_common_recv;
|
|
+ }
|
|
+ return op;
|
|
+}
|
|
+
|
|
+const char *kcm_opt_name(struct kcm_op *op)
|
|
+{
|
|
+ if (op == NULL || op->name == NULL) {
|
|
+ return "Unknown operation";
|
|
+ }
|
|
+
|
|
+ return op->name;
|
|
+}
|
|
diff --git a/src/responder/kcm/kcmsrv_ops.h b/src/responder/kcm/kcmsrv_ops.h
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..8e6feaf56a10b73c8b6375aea9ef26c392b5b492
|
|
--- /dev/null
|
|
+++ b/src/responder/kcm/kcmsrv_ops.h
|
|
@@ -0,0 +1,45 @@
|
|
+/*
|
|
+ SSSD
|
|
+
|
|
+ KCM Server - private header file
|
|
+
|
|
+ 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/>.
|
|
+*/
|
|
+
|
|
+#ifndef __KCMSRV_OPS_H__
|
|
+#define __KCMSRV_OPS_H__
|
|
+
|
|
+#include "config.h"
|
|
+
|
|
+#include <sys/types.h>
|
|
+#include "util/sss_iobuf.h"
|
|
+#include "responder/kcm/kcmsrv_pvt.h"
|
|
+
|
|
+struct kcm_op;
|
|
+struct kcm_op *kcm_get_opt(uint16_t opcode);
|
|
+const char *kcm_opt_name(struct kcm_op *op);
|
|
+
|
|
+struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_context *ev,
|
|
+ struct kcm_resp_ctx *kcm_data,
|
|
+ struct cli_creds *client,
|
|
+ struct kcm_data *input,
|
|
+ struct kcm_op *op);
|
|
+errno_t kcm_cmd_recv(TALLOC_CTX *mem_ctx,
|
|
+ struct tevent_req *req,
|
|
+ struct sss_iobuf **_reply);
|
|
+
|
|
+#endif /* __KCMSRV_OPS_H__ */
|
|
--
|
|
2.12.2
|
|
|