Esempio n. 1
0
krb5_error_code KRB5_CALLCONV
krb5_responder_otp_set_answer(krb5_context ctx, krb5_responder_context rctx,
                              size_t ti, const char *value, const char *pin)
{
    krb5_error_code retval;
    k5_json_object obj = NULL;
    k5_json_number num;
    k5_json_string str;
    char *tmp;

    retval = k5_json_object_create(&obj);
    if (retval != 0)
        goto error;

    retval = k5_json_number_create(ti, &num);
    if (retval != 0)
        goto error;

    retval = k5_json_object_set(obj, "tokeninfo", num);
    k5_json_release(num);
    if (retval != 0)
        goto error;

    if (value != NULL) {
        retval = k5_json_string_create(value, &str);
        if (retval != 0)
            goto error;

        retval = k5_json_object_set(obj, "value", str);
        k5_json_release(str);
        if (retval != 0)
            goto error;
    }

    if (pin != NULL) {
        retval = k5_json_string_create(pin, &str);
        if (retval != 0)
            goto error;

        retval = k5_json_object_set(obj, "pin", str);
        k5_json_release(str);
        if (retval != 0)
            goto error;
    }

    retval = k5_json_encode(obj, &tmp);
    if (retval != 0)
        goto error;
    k5_json_release(obj);

    retval = krb5_responder_set_answer(ctx, rctx, KRB5_RESPONDER_QUESTION_OTP,
                                       tmp);
    free(tmp);
    return retval;

error:
    k5_json_release(obj);
    return retval;
}
Esempio n. 2
0
/* Converts a krb5_pa_otp_challenge into a JSON object. */
static krb5_error_code
codec_encode_challenge(krb5_context ctx, krb5_pa_otp_challenge *chl,
                       char **json)
{
    k5_json_object obj = NULL, tmp = NULL;
    k5_json_string str = NULL;
    k5_json_array arr = NULL;
    krb5_error_code retval;
    int i;

    retval = k5_json_object_create(&obj);
    if (retval != 0)
        goto cleanup;

    if (chl->service.data) {
        retval = k5_json_string_create_len(chl->service.data,
                                           chl->service.length, &str);
        if (retval != 0)
            goto cleanup;
        retval = k5_json_object_set(obj, "service", str);
        k5_json_release(str);
        if (retval != 0)
            goto cleanup;
    }

    retval = k5_json_array_create(&arr);
    if (retval != 0)
        goto cleanup;

    for (i = 0; chl->tokeninfo[i] != NULL ; i++) {
        retval = codec_encode_tokeninfo(chl->tokeninfo[i], &tmp);
        if (retval != 0)
            goto cleanup;

        retval = k5_json_array_add(arr, tmp);
        k5_json_release(tmp);
        if (retval != 0)
            goto cleanup;
    }

    retval = k5_json_object_set(obj, "tokenInfo", arr);
    if (retval != 0)
        goto cleanup;

    retval = k5_json_encode(obj, json);
    if (retval)
        goto cleanup;

cleanup:
    k5_json_release(arr);
    k5_json_release(obj);
    return retval;
}
Esempio n. 3
0
/* Converts a krb5_data struct into a property of a JSON object. */
static krb5_error_code
codec_data_to_value(krb5_data *data, k5_json_object obj, const char *key)
{
    krb5_error_code retval;
    k5_json_string str;

    if (data->data == NULL)
        return 0;

    retval = k5_json_string_create_len(data->data, data->length, &str);
    if (retval)
        return retval;

    retval = k5_json_object_set(obj, key, str);
    k5_json_release(str);
    return retval;
}
Esempio n. 4
0
/* Converts a krb5_int32 into a property of a JSON object. */
static krb5_error_code
codec_int32_to_value(krb5_int32 int32, k5_json_object obj, const char *key)
{
    krb5_error_code retval;
    k5_json_number num;

    if (int32 == -1)
        return 0;

    retval = k5_json_number_create(int32, &num);
    if (retval)
        return retval;

    retval = k5_json_object_set(obj, key, num);
    k5_json_release(num);
    return retval;
}
Esempio n. 5
0
static krb5_error_code
responder(krb5_context ctx, void *rawdata, krb5_responder_context rctx)
{
    krb5_error_code err;
    char *key, *value, *pin, *encoded1, *encoded2;
    const char *challenge;
    k5_json_value decoded1, decoded2;
    k5_json_object ids;
    k5_json_number val;
    krb5_int32 token_flags;
    struct responder_data *data = rawdata;
    krb5_responder_pkinit_challenge *chl;
    krb5_responder_otp_challenge *ochl;
    unsigned int i, n;

    data->called = TRUE;

    /* Check that a particular challenge has the specified expected value. */
    if (data->challenge != NULL) {
        /* Separate the challenge name and its expected value. */
        key = strdup(data->challenge);
        if (key == NULL)
            exit(ENOMEM);
        value = key + strcspn(key, "=");
        if (*value != '\0')
            *value++ = '\0';
        /* Read the challenge. */
        challenge = krb5_responder_get_challenge(ctx, rctx, key);
        err = k5_json_decode(value, &decoded1);
        /* Check for "no challenge". */
        if (challenge == NULL && *value == '\0') {
            fprintf(stderr, "OK: (no challenge) == (no challenge)\n");
        } else if (err != 0) {
            /* It's not JSON, so assume we're just after a string compare. */
            if (strcmp(challenge, value) == 0) {
                fprintf(stderr, "OK: \"%s\" == \"%s\"\n", challenge, value);
            } else {
                fprintf(stderr, "ERROR: \"%s\" != \"%s\"\n", challenge, value);
                exit(1);
            }
        } else {
            /* Assume we're after a JSON compare - decode the actual value. */
            err = k5_json_decode(challenge, &decoded2);
            if (err != 0) {
                fprintf(stderr, "error decoding \"%s\"\n", challenge);
                exit(1);
            }
            /* Re-encode the expected challenge and the actual challenge... */
            err = k5_json_encode(decoded1, &encoded1);
            if (err != 0) {
                fprintf(stderr, "error encoding json data\n");
                exit(1);
            }
            err = k5_json_encode(decoded2, &encoded2);
            if (err != 0) {
                fprintf(stderr, "error encoding json data\n");
                exit(1);
            }
            k5_json_release(decoded1);
            k5_json_release(decoded2);
            /* ... and see if they look the same. */
            if (strcmp(encoded1, encoded2) == 0) {
                fprintf(stderr, "OK: \"%s\" == \"%s\"\n", encoded1, encoded2);
            } else {
                fprintf(stderr, "ERROR: \"%s\" != \"%s\"\n", encoded1,
                        encoded2);
                exit(1);
            }
            free(encoded1);
            free(encoded2);
        }
        free(key);
    }

    /* Provide a particular response for a challenge. */
    if (data->response != NULL) {
        /* Separate the challenge and its data content... */
        key = strdup(data->response);
        if (key == NULL)
            exit(ENOMEM);
        value = key + strcspn(key, "=");
        if (*value != '\0')
            *value++ = '\0';
        /* ... and pass it in. */
        err = krb5_responder_set_answer(ctx, rctx, key, value);
        if (err != 0) {
            fprintf(stderr, "error setting response\n");
            exit(1);
        }
        free(key);
    }

    if (data->print_pkinit_challenge) {
        /* Read the PKINIT challenge, formatted as a structure. */
        err = krb5_responder_pkinit_get_challenge(ctx, rctx, &chl);
        if (err != 0) {
            fprintf(stderr, "error getting pkinit challenge\n");
            exit(1);
        }
        if (chl != NULL) {
            for (n = 0; chl->identities[n] != NULL; n++)
                continue;
            for (i = 0; chl->identities[i] != NULL; i++) {
                if (chl->identities[i]->token_flags != -1) {
                    printf("identity %u/%u: %s (flags=0x%lx)\n", i + 1, n,
                           chl->identities[i]->identity,
                           (long)chl->identities[i]->token_flags);
                } else {
                    printf("identity %u/%u: %s\n", i + 1, n,
                           chl->identities[i]->identity);
                }
            }
        }
        krb5_responder_pkinit_challenge_free(ctx, rctx, chl);
    }

    /* Provide a particular response for the PKINIT challenge. */
    if (data->pkinit_answer != NULL) {
        /* Read the PKINIT challenge, formatted as a structure. */
        err = krb5_responder_pkinit_get_challenge(ctx, rctx, &chl);
        if (err != 0) {
            fprintf(stderr, "error getting pkinit challenge\n");
            exit(1);
        }
        /*
         * In case order matters, if the identity starts with "FILE:", exercise
         * the set_answer function, with the real answer second.
         */
        if (chl != NULL &&
            chl->identities != NULL &&
            chl->identities[0] != NULL) {
            if (strncmp(chl->identities[0]->identity, "FILE:", 5) == 0)
                krb5_responder_pkinit_set_answer(ctx, rctx, "foo", "bar");
        }
        /* Provide the real answer. */
        key = strdup(data->pkinit_answer);
        if (key == NULL)
            exit(ENOMEM);
        value = strrchr(key, '=');
        if (value != NULL)
            *value++ = '\0';
        else
            value = "";
        err = krb5_responder_pkinit_set_answer(ctx, rctx, key, value);
        if (err != 0) {
            fprintf(stderr, "error setting response\n");
            exit(1);
        }
        free(key);
        /*
         * In case order matters, if the identity starts with "PKCS12:",
         * exercise the set_answer function, with the real answer first.
         */
        if (chl != NULL &&
            chl->identities != NULL &&
            chl->identities[0] != NULL) {
            if (strncmp(chl->identities[0]->identity, "PKCS12:", 5) == 0)
                krb5_responder_pkinit_set_answer(ctx, rctx, "foo", "bar");
        }
        krb5_responder_pkinit_challenge_free(ctx, rctx, chl);
    }

    /*
     * Something we always check: read the PKINIT challenge, both as a
     * structure and in JSON form, reconstruct the JSON form from the
     * structure's contents, and check that they're the same.
     */
    challenge = krb5_responder_get_challenge(ctx, rctx,
                                             KRB5_RESPONDER_QUESTION_PKINIT);
    if (challenge != NULL) {
        krb5_responder_pkinit_get_challenge(ctx, rctx, &chl);
        if (chl == NULL) {
            fprintf(stderr, "pkinit raw challenge set, "
                    "but structure is NULL\n");
            exit(1);
        }
        if (k5_json_object_create(&ids) != 0) {
            fprintf(stderr, "error creating json objects\n");
            exit(1);
        }
        for (i = 0; chl->identities[i] != NULL; i++) {
            token_flags = chl->identities[i]->token_flags;
            if (k5_json_number_create(token_flags, &val) != 0) {
                fprintf(stderr, "error creating json number\n");
                exit(1);
            }
            if (k5_json_object_set(ids, chl->identities[i]->identity,
                                   val) != 0) {
                fprintf(stderr, "error adding json number to object\n");
                exit(1);
            }
            k5_json_release(val);
        }
        /* Encode the structure... */
        err = k5_json_encode(ids, &encoded1);
        if (err != 0) {
            fprintf(stderr, "error encoding json data\n");
            exit(1);
        }
        k5_json_release(ids);
        /* ... and see if they look the same. */
        if (strcmp(encoded1, challenge) != 0) {
            fprintf(stderr, "\"%s\" != \"%s\"\n", encoded1, challenge);
            exit(1);
        }
        krb5_responder_pkinit_challenge_free(ctx, rctx, chl);
        free(encoded1);
    }

    /* Provide a particular response for an OTP challenge. */
    if (data->otp_answer != NULL) {
        if (krb5_responder_otp_get_challenge(ctx, rctx, &ochl) == 0) {
            key = strchr(data->otp_answer, '=');
            if (key != NULL) {
                /* Make a copy of the answer that we can chop up. */
                key = strdup(data->otp_answer);
                if (key == NULL)
                    return ENOMEM;
                /* Isolate the ti value. */
                value = strchr(key, '=');
                *value++ = '\0';
                n = atoi(key);
                /* Break the value and PIN apart. */
                pin = strchr(value, ':');
                if (pin != NULL)
                    *pin++ = '\0';
                err = krb5_responder_otp_set_answer(ctx, rctx, n, value, pin);
                if (err != 0) {
                    fprintf(stderr, "error setting response\n");
                    exit(1);
                }
                free(key);
            }
            krb5_responder_otp_challenge_free(ctx, rctx, ochl);
        }
    }

    return 0;
}