summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2011-07-12 21:22:22 +0200
committerStephen Gallagher <sgallagh@redhat.com>2011-07-13 11:00:47 -0400
commit72e60fd4eabcfbcdbfe01e8c38b94052bc6c2067 (patch)
tree6702b1ff93ef9b3fd66ff5b921bb9732bd7f96a0
parent22d268c88f6d324b3a66846af007b06488eddae7 (diff)
downloadsssd-72e60fd4eabcfbcdbfe01e8c38b94052bc6c2067.tar.gz
sssd-72e60fd4eabcfbcdbfe01e8c38b94052bc6c2067.tar.xz
sssd-72e60fd4eabcfbcdbfe01e8c38b94052bc6c2067.zip
Fix python HBAC bindings for python <= 2.4
Several parts of the HBAC python bindings did not work with old Python versions, such as the one shipped in RHEL5. The changes include: * a compatibility wrapper around python set object * PyModule_AddIntMacro compat macro * Py_ssize_t compat definition * Do not use PyUnicode_FromFormat * several function prototypes and structures used to have "char arguments where they have "const char *" in recent versions. This caused compilation warnings this patch mitigates by using the discard_const hack on python 2.4
-rw-r--r--Makefile.am4
-rw-r--r--configure.ac1
-rw-r--r--src/external/python.m420
-rw-r--r--src/python/pyhbac.c201
-rwxr-xr-xsrc/tests/pyhbac-test.py7
-rw-r--r--src/util/sss_python.c104
-rw-r--r--src/util/sss_python.h63
7 files changed, 315 insertions, 85 deletions
diff --git a/Makefile.am b/Makefile.am
index 1eb2e7a7f..6829788ae 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -283,6 +283,7 @@ dist_noinst_HEADERS = \
src/util/util.h \
src/util/strtonum.h \
src/util/sss_ldap.h \
+ src/util/sss_python.h \
src/util/sss_krb5.h \
src/util/refcount.h \
src/util/find_uid.h \
@@ -1019,7 +1020,8 @@ pysss_la_LDFLAGS = \
-module
pyhbac_la_SOURCES = \
- src/python/pyhbac.c
+ src/python/pyhbac.c \
+ src/util/sss_python.c
pyhbac_la_CFLAGS = \
$(AM_CFLAGS) \
$(PYTHON_CFLAGS)
diff --git a/configure.ac b/configure.ac
index 2cf3137f8..0e2e6d44a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -150,6 +150,7 @@ if test x$HAVE_PYTHON_BINDINGS != x; then
AM_CHECK_PYTHON_HEADERS([],
AC_MSG_ERROR([Could not find python headers]))
AM_PYTHON_CONFIG
+ AM_CHECK_PYTHON_COMPAT
fi
if test x$HAVE_SELINUX != x; then
diff --git a/src/external/python.m4 b/src/external/python.m4
index db5986385..00487a746 100644
--- a/src/external/python.m4
+++ b/src/external/python.m4
@@ -56,3 +56,23 @@ AC_DEFUN([AM_CHECK_PYTHON_HEADERS],
])
+dnl Checks for a couple of functions we use that may not be defined
+dnl in some older python versions used e.g. on RHEL5
+AC_DEFUN([AM_CHECK_PYTHON_COMPAT],
+[AC_REQUIRE([AM_CHECK_PYTHON_HEADERS])
+ save_CPPFLAGS="$CPPFLAGS"
+ save_LIBS="$LIBS"
+ CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES"
+ LIBS="$LIBS $PYTHON_LIBS"
+
+ AC_CHECK_TYPE(Py_ssize_t,
+ [ AC_DEFINE_UNQUOTED(HAVE_PY_SSIZE_T, 1, [Native Py_ssize_t type]) ],
+ [],
+ [[#include <Python.h>]])
+
+ AC_CHECK_FUNCS([PySet_New PySet_Add PyErr_NewExceptionWithDoc])
+ AC_CHECK_DECLS([PySet_Check, PyModule_AddIntMacro, PyUnicode_FromString], [], [], [[#include <Python.h>]])
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LIBS="$save_LIBS"
+])
diff --git a/src/python/pyhbac.c b/src/python/pyhbac.c
index 85d2f3fdf..4c606dd64 100644
--- a/src/python/pyhbac.c
+++ b/src/python/pyhbac.c
@@ -22,18 +22,16 @@
#include <structmember.h>
#include "util/util.h"
+#include "util/sss_python.h"
#include "providers/ipa/ipa_hbac.h"
#define PYTHON_MODULE_NAME "pyhbac"
-#define TYPE_READY(module, type, name) do { \
- if (PyType_Ready(&type) < 0) \
- return; \
- Py_INCREF(&type); \
- PyModule_AddObject(module, \
- discard_const_p(char, name), \
- (PyObject *) &type); \
-} while(0); \
+#ifndef PYHBAC_ENCODING
+#define PYHBAC_ENCODING "UTF-8"
+#endif
+
+#define PYHBAC_ENCODING_ERRORS "strict"
#define CHECK_ATTRIBUTE_DELETE(attr, attrname) do { \
if (attr == NULL) { \
@@ -44,14 +42,6 @@
} \
} while(0);
-#define SAFE_SET(old, new) do { \
- PyObject *__simple_set_tmp = NULL; \
- __simple_set_tmp = old; \
- Py_INCREF(new); \
- old = new; \
- Py_XDECREF(__simple_set_tmp); \
-} while(0);
-
static PyObject *PyExc_HbacError;
/* ==================== Utility functions ========================*/
@@ -284,7 +274,7 @@ static void
set_hbac_exception(PyObject *exc, struct hbac_info *error)
{
PyErr_SetObject(exc,
- Py_BuildValue("(i,s)",
+ Py_BuildValue(sss_py_const_p(char, "(i,s)"),
error->code,
error->rule_name ? \
error->rule_name : "no rule"));
@@ -310,7 +300,7 @@ HbacRuleElement_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
- self->category = PySet_New(NULL);
+ self->category = sss_python_set_new();
self->names = PyList_New(0);
self->groups = PyList_New(0);
if (!self->names || !self->groups || !self->category) {
@@ -367,7 +357,7 @@ HbacRuleElement_init(HbacRuleElement *self, PyObject *args, PyObject *kwargs)
PyObject *tmp = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
- "|OOO",
+ sss_py_const_p(char, "|OOO"),
discard_const_p(char *, kwlist),
&names, &groups, &category)) {
return -1;
@@ -395,7 +385,7 @@ HbacRuleElement_init(HbacRuleElement *self, PyObject *args, PyObject *kwargs)
return -1;
}
- if (PySet_Add(self->category, tmp) != 0) {
+ if (sss_python_set_add(self->category, tmp) != 0) {
return -1;
}
}
@@ -458,7 +448,7 @@ hbac_rule_element_set_category(HbacRuleElement *self,
CHECK_ATTRIBUTE_DELETE(category, "category");
- if (!PySet_Check(category)) {
+ if (!sss_python_set_check(category)) {
PyErr_Format(PyExc_TypeError, "The category must be a set type\n");
return -1;
}
@@ -497,7 +487,12 @@ HbacRuleElement_repr(HbacRuleElement *self)
char *strnames = NULL;
char *strgroups = NULL;
uint32_t category;
- PyObject *o;
+ PyObject *o, *format, *args;
+
+ format = sss_python_unicode_from_string("<category %lu names [%s] groups [%s]>");
+ if (format == NULL) {
+ return NULL;
+ }
strnames = str_concat_sequence(self->names,
discard_const_p(char, ","));
@@ -507,13 +502,25 @@ HbacRuleElement_repr(HbacRuleElement *self)
if (strnames == NULL || strgroups == NULL || category == -1) {
PyMem_Free(strnames);
PyMem_Free(strgroups);
+ Py_DECREF(format);
+ return NULL;
+ }
+
+ args = Py_BuildValue(sss_py_const_p(char, "Kss"),
+ (unsigned long long ) category,
+ strnames, strgroups);
+ if (args == NULL) {
+ PyMem_Free(strnames);
+ PyMem_Free(strgroups);
+ Py_DECREF(format);
return NULL;
}
- o = PyUnicode_FromFormat("<category %lu names [%s] groups [%s]>",
- category, strnames, strgroups);
+ o = PyUnicode_Format(format, args);
PyMem_Free(strnames);
PyMem_Free(strgroups);
+ Py_DECREF(format);
+ Py_DECREF(args);
return o;
}
@@ -554,7 +561,7 @@ PyDoc_STRVAR(HbacRuleElement__doc__,
static PyTypeObject pyhbac_hbacrule_element_type = {
PyObject_HEAD_INIT(NULL)
- .tp_name = "pyhbac.HbacRuleElement",
+ .tp_name = sss_py_const_p(char, "pyhbac.HbacRuleElement"),
.tp_basicsize = sizeof(HbacRuleElement),
.tp_new = HbacRuleElement_new,
.tp_dealloc = (destructor) HbacRuleElement_dealloc,
@@ -635,7 +642,7 @@ HbacRule_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
- self->name = PyUnicode_FromString("");
+ self->name = sss_python_unicode_from_string("");
if (self->name == NULL) {
Py_DECREF(self);
PyErr_NoMemory();
@@ -692,11 +699,11 @@ HbacRule_dealloc(HbacRuleObject *self)
static int
HbacRule_traverse(HbacRuleObject *self, visitproc visit, void *arg)
{
- Py_VISIT(self->name);
- Py_VISIT(self->services);
- Py_VISIT(self->users);
- Py_VISIT(self->targethosts);
- Py_VISIT(self->srchosts);
+ Py_VISIT((PyObject *) self->name);
+ Py_VISIT((PyObject *) self->services);
+ Py_VISIT((PyObject *) self->users);
+ Py_VISIT((PyObject *) self->targethosts);
+ Py_VISIT((PyObject *) self->srchosts);
return 0;
}
@@ -711,7 +718,7 @@ HbacRule_init(HbacRuleObject *self, PyObject *args, PyObject *kwargs)
PyObject *empty_tuple = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
- "O|i",
+ sss_py_const_p(char, "O|i"),
discard_const_p(char *, kwlist),
&name, &self->enabled)) {
return -1;
@@ -826,7 +833,8 @@ hbac_rule_get_name(HbacRuleObject *self, void *closure)
Py_INCREF(self->name);
return self->name;
} else if (PyString_Check(self->name)) {
- return PyUnicode_FromObject(self->name);
+ return PyUnicode_FromEncodedObject(self->name,
+ PYHBAC_ENCODING, PYHBAC_ENCODING_ERRORS);
}
/* setter does typechecking but let us be paranoid */
@@ -837,15 +845,16 @@ hbac_rule_get_name(HbacRuleObject *self, void *closure)
static PyObject *
HbacRule_repr(HbacRuleObject *self)
{
- PyObject *utf_name;
PyObject *users_repr;
PyObject *services_repr;
PyObject *targethosts_repr;
PyObject *srchosts_repr;
- PyObject *o;
+ PyObject *o, *format, *args;
- utf_name = get_utf8_string(self->name, "name");
- if (utf_name == NULL) {
+ format = sss_python_unicode_from_string("<name %s enabled %d "
+ "users %s services %s "
+ "targethosts %s srchosts %s>");
+ if (format == NULL) {
return NULL;
}
@@ -855,26 +864,34 @@ HbacRule_repr(HbacRuleObject *self)
srchosts_repr = HbacRuleElement_repr(self->srchosts);
if (users_repr == NULL || services_repr == NULL ||
targethosts_repr == NULL || srchosts_repr == NULL) {
- Py_DECREF(utf_name);
Py_XDECREF(users_repr);
Py_XDECREF(services_repr);
Py_XDECREF(targethosts_repr);
Py_XDECREF(srchosts_repr);
+ Py_DECREF(format);
return NULL;
}
- o = PyUnicode_FromFormat("<name %s enabled %d "
- "users %U services %U "
- "targethosts %U srchosts %U>",
- PyString_AsString(utf_name),
- self->enabled,
- users_repr, services_repr,
- targethosts_repr, srchosts_repr);
- Py_DECREF(utf_name);
+ args = Py_BuildValue(sss_py_const_p(char, "OiOOOO"),
+ self->name, self->enabled,
+ users_repr, services_repr,
+ targethosts_repr, srchosts_repr);
+ if (args == NULL) {
+ Py_DECREF(users_repr);
+ Py_DECREF(services_repr);
+ Py_DECREF(targethosts_repr);
+ Py_DECREF(srchosts_repr);
+ Py_DECREF(format);
+ return NULL;
+ }
+
+ o = PyUnicode_Format(format, args);
Py_DECREF(users_repr);
Py_DECREF(services_repr);
Py_DECREF(targethosts_repr);
Py_DECREF(srchosts_repr);
+ Py_DECREF(format);
+ Py_DECREF(args);
return o;
}
@@ -937,7 +954,7 @@ PyDoc_STRVAR(HbacRuleObject__doc__,
static PyTypeObject pyhbac_hbacrule_type = {
PyObject_HEAD_INIT(NULL)
- .tp_name = "pyhbac.HbacRule",
+ .tp_name = sss_py_const_p(char, "pyhbac.HbacRule"),
.tp_basicsize = sizeof(HbacRuleObject),
.tp_new = HbacRule_new,
.tp_dealloc = (destructor) HbacRule_dealloc,
@@ -1031,7 +1048,7 @@ HbacRequestElement_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
- self->name = PyUnicode_FromString("");
+ self->name = sss_python_unicode_from_string("");
if (self->name == NULL) {
PyErr_NoMemory();
Py_DECREF(self);
@@ -1092,7 +1109,7 @@ HbacRequestElement_init(HbacRequestElement *self,
PyObject *groups = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
- "|OO",
+ sss_py_const_p(char, "|OO"),
discard_const_p(char *, kwlist),
&name, &groups)) {
return -1;
@@ -1136,7 +1153,8 @@ hbac_request_element_get_name(HbacRequestElement *self, void *closure)
Py_INCREF(self->name);
return self->name;
} else if (PyString_Check(self->name)) {
- return PyUnicode_FromObject(self->name);
+ return PyUnicode_FromEncodedObject(self->name,
+ PYHBAC_ENCODING, PYHBAC_ENCODING_ERRORS);
}
/* setter does typechecking but let us be paranoid */
@@ -1169,25 +1187,28 @@ hbac_request_element_get_groups(HbacRequestElement *self, void *closure)
static PyObject *
HbacRequestElement_repr(HbacRequestElement *self)
{
- PyObject *utf_name;
char *strgroups;
- PyObject *o;
+ PyObject *o, *format, *args;
- utf_name = get_utf8_string(self->name, "name");
- if (utf_name == NULL) {
+ format = sss_python_unicode_from_string("<name %s groups [%s]>");
+ if (format == NULL) {
return NULL;
}
strgroups = str_concat_sequence(self->groups, discard_const_p(char, ","));
if (strgroups == NULL) {
- Py_DECREF(utf_name);
+ Py_DECREF(format);
return NULL;
}
- o = PyUnicode_FromFormat("<name %s groups [%s]>",
- PyString_AsString(utf_name), strgroups);
- Py_DECREF(utf_name);
+ args = Py_BuildValue(sss_py_const_p(char, "Os"), self->name, strgroups);
+ if (args == NULL) {
+ }
+
+ o = PyUnicode_Format(format, args);
PyMem_Free(strgroups);
+ Py_DECREF(format);
+ Py_DECREF(args);
return o;
}
@@ -1220,7 +1241,7 @@ PyDoc_STRVAR(HbacRequestElement__doc__,
static PyTypeObject pyhbac_hbacrequest_element_type = {
PyObject_HEAD_INIT(NULL)
- .tp_name = "pyhbac.HbacRequestElement",
+ .tp_name = sss_py_const_p(char, "pyhbac.HbacRequestElement"),
.tp_basicsize = sizeof(HbacRequestElement),
.tp_new = HbacRequestElement_new,
.tp_dealloc = (destructor) HbacRequestElement_dealloc,
@@ -1355,10 +1376,10 @@ HbacRequest_dealloc(HbacRequest *self)
static int
HbacRequest_traverse(HbacRequest *self, visitproc visit, void *arg)
{
- Py_VISIT(self->service);
- Py_VISIT(self->user);
- Py_VISIT(self->targethost);
- Py_VISIT(self->srchost);
+ Py_VISIT((PyObject *) self->service);
+ Py_VISIT((PyObject *) self->user);
+ Py_VISIT((PyObject *) self->targethost);
+ Py_VISIT((PyObject *) self->srchost);
return 0;
}
@@ -1430,7 +1451,7 @@ py_hbac_evaluate(HbacRequest *self, PyObject *args)
PyObject *ret = NULL;
long i;
- if (!PyArg_ParseTuple(args, "O", &py_rules_list)) {
+ if (!PyArg_ParseTuple(args, sss_py_const_p(char, "O"), &py_rules_list)) {
goto fail;
}
@@ -1484,7 +1505,7 @@ py_hbac_evaluate(HbacRequest *self, PyObject *args)
eres = hbac_evaluate(rules, hbac_req, &info);
switch (eres) {
case HBAC_EVAL_ALLOW:
- self->rule_name = PyUnicode_FromString(info->rule_name);
+ self->rule_name = sss_python_unicode_from_string(info->rule_name);
if (!self->rule_name) {
PyErr_NoMemory();
goto fail;
@@ -1535,7 +1556,13 @@ HbacRequest_repr(HbacRequest *self)
PyObject *service_repr;
PyObject *targethost_repr;
PyObject *srchost_repr;
- PyObject *o;
+ PyObject *o, *format, *args;
+
+ format = sss_python_unicode_from_string("<user %s service %s "
+ "targethost %s srchost %s>");
+ if (format == NULL) {
+ return NULL;
+ }
user_repr = HbacRequestElement_repr(self->user);
service_repr = HbacRequestElement_repr(self->service);
@@ -1547,22 +1574,34 @@ HbacRequest_repr(HbacRequest *self)
Py_XDECREF(service_repr);
Py_XDECREF(targethost_repr);
Py_XDECREF(srchost_repr);
+ Py_DECREF(format);
return NULL;
}
- o = PyUnicode_FromFormat("<user %U service %U "
- "targethost %U srchost %U>",
- user_repr, service_repr,
- targethost_repr, srchost_repr);
+ args = Py_BuildValue(sss_py_const_p(char, "OOOO"),
+ user_repr, service_repr,
+ targethost_repr, srchost_repr);
+ if (args == NULL) {
+ Py_DECREF(user_repr);
+ Py_DECREF(service_repr);
+ Py_DECREF(targethost_repr);
+ Py_DECREF(srchost_repr);
+ Py_DECREF(format);
+ }
+
+ o = PyUnicode_Format(format, args);
Py_DECREF(user_repr);
Py_DECREF(service_repr);
Py_DECREF(targethost_repr);
Py_DECREF(srchost_repr);
+ Py_DECREF(format);
+ Py_DECREF(args);
return o;
}
static PyMethodDef py_hbac_request_methods[] = {
- { "evaluate", (PyCFunction) py_hbac_evaluate,
+ { sss_py_const_p(char, "evaluate"),
+ (PyCFunction) py_hbac_evaluate,
METH_VARARGS, py_hbac_evaluate__doc__
},
{ NULL, NULL, 0, NULL } /* Sentinel */
@@ -1626,7 +1665,7 @@ PyDoc_STRVAR(HbacRequest__doc__,
static PyTypeObject pyhbac_hbacrequest_type = {
PyObject_HEAD_INIT(NULL)
- .tp_name = "pyhbac.HbacRequest",
+ .tp_name = sss_py_const_p(char, "pyhbac.HbacRequest"),
.tp_basicsize = sizeof(HbacRequest),
.tp_new = HbacRequest_new,
.tp_dealloc = (destructor) HbacRequest_dealloc,
@@ -1698,7 +1737,7 @@ py_hbac_result_string(PyObject *module, PyObject *args)
enum hbac_eval_result result;
const char *str;
- if (!PyArg_ParseTuple(args, "i", &result)) {
+ if (!PyArg_ParseTuple(args, sss_py_const_p(char, "i"), &result)) {
return NULL;
}
@@ -1709,7 +1748,7 @@ py_hbac_result_string(PyObject *module, PyObject *args)
return Py_None;
}
- return PyUnicode_FromString(str);
+ return sss_python_unicode_from_string(str);
}
PyDoc_STRVAR(py_hbac_error_string__doc__,
@@ -1722,7 +1761,7 @@ py_hbac_error_string(PyObject *module, PyObject *args)
enum hbac_error_code code;
const char *str;
- if (!PyArg_ParseTuple(args, "i", &code)) {
+ if (!PyArg_ParseTuple(args, sss_py_const_p(char, "i"), &code)) {
return NULL;
}
@@ -1733,17 +1772,17 @@ py_hbac_error_string(PyObject *module, PyObject *args)
return Py_None;
}
- return PyUnicode_FromString(str);
+ return sss_python_unicode_from_string(str);
}
static PyMethodDef pyhbac_module_methods[] = {
- { "hbac_result_string",
+ { sss_py_const_p(char, "hbac_result_string"),
(PyCFunction) py_hbac_result_string,
METH_VARARGS,
py_hbac_result_string__doc__,
},
- { "hbac_error_string",
+ { sss_py_const_p(char, "hbac_error_string"),
(PyCFunction) py_hbac_error_string,
METH_VARARGS,
py_hbac_error_string__doc__,
@@ -1766,16 +1805,16 @@ initpyhbac(void)
PyObject *m;
int ret;
- m = Py_InitModule(PYTHON_MODULE_NAME, pyhbac_module_methods);
+ m = Py_InitModule(sss_py_const_p(char, PYTHON_MODULE_NAME), pyhbac_module_methods);
if (m == NULL) return;
/* The HBAC module exception */
- PyExc_HbacError = PyErr_NewExceptionWithDoc(
+ PyExc_HbacError = sss_exception_with_doc(
discard_const_p(char, "hbac.HbacError"),
HbacError__doc__,
PyExc_EnvironmentError, NULL);
Py_INCREF(PyExc_HbacError);
- ret = PyModule_AddObject(m, "HbacError", PyExc_HbacError);
+ ret = PyModule_AddObject(m, sss_py_const_p(char, "HbacError"), PyExc_HbacError);
if (ret == -1) return;
/* HBAC rule categories */
diff --git a/src/tests/pyhbac-test.py b/src/tests/pyhbac-test.py
index b15d16539..b19fe5861 100755
--- a/src/tests/pyhbac-test.py
+++ b/src/tests/pyhbac-test.py
@@ -11,10 +11,10 @@ if not srcdir:
MODPATH = srcdir + "/.libs" #FIXME - is there a way to get this from libtool?
def compat_assertItemsEqual(this, expected_seq, actual_seq, msg=None):
- return self.assertEqual(sorted(expected_seq), sorted(actual_seq))
+ return this.assertEqual(sorted(expected_seq), sorted(actual_seq))
def compat_assertIsInstance(this, obj, cls, msg=None):
- return self.assertTrue(isinstance(obj, cls))
+ return this.assertTrue(isinstance(obj, cls))
# add compat methods for old unittest.TestCase versions
# (python < 2.7, RHEL5 for instance)
@@ -312,7 +312,8 @@ class PyHbacRequestTest(unittest.TestCase):
def testRuleName(self):
req = pyhbac.HbacRequest()
self.assertEqual(req.rule_name, None)
- self.assertRaises(AttributeError, req.__setattr__, "rule_name", "foo")
+ # python 2.4 raises TypError, 2.7 raises AttributeError
+ self.assertRaises((TypeError, AttributeError), req.__setattr__, "rule_name", "foo")
def testEvaluate(self):
name = "someuser"
diff --git a/src/util/sss_python.c b/src/util/sss_python.c
new file mode 100644
index 000000000..19717a55c
--- /dev/null
+++ b/src/util/sss_python.c
@@ -0,0 +1,104 @@
+/*
+ Authors:
+ Jakub Hrozek <jhrozek@redhat.com>
+
+ Copyright (C) 2011 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ 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 "src/util/sss_python.h"
+#include "config.h"
+
+PyObject *
+sss_python_set_new(void)
+{
+#ifdef HAVE_PYSET_NEW
+ return PySet_New(NULL);
+#else
+ return PyObject_CallObject((PyObject *) &PySet_Type, NULL);
+#endif
+}
+
+int
+sss_python_set_add(PyObject *set, PyObject *key)
+{
+#ifdef HAVE_PYSET_ADD
+ return PySet_Add(set, key);
+#else
+ PyObject *pyret;
+ int ret;
+
+ pyret = PyObject_CallMethod(set, sss_py_const_p(char, "add"),
+ sss_py_const_p(char, "O"), key);
+ ret = (pyret == NULL) ? -1 : 0;
+ Py_XDECREF(pyret);
+ return ret;
+#endif
+}
+
+bool
+sss_python_set_check(PyObject *set)
+{
+#if HAVE_DECL_PYSET_CHECK
+ return PySet_Check(set);
+#else
+ return PyObject_TypeCheck(set, &PySet_Type);
+#endif
+}
+
+PyObject *
+sss_python_unicode_from_string(const char *u)
+{
+#ifdef HAVE_PYUNICODE_FROMSTRING
+ return PyUnicode_FromString(u);
+#else
+ return PyUnicode_DecodeUTF8(u, strlen(u), NULL);
+#endif
+}
+
+PyObject *
+sss_exception_with_doc(char *name, char *doc, PyObject *base, PyObject *dict)
+{
+#ifdef HAVE_PYERR_NEWEXCEPTIONWITHDOC
+ return PyErr_NewExceptionWithDoc(name, doc, base, dict);
+#else
+ int result;
+ PyObject *ret = NULL;
+ PyObject *mydict = NULL; /* points to the dict only if we create it */
+ PyObject *docobj;
+
+ if (dict == NULL) {
+ dict = mydict = PyDict_New();
+ if (dict == NULL) {
+ return NULL;
+ }
+ }
+
+ if (doc != NULL) {
+ docobj = PyString_FromString(doc);
+ if (docobj == NULL)
+ goto failure;
+ result = PyDict_SetItemString(dict, "__doc__", docobj);
+ Py_DECREF(docobj);
+ if (result < 0)
+ goto failure;
+ }
+
+ ret = PyErr_NewException(name, base, dict);
+ failure:
+ Py_XDECREF(mydict);
+ return ret;
+#endif
+}
diff --git a/src/util/sss_python.h b/src/util/sss_python.h
new file mode 100644
index 000000000..135c28771
--- /dev/null
+++ b/src/util/sss_python.h
@@ -0,0 +1,63 @@
+#ifndef __SSS_PYTHON_H__
+#define __SSS_PYTHON_H__
+
+#include <Python.h>
+#include <stdbool.h>
+#include "util/util.h"
+
+#if PY_VERSION_HEX < 0x02050000
+#define sss_py_const_p(type, value) discard_const_p(type, (value))
+#else
+#define sss_py_const_p(type, value) (value)
+#endif
+
+/* Py_ssize_t compatibility for python < 2.5 as per
+ * http://www.python.org/dev/peps/pep-0353/ */
+#ifndef HAVE_PY_SSIZE_T
+typedef int Py_ssize_t;
+#endif
+
+#ifndef PY_SSIZE_T_MAX
+#define PY_SSIZE_T_MAX INT_MAX
+#endif
+
+#ifndef PY_SSIZE_T_MIN
+#define PY_SSIZE_T_MIN INT_MIN
+#endif
+
+/* Wrappers providing the subset of C API for python's set objects we use */
+PyObject *sss_python_set_new(void);
+int sss_python_set_add(PyObject *set, PyObject *key);
+bool sss_python_set_check(PyObject *set);
+
+/* Unicode compatibility */
+PyObject *sss_python_unicode_from_string(const char *u);
+
+/* Exceptions compatibility */
+PyObject *
+sss_exception_with_doc(char *name, char *doc, PyObject *base, PyObject *dict);
+
+/* PyModule_AddIntMacro() compatibility */
+#if !HAVE_DECL_PYMODULE_ADDINTMACRO
+#define PyModule_AddIntMacro(m, c) PyModule_AddIntConstant(m, sss_py_const_p(char, #c), c)
+#endif
+
+/* Convenience macros */
+#define TYPE_READY(module, type, name) do { \
+ if (PyType_Ready(&type) < 0) \
+ return; \
+ Py_INCREF(&type); \
+ PyModule_AddObject(module, \
+ discard_const_p(char, name), \
+ (PyObject *) &type); \
+} while(0); \
+
+#define SAFE_SET(old, new) do { \
+ PyObject *__simple_set_tmp = NULL; \
+ __simple_set_tmp = old; \
+ Py_INCREF(new); \
+ old = new; \
+ Py_XDECREF(__simple_set_tmp); \
+} while(0);
+
+#endif /* __SSS_PYTHON_H__ */