code = restart_init_creds_loop(context, ctx, FALSE);
} 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(ctx);
krb5_free_pa_data(context, ctx->preauth_to_use);
ctx->preauth_to_use = ctx->err_padata;
ctx->err_padata = NULL;
goto cleanup;
/* process any preauth data in the as_reply */
- k5_reset_preauth_types_tried(ctx);
code = krb5int_fast_process_response(context, ctx->fast_state,
ctx->reply, &strengthen_key);
if (code != 0)
struct krb5_preauth_req_context_st {
krb5_context orig_context;
- krb5_preauthtype *tried;
+ krb5_preauthtype *failed;
krb5_clpreauth_modreq *modreqs;
};
free_handles(context, list);
}
-/*
- * Reset the memory of which preauth types we have already tried, because we
- * are entering a new phase of padata processing (such as the padata in an
- * AS-REP).
- */
+/* Reset the memory of which preauth types we have already tried. */
void
k5_reset_preauth_types_tried(krb5_init_creds_context ctx)
{
if (reqctx == NULL)
return;
- free(reqctx->tried);
- reqctx->tried = NULL;
+ free(reqctx->failed);
+ reqctx->failed = NULL;
}
+/* Add pa_type to the list of types which has previously failed. */
+krb5_error_code
+k5_preauth_note_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type)
+{
+ krb5_preauth_req_context reqctx = ctx->preauth_reqctx;
+ krb5_preauthtype *newptr;
+ size_t i;
+
+ for (i = 0; reqctx->failed != NULL && reqctx->failed[i] != 0; i++);
+ newptr = realloc(reqctx->failed, (i + 2) * sizeof(*newptr));
+ if (newptr == NULL)
+ return ENOMEM;
+ reqctx->failed = newptr;
+ reqctx->failed[i] = pa_type;
+ reqctx->failed[i + 1] = 0;
+ return 0;
+}
/* Free the per-krb5_context preauth_context. This means clearing any
* plugin-specific context which may have been created, and then
TRACE_PREAUTH_WRONG_CONTEXT(context);
}
free(reqctx->modreqs);
- free(reqctx->tried);
+ free(reqctx->failed);
free(reqctx);
ctx->preauth_reqctx = NULL;
}
pa_type == ctx->allowed_preauth_type;
}
-/*
- * If pa_type has already been tried as a real preauth type for this
- * authentication, return true. Otherwise ass pa_type to the list of tried
- * types and return false.
- */
+/* Return true if pa_type previously failed during this authentication. */
static krb5_boolean
-already_tried(krb5_init_creds_context ctx, krb5_preauthtype pa_type)
+previously_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type)
{
krb5_preauth_req_context reqctx = ctx->preauth_reqctx;
size_t i;
- krb5_preauthtype *newptr;
- for (i = 0; reqctx->tried != NULL && reqctx->tried[i] != 0; i++) {
- if (reqctx->tried[i] == pa_type)
+ for (i = 0; reqctx->failed != NULL && reqctx->failed[i] != 0; i++) {
+ if (reqctx->failed[i] == pa_type)
return TRUE;
}
- newptr = realloc(reqctx->tried, (i + 2) * sizeof(*newptr));
- if (newptr == NULL)
- return FALSE;
- reqctx->tried = newptr;
- reqctx->tried[i] = pa_type;
- reqctx->tried[i + 1] = ENCTYPE_NULL;
return FALSE;
}
/* Make sure this type is for the current pass. */
if (clpreauth_is_real(context, h, pa->pa_type) != real)
continue;
- /* Only try a real mechanism once per authentication. */
- if (real && already_tried(ctx, pa->pa_type))
+ /* Don't try a real mechanism again after failure. */
+ if (real && previously_failed(ctx, pa->pa_type))
continue;
mod_pa = NULL;
ret = clpreauth_process(context, h, modreq, ctx->opt, &callbacks,
/* Save the first error we get from a real preauth type. */
k5_save_ctx_error(context, ret, &save);
}
+ if (real && ret) {
+ /* Don't try this mechanism again for this authentication. */
+ ret = k5_preauth_note_failed(ctx, pa->pa_type);
+ if (ret)
+ goto cleanup;
+ }
}
}
TRACE_PREAUTH_TRYAGAIN(context, h->vt.name, pa_type, ret);
if (!ret && mod_pa == NULL)
ret = KRB5KRB_ERR_GENERIC;
- if (ret)
+ if (ret) {
+ k5_preauth_note_failed(ctx, pa_type);
return ret;
-
+ }
for (count = 0; mod_pa[count] != NULL; count++);
ret = copy_cookie(context, err_padata, &mod_pa, &count);