* Local static variables *
*************************************************/
-static auth_instance *authenticated_by;
-static BOOL auth_advertised;
+static struct {
+ BOOL auth_advertised :1;
#ifdef SUPPORT_TLS
-static BOOL tls_advertised;
+ BOOL tls_advertised :1;
# ifdef EXPERIMENTAL_REQUIRETLS
-static BOOL requiretls_advertised;
+ BOOL requiretls_advertised :1;
# endif
#endif
-static BOOL dsn_advertised;
-static BOOL esmtp;
-static BOOL helo_required = FALSE;
-static BOOL helo_verify = FALSE;
-static BOOL helo_seen;
-static BOOL helo_accept_junk;
-static BOOL count_nonmail;
-static BOOL rcpt_smtp_response_same;
-static BOOL rcpt_in_progress;
-static int nonmail_command_count;
-static BOOL smtp_exit_function_called = 0;
+ BOOL dsn_advertised :1;
+ BOOL esmtp :1;
+ BOOL helo_required :1;
+ BOOL helo_verify :1;
+ BOOL helo_seen :1;
+ BOOL helo_accept_junk :1;
+ BOOL rcpt_smtp_response_same :1;
+ BOOL rcpt_in_progress :1;
+ BOOL smtp_exit_function_called :1;
#ifdef SUPPORT_I18N
-static BOOL smtputf8_advertised;
+ BOOL smtputf8_advertised :1;
#endif
+} fl = {
+ .helo_required = FALSE,
+ .helo_verify = FALSE,
+ .smtp_exit_function_called = FALSE,
+};
+
+static auth_instance *authenticated_by;
+static int count_nonmail;
+static int nonmail_command_count;
static int synprot_error_count;
static int unknown_command_count;
static int sync_cmd_limit;
static BOOL
check_sync(void)
{
-if (!smtp_enforce_sync || !sender_host_address || sender_host_notsocket)
+if (!smtp_enforce_sync || !sender_host_address || f.sender_host_notsocket)
return TRUE;
return wouldblock_reading();
pipeline_response(void)
{
if ( !smtp_enforce_sync || !sender_host_address
- || sender_host_notsocket || !smtp_in_pipelining_advertised)
+ || f.sender_host_notsocket || !f.smtp_in_pipelining_advertised)
return FALSE;
-return !wouldblock_reading();
+if (wouldblock_reading()) return FALSE;
+f.smtp_in_pipelining_used = TRUE;
+return TRUE;
}
int rc, save_errno;
if (!smtp_out) return FALSE;
fflush(smtp_out);
-if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
+if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
/* Limit amount read, so non-message data is not fed to DKIM.
Take care to not touch the safety NUL at the end of the buffer. */
rc = read(fileno(smtp_in), smtp_inbuffer, MIN(IN_BUFFER_SIZE-1, lim));
save_errno = errno;
-if (smtp_receive_timeout > 0) alarm(0);
+if (smtp_receive_timeout > 0) ALARM_CLR(0);
if (rc <= 0)
{
/* Must put the error text in fixed store, because this might be during
/* Unless PIPELINING was offered, there should be no next command
until after we ack that chunk */
- if (!smtp_in_pipelining_advertised && !check_sync())
+ if (!f.smtp_in_pipelining_advertised && !check_sync())
{
unsigned n = smtp_inend - smtp_inptr;
if (n > 32) n = 32;
do it that way, so as not to have to mess with the code for the RCPT command,
which sometimes uses smtp_printf() and sometimes smtp_respond(). */
-if (rcpt_in_progress)
+if (fl.rcpt_in_progress)
{
if (rcpt_smtp_response == NULL)
rcpt_smtp_response = string_copy(big_buffer);
- else if (rcpt_smtp_response_same &&
+ else if (fl.rcpt_smtp_response_same &&
Ustrcmp(rcpt_smtp_response, big_buffer) != 0)
- rcpt_smtp_response_same = FALSE;
- rcpt_in_progress = FALSE;
+ fl.rcpt_smtp_response_same = FALSE;
+ fl.rcpt_in_progress = FALSE;
}
/* Now write the string */
}
else
{
- proxy_session_failed = TRUE;
+ f.proxy_session_failed = TRUE;
DEBUG(D_receive)
debug_printf("Failure to extract proxied host, only QUIT allowed\n");
}
{
#ifdef SUPPORT_PROXY
/* Only allow QUIT command if Proxy Protocol parsing failed */
- if (proxy_session && proxy_session_failed && p->cmd != QUIT_CMD)
+ if (proxy_session && f.proxy_session_failed && p->cmd != QUIT_CMD)
continue;
#endif
if ( p->len
check_sync && /* Local flag set */
smtp_enforce_sync && /* Global flag set */
sender_host_address != NULL && /* Not local input */
- !sender_host_notsocket) /* Really is a socket */
+ !f.sender_host_notsocket) /* Really is a socket */
return BADSYN_CMD;
/* The variables $smtp_command and $smtp_command_argument point into the
#ifdef SUPPORT_PROXY
/* Only allow QUIT command if Proxy Protocol parsing failed */
-if (proxy_session && proxy_session_failed)
+if (proxy_session && f.proxy_session_failed)
return PROXY_FAIL_IGNORE_CMD;
#endif
&& check_sync /* Local flag set */
&& smtp_enforce_sync /* Global flag set */
&& sender_host_address /* Not local input */
- && !sender_host_notsocket) /* Really is a socket */
+ && !f.sender_host_notsocket) /* Really is a socket */
return BADSYN_CMD;
return OTHER_CMD;
if (host_checking)
return string_sprintf("SMTP connection from %s", hostname);
-if (sender_host_unknown || sender_host_notsocket)
+if (f.sender_host_unknown || f.sender_host_notsocket)
return string_sprintf("SMTP connection from %s", sender_ident);
-if (is_inetd)
+if (f.is_inetd)
return string_sprintf("SMTP connection from %s (via inetd)", hostname);
if (LOGGING(incoming_interface) && interface_address != NULL)
if (!(s = string_from_gstring(g))) s = US"";
log_write(0, LOG_MAIN, "no MAIL in %sSMTP connection from %s D=%s%s",
- tcp_in_fastopen ? US"TFO " : US"",
+ f.tcp_in_fastopen ? US"TFO " : US"",
host_and_ident(FALSE), string_timesince(&smtp_connection_start), s);
}
{
uschar *start = s;
uschar *end = s + Ustrlen(s);
-BOOL yield = helo_accept_junk;
+BOOL yield = fl.helo_accept_junk;
/* Discard any previous helo name */
message_size = -1;
acl_added_headers = NULL;
acl_removed_headers = NULL;
-queue_only_policy = FALSE;
+f.queue_only_policy = FALSE;
rcpt_smtp_response = NULL;
-rcpt_smtp_response_same = TRUE;
-rcpt_in_progress = FALSE;
-deliver_freeze = FALSE; /* Can be set by ACL */
+fl.rcpt_smtp_response_same = TRUE;
+fl.rcpt_in_progress = FALSE;
+f.deliver_freeze = FALSE; /* Can be set by ACL */
freeze_tell = freeze_tell_config; /* Can be set by ACL */
fake_response = OK; /* Can be set by ACL */
#ifdef WITH_CONTENT_SCAN
-no_mbox_unspool = FALSE; /* Can be set by ACL */
+f.no_mbox_unspool = FALSE; /* Can be set by ACL */
#endif
-submission_mode = FALSE; /* Can be set by ACL */
-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 */
+f.submission_mode = FALSE; /* Can be set by ACL */
+f.suppress_local_fixups = f.suppress_local_fixups_default; /* Can be set by ACL */
+f.active_local_from_check = local_from_check; /* Can be set by ACL */
+f.active_local_sender_retain = local_sender_retain; /* Can be set by ACL */
sending_ip_address = NULL;
return_path = sender_address = NULL;
sender_data = NULL; /* Can be set by ACL */
dkim_cur_signer = dkim_signers =
dkim_signing_domain = dkim_signing_selector = dkim_signatures = NULL;
dkim_cur_signer = dkim_signers = dkim_signing_domain = dkim_signing_selector = NULL;
-dkim_disable_verify = FALSE;
+f.dkim_disable_verify = FALSE;
dkim_collect_input = 0;
dkim_verify_overall = dkim_verify_status = dkim_verify_reason = NULL;
dkim_key_length = 0;
dkim_verify_signers = US"$dkim_signers";
#endif
#ifdef EXPERIMENTAL_DMARC
-dmarc_has_been_checked = dmarc_disable_verify = dmarc_enable_forensic = FALSE;
+f.dmarc_has_been_checked = f.dmarc_disable_verify = f.dmarc_enable_forensic = FALSE;
dmarc_domain_policy = dmarc_status = dmarc_status_text =
dmarc_used_domain = NULL;
#endif
if ( !sender_domain
&& sender_address[0] != 0 && sender_address[0] != '@')
- if (allow_unqualified_sender)
+ if (f.allow_unqualified_sender)
{
sender_address = rewrite_address_qualify(sender_address, FALSE);
DEBUG(D_receive) debug_printf("unqualified address %s accepted "
add it to the list of recipients. */
if (!recipient_domain)
- if (allow_unqualified_recipient)
+ if (f.allow_unqualified_recipient)
{
DEBUG(D_receive) debug_printf("unqualified address %s accepted\n",
recipient);
+#ifdef SUPPORT_TLS
static BOOL
smtp_log_tls_fail(uschar * errstr)
{
log_write(0, LOG_MAIN, "TLS error on %s %s", conn_info, errstr);
return FALSE;
}
+#endif
)
{
DEBUG(D_receive) debug_printf("TCP_FASTOPEN mode connection (state TCP_SYN_RECV)\n");
- tcp_in_fastopen = TRUE;
+ f.tcp_in_fastopen = TRUE;
}
# endif
}
/* Default values for certain variables */
-helo_seen = esmtp = helo_accept_junk = FALSE;
+fl.helo_seen = fl.esmtp = fl.helo_accept_junk = FALSE;
smtp_mailcmd_count = 0;
count_nonmail = TRUE_UNSET;
synprot_error_count = unknown_command_count = nonmail_command_count = 0;
smtp_delay_mail = smtp_rlm_base;
-auth_advertised = FALSE;
-smtp_in_pipelining_advertised = FALSE;
-pipelining_enable = TRUE;
+fl.auth_advertised = FALSE;
+f.smtp_in_pipelining_advertised = f.smtp_in_pipelining_used = FALSE;
+f.pipelining_enable = TRUE;
sync_cmd_limit = NON_SYNC_CMD_NON_PIPELINING;
-smtp_exit_function_called = FALSE; /* For avoiding loop in not-quit exit */
+fl.smtp_exit_function_called = FALSE; /* For avoiding loop in not-quit exit */
/* If receiving by -bs from a trusted user, or testing with -bh, we allow
authentication settings from -oMaa to remain in force. */
-if (!host_checking && !sender_host_notsocket)
+if (!host_checking && !f.sender_host_notsocket)
sender_host_auth_pubname = sender_host_authenticated = NULL;
authenticated_by = NULL;
tls_in.ourcert = tls_in.peercert = NULL;
tls_in.sni = NULL;
tls_in.ocsp = OCSP_NOT_REQ;
-tls_advertised = FALSE;
+fl.tls_advertised = FALSE;
# ifdef EXPERIMENTAL_REQUIRETLS
-requiretls_advertised = FALSE;
+fl.requiretls_advertised = FALSE;
# endif
#endif
-dsn_advertised = FALSE;
+fl.dsn_advertised = FALSE;
#ifdef SUPPORT_I18N
-smtputf8_advertised = FALSE;
+fl.smtputf8_advertised = FALSE;
#endif
/* Reset ACL connection variables */
If smtp_accept_max and smtp_accept_reserve are set, keep some connections in
reserve for certain hosts and/or networks. */
-if (!sender_host_unknown)
+if (!f.sender_host_unknown)
{
int rc;
BOOL reserved_host = FALSE;
#define OPTSTYLE 3
#endif
- if (!host_checking && !sender_host_notsocket)
+ if (!host_checking && !f.sender_host_notsocket)
{
#if OPTSTYLE == 1
EXIM_SOCKLEN_T optlen = sizeof(struct ip_options) + MAX_IPOPTLEN;
setting is an attempt to get rid of some hanging connections that stick in
read() when the remote end (usually a dialup) goes away. */
- if (smtp_accept_keepalive && !sender_host_notsocket)
+ if (smtp_accept_keepalive && !f.sender_host_notsocket)
ip_keepalive(fileno(smtp_out), sender_host_address, FALSE);
/* If the current host matches host_lookup, set the name by doing a
addresses in the headers. For a site that permits no qualification, this
won't take long, however. */
- allow_unqualified_sender =
+ f.allow_unqualified_sender =
verify_check_host(&sender_unqualified_hosts) == OK;
- allow_unqualified_recipient =
+ f.allow_unqualified_recipient =
verify_check_host(&recipient_unqualified_hosts) == OK;
/* Determine whether HELO/EHLO is required for this host. The requirement
can be hard or soft. */
- helo_required = verify_check_host(&helo_verify_hosts) == OK;
- if (!helo_required)
- helo_verify = verify_check_host(&helo_try_verify_hosts) == OK;
+ fl.helo_required = verify_check_host(&helo_verify_hosts) == OK;
+ if (!fl.helo_required)
+ fl.helo_verify = verify_check_host(&helo_try_verify_hosts) == OK;
/* Determine whether this hosts is permitted to send syntactic junk
after a HELO or EHLO command. */
- helo_accept_junk = verify_check_host(&helo_accept_junk_hosts) == OK;
+ fl.helo_accept_junk = verify_check_host(&helo_accept_junk_hosts) == OK;
}
/* For batch SMTP input we are now done. */
#ifdef SUPPORT_PROXY
proxy_session = FALSE;
-proxy_session_failed = FALSE;
+f.proxy_session_failed = FALSE;
if (check_proxy_protocol_host())
setup_proxy_protocol_host();
#endif
int esclen = 0;
uschar *esc = US"";
-if (!final && no_multiline_responses) return;
+if (!final && f.no_multiline_responses) return;
if (codelen > 4)
{
do it that way, so as not to have to mess with the code for the RCPT command,
which sometimes uses smtp_printf() and sometimes smtp_respond(). */
-if (rcpt_in_progress)
+if (fl.rcpt_in_progress)
{
if (rcpt_smtp_response == NULL)
rcpt_smtp_response = string_copy(msg);
- else if (rcpt_smtp_response_same &&
+ else if (fl.rcpt_smtp_response_same &&
Ustrcmp(rcpt_smtp_response, msg) != 0)
- rcpt_smtp_response_same = FALSE;
- rcpt_in_progress = FALSE;
+ fl.rcpt_smtp_response_same = FALSE;
+ fl.rcpt_in_progress = FALSE;
}
/* Now output the message, splitting it up into multiple lines if necessary.
smtp_printf("%.3s%c%.*s%s\r\n", !final, code, final ? ' ':'-', esclen, esc, msg);
return;
}
- else if (nl[1] == 0 || no_multiline_responses)
+ else if (nl[1] == 0 || f.no_multiline_responses)
{
smtp_printf("%.3s%c%.*s%.*s\r\n", !final, code, final ? ' ':'-', esclen, esc,
(int)(nl - msg), msg);
if (sender_verified_failed &&
!testflag(sender_verified_failed, af_sverify_told))
{
- BOOL save_rcpt_in_progress = rcpt_in_progress;
- rcpt_in_progress = FALSE; /* So as not to treat these as the error */
+ BOOL save_rcpt_in_progress = fl.rcpt_in_progress;
+ fl.rcpt_in_progress = FALSE; /* So as not to treat these as the error */
setflag(sender_verified_failed, af_sverify_told);
sender_verified_failed->address,
sender_verified_failed->user_message));
- rcpt_in_progress = save_rcpt_in_progress;
+ fl.rcpt_in_progress = save_rcpt_in_progress;
}
/* Sort out text for logging */
be re-implemented in a tidier fashion. */
else
- if (acl_temp_details && user_msg)
+ if (f.acl_temp_details && user_msg)
{
if ( smtp_return_error_details
&& sender_verified_failed
/* Check for recursive acll */
-if (smtp_exit_function_called)
+if (fl.smtp_exit_function_called)
{
log_write(0, LOG_PANIC, "smtp_notquit_exit() called more than once (%s)",
reason);
return;
}
-smtp_exit_function_called = TRUE;
+fl.smtp_exit_function_called = TRUE;
/* Call the not-QUIT ACL, if there is one, unless no reason is given. */
log_msg);
}
+/* If the connection was dropped, we certainly are no longer talking TLS */
+tls_in.active.sock = -1;
+
/* Write an SMTP response if we are expected to give one. As the default
responses are all internal, they should always fit in the buffer, but code a
warning, just in case. Note that string_vformat() still leaves a complete
else if (sender_host_address == NULL)
{
HDEBUG(D_receive) debug_printf("no client IP address: assume success\n");
- helo_verified = TRUE;
+ f.helo_verified = TRUE;
}
/* Deal with the more common case when there is a sending IP address */
else if (sender_helo_name[0] == '[')
{
- helo_verified = Ustrncmp(sender_helo_name+1, sender_host_address,
+ f.helo_verified = Ustrncmp(sender_helo_name+1, sender_host_address,
Ustrlen(sender_host_address)) == 0;
#if HAVE_IPV6
- if (!helo_verified)
+ if (!f.helo_verified)
{
if (strncmpic(sender_host_address, US"::ffff:", 7) == 0)
- helo_verified = Ustrncmp(sender_helo_name + 1,
+ f.helo_verified = Ustrncmp(sender_helo_name + 1,
sender_host_address + 7, Ustrlen(sender_host_address) - 7) == 0;
}
#endif
HDEBUG(D_receive)
- { if (helo_verified) debug_printf("matched host address\n"); }
+ { if (f.helo_verified) debug_printf("matched host address\n"); }
}
/* Do a reverse lookup if one hasn't already given a positive or negative
/* If a host name is known, check it and all its aliases. */
if (sender_host_name)
- if ((helo_verified = strcmpic(sender_host_name, sender_helo_name) == 0))
+ if ((f.helo_verified = strcmpic(sender_host_name, sender_helo_name) == 0))
{
sender_helo_dnssec = sender_host_dnssec;
HDEBUG(D_receive) debug_printf("matched host name\n");
{
uschar **aliases = sender_host_aliases;
while (*aliases)
- if ((helo_verified = strcmpic(*aliases++, sender_helo_name) == 0))
+ if ((f.helo_verified = strcmpic(*aliases++, sender_helo_name) == 0))
{
sender_helo_dnssec = sender_host_dnssec;
break;
}
- HDEBUG(D_receive) if (helo_verified)
+ HDEBUG(D_receive) if (f.helo_verified)
debug_printf("matched alias %s\n", *(--aliases));
}
/* Final attempt: try a forward lookup of the helo name */
- if (!helo_verified)
+ if (!f.helo_verified)
{
int rc;
host_item h;
for (hh = &h; hh; hh = hh->next)
if (Ustrcmp(hh->address, sender_host_address) == 0)
{
- helo_verified = TRUE;
+ f.helo_verified = TRUE;
if (h.dnssec == DS_YES) sender_helo_dnssec = TRUE;
HDEBUG(D_receive)
{
}
}
-if (!helo_verified) helo_verify_failed = TRUE; /* We've tried ... */
+if (!f.helo_verified) f.helo_verify_failed = TRUE; /* We've tried ... */
return yield;
}
qualify_recipient(uschar ** recipient, uschar * smtp_cmd_data, uschar * tag)
{
int rd;
-if (allow_unqualified_recipient || strcmpic(*recipient, US"postmaster") == 0)
+if (f.allow_unqualified_recipient || strcmpic(*recipient, US"postmaster") == 0)
{
DEBUG(D_receive) debug_printf("unqualified address %s accepted\n",
*recipient);
smtp_reset(reset_point);
message_ended = END_NOTSTARTED;
-chunking_state = chunking_offered ? CHUNKING_OFFERED : CHUNKING_NOT_OFFERED;
+chunking_state = f.chunking_offered ? CHUNKING_OFFERED : CHUNKING_NOT_OFFERED;
cmd_list[CMD_LIST_RSET].is_mail_cmd = TRUE;
cmd_list[CMD_LIST_HELO].is_mail_cmd = TRUE;
int c;
auth_instance *au;
uschar *orcpt = NULL;
- int flags;
+ int dsn_flags;
gstring * g;
#ifdef AUTH_TLS
authentication_failed = TRUE;
cmd_list[CMD_LIST_AUTH].is_mail_cmd = FALSE;
- if (!auth_advertised && !allow_auth_unadvertised)
+ if (!fl.auth_advertised && !f.allow_auth_unadvertised)
{
done = synprot_error(L_smtp_protocol_error, 503, NULL,
US"AUTH command used when not advertised");
for (au = auths; au; au = au->next)
if (strcmpic(s, au->public_name) == 0 && au->server &&
- (au->advertised || allow_auth_unadvertised))
+ (au->advertised || f.allow_auth_unadvertised))
break;
if (au)
case HELO_CMD:
HAD(SCH_HELO);
hello = US"HELO";
- esmtp = FALSE;
+ fl.esmtp = FALSE;
goto HELO_EHLO;
case EHLO_CMD:
HAD(SCH_EHLO);
hello = US"EHLO";
- esmtp = TRUE;
+ fl.esmtp = TRUE;
HELO_EHLO: /* Common code for HELO and EHLO */
cmd_list[CMD_LIST_HELO].is_mail_cmd = FALSE;
is set, ensure that the HELO name matches the actual host. If helo_verify
is set, do the same check, but softly. */
- if (!sender_host_unknown)
+ if (!f.sender_host_unknown)
{
- BOOL old_helo_verified = helo_verified;
+ BOOL old_helo_verified = f.helo_verified;
uschar *p = smtp_cmd_data;
while (*p != 0 && !isspace(*p)) { *p = tolower(*p); p++; }
now obsolescent, since the verification can now be requested selectively
at ACL time. */
- helo_verified = helo_verify_failed = sender_helo_dnssec = FALSE;
- if (helo_required || helo_verify)
+ f.helo_verified = f.helo_verify_failed = sender_helo_dnssec = FALSE;
+ if (fl.helo_required || fl.helo_verify)
{
BOOL tempfail = !smtp_verify_helo();
- if (!helo_verified)
+ if (!f.helo_verified)
{
- if (helo_required)
+ if (fl.helo_required)
{
smtp_printf("%d %s argument does not match calling host\r\n", FALSE,
tempfail? 451 : 550, hello);
log_write(0, LOG_MAIN|LOG_REJECT, "%srejected \"%s %s\" from %s",
tempfail? "temporarily " : "",
hello, sender_helo_name, host_and_ident(FALSE));
- helo_verified = old_helo_verified;
+ f.helo_verified = old_helo_verified;
break; /* End of HELO/EHLO processing */
}
HDEBUG(D_all) debug_printf("%s verification failed but host is in "
some broken systems expect each response to be in a single packet, arrange
that the entire reply is sent in one write(). */
- auth_advertised = FALSE;
- smtp_in_pipelining_advertised = FALSE;
+ fl.auth_advertised = FALSE;
+ f.smtp_in_pipelining_advertised = FALSE;
#ifdef SUPPORT_TLS
- tls_advertised = FALSE;
+ fl.tls_advertised = FALSE;
# ifdef EXPERIMENTAL_REQUIRETLS
- requiretls_advertised = FALSE;
+ fl.requiretls_advertised = FALSE;
# endif
#endif
- dsn_advertised = FALSE;
+ fl.dsn_advertised = FALSE;
#ifdef SUPPORT_I18N
- smtputf8_advertised = FALSE;
+ fl.smtputf8_advertised = FALSE;
#endif
smtp_code = US"250 "; /* Default response code plus space*/
/* If we received EHLO, we must create a multiline response which includes
the functions supported. */
- if (esmtp)
+ if (fl.esmtp)
{
g->s[3] = '-';
{
g = string_catn(g, smtp_code, 3);
g = string_catn(g, US"-DSN\r\n", 6);
- dsn_advertised = TRUE;
+ fl.dsn_advertised = TRUE;
}
/* Advertise ETRN/VRFY/EXPN if there's are ACL checking whether a host is
/* Exim is quite happy with pipelining, so let the other end know that
it is safe to use it, unless advertising is disabled. */
- if (pipelining_enable &&
+ if (f.pipelining_enable &&
verify_check_host(&pipelining_advertise_hosts) == OK)
{
g = string_catn(g, smtp_code, 3);
g = string_catn(g, US"-PIPELINING\r\n", 13);
sync_cmd_limit = NON_SYNC_CMD_PIPELINING;
- smtp_in_pipelining_advertised = TRUE;
+ f.smtp_in_pipelining_advertised = TRUE;
}
g = string_catn(g, smtp_code, 3);
g = string_catn(g, US"-AUTH", 5);
first = FALSE;
- auth_advertised = TRUE;
+ fl.auth_advertised = TRUE;
}
saveptr = g->ptr;
g = string_catn(g, US" ", 1);
{
g = string_catn(g, smtp_code, 3);
g = string_catn(g, US"-CHUNKING\r\n", 11);
- chunking_offered = TRUE;
+ f.chunking_offered = TRUE;
chunking_state = CHUNKING_OFFERED;
}
{
g = string_catn(g, smtp_code, 3);
g = string_catn(g, US"-STARTTLS\r\n", 11);
- tls_advertised = TRUE;
+ fl.tls_advertised = TRUE;
}
# ifdef EXPERIMENTAL_REQUIRETLS
{
g = string_catn(g, smtp_code, 3);
g = string_catn(g, US"-REQUIRETLS\r\n", 13);
- requiretls_advertised = TRUE;
+ fl.requiretls_advertised = TRUE;
}
# endif
#endif
{
g = string_catn(g, smtp_code, 3);
g = string_catn(g, US"-SMTPUTF8\r\n", 11);
- smtputf8_advertised = TRUE;
+ fl.smtputf8_advertised = TRUE;
}
#endif
memmove(cr, cr + 1, (g->ptr--) - (cr - g->s));
debug_printf("SMTP>> %s", g->s);
}
- helo_seen = TRUE;
+ fl.helo_seen = TRUE;
/* Reset the protocol and the state, abandoning any previous message. */
received_protocol =
(sender_host_address ? protocols : protocols_local)
- [ (esmtp
+ [ (fl.esmtp
? pextend + (sender_host_authenticated ? pauthed : 0)
: pnormal)
+ (tls_in.active.sock >= 0 ? pcrpted : 0)
was_rej_mail = TRUE; /* Reset if accepted */
env_mail_type_t * mail_args; /* Sanity check & validate args */
- if (helo_required && !helo_seen)
+ if (fl.helo_required && !fl.helo_seen)
{
smtp_printf("503 HELO or EHLO required\r\n", FALSE);
log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL from %s: no "
/* Loop, checking for ESMTP additions to the MAIL FROM command. */
- if (esmtp) for(;;)
+ if (fl.esmtp) for(;;)
{
uschar *name, *value, *end;
unsigned long int size;
is included only if configured in at build time. */
case ENV_MAIL_OPT_RET:
- if (dsn_advertised)
+ if (fl.dsn_advertised)
{
/* Check if RET has already been set */
if (dsn_ret > 0)
}
break;
case ENV_MAIL_OPT_ENVID:
- if (dsn_advertised)
+ if (fl.dsn_advertised)
{
/* Check if the dsn envid has been already set */
if (dsn_envid)
#ifdef SUPPORT_I18N
case ENV_MAIL_OPT_UTF8:
- if (!smtputf8_advertised)
+ if (!fl.smtputf8_advertised)
{
done = synprot_error(L_smtp_syntax_error, 501, NULL,
US"SMTPUTF8 used when not advertised");
#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_REQUIRETLS)
case ENV_MAIL_OPT_REQTLS:
{
- const uschar * list = value;
- int sep = ',';
- const uschar * opt;
uschar * r, * t;
- if (!requiretls_advertised)
+ if (!fl.requiretls_advertised)
{
done = synprot_error(L_smtp_syntax_error, 555, NULL,
US"unadvertised MAIL option: REQUIRETLS");
of the SMTP connection. */
if (!sender_domain && *sender_address)
- if (allow_unqualified_sender)
+ if (f.allow_unqualified_sender)
{
sender_domain = Ustrlen(sender_address) + 1;
sender_address = rewrite_address_qualify(sender_address, FALSE);
if (acl_smtp_mail)
{
rc = acl_check(ACL_WHERE_MAIL, NULL, acl_smtp_mail, &user_msg, &log_msg);
- if (rc == OK && !smtp_in_pipelining_advertised && !check_sync())
+ if (rc == OK && !f.smtp_in_pipelining_advertised && !check_sync())
goto SYNC_FAILURE;
}
else
smtp_user_msg(US"250", user_msg);
}
smtp_delay_rcpt = smtp_rlr_base;
- recipients_discarded = (rc == DISCARD);
+ f.recipients_discarded = (rc == DISCARD);
was_rej_mail = FALSE;
}
else
case RCPT_CMD:
HAD(SCH_RCPT);
rcpt_count++;
- was_rcpt = rcpt_in_progress = TRUE;
+ was_rcpt = fl.rcpt_in_progress = TRUE;
/* There must be a sender address; if the sender was rejected and
pipelining was advertised, we assume the client was pipelining, and do not
if (sender_address == NULL)
{
- if (smtp_in_pipelining_advertised && last_was_rej_mail)
+ if (f.smtp_in_pipelining_advertised && last_was_rej_mail)
{
smtp_printf("503 sender not yet given\r\n", FALSE);
was_rej_mail = TRUE;
/* Set the DSN flags orcpt and dsn_flags from the session*/
orcpt = NULL;
- flags = 0;
+ dsn_flags = 0;
- if (esmtp) for(;;)
+ if (fl.esmtp) for(;;)
{
uschar *name, *value;
if (!extract_option(&name, &value))
break;
- if (dsn_advertised && strcmpic(name, US"ORCPT") == 0)
+ if (fl.dsn_advertised && strcmpic(name, US"ORCPT") == 0)
{
/* Check whether orcpt has been already set */
if (orcpt)
DEBUG(D_receive) debug_printf("DSN orcpt: %s\n", orcpt);
}
- else if (dsn_advertised && strcmpic(name, US"NOTIFY") == 0)
+ else if (fl.dsn_advertised && strcmpic(name, US"NOTIFY") == 0)
{
/* Check if the notify flags have been already set */
- if (flags > 0)
+ if (dsn_flags > 0)
{
done = synprot_error(L_smtp_syntax_error, 501, NULL,
US"NOTIFY can be specified once only");
goto COMMAND_LOOP;
}
if (strcmpic(value, US"NEVER") == 0)
- flags |= rf_notify_never;
+ dsn_flags |= rf_notify_never;
else
{
uschar *p = value;
if (strcmpic(p, US"SUCCESS") == 0)
{
DEBUG(D_receive) debug_printf("DSN: Setting notify success\n");
- flags |= rf_notify_success;
+ dsn_flags |= rf_notify_success;
}
else if (strcmpic(p, US"FAILURE") == 0)
{
DEBUG(D_receive) debug_printf("DSN: Setting notify failure\n");
- flags |= rf_notify_failure;
+ dsn_flags |= rf_notify_failure;
}
else if (strcmpic(p, US"DELAY") == 0)
{
DEBUG(D_receive) debug_printf("DSN: Setting notify delay\n");
- flags |= rf_notify_delay;
+ dsn_flags |= rf_notify_delay;
}
else
{
}
p = pp;
}
- DEBUG(D_receive) debug_printf("DSN Flags: %x\n", flags);
+ DEBUG(D_receive) debug_printf("DSN Flags: %x\n", dsn_flags);
}
}
there may be a delay in this, re-check for a synchronization error
afterwards, unless pipelining was advertised. */
- if (recipients_discarded)
+ if (f.recipients_discarded)
rc = DISCARD;
else
if ( (rc = acl_check(ACL_WHERE_RCPT, recipient, acl_smtp_rcpt, &user_msg,
&log_msg)) == OK
- && !smtp_in_pipelining_advertised && !check_sync())
+ && !f.smtp_in_pipelining_advertised && !check_sync())
goto SYNC_FAILURE;
/* The ACL was happy */
/* Set the dsn flags in the recipients_list */
recipients_list[recipients_count-1].orcpt = orcpt;
- recipients_list[recipients_count-1].dsn_flags = flags;
+ recipients_list[recipients_count-1].dsn_flags = dsn_flags;
DEBUG(D_receive) debug_printf("DSN: orcpt: %s flags: %d\n",
recipients_list[recipients_count-1].orcpt,
log_write(0, LOG_MAIN|LOG_REJECT, "%s F=<%s> RCPT %s: "
"discarded by %s ACL%s%s", host_and_ident(TRUE),
sender_address_unrewritten? sender_address_unrewritten : sender_address,
- smtp_cmd_argument, recipients_discarded? "MAIL" : "RCPT",
+ smtp_cmd_argument, f.recipients_discarded? "MAIL" : "RCPT",
log_msg ? US": " : US"", log_msg ? log_msg : US"");
}
receive_getc = bdat_getc;
receive_ungetc = bdat_ungetc;
- dot_ends = FALSE;
+ f.dot_ends = FALSE;
goto DATA_BDAT;
}
case DATA_CMD:
HAD(SCH_DATA);
- dot_ends = TRUE;
+ f.dot_ends = TRUE;
DATA_BDAT: /* Common code for DATA and BDAT */
if (!discarded && recipients_count <= 0)
{
- if (rcpt_smtp_response_same && rcpt_smtp_response != NULL)
+ if (fl.rcpt_smtp_response_same && rcpt_smtp_response != NULL)
{
uschar *code = US"503";
int len = Ustrlen(rcpt_smtp_response);
rcpt_smtp_response[len-2] = 0;
smtp_respond(code, 3, FALSE, rcpt_smtp_response);
}
- if (smtp_in_pipelining_advertised && last_was_rcpt)
+ 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]]);
else
else
{
uschar * acl = acl_smtp_predata ? acl_smtp_predata : US"accept";
- enable_dollar_recipients = TRUE;
+ f.enable_dollar_recipients = TRUE;
rc = acl_check(ACL_WHERE_PREDATA, NULL, acl, &user_msg,
&log_msg);
- enable_dollar_recipients = FALSE;
+ f.enable_dollar_recipients = FALSE;
if (rc == OK && !check_sync())
goto SYNC_FAILURE;
done = smtp_handle_acl_fail(ACL_WHERE_EXPN, rc, user_msg, log_msg);
else
{
- BOOL save_log_testing_mode = log_testing_mode;
- address_test_mode = log_testing_mode = TRUE;
+ BOOL save_log_testing_mode = f.log_testing_mode;
+ f.address_test_mode = f.log_testing_mode = TRUE;
(void) verify_address(deliver_make_addr(smtp_cmd_data, FALSE),
smtp_out, vopt_is_recipient | vopt_qualify | vopt_expn, -1, -1, -1,
NULL, NULL, NULL);
- address_test_mode = FALSE;
- log_testing_mode = save_log_testing_mode; /* true for -bh */
+ f.address_test_mode = FALSE;
+ f.log_testing_mode = save_log_testing_mode; /* true for -bh */
}
break;
case STARTTLS_CMD:
HAD(SCH_STARTTLS);
- if (!tls_advertised)
+ if (!fl.tls_advertised)
{
done = synprot_error(L_smtp_protocol_error, 503, NULL,
US"STARTTLS command used when not advertised");
if ((rc = tls_server_start(tls_require_ciphers, &s)) == OK)
{
if (!tls_remember_esmtp)
- helo_seen = esmtp = auth_advertised = smtp_in_pipelining_advertised = FALSE;
+ fl.helo_seen = fl.esmtp = fl.auth_advertised = f.smtp_in_pipelining_advertised = FALSE;
cmd_list[CMD_LIST_EHLO].is_mail_cmd = TRUE;
cmd_list[CMD_LIST_AUTH].is_mail_cmd = TRUE;
cmd_list[CMD_LIST_TLS_AUTH].is_mail_cmd = TRUE;
}
received_protocol =
(sender_host_address ? protocols : protocols_local)
- [ (esmtp
+ [ (fl.esmtp
? pextend + (sender_host_authenticated ? pauthed : 0)
: pnormal)
+ (tls_in.active.sock >= 0 ? pcrpted : 0)
/* Hard failure. Reject everything except QUIT or closed connection. One
cause for failure is a nested STARTTLS, in which case tls_in.active remains
- set, but we must still reject all incoming commands. */
+ set, but we must still reject all incoming commands. Another is a handshake
+ failure - and there may some encrypted data still in the pipe to us, which we
+ see as garbage commands. */
DEBUG(D_tls) debug_printf("TLS failed to start\n");
while (done <= 0) switch(smtp_read_command(FALSE, GETC_BUFFER_UNLIMITED))
if (sender_address || recipients_count > 0)
log_write(L_lost_incoming_connection, LOG_MAIN,
"unexpected %s while reading SMTP command from %s%s%s D=%s",
- sender_host_unknown ? "EOF" : "disconnection",
- tcp_in_fastopen && !tcp_in_fastopen_logged ? US"TFO " : US"",
+ f.sender_host_unknown ? "EOF" : "disconnection",
+ f.tcp_in_fastopen && !f.tcp_in_fastopen_logged ? US"TFO " : US"",
host_and_ident(FALSE), smtp_read_error,
string_timesince(&smtp_connection_start)
);
else
log_write(L_smtp_connection, LOG_MAIN, "%s %slost%s D=%s",
smtp_get_connection_info(),
- tcp_in_fastopen && !tcp_in_fastopen_logged ? US"TFO " : US"",
+ f.tcp_in_fastopen && !f.tcp_in_fastopen_logged ? US"TFO " : US"",
smtp_read_error,
string_timesince(&smtp_connection_start)
);
log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol synchronization error "
"(next input sent too soon: pipelining was%s advertised): "
"rejected \"%s\" %s next input=\"%s\"",
- smtp_in_pipelining_advertised ? "" : " not",
+ f.smtp_in_pipelining_advertised ? "" : " not",
smtp_cmd_buffer, host_and_ident(TRUE),
string_printing(smtp_inptr));
smtp_notquit_exit(US"synchronization-error", US"554",