Callouts: a "hold" option for receipient-verify, which keeps the connection open...
[exim.git] / src / src / smtp_in.c
index bd83de0456b0322662a9a51f1be93295d6b7a8c6..3c40a5c61bcd5ae399e8034cde75c202dc6039d6 100644 (file)
@@ -304,7 +304,6 @@ static int     smtp_had_error;
 
 
 /* forward declarations */
-int bdat_ungetc(int ch);
 static int smtp_read_command(BOOL check_sync, unsigned buffer_lim);
 static int synprot_error(int type, int code, uschar *data, uschar *errmess);
 static void smtp_quit_handler(uschar **, uschar **);
@@ -486,12 +485,17 @@ uschar * log_msg;
 
 for(;;)
   {
+#ifndef DISABLE_DKIM
+  BOOL dkim_save;
+#endif
+
   if (chunking_data_left > 0)
     return lwr_receive_getc(chunking_data_left--);
 
   receive_getc = lwr_receive_getc;
   receive_ungetc = lwr_receive_ungetc;
 #ifndef DISABLE_DKIM
+  dkim_save = dkim_collect_input;
   dkim_collect_input = FALSE;
 #endif
 
@@ -592,7 +596,7 @@ next_cmd:
       receive_getc = bdat_getc;
       receive_ungetc = bdat_ungetc;
 #ifndef DISABLE_DKIM
-      dkim_collect_input = TRUE;
+      dkim_collect_input = dkim_save;
 #endif
       break;   /* to top of main loop */
       }
@@ -945,43 +949,45 @@ Return the amount read.
 static int
 swallow_until_crlf(int fd, uschar *base, int already, int capacity)
 {
-  uschar *to = base + already;
-  uschar *cr;
-  int have = 0;
-  int ret;
-  int last = 0;
-
-  /* For "PROXY UNKNOWN\r\n" we, at time of writing, expect to have read
-  up through the \r; for the _normal_ case, we haven't yet seen the \r. */
-  cr = memchr(base, '\r', already);
-  if (cr != NULL)
-    {
-    if ((cr - base) < already - 1)
-      {
-      /* \r and presumed \n already within what we have; probably not
-      actually proxy protocol, but abort cleanly. */
-      return 0;
-      }
-    /* \r is last character read, just need one more. */
-    last = 1;
-    }
+uschar *to = base + already;
+uschar *cr;
+int have = 0;
+int ret;
+int last = 0;
+
+/* For "PROXY UNKNOWN\r\n" we, at time of writing, expect to have read
+up through the \r; for the _normal_ case, we haven't yet seen the \r. */
 
-  while (capacity > 0)
+cr = memchr(base, '\r', already);
+if (cr != NULL)
+  {
+  if ((cr - base) < already - 1)
     {
-    do { ret = recv(fd, to, 1, 0); } while (ret == -1 && errno == EINTR);
-    if (ret == -1)
-      return -1;
-    have++;
-    if (last)
-      return have;
-    if (*to == '\r')
-      last = 1;
-    capacity--;
-    to++;
+    /* \r and presumed \n already within what we have; probably not
+    actually proxy protocol, but abort cleanly. */
+    return 0;
     }
-  // reached end without having room for a final newline, abort
-  errno = EOVERFLOW;
-  return -1;
+  /* \r is last character read, just need one more. */
+  last = 1;
+  }
+
+while (capacity > 0)
+  {
+  do { ret = recv(fd, to, 1, 0); } while (ret == -1 && errno == EINTR);
+  if (ret == -1)
+    return -1;
+  have++;
+  if (last)
+    return have;
+  if (*to == '\r')
+    last = 1;
+  capacity--;
+  to++;
+  }
+
+/* reached end without having room for a final newline, abort */
+errno = EOVERFLOW;
+return -1;
 }
 
 /*************************************************
@@ -1089,9 +1095,9 @@ if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CS &tv, sizeof(tv)) < 0)
 do
   {
   /* The inbound host was declared to be a Proxy Protocol host, so
-     don't do a PEEK into the data, actually slurp up enough to be
-     "safe". Can't take it all because TLS-on-connect clients follow
-     immediately with TLS handshake. */
+  don't do a PEEK into the data, actually slurp up enough to be
+  "safe". Can't take it all because TLS-on-connect clients follow
+  immediately with TLS handshake. */
   ret = recv(fd, &hdr, PROXY_INITIAL_READ, 0);
   }
   while (ret == -1 && errno == EINTR);
@@ -1117,9 +1123,9 @@ if ((ret == PROXY_INITIAL_READ) && (memcmp(&hdr.v2, v2sig, sizeof(v2sig)) == 0))
   ver = (hdr.v2.ver_cmd & 0xf0) >> 4;
 
   /* May 2014: haproxy combined the version and command into one byte to
-     allow two full bytes for the length field in order to proxy SSL
-     connections.  SSL Proxy is not supported in this version of Exim, but
-     must still separate values here. */
+  allow two full bytes for the length field in order to proxy SSL
+  connections.  SSL Proxy is not supported in this version of Exim, but
+  must still separate values here. */
 
   if (ver != 0x02)
     {
@@ -1266,7 +1272,7 @@ else if (ret >= 8 && memcmp(hdr.v1.line, "PROXY", 5) == 0)
   DEBUG(D_receive) debug_printf("Detected PROXYv1 header\n");
   DEBUG(D_receive) debug_printf("Bytes read not within PROXY header: %d\n", ret - size);
   /* Step through the string looking for the required fields. Ensure
-     strict adherence to required formatting, exit for any error. */
+  strict adherence to required formatting, exit for any error. */
   p += 5;
   if (!isspace(*(p++)))
     {
@@ -1881,7 +1887,6 @@ smtp_reset(void *reset_point)
 recipients_list = NULL;
 rcpt_count = rcpt_defer_count = rcpt_fail_count =
   raw_recipients_count = recipients_count = recipients_list_max = 0;
-cancel_cutthrough_connection("smtp reset");
 message_linecount = 0;
 message_size = -1;
 acl_added_headers = NULL;
@@ -2012,6 +2017,7 @@ bsmtp_transaction_linecount = receive_linecount;
 
 if ((receive_feof)()) return 0;   /* Treat EOF as QUIT */
 
+cancel_cutthrough_connection(TRUE, US"smtp_setup_batch_msg");
 smtp_reset(reset_point);                /* Reset for start of message */
 
 /* Deal with SMTP commands. This loop is exited by setting done to a POSITIVE
@@ -2036,6 +2042,7 @@ while (done <= 0)
     /* Fall through */
 
     case RSET_CMD:
+    cancel_cutthrough_connection(TRUE, US"RSET received");
     smtp_reset(reset_point);
     bsmtp_transaction_linecount = receive_linecount;
     break;
@@ -2059,6 +2066,7 @@ while (done <= 0)
 
     /* Reset to start of message */
 
+    cancel_cutthrough_connection(TRUE, US"MAIL received");
     smtp_reset(reset_point);
 
     /* Apply SMTP rewrite */
@@ -2218,6 +2226,19 @@ return done - 2;  /* Convert yield values */
 
 
 
+static BOOL
+smtp_log_tls_fail(uschar * errstr)
+{
+uschar * conn_info = smtp_get_connection_info();
+
+if (Ustrncmp(conn_info, US"SMTP ", 5) == 0) conn_info += 5;
+/* I'd like to get separated H= here, but too hard for now */
+
+log_write(0, LOG_MAIN, "TLS error on %s %s", conn_info, errstr);
+return FALSE;
+}
+
+
 /*************************************************
 *          Start an SMTP session                 *
 *************************************************/
@@ -2706,8 +2727,8 @@ if (check_proxy_protocol_host())
   smtps port for use with older style SSL MTAs. */
 
 #ifdef SUPPORT_TLS
-  if (tls_in.on_connect && tls_server_start(tls_require_ciphers) != OK)
-    return FALSE;
+  if (tls_in.on_connect && tls_server_start(tls_require_ciphers, &user_msg) != OK)
+    return smtp_log_tls_fail(user_msg);
 #endif
 
 /* Run the connect ACL if it exists */
@@ -4234,6 +4255,7 @@ while (done <= 0)
          : pnormal)
        + (tls_in.active >= 0 ? pcrpted : 0)
        ];
+    cancel_cutthrough_connection(TRUE, US"sent EHLO response");
     smtp_reset(reset_point);
     toomany = FALSE;
     break;   /* HELO/EHLO */
@@ -4288,6 +4310,7 @@ while (done <= 0)
     /* Reset for start of message - even if this is going to fail, we
     obviously need to throw away any previous data. */
 
+    cancel_cutthrough_connection(TRUE, US"MAIL received");
     smtp_reset(reset_point);
     toomany = FALSE;
     sender_data = recipient_data = NULL;
@@ -5143,6 +5166,7 @@ while (done <= 0)
     do an implied RSET when STARTTLS is received. */
 
     incomplete_transaction_log(US"STARTTLS");
+    cancel_cutthrough_connection(TRUE, US"STARTTLS received");
     smtp_reset(reset_point);
     toomany = FALSE;
     cmd_list[CMD_LIST_STARTTLS].is_mail_cmd = FALSE;
@@ -5181,7 +5205,8 @@ while (done <= 0)
     We must allow for an extra EHLO command and an extra AUTH command after
     STARTTLS that don't add to the nonmail command count. */
 
-    if ((rc = tls_server_start(tls_require_ciphers)) == OK)
+    s = NULL;
+    if ((rc = tls_server_start(tls_require_ciphers, &s)) == OK)
       {
       if (!tls_remember_esmtp)
         helo_seen = esmtp = auth_advertised = pipelining_advertised = FALSE;
@@ -5210,11 +5235,13 @@ while (done <= 0)
       DEBUG(D_tls) debug_printf("TLS active\n");
       break;     /* Successful STARTTLS */
       }
+    else
+      (void) smtp_log_tls_fail(s);
 
     /* Some local configuration problem was discovered before actually trying
     to do a TLS handshake; give a temporary error. */
 
-    else if (rc == DEFER)
+    if (rc == DEFER)
       {
       smtp_printf("454 TLS currently unavailable\r\n");
       break;
@@ -5276,6 +5303,7 @@ while (done <= 0)
 
     case RSET_CMD:
     smtp_rset_handler();
+    cancel_cutthrough_connection(TRUE, US"RSET received");
     smtp_reset(reset_point);
     toomany = FALSE;
     break;