Ricardo Wurmus writes: > * gnu/packages/selinux.scm (policycoreutils): New variable. > --- > gnu/local.mk | 1 + > ...policycoreutils-make-sepolicy-use-python3.patch | 335 +++++++++++++++++++++ > gnu/packages/selinux.scm | 135 +++++++++ > 3 files changed, 471 insertions(+) > create mode 100644 gnu/packages/patches/policycoreutils-make-sepolicy-use-python3.patch > > diff --git a/gnu/local.mk b/gnu/local.mk > index 77302573a..79ffbe2fe 100644 > --- a/gnu/local.mk > +++ b/gnu/local.mk > @@ -856,6 +856,7 @@ dist_patch_DATA = \ > %D%/packages/patches/plink-endian-detection.patch \ > %D%/packages/patches/plotutils-libpng-jmpbuf.patch \ > %D%/packages/patches/polkit-drop-test.patch \ > + %D%/packages/patches/policycoreutils-make-sepolicy-use-python3.patch \ > %D%/packages/patches/portaudio-audacity-compat.patch \ > %D%/packages/patches/portmidi-modular-build.patch \ > %D%/packages/patches/procmail-ambiguous-getline-debian.patch \ > diff --git a/gnu/packages/patches/policycoreutils-make-sepolicy-use-python3.patch b/gnu/packages/patches/policycoreutils-make-sepolicy-use-python3.patch > new file mode 100644 > index 000000000..befe9fbb2 > --- /dev/null > +++ b/gnu/packages/patches/policycoreutils-make-sepolicy-use-python3.patch > @@ -0,0 +1,335 @@ > +Downloaded from https://anonscm.debian.org/cgit/selinux/policycoreutils.git/plain/debian/patches/policycoreutils-Make-sepolicy-work-with-python3.patch > + > +From 2d7ca0b862a35196d562f59bd098df011fd7f0e6 Mon Sep 17 00:00:00 2001 > +From: Laurent Bigonville > +Date: Mon, 7 Nov 2016 10:51:08 +0100 > +Subject: [PATCH] policycoreutils: Make sepolicy work with python3 > + > +Add python3 support for sepolicy > + > +Signed-off-by: Laurent Bigonville > +--- > + policycoreutils/sepolicy/selinux_client.py | 6 ++-- > + policycoreutils/sepolicy/sepolicy.py | 38 ++++++++++++------------ > + policycoreutils/sepolicy/sepolicy/__init__.py | 16 ++++++---- > + policycoreutils/sepolicy/sepolicy/communicate.py | 4 +-- > + policycoreutils/sepolicy/sepolicy/generate.py | 30 +++++++++---------- > + policycoreutils/sepolicy/sepolicy/interface.py | 14 ++++++--- > + policycoreutils/sepolicy/sepolicy/manpage.py | 7 +++-- > + 7 files changed, 65 insertions(+), 50 deletions(-) > + > +diff --git a/policycoreutils/sepolicy/selinux_client.py b/policycoreutils/sepolicy/selinux_client.py > +index 7f4a91c..dc29f28 100644 > +--- a/sepolicy/selinux_client.py > ++++ b/sepolicy/selinux_client.py > +@@ -39,6 +39,6 @@ if __name__ == "__main__": > + try: > + dbus_proxy = SELinuxDBus() > + resp = dbus_proxy.customized() > +- print convert_customization(resp) > +- except dbus.DBusException, e: > +- print e > ++ print(convert_customization(resp)) > ++ except dbus.DBusException as e: > ++ print(e) > +diff --git a/policycoreutils/sepolicy/sepolicy.py b/policycoreutils/sepolicy/sepolicy.py > +index 3e502a7..5bf9b52 100755 > +--- a/sepolicy/sepolicy.py > ++++ b/sepolicy/sepolicy.py > +@@ -262,7 +262,7 @@ def _print_net(src, protocol, perm): > + if len(portdict) > 0: > + bold_start = "\033[1m" > + bold_end = "\033[0;0m" > +- print "\n" + bold_start + "%s: %s %s" % (src, protocol, perm) + bold_end > ++ print("\n" + bold_start + "%s: %s %s" % (src, protocol, perm) + bold_end) > + port_strings = [] > + boolean_text = "" > + for p in portdict: > +@@ -275,7 +275,7 @@ def _print_net(src, protocol, perm): > + port_strings.append("%s (%s)" % (", ".join(recs), t)) > + port_strings.sort(numcmp) > + for p in port_strings: > +- print "\t" + p > ++ print("\t" + p) > + > + > + def network(args): > +@@ -286,7 +286,7 @@ def network(args): > + if i[0] not in all_ports: > + all_ports.append(i[0]) > + all_ports.sort() > +- print "\n".join(all_ports) > ++ print("\n".join(all_ports)) > + > + for port in args.port: > + found = False > +@@ -297,18 +297,18 @@ def network(args): > + else: > + range = "%s-%s" % (i[0], i[1]) > + found = True > +- print "%d: %s %s %s" % (port, i[2], portrecsbynum[i][0], range) > ++ print("%d: %s %s %s" % (port, i[2], portrecsbynum[i][0], range)) > + if not found: > + if port < 500: > +- print "Undefined reserved port type" > ++ print("Undefined reserved port type") > + else: > +- print "Undefined port type" > ++ print("Undefined port type") > + > + for t in args.type: > + if (t, 'tcp') in portrecs.keys(): > +- print "%s: tcp: %s" % (t, ",".join(portrecs[t, 'tcp'])) > ++ print("%s: tcp: %s" % (t, ",".join(portrecs[t, 'tcp']))) > + if (t, 'udp') in portrecs.keys(): > +- print "%s: udp: %s" % (t, ",".join(portrecs[t, 'udp'])) > ++ print( "%s: udp: %s" % (t, ",".join(portrecs[t, 'udp']))) > + > + for a in args.applications: > + d = sepolicy.get_init_transtype(a) > +@@ -357,7 +357,7 @@ def manpage(args): > + > + for domain in test_domains: > + m = ManPage(domain, path, args.root, args.source_files, args.web) > +- print m.get_man_page_path() > ++ print(m.get_man_page_path()) > + > + if args.web: > + HTMLManPages(manpage_roles, manpage_domains, path, args.os) > +@@ -418,7 +418,7 @@ def communicate(args): > + out = list(set(writable) & set(readable)) > + > + for t in out: > +- print t > ++ print(t) > + > + > + def gen_communicate_args(parser): > +@@ -445,7 +445,7 @@ def booleans(args): > + args.booleans.sort() > + > + for b in args.booleans: > +- print "%s=_(\"%s\")" % (b, boolean_desc(b)) > ++ print("%s=_(\"%s\")" % (b, boolean_desc(b))) > + > + > + def gen_booleans_args(parser): > +@@ -484,16 +484,16 @@ def print_interfaces(interfaces, args, append=""): > + for i in interfaces: > + if args.verbose: > + try: > +- print get_interface_format_text(i + append) > ++ print(get_interface_format_text(i + append)) > + except KeyError: > +- print i > ++ print(i) > + if args.compile: > + try: > + interface_compile_test(i) > + except KeyError: > +- print i > ++ print(i) > + else: > +- print i > ++ print(i) > + > + > + def interface(args): > +@@ -565,7 +565,7 @@ def generate(args): > + if args.policytype in APPLICATIONS: > + mypolicy.gen_writeable() > + mypolicy.gen_symbols() > +- print mypolicy.generate(args.path) > ++ print(mypolicy.generate(args.path)) > + > + > + def gen_interface_args(parser): > +@@ -698,12 +698,12 @@ if __name__ == '__main__': > + args = parser.parse_args(args=parser_args) > + args.func(args) > + sys.exit(0) > +- except ValueError, e: > ++ except ValueError as e: > + sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e))) > + sys.exit(1) > +- except IOError, e: > ++ except IOError as e: > + sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e))) > + sys.exit(1) > + except KeyboardInterrupt: > +- print "Out" > ++ print("Out") > + sys.exit(0) > +diff --git a/policycoreutils/sepolicy/sepolicy/__init__.py b/policycoreutils/sepolicy/sepolicy/__init__.py > +index 8fbd5b4..fee6438 100644 > +--- a/sepolicy/sepolicy/__init__.py > ++++ b/sepolicy/sepolicy/__init__.py > +@@ -695,7 +695,7 @@ def get_methods(): > + # List of per_role_template interfaces > + ifs = interfaces.InterfaceSet() > + ifs.from_file(fd) > +- methods = ifs.interfaces.keys() > ++ methods = list(ifs.interfaces.keys()) > + fd.close() > + except: > + sys.stderr.write("could not open interface info [%s]\n" % fn) > +@@ -752,7 +752,10 @@ def get_all_entrypoint_domains(): > + > + > + def gen_interfaces(): > +- import commands > ++ try: > ++ from commands import getstatusoutput > ++ except ImportError: > ++ from subprocess import getstatusoutput > + ifile = defaults.interface_info() > + headers = defaults.headers() > + try: > +@@ -763,7 +766,7 @@ def gen_interfaces(): > + > + if os.getuid() != 0: > + raise ValueError(_("You must regenerate interface info by running /usr/bin/sepolgen-ifgen")) > +- print(commands.getstatusoutput("/usr/bin/sepolgen-ifgen")[1]) > ++ print(getstatusoutput("/usr/bin/sepolgen-ifgen")[1]) > + > + > + def gen_port_dict(): > +@@ -1085,8 +1088,11 @@ def get_os_version(): > + os_version = "" > + pkg_name = "selinux-policy" > + try: > +- import commands > +- rc, output = commands.getstatusoutput("rpm -q '%s'" % pkg_name) > ++ try: > ++ from commands import getstatusoutput > ++ except ImportError: > ++ from subprocess import getstatusoutput > ++ rc, output = getstatusoutput("rpm -q '%s'" % pkg_name) > + if rc == 0: > + os_version = output.split(".")[-2] > + except: > +diff --git a/policycoreutils/sepolicy/sepolicy/communicate.py b/policycoreutils/sepolicy/sepolicy/communicate.py > +index b96c4b9..299316e 100755 > +--- a/sepolicy/sepolicy/communicate.py > ++++ b/sepolicy/sepolicy/communicate.py > +@@ -34,8 +34,8 @@ def usage(parser, msg): > + > + def expand_attribute(attribute): > + try: > +- return sepolicy.info(sepolicy.ATTRIBUTE, attribute)[0]["types"] > +- except RuntimeError: > ++ return list(next(sepolicy.info(sepolicy.ATTRIBUTE, attribute))["types"]) > ++ except StopIteration: > + return [attribute] > + > + > +diff --git a/policycoreutils/sepolicy/sepolicy/generate.py b/policycoreutils/sepolicy/sepolicy/generate.py > +index 65b33b6..5696110 100644 > +--- a/sepolicy/sepolicy/generate.py > ++++ b/sepolicy/sepolicy/generate.py > +@@ -31,21 +31,21 @@ import time > + import types > + import platform > + > +-from templates import executable > +-from templates import boolean > +-from templates import etc_rw > +-from templates import unit_file > +-from templates import var_cache > +-from templates import var_spool > +-from templates import var_lib > +-from templates import var_log > +-from templates import var_run > +-from templates import tmp > +-from templates import rw > +-from templates import network > +-from templates import script > +-from templates import spec > +-from templates import user > ++from .templates import executable > ++from .templates import boolean > ++from .templates import etc_rw > ++from .templates import unit_file > ++from .templates import var_cache > ++from .templates import var_spool > ++from .templates import var_lib > ++from .templates import var_log > ++from .templates import var_run > ++from .templates import tmp > ++from .templates import rw > ++from .templates import network > ++from .templates import script > ++from .templates import spec > ++from .templates import user > + import sepolgen.interfaces as interfaces > + import sepolgen.defaults as defaults > + > +diff --git a/policycoreutils/sepolicy/sepolicy/interface.py b/policycoreutils/sepolicy/sepolicy/interface.py > +index c2cb971..8956f39 100644 > +--- a/sepolicy/sepolicy/interface.py > ++++ b/sepolicy/sepolicy/interface.py > +@@ -192,10 +192,13 @@ def generate_compile_te(interface, idict, name="compiletest"): > + def get_xml_file(if_file): > + """ Returns xml format of interfaces for given .if policy file""" > + import os > +- import commands > ++ try: > ++ from commands import getstatusoutput > ++ except ImportError: > ++ from subprocess import getstatusoutput > + basedir = os.path.dirname(if_file) + "/" > + filename = os.path.basename(if_file).split(".")[0] > +- rc, output = commands.getstatusoutput("python /usr/share/selinux/devel/include/support/segenxml.py -w -m %s" % basedir + filename) > ++ rc, output = getstatusoutput("python /usr/share/selinux/devel/include/support/segenxml.py -w -m %s" % basedir + filename) > + if rc != 0: > + sys.stderr.write("\n Could not proceed selected interface file.\n") > + sys.stderr.write("\n%s" % output) > +@@ -208,7 +211,10 @@ def interface_compile_test(interface, path="/usr/share/selinux/devel/policy.xml" > + exclude_interfaces = ["userdom", "kernel", "corenet", "files", "dev"] > + exclude_interface_type = ["template"] > + > +- import commands > ++ try: > ++ from commands import getstatusoutput > ++ except ImportError: > ++ from subprocess import getstatusoutput > + import os > + policy_files = {'pp': "compiletest.pp", 'te': "compiletest.te", 'fc': "compiletest.fc", 'if': "compiletest.if"} > + idict = get_interface_dict(path) > +@@ -219,7 +225,7 @@ def interface_compile_test(interface, path="/usr/share/selinux/devel/policy.xml" > + fd = open(policy_files['te'], "w") > + fd.write(generate_compile_te(interface, idict)) > + fd.close() > +- rc, output = commands.getstatusoutput("make -f /usr/share/selinux/devel/Makefile %s" % policy_files['pp']) > ++ rc, output = getstatusoutput("make -f /usr/share/selinux/devel/Makefile %s" % policy_files['pp']) > + if rc != 0: > + sys.stderr.write(output) > + sys.stderr.write(_("\nCompile test for %s failed.\n") % interface) > +diff --git a/policycoreutils/sepolicy/sepolicy/manpage.py b/policycoreutils/sepolicy/sepolicy/manpage.py > +index 7365f93..773a9ab 100755 > +--- a/sepolicy/sepolicy/manpage.py > ++++ b/sepolicy/sepolicy/manpage.py > +@@ -27,7 +27,6 @@ __all__ = ['ManPage', 'HTMLManPages', 'manpage_domains', 'manpage_roles', 'gen_d > + import string > + import selinux > + import sepolicy > +-import commands > + import os > + import time > + > +@@ -162,7 +161,11 @@ def get_alphabet_manpages(manpage_list): > + > + > + def convert_manpage_to_html(html_manpage, manpage): > +- rc, output = commands.getstatusoutput("/usr/bin/groff -man -Thtml %s 2>/dev/null" % manpage) > ++ try: > ++ from commands import getstatusoutput > ++ except ImportError: > ++ from subprocess import getstatusoutput > ++ rc, output = getstatusoutput("/usr/bin/groff -man -Thtml %s 2>/dev/null" % manpage) > + if rc == 0: > + print(html_manpage, "has been created") > + fd = open(html_manpage, 'w') > +-- > +2.10.2 > + > diff --git a/gnu/packages/selinux.scm b/gnu/packages/selinux.scm > index 05197b85c..7acda89a6 100644 > --- a/gnu/packages/selinux.scm > +++ b/gnu/packages/selinux.scm > @@ -28,6 +28,10 @@ > #:use-module (gnu packages bison) > #:use-module (gnu packages docbook) > #:use-module (gnu packages flex) > + #:use-module (gnu packages gettext) > + #:use-module (gnu packages glib) > + #:use-module (gnu packages linux) > + #:use-module (gnu packages networking) > #:use-module (gnu packages pcre) > #:use-module (gnu packages pkg-config) > #:use-module (gnu packages python) > @@ -338,3 +342,134 @@ tools, and libraries designed to facilitate SELinux policy analysis.") > ;; Some programs are under GPL, all libraries under LGPL. > (license (list license:lgpl2.1+ > license:gpl2+)))) > + > +(define-public policycoreutils > + (package (inherit libsepol) > + (name "policycoreutils") > + (source > + (origin (inherit (package-source libsepol)) > + (patches (search-patches "policycoreutils-make-sepolicy-use-python3.patch")) > + (patch-flags '("-p1" "-d" "policycoreutils")))) > + (arguments > + `(#:test-target "test" > + #:make-flags > + (let ((out (assoc-ref %outputs "out"))) > + (list "CC=gcc" > + (string-append "PREFIX=" out) > + (string-append "LOCALEDIR=" out "/share/locale") > + (string-append "BASHCOMPLETIONDIR=" out > + "/share/bash-completion/completions") > + "INSTALL=install -c -p" > + "INSTALL_DIR=install -d" > + ;; These ones are needed because some Makefiles define the > + ;; directories relative to DESTDIR, not relative to PREFIX. > + (string-append "SBINDIR=" out "/sbin") > + (string-append "ETCDIR=" out "/etc") > + (string-append "SYSCONFDIR=" out "/etc/sysconfig") > + (string-append "MAN5DIR=" out "/share/man/man5") > + (string-append "INSTALL_NLS_DIR=" out "/share/locale") > + (string-append "AUTOSTARTDIR=" out "/etc/xdg/autostart") > + (string-append "DBUSSERVICEDIR=" out "/share/dbus-1/services") > + (string-append "SYSTEMDDIR=" out "/lib/systemd") > + (string-append "INITDIR=" out "/etc/rc.d/init.d") > + (string-append "SELINUXDIR=" out "/etc/selinux"))) > + #:phases > + (modify-phases %standard-phases > + (delete 'configure) > + (add-after 'unpack 'enter-dir > + (lambda _ (chdir ,name) #t)) > + (add-after 'enter-dir 'ignore-/usr-tests > + (lambda* (#:key inputs #:allow-other-keys) > + ;; The Makefile decides to build restorecond only if it finds the > + ;; inotify header somewhere under /usr. > + (substitute* "Makefile" > + (("ifeq.*") "") > + (("endif.*") "")) > + ;; Rewrite lookup paths for header files. > + (substitute* '("newrole/Makefile" > + "setfiles/Makefile" > + "run_init/Makefile") > + (("/usr(/include/security/pam_appl.h)" _ file) > + (string-append (assoc-ref inputs "pam") file)) > + (("/usr(/include/libaudit.h)" _ file) > + (string-append (assoc-ref inputs "audit") file))) > + #t)) > + (add-after 'enter-dir 'fix-glib-cflags > + (lambda* (#:key inputs #:allow-other-keys) > + (substitute* "restorecond/Makefile" > + (("/usr(/include/glib-2.0|/lib/glib-2.0/include)" _ path) > + (string-append (assoc-ref inputs "glib") path)) > + (("/usr(/include/dbus-1.0|/lib/dbus-1.0/include)" _ path) > + (string-append (assoc-ref inputs "dbus") path > + " -I" > + (assoc-ref inputs "dbus-glib") path))) > + #t)) > + (add-after 'enter-dir 'fix-linkage-with-libsepol > + (lambda* (#:key inputs #:allow-other-keys) > + (substitute* '("semodule_deps/Makefile" > + "sepolgen-ifgen/Makefile") > + (("\\$\\(LIBDIR\\)") > + (string-append (assoc-ref inputs "libsepol") "/lib/"))))) > + (add-after 'enter-dir 'fix-target-paths > + (lambda* (#:key outputs #:allow-other-keys) > + (let ((out (assoc-ref outputs "out"))) > + (substitute* "audit2allow/sepolgen-ifgen" > + (("ATTR_HELPER = \"/usr/bin/sepolgen-ifgen-attr-helper\"") > + (string-append "ATTR_HELPER = \"" out > + "/bin/sepolgen-ifgen-attr-helper\""))) > + (substitute* "sepolicy/sepolicy/__init__.py" > + (("/usr/bin/sepolgen-ifgen") > + (string-append out "/bin/sepolgen-ifgen"))) > + (substitute* "sepolicy/Makefile" > + ;; By default all Python files would be installed to > + ;; $out/gnu/store/...-python-.../. > + (("setup.py install.*$") > + (string-append "setup.py install --prefix=" out "\n")) > + (("\\$\\(DESTDIR\\)/etc") > + (string-append out "/etc")) > + (("\\$\\(DESTDIR\\)/usr") out))) > + #t)) > + (add-after 'install 'wrap-python-tools > + (lambda* (#:key outputs #:allow-other-keys) > + (let* ((out (assoc-ref outputs "out")) > + (var (string-append out "/lib/python3.5/site-packages:" ^^^ Can we use (version-major+minor (package-version python)) here? I plan to start a 3.6 branch soonish, unless someone beats me to it :) > + (getenv "PYTHONPATH")))) > + ;; The scripts' shebangs tell Python to ignore the PYTHONPATH, > + ;; so we need to patch them before wrapping. > + (for-each (lambda (file) > + (let ((path (string-append out "/" file))) > + (substitute* path > + (("bin/python -Es") "bin/python -s")) > + (wrap-program path > + `("PYTHONPATH" ":" prefix (,var))))) > + '("bin/audit2allow" > + "bin/chcat" > + "bin/sandbox" > + "bin/sepolgen-ifgen" > + "bin/sepolicy" > + "sbin/semanage"))) > + #t))))) > + (inputs > + `(("python" ,python-wrapper) > + ("audit" ,audit) > + ("pam" ,linux-pam) > + ("libsepol" ,libsepol) > + ("libselinux" ,libselinux) > + ("libsemanage" ,libsemanage) > + ("python-sepolgen" ,python-sepolgen) > + ("python-setools" ,python-setools) > + ("python-ipy" ,python-ipy) > + ("libcap-ng" ,libcap-ng) > + ("pcre" ,pcre) > + ("dbus" ,dbus) > + ("dbus-glib" ,dbus-glib) > + ("glib" ,glib))) > + (native-inputs > + `(("gettext" ,gettext-minimal))) > + (synopsis "SELinux core utilities") > + (description "The policycoreutils package contains the core utilities that > +are required for the basic operation of an SELinux-enabled GNU system and its > +policies. These utilities include @code{load_policy} to load policies, > +@code{setfiles} to label file systems, @code{newrole} to switch roles, and > +@code{run_init} to run service scripts in their proper context.") > + (license license:gpl2+))) > -- > 2.12.2