On Fri, 3 Jan 2003, Karl Schmidt wrote:
> Things are working normally except I have had mail bounce twice now with
> the following log message. The message was resent and the next time it
> went right through.
>
> I found the following in the receiving servers log:
>
> 2003-01-02 13:09:17 SMTP call from [123.45.67.89] dropped: too many
> nonmail commands (last was EHLO)
The patch below should fix this problem. It will be in the next release.
--
Philip Hazel University of Cambridge Computing Service,
ph10@??? Cambridge, England. Phone: +44 1223 334714.
*** exim-4.12/src/smtp_in.c Wed Dec 18 10:28:04 2002
--- smtp_in.c Wed Jan 22 12:25:26 2003
***************
*** 96,112 ****
static uschar *cmd_buffer;
! /* We need to know the position of RSET, HELO, EHLO, and STARTTLS. Their final
! fields are forced TRUE at the start of a new message setup, to allow one of
! each between messages that is not counted as a nonmail command. (In fact, only
! one of HELO/EHLO is not counted.) QUIT is "falsely" labelled as a mail command
! so that it doesn't up the count of non-mail commands and possibly provoke an
! error. */
static smtp_cmd_list cmd_list[] = {
{ "rset", sizeof("rset")-1, RSET_CMD, FALSE, FALSE }, /* First */
{ "helo", sizeof("helo")-1, HELO_CMD, TRUE, FALSE },
{ "ehlo", sizeof("ehlo")-1, EHLO_CMD, TRUE, FALSE },
#ifdef SUPPORT_TLS
{ "starttls", sizeof("starttls")-1, STARTTLS_CMD, FALSE, FALSE },
#endif
--- 96,121 ----
static uschar *cmd_buffer;
! /* We need to know the position of RSET, HELO, EHLO, AUTH, and STARTTLS. Their
! final fields of all except AUTH are forced TRUE at the start of a new message
! setup, to allow one of each between messages that is not counted as a nonmail
! command. (In fact, only one of HELO/EHLO is not counted.) Also, we have to
! allow a new EHLO after starting up TLS.
+ AUTH is "falsely" labelled as a mail command initially, so that it doesn't get
+ counted. However, the flag is changed when AUTH is received, so that multiple
+ failing AUTHs will eventually hit the limit. After a successful AUTH, another
+ AUTH is already forbidden. After a TLS session is started, AUTH's flag is again
+ forced TRUE, to allow for the re-authentication that can happen at that point.
+
+ QUIT is also "falsely" labelled as a mail command so that it doesn't up the
+ count of non-mail commands and possibly provoke an error. */
+
static smtp_cmd_list cmd_list[] = {
{ "rset", sizeof("rset")-1, RSET_CMD, FALSE, FALSE }, /* First */
{ "helo", sizeof("helo")-1, HELO_CMD, TRUE, FALSE },
{ "ehlo", sizeof("ehlo")-1, EHLO_CMD, TRUE, FALSE },
+ { "auth", sizeof("auth")-1, AUTH_CMD, TRUE, TRUE },
#ifdef SUPPORT_TLS
{ "starttls", sizeof("starttls")-1, STARTTLS_CMD, FALSE, FALSE },
#endif
***************
*** 113,125 ****
/* If you change anything above here, also fix the definitions below. */
! { "mail from:", sizeof("mail from:")-1, MAIL_CMD, TRUE, TRUE },
! { "rcpt to:", sizeof("rcpt to:")-1, RCPT_CMD, TRUE, TRUE },
! { "data", sizeof("data")-1, DATA_CMD, FALSE, TRUE },
! { "quit", sizeof("quit")-1, QUIT_CMD, FALSE, TRUE },
{ "noop", sizeof("noop")-1, NOOP_CMD, TRUE, FALSE },
! { "auth", sizeof("auth")-1, AUTH_CMD, TRUE, FALSE },
! { "etrn", sizeof("etrn")-1, ETRN_CMD, TRUE, FALSE},
{ "vrfy", sizeof("vrfy")-1, VRFY_CMD, TRUE, FALSE },
{ "expn", sizeof("expn")-1, EXPN_CMD, TRUE, FALSE },
{ "help", sizeof("help")-1, HELP_CMD, TRUE, FALSE }
--- 122,133 ----
/* If you change anything above here, also fix the definitions below. */
! { "mail from:", sizeof("mail from:")-1, MAIL_CMD, TRUE, TRUE },
! { "rcpt to:", sizeof("rcpt to:")-1, RCPT_CMD, TRUE, TRUE },
! { "data", sizeof("data")-1, DATA_CMD, FALSE, TRUE },
! { "quit", sizeof("quit")-1, QUIT_CMD, FALSE, TRUE },
{ "noop", sizeof("noop")-1, NOOP_CMD, TRUE, FALSE },
! { "etrn", sizeof("etrn")-1, ETRN_CMD, TRUE, FALSE },
{ "vrfy", sizeof("vrfy")-1, VRFY_CMD, TRUE, FALSE },
{ "expn", sizeof("expn")-1, EXPN_CMD, TRUE, FALSE },
{ "help", sizeof("help")-1, HELP_CMD, TRUE, FALSE }
***************
*** 131,137 ****
#define CMD_LIST_RSET 0
#define CMD_LIST_HELO 1
#define CMD_LIST_EHLO 2
! #define CMD_LIST_STARTTLS 3
static uschar *protocols[] = {
US"local-smtp", US"local-esmtp", US"local-asmtp" };
--- 139,146 ----
#define CMD_LIST_RSET 0
#define CMD_LIST_HELO 1
#define CMD_LIST_EHLO 2
! #define CMD_LIST_AUTH 3
! #define CMD_LIST_STARTTLS 4
static uschar *protocols[] = {
US"local-smtp", US"local-esmtp", US"local-asmtp" };
***************
*** 1725,1734 ****
{
/* The AUTH command is not permitted to occur inside a transaction, and may
occur successfully only once per connection, and then only when we've
! advertised it. */
case AUTH_CMD:
authentication_failed = TRUE;
if (!auth_advertised)
{
--- 1685,1701 ----
{
/* The AUTH command is not permitted to occur inside a transaction, and may
occur successfully only once per connection, and then only when we've
! advertised it. Actually, that isn't quite true. When TLS is started, all
! previous information about a connection must be discarded, so a new AUTH is
! permitted at that time.
+ AUTH is initially labelled as a "nonmail command" so that one occurrence
+ doesn't get counted. We change the label here so that multiple failing
+ AUTHS will eventually hit the nonmail threshold. */
+
case AUTH_CMD:
authentication_failed = TRUE;
+ cmd_list[CMD_LIST_AUTH].is_mail_cmd = FALSE;
if (!auth_advertised)
{
***************
*** 2751,2763 ****
cmd_list[CMD_LIST_STARTTLS].is_mail_cmd = FALSE;
/* Attempt to start up a TLS session, and if successful, discard all
! knowledge that was obtained previously. One cause for failure is a nested
! STARTTLS, in which case tls_active remains set, but we must still reject
! all incoming commands. */
if ((rc = tls_server_start()) == OK)
{
helo_seen = esmtp= FALSE;
if (sender_helo_name != NULL)
{
store_free(sender_helo_name);
--- 2716,2730 ----
cmd_list[CMD_LIST_STARTTLS].is_mail_cmd = FALSE;
/* Attempt to start up a TLS session, and if successful, discard all
! knowledge that was obtained previously. 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()) == OK)
{
helo_seen = esmtp= FALSE;
+ cmd_list[CMD_LIST_EHLO].is_mail_cmd = TRUE;
+ cmd_list[CMD_LIST_AUTH].is_mail_cmd = TRUE;
if (sender_helo_name != NULL)
{
store_free(sender_helo_name);