X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/27a79307f48631bbefe9abb6f399da0e8e4b46d1..74f1a42304ce056cf979d22fb970faae161e3ab2:/src/src/transports/smtp.c diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 2dfb5b73a..1f0256f3d 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -63,6 +63,8 @@ optionlist smtp_transport_options[] = { (void *)offsetof(smtp_transport_options_block, dkim.dkim_sign_headers) }, { "dkim_strict", opt_stringptr, (void *)offsetof(smtp_transport_options_block, dkim.dkim_strict) }, + { "dkim_timestamps", opt_stringptr, + (void *)offsetof(smtp_transport_options_block, dkim.dkim_timestamps) }, #endif { "dns_qualify_single", opt_bool, (void *)offsetof(smtp_transport_options_block, dns_qualify_single) }, @@ -295,6 +297,7 @@ smtp_transport_options_block smtp_transport_option_defaults = { .dkim_sign_headers = NULL, .dkim_strict = NULL, .dkim_hash = US"sha256", + .dkim_timestamps = NULL, .dot_stuffed = FALSE, .force_bodyhash = FALSE, # ifdef EXPERIMENTAL_ARC @@ -1643,11 +1646,13 @@ if (!continue_hostname) /* Make the TCP connection */ - sx->inblock.sock = sx->outblock.sock = + sx->cctx.sock = smtp_connect(sx->host, sx->host_af, sx->interface, sx->ob->connect_timeout, sx->tblock); + sx->cctx.tls_ctx = NULL; + sx->inblock.cctx = sx->outblock.cctx = &sx->cctx; - if (sx->inblock.sock < 0) + if (sx->cctx.sock < 0) { uschar * msg = NULL; if (sx->verify) @@ -1700,7 +1705,7 @@ if (!continue_hostname) BOOL good_response; #ifdef TCP_QUICKACK - (void) setsockopt(sx->inblock.sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off)); + (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off)); #endif good_response = smtp_read_response(&sx->inblock, sx->buffer, sizeof(sx->buffer), '2', sx->ob->command_timeout); @@ -1879,16 +1884,18 @@ separate - we could match up by host ip+port as a bodge. */ else { - if (cutthrough.fd >= 0 && cutthrough.callout_hold_only) + if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only) { - sx->inblock.sock = sx->outblock.sock = cutthrough.fd; + sx->cctx = cutthrough.cctx; sx->host->port = sx->port = cutthrough.host.port; } else { - sx->inblock.sock = sx->outblock.sock = 0; /* stdin */ + sx->cctx.sock = 0; /* stdin */ + sx->cctx.tls_ctx = NULL; smtp_port_for_connect(sx->host, sx->port); /* Record the port that was used */ } + sx->inblock.cctx = sx->outblock.cctx = &sx->cctx; smtp_command = big_buffer; sx->helo_data = NULL; /* ensure we re-expand ob->helo_data */ @@ -1896,7 +1903,8 @@ else held-open verify connection with TLS, nothing more to do. */ if ( continue_proxy_cipher - || (cutthrough.fd >= 0 && cutthrough.callout_hold_only && cutthrough.is_tls) + || (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only + && cutthrough.is_tls) ) { sx->peer_offered = smtp_peer_options; @@ -1956,18 +1964,19 @@ if ( smtp_peer_options & OPTION_TLS { address_item * addr; uschar * errstr; - int rc = tls_client_start(sx->inblock.sock, sx->host, sx->addrlist, sx->tblock, + sx->cctx.tls_ctx = tls_client_start(sx->cctx.sock, sx->host, + sx->addrlist, sx->tblock, # ifdef SUPPORT_DANE sx->dane ? &tlsa_dnsa : NULL, # endif - &errstr); + &tls_out, &errstr); - /* 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. */ - - if (rc != OK) + if (!sx->cctx.tls_ctx) { + /* 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 SUPPORT_DANE if (sx->dane) { @@ -2010,7 +2019,7 @@ another process, and so we won't have expanded helo_data above. We have to expand it here. $sending_ip_address and $sending_port are set up right at the start of the Exim process (in exim.c). */ -if (tls_out.active >= 0) +if (tls_out.active.sock >= 0) { char *greeting_cmd; BOOL good_response; @@ -2088,7 +2097,7 @@ we skip this. */ if (continue_hostname == NULL #ifdef SUPPORT_TLS - || tls_out.active >= 0 + || tls_out.active.sock >= 0 #endif ) { @@ -2267,7 +2276,11 @@ if (sx->send_quit) (void)smtp_write_command(&sx->outblock, SCMD_FLUSH, "QUIT\r\n"); #ifdef SUPPORT_TLS -tls_close(FALSE, TLS_SHUTDOWN_NOWAIT); +if (sx->cctx.tls_ctx) + { + tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT); + sx->cctx.tls_ctx = NULL; + } #endif /* Close the socket, and return the appropriate value, first setting @@ -2278,14 +2291,14 @@ remote_max_parallel is forced to 1 when delivering over an existing connection, HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n"); if (sx->send_quit) { - shutdown(sx->outblock.sock, SHUT_WR); - if (fcntl(sx->inblock.sock, F_SETFL, O_NONBLOCK) == 0) - for (rc = 16; read(sx->inblock.sock, sx->inbuffer, sizeof(sx->inbuffer)) > 0 && rc > 0;) + shutdown(sx->cctx.sock, SHUT_WR); + if (fcntl(sx->cctx.sock, F_SETFL, O_NONBLOCK) == 0) + for (rc = 16; read(sx->cctx.sock, sx->inbuffer, sizeof(sx->inbuffer)) > 0 && rc > 0;) rc--; /* drain socket */ sx->send_quit = FALSE; } -(void)close(sx->inblock.sock); -sx->inblock.sock = sx->outblock.sock = -1; +(void)close(sx->cctx.sock); +sx->cctx.sock = -1; #ifndef DISABLE_EVENT (void) event_raise(sx->tblock->event_action, US"tcp:close", NULL); @@ -2621,6 +2634,7 @@ Do blocking full-size writes, and reads under a timeout. Once both input channels are closed, exit the process. Arguments: + ct_ctx tls context buf space to use for buffering bufsiz size of buffer pfd pipe filedescriptor array; [0] is comms to proxied process @@ -2628,10 +2642,11 @@ Arguments: */ void -smtp_proxy_tls(uschar * buf, size_t bsize, int * pfd, int timeout) +smtp_proxy_tls(void * ct_ctx, uschar * buf, size_t bsize, int * pfd, + int timeout) { fd_set rfds, efds; -int max_fd = MAX(pfd[0], tls_out.active) + 1; +int max_fd = MAX(pfd[0], tls_out.active.sock) + 1; int rc, i, fd_bits, nbytes; close(pfd[1]); @@ -2644,7 +2659,7 @@ if ((rc = fork())) if (running_in_test_harness) millisleep(100); /* let parent debug out */ set_process_info("proxying TLS connection for continued transport"); FD_ZERO(&rfds); -FD_SET(tls_out.active, &rfds); +FD_SET(tls_out.active.sock, &rfds); FD_SET(pfd[0], &rfds); for (fd_bits = 3; fd_bits; ) @@ -2670,21 +2685,21 @@ for (fd_bits = 3; fd_bits; ) goto done; } - if (FD_ISSET(tls_out.active, &efds) || FD_ISSET(pfd[0], &efds)) + if (FD_ISSET(tls_out.active.sock, &efds) || FD_ISSET(pfd[0], &efds)) { DEBUG(D_transport) debug_printf("select: exceptional cond on %s fd\n", FD_ISSET(pfd[0], &efds) ? "proxy" : "tls"); goto done; } } - while (rc < 0 || !(FD_ISSET(tls_out.active, &rfds) || FD_ISSET(pfd[0], &rfds))); + while (rc < 0 || !(FD_ISSET(tls_out.active.sock, &rfds) || FD_ISSET(pfd[0], &rfds))); /* handle inbound data */ - if (FD_ISSET(tls_out.active, &rfds)) - if ((rc = tls_read(FALSE, buf, bsize)) <= 0) + if (FD_ISSET(tls_out.active.sock, &rfds)) + if ((rc = tls_read(ct_ctx, buf, bsize)) <= 0) { fd_bits &= ~1; - FD_CLR(tls_out.active, &rfds); + FD_CLR(tls_out.active.sock, &rfds); shutdown(pfd[0], SHUT_WR); timeout = 5; } @@ -2694,19 +2709,19 @@ for (fd_bits = 3; fd_bits; ) if ((i = write(pfd[0], buf + nbytes, rc - nbytes)) < 0) goto done; } else if (fd_bits & 1) - FD_SET(tls_out.active, &rfds); + FD_SET(tls_out.active.sock, &rfds); /* handle outbound data */ if (FD_ISSET(pfd[0], &rfds)) if ((rc = read(pfd[0], buf, bsize)) <= 0) { fd_bits = 0; - tls_close(FALSE, TLS_SHUTDOWN_NOWAIT); + tls_close(ct_ctx, TLS_SHUTDOWN_NOWAIT); } else { for (nbytes = 0; rc - nbytes > 0; nbytes += i) - if ((i = tls_write(FALSE, buf + nbytes, rc - nbytes, FALSE)) < 0) + if ((i = tls_write(ct_ctx, buf + nbytes, rc - nbytes, FALSE)) < 0) goto done; } else if (fd_bits & 2) @@ -2949,7 +2964,7 @@ if (!(sx.peer_offered & OPTION_CHUNKING) && !sx.ok) else { transport_ctx tctx = { - {sx.inblock.sock}, + {sx.cctx.sock}, /*XXX will this need TLS info? */ tblock, addrlist, US".", US"..", /* Escaping strings */ @@ -3462,7 +3477,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit) || continue_more || ( #ifdef SUPPORT_TLS - ( tls_out.active < 0 && !continue_proxy_cipher + ( tls_out.active.sock < 0 && !continue_proxy_cipher || verify_check_given_host(&sx.ob->hosts_nopass_tls, host) != OK ) && @@ -3500,7 +3515,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit) if (sx.ok) { int pfd[2]; - int socket_fd = sx.inblock.sock; + int socket_fd = sx.cctx.sock; if (sx.first_addr != NULL) /* More addresses still to be sent */ @@ -3515,7 +3530,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit) the connection still open. */ #ifdef SUPPORT_TLS - if (tls_out.active >= 0) + if (tls_out.active.sock >= 0) if ( continue_more || verify_check_given_host(&sx.ob->hosts_noproxy_tls, host) == OK) { @@ -3525,7 +3540,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit) a new EHLO. If we don't get a good response, we don't attempt to pass the socket on. */ - tls_close(FALSE, TLS_SHUTDOWN_WAIT); + tls_close(sx.cctx.tls_ctx, TLS_SHUTDOWN_WAIT); smtp_peer_options = smtp_peer_options_wrap; sx.ok = !sx.smtps && smtp_write_command(&sx.outblock, SCMD_FLUSH, @@ -3573,14 +3588,14 @@ propagate it from the initial get logging done asap. Which way to place the work makes assumptions about post-fork prioritisation which may not hold on all platforms. */ #ifdef SUPPORT_TLS - if (tls_out.active >= 0) + if (tls_out.active.sock >= 0) { int pid = fork(); if (pid == 0) /* child; fork again to disconnect totally */ { if (running_in_test_harness) millisleep(100); /* let parent debug out */ /* does not return */ - smtp_proxy_tls(sx.buffer, sizeof(sx.buffer), pfd, + smtp_proxy_tls(sx.cctx.tls_ctx, sx.buffer, sizeof(sx.buffer), pfd, sx.ob->command_timeout); } @@ -3590,8 +3605,10 @@ propagate it from the initial close(pfd[0]); /* tidy the inter-proc to disconn the proxy proc */ waitpid(pid, NULL, 0); - tls_close(FALSE, TLS_NO_SHUTDOWN); - (void)close(sx.inblock.sock); + tls_close(sx.cctx.tls_ctx, TLS_NO_SHUTDOWN); + sx.cctx.tls_ctx = NULL; + (void)close(sx.cctx.sock); + sx.cctx.sock = -1; continue_transport = NULL; continue_hostname = NULL; return yield; @@ -3636,7 +3653,7 @@ if (sx.send_quit) (void)smtp_write_command(&sx.outblock, SCMD_FLUSH, "QUIT\r\n") END_OFF: #ifdef SUPPORT_TLS -tls_close(FALSE, TLS_SHUTDOWN_NOWAIT); +tls_close(sx.cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT); #endif /* Close the socket, and return the appropriate value, first setting @@ -3652,12 +3669,12 @@ case continue_more won't get set. */ HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n"); if (sx.send_quit) { - shutdown(sx.outblock.sock, SHUT_WR); - if (fcntl(sx.inblock.sock, F_SETFL, O_NONBLOCK) == 0) - for (rc = 16; read(sx.inblock.sock, sx.inbuffer, sizeof(sx.inbuffer)) > 0 && rc > 0;) + shutdown(sx.cctx.sock, SHUT_WR); + if (fcntl(sx.cctx.sock, F_SETFL, O_NONBLOCK) == 0) + for (rc = 16; read(sx.cctx.sock, sx.inbuffer, sizeof(sx.inbuffer)) > 0 && rc > 0;) rc--; /* drain socket */ } -(void)close(sx.inblock.sock); +(void)close(sx.cctx.sock); #ifndef DISABLE_EVENT (void) event_raise(tblock->event_action, US"tcp:close", NULL); @@ -3693,19 +3710,24 @@ smtp_transport_closedown(transport_instance *tblock) { smtp_transport_options_block *ob = (smtp_transport_options_block *)tblock->options_block; +client_conn_ctx cctx; smtp_inblock inblock; smtp_outblock outblock; uschar buffer[256]; uschar inbuffer[4096]; uschar outbuffer[16]; -inblock.sock = fileno(stdin); +/*XXX really we need an active-smtp-client ctx, rather than assuming stdout */ +cctx.sock = fileno(stdin); +cctx.tls_ctx = cctx.sock == tls_out.active.sock ? tls_out.active.tls_ctx : NULL; + +inblock.cctx = &cctx; inblock.buffer = inbuffer; inblock.buffersize = sizeof(inbuffer); inblock.ptr = inbuffer; inblock.ptrend = inbuffer; -outblock.sock = inblock.sock; +outblock.cctx = &cctx; outblock.buffersize = sizeof(outbuffer); outblock.buffer = outbuffer; outblock.ptr = outbuffer; @@ -3715,7 +3737,7 @@ outblock.authenticating = FALSE; (void)smtp_write_command(&outblock, SCMD_FLUSH, "QUIT\r\n"); (void)smtp_read_response(&inblock, buffer, sizeof(buffer), '2', ob->command_timeout); -(void)close(inblock.sock); +(void)close(cctx.sock); } @@ -3816,7 +3838,7 @@ DEBUG(D_transport) if (continue_hostname) debug_printf("already connected to %s [%s] (on fd %d)\n", continue_hostname, continue_host_address, - cutthrough.fd >= 0 ? cutthrough.fd : 0); + cutthrough.cctx.sock >= 0 ? cutthrough.cctx.sock : 0); } /* Set the flag requesting that these hosts be added to the waiting @@ -4601,21 +4623,27 @@ retry_non_continued: if (continue_hostname && !continue_host_tried) { - int fd = cutthrough.fd >= 0 ? cutthrough.fd : 0; + int fd = cutthrough.cctx.sock >= 0 ? cutthrough.cctx.sock : 0; DEBUG(D_transport) debug_printf("no hosts match already-open connection\n"); #ifdef SUPPORT_TLS - if (tls_out.active == fd) + /* A TLS conn could be open for a cutthrough, but not for a plain continued- + transport */ +/*XXX doublecheck that! */ + + if (cutthrough.cctx.sock >= 0 && cutthrough.is_tls) { - (void) tls_write(FALSE, US"QUIT\r\n", 6, FALSE); - tls_close(FALSE, TLS_SHUTDOWN_NOWAIT); + (void) tls_write(cutthrough.cctx.tls_ctx, US"QUIT\r\n", 6, FALSE); + tls_close(cutthrough.cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT); + cutthrough.cctx.tls_ctx = NULL; + cutthrough.is_tls = FALSE; } else #else (void) write(fd, US"QUIT\r\n", 6); #endif (void) close(fd); - cutthrough.fd = -1; + cutthrough.cctx.sock = -1; continue_hostname = NULL; goto retry_non_continued; }