diff --git a/Makefile b/Makefile index d48f986..5e7ec5e 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ BINDIR ?= /usr/bin LIBDIR ?= /usr/lib SYSLIBDIR ?= /lib -PYTHON ?= /usr/bin/python2 +PYTHON ?= /usr/bin/python3 PYTHON_SITEARCH = $(shell python2 -c 'import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1)') PYTHON2_SITELIB = $(shell python2 -c 'import distutils.sysconfig; print distutils.sysconfig.get_python_lib()') PYTHON3_SITELIB = $(shell python3 -c 'import distutils.sysconfig; print(distutils.sysconfig.get_python_lib())') diff --git a/archlinux/PKGBUILD b/archlinux/PKGBUILD index ab6a0db..8c51c3a 100644 --- a/archlinux/PKGBUILD +++ b/archlinux/PKGBUILD @@ -61,10 +61,10 @@ build() { # * core systemd services and drop-ins # * basic network functionality (setting IP address, DNS, default gateway) package_qubes-vm-core() { - depends=("qubes-vm-utils>=3.1.3" python2 python2-xdg ethtool ntp net-tools + depends=("qubes-vm-utils>=3.1.3" python2 python3-xdg ethtool ntp net-tools gnome-packagekit imagemagick fakeroot notification-daemon dconf - zenity qubes-libvchan "qubes-db-vm>=3.2.1" haveged python2-gobject - python2-dbus xdg-utils notification-daemon gawk sed procps-ng librsvg + zenity qubes-libvchan "qubes-db-vm>=3.2.1" haveged python3-gobject + python3-dbus xdg-utils notification-daemon gawk sed procps-ng librsvg socat ) optdepends=(gnome-keyring gnome-settings-daemon python2-nautilus gpk-update-viewer qubes-vm-networking qubes-vm-keyring) @@ -74,7 +74,7 @@ package_qubes-vm-core() { # shellcheck disable=SC2154 make -C qrexec install DESTDIR="$pkgdir" SBINDIR=/usr/bin LIBDIR=/usr/lib SYSLIBDIR=/usr/lib - PYTHON=python2 make install-corevm DESTDIR="$pkgdir" SBINDIR=/usr/bin LIBDIR=/usr/lib SYSLIBDIR=/usr/lib SYSTEM_DROPIN_DIR=/usr/lib/systemd/system USER_DROPIN_DIR=/usr/lib/systemd/user DIST=archlinux + make install-corevm DESTDIR="$pkgdir" SBINDIR=/usr/bin LIBDIR=/usr/lib SYSLIBDIR=/usr/lib SYSTEM_DROPIN_DIR=/usr/lib/systemd/system USER_DROPIN_DIR=/usr/lib/systemd/user DIST=archlinux # Remove things non wanted in archlinux rm -r "$pkgdir/etc/yum"* @@ -122,13 +122,13 @@ EOF # package_qubes-vm-networking() { pkgdesc="Qubes OS tools allowing to use a Qubes VM as a NetVM/ProxyVM" - depends=(qubes-vm-core "qubes-vm-utils>=3.1.3" python2 ethtool net-tools + depends=(qubes-vm-core "qubes-vm-utils>=3.1.3" python3 ethtool net-tools "qubes-db-vm>=3.2.1" networkmanager iptables tinyproxy nftables ) install=PKGBUILD-networking.install # shellcheck disable=SC2154 - PYTHON=python2 make install-netvm DESTDIR="$pkgdir" SBINDIR=/usr/bin LIBDIR=/usr/lib SYSLIBDIR=/usr/lib SYSTEM_DROPIN_DIR=/usr/lib/systemd/system USER_DROPIN_DIR=/usr/lib/systemd/user DIST=archlinux + make install-netvm DESTDIR="$pkgdir" SBINDIR=/usr/bin LIBDIR=/usr/lib SYSLIBDIR=/usr/lib SYSTEM_DROPIN_DIR=/usr/lib/systemd/system USER_DROPIN_DIR=/usr/lib/systemd/user DIST=archlinux } diff --git a/debian/control b/debian/control index abe2dc0..9bb224c 100644 --- a/debian/control +++ b/debian/control @@ -7,7 +7,7 @@ Build-Depends: libqubes-rpc-filecopy-dev (>= 3.1.3), libvchan-xen-dev, python, - python-setuptools, + python3-setuptools, debhelper, quilt, libxen-dev, @@ -39,12 +39,12 @@ Depends: procps, util-linux, e2fsprogs, - python2.7, - python-daemon, - python-qubesdb, - python-gi, - python-xdg, - python-dbus, + python3-daemon, + python3-distutils, + python3-qubesdb, + python3-gi, + python3-xdg, + python3-dbus, qubes-utils (>= 3.1.3), qubes-core-qrexec, qubesdb-vm, @@ -54,7 +54,7 @@ Depends: xen-utils-common, xen-utils-guest, xenstore-utils, - ${python:Depends}, + ${python3:Depends}, ${shlibs:Depends}, ${misc:Depends} Recommends: @@ -128,7 +128,7 @@ Depends: socat, tinyproxy, iproute2, - ${python:Depends}, + ${python3:Depends}, ${misc:Depends} Suggests: nftables, diff --git a/debian/qubes-core-agent.install b/debian/qubes-core-agent.install index f0f884d..ed90ad8 100644 --- a/debian/qubes-core-agent.install +++ b/debian/qubes-core-agent.install @@ -107,8 +107,8 @@ usr/bin/qvm-connect-tcp usr/bin/qvm-console usr/bin/qvm-sync-clock usr/bin/xenstore-watch-qubes -usr/lib/python2.7/dist-packages/qubesagent-*.egg-info/* -usr/lib/python2.7/dist-packages/qubesagent/* +usr/lib/python3/dist-packages/qubesagent-*.egg-info/* +usr/lib/python3/dist-packages/qubesagent/* usr/lib/qubes-bind-dirs.d/30_cron.conf usr/lib/qubes/close-window usr/lib/qubes/init/bind-dirs.sh diff --git a/debian/rules b/debian/rules index 68d4c83..f8a1b49 100755 --- a/debian/rules +++ b/debian/rules @@ -9,7 +9,7 @@ include /usr/share/dpkg/default.mk export DESTDIR=$(shell pwd)/debian/tmp %: - dh $@ --with systemd,python2 --with=config-package + dh $@ --with systemd,python3 --with=config-package override_dh_auto_build: make all diff --git a/misc/qubes-desktop-run b/misc/qubes-desktop-run index 61de3ee..27d4558 100755 --- a/misc/qubes-desktop-run +++ b/misc/qubes-desktop-run @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 from qubesagent.xdg import launch import sys diff --git a/misc/qubes-session-autostart b/misc/qubes-session-autostart index 7c117a8..1dfcd4b 100644 --- a/misc/qubes-session-autostart +++ b/misc/qubes-session-autostart @@ -1,9 +1,9 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # -*- coding: utf-8 -*- # # The Qubes OS Project, http://www.qubes-os.org # -# Copyright (C) 2015 Marek Marczykowski-Górecki +# Copyright (C) 2015-2019 Marek Marczykowski-Górecki # # # This program is free software; you can redistribute it and/or @@ -21,7 +21,6 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # -import subprocess import sys from xdg.DesktopEntry import DesktopEntry @@ -78,8 +77,9 @@ def process_autostart(environments): if entry_should_be_started(entry, environments): launch(entry_path, wait=False) except Exception as e: - print >>sys.stderr, "Failed to process '{}': {}".format( - entry_name, str(e) + print("Failed to process '{}': {}".format( + entry_name, str(e)), + file=sys.stderr ) def main(): diff --git a/misc/qvm-features-request b/misc/qvm-features-request index 52964d0..4d21c2b 100755 --- a/misc/qvm-features-request +++ b/misc/qvm-features-request @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # vim: fileencoding=utf-8 # diff --git a/qubes-rpc/qrun-in-vm b/qubes-rpc/qrun-in-vm index 266f621..4d416ee 100755 --- a/qubes-rpc/qrun-in-vm +++ b/qubes-rpc/qrun-in-vm @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # Send the command to the remote side, and then transfer stdin from local to # remote and stdout from remote to local. # diff --git a/qubes-rpc/xdg-icon b/qubes-rpc/xdg-icon index a6a81b5..8492c8d 100755 --- a/qubes-rpc/xdg-icon +++ b/qubes-rpc/xdg-icon @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 import xdg.IconTheme import sys import os @@ -7,15 +7,15 @@ themes = ['Humanity', 'Adwaita', 'gnome', 'oxygen'] themes = themes + sorted([d for d in os.listdir("/usr/share/icons") if d not in themes and os.path.isdir("/usr/share/icons/" + d)]) if len(sys.argv) < 3: - print "Usage:", sys.argv[0], "ICON SIZE" - sys.exit(1) + print("Usage:", sys.argv[0], "ICON SIZE") + sys.exit(1) for theme in themes: - icon = xdg.IconTheme.getIconPath(sys.argv[1], theme = theme, size = int(sys.argv[2])) - if icon is not None: - break + icon = xdg.IconTheme.getIconPath(sys.argv[1], theme = theme, size = int(sys.argv[2])) + if icon is not None: + break if icon is None: - sys.exit(1) + sys.exit(1) -print icon +print(icon) diff --git a/qubesagent/firewall.py b/qubesagent/firewall.py index 5443dc0..663d480 100755 --- a/qubesagent/firewall.py +++ b/qubesagent/firewall.py @@ -1,4 +1,3 @@ -#!/usr/bin/python2 -O # vim: fileencoding=utf-8 # @@ -51,13 +50,13 @@ class FirewallWorker(object): self.log.addHandler(logging.StreamHandler(sys.stderr)) def init(self): - '''Create appropriate chains/tables''' + """Create appropriate chains/tables""" raise NotImplementedError def sd_notify(self, state): - '''Send notification to systemd, if available''' + """Send notification to systemd, if available""" # based on sdnotify python module - if not 'NOTIFY_SOCKET' in os.environ: + if 'NOTIFY_SOCKET' not in os.environ: return addr = os.environ['NOTIFY_SOCKET'] if addr[0] == '@': @@ -71,39 +70,40 @@ class FirewallWorker(object): pass def cleanup(self): - '''Remove tables/chains - reverse work done by init''' + """Remove tables/chains - reverse work done by init""" raise NotImplementedError def apply_rules(self, source_addr, rules): - '''Apply rules in given source address''' + """Apply rules in given source address""" raise NotImplementedError def run_firewall_dir(self): - '''Run scripts dir contents, before user script''' + """Run scripts dir contents, before user script""" script_dir_paths = ['/etc/qubes/qubes-firewall.d', - '/rw/config/qubes-firewall.d'] + '/rw/config/qubes-firewall.d'] for script_dir_path in script_dir_paths: - if not os.path.isdir(script_dir_path): - continue - for d_script in sorted(os.listdir(script_dir_path)): - d_script_path = os.path.join(script_dir_path, d_script) - if os.path.isfile(d_script_path) and \ - os.access(d_script_path, os.X_OK): - subprocess.call([d_script_path]) + if not os.path.isdir(script_dir_path): + continue + for d_script in sorted(os.listdir(script_dir_path)): + d_script_path = os.path.join(script_dir_path, d_script) + if os.path.isfile(d_script_path) and \ + os.access(d_script_path, os.X_OK): + subprocess.call([d_script_path]) def run_user_script(self): - '''Run user script in /rw/config''' + """Run user script in /rw/config""" user_script_path = '/rw/config/qubes-firewall-user-script' if os.path.isfile(user_script_path) and \ os.access(user_script_path, os.X_OK): subprocess.call([user_script_path]) def read_rules(self, target): - '''Read rules from QubesDB and return them as a list of dicts''' + """Read rules from QubesDB and return them as a list of dicts""" entries = self.qdb.multiread('/qubes-firewall/{}/'.format(target)) assert isinstance(entries, dict) # drop full path - entries = dict(((k.split('/')[3], v) for k, v in entries.items())) + entries = dict(((k.split('/')[3], v.decode()) + for k, v in entries.items())) if 'policy' not in entries: raise RuleParseError('No \'policy\' defined') policy = entries.pop('policy') @@ -196,7 +196,7 @@ class FirewallWorker(object): class IptablesWorker(FirewallWorker): supported_rule_opts = ['action', 'proto', 'dst4', 'dst6', 'dsthost', - 'dstports', 'specialtarget', 'icmptype'] + 'dstports', 'specialtarget', 'icmptype'] def __init__(self): super(IptablesWorker, self).__init__() @@ -207,7 +207,7 @@ class IptablesWorker(FirewallWorker): @staticmethod def chain_for_addr(addr): - '''Generate iptables chain name for given source address address''' + """Generate iptables chain name for given source address address""" return 'qbs-' + addr.replace('.', '-').replace(':', '-')[-20:] def run_ipt(self, family, args, **kwargs): @@ -221,17 +221,17 @@ class IptablesWorker(FirewallWorker): # pylint: disable=no-self-use if family == 6: return subprocess.Popen(['ip6tables-restore'] + args, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) else: return subprocess.Popen(['iptables-restore'] + args, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) def create_chain(self, addr, chain, family): - ''' + """ Create iptables chain and hook traffic coming from `addr` to it. :param addr: source IP from which traffic should be handled by the @@ -239,7 +239,7 @@ class IptablesWorker(FirewallWorker): :param chain: name of the chain to create :param family: address family (4 or 6) :return: None - ''' + """ self.run_ipt(family, ['-N', chain]) self.run_ipt(family, @@ -247,7 +247,7 @@ class IptablesWorker(FirewallWorker): self.chains[family].add(chain) def prepare_rules(self, chain, rules, family): - ''' + """ Helper function to translate rules list into input for iptables-restore :param chain: name of the chain to put rules into @@ -255,7 +255,7 @@ class IptablesWorker(FirewallWorker): :param family: address family (4 or 6) :return: input for iptables-restore :rtype: str - ''' + """ iptables = "*filter\n" @@ -359,7 +359,7 @@ class IptablesWorker(FirewallWorker): return iptables def apply_rules_family(self, source, rules, family): - ''' + """ Apply rules for given source address. Handle only rules for given address family (IPv4 or IPv6). @@ -367,7 +367,7 @@ class IptablesWorker(FirewallWorker): :param rules: rules list :param family: address family, either 4 or 6 :return: None - ''' + """ chain = self.chain_for_addr(source) if chain not in self.chains[family]: @@ -377,7 +377,7 @@ class IptablesWorker(FirewallWorker): try: self.run_ipt(family, ['-F', chain]) p = self.run_ipt_restore(family, ['-n']) - (output, _) = p.communicate(iptables) + (output, _) = p.communicate(iptables.encode()) if p.returncode != 0: raise RuleApplyError( 'iptables-restore failed: {}'.format(output)) @@ -417,7 +417,7 @@ class IptablesWorker(FirewallWorker): class NftablesWorker(FirewallWorker): supported_rule_opts = ['action', 'proto', 'dst4', 'dst6', 'dsthost', - 'dstports', 'specialtarget', 'icmptype'] + 'dstports', 'specialtarget', 'icmptype'] def __init__(self): super(NftablesWorker, self).__init__() @@ -428,21 +428,21 @@ class NftablesWorker(FirewallWorker): @staticmethod def chain_for_addr(addr): - '''Generate iptables chain name for given source address address''' + """Generate iptables chain name for given source address address""" return 'qbs-' + addr.replace('.', '-').replace(':', '-') def run_nft(self, nft_input): # pylint: disable=no-self-use p = subprocess.Popen(['nft', '-f', '/dev/stdin'], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - stdout, _ = p.communicate(nft_input) + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + stdout, _ = p.communicate(nft_input.encode()) if p.returncode != 0: raise RuleApplyError('nft failed: {}'.format(stdout)) def create_chain(self, addr, chain, family): - ''' + """ Create iptables chain and hook traffic coming from `addr` to it. :param addr: source IP from which traffic should be handled by the @@ -450,7 +450,7 @@ class NftablesWorker(FirewallWorker): :param chain: name of the chain to create :param family: address family (4 or 6) :return: None - ''' + """ nft_input = ( 'table {family} {table} {{\n' ' chain {chain} {{\n' @@ -469,7 +469,7 @@ class NftablesWorker(FirewallWorker): self.chains[family].add(chain) def prepare_rules(self, chain, rules, family): - ''' + """ Helper function to translate rules list into input for iptables-restore :param chain: name of the chain to put rules into @@ -477,7 +477,7 @@ class NftablesWorker(FirewallWorker): :param family: address family (4 or 6) :return: input for iptables-restore :rtype: str - ''' + """ assert family in (4, 6) nft_rules = [] @@ -517,7 +517,6 @@ class NftablesWorker(FirewallWorker): else rule['proto'] nft_rule += ' ip6 nexthdr {}'.format(proto) - if 'dst4' in rule: nft_rule += ' ip daddr {}'.format(rule['dst4']) elif 'dst6' in rule: @@ -587,7 +586,7 @@ class NftablesWorker(FirewallWorker): )) def apply_rules_family(self, source, rules, family): - ''' + """ Apply rules for given source address. Handle only rules for given address family (IPv4 or IPv6). @@ -595,7 +594,7 @@ class NftablesWorker(FirewallWorker): :param rules: rules list :param family: address family, either 4 or 6 :return: None - ''' + """ chain = self.chain_for_addr(source) if chain not in self.chains[family]: @@ -649,5 +648,6 @@ def main(): with context: worker.main() + if __name__ == '__main__': main() diff --git a/qubesagent/test_firewall.py b/qubesagent/test_firewall.py index a9c1294..d06253c 100644 --- a/qubesagent/test_firewall.py +++ b/qubesagent/test_firewall.py @@ -14,7 +14,7 @@ class DummyIptablesRestore(object): self.returncode = 0 def communicate(self, stdin=None): - self._worker_mock.loaded_iptables[self._family] = stdin + self._worker_mock.loaded_iptables[self._family] = stdin.decode() return ("", None) class DummyQubesDB(object): @@ -480,18 +480,18 @@ class TestFirewallWorker(TestCase): self.obj = FirewallWorker() rules = { '10.137.0.1': { - 'policy': 'accept', - '0000': 'proto=tcp dstports=80-80 action=drop', - '0001': 'proto=udp specialtarget=dns action=accept', - '0002': 'proto=udp action=drop', + 'policy': b'accept', + '0000': b'proto=tcp dstports=80-80 action=drop', + '0001': b'proto=udp specialtarget=dns action=accept', + '0002': b'proto=udp action=drop', }, - '10.137.0.2': {'policy': 'accept'}, + '10.137.0.2': {'policy': b'accept'}, # no policy - '10.137.0.3': {'0000': 'proto=tcp action=accept'}, + '10.137.0.3': {'0000': b'proto=tcp action=accept'}, # no action '10.137.0.4': { - 'policy': 'drop', - '0000': 'proto=tcp' + 'policy': b'drop', + '0000': b'proto=tcp' }, } for addr, entries in rules.items(): diff --git a/rpm_spec/core-agent.spec.in b/rpm_spec/core-agent.spec.in index 90e2c01..d72025f 100644 --- a/rpm_spec/core-agent.spec.in +++ b/rpm_spec/core-agent.spec.in @@ -124,12 +124,12 @@ Requires: hostname Requires: xterm # for qubes-desktop-run Requires: pygobject3-base -Requires: dbus-python +Requires: python3-dbus # for qubes-session-autostart, xdg-icon -Requires: pyxdg -Requires: python-daemon +Requires: python3-pyxdg +Requires: python3-daemon # for qvm-feature-request -Requires: python2-qubesdb +Requires: python3-qubesdb Requires: ImageMagick Requires: librsvg2-tools Requires: zenity @@ -137,11 +137,8 @@ Requires: dconf Requires: qubes-core-qrexec-vm Requires: qubes-libvchan Requires: qubes-db-vm -%if 0%{?fedora} >= 23 Requires: python%{python3_pkgversion}-dnf-plugins-qubes-hooks -%else -Requires: python2-dnf-plugins-qubes-hooks -%endif +Requires: python%{python3_pkgversion}-setuptools Obsoletes: qubes-core-vm-kernel-placeholder <= 1.0 Obsoletes: qubes-upgrade-vm < 3.2 Provides: qubes-core-vm = %{version}-%{release} @@ -156,9 +153,7 @@ BuildRequires: libX11-devel BuildRequires: qubes-utils-devel >= 3.1.3 BuildRequires: qubes-libvchan-@BACKEND_VMM@-devel BuildRequires: pam-devel -%if 0%{?rhel} >= 7 -BuildRequires: python-setuptools -%endif +BuildRequires: python%{python3_pkgversion}-setuptools BuildRequires: systemd Source0: %{name}-%{version}.tar.gz @@ -651,7 +646,6 @@ rm -f %{name}-%{version} /usr/lib/qubes/init/resize-rootfs-if-needed.sh /usr/lib/qubes/init/setup-rw.sh /usr/lib/qubes/init/setup-rwdev.sh -/usr/lib/qubes/init/functions %dir /usr/lib/qubes-bind-dirs.d /usr/lib/qubes-bind-dirs.d/30_cron.conf /usr/share/applications/qubes-run-terminal.desktop @@ -663,13 +657,14 @@ rm -f %{name}-%{version} /usr/share/glib-2.0/schemas/20_org.gnome.desktop.wm.preferences.qubes.gschema.override %{_mandir}/man1/qvm-*.1* -%dir %{python2_sitelib}/qubesagent-*-py2.7.egg-info -%{python2_sitelib}/qubesagent-*-py2.7.egg-info/* -%dir %{python2_sitelib}/qubesagent -%{python2_sitelib}/qubesagent/__init__.py* -%{python2_sitelib}/qubesagent/firewall.py* -%{python2_sitelib}/qubesagent/test_firewall.py* -%{python2_sitelib}/qubesagent/xdg.py* +%dir %{python3_sitelib}/qubesagent-*-py*.egg-info +%{python3_sitelib}/qubesagent-*-py*.egg-info/* +%{python3_sitelib}/qubesagent/__pycache__ +%dir %{python3_sitelib}/qubesagent +%{python3_sitelib}/qubesagent/__init__.py* +%{python3_sitelib}/qubesagent/firewall.py* +%{python3_sitelib}/qubesagent/test_firewall.py* +%{python3_sitelib}/qubesagent/xdg.py* /usr/share/qubes/mime-override/globs /usr/share/qubes/qubes-master-key.asc