This patch adds Python bindings using Cython, see http://www.cython.org
for more information.  There are also some minor tweaks to the build
macros while we are mucking around in macros.mk; nothing major.

Signed-off-by: Paul Moore <[email protected]>
---
 configure                 |   25 ++
 macros.mk                 |   32 ++-
 src/Makefile              |   26 ++
 src/python/.gitignore     |    2 
 src/python/Makefile       |   54 ++++
 src/python/libseccomp.pxd |   93 ++++++++
 src/python/seccomp.pyx    |  546 +++++++++++++++++++++++++++++++++++++++++++++
 src/python/setup.py       |   45 ++++
 8 files changed, 816 insertions(+), 7 deletions(-)
 create mode 100644 src/python/.gitignore
 create mode 100644 src/python/Makefile
 create mode 100644 src/python/libseccomp.pxd
 create mode 100644 src/python/seccomp.pyx
 create mode 100644 src/python/setup.py

diff --git a/configure b/configure
index e11dea6..8866fda 100755
--- a/configure
+++ b/configure
@@ -25,6 +25,7 @@
 opt_prefix="/usr/local"
 opt_libdir=""
 opt_sysinc_seccomp="yes"
+opt_bindings_python="no"
 
 # output files
 cnf_mk_file="configure.mk"
@@ -33,9 +34,15 @@ cnf_h_file="configure.h"
 ####
 # functions
 
+function test_deps() {
+       [[ -z "$1" ]] && return 0
+       which "$1" >& /dev/null && return 0
+       return 1
+}
+
 function verify_deps() {
        [[ -z "$1" ]] && return
-       if ! which "$1" >& /dev/null; then
+       if ! test_deps "$1"; then
                echo "error: install \"$1\" and include it in your \$PATH"
                exit 1
        fi
@@ -54,6 +61,8 @@ Options:
 * installation configuration
   --prefix=PREFIX      installation base [/usr/local]
   --libdir=DIR         library directory [/usr/local/lib]
+* build options
+  --enable-python      build the python bindings, requires cython
 EOF
 }
 
@@ -64,6 +73,7 @@ function msg_summary() {
   installation base:   $opt_prefix
   library directory:   $opt_libdir
   use system includes: $opt_sysinc_seccomp
+  python bindings:     $opt_bindings_python
 EOF
 }
 
@@ -162,7 +172,7 @@ verify_deps getopt
 
 # parse the command line options
 opt_str="$@"
-opt=$(getopt -n "$0" --options "h" --longoptions "help,prefix:,libdir:" -- 
"$@")
+opt=$(getopt -n "$0" --options "h" --longoptions 
"help,prefix:,libdir:,enable-python" -- "$@")
 eval set -- "$opt"
 while [[ $# -gt 0 ]]; do
        case "$1" in
@@ -174,6 +184,10 @@ while [[ $# -gt 0 ]]; do
                opt_libdir="$2"
                shift 2
                ;;
+       --enable-python)
+               opt_bindings_python="yes"
+               shift
+               ;;
        -h|--help)
                msg_usage
                exit 0
@@ -199,6 +213,12 @@ if [[ -e "$opt_libdir" && ! -d "$opt_libdir" ]]; then
        msg_error "libdir ($opt_libdir) is not a directory"
        exit 1
 fi
+if [[ "$opt_bindings_python" = "yes" ]]; then
+       if ! test_deps cython; then
+               msg_error "python bindings require the cython package"
+               exit 1
+       fi
+fi
 
 #
 # automatic configuration
@@ -243,6 +263,7 @@ cnf_header
 cnf_mk_entry "CONF_INSTALL_PREFIX" "$opt_prefix"
 cnf_mk_entry "CONF_INSTALL_LIBDIR" "$opt_libdir"
 cnf_entry "CONF_SYSINC_SECCOMP" "$opt_sysinc_seccomp"
+cnf_entry "CONF_BINDINGS_PYTHON" "$opt_bindings_python"
 
 # configuration footer
 cnf_footer
diff --git a/macros.mk b/macros.mk
index 6162900..5989e05 100644
--- a/macros.mk
+++ b/macros.mk
@@ -63,6 +63,8 @@ MKDIR ?= mkdir
 SED ?= sed
 AWK ?= awk
 
+PYTHON ?= /usr/bin/env python
+
 # we require gcc specific functionality
 GCC ?= gcc
 
@@ -96,10 +98,28 @@ VERSION_HDR = version.h
 # build macros
 #
 
+PY_DISTUTILS = \
+       VERSION_RELEASE="$(VERSION_RELEASE)" \
+       CFLAGS="$(CFLAGS) $(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \
+       $(PYTHON) ./setup.py
+
 ifeq ($(V),0)
-       ARCHIVE = @echo " AR $@ (add/update: $?)";
+       PY_BUILD = @echo " PYTHON build";
 endif
-ARCHIVE += $(AR) -cru $@ $?;
+PY_BUILD += $(PY_DISTUTILS)
+ifeq ($(V),0)
+       PY_BUILD += -q
+endif
+PY_BUILD += build
+
+ifeq ($(V),0)
+       PY_INSTALL = @echo " PYTHON install";
+endif
+PY_INSTALL += $(PY_DISTUTILS)
+ifeq ($(V),0)
+       PY_INSTALL += -q
+endif
+PY_INSTALL += install
 
 ifeq ($(V),0)
        COMPILE = @echo " CC $@";
@@ -112,6 +132,11 @@ endif
 COMPILE_EXEC += $(GCC) $(CFLAGS) $(CPPFLAGS) -o $@ $< $(LDFLAGS);
 
 ifeq ($(V),0)
+       ARCHIVE = @echo " AR $@";
+endif
+ARCHIVE += $(AR) -cru $@ $?;
+
+ifeq ($(V),0)
        LINK_EXEC = @echo " LD $@";
 endif
 LINK_EXEC += $(GCC) $(LDFLAGS) -o $@ $^ $(LIBFLAGS);
@@ -164,7 +189,8 @@ INSTALL_INC_MACRO += \
                        $^ "$(INSTALL_INC_DIR)";
 
 ifeq ($(V),0)
-       INSTALL_MAN3_MACRO = @echo " INSTALL manpages 
($(INSTALL_MAN_DIR)/man3)";
+       INSTALL_MAN3_MACRO = \
+               @echo " INSTALL manpages ($(INSTALL_MAN_DIR)/man3)";
 endif
 INSTALL_MAN3_MACRO += \
                $(INSTALL) -o $(INSTALL_OWNER) -g $(INSTALL_GROUP) \
diff --git a/src/Makefile b/src/Makefile
index 394e21a..f3a192c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -46,12 +46,22 @@ OBJS = \
 DEPS = $(OBJS:%.o=%.d)
 
 #
+# bindings configuration
+#
+
+BINDINGS =
+
+ifeq ($(CONF_BINDINGS_PYTHON), 1)
+       BINDINGS += python
+endif
+
+#
 # targets
 #
 
-.PHONY: all install clean
+.PHONY: all install clean python
 
-all: $(LIB_STATIC) $(LIB_SHARED)
+all: $(LIB_STATIC) $(LIB_SHARED) $(BINDINGS)
 
 -include $(DEPS)
 
@@ -61,8 +71,20 @@ $(LIB_STATIC): $(OBJS)
 $(LIB_SHARED): $(OBJS)
        $(LINK_LIB)
 
+python: $(LIB_STATIC)
+       @$(ECHO) ">> INFO: building in directory $@/ ..."
+       @$(MAKE) -C $@
+
 install: $(LIB_SHARED)
        $(INSTALL_LIB_MACRO)
+       @for dir in $(BINDINGS); do \
+               $(ECHO) ">> INFO: installing from $$dir/"; \
+               $(MAKE) -C $$dir install; \
+       done
 
 clean:
        $(RM) $(DEPS) $(OBJS) $(LIB_STATIC) $(LIB_SHARED)
+       @for dir in $(BINDINGS); do \
+               $(MAKE) -C $$dir clean; \
+       done
+
diff --git a/src/python/.gitignore b/src/python/.gitignore
new file mode 100644
index 0000000..fc8966d
--- /dev/null
+++ b/src/python/.gitignore
@@ -0,0 +1,2 @@
+build
+seccomp.c
diff --git a/src/python/Makefile b/src/python/Makefile
new file mode 100644
index 0000000..3543a65
--- /dev/null
+++ b/src/python/Makefile
@@ -0,0 +1,54 @@
+#
+# Enhanced Seccomp Library Python Bindings Makefile
+#
+# Copyright (c) 2012 Red Hat <[email protected]>
+# Author: Paul Moore <[email protected]>
+#
+
+#
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of version 2.1 of the GNU Lesser General Public License as
+# published by the Free Software Foundation.
+#
+# This library 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 Lesser General Public License
+# for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, see <http://www.gnu.org/licenses>.
+#
+
+#
+# macros
+#
+
+include ../../macros.mk
+
+#
+# configuration
+#
+
+include $(TOPDIR)/version_info.mk
+include $(TOPDIR)/configure.mk
+include $(TOPDIR)/install.mk
+
+LIB_STATIC = ../libseccomp.a
+
+#
+# targets
+#
+
+.PHONY: all install clean
+
+all: build
+
+build: $(LIB_STATIC) libseccomp.pxd seccomp.pyx
+       @$(RM) seccomp.c
+       $(PY_BUILD) && touch build
+
+install: build
+       $(PY_INSTALL) install --prefix=$(DESTDIR)/$(INSTALL_PREFIX)
+
+clean:
+       $(RM) -rf build seccomp.c
diff --git a/src/python/libseccomp.pxd b/src/python/libseccomp.pxd
new file mode 100644
index 0000000..4faed03
--- /dev/null
+++ b/src/python/libseccomp.pxd
@@ -0,0 +1,93 @@
+#
+# Seccomp Library Python Bindings
+#
+# Copyright (c) 2012 Red Hat <[email protected]>
+# Author: Paul Moore <[email protected]>
+#
+
+#
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of version 2.1 of the GNU Lesser General Public License as
+# published by the Free Software Foundation.
+#
+# This library 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 Lesser General Public License
+# for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, see <http://www.gnu.org/licenses>.
+#
+
+from libc.stdint cimport uint8_t, uint32_t, uint64_t
+
+cdef extern from "seccomp.h":
+
+    ctypedef void* scmp_filter_ctx
+
+    cdef enum:
+        SCMP_ARCH_NATIVE
+        SCMP_ARCH_X86
+        SCMP_ARCH_X86_64
+
+    cdef enum scmp_filter_attr:
+        SCMP_FLTATR_ACT_DEFAULT
+        SCMP_FLTATR_ACT_BADARCH
+        SCMP_FLTATR_CTL_NNP
+
+    cdef enum scmp_compare:
+        SCMP_CMP_NE
+        SCMP_CMP_LT
+        SCMP_CMP_LE
+        SCMP_CMP_EQ
+        SCMP_CMP_GE
+        SCMP_CMP_GT
+        SCMP_CMP_MASKED_EQ
+
+    cdef enum:
+        SCMP_ACT_KILL
+        SCMP_ACT_TRAP
+        SCMP_ACT_ALLOW
+    unsigned int SCMP_ACT_ERRNO(int errno)
+    unsigned int SCMP_ACT_TRACE(int value)
+
+    ctypedef uint64_t scmp_datum_t
+
+    cdef struct scmp_arg_cmp:
+        unsigned int arg
+        scmp_compare op
+        scmp_datum_t datum_a
+        scmp_datum_t datum_b
+
+    scmp_filter_ctx seccomp_init(uint32_t def_action)
+    int seccomp_reset(scmp_filter_ctx ctx, uint32_t def_action)
+    void seccomp_release(scmp_filter_ctx ctx)
+
+    int seccomp_merge(scmp_filter_ctx ctx_dst, scmp_filter_ctx ctx_src)
+
+    int seccomp_arch_exist(scmp_filter_ctx ctx, uint32_t arch_token)
+    int seccomp_arch_add(scmp_filter_ctx ctx, uint32_t arch_token)
+    int seccomp_arch_remove(scmp_filter_ctx ctx, uint32_t arch_token)
+
+    int seccomp_load(scmp_filter_ctx ctx)
+
+    int seccomp_attr_get(scmp_filter_ctx ctx,
+                         scmp_filter_attr attr, uint32_t* value)
+    int seccomp_attr_set(scmp_filter_ctx ctx,
+                         scmp_filter_attr attr, uint32_t value)
+
+    int seccomp_syscall_resolve_name(char *name)
+    int seccomp_syscall_priority(scmp_filter_ctx ctx,
+                                 int syscall, uint8_t priority)
+
+    int seccomp_rule_add(scmp_filter_ctx ctx, uint32_t action,
+                         int syscall, unsigned int arg_cnt, ...)
+
+    int seccomp_rule_add_exact(scmp_filter_ctx ctx, uint32_t action,
+                               int syscall, unsigned int arg_cnt, ...)
+
+    int seccomp_export_pfc(scmp_filter_ctx ctx, int fd)
+    int seccomp_export_bpf(scmp_filter_ctx ctx, int fd)
+
+# kate: syntax python;
+# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off;
diff --git a/src/python/seccomp.pyx b/src/python/seccomp.pyx
new file mode 100644
index 0000000..30e28a0
--- /dev/null
+++ b/src/python/seccomp.pyx
@@ -0,0 +1,546 @@
+#
+# Seccomp Library Python Bindings
+#
+# Copyright (c) 2012 Red Hat <[email protected]>
+# Author: Paul Moore <[email protected]>
+#
+
+#
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of version 2.1 of the GNU Lesser General Public License as
+# published by the Free Software Foundation.
+#
+# This library 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 Lesser General Public License
+# for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, see <http://www.gnu.org/licenses>.
+#
+
+""" Python bindings for the libseccomp library
+
+The libseccomp library provides and easy to use, platform independent,
+interface to the Linux Kernel's syscall filtering mechanism: seccomp.  The
+libseccomp API is designed to abstract away the underlying BPF based
+syscall filter language and present a more conventional function-call
+based filtering interface that should be familiar to, and easily adopted
+by application developers.
+
+Filter action values:
+    KILL - kill the process
+    ALLOW - allow the syscall to execute
+    TRAP - a SIGSYS signal will be thrown
+    ERRNO(x) - syscall will return (x)
+    TRACE(x) - if the process is being traced, (x) will be returned to the
+               tracing process via PTRACE_EVENT_SECCOMP and the
+               PTRACE_GETEVENTMSG option
+
+Argument comparison values:
+
+    NE - argument not equal the value
+    LT - argument less than the value
+    LE - argument less than, or equal to, the value
+    EQ - argument equal the value
+    GT - argument greater than the value
+    GE - argument greater than, or equal to, the value
+    MASKED_EQ - masked argument is equal to the value
+
+
+Example:
+
+    import sys
+    from seccomp import *
+
+    # create a filter object with a default KILL action
+    f = SyscallFilter(defaction=KILL)
+
+    # add syscall filter rules to allow certain syscalls
+    f.add_rule(ALLOW, "open")
+    f.add_rule(ALLOW, "close")
+    f.add_rule(ALLOW, "read", Arg(0, EQ, sys.stdin))
+    f.add_rule(ALLOW, "write", Arg(0, EQ, sys.stdout))
+    f.add_rule(ALLOW, "write", Arg(0, EQ, sys.stderr))
+    f.add_rule(ALLOW, "rt_sigreturn")
+
+    # load the filter into the kernel
+    f.load()
+"""
+__author__ =  'Paul Moore <[email protected]>'
+__date__ = "31 October 2012"
+
+from libc.stdint cimport uint32_t
+import errno
+
+cimport libseccomp
+
+KILL = libseccomp.SCMP_ACT_KILL
+TRAP = libseccomp.SCMP_ACT_TRAP
+ALLOW = libseccomp.SCMP_ACT_ALLOW
+def ERRNO(int errno):
+    return libseccomp.SCMP_ACT_ERRNO(errno)
+def TRACE(int value):
+    return libseccomp.SCMP_ACT_TRACE(value)
+
+NE = libseccomp.SCMP_CMP_NE
+LT = libseccomp.SCMP_CMP_LT
+LE = libseccomp.SCMP_CMP_LE
+EQ = libseccomp.SCMP_CMP_EQ
+GE = libseccomp.SCMP_CMP_GE
+GT = libseccomp.SCMP_CMP_GT
+MASKED_EQ = libseccomp.SCMP_CMP_MASKED_EQ
+
+cdef class Arch:
+    """ Python object representing the SyscallFilter architecture values.
+
+    Data values:
+    NATIVE - the native architecture
+    X86 - 32-bit x86
+    X86_64 - 64-bit x86
+    """
+
+    NATIVE = libseccomp.SCMP_ARCH_NATIVE
+    X86 = libseccomp.SCMP_ARCH_X86
+    X86_64 = libseccomp.SCMP_ARCH_X86_64
+
+cdef class Attr:
+    """ Python object representing the SyscallFilter attributes.
+
+    Data values:
+    ACT_DEFAULT - the filter's default action
+    ACT_BADARCH - the filter's bad architecture action
+    CTL_NNP - the filter's "no new privileges" flag
+    """
+    ACT_DEFAULT = libseccomp.SCMP_FLTATR_ACT_DEFAULT
+    ACT_BADARCH = libseccomp.SCMP_FLTATR_ACT_BADARCH
+    CTL_NNP = libseccomp.SCMP_FLTATR_CTL_NNP
+
+cdef class Arg:
+    """ Python object representing a SyscallFilter syscall argument.
+    """
+    cdef libseccomp.scmp_arg_cmp _arg
+
+    def __cinit__(self, arg, op, datum_a, datum_b = 0):
+        """ Initialize the argument comparison.
+
+        Arguments:
+        arg - the arguement number, starting at 0
+        op - the argument comparison operator, e.g. {NE,LT,LE,...}
+        datum_a - argument value
+        datum_b - argument value, only valid when op == MASKED_EQ
+
+        Description:
+        Create an argument comparison object for use with SyscallFilter.
+        """
+        self._arg.arg = arg
+        self._arg.op = op
+        if isinstance(datum_a, file):
+            self._arg.datum_a = datum_a.fileno()
+        else:
+            self._arg.datum_a = datum_a
+        if isinstance(datum_b, file):
+            self._arg.datum_b = datum_b.fileno()
+        else:
+            self._arg.datum_b = datum_b
+
+    def to_c(self):
+        """ Convert the object into a C structure.
+
+        Description:
+        Helper function which should only be used internally by
+        SyscallFilter objects and exists for the sole purpose of making it
+        easier to deal with the varadic functions of the libseccomp API,
+        e.g. seccomp_rule_add().
+        """
+        return self._arg
+
+cdef class SyscallFilter:
+    """ Python object representing a seccomp syscall filter. """
+    cdef int _defaction
+    cdef libseccomp.scmp_filter_ctx _ctx
+
+    def __cinit__(self, int defaction):
+        """ Initialize the filter state
+
+        Arguments:
+        defaction - the default filter action
+
+        Description:
+        Initializes the seccomp filter state to the defaults.
+        """
+        self._ctx = libseccomp.seccomp_init(defaction)
+        if self._ctx == NULL:
+            raise RuntimeError("Library error")
+        _defaction = defaction
+
+    def __dealloc__(self):
+        """ Destroys the filter state and releases any resources.
+
+        Description:
+        Destroys the seccomp filter state and releases any resources
+        associated with the filter state.  This function does not affect
+        any seccomp filters already loaded into the kernel.
+        """
+        if self._ctx != NULL:
+            libseccomp.seccomp_release(self._ctx)
+
+    def reset(self, int defaction = -1):
+        """ Reset the filter state.
+
+        Arguments:
+        defaction - the default filter action
+
+        Description:
+        Resets the seccomp filter state to an initial default state, if a
+        default filter action is not specified in the reset call the
+        original action will be reused.  This function does not affect any
+        seccomp filters alread loaded into the kernel.
+        """
+        if defaction == -1:
+            defaction = self._defaction
+        rc = libseccomp.seccomp_reset(self._ctx, defaction)
+        if rc == -errno.EINVAL:
+            raise ValueError("Invalid action")
+        if rc != 0:
+            raise RuntimeError(str.format("Library error (errno = {0})", rc))
+        _defaction = defaction
+
+    def merge(self, SyscallFilter filter):
+        """ Merge two existing SyscallFilter objects.
+
+        Arguments:
+        filter - a valid SyscallFilter object
+
+        Description:
+        Merges a valid SyscallFilter object with the current SyscallFilter
+        object; the passed filter object will be reset on success.  In
+        order to successfully merge two seccomp filters they must have the
+        same attribute values and not share any of the same architectures.
+        """
+        rc = libseccomp.seccomp_merge(self._ctx, filter._ctx)
+        if rc != 0:
+            raise RuntimeError(str.format("Library error (errno = {0})", rc))
+        filter._ctx = NULL
+        filter = SyscallFilter(filter._defaction)
+
+    def exist_arch(self, arch):
+        """ Check if the seccomp filter contains a given architecture.
+
+        Arguments:
+        arch - the architecture value, e.g. Arch.*
+
+        Description:
+        Test to see if a given architecture is included in the filter.
+        Return True is the architecture exists, False if it does not
+        exist.
+        """
+        rc = libseccomp.seccomp_arch_exist(self._ctx, arch)
+        if rc == 0:
+            return True
+        elif rc == -errno.EEXIST:
+            return False
+        elif rc == -errno.EINVAL:
+            raise ValueError("Invalid architecture")
+        else:
+            raise RuntimeError(str.format("Library error (errno = {0})", rc))
+
+    def add_arch(self, arch):
+        """ Add an architecture to the filter.
+
+        Arguments:
+        arch - the architecture value, e.g. Arch.*
+
+        Description:
+        Add the given architecture to the filter.  Any new rules added
+        after this method returns successfully will be added to this new
+        architecture, but any existing rules will not be added to the new
+        architecture.
+        """
+        rc = libseccomp.seccomp_arch_add(self._ctx, arch)
+        if rc == -errno.EINVAL:
+            raise ValueError("Invalid architecture")
+        elif rc != 0:
+            raise RuntimeError(str.format("Library error (errno = {0})", rc))
+
+    def remove_arch(self, arch):
+        """ Remove an architecture from the filter.
+
+        Arguments:
+        arch - the architecture value, e.g. Arch.*
+
+        Description:
+        Remove the given architecture from the filter.  The filter must
+        always contain at least one architecture, so if only one
+        architecture exists in the filter this method will fail.
+        """
+        rc = libseccomp.seccomp_arch_remove(self._ctx, arch)
+        if rc == -errno.EINVAL:
+            raise ValueError("Invalid architecture")
+        elif rc != 0:
+            raise RuntimeError(str.format("Library error (errno = {0})", rc))
+
+    def load(self):
+        """ Load the filter into the Linux Kernel.
+
+        Description:
+        Load the current filter into the Linux Kernel.  As soon as the
+        method returns the filter will be active and enforcing.
+        """
+        rc = libseccomp.seccomp_load(self._ctx)
+        if rc != 0:
+            raise RuntimeError(str.format("Library error (errno = {0})", rc))
+
+    def get_attr(self, attr):
+        """ Get an attribute value from the filter.
+
+        Arguments:
+        attr - the attribute, e.g. Attr.*
+
+        Description:
+        Lookup the given attribute in the filter and return the
+        attribute's value to the caller.
+        """
+        value = 0
+        rc = libseccomp.seccomp_attr_get(self._ctx,
+                                         attr, <uint32_t *>&value)
+        if rc == -errno.EINVAL:
+            raise ValueError("Invalid attribute")
+        elif rc != 0:
+            raise RuntimeError(str.format("Library error (errno = {0})", rc))
+        return value
+
+    def set_attr(self, attr, int value):
+        """ Set a filter attribute.
+
+        Arguments:
+        attr - the attribute, e.g. Attr.*
+        value - the attribute value
+
+        Description:
+        Lookup the given attribute in the filter and assign it the given
+        value.
+        """
+        rc = libseccomp.seccomp_attr_set(self._ctx, attr, value)
+        if rc == -errno.EINVAL:
+            raise ValueError("Invalid attribute")
+        elif rc != 0:
+            raise RuntimeError(str.format("Library error (errno = {0})", rc))
+
+    def syscall_priority(self, syscall, int priority):
+        """ Set the filter priority of a syscall.
+
+        Arguments:
+        syscall - the syscall name or number
+        priority - the priority of the syscall
+
+        Description:
+        Set the filter priority of the given syscall.  A syscall with a
+        higher priority will have less overhead in the generated filter
+        code which is loaded into the system.  Priority values can range
+        from 0 to 255 inclusive.
+        """
+        if priority < 0 or priority > 255:
+            raise ValueError("Syscall priority must be between 0 and 255");
+        if isinstance(syscall, str):
+            syscall_str = syscall.encode()
+            syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
+        elif isinstance(syscall, int):
+            syscall_num = syscall
+        else:
+            raise TypeError("Syscall must either be an int or str type");
+        rc = libseccomp.seccomp_syscall_priority(self._ctx,
+                                                 syscall_num, priority)
+        if rc != 0:
+            raise RuntimeError(str.format("Library error (errno = {0})", rc))
+
+    def add_rule(self, int action, syscall, *args):
+        """ Add a new rule to filter.
+
+        Arguments:
+        action - the rule action: KILL, TRAP, ERRNO(), TRACE(), or ALLOW
+        syscall - the syscall name or number
+        args - variable number of Arg objects
+
+        Description:
+        Add a new rule to the filter, matching on the given syscall and an
+        optional list of argument comparisons.  If the rule is triggered
+        the given action will be taken by the kernel.  In order for the
+        rule to trigger, the syscall as well as each argument comparison
+        must be true.
+
+        In the case where the specific rule is not valid on a specific
+        architecture, e.g. socket() on 32-bit x86, this method rewrites
+        the rule to the best possible match.  If you don't want this fule
+        rewriting to take place use add_rule_exactly().
+        """
+        cdef libseccomp.scmp_arg_cmp c_arg[6]
+        if isinstance(syscall, str):
+            syscall_str = syscall.encode()
+            syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
+        elif isinstance(syscall, int):
+            syscall_num = syscall
+        else:
+            raise TypeError("Syscall must either be an int or str type");
+        """ NOTE: the code below exists solely to deal with the varadic
+        nature of seccomp_rule_add() function and the inability of Cython
+        to handle this automatically """
+        for i, arg in enumerate(args):
+            c_arg[i] = arg.to_c()
+        if len(args) == 0:
+            rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num, 0)
+        elif len(args) == 1:
+            rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
+                                             len(args),
+                                             c_arg[0])
+        elif len(args) == 2:
+            rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
+                                             len(args),
+                                             c_arg[0],
+                                             c_arg[1])
+        elif len(args) == 3:
+            rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
+                                             len(args),
+                                             c_arg[0],
+                                             c_arg[1],
+                                             c_arg[2])
+        elif len(args) == 4:
+            rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
+                                             len(args),
+                                             c_arg[0],
+                                             c_arg[1],
+                                             c_arg[2],
+                                             c_arg[3])
+        elif len(args) == 5:
+            rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
+                                             len(args),
+                                             c_arg[0],
+                                             c_arg[1],
+                                             c_arg[2],
+                                             c_arg[3],
+                                             c_arg[4])
+        elif len(args) == 6:
+            rc = libseccomp.seccomp_rule_add(self._ctx, action, syscall_num,
+                                             len(args),
+                                             c_arg[0],
+                                             c_arg[1],
+                                             c_arg[2],
+                                             c_arg[3],
+                                             c_arg[4],
+                                             c_arg[5])
+        else:
+            raise RuntimeError("Maximum number of arguments exceeded")
+        if rc != 0:
+            raise RuntimeError(str.format("Library error (errno = {0})", rc))
+
+    def add_rule_exactly(self, int action, syscall, *args):
+        """ Add a new rule to filter.
+
+        Arguments:
+        action - the rule action: KILL, TRAP, ERRNO(), TRACE(), or ALLOW
+        syscall - the syscall name or number
+        args - variable number of Arg objects
+
+        Description:
+        Add a new rule to the filter, matching on the given syscall and an
+        optional list of argument comparisons.  If the rule is triggered
+        the given action will be taken by the kernel.  In order for the
+        rule to trigger, the syscall as well as each argument comparison
+        must be true.
+
+        This method attempts to add the filter rule exactly as specified
+        which can cause problems on certain architectures, e.g. socket()
+        on 32-bit x86.  For a architecture independent version of this
+        method use add_rule().
+        """
+        cdef libseccomp.scmp_arg_cmp c_arg[6]
+        if isinstance(syscall, str):
+            syscall_str = syscall.encode()
+            syscall_num = libseccomp.seccomp_syscall_resolve_name(syscall_str)
+        elif isinstance(syscall, int):
+            syscall_num = syscall
+        else:
+            raise TypeError("Syscall must either be an int or str type");
+        """ NOTE: the code below exists solely to deal with the varadic
+        nature of seccomp_rule_add_exact() function and the inability of
+        Cython to handle this automatically """
+        for i, arg in enumerate(args):
+            c_arg[i] = arg.to_c()
+        if len(args) == 0:
+            rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
+                                                   syscall_num, 0)
+        elif len(args) == 1:
+            rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
+                                                   syscall_num, len(args),
+                                                   c_arg[0])
+        elif len(args) == 2:
+            rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
+                                                   syscall_num, len(args),
+                                                   c_arg[0],
+                                                   c_arg[1])
+        elif len(args) == 3:
+            rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
+                                                   syscall_num, len(args),
+                                                   c_arg[0],
+                                                   c_arg[1],
+                                                   c_arg[2])
+        elif len(args) == 4:
+            rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
+                                                   syscall_num, len(args),
+                                                   c_arg[0],
+                                                   c_arg[1],
+                                                   c_arg[2],
+                                                   c_arg[3])
+        elif len(args) == 5:
+            rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
+                                                   syscall_num, len(args),
+                                                   c_arg[0],
+                                                   c_arg[1],
+                                                   c_arg[2],
+                                                   c_arg[3],
+                                                   c_arg[4])
+        elif len(args) == 6:
+            rc = libseccomp.seccomp_rule_add_exact(self._ctx, action,
+                                                   syscall_num, len(args),
+                                                   c_arg[0],
+                                                   c_arg[1],
+                                                   c_arg[2],
+                                                   c_arg[3],
+                                                   c_arg[4],
+                                                   c_arg[5])
+        else:
+            raise RuntimeError("Maximum number of arguments exceeded")
+        if rc != 0:
+            raise RuntimeError(str.format("Library error (errno = {0})", rc))
+
+    def export_pfc(self, file):
+        """ Export the filter in PFC format.
+
+        Arguments:
+        file - the output file
+
+        Description:
+        Output the filter in Pseudo Filter Code (PFC) to the given file.
+        The output is functionally equivalent to the BPF based filter
+        which is loaded into the Linux Kernel.
+        """
+        rc = libseccomp.seccomp_export_pfc(self._ctx, file.fileno())
+        if rc != 0:
+            raise RuntimeError(str.format("Library error (errno = {0})", rc))
+
+    def export_bpf(self, file):
+        """ Export the filter in BPF format.
+
+        Arguments:
+        file - the output file
+
+        Output the filter in Berkley Packet Filter (BPF) to the given
+        file.  The output is identical to what is loaded into the
+        Linux Kernel.
+        """
+        rc = libseccomp.seccomp_export_bpf(self._ctx, file.fileno())
+        if rc != 0:
+            raise RuntimeError(str.format("Library error (errno = {0})", rc))
+
+# kate: syntax python;
+# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off;
diff --git a/src/python/setup.py b/src/python/setup.py
new file mode 100644
index 0000000..872642e
--- /dev/null
+++ b/src/python/setup.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+#
+# Enhanced Seccomp Library Python Module Build Script
+#
+# Copyright (c) 2012 Red Hat <[email protected]>
+# Author: Paul Moore <[email protected]>
+#
+
+#
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of version 2.1 of the GNU Lesser General Public License as
+# published by the Free Software Foundation.
+#
+# This library 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 Lesser General Public License
+# for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, see <http://www.gnu.org/licenses>.
+#
+
+import os
+
+from distutils.core import setup
+from distutils.extension import Extension
+from Cython.Distutils import build_ext
+
+setup(
+       name = "seccomp",
+       version = os.environ["VERSION_RELEASE"],
+       description = "Python binding for libseccomp",
+       long_description = "Python API for the Linux Kernel's syscall filtering 
capability, seccomp.",
+       url = "http://libseccomp.sf.net";,
+       maintainer = "Paul Moore",
+       maintainer_email = "[email protected]",
+       license = "LGPLv2.1",
+       platforms = "Linux",
+       cmdclass = {'build_ext': build_ext},
+       ext_modules = [
+               Extension("seccomp", ["seccomp.pyx"],
+                       extra_objects=["../libseccomp.a"])
+               ]
+)


------------------------------------------------------------------------------
LogMeIn Central: Instant, anywhere, Remote PC access and management.
Stay in control, update software, and manage PCs from one command center
Diagnose problems and improve visibility into emerging IT issues
Automate, monitor and manage. Do more in less time with Central
http://p.sf.net/sfu/logmein12331_d2d
_______________________________________________
libseccomp-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libseccomp-discuss

Reply via email to