Added experimental features
[users/jgh/exim.git] / src / src / acl.c
index ffd7e9451b4c6d3221c91709db19f5c747cb8b1a..18629a1afe917cf3a61f57048add2dba6e143d0a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/acl.c,v 1.5.2.1 2004/11/25 15:33:55 tom Exp $ */
+/* $Cambridge: exim/src/src/acl.c,v 1.5.2.5 2004/12/10 14:59:08 tom Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -34,11 +34,19 @@ static int msgcond[] = { FAIL, OK, OK, FAIL, OK, FAIL, OK };
 /* ACL condition and modifier codes - keep in step with the table that
 follows. */
 
-enum { ACLC_ACL, ACLC_AUTHENTICATED, ACLC_CONDITION, ACLC_CONTROL,
+enum { ACLC_ACL, ACLC_AUTHENTICATED,
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+       ACLC_BMI_OPTIN,
+#endif
+ACLC_CONDITION, ACLC_CONTROL,
 #ifdef WITH_CONTENT_SCAN
        ACLC_DECODE,
 #endif
-       ACLC_DELAY, ACLC_DNSLISTS, ACLC_DOMAINS, ACLC_ENCRYPTED, ACLC_ENDPASS,
+       ACLC_DELAY,
+#ifdef WITH_OLD_DEMIME
+       ACLC_DEMIME,
+#endif        
+       ACLC_DNSLISTS, ACLC_DOMAINS, ACLC_ENCRYPTED, ACLC_ENDPASS,
        ACLC_HOSTS, ACLC_LOCAL_PARTS, ACLC_LOG_MESSAGE, ACLC_LOGWRITE,
 #ifdef WITH_CONTENT_SCAN
        ACLC_MALWARE,
@@ -49,11 +57,14 @@ enum { ACLC_ACL, ACLC_AUTHENTICATED, ACLC_CONDITION, ACLC_CONTROL,
 #endif
        ACLC_RECIPIENTS,
 #ifdef WITH_CONTENT_SCAN
-       ACLC_REGEX
+       ACLC_REGEX,
 #endif
        ACLC_SENDER_DOMAINS, ACLC_SENDERS, ACLC_SET,
 #ifdef WITH_CONTENT_SCAN
        ACLC_SPAM,       
+#endif
+#ifdef EXPERIMENTAL_SPF
+       ACLC_SPF,
 #endif
        ACLC_VERIFY };
 
@@ -61,12 +72,20 @@ enum { ACLC_ACL, ACLC_AUTHENTICATED, ACLC_CONDITION, ACLC_CONTROL,
 "log_message", "logwrite", and "set" are modifiers that look like conditions
 but always return TRUE. They are used for their side effects. */
 
-static uschar *conditions[] = { US"acl", US"authenticated", US"condition",
+static uschar *conditions[] = { US"acl", US"authenticated",
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+  US"bmi_optin",
+#endif
+  US"condition",
   US"control", 
 #ifdef WITH_CONTENT_SCAN
   US"decode",
 #endif
-  US"delay", US"dnslists", US"domains", US"encrypted",
+  US"delay",
+#ifdef WITH_OLD_DEMIME
+  US"demime",
+#endif
+  US"dnslists", US"domains", US"encrypted",
   US"endpass", US"hosts", US"local_parts", US"log_message", US"logwrite",
 #ifdef WITH_CONTENT_SCAN
   US"malware",
@@ -82,6 +101,9 @@ static uschar *conditions[] = { US"acl", US"authenticated", US"condition",
   US"sender_domains", US"senders", US"set",
 #ifdef WITH_CONTENT_SCAN
   US"spam",
+#endif
+#ifdef EXPERIMENTAL_SPF
+  US"spf",
 #endif
   US"verify" };
   
@@ -98,12 +120,18 @@ checking functions. */
 static uschar cond_expand_at_top[] = {
   TRUE,    /* acl */
   FALSE,   /* authenticated */
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+  TRUE,    /* bmi_optin */
+#endif  
   TRUE,    /* condition */
   TRUE,    /* control */
 #ifdef WITH_CONTENT_SCAN
   TRUE,    /* decode */
 #endif
   TRUE,    /* delay */
+#ifdef WITH_OLD_DEMIME
+  TRUE,    /* demime */
+#endif
   TRUE,    /* dnslists */
   FALSE,   /* domains */
   FALSE,   /* encrypted */
@@ -128,6 +156,9 @@ static uschar cond_expand_at_top[] = {
   TRUE,    /* set */
 #ifdef WITH_CONTENT_SCAN
   TRUE,    /* spam */
+#endif
+#ifdef EXPERIMENTAL_SPF
+  TRUE,    /* spf */
 #endif
   TRUE     /* verify */
 };
@@ -137,12 +168,18 @@ static uschar cond_expand_at_top[] = {
 static uschar cond_modifiers[] = {
   FALSE,   /* acl */
   FALSE,   /* authenticated */
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+  TRUE,    /* bmi_optin */
+#endif  
   FALSE,   /* condition */
   TRUE,    /* control */
 #ifdef WITH_CONTENT_SCAN
   FALSE,   /* decode */
 #endif
   TRUE,    /* delay */
+#ifdef WITH_OLD_DEMIME
+  FALSE,   /* demime */
+#endif
   FALSE,   /* dnslists */
   FALSE,   /* domains */
   FALSE,   /* encrypted */
@@ -167,6 +204,9 @@ static uschar cond_modifiers[] = {
   TRUE,    /* set */
 #ifdef WITH_CONTENT_SCAN
   FALSE,   /* spam */
+#endif
+#ifdef EXPERIMENTAL_SPF
+  FALSE,   /* spf */
 #endif
   FALSE    /* verify */
 };
@@ -178,13 +218,24 @@ static unsigned int cond_forbids[] = {
   0,                                               /* acl */
   (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_CONNECT)|   /* authenticated */
     (1<<ACL_WHERE_HELO),
+  
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+  (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)|      /* bmi_optin */
+    (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
+    (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
+    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|                                       
+    (1<<ACL_WHERE_MAILAUTH)|
+    (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
+    (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_PREDATA),
+#endif
+  
   0,                                               /* condition */
-
+  
   /* Certain types of control are always allowed, so we let it through
   always and check in the control processing itself */
-
+  
   0,                                               /* control */
-
+  
 #ifdef WITH_CONTENT_SCAN
   (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)|      /* decode */
     (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
@@ -196,6 +247,17 @@ static unsigned int cond_forbids[] = {
 #endif
 
   0,                                               /* delay */
+  
+#ifdef WITH_CONTENT_SCAN
+  (1<<ACL_WHERE_NOTSMTP)|(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),
+#endif
+  
   (1<<ACL_WHERE_NOTSMTP),                          /* dnslists */
 
   (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)|      /* domains */
@@ -286,6 +348,14 @@ static unsigned int cond_forbids[] = {
     (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_MIME),
 #endif
 
+#ifdef EXPERIMENTAL_SPF
+  (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|      /* spf */
+    (1<<ACL_WHERE_HELO)|
+    (1<<ACL_WHERE_MAILAUTH)|
+    (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+    (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY),
+#endif
+
   /* Certain types of verify are always allowed, so we let it through
   always and check in the verify function itself */
 
@@ -295,7 +365,11 @@ static unsigned int cond_forbids[] = {
 
 /* Return values from decode_control() */
 
-enum { CONTROL_ERROR, CONTROL_CASEFUL_LOCAL_PART, CONTROL_CASELOWER_LOCAL_PART,
+enum { 
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+  CONTROL_BMI_RUN,
+#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,
 #ifdef WITH_CONTENT_SCAN
@@ -308,6 +382,9 @@ each control, 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 control_forbids[] = {
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+  0,                                               /* bmi_run */
+#endif
   0,                                               /* error */
   ~(1<<ACL_WHERE_RCPT),                            /* caseful_local_part */
   ~(1<<ACL_WHERE_RCPT),                            /* caselower_local_part */
@@ -342,6 +419,9 @@ typedef struct control_def {
 } control_def;
 
 static control_def controls_list[] = {
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+  { US"bmi_run",                CONTROL_BMI_RUN, 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},
@@ -678,6 +758,11 @@ if (hlen > 0)
         newtype = htype_add_rec;
         p += 16;
         }
+      else if (strncmpic(p, US":at_start_rfc:", 14) == 0)
+        {
+        newtype = htype_add_rfc;
+        p += 14;
+        }        
       else if (strncmpic(p, US":at_start:", 10) == 0)
         {
         newtype = htype_add_top;
@@ -1384,6 +1469,9 @@ uschar *user_message = NULL;
 uschar *log_message = NULL;
 uschar *p;
 int rc = OK;
+#ifdef WITH_CONTENT_SCAN
+int sep = '/';
+#endif
 
 for (; cb != NULL; cb = cb->next)
   {
@@ -1491,6 +1579,17 @@ for (; cb != NULL; cb = cb->next)
         TRUE, NULL);
     break;
 
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+    case ACLC_BMI_OPTIN:
+      {
+      int old_pool = store_pool;
+      store_pool = POOL_PERM;
+      bmi_current_optin = string_copy(arg);
+      store_pool = old_pool;
+      }
+    break;
+#endif
+
     case ACLC_CONDITION:
     if (Ustrspn(arg, "0123456789") == Ustrlen(arg))     /* Digits, or empty */
       rc = (Uatoi(arg) == 0)? FAIL : OK;
@@ -1506,7 +1605,7 @@ for (; cb != NULL; cb = cb->next)
     case ACLC_CONTROL:
     control_type = decode_control(arg, &p, where, log_msgptr);
 
-    /* Check this control makes sense at this time */
+    /* Check if this control makes sense at this time */
 
     if ((control_forbids[control_type] & (1 << where)) != 0)
       {
@@ -1517,6 +1616,12 @@ for (; cb != NULL; cb = cb->next)
 
     switch(control_type)
       {
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+      case CONTROL_BMI_RUN:
+      bmi_run = 1;
+      break;
+#endif
+      
       case CONTROL_ERROR:
       return ERROR;
 
@@ -1549,6 +1654,18 @@ for (; cb != NULL; cb = cb->next)
 #ifdef WITH_CONTENT_SCAN
       case CONTROL_FAKEREJECT:
       fake_reject = TRUE;
+      if (*p == '/')
+        { 
+        uschar *pp = p + 1;
+        while (*pp != 0) pp++; 
+        fake_reject_text = expand_string(string_copyn(p+1, pp-p));
+        p = pp;
+        }
+       else
+        {
+        /* Explicitly reset to default string */
+        fake_reject_text = US"Your message has been rejected but is being kept for evaluation.\nIf it was a legit message, it may still be delivered to the target recipient(s).";
+        }
       break;
 #endif
 
@@ -1618,6 +1735,12 @@ for (; cb != NULL; cb = cb->next)
       }
     break;
 
+#ifdef WITH_OLD_DEMIME
+    case ACLC_DEMIME:
+      rc = demime(&arg);
+    break;
+#endif
+
     case ACLC_DNSLISTS:
     rc = verify_check_dnsbl(&arg);
     break;
@@ -1779,6 +1902,12 @@ for (; cb != NULL; cb = cb->next)
     break;
 #endif
 
+#ifdef EXPERIMENTAL_SPF
+    case ACLC_SPF:
+      rc = spf_process(&arg, sender_address);
+    break;
+#endif
+
     /* 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. */