From 68dbf1ba1071983aca9ec60d1edce387fd98a18e Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Mon, 17 Jun 2024 11:16:28 -0400 Subject: [PATCH] krb5: fcc_next_cred do not return removed creds commit a9bd3c6e5043fb3bb67dc338cf5a7e745a90590e ("Fix racy file ccache corruption in cred_delete()") implemented krb5_cc_remove_cred() for "FILE" ccaches by overwriting the removed credential endtime value with zero (Unix Epoch). However, it did not modify fcc_get_next() to filter out these deleted entries. As a result, invalid credentials can be returned from the FILE ccache where endtime < starttime. RFC4120 requires endtime >= starttime for all tickets. MIT Kerberos since d3b39a8bac6206b5ea78b0bf6a2958c1df0b0dd5 ("Implement krb5_cc_remove_cred for remaining types") modifies a removed cred by setting endtime = 0 authtime = -1 and then filters out removed creds from the fcc_next_cred() results. In 2013 Heimdal broke interop with MIT processes that share the FILE ccache by implementing remove by setting "endtime = 0" and now MIT has broken interop with the Heimdal implementation of fcc_remove_cred() by checking for both "endtime = 0" and "authtime = -1". This change filters results from fcc_get_next() when the "endtime == 0" which is acceptable because a KDC is not permitted to return a ticket with an endtime == 0. --- lib/krb5/fcache.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/krb5/fcache.c b/lib/krb5/fcache.c index 9fed685d6..adf22eb72 100644 --- a/lib/krb5/fcache.c +++ b/lib/krb5/fcache.c @@ -997,15 +997,25 @@ fcc_get_next (krb5_context context, if (FCC_CURSOR(*cursor) == NULL) return krb5_einval(context, 3); - FCC_CURSOR(*cursor)->cred_start = - krb5_storage_seek(FCC_CURSOR(*cursor)->sp, 0, SEEK_CUR); + while (1) { + FCC_CURSOR(*cursor)->cred_start = + krb5_storage_seek(FCC_CURSOR(*cursor)->sp, 0, SEEK_CUR); - ret = krb5_ret_creds(FCC_CURSOR(*cursor)->sp, creds); - if (ret) - krb5_clear_error_message(context); + ret = krb5_ret_creds(FCC_CURSOR(*cursor)->sp, creds); - FCC_CURSOR(*cursor)->cred_end = - krb5_storage_seek(FCC_CURSOR(*cursor)->sp, 0, SEEK_CUR); + FCC_CURSOR(*cursor)->cred_end = + krb5_storage_seek(FCC_CURSOR(*cursor)->sp, 0, SEEK_CUR); + + if (ret) { + krb5_clear_error_message(context); + break; + } + + if (creds->times.endtime != 0) + break; + + krb5_free_cred_contents(context, creds); + } return ret; }