From 95c3cab051aa1b8b4f7eb309bf135e8f51665baa Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Sun, 25 Jan 2015 16:53:49 -0500 Subject: [PATCH] Support KDC_ERR_MORE_PREAUTH_DATA_REQUIRED Add support for multi-hop preauth mechs. In the KDC, allow kdcpreauth modules to return KDC_ERR_MORE_PREAUTH_DATA_REQUIRED as defined in RFC 6113. In libkrb5, treat this code like KDC_ERR_PREAUTH_REQUIRED. clpreauth modules can use the modreq parameter to distinguish between the first and subsequent KDC messages. We assume that the error padata will include an element of the preauth mech's type, or at least of a type recognized by the clpreauth module. Also reset the list of previously attempted preauth types for both kinds of errors. That list is really only appropriate for retrying after a failed preauth attempt, which we don't currently do. Add an intermediate variable for the reply code to avoid a long conditional expression. [ghudson@mit.edu: adjust get_in_tkt.c logic to avoid needing a helper function; clarify commit message] ticket: 8063 (new) --- doc/plugindev/clpreauth.rst | 6 +++--- src/include/k5-int.h | 1 + src/kdc/kdc_preauth.c | 2 ++ src/lib/krb5/error_tables/krb5_err.et | 2 +- src/lib/krb5/krb/get_in_tkt.c | 13 ++++++++----- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/doc/plugindev/clpreauth.rst b/doc/plugindev/clpreauth.rst index c3e7298..38aa52e 100644 --- a/doc/plugindev/clpreauth.rst +++ b/doc/plugindev/clpreauth.rst @@ -21,9 +21,9 @@ A clpreauth module is generally responsible for: just returns ``PA_REAL``, indicating that it implements a normal preauthentication type. -* Examining the padata information included in the preauth_required - error and producing padata values for the next AS request. This is - done with the **process** method. +* Examining the padata information included in a PREAUTH_REQUIRED or + MORE_PREAUTH_DATA_REQUIRED error and producing padata values for the + next AS request. This is done with the **process** method. * Examining the padata information included in a successful ticket reply, possibly verifying the KDC identity and computing a reply diff --git a/src/include/k5-int.h b/src/include/k5-int.h index a1ea25a..4868e7d 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -391,6 +391,7 @@ typedef unsigned char u_char; not find a KDC */ #define KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE 86 /* The KDC did not respond to the IAKERB proxy */ +#define KDC_ERR_MORE_PREAUTH_DATA_REQUIRED 91 /* RFC 6113 */ #define KRB_ERR_MAX 127 /* err table base max offset for protocol err codes */ /* diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index 50cc252..dd83844 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -1000,6 +1000,8 @@ finish_check_padata(struct padata_state *state, krb5_error_code code) case KRB5KDC_ERR_DISCARD: /* pkinit alg-agility */ case KRB5KDC_ERR_NO_ACCEPTABLE_KDF: + /* rfc 6113 */ + case KRB5KDC_ERR_MORE_PREAUTH_DATA_REQUIRED: (*oldrespond)(oldarg, code); return; default: diff --git a/src/lib/krb5/error_tables/krb5_err.et b/src/lib/krb5/error_tables/krb5_err.et index 5c6f10b..7ba7c1e 100644 --- a/src/lib/krb5/error_tables/krb5_err.et +++ b/src/lib/krb5/error_tables/krb5_err.et @@ -132,7 +132,7 @@ error_code KRB5PLACEHOLD_87, "KRB5 error code 87" error_code KRB5PLACEHOLD_88, "KRB5 error code 88" error_code KRB5PLACEHOLD_89, "KRB5 error code 89" error_code KRB5PLACEHOLD_90, "KRB5 error code 90" -error_code KRB5PLACEHOLD_91, "KRB5 error code 91" +error_code KRB5KDC_ERR_MORE_PREAUTH_DATA_REQUIRED, "More preauthentication data is required" error_code KRB5PLACEHOLD_92, "KRB5 error code 92" error_code KRB5KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTION, "An unsupported critical FAST option was requested" error_code KRB5PLACEHOLD_94, "KRB5 error code 94" diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index f9bc027..fa8afcc 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -1239,7 +1239,8 @@ init_creds_step_request(krb5_context context, clear_cc_config_out_data(context, ctx); if (ctx->err_reply == NULL) { - /* either our first attempt, or retrying after PREAUTH_NEEDED */ + /* Either our first attempt, or retrying after KDC_ERR_PREAUTH_REQUIRED + * or KDC_ERR_MORE_PREAUTH_DATA_REQUIRED. */ code = k5_preauth(context, ctx, ctx->preauth_to_use, ctx->preauth_required, &ctx->request->padata, &ctx->selected_preauth_type); @@ -1408,6 +1409,7 @@ init_creds_step_reply(krb5_context context, krb5_preauthtype kdc_pa_type; krb5_boolean retry = FALSE; int canon_flag = 0; + uint32_t reply_code; krb5_keyblock *strengthen_key = NULL; krb5_keyblock encrypting_key; krb5_boolean fast_avail; @@ -1431,6 +1433,7 @@ init_creds_step_reply(krb5_context context, &retry); if (code != 0) goto cleanup; + reply_code = ctx->err_reply->error; if (negotiation_requests_restart(context, ctx, ctx->err_padata)) { ctx->have_restarted = 1; k5_preauth_request_context_fini(context); @@ -1441,9 +1444,10 @@ init_creds_step_reply(krb5_context context, ctx->err_reply = NULL; krb5_free_pa_data(context, ctx->err_padata); ctx->err_padata = NULL; - } else if (ctx->err_reply->error == KDC_ERR_PREAUTH_REQUIRED && - retry) { + } else if ((reply_code == KDC_ERR_MORE_PREAUTH_DATA_REQUIRED || + reply_code == KDC_ERR_PREAUTH_REQUIRED) && retry) { /* reset the list of preauth types to try */ + k5_reset_preauth_types_tried(context); krb5_free_pa_data(context, ctx->preauth_to_use); ctx->preauth_to_use = ctx->err_padata; ctx->err_padata = NULL; @@ -1480,8 +1484,7 @@ init_creds_step_reply(krb5_context context, code = 0; } else { /* error + no hints = give up */ - code = (krb5_error_code)ctx->err_reply->error + - ERROR_TABLE_BASE_krb5; + code = (krb5_error_code)reply_code + ERROR_TABLE_BASE_krb5; } }