X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/5cb8cbc6b514db2972dffadc30b3c7f2b7fc1dcb..1a46a8c5c398c91f20c3f4def0ceb448ec8de96a:/src/src/expand.c diff --git a/src/src/expand.c b/src/src/expand.c index 0ca5b4cc2..d27530bd7 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/expand.c,v 1.4 2004/11/17 14:32:25 ph10 Exp $ */ +/* $Cambridge: exim/src/src/expand.c,v 1.17 2005/03/22 14:11:54 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2004 */ +/* Copyright (c) University of Cambridge 1995 - 2005 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -48,6 +48,7 @@ static uschar *expand_string_internal(uschar *, BOOL, uschar **, BOOL); alphabetical order. */ static uschar *item_table[] = { + US"dlfunc", US"extract", US"hash", US"hmac", @@ -55,9 +56,7 @@ static uschar *item_table[] = { US"length", US"lookup", US"nhash", - #ifdef EXIM_PERL - US"perl", - #endif + US"perl", US"readfile", US"readsocket", US"run", @@ -66,6 +65,7 @@ static uschar *item_table[] = { US"tr" }; enum { + EITEM_DLFUNC, EITEM_EXTRACT, EITEM_HASH, EITEM_HMAC, @@ -73,9 +73,7 @@ enum { EITEM_LENGTH, EITEM_LOOKUP, EITEM_NHASH, - #ifdef EXIM_PERL - EITEM_PERL, - #endif + EITEM_PERL, EITEM_READFILE, EITEM_READSOCK, EITEM_RUN, @@ -285,7 +283,10 @@ enum { vtype_host_lookup, /* value not used; get host name */ 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 */ + 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 }; /* This table must be kept in alphabetical order. */ @@ -318,6 +319,12 @@ static var_entry var_table[] = { { "authenticated_id", vtype_stringptr, &authenticated_id }, { "authenticated_sender",vtype_stringptr, &authenticated_sender }, { "authentication_failed",vtype_int, &authentication_failed }, +#ifdef EXPERIMENTAL_BRIGHTMAIL + { "bmi_alt_location", vtype_stringptr, &bmi_alt_location }, + { "bmi_base64_tracker_verdict", vtype_stringptr, &bmi_base64_tracker_verdict }, + { "bmi_base64_verdict", vtype_stringptr, &bmi_base64_verdict }, + { "bmi_deliver", vtype_int, &bmi_deliver }, +#endif { "body_linecount", vtype_int, &body_linecount }, { "body_zerocount", vtype_int, &body_zerocount }, { "bounce_recipient", vtype_stringptr, &bounce_recipient }, @@ -326,6 +333,23 @@ static var_entry var_table[] = { { "caller_uid", vtype_uid, &real_uid }, { "compile_date", vtype_stringptr, &version_date }, { "compile_number", vtype_stringptr, &version_cnumber }, +#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 }, +#endif { "dnslist_domain", vtype_stringptr, &dnslist_domain }, { "dnslist_text", vtype_stringptr, &dnslist_text }, { "dnslist_value", vtype_stringptr, &dnslist_value }, @@ -334,10 +358,14 @@ static var_entry var_table[] = { { "exim_gid", vtype_gid, &exim_gid }, { "exim_path", vtype_stringptr, &exim_path }, { "exim_uid", vtype_uid, &exim_uid }, +#ifdef WITH_OLD_DEMIME + { "found_extension", vtype_stringptr, &found_extension }, +#endif { "home", vtype_stringptr, &deliver_home }, { "host", vtype_stringptr, &deliver_host }, { "host_address", vtype_stringptr, &deliver_host_address }, { "host_data", vtype_stringptr, &host_data }, + { "host_lookup_deferred",vtype_int, &host_lookup_deferred }, { "host_lookup_failed", vtype_int, &host_lookup_failed }, { "inode", vtype_ino, &deliver_inode }, { "interface_address", vtype_stringptr, &interface_address }, @@ -355,8 +383,11 @@ static var_entry var_table[] = { { "local_user_uid", vtype_uid, &local_user_uid }, { "localhost_number", vtype_int, &host_number }, { "log_inodes", vtype_pinodes, (void *)FALSE }, - { "log_space", vtype_pspace, (void *)FALSE }, + { "log_space", vtype_pspace, (void *)FALSE }, { "mailstore_basename", vtype_stringptr, &mailstore_basename }, +#ifdef WITH_CONTENT_SCAN + { "malware_name", vtype_stringptr, &malware_name }, +#endif { "message_age", vtype_int, &message_age }, { "message_body", vtype_msgbody, &message_body }, { "message_body_end", vtype_msgbody_end, &message_body_end }, @@ -364,6 +395,24 @@ static var_entry var_table[] = { { "message_headers", vtype_msgheaders, NULL }, { "message_id", vtype_stringptr, &message_id }, { "message_size", vtype_int, &message_size }, +#ifdef WITH_CONTENT_SCAN + { "mime_anomaly_level", vtype_int, &mime_anomaly_level }, + { "mime_anomaly_text", vtype_stringptr, &mime_anomaly_text }, + { "mime_boundary", vtype_stringptr, &mime_boundary }, + { "mime_charset", vtype_stringptr, &mime_charset }, + { "mime_content_description", vtype_stringptr, &mime_content_description }, + { "mime_content_disposition", vtype_stringptr, &mime_content_disposition }, + { "mime_content_id", vtype_stringptr, &mime_content_id }, + { "mime_content_size", vtype_int, &mime_content_size }, + { "mime_content_transfer_encoding",vtype_stringptr, &mime_content_transfer_encoding }, + { "mime_content_type", vtype_stringptr, &mime_content_type }, + { "mime_decoded_filename", vtype_stringptr, &mime_decoded_filename }, + { "mime_filename", vtype_stringptr, &mime_filename }, + { "mime_is_coverletter", vtype_int, &mime_is_coverletter }, + { "mime_is_multipart", vtype_int, &mime_is_multipart }, + { "mime_is_rfc822", vtype_int, &mime_is_rfc822 }, + { "mime_part_count", vtype_int, &mime_part_count }, +#endif { "n0", vtype_filter_int, &filter_n[0] }, { "n1", vtype_filter_int, &filter_n[1] }, { "n2", vtype_filter_int, &filter_n[2] }, @@ -391,9 +440,12 @@ static var_entry var_table[] = { { "received_for", vtype_stringptr, &received_for }, { "received_protocol", vtype_stringptr, &received_protocol }, { "recipient_data", vtype_stringptr, &recipient_data }, - { "recipient_verify_failure",vtype_stringptr,&recipient_verify_failure }, + { "recipient_verify_failure",vtype_stringptr,&recipient_verify_failure }, { "recipients", vtype_recipients, NULL }, { "recipients_count", vtype_int, &recipients_count }, +#ifdef WITH_CONTENT_SCAN + { "regex_match_string", vtype_stringptr, ®ex_match_string }, +#endif { "reply_address", vtype_reply, NULL }, { "return_path", vtype_stringptr, &return_path }, { "return_size_limit", vtype_int, &bounce_return_size_limit }, @@ -412,7 +464,8 @@ static var_entry var_table[] = { { "sender_host_port", vtype_int, &sender_host_port }, { "sender_ident", vtype_stringptr, &sender_ident }, { "sender_rcvhost", vtype_stringptr, &sender_rcvhost }, - { "sender_verify_failure",vtype_stringptr, &sender_verify_failure }, + { "sender_verify_failure",vtype_stringptr, &sender_verify_failure }, + { "smtp_active_hostname", vtype_stringptr, &smtp_active_hostname }, { "smtp_command_argument", vtype_stringptr, &smtp_command_argument }, { "sn0", vtype_filter_int, &filter_sn[0] }, { "sn1", vtype_filter_int, &filter_sn[1] }, @@ -424,9 +477,29 @@ static var_entry var_table[] = { { "sn7", vtype_filter_int, &filter_sn[7] }, { "sn8", vtype_filter_int, &filter_sn[8] }, { "sn9", vtype_filter_int, &filter_sn[9] }, +#ifdef WITH_CONTENT_SCAN + { "spam_bar", vtype_stringptr, &spam_bar }, + { "spam_report", vtype_stringptr, &spam_report }, + { "spam_score", vtype_stringptr, &spam_score }, + { "spam_score_int", vtype_stringptr, &spam_score_int }, +#endif +#ifdef EXPERIMENTAL_SPF + { "spf_header_comment", vtype_stringptr, &spf_header_comment }, + { "spf_received", vtype_stringptr, &spf_received }, + { "spf_result", vtype_stringptr, &spf_result }, + { "spf_smtp_comment", vtype_stringptr, &spf_smtp_comment }, +#endif { "spool_directory", vtype_stringptr, &spool_directory }, { "spool_inodes", vtype_pinodes, (void *)TRUE }, - { "spool_space", vtype_pspace, (void *)TRUE }, + { "spool_space", vtype_pspace, (void *)TRUE }, +#ifdef EXPERIMENTAL_SRS + { "srs_db_address", vtype_stringptr, &srs_db_address }, + { "srs_db_key", vtype_stringptr, &srs_db_key }, + { "srs_orig_recipient", vtype_stringptr, &srs_orig_recipient }, + { "srs_orig_sender", vtype_stringptr, &srs_orig_sender }, + { "srs_recipient", vtype_stringptr, &srs_recipient }, + { "srs_status", vtype_stringptr, &srs_status }, +#endif { "thisaddress", vtype_stringptr, &filter_thisaddress }, { "tls_certificate_verified", vtype_int, &tls_certificate_verified }, { "tls_cipher", vtype_stringptr, &tls_cipher }, @@ -1179,6 +1252,51 @@ while (last > first) if (!filter_running) return NULL; /* Fall through */ +#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 = "0"; break; + case DK_EXIM_ADDRESS_FROM_FROM: s = "from"; break; + case DK_EXIM_ADDRESS_FROM_SENDER: s = "sender"; break; + } + + if (Ustrcmp(var_table[middle].name, "dk_status") == 0) + switch(dk_verify_block->result) { + case DK_EXIM_RESULT_ERR: s = "error"; break; + case DK_EXIM_RESULT_BAD_FORMAT: s = "bad format"; break; + case DK_EXIM_RESULT_NO_KEY: s = "no key"; break; + case DK_EXIM_RESULT_NO_SIGNATURE: s = "no signature"; break; + case DK_EXIM_RESULT_REVOKED: s = "revoked"; break; + case DK_EXIM_RESULT_NON_PARTICIPANT: s = "non-participant"; break; + case DK_EXIM_RESULT_GOOD: s = "good"; break; + case DK_EXIM_RESULT_BAD: s = "bad"; break; + } + + if (Ustrcmp(var_table[middle].name, "dk_signsall") == 0) + s = (dk_verify_block->signsall)? "1" : "0"; + + if (Ustrcmp(var_table[middle].name, "dk_testing") == 0) + s = (dk_verify_block->testing)? "1" : "0"; + + if (Ustrcmp(var_table[middle].name, "dk_is_signed") == 0) + s = (dk_verify_block->is_signed)? "1" : "0"; + + return (s == NULL)? US"" : s; +#endif + case vtype_int: sprintf(CS var_buffer, "%d", *(int *)(var_table[middle].value)); /* Integer */ return var_buffer; @@ -1316,19 +1434,19 @@ while (last > first) s[ptr] = 0; /* string_cat() leaves room */ } return s; - + case vtype_pspace: { int inodes; - sprintf(CS var_buffer, "%d", - receive_statvfs((BOOL)(var_table[middle].value), &inodes)); + sprintf(CS var_buffer, "%d", + receive_statvfs(var_table[middle].value == (void *)TRUE, &inodes)); } return var_buffer; - + case vtype_pinodes: { int inodes; - (void) receive_statvfs((BOOL)(var_table[middle].value), &inodes); + (void) receive_statvfs(var_table[middle].value == (void *)TRUE, &inodes); sprintf(CS var_buffer, "%d", inodes); } return var_buffer; @@ -2175,17 +2293,24 @@ uschar *s = *sptr; /* Local value */ uschar *sub1, *sub2; /* If there are no following strings, we substitute the contents of $value for -lookups and for extractions in the success case. In the fail case, nothing is -substituted. In the case of "if", lack of following strings is an error. */ +lookups and for extractions in the success case. For the ${if item, the string +"true" is substituted. In the fail case, nothing is substituted for all three +items. */ while (isspace(*s)) s++; if (*s == '}') { - if (type[0] == 'i') goto FAILED_CURLY; - if (yes && lookup_value != NULL) - *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, lookup_value, - Ustrlen(lookup_value)); - lookup_value = save_lookup; + if (type[0] == 'i') + { + if (yes) *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, US"true", 4); + } + else + { + if (yes && lookup_value != NULL) + *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, lookup_value, + Ustrlen(lookup_value)); + lookup_value = save_lookup; + } s++; goto RETURN; } @@ -2945,10 +3070,15 @@ while (*s != 0) or ${perl{sub}{arg1}{arg2}} or up to a maximum of EXIM_PERL_MAX_ARGS arguments (defined below). */ - #ifdef EXIM_PERL #define EXIM_PERL_MAX_ARGS 8 case EITEM_PERL: + #ifndef EXIM_PERL + expand_string_message = US"\"${perl\" encountered, but this facility " + "is not included in this binary"; + goto EXPAND_FAILED; + + #else /* EXIM_PERL */ { uschar *sub_arg[EXIM_PERL_MAX_ARGS + 2]; uschar *new_yield; @@ -3720,6 +3850,106 @@ while (*s != 0) continue; } + + + /* If ${dlfunc support is configured, handle calling dynamically-loaded + functions, unless locked out at this time. Syntax is ${dlfunc{file}{func}} + or ${dlfunc{file}{func}{arg}} or ${dlfunc{file}{func}{arg1}{arg2}} or up to + a maximum of EXPAND_DLFUNC_MAX_ARGS arguments (defined below). */ + + #define EXPAND_DLFUNC_MAX_ARGS 8 + + case EITEM_DLFUNC: + #ifndef EXPAND_DLFUNC + expand_string_message = US"\"${dlfunc\" encountered, but this facility " + "is not included in this binary"; + goto EXPAND_FAILED; + + #else /* EXPAND_DLFUNC */ + { + tree_node *t; + exim_dlfunc_t *func; + uschar *result; + int status, argc; + uschar *argv[EXPAND_DLFUNC_MAX_ARGS + 3]; + + if ((expand_forbid & RDO_DLFUNC) != 0) + { + expand_string_message = + US"dynamically-loaded functions are not permitted"; + goto EXPAND_FAILED; + } + + switch(read_subs(argv, EXPAND_DLFUNC_MAX_ARGS + 2, 2, &s, skipping, + TRUE, US"dlfunc")) + { + case 1: goto EXPAND_FAILED_CURLY; + case 2: + case 3: goto EXPAND_FAILED; + } + + /* If skipping, we don't actually do anything */ + + if (skipping) continue; + + /* Look up the dynamically loaded object handle in the tree. If it isn't + found, dlopen() the file and put the handle in the tree for next time. */ + + t = tree_search(dlobj_anchor, argv[0]); + if (t == NULL) + { + void *handle = dlopen(CS argv[0], RTLD_LAZY); + if (handle == NULL) + { + expand_string_message = string_sprintf("dlopen \"%s\" failed: %s", + argv[0], dlerror()); + log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message); + goto EXPAND_FAILED; + } + t = store_get_perm(sizeof(tree_node) + Ustrlen(argv[0])); + Ustrcpy(t->name, argv[0]); + t->data.ptr = handle; + (void)tree_insertnode(&dlobj_anchor, t); + } + + /* Having obtained the dynamically loaded object handle, look up the + function pointer. */ + + func = (exim_dlfunc_t *)dlsym(t->data.ptr, CS argv[1]); + if (func == NULL) + { + expand_string_message = string_sprintf("dlsym \"%s\" in \"%s\" failed: " + "%s", argv[1], argv[0], dlerror()); + log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message); + goto EXPAND_FAILED; + } + + /* Call the function and work out what to do with the result. If it + 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. */ + + result = NULL; + for (argc = 0; argv[argc] != NULL; argc++); + status = func(&result, argc - 2, &argv[2]); + if(status == OK) + { + if (result == NULL) result = US""; + yield = string_cat(yield, &size, &ptr, result, Ustrlen(result)); + continue; + } + else + { + expand_string_message = result == NULL ? US"(no message)" : result; + if(status == FAIL_FORCED) expand_string_forcedfail = TRUE; + else if(status != FAIL) + log_write(0, LOG_MAIN|LOG_PANIC, "dlfunc{%s}{%s} failed (%d): %s", + argv[0], argv[1], status, expand_string_message); + goto EXPAND_FAILED; + } + } + #endif /* EXPAND_DLFUNC */ } /* Control reaches here if the name is not recognized as one of the more @@ -3951,7 +4181,7 @@ while (*s != 0) /* Convert to masked textual format and add to output. */ yield = string_cat(yield, &size, &ptr, buffer, - host_nmtoa(count, binary, mask, buffer)); + host_nmtoa(count, binary, mask, buffer, '.')); continue; } @@ -4083,7 +4313,7 @@ while (*s != 0) case EOP_RFC2047: { - uschar buffer[1024]; + uschar buffer[2048]; uschar *string = parse_quote_2047(sub, Ustrlen(sub), headers_charset, buffer, sizeof(buffer)); yield = string_cat(yield, &size, &ptr, string, Ustrlen(string));