|
Packit |
fd8b60 |
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit |
fd8b60 |
/* tests/responder.c - Test harness for responder callbacks and the like. */
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Copyright 2013 Red Hat, Inc. All rights reserved.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
fd8b60 |
* modification, are permitted provided that the following conditions are met:
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* 1. Redistributions of source code must retain the above copyright
|
|
Packit |
fd8b60 |
* notice, this list of conditions and the following disclaimer.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
Packit |
fd8b60 |
* notice, this list of conditions and the following disclaimer in
|
|
Packit |
fd8b60 |
* the documentation and/or other materials provided with the
|
|
Packit |
fd8b60 |
* distribution.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
Packit |
fd8b60 |
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
Packit |
fd8b60 |
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
Packit |
fd8b60 |
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
|
Packit |
fd8b60 |
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
Packit |
fd8b60 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
Packit |
fd8b60 |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
Packit |
fd8b60 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
Packit |
fd8b60 |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
Packit |
fd8b60 |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
Packit |
fd8b60 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* A helper for testing PKINIT and responder callbacks.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* This test helper takes multiple options and one argument.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* responder [options] principal
|
|
Packit |
fd8b60 |
* -X preauth_option -> preauth options, as for kinit
|
|
Packit |
fd8b60 |
* -x challenge -> expected responder challenge, of the form
|
|
Packit |
fd8b60 |
* "question=challenge"
|
|
Packit |
fd8b60 |
* -r response -> provide a reponder answer, in the form
|
|
Packit |
fd8b60 |
* "question=answer"
|
|
Packit |
fd8b60 |
* -c -> print the pkinit challenge
|
|
Packit |
fd8b60 |
* -p identity=pin -> provide a pkinit answer, in the form "identity=pin"
|
|
Packit |
fd8b60 |
* -o index=value:pin -> provide an OTP answer, in the form "index=value:pin"
|
|
Packit |
fd8b60 |
* principal -> client principal name
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* If the responder callback isn't called, that's treated as an error.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* If an expected responder challenge is specified, when the responder
|
|
Packit |
fd8b60 |
* callback is called, the challenge associated with the specified question is
|
|
Packit |
fd8b60 |
* compared against the specified value. If the value provided to the
|
|
Packit |
fd8b60 |
* callback doesn't parse as JSON, a literal string compare is performed,
|
|
Packit |
fd8b60 |
* otherwise both values are parsed as JSON and then re-encoded before
|
|
Packit |
fd8b60 |
* comparison. In either case, the comparison must succeed.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Any missing data or mismatches are treated as errors.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <k5-platform.h>
|
|
Packit |
fd8b60 |
#include <k5-json.h>
|
|
Packit |
fd8b60 |
#include <sys/types.h>
|
|
Packit |
fd8b60 |
#include <unistd.h>
|
|
Packit |
fd8b60 |
#include <krb5.h>
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
struct responder_data {
|
|
Packit |
fd8b60 |
krb5_boolean called;
|
|
Packit |
fd8b60 |
krb5_boolean print_pkinit_challenge;
|
|
Packit |
fd8b60 |
const char *challenge;
|
|
Packit |
fd8b60 |
const char *response;
|
|
Packit |
fd8b60 |
const char *pkinit_answer;
|
|
Packit |
fd8b60 |
const char *otp_answer;
|
|
Packit |
fd8b60 |
};
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static krb5_error_code
|
|
Packit |
fd8b60 |
responder(krb5_context ctx, void *rawdata, krb5_responder_context rctx)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code err;
|
|
Packit |
fd8b60 |
char *key, *value, *pin, *encoded1, *encoded2;
|
|
Packit |
fd8b60 |
const char *challenge;
|
|
Packit |
fd8b60 |
k5_json_value decoded1, decoded2;
|
|
Packit |
fd8b60 |
k5_json_object ids;
|
|
Packit |
fd8b60 |
k5_json_number val;
|
|
Packit |
fd8b60 |
krb5_int32 token_flags;
|
|
Packit |
fd8b60 |
struct responder_data *data = rawdata;
|
|
Packit |
fd8b60 |
krb5_responder_pkinit_challenge *chl;
|
|
Packit |
fd8b60 |
krb5_responder_otp_challenge *ochl;
|
|
Packit |
fd8b60 |
unsigned int i, n;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
data->called = TRUE;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Check that a particular challenge has the specified expected value. */
|
|
Packit |
fd8b60 |
if (data->challenge != NULL) {
|
|
Packit |
fd8b60 |
/* Separate the challenge name and its expected value. */
|
|
Packit |
fd8b60 |
key = strdup(data->challenge);
|
|
Packit |
fd8b60 |
if (key == NULL)
|
|
Packit |
fd8b60 |
exit(ENOMEM);
|
|
Packit |
fd8b60 |
value = key + strcspn(key, "=");
|
|
Packit |
fd8b60 |
if (*value != '\0')
|
|
Packit |
fd8b60 |
*value++ = '\0';
|
|
Packit |
fd8b60 |
/* Read the challenge. */
|
|
Packit |
fd8b60 |
challenge = krb5_responder_get_challenge(ctx, rctx, key);
|
|
Packit |
fd8b60 |
err = k5_json_decode(value, &decoded1);
|
|
Packit |
fd8b60 |
/* Check for "no challenge". */
|
|
Packit |
fd8b60 |
if (challenge == NULL && *value == '\0') {
|
|
Packit |
fd8b60 |
fprintf(stderr, "OK: (no challenge) == (no challenge)\n");
|
|
Packit |
fd8b60 |
} else if (err != 0) {
|
|
Packit |
fd8b60 |
/* It's not JSON, so assume we're just after a string compare. */
|
|
Packit |
fd8b60 |
if (strcmp(challenge, value) == 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "OK: \"%s\" == \"%s\"\n", challenge, value);
|
|
Packit |
fd8b60 |
} else {
|
|
Packit |
fd8b60 |
fprintf(stderr, "ERROR: \"%s\" != \"%s\"\n", challenge, value);
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
} else {
|
|
Packit |
fd8b60 |
/* Assume we're after a JSON compare - decode the actual value. */
|
|
Packit |
fd8b60 |
err = k5_json_decode(challenge, &decoded2);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error decoding \"%s\"\n", challenge);
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
/* Re-encode the expected challenge and the actual challenge... */
|
|
Packit |
fd8b60 |
err = k5_json_encode(decoded1, &encoded1);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error encoding json data\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
err = k5_json_encode(decoded2, &encoded2);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error encoding json data\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
k5_json_release(decoded1);
|
|
Packit |
fd8b60 |
k5_json_release(decoded2);
|
|
Packit |
fd8b60 |
/* ... and see if they look the same. */
|
|
Packit |
fd8b60 |
if (strcmp(encoded1, encoded2) == 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "OK: \"%s\" == \"%s\"\n", encoded1, encoded2);
|
|
Packit |
fd8b60 |
} else {
|
|
Packit |
fd8b60 |
fprintf(stderr, "ERROR: \"%s\" != \"%s\"\n", encoded1,
|
|
Packit |
fd8b60 |
encoded2);
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
free(encoded1);
|
|
Packit |
fd8b60 |
free(encoded2);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
free(key);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Provide a particular response for a challenge. */
|
|
Packit |
fd8b60 |
if (data->response != NULL) {
|
|
Packit |
fd8b60 |
/* Separate the challenge and its data content... */
|
|
Packit |
fd8b60 |
key = strdup(data->response);
|
|
Packit |
fd8b60 |
if (key == NULL)
|
|
Packit |
fd8b60 |
exit(ENOMEM);
|
|
Packit |
fd8b60 |
value = key + strcspn(key, "=");
|
|
Packit |
fd8b60 |
if (*value != '\0')
|
|
Packit |
fd8b60 |
*value++ = '\0';
|
|
Packit |
fd8b60 |
/* ... and pass it in. */
|
|
Packit |
fd8b60 |
err = krb5_responder_set_answer(ctx, rctx, key, value);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error setting response\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
free(key);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (data->print_pkinit_challenge) {
|
|
Packit |
fd8b60 |
/* Read the PKINIT challenge, formatted as a structure. */
|
|
Packit |
fd8b60 |
err = krb5_responder_pkinit_get_challenge(ctx, rctx, &chl;;
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error getting pkinit challenge\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (chl != NULL) {
|
|
Packit |
fd8b60 |
for (n = 0; chl->identities[n] != NULL; n++)
|
|
Packit |
fd8b60 |
continue;
|
|
Packit |
fd8b60 |
for (i = 0; chl->identities[i] != NULL; i++) {
|
|
Packit |
fd8b60 |
if (chl->identities[i]->token_flags != -1) {
|
|
Packit |
fd8b60 |
printf("identity %u/%u: %s (flags=0x%lx)\n", i + 1, n,
|
|
Packit |
fd8b60 |
chl->identities[i]->identity,
|
|
Packit |
fd8b60 |
(long)chl->identities[i]->token_flags);
|
|
Packit |
fd8b60 |
} else {
|
|
Packit |
fd8b60 |
printf("identity %u/%u: %s\n", i + 1, n,
|
|
Packit |
fd8b60 |
chl->identities[i]->identity);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
krb5_responder_pkinit_challenge_free(ctx, rctx, chl);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Provide a particular response for the PKINIT challenge. */
|
|
Packit |
fd8b60 |
if (data->pkinit_answer != NULL) {
|
|
Packit |
fd8b60 |
/* Read the PKINIT challenge, formatted as a structure. */
|
|
Packit |
fd8b60 |
err = krb5_responder_pkinit_get_challenge(ctx, rctx, &chl;;
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error getting pkinit challenge\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* In case order matters, if the identity starts with "FILE:", exercise
|
|
Packit |
fd8b60 |
* the set_answer function, with the real answer second.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
if (chl != NULL &&
|
|
Packit |
fd8b60 |
chl->identities != NULL &&
|
|
Packit |
fd8b60 |
chl->identities[0] != NULL) {
|
|
Packit |
fd8b60 |
if (strncmp(chl->identities[0]->identity, "FILE:", 5) == 0)
|
|
Packit |
fd8b60 |
krb5_responder_pkinit_set_answer(ctx, rctx, "foo", "bar");
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
/* Provide the real answer. */
|
|
Packit |
fd8b60 |
key = strdup(data->pkinit_answer);
|
|
Packit |
fd8b60 |
if (key == NULL)
|
|
Packit |
fd8b60 |
exit(ENOMEM);
|
|
Packit |
fd8b60 |
value = strrchr(key, '=');
|
|
Packit |
fd8b60 |
if (value != NULL)
|
|
Packit |
fd8b60 |
*value++ = '\0';
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
value = "";
|
|
Packit |
fd8b60 |
err = krb5_responder_pkinit_set_answer(ctx, rctx, key, value);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error setting response\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
free(key);
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* In case order matters, if the identity starts with "PKCS12:",
|
|
Packit |
fd8b60 |
* exercise the set_answer function, with the real answer first.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
if (chl != NULL &&
|
|
Packit |
fd8b60 |
chl->identities != NULL &&
|
|
Packit |
fd8b60 |
chl->identities[0] != NULL) {
|
|
Packit |
fd8b60 |
if (strncmp(chl->identities[0]->identity, "PKCS12:", 7) == 0)
|
|
Packit |
fd8b60 |
krb5_responder_pkinit_set_answer(ctx, rctx, "foo", "bar");
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
krb5_responder_pkinit_challenge_free(ctx, rctx, chl);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Something we always check: read the PKINIT challenge, both as a
|
|
Packit |
fd8b60 |
* structure and in JSON form, reconstruct the JSON form from the
|
|
Packit |
fd8b60 |
* structure's contents, and check that they're the same.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
challenge = krb5_responder_get_challenge(ctx, rctx,
|
|
Packit |
fd8b60 |
KRB5_RESPONDER_QUESTION_PKINIT);
|
|
Packit |
fd8b60 |
if (challenge != NULL) {
|
|
Packit |
fd8b60 |
krb5_responder_pkinit_get_challenge(ctx, rctx, &chl;;
|
|
Packit |
fd8b60 |
if (chl == NULL) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "pkinit raw challenge set, "
|
|
Packit |
fd8b60 |
"but structure is NULL\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (k5_json_object_create(&ids) != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error creating json objects\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
for (i = 0; chl->identities[i] != NULL; i++) {
|
|
Packit |
fd8b60 |
token_flags = chl->identities[i]->token_flags;
|
|
Packit |
fd8b60 |
if (k5_json_number_create(token_flags, &val) != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error creating json number\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (k5_json_object_set(ids, chl->identities[i]->identity,
|
|
Packit |
fd8b60 |
val) != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error adding json number to object\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
k5_json_release(val);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
/* Encode the structure... */
|
|
Packit |
fd8b60 |
err = k5_json_encode(ids, &encoded1);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error encoding json data\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
k5_json_release(ids);
|
|
Packit |
fd8b60 |
/* ... and see if they look the same. */
|
|
Packit |
fd8b60 |
if (strcmp(encoded1, challenge) != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "\"%s\" != \"%s\"\n", encoded1, challenge);
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
krb5_responder_pkinit_challenge_free(ctx, rctx, chl);
|
|
Packit |
fd8b60 |
free(encoded1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Provide a particular response for an OTP challenge. */
|
|
Packit |
fd8b60 |
if (data->otp_answer != NULL) {
|
|
Packit |
fd8b60 |
if (krb5_responder_otp_get_challenge(ctx, rctx, &ochl) == 0) {
|
|
Packit |
fd8b60 |
key = strchr(data->otp_answer, '=');
|
|
Packit |
fd8b60 |
if (key != NULL) {
|
|
Packit |
fd8b60 |
/* Make a copy of the answer that we can chop up. */
|
|
Packit |
fd8b60 |
key = strdup(data->otp_answer);
|
|
Packit |
fd8b60 |
if (key == NULL)
|
|
Packit |
fd8b60 |
return ENOMEM;
|
|
Packit |
fd8b60 |
/* Isolate the ti value. */
|
|
Packit |
fd8b60 |
value = strchr(key, '=');
|
|
Packit |
fd8b60 |
*value++ = '\0';
|
|
Packit |
fd8b60 |
n = atoi(key);
|
|
Packit |
fd8b60 |
/* Break the value and PIN apart. */
|
|
Packit |
fd8b60 |
pin = strchr(value, ':');
|
|
Packit |
fd8b60 |
if (pin != NULL)
|
|
Packit |
fd8b60 |
*pin++ = '\0';
|
|
Packit |
fd8b60 |
err = krb5_responder_otp_set_answer(ctx, rctx, n, value, pin);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error setting response\n");
|
|
Packit |
fd8b60 |
exit(1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
free(key);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
krb5_responder_otp_challenge_free(ctx, rctx, ochl);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
int
|
|
Packit |
fd8b60 |
main(int argc, char **argv)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_context context;
|
|
Packit |
fd8b60 |
krb5_ccache ccache;
|
|
Packit |
fd8b60 |
krb5_get_init_creds_opt *opts;
|
|
Packit |
fd8b60 |
krb5_principal principal;
|
|
Packit |
fd8b60 |
krb5_creds creds;
|
|
Packit |
fd8b60 |
krb5_error_code err;
|
|
Packit |
fd8b60 |
const char *errmsg;
|
|
Packit |
fd8b60 |
char *opt, *val;
|
|
Packit |
fd8b60 |
struct responder_data response;
|
|
Packit |
fd8b60 |
int c;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
err = krb5_init_context(&context);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error starting Kerberos: %s\n", error_message(err));
|
|
Packit |
fd8b60 |
return err;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
err = krb5_get_init_creds_opt_alloc(context, &opts);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error initializing options: %s\n",
|
|
Packit |
fd8b60 |
error_message(err));
|
|
Packit |
fd8b60 |
return err;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
err = krb5_cc_default(context, &ccache);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error resolving default ccache: %s\n",
|
|
Packit |
fd8b60 |
error_message(err));
|
|
Packit |
fd8b60 |
return err;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
err = krb5_get_init_creds_opt_set_out_ccache(context, opts, ccache);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error setting output ccache: %s\n",
|
|
Packit |
fd8b60 |
error_message(err));
|
|
Packit |
fd8b60 |
return err;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
memset(&response, 0, sizeof(response));
|
|
Packit |
fd8b60 |
while ((c = getopt(argc, argv, "X:x:cr:p:")) != -1) {
|
|
Packit |
fd8b60 |
switch (c) {
|
|
Packit |
fd8b60 |
case 'X':
|
|
Packit |
fd8b60 |
/* Like kinit, set a generic preauth option. */
|
|
Packit |
fd8b60 |
opt = strdup(optarg);
|
|
Packit |
fd8b60 |
val = opt + strcspn(opt, "=");
|
|
Packit |
fd8b60 |
if (*val != '\0') {
|
|
Packit |
fd8b60 |
*val++ = '\0';
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
err = krb5_get_init_creds_opt_set_pa(context, opts, opt, val);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error setting option \"%s\": %s\n", opt,
|
|
Packit |
fd8b60 |
error_message(err));
|
|
Packit |
fd8b60 |
return err;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
free(opt);
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 'x':
|
|
Packit |
fd8b60 |
/* Check that a particular question has a specific challenge. */
|
|
Packit |
fd8b60 |
response.challenge = optarg;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 'c':
|
|
Packit |
fd8b60 |
/* Note that we want a dump of the PKINIT challenge structure. */
|
|
Packit |
fd8b60 |
response.print_pkinit_challenge = TRUE;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 'r':
|
|
Packit |
fd8b60 |
/* Set a verbatim response for a verbatim challenge. */
|
|
Packit |
fd8b60 |
response.response = optarg;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 'p':
|
|
Packit |
fd8b60 |
/* Set a PKINIT answer for a specific PKINIT identity. */
|
|
Packit |
fd8b60 |
response.pkinit_answer = optarg;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case 'o':
|
|
Packit |
fd8b60 |
/* Set an OTP answer for a specific OTP tokeninfo. */
|
|
Packit |
fd8b60 |
response.otp_answer = optarg;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (argc > optind) {
|
|
Packit |
fd8b60 |
err = krb5_parse_name(context, argv[optind], &principal);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error parsing name \"%s\": %s", argv[optind],
|
|
Packit |
fd8b60 |
error_message(err));
|
|
Packit |
fd8b60 |
return err;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
} else {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error: no principal name provided\n");
|
|
Packit |
fd8b60 |
return -1;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
err = krb5_get_init_creds_opt_set_responder(context, opts,
|
|
Packit |
fd8b60 |
responder, &response);
|
|
Packit |
fd8b60 |
if (err != 0) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error setting responder: %s\n", error_message(err));
|
|
Packit |
fd8b60 |
return err;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
memset(&creds, 0, sizeof(creds));
|
|
Packit |
fd8b60 |
err = krb5_get_init_creds_password(context, &creds, principal, NULL,
|
|
Packit |
fd8b60 |
NULL, NULL, 0, NULL, opts);
|
|
Packit |
fd8b60 |
if (err == 0)
|
|
Packit |
fd8b60 |
krb5_free_cred_contents(context, &creds);
|
|
Packit |
fd8b60 |
krb5_free_principal(context, principal);
|
|
Packit |
fd8b60 |
krb5_get_init_creds_opt_free(context, opts);
|
|
Packit |
fd8b60 |
krb5_cc_close(context, ccache);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (!response.called) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "error: responder callback wasn't called\n");
|
|
Packit |
fd8b60 |
err = 1;
|
|
Packit |
fd8b60 |
} else if (err) {
|
|
Packit |
fd8b60 |
errmsg = krb5_get_error_message(context, err);
|
|
Packit |
fd8b60 |
fprintf(stderr, "error: krb5_get_init_creds_password failed: %s\n",
|
|
Packit |
fd8b60 |
errmsg);
|
|
Packit |
fd8b60 |
krb5_free_error_message(context, errmsg);
|
|
Packit |
fd8b60 |
err = 2;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
krb5_free_context(context);
|
|
Packit |
fd8b60 |
return err;
|
|
Packit |
fd8b60 |
}
|