/*
SSSD
KCM Server - the KCM server operations
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 "util/sss_iobuf.h"
#include "util/sss_krb5.h"
#include "util/util_creds.h"
#include "responder/kcm/kcmsrv_pvt.h"
#include "responder/kcm/kcmsrv_ops.h"
#include "responder/kcm/kcmsrv_ccache.h"
/* This limit comes from:
*/
struct kcm_op_ctx {
};
/* 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*
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx);
typedef errno_t
struct kcm_op {
const char *name;
};
struct kcm_cmd_state {
};
struct tevent_context *ev,
struct kcm_ops_queue_ctx *qctx,
struct kcm_resp_ctx *kcm_data,
{
return NULL;
}
goto immediate;
}
goto immediate;
}
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
*/
goto immediate;
}
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
*/
goto immediate;
}
goto immediate;
}
return req;
return req;
}
{
/* When this request finishes, it frees the queue_entry which unblocks
* other requests by the same UID
*/
return;
}
return;
}
}
{
"op receive function failed [%d]: %s\n",
return;
}
"KCM operation %s returned [%d]: %s\n",
/* The first four bytes of the reply is the operation status code */
return;
}
return;
}
}
struct tevent_req *req,
{
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
*/
return EOK; \
} while(0);
struct kcm_op_common_state {
};
{
struct kcm_op_common_state);
return EOK;
}
/* () -> (name) */
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
return NULL;
}
goto immediate;
}
return req;
return req;
}
{
char *newid;
struct tevent_req);
struct kcm_op_common_state);
"Cannot generate a new ID [%d]: %s\n",
return;
}
"Cannot write generated ID %d: %s\n",
return;
}
}
/* (princ) -> () */
struct kcm_op_initialize_state {
const char *name;
};
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
return NULL;
}
"Cannot read input name [%d]: %s\n",
goto immediate;
}
"Name %s is malformed [%d]: %s\n",
goto immediate;
}
"Cannot unmarshal principal [%d]: %s\n",
goto immediate;
}
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct kcm_op_initialize_state);
bool ok;
"Cannot get ccache by name [%d]: %s\n",
return;
}
if (!ok) {
return;
}
"Cannot get new ccache UUID [%d]: %s\n",
return;
}
/* Nuke any previous cache and its contents during initialization */
uuid);
return;
}
return;
}
}
{
struct tevent_req);
"Cannot delete ccache from the db %d: %s\n",
return;
}
}
{
struct kcm_op_initialize_state);
return;
}
return;
}
}
{
struct tevent_req);
struct kcm_op_initialize_state);
return;
}
/* If there was no previous default ccache, set this one as default */
return;
}
}
{
struct tevent_req);
struct kcm_op_initialize_state);
"Cannot get default ccache [%d]: %s\n",
return;
}
if (uuid_is_null(old_dfl_uuid) == false) {
/* If there was a previous default ccache, switch to the initialized
* one by default
*/
"Cannot get new ccache UUID [%d]: %s\n",
return;
}
dfl_uuid);
return;
}
return;
}
/* ENOENT, done */
}
{
struct tevent_req);
struct kcm_op_initialize_state);
return;
}
}
{
}
/* (name) -> () */
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
const char *name;
return NULL;
}
"Cannot unmarshall input name [%d]: %s\n",
goto immediate;
}
name);
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct kcm_op_common_state);
"Cannot get matching ccache [%d]: %s\n",
return;
}
uuid);
return;
}
}
{
struct tevent_req);
struct kcm_op_common_state);
"Cannot delete ccache from the db [%d]: %s\n",
return;
}
}
/* (name, cred) -> () */
struct kcm_op_store_state {
};
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
const char *name;
return NULL;
}
"Cannot unmarshall input name [%d]: %s\n",
goto immediate;
}
if (creds_len > KCM_REPLY_MAX) {
/* Protects against underflows and in general adds sanity */
goto immediate;
}
goto immediate;
}
NULL);
"Cannot unmarshall input cred blob [%d]: %s\n",
goto immediate;
}
name);
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct kcm_op_store_state);
"Cannot get ccache by name [%d]: %s\n",
return;
}
uuid,
return;
}
}
{
struct tevent_req);
struct kcm_op_store_state);
"Cannot store credentials [%d]: %s\n",
return;
}
}
{
}
/* (name) -> (princ) */
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
const char *name;
return NULL;
}
goto immediate;
}
name);
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct kcm_op_common_state);
"Cannot get ccache by name [%d]: %s\n",
return;
}
return;
}
/* Marshall the principal to the reply */
"Credentials with no principal?\n");
return;
}
"Cannot marshall principal [%d]: %s\n",
return;
}
}
/* (name) -> (uuid, ...) */
static struct tevent_req *
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
const char *name;
return NULL;
}
goto immediate;
}
name);
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct kcm_op_common_state);
"Cannot get ccache by name [%d]: %s\n",
return;
}
return;
}
continue;
}
uuid, UUID_BYTES);
"Cannot marshall UUID %s [%d]: %s\n",
continue;
}
}
}
/* (name, uuid) -> (cred) */
static struct tevent_req *
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
const char *name;
return NULL;
}
goto immediate;
}
name);
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct kcm_op_common_state);
"Cannot get ccache by name [%d]: %s\n",
return;
}
return;
}
"Cannot read input UUID [%d]: %s\n",
return;
}
"Cannot get UUID from creds, skipping\n");
continue;
}
break;
}
}
return;
}
return;
}
"Cannot write ccache blob [%d]: %s\n",
return;
}
}
/* (name, flags, credtag) -> () */
/* FIXME */
static struct tevent_req *
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
return NULL;
}
return req;
}
/* () -> (uuid, ...) */
static struct tevent_req *
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
return NULL;
}
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct kcm_op_common_state);
"Cannot list the ccache DB [%d]: %s\n",
return;
}
return;
}
for (int i = 0;
uuid_is_null(uuid_list[i]) == false;
i++) {
kcm_debug_uuid(uuid_list[i]);
uuid_list[i],
"Cannot marshall UUID %s [%d]: %s\n",
return;
}
}
}
/* (uuid) -> (name) */
static struct tevent_req *
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
return NULL;
}
"Cannot read input UUID [%d]: %s\n",
goto immediate;
}
uuid_in);
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct kcm_op_common_state);
const char *name;
"Cannot get ccahe by UUID [%d]: %s\n",
return;
}
return;
}
name);
"Cannot write output name [%d]: %s\n",
return;
}
}
/* () -> (name) */
struct kcm_op_get_default_ccache_state {
const char *name;
};
static errno_t
static struct tevent_req *
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
struct kcm_op_get_default_ccache_state);
return NULL;
}
goto immediate;
}
return req;
return req;
}
{
struct kcm_op_get_default_ccache_state);
"Cannot get default ccache [%d]: %s\n",
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
*/
return;
}
return;
}
/* Existing default */
dfl_uuid);
return;
}
return;
}
{
struct kcm_op_get_default_ccache_state);
"Cannot get ccahe by UUID [%d]: %s\n",
return;
}
return;
}
}
{
struct kcm_op_get_default_ccache_state);
"Cannot list ccaches [%d]: %s\n",
return;
}
/* No cache at all, just send back a reply */
return;
}
return;
}
/* Otherwise resolve the first cache and use it as a default */
uuid_list[0]);
return;
}
return;
}
static errno_t
{
"%"SPRIuid,
return ENOMEM;
}
}
"Cannot write output name [%d]: %s\n",
return ret;
}
return EOK;
}
{
}
/* (name) -> () */
static struct tevent_req *
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
const char *name;
return NULL;
}
"Cannot read input name [%d]: %s\n",
goto immediate;
}
name);
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct kcm_op_common_state);
"Cannot get ccache by name [%d]: %s\n",
return;
}
dfl_uuid);
return;
}
return;
}
{
struct tevent_req);
struct kcm_op_common_state);
return;
}
}
/* (name) -> (offset) */
static struct tevent_req *
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
const char *name;
return NULL;
}
"Cannot read input name [%d]: %s\n",
goto immediate;
}
name);
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct kcm_op_common_state);
"Cannot get matching ccache [%d]: %s\n",
return;
}
return;
}
"Cannot write KDC offset [%d]: %s\n",
return;
}
}
/* (name, offset) -> () */
/* () -> (name) */
struct kcm_op_set_kdc_offset_state {
};
static struct tevent_req *
struct tevent_context *ev,
struct kcm_op_ctx *op_ctx)
{
const char *name;
return NULL;
}
"Cannot read input name [%d]: %s\n",
goto immediate;
}
name);
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct kcm_op_set_kdc_offset_state);
"Cannot get matching ccache [%d]: %s\n",
return;
}
"Cannot read KDC offset [%d]: %s\n",
return;
}
return;
}
uuid,
mod_ctx);
return;
}
}
{
struct tevent_req);
struct kcm_op_set_kdc_offset_state);
"Cannot modify ccache [%d]: %s\n",
return;
}
}
{
}
};
{
if (opcode >= KCM_OP_SENTINEL) {
return NULL;
}
}
return op;
}
{
return "Unknown operation";
}
}