Copyright year updates (things touched in 2015)
[exim.git] / src / src / acl.c
index e16fbb989163fe0ee8cc8a7328e9b850c4d62812..e79c87f83daa5e8ff6ae0588b0527961f36cab63 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2014 */
+/* Copyright (c) University of Cambridge 1995 - 2015 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Code for handling Access Control Lists (ACLs) */
@@ -181,17 +181,17 @@ that follows! */
 
 enum {
   CONTROL_AUTH_UNADVERTISED,
-  #ifdef EXPERIMENTAL_BRIGHTMAIL
+#ifdef EXPERIMENTAL_BRIGHTMAIL
   CONTROL_BMI_RUN,
-  #endif
+#endif
   CONTROL_DEBUG,
-  #ifndef DISABLE_DKIM
+#ifndef DISABLE_DKIM
   CONTROL_DKIM_VERIFY,
-  #endif
-  #ifdef EXPERIMENTAL_DMARC
+#endif
+#ifdef EXPERIMENTAL_DMARC
   CONTROL_DMARC_VERIFY,
   CONTROL_DMARC_FORENSIC,
-  #endif
+#endif
   CONTROL_DSCP,
   CONTROL_ERROR,
   CONTROL_CASEFUL_LOCAL_PART,
@@ -203,11 +203,14 @@ enum {
   CONTROL_QUEUE_ONLY,
   CONTROL_SUBMISSION,
   CONTROL_SUPPRESS_LOCAL_FIXUPS,
-  #ifdef WITH_CONTENT_SCAN
+#ifdef WITH_CONTENT_SCAN
   CONTROL_NO_MBOX_UNSPOOL,
-  #endif
+#endif
   CONTROL_FAKEDEFER,
   CONTROL_FAKEREJECT,
+#ifdef EXPERIMENTAL_INTERNATIONAL
+  CONTROL_UTF8_DOWNCONVERT,
+#endif
   CONTROL_NO_MULTILINE,
   CONTROL_NO_PIPELINING,
   CONTROL_NO_DELAY_FLUSH,
@@ -221,17 +224,17 @@ and should be tidied up. */
 
 static uschar *controls[] = {
   US"allow_auth_unadvertised",
-  #ifdef EXPERIMENTAL_BRIGHTMAIL
+#ifdef EXPERIMENTAL_BRIGHTMAIL
   US"bmi_run",
-  #endif
+#endif
   US"debug",
-  #ifndef DISABLE_DKIM
+#ifndef DISABLE_DKIM
   US"dkim_disable_verify",
-  #endif
-  #ifdef EXPERIMENTAL_DMARC
+#endif
+#ifdef EXPERIMENTAL_DMARC
   US"dmarc_disable_verify",
   US"dmarc_enable_forensic",
-  #endif
+#endif
   US"dscp",
   US"error",
   US"caseful_local_part",
@@ -243,11 +246,14 @@ static uschar *controls[] = {
   US"queue_only",
   US"submission",
   US"suppress_local_fixups",
-  #ifdef WITH_CONTENT_SCAN
+#ifdef WITH_CONTENT_SCAN
   US"no_mbox_unspool",
-  #endif
+#endif
   US"fakedefer",
   US"fakereject",
+#ifdef EXPERIMENTAL_INTERNATIONAL
+  US"utf8_downconvert",
+#endif
   US"no_multiline_responses",
   US"no_pipelining",
   US"no_delay_flush",
@@ -600,26 +606,26 @@ static unsigned int control_forbids[] = {
   (unsigned int)
   ~((1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)),   /* allow_auth_unadvertised */
 
-  #ifdef EXPERIMENTAL_BRIGHTMAIL
+#ifdef EXPERIMENTAL_BRIGHTMAIL
   0,                                               /* bmi_run */
-  #endif
+#endif
 
   0,                                               /* debug */
 
-  #ifndef DISABLE_DKIM
+#ifndef DISABLE_DKIM
   (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|      /* dkim_disable_verify */
-  #ifndef DISABLE_PRDR
+ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
-  #endif
+endif
     (1<<ACL_WHERE_NOTSMTP_START),
-  #endif
+#endif
 
-  #ifdef EXPERIMENTAL_DMARC
+#ifdef EXPERIMENTAL_DMARC
   (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|      /* dmarc_disable_verify */
     (1<<ACL_WHERE_NOTSMTP_START),
   (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|      /* dmarc_enable_forensic */
     (1<<ACL_WHERE_NOTSMTP_START),
-  #endif
+#endif
 
   (1<<ACL_WHERE_NOTSMTP)|
     (1<<ACL_WHERE_NOTSMTP_START)|
@@ -663,30 +669,34 @@ static unsigned int control_forbids[] = {
     (1<<ACL_WHERE_PREDATA)|
     (1<<ACL_WHERE_NOTSMTP_START)),
 
-  #ifdef WITH_CONTENT_SCAN
+#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_PRDR)|    /* Not allow one user to freeze for all */
     (1<<ACL_WHERE_MIME)),
-  #endif
+#endif
 
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* fakedefer */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
-  #ifndef DISABLE_PRDR
+#ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
-  #endif
+#endif
     (1<<ACL_WHERE_MIME)),
 
   (unsigned int)
   ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|       /* fakereject */
     (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
-  #ifndef DISABLE_PRDR
+#ifndef DISABLE_PRDR
     (1<<ACL_WHERE_PRDR)|
-  #endif
+#endif
     (1<<ACL_WHERE_MIME)),
 
+#ifdef EXPERIMENTAL_INTERNATIONAL
+  0,                                               /* utf8_downconvert */
+#endif
+
   (1<<ACL_WHERE_NOTSMTP)|                          /* no_multiline */
     (1<<ACL_WHERE_NOTSMTP_START),
 
@@ -709,37 +719,40 @@ typedef struct control_def {
 } control_def;
 
 static control_def controls_list[] = {
-  { US"allow_auth_unadvertised", CONTROL_AUTH_UNADVERTISED, FALSE },
+  { US"allow_auth_unadvertised", CONTROL_AUTH_UNADVERTISED,     FALSE },
 #ifdef EXPERIMENTAL_BRIGHTMAIL
-  { US"bmi_run",                 CONTROL_BMI_RUN, FALSE },
+  { US"bmi_run",                 CONTROL_BMI_RUN,               FALSE },
 #endif
-  { US"debug",                   CONTROL_DEBUG, TRUE },
+  { US"debug",                   CONTROL_DEBUG,                 TRUE },
 #ifndef DISABLE_DKIM
-  { US"dkim_disable_verify",     CONTROL_DKIM_VERIFY, FALSE },
+  { US"dkim_disable_verify",     CONTROL_DKIM_VERIFY,           FALSE },
 #endif
 #ifdef EXPERIMENTAL_DMARC
-  { US"dmarc_disable_verify",    CONTROL_DMARC_VERIFY, FALSE },
-  { US"dmarc_enable_forensic",   CONTROL_DMARC_FORENSIC, FALSE },
+  { US"dmarc_disable_verify",    CONTROL_DMARC_VERIFY,          FALSE },
+  { US"dmarc_enable_forensic",   CONTROL_DMARC_FORENSIC,        FALSE },
 #endif
-  { US"dscp",                    CONTROL_DSCP, TRUE },
-  { 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, TRUE },
-  { US"no_callout_flush",        CONTROL_NO_CALLOUT_FLUSH, FALSE },
-  { US"no_delay_flush",          CONTROL_NO_DELAY_FLUSH, FALSE },
-  { US"no_enforce_sync",         CONTROL_NO_ENFORCE_SYNC, FALSE },
-  { US"no_multiline_responses",  CONTROL_NO_MULTILINE, FALSE },
-  { US"no_pipelining",           CONTROL_NO_PIPELINING, FALSE },
-  { US"queue_only",              CONTROL_QUEUE_ONLY, FALSE },
+  { US"dscp",                    CONTROL_DSCP,                  TRUE },
+  { 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,                TRUE },
+  { US"no_callout_flush",        CONTROL_NO_CALLOUT_FLUSH,      FALSE },
+  { US"no_delay_flush",          CONTROL_NO_DELAY_FLUSH,        FALSE },
+  { US"no_enforce_sync",         CONTROL_NO_ENFORCE_SYNC,       FALSE },
+  { US"no_multiline_responses",  CONTROL_NO_MULTILINE,          FALSE },
+  { US"no_pipelining",           CONTROL_NO_PIPELINING,         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 },
-  { US"cutthrough_delivery",     CONTROL_CUTTHROUGH_DELIVERY, FALSE }
+  { US"cutthrough_delivery",     CONTROL_CUTTHROUGH_DELIVERY,   FALSE },
+#ifdef EXPERIMENTAL_INTERNATIONAL
+  { US"utf8_downconvert",        CONTROL_UTF8_DOWNCONVERT,      TRUE }
+#endif
   };
 
 /* Support data structures for Client SMTP Authorization. acl_verify_csa()
@@ -2079,6 +2092,13 @@ else if (verify_sender_address != NULL)
     uschar *save_address_data = deliver_address_data;
 
     sender_vaddr = deliver_make_addr(verify_sender_address, TRUE);
+#ifdef EXPERIMENTAL_INTERNATIONAL
+    if ((sender_vaddr->prop.utf8_msg = message_smtputf8))
+      {
+      sender_vaddr->prop.utf8_downcvt =       message_utf8_downconvert == 1;
+      sender_vaddr->prop.utf8_downcvt_maybe = message_utf8_downconvert == -1;
+      }
+#endif
     if (no_details) setflag(sender_vaddr, af_sverify_told);
     if (verify_sender_address[0] != 0)
       {
@@ -2135,7 +2155,7 @@ else if (verify_sender_address != NULL)
 
   /* Put the sender address_data value into $sender_address_data */
 
-  sender_address_data = sender_vaddr->p.address_data;
+  sender_address_data = sender_vaddr->prop.address_data;
   }
 
 /* A recipient address just gets a straightforward verify; again we must handle
@@ -2165,7 +2185,7 @@ else
   if (testflag((&addr2), af_pass_message)) acl_temp_details = TRUE;
 
   /* Make $address_data visible */
-  deliver_address_data = addr2.p.address_data;
+  deliver_address_data = addr2.prop.address_data;
   }
 
 /* We have a result from the relevant test. Handle defer overrides first. */
@@ -2184,13 +2204,9 @@ sender_verified_failed to the address item that actually failed. */
 if (rc != OK && verify_sender_address != NULL)
   {
   if (rc != DEFER)
-    {
     *log_msgptr = *user_msgptr = US"Sender verify failed";
-    }
   else if (*basic_errno != ERRNO_CALLOUTDEFER)
-    {
     *log_msgptr = *user_msgptr = US"Could not complete sender verify";
-    }
   else
     {
     *log_msgptr = US"Could not complete sender verify callout";
@@ -3378,6 +3394,47 @@ for (; cb != NULL; cb = cb->next)
                                        arg, *log_msgptr);
          }
        return ERROR;
+
+    #ifdef EXPERIMENTAL_INTERNATIONAL
+       case CONTROL_UTF8_DOWNCONVERT:
+       if (*p == '/')
+         {
+         if (p[1] == '1')
+           {
+           message_utf8_downconvert = 1;
+           addr->prop.utf8_downcvt = TRUE;
+           addr->prop.utf8_downcvt_maybe = FALSE;
+           p += 2;
+           break;
+           }
+         if (p[1] == '0')
+           {
+           message_utf8_downconvert = 0;
+           addr->prop.utf8_downcvt = FALSE;
+           addr->prop.utf8_downcvt_maybe = FALSE;
+           p += 2;
+           break;
+           }
+         if (p[1] == '-' && p[2] == '1')
+           {
+           message_utf8_downconvert = -1;
+           addr->prop.utf8_downcvt = FALSE;
+           addr->prop.utf8_downcvt_maybe = TRUE;
+           p += 3;
+           break;
+           }
+         *log_msgptr = US"bad option value for control=utf8_downconvert";
+         }
+       else
+         {
+         message_utf8_downconvert = 1;
+         addr->prop.utf8_downcvt = TRUE;
+         addr->prop.utf8_downcvt_maybe = FALSE;
+         break;
+         }
+       return ERROR;
+    #endif
+
        }
       break;
       }
@@ -3391,14 +3448,9 @@ for (; cb != NULL; cb = cb->next)
       /* Run the dcc backend. */
       rc = dcc_process(&ss);
       /* Modify return code based upon the existance of options. */
-      while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))
-            != NULL) {
+      while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
         if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER)
-          {
-          /* FAIL so that the message is passed to the next ACL */
-          rc = FAIL;
-          }
-        }
+          rc = FAIL;   /* FAIL so that the message is passed to the next ACL */
       }
     break;
     #endif
@@ -3530,7 +3582,8 @@ for (; cb != NULL; cb = cb->next)
     rc = verify_check_this_host(&arg, sender_host_cache, NULL,
       (sender_host_address == NULL)? US"" : sender_host_address,
       CUSS &host_data);
-    if (host_data != NULL) host_data = string_copy_malloc(host_data);
+    if (rc == DEFER) *log_msgptr = search_error_message;
+    if (host_data) host_data = string_copy_malloc(host_data);
     break;
 
     case ACLC_LOCAL_PARTS:
@@ -3545,8 +3598,7 @@ for (; cb != NULL; cb = cb->next)
       int sep = 0;
       const uschar *s = arg;
       uschar *ss;
-      while ((ss = string_nextinlist(&s, &sep, big_buffer, big_buffer_size))
-              != NULL)
+      while ((ss = string_nextinlist(&s, &sep, big_buffer, big_buffer_size)))
         {
         if (Ustrcmp(ss, "main") == 0) logbits |= LOG_MAIN;
         else if (Ustrcmp(ss, "panic") == 0) logbits |= LOG_PANIC;
@@ -4383,7 +4435,11 @@ if (where == ACL_WHERE_RCPT)
     return DEFER;
     }
 #ifdef EXPERIMENTAL_INTERNATIONAL
-  addr->p.utf8 = message_smtputf8;
+  if ((addr->prop.utf8_msg = message_smtputf8))
+    {
+    addr->prop.utf8_downcvt =       message_utf8_downconvert == 1;
+    addr->prop.utf8_downcvt_maybe = message_utf8_downconvert == -1;
+    }
 #endif
   deliver_domain = addr->domain;
   deliver_localpart = addr->local_part;