third_party: Update pam_wrapper to version 1.1.4
authorAndreas Schneider <asn@cryptomilk.org>
Thu, 28 Oct 2021 08:50:30 +0000 (10:50 +0200)
committerJeremy Allison <jra@samba.org>
Thu, 28 Oct 2021 19:03:04 +0000 (19:03 +0000)
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

buildtools/wafsamba/samba_third_party.py
third_party/pam_wrapper/libpamtest.c
third_party/pam_wrapper/libpamtest.h
third_party/pam_wrapper/pam_wrapper.c
third_party/pam_wrapper/python/pypamtest.c
third_party/pam_wrapper/wscript

index 1c027cb68706084b43de36d69b76107beea9322c..f046ebc96da353631c3889f04f42d3b48ac1b2c8 100644 (file)
@@ -44,5 +44,5 @@ Build.BuildContext.CHECK_UID_WRAPPER = CHECK_UID_WRAPPER
 
 @conf
 def CHECK_PAM_WRAPPER(conf):
-    return conf.CHECK_BUNDLED_SYSTEM_PKG('pam_wrapper', minversion='1.1.2')
+    return conf.CHECK_BUNDLED_SYSTEM_PKG('pam_wrapper', minversion='1.1.4')
 Build.BuildContext.CHECK_PAM_WRAPPER = CHECK_PAM_WRAPPER
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 0307a2663afd7e7df77775ac4251be67dba98a69..4b4a50ecd5664694180e7b06d8376064ec4c9ac3 100644 (file)
@@ -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);
index dd69c43f021e17cbaf6ed264fd0782ee862393dc..da2c73816563d8f0e3fac1c94a05b0bfa4386e72 100644 (file)
@@ -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)
 {
index 8de05e9c39b9aec7e3157e6b6e878afcecbd591b..008a85fd778864a149ed86742236355b6e83ebc7 100644 (file)
@@ -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;
index fb57800587a4d85c08327e08bb7a69990814ea7e..28d003d9fab2ebb66c24d2ccf6033f1abf842f72 100644 (file)
@@ -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')