X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/e851856fc72bf126f7b649a007fb7040140d5d3c..99350dede64ad634300ddf15d0d97a81fd75d330:/src/src/transports/smtp.c diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 6559d4170..447f76a9b 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -3,6 +3,7 @@ *************************************************/ /* Copyright (c) University of Cambridge 1995 - 2018 */ +/* Copyright (c) The Exim Maintainers 2020 */ /* See the file NOTICE for conditions of use and distribution. */ #include "../exim.h" @@ -110,6 +111,7 @@ optionlist smtp_transport_options[] = { { "lmtp_ignore_quota", opt_bool, LOFF(lmtp_ignore_quota) }, { "max_rcpt", opt_int | opt_public, OPT_OFF(transport_instance, max_addresses) }, + { "message_linelength_limit", opt_int, LOFF(message_linelength_limit) }, { "multi_domain", opt_expand_bool | opt_public, OPT_OFF(transport_instance, multi_domain) }, { "port", opt_stringptr, LOFF(port) }, @@ -126,7 +128,7 @@ optionlist smtp_transport_options[] = { { "tls_dh_min_bits", opt_int, LOFF(tls_dh_min_bits) }, { "tls_privatekey", opt_stringptr, LOFF(tls_privatekey) }, { "tls_require_ciphers", opt_stringptr, LOFF(tls_require_ciphers) }, -# ifdef EXPERIMENTAL_TLS_RESUME +# ifndef DISABLE_TLS_RESUME { "tls_resumption_hosts", opt_stringptr, LOFF(tls_resumption_hosts) }, # endif { "tls_sni", opt_stringptr, LOFF(tls_sni) }, @@ -206,6 +208,7 @@ smtp_transport_options_block smtp_transport_option_defaults = { .size_addition = 1024, .hosts_max_try = 5, .hosts_max_try_hardlimit = 50, + .message_linelength_limit = 998, .address_retry_include_sender = TRUE, .allow_localhost = FALSE, .authenticated_sender_force = FALSE, @@ -232,7 +235,7 @@ smtp_transport_options_block smtp_transport_option_defaults = { .tls_verify_certificates = US"system", .tls_dh_min_bits = EXIM_CLIENT_DH_DEFAULT_MIN_BITS, .tls_tempfail_tryclear = TRUE, -# ifdef EXPERIMENTAL_TLS_RESUME +# ifndef DISABLE_TLS_RESUME .tls_resumption_hosts = NULL, # endif .tls_verify_hosts = NULL, @@ -240,7 +243,7 @@ smtp_transport_options_block smtp_transport_option_defaults = { .tls_verify_cert_hostnames = US"*", #endif #ifdef SUPPORT_I18N - .utf8_downconvert = NULL, + .utf8_downconvert = US"-1", #endif #ifndef DISABLE_DKIM .dkim = @@ -361,10 +364,6 @@ smtp_transport_setup(transport_instance *tblock, address_item *addrlist, { smtp_transport_options_block *ob = SOB tblock->options_block; -errmsg = errmsg; /* Keep picky compilers happy */ -uid = uid; -gid = gid; - /* Pass back options if required. This interface is getting very messy. */ if (tf) @@ -911,11 +910,9 @@ names = string_copyn(expand_nstring[1], expand_nlength[1]); for (au = auths, authnum = 0; au; au = au->next, authnum++) if (au->client) { const uschar * list = names; - int sep = ' '; - uschar name[32]; - - while (string_nextinlist(&list, &sep, name, sizeof(name))) - if (strcmpic(au->public_name, name) == 0) + uschar * s; + for (int sep = ' '; s = string_nextinlist(&list, &sep, NULL, 0); ) + if (strcmpic(au->public_name, s) == 0) { authbits |= BIT(authnum); break; } } @@ -1550,6 +1547,7 @@ if ( sx->esmtp if (require_auth == OK && !f.smtp_authenticated) { + invalidate_ehlo_cache_entry(sx); set_errno_nohost(sx->addrlist, ERRNO_AUTHFAIL, string_sprintf("authentication required but %s", fail_reason), DEFER, FALSE, &sx->delivery_start); @@ -1685,7 +1683,7 @@ current_local_identity = smtp_local_identity(s_compare->current_sender_address, s_compare->tblock); if (!(new_sender_address = deliver_get_sender_address(message_id))) - return 0; + return FALSE; message_local_identity = smtp_local_identity(new_sender_address, s_compare->tblock); @@ -1970,7 +1968,7 @@ tls_out.peerdn = NULL; tls_out.sni = NULL; #endif tls_out.ocsp = OCSP_NOT_REQ; -#ifdef EXPERIMENTAL_TLS_RESUME +#ifndef DISABLE_TLS_RESUME tls_out.resumption = 0; #endif tls_out.ver = NULL; @@ -2019,10 +2017,12 @@ if (!continue_hostname) switch (rc = tlsa_lookup(sx->conn_args.host, &sx->conn_args.tlsa_dnsa, sx->dane_required)) { case OK: sx->conn_args.dane = TRUE; - ob->tls_tempfail_tryclear = FALSE; + ob->tls_tempfail_tryclear = FALSE; /* force TLS */ + ob->tls_sni = sx->first_addr->domain; /* force SNI */ break; case FAIL_FORCED: break; - default: set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER, + default: + set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER, string_sprintf("DANE error: tlsa lookup %s", rc_to_string(rc)), rc, FALSE, &sx->delivery_start); @@ -2079,6 +2079,7 @@ if (!continue_hostname) else DEBUG(D_transport) debug_printf("helo needs $sending_ip_address\n"); +PIPE_CONNECT_RETRY: if (sx->early_pipe_active) sx->outblock.conn_args = &sx->conn_args; else @@ -2377,6 +2378,7 @@ else } sx->inblock.cctx = sx->outblock.cctx = &sx->cctx; smtp_command = big_buffer; + sx->peer_offered = smtp_peer_options; sx->helo_data = NULL; /* ensure we re-expand ob->helo_data */ /* For a continued connection with TLS being proxied for us, or a @@ -2387,7 +2389,6 @@ else && cutthrough.is_tls) ) { - sx->peer_offered = smtp_peer_options; sx->pipelining_used = pipelining_active = !!(smtp_peer_options & OPTION_PIPE); HDEBUG(D_transport) debug_printf("continued connection, %s TLS\n", continue_proxy_cipher ? "proxied" : "verify conn with"); @@ -2425,7 +2426,10 @@ if ( smtp_peer_options & OPTION_TLS { HDEBUG(D_transport) debug_printf("failed reaping pipelined cmd responses\n"); - goto RESPONSE_FAILED; + close(sx->cctx.sock); + sx->cctx.sock = -1; + sx->early_pipe_active = FALSE; + goto PIPE_CONNECT_RETRY; } #endif @@ -2459,9 +2463,7 @@ if ( smtp_peer_options & OPTION_TLS /* TLS negotiation failed; give an error. From outside, this function may be called again to try in clear on a new connection, if the options permit it for this host. */ -#ifdef USE_GNUTLS - GNUTLS_CONN_FAILED: -#endif + TLS_CONN_FAILED: DEBUG(D_tls) debug_printf("TLS session fail: %s\n", tls_errstr); # ifdef SUPPORT_DANE @@ -2483,7 +2485,23 @@ if ( smtp_peer_options & OPTION_TLS goto TLS_FAILED; } - /* TLS session is set up */ + /* TLS session is set up. Check the inblock fill level. If there is + content then as we have not yet done a tls read it must have arrived before + the TLS handshake, in-clear. That violates the sync requirement of the + STARTTLS RFC, so fail. */ + + if (sx->inblock.ptr != sx->inblock.ptrend) + { + DEBUG(D_tls) + { + int i = sx->inblock.ptrend - sx->inblock.ptr; + debug_printf("unused data in input buffer after ack for STARTTLS:\n" + "'%.*s'%s\n", + i > 100 ? 100 : i, sx->inblock.ptr, i > 100 ? "..." : ""); + } + tls_errstr = US"synch error before connect"; + goto TLS_CONN_FAILED; + } smtp_peer_options_wrap = smtp_peer_options; for (address_item * addr = sx->addrlist; addr; addr = addr->next) @@ -2588,7 +2606,7 @@ if (tls_out.active.sock >= 0) Can it do that, with all the flexibility we need? */ tls_errstr = US"error on first read"; - goto GNUTLS_CONN_FAILED; + goto TLS_CONN_FAILED; } #else goto RESPONSE_FAILED; @@ -3280,13 +3298,9 @@ int max_fd = MAX(pfd[0], tls_out.active.sock) + 1; int rc, i; close(pfd[1]); -if ((rc = fork())) - { - DEBUG(D_transport) debug_printf("proxy-proc final-pid %d\n", rc); +if ((rc = exim_fork(US"tls-proxy"))) _exit(rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS); - } -testharness_pause_ms(100); /* let parent debug out */ set_process_info("proxying TLS connection for continued transport"); FD_ZERO(&rfds); FD_SET(tls_out.active.sock, &rfds); @@ -3361,7 +3375,7 @@ for (int fd_bits = 3; fd_bits; ) done: testharness_pause_ms(100); /* let logging complete */ - exim_exit(0, US"TLS proxy"); + exim_exit(EXIT_SUCCESS); } #endif @@ -3372,8 +3386,9 @@ done: /* If continue_hostname is not null, we get here only when continuing to deliver down an existing channel. The channel was passed as the standard -input. TLS is never active on a passed channel; the previous process always -closes it down before passing the connection on. +input. TLS is never active on a passed channel; the previous process either +closes it down before passing the connection on, or inserts a TLS-proxy +process and passes on a cleartext conection. Otherwise, we have to make a connection to the remote host, and do the initial protocol exchange. @@ -3428,8 +3443,8 @@ BOOL pass_message = FALSE; uschar *message = NULL; uschar new_message_id[MESSAGE_ID_LENGTH + 1]; smtp_context * sx = store_get(sizeof(*sx), TRUE); /* tainted, for the data buffers */ +BOOL dane_held; -suppress_tls = suppress_tls; /* stop compiler warning when no TLS support */ *message_defer = FALSE; memset(sx, 0, sizeof(*sx)); @@ -3444,17 +3459,40 @@ sx->conn_args.tblock = tblock; gettimeofday(&sx->delivery_start, NULL); sx->sync_addr = sx->first_addr = addrlist; -/* Get the channel set up ready for a message (MAIL FROM being the next -SMTP command to send */ +DANE_DOMAINS: +dane_held = FALSE; + +/* Get the channel set up ready for a message, MAIL FROM being the next +SMTP command to send. */ if ((rc = smtp_setup_conn(sx, suppress_tls)) != OK) { timesince(&addrlist->delivery_time, &sx->delivery_start); - return rc; + yield = rc; + goto TIDYUP; + } + +/*XXX*/ +/* If the connection used DANE, ignore for now any addresses with incompatible +domains. The SNI has to be the domain. Arrange a whole new TCP conn later, +just in case only TLS isn't enough. */ + +if (sx->conn_args.dane) + { + const uschar * dane_domain = sx->first_addr->domain; + + for (address_item * a = sx->first_addr->next; a; a = a->next) + if ( a->transport_return == PENDING_DEFER + && Ustrcmp(dane_domain, a->domain) != 0) + { + DEBUG(D_transport) debug_printf("DANE: holding %s for later\n", a->domain); + dane_held = TRUE; + a->transport_return = DANE; + } } /* If there is a filter command specified for this transport, we can now -set it up. This cannot be done until the identify of the host is known. */ +set it up. This cannot be done until the identity of the host is known. */ if (tblock->filter_command) { @@ -3512,7 +3550,6 @@ always has a sequence number greater than one. */ if (continue_hostname && continue_sequence == 1) { - sx->peer_offered = smtp_peer_options; /* sx->pending_MAIL = FALSE; */ sx->ok = TRUE; /* sx->next_addr = NULL; */ @@ -4148,7 +4185,6 @@ DEBUG(D_transport) if (sx->completed_addr && sx->ok && sx->send_quit) { - BOOL more; smtp_compare_t t_compare; t_compare.tblock = tblock; @@ -4164,7 +4200,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit) && #endif transport_check_waiting(tblock->name, host->name, - tblock->connection_max_messages, new_message_id, &more, + tblock->connection_max_messages, new_message_id, (oicf)smtp_are_same_identities, (void*)&t_compare) ) ) { @@ -4202,7 +4238,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit) if (sx->first_addr != NULL) /* More addresses still to be sent */ - { /* in this run of the transport */ + { /* on this connection */ continue_sequence++; /* Causes * in logging */ pipelining_active = sx->pipelining_used; /* was cleared at DATA */ goto SEND_MESSAGE; @@ -4217,6 +4253,10 @@ if (sx->completed_addr && sx->ok && sx->send_quit) if (tls_out.active.sock >= 0) if ( f.continue_more || verify_check_given_host(CUSS &ob->hosts_noproxy_tls, host) == OK) + +/*XXX*/ +/* || sx->conn_args.dane && Ustrcmp( , ob->tls_sni) != 0 */ +/*XXX*/ { /* Before passing the socket on, or returning to caller with it still open, we must shut down TLS. Not all MTAs allow for the continuation @@ -4234,7 +4274,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit) '2', ob->command_timeout); if (sx->ok && f.continue_more) - return yield; /* More addresses for another run */ + goto TIDYUP; /* More addresses for another run */ } else { @@ -4254,7 +4294,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit) else #endif if (f.continue_more) - return yield; /* More addresses for another run */ + goto TIDYUP; /* More addresses for another run */ /* If the socket is successfully passed, we mustn't send QUIT (or indeed anything!) from here. */ @@ -4275,10 +4315,9 @@ propagate it from the initial #ifndef DISABLE_TLS if (tls_out.active.sock >= 0) { - int pid = fork(); + int pid = exim_fork(US"tls-proxy-interproc"); if (pid == 0) /* child; fork again to disconnect totally */ { - testharness_pause_ms(100); /* let parent debug out */ /* does not return */ smtp_proxy_tls(sx->cctx.tls_ctx, sx->buffer, sizeof(sx->buffer), pfd, ob->command_timeout); @@ -4286,7 +4325,6 @@ propagate it from the initial if (pid > 0) /* parent */ { - DEBUG(D_transport) debug_printf("proxy-proc inter-pid %d\n", pid); close(pfd[0]); /* tidy the inter-proc to disconn the proxy proc */ waitpid(pid, NULL, 0); @@ -4296,7 +4334,7 @@ propagate it from the initial sx->cctx.sock = -1; continue_transport = NULL; continue_hostname = NULL; - return yield; + goto TIDYUP; } log_write(0, LOG_PANIC_DIE, "fork failed"); } @@ -4371,9 +4409,35 @@ if (sx->send_quit) (void) event_raise(tblock->event_action, US"tcp:close", NULL); #endif +/*XXX*/ +if (dane_held) + { + sx->first_addr = NULL; + for (address_item * a = sx->addrlist->next; a; a = a->next) + if (a->transport_return == DANE) + { + a->transport_return = PENDING_DEFER; + if (!sx->first_addr) + { + /* Remember the new start-point in the addrlist, for smtp_setup_conn() + to get the domain string for SNI */ + + sx->first_addr = a; + DEBUG(D_transport) debug_printf("DANE: go-around for %s\n", a->domain); + } + } + goto DANE_DOMAINS; + } + continue_transport = NULL; continue_hostname = NULL; return yield; + +TIDYUP: +if (dane_held) for (address_item * a = sx->addrlist->next; a; a = a->next) + if (a->transport_return == DANE) + a->transport_return = PENDING_DEFER; +return yield; } @@ -4526,6 +4590,22 @@ DEBUG(D_transport) cutthrough.cctx.sock >= 0 ? cutthrough.cctx.sock : 0); } +/* Check the restrictions on line length */ + +if (max_received_linelength > ob->message_linelength_limit) + { + struct timeval now; + gettimeofday(&now, NULL); + + for (address_item * addr = addrlist; addr; addr = addr->next) + if (addr->transport_return == DEFER) + addr->transport_return = PENDING_DEFER; + + set_errno_nohost(addrlist, ERRNO_SMTPFORMAT, + US"message has lines too long for transport", FAIL, TRUE, &now); + goto END_TRANSPORT; + } + /* Set the flag requesting that these hosts be added to the waiting database if the delivery fails temporarily or if we are running with queue_smtp or a 2-stage queue run. This gets unset for certain @@ -4873,10 +4953,12 @@ retry_non_continued: &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) == OK) ) { + DEBUG(D_transport) debug_printf("first-pass routing only\n"); expired = FALSE; for (address_item * addr = addrlist; addr; addr = addr->next) if (addr->transport_return == DEFER) - addr->message = US"domain matches queue_smtp_domains, or -odqs set"; + addr->message = US"first-pass only routing due to -odqs, " + "queue_smtp_domains or control=queue"; continue; /* With next host */ } @@ -5164,7 +5246,12 @@ retry_non_continued: #ifndef DISABLE_EVENT /* If the last host gave a defer raise a per-message event */ - if (!nexthost && (message_defer || rc == DEFER)) + if ( !( nexthost + && unexpired_hosts_tried < ob->hosts_max_try + && total_hosts_tried < ob->hosts_max_try_hardlimit + ) + && (message_defer || rc == DEFER) + ) deferred_event_raise(first_addr, host, US"msg:defer"); #endif }