tidying
[exim.git] / src / src / transports / smtp.c
index e2c2680a0f8f7131d02d91e121c1dbbc1563353e..70ab483a6daf590a05cdc2539ad948086414036c 100644 (file)
@@ -2155,7 +2155,7 @@ if (continue_hostname && continue_proxy_cipher)
     DEBUG(D_transport)
       debug_printf("Closing proxied-TLS connection due to SNI mismatch\n");
 
-    HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP>> QUIT\n");
+    smtp_debug_cmd(US"QUIT", 0);
     write(0, "QUIT\r\n", 6);
     close(0);
     continue_hostname = continue_proxy_cipher = NULL;
@@ -2239,6 +2239,9 @@ if (!continue_hostname)
   sx->peer_limit_mail = sx->peer_limit_rcpt = sx->peer_limit_rcptdom =
 #endif
   sx->avoid_option = sx->peer_offered = smtp_peer_options = 0;
+#ifndef DISABLE_CLIENT_CMD_LOG
+  client_cmd_log = NULL;
+#endif
 
 #ifndef DISABLE_PIPE_CONNECT
   if (  verify_check_given_host(CUSS &ob->hosts_pipe_connect,
@@ -2248,6 +2251,7 @@ if (!continue_hostname)
     the helo string might use it avoid doing early-pipelining. */
 
     if (  !sx->helo_data
+       || sx->conn_args.interface
        || !Ustrstr(sx->helo_data, "$sending_ip_address")
        || Ustrstr(sx->helo_data, "def:sending_ip_address")
        )
@@ -2263,11 +2267,14 @@ if (!continue_hostname)
        }
       }
     else DEBUG(D_transport)
-      debug_printf("helo needs $sending_ip_address\n");
+      debug_printf("helo needs $sending_ip_address; avoid early-pipelining\n");
 
 PIPE_CONNECT_RETRY:
   if (sx->early_pipe_active)
+    {
     sx->outblock.conn_args = &sx->conn_args;
+    (void) smtp_boundsock(&sx->conn_args);
+    }
   else
 #endif
     {
@@ -2292,9 +2299,10 @@ PIPE_CONNECT_RETRY:
     }
   /* Expand the greeting message while waiting for the initial response. (Makes
   sense if helo_data contains ${lookup dnsdb ...} stuff). The expansion is
-  delayed till here so that $sending_interface and $sending_port are set. */
-/*XXX early-pipe: they still will not be. Is there any way to find out what they
-will be?  Somehow I doubt it. */
+  delayed till here so that $sending_ip_address and $sending_port are set.
+  Those will be known even for a TFO lazy-connect, having been set by the bind().
+  For early-pipe, we are ok if binding to a local interface; otherwise (if
+  $sending_ip_address is seen in helo_data) we disabled early-pipe above. */
 
   if (sx->helo_data)
     if (!(sx->helo_data = expand_string(sx->helo_data)))
@@ -2931,18 +2939,18 @@ if (   !continue_hostname
       smtp_peer_options & OPTION_PIPE ? "" : "not ");
 
     if (  sx->peer_offered & OPTION_CHUNKING
-       && verify_check_given_host(CUSS &ob->hosts_try_chunking, sx->conn_args.host) != OK)
-      sx->peer_offered &= ~OPTION_CHUNKING;
+       && verify_check_given_host(CUSS &ob->hosts_try_chunking, sx->conn_args.host) == OK)
+      smtp_peer_options |= OPTION_CHUNKING;
 
-    if (sx->peer_offered & OPTION_CHUNKING)
+    if (smtp_peer_options & OPTION_CHUNKING)
       DEBUG(D_transport) debug_printf("CHUNKING usable\n");
 
 #ifndef DISABLE_PRDR
     if (  sx->peer_offered & OPTION_PRDR
-       && verify_check_given_host(CUSS &ob->hosts_try_prdr, sx->conn_args.host) != OK)
-      sx->peer_offered &= ~OPTION_PRDR;
+       && verify_check_given_host(CUSS &ob->hosts_try_prdr, sx->conn_args.host) == OK)
+      smtp_peer_options |= OPTION_PRDR;
 
-    if (sx->peer_offered & OPTION_PRDR)
+    if (smtp_peer_options & OPTION_PRDR)
       DEBUG(D_transport) debug_printf("PRDR usable\n");
 #endif
 
@@ -3170,6 +3178,7 @@ sx->cctx.sock = -1;
 (void) event_raise(sx->conn_args.tblock->event_action, US"tcp:close", NULL, NULL);
 #endif
 
+smtp_debug_cmd_report();
 continue_transport = NULL;
 continue_hostname = NULL;
 return yield;
@@ -3212,7 +3221,7 @@ Or just forget about lines?  Or inflate by a fixed proportion? */
 request that */
 
 sx->prdr_active = FALSE;
-if (sx->peer_offered & OPTION_PRDR)
+if (smtp_peer_options & OPTION_PRDR)
   for (address_item * addr = addrlist; addr; addr = addr->next)
     if (addr->transport_return == PENDING_DEFER)
       {
@@ -3537,24 +3546,27 @@ Arguments:
   bufsiz       size of buffer
   pfd          pipe filedescriptor array; [0] is comms to proxied process
   timeout      per-read timeout, seconds
+  host         hostname of remote
 
 Does not return.
 */
 
 void
 smtp_proxy_tls(void * ct_ctx, uschar * buf, size_t bsize, int * pfd,
-  int timeout)
+  int timeout, const uschar * host)
 {
 struct pollfd p[2] = {{.fd = tls_out.active.sock, .events = POLLIN},
                      {.fd = pfd[0], .events = POLLIN}};
 int rc, i;
 BOOL send_tls_shutdown = TRUE;
+uschar * s =
+  string_sprintf("proxying TLS connection for continued transport to %s\n", host);
 
 close(pfd[1]);
 if ((rc = exim_fork(US"tls-proxy")))
   _exit(rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
 
-set_process_info("proxying TLS connection for continued transport");
+set_process_info(CCS s);
 
 do
   {
@@ -3712,6 +3724,7 @@ sx->port = defport;
 sx->conn_args.interface = interface;
 sx->helo_data = NULL;
 sx->conn_args.tblock = tblock;
+sx->conn_args.sock = -1;
 gettimeofday(&sx->delivery_start, NULL);
 sx->sync_addr = sx->first_addr = addrlist;
 
@@ -3761,7 +3774,7 @@ if (tblock->filter_command)
   yield ERROR. */
 
   if (!transport_set_up_command(&transport_filter_argv,
-       tblock->filter_command, TRUE, DEFER, addrlist,
+       tblock->filter_command, TRUE, DEFER, addrlist, FALSE,
        string_sprintf("%.50s transport filter", tblock->name), NULL))
     {
     set_errno_nohost(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
@@ -3773,7 +3786,7 @@ if (tblock->filter_command)
   if (  transport_filter_argv
      && *transport_filter_argv
      && **transport_filter_argv
-     && sx->peer_offered & OPTION_CHUNKING
+     && smtp_peer_options & OPTION_CHUNKING
 #ifndef DISABLE_DKIM
     /* When dkim signing, chunking is handled even with a transport-filter */
      && !(ob->dkim.dkim_private_key && ob->dkim.dkim_domain && ob->dkim.dkim_selector)
@@ -3781,7 +3794,7 @@ if (tblock->filter_command)
 #endif
      )
     {
-    sx->peer_offered &= ~OPTION_CHUNKING;
+    smtp_peer_options &= ~OPTION_CHUNKING;
     DEBUG(D_transport) debug_printf("CHUNKING not usable due to transport filter\n");
     }
   }
@@ -3858,7 +3871,7 @@ are pipelining. The responses are all handled by sync_responses().
 If using CHUNKING, do not send a BDAT until we know how big a chunk we want
 to send is. */
 
-if (  !(sx->peer_offered & OPTION_CHUNKING)
+if (  !(smtp_peer_options & OPTION_CHUNKING)
    && (sx->ok || (pipelining_active && !mua_wrapper)))
   {
   int count = smtp_write_command(sx, SCMD_FLUSH, "DATA\r\n");
@@ -3895,7 +3908,7 @@ well as body. Set the appropriate timeout value to be used for each chunk.
 (Haven't been able to make it work using select() for writing yet.) */
 
 if (  !sx->ok
-   && (!(sx->peer_offered & OPTION_CHUNKING) || !pipelining_active))
+   && (!(smtp_peer_options & OPTION_CHUNKING) || !pipelining_active))
   {
   /* Save the first address of the next batch. */
   sx->first_addr = sx->next_addr;
@@ -3924,7 +3937,7 @@ else
   of responses.  The callback needs a whole bunch of state so set up
   a transport-context structure to be passed around. */
 
-  if (sx->peer_offered & OPTION_CHUNKING)
+  if (smtp_peer_options & OPTION_CHUNKING)
     {
     tctx.check_string = tctx.escape_string = NULL;
     tctx.options |= topt_use_bdat;
@@ -3949,7 +3962,7 @@ else
   transport_write_timeout = ob->data_timeout;
   smtp_command = US"sending data block";   /* For error messages */
   DEBUG(D_transport|D_v)
-    if (sx->peer_offered & OPTION_CHUNKING)
+    if (smtp_peer_options & OPTION_CHUNKING)
       debug_printf("         will write message using CHUNKING\n");
     else
       debug_printf("  SMTP>> writing message and terminating \".\"\n");
@@ -4001,7 +4014,7 @@ else
   If we can, we want the message-write to not flush (the tail end of) its data out.  */
 
   if (  sx->pipelining_used
-     && (sx->ok && sx->completed_addr || sx->peer_offered & OPTION_CHUNKING)
+     && (sx->ok && sx->completed_addr || smtp_peer_options & OPTION_CHUNKING)
      && sx->send_quit
      && !(sx->first_addr || f.continue_more)
      && f.deliver_firsttime
@@ -4085,7 +4098,7 @@ else
       sx->send_quit = FALSE;   /* avoid sending it later */
 
 #ifndef DISABLE_TLS
-      if (sx->cctx.tls_ctx)    /* need to send TLS Close Notify */
+      if (sx->cctx.tls_ctx && sx->send_tlsclose)       /* need to send TLS Close Notify */
        {
 # ifdef EXIM_TCP_CORK          /* Use _CORK to get Close Notify in FIN segment */
        (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
@@ -4099,7 +4112,7 @@ else
       }
     }
 
-  if (sx->peer_offered & OPTION_CHUNKING && sx->cmd_count > 1)
+  if (smtp_peer_options & OPTION_CHUNKING && sx->cmd_count > 1)
     {
     /* Reap any outstanding MAIL & RCPT commands, but not a DATA-go-ahead */
     switch(sync_responses(sx, sx->cmd_count-1, 0))
@@ -4272,7 +4285,7 @@ else
 #ifndef DISABLE_PRDR
       if (sx->prdr_active) setflag(addr, af_prdr_used);
 #endif
-      if (sx->peer_offered & OPTION_CHUNKING) setflag(addr, af_chunking_used);
+      if (smtp_peer_options & OPTION_CHUNKING) setflag(addr, af_chunking_used);
       flag = '-';
 
 #ifndef DISABLE_PRDR
@@ -4429,7 +4442,8 @@ if (!sx->ok)
 # ifndef DISABLE_TLS
        if (sx->cctx.tls_ctx)
          {
-         tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT);
+         tls_close(sx->cctx.tls_ctx,
+                   sx->send_tlsclose ? TLS_SHUTDOWN_WAIT : TLS_SHUTDOWN_WONLY);
          sx->cctx.tls_ctx = NULL;
          }
 # endif
@@ -4640,7 +4654,8 @@ 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(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT);
+         tls_close(sx->cctx.tls_ctx,
+           sx->send_tlsclose ? TLS_SHUTDOWN_WAIT : TLS_SHUTDOWN_WONLY);
          sx->send_tlsclose = FALSE;
          sx->cctx.tls_ctx = NULL;
          tls_out.active.sock = -1;
@@ -4702,7 +4717,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit)
              {
              /* does not return */
              smtp_proxy_tls(sx->cctx.tls_ctx, sx->buffer, sizeof(sx->buffer), pfd,
-                             ob->command_timeout);
+                             ob->command_timeout, host->name);
              }
 
            if (pid > 0)                /* parent */
@@ -4742,7 +4757,7 @@ if (sx->send_quit)
   {                    /* Use _MORE to get QUIT in FIN segment */
   (void)smtp_write_command(sx, SCMD_MORE, "QUIT\r\n");
 #ifndef DISABLE_TLS
-  if (sx->cctx.tls_ctx)
+  if (sx->cctx.tls_ctx && sx->send_tlsclose)
     {
 # ifdef EXIM_TCP_CORK  /* Use _CORK to get TLS Close Notify in FIN segment */
     (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
@@ -4797,10 +4812,15 @@ if (sx->send_quit || tcw_done && !tcw)
     while (!sigalrm_seen && n > 0);
     ALARM_CLR(0);
 
+    if (sx->send_tlsclose)
+      {
 # ifdef EXIM_TCP_CORK
-    (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
+      (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
 # endif
-    tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT);
+      tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT);
+      }
+    else
+      tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WONLY);
     sx->cctx.tls_ctx = NULL;
     }
 #endif
@@ -4824,6 +4844,7 @@ HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(close)>>\n");
 sx->cctx.sock = -1;
 continue_transport = NULL;
 continue_hostname = NULL;
+smtp_debug_cmd_report();
 
 #ifndef DISABLE_EVENT
 (void) event_raise(tblock->event_action, US"tcp:close", NULL, NULL);