From 41c86e0ba3d77ac4beac832db2ec119402c3c45d Mon Sep 17 00:00:00 2001 From: fliu <10025-fliu@users.noreply.salsa.debian.org> Date: Sat, 21 Aug 2021 21:28:43 +0000 Subject: [PATCH] email: configure postfix domain names --- plinth/modules/email_server/__init__.py | 1 + plinth/modules/email_server/audit/domain.py | 152 +++++++++++++++++++- plinth/modules/email_server/views.py | 2 +- 3 files changed, 149 insertions(+), 6 deletions(-) diff --git a/plinth/modules/email_server/__init__.py b/plinth/modules/email_server/__init__.py index 305a10bf3..51851baa2 100644 --- a/plinth/modules/email_server/__init__.py +++ b/plinth/modules/email_server/__init__.py @@ -145,6 +145,7 @@ def setup(helper, old_version=None): """Installs and configures module""" helper.install(packages) helper.install(packages_bloat, skip_recommends=True) + helper.call('post', audit.domain.repair) helper.call('post', audit.ldap.repair) helper.call('post', audit.spam.repair) helper.call('post', audit.tls.repair) diff --git a/plinth/modules/email_server/audit/domain.py b/plinth/modules/email_server/audit/domain.py index 77f1951cb..bdd432e69 100644 --- a/plinth/modules/email_server/audit/domain.py +++ b/plinth/modules/email_server/audit/domain.py @@ -13,8 +13,10 @@ import time from types import SimpleNamespace from django.core.exceptions import ValidationError -from plinth.errors import ActionError +from django.utils.translation import ugettext_lazy as _ from plinth.actions import superuser_run +from plinth.errors import ActionError +from plinth.modules.config import get_domainname from . import models from plinth.modules.email_server import interproc, postconf @@ -29,13 +31,153 @@ class ClientError(RuntimeError): def get(): - # Stub - return [models.Diagnosis('Email domains')] + translation_table = [ + (check_postfix_domains, _('Postfix domain name config')), + ] + results = [] + with postconf.mutex.lock_all(): + for check, title in translation_table: + results.append(check(title)) + return results def repair(): - # Stub - raise RuntimeError() + superuser_run('email_server', ['-i', 'domain', 'set_up']) + + +def repair_component(action_name): + allowed_actions = {'set_up': ['postfix']} + if action_name not in allowed_actions: + return + superuser_run('email_server', ['-i', 'domain', action_name]) + return allowed_actions[action_name] + + +def action_set_up(): + with postconf.mutex.lock_all(): + fix_postfix_domains(check_postfix_domains()) + + +def check_postfix_domains(title=''): + diagnosis = models.MainCfDiagnosis(title, action='set_up') + domain = get_domainname() or 'localhost' + postconf_keys = (k for k in managed_keys if not k.startswith('_')) + conf = postconf.get_many_unsafe(postconf_keys, flag='-x') + + dest_set = set(postconf.parse_maps(conf['mydestination'])) + deletion_set = set() + + temp = _amend_mailname(domain) + if temp is not None: + diagnosis.error('Set /etc/mailname to %s', temp) + diagnosis.flag('_mailname', temp) + + # Amend $mydomain and conf['mydomain'] + temp = _amend_mydomain(conf['mydomain'], domain) + if temp is not None: + diagnosis.error('Set $mydomain to %s', temp) + diagnosis.flag('mydomain', temp) + deletion_set.add(conf['mydomain']) + conf['mydomain'] = temp + + # Amend $myhostname and conf['myhostname'] + temp = _amend_myhostname(conf['myhostname'], conf['mydomain']) + if temp is not None: + diagnosis.error('Set $myhostname to %s', temp) + diagnosis.flag('myhostname', temp) + deletion_set.add(conf['myhostname']) + conf['myhostname'] = temp + + # Delete old domain names + deletion_set.discard('localhost') + dest_set.difference_update(deletion_set) + + # Amend $mydestination + temp = _amend_mydestination(dest_set, conf['mydomain'], conf['myhostname'], + diagnosis.error) + if temp is not None: + diagnosis.flag('mydestination', temp) + elif len(deletion_set) > 0: + corrected_value = ', '.join(sorted(dest_set)) + diagnosis.error('Update $mydestination') + diagnosis.flag('mydestination', corrected_value) + + return diagnosis + + +def _amend_mailname(domain): + with open('/etc/mailname', 'r') as fd: + mailname = fd.readline().strip() + + # If mailname is not localhost, refresh it + if mailname != 'localhost': + temp = _change_to_domain_name(mailname, domain, False) + if temp != mailname: + return temp + + return None + + +def _amend_mydomain(conf_value, domain): + temp = _change_to_domain_name(conf_value, domain, False) + if temp != conf_value: + return temp + + return None + + +def _amend_myhostname(conf_value, mydomain): + if conf_value != mydomain: + if not conf_value.endswith('.' + mydomain): + return mydomain + + return None + + +def _amend_mydestination(dest_set, mydomain, myhostname, error): + addition_set = set() + if mydomain not in dest_set: + error('Value of $mydomain is not in $mydestination') + addition_set.add('$mydomain') + addition_set.add('$myhostname') + if myhostname not in dest_set: + error('Value of $myhostname is not in $mydestination') + addition_set.add('$mydomain') + addition_set.add('$myhostname') + if 'localhost' not in dest_set: + error('localhost is not in $mydestination') + addition_set.add('localhost') + + if addition_set: + addition_set.update(dest_set) + return ', '.join(sorted(addition_set)) + + return None + + +def _change_to_domain_name(value, domain, allow_old_fqdn): + # Detect invalid values + if not value or '.' not in value: + return domain + + if not allow_old_fqdn and value != domain: + return domain + else: + return value + + +def fix_postfix_domains(diagnosis): + diagnosis.apply_changes(_apply_domain_changes) + + +def _apply_domain_changes(conf_dict): + for key, value in conf_dict.items(): + if key.startswith('_'): + update = globals()['su_set' + key] + update(value) + + post = {k: v for (k, v) in conf_dict.items() if not k.startswith('_')} + postconf.set_many_unsafe(post) def get_domain_config(): diff --git a/plinth/modules/email_server/views.py b/plinth/modules/email_server/views.py index 57492845a..81ff70dd5 100644 --- a/plinth/modules/email_server/views.py +++ b/plinth/modules/email_server/views.py @@ -85,7 +85,7 @@ class EmailServerView(TabMixin, AppView): """Server configuration page""" app_id = 'email_server' template_name = 'email_server.html' - audit_modules = ('tls', 'rcube') + audit_modules = ('domain', 'tls', 'rcube') def get_context_data(self, *args, **kwargs): dlist = []