/*
SSSD
KCM Server - ccache storage in sssd-secrets
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 <stdio.h>
#include <talloc.h>
#include <jansson.h>
#include "util/crypto/sss_crypto.h"
#include "util/tev_curl.h"
#include "responder/kcm/kcmsrv_ccache_pvt.h"
#include "responder/kcm/kcmsrv_ccache_be.h"
#ifndef SSSD_SECRETS_SOCKET
#endif /* SSSD_SECRETS_SOCKET */
#ifndef SEC_TIMEOUT
#endif /* SEC_TIMEOUT */
/* Just to keep the name of the ccache readable */
/* Compat definition of json_array_foreach for older systems */
#ifndef json_array_foreach
for(idx = 0; \
idx++)
#endif
const char *name)
{
if (sec_key_list == NULL) {
return NULL;
}
for (int i = 0; sec_key_list[i]; i++) {
sec_name = sec_key_list[i];
break;
}
}
return sec_name;
}
{
if (sec_key_list == NULL) {
return NULL;
}
for (int i = 0; sec_key_list[i]; i++) {
sec_name = sec_key_list[i];
break;
}
}
return sec_name;
}
static const char *sec_headers[] = {
"Content-type: application/octet-stream",
NULL,
};
struct ccdb_sec {
};
{
if (http_code != 200) {
}
switch (http_code) {
case 200:
return EOK;
case 404:
return ERR_NO_CREDS;
case 400:
return ERR_INPUT_PARSE;
case 403:
return EACCES;
case 409:
return EEXIST;
case 413:
return E2BIG;
case 507:
return ENOSPC;
}
return EIO;
}
/*
* Helper request to list all UUID+name pairs
*/
struct sec_list_state {
const char **sec_key_list;
};
const char ***_list,
struct tevent_context *ev,
{
const char *container_url;
return NULL;
}
if (container_url == NULL) {
goto immediate;
}
NULL,
goto immediate;
}
return req;
return req;
}
{
struct sec_list_state);
int http_code;
return;
}
if (http_code == 404) {
/* If no ccaches are found, return an empty list */
return;
}
} else if (http_code == 200) {
return;
}
} else {
return;
}
}
const char ***_list,
{
int ok;
if (sec_http_list == NULL) {
return EINVAL;
}
sec_http_list_len, 0, &error);
"Failed to parse JSON payload on line %d: %s\n",
return ERR_JSON_DECODING;
}
if (!ok) {
goto done;
}
goto done;
}
goto done;
}
}
done:
}
return ret;
}
const char ***_sec_key_list,
{
struct sec_list_state);
if (_sec_key_list != NULL) {
}
if (_sec_key_list_len != NULL) {
}
return EOK;
}
/*
* Helper request to get a ccache by key
*/
struct sec_get_state {
const char *sec_key;
};
struct tevent_context *ev,
const char *sec_key)
{
const char *cc_url;
return NULL;
}
goto immediate;
}
ev,
NULL,
goto immediate;
}
return req;
return req;
}
{
struct sec_get_state);
const char *sec_value;
int http_code;
return;
}
if (http_code != 200) {
"GET operation returned HTTP error %d\n", http_code);
return;
}
return;
}
"Cannot convert JSON keyval to ccache blob [%d]: %s\n",
return;
}
}
struct kcm_ccache **_cc)
{
return EOK;
}
/*
* Helper request to get a ccache name or ID
*/
struct sec_get_ccache_state {
const char *name;
const char *sec_key;
};
struct tevent_context *ev,
const char *name,
{
return NULL;
}
goto immediate;
}
goto immediate;
}
return req;
return req;
}
{
struct sec_get_ccache_state);
const char **sec_key_list;
"Cannot list keys [%d]: %s\n",
return;
}
} else {
}
"Cannot find item in the ccache list\n");
/* Don't error out, just return an empty list */
return;
}
return;
}
}
{
struct tevent_req);
struct sec_get_ccache_state);
"Cannot resolve key to ccache [%d]: %s\n",
return;
}
}
struct kcm_ccache **_cc)
{
struct sec_get_ccache_state);
return EOK;
}
/*
* The actual sssd-secrets back end
*/
{
return ENOMEM;
}
return ENOMEM;
}
/* We just need the random numbers to generate pseudo-random ccache names
* and avoid conflicts */
return EOK;
}
/*
* Helper request to get a ccache by key
*/
struct sec_patch_state {
const char *sec_key_url;
};
struct tevent_context *ev,
const char *sec_key_url,
{
return NULL;
}
NULL,
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct sec_patch_state);
int http_code;
return;
}
if (http_code == 404) {
} else if (http_code != 200) {
return;
}
return;
}
}
{
struct tevent_req);
struct sec_patch_state);
int http_code;
return;
}
if (http_code != 200) {
return;
}
}
{
return EOK;
}
/* The operations between the KCM and sssd-secrets */
struct ccdb_sec_nextid_state {
unsigned int nextid;
char *nextid_name;
int maxtries;
int numtry;
};
/* Generate a unique ID */
/* GET the name from secrets, if doesn't exist, OK, if exists, try again */
struct tevent_context *ev,
{
return NULL;
}
goto immediate;
}
return req;
return req;
}
{
struct ccdb_sec_nextid_state);
return EBUSY;
}
return ENOMEM;
}
return ENOMEM;
}
return EOK;
}
{
struct tevent_req);
struct ccdb_sec_nextid_state);
const char **sec_key_list;
size_t i;
"Cannot list keys [%d]: %s\n",
return;
}
for (i = 0; i < sec_key_list_len; i++) {
break;
}
}
"Failed to find a random key, trying again..\n");
if (i < sec_key_list_len) {
/* Try again */
return;
}
return;
}
}
unsigned int *_nextid)
{
struct ccdb_sec_nextid_state);
return EOK;
}
/* We chose only UUID here to avoid issues later with renaming */
struct ccdb_sec_set_default_state {
};
struct tevent_context *ev,
{
const char *url;
return NULL;
}
"Setting the default ccache to %s\n", uuid_str);
goto immediate;
}
if (uuid_iobuf == NULL) {
goto immediate;
}
goto immediate;
}
return req;
return req;
}
{
"sec_patch request failed [%d]: %s\n",
return;
}
}
{
return EOK;
}
/* OUT: uuid */
struct ccdb_sec_get_default_state {
};
struct tevent_context *ev,
{
const char *url;
return NULL;
}
goto immediate;
}
url,
NULL,
goto immediate;
}
return req;
return req;
}
{
int http_code;
struct ccdb_sec_get_default_state);
"Communication with the secrets responder failed [%d]: %s\n",
return;
}
if (http_code == 404) {
/* Return a NULL uuid */
return;
} else if (http_code != 200) {
return;
}
if (uuid_size != UUID_STR_SIZE) {
return;
}
}
{
struct ccdb_sec_get_default_state);
return EOK;
}
/* OUT: a list of <uuid:name, uuid:name> */
struct ccdb_sec_list_state {
};
struct tevent_context *ev,
{
return NULL;
}
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct ccdb_sec_list_state);
const char **sec_key_list;
"Communication with the secrets responder failed [%d]: %s\n",
return;
}
return;
}
for (size_t i = 0; i < sec_key_list_len; i++) {
return;
}
}
/* Sentinel */
}
uuid_t **_uuid_list)
{
struct ccdb_sec_list_state);
return EOK;
}
struct ccdb_sec_getbyuuid_state {
};
/* OUT: a list of <uuid:name, uuid:name> */
/* for each item in list, compare with the uuid: portion */
/* return result */
struct tevent_context *ev,
{
return NULL;
}
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct ccdb_sec_getbyuuid_state);
return;
}
}
struct kcm_ccache **_cc)
{
struct ccdb_sec_getbyuuid_state);
return EOK;
}
/* OUT: a list of <uuid:name, uuid:name> */
/* for each item in list, compare with the :name portion */
/* return result */
struct ccdb_sec_getbyname_state {
};
struct tevent_context *ev,
const char *name)
{
return NULL;
}
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct ccdb_sec_getbyname_state);
return;
}
}
struct kcm_ccache **_cc)
{
struct ccdb_sec_getbyname_state);
return EOK;
}
struct ccdb_sec_name_by_uuid_state {
const char *name;
};
struct tevent_context *ev,
{
return NULL;
}
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct ccdb_sec_name_by_uuid_state);
const char **sec_key_list;
const char *name;
size_t i;
return;
}
for (i = 0; i < sec_key_list_len; i++) {
/* Match, copy name */
"Malformed key, cannot get name\n");
return;
}
return;
}
return;
}
}
return;
}
const char **_name)
{
struct ccdb_sec_name_by_uuid_state);
return EOK;
}
struct ccdb_sec_uuid_by_name_state {
const char *name;
};
struct tevent_context *ev,
const char *name)
{
return NULL;
}
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct ccdb_sec_uuid_by_name_state);
const char **sec_key_list;
size_t i;
return;
}
for (i = 0; i < sec_key_list_len; i++) {
/* Match, copy UUID */
"Malformed key, cannot get UUID\n");
return;
}
return;
}
}
return;
}
{
struct ccdb_sec_uuid_by_name_state);
return EOK;
}
/* HTTP POST $base to create the container */
/* HTTP PUT $base to create the container. Since PUT errors out on duplicates, at least
* we fail consistently here and don't overwrite the ccache on concurrent requests
*/
struct ccdb_sec_create_state {
const char *key_url;
};
struct tevent_context *ev,
struct kcm_ccache *cc)
{
const char *container_url;
return NULL;
}
/* Do the encoding asap so that if we fail, we don't even attempt any
* writes */
"Cannot convert cache %s to JSON [%d]: %s\n",
goto immediate;
}
if (container_url == NULL) {
goto immediate;
}
NULL,
goto immediate;
}
return req;
return req;
}
{
int http_code;
struct ccdb_sec_create_state);
"Communication with the secrets responder failed [%d]: %s\n",
return;
}
/* Conflict is not an error as multiple ccaches are under the same
* container */
if (http_code == 409) {
} else if (http_code != 200) {
return;
}
return;
}
}
{
int http_code;
struct ccdb_sec_create_state);
"Communication with the secrets responder failed [%d]: %s\n",
return;
}
if (http_code != 200) {
return;
}
}
{
return EOK;
}
struct ccdb_sec_mod_cred_state {
};
struct tevent_context *ev,
struct kcm_mod_ctx *mod_cc)
{
return NULL;
}
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct ccdb_sec_mod_cred_state);
const char *url;
return;
}
return;
}
"Failed to marshall modified ccache to payload [%d]: %s\n",
return;
}
url,
payload);
return;
}
}
{
struct tevent_req);
return;
}
}
{
return EOK;
}
struct ccdb_sec_store_cred_state {
};
struct tevent_context *ev,
{
return NULL;
}
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct ccdb_sec_store_cred_state);
const char *url;
return;
}
"Cannot store credentials to ccache [%d]: %s\n",
return;
}
"Failed to marshall modified ccache to payload [%d]: %s\n",
return;
}
url,
payload);
return;
}
}
{
struct tevent_req);
return;
}
}
{
return EOK;
}
struct ccdb_sec_delete_state {
};
struct tevent_context *ev,
{
return NULL;
}
goto immediate;
}
return req;
return req;
}
{
struct tevent_req);
struct ccdb_sec_delete_state);
const char **sec_key_list;
const char *sec_key;
const char *cc_url;
return;
}
if (state->sec_key_list_len == 0) {
return;
}
return;
}
return;
}
NULL,
return;
}
}
{
struct tevent_req);
struct ccdb_sec_delete_state);
int http_code;
const char *container_url;
"Cannot delete ccache [%d]: %s\n",
return;
}
if (http_code != 200) {
return;
}
return;
}
if (container_url == NULL) {
return;
}
NULL,
return;
}
}
{
struct tevent_req);
struct ccdb_sec_delete_state);
int http_code;
"Cannot delete ccache container [%d]: %s\n",
return;
}
if (http_code != 200) {
return;
}
}
{
return EOK;
}
.init = ccdb_sec_init,
};