]> eyrie.org Git - kerberos/krb5-strength.git/blobdiff - tests/plugin/mit-t.c
Change CrackLib tests for system CrackLib
[kerberos/krb5-strength.git] / tests / plugin / mit-t.c
index 1a49e4f65d7ab0925857dad236d34cc48e17bc19..4406e38796e8475c5517c35b8dd70ddc5378ed97 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Test for the MIT Kerberos shared module API.
  *
- * Written by Russ Allbery <rra@stanford.edu>
- * Copyright 2010, 2013
+ * Written by Russ Allbery <eagle@eyrie.org>
+ * Copyright 2010, 2013, 2014
  *     The Board of Trustees of the Leland Stanford Junior University
  *
  * See LICENSE for licensing terms.
 #include <util/macros.h>
 
 /*
- * The password test data, generated from the JSON source.  Defines an arrays
- * named cdb_tests, cracklib_tests, and generic_tests.
+ * The password test data, generated from the JSON source.  Defines arrays
+ * named *_tests, where * is the file name without the ".c" suffix.
  */
 #include <tests/data/passwords/cdb.c>
-#include <tests/data/passwords/class.c>
+#include <tests/data/passwords/classes.c>
 #include <tests/data/passwords/cracklib.c>
-#include <tests/data/passwords/generic.c>
 #include <tests/data/passwords/length.c>
+#include <tests/data/passwords/letter.c>
+#include <tests/data/passwords/principal.c>
+#include <tests/data/passwords/sqlite.c>
 
 
 #ifndef HAVE_KRB5_PWQUAL_PLUGIN_H
@@ -59,13 +61,13 @@ typedef krb5_error_code pwqual_strength_initvt(krb5_context, int, int,
 /*
  * Loads the Heimdal password change plugin and tests that its metadata is
  * correct.  Returns a pointer to the kadm5_pw_policy_verifier struct or bails
- * on failure to load the plugin.
+ * on failure to load the plugin.  Stores the handle from dlopen in its second
+ * argument for a later clean shutdown.
  */
 static krb5_pwqual_vtable
-load_plugin(krb5_context ctx)
+load_plugin(krb5_context ctx, void **handle)
 {
     char *path;
-    void *handle;
     krb5_error_code code;
     krb5_pwqual_vtable vtable = NULL;
     krb5_error_code (*init)(krb5_context, int, int, krb5_plugin_vtable);
@@ -74,13 +76,13 @@ load_plugin(krb5_context ctx)
     path = test_file_path("../plugin/.libs/strength.so");
     if (path == NULL)
         bail("cannot find plugin");
-    handle = dlopen(path, RTLD_NOW);
-    if (handle == NULL)
+    *handle = dlopen(path, RTLD_NOW);
+    if (*handle == NULL)
         bail("cannot dlopen %s: %s", path, dlerror());
     test_file_path_free(path);
 
     /* Find the entry point function. */
-    init = dlsym(handle, "pwqual_strength_initvt");
+    init = dlsym(*handle, "pwqual_strength_initvt");
     if (init == NULL)
         bail("cannot get pwqual_strength_initvt symbol: %s", dlerror());
 
@@ -147,30 +149,32 @@ int
 main(void)
 {
     char *path, *dictionary, *krb5_config, *krb5_config_empty, *tmpdir;
-    char *setup_argv[10];
+    char *setup_argv[12];
     const char*build;
     size_t i, count;
     krb5_context ctx;
     krb5_pwqual_vtable vtable;
     krb5_pwqual_moddata data;
     krb5_error_code code;
+    void *handle;
 
     /*
      * Calculate how many tests we have.  There are two tests for the module
-     * metadata, six more tests for initializing the plugin, one test for
-     * initialization without a valid dictionary, and two tests per password
-     * test.
+     * metadata, seven more tests for initializing the plugin, and two tests
+     * per password test.
      *
-     * We run all the CrackLib and generic tests twice, once with an explicit
-     * dictionary path and once from krb5.conf configuration.  We run the
-     * generic tests with both CrackLib and CDB configurations.
+     * We run all the CrackLib tests twice, once with an explicit dictionary
+     * path and once from krb5.conf configuration.  We run the principal tests
+     * with CrackLib, CDB, and SQLite configurations.
      */
     count = 2 * ARRAY_SIZE(cracklib_tests);
+    count += 2 * ARRAY_SIZE(length_tests);
     count += ARRAY_SIZE(cdb_tests);
-    count += ARRAY_SIZE(class_tests);
-    count += ARRAY_SIZE(length_tests);
-    count += 2 * ARRAY_SIZE(generic_tests);
-    plan(2 + 6 + count * 2);
+    count += ARRAY_SIZE(sqlite_tests);
+    count += ARRAY_SIZE(classes_tests);
+    count += ARRAY_SIZE(letter_tests);
+    count += 3 * ARRAY_SIZE(principal_tests);
+    plan(2 + 8 + count * 2);
 
     /* Start with the krb5.conf that contains no dictionary configuration. */
     path = test_file_path("data/krb5.conf");
@@ -184,13 +188,10 @@ main(void)
     if (code != 0)
         bail_krb5(ctx, code, "cannot initialize Kerberos context");
 
-    /* Load and initialize the plugin without a dictionary. */
-    vtable = load_plugin(ctx);
-    code = vtable->open(ctx, NULL, &data);
-    is_int(KADM5_MISSING_CONF_PARAMS, code,
-           "Plugin initialization (no dictionary)");
+    /* Load the plugin. */
+    vtable = load_plugin(ctx, &handle);
 
-    /* Initialize the plugin again with the correct dictionary. */
+    /* Initialize the plugin with a CrackLib dictionary. */
     build = getenv("BUILD");
     if (build == NULL)
         bail("BUILD not set in the environment");
@@ -200,11 +201,11 @@ main(void)
     if (code != 0)
         bail("cannot continue after plugin initialization failure");
 
-    /* Now, run all of the tests, with generic tests. */
+    /* Now, run all of the tests, with principal tests. */
     for (i = 0; i < ARRAY_SIZE(cracklib_tests); i++)
         is_password_test(ctx, vtable, data, &cracklib_tests[i]);
-    for (i = 0; i < ARRAY_SIZE(generic_tests); i++)
-        is_password_test(ctx, vtable, data, &generic_tests[i]);
+    for (i = 0; i < ARRAY_SIZE(principal_tests); i++)
+        is_password_test(ctx, vtable, data, &principal_tests[i]);
 
     /* Close that initialization of the plugin and destroy that context. */
     vtable->close(ctx, data);
@@ -234,7 +235,7 @@ main(void)
     if (code != 0)
         bail_krb5(ctx, code, "cannot initialize Kerberos context");
 
-    /* Run all of the tests again.  No need to re-run generic tests. */
+    /* Run all of the tests again.  No need to re-run principal tests. */
     code = vtable->open(ctx, NULL, &data);
     is_int(0, code, "Plugin initialization (krb5.conf dictionary)");
     if (code != 0)
@@ -243,7 +244,36 @@ main(void)
         is_password_test(ctx, vtable, data, &cracklib_tests[i]);
     vtable->close(ctx, data);
 
-    /* Add character class configuration to krb5.conf. */
+    /*
+     * Add length restrictions and a maximum length for CrackLib.  This should
+     * reject passwords as too short, but let through a password that's
+     * actually in the CrackLib dictionary.
+     */
+    setup_argv[5] = (char *) "minimum_length";
+    setup_argv[6] = (char *) "12";
+    setup_argv[7] = (char *) "cracklib_maxlen";
+    setup_argv[8] = (char *) "11";
+    setup_argv[9] = NULL;
+    run_setup((const char **) setup_argv);
+
+    /* Obtain a new Kerberos context with that krb5.conf file. */
+    krb5_free_context(ctx);
+    code = krb5_init_context(&ctx);
+    if (code != 0)
+        bail_krb5(ctx, code, "cannot initialize Kerberos context");
+
+    /* Run all of the length tests. */
+    code = vtable->open(ctx, NULL, &data);
+    is_int(0, code, "Plugin initialization (length)");
+    if (code != 0)
+        bail("cannot continue after plugin initialization failure");
+    for (i = 0; i < ARRAY_SIZE(length_tests); i++)
+        is_password_test(ctx, vtable, data, &length_tests[i]);
+    vtable->close(ctx, data);
+
+    /* Add simple character class configuration to krb5.conf. */
+    setup_argv[3] = (char *) "minimum_different";
+    setup_argv[4] = (char *) "8";
     setup_argv[5] = (char *) "require_ascii_printable";
     setup_argv[6] = (char *) "true";
     setup_argv[7] = (char *) "require_non_letter";
@@ -257,19 +287,43 @@ main(void)
     if (code != 0)
         bail_krb5(ctx, code, "cannot initialize Kerberos context");
 
-    /* Run all the character class tests. */
+    /* Run all the simple character class tests. */
     code = vtable->open(ctx, NULL, &data);
-    is_int(0, code, "Plugin initialization (character class)");
+    is_int(0, code, "Plugin initialization (simple character class)");
     if (code != 0)
         bail("cannot continue after plugin initialization failure");
-    for (i = 0; i < ARRAY_SIZE(class_tests); i++)
-        is_password_test(ctx, vtable, data, &class_tests[i]);
+    for (i = 0; i < ARRAY_SIZE(letter_tests); i++)
+        is_password_test(ctx, vtable, data, &letter_tests[i]);
     vtable->close(ctx, data);
 
-    /* Add minimum length configuration to krb5.conf. */
-    setup_argv[5] = (char *) "minimum_length";
-    setup_argv[6] = (char *) "12";
-    setup_argv[7] = NULL;
+    /*
+     * Add complex character class configuration to krb5.conf but drop
+     * the dictionary configuration.
+     */
+    setup_argv[3] = (char *) "require_classes";
+    setup_argv[4] = (char *) "8-19:lower,upper 8-15:digit 8-11:symbol 24-24:3";
+    setup_argv[5] = NULL;
+    run_setup((const char **) setup_argv);
+
+    /* Obtain a new Kerberos context with that krb5.conf file. */
+    krb5_free_context(ctx);
+    code = krb5_init_context(&ctx);
+    if (code != 0)
+        bail_krb5(ctx, code, "cannot initialize Kerberos context");
+
+    /* Run all the complex character class tests. */
+    code = vtable->open(ctx, NULL, &data);
+    is_int(0, code, "Plugin initialization (complex character class)");
+    if (code != 0)
+        bail_krb5(ctx, code, "plugin initialization failure");
+    for (i = 0; i < ARRAY_SIZE(classes_tests); i++)
+        is_password_test(ctx, vtable, data, &classes_tests[i]);
+    vtable->close(ctx, data);
+
+    /* Re-run the length restriction checks with no dictionary at all. */
+    setup_argv[3] = (char *) "minimum_length";
+    setup_argv[4] = (char *) "12";
+    setup_argv[5] = NULL;
     run_setup((const char **) setup_argv);
 
     /* Obtain a new Kerberos context with that krb5.conf file. */
@@ -290,7 +344,7 @@ main(void)
 #ifdef HAVE_CDB
 
     /* If built with CDB, set up krb5.conf to use a CDB dictionary instead. */
-    free(dictionary);
+    test_file_path_free(dictionary);
     dictionary = test_file_path("data/wordlist.cdb");
     if (dictionary == NULL)
         bail("cannot find data/wordlist.cdb in the test suite");
@@ -298,8 +352,6 @@ main(void)
     setup_argv[4] = dictionary;
     setup_argv[5] = NULL;
     run_setup((const char **) setup_argv);
-    test_file_path_free(setup_argv[0]);
-    test_file_path_free(path);
 
     /* Obtain a new Kerberos context with that krb5.conf file. */
     krb5_free_context(ctx);
@@ -307,31 +359,77 @@ main(void)
     if (code != 0)
         bail_krb5(ctx, code, "cannot initialize Kerberos context");
 
-    /* Run the CDB and generic tests. */
+    /* Run the CDB and principal tests. */
     code = vtable->open(ctx, NULL, &data);
     is_int(0, code, "Plugin initialization (CDB dictionary)");
     if (code != 0)
         bail("cannot continue after plugin initialization failure");
     for (i = 0; i < ARRAY_SIZE(cdb_tests); i++)
         is_password_test(ctx, vtable, data, &cdb_tests[i]);
-    for (i = 0; i < ARRAY_SIZE(generic_tests); i++)
-        is_password_test(ctx, vtable, data, &generic_tests[i]);
+    for (i = 0; i < ARRAY_SIZE(principal_tests); i++)
+        is_password_test(ctx, vtable, data, &principal_tests[i]);
     vtable->close(ctx, data);
 
 #else /* !HAVE_CDB */
 
     /* Otherwise, mark the CDB tests as skipped. */
-    count = ARRAY_SIZE(cdb_tests) + ARRAY_SIZE(generic_tests);
+    count = ARRAY_SIZE(cdb_tests) + ARRAY_SIZE(principal_tests);
     skip_block(count * 2 + 1, "not built with CDB support");
 
 #endif /* !HAVE_CDB */
 
+#ifdef HAVE_SQLITE
+
+    /*
+     * If built with SQLite, set up krb5.conf to use a SQLite dictionary
+     * instead.
+     */
+    test_file_path_free(dictionary);
+    dictionary = test_file_path("data/wordlist.sqlite");
+    if (dictionary == NULL)
+        bail("cannot find data/wordlist.sqlite in the test suite");
+    setup_argv[3] = (char *) "password_dictionary_sqlite";
+    setup_argv[4] = dictionary;
+    setup_argv[5] = NULL;
+    run_setup((const char **) setup_argv);
+    test_file_path_free(setup_argv[0]);
+    test_file_path_free(path);
+
+    /* Obtain a new Kerberos context with that krb5.conf file. */
+    krb5_free_context(ctx);
+    code = krb5_init_context(&ctx);
+    if (code != 0)
+        bail_krb5(ctx, code, "cannot initialize Kerberos context");
+
+    /* Run the SQLite and principal tests. */
+    code = vtable->open(ctx, NULL, &data);
+    is_int(0, code, "Plugin initialization (SQLite dictionary)");
+    if (code != 0)
+        bail("cannot continue after plugin initialization failure");
+    for (i = 0; i < ARRAY_SIZE(sqlite_tests); i++)
+        is_password_test(ctx, vtable, data, &sqlite_tests[i]);
+    for (i = 0; i < ARRAY_SIZE(principal_tests); i++)
+        is_password_test(ctx, vtable, data, &principal_tests[i]);
+    vtable->close(ctx, data);
+
+#else /* !HAVE_SQLITE */
+
+    /* Otherwise, mark the SQLite tests as skipped. */
+    count = ARRAY_SIZE(sqlite_tests) + ARRAY_SIZE(principal_tests);
+    skip_block(count * 2 + 1, "not built with SQLite support");
+
+#endif /* !HAVE_SQLITE */
+
     /* Manually clean up after the results of make-krb5-conf. */
     basprintf(&path, "%s/krb5.conf", tmpdir);
     unlink(path);
     free(path);
     test_tmpdir_free(tmpdir);
 
+    /* Close down the module. */
+    if (dlclose(handle) != 0)
+        bail("cannot close plugin: %s", dlerror());
+
     /* Keep valgrind clean by freeing all memory. */
     test_file_path_free(dictionary);
     krb5_free_context(ctx);