krb5 commit: Defer KEYRING key creation until initialize
Greg Hudson
ghudson at MIT.EDU
Wed Oct 2 10:45:01 EDT 2013
https://github.com/krb5/krb5/commit/75b7ea9163e57ff0522f55a9cd0c2ab4b4974e38
commit 75b7ea9163e57ff0522f55a9cd0c2ab4b4974e38
Author: Greg Hudson <ghudson at mit.edu>
Date: Thu Sep 26 11:40:13 2013 -0400
Defer KEYRING key creation until initialize
If we resolve a KEYRING cache and the key does not exist, wait until
initialize time to create it, to avoid wasting precious kernel memory
on a cache which might not ever be created. Properly error out if
store_cred or start_seq_get is called on an uninitialized cache, as we
would for a FILE cache.
Adapted from a patch by simo at redhat.com.
src/lib/krb5/ccache/cc_keyring.c | 80 +++++++++++++++++++++++++++----------
1 files changed, 58 insertions(+), 22 deletions(-)
diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c
index 12ad702..41fe4a6 100644
--- a/src/lib/krb5/ccache/cc_keyring.c
+++ b/src/lib/krb5/ccache/cc_keyring.c
@@ -315,6 +315,24 @@ static void krb5_krcc_update_change_time
/* Note the following is a stub function for Linux */
extern krb5_error_code krb5_change_cache(void);
+/* Find or create a keyring within parent with the given name. */
+static krb5_error_code
+find_or_create_keyring(key_serial_t parent, const char *name,
+ key_serial_t *key_out)
+{
+ key_serial_t key;
+
+ *key_out = -1;
+ key = keyctl_search(parent, KRCC_KEY_TYPE_KEYRING, name, 0);
+ if (key == -1) {
+ key = add_key(KRCC_KEY_TYPE_KEYRING, name, NULL, 0, parent);
+ if (key == -1)
+ return errno;
+ }
+ *key_out = key;
+ return 0;
+}
+
/*
* Modifies:
* id
@@ -332,22 +350,35 @@ static krb5_error_code KRB5_CALLCONV
krb5_krcc_initialize(krb5_context context, krb5_ccache id,
krb5_principal princ)
{
+ krb5_krcc_data *data = (krb5_krcc_data *)id->data;
krb5_error_code kret;
+ const char *ring_name, *p;
DEBUG_PRINT(("krb5_krcc_initialize: entered\n"));
- k5_cc_mutex_lock(context, &((krb5_krcc_data *) id->data)->lock);
+ k5_cc_mutex_lock(context, &data->lock);
kret = krb5_krcc_clearcache(context, id);
if (kret != KRB5_OK)
goto out;
+ if (!data->ring_id) {
+ /* The key didn't exist at resolve time. Check again and create the
+ * key if it still isn't there. */
+ p = strrchr(data->name, ':');
+ ring_name = (p != NULL) ? p + 1 : data->name;
+ kret = find_or_create_keyring(data->parent_id, ring_name,
+ &data->ring_id);
+ if (kret)
+ goto out;
+ }
+
kret = krb5_krcc_save_principal(context, id, princ);
if (kret == KRB5_OK)
krb5_change_cache();
out:
- k5_cc_mutex_unlock(context, &((krb5_krcc_data *) id->data)->lock);
+ k5_cc_mutex_unlock(context, &data->lock);
return kret;
}
@@ -405,9 +436,10 @@ krb5_krcc_clearcache(krb5_context context, krb5_ccache id)
DEBUG_PRINT(("krb5_krcc_clearcache: ring_id %d, princ_id %d\n",
d->ring_id, d->princ_id));
- res = keyctl_clear(d->ring_id);
- if (res != 0) {
- return errno;
+ if (d->ring_id) {
+ res = keyctl_clear(d->ring_id);
+ if (res != 0)
+ return errno;
}
d->princ_id = 0;
krb5_krcc_update_change_time(d);
@@ -437,12 +469,14 @@ krb5_krcc_destroy(krb5_context context, krb5_ccache id)
krb5_krcc_clearcache(context, id);
free(d->name);
- res = keyctl_unlink(d->ring_id, d->parent_id);
- if (res < 0) {
- kret = errno;
- DEBUG_PRINT(("krb5_krcc_destroy: unlinking key %d from ring %d: %s",
- d->ring_id, d->parent_id, error_message(errno)));
- goto cleanup;
+ if (d->ring_id) {
+ res = keyctl_unlink(d->ring_id, d->parent_id);
+ if (res < 0) {
+ kret = errno;
+ DEBUG_PRINT(("unlinking key %d from ring %d: %s",
+ d->ring_id, d->parent_id, error_message(errno)));
+ goto cleanup;
+ }
}
cleanup:
k5_cc_mutex_unlock(context, &d->lock);
@@ -515,16 +549,8 @@ krb5_krcc_resolve(krb5_context context, krb5_ccache * id, const char *full_resid
*/
key = keyctl_search(ring_id, KRCC_KEY_TYPE_KEYRING, residual, 0);
if (key < 0) {
- key = add_key(KRCC_KEY_TYPE_KEYRING, residual, NULL, 0, ring_id);
- if (key < 0) {
- kret = errno;
- DEBUG_PRINT(("krb5_krcc_resolve: Error adding new "
- "keyring '%s': %s\n", residual, strerror(errno)));
- return kret;
- }
- DEBUG_PRINT(("krb5_krcc_resolve: new keyring '%s', "
- "key %d, added to keyring %d\n",
- residual, key, ring_id));
+ /* Defer key creation to krb5_cc_initialize. */
+ key = 0;
} else {
DEBUG_PRINT(("krb5_krcc_resolve: found existing "
"key %d, with name '%s' in keyring %d\n",
@@ -588,6 +614,11 @@ krb5_krcc_start_seq_get(krb5_context context, krb5_ccache id,
d = id->data;
k5_cc_mutex_lock(context, &d->lock);
+ if (!d->ring_id) {
+ k5_cc_mutex_unlock(context, &d->lock);
+ return KRB5_FCC_NOFILE;
+ }
+
size = keyctl_read_alloc(d->ring_id, &keys);
if (size == -1) {
DEBUG_PRINT(("Error getting from keyring: %s\n", strerror(errno)));
@@ -940,6 +971,11 @@ krb5_krcc_store(krb5_context context, krb5_ccache id, krb5_creds * creds)
k5_cc_mutex_lock(context, &d->lock);
+ if (!d->ring_id) {
+ k5_cc_mutex_unlock(context, &d->lock);
+ return KRB5_FCC_NOFILE;
+ }
+
/* Get the service principal name and use it as the key name */
kret = krb5_unparse_name(context, creds->server, &keyname);
if (kret) {
@@ -1080,7 +1116,7 @@ krb5_krcc_retrieve_principal(krb5_context context, krb5_ccache id,
k5_cc_mutex_lock(context, &d->lock);
- if (!d->princ_id) {
+ if (!d->ring_id || !d->princ_id) {
princ = 0L;
kret = KRB5_FCC_NOFILE;
goto errout;
More information about the cvs-krb5
mailing list