X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/dd19ce4f24eec64177cdcfcf294b8efbb631a24b..a85c067ba6c6940512cf57ec213277a370d87e70:/src/src/deliver.c diff --git a/src/src/deliver.c b/src/src/deliver.c index 8aad811c6..719fa9d93 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -2,9 +2,10 @@ * Exim - an Internet mail transport agent * *************************************************/ +/* Copyright (c) The Exim Maintainers 2020 - 2022 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ -/* Copyright (c) The Exim Maintainers 2020 - 2021 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* The main code for delivering a message. */ @@ -146,7 +147,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), FALSE); +address_item * addr = store_get(sizeof(address_item), GET_UNTAINTED); *addr = address_defaults; if (copy) address = string_copy(address); addr->address = address; @@ -854,8 +855,18 @@ return g; #ifndef DISABLE_EVENT +/* Distribute a named event to any listeners. + +Args: action config option specifying listener + event name of the event + ev_data associated data for the event + errnop pointer to errno for modification, or null + +Return: string expansion from listener, or NULL +*/ + uschar * -event_raise(uschar * action, const uschar * event, uschar * ev_data) +event_raise(uschar * action, const uschar * event, uschar * ev_data, int * errnop) { uschar * s; if (action) @@ -882,7 +893,8 @@ if (action) { DEBUG(D_deliver) debug_printf("Event(%s): event_action returned \"%s\"\n", event, s); - errno = ERRNO_EVENT; + if (errnop) + *errnop = ERRNO_EVENT; return s; } } @@ -911,7 +923,7 @@ if (!addr->transport) a filter was used which triggered a fail command (in such a case a transport isn't needed). Convert it to an internal fail event. */ - (void) event_raise(event_action, US"msg:fail:internal", addr->message); + (void) event_raise(event_action, US"msg:fail:internal", addr->message, NULL); } } else @@ -923,7 +935,8 @@ else || Ustrcmp(addr->transport->driver_name, "smtp") == 0 || Ustrcmp(addr->transport->driver_name, "lmtp") == 0 || Ustrcmp(addr->transport->driver_name, "autoreply") == 0 - ? addr->message : NULL); + ? addr->message : NULL, + NULL); } deliver_host_port = save_port; @@ -941,9 +954,22 @@ router_name = transport_name = NULL; /************************************************* -* Generate local prt for logging * +* Generate local part for logging * *************************************************/ +static uschar * +string_get_lpart_sub(const address_item * addr, uschar * s) +{ +#ifdef SUPPORT_I18N +if (testflag(addr, af_utf8_downcvt)) + { + uschar * t = string_localpart_utf8_to_alabel(s, NULL); + return t ? t : s; /* t is NULL on a failed conversion */ + } +#endif +return s; +} + /* This function is a subroutine for use in string_log_address() below. Arguments: @@ -958,32 +984,13 @@ string_get_localpart(address_item * addr, gstring * yield) { uschar * s; -s = addr->prefix; -if (testflag(addr, af_include_affixes) && s) - { -#ifdef SUPPORT_I18N - if (testflag(addr, af_utf8_downcvt)) - s = string_localpart_utf8_to_alabel(s, NULL); -#endif - yield = string_cat(yield, s); - } +if (testflag(addr, af_include_affixes) && (s = addr->prefix)) + yield = string_cat(yield, string_get_lpart_sub(addr, s)); -s = addr->local_part; -#ifdef SUPPORT_I18N -if (testflag(addr, af_utf8_downcvt)) - s = string_localpart_utf8_to_alabel(s, NULL); -#endif -yield = string_cat(yield, s); +yield = string_cat(yield, string_get_lpart_sub(addr, addr->local_part)); -s = addr->suffix; -if (testflag(addr, af_include_affixes) && s) - { -#ifdef SUPPORT_I18N - if (testflag(addr, af_utf8_downcvt)) - s = string_localpart_utf8_to_alabel(s, NULL); -#endif - yield = string_cat(yield, s); - } +if (testflag(addr, af_include_affixes) && (s = addr->suffix)) + yield = string_cat(yield, string_get_lpart_sub(addr, s)); return yield; } @@ -1136,7 +1143,7 @@ pointer to a single host item in their host list, for use by the transport. */ #endif reset_point = store_mark(); -g = string_get_tainted(256, TRUE); /* addrs will be tainted, so avoid copy */ +g = string_get_tainted(256, GET_TAINTED); /* addrs will be tainted, so avoid copy */ if (msg) g = string_append(g, 2, host_and_ident(TRUE), US" "); @@ -1160,11 +1167,6 @@ if (LOGGING(sender_on_delivery) || msg) if (*queue_name) g = string_append(g, 2, US" Q=", queue_name); -#ifdef EXPERIMENTAL_SRS_ALT -if(addr->prop.srs_sender) - g = string_append(g, 3, US" SRS=<", addr->prop.srs_sender, US">"); -#endif - /* You might think that the return path must always be set for a successful delivery; indeed, I did for some time, until this statement crashed. The case when it is not set is for a delivery to /dev/null which is optimised by not @@ -2148,10 +2150,6 @@ has its own return path setting, expand it and replace the existing value. */ if(addr->prop.errors_address) return_path = addr->prop.errors_address; -#ifdef EXPERIMENTAL_SRS_ALT -else if (addr->prop.srs_sender) - return_path = addr->prop.srs_sender; -#endif else return_path = sender_address; @@ -2373,27 +2371,29 @@ if ((pid = exim_fork(US"delivery-local")) == 0) { BOOL ok = TRUE; set_process_info("delivering %s to %s using %s", message_id, - addr->local_part, addr->transport->name); + addr->local_part, tp->name); - /* Setting this global in the subprocess means we need never clear it */ + /* Setting these globals in the subprocess means we need never clear them */ transport_name = addr->transport->name; + driver_srcfile = tp->srcfile; + driver_srcline = tp->srcline; /* If a transport filter has been specified, set up its argument list. Any errors will get put into the address, and FALSE yielded. */ - if (addr->transport->filter_command) + if (tp->filter_command) { ok = transport_set_up_command(&transport_filter_argv, - addr->transport->filter_command, - TRUE, PANIC, addr, US"transport filter", NULL); - transport_filter_timeout = addr->transport->filter_timeout; + tp->filter_command, + TRUE, PANIC, addr, FALSE, US"transport filter", NULL); + transport_filter_timeout = tp->filter_timeout; } else transport_filter_argv = NULL; if (ok) { - debug_print_string(addr->transport->debug_string); - replicate = !(addr->transport->info->code)(addr->transport, addr); + debug_print_string(tp->debug_string); + replicate = !(tp->info->code)(addr->transport, addr); } } @@ -2413,13 +2413,13 @@ if ((pid = exim_fork(US"delivery-local")) == 0) uschar *s; int ret; - if( (ret = write(pfd[pipe_write], &addr2->transport_return, sizeof(int))) != sizeof(int) + if( (i = addr2->transport_return, (ret = write(pfd[pipe_write], &i, sizeof(int))) != sizeof(int)) || (ret = write(pfd[pipe_write], &transport_count, sizeof(transport_count))) != sizeof(transport_count) || (ret = write(pfd[pipe_write], &addr2->flags, sizeof(addr2->flags))) != sizeof(addr2->flags) || (ret = write(pfd[pipe_write], &addr2->basic_errno, sizeof(int))) != sizeof(int) || (ret = write(pfd[pipe_write], &addr2->more_errno, sizeof(int))) != sizeof(int) || (ret = write(pfd[pipe_write], &addr2->delivery_time, sizeof(struct timeval))) != sizeof(struct timeval) - || (ret = write(pfd[pipe_write], &addr2->special_action, sizeof(int))) != sizeof(int) + || (i = addr2->special_action, (ret = write(pfd[pipe_write], &i, sizeof(int))) != sizeof(int)) || (ret = write(pfd[pipe_write], &addr2->transport, sizeof(transport_instance *))) != sizeof(transport_instance *) @@ -2487,7 +2487,7 @@ for (addr2 = addr; addr2; addr2 = addr2->next) len = read(pfd[pipe_read], &addr2->basic_errno, sizeof(int)); len = read(pfd[pipe_read], &addr2->more_errno, sizeof(int)); len = read(pfd[pipe_read], &addr2->delivery_time, sizeof(struct timeval)); - len = read(pfd[pipe_read], &addr2->special_action, sizeof(int)); + len = read(pfd[pipe_read], &i, sizeof(int)); addr2->special_action = i; len = read(pfd[pipe_read], &addr2->transport, sizeof(transport_instance *)); @@ -3046,7 +3046,7 @@ while (addr_local) else for (addr2 = addr; addr2; addr2 = addr2->next) if (addr2->transport_return == OK) { - addr3 = store_get(sizeof(address_item), FALSE); + addr3 = store_get(sizeof(address_item), GET_UNTAINTED); *addr3 = *addr2; addr3->next = NULL; addr3->shadow_message = US &addr2->shadow_message; @@ -3441,7 +3441,7 @@ while (!done) if (!r || !(*ptr & rf_delete)) { - r = store_get(sizeof(retry_item), FALSE); + r = store_get(sizeof(retry_item), GET_UNTAINTED); r->next = addr->retries; addr->retries = r; r->flags = *ptr++; @@ -3632,7 +3632,7 @@ while (!done) if (*ptr) { - h = store_get(sizeof(host_item), FALSE); + h = store_get(sizeof(host_item), GET_UNTAINTED); h->name = string_copy(ptr); while (*ptr++); h->address = string_copy(ptr); @@ -4210,10 +4210,10 @@ set up, do so. */ if (!parlist) { - parlist = store_get(remote_max_parallel * sizeof(pardata), FALSE); + parlist = store_get(remote_max_parallel * sizeof(pardata), GET_UNTAINTED); for (poffset = 0; poffset < remote_max_parallel; poffset++) parlist[poffset].pid = 0; - parpoll = store_get(remote_max_parallel * sizeof(struct pollfd), FALSE); + parpoll = store_get(remote_max_parallel * sizeof(struct pollfd), GET_UNTAINTED); } /* Now loop for each remote delivery */ @@ -4441,10 +4441,6 @@ nonmatch domains if(addr->prop.errors_address) return_path = addr->prop.errors_address; -#ifdef EXPERIMENTAL_SRS_ALT - else if(addr->prop.srs_sender) - return_path = addr->prop.srs_sender; -#endif else return_path = sender_address; @@ -4665,8 +4661,10 @@ all pipes, so I do not see a reason to use non-blocking IO here int fd = pfd[pipe_write]; host_item *h; - /* Setting this global in the subprocess means we need never clear it */ - transport_name = tp->name; + /* Setting these globals in the subprocess means we need never clear them */ + transport_name = addr->transport->name; + driver_srcfile = tp->srcfile; + driver_srcline = tp->srcline; /* There are weird circumstances in which logging is disabled */ f.disable_logging = tp->disable_logging; @@ -5112,7 +5110,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, is_tainted(address)); +t = addr->cc_local_part = store_get(len+1, address); while(len-- > 0) { int c = *address++; @@ -5155,7 +5153,7 @@ if (percent_hack_domains) if (new_address) { - address_item *new_parent = store_get(sizeof(address_item), FALSE); + address_item * new_parent = store_get(sizeof(address_item), GET_UNTAINTED); *new_parent = *addr; addr->parent = new_parent; new_parent->child_count = 1; @@ -5349,10 +5347,10 @@ Returns: nothing */ static void -print_address_error(address_item *addr, FILE *f, uschar *t) +print_address_error(address_item * addr, FILE * f, const 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; @@ -5546,11 +5544,10 @@ FILE * fp = NULL; if (!s || !*s) log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand %s: '%s'\n", varname, filename); -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 (*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 (!(fp = Ufopen(s, "rb"))) log_write(0, LOG_MAIN|LOG_PANIC, "Failed to open %s for %s " "message texts: %s", s, reason, strerror(errno)); @@ -5893,7 +5890,7 @@ if (message_logs) return continue_closedown(); /* yields DELIVER_NOT_ATTEMPTED */ } - /* Make a C stream out of it. */ + /* Make a stdio stream out of it. */ if (!(message_log = fdopen(fd, "a"))) { @@ -6160,10 +6157,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); - { uschar *m; - if ((m = is_tainted2(tmp, 0, "Tainted values '%s' " "for transport '%s' as a system filter", tmp, tpname))) - p->message = m; - } + 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 @@ -6341,7 +6337,7 @@ if (process_recipients != RECIP_IGNORE) string_copyn(addr+start, dom ? (dom-1) - start : end - start); deliver_domain = dom ? CUS string_copyn(addr+dom, end - dom) : CUS""; - event_raise(event_action, US"msg:fail:internal", new->message); + (void) event_raise(event_action, US"msg:fail:internal", new->message, NULL); deliver_localpart = save_local; deliver_domain = save_domain; @@ -6421,10 +6417,8 @@ while (addr_new) /* Loop until all addresses dealt with */ while (addr_new) { int rc; - uschar *p; - tree_node *tnode; - dbdata_retry *domain_retry_record; - dbdata_retry *address_retry_record; + tree_node * tnode; + dbdata_retry * domain_retry_record, * address_retry_record; addr = addr_new; addr_new = addr->next; @@ -6557,7 +6551,7 @@ while (addr_new) /* Loop until all addresses dealt with */ if (Ustrcmp(addr->address, "/dev/null") == 0) { transport_instance * save_t = addr->transport; - transport_instance * t = store_get(sizeof(*t), is_tainted(save_t)); + transport_instance * t = store_get(sizeof(*t), save_t); *t = *save_t; t->name = US"**bypassed**"; addr->transport = t; @@ -6641,8 +6635,7 @@ while (addr_new) /* Loop until all addresses dealt with */ /* Ensure that the domain in the unique field is lower cased, because domains are always handled caselessly. */ - p = Ustrrchr(addr->unique, '@'); - while (*p != 0) { *p = tolower(*p); p++; } + for (uschar * p = Ustrrchr(addr->unique, '@'); *p; p++) *p = tolower(*p); DEBUG(D_deliver|D_route) debug_printf("unique = %s\n", addr->unique); @@ -7211,7 +7204,7 @@ local and remote LMTP deliveries. */ if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA = - regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE); + regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", MCS_NOFLAGS, TRUE); /* Handle local deliveries */ @@ -7392,7 +7385,7 @@ for (address_item * a = addr_succeed; a; a = a->next) { /* 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), FALSE); + addr_senddsn = store_get(sizeof(address_item), GET_UNTAINTED); *addr_senddsn = *a; addr_senddsn->next = addr_next; } @@ -8092,7 +8085,7 @@ if (!addr_defer) f.deliver_freeze = FALSE; #ifndef DISABLE_EVENT - (void) event_raise(event_action, US"msg:complete", NULL); + (void) event_raise(event_action, US"msg:complete", NULL, NULL); #endif } @@ -8611,7 +8604,7 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only) if (pid == 0) /* child: will fork again to totally disconnect */ { smtp_proxy_tls(cutthrough.cctx.tls_ctx, big_buffer, big_buffer_size, - pfd, 5*60); + pfd, 5*60, cutthrough.host.name); /* does not return */ }