[exim-cvs] Support AUTH for verify-callout and cutthrough-de…

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] Support AUTH for verify-callout and cutthrough-delivery.
Gitweb: http://git.exim.org/exim.git/commitdiff/fcc8e04755fd6f211fd636e6c077ac41963ab0b9
Commit:     fcc8e04755fd6f211fd636e6c077ac41963ab0b9
Parent:     f9d04f08f7ca18e099843180edea967dd831df91
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Sun May 19 18:14:50 2013 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Mon May 20 23:44:48 2013 +0100


    Support AUTH for verify-callout and cutthrough-delivery.


    Refactored smtp transport to pull out AUTH-related routines so they could be
    also called from the verify code.


    Bugs 321, 823.
---
 doc/doc-docbook/spec.xfpt    |    3 +
 doc/doc-txt/ChangeLog        |    3 +
 doc/doc-txt/NewStuff         |    5 +-
 src/src/transports/smtp.c    |  393 +++++++++++++++++++++++++-----------------
 src/src/verify.c             |   13 +-
 test/confs/0568              |   70 ++++++++
 test/scripts/0000-Basic/0568 |   76 ++++++++
 test/stderr/0398             |    1 +
 test/stderr/0432             |    2 +
 test/stderr/5410             |    3 +
 test/stdout/0568             |   82 +++++++++
 11 files changed, 485 insertions(+), 166 deletions(-)


diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index b024f72..842dd8f 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -28844,6 +28844,9 @@ following SMTP commands are sent:
LHLO is used instead of HELO if the transport's &%protocol%& option is
set to &"lmtp"&.

+The callout may use EHLO, AUTH and/or STARTTLS given appropriate option
+settings.
+
 A recipient callout check is similar. By default, it also uses an empty address
 for the sender. This default is chosen because most hosts do not make use of
 the sender address when verifying a recipient. Using the same address means
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index f06946a..11079a2 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -193,6 +193,9 @@ PP/19 Renamed DNSSEC-enabling option to "dns_dnssec_ok", to make it
 PP/20 Added force_command boolean option to pipe transport.
       Patch from Nick Koston, of cPanel Inc.


+JH/15 AUTH support on callouts (and hence cutthrough-deliveries).
+      Bugzilla 321, 823.
+


 Exim version 4.80.1
 -------------------
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index e349fc8..d1d0d72 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -83,7 +83,7 @@ Version 4.82
     for specific access to the information for each connection.  The old names
     are present for now but deprecated.


-    Not yet supported: IGNOREQUOTA, SIZE, PIPELINING, AUTH.
+    Not yet supported: IGNOREQUOTA, SIZE, PIPELINING.


  8. New expansion operators ${listnamed:name} to get the content of a named list
     and ${listcount:string} to count the items in a list.
@@ -134,6 +134,9 @@ Version 4.82
     decorating commands from user .forward pipe aliases with prefix
     wrappers, for instance.


+20. Callout connections can now AUTH; the same controls as normal delivery
+    connections apply.
+


Version 4.80
------------
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index 4b5529f..25cc549 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -814,6 +814,229 @@ return yield;



+/* Do the client side of smtp-level authentication */
+/*
+Arguments:
+  buffer    EHLO response from server (gets overwritten)
+  addrlist      chain of potential addresses to deliver
+  host          host to deliver to
+  ob        transport options
+  ibp, obp    comms channel control blocks
+
+Returns:
+  OK            Success, or failed (but not required): global "smtp_authenticated" set
+  DEFER            Failed authentication (and was required)
+  ERROR            Internal problem
+
+  FAIL_SEND        Failed communications - transmit
+  FAIL            - response
+*/
+
+int
+smtp_auth(uschar *buffer, unsigned bufsize, address_item *addrlist, host_item *host,
+    smtp_transport_options_block *ob, BOOL is_esmtp,
+    smtp_inblock *ibp, smtp_outblock *obp)
+{
+  int require_auth;
+  uschar *fail_reason = US"server did not advertise AUTH support";
+
+  smtp_authenticated = FALSE;
+  client_authenticator = client_authenticated_id = client_authenticated_sender = NULL;
+  require_auth = verify_check_this_host(&(ob->hosts_require_auth), NULL,
+    host->name, host->address, NULL);
+
+  if (is_esmtp && !regex_AUTH) regex_AUTH =
+      regex_must_compile(US"\\n250[\\s\\-]AUTH\\s+([\\-\\w\\s]+)(?:\\n|$)",
+            FALSE, TRUE);
+
+  if (is_esmtp && regex_match_and_setup(regex_AUTH, buffer, 0, -1))
+    {
+    uschar *names = string_copyn(expand_nstring[1], expand_nlength[1]);
+    expand_nmax = -1;                          /* reset */
+
+    /* Must not do this check until after we have saved the result of the
+    regex match above. */
+
+    if (require_auth == OK ||
+        verify_check_this_host(&(ob->hosts_try_auth), NULL, host->name,
+          host->address, NULL) == OK)
+      {
+      auth_instance *au;
+      fail_reason = US"no common mechanisms were found";
+
+      DEBUG(D_transport) debug_printf("scanning authentication mechanisms\n");
+
+      /* Scan the configured authenticators looking for one which is configured
+      for use as a client, which is not suppressed by client_condition, and
+      whose name matches an authentication mechanism supported by the server.
+      If one is found, attempt to authenticate by calling its client function.
+      */
+
+      for (au = auths; !smtp_authenticated && au != NULL; au = au->next)
+        {
+        uschar *p = names;
+        if (!au->client ||
+            (au->client_condition != NULL &&
+             !expand_check_condition(au->client_condition, au->name,
+               US"client authenticator")))
+          {
+          DEBUG(D_transport) debug_printf("skipping %s authenticator: %s\n",
+            au->name,
+            (au->client)? "client_condition is false" :
+                          "not configured as a client");
+          continue;
+          }
+
+        /* Loop to scan supported server mechanisms */
+
+        while (*p != 0)
+          {
+          int rc;
+          int len = Ustrlen(au->public_name);
+          while (isspace(*p)) p++;
+
+          if (strncmpic(au->public_name, p, len) != 0 ||
+              (p[len] != 0 && !isspace(p[len])))
+            {
+            while (*p != 0 && !isspace(*p)) p++;
+            continue;
+            }
+
+          /* Found data for a listed mechanism. Call its client entry. Set
+          a flag in the outblock so that data is overwritten after sending so
+          that reflections don't show it. */
+
+          fail_reason = US"authentication attempt(s) failed";
+          obp->authenticating = TRUE;
+          rc = (au->info->clientcode)(au, ibp, obp,
+            ob->command_timeout, buffer, bufsize);
+          obp->authenticating = FALSE;
+          DEBUG(D_transport) debug_printf("%s authenticator yielded %d\n",
+            au->name, rc);
+
+          /* A temporary authentication failure must hold up delivery to
+          this host. After a permanent authentication failure, we carry on
+          to try other authentication methods. If all fail hard, try to
+          deliver the message unauthenticated unless require_auth was set. */
+
+          switch(rc)
+            {
+            case OK:
+            smtp_authenticated = TRUE;   /* stops the outer loop */
+        client_authenticator = au->name;
+        if (au->set_client_id != NULL)
+          client_authenticated_id = expand_string(au->set_client_id);
+            break;
+
+            /* Failure after writing a command */
+
+            case FAIL_SEND:
+            return FAIL_SEND;
+
+            /* Failure after reading a response */
+
+            case FAIL:
+            if (errno != 0 || buffer[0] != '5') return FAIL;
+            log_write(0, LOG_MAIN, "%s authenticator failed H=%s [%s] %s",
+              au->name, host->name, host->address, buffer);
+            break;
+
+            /* Failure by some other means. In effect, the authenticator
+            decided it wasn't prepared to handle this case. Typically this
+            is the result of "fail" in an expansion string. Do we need to
+            log anything here? Feb 2006: a message is now put in the buffer
+            if logging is required. */
+
+            case CANCELLED:
+            if (*buffer != 0)
+              log_write(0, LOG_MAIN, "%s authenticator cancelled "
+                "authentication H=%s [%s] %s", au->name, host->name,
+                host->address, buffer);
+            break;
+
+            /* Internal problem, message in buffer. */
+
+            case ERROR:
+            set_errno(addrlist, 0, string_copy(buffer), DEFER, FALSE);
+            return ERROR;
+            }
+
+          break;  /* If not authenticated, try next authenticator */
+          }       /* Loop for scanning supported server mechanisms */
+        }         /* Loop for further authenticators */
+      }
+    }
+
+  /* If we haven't authenticated, but are required to, give up. */
+
+  if (require_auth == OK && !smtp_authenticated)
+    {
+    set_errno(addrlist, ERRNO_AUTHFAIL,
+      string_sprintf("authentication required but %s", fail_reason), DEFER,
+      FALSE);
+    return DEFER;
+    }
+  
+  return OK;
+}
+
+
+/* Construct AUTH appendix string for MAIL TO */
+/*
+Arguments
+  buffer    to build string
+  addrlist      chain of potential addresses to deliver
+  ob        transport options
+
+Globals        smtp_authenticated
+        client_authenticated_sender
+Return    True on error, otherwise buffer has (possibly empty) terminated string
+*/
+
+BOOL
+smtp_mail_auth_str(uschar *buffer, unsigned bufsize, address_item *addrlist,
+            smtp_transport_options_block *ob)
+{
+uschar *local_authenticated_sender = authenticated_sender;
+
+#ifdef notdef
+  debug_printf("smtp_mail_auth_str: as<%s> os<%s> SA<%s>\n", authenticated_sender, ob->authenticated_sender, smtp_authenticated?"Y":"N");
+#endif
+
+if (ob->authenticated_sender != NULL)
+  {
+  uschar *new = expand_string(ob->authenticated_sender);
+  if (new == NULL)
+    {
+    if (!expand_string_forcedfail)
+      {
+      uschar *message = string_sprintf("failed to expand "
+        "authenticated_sender: %s", expand_string_message);
+      set_errno(addrlist, 0, message, DEFER, FALSE);
+      return TRUE;
+      }
+    }
+  else if (new[0] != 0) local_authenticated_sender = new;
+  }
+
+/* Add the authenticated sender address if present */
+
+if ((smtp_authenticated || ob->authenticated_sender_force) &&
+    local_authenticated_sender != NULL)
+  {
+  string_format(buffer, bufsize, " AUTH=%s",
+    auth_xtextencode(local_authenticated_sender,
+    Ustrlen(local_authenticated_sender)));
+  client_authenticated_sender = string_copy(local_authenticated_sender);
+  }
+else
+  *buffer= 0;
+
+return FALSE;
+}
+
+
+
 /*************************************************
 *       Deliver address list to given host       *
 *************************************************/
@@ -893,7 +1116,6 @@ smtp_inblock inblock;
 smtp_outblock outblock;
 int max_rcpt = tblock->max_addresses;
 uschar *igquotstr = US"";
-uschar *local_authenticated_sender = authenticated_sender;
 uschar *helo_data = NULL;
 uschar *message = NULL;
 uschar new_message_id[MESSAGE_ID_LENGTH + 1];
@@ -1267,9 +1489,6 @@ if (continue_hostname == NULL
     #endif
     )
   {
-  int require_auth;
-  uschar *fail_reason = US"server did not advertise AUTH support";
-
   /* Set for IGNOREQUOTA if the response to LHLO specifies support and the
   lmtp_ignore_quota option was set. */


@@ -1313,139 +1532,13 @@ if (continue_hostname == NULL
the business. The host name and address must be available when the
authenticator's client driver is running. */

-  smtp_authenticated = FALSE;
-  client_authenticator = client_authenticated_id = client_authenticated_sender = NULL;
-  require_auth = verify_check_this_host(&(ob->hosts_require_auth), NULL,
-    host->name, host->address, NULL);
-
-  if (esmtp && regex_match_and_setup(regex_AUTH, buffer, 0, -1))
+  switch (yield = smtp_auth(buffer, sizeof(buffer), addrlist, host,
+                ob, esmtp, &inblock, &outblock))
     {
-    uschar *names = string_copyn(expand_nstring[1], expand_nlength[1]);
-    expand_nmax = -1;                          /* reset */
-
-    /* Must not do this check until after we have saved the result of the
-    regex match above. */
-
-    if (require_auth == OK ||
-        verify_check_this_host(&(ob->hosts_try_auth), NULL, host->name,
-          host->address, NULL) == OK)
-      {
-      auth_instance *au;
-      fail_reason = US"no common mechanisms were found";
-
-      DEBUG(D_transport) debug_printf("scanning authentication mechanisms\n");
-
-      /* Scan the configured authenticators looking for one which is configured
-      for use as a client, which is not suppressed by client_condition, and
-      whose name matches an authentication mechanism supported by the server.
-      If one is found, attempt to authenticate by calling its client function.
-      */
-
-      for (au = auths; !smtp_authenticated && au != NULL; au = au->next)
-        {
-        uschar *p = names;
-        if (!au->client ||
-            (au->client_condition != NULL &&
-             !expand_check_condition(au->client_condition, au->name,
-               US"client authenticator")))
-          {
-          DEBUG(D_transport) debug_printf("skipping %s authenticator: %s\n",
-            au->name,
-            (au->client)? "client_condition is false" :
-                          "not configured as a client");
-          continue;
-          }
-
-        /* Loop to scan supported server mechanisms */
-
-        while (*p != 0)
-          {
-          int rc;
-          int len = Ustrlen(au->public_name);
-          while (isspace(*p)) p++;
-
-          if (strncmpic(au->public_name, p, len) != 0 ||
-              (p[len] != 0 && !isspace(p[len])))
-            {
-            while (*p != 0 && !isspace(*p)) p++;
-            continue;
-            }
-
-          /* Found data for a listed mechanism. Call its client entry. Set
-          a flag in the outblock so that data is overwritten after sending so
-          that reflections don't show it. */
-
-          fail_reason = US"authentication attempt(s) failed";
-          outblock.authenticating = TRUE;
-          rc = (au->info->clientcode)(au, &inblock, &outblock,
-            ob->command_timeout, buffer, sizeof(buffer));
-          outblock.authenticating = FALSE;
-          DEBUG(D_transport) debug_printf("%s authenticator yielded %d\n",
-            au->name, rc);
-
-          /* A temporary authentication failure must hold up delivery to
-          this host. After a permanent authentication failure, we carry on
-          to try other authentication methods. If all fail hard, try to
-          deliver the message unauthenticated unless require_auth was set. */
-
-          switch(rc)
-            {
-            case OK:
-            smtp_authenticated = TRUE;   /* stops the outer loop */
-        client_authenticator = au->name;
-        if (au->set_client_id != NULL)
-          client_authenticated_id = expand_string(au->set_client_id);
-            break;
-
-            /* Failure after writing a command */
-
-            case FAIL_SEND:
-            goto SEND_FAILED;
-
-            /* Failure after reading a response */
-
-            case FAIL:
-            if (errno != 0 || buffer[0] != '5') goto RESPONSE_FAILED;
-            log_write(0, LOG_MAIN, "%s authenticator failed H=%s [%s] %s",
-              au->name, host->name, host->address, buffer);
-            break;
-
-            /* Failure by some other means. In effect, the authenticator
-            decided it wasn't prepared to handle this case. Typically this
-            is the result of "fail" in an expansion string. Do we need to
-            log anything here? Feb 2006: a message is now put in the buffer
-            if logging is required. */
-
-            case CANCELLED:
-            if (*buffer != 0)
-              log_write(0, LOG_MAIN, "%s authenticator cancelled "
-                "authentication H=%s [%s] %s", au->name, host->name,
-                host->address, buffer);
-            break;
-
-            /* Internal problem, message in buffer. */
-
-            case ERROR:
-            yield = ERROR;
-            set_errno(addrlist, 0, string_copy(buffer), DEFER, FALSE);
-            goto SEND_QUIT;
-            }
-
-          break;  /* If not authenticated, try next authenticator */
-          }       /* Loop for scanning supported server mechanisms */
-        }         /* Loop for further authenticators */
-      }
-    }
-
-  /* If we haven't authenticated, but are required to, give up. */
-
-  if (require_auth == OK && !smtp_authenticated)
-    {
-    yield = DEFER;
-    set_errno(addrlist, ERRNO_AUTHFAIL,
-      string_sprintf("authentication required but %s", fail_reason), DEFER,
-      FALSE);
-    goto SEND_QUIT;
+    default:        goto SEND_QUIT;
+    case OK:        break;
+    case FAIL_SEND:    goto SEND_FAILED;
+    case FAIL:        goto RESPONSE_FAILED;
     }
   }


@@ -1538,32 +1631,8 @@ Other expansion failures are serious. An empty result is ignored, but there is
otherwise no check - this feature is expected to be used with LMTP and other
cases where non-standard addresses (e.g. without domains) might be required. */

-if (ob->authenticated_sender != NULL)
-  {
-  uschar *new = expand_string(ob->authenticated_sender);
-  if (new == NULL)
-    {
-    if (!expand_string_forcedfail)
-      {
-      uschar *message = string_sprintf("failed to expand "
-        "authenticated_sender: %s", expand_string_message);
-      set_errno(addrlist, 0, message, DEFER, FALSE);
-      return ERROR;
-      }
-    }
-  else if (new[0] != 0) local_authenticated_sender = new;
-  }
-
-/* Add the authenticated sender address if present */
-
-if ((smtp_authenticated || ob->authenticated_sender_force) &&
-    local_authenticated_sender != NULL)
-  {
-  string_format(p, sizeof(buffer) - (p-buffer), " AUTH=%s",
-    auth_xtextencode(local_authenticated_sender,
-    Ustrlen(local_authenticated_sender)));
-  client_authenticated_sender = string_copy(local_authenticated_sender);
-  }
+if (smtp_mail_auth_str(p, sizeof(buffer) - (p-buffer), addrlist, ob))
+    return ERROR;


 /* From here until we send the DATA command, we can make use of PIPELINING
 if the server host supports it. The code has to be able to check the responses
diff --git a/src/src/verify.c b/src/src/verify.c
index 5240457..ea7869d 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -722,11 +722,18 @@ else
         }
       }


+    /* Try to AUTH */
+
+    else done = smtp_auth(responsebuffer, sizeof(responsebuffer),
+    addr, host, ob, esmtp, &inblock, &outblock) == OK  &&
+
+    /* Build a mail-AUTH string (re-using responsebuffer for convenience */
+      !smtp_mail_auth_str(responsebuffer, sizeof(responsebuffer), addr, ob)  &&
+
     /* Send the MAIL command */


-    else done =
-      smtp_write_command(&outblock, FALSE, "MAIL FROM:<%s>\r\n",
-        from_address) >= 0 &&
+      smtp_write_command(&outblock, FALSE, "MAIL FROM:<%s>%s\r\n",
+        from_address, responsebuffer) >= 0 &&
       smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
         '2', callout);


diff --git a/test/confs/0568 b/test/confs/0568
new file mode 100644
index 0000000..dec5b0d
--- /dev/null
+++ b/test/confs/0568
@@ -0,0 +1,70 @@
+# Exim test configuration 0568
+# Recipient callout with AUTH
+
+exim_path = EXIM_PATH
+host_lookup_order = bydns
+primary_hostname = myhost.test.ex
+rfc1413_query_timeout = 0s
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = check_rcpt
+
+queue_only
+
+
+# ----- Authentication -----
+
+begin authenticators
+
+plain:
+  driver = plaintext
+  public_name = PLAIN
+  client_send = ^userx^secret
+  server_advertise_condition =    yes
+  server_prompts =        :
+  server_condition =        yes
+  server_set_id =        $auth2
+
+
+# ----- ACLs -----
+
+begin acl
+
+check_rcpt:
+  accept  verify = recipient/callout
+
+
+# ----- Routers -----
+
+begin routers
+
+r1:
+  driver = accept
+  transport = ${if eq{force}{$domain} {t2}{t1}}
+
+
+# ----- Transports -----
+
+begin transports
+
+t1:
+  driver = smtp
+  hosts = 127.0.0.1
+  port = PORT_S
+  allow_localhost
+  hosts_try_auth = *
+
+t2:
+  driver = smtp
+  hosts = 127.0.0.1
+  port = PORT_S
+  allow_localhost
+  hosts_try_auth = *
+  authenticated_sender= brian
+
+# End
diff --git a/test/scripts/0000-Basic/0568 b/test/scripts/0000-Basic/0568
new file mode 100644
index 0000000..2aa86f4
--- /dev/null
+++ b/test/scripts/0000-Basic/0568
@@ -0,0 +1,76 @@
+# Recipient callout with AUTH
+need_ipv4
+#
+# Variant 1: using authenticated_sender on the transport.
+server PORT_S 1
+220 Welcome
+EHLO
+250-wotcher mate
+250-AUTH PLAIN
+250 Hi
+AUTH
+250 Oh alright then
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+QUIT
+250 OK
+****
+exim -odq -bs
+EHLO the.client
+mail from:<>
+RCPT TO:<abc@force> 
+quit
+****
+#
+#
+# Variant 2: Passing through an authenticated_sender from the MAIL FROM:
+server PORT_S 1
+220 Welcome
+EHLO
+250-wotcher mate
+250-AUTH PLAIN
+250 Hi
+AUTH
+250 Oh alright then
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+QUIT
+250 OK
+****
+exim -odq -bs
+EHLO the.client
+AUTH PLAIN AHVzZXJ4AHNlY3JldA==
+mail from:<> AUTH=freddy
+RCPT TO:<abc@normal> 
+quit
+****
+#
+#
+# Variant 3: An authenticated_sender option on the transport should override
+# a value set by the MAIL FROM:
+server PORT_S 1
+220 Welcome
+EHLO
+250-wotcher mate
+250-AUTH PLAIN
+250 Hi
+AUTH
+250 Oh alright then
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+QUIT
+250 OK
+****
+exim -odq -bs
+EHLO the.client
+AUTH PLAIN AHVzZXJ4AHNlY3JldA==
+mail from:<> AUTH=freddy
+RCPT TO:<def@force> 
+quit
+****
diff --git a/test/stderr/0398 b/test/stderr/0398
index 4e97f4e..0ad9113 100644
--- a/test/stderr/0398
+++ b/test/stderr/0398
@@ -129,6 +129,7 @@ Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
 127.0.0.1 in hosts_avoid_esmtp? no (option unset)
   SMTP>> EHLO mail.test.ex
   SMTP<< 250 OK
+127.0.0.1 in hosts_require_auth? no (option unset)
   SMTP>> MAIL FROM:<>
   SMTP<< 250 OK
   SMTP>> RCPT TO:<qq@remote>
diff --git a/test/stderr/0432 b/test/stderr/0432
index 33e1b98..759c9a8 100644
--- a/test/stderr/0432
+++ b/test/stderr/0432
@@ -92,6 +92,7 @@ Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
 127.0.0.1 in hosts_avoid_esmtp? no (option unset)
   SMTP>> EHLO myhost.test.ex
   SMTP<< 250 OK
+127.0.0.1 in hosts_require_auth? no (option unset)
   SMTP>> MAIL FROM:<>
   SMTP<< 250 OK
   SMTP>> RCPT TO:<x@y>
@@ -246,6 +247,7 @@ MUNGED: ::1 will be omitted in what follows

>>> 127.0.0.1 in hosts_avoid_esmtp? no (option unset)
>>> SMTP>> EHLO myhost.test.ex
>>> SMTP<< 250 OK

+>>> 127.0.0.1 in hosts_require_auth? no (option unset)
>>> SMTP>> MAIL FROM:<>
>>> SMTP<< 250 OK
>>> SMTP>> RCPT TO:<a@b>

diff --git a/test/stderr/5410 b/test/stderr/5410
index f8b31a7..40ef77c 100644
--- a/test/stderr/5410
+++ b/test/stderr/5410
@@ -86,6 +86,7 @@ expanding: ${if eq {$address_data}{userz}{*}{:}}
          250-8BITMIME
          250-PIPELINING
          250 HELP
+127.0.0.1 in hosts_require_auth? no (option unset)
   SMTP>> MAIL FROM:<CALLER@???>
   SMTP<< 250 OK
   SMTP>> RCPT TO:<userx@???>
@@ -218,6 +219,7 @@ skipping: result is not used
 expanding: ${if eq {$address_data}{usery}{*}{:}}
    result: *
 127.0.0.1 in hosts_avoid_tls? yes (matched "*")
+127.0.0.1 in hosts_require_auth? no (option unset)
   SMTP>> MAIL FROM:<CALLER@???>
   SMTP<< 250 OK
   SMTP>> RCPT TO:<usery@???>
@@ -350,6 +352,7 @@ skipping: result is not used
 expanding: ${if eq {$address_data}{usery}{*}{:}}
    result: *
 127.0.0.1 in hosts_avoid_tls? yes (matched "*")
+127.0.0.1 in hosts_require_auth? no (option unset)
   SMTP>> MAIL FROM:<CALLER@???>
   SMTP<< 250 OK
   SMTP>> RCPT TO:<usery@???>
diff --git a/test/stdout/0568 b/test/stdout/0568
new file mode 100644
index 0000000..671998a
--- /dev/null
+++ b/test/stdout/0568
@@ -0,0 +1,82 @@
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at the.client
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-AUTH PLAIN
+250 HELP
+250 OK
+250 Accepted
+221 myhost.test.ex closing connection
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at the.client
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-AUTH PLAIN
+250 HELP
+235 Authentication succeeded
+250 OK
+250 Accepted
+221 myhost.test.ex closing connection
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at the.client
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-AUTH PLAIN
+250 HELP
+235 Authentication succeeded
+250 OK
+250 Accepted
+221 myhost.test.ex closing connection
+
+******** SERVER ********
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Welcome
+EHLO myhost.test.ex
+250-wotcher mate
+250-AUTH PLAIN
+250 Hi
+AUTH PLAIN AHVzZXJ4AHNlY3JldA==
+250 Oh alright then
+MAIL FROM:<> AUTH=brian
+250 OK
+RCPT TO:<abc@force>
+250 OK
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Welcome
+EHLO myhost.test.ex
+250-wotcher mate
+250-AUTH PLAIN
+250 Hi
+AUTH PLAIN AHVzZXJ4AHNlY3JldA==
+250 Oh alright then
+MAIL FROM:<> AUTH=freddy
+250 OK
+RCPT TO:<abc@normal>
+250 OK
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Welcome
+EHLO myhost.test.ex
+250-wotcher mate
+250-AUTH PLAIN
+250 Hi
+AUTH PLAIN AHVzZXJ4AHNlY3JldA==
+250 Oh alright then
+MAIL FROM:<> AUTH=brian
+250 OK
+RCPT TO:<def@force>
+250 OK
+QUIT
+250 OK
+End of script