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.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()

View File

@ -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)

View File

@ -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()

View File

@ -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)