Negative caching of unknown principals

David Woodhouse dwmw2 at infradead.org
Thu Jul 31 16:52:50 EDT 2014


There are certain sites on our Intranet where unless you run 'kdestroy'
before pointing firefox at them, you end up waiting literally *minutes*
for pages to load.

Because it uses multiple connections (and because there are scripts
doing lots of little fetches), it's going back to the KDC over and over
and over again to attempt to obtain a ticket for the *same* server, and
quite predictably getting KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN every time.

This horrid proof-of-concept hack makes Firefox load it in about the
same time whether we have a Kerberos TGT or not.

I know this has been mentioned in the past, and kind of went nowhere
after a discussion about how we could maintain a negative cache in
persistent storage. But it's not entirely clear that's necessary; an
in-memory cache like this one is perfectly sufficient. A single failure
from any individual client is fine; it's the dozens of consecutive
attempts which are a real problem.

diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
index dc47053..d463314 100644
--- a/src/lib/gssapi/krb5/init_sec_context.c
+++ b/src/lib/gssapi/krb5/init_sec_context.c
@@ -113,6 +113,14 @@
    at some point */
 int krb5_gss_dbg_client_expcreds = 0;
 
+static struct bad_server {
+    krb5_gss_name_t server;
+    krb5_error_code code;
+    /* Expire? */
+    struct bad_server *next;
+} *bad_servers = NULL;
+static k5_mutex_t bad_servers_lock = K5_MUTEX_PARTIAL_INITIALIZER;
+
 /*
  * Common code which fetches the correct krb5 credentials from the
  * ccache.
@@ -126,9 +134,10 @@ static krb5_error_code get_credentials(context, cred, server, now,
     krb5_timestamp endtime;
     krb5_creds **out_creds;
 {
-    krb5_error_code     code;
+    krb5_error_code     code = 0;
     krb5_creds          in_creds, evidence_creds, *result_creds = NULL;
     krb5_flags          flags = 0;
+    struct bad_server *bad;
 
     *out_creds = NULL;
 
@@ -139,6 +148,17 @@ static krb5_error_code get_credentials(context, cred, server, now,
 
     assert(cred->name != NULL);
 
+    k5_mutex_lock(&bad_servers_lock);
+    for (bad = bad_servers; bad; bad = bad->next) {
+        if (kg_compare_name(context, server, bad->server)) {
+            printf("Already bad\n");
+            code = bad->code;
+            break;
+        }
+    }
+    k5_mutex_unlock(&bad_servers_lock);
+    if (code)
+        goto cleanup;
     /*
      * Do constrained delegation if we have proxy credentials and
      * we're not trying to get a ticket to ourselves (in which case
@@ -194,6 +214,21 @@ static krb5_error_code get_credentials(context, cred, server, now,
 
     code = krb5_get_credentials(context, flags, cred->ccache,
                                 &in_creds, &result_creds);
+    if (0 && code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
+        bad = malloc(sizeof(*bad));
+        if (!bad)
+            goto cleanup;
+        if (kg_duplicate_name(context, server, &bad->server)) {
+            free(bad);
+            goto cleanup;
+        }
+        bad->code = code;
+        k5_mutex_lock(&bad_servers_lock);
+        bad->next = bad_servers;
+        bad_servers = bad;
+        k5_mutex_unlock(&bad_servers_lock);
+        goto cleanup;
+    }
     if (code)
         goto cleanup;
 

-- 
dwmw2
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 5745 bytes
Desc: not available
Url : http://mailman.mit.edu/pipermail/krbdev/attachments/20140731/8920dc51/attachment.bin


More information about the krbdev mailing list