Implemented control=allow_auth_unadvertised.
authorPhilip Hazel <ph10@hermes.cam.ac.uk>
Thu, 2 Mar 2006 12:25:48 +0000 (12:25 +0000)
committerPhilip Hazel <ph10@hermes.cam.ac.uk>
Thu, 2 Mar 2006 12:25:48 +0000 (12:25 +0000)
doc/doc-misc/WishList
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
src/src/acl.c
src/src/globals.c
src/src/globals.h
src/src/smtp_in.c
test/confs/3400
test/scripts/3400-plaintext/3400
test/stderr/3400
test/stdout/3400

index 55aa19d9dfbda11cf7bccead2b743a4396db08c9..23a597d8a0373668a9bfebf28e283e31dfaf593b 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-misc/WishList,v 1.61 2006/03/02 11:24:25 ph10 Exp $
+$Cambridge: exim/doc/doc-misc/WishList,v 1.62 2006/03/02 12:25:48 ph10 Exp $
 
 EXIM 4 WISH LIST
 ----------------
@@ -1997,13 +1997,6 @@ code, because of caching. Probably means we have to invent ewildlsearch and
 enwildlsearch.
 ------------------------------------------------------------------------------
 
-(348) 17-Nov-05 S Option to allow AUTH when not advertised.
-
-It seems that there are clients that send AUTH when it hasn't been advertised,
-some even after HELO, not even EHLO. Sigh. Possibly this should be an ACL
-control, to enable it to be restricted to certain hosts.
-------------------------------------------------------------------------------
-
 (350) 28-Feb-06 S Additional errors for retry rules
 
 (i) Unexpected connection close; (ii) mail_4xx.
index 71e3e5e7e661891a1546f879d21f0fa1709b99c1..6266ed56bd44a38f3c5c06ba3de5e5de4c4c6a3f 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.320 2006/03/01 16:07:16 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.321 2006/03/02 12:25:48 ph10 Exp $
 
 Change log file for Exim from version 4.21
 -------------------------------------------
@@ -272,6 +272,9 @@ PH/53 This is related to PH/52, but is more general: for any failing address,
       "retry timeout exceeded" was returned. Now it returns the full error as
       well as "retry timeout exceeded".
 
+PH/54 Added control=allow_auth_unadvertised, as it seems there are clients that
+      do this, and (what is worse) MTAs that accept it.
+
 
 Exim version 4.60
 -----------------
index e8792c3fcfd9c363155a7fa9f5ff792d0768adec..06c6760500e583cb3530d9ed84612e68bade1d72 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/NewStuff,v 1.93 2006/03/01 11:40:51 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/NewStuff,v 1.94 2006/03/02 12:25:48 ph10 Exp $
 
 New Features in Exim
 --------------------
@@ -105,6 +105,19 @@ PH/15 The smtp transport has a new option called authenticated_sender_force.
 PH/16 The expansion ${time_eval:<string>} converts an Exim time string such as
       2d4h1m into a number of seconds.
 
+PH/17 The ACL modifier control=allow_auth_unadvertised can be used to permit a
+      client host to use the SMTP AUTH command even when it has not been
+      advertised in response to EHLO. Furthermore, because there are apparently
+      some really broken clients that do this, Exim will even accept AUTH after
+      HELO when this control is set. It should only be used if you really need
+      it, and you should limit its use to those broken hosts that do not work
+      without it. For example:
+
+        warn hosts   = 192.168.34.25
+             control = allow_auth_unadvertised
+
+      This control is permitted only in the connection and HELO ACLs.
+
 
 Version 4.60
 ------------
index 6efc313d1ba5681c5d23f44145cd239b0a89ec2a..2a7b5afe8c836d03bd5a887679a29189534c2be6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/acl.c,v 1.55 2006/02/13 12:02:59 ph10 Exp $ */
+/* $Cambridge: exim/src/src/acl.c,v 1.56 2006/03/02 12:25:48 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -132,19 +132,29 @@ static uschar *conditions[] = {
 that follows! */
 
 enum {
-#ifdef EXPERIMENTAL_BRIGHTMAIL
+  CONTROL_AUTH_UNADVERTISED,
+  #ifdef EXPERIMENTAL_BRIGHTMAIL
   CONTROL_BMI_RUN,
-#endif
-#ifdef EXPERIMENTAL_DOMAINKEYS
+  #endif
+  #ifdef EXPERIMENTAL_DOMAINKEYS
   CONTROL_DK_VERIFY,
-#endif
-  CONTROL_ERROR, CONTROL_CASEFUL_LOCAL_PART, CONTROL_CASELOWER_LOCAL_PART,
-  CONTROL_ENFORCE_SYNC, CONTROL_NO_ENFORCE_SYNC, CONTROL_FREEZE,
-  CONTROL_QUEUE_ONLY, CONTROL_SUBMISSION, CONTROL_SUPPRESS_LOCAL_FIXUPS,
-#ifdef WITH_CONTENT_SCAN
+  #endif
+  CONTROL_ERROR,
+  CONTROL_CASEFUL_LOCAL_PART,
+  CONTROL_CASELOWER_LOCAL_PART,
+  CONTROL_ENFORCE_SYNC,
+  CONTROL_NO_ENFORCE_SYNC,
+  CONTROL_FREEZE,
+  CONTROL_QUEUE_ONLY,
+  CONTROL_SUBMISSION,
+  CONTROL_SUPPRESS_LOCAL_FIXUPS,
+  #ifdef WITH_CONTENT_SCAN
   CONTROL_NO_MBOX_UNSPOOL,
-#endif
-  CONTROL_FAKEDEFER, CONTROL_FAKEREJECT, CONTROL_NO_MULTILINE };
+  #endif
+  CONTROL_FAKEDEFER,
+  CONTROL_FAKEREJECT,
+  CONTROL_NO_MULTILINE
+};
 
 /* ACL control names; keep in step with the table above! This list is used for
 turning ids into names. The actual list of recognized names is in the variable
@@ -152,20 +162,27 @@ control_def controls_list[] below. The fact that there are two lists is a mess
 and should be tidied up. */
 
 static uschar *controls[] = {
+  US"allow_auth_unadvertised",
   #ifdef EXPERIMENTAL_BRIGHTMAIL
   US"bmi_run",
   #endif
   #ifdef EXPERIMENTAL_DOMAINKEYS
   US"dk_verify",
   #endif
-  US"error", US"caseful_local_part",
-  US"caselower_local_part", US"enforce_sync", US"no_enforce_sync", US"freeze",
-  US"queue_only", US"submission", US"suppress_local_fixups",
+  US"error",
+  US"caseful_local_part",
+  US"caselower_local_part",
+  US"enforce_sync",
+  US"no_enforce_sync",
+  US"freeze",
+  US"queue_only",
+  US"submission",
+  US"suppress_local_fixups",
   #ifdef WITH_CONTENT_SCAN
   US"no_mbox_unspool",
   #endif
-
-  US"no_multiline"};
+  US"no_multiline"
+};
 
 /* Flags to indicate for which conditions /modifiers a string expansion is done
 at the outer level. In the other cases, expansion already occurs in the
@@ -453,12 +470,16 @@ each control, there's a bitmap of dis-allowed times. For some, it is easier to
 specify the negation of a small number of allowed times. */
 
 static unsigned int control_forbids[] = {
-#ifdef EXPERIMENTAL_BRIGHTMAIL
+  (unsigned int)
+  ~((1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)),   /* allow_auth_unadvertised */
+
+  #ifdef EXPERIMENTAL_BRIGHTMAIL
   0,                                               /* bmi_run */
-#endif
-#ifdef EXPERIMENTAL_DOMAINKEYS
+  #endif
+
+  #ifdef EXPERIMENTAL_DOMAINKEYS
   (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP),      /* dk_verify */
-#endif
+  #endif
 
   0,                                               /* error */
 
@@ -490,12 +511,12 @@ static unsigned int control_forbids[] = {
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* suppress_local_fixups */
     (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_PREDATA)),
 
-#ifdef WITH_CONTENT_SCAN
+  #ifdef WITH_CONTENT_SCAN
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* no_mbox_unspool */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
     (1<<ACL_WHERE_MIME)),
-#endif
+  #endif
 
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* fakedefer */
@@ -519,26 +540,27 @@ typedef struct control_def {
 } control_def;
 
 static control_def controls_list[] = {
+  { US"allow_auth_unadvertised", CONTROL_AUTH_UNADVERTISED, FALSE },
 #ifdef EXPERIMENTAL_BRIGHTMAIL
-  { US"bmi_run",                CONTROL_BMI_RUN, FALSE },
+  { US"bmi_run",                 CONTROL_BMI_RUN, FALSE },
 #endif
 #ifdef EXPERIMENTAL_DOMAINKEYS
-  { US"dk_verify",              CONTROL_DK_VERIFY, FALSE },
-#endif
-  { US"caseful_local_part",     CONTROL_CASEFUL_LOCAL_PART, FALSE },
-  { US"caselower_local_part",   CONTROL_CASELOWER_LOCAL_PART, FALSE },
-  { US"enforce_sync",           CONTROL_ENFORCE_SYNC, FALSE },
-  { US"freeze",                 CONTROL_FREEZE, TRUE },
-  { US"no_enforce_sync",        CONTROL_NO_ENFORCE_SYNC, FALSE },
-  { US"no_multiline_responses", CONTROL_NO_MULTILINE, FALSE },
-  { US"queue_only",             CONTROL_QUEUE_ONLY, FALSE },
+  { US"dk_verify",               CONTROL_DK_VERIFY, FALSE },
+#endif
+  { US"caseful_local_part",      CONTROL_CASEFUL_LOCAL_PART, FALSE },
+  { US"caselower_local_part",    CONTROL_CASELOWER_LOCAL_PART, FALSE },
+  { US"enforce_sync",            CONTROL_ENFORCE_SYNC, FALSE },
+  { US"freeze",                  CONTROL_FREEZE, TRUE },
+  { US"no_enforce_sync",         CONTROL_NO_ENFORCE_SYNC, FALSE },
+  { US"no_multiline_responses",  CONTROL_NO_MULTILINE, FALSE },
+  { US"queue_only",              CONTROL_QUEUE_ONLY, FALSE },
 #ifdef WITH_CONTENT_SCAN
-  { US"no_mbox_unspool",        CONTROL_NO_MBOX_UNSPOOL, FALSE },
+  { US"no_mbox_unspool",         CONTROL_NO_MBOX_UNSPOOL, FALSE },
 #endif
-  { US"fakedefer",              CONTROL_FAKEDEFER, TRUE },
-  { US"fakereject",             CONTROL_FAKEREJECT, TRUE },
-  { US"submission",             CONTROL_SUBMISSION, TRUE },
-  { US"suppress_local_fixups",  CONTROL_SUPPRESS_LOCAL_FIXUPS, FALSE }
+  { US"fakedefer",               CONTROL_FAKEDEFER, TRUE },
+  { US"fakereject",              CONTROL_FAKEREJECT, TRUE },
+  { US"submission",              CONTROL_SUBMISSION, TRUE },
+  { US"suppress_local_fixups",   CONTROL_SUPPRESS_LOCAL_FIXUPS, FALSE }
   };
 
 /* Support data structures for Client SMTP Authorization. acl_verify_csa()
@@ -2430,16 +2452,22 @@ for (; cb != NULL; cb = cb->next)
 
     switch(control_type)
       {
-#ifdef EXPERIMENTAL_BRIGHTMAIL
+      case CONTROL_AUTH_UNADVERTISED:
+      allow_auth_unadvertised = TRUE;
+      break;
+
+      #ifdef EXPERIMENTAL_BRIGHTMAIL
       case CONTROL_BMI_RUN:
       bmi_run = 1;
       break;
-#endif
-#ifdef EXPERIMENTAL_DOMAINKEYS
+      #endif
+
+      #ifdef EXPERIMENTAL_DOMAINKEYS
       case CONTROL_DK_VERIFY:
       dk_do_verify = 1;
       break;
-#endif
+      #endif
+
       case CONTROL_ERROR:
       return ERROR;
 
@@ -2459,11 +2487,11 @@ for (; cb != NULL; cb = cb->next)
       smtp_enforce_sync = FALSE;
       break;
 
-#ifdef WITH_CONTENT_SCAN
+      #ifdef WITH_CONTENT_SCAN
       case CONTROL_NO_MBOX_UNSPOOL:
       no_mbox_unspool = TRUE;
       break;
-#endif
+      #endif
 
       case CONTROL_NO_MULTILINE:
       no_multiline_responses = TRUE;
index 58b0321450625c6d4e2b62ae9b94cb080ef5b8f0..5d898d546f9fe311f4612341c4a9f0e5ddc05be4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.c,v 1.51 2006/02/20 16:31:49 ph10 Exp $ */
+/* $Cambridge: exim/src/src/globals.c,v 1.52 2006/03/02 12:25:48 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -299,6 +299,7 @@ tree_node *addresslist_anchor  = NULL;
 int     addresslist_count      = 0;
 gid_t  *admin_groups           = NULL;
 BOOL    admin_user             = FALSE;
+BOOL    allow_auth_unadvertised= FALSE;
 BOOL    allow_domain_literals  = FALSE;
 BOOL    allow_mx_to_ip         = FALSE;
 BOOL    allow_unqualified_recipient = TRUE;    /* For local messages */
index c884dfaf2a46029a84b4334974dd6a8326680186..114f859fb486d5ef8a32a904f6dc259094445f45 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.h,v 1.35 2006/02/13 12:02:59 ph10 Exp $ */
+/* $Cambridge: exim/src/src/globals.h,v 1.36 2006/03/02 12:25:48 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -143,6 +143,7 @@ extern tree_node *addresslist_anchor;  /* Tree of defined address lists */
 extern int     addresslist_count;      /* Number defined */
 extern gid_t  *admin_groups;           /* List of admin groups */
 extern BOOL    admin_user;             /* True if caller can do admin */
+extern BOOL    allow_auth_unadvertised;/* As it says */
 extern BOOL    allow_domain_literals;  /* As it says */
 extern BOOL    allow_mx_to_ip;         /* Allow MX records to -> ip address */
 extern BOOL    allow_unqualified_recipient; /* As it says */
index 4ed335c02da40c83a0adf51ce7f8f5d722778ee7..9df0f592ad20513d5039bfb80b1a6cf6d3cea797 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/smtp_in.c,v 1.33 2006/02/14 14:55:37 ph10 Exp $ */
+/* $Cambridge: exim/src/src/smtp_in.c,v 1.34 2006/03/02 12:25:48 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -2147,10 +2147,14 @@ while (done <= 0)
   switch(smtp_read_command(TRUE))
     {
     /* 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.
+    occur successfully only once per connection. 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 may only be used when it has been advertised. However, it seems that
+    there are clients that send AUTH when it hasn't been advertised, some of
+    them even doing this after HELO. And there are MTAs that accept this. Sigh.
+    So there's a get-out that allows this to happen.
 
     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
@@ -2160,7 +2164,7 @@ while (done <= 0)
     authentication_failed = TRUE;
     cmd_list[CMD_LIST_AUTH].is_mail_cmd = FALSE;
 
-    if (!auth_advertised)
+    if (!auth_advertised && !allow_auth_unadvertised)
       {
       done = synprot_error(L_smtp_protocol_error, 503, NULL,
         US"AUTH command used when not advertised");
@@ -2215,12 +2219,13 @@ while (done <= 0)
       }
 
     /* Search for an authentication mechanism which is configured for use
-    as a server and which has been advertised. */
+    as a server and which has been advertised (unless, sigh, allow_auth_
+    unadvertised is set). */
 
     for (au = auths; au != NULL; au = au->next)
       {
       if (strcmpic(s, au->public_name) == 0 && au->server &&
-          au->advertised) break;
+          (au->advertised || allow_auth_unadvertised)) break;
       }
 
     if (au == NULL)
index b84ee56c41f73ec5124eaf9891fd8dc1046f4401..e567565437a4e8082281d70222b0fc0624bdf9d1 100644 (file)
@@ -17,6 +17,7 @@ hostlist auth_hosts = 10.0.0.1
 hostlist relay_hosts = 10.0.0.4
 hostlist auth_relay_hosts = 10.0.0.3 : 10.0.0.4
 
+acl_smtp_connect = check_connect
 acl_smtp_etrn = check_etrn
 acl_smtp_expn = check_expn
 acl_smtp_rcpt = check_recipient
@@ -32,6 +33,11 @@ trusted_users = CALLER
 
 begin acl
 
+check_connect:
+  warn     hosts = 10.0.0.6
+           control = allow_auth_unadvertised
+  accept
+
 check_recipient:
   warn     hosts = 10.0.0.5
            message = authentication-failed: $authentication_failed
index b547a21b9344a0732d11542cb2c4916605265a46..164ace593efcfc4d3246ec8749002d8cf8dbb53f 100644 (file)
@@ -150,9 +150,11 @@ auth expandfail
 AHVzZXJ4AHNlY3JldA==
 quit
 ****
+# 10.0.0.2 is not allowed to use AUTH when it is not advertised
+#
 exim -bs -oMa 10.0.0.2
 ehlo test.host
-auth expandfail
+auth explain
 AHVzZXJ4AHNlY3JldA==
 quit
 ****
@@ -215,4 +217,18 @@ ehlo testing.testing
 auth mylogin dXNlcnggc2VjcmV0
 quit
 ****
+# 10.0.0.6 is allowed to use AUTH when it is not advertised
+#
+exim -bs -oMa 10.0.0.6
+ehlo test.host
+auth explain
+AHVzZXJ4AHNlY3JldA==
+quit
+****
+exim -bs -oMa 10.0.0.6
+helo test.host
+auth explain
+AHVzZXJ4AHNlY3JldA==
+quit
+****
 no_msglog_check
index fb3b9895be4fcbd89e7c7d342854f80f1cc13de2..573d3afeec68c1a60dc8925d8763aa94843dca88 100644 (file)
@@ -6,6 +6,13 @@
 >>> host in helo_verify_hosts? no (option unset)
 >>> host in helo_try_verify_hosts? no (option unset)
 >>> host in helo_accept_junk_hosts? no (option unset)
+>>> using ACL "check_connect"
+>>> processing "warn"
+>>> check hosts = 10.0.0.6
+>>> host in "10.0.0.6"? no (end of list)
+>>> warn: condition test failed
+>>> processing "accept"
+>>> accept: condition test succeeded
 >>> host in smtp_accept_max_nonmail_hosts? yes (matched "*")
 >>> using ACL "check_vrfy"
 >>> processing "deny"
@@ -62,6 +69,13 @@ LOG: H=[10.0.0.2] Warning: accepted ETRN #abcd
 >>> host in helo_verify_hosts? no (option unset)
 >>> host in helo_try_verify_hosts? no (option unset)
 >>> host in helo_accept_junk_hosts? no (option unset)
+>>> using ACL "check_connect"
+>>> processing "warn"
+>>> check hosts = 10.0.0.6
+>>> host in "10.0.0.6"? no (end of list)
+>>> warn: condition test failed
+>>> processing "accept"
+>>> accept: condition test succeeded
 >>> test.host in helo_lookup_domains? no (end of list)
 >>> host in pipelining_advertise_hosts? yes (matched "*")
 >>> host in "10.0.0.1"? yes (matched "10.0.0.1")
@@ -234,6 +248,13 @@ LOG: H=(test.host) [10.0.0.1] Warning: accepted ETRN #abcd
 >>> host in helo_verify_hosts? no (option unset)
 >>> host in helo_try_verify_hosts? no (option unset)
 >>> host in helo_accept_junk_hosts? no (option unset)
+>>> using ACL "check_connect"
+>>> processing "warn"
+>>> check hosts = 10.0.0.6
+>>> host in "10.0.0.6"? no (end of list)
+>>> warn: condition test failed
+>>> processing "accept"
+>>> accept: condition test succeeded
 >>> test.host in helo_lookup_domains? no (end of list)
 >>> host in pipelining_advertise_hosts? yes (matched "*")
 >>> host in "10.0.0.1"? no (end of list)
@@ -318,6 +339,13 @@ LOG: H=(test.host) [10.0.0.3] F=<junk@jink.jonk.test.ex> rejected RCPT <userx@cu
 >>> host in helo_verify_hosts? no (option unset)
 >>> host in helo_try_verify_hosts? no (option unset)
 >>> host in helo_accept_junk_hosts? no (option unset)
+>>> using ACL "check_connect"
+>>> processing "warn"
+>>> check hosts = 10.0.0.6
+>>> host in "10.0.0.6"? no (end of list)
+>>> warn: condition test failed
+>>> processing "accept"
+>>> accept: condition test succeeded
 >>> test.host in helo_lookup_domains? no (end of list)
 >>> host in pipelining_advertise_hosts? yes (matched "*")
 >>> host in "10.0.0.1"? no (end of list)
@@ -348,6 +376,13 @@ host in recipient_unqualified_hosts? no (option unset)
 host in helo_verify_hosts? no (option unset)
 host in helo_try_verify_hosts? no (option unset)
 host in helo_accept_junk_hosts? no (option unset)
+using ACL "check_connect"
+processing "warn"
+check hosts = 10.0.0.6
+host in "10.0.0.6"? no (end of list)
+warn: condition test failed
+processing "accept"
+accept: condition test succeeded
 SMTP>> 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 smtp_setup_msg entered
 SMTP<< ehlo testing.testing
index 7d8e3689aa4b3ce45f444a420e197405947844bd..002166e900a104e8ecb9121f44a6b83df54091ac 100644 (file)
 250 HELP\r
 235 Authentication succeeded\r
 221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at test.host [10.0.0.6]\r
+250-SIZE 52428800\r
+250-ETRN\r
+250-EXPN\r
+250-PIPELINING\r
+250 HELP\r
+334 \r
+235 Authentication succeeded\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250 myhost.test.ex Hello CALLER at test.host [10.0.0.6]\r
+334 \r
+235 Authentication succeeded\r
+221 myhost.test.ex closing connection\r