[31533] in CVS-changelog-for-Kerberos-V5

home help back first fref pref prev next nref lref last post

krb5 commit: Add klist -I option to show auth indicators

daemon@ATHENA.MIT.EDU (ghudson@mit.edu)
Fri May 15 18:08:05 2026

From: ghudson@mit.edu
To: cvs-krb5@mit.edu
Message-Id: <20260515220757.1E68C104332@krbdev.mit.edu>
Date: Fri, 15 May 2026 18:07:57 -0400 (EDT)
MIME-Version: 1.0
Reply-To: krbdev@mit.edu
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Errors-To: cvs-krb5-bounces@mit.edu

https://github.com/krb5/krb5/commit/e6024cd83adceef0955ba59297ed6962aa2a2302
commit e6024cd83adceef0955ba59297ed6962aa2a2302
Author: Alexander Bokovoy <abokovoy@redhat.com>
Date:   Mon Mar 30 16:18:38 2026 +0300

    Add klist -I option to show auth indicators
    
    klist -I decrypts service tickets using the provided keytab and
    displays any authentication indicators present in the ticket's
    authorization data.
    
    [ghudson@mit.edu: simplified code changes; edited commit message and
    documentation]
    
    ticket: 9208 (new)

 doc/user/user_commands/klist.rst |  13 ++++-
 src/clients/klist/klist.c        | 116 ++++++++++++++++++++++++++++++++++++---
 src/lib/krb5_32.def              |   4 ++
 src/tests/t_authdata.py          |   7 +++
 4 files changed, 132 insertions(+), 8 deletions(-)

diff --git a/doc/user/user_commands/klist.rst b/doc/user/user_commands/klist.rst
index eb5564508..8d2eac410 100644
--- a/doc/user/user_commands/klist.rst
+++ b/doc/user/user_commands/klist.rst
@@ -8,7 +8,8 @@ SYNOPSIS
 
 **klist**
 [**-e**]
-[[**-c**] [**-l**] [**-A**] [**-f**] [**-s**] [**-a** [**-n**]]]
+[[**-c**] [**-l**] [**-A**] [**-f**] [**-s**] [**-a** [**-n**]]
+[**-I** *keytab*]]
 [**-C**]
 [**-k** [**-i**] [**-t**] [**-K**]]
 [**-V**]
@@ -97,6 +98,16 @@ OPTIONS
 **-d**
     Display the authdata types (if any) for each entry.
 
+**-I** *keytab*
+    Decrypt service tickets in the credentials cache using keys from
+    *keytab* and display any authentication indicators
+    (see :ref:`auth_indicator`) found in the tickets.  Use ``-`` to
+    select the default keytab.  Authentication indicators are stored
+    inside the encrypted part of the ticket and are not accessible
+    without the service's long-term key.  Indicators will not be
+    displayed for credentials whose service key is not present in
+    *keytab*.
+
 **-V**
     Display the Kerberos version number and exit.
 
diff --git a/src/clients/klist/klist.c b/src/clients/klist/klist.c
index 59a02bedc..893a19208 100644
--- a/src/clients/klist/klist.c
+++ b/src/clients/klist/klist.c
@@ -54,6 +54,7 @@ int show_etype = 0, show_addresses = 0, no_resolve = 0, print_version = 0;
 int show_adtype = 0, show_all = 0, list_all = 0, use_client_keytab = 0;
 int show_config = 0;
 char *progname;
+char *authind_keytab = NULL;
 krb5_timestamp now;
 unsigned int timestamp_width;
 
@@ -61,7 +62,8 @@ krb5_context context;
 
 static krb5_boolean is_local_tgt(krb5_principal princ, krb5_data *realm);
 static char *etype_string(krb5_enctype );
-static void show_credential(krb5_creds *, const char *);
+static void show_credential(krb5_creds *, const char *,
+                            krb5_keytab authind_kt);
 
 static void list_all_ccaches(void);
 static int list_ccache(krb5_ccache);
@@ -82,8 +84,9 @@ static void
 usage(void)
 {
     fprintf(stderr, _("Usage: %s [-e] [-V] [[-c] [-l] [-A] [-d] [-f] [-s] "
-                      "[-a [-n]]] [-k [-i] [-t] [-K]] [-C] [name]\n"),
-            progname);
+                      "[-a [-n]] [-I keytab]]\n"
+                      "\t[-k [-i] [-t] [-K]] [-C] [name]\n\n"), progname);
+    fprintf(stderr, _("    options:\n"));
     fprintf(stderr, _("\t-c specifies credentials cache\n"));
     fprintf(stderr, _("\t-k specifies keytab\n"));
     fprintf(stderr, _("\t   (Default is credentials cache)\n"));
@@ -100,6 +103,10 @@ usage(void)
                       "existence\n"));
     fprintf(stderr, _("\t\t-a displays the address list\n"));
     fprintf(stderr, _("\t\t\t-n do not reverse-resolve\n"));
+    fprintf(stderr, _("\t\t-I decrypts tickets using the specified keytab "
+                      "and shows\n"
+                      "\t\t   authentication indicators; use - for default "
+                      "keytab\n"));
     fprintf(stderr, _("\toptions for keytabs:\n"));
     fprintf(stderr, _("\t\t-t shows keytab entry timestamps\n"));
     fprintf(stderr, _("\t\t-K shows keytab entry keys\n"));
@@ -134,7 +141,7 @@ main(int argc, char *argv[])
     name = NULL;
     mode = DEFAULT;
     /* V = version so v can be used for verbose later if desired. */
-    while ((c = getopt(argc, argv, "dfetKsnacki45lAVC")) != -1) {
+    while ((c = getopt(argc, argv, "dfetKsnacki45lAVCI:")) != -1) {
         switch (c) {
         case 'd':
             show_adtype = 1;
@@ -188,6 +195,9 @@ main(int argc, char *argv[])
         case 'C':
             show_config = 1;
             break;
+        case 'I':
+            authind_keytab = optarg;
+            break;
         case 'V':
             print_version = 1;
             break;
@@ -207,7 +217,7 @@ main(int argc, char *argv[])
             usage();
     } else {
         if (show_flags || status_only || show_addresses ||
-            show_all || list_all)
+            show_all || list_all || authind_keytab != NULL)
             usage();
     }
 
@@ -471,6 +481,7 @@ show_ccache(krb5_ccache cache)
     krb5_cc_cursor cur = NULL;
     krb5_creds creds;
     krb5_principal princ = NULL;
+    krb5_keytab authind_kt = NULL;
     krb5_error_code ret;
     char *defname = NULL;
     int status = 1;
@@ -496,6 +507,17 @@ show_ccache(krb5_ccache cache)
     fillit(stdout, timestamp_width - sizeof("Expires") + 3, (int) ' ');
     fputs("Service principal\n", stdout);
 
+    if (authind_keytab != NULL) {
+        if (strcmp(authind_keytab, "-") == 0)
+            ret = krb5_kt_default(context, &authind_kt);
+        else
+            ret = krb5_kt_resolve(context, authind_keytab, &authind_kt);
+        if (ret) {
+            com_err(progname, ret, _("while resolving keytab"));
+            goto cleanup;
+        }
+    }
+
     ret = krb5_cc_start_seq_get(context, cache, &cur);
     if (ret) {
         com_err(progname, ret, _("while starting to retrieve tickets"));
@@ -503,7 +525,7 @@ show_ccache(krb5_ccache cache)
     }
     while ((ret = krb5_cc_next_cred(context, cache, &cur, &creds)) == 0) {
         if (show_config || !krb5_is_config_principal(context, creds.server))
-            show_credential(&creds, defname);
+            show_credential(&creds, defname, authind_kt);
         krb5_free_cred_contents(context, &creds);
     }
     if (ret == KRB5_CC_END) {
@@ -523,6 +545,8 @@ show_ccache(krb5_ccache cache)
 cleanup:
     if (cur != NULL)
         (void)krb5_cc_end_seq_get(context, cache, &cur);
+    if (authind_kt != NULL)
+        krb5_kt_close(context, authind_kt);
     krb5_free_principal(context, princ);
     krb5_free_unparsed_name(context, defname);
     return status;
@@ -675,8 +699,83 @@ print_config_data(int col, krb5_data *data)
         putchar('\n');
 }
 
+/*
+ * Decrypt tkt using authind_keytab, then extract and display any
+ * authentication indicators from the ticket.  Failures are silently
+ * ignored (key not in keytab, no indicators, etc.).
+ */
+static void
+show_auth_indicators(krb5_ticket *tkt, krb5_keytab authind_kt)
+{
+    krb5_error_code ret;
+    krb5_keytab_entry entry = { 0 };
+    krb5_authdata **authdata, **ifrel, **cammac;
+    krb5_data **indicators = NULL;
+    int i, j, k;
+
+    ret = krb5_server_decrypt_ticket_keytab(context, authind_kt, tkt);
+    if (ret)
+        goto cleanup;
+
+    /* Look up the service key for CAMMAC verification. */
+    ret = krb5_kt_get_entry(context, authind_kt, tkt->server, 0,
+                            tkt->enc_part.enctype, &entry);
+    if (ret)
+        goto cleanup;
+
+    if (tkt->enc_part2 == NULL || tkt->enc_part2->authorization_data == NULL)
+        goto cleanup;
+
+    authdata = tkt->enc_part2->authorization_data;
+    for (i = 0; authdata[i] != NULL; i++) {
+        if (authdata[i]->ad_type != KRB5_AUTHDATA_IF_RELEVANT)
+            continue;
+
+        ret = krb5_decode_authdata_container(context,
+                                             KRB5_AUTHDATA_IF_RELEVANT,
+                                             authdata[i], &ifrel);
+        if (ret)
+            continue;
+
+        for (j = 0; ifrel[j] != NULL; j++) {
+            if (ifrel[j]->ad_type != KRB5_AUTHDATA_CAMMAC)
+                continue;
+
+            /* Verify and unwrap the CAMMAC using the service key. */
+            ret = k5_unwrap_cammac_svc(context, ifrel[j], &entry.key,
+                                       &cammac);
+            if (ret)
+                continue;
+
+            for (k = 0; cammac[k] != NULL; k++) {
+                if (cammac[k]->ad_type != KRB5_AUTHDATA_AUTH_INDICATOR)
+                    continue;
+                (void)k5_authind_decode(cammac[k], &indicators);
+            }
+
+            krb5_free_authdata(context, cammac);
+        }
+
+        krb5_free_authdata(context, ifrel);
+    }
+
+    if (indicators != NULL) {
+        printf(_("\tAuthentication indicators: "));
+        for (i = 0; indicators[i] != NULL; i++) {
+            if (i)
+                printf(", ");
+            printf("%.*s", (int)indicators[i]->length, indicators[i]->data);
+        }
+        printf("\n");
+    }
+
+cleanup:
+    k5_free_data_ptr_list(indicators);
+    krb5_free_keytab_entry_contents(context, &entry);
+}
+
 static void
-show_credential(krb5_creds *cred, const char *defname)
+show_credential(krb5_creds *cred, const char *defname, krb5_keytab authind_kt)
 {
     krb5_error_code ret;
     krb5_ticket *tkt = NULL;
@@ -816,6 +915,9 @@ show_credential(krb5_creds *cred, const char *defname)
         krb5_free_unparsed_name(context, tktsname);
     }
 
+    if (authind_kt != NULL && !is_config && tkt != NULL)
+        show_auth_indicators(tkt, authind_kt);
+
 cleanup:
     krb5_free_unparsed_name(context, name);
     krb5_free_unparsed_name(context, sname);
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
index c5a460185..23ad3f402 100644
--- a/src/lib/krb5_32.def
+++ b/src/lib/krb5_32.def
@@ -517,3 +517,7 @@ EXPORTS
 	encode_krb5_pkinit_supp_pub_info		@478 ; PRIVATE
 	krb5int_copy_data_contents			@479 ; PRIVATE
 	krb5_free_pa_data				@480 ; PRIVATE
+; private symbols new in 1.23, used by klist
+	k5_unwrap_cammac_svc				@481 ; PRIVATE
+	k5_authind_decode				@482 ; PRIVATE
+	k5_free_data_ptr_list				@483 ; PRIVATE
diff --git a/src/tests/t_authdata.py b/src/tests/t_authdata.py
index 72b57b0d7..d7b89cc26 100644
--- a/src/tests/t_authdata.py
+++ b/src/tests/t_authdata.py
@@ -192,6 +192,13 @@ realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e', 'aes128-cts',
 realm.kinit(realm.user_princ, None, ['-R'])
 realm.run([kvno, realm.host_princ])
 
+mark('klist -I keytab auth indicators')
+realm.kinit(realm.user_princ, password('user'),
+            ['-X', 'indicators=indcl', '-S', realm.host_princ])
+realm.run([klist, '-I', realm.keytab],
+          expected_msg='Authentication indicators: indcl')
+realm.run([klist, '-I', '-'], expected_msg='Authentication indicators: indcl')
+
 realm.stop()
 realm2.stop()
 
_______________________________________________
cvs-krb5 mailing list
cvs-krb5@mit.edu
https://mailman.mit.edu/mailman/listinfo/cvs-krb5

home help back first fref pref prev next nref lref last post