X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/8523533c08c018ac4b750b0e0fab6cfe611e8a49..1a46a8c5c398c91f20c3f4def0ceb448ec8de96a:/src/src/expand.c diff --git a/src/src/expand.c b/src/src/expand.c index 79d1c1f3a..d27530bd7 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/expand.c,v 1.8 2004/12/16 15:11:47 tom 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. */ @@ -335,6 +336,19 @@ static var_entry var_table[] = { #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 }, @@ -346,11 +360,12 @@ static var_entry var_table[] = { { "exim_uid", vtype_uid, &exim_uid }, #ifdef WITH_OLD_DEMIME { "found_extension", vtype_stringptr, &found_extension }, -#endif +#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 }, @@ -368,7 +383,7 @@ 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 }, @@ -425,7 +440,7 @@ 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 @@ -449,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] }, @@ -475,7 +491,7 @@ static var_entry var_table[] = { #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 }, @@ -1236,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; @@ -1373,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; @@ -2233,7 +2294,7 @@ uschar *sub1, *sub2; /* 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 -"true" is substituted. In the fail case, nothing is substituted for all three +"true" is substituted. In the fail case, nothing is substituted for all three items. */ while (isspace(*s)) s++; @@ -2241,10 +2302,10 @@ if (*s == '}') { if (type[0] == 'i') { - if (yes) *yieldptr = string_cat(*yieldptr, sizeptr, ptrptr, US"true", 4); + 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)); @@ -3009,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; @@ -3784,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