]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Fix AS-REQ checking of KDB-modified indicators 1040/head
authorGreg Hudson <ghudson@mit.edu>
Wed, 19 Feb 2020 20:36:38 +0000 (15:36 -0500)
committerGreg Hudson <ghudson@mit.edu>
Fri, 21 Feb 2020 18:00:00 +0000 (13:00 -0500)
Commit 7196c03f18f14695abeb5ae4923004469b172f0f (ticket 8823) gave the
KDB the ability to modify auth indicators, but it happens after the
asserted indicators are checked against the server principal
requirements.  In finish_process_as_req(), move the call to
check_indicators() after the call to handle_authdata() so that the
final indicator list is checked.

For the test case, add string attribute functionality to the test KDB
module, and fix a bug where test_get_principal() would return failure
if a principal has no keys.  Also add a test case for AS-REQ
enforcement of normally asserted auth indicators.

ticket: 8876 (new)
tags: pullup
target_version: 1.18-next

src/kdc/do_as_req.c
src/plugins/kdb/test/kdb_test.c
src/tests/t_authdata.py

index 87dd7e9934cd8a3cf1b5cdceddc3634f5f3dee69..9ae7b0a5e8720031b775529234e5b8eee569ff5c 100644 (file)
@@ -211,13 +211,6 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
 
     au_state->stage = ENCR_REP;
 
-    errcode = check_indicators(kdc_context, state->server,
-                               state->auth_indicators);
-    if (errcode) {
-        state->status = "HIGHER_AUTHENTICATION_REQUIRED";
-        goto egress;
-    }
-
     state->ticket_reply.enc_part2 = &state->enc_tkt_reply;
 
     errcode = check_kdcpolicy_as(kdc_context, state->request, state->client,
@@ -301,6 +294,13 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
         goto egress;
     }
 
+    errcode = check_indicators(kdc_context, state->server,
+                               state->auth_indicators);
+    if (errcode) {
+        state->status = "HIGHER_AUTHENTICATION_REQUIRED";
+        goto egress;
+    }
+
     errcode = krb5_encrypt_tkt_part(kdc_context, &state->server_keyblock,
                                     &state->ticket_reply);
     if (errcode)
index 8aac306aa3d11f60746c1d42ebd1fd08ca55f138..2138abc767a2e535d906033d573302cb433a1ffb 100644 (file)
@@ -54,6 +54,8 @@
  *                     # Initial number is kvno; defaults to 1.
  *                     keys = 3 aes256-cts aes128-cts:normal
  *                     keys = 2 rc4-hmac
+ *                     strings = key1:value1
+ *                     strings = key2:value2
  *                 }
  *             }
  *             delegation = {
@@ -282,6 +284,33 @@ make_keys(char **strings, const char *princstr, const krb5_data *realm,
     ent->n_key_data = nkeys;
 }
 
+static void
+make_strings(char **stringattrs, krb5_db_entry *ent)
+{
+    struct k5buf buf;
+    char **p;
+    const char *str, *sep;
+    krb5_tl_data *tl;
+
+    k5_buf_init_dynamic(&buf);
+    for (p = stringattrs; *p != NULL; p++) {
+        str = *p;
+        sep = strchr(str, ':');
+        assert(sep != NULL);
+        k5_buf_add_len(&buf, str, sep - str);
+        k5_buf_add_len(&buf, "\0", 1);
+        k5_buf_add_len(&buf, sep + 1, strlen(sep + 1) + 1);
+    }
+    assert(buf.data != NULL);
+
+    tl = ealloc(sizeof(*ent->tl_data));
+    tl->tl_data_next = NULL;
+    tl->tl_data_type = KRB5_TL_STRING_ATTRS;
+    tl->tl_data_length = buf.len;
+    tl->tl_data_contents = buf.data;
+    ent->tl_data = tl;
+}
+
 static krb5_error_code
 test_init()
 {
@@ -360,7 +389,8 @@ test_get_principal(krb5_context context, krb5_const_principal search_for,
     krb5_principal princ = NULL, tgtprinc;
     krb5_principal_data empty_princ = { KV5M_PRINCIPAL };
     testhandle h = context->dal_handle->db_context;
-    char *search_name = NULL, *canon = NULL, *flagstr, **names, **key_strings;
+    char *search_name = NULL, *canon = NULL, *flagstr;
+    char **names, **key_strings, **stringattrs;
     const char *ename;
     krb5_db_entry *ent;
 
@@ -439,7 +469,7 @@ test_get_principal(krb5_context context, krb5_const_principal search_for,
     ent->pw_expiration = get_time(h, "princs", ename, "pwexpiration");
 
     /* Leave last_success, last_failed, fail_auth_count zeroed. */
-    /* Leave tl_data and e_data empty. */
+    /* Leave e_data empty. */
 
     set_names(h, "princs", ename, "keys");
     ret = profile_get_values(h->profile, h->names, &key_strings);
@@ -448,11 +478,19 @@ test_get_principal(krb5_context context, krb5_const_principal search_for,
         profile_free_list(key_strings);
     }
 
+    set_names(h, "princs", ename, "strings");
+    ret = profile_get_values(h->profile, h->names, &stringattrs);
+    if (ret != PROF_NO_RELATION) {
+        make_strings(stringattrs, ent);
+        profile_free_list(stringattrs);
+    }
+
     /* We must include mod-princ data or kadm5_get_principal() won't work and
      * we can't extract keys with kadmin.local. */
     check(krb5_dbe_update_mod_princ_data(context, ent, 0, &empty_princ));
 
     *entry = ent;
+    ret = 0;
 
 cleanup:
     krb5_free_unparsed_name(context, search_name);
index 76b8fcd4bfc1b327d916c8047c698b444420ee9c..3fa957ad27686c61e0a2b53235c549f5dc7072c4 100644 (file)
@@ -158,6 +158,8 @@ realm.run(['./adata', realm.host_princ], expected_msg='+97: [indcl]')
 mark('auth indicator enforcement')
 realm.addprinc('restricted')
 realm.run([kadminl, 'setstr', 'restricted', 'require_auth', 'superstrong'])
+realm.kinit(realm.user_princ, password('user'), ['-S', 'restricted'],
+            expected_code=1, expected_msg='KDC policy rejects request')
 realm.run([kvno, 'restricted'], expected_code=1,
           expected_msg='KDC policy rejects request')
 realm.run([kadminl, 'setstr', 'restricted', 'require_auth', 'indcl'])
@@ -194,6 +196,8 @@ testprincs = {'krbtgt/KRBTEST.COM': {'keys': 'aes128-cts'},
               'krbtgt/FOREIGN': {'keys': 'aes128-cts'},
               'user': {'keys': 'aes128-cts', 'flags': '+preauth'},
               'user2': {'keys': 'aes128-cts', 'flags': '+preauth'},
+              'rservice': {'keys': 'aes128-cts',
+                           'strings': 'require_auth:strong'},
               'service/1': {'keys': 'aes128-cts',
                             'flags': '+ok_to_auth_as_delegate'},
               'service/2': {'keys': 'aes128-cts'},
@@ -208,6 +212,7 @@ usercache = 'FILE:' + os.path.join(realm.testdir, 'usercache')
 realm.extract_keytab(realm.krbtgt_princ, realm.keytab)
 realm.extract_keytab('krbtgt/FOREIGN', realm.keytab)
 realm.extract_keytab(realm.user_princ, realm.keytab)
+realm.extract_keytab('ruser', realm.keytab)
 realm.extract_keytab('service/1', realm.keytab)
 realm.extract_keytab('service/2', realm.keytab)
 realm.extract_keytab('noauthdata', realm.keytab)
@@ -252,6 +257,12 @@ if ' -2: self_ad' not in out or ' -2: proxy_ad' not in out:
 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]')
+realm.kinit(realm.user_princ, None,
+            ['-k', '-X', 'indicators=strong', '-S', 'rservice'])
+# Test enforcement of altered indicators during AS request.
+realm.kinit(realm.user_princ, None,
+            ['-k', '-X', 'indicators=strong dbincr1', '-S', 'rservice'],
+            expected_code=1)
 
 # Test that KDB module authdata is included in an AS request, by
 # default or with an explicit PAC request.