/* forward declarations */
-int bdat_ungetc(int ch);
static int smtp_read_command(BOOL check_sync, unsigned buffer_lim);
static int synprot_error(int type, int code, uschar *data, uschar *errmess);
static void smtp_quit_handler(uschar **, uschar **);
for(;;)
{
+#ifndef DISABLE_DKIM
+ BOOL dkim_save;
+#endif
+
if (chunking_data_left > 0)
return lwr_receive_getc(chunking_data_left--);
receive_getc = lwr_receive_getc;
receive_ungetc = lwr_receive_ungetc;
#ifndef DISABLE_DKIM
+ dkim_save = dkim_collect_input;
dkim_collect_input = FALSE;
#endif
receive_getc = bdat_getc;
receive_ungetc = bdat_ungetc;
#ifndef DISABLE_DKIM
- dkim_collect_input = TRUE;
+ dkim_collect_input = dkim_save;
#endif
break; /* to top of main loop */
}
static int
swallow_until_crlf(int fd, uschar *base, int already, int capacity)
{
- uschar *to = base + already;
- uschar *cr;
- int have = 0;
- int ret;
- int last = 0;
-
- /* For "PROXY UNKNOWN\r\n" we, at time of writing, expect to have read
- up through the \r; for the _normal_ case, we haven't yet seen the \r. */
- cr = memchr(base, '\r', already);
- if (cr != NULL)
- {
- if ((cr - base) < already - 1)
- {
- /* \r and presumed \n already within what we have; probably not
- actually proxy protocol, but abort cleanly. */
- return 0;
- }
- /* \r is last character read, just need one more. */
- last = 1;
- }
+uschar *to = base + already;
+uschar *cr;
+int have = 0;
+int ret;
+int last = 0;
- while (capacity > 0)
+/* For "PROXY UNKNOWN\r\n" we, at time of writing, expect to have read
+up through the \r; for the _normal_ case, we haven't yet seen the \r. */
+
+cr = memchr(base, '\r', already);
+if (cr != NULL)
+ {
+ if ((cr - base) < already - 1)
{
- do { ret = recv(fd, to, 1, 0); } while (ret == -1 && errno == EINTR);
- if (ret == -1)
- return -1;
- have++;
- if (last)
- return have;
- if (*to == '\r')
- last = 1;
- capacity--;
- to++;
+ /* \r and presumed \n already within what we have; probably not
+ actually proxy protocol, but abort cleanly. */
+ return 0;
}
- // reached end without having room for a final newline, abort
- errno = EOVERFLOW;
- return -1;
+ /* \r is last character read, just need one more. */
+ last = 1;
+ }
+
+while (capacity > 0)
+ {
+ do { ret = recv(fd, to, 1, 0); } while (ret == -1 && errno == EINTR);
+ if (ret == -1)
+ return -1;
+ have++;
+ if (last)
+ return have;
+ if (*to == '\r')
+ last = 1;
+ capacity--;
+ to++;
+ }
+
+/* reached end without having room for a final newline, abort */
+errno = EOVERFLOW;
+return -1;
}
/*************************************************
do
{
/* The inbound host was declared to be a Proxy Protocol host, so
- don't do a PEEK into the data, actually slurp up enough to be
- "safe". Can't take it all because TLS-on-connect clients follow
- immediately with TLS handshake. */
+ don't do a PEEK into the data, actually slurp up enough to be
+ "safe". Can't take it all because TLS-on-connect clients follow
+ immediately with TLS handshake. */
ret = recv(fd, &hdr, PROXY_INITIAL_READ, 0);
}
while (ret == -1 && errno == EINTR);
ver = (hdr.v2.ver_cmd & 0xf0) >> 4;
/* May 2014: haproxy combined the version and command into one byte to
- allow two full bytes for the length field in order to proxy SSL
- connections. SSL Proxy is not supported in this version of Exim, but
- must still separate values here. */
+ allow two full bytes for the length field in order to proxy SSL
+ connections. SSL Proxy is not supported in this version of Exim, but
+ must still separate values here. */
if (ver != 0x02)
{
DEBUG(D_receive) debug_printf("Detected PROXYv1 header\n");
DEBUG(D_receive) debug_printf("Bytes read not within PROXY header: %d\n", ret - size);
/* Step through the string looking for the required fields. Ensure
- strict adherence to required formatting, exit for any error. */
+ strict adherence to required formatting, exit for any error. */
p += 5;
if (!isspace(*(p++)))
{
static void
smtp_reset(void *reset_point)
{
-store_reset(reset_point);
recipients_list = NULL;
rcpt_count = rcpt_defer_count = rcpt_fail_count =
raw_recipients_count = recipients_count = recipients_list_max = 0;
-cancel_cutthrough_connection("smtp reset");
message_linecount = 0;
message_size = -1;
acl_added_headers = NULL;
suppress_local_fixups = suppress_local_fixups_default; /* Can be set by ACL */
active_local_from_check = local_from_check; /* Can be set by ACL */
active_local_sender_retain = local_sender_retain; /* Can be set by ACL */
-sender_address = NULL;
+sending_ip_address = NULL;
+return_path = sender_address = NULL;
+sender_data = NULL; /* Can be set by ACL */
+deliver_localpart_orig = NULL;
+deliver_domain_orig = NULL;
+callout_address = NULL;
submission_name = NULL; /* Can be set by ACL */
raw_sender = NULL; /* After SMTP rewrite, before qualifying */
sender_address_unrewritten = NULL; /* Set only after verify rewrite */
bmi_run = 0;
bmi_verdicts = NULL;
#endif
+dnslist_domain = dnslist_matched = NULL;
#ifndef DISABLE_DKIM
dkim_signers = NULL;
dkim_disable_verify = FALSE;
#endif
dsn_ret = 0;
dsn_envid = NULL;
+deliver_host = deliver_host_address = NULL; /* Can be set by ACL */
#ifndef DISABLE_PRDR
prdr_requested = FALSE;
#endif
not the first message in an SMTP session and the previous message caused them
to be referenced in an ACL. */
-if (message_body != NULL)
+if (message_body)
{
store_free(message_body);
message_body = NULL;
}
-if (message_body_end != NULL)
+if (message_body_end)
{
store_free(message_body_end);
message_body_end = NULL;
repetition in the same message, but it seems right to repeat them for different
messages. */
-while (acl_warn_logged != NULL)
+while (acl_warn_logged)
{
string_item *this = acl_warn_logged;
acl_warn_logged = acl_warn_logged->next;
store_free(this);
}
+store_reset(reset_point);
}
if ((receive_feof)()) return 0; /* Treat EOF as QUIT */
+cancel_cutthrough_connection(TRUE, US"smtp_setup_batch_msg");
smtp_reset(reset_point); /* Reset for start of message */
/* Deal with SMTP commands. This loop is exited by setting done to a POSITIVE
/* Fall through */
case RSET_CMD:
+ cancel_cutthrough_connection(TRUE, US"RSET received");
smtp_reset(reset_point);
bsmtp_transaction_linecount = receive_linecount;
break;
/* Reset to start of message */
+ cancel_cutthrough_connection(TRUE, US"MAIL received");
smtp_reset(reset_point);
/* Apply SMTP rewrite */
+static BOOL
+smtp_log_tls_fail(uschar * errstr)
+{
+uschar * conn_info = smtp_get_connection_info();
+
+if (Ustrncmp(conn_info, US"SMTP ", 5) == 0) conn_info += 5;
+/* I'd like to get separated H= here, but too hard for now */
+
+log_write(0, LOG_MAIN, "TLS error on %s %s", conn_info, errstr);
+return FALSE;
+}
+
+
/*************************************************
* Start an SMTP session *
*************************************************/
smtps port for use with older style SSL MTAs. */
#ifdef SUPPORT_TLS
- if (tls_in.on_connect && tls_server_start(tls_require_ciphers) != OK)
- return FALSE;
+ if (tls_in.on_connect && tls_server_start(tls_require_ciphers, &user_msg) != OK)
+ return smtp_log_tls_fail(user_msg);
#endif
/* Run the connect ACL if it exists */
: pnormal)
+ (tls_in.active >= 0 ? pcrpted : 0)
];
+ cancel_cutthrough_connection(TRUE, US"sent EHLO response");
smtp_reset(reset_point);
toomany = FALSE;
break; /* HELO/EHLO */
/* Reset for start of message - even if this is going to fail, we
obviously need to throw away any previous data. */
+ cancel_cutthrough_connection(TRUE, US"MAIL received");
smtp_reset(reset_point);
toomany = FALSE;
sender_data = recipient_data = NULL;
case ENV_MAIL_OPT_UTF8:
if (smtputf8_advertised)
{
+ int old_pool = store_pool;
+
DEBUG(D_receive) debug_printf("smtputf8 requested\n");
message_smtputf8 = allow_utf8_domains = TRUE;
+ store_pool = POOL_PERM;
received_protocol = string_sprintf("utf8%s", received_protocol);
+ store_pool = old_pool;
}
break;
#endif
do an implied RSET when STARTTLS is received. */
incomplete_transaction_log(US"STARTTLS");
+ cancel_cutthrough_connection(TRUE, US"STARTTLS received");
smtp_reset(reset_point);
toomany = FALSE;
cmd_list[CMD_LIST_STARTTLS].is_mail_cmd = FALSE;
We must allow for an extra EHLO command and an extra AUTH command after
STARTTLS that don't add to the nonmail command count. */
- if ((rc = tls_server_start(tls_require_ciphers)) == OK)
+ s = NULL;
+ if ((rc = tls_server_start(tls_require_ciphers, &s)) == OK)
{
if (!tls_remember_esmtp)
helo_seen = esmtp = auth_advertised = pipelining_advertised = FALSE;
DEBUG(D_tls) debug_printf("TLS active\n");
break; /* Successful STARTTLS */
}
+ else
+ (void) smtp_log_tls_fail(s);
/* Some local configuration problem was discovered before actually trying
to do a TLS handshake; give a temporary error. */
- else if (rc == DEFER)
+ if (rc == DEFER)
{
smtp_printf("454 TLS currently unavailable\r\n");
break;
case RSET_CMD:
smtp_rset_handler();
+ cancel_cutthrough_connection(TRUE, US"RSET received");
smtp_reset(reset_point);
toomany = FALSE;
break;