#include "k5-int.h"
#include "k5-json.h"
#include "int-proto.h"
#include "init_creds_ctx.h"
struct get_one_challenge_data {
krb5_responder_pkinit_identity **identities;
krb5_error_code err;
};
static void
get_one_challenge(void *arg, const char *key, k5_json_value val)
{
struct get_one_challenge_data *data;
unsigned long token_flags;
size_t i;
data = arg;
if (data->err != 0)
return;
if (k5_json_get_tid(val) != K5_JSON_TID_NUMBER) {
data->err = EINVAL;
return;
}
token_flags = k5_json_number_value(val);
for (i = 0; data->identities[i] != NULL; i++)
continue;
data->identities[i] = k5alloc(sizeof(*data->identities[i]), &data->err);
if (data->identities[i] == NULL)
return;
data->identities[i]->identity = strdup(key);
if (data->identities[i]->identity == NULL) {
data->err = ENOMEM;
return;
}
data->identities[i]->token_flags = token_flags;
}
krb5_error_code KRB5_CALLCONV
krb5_responder_pkinit_get_challenge(krb5_context ctx,
krb5_responder_context rctx,
krb5_responder_pkinit_challenge **chl_out)
{
const char *challenge;
k5_json_value j;
struct get_one_challenge_data get_one_challenge_data;
krb5_responder_pkinit_challenge *chl = NULL;
unsigned int n_ids;
krb5_error_code ret;
*chl_out = NULL;
challenge = krb5_responder_get_challenge(ctx, rctx,
KRB5_RESPONDER_QUESTION_PKINIT);
if (challenge == NULL)
return 0;
ret = k5_json_decode(challenge, &j);
if (ret != 0)
return ret;
chl = k5alloc(sizeof(*chl), &ret);
if (chl == NULL)
goto failed;
n_ids = k5_json_object_count(j);
chl->identities = k5calloc(n_ids + 1, sizeof(chl->identities[0]), &ret);
if (chl->identities == NULL)
goto failed;
memset(&get_one_challenge_data, 0, sizeof(get_one_challenge_data));
get_one_challenge_data.identities = chl->identities;
k5_json_object_iterate(j, get_one_challenge, &get_one_challenge_data);
if (get_one_challenge_data.err != 0) {
ret = get_one_challenge_data.err;
goto failed;
}
k5_json_release(j);
*chl_out = chl;
return 0;
failed:
k5_json_release(j);
krb5_responder_pkinit_challenge_free(ctx, rctx, chl);
return ret;
}
krb5_error_code KRB5_CALLCONV
krb5_responder_pkinit_set_answer(krb5_context ctx, krb5_responder_context rctx,
const char *identity, const char *pin)
{
char *answer = NULL;
const char *old_answer;
k5_json_value answers = NULL;
k5_json_string jpin = NULL;
krb5_error_code ret = ENOMEM;
old_answer = k5_response_items_get_answer(rctx->items,
KRB5_RESPONDER_QUESTION_PKINIT);
if (old_answer == NULL && pin == NULL)
return 0;
if (old_answer == NULL)
old_answer = "{}";
ret = k5_json_decode(old_answer, &answers);
if (ret != 0)
goto cleanup;
if (k5_json_get_tid(answers) != K5_JSON_TID_OBJECT) {
ret = EINVAL;
goto cleanup;
}
if (pin != NULL) {
ret = k5_json_string_create(pin, &jpin);
if (ret != 0)
goto cleanup;
ret = k5_json_object_set(answers, identity, jpin);
if (ret != 0)
goto cleanup;
} else {
ret = k5_json_object_set(answers, identity, NULL);
if (ret != 0)
goto cleanup;
}
ret = k5_json_encode(answers, &answer);
if (ret != 0)
goto cleanup;
ret = krb5_responder_set_answer(ctx, rctx, KRB5_RESPONDER_QUESTION_PKINIT,
answer);
cleanup:
k5_json_release(jpin);
k5_json_release(answers);
free(answer);
return ret;
}
void KRB5_CALLCONV
krb5_responder_pkinit_challenge_free(krb5_context ctx,
krb5_responder_context rctx,
krb5_responder_pkinit_challenge *chl)
{
size_t i;
if (chl == NULL)
return;
for (i = 0; chl->identities != NULL && chl->identities[i] != NULL; i++) {
free(chl->identities[i]->identity);
free(chl->identities[i]);
}
free(chl->identities);
free(chl);
}