From a1108b5118d32e969c5fe91b2110944f7483a7cb Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sun, 18 Apr 2021 01:51:28 +0100 Subject: [PATCH] Experimental: ESMTP LIMITS extension --- doc/doc-docbook/spec.xfpt | 12 +- doc/doc-txt/experimental-spec.txt | 36 ++ src/src/config.h.defaults | 1 + src/src/dbfn.c | 2 +- src/src/dbstuff.h | 10 +- src/src/deliver.c | 3 + src/src/exim.c | 16 +- src/src/functions.h | 7 +- src/src/globals.c | 12 + src/src/globals.h | 12 + src/src/readconf.c | 3 + src/src/smtp_in.c | 13 + src/src/transport.c | 36 +- src/src/transports/smtp.c | 544 +++++++++++++++++------- src/src/transports/smtp.h | 17 +- test/aux-var-src/tls_conf_prefix | 3 + test/confs/0453 | 4 +- test/confs/0564 | 3 + test/confs/0900 | 4 +- test/confs/0901 | 3 + test/confs/0906 | 3 + test/confs/3414 | 3 + test/confs/4050 | 3 + test/confs/4710 | 36 ++ test/confs/4711 | 31 ++ test/confs/4712 | 28 ++ test/confs/4713 | 31 ++ test/confs/4714 | 36 ++ test/confs/5670 | 8 +- test/log/4710 | 6 + test/log/4711 | 24 ++ test/log/4712 | 8 + test/log/4713 | 11 + test/log/4714 | 14 + test/runtest | 6 + test/scripts/0000-Basic/0453 | 2 +- test/scripts/4710-esmtp-limits/4710 | 86 ++++ test/scripts/4710-esmtp-limits/4711 | 138 ++++++ test/scripts/4710-esmtp-limits/4712 | 65 +++ test/scripts/4710-esmtp-limits/4713 | 64 +++ test/scripts/4710-esmtp-limits/4714 | 84 ++++ test/scripts/4710-esmtp-limits/REQUIRES | 1 + test/scripts/5670-OCSP-GnuTLS-1.3/5670 | 8 +- test/stdout/4710 | 87 ++++ test/stdout/4711 | 183 ++++++++ test/stdout/4712 | 89 ++++ test/stdout/4713 | 86 ++++ test/stdout/4714 | 117 +++++ 48 files changed, 1829 insertions(+), 170 deletions(-) create mode 100644 test/confs/4710 create mode 100644 test/confs/4711 create mode 100644 test/confs/4712 create mode 100644 test/confs/4713 create mode 100644 test/confs/4714 create mode 100644 test/log/4710 create mode 100644 test/log/4711 create mode 100644 test/log/4712 create mode 100644 test/log/4713 create mode 100644 test/log/4714 create mode 100644 test/scripts/4710-esmtp-limits/4710 create mode 100644 test/scripts/4710-esmtp-limits/4711 create mode 100644 test/scripts/4710-esmtp-limits/4712 create mode 100644 test/scripts/4710-esmtp-limits/4713 create mode 100644 test/scripts/4710-esmtp-limits/4714 create mode 100644 test/scripts/4710-esmtp-limits/REQUIRES create mode 100644 test/stdout/4710 create mode 100644 test/stdout/4711 create mode 100644 test/stdout/4712 create mode 100644 test/stdout/4713 create mode 100644 test/stdout/4714 diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 36be62f7a..56da191fa 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -3940,6 +3940,16 @@ This option is not intended for use by external callers. It is used internally by Exim in conjunction with the &%-MC%& option. It signifies that a remote host supports the ESMTP &_CHUNKING_& extension. +.new +.vitem &%-MCL%& +.oindex "&%-MCL%&" +This option is not intended for use by external callers. It is used internally +by Exim in conjunction with the &%-MC%& option. It signifies that the server to +which Exim is connected advertised limits on numbers of mails, recipients or +recipient domains. +The limits are given by the following three arguments. +.wen + .vitem &%-MCP%& .oindex "&%-MCP%&" This option is not intended for use by external callers. It is used internally @@ -25725,7 +25735,7 @@ has advertised support for IGNOREQUOTA in its response to the LHLO command. This option limits the number of RCPT commands that are sent in a single SMTP message transaction. Each set of addresses is treated independently, and so can cause parallel connections to the same host if &%remote_max_parallel%& -permits this. +permits this. A value setting of zero disables the limit. .new diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt index 47cd93f3d..5e0b04427 100644 --- a/doc/doc-txt/experimental-spec.txt +++ b/doc/doc-txt/experimental-spec.txt @@ -680,6 +680,42 @@ to its QUIT, not properly closing the TLS session and not properly closing the TCP connection. Previously this resulted is an error from SSL_write being logged. + + +Limits ESMTP extension +--------------------------------------------------------------- +Per https://datatracker.ietf.org/doc/html/draft-freed-smtp-limits-01 + +If compiled with EXPERIMENTAL_ESMTP_LIMITS=yes :- + +As a server, Exim will advertise, in the EHLO response, the limit for RCPT +commands set by the recipients_max main-section config option (if it is set), +and the limit for MAIL commands set by the smtp_accept_max_per_connection +option. + +Note that as of writing, smtp_accept_max_per_connection is expanded but +recipients_max is not. + +A new main-section option "limits_advertise_hosts" controls whether +the limits are advertised; the default for the option is "*". + +As a client, Exim will: + + - note an advertised MAILMAX; the lower of the value given and the + value from the transport connection_max_messages option is used. + + - note an advertised RCPTMAX; the lower of the + value given and the value from the transport max_rcpt option is used. + Parallisation of transactions is not done if due to a RCPTMAX, unlike + max_rcpt. + + - note an advertised RCPTDOMAINMAX, and behave as if the transport + multi_domains option was set to false. The value advertised is ignored. + +Values advertised are only noted for TLS connections and ones for which +the server does not advertise TLS support. + + -------------------------------------------------------------- End of file -------------------------------------------------------------- diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index 02031b7df..e233fb3e5 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -205,6 +205,7 @@ Do not put spaces between # and the 'define'. #define EXPERIMENTAL_BRIGHTMAIL #define EXPERIMENTAL_DCC #define EXPERIMENTAL_DSN_INFO +#define EXPERIMENTAL_ESMTP_LIMITS #define EXPERIMENTAL_QUEUEFILE #define EXPERIMENTAL_SRS_ALT diff --git a/src/src/dbfn.c b/src/src/dbfn.c index be6a47afc..0f56ad5a6 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -342,7 +342,7 @@ return yield; /* Read a record. If the length is not as expected then delete it, write -an error log line and return NULL. +an error log line, delete the record and return NULL. Use this for fixed-size records (so not retry or wait records). Arguments: diff --git a/src/src/dbstuff.h b/src/src/dbstuff.h index 5a8441d6a..89934154a 100644 --- a/src/src/dbstuff.h +++ b/src/src/dbstuff.h @@ -792,13 +792,21 @@ typedef struct { #ifndef DISABLE_PIPE_CONNECT /* This structure records the EHLO responses, cleartext and crypted, -for an IP, as bitmasks (cf. OPTION_TLS) */ +for an IP, as bitmasks (cf. OPTION_TLS). For LIMITS, also values +advertised for MAILMAX, RCPTMAX and RCPTDOMAINMAX; zero meaning no +value advertised. */ typedef struct { unsigned short cleartext_features; unsigned short crypted_features; unsigned short cleartext_auths; unsigned short crypted_auths; + +# ifdef EXPERIMENTAL_ESMTP_LIMITS + unsigned int limit_mail; + unsigned int limit_rcpt; + unsigned int limit_rcptdom; +# endif } ehlo_resp_precis; typedef struct { diff --git a/src/src/deliver.c b/src/src/deliver.c index 0cddec758..9ebd281fc 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -8570,6 +8570,9 @@ f.tcp_fastopen_ok = TRUE; +/* Called from a commandline, or from the daemon, to do a delivery. +We need to regain privs; do this by exec of the exim binary. */ + void delivery_re_exec(int exec_type) { diff --git a/src/src/exim.c b/src/src/exim.c index 1244aee0b..8526cbbf3 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1010,6 +1010,9 @@ g = string_cat(NULL, US"Support for:"); #ifdef EXPERIMENTAL_DSN_INFO g = string_cat(g, US" Experimental_DSN_info"); #endif +#ifdef EXPERIMENTAL_ESMTP_LIMITS + g = string_cat(g, US" Experimental_ESMTP_Limits"); +#endif #ifdef EXPERIMENTAL_QUEUEFILE g = string_cat(g, US" Experimental_QUEUEFILE"); #endif @@ -2257,7 +2260,7 @@ on the second character (the one after '-'), to save some effort. */ case 'P': /* -bP config: we need to setup here, because later, - * when list_options is checked, the config is read already */ + when list_options is checked, the config is read already */ if (*argrest) badarg = TRUE; else if (argv[i+1] && Ustrcmp(argv[i+1], "config") == 0) @@ -2788,6 +2791,17 @@ on the second character (the one after '-'), to save some effort. */ case 'K': smtp_peer_options |= OPTION_CHUNKING; break; +#ifdef EXPERIMENTAL_ESMTP_LIMITS + /* -MCL: peer used LIMITS RCPTMAX and/or RCPTDOMAINMAX */ + case 'L': if (++i < argc) continue_limit_mail = Uatoi(argv[i]); + else badarg = TRUE; + if (++i < argc) continue_limit_rcpt = Uatoi(argv[i]); + else badarg = TRUE; + if (++i < argc) continue_limit_rcptdom = Uatoi(argv[i]); + else badarg = TRUE; + break; +#endif + /* -MCP: set the smtp_use_pipelining flag; this is useful only when it preceded -MC (see above) */ diff --git a/src/src/functions.h b/src/src/functions.h index 0f962b313..7d6e3380e 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -593,8 +593,11 @@ extern BOOL transport_check_waiting(const uschar *, const uschar *, int, usch extern void transport_init(void); extern void transport_do_pass_socket(const uschar *, const uschar *, const uschar *, uschar *, int); -extern BOOL transport_pass_socket(const uschar *, const uschar *, const uschar *, uschar *, - int); +extern BOOL transport_pass_socket(const uschar *, const uschar *, const uschar *, uschar *, int +#ifdef EXPERIMENTAL_ESMTP_LIMITS + , unsigned, unsigned, unsigned +#endif + ); extern uschar *transport_rcpt_address(address_item *, BOOL); extern BOOL transport_set_up_command(const uschar ***, uschar *, BOOL, int, address_item *, uschar *, uschar **); diff --git a/src/src/globals.c b/src/src/globals.c index 7ee7c38b5..c45e8a930 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -710,6 +710,10 @@ unsigned chunking_data_left = 0; chunking_state_t chunking_state= CHUNKING_NOT_OFFERED; const pcre *regex_CHUNKING = NULL; +#ifdef EXPERIMENTAL_ESMTP_LIMITS +const pcre *regex_LIMITS = NULL; +#endif + uschar *client_authenticator = NULL; uschar *client_authenticated_id = NULL; uschar *client_authenticated_sender = NULL; @@ -742,6 +746,11 @@ uschar *continue_hostname = NULL; uschar *continue_host_address = NULL; int continue_sequence = 1; uschar *continue_transport = NULL; +#ifdef EXPERIMENTAL_ESMTP_LIMITS +unsigned continue_limit_mail = 0; +unsigned continue_limit_rcpt = 0; +unsigned continue_limit_rcptdom= 0; +#endif uschar *csa_status = NULL; cut_t cutthrough = { @@ -1001,6 +1010,9 @@ uschar *keep_environment = NULL; int keep_malformed = 4*24*60*60; /* 4 days */ uschar *eldap_dn = NULL; +#ifdef EXPERIMENTAL_ESMTP_LIMITS +uschar *limits_advertise_hosts = US"*"; +#endif int load_average = -2; uschar *local_from_prefix = NULL; uschar *local_from_suffix = NULL; diff --git a/src/src/globals.h b/src/src/globals.h index 58bf3c428..ed7cffb76 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -434,6 +434,12 @@ extern uschar *continue_hostname; /* Host for continued delivery */ extern uschar *continue_host_address; /* IP address for ditto */ extern int continue_sequence; /* Sequence num for continued delivery */ extern uschar *continue_transport; /* Transport for continued delivery */ +#ifdef EXPERIMENTAL_ESMTP_LIMITS +extern unsigned continue_limit_mail; /* Peer advertised limit */ +extern unsigned continue_limit_rcpt; +extern unsigned continue_limit_rcptdom; +#endif + extern uschar *csa_status; /* Client SMTP Authorization result */ @@ -652,6 +658,9 @@ extern uschar *keep_environment; /* Whitelist for environment variables */ extern int keep_malformed; /* Time to keep malformed messages */ extern uschar *eldap_dn; /* Where LDAP DNs are left */ +#ifdef EXPERIMENTAL_ESMTP_LIMITS +extern uschar *limits_advertise_hosts; /* for banner/EHLO pipelining */ +#endif extern int load_average; /* Most recently read load average */ extern BOOL local_from_check; /* For adding Sender: (global value) */ extern uschar *local_from_prefix; /* Permitted prefixes */ @@ -854,6 +863,9 @@ extern const pcre *regex_check_dns_names; /* For DNS name checking */ extern const pcre *regex_From; /* For recognizing "From_" lines */ extern const pcre *regex_CHUNKING; /* For recognizing CHUNKING (RFC 3030) */ extern const pcre *regex_IGNOREQUOTA; /* For recognizing IGNOREQUOTA (LMTP) */ +#ifdef EXPERIMENTAL_ESMTP_LIMITS +extern const pcre *regex_LIMITS; /* For recognizing LIMITS */ +#endif extern const pcre *regex_PIPELINING; /* For recognizing PIPELINING */ extern const pcre *regex_SIZE; /* For recognizing SIZE settings */ #ifndef DISABLE_PIPE_CONNECT diff --git a/src/src/readconf.c b/src/src/readconf.c index 0ae3166c3..e8e310beb 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -200,6 +200,9 @@ static optionlist optionlist_config[] = { { "ldap_require_cert", opt_stringptr, {&eldap_require_cert} }, { "ldap_start_tls", opt_bool, {&eldap_start_tls} }, { "ldap_version", opt_int, {&eldap_version} }, +#endif +#ifdef EXPERIMENTAL_ESMTP_LIMITS + { "limits_advertise_hosts", opt_stringptr, {&limits_advertise_hosts} }, #endif { "local_from_check", opt_bool, {&local_from_check} }, { "local_from_prefix", opt_stringptr, {&local_from_prefix} }, diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 2bb15b698..d60e7d5c5 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -4346,6 +4346,19 @@ while (done <= 0) g = string_catn(g, US"-SIZE\r\n", 7); } +#ifdef EXPERIMENTAL_ESMTP_LIMITS + if ( (mailmax > 0 || recipients_max) + && verify_check_host(&limits_advertise_hosts) == OK) + { + g = string_fmt_append(g, "%.3s-LIMITS", smtp_code); + if (mailmax > 0) + g = string_fmt_append(g, " MAILMAX=%d", mailmax); + if (recipients_max) + g = string_fmt_append(g, " RCPTMAX=%d", recipients_max); + g = string_catn(g, US"\r\n", 2); + } +#endif + /* Exim does not do protocol conversion or data conversion. It is 8-bit clean; if it has an 8-bit character in its hand, it just sends it. It cannot therefore specify 8BITMIME and remain consistent with the RFCs. diff --git a/src/src/transport.c b/src/src/transport.c index 49a84ccc4..d8fd85855 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -1880,9 +1880,21 @@ void transport_do_pass_socket(const uschar *transport_name, const uschar *hostname, const uschar *hostaddress, uschar *id, int socket_fd) { -int i = 27; +int i = 13; const uschar **argv; +#ifndef DISABLE_TLS +if (smtp_peer_options & OPTION_TLS) i += 6; +#endif +#ifdef EXPERIMENTAL_ESMTP_LIMITS +if (continue_limit_mail || continue_limit_rcpt || continue_limit_rcptdom) + i += 4; +#endif +if (queue_run_pid != (pid_t)0) i += 3; +#ifdef SUPPORT_SOCKS +if (proxy_session) i += 5; +#endif + /* Set up the calling arguments; use the standard function for the basics, but we have a number of extras that may be added. */ @@ -1916,6 +1928,16 @@ if (smtp_peer_options & OPTION_TLS) argv[i++] = US"-MCT"; #endif +#ifdef EXPERIMENTAL_ESMTP_LIMITS +if (continue_limit_rcpt || continue_limit_rcptdom) + { + argv[i++] = US"-MCL"; + argv[i++] = string_sprintf("%u", continue_limit_mail); + argv[i++] = string_sprintf("%u", continue_limit_rcpt); + argv[i++] = string_sprintf("%u", continue_limit_rcptdom); + } +#endif + if (queue_run_pid != (pid_t)0) { argv[i++] = US"-MCQ"; @@ -1976,13 +1998,23 @@ Returns: FALSE if fork fails; TRUE otherwise BOOL transport_pass_socket(const uschar *transport_name, const uschar *hostname, - const uschar *hostaddress, uschar *id, int socket_fd) + const uschar *hostaddress, uschar *id, int socket_fd +#ifdef EXPERIMENTAL_ESMTP_LIMITS + , unsigned peer_limit_mail, unsigned peer_limit_rcpt, unsigned peer_limit_rcptdom +#endif + ) { pid_t pid; int status; DEBUG(D_transport) debug_printf("transport_pass_socket entered\n"); +#ifdef EXPERIMENTAL_ESMTP_LIMITS +continue_limit_mail = peer_limit_mail; +continue_limit_rcpt = peer_limit_rcpt; +continue_limit_rcptdom = peer_limit_rcptdom; +#endif + if ((pid = exim_fork(US"continued-transport-interproc")) == 0) { /* Disconnect entirely from the parent process. If we are running in the diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 2a2928c46..52940572b 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -274,6 +274,11 @@ if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA = if (!regex_EARLY_PIPE) regex_EARLY_PIPE = regex_must_compile(US"\\n250[\\s\\-]" EARLY_PIPE_FEATURE_NAME "(\\s|\\n|$)", FALSE, TRUE); #endif + +#ifdef EXPERIMENTAL_ESMTP_LIMITS +if (!regex_LIMITS) regex_LIMITS = + regex_must_compile(US"\\n250[\\s\\-]LIMITS\\s", FALSE, TRUE); +#endif } @@ -756,6 +761,82 @@ return TRUE; } +/******************************************************************************/ + +#ifdef EXPERIMENTAL_ESMTP_LIMITS +/* If TLS, or TLS not offered, called with the EHLO response in the buffer. +Check it for a LIMITS keyword and parse values into the smtp context structure. + +We don't bother with peers that we won't talk TLS to, even though they can, +just ignore their LIMITS advice (if any) and treat them as if they do not. +This saves us dealing with a duplicate set of values. */ + +static void +ehlo_response_limits_read(smtp_context * sx) +{ +int ovec[3]; /* results vector for a main-match only */ + +/* matches up to just after the first space after the keyword */ + +if (pcre_exec(regex_LIMITS, NULL, CS sx->buffer, Ustrlen(sx->buffer), + 0, PCRE_EOPT, ovec, nelem(ovec)) >= 0) + for (const uschar * s = sx->buffer + ovec[1]; *s; ) + { + while (isspace(*s)) s++; + if (*s == '\n') break; + + if (strncmpic(s, US"MAILMAX=", 8) == 0) + { + sx->peer_limit_mail = atoi(CS (s += 8)); + while (isdigit(*s)) s++; + } + else if (strncmpic(s, US"RCPTMAX=", 8) == 0) + { + sx->peer_limit_rcpt = atoi(CS (s += 8)); + while (isdigit(*s)) s++; + } + else if (strncmpic(s, US"RCPTDOMAINMAX=", 14) == 0) + { + sx->peer_limit_rcptdom = atoi(CS (s += 14)); + while (isdigit(*s)) s++; + } + else + while (*s && !isspace(*s)) s++; + } +} + +/* Apply given values to the current connection */ +static void +ehlo_limits_apply(smtp_context * sx, + unsigned limit_mail, unsigned limit_rcpt, unsigned limit_rcptdom) +{ +if (limit_mail && limit_mail < sx->max_mail) sx->max_mail = limit_mail; +if (limit_rcpt && limit_rcpt < sx->max_rcpt) sx->max_rcpt = limit_rcpt; +if (limit_rcptdom) + { + DEBUG(D_transport) debug_printf("will treat as !multi_domain\n"); + sx->single_rcpt_domain = TRUE; + } +} + +/* Apply values from EHLO-resp to the current connection */ +static void +ehlo_response_limits_apply(smtp_context * sx) +{ +ehlo_limits_apply(sx, sx->peer_limit_mail, sx->peer_limit_rcpt, + sx->peer_limit_rcptdom); +} + +/* Apply values read from cache to the current connection */ +static void +ehlo_cache_limits_apply(smtp_context * sx) +{ +ehlo_limits_apply(sx, sx->ehlo_resp.limit_mail, sx->ehlo_resp.limit_rcpt, + sx->ehlo_resp.limit_rcptdom); +} +#endif + +/******************************************************************************/ #ifndef DISABLE_PIPE_CONNECT static uschar * @@ -769,19 +850,45 @@ return Ustrchr(host->address, ':') host->port == PORT_NONE ? sx->port : host->port); } +/* Cache EHLO-response info for use by early-pipe. +Called +- During a normal flow on EHLO response (either cleartext or under TLS), + when we are willing to do PIPE_CONNECT and it is offered +- During an early-pipe flow on receiving the actual EHLO response and noting + disparity versus the cached info used, when PIPE_CONNECT is still being offered + +We assume that suitable values have been set in the sx.ehlo_resp structure for +features and auths; we handle the copy of limits. */ + static void -write_ehlo_cache_entry(const smtp_context * sx) +write_ehlo_cache_entry(smtp_context * sx) { open_db dbblock, * dbm_file; +#ifdef EXPERIMENTAL_ESMTP_LIMITS +sx->ehlo_resp.limit_mail = sx->peer_limit_mail; +sx->ehlo_resp.limit_rcpt = sx->peer_limit_rcpt; +sx->ehlo_resp.limit_rcptdom = sx->peer_limit_rcptdom; +#endif + if ((dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE))) { uschar * ehlo_resp_key = ehlo_cache_key(sx); dbdata_ehlo_resp er = { .data = sx->ehlo_resp }; - HDEBUG(D_transport) debug_printf("writing clr %04x/%04x cry %04x/%04x\n", - sx->ehlo_resp.cleartext_features, sx->ehlo_resp.cleartext_auths, - sx->ehlo_resp.crypted_features, sx->ehlo_resp.crypted_auths); + HDEBUG(D_transport) +#ifdef EXPERIMENTAL_ESMTP_LIMITS + if (sx->ehlo_resp.limit_mail || sx->ehlo_resp.limit_rcpt || sx->ehlo_resp.limit_rcptdom) + debug_printf("writing clr %04x/%04x cry %04x/%04x lim %05d/%05d/%05d\n", + sx->ehlo_resp.cleartext_features, sx->ehlo_resp.cleartext_auths, + sx->ehlo_resp.crypted_features, sx->ehlo_resp.crypted_auths, + sx->ehlo_resp.limit_mail, sx->ehlo_resp.limit_rcpt, + sx->ehlo_resp.limit_rcptdom); + else +#endif + debug_printf("writing clr %04x/%04x cry %04x/%04x\n", + sx->ehlo_resp.cleartext_features, sx->ehlo_resp.cleartext_auths, + sx->ehlo_resp.crypted_features, sx->ehlo_resp.crypted_auths); dbfn_write(dbm_file, ehlo_resp_key, &er, (int)sizeof(er)); dbfn_close(dbm_file); @@ -826,12 +933,26 @@ else } else { + DEBUG(D_transport) +#ifdef EXPERIMENTAL_ESMTP_LIMITS + if (er->data.limit_mail || er->data.limit_rcpt || er->data.limit_rcptdom) + debug_printf("EHLO response bits from cache:" + " cleartext 0x%04x/0x%04x crypted 0x%04x/0x%04x lim %05d/%05d/%05d\n", + er->data.cleartext_features, er->data.cleartext_auths, + er->data.crypted_features, er->data.crypted_auths, + er->data.limit_mail, er->data.limit_rcpt, er->data.limit_rcptdom); + else +#endif + debug_printf("EHLO response bits from cache:" + " cleartext 0x%04x/0x%04x crypted 0x%04x/0x%04x\n", + er->data.cleartext_features, er->data.cleartext_auths, + er->data.crypted_features, er->data.crypted_auths); + sx->ehlo_resp = er->data; +#ifdef EXPERIMENTAL_ESMTP_LIMITS + ehlo_cache_limits_apply(sx); +#endif dbfn_close(dbm_file); - DEBUG(D_transport) debug_printf( - "EHLO response bits from cache: cleartext 0x%04x/0x%04x crypted 0x%04x/0x%04x\n", - er->data.cleartext_features, er->data.cleartext_auths, - er->data.crypted_features, er->data.crypted_auths); return TRUE; } dbfn_close(dbm_file); @@ -933,8 +1054,9 @@ if (pending_EHLO) goto fail; } - /* Compare the actual EHLO response to the cached value we assumed; - on difference, dump or rewrite the cache and arrange for a retry. */ + /* Compare the actual EHLO response extensions and AUTH methods to the cached + value we assumed; on difference, dump or rewrite the cache and arrange for a + retry. */ ap = tls_out.active.sock < 0 ? &sx->ehlo_resp.cleartext_auths : &sx->ehlo_resp.crypted_auths; @@ -944,6 +1066,10 @@ if (pending_EHLO) | OPTION_CHUNKING | OPTION_PRDR | OPTION_DSN | OPTION_PIPE | OPTION_SIZE | OPTION_UTF8 | OPTION_EARLY_PIPE ); +#ifdef EXPERIMENTAL_ESMTP_LIMITS + if (tls_out.active.sock >= 0 || !(peer_offered & OPTION_TLS)) + ehlo_response_limits_read(sx); +#endif if ( peer_offered != sx->peer_offered || (authbits = study_ehlo_auths(sx)) != *ap) { @@ -951,16 +1077,44 @@ if (pending_EHLO) debug_printf("EHLO %s extensions changed, 0x%04x/0x%04x -> 0x%04x/0x%04x\n", tls_out.active.sock < 0 ? "cleartext" : "crypted", sx->peer_offered, *ap, peer_offered, authbits); - *(tls_out.active.sock < 0 - ? &sx->ehlo_resp.cleartext_features : &sx->ehlo_resp.crypted_features) = peer_offered; - *ap = authbits; if (peer_offered & OPTION_EARLY_PIPE) + { + *(tls_out.active.sock < 0 + ? &sx->ehlo_resp.cleartext_features : &sx->ehlo_resp.crypted_features) = + peer_offered; + *ap = authbits; write_ehlo_cache_entry(sx); + } else invalidate_ehlo_cache_entry(sx); return OK; /* just carry on */ } +#ifdef EXPERIMENTAL_ESMTP_LIMITS + /* If we are handling LIMITS, compare the actual EHLO LIMITS values with the + cached values and invalidate cache if different. OK to carry on with + connect since values are advisory. */ + { + if ( (tls_out.active.sock >= 0 || !(peer_offered & OPTION_TLS)) + && ( sx->peer_limit_mail != sx->ehlo_resp.limit_mail + || sx->peer_limit_rcpt != sx->ehlo_resp.limit_rcpt + || sx->peer_limit_rcptdom != sx->ehlo_resp.limit_rcptdom + ) ) + { + HDEBUG(D_transport) + { + debug_printf("EHLO LIMITS changed:"); + if (sx->peer_limit_mail != sx->ehlo_resp.limit_mail) + debug_printf(" MAILMAX %u -> %u\n", sx->ehlo_resp.limit_mail, sx->peer_limit_mail); + else if (sx->peer_limit_rcpt != sx->ehlo_resp.limit_rcpt) + debug_printf(" RCPTMAX %u -> %u\n", sx->ehlo_resp.limit_rcpt, sx->peer_limit_rcpt); + else + debug_printf(" RCPTDOMAINMAX %u -> %u\n", sx->ehlo_resp.limit_rcptdom, sx->peer_limit_rcptdom); + } + invalidate_ehlo_cache_entry(sx); + } + } +#endif } return OK; @@ -1882,7 +2036,8 @@ sx->dane_required = /* sx->pending_BANNER = sx->pending_EHLO = sx->pending_MAIL = FALSE; */ #endif -if ((sx->max_rcpt = sx->conn_args.tblock->max_addresses) == 0) sx->max_rcpt = 999999; +if ((sx->max_mail = sx->conn_args.tblock->connection_max_messages) == 0) sx->max_mail = 999999; +if ((sx->max_rcpt = sx->conn_args.tblock->max_addresses) == 0) sx->max_rcpt = 999999; /* sx->peer_offered = 0; */ /* sx->avoid_option = 0; */ sx->igquotstr = US""; @@ -2083,6 +2238,9 @@ if (!continue_hostname) sx->cctx.tls_ctx = NULL; sx->inblock.cctx = sx->outblock.cctx = &sx->cctx; +#ifdef EXPERIMENTAL_ESMTP_LIMITS + sx->peer_limit_mail = sx->peer_limit_rcpt = sx->peer_limit_rcptdom = +#endif sx->avoid_option = sx->peer_offered = smtp_peer_options = 0; #ifndef DISABLE_PIPE_CONNECT @@ -2361,6 +2519,13 @@ goto SEND_QUIT; ) #endif ); +#ifdef EXPERIMENTAL_ESMTP_LIMITS + if (tls_out.active.sock >= 0 || !(sx->peer_offered & OPTION_TLS)) + { + ehlo_response_limits_read(sx); + ehlo_response_limits_apply(sx); + } +#endif #ifndef DISABLE_PIPE_CONNECT if (sx->early_pipe_ok) { @@ -2415,6 +2580,13 @@ else sx->inblock.cctx = sx->outblock.cctx = &sx->cctx; smtp_command = big_buffer; sx->peer_offered = smtp_peer_options; +#ifdef EXPERIMENTAL_ESMTP_LIMITS + /* Limits passed by cmdline over exec. */ + ehlo_limits_apply(sx, + sx->peer_limit_mail = continue_limit_mail, + sx->peer_limit_rcpt = continue_limit_rcpt, + sx->peer_limit_rcptdom = continue_limit_rcptdom); +#endif sx->helo_data = NULL; /* ensure we re-expand ob->helo_data */ /* For a continued connection with TLS being proxied for us, or a @@ -2456,7 +2628,8 @@ if ( smtp_peer_options & OPTION_TLS #ifndef DISABLE_PIPE_CONNECT /* If doing early-pipelining reap the banner and EHLO-response but leave - the response for the STARTTLS we just sent alone. */ + the response for the STARTTLS we just sent alone. On fail, assume wrong + cached capability and retry with the pipelining disabled. */ if (sx->early_pipe_active && sync_responses(sx, 2, 0) != 0) { @@ -2592,6 +2765,13 @@ if (tls_out.active.sock >= 0) DEBUG(D_transport) debug_printf("Using cached crypted PIPE_CONNECT\n"); } #endif +#ifdef EXPERIMMENTAL_ESMTP_LIMITS + /* As we are about to send another EHLO, forget any LIMITS received so far. */ + sx->peer_limit_mail = sx->peer_limit_rcpt = sx->peer_limit_rcptdom = 0; + if ((sx->max_mail = sx->conn_args.tblock->connection_max_message) == 0) sx->max_mail = 999999; + if ((sx->max_rcpt = sx->conn_args.tblock->max_addresses) == 0) sx->max_rcpt = 999999; + sx->single_rcpt_domain = FALSE; +#endif /* For SMTPS we need to wait for the initial OK response. */ if (sx->smtps) @@ -2721,6 +2901,14 @@ if ( !continue_hostname if (tls_out.active.sock >= 0) sx->ehlo_resp.crypted_features = sx->peer_offered; #endif + +#ifdef EXPERIMENTAL_ESMTP_LIMITS + if (tls_out.active.sock >= 0 || !(sx->peer_offered & OPTION_TLS)) + { + ehlo_response_limits_read(sx); + ehlo_response_limits_apply(sx); + } +#endif } /* Set for IGNOREQUOTA if the response to LHLO specifies support and the @@ -3054,7 +3242,7 @@ if ( sx->peer_offered & OPTION_UTF8 /* check if all addresses have DSN-lasthop flag; do not send RET and ENVID if so */ for (sx->dsn_all_lasthop = TRUE, addr = addrlist, address_count = 0; - addr && address_count < sx->max_rcpt; + addr && address_count < sx->max_rcpt; /*XXX maybe also || sx->single_rcpt_domain ? */ addr = addr->next) if (addr->transport_return == PENDING_DEFER) { address_count++; @@ -3142,6 +3330,9 @@ int smtp_write_mail_and_rcpt_cmds(smtp_context * sx, int * yield) { address_item * addr; +#ifdef EXPERIMENTAL_ESMTP_LIMITS +address_item * restart_addr = NULL; +#endif int address_count, pipe_limit; int rc; @@ -3233,6 +3424,24 @@ for (addr = sx->first_addr, address_count = 0, pipe_limit = 100; BOOL no_flush; uschar * rcpt_addr; +#ifdef EXPERIMENTAL_ESMTP_LIMITS + if ( sx->single_rcpt_domain /* restriction on domains */ + && address_count > 0 /* not first being sent */ + && Ustrcmp(addr->domain, sx->first_addr->domain) != 0 /* dom diff from first */ + ) + { + DEBUG(D_transport) debug_printf("skipping different domain %s\n", addr->domain); + + /* Ensure the smtp-response reaper does not think the address had a RCPT + command sent for it. Reset to PENDING_DEFER in smtp_deliver(), where we + goto SEND_MESSAGE. */ + + addr->transport_return = SKIP; + if (!restart_addr) restart_addr = addr; /* note restart point */ + continue; /* skip this one */ + } +#endif + addr->dsn_aware = sx->peer_offered & OPTION_DSN ? dsn_support_yes : dsn_support_no; @@ -3304,7 +3513,11 @@ for (addr = sx->first_addr, address_count = 0, pipe_limit = 100; } } /* Loop for next address */ +#ifdef EXPERIMENTAL_ESMTP_LIMITS +sx->next_addr = restart_addr ? restart_addr : addr; +#else sx->next_addr = addr; +#endif return 0; } @@ -3493,10 +3706,13 @@ int yield = OK; int save_errno; int rc; -BOOL pass_message = FALSE; uschar *message = NULL; uschar new_message_id[MESSAGE_ID_LENGTH + 1]; smtp_context * sx = store_get(sizeof(*sx), TRUE); /* tainted, for the data buffers */ +BOOL pass_message = FALSE; +#ifdef EXPERIMENTAL_ESMTP_LIMITS +BOOL mail_limit = FALSE; +#endif #ifdef SUPPORT_DANE BOOL dane_held; #endif @@ -3516,8 +3732,8 @@ sx->conn_args.tblock = tblock; gettimeofday(&sx->delivery_start, NULL); sx->sync_addr = sx->first_addr = addrlist; +REPEAT_CONN: #ifdef SUPPORT_DANE -DANE_DOMAINS: dane_held = FALSE; #endif @@ -4090,7 +4306,7 @@ else else sprintf(CS sx->buffer, "%.500s\n", addr->unique); - DEBUG(D_deliver) debug_printf("S:journalling %s\n", sx->buffer); + DEBUG(D_deliver) debug_printf("S:journalling %s", sx->buffer); len = Ustrlen(CS sx->buffer); if (write(journal_fd, sx->buffer, len) != len) log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for " @@ -4335,81 +4551,95 @@ DEBUG(D_transport) sx->send_rset, f.continue_more, yield, sx->first_addr ? "not " : ""); if (sx->completed_addr && sx->ok && sx->send_quit) - { - smtp_compare_t t_compare = - {.tblock = tblock, .current_sender_address = sender_address}; +#ifdef EXPERIMENTAL_ESMTP_LIMITS + if (mail_limit = continue_sequence >= sx->max_mail) + { + DEBUG(D_transport) + debug_printf("reached limit %u for MAILs per conn\n", sx->max_mail); + } + else +#endif + { + smtp_compare_t t_compare = + {.tblock = tblock, .current_sender_address = sender_address}; - if ( sx->first_addr /* more addrs for this message */ - || f.continue_more /* more addrs for continued-host */ - || tcw_done && tcw /* more messages for host */ - || ( + if ( sx->first_addr /* more addrs for this message */ + || f.continue_more /* more addrs for continued-host */ + || tcw_done && tcw /* more messages for host */ + || ( #ifndef DISABLE_TLS - ( tls_out.active.sock < 0 && !continue_proxy_cipher - || verify_check_given_host(CUSS &ob->hosts_nopass_tls, host) != OK - ) - && + ( tls_out.active.sock < 0 && !continue_proxy_cipher + || verify_check_given_host(CUSS &ob->hosts_nopass_tls, host) != OK + ) + && #endif - transport_check_waiting(tblock->name, host->name, - tblock->connection_max_messages, new_message_id, - (oicf)smtp_are_same_identities, (void*)&t_compare) - ) ) - { - uschar *msg; - BOOL pass_message; + transport_check_waiting(tblock->name, host->name, + sx->max_mail, new_message_id, + (oicf)smtp_are_same_identities, (void*)&t_compare) + ) ) + { + uschar *msg; + BOOL pass_message; - if (sx->send_rset) - if (! (sx->ok = smtp_write_command(sx, SCMD_FLUSH, "RSET\r\n") >= 0)) - { - msg = US string_sprintf("send() to %s [%s] failed: %s", host->name, - host->address, strerror(errno)); - sx->send_quit = FALSE; - } - else if (! (sx->ok = smtp_read_response(sx, sx->buffer, sizeof(sx->buffer), - '2', ob->command_timeout))) - { - int code; - sx->send_quit = check_response(host, &errno, 0, sx->buffer, &code, &msg, - &pass_message); - if (!sx->send_quit) - { - DEBUG(D_transport) debug_printf("H=%s [%s] %s\n", - host->name, host->address, msg); - } - } + if (sx->send_rset) + if (! (sx->ok = smtp_write_command(sx, SCMD_FLUSH, "RSET\r\n") >= 0)) + { + msg = US string_sprintf("send() to %s [%s] failed: %s", host->name, + host->address, strerror(errno)); + sx->send_quit = FALSE; + } + else if (! (sx->ok = smtp_read_response(sx, sx->buffer, sizeof(sx->buffer), + '2', ob->command_timeout))) + { + int code; + sx->send_quit = check_response(host, &errno, 0, sx->buffer, &code, &msg, + &pass_message); + if (!sx->send_quit) + { + DEBUG(D_transport) debug_printf("H=%s [%s] %s\n", + host->name, host->address, msg); + } + } - /* Either RSET was not needed, or it succeeded */ + /* Either RSET was not needed, or it succeeded */ - if (sx->ok) - { + if (sx->ok) + { #ifndef DISABLE_TLS - int pfd[2]; -#endif - int socket_fd = sx->cctx.sock; - - if (sx->first_addr) /* More addresses still to be sent */ - { /* for this message */ - continue_sequence++; /* for consistency */ - clearflag(sx->first_addr, af_new_conn); - setflag(sx->first_addr, af_cont_conn); /* Causes * in logging */ - pipelining_active = sx->pipelining_used; /* was cleared at DATA */ - goto SEND_MESSAGE; - } + int pfd[2]; +#endif + int socket_fd = sx->cctx.sock; + + if (sx->first_addr) /* More addresses still to be sent */ + { /* for this message */ +#ifdef EXPERIMENTAL_ESMTP_LIMITS + /* Any that we marked as skipped, reset to do now */ + for (address_item * a = sx->first_addr; a; a = a->next) + if (a->transport_return == SKIP) + a->transport_return = PENDING_DEFER; +#endif + continue_sequence++; /* for consistency */ + clearflag(sx->first_addr, af_new_conn); + setflag(sx->first_addr, af_cont_conn); /* Causes * in logging */ + pipelining_active = sx->pipelining_used; /* was cleared at DATA */ + goto SEND_MESSAGE; + } - /* Unless caller said it already has more messages listed for this host, - pass the connection on to a new Exim process (below, the call to - transport_pass_socket). If the caller has more ready, just return with - the connection still open. */ + /* Unless caller said it already has more messages listed for this host, + pass the connection on to a new Exim process (below, the call to + transport_pass_socket). If the caller has more ready, just return with + the connection still open. */ #ifndef DISABLE_TLS - if (tls_out.active.sock >= 0) - if ( f.continue_more - || verify_check_given_host(CUSS &ob->hosts_noproxy_tls, host) == OK) - { - /* Before passing the socket on, or returning to caller with it still - open, we must shut down TLS. Not all MTAs allow for the continuation - of the SMTP session when TLS is shut down. We test for this by sending - a new EHLO. If we don't get a good response, we don't attempt to pass - the socket on. */ + if (tls_out.active.sock >= 0) + if ( f.continue_more + || verify_check_given_host(CUSS &ob->hosts_noproxy_tls, host) == OK) + { + /* Before passing the socket on, or returning to caller with it still + open, we must shut down TLS. Not all MTAs allow for the continuation + of the SMTP session when TLS is shut down. We test for this by sending + a new EHLO. If we don't get a good response, we don't attempt to pass + the socket on. */ tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT); sx->send_tlsclose = FALSE; @@ -4422,84 +4652,88 @@ if (sx->completed_addr && sx->ok && sx->send_quit) && smtp_read_response(sx, sx->buffer, sizeof(sx->buffer), '2', ob->command_timeout); - if (sx->ok && f.continue_more) - goto TIDYUP; /* More addresses for another run */ - } - else - { - /* Set up a pipe for proxying TLS for the new transport process */ - - smtp_peer_options |= OPTION_TLS; - if ((sx->ok = socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) == 0)) - socket_fd = pfd[1]; + if (sx->ok && f.continue_more) + goto TIDYUP; /* More addresses for another run */ + } else - set_errno(sx->first_addr, errno, US"internal allocation problem", - DEFER, FALSE, host, + { + /* Set up a pipe for proxying TLS for the new transport process */ + + smtp_peer_options |= OPTION_TLS; + if ((sx->ok = socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) == 0)) + socket_fd = pfd[1]; + else + set_errno(sx->first_addr, errno, US"internal allocation problem", + DEFER, FALSE, host, # ifdef EXPERIMENTAL_DSN_INFO - sx->smtp_greeting, sx->helo_response, + sx->smtp_greeting, sx->helo_response, # endif - &sx->delivery_start); - } - else + &sx->delivery_start); + } + else #endif - if (f.continue_more) - goto TIDYUP; /* More addresses for another run */ - - /* If the socket is successfully passed, we mustn't send QUIT (or - indeed anything!) from here. */ + if (f.continue_more) + goto TIDYUP; /* More addresses for another run */ -/*XXX DSN_INFO: assume likely to do new HELO; but for greet we'll want to -propagate it from the initial -*/ - if (sx->ok && transport_pass_socket(tblock->name, host->name, - host->address, new_message_id, socket_fd)) - { - sx->send_quit = FALSE; + /* If the socket is successfully passed, we mustn't send QUIT (or + indeed anything!) from here. */ - /* We have passed the client socket to a fresh transport process. - If TLS is still active, we need to proxy it for the transport we - just passed the baton to. Fork a child to to do it, and return to - get logging done asap. Which way to place the work makes assumptions - about post-fork prioritisation which may not hold on all platforms. */ -#ifndef DISABLE_TLS - if (tls_out.active.sock >= 0) + /*XXX DSN_INFO: assume likely to do new HELO; but for greet we'll want to + propagate it from the initial + */ + if (sx->ok && transport_pass_socket(tblock->name, host->name, + host->address, new_message_id, socket_fd +#ifdef EXPERIMENTAL_ESMTP_LIMITS + , sx->peer_limit_mail, sx->peer_limit_rcpt, sx->peer_limit_rcptdom +#endif + )) { - int pid = exim_fork(US"tls-proxy-interproc"); - if (pid == 0) /* child; fork again to disconnect totally */ - { - /* does not return */ - smtp_proxy_tls(sx->cctx.tls_ctx, sx->buffer, sizeof(sx->buffer), pfd, - ob->command_timeout); - } + sx->send_quit = FALSE; - if (pid > 0) /* parent */ + /* We have passed the client socket to a fresh transport process. + If TLS is still active, we need to proxy it for the transport we + just passed the baton to. Fork a child to to do it, and return to + get logging done asap. Which way to place the work makes assumptions + about post-fork prioritisation which may not hold on all platforms. */ +#ifndef DISABLE_TLS + if (tls_out.active.sock >= 0) { - close(pfd[0]); - /* tidy the inter-proc to disconn the proxy proc */ - waitpid(pid, NULL, 0); - tls_close(sx->cctx.tls_ctx, TLS_NO_SHUTDOWN); - sx->cctx.tls_ctx = NULL; - (void)close(sx->cctx.sock); - sx->cctx.sock = -1; - continue_transport = NULL; - continue_hostname = NULL; - goto TIDYUP; + int pid = exim_fork(US"tls-proxy-interproc"); + if (pid == 0) /* child; fork again to disconnect totally */ + { + /* does not return */ + smtp_proxy_tls(sx->cctx.tls_ctx, sx->buffer, sizeof(sx->buffer), pfd, + ob->command_timeout); + } + + if (pid > 0) /* parent */ + { + close(pfd[0]); + /* tidy the inter-proc to disconn the proxy proc */ + waitpid(pid, NULL, 0); + tls_close(sx->cctx.tls_ctx, TLS_NO_SHUTDOWN); + sx->cctx.tls_ctx = NULL; + (void)close(sx->cctx.sock); + sx->cctx.sock = -1; + continue_transport = NULL; + continue_hostname = NULL; + goto TIDYUP; + } + log_write(0, LOG_PANIC_DIE, "fork failed"); } - log_write(0, LOG_PANIC_DIE, "fork failed"); - } #endif + } } - } - /* If RSET failed and there are addresses left, they get deferred. */ - else - set_errno(sx->first_addr, errno, msg, DEFER, FALSE, host, + /* If RSET failed and there are addresses left, they get deferred. */ + else + set_errno(sx->first_addr, errno, msg, DEFER, FALSE, host, #ifdef EXPERIMENTAL_DSN_INFO - sx->smtp_greeting, sx->helo_response, + sx->smtp_greeting, sx->helo_response, #endif - &sx->delivery_start); + &sx->delivery_start); + } } - } /* End off tidily with QUIT unless the connection has died or the socket has been passed to another process. */ @@ -4613,12 +4847,24 @@ if (dane_held) } } continue_sequence = 1; /* for consistency */ - goto DANE_DOMAINS; + goto REPEAT_CONN; + } +#endif + +#ifdef EXPERIMENTAL_ESMTP_LIMITS +if (mail_limit && sx->first_addr) + { + /* Reset the sequence count since we closed the connection. This is flagged + on the pipe back to the delivery process so that a non-continued-conn delivery + is logged. */ + + continue_sequence = 1; /* for consistency */ + clearflag(sx->first_addr, af_cont_conn); + setflag(sx->first_addr, af_new_conn); /* clear * from logging */ + goto REPEAT_CONN; } #endif -continue_transport = NULL; -continue_hostname = NULL; return yield; TIDYUP: diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h index 1ea2a4d00..aff3f5452 100644 --- a/src/src/transports/smtp.h +++ b/src/src/transports/smtp.h @@ -171,15 +171,25 @@ typedef struct { BOOL pending_BDAT:1; BOOL RCPT_452:1; BOOL good_RCPT:1; +#ifdef EXPERIMENTAL_ESMTP_LIMITS + BOOL single_rcpt_domain:1; +#endif BOOL completed_addr:1; BOOL send_rset:1; BOOL send_quit:1; BOOL send_tlsclose:1; + unsigned peer_offered; +#ifdef EXPERIMENTAL_ESMTP_LIMITS + unsigned peer_limit_mail; + unsigned peer_limit_rcpt; + unsigned peer_limit_rcptdom; +#endif + + unsigned max_mail; int max_rcpt; int cmd_count; - unsigned peer_offered; unsigned avoid_option; uschar * igquotstr; uschar * helo_data; @@ -188,6 +198,11 @@ typedef struct { uschar * helo_response; #endif #ifndef DISABLE_PIPE_CONNECT + /* Info about the EHLO response stored to / retrieved from cache. When + operating early-pipe, we use the cached values. For each of plaintext and + crypted we store bitmaps for ESMTP features and AUTH methods. If the LIMITS + extension is built and usable them at least one of the limits values cached + is nonzero, and we use the values to constrain the connection. */ ehlo_resp_precis ehlo_resp; #endif diff --git a/test/aux-var-src/tls_conf_prefix b/test/aux-var-src/tls_conf_prefix index 541817668..e3f09b98b 100644 --- a/test/aux-var-src/tls_conf_prefix +++ b/test/aux-var-src/tls_conf_prefix @@ -24,3 +24,6 @@ pipelining_connect_advertise_hosts = : .ifdef _HAVE_DMARC dmarc_tld_file = .endif +.ifdef _EXP_LIMITS +limits_advertise_hosts = !* +.endif diff --git a/test/confs/0453 b/test/confs/0453 index 3ecc86591..c611d4a41 100644 --- a/test/confs/0453 +++ b/test/confs/0453 @@ -1,6 +1,6 @@ # Exim test configuration 0453 -LIMIT= +ERROR_DETAILS= .include DIR/aux-var/std_conf_prefix @@ -11,7 +11,7 @@ primary_hostname = myhost.test.ex qualify_domain = test.ex -LIMIT +ERROR_DETAILS # End diff --git a/test/confs/0564 b/test/confs/0564 index de71325af..fd38c6213 100644 --- a/test/confs/0564 +++ b/test/confs/0564 @@ -15,6 +15,9 @@ pipelining_connect_advertise_hosts = .ifdef _HAVE_DMARC dmarc_tld_file = .endif +.ifdef _OPT_MAIN_LIMITS_ADVERTISE_HOSTS +limits_advertise_hosts = !* +.endif # ----- Main settings ----- diff --git a/test/confs/0900 b/test/confs/0900 index 7775fc4b0..a56ec0e5c 100644 --- a/test/confs/0900 +++ b/test/confs/0900 @@ -23,7 +23,9 @@ pipelining_connect_advertise_hosts = : .ifdef _HAVE_DMARC dmarc_tld_file = .endif - +.ifdef _OPT_MAIN_LIMITS_ADVERTISE_HOSTS +limits_advertise_hosts = !* +.endif # ----- Main settings ----- diff --git a/test/confs/0901 b/test/confs/0901 index a1f391613..361a9bf6c 100644 --- a/test/confs/0901 +++ b/test/confs/0901 @@ -17,6 +17,9 @@ tls_advertise_hosts = ${if eq {SRV}{tls} {*}} .ifdef _HAVE_DMARC dmarc_tld_file = .endif +.ifdef _OPT_MAIN_LIMITS_ADVERTISE_HOSTS +limits_advertise_hosts = !* +.endif pipelining_advertise_hosts = : diff --git a/test/confs/0906 b/test/confs/0906 index 5bd5f2a4f..57f359ff0 100644 --- a/test/confs/0906 +++ b/test/confs/0906 @@ -16,6 +16,9 @@ pipelining_connect_advertise_hosts = .ifdef _HAVE_DMARC dmarc_tld_file = .endif +.ifdef _EXP_LIMITS +limits_advertise_hosts = !* +.endif # ----- Main settings ----- diff --git a/test/confs/3414 b/test/confs/3414 index 5d0f93c46..25205a4c1 100644 --- a/test/confs/3414 +++ b/test/confs/3414 @@ -13,6 +13,9 @@ gecos_pattern = "" gecos_name = CALLER_NAME chunking_advertise_hosts = tls_advertise_hosts = +.ifdef _EXP_LIMITS +limits_advertise_hosts = !* +.endif # ----- Main settings ----- diff --git a/test/confs/4050 b/test/confs/4050 index c26b7a9c2..fd3d7db54 100644 --- a/test/confs/4050 +++ b/test/confs/4050 @@ -25,6 +25,9 @@ tls_advertise_hosts = .ifdef _HAVE_DMARC dmarc_tld_file = .endif +.ifdef _OPT_MAIN_LIMITS_ADVERTISE_HOSTS +limits_advertise_hosts = !* +.endif pipelining_connect_advertise_hosts = CONNECTCOND retry_data_expire = RETRY diff --git a/test/confs/4710 b/test/confs/4710 new file mode 100644 index 000000000..017fb56eb --- /dev/null +++ b/test/confs/4710 @@ -0,0 +1,36 @@ +# Exim test configuration 4710 +# + +exim_path = EXIM_PATH +keep_environment = USER +host_lookup_order = bydns +primary_hostname = myhost.test.ex +spool_directory = DIR/spool +log_file_path = DIR/spool/log/%slog +gecos_pattern = "" +gecos_name = CALLER_NAME +tls_advertise_hosts = +.ifdef _HAVE_PIPE_CONNECT +pipelining_connect_advertise_hosts = : +.endif +.ifdef _HAVE_DMARC +dmarc_tld_file = +.endif + +# ----- Main settings ----- + +.ifdef CONTROL +limits_advertise_hosts = : +.endif +.ifdef MAXNM +smtp_accept_max_per_connection = ${if eq {127.0.0.1}{$sender_host_address} {MAXNM}{44}} +.endif +.ifdef RCPT_MSG +recipients_max = RCPT_MSG +.endif + +# ----- ACL ----- + +begin acl + +# End diff --git a/test/confs/4711 b/test/confs/4711 new file mode 100644 index 000000000..23f141d02 --- /dev/null +++ b/test/confs/4711 @@ -0,0 +1,31 @@ +# Exim test configuration 4711 + +.include DIR/aux-var/std_conf_prefix + + +# ----- Main settings ----- + +acl_smtp_rcpt = accept + +# ----- Routers ----- + +begin routers + +send_to_server: + driver = accept + transport = to_server + +# ----- Transports ----- + +begin transports + +to_server: + driver = smtp + allow_localhost + hosts = 127.0.0.1 + port = PORT_D +.ifdef RCPT_MSG + max_rcpt = RCPT_MSG +.endif + +# End diff --git a/test/confs/4712 b/test/confs/4712 new file mode 100644 index 000000000..c48be50dc --- /dev/null +++ b/test/confs/4712 @@ -0,0 +1,28 @@ +# Exim test configuration 4712 + +.include DIR/aux-var/std_conf_prefix + + +# ----- Main settings ----- + +acl_smtp_rcpt = accept + +# ----- Routers ----- + +begin routers + +send_to_server: + driver = accept + transport = to_server + +# ----- Transports ----- + +begin transports + +to_server: + driver = smtp + allow_localhost + hosts = 127.0.0.1 + port = PORT_D + +# End diff --git a/test/confs/4713 b/test/confs/4713 new file mode 100644 index 000000000..c5394fb05 --- /dev/null +++ b/test/confs/4713 @@ -0,0 +1,31 @@ +# Exim test configuration 4711 + +.include DIR/aux-var/std_conf_prefix + + +# ----- Main settings ----- + +acl_smtp_rcpt = accept + +# ----- Routers ----- + +begin routers + +send_to_server: + driver = accept + transport = to_server + +# ----- Transports ----- + +begin transports + +to_server: + driver = smtp + allow_localhost + hosts = 127.0.0.1 + port = PORT_D +.ifdef CONTROL + multi_domain = false +.endif + +# End diff --git a/test/confs/4714 b/test/confs/4714 new file mode 100644 index 000000000..dd06bd8e5 --- /dev/null +++ b/test/confs/4714 @@ -0,0 +1,36 @@ +# Exim test configuration 4714 + +.include DIR/aux-var/std_conf_prefix + + +# ----- Main settings ----- + +log_selector = +received_recipients +queue_run_in_order + +acl_smtp_rcpt = accept + +# ----- Routers ----- + +begin routers + +send_to_server: + driver = accept + transport = to_server + +# ----- Transports ----- + +begin transports + +to_server: + driver = smtp + allow_localhost + hosts = 127.0.0.1 + port = PORT_D + +# ----- Retry ----- + +begin retry +* * F,5d,10s + +# End diff --git a/test/confs/5670 b/test/confs/5670 index d4bedac51..f4252668e 100644 --- a/test/confs/5670 +++ b/test/confs/5670 @@ -32,11 +32,11 @@ tls_ocsp_file = PEM DIR/tmp/ocsp/double_r.ocsp.pem .ifdef _HAVE_GNUTLS -tls_require_ciphers = ${if eq {LIMIT}{TLS1.2} {NORMAL:!VERS-ALL:+VERS-TLS1.2} {}} +tls_require_ciphers = ${if eq {TRUSTED}{TLS1.2} {NORMAL:!VERS-ALL:+VERS-TLS1.2} {}} .endif .ifdef _HAVE_OPENSSL -.ifdef LIMIT -openssl_options = ${if eq {LIMIT}{TLS1.2} {+no_tlsv1_3} {}} +.ifdef TRUSTED +openssl_options = ${if eq {TRUSTED}{TLS1.2} {+no_tlsv1_3} {}} .endif .endif @@ -81,7 +81,7 @@ remote_delivery: hosts_require_tls = * .ifdef _HAVE_GNUTLS - tls_require_ciphers = ${if eq {LIMIT}{TLS1.2} \ + tls_require_ciphers = ${if eq {TRUSTED}{TLS1.2} \ {NONE:\ +SIGN-RSA-SHA256:+VERS-TLS-ALL:+ECDHE-RSA:+DHE-RSA:+RSA\ :+CIPHER-ALL:+MAC-ALL:+COMP-NULL:+CURVE-ALL:+CTYPE-X509} \ diff --git a/test/log/4710 b/test/log/4710 new file mode 100644 index 000000000..6e70d69ad --- /dev/null +++ b/test/log/4710 @@ -0,0 +1,6 @@ +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port PORT_D diff --git a/test/log/4711 b/test/log/4711 new file mode 100644 index 000000000..520ad1f97 --- /dev/null +++ b/test/log/4711 @@ -0,0 +1,24 @@ +1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmaX-0005vi-00 => a@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaX-0005vi-00 -> b@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaX-0005vi-00 -> c@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaX-0005vi-00 -> d@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaX-0005vi-00 -> e@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaX-0005vi-00 Completed +1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmaY-0005vi-00 => a@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaY-0005vi-00 -> b@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaY-0005vi-00 => c@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1]* C="250 message received" +1999-03-02 09:44:33 10HmaY-0005vi-00 -> d@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1]* C="250 message received" +1999-03-02 09:44:33 10HmaY-0005vi-00 => e@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1]* C="250 message received" +1999-03-02 09:44:33 10HmaY-0005vi-00 Completed +1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmaZ-0005vi-00 => a@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaZ-0005vi-00 -> b@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaZ-0005vi-00 => c@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1]* C="250 message received" +1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed +1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmbA-0005vi-00 => a@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmbA-0005vi-00 -> b@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmbA-0005vi-00 => c@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmbA-0005vi-00 Completed diff --git a/test/log/4712 b/test/log/4712 new file mode 100644 index 000000000..8479516c1 --- /dev/null +++ b/test/log/4712 @@ -0,0 +1,8 @@ +1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmaX-0005vi-00 => a@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaX-0005vi-00 => b@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1]* C="250 message received" +1999-03-02 09:44:33 10HmaX-0005vi-00 Completed +1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmaY-0005vi-00 => a@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaY-0005vi-00 => b@test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaY-0005vi-00 Completed diff --git a/test/log/4713 b/test/log/4713 new file mode 100644 index 000000000..09a56f3bf --- /dev/null +++ b/test/log/4713 @@ -0,0 +1,11 @@ +1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmaX-0005vi-00 => a@a.test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaX-0005vi-00 -> b@b.test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaX-0005vi-00 Completed +1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss +1999-03-02 09:44:33 10HmaY-0005vi-00 => a@a.test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message received" +1999-03-02 09:44:33 10HmaY-0005vi-00 => b@b.test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1]* C="250 second message received" +1999-03-02 09:44:33 10HmaY-0005vi-00 => c@c.test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1]* C="250 third message received" +1999-03-02 09:44:33 10HmaY-0005vi-00 -> a2@a.test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1]* C="250 message received" +1999-03-02 09:44:33 10HmaY-0005vi-00 -> b2@b.test.ex R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1]* C="250 second message received" +1999-03-02 09:44:33 10HmaY-0005vi-00 Completed diff --git a/test/log/4714 b/test/log/4714 new file mode 100644 index 000000000..f97d89f6c --- /dev/null +++ b/test/log/4714 @@ -0,0 +1,14 @@ +1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss for r1_1.test.ex r1_2.test.ex +1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss for r2_1.test.ex r2_2.test.ex +1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@the.local.host.name U=CALLER P=local S=sss for r3_1.test.ex r3_2.test.ex +1999-03-02 09:44:33 Start queue run: pid=pppp -qq +1999-03-02 09:44:33 10HmaX-0005vi-00 => r1_1.test.ex@the.local.host.name R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message 1 received" +1999-03-02 09:44:33 10HmaX-0005vi-00 => r1_2.test.ex@the.local.host.name R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1]* C="250 message 2 received" +1999-03-02 09:44:33 10HmaX-0005vi-00 Completed +1999-03-02 09:44:33 10HmaZ-0005vi-00 => r3_1.test.ex@the.local.host.name R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1]* C="250 message 3 received" +1999-03-02 09:44:33 10HmaZ-0005vi-00 => r3_2.test.ex@the.local.host.name R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1]* C="250 message 4 received" +1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed +1999-03-02 09:44:33 10HmaY-0005vi-00 => r2_1.test.ex@the.local.host.name R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1]* C="250 message 5 received" +1999-03-02 09:44:33 10HmaY-0005vi-00 => r2_2.test.ex@the.local.host.name R=send_to_server T=to_server H=127.0.0.1 [127.0.0.1] C="250 message 6 received" +1999-03-02 09:44:33 10HmaY-0005vi-00 Completed +1999-03-02 09:44:33 End queue run: pid=pppp -qq diff --git a/test/runtest b/test/runtest index 8ebba5023..8f49b26d3 100755 --- a/test/runtest +++ b/test/runtest @@ -1020,6 +1020,9 @@ RESET_AFTER_EXTRA_LINE_READ: # ARC is not always supported by the build next if /^arc_sign =/; + # LIMITS is not always supported by the build + next if /^limits_advertise_hosts =/; + # TLS resumption is not always supported by the build next if /^tls_resumption_hosts =/; next if /^-tls_resumption/; @@ -1285,6 +1288,9 @@ RESET_AFTER_EXTRA_LINE_READ: # Experimental_REQUIRETLS next if / in tls_advertise_requiretls?\? no \(end of list\)/; + # Experimental_LIMITS + next if / in limits_advertise_hosts?\? no \(matched "!\*"\)/; + # TCP Fast Open next if /^(ppppp )?setsockopt FASTOPEN: Network Error/; diff --git a/test/scripts/0000-Basic/0453 b/test/scripts/0000-Basic/0453 index 8c199fe39..b07a7125c 100644 --- a/test/scripts/0000-Basic/0453 +++ b/test/scripts/0000-Basic/0453 @@ -9,7 +9,7 @@ helo helo **** 1 -exim -DLIMIT=smtp_max_synprot_errors=1 -bs +exim -DERROR_DETAILS=smtp_max_synprot_errors=1 -bs mail from:<> mail from:<> mail from:<> diff --git a/test/scripts/4710-esmtp-limits/4710 b/test/scripts/4710-esmtp-limits/4710 new file mode 100644 index 000000000..875613cab --- /dev/null +++ b/test/scripts/4710-esmtp-limits/4710 @@ -0,0 +1,86 @@ +# ESMTP LIMITS extension, server +# +# Baseline: advertised by default +exim -DSERVER=server -bd -oX PORT_D +**** +client 127.0.0.1 PORT_D +??? 220 +EHLO tester +??? 250- +??? 250-SIZE +??? 250-LIMITS MAILMAX=1000 +??? 250 +**** +killdaemon +# +# not advertised when disabled +exim -DSERVER=server -DCONTROL=disable -bd -oX PORT_D +**** +client 127.0.0.1 PORT_D +??? 220 +EHLO tester +??? 250- +??? 250-SIZE +??? 250-8BITMIME +**** +killdaemon +# +# smtp_accept_max_per_connection controls the MAILMAX value advertised, and is expanded +exim -DSERVER=server -DMAXNM=42 -bd -oX PORT_D +**** +client 127.0.0.1 PORT_D +??? 220 +EHLO tester +??? 250- +??? 250-SIZE +??? 250-LIMITS MAILMAX=42 +??? 250 +**** +client HOSTIPV4 PORT_D +??? 220 +EHLO tester +??? 250- +??? 250-SIZE +??? 250-LIMITS MAILMAX=44 +??? 250 +**** +killdaemon +# +# +# not advertised when zero and no RCPTMAX +exim -DSERVER=server -DMAXNM=0 -bd -oX PORT_D +**** +client 127.0.0.1 PORT_D +??? 220 +EHLO tester +??? 250- +??? 250-SIZE +??? 250 +**** +killdaemon +# +# reeipients_max controls an advertised RCPTMAX +exim -DSERVER=server -DRCPT_MSG=5 -bd -oX PORT_D +**** +client 127.0.0.1 PORT_D +??? 220 +EHLO tester +??? 250- +??? 250-SIZE +??? 250-LIMITS MAILMAX=1000 RCPTMAX=5 +??? 250 +**** +killdaemon +# +# RCPTMAX can appear on its own +exim -DSERVER=server -DMAXNM=0 -DRCPT_MSG=5 -bd -oX PORT_D +**** +client 127.0.0.1 PORT_D +??? 220 +EHLO tester +??? 250- +??? 250-SIZE +??? 250-LIMITS RCPTMAX=5 +??? 250 +**** +killdaemon diff --git a/test/scripts/4710-esmtp-limits/4711 b/test/scripts/4710-esmtp-limits/4711 new file mode 100644 index 000000000..ffbfa07d0 --- /dev/null +++ b/test/scripts/4710-esmtp-limits/4711 @@ -0,0 +1,138 @@ +# ESMTP LIMITS extension, client RCPTMAX +# +# Baseline: no RCPTMAX advertised, can send 5 RCPT commands +server PORT_D +220 Hi there +EHLO +250-yeah mate +250 LIMITS MAILMAX=10 +MAIL FROM +250 mail cmd good +RCPT TO +250 rcpt cmd 1 good +RCPT TO +250 rcpt cmd 2 good +RCPT TO +250 rcpt cmd 3 good +RCPT TO +250 rcpt cmd 4 good +RCPT TO +250 rcpt cmd 5 good +DATA +352 go ahead +. +250 message received +QUIT +220 bye +**** +exim -odi a@test.ex b@test.ex c@test.ex d@test.ex e@test.ex +**** +# +# RCPTMAX advertised, limits RCPT commands +# Client should immediate-retry fusther MAIL transaction for remaning rcpts +server PORT_D +220 Hi there +EHLO +250-yeah mate +250 LIMITS RCPTMAX=2 +MAIL FROM +250 mail cmd good +RCPT TO +250 rcpt cmd 1 good +RCPT TO +250 rcpt cmd 2 good +DATA +352 go ahead +. +250 message received +MAIL FROM +250 mail cmd good +RCPT TO +250 rcpt cmd 3 good +RCPT TO +250 rcpt cmd 4 good +DATA +352 go ahead +. +250 message received +MAIL FROM +250 mail cmd good +RCPT TO +250 rcpt cmd 5 good +DATA +352 go ahead +. +250 message received +QUIT +220 bye +**** +exim -odi a@test.ex b@test.ex c@test.ex d@test.ex e@test.ex +**** +# +# RCPTMAX advertised, overrides larger tpt max_rcpt and limits RCPT commands +server PORT_D +220 Hi there +EHLO +250-yeah mate +250 LIMITS RCPTMAX=2 +MAIL FROM +250 mail cmd good +RCPT TO +250 rcpt cmd 1 good +RCPT TO +250 rcpt cmd 2 good +DATA +352 go ahead +. +250 message received +MAIL FROM +250 mail cmd good +RCPT TO +250 rcpt cmd 3 good +DATA +352 go ahead +. +250 message received +QUIT +220 bye +**** +exim -odi -DRCPT_MSG=3 a@test.ex b@test.ex c@test.ex +**** +# +# RCPTMAX advertised, does not override smaller tpt max_rcpt which limits RCPT commands +# Client make a separate conn for the second transaction +server PORT_D 2 +220 Hi there +EHLO +250-yeah mate +250 LIMITS RCPTMAX=3 +MAIL FROM +250 mail cmd good +RCPT TO +250 rcpt cmd 1 good +RCPT TO +250 rcpt cmd 2 good +DATA +352 go ahead +. +250 message received +QUIT +220 bye +*eof +220 Hi there +EHLO +250-yeah mate +250 LIMITS RCPTMAX=3 +MAIL FROM +250 mail cmd good +RCPT TO +250 rcpt cmd 3 good +DATA +352 go ahead +. +250 message received +QUIT +220 bye +**** +exim -odi -DRCPT_MSG=2 a@test.ex b@test.ex c@test.ex +**** diff --git a/test/scripts/4710-esmtp-limits/4712 b/test/scripts/4710-esmtp-limits/4712 new file mode 100644 index 000000000..c5d1cab4e --- /dev/null +++ b/test/scripts/4710-esmtp-limits/4712 @@ -0,0 +1,65 @@ +# ESMTP LIMITS extension, client MAILMAX +# +# Baseline: no MAILMAX advertised, can send 2 messages +# - limiting the RCPT to 1 is convenient to get the multiple messages +server PORT_D +220 Hi there +EHLO +250-yeah mate +250 LIMITS RCPTMAX=1 +MAIL FROM +250 mail cmd 1 good +RCPT TO +250 rcpt cmd good +DATA +352 go ahead +. +250 message received +MAIL FROM +250 mail cmd 2 good +RCPT TO +250 rcpt cmd good +DATA +352 go ahead +. +250 message received +QUIT +220 bye +**** +exim -odi a@test.ex b@test.ex +**** +# +# limited to one MAIL per conn. Client should immediate-retry a second one. +server PORT_D 2 +220 Hi there +EHLO +250-yeah mate +250 LIMITS RCPTMAX=1 MAILMAX=1 +MAIL FROM +250 mail cmd 1 good +RCPT TO +250 rcpt cmd good +DATA +352 go ahead +. +250 message received +QUIT +220 bye +*eof +220 Hi there +EHLO +250-yeah mate +250 LIMITS RCPTMAX=1 MAILMAX=1 +MAIL FROM +250 mail cmd 2 good +RCPT TO +250 rcpt cmd good +DATA +352 go ahead +. +250 message received +QUIT +220 bye +**** +exim -odi a@test.ex b@test.ex +**** diff --git a/test/scripts/4710-esmtp-limits/4713 b/test/scripts/4710-esmtp-limits/4713 new file mode 100644 index 000000000..6003f2729 --- /dev/null +++ b/test/scripts/4710-esmtp-limits/4713 @@ -0,0 +1,64 @@ +# ESMTP LIMITS extension, client RCPTDOMAINMAX Limit +# +# Baseline: no RCPTDOMAINMAX Limit advertised, can send RCPT commands with distinct domains +server PORT_D +220 Hi there +EHLO +250-yeah mate +250 LIMITS MAILMAX=10 +MAIL FROM +250 mail cmd good +RCPT TO +250 rcpt cmd 1 good +RCPT TO +250 rcpt cmd 2 good +DATA +352 go ahead +. +250 message received +QUIT +220 bye +**** +exim -odi a@a.test.ex b@b.test.ex +**** +# +# RCPTDOMAINMAX Limit advertised, second domain temp-rejected +# Client should immediate-retry further MAIL transactions for remaining rcpts +server PORT_D +220 Hi there +EHLO +250-yeah mate +250 LIMITS MAILMAX=10 RCPTDOMAINMAX=100 +MAIL FROM +250 mail cmd good +RCPT TO: +250 rcpt cmd 1 good +RCPT TO: +250 rcpt cmd 2 good +DATA +352 go ahead +. +250 message received +MAIL FROM +250 second mail cmd good +RCPT TO: +250 rcpt cmd 1 good +RCPT TO +250 rcpt cmd 2 good +DATA +352 go ahead +. +250 second message received +MAIL FROM +250 third mail cmd good +RCPT TO: +250 rcpt cmd 1 good +DATA +352 go ahead +. +250 third message received +QUIT +220 bye +**** +exim -odi a@a.test.ex b@b.test.ex c@c.test.ex a2@a.test.ex b2@b.test.ex +**** diff --git a/test/scripts/4710-esmtp-limits/4714 b/test/scripts/4710-esmtp-limits/4714 new file mode 100644 index 000000000..f97d989e8 --- /dev/null +++ b/test/scripts/4710-esmtp-limits/4714 @@ -0,0 +1,84 @@ +# ESMTP LIMITS extension, client continued-connection +# +# queue up 3 messages each with 2 recipients +exim -odq r1_1.test.ex r1_2.test.ex +Subject: message 1 +**** +exim -odq r2_1.test.ex r2_2.test.ex +Subject: message 2 +**** +exim -odq r3_1.test.ex r3_2.test.ex +Subject: message 3 +**** +# +# Handed limits of 5 MAIL, 1 RCPT, expect to use 5 transactions in a one connection +# when the client does a 2-phase queue run, followed by one transaction in one connection +# from the same queue run. +# The second pair and third initial should be from continued-connection trasports, flagged by the log lines. +server PORT_D 2 +220 Hi there +EHLO +250-yeah mate +250 LIMITS MAILMAX=5 RCPTMAX=1 +MAIL FROM +250 mail cmd 1 good +RCPT TO +250 rcpt cmd good +DATA +352 go ahead +. +250 message 1 received +MAIL FROM +250 mail cmd 2 good +RCPT TO +250 rcpt cmd good +DATA +352 go ahead +. +250 message 2 received +MAIL FROM +250 mail cmd 3 good +RCPT TO +250 rcpt cmd good +DATA +352 go ahead +. +250 message 3 received +MAIL FROM +250 mail cmd 4 good +RCPT TO +250 rcpt cmd good +DATA +352 go ahead +. +250 message 4 received +MAIL FROM +250 mail cmd 5 good +RCPT TO +250 rcpt cmd good +DATA +352 go ahead +. +250 message 5 received +QUIT +221 bye +*eof +220 Hi there +EHLO +250-yeah mate +250 +MAIL FROM +250 mail cmd 1 good +RCPT TO +250 rcpt cmd good +DATA +352 go ahead +. +250 message 6 received +QUIT +221 bye +*eof +**** +# +exim -qq +**** diff --git a/test/scripts/4710-esmtp-limits/REQUIRES b/test/scripts/4710-esmtp-limits/REQUIRES new file mode 100644 index 000000000..4817265b8 --- /dev/null +++ b/test/scripts/4710-esmtp-limits/REQUIRES @@ -0,0 +1 @@ +support Experimental_ESMTP_Limits diff --git a/test/scripts/5670-OCSP-GnuTLS-1.3/5670 b/test/scripts/5670-OCSP-GnuTLS-1.3/5670 index 1df75fbf9..1ff6d8161 100644 --- a/test/scripts/5670-OCSP-GnuTLS-1.3/5670 +++ b/test/scripts/5670-OCSP-GnuTLS-1.3/5670 @@ -14,10 +14,10 @@ system 'cat server1.example.com/server1.example.com.ocsp.signernocert.good.resp. exim -z '1: TLS1.2 Server sends good leaf-staple on request, to client requiring RSA auth' **** # -sudo exim -bd -oX PORT_D -DSERVER=server -DLIMIT=TLS1.2 +sudo exim -bd -oX PORT_D -DSERVER=server -DTRUSTED=TLS1.2 **** # -exim -odf -DOPT=rsa -DLIMIT=TLS1.2 rsa.auth@test.ex +exim -odf -DOPT=rsa -DTRUSTED=TLS1.2 rsa.auth@test.ex Subject: test . @@ -29,7 +29,7 @@ exim -z '2: TLS1.3 Server sends good 3-element staple on request, to client requ **** # # Prefix with sudo to get SSLKEYLOGFILE to work. Only works on the server. -exim -bd -oX PORT_D -DSERVER=server -DLIMIT=TLS1.3 +exim -bd -oX PORT_D -DSERVER=server -DTRUSTED=TLS1.3 **** exim -odf -DOPT=rsa rsa.auth@test.ex Subject: test @@ -43,7 +43,7 @@ killdaemon exim -z '3: TLS1.3 Server sends bad nonleaf staple, client detects it' **** # -EXIM_TESTHARNESS_DISABLE_OCSPVALIDITYCHECK=y exim -bd -oX PORT_D -DSERVER=server -DLIMIT=TLS1.3 -DCONTROL=bad +EXIM_TESTHARNESS_DISABLE_OCSPVALIDITYCHECK=y exim -bd -oX PORT_D -DSERVER=server -DTRUSTED=TLS1.3 -DCONTROL=bad **** exim -odf -DOPT=rsa rsa.auth@test.ex Subject: test diff --git a/test/stdout/4710 b/test/stdout/4710 new file mode 100644 index 000000000..35a51c450 --- /dev/null +++ b/test/stdout/4710 @@ -0,0 +1,87 @@ +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 tester +??? 250- +<<< 250-myhost.test.ex Hello tester [127.0.0.1] +??? 250-SIZE +<<< 250-SIZE 52428800 +??? 250-LIMITS MAILMAX=1000 +<<< 250-LIMITS MAILMAX=1000 +??? 250 +<<< 250-8BITMIME +End of script +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 tester +??? 250- +<<< 250-myhost.test.ex Hello tester [127.0.0.1] +??? 250-SIZE +<<< 250-SIZE 52428800 +??? 250-8BITMIME +<<< 250-8BITMIME +End of script +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 tester +??? 250- +<<< 250-myhost.test.ex Hello tester [127.0.0.1] +??? 250-SIZE +<<< 250-SIZE 52428800 +??? 250-LIMITS MAILMAX=42 +<<< 250-LIMITS MAILMAX=42 +??? 250 +<<< 250-8BITMIME +End of script +Connecting to ip4.ip4.ip4.ip4 port 1225 ... connected +??? 220 +<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +>>> EHLO tester +??? 250- +<<< 250-myhost.test.ex Hello tester [ip4.ip4.ip4.ip4] +??? 250-SIZE +<<< 250-SIZE 52428800 +??? 250-LIMITS MAILMAX=44 +<<< 250-LIMITS MAILMAX=44 +??? 250 +<<< 250-8BITMIME +End of script +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 tester +??? 250- +<<< 250-myhost.test.ex Hello tester [127.0.0.1] +??? 250-SIZE +<<< 250-SIZE 52428800 +??? 250 +<<< 250-8BITMIME +End of script +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 tester +??? 250- +<<< 250-myhost.test.ex Hello tester [127.0.0.1] +??? 250-SIZE +<<< 250-SIZE 52428800 +??? 250-LIMITS MAILMAX=1000 RCPTMAX=5 +<<< 250-LIMITS MAILMAX=1000 RCPTMAX=5 +??? 250 +<<< 250-8BITMIME +End of script +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 tester +??? 250- +<<< 250-myhost.test.ex Hello tester [127.0.0.1] +??? 250-SIZE +<<< 250-SIZE 52428800 +??? 250-LIMITS RCPTMAX=5 +<<< 250-LIMITS RCPTMAX=5 +??? 250 +<<< 250-8BITMIME +End of script diff --git a/test/stdout/4711 b/test/stdout/4711 new file mode 100644 index 000000000..78b5203d4 --- /dev/null +++ b/test/stdout/4711 @@ -0,0 +1,183 @@ + +******** SERVER ******** +Listening on port 1225 ... +Connection request from [127.0.0.1] +220 Hi there +EHLO the.local.host.name +250-yeah mate +250 LIMITS MAILMAX=10 +MAIL FROM: +250 mail cmd good +RCPT TO: +250 rcpt cmd 1 good +RCPT TO: +250 rcpt cmd 2 good +RCPT TO: +250 rcpt cmd 3 good +RCPT TO: +250 rcpt cmd 4 good +RCPT TO: +250 rcpt cmd 5 good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +QUIT +220 bye +End of script +Listening on port 1225 ... +Connection request from [127.0.0.1] +220 Hi there +EHLO the.local.host.name +250-yeah mate +250 LIMITS RCPTMAX=2 +MAIL FROM: +250 mail cmd good +RCPT TO: +250 rcpt cmd 1 good +RCPT TO: +250 rcpt cmd 2 good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +MAIL FROM: +250 mail cmd good +RCPT TO: +250 rcpt cmd 3 good +RCPT TO: +250 rcpt cmd 4 good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +MAIL FROM: +250 mail cmd good +RCPT TO: +250 rcpt cmd 5 good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +QUIT +220 bye +End of script +Listening on port 1225 ... +Connection request from [127.0.0.1] +220 Hi there +EHLO the.local.host.name +250-yeah mate +250 LIMITS RCPTMAX=2 +MAIL FROM: +250 mail cmd good +RCPT TO: +250 rcpt cmd 1 good +RCPT TO: +250 rcpt cmd 2 good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +MAIL FROM: +250 mail cmd good +RCPT TO: +250 rcpt cmd 3 good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +QUIT +220 bye +End of script +Listening on port 1225 ... +Connection request from [127.0.0.1] +220 Hi there +EHLO the.local.host.name +250-yeah mate +250 LIMITS RCPTMAX=3 +MAIL FROM: +250 mail cmd good +RCPT TO: +250 rcpt cmd 1 good +RCPT TO: +250 rcpt cmd 2 good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmbA-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +QUIT +220 bye +Expected EOF read from client +Listening on port 1225 ... +Connection request from [127.0.0.1] +220 Hi there +EHLO the.local.host.name +250-yeah mate +250 LIMITS RCPTMAX=3 +MAIL FROM: +250 mail cmd good +RCPT TO: +250 rcpt cmd 3 good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmbA-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +QUIT +220 bye +End of script diff --git a/test/stdout/4712 b/test/stdout/4712 new file mode 100644 index 000000000..69be8af64 --- /dev/null +++ b/test/stdout/4712 @@ -0,0 +1,89 @@ + +******** SERVER ******** +Listening on port 1225 ... +Connection request from [127.0.0.1] +220 Hi there +EHLO the.local.host.name +250-yeah mate +250 LIMITS RCPTMAX=1 +MAIL FROM: +250 mail cmd 1 good +RCPT TO: +250 rcpt cmd good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +MAIL FROM: +250 mail cmd 2 good +RCPT TO: +250 rcpt cmd good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +QUIT +220 bye +End of script +Listening on port 1225 ... +Connection request from [127.0.0.1] +220 Hi there +EHLO the.local.host.name +250-yeah mate +250 LIMITS RCPTMAX=1 MAILMAX=1 +MAIL FROM: +250 mail cmd 1 good +RCPT TO: +250 rcpt cmd good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +QUIT +220 bye +Expected EOF read from client +Listening on port 1225 ... +Connection request from [127.0.0.1] +220 Hi there +EHLO the.local.host.name +250-yeah mate +250 LIMITS RCPTMAX=1 MAILMAX=1 +MAIL FROM: +250 mail cmd 2 good +RCPT TO: +250 rcpt cmd good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +QUIT +220 bye +End of script diff --git a/test/stdout/4713 b/test/stdout/4713 new file mode 100644 index 000000000..02b10ea77 --- /dev/null +++ b/test/stdout/4713 @@ -0,0 +1,86 @@ + +******** SERVER ******** +Listening on port 1225 ... +Connection request from [127.0.0.1] +220 Hi there +EHLO the.local.host.name +250-yeah mate +250 LIMITS MAILMAX=10 +MAIL FROM: +250 mail cmd good +RCPT TO: +250 rcpt cmd 1 good +RCPT TO: +250 rcpt cmd 2 good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +QUIT +220 bye +End of script +Listening on port 1225 ... +Connection request from [127.0.0.1] +220 Hi there +EHLO the.local.host.name +250-yeah mate +250 LIMITS MAILMAX=10 RCPTDOMAINMAX=100 +MAIL FROM: +250 mail cmd good +RCPT TO: +250 rcpt cmd 1 good +RCPT TO: +250 rcpt cmd 2 good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message received +MAIL FROM: +250 second mail cmd good +RCPT TO: +250 rcpt cmd 1 good +RCPT TO: +250 rcpt cmd 2 good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 second message received +MAIL FROM: +250 third mail cmd good +RCPT TO: +250 rcpt cmd 1 good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 third message received +QUIT +220 bye +End of script diff --git a/test/stdout/4714 b/test/stdout/4714 new file mode 100644 index 000000000..f7d8e221e --- /dev/null +++ b/test/stdout/4714 @@ -0,0 +1,117 @@ + +******** SERVER ******** +Listening on port 1225 ... +Connection request from [127.0.0.1] +220 Hi there +EHLO the.local.host.name +250-yeah mate +250 LIMITS MAILMAX=5 RCPTMAX=1 +MAIL FROM: +250 mail cmd 1 good +RCPT TO: +250 rcpt cmd good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Subject: message 1 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message 1 received +MAIL FROM: +250 mail cmd 2 good +RCPT TO: +250 rcpt cmd good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Subject: message 1 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message 2 received +MAIL FROM: +250 mail cmd 3 good +RCPT TO: +250 rcpt cmd good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Subject: message 3 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message 3 received +MAIL FROM: +250 mail cmd 4 good +RCPT TO: +250 rcpt cmd good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Subject: message 3 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message 4 received +MAIL FROM: +250 mail cmd 5 good +RCPT TO: +250 rcpt cmd good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Subject: message 2 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message 5 received +QUIT +221 bye +Expected EOF read from client +Listening on port 1225 ... +Connection request from [127.0.0.1] +220 Hi there +EHLO the.local.host.name +250-yeah mate +250 +MAIL FROM: +250 mail cmd 1 good +RCPT TO: +250 rcpt cmd good +DATA +352 go ahead +Received: from CALLER by the.local.host.name with local (Exim x.yz) + (envelope-from ) + id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000 +Subject: message 2 +Message-Id: +From: CALLER_NAME +Date: Tue, 2 Mar 1999 09:44:33 +0000 + +. +250 message 6 received +QUIT +221 bye +Expected EOF read from client +End of script -- 2.30.2