# endif
#endif /*!STAND_ALONE*/
-#ifdef LOOKUP_LDAP
-# include "lookups/ldap.h"
-#endif
-
#ifdef SUPPORT_CRYPTEQ
# ifdef CRYPT_H
# include <crypt.h>
};
-/* Types of table entry */
-
-enum vtypes {
- vtype_int, /* value is address of int */
- vtype_filter_int, /* ditto, but recognized only when filtering */
- vtype_ino, /* value is address of ino_t (not always an int) */
- vtype_uid, /* value is address of uid_t (not always an int) */
- vtype_gid, /* value is address of gid_t (not always an int) */
- vtype_bool, /* value is address of bool */
- vtype_stringptr, /* value is address of pointer to string */
- vtype_msgbody, /* as stringptr, but read when first required */
- vtype_msgbody_end, /* ditto, the end of the message */
- vtype_msgheaders, /* the message's headers, processed */
- vtype_msgheaders_raw, /* the message's headers, unprocessed */
- vtype_localpart, /* extract local part from string */
- vtype_domain, /* extract domain from string */
- vtype_string_func, /* value is string returned by given function */
- vtype_todbsdin, /* value not used; generate BSD inbox tod */
- vtype_tode, /* value not used; generate tod in epoch format */
- vtype_todel, /* value not used; generate tod in epoch/usec format */
- vtype_todf, /* value not used; generate full tod */
- vtype_todl, /* value not used; generate log tod */
- vtype_todlf, /* value not used; generate log file datestamp tod */
- vtype_todzone, /* value not used; generate time zone only */
- vtype_todzulu, /* value not used; generate zulu tod */
- vtype_reply, /* value not used; get reply from headers */
- vtype_pid, /* value not used; result is pid */
- 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_cert /* SSL certificate */
-#ifndef DISABLE_DKIM
- ,vtype_dkim /* Lookup of value in DKIM signature */
-#endif
-};
-
-/* Type for main variable table */
-
-typedef struct {
- const char *name;
- enum vtypes type;
- void *value;
-} var_entry;
-
/* Type for entries pointing to address/length pairs. Not currently
in use. */
{ "address_file", vtype_stringptr, &address_file },
{ "address_pipe", vtype_stringptr, &address_pipe },
#ifdef EXPERIMENTAL_ARC
- { "arc_domains", vtype_string_func, (void *) &fn_arc_domains },
- { "arc_oldest_pass", vtype_int, &arc_oldest_pass },
- { "arc_state", vtype_stringptr, &arc_state },
- { "arc_state_reason", vtype_stringptr, &arc_state_reason },
+ { "arc_domains", vtype_module, US"arc" },
+ { "arc_oldest_pass", vtype_module, US"arc" },
+ { "arc_state", vtype_module, US"arc" },
+ { "arc_state_reason", vtype_module, US"arc" },
#endif
{ "authenticated_fail_id",vtype_stringptr, &authenticated_fail_id },
{ "authenticated_id", vtype_stringptr, &authenticated_id },
{ "dcc_result", vtype_stringptr, &dcc_result },
#endif
#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_cur_signer", vtype_stringptr, &dkim_cur_signer },
- { "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_length", vtype_int, &dkim_key_length },
- { "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_signers", vtype_stringptr, &dkim_signers },
- { "dkim_verify_reason", vtype_stringptr, &dkim_verify_reason },
- { "dkim_verify_status", vtype_stringptr, &dkim_verify_status },
+ { "dkim_algo", vtype_module, US"dkim" },
+ { "dkim_bodylength", vtype_module, US"dkim" },
+ { "dkim_canon_body", vtype_module, US"dkim" },
+ { "dkim_canon_headers", vtype_module, US"dkim" },
+ { "dkim_copiedheaders", vtype_module, US"dkim" },
+ { "dkim_created", vtype_module, US"dkim" },
+ { "dkim_cur_signer", vtype_module, US"dkim" },
+ { "dkim_domain", vtype_module, US"dkim" },
+ { "dkim_expires", vtype_module, US"dkim" },
+ { "dkim_headernames", vtype_module, US"dkim" },
+ { "dkim_identity", vtype_module, US"dkim" },
+ { "dkim_key_granularity",vtype_module, US"dkim" },
+ { "dkim_key_length", vtype_module, US"dkim" },
+ { "dkim_key_nosubdomains",vtype_module, US"dkim" },
+ { "dkim_key_notes", vtype_module, US"dkim" },
+ { "dkim_key_srvtype", vtype_module, US"dkim" },
+ { "dkim_key_testing", vtype_module, US"dkim" },
+ { "dkim_selector", vtype_module, US"dkim" },
+ { "dkim_signers", vtype_module, US"dkim" },
+ { "dkim_verify_reason", vtype_module, US"dkim" },
+ { "dkim_verify_signers", vtype_module, US"dkim" },
+ { "dkim_verify_status", vtype_module, US"dkim" },
#endif
#ifdef SUPPORT_DMARC
- { "dmarc_domain_policy", vtype_stringptr, &dmarc_domain_policy },
- { "dmarc_status", vtype_stringptr, &dmarc_status },
- { "dmarc_status_text", vtype_stringptr, &dmarc_status_text },
- { "dmarc_used_domain", vtype_stringptr, &dmarc_used_domain },
+ { "dmarc_alignment_dkim",vtype_module, US"dmarc" },
+ { "dmarc_alignment_spf", vtype_module, US"dmarc" },
+ { "dmarc_domain_policy", vtype_module, US"dmarc" },
+ { "dmarc_status", vtype_module, US"dmarc" },
+ { "dmarc_status_text", vtype_module, US"dmarc" },
+ { "dmarc_used_domain", vtype_module, US"dmarc" },
#endif
{ "dnslist_domain", vtype_stringptr, &dnslist_domain },
{ "dnslist_matched", vtype_stringptr, &dnslist_matched },
{ "spam_score_int", vtype_stringptr, &spam_score_int },
#endif
#ifdef SUPPORT_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 },
- { "spf_result_guessed", vtype_bool, &spf_result_guessed },
- { "spf_smtp_comment", vtype_stringptr, &spf_smtp_comment },
+ { "spf_guess", vtype_module, US"spf" },
+ { "spf_header_comment", vtype_module, US"spf" },
+ { "spf_received", vtype_module, US"spf" },
+ { "spf_result", vtype_module, US"spf" },
+ { "spf_result_guessed", vtype_module, US"spf" },
+ { "spf_smtp_comment", vtype_module, US"spf" },
#endif
{ "spool_directory", vtype_stringptr, &spool_directory },
{ "spool_inodes", vtype_pinodes, (void *)TRUE },
*/
BOOL
-expand_check_condition(uschar *condition, uschar *m1, uschar *m2)
+expand_check_condition(const uschar * condition,
+ const uschar * m1, const uschar * m2)
{
-uschar * ss = expand_string(condition);
+const uschar * ss = expand_cstring(condition);
if (!ss)
{
if (!f.expand_string_forcedfail && !f.search_find_defer)
static var_entry *
-find_var_ent(uschar * name)
+find_var_ent(uschar * name, var_entry * table, unsigned nent)
{
int first = 0;
-int last = nelem(var_table);
+int last = nent;
while (last > first)
{
int middle = (first + last)/2;
- int c = Ustrcmp(name, var_table[middle].name);
+ int c = Ustrcmp(name, table[middle].name);
if (c > 0) { first = middle + 1; continue; }
if (c < 0) { last = middle; continue; }
- return &var_table[middle];
+ return &table[middle];
}
return NULL;
}
{
var_entry * vp;
-if (!(vp = find_var_ent(certvar)))
+if (!(vp = find_var_ent(certvar, var_table, nelem(var_table))))
{
expand_string_message =
string_sprintf("no variable named \"%s\"", certvar);
find_variable(uschar * name, esi_flags flags, int * newsize)
{
var_entry * vp;
-uschar *s, *domain;
-uschar **ss;
+uschar * s, * domain;
+uschar ** ss;
void * val;
+var_entry * table = var_table;
+unsigned table_count = nelem(var_table);
/* Handle ACL variables, whose names are of the form acl_cxxx or acl_mxxx.
Originally, xxx had to be a number in the range 0-9 (later 0-19), but from
}
#endif
+sublist:
+
/* For all other variables, search the table */
-if (!(vp = find_var_ent(name)))
+if (!(vp = find_var_ent(name, table, table_count)))
return NULL; /* Unknown variable name */
/* Found an existing variable. If in skipping state, the value isn't needed,
#ifndef DISABLE_DKIM
case vtype_dkim:
- return dkim_exim_expand_query((int)(long)val);
+ {
+ misc_module_info * mi = misc_mod_findonly(US"dkim");
+ typedef uschar * (*fn_t)(int);
+ return mi
+ ? (((fn_t *) mi->functions)[DKIM_EXPAND_QUERY]) ((int)(long)val)
+ : US"";
+ }
#endif
+ case vtype_module:
+ {
+ uschar * errstr;
+ misc_module_info * mi = misc_mod_find(val, &errstr);
+ if (mi)
+ {
+ table = mi->variables;
+ table_count = mi->variables_count;
+ goto sublist;
+ }
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "failed to find %s module for %s: %s", US val, name, errstr);
+ return US"";
+ }
}
return NULL; /* Unknown variable. Silences static checkers. */
modify_variable(uschar *name, void * value)
{
var_entry * vp;
-if ((vp = find_var_ent(name))) vp->value = value;
+if ((vp = find_var_ent(name, var_table, nelem(var_table))))
+ vp->value = value;
return; /* Unknown variable name, fail silently */
}
/* Various authentication tests - all optionally compiled */
case ECOND_PAM:
- #ifdef SUPPORT_PAM
- rc = auth_call_pam(sub[0], &expand_string_message);
- goto END_AUTH;
- #else
- goto COND_FAILED_NOT_COMPILED;
- #endif /* SUPPORT_PAM */
+#ifdef SUPPORT_PAM
+ {
+ const misc_module_info * mi = misc_mod_find(US"pam", NULL);
+ typedef int (*fn_t)(const uschar *, uschar **);
+ if (!mi)
+ goto COND_FAILED_NOT_COMPILED;
+ rc = (((fn_t *) mi->functions)[PAM_AUTH_CALL])
+ (sub[0], &expand_string_message);
+ goto END_AUTH;
+ }
+#else
+ goto COND_FAILED_NOT_COMPILED;
+#endif /* SUPPORT_PAM */
case ECOND_RADIUS:
- #ifdef RADIUS_CONFIG_FILE
- rc = auth_call_radius(sub[0], &expand_string_message);
- goto END_AUTH;
- #else
- goto COND_FAILED_NOT_COMPILED;
- #endif /* RADIUS_CONFIG_FILE */
+#ifdef RADIUS_CONFIG_FILE
+ {
+ const misc_module_info * mi = misc_mod_find(US"radius", NULL);
+ typedef int (*fn_t)(const uschar *, uschar **);
+ if (!mi)
+ goto COND_FAILED_NOT_COMPILED;
+ rc = (((fn_t *) mi->functions)[RADIUS_AUTH_CALL])
+ (sub[0], &expand_string_message);
+ goto END_AUTH;
+ }
+#else
+ goto COND_FAILED_NOT_COMPILED;
+#endif /* RADIUS_CONFIG_FILE */
case ECOND_LDAPAUTH:
#ifdef LOOKUP_LDAP
{
- /* Just to keep the interface the same */
- BOOL do_cache;
- int old_pool = store_pool;
- store_pool = POOL_SEARCH;
- rc = eldapauth_find((void *)(-1), NULL, sub[0], Ustrlen(sub[0]), NULL,
- &expand_string_message, &do_cache);
- store_pool = old_pool;
+ int expand_setup = -1;
+ const lookup_info * li = search_findtype(US"ldapauth", 8);
+ void * handle;
+
+ if (li && (handle = search_open(NULL, li, 0, NULL, NULL)))
+ rc = search_find(handle, NULL, sub[0],
+ -1, NULL, 0, 0, &expand_setup, NULL)
+ ? OK : f.search_find_defer ? DEFER : FAIL;
+ else
+ { expand_string_message = search_error_message; rc = FAIL; }
}
goto END_AUTH;
#else
yield = authres_local(yield, sub_arg[0]);
yield = authres_iprev(yield);
yield = authres_smtpauth(yield);
-#ifdef SUPPORT_SPF
- yield = authres_spf(yield);
-#endif
-#ifndef DISABLE_DKIM
- yield = authres_dkim(yield);
-#endif
-#ifdef SUPPORT_DMARC
- yield = authres_dmarc(yield);
-#endif
-#ifdef EXPERIMENTAL_ARC
- yield = authres_arc(yield);
-#endif
+ yield = misc_mod_authres(yield);
break;
}
case EITEM_LOOKUP:
{
- int stype, partial, affixlen, starflags;
- int expand_setup = 0;
- int nameptr = 0;
+ int expand_setup = 0, nameptr = 0;
+ int partial, affixlen, starflags;
+ const lookup_info * li;
uschar * key, * filename;
const uschar * affix, * opts;
uschar * save_lookup_value = lookup_value;
/* Now check for the individual search type and any partial or default
options. Only those types that are actually in the binary are valid. */
- if ((stype = search_findtype_partial(name, &partial, &affix, &affixlen,
- &starflags, &opts)) < 0)
+ if (!(li = search_findtype_partial(name, &partial, &affix, &affixlen,
+ &starflags, &opts)))
{
expand_string_message = search_error_message;
goto EXPAND_FAILED;
/* Check that a key was provided for those lookup types that need it,
and was not supplied for those that use the query style. */
- if (!mac_islookup(stype, lookup_querystyle|lookup_absfilequery))
+ if (!mac_islookup(li, lookup_querystyle|lookup_absfilequery))
{
if (!key)
{
file types, the query (i.e. "key") starts with a file name. */
if (!key)
- key = search_args(stype, name, filename, &filename, opts);
+ key = search_args(li, name, filename, &filename, opts);
/* If skipping, don't do the next bit - just lookup_value == NULL, as if
the entry was not found. Note that there is no search_close() function.
lookup_value = NULL;
else
{
- void * handle = search_open(filename, stype, 0, NULL, NULL);
+ void * handle = search_open(filename, li, 0, NULL, NULL);
if (!handle)
{
expand_string_message = search_error_message;
restore_expand_strings(save_expand_nmax, save_expand_nstring,
save_expand_nlength);
- if (flags & ESI_SKIPPING) continue;
- break;
+ if (flags & ESI_SKIPPING) continue; else break;
}
/* If Perl support is configured, handle calling embedded perl subroutines,
{
uschar * sub_arg[EXIM_PERL_MAX_ARGS + 2];
gstring * new_yield;
+ const misc_module_info * mi;
+ uschar * errstr;
if (expand_forbid & RDO_PERL)
{
goto EXPAND_FAILED;
}
+ if (!(mi = misc_mod_find(US"perl", &errstr)))
+ {
+ expand_string_message =
+ string_sprintf("failed to locate perl module: %s", errstr);
+ goto EXPAND_FAILED;
+ }
+
switch(read_subs(sub_arg, EXIM_PERL_MAX_ARGS + 1, 1, &s, flags, TRUE,
name, &resetok, NULL))
{
if (!opt_perl_started)
{
uschar * initerror;
+ typedef uschar * (*fn_t)(uschar *);
+
if (!opt_perl_startup)
{
expand_string_message = US"A setting of perl_startup is needed when "
goto EXPAND_FAILED;
}
DEBUG(D_any) debug_printf("Starting Perl interpreter\n");
- if ((initerror = init_perl(opt_perl_startup)))
+ initerror = (((fn_t *) mi->functions)[PERL_STARTUP]) (opt_perl_startup);
+ if (initerror)
{
expand_string_message =
string_sprintf("error in perl_startup code: %s\n", initerror);
/* Call the function */
sub_arg[EXIM_PERL_MAX_ARGS + 1] = NULL;
- new_yield = call_perl_cat(yield, &expand_string_message,
- sub_arg[0], sub_arg + 1);
+ {
+ typedef gstring * (*fn_t)(gstring *, uschar **, uschar *, uschar **);
+ new_yield = (((fn_t *) mi->functions)[PERL_CAT])
+ (yield, &expand_string_message,
+ sub_arg[0], sub_arg + 1);
+ }
/* NULL yield indicates failure; if the message pointer has been set to
NULL, the yield was undef, indicating a forced failure. Otherwise the
FILE * f;
uschar * sub_arg[2];
- if ((expand_forbid & RDO_READFILE) != 0)
+ if (expand_forbid & RDO_READFILE)
{
expand_string_message = US"file insertions are not permitted";
goto EXPAND_FAILED;
if (!(flags & ESI_SKIPPING))
{
- int stype = search_findtype(US"readsock", 8);
+ const lookup_info * li = search_findtype(US"readsock", 8);
gstring * g = NULL;
void * handle;
int expand_setup = -1;
uschar * s;
+ if (!li)
+ {
+ expand_string_message = search_error_message;
+ goto EXPAND_FAILED;
+ }
+
/* If the reqstr is empty, flag that and set a dummy */
if (!sub_arg[1][0])
/* First option has no tag and is timeout */
if ((item = string_nextinlist(&list, &sep, NULL, 0)))
- g = string_append_listele(g, ',',
- string_sprintf("timeout=%s", item));
+ g = string_append_listele_fmt(g, ',', TRUE, "timeout=%s", item);
/* The rest of the options from the expansion */
while ((item = string_nextinlist(&list, &sep, NULL, 0)))
options is the readsock expansion. */
if (sub_arg[3] && *sub_arg[3])
- g = string_append_listele(g, ',',
- string_sprintf("eol=%s",
- string_printing2(sub_arg[3], SP_TAB|SP_SPACE)));
+ g = string_append_listele_fmt(g, ',', TRUE,
+ "eol=%s", string_printing2(sub_arg[3], SP_TAB|SP_SPACE));
}
/* Gat a (possibly cached) handle for the connection */
- if (!(handle = search_open(sub_arg[0], stype, 0, NULL, NULL)))
+ if (!(handle = search_open(sub_arg[0], li, 0, NULL, NULL)))
{
if (*expand_string_message) goto EXPAND_FAILED;
expand_string_message = search_error_message;
expand_string_message = US"missing '}' closing readsocket";
goto EXPAND_FAILED_CURLY;
}
- if (flags & ESI_SKIPPING) continue;
- break;
+ if (flags & ESI_SKIPPING) continue; else break;
/* Come here on failure to create socket, connect socket, write to the
socket, or timeout on reading. If another substring follows, expand and
case 2: goto EXPAND_FAILED_CURLY; /* returned value is 0 */
}
- if (flags & ESI_SKIPPING) continue;
- break;
+ if (flags & ESI_SKIPPING) continue; else break;
}
/* Handle character translation for "tr" */
restore_expand_strings(save_expand_nmax, save_expand_nstring,
save_expand_nlength);
- if (flags & ESI_SKIPPING) continue;
- break;
+ if (flags & ESI_SKIPPING) continue; else break;
}
/* return the Nth item from a list */
restore_expand_strings(save_expand_nmax, save_expand_nstring,
save_expand_nlength);
- if (flags & ESI_SKIPPING) continue;
- break;
+ if (flags & ESI_SKIPPING) continue; else break;
}
case EITEM_LISTQUOTE:
restore_expand_strings(save_expand_nmax, save_expand_nstring,
save_expand_nlength);
- if (flags & ESI_SKIPPING) continue;
- break;
+ if (flags & ESI_SKIPPING) continue; else break;
}
#endif /*DISABLE_TLS*/
/* Restore preserved $item */
iterate_item = save_iterate_item;
- if (flags & ESI_SKIPPING) continue;
- break;
+ if (flags & ESI_SKIPPING) continue; else break;
}
case EITEM_SORT:
case 1: goto EXPAND_FAILED; /* when all is well, the */
case 2: goto EXPAND_FAILED_CURLY; /* returned value is 0 */
}
- if (flags & ESI_SKIPPING) continue;
- break;
+ if (flags & ESI_SKIPPING) continue; else break;
}
#ifdef SUPPORT_SRS
string_sprintf("missing '}' closing cert arg of %s", name);
goto EXPAND_FAILED_CURLY;
}
- if ((vp = find_var_ent(sub)) && vp->type == vtype_cert)
+ if ( (vp = find_var_ent(sub, var_table, nelem(var_table)))
+ && vp->type == vtype_cert)
{
s = s1+1;
break;
else
{
- int n;
+ const lookup_info * li;
uschar * opt = Ustrchr(arg, '_');
if (opt) *opt++ = 0;
- if ((n = search_findtype(arg, Ustrlen(arg))) < 0)
+ if (!(li = search_findtype(arg, Ustrlen(arg))))
{
expand_string_message = search_error_message;
goto EXPAND_FAILED;
}
- if (lookup_list[n]->quote)
- sub = (lookup_list[n]->quote)(sub, opt, (unsigned)n);
+ if (li->quote)
+ sub = (li->quote)(sub, opt, li->acq_num);
else if (opt)
sub = NULL;
int
exp_bool(address_item * addr,
- uschar * mtype, uschar * mname, unsigned dbg_opt,
+ const uschar * mtype, const uschar * mname, unsigned dbg_opt,
uschar * oname, BOOL bvalue,
- uschar * svalue, BOOL * rvalue)
+ const uschar * svalue, BOOL * rvalue)
{
-uschar * expanded;
+const uschar * expanded;
DEBUG(D_expand) debug_printf("try option %s\n", oname);
if (!svalue) { *rvalue = bvalue; return OK; }
-if (!(expanded = expand_string(svalue)))
+if (!(expanded = expand_cstring(svalue)))
{
if (f.expand_string_forcedfail)
{
if ((fd = exim_open2(CS filename, O_RDONLY)) < 0)
{
- log_write(0, LOG_MAIN | LOG_PANIC, "unable to open file for reading: %s",
- filename);
+ log_write(0, LOG_MAIN | LOG_PANIC, "unable to open file '%s' for reading: %s",
+ filename, strerror(errno));
return NULL;
}
uschar *errstr;
printf("Starting Perl interpreter\n");
errstr = init_perl(opt_perl_startup);
- if (errstr != NULL)
+ if (errstr)
{
printf("** error in perl_startup code: %s\n", errstr);
return EXIT_FAILURE;