X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Fexpand.c;h=1f0c5cb3cfd14799cccb8822d901a1a73a2fa0c0;hb=4c01d6abf6429fff8ca8a97027dc9ac965f477a3;hp=8e94c3e4b67edbe1ddb57e6e294815aecf1f96aa;hpb=9175a8d2ac50382af2045b37e7b054180f91f4e8;p=exim.git diff --git a/src/src/expand.c b/src/src/expand.c index 8e94c3e4b..1f0c5cb3c 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -13,8 +13,8 @@ /* Recursively called function */ -static uschar *expand_string_internal(uschar *, BOOL, uschar **, BOOL, BOOL, BOOL *); -static int_eximarith_t expanded_string_integer(uschar *, BOOL); +static uschar *expand_string_internal(const uschar *, BOOL, const uschar **, BOOL, BOOL, BOOL *); +static int_eximarith_t expanded_string_integer(const uschar *, BOOL); #ifdef STAND_ALONE #ifndef SUPPORT_CRYPTEQ @@ -446,6 +446,8 @@ static var_entry var_table[] = { { "caller_uid", vtype_uid, &real_uid }, { "compile_date", vtype_stringptr, &version_date }, { "compile_number", vtype_stringptr, &version_cnumber }, + { "config_dir", vtype_stringptr, &config_main_directory }, + { "config_file", vtype_stringptr, &config_main_filename }, { "csa_status", vtype_stringptr, &csa_status }, #ifdef EXPERIMENTAL_DCC { "dcc_header", vtype_stringptr, &dcc_header }, @@ -490,9 +492,18 @@ static var_entry var_table[] = { { "dnslist_value", vtype_stringptr, &dnslist_value }, { "domain", vtype_stringptr, &deliver_domain }, { "domain_data", vtype_stringptr, &deliver_domain_data }, +#ifdef EXPERIMENTAL_EVENT + { "event_data", vtype_stringptr, &event_data }, + + /*XXX want to use generic vars for as many of these as possible*/ + { "event_defer_errno", vtype_int, &event_defer_errno }, + + { "event_name", vtype_stringptr, &event_name }, +#endif { "exim_gid", vtype_gid, &exim_gid }, { "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 @@ -644,6 +655,7 @@ static var_entry var_table[] = { { "sn8", vtype_filter_int, &filter_sn[8] }, { "sn9", vtype_filter_int, &filter_sn[9] }, #ifdef WITH_CONTENT_SCAN + { "spam_action", vtype_stringptr, &spam_action }, { "spam_bar", vtype_stringptr, &spam_bar }, { "spam_report", vtype_stringptr, &spam_report }, { "spam_score", vtype_stringptr, &spam_score }, @@ -714,16 +726,9 @@ static var_entry var_table[] = { { "tod_logfile", vtype_todlf, NULL }, { "tod_zone", vtype_todzone, NULL }, { "tod_zulu", vtype_todzulu, NULL }, -#ifdef EXPERIMENTAL_TPDA - { "tpda_data", vtype_stringptr, &tpda_data }, - - /*XXX want to use generic vars for as many of these as possible*/ - { "tpda_defer_errno", vtype_int, &tpda_defer_errno }, - - { "tpda_event", vtype_stringptr, &tpda_event }, -#endif { "transport_name", vtype_stringptr, &transport_name }, { "value", vtype_stringptr, &lookup_value }, + { "verify_mode", vtype_stringptr, &verify_mode }, { "version_number", vtype_stringptr, &version_string }, { "warn_message_delay", vtype_stringptr, &warnmsg_delay }, { "warn_message_recipient",vtype_stringptr, &warnmsg_recipients }, @@ -970,8 +975,8 @@ Note: The test for *s != 0 in the while loop is necessary because Ustrchr() yields non-NULL if the character is zero (which is not something I expected). */ -static uschar * -read_name(uschar *name, int max, uschar *s, uschar *extras) +static const uschar * +read_name(uschar *name, int max, const uschar *s, uschar *extras) { int ptr = 0; while (*s != 0 && (isalnum(*s) || Ustrchr(extras, *s) != NULL)) @@ -1004,8 +1009,8 @@ Arguments: Returns: a pointer to the first character after the header name */ -static uschar * -read_header_name(uschar *name, int max, uschar *s) +static const uschar * +read_header_name(uschar *name, int max, const uschar *s) { int prelen = Ustrchr(name, '_') - name + 1; int ptr = Ustrlen(name) - prelen; @@ -1042,6 +1047,14 @@ while (isdigit(*s)) *n = *n * 10 + (*s++ - '0'); return s; } +static const uschar * +read_cnumber(int *n, const uschar *s) +{ +*n = 0; +while (isdigit(*s)) *n = *n * 10 + (*s++ - '0'); +return s; +} + /************************************************* @@ -1059,7 +1072,7 @@ Returns: NULL if the subfield was not found, or */ static uschar * -expand_getkeyed(uschar *key, uschar *s) +expand_getkeyed(uschar *key, const uschar *s) { int length = Ustrlen(key); while (isspace(*s)) s++; @@ -1070,7 +1083,7 @@ while (*s != 0) { int dkeylength; uschar *data; - uschar *dkey = s; + const uschar *dkey = s; while (*s != 0 && *s != '=' && !isspace(*s)) s++; dkeylength = s - dkey; @@ -1181,17 +1194,17 @@ return fieldtext; static uschar * -expand_getlistele(int field, uschar * list) +expand_getlistele(int field, const uschar * list) { -uschar * tlist= list; +const uschar * tlist= list; int sep= 0; uschar dummy; if(field<0) -{ + { for(field++; string_nextinlist(&tlist, &sep, &dummy, 1); ) field++; sep= 0; -} + } if(field==0) return NULL; while(--field>0 && (string_nextinlist(&list, &sep, &dummy, 1))) ; return string_nextinlist(&list, &sep, NULL, 0); @@ -1933,11 +1946,11 @@ Returns: 0 OK; string pointer updated */ static int -read_subs(uschar **sub, int n, int m, uschar **sptr, BOOL skipping, +read_subs(uschar **sub, int n, int m, const uschar **sptr, BOOL skipping, BOOL check_end, uschar *name, BOOL *resetok) { int i; -uschar *s = *sptr; +const uschar *s = *sptr; while (isspace(*s)) s++; for (i = 0; i < n; i++) @@ -2013,7 +2026,7 @@ static int eval_acl(uschar ** sub, int nsub, uschar ** user_msgp) { int i; -uschar *tmp; +uschar * tmp = NULL; int sav_narg = acl_narg; int ret; extern int acl_where; @@ -2069,8 +2082,8 @@ Returns: a pointer to the first character after the condition, or NULL after an error */ -static uschar * -eval_condition(uschar *s, BOOL *resetok, BOOL *yield) +static const uschar * +eval_condition(const uschar *s, BOOL *resetok, BOOL *yield) { BOOL testfor = TRUE; BOOL tempcond, combined_cond; @@ -2080,7 +2093,7 @@ int i, rc, cond_type, roffset; int_eximarith_t num[2]; struct stat statbuf; uschar name[256]; -uschar *sub[10]; +const uschar *sub[10]; const pcre *re; const uschar *rerror; @@ -2300,6 +2313,7 @@ switch(cond_type) case ECOND_ACL: /* ${if acl {{name}{arg1}{arg2}...} {yes}{no}} */ { + uschar *sub[10]; uschar *user_msg; BOOL cond = FALSE; int size = 0; @@ -2750,6 +2764,7 @@ switch(cond_type) case ECOND_INLIST: case ECOND_INLISTI: { + const uschar * list = sub[1]; int sep = 0; uschar *save_iterate_item = iterate_item; int (*compare)(const uschar *, const uschar *); @@ -2757,12 +2772,10 @@ switch(cond_type) DEBUG(D_expand) debug_printf("condition: %s\n", name); tempcond = FALSE; - if (cond_type == ECOND_INLISTI) - compare = strcmpic; - else - compare = (int (*)(const uschar *, const uschar *)) strcmp; + compare = cond_type == ECOND_INLISTI + ? strcmpic : (int (*)(const uschar *, const uschar *)) strcmp; - while ((iterate_item = string_nextinlist(&sub[1], &sep, NULL, 0)) != NULL) + while ((iterate_item = string_nextinlist(&list, &sep, NULL, 0))) if (compare(sub[0], iterate_item) == 0) { tempcond = TRUE; @@ -2840,6 +2853,7 @@ switch(cond_type) case ECOND_FORALL: case ECOND_FORANY: { + const uschar * list; int sep = 0; uschar *save_iterate_item = iterate_item; @@ -2879,7 +2893,8 @@ switch(cond_type) } if (yield != NULL) *yield = !testfor; - while ((iterate_item = string_nextinlist(&sub[0], &sep, NULL, 0)) != NULL) + list = sub[0]; + while ((iterate_item = string_nextinlist(&list, &sep, NULL, 0)) != NULL) { DEBUG(D_expand) debug_printf("%s: $item = \"%s\"\n", name, iterate_item); if (!eval_condition(sub[1], resetok, &tempcond)) @@ -3097,11 +3112,11 @@ Returns: 0 OK; lookup_value has been reset to save_lookup */ static int -process_yesno(BOOL skipping, BOOL yes, uschar *save_lookup, uschar **sptr, +process_yesno(BOOL skipping, BOOL yes, uschar *save_lookup, const uschar **sptr, uschar **yieldptr, int *sizeptr, int *ptrptr, uschar *type, BOOL *resetok) { int rc = 0; -uschar *s = *sptr; /* Local value */ +const uschar *s = *sptr; /* Local value */ uschar *sub1, *sub2; /* If there are no following strings, we substitute the contents of $value for @@ -3179,7 +3194,8 @@ inside another lookup or if or extract. */ else if (*s != '}') { uschar name[256]; - s = read_name(name, sizeof(name), s, US"_"); + /* deconst cast ok here as source is s anyway */ + s = US read_name(name, sizeof(name), s, US"_"); if (Ustrcmp(name, "fail") == 0) { if (!yes && !skipping) @@ -3748,14 +3764,14 @@ Returns: NULL if expansion fails: */ static uschar * -expand_string_internal(uschar *string, BOOL ket_ends, uschar **left, +expand_string_internal(const uschar *string, BOOL ket_ends, const uschar **left, BOOL skipping, BOOL honour_dollar, BOOL *resetok_p) { int ptr = 0; int size = Ustrlen(string)+ 64; int item_type; uschar *yield = store_get(size); -uschar *s = string; +const uschar *s = string; uschar *save_expand_nstring[EXPAND_MAXN+1]; int save_expand_nlength[EXPAND_MAXN+1]; BOOL resetok = TRUE; @@ -3783,7 +3799,7 @@ while (*s != 0) if (s[1] == 'N') { - uschar *t = s + 2; + 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); if (*s != 0) s += 2; @@ -3899,7 +3915,7 @@ while (*s != 0) if (isdigit(*s)) { int n; - s = read_number(&n, s); + s = read_cnumber(&n, s); if (n >= 0 && n <= expand_nmax) yield = string_cat(yield, &size, &ptr, expand_nstring[n], expand_nlength[n]); @@ -3920,7 +3936,7 @@ while (*s != 0) if (isdigit((*(++s)))) { int n; - s = read_number(&n, s); /*{*/ + s = read_cnumber(&n, s); /*{*/ if (*s++ != '}') { /*{*/ expand_string_message = US"} expected after number"; @@ -3997,7 +4013,7 @@ while (*s != 0) case EITEM_IF: { BOOL cond = FALSE; - uschar *next_s; + const uschar *next_s; int save_expand_nmax = save_expand_strings(save_expand_nstring, save_expand_nlength); @@ -4049,7 +4065,8 @@ while (*s != 0) int stype, partial, affixlen, starflags; int expand_setup = 0; int nameptr = 0; - uschar *key, *filename, *affix; + uschar *key, *filename; + const uschar *affix; uschar *save_lookup_value = lookup_value; int save_expand_nmax = save_expand_strings(save_expand_nstring, save_expand_nlength); @@ -4767,7 +4784,7 @@ while (*s != 0) { FILE *f; uschar *arg; - uschar **argv; + const uschar **argv; pid_t pid; int fd_in, fd_out; int lsize = 0; @@ -4805,7 +4822,7 @@ while (*s != 0) /* Create the child process, making it a group leader. */ - pid = child_open(argv, NULL, 0077, &fd_in, &fd_out, TRUE); + pid = child_open(USS argv, NULL, 0077, &fd_in, &fd_out, TRUE); if (pid < 0) { @@ -5467,7 +5484,7 @@ while (*s != 0) int sep = 0; int save_ptr = ptr; uschar outsep[2] = { '\0', '\0' }; - uschar *list, *expr, *temp; + const uschar *list, *expr, *temp; uschar *save_iterate_item = iterate_item; uschar *save_lookup_value = lookup_value; @@ -5480,11 +5497,12 @@ while (*s != 0) if (item_type == EITEM_REDUCE) { + uschar * t; while (isspace(*s)) s++; if (*s++ != '{') goto EXPAND_FAILED_CURLY; - temp = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok); + t = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok); if (temp == NULL) goto EXPAND_FAILED; - lookup_value = temp; + lookup_value = t; if (*s++ != '}') goto EXPAND_FAILED_CURLY; } @@ -5505,9 +5523,7 @@ while (*s != 0) if (temp != NULL) s = temp; } else - { temp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok); - } if (temp == NULL) { @@ -5565,7 +5581,8 @@ while (*s != 0) else { - temp = expand_string_internal(expr, TRUE, NULL, skipping, TRUE, &resetok); + uschar * t = expand_string_internal(expr, TRUE, NULL, skipping, TRUE, &resetok); + temp = t; if (temp == NULL) { iterate_item = save_iterate_item; @@ -5575,7 +5592,7 @@ while (*s != 0) } if (item_type == EITEM_REDUCE) { - lookup_value = temp; /* Update the value of $value */ + lookup_value = t; /* Update the value of $value */ continue; /* and continue the iteration */ } } @@ -5638,10 +5655,9 @@ while (*s != 0) case EITEM_SORT: { int sep = 0; - uschar *srclist, *cmp, *xtract; + const uschar *srclist, *cmp, *xtract; uschar *srcitem; - uschar *dstlist = NULL; - uschar *dstkeylist = NULL; + const uschar *dstlist = NULL, *dstkeylist = NULL; uschar * tmp; uschar *save_iterate_item = iterate_item; @@ -5915,7 +5931,7 @@ while (*s != 0) case EOP_SHA256: if (s[1] == '$') { - uschar * s1 = s; + const uschar * s1 = s; sub = expand_string_internal(s+2, TRUE, &s1, skipping, FALSE, &resetok); if (!sub) goto EXPAND_FAILED; /*{*/ @@ -6146,7 +6162,7 @@ while (*s != 0) uschar * cp; uschar buffer[256]; - while (string_nextinlist(&sub, &sep, buffer, sizeof(buffer)) != NULL) cnt++; + 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)); continue; @@ -6158,7 +6174,7 @@ while (*s != 0) case EOP_LISTNAMED: { tree_node *t = NULL; - uschar * list; + const uschar * list; int sep = 0; uschar * item; uschar * suffix = US""; @@ -6477,7 +6493,7 @@ while (*s != 0) case EOP_RFC2047: { uschar buffer[2048]; - uschar *string = parse_quote_2047(sub, Ustrlen(sub), headers_charset, + const uschar *string = parse_quote_2047(sub, Ustrlen(sub), headers_charset, buffer, sizeof(buffer), FALSE); yield = string_cat(yield, &size, &ptr, string, Ustrlen(string)); continue; @@ -6607,7 +6623,7 @@ while (*s != 0) case EOP_ESCAPE: { - uschar *t = string_printing(sub); + const uschar *t = string_printing(sub); yield = string_cat(yield, &size, &ptr, t, Ustrlen(t)); continue; } @@ -6995,23 +7011,35 @@ return (Ustrpbrk(string, "$\\") == NULL)? string : +const uschar * +expand_cstring(const uschar *string) +{ +search_find_defer = FALSE; +malformed_header = FALSE; +return (Ustrpbrk(string, "$\\") == NULL)? string : + expand_string_internal(string, FALSE, NULL, FALSE, TRUE, NULL); +} + + + /************************************************* * Expand and copy * *************************************************/ /* Now and again we want to expand a string and be sure that the result is in a new bit of store. This function does that. +Since we know it has been copied, the de-const cast is safe. Argument: the string to be expanded Returns: the expanded string, always in a new bit of store, or NULL */ uschar * -expand_string_copy(uschar *string) +expand_string_copy(const uschar *string) { -uschar *yield = expand_string(string); +const uschar *yield = expand_cstring(string); if (yield == string) yield = string_copy(string); -return yield; +return US yield; } @@ -7058,7 +7086,7 @@ Returns: the integer value, or */ static int_eximarith_t -expanded_string_integer(uschar *s, BOOL isplus) +expanded_string_integer(const uschar *s, BOOL isplus) { int_eximarith_t value; uschar *msg = US"invalid integer \"%s\""; @@ -7137,6 +7165,67 @@ return -2; } +/* These values are usually fixed boolean values, but they are permitted to be +expanded strings. + +Arguments: + addr address being routed + mtype the module type + mname the module name + dbg_opt debug selectors + oname the option name + bvalue the router's boolean value + svalue the router's string value + rvalue where to put the returned value + +Returns: OK value placed in rvalue + DEFER expansion failed +*/ + +int +exp_bool(address_item *addr, + uschar *mtype, uschar *mname, unsigned dbg_opt, + uschar *oname, BOOL bvalue, + uschar *svalue, BOOL *rvalue) +{ +uschar *expanded; +if (svalue == NULL) { *rvalue = bvalue; return OK; } + +expanded = expand_string(svalue); +if (expanded == NULL) + { + if (expand_string_forcedfail) + { + DEBUG(dbg_opt) debug_printf("expansion of \"%s\" forced failure\n", oname); + *rvalue = bvalue; + return OK; + } + addr->message = string_sprintf("failed to expand \"%s\" in %s %s: %s", + oname, mname, mtype, expand_string_message); + DEBUG(dbg_opt) debug_printf("%s\n", addr->message); + return DEFER; + } + +DEBUG(dbg_opt) debug_printf("expansion of \"%s\" yields \"%s\"\n", oname, + expanded); + +if (strcmpic(expanded, US"true") == 0 || strcmpic(expanded, US"yes") == 0) + *rvalue = TRUE; +else if (strcmpic(expanded, US"false") == 0 || strcmpic(expanded, US"no") == 0) + *rvalue = FALSE; +else + { + addr->message = string_sprintf("\"%s\" is not a valid value for the " + "\"%s\" option in the %s %s", expanded, oname, mname, mtype); + return DEFER; + } + +return OK; +} + + + + /************************************************* ************************************************** * Stand-alone test program *