X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/c65be1246d0cb9dc90bdeb99bb9162153a5e6fd7..c2f669a4994192344613569e198c7b503d46d45e:/src/src/exim.c diff --git a/src/src/exim.c b/src/src/exim.c index f6d9be6ef..46e856b7a 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 - 2014 */ +/* Copyright (c) University of Cambridge 1995 - 2016 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -230,7 +230,7 @@ to disrupt whatever is going on outside the signal handler. */ if (fd < 0) return; -{int dummy = write(fd, process_info, process_info_len); dummy = dummy; } +(void)write(fd, process_info, process_info_len); (void)close(fd); } @@ -817,15 +817,27 @@ 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_PRDR - fprintf(f, " PRDR"); +#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"); #endif @@ -844,20 +856,8 @@ fprintf(f, "Support for:"); #ifdef EXPERIMENTAL_DMARC fprintf(f, " Experimental_DMARC"); #endif -#ifdef EXPERIMENTAL_PROXY - fprintf(f, " Experimental_Proxy"); -#endif -#ifdef EXPERIMENTAL_EVENT - fprintf(f, " Experimental_Event"); -#endif -#ifdef EXPERIMENTAL_REDIS - fprintf(f, " Experimental_Redis"); -#endif -#ifdef EXPERIMENTAL_SOCKS - fprintf(f, " Experimental_SOCKS"); -#endif -#ifdef EXPERIMENTAL_INTERNATIONAL - fprintf(f, " Experimental_International"); +#ifdef EXPERIMENTAL_DSN_INFO + fprintf(f, " Experimental_DSN_info"); #endif fprintf(f, "\n"); @@ -901,6 +901,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 @@ -934,6 +937,9 @@ fprintf(f, "Authenticators:"); #ifdef AUTH_SPA fprintf(f, " spa"); #endif +#ifdef AUTH_TLS + fprintf(f, " tls"); +#endif fprintf(f, "\n"); fprintf(f, "Routers:"); @@ -1022,12 +1028,13 @@ DEBUG(D_any) do { #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); - } - } /* 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 @@ -1047,10 +1054,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); @@ -1131,23 +1136,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; } @@ -1261,7 +1266,7 @@ 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); @@ -1484,6 +1489,7 @@ 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; @@ -1600,8 +1606,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 @@ -1634,6 +1641,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". @@ -1744,6 +1755,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 @@ -1984,7 +1996,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 { @@ -2004,7 +2016,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]); @@ -2079,6 +2091,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]; } @@ -2141,15 +2154,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; } @@ -2158,6 +2182,7 @@ for (i = 1; i < argc; i++) else if (Ustrcmp(argrest, "rw") == 0) { + checking = TRUE; test_rewrite_arg = i + 1; goto END_ARG; } @@ -2200,6 +2225,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 */ @@ -2446,8 +2472,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; @@ -2519,7 +2545,7 @@ for (i = 1; i < argc; i++) case 'f': { - int start, end; + int dummy_start, dummy_end; uschar *errmess; if (*argrest == 0) { @@ -2527,9 +2553,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; @@ -2537,8 +2561,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) @@ -3705,11 +3736,48 @@ 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