diff options
author | Sam Hartman <hartmans@mit.edu> | 2010-09-15 17:13:23 +0000 |
---|---|---|
committer | Sam Hartman <hartmans@mit.edu> | 2010-09-15 17:13:23 +0000 |
commit | a063fe7e5c11900df005bb2875b27f8e284dfdba (patch) | |
tree | 36fe23e89c05a9727ccbf82059e3582a6938b4f0 /src/lib/kdb | |
parent | 4bcc98813080a3dabb94e31e974a6f74a81b2125 (diff) | |
download | krb5-a063fe7e5c11900df005bb2875b27f8e284dfdba.tar.gz krb5-a063fe7e5c11900df005bb2875b27f8e284dfdba.tar.xz krb5-a063fe7e5c11900df005bb2875b27f8e284dfdba.zip |
kdb: store mkey list in context and permit NULL mkey for kdb_dbe_decrypt_key_data
Previously, code needed to run a loop to find the current master key,
possibly fetch a new master key list and try finding the master key
again around each key decryption. This was not universally done;
there are cases where only the current master key was used. In
addition, the correct ideom for decrypting key data is too complicated
and is potentially unavailable to plugins that do not have access to
the master key. Instead, store the master key list in the dal_handle
whenever it is fetched and permit a NULL master key for
krb5_dbe_decrypt_key_data.
* Remove APIs for krb5_db_{get|set}_mkey_list
* krb5_db_fetch_mkey_list: memoize master key list in dal_handle
* krb5_db_free_mkey_list: don't free the memoized list; arrange for it to be freed later
* krb5_dbe_decrypt_key_data: Search for correct master key on NULL argument
* change call sites to take advantage
ticket: 6778
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24314 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib/kdb')
-rw-r--r-- | src/lib/kdb/kdb5.c | 111 | ||||
-rw-r--r-- | src/lib/kdb/kdb5.h | 3 | ||||
-rw-r--r-- | src/lib/kdb/keytab.c | 12 | ||||
-rw-r--r-- | src/lib/kdb/libkdb5.exports | 2 |
4 files changed, 80 insertions, 48 deletions
diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c index 978650300..c54968987 100644 --- a/src/lib/kdb/kdb5.c +++ b/src/lib/kdb/kdb5.c @@ -1,6 +1,6 @@ /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* - * Copyright 2006, 2009 by the Massachusetts Institute of Technology. + * Copyright 2006, 2009, 2010 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may @@ -549,17 +549,23 @@ static krb5_error_code kdb_free_lib_handle(krb5_context kcontext) { krb5_error_code status = 0; + krb5_keylist_node *old_keylist = kcontext->dal_handle->master_keylist; status = kdb_free_library(kcontext->dal_handle->lib_handle); if (status) return status; - + /* The dal_handle holds an alias to the most recent mkey_list*/ + if (kcontext->dal_handle->free_keylist) { + kcontext->dal_handle->master_keylist = NULL; /*force freeing*/ + krb5_db_free_mkey_list(kcontext, old_keylist); + } + krb5_free_principal(kcontext, kcontext->dal_handle->master_princ); free(kcontext->dal_handle); kcontext->dal_handle = NULL; return 0; } -static krb5_error_code +static krb5_error_code get_vftabl(krb5_context kcontext, kdb_vftabl **vftabl_ptr) { krb5_error_code status; @@ -989,35 +995,6 @@ krb5_db_iterate(krb5_context kcontext, } krb5_error_code -krb5_db_set_mkey_list(krb5_context kcontext, - krb5_keylist_node * keylist) -{ - krb5_error_code status = 0; - kdb_vftabl *v; - - status = get_vftabl(kcontext, &v); - if (status) - return status; - if (v->set_master_key_list == NULL) - return KRB5_PLUGIN_OP_NOTSUPP; - return v->set_master_key_list(kcontext, keylist); -} - -krb5_error_code -krb5_db_get_mkey_list(krb5_context kcontext, krb5_keylist_node ** keylist) -{ - krb5_error_code status = 0; - kdb_vftabl *v; - - status = get_vftabl(kcontext, &v); - if (status) - return status; - if (v->get_master_key_list == NULL) - return KRB5_PLUGIN_OP_NOTSUPP; - return v->get_master_key_list(kcontext, keylist); -} - -krb5_error_code krb5_db_fetch_mkey_list(krb5_context context, krb5_principal mname, const krb5_keyblock * mkey, @@ -1026,11 +1003,28 @@ krb5_db_fetch_mkey_list(krb5_context context, { kdb_vftabl *v; krb5_error_code status = 0; + krb5_keylist_node *local_keylist; status = get_vftabl(context, &v); if (status) return status; - return v->fetch_master_key_list(context, mname, mkey, mkvno, mkey_list); + if (!context->dal_handle->master_princ) { + status = krb5_copy_principal(context, mname, &context->dal_handle->master_princ); + if (status) + return status; + } + if (mkey_list == NULL) + mkey_list = &local_keylist; + status = v->fetch_master_key_list(context, mname, mkey, mkvno, mkey_list); + if (status == 0) { + /* The dal_handle holds an alias to the most recent master_keylist*/ + krb5_keylist_node *old_keylist = context->dal_handle->master_keylist; + context->dal_handle->master_keylist = *mkey_list; + if (context->dal_handle->free_keylist) + krb5_db_free_mkey_list(context, old_keylist); + context->dal_handle->free_keylist = (mkey_list == &local_keylist); + } + return status; } void @@ -1039,6 +1033,19 @@ krb5_db_free_mkey_list(krb5_context context, { krb5_keylist_node *cur, *prev; + /* + * The dal_handle holds onto the most recent master + * keylist that has been fetched throughout the lifetime of the context; if + * this function is called on that keylist, then the dal_handle is updated to + * indicate that the keylist should be freed on next call to + * krb5_db_fetch_mkey_list() or when the database is closed. Otherwise, the + * master_keylist is freed. Either way, the caller must not access this master + * keylist after calling this function. + */ + if (context&& context->dal_handle->master_keylist == mkey_list) { + context->dal_handle->free_keylist = 1; + return; + } for (cur = mkey_list; cur != NULL;) { prev = cur; cur = cur->next; @@ -2177,6 +2184,27 @@ krb5_db_promote(krb5_context kcontext, char **db_args) return status; } +static krb5_error_code +decrypt_iterator(krb5_context kcontext, + const krb5_key_data * key_data, + krb5_keyblock * dbkey, + krb5_keysalt * keysalt) +{ + krb5_error_code status = 0; + kdb_vftabl *v; + krb5_keylist_node *n = kcontext->dal_handle->master_keylist; + status = get_vftabl(kcontext, &v); + if (status) + return status; + for (;n; n = n->next) { + krb5_clear_error_message(kcontext); + status= v->decrypt_key_data(kcontext, &n->keyblock, key_data, dbkey, keysalt); + if (status == 0) + return 0; + } + return status; +} + krb5_error_code krb5_dbe_decrypt_key_data( krb5_context kcontext, const krb5_keyblock * mkey, @@ -2186,11 +2214,24 @@ krb5_dbe_decrypt_key_data( krb5_context kcontext, { krb5_error_code status = 0; kdb_vftabl *v; - + krb5_keylist_node *n = kcontext->dal_handle->master_keylist; status = get_vftabl(kcontext, &v); if (status) return status; - return v->decrypt_key_data(kcontext, mkey, key_data, dbkey, keysalt); + if (mkey ||!n) + return v->decrypt_key_data(kcontext, mkey, key_data, dbkey, keysalt); + status = decrypt_iterator(kcontext, key_data, dbkey, keysalt); + if (status == 0) + return 0; + if (kcontext->dal_handle->master_keylist) { + /* Try reloading master keys*/ + krb5_keyblock *cur_mkey = &kcontext->dal_handle->master_keylist->keyblock; + if (krb5_db_fetch_mkey_list(kcontext, kcontext->dal_handle->master_princ, + cur_mkey, -1, NULL) == 0) { + return decrypt_iterator(kcontext, key_data, dbkey, keysalt); + } + } + return status; } krb5_error_code diff --git a/src/lib/kdb/kdb5.h b/src/lib/kdb/kdb5.h index c1265e704..6d5c0a6cd 100644 --- a/src/lib/kdb/kdb5.h +++ b/src/lib/kdb/kdb5.h @@ -30,6 +30,9 @@ struct _kdb5_dal_handle extent. */ void *db_context; db_library lib_handle; + krb5_keylist_node *master_keylist; + krb5_boolean free_keylist; + krb5_principal master_princ; }; /* typedef kdb5_dal_handle is in k5-int.h now */ diff --git a/src/lib/kdb/keytab.c b/src/lib/kdb/keytab.c index 4d56915b9..dbbbe75cd 100644 --- a/src/lib/kdb/keytab.c +++ b/src/lib/kdb/keytab.c @@ -124,8 +124,6 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry) krb5_keytab_entry * entry; { krb5_context context; - krb5_keylist_node * master_keylist; - krb5_keyblock * master_key; krb5_error_code kerror = 0; krb5_key_data * key_data; krb5_db_entry * db_entry; @@ -157,14 +155,6 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry) } /* match key */ - kerror = krb5_db_get_mkey_list(context, &master_keylist); - if (kerror) - goto error; - - kerror = krb5_dbe_find_mkey(context, master_keylist, db_entry, &master_key); - if (kerror) - goto error; - /* For cross realm tgts, we match whatever enctype is provided; * for other principals, we only match the first enctype that is * found. Since the TGS and AS code do the same thing, then we @@ -178,7 +168,7 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry) goto error; - kerror = krb5_dbe_decrypt_key_data(context, master_key, key_data, + kerror = krb5_dbe_decrypt_key_data(context, NULL, key_data, &entry->key, NULL); if (kerror) goto error; diff --git a/src/lib/kdb/libkdb5.exports b/src/lib/kdb/libkdb5.exports index 6e890478d..f3f6a8021 100644 --- a/src/lib/kdb/libkdb5.exports +++ b/src/lib/kdb/libkdb5.exports @@ -18,7 +18,6 @@ krb5_db_fini krb5_db_free_principal krb5_db_get_age krb5_db_get_key_data_kvno -krb5_db_get_mkey_list krb5_db_get_context krb5_db_get_principal krb5_db_iterate @@ -26,7 +25,6 @@ krb5_db_lock krb5_db_put_principal krb5_db_refresh_config krb5_db_set_context -krb5_db_set_mkey_list krb5_db_setup_mkey_name krb5_db_sign_authdata krb5_db_unlock |