X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Fexpand.c;h=5189cdcfed5af230a5f80d60467f1271c1ec807c;hp=99d2ffc00052bf20f908f1ee271f78fd869ec52f;hb=e47376befc6e4a415319e3c29fad9b0ba2bbd8ee;hpb=3615fa9a06356891367c66ed284cef9db5cefca3 diff --git a/src/src/expand.c b/src/src/expand.c index 99d2ffc00..5189cdcfe 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2015 */ +/* Copyright (c) University of Cambridge 1995 - 2016 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -480,10 +480,6 @@ static var_entry var_table[] = { { "dcc_header", vtype_stringptr, &dcc_header }, { "dcc_result", vtype_stringptr, &dcc_result }, #endif -#ifdef WITH_OLD_DEMIME - { "demime_errorlevel", vtype_int, &demime_errorlevel }, - { "demime_reason", vtype_stringptr, &demime_reason }, -#endif #ifndef DISABLE_DKIM { "dkim_algo", vtype_dkim, (void *)DKIM_ALGO }, { "dkim_bodylength", vtype_dkim, (void *)DKIM_BODYLENGTH }, @@ -532,9 +528,6 @@ static var_entry var_table[] = { { "exim_path", vtype_stringptr, &exim_path }, { "exim_uid", vtype_uid, &exim_uid }, { "exim_version", vtype_stringptr, &version_string }, -#ifdef WITH_OLD_DEMIME - { "found_extension", vtype_stringptr, &found_extension }, -#endif { "headers_added", vtype_string_func, &fn_hdrs_added }, { "home", vtype_stringptr, &deliver_home }, { "host", vtype_stringptr, &deliver_host }, @@ -1676,9 +1669,8 @@ if (!enable_dollar_recipients) return NULL; else uschar * s = store_get(size); for (i = 0; i < recipients_count; i++) { - if (i != 0) s = string_cat(s, &size, &ptr, US", ", 2); - s = string_cat(s, &size, &ptr, recipients_list[i].address, - Ustrlen(recipients_list[i].address)); + if (i != 0) s = string_catn(s, &size, &ptr, US", ", 2); + s = string_cat(s, &size, &ptr, recipients_list[i].address); } s[ptr] = 0; /* string_cat() leaves room */ return s; @@ -1999,12 +1991,17 @@ for (i = 0; i < n; i++) { if (*s != '{') { - if (i < m) return 1; + if (i < m) + { + expand_string_message = string_sprintf("Not enough arguments for '%s' " + "(min is %d)", name, m); + return 1; + } sub[i] = NULL; break; } - sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, resetok); - if (sub[i] == NULL) return 3; + if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, resetok))) + return 3; if (*s++ != '}') return 1; while (isspace(*s)) s++; } @@ -2012,10 +2009,11 @@ if (check_end && *s++ != '}') { if (s[-1] == '{') { - expand_string_message = string_sprintf("Too many arguments for \"%s\" " + expand_string_message = string_sprintf("Too many arguments for '%s' " "(max is %d)", name, n); return 2; } + expand_string_message = string_sprintf("missing '}' after '%s'", name); return 1; } @@ -2058,7 +2056,7 @@ Load args from sub array to globals, and call acl_check(). Sub array will be corrupted on return. Returns: OK access is granted by an ACCEPT verb - DISCARD access is granted by a DISCARD verb + DISCARD access is (apparently) granted by a DISCARD verb FAIL access is denied FAIL_DROP access is denied; drop the connection DEFER can't tell at the moment @@ -2373,7 +2371,7 @@ switch(cond_type) case 3: return NULL; } - *resetok = FALSE; + *resetok = FALSE; /* eval_acl() might allocate; do not reclaim */ if (yield != NULL) switch(eval_acl(sub, nelem(sub), &user_msg)) { case OK: @@ -2382,7 +2380,7 @@ switch(cond_type) lookup_value = NULL; if (user_msg) { - lookup_value = string_cat(NULL, &size, &ptr, user_msg, Ustrlen(user_msg)); + lookup_value = string_cat(NULL, &size, &ptr, user_msg); lookup_value[ptr] = '\0'; } *yield = cond == testfor; @@ -2390,6 +2388,7 @@ switch(cond_type) case DEFER: expand_string_forcedfail = TRUE; + /*FALLTHROUGH*/ default: expand_string_message = string_sprintf("error from acl \"%s\"", sub[0]); return NULL; @@ -3172,6 +3171,7 @@ process_yesno(BOOL skipping, BOOL yes, uschar *save_lookup, const uschar **sptr, int rc = 0; const uschar *s = *sptr; /* Local value */ uschar *sub1, *sub2; +const uschar * errwhere; /* If there are no following strings, we substitute the contents of $value for lookups and for extractions in the success case. For the ${if item, the string @@ -3183,13 +3183,12 @@ if (*s == '}') { if (type[0] == 'i') { - if (yes) *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, US"true", 4); + if (yes) *yieldptr = string_catn(*yieldptr, sizeptr, ptrptr, US"true", 4); } else { if (yes && lookup_value) - *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, lookup_value, - Ustrlen(lookup_value)); + *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, lookup_value); lookup_value = save_lookup; } s++; @@ -3198,7 +3197,11 @@ if (*s == '}') /* The first following string must be braced. */ -if (*s++ != '{') goto FAILED_CURLY; +if (*s++ != '{') + { + errwhere = US"'yes' part did not start with '{'"; + goto FAILED_CURLY; + } /* Expand the first substring. Forced failures are noticed only if we actually want this string. Set skipping in the call in the fail case (this will always @@ -3207,12 +3210,16 @@ be the case if we were already skipping). */ sub1 = expand_string_internal(s, TRUE, &s, !yes, TRUE, resetok); if (sub1 == NULL && (yes || !expand_string_forcedfail)) goto FAILED; expand_string_forcedfail = FALSE; -if (*s++ != '}') goto FAILED_CURLY; +if (*s++ != '}') + { + errwhere = US"'yes' part did not end with '}'"; + goto FAILED_CURLY; + } /* If we want the first string, add it to the output */ if (yes) - *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, sub1, Ustrlen(sub1)); + *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, sub1); /* If this is called from a lookup/env or a (cert)extract, we want to restore $value to what it was at the start of the item, so that it has this value @@ -3233,12 +3240,16 @@ if (*s == '{') sub2 = expand_string_internal(s+1, TRUE, &s, yes || skipping, TRUE, resetok); if (sub2 == NULL && (!yes || !expand_string_forcedfail)) goto FAILED; expand_string_forcedfail = FALSE; - if (*s++ != '}') goto FAILED_CURLY; + if (*s++ != '}') + { + errwhere = US"'no' part did not start with '{'"; + goto FAILED_CURLY; + } /* If we want the second string, add it to the output */ if (!yes) - *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, sub2, Ustrlen(sub2)); + *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, sub2); } /* If there is no second string, but the word "fail" is present when the use of @@ -3256,7 +3267,11 @@ else if (*s != '}') if (!yes && !skipping) { while (isspace(*s)) s++; - if (*s++ != '}') goto FAILED_CURLY; + if (*s++ != '}') + { + errwhere = US"did not close with '}' after forcedfail"; + goto FAILED_CURLY; + } expand_string_message = string_sprintf("\"%s\" failed and \"fail\" requested", type); expand_string_forcedfail = TRUE; @@ -3274,23 +3289,30 @@ else if (*s != '}') /* All we have to do now is to check on the final closing brace. */ while (isspace(*s)) s++; -if (*s++ == '}') goto RETURN; - -/* Get here if there is a bracketing failure */ - -FAILED_CURLY: -rc++; - -/* Get here for other failures */ - -FAILED: -rc++; +if (*s++ != '}') + { + errwhere = US"did not close with '}'"; + goto FAILED_CURLY; + } -/* Update the input pointer value before returning */ RETURN: +/* Update the input pointer value before returning */ *sptr = s; return rc; + +FAILED_CURLY: + /* Get here if there is a bracketing failure */ + expand_string_message = string_sprintf( + "curly-bracket problem in conditional yes/no parsing: %s\n" + " remaining string is '%s'", errwhere, --s); + rc = 2; + goto RETURN; + +FAILED: + /* Get here for other failures */ + rc = 1; + goto RETURN; } @@ -3407,9 +3429,9 @@ if (key_num == NULL) if (Ustrlen(key) > 64) return NULL; -hash_source = string_cat(NULL,&size,&offset,key_num,1); -hash_source = string_cat(hash_source,&size,&offset,daystamp,3); -hash_source = string_cat(hash_source,&size,&offset,address,Ustrlen(address)); +hash_source = string_catn(NULL, &size, &offset, key_num, 1); +hash_source = string_catn(hash_source, &size, &offset, daystamp, 3); +hash_source = string_cat(hash_source, &size, &offset, address); hash_source[offset] = '\0'; DEBUG(D_expand) debug_printf("prvs: hash source is '%s'\n", hash_source); @@ -3473,9 +3495,9 @@ while (Ufgets(buffer, sizeof(buffer), f)) { int len = Ustrlen(buffer); if (eol && buffer[len-1] == '\n') len--; - yield = string_cat(yield, sizep, ptrp, buffer, len); + yield = string_catn(yield, sizep, ptrp, buffer, len); if (buffer[len] != 0) - yield = string_cat(yield, sizep, ptrp, eol, eollen); + yield = string_catn(yield, sizep, ptrp, eol, eollen); } if (yield) yield[*ptrp] = 0; @@ -3652,13 +3674,20 @@ eval_op_sum(uschar **sptr, BOOL decimal, uschar **error) { uschar *s = *sptr; int_eximarith_t x = eval_op_mult(&s, decimal, error); -if (*error == NULL) +if (!*error) { while (*s == '+' || *s == '-') { int op = *s++; int_eximarith_t y = eval_op_mult(&s, decimal, error); - if (*error != NULL) break; + if (*error) break; + if ( (x >= EXIM_ARITH_MAX/2 && x >= EXIM_ARITH_MAX/2) + || (x <= -(EXIM_ARITH_MAX/2) && y <= -(EXIM_ARITH_MAX/2))) + { /* over-conservative check */ + *error = op == '+' + ? US"overflow in sum" : US"overflow in difference"; + break; + } if (op == '+') x += y; else x -= y; } } @@ -3829,6 +3858,9 @@ uschar *save_expand_nstring[EXPAND_MAXN+1]; int save_expand_nlength[EXPAND_MAXN+1]; BOOL resetok = TRUE; +DEBUG(D_expand) + debug_printf("%s: %s\n", skipping ? " scanning" : "considering", string); + expand_string_forcedfail = FALSE; expand_string_message = US""; @@ -3854,7 +3886,7 @@ while (*s != 0) { const uschar * t = s + 2; for (s = t; *s != 0; s++) if (*s == '\\' && s[1] == 'N') break; - yield = string_cat(yield, &size, &ptr, t, s - t); + yield = string_catn(yield, &size, &ptr, t, s - t); if (*s != 0) s += 2; } @@ -3863,7 +3895,7 @@ while (*s != 0) uschar ch[1]; ch[0] = string_interpret_escape(&s); s++; - yield = string_cat(yield, &size, &ptr, ch, 1); + yield = string_catn(yield, &size, &ptr, ch, 1); } continue; @@ -3878,7 +3910,7 @@ while (*s != 0) if (*s != '$' || !honour_dollar) { - yield = string_cat(yield, &size, &ptr, s++, 1); + yield = string_catn(yield, &size, &ptr, s++, 1); continue; } @@ -3956,7 +3988,7 @@ while (*s != 0) size = newsize; ptr = len; } - else yield = string_cat(yield, &size, &ptr, value, len); + else yield = string_catn(yield, &size, &ptr, value, len); continue; } @@ -3966,7 +3998,7 @@ while (*s != 0) int n; s = read_cnumber(&n, s); if (n >= 0 && n <= expand_nmax) - yield = string_cat(yield, &size, &ptr, expand_nstring[n], + yield = string_catn(yield, &size, &ptr, expand_nstring[n], expand_nlength[n]); continue; } @@ -3992,7 +4024,7 @@ while (*s != 0) goto EXPAND_FAILED; } if (n >= 0 && n <= expand_nmax) - yield = string_cat(yield, &size, &ptr, expand_nstring[n], + yield = string_catn(yield, &size, &ptr, expand_nstring[n], expand_nlength[n]); continue; } @@ -4044,11 +4076,12 @@ while (*s != 0) DEBUG(D_expand) debug_printf("acl expansion yield: %s\n", user_msg); if (user_msg) - yield = string_cat(yield, &size, &ptr, user_msg, Ustrlen(user_msg)); + yield = string_cat(yield, &size, &ptr, user_msg); continue; case DEFER: expand_string_forcedfail = TRUE; + /*FALLTHROUGH*/ default: expand_string_message = string_sprintf("error from acl \"%s\"", sub[0]); goto EXPAND_FAILED; @@ -4135,7 +4168,7 @@ while (*s != 0) sub_arg[1][0], sub_arg[2], &expand_string_message))) goto EXPAND_FAILED; if (!skipping) - yield = string_cat(yield, &size, &ptr, encoded, Ustrlen(encoded)); + yield = string_cat(yield, &size, &ptr, encoded); continue; } #endif @@ -4171,8 +4204,12 @@ while (*s != 0) if (*s == '{') /*}*/ { key = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); - if (key == NULL) goto EXPAND_FAILED; /*{*/ - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (!key) goto EXPAND_FAILED; /*{{*/ + if (*s++ != '}') + { + expand_string_message = US"missing '}' after lookup key"; + goto EXPAND_FAILED_CURLY; + } while (isspace(*s)) s++; } else key = NULL; @@ -4235,10 +4272,18 @@ while (*s != 0) queries that also require a file name (e.g. sqlite), the file name comes first. */ - if (*s != '{') goto EXPAND_FAILED_CURLY; + if (*s != '{') + { + expand_string_message = US"missing '{' for lookup file-or-query arg"; + goto EXPAND_FAILED_CURLY; + } filename = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); if (filename == NULL) goto EXPAND_FAILED; - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (*s++ != '}') + { + expand_string_message = US"missing '}' closing lookup file-or-query arg"; + goto EXPAND_FAILED_CURLY; + } while (isspace(*s)) s++; /* If this isn't a single-key+file lookup, re-arrange the variables @@ -4246,15 +4291,13 @@ while (*s != 0) there is just a "key", and no file name. For the special query-style + file types, the query (i.e. "key") starts with a file name. */ - if (key == NULL) + if (!key) { while (isspace(*filename)) filename++; key = filename; if (mac_islookup(stype, lookup_querystyle)) - { filename = NULL; - } else { if (*filename != '/') @@ -4464,14 +4507,14 @@ while (*s != 0) /* Now separate the domain from the local part */ *domain++ = '\0'; - yield = string_cat(yield,&size,&ptr,US"prvs=",5); - string_cat(yield,&size,&ptr,(sub_arg[2] != NULL) ? sub_arg[2] : US"0", 1); - string_cat(yield,&size,&ptr,prvs_daystamp(7),3); - string_cat(yield,&size,&ptr,p,6); - string_cat(yield,&size,&ptr,US"=",1); - string_cat(yield,&size,&ptr,sub_arg[0],Ustrlen(sub_arg[0])); - string_cat(yield,&size,&ptr,US"@",1); - string_cat(yield,&size,&ptr,domain,Ustrlen(domain)); + yield = string_catn(yield, &size, &ptr, US"prvs=", 5); + yield = string_catn(yield, &size, &ptr, sub_arg[2] ? sub_arg[2] : US"0", 1); + yield = string_catn(yield, &size, &ptr, prvs_daystamp(7), 3); + yield = string_catn(yield, &size, &ptr, p, 6); + yield = string_catn(yield, &size, &ptr, US"=", 1); + yield = string_cat (yield, &size, &ptr, sub_arg[0]); + yield = string_catn(yield, &size, &ptr, US"@", 1); + yield = string_cat (yield, &size, &ptr, domain); continue; } @@ -4525,9 +4568,9 @@ while (*s != 0) DEBUG(D_expand) debug_printf("prvscheck domain: %s\n", domain); /* Set up expansion variables */ - prvscheck_address = string_cat(NULL, &mysize, &myptr, local_part, Ustrlen(local_part)); - string_cat(prvscheck_address,&mysize,&myptr,US"@",1); - string_cat(prvscheck_address,&mysize,&myptr,domain,Ustrlen(domain)); + prvscheck_address = string_cat (NULL, &mysize, &myptr, local_part); + prvscheck_address = string_catn(prvscheck_address, &mysize, &myptr, US"@", 1); + prvscheck_address = string_cat (prvscheck_address, &mysize, &myptr, domain); prvscheck_address[myptr] = '\0'; prvscheck_keynum = string_copy(key_num); @@ -4593,10 +4636,8 @@ while (*s != 0) case 3: goto EXPAND_FAILED; } - if (sub_arg[0] == NULL || *sub_arg[0] == '\0') - yield = string_cat(yield,&size,&ptr,prvscheck_address,Ustrlen(prvscheck_address)); - else - yield = string_cat(yield,&size,&ptr,sub_arg[0],Ustrlen(sub_arg[0])); + yield = string_cat(yield, &size, &ptr, + !sub_arg[0] || !*sub_arg[0] ? prvscheck_address : sub_arg[0]); /* Reset the "internal" variables afterwards, because they are in dynamic store that will be reclaimed if the expansion succeeded. */ @@ -4843,10 +4884,20 @@ while (*s != 0) { if (expand_string_internal(s+1, TRUE, &s, TRUE, TRUE, &resetok) == NULL) goto EXPAND_FAILED; - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (*s++ != '}') + { + expand_string_message = US"missing '}' closing failstring for readsocket"; + goto EXPAND_FAILED_CURLY; + } while (isspace(*s)) s++; } - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + + readsock_done: + if (*s++ != '}') + { + expand_string_message = US"missing '}' closing readsocket"; + goto EXPAND_FAILED_CURLY; + } continue; /* Come here on failure to create socket, connect socket, write to the @@ -4856,13 +4907,16 @@ 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, TRUE, &resetok); - if (arg == NULL) goto EXPAND_FAILED; - yield = string_cat(yield, &size, &ptr, arg, Ustrlen(arg)); - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (!(arg = expand_string_internal(s+1, TRUE, &s, FALSE, TRUE, &resetok))) + goto EXPAND_FAILED; + yield = string_cat(yield, &size, &ptr, arg); + if (*s++ != '}') + { + expand_string_message = US"missing '}' closing failstring for readsocket"; + goto EXPAND_FAILED_CURLY; + } while (isspace(*s)) s++; - if (*s++ != '}') goto EXPAND_FAILED_CURLY; - continue; + goto readsock_done; } /* Handle "run" to execute a program. */ @@ -4883,16 +4937,22 @@ while (*s != 0) } while (isspace(*s)) s++; - if (*s != '{') goto EXPAND_FAILED_CURLY; + if (*s != '{') + { + expand_string_message = US"missing '{' for command arg of run"; + goto EXPAND_FAILED_CURLY; + } arg = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); if (arg == NULL) goto EXPAND_FAILED; while (isspace(*s)) s++; - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (*s++ != '}') + { + expand_string_message = US"missing '}' closing command arg of run"; + goto EXPAND_FAILED_CURLY; + } if (skipping) /* Just pretend it worked when we're skipping */ - { runrc = 0; - } else { if (!transport_set_up_command(&argv, /* anchor for arg list */ @@ -4989,7 +5049,7 @@ while (*s != 0) case 3: goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, sub[0], Ustrlen(sub[0])); + yield = string_cat(yield, &size, &ptr, sub[0]); o2m = Ustrlen(sub[2]) - 1; if (o2m >= 0) for (; oldptr < ptr; oldptr++) @@ -5066,7 +5126,7 @@ while (*s != 0) extract_substr(sub[2], val[0], val[1], &len); if (ret == NULL) goto EXPAND_FAILED; - yield = string_cat(yield, &size, &ptr, ret, len); + yield = string_catn(yield, &size, &ptr, ret, len); continue; } @@ -5174,7 +5234,7 @@ while (*s != 0) DEBUG(D_any) debug_printf("HMAC[%s](%.*s,%.*s)=%.*s\n", sub[0], (int)keylen, keyptr, Ustrlen(sub[2]), sub[2], hashlen*2, finalhash_hex); - yield = string_cat(yield, &size, &ptr, finalhash_hex, hashlen*2); + yield = string_catn(yield, &size, &ptr, finalhash_hex, hashlen*2); } continue; @@ -5245,7 +5305,7 @@ while (*s != 0) emptyopt = 0; continue; } - yield = string_cat(yield, &size, &ptr, subject+moffset, slen-moffset); + yield = string_catn(yield, &size, &ptr, subject+moffset, slen-moffset); break; } @@ -5262,11 +5322,11 @@ while (*s != 0) /* Copy the characters before the match, plus the expanded insertion. */ - yield = string_cat(yield, &size, &ptr, subject + moffset, + yield = string_catn(yield, &size, &ptr, subject + moffset, ovector[0] - moffset); insert = expand_string(sub[2]); if (insert == NULL) goto EXPAND_FAILED; - yield = string_cat(yield, &size, &ptr, insert, Ustrlen(insert)); + yield = string_cat(yield, &size, &ptr, insert); moffset = ovector[1]; moffsetextra = 0; @@ -5307,16 +5367,44 @@ while (*s != 0) int save_expand_nmax = save_expand_strings(save_expand_nstring, save_expand_nlength); - /* Read the arguments */ + /* While skipping we cannot rely on the data for expansions being + available (eg. $item) hence cannot decide on numeric vs. keyed. + Just read as many arguments as there are. */ - for (i = 0; i < j; i++) + if (skipping) + { + while (isspace(*s)) s++; + while (*s == '{') + { + if (!expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok)) + goto EXPAND_FAILED; /*{*/ + if (*s++ != '}') + { + expand_string_message = US"missing '{' for arg of extract"; + goto EXPAND_FAILED_CURLY; + } + while (isspace(*s)) s++; + } + if (*s != '}') + { + expand_string_message = US"missing '}' closing extract"; + goto EXPAND_FAILED_CURLY; + } + } + + else for (i = 0; i < j; i++) /* Read the proper number of arguments */ { while (isspace(*s)) s++; if (*s == '{') /*}*/ { sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); if (sub[i] == NULL) goto EXPAND_FAILED; /*{*/ - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (*s++ != '}') + { + expand_string_message = string_sprintf( + US"missing '}' closing arg %d of extract", i+1); + goto EXPAND_FAILED_CURLY; + } /* After removal of leading and trailing white space, the first argument must not be empty; if it consists entirely of digits @@ -5336,31 +5424,33 @@ while (*s != 0) while (len > 0 && isspace(p[len-1])) len--; p[len] = 0; - if (!skipping) + if (*p == 0) { - if (*p == 0) - { - expand_string_message = US"first argument of \"extract\" must " - "not be empty"; - goto EXPAND_FAILED; - } + expand_string_message = US"first argument of \"extract\" must " + "not be empty"; + goto EXPAND_FAILED; + } - if (*p == '-') - { - field_number = -1; - p++; - } - while (*p != 0 && isdigit(*p)) x = x * 10 + *p++ - '0'; - if (*p == 0) - { - field_number *= x; - j = 3; /* Need 3 args */ - field_number_set = TRUE; - } + if (*p == '-') + { + field_number = -1; + p++; + } + while (*p != 0 && isdigit(*p)) x = x * 10 + *p++ - '0'; + if (*p == 0) + { + field_number *= x; + j = 3; /* Need 3 args */ + field_number_set = TRUE; } } } - else goto EXPAND_FAILED_CURLY; + else + { + expand_string_message = string_sprintf( + US"missing '{' for arg %d of extract", i+1); + goto EXPAND_FAILED_CURLY; + } } /* Extract either the numbered or the keyed substring into $value. If @@ -5413,11 +5503,20 @@ while (*s != 0) { while (isspace(*s)) s++; if (*s != '{') /*}*/ + { + expand_string_message = string_sprintf( + US"missing '{' for arg %d of listextract", i+1); goto EXPAND_FAILED_CURLY; + } sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); if (!sub[i]) goto EXPAND_FAILED; /*{*/ - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (*s++ != '}') + { + expand_string_message = string_sprintf( + US"missing '}' closing arg %d of listextract", i+1); + goto EXPAND_FAILED_CURLY; + } /* After removal of leading and trailing white space, the first argument must be numeric and nonempty. */ @@ -5500,10 +5599,17 @@ while (*s != 0) /* Read the field argument */ while (isspace(*s)) s++; if (*s != '{') /*}*/ + { + expand_string_message = US"missing '{' for field arg of certextract"; goto EXPAND_FAILED_CURLY; + } sub[0] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); if (!sub[0]) goto EXPAND_FAILED; /*{*/ - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (*s++ != '}') + { + expand_string_message = US"missing '}' closing field arg of certextract"; + goto EXPAND_FAILED_CURLY; + } /* strip spaces fore & aft */ { int len; @@ -5520,7 +5626,10 @@ while (*s != 0) /* inspect the cert argument */ while (isspace(*s)) s++; if (*s != '{') /*}*/ + { + expand_string_message = US"missing '{' for cert variable arg of certextract"; goto EXPAND_FAILED_CURLY; + } if (*++s != '$') { expand_string_message = US"second argument of \"certextract\" must " @@ -5529,7 +5638,11 @@ while (*s != 0) } sub[1] = expand_string_internal(s+1, TRUE, &s, skipping, FALSE, &resetok); if (!sub[1]) goto EXPAND_FAILED; /*{*/ - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (*s++ != '}') + { + expand_string_message = US"missing '}' closing cert variable arg of certextract"; + goto EXPAND_FAILED_CURLY; + } if (skipping) lookup_value = NULL; @@ -5573,25 +5686,48 @@ while (*s != 0) uschar *save_lookup_value = lookup_value; while (isspace(*s)) s++; - if (*s++ != '{') goto EXPAND_FAILED_CURLY; + if (*s++ != '{') + { + expand_string_message = + string_sprintf("missing '{' for first arg of %s", name); + goto EXPAND_FAILED_CURLY; + } list = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok); if (list == NULL) goto EXPAND_FAILED; - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (*s++ != '}') + { + expand_string_message = + string_sprintf("missing '}' closing first arg of %s", name); + goto EXPAND_FAILED_CURLY; + } if (item_type == EITEM_REDUCE) { uschar * t; while (isspace(*s)) s++; - if (*s++ != '{') goto EXPAND_FAILED_CURLY; + if (*s++ != '{') + { + expand_string_message = US"missing '{' for second arg of reduce"; + goto EXPAND_FAILED_CURLY; + } t = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok); if (!t) goto EXPAND_FAILED; lookup_value = t; - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (*s++ != '}') + { + expand_string_message = US"missing '}' closing second arg of reduce"; + goto EXPAND_FAILED_CURLY; + } } while (isspace(*s)) s++; - if (*s++ != '{') goto EXPAND_FAILED_CURLY; + if (*s++ != '{') + { + expand_string_message = + string_sprintf("missing '{' for last arg of %s", name); + goto EXPAND_FAILED_CURLY; + } expr = s; @@ -5689,7 +5825,7 @@ while (*s != 0) separator character, or is an empty string. */ if (ptr != save_ptr && (temp[0] == *outsep || temp[0] == 0)) - yield = string_cat(yield, &size, &ptr, US" ", 1); + yield = string_catn(yield, &size, &ptr, US" ", 1); /* Add the string in "temp" to the output list that we are building, This is done in chunks by searching for the separator character. */ @@ -5697,21 +5833,22 @@ while (*s != 0) for (;;) { size_t seglen = Ustrcspn(temp, outsep); - yield = string_cat(yield, &size, &ptr, temp, seglen + 1); + + yield = string_catn(yield, &size, &ptr, temp, seglen + 1); /* If we got to the end of the string we output one character too many; backup and end the loop. Otherwise arrange to double the separator. */ if (temp[seglen] == '\0') { ptr--; break; } - yield = string_cat(yield, &size, &ptr, outsep, 1); + yield = string_catn(yield, &size, &ptr, outsep, 1); temp += seglen + 1; } /* Output a separator after the string: we will remove the redundant final one at the end. */ - yield = string_cat(yield, &size, &ptr, outsep, 1); + yield = string_catn(yield, &size, &ptr, outsep, 1); } /* End of iteration over the list loop */ /* REDUCE has generated no output above: output the final value of @@ -5719,8 +5856,7 @@ while (*s != 0) if (item_type == EITEM_REDUCE) { - yield = string_cat(yield, &size, &ptr, lookup_value, - Ustrlen(lookup_value)); + yield = string_cat(yield, &size, &ptr, lookup_value); lookup_value = save_lookup_value; /* Restore $value */ } @@ -5746,28 +5882,52 @@ while (*s != 0) uschar *save_iterate_item = iterate_item; while (isspace(*s)) s++; - if (*s++ != '{') goto EXPAND_FAILED_CURLY; + if (*s++ != '{') + { + expand_string_message = US"missing '{' for list arg of sort"; + goto EXPAND_FAILED_CURLY; + } srclist = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok); if (!srclist) goto EXPAND_FAILED; - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (*s++ != '}') + { + expand_string_message = US"missing '}' closing list arg of sort"; + goto EXPAND_FAILED_CURLY; + } while (isspace(*s)) s++; - if (*s++ != '{') goto EXPAND_FAILED_CURLY; + if (*s++ != '{') + { + expand_string_message = US"missing '{' for comparator arg of sort"; + goto EXPAND_FAILED_CURLY; + } cmp = expand_string_internal(s, TRUE, &s, skipping, FALSE, &resetok); if (!cmp) goto EXPAND_FAILED; - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (*s++ != '}') + { + expand_string_message = US"missing '}' closing comparator arg of sort"; + goto EXPAND_FAILED_CURLY; + } while (isspace(*s)) s++; - if (*s++ != '{') goto EXPAND_FAILED_CURLY; + if (*s++ != '{') + { + expand_string_message = US"missing '{' for extractor arg of sort"; + goto EXPAND_FAILED_CURLY; + } xtract = s; tmp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok); if (!tmp) goto EXPAND_FAILED; xtract = string_copyn(xtract, s - xtract); - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (*s++ != '}') + { + expand_string_message = US"missing '}' closing extractor arg of sort"; + goto EXPAND_FAILED_CURLY; + } /*{*/ if (*s++ != '}') { /*{*/ @@ -5863,7 +6023,7 @@ while (*s != 0) } if (dstlist) - yield = string_cat(yield, &size, &ptr, dstlist, Ustrlen(dstlist)); + yield = string_cat(yield, &size, &ptr, dstlist); /* Restore preserved $item */ iterate_item = save_iterate_item; @@ -5961,7 +6121,7 @@ while (*s != 0) if(status == OK) { if (result == NULL) result = US""; - yield = string_cat(yield, &size, &ptr, result, Ustrlen(result)); + yield = string_cat(yield, &size, &ptr, result); continue; } else @@ -5987,7 +6147,11 @@ while (*s != 0) key = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok); if (!key) goto EXPAND_FAILED; /*{*/ - if (*s++ != '}') goto EXPAND_FAILED_CURLY; + if (*s++ != '}') + { + expand_string_message = US"missing '{' for name arg of env"; + goto EXPAND_FAILED_CURLY; + } lookup_value = US getenv(CS key); @@ -6051,7 +6215,12 @@ while (*s != 0) sub = expand_string_internal(s+2, TRUE, &s1, skipping, FALSE, &resetok); if (!sub) goto EXPAND_FAILED; /*{*/ - if (*s1 != '}') goto EXPAND_FAILED_CURLY; + if (*s1 != '}') + { + expand_string_message = + string_sprintf("missing '}' closing cert arg of %s", name); + goto EXPAND_FAILED_CURLY; + } if ((vp = find_var_ent(sub)) && vp->type == vtype_cert) { s = s1+1; @@ -6091,7 +6260,7 @@ while (*s != 0) goto EXPAND_FAILED; } t = string_base62(n); - yield = string_cat(yield, &size, &ptr, t, Ustrlen(t)); + yield = string_cat(yield, &size, &ptr, t); continue; } @@ -6115,7 +6284,7 @@ while (*s != 0) n = n * BASE_62 + (t - base62_chars); } (void)sprintf(CS buf, "%ld", n); - yield = string_cat(yield, &size, &ptr, buf, Ustrlen(buf)); + yield = string_cat(yield, &size, &ptr, buf); continue; } @@ -6129,7 +6298,7 @@ while (*s != 0) expand_string_message); goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, expanded, Ustrlen(expanded)); + yield = string_cat(yield, &size, &ptr, expanded); continue; } @@ -6138,7 +6307,7 @@ while (*s != 0) int count = 0; uschar *t = sub - 1; while (*(++t) != 0) { *t = tolower(*t); count++; } - yield = string_cat(yield, &size, &ptr, sub, count); + yield = string_catn(yield, &size, &ptr, sub, count); continue; } @@ -6147,7 +6316,7 @@ while (*s != 0) int count = 0; uschar *t = sub - 1; while (*(++t) != 0) { *t = toupper(*t); count++; } - yield = string_cat(yield, &size, &ptr, sub, count); + yield = string_catn(yield, &size, &ptr, sub, count); continue; } @@ -6156,7 +6325,7 @@ while (*s != 0) if (vp && *(void **)vp->value) { uschar * cp = tls_cert_fprt_md5(*(void **)vp->value); - yield = string_cat(yield, &size, &ptr, cp, Ustrlen(cp)); + yield = string_cat(yield, &size, &ptr, cp); } else #endif @@ -6168,7 +6337,7 @@ while (*s != 0) md5_start(&base); md5_end(&base, sub, Ustrlen(sub), digest); for(j = 0; j < 16; j++) sprintf(st+2*j, "%02x", digest[j]); - yield = string_cat(yield, &size, &ptr, US st, (int)strlen(st)); + yield = string_cat(yield, &size, &ptr, US st); } continue; @@ -6177,7 +6346,7 @@ while (*s != 0) if (vp && *(void **)vp->value) { uschar * cp = tls_cert_fprt_sha1(*(void **)vp->value); - yield = string_cat(yield, &size, &ptr, cp, Ustrlen(cp)); + yield = string_cat(yield, &size, &ptr, cp); } else #endif @@ -6189,7 +6358,7 @@ while (*s != 0) sha1_start(&base); sha1_end(&base, sub, Ustrlen(sub), digest); for(j = 0; j < 20; j++) sprintf(st+2*j, "%02X", digest[j]); - yield = string_cat(yield, &size, &ptr, US st, (int)strlen(st)); + yield = string_cat(yield, &size, &ptr, US st); } continue; @@ -6198,7 +6367,7 @@ while (*s != 0) if (vp && *(void **)vp->value) { uschar * cp = tls_cert_fprt_sha256(*(void **)vp->value); - yield = string_cat(yield, &size, &ptr, cp, (int)Ustrlen(cp)); + yield = string_cat(yield, &size, &ptr, cp); } else #endif @@ -6249,7 +6418,7 @@ while (*s != 0) } enc = b64encode(sub, out - sub); - yield = string_cat(yield, &size, &ptr, enc, Ustrlen(enc)); + yield = string_cat(yield, &size, &ptr, enc); continue; } @@ -6261,10 +6430,10 @@ while (*s != 0) while (*(++t) != 0) { if (*t < 0x21 || 0x7E < *t) - yield = string_cat(yield, &size, &ptr, + yield = string_catn(yield, &size, &ptr, string_sprintf("\\x%02x", *t), 4); else - yield = string_cat(yield, &size, &ptr, t, 1); + yield = string_catn(yield, &size, &ptr, t, 1); } continue; } @@ -6280,7 +6449,7 @@ while (*s != 0) while (string_nextinlist(CUSS &sub, &sep, buffer, sizeof(buffer)) != NULL) cnt++; cp = string_sprintf("%d", cnt); - yield = string_cat(yield, &size, &ptr, cp, Ustrlen(cp)); + yield = string_cat(yield, &size, &ptr, cp); continue; } @@ -6334,7 +6503,7 @@ while (*s != 0) { uschar * buf = US" : "; if (needsep) - yield = string_cat(yield, &size, &ptr, buf, 3); + yield = string_catn(yield, &size, &ptr, buf, 3); else needsep = TRUE; @@ -6350,21 +6519,21 @@ while (*s != 0) tok[0] = sep; tok[1] = ':'; tok[2] = 0; while ((cp= strpbrk((const char *)item, tok))) { - yield = string_cat(yield, &size, &ptr, item, cp-(char *)item); + yield = string_catn(yield, &size, &ptr, item, cp-(char *)item); if (*cp++ == ':') /* colon in a non-colon-sep list item, needs doubling */ { - yield = string_cat(yield, &size, &ptr, US"::", 2); + yield = string_catn(yield, &size, &ptr, US"::", 2); item = (uschar *)cp; } else /* sep in item; should already be doubled; emit once */ { - yield = string_cat(yield, &size, &ptr, (uschar *)tok, 1); + yield = string_catn(yield, &size, &ptr, (uschar *)tok, 1); if (*cp == sep) cp++; item = (uschar *)cp; } } } - yield = string_cat(yield, &size, &ptr, item, Ustrlen(item)); + yield = string_cat(yield, &size, &ptr, item); } continue; } @@ -6412,7 +6581,7 @@ while (*s != 0) /* Convert to masked textual format and add to output. */ - yield = string_cat(yield, &size, &ptr, buffer, + yield = string_catn(yield, &size, &ptr, buffer, host_nmtoa(count, binary, mask, buffer, '.')); continue; } @@ -6442,7 +6611,7 @@ while (*s != 0) goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, buffer, + yield = string_catn(yield, &size, &ptr, buffer, c == EOP_IPV6NORM ? ipv6_nmtoa(binary, buffer) : host_nmtoa(4, binary, -1, buffer, ':') @@ -6463,12 +6632,12 @@ while (*s != 0) if (c != EOP_DOMAIN) { if (c == EOP_LOCAL_PART && domain != 0) end = start + domain - 1; - yield = string_cat(yield, &size, &ptr, sub+start, end-start); + yield = string_catn(yield, &size, &ptr, sub+start, end-start); } else if (domain != 0) { domain += start; - yield = string_cat(yield, &size, &ptr, sub+domain, end-domain); + yield = string_catn(yield, &size, &ptr, sub+domain, end-domain); } } continue; @@ -6503,25 +6672,25 @@ while (*s != 0) if (address != NULL) { if (ptr != save_ptr && address[0] == *outsep) - yield = string_cat(yield, &size, &ptr, US" ", 1); + yield = string_catn(yield, &size, &ptr, US" ", 1); for (;;) { size_t seglen = Ustrcspn(address, outsep); - yield = string_cat(yield, &size, &ptr, address, seglen + 1); + yield = string_catn(yield, &size, &ptr, address, seglen + 1); /* If we got to the end of the string we output one character too many. */ if (address[seglen] == '\0') { ptr--; break; } - yield = string_cat(yield, &size, &ptr, outsep, 1); + yield = string_catn(yield, &size, &ptr, outsep, 1); address += seglen + 1; } /* Output a separator after the string: we will remove the redundant final one at the end. */ - yield = string_cat(yield, &size, &ptr, outsep, 1); + yield = string_catn(yield, &size, &ptr, outsep, 1); } if (saveend == '\0') break; @@ -6568,24 +6737,24 @@ while (*s != 0) if (needs_quote) { - yield = string_cat(yield, &size, &ptr, US"\"", 1); + yield = string_catn(yield, &size, &ptr, US"\"", 1); t = sub - 1; while (*(++t) != 0) { if (*t == '\n') - yield = string_cat(yield, &size, &ptr, US"\\n", 2); + yield = string_catn(yield, &size, &ptr, US"\\n", 2); else if (*t == '\r') - yield = string_cat(yield, &size, &ptr, US"\\r", 2); + yield = string_catn(yield, &size, &ptr, US"\\r", 2); else { if (*t == '\\' || *t == '"') - yield = string_cat(yield, &size, &ptr, US"\\", 1); - yield = string_cat(yield, &size, &ptr, t, 1); + yield = string_catn(yield, &size, &ptr, US"\\", 1); + yield = string_catn(yield, &size, &ptr, t, 1); } } - yield = string_cat(yield, &size, &ptr, US"\"", 1); + yield = string_catn(yield, &size, &ptr, US"\"", 1); } - else yield = string_cat(yield, &size, &ptr, sub, Ustrlen(sub)); + else yield = string_cat(yield, &size, &ptr, sub); continue; } @@ -6617,7 +6786,7 @@ while (*s != 0) goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, sub, Ustrlen(sub)); + yield = string_cat(yield, &size, &ptr, sub); continue; } @@ -6630,8 +6799,8 @@ while (*s != 0) while (*(++t) != 0) { if (!isalnum(*t)) - yield = string_cat(yield, &size, &ptr, US"\\", 1); - yield = string_cat(yield, &size, &ptr, t, 1); + yield = string_catn(yield, &size, &ptr, US"\\", 1); + yield = string_catn(yield, &size, &ptr, t, 1); } continue; } @@ -6644,7 +6813,7 @@ while (*s != 0) uschar buffer[2048]; const uschar *string = parse_quote_2047(sub, Ustrlen(sub), headers_charset, buffer, sizeof(buffer), FALSE); - yield = string_cat(yield, &size, &ptr, string, Ustrlen(string)); + yield = string_cat(yield, &size, &ptr, string); continue; } @@ -6661,7 +6830,7 @@ while (*s != 0) expand_string_message = error; goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, decoded, len); + yield = string_catn(yield, &size, &ptr, decoded, len); continue; } @@ -6677,7 +6846,7 @@ while (*s != 0) GETUTF8INC(c, sub); if (c > 255) c = '_'; buff[0] = c; - yield = string_cat(yield, &size, &ptr, buff, 1); + yield = string_catn(yield, &size, &ptr, buff, 1); } continue; } @@ -6712,7 +6881,7 @@ while (*s != 0) complete = -1; /* error (RFC3629 limit) */ else { /* finished; output utf-8 sequence */ - yield = string_cat(yield, &size, &ptr, seq_buff, seq_len); + yield = string_catn(yield, &size, &ptr, seq_buff, seq_len); index = 0; } } @@ -6721,7 +6890,7 @@ while (*s != 0) { if((c & 0x80) == 0) /* 1-byte sequence, US-ASCII, keep it */ { - yield = string_cat(yield, &size, &ptr, &c, 1); + yield = string_catn(yield, &size, &ptr, &c, 1); continue; } if((c & 0xe0) == 0xc0) /* 2-byte sequence */ @@ -6754,11 +6923,11 @@ while (*s != 0) if (complete != 0) { bytes_left = index = 0; - yield = string_cat(yield, &size, &ptr, UTF8_REPLACEMENT_CHAR, 1); + yield = string_catn(yield, &size, &ptr, UTF8_REPLACEMENT_CHAR, 1); } if ((complete == 1) && ((c & 0x80) == 0)) /* ASCII character follows incomplete sequence */ - yield = string_cat(yield, &size, &ptr, &c, 1); + yield = string_catn(yield, &size, &ptr, &c, 1); } continue; } @@ -6775,7 +6944,7 @@ while (*s != 0) string_printing(sub), error); goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); + yield = string_cat(yield, &size, &ptr, s); continue; } @@ -6790,7 +6959,7 @@ while (*s != 0) string_printing(sub), error); goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); + yield = string_cat(yield, &size, &ptr, s); continue; } @@ -6805,7 +6974,7 @@ while (*s != 0) string_printing(sub), error); goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); + yield = string_cat(yield, &size, &ptr, s); DEBUG(D_expand) debug_printf("yield: '%s'\n", yield); continue; } @@ -6821,7 +6990,7 @@ while (*s != 0) string_printing(sub), error); goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); + yield = string_cat(yield, &size, &ptr, s); continue; } #endif /* EXPERIMENTAL_INTERNATIONAL */ @@ -6831,7 +7000,7 @@ while (*s != 0) case EOP_ESCAPE: { const uschar *t = string_printing(sub); - yield = string_cat(yield, &size, &ptr, t, Ustrlen(t)); + yield = string_cat(yield, &size, &ptr, t); continue; } @@ -6851,7 +7020,7 @@ while (*s != 0) goto EXPAND_FAILED; } sprintf(CS var_buffer, PR_EXIM_ARITH, n); - yield = string_cat(yield, &size, &ptr, var_buffer, Ustrlen(var_buffer)); + yield = string_cat(yield, &size, &ptr, var_buffer); continue; } @@ -6867,7 +7036,7 @@ while (*s != 0) goto EXPAND_FAILED; } sprintf(CS var_buffer, "%d", n); - yield = string_cat(yield, &size, &ptr, var_buffer, Ustrlen(var_buffer)); + yield = string_cat(yield, &size, &ptr, var_buffer); continue; } @@ -6882,7 +7051,7 @@ while (*s != 0) goto EXPAND_FAILED; } t = readconf_printtime(n); - yield = string_cat(yield, &size, &ptr, t, Ustrlen(t)); + yield = string_cat(yield, &size, &ptr, t); continue; } @@ -6898,7 +7067,7 @@ while (*s != 0) #else uschar * s = b64encode(sub, Ustrlen(sub)); #endif - yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); + yield = string_cat(yield, &size, &ptr, s); continue; } @@ -6912,7 +7081,7 @@ while (*s != 0) "well-formed for \"%s\" operator", sub, name); goto EXPAND_FAILED; } - yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); + yield = string_cat(yield, &size, &ptr, s); continue; } @@ -6922,7 +7091,7 @@ while (*s != 0) { uschar buff[24]; (void)sprintf(CS buff, "%d", Ustrlen(sub)); - yield = string_cat(yield, &size, &ptr, buff, Ustrlen(buff)); + yield = string_cat(yield, &size, &ptr, buff); continue; } @@ -7013,7 +7182,7 @@ while (*s != 0) extract_substr(sub, value1, value2, &len); if (ret == NULL) goto EXPAND_FAILED; - yield = string_cat(yield, &size, &ptr, ret, len); + yield = string_catn(yield, &size, &ptr, ret, len); continue; } @@ -7068,7 +7237,7 @@ while (*s != 0) (long)st.st_dev, (long)st.st_nlink, (long)st.st_uid, (long)st.st_gid, st.st_size, (long)st.st_atime, (long)st.st_mtime, (long)st.st_ctime); - yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); + yield = string_cat(yield, &size, &ptr, s); continue; } @@ -7083,7 +7252,7 @@ while (*s != 0) if (expand_string_message != NULL) goto EXPAND_FAILED; s = string_sprintf("%d", vaguely_random_number((int)max)); - yield = string_cat(yield, &size, &ptr, s, Ustrlen(s)); + yield = string_cat(yield, &size, &ptr, s); continue; } @@ -7102,7 +7271,7 @@ while (*s != 0) goto EXPAND_FAILED; } invert_address(reversed, sub); - yield = string_cat(yield, &size, &ptr, reversed, Ustrlen(reversed)); + yield = string_cat(yield, &size, &ptr, reversed); continue; } @@ -7147,7 +7316,7 @@ while (*s != 0) size = newsize; ptr = len; } - else yield = string_cat(yield, &size, &ptr, value, len); + else yield = string_catn(yield, &size, &ptr, value, len); continue; } @@ -7188,9 +7357,9 @@ else if (resetok_p) *resetok_p = FALSE; DEBUG(D_expand) { - debug_printf("expanding: %.*s\n result: %s\n", (int)(s - string), string, + debug_printf(" expanding: %.*s\n result: %s\n", (int)(s - string), string, yield); - if (skipping) debug_printf("skipping: result is not used\n"); + if (skipping) debug_printf(" skipping: result is not used\n"); } return yield; @@ -7199,10 +7368,12 @@ to update the pointer to the terminator, for cases of nested calls with "fail". */ EXPAND_FAILED_CURLY: -expand_string_message = malformed_header? - US"missing or misplaced { or } - could be header name not terminated by colon" - : - US"missing or misplaced { or }"; +if (malformed_header) + expand_string_message = + US"missing or misplaced { or } - could be header name not terminated by colon"; + +else if (!expand_string_message || !*expand_string_message) + expand_string_message = US"missing or misplaced { or }"; /* At one point, Exim reset the store to yield (if yield was not NULL), but that is a bad idea, because expand_string_message is in dynamic store. */