LCOV - code coverage report
Current view: top level - python - pyhbac.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 590 740 79.7 %
Date: 2016-06-29 Functions: 61 64 95.3 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Jakub Hrozek <jhrozek@redhat.com>
       4             : 
       5             :     Copyright (C) 2011 Red Hat
       6             : 
       7             :     This program is free software; you can redistribute it and/or modify
       8             :     it under the terms of the GNU General Public License as published by
       9             :     the Free Software Foundation; either version 3 of the License, or
      10             :     (at your option) any later version.
      11             : 
      12             :     This program is distributed in the hope that it will be useful,
      13             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :     GNU General Public License for more details.
      16             : 
      17             :     You should have received a copy of the GNU General Public License
      18             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include <Python.h>
      22             : #include <structmember.h>
      23             : 
      24             : #include "util/util.h"
      25             : #include "util/sss_python.h"
      26             : #include "lib/ipa_hbac/ipa_hbac.h"
      27             : 
      28             : #define PYTHON_MODULE_NAME  "pyhbac"
      29             : 
      30             : #ifndef PYHBAC_ENCODING
      31             : #define PYHBAC_ENCODING "UTF-8"
      32             : #endif
      33             : 
      34             : #define PYHBAC_ENCODING_ERRORS "strict"
      35             : 
      36             : #define CHECK_ATTRIBUTE_DELETE(attr, attrname) do {         \
      37             :     if (attr == NULL) {                                     \
      38             :         PyErr_Format(PyExc_TypeError,                       \
      39             :                      "Cannot delete the %s attribute",      \
      40             :                       attrname);                            \
      41             :         return -1;                                          \
      42             :     }                                                       \
      43             : } while(0)
      44             : 
      45             : static PyObject *PyExc_HbacError;
      46             : 
      47             : /* ==================== Utility functions ========================*/
      48             : static char *
      49         174 : py_strdup(const char *string)
      50             : {
      51             :     char *copy;
      52             : 
      53         174 :     copy = PyMem_New(char, strlen(string)+1);
      54         174 :     if (copy ==  NULL) {
      55           0 :         PyErr_NoMemory();
      56           0 :         return NULL;
      57             :     }
      58             : 
      59         174 :     return strcpy(copy, string);
      60             : }
      61             : 
      62             : static char *
      63           4 : py_strcat_realloc(char *first, const char *second)
      64             : {
      65             :     char *new_first;
      66           4 :     new_first = PyMem_Realloc(first, strlen(first) + strlen(second) + 1);
      67           4 :     if (new_first == NULL) {
      68           0 :         PyErr_NoMemory();
      69           0 :         return NULL;
      70             :     }
      71             : 
      72           4 :     return strcat(new_first, second);
      73             : }
      74             : 
      75             : static PyObject *
      76         128 : get_utf8_string(PyObject *obj, const char *attrname)
      77             : {
      78         128 :     const char *a = attrname ? attrname : "attribute";
      79         128 :     PyObject *obj_utf8 = NULL;
      80             : 
      81         128 :     if (PyBytes_Check(obj)) {
      82          64 :         obj_utf8 = obj;
      83          64 :         Py_INCREF(obj_utf8); /* Make sure we can DECREF later */
      84          64 :     } else if (PyUnicode_Check(obj)) {
      85          64 :         if ((obj_utf8 = PyUnicode_AsUTF8String(obj)) == NULL) {
      86             :             return NULL;
      87             :         }
      88             :     } else {
      89           0 :         PyErr_Format(PyExc_TypeError, "%s must be a string", a);
      90           0 :         return NULL;
      91             :     }
      92             : 
      93         128 :     return obj_utf8;
      94             : }
      95             : 
      96             : static void
      97         182 : free_string_list(const char **list)
      98             : {
      99             :     int i;
     100             : 
     101         364 :     if (!list) return;
     102             : 
     103          64 :     for (i=0; list[i]; i++) {
     104          64 :         PyMem_Free(discard_const_p(char, list[i]));
     105             :     }
     106         182 :     PyMem_Free(list);
     107             : }
     108             : 
     109             : static const char **
     110         182 : sequence_as_string_list(PyObject *seq, const char *paramname)
     111             : {
     112         182 :     const char *p = paramname ? paramname : "attribute values";
     113             :     const char **ret;
     114             :     PyObject *utf_item;
     115             :     int i;
     116             :     Py_ssize_t len;
     117             :     PyObject *item;
     118             : 
     119         182 :     if (!PySequence_Check(seq)) {
     120           0 :         PyErr_Format(PyExc_TypeError,
     121             :                      "The object must be a sequence\n");
     122           0 :         return NULL;
     123             :     }
     124             : 
     125         182 :     len = PySequence_Size(seq);
     126         182 :     if (len == -1) return NULL;
     127             : 
     128         182 :     ret = PyMem_New(const char *, (len+1));
     129         182 :     if (!ret) {
     130           0 :         PyErr_NoMemory();
     131           0 :         return NULL;
     132             :     }
     133             : 
     134          64 :     for (i = 0; i < len; i++) {
     135          64 :         item = PySequence_GetItem(seq, i);
     136          64 :         if (item == NULL) {
     137             :             break;
     138             :         }
     139             : 
     140          64 :         utf_item = get_utf8_string(item, p);
     141          64 :         if (utf_item == NULL) {
     142           0 :             Py_DECREF(item);
     143             :             return NULL;
     144             :         }
     145             : 
     146          64 :         ret[i] = py_strdup(PyBytes_AsString(utf_item));
     147          64 :         Py_DECREF(utf_item);
     148          64 :         if (!ret[i]) {
     149           0 :             Py_DECREF(item);
     150             :             return NULL;
     151             :         }
     152          64 :         Py_DECREF(item);
     153             :     }
     154             : 
     155         182 :     ret[i] = NULL;
     156         182 :     return ret;
     157             : }
     158             : 
     159             : static bool
     160          82 : verify_sequence(PyObject *seq, const char *attrname)
     161             : {
     162          82 :     const char *a = attrname ? attrname : "attribute";
     163             : 
     164          82 :     if (!PySequence_Check(seq)) {
     165           8 :         PyErr_Format(PyExc_TypeError, "%s must be a sequence", a);
     166           8 :         return false;
     167             :     }
     168             : 
     169             :     return true;
     170             : }
     171             : 
     172             : static int
     173         106 : pyobject_to_category(PyObject *o)
     174             : {
     175             :     long c;
     176             : 
     177         106 :     c = PYNUMBER_ASLONG(o);
     178         106 :     if (c == -1 && PyErr_Occurred()) {
     179           0 :         PyErr_Format(PyExc_TypeError,
     180             :                      "Invalid type for category element - must be an int\n");
     181           0 :         return -1;
     182             :     }
     183             : 
     184         106 :     switch (c) {
     185             :         case HBAC_CATEGORY_NULL:
     186             :         case HBAC_CATEGORY_ALL:
     187         104 :             return c;
     188             :     }
     189             : 
     190           2 :     PyErr_Format(PyExc_ValueError, "Invalid value %ld for category\n", c);
     191           2 :     return -1;
     192             : }
     193             : 
     194             : static int
     195          96 : native_category(PyObject *pycat, uint32_t *_category)
     196             : {
     197             :     PyObject *iterator;
     198             :     PyObject *item;
     199             :     uint32_t cat;
     200             :     int ret;
     201             : 
     202          96 :     iterator = PyObject_GetIter(pycat);
     203          96 :     if (iterator == NULL) {
     204           0 :         PyErr_Format(PyExc_RuntimeError, "Cannot iterate category\n");
     205           0 :         return -1;
     206             :     }
     207             : 
     208             :     cat = 0;
     209         196 :     while ((item = PyIter_Next(iterator))) {
     210         102 :         ret = pyobject_to_category(item);
     211         102 :         Py_DECREF(item);
     212         102 :         if (ret == -1) {
     213           2 :             Py_DECREF(iterator);
     214             :             return -1;
     215             :         }
     216             : 
     217         100 :         cat |= ret;
     218             :     }
     219             : 
     220          94 :     Py_DECREF(iterator);
     221             : 
     222          94 :     *_category = cat;
     223          94 :     return 0;
     224             : }
     225             : 
     226             : static char *
     227          60 : str_concat_sequence(PyObject *seq, const char *delim)
     228             : {
     229             :     Py_ssize_t size;
     230             :     Py_ssize_t i;
     231             :     PyObject *item;
     232          60 :     char *s = NULL;
     233             :     char *part;
     234             : 
     235          60 :     size = PySequence_Size(seq);
     236             : 
     237          60 :     if (size == 0) {
     238          46 :         s = py_strdup("");
     239          46 :         if (s == NULL) {
     240             :             return NULL;
     241             :         }
     242          46 :         return s;
     243             :     }
     244             : 
     245          16 :     for (i=0; i < size; i++) {
     246          16 :         item = PySequence_GetItem(seq, i);
     247          16 :         if (item == NULL) goto fail;
     248             : 
     249             : #ifdef IS_PY3K
     250           8 :         part = PyUnicode_AsUTF8(item);
     251             : #else
     252           8 :         part = PyString_AsString(item);
     253             : #endif
     254             : 
     255          16 :         if (s) {
     256           2 :             s = py_strcat_realloc(s, delim);
     257           2 :             if (s == NULL) goto fail;
     258           2 :             s = py_strcat_realloc(s, part);
     259           2 :             if (s == NULL) goto fail;
     260             :         } else {
     261          14 :             s = py_strdup(part);
     262          14 :             if (s == NULL) goto fail;
     263             :         }
     264          16 :         Py_DECREF(item);
     265             :     }
     266             : 
     267             :     return s;
     268             : 
     269             : fail:
     270           0 :     Py_XDECREF(item);
     271           0 :     PyMem_Free(s);
     272           0 :     return NULL;
     273             : }
     274             : 
     275             : /* ================= HBAC Exception handling =====================*/
     276             : static void
     277           0 : set_hbac_exception(PyObject *exc, struct hbac_info *error)
     278             : {
     279             :     PyObject *obj;
     280             : 
     281           0 :     obj = Py_BuildValue(sss_py_const_p(char, "(i,s)"), error->code,
     282           0 :                         error->rule_name ? error->rule_name : "no rule");
     283             : 
     284           0 :     PyErr_SetObject(exc, obj);
     285           0 :     Py_XDECREF(obj);
     286           0 : }
     287             : 
     288             : /* ==================== HBAC Rule Element ========================*/
     289             : typedef struct {
     290             :     PyObject_HEAD
     291             : 
     292             :     PyObject *category;
     293             :     PyObject *names;
     294             :     PyObject *groups;
     295             : } HbacRuleElement;
     296             : 
     297             : static PyObject *
     298         106 : HbacRuleElement_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     299             : {
     300             :     HbacRuleElement *self;
     301             : 
     302         106 :     self = (HbacRuleElement *) type->tp_alloc(type, 0);
     303         106 :     if (self == NULL) {
     304           0 :         PyErr_NoMemory();
     305           0 :         return NULL;
     306             :     }
     307             : 
     308         106 :     self->category = PySet_New(NULL);
     309         106 :     self->names = PyList_New(0);
     310         106 :     self->groups = PyList_New(0);
     311         106 :     if (!self->names || !self->groups || !self->category) {
     312           0 :         Py_DECREF(self);
     313           0 :         PyErr_NoMemory();
     314           0 :         return NULL;
     315             :     }
     316             : 
     317             :     return (PyObject *) self;
     318             : }
     319             : 
     320             : static int
     321          92 : HbacRuleElement_clear(HbacRuleElement *self)
     322             : {
     323          92 :     Py_CLEAR(self->names);
     324          92 :     Py_CLEAR(self->groups);
     325          92 :     Py_CLEAR(self->category);
     326          92 :     return 0;
     327             : }
     328             : 
     329             : static void
     330          92 : HbacRuleElement_dealloc(HbacRuleElement *self)
     331             : {
     332          92 :     HbacRuleElement_clear(self);
     333          92 :     Py_TYPE(self)->tp_free((PyObject*) self);
     334          92 : }
     335             : 
     336             : static int
     337          40 : HbacRuleElement_traverse(HbacRuleElement *self, visitproc visit, void *arg)
     338             : {
     339          40 :     Py_VISIT(self->groups);
     340          40 :     Py_VISIT(self->names);
     341          40 :     Py_VISIT(self->category);
     342             :     return 0;
     343             : }
     344             : 
     345             : static int
     346             : hbac_rule_element_set_names(HbacRuleElement *self, PyObject *names,
     347             :                             void *closure);
     348             : static int
     349             : hbac_rule_element_set_groups(HbacRuleElement *self, PyObject *groups,
     350             :                              void *closure);
     351             : static int
     352             : hbac_rule_element_set_category(HbacRuleElement *self, PyObject *category,
     353             :                                void *closure);
     354             : 
     355             : static int
     356         106 : HbacRuleElement_init(HbacRuleElement *self, PyObject *args, PyObject *kwargs)
     357             : {
     358         106 :     const char * const kwlist[] = { "names", "groups", "category", NULL };
     359         106 :     PyObject *names = NULL;
     360         106 :     PyObject *groups = NULL;
     361         106 :     PyObject *category = NULL;
     362         106 :     PyObject *tmp = NULL;
     363             : 
     364         106 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
     365             :                                      sss_py_const_p(char, "|OOO"),
     366             :                                      discard_const_p(char *, kwlist),
     367             :                                      &names, &groups, &category)) {
     368         106 :         return -1;
     369             :     }
     370             : 
     371         106 :     if (names) {
     372          12 :         if (hbac_rule_element_set_names(self, names, NULL) != 0) {
     373             :             return -1;
     374             :         }
     375             :     }
     376             : 
     377         102 :     if (groups) {
     378           8 :         if (hbac_rule_element_set_groups(self, groups, NULL) != 0) {
     379             :             return -1;
     380             :         }
     381             :     }
     382             : 
     383         102 :     if (category) {
     384           0 :         if (hbac_rule_element_set_category(self, category, NULL) != 0) {
     385             :             return -1;
     386             :         }
     387             :     } else {
     388         102 :         tmp = PYNUMBER_FROMLONG(HBAC_CATEGORY_NULL);
     389         102 :         if (!tmp) {
     390             :             return -1;
     391             :         }
     392             : 
     393         102 :         if (PySet_Add(self->category, tmp) != 0) {
     394           0 :             Py_DECREF(tmp);
     395             :             return -1;
     396             :         }
     397             :     }
     398             : 
     399             :     return 0;
     400             : }
     401             : 
     402             : static int
     403          50 : hbac_rule_element_set_names(HbacRuleElement *self,
     404             :                             PyObject *names,
     405             :                             void *closure)
     406             : {
     407          50 :     CHECK_ATTRIBUTE_DELETE(names, "names");
     408             : 
     409          50 :     if (!verify_sequence(names, "names")) {
     410             :         return -1;
     411             :     }
     412             : 
     413          46 :     SAFE_SET(self->names, names);
     414             :     return 0;
     415             : }
     416             : 
     417             : static PyObject *
     418          20 : hbac_rule_element_get_names(HbacRuleElement *self, void *closure)
     419             : {
     420          20 :     Py_INCREF(self->names);
     421          20 :     return self->names;
     422             : }
     423             : 
     424             : static int
     425          16 : hbac_rule_element_set_groups(HbacRuleElement *self,
     426             :                              PyObject *groups,
     427             :                              void *closure)
     428             : {
     429          16 :     CHECK_ATTRIBUTE_DELETE(groups, "groups");
     430             : 
     431          16 :     if (!verify_sequence(groups, "groups")) {
     432             :         return -1;
     433             :     }
     434             : 
     435          16 :     SAFE_SET(self->groups, groups);
     436             :     return 0;
     437             : }
     438             : 
     439             : static PyObject *
     440          24 : hbac_rule_element_get_groups(HbacRuleElement *self, void *closure)
     441             : {
     442          24 :     Py_INCREF(self->groups);
     443          24 :     return self->groups;
     444             : }
     445             : 
     446             : static int
     447          10 : hbac_rule_element_set_category(HbacRuleElement *self,
     448             :                                PyObject *category,
     449             :                                void *closure)
     450             : {
     451             :     PyObject *iterator;
     452             :     PyObject *item;
     453             :     int ret;
     454             : 
     455          10 :     CHECK_ATTRIBUTE_DELETE(category, "category");
     456             : 
     457          10 :     if (!PySet_Check(category)) {
     458           6 :         PyErr_Format(PyExc_TypeError, "The category must be a set type\n");
     459           6 :         return -1;
     460             :     }
     461             : 
     462             :     /* Check the values, too */
     463           4 :     iterator = PyObject_GetIter(category);
     464           4 :     if (iterator == NULL) {
     465           0 :         PyErr_Format(PyExc_RuntimeError, "Cannot iterate a set?\n");
     466           0 :         return -1;
     467             :     }
     468             : 
     469           8 :     while ((item = PyIter_Next(iterator))) {
     470           4 :         ret = pyobject_to_category(item);
     471           4 :         Py_DECREF(item);
     472           4 :         if (ret == -1) {
     473           0 :             Py_DECREF(iterator);
     474             :             return -1;
     475             :         }
     476             :     }
     477             : 
     478           4 :     SAFE_SET(self->category, category);
     479           4 :     Py_DECREF(iterator);
     480             :     return 0;
     481             : }
     482             : 
     483             : static PyObject *
     484          20 : hbac_rule_element_get_category(HbacRuleElement *self, void *closure)
     485             : {
     486          20 :     Py_INCREF(self->category);
     487          20 :     return self->category;
     488             : }
     489             : 
     490             : static PyObject *
     491          20 : HbacRuleElement_repr(HbacRuleElement *self)
     492             : {
     493          20 :     char *strnames = NULL;
     494          20 :     char *strgroups = NULL;
     495             :     uint32_t category;
     496             :     int ret;
     497             :     PyObject *o, *format, *args;
     498             : 
     499          20 :     format = PyUnicode_FromString("<category %lu names [%s] groups [%s]>");
     500          20 :     if (format == NULL) {
     501          20 :         return NULL;
     502             :     }
     503             : 
     504          20 :     strnames = str_concat_sequence(self->names,
     505             :                                    discard_const_p(char, ","));
     506          20 :     strgroups = str_concat_sequence(self->groups,
     507             :                                     discard_const_p(char, ","));
     508          20 :     ret = native_category(self->category, &category);
     509          20 :     if (strnames == NULL || strgroups == NULL || ret == -1) {
     510           0 :         PyMem_Free(strnames);
     511           0 :         PyMem_Free(strgroups);
     512           0 :         Py_DECREF(format);
     513             :         return NULL;
     514             :     }
     515             : 
     516          20 :     args = Py_BuildValue(sss_py_const_p(char, "Kss"),
     517             :                          (unsigned long long ) category,
     518             :                          strnames, strgroups);
     519          20 :     if (args == NULL) {
     520           0 :         PyMem_Free(strnames);
     521           0 :         PyMem_Free(strgroups);
     522           0 :         Py_DECREF(format);
     523             :         return NULL;
     524             :     }
     525             : 
     526          20 :     o = PyUnicode_Format(format, args);
     527          20 :     PyMem_Free(strnames);
     528          20 :     PyMem_Free(strgroups);
     529          20 :     Py_DECREF(format);
     530          20 :     Py_DECREF(args);
     531          20 :     return o;
     532             : }
     533             : 
     534             : PyDoc_STRVAR(HbacRuleElement_names__doc__,
     535             : "(sequence of strings) A list of object names this element applies to");
     536             : PyDoc_STRVAR(HbacRuleElement_groups__doc__,
     537             : "(sequence of strings) A list of group names this element applies to");
     538             : PyDoc_STRVAR(HbacRuleElement_category__doc__,
     539             : "(set) A set of categories this rule falls into");
     540             : 
     541             : static PyGetSetDef py_hbac_rule_element_getset[] = {
     542             :     { discard_const_p(char, "names"),
     543             :       (getter) hbac_rule_element_get_names,
     544             :       (setter) hbac_rule_element_set_names,
     545             :       HbacRuleElement_names__doc__,
     546             :       NULL },
     547             : 
     548             :     { discard_const_p(char, "groups"),
     549             :       (getter) hbac_rule_element_get_groups,
     550             :       (setter) hbac_rule_element_set_groups,
     551             :       HbacRuleElement_groups__doc__,
     552             :       NULL },
     553             : 
     554             :     { discard_const_p(char, "category"),
     555             :       (getter) hbac_rule_element_get_category,
     556             :       (setter) hbac_rule_element_set_category,
     557             :       HbacRuleElement_category__doc__,
     558             :       NULL },
     559             : 
     560             :     { NULL, 0, 0, 0, NULL } /* Sentinel */
     561             : };
     562             : 
     563             : PyDoc_STRVAR(HbacRuleElement__doc__,
     564             : "IPA HBAC Rule Element\n\n"
     565             : "HbacRuleElement() -> new empty rule element\n"
     566             : "HbacRuleElement([names], [groups], [category]) -> optionally, provide\n"
     567             : "names and/or groups and/or category\n");
     568             : 
     569             : static PyTypeObject pyhbac_hbacrule_element_type = {
     570             :     PyVarObject_HEAD_INIT(NULL, 0)
     571             :     .tp_name = sss_py_const_p(char, "pyhbac.HbacRuleElement"),
     572             :     .tp_basicsize = sizeof(HbacRuleElement),
     573             :     .tp_new = HbacRuleElement_new,
     574             :     .tp_dealloc = (destructor) HbacRuleElement_dealloc,
     575             :     .tp_traverse = (traverseproc) HbacRuleElement_traverse,
     576             :     .tp_clear = (inquiry) HbacRuleElement_clear,
     577             :     .tp_init = (initproc) HbacRuleElement_init,
     578             :     .tp_repr = (reprfunc) HbacRuleElement_repr,
     579             :     .tp_getset = py_hbac_rule_element_getset,
     580             :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
     581             :     .tp_doc   = HbacRuleElement__doc__
     582             : };
     583             : 
     584             : static void
     585          86 : free_hbac_rule_element(struct hbac_rule_element *el)
     586             : {
     587         172 :     if (!el) return;
     588             : 
     589          76 :     free_string_list(el->names);
     590          76 :     free_string_list(el->groups);
     591          76 :     PyMem_Free(el);
     592             : }
     593             : 
     594             : struct hbac_rule_element *
     595          80 : HbacRuleElement_to_native(HbacRuleElement *pyel)
     596             : {
     597          80 :     struct hbac_rule_element *el = NULL;
     598             :     int ret;
     599             : 
     600             :     /* check the type, None would wreak havoc here because for some reason
     601             :      * it would pass the sequence check */
     602          80 :     if (!PyObject_IsInstance((PyObject *) pyel,
     603             :                              (PyObject *) &pyhbac_hbacrule_element_type)) {
     604           4 :         PyErr_Format(PyExc_TypeError,
     605             :                      "The element must be of type HbacRuleElement\n");
     606           4 :         goto fail;
     607             :     }
     608             : 
     609          76 :     el = PyMem_Malloc(sizeof(struct hbac_rule_element));
     610          76 :     if (!el) {
     611           0 :         PyErr_NoMemory();
     612           0 :         goto fail;
     613             :     }
     614             : 
     615          76 :     ret = native_category(pyel->category, &el->category);
     616          76 :     el->names = sequence_as_string_list(pyel->names, "names");
     617          76 :     el->groups = sequence_as_string_list(pyel->groups, "groups");
     618          76 :     if (!el->names || !el->groups || ret == -1) {
     619             :         goto fail;
     620             :     }
     621             : 
     622             :     return el;
     623             : 
     624             : fail:
     625           6 :     free_hbac_rule_element(el);
     626           6 :     return NULL;
     627             : }
     628             : 
     629             : /* ==================== HBAC Rule ========================*/
     630             : typedef struct {
     631             :     PyObject_HEAD
     632             : 
     633             :     PyObject *name;
     634             :     bool enabled;
     635             : 
     636             :     HbacRuleElement *users;
     637             :     HbacRuleElement *services;
     638             :     HbacRuleElement *targethosts;
     639             :     HbacRuleElement *srchosts;
     640             : } HbacRuleObject;
     641             : 
     642             : static void
     643             : free_hbac_rule(struct hbac_rule *rule);
     644             : static struct hbac_rule *
     645             : HbacRule_to_native(HbacRuleObject *pyrule);
     646             : 
     647             : static PyObject *
     648          20 : HbacRule_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     649             : {
     650             :     HbacRuleObject *self;
     651             : 
     652          20 :     self = (HbacRuleObject *) type->tp_alloc(type, 0);
     653          20 :     if (self == NULL) {
     654           0 :         PyErr_NoMemory();
     655           0 :         return NULL;
     656             :     }
     657             : 
     658          20 :     self->name = PyUnicode_FromString("");
     659          20 :     if (self->name == NULL) {
     660           0 :         Py_DECREF(self);
     661           0 :         PyErr_NoMemory();
     662           0 :         return NULL;
     663             :     }
     664             : 
     665          20 :     self->enabled = false;
     666             : 
     667          20 :     self->services = (HbacRuleElement *) HbacRuleElement_new(
     668             :                                                 &pyhbac_hbacrule_element_type,
     669             :                                                 NULL, NULL);
     670          20 :     self->users = (HbacRuleElement *) HbacRuleElement_new(
     671             :                                                 &pyhbac_hbacrule_element_type,
     672             :                                                 NULL, NULL);
     673          20 :     self->targethosts = (HbacRuleElement *) HbacRuleElement_new(
     674             :                                                 &pyhbac_hbacrule_element_type,
     675             :                                                 NULL, NULL);
     676          20 :     self->srchosts = (HbacRuleElement *) HbacRuleElement_new(
     677             :                                                 &pyhbac_hbacrule_element_type,
     678             :                                                 NULL, NULL);
     679          40 :     if (self->services == NULL || self->users == NULL ||
     680          40 :         self->targethosts == NULL || self->srchosts == NULL) {
     681           0 :         Py_XDECREF(self->services);
     682           0 :         Py_XDECREF(self->users);
     683           0 :         Py_XDECREF(self->targethosts);
     684           0 :         Py_XDECREF(self->srchosts);
     685           0 :         Py_DECREF(self->name);
     686           0 :         Py_DECREF(self);
     687           0 :         PyErr_NoMemory();
     688           0 :         return NULL;
     689             :     }
     690             : 
     691             :     return (PyObject *) self;
     692             : }
     693             : 
     694             : static int
     695          16 : HbacRule_clear(HbacRuleObject *self)
     696             : {
     697          16 :     Py_CLEAR(self->name);
     698          16 :     Py_CLEAR(self->services);
     699          16 :     Py_CLEAR(self->users);
     700          16 :     Py_CLEAR(self->targethosts);
     701          16 :     Py_CLEAR(self->srchosts);
     702          16 :     return 0;
     703             : }
     704             : 
     705             : static void
     706          16 : HbacRule_dealloc(HbacRuleObject *self)
     707             : {
     708          16 :     HbacRule_clear(self);
     709          16 :     Py_TYPE(self)->tp_free((PyObject*) self);
     710          16 : }
     711             : 
     712             : static int
     713          12 : HbacRule_traverse(HbacRuleObject *self, visitproc visit, void *arg)
     714             : {
     715          12 :     Py_VISIT((PyObject *) self->name);
     716          12 :     Py_VISIT((PyObject *) self->services);
     717          12 :     Py_VISIT((PyObject *) self->users);
     718          12 :     Py_VISIT((PyObject *) self->targethosts);
     719          12 :     Py_VISIT((PyObject *) self->srchosts);
     720             :     return 0;
     721             : }
     722             : 
     723             : static int
     724             : hbac_rule_set_enabled(HbacRuleObject *self, PyObject *enabled, void *closure);
     725             : static int
     726             : hbac_rule_set_name(HbacRuleObject *self, PyObject *name, void *closure);
     727             : 
     728             : static int
     729          20 : HbacRule_init(HbacRuleObject *self, PyObject *args, PyObject *kwargs)
     730             : {
     731          20 :     const char * const kwlist[] = { "name", "enabled", NULL };
     732          20 :     PyObject *name = NULL;
     733          20 :     PyObject *empty_tuple = NULL;
     734          20 :     PyObject *enabled=NULL;
     735             : 
     736          20 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
     737             :                                      sss_py_const_p(char, "O|O"),
     738             :                                      discard_const_p(char *, kwlist),
     739             :                                      &name, &enabled)) {
     740          20 :         return -1;
     741             :     }
     742             : 
     743          20 :     if (enabled) {
     744           4 :         if (hbac_rule_set_enabled(self, enabled, NULL) == -1) {
     745             :             return -1;
     746             :         }
     747             :     }
     748             : 
     749          20 :     if (hbac_rule_set_name(self, name, NULL) == -1) {
     750             :         return -1;
     751             :     }
     752             : 
     753          20 :     empty_tuple = PyTuple_New(0);
     754          20 :     if (!empty_tuple) {
     755             :         return -1;
     756             :     }
     757             : 
     758          40 :     if (HbacRuleElement_init(self->users, empty_tuple, NULL) == -1 ||
     759          40 :         HbacRuleElement_init(self->services, empty_tuple, NULL) == -1 ||
     760          40 :         HbacRuleElement_init(self->targethosts, empty_tuple, NULL) == -1 ||
     761          20 :         HbacRuleElement_init(self->srchosts, empty_tuple, NULL) == -1) {
     762           0 :         Py_DECREF(empty_tuple);
     763             :         return -1;
     764             :     }
     765             : 
     766          20 :     Py_DECREF(empty_tuple);
     767             :     return 0;
     768             : }
     769             : 
     770             : static int
     771          32 : hbac_rule_set_enabled(HbacRuleObject *self, PyObject *enabled, void *closure)
     772             : {
     773          32 :     CHECK_ATTRIBUTE_DELETE(enabled, "enabled");
     774             : 
     775          32 :     if (PyBytes_Check(enabled) || PyUnicode_Check(enabled)) {
     776             :         PyObject *utf8_str;
     777             :         char *str;
     778             : 
     779          14 :         utf8_str = get_utf8_string(enabled, "enabled");
     780          14 :         if (!utf8_str) return -1;
     781          14 :         str = PyBytes_AsString(utf8_str);
     782          14 :         if (!str) {
     783           0 :             Py_DECREF(utf8_str);
     784             :             return -1;
     785             :         }
     786             : 
     787          14 :         if (strcasecmp(str, "true") == 0) {
     788           6 :             self->enabled = true;
     789           8 :         } else if (strcasecmp(str, "false") == 0) {
     790           6 :             self->enabled = false;
     791             :         } else {
     792           2 :             PyErr_Format(PyExc_ValueError,
     793             :                          "enabled only accepts 'true' of 'false' "
     794             :                          "string literals");
     795           2 :             Py_DECREF(utf8_str);
     796             :             return -1;
     797             :         }
     798             : 
     799          12 :         Py_DECREF(utf8_str);
     800             :         return 0;
     801          18 :     } else if (PyBool_Check(enabled) == true) {
     802           8 :         self->enabled = (enabled == Py_True);
     803           8 :         return 0;
     804          10 :     } else if (PYNUMBER_CHECK(enabled)) {
     805           6 :         switch(PYNUMBER_ASLONG(enabled)) {
     806             :             case 0:
     807           2 :                 self->enabled = false;
     808           2 :                 break;
     809             :             case 1:
     810           2 :                 self->enabled = true;
     811           2 :                 break;
     812             :             default:
     813           2 :                 PyErr_Format(PyExc_ValueError,
     814             :                             "enabled only accepts '0' of '1' "
     815             :                             "integer constants");
     816           2 :                 return -1;
     817             :         }
     818             :         return 0;
     819             :     }
     820             : 
     821           4 :     PyErr_Format(PyExc_TypeError, "enabled must be a boolean, an integer "
     822             :                                   "1 or 0 or a string constant true/false");
     823           4 :     return -1;
     824             : 
     825             : }
     826             : 
     827             : static PyObject *
     828          20 : hbac_rule_get_enabled(HbacRuleObject *self, void *closure)
     829             : {
     830          20 :     if (self->enabled) {
     831          10 :         Py_RETURN_TRUE;
     832             :     }
     833             : 
     834          10 :     Py_RETURN_FALSE;
     835             : }
     836             : 
     837             : static int
     838          22 : hbac_rule_set_name(HbacRuleObject *self, PyObject *name, void *closure)
     839             : {
     840          22 :     CHECK_ATTRIBUTE_DELETE(name, "name");
     841             : 
     842          22 :     if (!PyBytes_Check(name) && !PyUnicode_Check(name)) {
     843           0 :         PyErr_Format(PyExc_TypeError, "name must be a string or Unicode");
     844           0 :         return -1;
     845             :     }
     846             : 
     847          22 :     SAFE_SET(self->name, name);
     848             :     return 0;
     849             : }
     850             : 
     851             : static PyObject *
     852           4 : hbac_rule_get_name(HbacRuleObject *self, void *closure)
     853             : {
     854           4 :     if (PyUnicode_Check(self->name)) {
     855           2 :         Py_INCREF(self->name);
     856           2 :         return self->name;
     857           2 :     } else if (PyBytes_Check(self->name)) {
     858           2 :         return PyUnicode_FromEncodedObject(self->name,
     859             :                                            PYHBAC_ENCODING, PYHBAC_ENCODING_ERRORS);
     860             :     }
     861             : 
     862             :     /* setter does typechecking but let us be paranoid */
     863           0 :     PyErr_Format(PyExc_TypeError, "name must be a string or Unicode");
     864           0 :     return NULL;
     865             : }
     866             : 
     867             : static PyObject *
     868           4 : HbacRule_repr(HbacRuleObject *self)
     869             : {
     870             :     PyObject *users_repr;
     871             :     PyObject *services_repr;
     872             :     PyObject *targethosts_repr;
     873             :     PyObject *srchosts_repr;
     874             :     PyObject *o, *format, *args;
     875             : 
     876           4 :     format = PyUnicode_FromString("<name %s enabled %d "
     877             :                                             "users %s services %s "
     878             :                                             "targethosts %s srchosts %s>");
     879           4 :     if (format == NULL) {
     880             :         return NULL;
     881             :     }
     882             : 
     883           4 :     users_repr = HbacRuleElement_repr(self->users);
     884           4 :     services_repr = HbacRuleElement_repr(self->services);
     885           4 :     targethosts_repr = HbacRuleElement_repr(self->targethosts);
     886           4 :     srchosts_repr = HbacRuleElement_repr(self->srchosts);
     887           4 :     if (users_repr == NULL || services_repr == NULL ||
     888           4 :         targethosts_repr == NULL || srchosts_repr == NULL) {
     889           0 :         Py_XDECREF(users_repr);
     890           0 :         Py_XDECREF(services_repr);
     891           0 :         Py_XDECREF(targethosts_repr);
     892           0 :         Py_XDECREF(srchosts_repr);
     893           0 :         Py_DECREF(format);
     894             :         return NULL;
     895             :     }
     896             : 
     897           4 :     args = Py_BuildValue(sss_py_const_p(char, "OiOOOO"),
     898           4 :                          self->name, self->enabled,
     899             :                          users_repr, services_repr,
     900             :                          targethosts_repr, srchosts_repr);
     901           4 :     if (args == NULL) {
     902           0 :         Py_DECREF(users_repr);
     903           0 :         Py_DECREF(services_repr);
     904           0 :         Py_DECREF(targethosts_repr);
     905           0 :         Py_DECREF(srchosts_repr);
     906           0 :         Py_DECREF(format);
     907             :         return NULL;
     908             :     }
     909             : 
     910           4 :     o = PyUnicode_Format(format, args);
     911           4 :     Py_DECREF(users_repr);
     912           4 :     Py_DECREF(services_repr);
     913           4 :     Py_DECREF(targethosts_repr);
     914           4 :     Py_DECREF(srchosts_repr);
     915           4 :     Py_DECREF(format);
     916           4 :     Py_DECREF(args);
     917           4 :     return o;
     918             : }
     919             : 
     920             : static PyObject *
     921           6 : py_hbac_rule_validate(HbacRuleObject *self, PyObject *args)
     922             : {
     923             :     struct hbac_rule *rule;
     924             :     bool is_valid;
     925             :     uint32_t missing;
     926             :     uint32_t attr;
     927           6 :     PyObject *ret = NULL;
     928           6 :     PyObject *py_is_valid = NULL;
     929           6 :     PyObject *py_missing = NULL;
     930           6 :     PyObject *py_attr = NULL;
     931             : 
     932           6 :     rule = HbacRule_to_native(self);
     933           6 :     if (!rule) {
     934             :         /* Make sure there is at least a generic exception */
     935           0 :         if (!PyErr_Occurred()) {
     936           0 :             PyErr_Format(PyExc_IOError,
     937             :                          "Could not convert HbacRule to native type\n");
     938             :         }
     939             :         goto fail;
     940             :     }
     941             : 
     942           6 :     is_valid = hbac_rule_is_complete(rule, &missing);
     943           6 :     free_hbac_rule(rule);
     944             : 
     945           6 :     ret = PyTuple_New(2);
     946           6 :     if (!ret) {
     947           0 :         PyErr_NoMemory();
     948             :         goto fail;
     949             :     }
     950             : 
     951           6 :     py_is_valid = PyBool_FromLong(is_valid);
     952           6 :     py_missing = PySet_New(NULL);
     953           6 :     if (!py_missing || !py_is_valid) {
     954           0 :         PyErr_NoMemory();
     955             :         goto fail;
     956             :     }
     957             : 
     958          30 :     for (attr = HBAC_RULE_ELEMENT_USERS;
     959             :          attr <= HBAC_RULE_ELEMENT_SOURCEHOSTS;
     960          24 :          attr <<= 1) {
     961          24 :         if (!(missing & attr)) continue;
     962             : 
     963          12 :         py_attr = PYNUMBER_FROMLONG(attr);
     964          12 :         if (!py_attr) {
     965           0 :             PyErr_NoMemory();
     966             :             goto fail;
     967             :         }
     968             : 
     969          12 :         if (PySet_Add(py_missing, py_attr) != 0) {
     970             :             /* If the set-add succeeded, it would steal the reference */
     971           0 :             Py_DECREF(py_attr);
     972             :             goto fail;
     973             :         }
     974             :     }
     975             : 
     976           6 :     PyTuple_SET_ITEM(ret, 0, py_is_valid);
     977           6 :     PyTuple_SET_ITEM(ret, 1, py_missing);
     978          12 :     return ret;
     979             : 
     980             : fail:
     981           0 :     Py_XDECREF(ret);
     982           0 :     Py_XDECREF(py_missing);
     983           0 :     Py_XDECREF(py_is_valid);
     984             :     return NULL;
     985             : }
     986             : 
     987             : PyDoc_STRVAR(py_hbac_rule_validate__doc__,
     988             : "validate() -> (valid, missing)\n\n"
     989             : "Validate an HBAC rule\n"
     990             : "Returns a tuple of (bool, set). The boolean value describes whether\n"
     991             : "the rule is valid. If it is False, then the set lists all the missing "
     992             : "rule elements as HBAC_RULE_ELEMENT_* constants\n");
     993             : 
     994             : static PyMethodDef py_hbac_rule_methods[] = {
     995             :     { sss_py_const_p(char, "validate"),
     996             :       (PyCFunction) py_hbac_rule_validate,
     997             :       METH_VARARGS, py_hbac_rule_validate__doc__,
     998             :     },
     999             :     { NULL, NULL, 0, NULL }        /* Sentinel */
    1000             : };
    1001             : 
    1002             : PyDoc_STRVAR(HbacRuleObject_users__doc__,
    1003             : "(HbacRuleElement) Users and user groups for which this rule applies");
    1004             : PyDoc_STRVAR(HbacRuleObject_services__doc__,
    1005             : "(HbacRuleElement) Services and service groups for which this rule applies");
    1006             : PyDoc_STRVAR(HbacRuleObject_targethosts__doc__,
    1007             : "(HbacRuleElement) Target hosts for which this rule applies");
    1008             : PyDoc_STRVAR(HbacRuleObject_srchosts__doc__,
    1009             : "(HbacRuleElement) Source hosts for which this rule applies");
    1010             : 
    1011             : static PyMemberDef py_hbac_rule_members[] = {
    1012             :     { discard_const_p(char, "users"), T_OBJECT_EX,
    1013             :       offsetof(HbacRuleObject, users), 0,
    1014             :       HbacRuleObject_users__doc__ },
    1015             : 
    1016             :     { discard_const_p(char, "services"), T_OBJECT_EX,
    1017             :       offsetof(HbacRuleObject, services), 0,
    1018             :       HbacRuleObject_services__doc__ },
    1019             : 
    1020             :     { discard_const_p(char, "targethosts"), T_OBJECT_EX,
    1021             :       offsetof(HbacRuleObject, targethosts), 0,
    1022             :       HbacRuleObject_targethosts__doc__},
    1023             : 
    1024             :     { discard_const_p(char, "srchosts"), T_OBJECT_EX,
    1025             :       offsetof(HbacRuleObject, srchosts), 0,
    1026             :       HbacRuleObject_srchosts__doc__},
    1027             : 
    1028             :     { NULL, 0, 0, 0, NULL } /* Sentinel */
    1029             : };
    1030             : 
    1031             : PyDoc_STRVAR(HbacRuleObject_enabled__doc__,
    1032             : "(bool) Is the rule enabled");
    1033             : PyDoc_STRVAR(HbacRuleObject_name__doc__,
    1034             : "(string) The name of the rule");
    1035             : 
    1036             : static PyGetSetDef py_hbac_rule_getset[] = {
    1037             :     { discard_const_p(char, "enabled"),
    1038             :       (getter) hbac_rule_get_enabled,
    1039             :       (setter) hbac_rule_set_enabled,
    1040             :       HbacRuleObject_enabled__doc__,
    1041             :       NULL },
    1042             : 
    1043             :     { discard_const_p(char, "name"),
    1044             :       (getter) hbac_rule_get_name,
    1045             :       (setter) hbac_rule_set_name,
    1046             :       HbacRuleObject_name__doc__,
    1047             :       NULL },
    1048             : 
    1049             :     {NULL, 0, 0, 0, NULL} /* Sentinel */
    1050             : };
    1051             : 
    1052             : PyDoc_STRVAR(HbacRuleObject__doc__,
    1053             : "IPA HBAC Rule\n\n"
    1054             : "HbacRule(name, [enabled]) -> instantiate an empty rule, optionally\n"
    1055             : "specify whether it is enabled. Rules are created disabled by default and\n"
    1056             : "contain empty HbacRuleElement instances in services, users, targethosts\n"
    1057             : "and srchosts attributes.\n");
    1058             : 
    1059             : static PyTypeObject pyhbac_hbacrule_type = {
    1060             :     PyVarObject_HEAD_INIT(NULL, 0)
    1061             :     .tp_name = sss_py_const_p(char, "pyhbac.HbacRule"),
    1062             :     .tp_basicsize = sizeof(HbacRuleObject),
    1063             :     .tp_new = HbacRule_new,
    1064             :     .tp_dealloc = (destructor) HbacRule_dealloc,
    1065             :     .tp_traverse = (traverseproc) HbacRule_traverse,
    1066             :     .tp_clear = (inquiry) HbacRule_clear,
    1067             :     .tp_init = (initproc) HbacRule_init,
    1068             :     .tp_repr = (reprfunc) HbacRule_repr,
    1069             :     .tp_members = py_hbac_rule_members,
    1070             :     .tp_methods = py_hbac_rule_methods,
    1071             :     .tp_getset = py_hbac_rule_getset,
    1072             :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
    1073             :     .tp_doc   = HbacRuleObject__doc__
    1074             : };
    1075             : 
    1076             : static void
    1077          20 : free_hbac_rule(struct hbac_rule *rule)
    1078             : {
    1079          40 :     if (!rule) return;
    1080             : 
    1081          20 :     free_hbac_rule_element(rule->services);
    1082          20 :     free_hbac_rule_element(rule->users);
    1083          20 :     free_hbac_rule_element(rule->targethosts);
    1084          20 :     free_hbac_rule_element(rule->srchosts);
    1085             : 
    1086          20 :     PyMem_Free(discard_const_p(char, rule->name));
    1087          20 :     PyMem_Free(rule);
    1088             : }
    1089             : 
    1090             : static struct hbac_rule *
    1091          20 : HbacRule_to_native(HbacRuleObject *pyrule)
    1092             : {
    1093          20 :     struct hbac_rule *rule = NULL;
    1094             :     PyObject *utf_name;
    1095             : 
    1096          20 :     rule = PyMem_Malloc(sizeof(struct hbac_rule));
    1097          20 :     if (!rule) {
    1098           0 :         PyErr_NoMemory();
    1099           0 :         goto fail;
    1100             :     }
    1101             : 
    1102          20 :     if (!PyObject_IsInstance((PyObject *) pyrule,
    1103             :                              (PyObject *) &pyhbac_hbacrule_type)) {
    1104           0 :         PyErr_Format(PyExc_TypeError,
    1105             :                      "The rule must be of type HbacRule\n");
    1106           0 :         goto fail;
    1107             :     }
    1108             : 
    1109          20 :     utf_name = get_utf8_string(pyrule->name, "name");
    1110          20 :     if (utf_name == NULL) {
    1111             :         return NULL;
    1112             :     }
    1113             : 
    1114          20 :     rule->name = py_strdup(PyBytes_AsString(utf_name));
    1115          20 :     Py_DECREF(utf_name);
    1116          20 :     if (rule->name == NULL) {
    1117             :         goto fail;
    1118             :     }
    1119             : 
    1120          20 :     rule->services = HbacRuleElement_to_native(pyrule->services);
    1121          20 :     rule->users = HbacRuleElement_to_native(pyrule->users);
    1122          20 :     rule->targethosts = HbacRuleElement_to_native(pyrule->targethosts);
    1123          20 :     rule->srchosts =  HbacRuleElement_to_native(pyrule->srchosts);
    1124          34 :     if (!rule->services || !rule->users ||
    1125          28 :         !rule->targethosts || !rule->srchosts) {
    1126             :         goto fail;
    1127             :     }
    1128             : 
    1129          14 :     rule->enabled = pyrule->enabled;
    1130          14 :     return rule;
    1131             : 
    1132             : fail:
    1133           6 :     free_hbac_rule(rule);
    1134           6 :     return NULL;
    1135             : }
    1136             : 
    1137             : /* ==================== HBAC Request Element ========================*/
    1138             : typedef struct {
    1139             :     PyObject_HEAD
    1140             : 
    1141             :     PyObject *name;
    1142             :     PyObject *groups;
    1143             : } HbacRequestElement;
    1144             : 
    1145             : static PyObject *
    1146          76 : HbacRequestElement_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
    1147             : {
    1148             :     HbacRequestElement *self;
    1149             : 
    1150          76 :     self = (HbacRequestElement *) type->tp_alloc(type, 0);
    1151          76 :     if (self == NULL) {
    1152           0 :         PyErr_NoMemory();
    1153           0 :         return NULL;
    1154             :     }
    1155             : 
    1156          76 :     self->name = PyUnicode_FromString("");
    1157          76 :     if (self->name == NULL) {
    1158           0 :         PyErr_NoMemory();
    1159           0 :         Py_DECREF(self);
    1160             :         return NULL;
    1161             :     }
    1162             : 
    1163          76 :     self->groups = PyList_New(0);
    1164          76 :     if (self->groups == NULL) {
    1165           0 :         Py_DECREF(self->name);
    1166           0 :         Py_DECREF(self);
    1167           0 :         PyErr_NoMemory();
    1168           0 :         return NULL;
    1169             :     }
    1170             : 
    1171             :     return (PyObject *) self;
    1172             : }
    1173             : 
    1174             : static int
    1175          76 : HbacRequestElement_clear(HbacRequestElement *self)
    1176             : {
    1177          76 :     Py_CLEAR(self->name);
    1178          76 :     Py_CLEAR(self->groups);
    1179          76 :     return 0;
    1180             : }
    1181             : 
    1182             : static void
    1183          76 : HbacRequestElement_dealloc(HbacRequestElement *self)
    1184             : {
    1185          76 :     HbacRequestElement_clear(self);
    1186          76 :     Py_TYPE(self)->tp_free((PyObject*) self);
    1187          76 : }
    1188             : 
    1189             : static int
    1190           0 : HbacRequestElement_traverse(HbacRequestElement *self,
    1191             :                             visitproc visit, void *arg)
    1192             : {
    1193           0 :     Py_VISIT(self->name);
    1194           0 :     Py_VISIT(self->groups);
    1195             :     return 0;
    1196             : }
    1197             : 
    1198             : static int
    1199             : hbac_request_element_set_groups(HbacRequestElement *self,
    1200             :                                 PyObject *groups,
    1201             :                                 void *closure);
    1202             : static int
    1203             : hbac_request_element_set_name(HbacRequestElement *self,
    1204             :                               PyObject *name,
    1205             :                               void *closure);
    1206             : 
    1207             : static int
    1208          76 : HbacRequestElement_init(HbacRequestElement *self,
    1209             :                         PyObject *args,
    1210             :                         PyObject *kwargs)
    1211             : {
    1212          76 :     const char * const kwlist[] = { "name", "groups", NULL };
    1213          76 :     PyObject *name = NULL;
    1214          76 :     PyObject *groups = NULL;
    1215             : 
    1216          76 :     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
    1217             :                                      sss_py_const_p(char, "|OO"),
    1218             :                                      discard_const_p(char *, kwlist),
    1219             :                                      &name, &groups)) {
    1220          76 :         return -1;
    1221             :     }
    1222             : 
    1223          76 :     if (name) {
    1224           4 :         if (hbac_request_element_set_name(self, name, NULL) != 0) {
    1225             :             return -1;
    1226             :         }
    1227             :     }
    1228             : 
    1229          76 :     if (groups) {
    1230           8 :         if (hbac_request_element_set_groups(self, groups, NULL) != 0) {
    1231             :             return -1;
    1232             :         }
    1233             :     }
    1234             : 
    1235             :     return 0;
    1236             : }
    1237             : 
    1238             : static int
    1239          36 : hbac_request_element_set_name(HbacRequestElement *self,
    1240             :                               PyObject *name,
    1241             :                               void *closure)
    1242             : {
    1243          36 :     CHECK_ATTRIBUTE_DELETE(name, "name");
    1244             : 
    1245          36 :     if (!PyBytes_Check(name) && !PyUnicode_Check(name)) {
    1246           0 :         PyErr_Format(PyExc_TypeError, "name must be a string or Unicode");
    1247           0 :         return -1;
    1248             :     }
    1249             : 
    1250          36 :     SAFE_SET(self->name, name);
    1251             :     return 0;
    1252             : }
    1253             : 
    1254             : static PyObject *
    1255          16 : hbac_request_element_get_name(HbacRequestElement *self, void *closure)
    1256             : {
    1257          16 :     if (PyUnicode_Check(self->name)) {
    1258          11 :         Py_INCREF(self->name);
    1259          11 :         return self->name;
    1260           5 :     } else if (PyBytes_Check(self->name)) {
    1261           5 :         return PyUnicode_FromEncodedObject(self->name,
    1262             :                                            PYHBAC_ENCODING, PYHBAC_ENCODING_ERRORS);
    1263             :     }
    1264             : 
    1265             :     /* setter does typechecking but let us be paranoid */
    1266           0 :     PyErr_Format(PyExc_TypeError, "name must be a string or Unicode");
    1267           0 :     return NULL;
    1268             : }
    1269             : 
    1270             : static int
    1271          16 : hbac_request_element_set_groups(HbacRequestElement *self,
    1272             :                                 PyObject *groups,
    1273             :                                 void *closure)
    1274             : {
    1275          16 :     CHECK_ATTRIBUTE_DELETE(groups, "groups");
    1276             : 
    1277          16 :     if (!verify_sequence(groups, "groups")) {
    1278             :         return -1;
    1279             :     }
    1280             : 
    1281          12 :     SAFE_SET(self->groups, groups);
    1282             :     return 0;
    1283             : }
    1284             : 
    1285             : static PyObject *
    1286          20 : hbac_request_element_get_groups(HbacRequestElement *self, void *closure)
    1287             : {
    1288          20 :     Py_INCREF(self->groups);
    1289          20 :     return self->groups;
    1290             : }
    1291             : 
    1292             : static PyObject *
    1293          20 : HbacRequestElement_repr(HbacRequestElement *self)
    1294             : {
    1295             :     char *strgroups;
    1296             :     PyObject *o, *format, *args;
    1297             : 
    1298          20 :     format = PyUnicode_FromString("<name %s groups [%s]>");
    1299          20 :     if (format == NULL) {
    1300             :         return NULL;
    1301             :     }
    1302             : 
    1303          20 :     strgroups = str_concat_sequence(self->groups, discard_const_p(char, ","));
    1304          20 :     if (strgroups == NULL) {
    1305           0 :         Py_DECREF(format);
    1306             :         return NULL;
    1307             :     }
    1308             : 
    1309          20 :     args = Py_BuildValue(sss_py_const_p(char, "Os"), self->name, strgroups);
    1310          20 :     if (args == NULL) {
    1311           0 :         PyMem_Free(strgroups);
    1312           0 :         Py_DECREF(format);
    1313             :         return NULL;
    1314             :     }
    1315             : 
    1316          20 :     o = PyUnicode_Format(format, args);
    1317          20 :     PyMem_Free(strgroups);
    1318          20 :     Py_DECREF(format);
    1319          20 :     Py_DECREF(args);
    1320          20 :     return o;
    1321             : }
    1322             : 
    1323             : PyDoc_STRVAR(HbacRequestElement_name__doc__,
    1324             : "(string) An object name this element applies to");
    1325             : PyDoc_STRVAR(HbacRequestElement_groups__doc__,
    1326             : "(list of strings) A list of group names this element applies to");
    1327             : 
    1328             : static PyGetSetDef py_hbac_request_element_getset[] = {
    1329             :     { discard_const_p(char, "name"),
    1330             :       (getter) hbac_request_element_get_name,
    1331             :       (setter) hbac_request_element_set_name,
    1332             :       HbacRequestElement_name__doc__,
    1333             :       NULL },
    1334             : 
    1335             :     { discard_const_p(char, "groups"),
    1336             :       (getter) hbac_request_element_get_groups,
    1337             :       (setter) hbac_request_element_set_groups,
    1338             :       HbacRequestElement_groups__doc__,
    1339             :       NULL },
    1340             : 
    1341             :     { NULL, 0, 0, 0, NULL } /* Sentinel */
    1342             : };
    1343             : 
    1344             : PyDoc_STRVAR(HbacRequestElement__doc__,
    1345             : "IPA HBAC Request Element\n\n"
    1346             : "HbacRequestElement() -> new empty request element\n"
    1347             : "HbacRequestElement([name], [groups]) -> optionally, provide name and/or "
    1348             : "groups\n");
    1349             : 
    1350             : static PyTypeObject pyhbac_hbacrequest_element_type = {
    1351             :     PyVarObject_HEAD_INIT(NULL, 0)
    1352             :     .tp_name = sss_py_const_p(char, "pyhbac.HbacRequestElement"),
    1353             :     .tp_basicsize = sizeof(HbacRequestElement),
    1354             :     .tp_new = HbacRequestElement_new,
    1355             :     .tp_dealloc = (destructor) HbacRequestElement_dealloc,
    1356             :     .tp_traverse = (traverseproc) HbacRequestElement_traverse,
    1357             :     .tp_clear = (inquiry) HbacRequestElement_clear,
    1358             :     .tp_init = (initproc) HbacRequestElement_init,
    1359             :     .tp_repr = (reprfunc) HbacRequestElement_repr,
    1360             :     .tp_getset = py_hbac_request_element_getset,
    1361             :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
    1362             :     .tp_doc   = HbacRequestElement__doc__
    1363             : };
    1364             : 
    1365             : static void
    1366          34 : free_hbac_request_element(struct hbac_request_element *el)
    1367             : {
    1368          68 :     if (!el) return;
    1369             : 
    1370          30 :     PyMem_Free(discard_const_p(char, el->name));
    1371          30 :     free_string_list(el->groups);
    1372          30 :     PyMem_Free(el);
    1373             : }
    1374             : 
    1375             : static struct hbac_request_element *
    1376          32 : HbacRequestElement_to_native(HbacRequestElement *pyel)
    1377             : {
    1378          32 :     struct hbac_request_element *el = NULL;
    1379             :     PyObject *utf_name;
    1380             : 
    1381          32 :     if (!PyObject_IsInstance((PyObject *) pyel,
    1382             :                              (PyObject *) &pyhbac_hbacrequest_element_type)) {
    1383           2 :         PyErr_Format(PyExc_TypeError,
    1384             :                      "The element must be of type HbacRequestElement\n");
    1385           2 :         goto fail;
    1386             :     }
    1387             : 
    1388          30 :     el = PyMem_Malloc(sizeof(struct hbac_request_element));
    1389          30 :     if (!el) {
    1390           0 :         PyErr_NoMemory();
    1391           0 :         goto fail;
    1392             :     }
    1393             : 
    1394          30 :     utf_name = get_utf8_string(pyel->name, "name");
    1395          30 :     if (utf_name == NULL) {
    1396             :         return NULL;
    1397             :     }
    1398             : 
    1399          30 :     el->name = py_strdup(PyBytes_AsString(utf_name));
    1400          30 :     Py_DECREF(utf_name);
    1401          30 :     if (!el->name) {
    1402             :         goto fail;
    1403             :     }
    1404             : 
    1405          30 :     el->groups = sequence_as_string_list(pyel->groups, "groups");
    1406          30 :     if (!el->groups) {
    1407             :         goto fail;
    1408             :     }
    1409             : 
    1410             :     return el;
    1411             : 
    1412             : fail:
    1413           2 :     free_hbac_request_element(el);
    1414           2 :     return NULL;
    1415             : }
    1416             : 
    1417             : /* ==================== HBAC Request ========================*/
    1418             : typedef struct {
    1419             :     PyObject_HEAD
    1420             : 
    1421             :     HbacRequestElement *service;
    1422             :     HbacRequestElement *user;
    1423             :     HbacRequestElement *targethost;
    1424             :     HbacRequestElement *srchost;
    1425             : 
    1426             :     PyObject *rule_name;
    1427             : } HbacRequest;
    1428             : 
    1429             : static PyObject *
    1430          14 : HbacRequest_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
    1431             : {
    1432             :     HbacRequest *self;
    1433             : 
    1434          14 :     self = (HbacRequest *) type->tp_alloc(type, 0);
    1435          14 :     if (self == NULL) {
    1436           0 :         PyErr_NoMemory();
    1437           0 :         return NULL;
    1438             :     }
    1439             : 
    1440          14 :     self->service = (HbacRequestElement *) HbacRequestElement_new(
    1441             :                                             &pyhbac_hbacrequest_element_type,
    1442             :                                             NULL, NULL);
    1443          14 :     self->user = (HbacRequestElement *) HbacRequestElement_new(
    1444             :                                             &pyhbac_hbacrequest_element_type,
    1445             :                                             NULL, NULL);
    1446          14 :     self->targethost = (HbacRequestElement *) HbacRequestElement_new(
    1447             :                                             &pyhbac_hbacrequest_element_type,
    1448             :                                             NULL, NULL);
    1449          14 :     self->srchost = (HbacRequestElement *) HbacRequestElement_new(
    1450             :                                             &pyhbac_hbacrequest_element_type,
    1451             :                                             NULL, NULL);
    1452          28 :     if (self->service == NULL || self->user == NULL ||
    1453          28 :         self->targethost == NULL || self->srchost == NULL) {
    1454           0 :         Py_XDECREF(self->service);
    1455           0 :         Py_XDECREF(self->user);
    1456           0 :         Py_XDECREF(self->targethost);
    1457           0 :         Py_XDECREF(self->srchost);
    1458           0 :         Py_DECREF(self);
    1459           0 :         PyErr_NoMemory();
    1460           0 :         return NULL;
    1461             :     }
    1462             : 
    1463             :     return (PyObject *) self;
    1464             : }
    1465             : 
    1466             : static int
    1467          14 : HbacRequest_clear(HbacRequest *self)
    1468             : {
    1469          14 :     Py_CLEAR(self->service);
    1470          14 :     Py_CLEAR(self->user);
    1471          14 :     Py_CLEAR(self->targethost);
    1472          14 :     Py_CLEAR(self->srchost);
    1473          14 :     Py_CLEAR(self->rule_name);
    1474          14 :     return 0;
    1475             : }
    1476             : 
    1477             : static void
    1478          14 : HbacRequest_dealloc(HbacRequest *self)
    1479             : {
    1480          14 :     HbacRequest_clear(self);
    1481          14 :     Py_TYPE(self)->tp_free((PyObject*) self);
    1482          14 : }
    1483             : 
    1484             : static int
    1485           0 : HbacRequest_traverse(HbacRequest *self, visitproc visit, void *arg)
    1486             : {
    1487           0 :     Py_VISIT((PyObject *) self->service);
    1488           0 :     Py_VISIT((PyObject *) self->user);
    1489           0 :     Py_VISIT((PyObject *) self->targethost);
    1490           0 :     Py_VISIT((PyObject *) self->srchost);
    1491             :     return 0;
    1492             : }
    1493             : 
    1494             : static int
    1495          14 : HbacRequest_init(HbacRequest *self, PyObject *args, PyObject *kwargs)
    1496             : {
    1497          14 :     PyObject *empty_tuple = NULL;
    1498             : 
    1499          14 :     empty_tuple = PyTuple_New(0);
    1500          14 :     if (!empty_tuple) {
    1501           0 :         PyErr_NoMemory();
    1502           0 :         return -1;
    1503             :     }
    1504             : 
    1505          14 :     self->rule_name = NULL;
    1506             : 
    1507          28 :     if (HbacRequestElement_init(self->user, empty_tuple, NULL) == -1 ||
    1508          28 :         HbacRequestElement_init(self->service, empty_tuple, NULL) == -1 ||
    1509          28 :         HbacRequestElement_init(self->targethost, empty_tuple, NULL) == -1 ||
    1510          14 :         HbacRequestElement_init(self->srchost, empty_tuple, NULL) == -1) {
    1511           0 :         Py_DECREF(empty_tuple);
    1512             :         return -1;
    1513             :     }
    1514             : 
    1515          14 :     Py_DECREF(empty_tuple);
    1516             :     return 0;
    1517             : }
    1518             : 
    1519             : PyDoc_STRVAR(py_hbac_evaluate__doc__,
    1520             : "evaluate(rules) -> int\n\n"
    1521             : "Evaluate a set of HBAC rules.\n"
    1522             : "rules is a sequence of HbacRule objects. The returned value describes\n"
    1523             : "the result of evaluation and will have one of HBAC_EVAL_* values.\n"
    1524             : "Use hbac_result_string() to get textual representation of the result\n"
    1525             : "On error, HbacError exception is raised.\n"
    1526             : "If HBAC_EVAL_ALLOW is returned, the class attribute rule_name would\n"
    1527             : "contain the name of the rule that matched. Otherwise, the attribute\n"
    1528             : "contains None\n");
    1529             : 
    1530             : static struct hbac_eval_req *
    1531             : HbacRequest_to_native(HbacRequest *pyreq);
    1532             : 
    1533             : static void
    1534          14 : free_hbac_rule_list(struct hbac_rule **rules)
    1535             : {
    1536             :     int i;
    1537             : 
    1538          28 :     if (!rules) return;
    1539             : 
    1540           8 :     for(i=0; rules[i]; i++) {
    1541           8 :         free_hbac_rule(rules[i]);
    1542             :     }
    1543          14 :     PyMem_Free(rules);
    1544             : }
    1545             : 
    1546             : static void
    1547             : free_hbac_eval_req(struct hbac_eval_req *req);
    1548             : 
    1549             : static PyObject *
    1550          14 : py_hbac_evaluate(HbacRequest *self, PyObject *args)
    1551             : {
    1552          14 :     PyObject *py_rules_list = NULL;
    1553          14 :     PyObject *py_rule = NULL;
    1554             :     Py_ssize_t num_rules;
    1555          14 :     struct hbac_rule **rules = NULL;
    1556          14 :     struct hbac_eval_req *hbac_req = NULL;
    1557             :     enum hbac_eval_result eres;
    1558          14 :     struct hbac_info *info = NULL;
    1559          14 :     PyObject *ret = NULL;
    1560             :     long i;
    1561             : 
    1562          14 :     if (!PyArg_ParseTuple(args, sss_py_const_p(char, "O"), &py_rules_list)) {
    1563             :         goto fail;
    1564             :     }
    1565             : 
    1566          14 :     if (!PySequence_Check(py_rules_list)) {
    1567           0 :         PyErr_Format(PyExc_TypeError,
    1568             :                      "The parameter rules must be a sequence\n");
    1569             :         goto fail;
    1570             :     }
    1571             : 
    1572          14 :     num_rules = PySequence_Size(py_rules_list);
    1573          14 :     rules = PyMem_New(struct hbac_rule *, num_rules+1);
    1574          14 :     if (!rules) {
    1575           0 :         PyErr_NoMemory();
    1576             :         goto fail;
    1577             :     }
    1578             : 
    1579           8 :     for (i=0; i < num_rules; i++) {
    1580          14 :         py_rule = PySequence_GetItem(py_rules_list, i);
    1581             : 
    1582          14 :         if (!PyObject_IsInstance(py_rule,
    1583             :                                  (PyObject *) &pyhbac_hbacrule_type)) {
    1584           0 :             PyErr_Format(PyExc_TypeError,
    1585             :                          "A rule must be of type HbacRule\n");
    1586             :             goto fail;
    1587             :         }
    1588             : 
    1589          14 :         rules[i] = HbacRule_to_native((HbacRuleObject *) py_rule);
    1590          14 :         if (!rules[i]) {
    1591             :             /* Make sure there is at least a generic exception */
    1592           6 :             if (!PyErr_Occurred()) {
    1593           0 :                 PyErr_Format(PyExc_IOError,
    1594             :                              "Could not convert HbacRule to native type\n");
    1595             :             }
    1596             :             goto fail;
    1597             :         }
    1598             :     }
    1599           8 :     rules[num_rules] = NULL;
    1600             : 
    1601           8 :     hbac_req = HbacRequest_to_native(self);
    1602           8 :     if (!hbac_req) {
    1603           2 :         if (!PyErr_Occurred()) {
    1604           0 :             PyErr_Format(PyExc_IOError,
    1605             :                          "Could not convert HbacRequest to native type\n");
    1606             :         }
    1607             :         goto fail;
    1608             :     }
    1609             : 
    1610           6 :     Py_XDECREF(self->rule_name);
    1611           6 :     self->rule_name = NULL;
    1612             : 
    1613           6 :     eres = hbac_evaluate(rules, hbac_req, &info);
    1614           6 :     switch (eres) {
    1615             :     case HBAC_EVAL_ALLOW:
    1616           4 :         self->rule_name = PyUnicode_FromString(info->rule_name);
    1617           4 :         if (!self->rule_name) {
    1618           0 :             PyErr_NoMemory();
    1619             :             goto fail;
    1620             :         }
    1621             :         /* FALLTHROUGH */
    1622             :     case HBAC_EVAL_DENY:
    1623           6 :         ret = PYNUMBER_FROMLONG(eres);
    1624             :         break;
    1625             :     case HBAC_EVAL_ERROR:
    1626           0 :         set_hbac_exception(PyExc_HbacError, info);
    1627             :         goto fail;
    1628             :     case HBAC_EVAL_OOM:
    1629           0 :         PyErr_NoMemory();
    1630             :         goto fail;
    1631             :     }
    1632             : 
    1633           6 :     free_hbac_eval_req(hbac_req);
    1634           6 :     free_hbac_rule_list(rules);
    1635           6 :     hbac_free_info(info);
    1636          14 :     return ret;
    1637             : 
    1638             : fail:
    1639           8 :     hbac_free_info(info);
    1640           8 :     free_hbac_eval_req(hbac_req);
    1641           8 :     free_hbac_rule_list(rules);
    1642             :     return NULL;
    1643             : }
    1644             : 
    1645             : static PyObject *
    1646           6 : hbac_request_element_get_rule_name(HbacRequest *self, void *closure)
    1647             : {
    1648           6 :     if (self->rule_name == NULL) {
    1649           4 :         Py_INCREF(Py_None);
    1650           4 :         return Py_None;
    1651           2 :     } else if (PyUnicode_Check(self->rule_name)) {
    1652           2 :         Py_INCREF(self->rule_name);
    1653           2 :         return self->rule_name;
    1654             :     }
    1655             : 
    1656           0 :     PyErr_Format(PyExc_TypeError, "rule_name is not Unicode");
    1657           0 :     return NULL;
    1658             : }
    1659             : 
    1660             : static PyObject *
    1661           4 : HbacRequest_repr(HbacRequest *self)
    1662             : {
    1663             :     PyObject *user_repr;
    1664             :     PyObject *service_repr;
    1665             :     PyObject *targethost_repr;
    1666             :     PyObject *srchost_repr;
    1667             :     PyObject *o, *format, *args;
    1668             : 
    1669           4 :     format = PyUnicode_FromString("<user %s service %s "
    1670             :                                             "targethost %s srchost %s>");
    1671           4 :     if (format == NULL) {
    1672             :         return NULL;
    1673             :     }
    1674             : 
    1675           4 :     user_repr = HbacRequestElement_repr(self->user);
    1676           4 :     service_repr = HbacRequestElement_repr(self->service);
    1677           4 :     targethost_repr = HbacRequestElement_repr(self->targethost);
    1678           4 :     srchost_repr = HbacRequestElement_repr(self->srchost);
    1679           4 :     if (user_repr == NULL || service_repr == NULL ||
    1680           4 :         targethost_repr == NULL || srchost_repr == NULL) {
    1681           0 :         Py_XDECREF(user_repr);
    1682           0 :         Py_XDECREF(service_repr);
    1683           0 :         Py_XDECREF(targethost_repr);
    1684           0 :         Py_XDECREF(srchost_repr);
    1685           0 :         Py_DECREF(format);
    1686             :         return NULL;
    1687             :     }
    1688             : 
    1689           4 :     args = Py_BuildValue(sss_py_const_p(char, "OOOO"),
    1690             :                          user_repr, service_repr,
    1691             :                          targethost_repr, srchost_repr);
    1692           4 :     if (args == NULL) {
    1693           0 :         Py_DECREF(user_repr);
    1694           0 :         Py_DECREF(service_repr);
    1695           0 :         Py_DECREF(targethost_repr);
    1696           0 :         Py_DECREF(srchost_repr);
    1697           0 :         Py_DECREF(format);
    1698             :         return NULL;
    1699             :     }
    1700             : 
    1701           4 :     o = PyUnicode_Format(format, args);
    1702           4 :     Py_DECREF(user_repr);
    1703           4 :     Py_DECREF(service_repr);
    1704           4 :     Py_DECREF(targethost_repr);
    1705           4 :     Py_DECREF(srchost_repr);
    1706           4 :     Py_DECREF(format);
    1707           4 :     Py_DECREF(args);
    1708           4 :     return o;
    1709             : }
    1710             : 
    1711             : static PyMethodDef py_hbac_request_methods[] = {
    1712             :     { sss_py_const_p(char, "evaluate"),
    1713             :       (PyCFunction) py_hbac_evaluate,
    1714             :       METH_VARARGS, py_hbac_evaluate__doc__
    1715             :     },
    1716             :     { NULL, NULL, 0, NULL }        /* Sentinel */
    1717             : };
    1718             : 
    1719             : PyDoc_STRVAR(HbacRequest_service__doc__,
    1720             : "(HbacRequestElement) This is a list of service DNs to check, it must\n"
    1721             : "consist of the actual service requested, as well as all parent groups\n"
    1722             : "containing that service");
    1723             : PyDoc_STRVAR(HbacRequest_user__doc__,
    1724             : "(HbacRequestElement) This is a list of user DNs to check, it must consist\n"
    1725             : "of the actual user requested, as well as all parent groups containing\n"
    1726             : "that user.");
    1727             : PyDoc_STRVAR(HbacRequest_targethost__doc__,
    1728             : "(HbacRequestElement) This is a list of target hosts to check, it must\n"
    1729             : "consist of the actual target host requested, as well as all parent groups\n"
    1730             : "containing that target host.");
    1731             : PyDoc_STRVAR(HbacRequest_srchost__doc__,
    1732             : "(HbacRequestElement) This is a list of source hosts to check, it must\n"
    1733             : "consist of the actual source host requested, as well as all parent groups\n"
    1734             : "containing that source host.");
    1735             : 
    1736             : static PyMemberDef py_hbac_request_members[] = {
    1737             :     { discard_const_p(char, "service"), T_OBJECT_EX,
    1738             :       offsetof(HbacRequest, service), 0,
    1739             :       HbacRequest_service__doc__ },
    1740             : 
    1741             :     { discard_const_p(char, "user"), T_OBJECT_EX,
    1742             :       offsetof(HbacRequest, user), 0,
    1743             :       HbacRequest_user__doc__ },
    1744             : 
    1745             :     { discard_const_p(char, "targethost"), T_OBJECT_EX,
    1746             :       offsetof(HbacRequest, targethost), 0,
    1747             :       HbacRequest_targethost__doc__ },
    1748             : 
    1749             :     { discard_const_p(char, "srchost"), T_OBJECT_EX,
    1750             :       offsetof(HbacRequest, srchost), 0,
    1751             :       HbacRequest_srchost__doc__ },
    1752             : 
    1753             :     { NULL, 0, 0, 0, NULL } /* Sentinel */
    1754             : };
    1755             : 
    1756             : PyDoc_STRVAR(HbacRequest_rule_name__doc__,
    1757             : "(string) If result of evaluation was to allow access, this member contains\n"
    1758             : "the name of the rule that allowed it. Otherwise, this attribute contains \n"
    1759             : "None. This attribute is read-only.\n");
    1760             : 
    1761             : static PyGetSetDef py_hbac_request_getset[] = {
    1762             :     { discard_const_p(char, "rule_name"),
    1763             :       (getter) hbac_request_element_get_rule_name,
    1764             :       NULL, /* read only */
    1765             :       HbacRequest_rule_name__doc__,
    1766             :       NULL },
    1767             : 
    1768             :     { NULL, 0, 0, 0, NULL } /* Sentinel */
    1769             : };
    1770             : 
    1771             : PyDoc_STRVAR(HbacRequest__doc__,
    1772             : "IPA HBAC Request\n\n"
    1773             : "HbacRequest() -> new empty HBAC request");
    1774             : 
    1775             : static PyTypeObject pyhbac_hbacrequest_type = {
    1776             :     PyVarObject_HEAD_INIT(NULL, 0)
    1777             :     .tp_name = sss_py_const_p(char, "pyhbac.HbacRequest"),
    1778             :     .tp_basicsize = sizeof(HbacRequest),
    1779             :     .tp_new = HbacRequest_new,
    1780             :     .tp_dealloc = (destructor) HbacRequest_dealloc,
    1781             :     .tp_traverse = (traverseproc) HbacRequest_traverse,
    1782             :     .tp_clear = (inquiry) HbacRequest_clear,
    1783             :     .tp_init = (initproc) HbacRequest_init,
    1784             :     .tp_repr = (reprfunc) HbacRequest_repr,
    1785             :     .tp_methods = py_hbac_request_methods,
    1786             :     .tp_members = py_hbac_request_members,
    1787             :     .tp_getset = py_hbac_request_getset,
    1788             :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    1789             :     .tp_doc   = HbacRequest__doc__
    1790             : };
    1791             : 
    1792             : static void
    1793          16 : free_hbac_eval_req(struct hbac_eval_req *req)
    1794             : {
    1795          32 :     if (!req) return;
    1796             : 
    1797           8 :     free_hbac_request_element(req->service);
    1798           8 :     free_hbac_request_element(req->user);
    1799           8 :     free_hbac_request_element(req->targethost);
    1800           8 :     free_hbac_request_element(req->srchost);
    1801             : 
    1802           8 :     PyMem_Free(req);
    1803             : }
    1804             : 
    1805             : static struct hbac_eval_req *
    1806           8 : HbacRequest_to_native(HbacRequest *pyreq)
    1807             : {
    1808           8 :     struct hbac_eval_req *req = NULL;
    1809             : 
    1810           8 :     req = PyMem_Malloc(sizeof(struct hbac_eval_req));
    1811           8 :     if (!req) {
    1812           0 :         PyErr_NoMemory();
    1813           0 :         goto fail;
    1814             :     }
    1815             : 
    1816           8 :     if (!PyObject_IsInstance((PyObject *) pyreq,
    1817             :                              (PyObject *) &pyhbac_hbacrequest_type)) {
    1818           0 :         PyErr_Format(PyExc_TypeError,
    1819             :                      "The request must be of type HbacRequest\n");
    1820           0 :         goto fail;
    1821             :     }
    1822             : 
    1823           8 :     req->service = HbacRequestElement_to_native(pyreq->service);
    1824           8 :     req->user = HbacRequestElement_to_native(pyreq->user);
    1825           8 :     req->targethost = HbacRequestElement_to_native(pyreq->targethost);
    1826           8 :     req->srchost =  HbacRequestElement_to_native(pyreq->srchost);
    1827          14 :     if (!req->service || !req->user ||
    1828          12 :         !req->targethost || !req->srchost) {
    1829             :         goto fail;
    1830             :     }
    1831             :     return req;
    1832             : 
    1833             : fail:
    1834           2 :     free_hbac_eval_req(req);
    1835           2 :     return NULL;
    1836             : }
    1837             : 
    1838             : /* =================== the pyhbac module initialization =====================*/
    1839             : PyDoc_STRVAR(py_hbac_result_string__doc__,
    1840             : "hbac_result_string(code) -> string\n"
    1841             : "Returns a string representation of the HBAC result code");
    1842             : 
    1843             : static PyObject *
    1844           6 : py_hbac_result_string(PyObject *module, PyObject *args)
    1845             : {
    1846             :     enum hbac_eval_result result;
    1847             :     const char *str;
    1848             : 
    1849           6 :     if (!PyArg_ParseTuple(args, sss_py_const_p(char, "i"), &result)) {
    1850           6 :         return NULL;
    1851             :     }
    1852             : 
    1853           6 :     str = hbac_result_string(result);
    1854           6 :     if (str == NULL) {
    1855             :         /* None needs to be referenced, too */
    1856           0 :         Py_INCREF(Py_None);
    1857           0 :         return Py_None;
    1858             :     }
    1859             : 
    1860           6 :     return PyUnicode_FromString(str);
    1861             : }
    1862             : 
    1863             : PyDoc_STRVAR(py_hbac_error_string__doc__,
    1864             : "hbac_error_string(code) -> string\n"
    1865             : "Returns a string representation of the HBAC error code");
    1866             : 
    1867             : static PyObject *
    1868          10 : py_hbac_error_string(PyObject *module, PyObject *args)
    1869             : {
    1870             :     enum hbac_error_code code;
    1871             :     const char *str;
    1872             : 
    1873          10 :     if (!PyArg_ParseTuple(args, sss_py_const_p(char, "i"), &code)) {
    1874          10 :         return NULL;
    1875             :     }
    1876             : 
    1877          10 :     str = hbac_error_string(code);
    1878          10 :     if (str == NULL) {
    1879             :         /* None needs to be referenced, too */
    1880           0 :         Py_INCREF(Py_None);
    1881           0 :         return Py_None;
    1882             :     }
    1883             : 
    1884          10 :     return PyUnicode_FromString(str);
    1885             : }
    1886             : 
    1887             : static PyMethodDef pyhbac_module_methods[] = {
    1888             :         {  sss_py_const_p(char, "hbac_result_string"),
    1889             :            (PyCFunction) py_hbac_result_string,
    1890             :            METH_VARARGS,
    1891             :            py_hbac_result_string__doc__,
    1892             :         },
    1893             : 
    1894             :         { sss_py_const_p(char, "hbac_error_string"),
    1895             :            (PyCFunction) py_hbac_error_string,
    1896             :            METH_VARARGS,
    1897             :            py_hbac_error_string__doc__,
    1898             :         },
    1899             : 
    1900             :         {NULL, NULL, 0, NULL}  /* Sentinel */
    1901             : };
    1902             : 
    1903             : PyDoc_STRVAR(HbacError__doc__,
    1904             : "An HBAC processing exception\n\n"
    1905             : "This exception is raised when there is an internal error during the\n"
    1906             : "HBAC processing, such as an Out-Of-Memory situation or unparseable\n"
    1907             : "rule. HbacError.args argument is a tuple that contains error code and\n"
    1908             : "the name of the rule that was being processed. Use hbac_error_string()\n"
    1909             : "to get the text representation of the HBAC error");
    1910             : 
    1911             : #ifdef IS_PY3K
    1912             : static struct PyModuleDef pyhbacdef = {
    1913             :     PyModuleDef_HEAD_INIT,
    1914             :     PYTHON_MODULE_NAME,
    1915             :     NULL,
    1916             :     -1,
    1917             :     pyhbac_module_methods,
    1918             :     NULL,
    1919             :     NULL,
    1920             :     NULL,
    1921             :     NULL
    1922             : };
    1923             : 
    1924             : PyMODINIT_FUNC
    1925           1 : PyInit_pyhbac(void)
    1926             : #else
    1927             : PyMODINIT_FUNC
    1928           1 : initpyhbac(void)
    1929             : #endif
    1930             : {
    1931             :     PyObject *m;
    1932             :     int ret;
    1933             : 
    1934             : #ifdef IS_PY3K
    1935           1 :     m = PyModule_Create(&pyhbacdef);
    1936             : #else
    1937           1 :     m = Py_InitModule(sss_py_const_p(char, PYTHON_MODULE_NAME),
    1938             :                       pyhbac_module_methods);
    1939             : #endif
    1940           2 :     if (m == NULL) MODINITERROR;
    1941             : 
    1942             :     /* The HBAC module exception */
    1943           2 :     PyExc_HbacError = sss_exception_with_doc(
    1944             :                         discard_const_p(char, "hbac.HbacError"),
    1945             :                         HbacError__doc__,
    1946             :                         PyExc_EnvironmentError, NULL);
    1947           2 :     Py_INCREF(PyExc_HbacError);
    1948           2 :     ret = PyModule_AddObject(m, sss_py_const_p(char, "HbacError"), PyExc_HbacError);
    1949           2 :     if (ret == -1) MODINITERROR;
    1950             : 
    1951             :     /* HBAC rule categories */
    1952           2 :     ret = PyModule_AddIntMacro(m, HBAC_CATEGORY_NULL);
    1953           2 :     if (ret == -1) MODINITERROR;
    1954           2 :     ret = PyModule_AddIntMacro(m, HBAC_CATEGORY_ALL);
    1955           2 :     if (ret == -1) MODINITERROR;
    1956             : 
    1957             :     /* HBAC rule elements */
    1958           2 :     ret = PyModule_AddIntMacro(m, HBAC_RULE_ELEMENT_USERS);
    1959           2 :     if (ret == -1) MODINITERROR;
    1960           2 :     ret = PyModule_AddIntMacro(m, HBAC_RULE_ELEMENT_SERVICES);
    1961           2 :     if (ret == -1) MODINITERROR;
    1962           2 :     ret = PyModule_AddIntMacro(m, HBAC_RULE_ELEMENT_TARGETHOSTS);
    1963           2 :     if (ret == -1) MODINITERROR;
    1964           2 :     ret = PyModule_AddIntMacro(m, HBAC_RULE_ELEMENT_SOURCEHOSTS);
    1965           2 :     if (ret == -1) MODINITERROR;
    1966             : 
    1967             :     /* enum hbac_eval_result */
    1968           2 :     ret = PyModule_AddIntMacro(m, HBAC_EVAL_ALLOW);
    1969           2 :     if (ret == -1) MODINITERROR;
    1970           2 :     ret = PyModule_AddIntMacro(m, HBAC_EVAL_DENY);
    1971           2 :     if (ret == -1) MODINITERROR;
    1972           2 :     ret = PyModule_AddIntMacro(m, HBAC_EVAL_ERROR);
    1973           2 :     if (ret == -1) MODINITERROR;
    1974             : 
    1975             :     /* enum hbac_error_code */
    1976           2 :     ret = PyModule_AddIntMacro(m, HBAC_ERROR_UNKNOWN);
    1977           2 :     if (ret == -1) MODINITERROR;
    1978           2 :     ret = PyModule_AddIntMacro(m, HBAC_SUCCESS);
    1979           2 :     if (ret == -1) MODINITERROR;
    1980           2 :     ret = PyModule_AddIntMacro(m, HBAC_ERROR_NOT_IMPLEMENTED);
    1981           2 :     if (ret == -1) MODINITERROR;
    1982           2 :     ret = PyModule_AddIntMacro(m, HBAC_ERROR_OUT_OF_MEMORY);
    1983           2 :     if (ret == -1) MODINITERROR;
    1984           2 :     ret = PyModule_AddIntMacro(m, HBAC_ERROR_UNPARSEABLE_RULE);
    1985           2 :     if (ret == -1) MODINITERROR;
    1986             : 
    1987           2 :     TYPE_READY(m, pyhbac_hbacrule_type, "HbacRule");
    1988           2 :     TYPE_READY(m, pyhbac_hbacrule_element_type, "HbacRuleElement");
    1989           2 :     TYPE_READY(m, pyhbac_hbacrequest_element_type, "HbacRequestElement");
    1990           2 :     TYPE_READY(m, pyhbac_hbacrequest_type, "HbacRequest");
    1991             : 
    1992             : #ifdef IS_PY3K
    1993           1 :     return m;
    1994             : #endif
    1995             : }

Generated by: LCOV version 1.10