Blame SOURCES/Continue-preauth-after-client-side-failures.patch

749169
From d45e1ea83a6ed9eef0e7e6bfe86c8d4995a7402d Mon Sep 17 00:00:00 2001
665228
From: Greg Hudson <ghudson@mit.edu>
665228
Date: Sat, 14 Jan 2017 13:55:22 -0500
665228
Subject: [PATCH] Continue preauth after client-side failures
665228
665228
If the module for the selected preauth mechanism fails when processing
665228
a KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error, or fails a tryagain
665228
operation, try again with a different preauth mech using the cached
665228
method data.
665228
665228
If optimistic preauth fails on the client side, send an
665228
unauthenticated request, allowing the mechanisms we tried
665228
optimistically to be tried again.
665228
665228
ticket: 8537
665228
(cherry picked from commit 644840a207917661a6ccf706e7830bec273e23b3)
665228
---
665228
 src/lib/krb5/krb/get_in_tkt.c | 49 +++++++++++++++++++++++------------
665228
 1 file changed, 32 insertions(+), 17 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 8c7919e65..8d0f964f9 100644
665228
--- a/src/lib/krb5/krb/get_in_tkt.c
665228
+++ b/src/lib/krb5/krb/get_in_tkt.c
665228
@@ -1307,6 +1307,7 @@ init_creds_step_request(krb5_context context,
665228
 {
665228
     krb5_error_code code;
665228
     krb5_preauthtype pa_type;
665228
+    struct errinfo save = EMPTY_ERRINFO;
665228
 
665228
     if (ctx->loopcount >= MAX_IN_TKT_LOOPS) {
665228
         code = KRB5_GET_IN_TKT_LOOP;
665228
@@ -1341,38 +1342,51 @@ init_creds_step_request(krb5_context context,
665228
     if (ctx->optimistic_padata != NULL) {
665228
         /* Our first attempt, using an optimistic padata list. */
665228
         TRACE_INIT_CREDS_PREAUTH_OPTIMISTIC(context);
665228
-        code = k5_preauth(context, ctx, ctx->optimistic_padata, FALSE,
665228
+        code = k5_preauth(context, ctx, ctx->optimistic_padata, TRUE,
665228
                           &ctx->request->padata, &ctx->selected_preauth_type);
665228
         krb5_free_pa_data(context, ctx->optimistic_padata);
665228
         ctx->optimistic_padata = NULL;
665228
-        if (code != 0)
665228
-            goto cleanup;
665228
+        if (code) {
665228
+            /* Make an unauthenticated request, and possibly try again using
665228
+             * the same mechanisms as we tried optimistically. */
665228
+            k5_reset_preauth_types_tried(ctx);
665228
+            krb5_clear_error_message(context);
665228
+            code = 0;
665228
+        }
665228
     } if (ctx->more_padata != NULL) {
665228
         /* Continuing after KDC_ERR_MORE_PREAUTH_DATA_REQUIRED. */
665228
         TRACE_INIT_CREDS_PREAUTH_MORE(context, ctx->selected_preauth_type);
665228
         code = k5_preauth(context, ctx, ctx->more_padata, TRUE,
665228
                           &ctx->request->padata, &pa_type);
665228
-        if (code != 0)
665228
-            goto cleanup;
665228
     } else if (ctx->err_reply != NULL &&
665228
-               ctx->err_reply->error == KDC_ERR_PREAUTH_REQUIRED) {
665228
-        /* Continuing after KDC_ERR_PREAUTH_REQUIRED, using method data. */
665228
-        TRACE_INIT_CREDS_PREAUTH(context);
665228
-        code = k5_preauth(context, ctx, ctx->method_padata, TRUE,
665228
-                          &ctx->request->padata, &ctx->selected_preauth_type);
665228
-        if (code != 0)
665228
-            goto cleanup;
665228
-    } else if (ctx->err_reply != NULL) {
665228
-        /* Retry after an error other than PREAUTH_REQUIRED, using error padata
665228
-         * to figure out what to change. */
665228
+               ctx->err_reply->error != KDC_ERR_PREAUTH_REQUIRED) {
665228
+        /* Retrying after an error (possibly mechanism-specific), using error
665228
+         * padata to figure out what to change. */
665228
         TRACE_INIT_CREDS_PREAUTH_TRYAGAIN(context, ctx->err_reply->error,
665228
                                           ctx->selected_preauth_type);
665228
         code = k5_preauth_tryagain(context, ctx, ctx->selected_preauth_type,
665228
                                    ctx->err_reply, ctx->err_padata,
665228
                                    &ctx->request->padata);
665228
-        if (code != 0) {
665228
-            /* couldn't come up with anything better */
665228
+        if (code) {
665228
+            krb5_clear_error_message(context);
665228
             code = ctx->err_reply->error + ERROR_TABLE_BASE_krb5;
665228
+        }
665228
+    }
665228
+    if (code) {
665228
+        /* See if we can try a different preauth mech before giving up. */
665228
+        k5_save_ctx_error(context, code, &save);
665228
+        ctx->selected_preauth_type = KRB5_PADATA_NONE;
665228
+    }
665228
+
665228
+    if (ctx->request->padata == NULL && ctx->method_padata != NULL) {
665228
+        /* Retrying after KDC_ERR_PREAUTH_REQUIRED, or trying again with a
665228
+         * different mechanism after a client-side failure. */
665228
+        TRACE_INIT_CREDS_PREAUTH(context);
665228
+        code = k5_preauth(context, ctx, ctx->method_padata, TRUE,
665228
+                          &ctx->request->padata, &ctx->selected_preauth_type);
665228
+        if (code) {
665228
+            if (save.code != 0)
665228
+                code = k5_restore_ctx_error(context, &save);
665228
             goto cleanup;
665228
         }
665228
     }
665228
@@ -1413,6 +1427,7 @@ init_creds_step_request(krb5_context context,
665228
 cleanup:
665228
     krb5_free_pa_data(context, ctx->request->padata);
665228
     ctx->request->padata = NULL;
665228
+    k5_clear_error(&save);
665228
     return code;
665228
 }
665228