X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/d8b8dd159b784810ec7e5d55e3c49319fc63598a..b7d3afcfad94edf99a8dbc50ab670ded417e6bea:/src/src/transports/smtp.c diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 4ce839d63..758f1143a 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -796,7 +796,9 @@ with an address by scanning for the next address whose status is PENDING_DEFER. while (count-- > 0) { - while (addr->transport_return != PENDING_DEFER) addr = addr->next; + while (addr->transport_return != PENDING_DEFER) + if (!(addr = addr->next)) + return -2; /* The address was accepted */ addr->host_used = sx->host; @@ -1370,13 +1372,14 @@ smtp_context * sx = tctx->smtp_context; int cmd_count = 0; int prev_cmd_count; -/* Write SMTP chunk header command */ +/* Write SMTP chunk header command. If not reaping responses, note that +there may be more writes (like, the chunk data) done soon. */ if (chunk_size > 0) { - if((cmd_count = smtp_write_command(&sx->outblock, FALSE, "BDAT %u%s\r\n", - chunk_size, - flags & tc_chunk_last ? " LAST" : "") + if((cmd_count = smtp_write_command(&sx->outblock, + flags & tc_reap_prev ? SCMD_FLUSH : SCMD_MORE, + "BDAT %u%s\r\n", chunk_size, flags & tc_chunk_last ? " LAST" : "") ) < 0) return ERROR; if (flags & tc_chunk_last) data_command = string_copy(big_buffer); /* Save for later error message */ @@ -1739,7 +1742,7 @@ goto SEND_QUIT; if (sx->esmtp) { - if (smtp_write_command(&sx->outblock, FALSE, "%s %s\r\n", + if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "%s %s\r\n", sx->lmtp ? "LHLO" : "EHLO", sx->helo_data) < 0) goto SEND_FAILED; sx->esmtp_sent = TRUE; @@ -1772,7 +1775,7 @@ goto SEND_QUIT; if (sx->esmtp_sent && (n = Ustrlen(sx->buffer)) < sizeof(sx->buffer)/2) { rsp = sx->buffer + n + 1; n = sizeof(sx->buffer) - n; } - if (smtp_write_command(&sx->outblock, FALSE, "HELO %s\r\n", sx->helo_data) < 0) + if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "HELO %s\r\n", sx->helo_data) < 0) goto SEND_FAILED; good_response = smtp_read_response(&sx->inblock, rsp, n, '2', sx->ob->command_timeout); @@ -1872,7 +1875,7 @@ if ( smtp_peer_options & PEER_OFFERED_TLS ) ) { uschar buffer2[4096]; - if (smtp_write_command(&sx->outblock, FALSE, "STARTTLS\r\n") < 0) + if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "STARTTLS\r\n") < 0) goto SEND_FAILED; /* If there is an I/O error, transmission of this message is deferred. If @@ -1986,7 +1989,7 @@ if (tls_out.active >= 0) debug_printf("not sending EHLO (host matches hosts_avoid_esmtp)\n"); } - if (smtp_write_command(&sx->outblock, FALSE, "%s %s\r\n", + if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "%s %s\r\n", sx->lmtp ? "LHLO" : greeting_cmd, sx->helo_data) < 0) goto SEND_FAILED; good_response = smtp_read_response(&sx->inblock, sx->buffer, sizeof(sx->buffer), @@ -2190,7 +2193,7 @@ FAILED: SEND_QUIT: if (sx->send_quit) - (void)smtp_write_command(&sx->outblock, FALSE, "QUIT\r\n"); + (void)smtp_write_command(&sx->outblock, SCMD_FLUSH, "QUIT\r\n"); #ifdef SUPPORT_TLS tls_close(FALSE, TRUE); @@ -2199,12 +2202,7 @@ tls_close(FALSE, TRUE); /* Close the socket, and return the appropriate value, first setting works because the NULL setting is passed back to the calling process, and remote_max_parallel is forced to 1 when delivering over an existing connection, - -If all went well and continue_more is set, we shouldn't actually get here if -there are further addresses, as the return above will be taken. However, -writing RSET might have failed, or there may be other addresses whose hosts are -specified in the transports, and therefore not visible at top level, in which -case continue_more won't get set. */ +*/ HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n"); if (sx->send_quit) @@ -2251,6 +2249,9 @@ included in the count.) */ if (sx->peer_offered & PEER_OFFERED_SIZE) { +/*XXX problem here under spool_files_wireformat? +Or just forget about lines? Or inflate by a fixed proportion? */ + sprintf(CS p, " SIZE=%d", message_size+message_linecount+sx->ob->size_addition); while (*p) p++; } @@ -2420,7 +2421,7 @@ sx->pending_MAIL = TRUE; /* The block starts with MAIL */ } #endif - rc = smtp_write_command(&sx->outblock, pipelining_active, + rc = smtp_write_command(&sx->outblock, pipelining_active ? SCMD_BUFFER : SCMD_FLUSH, "MAIL FROM:<%s>%s\r\n", s, sx->buffer); } @@ -2475,7 +2476,8 @@ for (addr = sx->first_addr, address_count = 0; ? dsn_support_yes : dsn_support_no; address_count++; - no_flush = pipelining_active && !sx->verify && (!mua_wrapper || addr->next); + no_flush = pipelining_active && !sx->verify + && (!mua_wrapper || addr->next && address_count < sx->max_rcpt); build_rcptcmd_options(sx, addr); @@ -2497,8 +2499,8 @@ for (addr = sx->first_addr, address_count = 0; } #endif - count = smtp_write_command(&sx->outblock, no_flush, "RCPT TO:<%s>%s%s\r\n", - rcpt_addr, sx->igquotstr, sx->buffer); + count = smtp_write_command(&sx->outblock, no_flush ? SCMD_BUFFER : SCMD_FLUSH, + "RCPT TO:<%s>%s%s\r\n", rcpt_addr, sx->igquotstr, sx->buffer); if (count < 0) return -5; if (count > 0) @@ -2701,17 +2703,14 @@ set it up. This cannot be done until the identify of the host is known. */ if (tblock->filter_command) { - BOOL rc; - uschar fbuf[64]; - sprintf(CS fbuf, "%.50s transport", tblock->name); - rc = transport_set_up_command(&transport_filter_argv, tblock->filter_command, - TRUE, DEFER, addrlist, fbuf, NULL); transport_filter_timeout = tblock->filter_timeout; /* On failure, copy the error to all addresses, abandon the SMTP call, and yield ERROR. */ - if (!rc) + if (!transport_set_up_command(&transport_filter_argv, + tblock->filter_command, TRUE, DEFER, addrlist, + string_sprintf("%.50s transport", tblock->name), NULL)) { set_errno_nohost(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER, FALSE); @@ -2730,6 +2729,7 @@ if (tblock->filter_command) } } +sx.first_addr = addrlist; /* For messages that have more than the maximum number of envelope recipients, we want to send several transactions down the same SMTP connection. (See @@ -2741,7 +2741,7 @@ transaction to handle. */ SEND_MESSAGE: sx.from_addr = return_path; -sx.first_addr = sx.sync_addr = addrlist; +sx.sync_addr = sx.first_addr; sx.ok = FALSE; sx.send_rset = TRUE; sx.completed_addr = FALSE; @@ -2783,13 +2783,15 @@ else if (mua_wrapper) { - address_item *badaddr; - for (badaddr = sx.first_addr; badaddr; badaddr = badaddr->next) - if (badaddr->transport_return != PENDING_OK) + address_item * a; + unsigned cnt; + + for (a = sx.first_addr, cnt = 0; a && cnt < sx.max_rcpt; a = a->next, cnt++) + if (a->transport_return != PENDING_OK) { /*XXX could we find a better errno than 0 here? */ - set_errno_nohost(addrlist, 0, badaddr->message, FAIL, - testflag(badaddr, af_pass_message)); + set_errno_nohost(addrlist, 0, a->message, FAIL, + testflag(a, af_pass_message)); sx.ok = FALSE; break; } @@ -2807,7 +2809,7 @@ to send is. */ if ( !(sx.peer_offered & PEER_OFFERED_CHUNKING) && (sx.ok || (pipelining_active && !mua_wrapper))) { - int count = smtp_write_command(&sx.outblock, FALSE, "DATA\r\n"); + int count = smtp_write_command(&sx.outblock, SCMD_FLUSH, "DATA\r\n"); if (count < 0) goto SEND_FAILED; switch(sync_responses(&sx, count, sx.ok ? +1 : -1)) @@ -2844,6 +2846,7 @@ if (!(sx.peer_offered & PEER_OFFERED_CHUNKING) && !sx.ok) else { transport_ctx tctx = { + sx.inblock.sock, tblock, addrlist, US".", US"..", /* Escaping strings */ @@ -2892,10 +2895,9 @@ else transport_count = 0; #ifndef DISABLE_DKIM - sx.ok = dkim_transport_write_message(sx.inblock.sock, &tctx, &sx.ob->dkim, - CUSS &message); + sx.ok = dkim_transport_write_message(&tctx, &sx.ob->dkim, CUSS &message); #else - sx.ok = transport_write_message(sx.inblock.sock, &tctx, 0); + sx.ok = transport_write_message(&tctx, 0); #endif /* transport_write_message() uses write() because it is called from other @@ -3334,7 +3336,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit) BOOL pass_message; if (sx.send_rset) - if (! (sx.ok = smtp_write_command(&sx.outblock, FALSE, "RSET\r\n") >= 0)) + if (! (sx.ok = smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0)) { msg = US string_sprintf("send() to %s [%s] failed: %s", host->name, host->address, strerror(errno)); @@ -3366,26 +3368,33 @@ if (sx.completed_addr && sx.ok && sx.send_quit) continue_sequence++; /* Causes * in logging */ goto SEND_MESSAGE; } - if (continue_more) return yield; /* More addresses for another run */ - /* Pass the connection on to a new Exim process. */ + /* 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 + the connection still open. */ + #ifdef SUPPORT_TLS if (tls_out.active >= 0) - if (verify_check_given_host(&sx.ob->hosts_noproxy_tls, host) == OK) + if ( continue_more + || verify_check_given_host(&sx.ob->hosts_noproxy_tls, host) == OK) { - /* Pass the socket, for direct use, to a new Exim process. Before - doing so, we must shut down TLS. Not all MTAs allow for the - continuation of the SMTP session when TLS is shut down. We test for - this by sending a new EHLO. If we don't get a good response, we don't - attempt to pass the socket on. */ + /* 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 + of the SMTP session when TLS is shut down. We test for this by sending + a new EHLO. If we don't get a good response, we don't attempt to pass + the socket on. */ tls_close(FALSE, TRUE); smtp_peer_options = smtp_peer_options_wrap; sx.ok = !sx.smtps - && smtp_write_command(&sx.outblock, FALSE, + && smtp_write_command(&sx.outblock, SCMD_FLUSH, "EHLO %s\r\n", sx.helo_data) >= 0 && smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer), '2', sx.ob->command_timeout); + + if (sx.ok && continue_more) + return yield; /* More addresses for another run */ } else { @@ -3402,7 +3411,10 @@ if (sx.completed_addr && sx.ok && sx.send_quit) # endif ); } + else #endif + if (continue_more) + return yield; /* More addresses for another run */ /* If the socket is successfully passed, we mustn't send QUIT (or indeed anything!) from here. */ @@ -3425,14 +3437,21 @@ propagate it from the initial int pid = fork(); if (pid > 0) /* parent */ { + DEBUG(D_transport) debug_printf("proxy-proc inter-pid %d\n", pid); + waitpid(pid, NULL, 0); tls_close(FALSE, FALSE); (void)close(sx.inblock.sock); continue_transport = NULL; continue_hostname = NULL; return yield; } - else if (pid == 0) /* child */ + else if (pid == 0) /* child; fork again to disconnect totally */ { + if ((pid = fork())) + { + DEBUG(D_transport) debug_printf("proxy-prox final-pid %d\n", pid); + _exit(pid ? EXIT_FAILURE : EXIT_SUCCESS); + } smtp_proxy_tls(sx.buffer, sizeof(sx.buffer), pfd[0], sx.ob->command_timeout); exim_exit(0); } @@ -3470,7 +3489,7 @@ This change is being made on 31-Jul-98. After over a year of trouble-free operation, the old commented-out code was removed on 17-Sep-99. */ SEND_QUIT: -if (sx.send_quit) (void)smtp_write_command(&sx.outblock, FALSE, "QUIT\r\n"); +if (sx.send_quit) (void)smtp_write_command(&sx.outblock, SCMD_FLUSH, "QUIT\r\n"); END_OFF: @@ -3551,7 +3570,7 @@ outblock.ptr = outbuffer; outblock.cmd_count = 0; outblock.authenticating = FALSE; -(void)smtp_write_command(&outblock, FALSE, "QUIT\r\n"); +(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);