示例#1
0
static krb5_error_code
prepare_error_as (struct kdc_request_state *rstate, krb5_kdc_req *request,
                  int error, krb5_pa_data **e_data, krb5_boolean typed_e_data,
                  krb5_principal canon_client, krb5_data **response,
                  const char *status)
{
    krb5_error errpkt;
    krb5_error_code retval;
    krb5_data *scratch = NULL, *e_data_asn1 = NULL, *fast_edata = NULL;
    kdc_realm_t *kdc_active_realm = rstate->realm_data;

    errpkt.ctime = request->nonce;
    errpkt.cusec = 0;

    retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec);
    if (retval)
        return retval;
    errpkt.error = error;
    errpkt.server = request->server;
    errpkt.client = (error == KRB5KDC_ERR_WRONG_REALM) ? canon_client :
        request->client;
    errpkt.text = string2data((char *)status);

    if (e_data != NULL) {
        if (typed_e_data)
            retval = encode_krb5_typed_data(e_data, &e_data_asn1);
        else
            retval = encode_krb5_padata_sequence(e_data, &e_data_asn1);
        if (retval)
            goto cleanup;
        errpkt.e_data = *e_data_asn1;
    } else
        errpkt.e_data = empty_data();

    retval = kdc_fast_handle_error(kdc_context, rstate, request, e_data,
                                   &errpkt, &fast_edata);
    if (retval)
        goto cleanup;
    if (fast_edata != NULL)
        errpkt.e_data = *fast_edata;

    scratch = k5alloc(sizeof(*scratch), &retval);
    if (scratch == NULL)
        goto cleanup;
    if (kdc_fast_hide_client(rstate) && errpkt.client != NULL)
        errpkt.client = (krb5_principal)krb5_anonymous_principal();
    retval = krb5_mk_error(kdc_context, &errpkt, scratch);
    if (retval)
        goto cleanup;

    *response = scratch;
    scratch = NULL;

cleanup:
    krb5_free_data(kdc_context, fast_edata);
    krb5_free_data(kdc_context, e_data_asn1);
    free(scratch);
    return retval;
}
示例#2
0
/*
 * FAST separates two concepts: the set of padata we're using to
 * decide what pre-auth mechanisms to use and the set of padata we're
 * making available to mechanisms in order for them to respond to an
 * error.  The plugin interface in March 2009 does not permit
 * separating these concepts for the plugins.  This function makes
 * both available for future revisions to the plugin interface.  It
 * also re-encodes the padata from the current error as a encoded
 * typed-data and puts that in the e_data field.  That will allow
 * existing plugins with the old interface to find the error data.
 * The output parameter out_padata contains the padata from the error
 * whenever padata  is available (all the time with fast).
 */
krb5_error_code
krb5int_fast_process_error(krb5_context context,
                           struct krb5int_fast_request_state *state,
                           krb5_error **err_replyptr,
                           krb5_pa_data ***out_padata,
                           krb5_boolean *retry)
{
    krb5_error_code retval = 0;
    krb5_error *err_reply = *err_replyptr;

    *out_padata = NULL;
    *retry = 0;
    if (state->armor_key) {
        krb5_pa_data *fx_error_pa;
        krb5_pa_data **result = NULL;
        krb5_data scratch, *encoded_td = NULL;
        krb5_error *fx_error = NULL;
        krb5_fast_response *fast_response = NULL;

        retval = decode_krb5_padata_sequence(&err_reply->e_data, &result);
        if (retval == 0)
            retval = decrypt_fast_reply(context, state, result,
                                        &fast_response);
        if (retval) {
            /*
             * This can happen if the KDC does not understand FAST. We don't
             * expect that, but treating it as the fatal error indicated by the
             * KDC seems reasonable.
             */
            *retry = 0;
            krb5_free_pa_data(context, result);
            return 0;
        }
        krb5_free_pa_data(context, result);
        result = NULL;
        if (retval == 0) {
            fx_error_pa = krb5int_find_pa_data(context, fast_response->padata,
                                               KRB5_PADATA_FX_ERROR);
            if (fx_error_pa == NULL) {
                krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
                                       "Expecting FX_ERROR pa-data inside "
                                       "FAST container");
                retval = KRB5KDC_ERR_PREAUTH_FAILED;
            }
        }
        if (retval == 0) {
            scratch.data = (char *) fx_error_pa->contents;
            scratch.length = fx_error_pa->length;
            retval = decode_krb5_error(&scratch, &fx_error);
        }
        /*
         * krb5_pa_data and krb5_typed_data are safe to cast between:
         * they have the same type fields in the same order.
         * (krb5_preauthtype is a krb5_int32).  If krb5_typed_data is
         * ever changed then this will need to be a copy not a cast.
         */
        if (retval == 0)
            retval = encode_krb5_typed_data((const krb5_typed_data **)
                                            fast_response->padata,
                                            &encoded_td);
        if (retval == 0) {
            fx_error->e_data = *encoded_td;
            free(encoded_td); /*contents owned by fx_error*/
            encoded_td = NULL;
            krb5_free_error(context, err_reply);
            *err_replyptr = fx_error;
            fx_error = NULL;
            *out_padata = fast_response->padata;
            fast_response->padata = NULL;
            /*
             * If there is more than the fx_error padata, then we want
             * to retry the error if a cookie is present
             */
            *retry = (*out_padata)[1] != NULL;
            if (krb5int_find_pa_data(context, *out_padata,
                                     KRB5_PADATA_FX_COOKIE) == NULL)
                *retry = 0;
        }
        if (fx_error)
            krb5_free_error(context, fx_error);
        krb5_free_fast_response(context, fast_response);
    } else { /*not FAST*/
        *retry = (err_reply->e_data.length > 0);
        if ((err_reply->error == KDC_ERR_PREAUTH_REQUIRED ||
                err_reply->error == KDC_ERR_PREAUTH_FAILED) &&
                err_reply->e_data.length) {
            krb5_pa_data **result = NULL;
            retval = decode_krb5_padata_sequence(&err_reply->e_data, &result);
            if (retval == 0) {
                *out_padata = result;
                return 0;
            }
            krb5_free_pa_data(context, result);
            krb5_set_error_message(context, retval,
                                   "Error decoding padata in error reply");
            return retval;
        }
    }
    return retval;
}
示例#3
0
static krb5_error_code
prepare_error_as(struct kdc_request_state *rstate, krb5_kdc_req *request,
                 krb5_db_entry *local_tgt, int error, krb5_pa_data **e_data_in,
                 krb5_boolean typed_e_data, krb5_principal canon_client,
                 krb5_data **response, const char *status)
{
    krb5_error errpkt;
    krb5_error_code retval;
    krb5_data *scratch = NULL, *e_data_asn1 = NULL, *fast_edata = NULL;
    krb5_pa_data **e_data = NULL, *cookie = NULL;
    kdc_realm_t *kdc_active_realm = rstate->realm_data;
    size_t count;

    if (e_data_in != NULL) {
        /* Add a PA-FX-COOKIE to e_data_in.  e_data is a shallow copy
         * containing aliases. */
        for (count = 0; e_data_in[count] != NULL; count++);
        e_data = calloc(count + 2, sizeof(*e_data));
        if (e_data == NULL)
            return ENOMEM;
        memcpy(e_data, e_data_in, count * sizeof(*e_data));
        retval = kdc_fast_make_cookie(kdc_context, rstate, local_tgt,
                                      request->client, &cookie);
        e_data[count] = cookie;
    }

    errpkt.ctime = request->nonce;
    errpkt.cusec = 0;

    retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec);
    if (retval)
        goto cleanup;
    errpkt.error = error;
    errpkt.server = request->server;
    errpkt.client = (error == KDC_ERR_WRONG_REALM) ? canon_client :
                    request->client;
    errpkt.text = string2data((char *)status);

    if (e_data != NULL) {
        if (typed_e_data)
            retval = encode_krb5_typed_data(e_data, &e_data_asn1);
        else
            retval = encode_krb5_padata_sequence(e_data, &e_data_asn1);
        if (retval)
            goto cleanup;
        errpkt.e_data = *e_data_asn1;
    } else
        errpkt.e_data = empty_data();

    retval = kdc_fast_handle_error(kdc_context, rstate, request, e_data,
                                   &errpkt, &fast_edata);
    if (retval)
        goto cleanup;
    if (fast_edata != NULL)
        errpkt.e_data = *fast_edata;

    scratch = k5alloc(sizeof(*scratch), &retval);
    if (scratch == NULL)
        goto cleanup;
    if (kdc_fast_hide_client(rstate) && errpkt.client != NULL)
        errpkt.client = (krb5_principal)krb5_anonymous_principal();
    retval = krb5_mk_error(kdc_context, &errpkt, scratch);
    if (retval)
        goto cleanup;

    *response = scratch;
    scratch = NULL;

cleanup:
    krb5_free_data(kdc_context, fast_edata);
    krb5_free_data(kdc_context, e_data_asn1);
    free(scratch);
    free(e_data);
    if (cookie != NULL)
        free(cookie->contents);
    free(cookie);
    return retval;
}