[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