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"])
+               ]
+)


------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_sfd2d_oct
_______________________________________________
libseccomp-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libseccomp-discuss

Reply via email to