Cheap method to follow redis cluster MOVED replies
[exim.git] / src / src / acl.c
index f01f5cf3c0410b271b9a6ae0f7d9d75d346281c1..4be5e071a4550514a4fa2a1fda3c7f8903014c70 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2017 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Code for handling Access Control Lists (ACLs) */
@@ -523,7 +523,8 @@ static control_def controls_list[] = {
   },
 #ifdef SUPPORT_I18N
 [CONTROL_UTF8_DOWNCONVERT] =
-  { US"utf8_downconvert",        TRUE, 0 }
+  { US"utf8_downconvert",        TRUE, (unsigned) ~(ACL_BIT_RCPT | ACL_BIT_VRFY)
+  }
 #endif
 };
 
@@ -957,7 +958,7 @@ else
 
 /* Loop for multiple header lines, taking care about continuations */
 
-for (p = q; *p != 0; )
+for (p = q; *p; p = q)
   {
   const uschar *s;
   uschar * hdr;
@@ -969,7 +970,7 @@ for (p = q; *p != 0; )
   for (;;)
     {
     q = Ustrchr(q, '\n');              /* we know there was a newline */
-    if (*(++q) != ' ' && *q != '\t') break;
+    if (*++q != ' ' && *q != '\t') break;
     }
 
   /* If the line starts with a colon, interpret the instruction for where to
@@ -1004,24 +1005,22 @@ for (p = q; *p != 0; )
   to the front of it. */
 
   for (s = p; s < q - 1; s++)
-    {
     if (*s == ':' || !isgraph(*s)) break;
-    }
 
-  hdr = string_sprintf("%s%.*s", (*s == ':')? "" : "X-ACL-Warn: ", (int) (q - p), p);
+  hdr = string_sprintf("%s%.*s", *s == ':' ? "" : "X-ACL-Warn: ", (int) (q - p), p);
   hlen = Ustrlen(hdr);
 
   /* See if this line has already been added */
 
-  while (*hptr != NULL)
+  while (*hptr)
     {
     if (Ustrncmp((*hptr)->text, hdr, hlen) == 0) break;
-    hptr = &((*hptr)->next);
+    hptr = &(*hptr)->next;
     }
 
   /* Add if not previously present */
 
-  if (*hptr == NULL)
+  if (!*hptr)
     {
     header_line *h = store_get(sizeof(header_line));
     h->text = hdr;
@@ -1029,12 +1028,8 @@ for (p = q; *p != 0; )
     h->type = newtype;
     h->slen = hlen;
     *hptr = h;
-    hptr = &(h->next);
+    hptr = &h->next;
     }
-
-  /* Advance for next header line within the string */
-
-  p = q;
   }
 }
 
@@ -1661,9 +1656,9 @@ if (!(vp->where_allowed & BIT(where)))
 switch(vp->value)
   {
   case VERIFY_REV_HOST_LKUP:
-    if (sender_host_address == NULL) return OK;
+    if (!sender_host_address) return OK;
     if ((rc = acl_verify_reverse(user_msgptr, log_msgptr)) == DEFER)
-      while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
+      while ((ss = string_nextinlist(&list, &sep, NULL, 0)))
        if (strcmpic(ss, US"defer_ok") == 0)
          return OK;
     return rc;
@@ -1682,7 +1677,7 @@ switch(vp->value)
     occurred earlier. If not, we can attempt the verification now. */
 
     if (!helo_verified && !helo_verify_failed) smtp_verify_helo();
-    return helo_verified? OK : FAIL;
+    return helo_verified ? OK : FAIL;
 
   case VERIFY_CSA:
     /* Do Client SMTP Authorization checks in a separate function, and turn the
@@ -1695,6 +1690,23 @@ switch(vp->value)
     DEBUG(D_acl) debug_printf_indent("CSA result %s\n", csa_status);
     return csa_return_code[rc];
 
+#ifdef EXPERIMENTAL_ARC
+  case VERIFY_ARC:
+    {  /* Do Authenticated Received Chain checks in a separate function. */
+    const uschar * condlist = CUS string_nextinlist(&list, &sep, NULL, 0);
+    int csep = 0;
+    uschar * cond;
+
+    if (!(arc_state = acl_verify_arc())) return DEFER;
+    DEBUG(D_acl) debug_printf_indent("ARC verify result %s\n", arc_state);
+
+    if (!condlist) condlist = US"none:pass";
+    while ((cond = string_nextinlist(&condlist, &csep, NULL, 0)))
+      if (Ustrcmp(arc_state, cond) == 0) return OK;
+    return FAIL;
+    }
+#endif
+
   case VERIFY_HDR_SYNTAX:
     /* Check that all relevant header lines have the correct 5322-syntax. If there is
     a syntax error, we return details of the error to the sender if configured to
@@ -1714,7 +1726,7 @@ switch(vp->value)
     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)
+    if (rc != OK && smtp_return_error_details && *log_msgptr)
       *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr);
     return rc;
 
@@ -1722,8 +1734,7 @@ switch(vp->value)
     /* Check that no recipient of this message is "blind", that is, every envelope
     recipient must be mentioned in either To: or Cc:. */
 
-    rc = verify_check_notblind();
-    if (rc != OK)
+    if ((rc = verify_check_notblind()) != OK)
       {
       *log_msgptr = string_sprintf("bcc recipient detected");
       if (smtp_return_error_details)
@@ -2969,9 +2980,8 @@ for (; cb != NULL; cb = cb->next)
     break;
 
     case ACLC_AUTHENTICATED:
-    rc = (sender_host_authenticated == NULL)? FAIL :
-      match_isinlist(sender_host_authenticated, &arg, 0, NULL, NULL, MCL_STRING,
-        TRUE, NULL);
+      rc = sender_host_authenticated ? match_isinlist(sender_host_authenticated,
+             &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL) : FAIL;
     break;
 
     #ifdef EXPERIMENTAL_BRIGHTMAIL
@@ -3251,6 +3261,8 @@ for (; cb != NULL; cb = cb->next)
        break;
 
        case CONTROL_CUTTHROUGH_DELIVERY:
+       {
+       uschar * ignored = NULL;
 #ifndef DISABLE_PRDR
        if (prdr_requested)
 #else
@@ -3259,20 +3271,20 @@ for (; cb != NULL; cb = cb->next)
          /* Too hard to think about for now.  We might in future cutthrough
          the case where both sides handle prdr and this-node prdr acl
          is "accept" */
-         *log_msgptr = string_sprintf("PRDR on %s reception\n", arg);
+         ignored = US"PRDR active";
        else
          {
          if (deliver_freeze)
-           *log_msgptr = US"frozen";
+           ignored = US"frozen";
          else if (queue_only_policy)
-           *log_msgptr = US"queue-only";
+           ignored = US"queue-only";
          else if (fake_response == FAIL)
-           *log_msgptr = US"fakereject";
+           ignored = US"fakereject";
          else
            {
            if (rcpt_count == 1)
              {
-             cutthrough.delivery = TRUE;
+             cutthrough.delivery = TRUE;       /* control accepted */
              while (*p == '/')
                {
                const uschar * pp = p+1;
@@ -3287,12 +3299,14 @@ for (; cb != NULL; cb = cb->next)
                p = pp;
                }
              }
-           break;
+           else
+             ignored = US"nonfirst rcpt";
            }
-         *log_msgptr = string_sprintf("\"control=%s\" on %s item",
-                                       arg, *log_msgptr);
          }
-       return ERROR;
+       DEBUG(D_acl) if (ignored)
+         debug_printf(" cutthrough request ignored on %s item\n", ignored);
+       }
+       break;
 
 #ifdef SUPPORT_I18N
        case CONTROL_UTF8_DOWNCONVERT:
@@ -4417,22 +4431,29 @@ switch (where)
     else if (  rc == OK
            && cutthrough.delivery
            && rcpt_count > cutthrough.nrcpt
-           && (rc = open_cutthrough_connection(addr)) == DEFER
            )
-      if (cutthrough.defer_pass)
-       {
-       uschar * s = addr->message;
-       /* Horrid kludge to recover target's SMTP message */
-       while (*s) s++;
-       do --s; while (!isdigit(*s));
-       if (*--s && isdigit(*s) && *--s && isdigit(*s)) *user_msgptr = s;
-       acl_temp_details = TRUE;
-       }
-      else
-       {
-       HDEBUG(D_acl) debug_printf_indent("cutthrough defer; will spool\n");
-       rc = OK;
-       }
+      {
+      if ((rc = open_cutthrough_connection(addr)) == DEFER)
+       if (cutthrough.defer_pass)
+         {
+         uschar * s = addr->message;
+         /* Horrid kludge to recover target's SMTP message */
+         while (*s) s++;
+         do --s; while (!isdigit(*s));
+         if (*--s && isdigit(*s) && *--s && isdigit(*s)) *user_msgptr = s;
+         acl_temp_details = TRUE;
+         }
+       else
+         {
+         HDEBUG(D_acl) debug_printf_indent("cutthrough defer; will spool\n");
+         rc = OK;
+         }
+      }
+    else HDEBUG(D_acl) if (cutthrough.delivery)
+      if (rcpt_count <= cutthrough.nrcpt)
+       debug_printf_indent("ignore cutthrough request; nonfirst message\n");
+      else if (rc != OK)
+       debug_printf_indent("ignore cutthrough request; ACL did not accept\n");
     break;
 
   case ACL_WHERE_PREDATA: