diff --git a/.editorconfig b/.editorconfig index 593ae64e..fbe828c3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,7 +13,7 @@ trim_trailing_whitespace = true insert_final_newline = true [Makefile] -indent_style = tabs +indent_style = tab indent_size = 4 [Vagrantfile] @@ -23,7 +23,7 @@ indent_size = 2 indent_size = 2 [*.py] -indent_style = tabs +indent_style = tab [*.js] indent_size = 2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6688e676..d4247085 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,40 @@ CHANGELOG ========= +v0.44 (February 15, 2020) +------------------------- + +System: + +* TLS settings have been upgraded following Mozilla's recommendations for servers. TLS1.2 and 1.3 are now the only supported protocols for web, IMAP, and SMTP (submission). +* Fixed an issue starting services when Mail-in-a-Box isn't on the root filesystem. +* Changed some performance options affecting Roundcube and Nextcloud. + +Software updates: + +* Upgraded Nextcloud from 15.0.8 to 17.0.2 (with Contacts from 3.1.1 to 3.1.6 and Calendar from 1.6.5 to 1.7.1) +* Upgraded Z-Push to 2.5.1. +* Upgraded Roundcube from 1.3.10 to 1.4.2 and changed the default skin (theme) to Elastic. + +Control panel: + +* The Custom DNS list of records is now sorted. +* The emails that report TLS provisioning results now has a less scary subject line. + +Mail: + +* Fetching of updated whitelist for greylisting was fetching each day instead of every month. +* OpenDKIM signing has been changed to 'relaxed' mode so that some old mail lists that forward mail can do so. + +DNS: + +* Automatic autoconfig.* subdomains can now be suppressed with custom DNS records. +* DNS zone transfer now works with IPv6 addresses. + +Setup: + +* An Ubuntu package source was missing on systems where it defaults off. + v0.43 (September 1, 2019) ------------------------- diff --git a/README.md b/README.md index 3f765c5f..8b6039e8 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ This is an experimental implementation of Mail-in-a-box with quota support. Quotas can be set and viewed in the control panel To set quotas from the command line, use: - + tools/mail.py user quota To set the system default quota for new users, use: - + tools/mail.py system default-quota Mailbox size recalculation by Dovecot can be forced using the command: @@ -63,12 +63,16 @@ Upgrading MiaB with quotas to a New Version Issues ------ -* When a user's quota is changed, any IMAP session running for that user will not recognize the new quota. To solve this a `dovecot reload` could be issued causing all current IMAP sessions to be terminated. On a system with many users, it might not be desirable to reset all users sessions to fix the quota for one user. Also if the administrator is setting the quota for several users it would result in the continual reset of those connections. +* When a user's quota is changed, any IMAP session running for that user will not recognize the new quota. To solve this a `dovecot reload` could be issued causing all current IMAP sessions to be terminated. On a system with many users, it might not be desirable to reset all users sessions to fix the quota for one user. Also if the administrator is setting the quota for several users it would result in the continual reset of those connections. Changes ------- +### v0.44-quota-0.22-beta + +* Update to v0.44 of Mail-in-a-Box + ### v0.43-quota-0.22-beta * Fix bug that crashed user list when there is an archived user. @@ -177,7 +181,7 @@ Our goals are to: * Make deploying a good mail server easy. * Promote [decentralization](http://redecentralize.org/), innovation, and privacy on the web. -* Have automated, auditable, and [idempotent](https://sharknet.us/2014/02/01/automated-configuration-management-challenges-with-idempotency/) configuration. +* Have automated, auditable, and [idempotent](https://web.archive.org/web/20190518072631/https://sharknet.us/2014/02/01/automated-configuration-management-challenges-with-idempotency/) configuration. * **Not** make a totally unhackable, NSA-proof server. * **Not** make something customizable by power users. @@ -222,7 +226,7 @@ by him: $ curl -s https://keybase.io/joshdata/key.asc | gpg --import gpg: key C10BDD81: public key "Joshua Tauberer " imported - $ git verify-tag v0.43 + $ git verify-tag v0.44 gpg: Signature made ..... using RSA key ID C10BDD81 gpg: Good signature from "Joshua Tauberer " gpg: WARNING: This key is not certified with a trusted signature! @@ -235,7 +239,7 @@ and on his [personal homepage](https://razor.occams.info/). (Of course, if this Checkout the tag corresponding to the most recent release: - $ git checkout v0.43 + $ git checkout v0.44 Begin the installation. @@ -248,7 +252,7 @@ Post your question on the [discussion forum](https://discourse.mailinabox.email/ Contributing and Development ---------------------------- -Mail-in-a-Box is an open source project. Your contributions and pull requests are welcome. See [CONTRIBUTING](CONTRIBUTING.md) to get started. +Mail-in-a-Box is an open source project. Your contributions and pull requests are welcome. See [CONTRIBUTING](CONTRIBUTING.md) to get started. The Acknowledgements diff --git a/conf/nginx-ssl.conf b/conf/nginx-ssl.conf index 1aba45c3..621973df 100644 --- a/conf/nginx-ssl.conf +++ b/conf/nginx-ssl.conf @@ -1,7 +1,7 @@ # We track the Mozilla "intermediate" compatibility TLS recommendations. # Note that these settings are repeated in the SMTP and IMAP configuration. # ssl_protocols has moved to nginx.conf in bionic, check there for enabled protocols. -ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; +ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; ssl_dhparam STORAGE_ROOT/ssl/dh2048.pem; # as recommended by http://nginx.org/en/docs/http/configuring_https_servers.html diff --git a/management/backup.py b/management/backup.py index 11cdbb8a..e1651552 100755 --- a/management/backup.py +++ b/management/backup.py @@ -410,7 +410,7 @@ def list_target_files(config): reason = "The hostname {} cannot be resolved.".format(target.hostname) else: reason = "Unknown error." \ - "Please check running 'python management/backup.py --verify'" \ + "Please check running 'management/backup.py --verify'" \ "from mailinabox sources to debug the issue." raise ValueError("Connection to rsync host failed: {}".format(reason)) diff --git a/management/daily_tasks.sh b/management/daily_tasks.sh index 3054dd33..2f723352 100755 --- a/management/daily_tasks.sh +++ b/management/daily_tasks.sh @@ -19,7 +19,7 @@ fi management/backup.py | management/email_administrator.py "Backup Status" # Provision any new certificates for new domains or domains with expiring certificates. -management/ssl_certificates.py -q | management/email_administrator.py "Error Provisioning TLS Certificate" +management/ssl_certificates.py -q | management/email_administrator.py "TLS Certificate Provisioning Result" # Run status checks and email the administrator if anything changed. management/status_checks.py --show-changes | management/email_administrator.py "Status Checks Change Notice" diff --git a/management/dns_update.py b/management/dns_update.py index dba6dbc1..7d053d5e 100755 --- a/management/dns_update.py +++ b/management/dns_update.py @@ -523,9 +523,11 @@ zone: """ % (domain, zonefile) # If custom secondary nameservers have been set, allow zone transfers - # and notifies to them. + # and, if not a subnet, notifies to them. for ipaddr in get_secondary_dns(additional_records, mode="xfr"): - nsdconf += "\n\tnotify: %s NOKEY\n\tprovide-xfr: %s NOKEY\n" % (ipaddr, ipaddr) + if "/" not in ipaddr: + nsdconf += "\n\tnotify: %s NOKEY" % (ipaddr) + nsdconf += "\n\tprovide-xfr: %s NOKEY\n" % (ipaddr) # Check if the file is changing. If it isn't changing, # return False to flag that no change was made. @@ -873,10 +875,15 @@ def get_secondary_dns(custom_dns, mode=None): # This is a hostname. Before including in zone xfr lines, # resolve to an IP address. Otherwise just return the hostname. + # It may not resolve to IPv6, so don't throw an exception if it + # doesn't. if not hostname.startswith("xfr:"): if mode == "xfr": - response = dns.resolver.query(hostname+'.', "A") - hostname = str(response[0]) + response = dns.resolver.query(hostname+'.', "A", raise_on_no_answer=False) + values.extend(map(str, response)) + response = dns.resolver.query(hostname+'.', "AAAA", raise_on_no_answer=False) + values.extend(map(str, response)) + continue values.append(hostname) # This is a zone-xfer-only IP address. Do not return if diff --git a/management/templates/custom-dns.html b/management/templates/custom-dns.html index 56facdc9..a2d5042d 100644 --- a/management/templates/custom-dns.html +++ b/management/templates/custom-dns.html @@ -192,6 +192,22 @@ function show_current_custom_dns() { $('#custom-dns-current').fadeIn(); else $('#custom-dns-current').fadeOut(); + + var reverse_fqdn = function(el) { + el.qname = el.qname.split('.').reverse().join('.'); + return el; + } + var sort = function(a, b) { + if(a.qname === b.qname) { + if(a.rtype === b.rtype) { + return a.value > b.value ? 1 : -1; + } + return a.rtype > b.rtype ? 1 : -1; + } + return a.qname > b.qname ? 1 : -1; + } + + data = data.map(reverse_fqdn).sort(sort).map(reverse_fqdn); $('#custom-dns-current').find("tbody").text(''); for (var i = 0; i < data.length; i++) { diff --git a/management/web_update.py b/management/web_update.py index 12959632..72295c21 100644 --- a/management/web_update.py +++ b/management/web_update.py @@ -23,11 +23,6 @@ def get_web_domains(env, include_www_redirects=True, exclude_dns_elsewhere=True) # to the main domain for. We'll add 'www.' to any DNS zones, i.e. # the topmost of each domain we serve. domains |= set('www.' + zone for zone, zonefile in get_dns_zones(env)) - - if exclude_dns_elsewhere: - # ...Unless the domain has an A/AAAA record that maps it to a different - # IP address than this box. Remove those domains from our list. - domains -= get_domains_with_a_records(env) # Add Autoconfiguration domains, allowing us to serve correct SSL certs. # 'autoconfig.' for Mozilla Thunderbird auto setup. @@ -35,6 +30,11 @@ def get_web_domains(env, include_www_redirects=True, exclude_dns_elsewhere=True) domains |= set('autoconfig.' + maildomain for maildomain in get_mail_domains(env)) domains |= set('autodiscover.' + maildomain for maildomain in get_mail_domains(env)) + if exclude_dns_elsewhere: + # ...Unless the domain has an A/AAAA record that maps it to a different + # IP address than this box. Remove those domains from our list. + domains -= get_domains_with_a_records(env) + # Ensure the PRIMARY_HOSTNAME is in the list so we can serve webmail # as well as Z-Push for Exchange ActiveSync. This can't be removed # by a custom A/AAAA record and is never a 'www.' redirect. diff --git a/security.md b/security.md index b8dc35af..8c9d43e5 100644 --- a/security.md +++ b/security.md @@ -39,9 +39,8 @@ These services are protected by [TLS](https://en.wikipedia.org/wiki/Transport_La The services all follow these rules: * TLS certificates are generated with 2048-bit RSA keys and SHA-256 fingerprints. The box provides a self-signed certificate by default. The [setup guide](https://mailinabox.email/guide.html) explains how to verify the certificate fingerprint on first login. Users are encouraged to replace the certificate with a proper CA-signed one. ([source](setup/ssl.sh)) -* Only TLSv1, TLSv1.1 and TLSv1.2 are offered (the older SSL protocols are not offered). -* HTTPS, IMAP, and POP track the [Mozilla Intermediate Ciphers Recommendation](https://wiki.mozilla.org/Security/Server_Side_TLS), balancing security with supporting a wide range of mail clients. Diffie-Hellman ciphers use a 2048-bit key for forward secrecy. For more details, see the [output of SSLyze for these ports](tests/tls_results.txt). -* SMTP (port 25) uses the Postfix medium grade ciphers and SMTP Submission (port 587) uses the Postfix high grade ciphers ([more info](http://www.postfix.org/postconf.5.html#smtpd_tls_mandatory_ciphers)). +* Only TLSv1.2+ are offered (the older SSL protocols are not offered). +* We track the [Mozilla Intermediate Ciphers Recommendation](https://wiki.mozilla.org/Security/Server_Side_TLS), balancing security with supporting a wide range of mail clients. Diffie-Hellman ciphers use a 2048-bit key for forward secrecy. For more details, see the [output of SSLyze for these ports](tests/tls_results.txt). Additionally: @@ -95,7 +94,7 @@ Domain policy records allow recipient MTAs to detect when the _domain_ part of o ### User Policy -While domain policy records prevent other servers from sending mail with a "From:" header that matches a domain hosted on the box (see above), those policy records do not guarnatee that the user portion of the sender email address matches the actual sender. In enterprise environments where the box may host the mail of untrusted users, it is important to guard against users impersonating other users. +While domain policy records prevent other servers from sending mail with a "From:" header that matches a domain hosted on the box (see above), those policy records do not guarantee that the user portion of the sender email address matches the actual sender. In enterprise environments where the box may host the mail of untrusted users, it is important to guard against users impersonating other users. The box restricts the envelope sender address (also called the return path or MAIL FROM address --- this is different from the "From:" header) that users may put into outbound mail. The envelope sender address must be either their own email address (their SMTP login username) or any alias that they are listed as a permitted sender of. (There is currently no restriction on the contents of the "From:" header.) diff --git a/setup/bootstrap.sh b/setup/bootstrap.sh index 9eb65df5..f35201ce 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.43-quota-0.22-beta + TAG=v0.44-quota-0.22-beta 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/dkim.sh b/setup/dkim.sh index dc7e51e2..5bd32370 100755 --- a/setup/dkim.sh +++ b/setup/dkim.sh @@ -31,6 +31,7 @@ if grep -q "ExternalIgnoreList" /etc/opendkim.conf; then else # Add various configuration options to the end of `opendkim.conf`. cat >> /etc/opendkim.conf << EOF; +Canonicalization relaxed/simple MinimumKeyBits 1024 ExternalIgnoreList refile:/etc/opendkim/TrustedHosts InternalHosts refile:/etc/opendkim/TrustedHosts diff --git a/setup/mail-dovecot.sh b/setup/mail-dovecot.sh index f3ef753f..2f3fdf50 100755 --- a/setup/mail-dovecot.sh +++ b/setup/mail-dovecot.sh @@ -80,17 +80,16 @@ tools/editconf.py /etc/dovecot/conf.d/10-auth.conf \ "auth_mechanisms=plain login" # Enable SSL, specify the location of the SSL certificate and private key files. -# Disable obsolete SSL protocols and allow only good ciphers per http://baldric.net/2013/12/07/tls-ciphers-in-postfix-and-dovecot/. -# Enable strong ssl dh parameters - +# Use Mozilla's "Intermediate" recommendations at https://ssl-config.mozilla.org/#server=dovecot&server-version=2.2.33&config=intermediate&openssl-version=1.1.1, +# except that the current version of Dovecot does not have a TLSv1.3 setting, so we only use TLSv1.2. tools/editconf.py /etc/dovecot/conf.d/10-ssl.conf \ ssl=required \ "ssl_cert=<$STORAGE_ROOT/ssl/ssl_certificate.pem" \ "ssl_key=<$STORAGE_ROOT/ssl/ssl_private_key.pem" \ - "ssl_protocols=!SSLv3" \ - "ssl_cipher_list=ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS" \ - "ssl_prefer_server_ciphers = yes" \ - "ssl_dh_parameters_length = 2048" + "ssl_protocols=TLSv1.2" \ + "ssl_cipher_list=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" \ + "ssl_prefer_server_ciphers=no" \ + "ssl_dh_parameters_length=2048" # Disable in-the-clear IMAP/POP because there is no reason for a user to transmit # login credentials outside of an encrypted connection. Only the over-TLS versions diff --git a/setup/mail-postfix.sh b/setup/mail-postfix.sh index 684aafdd..c10c18b7 100755 --- a/setup/mail-postfix.sh +++ b/setup/mail-postfix.sh @@ -80,8 +80,7 @@ tools/editconf.py /etc/postfix/main.cf \ # OpenDKIM milter only. See dkim.sh. # * Even though we dont allow auth over non-TLS connections (smtpd_tls_auth_only below, and without auth the client cant # send outbound mail), don't allow non-TLS mail submission on this port anyway to prevent accidental misconfiguration. -# * Require the best ciphers for incoming connections per http://baldric.net/2013/12/07/tls-ciphers-in-postfix-and-dovecot/. -# By putting this setting here we leave opportunistic TLS on incoming mail at default cipher settings (any cipher is better than none). +# Setting smtpd_tls_security_level=encrypt also triggers the use of the 'mandatory' settings below. # * Give it a different name in syslog to distinguish it from the port 25 smtpd server. # * Add a new cleanup service specific to the submission service ('authclean') # that filters out privacy-sensitive headers on mail being sent out by @@ -93,7 +92,6 @@ tools/editconf.py /etc/postfix/master.cf -s -w \ -o syslog_name=postfix/submission -o smtpd_milters=inet:127.0.0.1:8891 -o smtpd_tls_security_level=encrypt - -o smtpd_tls_ciphers=high -o smtpd_tls_exclude_ciphers=aNULL,DES,3DES,MD5,DES+MD5,RC4 -o smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3 -o cleanup_service_name=authclean" \ "authclean=unix n - - - 0 cleanup -o header_checks=pcre:/etc/postfix/outgoing_mail_header_filters @@ -108,20 +106,35 @@ cp conf/postfix_outgoing_mail_header_filters /etc/postfix/outgoing_mail_header_f sed -i "s/PRIMARY_HOSTNAME/$PRIMARY_HOSTNAME/" /etc/postfix/outgoing_mail_header_filters sed -i "s/PUBLIC_IP/$PUBLIC_IP/" /etc/postfix/outgoing_mail_header_filters -# Enable TLS on these and all other connections (i.e. ports 25 *and* 587) and -# require TLS before a user is allowed to authenticate. This also makes -# opportunistic TLS available on *incoming* mail. -# Set stronger DH parameters, which via openssl tend to default to 1024 bits -# (see ssl.sh). +# Enable TLS on incoming connections. It is not required on port 25, allowing for opportunistic +# encryption. On port 587 it is mandatory (see above). Shared and non-shared settings are +# given here. Shared settings include: +# * Require TLS before a user is allowed to authenticate. +# * Set the path to the server TLS certificate and 2048-bit DH parameters for old DH ciphers. +# For port 25 only: +# * Disable extremely old versions of TLS and extremely unsafe ciphers, but some mail servers out in +# the world are very far behind and if we disable too much, they may not be able to use TLS and +# won't fall back to cleartext. So we don't disable too much. smtpd_tls_exclude_ciphers applies to +# both port 25 and port 587, but because we override the cipher list for both, it probably isn't used. +# Use Mozilla's "Old" recommendations at https://ssl-config.mozilla.org/#server=postfix&server-version=3.3.0&config=old&openssl-version=1.1.1 +# For port 587 (via the 'mandatory' settings): +# * Use Mozilla's "Intermediate" TLS recommendations from https://ssl-config.mozilla.org/#server=postfix&server-version=3.3.0&config=intermediate&openssl-version=1.1.1 +# using and overriding the "high" cipher list so we don't conflict with the more permissive settings for port 25. tools/editconf.py /etc/postfix/main.cf \ smtpd_tls_security_level=may\ smtpd_tls_auth_only=yes \ smtpd_tls_cert_file=$STORAGE_ROOT/ssl/ssl_certificate.pem \ smtpd_tls_key_file=$STORAGE_ROOT/ssl/ssl_private_key.pem \ smtpd_tls_dh1024_param_file=$STORAGE_ROOT/ssl/dh2048.pem \ - smtpd_tls_protocols=\!SSLv2,\!SSLv3 \ + smtpd_tls_protocols="!SSLv2,!SSLv3" \ smtpd_tls_ciphers=medium \ + tls_medium_cipherlist=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA \ smtpd_tls_exclude_ciphers=aNULL,RC4 \ + smtpd_tls_mandatory_protocols="!SSLv2,!SSLv3,!TLSv1,!TLSv1.1" \ + smtpd_tls_mandatory_ciphers=high \ + tls_high_cipherlist=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 \ + smtpd_tls_mandatory_exclude_ciphers=aNULL,DES,3DES,MD5,DES+MD5,RC4 \ + tls_preempt_cipherlist=no \ smtpd_tls_received_header=yes # Prevent non-authenticated users from sending mail that requires being @@ -143,8 +156,12 @@ tools/editconf.py /etc/postfix/main.cf \ # offers it, otherwise it will transmit the message in the clear. Postfix will # accept whatever SSL certificate the remote end provides. Opportunistic TLS # protects against passive easvesdropping (but not man-in-the-middle attacks). +# Since we'd rather have poor encryption than none at all, we use Mozilla's +# "Old" recommendations at https://ssl-config.mozilla.org/#server=postfix&server-version=3.3.0&config=old&openssl-version=1.1.1 +# for opportunistic encryption but "Intermediate" recommendations when DANE +# is used (see next and above). The cipher lists are set above. + # DANE takes this a step further: -# # Postfix queries DNS for the TLSA record on the destination MX host. If no TLSA records are found, # then opportunistic TLS is used. Otherwise the server certificate must match the TLSA records # or else the mail bounces. TLSA also requires DNSSEC on the MX host. Postfix doesn't do DNSSEC @@ -157,11 +174,12 @@ tools/editconf.py /etc/postfix/main.cf \ # now see notices about trusted certs. The CA file is provided by the package `ca-certificates`. tools/editconf.py /etc/postfix/main.cf \ smtp_tls_protocols=\!SSLv2,\!SSLv3 \ - smtp_tls_mandatory_protocols=\!SSLv2,\!SSLv3 \ smtp_tls_ciphers=medium \ smtp_tls_exclude_ciphers=aNULL,RC4 \ smtp_tls_security_level=dane \ smtp_dns_support_level=dnssec \ + smtp_tls_mandatory_protocols="!SSLv2,!SSLv3,!TLSv1,!TLSv1.1" \ + smtp_tls_mandatory_ciphers=high \ smtp_tls_CAfile=/etc/ssl/certs/ca-certificates.crt \ smtp_tls_loglevel=2 @@ -208,7 +226,7 @@ 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 --whitelist-recipients=/etc/postgrey/whitelist_clients'\" + POSTGREY_OPTS=\"'--inet=127.0.0.1:10023 --delay=180'\" # We are going to setup a newer whitelist for postgrey, the version included in the distribution is old @@ -218,7 +236,7 @@ cat > /etc/cron.daily/mailinabox-postgrey-whitelist << EOF; # 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 +if [ ! -f /etc/postgrey/whitelist_clients ] || find /etc/postgrey/whitelist_clients -mtime +28 | grep -q '.' ; 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 diff --git a/setup/management.sh b/setup/management.sh index 3a6e187b..3caf8eea 100755 --- a/setup/management.sh +++ b/setup/management.sh @@ -93,7 +93,8 @@ source $venv/bin/activate exec python `pwd`/management/daemon.py EOF chmod +x $inst_dir/start -hide_output systemctl link -f conf/mailinabox.service +cp --remove-destination conf/mailinabox.service /lib/systemd/system/mailinabox.service # target was previously a symlink so remove it first +hide_output systemctl link -f /lib/systemd/system/mailinabox.service hide_output systemctl daemon-reload hide_output systemctl enable mailinabox.service diff --git a/setup/munin.sh b/setup/munin.sh index df7af601..6799cad6 100755 --- a/setup/munin.sh +++ b/setup/munin.sh @@ -53,7 +53,7 @@ find /etc/munin/plugins/ -lname /usr/share/munin/plugins/ntp_ -print0 | xargs -0 # Deactivate monitoring of network interfaces that are not up. Otherwise we can get a lot of empty charts. for f in $(find /etc/munin/plugins/ \( -lname /usr/share/munin/plugins/if_ -o -lname /usr/share/munin/plugins/if_err_ -o -lname /usr/share/munin/plugins/bonding_err_ \)); do IF=$(echo $f | sed s/.*_//); - if ! ifquery $IF >/dev/null 2>/dev/null; then + if ! grep -qFx up /sys/class/net/$IF/operstate 2>/dev/null; then rm $f; fi; done @@ -64,7 +64,8 @@ mkdir -p /var/lib/munin-node/plugin-state/ # Create a systemd service for munin. ln -sf $(pwd)/management/munin_start.sh /usr/local/lib/mailinabox/munin_start.sh chmod 0744 /usr/local/lib/mailinabox/munin_start.sh -hide_output systemctl link -f conf/munin.service +cp --remove-destination conf/munin.service /lib/systemd/system/munin.service # target was previously a symlink so remove first +hide_output systemctl link -f /lib/systemd/system/munin.service hide_output systemctl daemon-reload hide_output systemctl unmask munin.service hide_output systemctl enable munin.service diff --git a/setup/nextcloud.sh b/setup/nextcloud.sh index d5a8e7c5..3ab21176 100755 --- a/setup/nextcloud.sh +++ b/setup/nextcloud.sh @@ -40,18 +40,18 @@ InstallNextcloud() { # their github repositories. mkdir -p /usr/local/lib/owncloud/apps - wget_verify https://github.com/nextcloud/contacts/releases/download/v3.1.1/contacts.tar.gz a06bd967197dcb03c94ec1dbd698c037018669e5 /tmp/contacts.tgz + wget_verify https://github.com/nextcloud/contacts/releases/download/v3.1.6/contacts.tar.gz d331dc6db2ecf7c8e6166926a055dfa3b59722c3 /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/v1.6.5/calendar.tar.gz 79941255521a5172f7e4ce42dc7773838b5ede2f /tmp/calendar.tgz + wget_verify https://github.com/nextcloud/calendar/releases/download/v1.7.1/calendar.tar.gz bd7c846bad06da6d6ba04280f6fbf37ef846c2ad /tmp/calendar.tgz tar xf /tmp/calendar.tgz -C /usr/local/lib/owncloud/apps/ rm /tmp/calendar.tgz # Starting with Nextcloud 15, the app user_external is no longer included in Nextcloud core, # we will install from their github repository. - if [[ $version =~ ^15 ]]; then - wget_verify https://github.com/nextcloud/user_external/releases/download/v0.6.3/user_external-0.6.3.tar.gz 0f756d35fef6b64a177d6a16020486b76ea5799c /tmp/user_external.tgz + if [[ $version =~ ^1[567] ]]; then + wget_verify https://github.com/nextcloud/user_external/releases/download/v0.7.0/user_external-0.7.0.tar.gz 555a94811daaf5bdd336c5e48a78aa8567b86437 /tmp/user_external.tgz tar -xf /tmp/user_external.tgz -C /usr/local/lib/owncloud/apps/ rm /tmp/user_external.tgz fi @@ -91,8 +91,8 @@ InstallNextcloud() { } # Nextcloud Version to install. Checks are done down below to step through intermediate versions. -nextcloud_ver=15.0.8 -nextcloud_hash=4129d8d4021c435f2e86876225fb7f15adf764a3 +nextcloud_ver=17.0.2 +nextcloud_hash=8095fb46e9e0c536163708aee3d17fab8b498ad6 # Current Nextcloud Version, #1623 # Checking /usr/local/lib/owncloud/version.php shows version of the Nextcloud application, not the DB @@ -142,11 +142,19 @@ if [ ! -d /usr/local/lib/owncloud/ ] || [[ ! ${CURRENT_NEXTCLOUD_VER} =~ ^$nextc elif [[ ${CURRENT_NEXTCLOUD_VER} =~ ^13 ]]; then # If we are running Nextcloud 13, upgrade to Nextcloud 14 InstallNextcloud 14.0.6 4e43a57340f04c2da306c8eea98e30040399ae5a - elif [[ ${CURRENT_NEXTCLOUD_VER} =~ ^14 ]]; then + CURRENT_NEXTCLOUD_VER="14.0.6" + fi + if [[ ${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 + InstallNextcloud 15.0.8 4129d8d4021c435f2e86876225fb7f15adf764a3 + CURRENT_NEXTCLOUD_VER="15.0.8" fi + if [[ ${CURRENT_NEXTCLOUD_VER} =~ ^15 ]]; then + InstallNextcloud 16.0.6 0bb3098455ec89f5af77a652aad553ad40a88819 + CURRENT_NEXTCLOUD_VER="16.0.6" + fi fi InstallNextcloud $nextcloud_ver $nextcloud_hash @@ -295,10 +303,6 @@ tools/editconf.py /etc/php/7.2/cli/conf.d/10-opcache.ini -c ';' \ opcache.save_comments=1 \ opcache.revalidate_freq=1 -# Configure the path environment for php-fpm -tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \ - env[PATH]=/usr/local/bin:/usr/bin:/bin - # If apc is explicitly disabled we need to enable it if grep -q apc.enabled=0 /etc/php/7.2/mods-available/apcu.ini; then tools/editconf.py /etc/php/7.2/mods-available/apcu.ini -c ';' \ @@ -306,12 +310,15 @@ if grep -q apc.enabled=0 /etc/php/7.2/mods-available/apcu.ini; then fi # Set up a cron job for Nextcloud. -cat > /etc/cron.hourly/mailinabox-owncloud << EOF; +cat > /etc/cron.d/mailinabox-nextcloud << EOF; #!/bin/bash # Mail-in-a-Box -sudo -u www-data php -f /usr/local/lib/owncloud/cron.php +*/5 * * * * root sudo -u www-data php -f /usr/local/lib/owncloud/cron.php EOF -chmod +x /etc/cron.hourly/mailinabox-owncloud +chmod +x /etc/cron.d/mailinabox-nextcloud + +# Remove previous hourly cronjob +rm -f /etc/cron.hourly/mailinabox-owncloud # There's nothing much of interest that a user could do as an admin for Nextcloud, # and there's a lot they could mess up, so we don't make any users admins of Nextcloud. diff --git a/setup/spamassassin.sh b/setup/spamassassin.sh index 148cfd0b..d6c8b83b 100755 --- a/setup/spamassassin.sh +++ b/setup/spamassassin.sh @@ -64,8 +64,8 @@ tools/editconf.py /etc/default/spampd \ # the X-Spam-Status & X-Spam-Score mail headers and related headers. tools/editconf.py /etc/spamassassin/local.cf -s \ report_safe=0 \ - add_header="all Report _REPORT_" \ - add_header="all Score _SCORE_" + "add_header all Report"=_REPORT_ \ + "add_header all Score"=_SCORE_ # Bayesean learning # ----------------- diff --git a/setup/system.sh b/setup/system.sh index ccc60231..28043b16 100755 --- a/setup/system.sh +++ b/setup/system.sh @@ -86,6 +86,10 @@ if [ ! -f /usr/bin/add-apt-repository ]; then apt_install software-properties-common fi +# Ensure the universe repository is enabled since some of our packages +# come from there and minimal Ubuntu installs may have it turned off. +hide_output add-apt-repository -y universe + # Install the certbot PPA. hide_output add-apt-repository -y ppa:certbot/certbot @@ -121,11 +125,12 @@ apt_get_quiet autoremove # * sudo: allows privileged users to execute commands as root without being root # * coreutils: includes `nproc` tool to report number of processors, mktemp # * bc: allows us to do math to compute sane defaults +# * openssh-client: provides ssh-keygen echo Installing system packages... apt_install python3 python3-dev python3-pip \ netcat-openbsd wget curl git sudo coreutils bc \ - haveged pollinate unzip \ + haveged pollinate openssh-client unzip \ unattended-upgrades cron ntp fail2ban rsyslog # ### Suppress Upgrade Prompts diff --git a/setup/web.sh b/setup/web.sh index ed37e5e3..e6aac6ef 100755 --- a/setup/web.sh +++ b/setup/web.sh @@ -31,14 +31,19 @@ sed "s#STORAGE_ROOT#$STORAGE_ROOT#" \ conf/nginx-ssl.conf > /etc/nginx/conf.d/ssl.conf # Fix some nginx defaults. +# # The server_names_hash_bucket_size seems to prevent long domain names! # The default, according to nginx's docs, depends on "the size of the # processor’s cache line." It could be as low as 32. We fixed it at # 64 in 2014 to accommodate a long domain name (20 characters?). But # even at 64, a 58-character domain name won't work (#93), so now # we're going up to 128. +# +# Drop TLSv1.0, TLSv1.1, following the Mozilla "Intermediate" recommendations +# at https://ssl-config.mozilla.org/#server=nginx&server-version=1.17.0&config=intermediate&openssl-version=1.1.1. tools/editconf.py /etc/nginx/nginx.conf -s \ - server_names_hash_bucket_size="128;" + server_names_hash_bucket_size="128;" \ + ssl_protocols="TLSv1.2 TLSv1.3;" # Tell PHP not to expose its version number in the X-Powered-By header. tools/editconf.py /etc/php/7.2/fpm/php.ini -c ';' \ @@ -48,13 +53,47 @@ tools/editconf.py /etc/php/7.2/fpm/php.ini -c ';' \ tools/editconf.py /etc/php/7.2/fpm/php.ini -c ';' \ default_charset="UTF-8" -# Switch from the dynamic process manager to the ondemand manager see #1216 +# Configure the path environment for php-fpm tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \ - pm=ondemand + env[PATH]=/usr/local/bin:/usr/bin:/bin \ -# Bump up PHP's max_children to support more concurrent connections -tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \ - pm.max_children=8 +# Configure php-fpm based on the amount of memory the machine has +# This is based on the nextcloud manual for performance tuning: https://docs.nextcloud.com/server/17/admin_manual/installation/server_tuning.html +# Some synchronisation issues can occur when many people access the site at once. +# The pm=ondemand setting is used for memory constrained machines < 2GB, this is copied over from PR: 1216 +TOTAL_PHYSICAL_MEM=$(head -n 1 /proc/meminfo | awk '{print $2}' || /bin/true) +if [ $TOTAL_PHYSICAL_MEM -lt 1000000 ] +then + tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \ + pm=ondemand \ + pm.max_children=8 \ + pm.start_servers=2 \ + pm.min_spare_servers=1 \ + pm.max_spare_servers=3 +elif [ $TOTAL_PHYSICAL_MEM -lt 2000000 ] +then + tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \ + pm=ondemand \ + pm.max_children=16 \ + pm.start_servers=4 \ + pm.min_spare_servers=1 \ + pm.max_spare_servers=6 +elif [ $TOTAL_PHYSICAL_MEM -lt 3000000 ] +then + tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \ + pm=dynamic \ + pm.max_children=60 \ + pm.start_servers=6 \ + pm.min_spare_servers=3 \ + pm.max_spare_servers=9 +else + tools/editconf.py /etc/php/7.2/fpm/pool.d/www.conf -c ';' \ + pm=dynamic \ + pm.max_children=120 \ + pm.start_servers=12 \ + pm.min_spare_servers=6 \ + pm.max_spare_servers=18 +fi # Other nginx settings will be configured by the management service # since it depends on what domains we're serving, which we don't know diff --git a/setup/webmail.sh b/setup/webmail.sh index 5e1c6233..3834374d 100755 --- a/setup/webmail.sh +++ b/setup/webmail.sh @@ -22,15 +22,15 @@ source /etc/mailinabox.conf # load global vars echo "Installing Roundcube (webmail)..." apt_install \ dbconfig-common \ - php-cli php-sqlite3 php-intl php-json php-common php-curl \ + php-cli php-sqlite3 php-intl php-json php-common php-curl php-ldap \ php-gd php-pspell tinymce libjs-jquery libjs-jquery-mousewheel libmagic1 php-mbstring # 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.10 -HASH=431625fc737e301f9b7e502cccc61e50a24786b8 -PERSISTENT_LOGIN_VERSION=dc5ca3d3f4415cc41edb2fde533c8a8628a94c76 +VERSION=1.4.2 +HASH=d53fcd7f1109a63364d5d4a43f879c6f47d34a89 +PERSISTENT_LOGIN_VERSION=6b3fc450cae23ccb2f393d0ef67aa319e877e435 HTML5_NOTIFIER_VERSION=4b370e3cd60dabd2f428a26f45b677ad1b7118d5 CARDDAV_VERSION=3.0.3 CARDDAV_HASH=d1e3b0d851ffa2c6bd42bf0c04f70d0e1d0d78f8 @@ -51,6 +51,13 @@ elif [[ "$UPDATE_KEY" != `cat /usr/local/lib/roundcubemail/version` ]]; then needs_update=1 #NODOC fi if [ $needs_update == 1 ]; then + # if upgrading from 1.3.x, clear the temp_dir + if [ -f /usr/local/lib/roundcubemail/version ]; then + if [ "$(cat /usr/local/lib/roundcubemail/version | cut -c1-3)" == '1.3' ]; then + find /var/tmp/roundcubemail/ -type f ! -name 'RCMTEMP*' -delete + fi + fi + # install roundcube wget_verify \ https://github.com/roundcube/roundcubemail/releases/download/$VERSION/roundcubemail-$VERSION-complete.tar.gz \ @@ -110,9 +117,6 @@ cat > $RCM_CONFIG < array( 'verify_peer' => false, @@ -123,7 +127,7 @@ cat > $RCM_CONFIG <