From 57cc27852af9019c0c423bcfde0165e698a0ce54 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 21 Mar 2017 16:16:38 +0000 Subject: [PATCH] Callouts: a "hold" option for receipient-verify, which keeps the connection open both for further recipients and for eventual delivery. --- doc/doc-docbook/spec.xfpt | 15 ++ doc/doc-txt/NewStuff | 3 + src/src/acl.c | 38 +-- src/src/daemon.c | 15 +- src/src/deliver.c | 479 +++++++++++++++++++-------------- src/src/exim.c | 74 ++--- src/src/functions.h | 11 +- src/src/globals.c | 2 + src/src/globals.h | 6 + src/src/macros.h | 3 +- src/src/receive.c | 72 ++--- src/src/smtp_in.c | 8 +- src/src/tls-openssl.c | 1 + src/src/transport.c | 125 +++++---- src/src/transports/smtp.c | 128 +++++---- src/src/verify.c | 160 +++++++---- test/confs/0580 | 46 ++++ test/confs/0581 | 1 + test/confs/0582 | 1 + test/confs/2035 | 84 ++++++ test/confs/2036 | 1 + test/confs/2037 | 1 + test/confs/2135 | 85 ++++++ test/confs/2136 | 1 + test/confs/2137 | 1 + test/log/0580 | 15 ++ test/log/0581 | 23 ++ test/log/0582 | 3 + test/log/2035 | 11 + test/log/2036 | 20 ++ test/log/2037 | 10 + test/log/2135 | 11 + test/log/2136 | 20 ++ test/log/2137 | 10 + test/rejectlog/0582 | 1 + test/rejectlog/2037 | 21 ++ test/rejectlog/2137 | 20 ++ test/scripts/0000-Basic/0580 | 156 +++++++++++ test/scripts/0000-Basic/0581 | 264 ++++++++++++++++++ test/scripts/0000-Basic/0582 | 56 ++++ test/scripts/2000-GnuTLS/2035 | 26 ++ test/scripts/2000-GnuTLS/2036 | 70 +++++ test/scripts/2000-GnuTLS/2037 | 31 +++ test/scripts/2100-OpenSSL/2135 | 25 ++ test/scripts/2100-OpenSSL/2136 | 71 +++++ test/scripts/2100-OpenSSL/2137 | 30 +++ test/stderr/0021 | 1 + test/stderr/0275 | 1 + test/stderr/0278 | 1 + test/stderr/0361 | 1 + test/stderr/0386 | 2 + test/stderr/0388 | 1 + test/stderr/0402 | 1 + test/stderr/0403 | 1 + test/stderr/0404 | 2 + test/stderr/0408 | 1 + test/stderr/0487 | 1 + test/stderr/2600 | 1 + test/stderr/5004 | 1 + test/stderr/5005 | 4 + test/stderr/5006 | 1 + 61 files changed, 1823 insertions(+), 452 deletions(-) create mode 100644 test/confs/0580 create mode 120000 test/confs/0581 create mode 120000 test/confs/0582 create mode 100644 test/confs/2035 create mode 120000 test/confs/2036 create mode 120000 test/confs/2037 create mode 100644 test/confs/2135 create mode 120000 test/confs/2136 create mode 120000 test/confs/2137 create mode 100644 test/log/0580 create mode 100644 test/log/0581 create mode 100644 test/log/0582 create mode 100644 test/log/2035 create mode 100644 test/log/2036 create mode 100644 test/log/2037 create mode 100644 test/log/2135 create mode 100644 test/log/2136 create mode 100644 test/log/2137 create mode 100644 test/rejectlog/0582 create mode 100644 test/rejectlog/2037 create mode 100644 test/rejectlog/2137 create mode 100644 test/scripts/0000-Basic/0580 create mode 100644 test/scripts/0000-Basic/0581 create mode 100644 test/scripts/0000-Basic/0582 create mode 100644 test/scripts/2000-GnuTLS/2035 create mode 100644 test/scripts/2000-GnuTLS/2036 create mode 100644 test/scripts/2000-GnuTLS/2037 create mode 100644 test/scripts/2100-OpenSSL/2135 create mode 100644 test/scripts/2100-OpenSSL/2136 create mode 100644 test/scripts/2100-OpenSSL/2137 diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index c62c1eecf..925b96324 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -30908,6 +30908,21 @@ command when performing the callout, instead of an empty address. There is no need to use this option unless you know that the called hosts make use of the sender when checking recipients. If used indiscriminately, it reduces the usefulness of callout caching. + +.vitem &*hold*& +This option applies to recipient callouts only. For example: +.code +require verify = recipient/callout=use_sender,hold +.endd +It causes the connection to be helod open and used for any further recipients +and for eventual delivery (should that be done quickly). +Doing this saves on TCP and SMTP startup costs, and TLS costs also +when that is used for the connections. +The advantage is only gained if there are no callout cache hits +(which could be enforced by the no_cache option), +if the use_sender option is used, +if neither the random nor the use_postmaster option is used, +and if no other callouts intervene. .endlist If you use any of the parameters that set a non-empty sender for the MAIL diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 872371fcb..c0d07b446 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -23,6 +23,9 @@ Version 4.90 4. A malware connection type for the FPSCAND protocol. + 5. An option for recipient verify callouts to hold the connection open for + further recipients and for delivery. + Version 4.89 ------------ diff --git a/src/src/acl.c b/src/src/acl.c index efab1d31e..7aa8c78ad 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1500,7 +1500,7 @@ static verify_type_t verify_type_list[] = { enum { CALLOUT_DEFER_OK, CALLOUT_NOCACHE, CALLOUT_RANDOM, CALLOUT_USE_SENDER, CALLOUT_USE_POSTMASTER, CALLOUT_POSTMASTER, CALLOUT_FULLPOSTMASTER, CALLOUT_MAILFROM, CALLOUT_POSTMASTER_MAILFROM, CALLOUT_MAXWAIT, CALLOUT_CONNECT, - CALLOUT_TIME + CALLOUT_HOLD, CALLOUT_TIME /* TIME must be last */ }; typedef struct { uschar * name; @@ -1521,6 +1521,7 @@ static callout_opt_t callout_opt_list[] = { { US"mailfrom", CALLOUT_MAILFROM, 0, TRUE, FALSE }, { US"maxwait", CALLOUT_MAXWAIT, 0, TRUE, TRUE }, { US"connect", CALLOUT_CONNECT, 0, TRUE, TRUE }, + { US"hold", CALLOUT_HOLD, vopt_callout_hold, FALSE, FALSE }, { NULL, CALLOUT_TIME, 0, FALSE, TRUE } }; @@ -1744,8 +1745,7 @@ while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)) uschar buffer[256]; while (isspace(*sublist)) sublist++; - while ((opt = string_nextinlist(&sublist, &optsep, buffer, sizeof(buffer))) - != NULL) + while ((opt = string_nextinlist(&sublist, &optsep, buffer, sizeof(buffer)))) { callout_opt_t * op; double period = 1.0F; @@ -1767,15 +1767,11 @@ while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)) } while (isspace(*opt)) opt++; } - if (op->timeval) + if (op->timeval && (period = readconf_readtime(opt, 0, FALSE)) < 0) { - period = readconf_readtime(opt, 0, FALSE); - if (period < 0) - { - *log_msgptr = string_sprintf("bad time value in ACL condition " - "\"verify %s\"", arg); - return ERROR; - } + *log_msgptr = string_sprintf("bad time value in ACL condition " + "\"verify %s\"", arg); + return ERROR; } switch(op->value) @@ -3069,7 +3065,7 @@ for (; cb != NULL; cb = cb->next) break; case CONTROL_FAKEREJECT: - cancel_cutthrough_connection("fakereject"); + cancel_cutthrough_connection(TRUE, US"fakereject"); case CONTROL_FAKEDEFER: fake_response = (control_type == CONTROL_FAKEDEFER) ? DEFER : FAIL; if (*p == '/') @@ -3100,12 +3096,12 @@ for (; cb != NULL; cb = cb->next) *log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg); return ERROR; } - cancel_cutthrough_connection("item frozen"); + cancel_cutthrough_connection(TRUE, US"item frozen"); break; case CONTROL_QUEUE_ONLY: queue_only_policy = TRUE; - cancel_cutthrough_connection("queueing forced"); + cancel_cutthrough_connection(TRUE, US"queueing forced"); break; case CONTROL_SUBMISSION: @@ -4334,8 +4330,9 @@ switch (where) #ifndef DISABLE_PRDR case ACL_WHERE_PRDR: #endif + if (host_checking_callout) /* -bhc mode */ - cancel_cutthrough_connection("host-checking mode"); + cancel_cutthrough_connection(TRUE, US"host-checking mode"); else if ( rc == OK && cutthrough.delivery @@ -4362,13 +4359,20 @@ switch (where) if (rc == OK) cutthrough_predata(); else - cancel_cutthrough_connection("predata acl not ok"); + cancel_cutthrough_connection(TRUE, US"predata acl not ok"); break; case ACL_WHERE_QUIT: case ACL_WHERE_NOTQUIT: - cancel_cutthrough_connection("quit or notquit"); + /* Drop cutthrough conns, and drop heldopen verify conns if + the previous was not DATA */ + { + uschar prev = smtp_connection_had[smtp_ch_index-2]; + BOOL dropverify = !(prev == SCH_DATA || prev == SCH_BDAT); + + cancel_cutthrough_connection(dropverify, US"quit or conndrop"); break; + } default: break; diff --git a/src/src/daemon.c b/src/src/daemon.c index ebd06b523..187378684 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -510,6 +510,7 @@ if (pid == 0) search_tidyup(); /* Close cached databases */ if (!ok) /* Connection was dropped */ { + cancel_cutthrough_connection(TRUE, US"receive dropped"); mac_smtp_fflush(); smtp_log_no_mail(); /* Log no mail if configured */ _exit(EXIT_SUCCESS); @@ -528,6 +529,7 @@ if (pid == 0) if (fcntl(fd, F_SETFL, O_NONBLOCK) == 0) for(i = 16; read(fd, buf, sizeof(buf)) > 0 && i > 0; ) i--; } + cancel_cutthrough_connection(TRUE, US"message setup dropped"); search_tidyup(); smtp_log_no_mail(); /* Log no mail if configured */ @@ -653,9 +655,9 @@ if (pid == 0) /* Don't ever molest the parent's SSL connection, but do clean up the data structures if necessary. */ - #ifdef SUPPORT_TLS +#ifdef SUPPORT_TLS tls_close(TRUE, FALSE); - #endif +#endif /* Reset SIGHUP and SIGCHLD in the child in both cases. */ @@ -665,25 +667,28 @@ if (pid == 0) if (geteuid() != root_uid && !deliver_drop_privilege) { signal(SIGALRM, SIG_DFL); - (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, FALSE, - 2, US"-Mc", message_id); + delivery_re_exec(CEE_EXEC_PANIC); /* Control does not return here. */ } /* No need to re-exec; SIGALRM remains set to the default handler */ - (void)deliver_message(message_id, FALSE, FALSE); + (void) deliver_message(message_id, FALSE, FALSE); search_tidyup(); _exit(EXIT_SUCCESS); } if (dpid > 0) { + release_cutthrough_connection(US"passed for delivery"); DEBUG(D_any) debug_printf("forked delivery process %d\n", (int)dpid); } else + { + cancel_cutthrough_connection(TRUE, US"delivery fork failed"); log_write(0, LOG_MAIN|LOG_PANIC, "daemon: delivery process fork " "failed: %s", strerror(errno)); + } } } } diff --git a/src/src/deliver.c b/src/src/deliver.c index ccc32667e..351a02b0a 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -3366,15 +3366,15 @@ while (!done) up by checking the IP address. */ case 'H': - for (h = addrlist->host_list; h; h = h->next) - { - if (!h->address || Ustrcmp(h->address, ptr+2) != 0) continue; - h->status = ptr[0]; - h->why = ptr[1]; - } - ptr += 2; - while (*ptr++); - break; + for (h = addrlist->host_list; h; h = h->next) + { + if (!h->address || Ustrcmp(h->address, ptr+2) != 0) continue; + h->status = ptr[0]; + h->why = ptr[1]; + } + ptr += 2; + while (*ptr++); + break; /* Retry items are sent in a preceding R item for each address. This is kept separate to keep each message short enough to guarantee it won't @@ -3388,62 +3388,61 @@ while (!done) that a "delete" item is dropped in favour of an "add" item. */ case 'R': - if (!addr) goto ADDR_MISMATCH; + if (!addr) goto ADDR_MISMATCH; - DEBUG(D_deliver|D_retry) - debug_printf("reading retry information for %s from subprocess\n", - ptr+1); + DEBUG(D_deliver|D_retry) + debug_printf("reading retry information for %s from subprocess\n", + ptr+1); - /* Cut out any "delete" items on the list. */ + /* Cut out any "delete" items on the list. */ - for (rp = &addr->retries; (r = *rp); rp = &r->next) - if (Ustrcmp(r->key, ptr+1) == 0) /* Found item with same key */ - { - if ((r->flags & rf_delete) == 0) break; /* It was not "delete" */ - *rp = r->next; /* Excise a delete item */ - DEBUG(D_deliver|D_retry) - debug_printf(" existing delete item dropped\n"); - } + for (rp = &addr->retries; (r = *rp); rp = &r->next) + if (Ustrcmp(r->key, ptr+1) == 0) /* Found item with same key */ + { + if (!(r->flags & rf_delete)) break; /* It was not "delete" */ + *rp = r->next; /* Excise a delete item */ + DEBUG(D_deliver|D_retry) + debug_printf(" existing delete item dropped\n"); + } - /* We want to add a delete item only if there is no non-delete item; - however we still have to step ptr through the data. */ + /* We want to add a delete item only if there is no non-delete item; + however we still have to step ptr through the data. */ - if (!r || !(*ptr & rf_delete)) - { - r = store_get(sizeof(retry_item)); - r->next = addr->retries; - addr->retries = r; - r->flags = *ptr++; - r->key = string_copy(ptr); - while (*ptr++); - memcpy(&(r->basic_errno), ptr, sizeof(r->basic_errno)); - ptr += sizeof(r->basic_errno); - memcpy(&(r->more_errno), ptr, sizeof(r->more_errno)); - ptr += sizeof(r->more_errno); - r->message = (*ptr)? string_copy(ptr) : NULL; - DEBUG(D_deliver|D_retry) - debug_printf(" added %s item\n", - ((r->flags & rf_delete) == 0)? "retry" : "delete"); - } + if (!r || !(*ptr & rf_delete)) + { + r = store_get(sizeof(retry_item)); + r->next = addr->retries; + addr->retries = r; + r->flags = *ptr++; + r->key = string_copy(ptr); + while (*ptr++); + memcpy(&(r->basic_errno), ptr, sizeof(r->basic_errno)); + ptr += sizeof(r->basic_errno); + memcpy(&(r->more_errno), ptr, sizeof(r->more_errno)); + ptr += sizeof(r->more_errno); + r->message = *ptr ? string_copy(ptr) : NULL; + DEBUG(D_deliver|D_retry) debug_printf(" added %s item\n", + r->flags & rf_delete ? "delete" : "retry"); + } - else - { - DEBUG(D_deliver|D_retry) - debug_printf(" delete item not added: non-delete item exists\n"); - ptr++; - while(*ptr++); - ptr += sizeof(r->basic_errno) + sizeof(r->more_errno); - } + else + { + DEBUG(D_deliver|D_retry) + debug_printf(" delete item not added: non-delete item exists\n"); + ptr++; + while(*ptr++); + ptr += sizeof(r->basic_errno) + sizeof(r->more_errno); + } - while(*ptr++); - break; + while(*ptr++); + break; /* Put the amount of data written into the parlist block */ case 'S': - memcpy(&(p->transport_count), ptr, sizeof(transport_count)); - ptr += sizeof(transport_count); - break; + memcpy(&(p->transport_count), ptr, sizeof(transport_count)); + ptr += sizeof(transport_count); + break; /* Address items are in the order of items on the address chain. We remember the current address value in case this function is called @@ -3454,162 +3453,157 @@ while (!done) #ifdef SUPPORT_TLS case 'X': - if (!addr) goto ADDR_MISMATCH; /* Below, in 'A' handler */ - switch (subid) - { - case '1': - addr->cipher = NULL; - addr->peerdn = NULL; - - if (*ptr) - addr->cipher = string_copy(ptr); - while (*ptr++); - if (*ptr) - addr->peerdn = string_copy(ptr); - break; - - case '2': - if (*ptr) - (void) tls_import_cert(ptr, &addr->peercert); - else - addr->peercert = NULL; - break; + if (!addr) goto ADDR_MISMATCH; /* Below, in 'A' handler */ + switch (subid) + { + case '1': + addr->cipher = NULL; + addr->peerdn = NULL; - case '3': - if (*ptr) - (void) tls_import_cert(ptr, &addr->ourcert); - else - addr->ourcert = NULL; - break; + if (*ptr) + addr->cipher = string_copy(ptr); + while (*ptr++); + if (*ptr) + addr->peerdn = string_copy(ptr); + break; + + case '2': + if (*ptr) + (void) tls_import_cert(ptr, &addr->peercert); + else + addr->peercert = NULL; + break; + + case '3': + if (*ptr) + (void) tls_import_cert(ptr, &addr->ourcert); + else + addr->ourcert = NULL; + break; # ifndef DISABLE_OCSP - case '4': - addr->ocsp = *ptr ? *ptr - '0' : OCSP_NOT_REQ; - break; + case '4': + addr->ocsp = *ptr ? *ptr - '0' : OCSP_NOT_REQ; + break; # endif - } - while (*ptr++); - break; + } + while (*ptr++); + break; #endif /*SUPPORT_TLS*/ case 'C': /* client authenticator information */ - switch (subid) - { - case '1': - addr->authenticator = (*ptr)? string_copy(ptr) : NULL; - break; - case '2': - addr->auth_id = (*ptr)? string_copy(ptr) : NULL; - break; - case '3': - addr->auth_sndr = (*ptr)? string_copy(ptr) : NULL; - break; - } - while (*ptr++); - break; + switch (subid) + { + case '1': addr->authenticator = *ptr ? string_copy(ptr) : NULL; break; + case '2': addr->auth_id = *ptr ? string_copy(ptr) : NULL; break; + case '3': addr->auth_sndr = *ptr ? string_copy(ptr) : NULL; break; + } + while (*ptr++); + break; #ifndef DISABLE_PRDR case 'P': - addr->flags |= af_prdr_used; - break; + addr->flags |= af_prdr_used; + break; #endif case 'K': - addr->flags |= af_chunking_used; - break; + addr->flags |= af_chunking_used; + break; case 'D': - if (!addr) goto ADDR_MISMATCH; - memcpy(&(addr->dsn_aware), ptr, sizeof(addr->dsn_aware)); - ptr += sizeof(addr->dsn_aware); - DEBUG(D_deliver) debug_printf("DSN read: addr->dsn_aware = %d\n", addr->dsn_aware); - break; - - case 'A': - if (!addr) - { - ADDR_MISMATCH: - msg = string_sprintf("address count mismatch for data read from pipe " - "for transport process %d for transport %s", pid, - addrlist->transport->driver_name); - done = TRUE; + if (!addr) goto ADDR_MISMATCH; + memcpy(&(addr->dsn_aware), ptr, sizeof(addr->dsn_aware)); + ptr += sizeof(addr->dsn_aware); + DEBUG(D_deliver) debug_printf("DSN read: addr->dsn_aware = %d\n", addr->dsn_aware); break; - } - switch (subid) - { -#ifdef SUPPORT_SOCKS - case '2': /* proxy information; must arrive before A0 and applies to that addr XXX oops*/ - proxy_session = TRUE; /*XXX should this be cleared somewhere? */ - if (*ptr == 0) - ptr++; - else - { - proxy_local_address = string_copy(ptr); - while(*ptr++); - memcpy(&proxy_local_port, ptr, sizeof(proxy_local_port)); - ptr += sizeof(proxy_local_port); - } + case 'A': + if (!addr) + { + ADDR_MISMATCH: + msg = string_sprintf("address count mismatch for data read from pipe " + "for transport process %d for transport %s", pid, + addrlist->transport->driver_name); + done = TRUE; break; -#endif + } -#ifdef EXPERIMENTAL_DSN_INFO - case '1': /* must arrive before A0, and applies to that addr */ - /* Two strings: smtp_greeting and helo_response */ - addr->smtp_greeting = string_copy(ptr); - while(*ptr++); - addr->helo_response = string_copy(ptr); - while(*ptr++); - break; -#endif + switch (subid) + { + #ifdef SUPPORT_SOCKS + case '2': /* proxy information; must arrive before A0 and applies to that addr XXX oops*/ + proxy_session = TRUE; /*XXX should this be cleared somewhere? */ + if (*ptr == 0) + ptr++; + else + { + proxy_local_address = string_copy(ptr); + while(*ptr++); + memcpy(&proxy_local_port, ptr, sizeof(proxy_local_port)); + ptr += sizeof(proxy_local_port); + } + break; + #endif - case '0': - addr->transport_return = *ptr++; - addr->special_action = *ptr++; - memcpy(&(addr->basic_errno), ptr, sizeof(addr->basic_errno)); - ptr += sizeof(addr->basic_errno); - memcpy(&(addr->more_errno), ptr, sizeof(addr->more_errno)); - ptr += sizeof(addr->more_errno); - memcpy(&(addr->flags), ptr, sizeof(addr->flags)); - ptr += sizeof(addr->flags); - addr->message = (*ptr)? string_copy(ptr) : NULL; - while(*ptr++); - addr->user_message = (*ptr)? string_copy(ptr) : NULL; - while(*ptr++); + #ifdef EXPERIMENTAL_DSN_INFO + case '1': /* must arrive before A0, and applies to that addr */ + /* Two strings: smtp_greeting and helo_response */ + addr->smtp_greeting = string_copy(ptr); + while(*ptr++); + addr->helo_response = string_copy(ptr); + while(*ptr++); + break; + #endif + + case '0': + DEBUG(D_deliver) debug_printf("A0 %s tret %d\n", addr->address, *ptr); + addr->transport_return = *ptr++; + addr->special_action = *ptr++; + memcpy(&(addr->basic_errno), ptr, sizeof(addr->basic_errno)); + ptr += sizeof(addr->basic_errno); + memcpy(&(addr->more_errno), ptr, sizeof(addr->more_errno)); + ptr += sizeof(addr->more_errno); + memcpy(&(addr->flags), ptr, sizeof(addr->flags)); + ptr += sizeof(addr->flags); + addr->message = *ptr ? string_copy(ptr) : NULL; + while(*ptr++); + addr->user_message = *ptr ? string_copy(ptr) : NULL; + while(*ptr++); - /* Always two strings for host information, followed by the port number and DNSSEC mark */ + /* Always two strings for host information, followed by the port number and DNSSEC mark */ - if (*ptr != 0) - { - h = store_get(sizeof(host_item)); - h->name = string_copy(ptr); - while (*ptr++); - h->address = string_copy(ptr); - while(*ptr++); - memcpy(&(h->port), ptr, sizeof(h->port)); - ptr += sizeof(h->port); - h->dnssec = *ptr == '2' ? DS_YES - : *ptr == '1' ? DS_NO - : DS_UNK; - ptr++; - addr->host_used = h; - } - else ptr++; + if (*ptr) + { + h = store_get(sizeof(host_item)); + h->name = string_copy(ptr); + while (*ptr++); + h->address = string_copy(ptr); + while(*ptr++); + memcpy(&h->port, ptr, sizeof(h->port)); + ptr += sizeof(h->port); + h->dnssec = *ptr == '2' ? DS_YES + : *ptr == '1' ? DS_NO + : DS_UNK; + ptr++; + addr->host_used = h; + } + else ptr++; - /* Finished with this address */ + /* Finished with this address */ - addr = addr->next; - break; - } - break; + addr = addr->next; + break; + } + break; /* Local interface address/port */ case 'I': - if (*ptr) sending_ip_address = string_copy(ptr); - while (*ptr++) ; - if (*ptr) sending_port = atoi(CS ptr); - while (*ptr++) ; - break; + if (*ptr) sending_ip_address = string_copy(ptr); + while (*ptr++) ; + if (*ptr) sending_port = atoi(CS ptr); + while (*ptr++) ; + break; /* Z marks the logical end of the data. It is followed by '0' if continue_transport was NULL at the end of transporting, otherwise '1'. @@ -3618,23 +3612,23 @@ while (!done) most normal messages it will remain NULL all the time. */ case 'Z': - if (*ptr == '0') - { - continue_transport = NULL; - continue_hostname = NULL; - } - done = TRUE; - DEBUG(D_deliver) debug_printf("Z0%c item read\n", *ptr); - break; + if (*ptr == '0') + { + continue_transport = NULL; + continue_hostname = NULL; + } + done = TRUE; + DEBUG(D_deliver) debug_printf("Z0%c item read\n", *ptr); + break; /* Anything else is a disaster. */ default: - msg = string_sprintf("malformed data (%d) read from pipe for transport " - "process %d for transport %s", ptr[-1], pid, - addr->transport->driver_name); - done = TRUE; - break; + msg = string_sprintf("malformed data (%d) read from pipe for transport " + "process %d for transport %s", ptr[-1], pid, + addr->transport->driver_name); + done = TRUE; + break; } } @@ -4434,6 +4428,23 @@ for (delivery_count = 0; addr_remote; delivery_count++) if (tp->setup) (void)((tp->setup)(addr->transport, addr, NULL, uid, gid, NULL)); + /* If we have a connection still open from a verify stage (lazy-close) + treat it as if it is a continued connection (apart from the counter used + for the log line mark). */ + + if (cutthrough.fd >= 0 && cutthrough.callout_hold_only) + { + DEBUG(D_deliver) + debug_printf("lazy-callout-close: have conn still open from verification\n"); + continue_transport = cutthrough.transport; + continue_hostname = string_copy(cutthrough.host.name); + continue_host_address = string_copy(cutthrough.host.address); + continue_sequence = 1; + sending_ip_address = cutthrough.snd_ip; + sending_port = cutthrough.snd_port; + smtp_peer_options = cutthrough.peer_options; + } + /* If this is a run to continue delivery down an already-established channel, check that this set of addresses matches the transport and the channel. If it does not, defer the addresses. If a host list exists, @@ -4775,7 +4786,6 @@ for (delivery_count = 0; addr_remote; delivery_count++) memcpy(big_buffer, &addr->dsn_aware, sizeof(addr->dsn_aware)); rmt_dlv_checked_write(fd, 'D', '0', big_buffer, sizeof(addr->dsn_aware)); - DEBUG(D_deliver) debug_printf("DSN write: addr->dsn_aware = %d\n", addr->dsn_aware); /* Retry information: for most success cases this will be null. */ @@ -4890,6 +4900,19 @@ for (delivery_count = 0; addr_remote; delivery_count++) (void)close(pfd[pipe_write]); + /* If we have a connection still open from a verify stage (lazy-close) + release its TLS library context (if any) as responsibility was passed to + the delivery child process. */ + + if (cutthrough.fd >= 0 && cutthrough.callout_hold_only) + { +#ifdef SUPPORT_TLS + tls_close(FALSE, FALSE); +#endif + (void) close(cutthrough.fd); + release_cutthrough_connection(US"passed to transport proc"); + } + /* Fork failed; defer with error message */ if (pid < 0) @@ -7040,6 +7063,7 @@ phase, to minimize cases of half-done things. */ DEBUG(D_deliver) debug_printf(">>>>>>>>>>>>>>>> deliveries are done >>>>>>>>>>>>>>>>\n"); +cancel_cutthrough_connection(TRUE, "deliveries are done"); /* Root privilege is no longer needed */ @@ -8416,6 +8440,67 @@ deliver_datafile = -1; return new_sender_address; } + + +void +delivery_re_exec(int exec_type) +{ +uschar * s; + +if (cutthrough.fd >= 0 && cutthrough.callout_hold_only) + { + int pfd[2], channel_fd = cutthrough.fd, pid; + + smtp_peer_options = cutthrough.peer_options; + continue_sequence = 0; + +#ifdef SUPPORT_TLS + if (cutthrough.is_tls) + { + smtp_peer_options |= PEER_OFFERED_TLS; + sending_ip_address = cutthrough.snd_ip; + sending_port = cutthrough.snd_port; + + s = US"socketpair"; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) != 0) + goto fail; + + s = US"fork"; + if ((pid = fork()) < 0) + goto fail; + + else if (pid == 0) /* child */ + { + smtp_proxy_tls(big_buffer, big_buffer_size, pfd[0], 5*60); + exim_exit(0); + } + + (void) close(channel_fd); /* release the client socket */ + channel_fd = pfd[1]; + } +#endif + + transport_do_pass_socket(cutthrough.transport, cutthrough.host.name, + cutthrough.host.address, message_id, channel_fd); + } +else + { + cancel_cutthrough_connection(TRUE, "non-continued delivery"); + (void) child_exec_exim(exec_type, FALSE, NULL, FALSE, 2, US"-Mc", message_id); + } +/* Control does not return here. */ + +fail: + log_write(0, + LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE), + "delivery re-exec failed: %s", strerror(errno)); + + /* Get here if exec_type == CEE_EXEC_EXIT. + Note: this must be _exit(), not exit(). */ + + _exit(EX_EXECFAILED); +} + /* vi: aw ai sw=2 */ /* End of deliver.c */ diff --git a/src/src/exim.c b/src/src/exim.c index 383382072..3dfe5db94 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -4352,11 +4352,8 @@ if (!unprivileged && /* originally had root AND */ (msg_action_arg < 0 || /* and */ msg_action != MSG_DELIVER) && /* not delivering and */ (!checking || !address_test_mode) /* not address checking */ - ) - )) - { + ) ) ) exim_setugid(exim_uid, exim_gid, TRUE, US"privilege not needed"); - } /* When we are retaining a privileged uid, we still change to the exim gid. */ @@ -4370,7 +4367,6 @@ else there's no security risk. For me, it's { exim -bV } on a just-built binary, no need to complain then. */ if (rv == -1) - { if (!(unprivileged || removed_privilege)) { fprintf(stderr, @@ -4380,7 +4376,6 @@ else else DEBUG(D_any) debug_printf("changing group to %ld failed: %s\n", (long int)exim_gid, strerror(errno)); - } } /* Handle a request to scan a file for malware */ @@ -5329,15 +5324,13 @@ if (smtp_input) else { thismessage_size_limit = expand_string_integer(message_size_limit, TRUE); - if (expand_string_message != NULL) - { + if (expand_string_message) if (thismessage_size_limit == -1) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand " "message_size_limit: %s", expand_string_message); else log_write(0, LOG_MAIN|LOG_PANIC_DIE, "invalid value for " "message_size_limit: %s", expand_string_message); - } } /* Loop for several messages when reading SMTP input. If we fork any child @@ -5434,6 +5427,7 @@ while (more) more = receive_msg(extract_recipients); if (message_id[0] == 0) { + cancel_cutthrough_connection(TRUE, US"receive dropped"); if (more) goto moreloop; smtp_log_no_mail(); /* Log no mail if configured */ exim_exit(EXIT_FAILURE); @@ -5441,6 +5435,7 @@ while (more) } else { + cancel_cutthrough_connection(TRUE, US"message setup dropped"); smtp_log_no_mail(); /* Log no mail if configured */ exim_exit((rc == 0)? EXIT_SUCCESS : EXIT_FAILURE); } @@ -5716,21 +5711,28 @@ while (more) not if queue_only is set (case 0). Case 1 doesn't happen here (too many connections). */ - if (local_queue_only) switch(queue_only_reason) + if (local_queue_only) { - case 2: - log_write(L_delay_delivery, - LOG_MAIN, "no immediate delivery: more than %d messages " - "received in one connection", smtp_accept_queue_per_connection); - break; + cancel_cutthrough_connection(TRUE, US"no delivery; queueing"); + switch(queue_only_reason) + { + case 2: + log_write(L_delay_delivery, + LOG_MAIN, "no immediate delivery: more than %d messages " + "received in one connection", smtp_accept_queue_per_connection); + break; - case 3: - log_write(L_delay_delivery, - LOG_MAIN, "no immediate delivery: load average %.2f", - (double)load_average/1000.0); - break; + case 3: + log_write(L_delay_delivery, + LOG_MAIN, "no immediate delivery: load average %.2f", + (double)load_average/1000.0); + break; + } } + else if (queue_only_policy || deliver_freeze) + cancel_cutthrough_connection(TRUE, US"no delivery; queueing"); + /* Else do the delivery unless the ACL or local_scan() called for queue only or froze the message. Always deliver in a separate process. A fork failure is not a disaster, as the delivery will eventually happen on a subsequent queue @@ -5739,7 +5741,7 @@ while (more) thereby defer the delivery if it tries to use (for example) a cached ldap connection that the parent has called unbind on. */ - else if (!queue_only_policy && !deliver_freeze) + else { pid_t pid; search_tidyup(); @@ -5755,8 +5757,7 @@ while (more) if (geteuid() != root_uid && !deliver_drop_privilege && !unprivileged) { - (void)child_exec_exim(CEE_EXEC_EXIT, FALSE, NULL, FALSE, - 2, US"-Mc", message_id); + delivery_re_exec(CEE_EXEC_EXIT); /* Control does not return here. */ } @@ -5770,22 +5771,27 @@ while (more) if (pid < 0) { + cancel_cutthrough_connection(TRUE, US"delivery fork failed"); log_write(0, LOG_MAIN|LOG_PANIC, "failed to fork automatic delivery " "process: %s", strerror(errno)); } + else + { + release_cutthrough_connection(US"msg passed for delivery"); - /* In the parent, wait if synchronous delivery is required. This will - always be the case in MUA wrapper mode. */ + /* In the parent, wait if synchronous delivery is required. This will + always be the case in MUA wrapper mode. */ - else if (synchronous_delivery) - { - int status; - while (wait(&status) != pid); - if ((status & 0x00ff) != 0) - log_write(0, LOG_MAIN|LOG_PANIC, - "process %d crashed with signal %d while delivering %s", - (int)pid, status & 0x00ff, message_id); - if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE); + if (synchronous_delivery) + { + int status; + while (wait(&status) != pid); + if ((status & 0x00ff) != 0) + log_write(0, LOG_MAIN|LOG_PANIC, + "process %d crashed with signal %d while delivering %s", + (int)pid, status & 0x00ff, message_id); + if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE); + } } } diff --git a/src/src/functions.h b/src/src/functions.h index a7d9c1116..331480188 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -110,18 +110,19 @@ extern void bdat_flush_data(void); extern void bits_clear(unsigned int *, size_t, int *); extern void bits_set(unsigned int *, size_t, int *); -extern void cancel_cutthrough_connection(const char *); +extern void cancel_cutthrough_connection(BOOL, const uschar *); extern int check_host(void *, const uschar *, const uschar **, uschar **); extern uschar **child_exec_exim(int, BOOL, int *, BOOL, int, ...); extern pid_t child_open_uid(const uschar **, const uschar **, int, uid_t *, gid_t *, int *, int *, uschar *, BOOL); extern BOOL cleanup_environment(void); +extern BOOL cutthrough_data_puts(uschar *, int); +extern BOOL cutthrough_data_put_nl(void); extern uschar *cutthrough_finaldot(void); extern BOOL cutthrough_flush_send(void); extern BOOL cutthrough_headers_send(void); extern BOOL cutthrough_predata(void); -extern BOOL cutthrough_puts(uschar *, int); -extern BOOL cutthrough_put_nl(void); +extern void release_cutthrough_connection(const uschar *); extern void daemon_go(void); @@ -149,6 +150,7 @@ extern int deliver_split_address(address_item *); extern void deliver_succeeded(address_item *); extern uschar *deliver_get_sender_address (uschar *id); +extern void delivery_re_exec(int); extern BOOL directory_make(const uschar *, const uschar *, int, BOOL); #ifndef DISABLE_DKIM @@ -405,6 +407,7 @@ extern void smtp_get_cache(void); extern int smtp_handle_acl_fail(int, int, uschar *, uschar *); extern void smtp_log_no_mail(void); extern void smtp_message_code(uschar **, int *, uschar **, uschar **, BOOL); +extern void smtp_proxy_tls(uschar *, size_t, int, int); extern BOOL smtp_read_response(smtp_inblock *, uschar *, int, int, int); extern void smtp_respond(uschar *, int, BOOL, uschar *); extern void smtp_notquit_exit(uschar *, uschar *, uschar *, ...); @@ -472,6 +475,8 @@ extern void tls_modify_variables(tls_support *); extern BOOL transport_check_waiting(const uschar *, const uschar *, int, uschar *, BOOL *, oicf, void*); 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 uschar *transport_rcpt_address(address_item *, BOOL); diff --git a/src/src/globals.c b/src/src/globals.c index 9e417b0d2..8dd3922cc 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -538,8 +538,10 @@ uschar *continue_transport = NULL; uschar *csa_status = NULL; cut_t cutthrough = { + FALSE, /* verify-only: normal delivery */ FALSE, /* delivery: when to attempt */ FALSE, /* on defer: spool locally */ + FALSE, /* not a TLS conn yet */ -1, /* fd: open connection */ 0, /* nrcpt: number of addresses */ }; diff --git a/src/src/globals.h b/src/src/globals.h index 72be706a4..5f9ad3bfe 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -299,11 +299,17 @@ extern uschar *continue_transport; /* Transport for continued delivery */ extern uschar *csa_status; /* Client SMTP Authorization result */ typedef struct { + unsigned callout_hold_only:1; /* Conn is only for verify callout */ unsigned delivery:1; /* When to attempt */ unsigned defer_pass:1; /* Pass 4xx to caller rather than spooling */ + unsigned is_tls:1; /* Conn has TLS active */ int fd; /* Open connection */ int nrcpt; /* Count of addresses */ + uschar * transport; /* Name of transport */ uschar * interface; /* (address of) */ + uschar * snd_ip; /* sending_ip_address */ + int snd_port; /* sending_port */ + unsigned peer_options; /* smtp_peer_options */ host_item host; /* Host used */ address_item addr; /* (Chain of) addresses */ } cut_t; diff --git a/src/src/macros.h b/src/src/macros.h index 004d6dfd7..08f631bbb 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -721,7 +721,8 @@ enum { v_none, v_sender, v_recipient, v_expn }; #define vopt_callout_no_cache 0x0040 /* disable callout cache */ #define vopt_callout_recipsender 0x0080 /* use real sender to verify recip */ #define vopt_callout_recippmaster 0x0100 /* use postmaster to verify recip */ -#define vopt_success_on_redirect 0x0200 +#define vopt_callout_hold 0x0200 /* lazy close connection */ +#define vopt_success_on_redirect 0x0400 /* Values for fields in callout cache records */ diff --git a/src/src/receive.c b/src/src/receive.c index 7980c324f..33c60e08d 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -831,7 +831,7 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF) { message_size++; if (fout != NULL && fputc('\n', fout) == EOF) return END_WERROR; - (void) cutthrough_put_nl(); + (void) cutthrough_data_put_nl(); if (ch != '\r') ch_state = 1; else continue; } break; @@ -850,7 +850,7 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF) if (ch == '.') { uschar c= ch; - (void) cutthrough_puts(&c, 1); + (void) cutthrough_data_puts(&c, 1); } ch_state = 1; break; @@ -860,7 +860,7 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF) message_size++; body_linecount++; if (fout != NULL && fputc('\n', fout) == EOF) return END_WERROR; - (void) cutthrough_put_nl(); + (void) cutthrough_data_put_nl(); if (ch == '\r') { ch_state = 2; @@ -881,11 +881,11 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF) if (message_size > thismessage_size_limit) return END_SIZE; } if(ch == '\n') - (void) cutthrough_put_nl(); + (void) cutthrough_data_put_nl(); else { uschar c = ch; - (void) cutthrough_puts(&c, 1); + (void) cutthrough_data_puts(&c, 1); } } @@ -991,7 +991,7 @@ for(;;) { message_size++; if (fout && fputc('\n', fout) == EOF) return END_WERROR; - (void) cutthrough_put_nl(); + (void) cutthrough_data_put_nl(); if (ch == '\r') continue; /* don't write CR */ ch_state = MID_LINE; } @@ -1008,11 +1008,11 @@ for(;;) if (message_size > thismessage_size_limit) return END_SIZE; } if(ch == '\n') - (void) cutthrough_put_nl(); + (void) cutthrough_data_put_nl(); else { uschar c = ch; - (void) cutthrough_puts(&c, 1); + (void) cutthrough_data_puts(&c, 1); } } /*NOTREACHED*/ @@ -1140,7 +1140,8 @@ switch(where) case ACL_WHERE_DKIM: case ACL_WHERE_MIME: case ACL_WHERE_DATA: - if (cutthrough.fd >= 0 && (acl_removed_headers || acl_added_headers)) + if ( cutthrough.fd >= 0 && cutthrough.delivery + && (acl_removed_headers || acl_added_headers)) { log_write(0, LOG_MAIN|LOG_PANIC, "Header modification in data ACLs" " will not take effect on cutthrough deliveries"); @@ -1148,11 +1149,11 @@ switch(where) } } -if (acl_removed_headers != NULL) +if (acl_removed_headers) { DEBUG(D_receive|D_acl) debug_printf_indent(">>Headers removed by %s ACL:\n", acl_name); - for (h = header_list; h != NULL; h = h->next) if (h->type != htype_old) + for (h = header_list; h; h = h->next) if (h->type != htype_old) { const uschar * list = acl_removed_headers; int sep = ':'; /* This is specified as a colon-separated list */ @@ -1170,10 +1171,10 @@ if (acl_removed_headers != NULL) DEBUG(D_receive|D_acl) debug_printf_indent(">>\n"); } -if (acl_added_headers == NULL) return; +if (!acl_added_headers) return; DEBUG(D_receive|D_acl) debug_printf_indent(">>Headers added by %s ACL:\n", acl_name); -for (h = acl_added_headers; h != NULL; h = next) +for (h = acl_added_headers; h; h = next) { next = h->next; @@ -1653,7 +1654,7 @@ search_tidyup(); cutthrough delivery with the no-spool option. It shouldn't be possible to set up the combination, but just in case kill any ongoing connection. */ if (extract_recip || !smtp_input) - cancel_cutthrough_connection("not smtp input"); + cancel_cutthrough_connection(TRUE, US"not smtp input"); /* Initialize the chain of headers by setting up a place-holder for Received: header. Temporarily mark it as "old", i.e. not to be used. We keep header_last @@ -2988,26 +2989,25 @@ inbound is, but inbound chunking ought to be ok with outbound plain. Could we do onward CHUNKING given inbound CHUNKING? */ if (chunking_state > CHUNKING_OFFERED) - cancel_cutthrough_connection("chunking active"); + cancel_cutthrough_connection(FALSE, US"chunking active"); /* Cutthrough delivery: We have to create the Received header now rather than at the end of reception, so the timestamp behaviour is a change to the normal case. XXX Ensure this gets documented XXX. Having created it, send the headers to the destination. */ -if (cutthrough.fd >= 0) + +if (cutthrough.fd >= 0 && cutthrough.delivery) { if (received_count > received_headers_max) { - cancel_cutthrough_connection("too many headers"); + cancel_cutthrough_connection(TRUE, US"too many headers"); if (smtp_input) receive_swallow_smtp(); /* Swallow incoming SMTP */ log_write(0, LOG_MAIN|LOG_REJECT, "rejected from <%s>%s%s%s%s: " "Too many \"Received\" headers", sender_address, - (sender_fullhost == NULL)? "" : " H=", - (sender_fullhost == NULL)? US"" : sender_fullhost, - (sender_ident == NULL)? "" : " U=", - (sender_ident == NULL)? US"" : sender_ident); + sender_fullhost ? "H=" : "", sender_fullhost ? sender_fullhost : US"", + sender_ident ? "U=" : "", sender_ident ? sender_ident : US""); message_id[0] = 0; /* Indicate no message accepted */ smtp_reply = US"550 Too many \"Received\" headers - suspected mail loop"; goto TIDYUP; /* Skip to end of function */ @@ -3105,7 +3105,7 @@ if (!ferror(data_file) && !(receive_feof)() && message_ended != END_DOT) if (smtp_input) { Uunlink(spool_name); /* Lose data file when closed */ - cancel_cutthrough_connection("sender closed connection"); + cancel_cutthrough_connection(TRUE, US"sender closed connection"); message_id[0] = 0; /* Indicate no message accepted */ smtp_reply = handle_lost_connection(US""); smtp_yield = FALSE; @@ -3118,7 +3118,7 @@ if (!ferror(data_file) && !(receive_feof)() && message_ended != END_DOT) case END_SIZE: Uunlink(spool_name); /* Lose the data file when closed */ - cancel_cutthrough_connection("mail too big"); + cancel_cutthrough_connection(TRUE, US"mail too big"); if (smtp_input) receive_swallow_smtp(); /* Swallow incoming SMTP */ log_write(L_size_reject, LOG_MAIN|LOG_REJECT, "rejected from <%s>%s%s%s%s: " @@ -3151,7 +3151,7 @@ if (!ferror(data_file) && !(receive_feof)() && message_ended != END_DOT) case END_PROTOCOL: Uunlink(spool_name); /* Lose the data file when closed */ - cancel_cutthrough_connection("sender protocol error"); + cancel_cutthrough_connection(TRUE, US"sender protocol error"); smtp_reply = US""; /* Response already sent */ message_id[0] = 0; /* Indicate no message accepted */ goto TIDYUP; /* Skip to end of function */ @@ -3184,7 +3184,7 @@ if (fflush(data_file) == EOF || ferror(data_file) || log_write(0, LOG_MAIN, "Message abandoned: %s", msg); Uunlink(spool_name); /* Lose the data file */ - cancel_cutthrough_connection("error writing spoolfile"); + cancel_cutthrough_connection(TRUE, US"error writing spoolfile"); if (smtp_input) { @@ -3423,7 +3423,7 @@ else DEBUG(D_receive) debug_printf("acl_smtp_dkim: acl_check returned %d on %s, " "skipping remaining items\n", rc, item); - cancel_cutthrough_connection("dkim acl not ok"); + cancel_cutthrough_connection(TRUE, US"dkim acl not ok"); break; } } @@ -3542,14 +3542,14 @@ else { recipients_count = 0; blackholed_by = US"DATA ACL"; - if (log_msg != NULL) + if (log_msg) blackhole_log_msg = string_sprintf(": %s", log_msg); - cancel_cutthrough_connection("data acl discard"); + cancel_cutthrough_connection(TRUE, US"data acl discard"); } else if (rc != OK) { Uunlink(spool_name); - cancel_cutthrough_connection("data acl not ok"); + cancel_cutthrough_connection(TRUE, US"data acl not ok"); #ifdef WITH_CONTENT_SCAN unspool_mbox(); #endif @@ -4148,9 +4148,9 @@ for this message. */ XXX We do not handle queue-only, freezing, or blackholes. */ -if(cutthrough.fd >= 0) +if(cutthrough.fd >= 0 && cutthrough.delivery) { - uschar * msg= cutthrough_finaldot(); /* Ask the target system to accept the message */ + uschar * msg = cutthrough_finaldot(); /* Ask the target system to accept the message */ /* Logging was done in finaldot() */ switch(msg[0]) { @@ -4297,7 +4297,6 @@ if (smtp_input) Uunlink(spool_fname(US"input", message_subdir, message_id, US"-D")); Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H")); Uunlink(spool_fname(US"msglog", message_subdir, message_id, US"")); - message_id[0] = 0; /* Prevent a delivery from starting */ break; case TMP_REJ: @@ -4307,12 +4306,15 @@ if (smtp_input) Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H")); Uunlink(spool_fname(US"msglog", message_subdir, message_id, US"")); } - message_id[0] = 0; /* Prevent a delivery from starting */ default: break; } - cutthrough.delivery = FALSE; - cutthrough.defer_pass = FALSE; + if (cutthrough_done != NOT_TRIED) + { + message_id[0] = 0; /* Prevent a delivery from starting */ + cutthrough.delivery = cutthrough.callout_hold_only = FALSE; + cutthrough.defer_pass = FALSE; + } } /* For batched SMTP, generate an error message on failure, and do diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index f0885b3a1..3c40a5c61 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1887,7 +1887,6 @@ smtp_reset(void *reset_point) recipients_list = NULL; rcpt_count = rcpt_defer_count = rcpt_fail_count = raw_recipients_count = recipients_count = recipients_list_max = 0; -cancel_cutthrough_connection("smtp reset"); message_linecount = 0; message_size = -1; acl_added_headers = NULL; @@ -2018,6 +2017,7 @@ bsmtp_transaction_linecount = receive_linecount; if ((receive_feof)()) return 0; /* Treat EOF as QUIT */ +cancel_cutthrough_connection(TRUE, US"smtp_setup_batch_msg"); smtp_reset(reset_point); /* Reset for start of message */ /* Deal with SMTP commands. This loop is exited by setting done to a POSITIVE @@ -2042,6 +2042,7 @@ while (done <= 0) /* Fall through */ case RSET_CMD: + cancel_cutthrough_connection(TRUE, US"RSET received"); smtp_reset(reset_point); bsmtp_transaction_linecount = receive_linecount; break; @@ -2065,6 +2066,7 @@ while (done <= 0) /* Reset to start of message */ + cancel_cutthrough_connection(TRUE, US"MAIL received"); smtp_reset(reset_point); /* Apply SMTP rewrite */ @@ -4253,6 +4255,7 @@ while (done <= 0) : pnormal) + (tls_in.active >= 0 ? pcrpted : 0) ]; + cancel_cutthrough_connection(TRUE, US"sent EHLO response"); smtp_reset(reset_point); toomany = FALSE; break; /* HELO/EHLO */ @@ -4307,6 +4310,7 @@ while (done <= 0) /* Reset for start of message - even if this is going to fail, we obviously need to throw away any previous data. */ + cancel_cutthrough_connection(TRUE, US"MAIL received"); smtp_reset(reset_point); toomany = FALSE; sender_data = recipient_data = NULL; @@ -5162,6 +5166,7 @@ while (done <= 0) do an implied RSET when STARTTLS is received. */ incomplete_transaction_log(US"STARTTLS"); + cancel_cutthrough_connection(TRUE, US"STARTTLS received"); smtp_reset(reset_point); toomany = FALSE; cmd_list[CMD_LIST_STARTTLS].is_mail_cmd = FALSE; @@ -5298,6 +5303,7 @@ while (done <= 0) case RSET_CMD: smtp_rset_handler(); + cancel_cutthrough_connection(TRUE, US"RSET received"); smtp_reset(reset_point); toomany = FALSE; break; diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 4a41ba192..38a16b222 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -1699,6 +1699,7 @@ uschar *expcerts, *expcrl; if (!expand_check(certs, US"tls_verify_certificates", &expcerts, errstr)) return DEFER; +DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts); if (expcerts && *expcerts) { diff --git a/src/src/transport.c b/src/src/transport.c index e6e327822..1a53690cc 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -1238,7 +1238,6 @@ set up a filtering process, fork another process to call the internal function to write to the filter, and in this process just suck from the filter and write down the given fd. At the end, tidy up the pipes and the processes. -XXX Arguments: as for internal_transport_write_message() above Returns: TRUE on success; FALSE (with errno) for any failure @@ -1934,6 +1933,72 @@ return TRUE; * Deliver waiting message down same socket * *************************************************/ +/* Just the regain-root-privilege exec portion */ +void +transport_do_pass_socket(const uschar *transport_name, const uschar *hostname, + const uschar *hostaddress, uschar *id, int socket_fd) +{ +pid_t pid; +int status; +int i = 20; +const uschar **argv; + +/* Set up the calling arguments; use the standard function for the basics, +but we have a number of extras that may be added. */ + +argv = CUSS child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0); + +if (smtp_authenticated) argv[i++] = US"-MCA"; +if (smtp_peer_options & PEER_OFFERED_CHUNKING) argv[i++] = US"-MCK"; +if (smtp_peer_options & PEER_OFFERED_DSN) argv[i++] = US"-MCD"; +if (smtp_peer_options & PEER_OFFERED_PIPE) argv[i++] = US"-MCP"; +if (smtp_peer_options & PEER_OFFERED_SIZE) argv[i++] = US"-MCS"; +#ifdef SUPPORT_TLS +if (smtp_peer_options & PEER_OFFERED_TLS) + if (tls_out.active >= 0 || continue_proxy_cipher) + { + argv[i++] = US"-MCt"; + argv[i++] = sending_ip_address; + argv[i++] = string_sprintf("%d", sending_port); + argv[i++] = tls_out.active >= 0 ? tls_out.cipher : continue_proxy_cipher; + } + else + argv[i++] = US"-MCT"; +#endif + +if (queue_run_pid != (pid_t)0) + { + argv[i++] = US"-MCQ"; + argv[i++] = string_sprintf("%d", queue_run_pid); + argv[i++] = string_sprintf("%d", queue_run_pipe); + } + +argv[i++] = US"-MC"; +argv[i++] = US transport_name; +argv[i++] = US hostname; +argv[i++] = US hostaddress; +argv[i++] = string_sprintf("%d", continue_sequence + 1); +argv[i++] = id; +argv[i++] = NULL; + +/* Arrange for the channel to be on stdin. */ + +if (socket_fd != 0) + { + (void)dup2(socket_fd, 0); + (void)close(socket_fd); + } + +DEBUG(D_exec) debug_print_argv(argv); +exim_nullstd(); /* Ensure std{out,err} exist */ +execv(CS argv[0], (char *const *)argv); + +DEBUG(D_any) debug_printf("execv failed: %s\n", strerror(errno)); +_exit(errno); /* Note: must be _exit(), NOT exit() */ +} + + + /* Fork a new exim process to deliver the message, and do a re-exec, both to get a clean delivery process, and to regain root privilege in cases where it has been given away. @@ -1959,9 +2024,6 @@ DEBUG(D_transport) debug_printf("transport_pass_socket entered\n"); if ((pid = fork()) == 0) { - int i = 20; - const uschar **argv; - /* Disconnect entirely from the parent process. If we are running in the test harness, wait for a bit to allow the previous process time to finish, write the log, etc., so that the output is always in the same order for @@ -1970,59 +2032,8 @@ if ((pid = fork()) == 0) if ((pid = fork()) != 0) _exit(EXIT_SUCCESS); if (running_in_test_harness) sleep(1); - /* Set up the calling arguments; use the standard function for the basics, - but we have a number of extras that may be added. */ - - argv = CUSS child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0); - - if (smtp_authenticated) argv[i++] = US"-MCA"; - - if (smtp_peer_options & PEER_OFFERED_CHUNKING) argv[i++] = US"-MCK"; - if (smtp_peer_options & PEER_OFFERED_DSN) argv[i++] = US"-MCD"; - if (smtp_peer_options & PEER_OFFERED_PIPE) argv[i++] = US"-MCP"; - if (smtp_peer_options & PEER_OFFERED_SIZE) argv[i++] = US"-MCS"; -#ifdef SUPPORT_TLS - if (smtp_peer_options & PEER_OFFERED_TLS) - if (tls_out.active >= 0 || continue_proxy_cipher) - { - argv[i++] = US"-MCt"; - argv[i++] = sending_ip_address; - argv[i++] = string_sprintf("%d", sending_port); - argv[i++] = tls_out.active >= 0 ? tls_out.cipher : continue_proxy_cipher; - } - else - argv[i++] = US"-MCT"; -#endif - - if (queue_run_pid != (pid_t)0) - { - argv[i++] = US"-MCQ"; - argv[i++] = string_sprintf("%d", queue_run_pid); - argv[i++] = string_sprintf("%d", queue_run_pipe); - } - - argv[i++] = US"-MC"; - argv[i++] = US transport_name; - argv[i++] = US hostname; - argv[i++] = US hostaddress; - argv[i++] = string_sprintf("%d", continue_sequence + 1); - argv[i++] = id; - argv[i++] = NULL; - - /* Arrange for the channel to be on stdin. */ - - if (socket_fd != 0) - { - (void)dup2(socket_fd, 0); - (void)close(socket_fd); - } - - DEBUG(D_exec) debug_print_argv(argv); - exim_nullstd(); /* Ensure std{out,err} exist */ - execv(CS argv[0], (char *const *)argv); - - DEBUG(D_any) debug_printf("execv failed: %s\n", strerror(errno)); - _exit(errno); /* Note: must be _exit(), NOT exit() */ + transport_do_pass_socket(transport_name, hostname, hostaddress, + id, socket_fd); } /* If the process creation succeeded, wait for the first-level child, which diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 34c96dbff..c4626b3e9 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -220,8 +220,10 @@ smtp_transport_options_block smtp_transport_option_defaults = { NULL, /* hosts_verify_avoid_tls */ NULL, /* hosts_avoid_pipelining */ NULL, /* hosts_avoid_esmtp */ +#ifdef SUPPORT_TLS NULL, /* hosts_nopass_tls */ US"*", /* hosts_noproxy_tls */ +#endif 5*60, /* command_timeout */ 5*60, /* connect_timeout; shorter system default overrides */ 5*60, /* data timeout */ @@ -1801,9 +1803,11 @@ goto SEND_QUIT; } } -/* For continuing deliveries down the same channel, the socket is the standard -input, and we don't need to redo EHLO here (but may need to do so for TLS - see -below). Set up the pointer to where subsequent commands will be left, for +/* For continuing deliveries down the same channel, having re-exec'd the socket +is the standard input; for a socket held open from verify it is recorded +in the cutthrough context block. Either way we don't need to redo EHLO here +(but may need to do so for TLS - see below). +Set up the pointer to where subsequent commands will be left, for error messages. Note that smtp_peer_options will have been set from the command line if they were set in the process that passed the connection on. */ @@ -1815,19 +1819,30 @@ separate - we could match up by host ip+port as a bodge. */ else { - sx->inblock.sock = sx->outblock.sock = 0; /* stdin */ + if (cutthrough.fd >= 0 && cutthrough.callout_hold_only) + { + sx->inblock.sock = sx->outblock.sock = cutthrough.fd; + sx->host->port = sx->port = cutthrough.host.port; + } + else + { + sx->inblock.sock = sx->outblock.sock = 0; /* stdin */ + sx->host->port = sx->port; /* Record the port that was used */ + } smtp_command = big_buffer; - sx->host->port = sx->port; /* Record the port that was used */ sx->helo_data = NULL; /* ensure we re-expand ob->helo_data */ - /* For a continued connection with TLS being proxied for us, nothing - more to do. */ + /* For a continued connection with TLS being proxied for us, or a + held-open verify connection with TLS, nothing more to do. */ - if (continue_proxy_cipher) + if ( continue_proxy_cipher + || (cutthrough.fd >= 0 && cutthrough.callout_hold_only && cutthrough.is_tls) + ) { sx->peer_offered = smtp_peer_options; pipelining_active = !!(smtp_peer_options & PEER_OFFERED_PIPE); - HDEBUG(D_transport) debug_printf("continued connection, proxied TLS\n"); + HDEBUG(D_transport) debug_printf("continued connection, %s TLS\n", + continue_proxy_cipher ? "proxied" : "verify conn with"); return OK; } HDEBUG(D_transport) debug_printf("continued connection, no TLS\n"); @@ -2511,19 +2526,20 @@ return 0; * Proxy TLS connection for another transport process * ******************************************************/ /* -Use the smtp-context buffer as a staging area, and select on both the slave -process and the TLS'd fd for data to read (per the coding in ip_recv() and +Use the given buffer as a staging area, and select on both the given fd +and the TLS'd client-fd for data to read (per the coding in ip_recv() and fd_ready() this is legitimate). Do blocking full-size writes, and reads under a timeout. Arguments: - sx smtp context block + buf space to use for buffering + bufsiz size of buffer proxy_fd comms to proxied process timeout per-read timeout, seconds */ -static void -smtp_proxy_tls(smtp_context * sx, int proxy_fd, int timeout) +void +smtp_proxy_tls(uschar * buf, size_t bsize, int proxy_fd, int timeout) { fd_set fds; int max_fd = MAX(proxy_fd, tls_out.active) + 1; @@ -2559,7 +2575,7 @@ for (fd_bits = 3; fd_bits; ) /* handle inbound data */ if (FD_ISSET(tls_out.active, &fds)) - if ((rc = tls_read(FALSE, sx->buffer, sizeof(sx->buffer))) <= 0) + if ((rc = tls_read(FALSE, buf, bsize)) <= 0) { fd_bits &= ~1; FD_CLR(tls_out.active, &fds); @@ -2568,14 +2584,14 @@ for (fd_bits = 3; fd_bits; ) else { for (nbytes = 0; rc - nbytes > 0; nbytes += i) - if ((i = write(proxy_fd, sx->buffer + nbytes, rc - nbytes)) < 0) return; + if ((i = write(proxy_fd, buf + nbytes, rc - nbytes)) < 0) return; } else if (fd_bits & 1) FD_SET(tls_out.active, &fds); /* handle outbound data */ if (FD_ISSET(proxy_fd, &fds)) - if ((rc = read(proxy_fd, sx->buffer, sizeof(sx->buffer))) <= 0) + if ((rc = read(proxy_fd, buf, bsize)) <= 0) { fd_bits &= ~2; FD_CLR(proxy_fd, &fds); @@ -2584,7 +2600,7 @@ for (fd_bits = 3; fd_bits; ) else { for (nbytes = 0; rc - nbytes > 0; nbytes += i) - if ((i = tls_write(FALSE, sx->buffer + nbytes, rc - nbytes)) < 0) return; + if ((i = tls_write(FALSE, buf + nbytes, rc - nbytes)) < 0) return; } else if (fd_bits & 2) FD_SET(proxy_fd, &fds); @@ -2724,33 +2740,52 @@ sx.send_rset = TRUE; sx.completed_addr = FALSE; -/* Initiate a message transfer. */ +/* If we are a continued-connection-after-verify the MAIL and RCPT +commands were already sent; do not re-send but do mark the addrs as +having been accepted up to RCPT stage. A traditional cont-conn +always has a sequence number greater than one. */ -switch(smtp_write_mail_and_rcpt_cmds(&sx, &yield)) +if (continue_hostname && continue_sequence == 1) { - case 0: break; - case -1: case -2: goto RESPONSE_FAILED; - case -3: goto END_OFF; - case -4: goto SEND_QUIT; - default: goto SEND_FAILED; - } + address_item * addr; -/* If we are an MUA wrapper, abort if any RCPTs were rejected, either -permanently or temporarily. We should have flushed and synced after the last -RCPT. */ + sx.peer_offered = smtp_peer_options; + sx.ok = TRUE; + sx.next_addr = NULL; -if (mua_wrapper) + for (addr = addrlist; addr; addr = addr->next) + addr->transport_return = PENDING_OK; + } +else { - address_item *badaddr; - for (badaddr = sx.first_addr; badaddr; badaddr = badaddr->next) - if (badaddr->transport_return != PENDING_OK) - { - /*XXX could we find a better errno than 0 here? */ - set_errno_nohost(addrlist, 0, badaddr->message, FAIL, - testflag(badaddr, af_pass_message)); - sx.ok = FALSE; - break; - } + /* Initiate a message transfer. */ + + switch(smtp_write_mail_and_rcpt_cmds(&sx, &yield)) + { + case 0: break; + case -1: case -2: goto RESPONSE_FAILED; + case -3: goto END_OFF; + case -4: goto SEND_QUIT; + default: goto SEND_FAILED; + } + + /* If we are an MUA wrapper, abort if any RCPTs were rejected, either + permanently or temporarily. We should have flushed and synced after the last + RCPT. */ + + if (mua_wrapper) + { + address_item *badaddr; + for (badaddr = sx.first_addr; badaddr; badaddr = badaddr->next) + if (badaddr->transport_return != PENDING_OK) + { + /*XXX could we find a better errno than 0 here? */ + set_errno_nohost(addrlist, 0, badaddr->message, FAIL, + testflag(badaddr, af_pass_message)); + sx.ok = FALSE; + break; + } + } } /* If ok is TRUE, we know we have got at least one good recipient, and must now @@ -3050,7 +3085,7 @@ else else sprintf(CS sx.buffer, "%.500s\n", addr->unique); - DEBUG(D_deliver) debug_printf("journalling %s\n", sx.buffer); + DEBUG(D_deliver) debug_printf("S:journalling %s\n", 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 " @@ -3376,7 +3411,7 @@ propagate it from the initial 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. */ - +#ifdef SUPPORT_TLS if (tls_out.active >= 0) { int pid = fork(); @@ -3390,10 +3425,11 @@ propagate it from the initial } else if (pid == 0) /* child */ { - smtp_proxy_tls(&sx, pfd[0], sx.ob->command_timeout); + smtp_proxy_tls(sx.buffer, sizeof(sx.buffer), pfd[0], sx.ob->command_timeout); exim_exit(0); } } +#endif } } @@ -3608,8 +3644,10 @@ DEBUG(D_transport) for (host = hostlist; host; host = host->next) debug_printf(" %s:%d\n", host->name, host->port); } - if (continue_hostname) debug_printf("already connected to %s [%s]\n", - continue_hostname, continue_host_address); + if (continue_hostname) + debug_printf("already connected to %s [%s] (on fd %d)\n", + continue_hostname, continue_host_address, + cutthrough.fd >= 0 ? cutthrough.fd : 0); } /* Set the flag requesting that these hosts be added to the waiting diff --git a/src/src/verify.c b/src/src/verify.c index 9ff1807d4..59add8c00 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -39,7 +39,7 @@ static tree_node *dnsbl_cache = NULL; #define MT_NOT 1 #define MT_ALL 2 -static uschar cutthrough_response(char, uschar **, int); +static uschar cutthrough_response(int, char, uschar **, int); @@ -388,7 +388,7 @@ if (addr->transport == cutthrough.addr.transport) deliver_domain = addr->domain; transport_name = addr->transport->name; - host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET:AF_INET6; + host_af = Ustrchr(host->address, ':') ? AF_INET6 : AF_INET; if (!smtp_get_interface(tf->interface, host_af, addr, &interface, US"callout") || @@ -411,7 +411,7 @@ if (addr->transport == cutthrough.addr.transport) smtp_write_command(&ctblock, FALSE, "RCPT TO:<%.1000s>\r\n", transport_rcpt_address(addr, addr->transport->rcpt_include_affixes)) >= 0 && - cutthrough_response('2', &resp, CUTTHROUGH_DATA_TIMEOUT) == '2'; + cutthrough_response(cutthrough.fd, '2', &resp, CUTTHROUGH_DATA_TIMEOUT) == '2'; /* This would go horribly wrong if a callout fail was ignored by ACL. We punt by abandoning cutthrough on a reject, like the @@ -429,7 +429,7 @@ if (addr->transport == cutthrough.addr.transport) } else { - cancel_cutthrough_connection("recipient rejected"); + cancel_cutthrough_connection(TRUE, US"recipient rejected"); if (!resp || errno == ETIMEDOUT) { HDEBUG(D_verify) debug_printf("SMTP timeout\n"); @@ -459,7 +459,7 @@ if (addr->transport == cutthrough.addr.transport) break; /* host_list */ } if (!done) - cancel_cutthrough_connection("incompatible connection"); + cancel_cutthrough_connection(TRUE, US"incompatible connection"); return done; } @@ -490,6 +490,7 @@ Arguments: vopt_callout_random => do the "random" thing vopt_callout_recipsender => use real sender for recipient vopt_callout_recippmaster => use postmaster for recipient + vopt_callout_hold => lazy close connection se_mailfrom MAIL FROM address for sender verify; NULL => "" pm_mailfrom if non-NULL, do the postmaster check with this sender @@ -556,7 +557,10 @@ else if (cached_callout_lookup(addr, address_key, from_address, &options, &pm_mailfrom, &yield, failure_ptr, &new_domain_record, &old_domain_cache_result)) + { + cancel_cutthrough_connection(TRUE, US"cache-hit"); goto END_CALLOUT; + } if (!addr->transport) { @@ -756,9 +760,12 @@ tls_retry_connection: } #endif - /* This would be ok for 1st rcpt of a cutthrough (XXX do we have a count?) , but no way to - handle a subsequent because of the RSET. So refuse to support any. */ - cancel_cutthrough_connection("random-recipient"); + /* This would be ok for 1st rcpt of a cutthrough (the case handled here; + subsequents are done in cutthrough_multi()), but no way to + handle a subsequent because of the RSET vaporising the MAIL FROM. + So refuse to support any. Most cutthrough use will not involve + random_local_part, so no loss. */ + cancel_cutthrough_connection(TRUE, US"random-recipient"); addr->address = string_sprintf("%s@%.1000s", random_local_part, rcpt_domain); @@ -887,7 +894,7 @@ tls_retry_connection: /* Could possibly shift before main verify, just above, and be ok for cutthrough. But no way to handle a subsequent rcpt, so just refuse any */ - cancel_cutthrough_connection("postmaster verify"); + cancel_cutthrough_connection(TRUE, US"postmaster verify"); HDEBUG(D_acl|D_v) debug_printf_indent("Cutthrough cancelled by presence of postmaster verify\n"); done = smtp_write_command(&sx.outblock, FALSE, "RSET\r\n") >= 0 @@ -1003,8 +1010,10 @@ no_conn: /* Cutthrough - on a successful connect and recipient-verify with use-sender and we are 1st rcpt and have no cutthrough conn so far - here is where we want to leave the conn open */ - if ( cutthrough.delivery + here is where we want to leave the conn open. Ditto for a lazy-close + verify. */ + + if ( (cutthrough.delivery || options & vopt_callout_hold) && rcpt_count == 1 && done && yield == OK @@ -1016,14 +1025,29 @@ no_conn: && !sx.lmtp ) { - HDEBUG(D_acl|D_v) debug_printf_indent("holding verify callout open for cutthrough delivery\n"); - - cutthrough.fd = sx.outblock.sock; /* We assume no buffer in use in the outblock */ - cutthrough.nrcpt = 1; - cutthrough.interface = interface; - cutthrough.host = *host; - cutthrough.addr = *addr; /* Save the address_item for later logging */ - cutthrough.addr.next = NULL; + HDEBUG(D_acl|D_v) debug_printf_indent("holding verify callout open for %s\n", + cutthrough.delivery + ? "cutthrough delivery" : "potential further verifies and delivery"); + + cutthrough.callout_hold_only = !cutthrough.delivery; + cutthrough.is_tls = tls_out.active >= 0; + cutthrough.fd = sx.outblock.sock; /* We assume no buffer in use in the outblock */ + cutthrough.nrcpt = 1; + cutthrough.transport = addr->transport->name; + cutthrough.interface = interface; + cutthrough.snd_port = sending_port; + cutthrough.peer_options = smtp_peer_options; + cutthrough.host = *host; + { + int oldpool = store_pool; + store_pool = POOL_PERM; + cutthrough.snd_ip = string_copy(sending_ip_address); + cutthrough.host.name = string_copy(host->name); + cutthrough.host.address = string_copy(host->address); + store_pool = oldpool; + } + cutthrough.addr = *addr; /* Save the address_item for later logging */ + cutthrough.addr.next = NULL; cutthrough.addr.host_used = &cutthrough.host; if (addr->parent) *(cutthrough.addr.parent = store_get(sizeof(address_item))) = @@ -1036,9 +1060,9 @@ no_conn: } else { - /* Ensure no cutthrough on multiple address verifies */ + /* Ensure no cutthrough on multiple verifies that were incompatible */ if (options & vopt_callout_recipsender) - cancel_cutthrough_connection("not usable for cutthrough"); + cancel_cutthrough_connection(TRUE, US"not usable for cutthrough"); if (sx.send_quit) { (void) smtp_write_command(&sx.outblock, FALSE, "QUIT\r\n"); @@ -1184,20 +1208,26 @@ return TRUE; } /* Buffered output of counted data block. Return boolean success */ -BOOL +static BOOL cutthrough_puts(uschar * cp, int n) { if (cutthrough.fd < 0) return TRUE; if (_cutthrough_puts(cp, n)) return TRUE; -cancel_cutthrough_connection("transmit failed"); +cancel_cutthrough_connection(TRUE, US"transmit failed"); return FALSE; } +BOOL +cutthrough_data_puts(uschar * cp, int n) +{ +if (cutthrough.delivery) cutthrough_puts(cp, n); +} + static BOOL _cutthrough_flush_send(void) { -int n= ctblock.ptr-ctblock.buffer; +int n = ctblock.ptr - ctblock.buffer; if(n>0) if(!cutthrough_send(n)) @@ -1211,21 +1241,28 @@ BOOL cutthrough_flush_send(void) { if (_cutthrough_flush_send()) return TRUE; -cancel_cutthrough_connection("transmit failed"); +cancel_cutthrough_connection(TRUE, US"transmit failed"); return FALSE; } -BOOL +static BOOL cutthrough_put_nl(void) { return cutthrough_puts(US"\r\n", 2); } +BOOL +cutthrough_data_put_nl(void) +{ +return cutthrough_data_puts(US"\r\n", 2); +} + + /* Get and check response from cutthrough target */ static uschar -cutthrough_response(char expect, uschar ** copy, int timeout) +cutthrough_response(int fd, char expect, uschar ** copy, int timeout) { smtp_inblock inblock; uschar inbuffer[4096]; @@ -1235,12 +1272,12 @@ inblock.buffer = inbuffer; inblock.buffersize = sizeof(inbuffer); inblock.ptr = inbuffer; inblock.ptrend = inbuffer; -inblock.sock = cutthrough.fd; +inblock.sock = fd; /* this relies on (inblock.sock == tls_out.active) */ if(!smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), expect, timeout)) - cancel_cutthrough_connection("target timeout on read"); + cancel_cutthrough_connection(TRUE, US"target timeout on read"); -if(copy != NULL) +if(copy) { uschar * cp; *copy = cp = string_copy(responsebuffer); @@ -1258,7 +1295,7 @@ return responsebuffer[0]; BOOL cutthrough_predata(void) { -if(cutthrough.fd < 0) +if(cutthrough.fd < 0 || cutthrough.callout_hold_only) return FALSE; HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> DATA\n"); @@ -1266,7 +1303,7 @@ cutthrough_puts(US"DATA\r\n", 6); cutthrough_flush_send(); /* Assume nothing buffered. If it was it gets ignored. */ -return cutthrough_response('3', NULL, CUTTHROUGH_DATA_TIMEOUT) == '3'; +return cutthrough_response(cutthrough.fd, '3', NULL, CUTTHROUGH_DATA_TIMEOUT) == '3'; } @@ -1293,7 +1330,7 @@ cutthrough_headers_send(void) { transport_ctx tctx; -if(cutthrough.fd < 0) +if(cutthrough.fd < 0 || cutthrough.callout_hold_only) return FALSE; /* We share a routine with the mainline transport to handle header add/remove/rewrites, @@ -1318,7 +1355,8 @@ return TRUE; static void close_cutthrough_connection(const char * why) { -if(cutthrough.fd >= 0) +int fd = cutthrough.fd; +if(fd >= 0) { /* We could be sending this after a bunch of data, but that is ok as the only way to cancel the transfer in dataphase is to drop the tcp @@ -1328,26 +1366,36 @@ if(cutthrough.fd >= 0) HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> QUIT\n"); _cutthrough_puts(US"QUIT\r\n", 6); /* avoid recursion */ _cutthrough_flush_send(); + cutthrough.fd = -1; /* avoid recursion via read timeout */ /* Wait a short time for response, and discard it */ - cutthrough_response('2', NULL, 1); + cutthrough_response(fd, '2', NULL, 1); - #ifdef SUPPORT_TLS +#ifdef SUPPORT_TLS tls_close(FALSE, TRUE); - #endif +#endif HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n"); - (void)close(cutthrough.fd); - cutthrough.fd = -1; + (void)close(fd); HDEBUG(D_acl) debug_printf_indent("----------- cutthrough shutdown (%s) ------------\n", why); } ctblock.ptr = ctbuffer; } void -cancel_cutthrough_connection(const char * why) +cancel_cutthrough_connection(BOOL close_noncutthrough_verifies, const uschar * why) +{ +if (cutthrough.delivery || close_noncutthrough_verifies) + close_cutthrough_connection(why); +cutthrough.delivery = cutthrough.callout_hold_only = FALSE; +} + + +void +release_cutthrough_connection(const uschar * why) { -close_cutthrough_connection(why); -cutthrough.delivery = FALSE; +HDEBUG(D_acl) debug_printf_indent("release cutthrough conn: %s\n", why); +cutthrough.fd = -1; +cutthrough.delivery = cutthrough.callout_hold_only = FALSE; } @@ -1372,7 +1420,7 @@ if( !cutthrough_puts(US".", 1) ) return cutthrough.addr.message; -res = cutthrough_response('2', &cutthrough.addr.message, CUTTHROUGH_DATA_TIMEOUT); +res = cutthrough_response(cutthrough.fd, '2', &cutthrough.addr.message, CUTTHROUGH_DATA_TIMEOUT); for (addr = &cutthrough.addr; addr; addr = addr->next) { addr->message = cutthrough.addr.message; @@ -1879,7 +1927,7 @@ while (addr_new) } respond_printf(f, "%s\n", cr); } - cancel_cutthrough_connection("routing hard fail"); + cancel_cutthrough_connection(TRUE, US"routing hard fail"); if (!full_info) { @@ -1918,7 +1966,7 @@ while (addr_new) } respond_printf(f, "%s\n", cr); } - cancel_cutthrough_connection("routing soft fail"); + cancel_cutthrough_connection(TRUE, US"routing soft fail"); if (!full_info) { @@ -1991,7 +2039,7 @@ while (addr_new) /* If stopped because more than one new address, cannot cutthrough */ if (addr_new && addr_new->next) - cancel_cutthrough_connection("multiple addresses from routing"); + cancel_cutthrough_connection(TRUE, US"multiple addresses from routing"); yield = OK; goto out; @@ -2241,18 +2289,16 @@ verify_check_header_names_ascii(uschar **msgptr) header_line *h; uschar *colon, *s; -for (h = header_list; h != NULL; h = h->next) +for (h = header_list; h; h = h->next) { - colon = Ustrchr(h->text, ':'); - for(s = h->text; s < colon; s++) - { - if ((*s < 33) || (*s > 126)) - { - *msgptr = string_sprintf("Invalid character in header \"%.*s\" found", - colon - h->text, h->text); - return FAIL; - } - } + colon = Ustrchr(h->text, ':'); + for(s = h->text; s < colon; s++) + if ((*s < 33) || (*s > 126)) + { + *msgptr = string_sprintf("Invalid character in header \"%.*s\" found", + colon - h->text, h->text); + return FAIL; + } } return OK; } diff --git a/test/confs/0580 b/test/confs/0580 new file mode 100644 index 000000000..54ef7ae70 --- /dev/null +++ b/test/confs/0580 @@ -0,0 +1,46 @@ +# Exim test configuration 0580 + +OPT = + +.include DIR/aux-var/std_conf_prefix + +primary_hostname = myhost.test.ex + +# ----- Main settings ----- + +acl_smtp_rcpt = check_rcpt + +log_selector = +received_recipients +OPT + +# ----- ACLs ----- + +begin acl + +check_rcpt: + accept verify = recipient/callout=use_sender,hold + + +# ----- Routers ----- + +begin routers + +r1: + driver = manualroute + route_list = * 127.0.0.1 + self = send + transport = t1 + + +begin transports + +t1: + driver = smtp + port = PORT_S + + +# ----- Retry ----- +begin retry + +* * F,5d,10s +# End diff --git a/test/confs/0581 b/test/confs/0581 new file mode 120000 index 000000000..35e8a25bd --- /dev/null +++ b/test/confs/0581 @@ -0,0 +1 @@ +0580 \ No newline at end of file diff --git a/test/confs/0582 b/test/confs/0582 new file mode 120000 index 000000000..35e8a25bd --- /dev/null +++ b/test/confs/0582 @@ -0,0 +1 @@ +0580 \ No newline at end of file diff --git a/test/confs/2035 b/test/confs/2035 new file mode 100644 index 000000000..a10dc53e9 --- /dev/null +++ b/test/confs/2035 @@ -0,0 +1,84 @@ +# Exim test configuration 2035 + +OPT = + +.include DIR/aux-var/tls_conf_prefix + +.ifdef SERVER +tls_certificate = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.chain.pem +tls_privatekey = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.unlocked.key +.else +tls_advertise_hosts = +.endif + +primary_hostname = myhost.test.ex + +# ----- Main settings ----- + +acl_smtp_rcpt = check_rcpt +acl_smtp_data = check_data + +log_selector = +received_recipients +outgoing_port +OPT + +# ----- ACLs ----- + +begin acl + +check_rcpt: + accept + condition = ${if or { {!eq {SERVER}{server}} {= {$received_port}{PORT_S}} }} + verify = recipient/callout=use_sender,hold + defer condition = ${if eq {SERVER}{server}} + local_parts = rcpt_defer + accept + +check_data: + warn logwrite = $message_exim_id received on port $received_port + defer condition = ${if eq {SERVER}{server}} + condition = ${if eq {data_defer}{${local_part:$recipients}}} + accept + +# ----- Routers ----- + +begin routers + +.ifdef SERVER + +target: + driver = redirect + condition = ${if = {$received_port}{PORT_D}} + data = :blackhole: + +dut: + driver = manualroute + route_list = * 127.0.0.1 + self = send + transport = t1 + +.else + +client: + driver = manualroute + route_list = * 127.0.0.1 + self = send + transport = t1 + errors_to = "" + +.endif + + +begin transports + +t1: + driver = smtp + port = PORT_D + tls_verify_certificates = DIR/aux-fixed/exim-ca/example.com/CA/CA.pem + tls_verify_cert_hostnames = : + + +# ----- Retry ----- +begin retry + +* * F,5d,10s +# End diff --git a/test/confs/2036 b/test/confs/2036 new file mode 120000 index 000000000..3f3e22d7e --- /dev/null +++ b/test/confs/2036 @@ -0,0 +1 @@ +2035 \ No newline at end of file diff --git a/test/confs/2037 b/test/confs/2037 new file mode 120000 index 000000000..3f3e22d7e --- /dev/null +++ b/test/confs/2037 @@ -0,0 +1 @@ +2035 \ No newline at end of file diff --git a/test/confs/2135 b/test/confs/2135 new file mode 100644 index 000000000..fcb5f00f4 --- /dev/null +++ b/test/confs/2135 @@ -0,0 +1,85 @@ +# Exim test configuration 2135 + +OPT = + +.include DIR/aux-var/tls_conf_prefix + +.ifdef SERVER +tls_certificate = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.chain.pem +tls_privatekey = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.unlocked.key +.else +tls_advertise_hosts = +.endif + +primary_hostname = myhost.test.ex + +# ----- Main settings ----- + +acl_smtp_rcpt = check_rcpt +acl_smtp_data = check_data + +log_selector = +received_recipients +outgoing_port +OPT + +# ----- ACLs ----- + +begin acl + +check_rcpt: + accept + condition = ${if or { {!eq {SERVER}{server}} {= {$received_port}{PORT_S}} }} + verify = recipient/callout=use_sender,hold + defer condition = ${if eq {SERVER}{server}} + local_parts = rcpt_defer + accept + +check_data: + warn logwrite = $message_exim_id received on port $received_port + defer condition = ${if eq {SERVER}{server}} + condition = ${if eq {data_defer}{${local_part:$recipients}}} + accept + +# ----- Routers ----- + +begin routers + +.ifdef SERVER + +target: + driver = redirect + condition = ${if = {$received_port}{PORT_D}} + data = :blackhole: + +dut: + driver = manualroute + route_list = * 127.0.0.1 + self = send + transport = t1 + +.else + +client: + driver = manualroute + route_list = * 127.0.0.1 + self = send + transport = t1 + errors_to = "" + +.endif + + +begin transports + +t1: + driver = smtp + port = PORT_D + tls_verify_certificates = DIR/aux-fixed/exim-ca/example.com/CA/CA.pem + tls_verify_cert_hostnames = : + + +# ----- Retry ----- +begin retry + +* * F,5d,10s + +# End diff --git a/test/confs/2136 b/test/confs/2136 new file mode 120000 index 000000000..b9dc6e979 --- /dev/null +++ b/test/confs/2136 @@ -0,0 +1 @@ +2135 \ No newline at end of file diff --git a/test/confs/2137 b/test/confs/2137 new file mode 120000 index 000000000..b9dc6e979 --- /dev/null +++ b/test/confs/2137 @@ -0,0 +1 @@ +2135 \ No newline at end of file diff --git a/test/log/0580 b/test/log/0580 new file mode 100644 index 000000000..f006778e5 --- /dev/null +++ b/test/log/0580 @@ -0,0 +1,15 @@ +1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for usery@test.ex +1999-03-02 09:44:33 10HmaX-0005vi-00 => usery@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmaX-0005vi-00 Completed +1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for usery@test.ex usery2@test.ex +1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmaY-0005vi-00 -> usery2@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmaY-0005vi-00 Completed +1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for usery3@test.ex usery@test.ex +1999-03-02 09:44:33 10HmaZ-0005vi-00 => usery3@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmaZ-0005vi-00 -> usery@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed +1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for usery4@test.ex usery5@test.ex +1999-03-02 09:44:33 10HmbA-0005vi-00 => usery4@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmbA-0005vi-00 -> usery5@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmbA-0005vi-00 Completed diff --git a/test/log/0581 b/test/log/0581 new file mode 100644 index 000000000..f554e0057 --- /dev/null +++ b/test/log/0581 @@ -0,0 +1,23 @@ + +******** 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 10HmaX-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd@test.ex +1999-03-02 09:44:33 10HmaX-0005vi-00 => userd@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmaX-0005vi-00 Completed +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 10HmaY-0005vi-00 <= usere@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userf@test.ex +1999-03-02 09:44:33 10HmaY-0005vi-00 => userf@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmaY-0005vi-00 Completed +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 10HmaZ-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd@test.ex userd2@test.ex +1999-03-02 09:44:33 10HmaZ-0005vi-00 => userd@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmaZ-0005vi-00 -> userd2@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed +1999-03-02 09:44:33 10HmbA-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd3@test.ex userd2@test.ex +1999-03-02 09:44:33 10HmbA-0005vi-00 => userd3@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmbA-0005vi-00 -> userd2@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmbA-0005vi-00 Completed +1999-03-02 09:44:33 10HmbB-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd4@test.ex userd5@test.ex +1999-03-02 09:44:33 10HmbB-0005vi-00 => userd4@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmbB-0005vi-00 -> userd5@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message" +1999-03-02 09:44:33 10HmbB-0005vi-00 Completed diff --git a/test/log/0582 b/test/log/0582 new file mode 100644 index 000000000..8953064ef --- /dev/null +++ b/test/log/0582 @@ -0,0 +1,3 @@ +1999-03-02 09:44:33 U=CALLER F= temporarily rejected RCPT : Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:: 451 not right now +1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for userh@test.ex +1999-03-02 09:44:33 10HmaX-0005vi-00 == userh@test.ex R=r1 T=t1 defer (-46) H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after end of data: 451 not right now diff --git a/test/log/2035 b/test/log/2035 new file mode 100644 index 000000000..13c6c838e --- /dev/null +++ b/test/log/2035 @@ -0,0 +1,11 @@ +1999-03-02 09:44:33 10HmaX-0005vi-00 10HmaX-0005vi-00 received on port 0 +1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for userb@test.ex +1999-03-02 09:44:33 10HmaX-0005vi-00 => userb@test.ex R=client T=t1 H=127.0.0.1 [127.0.0.1]:1225 X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmaY-0005vi-00" +1999-03-02 09:44:33 10HmaX-0005vi-00 Completed + +******** 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 10HmaY-0005vi-00 10HmaY-0005vi-00 received on port 1225 +1999-03-02 09:44:33 10HmaY-0005vi-00 <= usera@ok.example H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userb@test.ex +1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: R=target +1999-03-02 09:44:33 10HmaY-0005vi-00 Completed diff --git a/test/log/2036 b/test/log/2036 new file mode 100644 index 000000000..b2cbc2c98 --- /dev/null +++ b/test/log/2036 @@ -0,0 +1,20 @@ + +******** SERVER ******** +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224 +1999-03-02 09:44:33 10HmaX-0005vi-00 10HmaX-0005vi-00 received on port 1224 +1999-03-02 09:44:33 10HmaX-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd@test.ex +1999-03-02 09:44:33 10HmaY-0005vi-00 10HmaY-0005vi-00 received on port 1225 +1999-03-02 09:44:33 10HmaY-0005vi-00 <= userc@ok.example H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss for userd@test.ex +1999-03-02 09:44:33 10HmaX-0005vi-00 => userd@test.ex R=dut T=t1 H=127.0.0.1 [127.0.0.1]:1225 X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmaY-0005vi-00" +1999-03-02 09:44:33 10HmaX-0005vi-00 Completed +1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: R=target +1999-03-02 09:44:33 10HmaY-0005vi-00 Completed +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224 +1999-03-02 09:44:33 10HmaZ-0005vi-00 10HmaZ-0005vi-00 received on port 1224 +1999-03-02 09:44:33 10HmaZ-0005vi-00 <= usere@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userf@test.ex +1999-03-02 09:44:33 10HmbA-0005vi-00 10HmbA-0005vi-00 received on port 1225 +1999-03-02 09:44:33 10HmbA-0005vi-00 <= usere@ok.example H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss for userf@test.ex +1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: R=target +1999-03-02 09:44:33 10HmbA-0005vi-00 Completed +1999-03-02 09:44:33 10HmaZ-0005vi-00 => userf@test.ex R=dut T=t1 H=127.0.0.1 [127.0.0.1]:1225 C="250 OK id=10HmbA-0005vi-00" +1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed diff --git a/test/log/2037 b/test/log/2037 new file mode 100644 index 000000000..896dcf6f8 --- /dev/null +++ b/test/log/2037 @@ -0,0 +1,10 @@ +1999-03-02 09:44:33 U=CALLER F= temporarily rejected RCPT : Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:: 451 Temporary local problem - please try later +1999-03-02 09:44:33 10HmaY-0005vi-00 10HmaY-0005vi-00 received on port 0 +1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for data_defer@test.ex +1999-03-02 09:44:33 10HmaY-0005vi-00 == data_defer@test.ex R=client T=t1 defer (-46) H=127.0.0.1 [127.0.0.1]:1111: SMTP error from remote mail server after end of data: 451 Temporary local problem - please try later + +******** 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 H=localhost (myhost.test.ex) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F= temporarily rejected RCPT +1999-03-02 09:44:33 10HmaX-0005vi-00 10HmaX-0005vi-00 received on port 1225 +1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost (myhost.test.ex) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F= temporarily rejected after DATA diff --git a/test/log/2135 b/test/log/2135 new file mode 100644 index 000000000..d2a01cd23 --- /dev/null +++ b/test/log/2135 @@ -0,0 +1,11 @@ +1999-03-02 09:44:33 10HmaX-0005vi-00 10HmaX-0005vi-00 received on port 0 +1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for userb@test.ex +1999-03-02 09:44:33 10HmaX-0005vi-00 => userb@test.ex R=client T=t1 H=127.0.0.1 [127.0.0.1]:1225 X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmaY-0005vi-00" +1999-03-02 09:44:33 10HmaX-0005vi-00 Completed + +******** 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 10HmaY-0005vi-00 10HmaY-0005vi-00 received on port 1225 +1999-03-02 09:44:33 10HmaY-0005vi-00 <= usera@ok.example H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userb@test.ex +1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: R=target +1999-03-02 09:44:33 10HmaY-0005vi-00 Completed diff --git a/test/log/2136 b/test/log/2136 new file mode 100644 index 000000000..bfd9e31fd --- /dev/null +++ b/test/log/2136 @@ -0,0 +1,20 @@ + +******** SERVER ******** +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224 +1999-03-02 09:44:33 10HmaX-0005vi-00 10HmaX-0005vi-00 received on port 1224 +1999-03-02 09:44:33 10HmaX-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd@test.ex +1999-03-02 09:44:33 10HmaY-0005vi-00 10HmaY-0005vi-00 received on port 1225 +1999-03-02 09:44:33 10HmaY-0005vi-00 <= userc@ok.example H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss for userd@test.ex +1999-03-02 09:44:33 10HmaX-0005vi-00 => userd@test.ex R=dut T=t1 H=127.0.0.1 [127.0.0.1]:1225 X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmaY-0005vi-00" +1999-03-02 09:44:33 10HmaX-0005vi-00 Completed +1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: R=target +1999-03-02 09:44:33 10HmaY-0005vi-00 Completed +1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224 +1999-03-02 09:44:33 10HmaZ-0005vi-00 10HmaZ-0005vi-00 received on port 1224 +1999-03-02 09:44:33 10HmaZ-0005vi-00 <= usere@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userf@test.ex +1999-03-02 09:44:33 10HmbA-0005vi-00 10HmbA-0005vi-00 received on port 1225 +1999-03-02 09:44:33 10HmbA-0005vi-00 <= usere@ok.example H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss for userf@test.ex +1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: R=target +1999-03-02 09:44:33 10HmbA-0005vi-00 Completed +1999-03-02 09:44:33 10HmaZ-0005vi-00 => userf@test.ex R=dut T=t1 H=127.0.0.1 [127.0.0.1]:1225 C="250 OK id=10HmbA-0005vi-00" +1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed diff --git a/test/log/2137 b/test/log/2137 new file mode 100644 index 000000000..bef7dce9d --- /dev/null +++ b/test/log/2137 @@ -0,0 +1,10 @@ +1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT : Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:: 451 Temporary local problem - please try later +1999-03-02 09:44:33 10HmaY-0005vi-00 10HmaY-0005vi-00 received on port 0 +1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for data_defer@test.ex +1999-03-02 09:44:33 10HmaY-0005vi-00 == data_defer@test.ex R=client T=t1 defer (-46) H=127.0.0.1 [127.0.0.1]:1111: SMTP error from remote mail server after end of data: 451 Temporary local problem - please try later + +******** 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 H=localhost (myhost.test.ex) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> temporarily rejected RCPT +1999-03-02 09:44:33 10HmaX-0005vi-00 10HmaX-0005vi-00 received on port 1225 +1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost (myhost.test.ex) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> temporarily rejected after DATA diff --git a/test/rejectlog/0582 b/test/rejectlog/0582 new file mode 100644 index 000000000..614c29400 --- /dev/null +++ b/test/rejectlog/0582 @@ -0,0 +1 @@ +1999-03-02 09:44:33 U=CALLER F= temporarily rejected RCPT : Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:: 451 not right now diff --git a/test/rejectlog/2037 b/test/rejectlog/2037 new file mode 100644 index 000000000..19259d512 --- /dev/null +++ b/test/rejectlog/2037 @@ -0,0 +1,21 @@ +1999-03-02 09:44:33 U=CALLER F= temporarily rejected RCPT : Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:: 451 Temporary local problem - please try later + +******** SERVER ******** +1999-03-02 09:44:33 H=localhost (myhost.test.ex) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F= temporarily rejected RCPT +1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost (myhost.test.ex) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F= temporarily rejected after DATA +Envelope-from: +Envelope-to: +P Received: from localhost ([127.0.0.1] helo=myhost.test.ex) + by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256) + (Exim x.yz) + (envelope-from ) + id 10HmaX-0005vi-00 + for data_defer@test.ex; Tue, 2 Mar 1999 09:44:33 +0000 +P Received: from CALLER by myhost.test.ex with local-smtp (Exim x.yz) + (envelope-from ) + id 10HmaY-0005vi-00 + for data_defer@test.ex; Tue, 2 Mar 1999 09:44:33 +0000 + Subject: test +I Message-Id: +F From: CALLER_NAME + Date: Tue, 2 Mar 1999 09:44:33 +0000 diff --git a/test/rejectlog/2137 b/test/rejectlog/2137 new file mode 100644 index 000000000..6ec734584 --- /dev/null +++ b/test/rejectlog/2137 @@ -0,0 +1,20 @@ +1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT : Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:: 451 Temporary local problem - please try later + +******** SERVER ******** +1999-03-02 09:44:33 H=localhost (myhost.test.ex) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> temporarily rejected RCPT +1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost (myhost.test.ex) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> temporarily rejected after DATA +Envelope-from: <> +Envelope-to: +P Received: from localhost ([127.0.0.1] helo=myhost.test.ex) + by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256) + (Exim x.yz) + id 10HmaX-0005vi-00 + for data_defer@test.ex; Tue, 2 Mar 1999 09:44:33 +0000 +P Received: from CALLER by myhost.test.ex with local-smtp (Exim x.yz) + (envelope-from ) + id 10HmaY-0005vi-00 + for data_defer@test.ex; Tue, 2 Mar 1999 09:44:33 +0000 + Subject: test +I Message-Id: +F From: CALLER_NAME + Date: Tue, 2 Mar 1999 09:44:33 +0000 diff --git a/test/scripts/0000-Basic/0580 b/test/scripts/0000-Basic/0580 new file mode 100644 index 000000000..8d8a11751 --- /dev/null +++ b/test/scripts/0000-Basic/0580 @@ -0,0 +1,156 @@ +# callout lazy-close, -bs send +need_ipv4 +# +# a recipient verify and continued-delivery +# cmdline -bs send +server PORT_S +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO +250 OK +DATA +354 hit me +. +250 yeah got that message +QUIT +221 Bye +**** +# +exim -bs +mail from: +rcpt to: +data +Subject: test + +body +. +quit +**** +sleep 1 +# +# +# multiple recipients +# 1st callout result is cached (above); should not activate LCC +server PORT_S 2 +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO +250 OK +QUIT +221 Bye +*eof +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO +250 OK +RCPT TO +250 OK +DATA +354 hit me +. +250 yeah got that message +QUIT +221 Bye +**** +# +exim -bs +mail from: +rcpt to: +rcpt to: +data +Subject: test + +body +. +quit +**** +sleep 1 +# +# +# 2nd callout result is cached (above); should not activate LCC +server PORT_S 2 +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO +250 OK +QUIT +221 Bye +*eof +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO +250 OK +RCPT TO +250 OK +DATA +354 hit me +. +250 yeah got that message +QUIT +221 Bye +**** +# +exim -bs +mail from: +rcpt to: +rcpt to: +data +Subject: test + +body +. +quit +**** +sleep 1 +# +# +# no cache hits; should do LCC +server PORT_S +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO +250 OK +RCPT TO +250 OK +DATA +354 hit me +. +250 yeah got that message +QUIT +221 Bye +**** +# +exim -bs +mail from: +rcpt to: +rcpt to: +data +Subject: test + +body +. +quit +**** +sleep 1 +# +# +no_stdout_check +no_msglog_check diff --git a/test/scripts/0000-Basic/0581 b/test/scripts/0000-Basic/0581 new file mode 100644 index 000000000..f0ce3bcd7 --- /dev/null +++ b/test/scripts/0000-Basic/0581 @@ -0,0 +1,264 @@ +# callout lazy-close, smtp send +need_ipv4 +# +# a recipient verify and continued-delivery +# smtp send +server PORT_S +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO +250 OK +DATA +354 hit me +. +250 yeah got that message +QUIT +221 Bye +**** +# +exim -DSERVER=server -bd -oX PORT_D +**** +# +client 127.0.0.1 PORT_D +??? 220 +EHLO test.ex +??? 250- +??? 250- +??? 250- +??? 250- +??? 250 +MAIL FROM: +??? 250 +RCPT TO: +??? 250 +DATA +??? 354 +Subject: test + +body +. +??? 250 +QUIT +??? 221 +**** +sleep 1 +killdaemon +# +# +# smtp send, deliver_drop_priv +server PORT_S +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO +250 OK +DATA +354 hit me +. +250 yeah got that message +QUIT +221 Bye +**** +# +exim -DSERVER=server -DOPT=deliver_drop_privilege -bd -oX PORT_D +**** +# +client 127.0.0.1 PORT_D +??? 220 +EHLO test.ex +??? 250- +??? 250- +??? 250- +??? 250- +??? 250 +MAIL FROM: +??? 250 +RCPT TO: +??? 250 +DATA +??? 354 +Subject: test + +body +. +??? 250 +QUIT +??? 221 +**** +sleep 1 +killdaemon +# +# +# multiple recipients +# 1st callout result is cached (above); should not activate LCC +# smtp send +server PORT_S 2 +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO: +250 OK +QUIT +221 Bye +*eof +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO: +250 OK +RCPT TO: +250 OK +DATA +354 hit me +. +250 yeah got that message +QUIT +221 Bye +**** +# +exim -DSERVER=server -bd -oX PORT_D +**** +# +client 127.0.0.1 PORT_D +??? 220 +EHLO test.ex +??? 250- +??? 250- +??? 250- +??? 250- +??? 250 +MAIL FROM: +??? 250 +RCPT TO: +??? 250 +RCPT TO: +??? 250 +DATA +??? 354 +Subject: test + +body +. +??? 250 +QUIT +??? 221 +**** +sleep 1 +# +# +# 2nd callout result is cached (above); should not activate LCC +# smtp send +server PORT_S 2 +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO: +250 OK +QUIT +221 Bye +*eof +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO: +250 OK +RCPT TO: +250 OK +DATA +354 hit me +. +250 yeah got that message +QUIT +221 Bye +**** +# +client 127.0.0.1 PORT_D +??? 220 +EHLO test.ex +??? 250- +??? 250- +??? 250- +??? 250- +??? 250 +MAIL FROM: +??? 250 +RCPT TO: +??? 250 +RCPT TO: +??? 250 +DATA +??? 354 +Subject: test + +body +. +??? 250 +QUIT +??? 221 +**** +sleep 1 +# +# +# no cache hits; should do LCC +# smtp send +server PORT_S 2 +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO: +250 OK +RCPT TO: +250 OK +DATA +354 hit me +. +250 yeah got that message +QUIT +221 Bye +**** +# +client 127.0.0.1 PORT_D +??? 220 +EHLO test.ex +??? 250- +??? 250- +??? 250- +??? 250- +??? 250 +MAIL FROM: +??? 250 +RCPT TO: +??? 250 +RCPT TO: +??? 250 +DATA +??? 354 +Subject: test + +body +. +??? 250 +QUIT +??? 221 +**** +sleep 1 +killdaemon +# +# +no_stdout_check +no_msglog_check diff --git a/test/scripts/0000-Basic/0582 b/test/scripts/0000-Basic/0582 new file mode 100644 index 000000000..3eefcc979 --- /dev/null +++ b/test/scripts/0000-Basic/0582 @@ -0,0 +1,56 @@ +# callout lazy-close, defers +need_ipv4 +# +# a recipient verify and continued-delivery +# cmdline -bs send, rcpt-time defer +server PORT_S +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO +451 not right now +QUIT +221 Bye +**** +# +exim -bs +mail from: +rcpt to: +quit +**** +sleep 1 +# +# cmdline -bs send, data-time defer +server PORT_S +220 Welcome +EHLO +250 Hi +MAIL FROM +250 OK +RCPT TO +250 OK +DATA +354 hit me +. +451 not right now +QUIT +221 Bye +**** +# +exim -bs +mail from: +rcpt to: +data +Subject: test + +body +. +quit +**** +sleep 1 +# +# +no_stdout_check +no_msglog_check diff --git a/test/scripts/2000-GnuTLS/2035 b/test/scripts/2000-GnuTLS/2035 new file mode 100644 index 000000000..cb227868c --- /dev/null +++ b/test/scripts/2000-GnuTLS/2035 @@ -0,0 +1,26 @@ +# client: callout lazy-close, -bs send +gnutls +need_ipv4 +# +# a tls-capable target for the verify/delivery connection +exim -bd -DSERVER=server -oX PORT_D +**** +# +# a recipient verify and continued-delivery +# cmdline -bs send +exim -bs +mail from: +rcpt to: +data +Subject: test + +body +. +quit +**** +sleep 1 +killdaemon +# +# +no_stdout_check +no_msglog_check diff --git a/test/scripts/2000-GnuTLS/2036 b/test/scripts/2000-GnuTLS/2036 new file mode 100644 index 000000000..1891d2fe8 --- /dev/null +++ b/test/scripts/2000-GnuTLS/2036 @@ -0,0 +1,70 @@ +# client: callout lazy-close, smtp send +gnutls +need_ipv4 +# +# smtp send +# a tls-capable target for the verify/delivery connection on PORT_D +# plus a daemon under test on PORT_S +exim -bd -DSERVER=server -oX PORT_D:PORT_S +**** +# +client 127.0.0.1 PORT_S +??? 220 +EHLO test.ex +??? 250- +??? 250- +??? 250- +??? 250- +??? 250- +??? 250 +MAIL FROM: +??? 250 +RCPT TO: +??? 250 +DATA +??? 354 +Subject: test + +body +. +??? 250 +QUIT +??? 221 +**** +sleep 1 +killdaemon +# +# +# smtp send, deliver_drop_priv +exim -bd -DSERVER=server -DOPT=deliver_drop_privilege -oX PORT_D:PORT_S +**** +# +client 127.0.0.1 PORT_S +??? 220 +EHLO test.ex +??? 250- +??? 250- +??? 250- +??? 250- +??? 250- +??? 250 +MAIL FROM: +??? 250 +RCPT TO: +??? 250 +DATA +??? 354 +Subject: test + +body +. +??? 250 +QUIT +??? 221 +**** +sleep 1 +killdaemon +# +# +no_stdout_check +no_msglog_check diff --git a/test/scripts/2000-GnuTLS/2037 b/test/scripts/2000-GnuTLS/2037 new file mode 100644 index 000000000..8dca68114 --- /dev/null +++ b/test/scripts/2000-GnuTLS/2037 @@ -0,0 +1,31 @@ +# client: callout lazy-close, defers +gnutls +need_ipv4 +# +exim -bd -DSERVER=server -oX PORT_D +**** +# cmdline -bs send, rcpt-time defer +exim -bs +mail from: +rcpt to: +quit +**** +sleep 1 +# +# cmdline -bs send, data-time defer +exim -bs +mail from: +rcpt to: +data +Subject: test + +body +. +quit +**** +sleep 1 +killdaemon +# +# +no_stdout_check +no_msglog_check diff --git a/test/scripts/2100-OpenSSL/2135 b/test/scripts/2100-OpenSSL/2135 new file mode 100644 index 000000000..e521c45e3 --- /dev/null +++ b/test/scripts/2100-OpenSSL/2135 @@ -0,0 +1,25 @@ +# client: callout lazy-close, -bs send +need_ipv4 +# +# a tls-capable target for the verify/delivery connection +exim -bd -DSERVER=server -oX PORT_D +**** +# +# a recipient verify and continued-delivery +# cmdline -bs send +exim -bs +mail from: +rcpt to: +data +Subject: test + +body +. +quit +**** +sleep 1 +killdaemon +# +# +no_stdout_check +no_msglog_check diff --git a/test/scripts/2100-OpenSSL/2136 b/test/scripts/2100-OpenSSL/2136 new file mode 100644 index 000000000..aa13114d5 --- /dev/null +++ b/test/scripts/2100-OpenSSL/2136 @@ -0,0 +1,71 @@ +# client: callout lazy-close, smtp send +need_ipv4 +# +# a recipient verify and continued-delivery +# smtp send +# a tls-capable target for the verify/delivery connection on PORT_D +# plus a daemon under test on PORT_S +exim -bd -DSERVER=server -oX PORT_D:PORT_S +**** +# +client 127.0.0.1 PORT_S +??? 220 +EHLO test.ex +??? 250- +??? 250- +??? 250- +??? 250- +??? 250- +??? 250 +MAIL FROM: +??? 250 +RCPT TO: +??? 250 +DATA +??? 354 +Subject: test + +body +. +??? 250 +QUIT +??? 221 +**** +sleep 1 +killdaemon +# +# +# smtp send, deliver_drop_priv +exim -bd -DSERVER=server -DOPT=deliver_drop_privilege -oX PORT_D:PORT_S +**** +# +client 127.0.0.1 PORT_S +??? 220 +EHLO test.ex +??? 250- +??? 250- +??? 250- +??? 250- +??? 250- +??? 250 +MAIL FROM: +??? 250 +RCPT TO: +??? 250 +DATA +??? 354 +Subject: test + +body +. +??? 250 +QUIT +??? 221 +**** +sleep 1 +killdaemon +# +# +# +no_stdout_check +no_msglog_check diff --git a/test/scripts/2100-OpenSSL/2137 b/test/scripts/2100-OpenSSL/2137 new file mode 100644 index 000000000..ec9a964a2 --- /dev/null +++ b/test/scripts/2100-OpenSSL/2137 @@ -0,0 +1,30 @@ +# client: callout lazy-close, defers +need_ipv4 +# +exim -bd -DSERVER=server -oX PORT_D +**** +# cmdline -bs send, rcpt-time defer +exim -bs +mail from:<> +rcpt to: +quit +**** +sleep 1 +# +# cmdline -bs send, data-time defer +exim -bs +mail from:<> +rcpt to: +data +Subject: test + +body +. +quit +**** +sleep 1 +killdaemon +# +# +no_stdout_check +no_msglog_check diff --git a/test/stderr/0021 b/test/stderr/0021 index 7c5a79ee9..ce72feb75 100644 --- a/test/stderr/0021 +++ b/test/stderr/0021 @@ -183,6 +183,7 @@ end of ACL "rcpt": ACCEPT >> LOG: MAIN <= ok@test3 H=[10.9.8.8] U=CALLER P=smtp S=sss +release cutthrough conn: msg passed for delivery Exim version x.yz .... configuration file is TESTSUITE/test-config trusted user diff --git a/test/stderr/0275 b/test/stderr/0275 index 5f76af09a..3ec0da1d4 100644 --- a/test/stderr/0275 +++ b/test/stderr/0275 @@ -163,6 +163,7 @@ LOG: MAIN <= CALLER@test.ex U=CALLER P=local S=sss created log directory TESTSUITE/spool/log search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaX-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective diff --git a/test/stderr/0278 b/test/stderr/0278 index 2d9967293..0274527ee 100644 --- a/test/stderr/0278 +++ b/test/stderr/0278 @@ -114,6 +114,7 @@ LOG: MAIN <= CALLER@test.ex U=CALLER P=local S=sss created log directory TESTSUITE/spool/log search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaX-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective diff --git a/test/stderr/0361 b/test/stderr/0361 index 2506e1cfb..d90d472d6 100644 --- a/test/stderr/0361 +++ b/test/stderr/0361 @@ -56,6 +56,7 @@ Size of headers = sss LOG: MAIN <= CALLER@test.ex U=CALLER P=local S=sss search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -N -odi -Mc 10HmaY-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective diff --git a/test/stderr/0386 b/test/stderr/0386 index 44e856da2..0b980acda 100644 --- a/test/stderr/0386 +++ b/test/stderr/0386 @@ -221,6 +221,7 @@ LOG: MAIN <= x@y H=[V4NET.11.12.13] U=CALLER P=smtp S=sss SMTP>> 250 OK id=10HmaX-0005vi-00 search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaX-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective @@ -402,6 +403,7 @@ LOG: MAIN <= x@y H=[V4NET.11.12.13] U=CALLER P=smtp S=sss SMTP>> 250 OK id=10HmaY-0005vi-00 search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaY-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective diff --git a/test/stderr/0388 b/test/stderr/0388 index 92b3f23e1..df772c330 100644 --- a/test/stderr/0388 +++ b/test/stderr/0388 @@ -223,6 +223,7 @@ Size of headers = sss LOG: MAIN <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xebb95ced -odi -Mc 10HmaY-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective diff --git a/test/stderr/0402 b/test/stderr/0402 index a007de31c..ea99dea2c 100644 --- a/test/stderr/0402 +++ b/test/stderr/0402 @@ -174,6 +174,7 @@ LOG: MAIN <= CALLER@test.ex U=CALLER P=local S=sss created log directory TESTSUITE/spool/log search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95dfd -odi -Mc 10HmaX-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective diff --git a/test/stderr/0403 b/test/stderr/0403 index 716cabdf2..32387a9fc 100644 --- a/test/stderr/0403 +++ b/test/stderr/0403 @@ -47,6 +47,7 @@ LOG: MAIN <= CALLER@test.ex U=CALLER P=local S=sss created log directory TESTSUITE/spool/log search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -N -odi -Mc 10HmaX-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective diff --git a/test/stderr/0404 b/test/stderr/0404 index d3d8f4c64..96c42cb7a 100644 --- a/test/stderr/0404 +++ b/test/stderr/0404 @@ -147,6 +147,7 @@ LOG: MAIN <= CALLER@test.ex U=CALLER P=local S=sss created log directory TESTSUITE/spool/log search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaX-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective @@ -1524,6 +1525,7 @@ Size of headers = sss LOG: MAIN <= <> R=10HmaX-0005vi-00 U=CALLER P=local S=sss search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaY-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective diff --git a/test/stderr/0408 b/test/stderr/0408 index f3d6d6b1a..e71299fea 100644 --- a/test/stderr/0408 +++ b/test/stderr/0408 @@ -47,6 +47,7 @@ LOG: MAIN <= CALLER@test.ex U=CALLER P=local S=sss created log directory TESTSUITE/spool/log search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaX-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective diff --git a/test/stderr/0487 b/test/stderr/0487 index 7319b67dd..c29883a0f 100644 --- a/test/stderr/0487 +++ b/test/stderr/0487 @@ -74,6 +74,7 @@ LOG: MAIN created log directory TESTSUITE/spool/log SMTP>> 250 OK id=10HmaX-0005vi-00 search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaX-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective diff --git a/test/stderr/2600 b/test/stderr/2600 index 4e9974733..957092f7f 100644 --- a/test/stderr/2600 +++ b/test/stderr/2600 @@ -335,6 +335,7 @@ LOG: MAIN <= CALLER@myhost.test.ex U=CALLER P=local S=sss created log directory TESTSUITE/spool/log search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaX-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective diff --git a/test/stderr/5004 b/test/stderr/5004 index ad5c9b331..62a0ef987 100644 --- a/test/stderr/5004 +++ b/test/stderr/5004 @@ -49,6 +49,7 @@ LOG: MAIN <= CALLER@test.ex U=CALLER P=local S=sss created log directory TESTSUITE/spool/log search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaX-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective diff --git a/test/stderr/5005 b/test/stderr/5005 index 8b28b7055..74f66486e 100644 --- a/test/stderr/5005 +++ b/test/stderr/5005 @@ -47,6 +47,7 @@ LOG: MAIN <= CALLER@test.ex U=CALLER P=local S=sss created log directory TESTSUITE/spool/log search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaX-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective @@ -235,6 +236,7 @@ Size of headers = sss LOG: MAIN <= CALLER@test.ex U=CALLER P=local S=sss search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaY-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective @@ -424,6 +426,7 @@ Size of headers = sss LOG: MAIN <= CALLER@test.ex U=CALLER P=local S=sss search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaZ-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective @@ -622,6 +625,7 @@ Size of headers = sss LOG: MAIN <= CALLER@test.ex U=CALLER P=local S=sss search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmbA-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective diff --git a/test/stderr/5006 b/test/stderr/5006 index dce0d0050..4211a1877 100644 --- a/test/stderr/5006 +++ b/test/stderr/5006 @@ -47,6 +47,7 @@ LOG: MAIN <= CALLER@test.ex U=CALLER P=local S=sss created log directory TESTSUITE/spool/log search_tidyup called +release cutthrough conn: msg passed for delivery exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xfbb95cfd -odi -Mc 10HmaX-0005vi-00 Exim version x.yz .... changed uid/gid: forcing real = effective -- 2.25.1