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

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


http://src.mit.edu/fisheye/changelog/krb5/?cs=23421
Commit By: hartmans
Log Message:
While developing the fast negotiation changes, the get_in_tkt code was
reorganized to be more maintainable and asynchronous.  This commit
forward ports old changes found in users/hartmans/fast-negotiate to
the new architecture.  All the changes were ported at once rather than
porting each individual change.


Changed Files:
U   branches/fast-negotiate/src/lib/krb5/krb/get_in_tkt.c
U   branches/fast-negotiate/src/lib/krb5/krb/init_creds_ctx.h
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:44 UTC (rev 23420)
+++ branches/fast-negotiate/src/lib/krb5/krb/get_in_tkt.c	2009-12-02 16:16:47 UTC (rev 23421)
@@ -545,6 +545,29 @@
             && data_eq(tgt->server->realm, tgt->client->realm));
 }
 
+static krb5_error_code request_enc_pa_rep(krb5_pa_data ***padptr)
+{
+    size_t size = 0;
+    krb5_pa_data **pad = *padptr;
+    krb5_pa_data *pa= NULL;
+    if (pad)
+        for (size=0; pad[size]; size++);
+    pad = realloc(pad, sizeof(*pad)*(size+2));
+
+    if (pad == NULL)
+        return ENOMEM;
+    pad[size+1] = NULL;
+    pa = malloc(sizeof(krb5_pa_data));
+    if (pa == NULL)
+        return ENOMEM;
+    pa->contents = NULL;
+    pa->length = 0;
+    pa->pa_type = KRB5_ENCPADATA_REQ_ENC_PA_REP;
+    pad[size] = pa;
+    *padptr = pad;
+    return 0;
+}
+
 krb5_error_code KRB5_CALLCONV
 krb5_get_in_tkt(krb5_context context,
                 krb5_flags options,
@@ -1234,6 +1257,44 @@
     return code;
 }
 
+static krb5_error_code
+restart_init_creds_loop(krb5_context context,
+                        krb5_init_creds_context *ctx)
+{
+    krb5_error_code ret = 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;
+    }
+    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)))
+            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)
+        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);
+cleanup:
+    return ret;
+}
+
 krb5_error_code KRB5_CALLCONV
 krb5_init_creds_init(krb5_context context,
                      krb5_principal client,
@@ -1256,7 +1317,7 @@
     ctx->request = k5alloc(sizeof(krb5_kdc_req), &code);
     if (code != 0)
         goto cleanup;
-
+    ctx->enc_pa_rep_permitted = 1;
     code = krb5_copy_principal(context, client, &ctx->request->client);
     if (code != 0)
         goto cleanup;
@@ -1388,8 +1449,8 @@
         if (code != 0)
             goto cleanup;
     } else if (krb5_libdefault_boolean(context, &ctx->request->client->realm,
-                                     KRB5_CONF_NOADDRESSES, &tmp) != 0
-             || tmp) {
+                                       KRB5_CONF_NOADDRESSES, &tmp) != 0
+               || tmp) {
         ctx->request->addresses = NULL;
     } else {
         code = krb5_os_localaddr(context, &ctx->request->addresses);
@@ -1397,18 +1458,6 @@
             goto cleanup;
     }
 
-    /* initial preauth state */
-    krb5_preauth_request_context_init(context);
-
-    if (opte->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) {
-        code = make_preauth_list(context,
-                                 opte->preauth_list,
-                                 opte->preauth_list_length,
-                                 &ctx->preauth_to_use);
-        if (code != 0)
-            goto cleanup;
-    }
-
     if (opte->flags & KRB5_GET_INIT_CREDS_OPT_SALT) {
         code = krb5int_copy_data_contents(context, opte->salt, &ctx->salt);
         if (code != 0)
@@ -1418,34 +1467,8 @@
         ctx->salt.data = NULL;
     }
 
-    /* nonce */
-    {
-        unsigned char random_buf[4];
-        krb5_data random_data;
+    code = restart_init_creds_loop(context, ctx);
 
-        random_data.length = sizeof(random_buf);
-        random_data.data = (char *)random_buf;
-
-        /*
-         * 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.
-         */
-        if (krb5_c_random_make_octets(context, &random_data) == 0)
-            ctx->request->nonce = 0x7fffffff & load_32_n(random_buf);
-        else {
-            krb5_timestamp now;
-
-            code = krb5_timeofday(context, &now);
-            if (code != 0)
-                goto cleanup;
-
-            ctx->request->nonce = (krb5_int32)now;
-        }
-    }
-
-    ctx->loopcount = 0;
-
     *pctx = ctx;
 
 cleanup:
@@ -1657,7 +1680,10 @@
         krb5_free_data(context, ctx->encoded_previous_request);
         ctx->encoded_previous_request = NULL;
     }
-
+    if (ctx->enc_pa_rep_permitted)
+        code = request_enc_pa_rep(&ctx->request->padata);
+    if (code)
+        goto cleanup;
     code = krb5int_fast_prep_req(context, ctx->fast_state,
                                  ctx->request, ctx->encoded_request_body,
                                  encode_krb5_as_req,
@@ -1675,6 +1701,54 @@
     return code;
 }
 
+/* The control flow is complicated.  In order to switch from non-FAST mode
+ * to FAST mode, we need to reset our pre-authentication state.  FAST
+ * negotiation attempts to make sure we rarely have to do this.  When FAST
+ * negotiation is working, we record whether FAST is available when we
+ * obtain an armor ticket; if so, we start out with FAST enabled .  There
+ * are two complicated situations.
+ *
+ * First, if we get a PREAUTH_REQUIRED error including PADATA_FX_FAST back from
+ * a KDC in a case where we were not expecting to use FAST, and we have an
+ * armor ticket available, then we want to use  FAST.   That involves
+ * clearing out the pre-auth state, reinitializing the plugins and trying
+ * again with an armor key.
+ *
+ * Secondly, using the negotiation can cause problems with some older
+ * KDCs.  Negotiation involves including a special padata item.  Some KDCs,
+ * including MIT prior to 1.7, will return PREAUTH_FAILED rather than
+ * PREAUTH_REQUIRED in pre-authentication is required and unknown padata are
+ * included in the request.  To make matters worse, these KDCs typically do
+ * not include a list of padata in PREAUTH_FAILED errors.  So, if we get
+ * PREAUTH_FAILED and we generated no pre-authentication other than the
+ * negotiation then we want to retry without negotiation.  In this case it
+ * is probably also desirable to retry  with the preauth plugin state cleared.
+ *
+ * In all these cases we should not start over more than once.  Control
+ *  flow is managed  by several variables.
+ *
+ *  sent_nontrivial_preauth: if true, we sent preauth other than
+ * negotiation; no restart on PREAUTH_FAILED
+ *
+ *                          KRB5INT_FAST_ARMOR_AVAIL: fast_state_flag
+ *  if desired we could generate armor; if not set, then we can't use FAST
+ *  even if the KDC wants to.
+ *
+ *  have_restarted: true if we've already restarted
+ */
+static krb5_boolean
+negotiation_requests_restart(krb5_context context,
+                             krb5_init_creds_context *ctx,
+                             krb5_pa_data **padata)
+{
+    if ((ctx->loopcount == 0) &&(!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))))
+        return 1;
+    return 0;
+}
+
 static krb5_error_code
 init_creds_step_reply(krb5_context context,
                       krb5_init_creds_context ctx,
@@ -1687,6 +1761,7 @@
     int canon_flag = 0;
     krb5_keyblock *strengthen_key = NULL;
     krb5_keyblock encrypting_key;
+    krb5_boolean fast_avail;
 
     encrypting_key.length = 0;
     encrypting_key.contents = NULL;
@@ -1705,8 +1780,15 @@
                                           &ctx->err_reply, &padata, &retry);
         if (code != 0)
             goto cleanup;
-
-        if (ctx->err_reply->error == KDC_ERR_PREAUTH_REQUIRED && retry) {
+        if (negotiation_requests_restart(context, ctx, out_padata)) {
+            ctx->have_restarted = 1;
+            krb5_preauth_request_context_fini(context);
+            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);
             ctx->preauth_to_use = padata;
@@ -1738,7 +1820,7 @@
             } else {
                 /* error + no hints = give up */
                 code = (krb5_error_code)ctx->err_reply->error +
-                       ERROR_TABLE_BASE_krb5;
+                    ERROR_TABLE_BASE_krb5;
             }
         }
 
@@ -1812,7 +1894,7 @@
        again.  */
     if (ctx->as_key.length) {
         code = krb5int_fast_reply_key(context, strengthen_key, &ctx->as_key,
-                                     &encrypting_key);
+                                      &encrypting_key);
         if (code != 0)
             goto cleanup;
         code = decrypt_as_reply(context, NULL, ctx->reply, NULL, NULL,
@@ -1843,6 +1925,11 @@
             goto cleanup;
     }
 
+    code = krb5int_fast_verify_nego(context, ctx->fast_state,
+                                    ctx->reply, ctx->encoded_previous_request,
+                                    &encrypting_key, &fast_avail);
+    if (code)
+        goto cleanup;
     code = verify_as_reply(context, ctx->request_time,
                            ctx->request, ctx->reply);
     if (code != 0)
@@ -1852,6 +1939,29 @@
                           ctx->reply, &ctx->cred, NULL);
     if (code != 0)
         goto cleanup;
+    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);
+        if (code != 0)
+            goto cc_cleanup;
+        code = krb5_cc_store_cred(context, out_ccache, &ctx->cred);
+        if (code != 0)
+            goto cc_cleanup;
+        if (fast_avail) {
+            config_data.data = "yes";
+            config_data.length = strlen(config_data.data);
+            code = krb5_cc_set_config(context, out_ccache, ctx->cred.server,
+                                      KRB5_CCCONF_FAST_AVAIL, &config_data);
+        }
+    cc_cleanup:
+        if (code !=0) {
+            const char *msg;
+            msg = krb5_get_error_message(context, code);
+            krb5_set_error_message(context, code, "%s while storing credentials", msg);
+            krb5_free_error_message(context, msg);
+        }
+    }
 
     krb5_preauth_request_context_fini(context);
 
@@ -2002,4 +2112,3 @@
 
     return code;
 }
-

Modified: branches/fast-negotiate/src/lib/krb5/krb/init_creds_ctx.h
===================================================================
--- branches/fast-negotiate/src/lib/krb5/krb/init_creds_ctx.h	2009-12-02 16:16:44 UTC (rev 23420)
+++ branches/fast-negotiate/src/lib/krb5/krb/init_creds_ctx.h	2009-12-02 16:16:47 UTC (rev 23421)
@@ -49,4 +49,3 @@
                          void *gak_data);
 
 #endif /* !KRB5_INIT_CREDS_CONTEXT */
-




More information about the cvs-krb5 mailing list