From 14aa5a05b6399f98744f9542765288313d0bfb9d Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Mon, 2 Oct 2006 13:38:17 +0000 Subject: [PATCH] Added dovecot authenticator. --- doc/doc-txt/ChangeLog | 17 +- doc/doc-txt/NewStuff | 22 ++- src/ACKNOWLEDGMENTS | 5 +- src/scripts/MakeLinks | 4 +- src/src/EDITME | 3 +- src/src/auths/Makefile | 6 +- src/src/auths/dovecot.c | 283 +++++++++++++++++++++++++++++ src/src/auths/dovecot.h | 30 +++ src/src/config.h.defaults | 3 +- src/src/drtables.c | 19 +- src/src/exim.c | 5 +- test/confs/3650 | 39 ++++ test/log/3650 | 4 + test/rejectlog/3650 | 3 + test/scripts/3650-Dovecot/3650 | 18 ++ test/scripts/3650-Dovecot/REQUIRES | 2 + test/stderr/3650 | 2 + test/stdout/3650 | 21 +++ 18 files changed, 475 insertions(+), 11 deletions(-) create mode 100644 src/src/auths/dovecot.c create mode 100644 src/src/auths/dovecot.h create mode 100644 test/confs/3650 create mode 100644 test/log/3650 create mode 100644 test/rejectlog/3650 create mode 100644 test/scripts/3650-Dovecot/3650 create mode 100644 test/scripts/3650-Dovecot/REQUIRES create mode 100644 test/stderr/3650 create mode 100644 test/stdout/3650 diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 261a42c51..d19dddad2 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.399 2006/09/26 13:51:57 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.400 2006/10/02 13:38:17 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -64,6 +64,21 @@ PH/11 Callouts were setting the name used for EHLO/HELO from $smtp_active_ there is no remote transport (possible with a router that sets up host addresses), $smtp_active_hostname is used. +PH/12 Installed Andrey Panin's patch to add a dovecot authenticator. Various + tweaks were necessary in order to get it to work: + (a) The code assumed that strncpy() returns a negative number on buffer + overflow, which isn't the case. Replaced with Exim's string_format() + function. + (b) There were several signed/unsigned issues. I just did the minimum + hacking in of casts. There is scope for a larger refactoring. + (c) The code used strcasecmp() which is not a standard C function. + Replaced with Exim's strcmpic() function. + (d) The code set only $1; it now sets $auth1 as well. + (e) A simple test gave the error "authentication client didn't specify + service in request". It would seem that Dovecot has changed its + interface. Fortunately there's a specification; I followed it and + changed what the client sends and it appears to be working now. + Exim version 4.63 ----------------- diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index ae4043cc1..263df8776 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/NewStuff,v 1.111 2006/09/25 10:14:20 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/NewStuff,v 1.112 2006/10/02 13:38:18 ph10 Exp $ New Features in Exim -------------------- @@ -50,6 +50,26 @@ Version 4.64 The modifier can be used in SMTP and non-SMTP ACLs. It applies to both permanent and temporary rejections. +3. There is a new authenticator called "dovecot". This is an interface to the + authentication facility of the Dovecot POP/IMAP server, which can support a + number of authentication methods. 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. The only option is + server_socket, which must specify the socket which is the interface to + Dovecot authentication. The public_name option must specify an + authentication mechanism that Dovecot is configured to support. You can have + several authenticators for different mechanisms. For example: + + dovecot_plain: + driver = PLAIN + server_name = /var/run/dovecot/auth-client + server_setid = $auth1 + + dovecot_ntlm: + driver = NTLM + server_name = /var/run/dovecot/auth-client + server_setid = $auth1 + Version 4.63 ------------ diff --git a/src/ACKNOWLEDGMENTS b/src/ACKNOWLEDGMENTS index 43b171e00..0a9259481 100644 --- a/src/ACKNOWLEDGMENTS +++ b/src/ACKNOWLEDGMENTS @@ -1,4 +1,4 @@ -$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.55 2006/09/19 11:28:44 ph10 Exp $ +$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.56 2006/10/02 13:38:18 ph10 Exp $ EXIM ACKNOWLEDGEMENTS @@ -20,7 +20,7 @@ relatively small patches. Philip Hazel Lists created: 20 November 2002 -Last updated: 19 September 2006 +Last updated: 02 October 2006 THE OLD LIST @@ -210,6 +210,7 @@ Pete Naylor Patch for LDAP TCP connect timeout setting Alexander Newmann Diagnosing and patching obscure and subtle socket bug Matthew Newton Patch for exicyclog log location problem Marcin Owsiany Diagnosis of a tricky timeout failure bug +Andrey Panin Dovecot authenticator Eric Parusel Patch for tls_remember_esmtp Gaige Paulsen Amended Darwin config files Richard Premdas Patch for PAM buglet diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 120a25b9d..d38f8b00c 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -1,5 +1,5 @@ #!/bin/sh -# $Cambridge: exim/src/scripts/MakeLinks,v 1.6 2005/08/01 13:20:28 ph10 Exp $ +# $Cambridge: exim/src/scripts/MakeLinks,v 1.7 2006/10/02 13:38:18 ph10 Exp $ # Script to build links for all the exim source files from the system- # specific build directory. It should be run from within that directory. @@ -177,6 +177,8 @@ ln -s ../../src/auths/pwcheck.c pwcheck.c ln -s ../../src/auths/pwcheck.h pwcheck.h ln -s ../../src/auths/auth-spa.c auth-spa.c ln -s ../../src/auths/auth-spa.h auth-spa.h +ln -s ../../src/auths/dovecot.c dovecot.c +ln -s ../../src/auths/dovecot.h dovecot.h ln -s ../../src/auths/sha1.c sha1.c ln -s ../../src/auths/spa.c spa.c ln -s ../../src/auths/spa.h spa.h diff --git a/src/src/EDITME b/src/src/EDITME index 135189d0f..17f83297e 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -1,4 +1,4 @@ -# $Cambridge: exim/src/src/EDITME,v 1.16 2005/10/12 15:45:38 ph10 Exp $ +# $Cambridge: exim/src/src/EDITME,v 1.17 2006/10/02 13:38:18 ph10 Exp $ ################################################## # The Exim mail transport agent # @@ -475,6 +475,7 @@ FIXED_NEVER_USERS=root # AUTH_CRAM_MD5=yes # AUTH_CYRUS_SASL=yes +# AUTH_DOVECOT=yes # AUTH_PLAINTEXT=yes # AUTH_SPA=yes diff --git a/src/src/auths/Makefile b/src/src/auths/Makefile index 0d40d4527..889e24b8c 100644 --- a/src/src/auths/Makefile +++ b/src/src/auths/Makefile @@ -1,4 +1,4 @@ -# $Cambridge: exim/src/src/auths/Makefile,v 1.3 2005/09/12 13:50:03 ph10 Exp $ +# $Cambridge: exim/src/src/auths/Makefile,v 1.4 2006/10/02 13:38:18 ph10 Exp $ # Make file for building a library containing all the available authorization # methods, and calling it auths.a. In addition, there are functions that are @@ -9,7 +9,8 @@ OBJ = b64encode.o b64decode.o call_pam.o call_pwcheck.o call_radius.o \ xtextencode.o xtextdecode.o get_data.o get_no64_data.o md5.o \ - cram_md5.o cyrus_sasl.o plaintext.o pwcheck.o sha1.o auth-spa.o spa.o + cram_md5.o cyrus_sasl.o dovecot.o plaintext.o pwcheck.o sha1.o \ + auth-spa.o spa.o auths.a: $(OBJ) @$(RM_COMMAND) -f auths.a @@ -38,6 +39,7 @@ xtextdecode.o: $(HDRS) xtextdecode.c cram_md5.o: $(HDRS) cram_md5.c cram_md5.h cyrus_sasl.o: $(HDRS) cyrus_sasl.c cyrus_sasl.h +dovecot.o: $(HDRS) dovecot.c dovecot.h plaintext.o: $(HDRS) plaintext.c plaintext.h spa.o: $(HDRS) spa.c spa.h diff --git a/src/src/auths/dovecot.c b/src/src/auths/dovecot.c new file mode 100644 index 000000000..6168ac9a2 --- /dev/null +++ b/src/src/auths/dovecot.c @@ -0,0 +1,283 @@ +/* $Cambridge: exim/src/src/auths/dovecot.c,v 1.1 2006/10/02 13:38:18 ph10 Exp $ */ + +/* + * Copyright (c) 2004 Andrey Panin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "../exim.h" +#include "dovecot.h" + +#define VERSION_MAJOR 1 +#define VERSION_MINOR 0 + +/* Options specific to the authentication mechanism. */ +optionlist auth_dovecot_options[] = { + { + "server_socket", + opt_stringptr, + (void *)(offsetof(auth_dovecot_options_block, server_socket)) + }, +}; + +/* Size of the options list. An extern variable has to be used so that its +address can appear in the tables drtables.c. */ +int auth_dovecot_options_count = + sizeof(auth_dovecot_options) / sizeof(optionlist); + +/* Default private options block for the authentication method. */ +auth_dovecot_options_block auth_dovecot_option_defaults = { + NULL, /* server_socket */ +}; + +/************************************************* + * Initialization entry point * + *************************************************/ + +/* Called for each instance, after its options have been read, to +enable consistency checks to be done, or anything else that needs +to be set up. */ +void auth_dovecot_init(auth_instance *ablock) +{ + auth_dovecot_options_block *ob = + (auth_dovecot_options_block *)(ablock->options_block); + + if (ablock->public_name == NULL) + ablock->public_name = ablock->name; + if (ob->server_socket != NULL) + ablock->server = TRUE; + ablock->client = FALSE; +} + +static int strcut(char *str, char **ptrs, int nptrs) +{ + char *tmp = str; + int n; + + for (n = 0; n < nptrs; n++) + ptrs[n] = NULL; + n = 1; + + while (*str) { + if (*str == '\t') { + if (n <= nptrs) { + *ptrs++ = tmp; + tmp = str + 1; + *str = 0; + } + n++; + } + str++; + } + + if (n < nptrs) + *ptrs = tmp; + + return n; +} + +#define CHECK_COMMAND(str, arg_min, arg_max) do { \ + if (strcasecmp((str), args[0]) != 0) \ + goto out; \ + if (nargs - 1 < (arg_min)) \ + goto out; \ + if (nargs - 1 > (arg_max)) \ + goto out; \ +} while (0) + +#define OUT(msg) do { \ + auth_defer_msg = (US msg); \ + goto out; \ +} while(0) + +/************************************************* + * Server entry point * + *************************************************/ + +int auth_dovecot_server(auth_instance *ablock, uschar *data) +{ + auth_dovecot_options_block *ob = + (auth_dovecot_options_block *)(ablock->options_block); + struct sockaddr_un sa; + char buffer[4096]; + char *args[8]; + int nargs, tmp; + int cuid = 0, cont = 1, found = 0, fd, ret = DEFER; + FILE *f; + + HDEBUG(D_auth) debug_printf("dovecot authentication\n"); + + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + + /* This was the original code here: it is nonsense because strncpy() + does not return an integer. I have converted this to use the function + that formats and checks length. PH */ + + /* + if (strncpy(sa.sun_path, ob->server_socket, sizeof(sa.sun_path)) < 0) { + */ + + if (!string_format(US sa.sun_path, sizeof(sa.sun_path), "%s", + ob->server_socket)) { + auth_defer_msg = US"authentication socket path too long"; + return DEFER; + } + + auth_defer_msg = US"authentication socket connection error"; + + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + return DEFER; + + if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) + goto out; + + f = fdopen(fd, "a+"); + if (f == NULL) + goto out; + + auth_defer_msg = US"authentication socket protocol error"; + + while (cont) { + if (fgets(buffer, sizeof(buffer), f) == NULL) + OUT("authentication socket read error or premature eof"); + + buffer[strlen(buffer) - 1] = 0; + HDEBUG(D_auth) debug_printf("received: %s\n", buffer); + nargs = strcut(buffer, args, sizeof(args) / sizeof(args[0])); + + switch (toupper(*args[0])) { + case 'C': + CHECK_COMMAND("CUID", 1, 1); + cuid = atoi(args[1]); + break; + + case 'D': + CHECK_COMMAND("DONE", 0, 0); + cont = 0; + break; + + case 'M': + CHECK_COMMAND("MECH", 1, INT_MAX); + if (strcmpic(US args[1], ablock->public_name) == 0) + found = 1; + break; + + case 'S': + CHECK_COMMAND("SPID", 1, 1); + break; + + case 'V': + CHECK_COMMAND("VERSION", 2, 2); + if (atoi(args[1]) != VERSION_MAJOR) + OUT("authentication socket protocol version mismatch"); + break; + + default: + goto out; + } + } + + if (!found) + goto out; + + fprintf(f, "VERSION\t%d\t%d\nCPID\t%d\n" + "AUTH\t%d\t%s\tservice=smtp\trip=%s\tlip=%s\tresp=%s\n", + VERSION_MAJOR, VERSION_MINOR, getpid(), cuid, + ablock->public_name, sender_host_address, interface_address, + data ? (char *) data : ""); + +/**************************************************************************** + The code below was the original code here. It didn't work. A reading of the + file auth-protocol.txt.gz that came with Dovecot 1.0_beta8 indicated that + this was not right. Maybe something changed. I changed it to the above, and + it seems to be better. PH + + fprintf(f, "VERSION\t%d\t%d\r\nSERVICE\tSMTP\r\nCPID\t%d\r\n" + "AUTH\t%d\t%s\trip=%s\tlip=%s\tresp=%s\r\n", + VERSION_MAJOR, VERSION_MINOR, getpid(), cuid, + ablock->public_name, sender_host_address, interface_address, + data ? (char *) data : ""); +****************************************************************************/ + + HDEBUG(D_auth) debug_printf("sent: VERSION\t%d\t%d\nsent: CPID\t%d\n" + "sent: AUTH\t%d\t%s\tservice=smtp\trip=%s\tlip=%s\tresp=%s\n", + VERSION_MAJOR, VERSION_MINOR, getpid(), cuid, + ablock->public_name, sender_host_address, interface_address, + data ? (char *) data : ""); + + + while (1) { + if (fgets(buffer, sizeof(buffer), f) == NULL) { + auth_defer_msg = US"authentication socket read error or premature eof"; + goto out; + } + + buffer[strlen(buffer) - 1] = 0; + HDEBUG(D_auth) debug_printf("received: %s\n", buffer); + nargs = strcut(buffer, args, sizeof(args) / sizeof(args[0])); + + if (atoi(args[1]) != cuid) + OUT("authentication socket connection id mismatch"); + + switch (toupper(*args[0])) { + case 'C': + CHECK_COMMAND("CONT", 1, 2); + + tmp = auth_get_no64_data(&data, US args[2]); + if (tmp != OK) { + ret = tmp; + goto out; + } + + if (fprintf(f, "CONT\t%d\t%s\r\n", cuid, data) < 0) + OUT("authentication socket write error"); + + break; + + case 'F': + CHECK_COMMAND("FAIL", 1, 2); + + /* FIXME: add proper response handling */ + if (args[2]) { + uschar *p = US strchr(args[2], '='); + if (p) { + ++p; + expand_nstring[1] = auth_vars[0] = p; + expand_nlength[1] = Ustrlen(p); + expand_nmax = 1; + } + } + + ret = FAIL; + goto out; + + case 'O': + CHECK_COMMAND("OK", 2, 2); + { + /* FIXME: add proper response handling */ + uschar *p = US strchr(args[2], '='); + if (!p) + OUT("authentication socket protocol error, username missing"); + + p++; + expand_nstring[1] = auth_vars[0] = p; + expand_nlength[1] = Ustrlen(p); + expand_nmax = 1; + } + ret = OK; + /* fallthrough */ + + default: + goto out; + } + } + +out: close(fd); + return ret; +} diff --git a/src/src/auths/dovecot.h b/src/src/auths/dovecot.h new file mode 100644 index 000000000..9fd324b0f --- /dev/null +++ b/src/src/auths/dovecot.h @@ -0,0 +1,30 @@ +/* $Cambridge: exim/src/src/auths/dovecot.h,v 1.1 2006/10/02 13:38:18 ph10 Exp $ */ + +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) University of Cambridge 1995 - 2006 */ +/* See the file NOTICE for conditions of use and distribution. */ + +/* Private structure for the private options. */ + +typedef struct { + uschar *server_socket; +} auth_dovecot_options_block; + +/* Data for reading the private options. */ + +extern optionlist auth_dovecot_options[]; +extern int auth_dovecot_options_count; + +/* Block containing default values. */ + +extern auth_dovecot_options_block auth_dovecot_option_defaults; + +/* The entry points for the mechanism */ + +extern void auth_dovecot_init(auth_instance *); +extern int auth_dovecot_server(auth_instance *, uschar *); + +/* End of dovecot.h */ diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index e754e39e4..7974a4149 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/config.h.defaults,v 1.11 2006/09/19 11:28:45 ph10 Exp $ */ +/* $Cambridge: exim/src/src/config.h.defaults,v 1.12 2006/10/02 13:38:18 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -21,6 +21,7 @@ it's a default value. */ #define AUTH_CRAM_MD5 #define AUTH_CYRUS_SASL +#define AUTH_DOVECOT #define AUTH_PLAINTEXT #define AUTH_SPA diff --git a/src/src/drtables.c b/src/src/drtables.c index 5f3b33081..e27fc56a1 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/drtables.c,v 1.6 2006/02/07 11:19:00 ph10 Exp $ */ +/* $Cambridge: exim/src/src/drtables.c,v 1.7 2006/10/02 13:38:18 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -551,6 +551,10 @@ set to NULL for those that are not compiled into the binary. */ #include "auths/cyrus_sasl.h" #endif +#ifdef AUTH_DOVECOT +#include "auths/dovecot.h" +#endif + #ifdef AUTH_PLAINTEXT #include "auths/plaintext.h" #endif @@ -589,6 +593,19 @@ auth_info auths_available[] = { }, #endif +#ifdef AUTH_DOVECOT + { + US"dovecot", /* lookup name */ + auth_dovecot_options, + &auth_dovecot_options_count, + &auth_dovecot_option_defaults, + sizeof(auth_dovecot_options_block), + auth_dovecot_init, /* init function */ + auth_dovecot_server, /* server function */ + NULL /* client function */ + }, +#endif + #ifdef AUTH_PLAINTEXT { US"plaintext", /* lookup name */ diff --git a/src/src/exim.c b/src/src/exim.c index d209b767e..fc3e67d2b 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/exim.c,v 1.43 2006/09/18 14:49:23 ph10 Exp $ */ +/* $Cambridge: exim/src/src/exim.c,v 1.44 2006/10/02 13:38:18 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -980,6 +980,9 @@ fprintf(f, "Authenticators:"); #ifdef AUTH_CYRUS_SASL fprintf(f, " cyrus_sasl"); #endif +#ifdef AUTH_DOVECOT + fprintf(f, " dovecot"); +#endif #ifdef AUTH_PLAINTEXT fprintf(f, " plaintext"); #endif diff --git a/test/confs/3650 b/test/confs/3650 new file mode 100644 index 000000000..fd75156f5 --- /dev/null +++ b/test/confs/3650 @@ -0,0 +1,39 @@ +# Exim test configuration 3650 + +SERVER= + +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/SERVER%slog +gecos_pattern = "" +gecos_name = CALLER_NAME + +# ----- Main settings ----- + +acl_smtp_rcpt = check_recipient + + +# ----- ACL ----- + +begin acl + +check_recipient: + deny message = authentication required + !authenticated = * + accept + + +# ----- Authentication ----- + +begin authenticators + +dovecot: + driver = dovecot + public_name = PLAIN + server_socket = /var/run/dovecot/auth-client + server_set_id = $auth1 + +# End diff --git a/test/log/3650 b/test/log/3650 new file mode 100644 index 000000000..8d693548e --- /dev/null +++ b/test/log/3650 @@ -0,0 +1,4 @@ + +******** SERVER ******** +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 +1999-03-02 09:44:33 dovecot authenticator failed for (xxxx) [127.0.0.1]: 535 Incorrect authentication data (set_id=userx) diff --git a/test/rejectlog/3650 b/test/rejectlog/3650 new file mode 100644 index 000000000..1af78c03d --- /dev/null +++ b/test/rejectlog/3650 @@ -0,0 +1,3 @@ + +******** SERVER ******** +1999-03-02 09:44:33 dovecot authenticator failed for (xxxx) [127.0.0.1]: 535 Incorrect authentication data (set_id=userx) diff --git a/test/scripts/3650-Dovecot/3650 b/test/scripts/3650-Dovecot/3650 new file mode 100644 index 000000000..55b6c1e42 --- /dev/null +++ b/test/scripts/3650-Dovecot/3650 @@ -0,0 +1,18 @@ +# Dovecot authentication (server only) +exim -DSERVER=server -bd -oX PORT_D +**** +client -t3 127.0.0.1 PORT_D +??? 220 +EHLO xxxx +??? 250- +??? 250- +??? 250- +??? 250- +??? 250 +AUTH PLAIN AHVzZXJ4AHNlY3JldA== +??? 535 +quit +??? 221 +**** +killdaemon +no_msglog_check diff --git a/test/scripts/3650-Dovecot/REQUIRES b/test/scripts/3650-Dovecot/REQUIRES new file mode 100644 index 000000000..76218eb92 --- /dev/null +++ b/test/scripts/3650-Dovecot/REQUIRES @@ -0,0 +1,2 @@ +authenticator dovecot +running IPv4 diff --git a/test/stderr/3650 b/test/stderr/3650 new file mode 100644 index 000000000..045fadc9b --- /dev/null +++ b/test/stderr/3650 @@ -0,0 +1,2 @@ + +******** SERVER ******** diff --git a/test/stdout/3650 b/test/stdout/3650 new file mode 100644 index 000000000..87f70de47 --- /dev/null +++ b/test/stdout/3650 @@ -0,0 +1,21 @@ +Connecting to 127.0.0.1 port 1225 ... connected +??? 220 +<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +>>> EHLO xxxx +??? 250- +<<< 250-myhost.test.ex Hello xxxx [127.0.0.1] +??? 250- +<<< 250-SIZE 52428800 +??? 250- +<<< 250-PIPELINING +??? 250- +<<< 250-AUTH PLAIN +??? 250 +<<< 250 HELP +>>> AUTH PLAIN AHVzZXJ4AHNlY3JldA== +??? 535 +<<< 535 Incorrect authentication data +>>> quit +??? 221 +<<< 221 myhost.test.ex closing connection +End of script -- 2.30.2