diff --git a/core/admin/mailu/internal/nginx.py b/core/admin/mailu/internal/nginx.py index b5fda17d..9667d3f7 100644 --- a/core/admin/mailu/internal/nginx.py +++ b/core/admin/mailu/internal/nginx.py @@ -13,6 +13,7 @@ STATUSES = { "authentication": ("Authentication credentials invalid", { "imap": "AUTHENTICATIONFAILED", "smtp": "535 5.7.8", + "submission": "535 5.7.8", "pop3": "-ERR Authentication failed", "sieve": "AuthFailed" }), @@ -56,7 +57,7 @@ def handle_authentication(headers): method = headers["Auth-Method"].lower() protocol = headers["Auth-Protocol"].lower() # Incoming mail, no authentication - if method == "none" and protocol == "smtp": + if method in ['', 'none'] and protocol in ['smtp', 'lmtp']: server, port = get_server(protocol, False) if app.config["INBOUND_TLS_ENFORCE"]: if "Auth-SSL" in headers and headers["Auth-SSL"] == "on": @@ -79,7 +80,7 @@ def handle_authentication(headers): "Auth-Port": port } # Authenticated user - elif method == "plain": + elif method in ['plain', 'login']: is_valid_user = False # According to RFC2616 section 3.7.1 and PEP 3333, HTTP headers should # be ASCII and are generally considered ISO8859-1. However when passing @@ -122,7 +123,7 @@ def handle_authentication(headers): "Auth-Wait": 0 } # Unexpected - raise Exception("SHOULD NOT HAPPEN") + raise Exception(f"SHOULD NOT HAPPEN {protocol} {method}") def get_status(protocol, status): @@ -132,16 +133,20 @@ def get_status(protocol, status): return status, codes[protocol] def get_server(protocol, authenticated=False): - if protocol == "imap": + if protocol == 'imap': hostname, port = app.config['IMAP_ADDRESS'], 143 - elif protocol == "pop3": + elif protocol == 'pop3': hostname, port = app.config['IMAP_ADDRESS'], 110 - elif protocol == "smtp": + elif protocol == 'smtp': if authenticated: hostname, port = app.config['SMTP_ADDRESS'], 10025 else: hostname, port = app.config['SMTP_ADDRESS'], 25 - elif protocol == "sieve": + elif protocol == 'submission': + hostname, port = app.config['SMTP_ADDRESS'], 10025 + elif protocol == 'lmtp': + hostname, port = app.config['IMAP_ADDRESS'], 2525 + elif protocol == 'sieve': hostname, port = app.config['IMAP_ADDRESS'], 4190 try: # test if hostname is already resolved to an ip address diff --git a/core/admin/mailu/internal/views/auth.py b/core/admin/mailu/internal/views/auth.py index c51bf103..cea90e6d 100644 --- a/core/admin/mailu/internal/views/auth.py +++ b/core/admin/mailu/internal/views/auth.py @@ -31,7 +31,7 @@ def nginx_authentication(): if int(flask.request.headers['Auth-Login-Attempt']) < 10: response.headers['Auth-Wait'] = '3' return response - raw_password = urllib.parse.unquote(headers["Auth-Pass"]) + raw_password = urllib.parse.unquote(headers['Auth-Pass']) if 'Auth-Pass' in headers else '' headers = nginx.handle_authentication(flask.request.headers) response = flask.Response() for key, value in headers.items(): diff --git a/core/admin/mailu/models.py b/core/admin/mailu/models.py index 8022709b..a6ec5c92 100644 --- a/core/admin/mailu/models.py +++ b/core/admin/mailu/models.py @@ -421,7 +421,7 @@ class Email(object): """ send an email to the address """ try: f_addr = f'{app.config["POSTMASTER"]}@{idna.encode(app.config["DOMAIN"]).decode("ascii")}' - with smtplib.LMTP(host=app.config['IMAP_ADDRESS'], port=2525) as lmtp: + with smtplib.LMTP(host=app.config['FRONT_ADDRESS'], port=2525) as lmtp: to_address = f'{self.localpart}@{idna.encode(self.domain_name).decode("ascii")}' msg = text.MIMEText(body) msg['Subject'] = subject diff --git a/core/dovecot/Dockerfile b/core/dovecot/Dockerfile index 97aa26ce..872e1ecf 100644 --- a/core/dovecot/Dockerfile +++ b/core/dovecot/Dockerfile @@ -15,7 +15,7 @@ COPY start.py / RUN echo $VERSION >/version -EXPOSE 110/tcp 143/tcp 993/tcp 4190/tcp 2525/tcp +# EXPOSE 110/tcp 143/tcp 993/tcp 4190/tcp 2525/tcp HEALTHCHECK CMD kill -0 `cat /run/dovecot/master.pid` VOLUME ["/mail"] diff --git a/core/dovecot/conf/dovecot.conf b/core/dovecot/conf/dovecot.conf index 43dcebe2..38ceb015 100644 --- a/core/dovecot/conf/dovecot.conf +++ b/core/dovecot/conf/dovecot.conf @@ -11,7 +11,6 @@ default_internal_user = dovecot default_login_user = mail default_internal_group = dovecot -haproxy_trusted_networks = {{ SUBNET }} {{ SUBNET6 }} login_trusted_networks = {{ SUBNET }} {{ SUBNET6 }} ############### @@ -112,14 +111,12 @@ protocol pop3 { service imap-login { inet_listener imap { port = 143 - haproxy = yes } } service pop3-login { inet_listener pop3 { port = 110 - haproxy = yes } } @@ -191,6 +188,12 @@ plugin { imapsieve_mailbox2_before = file:/conf/report-ham.sieve } +service anvil { + unix_listener anvil-auth-penalty { + mode = 0 + } +} + ############### # Extensions ############### diff --git a/core/nginx/Dockerfile b/core/nginx/Dockerfile index ac01a17e..f2eaac81 100644 --- a/core/nginx/Dockerfile +++ b/core/nginx/Dockerfile @@ -17,7 +17,7 @@ ARG VERSION LABEL version=$VERSION RUN set -euxo pipefail \ - ; apk add --no-cache certbot nginx nginx-mod-http-brotli nginx-mod-mail openssl dovecot-lua dovecot-pigeonhole-plugin + ; apk add --no-cache certbot nginx nginx-mod-http-brotli nginx-mod-mail openssl dovecot-lua dovecot-pigeonhole-plugin dovecot-lmtpd dovecot-pop3d dovecot-submissiond COPY conf/ /conf/ COPY --from=static /static/ /static/ diff --git a/core/nginx/conf/nginx.conf b/core/nginx/conf/nginx.conf index dc04b4d9..fdc3e171 100644 --- a/core/nginx/conf/nginx.conf +++ b/core/nginx/conf/nginx.conf @@ -321,28 +321,6 @@ mail { # Advertise real capabilities of backends (postfix/dovecot) smtp_capabilities PIPELINING "SIZE {{ MESSAGE_SIZE_LIMIT }}" ETRN ENHANCEDSTATUSCODES 8BITMIME DSN; - pop3_capabilities TOP UIDL RESP-CODES PIPELINING AUTH-RESP-CODE USER; - imap_capabilities IMAP4 IMAP4rev1 UIDPLUS SASL-IR LOGIN-REFERRALS ID ENABLE IDLE LITERAL+; - - # Default SMTP server for the webmail (no encryption, but authentication) - server { - listen 10025; - protocol smtp; - smtp_auth plain; - auth_http_header Auth-Port 10025; - auth_http_header Client-Port $remote_port; - } - - # Default IMAP server for the webmail (no encryption, but authentication) - server { - listen 10143; - protocol imap; - smtp_auth plain; - auth_http_header Auth-Port 10143; - auth_http_header Client-Port $remote_port; - # ensure we talk HAPROXY protocol to the backends - proxy_protocol on; - } # SMTP is always enabled, to avoid losing emails when TLS is failing server { @@ -367,92 +345,4 @@ mail { auth_http_header Auth-Port 25; auth_http_header Client-Port $remote_port; } - - # All other protocols are disabled if TLS is failing - {% if not TLS_ERROR %} - server { - listen 143{% if PROXY_PROTOCOL in ['all', 'mail'] %} proxy_protocol{% endif %}; -{% if SUBNET6 %} - listen [::]:143{% if PROXY_PROTOCOL in ['all', 'mail'] %} proxy_protocol{% endif %}; -{% endif %} - {% if TLS %} - starttls only; - {% endif %} - protocol imap; - imap_auth plain; - auth_http_header Auth-Port 143; - auth_http_header Client-Port $remote_port; - # ensure we talk HAPROXY protocol to the backends - proxy_protocol on; - } - - server { - listen 110{% if PROXY_PROTOCOL in ['all', 'mail'] %} proxy_protocol{% endif %}; -{% if SUBNET6 %} - listen [::]:110{% if PROXY_PROTOCOL in ['all', 'mail'] %} proxy_protocol{% endif %}; -{% endif %} - {% if TLS %} - starttls only; - {% endif %} - protocol pop3; - pop3_auth plain; - auth_http_header Auth-Port 110; - auth_http_header Client-Port $remote_port; - # ensure we talk HAPROXY protocol to the backends - proxy_protocol on; - } - - server { - listen 587{% if PROXY_PROTOCOL in ['all', 'mail'] %} proxy_protocol{% endif %}; -{% if SUBNET6 %} - listen [::]:587{% if PROXY_PROTOCOL in ['all', 'mail'] %} proxy_protocol{% endif %}; -{% endif %} - {% if TLS %} - starttls only; - {% endif %} - protocol smtp; - smtp_auth plain login; - auth_http_header Auth-Port 587; - auth_http_header Client-Port $remote_port; - } - - {% if TLS %} - server { - listen 465 ssl{% if PROXY_PROTOCOL in ['all', 'mail'] %} proxy_protocol{% endif %}; -{% if SUBNET6 %} - listen [::]:465 ssl{% if PROXY_PROTOCOL in ['all', 'mail'] %} proxy_protocol{% endif %}; -{% endif %} - protocol smtp; - smtp_auth plain login; - auth_http_header Auth-Port 465; - auth_http_header Client-Port $remote_port; - } - - server { - listen 993 ssl{% if PROXY_PROTOCOL in ['all', 'mail'] %} proxy_protocol{% endif %}; -{% if SUBNET6 %} - listen [::]:993 ssl{% if PROXY_PROTOCOL in ['all', 'mail'] %} proxy_protocol{% endif %}; -{% endif %} - protocol imap; - imap_auth plain; - auth_http_header Auth-Port 993; - auth_http_header Client-Port $remote_port; - # ensure we talk HAPROXY protocol to the backends - proxy_protocol on; - } - - server { - listen 995 ssl{% if PROXY_PROTOCOL in ['all', 'mail'] %} proxy_protocol{% endif %}; -{% if SUBNET6 %} - listen [::]:995 ssl{% if PROXY_PROTOCOL in ['all', 'mail'] %} proxy_protocol{% endif %}; -{% endif %} - protocol pop3; - pop3_auth plain; - auth_http_header Auth-Port 995; - auth_http_header Client-Port $remote_port; - # ensure we talk HAPROXY protocol to the backends - proxy_protocol on; - } - {% endif %} - {% endif %} } diff --git a/core/nginx/dovecot/login.lua b/core/nginx/dovecot/login.lua index 7c2c6c02..0b87a765 100644 --- a/core/nginx/dovecot/login.lua +++ b/core/nginx/dovecot/login.lua @@ -16,7 +16,10 @@ function auth_passdb_lookup(req) } auth_request:add_header('Auth-Port', req.local_port) auth_request:add_header('Auth-User', req.user) - auth_request:add_header('Auth-Pass', req.password) + if req.password ~= nil + then + auth_request:add_header('Auth-Pass', req.password) + end auth_request:add_header('Auth-Protocol', req.service) auth_request:add_header('Client-IP', req.remote_ip) auth_request:add_header('Client-Port', req.remote_port) @@ -31,7 +34,7 @@ function auth_passdb_lookup(req) then local server = auth_response:header('Auth-Server') local port = auth_response:header('Auth-Port') - return dovecot.auth.PASSDB_RESULT_OK, "proxy=y host=" .. server .. " port=" .. port .. " nopassword=Y" + return dovecot.auth.PASSDB_RESULT_OK, "proxy=y host=" .. server .. " port=" .. port .. " nopassword=Y proxy_noauth=Y" else return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, "" end diff --git a/core/nginx/dovecot/proxy.conf b/core/nginx/dovecot/proxy.conf index 64591626..4ab54005 100644 --- a/core/nginx/dovecot/proxy.conf +++ b/core/nginx/dovecot/proxy.conf @@ -5,10 +5,21 @@ log_path = /dev/stderr auth_verbose=yes mail_debug=yes login_log_format_elements = user=<%u> method=%m rip=%r rport=%b lip=%l lport=%a mpid=%e %c -protocols = sieve +protocols = sieve imap pop3 lmtp submission postmaster_address = {{ POSTMASTER }}@{{ DOMAIN }} hostname = {{ HOSTNAMES.split(",")[0] }} -submission_host = {{ FRONT_ADDRESS }} +submission_host = {{ SMTP_ADDRESS }} +submission_relay_host = {{ SMTP_ADDRESS }} +submission_relay_port = 10025 +submission_relay_trusted = yes +submission_relay_ssl = no +submission_max_mail_size = {{ MESSAGE_SIZE_LIMIT }} +submission_backend_capabilities = 8BITMIME DSN VRFY +submission_client_workarounds = mailbox-for-path whitespace-before-path +# disable BURL +imap_urlauth_host= +lmtp_proxy = yes +lmtp_client_workarounds = whitespace-before-path mailbox-for-path default_internal_user = dovecot default_login_user = mail @@ -32,15 +43,12 @@ ssl_alt_key = <{{ TLS[3] }} {% endif %} # intermediate configuration ssl_min_protocol = 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_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 ssl_prefer_server_ciphers = no -ssl_dh = array( + 'verify_peer' => false, + 'verify_peer_name' => false, + 'allow_self_signed' => true, + ), +); +$config['smtp_host'] = 'tls://{{ FRONT_ADDRESS or "front" }}:10025'; $config['smtp_user'] = '%u'; $config['smtp_pass'] = '%p'; +$config['smtp_conn_options'] = array( + 'ssl' => array( + 'verify_peer' => false, + 'verify_peer_name' => false, + 'allow_self_signed' => true, + ), +); // Sieve script management $config['managesieve_host'] = 'tls://{{ FRONT_ADDRESS or "front" }}:14190'; diff --git a/webmails/snappymail/defaults/default.json b/webmails/snappymail/defaults/default.json index 28107f4d..d7659405 100644 --- a/webmails/snappymail/defaults/default.json +++ b/webmails/snappymail/defaults/default.json @@ -3,7 +3,7 @@ "IMAP": { "host": "{{ FRONT_ADDRESS }}", "port": 10143, - "secure": 0, + "secure": 2, "shortLogin": false, "ssl": { "verify_peer": false, @@ -17,7 +17,7 @@ "SMTP": { "host": "{{ FRONT_ADDRESS }}", "port": 10025, - "secure": 0, + "secure": 2, "shortLogin": false, "ssl": { "verify_peer": false,