#endif
extern void init_lookup_list(void);
+extern void init_misc_mod_list(void);
log_write(0, LOG_MAIN|LOG_PANIC, "backtrace");
log_write(0, LOG_MAIN|LOG_PANIC, "---");
+
+/* This function is officially not callable from a signal handler, as it
+calls malloc() for the returned data. However, it seems to work - and we
+know we're going on to crash anyway - so just hold our noses and do it.
+A alternative might be backtrace_symbols_fd(). */
+
if ((ss = backtrace_symbols(buf, nptrs)))
{
for (int i = 0; i < nptrs; i++)
#ifdef SA_SIGINFO
segv_handler(int sig, siginfo_t * info, void * uctx)
{
-log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (fault address: %p)", info->si_addr);
-# if defined(SEGV_MAPERR) && defined(SEGV_ACCERR) && defined(SEGV_BNDERR) && defined(SEGV_PKUERR)
-switch (info->si_code)
+if (!panic_coredump)
{
- case SEGV_MAPERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_MAPERR"); break;
- case SEGV_ACCERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_ACCERR"); break;
- case SEGV_BNDERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_BNDERR"); break;
- case SEGV_PKUERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_PKUERR"); break;
+ log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (fault address: %p)", info->si_addr);
+ # if defined(SEGV_MAPERR) && defined(SEGV_ACCERR) && defined(SEGV_BNDERR) && defined(SEGV_PKUERR)
+ switch (info->si_code)
+ {
+ case SEGV_MAPERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_MAPERR"); break;
+ case SEGV_ACCERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_ACCERR"); break;
+ case SEGV_BNDERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_BNDERR"); break;
+ case SEGV_PKUERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_PKUERR"); break;
+ }
+ # endif
}
-# endif
-if (US info->si_addr < US 4096)
+if (panic_coredump)
+ log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (deliberate trap)");
+else if (US info->si_addr < US 4096)
log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (null pointer indirection)");
else
log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (maybe attempt to write to immutable memory)");
if (fd < 0) return;
-(void)write(fd, process_info, process_info_len);
+if (write(fd, process_info, process_info_len) != 0) ;
(void)close(fd);
}
return item;
}
+/* as above, copying as tainted */
+static inline const uschar *
+exim_arg_copy(const uschar * item, int maxlen, const char * description)
+{
+return string_copy_taint(exim_str_fail_toolong(item, maxlen, description),
+ GET_TAINTED);
+}
+
/* exim_chown_failure() called from exim_chown()/exim_fchown() on failure
of chown()/fchown(). See src/functions.h for more explanation */
int
{
gstring * b = NULL, * d = NULL;
-#if defined(LOOKUP_LSEARCH)
+#ifdef LOOKUP_LSEARCH
# if LOOKUP_LSEARCH!=2
b = string_cat(b, US" lsearch wildlsearch nwildlsearch iplsearch");
# else
d = string_cat(d, US" lsearch wildlsearch nwildlsearch iplsearch");
# endif
#endif
-#if defined(LOOKUP_CDB)
+#ifdef LOOKUP_CDB
# if LOOKUP_CDB!=2
b = string_cat(b, US" cdb");
# else
d = string_cat(d, US" cdb");
# endif
#endif
-#if defined(LOOKUP_DBM)
+#ifdef LOOKUP_DBM
# if LOOKUP_DBM!=2
b = string_cat(b, US" dbm dbmjz dbmnz");
# else
d = string_cat(d, US" dbm dbmjz dbmnz");
# endif
#endif
-#if defined(LOOKUP_DNSDB)
+#ifdef LOOKUP_DNSDB
# if LOOKUP_DNSDB!=2
b = string_cat(b, US" dnsdb");
# else
d = string_cat(d, US" dnsdb");
# endif
#endif
-#if defined(LOOKUP_DSEARCH)
+#ifdef LOOKUP_DSEARCH
# if LOOKUP_DSEARCH!=2
b = string_cat(b, US" dsearch");
# else
d = string_cat(d, US" dsearch");
# endif
#endif
-#if defined(LOOKUP_IBASE)
+#ifdef LOOKUP_IBASE
# if LOOKUP_IBASE!=2
b = string_cat(b, US" ibase");
# else
d = string_cat(d, US" ibase");
# endif
#endif
-#if defined(LOOKUP_JSON)
+#ifdef LOOKUP_JSON
# if LOOKUP_JSON!=2
b = string_cat(b, US" json");
# else
d = string_cat(d, US" json");
# endif
#endif
-#if defined(LOOKUP_LDAP)
+#ifdef LOOKUP_LDAP
# if LOOKUP_LDAP!=2
b = string_cat(b, US" ldap ldapdn ldapm");
# else
# endif
#endif
#ifdef LOOKUP_LMDB
+# if LOOKUP_LMDB!=2
b = string_cat(b, US" lmdb");
+# else
+ d = string_cat(d, US" lmdb");
+# endif
#endif
-#if defined(LOOKUP_MYSQL)
+#ifdef LOOKUP_MYSQL
# if LOOKUP_MYSQL!=2
b = string_cat(b, US" mysql");
# else
d = string_cat(d, US" mysql");
# endif
#endif
-#if defined(LOOKUP_NIS)
+#ifdef LOOKUP_NIS
# if LOOKUP_NIS!=2
b = string_cat(b, US" nis nis0");
# else
d = string_cat(d, US" nis nis0");
# endif
#endif
-#if defined(LOOKUP_NISPLUS)
+#ifdef LOOKUP_NISPLUS
# if LOOKUP_NISPLUS!=2
b = string_cat(b, US" nisplus");
# else
d = string_cat(d, US" nisplus");
# endif
#endif
-#if defined(LOOKUP_ORACLE)
+#ifdef LOOKUP_ORACLE
# if LOOKUP_ORACLE!=2
b = string_cat(b, US" oracle");
# else
d = string_cat(d, US" oracle");
# endif
#endif
-#if defined(LOOKUP_PASSWD)
+#ifdef LOOKUP_PASSWD
# if LOOKUP_PASSWD!=2
b = string_cat(b, US" passwd");
# else
d = string_cat(d, US" passwd");
# endif
#endif
-#if defined(LOOKUP_PGSQL)
+#ifdef LOOKUP_PGSQL
# if LOOKUP_PGSQL!=2
b = string_cat(b, US" pgsql");
# else
d = string_cat(d, US" pgsql");
# endif
#endif
-#if defined(LOOKUP_REDIS)
+#ifdef LOOKUP_REDIS
# if LOOKUP_REDIS!=2
b = string_cat(b, US" redis");
# else
d = string_cat(d, US" redis");
# endif
#endif
-#if defined(LOOKUP_SQLITE)
+#ifdef SUPPORT_SPF
+# if SUPPORT_SPF!=2
+ b = string_cat(b, US" spf");
+# else
+ d = string_cat(d, US" spf");
+# endif
+#endif
+#ifdef LOOKUP_SQLITE
# if LOOKUP_SQLITE!=2
b = string_cat(b, US" sqlite");
# else
d = string_cat(d, US" sqlite");
# endif
#endif
-#if defined(LOOKUP_TESTDB)
+#ifdef LOOKUP_TESTDB
# if LOOKUP_TESTDB!=2
b = string_cat(b, US" testdb");
# else
d = string_cat(d, US" testdb");
# endif
#endif
-#if defined(LOOKUP_WHOSON)
+#ifdef LOOKUP_WHOSON
# if LOOKUP_WHOSON!=2
b = string_cat(b, US" whoson");
# else
}
+static void
+lookup_version_report_cb(uschar * name, uschar * ptr, void * ctx)
+{
+const lookup_info * li = (lookup_info *)ptr;
+gstring ** gp = ctx;
+
+if (li->version_report)
+ *gp = li->version_report(*gp);
+}
+
+
/* This function is called for -bV/--version and for -d to output the optional
features of the current Exim binary.
#ifdef WITH_CONTENT_SCAN
g = string_cat(g, US" Content_Scanning");
#endif
+#ifndef DISABLE_EXIM_FILTER
+ g = string_cat(g, US" Exim_filter");
+#endif
+#ifndef DISABLE_SIEVE_FILTER
+ g = string_cat(g, US" Sieve_filter");
+#endif
#ifdef SUPPORT_CRYPTEQ
g = string_cat(g, US" crypteq");
#endif
# ifdef __VERSION__
g = string_fmt_append(g, "Compiler: GCC [%s]\n", __VERSION__);
# else
- g = string_fmt_append(g, "Compiler: GCC [%s]\n", "? unknown version ?";
+ g = string_fmt_append(g, "Compiler: GCC [%s]\n", "? unknown version ?");
# endif
#else
g = string_cat(g, US"Compiler: <unknown>\n");
gnu_get_libc_version());
#endif
-g = show_db_version(g);
+ g = show_db_version(g);
#ifndef DISABLE_TLS
g = tls_version_report(g);
#ifdef SUPPORT_I18N
g = utf8_version_report(g);
#endif
-#ifdef SUPPORT_DMARC
- g = dmarc_version_report(g);
-#endif
-#ifdef SUPPORT_SPF
- g = spf_lib_version_report(g);
-#endif
-show_string(is_stdout, g);
-g = NULL;
+/*XXX do we need a "show misc-mods version-report" ?
+Currently they are output in misc_mod_add() */
+
+ show_string(is_stdout, g);
+ g = NULL;
-for (auth_info * ai= auths_available; *ai->drinfo.driver_name != '\0'; ai++)
- if (ai->version_report)
- g = (*ai->version_report)(g);
+ for (auth_info * ai = auths_available; ai; ai = (auth_info *)ai->drinfo.next)
+ if (ai->version_report)
+ g = (*ai->version_report)(g);
/* PCRE_PRERELEASE is either defined and empty or a bare sequence of
characters; unless it's an ancient version of PCRE in which case it
#endif
#define QUOTE(X) #X
#define EXPAND_AND_QUOTE(X) QUOTE(X)
- {
- uschar buf[24];
- pcre2_config(PCRE2_CONFIG_VERSION, buf);
- g = string_fmt_append(g, "Library version: PCRE2: Compile: %d.%d%s\n"
- " Runtime: %s\n",
- PCRE2_MAJOR, PCRE2_MINOR,
- EXPAND_AND_QUOTE(PCRE2_PRERELEASE) "",
- buf);
- }
+ {
+ uschar buf[24];
+ pcre2_config(PCRE2_CONFIG_VERSION, buf);
+ g = string_fmt_append(g, "Library version: PCRE2: Compile: %d.%d%s\n"
+ " Runtime: %s\n",
+ PCRE2_MAJOR, PCRE2_MINOR,
+ EXPAND_AND_QUOTE(PCRE2_PRERELEASE) "",
+ buf);
+ }
#undef QUOTE
#undef EXPAND_AND_QUOTE
-show_string(is_stdout, g);
-g = NULL;
+ show_string(is_stdout, g);
+ g = NULL;
-init_lookup_list();
-for (int i = 0; i < lookup_list_count; i++)
- if (lookup_list[i]->version_report)
- g = lookup_list[i]->version_report(g);
-show_string(is_stdout, g);
-g = NULL;
+ init_lookup_list();
+ tree_walk(lookups_tree, lookup_version_report_cb, &g);
+ show_string(is_stdout, g);
+ g = NULL;
+ init_misc_mod_list();
#ifdef WHITELIST_D_MACROS
g = string_fmt_append(g, "WHITELIST_D_MACROS: \"%s\"\n", WHITELIST_D_MACROS);
);
return;
case CMDINFO_SIEVE:
- for (const uschar ** pp = exim_sieve_extension_list; *pp; ++pp)
- fprintf(stream, "%s\n", *pp);
+ {
+ const misc_module_info * mi;
+ typedef void (*fn_t)(FILE *);
+ if ((mi = misc_mod_find(US"sieve_filter", NULL)))
+ (((fn_t *) mi->functions)[SIEVE_EXTENSIONS]) (stream);
+ else
+ fprintf(stream, "Sieve filtering not available\n");
+ }
return;
case CMDINFO_DSCP:
dscp_list_to_stream(stream);
(void) macros_expand(0, &len, &dummy_macexp);
+#ifdef LOOKUP_MODULE_DIR
+//mod_load_check(big_buffer);
+#endif
+
if (isupper(big_buffer[0]))
{
if (macro_read_assignment(big_buffer))
/* sendmail uses -Ac and -Am to control which .cf file is used;
we ignore them. */
case 'A':
- if (!*argrest) { badarg = TRUE; break; }
- else
- {
- BOOL ignore = FALSE;
- switch (*argrest)
- {
- case 'c':
- case 'm':
- if (*(argrest + 1) == '\0')
- ignore = TRUE;
- break;
- }
- if (!ignore) badarg = TRUE;
- }
- break;
+ if (!*argrest) { badarg = TRUE; break; }
+ else
+ {
+ BOOL ignore = FALSE;
+ switch (*argrest)
+ {
+ case 'c':
+ case 'm':
+ if (*(argrest + 1) == '\0')
+ ignore = TRUE;
+ break;
+ }
+ if (!ignore) badarg = TRUE;
+ }
+ break;
+
+ /* -atrn <host> <domains> */
+ case 'a':
+ if (Ustrcmp(argrest, "trn") == 0)
+ if (i+2 < argc)
+ {
+ atrn_mode = US"C"; /* Customer mode */
+
+ /* The host could at this point have a port attached */
+ atrn_host = exim_arg_copy(argv[++i], EXIM_DOMAINNAME_MAX, "-atrn");
+ atrn_domains = exim_arg_copy(argv[++i], EXIM_DOMAINNAME_MAX*4,
+ "-atrn");
+ i++;
+ }
+ else
+ exim_fail("exim: host and domainlist expected after %s\n", argv[i]);
+ else badarg = TRUE;
+ break;
/* -Btype is a sendmail option for 7bit/8bit setting. Exim is 8-bit clean
so has no need of it. */
case 'B':
- if (!*argrest) i++; /* Skip over the type */
- break;
+ if (!*argrest) i++; /* Skip over the type */
+ break;
case 'b':
/* -bw: inetd wait mode, accept a listening socket as stdin */
case 'w':
- f.inetd_wait_mode = TRUE;
+ f.inetd_wait_mode = f.daemon_listen = f.daemon_scion = TRUE;
f.background_daemon = FALSE;
- f.daemon_listen = f.daemon_scion = TRUE;
if (*argrest)
if ((inetd_wait_timeout = readconf_readtime(argrest, 0, FALSE)) <= 0)
exim_fail("exim: bad time value %s: abandoned\n", argv[i]);
if (usage_wanted) exim_usage(called_as);
/* Arguments have been processed. Check for incompatibilities. */
-if ( ( (smtp_input || extract_recipients || recipients_arg < argc)
+if ( (smtp_input || extract_recipients || recipients_arg < argc)
&& ( f.daemon_listen || qrunners || bi_option
|| test_retry_arg >= 0 || test_rewrite_arg >= 0
|| filter_test != FTEST_NONE
|| msg_action_arg > 0 && !one_msg_action
- ) )
- || ( msg_action_arg > 0
+ )
+ || msg_action_arg > 0
&& ( f.daemon_listen || is_multiple_qrun() || list_options
|| checking && msg_action != MSG_LOAD
|| bi_option || test_retry_arg >= 0 || test_rewrite_arg >= 0
- ) )
- || ( (f.daemon_listen || is_multiple_qrun())
+ )
+ || (f.daemon_listen || is_multiple_qrun())
&& ( sender_address || list_options || list_queue || checking
|| bi_option
- ) )
+ )
|| f.daemon_listen && is_onetime_qrun()
|| f.inetd_wait_mode && qrunners
- || ( list_options
+ || list_options
&& ( checking || smtp_input || extract_recipients
|| filter_test != FTEST_NONE || bi_option
- ) )
- || ( verify_address_mode
+ )
+ || verify_address_mode
&& ( f.address_test_mode || smtp_input || extract_recipients
|| filter_test != FTEST_NONE || bi_option
- ) )
- || ( f.address_test_mode
+ )
+ || f.address_test_mode
&& ( smtp_input || extract_recipients || filter_test != FTEST_NONE
|| bi_option
- ) )
- || ( smtp_input
+ )
+ || smtp_input
&& (sender_address || filter_test != FTEST_NONE || extract_recipients)
- )
|| deliver_selectstring && !qrunners
|| msg_action == MSG_LOAD && (!expansion_test || expansion_test_message)
+ || atrn_mode
+ && ( f.daemon_listen || expansion_test || filter_test != FTEST_NONE
+ || checking /* || bi_option || info_stdout || receiving_message
+ || malware_test_file || list_queue || list_config || list_options
+ || version_printed || msg_action_arg > 0 || qrunners
+ */
+ )
)
exim_fail("exim: incompatible command-line options or arguments\n");
This needs to happen before we read the main configuration. */
init_lookup_list();
+init_misc_mod_list();
/*XXX this excrescence could move to the testsuite standard config setup file */
#ifdef SUPPORT_I18N
opt_perl_at_start = (perl_start_option > 0);
if (opt_perl_at_start && opt_perl_startup != NULL)
{
- uschar *errstr;
+ uschar * errstr;
+ const misc_module_info * mi = misc_mod_find(US"perl", &errstr);
+ typedef uschar * (*fn_t)(uschar *);
+
+ if (!mi)
+ exim_fail("exim: error finding perl module: %s\n", errstr);
+
DEBUG(D_any) debug_printf("Starting Perl interpreter\n");
- if ((errstr = init_perl(opt_perl_startup)))
+
+ if ((errstr = (((fn_t *) mi->functions)[PERL_STARTUP]) (opt_perl_startup)))
exim_fail("exim: error in perl_startup code: %s\n", errstr);
opt_perl_started = TRUE;
}
if (Uchdir(spool_directory) != 0)
{
(void) directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE);
- (void) Uchdir(spool_directory);
+ if (Uchdir(spool_directory) < 0) ;
}
/* Handle calls with the -bi option. This is a sendmail option to rebuild *the*
if (real_uid == root_uid || real_uid == exim_uid || interface_port < 1024)
{
+ if (mua_wrapper) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Input from "
+ "inetd is not supported when mua_wrapper is set");
f.is_inetd = TRUE;
sender_host_address = host_ntoa(-1, (struct sockaddr *)(&inetd_sock),
NULL, &sender_host_port);
- if (mua_wrapper) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Input from "
- "inetd is not supported when mua_wrapper is set");
}
else
exim_fail(
#ifdef LOAD_AVG_NEEDS_ROOT
if ( receiving_message
- && (queue_only_load >= 0 || (f.is_inetd && smtp_load_reserve >= 0)))
+ && (queue_only_load >= 0 || f.is_inetd && smtp_load_reserve >= 0))
load_average = OS_GETLOADAVG();
#endif
#endif
daemon_go();
+ /*NOTREACHED*/
}
/* If the sender ident has not been set (by a trusted caller) set it to
/* Expand command line items */
if (recipients_arg < argc)
- while (recipients_arg < argc)
- expansion_test_line(exim_str_fail_toolong(argv[recipients_arg++], EXIM_EMAILADDR_MAX, "recipient"));
+ {
+ config_filename = US"-be args";
+ for (config_lineno = 1; recipients_arg < argc; config_lineno++)
+ expansion_test_line(exim_str_fail_toolong(argv[recipients_arg++],
+ EXIM_EMAILADDR_MAX, "-be arg"));
+ }
/* Read stdin */
void *dlhandle = set_readline(&fn_readline, &fn_addhist);
#endif
- while (s = get_stdinput(fn_readline, fn_addhist))
+ config_filename = US"-be stdin";
+ for (config_lineno = 1; s = get_stdinput(fn_readline, fn_addhist);
+ config_lineno++)
expansion_test_line(s);
#ifdef USE_READLINE
return_path = sender_address = NULL;
dnslist_domain = dnslist_matched = NULL;
-#ifndef DISABLE_DKIM
- dkim_cur_signer = NULL;
-#endif
acl_var_m = NULL;
deliver_localpart_orig = NULL;
deliver_domain_orig = NULL;
verification test or info dump.
In the former case, show the configuration file name. */
-if (recipients_arg >= argc && !extract_recipients && !smtp_input)
+if ( recipients_arg >= argc && !extract_recipients
+ && !smtp_input && !atrn_mode)
{
if (version_printed)
{
exim_usage(called_as);
}
+/*XXX somewhere around here. Maybe earlier, but no later. ATRN customer */
+if (atrn_mode)
+ atrn_handle_customer();
+
/* If mua_wrapper is set, Exim is being used to turn an MUA that submits on the
standard input into an MUA that submits to a smarthost over TCP/IP. We know
logging being sent down the socket and make an identd call to get the
sender_ident. */
-else if (f.is_inetd)
+else if (f.is_inetd && !atrn_mode)
{
(void)fclose(stderr);
exim_nullstd(); /* Re-open to /dev/null */
{
smtp_in = stdin;
smtp_out = stdout;
+
memset(sender_host_cache, 0, sizeof(sender_host_cache));
if (verify_check_host(&hosts_connection_nolog) == OK)
{
rmark reset_point = store_mark();
message_id[0] = 0;
- /* Handle the SMTP case; call smtp_setup_mst() to deal with the initial SMTP
+ /* Handle the SMTP case; call smtp_setup_msg() to deal with the initial SMTP
input and build the recipients list, before calling receive_msg() to read the
message proper. Whatever sender address is given in the SMTP transaction is
often ignored for local senders - we use the actual sender, which is normally