diff options
author | Andreas Schneider <asn@cryptomilk.org> | 2021-10-28 10:50:30 +0200 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2021-10-28 19:03:04 +0000 |
commit | 7f6f4777b4081dbfcd875bf6dcbbab03a1fa413d (patch) | |
tree | a1dfb4409718f63cad80e674a096a0fc8aa5e650 /third_party | |
parent | 6ed71ad7e6aa98a34cfde95d7d62c46694d58469 (diff) | |
download | samba-7f6f4777b4081dbfcd875bf6dcbbab03a1fa413d.tar.gz |
third_party: Update pam_wrapper to version 1.1.4
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Thu Oct 28 19:03:04 UTC 2021 on sn-devel-184
Diffstat (limited to 'third_party')
-rw-r--r-- | third_party/pam_wrapper/libpamtest.c | 19 | ||||
-rw-r--r-- | third_party/pam_wrapper/libpamtest.h | 30 | ||||
-rw-r--r-- | third_party/pam_wrapper/pam_wrapper.c | 142 | ||||
-rw-r--r-- | third_party/pam_wrapper/python/pypamtest.c | 192 | ||||
-rw-r--r-- | third_party/pam_wrapper/wscript | 7 |
5 files changed, 230 insertions, 160 deletions
diff --git a/third_party/pam_wrapper/libpamtest.c b/third_party/pam_wrapper/libpamtest.c index 4474736d688..6033d5a5b7e 100644 --- a/third_party/pam_wrapper/libpamtest.c +++ b/third_party/pam_wrapper/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/third_party/pam_wrapper/libpamtest.h b/third_party/pam_wrapper/libpamtest.h index 0307a2663af..4b4a50ecd56 100644 --- a/third_party/pam_wrapper/libpamtest.h +++ b/third_party/pam_wrapper/libpamtest.h @@ -19,6 +19,7 @@ #ifndef __LIBPAMTEST_H_ #define __LIBPAMTEST_H_ +#include <stddef.h> #include <stdint.h> #include <security/pam_appl.h> @@ -128,12 +129,11 @@ struct pamtest_conv_data { * an index internally. */ const char **in_echo_on; - - /** Captures messages through PAM_TEXT_INFO. The test caller is + /** Captures messages through PAM_ERROR_MSG. The test caller is * responsible for allocating enough space in the array. */ char **out_err; - /** Captures messages through PAM_ERROR_MSG. The test caller is + /** Captures messages through PAM_TEXT_INFO. The test caller is * responsible for allocating enough space in the array. */ char **out_info; @@ -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]) +#define run_pamtest_conv(service, user, conv_fn, conv_data, test_cases, pam_handle) \ + _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/third_party/pam_wrapper/pam_wrapper.c b/third_party/pam_wrapper/pam_wrapper.c index dd69c43f021..da2c7381656 100644 --- a/third_party/pam_wrapper/pam_wrapper.c +++ b/third_party/pam_wrapper/pam_wrapper.c @@ -311,7 +311,14 @@ static struct pwrap pwrap; *********************************************************/ bool pam_wrapper_enabled(void); +#if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT) +/* xlC and other oldschool compilers support (only) this */ +#pragma init (pwrap_constructor) +#endif void pwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE; +#if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI) +#pragma fini (pwrap_destructor) +#endif void pwrap_destructor(void) DESTRUCTOR_ATTRIBUTE; /********************************************************* @@ -784,14 +791,20 @@ static void pwrap_clean_stale_dirs(const char *dir) buf[sizeof(buf) - 1] = '\0'; tmp = strtol(buf, NULL, 10); - if (tmp == 0 || tmp > 0xFFFF || errno == ERANGE) { + if (tmp == 0 || errno == ERANGE) { PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to parse pid, buf=%s", buf); return; } - pid = (pid_t)(tmp & 0xFFFF); + pid = (pid_t)tmp; + /* Check if we are out of pid_t range on this system */ + if ((long)pid != tmp) { + PWRAP_LOG(PWRAP_LOG_ERROR, + "pid out of range: %ld", tmp); + return; + } rc = kill(pid, 0); if (rc == -1) { @@ -935,130 +948,6 @@ static void pwrap_init(void) #else /* HAVE_PAM_START_CONFDIR */ -#ifdef HAVE_PAM_MODUTIL_SEARCH_KEY -/* - * This is needed to workaround Tumbleweed which packages a libpam git version. - */ -static int pso_copy(const char *src, const char *dst, const char *pdir, mode_t mode) -{ -#define PSO_COPY_READ_SIZE 16 - int srcfd = -1; - int dstfd = -1; - int rc = -1; - ssize_t bread, bwritten; - struct stat sb; - char buf[PSO_COPY_READ_SIZE + 1]; - size_t pso_copy_read_size = PSO_COPY_READ_SIZE; - int cmp; - size_t to_read; - bool found_slash; - - cmp = strcmp(src, dst); - if (cmp == 0) { - return -1; - } - - srcfd = open(src, O_RDONLY, 0); - if (srcfd < 0) { - return -1; - } - - if (mode == 0) { - rc = fstat(srcfd, &sb); - if (rc != 0) { - rc = -1; - goto out; - } - mode = sb.st_mode; - } - - dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode); - if (dstfd < 0) { - rc = -1; - goto out; - } - - found_slash = false; - to_read = 1; - - for (;;) { - bread = read(srcfd, buf, to_read); - if (bread == 0) { - /* done */ - break; - } else if (bread < 0) { - errno = EIO; - rc = -1; - goto out; - } - - to_read = 1; - if (!found_slash && buf[0] == '/') { - found_slash = true; - to_read = pso_copy_read_size; - } - - if (found_slash && bread == PSO_COPY_READ_SIZE) { - cmp = memcmp(buf, "usr/etc/pam.d/%s", 16); - if (cmp == 0) { - char tmp[16] = {0}; - - snprintf(tmp, sizeof(tmp), "%s/%%s", pdir + 1); - - memcpy(buf, tmp, 12); - memset(&buf[12], '\0', 4); - - /* - * If we found this string, we need to reduce - * the read size to not miss, the next one. - */ - pso_copy_read_size = 13; - } else { - cmp = memcmp(buf, "usr/etc/pam.d", 13); - if (cmp == 0) { - memcpy(buf, pdir + 1, 9); - memset(&buf[9], '\0', 4); - } else { - cmp = memcmp(buf, "etc/pam.d", 9); - if (cmp == 0) { - memcpy(buf, pdir + 1, 9); - } - } - } - found_slash = false; - } - - bwritten = write(dstfd, buf, bread); - if (bwritten < 0) { - errno = EIO; - rc = -1; - goto out; - } - - if (bread != bwritten) { - errno = EFAULT; - rc = -1; - goto out; - } - } - - rc = 0; -out: - if (srcfd != -1) { - close(srcfd); - } - if (dstfd != -1) { - close(dstfd); - } - if (rc < 0) { - unlink(dst); - } - - return rc; -#undef PSO_COPY_READ_SIZE -} -#else /* HAVE_PAM_MODUTIL_SEARCH_KEY */ - static int pso_copy(const char *src, const char *dst, const char *pdir, mode_t mode) { #define PSO_COPY_READ_SIZE 9 @@ -1154,7 +1043,6 @@ out: return rc; #undef PSO_COPY_READ_SIZE } -#endif /* HAVE_PAM_MODUTIL_SEARCH_KEY */ static void pwrap_init(void) { diff --git a/third_party/pam_wrapper/python/pypamtest.c b/third_party/pam_wrapper/python/pypamtest.c index 8de05e9c39b..008a85fd778 100644 --- a/third_party/pam_wrapper/python/pypamtest.c +++ b/third_party/pam_wrapper/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/third_party/pam_wrapper/wscript b/third_party/pam_wrapper/wscript index fb57800587a..28d003d9fab 100644 --- a/third_party/pam_wrapper/wscript +++ b/third_party/pam_wrapper/wscript @@ -2,7 +2,7 @@ import os -VERSION="1.1.2" +VERSION="1.1.4" def find_library(library_names, lookup_paths): for directory in lookup_paths: @@ -56,11 +56,6 @@ def configure(conf): checklibc=False, headers='security/pam_appl.h') - conf.CHECK_FUNCS_IN('pam_modutil_search_key', - 'pam', - checklibc=False, - headers='security/pam_modutil.h') - conf.CHECK_C_PROTOTYPE('pam_vprompt', 'int pam_vprompt(const pam_handle_t *_pamh, int _style, char **_resp, const char *_fmt, va_list _ap)', define='HAVE_PAM_VPROMPT_CONST', headers='stdio.h sys/types.h security/pam_appl.h security/pam_modules.h') |