|
|
749169 |
From 6a69660d9415bc49948143109759f36b2ad70d1b Mon Sep 17 00:00:00 2001
|
|
|
665228 |
From: Greg Hudson <ghudson@mit.edu>
|
|
|
665228 |
Date: Fri, 13 Jan 2017 12:16:04 -0500
|
|
|
665228 |
Subject: [PATCH] Track preauth failures instead of tries
|
|
|
665228 |
|
|
|
665228 |
In preauth2.c, instead of noting whenever we try a real preauth mech,
|
|
|
665228 |
note when a mechanism fails on our side. Tracking only failures
|
|
|
665228 |
eliminates the need to reset the list for multi-step preauth exchanges
|
|
|
665228 |
or for processing padata in the AS-REP, but we will need the function
|
|
|
665228 |
later for continuing after optimistic preauth failures.
|
|
|
665228 |
|
|
|
665228 |
ticket: 8537
|
|
|
665228 |
(cherry picked from commit a1dc81d22304e77edaa8388c7d7d75cade81dc80)
|
|
|
665228 |
---
|
|
|
665228 |
src/lib/krb5/krb/get_in_tkt.c | 3 --
|
|
|
665228 |
src/lib/krb5/krb/int-proto.h | 3 ++
|
|
|
665228 |
src/lib/krb5/krb/preauth2.c | 65 ++++++++++++++++++++---------------
|
|
|
665228 |
3 files changed, 40 insertions(+), 31 deletions(-)
|
|
|
665228 |
|
|
|
665228 |
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
|
|
|
665228 |
index 48dc00ea6..bc903b6e9 100644
|
|
|
665228 |
--- a/src/lib/krb5/krb/get_in_tkt.c
|
|
|
665228 |
+++ b/src/lib/krb5/krb/get_in_tkt.c
|
|
|
665228 |
@@ -1496,8 +1496,6 @@ init_creds_step_reply(krb5_context context,
|
|
|
665228 |
code = restart_init_creds_loop(context, ctx, FALSE);
|
|
|
665228 |
} else if ((reply_code == KDC_ERR_MORE_PREAUTH_DATA_REQUIRED ||
|
|
|
665228 |
reply_code == KDC_ERR_PREAUTH_REQUIRED) && retry) {
|
|
|
665228 |
- /* reset the list of preauth types to try */
|
|
|
665228 |
- k5_reset_preauth_types_tried(ctx);
|
|
|
665228 |
krb5_free_pa_data(context, ctx->preauth_to_use);
|
|
|
665228 |
ctx->preauth_to_use = ctx->err_padata;
|
|
|
665228 |
ctx->err_padata = NULL;
|
|
|
665228 |
@@ -1547,7 +1545,6 @@ init_creds_step_reply(krb5_context context,
|
|
|
665228 |
goto cleanup;
|
|
|
665228 |
|
|
|
665228 |
/* process any preauth data in the as_reply */
|
|
|
665228 |
- k5_reset_preauth_types_tried(ctx);
|
|
|
665228 |
code = krb5int_fast_process_response(context, ctx->fast_state,
|
|
|
665228 |
ctx->reply, &strengthen_key);
|
|
|
665228 |
if (code != 0)
|
|
|
665228 |
diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h
|
|
|
665228 |
index 8903df232..41a69c207 100644
|
|
|
665228 |
--- a/src/lib/krb5/krb/int-proto.h
|
|
|
665228 |
+++ b/src/lib/krb5/krb/int-proto.h
|
|
|
665228 |
@@ -197,6 +197,9 @@ k5_free_preauth_context(krb5_context context);
|
|
|
665228 |
void
|
|
|
665228 |
k5_reset_preauth_types_tried(krb5_init_creds_context ctx);
|
|
|
665228 |
|
|
|
665228 |
+krb5_error_code
|
|
|
665228 |
+k5_preauth_note_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type);
|
|
|
665228 |
+
|
|
|
665228 |
void
|
|
|
665228 |
k5_preauth_prepare_request(krb5_context context, krb5_get_init_creds_opt *opt,
|
|
|
665228 |
krb5_kdc_req *request);
|
|
|
665228 |
diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c
|
|
|
665228 |
index 354234a93..17f2133b1 100644
|
|
|
665228 |
--- a/src/lib/krb5/krb/preauth2.c
|
|
|
665228 |
+++ b/src/lib/krb5/krb/preauth2.c
|
|
|
665228 |
@@ -54,7 +54,7 @@ struct krb5_preauth_context_st {
|
|
|
665228 |
|
|
|
665228 |
struct krb5_preauth_req_context_st {
|
|
|
665228 |
krb5_context orig_context;
|
|
|
665228 |
- krb5_preauthtype *tried;
|
|
|
665228 |
+ krb5_preauthtype *failed;
|
|
|
665228 |
krb5_clpreauth_modreq *modreqs;
|
|
|
665228 |
};
|
|
|
665228 |
|
|
|
665228 |
@@ -201,11 +201,7 @@ cleanup:
|
|
|
665228 |
free_handles(context, list);
|
|
|
665228 |
}
|
|
|
665228 |
|
|
|
665228 |
-/*
|
|
|
665228 |
- * Reset the memory of which preauth types we have already tried, because we
|
|
|
665228 |
- * are entering a new phase of padata processing (such as the padata in an
|
|
|
665228 |
- * AS-REP).
|
|
|
665228 |
- */
|
|
|
665228 |
+/* Reset the memory of which preauth types we have already tried. */
|
|
|
665228 |
void
|
|
|
665228 |
k5_reset_preauth_types_tried(krb5_init_creds_context ctx)
|
|
|
665228 |
{
|
|
|
665228 |
@@ -213,10 +209,27 @@ k5_reset_preauth_types_tried(krb5_init_creds_context ctx)
|
|
|
665228 |
|
|
|
665228 |
if (reqctx == NULL)
|
|
|
665228 |
return;
|
|
|
665228 |
- free(reqctx->tried);
|
|
|
665228 |
- reqctx->tried = NULL;
|
|
|
665228 |
+ free(reqctx->failed);
|
|
|
665228 |
+ reqctx->failed = NULL;
|
|
|
665228 |
}
|
|
|
665228 |
|
|
|
665228 |
+/* Add pa_type to the list of types which has previously failed. */
|
|
|
665228 |
+krb5_error_code
|
|
|
665228 |
+k5_preauth_note_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type)
|
|
|
665228 |
+{
|
|
|
665228 |
+ krb5_preauth_req_context reqctx = ctx->preauth_reqctx;
|
|
|
665228 |
+ krb5_preauthtype *newptr;
|
|
|
665228 |
+ size_t i;
|
|
|
665228 |
+
|
|
|
665228 |
+ for (i = 0; reqctx->failed != NULL && reqctx->failed[i] != 0; i++);
|
|
|
665228 |
+ newptr = realloc(reqctx->failed, (i + 2) * sizeof(*newptr));
|
|
|
665228 |
+ if (newptr == NULL)
|
|
|
665228 |
+ return ENOMEM;
|
|
|
665228 |
+ reqctx->failed = newptr;
|
|
|
665228 |
+ reqctx->failed[i] = pa_type;
|
|
|
665228 |
+ reqctx->failed[i + 1] = 0;
|
|
|
665228 |
+ return 0;
|
|
|
665228 |
+}
|
|
|
665228 |
|
|
|
665228 |
/* Free the per-krb5_context preauth_context. This means clearing any
|
|
|
665228 |
* plugin-specific context which may have been created, and then
|
|
|
665228 |
@@ -291,7 +304,7 @@ k5_preauth_request_context_fini(krb5_context context,
|
|
|
665228 |
TRACE_PREAUTH_WRONG_CONTEXT(context);
|
|
|
665228 |
}
|
|
|
665228 |
free(reqctx->modreqs);
|
|
|
665228 |
- free(reqctx->tried);
|
|
|
665228 |
+ free(reqctx->failed);
|
|
|
665228 |
free(reqctx);
|
|
|
665228 |
ctx->preauth_reqctx = NULL;
|
|
|
665228 |
}
|
|
|
665228 |
@@ -612,28 +625,17 @@ pa_type_allowed(krb5_init_creds_context ctx, krb5_preauthtype pa_type)
|
|
|
665228 |
pa_type == ctx->allowed_preauth_type;
|
|
|
665228 |
}
|
|
|
665228 |
|
|
|
665228 |
-/*
|
|
|
665228 |
- * If pa_type has already been tried as a real preauth type for this
|
|
|
665228 |
- * authentication, return true. Otherwise ass pa_type to the list of tried
|
|
|
665228 |
- * types and return false.
|
|
|
665228 |
- */
|
|
|
665228 |
+/* Return true if pa_type previously failed during this authentication. */
|
|
|
665228 |
static krb5_boolean
|
|
|
665228 |
-already_tried(krb5_init_creds_context ctx, krb5_preauthtype pa_type)
|
|
|
665228 |
+previously_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type)
|
|
|
665228 |
{
|
|
|
665228 |
krb5_preauth_req_context reqctx = ctx->preauth_reqctx;
|
|
|
665228 |
size_t i;
|
|
|
665228 |
- krb5_preauthtype *newptr;
|
|
|
665228 |
|
|
|
665228 |
- for (i = 0; reqctx->tried != NULL && reqctx->tried[i] != 0; i++) {
|
|
|
665228 |
- if (reqctx->tried[i] == pa_type)
|
|
|
665228 |
+ for (i = 0; reqctx->failed != NULL && reqctx->failed[i] != 0; i++) {
|
|
|
665228 |
+ if (reqctx->failed[i] == pa_type)
|
|
|
665228 |
return TRUE;
|
|
|
665228 |
}
|
|
|
665228 |
- newptr = realloc(reqctx->tried, (i + 2) * sizeof(*newptr));
|
|
|
665228 |
- if (newptr == NULL)
|
|
|
665228 |
- return FALSE;
|
|
|
665228 |
- reqctx->tried = newptr;
|
|
|
665228 |
- reqctx->tried[i] = pa_type;
|
|
|
665228 |
- reqctx->tried[i + 1] = ENCTYPE_NULL;
|
|
|
665228 |
return FALSE;
|
|
|
665228 |
}
|
|
|
665228 |
|
|
|
665228 |
@@ -665,8 +667,8 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx,
|
|
|
665228 |
/* Make sure this type is for the current pass. */
|
|
|
665228 |
if (clpreauth_is_real(context, h, pa->pa_type) != real)
|
|
|
665228 |
continue;
|
|
|
665228 |
- /* Only try a real mechanism once per authentication. */
|
|
|
665228 |
- if (real && already_tried(ctx, pa->pa_type))
|
|
|
665228 |
+ /* Don't try a real mechanism again after failure. */
|
|
|
665228 |
+ if (real && previously_failed(ctx, pa->pa_type))
|
|
|
665228 |
continue;
|
|
|
665228 |
mod_pa = NULL;
|
|
|
665228 |
ret = clpreauth_process(context, h, modreq, ctx->opt, &callbacks,
|
|
|
665228 |
@@ -694,6 +696,12 @@ process_pa_data(krb5_context context, krb5_init_creds_context ctx,
|
|
|
665228 |
/* Save the first error we get from a real preauth type. */
|
|
|
665228 |
k5_save_ctx_error(context, ret, &save);
|
|
|
665228 |
}
|
|
|
665228 |
+ if (real && ret) {
|
|
|
665228 |
+ /* Don't try this mechanism again for this authentication. */
|
|
|
665228 |
+ ret = k5_preauth_note_failed(ctx, pa->pa_type);
|
|
|
665228 |
+ if (ret)
|
|
|
665228 |
+ goto cleanup;
|
|
|
665228 |
+ }
|
|
|
665228 |
}
|
|
|
665228 |
}
|
|
|
665228 |
|
|
|
665228 |
@@ -944,9 +952,10 @@ k5_preauth_tryagain(krb5_context context, krb5_init_creds_context ctx,
|
|
|
665228 |
TRACE_PREAUTH_TRYAGAIN(context, h->vt.name, pa_type, ret);
|
|
|
665228 |
if (!ret && mod_pa == NULL)
|
|
|
665228 |
ret = KRB5KRB_ERR_GENERIC;
|
|
|
665228 |
- if (ret)
|
|
|
665228 |
+ if (ret) {
|
|
|
665228 |
+ k5_preauth_note_failed(ctx, pa_type);
|
|
|
665228 |
return ret;
|
|
|
665228 |
-
|
|
|
665228 |
+ }
|
|
|
665228 |
|
|
|
665228 |
for (count = 0; mod_pa[count] != NULL; count++);
|
|
|
665228 |
ret = copy_cookie(context, err_padata, &mod_pa, &count);
|