summaryrefslogtreecommitdiffstats
path: root/src/lib/krb5
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2013-09-26 11:40:13 -0400
committerGreg Hudson <ghudson@mit.edu>2013-09-28 15:25:26 -0400
commit75b7ea9163e57ff0522f55a9cd0c2ab4b4974e38 (patch)
treee1f8bb9e8cea1c0bfbcd793aea71962c14d974b3 /src/lib/krb5
parent1f1b76ab8937c2cb0273cc5d8a7ee806240e1879 (diff)
downloadkrb5-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.c80
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;