X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/cb46fd2b91514ce49ad0e13788127d756ed35145..43ba2742c700d625dcdcdaf7bbadc2f72776854a:/src/src/exim.c diff --git a/src/src/exim.c b/src/src/exim.c index 8ab0456d8..beb5abc25 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 - 2015 */ /* See the file NOTICE for conditions of use and distribution. */ @@ -12,6 +12,13 @@ Also a few functions that don't naturally fit elsewhere. */ #include "exim.h" +#ifdef USE_GNUTLS +# include +# if GNUTLS_VERSION_NUMBER < 0x030103 && !defined(DISABLE_OCSP) +# define DISABLE_OCSP +# endif +#endif + extern void init_lookup_list(void); @@ -81,7 +88,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; @@ -93,7 +100,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) @@ -124,10 +131,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; @@ -137,7 +145,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--; @@ -267,6 +275,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 */ @@ -276,6 +288,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 */ @@ -398,10 +413,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); } } @@ -526,7 +542,7 @@ close_unwanted(void) if (smtp_input) { #ifdef SUPPORT_TLS - tls_close(FALSE, 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)); @@ -804,6 +820,15 @@ fprintf(f, "Support for:"); #ifdef WITH_OLD_DEMIME fprintf(f, " Old_Demime"); #endif +#ifndef DISABLE_DNSSEC + fprintf(f, " DNSSEC"); +#endif +#ifndef DISABLE_PRDR + fprintf(f, " PRDR"); +#endif +#ifndef DISABLE_OCSP + fprintf(f, " OCSP"); +#endif #ifdef EXPERIMENTAL_SPF fprintf(f, " Experimental_SPF"); #endif @@ -813,17 +838,29 @@ 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_OCSP - fprintf(f, " Experimental_OCSP"); +#ifdef EXPERIMENTAL_PROXY + fprintf(f, " Experimental_Proxy"); #endif -#ifdef EXPERIMENTAL_PRDR - fprintf(f, " Experimental_PRDR"); +#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"); #endif fprintf(f, "\n"); @@ -900,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:"); @@ -988,12 +1028,13 @@ DEBUG(D_any) do { #ifdef SUPPORT_TLS tls_version_report(f); #endif +#ifdef EXPERIMENTAL_INTERNATIONAL + 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 @@ -1013,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); @@ -1473,6 +1512,7 @@ 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"/"; @@ -2279,7 +2319,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) @@ -2484,7 +2524,7 @@ for (i = 1; i < argc; i++) case 'f': { - int start, end; + int dummy_start, dummy_end; uschar *errmess; if (*argrest == 0) { @@ -2492,9 +2532,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; @@ -2502,8 +2540,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 EXPERIMENTAL_INTERNATIONAL + allow_utf8_domains = TRUE; +#endif + sender_address = parse_extract_address(argrest, &errmess, + &dummy_start, &dummy_end, &sender_address_domain, TRUE); +#ifdef EXPERIMENTAL_INTERNATIONAL + message_smtputf8 = string_is_utf8(sender_address); + allow_utf8_domains = FALSE; +#endif allow_domain_literals = FALSE; strip_trailing_dot = FALSE; if (sender_address == NULL) @@ -2647,6 +2692,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) */ @@ -2980,6 +3033,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]; @@ -3331,13 +3401,20 @@ for (i = 1; i < argc; i++) 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 */ @@ -3638,12 +3715,27 @@ is equivalent to the ability to modify a setuid binary! This needs to happen before we read the main configuration. */ init_lookup_list(); +#ifdef EXPERIMENTAL_INTERNATIONAL +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. */ +/* To be safe: change the working directory to /. */ +if (Uchdir("/") < 0) + { + perror("exim: chdir `/': "); + exit(EXIT_FAILURE); + } + readconf_main(); +if (cleanup_environment() == FALSE) + log_write(0, LOG_PANIC_DIE, "Can't cleanup environment"); + + /* If an action on specific messages is requested, or if a daemon or queue runner is being started, we need to know if Exim was called by an admin user. This is the case if the real user is root or exim, or if the real group is @@ -3780,6 +3872,17 @@ if (Ustrlen(syslog_processname) > 32) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "syslog_processname is longer than 32 chars: aborting"); +if (log_oneline) + { + if (admin_user) + { + log_write(0, LOG_MAIN, "%s", log_oneline); + return EXIT_SUCCESS; + } + else + return EXIT_FAILURE; + } + /* In some operating systems, the environment variable TMPDIR controls where temporary files are created; Exim doesn't use these (apart from when delivering to MBX mailboxes), but called libraries such as DBM libraries may require them. @@ -3789,7 +3892,7 @@ TMPDIR macro, if this macro is defined. */ #ifdef TMPDIR { uschar **p; - for (p = USS environ; *p != NULL; p++) + if (environ) for (p = USS environ; *p != NULL; p++) { if (Ustrncmp(*p, "TMPDIR=", 7) == 0 && Ustrcmp(*p+7, TMPDIR) != 0) @@ -3829,10 +3932,10 @@ else uschar **new; uschar **newp; int count = 0; - while (*p++ != NULL) count++; + if (environ) while (*p++ != NULL) count++; if (envtz == NULL) count++; newp = new = malloc(sizeof(uschar *) * (count + 1)); - for (p = USS environ; *p != NULL; p++) + if (environ) for (p = USS environ; *p != NULL; p++) { if (Ustrncmp(*p, "TZ=", 3) == 0) continue; *newp++ = *p; @@ -3923,7 +4026,7 @@ if (((debug_selector & D_any) != 0 || (log_extra_selector & LX_arguments) != 0) for (i = 0; i < argc; i++) { int len = Ustrlen(argv[i]); - uschar *printing; + const uschar *printing; uschar *quote; if (p + len + 8 >= big_buffer + big_buffer_size) { @@ -3935,7 +4038,7 @@ if (((debug_selector & D_any) != 0 || (log_extra_selector & LX_arguments) != 0) printing = string_printing(argv[i]); if (printing[0] == 0) quote = US"\""; else { - uschar *pp = printing; + const uschar *pp = printing; quote = US""; while (*pp != 0) if (isspace(*pp++)) { quote = US"\""; break; } } @@ -4422,7 +4525,8 @@ if (list_options) (Ustrcmp(argv[i], "router") == 0 || Ustrcmp(argv[i], "transport") == 0 || Ustrcmp(argv[i], "authenticator") == 0 || - Ustrcmp(argv[i], "macro") == 0)) + Ustrcmp(argv[i], "macro") == 0 || + Ustrcmp(argv[i], "environment") == 0)) { readconf_print(argv[i+1], argv[i], flag_n); i++; @@ -4998,6 +5102,9 @@ if (mua_wrapper) deliver_drop_privilege = TRUE; queue_smtp = FALSE; queue_smtp_domains = NULL; +#ifdef EXPERIMENTAL_INTERNATIONAL + message_utf8_downconvert = -1; /* convert-if-needed */ +#endif } @@ -5276,7 +5383,6 @@ while (more) if (recipients_max > 0 && ++rcount > recipients_max && !extract_recipients) - { if (error_handling == ERRORS_STDERR) { fprintf(stderr, "exim: too many recipients\n"); @@ -5288,11 +5394,22 @@ while (more) moan_to_sender(ERRMESS_TOOMANYRECIP, NULL, NULL, stdin, TRUE)? errors_sender_rc : EXIT_FAILURE; } - } +#ifdef EXPERIMENTAL_INTERNATIONAL + { + BOOL b = allow_utf8_domains; + allow_utf8_domains = TRUE; +#endif recipient = parse_extract_address(s, &errmess, &start, &end, &domain, FALSE); +#ifdef EXPERIMENTAL_INTERNATIONAL + if (string_is_utf8(recipient)) + message_smtputf8 = TRUE; + else + allow_utf8_domains = b; + } +#endif if (domain == 0 && !allow_unqualified_recipient) { recipient = NULL; @@ -5392,9 +5509,7 @@ while (more) return_path = string_copy(sender_address); } else - { printf("Return-path = %s\n", (return_path[0] == 0)? US"<>" : return_path); - } printf("Sender = %s\n", (sender_address[0] == 0)? US"<>" : sender_address); receive_add_recipient(