From 1a46a8c5c398c91f20c3f4def0ceb448ec8de96a Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Tue, 22 Mar 2005 14:11:54 +0000 Subject: 1. Added Tony F's ${dlfunc expansion, slightly modified (see NewStuff). 2. Recognize ${perl even if not compiled, and give suitable error message. --- src/ACKNOWLEDGMENTS | 23 ++++----- src/src/EDITME | 11 ++++- src/src/config.h.defaults | 5 +- src/src/exim.c | 5 +- src/src/exim.h | 8 +-- src/src/expand.c | 119 ++++++++++++++++++++++++++++++++++++++++++--- src/src/globals.c | 6 ++- src/src/globals.h | 6 ++- src/src/local_scan.h | 22 +++++++-- src/src/macros.h | 43 ++++++++-------- src/src/routers/redirect.c | 6 ++- 11 files changed, 200 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/ACKNOWLEDGMENTS b/src/ACKNOWLEDGMENTS index 8314c699a..0982973d2 100644 --- a/src/ACKNOWLEDGMENTS +++ b/src/ACKNOWLEDGMENTS @@ -1,4 +1,4 @@ -$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.15 2005/03/15 12:27:54 ph10 Exp $ +$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.16 2005/03/22 14:11:54 ph10 Exp $ EXIM ACKNOWLEDGEMENTS @@ -20,7 +20,7 @@ relatively small patches. Philip Hazel Lists created: 20 November 2002 -Last updated: 15 March 2005 +Last updated: 22 March 2005 THE OLD LIST @@ -78,7 +78,7 @@ Richard Birkett Fix for empty -f address crash Nick Burrett Patch for CONFIGURE_FILE_USE_EUID in exicyclog Matthew Byng-Maddick Patch for qualify_domain in redirect router Patch for ignore_target_hosts in ipliteral router - The cyrus_sasl authenticator + The cyrus_sasl authenticator Steve Campbell eximstats extensions and continued maintenance Brian Candler Use h_errno for gethostbyname() Suggested patch for .ifdef etc @@ -93,7 +93,7 @@ Andrew Doran Patch for NetBSD configuration files Patch for ifreq alignment and size problems Michael Deutschmann Suggested patch for treating bind() failure like connect() Patch for $sender_data and $recipient_data - Suggested patch for null address match lookup bug + Suggested patch for null address match lookup bug Oliver Eikemeier Patch to skip Received: if expansion is empty Patch for "eqi" Nico Erfurth Fix for bug in ${readfile} @@ -121,9 +121,10 @@ Tony Finch Expansion extensions A number of useful code criticisms Timezone patch for exiwhat Patch for more daemon exiwhat information - Patch for -dd - Patch for mxh lookup type in dnsdb - Patch for defer_foo in dndsb + Patch for -dd + Patch for mxh lookup type in dnsdb + Patch for defer_foo in dndsb + Patch for ${dlfunc Giuliano Gavazzi Patches for OSX compilation Dominic Germain Patch for exiqgrep MacOS X bug Oliver Gorwits $load_average patch @@ -138,7 +139,7 @@ Michael Haardt Tidies to make the code stricter Module to support Sieve (RFC 3028) filters and continued maintenance of same Patch for faster sort algorithm in queue.c - Patch for LDAP timeout handling + Patch for LDAP timeout handling Thomas Hager Patch for saslauthd crash bug Richard Hall Fix for file descriptor leak in redirection Steve Haslam Lots of stuff, including @@ -154,7 +155,7 @@ Christian Kellner Patch for LDAP dereferencing Alex Kiernan Patch for libradius Diagnosis of milliwait clock-backwards bug Tom Kistner SPA server code - Writing and maintaining the content scanning + Writing and maintaining the content scanning extension (exiscan) Friso Kuipers Patch for GDBM problem Chris Liddiard Fix for bug in exiqsumm @@ -174,9 +175,9 @@ Marc Merlin Many suggestions and patches for callouts and SMTP error message features Andreas Metzler Patch for message_id_header_domain Suggested patch for multi-config files in scripts bug -Alex Miller Suggested readline() patch +Alex Miller Suggested readline() patch Patch for LDAP_RES_SEARCH_REFERENCE handling - Support for the DrWeb content scanner + Support for the DrWeb content scanner Andreas Mueller Patch for logging uncompleted SMTP transactions Pete Naylor Patch for LDAP TCP connect timeout setting Marcin Owsiany Diagnosis of a tricky timeout failure bug diff --git a/src/src/EDITME b/src/src/EDITME index 60774cf49..72f797bb3 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -1,4 +1,4 @@ -# $Cambridge: exim/src/src/EDITME,v 1.8 2005/02/17 11:58:25 ph10 Exp $ +# $Cambridge: exim/src/src/EDITME,v 1.9 2005/03/22 14:11:54 ph10 Exp $ ################################################## # The Exim mail transport agent # @@ -689,6 +689,15 @@ ZCAT_COMMAND=/usr/bin/zcat # EXIM_PERL=perl.o +#------------------------------------------------------------------------------ +# Support for dynamically-loaded string expansion functions via ${dlfunc. If +# you are using gcc the dynamically-loaded object must be compiled with the +# -shared option, and you will need to add -export-dynamic to EXTRALIBS so +# that the local_scan API is made available by the linker. + +# EXPAND_DLFUNC=yes + + #------------------------------------------------------------------------------ # Exim has support for PAM (Pluggable Authentication Modules), a facility # which is available in the latest releases of Solaris and in some GNU/Linux diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index ea63c888f..2825f98c1 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/config.h.defaults,v 1.5 2005/03/08 15:32:02 tom Exp $ */ +/* $Cambridge: exim/src/src/config.h.defaults,v 1.6 2005/03/22 14:11:54 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -42,11 +42,10 @@ in config.h unless some value is defined in Local/Makefile. */ #define EXIMDB_LOCK_TIMEOUT 60 #define EXIMDB_LOCKFILE_MODE 0640 #define EXIMDB_MODE 0640 - #define EXIM_PERL - /* Both uid and gid are triggered by this */ #define EXIM_UID +#define EXPAND_DLFUNC #define FIXED_NEVER_USERS "root" diff --git a/src/src/exim.c b/src/src/exim.c index 14cd03228..ffe596d15 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/exim.c,v 1.16 2005/03/15 14:09:12 ph10 Exp $ */ +/* $Cambridge: exim/src/src/exim.c,v 1.17 2005/03/22 14:11:54 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -829,6 +829,9 @@ fprintf(f, "Support for:"); #ifdef EXIM_PERL fprintf(f, " Perl"); #endif +#ifdef EXPAND_DLFUNC + fprintf(f, " Expand_dlfunc"); +#endif #ifdef USE_TCP_WRAPPERS fprintf(f, " TCPwrappers"); #endif diff --git a/src/src/exim.h b/src/src/exim.h index 42f7980c2..b28edb79b 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/exim.h,v 1.9 2005/03/15 14:09:12 ph10 Exp $ */ +/* $Cambridge: exim/src/src/exim.h,v 1.10 2005/03/22 14:11:54 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -60,7 +60,7 @@ making unique names. */ /* Unix includes */ #include -#if defined(__svr4__) && defined(__sparc) && ! defined(__EXTENSIONS__) +#if defined(__svr4__) && defined(__sparc) && ! defined(__EXTENSIONS__) #define __EXTENSIONS__ /* so that SunOS 5 gets NGROUPS_MAX */ #include #undef __EXTENSIONS__ @@ -207,7 +207,7 @@ or a macro with entries f_frsize and f_bsize. */ #endif -#ifndef SIOCGIFCONF /* HACK for SunOS 5 */ +#ifndef SIOCGIFCONF /* HACK for SunOS 5 */ #include #endif @@ -414,7 +414,7 @@ requires various things that are set therein. */ #include #endif -#ifdef USE_READLINE +#if defined(USE_READLINE) || defined(EXPAND_DLFUNC) #include #endif diff --git a/src/src/expand.c b/src/src/expand.c index 6e7d3550f..d27530bd7 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/expand.c,v 1.16 2005/03/09 08:27:51 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 * @@ -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, @@ -3072,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; @@ -3847,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 diff --git a/src/src/globals.c b/src/src/globals.c index fdccc0b98..2324e4072 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/globals.c,v 1.19 2005/03/08 15:32:02 tom Exp $ */ +/* $Cambridge: exim/src/src/globals.c,v 1.20 2005/03/22 14:11:54 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -62,6 +62,10 @@ BOOL opt_perl_at_start = FALSE; BOOL opt_perl_started = FALSE; #endif +#ifdef EXPAND_DLFUNC +tree_node *dlobj_anchor = NULL; +#endif + #ifdef LOOKUP_IBASE uschar *ibase_servers = NULL; #endif diff --git a/src/src/globals.h b/src/src/globals.h index 2bb61c145..404838126 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/globals.h,v 1.12 2005/03/08 15:32:02 tom Exp $ */ +/* $Cambridge: exim/src/src/globals.h,v 1.13 2005/03/22 14:11:54 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -26,6 +26,10 @@ extern BOOL opt_perl_at_start; /* Start Perl interpreter at start */ extern BOOL opt_perl_started; /* Set once interpreter started */ #endif +#ifdef EXPAND_DLFUNC +extern tree_node *dlobj_anchor; /* Tree of dynamically-loaded objects */ +#endif + #ifdef LOOKUP_IBASE extern uschar *ibase_servers; #endif diff --git a/src/src/local_scan.h b/src/src/local_scan.h index e612ccd84..fdc73bed5 100644 --- a/src/src/local_scan.h +++ b/src/src/local_scan.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/local_scan.h,v 1.3 2005/01/04 10:00:42 ph10 Exp $ */ +/* $Cambridge: exim/src/src/local_scan.h,v 1.4 2005/03/22 14:11:54 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -9,7 +9,9 @@ /* This file is the header that is the only Exim header to be included in the source for the local_scan.c() function. It contains definitions that are made -available for use in that function, and which are documented. */ +available for use in that function, and which are documented. + +This API is also used for functions called by the ${dlfunc expansion item. */ /* Some basic types that make some things easier, and the store functions. */ @@ -34,13 +36,27 @@ enum { }; -/* Return codes from the support functions lss_match_xxx(). */ +/* Functions called by ${dlfunc{file}{func}{arg}...} return one of the five +status codes defined immediately below. The function's first argument is either +the result of expansion, or the error message in case of failure. The second +and third arguments are standard argument count and vector, comprising the +{arg} values specified in the expansion item. */ + +typedef int exim_dlfunc_t(uschar **yield, int argc, uschar *argv[]); + + +/* Return codes from the support functions lss_match_xxx(). These are also the +codes that dynamically-loaded ${dlfunc functions must return. */ #define OK 0 /* Successful match */ #define DEFER 1 /* Defer - some problem */ #define FAIL 2 /* Matching failed */ #define ERROR 3 /* Internal or config error */ +/* Extra return code for ${dlfunc functions */ + +#define FAIL_FORCED 4 /* "Forced" failure */ + /* Available logging destinations */ diff --git a/src/src/macros.h b/src/src/macros.h index d69da22f7..86bb84f12 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/macros.h,v 1.10 2005/03/10 08:56:03 tom Exp $ */ +/* $Cambridge: exim/src/src/macros.h,v 1.11 2005/03/22 14:11:54 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -237,27 +237,29 @@ enum { apply to all of them). Some other functions also use these convenient values, and some additional values are used only by non-driver functions. -OK, FAIL, DEFER, and ERROR are also declared in local_scan.h for use in the -local_scan() function. Do not change them unilaterally. */ +OK, FAIL, DEFER, ERROR, and FAIL_FORCED are also declared in local_scan.h for +use in the local_scan() function and in ${dlfunc loaded functions. Do not +change them unilaterally. */ #define OK 0 /* Successful match */ #define DEFER 1 /* Defer - some problem */ #define FAIL 2 /* Matching failed */ #define ERROR 3 /* Internal or config error */ +#define FAIL_FORCED 4 /* "Forced" failure */ /***********/ -#define DECLINE 4 /* Declined to handle the address, pass to next +#define DECLINE 5 /* Declined to handle the address, pass to next router unless no_more is set */ -#define PASS 5 /* Pass to next driver, or to pass_router, +#define PASS 6 /* Pass to next driver, or to pass_router, even if no_more is set */ -#define DISCARD 6 /* Address routed to :blackhole: or "seen finish" */ -#define SKIP 7 /* Skip this router (used in route_address only) */ -#define REROUTED 8 /* Address was changed and child created*/ -#define PANIC 9 /* Hard failed with internal error */ -#define BAD64 10 /* Bad base64 data (auth) */ -#define UNEXPECTED 11 /* Unexpected initial auth data */ -#define CANCELLED 12 /* Authentication cancelled */ -#define FAIL_SEND 13 /* send() failed in authenticator */ -#define FAIL_DROP 14 /* Fail and drop connection (used in ACL) */ +#define DISCARD 7 /* Address routed to :blackhole: or "seen finish" */ +#define SKIP 8 /* Skip this router (used in route_address only) */ +#define REROUTED 9 /* Address was changed and child created*/ +#define PANIC 10 /* Hard failed with internal error */ +#define BAD64 11 /* Bad base64 data (auth) */ +#define UNEXPECTED 12 /* Unexpected initial auth data */ +#define CANCELLED 13 /* Authentication cancelled */ +#define FAIL_SEND 14 /* send() failed in authenticator */ +#define FAIL_DROP 15 /* Fail and drop connection (used in ACL) */ /* Returns from the deliver_message() function */ @@ -489,15 +491,16 @@ router, which were chosen to represent the standard situation for users' #define RDO_READFILE 0x00001000 /* Forbid "readfile" in exp in filter */ #define RDO_READSOCK 0x00002000 /* Forbid "readsocket" in exp in filter */ #define RDO_RUN 0x00004000 /* Forbid "run" in expansion in filter */ -#define RDO_REALLOG 0x00008000 /* Really do log (not testing/verifying) */ -#define RDO_REWRITE 0x00010000 /* Rewrite generated addresses */ -#define RDO_EXIM_FILTER 0x00020000 /* Forbid Exim filters */ -#define RDO_SIEVE_FILTER 0x00040000 /* Forbid Sieve filters */ +#define RDO_DLFUNC 0x00008000 /* Forbid "dlfunc" in expansion in filter */ +#define RDO_REALLOG 0x00010000 /* Really do log (not testing/verifying) */ +#define RDO_REWRITE 0x00020000 /* Rewrite generated addresses */ +#define RDO_EXIM_FILTER 0x00040000 /* Forbid Exim filters */ +#define RDO_SIEVE_FILTER 0x00080000 /* Forbid Sieve filters */ /* This is the set that apply to expansions in filters */ #define RDO_FILTER_EXPANSIONS \ - (RDO_EXISTS|RDO_LOOKUP|RDO_PERL|RDO_READFILE|RDO_READSOCK|RDO_RUN) + (RDO_EXISTS|RDO_LOOKUP|RDO_PERL|RDO_READFILE|RDO_READSOCK|RDO_RUN|RDO_DLFUNC) /* As well as the RDO bits themselves, we need the bit numbers in order to access (most of) the individual bits as separate options. This could be @@ -505,7 +508,7 @@ automated, but I haven't bothered. Keep this list in step with the above! */ enum { RDON_BLACKHOLE, RDON_DEFER, RDON_EACCES, RDON_ENOTDIR, RDON_EXISTS, RDON_FAIL, RDON_FILTER, RDON_FREEZE, RDON_INCLUDE, RDON_LOG, RDON_LOOKUP, - RDON_PERL, RDON_READFILE, RDON_READSOCK, RDON_RUN, RDON_REALLOG, + RDON_PERL, RDON_READFILE, RDON_READSOCK, RDON_RUN, RDON_DLFUNC, RDON_REALLOG, RDON_REWRITE, RDON_EXIM_FILTER, RDON_SIEVE_FILTER }; /* Results of filter or forward file processing. Some are only from a filter; diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c index 461fc5d92..65b5e4099 100644 --- a/src/src/routers/redirect.c +++ b/src/src/routers/redirect.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/routers/redirect.c,v 1.6 2005/03/15 11:37:21 ph10 Exp $ */ +/* $Cambridge: exim/src/src/routers/redirect.c,v 1.7 2005/03/22 14:11:55 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -45,6 +45,10 @@ optionlist redirect_router_options[] = { (void *)offsetof(redirect_router_options_block, bit_options) }, { "forbid_file", opt_bool, (void *)offsetof(redirect_router_options_block, forbid_file) }, + #ifdef EXPAND_DLFUNC + { "forbid_filter_dlfunc", opt_bit | (RDON_DLFUNC << 16), + (void *)offsetof(redirect_router_options_block, bit_options) }, + #endif { "forbid_filter_existstest", opt_bit | (RDON_EXISTS << 16), (void *)offsetof(redirect_router_options_block, bit_options) }, { "forbid_filter_logwrite",opt_bit | (RDON_LOG << 16), -- cgit v1.2.3