diff --git a/CHANGELOG.md b/CHANGELOG.md index 67fcdd94..d796970e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,29 @@ CHANGELOG ========= +Version 56 (January 19, 2022) +----------------------------- + +Software updates: + +* Roundcube updated to 1.5.2 (from 1.5.0), and the persistent_login and CardDAV (to 4.3.0 from 3.0.3) plugins are updated. +* Nextcloud updated to 20.0.14 (from 20.0.8), contacts to 4.0.7 (from 3.5.1), and calendar to 3.0.4 (from 2.2.0). + +Setup: + +* Fixed failed setup if a previous attempt failed while updating Nextcloud. + +Control panel: + +* Fixed a crash if a custom DNS entry is not under a zone managed by the box. +* Fix DNSSEC instructions typo. + +Other: + +* Set systemd journald log retention to 10 days (from no limit) to reduce disk usage. +* Fixed log processing for submission lines that have a sasl_sender or other extra information. +* Fix DNS secondary nameserver refesh failure retry period. + Version 55 (October 18, 2021) ----------------------------- diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 00e15ec7..953c9016 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,9 +20,9 @@ _If you're seeing an error message about your *IP address being listed in the Sp ### Modifying your `hosts` file -After a while, Mail-in-a-Box will be available at `192.168.50.4` (unless you changed that in your `Vagrantfile`). To be able to use the web-based bits, we recommend to add a hostname to your `hosts` file: +After a while, Mail-in-a-Box will be available at `192.168.56.4` (unless you changed that in your `Vagrantfile`). To be able to use the web-based bits, we recommend to add a hostname to your `hosts` file: - $ echo "192.168.50.4 mailinabox.lan" | sudo tee -a /etc/hosts + $ echo "192.168.56.4 mailinabox.lan" | sudo tee -a /etc/hosts You should now be able to navigate to https://mailinabox.lan/admin using your browser. There should be an initial admin user with the name `me@mailinabox.lan` and the password `12345678`. diff --git a/README.md b/README.md index 317fb60e..5d15ebe5 100644 --- a/README.md +++ b/README.md @@ -262,7 +262,7 @@ Clone this repository and checkout the tag corresponding to the most recent rele $ git clone https://github.com/mail-in-a-box/mailinabox $ cd mailinabox - $ git checkout v55 + $ git checkout v56 Begin the installation. diff --git a/Vagrantfile b/Vagrantfile index 467fb95e..04788292 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -9,7 +9,7 @@ Vagrant.configure("2") do |config| # the machine's box will let anyone log into it. So instead we'll put the # machine on a private network. config.vm.hostname = "mailinabox.lan" - config.vm.network "private_network", ip: "192.168.50.4" + config.vm.network "private_network", ip: "192.168.56.4" config.vm.provision :shell, :inline => <<-SH # Set environment variables so that the setup script does diff --git a/api/mailinabox.yml b/api/mailinabox.yml index bd4b203b..f3290fb9 100644 --- a/api/mailinabox.yml +++ b/api/mailinabox.yml @@ -71,7 +71,7 @@ paths: x-codeSamples: - lang: curl source: | - curl -X GET "https://{host}/admin/login" \ + curl -X POST "https://{host}/admin/login" \ -u ":" responses: 200: @@ -103,13 +103,15 @@ paths: x-codeSamples: - lang: curl source: | - curl -X GET "https://{host}/admin/logout" \ + curl -X POST "https://{host}/admin/logout" \ -u ":" responses: 200: description: Successful operation content: application/json: + schema: + $ref: '#/components/schemas/LogoutResponse' /system/status: post: tags: @@ -2723,3 +2725,8 @@ components: nullable: true MfaDisableSuccessResponse: type: string + LogoutResponse: + type: object + properties: + status: + type: string diff --git a/management/daemon.py b/management/daemon.py index 88c04ffe..9fee8068 100755 --- a/management/daemon.py +++ b/management/daemon.py @@ -354,7 +354,7 @@ def dns_get_records(qname=None, rtype=None): r["sort-order"]["created"] = i domain_sort_order = utils.sort_domains([r["qname"] for r in records], env) for i, r in enumerate(sorted(records, key = lambda r : ( - zones.index(r["zone"]), + zones.index(r["zone"]) if r.get("zone") else 0, # record is not within a zone managed by the box domain_sort_order.index(r["qname"]), r["rtype"]))): r["sort-order"]["qname"] = i diff --git a/management/dns_update.py b/management/dns_update.py index b79e266a..fde9b146 100755 --- a/management/dns_update.py +++ b/management/dns_update.py @@ -484,7 +484,7 @@ def write_nsd_zone(domain, zonefile, records, env, force): # @ the PRIMARY_HOSTNAME. Hopefully that's legit. # # For the refresh through TTL fields, a good reference is: - # http://www.peerwisdom.org/2013/05/15/dns-understanding-the-soa-record/ + # https://www.ripe.net/publications/docs/ripe-203 # # A hash of the available DNSSEC keys are added in a comment so that when # the keys change we force a re-generation of the zone which triggers @@ -497,7 +497,7 @@ $TTL 86400 ; default time to live @ IN SOA ns1.{primary_domain}. hostmaster.{primary_domain}. ( __SERIAL__ ; serial number 7200 ; Refresh (secondary nameserver update interval) - 86400 ; Retry (when refresh fails, how often to try again) + 3600 ; Retry (when refresh fails, how often to try again, should be lower than the refresh) 1209600 ; Expire (when refresh fails, how long secondary nameserver will keep records around anyway) 86400 ; Negative TTL (how long negative responses are cached) ) diff --git a/management/mail_log.py b/management/mail_log.py index 59c32c6e..bdf757cc 100755 --- a/management/mail_log.py +++ b/management/mail_log.py @@ -549,8 +549,9 @@ def scan_postfix_submission_line(date, log, collector): """ # Match both the 'plain' and 'login' sasl methods, since both authentication methods are - # allowed by Dovecot - m = re.match("([A-Z0-9]+): client=(\S+), sasl_method=(PLAIN|LOGIN), sasl_username=(\S+)", log) + # allowed by Dovecot. Exclude trailing comma after the username when additional fields + # follow after. + m = re.match("([A-Z0-9]+): client=(\S+), sasl_method=(PLAIN|LOGIN), sasl_username=(\S+)(?Backup Status -

The box makes an incremental backup each night. By default the backup is stored on the machine itself, but you can also store in on S3-compatible services like Amazon Web Services (AWS).

+

The box makes an incremental backup each night. By default the backup is stored on the machine itself, but you can also store it on S3-compatible services like Amazon Web Services (AWS).

Configuration

diff --git a/security.md b/security.md index 5de8c612..ac508c93 100644 --- a/security.md +++ b/security.md @@ -3,7 +3,12 @@ Mail-in-a-Box Security Guide Mail-in-a-Box turns a fresh Ubuntu 18.04 LTS 64-bit machine into a mail server appliance by installing and configuring various components. -This page documents the security features of Mail-in-a-Box. The term “box” is used below to mean a configured Mail-in-a-Box. +This page documents the security posture of Mail-in-a-Box. The term “box” is used below to mean a configured Mail-in-a-Box. + +Reporting Security Vulnerabilities +---------------------------------- + +Security vulnerabilities should be reported to the [project's maintainer](https://joshdata.me) via email. Threat Model ------------ @@ -49,9 +54,7 @@ Additionally: ### Password Storage -The passwords for mail users are stored on disk using the [SHA512-CRYPT](http://man7.org/linux/man-pages/man3/crypt.3.html) hashing scheme. ([source](management/mailconfig.py)) - -When using the web-based administrative control panel, after logging in an API key is placed in the browser's local storage (rather than, say, the user's actual password). The API key is an HMAC based on the user's email address and current password, and it is keyed by a secret known only to the control panel service. By resetting an administrator's password, any HMACs previously generated for that user will expire. +The passwords for mail users are stored on disk using the [SHA512-CRYPT](http://man7.org/linux/man-pages/man3/crypt.3.html) hashing scheme. ([source](management/mailconfig.py)) Password changes (as well as changes to control panel two-factor authentication settings) expire any control panel login sessions. ### Console access @@ -65,7 +68,7 @@ If DNSSEC is enabled at the box's domain name's registrar, the SSHFP record that `fail2ban` provides some protection from brute-force login attacks (repeated logins that guess account passwords) by blocking offending IP addresses at the network level. -The following services are protected: SSH, IMAP (dovecot), SMTP submission (postfix), webmail (roundcube), Nextcloud/CalDAV/CardDAV (over HTTP), and the Mail-in-a-Box control panel & munin (over HTTP). +The following services are protected: SSH, IMAP (dovecot), SMTP submission (postfix), webmail (roundcube), Nextcloud/CalDAV/CardDAV (over HTTP), and the Mail-in-a-Box control panel (over HTTP). Some other services running on the box may be missing fail2ban filters. diff --git a/setup/bootstrap.sh b/setup/bootstrap.sh index 92397fdb..d0da1b25 100644 --- a/setup/bootstrap.sh +++ b/setup/bootstrap.sh @@ -20,7 +20,7 @@ if [ -z "$TAG" ]; then # want to display in status checks. if [ "$(lsb_release -d | sed 's/.*:\s*//' | sed 's/18\.04\.[0-9]/18.04/' )" == "Ubuntu 18.04 LTS" ]; then # This machine is running Ubuntu 18.04. - TAG=v0.55-quota-0.22-beta + TAG=v56-quota elif [ "$(lsb_release -d | sed 's/.*:\s*//' | sed 's/14\.04\.[0-9]/14.04/' )" == "Ubuntu 14.04 LTS" ]; then # This machine is running Ubuntu 14.04. diff --git a/setup/management.sh b/setup/management.sh index 7e31fe00..8dc64f3b 100755 --- a/setup/management.sh +++ b/setup/management.sh @@ -25,7 +25,7 @@ done # # certbot installs EFF's certbot which we use to # provision free TLS certificates. -apt_install duplicity python-pip virtualenv certbot +apt_install duplicity python-pip virtualenv certbot rsync # b2sdk is used for backblaze backups. # boto is used for amazon aws backups. diff --git a/setup/nextcloud.sh b/setup/nextcloud.sh index af848344..d8ce7635 100755 --- a/setup/nextcloud.sh +++ b/setup/nextcloud.sh @@ -9,6 +9,39 @@ source /etc/mailinabox.conf # load global vars echo "Installing Nextcloud (contacts/calendar)..." +# Nextcloud core and app (plugin) versions to install. +# With each version we store a hash to ensure we install what we expect. + +# Nextcloud core +# -------------- +# * See https://nextcloud.com/changelog for the latest version. +# * Check https://docs.nextcloud.com/server/latest/admin_manual/installation/system_requirements.html +# for whether it supports the version of PHP available on this machine. +# * Since Nextcloud only supports upgrades from consecutive major versions, +# we automatically install intermediate versions as needed. +# * The hash is the SHA1 hash of the ZIP package, which you can find by just running this script and +# copying it from the error message when it doesn't match what is below. +nextcloud_ver=20.0.14 +nextcloud_hash=92cac708915f51ee2afc1787fd845476fd090c81 + +# Nextcloud apps +# -------------- +# * Find the most recent tag that is compatible with the Nextcloud version above by +# consulting the ... node at: +# https://github.com/nextcloud-releases/contacts/blob/maaster/appinfo/info.xml +# https://github.com/nextcloud-releases/calendar/blob/master/appinfo/info.xml +# https://github.com/nextcloud/user_external/blob/master/appinfo/info.xml +# * The hash is the SHA1 hash of the ZIP package, which you can find by just running this script and +# copying it from the error message when it doesn't match what is below. +contacts_ver=4.0.7 +contacts_hash=8ab31d205408e4f12067d8a4daa3595d46b513e3 +calendar_ver=3.0.4 +calendar_hash=6fb1e998d307c53245faf1c37a96eb982bbee8ba +user_external_ver=1.0.0 +user_external_hash=3bf2609061d7214e7f0f69dd8883e55c4ec8f50a + +# Clear prior packages and install dependencies from apt. + apt-get purge -qq -y owncloud* # we used to use the package manager apt_install php php-fpm \ @@ -46,11 +79,11 @@ InstallNextcloud() { # their github repositories. mkdir -p /usr/local/lib/owncloud/apps - wget_verify https://github.com/nextcloud/contacts/releases/download/v$version_contacts/contacts.tar.gz $hash_contacts /tmp/contacts.tgz + wget_verify https://github.com/nextcloud-releases/contacts/releases/download/v$version_contacts/contacts-v$version_contacts.tar.gz $hash_contacts /tmp/contacts.tgz tar xf /tmp/contacts.tgz -C /usr/local/lib/owncloud/apps/ rm /tmp/contacts.tgz - wget_verify https://github.com/nextcloud/calendar/releases/download/v$version_calendar/calendar.tar.gz $hash_calendar /tmp/calendar.tgz + wget_verify https://github.com/nextcloud-releases/calendar/releases/download/v$version_calendar/calendar-v$version_calendar.tar.gz $hash_calendar /tmp/calendar.tgz tar xf /tmp/calendar.tgz -C /usr/local/lib/owncloud/apps/ rm /tmp/calendar.tgz @@ -96,16 +129,6 @@ InstallNextcloud() { fi } -# Nextcloud Version to install. Checks are done down below to step through intermediate versions. -nextcloud_ver=20.0.8 -nextcloud_hash=372b0b4bb07c7984c04917aff86b280e68fbe761 -contacts_ver=3.5.1 -contacts_hash=d2ffbccd3ed89fa41da20a1dff149504c3b33b93 -calendar_ver=2.2.0 -calendar_hash=673ad72ca28adb8d0f209015ff2dca52ffad99af -user_external_ver=1.0.0 -user_external_hash=3bf2609061d7214e7f0f69dd8883e55c4ec8f50a - # 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 @@ -172,7 +195,8 @@ if [ ! -d /usr/local/lib/owncloud/ ] || [[ ! ${CURRENT_NEXTCLOUD_VER} =~ ^$nextc CURRENT_NEXTCLOUD_VER="17.0.6" fi if [[ ${CURRENT_NEXTCLOUD_VER} =~ ^17 ]]; then - echo "ALTER TABLE oc_flow_operations ADD COLUMN entity VARCHAR;" | sqlite3 $STORAGE_ROOT/owncloud/owncloud.db + # Don't exit the install if this column already exists (see #2076) + (echo "ALTER TABLE oc_flow_operations ADD COLUMN entity VARCHAR;" | sqlite3 $STORAGE_ROOT/owncloud/owncloud.db 2>/dev/null) || true InstallNextcloud 18.0.10 39c0021a8b8477c3f1733fddefacfa5ebf921c68 3.4.1 aee680a75e95f26d9285efd3c1e25cf7f3bfd27e 2.0.3 9d9717b29337613b72c74e9914c69b74b346c466 1.0.0 3bf2609061d7214e7f0f69dd8883e55c4ec8f50a CURRENT_NEXTCLOUD_VER="18.0.10" fi diff --git a/setup/system.sh b/setup/system.sh index ed399ba0..036fe3f9 100755 --- a/setup/system.sh +++ b/setup/system.sh @@ -75,6 +75,13 @@ then fi fi +# ### Set log retention policy. + +# Set the systemd journal log retention from infinite to 10 days, +# since over time the logs take up a large amount of space. +# (See https://discourse.mailinabox.email/t/journalctl-reclaim-space-on-small-mailinabox/6728/11.) +tools/editconf.py /etc/systemd/journald.conf MaxRetentionSec=10day + # ### Add PPAs. # We install some non-standard Ubuntu packages maintained by other diff --git a/setup/webmail.sh b/setup/webmail.sh index 955735cf..5053b490 100755 --- a/setup/webmail.sh +++ b/setup/webmail.sh @@ -28,13 +28,19 @@ 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.5.0 -HASH=2a9d11d9c10c8e8756120606c47eef702f00fe6d -PERSISTENT_LOGIN_VERSION=6b3fc450cae23ccb2f393d0ef67aa319e877e435 # version 5.2.0 +# For the latest versions, see: +# https://github.com/roundcube/roundcubemail/releases +# https://github.com/mfreiholz/persistent_login/commits/master +# https://github.com/stremlau/html5_notifier/commits/master +# 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.5.2 +HASH=208ce4ca0be423cc0f7070ff59bd03588b4439bf +PERSISTENT_LOGIN_VERSION=59ca1b0d3a02cff5fa621c1ad581d15f9d642fe8 HTML5_NOTIFIER_VERSION=68d9ca194212e15b3c7225eb6085dbcf02fd13d7 # version 0.6.4+ -CARDDAV_VERSION=3.0.3 -CARDDAV_HASH=d1e3b0d851ffa2c6bd42bf0c04f70d0e1d0d78f8 +CARDDAV_VERSION=4.3.0 +CARDDAV_HASH=4ad7df8843951062878b1375f77c614f68bc5c61 UPDATE_KEY=$VERSION:$PERSISTENT_LOGIN_VERSION:$HTML5_NOTIFIER_VERSION:$CARDDAV_VERSION @@ -77,13 +83,13 @@ if [ $needs_update == 1 ]; then # download and verify the full release of the carddav plugin wget_verify \ - https://github.com/blind-coder/rcmcarddav/releases/download/v${CARDDAV_VERSION}/carddav-${CARDDAV_VERSION}.zip \ + https://github.com/blind-coder/rcmcarddav/releases/download/v${CARDDAV_VERSION}/carddav-v${CARDDAV_VERSION}.tar.gz \ $CARDDAV_HASH \ - /tmp/carddav.zip + /tmp/carddav.tar.gz # unzip and cleanup - unzip -q /tmp/carddav.zip -d ${RCM_PLUGIN_DIR} - rm -f /tmp/carddav.zip + tar -C ${RCM_PLUGIN_DIR} -zxf /tmp/carddav.tar.gz + rm -f /tmp/carddav.tar.gz # record the version we've installed echo $UPDATE_KEY > ${RCM_DIR}/version