Commit 2945af40 authored by ale's avatar ale

Switch from SWIG to a native Python module

The native Python module implements a narrower interface and is much
simpler than the SWIG-wrapped version (the Python sso module API stays
the same).

The native Python module supports Python 3.
parent cf9b7be3
......@@ -84,13 +84,11 @@ if test "$build_pam_sso" != "no" ; then
fi
AM_CONDITIONAL(ENABLE_PAM_SSO, [ test "$build_pam_sso" != "no" ])
dnl SWIG
dnl AC_PROG_SWIG(1.3.17)
AX_PKG_SWIG(1.3.17)
AX_SWIG_ENABLE_CXX
AX_SWIG_MULTI_MODULE_SUPPORT
AX_SWIG_PYTHON
AM_CONDITIONAL(SWIG, [ test -n "$SWIG" && $SWIG -version >/dev/null 2>&1 ])
dnl Python-dev (actually only used for $PYTHON)
AX_PYTHON_DEVEL
dnl nosetests
AC_PATH_PROG([NOSETESTS], [nosetests])
dnl GoogleTest (use the embedded version)
GTEST_LIBS="\$(top_builddir)/lib/gtest/libgtest.la"
......
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PKG_SWIG([major.minor.micro], [action-if-found], [action-if-not-found])
#
# DESCRIPTION
#
# This macro searches for a SWIG installation on your system. If found,
# then SWIG is AC_SUBST'd; if not found, then $SWIG is empty. If SWIG is
# found, then SWIG_LIB is set to the SWIG library path, and AC_SUBST'd.
#
# You can use the optional first argument to check if the version of the
# available SWIG is greater than or equal to the value of the argument. It
# should have the format: N[.N[.N]] (N is a number between 0 and 999. Only
# the first N is mandatory.) If the version argument is given (e.g.
# 1.3.17), AX_PKG_SWIG checks that the swig package is this version number
# or higher.
#
# As usual, action-if-found is executed if SWIG is found, otherwise
# action-if-not-found is executed.
#
# In configure.in, use as:
#
# AX_PKG_SWIG(1.3.17, [], [ AC_MSG_ERROR([SWIG is required to build..]) ])
# AX_SWIG_ENABLE_CXX
# AX_SWIG_MULTI_MODULE_SUPPORT
# AX_SWIG_PYTHON
#
# LICENSE
#
# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
# Copyright (c) 2011 Murray Cumming <murrayc@openismus.com>
#
# 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 2 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/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 8
AC_DEFUN([AX_PKG_SWIG],[
# Ubuntu has swig 2.0 as /usr/bin/swig2.0
AC_PATH_PROGS([SWIG],[swig swig2.0])
if test -z "$SWIG" ; then
m4_ifval([$3],[$3],[:])
elif test -n "$1" ; then
AC_MSG_CHECKING([SWIG version])
[swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
AC_MSG_RESULT([$swig_version])
if test -n "$swig_version" ; then
# Calculate the required version number components
[required=$1]
[required_major=`echo $required | sed 's/[^0-9].*//'`]
if test -z "$required_major" ; then
[required_major=0]
fi
[required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
[required_minor=`echo $required | sed 's/[^0-9].*//'`]
if test -z "$required_minor" ; then
[required_minor=0]
fi
[required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
[required_patch=`echo $required | sed 's/[^0-9].*//'`]
if test -z "$required_patch" ; then
[required_patch=0]
fi
# Calculate the available version number components
[available=$swig_version]
[available_major=`echo $available | sed 's/[^0-9].*//'`]
if test -z "$available_major" ; then
[available_major=0]
fi
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
[available_minor=`echo $available | sed 's/[^0-9].*//'`]
if test -z "$available_minor" ; then
[available_minor=0]
fi
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
[available_patch=`echo $available | sed 's/[^0-9].*//'`]
if test -z "$available_patch" ; then
[available_patch=0]
fi
# Convert the version tuple into a single number for easier comparison.
# Using base 100 should be safe since SWIG internally uses BCD values
# to encode its version number.
required_swig_vernum=`expr $required_major \* 10000 \
\+ $required_minor \* 100 \+ $required_patch`
available_swig_vernum=`expr $available_major \* 10000 \
\+ $available_minor \* 100 \+ $available_patch`
if test $available_swig_vernum -lt $required_swig_vernum; then
AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version.])
SWIG=''
m4_ifval([$3],[$3],[])
else
AC_MSG_CHECKING([for SWIG library])
SWIG_LIB=`$SWIG -swiglib`
AC_MSG_RESULT([$SWIG_LIB])
m4_ifval([$2],[$2],[])
fi
else
AC_MSG_WARN([cannot determine SWIG version])
SWIG=''
m4_ifval([$3],[$3],[])
fi
fi
AC_SUBST([SWIG_LIB])
])
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_swig_enable_cxx.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_SWIG_ENABLE_CXX
#
# DESCRIPTION
#
# Enable SWIG C++ support. This affects all invocations of $(SWIG).
#
# LICENSE
#
# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
#
# 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 2 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/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 6
AU_ALIAS([SWIG_ENABLE_CXX], [AX_SWIG_ENABLE_CXX])
AC_DEFUN([AX_SWIG_ENABLE_CXX],[
AC_REQUIRE([AX_PKG_SWIG])
AC_REQUIRE([AC_PROG_CXX])
SWIG="$SWIG -c++"
])
# ================================================================================
# http://www.gnu.org/software/autoconf-archive/ax_swig_multi_module_support.html
# ================================================================================
#
# SYNOPSIS
#
# AX_SWIG_MULTI_MODULE_SUPPORT
#
# DESCRIPTION
#
# Enable support for multiple modules. This effects all invocations of
# $(SWIG). You have to link all generated modules against the appropriate
# SWIG runtime library. If you want to build Python modules for example,
# use the AX_SWIG_PYTHON macro and link the modules against
# $(AX_SWIG_PYTHON_LIBS).
#
# LICENSE
#
# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
#
# 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 2 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/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 7
AU_ALIAS([SWIG_MULTI_MODULE_SUPPORT], [AX_SWIG_MULTI_MODULE_SUPPORT])
AC_DEFUN([AX_SWIG_MULTI_MODULE_SUPPORT],[
AC_REQUIRE([AX_PKG_SWIG])
SWIG="$SWIG -noruntime"
])
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_swig_python.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_SWIG_PYTHON([use-shadow-classes = {no, yes}])
#
# DESCRIPTION
#
# Checks for Python and provides the $(AX_SWIG_PYTHON_CPPFLAGS), and
# $(AX_SWIG_PYTHON_OPT) output variables.
#
# $(AX_SWIG_PYTHON_OPT) contains all necessary SWIG options to generate
# code for Python. Shadow classes are enabled unless the value of the
# optional first argument is exactly 'no'. If you need multi module
# support (provided by the AX_SWIG_MULTI_MODULE_SUPPORT macro) use
# $(AX_SWIG_PYTHON_LIBS) to link against the appropriate library. It
# contains the SWIG Python runtime library that is needed by the type
# check system for example.
#
# LICENSE
#
# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
#
# 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 2 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/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 7
AU_ALIAS([SWIG_PYTHON], [AX_SWIG_PYTHON])
AC_DEFUN([AX_SWIG_PYTHON],[
AC_REQUIRE([AX_PKG_SWIG])
AC_REQUIRE([AX_PYTHON_DEVEL])
test "x$1" != "xno" || swig_shadow=" -noproxy"
AC_SUBST([AX_SWIG_PYTHON_OPT],[-python$swig_shadow])
AC_SUBST([AX_SWIG_PYTHON_CPPFLAGS],[$PYTHON_CPPFLAGS])
])
......@@ -7,9 +7,7 @@ if ENABLE_PAM_SSO
PAM_SSO_SUBDIR = pam_sso
endif
if SWIG
PYTHON_SUBDIR = python sso_server
endif
SUBDIRS = \
sso \
......
......@@ -15,10 +15,10 @@ check-local:
env \
LD_LIBRARY_PATH=$(top_builddir)/src/sso/.libs \
DYLD_LIBRARY_PATH=$(top_builddir)/src/sso/.libs \
nosetests -v
$(NOSETESTS) -v
clean-local:
-rm -f sso/sso_c.py sso/sso_wrap.cpp $(wildcard sso/_sso_c.*so)
-rm -f $(wildcard sso/_pysso*.so)
$(PYTHON_SETUP_PY) clean --all
install-exec-local:
......
......@@ -10,7 +10,7 @@ top_srcdir = os.path.join(SRCDIR, '..')
# If BUILD_MODULE is not defined, bundle libsso into the Python
# extension so that this package is pip-installable directly.
ext_sources = ['sso/sso.i']
ext_sources = ['sso/sso_python.c']
libraries = ['sso']
if not os.getenv('BUILD_MODULE'):
ext_sources.extend(os.path.join(top_srcdir, 'sso', x) for x in [
......@@ -28,8 +28,8 @@ class build_py(_build_py):
setup(name='sso',
cmdclass={'build_py': build_py},
ext_modules=[Extension('sso._sso_c', ext_sources,
swig_opts=['-modern', '-I' + top_srcdir, '-py3'],
ext_modules=[Extension('sso._pysso', ext_sources,
#swig_opts=['-modern', '-I' + top_srcdir, '-py3'],
include_dirs=[top_srcdir],
libraries=libraries,
library_dirs=[SSO_LIB_DIR],
......
_sso_c.so
sso_c.py
sso_wrap.c
*.so
# Python 3 compatibility for basestring check as used in isinstance() below.
try:
basestring
except NameError:
basestring = (str, bytes)
from .sso_c import sso_generate_keys as generate_keys
from .sso_c import sso_ticket_new, sso_ticket_free, \
sso_ticket_sign, sso_ticket_open, sso_strerror, \
sso_validate
class Error(Exception):
def __init__(self, code):
self.code = code
Exception.__init__(self, sso_strerror(code))
import time
from ._pysso import generate_keys, create_and_sign_ticket, verify_ticket, error
Error = error
# Ticket is just a simple container for ticket attributes.
class Ticket(object):
def __init__(self, tkt_or_user=None, service=None, domain=None,
nonce=None, groups=None, ttl=3600):
# Fix old constructor behavior with positional args.
if isinstance(groups, int):
ttl = groups
groups = None
if tkt_or_user is None or isinstance(tkt_or_user, basestring):
self._tkt = sso_ticket_new(
tkt_or_user, service, domain, nonce, groups, ttl)
else:
self._tkt = tkt_or_user
def __del__(self):
if hasattr(self, '_tkt'):
sso_ticket_free(self._tkt)
def __init__(self, user, service, domain, nonce=None, groups=None, ttl=3600, expires=None):
self._user = user
self._service = service
self._domain = domain
self._nonce = nonce
self._groups = groups
# 'expires' has precedence over 'ttl'.
if expires is None:
expires = int(time.time()) + ttl
self._expires = expires
def __eq__(self, t2):
return (self.user() == t2.user() and
self.service() == t2.service() and
self.domain() == t2.domain() and
self.expires() == t2.expires())
self.nonce() == t2.nonce())
def empty(self):
return (not self._tkt.user and not self._tkt.domain
and not self._tkt.service)
return (not self._user and not self._domain
and not self._service)
def user(self):
return self._tkt.user
return self._user
def domain(self):
return self._tkt.domain
return self._domain
def service(self):
return self._tkt.service
return self._service
def nonce(self):
return self._tkt.nonce
return self._nonce
def groups(self):
return self._tkt.groups
return self._groups
def expires(self):
return self._tkt.expires
return self._expires
def ttl(self):
return int(self._expires - time.time())
class Signer(object):
......@@ -70,10 +55,15 @@ class Signer(object):
self._sk = sk
def sign(self, t):
r, signed = sso_ticket_sign(t._tkt, self._sk)
if r != 0:
raise Error(r)
return signed
return create_and_sign_ticket(
self._sk,
t.user(),
t.service(),
t.domain(),
t.nonce(),
t.groups(),
t.ttl(),
)
class Verifier(object):
......@@ -85,10 +75,12 @@ class Verifier(object):
self._ok_groups = ok_groups
def verify(self, encoded_tkt, nonce=None):
r, tkt = sso_ticket_open(encoded_tkt, self._pk)
if r != 0:
raise Error(r)
r = sso_validate(tkt, self._service, self._domain, nonce, self._ok_groups)
if r != 0:
raise Error(r)
return Ticket(tkt)
result = verify_ticket(self._pk, encoded_tkt, self._service, self._domain, nonce, self._ok_groups)
return Ticket(
result['user'],
self._service,
self._domain,
nonce,
result['groups'],
result['expires'],
)
/*
Unix SMB/CIFS implementation.
Python 3 compatibility macros
Copyright (C) Petr Viktorin <pviktori@redhat.com> 2015
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/>.
*/
#ifndef _SAMBA_PY3COMPAT_H_
#define _SAMBA_PY3COMPAT_H_
#include <Python.h>
/* Quick docs:
*
* The IS_PY3 preprocessor constant is 1 on Python 3, and 0 on Python 2.
*
* "PyStr_*" works like PyUnicode_* on Python 3, but uses bytestrings (str)
* under Python 2.
*
* "PyBytes_*" work like in Python 3; on Python 2 they are aliased to their
* PyString_* names.
*
* "PyInt_*" works like PyLong_*
*
* Syntax for module initialization is as in Python 3, except the entrypoint
* function definition and declaration:
* PyMODINIT_FUNC PyInit_modulename(void);
* PyMODINIT_FUNC PyInit_modulename(void)
* {
* ...
* }
* is replaced by:
* MODULE_INIT_FUNC(modulename)
* {
* ...
* }
*
* In the entrypoint, create a module using PyModule_Create and PyModuleDef,
* and return it. See Python 3 documentation for details.
* For Python 2 compatibility, always set PyModuleDef.m_size to -1.
*
*/
#if PY_MAJOR_VERSION >= 3
/***** Python 3 *****/
#define IS_PY3 1
/* Strings */
#define PyStr_Type PyUnicode_Type
#define PyStr_Check PyUnicode_Check
#define PyStr_CheckExact PyUnicode_CheckExact
#define PyStr_FromString PyUnicode_FromString
#define PyStr_FromStringAndSize PyUnicode_FromStringAndSize
#define PyStr_FromFormat PyUnicode_FromFormat
#define PyStr_FromFormatV PyUnicode_FromFormatV
#define PyStr_AsString PyUnicode_AsUTF8
#define PyStr_Concat PyUnicode_Concat
#define PyStr_Format PyUnicode_Format
#define PyStr_InternInPlace PyUnicode_InternInPlace
#define PyStr_InternFromString PyUnicode_InternFromString
#define PyStr_Decode PyUnicode_Decode
#define PyStr_AsUTF8String PyUnicode_AsUTF8String // returns PyBytes
#define PyStr_AsUTF8 PyUnicode_AsUTF8
#define PyStr_AsUTF8AndSize PyUnicode_AsUTF8AndSize
/* description of bytes and string objects */
#define PY_DESC_PY3_BYTES "bytes"
#define PY_DESC_PY3_STRING "string"
/* Determine if object is really bytes, for code that runs
* in python2 & python3 (note: PyBytes_Check is replaced by
* PyString_Check in python2) so care needs to be taken when
* writing code that will check if incoming type is bytes that
* will work as expected in python2 & python3
*/
#define IsPy3Bytes PyBytes_Check
#define IsPy3BytesOrString(pystr) \
(PyStr_Check(pystr) || PyBytes_Check(pystr))
#else
/***** Python 2 *****/
#define IS_PY3 0
/* Strings */
#define PyStr_Type PyString_Type
#define PyStr_Check PyString_Check
#define PyStr_CheckExact PyString_CheckExact
#define PyStr_FromString PyString_FromString
#define PyStr_FromStringAndSize PyString_FromStringAndSize
#define PyStr_FromFormat PyString_FromFormat
#define PyStr_FromFormatV PyString_FromFormatV
#define PyStr_AsString PyString_AsString
#define PyStr_Format PyString_Format
#define PyStr_InternInPlace PyString_InternInPlace
#define PyStr_InternFromString PyString_InternFromString
#define PyStr_Decode PyString_Decode
#define PyStr_AsUTF8String(str) (Py_INCREF(str), (str))
#define PyStr_AsUTF8 PyString_AsString
#define PyStr_AsUTF8AndSize(pystr, sizeptr) \
((*sizeptr=PyString_Size(pystr)), PyString_AsString(pystr))
#define PyBytes_Type PyString_Type
#define PyBytes_Check PyString_Check
#define PyBytes_CheckExact PyString_CheckExact
#define PyBytes_FromString PyString_FromString
#define PyBytes_FromStringAndSize PyString_FromStringAndSize
#define PyBytes_FromFormat PyString_FromFormat
#define PyBytes_FromFormatV PyString_FromFormatV
#define PyBytes_Size PyString_Size
#define PyBytes_GET_SIZE PyString_GET_SIZE
#define PyBytes_AsString PyString_AsString
#define PyBytes_AS_STRING PyString_AS_STRING
#define PyBytes_AsStringAndSize PyString_AsStringAndSize
#define PyBytes_Concat PyString_Concat
#define PyBytes_ConcatAndDel PyString_ConcatAndDel
#define _PyBytes_Resize _PyString_Resize
/* description of bytes and string objects */
#define PY_DESC_PY3_BYTES "string"
#define PY_DESC_PY3_STRING "unicode"
/* Determine if object is really bytes, for code that runs
* in python2 & python3 (note: PyBytes_Check is replaced by
* PyString_Check in python2) so care needs to be taken when
* writing code that will check if incoming type is bytes that
* will work as expected in python2 & python3
*/
#define IsPy3Bytes(pystr) false
#define IsPy3BytesOrString PyStr_Check
/* PyArg_ParseTuple/Py_BuildValue argument */
#define PYARG_BYTES_LEN "s#"
/*
* We want a format that will ensure unicode is encoded using the
* specified encoding 'utf8' (to obtain the char* array)
* In python3 we use "es" but in python2 the specifiying 'es' will
* result in the any incomming 'str' type being decoded first to ascii
* then encoded to the specified 'utf8' encoding. In order to avoid that
* we use format 'et' in python2 instead.
*/
#define PYARG_STR_UNI "et"
/* Module init */
#define PyModuleDef_HEAD_INIT 0
typedef struct PyModuleDef {
int m_base;
const char* m_name;
const char* m_doc;
Py_ssize_t m_size;
PyMethodDef *m_methods;
} PyModuleDef;
#define PyModule_Create(def) \
Py_InitModule3((def)->m_name, (def)->m_methods, (def)->m_doc)
#define MODULE_INIT_FUNC(name) \
static PyObject *PyInit_ ## name(void); \
void init ## name(void); \
void init ## name(void) { PyInit_ ## name(); } \
static PyObject *PyInit_ ## name(void)
#endif
#endif
%module sso_c
//%include "typemaps.i"
%{
#include "sso/sso.h"
%}
// convert time_t to python ints
%typemap(out) time_t {
$result = PyInt_FromLong((int)$1);
}
// convert unsigned char * to Python strings.
%typemap(out) unsigned char * {
$result = PyString_FromString((char *)$1);
}
// convert Python string to unsigned char *
%typemap(in) unsigned char * {
$1 = (unsigned char *)PyString_AsString($input);
}
// typemaps for groups
%typemap(typecheck,precedence=SWIG_TYPECHECK_STRING) char ** {
PyObject *iter = PyObject_GetIter($input);
if (!iter) {
$1 = 0;
} else {
Py_DECREF(iter);
$1 = 1;
}
}
// groups as input
%typemap(in) char ** {
if ($input == Py_None) {
$1 = NULL;
} else {
int bufalloc = 8, i = 0;
char **buf = (char **)malloc(sizeof(char *)*bufalloc);
PyObject *iter = PyObject_GetIter($input);
PyObject *item;
while ((item = PyIter_Next(iter))) {
buf[i++] = PyString_AsString(item);
if (i >= bufalloc - 1) {
bufalloc *= 2;
buf = (char **)realloc(buf, sizeof(char *)*bufalloc);
}
Py_DECREF(item);
}
buf[i] = NULL;
Py_DECREF(iter);
$1 = buf;