lib/krb5_wrap: let smb_krb5_cc_get_lifetime() behave more like the heimdal krb5_cc_ge...
authorStefan Metzmacher <metze@samba.org>
Fri, 8 Mar 2024 10:39:35 +0000 (11:39 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 23 Apr 2024 14:17:32 +0000 (14:17 +0000)
If the ccache doesn't have a intial TGT the shortest lifetime of
service tickets should be returned.

This is needed in order to work with special ccaches used for
things like S2U4Self/S4U2Proxy tickets or other things
where the caller only wants to pass a single service ticket.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
lib/krb5_wrap/krb5_samba.c

index 6865b049b7745053545d709bfd4ced657c6dd869..7cc28697e8162d60aeff669f950aae727d4b5d10 100644 (file)
@@ -3028,6 +3028,7 @@ krb5_error_code smb_krb5_cc_get_lifetime(krb5_context context,
        krb5_cc_cursor cursor;
        krb5_error_code kerr;
        krb5_creds cred;
+       krb5_timestamp endtime = 0;
        krb5_timestamp now;
 
        *t = 0;
@@ -3043,20 +3044,45 @@ krb5_error_code smb_krb5_cc_get_lifetime(krb5_context context,
        }
 
        while ((kerr = krb5_cc_next_cred(context, id, &cursor, &cred)) == 0) {
+               if (krb5_is_config_principal(context, cred.server)) {
+                       krb5_free_cred_contents(context, &cred);
+                       continue;
+               }
+
 #ifndef HAVE_FLAGS_IN_KRB5_CREDS
                if (cred.ticket_flags & TKT_FLG_INITIAL) {
 #else
                if (cred.flags.b.initial) {
 #endif
                        if (now < cred.times.endtime) {
-                               *t = (time_t) (cred.times.endtime - now);
+                               endtime = cred.times.endtime;
                        }
                        krb5_free_cred_contents(context, &cred);
                        break;
                }
+
+               if (cred.times.endtime <= now) {
+                       /* already expired */
+                       krb5_free_cred_contents(context, &cred);
+                       continue;
+               }
+
+               /**
+                * If there was no krbtgt, use the shortest lifetime of
+                * service tickets that have yet to expire.  If all
+                * credentials are expired, krb5_cc_get_lifetime() will fail.
+                */
+               if (endtime == 0 || cred.times.endtime < endtime) {
+                       endtime = cred.times.endtime;
+               }
                krb5_free_cred_contents(context, &cred);
        }
 
+       if (now < endtime) {
+               *t = (time_t) (endtime - now);
+               kerr = 0;
+       }
+
        krb5_cc_end_seq_get(context, id, &cursor);
 
        return kerr;