[krbdev.mit.edu #9178] krb5_cc_set_config() fails to overwrite existing entries and creates duplicate credential objects
"Steffen Kieß via RT" <[email protected]> Mon, 07 Jul 2025 12:10:50 -0400
| Newsgroups | gmane.comp.encryption.kerberos.bugs |
|---|---|
| Message-ID | <rt-4.4.3-2-1168337-1751904650-1441.9178-4-0@kerborg-prod-app-1.mit.edu> |
Mon Jul 07 12:10:50 2025: Request 9178 was acted upon. Transaction: Ticket created by [email protected] Queue: krb5 Subject: krb5_cc_set_config() fails to overwrite existing entries and creates duplicate credential objects Owner: Nobody Requestors: [email protected] Status: new Ticket <URL: http://kerborg-prod-app-1.mit.edu/rt/Ticket/Display.html?id=9178 > krb5_cc_set_config() fails to overwrite existing entries and creates duplicate credential objects, at least for FILE:, MEMORY: and KCM: (with Heimdal kcm) CCs. This can cause the CC to be filled hundreds of "refresh_time" entries (which can be seen e.g. with "klist -AC".) This is probably related to <https://github.com/krb5/krb5/commit/c0a51fe0c8051e27c6cee4f4f0c705356a715e1e>. The following code demonstrates the problem: #include <stdio.h> #include <string.h> #include <krb5.h> int main() { krb5_context context; if (krb5_init_context(&context)) abort(); const char* cname = "FILE:/tmp/test-cache"; // const char* cname = "KCM:1000:12345"; // const char* cname = "MEMORY:"; // const char* cname = "KEYRING:"; // Create credential cache krb5_ccache cache; if (krb5_cc_resolve(context, cname, &cache)) abort(); krb5_principal princ; if (krb5_build_principal(context, &princ, 5, "REALM", "user", NULL)) abort(); if (krb5_cc_initialize(context, cache, princ)) abort(); // Set config "test" to "foo" krb5_data data; data.data = "foo"; data.length = 3; if (krb5_cc_set_config(context, cache, NULL, "test", &data)) abort(); // Read config "test" if (krb5_cc_get_config(context, cache, NULL, "test", &data)) abort(); { char* data2 = malloc(data.length + 1); if (!data2) abort(); memcpy(data2, data.data, data.length); data2[data.length] = 0; printf("krb5_cc_get_config: '%s'\n", data2); } // Set config "test" to "foo2" data.data = "foo2"; data.length = 4; if (krb5_cc_set_config(context, cache, NULL, "test", &data)) abort(); // Read config "test" if (krb5_cc_get_config(context, cache, NULL, "test", &data)) abort(); { char* data2 = malloc(data.length + 1); if (!data2) abort(); memcpy(data2, data.data, data.length); data2[data.length] = 0; printf("krb5_cc_get_config: '%s'\n", data2); } // Print entries in cache krb5_cc_cursor cursor; if (krb5_cc_start_seq_get(context, cache, &cursor)) abort(); for (;;) { krb5_creds creds; if (krb5_cc_next_cred(context, cache, &cursor, &creds)) break; char* data2 = malloc(creds.ticket.length + 1); if (!data2) abort(); memcpy(data2, creds.ticket.data, creds.ticket.length); data2[creds.ticket.length] = 0; printf("Got: '%s'\n", data2); } } The output on my system is: krb5_cc_get_config: 'foo' krb5_cc_get_config: 'foo' Got: 'foo' Got: 'foo2' It should be: krb5_cc_get_config: 'foo' krb5_cc_get_config: 'foo2' Got: 'foo2' This affects the current git master (and probably krb5 versions going back more than a decade).