svn rev #23422: branches/fast-negotiate/src/lib/krb5/krb/

hartmans@MIT.EDU hartmans at MIT.EDU
Wed Dec 2 11:16:50 EST 2009


http://src.mit.edu/fisheye/changelog/krb5/?cs=23422
Commit By: hartmans
Log Message:
Both in the previous trunk code  and in the fast negotiation code,  referrals and pre-authentication did not work correctly.
In particular, the set of preauthentication mechanisms that had been used in the preauth context, the initial set of mechanisms to try, the fast state, and the negotiated state were not reset whenever the realm changed.

Refactor handling of init_creds loop restarts.  There are three cases
where the loop starts up: at init_creds_init time, when negotiation
needs to restart (fast detected or negotiation not supported), or when
referrals cause the realm to change.  Factor out as much code as
possible to be common in these cases.


Changed Files:
U   branches/fast-negotiate/src/lib/krb5/krb/get_in_tkt.c
Modified: branches/fast-negotiate/src/lib/krb5/krb/get_in_tkt.c
===================================================================
--- branches/fast-negotiate/src/lib/krb5/krb/get_in_tkt.c	2009-12-02 16:16:47 UTC (rev 23421)
+++ branches/fast-negotiate/src/lib/krb5/krb/get_in_tkt.c	2009-12-02 16:16:50 UTC (rev 23422)
@@ -1257,42 +1257,105 @@
     return code;
 }
 
+/** Throw away any state related to specific realm either at the beginning of a
+ * request, or when a realm changes, or when we start to  use FAST after
+ * assuming we would not do so.
+ *
+ * @param padata padata from an error if an error from the realm we now expect
+ * to talk to caused the restart.  Used to infer negotiation characteristics
+ * such as whether FAST is used.
+ */
 static krb5_error_code
 restart_init_creds_loop(krb5_context context,
-                        krb5_init_creds_context *ctx)
+                        struct _krb5_init_creds_context *ctx,
+                        krb5_pa_data **padata)
 {
-    krb5_error_code ret = 0;
+    krb5_error_code code = 0;
     unsigned char random_buf[4];
     krb5_data random_data;
     if (ctx->preauth_to_use) {
         krb5_free_pa_data(context, ctx->preauth_to_use);
         ctx->preauth_to_use = NULL;
     }
+
+    if (ctx->fast_state) {
+        krb5int_fast_free_state(context, ctx->fast_state);
+        ctx->fast_state = NULL;
+    }
+    code = krb5int_fast_make_state(context, &ctx->fast_state);
+    if (code != 0)
+        goto cleanup;
+    ctx->get_data_rock.fast_state = ctx->fast_state;
     krb5_preauth_request_context_init(context);
     if (ctx->encoded_request_body) {
         krb5_free_data(context, ctx->encoded_request_body);
         ctx->encoded_request_body = NULL;
     }
-    ctx->loop_count = 0;
     if (ctx->opte && (ctx->opte->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)) {
-        if ((ret = make_preauth_list(context, ctx->opte->preauth_list,
-                                     ctx->opte->preauth_list_length,
-                                     &ctx->preauth_to_use)))
+        if ((code = make_preauth_list(context, ctx->opte->preauth_list,
+                                      ctx->opte->preauth_list_length,
+                                      &ctx->preauth_to_use)))
             goto cleanup;
     }
 
     /* set the request nonce */
     random_data.length = 4;
     random_data.data = (char *)random_buf;
-    ret = krb5_c_random_make_octets(context, &random_data);
-    if (ret !=0)
+    code = krb5_c_random_make_octets(context, &random_data);
+    if (code !=0)
         goto cleanup;
 /* See RT ticket 3196 at MIT.  If we set the high bit, we
    may have compatibility problems with Heimdal, because
    we (incorrectly) encode this value as signed.  */
     ctx->request->nonce = 0x7fffffff & load_32_n(random_buf);
+    krb5_free_principal(context, ctx->request->server);
+    ctx->request->server = NULL;
+
+    code = build_in_tkt_name(context, ctx->in_tkt_service,
+                             ctx->request->client,
+                             &ctx->request->server);
+    if (code != 0)
+        goto cleanup;
+
+    code = krb5_timeofday(context, &ctx->request_time);
+    if (code != 0)
+        goto cleanup;
+
+    code = krb5int_fast_as_armor(context, ctx->fast_state,
+                                 ctx->opte, ctx->request);
+    if (code != 0)
+        goto cleanup;
+    if (krb5int_upgrade_to_fast_p(context, ctx->fast_state, padata)) {
+        code = krb5int_fast_as_armor(context, ctx->fast_state,
+                                     ctx->opte, ctx->request);
+        if (code != 0)
+            goto cleanup;
+    }
+    /* give the preauth plugins a chance to prep the request body */
+    krb5_preauth_prepare_request(context, ctx->opte, ctx->request);
+
+    ctx->request->from = krb5int_addint32(ctx->request_time,
+                                          ctx->start_time);
+    ctx->request->till = krb5int_addint32(ctx->request->from,
+                                          ctx->tkt_life);
+
+    if (ctx->renew_life > 0) {
+        ctx->request->rtime =
+            krb5int_addint32(ctx->request->from, ctx->renew_life);
+        if (ctx->request->rtime < ctx->request->till) {
+            /* don't ask for a smaller renewable time than the lifetime */
+            ctx->request->rtime = ctx->request->till;
+        }
+        ctx->request->kdc_options &= ~(KDC_OPT_RENEWABLE_OK);
+    } else
+        ctx->request->rtime = 0;
+    code = krb5int_fast_prep_req_body(context, ctx->fast_state,
+                                      ctx->request,
+                                      &ctx->encoded_request_body);
+    if (code != 0)
+        goto cleanup;
 cleanup:
-    return ret;
+    return code;
 }
 
 krb5_error_code KRB5_CALLCONV
@@ -1343,13 +1406,8 @@
 
     opte = ctx->opte;
 
-    code = krb5int_fast_make_state(context, &ctx->fast_state);
-    if (code != 0)
-        goto cleanup;
-
     ctx->get_data_rock.magic = CLIENT_ROCK_MAGIC;
     ctx->get_data_rock.etype = &ctx->etype;
-    ctx->get_data_rock.fast_state = ctx->fast_state;
 
     /* Initialise request parameters as per krb5_get_init_creds() */
     ctx->request->kdc_options = context->kdc_default_options;
@@ -1467,7 +1525,7 @@
         ctx->salt.data = NULL;
     }
 
-    code = restart_init_creds_loop(context, ctx);
+    code = restart_init_creds_loop(context, ctx, NULL);
 
     *pctx = ctx;
 
@@ -1575,49 +1633,7 @@
 {
     krb5_error_code code;
 
-    krb5_free_principal(context, ctx->request->server);
-    ctx->request->server = NULL;
-
-    code = build_in_tkt_name(context, ctx->in_tkt_service,
-                             ctx->request->client,
-                             &ctx->request->server);
-    if (code != 0)
-        goto cleanup;
-
-    if (ctx->loopcount == 0) {
-        code = krb5_timeofday(context, &ctx->request_time);
-        if (code != 0)
-            goto cleanup;
-
-        code = krb5int_fast_as_armor(context, ctx->fast_state,
-                                     ctx->opte, ctx->request);
-        if (code != 0)
-            goto cleanup;
-
-        /* give the preauth plugins a chance to prep the request body */
-        krb5_preauth_prepare_request(context, ctx->opte, ctx->request);
-        code = krb5int_fast_prep_req_body(context, ctx->fast_state,
-                                          ctx->request,
-                                          &ctx->encoded_request_body);
-        if (code != 0)
-            goto cleanup;
-
-        ctx->request->from = krb5int_addint32(ctx->request_time,
-                                              ctx->start_time);
-        ctx->request->till = krb5int_addint32(ctx->request->from,
-                                              ctx->tkt_life);
-
-        if (ctx->renew_life > 0) {
-            ctx->request->rtime =
-                krb5int_addint32(ctx->request->from, ctx->renew_life);
-            if (ctx->request->rtime < ctx->request->till) {
-                /* don't ask for a smaller renewable time than the lifetime */
-                ctx->request->rtime = ctx->request->till;
-            }
-            ctx->request->kdc_options &= ~(KDC_OPT_RENEWABLE_OK);
-        } else
-            ctx->request->rtime = 0;
-    } else if (ctx->loopcount >= MAX_IN_TKT_LOOPS) {
+    if (ctx->loopcount >= MAX_IN_TKT_LOOPS) {
         code = KRB5_GET_IN_TKT_LOOP;
         goto cleanup;
     }
@@ -1680,6 +1696,8 @@
         krb5_free_data(context, ctx->encoded_previous_request);
         ctx->encoded_previous_request = NULL;
     }
+    if (ctx->request->padata)
+        ctx->sent_nontrivial_preauth = 1;
     if (ctx->enc_pa_rep_permitted)
         code = request_enc_pa_rep(&ctx->request->padata);
     if (code)
@@ -1738,10 +1756,10 @@
  */
 static krb5_boolean
 negotiation_requests_restart(krb5_context context,
-                             krb5_init_creds_context *ctx,
+                             struct _krb5_init_creds_context *ctx,
                              krb5_pa_data **padata)
 {
-    if ((ctx->loopcount == 0) &&(!ctx->have_restarted) && (
+    if ((!ctx->have_restarted) && (
             krb5int_upgrade_to_fast_p(context, ctx->fast_state, padata)
             || (ctx->err_reply->error == KDC_ERR_PREAUTH_FAILED &&
                 (!ctx->sent_nontrivial_preauth))))
@@ -1780,14 +1798,14 @@
                                           &ctx->err_reply, &padata, &retry);
         if (code != 0)
             goto cleanup;
-        if (negotiation_requests_restart(context, ctx, out_padata)) {
+        if (negotiation_requests_restart(context, ctx, padata)) {
             ctx->have_restarted = 1;
             krb5_preauth_request_context_fini(context);
+            if ((ctx->fast_state->fast_state_flags & KRB5INT_FAST_DO_FAST) ==0)
+                ctx->enc_pa_rep_permitted = 0;
+            code = restart_init_creds_loop(context, ctx, padata);
             krb5_free_error(context, ctx->err_reply);
             ctx->err_reply = NULL;
-            if ((ctx->fast_state->fast_state_flags & KRB5INT_FAST_DO_FAST) ==0)
-                ctx->enc_pa_rep_permitted = 0;
-            code = restart_init_creds_loop(context, ctx);
         }else if (ctx->err_reply->error == KDC_ERR_PREAUTH_REQUIRED && retry) {
             /* reset the list of preauth types to try */
             krb5_free_pa_data(context, ctx->preauth_to_use);
@@ -1814,6 +1832,12 @@
             /* this will trigger a new call to krb5_do_preauth() */
             krb5_free_error(context, ctx->err_reply);
             ctx->err_reply = NULL;
+            krb5_preauth_request_context_fini(context);
+            ctx->have_restarted = 0; /*permit another negotiation based restart*/
+            ctx->sent_nontrivial_preauth = 0;
+            code = restart_init_creds_loop(context, ctx, NULL);
+            if (code != 0)
+                goto cleanup;
         } else {
             if (retry) {
                 code = 0;
@@ -1942,7 +1966,7 @@
     if (ctx->opte&&ctx->opte->opt_private->out_ccache) {
         krb5_ccache out_ccache = ctx->opte->opt_private->out_ccache;
         krb5_data config_data;
-        code = krb5_cc_initialize(context, out_ccache, ctx->cred->client);
+        code = krb5_cc_initialize(context, out_ccache, ctx->cred.client);
         if (code != 0)
             goto cc_cleanup;
         code = krb5_cc_store_cred(context, out_ccache, &ctx->cred);




More information about the cvs-krb5 mailing list