consistent fork-time debug
[exim.git] / src / src / smtp_out.c
index d8cb42e01e11e8dd711d7aabe336551dba5d1c25..12ed5bc612e3fd639056c97ebb479877c41ec5eb 100644 (file)
@@ -52,6 +52,17 @@ if (!(expint = expand_string(istring)))
   return FALSE;
   }
 
   return FALSE;
   }
 
+if (is_tainted(expint))
+  {
+  log_write(0, LOG_MAIN|LOG_PANIC,
+    "attempt to use tainted value '%s' from '%s' for interface",
+    expint, istring);
+  addr->transport_return = PANIC;
+  addr->message = string_sprintf("failed to expand \"interface\" "
+      "option for %s: configuration error", msg);
+  return FALSE;
+  }
+
 while (isspace(*expint)) expint++;
 if (*expint == 0) return TRUE;
 
 while (isspace(*expint)) expint++;
 if (*expint == 0) return TRUE;
 
@@ -144,7 +155,28 @@ return TRUE;
 static void
 tfo_out_check(int sock)
 {
 static void
 tfo_out_check(int sock)
 {
-# if defined(TCP_INFO) && defined(EXIM_HAVE_TCPI_UNACKED)
+# ifdef __FreeBSD__
+struct tcp_info tinfo;
+int val;
+socklen_t len = sizeof(val);
+
+/* The observability as of 12.1 is not useful as a client, only telling us that
+a TFO option was used on SYN.  It could have been a TFO-R, or ignored by the
+server. */
+
+/*
+if (tcp_out_fastopen == TFO_ATTEMPTED_NODATA || tcp_out_fastopen == TFO_ATTEMPTED_DATA)
+  if (getsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, &val, &len) == 0 && val != 0) {}
+*/
+switch (tcp_out_fastopen)
+  {
+  case TFO_ATTEMPTED_NODATA:   tcp_out_fastopen = TFO_USED_NODATA; break;
+  case TFO_ATTEMPTED_DATA:     tcp_out_fastopen = TFO_USED_DATA; break;
+  default: break; /* compiler quietening */
+  }
+
+# else /* Linux & Apple */
+#  if defined(TCP_INFO) && defined(EXIM_HAVE_TCPI_UNACKED)
 struct tcp_info tinfo;
 socklen_t len = sizeof(tinfo);
 
 struct tcp_info tinfo;
 socklen_t len = sizeof(tinfo);
 
@@ -194,7 +226,8 @@ switch (tcp_out_fastopen)
 
   default: break; /* compiler quietening */
   }
 
   default: break; /* compiler quietening */
   }
-# endif
+#  endif
+# endif        /* Linux & Apple */
 }
 #endif
 
 }
 #endif
 
@@ -296,7 +329,7 @@ if (save_errno != 0)
   {
   HDEBUG(D_transport|D_acl|D_v)
     {
   {
   HDEBUG(D_transport|D_acl|D_v)
     {
-    debug_printf_indent("failed: %s", CUstrerror(save_errno));
+    debug_printf_indent(" failed: %s", CUstrerror(save_errno));
     if (save_errno == ETIMEDOUT)
       debug_printf(" (timeout=%s)", readconf_printtime(timeout));
     debug_printf("\n");
     if (save_errno == ETIMEDOUT)
       debug_printf(" (timeout=%s)", readconf_printtime(timeout));
     debug_printf("\n");
@@ -313,7 +346,7 @@ else
   union sockaddr_46 interface_sock;
   EXIM_SOCKLEN_T size = sizeof(interface_sock);
 
   union sockaddr_46 interface_sock;
   EXIM_SOCKLEN_T size = sizeof(interface_sock);
 
-  HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("connected\n");
+  HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" connected\n");
   if (getsockname(sock, (struct sockaddr *)(&interface_sock), &size) == 0)
     sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port);
   else
   if (getsockname(sock, (struct sockaddr *)(&interface_sock), &size) == 0)
     sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port);
   else
@@ -467,7 +500,7 @@ else
     rc = n;
     }
   else
     rc = n;
     }
   else
-
+    {
     rc = send(outblock->cctx->sock, outblock->buffer, n,
 #ifdef MSG_MORE
              more ? MSG_MORE : 0
     rc = send(outblock->cctx->sock, outblock->buffer, n,
 #ifdef MSG_MORE
              more ? MSG_MORE : 0
@@ -475,6 +508,7 @@ else
              0
 #endif
             );
              0
 #endif
             );
+    }
   }
 
 if (rc <= 0)
   }
 
 if (rc <= 0)
@@ -521,8 +555,14 @@ if (format)
   gstring gs = { .size = big_buffer_size, .ptr = 0, .s = big_buffer };
   va_list ap;
 
   gstring gs = { .size = big_buffer_size, .ptr = 0, .s = big_buffer };
   va_list ap;
 
+  /* Use taint-unchecked routines for writing into big_buffer, trusting that
+  we'll never expand the results.  Actually, the error-message use - leaving
+  the results in big_buffer for potential later use - is uncomfortably distant.
+  XXX Would be better to assume all smtp commands are short, use normal pool
+  alloc rather than big_buffer, and another global for the data-for-error. */
+
   va_start(ap, format);
   va_start(ap, format);
-  if (!string_vformat(&gs, FALSE, CS format, ap))
+  if (!string_vformat(&gs, SVFMT_TAINT_NOCHK, CS format, ap))
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong write_command in outgoing "
       "SMTP");
   va_end(ap);
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong write_command in outgoing "
       "SMTP");
   va_end(ap);
@@ -538,7 +578,7 @@ if (format)
     if (!flush_buffer(outblock, SCMD_FLUSH)) return -1;
     }
 
     if (!flush_buffer(outblock, SCMD_FLUSH)) return -1;
     }
 
-  Ustrncpy(CS outblock->ptr, gs.s, gs.ptr);
+  Ustrncpy(outblock->ptr, gs.s, gs.ptr);
   outblock->ptr += gs.ptr;
   outblock->cmd_count++;
   gs.ptr -= 2; string_from_gstring(&gs); /* remove \r\n for error message */
   outblock->ptr += gs.ptr;
   outblock->cmd_count++;
   gs.ptr -= 2; string_from_gstring(&gs); /* remove \r\n for error message */
@@ -589,14 +629,14 @@ Arguments:
   inblock   the SMTP input block (contains holding buffer, socket, etc.)
   buffer    where to put the line
   size      space available for the line
   inblock   the SMTP input block (contains holding buffer, socket, etc.)
   buffer    where to put the line
   size      space available for the line
-  timeout   the timeout to use when reading a packet
+  timelimit deadline for reading the lime, seconds past epoch
 
 Returns:    length of a line that has been put in the buffer
             -1 otherwise, with errno set
 */
 
 static int
 
 Returns:    length of a line that has been put in the buffer
             -1 otherwise, with errno set
 */
 
 static int
-read_response_line(smtp_inblock *inblock, uschar *buffer, int size, int timeout)
+read_response_line(smtp_inblock *inblock, uschar *buffer, int size, time_t timelimit)
 {
 uschar *p = buffer;
 uschar *ptr = inblock->ptr;
 {
 uschar *p = buffer;
 uschar *ptr = inblock->ptr;
@@ -639,9 +679,9 @@ for (;;)
 
   /* Need to read a new input packet. */
 
 
   /* Need to read a new input packet. */
 
-  if((rc = ip_recv(cctx, inblock->buffer, inblock->buffersize, timeout)) <= 0)
+  if((rc = ip_recv(cctx, inblock->buffer, inblock->buffersize, timelimit)) <= 0)
     {
     {
-    DEBUG(D_deliver|D_transport|D_acl)
+    DEBUG(D_deliver|D_transport|D_acl|D_v)
       debug_printf_indent(errno ? "  SMTP(%s)<<\n" : "  SMTP(closed)<<\n",
        strerror(errno));
     break;
       debug_printf_indent(errno ? "  SMTP(%s)<<\n" : "  SMTP(closed)<<\n",
        strerror(errno));
     break;
@@ -696,10 +736,11 @@ smtp_read_response(void * sx0, uschar * buffer, int size, int okdigit,
 smtp_context * sx = sx0;
 uschar * ptr = buffer;
 int count = 0;
 smtp_context * sx = sx0;
 uschar * ptr = buffer;
 int count = 0;
+time_t timelimit = time(NULL) + timeout;
 
 errno = 0;  /* Ensure errno starts out zero */
 
 
 errno = 0;  /* Ensure errno starts out zero */
 
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifndef DISABLE_PIPE_CONNECT
 if (sx->pending_BANNER || sx->pending_EHLO)
   {
   int rc;
 if (sx->pending_BANNER || sx->pending_EHLO)
   {
   int rc;
@@ -718,7 +759,7 @@ response. */
 
 for (;;)
   {
 
 for (;;)
   {
-  if ((count = read_response_line(&sx->inblock, ptr, size, timeout)) < 0)
+  if ((count = read_response_line(&sx->inblock, ptr, size, timelimit)) < 0)
     return FALSE;
 
   HDEBUG(D_transport|D_acl|D_v)
     return FALSE;
 
   HDEBUG(D_transport|D_acl|D_v)