LCOV - code coverage report
Current view: top level - third_party/pam_wrapper/python - pypamtest.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 289 490 59.0 %
Date: 2024-04-21 15:09:00 Functions: 23 31 74.2 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Andreas Schneider <asn@samba.org>
       3             :  * Copyright (c) 2015 Jakub Hrozek <jakub.hrozek@posteo.se>
       4             :  *
       5             :  * This program is free software: you can redistribute it and/or modify
       6             :  * it under the terms of the GNU General Public License as published by
       7             :  * the Free Software Foundation, either version 3 of the License, or
       8             :  * (at your option) any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :  * GNU General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License
      16             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17             :  */
      18             : 
      19             : #include "config.h"
      20             : 
      21             : #include <Python.h>
      22             : #include <structmember.h>
      23             : 
      24             : #include "libpamtest.h"
      25             : 
      26             : #define PYTHON_MODULE_NAME  "pypamtest"
      27             : 
      28             : #ifndef discard_const_p
      29             : #if defined(__intptr_t_defined) || defined(HAVE_UINTPTR_T)
      30             : # define discard_const_p(type, ptr) ((type *)((uintptr_t)(ptr)))
      31             : #else
      32             : # define discard_const_p(type, ptr) ((type *)(ptr))
      33             : #endif
      34             : #endif
      35             : 
      36             : #define    __unused    __attribute__((__unused__))
      37             : 
      38             : #if PY_MAJOR_VERSION >= 3
      39             : #define IS_PYTHON3 1
      40             : #define RETURN_ON_ERROR return NULL
      41             : #else
      42             : #define IS_PYTHON3 0
      43             : #define RETURN_ON_ERROR return
      44             : #endif /* PY_MAJOR_VERSION */
      45             : 
      46             : /* We only return up to 16 messages from the PAM conversation */
      47             : #define PAM_CONV_MSG_MAX        16
      48             : 
      49             : #if IS_PYTHON3
      50             : PyMODINIT_FUNC PyInit_pypamtest(void);
      51             : #else
      52             : PyMODINIT_FUNC initpypamtest(void);
      53             : #endif
      54             : 
      55             : typedef struct {
      56             :         PyObject_HEAD
      57             : 
      58             :         enum pamtest_ops pam_operation;
      59             :         int expected_rv;
      60             :         int flags;
      61             : 
      62             :         PyObject *pam_handle;
      63             :         PyObject *pam_env;
      64             : } TestCaseObject;
      65             : 
      66             : #define PyTestCase_AsTestCaseObject(py_obj) \
      67             :         (TestCaseObject *)(py_obj)
      68             : 
      69             : /**********************************************************
      70             :  *** module-specific exceptions
      71             :  **********************************************************/
      72             : static PyObject *PyExc_PamTestError;
      73             : 
      74             : /**********************************************************
      75             :  *** helper functions
      76             :  **********************************************************/
      77             : 
      78             : #define REPR_FMT "{ pam_operation [%d] " \
      79             :                               "expected_rv [%d] " \
      80             :                               "flags [%d] }"
      81             : 
      82         274 : static char *py_strdup(const char *string)
      83             : {
      84             :         char *copy;
      85             : 
      86         274 :         copy = PyMem_New(char, strlen(string) + 1);
      87         274 :         if (copy ==  NULL) {
      88           0 :                 PyErr_NoMemory();
      89           0 :                 return NULL;
      90             :         }
      91             : 
      92         274 :         return strcpy(copy, string);
      93             : }
      94             : 
      95         274 : static PyObject *get_utf8_string(PyObject *obj,
      96             :                                  const char *attrname)
      97             : {
      98         274 :         const char *a = attrname ? attrname : "attribute";
      99         274 :         PyObject *obj_utf8 = NULL;
     100             : 
     101         274 :         if (PyBytes_Check(obj)) {
     102           0 :                 obj_utf8 = obj;
     103           0 :                 Py_INCREF(obj_utf8); /* Make sure we can DECREF later */
     104         274 :         } else if (PyUnicode_Check(obj)) {
     105         274 :                 if ((obj_utf8 = PyUnicode_AsUTF8String(obj)) == NULL) {
     106           0 :                         return NULL;
     107             :                 }
     108             :         } else {
     109           0 :                 PyErr_Format(PyExc_TypeError, "%s must be a string", a);
     110           0 :                 return NULL;
     111             :         }
     112             : 
     113         274 :         return obj_utf8;
     114             : }
     115             : 
     116         504 : static void free_cstring_list(const char **list)
     117             : {
     118             :         int i;
     119             : 
     120         504 :         if (list == NULL) {
     121         254 :                 return;
     122             :         }
     123             : 
     124         524 :         for (i=0; list[i]; i++) {
     125         274 :                 PyMem_Free(discard_const_p(char, list[i]));
     126             :         }
     127         250 :         PyMem_Free(list);
     128             : }
     129             : 
     130         504 : static void free_string_list(char **list)
     131             : {
     132             :         int i;
     133             : 
     134         504 :         if (list == NULL) {
     135           0 :                 return;
     136             :         }
     137             : 
     138        8568 :         for (i=0; list[i]; i++) {
     139        8064 :                 PyMem_Free(list[i]);
     140             :         }
     141         504 :         PyMem_Free(list);
     142             : }
     143             : 
     144         504 : static char **new_conv_list(const size_t list_size)
     145             : {
     146             :         char **list;
     147             :         size_t i;
     148             : 
     149         504 :         if (list_size == 0) {
     150           0 :                 return NULL;
     151             :         }
     152             : 
     153         504 :         if (list_size + 1 < list_size) {
     154           0 :                 return NULL;
     155             :         }
     156             : 
     157         504 :         list = PyMem_New(char *, list_size + 1);
     158         504 :         if (list == NULL) {
     159           0 :                 return NULL;
     160             :         }
     161         504 :         list[list_size] = NULL;
     162             : 
     163        8568 :         for (i = 0; i < list_size; i++) {
     164        8064 :                 list[i] = PyMem_New(char, PAM_MAX_MSG_SIZE);
     165        8064 :                 if (list[i] == NULL) {
     166           0 :                         PyMem_Free(list);
     167           0 :                         return NULL;
     168             :                 }
     169        8064 :                 memset(list[i], 0, PAM_MAX_MSG_SIZE);
     170             :         }
     171             : 
     172         504 :         return list;
     173             : }
     174             : 
     175         250 : static int sequence_as_string_list(PyObject *seq,
     176             :                                    const char *paramname,
     177             :                                    const char **str_list[],
     178             :                                    size_t *num_str_list)
     179             : {
     180         250 :         const char *p = paramname ? paramname : "attribute values";
     181             :         const char **result;
     182             :         PyObject *utf_item;
     183             :         int i;
     184             :         Py_ssize_t len;
     185             :         PyObject *item;
     186             : 
     187         250 :         if (!PySequence_Check(seq)) {
     188           0 :                 PyErr_Format(PyExc_TypeError,
     189             :                              "The object must be a sequence\n");
     190           0 :                 return -1;
     191             :         }
     192             : 
     193         250 :         len = PySequence_Size(seq);
     194         250 :         if (len == -1) {
     195           0 :                 return -1;
     196             :         }
     197             : 
     198         250 :         result = PyMem_New(const char *, (len + 1));
     199         250 :         if (result == NULL) {
     200           0 :                 PyErr_NoMemory();
     201           0 :                 return -1;
     202             :         }
     203             : 
     204         524 :         for (i = 0; i < len; i++) {
     205         274 :                 item = PySequence_GetItem(seq, i);
     206         274 :                 if (item == NULL) {
     207           0 :                         break;
     208             :                 }
     209             : 
     210         274 :                 utf_item = get_utf8_string(item, p);
     211         274 :                 if (utf_item == NULL) {
     212           0 :                         Py_DECREF(item);
     213           0 :                         return -1;
     214             :                 }
     215             : 
     216         274 :                 result[i] = py_strdup(PyBytes_AsString(utf_item));
     217         137 :                 Py_DECREF(utf_item);
     218         274 :                 if (result[i] == NULL) {
     219           0 :                         Py_DECREF(item);
     220           0 :                         return -1;
     221             :                 }
     222         137 :                 Py_DECREF(item);
     223             :         }
     224             : 
     225         250 :         result[i] = NULL;
     226             : 
     227         250 :         *str_list = result;
     228         250 :         *num_str_list = (size_t)len;
     229             : 
     230         250 :         return 0;
     231             : }
     232             : 
     233         504 : static PyObject *string_list_as_tuple(char **str_list)
     234             : {
     235             :         int rc;
     236             :         size_t len, i;
     237             :         PyObject *tup;
     238             :         PyObject *py_str;
     239             : 
     240         572 :         for (len=0; str_list[len] != NULL; len++) {
     241         572 :                 if (str_list[len][0] == '\0') {
     242             :                         /* unused string, stop counting */
     243         504 :                         break;
     244             :                 }
     245             :         }
     246             : 
     247         504 :         tup = PyTuple_New(len);
     248         504 :         if (tup == NULL) {
     249           0 :                 PyErr_NoMemory();
     250           0 :                 return NULL;
     251             :         }
     252             : 
     253         572 :         for (i = 0; i < len; i++) {
     254          68 :                 py_str = PyUnicode_FromString(str_list[i]);
     255          68 :                 if (py_str == NULL) {
     256           0 :                         Py_DECREF(tup);
     257           0 :                         PyErr_NoMemory();
     258           0 :                         return NULL;
     259             :                 }
     260             : 
     261             :                 /* PyTuple_SetItem() steals the reference to
     262             :                  * py_str, so it's enough to decref the tuple
     263             :                  * pointer afterwards */
     264          68 :                 rc = PyTuple_SetItem(tup, i, py_str);
     265          68 :                 if (rc != 0) {
     266             :                         /* cleanup */
     267           0 :                         Py_DECREF(py_str);
     268           0 :                         Py_DECREF(tup);
     269           0 :                         PyErr_NoMemory();
     270           0 :                         return NULL;
     271             :                 }
     272             :         }
     273             : 
     274         504 :         return tup;
     275             : }
     276             : 
     277             : static void
     278           0 : set_pypamtest_exception(PyObject *exc,
     279             :                         enum pamtest_err perr,
     280             :                         struct pam_testcase *tests,
     281             :                         size_t num_tests)
     282             : {
     283           0 :         PyObject *obj = NULL;
     284             :         /* REPR_FMT contains just %d expansions, so this is safe */
     285           0 :         char test_repr[256] = { '\0' };
     286             :         union {
     287             :                 char *str;
     288             :                 PyObject *obj;
     289             :         } pypam_str_object;
     290             :         const char *strerr;
     291           0 :         const struct pam_testcase *failed = NULL;
     292             : 
     293           0 :         if (exc == NULL) {
     294           0 :                 PyErr_BadArgument();
     295           0 :                 return;
     296             :         }
     297             : 
     298           0 :         strerr = pamtest_strerror(perr);
     299             : 
     300           0 :         if (perr == PAMTEST_ERR_CASE) {
     301           0 :                 failed = _pamtest_failed_case(tests, num_tests);
     302           0 :                 if (failed) {
     303           0 :                         snprintf(test_repr, sizeof(test_repr), REPR_FMT,
     304           0 :                                  failed->pam_operation,
     305           0 :                                  failed->expected_rv,
     306           0 :                                  failed->flags);
     307             :                 }
     308             :         }
     309             : 
     310           0 :         if (test_repr[0] != '\0' && failed != NULL) {
     311           0 :                 PyErr_Format(exc,
     312             :                              "Error [%d]: Test case %s returned [%d]",
     313           0 :                              perr, test_repr, failed->op_rv);
     314             :         } else {
     315           0 :                 obj = Py_BuildValue(discard_const_p(char, "(i,s)"),
     316             :                                         perr,
     317             :                                         strerr ? strerr : "Unknown error");
     318           0 :                 PyErr_SetObject(exc, obj);
     319             :         }
     320             : 
     321           0 :         pypam_str_object.str = test_repr;
     322           0 :         Py_XDECREF(pypam_str_object.obj);
     323           0 :         Py_XDECREF(obj);
     324             : }
     325             : 
     326             : /* Returned when doc(test_case) is invoked */
     327             : PyDoc_STRVAR(TestCaseObject__doc__,
     328             : "pamtest test case\n\n"
     329             : "Represents one operation in PAM transaction. An example is authentication, "
     330             : "opening a session or password change. Each operation has an expected error "
     331             : "code. The run_pamtest() function accepts a list of these test case objects\n"
     332             : "Params:\n\n"
     333             : "pam_operation: - the PAM operation to run. Use constants from pypamtest "
     334             : "such as pypamtest.PAMTEST_AUTHENTICATE. This argument is required.\n"
     335             : "expected_rv: - The PAM return value we expect the operation to return. "
     336             : "Defaults to 0 (PAM_SUCCESS)\n"
     337             : "flags: - Additional flags to pass to the PAM operation. Defaults to 0.\n"
     338             : );
     339             : 
     340             : static PyObject *
     341         256 : TestCase_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     342             : {
     343             :         TestCaseObject *self;
     344             : 
     345             :         (void) args; /* unused */
     346             :         (void) kwds; /* unused */
     347             : 
     348         256 :         self = (TestCaseObject *)type->tp_alloc(type, 0);
     349         256 :         if (self == NULL) {
     350           0 :                 PyErr_NoMemory();
     351           0 :                 return NULL;
     352             :         }
     353             : 
     354         256 :         return (PyObject *) self;
     355             : }
     356             : 
     357             : /* The traverse and clear methods must be defined even though they do nothing
     358             :  * otherwise Garbage Collector is not happy
     359             :  */
     360           0 : static int TestCase_clear(TestCaseObject *self)
     361             : {
     362             :         (void) self; /* unused */
     363             : 
     364           0 :         return 0;
     365             : }
     366             : 
     367         256 : static void TestCase_dealloc(TestCaseObject *self)
     368             : {
     369         256 :         Py_TYPE(self)->tp_free((PyObject *)self);
     370         256 : }
     371             : 
     372           0 : static int TestCase_traverse(TestCaseObject *self,
     373             :                              visitproc visit,
     374             :                              void *arg)
     375             : {
     376             :         (void) self; /* unused */
     377             :         (void) visit; /* unused */
     378             :         (void) arg; /* unused */
     379             : 
     380           0 :         return 0;
     381             : }
     382             : 
     383         256 : static int TestCase_init(TestCaseObject *self,
     384             :                          PyObject *args,
     385             :                          PyObject *kwargs)
     386             : {
     387         256 :         const char * const kwlist[] = { "pam_operation",
     388             :                                         "expected_rv",
     389             :                                         "flags",
     390             :                                         NULL };
     391         256 :         int pam_operation = -1;
     392         256 :         int expected_rv = PAM_SUCCESS;
     393         256 :         int flags = 0;
     394             :         int ok;
     395             : 
     396         256 :         ok = PyArg_ParseTupleAndKeywords(args,
     397             :                                          kwargs,
     398             :                                          "i|ii",
     399             :                                          discard_const_p(char *, kwlist),
     400             :                                          &pam_operation,
     401             :                                          &expected_rv,
     402             :                                          &flags);
     403         256 :         if (!ok) {
     404           0 :                 return -1;
     405             :         }
     406             : 
     407         256 :         switch (pam_operation) {
     408         256 :         case PAMTEST_AUTHENTICATE:
     409             :         case PAMTEST_SETCRED:
     410             :         case PAMTEST_ACCOUNT:
     411             :         case PAMTEST_OPEN_SESSION:
     412             :         case PAMTEST_CLOSE_SESSION:
     413             :         case PAMTEST_CHAUTHTOK:
     414             :         case PAMTEST_GETENVLIST:
     415             :         case PAMTEST_KEEPHANDLE:
     416         256 :                 break;
     417           0 :         default:
     418           0 :                 PyErr_Format(PyExc_ValueError,
     419             :                              "Unsupported PAM operation %d",
     420             :                              pam_operation);
     421           0 :                 return -1;
     422             :         }
     423             : 
     424         256 :         self->flags = flags;
     425         256 :         self->expected_rv = expected_rv;
     426         256 :         self->pam_operation = pam_operation;
     427             : 
     428         256 :         return 0;
     429             : }
     430             : 
     431             : /*
     432             :  * This function returns string representation of the object, but one that
     433             :  * can be parsed by a machine.
     434             :  *
     435             :  * str() is also string represtentation, but just human-readable.
     436             :  */
     437           0 : static PyObject *TestCase_repr(TestCaseObject *self)
     438             : {
     439           0 :         return PyUnicode_FromFormat(REPR_FMT,
     440           0 :                                     self->pam_operation,
     441             :                                     self->expected_rv,
     442             :                                     self->flags);
     443             : }
     444             : 
     445             : static PyMemberDef pypamtest_test_case_members[] = {
     446             :         {
     447             :                 discard_const_p(char, "pam_operation"),
     448             :                 T_INT,
     449             :                 offsetof(TestCaseObject, pam_operation),
     450             :                 READONLY,
     451             :                 discard_const_p(char, "The PAM operation to run"),
     452             :         },
     453             : 
     454             :         {
     455             :                 discard_const_p(char, "expected_rv"),
     456             :                 T_INT,
     457             :                 offsetof(TestCaseObject, expected_rv),
     458             :                 READONLY,
     459             :                 discard_const_p(char, "The expected PAM return code"),
     460             :         },
     461             : 
     462             :         {
     463             :                 discard_const_p(char, "flags"),
     464             :                 T_INT,
     465             :                 offsetof(TestCaseObject, flags),
     466             :                 READONLY,
     467             :                 discard_const_p(char, "Additional flags for the PAM operation"),
     468             :         },
     469             : 
     470             :         {
     471             :                 discard_const_p(char, "pam_handle"),
     472             :                 T_OBJECT_EX,
     473             :                 offsetof(TestCaseObject, pam_handle),
     474             :                 READONLY,
     475             :                 discard_const_p(char, "Pam handle"),
     476             :         },
     477             : 
     478             :         {
     479             :                 discard_const_p(char, "pam_env"),
     480             :                 T_OBJECT_EX,
     481             :                 offsetof(TestCaseObject, pam_env),
     482             :                 READONLY,
     483             :                 discard_const_p(char, "Pam env"),
     484             :         },
     485             : 
     486             :         { NULL, 0, 0, 0, NULL } /* Sentinel */
     487             : };
     488             : 
     489             : static PyTypeObject pypamtest_test_case = {
     490             :         PyVarObject_HEAD_INIT(NULL, 0)
     491             :         .tp_name = "pypamtest.TestCase",
     492             :         .tp_basicsize = sizeof(TestCaseObject),
     493             :         .tp_new = TestCase_new,
     494             :         .tp_dealloc = (destructor) TestCase_dealloc,
     495             :         .tp_traverse = (traverseproc) TestCase_traverse,
     496             :         .tp_clear = (inquiry) TestCase_clear,
     497             :         .tp_init = (initproc) TestCase_init,
     498             :         .tp_repr = (reprfunc) TestCase_repr,
     499             :         .tp_members = pypamtest_test_case_members,
     500             :         .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
     501             :         .tp_doc   = TestCaseObject__doc__
     502             : };
     503             : 
     504             : PyDoc_STRVAR(TestResultObject__doc__,
     505             : "pamtest test result\n\n"
     506             : "The test result object is returned from run_pamtest on success. It contains"
     507             : "two lists of strings (up to 16 strings each) which contain the info and error"
     508             : "messages the PAM conversation printed\n\n"
     509             : "Attributes:\n"
     510             : "errors: PAM_ERROR_MSG-level messages printed during the PAM conversation\n"
     511             : "info: PAM_TEXT_INFO-level messages printed during the PAM conversation\n"
     512             : );
     513             : 
     514             : typedef struct {
     515             :         PyObject_HEAD
     516             : 
     517             :         PyObject *info_msg_list;
     518             :         PyObject *error_msg_list;
     519             : } TestResultObject;
     520             : 
     521             : static PyObject *
     522         252 : TestResult_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     523             : {
     524             :         TestResultObject *self;
     525             : 
     526             :         (void) args; /* unused */
     527             :         (void) kwds; /* unused */
     528             : 
     529         252 :         self = (TestResultObject *)type->tp_alloc(type, 0);
     530         252 :         if (self == NULL) {
     531           0 :                 PyErr_NoMemory();
     532           0 :                 return NULL;
     533             :         }
     534             : 
     535         252 :         return (PyObject *) self;
     536             : }
     537             : 
     538           0 : static int TestResult_clear(TestResultObject *self)
     539             : {
     540             :         (void) self; /* unused */
     541             : 
     542           0 :         return 0;
     543             : }
     544             : 
     545         252 : static void TestResult_dealloc(TestResultObject *self)
     546             : {
     547         252 :         Py_TYPE(self)->tp_free((PyObject *)self);
     548         252 : }
     549             : 
     550           0 : static int TestResult_traverse(TestResultObject *self,
     551             :                                visitproc visit,
     552             :                                void *arg)
     553             : {
     554             :         (void) self;    /* unused */
     555             :         (void) visit;   /* unused */
     556             :         (void) arg;     /* unused */
     557             : 
     558           0 :         return 0;
     559             : }
     560             : 
     561         252 : static int TestResult_init(TestResultObject *self,
     562             :                            PyObject *args,
     563             :                            PyObject *kwargs)
     564             : {
     565         252 :         const char * const kwlist[] = { "info_msg_list",
     566             :                                         "error_msg_list",
     567             :                                         NULL };
     568             :         int ok;
     569         252 :         PyObject *py_info_list = NULL;
     570         252 :         PyObject *py_err_list = NULL;
     571             : 
     572         252 :         ok = PyArg_ParseTupleAndKeywords(args,
     573             :                                          kwargs,
     574             :                                          "|OO",
     575             :                                          discard_const_p(char *, kwlist),
     576             :                                          &py_info_list,
     577             :                                          &py_err_list);
     578         252 :         if (!ok) {
     579           0 :                 return -1;
     580             :         }
     581             : 
     582         252 :         if (py_info_list) {
     583         252 :                 ok = PySequence_Check(py_info_list);
     584         252 :                 if (!ok) {
     585           0 :                         PyErr_Format(PyExc_TypeError,
     586             :                                 "List of info messages must be a sequence\n");
     587           0 :                         return -1;
     588             :                 }
     589             : 
     590         252 :                 self->info_msg_list = py_info_list;
     591         252 :                 Py_XINCREF(py_info_list);
     592             :         } else {
     593           0 :                 self->info_msg_list = PyList_New(0);
     594           0 :                 if (self->info_msg_list == NULL) {
     595           0 :                         PyErr_NoMemory();
     596           0 :                         return -1;
     597             :                 }
     598             :         }
     599             : 
     600         252 :         if (py_err_list) {
     601         252 :                 ok = PySequence_Check(py_err_list);
     602         252 :                 if (!ok) {
     603           0 :                         PyErr_Format(PyExc_TypeError,
     604             :                                 "List of error messages must be a sequence\n");
     605           0 :                         return -1;
     606             :                 }
     607             : 
     608         252 :                 self->error_msg_list = py_err_list;
     609         252 :                 Py_XINCREF(py_err_list);
     610             :         } else {
     611           0 :                 self->error_msg_list = PyList_New(0);
     612           0 :                 if (self->error_msg_list == NULL) {
     613           0 :                         PyErr_NoMemory();
     614           0 :                         return -1;
     615             :                 }
     616             :         }
     617             : 
     618         252 :         return 0;
     619             : }
     620             : 
     621           0 : static PyObject *test_result_list_concat(PyObject *list,
     622             :                                          const char delim_pre,
     623             :                                          const char delim_post)
     624             : {
     625             :         PyObject *res;
     626             :         PyObject *item;
     627             :         Py_ssize_t size;
     628             :         Py_ssize_t i;
     629             : 
     630           0 :         res = PyUnicode_FromString("");
     631           0 :         if (res == NULL) {
     632           0 :                 return NULL;
     633             :         }
     634             : 
     635           0 :         size = PySequence_Size(list);
     636             : 
     637           0 :         for (i=0; i < size; i++) {
     638           0 :                 item = PySequence_GetItem(list, i);
     639           0 :                 if (item == NULL) {
     640           0 :                         PyMem_Free(res);
     641           0 :                         return NULL;
     642             :                 }
     643             : 
     644             : #if IS_PYTHON3
     645           0 :                 res = PyUnicode_FromFormat("%U%c%U%c",
     646             :                                            res, delim_pre, item, delim_post);
     647             : #else
     648             :                 res = PyUnicode_FromFormat("%U%c%s%c",
     649             :                                            res,
     650             :                                            delim_pre,
     651             :                                            PyString_AsString(item),
     652             :                                            delim_post);
     653             : #endif
     654           0 :                 Py_XDECREF(item);
     655             :         }
     656             : 
     657           0 :         return res;
     658             : }
     659             : 
     660           0 : static PyObject *TestResult_repr(TestResultObject *self)
     661             : {
     662           0 :         PyObject *u_info = NULL;
     663           0 :         PyObject *u_error = NULL;
     664           0 :         PyObject *res = NULL;
     665             : 
     666           0 :         u_info = test_result_list_concat(self->info_msg_list, '{', '}');
     667           0 :         u_error = test_result_list_concat(self->info_msg_list, '{', '}');
     668           0 :         if (u_info == NULL || u_error == NULL) {
     669           0 :                 Py_XDECREF(u_error);
     670           0 :                 Py_XDECREF(u_info);
     671           0 :                 return NULL;
     672             :         }
     673             : 
     674           0 :         res = PyUnicode_FromFormat("{ errors: { %U } infos: { %U } }",
     675             :                                    u_info, u_error);
     676           0 :         Py_DECREF(u_error);
     677           0 :         Py_DECREF(u_info);
     678           0 :         return res;
     679             : }
     680             : 
     681             : static PyMemberDef pypamtest_test_result_members[] = {
     682             :         {
     683             :                 discard_const_p(char, "errors"),
     684             :                 T_OBJECT_EX,
     685             :                 offsetof(TestResultObject, error_msg_list),
     686             :                 READONLY,
     687             :                 discard_const_p(char,
     688             :                                 "List of error messages from PAM conversation"),
     689             :         },
     690             : 
     691             :         {
     692             :                 discard_const_p(char, "info"),
     693             :                 T_OBJECT_EX,
     694             :                 offsetof(TestResultObject, info_msg_list),
     695             :                 READONLY,
     696             :                 discard_const_p(char,
     697             :                                 "List of info messages from PAM conversation"),
     698             :         },
     699             : 
     700             :         { NULL, 0, 0, 0, NULL } /* Sentinel */
     701             : };
     702             : 
     703             : static PyTypeObject pypamtest_test_result = {
     704             :         PyVarObject_HEAD_INIT(NULL, 0)
     705             :         .tp_name = "pypamtest.TestResult",
     706             :         .tp_basicsize = sizeof(TestResultObject),
     707             :         .tp_new = TestResult_new,
     708             :         .tp_dealloc = (destructor) TestResult_dealloc,
     709             :         .tp_traverse = (traverseproc) TestResult_traverse,
     710             :         .tp_clear = (inquiry) TestResult_clear,
     711             :         .tp_init = (initproc) TestResult_init,
     712             :         .tp_repr = (reprfunc) TestResult_repr,
     713             :         .tp_members = pypamtest_test_result_members,
     714             :         .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
     715             :         .tp_doc   = TestResultObject__doc__
     716             : };
     717             : 
     718             : /**********************************************************
     719             :  *** Methods of the module
     720             :  **********************************************************/
     721             : 
     722         252 : static TestResultObject *construct_test_conv_result(char **msg_info, char **msg_err)
     723             : {
     724         252 :         PyObject *py_msg_info = NULL;
     725         252 :         PyObject *py_msg_err = NULL;
     726         252 :         TestResultObject *result = NULL;
     727         252 :         PyObject *result_args = NULL;
     728             :         int rc;
     729             : 
     730         252 :         py_msg_info = string_list_as_tuple(msg_info);
     731         252 :         py_msg_err = string_list_as_tuple(msg_err);
     732         252 :         if (py_msg_info == NULL || py_msg_err == NULL) {
     733             :                 /* The exception is raised in string_list_as_tuple() */
     734           0 :                 Py_XDECREF(py_msg_err);
     735           0 :                 Py_XDECREF(py_msg_info);
     736           0 :                 return NULL;
     737             :         }
     738             : 
     739         252 :         result = (TestResultObject *) TestResult_new(&pypamtest_test_result,
     740             :                                                      NULL,
     741             :                                                      NULL);
     742         252 :         if (result == NULL) {
     743             :                 /* The exception is raised in TestResult_new */
     744           0 :                 Py_XDECREF(py_msg_err);
     745           0 :                 Py_XDECREF(py_msg_info);
     746           0 :                 return NULL;
     747             :         }
     748             : 
     749         252 :         result_args = PyTuple_New(2);
     750         252 :         if (result_args == NULL) {
     751             :                 /* The exception is raised in TestResult_new */
     752           0 :                 Py_XDECREF(result);
     753           0 :                 Py_XDECREF(py_msg_err);
     754           0 :                 Py_XDECREF(py_msg_info);
     755           0 :                 return NULL;
     756             :         }
     757             : 
     758             :         /* Brand new tuples with fixed size don't need error checking */
     759         252 :         PyTuple_SET_ITEM(result_args, 0, py_msg_info);
     760         252 :         PyTuple_SET_ITEM(result_args, 1, py_msg_err);
     761             : 
     762         252 :         rc = TestResult_init(result, result_args, NULL);
     763         252 :         Py_XDECREF(result_args);
     764         252 :         if (rc != 0) {
     765           0 :                 Py_XDECREF(result);
     766           0 :                 return NULL;
     767             :         }
     768             : 
     769         252 :         return result;
     770             : }
     771             : 
     772         768 : static int py_testcase_get(PyObject *py_test,
     773             :                            const char *member_name,
     774             :                            long *_value)
     775             : {
     776         768 :         PyObject* item = NULL;
     777             : 
     778             :         /*
     779             :          * PyPyObject_GetAttrString() increases the refcount on the
     780             :          * returned value.
     781             :          */
     782         768 :         item = PyObject_GetAttrString(py_test, member_name);
     783         768 :         if (item == NULL) {
     784           0 :                 return EINVAL;
     785             :         }
     786             : 
     787         768 :         *_value = PyLong_AsLong(item);
     788         384 :         Py_DECREF(item);
     789             : 
     790         768 :         return 0;
     791             : }
     792             : 
     793         256 : static int py_testcase_to_cstruct(PyObject *py_test, struct pam_testcase *test)
     794             : {
     795             :         int rc;
     796             :         long value;
     797             : 
     798         256 :         memset(test, 0, sizeof(struct pam_testcase));
     799             : 
     800         256 :         rc = py_testcase_get(py_test, "pam_operation", &value);
     801         256 :         if (rc != 0) {
     802           0 :                 return rc;
     803             :         }
     804         256 :         test->pam_operation = value;
     805             : 
     806         256 :         rc = py_testcase_get(py_test, "expected_rv", &value);
     807         256 :         if (rc != 0) {
     808           0 :                 return rc;
     809             :         }
     810         256 :         test->expected_rv = value;
     811             : 
     812         256 :         rc = py_testcase_get(py_test, "flags", &value);
     813         256 :         if (rc != 0) {
     814           0 :                 return rc;
     815             :         }
     816         256 :         test->flags = value;
     817             : 
     818         256 :         return 0;
     819             : }
     820             : 
     821         252 : static void free_conv_data(struct pamtest_conv_data *conv_data)
     822             : {
     823         252 :         if (conv_data == NULL) {
     824           0 :                 return;
     825             :         }
     826             : 
     827         252 :         free_string_list(conv_data->out_err);
     828         252 :         free_string_list(conv_data->out_info);
     829         252 :         free_cstring_list(conv_data->in_echo_on);
     830         252 :         free_cstring_list(conv_data->in_echo_off);
     831             : }
     832             : 
     833             : /* conv_data must be a pointer to allocated conv_data structure.
     834             :  *
     835             :  * Use free_conv_data() to free the contents.
     836             :  */
     837         252 : static int fill_conv_data(PyObject *py_echo_off,
     838             :                           PyObject *py_echo_on,
     839             :                           struct pamtest_conv_data *conv_data)
     840             : {
     841         252 :         size_t conv_count = 0;
     842         252 :         size_t count = 0;
     843             :         int rc;
     844             : 
     845         252 :         conv_data->in_echo_on = NULL;
     846         252 :         conv_data->in_echo_off = NULL;
     847         252 :         conv_data->out_err = NULL;
     848         252 :         conv_data->out_info = NULL;
     849             : 
     850         252 :         if (py_echo_off != NULL) {
     851         250 :                 rc = sequence_as_string_list(py_echo_off,
     852             :                                              "echo_off",
     853             :                                              &conv_data->in_echo_off,
     854             :                                              &count);
     855         250 :                 if (rc != 0) {
     856           0 :                         free_conv_data(conv_data);
     857           0 :                         return ENOMEM;
     858             :                 }
     859         250 :                 conv_count += count;
     860             :         }
     861             : 
     862         252 :         if (py_echo_on != NULL) {
     863           0 :                 rc = sequence_as_string_list(py_echo_on,
     864             :                                              "echo_on",
     865             :                                              &conv_data->in_echo_on,
     866             :                                              &count);
     867           0 :                 if (rc != 0) {
     868           0 :                         free_conv_data(conv_data);
     869           0 :                         return ENOMEM;
     870             :                 }
     871           0 :                 conv_count += count;
     872             :         }
     873             : 
     874         252 :         if (conv_count > PAM_CONV_MSG_MAX) {
     875           0 :                 free_conv_data(conv_data);
     876           0 :                 return ENOMEM;
     877             :         }
     878             : 
     879         252 :         conv_data->out_info = new_conv_list(PAM_CONV_MSG_MAX);
     880         252 :         conv_data->out_err = new_conv_list(PAM_CONV_MSG_MAX);
     881         252 :         if (conv_data->out_info == NULL || conv_data->out_err == NULL) {
     882           0 :                 free_conv_data(conv_data);
     883           0 :                 return ENOMEM;
     884             :         }
     885             : 
     886         252 :         return 0;
     887             : }
     888             : 
     889             : /* test_list is allocated using PyMem_New and must be freed accordingly.
     890             :  * Returns errno that should be handled into exception in the caller
     891             :  */
     892         252 : static int py_tc_list_to_cstruct_list(PyObject *py_test_list,
     893             :                                       Py_ssize_t num_tests,
     894             :                                       struct pam_testcase **_test_list)
     895             : {
     896             :         Py_ssize_t i;
     897             :         PyObject *py_test;
     898             :         int rc;
     899             :         struct pam_testcase *test_list;
     900             : 
     901         252 :         test_list = PyMem_New(struct pam_testcase,
     902             :                             num_tests * sizeof(struct pam_testcase));
     903         252 :         if (test_list == NULL) {
     904           0 :                 return ENOMEM;
     905             :         }
     906             : 
     907         508 :         for (i = 0; i < num_tests; i++) {
     908             :                 /*
     909             :                  * PySequence_GetItem() increases the refcount on the
     910             :                  * returned value
     911             :                  */
     912         256 :                 py_test = PySequence_GetItem(py_test_list, i);
     913         256 :                 if (py_test == NULL) {
     914           0 :                         PyMem_Free(test_list);
     915           0 :                         return EIO;
     916             :                 }
     917             : 
     918         256 :                 rc = py_testcase_to_cstruct(py_test, &test_list[i]);
     919         128 :                 Py_DECREF(py_test);
     920         256 :                 if (rc != 0) {
     921           0 :                         PyMem_Free(test_list);
     922           0 :                         return EIO;
     923             :                 }
     924             :         }
     925             : 
     926         252 :         *_test_list = test_list;
     927         252 :         return 0;
     928             : }
     929             : 
     930         256 : static int cstruct_to_py_testcase(PyObject *pytest, struct pam_testcase *ctest)
     931             : {
     932         256 :         TestCaseObject *t = PyTestCase_AsTestCaseObject(pytest);
     933             :         size_t i;
     934             :         int rc;
     935             : 
     936         256 :         switch (t->pam_operation) {
     937           2 :         case PAMTEST_GETENVLIST:
     938           2 :                 if (ctest->case_out.envlist == NULL) {
     939           0 :                         break;
     940             :                 }
     941             : 
     942           2 :                 t->pam_env = PyDict_New();
     943           2 :                 if (t->pam_env == NULL) {
     944           0 :                         return ENOMEM;
     945             :                 }
     946           4 :                 for (i = 0; ctest->case_out.envlist[i] != NULL; i++) {
     947           2 :                         char *key = NULL;
     948           2 :                         char *val = NULL;
     949           2 :                         key = strdup(ctest->case_out.envlist[i]);
     950           2 :                         if (key == NULL) {
     951           0 :                                 return ENOMEM;
     952             :                         }
     953           2 :                         val = strrchr(key, '=');
     954           2 :                         if (val == NULL) {
     955           0 :                                 PyErr_Format(PyExc_IOError,
     956             :                                              "Failed to parse PAM environment "
     957             :                                              "variable");
     958           0 :                                 free(key);
     959           0 :                                 return EINVAL;
     960             :                         }
     961           2 :                         *val = '\0';
     962           2 :                         rc = PyDict_SetItem(t->pam_env,
     963             :                                             PyUnicode_FromString(key),
     964           2 :                                             PyUnicode_FromString(val + 1));
     965           2 :                         free(key);
     966           2 :                         if (rc == -1) {
     967           0 :                                 return rc;
     968             :                         }
     969             :                 }
     970           2 :                 break;
     971           2 :         case PAMTEST_KEEPHANDLE:
     972           2 :                 t->pam_handle = PyCapsule_New(ctest->case_out.ph, NULL, NULL);
     973           2 :                 if (t->pam_handle == NULL) {
     974           0 :                         return ENOMEM;
     975             :                 }
     976           2 :                 break;
     977         252 :         default:
     978         252 :                 break;
     979             :         }
     980             : 
     981         256 :         return 0;
     982             : }
     983             : 
     984         252 : static int cstruct_list_to_py_tc_list(PyObject *py_test_list,
     985             :                                       Py_ssize_t num_tests,
     986             :                                       struct pam_testcase *test_list)
     987             : {
     988             :         Py_ssize_t i;
     989         252 :         PyObject *py_test = NULL;
     990             :         int rc;
     991             : 
     992         508 :         for (i = 0; i < num_tests; i++) {
     993         256 :                 py_test = PySequence_GetItem(py_test_list, i);
     994         256 :                 if (py_test == NULL) {
     995           0 :                         return EIO;
     996             :                 }
     997             : 
     998         256 :                 rc = cstruct_to_py_testcase(py_test, &test_list[i]);
     999         128 :                 Py_DECREF(py_test);
    1000         256 :                 if (rc != 0) {
    1001           0 :                         return EIO;
    1002             :                 }
    1003             :         }
    1004             : 
    1005         252 :         return 0;
    1006             : }
    1007             : 
    1008             : PyDoc_STRVAR(RunPamTest__doc__,
    1009             : "Run PAM tests\n\n"
    1010             : "This function runs PAM test cases and reports result\n"
    1011             : "Parameters:\n"
    1012             : "service: The PAM service to use in the conversation (string)\n"
    1013             : "username: The user to run PAM conversation as\n"
    1014             : "test_list: Sequence of pypamtest.TestCase objects\n"
    1015             : "echo_off_list: Sequence of strings that will be used by PAM "
    1016             : "conversation for PAM_PROMPT_ECHO_OFF input. These are typically "
    1017             : "passwords.\n"
    1018             : "echo_on_list: Sequence of strings that will be used by PAM "
    1019             : "conversation for PAM_PROMPT_ECHO_ON input.\n"
    1020             : );
    1021             : 
    1022         252 : static PyObject *pypamtest_run_pamtest(PyObject *module,
    1023             :                                        PyObject *args,
    1024             :                                        PyObject *kwargs)
    1025             : {
    1026             :         int ok;
    1027             :         int rc;
    1028         252 :         char *username = NULL;
    1029         252 :         char *service = NULL;
    1030             :         PyObject *py_test_list;
    1031         252 :         PyObject *py_echo_off = NULL;
    1032         252 :         PyObject *py_echo_on = NULL;
    1033         252 :         PyObject *py_pam_handle = NULL;
    1034             :         Py_ssize_t num_tests;
    1035             :         struct pam_testcase *test_list;
    1036             :         enum pamtest_err perr;
    1037             :         struct pamtest_conv_data conv_data;
    1038         252 :         pam_handle_t *pam_handle = NULL;
    1039         252 :         TestResultObject *result = NULL;
    1040         252 :         const char * const kwnames[] = { "username",
    1041             :                                   "service",
    1042             :                                   "tests",
    1043             :                                   "echo_off",
    1044             :                                   "echo_on",
    1045             :                                   "handle",
    1046             :                                   NULL };
    1047             : 
    1048             :         (void) module;  /* unused */
    1049             : 
    1050         252 :         ok = PyArg_ParseTupleAndKeywords(args,
    1051             :                                          kwargs,
    1052             :                                          discard_const_p(char, "ssO|OOO"),
    1053             :                                          discard_const_p(char *, kwnames),
    1054             :                                          &username,
    1055             :                                          &service,
    1056             :                                          &py_test_list,
    1057             :                                          &py_echo_off,
    1058             :                                          &py_echo_on,
    1059             :                                          &py_pam_handle);
    1060         252 :         if (!ok) {
    1061           0 :                 return NULL;
    1062             :         }
    1063             : 
    1064         252 :         ok = PySequence_Check(py_test_list);
    1065         252 :         if (!ok) {
    1066           0 :                 PyErr_Format(PyExc_TypeError, "tests must be a sequence");
    1067           0 :                 return NULL;
    1068             :         }
    1069             : 
    1070         252 :         num_tests = PySequence_Size(py_test_list);
    1071         252 :         if (num_tests == -1) {
    1072           0 :                 PyErr_Format(PyExc_IOError, "Cannot get sequence length");
    1073           0 :                 return NULL;
    1074             :         }
    1075             : 
    1076         252 :         rc = py_tc_list_to_cstruct_list(py_test_list, num_tests, &test_list);
    1077         252 :         if (rc != 0) {
    1078           0 :                 if (rc == ENOMEM) {
    1079           0 :                         PyErr_NoMemory();
    1080           0 :                         return NULL;
    1081             :                 } else {
    1082           0 :                         PyErr_Format(PyExc_IOError,
    1083             :                                      "Cannot convert test to C structure");
    1084           0 :                         return NULL;
    1085             :                 }
    1086             :         }
    1087             : 
    1088         252 :         rc = fill_conv_data(py_echo_off, py_echo_on, &conv_data);
    1089         252 :         if (rc != 0) {
    1090           0 :                 PyMem_Free(test_list);
    1091           0 :                 PyErr_NoMemory();
    1092           0 :                 return NULL;
    1093             :         }
    1094             : 
    1095         252 :         if (py_pam_handle != NULL) {
    1096           2 :                 pam_handle = (pam_handle_t *)PyCapsule_GetPointer(py_pam_handle,
    1097             :                                                                   NULL);
    1098           2 :                 if (pam_handle == NULL) {
    1099           0 :                         PyMem_Free(test_list);
    1100           0 :                         PyErr_Format(PyExc_IOError,
    1101             :                                      "Failed to get the pam handle pointer");
    1102           0 :                         return NULL;
    1103             :                 }
    1104             :         }
    1105             : 
    1106         252 :         perr = _pamtest(service,
    1107             :                         username,
    1108             :                         &conv_data,
    1109             :                         test_list,
    1110             :                         num_tests,
    1111             :                         pam_handle);
    1112         252 :         if (perr != PAMTEST_ERR_OK) {
    1113           0 :                 free_conv_data(&conv_data);
    1114           0 :                 set_pypamtest_exception(PyExc_PamTestError,
    1115             :                                         perr,
    1116             :                                         test_list,
    1117             :                                         num_tests);
    1118           0 :                 PyMem_Free(test_list);
    1119           0 :                 return NULL;
    1120             :         }
    1121             : 
    1122         252 :         rc = cstruct_list_to_py_tc_list(py_test_list, num_tests, test_list);
    1123         252 :         if (rc != 0) {
    1124           0 :                 if (rc == ENOMEM) {
    1125           0 :                         PyErr_NoMemory();
    1126           0 :                         return NULL;
    1127             :                 } else {
    1128           0 :                         PyErr_Format(PyExc_IOError,
    1129             :                                      "Cannot convert C structure to python");
    1130           0 :                         return NULL;
    1131             :                 }
    1132             :         }
    1133         252 :         PyMem_Free(test_list);
    1134             : 
    1135         252 :         result = construct_test_conv_result(conv_data.out_info,
    1136             :                                             conv_data.out_err);
    1137         252 :         free_conv_data(&conv_data);
    1138         252 :         if (result == NULL) {
    1139           0 :                 PyMem_Free(test_list);
    1140           0 :                 return NULL;
    1141             :         }
    1142             : 
    1143         252 :         return (PyObject *)result;
    1144             : }
    1145             : 
    1146             : static PyMethodDef pypamtest_module_methods[] = {
    1147             :         {
    1148             :                 discard_const_p(char, "run_pamtest"),
    1149             :                 (PyCFunction) pypamtest_run_pamtest,
    1150             :                 METH_VARARGS | METH_KEYWORDS,
    1151             :                 RunPamTest__doc__,
    1152             :         },
    1153             : 
    1154             :         { NULL, NULL, 0, NULL }  /* Sentinel */
    1155             : };
    1156             : 
    1157             : /*
    1158             :  * This is the module structure describing the module and
    1159             :  * to define methods
    1160             :  */
    1161             : #if IS_PYTHON3
    1162             : static struct PyModuleDef pypamtestdef = {
    1163             :         .m_base = PyModuleDef_HEAD_INIT,
    1164             :         .m_name = PYTHON_MODULE_NAME,
    1165             :         .m_size = -1,
    1166             :         .m_methods = pypamtest_module_methods,
    1167             : };
    1168             : #endif
    1169             : 
    1170             : /**********************************************************
    1171             :  *** Initialize the module
    1172             :  **********************************************************/
    1173             : 
    1174             : #if PY_VERSION_HEX >= 0x02070000 /* >= 2.7.0 */
    1175             : PyDoc_STRVAR(PamTestError__doc__,
    1176             : "pypamtest specific exception\n\n"
    1177             : "This exception is raised if the _pamtest() function fails. If _pamtest() "
    1178             : "returns PAMTEST_ERR_CASE (a test case returns unexpected error code), then "
    1179             : "the exception also details which test case failed."
    1180             : );
    1181             : #endif
    1182             : 
    1183             : #if IS_PYTHON3
    1184          98 : PyMODINIT_FUNC PyInit_pypamtest(void)
    1185             : #else
    1186             : PyMODINIT_FUNC initpypamtest(void)
    1187             : #endif
    1188             : {
    1189             :         PyObject *m;
    1190             :         union {
    1191             :                 PyTypeObject *type_obj;
    1192             :                 PyObject *obj;
    1193             :         } pypam_object;
    1194             :         int ret;
    1195             : 
    1196             : #if IS_PYTHON3
    1197          98 :         m = PyModule_Create(&pypamtestdef);
    1198          98 :         if (m == NULL) {
    1199           0 :                 RETURN_ON_ERROR;
    1200             :         }
    1201             : #else
    1202             :         m = Py_InitModule(discard_const_p(char, PYTHON_MODULE_NAME),
    1203             :                           pypamtest_module_methods);
    1204             : #endif
    1205             : 
    1206             : #if PY_VERSION_HEX >= 0x02070000 /* >= 2.7.0 */
    1207          98 :         PyExc_PamTestError = PyErr_NewExceptionWithDoc(discard_const_p(char, "pypamtest.PamTestError"),
    1208             :                                                        PamTestError__doc__,
    1209             :                                                        PyExc_EnvironmentError,
    1210             :                                                        NULL);
    1211             : #else /* < 2.7.0 */
    1212             :         PyExc_PamTestError = PyErr_NewException(discard_const_p(char, "pypamtest.PamTestError"),
    1213             :                                                        PyExc_EnvironmentError,
    1214             :                                                        NULL);
    1215             : #endif
    1216             : 
    1217          98 :         if (PyExc_PamTestError == NULL) {
    1218           0 :                 RETURN_ON_ERROR;
    1219             :         }
    1220             : 
    1221          98 :         Py_INCREF(PyExc_PamTestError);
    1222          98 :         ret = PyModule_AddObject(m, discard_const_p(char, "PamTestError"),
    1223             :                                  PyExc_PamTestError);
    1224          98 :         if (ret == -1) {
    1225           0 :                 RETURN_ON_ERROR;
    1226             :         }
    1227             : 
    1228          98 :         ret = PyModule_AddIntMacro(m, PAMTEST_AUTHENTICATE);
    1229          98 :         if (ret == -1) {
    1230           0 :                 RETURN_ON_ERROR;
    1231             :         }
    1232          98 :         ret = PyModule_AddIntMacro(m, PAMTEST_SETCRED);
    1233          98 :         if (ret == -1) {
    1234           0 :                 RETURN_ON_ERROR;
    1235             :         }
    1236          98 :         ret = PyModule_AddIntMacro(m, PAMTEST_ACCOUNT);
    1237          98 :         if (ret == -1) {
    1238           0 :                 RETURN_ON_ERROR;
    1239             :         }
    1240          98 :         ret = PyModule_AddIntMacro(m, PAMTEST_OPEN_SESSION);
    1241          98 :         if (ret == -1) {
    1242           0 :                 RETURN_ON_ERROR;
    1243             :         }
    1244          98 :         ret = PyModule_AddIntMacro(m, PAMTEST_CLOSE_SESSION);
    1245          98 :         if (ret == -1) {
    1246           0 :                 RETURN_ON_ERROR;
    1247             :         }
    1248          98 :         ret = PyModule_AddIntMacro(m, PAMTEST_CHAUTHTOK);
    1249          98 :         if (ret == -1) {
    1250           0 :                 RETURN_ON_ERROR;
    1251             :         }
    1252             : 
    1253          98 :         ret = PyModule_AddIntMacro(m, PAMTEST_GETENVLIST);
    1254          98 :         if (ret == -1) {
    1255           0 :                 RETURN_ON_ERROR;
    1256             :         }
    1257          98 :         ret = PyModule_AddIntMacro(m, PAMTEST_KEEPHANDLE);
    1258          98 :         if (ret == -1) {
    1259           0 :                 RETURN_ON_ERROR;
    1260             :         }
    1261             : 
    1262          98 :         ret = PyModule_AddIntConstant(m,
    1263             :                                       "PAMTEST_FLAG_DELETE_CRED",
    1264             :                                       PAM_DELETE_CRED);
    1265          98 :         if (ret == -1) {
    1266           0 :                 RETURN_ON_ERROR;
    1267             :         }
    1268             : 
    1269          98 :         ret = PyModule_AddIntConstant(m,
    1270             :                                       "PAMTEST_FLAG_ESTABLISH_CRED",
    1271             :                                       PAM_ESTABLISH_CRED);
    1272          98 :         if (ret == -1) {
    1273           0 :                 RETURN_ON_ERROR;
    1274             :         }
    1275             : 
    1276          98 :         ret = PyModule_AddIntConstant(m,
    1277             :                                       "PAMTEST_FLAG_REINITIALIZE_CRED",
    1278             :                                       PAM_REINITIALIZE_CRED);
    1279          98 :         if (ret == -1) {
    1280           0 :                 RETURN_ON_ERROR;
    1281             :         }
    1282             : 
    1283          98 :         ret = PyModule_AddIntConstant(m,
    1284             :                                       "PAMTEST_FLAG_REFRESH_CRED",
    1285             :                                       PAM_REFRESH_CRED);
    1286          98 :         if (ret == -1) {
    1287           0 :                 RETURN_ON_ERROR;
    1288             :         }
    1289             : 
    1290          98 :         pypam_object.type_obj = &pypamtest_test_case;
    1291          98 :         if (PyType_Ready(pypam_object.type_obj) < 0) {
    1292           0 :                 RETURN_ON_ERROR;
    1293             :         }
    1294          98 :         Py_INCREF(pypam_object.obj);
    1295          98 :         PyModule_AddObject(m, "TestCase", pypam_object.obj);
    1296             : 
    1297          98 :         pypam_object.type_obj = &pypamtest_test_result;
    1298          98 :         if (PyType_Ready(pypam_object.type_obj) < 0) {
    1299           0 :                 RETURN_ON_ERROR;
    1300             :         }
    1301          98 :         Py_INCREF(pypam_object.obj);
    1302          98 :         PyModule_AddObject(m, "TestResult", pypam_object.obj);
    1303             : 
    1304             : #if IS_PYTHON3
    1305          98 :         return m;
    1306             : #endif
    1307             : }

Generated by: LCOV version 1.14