diff options
Diffstat (limited to 'src/lib/krb5/krb/preauth2.c')
-rw-r--r-- | src/lib/krb5/krb/preauth2.c | 224 |
1 files changed, 106 insertions, 118 deletions
diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index e50440e..6238a82 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -35,7 +35,7 @@ typedef krb5_error_code (*pa_function)(krb5_context, krb5_kdc_req *request, krb5_pa_data *in_padata, krb5_pa_data **out_padata, - krb5_data *salt, + krb5_data *salt, krb5_data *s2kparams, krb5_enctype *etype, krb5_keyblock *as_key, krb5_prompter_fct prompter_fct, @@ -57,7 +57,7 @@ krb5_error_code pa_salt(krb5_context context, krb5_kdc_req *request, krb5_pa_data *in_padata, krb5_pa_data **out_padata, - krb5_data *salt, + krb5_data *salt, krb5_data *s2kparams, krb5_enctype *etype, krb5_keyblock *as_key, krb5_prompter_fct prompter, void *prompter_data, @@ -65,22 +65,11 @@ krb5_error_code pa_salt(krb5_context context, { krb5_data tmp; - /* screw the abstraction. If there was a *reasonable* copy_data, - I'd use it. But I'm inside the library, which is the twilight - zone of source code, so I can do anything. */ - + tmp.data = in_padata->contents; tmp.length = in_padata->length; - if (tmp.length) { - if ((tmp.data = malloc(tmp.length)) == NULL) - return ENOMEM; - memcpy(tmp.data, in_padata->contents, tmp.length); - } else { - tmp.data = NULL; - } - - *salt = tmp; - - /* assume that no other salt was allocated */ + krb5_free_data_contents(context, salt); + krb5int_copy_data_contents(context, &tmp, salt); + if (in_padata->pa_type == KRB5_PADATA_AFS3_SALT) salt->length = SALT_TYPE_AFS_LENGTH; @@ -94,6 +83,7 @@ krb5_error_code pa_enc_timestamp(krb5_context context, krb5_pa_data *in_padata, krb5_pa_data **out_padata, krb5_data *salt, + krb5_data *s2kparams, krb5_enctype *etype, krb5_keyblock *as_key, krb5_prompter_fct prompter, @@ -119,7 +109,7 @@ krb5_error_code pa_enc_timestamp(krb5_context context, if ((ret = ((*gak_fct)(context, request->client, *etype ? *etype : request->ktype[0], prompter, prompter_data, - salt, as_key, gak_data)))) + salt, s2kparams, as_key, gak_data)))) return(ret); } @@ -233,6 +223,7 @@ krb5_error_code pa_sam(krb5_context context, krb5_pa_data *in_padata, krb5_pa_data **out_padata, krb5_data *salt, + krb5_data *s2kparams, krb5_enctype *etype, krb5_keyblock *as_key, krb5_prompter_fct prompter, @@ -283,7 +274,7 @@ krb5_error_code pa_sam(krb5_context context, *etype = ENCTYPE_DES_CBC_CRC; if ((ret = (gak_fct)(context, request->client, *etype, prompter, - prompter_data, salt, as_key, gak_data))) + prompter_data, salt, s2kparams, as_key, gak_data))) return(ret); } sprintf(name, "%.*s", @@ -472,6 +463,7 @@ krb5_error_code pa_sam_2(krb5_context context, krb5_pa_data *in_padata, krb5_pa_data **out_padata, krb5_data *salt, + krb5_data *s2kparams, krb5_enctype *etype, krb5_keyblock *as_key, krb5_prompter_fct prompter, @@ -542,7 +534,7 @@ krb5_error_code pa_sam_2(krb5_context context, retval = (gak_fct)(context, request->client, sc2b->sam_etype, prompter, - prompter_data, salt, as_key, gak_data); + prompter_data, salt, s2kparams, as_key, gak_data); if (retval) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); @@ -827,87 +819,19 @@ static const pa_types_t pa_types[] = { }, }; -static void -sort_etype_info(krb5_context context, krb5_kdc_req *request, - krb5_etype_info_entry **etype_info) -{ -/* Originally adapted from a proposed solution in ticket 1006. This - * solution is not efficient, but implementing an efficient sort - * with a comparison function based on order in the kdc request would - * be difficult.*/ - krb5_etype_info_entry *tmp; - int i, j, e; - krb5_boolean similar; - - if (etype_info == NULL) - return; - - /* First, move up etype_info_entries whose enctype exactly matches a - * requested enctype. - */ - e = 0; - for ( i = 0 ; i < request->nktypes && etype_info[e] != NULL ; i++ ) - { - if (request->ktype[i] == etype_info[e]->etype) - { - e++; - continue; - } - for ( j = e+1 ; etype_info[j] ; j++ ) - if (request->ktype[i] == etype_info[j]->etype) - break; - if (etype_info[j] == NULL) - continue; - - tmp = etype_info[j]; - etype_info[j] = etype_info[e]; - etype_info[e] = tmp; - e++; - } - - /* Then move up etype_info_entries whose enctype is similar to a - * requested enctype. - */ - for ( i = 0 ; i < request->nktypes && etype_info[e] != NULL ; i++ ) - { - if (krb5_c_enctype_compare(context, request->ktype[i], etype_info[e]->etype, &similar) != 0) - continue; - - if (similar) - { - e++; - continue; - } - for ( j = e+1 ; etype_info[j] ; j++ ) - { - if (krb5_c_enctype_compare(context, request->ktype[i], etype_info[j]->etype, &similar) != 0) - continue; - - if (similar) - break; - } - if (etype_info[j] == NULL) - continue; - - tmp = etype_info[j]; - etype_info[j] = etype_info[e]; - etype_info[e] = tmp; - e++; - } -} - - krb5_error_code krb5_do_preauth(krb5_context context, krb5_kdc_req *request, krb5_pa_data **in_padata, krb5_pa_data ***out_padata, - krb5_data *salt, krb5_enctype *etype, + krb5_data *salt, krb5_data *s2kparams, + krb5_enctype *etype, krb5_keyblock *as_key, krb5_prompter_fct prompter, void *prompter_data, krb5_gic_get_as_key_fct gak_fct, void *gak_data) { int h, i, j, out_pa_list_size; - krb5_pa_data *out_pa, **out_pa_list; + int seen_etype_info2 = 0; + krb5_pa_data *out_pa = NULL, **out_pa_list = NULL; krb5_data scratch; krb5_etype_info etype_info = NULL; krb5_error_code ret; @@ -938,6 +862,7 @@ krb5_do_preauth(krb5_context context, for (h=0; h<(sizeof(paorder)/sizeof(paorder[0])); h++) { realdone = 0; for (i=0; in_padata[i] && !realdone; i++) { + int k, l, etype_found, valid_etype_found; /* * This is really gross, but is necessary to prevent * lossge when talking to a 1.0.x KDC, which returns an @@ -946,27 +871,81 @@ krb5_do_preauth(krb5_context context, */ switch (in_padata[i]->pa_type) { case KRB5_PADATA_ETYPE_INFO: - if (etype_info) - continue; + case KRB5_PADATA_ETYPE_INFO2: + { + krb5_preauthtype pa_type = in_padata[i]->pa_type; + if (etype_info) { + if (seen_etype_info2 || pa_type != KRB5_PADATA_ETYPE_INFO2) + continue; + if (pa_type == KRB5_PADATA_ETYPE_INFO2) { + krb5_free_etype_info( context, etype_info); + etype_info = NULL; + } + } + scratch.length = in_padata[i]->length; scratch.data = (char *) in_padata[i]->contents; - ret = decode_krb5_etype_info(&scratch, &etype_info); + if (pa_type == KRB5_PADATA_ETYPE_INFO2) { + seen_etype_info2++; + ret = decode_krb5_etype_info2(&scratch, &etype_info); + } + else ret = decode_krb5_etype_info(&scratch, &etype_info); if (ret) { - if (out_pa_list) { - out_pa_list[out_pa_list_size++] = NULL; - krb5_free_pa_data(context, out_pa_list); - } - return ret; + ret = 0; /*Ignore error and etype_info element*/ + krb5_free_etype_info( context, etype_info); + etype_info = NULL; + continue; } if (etype_info[0] == NULL) { krb5_free_etype_info(context, etype_info); etype_info = NULL; break; } - sort_etype_info(context, request, etype_info); - salt->data = (char *) etype_info[0]->salt; - salt->length = etype_info[0]->length; - *etype = etype_info[0]->etype; + /* + * Select first etype in our request which is also in + * etype-info (preferring client request ktype order). + */ + for (etype_found = 0, valid_etype_found = 0, k = 0; + !etype_found && k < request->nktypes; k++) { + for (l = 0; etype_info[l]; l++) { + if (etype_info[l]->etype == request->ktype[k]) { + etype_found++; + break; + } + /* check if program has support for this etype for more + * precise error reporting. + */ + if (valid_enctype(etype_info[l]->etype)) + valid_etype_found++; + } + } + if (!etype_found) { + if (valid_etype_found) { + /* supported enctype but not requested */ + ret = KRB5_CONFIG_ETYPE_NOSUPP; + goto cleanup; + } + else { + /* unsupported enctype */ + ret = KRB5_PROG_ETYPE_NOSUPP; + goto cleanup; + } + + } + scratch.data = (char *) etype_info[l]->salt; + scratch.length = etype_info[l]->length; + krb5_free_data_contents(context, salt); + if (scratch.length == KRB5_ETYPE_NO_SALT) + salt->data = NULL; + else + if ((ret = krb5int_copy_data_contents( context, &scratch, salt)) != 0) + goto cleanup; + *etype = etype_info[l]->etype; + krb5_free_data_contents(context, s2kparams); + if ((ret = krb5int_copy_data_contents(context, + &etype_info[l]->s2kparams, + s2kparams)) != 0) + goto cleanup; #ifdef DEBUG for (j = 0; etype_info[j]; j++) { krb5_etype_info_entry *e = etype_info[j]; @@ -978,6 +957,7 @@ krb5_do_preauth(krb5_context context, } #endif break; + } case KRB5_PADATA_PW_SALT: case KRB5_PADATA_AFS3_SALT: if (etype_info) @@ -993,16 +973,10 @@ krb5_do_preauth(krb5_context context, if ((ret = ((*pa_types[j].fct)(context, request, in_padata[i], &out_pa, - salt, etype, as_key, + salt, s2kparams, etype, as_key, prompter, prompter_data, gak_fct, gak_data)))) { - if (out_pa_list) { - out_pa_list[out_pa_list_size++] = NULL; - krb5_free_pa_data(context, out_pa_list); - } - if (etype_info) - krb5_free_etype_info(context, etype_info); - return(ret); + goto cleanup; } if (out_pa) { @@ -1010,18 +984,22 @@ krb5_do_preauth(krb5_context context, if ((out_pa_list = (krb5_pa_data **) malloc(2*sizeof(krb5_pa_data *))) - == NULL) - return(ENOMEM); + == NULL) { + ret = ENOMEM; + goto cleanup; + } } else { if ((out_pa_list = (krb5_pa_data **) realloc(out_pa_list, (out_pa_list_size+2)* sizeof(krb5_pa_data *))) - == NULL) - /* XXX this will leak the pointers which + == NULL) { + /* XXX this will leak the pointers which have already been allocated. oh well. */ - return(ENOMEM); + ret = ENOMEM; + goto cleanup; + } } out_pa_list[out_pa_list_size++] = out_pa; @@ -1037,6 +1015,16 @@ krb5_do_preauth(krb5_context context, out_pa_list[out_pa_list_size++] = NULL; *out_padata = out_pa_list; - + if (etype_info) + krb5_free_etype_info(context, etype_info); + return(0); + cleanup: + if (out_pa_list) { + out_pa_list[out_pa_list_size++] = NULL; + krb5_free_pa_data(context, out_pa_list); + } + if (etype_info) + krb5_free_etype_info(context, etype_info); + return (ret); } |