From 0657f9e875895adbc46cb36b72c6aa3f55a88e45 Mon Sep 17 00:00:00 2001 From: captainwasabi Date: Tue, 13 Aug 2019 05:47:11 -0400 Subject: [PATCH 01/12] add proper check for DNS error in list_target_files (#1625) The elif needed to check to see if the string was in the listing of results of the shell command. As it was the conditional was just the string which always evaluates to true and was therefore giving a misleading error message. --- management/backup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/management/backup.py b/management/backup.py index 93136bf5..cd1ee6fc 100755 --- a/management/backup.py +++ b/management/backup.py @@ -406,7 +406,7 @@ def list_target_files(config): reason = "Provided path {} is invalid.".format(target_path) elif 'Network is unreachable' in listing: reason = "The IP address {} is unreachable.".format(target.hostname) - elif 'Could not resolve hostname': + elif 'Could not resolve hostname' in listing: reason = "The hostname {} cannot be resolved.".format(target.hostname) else: reason = "Unknown error." \ From c4cb828f6562ad03497e64acd2ebb0af7294d36c Mon Sep 17 00:00:00 2001 From: captainwasabi Date: Tue, 13 Aug 2019 05:57:05 -0400 Subject: [PATCH 02/12] Fix rsync backup options string: extraneous single quotes causing problems (#1629) The resulting command had nested single quotes which doesn't work I think this fixes all/most of the issues in #1627. I am getting a full backup, then the next time it's run I get an incremental. running from the CLI with --status looks good, --verify looks good, and --list looks good. --- management/backup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/management/backup.py b/management/backup.py index cd1ee6fc..11cdbb8a 100755 --- a/management/backup.py +++ b/management/backup.py @@ -15,8 +15,8 @@ from exclusiveprocess import Lock from utils import load_environment, shell, wait_for_service, fix_boto rsync_ssh_options = [ - "--ssh-options='-i /root/.ssh/id_rsa_miab'", - "--rsync-options=-e \"/usr/bin/ssh -oStrictHostKeyChecking=no -oBatchMode=yes -p 22 -i /root/.ssh/id_rsa_miab\"", + "--ssh-options= -i /root/.ssh/id_rsa_miab", + "--rsync-options= -e \"/usr/bin/ssh -oStrictHostKeyChecking=no -oBatchMode=yes -p 22 -i /root/.ssh/id_rsa_miab\"", ] def backup_status(env): From 295d481603025a603e3f39cb8da8629ba569f98f Mon Sep 17 00:00:00 2001 From: cmharper <1422608+cmharper@users.noreply.github.com> Date: Sat, 31 Aug 2019 11:55:38 +0000 Subject: [PATCH 03/12] Upgraded roundcube to 1.3.10 (#1634) --- setup/webmail.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/webmail.sh b/setup/webmail.sh index cbe6bfca..6cbe55f9 100755 --- a/setup/webmail.sh +++ b/setup/webmail.sh @@ -28,8 +28,8 @@ apt_install \ # Install Roundcube from source if it is not already present or if it is out of date. # Combine the Roundcube version number with the commit hash of plugins to track # whether we have the latest version of everything. -VERSION=1.3.9 -HASH=02850972b416bbfa1c13580f16d06fd7ae2774aa +VERSION=1.3.10 +HASH=431625fc737e301f9b7e502cccc61e50a24786b8 PERSISTENT_LOGIN_VERSION=dc5ca3d3f4415cc41edb2fde533c8a8628a94c76 HTML5_NOTIFIER_VERSION=4b370e3cd60dabd2f428a26f45b677ad1b7118d5 CARDDAV_VERSION=3.0.3 From 08021ea19f1a5395d09e2bc557cbf8b5cdef18d4 Mon Sep 17 00:00:00 2001 From: Snacho Date: Sat, 31 Aug 2019 14:58:12 +0300 Subject: [PATCH 04/12] Fix an issue when Secondary NS has multiple A records (#1633) If a custom secondary NS server has multiple A records status_checks.py will fail with a timeout and Web UI won't load. --- management/status_checks.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/management/status_checks.py b/management/status_checks.py index 6f9bb1ef..a9d0595c 100755 --- a/management/status_checks.py +++ b/management/status_checks.py @@ -486,10 +486,12 @@ def check_dns_zone(domain, env, output, dns_zonefiles): if custom_secondary_ns and not probably_external_dns: for ns in custom_secondary_ns: # We must first resolve the nameserver to an IP address so we can query it. - ns_ip = query_dns(ns, "A") - if not ns_ip: + ns_ips = query_dns(ns, "A") + if not ns_ips: output.print_error("Secondary nameserver %s is not valid (it doesn't resolve to an IP address)." % ns) continue + # Choose the first IP if nameserver returns multiple + ns_ip = ns_ips.split('; ')[0] # Now query it to see what it says about this domain. ip = query_dns(domain, "A", at=ns_ip, nxdomain=None) From c7377e602d06a792b97a5a1047bbdeb32bdd377a Mon Sep 17 00:00:00 2001 From: Kim Schulz Date: Sat, 31 Aug 2019 14:00:18 +0200 Subject: [PATCH 05/12] make it possible to use subnet addresses for axfr (#1616) it is sometimes needed to be able to set axfr to more than just one ip address. This can be done with multiple xfr: in the secondary dns input but if you need to add an entire subnet segment (xxx.xxx.xxx.0/yy) then it will not work. With this patch it is now possible to use a subnet as input for xfr the same way as if it was an ip address. --- management/dns_update.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/management/dns_update.py b/management/dns_update.py index 7e006d0b..7eed50b5 100755 --- a/management/dns_update.py +++ b/management/dns_update.py @@ -903,8 +903,12 @@ def set_secondary_dns(hostnames, env): else: # Validate IP address. try: - v = ipaddress.ip_address(item[4:]) # raises a ValueError if there's a problem - if not isinstance(v, ipaddress.IPv4Address): raise ValueError("That's an IPv6 address.") + if "/" in item[4:]: + v = ipaddress.ip_network(item[4:] # raises a ValueError if there's a problem + if not isinstance(v, ipaddress.IPv4Network): raise ValueError("That's an IPv6 subnet.") + else: + v = ipaddress.ip_address(item[4:]) # raises a ValueError if there's a problem + if not isinstance(v, ipaddress.IPv4Address): raise ValueError("That's an IPv6 address.") except ValueError: raise ValueError("'%s' is not an IPv4 address." % item[4:]) From 1d6793d12434a407d47efa7dc276f63227ad29e5 Mon Sep 17 00:00:00 2001 From: Michael Kroes Date: Sat, 31 Aug 2019 14:38:41 +0200 Subject: [PATCH 06/12] Update the Postgrey whitelist to a newer version monthly (#1611) Automatically update the Postgrey whitelist to a newer version once a month. --- CHANGELOG.md | 5 +++++ setup/mail-postfix.sh | 29 ++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a07304b6..7c1849fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +In Development +-------------- + +* Fetch an updated whitelist for Postgrey on a monthly basis. + v0.42b (August 3, 2019) ----------------------- diff --git a/setup/mail-postfix.sh b/setup/mail-postfix.sh index 4d66cd58..283d08af 100755 --- a/setup/mail-postfix.sh +++ b/setup/mail-postfix.sh @@ -208,7 +208,34 @@ tools/editconf.py /etc/postfix/main.cf \ # e-mails really latter, delay of greylisting has been set to # 180 seconds (default is 300 seconds). tools/editconf.py /etc/default/postgrey \ - POSTGREY_OPTS=\"'--inet=127.0.0.1:10023 --delay=180'\" + POSTGREY_OPTS=\"'--inet=127.0.0.1:10023 --delay=180 --whitelist-recipients=/etc/postgrey/whitelist_clients'\" + + +# We are going to setup a newer whitelist for postgrey, the version included in the distribution is old +cat > /etc/cron.daily/mailinabox-postgrey-whitelist << EOF; +#!/bin/bash + +# Mail-in-a-Box + +# check we have a postgrey_whitelist_clients file and that it is not older than 28 days +if [ ! -f /etc/postgrey/whitelist_clients ] || find /etc/postgrey/whitelist_clients -mtime +28 > /dev/null ; then + # ok we need to update the file, so lets try to fetch it + if curl https://postgrey.schweikert.ch/pub/postgrey_whitelist_clients --output /tmp/postgrey_whitelist_clients -sS --fail > /dev/null 2>&1 ; then + # if fetching hasn't failed yet then check it is a plain text file + # curl manual states that --fail sometimes still produces output + # this final check will at least check the output is not html + # before moving it into place + if [ "\$(file -b --mime-type /tmp/postgrey_whitelist_clients)" == "text/plain" ]; then + mv /tmp/postgrey_whitelist_clients /etc/postgrey/whitelist_clients + service postgrey restart + else + rm /tmp/postgrey_whitelist_clients + fi + fi +fi +EOF +chmod +x /etc/cron.daily/mailinabox-postgrey-whitelist +/etc/cron.daily/mailinabox-postgrey-whitelist # Increase the message size limit from 10MB to 128MB. # The same limit is specified in nginx.conf for mail submitted via webmail and Z-Push. From d6becddbe5f120818fca111187a7313d4944fb71 Mon Sep 17 00:00:00 2001 From: jvolkenant Date: Sat, 31 Aug 2019 05:50:36 -0700 Subject: [PATCH 07/12] Change Nextcloud upgrade logic to look at STORAGE_ROOT's config.php version vs /usr/local's version.php version (#1632) * Download and verify Nextcloud download before deleting old install directory * Changed install logic to look at config.php and not version.php for database version number. When restoring from a backup, config.php in STORAGE_ROOT will hold the Nextcloud version that corresponds to the user's database and version.php in /usr/local won't even exist, so we were missing Nextcloud migration steps. In other cases they should be the same. --- setup/nextcloud.sh | 47 ++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/setup/nextcloud.sh b/setup/nextcloud.sh index 9f36ee56..d5a8e7c5 100755 --- a/setup/nextcloud.sh +++ b/setup/nextcloud.sh @@ -25,12 +25,12 @@ InstallNextcloud() { echo "Upgrading to Nextcloud version $version" echo + # Download and verify + wget_verify https://download.nextcloud.com/server/releases/nextcloud-$version.zip $hash /tmp/nextcloud.zip + # Remove the current owncloud/Nextcloud rm -rf /usr/local/lib/owncloud - # Download and verify - wget_verify https://download.nextcloud.com/server/releases/nextcloud-$version.zip $hash /tmp/nextcloud.zip - # Extract ownCloud/Nextcloud unzip -q /tmp/nextcloud.zip -d /usr/local/lib mv /usr/local/lib/nextcloud /usr/local/lib/owncloud @@ -90,11 +90,26 @@ InstallNextcloud() { fi } +# Nextcloud Version to install. Checks are done down below to step through intermediate versions. nextcloud_ver=15.0.8 nextcloud_hash=4129d8d4021c435f2e86876225fb7f15adf764a3 -# Check if Nextcloud dir exist, and check if version matches nextcloud_ver (if either doesn't - install/upgrade) -if [ ! -d /usr/local/lib/owncloud/ ] \ - || ! grep -q $nextcloud_ver /usr/local/lib/owncloud/version.php; then + +# Current Nextcloud Version, #1623 +# Checking /usr/local/lib/owncloud/version.php shows version of the Nextcloud application, not the DB +# $STORAGE_ROOT/owncloud is kept together even during a backup. It is better to rely on config.php than +# version.php since the restore procedure can leave the system in a state where you have a newer Nextcloud +# application version than the database. + +# If config.php exists, get version number, otherwise CURRENT_NEXTCLOUD_VER is empty. +if [ -f "$STORAGE_ROOT/owncloud/config.php" ]; then + CURRENT_NEXTCLOUD_VER=$(php -r "include(\"$STORAGE_ROOT/owncloud/config.php\"); echo(\$CONFIG['version']);") +else + CURRENT_NEXTCLOUD_VER="" +fi + +# If the Nextcloud directory is missing (never been installed before, or the nextcloud version to be installed is different +# from the version currently installed, do the install/upgrade +if [ ! -d /usr/local/lib/owncloud/ ] || [[ ! ${CURRENT_NEXTCLOUD_VER} =~ ^$nextcloud_ver ]]; then # Stop php-fpm if running. If theyre not running (which happens on a previously failed install), dont bail. service php7.2-fpm stop &> /dev/null || /bin/true @@ -115,25 +130,21 @@ if [ ! -d /usr/local/lib/owncloud/ ] \ fi # If ownCloud or Nextcloud was previously installed.... - if [ -e /usr/local/lib/owncloud/version.php ]; then + if [ ! -z ${CURRENT_NEXTCLOUD_VER} ]; then # Database migrations from ownCloud are no longer possible because ownCloud cannot be run under # PHP 7. - if grep -q "OC_VersionString = '[89]\." /usr/local/lib/owncloud/version.php; then + if [[ ${CURRENT_NEXTCLOUD_VER} =~ ^[89] ]]; then echo "Upgrades from Mail-in-a-Box prior to v0.28 (dated July 30, 2018) with Nextcloud < 13.0.6 (you have ownCloud 8 or 9) are not supported. Upgrade to Mail-in-a-Box version v0.30 first. Setup aborting." exit 1 - fi - if grep -q "OC_VersionString = '1[012]\." /usr/local/lib/owncloud/version.php; then + elif [[ ${CURRENT_NEXTCLOUD_VER} =~ ^1[012] ]]; then echo "Upgrades from Mail-in-a-Box prior to v0.28 (dated July 30, 2018) with Nextcloud < 13.0.6 (you have ownCloud 10, 11 or 12) are not supported. Upgrade to Mail-in-a-Box version v0.30 first. Setup aborting." exit 1 - fi - # If we are running Nextcloud 13, upgrade to Nextcloud 14 - if grep -q "OC_VersionString = '13\." /usr/local/lib/owncloud/version.php; then + elif [[ ${CURRENT_NEXTCLOUD_VER} =~ ^13 ]]; then + # If we are running Nextcloud 13, upgrade to Nextcloud 14 InstallNextcloud 14.0.6 4e43a57340f04c2da306c8eea98e30040399ae5a - - fi - # During the upgrade from Nextcloud 14 to 15, user_external may cause the upgrade to fail. - # We will disable it here before the upgrade and install it again after the upgrade. - if grep -q "OC_VersionString = '14\." /usr/local/lib/owncloud/version.php; then + elif [[ ${CURRENT_NEXTCLOUD_VER} =~ ^14 ]]; then + # During the upgrade from Nextcloud 14 to 15, user_external may cause the upgrade to fail. + # We will disable it here before the upgrade and install it again after the upgrade. hide_output sudo -u www-data php /usr/local/lib/owncloud/console.php app:disable user_external fi fi From 3ff9817325d6d113c03f2d8f3b1eef9623b07e87 Mon Sep 17 00:00:00 2001 From: Joshua Tauberer Date: Sat, 31 Aug 2019 08:15:38 -0400 Subject: [PATCH 08/12] document the xfr: CIDR notation, fix spaces vs tabs and syntax error, broken by c7377e602d06a792b97a5a1047bbdeb32bdd377a, #1616 --- management/dns_update.py | 14 +++++++------- management/templates/custom-dns.html | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/management/dns_update.py b/management/dns_update.py index 7eed50b5..dba6dbc1 100755 --- a/management/dns_update.py +++ b/management/dns_update.py @@ -903,14 +903,14 @@ def set_secondary_dns(hostnames, env): else: # Validate IP address. try: - if "/" in item[4:]: - v = ipaddress.ip_network(item[4:] # raises a ValueError if there's a problem - if not isinstance(v, ipaddress.IPv4Network): raise ValueError("That's an IPv6 subnet.") - else: - v = ipaddress.ip_address(item[4:]) # raises a ValueError if there's a problem - if not isinstance(v, ipaddress.IPv4Address): raise ValueError("That's an IPv6 address.") + if "/" in item[4:]: + v = ipaddress.ip_network(item[4:]) # raises a ValueError if there's a problem + if not isinstance(v, ipaddress.IPv4Network): raise ValueError("That's an IPv6 subnet.") + else: + v = ipaddress.ip_address(item[4:]) # raises a ValueError if there's a problem + if not isinstance(v, ipaddress.IPv4Address): raise ValueError("That's an IPv6 address.") except ValueError: - raise ValueError("'%s' is not an IPv4 address." % item[4:]) + raise ValueError("'%s' is not an IPv4 address or subnet." % item[4:]) # Set. set_custom_dns_record("_secondary_nameserver", "A", " ".join(hostnames), "set", env) diff --git a/management/templates/custom-dns.html b/management/templates/custom-dns.html index c838d32a..56facdc9 100644 --- a/management/templates/custom-dns.html +++ b/management/templates/custom-dns.html @@ -90,7 +90,7 @@

Multiple secondary servers can be separated with commas or spaces (i.e., ns2.hostingcompany.com ns3.hostingcompany.com). - To enable zone transfers to additional servers without listing them as secondary nameservers, add xfr:IPADDRESS. + To enable zone transfers to additional servers without listing them as secondary nameservers, add an IP address or subnet using xfr:10.20.30.40 or xfr:10.20.30.40/24.