X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/b3ce3e5440ea0ce5e3580aa9a0fa18c88214a286..4a852e8c97fa4de42c443107121c7717e1f0c9b2:/src/src/expand.c diff --git a/src/src/expand.c b/src/src/expand.c index bce335629..2bd78aac6 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -2543,16 +2543,13 @@ BOOL tempcond, combined_cond; BOOL *subcondptr; BOOL sub2_honour_dollar = TRUE; BOOL is_forany, is_json, is_jsons; -int rc, cond_type, roffset; +int rc, cond_type; int_eximarith_t num[2]; struct stat statbuf; uschar * opname; uschar name[256]; const uschar *sub[10]; -const pcre *re; -const uschar *rerror; - for (;;) if (Uskip_whitespace(&s) == '!') { testfor = !testfor; s++; } else break; @@ -2974,15 +2971,24 @@ switch(cond_type = identify_operator(&s, &opname)) break; case ECOND_MATCH: /* Regular expression match */ - if (!(re = pcre_compile(CS sub[1], PCRE_COPT, CCSS &rerror, - &roffset, NULL))) { - expand_string_message = string_sprintf("regular expression error in " - "\"%s\": %s at offset %d", sub[1], rerror, roffset); - return NULL; + const pcre2_code * re; + PCRE2_SIZE offset; + int err; + + if (!(re = pcre2_compile((PCRE2_SPTR)sub[1], PCRE2_ZERO_TERMINATED, + PCRE_COPT, &err, &offset, pcre_cmp_ctx))) + { + uschar errbuf[128]; + pcre2_get_error_message(err, errbuf, sizeof(errbuf)); + expand_string_message = string_sprintf("regular expression error in " + "\"%s\": %s at offset %d", sub[1], errbuf, offset); + return NULL; + } + + tempcond = regex_match_and_setup(re, sub[0], 0, -1); + break; } - tempcond = regex_match_and_setup(re, sub[0], 0, -1); - break; case ECOND_MATCH_ADDRESS: /* Match in an address list */ rc = match_address_list(sub[0], TRUE, FALSE, &(sub[1]), NULL, -1, 0, NULL); @@ -3448,9 +3454,10 @@ switch(cond_type = identify_operator(&s, &opname)) /* ${if inbound_srs {local_part}{secret} {yes}{no}} */ { uschar * sub[2]; - const pcre * re; - int ovec[3*(4+1)]; - int n, quoting = 0; + const pcre2_code * re; + pcre2_match_data * md; + PCRE2_SIZE * ovec; + int quoting = 0; uschar cksum[4]; BOOL boolvalue = FALSE; @@ -3466,12 +3473,14 @@ switch(cond_type = identify_operator(&s, &opname)) re = regex_must_compile(US"^(?i)SRS0=([^=]+)=([A-Z2-7]+)=([^=]*)=(.*)$", TRUE, FALSE); - if (pcre_exec(re, NULL, CS sub[0], Ustrlen(sub[0]), 0, PCRE_EOPT, - ovec, nelem(ovec)) < 0) + md = pcre2_match_data_create(4+1, pcre_gen_ctx); + if (pcre2_match(re, sub[0], PCRE2_ZERO_TERMINATED, 0, PCRE_EOPT, + md, pcre_mtc_ctx) < 0) { DEBUG(D_expand) debug_printf("no match for SRS'd local-part pattern\n"); goto srs_result; } + ovec = pcre2_get_ovector_pointer(md); if (sub[0][0] == '"') quoting = 1; @@ -3503,6 +3512,7 @@ switch(cond_type = identify_operator(&s, &opname)) struct timeval now; uschar * ss = sub[0] + ovec[4]; /* substring 2, the timestamp */ long d; + int n; gettimeofday(&now, NULL); now.tv_sec /= 86400; /* days since epoch */ @@ -4483,13 +4493,13 @@ DEBUG(D_expand) f.expand_string_forcedfail = FALSE; expand_string_message = US""; -if (is_tainted(string)) +{ uschar *m; +if ((m = is_tainted2(string, LOG_MAIN|LOG_PANIC, "Tainted string '%s' in expansion", s))) { - expand_string_message = - string_sprintf("attempt to expand tainted string '%s'", s); - log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message); + expand_string_message = m; goto EXPAND_FAILED; } +} while (*s) { @@ -5189,7 +5199,7 @@ while (*s) { uschar *sub_arg[3]; gstring * g; - const pcre *re; + const pcre2_code *re; uschar *p; /* TF: Ugliness: We want to expand parameter 1 first, then set @@ -5829,11 +5839,11 @@ while (*s) case EITEM_SG: { - const pcre *re; + const pcre2_code * re; int moffset, moffsetextra, slen; - int roffset; - int emptyopt; - const uschar *rerror; + PCRE2_SIZE roffset; + pcre2_match_data * md; + int err, emptyopt; uschar *subject; uschar *sub[3]; int save_expand_nmax = @@ -5848,13 +5858,16 @@ while (*s) /* Compile the regular expression */ - if (!(re = pcre_compile(CS sub[1], PCRE_COPT, CCSS &rerror, - &roffset, NULL))) + if (!(re = pcre2_compile((PCRE2_SPTR)sub[1], PCRE2_ZERO_TERMINATED, + PCRE_COPT, &err, &roffset, pcre_cmp_ctx))) { + uschar errbuf[128]; + pcre2_get_error_message(err, errbuf, sizeof(errbuf)); expand_string_message = string_sprintf("regular expression error in " - "\"%s\": %s at offset %d", sub[1], rerror, roffset); + "\"%s\": %s at offset %ld", sub[1], errbuf, (long)roffset); goto EXPAND_FAILED; } + md = pcre2_match_data_create(EXPAND_MAXN + 1, pcre_gen_ctx); /* Now run a loop to do the substitutions as often as necessary. It ends when there are no more matches. Take care over matches of the null string; @@ -5867,9 +5880,9 @@ while (*s) for (;;) { - int ovector[3*(EXPAND_MAXN+1)]; - int n = pcre_exec(re, NULL, CS subject, slen, moffset + moffsetextra, - PCRE_EOPT | emptyopt, ovector, nelem(ovector)); + PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md); + int n = pcre2_match(re, (PCRE2_SPTR)subject, slen, moffset + moffsetextra, + PCRE_EOPT | emptyopt, md, pcre_mtc_ctx); uschar *insert; /* No match - if we previously set PCRE_NOTEMPTY after a null match, this @@ -5897,19 +5910,19 @@ while (*s) expand_nmax = 0; for (int nn = 0; nn < n*2; nn += 2) { - expand_nstring[expand_nmax] = subject + ovector[nn]; - expand_nlength[expand_nmax++] = ovector[nn+1] - ovector[nn]; + expand_nstring[expand_nmax] = subject + ovec[nn]; + expand_nlength[expand_nmax++] = ovec[nn+1] - ovec[nn]; } expand_nmax--; /* Copy the characters before the match, plus the expanded insertion. */ - yield = string_catn(yield, subject + moffset, ovector[0] - moffset); + yield = string_catn(yield, subject + moffset, ovec[0] - moffset); if (!(insert = expand_string(sub[2]))) goto EXPAND_FAILED; yield = string_cat(yield, insert); - moffset = ovector[1]; + moffset = ovec[1]; moffsetextra = 0; emptyopt = 0; @@ -5920,10 +5933,10 @@ while (*s) string at the same point. If this fails (picked up above) we advance to the next character. */ - if (ovector[0] == ovector[1]) + if (ovec[0] == ovec[1]) { - if (ovector[0] == slen) break; - emptyopt = PCRE_NOTEMPTY | PCRE_ANCHORED; + if (ovec[0] == slen) break; + emptyopt = PCRE2_NOTEMPTY | PCRE2_ANCHORED; } } @@ -6431,13 +6444,10 @@ while (*s) condition for real. For EITEM_MAP and EITEM_REDUCE, do the same, using the normal internal expansion function. */ - if (item_type == EITEM_FILTER) - { - if ((temp = eval_condition(expr, &resetok, NULL))) - s = temp; - } - else + if (item_type != EITEM_FILTER) temp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok); + else + if ((temp = eval_condition(expr, &resetok, NULL))) s = temp; if (!temp) { @@ -6446,7 +6456,7 @@ while (*s) goto EXPAND_FAILED; } - Uskip_whitespace(&s); + Uskip_whitespace(&s); /*{*/ if (*s++ != '}') { /*{*/ expand_string_message = string_sprintf("missing } at end of condition " @@ -7336,11 +7346,11 @@ while (*s) int count; uschar *endptr; int binary[4]; - int mask, maskoffset; - int type = string_is_ip_address(sub, &maskoffset); + int type, mask, maskoffset; + BOOL normalised; uschar buffer[64]; - if (type == 0) + if ((type = string_is_ip_address(sub, &maskoffset)) == 0) { expand_string_message = string_sprintf("\"%s\" is not an IP address", sub); @@ -7356,13 +7366,18 @@ while (*s) mask = Ustrtol(sub + maskoffset + 1, &endptr, 10); - if (*endptr != 0 || mask < 0 || mask > ((type == 4)? 32 : 128)) + if (*endptr || mask < 0 || mask > (type == 4 ? 32 : 128)) { expand_string_message = string_sprintf("mask value too big in \"%s\"", sub); goto EXPAND_FAILED; } + /* If an optional 'n' was given, ipv6 gets normalised output: + colons rather than dots, and zero-compressed. */ + + normalised = arg && *arg == 'n'; + /* Convert the address to binary integer(s) and apply the mask */ sub[maskoffset] = 0; @@ -7371,8 +7386,14 @@ while (*s) /* Convert to masked textual format and add to output. */ - yield = string_catn(yield, buffer, - host_nmtoa(count, binary, mask, buffer, '.')); + if (type == 4 || !normalised) + yield = string_catn(yield, buffer, + host_nmtoa(count, binary, mask, buffer, '.')); + else + { + ipv6_nmtoa(binary, buffer); + yield = string_fmt_append(yield, "%s/%d", buffer, mask); + } continue; } @@ -7648,10 +7669,12 @@ while (*s) /* Manually track tainting, as we deal in individual chars below */ if (is_tainted(sub)) + { if (yield->s && yield->ptr) gstring_rebuffer(yield); else yield->s = store_get(yield->size = Ustrlen(sub), TRUE); + } /* Check the UTF-8, byte-by-byte */ @@ -8212,6 +8235,7 @@ that is a bad idea, because expand_string_message is in dynamic store. */ EXPAND_FAILED: if (left) *left = s; DEBUG(D_expand) + { DEBUG(D_noutf8) { debug_printf_indent("|failed to expand: %s\n", string); @@ -8231,6 +8255,7 @@ DEBUG(D_expand) if (f.expand_string_forcedfail) debug_printf_indent(UTF8_UP_RIGHT "failure was forced\n"); } + } if (resetok_p && !resetok) *resetok_p = FALSE; expand_level--; return NULL; @@ -8596,11 +8621,11 @@ if (e.var_name) BOOL -regex_match_and_setup(const pcre *re, uschar *subject, int options, int setup) +regex_match_and_setup(const pcre2_code *re, uschar *subject, int options, int setup) { -int ovector[3*(EXPAND_MAXN+1)]; +int ovec[3*(EXPAND_MAXN+1)]; int n = pcre_exec(re, NULL, subject, Ustrlen(subject), 0, PCRE_EOPT|options, - ovector, nelem(ovector)); + ovec, nelem(ovec)); BOOL yield = n >= 0; if (n == 0) n = EXPAND_MAXN + 1; if (yield) @@ -8608,8 +8633,8 @@ if (yield) expand_nmax = setup < 0 ? 0 : setup + 1; for (int nn = setup < 0 ? 0 : 2; nn < n*2; nn += 2) { - expand_nstring[expand_nmax] = subject + ovector[nn]; - expand_nlength[expand_nmax++] = ovector[nn+1] - ovector[nn]; + expand_nstring[expand_nmax] = subject + ovec[nn]; + expand_nlength[expand_nmax++] = ovec[nn+1] - ovec[nn]; } expand_nmax--; }