Add missing search_tidyup() calls for the subprocess used for running
[exim.git] / src / src / smtp_in.c
index 8bc12debfb26fbce983a47591ebbc6c94db1295a..f7549bb7c8580c3bb01825838945e3a9d4d75dbc 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/smtp_in.c,v 1.1 2004/10/07 10:39:01 ph10 Exp $ */
+/* $Cambridge: exim/src/src/smtp_in.c,v 1.21 2005/08/02 08:25:45 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2004 */
+/* Copyright (c) University of Cambridge 1995 - 2005 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions for handling an incoming SMTP call. */
@@ -34,9 +34,12 @@ int deny_severity  = LOG_NOTICE;
 #endif
 
 
-/* Size of buffer for reading SMTP commands */
+/* Size of buffer for reading SMTP commands. We used to use 512, as defined
+by RFC 821. However, RFC 1869 specifies that this must be increased for SMTP
+commands that accept arguments, and this in particular applies to AUTH, where
+the data can be quite long. */
 
-#define cmd_buffer_size  512      /* Ref. RFC 821 */
+#define cmd_buffer_size  2048
 
 /* Size of buffer for reading SMTP incoming packets */
 
@@ -167,17 +170,18 @@ static smtp_cmd_list *cmd_list_end =
 #define CMD_LIST_STARTTLS  4
 
 static uschar *protocols[] = {
-  US"local-smtp",
-  US"local-esmtp",
-  US"local-esmtpa",
-  US"local-esmtps",
-  US"local-esmtpsa"
+  US"local-smtp",        /* HELO */
+  US"local-smtps",       /* The rare case EHLO->STARTTLS->HELO */
+  US"local-esmtp",       /* EHLO */
+  US"local-esmtps",      /* EHLO->STARTTLS->EHLO */
+  US"local-esmtpa",      /* EHLO->AUTH */
+  US"local-esmtpsa"      /* EHLO->STARTTLS->EHLO->AUTH */
   };
 
 #define pnormal  0
-#define pextend  1
-#define pauthed  1  /* added to pextend */
-#define pcrpted  2  /* added to pextend */
+#define pextend  2
+#define pcrpted  1  /* added to pextend or pnormal */
+#define pauthed  2  /* added to pextend */
 #define pnlocal  6  /* offset to remove "local" */
 
 /* When reading SMTP from a remote host, we have to use our own versions of the
@@ -800,11 +804,18 @@ store_reset(reset_point);
 recipients_list = NULL;
 rcpt_count = rcpt_defer_count = rcpt_fail_count =
   raw_recipients_count = recipients_count = recipients_list_max = 0;
+message_linecount = 0;
 message_size = -1;
 acl_warn_headers = NULL;
 queue_only_policy = FALSE;
-deliver_freeze = FALSE;             /* Can be set by ACL */
-submission_mode = FALSE;            /* Can be set by ACL */
+deliver_freeze = FALSE;                              /* Can be set by ACL */
+fake_response = OK;                                  /* Can be set by ACL */
+#ifdef WITH_CONTENT_SCAN
+no_mbox_unspool = FALSE;                             /* Can be set by ACL */
+#endif
+submission_mode = FALSE;                             /* Can be set by ACL */
+active_local_from_check = local_from_check;          /* Can be set by ACL */
+active_local_sender_retain = local_sender_retain;    /* Can be set by ACL */
 sender_address = NULL;
 raw_sender = NULL;                  /* After SMTP rewrite, before qualifying */
 sender_address_unrewritten = NULL;  /* Set only after verify rewrite */
@@ -812,8 +823,25 @@ sender_verified_list = NULL;        /* No senders verified */
 memset(sender_address_cache, 0, sizeof(sender_address_cache));
 memset(sender_domain_cache, 0, sizeof(sender_domain_cache));
 authenticated_sender = NULL;
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+bmi_run = 0;
+bmi_verdicts = NULL;
+#endif
+#ifdef EXPERIMENTAL_DOMAINKEYS
+dk_do_verify = 0;
+#endif
+#ifdef EXPERIMENTAL_SPF
+spf_header_comment = NULL;
+spf_received = NULL;
+spf_result = NULL;
+spf_smtp_comment = NULL;
+#endif
 body_linecount = body_zerocount = 0;
 
+sender_rate = sender_rate_limit = sender_rate_period = NULL;
+ratelimiters_mail = NULL;           /* Updated by ratelimit ACL condition */
+                   /* Note that ratelimiters_conn persists across resets. */
+
 for (i = 0; i < ACL_M_MAX; i++) acl_var[ACL_C_MAX + i] = NULL;
 
 /* The message body variables use malloc store. They may be set if this is
@@ -1104,6 +1132,17 @@ int size = 256;
 int i, ptr;
 uschar *p, *s, *ss;
 
+/* If we are running in the test harness, and the incoming call is from
+127.0.0.2 (sic), have a short delay. This makes it possible to test handling of
+input sent too soon (before the banner is output). */
+
+if (running_in_test_harness &&
+    sender_host_address != NULL &&
+    Ustrcmp(sender_host_address, "127.0.0.2") == 0)
+  sleep(1);
+
+/* Default values for certain variables */
+
 helo_seen = esmtp = helo_accept_junk = FALSE;
 count_nonmail = TRUE_UNSET;
 synprot_error_count = unknown_command_count = nonmail_command_count = 0;
@@ -1231,16 +1270,16 @@ if (!sender_host_unknown)
   if (!host_checking && !sender_host_notsocket)
     {
     #if OPTSTYLE == 1
-    SOCKLEN_T optlen = sizeof(struct ip_options) + MAX_IPOPTLEN;
+    EXIM_SOCKLEN_T optlen = sizeof(struct ip_options) + MAX_IPOPTLEN;
     struct ip_options *ipopt = store_get(optlen);
     #elif OPTSTYLE == 2
     struct ip_opts ipoptblock;
     struct ip_opts *ipopt = &ipoptblock;
-    SOCKLEN_T optlen = sizeof(ipoptblock);
+    EXIM_SOCKLEN_T optlen = sizeof(ipoptblock);
     #else
     struct ipoption ipoptblock;
     struct ipoption *ipopt = &ipoptblock;
-    SOCKLEN_T optlen = sizeof(ipoptblock);
+    EXIM_SOCKLEN_T optlen = sizeof(ipoptblock);
     #endif
 
     /* Occasional genuine failures of getsockopt() have been seen - for
@@ -1581,11 +1620,18 @@ if (smtp_enforce_sync && sender_host_address != NULL && !sender_host_notsocket)
   if (select(fileno(smtp_in) + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL,
       &tzero) > 0)
     {
-    log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol violation: "
-      "synchronization error (input sent without waiting for greeting): "
-      "rejected connection from %s", host_and_ident(TRUE));
-    smtp_printf("554 SMTP synchronization error\r\n");
-    return FALSE;
+    int rc = read(fileno(smtp_in), smtp_inbuffer, in_buffer_size);
+    if (rc > 0)
+      {
+      if (rc > 150) rc = 150;
+      smtp_inbuffer[rc] = 0;
+      log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol "
+        "synchronization error (input sent without waiting for greeting): "
+        "rejected connection from %s input=\"%s\"", host_and_ident(TRUE),
+        string_printing(smtp_inbuffer));
+      smtp_printf("554 SMTP synchronization error\r\n");
+      return FALSE;
+      }
     }
   }
 
@@ -1771,6 +1817,9 @@ BOOL drop = rc == FAIL_DROP;
 uschar *lognl;
 uschar *sender_info = US"";
 uschar *what = (where == ACL_WHERE_PREDATA)? US"DATA" :
+#ifdef WITH_CONTENT_SCAN
+               (where == ACL_WHERE_MIME)? US"during MIME ACL checks" :
+#endif
                (where == ACL_WHERE_DATA)? US"after DATA" :
   string_sprintf("%s %s", acl_wherenames[where], smtp_data);
 
@@ -1782,7 +1831,11 @@ fixed, sender_address at this point became the rewritten address. I'm not sure
 this is what should be logged, so I've changed to logging the unrewritten
 address to retain backward compatibility. */
 
+#ifndef WITH_CONTENT_SCAN
 if (where == ACL_WHERE_RCPT || where == ACL_WHERE_DATA)
+#else
+if (where == ACL_WHERE_RCPT || where == ACL_WHERE_DATA || where == ACL_WHERE_MIME)
+#endif
   {
   sender_info = string_sprintf("F=<%s> ", (sender_address_unrewritten != NULL)?
     sender_address_unrewritten : sender_address);
@@ -2065,6 +2118,14 @@ while (done <= 0)
     if (au->set_id != NULL) set_id = expand_string(au->set_id);
     expand_nmax = -1;        /* Reset numeric variables */
 
+    /* The value of authenticated_id is stored in the spool file and printed in
+    log lines. It must not contain binary zeros or newline characters. In
+    normal use, it never will, but when playing around or testing, this error
+    can (did) happen. To guard against this, ensure that the id contains only
+    printing characters. */
+
+    if (set_id != NULL) set_id = string_printing(set_id);
+
     /* For the non-OK cases, set up additional logging data if set_id
     is not empty. */
 
@@ -2337,6 +2398,11 @@ while (done <= 0)
         }
       }
 
+#ifdef EXPERIMENTAL_SPF
+    /* set up SPF context */
+    spf_init(sender_helo_name, sender_host_address);
+#endif
+
     /* Apply an ACL check if one is defined */
 
     if (acl_smtp_helo != NULL)
@@ -2360,7 +2426,7 @@ while (done <= 0)
         ((sender_host_authenticated != NULL)? pauthed : 0) +
         ((tls_active >= 0)? pcrpted : 0)]
       :
-      protocols[pnormal])
+      protocols[pnormal + ((tls_active >= 0)? pcrpted : 0)])
       +
       ((sender_host_address != NULL)? pnlocal : 0);
 
@@ -2527,7 +2593,7 @@ while (done <= 0)
     if (tls_active >= 0) (void)tls_write(s, ptr); else
     #endif
 
-    fwrite(s, 1, ptr, smtp_out);
+    (void)fwrite(s, 1, ptr, smtp_out);
     DEBUG(D_receive) debug_printf("SMTP>> %s", s);
     helo_seen = TRUE;
     break;   /* HELO/EHLO */
@@ -3032,8 +3098,13 @@ while (done <= 0)
       break;
       }
 
-    rc = (acl_smtp_predata == NULL)? OK :
-      acl_check(ACL_WHERE_PREDATA, NULL, acl_smtp_predata, &user_msg, &log_msg);
+    if (acl_smtp_predata == NULL) rc = OK; else
+      {
+      enable_dollar_recipients = TRUE;
+      rc = acl_check(ACL_WHERE_PREDATA, NULL, acl_smtp_predata, &user_msg,
+        &log_msg);
+      enable_dollar_recipients = FALSE;
+      }
 
     if (rc == OK)
       {
@@ -3071,7 +3142,7 @@ while (done <= 0)
         {
         address_item *addr = deliver_make_addr(address, FALSE);
         switch(verify_address(addr, NULL, vopt_is_recipient | vopt_qualify, -1,
-               -1, NULL, NULL, NULL))
+               -1, -1, NULL, NULL, NULL))
           {
           case OK:
           s = string_sprintf("250 <%s> is deliverable", address);
@@ -3108,7 +3179,8 @@ while (done <= 0)
       BOOL save_log_testing_mode = log_testing_mode;
       address_test_mode = log_testing_mode = TRUE;
       (void) verify_address(deliver_make_addr(smtp_data, FALSE), smtp_out,
-        vopt_is_recipient | vopt_qualify | vopt_expn, -1, -1, NULL, NULL, NULL);
+        vopt_is_recipient | vopt_qualify | vopt_expn, -1, -1, -1, NULL, NULL,
+        NULL);
       address_test_mode = FALSE;
       log_testing_mode = save_log_testing_mode;    /* true for -bh */
       }
@@ -3174,7 +3246,7 @@ while (done <= 0)
         protocols[pextend + pcrpted +
           ((sender_host_authenticated != NULL)? pauthed : 0)]
         :
-        protocols[pnormal])
+        protocols[pnormal + pcrpted])
         +
         ((sender_host_address != NULL)? pnlocal : 0);
 
@@ -3411,9 +3483,9 @@ while (done <= 0)
 
     if ((pid = fork()) == 0)
       {
-      smtp_input = FALSE;    /* This process is not associated with the */
-      fclose(smtp_in);       /* SMTP call any more. */
-      fclose(smtp_out);
+      smtp_input = FALSE;       /* This process is not associated with the */
+      (void)fclose(smtp_in);    /* SMTP call any more. */
+      (void)fclose(smtp_out);
 
       signal(SIGCHLD, SIG_DFL);      /* Want to catch child */
 
@@ -3490,8 +3562,7 @@ while (done <= 0)
     if (c > 150) c = 150;
     smtp_inptr[c] = 0;
     incomplete_transaction_log(US"sync failure");
-    log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol violation: "
-      "synchronization error "
+    log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol synchronization error "
       "(next input sent too soon: pipelining was%s advertised): "
       "rejected \"%s\" %s next input=\"%s\"",
       pipelining_advertised? "" : " not",