From 7fc21c4a4a6ef8a88567f166eda1fe73784686c7 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Mon, 24 Oct 2011 15:09:32 +0000 Subject: [PATCH] Refactor salt computation into libkdb5 Add a new API krb5_dbe_compute_salt() to determine the salt for a key data entry, and use it in the three places we currently compute salts. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25410 dc483132-0cff-0310-8789-dd5450dbe970 --- src/include/kdb.h | 6 ++ src/kdc/kdc_preauth.c | 149 +++++++++++------------------- src/kdc/kdc_util.c | 56 ----------- src/kdc/kdc_util.h | 4 - src/lib/kadm5/srv/svr_principal.c | 62 +++---------- src/lib/kdb/kdb5.c | 50 ++++++++++ src/lib/kdb/libkdb5.exports | 1 + 7 files changed, 124 insertions(+), 204 deletions(-) diff --git a/src/include/kdb.h b/src/include/kdb.h index 78f786f3b..0f50a83c1 100644 --- a/src/include/kdb.h +++ b/src/include/kdb.h @@ -576,6 +576,12 @@ krb5_dbe_update_tl_data( krb5_context context, krb5_db_entry * entry, krb5_tl_data * new_tl_data); +/* Compute the salt for a key data entry given the corresponding principal. */ +krb5_error_code +krb5_dbe_compute_salt(krb5_context context, const krb5_key_data *key, + krb5_const_principal princ, krb5_int16 *salttype_out, + krb5_data **salt_out); + krb5_error_code krb5_dbe_cpw( krb5_context kcontext, krb5_keyblock * master_key, diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index 272980db5..fc7e43bca 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -1315,62 +1315,54 @@ request_contains_enctype(krb5_context context, const krb5_kdc_req *request, static krb5_error_code _make_etype_info_entry(krb5_context context, krb5_principal client_princ, krb5_key_data *client_key, - krb5_enctype etype, krb5_etype_info_entry **entry, + krb5_enctype etype, krb5_etype_info_entry **entry_out, int etype_info2) { - krb5_data salt; - krb5_etype_info_entry * tmp_entry; - krb5_error_code retval; + krb5_error_code retval; + krb5_int16 salttype; + krb5_data *salt = NULL; + krb5_etype_info_entry *entry = NULL; - if ((tmp_entry = malloc(sizeof(krb5_etype_info_entry))) == NULL) + *entry_out = NULL; + entry = malloc(sizeof(*entry)); + if (entry == NULL) return ENOMEM; - salt.data = 0; - - tmp_entry->magic = KV5M_ETYPE_INFO_ENTRY; - tmp_entry->etype = etype; - tmp_entry->length = KRB5_ETYPE_NO_SALT; - tmp_entry->salt = 0; - tmp_entry->s2kparams.data = NULL; - tmp_entry->s2kparams.length = 0; - retval = get_salt_from_key(context, client_princ, client_key, &salt); + entry->magic = KV5M_ETYPE_INFO_ENTRY; + entry->etype = etype; + entry->length = KRB5_ETYPE_NO_SALT; + entry->salt = NULL; + entry->s2kparams = empty_data(); + retval = krb5_dbe_compute_salt(context, client_key, client_princ, + &salttype, &salt); if (retval) - goto fail; - if (etype_info2 && client_key->key_data_ver > 1 && - client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_AFS3) { + goto cleanup; + if (etype_info2 && salttype == KRB5_KDB_SALTTYPE_AFS3) { switch (etype) { case ENCTYPE_DES_CBC_CRC: case ENCTYPE_DES_CBC_MD4: case ENCTYPE_DES_CBC_MD5: - tmp_entry->s2kparams.data = malloc(1); - if (tmp_entry->s2kparams.data == NULL) { - retval = ENOMEM; - goto fail; - } - tmp_entry->s2kparams.length = 1; - tmp_entry->s2kparams.data[0] = 1; + retval = alloc_data(&entry->s2kparams, 1); + if (retval) + goto cleanup; + entry->s2kparams.data[0] = 1; break; default: break; } } - if (salt.length >= 0) { - tmp_entry->length = salt.length; - tmp_entry->salt = (unsigned char *) salt.data; - salt.data = 0; - } - *entry = tmp_entry; - return 0; + entry->length = salt->length; + entry->salt = (unsigned char *)salt->data; + salt->data = NULL; + *entry_out = entry; + entry = NULL; -fail: - if (tmp_entry) { - if (tmp_entry->s2kparams.data) - free(tmp_entry->s2kparams.data); - free(tmp_entry); - } - if (salt.data) - free(salt.data); +cleanup: + if (entry != NULL) + krb5_free_data_contents(context, &entry->s2kparams); + free(entry); + krb5_free_data(context, salt); return retval; } @@ -1606,8 +1598,8 @@ return_pw_salt(krb5_context context, krb5_pa_data *in_padata, { krb5_error_code retval; krb5_pa_data * padata; - krb5_data * scratch; - krb5_data salt_data; + krb5_data * salt = NULL; + krb5_int16 salttype; krb5_key_data * client_key = rock->client_key; int i; @@ -1615,74 +1607,37 @@ return_pw_salt(krb5_context context, krb5_pa_data *in_padata, if (enctype_requires_etype_info_2(request->ktype[i])) return 0; } - if (client_key->key_data_ver == 1 || - client_key->key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL) + retval = krb5_dbe_compute_salt(context, client_key, request->client, + &salttype, &salt); + if (retval) return 0; - if ((padata = malloc(sizeof(krb5_pa_data))) == NULL) - return ENOMEM; + padata = k5alloc(sizeof(*padata), &retval); + if (padata == NULL) + goto cleanup; padata->magic = KV5M_PA_DATA; - padata->pa_type = KRB5_PADATA_PW_SALT; - switch (client_key->key_data_type[1]) { - case KRB5_KDB_SALTTYPE_V4: - /* send an empty (V4) salt */ - padata->contents = 0; - padata->length = 0; - break; - case KRB5_KDB_SALTTYPE_NOREALM: - if ((retval = krb5_principal2salt_norealm(kdc_context, - request->client, - &salt_data))) + if (salttype == KRB5_KDB_SALTTYPE_AFS3) { + padata->contents = k5alloc(salt->length + 1, &retval); + if (padata->contents == NULL) goto cleanup; - padata->contents = (krb5_octet *)salt_data.data; - padata->length = salt_data.length; - break; - case KRB5_KDB_SALTTYPE_AFS3: - /* send an AFS style realm-based salt */ - /* for now, just pass the realm back and let the client - do the work. In the future, add a kdc configuration - variable that specifies the old cell name. */ + memcpy(padata->contents, salt->data, salt->length); padata->pa_type = KRB5_PADATA_AFS3_SALT; - /* it would be just like ONLYREALM, but we need to pass the 0 */ - scratch = krb5_princ_realm(kdc_context, request->client); - if ((padata->contents = malloc(scratch->length+1)) == NULL) { - retval = ENOMEM; - goto cleanup; - } - memcpy(padata->contents, scratch->data, scratch->length); - padata->length = scratch->length+1; - padata->contents[scratch->length] = 0; - break; - case KRB5_KDB_SALTTYPE_ONLYREALM: - scratch = krb5_princ_realm(kdc_context, request->client); - if ((padata->contents = malloc(scratch->length)) == NULL) { - retval = ENOMEM; - goto cleanup; - } - memcpy(padata->contents, scratch->data, scratch->length); - padata->length = scratch->length; - break; - case KRB5_KDB_SALTTYPE_SPECIAL: - if ((padata->contents = malloc(client_key->key_data_length[1])) - == NULL) { - retval = ENOMEM; - goto cleanup; - } - memcpy(padata->contents, client_key->key_data_contents[1], - client_key->key_data_length[1]); - padata->length = client_key->key_data_length[1]; - break; - default: - free(padata); - return 0; + padata->contents[salt->length] = '\0'; + padata->length = salt->length + 1; + } else { + padata->pa_type = KRB5_PADATA_PW_SALT; + padata->length = salt->length; + padata->contents = (krb5_octet *)salt->data; + salt->data = NULL; } *send_pa = padata; - return 0; + padata = NULL; cleanup: free(padata); + krb5_free_data(context, salt); return retval; } diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c index e03cb27cb..e5c554f1b 100644 --- a/src/kdc/kdc_util.c +++ b/src/kdc/kdc_util.c @@ -1501,62 +1501,6 @@ select_session_keytype(krb5_context context, krb5_db_entry *server, return 0; } -/* - * This function returns salt information for a particular client_key - */ -krb5_error_code -get_salt_from_key(krb5_context context, krb5_principal client, - krb5_key_data *client_key, krb5_data *salt) -{ - krb5_error_code retval; - krb5_data * realm; - - salt->data = 0; - salt->length = SALT_TYPE_NO_LENGTH; - - if (client_key->key_data_ver == 1) - return 0; - - switch (client_key->key_data_type[1]) { - case KRB5_KDB_SALTTYPE_NORMAL: - /* - * The client could infer the salt from the principal, but - * might use the wrong principal name if this is an alias. So - * it's more reliable to send an explicit salt. - */ - if ((retval = krb5_principal2salt(context, client, salt))) - return retval; - break; - case KRB5_KDB_SALTTYPE_V4: - /* send an empty (V4) salt */ - salt->data = 0; - salt->length = 0; - break; - case KRB5_KDB_SALTTYPE_NOREALM: - if ((retval = krb5_principal2salt_norealm(context, client, salt))) - return retval; - break; - case KRB5_KDB_SALTTYPE_AFS3: - /* send the same salt as with onlyrealm - but with no type info, - we just hope they figure it out on the other end. */ - /* fall through to onlyrealm: */ - case KRB5_KDB_SALTTYPE_ONLYREALM: - realm = krb5_princ_realm(context, client); - salt->length = realm->length; - if ((salt->data = malloc(realm->length)) == NULL) - return ENOMEM; - memcpy(salt->data, realm->data, realm->length); - break; - case KRB5_KDB_SALTTYPE_SPECIAL: - salt->length = client_key->key_data_length[1]; - if ((salt->data = malloc(salt->length)) == NULL) - return ENOMEM; - memcpy(salt->data, client_key->key_data_contents[1], salt->length); - break; - } - return 0; -} - /* * Limit strings to a "reasonable" length to prevent crowding out of * other useful information in the log entry diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h index bdeaa5f7d..f4773ae4c 100644 --- a/src/kdc/kdc_util.h +++ b/src/kdc/kdc_util.h @@ -105,10 +105,6 @@ select_session_keytype (krb5_context context, int nktypes, krb5_enctype *ktypes); -krb5_error_code -get_salt_from_key (krb5_context, krb5_principal, - krb5_key_data *, krb5_data *); - void limit_string (char *name); void diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c index a9d0cdb88..d50007c52 100644 --- a/src/lib/kadm5/srv/svr_principal.c +++ b/src/lib/kadm5/srv/svr_principal.c @@ -725,10 +725,10 @@ kadm5_rename_principal(void *server_handle, { krb5_db_entry *kdb; osa_princ_ent_rec adb; - int ret, i; + krb5_error_code ret; kadm5_server_handle_t handle = server_handle; - krb5_int32 stype; - krb5_data sdata; + krb5_int16 stype, i; + krb5_data *salt = NULL; CHECK_HANDLE(server_handle); @@ -747,52 +747,19 @@ kadm5_rename_principal(void *server_handle, /* Transform salts as necessary. */ for (i = 0; i < kdb->n_key_data; i++) { - sdata = empty_data(); - if (kdb->key_data[i].key_data_ver > 1) - stype = kdb->key_data[i].key_data_type[1]; - else - stype = KRB5_KDB_SALTTYPE_NORMAL; - - /* For salt types which compute a salt from the principal name, compute - * the salt based on the old principal name into sdata. */ - switch (stype) { - case KRB5_KDB_SALTTYPE_NORMAL: - ret = krb5_principal2salt(handle->context, kdb->princ, &sdata); - if (ret) - goto done; - break; - case KRB5_KDB_SALTTYPE_NOREALM: - ret = krb5_principal2salt_norealm(handle->context, kdb->princ, - &sdata); - if (ret) - goto done; - break; - case KRB5_KDB_SALTTYPE_ONLYREALM: - ret = alloc_data(&sdata, kdb->princ->realm.length); - if (ret) - goto done; - memcpy(sdata.data, kdb->princ->realm.data, - kdb->princ->realm.length); - break; - case KRB5_KDB_SALTTYPE_SPECIAL: - case KRB5_KDB_SALTTYPE_V4: - case KRB5_KDB_SALTTYPE_AFS3: - /* Don't compute a new salt. Assume the realm doesn't change for - * V4 and AFS3. */ - break; - default: - /* We don't recognize this salt type. Be conservative. */ + ret = krb5_dbe_compute_salt(handle->context, &kdb->key_data[i], + kdb->princ, &stype, &salt); + if (ret == KRB5_KDB_BAD_SALTTYPE) ret = KADM5_NO_RENAME_SALT; + if (ret) goto done; - } - /* If we computed a salt, store it as an explicit salt. */ - if (sdata.data != NULL) { - kdb->key_data[i].key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL; - free(kdb->key_data[i].key_data_contents[1]); - kdb->key_data[i].key_data_contents[1] = (krb5_octet *)sdata.data; - kdb->key_data[i].key_data_length[1] = sdata.length; - kdb->key_data[i].key_data_ver = 2; - } + kdb->key_data[i].key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL; + free(kdb->key_data[i].key_data_contents[1]); + kdb->key_data[i].key_data_contents[1] = (krb5_octet *)salt->data; + kdb->key_data[i].key_data_length[1] = salt->length; + kdb->key_data[i].key_data_ver = 2; + free(salt); + salt = NULL; } kadm5_free_principal(handle->context, kdb->princ); @@ -808,6 +775,7 @@ kadm5_rename_principal(void *server_handle, ret = kdb_delete_entry(handle, source); done: + krb5_free_data(handle->context, salt); kdb_free_entry(handle, kdb, &adb); return ret; } diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c index 011c83bf3..380c3d69d 100644 --- a/src/lib/kdb/kdb5.c +++ b/src/lib/kdb/kdb5.c @@ -2234,6 +2234,56 @@ krb5_dbe_update_tl_data(krb5_context context, krb5_db_entry *entry, return (0); } +krb5_error_code +krb5_dbe_compute_salt(krb5_context context, const krb5_key_data *key, + krb5_const_principal princ, krb5_int16 *salttype_out, + krb5_data **salt_out) +{ + krb5_error_code retval; + krb5_int16 stype; + krb5_data *salt, sdata; + + stype = (key->key_data_ver < 2) ? KRB5_KDB_SALTTYPE_NORMAL : + key->key_data_type[1]; + *salttype_out = stype; + *salt_out = NULL; + + /* Place computed salt into sdata, or directly into salt_out and return. */ + switch (stype) { + case KRB5_KDB_SALTTYPE_NORMAL: + retval = krb5_principal2salt(context, princ, &sdata); + if (retval) + return retval; + break; + case KRB5_KDB_SALTTYPE_V4: + sdata = empty_data(); + break; + case KRB5_KDB_SALTTYPE_NOREALM: + retval = krb5_principal2salt_norealm(context, princ, &sdata); + if (retval) + return retval; + break; + case KRB5_KDB_SALTTYPE_AFS3: + case KRB5_KDB_SALTTYPE_ONLYREALM: + return krb5_copy_data(context, &princ->realm, salt_out); + case KRB5_KDB_SALTTYPE_SPECIAL: + sdata = make_data(key->key_data_contents[1], key->key_data_length[1]); + return krb5_copy_data(context, &sdata, salt_out); + default: + return KRB5_KDB_BAD_SALTTYPE; + } + + /* Make a container for sdata. */ + salt = malloc(sizeof(*salt)); + if (salt == NULL) { + free(sdata.data); + return ENOMEM; + } + *salt = sdata; + *salt_out = salt; + return 0; +} + /* change password functions */ krb5_error_code krb5_dbe_cpw(krb5_context kcontext, krb5_keyblock *master_key, diff --git a/src/lib/kdb/libkdb5.exports b/src/lib/kdb/libkdb5.exports index 3ea179a46..e32b7a1d2 100644 --- a/src/lib/kdb/libkdb5.exports +++ b/src/lib/kdb/libkdb5.exports @@ -48,6 +48,7 @@ krb5_dbe_free_strings krb5_dbe_get_mkvno krb5_dbe_get_string krb5_dbe_get_strings +krb5_dbe_compute_salt krb5_dbe_lookup_last_admin_unlock krb5_dbe_lookup_last_pwd_change krb5_dbe_lookup_actkvno -- 2.26.2