auth: keytab invalidation test
authorAaron Haslett <aaronhaslett@catalyst.net.nz>
Mon, 30 Apr 2018 23:10:24 +0000 (11:10 +1200)
committerAndreas Schneider <asn@cryptomilk.org>
Tue, 15 May 2018 10:41:55 +0000 (12:41 +0200)
chgtdcpass should add a new DC password and delete the old ones but the bug
exposed by this test causes the tool to remove only a single record from
the old entries, leaving the old passwords functional.  Since the tool is
used by administrators who may have disclosed their domain join password and
want to invalidate it, this is a security concern.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13415

Signed-off-by: Aaron Haslett <aaronhaslett@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
selftest/knownfail.d/keytab [new file with mode: 0644]
selftest/tests.py
source4/auth/tests/kerberos.c [new file with mode: 0644]
source4/auth/wscript_build

diff --git a/selftest/knownfail.d/keytab b/selftest/knownfail.d/keytab
new file mode 100644 (file)
index 0000000..6777d98
--- /dev/null
@@ -0,0 +1 @@
+^samba.unittests.kerberos.test_krb5_remove_obsolete_keytab_entries_many
index 185ad37fd4ae35dea4ec967387e139019e58d3e6..f354bb57ef5d54ead876e230fca92ca29090ce2e 100644 (file)
@@ -187,5 +187,7 @@ plantestsuite("samba.unittests.tldap", "none",
               [os.path.join(bindir(), "default/source3/test_tldap")])
 plantestsuite("samba.unittests.rfc1738", "none",
               [os.path.join(bindir(), "default/lib/util/test_rfc1738")])
+plantestsuite("samba.unittests.kerberos", "none",
+              [os.path.join(bindir(), "test_kerberos")])
 plantestsuite("samba.unittests.ms_fnmatch", "none",
               [os.path.join(bindir(), "default/lib/util/test_ms_fnmatch")])
diff --git a/source4/auth/tests/kerberos.c b/source4/auth/tests/kerberos.c
new file mode 100644 (file)
index 0000000..703c806
--- /dev/null
@@ -0,0 +1,107 @@
+#include <time.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdint.h>
+#include <cmocka.h>
+
+#include "includes.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
+#include "auth/credentials/credentials.h"
+#include "auth/credentials/credentials_proto.h"
+#include "auth/credentials/credentials_krb5.h"
+#include "auth/kerberos/kerberos_credentials.h"
+#include "auth/kerberos/kerberos_util.h"
+
+static void internal_obsolete_keytab_test(int num_principals, int num_kvnos,
+                                         krb5_kvno kvno, const char *kt_name)
+{
+       krb5_context krb5_ctx;
+       krb5_keytab keytab;
+       krb5_keytab_entry kt_entry;
+       krb5_kt_cursor cursor;
+       krb5_error_code code;
+
+       int i,j;
+       char princ_name[6] = "user0";
+       char expect_princ_name[23] = "user0@samba.example.com";
+       bool found_previous;
+       const char *error_str;
+
+       TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+       krb5_principal *principals = talloc_zero_array(tmp_ctx,
+                                                      krb5_principal,
+                                                      num_principals);
+       krb5_init_context(&krb5_ctx);
+       krb5_kt_resolve(krb5_ctx, kt_name, &keytab);
+       ZERO_STRUCT(kt_entry);
+
+       for(i=0; i<num_principals; i++) {
+               princ_name[4] = (char)i+48;
+               smb_krb5_make_principal(krb5_ctx, &(principals[i]),
+                                   "samba.example.com", princ_name, NULL);
+               kt_entry.principal = principals[i];
+               for (j=0; j<num_kvnos; j++) {
+                       kt_entry.vno = j+1;
+                       krb5_kt_add_entry(krb5_ctx, keytab, &kt_entry);
+               }
+       }
+
+       code = krb5_kt_start_seq_get(krb5_ctx, keytab, &cursor);
+       assert_int_equal(code, 0);
+       for (i=0; i<num_principals; i++) {
+               expect_princ_name[4] = (char)i+48;
+               for (j=0; j<num_kvnos; j++) {
+                       char *unparsed_name;
+                       code = krb5_kt_next_entry(krb5_ctx, keytab,
+                                                 &kt_entry, &cursor);
+                       assert_int_equal(code, 0);
+                       assert_int_equal(kt_entry.vno, j+1);
+                       krb5_unparse_name(krb5_ctx, kt_entry.principal,
+                                         &unparsed_name);
+                       assert_string_equal(expect_princ_name, unparsed_name);
+               }
+       }
+
+       smb_krb5_remove_obsolete_keytab_entries(tmp_ctx, krb5_ctx, keytab,
+                                               num_principals, principals,
+                                               kvno, &found_previous,
+                                               &error_str);
+
+       code = krb5_kt_start_seq_get(krb5_ctx, keytab, &cursor);
+       assert_int_equal(code, 0);
+       for (i=0; i<num_principals; i++) {
+               char *unparsed_name;
+               expect_princ_name[4] = (char)i+48;
+               code = krb5_kt_next_entry(krb5_ctx, keytab, &kt_entry, &cursor);
+               assert_int_equal(code, 0);
+               assert_int_equal(kt_entry.vno, kvno-1);
+               krb5_unparse_name(krb5_ctx, kt_entry.principal, &unparsed_name);
+               assert_string_equal(expect_princ_name, unparsed_name);
+       }
+       code = krb5_kt_next_entry(krb5_ctx, keytab, &kt_entry, &cursor);
+       assert_int_not_equal(code, 0);
+}
+
+static void test_krb5_remove_obsolete_keytab_entries_many(void **state)
+{
+       internal_obsolete_keytab_test(5, 4, (krb5_kvno)5, "MEMORY:LOL2");
+}
+
+static void test_krb5_remove_obsolete_keytab_entries_one(void **state)
+{
+       internal_obsolete_keytab_test(1, 2, (krb5_kvno)3, "MEMORY:LOL");
+}
+
+int main(int argc, const char **argv)
+{
+       const struct CMUnitTest tests[] = {
+               cmocka_unit_test(test_krb5_remove_obsolete_keytab_entries_one),
+               cmocka_unit_test(test_krb5_remove_obsolete_keytab_entries_many),
+       };
+
+       cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+       return cmocka_run_group_tests(tests, NULL, NULL);
+}
index f7508619cd7781decac053b727d145f51b8ccfbb..d3452d2ca927d14c9bc250018e31ae30eeab31fc 100644 (file)
@@ -42,6 +42,12 @@ bld.SAMBA_SUBSYSTEM('auth4_sam',
        deps=''
        )
 
+bld.SAMBA_BINARY('test_kerberos',
+        source='tests/kerberos.c',
+        deps='cmocka authkrb5 krb5samba com_err CREDENTIALS_KRB5',
+        local_include=False,
+        install=False
+        )
 
 for env in bld.gen_python_environments():
        pytalloc_util = bld.pyembed_libname('pytalloc-util')