X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/863bd541063e72fcea7305b9d3ee2cb460a6d3d1..ee25093663e5a72df66ba5b2c2934ea844a12133:/src/src/exim.c diff --git a/src/src/exim.c b/src/src/exim.c index a6a1ea82c..e15864839 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -12,7 +12,7 @@ Also a few functions that don't naturally fit elsewhere. */ #include "exim.h" -#ifdef __GLIBC__ +#if defined(__GLIBC__) && !defined(__UCLIBC__) # include #endif @@ -212,8 +212,7 @@ int fd; os_restarting_signal(sig, usr1_handler); -fd = Uopen(process_log_path, O_APPEND|O_WRONLY, LOG_MODE); -if (fd < 0) +if ((fd = Uopen(process_log_path, O_APPEND|O_WRONLY, LOG_MODE)) < 0) { /* If we are already running as the Exim user, try to create it in the current process (assuming spool_directory exists). Otherwise, if we are @@ -345,7 +344,7 @@ Arguments: Returns: -1, 0, or +1 */ -int +static int exim_tvcmp(struct timeval *t1, struct timeval *t2) { if (t1->tv_sec > t2->tv_sec) return +1; @@ -659,12 +658,13 @@ Returns: does not return */ void -exim_exit(int rc) +exim_exit(int rc, const uschar * process) { search_tidyup(); DEBUG(D_any) - debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d terminating with rc=%d " - ">>>>>>>>>>>>>>>>\n", (int)getpid(), rc); + debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d %s%s%sterminating with rc=%d " + ">>>>>>>>>>>>>>>>\n", (int)getpid(), + process ? "(" : "", process, process ? ") " : "", rc); exit(rc); } @@ -841,7 +841,8 @@ fprintf(f, "Support for:"); fprintf(f, " SOCKS"); #endif #ifdef TCP_FASTOPEN - fprintf(f, " TCP_Fast_Open"); + deliver_init(); + if (tcp_fastopen_ok) fprintf(f, " TCP_Fast_Open"); #endif #ifdef EXPERIMENTAL_LMDB fprintf(f, " Experimental_LMDB"); @@ -1044,7 +1045,7 @@ DEBUG(D_any) do { fprintf(f, "Compiler: \n"); #endif -#ifdef __GLIBC__ +#if defined(__GLIBC__) && !defined(__UCLIBC__) fprintf(f, "Library version: Glibc: Compile: %d.%d\n", __GLIBC__, __GLIBC_MINOR__); if (__GLIBC_PREREQ(2, 1)) @@ -1150,8 +1151,7 @@ uschar * local_part_quote(uschar *lpart) { BOOL needs_quote = FALSE; -int size, ptr; -uschar *yield; +gstring * g; uschar *t; for (t = lpart; !needs_quote && *t != 0; t++) @@ -1162,26 +1162,24 @@ for (t = lpart; !needs_quote && *t != 0; t++) if (!needs_quote) return lpart; -size = ptr = 0; -yield = string_catn(NULL, &size, &ptr, US"\"", 1); +g = string_catn(NULL, US"\"", 1); for (;;) { uschar *nq = US Ustrpbrk(lpart, "\\\""); if (nq == NULL) { - yield = string_cat(yield, &size, &ptr, lpart); + g = string_cat(g, lpart); break; } - 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); + g = string_catn(g, lpart, nq - lpart); + g = string_catn(g, US"\\", 1); + g = string_catn(g, nq, 1); lpart = nq + 1; } -yield = string_catn(yield, &size, &ptr, US"\"", 1); -yield[ptr] = 0; -return yield; +g = string_catn(g, US"\"", 1); +return string_from_gstring(g); } @@ -1254,11 +1252,9 @@ static uschar * get_stdinput(char *(*fn_readline)(const char *), void(*fn_addhist)(const char *)) { int i; -int size = 0; -int ptr = 0; -uschar *yield = NULL; +gstring * g = NULL; -if (fn_readline == NULL) { printf("> "); fflush(stdout); } +if (!fn_readline) { printf("> "); fflush(stdout); } for (i = 0;; i++) { @@ -1293,23 +1289,22 @@ for (i = 0;; i++) while (p < ss && isspace(*p)) p++; /* leading space after cont */ } - yield = string_catn(yield, &size, &ptr, p, ss - p); + g = string_catn(g, p, ss - p); #ifdef USE_READLINE - if (fn_readline != NULL) free(readline_line); + if (fn_readline) free(readline_line); #endif - /* yield can only be NULL if ss==p */ - if (ss == p || yield[ptr-1] != '\\') - { - if (yield) yield[ptr] = 0; + /* g can only be NULL if ss==p */ + if (ss == p || g->s[g->ptr-1] != '\\') break; - } - yield[--ptr] = 0; + + --g->ptr; + (void) string_from_gstring(g); } -if (yield == NULL) printf("\n"); -return yield; +if (!g) printf("\n"); +return string_from_gstring(g); } @@ -1443,10 +1438,9 @@ for (m = macros; m; m = m->next) if (m->command_line) } if (!found) return FALSE; - if (m->replacement == NULL) + if (!m->replacement) continue; - len = Ustrlen(m->replacement); - if (len == 0) + if ((len = m->replen) == 0) continue; n = pcre_exec(regex_whitelisted_macro, NULL, CS m->replacement, len, 0, PCRE_EOPT, NULL, 0); @@ -2457,7 +2451,7 @@ for (i = 1; i < argc; i++) exit(EXIT_FAILURE); } - m = macro_create(name, s, TRUE, FALSE); + m = macro_create(string_copy(name), string_copy(s), TRUE); if (clmacro_count >= MAX_CLMACROS) { @@ -2708,18 +2702,19 @@ for (i = 1; i < argc; i++) return EXIT_FAILURE; } - /* Set up $sending_ip_address and $sending_port */ + /* Set up $sending_ip_address and $sending_port, unless proxied */ - if (getsockname(fileno(stdin), (struct sockaddr *)(&interface_sock), - &size) == 0) - sending_ip_address = host_ntoa(-1, &interface_sock, NULL, - &sending_port); - else - { - fprintf(stderr, "exim: getsockname() failed after -MC option: %s\n", - strerror(errno)); - return EXIT_FAILURE; - } + if (!continue_proxy_cipher) + if (getsockname(fileno(stdin), (struct sockaddr *)(&interface_sock), + &size) == 0) + sending_ip_address = host_ntoa(-1, &interface_sock, NULL, + &sending_port); + else + { + fprintf(stderr, "exim: getsockname() failed after -MC option: %s\n", + strerror(errno)); + return EXIT_FAILURE; + } if (running_in_test_harness) millisleep(500); break; @@ -2727,7 +2722,7 @@ for (i = 1; i < argc; i++) else if (*argrest == 'C' && argrest[1] && !argrest[2]) { - switch(argrest[1]) + switch(argrest[1]) { /* -MCA: set the smtp_authenticated flag; this is useful only when it precedes -MC (see above). The flag indicates that the host to which @@ -2738,7 +2733,7 @@ for (i = 1; i < argc; i++) /* -MCD: set the smtp_use_dsn flag; this indicates that the host that exim is connected to supports the esmtp extension DSN */ - case 'D': smtp_peer_options |= PEER_OFFERED_DSN; break; + case 'D': smtp_peer_options |= OPTION_DSN; break; /* -MCG: set the queue name, to a non-default value */ @@ -2748,12 +2743,12 @@ for (i = 1; i < argc; i++) /* -MCK: the peer offered CHUNKING. Must precede -MC */ - case 'K': smtp_peer_options |= PEER_OFFERED_CHUNKING; break; + case 'K': smtp_peer_options |= OPTION_CHUNKING; break; /* -MCP: set the smtp_use_pipelining flag; this is useful only when it preceded -MC (see above) */ - case 'P': smtp_peer_options |= PEER_OFFERED_PIPE; break; + case 'P': smtp_peer_options |= OPTION_PIPE; break; /* -MCQ: pass on the pid of the queue-running process that started this chain of deliveries and the fd of its synchronizing pipe; this @@ -2768,14 +2763,27 @@ for (i = 1; i < argc; i++) /* -MCS: set the smtp_use_size flag; this is useful only when it precedes -MC (see above) */ - case 'S': smtp_peer_options |= PEER_OFFERED_SIZE; break; + case 'S': smtp_peer_options |= OPTION_SIZE; break; #ifdef SUPPORT_TLS + /* -MCt: similar to -MCT below but the connection is still open + via a proxy proces which handles the TLS context and coding. + Require three arguments for the proxied local address and port, + and the TLS cipher. */ + + case 't': if (++i < argc) sending_ip_address = argv[i]; + else badarg = TRUE; + if (++i < argc) sending_port = (int)(Uatol(argv[i])); + else badarg = TRUE; + if (++i < argc) continue_proxy_cipher = argv[i]; + else badarg = TRUE; + /*FALLTHROUGH*/ + /* -MCT: set the tls_offered flag; this is useful only when it precedes -MC (see above). The flag indicates that the host to which Exim is connected has offered TLS support. */ - case 'T': smtp_peer_options |= PEER_OFFERED_TLS; break; + case 'T': smtp_peer_options |= OPTION_TLS; break; #endif default: badarg = TRUE; break; @@ -3092,7 +3100,14 @@ for (i = 1; i < argc; i++) /* -oMr: Received protocol */ - else if (Ustrcmp(argrest, "Mr") == 0) received_protocol = argv[++i]; + else if (Ustrcmp(argrest, "Mr") == 0) + + if (received_protocol) + { + fprintf(stderr, "received_protocol is set already\n"); + exit(EXIT_FAILURE); + } + else received_protocol = argv[++i]; /* -oMs: Set sender host name */ @@ -3188,7 +3203,15 @@ for (i = 1; i < argc; i++) if (*argrest != 0) { - uschar *hn = Ustrchr(argrest, ':'); + uschar *hn; + + if (received_protocol) + { + fprintf(stderr, "received_protocol is set already\n"); + exit(EXIT_FAILURE); + } + + hn = Ustrchr(argrest, ':'); if (hn == NULL) { received_protocol = argrest; @@ -3797,6 +3820,10 @@ defined) */ readconf_main(checking || list_options); +if (builtin_macros_create_trigger) DEBUG(D_any) + debug_printf("Builtin macros created (expensive) due to config line '%.*s'\n", + Ustrlen(builtin_macros_create_trigger)-1, builtin_macros_create_trigger); + /* Now in directory "/" */ if (cleanup_environment() == FALSE) @@ -3816,17 +3843,13 @@ if (real_uid == root_uid || real_uid == exim_uid || real_gid == exim_gid) else { int i, j; - for (i = 0; i < group_count; i++) - { - if (group_list[i] == exim_gid) admin_user = TRUE; - else if (admin_groups != NULL) - { - for (j = 1; j <= (int)(admin_groups[0]); j++) + for (i = 0; i < group_count && !admin_user; i++) + if (group_list[i] == exim_gid) + admin_user = TRUE; + else if (admin_groups) + for (j = 1; j <= (int)admin_groups[0] && !admin_user; j++) if (admin_groups[j] == group_list[i]) - { admin_user = TRUE; break; } - } - if (admin_user) break; - } + admin_user = TRUE; } /* Another group of privileged users are the trusted users. These are root, @@ -3840,29 +3863,28 @@ else { int i, j; - if (trusted_users != NULL) - { - for (i = 1; i <= (int)(trusted_users[0]); i++) + if (trusted_users) + for (i = 1; i <= (int)trusted_users[0] && !trusted_caller; i++) if (trusted_users[i] == real_uid) - { trusted_caller = TRUE; break; } - } + trusted_caller = TRUE; - if (!trusted_caller && trusted_groups != NULL) - { - for (i = 1; i <= (int)(trusted_groups[0]); i++) - { + if (trusted_groups) + for (i = 1; i <= (int)trusted_groups[0] && !trusted_caller; i++) if (trusted_groups[i] == real_gid) trusted_caller = TRUE; - else for (j = 0; j < group_count; j++) - { + else for (j = 0; j < group_count && !trusted_caller; j++) if (trusted_groups[i] == group_list[j]) - { trusted_caller = TRUE; break; } - } - if (trusted_caller) break; - } - } + trusted_caller = TRUE; } +/* At this point, we know if the user is privileged and some command-line +options become possibly imperssible, depending upon the configuration file. */ + +if (checking && commandline_checks_require_admin && !admin_user) { + fprintf(stderr, "exim: those command-line flags are set to require admin\n"); + exit(EXIT_FAILURE); +} + /* Handle the decoding of logging options. */ decode_bits(log_selector, log_selector_size, log_notall, @@ -4105,9 +4127,8 @@ if (((debug_selector & D_any) != 0 || LOGGING(arguments)) quote = US""; while (*pp != 0) if (isspace(*pp++)) { quote = US"\""; break; } } - sprintf(CS p, " %s%.*s%s", quote, (int)(big_buffer_size - + p += sprintf(CS p, " %s%.*s%s", quote, (int)(big_buffer_size - (p - big_buffer) - 4), printing, quote); - while (*p) p++; } if (LOGGING(arguments)) @@ -4128,6 +4149,7 @@ if (Uchdir(spool_directory) != 0) int dummy; (void)directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE); dummy = /* quieten compiler */ Uchdir(spool_directory); + dummy = dummy; /* yet more compiler quietening, sigh */ } /* Handle calls with the -bi option. This is a sendmail option to rebuild *the* @@ -4338,11 +4360,8 @@ if (!unprivileged && /* originally had root AND */ (msg_action_arg < 0 || /* and */ msg_action != MSG_DELIVER) && /* not delivering and */ (!checking || !address_test_mode) /* not address checking */ - ) - )) - { + ) ) ) exim_setugid(exim_uid, exim_gid, TRUE, US"privilege not needed"); - } /* When we are retaining a privileged uid, we still change to the exim gid. */ @@ -4356,7 +4375,6 @@ else there's no security risk. For me, it's { exim -bV } on a just-built binary, no need to complain then. */ if (rv == -1) - { if (!(unprivileged || removed_privilege)) { fprintf(stderr, @@ -4366,7 +4384,6 @@ else else DEBUG(D_any) debug_printf("changing group to %ld failed: %s\n", (long int)exim_gid, strerror(errno)); - } } /* Handle a request to scan a file for malware */ @@ -4467,7 +4484,7 @@ if (test_retry_arg >= 0) if (test_retry_arg >= argc) { printf("-brt needs a domain or address argument\n"); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } s1 = argv[test_retry_arg++]; s2 = NULL; @@ -4516,8 +4533,9 @@ if (test_retry_arg >= 0) } } - yield = retry_find_config(s1, s2, basic_errno, more_errno); - if (yield == NULL) printf("No retry information found\n"); else + if (!(yield = retry_find_config(s1, s2, basic_errno, more_errno))) + printf("No retry information found\n"); + else { retry_rule *r; more_errno = yield->more_errno; @@ -4549,7 +4567,7 @@ if (test_retry_arg >= 0) printf("auth_failed "); else printf("* "); - for (r = yield->rules; r != NULL; r = r->next) + for (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 */ @@ -4572,7 +4590,7 @@ if (test_retry_arg >= 0) printf("\n"); } - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } /* Handle a request to list one or more configuration options */ @@ -4596,14 +4614,14 @@ if (list_options) } else readconf_print(argv[i], NULL, flag_n); } - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } if (list_config) { set_process_info("listing config"); readconf_print(US"config", NULL, flag_n); - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } @@ -4632,7 +4650,7 @@ if (msg_action_arg > 0 && msg_action != MSG_LOAD) if (prod_requires_admin && !admin_user) { fprintf(stderr, "exim: Permission denied\n"); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } set_process_info("delivering specified messages"); if (deliver_give_up) forced_delivery = deliver_force_thaw = TRUE; @@ -4651,11 +4669,11 @@ if (msg_action_arg > 0 && msg_action != MSG_LOAD) { fprintf(stderr, "failed to fork delivery process for %s: %s\n", argv[i], strerror(errno)); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } else wait(&status); } - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } @@ -4674,7 +4692,7 @@ if (queue_interval == 0 && !daemon_listen) else set_process_info("running the queue (single queue run)"); queue_run(start_queue_run_id, stop_queue_run_id, FALSE); - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } @@ -4697,10 +4715,9 @@ for (i = 0;;) /* If user name has not been set by -F, set it from the passwd entry unless -f has been used to set the sender address by a trusted user. */ - if (originator_name == NULL) + if (!originator_name) { - if (sender_address == NULL || - (!trusted_caller && filter_test == FTEST_NONE)) + if (!sender_address || (!trusted_caller && filter_test == FTEST_NONE)) { uschar *name = US pw->pw_gecos; uschar *amp = Ustrchr(name, '&'); @@ -4710,11 +4727,11 @@ for (i = 0;;) replaced by a copy of the login name, and some even specify that the first character should be upper cased, so that's what we do. */ - if (amp != NULL) + if (amp) { int loffset; string_format(buffer, sizeof(buffer), "%.*s%n%s%s", - amp - name, name, &loffset, originator_login, amp + 1); + (int)(amp - name), name, &loffset, originator_login, amp + 1); buffer[loffset] = toupper(buffer[loffset]); name = buffer; } @@ -4722,7 +4739,7 @@ for (i = 0;;) /* If a pattern for matching the gecos field was supplied, apply it and then expand the name string. */ - if (gecos_pattern != NULL && gecos_name != NULL) + if (gecos_pattern && gecos_name) { const pcre *re; re = regex_must_compile(gecos_pattern, FALSE, TRUE); /* Use malloc */ @@ -4731,7 +4748,7 @@ for (i = 0;;) { uschar *new_name = expand_string(gecos_name); expand_nmax = -1; - if (new_name != NULL) + if (new_name) { DEBUG(D_receive) debug_printf("user name \"%s\" extracted from " "gecos field \"%s\"\n", new_name, name); @@ -4828,10 +4845,10 @@ if (test_rewrite_arg >= 0) if (test_rewrite_arg >= argc) { printf("-brw needs an address argument\n"); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } rewrite_test(argv[test_rewrite_arg]); - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } /* A locally-supplied message is considered to be coming from a local user @@ -4946,7 +4963,7 @@ if (verify_address_mode || address_test_mode) } route_tidyup(); - exim_exit(exit_value); + exim_exit(exit_value, US"main"); } /* Handle expansion checking. Either expand items on the command line, or read @@ -5048,7 +5065,7 @@ if (expansion_test) deliver_datafile = -1; } - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } @@ -5142,7 +5159,7 @@ if (host_checking) } smtp_log_no_mail(); } - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } @@ -5306,7 +5323,7 @@ if (smtp_input) if (!smtp_start_session()) { mac_smtp_fflush(); - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"smtp_start toplevel"); } } @@ -5315,15 +5332,13 @@ if (smtp_input) else { thismessage_size_limit = expand_string_integer(message_size_limit, TRUE); - if (expand_string_message != NULL) - { + if (expand_string_message) if (thismessage_size_limit == -1) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand " "message_size_limit: %s", expand_string_message); else log_write(0, LOG_MAIN|LOG_PANIC_DIE, "invalid value for " "message_size_limit: %s", expand_string_message); - } } /* Loop for several messages when reading SMTP input. If we fork any child @@ -5420,15 +5435,17 @@ while (more) more = receive_msg(extract_recipients); if (message_id[0] == 0) { + cancel_cutthrough_connection(TRUE, US"receive dropped"); if (more) goto moreloop; smtp_log_no_mail(); /* Log no mail if configured */ - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"receive toplevel"); } } else { + cancel_cutthrough_connection(TRUE, US"message setup dropped"); smtp_log_no_mail(); /* Log no mail if configured */ - exim_exit((rc == 0)? EXIT_SUCCESS : EXIT_FAILURE); + exim_exit(rc ? EXIT_FAILURE : EXIT_SUCCESS, US"msg setup toplevel"); } } @@ -5479,14 +5496,12 @@ while (more) if (error_handling == ERRORS_STDERR) { fprintf(stderr, "exim: too many recipients\n"); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } else - { return moan_to_sender(ERRMESS_TOOMANYRECIP, NULL, NULL, stdin, TRUE)? errors_sender_rc : EXIT_FAILURE; - } #ifdef SUPPORT_I18N { @@ -5515,7 +5530,7 @@ while (more) { fprintf(stderr, "exim: bad recipient address \"%s\": %s\n", string_printing(list[i]), errmess); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } else { @@ -5570,7 +5585,7 @@ while (more) if (!receive_timeout) { - struct timeval t = { 30*60, 0 }; /* 30 minutes */ + struct timeval t = { .tv_sec = 30*60, .tv_usec = 0 }; /* 30 minutes */ fd_set r; FD_ZERO(&r); FD_SET(0, &r); @@ -5588,7 +5603,7 @@ while (more) for real; when reading the headers of a message for filter testing, it is TRUE if the headers were terminated by '.' and FALSE otherwise. */ - if (message_id[0] == 0) exim_exit(EXIT_FAILURE); + if (message_id[0] == 0) exim_exit(EXIT_FAILURE, US"main"); } /* Non-SMTP message reception */ /* If this is a filter testing run, there are headers in store, but @@ -5633,7 +5648,7 @@ while (more) if (chdir("/")) /* Get away from wherever the user is running this from */ { DEBUG(D_receive) debug_printf("chdir(\"/\") failed\n"); - exim_exit(EXIT_FAILURE); + exim_exit(EXIT_FAILURE, US"main"); } /* Now we run either a system filter test, or a user filter test, or both. @@ -5642,20 +5657,16 @@ while (more) explicitly. */ if ((filter_test & FTEST_SYSTEM) != 0) - { if (!filter_runtest(filter_sfd, filter_test_sfile, TRUE, more)) - exim_exit(EXIT_FAILURE); - } + exim_exit(EXIT_FAILURE, US"main"); memcpy(filter_sn, filter_n, sizeof(filter_sn)); if ((filter_test & FTEST_USER) != 0) - { if (!filter_runtest(filter_ufd, filter_test_ufile, FALSE, more)) - exim_exit(EXIT_FAILURE); - } + exim_exit(EXIT_FAILURE, US"main"); - exim_exit(EXIT_SUCCESS); + exim_exit(EXIT_SUCCESS, US"main"); } /* Else act on the result of message reception. We should not get here unless @@ -5702,21 +5713,28 @@ while (more) not if queue_only is set (case 0). Case 1 doesn't happen here (too many connections). */ - if (local_queue_only) switch(queue_only_reason) + if (local_queue_only) { - case 2: - log_write(L_delay_delivery, - LOG_MAIN, "no immediate delivery: more than %d messages " - "received in one connection", smtp_accept_queue_per_connection); - break; + cancel_cutthrough_connection(TRUE, US"no delivery; queueing"); + switch(queue_only_reason) + { + case 2: + log_write(L_delay_delivery, + LOG_MAIN, "no immediate delivery: more than %d messages " + "received in one connection", smtp_accept_queue_per_connection); + break; - case 3: - log_write(L_delay_delivery, - LOG_MAIN, "no immediate delivery: load average %.2f", - (double)load_average/1000.0); - break; + case 3: + log_write(L_delay_delivery, + LOG_MAIN, "no immediate delivery: load average %.2f", + (double)load_average/1000.0); + break; + } } + else if (queue_only_policy || deliver_freeze) + cancel_cutthrough_connection(TRUE, US"no delivery; queueing"); + /* Else do the delivery unless the ACL or local_scan() called for queue only or froze the message. Always deliver in a separate process. A fork failure is not a disaster, as the delivery will eventually happen on a subsequent queue @@ -5725,7 +5743,7 @@ while (more) thereby defer the delivery if it tries to use (for example) a cached ldap connection that the parent has called unbind on. */ - else if (!queue_only_policy && !deliver_freeze) + else { pid_t pid; search_tidyup(); @@ -5741,8 +5759,7 @@ while (more) if (geteuid() != root_uid && !deliver_drop_privilege && !unprivileged) { - (void)child_exec_exim(CEE_EXEC_EXIT, FALSE, NULL, FALSE, - 2, US"-Mc", message_id); + delivery_re_exec(CEE_EXEC_EXIT); /* Control does not return here. */ } @@ -5756,22 +5773,27 @@ while (more) if (pid < 0) { + cancel_cutthrough_connection(TRUE, US"delivery fork failed"); log_write(0, LOG_MAIN|LOG_PANIC, "failed to fork automatic delivery " "process: %s", strerror(errno)); } + else + { + release_cutthrough_connection(US"msg passed for delivery"); - /* In the parent, wait if synchronous delivery is required. This will - always be the case in MUA wrapper mode. */ + /* In the parent, wait if synchronous delivery is required. This will + always be the case in MUA wrapper mode. */ - else if (synchronous_delivery) - { - int status; - while (wait(&status) != pid); - if ((status & 0x00ff) != 0) - log_write(0, LOG_MAIN|LOG_PANIC, - "process %d crashed with signal %d while delivering %s", - (int)pid, status & 0x00ff, message_id); - if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE); + if (synchronous_delivery) + { + int status; + while (wait(&status) != pid); + if ((status & 0x00ff) != 0) + log_write(0, LOG_MAIN|LOG_PANIC, + "process %d crashed with signal %d while delivering %s", + (int)pid, status & 0x00ff, message_id); + if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE, US"main"); + } } } @@ -5802,8 +5824,9 @@ moreloop: store_reset(reset_point); } -exim_exit(EXIT_SUCCESS); /* Never returns */ +exim_exit(EXIT_SUCCESS, US"main"); /* Never returns */ return 0; /* To stop compiler warning */ } + /* End of exim.c */