Move PRDR out of EXPERIMENTAL
[exim.git] / src / src / acl.c
index e3efb7ed873c627b89474a8940ff3dab13824e5b..e8a0657f2f6787fa4719b1392fcabd7fd7b715aa 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 handling Access Control Lists (ACLs) */
@@ -397,7 +397,7 @@ static unsigned int cond_forbids[] = {
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* add_header */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
-  #ifdef EXPERIMENTAL_PRDR
+  #ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
   #endif
     (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
@@ -412,7 +412,7 @@ static unsigned int cond_forbids[] = {
   (1<<ACL_WHERE_AUTH)|                             /* bmi_optin */
     (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
     (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
-  #ifdef EXPERIMENTAL_PRDR
+  #ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
   #endif
     (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
@@ -434,9 +434,9 @@ static unsigned int cond_forbids[] = {
   #ifdef EXPERIMENTAL_DCC
   (unsigned int)
   ~((1<<ACL_WHERE_DATA)|                           /* dcc */
-  #ifdef EXPERIMENTAL_PRDR
+  #ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
-  #endif /* EXPERIMENTAL_PRDR */
+  #endif
     (1<<ACL_WHERE_NOTSMTP)),
   #endif
 
@@ -450,9 +450,9 @@ static unsigned int cond_forbids[] = {
   #ifdef WITH_OLD_DEMIME
   (unsigned int)
   ~((1<<ACL_WHERE_DATA)|                           /* demime */
-  #ifdef EXPERIMENTAL_PRDR
+  #ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
-  #endif /* EXPERIMENTAL_PRDR */
+  #endif
     (1<<ACL_WHERE_NOTSMTP)),
   #endif
 
@@ -474,7 +474,7 @@ static unsigned int cond_forbids[] = {
 
   (unsigned int)
   ~((1<<ACL_WHERE_RCPT)                            /* domains */
-  #ifdef EXPERIMENTAL_PRDR
+  #ifndef DISABLE_PRDR
     |(1<<ACL_WHERE_PRDR)
   #endif
     ),
@@ -505,9 +505,9 @@ static unsigned int cond_forbids[] = {
   #ifdef WITH_CONTENT_SCAN
   (unsigned int)
   ~((1<<ACL_WHERE_DATA)|                           /* malware */
-  #ifdef EXPERIMENTAL_PRDR
+  #ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
-  #endif /* EXPERIMENTAL_PRDR */
+  #endif
     (1<<ACL_WHERE_NOTSMTP)),
   #endif
 
@@ -526,9 +526,9 @@ static unsigned int cond_forbids[] = {
   #ifdef WITH_CONTENT_SCAN
   (unsigned int)
   ~((1<<ACL_WHERE_DATA)|                           /* regex */
-  #ifdef EXPERIMENTAL_PRDR
+  #ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
-  #endif /* EXPERIMENTAL_PRDR */
+  #endif
     (1<<ACL_WHERE_NOTSMTP)|
     (1<<ACL_WHERE_MIME)),
   #endif
@@ -536,7 +536,7 @@ static unsigned int cond_forbids[] = {
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* remove_header */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
-  #ifdef EXPERIMENTAL_PRDR
+  #ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
   #endif
     (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
@@ -559,9 +559,9 @@ static unsigned int cond_forbids[] = {
   #ifdef WITH_CONTENT_SCAN
   (unsigned int)
   ~((1<<ACL_WHERE_DATA)|                           /* spam */
-  #ifdef EXPERIMENTAL_PRDR
+  #ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
-  #endif /* EXPERIMENTAL_PRDR */
+  #endif
     (1<<ACL_WHERE_NOTSMTP)),
   #endif
 
@@ -608,9 +608,9 @@ static unsigned int control_forbids[] = {
 
   #ifndef DISABLE_DKIM
   (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|      /* dkim_disable_verify */
-  #ifdef EXPERIMENTAL_PRDR
+  #ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
-  #endif /* EXPERIMENTAL_PRDR */
+  #endif
     (1<<ACL_WHERE_NOTSMTP_START),
   #endif
 
@@ -674,17 +674,17 @@ static unsigned int control_forbids[] = {
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* fakedefer */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
-  #ifdef EXPERIMENTAL_PRDR
+  #ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
-  #endif /* EXPERIMENTAL_PRDR */
+  #endif
     (1<<ACL_WHERE_MIME)),
 
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* fakereject */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
-  #ifdef EXPERIMENTAL_PRDR
+  #ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
-  #endif /* EXPERIMENTAL_PRDR */
+  #endif
     (1<<ACL_WHERE_MIME)),
 
   (1<<ACL_WHERE_NOTSMTP)|                          /* no_multiline */
@@ -1614,6 +1614,7 @@ else
 DNS_LOOKUP_AGAIN:
 #endif
 
+lookup_dnssec_authenticated = NULL;
 switch (dns_lookup(&dnsa, target, type, NULL))
   {
   /* If something bad happened (most commonly DNS_AGAIN), defer. */
@@ -1650,7 +1651,8 @@ switch (dns_lookup(&dnsa, target, type, NULL))
 *************************************************/
 
 enum { VERIFY_REV_HOST_LKUP, VERIFY_CERT, VERIFY_HELO, VERIFY_CSA, VERIFY_HDR_SYNTAX,
-  VERIFY_NOT_BLIND, VERIFY_HDR_SNDR, VERIFY_SNDR, VERIFY_RCPT
+       VERIFY_NOT_BLIND, VERIFY_HDR_SNDR, VERIFY_SNDR, VERIFY_RCPT,
+       VERIFY_HDR_NAMES_ASCII
   };
 typedef struct {
   uschar * name;
@@ -1670,7 +1672,8 @@ static verify_type_t verify_type_list[] = {
     { US"sender",              VERIFY_SNDR,            (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)
                        |(1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP),
                                                                                FALSE, 6 },
-    { US"recipient",           VERIFY_RCPT,            (1<<ACL_WHERE_RCPT),    FALSE, 0 }
+    { US"recipient",           VERIFY_RCPT,            (1<<ACL_WHERE_RCPT),    FALSE, 0 },
+    { US"header_names_ascii",  VERIFY_HDR_NAMES_ASCII, (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP), TRUE, 0 }
   };
 
 
@@ -1820,6 +1823,15 @@ switch(vp->value)
       *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr);
     return rc;
 
+  case VERIFY_HDR_NAMES_ASCII:
+    /* Check that all header names are true 7 bit strings
+    See RFC 5322, 2.2. and RFC 6532, 3. */
+
+    rc = verify_check_header_names_ascii(log_msgptr);
+    if (rc != OK && smtp_return_error_details && *log_msgptr != NULL)
+      *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr);
+    return rc;
+
   case VERIFY_NOT_BLIND:
     /* Check that no recipient of this message is "blind", that is, every envelope
     recipient must be mentioned in either To: or Cc:. */
@@ -2202,8 +2214,8 @@ return rc;
 
 BAD_VERIFY:
 *log_msgptr = string_sprintf("expected \"sender[=address]\", \"recipient\", "
-  "\"helo\", \"header_syntax\", \"header_sender\" or "
-  "\"reverse_host_lookup\" at start of ACL condition "
+  "\"helo\", \"header_syntax\", \"header_sender\", \"header_names_ascii\" "
+  "or \"reverse_host_lookup\" at start of ACL condition "
   "\"verify %s\"", arg);
 return ERROR;
 }
@@ -2846,9 +2858,9 @@ uschar *portstr;
 uschar *portend;
 host_item *h;
 int portnum;
-int host_af;
 int len;
 int r, s;
+uschar * errstr;
 
 hostname = string_nextinlist(&arg, &sep, NULL, 0);
 portstr = string_nextinlist(&arg, &sep, NULL, 0);
@@ -2895,14 +2907,18 @@ if (r == HOST_FIND_FAILED || r == HOST_FIND_AGAIN)
 HDEBUG(D_acl)
   debug_printf("udpsend [%s]:%d %s\n", h->address, portnum, arg);
 
-host_af = (Ustrchr(h->address, ':') == NULL)? AF_INET:AF_INET6;
-r = s = ip_socket(SOCK_DGRAM, host_af);
-if (r < 0) goto defer;
-r = ip_connect(s, host_af, h->address, portnum, 1);
+r = s = ip_connectedsocket(SOCK_DGRAM, h->address, portnum, portnum,
+               1, NULL, &errstr);
 if (r < 0) goto defer;
 len = Ustrlen(arg);
-r = send(s, arg, len, MSG_NOSIGNAL);
-if (r < 0) goto defer;
+r = send(s, arg, len, 0);
+if (r < 0)
+  {
+  errstr = US strerror(errno);
+  close(s);
+  goto defer;
+  }
+close(s);
 if (r < len)
   {
   *log_msgptr =
@@ -2916,7 +2932,7 @@ HDEBUG(D_acl)
 return OK;
 
 defer:
-*log_msgptr = string_sprintf("\"udpsend\" failed: %s", strerror(errno));
+*log_msgptr = string_sprintf("\"udpsend\" failed: %s", errstr);
 return DEFER;
 }
 
@@ -2976,12 +2992,14 @@ for (; cb != NULL; cb = cb->next)
 
   if (cb->type == ACLC_MESSAGE)
     {
+    HDEBUG(D_acl) debug_printf("  message: %s\n", cb->arg);
     user_message = cb->arg;
     continue;
     }
 
   if (cb->type == ACLC_LOG_MESSAGE)
     {
+    HDEBUG(D_acl) debug_printf("l_message: %s\n", cb->arg);
     log_message = cb->arg;
     continue;
     }
@@ -3088,7 +3106,9 @@ for (; cb != NULL; cb = cb->next)
     /* The true/false parsing here should be kept in sync with that used in
     expand.c when dealing with ECOND_BOOL so that we don't have too many
     different definitions of what can be a boolean. */
-    if (Ustrspn(arg, "0123456789") == Ustrlen(arg))     /* Digits, or empty */
+    if (*arg == '-'
+       ? Ustrspn(arg+1, "0123456789") == Ustrlen(arg+1)    /* Negative number */
+       : Ustrspn(arg,   "0123456789") == Ustrlen(arg))     /* Digits, or empty */
       rc = (Uatoi(arg) == 0)? FAIL : OK;
     else
       rc = (strcmpic(arg, US"no") == 0 ||
@@ -3228,8 +3248,9 @@ for (; cb != NULL; cb = cb->next)
       disable_callout_flush = TRUE;
       break;
 
-      case CONTROL_FAKEDEFER:
       case CONTROL_FAKEREJECT:
+      cancel_cutthrough_connection("fakereject");
+      case CONTROL_FAKEDEFER:
       fake_response = (control_type == CONTROL_FAKEDEFER) ? DEFER : FAIL;
       if (*p == '/')
         {
@@ -3259,10 +3280,12 @@ for (; cb != NULL; cb = cb->next)
         *log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg);
         return ERROR;
         }
+      cancel_cutthrough_connection("item frozen");
       break;
 
       case CONTROL_QUEUE_ONLY:
       queue_only_policy = TRUE;
+      cancel_cutthrough_connection("queueing forced");
       break;
 
       case CONTROL_SUBMISSION:
@@ -3329,17 +3352,19 @@ for (; cb != NULL; cb = cb->next)
 
       case CONTROL_CUTTHROUGH_DELIVERY:
       if (deliver_freeze)
-        {
-        *log_msgptr = string_sprintf("\"control=%s\" on frozen item", arg);
-        return ERROR;
-        }
-       if (queue_only_policy)
-        {
-        *log_msgptr = string_sprintf("\"control=%s\" on queue-only item", arg);
-        return ERROR;
-        }
-      cutthrough_delivery = TRUE;
-      break;
+        *log_msgptr = US"frozen";
+      else if (queue_only_policy)
+        *log_msgptr = US"queue-only";
+      else if (fake_response == FAIL)
+        *log_msgptr = US"fakereject";
+      else
+       {
+       cutthrough_delivery = TRUE;
+       break;
+       }
+      *log_msgptr = string_sprintf("\"control=%s\" on %s item",
+                                   arg, *log_msgptr);
+      return ERROR;
       }
     break;
 
@@ -4294,7 +4319,7 @@ sender_verified_failed = NULL;
 ratelimiters_cmd = NULL;
 log_reject_target = LOG_MAIN|LOG_REJECT;
 
-#ifdef EXPERIMENTAL_PRDR
+#ifndef DISABLE_PRDR
 if (where == ACL_WHERE_RCPT || where == ACL_WHERE_PRDR )
 #else
 if (where == ACL_WHERE_RCPT )
@@ -4338,7 +4363,7 @@ If conn-failure, no action (and keep the spooled copy).
 switch (where)
 {
 case ACL_WHERE_RCPT:
-#ifdef EXPERIMENTAL_PRDR
+#ifndef DISABLE_PRDR
 case ACL_WHERE_PRDR:
 #endif
   if( rcpt_count > 1 )
@@ -4458,4 +4483,6 @@ FILE *f = (FILE *)ctx;
 fprintf(f, "-acl%c %s %d\n%s\n", name[0], name+1, Ustrlen(value), value);
 }
 
+/* vi: aw ai sw=2
+*/
 /* End of acl.c */