From 9b525f2406da57eb7a064fc56398a41e2680999a Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Fri, 13 Jan 2017 20:45:48 -0500
Subject: [PATCH] Simplify k5_preauth_tryagain()
When retrying pre-authentication for an error, try only the module for
the selected preauth type, not all preauth types in the original
method data. Pass the error and its padata to k5_preauth_tryagain()
explicitly, so that those fields of krb5_init_creds_context are only
referenced in get_in_tkt.c. Handle a degenerate case in
init_creds_step_reply() to simplify the code in
init_creds_step_request().
ticket: 8537
(cherry picked from commit 27628e5d9d5e6fcfa73276106edbd8149d134dc0)
---
src/include/k5-trace.h | 7 ++--
src/lib/krb5/krb/get_in_tkt.c | 20 ++++-------
src/lib/krb5/krb/int-proto.h | 3 +-
src/lib/krb5/krb/preauth2.c | 64 +++++++++++++++++++----------------
4 files changed, 48 insertions(+), 46 deletions(-)
diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h
index f44f162d3..814da3195 100644
--- a/src/include/k5-trace.h
+++ b/src/include/k5-trace.h
@@ -287,8 +287,11 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
#define TRACE_PREAUTH_SKIP(c, name, patype) \
TRACE(c, "Skipping previously used preauth module {str} ({int})", \
name, (int) patype)
-#define TRACE_PREAUTH_TRYAGAIN_INPUT(c, padata) \
- TRACE(c, "Preauth tryagain input types: {patypes}", padata)
+#define TRACE_PREAUTH_TRYAGAIN_INPUT(c, patype, padata) \
+ TRACE(c, "Preauth tryagain input types ({int}): {patypes}", patype, padata)
+#define TRACE_PREAUTH_TRYAGAIN(c, name, patype, code) \
+ TRACE(c, "Preauth module {str} ({int}) tryagain returned: {kerr}", \
+ name, (int)patype, code)
#define TRACE_PREAUTH_TRYAGAIN_OUTPUT(c, padata) \
TRACE(c, "Followup preauth for next request: {patypes}", padata)
#define TRACE_PREAUTH_WRONG_CONTEXT(c) \
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
index da12204ac..988fca233 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -1340,17 +1340,11 @@ init_creds_step_request(krb5_context context,
if (code != 0)
goto cleanup;
} else {
- if (ctx->preauth_to_use != NULL) {
- /*
- * Retry after an error other than PREAUTH_NEEDED,
- * using ctx->err_padata to figure out what to change.
- */
- code = k5_preauth_tryagain(context, ctx, ctx->preauth_to_use,
- &ctx->request->padata);
- } else {
- /* No preauth supplied, so can't query the plugins. */
- code = KRB5KRB_ERR_GENERIC;
- }
+ /* Retry after an error other than PREAUTH_NEEDED, using error padata
+ * to figure out what to change. */
+ code = k5_preauth_tryagain(context, ctx, ctx->selected_preauth_type,
+ ctx->err_reply, ctx->err_padata,
+ &ctx->request->padata);
if (code != 0) {
/* couldn't come up with anything better */
code = ctx->err_reply->error + ERROR_TABLE_BASE_krb5;
@@ -1535,10 +1529,10 @@ init_creds_step_reply(krb5_context context,
ctx->enc_pa_rep_permitted = TRUE;
code = restart_init_creds_loop(context, ctx, FALSE);
} else {
- if (retry) {
+ if (retry && ctx->selected_preauth_type != KRB5_PADATA_NONE) {
code = 0;
} else {
- /* error + no hints = give up */
+ /* error + no hints (or no preauth mech) = give up */
code = (krb5_error_code)reply_code + ERROR_TABLE_BASE_krb5;
}
}
diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h
index 628f0baa8..8903df232 100644
--- a/src/lib/krb5/krb/int-proto.h
+++ b/src/lib/krb5/krb/int-proto.h
@@ -185,7 +185,8 @@ k5_preauth(krb5_context context, krb5_init_creds_context ctx,
krb5_error_code
k5_preauth_tryagain(krb5_context context, krb5_init_creds_context ctx,
- krb5_pa_data **in_padata, krb5_pa_data ***padata_out);
+ krb5_preauthtype pa_type, krb5_error *err,
+ krb5_pa_data **err_padata, krb5_pa_data ***padata_out);
void
k5_init_preauth_context(krb5_context context);
diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c
index cfe3dd5b0..354234a93 100644
--- a/src/lib/krb5/krb/preauth2.c
+++ b/src/lib/krb5/krb/preauth2.c
@@ -911,49 +911,53 @@ add_s4u_x509_user_padata(krb5_context context, krb5_s4u_userid *userid,
}
/*
- * If one of the modules can adjust its AS_REQ data using the contents of the
- * err_reply, return 0. If it's the sort of correction which requires that we
- * ask the user another question, we let the calling application deal with it.
+ * If the module for pa_type can adjust its AS_REQ data using the contents of
+ * err and err_padata, return 0 with *padata_out set to a padata list for the
+ * next request. If it's the sort of correction which requires that we ask the
+ * user another question, we let the calling application deal with it.
*/
krb5_error_code
k5_preauth_tryagain(krb5_context context, krb5_init_creds_context ctx,
- krb5_pa_data **in_padata, krb5_pa_data ***padata_out)
+ krb5_preauthtype pa_type, krb5_error *err,
+ krb5_pa_data **err_padata, krb5_pa_data ***padata_out)
{
krb5_error_code ret;
krb5_pa_data **mod_pa;
krb5_clpreauth_modreq modreq;
clpreauth_handle h;
- int i, count;
+ int count;
*padata_out = NULL;
- TRACE_PREAUTH_TRYAGAIN_INPUT(context, in_padata);
+ TRACE_PREAUTH_TRYAGAIN_INPUT(context, pa_type, err_padata);
- for (i = 0; in_padata[i] != NULL; i++) {
- h = find_module(context, ctx, in_padata[i]->pa_type, &modreq);
- if (h == NULL)
- continue;
- mod_pa = NULL;
- ret = clpreauth_tryagain(context, h, modreq, ctx->opt, &callbacks,
- (krb5_clpreauth_rock)ctx, ctx->request,
- ctx->inner_request_body,
- ctx->encoded_previous_request,
- in_padata[i]->pa_type,
- ctx->err_reply, ctx->err_padata,
- ctx->prompter, ctx->prompter_data, &mod_pa);
- if (ret == 0 && mod_pa != NULL) {
- for (count = 0; mod_pa[count] != NULL; count++);
- ret = copy_cookie(context, ctx->err_padata, &mod_pa, &count);
- if (ret) {
- krb5_free_pa_data(context, mod_pa);
- return ret;
- }
- TRACE_PREAUTH_TRYAGAIN_OUTPUT(context, mod_pa);
- *padata_out = mod_pa;
- return 0;
- }
+ h = find_module(context, ctx, pa_type, &modreq);
+ if (h == NULL)
+ return KRB5KRB_ERR_GENERIC;
+ mod_pa = NULL;
+ ret = clpreauth_tryagain(context, h, modreq, ctx->opt, &callbacks,
+ (krb5_clpreauth_rock)ctx, ctx->request,
+ ctx->inner_request_body,
+ ctx->encoded_previous_request, pa_type, err,
+ err_padata, ctx->prompter, ctx->prompter_data,
+ &mod_pa);
+ TRACE_PREAUTH_TRYAGAIN(context, h->vt.name, pa_type, ret);
+ if (!ret && mod_pa == NULL)
+ ret = KRB5KRB_ERR_GENERIC;
+ if (ret)
+ return ret;
+
+
+ for (count = 0; mod_pa[count] != NULL; count++);
+ ret = copy_cookie(context, err_padata, &mod_pa, &count);
+ if (ret) {
+ krb5_free_pa_data(context, mod_pa);
+ return ret;
}
- return KRB5KRB_ERR_GENERIC;
+
+ TRACE_PREAUTH_TRYAGAIN_OUTPUT(context, mod_pa);
+ *padata_out = mod_pa;
+ return 0;
}
/* Compile the set of response items for in_padata by invoke each module's