X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/93655c46a6d1c1931c50fe6e17fd711578d4f07e..da5dfc3ab22a3189116ea5c78927e9884529c0c0:/src/src/expand.c diff --git a/src/src/expand.c b/src/src/expand.c index abff94996..943ec76ec 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/expand.c,v 1.86 2007/06/14 14:18:19 ph10 Exp $ */ +/* $Cambridge: exim/src/src/expand.c,v 1.100 2009/08/31 21:14:50 tom Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -364,9 +364,9 @@ enum { vtype_load_avg, /* value not used; result is int from os_getloadavg */ vtype_pspace, /* partition space; value is T/F for spool/log */ vtype_pinodes /* partition inodes; value is T/F for spool/log */ -#ifdef EXPERIMENTAL_DOMAINKEYS - ,vtype_dk_verify /* Serve request out of DomainKeys verification structure */ -#endif + #ifndef DISABLE_DKIM + ,vtype_dkim /* Lookup of value in DKIM signature */ + #endif }; /* This table must be kept in alphabetical order. */ @@ -396,22 +396,34 @@ static var_entry var_table[] = { { "compile_date", vtype_stringptr, &version_date }, { "compile_number", vtype_stringptr, &version_cnumber }, { "csa_status", vtype_stringptr, &csa_status }, +#ifdef EXPERIMENTAL_DCC + { "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 -#ifdef EXPERIMENTAL_DOMAINKEYS - { "dk_domain", vtype_stringptr, &dk_signing_domain }, - { "dk_is_signed", vtype_dk_verify, NULL }, - { "dk_result", vtype_dk_verify, NULL }, - { "dk_selector", vtype_stringptr, &dk_signing_selector }, - { "dk_sender", vtype_dk_verify, NULL }, - { "dk_sender_domain", vtype_dk_verify, NULL }, - { "dk_sender_local_part",vtype_dk_verify, NULL }, - { "dk_sender_source", vtype_dk_verify, NULL }, - { "dk_signsall", vtype_dk_verify, NULL }, - { "dk_status", vtype_dk_verify, NULL }, - { "dk_testing", vtype_dk_verify, NULL }, +#ifndef DISABLE_DKIM + { "dkim_algo", vtype_dkim, (void *)DKIM_ALGO }, + { "dkim_bodylength", vtype_dkim, (void *)DKIM_BODYLENGTH }, + { "dkim_canon_body", vtype_dkim, (void *)DKIM_CANON_BODY }, + { "dkim_canon_headers", vtype_dkim, (void *)DKIM_CANON_HEADERS }, + { "dkim_copiedheaders", vtype_dkim, (void *)DKIM_COPIEDHEADERS }, + { "dkim_created", vtype_dkim, (void *)DKIM_CREATED }, + { "dkim_domain", vtype_stringptr, &dkim_signing_domain }, + { "dkim_expires", vtype_dkim, (void *)DKIM_EXPIRES }, + { "dkim_headernames", vtype_dkim, (void *)DKIM_HEADERNAMES }, + { "dkim_identity", vtype_dkim, (void *)DKIM_IDENTITY }, + { "dkim_key_granularity",vtype_dkim, (void *)DKIM_KEY_GRANULARITY }, + { "dkim_key_nosubdomains",vtype_dkim, (void *)DKIM_NOSUBDOMAINS }, + { "dkim_key_notes", vtype_dkim, (void *)DKIM_KEY_NOTES }, + { "dkim_key_srvtype", vtype_dkim, (void *)DKIM_KEY_SRVTYPE }, + { "dkim_key_testing", vtype_dkim, (void *)DKIM_KEY_TESTING }, + { "dkim_selector", vtype_stringptr, &dkim_signing_selector }, + { "dkim_signing_domains",vtype_stringptr, &dkim_signing_domains }, + { "dkim_verify_reason", vtype_dkim, (void *)DKIM_VERIFY_REASON }, + { "dkim_verify_status", vtype_dkim, (void *)DKIM_VERIFY_STATUS}, #endif { "dnslist_domain", vtype_stringptr, &dnslist_domain }, { "dnslist_matched", vtype_stringptr, &dnslist_matched }, @@ -453,6 +465,7 @@ static var_entry var_table[] = { #ifdef WITH_CONTENT_SCAN { "malware_name", vtype_stringptr, &malware_name }, #endif + { "max_received_linelength", vtype_int, &max_received_linelength }, { "message_age", vtype_int, &message_age }, { "message_body", vtype_msgbody, &message_body }, { "message_body_end", vtype_msgbody_end, &message_body_end }, @@ -548,6 +561,7 @@ static var_entry var_table[] = { { "smtp_command", vtype_stringptr, &smtp_cmd_buffer }, { "smtp_command_argument", vtype_stringptr, &smtp_cmd_argument }, { "smtp_count_at_connection_start", vtype_int, &smtp_accept_count }, + { "smtp_notquit_reason", vtype_stringptr, &smtp_notquit_reason }, { "sn0", vtype_filter_int, &filter_sn[0] }, { "sn1", vtype_filter_int, &filter_sn[1] }, { "sn2", vtype_filter_int, &filter_sn[2] }, @@ -565,6 +579,7 @@ static var_entry var_table[] = { { "spam_score_int", vtype_stringptr, &spam_score_int }, #endif #ifdef EXPERIMENTAL_SPF + { "spf_guess", vtype_stringptr, &spf_guess }, { "spf_header_comment", vtype_stringptr, &spf_header_comment }, { "spf_received", vtype_stringptr, &spf_received }, { "spf_result", vtype_stringptr, &spf_result }, @@ -1371,51 +1386,6 @@ while (last > first) switch (var_table[middle].type) { -#ifdef EXPERIMENTAL_DOMAINKEYS - - case vtype_dk_verify: - if (dk_verify_block == NULL) return US""; - s = NULL; - if (Ustrcmp(var_table[middle].name, "dk_result") == 0) - s = dk_verify_block->result_string; - if (Ustrcmp(var_table[middle].name, "dk_sender") == 0) - s = dk_verify_block->address; - if (Ustrcmp(var_table[middle].name, "dk_sender_domain") == 0) - s = dk_verify_block->domain; - if (Ustrcmp(var_table[middle].name, "dk_sender_local_part") == 0) - s = dk_verify_block->local_part; - - if (Ustrcmp(var_table[middle].name, "dk_sender_source") == 0) - switch(dk_verify_block->address_source) { - case DK_EXIM_ADDRESS_NONE: s = US"0"; break; - case DK_EXIM_ADDRESS_FROM_FROM: s = US"from"; break; - case DK_EXIM_ADDRESS_FROM_SENDER: s = US"sender"; break; - } - - if (Ustrcmp(var_table[middle].name, "dk_status") == 0) - switch(dk_verify_block->result) { - case DK_EXIM_RESULT_ERR: s = US"error"; break; - case DK_EXIM_RESULT_BAD_FORMAT: s = US"bad format"; break; - case DK_EXIM_RESULT_NO_KEY: s = US"no key"; break; - case DK_EXIM_RESULT_NO_SIGNATURE: s = US"no signature"; break; - case DK_EXIM_RESULT_REVOKED: s = US"revoked"; break; - case DK_EXIM_RESULT_NON_PARTICIPANT: s = US"non-participant"; break; - case DK_EXIM_RESULT_GOOD: s = US"good"; break; - case DK_EXIM_RESULT_BAD: s = US"bad"; break; - } - - if (Ustrcmp(var_table[middle].name, "dk_signsall") == 0) - s = (dk_verify_block->signsall)? US"1" : US"0"; - - if (Ustrcmp(var_table[middle].name, "dk_testing") == 0) - s = (dk_verify_block->testing)? US"1" : US"0"; - - if (Ustrcmp(var_table[middle].name, "dk_is_signed") == 0) - s = (dk_verify_block->is_signed)? US"1" : US"0"; - - return (s == NULL)? US"" : s; -#endif - case vtype_filter_int: if (!filter_running) return NULL; /* Fall through */ @@ -1445,7 +1415,7 @@ while (last > first) return var_buffer; case vtype_load_avg: - sprintf(CS var_buffer, "%d", os_getloadavg()); /* load_average */ + sprintf(CS var_buffer, "%d", OS_GETLOADAVG()); /* load_average */ return var_buffer; case vtype_host_lookup: /* Lookup if not done so */ @@ -1504,9 +1474,15 @@ while (last > first) if (len > 0) { body[len] = 0; - while (len > 0) + if (message_body_newlines) /* Separate loops for efficiency */ + { + while (len > 0) + { if (body[--len] == 0) body[len] = ' '; } + } + else { - if (body[--len] == '\n' || body[len] == 0) body[len] = ' '; + while (len > 0) + { if (body[--len] == '\n' || body[len] == 0) body[len] = ' '; } } } } @@ -1588,6 +1564,12 @@ while (last > first) sprintf(CS var_buffer, "%d", inodes); } return var_buffer; + + #ifndef DISABLE_DKIM + case vtype_dkim: + return dkim_exim_expand_query((int)(long)var_table[middle].value); + #endif + } } @@ -3119,6 +3101,12 @@ we reset the store before processing it; if the result is in fresh store, we use that without copying. This is helpful for expanding strings like $message_headers which can get very long. +There's a problem if a ${dlfunc item has side-effects that cause allocation, +since resetting the store at the end of the expansion will free store that was +allocated by the plugin code as well as the slop after the expanded string. So +we skip any resets if ${dlfunc has been used. This is an unfortunate +consequence of string expansion becoming too powerful. + Arguments: string the string to be expanded ket_ends true if expansion is to stop at } @@ -3144,6 +3132,7 @@ uschar *yield = store_get(size); uschar *s = string; uschar *save_expand_nstring[EXPAND_MAXN+1]; int save_expand_nlength[EXPAND_MAXN+1]; +BOOL resetok = TRUE; expand_string_forcedfail = FALSE; expand_string_message = US""; @@ -3216,7 +3205,7 @@ while (*s != 0) if (ptr == 0 && yield != NULL) { - store_reset(yield); + if (resetok) store_reset(yield); yield = NULL; size = 0; } @@ -3801,7 +3790,7 @@ while (*s != 0) Adjust "inow" accordingly. */ if ( (iexpire < 7) && (inow >= 993) ) inow = 0; - if (iexpire > inow) + if (iexpire >= inow) { prvscheck_result = US"1"; DEBUG(D_expand) debug_printf("prvscheck: success, $pvrs_result set to 1\n"); @@ -4635,7 +4624,7 @@ while (*s != 0) while (len > 0 && isspace(p[len-1])) len--; p[len] = 0; - if (*p == 0) + if (*p == 0 && !skipping) { expand_string_message = US"first argument of \"extract\" must " "not be empty"; @@ -4946,8 +4935,10 @@ while (*s != 0) returns OK, we have a replacement string; if it returns DEFER then expansion has failed in a non-forced manner; if it returns FAIL then failure was forced; if it returns ERROR or any other value there's a - problem, so panic slightly. */ + problem, so panic slightly. In any case, assume that the function has + side-effects on the store that must be preserved. */ + resetok = FALSE; result = NULL; for (argc = 0; argv[argc] != NULL; argc++); status = func(&result, argc - 2, &argv[2]); @@ -5685,7 +5676,7 @@ while (*s != 0) int newsize = 0; if (ptr == 0) { - store_reset(yield); + if (resetok) store_reset(yield); yield = NULL; size = 0; } @@ -5740,7 +5731,7 @@ if (left != NULL) *left = s; In many cases the final string will be the first one that was got and so there will be optimal store usage. */ -store_reset(yield + ptr + 1); +if (resetok) store_reset(yield + ptr + 1); DEBUG(D_expand) { debug_printf("expanding: %.*s\n result: %s\n", (int)(s - string), string, @@ -5848,6 +5839,23 @@ systems, so we set it zero ourselves. */ errno = 0; expand_string_message = NULL; /* Indicates no error */ + +/* Before Exim 4.64, strings consisting entirely of whitespace compared +equal to 0. Unfortunately, people actually relied upon that, so preserve +the behaviour explicitly. Stripping leading whitespace is a harmless +noop change since strtol skips it anyway (provided that there is a number +to find at all). */ +if (isspace(*s)) + { + while (isspace(*s)) ++s; + if (*s == '\0') + { + DEBUG(D_expand) + debug_printf("treating blank string as number 0\n"); + return 0; + } + } + value = strtol(CS s, CSS &endptr, 10); if (endptr == s)