Create a hosts_try_dane transport option, does nothing yet
[users/jgh/exim.git] / src / src / receive.c
index 56de9fbb30dda6228a19891ebb5ebd3b2544c763..f27dc425ebb9fc64f13970537c2c8070c3898101 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2012 */
+/* Copyright (c) University of Cambridge 1995 - 2014 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Code for receiving a message and setting up spool files. */
 extern int dcc_ok;
 #endif
 
+#ifdef EXPERIMENTAL_DMARC
+# include "dmarc.h"
+#endif /* EXPERIMENTAL_DMARC */
+
 /*************************************************
 *                Local static variables          *
 *************************************************/
@@ -493,6 +497,10 @@ recipients_list[recipients_count].bmi_optin = bmi_current_optin;
 /* reset optin string pointer for next recipient */
 bmi_current_optin = NULL;
 #endif
+#ifdef EXPERIMENTAL_DSN
+recipients_list[recipients_count].orcpt = NULL;
+recipients_list[recipients_count].dsn_flags = 0;
+#endif
 recipients_list[recipients_count++].errors_to = NULL;
 }
 
@@ -502,30 +510,32 @@ recipients_list[recipients_count++].errors_to = NULL;
 /*************************************************
 *        Send user response message              *
 *************************************************/
-        
+
 /* This function is passed a default response code and a user message. It calls
 smtp_message_code() to check and possibly modify the response code, and then
 calls smtp_respond() to transmit the response. I put this into a function
 just to avoid a lot of repetition.
-            
-Arguments:               
+
+Arguments:
   code         the response code
   user_msg     the user message
 
 Returns:       nothing
-*/        
-            
-static void 
+*/
+
+#ifndef DISABLE_PRDR
+static void
 smtp_user_msg(uschar *code, uschar *user_msg)
-{           
+{
 int len = 3;
 smtp_message_code(&code, &len, &user_msg, NULL);
 smtp_respond(code, len, TRUE, user_msg);
-}           
-                        
-            
-          
-          
+}
+#endif
+
+
+
+
 
 /*************************************************
 *        Remove a recipient from the list        *
@@ -674,6 +684,7 @@ while ((ch = (receive_getc)()) != EOF)
 
     case 1:                         /* After written "\n" */
     if (ch == '.') { ch_state = 3; continue; }
+    if (ch == '\r') { ch_state = 2; continue; }
     if (ch != '\n') ch_state = 0; else linelength = -1;
     break;
 
@@ -978,11 +989,24 @@ Returns:     nothing
 */
 
 static void
-add_acl_headers(uschar *acl_name)
+add_acl_headers(int where, uschar *acl_name)
 {
 header_line *h, *next;
 header_line *last_received = NULL;
 
+switch(where)
+  {
+  case ACL_WHERE_DKIM:
+  case ACL_WHERE_MIME:
+  case ACL_WHERE_DATA:
+    if (cutthrough_fd >= 0 && (acl_removed_headers || acl_added_headers))
+    {
+    log_write(0, LOG_MAIN|LOG_PANIC, "Header modification in data ACLs"
+                       " will not take effect on cutthrough deliveries");
+    return;
+    }
+  }
+
 if (acl_removed_headers != NULL)
   {
   DEBUG(D_receive|D_acl) debug_printf(">>Headers removed by %s ACL:\n", acl_name);
@@ -1258,7 +1282,7 @@ if (rc == OK)
   }
 
 END_MIME_ACL:
-add_acl_headers(US"MIME");
+add_acl_headers(ACL_WHERE_MIME, US"MIME");
 if (rc == DISCARD)
   {
   recipients_count = 0;
@@ -1271,9 +1295,10 @@ else if (rc != OK)
 #ifdef EXPERIMENTAL_DCC
   dcc_ok = 0;
 #endif
-  if (smtp_handle_acl_fail(ACL_WHERE_MIME, rc, user_msg, log_msg) != 0)
+  if (smtp_input && smtp_handle_acl_fail(ACL_WHERE_MIME, rc, user_msg, log_msg) != 0) {
     *smtp_yield_ptr = FALSE;    /* No more messsages after dropped connection */
-  *smtp_reply_ptr = US"";       /* Indicate reply already sent */
+    *smtp_reply_ptr = US"";     /* Indicate reply already sent */
+  }
   message_id[0] = 0;            /* Indicate no message accepted */
   return FALSE;                 /* Cause skip to end of receive function */
   }
@@ -1447,7 +1472,7 @@ BOOL resents_exist = FALSE;
 uschar *resent_prefix = US"";
 uschar *blackholed_by = NULL;
 uschar *blackhole_log_msg = US"";
-int  cutthrough_done = 0;
+enum {NOT_TRIED, TMP_REJ, PERM_REJ, ACCEPTED} cutthrough_done = NOT_TRIED;
 
 flock_t lock_data;
 error_block *bad_addresses = NULL;
@@ -1478,6 +1503,10 @@ header_line *subject_header = NULL;
 header_line *msgid_header = NULL;
 header_line *received_header;
 
+#ifdef EXPERIMENTAL_DMARC
+int dmarc_up = 0;
+#endif /* EXPERIMENTAL_DMARC */
+
 /* Variables for use when building the Received: header. */
 
 uschar *timestamp;
@@ -1534,6 +1563,11 @@ message_linecount = body_linecount = body_zerocount =
 if (smtp_input && !smtp_batched_input && !dkim_disable_verify) dkim_exim_verify_init();
 #endif
 
+#ifdef EXPERIMENTAL_DMARC
+/* initialize libopendmarc */
+dmarc_up = dmarc_init();
+#endif
+
 /* Remember the time of reception. Exim uses time+pid for uniqueness of message
 ids, and fractions of a second are required. See the comments that precede the
 message id creation below. */
@@ -2704,7 +2738,6 @@ if (from_header != NULL &&
     }
   }
 
-
 /* If there are any rewriting rules, apply them to the sender address, unless
 it has already been rewritten as part of verification for SMTP input. */
 
@@ -2811,10 +2844,10 @@ if (cutthrough_fd >= 0)
     goto TIDYUP;                             /* Skip to end of function */
     }
   received_header_gen();
-  add_acl_headers(US"MAIL or RCPT");
+  add_acl_headers(ACL_WHERE_RCPT, US"MAIL or RCPT");
   (void) cutthrough_headers_send();
   }
+
 
 /* Open a new spool file for the data portion of the message. We need
 to access it both via a file descriptor and a stream. Try to make the
@@ -3103,7 +3136,7 @@ if (received_header->text == NULL)        /* Non-cutthrough case */
   /* If an ACL from any RCPT commands set up any warning headers to add, do so
   now, before running the DATA ACL. */
 
-  add_acl_headers(US"MAIL or RCPT");
+  add_acl_headers(ACL_WHERE_RCPT, US"MAIL or RCPT");
   }
 else
   message_body_size = (fstat(data_fd, &statbuf) == 0)?
@@ -3177,7 +3210,7 @@ else
               uschar seen_item_buf[256];
               uschar *seen_items_list = seen_items;
               int seen_this_item = 0;
-              
+
               while ((seen_item = string_nextinlist(&seen_items_list, &sep,
                                                     seen_item_buf,
                                                     sizeof(seen_item_buf))) != NULL)
@@ -3186,7 +3219,7 @@ else
                     {
                       seen_this_item = 1;
                       break;
-                    } 
+                    }
                 }
 
               if (seen_this_item > 0)
@@ -3195,7 +3228,7 @@ else
                   debug_printf("acl_smtp_dkim: skipping signer %s, already seen\n", item);
                 continue;
                 }
-              
+
               seen_items = string_append(seen_items,&seen_items_size,&seen_items_offset,1,":");
               }
 
@@ -3216,7 +3249,7 @@ else
                 break;
               }
             }
-          add_acl_headers(US"DKIM");
+          add_acl_headers(ACL_WHERE_DKIM, US"DKIM");
           if (rc == DISCARD)
             {
             recipients_count = 0;
@@ -3245,8 +3278,12 @@ else
       goto TIDYUP;
 #endif /* WITH_CONTENT_SCAN */
 
-#ifdef EXPERIMENTAL_PRDR
-    if (prdr_requested && recipients_count > 1 && acl_smtp_data_prdr != NULL )
+#ifdef EXPERIMENTAL_DMARC
+    dmarc_up = dmarc_store_data(from_header);
+#endif /* EXPERIMENTAL_DMARC */
+
+#ifndef DISABLE_PRDR
+    if (prdr_requested && recipients_count > 1 && acl_smtp_data_prdr)
       {
       unsigned int c;
       int all_pass = OK;
@@ -3293,7 +3330,7 @@ else
          }
        if (log_msg)       log_write(0, LOG_MAIN, "PRDR %s %s", addr, log_msg);
        else if (user_msg) log_write(0, LOG_MAIN, "PRDR %s %s", addr, user_msg);
-       else               log_write(0, LOG_MAIN, CS msg);
+       else               log_write(0, LOG_MAIN, "%s", CS msg);
 
        if (rc != OK) { receive_remove_recipient(addr); c--; }
         }
@@ -3314,7 +3351,7 @@ else
       }
     else
       prdr_requested = FALSE;
-#endif /* EXPERIMENTAL_PRDR */
+#endif /* !DISABLE_PRDR */
 
     /* Check the recipients count again, as the MIME ACL might have changed
     them. */
@@ -3322,7 +3359,7 @@ else
     if (acl_smtp_data != NULL && recipients_count > 0)
       {
       rc = acl_check(ACL_WHERE_DATA, NULL, acl_smtp_data, &user_msg, &log_msg);
-      add_acl_headers(US"DATA");
+      add_acl_headers(ACL_WHERE_DATA, US"DATA");
       if (rc == DISCARD)
         {
         recipients_count = 0;
@@ -3405,7 +3442,7 @@ else
           /* Does not return */
           }
         }
-      add_acl_headers(US"non-SMTP");
+      add_acl_headers(ACL_WHERE_NOTSMTP, US"non-SMTP");
       }
     }
 
@@ -3707,21 +3744,20 @@ if (message_reference != NULL)
 s = add_host_info_for_log(s, &size, &sptr);
 
 #ifdef SUPPORT_TLS
-if ((log_extra_selector & LX_tls_cipher) != 0 && tls_in.cipher != NULL)
+if (log_extra_selector & LX_tls_cipher && tls_in.cipher)
   s = string_append(s, &size, &sptr, 2, US" X=", tls_in.cipher);
-if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
-     tls_in.cipher != NULL)
+if (log_extra_selector & LX_tls_certificate_verified && tls_in.cipher)
   s = string_append(s, &size, &sptr, 2, US" CV=",
     tls_in.certificate_verified? "yes":"no");
-if ((log_extra_selector & LX_tls_peerdn) != 0 && tls_in.peerdn != NULL)
+if (log_extra_selector & LX_tls_peerdn && tls_in.peerdn)
   s = string_append(s, &size, &sptr, 3, US" DN=\"",
     string_printing(tls_in.peerdn), US"\"");
-if ((log_extra_selector & LX_tls_sni) != 0 && tls_in.sni != NULL)
+if (log_extra_selector & LX_tls_sni && tls_in.sni)
   s = string_append(s, &size, &sptr, 3, US" SNI=\"",
     string_printing(tls_in.sni), US"\"");
 #endif
 
-if (sender_host_authenticated != NULL)
+if (sender_host_authenticated)
   {
   s = string_append(s, &size, &sptr, 2, US" A=", sender_host_authenticated);
   if (authenticated_id != NULL)
@@ -3732,11 +3768,16 @@ if (sender_host_authenticated != NULL)
     }
   }
 
-#ifdef EXPERIMENTAL_PRDR
+#ifndef DISABLE_PRDR
 if (prdr_requested)
   s = string_append(s, &size, &sptr, 1, US" PRDR");
 #endif
 
+#ifdef EXPERIMENTAL_PROXY
+if (proxy_session &&  log_extra_selector & LX_proxy)
+  s = string_append(s, &size, &sptr, 2, US" PRX=", proxy_host_address);
+#endif
+
 sprintf(CS big_buffer, "%d", msg_size);
 s = string_append(s, &size, &sptr, 2, US" S=", big_buffer);
 
@@ -3930,7 +3971,6 @@ for this message. */
 
    XXX We do not handle queue-only, freezing, or blackholes.
 */
-cutthrough_done = 0;
 if(cutthrough_fd >= 0)
   {
   uschar * msg= cutthrough_finaldot(); /* Ask the target system to accept the messsage */
@@ -3938,26 +3978,26 @@ if(cutthrough_fd >= 0)
   switch(msg[0])
     {
     case '2':  /* Accept. Do the same to the source; dump any spoolfiles.   */
-      cutthrough_done = 3;
+      cutthrough_done = ACCEPTED;
       break;                                   /* message_id needed for SMTP accept below */
-  
+
     default:   /* Unknown response, or error.  Treat as temp-reject.         */
     case '4':  /* Temp-reject. Keep spoolfiles and accept. */
-      cutthrough_done = 1;                     /* Avoid the usual immediate delivery attempt */
+      cutthrough_done = TMP_REJ;               /* Avoid the usual immediate delivery attempt */
       break;                                   /* message_id needed for SMTP accept below */
-  
+
     case '5':  /* Perm-reject.  Do the same to the source.  Dump any spoolfiles */
       smtp_reply= msg;         /* Pass on the exact error */
-      cutthrough_done = 2;
+      cutthrough_done = PERM_REJ;
       break;
     }
   }
 
-if(smtp_reply == NULL
-#ifdef EXPERIMENTAL_PRDR
-                     || prdr_requested
+#ifndef DISABLE_PRDR
+if(!smtp_reply || prdr_requested)
+#else
+if(!smtp_reply)
 #endif
-  )
   {
   log_write(0, LOG_MAIN |
     (((log_extra_selector & LX_received_recipients) != 0)? LOG_RECIPIENTS : 0) |
@@ -4062,8 +4102,8 @@ if (smtp_input)
 
     switch (cutthrough_done)
       {
-      case 3: log_write(0, LOG_MAIN, "Completed");     /* Delivery was done */
-      case 2: {                                                /* Delete spool files */
+      case ACCEPTED: log_write(0, LOG_MAIN, "Completed");/* Delivery was done */
+      case PERM_REJ: {                                 /* Delete spool files */
              sprintf(CS spool_name, "%s/input/%s/%s-D", spool_directory,
                message_subdir, message_id);
              Uunlink(spool_name);
@@ -4074,7 +4114,7 @@ if (smtp_input)
                message_subdir, message_id);
              Uunlink(spool_name);
              }
-      case 1: message_id[0] = 0;                       /* Prevent a delivery from starting */
+      case TMP_REJ: message_id[0] = 0;   /* Prevent a delivery from starting */
       default:break;
       }
     cutthrough_delivery = FALSE;