X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/b6054898ace169a0e5143117397a4f666a5e7283..0a3c9b00e50a4bd4a7cfca5c9640d8f3c7333cd3:/src/src/deliver.c diff --git a/src/src/deliver.c b/src/src/deliver.c index 9c4c1a746..4594c4a1d 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -3,7 +3,7 @@ *************************************************/ /* Copyright (c) University of Cambridge 1995 - 2018 */ -/* Copyright (c) The Exim Maintainers 2020 */ +/* Copyright (c) The Exim Maintainers 2020 - 2021 */ /* See the file NOTICE for conditions of use and distribution. */ /* The main code for delivering a message. */ @@ -334,7 +334,7 @@ static int open_msglog_file(uschar *filename, int mode, uschar **error) { if (Ustrstr(filename, US"/../")) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Attempt to open msglog file path with upward-traversal: '%s'\n", filename); for (int i = 2; i > 0; i--) @@ -521,8 +521,12 @@ while (one && two) else if (one->port != two->port) return FALSE; - /* Hosts matched */ +#ifdef SUPPORT_DANE + /* DNSSEC equality */ + if (one->dnssec != two->dnssec) return FALSE; +#endif + /* Hosts matched */ one = one->next; two = two->next; } @@ -792,6 +796,9 @@ g = string_append(g, 3, US" [", h->address, US"]"); if (LOGGING(outgoing_port)) g = string_fmt_append(g, ":%d", h->port); +if (continue_sequence > 1) /*XXX this is wrong for a dropped proxyconn. Would have to pass back from transport */ + g = string_catn(g, US"*", 1); + #ifdef SUPPORT_SOCKS if (LOGGING(proxy) && proxy_local_address) { @@ -1195,8 +1202,6 @@ else if (addr->host_used) { g = d_hostlog(g, addr); - if (continue_sequence > 1) /*XXX this is wrong for a dropped proxyconn. Would have to pass back from transport */ - g = string_catn(g, US"*", 1); #ifndef DISABLE_EVENT deliver_host_address = addr->host_used->address; @@ -1268,8 +1273,8 @@ if ( LOGGING(smtp_confirmation) /* Time on queue and actual time taken to deliver */ if (LOGGING(queue_time)) - g = string_append(g, 2, US" QT=", - string_timesince(&received_time)); + g = string_append(g, 2, US" QT=", string_timesince( + LOGGING(queue_time_exclusive) ? &received_time_complete : &received_time)); if (LOGGING(deliver_time)) g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time)); @@ -1325,20 +1330,10 @@ else if (driver_kind) g = string_fmt_append(g, " defer (%d)", addr->basic_errno); if (addr->basic_errno > 0) - g = string_append(g, 2, US": ", - US strerror(addr->basic_errno)); + g = string_append(g, 2, US": ", US strerror(addr->basic_errno)); if (addr->host_used) - { - g = string_append(g, 5, - US" H=", addr->host_used->name, - US" [", addr->host_used->address, US"]"); - if (LOGGING(outgoing_port)) - { - int port = addr->host_used->port; - g = string_fmt_append(g, ":%d", port == PORT_NONE ? 25 : port); - } - } + g = d_hostlog(g, addr); if (LOGGING(deliver_time)) g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time)); @@ -1589,6 +1584,12 @@ if (addr->return_file >= 0 && addr->return_filename) (void)close(addr->return_file); } +/* Check if the transport notifed continue-conn status explicitly, and +update our knowlege. */ + +if (testflag(addr, af_new_conn)) continue_sequence = 1; +else if (testflag(addr, af_cont_conn)) continue_sequence++; + /* The success case happens only after delivery by a transport. */ if (result == OK) @@ -2096,9 +2097,9 @@ return FALSE; /* Each local delivery is performed in a separate process which sets its uid and gid as specified. This is a safer way than simply changing and -restoring using seteuid(); there is a body of opinion that seteuid() cannot be -used safely. From release 4, Exim no longer makes any use of it. Besides, not -all systems have seteuid(). +restoring using seteuid(); there is a body of opinion that seteuid() +cannot be used safely. From release 4, Exim no longer makes any use of +it for delivery. Besides, not all systems have seteuid(). If the uid/gid are specified in the transport_instance, they are used; the transport initialization must ensure that either both or neither are set. @@ -2887,10 +2888,8 @@ while (addr_local) deliveries (e.g. to pipes) can take a substantial time. */ 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"); - } addr2 = addr; addr3 = NULL; @@ -3194,6 +3193,7 @@ const uschar *listptr = remote_sort_domains; uschar *pattern; uschar patbuf[256]; +/*XXX The list is used before expansion. Not sure how that ties up with the docs */ while ( *aptr && (pattern = string_nextinlist(&listptr, &sep, patbuf, sizeof(patbuf))) ) @@ -3579,7 +3579,13 @@ while (!done) switch (*subid) { - #ifdef SUPPORT_SOCKS + case 3: /* explicit notification of continued-connection (non)use; + overrides caller's knowlege. */ + if (*ptr & BIT(1)) setflag(addr, af_new_conn); + else if (*ptr & BIT(2)) setflag(addr, af_cont_conn); + break; + +#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) @@ -3592,9 +3598,9 @@ while (!done) ptr += sizeof(proxy_local_port); } break; - #endif +#endif - #ifdef EXPERIMENTAL_DSN_INFO +#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); @@ -3602,7 +3608,7 @@ while (!done) addr->helo_response = string_copy(ptr); while(*ptr++); break; - #endif +#endif case '0': DEBUG(D_deliver) debug_printf("A0 %s tret %d\n", addr->address, *ptr); @@ -4893,6 +4899,14 @@ all pipes, so I do not see a reason to use non-blocking IO here rmt_dlv_checked_write(fd, 'R', '0', big_buffer, ptr - big_buffer); } + if (testflag(addr, af_new_conn) || testflag(addr, af_cont_conn)) + { + DEBUG(D_deliver) debug_printf("%scontinued-connection\n", + testflag(addr, af_new_conn) ? "non-" : ""); + big_buffer[0] = testflag(addr, af_new_conn) ? BIT(1) : BIT(2); + rmt_dlv_checked_write(fd, 'A', '3', big_buffer, 1); + } + #ifdef SUPPORT_SOCKS if (LOGGING(proxy) && proxy_session) { @@ -5536,10 +5550,11 @@ FILE * fp = NULL; if (!s || !*s) log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand %s: '%s'\n", varname, filename); -else if (*s != '/' || is_tainted(s)) - log_write(0, LOG_MAIN|LOG_PANIC, - "%s is not %s after expansion: '%s'\n", - varname, *s == '/' ? "untainted" : "absolute", s); +else if (*s != '/') + log_write(0, LOG_MAIN|LOG_PANIC, "%s is not absolute after expansion: '%s'\n", + varname, s); +else if (is_tainted2(s, LOG_MAIN|LOG_PANIC, "Tainted %s after expansion: '%s'\n", varname, s)) + ; else if (!(fp = Ufopen(s, "rb"))) log_write(0, LOG_MAIN|LOG_PANIC, "Failed to open %s for %s " "message texts: %s", s, reason, strerror(errno)); @@ -6149,9 +6164,10 @@ 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); + { uschar *m; + if ((m = is_tainted2(tmp, 0, "Tainted values '%s' " "for transport '%s' as a system filter", tmp, tpname))) + p->message = m; + } tpname = tmp; } else @@ -6538,14 +6554,19 @@ while (addr_new) /* Loop until all addresses dealt with */ /* Treat /dev/null as a special case and abandon the delivery. This avoids having to specify a uid on the transport just for this case. - Arrange for the transport name to be logged as "**bypassed**". */ + Arrange for the transport name to be logged as "**bypassed**". + Copy the transport for this fairly unusual case rather than having + to make all transports mutable. */ if (Ustrcmp(addr->address, "/dev/null") == 0) { - uschar *save = addr->transport->name; - addr->transport->name = US"**bypassed**"; + transport_instance * save_t = addr->transport; + transport_instance * t = store_get(sizeof(*t), is_tainted(save_t)); + *t = *save_t; + t->name = US"**bypassed**"; + addr->transport = t; (void)post_process_one(addr, OK, LOG_MAIN, EXIM_DTYPE_TRANSPORT, '='); - addr->transport->name = save; + addr->transport= save_t; continue; /* with the next new address */ } @@ -6822,7 +6843,7 @@ while (addr_new) /* Loop until all addresses dealt with */ addr_route = addr->next; deliver_domain = addr->domain; /* set $domain */ - if ((rc = match_isinlist(addr->domain, (const uschar **)&queue_domains, 0, + if ((rc = match_isinlist(addr->domain, CUSS &queue_domains, 0, &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL)) != OK) if (rc == DEFER) @@ -7077,13 +7098,23 @@ if ( mua_wrapper /* If this is a run to continue deliveries to an external channel that is -already set up, defer any local deliveries. */ +already set up, defer any local deliveries. -if (continue_transport) +jgh 2020/12/20: I don't see why; locals should be quick. +The defer goes back to version 1.62 in 1997. A local being still deliverable +during a continued run might result from something like a defer during the +original delivery, eg. in a DB lookup. Unlikely but possible. + +To avoid delaying a local when combined with a callout-hold for a remote +delivery, test continue_sequence rather than continue_transport. */ + +if (continue_sequence > 1 && addr_local) { + DEBUG(D_deliver|D_retry|D_route) + debug_printf("deferring local deliveries due to continued-transport\n"); if (addr_defer) { - address_item *addr = addr_defer; + address_item * addr = addr_defer; while (addr->next) addr = addr->next; addr->next = addr_local; } @@ -8414,7 +8445,7 @@ else if (addr_defer != (address_item *)(+1)) /* If this was a first delivery attempt, unset the first time flag, and ensure that the spool gets updated. */ - if (f.deliver_firsttime) + if (f.deliver_firsttime && !f.queue_2stage) { f.deliver_firsttime = FALSE; update_spool = TRUE; @@ -8547,52 +8578,9 @@ f.tcp_fastopen_ok = TRUE; } -uschar * -deliver_get_sender_address (uschar * id) -{ -int rc; -uschar * new_sender_address, - * save_sender_address; -BOOL save_qr = f.queue_running; -uschar * spoolname; - -/* make spool_open_datafile non-noisy on fail */ - -f.queue_running = TRUE; - -/* Side effect: message_subdir is set for the (possibly split) spool directory */ - -deliver_datafile = spool_open_datafile(id); -f.queue_running = save_qr; -if (deliver_datafile < 0) - return NULL; - -/* Save and restore the global sender_address. I'm not sure if we should -not save/restore all the other global variables too, because -spool_read_header() may change all of them. But OTOH, when this -deliver_get_sender_address() gets called, the current message is done -already and nobody needs the globals anymore. (HS12, 2015-08-21) */ - -spoolname = string_sprintf("%s-H", id); -save_sender_address = sender_address; - -rc = spool_read_header(spoolname, TRUE, TRUE); - -new_sender_address = sender_address; -sender_address = save_sender_address; - -if (rc != spool_read_OK) - return NULL; - -assert(new_sender_address); - -(void)close(deliver_datafile); -deliver_datafile = -1; - -return new_sender_address; -} - +/* Called from a commandline, or from the daemon, to do a delivery. +We need to regain privs; do this by exec of the exim binary. */ void delivery_re_exec(int exec_type)