From b9c5cd248f3adc5fac39c0a93e2f72104bccee00 Mon Sep 17 00:00:00 2001 From: matidau <65836048+matidau@users.noreply.github.com> Date: Thu, 15 Aug 2024 22:49:52 +1000 Subject: [PATCH 01/24] Update Roundcube to 1.6.8 (#2422) --- setup/webmail.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/webmail.sh b/setup/webmail.sh index 66a85596..4591119c 100644 --- a/setup/webmail.sh +++ b/setup/webmail.sh @@ -36,8 +36,8 @@ apt_install \ # https://github.com/mstilkerich/rcmcarddav/releases # The easiest way to get the package hashes is to run this script and get the hash from # the error message. -VERSION=1.6.6 -HASH=7705d2736890c49e7ae3ac75e3ae00ba56187056 +VERSION=1.6.8 +HASH=00586f5163b3f6c1b0798be745982e3547b1b24a PERSISTENT_LOGIN_VERSION=bde7b6840c7d91de627ea14e81cf4133cbb3c07a # version 5.3 HTML5_NOTIFIER_VERSION=68d9ca194212e15b3c7225eb6085dbcf02fd13d7 # version 0.6.4+ CARDDAV_VERSION=4.4.3 From 41870d22b0c679f433c2c568b8fd0eb85b720f4c Mon Sep 17 00:00:00 2001 From: Joshua Tauberer Date: Thu, 15 Aug 2024 08:52:48 -0400 Subject: [PATCH 02/24] v70 --- CHANGELOG.md | 5 +++++ setup/bootstrap.sh | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f27aff7c..718e6682 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +Version 70 (August 15, 2024) +---------------------------- + +* Roundcube is updated to version 1.6.8 fixing security vulnerabilities. + Version 69 (July 20, 2024) -------------------------- diff --git a/setup/bootstrap.sh b/setup/bootstrap.sh index 18c53559..00d1b214 100644 --- a/setup/bootstrap.sh +++ b/setup/bootstrap.sh @@ -23,7 +23,7 @@ if [ -z "$TAG" ]; then if [ "$UBUNTU_VERSION" == "Ubuntu 22.04 LTS" ]; then # This machine is running Ubuntu 22.04, which is supported by # Mail-in-a-Box versions 60 and later. - TAG=v69b + TAG=v70 elif [ "$UBUNTU_VERSION" == "Ubuntu 18.04 LTS" ]; then # This machine is running Ubuntu 18.04, which is supported by # Mail-in-a-Box versions 0.40 through 5x. From f453c44d524b68a3a99f567168dd401f88556633 Mon Sep 17 00:00:00 2001 From: darren Date: Fri, 30 Aug 2024 11:26:05 -0700 Subject: [PATCH 03/24] Update setup to handle multiple SSH ports (#2437) This PR addresses an issue reported in the mailinabox Slack channel where a system had sshd configured to listen on two ports. Co-authored-by: Darren Sanders --- setup/system.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/setup/system.sh b/setup/system.sh index fac50df7..b8d65608 100755 --- a/setup/system.sh +++ b/setup/system.sh @@ -270,14 +270,14 @@ if [ -z "${DISABLE_FIREWALL:-}" ]; then # ssh might be running on an alternate port. Use sshd -T to dump sshd's #NODOC # settings, find the port it is supposedly running on, and open that port #NODOC # too. #NODOC - SSH_PORT=$(sshd -T 2>/dev/null | grep "^port " | sed "s/port //") #NODOC + SSH_PORT=$(sshd -T 2>/dev/null | grep "^port " | sed "s/port //" | tr '\n' ' ') #NODOC if [ -n "$SSH_PORT" ]; then - if [ "$SSH_PORT" != "22" ]; then - - echo "Opening alternate SSH port $SSH_PORT." #NODOC - ufw_limit "$SSH_PORT" #NODOC - - fi + for $port in $SSH_PORT; do + if [ "$port" != "22" ]; then + echo "Opening alternate SSH port $port." #NODOC + ufw_limit "$port" #NODOC + fi + done fi ufw --force enable; From 3b8f4a2fe8bd686f9d3ff405d9bb380c3c6315a8 Mon Sep 17 00:00:00 2001 From: matidau <65836048+matidau@users.noreply.github.com> Date: Sat, 31 Aug 2024 04:27:44 +1000 Subject: [PATCH 04/24] Z-Push remove config lines no longer supported (#2433) --- setup/zpush.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/setup/zpush.sh b/setup/zpush.sh index 3b14c047..a5538d70 100755 --- a/setup/zpush.sh +++ b/setup/zpush.sh @@ -57,8 +57,6 @@ fi sed -i "s^define('TIMEZONE', .*^define('TIMEZONE', '$(cat /etc/timezone)');^" /usr/local/lib/z-push/config.php sed -i "s/define('BACKEND_PROVIDER', .*/define('BACKEND_PROVIDER', 'BackendCombined');/" /usr/local/lib/z-push/config.php sed -i "s/define('USE_FULLEMAIL_FOR_LOGIN', .*/define('USE_FULLEMAIL_FOR_LOGIN', true);/" /usr/local/lib/z-push/config.php -sed -i "s/define('LOG_MEMORY_PROFILER', .*/define('LOG_MEMORY_PROFILER', false);/" /usr/local/lib/z-push/config.php -sed -i "s/define('BUG68532FIXED', .*/define('BUG68532FIXED', false);/" /usr/local/lib/z-push/config.php sed -i "s/define('LOGLEVEL', .*/define('LOGLEVEL', LOGLEVEL_ERROR);/" /usr/local/lib/z-push/config.php # Configure BACKEND From ca123515aad102327701b18a7d65d180f800b815 Mon Sep 17 00:00:00 2001 From: Downtown Allday Date: Mon, 2 Sep 2024 21:30:01 -0400 Subject: [PATCH 05/24] fix variable (#2439) --- setup/system.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/system.sh b/setup/system.sh index b8d65608..7467a72c 100755 --- a/setup/system.sh +++ b/setup/system.sh @@ -272,7 +272,7 @@ if [ -z "${DISABLE_FIREWALL:-}" ]; then # too. #NODOC SSH_PORT=$(sshd -T 2>/dev/null | grep "^port " | sed "s/port //" | tr '\n' ' ') #NODOC if [ -n "$SSH_PORT" ]; then - for $port in $SSH_PORT; do + for port in $SSH_PORT; do if [ "$port" != "22" ]; then echo "Opening alternate SSH port $port." #NODOC ufw_limit "$port" #NODOC From 1699ab8c02e6813075a65fff9903c85e31d52445 Mon Sep 17 00:00:00 2001 From: matidau <65836048+matidau@users.noreply.github.com> Date: Wed, 18 Sep 2024 04:51:26 +1000 Subject: [PATCH 06/24] Update zpush.sh to version 2.7.4 (#2423) --- setup/zpush.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/zpush.sh b/setup/zpush.sh index a5538d70..5c3e5b30 100755 --- a/setup/zpush.sh +++ b/setup/zpush.sh @@ -22,8 +22,8 @@ apt_install \ phpenmod -v "$PHP_VER" imap # Copy Z-Push into place. -VERSION=2.7.3 -TARGETHASH=9d4bec41935e9a4e07880c5ff915bcddbda4443b +VERSION=2.7.4 +TARGETHASH=78744d56b8799d9828ec8f99a12c1af4e9f9239b needs_update=0 #NODOC if [ ! -f /usr/local/lib/z-push/version ]; then needs_update=1 #NODOC From a8d13b84b4e2ac7332ae825177c4f9aa7a01e782 Mon Sep 17 00:00:00 2001 From: Downtown Allday Date: Wed, 27 Nov 2024 08:22:45 -0500 Subject: [PATCH 07/24] fix: NameError: name 'subprocess' is not defined (#2425) --- management/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/management/utils.py b/management/utils.py index 397f124d..1dbbeb7e 100644 --- a/management/utils.py +++ b/management/utils.py @@ -189,6 +189,7 @@ def get_ssh_port(): def get_ssh_config_value(parameter_name): # Returns ssh configuration value for the provided parameter + import subprocess try: output = shell('check_output', ['sshd', '-T']) except FileNotFoundError: From 7ef859ce961ea24b70f7e4f8307f069a8f7b42b3 Mon Sep 17 00:00:00 2001 From: matidau <65836048+matidau@users.noreply.github.com> Date: Sat, 14 Dec 2024 01:28:45 +1100 Subject: [PATCH 08/24] Update zpush.sh to version 2.7.5 (#2463) --- setup/zpush.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/zpush.sh b/setup/zpush.sh index 5c3e5b30..5e0ea2c4 100755 --- a/setup/zpush.sh +++ b/setup/zpush.sh @@ -22,8 +22,8 @@ apt_install \ phpenmod -v "$PHP_VER" imap # Copy Z-Push into place. -VERSION=2.7.4 -TARGETHASH=78744d56b8799d9828ec8f99a12c1af4e9f9239b +VERSION=2.7.5 +TARGETHASH=f0b0b06e255f3496173ab9d28a4f2d985184720e needs_update=0 #NODOC if [ ! -f /usr/local/lib/z-push/version ]; then needs_update=1 #NODOC From 81b0e0a64f3ed295205dbc5461bb8f4fc2791e3d Mon Sep 17 00:00:00 2001 From: Nicholas Wilson Date: Sun, 22 Dec 2024 06:26:59 -0600 Subject: [PATCH 09/24] Updated CHANGELOG.md, fix typo(s) (#2459) --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 718e6682..55cd75b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,7 +73,7 @@ Version 64 (September 2, 2023) * Fixed backups to work with the latest duplicity package which was not backwards compatible. * Fixed setting B2 as a backup target with a slash in the application key. * Turned off OpenDMARC diagnostic reports sent in response to incoming mail. -* Fixed some crashes when using an unrelased version of Mail-in-a-Box. +* Fixed some crashes when using an unreleased version of Mail-in-a-Box. * Added z-push administration scripts. Version 63 (July 27, 2023) @@ -1129,7 +1129,7 @@ Control panel: System: * The munin system monitoring tool is now installed and accessible at /admin/munin. -* ownCloud updated to version 8.0.4. The ownCloud installation step now is reslient to download problems. The ownCloud configuration file is now stored in STORAGE_ROOT to fix loss of data when moving STORAGE_ROOT to a new machine. +* ownCloud updated to version 8.0.4. The ownCloud installation step now is resilient to download problems. The ownCloud configuration file is now stored in STORAGE_ROOT to fix loss of data when moving STORAGE_ROOT to a new machine. * The setup scripts now run `apt-get update` prior to installing anything to ensure the apt database is in sync with the packages actually available. @@ -1167,7 +1167,7 @@ DNS: * Internationalized Domain Names (IDNs) should now work in email. If you had custom DNS or custom web settings for internationalized domains, check that they are still working. * It is now possible to set multiple TXT and other types of records on the same domain in the control panel. * The custom DNS API was completely rewritten to support setting multiple records of the same type on a domain. Any existing client code using the DNS API will have to be rewritten. (Existing code will just get 404s back.) -* On some systems the `nsd` service failed to start if network inferfaces were not ready. +* On some systems the `nsd` service failed to start if network interfaces were not ready. System / Control Panel: From d8563be38b2fa047725ee85c7330bdf775101cdd Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 22 Dec 2024 04:27:36 -0800 Subject: [PATCH 10/24] Disable MOTD advertisements (#2457) Disables MOTD advertisements which use a script to send server information in `wget` headers to Canonical. --- setup/system.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/setup/system.sh b/setup/system.sh index 7467a72c..dd366401 100755 --- a/setup/system.sh +++ b/setup/system.sh @@ -83,6 +83,13 @@ fi # (See https://discourse.mailinabox.email/t/journalctl-reclaim-space-on-small-mailinabox/6728/11.) tools/editconf.py /etc/systemd/journald.conf MaxRetentionSec=10day +# ### Improve server privacy + +# Disable MOTD adverts to prevent revealing server information in MOTD request headers +# See https://ma.ttias.be/what-exactly-being-sent-ubuntu-motd/ +tools/editconf.py /etc/default/motd-news ENABLED=0 +rm -f /var/cache/motd-news + # ### Add PPAs. # We install some non-standard Ubuntu packages maintained by other From ee0d750b8560b0e2e9a9bf0afe52ed12982cb7f2 Mon Sep 17 00:00:00 2001 From: Harm Berntsen Date: Sun, 22 Dec 2024 13:28:04 +0100 Subject: [PATCH 11/24] Add missing php-xml package for Roundcube without Nextcloud (#2441) When the Nextcloud installation is skipped, php8.0-xml will also not be installed. This causes issues for Roundcube because it won't load: `PHP Fatal error: Uncaught Error: Class "DOMDocument" not found in /usr/local/lib/roundcubemail/program/lib/Roundcube/html.php:367`. Installing the package on the Roundcube side as well fixes it for me. --- setup/webmail.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/webmail.sh b/setup/webmail.sh index 4591119c..db95028b 100644 --- a/setup/webmail.sh +++ b/setup/webmail.sh @@ -23,7 +23,7 @@ echo "Installing Roundcube (webmail)..." apt_install \ dbconfig-common \ php"${PHP_VER}"-cli php"${PHP_VER}"-sqlite3 php"${PHP_VER}"-intl php"${PHP_VER}"-common php"${PHP_VER}"-curl php"${PHP_VER}"-imap \ - php"${PHP_VER}"-gd php"${PHP_VER}"-pspell php"${PHP_VER}"-mbstring libjs-jquery libjs-jquery-mousewheel libmagic1 \ + php"${PHP_VER}"-gd php"${PHP_VER}"-pspell php"${PHP_VER}"-mbstring php"${PHP_VER}"-xml libjs-jquery libjs-jquery-mousewheel libmagic1 \ sqlite3 # Install Roundcube from source if it is not already present or if it is out of date. From 3d59f2d7e0d0c2794f88fc36d5fca11fc757f9a7 Mon Sep 17 00:00:00 2001 From: KiekerJan Date: Sun, 22 Dec 2024 13:28:39 +0100 Subject: [PATCH 12/24] Update roundcube to 1.6.9 (#2440) --- setup/webmail.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/webmail.sh b/setup/webmail.sh index db95028b..a203cb8c 100644 --- a/setup/webmail.sh +++ b/setup/webmail.sh @@ -36,8 +36,8 @@ apt_install \ # https://github.com/mstilkerich/rcmcarddav/releases # The easiest way to get the package hashes is to run this script and get the hash from # the error message. -VERSION=1.6.8 -HASH=00586f5163b3f6c1b0798be745982e3547b1b24a +VERSION=1.6.9 +HASH=b63f74209cf287402f6f44b85877388899261f3c PERSISTENT_LOGIN_VERSION=bde7b6840c7d91de627ea14e81cf4133cbb3c07a # version 5.3 HTML5_NOTIFIER_VERSION=68d9ca194212e15b3c7225eb6085dbcf02fd13d7 # version 0.6.4+ CARDDAV_VERSION=4.4.3 From e36c17fc72249fef1eb6b638c4fa3ad2ad765d32 Mon Sep 17 00:00:00 2001 From: matidau <65836048+matidau@users.noreply.github.com> Date: Sun, 22 Dec 2024 23:42:56 +1100 Subject: [PATCH 13/24] Fixstates only after Z-Push upgrade (#2432) --- setup/zpush.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup/zpush.sh b/setup/zpush.sh index 5e0ea2c4..397ee4a9 100755 --- a/setup/zpush.sh +++ b/setup/zpush.sh @@ -110,4 +110,6 @@ restart_service php"$PHP_VER"-fpm # Fix states after upgrade -hide_output php"$PHP_VER" /usr/local/lib/z-push/z-push-admin.php -a fixstates +if [ $needs_update == 1 ]; then + hide_output php"$PHP_VER" /usr/local/lib/z-push/z-push-admin.php -a fixstates +fi From 9f87b36ba182e5ec6e519a4a6c27e9ead8c08469 Mon Sep 17 00:00:00 2001 From: KiekerJan Date: Sun, 22 Dec 2024 13:45:45 +0100 Subject: [PATCH 14/24] add check on SOA record to determine up to date synchronization of secondary nameserver (#2429) --- management/status_checks.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/management/status_checks.py b/management/status_checks.py index 51f8e631..96d10c95 100755 --- a/management/status_checks.py +++ b/management/status_checks.py @@ -521,6 +521,8 @@ def check_dns_zone(domain, env, output, dns_zonefiles): # Check that each custom secondary nameserver resolves the IP address. if custom_secondary_ns and not probably_external_dns: + SOARecord = query_dns(domain, "SOA", at=env['PUBLIC_IP'])# Explicitly ask the local dns server. + for ns in custom_secondary_ns: # We must first resolve the nameserver to an IP address so we can query it. ns_ips = query_dns(ns, "A") @@ -530,15 +532,36 @@ def check_dns_zone(domain, env, output, dns_zonefiles): # Choose the first IP if nameserver returns multiple ns_ip = ns_ips.split('; ')[0] + checkSOA = True + # Now query it to see what it says about this domain. ip = query_dns(domain, "A", at=ns_ip, nxdomain=None) if ip == correct_ip: - output.print_ok("Secondary nameserver %s resolved the domain correctly." % ns) + output.print_ok(f"Secondary nameserver {ns} resolved the domain correctly.") elif ip is None: - output.print_error("Secondary nameserver %s is not configured to resolve this domain." % ns) + output.print_error(f"Secondary nameserver {ns} is not configured to resolve this domain.") + # No need to check SOA record if not configured as nameserver + checkSOA = False + elif ip == '[timeout]': + output.print_error(f"Secondary nameserver {ns} did not resolve this domain, result: {ip}") + checkSOA = False else: output.print_error(f"Secondary nameserver {ns} is not configured correctly. (It resolved this domain as {ip}. It should be {correct_ip}.)") + if checkSOA: + # Check that secondary DNS server is synchronized with our primary DNS server. Simplified by checking the SOA record which has a version number + SOASecondary = query_dns(domain, "SOA", at=ns_ip) + + if SOARecord == SOASecondary: + output.print_ok(f"Secondary nameserver {ns} has consistent SOA record.") + elif SOARecord == '[Not Set]': + output.print_error(f"Secondary nameserver {ns} has no SOA record configured.") + elif SOARecord == '[timeout]': + output.print_error(f"Secondary nameserver {ns} timed out on checking SOA record.") + else: + output.print_error(f"""Secondary nameserver {ns} has inconsistent SOA record (primary: {SOARecord} versus secondary: {SOASecondary}). + Check that synchronization between secondary and primary DNS servers is properly set-up.""") + def check_dns_zone_suggestions(domain, env, output, dns_zonefiles, domains_with_a_records): # Warn if a custom DNS record is preventing this or the automatic www redirect from # being served. From 564ed59bb47da24c9ebc50ae9137e6dcbcae9826 Mon Sep 17 00:00:00 2001 From: KiekerJan Date: Sun, 22 Dec 2024 13:48:36 +0100 Subject: [PATCH 15/24] Add check on ipv6 for spamhaus (#2428) --- management/status_checks.py | 41 +++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/management/status_checks.py b/management/status_checks.py index 96d10c95..67aaaeb4 100755 --- a/management/status_checks.py +++ b/management/status_checks.py @@ -282,26 +282,45 @@ def run_network_checks(env, output): # The user might have ended up on an IP address that was previously in use # by a spammer, or the user may be deploying on a residential network. We # will not be able to reliably send mail in these cases. - + rev_ip4 = ".".join(reversed(env['PUBLIC_IP'].split('.'))) + zen = query_dns(rev_ip4+'.zen.spamhaus.org', 'A', nxdomain=None, retry = False) + evaluate_spamhaus_lookup(env['PUBLIC_IP'], 'IPv4', rev_ip4, output, zen) + + if not env['PUBLIC_IPV6']: + return + + from ipaddress import IPv6Address + + rev_ip6 = ".".join(reversed(IPv6Address(env['PUBLIC_IPV6']).exploded.split(':'))) + zen = query_dns(rev_ip6+'.zen.spamhaus.org', 'A', nxdomain=None, retry = False) + evaluate_spamhaus_lookup(env['PUBLIC_IPV6'], 'IPv6', rev_ip6, output, zen) + + +def evaluate_spamhaus_lookup(lookupaddress, lookuptype, lookupdomain, output, zen): # See https://www.spamhaus.org/news/article/807/using-our-public-mirrors-check-your-return-codes-now. for # information on spamhaus return codes - rev_ip4 = ".".join(reversed(env['PUBLIC_IP'].split('.'))) - zen = query_dns(rev_ip4+'.zen.spamhaus.org', 'A', nxdomain=None) if zen is None: - output.print_ok("IP address is not blacklisted by zen.spamhaus.org.") + output.print_ok(f"{lookuptype} address is not blacklisted by zen.spamhaus.org.") elif zen == "[timeout]": - output.print_warning("Connection to zen.spamhaus.org timed out. Could not determine whether this box's IP address is blacklisted. Please try again later.") + output.print_warning(f"""Connection to zen.spamhaus.org timed out. Could not determine whether this box's + {lookuptype} address is blacklisted. Please try again later.""") elif zen == "[Not Set]": - output.print_warning("Could not connect to zen.spamhaus.org. Could not determine whether this box's IP address is blacklisted. Please try again later.") + output.print_warning(f"""Could not connect to zen.spamhaus.org. Could not determine whether this box's + {lookuptype} address is blacklisted. Please try again later.""") elif zen == "127.255.255.252": - output.print_warning("Incorrect spamhaus query: %s. Could not determine whether this box's IP address is blacklisted." % (rev_ip4+'.zen.spamhaus.org')) + output.print_warning(f"""Incorrect spamhaus query: {lookupdomain + '.zen.spamhaus.org'}. Could not determine whether + this box's {lookuptype} address is blacklisted.""") elif zen == "127.255.255.254": - output.print_warning("Mail-in-a-Box is configured to use a public DNS server. This is not supported by spamhaus. Could not determine whether this box's IP address is blacklisted.") + output.print_warning(f"""Mail-in-a-Box is configured to use a public DNS server. This is not supported by + spamhaus. Could not determine whether this box's {lookuptype} address is blacklisted.""") elif zen == "127.255.255.255": - output.print_warning("Too many queries have been performed on the spamhaus server. Could not determine whether this box's IP address is blacklisted.") + output.print_warning(f"""Too many queries have been performed on the spamhaus server. Could not determine + whether this box's {lookuptype} address is blacklisted.""") else: - output.print_error("""The IP address of this machine {} is listed in the Spamhaus Block List (code {}), - which may prevent recipients from receiving your email. See http://www.spamhaus.org/query/ip/{}.""".format(env['PUBLIC_IP'], zen, env['PUBLIC_IP'])) + output.print_error(f"""The {lookuptype} address of this machine {lookupaddress} is listed in the Spamhaus Block + List (code {zen}), which may prevent recipients from receiving your email. See + http://www.spamhaus.org/query/ip/{lookupaddress}.""") + def run_domain_checks(rounded_time, env, output, pool, domains_to_check=None): # Get the list of domains we handle mail for. From 4f094f7859cab6ee72792b96313c1c7d4407685d Mon Sep 17 00:00:00 2001 From: zoof Date: Sun, 22 Dec 2024 07:57:59 -0500 Subject: [PATCH 16/24] Change hour of daily tasks to run at 1am and only run full backups on weekends (#2424) * Change hour of daily tasks to run at 1am * Change to only do full backup on weekends --- management/backup.py | 17 +++++++++++------ setup/management.sh | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/management/backup.py b/management/backup.py index aae6c00b..238cb2ed 100755 --- a/management/backup.py +++ b/management/backup.py @@ -9,6 +9,7 @@ import os, os.path, re, datetime, sys import dateutil.parser, dateutil.relativedelta, dateutil.tz +from datetime import date import rtyaml from exclusiveprocess import Lock @@ -157,6 +158,8 @@ def should_force_full(config, env): # since the last full backup is greater than half the size # of that full backup. inc_size = 0 + # Check if day of week is a weekend day + weekend = date.today().weekday()>=5 for bak in backup_status(env)["backups"]: if not bak["full"]: # Scan through the incremental backups cumulating @@ -165,12 +168,14 @@ def should_force_full(config, env): else: # ...until we reach the most recent full backup. # Return if we should to a full backup, which is based - # on the size of the increments relative to the full - # backup, as well as the age of the full backup. - if inc_size > .5*bak["size"]: - return True - if dateutil.parser.parse(bak["date"]) + datetime.timedelta(days=config["min_age_in_days"]*10+1) < datetime.datetime.now(dateutil.tz.tzlocal()): - return True + # on whether it is a weekend day, the size of the + # increments relative to the full backup, as well as + # the age of the full backup. + if weekend: + if inc_size > .5*bak["size"]: + return True + if dateutil.parser.parse(bak["date"]) + datetime.timedelta(days=config["min_age_in_days"]*10+1) < datetime.datetime.now(dateutil.tz.tzlocal()): + return True return False else: # If we got here there are no (full) backups, so make one. diff --git a/setup/management.sh b/setup/management.sh index fb359cd3..d8032312 100755 --- a/setup/management.sh +++ b/setup/management.sh @@ -116,7 +116,7 @@ minute=$((RANDOM % 60)) # avoid overloading mailinabox.email cat > /etc/cron.d/mailinabox-nightly << EOF; # Mail-in-a-Box --- Do not edit / will be overwritten on update. # Run nightly tasks: backup, status checks. -$minute 3 * * * root (cd $PWD && management/daily_tasks.sh) +$minute 1 * * * root (cd $PWD && management/daily_tasks.sh) EOF # Start the management server. From 0d7388899c02a3785714bfe75d711f5929b3ded2 Mon Sep 17 00:00:00 2001 From: Tomasz Stanczak Date: Sun, 22 Dec 2024 13:59:58 +0100 Subject: [PATCH 17/24] Allow DSA end EllipticCurve private keys to be used additionally to RSA for HTTPS certificates (#2416) Co-authored-by: Tomasz Stanczak --- management/ssl_certificates.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/management/ssl_certificates.py b/management/ssl_certificates.py index c9f1126c..8c1b841e 100755 --- a/management/ssl_certificates.py +++ b/management/ssl_certificates.py @@ -14,7 +14,7 @@ def get_ssl_certificates(env): # that the certificates are good for to the best certificate for # the domain. - from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey + from cryptography.hazmat.primitives.asymmetric import dsa, rsa, ec from cryptography.x509 import Certificate # The certificates are all stored here: @@ -59,13 +59,15 @@ def get_ssl_certificates(env): # Not a valid PEM format for a PEM type we care about. continue - # Is it a private key? - if isinstance(pem, RSAPrivateKey): - private_keys[pem.public_key().public_numbers()] = { "filename": fn, "key": pem } - # Is it a certificate? if isinstance(pem, Certificate): certificates.append({ "filename": fn, "cert": pem }) + # It is a private key + elif (isinstance(pem, rsa.RSAPrivateKey) + or isinstance(pem, dsa.DSAPrivateKey) + or isinstance(pem, ec.EllipticCurvePrivateKey)): + private_keys[pem.public_key().public_numbers()] = { "filename": fn, "key": pem } + # Process the certificates. domains = { } @@ -505,7 +507,7 @@ def check_certificate(domain, ssl_certificate, ssl_private_key, warn_if_expiring # Check that the ssl_certificate & ssl_private_key files are good # for the provided domain. - from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey + from cryptography.hazmat.primitives.asymmetric import rsa, dsa, ec from cryptography.x509 import Certificate # The ssl_certificate file may contain a chain of certificates. We'll @@ -539,7 +541,9 @@ def check_certificate(domain, ssl_certificate, ssl_private_key, warn_if_expiring except ValueError as e: return (f"The private key file {ssl_private_key} is not a private key file: {e!s}", None) - if not isinstance(priv_key, RSAPrivateKey): + if (not isinstance(priv_key, rsa.RSAPrivateKey) + and not isinstance(priv_key, dsa.DSAPrivateKey) + and not isinstance(priv_key, ec.EllipticCurvePrivateKey)): return ("The private key file %s is not a private key file." % ssl_private_key, None) if priv_key.public_key().public_numbers() != cert.public_key().public_numbers(): @@ -639,7 +643,7 @@ def load_pem(pem): msg = "File is not a valid PEM-formatted file." raise ValueError(msg) pem_type = pem_type.group(1) - if pem_type in {b"RSA PRIVATE KEY", b"PRIVATE KEY"}: + if pem_type.endswith(b"PRIVATE KEY"): return serialization.load_pem_private_key(pem, password=None, backend=default_backend()) if pem_type == b"CERTIFICATE": return load_pem_x509_certificate(pem, default_backend()) From 2e0482e1817fd1a167b247a9137b86ee190d2947 Mon Sep 17 00:00:00 2001 From: KiekerJan Date: Sun, 22 Dec 2024 14:01:02 +0100 Subject: [PATCH 18/24] Exclude the owncloud-backup folder from the nightly backup (#2413) --- management/backup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/management/backup.py b/management/backup.py index 238cb2ed..ac16eade 100755 --- a/management/backup.py +++ b/management/backup.py @@ -325,6 +325,7 @@ def perform_backup(full_backup): "--verbosity", "warning", "--no-print-statistics", "--archive-dir", backup_cache_dir, "--exclude", backup_root, + "--exclude", os.path.join(env["STORAGE_ROOT"], "owncloud-backup"), "--volsize", "250", "--gpg-options", "'--cipher-algo=AES256'", "--allow-source-mismatch", @@ -404,6 +405,7 @@ def run_duplicity_verification(): "--compare-data", "--archive-dir", backup_cache_dir, "--exclude", backup_root, + "--exclude", os.path.join(env["STORAGE_ROOT"], "owncloud-backup"), *get_duplicity_additional_args(env), get_duplicity_target_url(config), env["STORAGE_ROOT"], From e0b93718a33338115e953564170d87af6a55e1f9 Mon Sep 17 00:00:00 2001 From: yeah Date: Sun, 22 Dec 2024 14:02:49 +0100 Subject: [PATCH 19/24] =?UTF-8?q?Revert=20"increase=20timeout=20for=20the?= =?UTF-8?q?=20nginx=20proxy=20that=20provides=20access=20to=20the=20Mail?= =?UTF-8?q?=E2=80=A6"=20(#2411)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverts #2407 - as per #2316 This reverts commit 2803d8889454fa3a8295c0cfd382cdbe996284d9. --- conf/nginx-primaryonly.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/conf/nginx-primaryonly.conf b/conf/nginx-primaryonly.conf index b361a7b2..36f62aab 100644 --- a/conf/nginx-primaryonly.conf +++ b/conf/nginx-primaryonly.conf @@ -8,7 +8,6 @@ rewrite ^/admin/munin$ /admin/munin/ redirect; location /admin/ { proxy_pass http://127.0.0.1:10222/; - proxy_read_timeout 600s; proxy_set_header X-Forwarded-For $remote_addr; add_header X-Frame-Options "DENY"; add_header X-Content-Type-Options nosniff; From 18721e42d19e87df5b7ba0182525739928dd39fa Mon Sep 17 00:00:00 2001 From: yeah Date: Sun, 22 Dec 2024 14:07:04 +0100 Subject: [PATCH 20/24] Cronjob for cleaning up expired SSL certificates in order to improve page load times with many domains (#2410) Fixes #2316. --- setup/ssl.sh | 9 +++++++++ tools/ssl_cleanup | 17 +++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100755 tools/ssl_cleanup diff --git a/setup/ssl.sh b/setup/ssl.sh index 19a0c048..0aa9b136 100755 --- a/setup/ssl.sh +++ b/setup/ssl.sh @@ -96,3 +96,12 @@ fi if [ ! -f "$STORAGE_ROOT/ssl/dh2048.pem" ]; then openssl dhparam -out "$STORAGE_ROOT/ssl/dh2048.pem" 2048 fi + +# Cleanup expired SSL certificates from $STORAGE_ROOT/ssl daily +cat > /etc/cron.daily/mailinabox-ssl-cleanup << EOF; +#!/bin/bash +# Mail-in-a-Box +# Cleanup expired SSL certificates +$(pwd)/tools/ssl_cleanup +EOF +chmod +x /etc/cron.daily/mailinabox-ssl-cleanup diff --git a/tools/ssl_cleanup b/tools/ssl_cleanup new file mode 100755 index 00000000..5adfa1be --- /dev/null +++ b/tools/ssl_cleanup @@ -0,0 +1,17 @@ +#!/bin/bash +# Cleanup SSL certificates which expired more than 7 days ago from $STORAGE_ROOT/ssl and move them to $STORAGE_ROOT/ssl.expired + +source /etc/mailinabox.conf +shopt -s extglob + +retain_after="$(date --date="7 days ago" +%Y%m%d)" + +mkdir -p $STORAGE_ROOT/ssl.expired +for file in $STORAGE_ROOT/ssl/*-+([0-9])-+([0-9a-f]).pem; do + pem="$(basename "$file")" + not_valid_after="$(cut -d- -f1 <<< "${pem: -21}")" + + if [ "$not_valid_after" -lt "$retain_after" ]; then + mv "$file" "$STORAGE_ROOT/ssl.expired/${pem}" + fi +done From f73da3db60fc221fd2ecae17eac16db426800b2b Mon Sep 17 00:00:00 2001 From: Joshua Tauberer Date: Mon, 23 Dec 2024 11:26:09 -0500 Subject: [PATCH 21/24] Fix likely merge mistake in 564ed59bb47da24c9ebc50ae9137e6dcbcae9826 Fixes #2466 --- management/status_checks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/management/status_checks.py b/management/status_checks.py index 67aaaeb4..68755cb7 100755 --- a/management/status_checks.py +++ b/management/status_checks.py @@ -283,7 +283,7 @@ def run_network_checks(env, output): # by a spammer, or the user may be deploying on a residential network. We # will not be able to reliably send mail in these cases. rev_ip4 = ".".join(reversed(env['PUBLIC_IP'].split('.'))) - zen = query_dns(rev_ip4+'.zen.spamhaus.org', 'A', nxdomain=None, retry = False) + zen = query_dns(rev_ip4+'.zen.spamhaus.org', 'A', nxdomain=None) evaluate_spamhaus_lookup(env['PUBLIC_IP'], 'IPv4', rev_ip4, output, zen) if not env['PUBLIC_IPV6']: @@ -292,7 +292,7 @@ def run_network_checks(env, output): from ipaddress import IPv6Address rev_ip6 = ".".join(reversed(IPv6Address(env['PUBLIC_IPV6']).exploded.split(':'))) - zen = query_dns(rev_ip6+'.zen.spamhaus.org', 'A', nxdomain=None, retry = False) + zen = query_dns(rev_ip6+'.zen.spamhaus.org', 'A', nxdomain=None) evaluate_spamhaus_lookup(env['PUBLIC_IPV6'], 'IPv6', rev_ip6, output, zen) From d58dd0c91dd677acd6940d9b6099e2abb0ede729 Mon Sep 17 00:00:00 2001 From: Joshua Tauberer Date: Sat, 4 Jan 2025 14:38:45 -0500 Subject: [PATCH 22/24] v71 --- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ setup/bootstrap.sh | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55cd75b8..21d76e05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,35 @@ CHANGELOG ========= +Version 71 (January 4, 2025) +---------------------------- + +Upgrades + +* Roundcube upgraded to version 1.6.9. +* Z-Push upgraded to version 2.7.5. + +Automated Maintenance + +* Daily automated tasks are now run at 1am in the box's timezone and full backups are now restricted to running only on Saturdays and Sundays at that time. +* Backups now exclude the owncloud-backup folder so that we're not backing up backups. +* Old TLS certificates are now automatically deleted to improve control panel performance. + +Setup + +* Fixed broken setup if SSH was configured to listen on multiple ports. +* Ubuntu MOTD advertisements are now disabled. +* Fixed missing Roundcube dependency package if NextCloud isn't installed. + +Control Panel + +* Improved status checks for secondary nameservers. +* Spamhaus is now queried for the box's IPv6 address also. +* DSA and EC private keys are now accepted for TLS certificates. +* Timeouts for loading slow control panel pages are reduced. + +And other minor fixes. + Version 70 (August 15, 2024) ---------------------------- diff --git a/setup/bootstrap.sh b/setup/bootstrap.sh index 00d1b214..00b64c13 100644 --- a/setup/bootstrap.sh +++ b/setup/bootstrap.sh @@ -23,7 +23,7 @@ if [ -z "$TAG" ]; then if [ "$UBUNTU_VERSION" == "Ubuntu 22.04 LTS" ]; then # This machine is running Ubuntu 22.04, which is supported by # Mail-in-a-Box versions 60 and later. - TAG=v70 + TAG=v71 elif [ "$UBUNTU_VERSION" == "Ubuntu 18.04 LTS" ]; then # This machine is running Ubuntu 18.04, which is supported by # Mail-in-a-Box versions 0.40 through 5x. From 432b470d2931a15a3761a3e35f1c30cac4e83b49 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 6 Jan 2025 04:06:01 -0800 Subject: [PATCH 23/24] New & improved Disable MOTD advertisements (#2470) Checks if /etc/default/motd-news exists before running commands. --- setup/system.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup/system.sh b/setup/system.sh index dd366401..fce3091f 100755 --- a/setup/system.sh +++ b/setup/system.sh @@ -87,8 +87,10 @@ tools/editconf.py /etc/systemd/journald.conf MaxRetentionSec=10day # Disable MOTD adverts to prevent revealing server information in MOTD request headers # See https://ma.ttias.be/what-exactly-being-sent-ubuntu-motd/ +if [ -f /etc/default/motd-news ]; then tools/editconf.py /etc/default/motd-news ENABLED=0 rm -f /var/cache/motd-news +fi # ### Add PPAs. From e6c354c3125bdfdf32fecabb851288a385705e72 Mon Sep 17 00:00:00 2001 From: Joshua Tauberer Date: Mon, 6 Jan 2025 07:07:53 -0500 Subject: [PATCH 24/24] v71a --- CHANGELOG.md | 2 ++ setup/bootstrap.sh | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21d76e05..45943e95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG Version 71 (January 4, 2025) ---------------------------- +(Version 71a was posted on January 6, 2025 and fixes a setup regression.) + Upgrades * Roundcube upgraded to version 1.6.9. diff --git a/setup/bootstrap.sh b/setup/bootstrap.sh index 00b64c13..fc191c21 100644 --- a/setup/bootstrap.sh +++ b/setup/bootstrap.sh @@ -23,7 +23,7 @@ if [ -z "$TAG" ]; then if [ "$UBUNTU_VERSION" == "Ubuntu 22.04 LTS" ]; then # This machine is running Ubuntu 22.04, which is supported by # Mail-in-a-Box versions 60 and later. - TAG=v71 + TAG=v71a elif [ "$UBUNTU_VERSION" == "Ubuntu 18.04 LTS" ]; then # This machine is running Ubuntu 18.04, which is supported by # Mail-in-a-Box versions 0.40 through 5x.