The branch, master has been updated
       via  88b9921 cmake: Silence warning with gcc version >= 8
       via  1330009 python: Export pam_setcred flags, to be used in python 
testcase objects
       via  6ada64a libpamtest: Add a new keyword parameter to reuse the PAM 
handle
       via  dd5608b python: Store the pam handle in the python test object
       via  b0ff06b python: Store the pam env in the python test object
      from  0e28e3e tests: Correctly implement free_vlist()

https://git.samba.org/?p=pam_wrapper.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 88b9921bd106ad3d06062e42fd76898525a9d542
Author: Samuel Cabrero <scabr...@suse.de>
Date:   Mon Jun 21 12:46:20 2021 +0200

    cmake: Silence warning with gcc version >= 8
    
    src/python/pypamtest.c:1149:17: warning[-Wcast-function-type]: cast between
    incompatible function types from ‘PyObject * (*)(PyObject *, PyObject *,
    PyObject *)’ {aka ‘struct _object * (*)(struct _object *, struct _object *,
    struct _object *)’} to ‘PyObject * (*)(PyObject *, PyObject *)’
    {aka ‘struct _object * (*)(struct _object *, struct _object *)’}
    
    Signed-off-by: Samuel Cabrero <scabr...@suse.de>
    Reviewed-by: Andreas Schneider <a...@samba.org>

commit 1330009d5277e7e4673112be0ff9de9cf0e1a618
Author: Samuel Cabrero <scabr...@samba.org>
Date:   Fri Jun 18 15:38:31 2021 +0200

    python: Export pam_setcred flags, to be used in python testcase objects
    
    Signed-off-by: Samuel Cabrero <scabr...@samba.org>
    Reviewed-by: Andreas Schneider <a...@samba.org>

commit 6ada64a7ab52c07417bc012a200ac6e9fa5d5c2f
Author: Samuel Cabrero <scabr...@samba.org>
Date:   Fri Jun 18 10:36:17 2021 +0200

    libpamtest: Add a new keyword parameter to reuse the PAM handle
    
    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 <scabr...@samba.org>
    Reviewed-by: Andreas Schneider <a...@samba.org>

commit dd5608b36a5f6d7121a8ba6590de1eacd0cc48b3
Author: Samuel Cabrero <scabr...@samba.org>
Date:   Fri Jun 18 09:21:12 2021 +0200

    python: Store the pam handle in the python test object
    
    There was no way to get the PAM handler from a PAMTEST_KEEPHANDLE test
    object.
    
    The PAM handle is stored in the pam_handle member of the test object.
    
    Signed-off-by: Samuel Cabrero <scabr...@samba.org>
    Reviewed-by: Andreas Schneider <a...@samba.org>

commit b0ff06ba02a3c08fd4a60aacf716bc97efec9588
Author: Samuel Cabrero <scabr...@samba.org>
Date:   Fri Jun 18 09:19:25 2021 +0200

    python: Store the pam env in the python test object
    
    There was no way to retrieve the PAM environment from a
    PAMTEST_GETENVLIST test object.
    
    The PAM environment is stored as a dictionary in the pam_env member of
    the test object.
    
    Signed-off-by: Samuel Cabrero <scabr...@samba.org>
    Reviewed-by: Andreas Schneider <a...@samba.org>

-----------------------------------------------------------------------

Summary of changes:
 include/libpamtest.h      |  22 ++++--
 src/libpamtest.c          |  19 +++--
 src/python/CMakeLists.txt |   4 +
 src/python/pypamtest.c    | 192 +++++++++++++++++++++++++++++++++++++++++++---
 tests/test_pam_wrapper.c  |  30 ++++----
 5 files changed, 229 insertions(+), 38 deletions(-)


Changeset truncated at 500 lines:

diff --git a/include/libpamtest.h b/include/libpamtest.h
index 3fa69c7..4ebe83f 100644
--- a/include/libpamtest.h
+++ b/include/libpamtest.h
@@ -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);
diff --git a/src/libpamtest.c b/src/libpamtest.c
index 4474736..6033d5a 100644
--- a/src/libpamtest.c
+++ b/src/libpamtest.c
@@ -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);
 }
diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt
index 3394a84..e8730d9 100644
--- a/src/python/CMakeLists.txt
+++ b/src/python/CMakeLists.txt
@@ -2,3 +2,7 @@ project(pypamtest C)
 
 add_subdirectory(python2)
 add_subdirectory(python3)
+
+set_source_files_properties(pypamtest.c
+                            DIRECTORY python2 python3
+                            PROPERTIES COMPILE_OPTIONS 
"-Wno-cast-function-type")
diff --git a/src/python/pypamtest.c b/src/python/pypamtest.c
index 8de05e9..008a85f 100644
--- a/src/python/pypamtest.c
+++ b/src/python/pypamtest.c
@@ -58,8 +58,14 @@ typedef struct {
        enum pamtest_ops pam_operation;
        int expected_rv;
        int flags;
+
+       PyObject *pam_handle;
+       PyObject *pam_env;
 } TestCaseObject;
 
+#define PyTestCase_AsTestCaseObject(py_obj) \
+       (TestCaseObject *)(py_obj)
+
 /**********************************************************
  *** module-specific exceptions
  **********************************************************/
@@ -461,6 +467,22 @@ static PyMemberDef pypamtest_test_case_members[] = {
                discard_const_p(char, "Additional flags for the PAM operation"),
        },
 
+       {
+               discard_const_p(char, "pam_handle"),
+               T_OBJECT_EX,
+               offsetof(TestCaseObject, pam_handle),
+               READONLY,
+               discard_const_p(char, "Pam handle"),
+       },
+
+       {
+               discard_const_p(char, "pam_env"),
+               T_OBJECT_EX,
+               offsetof(TestCaseObject, pam_env),
+               READONLY,
+               discard_const_p(char, "Pam env"),
+       },
+
        { NULL, 0, 0, 0, NULL } /* Sentinel */
 };
 
@@ -773,6 +795,8 @@ static int py_testcase_to_cstruct(PyObject *py_test, struct 
pam_testcase *test)
        int rc;
        long value;
 
+       memset(test, 0, sizeof(struct pam_testcase));
+
        rc = py_testcase_get(py_test, "pam_operation", &value);
        if (rc != 0) {
                return rc;
@@ -903,6 +927,84 @@ static int py_tc_list_to_cstruct_list(PyObject 
*py_test_list,
        return 0;
 }
 
+static int cstruct_to_py_testcase(PyObject *pytest, struct pam_testcase *ctest)
+{
+       TestCaseObject *t = PyTestCase_AsTestCaseObject(pytest);
+       size_t i;
+       int rc;
+
+       switch (t->pam_operation) {
+       case PAMTEST_GETENVLIST:
+               if (ctest->case_out.envlist == NULL) {
+                       break;
+               }
+
+               t->pam_env = PyDict_New();
+               if (t->pam_env == NULL) {
+                       return ENOMEM;
+               }
+               for (i = 0; ctest->case_out.envlist[i] != NULL; i++) {
+                       char *key = NULL;
+                       char *val = NULL;
+                       key = strdup(ctest->case_out.envlist[i]);
+                       if (key == NULL) {
+                               return ENOMEM;
+                       }
+                       val = strrchr(key, '=');
+                       if (val == NULL) {
+                               PyErr_Format(PyExc_IOError,
+                                            "Failed to parse PAM environment "
+                                            "variable");
+                               free(key);
+                               return EINVAL;
+                       }
+                       *val = '\0';
+                       rc = PyDict_SetItem(t->pam_env,
+                                           PyUnicode_FromString(key),
+                                           PyUnicode_FromString(val + 1));
+                       free(key);
+                       if (rc == -1) {
+                               return rc;
+                       }
+               }
+               break;
+       case PAMTEST_KEEPHANDLE:
+               t->pam_handle = PyCapsule_New(ctest->case_out.ph, NULL, NULL);
+               if (t->pam_handle == NULL) {
+                       return ENOMEM;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int cstruct_list_to_py_tc_list(PyObject *py_test_list,
+                                     Py_ssize_t num_tests,
+                                     struct pam_testcase *test_list)
+{
+       Py_ssize_t i;
+       PyObject *py_test = NULL;
+       int rc;
+
+       for (i = 0; i < num_tests; i++) {
+               py_test = PySequence_GetItem(py_test_list, i);
+               if (py_test == NULL) {
+                       return EIO;
+               }
+
+               rc = cstruct_to_py_testcase(py_test, &test_list[i]);
+               Py_DECREF(py_test);
+               if (rc != 0) {
+                       return EIO;
+               }
+       }
+
+       return 0;
+}
+
 PyDoc_STRVAR(RunPamTest__doc__,
 "Run PAM tests\n\n"
 "This function runs PAM test cases and reports result\n"
@@ -917,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;
@@ -926,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;
        }
@@ -976,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,
@@ -986,6 +1118,18 @@ static PyObject *pypamtest_run_pamtest(PyObject *module, 
PyObject *args)
                PyMem_Free(test_list);
                return NULL;
        }
+
+       rc = cstruct_list_to_py_tc_list(py_test_list, num_tests, test_list);
+       if (rc != 0) {
+               if (rc == ENOMEM) {
+                       PyErr_NoMemory();
+                       return NULL;
+               } else {
+                       PyErr_Format(PyExc_IOError,
+                                    "Cannot convert C structure to python");
+                       return NULL;
+               }
+       }
        PyMem_Free(test_list);
 
        result = construct_test_conv_result(conv_data.out_info,
@@ -1003,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__,
        },
 
@@ -1115,6 +1259,34 @@ PyMODINIT_FUNC initpypamtest(void)
                RETURN_ON_ERROR;
        }
 
+       ret = PyModule_AddIntConstant(m,
+                                     "PAMTEST_FLAG_DELETE_CRED",
+                                     PAM_DELETE_CRED);
+       if (ret == -1) {
+               RETURN_ON_ERROR;
+       }
+
+       ret = PyModule_AddIntConstant(m,
+                                     "PAMTEST_FLAG_ESTABLISH_CRED",
+                                     PAM_ESTABLISH_CRED);
+       if (ret == -1) {
+               RETURN_ON_ERROR;
+       }
+
+       ret = PyModule_AddIntConstant(m,
+                                     "PAMTEST_FLAG_REINITIALIZE_CRED",
+                                     PAM_REINITIALIZE_CRED);
+       if (ret == -1) {
+               RETURN_ON_ERROR;
+       }
+
+       ret = PyModule_AddIntConstant(m,
+                                     "PAMTEST_FLAG_REFRESH_CRED",
+                                     PAM_REFRESH_CRED);
+       if (ret == -1) {
+               RETURN_ON_ERROR;
+       }
+
        pypam_object.type_obj = &pypamtest_test_case;
        if (PyType_Ready(pypam_object.type_obj) < 0) {
                RETURN_ON_ERROR;
diff --git a/tests/test_pam_wrapper.c b/tests/test_pam_wrapper.c
index 7e8b9ee..1e0c292 100644
--- a/tests/test_pam_wrapper.c
+++ b/tests/test_pam_wrapper.c
@@ -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 */


-- 
pam wrapper repository

Reply via email to