X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/2df588c9eec886db81da1ff981946d2c91ae789d..6a8de8541c16d12eceab2c6610cd209e7641217a:/src/src/expand.c diff --git a/src/src/expand.c b/src/src/expand.c index 47453dc6d..9f9cbb7be 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/expand.c,v 1.103 2009/10/15 08:27:37 tom Exp $ */ +/* $Cambridge: exim/src/src/expand.c,v 1.107 2010/06/07 08:23:20 pdp Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2007 */ +/* Copyright (c) University of Cambridge 1995 - 2009 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -156,6 +156,7 @@ static uschar *op_table_underscore[] = { US"from_utf8", US"local_part", US"quote_local_part", + US"reverse_ip", US"time_eval", US"time_interval"}; @@ -163,6 +164,7 @@ enum { EOP_FROM_UTF8, EOP_LOCAL_PART, EOP_QUOTE_LOCAL_PART, + EOP_REVERSE_IP, EOP_TIME_EVAL, EOP_TIME_INTERVAL }; @@ -187,6 +189,7 @@ static uschar *op_table_main[] = { US"nh", US"nhash", US"quote", + US"randint", US"rfc2047", US"rfc2047d", US"rxquote", @@ -219,6 +222,7 @@ enum { EOP_NH, EOP_NHASH, EOP_QUOTE, + EOP_RANDINT, EOP_RFC2047, EOP_RFC2047D, EOP_RXQUOTE, @@ -243,6 +247,7 @@ static uschar *cond_table[] = { US">=", US"and", US"bool", + US"bool_lax", US"crypteq", US"def", US"eq", @@ -285,6 +290,7 @@ enum { ECOND_NUM_GE, ECOND_AND, ECOND_BOOL, + ECOND_BOOL_LAX, ECOND_CRYPTEQ, ECOND_DEF, ECOND_STR_EQ, @@ -730,6 +736,8 @@ or "false" value. Failure of the expansion yields FALSE; logged unless it was a forced fail or lookup defer. All store used by the function can be released on exit. +The actual false-value tests should be replicated for ECOND_BOOL_LAX. + Arguments: condition the condition string m1 text to be incorporated in panic error @@ -759,6 +767,75 @@ return rc; +/************************************************* +* Pseudo-random number generation * +*************************************************/ + +/* Pseudo-random number generation. The result is not "expected" to be +cryptographically strong but not so weak that someone will shoot themselves +in the foot using it as a nonce in some email header scheme or whatever +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. + +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? + +Arguments: + max range maximum +Returns a random number in range [0, max-1] +*/ + +#if !defined(SUPPORT_TLS) || defined(USE_GNUTLS) +int +pseudo_random_number(int max) +{ + static pid_t pid = 0; + pid_t p2; +#if defined(HAVE_SRANDOM) && !defined(HAVE_SRANDOMDEV) + struct timeval tv; +#endif + + p2 = getpid(); + if (p2 != pid) + { + if (pid != 0) + { + +#ifdef HAVE_ARC4RANDOM + /* cryptographically strong randomness, common on *BSD platforms, not + so much elsewhere. Alas. */ + arc4random_stir(); +#elif defined(HAVE_SRANDOM) || defined(HAVE_SRANDOMDEV) +#ifdef HAVE_SRANDOMDEV + /* uses random(4) for seeding */ + srandomdev(); +#else + gettimeofday(&tv, NULL); + srandom(tv.tv_sec | tv.tv_usec | getpid()); +#endif +#else + /* Poor randomness and no seeding here */ +#endif + + } + pid = p2; + } + +#ifdef HAVE_ARC4RANDOM + return arc4random() % max; +#elif defined(HAVE_SRANDOM) || defined(HAVE_SRANDOMDEV) + return random() % max; +#else + /* This one returns a 16-bit number, definitely not crypto-strong */ + return random_number(max); +#endif +} + +#endif + /************************************************* * Pick out a name from a string * *************************************************/ @@ -2418,19 +2495,25 @@ switch(cond_type) interpretation, where general data can be used and only a few values map to FALSE. Note that readconf.c boolean matching, for boolean configuration options, - only matches true/yes/false/no. */ + only matches true/yes/false/no. + The bool_lax{} condition matches the Router logic, which is much more + liberal. */ case ECOND_BOOL: + case ECOND_BOOL_LAX: { uschar *sub_arg[1]; uschar *t; + uschar *ourname; size_t len; BOOL boolvalue = FALSE; while (isspace(*s)) s++; if (*s != '{') goto COND_FAILED_CURLY_START; - switch(read_subs(sub_arg, 1, 1, &s, yield == NULL, FALSE, US"bool")) + ourname = cond_type == ECOND_BOOL_LAX ? US"bool_lax" : US"bool"; + switch(read_subs(sub_arg, 1, 1, &s, yield == NULL, FALSE, ourname)) { - case 1: expand_string_message = US"too few arguments or bracketing " - "error for bool"; + case 1: expand_string_message = string_sprintf( + "too few arguments or bracketing error for %s", + ourname); /*FALLTHROUGH*/ case 2: case 3: return NULL; @@ -2439,15 +2522,25 @@ switch(cond_type) while (isspace(*t)) t++; len = Ustrlen(t); DEBUG(D_expand) - debug_printf("considering bool: %s\n", len ? t : US""); + debug_printf("considering %s: %s\n", ourname, len ? t : US""); + /* logic for the lax case from expand_check_condition(), which also does + expands, and the logic is both short and stable enough that there should + be no maintenance burden from replicating it. */ if (len == 0) boolvalue = FALSE; else if (Ustrspn(t, "0123456789") == len) + { boolvalue = (Uatoi(t) == 0) ? FALSE : TRUE; + /* expand_check_condition only does a literal string "0" check */ + if ((cond_type == ECOND_BOOL_LAX) && (len > 1)) + boolvalue = TRUE; + } else if (strcmpic(t, US"true") == 0 || strcmpic(t, US"yes") == 0) boolvalue = TRUE; else if (strcmpic(t, US"false") == 0 || strcmpic(t, US"no") == 0) boolvalue = FALSE; + else if (cond_type == ECOND_BOOL_LAX) + boolvalue = TRUE; else { expand_string_message = string_sprintf("unrecognised boolean " @@ -5704,6 +5797,40 @@ while (*s != 0) continue; } + /* pseudo-random number less than N */ + + case EOP_RANDINT: + { + int max; + uschar *s; + + max = expand_string_integer(sub, TRUE); + if (expand_string_message != NULL) + goto EXPAND_FAILED; + s = string_sprintf("%d", pseudo_random_number(max)); + yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); + continue; + } + + /* Reverse IP, including IPv6 to dotted-nibble */ + + case EOP_REVERSE_IP: + { + int family, maskptr; + uschar reversed[128]; + + family = string_is_ip_address(sub, &maskptr); + if (family == 0) + { + expand_string_message = string_sprintf( + "reverse_ip() not given an IP address [%s]", sub); + goto EXPAND_FAILED; + } + invert_address(reversed, sub); + yield = string_cat(yield, &size, &ptr, reversed, Ustrlen(reversed)); + continue; + } + /* Unknown operator */ default: