A tweak to change PH/13, so that verify=helo never defers (as in 4.52).
[exim.git] / src / src / acl.c
index f4788d19e55b94a8c575c688f96530a6900391e1..c06707ec68ffebaf1e72c4adba9cce1e719782b0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/acl.c,v 1.43 2005/08/02 15:19:20 ph10 Exp $ */
+/* $Cambridge: exim/src/src/acl.c,v 1.49 2005/09/22 12:02:22 fanf2 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -140,13 +140,16 @@ enum {
 #endif
   CONTROL_ERROR, CONTROL_CASEFUL_LOCAL_PART, CONTROL_CASELOWER_LOCAL_PART,
   CONTROL_ENFORCE_SYNC, CONTROL_NO_ENFORCE_SYNC, CONTROL_FREEZE,
-  CONTROL_QUEUE_ONLY, CONTROL_SUBMISSION,
+  CONTROL_QUEUE_ONLY, CONTROL_SUBMISSION, CONTROL_SUPPRESS_LOCAL_FIXUPS,
 #ifdef WITH_CONTENT_SCAN
   CONTROL_NO_MBOX_UNSPOOL,
 #endif
   CONTROL_FAKEDEFER, CONTROL_FAKEREJECT, CONTROL_NO_MULTILINE };
 
-/* ACL control names; keep in step with the table above! */
+/* ACL control names; keep in step with the table above! This list is used for
+turning ids into names. The actual list of recognized names is in the variable
+control_def controls_list[] below. The fact that there are two lists is a mess
+and should be tidied up. */
 
 static uschar *controls[] = {
   #ifdef EXPERIMENTAL_BRIGHTMAIL
@@ -157,10 +160,11 @@ static uschar *controls[] = {
   #endif
   US"error", US"caseful_local_part",
   US"caselower_local_part", US"enforce_sync", US"no_enforce_sync", US"freeze",
-  US"queue_only", US"submission",
+  US"queue_only", US"submission", US"suppress_local_fixups",
   #ifdef WITH_CONTENT_SCAN
   US"no_mbox_unspool",
   #endif
+
   US"no_multiline"};
 
 /* Flags to indicate for which conditions /modifiers a string expansion is done
@@ -482,6 +486,10 @@ static unsigned int control_forbids[] = {
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* submission */
     (1<<ACL_WHERE_PREDATA)),
 
+  (unsigned int)
+  ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* suppress_local_fixups */
+    (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_PREDATA)),
+
 #ifdef WITH_CONTENT_SCAN
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* no_mbox_unspool */
@@ -512,24 +520,25 @@ typedef struct control_def {
 
 static control_def controls_list[] = {
 #ifdef EXPERIMENTAL_BRIGHTMAIL
-  { US"bmi_run",                CONTROL_BMI_RUN, FALSE},
+  { US"bmi_run",                CONTROL_BMI_RUN, FALSE },
 #endif
 #ifdef EXPERIMENTAL_DOMAINKEYS
-  { US"dk_verify",              CONTROL_DK_VERIFY, FALSE},
-#endif
-  { US"caseful_local_part",     CONTROL_CASEFUL_LOCAL_PART, FALSE},
-  { US"caselower_local_part",   CONTROL_CASELOWER_LOCAL_PART, FALSE},
-  { US"enforce_sync",           CONTROL_ENFORCE_SYNC, FALSE},
-  { US"freeze",                 CONTROL_FREEZE, FALSE},
-  { US"no_enforce_sync",        CONTROL_NO_ENFORCE_SYNC, FALSE},
-  { US"no_multiline_responses", CONTROL_NO_MULTILINE, FALSE},
-  { US"queue_only",             CONTROL_QUEUE_ONLY, FALSE},
+  { US"dk_verify",              CONTROL_DK_VERIFY, FALSE },
+#endif
+  { US"caseful_local_part",     CONTROL_CASEFUL_LOCAL_PART, FALSE },
+  { US"caselower_local_part",   CONTROL_CASELOWER_LOCAL_PART, FALSE },
+  { US"enforce_sync",           CONTROL_ENFORCE_SYNC, FALSE },
+  { US"freeze",                 CONTROL_FREEZE, FALSE },
+  { US"no_enforce_sync",        CONTROL_NO_ENFORCE_SYNC, FALSE },
+  { US"no_multiline_responses", CONTROL_NO_MULTILINE, FALSE },
+  { US"queue_only",             CONTROL_QUEUE_ONLY, FALSE },
 #ifdef WITH_CONTENT_SCAN
-  { US"no_mbox_unspool",        CONTROL_NO_MBOX_UNSPOOL, FALSE},
+  { US"no_mbox_unspool",        CONTROL_NO_MBOX_UNSPOOL, FALSE },
 #endif
-  { US"fakedefer",              CONTROL_FAKEDEFER, TRUE},
-  { US"fakereject",             CONTROL_FAKEREJECT, TRUE},
-  { US"submission",             CONTROL_SUBMISSION, TRUE}
+  { US"fakedefer",              CONTROL_FAKEDEFER, TRUE },
+  { US"fakereject",             CONTROL_FAKEREJECT, TRUE },
+  { US"submission",             CONTROL_SUBMISSION, TRUE },
+  { US"suppress_local_fixups",  CONTROL_SUPPRESS_LOCAL_FIXUPS, FALSE }
   };
 
 /* Support data structures for Client SMTP Authorization. acl_verify_csa()
@@ -1382,10 +1391,8 @@ occurred earlier. If not, we can attempt the verification now. */
 if (strcmpic(ss, US"helo") == 0)
   {
   if (slash != NULL) goto NO_OPTIONS;
-  if (helo_verified) return OK;
-  if (helo_verify_failed) return FAIL;
-  if (smtp_verify_helo()) return helo_verified? OK : FAIL;
-  return DEFER;
+  if (!helo_verified && !helo_verify_failed) smtp_verify_helo();
+  return helo_verified? OK : FAIL;
   }
 
 /* Do Client SMTP Authorization checks in a separate function, and turn the
@@ -1409,18 +1416,29 @@ always). */
 if (strcmpic(ss, US"header_syntax") == 0)
   {
   if (slash != NULL) goto NO_OPTIONS;
-  if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP)
-    {
-    *log_msgptr = string_sprintf("cannot check header contents in ACL for %s "
-      "(only possible in ACL for DATA)", acl_wherenames[where]);
-    return ERROR;
-    }
+  if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP) goto WRONG_ACL;
   rc = verify_check_headers(log_msgptr);
   if (rc != OK && smtp_return_error_details && *log_msgptr != NULL)
     *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr);
   return rc;
   }
 
+/* Check that no recipient of this message is "blind", that is, every envelope
+recipient must be mentioned in either To: or Cc:. */
+
+if (strcmpic(ss, US"not_blind") == 0)
+  {
+  if (slash != NULL) goto NO_OPTIONS;
+  if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP) goto WRONG_ACL;
+  rc = verify_check_notblind();
+  if (rc != OK)
+    {
+    *log_msgptr = string_sprintf("bcc recipient detected");
+    if (smtp_return_error_details)
+      *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr);
+    }
+  return rc;
+  }
 
 /* The remaining verification tests check recipient and sender addresses,
 either from the envelope or from the header. There are a number of
@@ -1433,12 +1451,7 @@ sender and recipient. */
 
 if (strcmpic(ss, US"header_sender") == 0)
   {
-  if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP)
-    {
-    *log_msgptr = string_sprintf("cannot check header contents in ACL for %s "
-      "(only possible in ACL for DATA)", acl_wherenames[where]);
-    return ERROR;
-    }
+  if (where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP) goto WRONG_ACL;
   verify_header_sender = TRUE;
   }
 
@@ -1875,6 +1888,13 @@ NO_OPTIONS:
 *log_msgptr = string_sprintf("unexpected '/' found in \"%s\" "
   "(this verify item has no options)", arg);
 return ERROR;
+
+/* Calls in the wrong ACL come here */
+
+WRONG_ACL:
+*log_msgptr = string_sprintf("cannot check header contents in ACL for %s "
+  "(only possible in ACL for DATA)", acl_wherenames[where]);
+return ERROR;
 }
 
 
@@ -2142,16 +2162,16 @@ else
                    + (double)tv.tv_usec / 1000000.0;
   double prev_time = (double)dbd->time_stamp
                    + (double)dbd->time_usec / 1000000.0;
-  double interval = this_time - prev_time;
-
-  double i_over_p = interval / period;
-  double a = exp(-i_over_p);
 
   /* We must avoid division by zero, and deal gracefully with the clock going
   backwards. If we blunder ahead when time is in reverse then the computed
-  rate will become bogusly huge. Clamp i/p to a very small number instead. */
+  rate will be bogus. To be safe we clamp interval to a very small number. */
 
-  if (i_over_p <= 0.0) i_over_p = 1e-9;
+  double interval = this_time - prev_time <= 0.0 ? 1e-9
+                  : this_time - prev_time;
+
+  double i_over_p = interval / period;
+  double a = exp(-i_over_p);
 
   dbd->time_stamp = tv.tv_sec;
   dbd->time_usec = tv.tv_usec;
@@ -2481,7 +2501,7 @@ for (; cb != NULL; cb = cb->next)
           {
           uschar *pp = p + 6;
           while (*pp != 0 && *pp != '/') pp++;
-          originator_name = string_copy(parse_fix_phrase(p+6, pp-p-6,
+          submission_name = string_copy(parse_fix_phrase(p+6, pp-p-6,
             big_buffer, big_buffer_size));
           p = pp;
           }
@@ -2493,6 +2513,10 @@ for (; cb != NULL; cb = cb->next)
         return ERROR;
         }
       break;
+
+      case CONTROL_SUPPRESS_LOCAL_FIXUPS:
+      suppress_local_fixups = TRUE;
+      break;
       }
     break;
 
@@ -3331,7 +3355,7 @@ acl_check_internal() to do the actual work.
 
 Arguments:
   where        ACL_WHERE_xxxx indicating where called from
-  data_string  RCPT address, or SMTP command argument, or NULL
+  recipient    RCPT address for RCPT check, else NULL
   s            the input string; NULL is the same as an empty ACL => DENY
   user_msgptr  where to put a user error (for SMTP response)
   log_msgptr   where to put a logging message (not for SMTP response)
@@ -3345,12 +3369,12 @@ Returns:       OK         access is granted by an ACCEPT verb
 */
 
 int
-acl_check(int where, uschar *data_string, uschar *s, uschar **user_msgptr,
+acl_check(int where, uschar *recipient, uschar *s, uschar **user_msgptr,
   uschar **log_msgptr)
 {
 int rc;
 address_item adb;
-address_item *addr;
+address_item *addr = NULL;
 
 *user_msgptr = *log_msgptr = NULL;
 sender_verified_failed = NULL;
@@ -3360,7 +3384,7 @@ if (where == ACL_WHERE_RCPT)
   {
   adb = address_defaults;
   addr = &adb;
-  addr->address = data_string;
+  addr->address = recipient;
   if (deliver_split_address(addr) == DEFER)
     {
     *log_msgptr = US"defer in percent_hack_domains check";
@@ -3369,16 +3393,11 @@ if (where == ACL_WHERE_RCPT)
   deliver_domain = addr->domain;
   deliver_localpart = addr->local_part;
   }
-else
-  {
-  addr = NULL;
-  smtp_command_argument = data_string;
-  }
 
 rc = acl_check_internal(where, addr, s, 0, user_msgptr, log_msgptr);
 
-smtp_command_argument = deliver_domain =
-  deliver_localpart = deliver_address_data = sender_address_data = NULL;
+deliver_domain = deliver_localpart = deliver_address_data =
+  sender_address_data = NULL;
 
 /* A DISCARD response is permitted only for message ACLs, excluding the PREDATA
 ACL, which is really in the middle of an SMTP command. */