[SCM] pam wrapper repository - branch master updated

Andreas Schneider asn at samba.org
Thu Jun 24 19:13:53 UTC 2021


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 <scabrero at 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 <scabrero at suse.de>
    Reviewed-by: Andreas Schneider <asn at samba.org>

commit 1330009d5277e7e4673112be0ff9de9cf0e1a618
Author: Samuel Cabrero <scabrero at 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 <scabrero at samba.org>
    Reviewed-by: Andreas Schneider <asn at samba.org>

commit 6ada64a7ab52c07417bc012a200ac6e9fa5d5c2f
Author: Samuel Cabrero <scabrero at 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 <scabrero at samba.org>
    Reviewed-by: Andreas Schneider <asn at samba.org>

commit dd5608b36a5f6d7121a8ba6590de1eacd0cc48b3
Author: Samuel Cabrero <scabrero at 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 <scabrero at samba.org>
    Reviewed-by: Andreas Schneider <asn at samba.org>

commit b0ff06ba02a3c08fd4a60aacf716bc97efec9588
Author: Samuel Cabrero <scabrero at 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 <scabrero at samba.org>
    Reviewed-by: Andreas Schneider <asn at 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



More information about the samba-cvs mailing list