krb5 commit: Allow the KDB to see and modify auth indicators

Greg Hudson <[email protected]>
Newsgroups gmane.comp.encryption.kerberos.cvs
Message-ID <[email protected]>
https://github.com/krb5/krb5/commit/7196c03f18f14695abeb5ae4923004469b172f0f
commit 7196c03f18f14695abeb5ae4923004469b172f0f
Author: Greg Hudson <[email protected]>
Date:   Wed Aug 7 17:51:17 2019 -0400

    Allow the KDB to see and modify auth indicators
    
    Amend the sign_authdata method signature to include a modifiable
    auth_indicators array.  Bump the DAL major version and the libkdb5
    soname.  Add a test case using the test KDB module.
    
    ticket: 8823 (new)

 src/include/kdb.h               |   16 +++++++++++-----
 src/kdc/do_as_req.c             |    2 +-
 src/kdc/do_tgs_req.c            |    9 ++-------
 src/kdc/kdc_authdata.c          |   26 +++++++++++++++-----------
 src/kdc/kdc_util.h              |    2 +-
 src/lib/kdb/Makefile.in         |    2 +-
 src/lib/kdb/kdb5.c              |   10 +++-------
 src/plugins/kdb/test/kdb_test.c |   23 ++++++++++++++++++++++-
 src/tests/t_authdata.py         |    5 +++++
 9 files changed, 61 insertions(+), 34 deletions(-)

diff --git a/src/include/kdb.h b/src/include/kdb.h
index 86d4a64..38419f6 100644
--- a/src/include/kdb.h
+++ b/src/include/kdb.h
@@ -69,7 +69,7 @@
 
 /* This version will be incremented when incompatible changes are made to the
  * KDB API, and will be kept in sync with the libkdb major version. */
-#define KRB5_KDB_API_VERSION 9
+#define KRB5_KDB_API_VERSION 10
 
 /* Salt types */
 #define KRB5_KDB_SALTTYPE_NORMAL        0
@@ -670,6 +670,7 @@ krb5_error_code krb5_db_sign_authdata(krb5_context kcontext,
                                       krb5_keyblock *session_key,
                                       krb5_timestamp authtime,
                                       krb5_authdata **tgt_auth_data,
+                                      krb5_data ***auth_indicators,
                                       krb5_authdata ***signed_auth_data);
 
 krb5_error_code krb5_db_check_transited_realms(krb5_context kcontext,
@@ -871,7 +872,7 @@ krb5_error_code krb5_db_register_keytab(krb5_context context);
  * This number indicates the date of the last incompatible change to the DAL.
  * The maj_ver field of the module's vtable structure must match this version.
  */
-#define KRB5_KDB_DAL_MAJOR_VERSION 7
+#define KRB5_KDB_DAL_MAJOR_VERSION 8
 
 /*
  * A krb5_context can hold one database object.  Modules should use
@@ -1304,6 +1305,12 @@ typedef struct _kdb_vftabl {
      *
      *   tgt_auth_data: For TGS requests, the authorization data present in the
      *     subject ticket.  For AS requests, NULL.
+     *
+     *   auth_indicators: Points to NULL or a null-terminated list of krb5_data
+     *     pointers, each containing an authentication indicator (RFC 8129).
+     *     The method may modify this list, or free it and replace
+     *     *auth_indicators with NULL, to change which auth indicators will be
+     *     included in the ticket.
      */
     krb5_error_code (*sign_authdata)(krb5_context kcontext,
                                      unsigned int flags,
@@ -1317,6 +1324,7 @@ typedef struct _kdb_vftabl {
                                      krb5_keyblock *session_key,
                                      krb5_timestamp authtime,
                                      krb5_authdata **tgt_auth_data,
+                                     krb5_data ***auth_indicators,
                                      krb5_authdata ***signed_auth_data);
 
     /*
@@ -1405,8 +1413,6 @@ typedef struct _kdb_vftabl {
      */
     void (*free_principal_e_data)(krb5_context kcontext, krb5_octet *e_data);
 
-    /* End of minor version 0. */
-
     /*
      * Optional: get a principal entry for S4U2Self based on X509 certificate.
      *
@@ -1426,7 +1432,7 @@ typedef struct _kdb_vftabl {
                                               unsigned int flags,
                                               krb5_db_entry **entry_out);
 
-    /* End of minor version 1 for major version 7. */
+    /* End of minor version 0 for major version 8. */
 } kdb_vftabl;
 
 #endif /* !defined(_WIN32) */
diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
index a14e64f..894a9d4 100644
--- a/src/kdc/do_as_req.c
+++ b/src/kdc/do_as_req.c
@@ -300,7 +300,7 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
                               &state->local_tgt_key, &state->client_keyblock,
                               &state->server_keyblock, NULL, state->req_pkt,
                               state->request, NULL, NULL,
-                              state->auth_indicators, &state->enc_tkt_reply);
+                              &state->auth_indicators, &state->enc_tkt_reply);
     if (errcode) {
         krb5_klog_syslog(LOG_INFO, _("AS_REQ : handle_authdata (%d)"),
                          errcode);
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
index 98f4cc6..bed5630 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -610,15 +610,10 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
                               header_server, local_tgt, &local_tgt_key,
                               subkey != NULL ? subkey :
                               header_ticket->enc_part2->session,
-                              encrypting_key, /* U2U or server key */
-                              header_key,
-                              pkt,
-                              request,
+                              encrypting_key, header_key, pkt, request,
                               s4u_x509_user ?
                               s4u_x509_user->user_id.user : NULL,
-                              subject_tkt,
-                              auth_indicators,
-                              &enc_tkt_reply);
+                              subject_tkt, &auth_indicators, &enc_tkt_reply);
     if (errcode) {
         krb5_klog_syslog(LOG_INFO, _("TGS_REQ : handle_authdata (%d)"),
                          errcode);
diff --git a/src/kdc/kdc_authdata.c b/src/kdc/kdc_authdata.c
index df670e8..72e830d 100644
--- a/src/kdc/kdc_authdata.c
+++ b/src/kdc/kdc_authdata.c
@@ -320,7 +320,8 @@ fetch_kdb_authdata(krb5_context context, unsigned int flags,
                    krb5_keyblock *server_key, krb5_keyblock *header_key,
                    krb5_kdc_req *req, krb5_const_principal for_user_princ,
                    krb5_enc_tkt_part *enc_tkt_req,
-                   krb5_enc_tkt_part *enc_tkt_reply)
+                   krb5_enc_tkt_part *enc_tkt_reply,
+                   krb5_data ***auth_indicators)
 {
     krb5_error_code ret;
     krb5_authdata **tgt_authdata, **db_authdata = NULL;
@@ -379,7 +380,7 @@ fetch_kdb_authdata(krb5_context context, unsigned int flags,
                                 server, krbtgt, client_key, server_key,
                                 krbtgt_key, enc_tkt_reply->session,
                                 enc_tkt_reply->times.authtime, tgt_authdata,
-                                &db_authdata);
+                                auth_indicators, &db_authdata);
     if (ret)
         return (ret == KRB5_PLUGIN_OP_NOTSUPP) ? 0 : ret;
 
@@ -824,7 +825,7 @@ handle_authdata(krb5_context context, unsigned int flags,
                 krb5_data *req_pkt, krb5_kdc_req *req,
                 krb5_const_principal for_user_princ,
                 krb5_enc_tkt_part *enc_tkt_req,
-                krb5_data *const *auth_indicators,
+                krb5_data ***auth_indicators,
                 krb5_enc_tkt_part *enc_tkt_reply)
 {
     kdcauthdata_handle *h;
@@ -862,23 +863,26 @@ handle_authdata(krb5_context context, unsigned int flags,
             return ret;
     }
 
+    if (!isflagset(enc_tkt_reply->flags, TKT_FLG_ANONYMOUS)) {
+        /* Fetch authdata from the KDB if appropriate. */
+        ret = fetch_kdb_authdata(context, flags, client, server, header_server,
+                                 client_key, server_key, header_key, req,
+                                 for_user_princ, enc_tkt_req, enc_tkt_reply,
+                                 auth_indicators);
+        if (ret)
+            return ret;
+    }
+
     /* Add auth indicators if any were given. */
     if (auth_indicators != NULL && *auth_indicators != NULL &&
         !isflagset(server->attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED)) {
-        ret = add_auth_indicators(context, auth_indicators, server_key,
+        ret = add_auth_indicators(context, *auth_indicators, server_key,
                                   local_tgt, local_tgt_key, enc_tkt_reply);
         if (ret)
             return ret;
     }
 
     if (!isflagset(enc_tkt_reply->flags, TKT_FLG_ANONYMOUS)) {
-        /* Fetch authdata from the KDB if appropriate. */
-        ret = fetch_kdb_authdata(context, flags, client, server, header_server,
-                                 client_key, server_key, header_key, req,
-                                 for_user_princ, enc_tkt_req, enc_tkt_reply);
-        if (ret)
-            return ret;
-
         /* Validate and insert AD-SIGNTICKET authdata.  This must happen last
          * since it contains a signature over the other authdata. */
         ret = handle_signticket(context, flags, client, server, local_tgt,
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index f41c0d9..8583a91 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -236,7 +236,7 @@ handle_authdata (krb5_context context,
                  krb5_kdc_req *request,
                  krb5_const_principal for_user_princ,
                  krb5_enc_tkt_part *enc_tkt_request,
-                 krb5_data *const *auth_indicators,
+                 krb5_data ***auth_indicators,
                  krb5_enc_tkt_part *enc_tkt_reply);
 
 /* replay.c */
diff --git a/src/lib/kdb/Makefile.in b/src/lib/kdb/Makefile.in
index b77bf49..25da081 100644
--- a/src/lib/kdb/Makefile.in
+++ b/src/lib/kdb/Makefile.in
@@ -5,7 +5,7 @@ LOCALINCLUDES= -I.
 
 # Keep LIBMAJOR in sync with KRB5_KDB_API_VERSION in include/kdb.h.
 LIBBASE=kdb5
-LIBMAJOR=9
+LIBMAJOR=10
 LIBMINOR=0
 LIBINITFUNC=kdb_init_lock_list
 LIBFINIFUNC=kdb_fini_lock_list
diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c
index b910bd3..3058b47 100644
--- a/src/lib/kdb/kdb5.c
+++ b/src/lib/kdb/kdb5.c
@@ -323,12 +323,7 @@ copy_vtable(const kdb_vftabl *in, kdb_vftabl *out)
     out->refresh_config = in->refresh_config;
     out->check_allowed_to_delegate = in->check_allowed_to_delegate;
     out->free_principal_e_data = in->free_principal_e_data;
-
-    /* Copy fields for minor version 1 (major version 7). */
-    assert(KRB5_KDB_DAL_MAJOR_VERSION == 7);
-    out->get_s4u_x509_principal = NULL;
-    if (in->min_ver >= 1)
-        out->get_s4u_x509_principal = in->get_s4u_x509_principal;
+    out->get_s4u_x509_principal = in->get_s4u_x509_principal;
 
     /* Set defaults for optional fields. */
     if (out->fetch_master_key == NULL)
@@ -2599,6 +2594,7 @@ krb5_db_sign_authdata(krb5_context kcontext, unsigned int flags,
                       krb5_keyblock *client_key, krb5_keyblock *server_key,
                       krb5_keyblock *krbtgt_key, krb5_keyblock *session_key,
                       krb5_timestamp authtime, krb5_authdata **tgt_auth_data,
+                      krb5_data ***auth_indicators,
                       krb5_authdata ***signed_auth_data)
 {
     krb5_error_code status = 0;
@@ -2613,7 +2609,7 @@ krb5_db_sign_authdata(krb5_context kcontext, unsigned int flags,
     return v->sign_authdata(kcontext, flags, client_princ, client, server,
                             krbtgt, client_key, server_key, krbtgt_key,
                             session_key, authtime, tgt_auth_data,
-                            signed_auth_data);
+                            auth_indicators, signed_auth_data);
 }
 
 krb5_error_code
diff --git a/src/plugins/kdb/test/kdb_test.c b/src/plugins/kdb/test/kdb_test.c
index 690c025..351bd8c 100644
--- a/src/plugins/kdb/test/kdb_test.c
+++ b/src/plugins/kdb/test/kdb_test.c
@@ -544,9 +544,12 @@ test_sign_authdata(krb5_context context, unsigned int flags,
                    krb5_keyblock *client_key, krb5_keyblock *server_key,
                    krb5_keyblock *krbtgt_key, krb5_keyblock *session_key,
                    krb5_timestamp authtime, krb5_authdata **tgt_auth_data,
+                   krb5_data ***auth_indicators,
                    krb5_authdata ***signed_auth_data)
 {
     krb5_authdata **list, *ad;
+    krb5_data **inds, d;
+    int i, val;
 
     ad = ealloc(sizeof(*ad));
     ad->magic = KV5M_AUTHDATA;
@@ -557,6 +560,24 @@ test_sign_authdata(krb5_context context, unsigned int flags,
     list[0] = ad;
     list[1] = NULL;
     *signed_auth_data = list;
+
+    /* If we see an auth indicator "dbincrX", replace the whole indicator list
+     * with "dbincr{X+1}". */
+    inds = *auth_indicators;
+    for (i = 0; inds != NULL && inds[i] != NULL; i++) {
+        if (inds[i]->length == 7 && memcmp(inds[i]->data, "dbincr", 6) == 0) {
+            val = inds[i]->data[6];
+            k5_free_data_ptr_list(inds);
+            inds = ealloc(2 * sizeof(*inds));
+            d = string2data("dbincr0");
+            check(krb5_copy_data(context, &d, &inds[0]));
+            inds[0]->data[6] = val + 1;
+            inds[1] = NULL;
+            *auth_indicators = inds;
+            break;
+        }
+    }
+
     return 0;
 }
 
@@ -593,7 +614,7 @@ test_check_allowed_to_delegate(krb5_context context,
 
 kdb_vftabl PLUGIN_SYMBOL_NAME(krb5_test, kdb_function_table) = {
     KRB5_KDB_DAL_MAJOR_VERSION,             /* major version number */
-    1,                                      /* minor version number */
+    0,                                      /* minor version number */
     test_init,
     test_cleanup,
     test_open,
diff --git a/src/tests/t_authdata.py b/src/tests/t_authdata.py
index d98974b..9b41bc0 100644
--- a/src/tests/t_authdata.py
+++ b/src/tests/t_authdata.py
@@ -228,6 +228,11 @@ out = realm.run(['./adata', '-p', realm.user_princ, 'service/2'])
 if '+97: [indcl]' not in out or '[inds1]' in out:
     fail('correct auth-indicator not seen for S4U2Proxy req')
 
+# Test alteration of auth indicators by KDB module (AS and TGS).
+realm.kinit(realm.user_princ, None, ['-k', '-X', 'indicators=dummy dbincr1'])
+realm.run(['./adata', realm.krbtgt_princ], expected_msg='+97: [dbincr2]')
+realm.run(['./adata', 'service/1'], expected_msg='+97: [dbincr3]')
+
 # Test that KDB module authdata is included in an AS request, by
 # default or with an explicit PAC request.
 mark('AS-REQ KDB module authdata')
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.