X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/aded22555eeb31bc032f9bc58a83762981a58391..d85cdeb5e554b59bf4c43c54461409c15c6ee9c5:/src/src/exim.c diff --git a/src/src/exim.c b/src/src/exim.c index f6f15f449..68734e35c 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -42,7 +42,9 @@ regular expression for a long time; the other for short-term use. */ static void * function_store_get(size_t size) { -return store_get((int)size); +/* For now, regard all RE results as potentially tainted. We might need +more intelligence on this point. */ +return store_get((int)size, TRUE); } static void @@ -145,9 +147,8 @@ BOOL yield = n >= 0; if (n == 0) n = EXPAND_MAXN + 1; if (yield) { - int nn; expand_nmax = setup < 0 ? 0 : setup + 1; - for (nn = setup < 0 ? 0 : 2; nn < n*2; nn += 2) + for (int nn = setup < 0 ? 0 : 2; nn < n*2; nn += 2) { expand_nstring[expand_nmax] = s + ovector[nn]; expand_nlength[expand_nmax++] = ovector[nn+1] - ovector[nn]; @@ -182,7 +183,7 @@ va_list ap; g = string_fmt_append(&gs, "%5d ", (int)getpid()); len = g->ptr; va_start(ap, format); -if (!string_vformat(g, FALSE, format, ap)) +if (!string_vformat(g, 0, format, ap)) { gs.ptr = len; g = string_cat(&gs, US"**** string overflowed buffer ****"); @@ -474,8 +475,6 @@ return f; } - - /************************************************* * Ensure stdin, stdout, and stderr exist * *************************************************/ @@ -497,16 +496,15 @@ Returns: Nothing void exim_nullstd(void) { -int i; int devnull = -1; struct stat statbuf; -for (i = 0; i <= 2; i++) +for (int i = 0; i <= 2; i++) { if (fstat(i, &statbuf) < 0 && errno == EBADF) { if (devnull < 0) devnull = open("/dev/null", O_RDWR); if (devnull < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", - string_open_failed(errno, "/dev/null")); + string_open_failed(errno, "/dev/null", NULL)); if (devnull != i) (void)dup2(devnull, i); } } @@ -557,7 +555,7 @@ close_unwanted(void) { if (smtp_input) { -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS tls_close(NULL, TLS_NO_SHUTDOWN); /* Shut down the TLS library */ #endif (void)close(fileno(smtp_in)); @@ -642,10 +640,7 @@ DEBUG(D_uid) save_errno = errno; debug_printf(" auxiliary group list:"); if (group_count > 0) - { - int i; - for (i = 0; i < group_count; i++) debug_printf(" %d", (int)group_list[i]); - } + for (int i = 0; i < group_count; i++) debug_printf(" %d", (int)group_list[i]); else if (group_count < 0) debug_printf(" ", strerror(save_errno)); else debug_printf(" "); @@ -673,6 +668,7 @@ void exim_exit(int rc, const uschar * process) { search_tidyup(); +store_exit(); DEBUG(D_any) debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d %s%s%sterminating with rc=%d " ">>>>>>>>>>>>>>>>\n", (int)getpid(), @@ -681,6 +677,14 @@ exit(rc); } +void +exim_underbar_exit(int rc) +{ +store_exit(); +_exit(rc); +} + + /* Print error string, then die */ static void @@ -692,6 +696,36 @@ vfprintf(stderr, fmt, ap); exit(EXIT_FAILURE); } +/* exim_chown_failure() called from exim_chown()/exim_fchown() on failure +of chown()/fchown(). See src/functions.h for more explanation */ +int +exim_chown_failure(int fd, const uschar *name, uid_t owner, gid_t group) +{ +int saved_errno = errno; /* from the preceeding chown call */ +#if 1 +log_write(0, LOG_MAIN|LOG_PANIC, + __FILE__ ":%d: chown(%s, %d:%d) failed (%s)." + " Please contact the authors and refer to https://bugs.exim.org/show_bug.cgi?id=2391", + __LINE__, name?name:US"", owner, group, strerror(errno)); +#else +/* I leave this here, commented, in case the "bug"(?) comes up again. + It is not an Exim bug, but we can provide a workaround. + See Bug 2391 + HS 2019-04-18 */ + +struct stat buf; + +if (0 == (fd < 0 ? stat(name, &buf) : fstat(fd, &buf))) +{ + if (buf.st_uid == owner && buf.st_gid == group) return 0; + log_write(0, LOG_MAIN|LOG_PANIC, "Wrong ownership on %s", name); +} +else log_write(0, LOG_MAIN|LOG_PANIC, "Stat failed on %s: %s", name, strerror(errno)); + +#endif +errno = saved_errno; +return -1; +} /************************************************* @@ -807,8 +841,6 @@ Returns: nothing static void show_whats_supported(FILE * fp) { -auth_info * authi; - DEBUG(D_any) {} else show_db_version(fp); fprintf(fp, "Support for:"); @@ -836,12 +868,11 @@ fprintf(fp, "Support for:"); #ifdef USE_TCP_WRAPPERS fprintf(fp, " TCPwrappers"); #endif -#ifdef SUPPORT_TLS -# ifdef USE_GNUTLS +#ifdef USE_GNUTLS fprintf(fp, " GnuTLS"); -# else +#endif +#ifdef USE_OPENSSL fprintf(fp, " OpenSSL"); -# endif #endif #ifdef SUPPORT_TRANSLATE_IP_ADDRESS fprintf(fp, " translate_ip_address"); @@ -870,6 +901,9 @@ fprintf(fp, "Support for:"); #ifndef DISABLE_OCSP fprintf(fp, " OCSP"); #endif +#ifdef SUPPORT_PIPE_CONNECT + fprintf(fp, " PIPE_CONNECT"); +#endif #ifndef DISABLE_PRDR fprintf(fp, " PRDR"); #endif @@ -882,8 +916,11 @@ fprintf(fp, "Support for:"); #ifdef SUPPORT_SPF fprintf(fp, " SPF"); #endif +#ifdef SUPPORT_DMARC + fprintf(fp, " DMARC"); +#endif #ifdef TCP_FASTOPEN - deliver_init(); + tcp_init(); if (f.tcp_fastopen_ok) fprintf(fp, " TCP_Fast_Open"); #endif #ifdef EXPERIMENTAL_LMDB @@ -904,17 +941,11 @@ fprintf(fp, "Support for:"); #ifdef EXPERIMENTAL_DCC fprintf(fp, " Experimental_DCC"); #endif -#ifdef EXPERIMENTAL_DMARC - fprintf(fp, " Experimental_DMARC"); -#endif #ifdef EXPERIMENTAL_DSN_INFO fprintf(fp, " Experimental_DSN_info"); #endif -#ifdef EXPERIMENTAL_REQUIRETLS - fprintf(fp, " Experimental_REQUIRETLS"); -#endif -#ifdef EXPERIMENTAL_PIPE_CONNECT - fprintf(fp, " Experimental_PIPE_CONNECT"); +#ifdef EXPERIMENTAL_TLS_RESUME + fprintf(fp, " Experimental_TLS_resume"); #endif fprintf(fp, "\n"); @@ -937,6 +968,9 @@ fprintf(fp, "Lookups (built-in):"); #if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2 fprintf(fp, " ibase"); #endif +#if defined(LOOKUP_JSON) && LOOKUP_JSON!=2 + fprintf(fp, " json"); +#endif #if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2 fprintf(fp, " ldap ldapdn ldapm"); #endif @@ -1000,8 +1034,6 @@ fprintf(fp, "Size of off_t: " SIZE_T_FMT "\n", sizeof(off_t)); Perhaps the tls_version_report should move into this too. */ DEBUG(D_any) do { - int i; - /* clang defines __GNUC__ (at least, for me) so test for it first */ #if defined(__clang__) fprintf(fp, "Compiler: CLang [%s]\n", __clang_version__); @@ -1027,14 +1059,14 @@ DEBUG(D_any) do { show_db_version(fp); -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS tls_version_report(fp); #endif #ifdef SUPPORT_I18N utf8_version_report(fp); #endif - for (authi = auths_available; *authi->driver_name != '\0'; ++authi) + for (auth_info * authi = auths_available; *authi->driver_name != '\0'; ++authi) if (authi->version_report) (*authi->version_report)(fp); @@ -1055,7 +1087,7 @@ show_db_version(fp); #undef EXPAND_AND_QUOTE init_lookup_list(); - for (i = 0; i < lookup_list_count; i++) + for (int i = 0; i < lookup_list_count; i++) if (lookup_list[i]->version_report) lookup_list[i]->version_report(fp); @@ -1081,8 +1113,6 @@ show_db_version(fp); static void show_exim_information(enum commandline_info request, FILE *stream) { -const uschar **pp; - switch(request) { case CMDINFO_NONE: @@ -1099,7 +1129,7 @@ switch(request) ); return; case CMDINFO_SIEVE: - for (pp = exim_sieve_extension_list; *pp; ++pp) + for (const uschar ** pp = exim_sieve_extension_list; *pp; ++pp) fprintf(stream, "%s\n", *pp); return; case CMDINFO_DSCP: @@ -1126,9 +1156,8 @@ local_part_quote(uschar *lpart) { BOOL needs_quote = FALSE; gstring * g; -uschar *t; -for (t = lpart; !needs_quote && *t != 0; t++) +for (uschar * t = lpart; !needs_quote && *t != 0; t++) { needs_quote = !isalnum(*t) && strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL && (*t != '.' || t == lpart || t[1] == 0); @@ -1225,22 +1254,21 @@ Returns: pointer to dynamic memory, or NULL at end of file static uschar * get_stdinput(char *(*fn_readline)(const char *), void(*fn_addhist)(const char *)) { -int i; gstring * g = NULL; if (!fn_readline) { printf("> "); fflush(stdout); } -for (i = 0;; i++) +for (int i = 0;; i++) { uschar buffer[1024]; uschar *p, *ss; #ifdef USE_READLINE char *readline_line = NULL; - if (fn_readline != NULL) + if (fn_readline) { - if ((readline_line = fn_readline((i > 0)? "":"> ")) == NULL) break; - if (*readline_line != 0 && fn_addhist != NULL) fn_addhist(readline_line); + if (!(readline_line = fn_readline((i > 0)? "":"> "))) break; + if (*readline_line != 0 && fn_addhist) fn_addhist(readline_line); p = US readline_line; } else @@ -1259,9 +1287,7 @@ for (i = 0;; i++) while (ss > p && isspace(ss[-1])) ss--; if (i > 0) - { while (p < ss && isspace(*p)) p++; /* leading space after cont */ - } g = string_catn(g, p, ss - p); @@ -1330,8 +1356,7 @@ static BOOL macros_trusted(BOOL opt_D_used) { #ifdef WHITELIST_D_MACROS -macro_item *m; -uschar *whitelisted, *end, *p, **whites, **w; +uschar *whitelisted, *end, *p, **whites; int white_count, i, n; size_t len; BOOL prev_char_item, found; @@ -1359,7 +1384,7 @@ if ( ! ((real_uid == root_uid) } /* Get a list of macros which are whitelisted */ -whitelisted = string_copy_malloc(US WHITELIST_D_MACROS); +whitelisted = string_copy_perm(US WHITELIST_D_MACROS, FALSE); prev_char_item = FALSE; white_count = 0; for (p = whitelisted; *p != '\0'; ++p) @@ -1396,10 +1421,10 @@ whites[i] = NULL; /* The list of commandline macros should be very short. Accept the N*M complexity. */ -for (m = macros_user; m; m = m->next) if (m->command_line) +for (macro_item * m = macros_user; m; m = m->next) if (m->command_line) { found = FALSE; - for (w = whites; *w; ++w) + for (uschar ** w = whites; *w; ++w) if (Ustrcmp(*w, m->name) == 0) { found = TRUE; @@ -1546,7 +1571,7 @@ uschar *malware_test_file = NULL; uschar *real_sender_address; uschar *originator_home = US"/"; size_t sz; -void *reset_point; +rmark reset_point; struct passwd *pw; struct stat statbuf; @@ -1568,6 +1593,10 @@ because some OS define it in /usr/include/unistd.h. */ extern char **environ; +#ifdef MEASURE_TIMING +(void)gettimeofday(×tamp_startup, NULL); +#endif + /* If the Exim user and/or group and/or the configuration file owner/group were defined by ref:name at build time, we must now find the actual uid/gid values. This is a feature to make the lives of binary distributors easier. */ @@ -1675,6 +1704,7 @@ big_buffer = store_malloc(big_buffer_size); /* Set up the handler for the data request signal, and set the initial descriptive text. */ +process_info = store_get(PROCESS_INFO_SIZE, TRUE); /* tainted */ set_process_info("initializing"); os_restarting_signal(SIGUSR1, usr1_handler); @@ -2302,7 +2332,7 @@ for (i = 1; i < argc; i++) else { /* Well, the trust list at least is up to scratch... */ - void *reset_point = store_get(0); + rmark reset_point = store_mark(); uschar *trusted_configs[32]; int nr_configs = 0; int i = 0; @@ -2332,30 +2362,22 @@ for (i = 1; i < argc; i++) &sep, big_buffer, big_buffer_size)) != NULL) { for (i=0; i < nr_configs; i++) - { if (Ustrcmp(filename, trusted_configs[i]) == 0) break; - } if (i == nr_configs) { f.trusted_config = FALSE; break; } } - store_reset(reset_point); } - else - { - /* No valid prefixes found in trust_list file. */ + else /* No valid prefixes found in trust_list file. */ f.trusted_config = FALSE; - } + store_reset(reset_point); } } - else - { - /* Could not open trust_list file. */ + else /* Could not open trust_list file. */ f.trusted_config = FALSE; - } } #else /* Not root; don't trust config */ @@ -2410,8 +2432,8 @@ for (i = 1; i < argc; i++) if (clmacro_count >= MAX_CLMACROS) exim_fail("exim: too many -D options on command line\n"); - clmacros[clmacro_count++] = string_sprintf("-D%s=%s", m->name, - m->replacement); + clmacros[clmacro_count++] = + string_sprintf("-D%s=%s", m->name, m->replacement); } #endif break; @@ -2521,7 +2543,7 @@ for (i = 1; i < argc; i++) { badarg = TRUE; break; } } if (*argrest == 0) - sender_address = string_sprintf(""); /* Ensure writeable memory */ + *(sender_address = store_get(1, FALSE)) = '\0'; /* Ensure writeable memory */ else { uschar *temp = argrest + Ustrlen(argrest) - 1; @@ -2534,6 +2556,7 @@ for (i = 1; i < argc; i++) #endif sender_address = parse_extract_address(argrest, &errmess, &dummy_start, &dummy_end, &sender_address_domain, TRUE); + sender_address = string_copy_taint(sender_address, TRUE); #ifdef SUPPORT_I18N message_smtputf8 = string_is_utf8(sender_address); allow_utf8_domains = FALSE; @@ -2646,7 +2669,7 @@ for (i = 1; i < argc; i++) exim_fail("exim: getsockname() failed after -MC option: %s\n", strerror(errno)); - if (f.running_in_test_harness) millisleep(500); + testharness_pause_ms(500); break; } @@ -2695,7 +2718,7 @@ for (i = 1; i < argc; i++) case 'S': smtp_peer_options |= OPTION_SIZE; break; -#ifdef SUPPORT_TLS +#ifndef DISABLE_TLS /* -MCt: similar to -MCT below but the connection is still open via a proxy process which handles the TLS context and coding. Require three arguments for the proxied local address and port, @@ -2721,16 +2744,6 @@ for (i = 1; i < argc; i++) break; } -#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_REQUIRETLS) - /* -MS set REQUIRETLS on (new) message */ - - else if (*argrest == 'S') - { - tls_requiretls |= REQUIRETLS_MSG; - break; - } -#endif - /* -M[x]: various operations on the following list of message ids: -M deliver the messages, ignoring next retry times and thawing -Mc deliver the messages, checking next retry times, no thawing @@ -2822,8 +2835,7 @@ for (i = 1; i < argc; i++) if (!one_msg_action) { - int j; - for (j = msg_action_arg; j < argc; j++) if (!mac_ismsgid(argv[j])) + for (int j = msg_action_arg; j < argc; j++) if (!mac_ismsgid(argv[j])) exim_fail("exim: malformed message id %s after %s option\n", argv[j], arg); goto END_ARG; /* Remaining args are ids */ @@ -2990,11 +3002,13 @@ for (i = 1; i < argc; i++) /* -oMas: setting authenticated sender */ - else if (Ustrcmp(argrest, "Mas") == 0) authenticated_sender = argv[++i]; + else if (Ustrcmp(argrest, "Mas") == 0) + authenticated_sender = string_copy_taint(argv[++i], TRUE); /* -oMai: setting authenticated id */ - else if (Ustrcmp(argrest, "Mai") == 0) authenticated_id = argv[++i]; + else if (Ustrcmp(argrest, "Mai") == 0) + authenticated_id = string_copy_taint(argv[++i], TRUE); /* -oMi: Set incoming interface address */ @@ -3022,7 +3036,8 @@ for (i = 1; i < argc; i++) /* -oMs: Set sender host name */ - else if (Ustrcmp(argrest, "Ms") == 0) sender_host_name = argv[++i]; + else if (Ustrcmp(argrest, "Ms") == 0) + sender_host_name = string_copy_taint(argv[++i], TRUE); /* -oMt: Set sender ident */ @@ -3187,22 +3202,23 @@ for (i = 1; i < argc; i++) /* -q[f][f][l][G]: Run the queue, optionally forced, optionally local only, optionally named, optionally starting from a given message id. */ - if (*argrest == 0 && - (i + 1 >= argc || argv[i+1][0] == '-' || mac_ismsgid(argv[i+1]))) - { - queue_interval = 0; - if (i+1 < argc && mac_ismsgid(argv[i+1])) - start_queue_run_id = argv[++i]; - if (i+1 < argc && mac_ismsgid(argv[i+1])) - stop_queue_run_id = argv[++i]; - } + if (!(list_queue || count_queue)) + if (*argrest == 0 + && (i + 1 >= argc || argv[i+1][0] == '-' || mac_ismsgid(argv[i+1]))) + { + queue_interval = 0; + if (i+1 < argc && mac_ismsgid(argv[i+1])) + start_queue_run_id = argv[++i]; + if (i+1 < argc && mac_ismsgid(argv[i+1])) + stop_queue_run_id = argv[++i]; + } /* -q[f][f][l][G/]: Run the queue at regular intervals, optionally forced, optionally local only, optionally named. */ - else if ((queue_interval = readconf_readtime(*argrest ? argrest : argv[++i], - 0, FALSE)) <= 0) - exim_fail("exim: bad time value %s: abandoned\n", argv[i]); + else if ((queue_interval = readconf_readtime(*argrest ? argrest : argv[++i], + 0, FALSE)) <= 0) + exim_fail("exim: bad time value %s: abandoned\n", argv[i]); break; @@ -3219,9 +3235,7 @@ for (i = 1; i < argc; i++) argument. */ if (*argrest != 0) - { - int i; - for (i = 0; i < nelem(rsopts); i++) + for (int i = 0; i < nelem(rsopts); i++) if (Ustrcmp(argrest, rsopts[i]) == 0) { if (i != 2) f.queue_run_force = TRUE; @@ -3229,7 +3243,6 @@ for (i = 1; i < argc; i++) if (i == 1 || i == 4) f.deliver_force_thaw = TRUE; argrest += Ustrlen(rsopts[i]); } - } /* -R: Set string to match in addresses for forced queue run to pick out particular messages. */ @@ -3261,9 +3274,7 @@ for (i = 1; i < argc; i++) argument. */ if (*argrest) - { - int i; - for (i = 0; i < nelem(rsopts); i++) + for (int i = 0; i < nelem(rsopts); i++) if (Ustrcmp(argrest, rsopts[i]) == 0) { if (i != 2) f.queue_run_force = TRUE; @@ -3271,7 +3282,6 @@ for (i = 1; i < argc; i++) if (i == 1 || i == 4) f.deliver_force_thaw = TRUE; argrest += Ustrlen(rsopts[i]); } - } /* -S: Set string to match in addresses for forced queue run to pick out particular messages. */ @@ -3312,7 +3322,7 @@ for (i = 1; i < argc; i++) /* -tls-on-connect: don't wait for STARTTLS (for old clients) */ - #ifdef SUPPORT_TLS + #ifndef DISABLE_TLS else if (Ustrcmp(argrest, "ls-on-connect") == 0) tls_in.on_connect = TRUE; #endif @@ -3458,7 +3468,7 @@ if (debug_selector != 0) debug_file = stderr; debug_fd = fileno(debug_file); f.background_daemon = FALSE; - if (f.running_in_test_harness) millisleep(100); /* lets caller finish */ + testharness_pause_ms(100); /* lets caller finish */ if (debug_selector != D_v) /* -v only doesn't show this */ { debug_printf("Exim version %s uid=%ld gid=%ld pid=%d D=%x\n", @@ -3680,7 +3690,18 @@ If any of these options is set, we suppress warnings about configuration issues (currently about tls_advertise_hosts and keep_environment not being defined) */ -readconf_main(checking || list_options); + { +#ifdef MEASURE_TIMING + struct timeval t0, diff; + (void)gettimeofday(&t0, NULL); +#endif + + readconf_main(checking || list_options); + +#ifdef MEASURE_TIMING + report_time_since(&t0, US"readconf_main (delta)"); +#endif + } /* Now in directory "/" */ @@ -3700,16 +3721,13 @@ for later interrogation. */ if (real_uid == root_uid || real_uid == exim_uid || real_gid == exim_gid) f.admin_user = TRUE; else - { - int i, j; - for (i = 0; i < group_count && !f.admin_user; i++) + for (int i = 0; i < group_count && !f.admin_user; i++) if (group_list[i] == exim_gid) f.admin_user = TRUE; else if (admin_groups) - for (j = 1; j <= (int)admin_groups[0] && !f.admin_user; j++) + for (int j = 1; j <= (int)admin_groups[0] && !f.admin_user; j++) if (admin_groups[j] == group_list[i]) f.admin_user = TRUE; - } /* Another group of privileged users are the trusted users. These are root, exim, and any caller matching trusted_users or trusted_groups. Trusted callers @@ -3720,18 +3738,16 @@ if (real_uid == root_uid || real_uid == exim_uid) f.trusted_caller = TRUE; else { - int i, j; - if (trusted_users) - for (i = 1; i <= (int)trusted_users[0] && !f.trusted_caller; i++) + for (int i = 1; i <= (int)trusted_users[0] && !f.trusted_caller; i++) if (trusted_users[i] == real_uid) f.trusted_caller = TRUE; if (trusted_groups) - for (i = 1; i <= (int)trusted_groups[0] && !f.trusted_caller; i++) + for (int i = 1; i <= (int)trusted_groups[0] && !f.trusted_caller; i++) if (trusted_groups[i] == real_gid) f.trusted_caller = TRUE; - else for (j = 0; j < group_count && !f.trusted_caller; j++) + else for (int j = 0; j < group_count && !f.trusted_caller; j++) if (trusted_groups[i] == group_list[j]) f.trusted_caller = TRUE; } @@ -3749,10 +3765,9 @@ decode_bits(log_selector, log_selector_size, log_notall, DEBUG(D_any) { - int i; debug_printf("configuration file is %s\n", config_main_filename); debug_printf("log selectors ="); - for (i = 0; i < log_selector_size; i++) + for (int i = 0; i < log_selector_size; i++) debug_printf(" %08x", log_selector[i]); debug_printf("\n"); } @@ -3829,9 +3844,7 @@ EXIM_TMPDIR by the build scripts. */ #ifdef EXIM_TMPDIR - { - uschar **p; - if (environ) for (p = USS environ; *p; p++) + if (environ) for (uschar ** p = USS environ; *p; p++) if (Ustrncmp(*p, "TMPDIR=", 7) == 0 && Ustrcmp(*p+7, EXIM_TMPDIR) != 0) { uschar * newp = store_malloc(Ustrlen(EXIM_TMPDIR) + 8); @@ -3839,7 +3852,6 @@ EXIM_TMPDIR by the build scripts. *p = newp; DEBUG(D_any) debug_printf("reset TMPDIR=%s in environment\n", EXIM_TMPDIR); } - } #endif /* Timezone handling. If timezone_string is "utc", set a flag to cause all @@ -3941,9 +3953,8 @@ verifying/testing addresses or expansions. */ if ( (debug_selector & D_any || LOGGING(arguments)) && f.really_exim && !list_options && !checking) { - int i; uschar *p = big_buffer; - Ustrcpy(p, "cwd= (failed)"); + Ustrcpy(p, US"cwd= (failed)"); if (!initial_cwd) p += 13; @@ -3958,16 +3969,16 @@ if ( (debug_selector & D_any || LOGGING(arguments)) (void)string_format(p, big_buffer_size - (p - big_buffer), " %d args:", argc); while (*p) p++; - for (i = 0; i < argc; i++) + for (int i = 0; i < argc; i++) { int len = Ustrlen(argv[i]); const uschar *printing; uschar *quote; if (p + len + 8 >= big_buffer + big_buffer_size) { - Ustrcpy(p, " ..."); + Ustrcpy(p, US" ..."); log_write(0, LOG_MAIN, "%s", big_buffer); - Ustrcpy(big_buffer, "..."); + Ustrcpy(big_buffer, US"..."); p = big_buffer + 3; } printing = string_printing(argv[i]); @@ -4205,6 +4216,7 @@ if (!unprivileged && /* originally had root AND */ else { int rv; + DEBUG(D_any) debug_printf("dropping to exim gid; retaining priv uid\n"); rv = setgid(exim_gid); /* Impact of failure is that some stuff might end up with an incorrect group. We track this for failures from root, since any attempt to change privilege @@ -4297,16 +4309,18 @@ if (msg_action_arg > 0 && msg_action != MSG_DELIVER && msg_action != MSG_LOAD) Now, since the intro of the ${acl } expansion, ACL definitions may be needed in transports so we lost the optimisation. */ -readconf_rest(); + { +#ifdef MEASURE_TIMING + struct timeval t0, diff; + (void)gettimeofday(&t0, NULL); +#endif -/* The configuration data will have been read into POOL_PERM because we won't -ever want to reset back past it. Change the current pool to POOL_MAIN. In fact, -this is just a bit of pedantic tidiness. It wouldn't really matter if the -configuration were read into POOL_MAIN, because we don't do any resets till -later on. However, it seems right, and it does ensure that both pools get used. -*/ + readconf_rest(); -store_pool = POOL_MAIN; +#ifdef MEASURE_TIMING + report_time_since(&t0, US"readconf_rest (delta)"); +#endif + } /* Handle the -brt option. This is for checking out retry configurations. The next three arguments are a domain name or a complete address, and @@ -4376,7 +4390,6 @@ if (test_retry_arg >= 0) printf("No retry information found\n"); else { - retry_rule *r; more_errno = yield->more_errno; printf("Retry rule: %s ", yield->pattern); @@ -4406,7 +4419,7 @@ if (test_retry_arg >= 0) printf("auth_failed "); else printf("* "); - for (r = yield->rules; r; r = r->next) + for (retry_rule * r = yield->rules; r; r = r->next) { printf("%c,%s", r->rule, readconf_printtime(r->timeout)); /* Do not */ printf(",%s", readconf_printtime(r->p1)); /* amalgamate */ @@ -4467,12 +4480,9 @@ if (list_config) } -/* Initialise subsystems as required */ -#ifndef DISABLE_DKIM -dkim_exim_init(); -#endif -deliver_init(); +/* Initialise subsystems as required. */ +tcp_init(); /* Handle a request to deliver one or more messages that are already on the queue. Values of msg_action other than MSG_DELIVER and MSG_LOAD are dealt with @@ -4505,7 +4515,7 @@ if (msg_action_arg > 0 && msg_action != MSG_LOAD) else if ((pid = fork()) == 0) { (void)deliver_message(argv[i], forced_delivery, deliver_give_up); - _exit(EXIT_SUCCESS); + exim_underbar_exit(EXIT_SUCCESS); } else if (pid < 0) { @@ -4667,6 +4677,21 @@ if (f.daemon_listen || f.inetd_wait_mode || queue_interval > 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Daemon cannot be run when " "mua_wrapper is set"); } + + /* This also checks that the library linkage is working and we can call + routines in it, so call even if tls_require_ciphers is unset */ + { +#ifdef MEASURE_TIMING + struct timeval t0, diff; + (void)gettimeofday(&t0, NULL); +#endif + if (!tls_dropprivs_validate_require_cipher(FALSE)) + exit(1); +#ifdef MEASURE_TIMING + report_time_since(&t0, US"validate_ciphers (delta)"); +#endif + } + daemon_go(); } @@ -4674,8 +4699,8 @@ if (f.daemon_listen || f.inetd_wait_mode || queue_interval > 0) the caller. This will get overwritten below for an inetd call. If a trusted caller has set it empty, unset it. */ -if (sender_ident == NULL) sender_ident = originator_login; - else if (sender_ident[0] == 0) sender_ident = NULL; +if (!sender_ident) sender_ident = originator_login; +else if (!*sender_ident) sender_ident = NULL; /* Handle the -brw option, which is for checking out rewriting rules. Cause log writes (on errors) to go to stderr instead. Can't do this earlier, as want the @@ -4697,8 +4722,8 @@ if (test_rewrite_arg >= 0) unless a trusted caller supplies a sender address with -f, or is passing in the message via SMTP (inetd invocation or otherwise). */ -if ((sender_address == NULL && !smtp_input) || - (!f.trusted_caller && filter_test == FTEST_NONE)) +if ( !sender_address && !smtp_input + || !f.trusted_caller && filter_test == FTEST_NONE) { f.sender_local = TRUE; @@ -4706,10 +4731,10 @@ if ((sender_address == NULL && !smtp_input) || via -oMas and -oMai and if so, they will already be set. Otherwise, force defaults except when host checking. */ - if (authenticated_sender == NULL && !host_checking) + if (!authenticated_sender && !host_checking) authenticated_sender = string_sprintf("%s@%s", originator_login, qualify_domain_sender); - if (authenticated_id == NULL && !host_checking) + if (!authenticated_id && !host_checking) authenticated_id = originator_login; } @@ -4719,8 +4744,8 @@ is specified is the empty address. However, if a trusted caller does not specify a sender address for SMTP input, we leave sender_address unset. This causes the MAIL commands to be honoured. */ -if ((!smtp_input && sender_address == NULL) || - !receive_check_set_sender(sender_address)) +if ( !smtp_input && !sender_address + || !receive_check_set_sender(sender_address)) { /* Either the caller is not permitted to set a general sender, or this is non-SMTP input and the trusted caller has not set a sender. If there is no @@ -4746,8 +4771,7 @@ f.sender_set_untrusted = sender_address != originator_login && !f.trusted_caller address, which indicates an error message, or doesn't exist (root caller, smtp interface, no -f argument). */ -if (sender_address != NULL && sender_address[0] != 0 && - sender_address_domain == 0) +if (sender_address && *sender_address && sender_address_domain == 0) sender_address = string_sprintf("%s@%s", local_part_quote(sender_address), qualify_domain_sender); @@ -4937,7 +4961,7 @@ if (host_checking) it. The code works for both IPv4 and IPv6, as it happens. */ size = host_aton(sender_host_address, x); - sender_host_address = store_get(48); /* large enough for full IPv6 */ + sender_host_address = store_get(48, FALSE); /* large enough for full IPv6 */ (void)host_nmtoa(size, x, -1, sender_host_address, ':'); /* Now set up for testing */ @@ -4967,7 +4991,7 @@ if (host_checking) if (smtp_start_session()) { - for (reset_point = store_get(0); ; store_reset(reset_point)) + for (; (reset_point = store_mark()); store_reset(reset_point)) { if (smtp_setup_msg() <= 0) break; if (!receive_msg(FALSE)) break; @@ -5210,7 +5234,6 @@ if (!f.synchronous_delivery) /* Save the current store pool point, for resetting at the start of each message, and save the real sender address, if any. */ -reset_point = store_get(0); real_sender_address = sender_address; /* Loop to receive messages; receive_msg() returns TRUE if there are more @@ -5219,6 +5242,7 @@ collapsed). */ while (more) { + reset_point = store_mark(); message_id[0] = 0; /* Handle the SMTP case; call smtp_setup_mst() to deal with the initial SMTP @@ -5282,7 +5306,6 @@ while (more) else { - int i; int rcount = 0; int count = argc - recipients_arg; uschar **list = argv + recipients_arg; @@ -5298,7 +5321,7 @@ while (more) /* Loop for each argument */ - for (i = 0; i < count; i++) + for (int i = 0; i < count; i++) { int start, end, domain; uschar *errmess; @@ -5369,7 +5392,7 @@ while (more) } } - receive_add_recipient(recipient, -1); + receive_add_recipient(string_copy_taint(recipient, TRUE), -1); s = ss; if (!finished) while (*(++s) != 0 && (*s == ',' || isspace(*s))); @@ -5380,12 +5403,11 @@ while (more) DEBUG(D_receive) { - int i; if (sender_address != NULL) debug_printf("Sender: %s\n", sender_address); if (recipients_list != NULL) { debug_printf("Recipients:\n"); - for (i = 0; i < recipients_count; i++) + for (int i = 0; i < recipients_count; i++) debug_printf(" %s\n", recipients_list[i].address); } } @@ -5592,8 +5614,8 @@ while (more) rc = deliver_message(message_id, FALSE, FALSE); search_tidyup(); - _exit((!mua_wrapper || rc == DELIVER_MUA_SUCCEEDED)? - EXIT_SUCCESS : EXIT_FAILURE); + exim_underbar_exit(!mua_wrapper || rc == DELIVER_MUA_SUCCEEDED + ? EXIT_SUCCESS : EXIT_FAILURE); } if (pid < 0) @@ -5644,7 +5666,7 @@ moreloop: callout_address = NULL; sending_ip_address = NULL; acl_var_m = NULL; - { int i; for(i=0; i