/*
SSSD
KCM Server - the KCM server request and reply parsing and dispatching
Copyright (C) Red Hat, 2016
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 "responder/common/responder.h"
#include "responder/kcm/kcmsrv_pvt.h"
#include "responder/kcm/kcmsrv_ops.h"
/* The first four bytes of a message is always the size */
/* The return code is 32bits */
/* The maximum length of a request or reply as defined by the RPC
* protocol. This is the same constant size as MIT KRB5 uses
*/
/* KCM operation, its raw input and raw output and result */
struct kcm_op_io {
};
/**
* KCM IO-vector operations
*/
struct kcm_iovec {
/* We don't use iovec b/c void pointers don't allow for
* pointer arithmetics and it's convenient to keep track
* of processed bytes
*/
};
{
/* This iovec is full (read) or depleted (write), proceed to the next one */
return EOK;
}
if (do_read) {
} else {
}
if (len == -1) {
return EAGAIN;
} else {
return errno;
}
}
if (len == 0) {
/* Read event on fd that doesn't yield data? error */
return ENODATA;
}
/* Decrease the amount of available free space in the iovec */
return EOK;
}
{
}
{
}
/**
* Parsing KCM input
*
* The request is received as two IO vectors:
*
* first iovec:
* length 32-bit big-endian integer
*
* second iovec:
* major protocol number 8-bit big-endian integer
* minor protocol number 8-bit big-endian integer
* opcode 16-bit big-endian integer
* message payload buffer
*/
struct kcm_reqbuf {
/* Includes the major, minor versions etc */
};
{
/* The first 4 bytes before the payload is message length */
}
{
if (msglen == 0) {
return EBADMSG;
}
"but received %zu\n",
return EBADMSG;
}
/* First 16 bits are 8 bit major and 8bit minor protocol version */
&mc);
&mc);
if (proto_maj != KCM_PROTOCOL_VERSION_MAJOR) {
return ERR_KCM_MALFORMED_IN_PKT;
}
if (proto_min != KCM_PROTOCOL_VERSION_MINOR) {
return ERR_KCM_MALFORMED_IN_PKT;
}
&mc);
"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 */
return EOK;
}
/**
* Constructing a reply for failure and success
*
* The reply consists of three IO vectors:
* 1) length iovec:
* length: 32-bit big-endian
*
* 2) return code iovec:
* retcode: 32-bit big-endian. Non-zero on failure in the KCM server,
* zero if the KCM operation ran (even if the operation itself
* failed)
*
* 3) reply iovec
* message: buffer, first 32-bits of the buffer is the return code of
* the KCM operation, the rest depends on the operation itself.
* The buffer's length is specified by the first integer in the
* reply (very intuitive, right?)
*
* The client always reads the length and return code iovectors. However, the
* client reads the reply iovec only if retcode is 0 in the return code iovector
* (see kcmio_unix_socket_read() in the MIT tree)
*/
struct kcm_repbuf {
};
struct kcm_repbuf *repbuf)
{
size_t c;
c = 0;
c = 0;
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
*/
struct kcm_repbuf *repbuf)
{
size_t c;
if (replen > KCM_PACKET_MAX_SIZE) {
"Reply exceeds the KCM protocol limit, aborting\n");
return E2BIG;
}
"Sending a reply with %zu bytes of payload\n", replen);
c = 0;
c = 0;
if (replen > 0) {
"Failed to allocate memory for the message\n");
return ENOMEM;
}
c = 0;
&c);
/* Set the buffer and its length to send to KCM client */
}
return EOK;
}
/**
* Construct a reply buffer and send it to the KCM client
*/
struct kcm_repbuf *repbuf)
{
"KCM operation returs failure [%d]: %s\n",
"Cannot construct the reply buffer, terminating client\n");
return;
}
}
/**
* Request-reply dispatcher
*/
struct kcm_req_ctx {
/* client context owns per-client buffers including this one */
/* raw IO buffers */
/* long-lived responder structures */
};
{
"Cannot construct the reply buffer, terminating client\n");
return;
}
}
struct kcm_req_ctx *req_ctx)
{
return ENOMEM;
}
return EOK;
}
{
return;
}
}
int fd,
struct kcm_reqbuf *reqbuf)
{
/* Not all errors are fatal, hence we don't print DEBUG messages
* here, but in the caller
*/
return ret;
}
if (msglen > KCM_PACKET_MAX_SIZE) {
"Request exceeds the KCM protocol limit, aborting\n");
return E2BIG;
}
"Failed to allocate memory for the message\n");
return ENOMEM;
}
/* Set the buffer and its expected len to receive the data */
/* Not all errors are fatal, hence we don't print DEBUG messages
* here, but in the caller
*/
return ret;
}
return EOK;
}
/* Mind that kcm_new_req() does not take a mem_ctx argument on purpose as we
* really want the cctx to be the memory context here so that if the client
* disconnects, the request goes away. */
{
return NULL;
}
return req;
}
{
int ret;
/* A new request comes in, setup data structures. */
"Cannot set up client connection\n");
return;
}
}
switch (ret) {
case ENODATA:
return;
case EAGAIN:
return;
case EOK:
/* all fine */
break;
default:
"Failed to receive data (%d, %s), aborting client\n",
return;
}
"Failed to parse data (%d, %s), aborting client\n",
goto fail;
}
/* do not read anymore, client is done sending */
"Failed to dispatch KCM operation [%d]: %s\n",
goto fail;
}
/* Dispatched request resumes in kcm_cmd_request_done */
return;
fail:
/* Fail with reply */
}
{
"Failed to write the length iovec [%d]: %s\n",
return ret;
}
"Failed to write the retcode iovec [%d]: %s\n",
return ret;
}
"Failed to write the msg iovec [%d]: %s\n",
return ret;
}
return EOK;
}
{
return;
return;
}
return;
}
{
}
{
return EOK;
}
{
switch (err) {
case EOK:
return 0;
case ENOMEM:
return KRB5_CC_NOMEM;
case EACCES:
return KRB5_FCC_PERM;
return KRB5_CC_NOSUPP;
case ERR_WRONG_NAME_FORMAT:
return KRB5_CC_BADNAME;
case ERR_NO_MATCHING_CREDS:
return KRB5_FCC_NOFILE;
case ERR_NO_CREDS:
return KRB5_CC_NOTFOUND;
case ERR_KCM_CC_END:
return KRB5_CC_END;
case ERR_KCM_MALFORMED_IN_PKT:
case EINVAL:
case EIO:
return KRB5_CC_IO;
}
return KRB5_FCC_INTERNAL;
}
/* Dummy, not used here but required to link to other responder files */
{
return NULL;
}