X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/ee8b809061baea861fc87c41bcb72a62d76b0047..f374b08a8eb32aebe9d3a4a0455313ca911c3ff8:/src/src/deliver.c diff --git a/src/src/deliver.c b/src/src/deliver.c index 9f292fc53..34990b71e 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -66,7 +66,6 @@ static address_item *addr_new = NULL; static address_item *addr_remote = NULL; static address_item *addr_route = NULL; static address_item *addr_succeed = NULL; -static address_item *addr_dsntmp = NULL; static address_item *addr_senddsn = NULL; static FILE *message_log = NULL; @@ -108,21 +107,21 @@ Returns: the amount of bytes read static ssize_t readn(int fd, void * buffer, size_t len) { - void * next = buffer; - void * end = buffer + len; +uschar * next = buffer; +uschar * end = next + len; - while (next < end) - { - ssize_t got = read(fd, next, end - next); +while (next < end) + { + ssize_t got = read(fd, next, end - next); - /* I'm not sure if there are signals that can interrupt us, - for now I assume the worst */ - if (got == -1 && errno == EINTR) continue; - if (got <= 0) return next - buffer; - next += got; - } + /* I'm not sure if there are signals that can interrupt us, + for now I assume the worst */ + if (got == -1 && errno == EINTR) continue; + if (got <= 0) return next - US buffer; + next += got; + } - return len; +return len; } @@ -145,7 +144,7 @@ Returns: a pointer to an initialized address_item address_item * deliver_make_addr(uschar *address, BOOL copy) { -address_item *addr = store_get(sizeof(address_item)); +address_item *addr = store_get(sizeof(address_item), FALSE); *addr = address_defaults; if (copy) address = string_copy(address); addr->address = address; @@ -199,6 +198,7 @@ deliver_recipients = addr; deliver_address_data = addr->prop.address_data; deliver_domain_data = addr->prop.domain_data; deliver_localpart_data = addr->prop.localpart_data; +router_var = addr->prop.variables; /* These may be unset for multiple addresses */ @@ -284,13 +284,12 @@ to the same pipe or file. */ else { - address_item *addr2; if (testflag(addr, af_pfr)) { if (testflag(addr, af_file)) address_file = addr->local_part; else if (addr->local_part[0] == '|') address_pipe = addr->local_part; } - for (addr2 = addr->next; addr2; addr2 = addr2->next) + for (address_item * addr2 = addr->next; addr2; addr2 = addr2->next) { if (deliver_domain && Ustrcmp(deliver_domain, addr2->domain) != 0) deliver_domain = NULL; @@ -329,11 +328,13 @@ Returns: a file descriptor, or -1 (with errno set) static int open_msglog_file(uschar *filename, int mode, uschar **error) { -int fd, i; +if (Ustrstr(filename, US"/../")) + log_write(0, LOG_MAIN|LOG_PANIC, + "Attempt to open msglog file path with upward-traversal: '%s'\n", filename); -for (i = 2; i > 0; i--) +for (int i = 2; i > 0; i--) { - fd = Uopen(filename, + int fd = Uopen(filename, #ifdef O_CLOEXEC O_CLOEXEC | #endif @@ -350,7 +351,7 @@ for (i = 2; i > 0; i--) #ifndef O_CLOEXEC (void)fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); #endif - if (fchown(fd, exim_uid, exim_gid) < 0) + if (exim_fchown(fd, exim_uid, exim_gid, filename) < 0) { *error = US"chown"; return -1; @@ -370,7 +371,7 @@ for (i = 2; i > 0; i--) MSGLOG_DIRECTORY_MODE, TRUE); } -*error = US"create"; +*error = US"create or open"; return -1; } @@ -422,8 +423,7 @@ Returns: nothing static void replicate_status(address_item *addr) { -address_item *addr2; -for (addr2 = addr->next; addr2; addr2 = addr2->next) +for (address_item * addr2 = addr->next; addr2; addr2 = addr2->next) { addr2->transport = addr->transport; addr2->transport_return = addr->transport_return; @@ -657,8 +657,6 @@ Returns: nothing static void address_done(address_item *addr, uschar *now) { -address_item *dup; - update_spool = TRUE; /* Ensure spool gets updated */ /* Top-level address */ @@ -685,7 +683,7 @@ else tree_add_nonrecipient(addr->unique); /* Check the list of duplicate addresses and ensure they are now marked done as well. */ -for (dup = addr_duplicate; dup; dup = dup->next) +for (address_item * dup = addr_duplicate; dup; dup = dup->next) if (Ustrcmp(addr->unique, dup->unique) == 0) { tree_add_nonrecipient(dup->unique); @@ -716,9 +714,10 @@ Returns: nothing static void child_done(address_item *addr, uschar *now) { -address_item *aa; while (addr->parent) { + address_item *aa; + addr = addr->parent; if (--addr->child_count > 0) return; /* Incomplete parent */ address_done(addr, now); @@ -761,10 +760,9 @@ d_log_interface(gstring * g) if (LOGGING(incoming_interface) && LOGGING(outgoing_interface) && sending_ip_address) { - g = string_append(g, 2, US" I=[", sending_ip_address); - g = LOGGING(outgoing_port) - ? string_append(g, 2, US"]:", string_sprintf("%d", sending_port)) - : string_catn(g, US"]", 1); + g = string_fmt_append(g, " I=[%s]", sending_ip_address); + if (LOGGING(outgoing_port)) + g = string_fmt_append(g, ":%d", sending_port); } return g; } @@ -784,14 +782,14 @@ if (LOGGING(dnssec) && h->dnssec == DS_YES) g = string_append(g, 3, US" [", h->address, US"]"); if (LOGGING(outgoing_port)) - g = string_append(g, 2, US":", string_sprintf("%d", h->port)); + g = string_fmt_append(g, ":%d", h->port); #ifdef SUPPORT_SOCKS if (LOGGING(proxy) && proxy_local_address) { g = string_append(g, 3, US" PRX=[", proxy_local_address, US"]"); if (LOGGING(outgoing_port)) - g = string_append(g, 2, US":", string_sprintf("%d", proxy_local_port)); + g = string_fmt_append(g, ":%d", proxy_local_port); } #endif @@ -807,14 +805,20 @@ return g; -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS static gstring * -d_tlslog(gstring * s, address_item * addr) +d_tlslog(gstring * g, address_item * addr) { if (LOGGING(tls_cipher) && addr->cipher) - s = string_append(s, 2, US" X=", addr->cipher); + { + g = string_append(g, 2, US" X=", addr->cipher); +#ifdef EXPERIMENTAL_TLS_RESUME + if (LOGGING(tls_resumption) && testflag(addr, af_tls_resume)) + g = string_catn(g, US"*", 1); +#endif + } if (LOGGING(tls_certificate_verified) && addr->cipher) - s = string_append(s, 2, US" CV=", + g = string_append(g, 2, US" CV=", testflag(addr, af_cert_verified) ? #ifdef SUPPORT_DANE @@ -825,8 +829,8 @@ if (LOGGING(tls_certificate_verified) && addr->cipher) "yes" : "no"); if (LOGGING(tls_peerdn) && addr->peerdn) - s = string_append(s, 3, US" DN=\"", string_printing(addr->peerdn), US"\""); -return s; + g = string_append(g, 3, US" DN=\"", string_printing(addr->peerdn), US"\""); +return g; } #endif @@ -862,6 +866,7 @@ if (action) { DEBUG(D_deliver) debug_printf("Event(%s): event_action returned \"%s\"\n", event, s); + errno = ERRNO_EVENT; return s; } } @@ -1022,7 +1027,8 @@ splitting is done; in those cases use the original field. */ else { - uschar * cmp = g->s + g->ptr; + uschar * cmp; + int off = g->ptr; /* start of the "full address" */ if (addr->local_part) { @@ -1044,6 +1050,7 @@ else of all, do a caseless comparison; if this succeeds, do a caseful comparison on the local parts. */ + cmp = g->s + off; /* only now, as rebuffer likely done */ string_from_gstring(g); /* ensure nul-terminated */ if ( strcmpic(cmp, topaddr->address) == 0 && Ustrncmp(cmp, topaddr->address, Ustrchr(cmp, '@') - cmp) == 0 @@ -1062,8 +1069,7 @@ if ( (all_parents || testflag(addr, af_pfr)) && addr->parent != topaddr) { uschar *s = US" ("; - address_item *addr2; - for (addr2 = addr->parent; addr2 != topaddr; addr2 = addr2->parent) + for (address_item * addr2 = addr->parent; addr2 != topaddr; addr2 = addr2->parent) { g = string_catn(g, s, 2); g = string_cat (g, addr2->address); @@ -1086,42 +1092,6 @@ return g; -void -timesince(struct timeval * diff, struct timeval * then) -{ -gettimeofday(diff, NULL); -diff->tv_sec -= then->tv_sec; -if ((diff->tv_usec -= then->tv_usec) < 0) - { - diff->tv_sec--; - diff->tv_usec += 1000*1000; - } -} - - - -uschar * -string_timediff(struct timeval * diff) -{ -static uschar buf[sizeof("0.000s")]; - -if (diff->tv_sec >= 5 || !LOGGING(millisec)) - return readconf_printtime((int)diff->tv_sec); - -sprintf(CS buf, "%u.%03us", (uint)diff->tv_sec, (uint)diff->tv_usec/1000); -return buf; -} - - -uschar * -string_timesince(struct timeval * then) -{ -struct timeval diff; - -timesince(&diff, then); -return string_timediff(&diff); -} - /******************************************************************************/ @@ -1137,7 +1107,7 @@ void delivery_log(int flags, address_item * addr, int logchar, uschar * msg) { gstring * g; /* Used for a temporary, expanding buffer, for building log lines */ -void * reset_point; /* released afterwards. */ +rmark reset_point; /* Log the delivery on the main log. We use an extensible string to build up the log line, and reset the store afterwards. Remote deliveries should always @@ -1149,7 +1119,8 @@ pointer to a single host item in their host list, for use by the transport. */ lookup_dnssec_authenticated = NULL; #endif -g = reset_point = string_get(256); +reset_point = store_mark(); +g = string_get_tainted(256, TRUE); /* addrs will be tainted, so avoid copy */ if (msg) g = string_append(g, 2, host_and_ident(TRUE), US" "); @@ -1196,8 +1167,7 @@ if (addr->router) g = string_append(g, 2, US" T=", addr->transport->name); if (LOGGING(delivery_size)) - g = string_append(g, 2, US" S=", - string_sprintf("%d", transport_count)); + g = string_fmt_append(g, " S=%d", transport_count); /* Local delivery */ @@ -1232,7 +1202,7 @@ else #endif } -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS g = d_tlslog(g, addr); #endif @@ -1251,7 +1221,7 @@ else { if (testflag(addr, af_pipelining)) g = string_catn(g, US" L", 2); -#ifdef EXPERIMENTAL_PIPE_CONNECT +#ifdef SUPPORT_PIPE_CONNECT if (testflag(addr, af_early_pipe)) g = string_catn(g, US"*", 1); #endif @@ -1273,12 +1243,11 @@ if ( LOGGING(smtp_confirmation) && (addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0) ) { - unsigned i; unsigned lim = big_buffer_size < 1024 ? big_buffer_size : 1024; uschar *p = big_buffer; uschar *ss = addr->message; *p++ = '\"'; - for (i = 0; i < lim && ss[i] != 0; i++) /* limit logged amount */ + for (int i = 0; i < lim && ss[i] != 0; i++) /* limit logged amount */ { if (ss[i] == '\"' || ss[i] == '\\') *p++ = '\\'; /* quote \ and " */ *p++ = ss[i]; @@ -1319,14 +1288,12 @@ static void deferral_log(address_item * addr, uschar * now, int logflags, uschar * driver_name, uschar * driver_kind) { -gstring * g; -void * reset_point; +rmark reset_point = store_mark(); +gstring * g = string_get(256); /* Build up the line that is used for both the message log and the main log. */ -g = reset_point = string_get(256); - /* Create the address string for logging. Must not do this earlier, because an OK result may be changed to FAIL when a pipe returns text. */ @@ -1345,13 +1312,12 @@ if (driver_name) { if (driver_kind[1] == 't' && addr->router) g = string_append(g, 2, US" R=", addr->router->name); - g = string_cat(g, string_sprintf(" %c=%s", toupper(driver_kind[1]), driver_name)); + g = string_fmt_append(g, " %c=%s", toupper(driver_kind[1]), driver_name); } else if (driver_kind) g = string_append(g, 2, US" ", driver_kind); -/*XXX need an s+s+p sprintf */ -g = string_cat(g, string_sprintf(" defer (%d)", addr->basic_errno)); +g = string_fmt_append(g, " defer (%d)", addr->basic_errno); if (addr->basic_errno > 0) g = string_append(g, 2, US": ", @@ -1365,8 +1331,7 @@ if (addr->host_used) if (LOGGING(outgoing_port)) { int port = addr->host_used->port; - g = string_append(g, 2, - US":", port == PORT_NONE ? US"25" : string_sprintf("%d", port)); + g = string_fmt_append(g, ":%d", port == PORT_NONE ? 25 : port); } } @@ -1400,8 +1365,8 @@ return; static void failure_log(address_item * addr, uschar * driver_kind, uschar * now) { -void * reset_point; -gstring * g = reset_point = string_get(256); +rmark reset_point = store_mark(); +gstring * g = string_get(256); #ifndef DISABLE_EVENT /* Message failures for which we will send a DSN get their event raised @@ -1439,7 +1404,7 @@ if (addr->transport) if (addr->host_used) g = d_hostlog(g, addr); -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS g = d_tlslog(g, addr); #endif @@ -1639,7 +1604,7 @@ if (result == OK) } /* Certificates for logging (via events) */ -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS tls_out.ourcert = addr->ourcert; addr->ourcert = NULL; tls_out.peercert = addr->peercert; @@ -1655,7 +1620,7 @@ if (result == OK) delivery_log(LOG_MAIN, addr, logchar, NULL); -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS tls_free_cert(&tls_out.ourcert); tls_free_cert(&tls_out.peercert); tls_out.cipher = NULL; @@ -1786,22 +1751,20 @@ Returns: nothing static void common_error(BOOL logit, address_item *addr, int code, uschar *format, ...) { -address_item *addr2; addr->basic_errno = code; if (format) { va_list ap; - uschar buffer[512]; + gstring * g; + va_start(ap, format); - if (!string_vformat(buffer, sizeof(buffer), CS format, ap)) - log_write(0, LOG_MAIN|LOG_PANIC_DIE, - "common_error expansion was longer than " SIZE_T_FMT, sizeof(buffer)); + g = string_vformat(NULL, SVFMT_EXTEND|SVFMT_REBUFFER, CS format, ap); va_end(ap); - addr->message = string_copy(buffer); + addr->message = string_from_gstring(g); } -for (addr2 = addr->next; addr2; addr2 = addr2->next) +for (address_item * addr2 = addr->next; addr2; addr2 = addr2->next) { addr2->basic_errno = code; addr2->message = addr->message; @@ -1831,9 +1794,8 @@ Returns: TRUE if the uid is on the list static BOOL check_never_users(uid_t uid, uid_t *nusers) { -int i; if (!nusers) return FALSE; -for (i = 1; i <= (int)(nusers[0]); i++) if (nusers[i] == uid) return TRUE; +for (int i = 1; i <= (int)(nusers[0]); i++) if (nusers[i] == uid) return TRUE; return FALSE; } @@ -2059,10 +2021,10 @@ Returns: TRUE if previously delivered by the transport static BOOL previously_transported(address_item *addr, BOOL testing) { -(void)string_format(big_buffer, big_buffer_size, "%s/%s", +uschar * s = string_sprintf("%s/%s", addr->unique + (testflag(addr, af_homonym)? 3:0), addr->transport->name); -if (tree_search(tree_nonrecipients, big_buffer) != 0) +if (tree_search(tree_nonrecipients, s) != 0) { DEBUG(D_deliver|D_route|D_transport) debug_printf("%s was previously delivered (%s transport): discarded\n", @@ -2378,9 +2340,8 @@ if ((pid = fork()) == 0) DEBUG(D_deliver) { - address_item *batched; debug_printf(" home=%s current=%s\n", deliver_home, working_directory); - for (batched = addr->next; batched; batched = batched->next) + for (address_item * batched = addr->next; batched; batched = batched->next) debug_printf("additional batched address: %s\n", batched->address); } @@ -2582,7 +2543,7 @@ if (!shadowing) /* In the test harness, wait just a bit to let the subprocess finish off any debug output etc first. */ - if (f.running_in_test_harness) millisleep(300); + testharness_pause_ms(300); DEBUG(D_deliver) debug_printf("journalling %s", big_buffer); len = Ustrlen(big_buffer); @@ -2763,7 +2724,7 @@ while (addr_local) f.disable_logging = FALSE; /* Jic */ addr->message = addr->router ? string_sprintf("No transport set by %s router", addr->router->name) - : string_sprintf("No transport set by system filter"); + : US"No transport set by system filter"; post_process_one(addr, DEFER, logflags, EXIM_DTYPE_TRANSPORT, 0); continue; } @@ -2914,7 +2875,7 @@ while (addr_local) of these checks, rather than for all local deliveries, because some local deliveries (e.g. to pipes) can take a substantial time. */ - if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE))) + if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE))) { DEBUG(D_deliver|D_retry|D_hints_lookup) debug_printf("no retry data available\n"); @@ -3074,7 +3035,7 @@ while (addr_local) else for (addr2 = addr; addr2; addr2 = addr2->next) if (addr2->transport_return == OK) { - addr3 = store_get(sizeof(address_item)); + addr3 = store_get(sizeof(address_item), FALSE); *addr3 = *addr2; addr3->next = NULL; addr3->shadow_message = US &addr2->shadow_message; @@ -3118,12 +3079,7 @@ while (addr_local) DEBUG(D_deliver|D_transport) debug_printf("%s shadow transport returned %s for %s\n", - stp->name, - sresult == OK ? "OK" : - sresult == DEFER ? "DEFER" : - sresult == FAIL ? "FAIL" : - sresult == PANIC ? "PANIC" : "?", - shadow_addr->address); + stp->name, rc_to_string(sresult), shadow_addr->address); } DEBUG(D_deliver|D_transport) @@ -3152,12 +3108,7 @@ while (addr_local) DEBUG(D_deliver|D_transport) debug_printf("%s transport returned %s for %s\n", - tp->name, - result == OK ? "OK" : - result == DEFER ? "DEFER" : - result == FAIL ? "FAIL" : - result == PANIC ? "PANIC" : "?", - addr2->address); + tp->name, rc_to_string(result), addr2->address); /* If there is a retry_record, or if delivery is deferred, build a retry item for setting a new retry time or deleting the old retry record from @@ -3290,9 +3241,8 @@ while ( *aptr DEBUG(D_deliver) { - address_item *addr; debug_printf("remote addresses after sorting:\n"); - for (addr = addr_remote; addr; addr = addr->next) + for (address_item * addr = addr_remote; addr; addr = addr->next) debug_printf(" %s\n", addr->address); } } @@ -3483,7 +3433,7 @@ while (!done) if (!r || !(*ptr & rf_delete)) { - r = store_get(sizeof(retry_item)); + r = store_get(sizeof(retry_item), FALSE); r->next = addr->retries; addr->retries = r; r->flags = *ptr++; @@ -3524,7 +3474,7 @@ while (!done) it in with the other info, in order to keep each message short enough to guarantee it won't be split in the pipe. */ -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS case 'X': if (!addr) goto ADDR_MISMATCH; /* Below, in 'A' handler */ switch (*subid) @@ -3562,7 +3512,7 @@ while (!done) } while (*ptr++); break; -#endif /*SUPPORT_TLS*/ +#endif /*DISABLE_TLS*/ case 'C': /* client authenticator information */ switch (*subid) @@ -3583,7 +3533,7 @@ while (!done) case 'L': switch (*subid) { -#ifdef EXPERIMENTAL_PIPE_CONNECT +#ifdef SUPPORT_PIPE_CONNECT case 2: setflag(addr, af_early_pipe); /*FALLTHROUGH*/ #endif case 1: setflag(addr, af_pipelining); break; @@ -3666,7 +3616,7 @@ while (!done) if (*ptr) { - h = store_get(sizeof(host_item)); + h = store_get(sizeof(host_item), FALSE); h->name = string_copy(ptr); while (*ptr++); h->address = string_copy(ptr); @@ -3797,12 +3747,10 @@ static void remote_post_process(address_item *addr, int logflags, uschar *msg, BOOL fallback) { -host_item *h; - /* If any host addresses were found to be unusable, add them to the unusable tree so that subsequent deliveries don't try them. */ -for (h = addr->host_list; h; h = h->next) +for (host_item * h = addr->host_list; h; h = h->next) if (h->address) if (h->status >= hstatus_unusable) tree_add_unusable(h); @@ -4236,7 +4184,6 @@ static BOOL do_remote_deliveries(BOOL fallback) { int parmax; -int delivery_count; int poffset; parcount = 0; /* Number of executing subprocesses */ @@ -4253,14 +4200,14 @@ set up, do so. */ if (!parlist) { - parlist = store_get(remote_max_parallel * sizeof(pardata)); + parlist = store_get(remote_max_parallel * sizeof(pardata), FALSE); for (poffset = 0; poffset < remote_max_parallel; poffset++) parlist[poffset].pid = 0; } /* Now loop for each remote delivery */ -for (delivery_count = 0; addr_remote; delivery_count++) +for (int delivery_count = 0; addr_remote; delivery_count++) { pid_t pid; uid_t uid; @@ -4559,9 +4506,8 @@ for (delivery_count = 0; addr_remote; delivery_count++) && addr->host_list ) { - host_item * h; ok = FALSE; - for (h = addr->host_list; h; h = h->next) + for (host_item * h = addr->host_list; h; h = h->next) if (Ustrcmp(h->name, continue_hostname) == 0) /*XXX should also check port here */ { ok = TRUE; break; } @@ -4613,12 +4559,9 @@ for (delivery_count = 0; addr_remote; delivery_count++) interface to the transport. */ for (next = addr_remote; next && !f.continue_more; next = next->next) - { - host_item *h; - for (h = next->host_list; h; h = h->next) + for (host_item * h = next->host_list; h; h = h->next) if (Ustrcmp(h->name, continue_hostname) == 0) { f.continue_more = TRUE; break; } - } } /* The transports set up the process info themselves as they may connect @@ -4819,16 +4762,18 @@ all pipes, so I do not see a reason to use non-blocking IO here for(; addr; addr = addr->next) { uschar *ptr; - retry_item *r; /* The certificate verification status goes into the flags */ if (tls_out.certificate_verified) setflag(addr, af_cert_verified); #ifdef SUPPORT_DANE if (tls_out.dane_verified) setflag(addr, af_dane_verified); #endif +# ifdef EXPERIMENTAL_TLS_RESUME + if (tls_out.resumption & RESUME_USED) setflag(addr, af_tls_resume); +# endif /* Use an X item only if there's something to send */ -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS if (addr->cipher) { ptr = big_buffer + sprintf(CS big_buffer, "%.128s", addr->cipher) + 1; @@ -4849,7 +4794,7 @@ all pipes, so I do not see a reason to use non-blocking IO here if (addr->peercert) { ptr = big_buffer; - if (!tls_export_cert(ptr, big_buffer_size-2, addr->peercert)) + if (tls_export_cert(ptr, big_buffer_size-2, addr->peercert)) while(*ptr++); else *ptr++ = 0; @@ -4858,7 +4803,7 @@ all pipes, so I do not see a reason to use non-blocking IO here if (addr->ourcert) { ptr = big_buffer; - if (!tls_export_cert(ptr, big_buffer_size-2, addr->ourcert)) + if (tls_export_cert(ptr, big_buffer_size-2, addr->ourcert)) while(*ptr++); else *ptr++ = 0; @@ -4871,7 +4816,7 @@ all pipes, so I do not see a reason to use non-blocking IO here rmt_dlv_checked_write(fd, 'X', '4', big_buffer, ptr - big_buffer); } # endif -#endif /*SUPPORT_TLS*/ +#endif /*DISABLE_TLS*/ if (client_authenticator) { @@ -4895,7 +4840,7 @@ all pipes, so I do not see a reason to use non-blocking IO here #endif if (testflag(addr, af_pipelining)) -#ifdef EXPERIMENTAL_PIPE_CONNECT +#ifdef SUPPORT_PIPE_CONNECT if (testflag(addr, af_early_pipe)) rmt_dlv_checked_write(fd, 'L', '2', NULL, 0); else @@ -4916,7 +4861,7 @@ all pipes, so I do not see a reason to use non-blocking IO here /* Retry information: for most success cases this will be null. */ - for (r = addr->retries; r; r = r->next) + for (retry_item * r = addr->retries; r; r = r->next) { sprintf(CS big_buffer, "%c%.500s", r->flags, r->key); ptr = big_buffer + Ustrlen(big_buffer+2) + 3; @@ -5035,7 +4980,7 @@ all pipes, so I do not see a reason to use non-blocking IO here if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only) { -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS if (cutthrough.is_tls) tls_close(cutthrough.cctx.tls_ctx, TLS_NO_SHUTDOWN); #endif @@ -5079,9 +5024,10 @@ all pipes, so I do not see a reason to use non-blocking IO here /* Otherwise, if we are running in the test harness, wait a bit, to let the newly created process get going before we create another process. This should - ensure repeatability in the tests. We only need to wait a tad. */ + ensure repeatability in the tests. Wait long enough for most cases to complete + the transport. */ - else if (f.running_in_test_harness) millisleep(500); + else testharness_pause_ms(600); continue; @@ -5140,7 +5086,7 @@ where they are locally interpreted. [The new draft "821" is more explicit on this, Jan 1999.] We know the syntax is valid, so this can be done by simply removing quoting backslashes and any unquoted doublequotes. */ -t = addr->cc_local_part = store_get(len+1); +t = addr->cc_local_part = store_get(len+1, is_tainted(address)); while(len-- > 0) { int c = *address++; @@ -5183,7 +5129,7 @@ if (percent_hack_domains) if (new_address) { - address_item *new_parent = store_get(sizeof(address_item)); + address_item *new_parent = store_get(sizeof(address_item), FALSE); *new_parent = *addr; addr->parent = new_parent; new_parent->child_count = 1; @@ -5267,15 +5213,12 @@ static int continue_closedown(void) { if (continue_transport) - { - transport_instance *t; - for (t = transports; t; t = t->next) + for (transport_instance * t = transports; t; t = t->next) if (Ustrcmp(t->name, continue_transport) == 0) { if (t->info->closedown) (t->info->closedown)(t); break; } - } return DELIVER_NOT_ATTEMPTED; } @@ -5383,7 +5326,7 @@ static void print_address_error(address_item *addr, FILE *f, uschar *t) { int count = Ustrlen(t); -uschar *s = testflag(addr, af_pass_message)? addr->message : NULL; +uschar *s = testflag(addr, af_pass_message) ? addr->message : NULL; if (!s && !(s = addr->user_message)) return; @@ -5512,6 +5455,45 @@ while ((addr = *anchor)) +/************************************************/ + +static void +print_dsn_addr_action(FILE * f, address_item * addr, + uschar * action, uschar * status) +{ +address_item * pa; + +if (addr->dsn_orcpt) + fprintf(f,"Original-Recipient: %s\n", addr->dsn_orcpt); + +for (pa = addr; pa->parent; ) pa = pa->parent; +fprintf(f, "Action: %s\n" + "Final-Recipient: rfc822;%s\n" + "Status: %s\n", + action, pa->address, status); +} + + + +/* When running in the test harness, there's an option that allows us to +fudge this time so as to get repeatability of the tests. Take the first +time off the list. In queue runs, the list pointer gets updated in the +calling process. */ + +int +test_harness_fudged_queue_time(int actual_time) +{ +int qt; +if ( f.running_in_test_harness && *fudged_queue_times + && (qt = readconf_readtime(fudged_queue_times, '/', FALSE)) >= 0) + { + DEBUG(D_deliver) debug_printf("fudged queue_times = %s\n", + fudged_queue_times); + return qt; + } +return actual_time; +} + /************************************************* * Deliver one message * *************************************************/ @@ -5563,8 +5545,13 @@ int process_recipients = RECIP_ACCEPT; open_db dbblock; open_db *dbm_file; extern int acl_where; +uschar *info; -uschar *info = queue_run_pid == (pid_t)0 +#ifdef MEASURE_TIMING +report_time_since(×tamp_startup, US"delivery start"); /* testcase 0022, 2100 */ +#endif + +info = queue_run_pid == (pid_t)0 ? string_sprintf("delivering %s", id) : string_sprintf("delivering %s (queue run pid %d)", id, queue_run_pid); @@ -5890,9 +5877,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) ugid.uid_set = ugid.gid_set = TRUE; } else - { ugid.uid_set = ugid.gid_set = FALSE; - } return_path = sender_address; f.enable_dollar_recipients = TRUE; /* Permit $recipients in system filter */ @@ -6037,8 +6022,8 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) if (addr_new) { - int uid = (system_filter_uid_set)? system_filter_uid : geteuid(); - int gid = (system_filter_gid_set)? system_filter_gid : getegid(); + int uid = system_filter_uid_set ? system_filter_uid : geteuid(); + int gid = system_filter_gid_set ? system_filter_gid : getegid(); /* The text "system-filter" is tested in transport_set_up_command() and in set_up_shell_command() in the pipe transport, to enable them to permit @@ -6112,6 +6097,9 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) if (!tmp) p->message = string_sprintf("failed to expand \"%s\" as a " "system filter transport name", tpname); + if (is_tainted(tmp)) + p->message = string_sprintf("attempt to used tainted value '%s' for" + "transport '%s' as a system filter", tmp, tpname); tpname = tmp; } else @@ -6196,10 +6184,11 @@ if (process_recipients != RECIP_IGNORE) new->onetime_parent = recipients_list[r->pno].address; /* If DSN support is enabled, set the dsn flags and the original receipt - to be passed on to other DSN enabled MTAs */ + to be passed on to other DSN enabled MTAs */ + new->dsn_flags = r->dsn_flags & rf_dsnflags; new->dsn_orcpt = r->orcpt; - DEBUG(D_deliver) debug_printf("DSN: set orcpt: %s flags: %d\n", + DEBUG(D_deliver) debug_printf("DSN: set orcpt: %s flags: 0x%x\n", new->dsn_orcpt ? new->dsn_orcpt : US"", new->dsn_flags); switch (process_recipients) @@ -6272,7 +6261,7 @@ if (process_recipients != RECIP_IGNORE) } #ifndef DISABLE_EVENT - if (process_recipients != RECIP_ACCEPT) + if (process_recipients != RECIP_ACCEPT && event_action) { uschar * save_local = deliver_localpart; const uschar * save_domain = deliver_domain; @@ -6299,9 +6288,8 @@ if (process_recipients != RECIP_IGNORE) DEBUG(D_deliver) { - address_item *p; debug_printf("Delivery address list:\n"); - for (p = addr_new; p; p = p->next) + for (address_item * p = addr_new; p; p = p->next) debug_printf(" %s %s\n", p->address, p->onetime_parent ? p->onetime_parent : US""); } @@ -6359,7 +6347,7 @@ while (addr_new) /* Loop until all addresses dealt with */ /* Failure to open the retry database is treated the same as if it does not exist. In both cases, dbm_file is NULL. */ - if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE))) + if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE))) DEBUG(D_deliver|D_retry|D_route|D_hints_lookup) debug_printf("no retry data available\n"); @@ -6421,10 +6409,8 @@ while (addr_new) /* Loop until all addresses dealt with */ keep piling '>' characters on the front. */ if (addr->address[0] == '>') - { while (tree_search(tree_duplicates, addr->unique)) addr->unique = string_sprintf(">%s", addr->unique); - } else if ((tnode = tree_search(tree_duplicates, addr->unique))) { @@ -6615,13 +6601,21 @@ while (addr_new) /* Loop until all addresses dealt with */ if ( domain_retry_record && now - domain_retry_record->time_stamp > retry_data_expire ) + { + DEBUG(D_deliver|D_retry) + debug_printf("domain retry record present but expired\n"); domain_retry_record = NULL; /* Ignore if too old */ + } address_retry_record = dbfn_read(dbm_file, addr->address_retry_key); if ( address_retry_record && now - address_retry_record->time_stamp > retry_data_expire ) + { + DEBUG(D_deliver|D_retry) + debug_printf("address retry record present but expired\n"); address_retry_record = NULL; /* Ignore if too old */ + } if (!address_retry_record) { @@ -6630,7 +6624,11 @@ while (addr_new) /* Loop until all addresses dealt with */ address_retry_record = dbfn_read(dbm_file, altkey); if ( address_retry_record && now - address_retry_record->time_stamp > retry_data_expire) + { + DEBUG(D_deliver|D_retry) + debug_printf("address retry record present but expired\n"); address_retry_record = NULL; /* Ignore if too old */ + } } } else @@ -6639,9 +6637,18 @@ while (addr_new) /* Loop until all addresses dealt with */ DEBUG(D_deliver|D_retry) { if (!domain_retry_record) - debug_printf("no domain retry record\n"); + debug_printf("no domain retry record\n"); + else + debug_printf("have domain retry record; next_try = now%+d\n", + f.running_in_test_harness ? 0 : + (int)(domain_retry_record->next_try - now)); + if (!address_retry_record) - debug_printf("no address retry record\n"); + debug_printf("no address retry record\n"); + else + debug_printf("have address retry record; next_try = now%+d\n", + f.running_in_test_harness ? 0 : + (int)(address_retry_record->next_try - now)); } /* If we are sending a message down an existing SMTP connection, we must @@ -6663,6 +6670,9 @@ while (addr_new) /* Loop until all addresses dealt with */ addr->message = US"reusing SMTP connection skips previous routing defer"; addr->basic_errno = ERRNO_RRETRY; (void)post_process_one(addr, DEFER, LOG_MAIN, EXIM_DTYPE_ROUTER, 0); + + addr->message = domain_retry_record->text; + setflag(addr, af_pass_message); } /* If we are in a queue run, defer routing unless there is no retry data or @@ -6716,6 +6726,16 @@ while (addr_new) /* Loop until all addresses dealt with */ addr->message = US"retry time not reached"; addr->basic_errno = ERRNO_RRETRY; (void)post_process_one(addr, DEFER, LOG_MAIN, EXIM_DTYPE_ROUTER, 0); + + /* For remote-retry errors (here and just above) that we've not yet + hit the retry time, use the error recorded in the retry database + as info in the warning message. This lets us send a message even + when we're not failing on a fresh attempt. We assume that this + info is not sensitive. */ + + addr->message = domain_retry_record + ? domain_retry_record->text : address_retry_record->text; + setflag(addr, af_pass_message); } /* The domain is OK for routing. Remember if retry data exists so it @@ -6798,8 +6818,8 @@ while (addr_new) /* Loop until all addresses dealt with */ &addr_succeed, v_none)) == DEFER) retry_add_item(addr, addr->router->retry_use_local_part - ? string_sprintf("R:%s@%s", addr->local_part, addr->domain) - : string_sprintf("R:%s", addr->domain), + ? string_sprintf("R:%s@%s", addr->local_part, addr->domain) + : string_sprintf("R:%s", addr->domain), 0); /* Otherwise, if there is an existing retry record in the database, add @@ -6911,22 +6931,21 @@ while (addr_new) /* Loop until all addresses dealt with */ DEBUG(D_deliver|D_retry|D_route) { - address_item *p; debug_printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); debug_printf("After routing:\n Local deliveries:\n"); - for (p = addr_local; p; p = p->next) + for (address_item * p = addr_local; p; p = p->next) debug_printf(" %s\n", p->address); debug_printf(" Remote deliveries:\n"); - for (p = addr_remote; p; p = p->next) + for (address_item * p = addr_remote; p; p = p->next) debug_printf(" %s\n", p->address); debug_printf(" Failed addresses:\n"); - for (p = addr_failed; p; p = p->next) + for (address_item * p = addr_failed; p; p = p->next) debug_printf(" %s\n", p->address); debug_printf(" Deferred addresses:\n"); - for (p = addr_defer; p; p = p->next) + for (address_item * p = addr_defer; p; p = p->next) debug_printf(" %s\n", p->address); } @@ -7046,7 +7065,7 @@ if ( f.header_rewritten } -/* If there are any deliveries to be and we do not already have the journal +/* If there are any deliveries to do and we do not already have the journal file, create it. This is used to record successful deliveries as soon as possible after each delivery is known to be complete. A file opened with O_APPEND is used so that several processes can run simultaneously. @@ -7077,7 +7096,7 @@ if (addr_local || addr_remote) that the mode is correct - the group setting doesn't always seem to get set automatically. */ - if( fchown(journal_fd, exim_uid, exim_gid) + if( exim_fchown(journal_fd, exim_uid, exim_gid, fname) || fchmod(journal_fd, SPOOL_MODE) #ifndef O_CLOEXEC || fcntl(journal_fd, F_SETFD, fcntl(journal_fd, F_GETFD) | FD_CLOEXEC) @@ -7208,8 +7227,8 @@ if (mua_wrapper) { if (addr_defer) { - address_item *addr, *nextaddr; - for (addr = addr_defer; addr; addr = nextaddr) + address_item * nextaddr; + for (address_item * addr = addr_defer; addr; addr = nextaddr) { log_write(0, LOG_MAIN, "** %s mua_wrapper forced failure for deferred " "delivery", addr->address); @@ -7265,38 +7284,37 @@ else if (!f.dont_deliver) /* Send DSN for successful messages if requested */ addr_senddsn = NULL; -for (addr_dsntmp = addr_succeed; addr_dsntmp; addr_dsntmp = addr_dsntmp->next) +for (address_item * a = addr_succeed; a; a = a->next) { /* af_ignore_error not honored here. it's not an error */ DEBUG(D_deliver) debug_printf("DSN: processing router : %s\n" "DSN: processing successful delivery address: %s\n" "DSN: Sender_address: %s\n" - "DSN: orcpt: %s flags: %d\n" + "DSN: orcpt: %s flags: 0x%x\n" "DSN: envid: %s ret: %d\n" "DSN: Final recipient: %s\n" "DSN: Remote SMTP server supports DSN: %d\n", - addr_dsntmp->router ? addr_dsntmp->router->name : US"(unknown)", - addr_dsntmp->address, + a->router ? a->router->name : US"(unknown)", + a->address, sender_address, - addr_dsntmp->dsn_orcpt ? addr_dsntmp->dsn_orcpt : US"NULL", - addr_dsntmp->dsn_flags, + a->dsn_orcpt ? a->dsn_orcpt : US"NULL", + a->dsn_flags, dsn_envid ? dsn_envid : US"NULL", dsn_ret, - addr_dsntmp->address, - addr_dsntmp->dsn_aware + a->address, + a->dsn_aware ); /* send report if next hop not DSN aware or a router flagged "last DSN hop" - and a report was requested */ - if ( ( addr_dsntmp->dsn_aware != dsn_support_yes - || addr_dsntmp->dsn_flags & rf_dsnlasthop - ) - && addr_dsntmp->dsn_flags & rf_notify_success + and a report was requested */ + + if ( (a->dsn_aware != dsn_support_yes || a->dsn_flags & rf_dsnlasthop) + && a->dsn_flags & rf_notify_success ) { /* copy and relink address_item and send report with all of them at once later */ address_item * addr_next = addr_senddsn; - addr_senddsn = store_get(sizeof(address_item)); - *addr_senddsn = *addr_dsntmp; + addr_senddsn = store_get(sizeof(address_item), FALSE); + *addr_senddsn = *a; addr_senddsn->next = addr_next; } else @@ -7316,7 +7334,7 @@ if (addr_senddsn) if (pid < 0) /* Creation of child failed */ { log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Process %d (parent %d) failed to " - "create child process to send failure message: %s", getpid(), + "create child process to send success-dsn message: %s", getpid(), getppid(), strerror(errno)); DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n"); @@ -7329,7 +7347,7 @@ if (addr_senddsn) transport_ctx tctx = {{0}}; DEBUG(D_deliver) - debug_printf("sending error message to: %s\n", sender_address); + debug_printf("sending success-dsn to: %s\n", sender_address); /* build unique id for MIME boundary */ bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand()); @@ -7338,11 +7356,14 @@ if (addr_senddsn) if (errors_reply_to) fprintf(f, "Reply-To: %s\n", errors_reply_to); + moan_write_from(f); fprintf(f, "Auto-Submitted: auto-generated\n" - "From: Mail Delivery System \n" "To: %s\n" - "Subject: Delivery Status Notification\n" - "Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n" + "Subject: Delivery Status Notification\n", + sender_address); + moan_write_references(f, NULL); + fprintf(f, "Content-Type: multipart/report;" + " report-type=delivery-status; boundary=%s\n" "MIME-Version: 1.0\n\n" "--%s\n" @@ -7350,14 +7371,13 @@ if (addr_senddsn) "This message was created automatically by mail delivery software.\n" " ----- The following addresses had successful delivery notifications -----\n", - qualify_domain_sender, sender_address, bound, bound); + bound, bound); - for (addr_dsntmp = addr_senddsn; addr_dsntmp; - addr_dsntmp = addr_dsntmp->next) + for (address_item * a = addr_senddsn; a; a = a->next) fprintf(f, "<%s> (relayed %s)\n\n", - addr_dsntmp->address, - addr_dsntmp->dsn_flags & rf_dsnlasthop ? "via non DSN router" - : addr_dsntmp->dsn_aware == dsn_support_no ? "to non-DSN-aware mailer" + a->address, + a->dsn_flags & rf_dsnlasthop ? "via non DSN router" + : a->dsn_aware == dsn_support_no ? "to non-DSN-aware mailer" : "via non \"Remote SMTP\" router" ); @@ -7376,24 +7396,18 @@ if (addr_senddsn) } fputc('\n', f); - for (addr_dsntmp = addr_senddsn; - addr_dsntmp; - addr_dsntmp = addr_dsntmp->next) + for (address_item * a = addr_senddsn; a; a = a->next) { - if (addr_dsntmp->dsn_orcpt) - fprintf(f,"Original-Recipient: %s\n", addr_dsntmp->dsn_orcpt); + host_item * hu; - fprintf(f, "Action: delivered\n" - "Final-Recipient: rfc822;%s\n" - "Status: 2.0.0\n", - addr_dsntmp->address); + print_dsn_addr_action(f, a, US"delivered", US"2.0.0"); - if (addr_dsntmp->host_used && addr_dsntmp->host_used->name) + if ((hu = a->host_used) && hu->name) fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n\n", - addr_dsntmp->host_used->name); + hu->name); else fprintf(f, "Diagnostic-Code: X-Exim; relayed via non %s router\n\n", - addr_dsntmp->dsn_flags & rf_dsnlasthop ? "DSN" : "SMTP"); + a->dsn_flags & rf_dsnlasthop ? "DSN" : "SMTP"); } fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", bound); @@ -7406,7 +7420,7 @@ if (addr_senddsn) tctx.u.fd = fd; tctx.options = topt_add_return_path | topt_no_body; - /*XXX hmm, retval ignored. + /*XXX hmm, FALSE(fail) retval ignored. Could error for any number of reasons, and they are not handled. */ transport_write_message(&tctx, 0); fflush(f); @@ -7476,7 +7490,8 @@ while (addr_failed) mark the recipient done. */ if ( addr_failed->prop.ignore_error - || addr_failed->dsn_flags & (rf_dsnflags & ~rf_notify_failure) + || addr_failed->dsn_flags & rf_dsnflags + && !(addr_failed->dsn_flags & rf_notify_failure) ) { addr = addr_failed; @@ -7486,11 +7501,13 @@ while (addr_failed) #ifndef DISABLE_EVENT msg_event_raise(US"msg:fail:delivery", addr); #endif - log_write(0, LOG_MAIN, "%s%s%s%s: error ignored", + log_write(0, LOG_MAIN, "%s%s%s%s: error ignored%s", addr->address, !addr->parent ? US"" : US" <", !addr->parent ? US"" : addr->parent->address, - !addr->parent ? US"" : US">"); + !addr->parent ? US"" : US">", + addr->prop.ignore_error + ? US"" : US": RFC 3461 DSN, failure notify not requested"); address_done(addr, logtod); child_done(addr, logtod); @@ -7583,6 +7600,7 @@ while (addr_failed) fprintf(fp, "Auto-Submitted: auto-replied\n"); moan_write_from(fp); fprintf(fp, "To: %s\n", bounce_recipient); + moan_write_references(fp, NULL); /* generate boundary string and output MIME-Headers */ bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand()); @@ -7771,10 +7789,9 @@ wording. */ for (addr = handled_addr; addr; addr = addr->next) { host_item * hu; - fprintf(fp, "Action: failed\n" - "Final-Recipient: rfc822;%s\n" - "Status: 5.0.0\n", - addr->address); + + print_dsn_addr_action(fp, addr, US"failed", US"5.0.0"); + if ((hu = addr->host_used) && hu->name) { fprintf(fp, "Remote-MTA: dns; %s\n", hu->name); @@ -7894,7 +7911,7 @@ wording. */ /* In the test harness, let the child do it's thing first. */ - if (f.running_in_test_harness) millisleep(500); + testharness_pause_ms(500); /* If the process failed, there was some disaster in setting up the error message. Unless the message is very old, ensure that addr_defer @@ -8017,6 +8034,8 @@ the parent's domain. If all the deferred addresses have an error number that indicates "retry time not reached", skip sending the warning message, because it won't contain the reason for the delay. It will get sent at the next real delivery attempt. + Exception: for retries caused by a remote peer we use the error message + store in the retry DB as the reason. However, if at least one address has tried, we'd better include all of them in the message. @@ -8034,18 +8053,17 @@ was set just to keep the message on the spool, so there is nothing to do here. else if (addr_defer != (address_item *)(+1)) { - address_item *addr; uschar *recipients = US""; - BOOL delivery_attempted = FALSE; + BOOL want_warning_msg = FALSE; deliver_domain = testflag(addr_defer, af_pfr) ? addr_defer->parent->domain : addr_defer->domain; - for (addr = addr_defer; addr; addr = addr->next) + for (address_item * addr = addr_defer; addr; addr = addr->next) { address_item *otaddr; - if (addr->basic_errno > ERRNO_RETRY_BASE) delivery_attempted = TRUE; + if (addr->basic_errno > ERRNO_WARN_BASE) want_warning_msg = TRUE; if (deliver_domain) { @@ -8117,7 +8135,7 @@ else if (addr_defer != (address_item *)(+1)) it also defers). */ if ( !f.queue_2stage - && delivery_attempted + && want_warning_msg && ( !(addr_defer->dsn_flags & rf_dsnflags) || addr_defer->dsn_flags & rf_notify_delay ) @@ -8133,21 +8151,7 @@ else if (addr_defer != (address_item *)(+1)) int show_time; int queue_time = time(NULL) - received_time.tv_sec; - /* When running in the test harness, there's an option that allows us to - fudge this time so as to get repeatability of the tests. Take the first - time off the list. In queue runs, the list pointer gets updated in the - calling process. */ - - if (f.running_in_test_harness && fudged_queue_times[0] != 0) - { - int qt = readconf_readtime(fudged_queue_times, '/', FALSE); - if (qt >= 0) - { - DEBUG(D_deliver) debug_printf("fudged queue_times = %s\n", - fudged_queue_times); - queue_time = qt; - } - } + queue_time = test_harness_fudged_queue_time(queue_time); /* See how many warnings we should have sent by now */ @@ -8168,7 +8172,8 @@ else if (addr_defer != (address_item *)(+1)) DEBUG(D_deliver) { - debug_printf("time on queue = %s\n", readconf_printtime(queue_time)); + debug_printf("time on queue = %s id %s addr %s\n", + readconf_printtime(queue_time), message_id, addr_defer->address); debug_printf("warning counts: required %d done %d\n", count, warning_count); } @@ -8206,6 +8211,7 @@ else if (addr_defer != (address_item *)(+1)) fprintf(f, "Auto-Submitted: auto-replied\n"); moan_write_from(f); fprintf(f, "To: %s\n", recipients); + moan_write_references(f, NULL); /* generated boundary string and output MIME-Headers */ bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand()); @@ -8263,13 +8269,9 @@ else if (addr_defer != (address_item *)(+1)) /* List the addresses, with error information if allowed */ - /* store addr_defer for machine readable part */ - address_item *addr_dsndefer = addr_defer; fputc('\n', f); - while (addr_defer) + for (address_item * addr = addr_defer; addr; addr = addr->next) { - address_item *addr = addr_defer; - addr_defer = addr->next; if (print_address_information(addr, f, US" ", US"\n ", US"")) print_address_error(addr, f, US"Delay reason: "); fputc('\n', f); @@ -8312,20 +8314,16 @@ else if (addr_defer != (address_item *)(+1)) } fputc('\n', f); - for ( ; addr_dsndefer; addr_dsndefer = addr_dsndefer->next) + for (address_item * addr = addr_defer; addr; addr = addr->next) { - if (addr_dsndefer->dsn_orcpt) - fprintf(f, "Original-Recipient: %s\n", addr_dsndefer->dsn_orcpt); - - fprintf(f, "Action: delayed\n" - "Final-Recipient: rfc822;%s\n" - "Status: 4.0.0\n", - addr_dsndefer->address); - if (addr_dsndefer->host_used && addr_dsndefer->host_used->name) + host_item * hu; + + print_dsn_addr_action(f, addr, US"delayed", US"4.0.0"); + + if ((hu = addr->host_used) && hu->name) { - fprintf(f, "Remote-MTA: dns; %s\n", - addr_dsndefer->host_used->name); - print_dsn_diagnostic_code(addr_dsndefer, f); + fprintf(f, "Remote-MTA: dns; %s\n", hu->name); + print_dsn_diagnostic_code(addr, f); } fputc('\n', f); } @@ -8475,6 +8473,9 @@ to try delivery. */ (void)close(deliver_datafile); deliver_datafile = -1; DEBUG(D_deliver) debug_printf("end delivery of %s\n", id); +#ifdef MEASURE_TIMING +report_time_since(×tamp_startup, US"delivery end"); /* testcase 0005 */ +#endif /* It is unlikely that there will be any cached resources, since they are released after routing, and in the delivery subprocesses. However, it's @@ -8508,14 +8509,9 @@ if (!regex_SIZE) regex_SIZE = if (!regex_AUTH) regex_AUTH = regex_must_compile(AUTHS_REGEX, FALSE, TRUE); -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS if (!regex_STARTTLS) regex_STARTTLS = regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE); - -# ifdef EXPERIMENTAL_REQUIRETLS -if (!regex_REQUIRETLS) regex_REQUIRETLS = - regex_must_compile(US"\\n250[\\s\\-]REQUIRETLS(\\s|\\n|$)", FALSE, TRUE); -# endif #endif if (!regex_CHUNKING) regex_CHUNKING = @@ -8537,7 +8533,7 @@ if (!regex_DSN) regex_DSN = if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA = regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE); -#ifdef EXPERIMENTAL_PIPE_CONNECT +#ifdef SUPPORT_PIPE_CONNECT if (!regex_EARLY_PIPE) regex_EARLY_PIPE = regex_must_compile(US"\\n250[\\s\\-]" EARLY_PIPE_FEATURE_NAME "(\\s|\\n|$)", FALSE, TRUE); #endif @@ -8603,7 +8599,7 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only) smtp_peer_options = cutthrough.peer_options; continue_sequence = 0; -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS if (cutthrough.is_tls) { int pfd[2], pid; @@ -8622,7 +8618,7 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only) else if (pid == 0) /* child: fork again to totally disconnect */ { - if (f.running_in_test_harness) millisleep(100); /* let parent debug out */ + testharness_pause_ms(100); /* let parent debug out */ /* does not return */ smtp_proxy_tls(cutthrough.cctx.tls_ctx, big_buffer, big_buffer_size, pfd, 5*60); @@ -8646,7 +8642,7 @@ else } return; /* compiler quietening; control does not reach here. */ -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS fail: log_write(0, LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE),