libpamtest: Add a new keyword parameter to reuse the PAM handle
authorSamuel Cabrero <scabrero@samba.org>
Fri, 18 Jun 2021 08:36:17 +0000 (10:36 +0200)
committerAndreas Schneider <asn@samba.org>
Thu, 24 Jun 2021 19:08:49 +0000 (21:08 +0200)
Add a new keyword parameter to pass and reuse a PAM handle obtained by a
previous run having a test object of type PAMTEST_KEEPHANDLE.

Signed-off-by: Samuel Cabrero <scabrero@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
include/libpamtest.h
src/libpamtest.c
src/python/pypamtest.c
tests/test_pam_wrapper.c

index 3fa69c72a9cade86368d24a6ff59f24047bb0dd5..4ebe83f91dcc76abfcbc93e96127c7c7175cf8c2 100644 (file)
@@ -156,6 +156,8 @@ struct pamtest_conv_data {
  * @param[in]  test_cases   List of libpamtest test cases. Must end with
  *                          PAMTEST_CASE_SENTINEL
  *
+ * @param[in]  pam_handle   The PAM handle to use to run the tests
+ *
  * @code
  * int main(void) {
  *     int rc;
@@ -175,10 +177,11 @@ enum pamtest_err run_pamtest_conv(const char *service,
                                  const char *user,
                                  pam_conv_fn conv_fn,
                                  void *conv_userdata,
-                                 struct pam_testcase test_cases[]);
+                                 struct pam_testcase test_cases[],
+                                 pam_handle_t *pam_handle);
 #else
 #define run_pamtest_conv(service, user, conv_fn, conv_data, test_cases) \
-       _pamtest_conv(service, user, conv_fn, conv_data, test_cases, sizeof(test_cases)/sizeof(test_cases[0])
+       _pamtest_conv(service, user, conv_fn, conv_data, test_cases, sizeof(test_cases)/sizeof(test_cases[0], pam_handle)
 #endif
 
 #ifdef DOXYGEN
@@ -196,6 +199,8 @@ enum pamtest_err run_pamtest_conv(const char *service,
  * @param[in]  test_cases   List of libpamtest test cases. Must end with
  *                          PAMTEST_CASE_SENTINEL
  *
+ * @param[in]  pam_handle   The PAM handle to use to run the tests
+ *
  * @code
  * int main(void) {
  *     int rc;
@@ -214,10 +219,11 @@ enum pamtest_err run_pamtest_conv(const char *service,
 enum pamtest_err run_pamtest(const char *service,
                             const char *user,
                             struct pamtest_conv_data *conv_data,
-                            struct pam_testcase test_cases[]);
+                            struct pam_testcase test_cases[],
+                            pam_handle_t *pam_handle);
 #else
-#define run_pamtest(service, user, conv_data, test_cases) \
-       _pamtest(service, user, conv_data, test_cases, sizeof(test_cases)/sizeof(test_cases[0]))
+#define run_pamtest(service, user, conv_data, test_cases, pam_handle) \
+       _pamtest(service, user, conv_data, test_cases, sizeof(test_cases)/sizeof(test_cases[0]), pam_handle)
 #endif
 
 #ifdef DOXYGEN
@@ -262,13 +268,15 @@ enum pamtest_err _pamtest_conv(const char *service,
                               pam_conv_fn conv_fn,
                               void *conv_userdata,
                               struct pam_testcase test_cases[],
-                              size_t num_test_cases);
+                              size_t num_test_cases,
+                              pam_handle_t *pam_handle);
 
 enum pamtest_err _pamtest(const char *service,
                          const char *user,
                          struct pamtest_conv_data *conv_data,
                          struct pam_testcase test_cases[],
-                         size_t num_test_cases);
+                         size_t num_test_cases,
+                         pam_handle_t *pam_handle);
 
 const struct pam_testcase *_pamtest_failed_case(struct pam_testcase test_cases[],
                                                size_t num_test_cases);
index 4474736d688bd0fe9652cac1ba909fbdf05f502e..6033d5a5b7e92b292459cadef1d4436a42c84093 100644 (file)
@@ -66,7 +66,8 @@ enum pamtest_err _pamtest_conv(const char *service,
                               pam_conv_fn conv_fn,
                               void *conv_userdata,
                               struct pam_testcase test_cases[],
-                              size_t num_test_cases)
+                              size_t num_test_cases,
+                              pam_handle_t *pam_handle)
 {
        int rv;
        pam_handle_t *ph;
@@ -82,9 +83,13 @@ enum pamtest_err _pamtest_conv(const char *service,
                return PAMTEST_ERR_INTERNAL;
        }
 
-       rv = pam_start(service, user, &conv, &ph);
-       if (rv != PAM_SUCCESS) {
-               return PAMTEST_ERR_START;
+       if (pam_handle == NULL) {
+               rv = pam_start(service, user, &conv, &ph);
+               if (rv != PAM_SUCCESS) {
+                       return PAMTEST_ERR_START;
+               }
+       } else {
+               ph = pam_handle;
        }
 
        for (tcindex = 0; tcindex < num_test_cases; tcindex++) {
@@ -322,7 +327,8 @@ enum pamtest_err _pamtest(const char *service,
                          const char *user,
                          struct pamtest_conv_data *conv_data,
                          struct pam_testcase test_cases[],
-                         size_t num_test_cases)
+                         size_t num_test_cases,
+                         pam_handle_t *pam_handle)
 {
        struct pamtest_conv_ctx cctx = {
                .data = conv_data,
@@ -332,5 +338,6 @@ enum pamtest_err _pamtest(const char *service,
                             pamtest_simple_conv,
                             &cctx,
                             test_cases,
-                            num_test_cases);
+                            num_test_cases,
+                            pam_handle);
 }
index 033e5a7004d93f194e0f383c49df27f389c02a42..7bacc77ea4ecfec541970d19e5e7c4ee4cdb613d 100644 (file)
@@ -1019,7 +1019,9 @@ PyDoc_STRVAR(RunPamTest__doc__,
 "conversation for PAM_PROMPT_ECHO_ON input.\n"
 );
 
-static PyObject *pypamtest_run_pamtest(PyObject *module, PyObject *args)
+static PyObject *pypamtest_run_pamtest(PyObject *module,
+                                      PyObject *args,
+                                      PyObject *kwargs)
 {
        int ok;
        int rc;
@@ -1028,21 +1030,33 @@ static PyObject *pypamtest_run_pamtest(PyObject *module, PyObject *args)
        PyObject *py_test_list;
        PyObject *py_echo_off = NULL;
        PyObject *py_echo_on = NULL;
+       PyObject *py_pam_handle = NULL;
        Py_ssize_t num_tests;
        struct pam_testcase *test_list;
        enum pamtest_err perr;
        struct pamtest_conv_data conv_data;
+       pam_handle_t *pam_handle = NULL;
        TestResultObject *result = NULL;
+       const char * const kwnames[] = { "username",
+                                 "service",
+                                 "tests",
+                                 "echo_off",
+                                 "echo_on",
+                                 "handle",
+                                 NULL };
 
        (void) module;  /* unused */
 
-       ok = PyArg_ParseTuple(args,
-                             discard_const_p(char, "ssO|OO"),
-                             &username,
-                             &service,
-                             &py_test_list,
-                             &py_echo_off,
-                             &py_echo_on);
+       ok = PyArg_ParseTupleAndKeywords(args,
+                                        kwargs,
+                                        discard_const_p(char, "ssO|OOO"),
+                                        discard_const_p(char *, kwnames),
+                                        &username,
+                                        &service,
+                                        &py_test_list,
+                                        &py_echo_off,
+                                        &py_echo_on,
+                                        &py_pam_handle);
        if (!ok) {
                return NULL;
        }
@@ -1078,7 +1092,23 @@ static PyObject *pypamtest_run_pamtest(PyObject *module, PyObject *args)
                return NULL;
        }
 
-       perr = _pamtest(service, username, &conv_data, test_list, num_tests);
+       if (py_pam_handle != NULL) {
+               pam_handle = (pam_handle_t *)PyCapsule_GetPointer(py_pam_handle,
+                                                                 NULL);
+               if (pam_handle == NULL) {
+                       PyMem_Free(test_list);
+                       PyErr_Format(PyExc_IOError,
+                                    "Failed to get the pam handle pointer");
+                       return NULL;
+               }
+       }
+
+       perr = _pamtest(service,
+                       username,
+                       &conv_data,
+                       test_list,
+                       num_tests,
+                       pam_handle);
        if (perr != PAMTEST_ERR_OK) {
                free_conv_data(&conv_data);
                set_pypamtest_exception(PyExc_PamTestError,
@@ -1117,7 +1147,7 @@ static PyMethodDef pypamtest_module_methods[] = {
        {
                discard_const_p(char, "run_pamtest"),
                (PyCFunction) pypamtest_run_pamtest,
-               METH_VARARGS,
+               METH_VARARGS | METH_KEYWORDS,
                RunPamTest__doc__,
        },
 
index 7e8b9eeda32ea6906fc3f35cb1e2d739f7edbb0c..1e0c2924ad8ffe9ef30a5b17718eb542f7152e5b 100644 (file)
@@ -267,7 +267,7 @@ static void test_pam_authenticate(void **state)
        ZERO_STRUCT(conv_data);
        conv_data.in_echo_off = trinity_authtoks;
 
-       perr = run_pamtest("matrix", "trinity", &conv_data, tests);
+       perr = run_pamtest("matrix", "trinity", &conv_data, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 }
 
@@ -287,7 +287,7 @@ static void test_pam_authenticate_null_password(void **state)
        ZERO_STRUCT(conv_data);
        conv_data.in_echo_off = empty_authtoks;
 
-       perr = run_pamtest("matrix", "trinity", &conv_data, tests);
+       perr = run_pamtest("matrix", "trinity", &conv_data, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 }
 
@@ -308,7 +308,7 @@ static void test_pam_authenticate_err(void **state)
        ZERO_STRUCT(conv_data);
        conv_data.in_echo_off = trinity_authtoks;
 
-       perr = run_pamtest("matrix", "trinity", &conv_data, tests);
+       perr = run_pamtest("matrix", "trinity", &conv_data, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 }
 
@@ -321,7 +321,7 @@ static void test_pam_acct(void **state)
 
        (void) state;   /* unused */
 
-       perr = run_pamtest("matrix", "trinity", NULL, tests);
+       perr = run_pamtest("matrix", "trinity", NULL, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 }
 
@@ -334,7 +334,7 @@ static void test_pam_acct_err(void **state)
 
        (void) state;   /* unused */
 
-       perr = run_pamtest("matrix", "neo", NULL, tests);
+       perr = run_pamtest("matrix", "neo", NULL, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 }
 
@@ -458,7 +458,7 @@ static void test_pam_session(void **state)
 
        (void) state;   /* unused */
 
-       perr = run_pamtest("matrix", "trinity", NULL, tests);
+       perr = run_pamtest("matrix", "trinity", NULL, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 
        v = string_in_list(tests[1].case_out.envlist, "HOMEDIR");
@@ -500,7 +500,7 @@ static void test_pam_chauthtok(void **state)
        ZERO_STRUCT(conv_data);
        conv_data.in_echo_off = trinity_new_authtoks;
 
-       perr = run_pamtest("matrix", "trinity", &conv_data, tests);
+       perr = run_pamtest("matrix", "trinity", &conv_data, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 }
 
@@ -523,7 +523,7 @@ static void test_pam_chauthtok_prelim_failed(void **state)
        ZERO_STRUCT(conv_data);
        conv_data.in_echo_off = trinity_new_authtoks;
 
-       perr = run_pamtest("matrix", "trinity", &conv_data, tests);
+       perr = run_pamtest("matrix", "trinity", &conv_data, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 }
 
@@ -546,7 +546,7 @@ static void test_pam_chauthtok_diff_passwords(void **state)
        ZERO_STRUCT(conv_data);
        conv_data.in_echo_off = trinity_new_authtoks;
 
-       perr = run_pamtest("matrix", "trinity", &conv_data, tests);
+       perr = run_pamtest("matrix", "trinity", &conv_data, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 }
 
@@ -562,7 +562,7 @@ static void test_pam_setcred(void **state)
 
        (void) state;   /* unused */
 
-       perr = run_pamtest("matrix", "trinity", NULL, tests);
+       perr = run_pamtest("matrix", "trinity", NULL, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 
        /* environment is clean before setcred */
@@ -773,7 +773,7 @@ static void test_pam_authenticate_db_opt(void **state)
        conv_data.in_echo_on = trinity_authtoks;
        conv_data.out_info = info_arr;
 
-       perr = run_pamtest("matrix_opt", "trinity_ro", &conv_data, tests);
+       perr = run_pamtest("matrix_opt", "trinity_ro", &conv_data, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 
        assert_string_equal(auth_info_msg, "Authentication succeeded");
@@ -802,7 +802,7 @@ static void test_pam_authenticate_db_opt_err(void **state)
        conv_data.in_echo_on = trinity_authtoks;
        conv_data.out_err = err_arr;
 
-       perr = run_pamtest("matrix_opt", "trinity_ro", &conv_data, tests);
+       perr = run_pamtest("matrix_opt", "trinity_ro", &conv_data, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 
        assert_string_equal(auth_err_msg, "Authentication failed");
@@ -903,7 +903,7 @@ static void test_get_set(void **state)
        test_setenv("PAM_AUTHTOK_TYPE");
 #endif
 
-       perr = run_pamtest("pwrap_get_set", "trinity", NULL, tests);
+       perr = run_pamtest("pwrap_get_set", "trinity", NULL, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 
        /* PAM_SERVICE is a special case, Linux's libpam lowercases it.
@@ -951,7 +951,7 @@ static void test_libpamtest_keepopen(void **state)
        ZERO_STRUCT(conv_data);
        conv_data.in_echo_off = trinity_authtoks;
 
-       perr = run_pamtest("matrix", "trinity", &conv_data, tests);
+       perr = run_pamtest("matrix", "trinity", &conv_data, tests, NULL);
        assert_int_equal(perr, PAMTEST_ERR_OK);
 
        assert_non_null(tests[1].case_out.ph);
@@ -978,7 +978,7 @@ static void test_libpamtest_get_failed_test(void **state)
        ZERO_STRUCT(conv_data);
        conv_data.in_echo_off = trinity_authtoks;
 
-       perr = run_pamtest("matrix", "trinity", &conv_data, tests);
+       perr = run_pamtest("matrix", "trinity", &conv_data, tests, NULL);
        assert_int_not_equal(perr, PAMTEST_ERR_OK);
 
        failed_tc = pamtest_failed_case(tests);