Gitweb:
https://git.exim.org/exim.git/commitdiff/afaf5a50b05810d75c1f7ae9d1cd83697815a997
Commit: afaf5a50b05810d75c1f7ae9d1cd83697815a997
Parent: fd3b39c16b3040cc7f12dbc3afdfc4e9e6e0807b
Author: Jeremy Harris <jgh146exb@???>
AuthorDate: Thu Jul 23 16:32:29 2020 +0100
Committer: Jeremy Harris <jgh146exb@???>
CommitDate: Fri Jul 24 15:00:57 2020 +0100
OpenSSL: in server, detect TCP RST from client after QUIT under SSL,
and log different message (under new log_selector)
---
doc/doc-txt/experimental-spec.txt | 14 ++++++++++++++
src/src/acl.c | 6 ++++--
src/src/globals.c | 6 ++++--
src/src/globals.h | 1 +
src/src/macros.h | 2 ++
src/src/smtp_in.c | 18 ++++++++++--------
src/src/tls-openssl.c | 15 +++++++++++----
7 files changed, 46 insertions(+), 16 deletions(-)
diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt
index 68366a4..e4a9301 100644
--- a/doc/doc-txt/experimental-spec.txt
+++ b/doc/doc-txt/experimental-spec.txt
@@ -666,6 +666,20 @@ and a whitespace-separated port number must be given.
+
+Logging protocol unusual states
+---------------------------------------------------------------
+An extra log_selector, "protocol_detail" has been added in the default build.
+The name may change in future, hence the Experimenal status.
+
+Currrently the only effect is to enable logging, under OpenSSL,
+of a TCP RST received directly after a QUIT (in server mode).
+
+Outlook is consistently doing this; not waiting for the SMTP response
+to its QUIT, not properly closing the TLS session and not properly closing
+the TCP connection. Previously this resulted is an error from SSL_write
+being logged.
+
--------------------------------------------------------------
End of file
--------------------------------------------------------------
diff --git a/src/src/acl.c b/src/src/acl.c
index 185a39d..934112c 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -1944,7 +1944,8 @@ if (quota)
{
if (!*user_msgptr && *log_msgptr)
*user_msgptr = string_sprintf("Rejected after %s: %s",
- smtp_names[smtp_connection_had[smtp_ch_index-1]], *log_msgptr);
+ smtp_names[smtp_connection_had[SMTP_HBUFF_PREV(smtp_ch_index)]],
+ *log_msgptr);
if (rc == DEFER) f.acl_temp_details = TRUE;
}
}
@@ -4542,7 +4543,8 @@ switch (where)
/* Drop cutthrough conns, and drop heldopen verify conns if
the previous was not DATA */
{
- uschar prev = smtp_connection_had[smtp_ch_index-2];
+ uschar prev =
+ smtp_connection_had[SMTP_HBUFF_PREV(SMTP_HBUFF_PREV(smtp_ch_index))];
BOOL dropverify = !(prev == SCH_DATA || prev == SCH_BDAT);
cancel_cutthrough_connection(dropverify, US"quit or conndrop");
diff --git a/src/src/globals.c b/src/src/globals.c
index 654c39b..a5df06d 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -307,6 +307,7 @@ struct global_flags f =
#endif
.smtp_in_pipelining_advertised = FALSE,
.smtp_in_pipelining_used = FALSE,
+ .smtp_in_quit = FALSE,
.spool_file_wireformat = FALSE,
.submission_mode = FALSE,
.suppress_local_fixups = FALSE,
@@ -1073,6 +1074,7 @@ bit_table log_options[] = { /* must be in alphabetical order,
BIT_TABLE(L, outgoing_port),
BIT_TABLE(L, pid),
BIT_TABLE(L, pipelining),
+ BIT_TABLE(L, protocol_detail),
#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS)
BIT_TABLE(L, proxy),
#endif
@@ -1464,6 +1466,8 @@ uschar *smtp_etrn_command = NULL;
int smtp_max_synprot_errors= 3;
int smtp_max_unknown_commands = 3;
uschar *smtp_notquit_reason = NULL;
+unsigned smtp_peer_options = 0;
+unsigned smtp_peer_options_wrap= 0;
uschar *smtp_ratelimit_hosts = NULL;
uschar *smtp_ratelimit_mail = NULL;
uschar *smtp_ratelimit_rcpt = NULL;
@@ -1479,8 +1483,6 @@ int smtp_rlr_base = 0;
double smtp_rlr_factor = 0.0;
int smtp_rlr_limit = 0;
int smtp_rlr_threshold = INT_MAX;
-unsigned smtp_peer_options = 0;
-unsigned smtp_peer_options_wrap= 0;
#ifdef SUPPORT_I18N
uschar *smtputf8_advertise_hosts = US"*"; /* overridden under test-harness */
#endif
diff --git a/src/src/globals.h b/src/src/globals.h
index 0c85c11..ea32695 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -269,6 +269,7 @@ extern struct global_flags {
#endif
BOOL smtp_in_pipelining_advertised :1; /* server advertised PIPELINING */
BOOL smtp_in_pipelining_used :1; /* server noted client using PIPELINING */
+ BOOL smtp_in_quit :1; /* server noted QUIT command */
BOOL spool_file_wireformat :1; /* current -D file has CRLF rather than NL */
BOOL submission_mode :1; /* Can be forced from ACL */
BOOL suppress_local_fixups :1; /* Can be forced from ACL */
diff --git a/src/src/macros.h b/src/src/macros.h
index b5221c7..4c5279f 100644
--- a/src/src/macros.h
+++ b/src/src/macros.h
@@ -148,6 +148,7 @@ enough to hold all the headers from a normal kind of message. */
/* The size of the circular buffer that remembers recent SMTP commands */
#define SMTP_HBUFF_SIZE 20
+#define SMTP_HBUFF_PREV(n) ((n) ? (n)-1 : SMTP_HBUFF_SIZE-1)
/* The initial size of a big buffer for use in various places. It gets put
into big_buffer_size and in some circumstances increased. It should be at least
@@ -480,6 +481,7 @@ enum logbit {
Li_outgoing_port,
Li_pid,
Li_pipelining,
+ Li_protocol_detail,
Li_proxy,
Li_queue_time,
Li_queue_time_overall,
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index ef3964f..3325d54 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -1733,6 +1733,7 @@ for (;;) switch(smtp_read_command(FALSE, GETC_BUFFER_UNLIMITED))
return;
case QUIT_CMD:
+ f.smtp_in_quit = TRUE;
smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
mac_smtp_fflush();
return;
@@ -2349,8 +2350,9 @@ while (done <= 0)
break;
- case EOF_CMD:
case QUIT_CMD:
+ f.smtp_in_quit = TRUE;
+ case EOF_CMD:
done = 2;
break;
@@ -3835,14 +3837,13 @@ static void
smtp_quit_handler(uschar ** user_msgp, uschar ** log_msgp)
{
HAD(SCH_QUIT);
+f.smtp_in_quit = TRUE;
incomplete_transaction_log(US"QUIT");
-if (acl_smtp_quit)
- {
- int rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, user_msgp, log_msgp);
- if (rc == ERROR)
+if ( acl_smtp_quit
+ && acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, user_msgp, log_msgp)
+ == ERROR)
log_write(0, LOG_MAIN|LOG_PANIC, "ACL for QUIT returned ERROR: %s",
*log_msgp);
- }
#ifdef TCP_CORK
(void) setsockopt(fileno(smtp_out), IPPROTO_TCP, TCP_CORK, US &on, sizeof(on));
@@ -5284,10 +5285,10 @@ while (done <= 0)
}
if (f.smtp_in_pipelining_advertised && last_was_rcpt)
smtp_printf("503 Valid RCPT command must precede %s\r\n", FALSE,
- smtp_names[smtp_connection_had[smtp_ch_index-1]]);
+ smtp_names[smtp_connection_had[SMTP_HBUFF_PREV(smtp_ch_index)]]);
else
done = synprot_error(L_smtp_protocol_error, 503, NULL,
- smtp_connection_had[smtp_ch_index-1] == SCH_DATA
+ smtp_connection_had[SMTP_HBUFF_PREV(smtp_ch_index)] == SCH_DATA
? US"valid RCPT command must precede DATA"
: US"valid RCPT command must precede BDAT");
@@ -5551,6 +5552,7 @@ while (done <= 0)
some sense is perhaps "right". */
case QUIT_CMD:
+ f.smtp_in_quit = TRUE;
user_msg = NULL;
if ( acl_smtp_quit
&& ((rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, &user_msg,
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index 50384cb..64f60b7 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -3673,7 +3673,7 @@ context for the stashed information. */
a store reset there, so use POOL_PERM. */
/* + if CHUNKING, cmds EHLO,MAIL,RCPT(s),BDAT */
-if ((more || corked))
+if (more || corked)
{
if (!len) buff = US &error; /* dummy just so that string_catn is ok */
@@ -3722,9 +3722,16 @@ for (int left = len; left > 0;)
return -1;
case SSL_ERROR_SYSCALL:
- log_write(0, LOG_MAIN, "SSL_write: (from %s) syscall: %s",
- sender_fullhost ? sender_fullhost : US"<unknown>",
- strerror(errno));
+ if (ct_ctx || errno != ECONNRESET || !f.smtp_in_quit)
+ log_write(0, LOG_MAIN, "SSL_write: (from %s) syscall: %s",
+ sender_fullhost ? sender_fullhost : US"<unknown>",
+ strerror(errno));
+ else if (LOGGING(protocol_detail))
+ log_write(0, LOG_MAIN, "[%s] after QUIT, client reset TCP before"
+ " SMTP response and TLS close\n", sender_host_address);
+ else
+ DEBUG(D_tls) debug_printf("[%s] SSL_write: after QUIT,"
+ " client reset TCP before TLS close\n", sender_host_address);
return -1;
default: