X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fsrc%2Fexpand.c;h=bcfa60fb660e1246c048bd808a7bc13fa4f33b8e;hb=refs%2Fheads%2Ffix_isis_typos;hp=fe0fd1469400a31d47534e98424682c51f9ca403;hpb=12e1cfcb1649e2ea213c2965adf8479f1cff06f7;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/expand.c b/src/src/expand.c index fe0fd1469..bcfa60fb6 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -475,6 +475,7 @@ typedef struct { typedef uschar * stringptr_fn_t(void); static uschar * fn_recipients(void); +static uschar * fn_recipients_list(void); static uschar * fn_queue_size(void); /* This table must be kept in alphabetical order. */ @@ -694,6 +695,7 @@ static var_entry var_table[] = { { "recipient_verify_failure",vtype_stringptr,&recipient_verify_failure }, { "recipients", vtype_string_func, (void *) &fn_recipients }, { "recipients_count", vtype_int, &recipients_count }, + { "recipients_list", vtype_string_func, (void *) &fn_recipients_list }, { "regex_cachesize", vtype_int, ®ex_cachesize },/* undocumented; devel observability */ #ifdef WITH_CONTENT_SCAN { "regex_match_string", vtype_stringptr, ®ex_match_string }, @@ -839,6 +841,7 @@ uschar * fn_arc_domains(void) {return NULL;} uschar * fn_hdrs_added(void) {return NULL;} uschar * fn_queue_size(void) {return NULL;} uschar * fn_recipients(void) {return NULL;} +uschar * fn_recipients_list(void) {return NULL;} uschar * sender_helo_verified_boolstr(void) {return NULL;} uschar * smtp_cmd_hist(void) {return NULL;} @@ -1800,7 +1803,9 @@ return g; *************************************************/ /* A recipients list is available only during system message filtering, during ACL processing after DATA, and while expanding pipe commands -generated from a system filter, but not elsewhere. */ +generated from a system filter, but not elsewhere. Note that this does +not check for comman in the elements, and uses comma-space as seperator - +so cannot be used as an exim list as-is. */ static uschar * fn_recipients(void) @@ -1815,6 +1820,23 @@ for (int i = 0; i < recipients_count; i++) s = recipients_list[i].address; g = string_append2_listele_n(g, US", ", s, Ustrlen(s)); } +gstring_release_unused(g); +return string_from_gstring(g); +} + +/* Similar, but as a properly-quoted exim list */ + + +static uschar * +fn_recipients_list(void) +{ +gstring * g = NULL; + +if (!f.enable_dollar_recipients) return NULL; + +for (int i = 0; i < recipients_count; i++) + g = string_append_listele(g, ':', recipients_list[i].address); +gstring_release_unused(g); return string_from_gstring(g); } @@ -2037,7 +2059,8 @@ switch (vp->type) if (!*ss && deliver_datafile >= 0) /* Read body when needed */ { uschar * body; - off_t start_offset = SPOOL_DATA_START_OFFSET; + off_t start_offset_o = spool_data_start_offset(message_id); + off_t start_offset = start_offset_o; int len = message_body_visible; if (len > message_size) len = message_size; @@ -2049,8 +2072,8 @@ switch (vp->type) if (fstat(deliver_datafile, &statbuf) == 0) { start_offset = statbuf.st_size - len; - if (start_offset < SPOOL_DATA_START_OFFSET) - start_offset = SPOOL_DATA_START_OFFSET; + if (start_offset < start_offset_o) + start_offset = start_offset_o; } } if (lseek(deliver_datafile, start_offset, SEEK_SET) < 0) @@ -2118,7 +2141,7 @@ switch (vp->type) case vtype_string_func: { stringptr_fn_t * fn = (stringptr_fn_t *) val; - uschar* s = fn(); + uschar * s = fn(); return s ? s : US""; } @@ -2383,19 +2406,26 @@ static uschar * json_nextinlist(const uschar ** list) { unsigned array_depth = 0, object_depth = 0; +BOOL quoted = FALSE; const uschar * s = *list, * item; skip_whitespace(&s); for (item = s; - *s && (*s != ',' || array_depth != 0 || object_depth != 0); + *s && (*s != ',' || array_depth != 0 || object_depth != 0 || quoted); s++) - switch (*s) + if (!quoted) switch (*s) { case '[': array_depth++; break; case ']': array_depth--; break; case '{': object_depth++; break; case '}': object_depth--; break; + case '"': quoted = TRUE; + } + else switch(*s) + { + case '\\': s++; break; /* backslash protects one char */ + case '"': quoted = FALSE; break; } *list = *s ? s+1 : s; if (item == s) return NULL; @@ -3523,7 +3553,7 @@ switch(cond_type = identify_operator(&s, &opname)) /* Match the given local_part against the SRS-encoded pattern */ - re = regex_must_compile(US"^(?i)SRS0=([^=]+)=([A-Z2-7]+)=([^=]*)=(.*)$", + re = regex_must_compile(US"^(?i)SRS0=([^=]+)=([A-Z2-7]{2})=([^=]*)=(.*)$", MCS_CASELESS | MCS_CACHEABLE, FALSE); md = pcre2_match_data_create(4+1, pcre_gen_ctx); if (pcre2_match(re, sub[0], PCRE2_ZERO_TERMINATED, 0, PCRE_EOPT, @@ -3553,53 +3583,50 @@ switch(cond_type = identify_operator(&s, &opname)) /* If a zero-length secret was given, we're done. Otherwise carry on and validate the given SRS local_part againt our secret. */ - if (!*sub[1]) + if (*sub[1]) { - boolvalue = TRUE; - goto srs_result; - } + /* check the timestamp */ + { + struct timeval now; + uschar * ss = sub[0] + ovec[4]; /* substring 2, the timestamp */ + long d; + int n; - /* check the timestamp */ - { - 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 */ - gettimeofday(&now, NULL); - now.tv_sec /= 86400; /* days since epoch */ + /* Decode substring 2 from base32 to a number */ - /* Decode substring 2 from base32 to a number */ + for (d = 0, n = ovec[5]-ovec[4]; n; n--) + { + uschar * t = Ustrchr(base32_chars, *ss++); + d = d * 32 + (t - base32_chars); + } - for (d = 0, n = ovec[5]-ovec[4]; n; n--) - { - uschar * t = Ustrchr(base32_chars, *ss++); - d = d * 32 + (t - base32_chars); + if (((now.tv_sec - d) & 0x3ff) > 10) /* days since SRS generated */ + { + DEBUG(D_expand) debug_printf("SRS too old\n"); + goto srs_result; + } } - if (((now.tv_sec - d) & 0x3ff) > 10) /* days since SRS generated */ + /* check length of substring 1, the offered checksum */ + + if (ovec[3]-ovec[2] != 4) { - DEBUG(D_expand) debug_printf("SRS too old\n"); + DEBUG(D_expand) debug_printf("SRS checksum wrong size\n"); goto srs_result; } - } - - /* check length of substring 1, the offered checksum */ - - if (ovec[3]-ovec[2] != 4) - { - DEBUG(D_expand) debug_printf("SRS checksum wrong size\n"); - goto srs_result; - } - /* Hash the address with our secret, and compare that computed checksum - with the one extracted from the arg */ + /* Hash the address with our secret, and compare that computed checksum + with the one extracted from the arg */ - hmac_md5(sub[1], srs_recipient, cksum, sizeof(cksum)); - if (Ustrncmp(cksum, sub[0] + ovec[2], 4) != 0) - { - DEBUG(D_expand) debug_printf("SRS checksum mismatch\n"); - goto srs_result; + hmac_md5(sub[1], srs_recipient, cksum, sizeof(cksum)); + if (Ustrncmp(cksum, sub[0] + ovec[2], 4) != 0) + { + DEBUG(D_expand) debug_printf("SRS checksum mismatch\n"); + goto srs_result; + } } boolvalue = TRUE; @@ -3956,10 +3983,9 @@ if (Ustrlen(key) > 64) hash_source = string_catn(NULL, key_num, 1); hash_source = string_catn(hash_source, daystamp, 3); hash_source = string_cat(hash_source, address); -(void) string_from_gstring(hash_source); DEBUG(D_expand) - debug_printf_indent("prvs: hash source is '%s'\n", hash_source->s); + debug_printf_indent("prvs: hash source is '%Y'\n", hash_source); memset(innerkey, 0x36, 64); memset(outerkey, 0x5c, 64); @@ -5382,18 +5408,18 @@ while (*s) if (iexpire >= inow) { prvscheck_result = US"1"; - DEBUG(D_expand) debug_printf_indent("prvscheck: success, $pvrs_result set to 1\n"); + DEBUG(D_expand) debug_printf_indent("prvscheck: success, $prvscheck_result set to 1\n"); } else { prvscheck_result = NULL; - DEBUG(D_expand) debug_printf_indent("prvscheck: signature expired, $pvrs_result unset\n"); + DEBUG(D_expand) debug_printf_indent("prvscheck: signature expired, $prvscheck_result unset\n"); } } else { prvscheck_result = NULL; - DEBUG(D_expand) debug_printf_indent("prvscheck: hash failure, $pvrs_result unset\n"); + DEBUG(D_expand) debug_printf_indent("prvscheck: hash failure, $prvscheck_result unset\n"); } /* Now expand the final argument. We leave this till now so that @@ -5616,7 +5642,7 @@ while (*s) { FILE * f; const uschar * arg, ** argv; - BOOL late_expand = TRUE; + unsigned late_expand = TSUC_EXPAND_ARGS | TSUC_ALLOW_TAINTED_ARGS | TSUC_ALLOW_RECIPIENTS; if (expand_forbid & RDO_RUN) { @@ -5628,7 +5654,7 @@ while (*s) while (*s == ',') if (Ustrncmp(++s, "preexpand", 9) == 0) - { late_expand = FALSE; s += 9; } + { late_expand = 0; s += 9; } else { const uschar * t = s; @@ -5688,7 +5714,6 @@ while (*s) late_expand, /* expand args if not already done */ 0, /* not relevant when... */ NULL, /* no transporting address */ - late_expand, /* allow tainted args, when expand-after-split */ US"${run} expansion", /* for error messages */ &expand_string_message)) /* where to put error message */ goto EXPAND_FAILED; @@ -5779,16 +5804,15 @@ while (*s) case 3: goto EXPAND_FAILED; } - yield = string_cat(yield, sub[0]); - o2m = Ustrlen(sub[2]) - 1; - - if (o2m >= 0) for (; oldptr < yield->ptr; oldptr++) + if ( (yield = string_cat(yield, sub[0])) + && (o2m = Ustrlen(sub[2]) - 1) >= 0) + for (; oldptr < yield->ptr; oldptr++) { uschar * m = Ustrrchr(sub[1], yield->s[oldptr]); if (m) { int o = m - sub[1]; - yield->s[oldptr] = sub[2][(o < o2m)? o : o2m]; + yield->s[oldptr] = sub[2][o < o2m ? o : o2m]; } } @@ -7047,6 +7071,7 @@ while (*s) case 2: case 3: goto EXPAND_FAILED; } + if (flags & ESI_SKIPPING) continue; if (sub[1] && *(sub[1])) { @@ -7061,13 +7086,11 @@ while (*s) { struct timeval now; unsigned long i; - gstring * h = NULL; gettimeofday(&now, NULL); - for (unsigned long i = (now.tv_sec / 86400) & 0x3ff; i; i >>= 5) - h = string_catn(h, &base32_chars[i & 0x1f], 1); - if (h) while (h->ptr > 0) - g = string_catn(g, &h->s[--h->ptr], 1); + i = (now.tv_sec / 86400) & 0x3ff; + g = string_catn(g, &base32_chars[i >> 5], 1); + g = string_catn(g, &base32_chars[i & 0x1f], 1); } g = string_catn(g, US"=", 1); @@ -7265,7 +7288,7 @@ NOT_ITEM: ; "operator is \"%s\", which is not a decimal number", sub); goto EXPAND_FAILED; } - yield = string_cat(yield, string_base62(n)); + yield = string_cat(yield, string_base62_32(n)); /*XXX only handles 32b input range. Need variants? */ break; } @@ -7856,7 +7879,7 @@ NOT_ITEM: ; case EOP_UTF8CLEAN: { int seq_len = 0, index = 0, bytes_left = 0, complete; - long codepoint = -1; + u_long codepoint = (u_long)-1; uschar seq_buff[4]; /* accumulate utf-8 here */ /* Manually track tainting, as we deal in individual chars below */ @@ -7890,6 +7913,15 @@ NOT_ITEM: ; if (--bytes_left == 0) /* codepoint complete */ if(codepoint > 0x10FFFF) /* is it too large? */ complete = -1; /* error (RFC3629 limit) */ + else if ( (codepoint & 0x1FF800 ) == 0xD800 ) /* surrogate */ + /* A UTF-16 surrogate (which should be one of a pair that + encode a Unicode codepoint that is outside the Basic + Multilingual Plane). Error, not UTF8. + RFC2279.2 is slightly unclear on this, but + https://unicodebook.readthedocs.io/issues.html#strict-utf8-decoder + says "Surrogates characters are also invalid in UTF-8: + characters in U+D800—U+DFFF have to be rejected." */ + complete = -1; else { /* finished; output utf-8 sequence */ yield = string_catn(yield, seq_buff, seq_len); @@ -7899,27 +7931,25 @@ NOT_ITEM: ; } else /* no bytes left: new sequence */ { - if(!(c & 0x80)) /* 1-byte sequence, US-ASCII, keep it */ + if (!(c & 0x80)) /* 1-byte sequence, US-ASCII, keep it */ { yield = string_catn(yield, &c, 1); continue; } - if((c & 0xe0) == 0xc0) /* 2-byte sequence */ - { - if(c == 0xc0 || c == 0xc1) /* 0xc0 and 0xc1 are illegal */ + if ((c & 0xe0) == 0xc0) /* 2-byte sequence */ + if (c == 0xc0 || c == 0xc1) /* 0xc0 and 0xc1 are illegal */ complete = -1; else { - bytes_left = 1; - codepoint = c & 0x1f; + bytes_left = 1; + codepoint = c & 0x1f; } - } - else if((c & 0xf0) == 0xe0) /* 3-byte sequence */ + else if ((c & 0xf0) == 0xe0) /* 3-byte sequence */ { bytes_left = 2; codepoint = c & 0x0f; } - else if((c & 0xf8) == 0xf0) /* 4-byte sequence */ + else if ((c & 0xf8) == 0xf0) /* 4-byte sequence */ { bytes_left = 3; codepoint = c & 0x07; @@ -7993,7 +8023,7 @@ NOT_ITEM: ; goto EXPAND_FAILED; } yield = string_cat(yield, s); - DEBUG(D_expand) debug_printf_indent("yield: '%s'\n", string_from_gstring(yield)); + DEBUG(D_expand) debug_printf_indent("yield: '%Y'\n", yield); break; } @@ -8101,7 +8131,7 @@ NOT_ITEM: ; case EOP_BASE64D: { uschar * s; - int len = b64decode(sub, &s); + int len = b64decode(sub, &s, sub); if (len < 0) { expand_string_message = string_sprintf("string \"%s\" is not "