Docs: Fix various typos (Closes 2650, 2651)
[exim.git] / src / src / expand.c
index 6d43774f18c1c3d78c41b5a98107bdb6dcecd295..9bb30de4f3f8f5514c42f4e0ee13f89684b72c1b 100644 (file)
@@ -3,6 +3,7 @@
 *************************************************/
 
 /* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -130,7 +131,7 @@ static uschar *item_table[] = {
   US"run",
   US"sg",
   US"sort",
-#ifdef EXPERIMENTAL_SRS_NATIVE
+#ifdef SUPPORT_SRS
   US"srs_encode",
 #endif
   US"substr",
@@ -165,7 +166,7 @@ enum {
   EITEM_RUN,
   EITEM_SG,
   EITEM_SORT,
-#ifdef EXPERIMENTAL_SRS_NATIVE
+#ifdef SUPPORT_SRS
   EITEM_SRS_ENCODE,
 #endif
   EITEM_SUBSTR,
@@ -333,7 +334,7 @@ static uschar *cond_table[] = {
   US"gei",
   US"gt",
   US"gti",
-#ifdef EXPERIMENTAL_SRS_NATIVE
+#ifdef SUPPORT_SRS
   US"inbound_srs",
 #endif
   US"inlist",
@@ -386,7 +387,7 @@ enum {
   ECOND_STR_GEI,
   ECOND_STR_GT,
   ECOND_STR_GTI,
-#ifdef EXPERIMENTAL_SRS_NATIVE
+#ifdef SUPPORT_SRS
   ECOND_INBOUND_SRS,
 #endif
   ECOND_INLIST,
@@ -594,7 +595,6 @@ static var_entry var_table[] = {
   { "local_part_prefix_v", vtype_stringptr,   &deliver_localpart_prefix_v },
   { "local_part_suffix",   vtype_stringptr,   &deliver_localpart_suffix },
   { "local_part_suffix_v", vtype_stringptr,   &deliver_localpart_suffix_v },
-  { "local_part_verified", vtype_stringptr,   &deliver_localpart_verified },
 #ifdef HAVE_LOCAL_SCAN
   { "local_scan_data",     vtype_stringptr,   &local_scan_data },
 #endif
@@ -752,16 +752,16 @@ static var_entry var_table[] = {
   { "spool_directory",     vtype_stringptr,   &spool_directory },
   { "spool_inodes",        vtype_pinodes,     (void *)TRUE },
   { "spool_space",         vtype_pspace,      (void *)TRUE },
-#ifdef EXPERIMENTAL_SRS
+#ifdef EXPERIMENTAL_SRS_ALT
   { "srs_db_address",      vtype_stringptr,   &srs_db_address },
   { "srs_db_key",          vtype_stringptr,   &srs_db_key },
   { "srs_orig_recipient",  vtype_stringptr,   &srs_orig_recipient },
   { "srs_orig_sender",     vtype_stringptr,   &srs_orig_sender },
 #endif
-#if defined(EXPERIMENTAL_SRS) || defined(EXPERIMENTAL_SRS_NATIVE)
+#if defined(EXPERIMENTAL_SRS_ALT) || defined(SUPPORT_SRS)
   { "srs_recipient",       vtype_stringptr,   &srs_recipient },
 #endif
-#ifdef EXPERIMENTAL_SRS
+#ifdef EXPERIMENTAL_SRS_ALT
   { "srs_status",          vtype_stringptr,   &srs_status },
 #endif
   { "thisaddress",         vtype_stringptr,   &filter_thisaddress },
@@ -779,7 +779,7 @@ static var_entry var_table[] = {
   { "tls_in_ourcert",      vtype_cert,        &tls_in.ourcert },
   { "tls_in_peercert",     vtype_cert,        &tls_in.peercert },
   { "tls_in_peerdn",       vtype_stringptr,   &tls_in.peerdn },
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
   { "tls_in_resumption",   vtype_int,         &tls_in.resumption },
 #endif
 #ifndef DISABLE_TLS
@@ -797,7 +797,7 @@ static var_entry var_table[] = {
   { "tls_out_ourcert",     vtype_cert,        &tls_out.ourcert },
   { "tls_out_peercert",    vtype_cert,        &tls_out.peercert },
   { "tls_out_peerdn",      vtype_stringptr,   &tls_out.peerdn },
-#ifdef EXPERIMENTAL_TLS_RESUME
+#ifndef DISABLE_TLS_RESUME
   { "tls_out_resumption",  vtype_int,         &tls_out.resumption },
 #endif
 #ifndef DISABLE_TLS
@@ -1984,11 +1984,12 @@ switch (vp->type)
     ss = (uschar **)(val);
     if (!*ss && deliver_datafile >= 0)  /* Read body when needed */
       {
-      uschar *body;
+      uschar * body;
       off_t start_offset = SPOOL_DATA_START_OFFSET;
       int len = message_body_visible;
+
       if (len > message_size) len = message_size;
-      *ss = body = store_malloc(len+1);
+      *ss = body = store_get(len+1, TRUE);
       body[0] = 0;
       if (vp->type == vtype_msgbody_end)
        {
@@ -2003,8 +2004,7 @@ switch (vp->type)
       if (lseek(deliver_datafile, start_offset, SEEK_SET) < 0)
        log_write(0, LOG_MAIN|LOG_PANIC_DIE, "deliver_datafile lseek: %s",
          strerror(errno));
-      len = read(deliver_datafile, body, len);
-      if (len > 0)
+      if ((len = read(deliver_datafile, body, len)) > 0)
        {
        body[len] = 0;
        if (message_body_newlines)   /* Separate loops for efficiency */
@@ -2066,7 +2066,8 @@ switch (vp->type)
   case vtype_string_func:
     {
     stringptr_fn_t * fn = (stringptr_fn_t *) val;
-    return fn();
+    uschar* s = fn();
+    return s ? s : US"";
     }
 
   case vtype_pspace:
@@ -2438,7 +2439,7 @@ else
 
 
 
-#ifdef EXPERIMENTAL_SRS_NATIVE
+#ifdef SUPPORT_SRS
 /* Do an hmac_md5.  The result is _not_ nul-terminated, and is sized as
 the smaller of a full hmac_md5 result (16 bytes) or the supplied output buffer.
 
@@ -2513,7 +2514,7 @@ for (int i = 0, j = len; i < MD5_HASHLEN; i++)
   }
 return;
 }
-#endif /*EXPERIMENTAL_SRS_NATIVE*/
+#endif /*SUPPORT_SRS*/
 
 
 /*************************************************
@@ -3443,14 +3444,14 @@ switch(cond_type = identify_operator(&s, &opname))
     return s;
     }
 
-#ifdef EXPERIMENTAL_SRS_NATIVE
+#ifdef SUPPORT_SRS
   case ECOND_INBOUND_SRS:
     /* ${if inbound_srs {local_part}{secret}  {yes}{no}} */
     {
     uschar * sub[2];
     const pcre * re;
     int ovec[3*(4+1)];
-    int n;
+    int n, quoting = 0;
     uschar cksum[4];
     BOOL boolvalue = FALSE;
 
@@ -3473,10 +3474,20 @@ switch(cond_type = identify_operator(&s, &opname))
       goto srs_result;
       }
 
-    /* Side-effect: record the decoded recipient */
+    if (sub[0][0] == '"')
+      quoting = 1;
+    else for (uschar * s = sub[0]; *s; s++)
+      if (!isalnum(*s) && Ustrchr(".!#$%&'*+-/=?^_`{|}~", *s) == NULL)
+       { quoting = 1; break; }
+    if (quoting)
+      DEBUG(D_expand) debug_printf_indent("auto-quoting local part\n");
 
-    srs_recipient = string_sprintf("%.*S@%.*S",                /* lowercased */
+    /* Record the (quoted, if needed) decoded recipient as $srs_recipient */
+
+    srs_recipient = string_sprintf("%.*s%.*S%.*s@%.*S",        /* lowercased */
+                     quoting, "\"",
                      ovec[9]-ovec[8], sub[0] + ovec[8],        /* substring 4 */
+                     quoting, "\"",
                      ovec[7]-ovec[6], sub[0] + ovec[6]);       /* substring 3 */
 
     /* If a zero-length secret was given, we're done.  Otherwise carry on
@@ -3535,7 +3546,7 @@ srs_result:
     if (yield) *yield = (boolvalue == testfor);
     return s;
     }
-#endif /*EXPERIMENTAL_SRS_NATIVE*/
+#endif /*SUPPORT_SRS*/
 
   /* Unknown condition */
 
@@ -4389,7 +4400,7 @@ if (is_tainted(string))
   goto EXPAND_FAILED;
   }
 
-while (*s != 0)
+while (*s)
   {
   uschar *value;
   uschar name[256];
@@ -4775,7 +4786,7 @@ while (*s != 0)
       int save_expand_nmax =
         save_expand_strings(save_expand_nstring, save_expand_nlength);
 
-      if ((expand_forbid & RDO_LOOKUP) != 0)
+      if (expand_forbid & RDO_LOOKUP)
         {
         expand_string_message = US"lookup expansions are not permitted";
         goto EXPAND_FAILED;
@@ -4874,21 +4885,7 @@ while (*s != 0)
       file types, the query (i.e. "key") starts with a file name. */
 
       if (!key)
-        {
-       Uskip_whitespace(&filename);
-        key = filename;
-
-        if (mac_islookup(stype, lookup_querystyle))
-          filename = NULL;
-        else
-          if (*filename == '/')
-           {
-           while (*key && !isspace(*key)) key++;
-           if (*key) *key++ = '\0';
-           }
-         else
-           filename = NULL;
-        }
+       key = search_args(stype, name, filename, &filename, opts);
 
       /* If skipping, don't do the next bit - just lookup_value == NULL, as if
       the entry was not found. Note that there is no search_close() function.
@@ -4919,7 +4916,7 @@ while (*s != 0)
           {
           expand_string_message =
             string_sprintf("lookup of \"%s\" gave DEFER: %s",
-              string_printing2(key, FALSE), search_error_message);
+              string_printing2(key, SP_TAB), search_error_message);
           goto EXPAND_FAILED;
           }
         if (expand_setup > 0) expand_nmax = expand_setup;
@@ -5264,7 +5261,7 @@ while (*s != 0)
 
       if (!(f = Ufopen(sub_arg[0], "rb")))
         {
-        expand_string_message = string_open_failed(errno, "%s", sub_arg[0]);
+        expand_string_message = string_open_failed("%s", sub_arg[0]);
         goto EXPAND_FAILED;
         }
 
@@ -5333,11 +5330,14 @@ while (*s != 0)
          while ((item = string_nextinlist(&list, &sep, NULL, 0)))
            g = string_append_listele(g, ',', item);
 
-         /* possibly plus an EOL string */
+         /* possibly plus an EOL string.  Process with escapes, to protect
+         from list-processing.  The only current user of eol= in search
+         options is the readsock expansion. */
+
          if (sub_arg[3] && *sub_arg[3])
            g = string_append_listele(g, ',',
-                 string_sprintf("eol=%s", sub_arg[3]));
-
+                 string_sprintf("eol=%s",
+                   string_printing2(sub_arg[3], SP_TAB|SP_SPACE)));
          }
 
        /* Gat a (possibly cached) handle for the connection */
@@ -6186,11 +6186,12 @@ while (*s != 0)
         case 2:
         case 3: goto EXPAND_FAILED;
         }
-      for (uschar sep = *sub[0], c; c = *sub[1]; sub[1]++)
+      if (*sub[1]) for (uschar sep = *sub[0], c; c = *sub[1]; sub[1]++)
        {
        if (c == sep) yield = string_catn(yield, sub[1], 1);
        yield = string_catn(yield, sub[1], 1);
        }
+      else yield = string_catn(yield, US" ", 1);
       continue;
       }
 
@@ -6783,12 +6784,14 @@ while (*s != 0)
       continue;
       }
 
-#ifdef EXPERIMENTAL_SRS_NATIVE
+#ifdef SUPPORT_SRS
     case EITEM_SRS_ENCODE:
       /* ${srs_encode {secret} {return_path} {orig_domain}} */
       {
       uschar * sub[3];
       uschar cksum[4];
+      gstring * g = NULL;
+      BOOL quoted = FALSE;
 
       switch (read_subs(sub, 3, 3, CUSS &s, skipping, TRUE, name, &resetok))
         {
@@ -6797,47 +6800,71 @@ while (*s != 0)
         case 3: goto EXPAND_FAILED;
         }
 
-      yield = string_catn(yield, US"SRS0=", 5);
+      g = string_catn(g, US"SRS0=", 5);
 
       /* ${l_4:${hmac{md5}{SRS_SECRET}{${lc:$return_path}}}}= */
       hmac_md5(sub[0], string_copylc(sub[1]), cksum, sizeof(cksum));
-      yield = string_catn(yield, cksum, sizeof(cksum));
-      yield = string_catn(yield, US"=", 1);
+      g = string_catn(g, cksum, sizeof(cksum));
+      g = string_catn(g, US"=", 1);
 
       /* ${base32:${eval:$tod_epoch/86400&0x3ff}}= */
        {
        struct timeval now;
        unsigned long i;
-       gstring * g = NULL;
+       gstring * h = NULL;
 
        gettimeofday(&now, NULL);
        for (unsigned long i = (now.tv_sec / 86400) & 0x3ff; i; i >>= 5)
-         g = string_catn(g, &base32_chars[i & 0x1f], 1);
-       if (g) while (g->ptr > 0)
-         yield = string_catn(yield, &g->s[--g->ptr], 1);
+         h = string_catn(h, &base32_chars[i & 0x1f], 1);
+       if (h) while (h->ptr > 0)
+         g = string_catn(g, &h->s[--h->ptr], 1);
        }
-      yield = string_catn(yield, US"=", 1);
+      g = string_catn(g, US"=", 1);
 
       /* ${domain:$return_path}=${local_part:$return_path} */
        {
         int start, end, domain;
         uschar * t = parse_extract_address(sub[1], &expand_string_message,
                                          &start, &end, &domain, FALSE);
+       uschar * s;
+
         if (!t)
          goto EXPAND_FAILED;
 
-       if (domain > 0) yield = string_cat(yield, t + domain);
-       yield = string_catn(yield, US"=", 1);
-       yield = domain > 0
-         ? string_catn(yield, t, domain - 1) : string_cat(yield, t);
+       if (domain > 0) g = string_cat(g, t + domain);
+       g = string_catn(g, US"=", 1);
+
+       s = domain > 0 ? string_copyn(t, domain - 1) : t;
+       if ((quoted = Ustrchr(s, '"') != NULL))
+         {
+         gstring * h = NULL;
+         DEBUG(D_expand) debug_printf_indent("auto-quoting local part\n");
+         while (*s)            /* de-quote */
+           {
+           while (*s && *s != '"') h = string_catn(h, s++, 1);
+           if (*s) s++;
+           while (*s && *s != '"') h = string_catn(h, s++, 1);
+           if (*s) s++;
+           }
+         gstring_release_unused(h);
+         s = string_from_gstring(h);
+         }
+       g = string_cat(g, s);
         }
 
+      /* Assume that if the original local_part had quotes
+      it was for good reason */
+
+      if (quoted) yield = string_catn(yield, US"\"", 1);
+      yield = string_catn(yield, g->s, g->ptr);
+      if (quoted) yield = string_catn(yield, US"\"", 1);
+
       /* @$original_domain */
       yield = string_catn(yield, US"@", 1);
       yield = string_cat(yield, sub[2]);
       continue;
       }
-#endif /*EXPERIMENTAL_SRS_NATIVE*/
+#endif /*SUPPORT_SRS*/
     }  /* EITEM_* switch */
 
   /* Control reaches here if the name is not recognized as one of the more
@@ -7206,9 +7233,8 @@ while (*s != 0)
         {
        int cnt = 0;
        int sep = 0;
-       uschar buffer[256];
 
-       while (string_nextinlist(CUSS &sub, &sep, buffer, sizeof(buffer))) cnt++;
+       while (string_nextinlist(CUSS &sub, &sep, NULL, 0)) cnt++;
        yield = string_fmt_append(yield, "%d", cnt);
         continue;
         }
@@ -7484,24 +7510,20 @@ while (*s != 0)
         uschar *t = sub - 1;
 
         if (c == EOP_QUOTE)
-          {
-          while (!needs_quote && *(++t) != 0)
+          while (!needs_quote && *++t)
             needs_quote = !isalnum(*t) && !strchr("_-.", *t);
-          }
+
         else  /* EOP_QUOTE_LOCAL_PART */
-          {
-          while (!needs_quote && *(++t) != 0)
-            needs_quote = !isalnum(*t) &&
-              strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL &&
-              (*t != '.' || t == sub || t[1] == 0);
-          }
+          while (!needs_quote && *++t)
+            needs_quote = !isalnum(*t)
+             && strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL
+             && (*t != '.' || t == sub || !t[1]);
 
         if (needs_quote)
           {
           yield = string_catn(yield, US"\"", 1);
           t = sub - 1;
-          while (*(++t) != 0)
-            {
+          while (*++t)
             if (*t == '\n')
               yield = string_catn(yield, US"\\n", 2);
             else if (*t == '\r')
@@ -7512,10 +7534,10 @@ while (*s != 0)
                 yield = string_catn(yield, US"\\", 1);
               yield = string_catn(yield, t, 1);
               }
-            }
           yield = string_catn(yield, US"\"", 1);
           }
-        else yield = string_cat(yield, sub);
+        else
+         yield = string_cat(yield, sub);
         continue;
         }
 
@@ -7570,13 +7592,10 @@ while (*s != 0)
       prescribed by the RFC, if there are characters that need to be encoded */
 
       case EOP_RFC2047:
-        {
-        uschar buffer[2048];
         yield = string_cat(yield,
                            parse_quote_2047(sub, Ustrlen(sub), headers_charset,
-                             buffer, sizeof(buffer), FALSE));
+                             FALSE));
         continue;
-        }
 
       /* RFC 2047 decode */