From 2e7b9f8a8e4dad0b7fd1adc392dd406366df8fca Mon Sep 17 00:00:00 2001 From: Veiko Aasa Date: Fri, 20 Dec 2024 08:36:20 +0200 Subject: [PATCH] tor, torproxy: Fix daemon services are running after reboot when app is disabled Mask disabled Tor systemd services to prevent services starting by the Tor master service after system reboot. Also: - Fix torproxy app always enabled after setup. - Minor privileged code cleanup - removed unused functions. Tests performed on Debian stable and testing: - Installed and disabled the apps, rebooted the system, then applied the patch. Ensured that apps are upgraded successfully and apps are disabled after upgrade. Ensured that tor@default, tor@plinth and tor@fbxlocal services are masked and not running. - After 1)enabling and 2)disabling both apps and 3)rebooting the system: - Ensured that the tor@default service is not running and is masked. - Ensured that tor@plinth or tor@fbxproxy service states match the states of the app. - Uninstalled the apps, ensured that only the tor@default service masked state remains in the systemd. - All the tor and torproxy tests pass. Closes #2369, #2454. Signed-off-by: Veiko Aasa Reviewed-by: James Valleroy --- plinth/modules/tor/__init__.py | 11 +++++++++- plinth/modules/tor/privileged.py | 20 ++++++------------ plinth/modules/torproxy/__init__.py | 17 +++++++++++++-- plinth/modules/torproxy/privileged.py | 30 ++++++++------------------- 4 files changed, 40 insertions(+), 38 deletions(-) diff --git a/plinth/modules/tor/__init__.py b/plinth/modules/tor/__init__.py index 1aaafa8c7..91085ff5e 100644 --- a/plinth/modules/tor/__init__.py +++ b/plinth/modules/tor/__init__.py @@ -22,6 +22,7 @@ from plinth.modules.names.components import DomainType from plinth.modules.torproxy.utils import is_apt_transport_tor_enabled from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages +from plinth.privileged import service as service_privileged from plinth.signals import domain_added, domain_removed from plinth.utils import format_lazy @@ -51,7 +52,7 @@ class TorApp(app_module.App): app_id = 'tor' - _version = 7 + _version = 8 def __init__(self) -> None: """Create components for the app.""" @@ -114,6 +115,7 @@ class TorApp(app_module.App): def enable(self): """Enable the app and update firewall ports.""" + service_privileged.unmask('tor@plinth') super().enable() privileged.update_ports() update_hidden_service_domain() @@ -121,6 +123,7 @@ class TorApp(app_module.App): def disable(self): """Disable the app and remove HS domain.""" super().disable() + service_privileged.mask('tor@plinth') update_hidden_service_domain() def diagnose(self) -> list[DiagnosticCheck]: @@ -211,6 +214,12 @@ class TorApp(app_module.App): # operation (Tor setup) is completed. setup_module_.run_setup_on_app('torproxy') + # Version 8 masks the tor@plinth service when disabling the app to + # prevent the service starting by the Tor master service after system + # reboot. + if old_version and old_version < 8 and not self.is_enabled(): + self.disable() + if not old_version: logger.info('Enabling Tor app') self.enable() diff --git a/plinth/modules/tor/privileged.py b/plinth/modules/tor/privileged.py index c32a31dc5..b2b4847f2 100644 --- a/plinth/modules/tor/privileged.py +++ b/plinth/modules/tor/privileged.py @@ -32,6 +32,11 @@ logger = logging.getLogger(__name__) @privileged def setup(old_version: int): """Setup Tor configuration after installing it.""" + # Disable default Tor service. We will use tor@plinth instance instead. + action_utils.service_disable('tor@default') + # Mask the service to prevent re-enabling it by the Tor master service. + action_utils.service_mask('tor@default') + if old_version: if old_version <= 4: _upgrade_orport_value() @@ -48,9 +53,6 @@ def setup(old_version: int): def _first_time_setup(): """Setup Tor configuration for the first time setting defaults.""" logger.info('Performing first time setup for Tor') - # Disable default tor service. We will use tor@plinth instance - # instead. - action_utils.service_disable('tor@default') subprocess.run(['tor-instance-create', INSTANCE_NAME], check=True) @@ -311,17 +313,6 @@ def _get_hidden_service(aug=None) -> dict[str, Any]: } -def _enable(): - """Enable and start the service.""" - action_utils.service_enable(SERVICE_NAME) - _update_ports() - - -def _disable(): - """Disable and stop the service.""" - action_utils.service_disable(SERVICE_NAME) - - def _use_upstream_bridges(use_upstream_bridges: bool | None = None, aug=None): """Enable use of upstream bridges.""" if use_upstream_bridges is None: @@ -505,3 +496,4 @@ def uninstall(): shutil.rmtree(directory, ignore_errors=True) os.unlink(f'/var/run/tor-instances/{INSTANCE_NAME}.defaults') + action_utils.service_unmask(SERVICE_NAME) diff --git a/plinth/modules/torproxy/__init__.py b/plinth/modules/torproxy/__init__.py index 191dd30de..3fb376745 100644 --- a/plinth/modules/torproxy/__init__.py +++ b/plinth/modules/torproxy/__init__.py @@ -17,6 +17,7 @@ from plinth.modules.backups.components import BackupRestore from plinth.modules.firewall.components import Firewall from plinth.modules.users.components import UsersAndGroups from plinth.package import Packages +from plinth.privileged import service as service_privileged from plinth.utils import format_lazy from . import manifest, privileged @@ -46,7 +47,7 @@ class TorProxyApp(app_module.App): app_id = 'torproxy' - _version = 1 + _version = 2 def __init__(self) -> None: """Create components for the app.""" @@ -96,10 +97,16 @@ class TorProxyApp(app_module.App): **manifest.backup) self.add(backup_restore) + def enable(self): + """Enable app.""" + service_privileged.unmask('tor@fbxproxy') + super().enable() + def disable(self): """Disable APT use of Tor before disabling.""" privileged.configure(apt_transport_tor=False) super().disable() + service_privileged.mask('tor@fbxproxy') def diagnose(self) -> list[DiagnosticCheck]: """Run diagnostics and return the results.""" @@ -113,7 +120,7 @@ class TorProxyApp(app_module.App): def setup(self, old_version): """Install and configure the app.""" super().setup(old_version) - privileged.setup(old_version) + privileged.setup() if not old_version: logger.info('Enabling apt-transport-tor') config = kvstore.get_default(PREINSTALL_CONFIG_KEY, '{}') @@ -128,6 +135,12 @@ class TorProxyApp(app_module.App): self.enable() kvstore.delete(PREINSTALL_CONFIG_KEY, ignore_missing=True) + # Version 2 masks the tor@fbproxy service when disabling the app to + # prevent the service starting by the Tor master service after system + # reboot. + if old_version and old_version < 2 and not self.is_enabled(): + self.disable() + def uninstall(self): """De-configure and uninstall the app.""" super().uninstall() diff --git a/plinth/modules/torproxy/privileged.py b/plinth/modules/torproxy/privileged.py index 46b12393d..0f66d43ea 100644 --- a/plinth/modules/torproxy/privileged.py +++ b/plinth/modules/torproxy/privileged.py @@ -24,18 +24,16 @@ TORPROXY_CONFIG_AUG = f'/files/{TORPROXY_CONFIG}' @privileged -def setup(old_version: int): - """Setup Tor configuration after installing it.""" - _first_time_setup() - - -def _first_time_setup(): - """Setup Tor configuration for the first time setting defaults.""" - logger.info('Performing first time setup for Tor Proxy') +def setup(): + """Setup Tor configuration.""" # Disable default tor service. We will use tor@fbxproxy instance # instead. _disable_apt_transport_tor() + + # Disable default Tor service. action_utils.service_disable('tor@default') + # Mask the service to prevent re-enabling it by the Tor master service. + action_utils.service_mask('tor@default') subprocess.run(['tor-instance-create', INSTANCE_NAME], check=True) @@ -61,8 +59,8 @@ def _first_time_setup(): aug.save() - action_utils.service_enable(SERVICE_NAME) - action_utils.service_restart(SERVICE_NAME) + if action_utils.service_is_running(SERVICE_NAME): + action_utils.service_restart(SERVICE_NAME) @privileged @@ -114,17 +112,6 @@ def _get_upstream_bridges(aug) -> str: return '\n'.join(bridges) -def _enable(): - """Enable and start the service.""" - action_utils.service_enable(SERVICE_NAME) - - -def _disable(): - """Disable and stop the service.""" - _disable_apt_transport_tor() - action_utils.service_disable(SERVICE_NAME) - - def _use_upstream_bridges(use_upstream_bridges: bool | None = None, aug=None): """Enable use of upstream bridges.""" if use_upstream_bridges is None: @@ -214,3 +201,4 @@ def uninstall(): shutil.rmtree(directory, ignore_errors=True) os.unlink(f'/var/run/tor-instances/{INSTANCE_NAME}.defaults') + action_utils.service_unmask(SERVICE_NAME)