third_party: Update pam_wrapper to version 1.1.2
authorAndreas Schneider <asn@samba.org>
Fri, 20 Mar 2020 14:25:47 +0000 (15:25 +0100)
committerStefan Metzmacher <metze@samba.org>
Wed, 25 Mar 2020 06:58:38 +0000 (06:58 +0000)
Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
buildtools/wafsamba/samba_third_party.py
third_party/pam_wrapper/pam_wrapper.c
third_party/pam_wrapper/python/pypamtest.c
third_party/pam_wrapper/wscript

index a70260349844d6bacc7c05376c63aec355ae8d06..fbe58f3c166f3d5ab9677fbea2a3be4dc5d57f80 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.0.7')
+    return conf.CHECK_BUNDLED_SYSTEM_PKG('pam_wrapper', minversion='1.1.2')
 Build.BuildContext.CHECK_PAM_WRAPPER = CHECK_PAM_WRAPPER
index 48d2c2ae566a6a20a74e2caec5ff448c706aa44b..dd69c43f021e17cbaf6ed264fd0782ee862393dc 100644 (file)
@@ -36,6 +36,8 @@
 #include <limits.h>
 #include <ctype.h>
 
+#include <pthread.h>
+
 #include <ftw.h>
 
 #ifdef HAVE_SECURITY_PAM_APPL_H
  * LOGGING
  *****************/
 
+#ifndef HAVE_GETPROGNAME
+static const char *getprogname(void)
+{
+#if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
+       return program_invocation_short_name;
+#elif defined(HAVE_GETEXECNAME)
+       return getexecname();
+#else
+       return NULL;
+#endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
+}
+#endif /* HAVE_GETPROGNAME */
+
 enum pwrap_dbglvl_e {
        PWRAP_LOG_ERROR = 0,
        PWRAP_LOG_WARN,
@@ -123,6 +138,7 @@ static void pwrap_vlog(enum pwrap_dbglvl_e dbglvl,
        const char *d;
        unsigned int lvl = 0;
        const char *prefix = "PWRAP";
+       const char *progname = getprogname();
 
        d = getenv("PAM_WRAPPER_DEBUGLEVEL");
        if (d != NULL) {
@@ -136,24 +152,29 @@ static void pwrap_vlog(enum pwrap_dbglvl_e dbglvl,
        vsnprintf(buffer, sizeof(buffer), format, args);
 
        switch (dbglvl) {
-       case PWRAP_LOG_ERROR:
-               prefix = "PWRAP_ERROR";
-               break;
-       case PWRAP_LOG_WARN:
-               prefix = "PWRAP_WARN";
-               break;
-       case PWRAP_LOG_DEBUG:
-               prefix = "PWRAP_DEBUG";
-               break;
-       case PWRAP_LOG_TRACE:
-               prefix = "PWRAP_TRACE";
-               break;
+               case PWRAP_LOG_ERROR:
+                       prefix = "PWRAP_ERROR";
+                       break;
+               case PWRAP_LOG_WARN:
+                       prefix = "PWRAP_WARN";
+                       break;
+               case PWRAP_LOG_DEBUG:
+                       prefix = "PWRAP_DEBUG";
+                       break;
+               case PWRAP_LOG_TRACE:
+                       prefix = "PWRAP_TRACE";
+                       break;
+       }
+
+       if (progname == NULL) {
+               progname = "<unknown>";
        }
 
        fprintf(stderr,
-               "%s(%d) - %s: %s\n",
+               "%s[%s (%u)] - %s: %s\n",
                prefix,
-               (int)getpid(),
+               progname,
+               (unsigned int)getpid(),
                function,
                buffer);
 }
@@ -180,6 +201,12 @@ typedef int (*__libpam_pam_start)(const char *service_name,
                                  const struct pam_conv *pam_conversation,
                                  pam_handle_t **pamh);
 
+typedef int (*__libpam_pam_start_confdir)(const char *service_name,
+                                         const char *user,
+                                         const struct pam_conv *pam_conversation,
+                                         const char *confdir,
+                                         pam_handle_t **pamh);
+
 typedef int (*__libpam_pam_end)(pam_handle_t *pamh, int pam_status);
 
 typedef int (*__libpam_pam_authenticate)(pam_handle_t *pamh, int flags);
@@ -243,6 +270,7 @@ typedef void (*__libpam_pam_vsyslog)(const pam_handle_t *pamh,
 
 struct pwrap_libpam_symbols {
        PWRAP_SYMBOL_ENTRY(pam_start);
+       PWRAP_SYMBOL_ENTRY(pam_start_confdir);
        PWRAP_SYMBOL_ENTRY(pam_end);
        PWRAP_SYMBOL_ENTRY(pam_authenticate);
        PWRAP_SYMBOL_ENTRY(pam_chauthtok);
@@ -300,15 +328,25 @@ static void *pwrap_load_lib_handle(enum pwrap_lib lib)
        void *handle = NULL;
 
 #ifdef RTLD_DEEPBIND
-       const char *env = getenv("LD_PRELOAD");
+       const char *env_preload = getenv("LD_PRELOAD");
+       const char *env_deepbind = getenv("UID_WRAPPER_DISABLE_DEEPBIND");
+       bool enable_deepbind = true;
 
        /* Don't do a deepbind if we run with libasan */
-       if (env != NULL && strlen(env) < PATH_MAX) {
-               const char *p = strstr(env, "libasan.so");
-               if (p == NULL) {
-                       flags |= RTLD_DEEPBIND;
+       if (env_preload != NULL && strlen(env_preload) < 1024) {
+               const char *p = strstr(env_preload, "libasan.so");
+               if (p != NULL) {
+                       enable_deepbind = false;
                }
        }
+
+       if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
+               enable_deepbind = false;
+       }
+
+       if (enable_deepbind) {
+               flags |= RTLD_DEEPBIND;
+       }
 #endif
 
        switch (lib) {
@@ -368,6 +406,22 @@ static void *_pwrap_bind_symbol(enum pwrap_lib lib, const char *fn_name)
  * valgrind and has probably something todo with with the linker.
  * So we need load each function at the point it is called the first time.
  */
+#ifdef HAVE_PAM_START_CONFDIR
+static int libpam_pam_start_confdir(const char *service_name,
+                                   const char *user,
+                                   const struct pam_conv *pam_conversation,
+                                   const char *confdir,
+                                   pam_handle_t **pamh)
+{
+       pwrap_bind_symbol_libpam(pam_start_confdir);
+
+       return pwrap.libpam.symbols._libpam_pam_start_confdir.f(service_name,
+                                                               user,
+                                                               pam_conversation,
+                                                               confdir,
+                                                               pamh);
+}
+#else
 static int libpam_pam_start(const char *service_name,
                            const char *user,
                            const struct pam_conv *pam_conversation,
@@ -381,6 +435,8 @@ static int libpam_pam_start(const char *service_name,
                                                        pamh);
 }
 
+#endif
+
 static int libpam_pam_end(pam_handle_t *pamh, int pam_status)
 {
        pwrap_bind_symbol_libpam(pam_end);
@@ -748,14 +804,270 @@ static void pwrap_clean_stale_dirs(const char *dir)
        return;
 }
 
+#ifdef HAVE_PAM_START_CONFDIR
+static void pwrap_init(void)
+{
+       char tmp_config_dir[] = "/tmp/pam.X";
+       size_t len = strlen(tmp_config_dir);
+       const char *env;
+       struct stat sb;
+       int rc;
+       unsigned i;
+       ssize_t ret;
+       FILE *pidfile;
+       char pidfile_path[1024] = { 0 };
+       char letter;
+
+       if (!pam_wrapper_enabled()) {
+               return;
+       }
+
+       if (pwrap.initialised) {
+               return;
+       }
+
+       /*
+        * The name is selected to match/replace /etc/pam.d
+        * We start from a random alphanum trying letters until
+        * an available directory is found.
+        */
+       letter = 48 + (getpid() % 70);
+       for (i = 0; i < 127; i++) {
+               if (isalpha(letter) || isdigit(letter)) {
+                       tmp_config_dir[len - 1] = letter;
+
+                       rc = lstat(tmp_config_dir, &sb);
+                       if (rc == 0) {
+                               PWRAP_LOG(PWRAP_LOG_TRACE,
+                                         "Check if pam_wrapper dir %s is a "
+                                         "stale directory",
+                                         tmp_config_dir);
+                               pwrap_clean_stale_dirs(tmp_config_dir);
+                       } else if (rc < 0) {
+                               if (errno != ENOENT) {
+                                       continue;
+                               }
+                               break; /* found */
+                       }
+               }
+
+               letter++;
+               letter %= 127;
+       }
+
+       if (i == 127) {
+               PWRAP_LOG(PWRAP_LOG_ERROR,
+                         "Failed to find a possible path to create "
+                         "pam_wrapper config dir: %s",
+                         tmp_config_dir);
+               exit(1);
+       }
+
+       PWRAP_LOG(PWRAP_LOG_DEBUG, "Initialize pam_wrapper");
+
+       pwrap.config_dir = strdup(tmp_config_dir);
+       if (pwrap.config_dir == NULL) {
+               PWRAP_LOG(PWRAP_LOG_ERROR,
+                         "No memory");
+               exit(1);
+       }
+       PWRAP_LOG(PWRAP_LOG_TRACE,
+                 "pam_wrapper config dir: %s",
+                 tmp_config_dir);
+
+       rc = mkdir(pwrap.config_dir, 0755);
+       if (rc != 0) {
+               PWRAP_LOG(PWRAP_LOG_ERROR,
+                         "Failed to create pam_wrapper config dir: %s - %s",
+                         tmp_config_dir, strerror(errno));
+       }
+
+       /* Create file with the PID of the the process */
+       ret = snprintf(pidfile_path, sizeof(pidfile_path),
+                      "%s/pid", pwrap.config_dir);
+       if (ret < 0) {
+               p_rmdirs(pwrap.config_dir);
+               exit(1);
+       }
+
+       pidfile = fopen(pidfile_path, "w");
+       if (pidfile == NULL) {
+               p_rmdirs(pwrap.config_dir);
+               exit(1);
+       }
+
+       rc = fprintf(pidfile, "%d", getpid());
+       fclose(pidfile);
+       if (rc <= 0) {
+               p_rmdirs(pwrap.config_dir);
+               exit(1);
+       }
+
+       pwrap.libpam_so = strdup(PAM_LIBRARY);
+       if (pwrap.libpam_so == NULL) {
+               PWRAP_LOG(PWRAP_LOG_ERROR, "No memory");
+               p_rmdirs(pwrap.config_dir);
+               exit(1);
+       }
+
+       PWRAP_LOG(PWRAP_LOG_TRACE, "Using libpam path: %s", pwrap.libpam_so);
+
+       pwrap.initialised = true;
+
+       env = getenv("PAM_WRAPPER_SERVICE_DIR");
+       if (env == NULL) {
+               PWRAP_LOG(PWRAP_LOG_ERROR, "No config file");
+               p_rmdirs(pwrap.config_dir);
+               exit(1);
+       }
+
+       rc = copy_confdir(env);
+       if (rc != 0) {
+               PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to copy config files");
+               p_rmdirs(pwrap.config_dir);
+               exit(1);
+       }
+
+       setenv("PAM_WRAPPER_RUNTIME_DIR", pwrap.config_dir, 1);
+
+       PWRAP_LOG(PWRAP_LOG_DEBUG, "Successfully initialized pam_wrapper");
+}
+
+#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
        int srcfd = -1;
        int dstfd = -1;
        int rc = -1;
        ssize_t bread, bwritten;
        struct stat sb;
-       char buf[10];
+       char buf[PSO_COPY_READ_SIZE + 1];
        int cmp;
        size_t to_read;
        bool found_slash;
@@ -802,13 +1114,13 @@ static int pso_copy(const char *src, const char *dst, const char *pdir, mode_t m
                to_read = 1;
                if (!found_slash && buf[0] == '/') {
                        found_slash = true;
-                       to_read = 9;
+                       to_read = PSO_COPY_READ_SIZE;
                }
 
-               if (found_slash && bread == 9) {
-                       cmp = memcmp(buf, "etc/pam.d", 9);
+               if (found_slash && bread == PSO_COPY_READ_SIZE) {
+                       cmp = memcmp(buf, "etc/pam.d", PSO_COPY_READ_SIZE);
                        if (cmp == 0) {
-                               memcpy(buf, pdir + 1, 9);
+                               memcpy(buf, pdir + 1, PSO_COPY_READ_SIZE);
                        }
                        found_slash = false;
                }
@@ -840,7 +1152,9 @@ out:
        }
 
        return rc;
+#undef PSO_COPY_READ_SIZE
 }
+#endif /* HAVE_PAM_MODUTIL_SEARCH_KEY */
 
 static void pwrap_init(void)
 {
@@ -1027,6 +1341,8 @@ static void pwrap_init(void)
                exit(1);
        }
 
+       PWRAP_LOG(PWRAP_LOG_TRACE, "Using libpam path: %s", pwrap.libpam_so);
+
        pwrap.initialised = true;
 
        env = getenv("PAM_WRAPPER_SERVICE_DIR");
@@ -1047,6 +1363,7 @@ static void pwrap_init(void)
 
        PWRAP_LOG(PWRAP_LOG_DEBUG, "Successfully initialized pam_wrapper");
 }
+#endif /* HAVE_PAM_START_CONFDIR */
 
 bool pam_wrapper_enabled(void)
 {
@@ -1071,19 +1388,6 @@ bool pam_wrapper_enabled(void)
        return pwrap.enabled;
 }
 
-/****************************
- * CONSTRUCTOR
- ***************************/
-void pwrap_constructor(void)
-{
-       /*
-        * Here is safe place to call pwrap_init() and initialize data
-        * for main process.
-        */
-       pwrap_init();
-}
-
-
 #ifdef HAVE_OPENPAM
 static int pwrap_openpam_start(const char *service_name,
                               const char *user,
@@ -1139,22 +1443,35 @@ static int pwrap_pam_start(const char *service_name,
                           const struct pam_conv *pam_conversation,
                           pam_handle_t **pamh)
 {
+       int rc;
+
+       pwrap_init();
+
        PWRAP_LOG(PWRAP_LOG_TRACE,
                  "pam_start service=%s, user=%s",
                  service_name,
                  user);
 
-#ifdef HAVE_OPENPAM
-       return pwrap_openpam_start(service_name,
-                                  user,
-                                  pam_conversation,
-                                  pamh);
+#if defined(HAVE_OPENPAM)
+       rc = pwrap_openpam_start(service_name,
+                                user,
+                                pam_conversation,
+                                pamh);
+#elif defined (HAVE_PAM_START_CONFDIR)
+       rc = libpam_pam_start_confdir(service_name,
+                                     user,
+                                     pam_conversation,
+                                     pwrap.config_dir,
+                                     pamh);
 #else
-       return libpam_pam_start(service_name,
-                               user,
-                               pam_conversation,
-                               pamh);
+       rc = libpam_pam_start(service_name,
+                             user,
+                             pam_conversation,
+                             pamh);
 #endif
+       PWRAP_LOG(PWRAP_LOG_TRACE, "pam_start rc=%d", rc);
+
+       return rc;
 }
 
 
@@ -1678,21 +1995,77 @@ int cannot_audit(int x)
        return 1;
 }
 
+/****************************
+ * CONSTRUCTOR
+ ***************************/
+
+/*
+ * Handler executed before fork(2) processing starts.
+ */
+static void pwrap_thread_prepare(void)
+{
+}
+
+/*
+ * Handler that is executed in the parent process after fork(2) processing
+ * completes.
+ */
+static void pwrap_thread_parent(void)
+{
+}
+
+/*
+ * Handler that is executed in the child process after fork(2) processing
+ * completes.
+ */
+static void pwrap_thread_child(void)
+{
+       pwrap.initialised = false;
+}
+
+void pwrap_constructor(void)
+{
+       /*
+       * If we hold a lock and the application forks, then the child
+       * is not able to unlock the mutex and we are in a deadlock.
+       * This should prevent such deadlocks.
+       */
+       pthread_atfork(&pwrap_thread_prepare,
+                      &pwrap_thread_parent,
+                      &pwrap_thread_child);
+
+       /*
+        * Here is safe place to call pwrap_init() and initialize data
+        * for main process.
+        */
+       pwrap_init();
+}
+
 /****************************
  * DESTRUCTOR
  ***************************/
 
 static int p_rmdirs_at(const char *path, int parent_fd)
 {
-       DIR *d;
-       struct dirent *dp;
+       DIR *d = NULL;
+       struct dirent *dp = NULL;
        struct stat sb;
+       char fd_str[64] = { 0 };
        int path_fd;
        int rc;
 
+       switch(parent_fd) {
+       case AT_FDCWD:
+               snprintf(fd_str, sizeof(fd_str), "CWD");
+               break;
+       default:
+               snprintf(fd_str, sizeof(fd_str), "fd=%d", parent_fd);
+               break;
+       }
+
        /* If path is absolute, parent_fd is ignored. */
        PWRAP_LOG(PWRAP_LOG_TRACE,
-                 "p_rmdirs_at removing %s at %d\n", path, parent_fd);
+                 "p_rmdirs_at removing %s at %s\n", path, fd_str);
 
        path_fd = openat(parent_fd,
                         path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
@@ -1773,6 +2146,7 @@ void pwrap_destructor(void)
        if (!pwrap.initialised) {
                return;
        }
+       pwrap.initialised = false;
 
        PWRAP_LOG(PWRAP_LOG_TRACE,
                  "destructor called for pam_wrapper dir %s",
index 6bb1e204539c25769535e6a2b1aee7f744d23edf..8de05e9c39b9aec7e3157e6b6e878afcecbd591b 100644 (file)
@@ -166,11 +166,13 @@ static char **new_conv_list(const size_t list_size)
        return list;
 }
 
-static const char **sequence_as_string_list(PyObject *seq,
-                                           const char *paramname)
+static int sequence_as_string_list(PyObject *seq,
+                                  const char *paramname,
+                                  const char **str_list[],
+                                  size_t *num_str_list)
 {
        const char *p = paramname ? paramname : "attribute values";
-       const char **ret;
+       const char **result;
        PyObject *utf_item;
        int i;
        Py_ssize_t len;
@@ -179,18 +181,18 @@ static const char **sequence_as_string_list(PyObject *seq,
        if (!PySequence_Check(seq)) {
                PyErr_Format(PyExc_TypeError,
                             "The object must be a sequence\n");
-               return NULL;
+               return -1;
        }
 
        len = PySequence_Size(seq);
        if (len == -1) {
-               return NULL;
+               return -1;
        }
 
-       ret = PyMem_New(const char *, (len + 1));
-       if (!ret) {
+       result = PyMem_New(const char *, (len + 1));
+       if (result == NULL) {
                PyErr_NoMemory();
-               return NULL;
+               return -1;
        }
 
        for (i = 0; i < len; i++) {
@@ -202,20 +204,24 @@ static const char **sequence_as_string_list(PyObject *seq,
                utf_item = get_utf8_string(item, p);
                if (utf_item == NULL) {
                        Py_DECREF(item);
-                       return NULL;
+                       return -1;
                }
 
-               ret[i] = py_strdup(PyBytes_AsString(utf_item));
+               result[i] = py_strdup(PyBytes_AsString(utf_item));
                Py_DECREF(utf_item);
-               if (!ret[i]) {
+               if (result[i] == NULL) {
                        Py_DECREF(item);
-                       return NULL;
+                       return -1;
                }
                Py_DECREF(item);
        }
 
-       ret[i] = NULL;
-       return ret;
+       result[i] = NULL;
+
+       *str_list = result;
+       *num_str_list = (size_t)len;
+
+       return 0;
 }
 
 static PyObject *string_list_as_tuple(char **str_list)
@@ -225,7 +231,7 @@ static PyObject *string_list_as_tuple(char **str_list)
        PyObject *tup;
        PyObject *py_str;
 
-       for (len=0; len < PAM_CONV_MSG_MAX; len++) {
+       for (len=0; str_list[len] != NULL; len++) {
                if (str_list[len][0] == '\0') {
                        /* unused string, stop counting */
                        break;
@@ -297,7 +303,7 @@ set_pypamtest_exception(PyObject *exc,
 
        if (test_repr[0] != '\0' && failed != NULL) {
                PyErr_Format(exc,
-                            "Error [%d]: Test case %s retured [%d]",
+                            "Error [%d]: Test case %s returned [%d]",
                             perr, test_repr, failed->op_rv);
        } else {
                obj = Py_BuildValue(discard_const_p(char, "(i,s)"),
@@ -808,27 +814,42 @@ static int fill_conv_data(PyObject *py_echo_off,
                          PyObject *py_echo_on,
                          struct pamtest_conv_data *conv_data)
 {
+       size_t conv_count = 0;
+       size_t count = 0;
+       int rc;
+
        conv_data->in_echo_on = NULL;
        conv_data->in_echo_off = NULL;
        conv_data->out_err = NULL;
        conv_data->out_info = NULL;
 
        if (py_echo_off != NULL) {
-               conv_data->in_echo_off = sequence_as_string_list(py_echo_off,
-                                                                "echo_off");
-               if (conv_data->in_echo_off == NULL) {
+               rc = sequence_as_string_list(py_echo_off,
+                                            "echo_off",
+                                            &conv_data->in_echo_off,
+                                            &count);
+               if (rc != 0) {
                        free_conv_data(conv_data);
                        return ENOMEM;
                }
+               conv_count += count;
        }
 
        if (py_echo_on != NULL) {
-               conv_data->in_echo_on = sequence_as_string_list(py_echo_on,
-                                                               "echo_on");
-               if (conv_data->in_echo_on == NULL) {
+               rc = sequence_as_string_list(py_echo_on,
+                                            "echo_on",
+                                            &conv_data->in_echo_on,
+                                            &count);
+               if (rc != 0) {
                        free_conv_data(conv_data);
                        return ENOMEM;
                }
+               conv_count += count;
+       }
+
+       if (conv_count > PAM_CONV_MSG_MAX) {
+               free_conv_data(conv_data);
+               return ENOMEM;
        }
 
        conv_data->out_info = new_conv_list(PAM_CONV_MSG_MAX);
@@ -885,7 +906,7 @@ static int py_tc_list_to_cstruct_list(PyObject *py_test_list,
 PyDoc_STRVAR(RunPamTest__doc__,
 "Run PAM tests\n\n"
 "This function runs PAM test cases and reports result\n"
-"Paramaters:\n"
+"Parameters:\n"
 "service: The PAM service to use in the conversation (string)\n"
 "username: The user to run PAM conversation as\n"
 "test_list: Sequence of pypamtest.TestCase objects\n"
index aface6192c51865ff5f4dae7419f9c05e29797a5..fb57800587a4d85c08327e08bb7a69990814ea7e 100644 (file)
@@ -2,7 +2,7 @@
 
 import os
 
-VERSION="1.0.7"
+VERSION="1.1.2"
 
 def find_library(library_names, lookup_paths):
     for directory in lookup_paths:
@@ -51,6 +51,16 @@ def configure(conf):
                             checklibc=False,
                             headers='security/pam_ext.h')
 
+        conf.CHECK_FUNCS_IN('pam_start_confdir',
+                            'pam',
+                            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')
@@ -86,7 +96,7 @@ def build(bld):
         # breaks preloading!
         bld.SAMBA_LIBRARY('pam_wrapper',
                           source='pam_wrapper.c',
-                          deps='dl',
+                          deps='dl pthread',
                           install=False,
                           realname='libpam-wrapper.so')