X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/4687a69c269ee3f2a7f0625e0147a503fd9d3d0b..600dc06981df5a906125f8442c36056a117412d4:/src/src/transports/smtp.c diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index ed5994241..172ee3445 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) The Exim Maintainers 2020 - 2023 */ +/* Copyright (c) The Exim Maintainers 2020 - 2024 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* SPDX-License-Identifier: GPL-2.0-or-later */ @@ -668,12 +668,15 @@ deferred_event_raise(address_item * addr, host_item * host, uschar * evstr) { uschar * action = addr->transport->event_action; const uschar * save_domain, * save_local; +uschar * save_rn, * save_tn; if (!action) return; save_domain = deliver_domain; save_local = deliver_localpart; +save_rn = router_name; +save_tn = transport_name; /*XXX would ip & port already be set up? */ deliver_host_address = string_copy(host->address); @@ -697,7 +700,8 @@ deliver_localpart = addr->local_part; deliver_localpart = save_local; deliver_domain = save_domain; -router_name = transport_name = NULL; +router_name = save_rn; +router_name = save_tn; } #endif @@ -945,7 +949,8 @@ if ( sx->early_pipe_active if (!(er = dbfn_read_enforce_length(dbm_file, ehlo_resp_key, sizeof(dbdata_ehlo_resp)))) debug_printf("no ehlo-resp record!\n"); else - debug_printf("ehlo-resp record is %d seconds old\n", time(NULL) - er->time_stamp); + debug_printf("ehlo-resp record is %.0f seconds old\n", + difftime(time(NULL), er->time_stamp)); } dbfn_delete(dbm_file, ehlo_resp_key); @@ -1086,7 +1091,7 @@ if (pending_BANNER) } /*XXX EXPERIMENTAL_ESMTP_LIMITS ? */ -# ifndef DISABLE_TLS_RESUME +# if !defined(DISABLE_TLS) && !defined(DISABLE_TLS_RESUME) GET_OPTION("host_name_extract"); s = ((smtp_transport_options_block *)sx->conn_args.ob)->host_name_extract; if (!s) s = HNE_DEFAULT; @@ -1306,7 +1311,7 @@ while (count-- > 0) if (testflag(addr, af_dr_retry_exists)) { - uschar *altkey = string_sprintf("%s:<%s>", addr->address_retry_key, + uschar * altkey = string_sprintf("%s:<%s>", addr->address_retry_key, sender_address); retry_add_item(addr, altkey, rf_delete); retry_add_item(addr, addr->address_retry_key, rf_delete); @@ -1322,7 +1327,7 @@ while (count-- > 0) else if (errno == ETIMEDOUT) { - uschar *message = string_sprintf("SMTP timeout after RCPT TO:<%s>", + uschar * message = string_sprintf("SMTP timeout after RCPT TO:<%s>", transport_rcpt_address(addr, sx->conn_args.tblock->rcpt_include_affixes)); set_errno_nohost(sx->first_addr, ETIMEDOUT, message, DEFER, FALSE, &sx->delivery_start); retry_add_item(addr, addr->address_retry_key, 0); @@ -2630,7 +2635,7 @@ goto SEND_QUIT; } } #endif -#ifndef DISABLE_TLS_RESUME +#if !defined(DISABLE_TLS) && !defined(DISABLE_TLS_RESUME) GET_OPTION("host_name_extract"); if (!(s = ob->host_name_extract)) s = HNE_DEFAULT; ehlo_response_lbserver(sx, s); @@ -3425,7 +3430,7 @@ if (sx->peer_offered & OPTION_DSN && !(addr->dsn_flags & rf_dsnlasthop)) /* Send MAIL FROM and RCPT TO commands. See sw_mrc_t definition for return codes. - */ +*/ sw_mrc_t smtp_write_mail_and_rcpt_cmds(smtp_context * sx, int * yield) @@ -3795,7 +3800,6 @@ int save_errno; int rc; uschar *message = NULL; -uschar new_message_id[MESSAGE_ID_LENGTH + 1]; smtp_context * sx = store_get(sizeof(*sx), GET_TAINTED); /* tainted, for the data buffers */ BOOL pass_message = FALSE; #ifndef DISABLE_ESMTP_LIMITS @@ -3804,9 +3808,10 @@ BOOL mail_limit = FALSE; #ifdef SUPPORT_DANE BOOL dane_held; #endif -BOOL tcw_done = FALSE, tcw = FALSE; +BOOL tcw_done = FALSE, tcw = FALSE, passback_tcw = FALSE; *message_defer = FALSE; +continue_next_id[0] = '\0'; memset(sx, 0, sizeof(*sx)); sx->addrlist = addrlist; @@ -4127,7 +4132,7 @@ else && #endif transport_check_waiting(tblock->name, host->name, - tblock->connection_max_messages, new_message_id, + tblock->connection_max_messages, continue_next_id, (oicf)smtp_are_same_identities, (void*)&t_compare); if (!tcw) { @@ -4687,6 +4692,11 @@ if (sx->completed_addr && sx->ok && sx->send_quit) { DEBUG(D_transport) debug_printf("reached limit %u for MAILs per conn\n", sx->max_mail); + /* We will close the smtp session and connection, and clear + continue_hostname. Then if there are further addrs for the message we will + loop to the top of this function and make a fresh connection. Any further + message found in the wait-tpt hintsdb would then do a transport_pass_socket + to get the connection fd back to the delivery process. */ } else #endif @@ -4694,9 +4704,9 @@ if (sx->completed_addr && sx->ok && sx->send_quit) smtp_compare_t t_compare = {.tblock = tblock, .current_sender_address = sender_address}; - if ( sx->first_addr /* more addrs for this message */ - || f.continue_more /* more addrs for continued-host */ - || tcw_done && tcw /* more messages for host */ + if ( sx->first_addr /* more addrs for this message */ + || f.continue_more /* more addrs for continued-host */ + || tcw_done && tcw /* more messages for host */ || ( #ifndef DISABLE_TLS ( tls_out.active.sock < 0 && !continue_proxy_cipher @@ -4705,7 +4715,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit) && #endif transport_check_waiting(tblock->name, host->name, - sx->max_mail, new_message_id, + sx->max_mail, continue_next_id, (oicf)smtp_are_same_identities, (void*)&t_compare) ) ) { @@ -4756,6 +4766,20 @@ if (sx->completed_addr && sx->ok && sx->send_quit) goto SEND_MESSAGE; } + /* If there is a next-message-id from the wait-transport hintsdb, + pretend caller said it has further message for us. Note that we lose + the TLS session (below), and that our caller will pass back the id to + the delivery process. If not, remember to later cancel the + next-message-id so that the transport-caller code (in deliver.c) does + not report it back up the pipe to the delivery process. + XXX It would be feasible to also report the other continue_* with the + _id - taking out the exec for the first continued-transport. But the + actual conn, and it's fd, is a problem. Maybe replace the transport + pipe with a unix-domain socket? */ + + if (!f.continue_more && continue_hostname && *continue_next_id) + f.continue_more = passback_tcw = TRUE; + /* Unless caller said it already has more messages listed for this host, pass the connection on to a new Exim process (below, the call to transport_pass_socket). If the caller has more ready, just return with @@ -4817,7 +4841,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit) propagate it from the initial */ if (sx->ok && transport_pass_socket(tblock->name, host->name, - host->address, new_message_id, socket_fd + host->address, continue_next_id, socket_fd #ifndef DISABLE_ESMTP_LIMITS , sx->peer_limit_mail, sx->peer_limit_rcpt, sx->peer_limit_rcptdom #endif @@ -4850,8 +4874,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit) sx->cctx.tls_ctx = NULL; (void)close(sx->cctx.sock); sx->cctx.sock = -1; - continue_transport = NULL; - continue_hostname = NULL; + continue_transport = continue_hostname = NULL; goto TIDYUP; } log_write(0, LOG_PANIC_DIE, "fork failed"); @@ -4963,7 +4986,6 @@ if (sx->send_quit || tcw_done && !tcw) HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n"); (void)close(sx->cctx.sock); sx->cctx.sock = -1; -continue_transport = NULL; continue_hostname = NULL; smtp_debug_cmd_report(); @@ -5005,19 +5027,21 @@ if (mail_limit && sx->first_addr) continue_sequence = 1; /* for consistency */ clearflag(sx->first_addr, af_cont_conn); setflag(sx->first_addr, af_new_conn); /* clear * from logging */ - goto REPEAT_CONN; + goto REPEAT_CONN; /* open a fresh connection */ } #endif -return yield; +OUT: + if (!passback_tcw) continue_next_id[0] = '\0'; + return yield; TIDYUP: #ifdef SUPPORT_DANE -if (dane_held) for (address_item * a = sx->addrlist->next; a; a = a->next) - if (a->transport_return == DANE) - a->transport_return = PENDING_DEFER; + if (dane_held) for (address_item * a = sx->addrlist->next; a; a = a->next) + if (a->transport_return == DANE) + a->transport_return = PENDING_DEFER; #endif -return yield; + goto OUT; } @@ -5376,7 +5400,7 @@ retry_non_continued: BOOL host_is_expired = FALSE, message_defer = FALSE, some_deferred = FALSE; address_item * first_addr = NULL; uschar * interface = NULL; - uschar * retry_host_key = NULL, * retry_message_key = NULL; + const uschar * retry_host_key = NULL, * retry_message_key = NULL; uschar * serialize_key = NULL; /* Deal slightly better with a possible Linux kernel bug that results @@ -5873,9 +5897,7 @@ retry_non_continued: ob->expand_retry_include_ip_address, &incl_ip) != OK) incl_ip = TRUE; /* error; use most-specific retry record */ - retry_host_key = incl_ip - ? string_sprintf("T:%S:%s%s", host->name, host->address, pistring) - : string_sprintf("T:%S%s", host->name, pistring); + retry_host_key = retry_host_key_build(host, incl_ip, pistring); } /* If a delivery of another message over an existing SMTP connection @@ -5921,10 +5943,8 @@ retry_non_continued: ob->expand_retry_include_ip_address, &incl_ip) != OK) incl_ip = TRUE; /* error; use most-specific retry record */ - retry_message_key = incl_ip - ? string_sprintf("T:%S:%s%s:%s", host->name, host->address, pistring, - message_id) - : string_sprintf("T:%S%s:%s", host->name, pistring, message_id); + retry_message_key = string_sprintf("%s:%s", + retry_host_key_build(host, incl_ip, pistring), message_id); } retry_add_item(addrlist, retry_message_key, rf_message | rf_host | delete_flag);