diff options
author | Greg Hudson <ghudson@mit.edu> | 2013-09-26 11:40:13 -0400 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2013-09-28 15:25:26 -0400 |
commit | 75b7ea9163e57ff0522f55a9cd0c2ab4b4974e38 (patch) | |
tree | e1f8bb9e8cea1c0bfbcd793aea71962c14d974b3 /src/lib/krb5 | |
parent | 1f1b76ab8937c2cb0273cc5d8a7ee806240e1879 (diff) | |
download | krb5-75b7ea9163e57ff0522f55a9cd0c2ab4b4974e38.tar.gz krb5-75b7ea9163e57ff0522f55a9cd0c2ab4b4974e38.tar.xz krb5-75b7ea9163e57ff0522f55a9cd0c2ab4b4974e38.zip |
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@redhat.com.
Diffstat (limited to 'src/lib/krb5')
-rw-r--r-- | 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 12ad702329..41fe4a6194 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; |