Blame SOURCES/krb5-master-keyring-expiration.patch

7d335d
commit 29e60c5b7ac0980606971afc6fd6028bcf0c7f0f
7d335d
Author: Simo Sorce <simo@redhat.com>
7d335d
Date:   Fri Nov 15 16:36:05 2013 -0500
7d335d
7d335d
    Set expiration time on keys and keyrings
7d335d
    
7d335d
    By setting the timeout based on the credetial's timeout we let the
7d335d
    system automatically cleanup expired credentials.
7d335d
    
7d335d
    [ghudson@mit.edu: simplified code slightly]
7d335d
    
7d335d
    ticket: 7769 (new)
7d335d
    target_version: 1.12
7d335d
    tags: pullup
7d335d
7d335d
diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c
7d335d
index 2192fa5..1a0f1df 100644
7d335d
--- a/src/lib/krb5/ccache/cc_keyring.c
7d335d
+++ b/src/lib/krb5/ccache/cc_keyring.c
7d335d
@@ -818,21 +818,68 @@ cleanup:
7d335d
 
7d335d
 static krb5_error_code
7d335d
 add_cred_key(const char *name, const void *payload, size_t plen,
7d335d
-             key_serial_t cache_id, krb5_boolean legacy_type)
7d335d
+             key_serial_t cache_id, krb5_boolean legacy_type,
7d335d
+             key_serial_t *key_out)
7d335d
 {
7d335d
     key_serial_t key;
7d335d
 
7d335d
+    *key_out = -1;
7d335d
     if (!legacy_type) {
7d335d
         /* Try the preferred cred key type; fall back if no kernel support. */
7d335d
         key = add_key(KRCC_CRED_KEY_TYPE, name, payload, plen, cache_id);
7d335d
-        if (key != -1)
7d335d
+        if (key != -1) {
7d335d
+            *key_out = key;
7d335d
             return 0;
7d335d
-        else if (errno != EINVAL && errno != ENODEV)
7d335d
+        } else if (errno != EINVAL && errno != ENODEV) {
7d335d
             return errno;
7d335d
+        }
7d335d
     }
7d335d
     /* Use the user key type. */
7d335d
     key = add_key(KRCC_KEY_TYPE_USER, name, payload, plen, cache_id);
7d335d
-    return (key == -1) ? errno : 0;
7d335d
+    if (key == -1)
7d335d
+        return errno;
7d335d
+    *key_out = key;
7d335d
+    return 0;
7d335d
+}
7d335d
+
7d335d
+static void
7d335d
+update_keyring_expiration(krb5_context context, krb5_ccache id)
7d335d
+{
7d335d
+    krb5_krcc_data *d = (krb5_krcc_data *)id->data;
7d335d
+    krb5_cc_cursor cursor;
7d335d
+    krb5_creds creds;
7d335d
+    krb5_timestamp now, endtime = 0;
7d335d
+    unsigned int timeout;
7d335d
+
7d335d
+    /*
7d335d
+     * We have no way to know what is the actual timeout set on the keyring.
7d335d
+     * We also cannot keep track of it in a local variable as another process
7d335d
+     * can always modify the keyring independently, so just always enumerate
7d335d
+     * all keys and find out the highest endtime time.
7d335d
+     */
7d335d
+
7d335d
+    /* Find the maximum endtime of all creds in the cache. */
7d335d
+    if (krb5_krcc_start_seq_get(context, id, &cursor) != 0)
7d335d
+        return;
7d335d
+    for (;;) {
7d335d
+        if (krb5_krcc_next_cred(context, id, &cursor, &creds) != 0)
7d335d
+            break;
7d335d
+        if (creds.times.endtime > endtime)
7d335d
+            endtime = creds.times.endtime;
7d335d
+        krb5_free_cred_contents(context, &creds);
7d335d
+    }
7d335d
+    (void)krb5_krcc_end_seq_get(context, id, &cursor);
7d335d
+
7d335d
+    if (endtime == 0)        /* No creds with end times */
7d335d
+        return;
7d335d
+
7d335d
+    if (krb5_timeofday(context, &now) != 0)
7d335d
+        return;
7d335d
+
7d335d
+    /* Setting the timeout to zero would reset the timeout, so we set it to one
7d335d
+     * second instead if creds are already expired. */
7d335d
+    timeout = (endtime > now) ? endtime - now : 1;
7d335d
+    (void)keyctl_set_timeout(d->cache_id, timeout);
7d335d
 }
7d335d
 
7d335d
 /*
7d335d
@@ -1497,6 +1544,8 @@ krb5_krcc_store(krb5_context context, krb5_ccache id, krb5_creds * creds)
7d335d
     char   *payload = NULL;
7d335d
     unsigned int payloadlen;
7d335d
     char   *keyname = NULL;
7d335d
+    key_serial_t cred_key;
7d335d
+    krb5_timestamp now;
7d335d
 
7d335d
     DEBUG_PRINT(("krb5_krcc_store: entered\n"));
7d335d
 
7d335d
@@ -1523,12 +1572,24 @@ krb5_krcc_store(krb5_context context, krb5_ccache id, krb5_creds * creds)
7d335d
     DEBUG_PRINT(("krb5_krcc_store: adding new key '%s' to keyring %d\n",
7d335d
                  keyname, d->cache_id));
7d335d
     kret = add_cred_key(keyname, payload, payloadlen, d->cache_id,
7d335d
-                        d->is_legacy_type);
7d335d
+                        d->is_legacy_type, &cred_key);
7d335d
     if (kret)
7d335d
         goto errout;
7d335d
 
7d335d
     krb5_krcc_update_change_time(d);
7d335d
 
7d335d
+    /* Set appropriate timeouts on cache keys. */
7d335d
+    kret = krb5_timeofday(context, &now;;
7d335d
+    if (kret)
7d335d
+        goto errout;
7d335d
+
7d335d
+    if (creds->times.endtime > now)
7d335d
+        (void)keyctl_set_timeout(cred_key, creds->times.endtime - now);
7d335d
+
7d335d
+    update_keyring_expiration(context, id);
7d335d
+
7d335d
+    kret = KRB5_OK;
7d335d
+
7d335d
 errout:
7d335d
     if (keyname)
7d335d
         krb5_free_unparsed_name(context, keyname);