X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/80a47a2c9633437d4ceebd214cd44abfbd4f4543..54e7ce4ad20a6977ee895a358259122bf3630090:/src/src/expand.c diff --git a/src/src/expand.c b/src/src/expand.c index d01d0d11e..06e0eb0ce 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/expand.c,v 1.98 2009/06/10 07:34:04 tom Exp $ */ +/* $Cambridge: exim/src/src/expand.c,v 1.108 2010/06/07 08:42:15 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, @@ -242,6 +246,8 @@ static uschar *cond_table[] = { US">", US">=", US"and", + US"bool", + US"bool_lax", US"crypteq", US"def", US"eq", @@ -283,6 +289,8 @@ enum { ECOND_NUM_G, ECOND_NUM_GE, ECOND_AND, + ECOND_BOOL, + ECOND_BOOL_LAX, ECOND_CRYPTEQ, ECOND_DEF, ECOND_STR_EQ, @@ -320,9 +328,9 @@ enum { /* Type for main variable table */ typedef struct { - char *name; - int type; - void *value; + const char *name; + int type; + void *value; } var_entry; /* Type for entries pointing to address/length pairs. Not currently @@ -411,6 +419,7 @@ static var_entry var_table[] = { { "dkim_canon_headers", vtype_dkim, (void *)DKIM_CANON_HEADERS }, { "dkim_copiedheaders", vtype_dkim, (void *)DKIM_COPIEDHEADERS }, { "dkim_created", vtype_dkim, (void *)DKIM_CREATED }, + { "dkim_cur_signer", vtype_stringptr, &dkim_cur_signer }, { "dkim_domain", vtype_stringptr, &dkim_signing_domain }, { "dkim_expires", vtype_dkim, (void *)DKIM_EXPIRES }, { "dkim_headernames", vtype_dkim, (void *)DKIM_HEADERNAMES }, @@ -421,7 +430,7 @@ static var_entry var_table[] = { { "dkim_key_srvtype", vtype_dkim, (void *)DKIM_KEY_SRVTYPE }, { "dkim_key_testing", vtype_dkim, (void *)DKIM_KEY_TESTING }, { "dkim_selector", vtype_stringptr, &dkim_signing_selector }, - { "dkim_signing_domains",vtype_stringptr, &dkim_signing_domains }, + { "dkim_signers", vtype_stringptr, &dkim_signers }, { "dkim_verify_reason", vtype_dkim, (void *)DKIM_VERIFY_REASON }, { "dkim_verify_status", vtype_dkim, (void *)DKIM_VERIFY_STATUS}, #endif @@ -623,9 +632,9 @@ static BOOL malformed_header; /* For textual hashes */ -static char *hashcodes = "abcdefghijklmnopqrtsuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789"; +static const char *hashcodes = "abcdefghijklmnopqrtsuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; enum { HMAC_MD5, HMAC_SHA1 }; @@ -727,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 @@ -756,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 * *************************************************/ @@ -1507,7 +1587,7 @@ while (last > first) return tod_stamp(tod_zulu); case vtype_todlf: /* Log file datestamp tod */ - return tod_stamp(tod_log_datestamp); + return tod_stamp(tod_log_datestamp_daily); case vtype_reply: /* Get reply address */ s = find_header(US"reply-to:", exists_only, newsize, TRUE, @@ -1565,9 +1645,9 @@ while (last > first) } return var_buffer; - #ifndef DKIM_DISABLE + #ifndef DISABLE_DKIM case vtype_dkim: - return dkim_exim_expand_query((int)var_table[middle].value); + return dkim_exim_expand_query((int)(long)var_table[middle].value); #endif } @@ -2408,6 +2488,80 @@ switch(cond_type) } + /* The bool{} expansion condition maps a string to boolean. + The values supported should match those supported by the ACL condition + (acl.c, ACLC_CONDITION) so that we keep to a minimum the different ideas + of true/false. Note that Router "condition" rules have a different + 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. + 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, *t2; + uschar *ourname; + size_t len; + BOOL boolvalue = FALSE; + while (isspace(*s)) s++; + if (*s != '{') goto COND_FAILED_CURLY_START; + 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 = string_sprintf( + "too few arguments or bracketing error for %s", + ourname); + /*FALLTHROUGH*/ + case 2: + case 3: return NULL; + } + t = sub_arg[0]; + while (isspace(*t)) t++; + len = Ustrlen(t); + if (len) + { + /* trailing whitespace: seems like a good idea to ignore it too */ + t2 = t + len - 1; + while (isspace(*t2)) t2--; + if (t2 != (t + len)) + { + *++t2 = '\0'; + len = t2 - t; + } + } + DEBUG(D_expand) + 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 " + "value \"%s\"", t); + return NULL; + } + if (yield != NULL) *yield = (boolvalue != 0); + return s; + } + /* Unknown condition */ default: @@ -2953,7 +3107,16 @@ if (*error == NULL) int y = eval_op_unary(&s, decimal, error); if (*error != NULL) break; if (op == '*') x *= y; - else if (op == '/') x /= y; + else if (op == '/') + { + if (y == 0) + { + *error = US"divide by zero"; + x = 0; + break; + } + x /= y; + } else x %= y; } } @@ -3521,8 +3684,8 @@ while (*s != 0) if (search_find_defer) { expand_string_message = - string_sprintf("lookup of \"%s\" gave DEFER: %s", key, - search_error_message); + string_sprintf("lookup of \"%s\" gave DEFER: %s", + string_printing2(key, FALSE), search_error_message); goto EXPAND_FAILED; } if (expand_setup > 0) expand_nmax = expand_setup; @@ -5352,8 +5515,8 @@ while (*s != 0) goto EXPAND_FAILED; } - if (lookup_list[n].quote != NULL) - sub = (lookup_list[n].quote)(sub, opt); + if (lookup_list[n]->quote != NULL) + sub = (lookup_list[n]->quote)(sub, opt); else if (opt != NULL) sub = NULL; if (sub == NULL) @@ -5654,6 +5817,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: