From 6e8b825d44e848695df15950cb978bb76a96c408 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Thu, 14 Oct 2021 18:29:33 -0700 Subject: [PATCH] email_server: aliases: Drop hash DB and use sqlite3 directly - Postfix has the ability to use sqlite3 databases directly. There is no need to synchronize to a hash db and then use that. - Store the aliases database in /var/lib/postfix/. This will make backup and restore easier and remove dependence on FreedomBox and its data directory. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/modules/email_server/__init__.py | 1 + .../modules/email_server/aliases/__init__.py | 49 ++----------------- plinth/modules/email_server/audit/__init__.py | 6 ++- plinth/modules/email_server/audit/aliases.py | 12 +++++ plinth/modules/email_server/audit/ldap.py | 2 +- .../data/etc/postfix/freedombox-aliases.cf | 5 ++ 6 files changed, 26 insertions(+), 49 deletions(-) create mode 100644 plinth/modules/email_server/audit/aliases.py create mode 100644 plinth/modules/email_server/data/etc/postfix/freedombox-aliases.cf diff --git a/plinth/modules/email_server/__init__.py b/plinth/modules/email_server/__init__.py index c2adc5efe..8926ea019 100644 --- a/plinth/modules/email_server/__init__.py +++ b/plinth/modules/email_server/__init__.py @@ -30,6 +30,7 @@ package_conflicts_action = 'ignore' packages = [ 'postfix-ldap', + 'postfix-sqlite', 'dovecot-pop3d', 'dovecot-imapd', 'dovecot-ldap', diff --git a/plinth/modules/email_server/aliases/__init__.py b/plinth/modules/email_server/aliases/__init__.py index d12d70946..206409056 100644 --- a/plinth/modules/email_server/aliases/__init__.py +++ b/plinth/modules/email_server/aliases/__init__.py @@ -2,13 +2,10 @@ # SPDX-License-Identifier: AGPL-3.0-or-later import contextlib -import dbm -import logging -import os import pwd import sqlite3 -from plinth.modules.email_server import lock +from plinth import actions from . import models @@ -24,12 +21,7 @@ CREATE TABLE IF NOT EXISTS Alias ( COMMIT; """ -mailsrv_dir = '/var/lib/plinth/mailsrv' -hash_db_path = mailsrv_dir + '/aliases' -sqlite_db_path = mailsrv_dir + '/aliases.sqlite3' - -alias_sync_mutex = lock.Mutex('alias-sync') -logger = logging.getLogger(__name__) +sqlite_db_path = '/var/lib/postfix/freedombox-aliases/aliases.sqlite3' @contextlib.contextmanager @@ -74,8 +66,6 @@ def put(uid_number, email_name): with db_cursor() as cur: cur.execute(s, (email_name, uid_number, 1, email_name)) - schedule_hash_update() - def delete(uid_number, alias_list): s = 'DELETE FROM Alias WHERE uid_number=? AND email_name=?' @@ -84,7 +74,6 @@ def delete(uid_number, alias_list): cur.execute('BEGIN') cur.executemany(s, parameter_seq) cur.execute('COMMIT') - schedule_hash_update() def set_enabled(uid_number, alias_list): @@ -102,46 +91,14 @@ def _set_status(uid_number, alias_list, status): cur.execute('BEGIN') cur.executemany(s, parameter_seq) cur.execute('COMMIT') - schedule_hash_update() - - -def schedule_hash_update(): - tmp = hash_db_path + '-tmp' - with alias_sync_mutex.lock_all(), db_cursor() as cur: - all_aliases = cur.execute('SELECT * FROM Alias') - - # Delete the temp file if exists - if os.path.exists(tmp): - os.unlink(tmp) - - # Create new alias db at temp path - db = dbm.ndbm.open(tmp, 'c') - try: - for row in all_aliases: - alias = models.Alias(**row) - key = alias.email_name.encode('ascii') + b'\0' - if alias.enabled: - value = str(alias.uid_number).encode('ascii') - value += b'@localhost\0' - else: - value = b'/dev/null\0' - db[key] = value - finally: - db.close() - - # Atomically replace old alias db, rename(2) - os.rename(tmp + '.db', hash_db_path + '.db') def first_setup(): + actions.superuser_run('email_server', ['-i', 'aliases', 'setup']) _create_db_schema_if_not_exists() - schedule_hash_update() def _create_db_schema_if_not_exists(): - # Create folder - if not os.path.isdir(mailsrv_dir): - os.mkdir(mailsrv_dir) # Create schema if not exists with db_cursor() as cur: cur.executescript(map_db_schema_script) diff --git a/plinth/modules/email_server/audit/__init__.py b/plinth/modules/email_server/audit/__init__.py index c543f483d..e35045731 100644 --- a/plinth/modules/email_server/audit/__init__.py +++ b/plinth/modules/email_server/audit/__init__.py @@ -3,6 +3,8 @@ Provides diagnosis and repair of email server configuration issues """ -from . import domain, home, ldap, models, rcube, spam, tls +from . import aliases, domain, home, ldap, models, rcube, spam, tls -__all__ = ['domain', 'home', 'ldap', 'models', 'rcube', 'spam', 'tls'] +__all__ = [ + 'aliases', 'domain', 'home', 'ldap', 'models', 'rcube', 'spam', 'tls' +] diff --git a/plinth/modules/email_server/audit/aliases.py b/plinth/modules/email_server/audit/aliases.py new file mode 100644 index 000000000..6edba5865 --- /dev/null +++ b/plinth/modules/email_server/audit/aliases.py @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Privileged operations for managing aliases.""" + +import pathlib +import shutil + + +def action_setup(): + """Create a the sqlite3 database to be managed by FreedomBox.""" + path = pathlib.Path('/var/lib/postfix/freedombox-aliases/') + path.mkdir(mode=0o750, exist_ok=True) + shutil.chown(path, user='plinth', group='postfix') diff --git a/plinth/modules/email_server/audit/ldap.py b/plinth/modules/email_server/audit/ldap.py index 570adedd6..b62cabd5c 100644 --- a/plinth/modules/email_server/audit/ldap.py +++ b/plinth/modules/email_server/audit/ldap.py @@ -56,7 +56,7 @@ default_smtps_options = { MAILSRV_DIR = '/var/lib/plinth/mailsrv' ETC_ALIASES = 'hash:/etc/aliases' BEFORE_ALIASES = 'ldap:/etc/postfix/freedombox-username-to-uid-number.cf' -AFTER_ALIASES = 'hash:' + aliases.hash_db_path +AFTER_ALIASES = 'sqlite:/etc/postfix/freedombox-aliases.cf' logger = logging.getLogger(__name__) diff --git a/plinth/modules/email_server/data/etc/postfix/freedombox-aliases.cf b/plinth/modules/email_server/data/etc/postfix/freedombox-aliases.cf new file mode 100644 index 000000000..1d4b256b3 --- /dev/null +++ b/plinth/modules/email_server/data/etc/postfix/freedombox-aliases.cf @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later + +# Maintained by FreedomBox, do not edit. +dbpath = /var/lib/postfix/freedombox-aliases/aliases.sqlite3 +query = SELECT uid_number FROM Alias WHERE email_name='%s' AND status=1