Blame SOURCES/0023-KCM-request-parsing-and-sending-a-reply.patch

ecf709
From aface2604c53db717299ac3dfe798dfd0c540f99 Mon Sep 17 00:00:00 2001
ecf709
From: Jakub Hrozek <jhrozek@redhat.com>
ecf709
Date: Fri, 23 Sep 2016 14:00:10 +0200
ecf709
Subject: [PATCH 23/36] KCM: request parsing and sending a reply
ecf709
MIME-Version: 1.0
ecf709
Content-Type: text/plain; charset=UTF-8
ecf709
Content-Transfer-Encoding: 8bit
ecf709
ecf709
Implements parsing the KCM client request into per-client buffers and
ecf709
sending a response for both the failure case and for success.
ecf709
ecf709
The protocol is documented at:
ecf709
    http://k5wiki.kerberos.org/wiki/Projects/KCM_client
ecf709
ecf709
Several places don't use the sss_iobuf structure, because they don't
ecf709
parse variable-length data from the buffer and it's much more efficient
ecf709
to just allocate the needed request and reply structure on the stack.
ecf709
ecf709
Reviewed-by: Michal Židek <mzidek@redhat.com>
ecf709
Reviewed-by: Simo Sorce <simo@redhat.com>
ecf709
---
ecf709
 src/responder/kcm/kcmsrv_cmd.c | 467 ++++++++++++++++++++++++++++++++++++++++-
ecf709
 src/responder/kcm/kcmsrv_pvt.h |  21 +-
ecf709
 2 files changed, 474 insertions(+), 14 deletions(-)
ecf709
ecf709
diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c
ecf709
index e9a03cbd41169c93e00b0630dc1e05e205881ec9..cbf70353730d8a4e03d8f75c97395f4ef007e77f 100644
ecf709
--- a/src/responder/kcm/kcmsrv_cmd.c
ecf709
+++ b/src/responder/kcm/kcmsrv_cmd.c
ecf709
@@ -19,14 +19,430 @@
ecf709
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
ecf709
 */
ecf709
 
ecf709
+#include <krb5/krb5.h>
ecf709
+
ecf709
 #include "config.h"
ecf709
 #include "util/util.h"
ecf709
+#include "util/sss_iobuf.h"
ecf709
 #include "responder/common/responder.h"
ecf709
+#include "responder/kcm/kcmsrv_pvt.h"
ecf709
+#include "responder/kcm/kcm.h"
ecf709
 
ecf709
-struct kcm_proto_ctx {
ecf709
-    void *unused;
ecf709
+/* The first four bytes of a message is always the size */
ecf709
+#define KCM_MSG_LEN_SIZE 4
ecf709
+
ecf709
+/* The return code is 32bits */
ecf709
+#define KCM_RETCODE_SIZE 4
ecf709
+
ecf709
+/* The maximum length of a request or reply as defined by the RPC
ecf709
+ * protocol. This is the same constant size as MIT KRB5 uses
ecf709
+ */
ecf709
+#define KCM_PACKET_MAX_SIZE 2048
ecf709
+
ecf709
+/* KCM operation, its raw input and raw output and result */
ecf709
+struct kcm_op_io {
ecf709
+    struct kcm_op *op;
ecf709
+    struct kcm_data request;
ecf709
+    struct sss_iobuf *reply;
ecf709
+};
ecf709
+
ecf709
+/**
ecf709
+ * KCM IO-vector operations
ecf709
+ */
ecf709
+struct kcm_iovec {
ecf709
+    /* We don't use iovec b/c void pointers don't allow for
ecf709
+     * pointer arithmetics and it's convenient to keep track
ecf709
+     * of processed bytes
ecf709
+     */
ecf709
+    uint8_t *kiov_base;
ecf709
+    size_t kiov_len;
ecf709
+    size_t nprocessed;
ecf709
+};
ecf709
+
ecf709
+static errno_t kcm_iovec_op(int fd, struct kcm_iovec *kiov, bool do_read)
ecf709
+{
ecf709
+    ssize_t len;
ecf709
+    struct iovec iov[1];
ecf709
+
ecf709
+    iov[0].iov_base = kiov->kiov_base + kiov->nprocessed;
ecf709
+    iov[0].iov_len = kiov->kiov_len - kiov->nprocessed;
ecf709
+    if (iov[0].iov_len == 0) {
ecf709
+        /* This iovec is full (read) or depleted (write), proceed to the next one */
ecf709
+        return EOK;
ecf709
+    }
ecf709
+
ecf709
+    if (do_read) {
ecf709
+        len = readv(fd, iov, 1);
ecf709
+    } else {
ecf709
+        len = writev(fd, iov, 1);
ecf709
+    }
ecf709
+
ecf709
+    if (len == -1) {
ecf709
+        if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
ecf709
+            return EAGAIN;
ecf709
+        } else {
ecf709
+            return errno;
ecf709
+        }
ecf709
+    }
ecf709
+
ecf709
+    if (len == 0) {
ecf709
+        /* Read event on fd that doesn't yield data? error */
ecf709
+        return ENODATA;
ecf709
+    }
ecf709
+
ecf709
+    /* Decrease the amount of available free space in the iovec */
ecf709
+    kiov->nprocessed += len;
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+static errno_t kcm_read_iovec(int fd, struct kcm_iovec *kiov)
ecf709
+{
ecf709
+    return kcm_iovec_op(fd, kiov, true);
ecf709
+}
ecf709
+
ecf709
+static errno_t kcm_write_iovec(int fd, struct kcm_iovec *kiov)
ecf709
+{
ecf709
+    return kcm_iovec_op(fd, kiov, false);
ecf709
+}
ecf709
+
ecf709
+/**
ecf709
+ * Parsing KCM input
ecf709
+ *
ecf709
+ * The request is received as two IO vectors:
ecf709
+ *
ecf709
+ * first iovec:
ecf709
+ *  length                      32-bit big-endian integer
ecf709
+ *
ecf709
+ * second iovec:
ecf709
+ *  major protocol number       8-bit big-endian integer
ecf709
+ *  minor protocol number       8-bit big-endian integer
ecf709
+ *  opcode                      16-bit big-endian integer
ecf709
+ *  message payload             buffer
ecf709
+ */
ecf709
+struct kcm_reqbuf {
ecf709
+    uint8_t lenbuf[KCM_MSG_LEN_SIZE];
ecf709
+    struct kcm_iovec v_len;
ecf709
+
ecf709
+    /* Includes the major, minor versions etc */
ecf709
+    uint8_t msgbuf[KCM_PACKET_MAX_SIZE];
ecf709
+    struct kcm_iovec v_msg;
ecf709
+};
ecf709
+
ecf709
+static errno_t kcm_input_parse(struct kcm_reqbuf *reqbuf,
ecf709
+                               struct kcm_op_io *op_io)
ecf709
+{
ecf709
+    size_t lc = 0;
ecf709
+    size_t mc = 0;
ecf709
+    uint16_t opcode = 0;
ecf709
+    uint16_t opcode_be = 0;
ecf709
+    uint32_t len_be = 0;
ecf709
+    uint32_t msglen;
ecf709
+    uint8_t proto_maj = 0;
ecf709
+    uint8_t proto_min = 0;
ecf709
+
ecf709
+    /* The first 4 bytes before the payload is message length */
ecf709
+    SAFEALIGN_COPY_UINT32_CHECK(&len_be,
ecf709
+                                reqbuf->v_len.kiov_base,
ecf709
+                                reqbuf->v_len.kiov_len,
ecf709
+                                &lc);
ecf709
+    msglen = be32toh(len_be);
ecf709
+    DEBUG(SSSDBG_TRACE_LIBS,
ecf709
+          "Received message with length %"PRIu32"\n", msglen);
ecf709
+
ecf709
+    if (msglen == 0) {
ecf709
+        DEBUG(SSSDBG_CRIT_FAILURE, "Illegal zero-length message\n");
ecf709
+        return EBADMSG;
ecf709
+    }
ecf709
+
ecf709
+    if (msglen != reqbuf->v_msg.nprocessed) {
ecf709
+        DEBUG(SSSDBG_CRIT_FAILURE,
ecf709
+              "Sender claims the message is %"PRIu32" bytes, "
ecf709
+              "but received %zu\n",
ecf709
+              msglen, reqbuf->v_msg.nprocessed);
ecf709
+        return EBADMSG;
ecf709
+    }
ecf709
+
ecf709
+    /* First 16 bits are 8 bit major and 8bit major protocol version */
ecf709
+    SAFEALIGN_COPY_UINT8_CHECK(&proto_maj,
ecf709
+                               reqbuf->v_msg.kiov_base + mc,
ecf709
+                               reqbuf->v_msg.kiov_len,
ecf709
+                               &mc);
ecf709
+    SAFEALIGN_COPY_UINT8_CHECK(&proto_min,
ecf709
+                               reqbuf->v_msg.kiov_base + mc,
ecf709
+                               reqbuf->v_msg.kiov_len,
ecf709
+                               &mc);
ecf709
+
ecf709
+    if (proto_maj != KCM_PROTOCOL_VERSION_MAJOR) {
ecf709
+        DEBUG(SSSDBG_CRIT_FAILURE,
ecf709
+              "Expected major version %d, got %"PRIu16"\n",
ecf709
+              KCM_PROTOCOL_VERSION_MAJOR, (uint16_t) proto_maj);
ecf709
+        return ERR_KCM_MALFORMED_IN_PKT;
ecf709
+    }
ecf709
+
ecf709
+    if (proto_min != KCM_PROTOCOL_VERSION_MINOR) {
ecf709
+        DEBUG(SSSDBG_CRIT_FAILURE,
ecf709
+              "Expected minor version %d, got %"PRIu16"\n",
ecf709
+              KCM_PROTOCOL_VERSION_MINOR, (uint16_t) proto_maj);
ecf709
+        return ERR_KCM_MALFORMED_IN_PKT;
ecf709
+    }
ecf709
+
ecf709
+    SAFEALIGN_COPY_UINT16_CHECK(&opcode_be,
ecf709
+                                reqbuf->v_msg.kiov_base + mc,
ecf709
+                                reqbuf->v_msg.kiov_len,
ecf709
+                                &mc);
ecf709
+
ecf709
+    opcode = be16toh(opcode_be);
ecf709
+    DEBUG(SSSDBG_TRACE_LIBS, "Received operation code %"PRIu16"\n", opcode);
ecf709
+
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+/**
ecf709
+ * Constructing a reply for failure and success
ecf709
+ *
ecf709
+ * The reply consists of three IO vectors:
ecf709
+ * 1) length iovec:
ecf709
+ *  length:     32-bit big-endian
ecf709
+ *
ecf709
+ * 2) return code iovec:
ecf709
+ *  retcode:    32-bit big-endian. Non-zero on failure in the KCM server,
ecf709
+ *              zero if the KCM operation ran (even if the operation itself
ecf709
+ *              failed)
ecf709
+ *
ecf709
+ * 3) reply iovec
ecf709
+ *  message:    buffer, first 32-bits of the buffer is the return code of
ecf709
+ *              the KCM operation, the rest depends on the operation itself.
ecf709
+ *              The buffer's length is specified by the first integer in the
ecf709
+ *              reply (very intuitive, right?)
ecf709
+ *
ecf709
+ *  The client always reads the length and return code iovectors. However, the
ecf709
+ *  client reads the reply iovec only if retcode is 0 in the return code iovector
ecf709
+ *  (see kcmio_unix_socket_read() in the MIT tree)
ecf709
+ */
ecf709
+struct kcm_repbuf {
ecf709
+    uint8_t lenbuf[KCM_MSG_LEN_SIZE];
ecf709
+    struct kcm_iovec v_len;
ecf709
+
ecf709
+    uint8_t rcbuf[KCM_RETCODE_SIZE];
ecf709
+    struct kcm_iovec v_rc;
ecf709
+
ecf709
+    uint8_t msgbuf[KCM_PACKET_MAX_SIZE];
ecf709
+    struct kcm_iovec v_msg;
ecf709
+};
ecf709
+
ecf709
+static errno_t kcm_failbuf_construct(errno_t ret,
ecf709
+                                     struct kcm_repbuf *repbuf)
ecf709
+{
ecf709
+    size_t c;
ecf709
+
ecf709
+    c = 0;
ecf709
+    SAFEALIGN_SETMEM_UINT32(repbuf->lenbuf, 0, &c);
ecf709
+    c = 0;
ecf709
+    SAFEALIGN_SETMEM_UINT32(repbuf->rcbuf, htobe32(ret), &c);
ecf709
+
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+/**
ecf709
+ * Construct a reply buffer and send it to the KCM client
ecf709
+ */
ecf709
+static void kcm_reply_error(struct cli_ctx *cctx,
ecf709
+                            errno_t retcode,
ecf709
+                            struct kcm_repbuf *repbuf)
ecf709
+{
ecf709
+    errno_t ret;
ecf709
+    krb5_error_code kerr;
ecf709
+
ecf709
+    DEBUG(SSSDBG_OP_FAILURE,
ecf709
+          "KCM operation returs failure [%d]: %s\n",
ecf709
+          retcode, sss_strerror(retcode));
ecf709
+    kerr = sss2krb5_error(retcode);
ecf709
+
ecf709
+    ret = kcm_failbuf_construct(kerr, repbuf);
ecf709
+    if (ret != EOK) {
ecf709
+        /* If we can't construct the reply buffer, just terminate the client */
ecf709
+        talloc_free(cctx);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    TEVENT_FD_WRITEABLE(cctx->cfde);
ecf709
+}
ecf709
+
ecf709
+/**
ecf709
+ * Request-reply dispatcher
ecf709
+ */
ecf709
+struct kcm_req_ctx {
ecf709
+    /* client context owns per-client buffers including this one */
ecf709
+    struct cli_ctx *cctx;
ecf709
+
ecf709
+    /* raw IO buffers */
ecf709
+    struct kcm_reqbuf reqbuf;
ecf709
+    struct kcm_repbuf repbuf;
ecf709
+
ecf709
+    /* long-lived responder structures */
ecf709
+    struct kcm_ctx *kctx;
ecf709
+
ecf709
+    struct kcm_op_io op_io;
ecf709
 };
ecf709
 
ecf709
+static errno_t kcm_recv_data(int fd, struct kcm_reqbuf *reqbuf)
ecf709
+{
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    ret = kcm_read_iovec(fd, &reqbuf->v_len);
ecf709
+    if (ret != EOK) {
ecf709
+        return ret;
ecf709
+    }
ecf709
+
ecf709
+    ret = kcm_read_iovec(fd, &reqbuf->v_msg);
ecf709
+    if (ret != EOK) {
ecf709
+        return ret;
ecf709
+    }
ecf709
+
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+static struct kcm_req_ctx *kcm_new_req(TALLOC_CTX *mem_ctx,
ecf709
+                                       struct cli_ctx *cctx,
ecf709
+                                       struct kcm_ctx *kctx)
ecf709
+{
ecf709
+    struct kcm_req_ctx *req;
ecf709
+
ecf709
+    req = talloc_zero(cctx, struct kcm_req_ctx);
ecf709
+    if (req == NULL) {
ecf709
+        return NULL;
ecf709
+    }
ecf709
+
ecf709
+    req->reqbuf.v_len.kiov_base = req->reqbuf.lenbuf;
ecf709
+    req->reqbuf.v_len.kiov_len = KCM_MSG_LEN_SIZE;
ecf709
+
ecf709
+    req->reqbuf.v_msg.kiov_base = req->reqbuf.msgbuf;
ecf709
+    req->reqbuf.v_msg.kiov_len = KCM_PACKET_MAX_SIZE;
ecf709
+
ecf709
+    req->repbuf.v_len.kiov_base = req->repbuf.lenbuf;
ecf709
+    req->repbuf.v_len.kiov_len = KCM_MSG_LEN_SIZE;
ecf709
+
ecf709
+    req->repbuf.v_rc.kiov_base = req->repbuf.rcbuf;
ecf709
+    req->repbuf.v_rc.kiov_len = KCM_RETCODE_SIZE;
ecf709
+
ecf709
+    req->repbuf.v_msg.kiov_base = req->repbuf.msgbuf;
ecf709
+    /* Length of the msg iobuf will be adjusted later, so far use the full
ecf709
+     * length so that constructing the reply can use that capacity
ecf709
+     */
ecf709
+    req->repbuf.v_msg.kiov_len = KCM_PACKET_MAX_SIZE;
ecf709
+
ecf709
+    req->cctx = cctx;
ecf709
+    req->kctx = kctx;
ecf709
+
ecf709
+    return req;
ecf709
+}
ecf709
+
ecf709
+static void kcm_recv(struct cli_ctx *cctx)
ecf709
+{
ecf709
+    struct kcm_req_ctx *req;
ecf709
+    struct kcm_ctx *kctx;
ecf709
+    int ret;
ecf709
+
ecf709
+    kctx = talloc_get_type(cctx->rctx->pvt_ctx, struct kcm_ctx);
ecf709
+    req = talloc_get_type(cctx->state_ctx, struct kcm_req_ctx);
ecf709
+    if (req == NULL) {
ecf709
+        /* A new request comes in, setup data structures */
ecf709
+        req = kcm_new_req(cctx, cctx, kctx);
ecf709
+        if (req == NULL) {
ecf709
+            DEBUG(SSSDBG_CRIT_FAILURE,
ecf709
+                  "Cannot set up client connection\n");
ecf709
+            talloc_free(cctx);
ecf709
+            return;
ecf709
+        }
ecf709
+
ecf709
+        cctx->state_ctx = req;
ecf709
+    }
ecf709
+
ecf709
+    ret = kcm_recv_data(cctx->cfd, &req->reqbuf);
ecf709
+    switch (ret) {
ecf709
+    case ENODATA:
ecf709
+        DEBUG(SSSDBG_TRACE_ALL, "Client closed connection.\n");
ecf709
+        talloc_free(cctx);
ecf709
+        return;
ecf709
+    case EAGAIN:
ecf709
+        DEBUG(SSSDBG_TRACE_ALL, "Retry later\n");
ecf709
+        return;
ecf709
+    case EOK:
ecf709
+        /* all fine */
ecf709
+        break;
ecf709
+    default:
ecf709
+        DEBUG(SSSDBG_FATAL_FAILURE,
ecf709
+              "Failed to receive data (%d, %s), aborting client\n",
ecf709
+              ret, sss_strerror(ret));
ecf709
+        talloc_free(cctx);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    ret = kcm_input_parse(&req->reqbuf, &req->op_io);
ecf709
+    if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_FATAL_FAILURE,
ecf709
+            "Failed to parse data (%d, %s), aborting client\n",
ecf709
+            ret, sss_strerror(ret));
ecf709
+        goto fail;
ecf709
+    }
ecf709
+
ecf709
+    /* do not read anymore, client is done sending */
ecf709
+    TEVENT_FD_NOT_READABLE(cctx->cfde);
ecf709
+
ecf709
+    kcm_reply_error(cctx, ret, &req->repbuf);
ecf709
+    return;
ecf709
+
ecf709
+fail:
ecf709
+    /* Fail with reply */
ecf709
+    kcm_reply_error(cctx, ret, &req->repbuf);
ecf709
+}
ecf709
+
ecf709
+static int kcm_send_data(struct cli_ctx *cctx)
ecf709
+{
ecf709
+    struct kcm_req_ctx *req;
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    req = talloc_get_type(cctx->state_ctx, struct kcm_req_ctx);
ecf709
+
ecf709
+    ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_len);
ecf709
+    if (ret != EOK) {
ecf709
+        return ret;
ecf709
+    }
ecf709
+
ecf709
+    ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_rc);
ecf709
+    if (ret != EOK) {
ecf709
+        return ret;
ecf709
+    }
ecf709
+
ecf709
+    ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_msg);
ecf709
+    if (ret != EOK) {
ecf709
+        return ret;
ecf709
+    }
ecf709
+
ecf709
+    return EOK;
ecf709
+}
ecf709
+
ecf709
+static void kcm_send(struct cli_ctx *cctx)
ecf709
+{
ecf709
+    errno_t ret;
ecf709
+
ecf709
+    ret = kcm_send_data(cctx);
ecf709
+    if (ret == EAGAIN) {
ecf709
+        /* not all data was sent, loop again */
ecf709
+        return;
ecf709
+    } else if (ret != EOK) {
ecf709
+        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting client!\n");
ecf709
+        talloc_free(cctx);
ecf709
+        return;
ecf709
+    }
ecf709
+
ecf709
+    /* ok all sent */
ecf709
+    TEVENT_FD_NOT_WRITEABLE(cctx->cfde);
ecf709
+    TEVENT_FD_READABLE(cctx->cfde);
ecf709
+    talloc_zfree(cctx->state_ctx);
ecf709
+    return;
ecf709
+}
ecf709
+
ecf709
 static void kcm_fd_handler(struct tevent_context *ev,
ecf709
                            struct tevent_fd *fde,
ecf709
                            uint16_t flags, void *ptr)
ecf709
@@ -39,25 +455,54 @@ static void kcm_fd_handler(struct tevent_context *ev,
ecf709
     if (ret != EOK) {
ecf709
         DEBUG(SSSDBG_CRIT_FAILURE,
ecf709
               "Could not create idle timer for client. "
ecf709
-               "This connection may not auto-terminate\n");
ecf709
+              "This connection may not auto-terminate\n");
ecf709
         /* Non-fatal, continue */
ecf709
     }
ecf709
+
ecf709
+    if (flags & TEVENT_FD_READ) {
ecf709
+        kcm_recv(cctx);
ecf709
+        return;
ecf709
+    }
ecf709
+    if (flags & TEVENT_FD_WRITE) {
ecf709
+        kcm_send(cctx);
ecf709
+        return;
ecf709
+    }
ecf709
 }
ecf709
 
ecf709
 int kcm_connection_setup(struct cli_ctx *cctx)
ecf709
 {
ecf709
-    struct kcm_proto_ctx *protocol_ctx;
ecf709
-
ecf709
-    protocol_ctx = talloc_zero(cctx, struct kcm_proto_ctx);
ecf709
-    if (protocol_ctx == NULL) {
ecf709
-        return ENOMEM;
ecf709
-    }
ecf709
-
ecf709
-    cctx->protocol_ctx = protocol_ctx;
ecf709
     cctx->cfd_handler = kcm_fd_handler;
ecf709
     return EOK;
ecf709
 }
ecf709
 
ecf709
+krb5_error_code sss2krb5_error(errno_t err)
ecf709
+{
ecf709
+    switch (err) {
ecf709
+    case EOK:
ecf709
+        return 0;
ecf709
+    case ENOMEM:
ecf709
+        return KRB5_CC_NOMEM;
ecf709
+    case EACCES:
ecf709
+        return KRB5_FCC_PERM;
ecf709
+    case ERR_KCM_OP_NOT_IMPLEMENTED:
ecf709
+        return KRB5_CC_NOSUPP;
ecf709
+    case ERR_WRONG_NAME_FORMAT:
ecf709
+        return KRB5_CC_BADNAME;
ecf709
+    case ERR_NO_MATCHING_CREDS:
ecf709
+        return KRB5_FCC_NOFILE;
ecf709
+    case ERR_NO_CREDS:
ecf709
+        return KRB5_CC_NOTFOUND;
ecf709
+    case ERR_KCM_CC_END:
ecf709
+        return KRB5_CC_END;
ecf709
+    case ERR_KCM_MALFORMED_IN_PKT:
ecf709
+    case EINVAL:
ecf709
+    case EIO:
ecf709
+        return KRB5_CC_IO;
ecf709
+    }
ecf709
+
ecf709
+    return KRB5_FCC_INTERNAL;
ecf709
+}
ecf709
+
ecf709
 /* Dummy, not used here but required to link to other responder files */
ecf709
 struct cli_protocol_version *register_cli_protocol_version(void)
ecf709
 {
ecf709
diff --git a/src/responder/kcm/kcmsrv_pvt.h b/src/responder/kcm/kcmsrv_pvt.h
ecf709
index a7c9d062c17f09986d894064176c3a461d396ac0..fd1fd9fa32d59a323d465def68999f24f84e3923 100644
ecf709
--- a/src/responder/kcm/kcmsrv_pvt.h
ecf709
+++ b/src/responder/kcm/kcmsrv_pvt.h
ecf709
@@ -27,13 +27,20 @@
ecf709
 #include <sys/types.h>
ecf709
 #include "responder/common/responder.h"
ecf709
 
ecf709
-/* KCM IO structure */
ecf709
+/*
ecf709
+ * KCM IO structure
ecf709
+ *
ecf709
+ * In theory we cold use sss_iobuf there, but since iobuf was
ecf709
+ * made opaque, this allows it to allocate the structures on
ecf709
+ * the stack in one go.
ecf709
+ * */
ecf709
 struct kcm_data {
ecf709
     uint8_t *data;
ecf709
     size_t length;
ecf709
 };
ecf709
 
ecf709
-/* To avoid leaking the sssd-specific responder data to other
ecf709
+/*
ecf709
+ * To avoid leaking the sssd-specific responder data to other
ecf709
  * modules, the ccache databases and other KCM specific data
ecf709
  * are kept separately
ecf709
  */
ecf709
@@ -41,7 +48,8 @@ struct kcm_resp_ctx {
ecf709
     krb5_context k5c;
ecf709
 };
ecf709
 
ecf709
-/* responder context that contains both the responder data,
ecf709
+/*
ecf709
+ * responder context that contains both the responder data,
ecf709
  * like the ccaches and the sssd-specific stuff like the
ecf709
  * generic responder ctx
ecf709
  */
ecf709
@@ -55,4 +63,11 @@ struct kcm_ctx {
ecf709
 
ecf709
 int kcm_connection_setup(struct cli_ctx *cctx);
ecf709
 
ecf709
+/*
ecf709
+ * Internally in SSSD-KCM we use SSSD-internal error codes so that we
ecf709
+ * can always the same sss_strerror() functions to format the errors
ecf709
+ * nicely, but the client expects libkrb5 error codes.
ecf709
+ */
ecf709
+krb5_error_code sss2krb5_error(errno_t err);
ecf709
+
ecf709
 #endif /* __KCMSRV_PVT_H__ */
ecf709
-- 
ecf709
2.9.3
ecf709