From: Sam Hartman Date: Thu, 26 Mar 2009 05:36:58 +0000 (+0000) Subject: Client AS-req error handling for FAST X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=11320a91a70af55ee6139e8f3a125b8f13f47d91;p=thirdparty%2Fkrb5.git Client AS-req error handling for FAST Find and decode the fast_response and fx_error. Pull out padata and re-encode as typed-data * Implement krb5_free_typed_data * implement error handling logic in krb5int_fast_handle_error * Implement krb5int_find_pa_data git-svn-id: svn://anonsvn.mit.edu/krb5/branches/fast@22131 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/include/k5-int-pkinit.h b/src/include/k5-int-pkinit.h index e75c8031f8..2fb5f87192 100644 --- a/src/include/k5-int-pkinit.h +++ b/src/include/k5-int-pkinit.h @@ -101,6 +101,9 @@ typedef struct _krb5_trusted_ca { } krb5_trusted_ca; /* typed data */ +/* The FAST error handling logic currently assumes that this structure and krb5_pa_data * can be safely cast to each other + * if this structure changes, that code needs to be updated to copy. + */ typedef struct _krb5_typed_data { krb5_magic magic; krb5_int32 type; @@ -267,4 +270,6 @@ krb5_error_code decode_krb5_td_trusted_certifiers krb5_error_code decode_krb5_td_dh_parameters (const krb5_data *, krb5_algorithm_identifier ***); +void krb5_free_typed_data(krb5_context, krb5_typed_data **); + #endif /* _KRB5_INT_PKINIT_H */ diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 8d5d817f8f..957f39c8c5 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -1074,6 +1074,10 @@ krb5_error_code krb5_process_padata krb5_creds *, krb5_int32 *); +krb5_pa_data * krb5int_find_pa_data +(krb5_context, krb5_pa_data * const *, krb5_preauthtype); +/* Does not return a copy; original padata sequence responsible for freeing*/ + void krb5_free_etype_info (krb5_context, krb5_etype_info); diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c index a6d8eabe49..b7db1edb26 100644 --- a/src/kdc/kdc_util.c +++ b/src/kdc/kdc_util.c @@ -217,17 +217,7 @@ comp_cksum(krb5_context kcontext, krb5_data *source, krb5_ticket *ticket, krb5_pa_data * find_pa_data(krb5_pa_data **padata, krb5_preauthtype pa_type) { - krb5_pa_data **tmppa; - - if (padata == NULL) - return NULL; - - for (tmppa = padata; *tmppa != NULL; tmppa++) { - if ((*tmppa)->pa_type == pa_type) - break; - } - - return *tmppa; +return krb5int_find_pa_data(kdc_context, padata, pa_type); } krb5_error_code diff --git a/src/lib/krb5/krb/fast.c b/src/lib/krb5/krb/fast.c index e224a2d84f..446a621266 100644 --- a/src/lib/krb5/krb/fast.c +++ b/src/lib/krb5/krb/fast.c @@ -153,24 +153,88 @@ krb5int_fast_process_error(krb5_context context, struct krb5int_fast_request_sta { krb5_error_code retval = 0; krb5_error *err_reply = *err_replyptr; - *retry = (err_reply->e_data.length > 0); *out_padata = NULL; - if ((err_reply->error == KDC_ERR_PREAUTH_REQUIRED - ||err_reply->error == KDC_ERR_PREAUTH_FAILED) && err_reply->e_data.length) { + if (state->armor_key) { + krb5_pa_data *fast_pa, *fx_error_pa; krb5_pa_data **result = NULL; + krb5_data scratch, *encoded_td = NULL; + krb5_error *fx_error = NULL; + krb5_fast_response *fast_response = NULL; retval = decode_krb5_padata_sequence(&err_reply->e_data, &result); if (retval == 0) - if (retval == 0) { - *out_padata = result; - + fast_pa = krb5int_find_pa_data(context, result, KRB5_PADATA_FX_FAST); + if (retval || fast_pa == NULL) { + /*This can happen if the KDC does not understand FAST. We + * don't expect that, but treating it as the fatal error + * indicated by the KDC seems reasonable. + */ + *retry = 0; + krb5_free_pa_data(context, result); return 0; } + scratch.data = (char *) fast_pa->contents; + scratch.length = fast_pa->length; + retval = decode_krb5_fast_response(&scratch, &fast_response); krb5_free_pa_data(context, result); - krb5_set_error_message(context, retval, - "Error decoding padata in error reply"); - return retval; - } - return 0; + result = NULL; + if (retval == 0) { + fx_error_pa = krb5int_find_pa_data(context, fast_response->padata, KRB5_PADATA_FX_ERROR); + if (fx_error_pa == NULL) { + krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED, "Expecting FX_ERROR pa-data inside FAST container"); + retval = KRB5KDC_ERR_PREAUTH_FAILED; + } + } + if (retval == 0) { + scratch.data = (char *) fx_error_pa->contents; + scratch.length = fx_error_pa->length; + retval = decode_krb5_error(&scratch, &fx_error); + } + /* + * krb5_pa_data and krb5_typed_data are safe to cast between: + * they have the same type fields in the same order. + * (krb5_preauthtype is a krb5_int32). If krb5_typed_data is + * ever changed then this will need to be a copy not a cast. + */ + if (retval == 0) + retval = encode_krb5_typed_data( (krb5_typed_data **) fast_response->padata, + &encoded_td); + if (retval == 0) { + fx_error->e_data = *encoded_td; + free(encoded_td); /*contents owned by fx_error*/ + encoded_td = NULL; + krb5_free_error(context, err_reply); + *err_replyptr = fx_error; + fx_error = NULL; + *out_padata = fast_response->padata; + fast_response->padata = NULL; + /* + * If there is more than the fx_error padata, then we want + * to retry the error + */ + *retry = (*out_padata)[1] != NULL; + } + if (fx_error) + krb5_free_error(context, fx_error); + krb5_free_fast_response(context, fast_response); + } else { /*not FAST*/ + *retry = (err_reply->e_data.length > 0); + if ((err_reply->error == KDC_ERR_PREAUTH_REQUIRED + ||err_reply->error == KDC_ERR_PREAUTH_FAILED) && err_reply->e_data.length) { + krb5_pa_data **result = NULL; + retval = decode_krb5_padata_sequence(&err_reply->e_data, &result); + if (retval == 0) + if (retval == 0) { + *out_padata = result; + + return 0; + } + krb5_free_pa_data(context, result); + krb5_set_error_message(context, retval, + "Error decoding padata in error reply"); + return retval; + } + } + return retval; } krb5_error_code @@ -194,3 +258,20 @@ krb5int_fast_free_state( krb5_context context, struct krb5int_fast_request_state krb5_free_fast_armor(context, state->armor); krb5_free_data_contents(context, &state->cookie_contents); } + +krb5_pa_data * krb5int_find_pa_data +(krb5_context context, krb5_pa_data *const *padata, krb5_preauthtype pa_type) +{ + krb5_pa_data * const *tmppa; + + if (padata == NULL) + return NULL; + + for (tmppa = padata; *tmppa != NULL; tmppa++) { + if ((*tmppa)->pa_type == pa_type) + break; + } + + return *tmppa; +} + diff --git a/src/lib/krb5/krb/kfree.c b/src/lib/krb5/krb/kfree.c index a1f71c1eda..5813fc0242 100644 --- a/src/lib/krb5/krb/kfree.c +++ b/src/lib/krb5/krb/kfree.c @@ -831,3 +831,16 @@ void krb5_free_fast_finished krb5_free_checksum_contents(context, &val->checksum); krb5_free_checksum_contents(context, &val->ticket_checksum); } + +void krb5_free_typed_data(krb5_context context, krb5_typed_data **in) +{ + int i = 0; + if (in == NULL) return; + while (in[i] != NULL) { + if (in[i]->data != NULL) + free(in[i]->data); + free(in[i]); + i++; + } + free(in); +} diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports index 886553c222..17b8fd3c65 100644 --- a/src/lib/krb5/libkrb5.exports +++ b/src/lib/krb5/libkrb5.exports @@ -37,6 +37,7 @@ decode_krb5_setpw_req decode_krb5_tgs_rep decode_krb5_tgs_req decode_krb5_ticket +decode_krb5_typed_data encode_krb5_alt_method encode_krb5_ap_rep encode_krb5_ap_rep_enc_part @@ -269,6 +270,7 @@ krb5_free_tgt_creds krb5_free_ticket krb5_free_tickets krb5_free_tkt_authent +krb5_free_typed_data krb5_free_unparsed_name krb5_fwd_tgt_creds krb5_gen_portaddr @@ -519,6 +521,7 @@ krb5int_cc_default krb5int_cleanup_library krb5int_cm_call_select krb5int_copy_data_contents_add0 +krb5int_find_pa_data krb5int_foreach_localaddr krb5int_free_addrlist krb5int_init_context_kdc