[krbdev.mit.edu #9178] krb5_cc_set_config() fails to overwrite existing entries and creates duplicate credential objects
Steffen Kieß via RT
rt-comment at kerborg-prod-app-1.mit.edu
Mon Jul 7 12:10:50 EDT 2025
Mon Jul 07 12:10:50 2025: Request 9178 was acted upon.
Transaction: Ticket created by steffen.kiess at cis.iti.uni-stuttgart.de
Queue: krb5
Subject: krb5_cc_set_config() fails to overwrite existing entries and creates duplicate credential objects
Owner: Nobody
Requestors: steffen.kiess at cis.iti.uni-stuttgart.de
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).
More information about the krb5-bugs
mailing list