Only expand integers for integer math once
[exim.git] / src / src / expand.c
index 9532d9d3364f2987e9bfaf6ce816932307138df3..c6356fbe12202145895a8aa15aaf2c90643ccfc7 100644 (file)
@@ -14,6 +14,7 @@
 /* Recursively called function */
 
 static uschar *expand_string_internal(uschar *, BOOL, uschar **, BOOL, BOOL, BOOL *);
+static int_eximarith_t expanded_string_integer(uschar *, BOOL);
 
 #ifdef STAND_ALONE
 #ifndef SUPPORT_CRYPTEQ
@@ -205,6 +206,7 @@ static uschar *op_table_main[] = {
   US"rxquote",
   US"s",
   US"sha1",
+  US"sha256",
   US"stat",
   US"str2b64",
   US"strlen",
@@ -242,6 +244,7 @@ enum {
   EOP_RXQUOTE,
   EOP_S,
   EOP_SHA1,
+  EOP_SHA256,
   EOP_STAT,
   EOP_STR2B64,
   EOP_STRLEN,
@@ -346,25 +349,9 @@ enum {
 };
 
 
-/* Type for main variable table */
-
-typedef struct {
-  const char *name;
-  int         type;
-  void       *value;
-} var_entry;
-
-/* Type for entries pointing to address/length pairs. Not currently
-in use. */
-
-typedef struct {
-  uschar **address;
-  int  *length;
-} alblock;
-
 /* Types of table entry */
 
-enum {
+enum vtypes {
   vtype_int,            /* value is address of int */
   vtype_filter_int,     /* ditto, but recognized only when filtering */
   vtype_ino,            /* value is address of ino_t (not always an int) */
@@ -397,7 +384,23 @@ enum {
   #ifndef DISABLE_DKIM
   ,vtype_dkim           /* Lookup of value in DKIM signature */
   #endif
-  };
+};
+
+/* Type for main variable table */
+
+typedef struct {
+  const char *name;
+  enum vtypes type;
+  void       *value;
+} var_entry;
+
+/* Type for entries pointing to address/length pairs. Not currently
+in use. */
+
+typedef struct {
+  uschar **address;
+  int  *length;
+} alblock;
 
 static uschar * fn_recipients(void);
 
@@ -675,7 +678,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 },
-#if defined(SUPPORT_TLS) && !defined(USE_GNUTLS)
+#if defined(SUPPORT_TLS)
   { "tls_in_sni",          vtype_stringptr,   &tls_in.sni },
 #endif
   { "tls_out_bits",        vtype_int,         &tls_out.bits },
@@ -685,12 +688,12 @@ 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 },
-#if defined(SUPPORT_TLS) && !defined(USE_GNUTLS)
+#if defined(SUPPORT_TLS)
   { "tls_out_sni",         vtype_stringptr,   &tls_out.sni },
 #endif
 
   { "tls_peerdn",          vtype_stringptr,   &tls_in.peerdn },        /* mind the alphabetical order! */
-#if defined(SUPPORT_TLS) && !defined(USE_GNUTLS)
+#if defined(SUPPORT_TLS)
   { "tls_sni",             vtype_stringptr,   &tls_in.sni },   /* mind the alphabetical order! */
 #endif
 
@@ -2443,7 +2446,7 @@ switch(cond_type)
         }
       else
         {
-        num[i] = expand_string_integer(sub[i], FALSE);
+        num[i] = expanded_string_integer(sub[i], FALSE);
         if (expand_string_message != NULL) return NULL;
         }
       }
@@ -4665,6 +4668,9 @@ while (*s != 0)
 
         DEBUG(D_expand) debug_printf("connected to socket %s\n", sub_arg[0]);
 
+       /* Allow sequencing of test actions */
+       if (running_in_test_harness) millisleep(100);
+
         /* Write the request string, if not empty */
 
         if (sub_arg[1][0] != 0)
@@ -4688,6 +4694,8 @@ while (*s != 0)
         shutdown(fd, SHUT_WR);
         #endif
 
+       if (running_in_test_harness) millisleep(100);
+
         /* Now we need to read from the socket, under a timeout. The function
         that reads a file can be used. */
 
@@ -5365,8 +5373,6 @@ while (*s != 0)
 #ifdef SUPPORT_TLS
     case EITEM_CERTEXTRACT:
       {
-      int i;
-      int field_number = 1;
       uschar *save_lookup_value = lookup_value;
       uschar *sub[2];
       int save_expand_nmax =
@@ -5382,7 +5388,6 @@ while (*s != 0)
       /* strip spaces fore & aft */
       {
       int len;
-      int x = 0;
       uschar *p = sub[0];
 
       while (isspace(*p)) p++;
@@ -5725,7 +5730,7 @@ while (*s != 0)
     int c;
     uschar *arg = NULL;
     uschar *sub;
-    var_entry *vp;
+    var_entry *vp = NULL;
 
     /* Owing to an historical mis-design, an underscore may be part of the
     operator name, or it may introduce arguments.  We therefore first scan the
@@ -5747,8 +5752,10 @@ while (*s != 0)
     as we do not want to do the usual expansion. For most, expand the string.*/
     switch(c)
       {
-      case EOP_SHA1:
+#ifdef SUPPORT_TLS
       case EOP_MD5:
+      case EOP_SHA1:
+      case EOP_SHA256:
        if (s[1] == '$')
          {
          uschar * s1 = s;
@@ -5761,9 +5768,10 @@ while (*s != 0)
            s = s1+1;
            break;
            }
+         vp = NULL;
          }
-       vp = NULL;
         /*FALLTHROUGH*/
+#endif
       default:
        sub = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
        if (!sub) goto EXPAND_FAILED;
@@ -5855,12 +5863,14 @@ while (*s != 0)
         }
 
       case EOP_MD5:
+#ifdef SUPPORT_TLS
        if (vp && *(void **)vp->value)
          {
          uschar * cp = tls_cert_fprt_md5(*(void **)vp->value);
-         yield = string_cat(yield, &size, &ptr, cp, (int)strlen(cp));
+         yield = string_cat(yield, &size, &ptr, cp, Ustrlen(cp));
          }
        else
+#endif
          {
          md5 base;
          uschar digest[16];
@@ -5874,12 +5884,14 @@ while (*s != 0)
         continue;
 
       case EOP_SHA1:
+#ifdef SUPPORT_TLS
        if (vp && *(void **)vp->value)
          {
          uschar * cp = tls_cert_fprt_sha1(*(void **)vp->value);
-         yield = string_cat(yield, &size, &ptr, cp, (int)strlen(cp));
+         yield = string_cat(yield, &size, &ptr, cp, Ustrlen(cp));
          }
        else
+#endif
          {
          sha1 base;
          uschar digest[20];
@@ -5892,6 +5904,18 @@ while (*s != 0)
          }
         continue;
 
+      case EOP_SHA256:
+#ifdef SUPPORT_TLS
+       if (vp && *(void **)vp->value)
+         {
+         uschar * cp = tls_cert_fprt_sha256(*(void **)vp->value);
+         yield = string_cat(yield, &size, &ptr, cp, (int)Ustrlen(cp));
+         }
+       else
+#endif
+         expand_string_message = US"sha256 only supported for certificates";
+        continue;
+
       /* Convert hex encoding to base64 encoding */
 
       case EOP_HEX2B64:
@@ -6343,7 +6367,7 @@ while (*s != 0)
       case EOP_UTF8CLEAN:
         {
         int seq_len, index = 0;
-        int bytes_left  = 0;
+        int bytes_left = 0;
         uschar seq_buff[4];                    /* accumulate utf-8 here */
         
         while (*sub != 0)
@@ -6354,7 +6378,7 @@ while (*s != 0)
 
          complete = 0;
          c = *sub++;
-         if(bytes_left)
+         if (bytes_left)
            {
            if ((c & 0xc0) != 0x80)
              {
@@ -6656,7 +6680,7 @@ while (*s != 0)
         int_eximarith_t max;
         uschar *s;
 
-        max = expand_string_integer(sub, TRUE);
+        max = expanded_string_integer(sub, TRUE);
         if (expand_string_message != NULL)
           goto EXPAND_FAILED;
         s = string_sprintf("%d", vaguely_random_number((int)max));
@@ -6856,8 +6880,32 @@ Returns:  the integer value, or
 int_eximarith_t
 expand_string_integer(uschar *string, BOOL isplus)
 {
+return expanded_string_integer(expand_string(string), isplus);
+}
+
+
+/*************************************************
+ *         Interpret string as an integer        *
+ *************************************************/
+
+/* Convert a string (that has already been expanded) into an integer.
+
+This function is used inside the expansion code.
+
+Arguments:
+  s       the string to be expanded
+  isplus  TRUE if a non-negative number is expected
+
+Returns:  the integer value, or
+          -1 if string is NULL (which implies an expansion error)
+          -2 for an integer interpretation error
+          expand_string_message is set NULL for an OK integer
+*/
+
+static int_eximarith_t
+expanded_string_integer(uschar *s, BOOL isplus)
+{
 int_eximarith_t value;
-uschar *s = expand_string(string);
 uschar *msg = US"invalid integer \"%s\"";
 uschar *endptr;