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 <veiko17@disroot.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Veiko Aasa 2024-12-20 08:36:20 +02:00 committed by James Valleroy
parent cde3f151fb
commit 2e7b9f8a8e
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
4 changed files with 40 additions and 38 deletions

View File

@ -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.torproxy.utils import is_apt_transport_tor_enabled
from plinth.modules.users.components import UsersAndGroups from plinth.modules.users.components import UsersAndGroups
from plinth.package import Packages from plinth.package import Packages
from plinth.privileged import service as service_privileged
from plinth.signals import domain_added, domain_removed from plinth.signals import domain_added, domain_removed
from plinth.utils import format_lazy from plinth.utils import format_lazy
@ -51,7 +52,7 @@ class TorApp(app_module.App):
app_id = 'tor' app_id = 'tor'
_version = 7 _version = 8
def __init__(self) -> None: def __init__(self) -> None:
"""Create components for the app.""" """Create components for the app."""
@ -114,6 +115,7 @@ class TorApp(app_module.App):
def enable(self): def enable(self):
"""Enable the app and update firewall ports.""" """Enable the app and update firewall ports."""
service_privileged.unmask('tor@plinth')
super().enable() super().enable()
privileged.update_ports() privileged.update_ports()
update_hidden_service_domain() update_hidden_service_domain()
@ -121,6 +123,7 @@ class TorApp(app_module.App):
def disable(self): def disable(self):
"""Disable the app and remove HS domain.""" """Disable the app and remove HS domain."""
super().disable() super().disable()
service_privileged.mask('tor@plinth')
update_hidden_service_domain() update_hidden_service_domain()
def diagnose(self) -> list[DiagnosticCheck]: def diagnose(self) -> list[DiagnosticCheck]:
@ -211,6 +214,12 @@ class TorApp(app_module.App):
# operation (Tor setup) is completed. # operation (Tor setup) is completed.
setup_module_.run_setup_on_app('torproxy') 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: if not old_version:
logger.info('Enabling Tor app') logger.info('Enabling Tor app')
self.enable() self.enable()

View File

@ -32,6 +32,11 @@ logger = logging.getLogger(__name__)
@privileged @privileged
def setup(old_version: int): def setup(old_version: int):
"""Setup Tor configuration after installing it.""" """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:
if old_version <= 4: if old_version <= 4:
_upgrade_orport_value() _upgrade_orport_value()
@ -48,9 +53,6 @@ def setup(old_version: int):
def _first_time_setup(): def _first_time_setup():
"""Setup Tor configuration for the first time setting defaults.""" """Setup Tor configuration for the first time setting defaults."""
logger.info('Performing first time setup for Tor') 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) 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): def _use_upstream_bridges(use_upstream_bridges: bool | None = None, aug=None):
"""Enable use of upstream bridges.""" """Enable use of upstream bridges."""
if use_upstream_bridges is None: if use_upstream_bridges is None:
@ -505,3 +496,4 @@ def uninstall():
shutil.rmtree(directory, ignore_errors=True) shutil.rmtree(directory, ignore_errors=True)
os.unlink(f'/var/run/tor-instances/{INSTANCE_NAME}.defaults') os.unlink(f'/var/run/tor-instances/{INSTANCE_NAME}.defaults')
action_utils.service_unmask(SERVICE_NAME)

View File

@ -17,6 +17,7 @@ from plinth.modules.backups.components import BackupRestore
from plinth.modules.firewall.components import Firewall from plinth.modules.firewall.components import Firewall
from plinth.modules.users.components import UsersAndGroups from plinth.modules.users.components import UsersAndGroups
from plinth.package import Packages from plinth.package import Packages
from plinth.privileged import service as service_privileged
from plinth.utils import format_lazy from plinth.utils import format_lazy
from . import manifest, privileged from . import manifest, privileged
@ -46,7 +47,7 @@ class TorProxyApp(app_module.App):
app_id = 'torproxy' app_id = 'torproxy'
_version = 1 _version = 2
def __init__(self) -> None: def __init__(self) -> None:
"""Create components for the app.""" """Create components for the app."""
@ -96,10 +97,16 @@ class TorProxyApp(app_module.App):
**manifest.backup) **manifest.backup)
self.add(backup_restore) self.add(backup_restore)
def enable(self):
"""Enable app."""
service_privileged.unmask('tor@fbxproxy')
super().enable()
def disable(self): def disable(self):
"""Disable APT use of Tor before disabling.""" """Disable APT use of Tor before disabling."""
privileged.configure(apt_transport_tor=False) privileged.configure(apt_transport_tor=False)
super().disable() super().disable()
service_privileged.mask('tor@fbxproxy')
def diagnose(self) -> list[DiagnosticCheck]: def diagnose(self) -> list[DiagnosticCheck]:
"""Run diagnostics and return the results.""" """Run diagnostics and return the results."""
@ -113,7 +120,7 @@ class TorProxyApp(app_module.App):
def setup(self, old_version): def setup(self, old_version):
"""Install and configure the app.""" """Install and configure the app."""
super().setup(old_version) super().setup(old_version)
privileged.setup(old_version) privileged.setup()
if not old_version: if not old_version:
logger.info('Enabling apt-transport-tor') logger.info('Enabling apt-transport-tor')
config = kvstore.get_default(PREINSTALL_CONFIG_KEY, '{}') config = kvstore.get_default(PREINSTALL_CONFIG_KEY, '{}')
@ -128,6 +135,12 @@ class TorProxyApp(app_module.App):
self.enable() self.enable()
kvstore.delete(PREINSTALL_CONFIG_KEY, ignore_missing=True) 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): def uninstall(self):
"""De-configure and uninstall the app.""" """De-configure and uninstall the app."""
super().uninstall() super().uninstall()

View File

@ -24,18 +24,16 @@ TORPROXY_CONFIG_AUG = f'/files/{TORPROXY_CONFIG}'
@privileged @privileged
def setup(old_version: int): def setup():
"""Setup Tor configuration after installing it.""" """Setup Tor configuration."""
_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')
# Disable default tor service. We will use tor@fbxproxy instance # Disable default tor service. We will use tor@fbxproxy instance
# instead. # instead.
_disable_apt_transport_tor() _disable_apt_transport_tor()
# Disable default Tor service.
action_utils.service_disable('tor@default') 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) subprocess.run(['tor-instance-create', INSTANCE_NAME], check=True)
@ -61,8 +59,8 @@ def _first_time_setup():
aug.save() aug.save()
action_utils.service_enable(SERVICE_NAME) if action_utils.service_is_running(SERVICE_NAME):
action_utils.service_restart(SERVICE_NAME) action_utils.service_restart(SERVICE_NAME)
@privileged @privileged
@ -114,17 +112,6 @@ def _get_upstream_bridges(aug) -> str:
return '\n'.join(bridges) 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): def _use_upstream_bridges(use_upstream_bridges: bool | None = None, aug=None):
"""Enable use of upstream bridges.""" """Enable use of upstream bridges."""
if use_upstream_bridges is None: if use_upstream_bridges is None:
@ -214,3 +201,4 @@ def uninstall():
shutil.rmtree(directory, ignore_errors=True) shutil.rmtree(directory, ignore_errors=True)
os.unlink(f'/var/run/tor-instances/{INSTANCE_NAME}.defaults') os.unlink(f'/var/run/tor-instances/{INSTANCE_NAME}.defaults')
action_utils.service_unmask(SERVICE_NAME)