pyhbac.c revision a63b368a025a61edf41a3d5ce34f325b03295cf6
/*
Authors:
Jakub Hrozek <jhrozek@redhat.com>
Copyright (C) 2011 Red Hat
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Python.h>
#include <structmember.h>
#include "util/sss_python.h"
#include "providers/ipa/ipa_hbac.h"
#define PYTHON_MODULE_NAME "pyhbac"
#ifndef PYHBAC_ENCODING
#define PYHBAC_ENCODING "UTF-8"
#endif
#define PYHBAC_ENCODING_ERRORS "strict"
"Cannot delete the %s attribute", \
attrname); \
return -1; \
} \
} while(0)
static PyObject *PyExc_HbacError;
/* ==================== Utility functions ========================*/
static char *
{
char *copy;
return NULL;
}
}
static char *
{
char *new_first;
return NULL;
}
}
static PyObject *
{
if (PyBytes_Check(obj)) {
} else if (PyUnicode_Check(obj)) {
return NULL;
}
} else {
return NULL;
}
return obj_utf8;
}
static void
free_string_list(const char **list)
{
int i;
if (!list) return;
for (i=0; list[i]; i++) {
}
}
static const char **
{
const char **ret;
int i;
if (!PySequence_Check(seq)) {
"The object must be a sequence\n");
return NULL;
}
if (!ret) {
return NULL;
}
for (i = 0; i < len; i++) {
break;
}
return NULL;
}
if (!ret[i]) {
return NULL;
}
}
return ret;
}
static bool
{
if (!PySequence_Check(seq)) {
return false;
}
return true;
}
static int
{
long c;
c = PYNUMBER_ASLONG(o);
if (c == -1 && PyErr_Occurred()) {
"Invalid type for category element - must be an int\n");
return -1;
}
switch (c) {
case HBAC_CATEGORY_NULL:
case HBAC_CATEGORY_ALL:
return c;
}
return -1;
}
static uint32_t
{
int ret;
return -1;
}
cat = 0;
if (ret == -1) {
return -1;
}
}
return cat;
}
static char *
{
Py_ssize_t i;
char *s = NULL;
char *part;
if (size == 0) {
s = py_strdup("");
if (s == NULL) {
return NULL;
}
return s;
}
for (i=0; i < size; i++) {
#ifdef IS_PY3K
#else
#endif
if (s) {
s = py_strcat_realloc(s, delim);
s = py_strcat_realloc(s, part);
} else {
}
}
return s;
fail:
PyMem_Free(s);
return NULL;
}
/* ================= HBAC Exception handling =====================*/
static void
{
}
/* ==================== HBAC Rule Element ========================*/
typedef struct {
static PyObject *
{
return NULL;
}
return NULL;
}
}
static int
{
return 0;
}
static void
{
}
static int
{
return 0;
}
static int
void *closure);
static int
void *closure);
static int
void *closure);
static int
{
sss_py_const_p(char, "|OOO"),
discard_const_p(char *, kwlist),
return -1;
}
if (names) {
return -1;
}
}
if (groups) {
return -1;
}
}
if (category) {
return -1;
}
} else {
if (!tmp) {
return -1;
}
return -1;
}
}
return 0;
}
static int
void *closure)
{
return -1;
}
return 0;
}
static PyObject *
{
}
static int
void *closure)
{
return -1;
}
return 0;
}
static PyObject *
{
}
static int
void *closure)
{
int ret;
if (!PySet_Check(category)) {
return -1;
}
/* Check the values, too */
return -1;
}
if (ret == -1) {
return -1;
}
}
return 0;
}
static PyObject *
{
}
static PyObject *
{
return NULL;
}
discard_const_p(char, ","));
discard_const_p(char, ","));
return NULL;
}
(unsigned long long ) category,
return NULL;
}
return o;
}
"(sequence of strings) A list of object names this element applies to");
"(sequence of strings) A list of group names this element applies to");
"(set) A set of categories this rule falls into");
static PyGetSetDef py_hbac_rule_element_getset[] = {
{ discard_const_p(char, "names"),
NULL },
{ discard_const_p(char, "groups"),
NULL },
{ discard_const_p(char, "category"),
NULL },
};
"IPA HBAC Rule Element\n\n"
"HbacRuleElement() -> new empty rule element\n"
"HbacRuleElement([names], [groups], [category]) -> optionally, provide\n"
static PyTypeObject pyhbac_hbacrule_element_type = {
.tp_basicsize = sizeof(HbacRuleElement),
};
static void
{
if (!el) return;
PyMem_Free(el);
}
struct hbac_rule_element *
{
/* check the type, None would wreak havoc here because for some reason
* it would pass the sequence check */
(PyObject *) &pyhbac_hbacrule_element_type)) {
"The element must be of type HbacRuleElement\n");
goto fail;
}
if (!el) {
goto fail;
}
goto fail;
}
return el;
fail:
return NULL;
}
/* ==================== HBAC Rule ========================*/
typedef struct {
bool enabled;
static void
static struct hbac_rule *
static PyObject *
{
return NULL;
}
return NULL;
}
return NULL;
}
}
static int
{
return 0;
}
static void
{
}
static int
{
return 0;
}
static int
static int
static int
{
sss_py_const_p(char, "O|O"),
discard_const_p(char *, kwlist),
return -1;
}
if (enabled) {
return -1;
}
}
return -1;
}
empty_tuple = PyTuple_New(0);
if (!empty_tuple) {
return -1;
}
return -1;
}
return 0;
}
static int
{
char *str;
if (!utf8_str) return -1;
if (!str) {
return -1;
}
} else {
"enabled only accepts 'true' of 'false' "
"string literals");
return -1;
}
return 0;
} else if (PyBool_Check(enabled) == true) {
return 0;
} else if (PYNUMBER_CHECK(enabled)) {
switch(PYNUMBER_ASLONG(enabled)) {
case 0:
break;
case 1:
break;
default:
"enabled only accepts '0' of '1' "
"integer constants");
return -1;
}
return 0;
}
return -1;
}
static PyObject *
{
}
}
static int
{
return -1;
}
return 0;
}
static PyObject *
{
}
/* setter does typechecking but let us be paranoid */
return NULL;
}
static PyObject *
{
"users %s services %s "
"targethosts %s srchosts %s>");
return NULL;
}
return NULL;
}
return NULL;
}
return o;
}
static PyObject *
{
bool is_valid;
if (!rule) {
/* Make sure there is at least a generic exception */
if (!PyErr_Occurred()) {
"Could not convert HbacRule to native type\n");
}
goto fail;
}
if (!ret) {
goto fail;
}
if (!py_missing || !py_is_valid) {
goto fail;
}
for (attr = HBAC_RULE_ELEMENT_USERS;
attr <<= 1) {
if (!py_attr) {
goto fail;
}
/* If the set-add succeeded, it would steal the reference */
goto fail;
}
}
return ret;
fail:
return NULL;
}
"validate() -> (valid, missing)\n\n"
"Validate an HBAC rule\n"
"Returns a tuple of (bool, set). The boolean value describes whether\n"
"the rule is valid. If it is False, then the set lists all the missing "
"rule elements as HBAC_RULE_ELEMENT_* constants\n");
static PyMethodDef py_hbac_rule_methods[] = {
{ sss_py_const_p(char, "validate"),
},
};
"(HbacRuleElement) Users and user groups for which this rule applies");
"(HbacRuleElement) Services and service groups for which this rule applies");
"(HbacRuleElement) Target hosts for which this rule applies");
"(HbacRuleElement) Source hosts for which this rule applies");
static PyMemberDef py_hbac_rule_members[] = {
};
"(bool) Is the rule enabled");
"(string) The name of the rule");
static PyGetSetDef py_hbac_rule_getset[] = {
{ discard_const_p(char, "enabled"),
NULL },
{ discard_const_p(char, "name"),
NULL },
};
"IPA HBAC Rule\n\n"
"HbacRule(name, [enabled]) -> instantiate an empty rule, optionally\n"
"specify whether it is enabled. Rules are created disabled by default and\n"
"contain empty HbacRuleElement instances in services, users, targethosts\n"
"and srchosts attributes.\n");
static PyTypeObject pyhbac_hbacrule_type = {
.tp_basicsize = sizeof(HbacRuleObject),
.tp_new = HbacRule_new,
};
static void
{
if (!rule) return;
}
static struct hbac_rule *
{
if (!rule) {
goto fail;
}
(PyObject *) &pyhbac_hbacrule_type)) {
"The rule must be of type HbacRule\n");
goto fail;
}
return NULL;
}
goto fail;
}
goto fail;
}
return rule;
fail:
return NULL;
}
/* ==================== HBAC Request Element ========================*/
typedef struct {
static PyObject *
{
return NULL;
}
return NULL;
}
return NULL;
}
}
static int
{
return 0;
}
static void
{
}
static int
{
return 0;
}
static int
void *closure);
static int
void *closure);
static int
{
sss_py_const_p(char, "|OO"),
discard_const_p(char *, kwlist),
return -1;
}
if (name) {
return -1;
}
}
if (groups) {
return -1;
}
}
return 0;
}
static int
void *closure)
{
return -1;
}
return 0;
}
static PyObject *
{
}
/* setter does typechecking but let us be paranoid */
return NULL;
}
static int
void *closure)
{
return -1;
}
return 0;
}
static PyObject *
{
}
static PyObject *
{
char *strgroups;
return NULL;
}
return NULL;
}
return NULL;
}
return o;
}
"(string) An object name this element applies to");
"(list of strings) A list of group names this element applies to");
static PyGetSetDef py_hbac_request_element_getset[] = {
{ discard_const_p(char, "name"),
NULL },
{ discard_const_p(char, "groups"),
NULL },
};
"IPA HBAC Request Element\n\n"
"HbacRequestElement() -> new empty request element\n"
"groups\n");
static PyTypeObject pyhbac_hbacrequest_element_type = {
.tp_basicsize = sizeof(HbacRequestElement),
};
static void
{
if (!el) return;
PyMem_Free(el);
}
static struct hbac_request_element *
{
(PyObject *) &pyhbac_hbacrequest_element_type)) {
"The element must be of type HbacRequestElement\n");
goto fail;
}
if (!el) {
goto fail;
}
return NULL;
}
goto fail;
}
goto fail;
}
return el;
fail:
return NULL;
}
/* ==================== HBAC Request ========================*/
typedef struct {
} HbacRequest;
static PyObject *
{
return NULL;
}
return NULL;
}
}
static int
{
return 0;
}
static void
{
}
static int
{
return 0;
}
static int
{
empty_tuple = PyTuple_New(0);
if (!empty_tuple) {
return -1;
}
return -1;
}
return 0;
}
"evaluate(rules) -> int\n\n"
"Evaluate a set of HBAC rules.\n"
"rules is a sequence of HbacRule objects. The returned value describes\n"
"the result of evaluation and will have one of HBAC_EVAL_* values.\n"
"Use hbac_result_string() to get textual representation of the result\n"
"On error, HbacError exception is raised.\n"
"If HBAC_EVAL_ALLOW is returned, the class attribute rule_name would\n"
"contain the name of the rule that matched. Otherwise, the attribute\n"
"contains None\n");
static struct hbac_eval_req *
static void
{
int i;
if (!rules) return;
for(i=0; rules[i]; i++) {
free_hbac_rule(rules[i]);
}
}
static void
static PyObject *
{
enum hbac_eval_result eres;
long i;
goto fail;
}
if (!PySequence_Check(py_rules_list)) {
"The parameter rules must be a sequence\n");
goto fail;
}
if (!rules) {
goto fail;
}
for (i=0; i < num_rules; i++) {
if (!PyObject_IsInstance(py_rule,
(PyObject *) &pyhbac_hbacrule_type)) {
"A rule must be of type HbacRule\n");
goto fail;
}
if (!rules[i]) {
/* Make sure there is at least a generic exception */
if (!PyErr_Occurred()) {
"Could not convert HbacRule to native type\n");
}
goto fail;
}
}
if (!hbac_req) {
if (!PyErr_Occurred()) {
"Could not convert HbacRequest to native type\n");
}
goto fail;
}
switch (eres) {
case HBAC_EVAL_ALLOW:
goto fail;
}
/* FALLTHROUGH */
case HBAC_EVAL_DENY:
break;
case HBAC_EVAL_ERROR:
goto fail;
case HBAC_EVAL_OOM:
goto fail;
}
return ret;
fail:
return NULL;
}
static PyObject *
{
return Py_None;
}
return NULL;
}
static PyObject *
{
"targethost %s srchost %s>");
return NULL;
}
return NULL;
}
return NULL;
}
return o;
}
static PyMethodDef py_hbac_request_methods[] = {
{ sss_py_const_p(char, "evaluate"),
},
};
"(HbacRequestElement) This is a list of service DNs to check, it must\n"
"consist of the actual service requested, as well as all parent groups\n"
"containing that service");
"(HbacRequestElement) This is a list of user DNs to check, it must consist\n"
"of the actual user requested, as well as all parent groups containing\n"
"that user.");
"(HbacRequestElement) This is a list of target hosts to check, it must\n"
"consist of the actual target host requested, as well as all parent groups\n"
"containing that target host.");
"(HbacRequestElement) This is a list of source hosts to check, it must\n"
"consist of the actual source host requested, as well as all parent groups\n"
"containing that source host.");
static PyMemberDef py_hbac_request_members[] = {
};
"(string) If result of evaluation was to allow access, this member contains\n"
"the name of the rule that allowed it. Otherwise, this attribute contains \n"
"None. This attribute is read-only.\n");
static PyGetSetDef py_hbac_request_getset[] = {
{ discard_const_p(char, "rule_name"),
NULL, /* read only */
NULL },
};
"IPA HBAC Request\n\n"
"HbacRequest() -> new empty HBAC request");
static PyTypeObject pyhbac_hbacrequest_type = {
.tp_basicsize = sizeof(HbacRequest),
};
static void
{
if (!req) return;
}
static struct hbac_eval_req *
{
if (!req) {
goto fail;
}
(PyObject *) &pyhbac_hbacrequest_type)) {
"The request must be of type HbacRequest\n");
goto fail;
}
goto fail;
}
return req;
fail:
return NULL;
}
/* =================== the pyhbac module initialization =====================*/
"hbac_result_string(code) -> string\n"
"Returns a string representation of the HBAC result code");
static PyObject *
{
enum hbac_eval_result result;
const char *str;
return NULL;
}
/* None needs to be referenced, too */
return Py_None;
}
return sss_python_unicode_from_string(str);
}
"hbac_error_string(code) -> string\n"
"Returns a string representation of the HBAC error code");
static PyObject *
{
enum hbac_error_code code;
const char *str;
return NULL;
}
/* None needs to be referenced, too */
return Py_None;
}
return sss_python_unicode_from_string(str);
}
static PyMethodDef pyhbac_module_methods[] = {
{ sss_py_const_p(char, "hbac_result_string"),
},
{ sss_py_const_p(char, "hbac_error_string"),
},
};
"An HBAC processing exception\n\n"
"This exception is raised when there is an internal error during the\n"
"HBAC processing, such as an Out-Of-Memory situation or unparseable\n"
"rule. HbacError.args argument is a tuple that contains error code and\n"
"the name of the rule that was being processed. Use hbac_error_string()\n"
"to get the text representation of the HBAC error");
#ifdef IS_PY3K
static struct PyModuleDef pyhbacdef = {
NULL,
-1,
NULL,
NULL,
NULL,
};
PyInit_pyhbac(void)
#else
initpyhbac(void)
#endif
{
PyObject *m;
int ret;
#ifdef IS_PY3K
m = PyModule_Create(&pyhbacdef);
#else
#endif
if (m == NULL) MODINITERROR;
/* The HBAC module exception */
discard_const_p(char, "hbac.HbacError"),
/* HBAC rule categories */
/* HBAC rule elements */
/* enum hbac_eval_result */
/* enum hbac_error_code */
#ifdef IS_PY3K
return m;
#endif
}