HAVE_IPV6=yes in comment; need value!
[exim.git] / src / src / expand.c
index 54501de0b92497984038cefbb9c90b7fb281a183..84167b688d60c756ac0eac726622e7c7c99963b8 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2012 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -363,6 +363,7 @@ enum {
                         /* local_scan()) */
   vtype_todbsdin,       /* value not used; generate BSD inbox tod */
   vtype_tode,           /* value not used; generate tod in epoch format */
                         /* local_scan()) */
   vtype_todbsdin,       /* value not used; generate BSD inbox tod */
   vtype_tode,           /* value not used; generate tod in epoch format */
+  vtype_todel,          /* value not used; generate tod in epoch/usec format */
   vtype_todf,           /* value not used; generate full tod */
   vtype_todl,           /* value not used; generate log tod */
   vtype_todlf,          /* value not used; generate log file datestamp tod */
   vtype_todf,           /* value not used; generate full tod */
   vtype_todl,           /* value not used; generate log tod */
   vtype_todlf,          /* value not used; generate log file datestamp tod */
@@ -615,8 +616,12 @@ static var_entry var_table[] = {
   { "tls_certificate_verified", vtype_int,    &tls_certificate_verified },
   { "tls_cipher",          vtype_stringptr,   &tls_cipher },
   { "tls_peerdn",          vtype_stringptr,   &tls_peerdn },
   { "tls_certificate_verified", vtype_int,    &tls_certificate_verified },
   { "tls_cipher",          vtype_stringptr,   &tls_cipher },
   { "tls_peerdn",          vtype_stringptr,   &tls_peerdn },
+#ifdef SUPPORT_TLS
+  { "tls_sni",             vtype_stringptr,   &tls_sni },
+#endif
   { "tod_bsdinbox",        vtype_todbsdin,    NULL },
   { "tod_epoch",           vtype_tode,        NULL },
   { "tod_bsdinbox",        vtype_todbsdin,    NULL },
   { "tod_epoch",           vtype_tode,        NULL },
+  { "tod_epoch_l",         vtype_todel,       NULL },
   { "tod_full",            vtype_todf,        NULL },
   { "tod_log",             vtype_todl,        NULL },
   { "tod_logfile",         vtype_todlf,       NULL },
   { "tod_full",            vtype_todf,        NULL },
   { "tod_log",             vtype_todl,        NULL },
   { "tod_logfile",         vtype_todlf,       NULL },
@@ -773,6 +778,7 @@ return rc;
 
 
 
 
 
 
+
 /*************************************************
 *        Pseudo-random number generation         *
 *************************************************/
 /*************************************************
 *        Pseudo-random number generation         *
 *************************************************/
@@ -785,19 +791,23 @@ weirdness they'll twist this into.  The result should ideally handle fork().
 However, if we're stuck unable to provide this, then we'll fall back to
 appallingly bad randomness.
 
 However, if we're stuck unable to provide this, then we'll fall back to
 appallingly bad randomness.
 
-If SUPPORT_TLS is defined and OpenSSL is used, then this will not be used.
-The GNUTLS randomness functions found do not seem amenable to extracting
-random numbers outside of a TLS context.  Any volunteers?
+If SUPPORT_TLS is defined then this will not be used except as an emergency
+fallback.
 
 Arguments:
   max       range maximum
 Returns     a random number in range [0, max-1]
 */
 
 
 Arguments:
   max       range maximum
 Returns     a random number in range [0, max-1]
 */
 
-#if !defined(SUPPORT_TLS) || defined(USE_GNUTLS)
+#ifdef SUPPORT_TLS
+# define vaguely_random_number vaguely_random_number_fallback
+#endif
 int
 int
-pseudo_random_number(int max)
+vaguely_random_number(int max)
 {
 {
+#ifdef SUPPORT_TLS
+# undef vaguely_random_number
+#endif
   static pid_t pid = 0;
   pid_t p2;
 #if defined(HAVE_SRANDOM) && !defined(HAVE_SRANDOMDEV)
   static pid_t pid = 0;
   pid_t p2;
 #if defined(HAVE_SRANDOM) && !defined(HAVE_SRANDOMDEV)
@@ -840,7 +850,8 @@ pseudo_random_number(int max)
 #endif
 }
 
 #endif
 }
 
-#endif
+
+
 
 /*************************************************
 *             Pick out a name from a string      *
 
 /*************************************************
 *             Pick out a name from a string      *
@@ -1516,8 +1527,8 @@ while (last > first)
     domain = Ustrrchr(s, '@');
     if (domain == NULL) return s;
     if (domain - s > sizeof(var_buffer) - 1)
     domain = Ustrrchr(s, '@');
     if (domain == NULL) return s;
     if (domain - s > sizeof(var_buffer) - 1)
-      log_write(0, LOG_MAIN|LOG_PANIC_DIE, "local part longer than %d in "
-        "string expansion", sizeof(var_buffer));
+      log_write(0, LOG_MAIN|LOG_PANIC_DIE, "local part longer than " SIZE_T_FMT
+          " in string expansion", sizeof(var_buffer));
     Ustrncpy(var_buffer, s, domain - s);
     var_buffer[domain - s] = 0;
     return var_buffer;
     Ustrncpy(var_buffer, s, domain - s);
     var_buffer[domain - s] = 0;
     return var_buffer;
@@ -1580,6 +1591,9 @@ while (last > first)
     case vtype_tode:                           /* Unix epoch time of day */
     return tod_stamp(tod_epoch);
 
     case vtype_tode:                           /* Unix epoch time of day */
     return tod_stamp(tod_epoch);
 
+    case vtype_todel:                          /* Unix epoch/usec time of day */
+    return tod_stamp(tod_epoch_l);
+
     case vtype_todf:                           /* Full time of day */
     return tod_stamp(tod_full);
 
     case vtype_todf:                           /* Full time of day */
     return tod_stamp(tod_full);
 
@@ -1778,7 +1792,7 @@ BOOL tempcond, combined_cond;
 BOOL *subcondptr;
 BOOL sub2_honour_dollar = TRUE;
 int i, rc, cond_type, roffset;
 BOOL *subcondptr;
 BOOL sub2_honour_dollar = TRUE;
 int i, rc, cond_type, roffset;
-int num[2];
+int_eximarith_t num[2];
 struct stat statbuf;
 uschar name[256];
 uschar *sub[4];
 struct stat statbuf;
 uschar name[256];
 uschar *sub[4];
@@ -3066,14 +3080,14 @@ Returns:      on success: the value of the expression, with *error still NULL
               on failure: an undefined value, with *error = a message
 */
 
               on failure: an undefined value, with *error = a message
 */
 
-static int eval_op_or(uschar **, BOOL, uschar **);
+static int_eximarith_t eval_op_or(uschar **, BOOL, uschar **);
 
 
 
 
-static int
+static int_eximarith_t
 eval_expr(uschar **sptr, BOOL decimal, uschar **error, BOOL endket)
 {
 uschar *s = *sptr;
 eval_expr(uschar **sptr, BOOL decimal, uschar **error, BOOL endket)
 {
 uschar *s = *sptr;
-int x = eval_op_or(&s, decimal, error);
+int_eximarith_t x = eval_op_or(&s, decimal, error);
 if (*error == NULL)
   {
   if (endket)
 if (*error == NULL)
   {
   if (endket)
@@ -3090,21 +3104,26 @@ return x;
 }
 
 
 }
 
 
-static int
+static int_eximarith_t
 eval_number(uschar **sptr, BOOL decimal, uschar **error)
 {
 register int c;
 eval_number(uschar **sptr, BOOL decimal, uschar **error)
 {
 register int c;
-int n;
+int_eximarith_t n;
 uschar *s = *sptr;
 while (isspace(*s)) s++;
 c = *s;
 if (isdigit(c))
   {
   int count;
 uschar *s = *sptr;
 while (isspace(*s)) s++;
 c = *s;
 if (isdigit(c))
   {
   int count;
-  (void)sscanf(CS s, (decimal? "%d%n" : "%i%n"), &n, &count);
+  (void)sscanf(CS s, (decimal? SC_EXIM_DEC "%n" : SC_EXIM_ARITH "%n"), &n, &count);
   s += count;
   s += count;
-  if (tolower(*s) == 'k') { n *= 1024; s++; }
-    else if (tolower(*s) == 'm') { n *= 1024*1024; s++; }
+  switch (tolower(*s))
+    {
+    default: break;
+    case 'k': n *= 1024; s++; break;
+    case 'm': n *= 1024*1024; s++; break;
+    case 'g': n *= 1024*1024*1024; s++; break;
+    }
   while (isspace (*s)) s++;
   }
 else if (c == '(')
   while (isspace (*s)) s++;
   }
 else if (c == '(')
@@ -3122,10 +3141,11 @@ return n;
 }
 
 
 }
 
 
-static int eval_op_unary(uschar **sptr, BOOL decimal, uschar **error)
+static int_eximarith_t
+eval_op_unary(uschar **sptr, BOOL decimal, uschar **error)
 {
 uschar *s = *sptr;
 {
 uschar *s = *sptr;
-int x;
+int_eximarith_t x;
 while (isspace(*s)) s++;
 if (*s == '+' || *s == '-' || *s == '~')
   {
 while (isspace(*s)) s++;
 if (*s == '+' || *s == '-' || *s == '~')
   {
@@ -3143,16 +3163,17 @@ return x;
 }
 
 
 }
 
 
-static int eval_op_mult(uschar **sptr, BOOL decimal, uschar **error)
+static int_eximarith_t
+eval_op_mult(uschar **sptr, BOOL decimal, uschar **error)
 {
 uschar *s = *sptr;
 {
 uschar *s = *sptr;
-int x = eval_op_unary(&s, decimal, error);
+int_eximarith_t x = eval_op_unary(&s, decimal, error);
 if (*error == NULL)
   {
   while (*s == '*' || *s == '/' || *s == '%')
     {
     int op = *s++;
 if (*error == NULL)
   {
   while (*s == '*' || *s == '/' || *s == '%')
     {
     int op = *s++;
-    int y = eval_op_unary(&s, decimal, error);
+    int_eximarith_t y = eval_op_unary(&s, decimal, error);
     if (*error != NULL) break;
     /* SIGFPE both on div/mod by zero and on INT_MIN / -1, which would give
      * a value of INT_MAX+1. Note that INT_MIN * -1 gives INT_MIN for me, which
     if (*error != NULL) break;
     /* SIGFPE both on div/mod by zero and on INT_MIN / -1, which would give
      * a value of INT_MAX+1. Note that INT_MIN * -1 gives INT_MIN for me, which
@@ -3172,12 +3193,12 @@ if (*error == NULL)
      * can just let the other invalid results occur otherwise, as they have
      * until now.  For this one case, we can coerce.
      */
      * can just let the other invalid results occur otherwise, as they have
      * until now.  For this one case, we can coerce.
      */
-    if (y == -1 && x == INT_MIN && op != '*')
+    if (y == -1 && x == LLONG_MIN && op != '*')
       {
       DEBUG(D_expand)
       {
       DEBUG(D_expand)
-        debug_printf("Integer exception dodging: %d%c-1 coerced to %d\n",
-            INT_MIN, op, INT_MAX);
-      x = INT_MAX;
+        debug_printf("Integer exception dodging: " PR_EXIM_ARITH "%c-1 coerced to " PR_EXIM_ARITH "\n",
+            LLONG_MIN, op, LLONG_MAX);
+      x = LLONG_MAX;
       continue;
       }
     if (op == '*')
       continue;
       }
     if (op == '*')
@@ -3202,16 +3223,17 @@ return x;
 }
 
 
 }
 
 
-static int eval_op_sum(uschar **sptr, BOOL decimal, uschar **error)
+static int_eximarith_t
+eval_op_sum(uschar **sptr, BOOL decimal, uschar **error)
 {
 uschar *s = *sptr;
 {
 uschar *s = *sptr;
-int x = eval_op_mult(&s, decimal, error);
+int_eximarith_t x = eval_op_mult(&s, decimal, error);
 if (*error == NULL)
   {
   while (*s == '+' || *s == '-')
     {
     int op = *s++;
 if (*error == NULL)
   {
   while (*s == '+' || *s == '-')
     {
     int op = *s++;
-    int y = eval_op_mult(&s, decimal, error);
+    int_eximarith_t y = eval_op_mult(&s, decimal, error);
     if (*error != NULL) break;
     if (op == '+') x += y; else x -= y;
     }
     if (*error != NULL) break;
     if (op == '+') x += y; else x -= y;
     }
@@ -3221,15 +3243,16 @@ return x;
 }
 
 
 }
 
 
-static int eval_op_shift(uschar **sptr, BOOL decimal, uschar **error)
+static int_eximarith_t
+eval_op_shift(uschar **sptr, BOOL decimal, uschar **error)
 {
 uschar *s = *sptr;
 {
 uschar *s = *sptr;
-int x = eval_op_sum(&s, decimal, error);
+int_eximarith_t x = eval_op_sum(&s, decimal, error);
 if (*error == NULL)
   {
   while ((*s == '<' || *s == '>') && s[1] == s[0])
     {
 if (*error == NULL)
   {
   while ((*s == '<' || *s == '>') && s[1] == s[0])
     {
-    int y;
+    int_eximarith_t y;
     int op = *s++;
     s++;
     y = eval_op_sum(&s, decimal, error);
     int op = *s++;
     s++;
     y = eval_op_sum(&s, decimal, error);
@@ -3242,15 +3265,16 @@ return x;
 }
 
 
 }
 
 
-static int eval_op_and(uschar **sptr, BOOL decimal, uschar **error)
+static int_eximarith_t
+eval_op_and(uschar **sptr, BOOL decimal, uschar **error)
 {
 uschar *s = *sptr;
 {
 uschar *s = *sptr;
-int x = eval_op_shift(&s, decimal, error);
+int_eximarith_t x = eval_op_shift(&s, decimal, error);
 if (*error == NULL)
   {
   while (*s == '&')
     {
 if (*error == NULL)
   {
   while (*s == '&')
     {
-    int y;
+    int_eximarith_t y;
     s++;
     y = eval_op_shift(&s, decimal, error);
     if (*error != NULL) break;
     s++;
     y = eval_op_shift(&s, decimal, error);
     if (*error != NULL) break;
@@ -3262,15 +3286,16 @@ return x;
 }
 
 
 }
 
 
-static int eval_op_xor(uschar **sptr, BOOL decimal, uschar **error)
+static int_eximarith_t
+eval_op_xor(uschar **sptr, BOOL decimal, uschar **error)
 {
 uschar *s = *sptr;
 {
 uschar *s = *sptr;
-int x = eval_op_and(&s, decimal, error);
+int_eximarith_t x = eval_op_and(&s, decimal, error);
 if (*error == NULL)
   {
   while (*s == '^')
     {
 if (*error == NULL)
   {
   while (*s == '^')
     {
-    int y;
+    int_eximarith_t y;
     s++;
     y = eval_op_and(&s, decimal, error);
     if (*error != NULL) break;
     s++;
     y = eval_op_and(&s, decimal, error);
     if (*error != NULL) break;
@@ -3282,15 +3307,16 @@ return x;
 }
 
 
 }
 
 
-static int eval_op_or(uschar **sptr, BOOL decimal, uschar **error)
+static int_eximarith_t
+eval_op_or(uschar **sptr, BOOL decimal, uschar **error)
 {
 uschar *s = *sptr;
 {
 uschar *s = *sptr;
-int x = eval_op_xor(&s, decimal, error);
+int_eximarith_t x = eval_op_xor(&s, decimal, error);
 if (*error == NULL)
   {
   while (*s == '|')
     {
 if (*error == NULL)
   {
   while (*s == '|')
     {
-    int y;
+    int_eximarith_t y;
     s++;
     y = eval_op_xor(&s, decimal, error);
     if (*error != NULL) break;
     s++;
     y = eval_op_xor(&s, decimal, error);
     if (*error != NULL) break;
@@ -5690,7 +5716,7 @@ while (*s != 0)
         {
         uschar *save_sub = sub;
         uschar *error = NULL;
         {
         uschar *save_sub = sub;
         uschar *error = NULL;
-        int n = eval_expr(&sub, (c == EOP_EVAL10), &error, FALSE);
+        int_eximarith_t n = eval_expr(&sub, (c == EOP_EVAL10), &error, FALSE);
         if (error != NULL)
           {
           expand_string_message = string_sprintf("error in expression "
         if (error != NULL)
           {
           expand_string_message = string_sprintf("error in expression "
@@ -5698,7 +5724,7 @@ while (*s != 0)
               save_sub);
           goto EXPAND_FAILED;
           }
               save_sub);
           goto EXPAND_FAILED;
           }
-        sprintf(CS var_buffer, "%d", n);
+        sprintf(CS var_buffer, PR_EXIM_ARITH, n);
         yield = string_cat(yield, &size, &ptr, var_buffer, Ustrlen(var_buffer));
         continue;
         }
         yield = string_cat(yield, &size, &ptr, var_buffer, Ustrlen(var_buffer));
         continue;
         }
@@ -5899,17 +5925,17 @@ while (*s != 0)
         continue;
         }
 
         continue;
         }
 
-      /* pseudo-random number less than N */
+      /* vaguely random number less than N */
 
       case EOP_RANDINT:
         {
 
       case EOP_RANDINT:
         {
-        int max;
+        int_eximarith_t max;
         uschar *s;
 
         max = expand_string_integer(sub, TRUE);
         if (expand_string_message != NULL)
           goto EXPAND_FAILED;
         uschar *s;
 
         max = expand_string_integer(sub, TRUE);
         if (expand_string_message != NULL)
           goto EXPAND_FAILED;
-        s = string_sprintf("%d", pseudo_random_number(max));
+        s = string_sprintf("%d", vaguely_random_number((int)max));
         yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
         continue;
         }
         yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
         continue;
         }
@@ -6100,10 +6126,10 @@ Returns:  the integer value, or
           expand_string_message is set NULL for an OK integer
 */
 
           expand_string_message is set NULL for an OK integer
 */
 
-int
+int_eximarith_t
 expand_string_integer(uschar *string, BOOL isplus)
 {
 expand_string_integer(uschar *string, BOOL isplus)
 {
-long int value;
+int_eximarith_t value;
 uschar *s = expand_string(string);
 uschar *msg = US"invalid integer \"%s\"";
 uschar *endptr;
 uschar *s = expand_string(string);
 uschar *msg = US"invalid integer \"%s\"";
 uschar *endptr;
@@ -6135,7 +6161,7 @@ if (isspace(*s))
     }
   }
 
     }
   }
 
-value = strtol(CS s, CSS &endptr, 10);
+value = strtoll(CS s, CSS &endptr, 10);
 
 if (endptr == s)
   {
 
 if (endptr == s)
   {
@@ -6147,24 +6173,18 @@ else if (value < 0 && isplus)
   }
 else
   {
   }
 else
   {
-  /* Ensure we can cast this down to an int */
-  if (value > INT_MAX  || value < INT_MIN) errno = ERANGE;
-
-  if (errno != ERANGE)
+  if (tolower(*endptr) == 'k')
     {
     {
-    if (tolower(*endptr) == 'k')
-      {
-      if (value > INT_MAX/1024 || value < INT_MIN/1024) errno = ERANGE;
-        else value *= 1024;
-      endptr++;
-      }
+    if (value > LLONG_MAX/1024 || value < LLONG_MIN/1024) errno = ERANGE;
+      else value *= 1024;
+    endptr++;
+    }
     else if (tolower(*endptr) == 'm')
     else if (tolower(*endptr) == 'm')
-      {
-      if (value > INT_MAX/(1024*1024) || value < INT_MIN/(1024*1024))
-        errno = ERANGE;
-      else value *= 1024*1024;
-      endptr++;
-      }
+    {
+    if (value > LLONG_MAX/(1024*1024) || value < LLONG_MIN/(1024*1024))
+      errno = ERANGE;
+    else value *= 1024*1024;
+    endptr++;
     }
   if (errno == ERANGE)
     msg = US"absolute value of integer \"%s\" is too large (overflow)";
     }
   if (errno == ERANGE)
     msg = US"absolute value of integer \"%s\" is too large (overflow)";