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