X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Fexim.c;h=474851c21ec9a7b577aa21256d62617ed8d35625;hp=af01d40d468fef80f9d7718d0a401db8cfe2a6c0;hb=1a6230a33e235e2b008caabd112f8bc6cb1bcc60;hpb=6475bd82de30cfbb2b0897a05d1200674aa88f4f diff --git a/src/src/exim.c b/src/src/exim.c index af01d40d4..474851c21 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2012 */ +/* Copyright (c) University of Cambridge 1995 - 2016 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -12,6 +12,17 @@ Also a few functions that don't naturally fit elsewhere. */ #include "exim.h" +#ifdef __GLIBC__ +# include +#endif + +#ifdef USE_GNUTLS +# include +# if GNUTLS_VERSION_NUMBER < 0x030103 && !defined(DISABLE_OCSP) +# define DISABLE_OCSP +# endif +#endif + extern void init_lookup_list(void); @@ -52,6 +63,16 @@ store_free(block); +/************************************************* +* Enums for cmdline interface * +*************************************************/ + +enum commandline_info { CMDINFO_NONE=0, + CMDINFO_HELP, CMDINFO_SIEVE, CMDINFO_DSCP }; + + + + /************************************************* * Compile regular expression and panic on fail * *************************************************/ @@ -71,7 +92,7 @@ Returns: pointer to the compiled pattern */ const pcre * -regex_must_compile(uschar *pattern, BOOL caseless, BOOL use_malloc) +regex_must_compile(const uschar *pattern, BOOL caseless, BOOL use_malloc) { int offset; int options = PCRE_COPT; @@ -83,7 +104,7 @@ if (use_malloc) pcre_free = function_store_free; } if (caseless) options |= PCRE_CASELESS; -yield = pcre_compile(CS pattern, options, (const char **)&error, &offset, NULL); +yield = pcre_compile(CCS pattern, options, (const char **)&error, &offset, NULL); pcre_malloc = function_store_get; pcre_free = function_dummy_free; if (yield == NULL) @@ -114,10 +135,11 @@ Returns: TRUE or FALSE */ BOOL -regex_match_and_setup(const pcre *re, uschar *subject, int options, int setup) +regex_match_and_setup(const pcre *re, const uschar *subject, int options, int setup) { int ovector[3*(EXPAND_MAXN+1)]; -int n = pcre_exec(re, NULL, CS subject, Ustrlen(subject), 0, +uschar * s = string_copy(subject); /* de-constifying */ +int n = pcre_exec(re, NULL, CS s, Ustrlen(s), 0, PCRE_EOPT | options, ovector, sizeof(ovector)/sizeof(int)); BOOL yield = n >= 0; if (n == 0) n = EXPAND_MAXN + 1; @@ -127,7 +149,7 @@ if (yield) expand_nmax = (setup < 0)? 0 : setup + 1; for (nn = (setup < 0)? 0 : 2; nn < n*2; nn += 2) { - expand_nstring[expand_nmax] = subject + ovector[nn]; + expand_nstring[expand_nmax] = s + ovector[nn]; expand_nlength[expand_nmax++] = ovector[nn+1] - ovector[nn]; } expand_nmax--; @@ -257,6 +279,10 @@ will wait for ever, so we panic in this instance. (There was a case of this when a bug in a function that calls milliwait() caused it to pass invalid data. That's when I added the check. :-) +We assume it to be not worth sleeping for under 100us; this value will +require revisiting as hardware advances. This avoids the issue of +a zero-valued timer setting meaning "never fire". + Argument: an itimerval structure containing the interval Returns: nothing */ @@ -266,6 +292,9 @@ milliwait(struct itimerval *itval) { sigset_t sigmask; sigset_t old_sigmask; + +if (itval->it_value.tv_usec < 100 && itval->it_value.tv_sec == 0) + return; (void)sigemptyset(&sigmask); /* Empty mask */ (void)sigaddset(&sigmask, SIGALRM); /* Add SIGALRM */ (void)sigprocmask(SIG_BLOCK, &sigmask, &old_sigmask); /* Block SIGALRM */ @@ -388,10 +417,11 @@ if (exim_tvcmp(&now_tv, then_tv) <= 0) { if (!running_in_test_harness) { - debug_printf("tick check: %lu.%06lu %lu.%06lu\n", - then_tv->tv_sec, then_tv->tv_usec, now_tv.tv_sec, now_tv.tv_usec); - debug_printf("waiting %lu.%06lu\n", itval.it_value.tv_sec, - itval.it_value.tv_usec); + debug_printf("tick check: " TIME_T_FMT ".%06lu " TIME_T_FMT ".%06lu\n", + then_tv->tv_sec, (long) then_tv->tv_usec, + now_tv.tv_sec, (long) now_tv.tv_usec); + debug_printf("waiting " TIME_T_FMT ".%06lu\n", + itval.it_value.tv_sec, (long) itval.it_value.tv_usec); } } @@ -516,7 +546,7 @@ close_unwanted(void) if (smtp_input) { #ifdef SUPPORT_TLS - tls_close(FALSE); /* Shut down the TLS library */ + tls_close(TRUE, FALSE); /* Shut down the TLS library */ #endif (void)close(fileno(smtp_in)); (void)close(fileno(smtp_out)); @@ -791,8 +821,26 @@ fprintf(f, "Support for:"); #ifndef DISABLE_DKIM fprintf(f, " DKIM"); #endif -#ifdef WITH_OLD_DEMIME - fprintf(f, " Old_Demime"); +#ifndef DISABLE_DNSSEC + fprintf(f, " DNSSEC"); +#endif +#ifndef DISABLE_EVENT + fprintf(f, " Event"); +#endif +#ifdef SUPPORT_I18N + fprintf(f, " I18N"); +#endif +#ifndef DISABLE_OCSP + fprintf(f, " OCSP"); +#endif +#ifndef DISABLE_PRDR + fprintf(f, " PRDR"); +#endif +#ifdef SUPPORT_PROXY + fprintf(f, " PROXY"); +#endif +#ifdef SUPPORT_SOCKS + fprintf(f, " SOCKS"); #endif #ifdef EXPERIMENTAL_SPF fprintf(f, " Experimental_SPF"); @@ -803,9 +851,18 @@ fprintf(f, "Support for:"); #ifdef EXPERIMENTAL_BRIGHTMAIL fprintf(f, " Experimental_Brightmail"); #endif +#ifdef EXPERIMENTAL_DANE + fprintf(f, " Experimental_DANE"); +#endif #ifdef EXPERIMENTAL_DCC fprintf(f, " Experimental_DCC"); #endif +#ifdef EXPERIMENTAL_DMARC + fprintf(f, " Experimental_DMARC"); +#endif +#ifdef EXPERIMENTAL_DSN_INFO + fprintf(f, " Experimental_DSN_info"); +#endif fprintf(f, "\n"); fprintf(f, "Lookups (built-in):"); @@ -848,6 +905,9 @@ fprintf(f, "Lookups (built-in):"); #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2 fprintf(f, " pgsql"); #endif +#if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2 + fprintf(f, " redis"); +#endif #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2 fprintf(f, " sqlite"); #endif @@ -881,6 +941,9 @@ fprintf(f, "Authenticators:"); #ifdef AUTH_SPA fprintf(f, " spa"); #endif +#ifdef AUTH_TLS + fprintf(f, " tls"); +#endif fprintf(f, "\n"); fprintf(f, "Routers:"); @@ -966,21 +1029,30 @@ DEBUG(D_any) do { fprintf(f, "Compiler: \n"); #endif +#ifdef __GLIBC__ + fprintf(f, "Library version: Glibc: Compile: %d.%d\n", + __GLIBC__, __GLIBC_MINOR__); + if (__GLIBC_PREREQ(2, 1)) + fprintf(f, " Runtime: %s\n", + gnu_get_libc_version()); +#endif + #ifdef SUPPORT_TLS tls_version_report(f); #endif +#ifdef SUPPORT_I18N + utf8_version_report(f); +#endif - for (authi = auths_available; *authi->driver_name != '\0'; ++authi) { - if (authi->version_report) { + for (authi = auths_available; *authi->driver_name != '\0'; ++authi) + if (authi->version_report) (*authi->version_report)(f); - } - } - /* PRE_PRERELEASE is either defined and empty or a bare sequence of + /* 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 is not defined. */ #ifndef PCRE_PRERELEASE -#define PCRE_PRERELEASE +# define PCRE_PRERELEASE #endif #define QUOTE(X) #X #define EXPAND_AND_QUOTE(X) QUOTE(X) @@ -994,10 +1066,8 @@ DEBUG(D_any) do { init_lookup_list(); for (i = 0; i < lookup_list_count; i++) - { if (lookup_list[i]->version_report) lookup_list[i]->version_report(f); - } #ifdef WHITELIST_D_MACROS fprintf(f, "WHITELIST_D_MACROS: \"%s\"\n", WHITELIST_D_MACROS); @@ -1014,6 +1084,39 @@ DEBUG(D_any) do { } +/************************************************* +* Show auxiliary information about Exim * +*************************************************/ + +static void +show_exim_information(enum commandline_info request, FILE *stream) +{ +const uschar **pp; + +switch(request) + { + case CMDINFO_NONE: + fprintf(stream, "Oops, something went wrong.\n"); + return; + case CMDINFO_HELP: + fprintf(stream, +"The -bI: flag takes a string indicating which information to provide.\n" +"If the string is not recognised, you'll get this help (on stderr).\n" +"\n" +" exim -bI:help this information\n" +" exim -bI:dscp dscp value keywords known\n" +" exim -bI:sieve list of supported sieve extensions, one per line.\n" +); + return; + case CMDINFO_SIEVE: + for (pp = exim_sieve_extension_list; *pp; ++pp) + fprintf(stream, "%s\n", *pp); + return; + case CMDINFO_DSCP: + dscp_list_to_stream(stream); + return; + } +} /************************************************* @@ -1045,23 +1148,23 @@ for (t = lpart; !needs_quote && *t != 0; t++) if (!needs_quote) return lpart; size = ptr = 0; -yield = string_cat(NULL, &size, &ptr, US"\"", 1); +yield = string_catn(NULL, &size, &ptr, US"\"", 1); for (;;) { uschar *nq = US Ustrpbrk(lpart, "\\\""); if (nq == NULL) { - yield = string_cat(yield, &size, &ptr, lpart, Ustrlen(lpart)); + yield = string_cat(yield, &size, &ptr, lpart); break; } - yield = string_cat(yield, &size, &ptr, lpart, nq - lpart); - yield = string_cat(yield, &size, &ptr, US"\\", 1); - yield = string_cat(yield, &size, &ptr, nq, 1); + yield = string_catn(yield, &size, &ptr, lpart, nq - lpart); + yield = string_catn(yield, &size, &ptr, US"\\", 1); + yield = string_catn(yield, &size, &ptr, nq, 1); lpart = nq + 1; } -yield = string_cat(yield, &size, &ptr, US"\"", 1); +yield = string_catn(yield, &size, &ptr, US"\"", 1); yield[ptr] = 0; return yield; } @@ -1175,15 +1278,16 @@ for (i = 0;; i++) while (p < ss && isspace(*p)) p++; /* leading space after cont */ } - yield = string_cat(yield, &size, &ptr, p, ss - p); + yield = string_catn(yield, &size, &ptr, p, ss - p); #ifdef USE_READLINE if (fn_readline != NULL) free(readline_line); #endif + /* yield can only be NULL if ss==p */ if (ss == p || yield[ptr-1] != '\\') { - yield[ptr] = 0; + if (yield) yield[ptr] = 0; break; } yield[--ptr] = 0; @@ -1391,11 +1495,14 @@ BOOL checking = FALSE; BOOL count_queue = FALSE; BOOL expansion_test = FALSE; BOOL extract_recipients = FALSE; +BOOL flag_G = FALSE; +BOOL flag_n = FALSE; BOOL forced_delivery = FALSE; BOOL f_end_dot = FALSE; BOOL deliver_give_up = FALSE; BOOL list_queue = FALSE; BOOL list_options = FALSE; +BOOL list_config = FALSE; BOOL local_queue_only; BOOL more = TRUE; BOOL one_msg_action = FALSE; @@ -1411,6 +1518,7 @@ BOOL verify_as_sender = FALSE; BOOL version_printed = FALSE; uschar *alias_arg = NULL; uschar *called_as = US""; +uschar *cmdline_syslog_name = NULL; uschar *start_queue_run_id = NULL; uschar *stop_queue_run_id = NULL; uschar *expansion_test_message = NULL; @@ -1418,9 +1526,11 @@ uschar *ftest_domain = NULL; uschar *ftest_localpart = NULL; uschar *ftest_prefix = NULL; uschar *ftest_suffix = NULL; +uschar *log_oneline = NULL; uschar *malware_test_file = NULL; uschar *real_sender_address; uschar *originator_home = US"/"; +size_t sz; void *reset_point; struct passwd *pw; @@ -1429,6 +1539,10 @@ pid_t passed_qr_pid = (pid_t)0; int passed_qr_pipe = -1; gid_t group_list[NGROUPS_MAX]; +/* For the -bI: flag */ +enum commandline_info info_flag = CMDINFO_NONE; +BOOL info_stdout = FALSE; + /* Possible options for -R and -S */ static uschar *rsopts[] = { US"f", US"ff", US"r", US"rf", US"rff" }; @@ -1505,8 +1619,9 @@ if (!route_findgroup(US CONFIGURE_GROUPNAME, &config_gid)) } #endif -/* In the Cygwin environment, some initialization needs doing. It is fudged -in by means of this macro. */ +/* In the Cygwin environment, some initialization used to need doing. +It was fudged in by means of this macro; now no longer but we'll leave +it in case of others. */ #ifdef OS_INIT OS_INIT @@ -1539,6 +1654,10 @@ if (log_buffer == NULL) exit(EXIT_FAILURE); } +/* Initialize the default log options. */ + +bits_set(log_selector, log_selector_size, log_default); + /* Set log_stderr to stderr, provided that stderr exists. This gets reset to NULL when the daemon is run and the file is closed. We have to use this indirection, because some systems don't allow writing to the variable "stderr". @@ -1649,6 +1768,7 @@ regex_whitelisted_macro = regex_must_compile(US"^[A-Za-z0-9_/.-]*$", FALSE, TRUE); #endif +for (i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL; /* If the program is called as "mailq" treat it as equivalent to "exim -bp"; this seems to be a generally accepted convention, since one finds symbolic @@ -1827,6 +1947,26 @@ for (i = 1; i < argc; i++) switch(switchchar) { + + /* sendmail uses -Ac and -Am to control which .cf file is used; + we ignore them. */ + case 'A': + if (*argrest == '\0') { 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; } + } + break; + /* -Btype is a sendmail option for 7bit/8bit setting. Exim is 8-bit clean so has no need of it. */ @@ -1869,7 +2009,7 @@ for (i = 1; i < argc; i++) else if (*argrest == 'F') { - filter_test |= FTEST_SYSTEM; + filter_test |= checking = FTEST_SYSTEM; if (*(++argrest) != 0) { badarg = TRUE; break; } if (++i < argc) filter_test_sfile = argv[i]; else { @@ -1889,7 +2029,7 @@ for (i = 1; i < argc; i++) { if (*(++argrest) == 0) { - filter_test |= FTEST_USER; + filter_test |= checking = FTEST_USER; if (++i < argc) filter_test_ufile = argv[i]; else { fprintf(stderr, "exim: file name expected after %s\n", argv[i-1]); @@ -1919,6 +2059,7 @@ for (i = 1; i < argc; i++) sender_host_address = argv[i]; host_checking = checking = log_testing_mode = TRUE; host_checking_callout = argrest[1] == 'c'; + message_logs = FALSE; } /* -bi: This option is used by sendmail to initialize *the* alias file, @@ -1928,6 +2069,32 @@ for (i = 1; i < argc; i++) else if (Ustrcmp(argrest, "i") == 0) bi_option = TRUE; + /* -bI: provide information, of the type to follow after a colon. + This is an Exim flag. */ + + else if (argrest[0] == 'I' && Ustrlen(argrest) >= 2 && argrest[1] == ':') + { + uschar *p = &argrest[2]; + info_flag = CMDINFO_HELP; + if (Ustrlen(p)) + { + if (strcmpic(p, CUS"sieve") == 0) + { + info_flag = CMDINFO_SIEVE; + info_stdout = TRUE; + } + else if (strcmpic(p, CUS"dscp") == 0) + { + info_flag = CMDINFO_DSCP; + info_stdout = TRUE; + } + else if (strcmpic(p, CUS"help") == 0) + { + info_stdout = TRUE; + } + } + } + /* -bm: Accept and deliver message - the default option. Reinstate receiving_message, which got turned off for all -b options. */ @@ -1938,6 +2105,7 @@ for (i = 1; i < argc; i++) else if (Ustrcmp(argrest, "malware") == 0) { if (++i >= argc) { badarg = TRUE; break; } + checking = TRUE; malware_test_file = argv[i]; } @@ -2000,15 +2168,26 @@ for (i = 1; i < argc; i++) else if (Ustrcmp(argrest, "P") == 0) { - list_options = TRUE; - debug_selector |= D_v; - debug_file = stderr; + /* -bP config: we need to setup here, because later, + * when list_options is checked, the config is read already */ + if (argv[i+1] && Ustrcmp(argv[i+1], "config") == 0) + { + list_config = TRUE; + readconf_save_config(version_string); + } + else + { + list_options = TRUE; + debug_selector |= D_v; + debug_file = stderr; + } } /* -brt: Test retry configuration lookup */ else if (Ustrcmp(argrest, "rt") == 0) { + checking = TRUE; test_retry_arg = i + 1; goto END_ARG; } @@ -2017,6 +2196,7 @@ for (i = 1; i < argc; i++) else if (Ustrcmp(argrest, "rw") == 0) { + checking = TRUE; test_rewrite_arg = i + 1; goto END_ARG; } @@ -2059,6 +2239,7 @@ for (i = 1; i < argc; i++) printf("%s\n", CS version_copyright); version_printed = TRUE; show_whats_supported(stdout); + log_testing_mode = TRUE; } /* -bw: inetd wait mode, accept a listening socket as stdin */ @@ -2173,7 +2354,7 @@ for (i = 1; i < argc; i++) if (nr_configs) { int sep = 0; - uschar *list = argrest; + const uschar *list = argrest; uschar *filename; while (trusted_config && (filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)) != NULL) @@ -2305,8 +2486,8 @@ for (i = 1; i < argc; i++) argrest++; } if (*argrest != 0) - decode_bits(&selector, NULL, D_memory, 0, argrest, debug_options, - debug_options_count, US"debug", 0); + decode_bits(&selector, 1, debug_notall, argrest, + debug_options, debug_options_count, US"debug", 0); debug_selector = selector; } break; @@ -2378,7 +2559,7 @@ for (i = 1; i < argc; i++) case 'f': { - int start, end; + int dummy_start, dummy_end; uschar *errmess; if (*argrest == 0) { @@ -2386,9 +2567,7 @@ for (i = 1; i < argc; i++) { badarg = TRUE; break; } } if (*argrest == 0) - { sender_address = string_sprintf(""); /* Ensure writeable memory */ - } else { uschar *temp = argrest + Ustrlen(argrest) - 1; @@ -2396,8 +2575,15 @@ for (i = 1; i < argc; i++) if (temp >= argrest && *temp == '.') f_end_dot = TRUE; allow_domain_literals = TRUE; strip_trailing_dot = TRUE; - sender_address = parse_extract_address(argrest, &errmess, &start, &end, - &sender_address_domain, TRUE); +#ifdef SUPPORT_I18N + allow_utf8_domains = TRUE; +#endif + sender_address = parse_extract_address(argrest, &errmess, + &dummy_start, &dummy_end, &sender_address_domain, TRUE); +#ifdef SUPPORT_I18N + message_smtputf8 = string_is_utf8(sender_address); + allow_utf8_domains = FALSE; +#endif allow_domain_literals = FALSE; strip_trailing_dot = FALSE; if (sender_address == NULL) @@ -2410,9 +2596,13 @@ for (i = 1; i < argc; i++) } break; - /* This is some Sendmail thing which can be ignored */ + /* -G: sendmail invocation to specify that it's a gateway submission and + sendmail may complain about problems instead of fixing them. + We make it equivalent to an ACL "control = suppress_local_fixups" and do + not at this time complain about problems. */ case 'G': + flag_G = TRUE; break; /* -h: Set the hop count for an incoming message. Exim does not currently @@ -2437,6 +2627,29 @@ for (i = 1; i < argc; i++) break; + /* -L: set the identifier used for syslog; equivalent to setting + syslog_processname in the config file, but needs to be an admin option. */ + + case 'L': + if (*argrest == '\0') + { + if(++i < argc) argrest = argv[i]; else + { badarg = TRUE; break; } + } + sz = Ustrlen(argrest); + if (sz > 32) + { + fprintf(stderr, "exim: the -L syslog name is too long: \"%s\"\n", argrest); + return EXIT_FAILURE; + } + if (sz < 1) + { + fprintf(stderr, "exim: the -L syslog name is too short\n"); + return EXIT_FAILURE; + } + cmdline_syslog_name = argrest; + break; + case 'M': receiving_message = FALSE; @@ -2514,6 +2727,14 @@ for (i = 1; i < argc; i++) break; } + /* -MCD: set the smtp_use_dsn flag; this indicates that the host + that exim is connected to supports the esmtp extension DSN */ + else if (Ustrcmp(argrest, "CD") == 0) + { + smtp_use_dsn = TRUE; + break; + } + /* -MCP: set the smtp_use_pipelining flag; this is useful only when it preceded -MC (see above) */ @@ -2699,10 +2920,12 @@ for (i = 1; i < argc; i++) break; - /* -n: This means "don't alias" in sendmail, apparently. Just ignore - it. */ + /* -n: This means "don't alias" in sendmail, apparently. + For normal invocations, it has no effect. + It may affect some other options. */ case 'n': + flag_n = TRUE; break; /* -O: Just ignore it. In sendmail, apparently -O option=value means set @@ -2845,6 +3068,23 @@ for (i = 1; i < argc; i++) else if (Ustrcmp(argrest, "Mi") == 0) interface_address = argv[++i]; + /* -oMm: Message reference */ + + else if (Ustrcmp(argrest, "Mm") == 0) + { + if (!mac_ismsgid(argv[i+1])) + { + fprintf(stderr,"-oMm must be a valid message ID\n"); + exit(EXIT_FAILURE); + } + if (!trusted_config) + { + fprintf(stderr,"-oMm must be called by a trusted user/config\n"); + exit(EXIT_FAILURE); + } + message_reference = argv[++i]; + } + /* -oMr: Received protocol */ else if (Ustrcmp(argrest, "Mr") == 0) received_protocol = argv[++i]; @@ -3150,7 +3390,7 @@ for (i = 1; i < argc; i++) /* -tls-on-connect: don't wait for STARTTLS (for old clients) */ #ifdef SUPPORT_TLS - else if (Ustrcmp(argrest, "ls-on-connect") == 0) tls_on_connect = TRUE; + else if (Ustrcmp(argrest, "ls-on-connect") == 0) tls_in.on_connect = TRUE; #endif else badarg = TRUE; @@ -3191,6 +3431,27 @@ for (i = 1; i < argc; i++) if (*argrest != 0) badarg = TRUE; break; + /* -X: in sendmail: takes one parameter, logfile, and sends debugging + logs to that file. We swallow the parameter and otherwise ignore it. */ + + case 'X': + if (*argrest == '\0') + if (++i >= argc) + { + fprintf(stderr, "exim: string expected after -X\n"); + exit(EXIT_FAILURE); + } + break; + + case 'z': + if (*argrest == '\0') + if (++i < argc) log_oneline = argv[i]; else + { + fprintf(stderr, "exim: file name expected after %s\n", argv[i-1]); + exit(EXIT_FAILURE); + } + break; + /* All other initial characters are errors */ default: @@ -3489,22 +3750,122 @@ is equivalent to the ability to modify a setuid binary! This needs to happen before we read the main configuration. */ init_lookup_list(); +#ifdef SUPPORT_I18N +if (running_in_test_harness) smtputf8_advertise_hosts = NULL; +#endif + /* Read the main runtime configuration data; this gives up if there is a failure. It leaves the configuration file open so that the subsequent -configuration data for delivery can be read if needed. */ +configuration data for delivery can be read if needed. + +NOTE: immediatly after opening the configuration file we change the working +directory to "/"! Later we change to $spool_directory. We do it there, because +during readconf_main() some expansion takes place already. */ + +/* Store the initial cwd before we change directories */ +if ((initial_cwd = os_getcwd(NULL, 0)) == NULL) + { + perror("exim: can't get the current working directory"); + exit(EXIT_FAILURE); + } + +/* checking: + -be[m] expansion test - + -b[fF] filter test new + -bh[c] host test - + -bmalware malware_test_file new + -brt retry test new + -brw rewrite test new + -bt address test - + -bv[s] address verify - + list_options: + -bP