Add sender to log line for DATA timeout.
[exim.git] / src / src / acl.c
index 439e9d424568461939478640eaf00fae60d60ff0..c0a5e944f1ab3b5d637d64a8f789b702767383f2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/acl.c,v 1.20 2005/03/08 15:32:02 tom Exp $ */
+/* $Cambridge: exim/src/src/acl.c,v 1.28 2005/04/06 14:03:53 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -149,12 +149,12 @@ static uschar cond_expand_at_top[] = {
   TRUE,    /* demime */
 #endif
 #ifdef EXPERIMENTAL_DOMAINKEYS
-  TRUE,
-  TRUE,
-  TRUE,
-  TRUE,
-  TRUE,
-  TRUE,
+  TRUE,    /* dk_domain_source */
+  TRUE,    /* dk_policy */
+  TRUE,    /* dk_sender_domains */
+  TRUE,    /* dk_sender_local_parts */
+  TRUE,    /* dk_senders */
+  TRUE,    /* dk_status */
 #endif
   TRUE,    /* dnslists */
   FALSE,   /* domains */
@@ -205,12 +205,12 @@ static uschar cond_modifiers[] = {
   FALSE,   /* demime */
 #endif
 #ifdef EXPERIMENTAL_DOMAINKEYS
-  FALSE,
-  FALSE,
-  FALSE,
-  FALSE,
-  FALSE,
-  FALSE,
+  FALSE,   /* dk_domain_source */
+  FALSE,   /* dk_policy */
+  FALSE,   /* dk_sender_domains */
+  FALSE,   /* dk_sender_local_parts */
+  FALSE,   /* dk_senders */
+  FALSE,   /* dk_status */
 #endif
   FALSE,   /* dnslists */
   FALSE,   /* domains */
@@ -244,7 +244,8 @@ static uschar cond_modifiers[] = {
 };
 
 /* Bit map vector of which conditions are not allowed at certain times. For
-each condition, there's a bitmap of dis-allowed times. */
+each condition, there's a bitmap of dis-allowed times. For some, it is easier
+to specify the negation of a small number of allowed times. */
 
 static unsigned int cond_forbids[] = {
   0,                                               /* acl */
@@ -265,74 +266,64 @@ static unsigned int cond_forbids[] = {
   0,                                               /* condition */
 
   /* Certain types of control are always allowed, so we let it through
-  always and check in the control processing itself */
+  always and check in the control processing itself. */
 
   0,                                               /* control */
 
 #ifdef WITH_CONTENT_SCAN
-  (1<<ACL_WHERE_AUTH)|                             /* decode */
-    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
-    (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_PREDATA)|
-    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
-    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-    (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_RCPT),
+  (unsigned int)
+  ~(1<<ACL_WHERE_MIME),                            /* decode */
 #endif
 
   0,                                               /* delay */
 
 #ifdef WITH_OLD_DEMIME
-  (1<<ACL_WHERE_AUTH)|                             /* demime */
-    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
-    (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
-    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
-    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-    (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_MIME),
+  (unsigned int)
+  ~((1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)),   /* demime */
 #endif
 
 #ifdef EXPERIMENTAL_DOMAINKEYS
-  (1<<ACL_WHERE_AUTH)|
+  (1<<ACL_WHERE_AUTH)|                             /* dk_domain_source */
     (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
     (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
     (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
     (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
     (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
     (1<<ACL_WHERE_VRFY),
-    
-  (1<<ACL_WHERE_AUTH)|
+
+  (1<<ACL_WHERE_AUTH)|                             /* dk_policy */
     (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
     (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
     (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
     (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
     (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
     (1<<ACL_WHERE_VRFY),
-  
-  (1<<ACL_WHERE_AUTH)|
+
+  (1<<ACL_WHERE_AUTH)|                             /* dk_sender_domains */
     (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
     (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
     (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
     (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
     (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
     (1<<ACL_WHERE_VRFY),
-    
-  (1<<ACL_WHERE_AUTH)|
+
+  (1<<ACL_WHERE_AUTH)|                             /* dk_sender_local_parts */
     (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
     (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
     (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
     (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
     (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
     (1<<ACL_WHERE_VRFY),
-    
-  (1<<ACL_WHERE_AUTH)|
+
+  (1<<ACL_WHERE_AUTH)|                             /* dk_senders */
     (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
     (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
     (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
     (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
     (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
     (1<<ACL_WHERE_VRFY),
-    
-  (1<<ACL_WHERE_AUTH)|
+
+  (1<<ACL_WHERE_AUTH)|                             /* dk_status */
     (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
     (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
     (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
@@ -343,13 +334,8 @@ static unsigned int cond_forbids[] = {
 
   (1<<ACL_WHERE_NOTSMTP),                          /* dnslists */
 
-  (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)|      /* domains */
-    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
-    (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_PREDATA)|
-    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
-    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-    (1<<ACL_WHERE_VRFY),
+  (unsigned int)
+  ~(1<<ACL_WHERE_RCPT),                            /* domains */
 
   (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_CONNECT)|   /* encrypted */
     (1<<ACL_WHERE_HELO),
@@ -358,56 +344,32 @@ static unsigned int cond_forbids[] = {
 
   (1<<ACL_WHERE_NOTSMTP),                          /* hosts */
 
-  (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)|      /* local_parts */
-    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
-    (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_PREDATA)|
-    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
-    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-    (1<<ACL_WHERE_VRFY),
+  (unsigned int)
+  ~(1<<ACL_WHERE_RCPT),                            /* local_parts */
 
   0,                                               /* log_message */
 
   0,                                               /* logwrite */
 
 #ifdef WITH_CONTENT_SCAN
-  (1<<ACL_WHERE_AUTH)|                             /* malware */
-    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
-    (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
-    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
-    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-    (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_MIME),
+  (unsigned int)
+  ~((1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)),   /* malware */
 #endif
 
   0,                                               /* message */
 
 #ifdef WITH_CONTENT_SCAN
-  (1<<ACL_WHERE_AUTH)|                             /* mime_regex */
-    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
-    (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_PREDATA)|
-    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
-    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-    (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_RCPT),
+  (unsigned int)
+  ~(1<<ACL_WHERE_MIME),                            /* mime_regex */
 #endif
 
-  (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)|      /* recipients */
-    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
-    (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_PREDATA)|
-    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
-    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-    (1<<ACL_WHERE_VRFY),
+  (unsigned int)
+  ~(1<<ACL_WHERE_RCPT),                            /* recipients */
 
 #ifdef WITH_CONTENT_SCAN
-  (1<<ACL_WHERE_AUTH)|                             /* regex */
-    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
-    (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
-    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
-    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-    (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_MIME),
+  (unsigned int)
+  ~((1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|    /* regex */
+    (1<<ACL_WHERE_MIME)),
 #endif
 
   (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|      /* sender_domains */
@@ -425,13 +387,8 @@ static unsigned int cond_forbids[] = {
   0,                                               /* set */
 
 #ifdef WITH_CONTENT_SCAN
-  (1<<ACL_WHERE_AUTH)|                             /* spam */
-    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
-    (1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
-    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-    (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
-    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-    (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_MIME),
+  (unsigned int)
+  ~((1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)),   /* spam */
 #endif
 
 #ifdef EXPERIMENTAL_SPF
@@ -475,7 +432,7 @@ static unsigned int control_forbids[] = {
   0,                                               /* bmi_run */
 #endif
 #ifdef EXPERIMENTAL_DOMAINKEYS
-  (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA),      /* dk_verify */
+  (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP),      /* dk_verify */
 #endif
 
   0,                                               /* error */
@@ -493,12 +450,12 @@ static unsigned int control_forbids[] = {
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* freeze */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
-    (1<<ACL_WHERE_NOTSMTP)),
+    (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME)),
 
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* queue_only */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
-    (1<<ACL_WHERE_NOTSMTP)),
+    (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME)),
 
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* submission */
@@ -507,12 +464,14 @@ static unsigned int control_forbids[] = {
 #ifdef WITH_CONTENT_SCAN
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* no_mbox_unspool */
-    (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)),
+    (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+    (1<<ACL_WHERE_MIME)),
 #endif
 
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* fakereject */
-    (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)),
+    (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+    (1<<ACL_WHERE_MIME)),
 
   (1<<ACL_WHERE_NOTSMTP)                           /* no_multiline */
 };
@@ -630,18 +589,11 @@ while ((s = (*func)()) != NULL)
     s++;
     }
 
-  /* Read the name of a verb or a condition, or the start of a new ACL */
+  /* Read the name of a verb or a condition, or the start of a new ACL, which
+  can be started by a name, or by a macro definition. */
 
   s = readconf_readname(name, sizeof(name), s);
-  if (*s == ':')
-    {
-    if (negated || name[0] == 0)
-      {
-      *error = string_sprintf("malformed ACL name in \"%s\"", saveline);
-      return NULL;
-      }
-    break;
-    }
+  if (*s == ':' || isupper(name[0] && *s == '=')) return yield;
 
   /* If a verb is unrecognized, it may be another condition or modifier that
   continues the previous verb. */
@@ -1026,6 +978,13 @@ address_item *sender_vaddr = NULL;
 uschar *verify_sender_address = NULL;
 uschar *pm_mailfrom = NULL;
 uschar *se_mailfrom = NULL;
+
+/* Some of the verify items have slash-separated options; some do not. Diagnose
+an error if options are given for items that don't expect them. This code has
+now got very message. Refactoring to use a table would be a good idea one day.
+*/
+
+uschar *slash = Ustrchr(arg, '/');
 uschar *list = arg;
 uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size);
 
@@ -1035,6 +994,7 @@ if (ss == NULL) goto BAD_VERIFY;
 
 if (strcmpic(ss, US"reverse_host_lookup") == 0)
   {
+  if (slash != NULL) goto NO_OPTIONS;
   if (sender_host_address == NULL) return OK;
   return acl_verify_reverse(user_msgptr, log_msgptr);
   }
@@ -1045,6 +1005,7 @@ mandatory verification, the connection doesn't last this long.) */
 
 if (strcmpic(ss, US"certificate") == 0)
   {
+  if (slash != NULL) goto NO_OPTIONS;
   if (tls_certificate_verified) return OK;
   *user_msgptr = US"no verified certificate";
   return FAIL;
@@ -1052,42 +1013,51 @@ if (strcmpic(ss, US"certificate") == 0)
 
 /* We can test the result of optional HELO verification */
 
-if (strcmpic(ss, US"helo") == 0) return helo_verified? OK : FAIL;
+if (strcmpic(ss, US"helo") == 0)
+  {
+  if (slash != NULL) goto NO_OPTIONS;
+  return helo_verified? OK : FAIL;
+  }
 
-/* Handle header verification options - permitted only after DATA or a non-SMTP
-message. */
+/* Check that all relevant header lines have the correct syntax. If there is
+a syntax error, we return details of the error to the sender if configured to
+send out full details. (But a "message" setting on the ACL can override, as
+always). */
 
-if (strncmpic(ss, US"header_", 7) == 0)
+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;
     }
+  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 all relevant header lines have the correct syntax. If there is
-  a syntax error, we return details of the error to the sender if configured to
-  send out full details. (But a "message" setting on the ACL can override, as
-  always). */
-
-  if (strcmpic(ss+7, US"syntax") == 0)
-    {
-    int 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 there is at least one verifiable sender address in the relevant
-  header lines. This can be followed by callout and defer options, just like
-  sender and recipient. */
+/* The remaining verification tests check recipient and sender addresses,
+either from the envelope or from the header. There are a number of
+slash-separated options that are common to all of them. */
 
-  else if (strcmpic(ss+7, US"sender") == 0) verify_header_sender = TRUE;
 
-  /* Unknown verify argument starting with "header_" */
+/* Check that there is at least one verifiable sender address in the relevant
+header lines. This can be followed by callout and defer options, just like
+sender and recipient. */
 
-  else goto BAD_VERIFY;
+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;
+    }
+  verify_header_sender = TRUE;
   }
 
 /* Otherwise, first item in verify argument must be "sender" or "recipient".
@@ -1125,7 +1095,8 @@ else
     }
   }
 
-/* Remaining items are optional */
+/* Remaining items are optional; they apply to sender and recipient
+verification, including "header sender" verification. */
 
 while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))
       != NULL)
@@ -1499,9 +1470,17 @@ return rc;
 
 BAD_VERIFY:
 *log_msgptr = string_sprintf("expected \"sender[=address]\", \"recipient\", "
-  "\"header_syntax\" or \"header_sender\" at start of ACL condition "
+  "\"helo\", \"header_syntax\", \"header_sender\" or "
+  "\"reverse_host_lookup\" at start of ACL condition "
   "\"verify %s\"", arg);
 return ERROR;
+
+/* Options supplied when not allowed come here */
+
+NO_OPTIONS:
+*log_msgptr = string_sprintf("unexpected '/' found in \"%s\" "
+  "(this verify item has no options)", arg);
+return ERROR;
 }
 
 
@@ -2120,10 +2099,13 @@ for (; cb != NULL; cb = cb->next)
 
     /* If the verb is WARN, discard any user message from verification, because
     such messages are SMTP responses, not header additions. The latter come
-    only from explicit "message" modifiers. */
+    only from explicit "message" modifiers. However, put the user message into
+    $acl_verify_message so it can be used in subsequent conditions or modifiers
+    (until something changes it). */
 
     case ACLC_VERIFY:
     rc = acl_verify(where, addr, arg, user_msgptr, log_msgptr, basic_errno);
+    acl_verify_message = *user_msgptr;
     if (verb == ACL_WARN) *user_msgptr = NULL;
     break;