/* Copyright (c) The Exim Maintainers 2020 - 2022 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Functions for handling an incoming SMTP call. */
}
bdat_pop_receive_functions();
-
-if (chunking_state != CHUNKING_LAST)
- {
- chunking_state = CHUNKING_OFFERED;
- DEBUG(D_receive) debug_printf("chunking state %d\n", (int)chunking_state);
- }
+chunking_state = CHUNKING_OFFERED;
+DEBUG(D_receive) debug_printf("chunking state %d\n", (int)chunking_state);
}
if (fl.rcpt_in_progress)
{
- if (rcpt_smtp_response == NULL)
+ if (!rcpt_smtp_response)
rcpt_smtp_response = string_copy(big_buffer);
else if (fl.rcpt_smtp_response_same &&
Ustrcmp(rcpt_smtp_response, big_buffer) != 0)
*/
void
-smtp_closedown(uschar *message)
+smtp_closedown(uschar * message)
{
if (!smtp_in || smtp_batched_input) return;
receive_swallow_smtp();
#ifdef SUPPORT_I18N
message_smtputf8 = FALSE;
#endif
+#ifdef WITH_CONTENT_SCAN
+regex_vars_clear();
+#endif
body_linecount = body_zerocount = 0;
+lookup_value = NULL; /* Can be set by ACL */
sender_rate = sender_rate_limit = sender_rate_period = NULL;
ratelimiters_mail = NULL; /* Updated by ratelimit ACL condition */
/* Note that ratelimiters_conn persists across resets. */
#endif
+static void
+log_connect_tls_drop(const uschar * what, const uschar * log_msg)
+{
+gstring * g = s_tlslog(NULL);
+uschar * tls = string_from_gstring(g);
+
+log_write(L_connection_reject,
+ log_reject_target, "%s%s%s dropped by %s%s%s",
+ LOGGING(dnssec) && sender_host_dnssec ? US" DS" : US"",
+ host_and_ident(TRUE),
+ tls ? tls : US"",
+ what,
+ log_msg ? US": " : US"", log_msg);
+}
+
+
/*************************************************
* Start an SMTP session *
*************************************************/
#if !HAVE_IPV6 && !defined(NO_IP_OPTIONS)
- #ifdef GLIBC_IP_OPTIONS
- #if (!defined __GLIBC__) || (__GLIBC__ < 2)
- #define OPTSTYLE 1
- #else
- #define OPTSTYLE 2
- #endif
- #elif defined DARWIN_IP_OPTIONS
- #define OPTSTYLE 2
- #else
- #define OPTSTYLE 3
- #endif
+# ifdef GLIBC_IP_OPTIONS
+# if (!defined __GLIBC__) || (__GLIBC__ < 2)
+# define OPTSTYLE 1
+# else
+# define OPTSTYLE 2
+# endif
+# elif defined DARWIN_IP_OPTIONS
+# define OPTSTYLE 2
+# else
+# define OPTSTYLE 3
+# endif
if (!host_checking && !f.sender_host_notsocket)
{
- #if OPTSTYLE == 1
+# if OPTSTYLE == 1
EXIM_SOCKLEN_T optlen = sizeof(struct ip_options) + MAX_IPOPTLEN;
struct ip_options *ipopt = store_get(optlen, GET_UNTAINTED);
- #elif OPTSTYLE == 2
+# elif OPTSTYLE == 2
struct ip_opts ipoptblock;
struct ip_opts *ipopt = &ipoptblock;
EXIM_SOCKLEN_T optlen = sizeof(ipoptblock);
- #else
+# else
struct ipoption ipoptblock;
struct ipoption *ipopt = &ipoptblock;
EXIM_SOCKLEN_T optlen = sizeof(ipoptblock);
- #endif
+# endif
/* Occasional genuine failures of getsockopt() have been seen - for
example, "reset by peer". Therefore, just log and give up on this
else if (optlen > 0)
{
- uschar *p = big_buffer;
- uschar *pend = big_buffer + big_buffer_size;
- uschar *adptr;
+ uschar * p = big_buffer;
+ uschar * pend = big_buffer + big_buffer_size;
+ uschar * adptr;
int optcount;
struct in_addr addr;
- #if OPTSTYLE == 1
- uschar *optstart = US (ipopt->__data);
- #elif OPTSTYLE == 2
- uschar *optstart = US (ipopt->ip_opts);
- #else
- uschar *optstart = US (ipopt->ipopt_list);
- #endif
+# if OPTSTYLE == 1
+ uschar * optstart = US (ipopt->__data);
+# elif OPTSTYLE == 2
+ uschar * optstart = US (ipopt->ip_opts);
+# else
+ uschar * optstart = US (ipopt->ipopt_list);
+# endif
DEBUG(D_receive) debug_printf("IP options exist\n");
switch (*opt)
{
case IPOPT_EOL:
- opt = NULL;
- break;
+ opt = NULL;
+ break;
case IPOPT_NOP:
- opt++;
- break;
+ opt++;
+ break;
case IPOPT_SSRR:
case IPOPT_LSRR:
- if (!string_format(p, pend-p, " %s [@%s",
- (*opt == IPOPT_SSRR)? "SSRR" : "LSRR",
- #if OPTSTYLE == 1
- inet_ntoa(*((struct in_addr *)(&(ipopt->faddr))))))
- #elif OPTSTYLE == 2
- inet_ntoa(ipopt->ip_dst)))
- #else
- inet_ntoa(ipopt->ipopt_dst)))
- #endif
- {
- opt = NULL;
- break;
- }
+ if (!
+# if OPTSTYLE == 1
+ string_format(p, pend-p, " %s [@%s",
+ (*opt == IPOPT_SSRR)? "SSRR" : "LSRR",
+ inet_ntoa(*((struct in_addr *)(&(ipopt->faddr)))))
+# elif OPTSTYLE == 2
+ string_format(p, pend-p, " %s [@%s",
+ (*opt == IPOPT_SSRR)? "SSRR" : "LSRR",
+ inet_ntoa(ipopt->ip_dst))
+# else
+ string_format(p, pend-p, " %s [@%s",
+ (*opt == IPOPT_SSRR)? "SSRR" : "LSRR",
+ inet_ntoa(ipopt->ipopt_dst))
+# endif
+ )
+ {
+ opt = NULL;
+ break;
+ }
- p += Ustrlen(p);
- optcount = (opt[1] - 3) / sizeof(struct in_addr);
- adptr = opt + 3;
- while (optcount-- > 0)
- {
- memcpy(&addr, adptr, sizeof(addr));
- if (!string_format(p, pend - p - 1, "%s%s",
- (optcount == 0)? ":" : "@", inet_ntoa(addr)))
- {
- opt = NULL;
- break;
- }
- p += Ustrlen(p);
- adptr += sizeof(struct in_addr);
- }
- *p++ = ']';
- opt += opt[1];
- break;
+ p += Ustrlen(p);
+ optcount = (opt[1] - 3) / sizeof(struct in_addr);
+ adptr = opt + 3;
+ while (optcount-- > 0)
+ {
+ memcpy(&addr, adptr, sizeof(addr));
+ if (!string_format(p, pend - p - 1, "%s%s",
+ (optcount == 0)? ":" : "@", inet_ntoa(addr)))
+ {
+ opt = NULL;
+ break;
+ }
+ p += Ustrlen(p);
+ adptr += sizeof(struct in_addr);
+ }
+ *p++ = ']';
+ opt += opt[1];
+ break;
default:
- {
- if (pend - p < 4 + 3*opt[1]) { opt = NULL; break; }
- Ustrcat(p, "[ ");
- p += 2;
- for (int i = 0; i < opt[1]; i++)
- p += sprintf(CS p, "%2.2x ", opt[i]);
- *p++ = ']';
- }
- opt += opt[1];
- break;
+ {
+ if (pend - p < 4 + 3*opt[1]) { opt = NULL; break; }
+ Ustrcat(p, "[ ");
+ p += 2;
+ for (int i = 0; i < opt[1]; i++)
+ p += sprintf(CS p, "%2.2x ", opt[i]);
+ *p++ = ']';
+ }
+ opt += opt[1];
+ break;
}
*p = 0;
{
log_write(L_connection_reject, LOG_MAIN|LOG_REJECT, "refused connection "
"from %s (host_reject_connection)", host_and_ident(FALSE));
- smtp_printf("554 SMTP service not available\r\n", FALSE);
+#ifndef DISABLE_TLS
+ if (!tls_in.on_connect)
+#endif
+ smtp_printf("554 SMTP service not available\r\n", FALSE);
return FALSE;
}
setup_proxy_protocol_host();
#endif
-/* Start up TLS if tls_on_connect is set. This is for supporting the legacy
-smtps port for use with older style SSL MTAs. */
-
-#ifndef DISABLE_TLS
-if (tls_in.on_connect)
- {
- if (tls_server_start(&user_msg) != OK)
- return smtp_log_tls_fail(user_msg);
- cmd_list[CMD_LIST_TLS_AUTH].is_mail_cmd = TRUE;
- }
-#endif
-
/* Run the connect ACL if it exists */
user_msg = NULL;
if ((rc = acl_check(ACL_WHERE_CONNECT, NULL, acl_smtp_connect, &user_msg,
&log_msg)) != OK)
{
- (void) smtp_handle_acl_fail(ACL_WHERE_CONNECT, rc, user_msg, log_msg);
+#ifndef DISABLE_TLS
+ if (tls_in.on_connect)
+ log_connect_tls_drop(US"'connect' ACL", log_msg);
+ else
+#endif
+ (void) smtp_handle_acl_fail(ACL_WHERE_CONNECT, rc, user_msg, log_msg);
return FALSE;
}
}
+/* Start up TLS if tls_on_connect is set. This is for supporting the legacy
+smtps port for use with older style SSL MTAs. */
+
+#ifndef DISABLE_TLS
+if (tls_in.on_connect)
+ {
+ if (tls_server_start(&user_msg) != OK)
+ return smtp_log_tls_fail(user_msg);
+ cmd_list[CMD_LIST_TLS_AUTH].is_mail_cmd = TRUE;
+ }
+#endif
+
/* Output the initial message for a two-way SMTP connection. It may contain
newlines, which then cause a multi-line response to be given. */
esc = US""; /* Default extended status code */
esclen = 0; /* Length of esc */
-if (!user_msg)
- {
- if (!(s = expand_string(smtp_banner)))
- log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Expansion of \"%s\" (smtp_banner) "
- "failed: %s", smtp_banner, expand_string_message);
- }
-else
+if (user_msg)
{
int codelen = 3;
s = user_msg;
esclen = codelen - 4;
}
}
+else if (!(s = expand_string(smtp_banner)))
+ {
+ log_write(0, f.expand_string_forcedfail ? LOG_MAIN : LOG_MAIN|LOG_PANIC_DIE,
+ "Expansion of \"%s\" (smtp_banner) failed: %s",
+ smtp_banner, expand_string_message);
+ /* for force-fail */
+#ifndef DISABLE_TLS
+ if (tls_in.on_connect) tls_close(NULL, TLS_SHUTDOWN_WAIT);
+#endif
+ return FALSE;
+ }
/* Remove any terminating newlines; might as well remove trailing space too */
static int
-smtp_in_auth(auth_instance *au, uschar ** s, uschar ** ss)
+smtp_in_auth(auth_instance *au, uschar ** smtp_resp, uschar ** errmsg)
{
const uschar *set_id = NULL;
int rc;
received_protocol =
(sender_host_address ? protocols : protocols_local)
[pextend + pauthed + (tls_in.active.sock >= 0 ? pcrpted:0)];
- *s = *ss = US"235 Authentication succeeded";
+ *smtp_resp = *errmsg = US"235 Authentication succeeded";
authenticated_by = au;
break;
}
case DEFER:
if (set_id) authenticated_fail_id = string_copy_perm(set_id, TRUE);
- *s = string_sprintf("435 Unable to authenticate at present%s",
+ *smtp_resp = string_sprintf("435 Unable to authenticate at present%s",
auth_defer_user_msg);
- *ss = string_sprintf("435 Unable to authenticate at present%s: %s",
+ *errmsg = string_sprintf("435 Unable to authenticate at present%s: %s",
set_id, auth_defer_msg);
break;
case BAD64:
- *s = *ss = US"501 Invalid base64 data";
+ *smtp_resp = *errmsg = US"501 Invalid base64 data";
break;
case CANCELLED:
- *s = *ss = US"501 Authentication cancelled";
+ *smtp_resp = *errmsg = US"501 Authentication cancelled";
break;
case UNEXPECTED:
- *s = *ss = US"553 Initial data not expected";
+ *smtp_resp = *errmsg = US"553 Initial data not expected";
break;
case FAIL:
if (set_id) authenticated_fail_id = string_copy_perm(set_id, TRUE);
- *s = US"535 Incorrect authentication data";
- *ss = string_sprintf("535 Incorrect authentication data%s", set_id);
+ *smtp_resp = US"535 Incorrect authentication data";
+ *errmsg = string_sprintf("535 Incorrect authentication data%s", set_id);
break;
default:
if (set_id) authenticated_fail_id = string_copy_perm(set_id, TRUE);
- *s = US"435 Internal error";
- *ss = string_sprintf("435 Internal error%s: return %d from authentication "
+ *smtp_resp = US"435 Internal error";
+ *errmsg = string_sprintf("435 Internal error%s: return %d from authentication "
"check", set_id, rc);
break;
}
incomplete_transaction_log(US"RSET");
smtp_printf("250 Reset OK\r\n", FALSE);
cmd_list[CMD_LIST_RSET].is_mail_cmd = FALSE;
+if (chunking_state > CHUNKING_OFFERED)
+ chunking_state = CHUNKING_OFFERED;
}
if (smtp_in_auth(au, &s, &ss) == OK)
{ DEBUG(D_auth) debug_printf("tls auth succeeded\n"); }
else
- { DEBUG(D_auth) debug_printf("tls auth not succeeded\n"); }
+ {
+ DEBUG(D_auth) debug_printf("tls auth not succeeded\n");
+#ifndef DISABLE_EVENT
+ {
+ uschar * save_name = sender_host_authenticated, * logmsg;
+ sender_host_authenticated = au->name;
+ if ((logmsg = event_raise(event_action, US"auth:fail", s, NULL)))
+ log_write(0, LOG_MAIN, "%s", logmsg);
+ sender_host_authenticated = save_name;
+ }
+#endif
+ }
}
break;
}
{
auth_instance * au;
+ uschar * smtp_resp, * errmsg;
+
for (au = auths; au; au = au->next)
if (strcmpic(s, au->public_name) == 0 && au->server &&
(au->advertised || f.allow_auth_unadvertised))
if (au)
{
- c = smtp_in_auth(au, &s, &ss);
+ int rc = smtp_in_auth(au, &smtp_resp, &errmsg);
- smtp_printf("%s\r\n", FALSE, s);
- if (c != OK)
- log_write(0, LOG_MAIN|LOG_REJECT, "%s authenticator failed for %s: %s",
- au->name, host_and_ident(FALSE), ss);
+ smtp_printf("%s\r\n", FALSE, smtp_resp);
+ if (rc != OK)
+ {
+ uschar * logmsg = NULL;
+#ifndef DISABLE_EVENT
+ {uschar * save_name = sender_host_authenticated;
+ sender_host_authenticated = au->name;
+ logmsg = event_raise(event_action, US"auth:fail", smtp_resp, NULL);
+ sender_host_authenticated = save_name;
+ }
+#endif
+ if (logmsg)
+ log_write(0, LOG_MAIN|LOG_REJECT, "%s", logmsg);
+ else
+ log_write(0, LOG_MAIN|LOG_REJECT, "%s authenticator failed for %s: %s",
+ au->name, host_and_ident(FALSE), errmsg);
+ }
}
else
done = synprot_error(L_smtp_protocol_error, 504, NULL,
else
{
- char *ss;
+ char * ss;
int codelen = 4;
smtp_message_code(&smtp_code, &codelen, &user_msg, NULL, TRUE);
s = string_sprintf("%.*s%s", codelen, smtp_code, user_msg);
count this as a protocol error. Reset was_rej_mail so that further RCPTs
get the same treatment. */
- if (sender_address == NULL)
+ if (!sender_address)
{
if (f.smtp_in_pipelining_advertised && last_was_rej_mail)
{
/* Check for an operand */
- if (smtp_cmd_data[0] == 0)
+ if (!smtp_cmd_data[0])
{
done = synprot_error(L_smtp_syntax_error, 501, NULL,
US"RCPT must have an address operand");
#endif
if (!discarded && recipients_count <= 0)
{
- if (fl.rcpt_smtp_response_same && rcpt_smtp_response != NULL)
+ if (fl.rcpt_smtp_response_same && rcpt_smtp_response)
{
uschar *code = US"503";
int len = Ustrlen(rcpt_smtp_response);
COMMAND_LOOP:
last_was_rej_mail = was_rej_mail; /* Remember some last commands for */
last_was_rcpt = was_rcpt; /* protocol error handling */
- continue;
}
return done - 2; /* Convert yield values */