X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Fexpand.c;h=3fb431c2e2d994dd926688d66ca67556fca6992b;hp=fece8c150b4fc8e2e938106b150f24a3d9f42226;hb=817d9f576cdfbc27cf0536be348645baf27d7836;hpb=a5b5269546e02d1f2e90000e79df8409d4f269db diff --git a/src/src/expand.c b/src/src/expand.c index fece8c150..3fb431c2e 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1,10 +1,8 @@ -/* $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 - 2009 */ +/* Copyright (c) University of Cambridge 1995 - 2012 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -15,7 +13,7 @@ /* Recursively called function */ -static uschar *expand_string_internal(uschar *, BOOL, uschar **, BOOL); +static uschar *expand_string_internal(uschar *, BOOL, uschar **, BOOL, BOOL); #ifdef STAND_ALONE #ifndef SUPPORT_CRYPTEQ @@ -260,6 +258,8 @@ static uschar *cond_table[] = { US"gei", US"gt", US"gti", + US"inlist", + US"inlisti", US"isip", US"isip4", US"isip6", @@ -303,6 +303,8 @@ enum { ECOND_STR_GEI, ECOND_STR_GT, ECOND_STR_GTI, + ECOND_INLIST, + ECOND_INLISTI, ECOND_ISIP, ECOND_ISIP4, ECOND_ISIP6, @@ -361,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 */ + 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 */ @@ -389,6 +392,9 @@ static var_entry var_table[] = { { "authenticated_id", vtype_stringptr, &authenticated_id }, { "authenticated_sender",vtype_stringptr, &authenticated_sender }, { "authentication_failed",vtype_int, &authentication_failed }, +#ifdef WITH_CONTENT_SCAN + { "av_failed", vtype_int, &av_failed }, +#endif #ifdef EXPERIMENTAL_BRIGHTMAIL { "bmi_alt_location", vtype_stringptr, &bmi_alt_location }, { "bmi_base64_tracker_verdict", vtype_stringptr, &bmi_base64_tracker_verdict }, @@ -606,11 +612,25 @@ static var_entry var_table[] = { { "srs_status", vtype_stringptr, &srs_status }, #endif { "thisaddress", vtype_stringptr, &filter_thisaddress }, - { "tls_certificate_verified", vtype_int, &tls_certificate_verified }, - { "tls_cipher", vtype_stringptr, &tls_cipher }, - { "tls_peerdn", vtype_stringptr, &tls_peerdn }, + + { "tls_bits", vtype_int, &tls_in.bits }, + { "tls_certificate_verified", vtype_int, &tls_in.certificate_verified }, + { "tls_cipher", vtype_stringptr, &tls_in.cipher }, + { "tls_peerdn", vtype_stringptr, &tls_in.peerdn }, +#if defined(SUPPORT_TLS) && !defined(USE_GNUTLS) + { "tls_sni", vtype_stringptr, &tls_in.sni }, +#endif + { "tls_out_bits", vtype_int, &tls_out.bits }, + { "tls_out_certificate_verified", vtype_int, &tls_out.certificate_verified }, + { "tls_out_cipher", vtype_stringptr, &tls_out.cipher }, + { "tls_out_peerdn", vtype_stringptr, &tls_out.peerdn }, +#if defined(SUPPORT_TLS) && !defined(USE_GNUTLS) + { "tls_out_sni", vtype_stringptr, &tls_out.sni }, +#endif + { "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 }, @@ -767,6 +787,7 @@ return rc; + /************************************************* * Pseudo-random number generation * *************************************************/ @@ -779,19 +800,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. -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] */ -#if !defined(SUPPORT_TLS) || defined(USE_GNUTLS) +#ifdef SUPPORT_TLS +# define vaguely_random_number vaguely_random_number_fallback +#endif 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) @@ -834,7 +859,8 @@ pseudo_random_number(int max) #endif } -#endif + + /************************************************* * Pick out a name from a string * @@ -1510,8 +1536,8 @@ while (last > first) 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; @@ -1574,6 +1600,9 @@ while (last > first) 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); @@ -1698,7 +1727,7 @@ for (i = 0; i < n; i++) sub[i] = NULL; break; } - sub[i] = expand_string_internal(s+1, TRUE, &s, skipping); + sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE); if (sub[i] == NULL) return 3; if (*s++ != '}') return 1; while (isspace(*s)) s++; @@ -1770,8 +1799,9 @@ eval_condition(uschar *s, BOOL *yield) BOOL testfor = TRUE; BOOL tempcond, combined_cond; 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]; @@ -1902,7 +1932,7 @@ switch(cond_type) while (isspace(*s)) s++; if (*s != '{') goto COND_FAILED_CURLY_START; - sub[0] = expand_string_internal(s+1, TRUE, &s, yield == NULL); + sub[0] = expand_string_internal(s+1, TRUE, &s, yield == NULL, TRUE); if (sub[0] == NULL) return NULL; if (*s++ != '}') goto COND_FAILED_CURLY_END; @@ -2015,22 +2045,30 @@ switch(cond_type) /* symbolic operators for numeric and string comparison, and a number of other operators, all requiring two arguments. + crypteq: encrypts plaintext and compares against an encrypted text, + using crypt(), crypt16(), MD5 or SHA-1 + inlist/inlisti: checks if first argument is in the list of the second match: does a regular expression match and sets up the numerical variables if it succeeds match_address: matches in an address list match_domain: matches in a domain list match_ip: matches a host list that is restricted to IP addresses match_local_part: matches in a local part list - crypteq: encrypts plaintext and compares against an encrypted text, - using crypt(), crypt16(), MD5 or SHA-1 */ - case ECOND_MATCH: case ECOND_MATCH_ADDRESS: case ECOND_MATCH_DOMAIN: case ECOND_MATCH_IP: case ECOND_MATCH_LOCAL_PART: +#ifndef EXPAND_LISTMATCH_RHS + sub2_honour_dollar = FALSE; +#endif + /* FALLTHROUGH */ + case ECOND_CRYPTEQ: + case ECOND_INLIST: + case ECOND_INLISTI: + case ECOND_MATCH: case ECOND_NUM_L: /* Numerical comparisons */ case ECOND_NUM_LE: @@ -2052,6 +2090,13 @@ switch(cond_type) for (i = 0; i < 2; i++) { + /* Sometimes, we don't expand substrings; too many insecure configurations + created using match_address{}{} and friends, where the second param + includes information from untrustworthy sources. */ + BOOL honour_dollar = TRUE; + if ((i > 0) && !sub2_honour_dollar) + honour_dollar = FALSE; + while (isspace(*s)) s++; if (*s != '{') { @@ -2060,7 +2105,8 @@ switch(cond_type) "after \"%s\"", name); return NULL; } - sub[i] = expand_string_internal(s+1, TRUE, &s, yield == NULL); + sub[i] = expand_string_internal(s+1, TRUE, &s, yield == NULL, + honour_dollar); if (sub[i] == NULL) return NULL; if (*s++ != '}') goto COND_FAILED_CURLY_END; @@ -2319,6 +2365,7 @@ switch(cond_type) } else /* {crypt} or {crypt16} and non-{ at start */ + /* }-for-text-editors */ { int which = 0; uschar *coded; @@ -2365,6 +2412,30 @@ switch(cond_type) } break; #endif /* SUPPORT_CRYPTEQ */ + + case ECOND_INLIST: + case ECOND_INLISTI: + { + int sep = 0; + BOOL found = FALSE; + uschar *save_iterate_item = iterate_item; + int (*compare)(const uschar *, const uschar *); + + if (cond_type == ECOND_INLISTI) + compare = strcmpic; + else + compare = (int (*)(const uschar *, const uschar *)) strcmp; + + while ((iterate_item = string_nextinlist(&sub[1], &sep, NULL, 0)) != NULL) + if (compare(sub[0], iterate_item) == 0) + { + found = TRUE; + break; + } + iterate_item = save_iterate_item; + *yield = found; + } + } /* Switch for comparison conditions */ return s; /* End of comparison conditions */ @@ -2436,7 +2507,7 @@ switch(cond_type) while (isspace(*s)) s++; if (*s++ != '{') goto COND_FAILED_CURLY_START; - sub[0] = expand_string_internal(s, TRUE, &s, (yield == NULL)); + sub[0] = expand_string_internal(s, TRUE, &s, (yield == NULL), TRUE); if (sub[0] == NULL) return NULL; if (*s++ != '}') goto COND_FAILED_CURLY_END; @@ -2558,7 +2629,7 @@ switch(cond_type) "value \"%s\"", t); return NULL; } - if (yield != NULL) *yield = (boolvalue != 0); + if (yield != NULL) *yield = (boolvalue == testfor); return s; } @@ -2718,7 +2789,7 @@ if (*s++ != '{') goto FAILED_CURLY; want this string. Set skipping in the call in the fail case (this will always be the case if we were already skipping). */ -sub1 = expand_string_internal(s, TRUE, &s, !yes); +sub1 = expand_string_internal(s, TRUE, &s, !yes, TRUE); if (sub1 == NULL && (yes || !expand_string_forcedfail)) goto FAILED; expand_string_forcedfail = FALSE; if (*s++ != '}') goto FAILED_CURLY; @@ -2743,7 +2814,7 @@ already skipping. */ while (isspace(*s)) s++; if (*s == '{') { - sub2 = expand_string_internal(s+1, TRUE, &s, yes || skipping); + sub2 = expand_string_internal(s+1, TRUE, &s, yes || skipping, TRUE); if (sub2 == NULL && (!yes || !expand_string_forcedfail)) goto FAILED; expand_string_forcedfail = FALSE; if (*s++ != '}') goto FAILED_CURLY; @@ -3018,14 +3089,14 @@ Returns: on success: the value of the expression, with *error still NULL 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; -int x = eval_op_or(&s, decimal, error); +int_eximarith_t x = eval_op_or(&s, decimal, error); if (*error == NULL) { if (endket) @@ -3042,21 +3113,26 @@ return x; } -static int +static int_eximarith_t 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; - (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; - 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 == '(') @@ -3074,10 +3150,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; -int x; +int_eximarith_t x; while (isspace(*s)) s++; if (*s == '+' || *s == '-' || *s == '~') { @@ -3095,17 +3172,44 @@ 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; -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++; - 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 + * is a bug somewhere in [gcc 4.2.1, FreeBSD, amd64]. In fact, -N*-M where + * -N*M is INT_MIN will yielf INT_MIN. + * Since we don't support floating point, this is somewhat simpler. + * Ideally, we'd return an error, but since we overflow for all other + * arithmetic, consistency suggests otherwise, but what's the correct value + * to use? There is none. + * The C standard guarantees overflow for unsigned arithmetic but signed + * overflow invokes undefined behaviour; in practice, this is overflow + * except for converting INT_MIN to INT_MAX+1. We also can't guarantee + * that long/longlong larger than int are available, or we could just work + * with larger types. We should consider whether to guarantee 32bit eval + * and 64-bit working variables, with errors returned. For now ... + * So, the only SIGFPEs occur with a non-shrinking div/mod, thus -1; we + * 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 == LLONG_MIN && op != '*') + { + DEBUG(D_expand) + 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 == '*') x *= y; else @@ -3128,16 +3232,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; -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++; - 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; } @@ -3147,15 +3252,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; -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]) { - int y; + int_eximarith_t y; int op = *s++; s++; y = eval_op_sum(&s, decimal, error); @@ -3168,15 +3274,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; -int x = eval_op_shift(&s, decimal, error); +int_eximarith_t x = eval_op_shift(&s, decimal, error); if (*error == NULL) { while (*s == '&') { - int y; + int_eximarith_t y; s++; y = eval_op_shift(&s, decimal, error); if (*error != NULL) break; @@ -3188,15 +3295,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; -int x = eval_op_and(&s, decimal, error); +int_eximarith_t x = eval_op_and(&s, decimal, error); if (*error == NULL) { while (*s == '^') { - int y; + int_eximarith_t y; s++; y = eval_op_and(&s, decimal, error); if (*error != NULL) break; @@ -3208,15 +3316,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; -int x = eval_op_xor(&s, decimal, error); +int_eximarith_t x = eval_op_xor(&s, decimal, error); if (*error == NULL) { while (*s == '|') { - int y; + int_eximarith_t y; s++; y = eval_op_xor(&s, decimal, error); if (*error != NULL) break; @@ -3280,6 +3389,8 @@ Arguments: expansion is placed here (typically used with ket_ends) skipping TRUE for recursive calls when the value isn't actually going to be used (to allow for optimisation) + honour_dollar TRUE if $ is to be expanded, + FALSE if it's just another character Returns: NULL if expansion fails: expand_string_forcedfail is set TRUE if failure was forced @@ -3289,7 +3400,7 @@ Returns: NULL if expansion fails: static uschar * expand_string_internal(uschar *string, BOOL ket_ends, uschar **left, - BOOL skipping) + BOOL skipping, BOOL honour_dollar) { int ptr = 0; int size = Ustrlen(string)+ 64; @@ -3345,7 +3456,7 @@ while (*s != 0) if (ket_ends && *s == '}') break; - if (*s != '$') + if (*s != '$' || !honour_dollar) { yield = string_cat(yield, &size, &ptr, s++, 1); continue; @@ -3561,7 +3672,7 @@ while (*s != 0) while (isspace(*s)) s++; if (*s == '{') { - key = expand_string_internal(s+1, TRUE, &s, skipping); + key = expand_string_internal(s+1, TRUE, &s, skipping, TRUE); if (key == NULL) goto EXPAND_FAILED; if (*s++ != '}') goto EXPAND_FAILED_CURLY; while (isspace(*s)) s++; @@ -3627,7 +3738,7 @@ while (*s != 0) first. */ if (*s != '{') goto EXPAND_FAILED_CURLY; - filename = expand_string_internal(s+1, TRUE, &s, skipping); + filename = expand_string_internal(s+1, TRUE, &s, skipping, TRUE); if (filename == NULL) goto EXPAND_FAILED; if (*s++ != '}') goto EXPAND_FAILED_CURLY; while (isspace(*s)) s++; @@ -4296,7 +4407,7 @@ while (*s != 0) if (*s == '{') { - if (expand_string_internal(s+1, TRUE, &s, TRUE) == NULL) + if (expand_string_internal(s+1, TRUE, &s, TRUE, TRUE) == NULL) goto EXPAND_FAILED; if (*s++ != '}') goto EXPAND_FAILED_CURLY; while (isspace(*s)) s++; @@ -4311,7 +4422,7 @@ while (*s != 0) SOCK_FAIL: if (*s != '{') goto EXPAND_FAILED; DEBUG(D_any) debug_printf("%s\n", expand_string_message); - arg = expand_string_internal(s+1, TRUE, &s, FALSE); + arg = expand_string_internal(s+1, TRUE, &s, FALSE, TRUE); if (arg == NULL) goto EXPAND_FAILED; yield = string_cat(yield, &size, &ptr, arg, Ustrlen(arg)); if (*s++ != '}') goto EXPAND_FAILED_CURLY; @@ -4340,7 +4451,7 @@ while (*s != 0) while (isspace(*s)) s++; if (*s != '{') goto EXPAND_FAILED_CURLY; - arg = expand_string_internal(s+1, TRUE, &s, skipping); + arg = expand_string_internal(s+1, TRUE, &s, skipping, TRUE); if (arg == NULL) goto EXPAND_FAILED; while (isspace(*s)) s++; if (*s++ != '}') goto EXPAND_FAILED_CURLY; @@ -4377,13 +4488,24 @@ while (*s != 0) (void)close(fd_in); + /* Read the pipe to get the command's output into $value (which is kept + in lookup_value). Read during execution, so that if the output exceeds + the OS pipe buffer limit, we don't block forever. */ + + f = fdopen(fd_out, "rb"); + sigalrm_seen = FALSE; + alarm(60); + lookup_value = cat_file(f, lookup_value, &lsize, &lptr, NULL); + alarm(0); + (void)fclose(f); + /* Wait for the process to finish, applying the timeout, and inspect its return code for serious disasters. Simple non-zero returns are passed on. */ - if ((runrc = child_close(pid, 60)) < 0) + if (sigalrm_seen == TRUE || (runrc = child_close(pid, 30)) < 0) { - if (runrc == -256) + if (sigalrm_seen == TRUE || runrc == -256) { expand_string_message = string_sprintf("command timed out"); killpg(pid, SIGKILL); /* Kill the whole process group */ @@ -4399,14 +4521,6 @@ while (*s != 0) goto EXPAND_FAILED; } - - /* Read the pipe to get the command's output into $value (which is kept - in lookup_value). */ - - f = fdopen(fd_out, "rb"); - lookup_value = NULL; - lookup_value = cat_file(f, lookup_value, &lsize, &lptr, NULL); - (void)fclose(f); } /* Process the yes/no strings; $value may be useful in both cases */ @@ -4768,7 +4882,7 @@ while (*s != 0) while (isspace(*s)) s++; if (*s == '{') { - sub[i] = expand_string_internal(s+1, TRUE, &s, skipping); + sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE); if (sub[i] == NULL) goto EXPAND_FAILED; if (*s++ != '}') goto EXPAND_FAILED_CURLY; @@ -4863,7 +4977,7 @@ while (*s != 0) while (isspace(*s)) s++; if (*s++ != '{') goto EXPAND_FAILED_CURLY; - list = expand_string_internal(s, TRUE, &s, skipping); + list = expand_string_internal(s, TRUE, &s, skipping, TRUE); if (list == NULL) goto EXPAND_FAILED; if (*s++ != '}') goto EXPAND_FAILED_CURLY; @@ -4871,7 +4985,7 @@ while (*s != 0) { while (isspace(*s)) s++; if (*s++ != '{') goto EXPAND_FAILED_CURLY; - temp = expand_string_internal(s, TRUE, &s, skipping); + temp = expand_string_internal(s, TRUE, &s, skipping, TRUE); if (temp == NULL) goto EXPAND_FAILED; lookup_value = temp; if (*s++ != '}') goto EXPAND_FAILED_CURLY; @@ -4895,7 +5009,7 @@ while (*s != 0) } else { - temp = expand_string_internal(s, TRUE, &s, TRUE); + temp = expand_string_internal(s, TRUE, &s, TRUE, TRUE); } if (temp == NULL) @@ -4954,7 +5068,7 @@ while (*s != 0) else { - temp = expand_string_internal(expr, TRUE, NULL, skipping); + temp = expand_string_internal(expr, TRUE, NULL, skipping, TRUE); if (temp == NULL) { iterate_item = save_iterate_item; @@ -5136,7 +5250,7 @@ while (*s != 0) { int c; uschar *arg = NULL; - uschar *sub = expand_string_internal(s+1, TRUE, &s, skipping); + uschar *sub = expand_string_internal(s+1, TRUE, &s, skipping, TRUE); if (sub == NULL) goto EXPAND_FAILED; s++; @@ -5211,7 +5325,7 @@ while (*s != 0) case EOP_EXPAND: { - uschar *expanded = expand_string_internal(sub, FALSE, NULL, skipping); + uschar *expanded = expand_string_internal(sub, FALSE, NULL, skipping, TRUE); if (expanded == NULL) { expand_string_message = @@ -5611,7 +5725,7 @@ while (*s != 0) { 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 " @@ -5619,7 +5733,7 @@ while (*s != 0) 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; } @@ -5820,17 +5934,17 @@ while (*s != 0) continue; } - /* pseudo-random number less than N */ + /* vaguely random number less than N */ 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; - 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; } @@ -5979,7 +6093,7 @@ expand_string(uschar *string) search_find_defer = FALSE; malformed_header = FALSE; return (Ustrpbrk(string, "$\\") == NULL)? string : - expand_string_internal(string, FALSE, NULL, FALSE); + expand_string_internal(string, FALSE, NULL, FALSE, TRUE); } @@ -6021,10 +6135,10 @@ Returns: the integer value, or expand_string_message is set NULL for an OK integer */ -int +int_eximarith_t 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; @@ -6056,7 +6170,7 @@ if (isspace(*s)) } } -value = strtol(CS s, CSS &endptr, 10); +value = strtoll(CS s, CSS &endptr, 10); if (endptr == s) { @@ -6068,24 +6182,18 @@ else if (value < 0 && isplus) } 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') - { - 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)";