[exim-cvs] Testsuite: dovecot suthenticator testing

Startseite
Nachricht löschen
Nachricht beantworten
Autor: Exim Git Commits Mailing List
Datum:  
To: exim-cvs
Betreff: [exim-cvs] Testsuite: dovecot suthenticator testing
Gitweb: https://git.exim.org/exim.git/commitdiff/04e5caa9a7e84b2afca642d28096d988cb6802e7
Commit:     04e5caa9a7e84b2afca642d28096d988cb6802e7
Parent:     9ee30919f807678b0bc9f675dcfa73225b486574
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Mon Jan 30 13:31:40 2023 +0000
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Mon Jan 30 13:34:33 2023 +0000


    Testsuite: dovecot suthenticator testing
---
 doc/doc-docbook/spec.xfpt          |  10 ++-
 src/src/auths/check_serv_cond.c    |  10 +--
 src/src/auths/dovecot.c            |  25 +++---
 src/src/auths/plaintext.c          |   6 +-
 test/aux-fixed/3550.dovecot.passwd |   1 +
 test/aux-var-src/3550.dovecot.conf | 163 ++++++++++++++++++++++++++++++++++++
 test/aux-var-src/3551.dovecot.conf | 164 +++++++++++++++++++++++++++++++++++++
 test/confs/3550                    |  68 +++++++++++++++
 test/confs/3551                    |  69 ++++++++++++++++
 test/log/3550                      |   1 +
 test/log/3551                      |   8 ++
 test/mail/3551.userx               |  13 +++
 test/rejectlog/3550                |   1 +
 test/rejectlog/3551                |   5 ++
 test/runtest                       |  15 ++++
 test/scripts/3550-dovecot/3550     |  55 +++++++++++++
 test/scripts/3550-dovecot/3551     |  80 ++++++++++++++++++
 test/scripts/3550-dovecot/REQUIRES |   2 +
 test/stderr/3550                   |  61 ++++++++++++++
 test/stderr/3551                   |  20 +++++
 test/stdout/3550                   |  64 +++++++++++++++
 test/stdout/3551                   |  97 ++++++++++++++++++++++
 22 files changed, 919 insertions(+), 19 deletions(-)


diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index dc4e38c4a..fd2b47f22 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -28293,7 +28293,7 @@ Dovecot 2 POP/IMAP server, which can support a number of authentication methods.
Note that Dovecot must be configured to use auth-client not auth-userdb.
If you are using Dovecot to authenticate POP/IMAP clients, it might be helpful
to use the same mechanisms for SMTP authentication. This is a server
-authenticator only. There is only one option:
+authenticator only. There is only one non-generic option:

.option server_socket dovecot string unset

@@ -28305,6 +28305,7 @@ authenticators for different mechanisms. For example:
dovecot_plain:
driver = dovecot
public_name = PLAIN
+ server_advertise_condition = ${if def:tls_in_cipher}
server_socket = /var/run/dovecot/auth-client
server_set_id = $auth1

@@ -28314,6 +28315,13 @@ dovecot_ntlm:
server_socket = /var/run/dovecot/auth-client
server_set_id = $auth1
.endd
+
+.new
+&*Note*&: plaintext authentication methods such as PLAIN and LOGIN
+should not be advertised on cleartext SMTP connections.
+See the discussion in section &<<SECTplain_TLS>>&.
+.wen
+
If the SMTP connection is encrypted, or if &$sender_host_address$& is equal to
&$received_ip_address$& (that is, the connection is local), the &"secured"&
option is passed in the Dovecot authentication command. If, for a TLS
diff --git a/src/src/auths/check_serv_cond.c b/src/src/auths/check_serv_cond.c
index 5201d2177..1b0430ab1 100644
--- a/src/src/auths/check_serv_cond.c
+++ b/src/src/auths/check_serv_cond.c
@@ -31,9 +31,9 @@ Returns:
*/

 int
-auth_check_serv_cond(auth_instance *ablock)
+auth_check_serv_cond(auth_instance * ablock)
 {
-  return auth_check_some_cond(ablock,
+return auth_check_some_cond(ablock,
       US"server_condition", ablock->server_condition, OK);
 }


@@ -58,10 +58,10 @@ Returns:
*/

 int
-auth_check_some_cond(auth_instance *ablock,
-    uschar *label, uschar *condition, int unset)
+auth_check_some_cond(auth_instance * ablock,
+    uschar * label, uschar * condition, int unset)
 {
-uschar *cond;
+uschar * cond;


HDEBUG(D_auth)
{
diff --git a/src/src/auths/dovecot.c b/src/src/auths/dovecot.c
index ed56ab8cd..85d029c9c 100644
--- a/src/src/auths/dovecot.c
+++ b/src/src/auths/dovecot.c
@@ -97,13 +97,15 @@ static int socket_buffer_left;
enable consistency checks to be done, or anything else that needs
to be set up. */

-void auth_dovecot_init(auth_instance *ablock)
+void
+auth_dovecot_init(auth_instance * ablock)
 {
-auth_dovecot_options_block *ob =
+auth_dovecot_options_block * ob =
        (auth_dovecot_options_block *)(ablock->options_block);


if (!ablock->public_name) ablock->public_name = ablock->name;
if (ob->server_socket) ablock->server = TRUE;
+else DEBUG(D_auth) debug_printf("Dovecot auth driver: no server_socket for %s\n", ablock->public_name);
ablock->client = FALSE;
}

@@ -304,16 +306,14 @@ auth_defer_msg = US"authentication socket protocol error";
 socket_buffer_left = 0;  /* Global, used to read more than a line but return by line */
 for (;;)
   {
-debug_printf("%s %d\n", __FUNCTION__, __LINE__);
   if (!dc_gets(buffer, sizeof(buffer), &cctx))
     OUT("authentication socket read error or premature eof");
-debug_printf("%s %d\n", __FUNCTION__, __LINE__);
   p = buffer + Ustrlen(buffer) - 1;
   if (*p != '\n')
     OUT("authentication socket protocol line too long");


*p = '\0';
- HDEBUG(D_auth) debug_printf("received: '%s'\n", buffer);
+ HDEBUG(D_auth) debug_printf(" DOVECOT<< '%s'\n", buffer);

nargs = strcut(buffer, args, nelem(args));

@@ -423,12 +423,12 @@ if ((
   HDEBUG(D_auth) debug_printf("error sending auth_command: %s\n",
     strerror(errno));


-HDEBUG(D_auth) debug_printf("sent: '%s'\n", auth_command);
+HDEBUG(D_auth) debug_printf(" DOVECOT>> '%s'\n", auth_command);

while (1)
{
- uschar *temp;
- uschar *auth_id_pre = NULL;
+ uschar * temp;
+ uschar * auth_id_pre = NULL;

   if (!dc_gets(buffer, sizeof(buffer), &cctx))
     {
@@ -437,7 +437,7 @@ while (1)
     }


buffer[Ustrlen(buffer) - 1] = 0;
- HDEBUG(D_auth) debug_printf("received: '%s'\n", buffer);
+ HDEBUG(D_auth) debug_printf(" DOVECOT<< '%s'\n", buffer);
nargs = strcut(buffer, args, nelem(args));
HDEBUG(D_auth) debug_strcut(args, nargs, nelem(args));

@@ -471,6 +471,8 @@ while (1)
 #endif
       write(cctx.sock, temp, Ustrlen(temp))) < 0)
     OUT("authentication socket write error");
+
+      HDEBUG(D_auth) debug_printf("  DOVECOT>> '%s'\n", temp);
       break;


     case 'F':
@@ -524,7 +526,10 @@ if (cctx.sock >= 0)
   close(cctx.sock);


/* Expand server_condition as an authorization check */
-return ret == OK ? auth_check_serv_cond(ablock) : ret;
+if (ret == OK) ret = auth_check_serv_cond(ablock);
+
+HDEBUG(D_auth) debug_printf("dovecot auth ret: %s\n", rc_names[ret]);
+return ret;
}


diff --git a/src/src/auths/plaintext.c b/src/src/auths/plaintext.c
index 6692a676e..1392b369f 100644
--- a/src/src/auths/plaintext.c
+++ b/src/src/auths/plaintext.c
@@ -62,9 +62,9 @@ auth_plaintext_init(auth_instance *ablock)
{
auth_plaintext_options_block *ob =
(auth_plaintext_options_block *)(ablock->options_block);
-if (ablock->public_name == NULL) ablock->public_name = ablock->name;
-if (ablock->server_condition != NULL) ablock->server = TRUE;
-if (ob->client_send != NULL) ablock->client = TRUE;
+if (!ablock->public_name) ablock->public_name = ablock->name;
+if (ablock->server_condition) ablock->server = TRUE;
+if (ob->client_send) ablock->client = TRUE;
}


diff --git a/test/aux-fixed/3550.dovecot.passwd b/test/aux-fixed/3550.dovecot.passwd
new file mode 100644
index 000000000..6b22e3b5d
--- /dev/null
+++ b/test/aux-fixed/3550.dovecot.passwd
@@ -0,0 +1 @@
+userx:{PLAIN}secret:4242:4242::/home/user2
diff --git a/test/aux-var-src/3550.dovecot.conf b/test/aux-var-src/3550.dovecot.conf
new file mode 100644
index 000000000..df3f1d105
--- /dev/null
+++ b/test/aux-var-src/3550.dovecot.conf
@@ -0,0 +1,163 @@
+
+base_dir = DIR/tmp
+default_login_user = CALLER
+default_internal_group = CALLERGROUP
+default_internal_user = CALLER
+
+# Disabled POP, IMAP
+protocols =
+
+log_path = DIR/tmp/dovecot.log
+auth_debug = yes
+
+service auth {
+#SASL
+  unix_listener auth-client {
+    mode = 0666
+    user = CALLER
+
+    # this goes in base_dir
+    path = dovecot_auth_socket
+  }
+}
+
+
+service anvil {
+  unix_listener anvil-auth-penalty {
+    mode = 0
+  }
+}
+
+
+
+
+# /usr/share/doc/dovecot/example-config/conf.d/10-auth.conf
+##
+## Authentication processes
+##
+
+# Disable LOGIN command and all other plaintext authentications unless
+# SSL/TLS is used (LOGINDISABLED capability). Note that if the remote IP
+# matches the local IP (ie. you're connecting from the same computer), the
+# connection is considered secure and plaintext authentication is allowed.
+# See also ssl=required setting.
+disable_plaintext_auth = yes
+
+# Authentication cache size (e.g. 10M). 0 means it's disabled. Note that
+# bsdauth and PAM require cache_key to be set for caching to be used.
+#auth_cache_size = 0
+# Time to live for cached data. After TTL expires the cached record is no
+# longer used, *except* if the main database lookup returns internal failure.
+# We also try to handle password changes automatically: If user's previous
+# authentication was successful, but this one wasn't, the cache isn't used.
+# For now this works only with plaintext authentication.
+#auth_cache_ttl = 1 hour
+# TTL for negative hits (user not found, password mismatch).
+# 0 disables caching them completely.
+#auth_cache_negative_ttl = 1 hour
+auth_cache_negative_ttl = 0
+
+# Space separated list of realms for SASL authentication mechanisms that need
+# them. You can leave it empty if you don't want to support multiple realms.
+# Many clients simply use the first one listed here, so keep the default realm
+# first.
+#auth_realms =
+
+# Default realm/domain to use if none was specified. This is used for both
+# SASL realms and appending @domain to username in plaintext logins.
+#auth_default_realm = 
+
+# List of allowed characters in username. If the user-given username contains
+# a character not listed in here, the login automatically fails. This is just
+# an extra check to make sure user can't exploit any potential quote escaping
+# vulnerabilities with SQL/LDAP databases. If you want to allow all characters,
+# set this value to empty.
+#auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@
+
+# Username character translations before it's looked up from databases. The
+# value contains series of from -> to characters. For example "#@/@" means
+# that '#' and '/' characters are translated to '@'.
+#auth_username_translation =
+
+# Username formatting before it's looked up from databases. You can use
+# the standard variables here, eg. %Lu would lowercase the username, %n would
+# drop away the domain if it was given, or "%n-AT-%d" would change the '@' into
+# "-AT-". This translation is done after auth_username_translation changes.
+#auth_username_format = %Lu
+
+# If you want to allow master users to log in by specifying the master
+# username within the normal username string (ie. not using SASL mechanism's
+# support for it), you can specify the separator character here. The format
+# is then <username><separator><master username>. UW-IMAP uses "*" as the
+# separator, so that could be a good choice.
+#auth_master_user_separator =
+
+# Username to use for users logging in with ANONYMOUS SASL mechanism
+#auth_anonymous_username = anonymous
+
+# Maximum number of dovecot-auth worker processes. They're used to execute
+# blocking passdb and userdb queries (eg. MySQL and PAM). They're
+# automatically created and destroyed as needed.
+#auth_worker_max_count = 30
+
+# Host name to use in GSSAPI principal names. The default is to use the
+# name returned by gethostname(). Use "$ALL" (with quotes) to allow all keytab
+# entries.
+#auth_gssapi_hostname =
+
+# Kerberos keytab to use for the GSSAPI mechanism. Will use the system
+# default (usually /etc/krb5.keytab) if not specified. You may need to change
+# the auth service to run as root to be able to read this file.
+#auth_krb5_keytab = 
+
+# Do NTLM and GSS-SPNEGO authentication using Samba's winbind daemon and
+# ntlm_auth helper. <doc/wiki/Authentication/Mechanisms/Winbind.txt>
+#auth_use_winbind = no
+
+# Path for Samba's ntlm_auth helper binary.
+#auth_winbind_helper_path = /usr/bin/ntlm_auth
+
+# Time to delay before replying to failed authentications.
+#auth_failure_delay = 2 secs
+auth_failure_delay = 0 secs
+
+# Require a valid SSL client certificate or the authentication fails.
+#auth_ssl_require_client_cert = no
+
+# Take the username from client's SSL certificate, using 
+# X509_NAME_get_text_by_NID() which returns the subject's DN's
+# CommonName. 
+#auth_ssl_username_from_cert = no
+
+# Space separated list of wanted authentication mechanisms:
+#   plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp
+#   gss-spnego
+# NOTE: See also disable_plaintext_auth setting.
+auth_mechanisms = plain login
+
+##
+## Password and user databases
+##
+
+#
+# Password database is used to verify user's password (and nothing more).
+# You can have multiple passdbs and userdbs. This is useful if you want to
+# allow both system users (/etc/passwd) and virtual users to login without
+# duplicating the system users into virtual database.
+#
+# <doc/wiki/PasswordDatabase.txt>
+#
+# User database specifies where mails are located and what user/group IDs
+# own them. For single-UID configuration use "static" userdb.
+#
+# <doc/wiki/UserDatabase.txt>
+
+passdb {
+  driver = passwd-file
+  args = DIR/aux-fixed/3550.dovecot.passwd
+}
+userdb {
+  driver = passwd-file
+  args = DIR/aux-fixed/3550.dovecot.passwd
+}
+
diff --git a/test/aux-var-src/3551.dovecot.conf b/test/aux-var-src/3551.dovecot.conf
new file mode 100644
index 000000000..2b34e3beb
--- /dev/null
+++ b/test/aux-var-src/3551.dovecot.conf
@@ -0,0 +1,164 @@
+
+base_dir = DIR/tmp
+default_login_user = CALLER
+default_internal_group = CALLERGROUP
+default_internal_user = CALLER
+
+# Disabled POP, IMAP
+protocols =
+
+log_path = DIR/tmp/dovecot.log
+auth_debug = yes
+auth_debug_passwords = yes
+
+service auth {
+#SASL
+  unix_listener auth-client {
+    mode = 0666
+    user = CALLER
+
+    # this goes in base_dir
+    path = dovecot_auth_socket
+  }
+}
+
+
+service anvil {
+  unix_listener anvil-auth-penalty {
+    mode = 0
+  }
+}
+
+
+
+
+# /usr/share/doc/dovecot/example-config/conf.d/10-auth.conf
+##
+## Authentication processes
+##
+
+# Disable LOGIN command and all other plaintext authentications unless
+# SSL/TLS is used (LOGINDISABLED capability). Note that if the remote IP
+# matches the local IP (ie. you're connecting from the same computer), the
+# connection is considered secure and plaintext authentication is allowed.
+# See also ssl=required setting.
+disable_plaintext_auth = yes
+
+# Authentication cache size (e.g. 10M). 0 means it's disabled. Note that
+# bsdauth and PAM require cache_key to be set for caching to be used.
+#auth_cache_size = 0
+# Time to live for cached data. After TTL expires the cached record is no
+# longer used, *except* if the main database lookup returns internal failure.
+# We also try to handle password changes automatically: If user's previous
+# authentication was successful, but this one wasn't, the cache isn't used.
+# For now this works only with plaintext authentication.
+#auth_cache_ttl = 1 hour
+# TTL for negative hits (user not found, password mismatch).
+# 0 disables caching them completely.
+#auth_cache_negative_ttl = 1 hour
+auth_cache_negative_ttl = 0
+
+# Space separated list of realms for SASL authentication mechanisms that need
+# them. You can leave it empty if you don't want to support multiple realms.
+# Many clients simply use the first one listed here, so keep the default realm
+# first.
+#auth_realms =
+
+# Default realm/domain to use if none was specified. This is used for both
+# SASL realms and appending @domain to username in plaintext logins.
+#auth_default_realm = 
+
+# List of allowed characters in username. If the user-given username contains
+# a character not listed in here, the login automatically fails. This is just
+# an extra check to make sure user can't exploit any potential quote escaping
+# vulnerabilities with SQL/LDAP databases. If you want to allow all characters,
+# set this value to empty.
+#auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@
+
+# Username character translations before it's looked up from databases. The
+# value contains series of from -> to characters. For example "#@/@" means
+# that '#' and '/' characters are translated to '@'.
+#auth_username_translation =
+
+# Username formatting before it's looked up from databases. You can use
+# the standard variables here, eg. %Lu would lowercase the username, %n would
+# drop away the domain if it was given, or "%n-AT-%d" would change the '@' into
+# "-AT-". This translation is done after auth_username_translation changes.
+#auth_username_format = %Lu
+
+# If you want to allow master users to log in by specifying the master
+# username within the normal username string (ie. not using SASL mechanism's
+# support for it), you can specify the separator character here. The format
+# is then <username><separator><master username>. UW-IMAP uses "*" as the
+# separator, so that could be a good choice.
+#auth_master_user_separator =
+
+# Username to use for users logging in with ANONYMOUS SASL mechanism
+#auth_anonymous_username = anonymous
+
+# Maximum number of dovecot-auth worker processes. They're used to execute
+# blocking passdb and userdb queries (eg. MySQL and PAM). They're
+# automatically created and destroyed as needed.
+#auth_worker_max_count = 30
+
+# Host name to use in GSSAPI principal names. The default is to use the
+# name returned by gethostname(). Use "$ALL" (with quotes) to allow all keytab
+# entries.
+#auth_gssapi_hostname =
+
+# Kerberos keytab to use for the GSSAPI mechanism. Will use the system
+# default (usually /etc/krb5.keytab) if not specified. You may need to change
+# the auth service to run as root to be able to read this file.
+#auth_krb5_keytab = 
+
+# Do NTLM and GSS-SPNEGO authentication using Samba's winbind daemon and
+# ntlm_auth helper. <doc/wiki/Authentication/Mechanisms/Winbind.txt>
+#auth_use_winbind = no
+
+# Path for Samba's ntlm_auth helper binary.
+#auth_winbind_helper_path = /usr/bin/ntlm_auth
+
+# Time to delay before replying to failed authentications.
+#auth_failure_delay = 2 secs
+auth_failure_delay = 0 secs
+
+# Require a valid SSL client certificate or the authentication fails.
+#auth_ssl_require_client_cert = no
+
+# Take the username from client's SSL certificate, using 
+# X509_NAME_get_text_by_NID() which returns the subject's DN's
+# CommonName. 
+#auth_ssl_username_from_cert = no
+
+# Space separated list of wanted authentication mechanisms:
+#   plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp
+#   gss-spnego
+# NOTE: See also disable_plaintext_auth setting.
+auth_mechanisms = plain login
+
+##
+## Password and user databases
+##
+
+#
+# Password database is used to verify user's password (and nothing more).
+# You can have multiple passdbs and userdbs. This is useful if you want to
+# allow both system users (/etc/passwd) and virtual users to login without
+# duplicating the system users into virtual database.
+#
+# <doc/wiki/PasswordDatabase.txt>
+#
+# User database specifies where mails are located and what user/group IDs
+# own them. For single-UID configuration use "static" userdb.
+#
+# <doc/wiki/UserDatabase.txt>
+
+passdb {
+  driver = passwd-file
+  args = DIR/aux-fixed/3550.dovecot.passwd
+}
+userdb {
+  driver = passwd-file
+  args = DIR/aux-fixed/3550.dovecot.passwd
+}
+
diff --git a/test/confs/3550 b/test/confs/3550
new file mode 100644
index 000000000..46d35bfbd
--- /dev/null
+++ b/test/confs/3550
@@ -0,0 +1,68 @@
+# Exim test configuration 3550
+
+AUTHS=DIR/tmp/dovecot_auth_socket
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+domainlist local_domains = test.ex : *.test.ex
+
+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_rcpt = check_recipient
+auth_advertise_hosts = +auth_hosts : !+relay_hosts : +auth_relay_hosts : \
+                       10.0.0.5
+smtp_accept_max_nonmail = 20
+trusted_users = CALLER
+
+
+# ----- ACL -----
+
+begin acl
+
+check_recipient:
+  deny     message = authentication required
+          !authenticated = *
+  accept
+
+# ----- Authentication -----
+
+begin authenticators
+
+plain:
+  driver =        dovecot
+  public_name =        PLAIN
+  server_socket =    AUTHS
+  server_condition =    ${if eq {$auth1}{userx} {yes}{no}}
+  server_set_id =    $auth1
+
+# ----- Routers -----
+
+begin routers
+
+localuser:
+  driver =    accept
+  local_parts =    userx
+  transport =    appendfile
+
+
+# ----- Transports -----
+
+begin transports
+
+appendfile:
+  driver =    appendfile
+  delivery_date_add
+  envelope_to_add
+  file =    DIR/test-mail/$local_part
+  create_file =    DIR/test-mail
+  return_path_add
+  user =    CALLER
+
+
+# End
diff --git a/test/confs/3551 b/test/confs/3551
new file mode 100644
index 000000000..ef85ee006
--- /dev/null
+++ b/test/confs/3551
@@ -0,0 +1,69 @@
+# Exim test configuration 3550
+
+AUTHS=DIR/tmp/dovecot_auth_socket
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+domainlist local_domains = test.ex : *.test.ex
+
+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_rcpt = check_recipient
+auth_advertise_hosts = +auth_hosts : !+relay_hosts : +auth_relay_hosts : \
+                       10.0.0.5
+smtp_accept_max_nonmail = 20
+trusted_users = CALLER
+
+
+# ----- ACL -----
+
+begin acl
+
+check_recipient:
+  deny     message = authentication required
+          !authenticated = *
+  accept
+
+# ----- Authentication -----
+
+begin authenticators
+
+login:
+  driver =        dovecot
+  public_name =        LOGIN
+  server_socket =    AUTHS
+  server_condition =    ${if eq {$auth1}{userx} {yes}{no}}
+  server_set_id =    $auth1
+
+
+# ----- Routers -----
+
+begin routers
+
+localuser:
+  driver =    accept
+  local_parts =    userx
+  transport =    appendfile
+
+
+# ----- Transports -----
+
+begin transports
+
+appendfile:
+  driver =    appendfile
+  delivery_date_add
+  envelope_to_add
+  file =    DIR/test-mail/$local_part
+  create_file =    DIR/test-mail
+  return_path_add
+  user =    CALLER
+
+
+# End
diff --git a/test/log/3550 b/test/log/3550
new file mode 100644
index 000000000..df8a9686d
--- /dev/null
+++ b/test/log/3550
@@ -0,0 +1 @@
+1999-03-02 09:44:33 plain authenticator failed for (test.host) [10.0.0.1] U=CALLER: 535 Incorrect authentication data (set_id=eserx)
diff --git a/test/log/3551 b/test/log/3551
new file mode 100644
index 000000000..0f295cbca
--- /dev/null
+++ b/test/log/3551
@@ -0,0 +1,8 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= userx@??? H=(test.host) [10.0.0.1] U=CALLER P=esmtpa A=login:userx S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx <userx@???> R=localuser T=appendfile
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 login authenticator failed for (test.host) [10.0.0.1] U=CALLER: 535 Incorrect authentication data
+1999-03-02 09:44:33 login authenticator failed for (test.host) [10.0.0.1] U=CALLER: 535 Incorrect authentication data
+1999-03-02 09:44:33 login authenticator failed for (test.host) [10.0.0.1] U=CALLER: 501 Authentication cancelled
+1999-03-02 09:44:33 login authenticator failed for (test.host) [10.0.0.1] U=CALLER: 535 Incorrect authentication data
+1999-03-02 09:44:33 login authenticator failed for (test.host) [10.0.0.1] U=CALLER: 535 Incorrect authentication data (set_id=\001rserx)
diff --git a/test/mail/3551.userx b/test/mail/3551.userx
new file mode 100644
index 000000000..11f9e5654
--- /dev/null
+++ b/test/mail/3551.userx
@@ -0,0 +1,13 @@
+From userx@??? Tue Mar 02 09:44:33 1999
+Return-path: <userx@???>
+Envelope-to: userx@???
+Delivery-date: Tue, 2 Mar 1999 09:44:33 +0000
+Received: from [10.0.0.1] (helo=test.host ident=CALLER)
+    by myhost.test.ex with esmtpa (Exim x.yz)
+    (envelope-from <userx@???>)
+    id 10HmaX-0005vi-00
+    for userx@???;
+    Tue, 2 Mar 1999 09:44:33 +0000
+
+Testing authenticated.
+
diff --git a/test/rejectlog/3550 b/test/rejectlog/3550
new file mode 100644
index 000000000..df8a9686d
--- /dev/null
+++ b/test/rejectlog/3550
@@ -0,0 +1 @@
+1999-03-02 09:44:33 plain authenticator failed for (test.host) [10.0.0.1] U=CALLER: 535 Incorrect authentication data (set_id=eserx)
diff --git a/test/rejectlog/3551 b/test/rejectlog/3551
new file mode 100644
index 000000000..2fe157f5c
--- /dev/null
+++ b/test/rejectlog/3551
@@ -0,0 +1,5 @@
+1999-03-02 09:44:33 login authenticator failed for (test.host) [10.0.0.1] U=CALLER: 535 Incorrect authentication data
+1999-03-02 09:44:33 login authenticator failed for (test.host) [10.0.0.1] U=CALLER: 535 Incorrect authentication data
+1999-03-02 09:44:33 login authenticator failed for (test.host) [10.0.0.1] U=CALLER: 501 Authentication cancelled
+1999-03-02 09:44:33 login authenticator failed for (test.host) [10.0.0.1] U=CALLER: 535 Incorrect authentication data
+1999-03-02 09:44:33 login authenticator failed for (test.host) [10.0.0.1] U=CALLER: 535 Incorrect authentication data (set_id=\001rserx)
diff --git a/test/runtest b/test/runtest
index 84cf4df4f..5e4b160b9 100755
--- a/test/runtest
+++ b/test/runtest
@@ -3206,6 +3206,20 @@ if (defined $parm_lookups{redis})
   }
 }


+sub check_running_dovecot
+{
+system('dovecot --version >/dev/null');
+if ($? == 0)
+ {
+ print "Dovecot appears to be available\n";
+ $parm_running{dovecot} = ' ';
+ }
+else
+ {
+ print "Dovecot not found\n";
+ }
+}
+


###############################################################################
@@ -3568,6 +3582,7 @@ if (defined $parm_support{Content_Scanning})
check_running_clamav();
}
check_running_redis();
+check_running_dovecot();

 ##################################################
 #         Test for the basic requirements        #
diff --git a/test/scripts/3550-dovecot/3550 b/test/scripts/3550-dovecot/3550
new file mode 100644
index 000000000..803de86e3
--- /dev/null
+++ b/test/scripts/3550-dovecot/3550
@@ -0,0 +1,55 @@
+# dovecot server auth, PLAIN
+#
+mkdir DIR/tmp
+#
+background
+dovecot -F -c DIR/aux-var/TESTNUM.dovecot.conf
+****
+sleep 1
+#
+#
+#
+#
+### Lack of attempt to auth
+exim -bh 10.0.0.2
+HELO test
+MAIL FROM:<junk@???>
+RCPT TO:<fail_no_auth@???>
+QUIT
+****
+#
+### PLAIN/userx/secret
+exim -bs -oMa 10.0.0.1
+EHLO test.host
+AUTH PLAIN AHVzZXJ4AHNlY3JldA==
+QUIT
+****
+### ditto, split over two lines
+exim -bs -oMa 10.0.0.1
+EHLO test.host
+AUTH PLAIN 
+AHVzZXJ4AHNlY3JldA==
+QUIT
+****
+#
+#
+### Check auth_advertise_hosts no-match
+exim -bh 10.0.0.4
+ehlo test.host
+quit
+****
+#
+#
+### PLAIN (bad auth)   should fail
+exim -bs -oMa 10.0.0.1
+ehlo test.host
+auth plain AGVzZXJ4AHNlY3JldA==
+quit
+****
+#
+#
+### Shut down dovecot
+killdaemon
+#
+sudo rm -fr DIR/tmp
+no_msglog_check
diff --git a/test/scripts/3550-dovecot/3551 b/test/scripts/3550-dovecot/3551
new file mode 100644
index 000000000..9bcb5ce9b
--- /dev/null
+++ b/test/scripts/3550-dovecot/3551
@@ -0,0 +1,80 @@
+# dovecot server auth, LOGIN
+#
+mkdir DIR/tmp
+#
+background
+dovecot -F -c DIR/aux-var/TESTNUM.dovecot.conf
+****
+sleep 1
+#
+#
+#
+### LOGIN/userx/secret
+exim -odi -bs -oMa 10.0.0.1
+EHLO test.host
+AUTH LOGIN
+dXNlcng=
+c2VjcmV0
+MAIL FROM:<userx@???>
+RCPT TO:<userx@???>
+DATA
+Testing authenticated.
+.
+quit
+****
+### ditto, on two lines from client rather than three; fails
+###  (not legit; the username & passwd should be suplied separately in response to prompts)
+# the Exim "plaintext" authenticator is fine with it, but it's outside what we know of the "specification"
+exim -bs -oMa 10.0.0.1
+ehlo test.host
+AUTH LOGIN
+dXNlcngAc2VjcmV0
+quit
+****
+### ditto, on one line; fails
+exim -bs -oMa 10.0.0.1
+ehlo test.host
+AUTH LOGIN dXNlcngAc2VjcmV0
+quit
+****
+### ditto, a different split of two lines; passes (though not strictly within spec)
+exim -bs -oMa 10.0.0.1
+ehlo test.host
+AUTH LOGIN dXNlcng=
+c2VjcmV0
+quit
+****
+### LOGIN - cancelled part-way through (returns a fail)
+exim -bs -oMa 10.0.0.1
+ehlo test.host
+AUTH LOGIN
+dXNlcng=
+*
+quit
+****
+#
+#
+### LOGIN (empty username; bad auth)   should fail
+exim -odi -bs -oMa 10.0.0.1
+ehlo test.host
+AUTH LOGIN
+
+c2VjcmV0
+quit
+****
+#
+### LOGIN (bad username; bad auth)   should fail
+exim -odi -bs -oMa 10.0.0.1
+ehlo test.host
+AUTH LOGIN
+DXNlcng=
+c2VjcmV0
+quit
+****
+#
+#
+### Shut down dovecot
+killdaemon
+#
+sudo rm -fr DIR/tmp
+no_msglog_check
diff --git a/test/scripts/3550-dovecot/REQUIRES b/test/scripts/3550-dovecot/REQUIRES
new file mode 100644
index 000000000..2d95fc53d
--- /dev/null
+++ b/test/scripts/3550-dovecot/REQUIRES
@@ -0,0 +1,2 @@
+authenticator dovecot
+running dovecot
diff --git a/test/stderr/3550 b/test/stderr/3550
new file mode 100644
index 000000000..c8fef7ef3
--- /dev/null
+++ b/test/stderr/3550
@@ -0,0 +1,61 @@
+### Lack of attempt to auth
+>>> host in hosts_connection_nolog? no (option unset)
+>>> host in host_lookup? no (option unset)
+>>> host in host_reject_connection? no (option unset)
+>>> host in sender_unqualified_hosts? no (option unset)
+>>> 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)
+>>> test in helo_lookup_domains?
+>>>  list element: @
+>>>  list element: @[]
+>>> test in helo_lookup_domains? no (end of list)
+>>> using ACL "check_recipient"
+>>> processing "deny" (TESTSUITE/test-config 29)
+>>>   message: authentication required
+>>> check !authenticated = *
+>>> deny: condition test succeeded in ACL "check_recipient"
+>>> end of ACL "check_recipient": DENY
+LOG: H=(test) [10.0.0.2] F=<junk@???> rejected RCPT <fail_no_auth@???>: authentication required
+### PLAIN/userx/secret
+### ditto, split over two lines
+### Check auth_advertise_hosts no-match
+>>> host in hosts_connection_nolog? no (option unset)
+>>> host in host_lookup? no (option unset)
+>>> host in host_reject_connection? no (option unset)
+>>> host in sender_unqualified_hosts? no (option unset)
+>>> 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)
+>>> test.host in helo_lookup_domains?
+>>>  list element: @
+>>>  list element: @[]
+>>> test.host in helo_lookup_domains? no (end of list)
+>>> host in dsn_advertise_hosts? no (option unset)
+>>> host in pipelining_advertise_hosts?
+>>>  list element: *
+>>>  host in pipelining_advertise_hosts? yes (matched "*")
+>>> host in auth_advertise_hosts?
+>>>  list element: +auth_hosts
+>>>  host in "10.0.0.1"?
+>>>   list element: 10.0.0.1
+>>>  host in "10.0.0.1"? no (end of list)
+>>>  list element: !+relay_hosts
+>>>  host in "10.0.0.4"?
+>>>   list element: 10.0.0.4
+>>>   host in "10.0.0.4"? yes (matched "10.0.0.4")
+>>>  host in auth_advertise_hosts? no (matched "!+relay_hosts")
+>>> host in chunking_advertise_hosts?
+>>> host in chunking_advertise_hosts? no (end of list)
+### PLAIN (bad auth)   should fail
+### Shut down dovecot
+
+******** SERVER ********
+### Lack of attempt to auth
+### PLAIN/userx/secret
+### ditto, split over two lines
+### Check auth_advertise_hosts no-match
+### PLAIN (bad auth)   should fail
+### Shut down dovecot
diff --git a/test/stderr/3551 b/test/stderr/3551
new file mode 100644
index 000000000..064d108b7
--- /dev/null
+++ b/test/stderr/3551
@@ -0,0 +1,20 @@
+### LOGIN/userx/secret
+### ditto, on two lines from client rather than three; fails
+###  (not legit; the username & passwd should be suplied separately in response to prompts)
+### ditto, on one line; fails
+### ditto, a different split of two lines; passes (though not strictly within spec)
+### LOGIN - cancelled part-way through (returns a fail)
+### LOGIN (empty username; bad auth)   should fail
+### LOGIN (bad username; bad auth)   should fail
+### Shut down dovecot
+
+******** SERVER ********
+### LOGIN/userx/secret
+### ditto, on two lines from client rather than three; fails
+###  (not legit; the username & passwd should be suplied separately in response to prompts)
+### ditto, on one line; fails
+### ditto, a different split of two lines; passes (though not strictly within spec)
+### LOGIN - cancelled part-way through (returns a fail)
+### LOGIN (empty username; bad auth)   should fail
+### LOGIN (bad username; bad auth)   should fail
+### Shut down dovecot
diff --git a/test/stdout/3550 b/test/stdout/3550
new file mode 100644
index 000000000..5dc50295e
--- /dev/null
+++ b/test/stdout/3550
@@ -0,0 +1,64 @@
+### Lack of attempt to auth
+
+**** SMTP testing session as if from host 10.0.0.2
+**** but without any ident (RFC 1413) callback.
+**** This is not for real!
+
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250 myhost.test.ex Hello test [10.0.0.2]
+250 OK
+550 authentication required
+221 myhost.test.ex closing connection
+### PLAIN/userx/secret
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.host [10.0.0.1]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-AUTH PLAIN
+250 HELP
+235 Authentication succeeded
+221 myhost.test.ex closing connection
+### ditto, split over two lines
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.host [10.0.0.1]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-AUTH PLAIN
+250 HELP
+334 
+235 Authentication succeeded
+221 myhost.test.ex closing connection
+### Check auth_advertise_hosts no-match
+
+**** SMTP testing session as if from host 10.0.0.4
+**** but without any ident (RFC 1413) callback.
+**** This is not for real!
+
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello test.host [10.0.0.4]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250 HELP
+221 myhost.test.ex closing connection
+### PLAIN (bad auth)   should fail
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.host [10.0.0.1]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-AUTH PLAIN
+250 HELP
+535 Incorrect authentication data
+221 myhost.test.ex closing connection
+### Shut down dovecot
+
+******** SERVER ********
+### Lack of attempt to auth
+### PLAIN/userx/secret
+### ditto, split over two lines
+### Check auth_advertise_hosts no-match
+### PLAIN (bad auth)   should fail
+### Shut down dovecot
diff --git a/test/stdout/3551 b/test/stdout/3551
new file mode 100644
index 000000000..8d9d882f7
--- /dev/null
+++ b/test/stdout/3551
@@ -0,0 +1,97 @@
+### LOGIN/userx/secret
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.host [10.0.0.1]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-AUTH LOGIN
+250 HELP
+334 VXNlcm5hbWU6
+334 UGFzc3dvcmQ6
+235 Authentication succeeded
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmaX-0005vi-00
+221 myhost.test.ex closing connection
+### ditto, on two lines from client rather than three; fails
+###  (not legit; the username & passwd should be suplied separately in response to prompts)
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.host [10.0.0.1]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-AUTH LOGIN
+250 HELP
+334 VXNlcm5hbWU6
+535 Incorrect authentication data
+221 myhost.test.ex closing connection
+### ditto, on one line; fails
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.host [10.0.0.1]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-AUTH LOGIN
+250 HELP
+535 Incorrect authentication data
+221 myhost.test.ex closing connection
+### ditto, a different split of two lines; passes (though not strictly within spec)
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.host [10.0.0.1]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-AUTH LOGIN
+250 HELP
+334 UGFzc3dvcmQ6
+235 Authentication succeeded
+221 myhost.test.ex closing connection
+### LOGIN - cancelled part-way through (returns a fail)
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.host [10.0.0.1]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-AUTH LOGIN
+250 HELP
+334 VXNlcm5hbWU6
+334 UGFzc3dvcmQ6
+501 Authentication cancelled
+221 myhost.test.ex closing connection
+### LOGIN (empty username; bad auth)   should fail
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.host [10.0.0.1]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-AUTH LOGIN
+250 HELP
+334 VXNlcm5hbWU6
+535 Incorrect authentication data
+500 unrecognized command
+221 myhost.test.ex closing connection
+### LOGIN (bad username; bad auth)   should fail
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.host [10.0.0.1]
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250-AUTH LOGIN
+250 HELP
+334 VXNlcm5hbWU6
+535 Incorrect authentication data
+500 unrecognized command
+221 myhost.test.ex closing connection
+### Shut down dovecot
+
+******** SERVER ********
+### LOGIN/userx/secret
+### ditto, on two lines from client rather than three; fails
+###  (not legit; the username & passwd should be suplied separately in response to prompts)
+### ditto, on one line; fails
+### ditto, a different split of two lines; passes (though not strictly within spec)
+### LOGIN - cancelled part-way through (returns a fail)
+### LOGIN (empty username; bad auth)   should fail
+### LOGIN (bad username; bad auth)   should fail
+### Shut down dovecot