From ff1e0ece50986156e0b6f5f37985833ed0ae6c97 Mon Sep 17 00:00:00 2001 From: manuel Date: Tue, 26 Sep 2023 14:11:58 +0200 Subject: Add support for "require TLS"-settings --- qmail-remote.c | 48 ++++++++++++++++++++++++++++++++++++++---------- qmail-smtpd.c | 21 ++++++++++++++++++--- 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/qmail-remote.c b/qmail-remote.c index 125d813..a743e06 100644 --- a/qmail-remote.c +++ b/qmail-remote.c @@ -9,6 +9,7 @@ #include "substdio.h" #include "subfd.h" #include "scan.h" +#include "byte.h" #include "case.h" #include "error.h" #include "auto_qmail.h" @@ -401,6 +402,7 @@ static int tls_init(struct ip_mx *current_mx) stralloc saciphers = {0}; const char *ciphers, *servercert = 0; const char *mx_host = current_mx->fqdn; + const char *failure_class = "Z"; // per default we do temp failures if (mx_host) { struct stat st; @@ -425,10 +427,26 @@ static int tls_init(struct ip_mx *current_mx) } } - /* DANE: lookup TLSA records */ int tls_required = (smtps || servercert != NULL); - stralloc tlsa_rr = { 0 }; + /* per-domain "require TLS"-settings */ + if (!tls_required) { + int at = byte_rchr(sender.s, sender.len, '@') + 1; + if (at < sender.len) { + stralloc tmp = { 0 }; + if (!stralloc_copys(&tmp, "control/tlsrequire/") + || !stralloc_catb(&tmp, sender.s + at, sender.len - at) + || !stralloc_0(&tmp)) // sender is not 0-terminated + temp_nomem(); + if (control_readint(&tls_required, tmp.s) == -1) temp_control(); + tls_required = (tls_required & 0x02) ? 1 : 0; // 2nd bit is SMTP outgoing + if (tls_required) + failure_class = "D"; // do perm failures for faster user feedback + } + } + + /* DANE: lookup TLSA records */ + stralloc tlsa_rr = { 0 }; if (mx_host && !servercert && current_mx->validated) { stralloc tlsa_label = { 0 }; char port[FMT_ULONG]; @@ -456,8 +474,10 @@ static int tls_init(struct ip_mx *current_mx) for ( ; len && case_diffs(sa->s, "STARTTLS"); ++sa, --len) ; if (!len) { if (!tls_required) return 0; - out("ZNo TLS achieved while TLS is required by configuration"); - smtptext.len = 0; TLS_QUIT; + out(failure_class); + out("TLS is required, but was not offered by host"); + smtptext.len = 0; + TLS_QUIT; } } @@ -615,10 +635,12 @@ static int tls_init(struct ip_mx *current_mx) /* read the responce to STARTTLS */ if (!smtps) { - if (smtpcode() != 220) { + unsigned int code = smtpcode(); + if (code != 220) { SSL_free(myssl); if (!tls_required) return 0; - out("ZSTARTTLS rejected while TLS is required by configuration"); + out((code >= 500) ? "D" : failure_class); + out("TLS is required, but host refused to start TLS"); TLS_QUIT; } smtptext.len = 0; @@ -626,8 +648,10 @@ static int tls_init(struct ip_mx *current_mx) ssl = myssl; if (ssl_timeoutconn(timeout, smtpfd, smtpfd, myssl) <= 0) { - if (tls_required) - tls_quit("ZTLS connect failed", ssl_error_str()); + if (tls_required) { + out(failure_class); + tls_quit("TLS connect failed", ssl_error_str()); + } else { out("lTLS connect failed"); const char *err = ssl_error_str(); @@ -707,8 +731,12 @@ static int tls_init(struct ip_mx *current_mx) } } - if (smtps) if (smtpcode() != 220) - quit("ZTLS Connected to "," but greeting failed"); + if (smtps) { + unsigned int code = smtpcode(); + if (code >= 500 && code < 600) quit("DTLS connected to "," but greeting failed"); + if (code >= 400 && code < 500) return -1; /* try next MX, see RFC-2821 */ + if (code != 220) quit("ZTLS connected to "," but greeting failed"); + } return 1; } diff --git a/qmail-smtpd.c b/qmail-smtpd.c index 48a66b1..d0395fc 100644 --- a/qmail-smtpd.c +++ b/qmail-smtpd.c @@ -78,7 +78,7 @@ void tls_nogateway(); int ssl_rfd = -1, ssl_wfd = -1; /* SSL_get_Xfd() are broken */ stralloc proto = {0}; int tls_before_auth = 0; -int tls_require = 0; +int tls_required = 0; #endif #ifdef SMTPUTF8 @@ -344,7 +344,7 @@ void setup() #ifdef TLS if (env_get("TLSBEFOREAUTH")) tls_before_auth = 1; - if (env_get("TLSREQUIRE")) tls_require = 1; + if (env_get("TLSREQUIRE")) tls_required = 1; if (env_get("SMTPS")) { smtps = 1; tls_init(); } else #endif @@ -722,7 +722,7 @@ void smtp_mail(arg) char *arg; { if (!seenhelo) { err_wanthelo(); return; } #if defined(TLS) - if (tls_require && !ssl) { err_wantstarttls(); return; } + if (tls_required && !ssl) { err_wantstarttls(); return; } #endif if (!addrparse(arg)) { err_syntax(); return; } flagsize = 0; @@ -818,6 +818,21 @@ void smtp_rcpt(arg) char *arg; { return; } } +#if defined(TLS) + /* per-domain "require TLS"-settings */ + if (!tls_required && !relayclient) { + int at = byte_rchr(addr.s, addr.len, '@') + 1; + if (at < addr.len) { + stralloc tmp = { 0 }; + if (!stralloc_copys(&tmp, "control/tlsrequire/") + || !stralloc_catb(&tmp, addr.s + at, addr.len - at)) // addr is 0-terminated + die_nomem(); + if (control_readint(&tls_required, tmp.s) == -1) die_control(); + tls_required = (tls_required & 0x01) ? 1 : 0; // 1st bit is SMTP incoming + if (tls_required && !ssl) { err_wantstarttls(); return; } + } + } +#endif spp_rcpt_accepted(); if (!stralloc_cats(&rcptto,"T")) die_nomem(); if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); -- cgit v1.2.3