X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/dec766a1977250758eb7a3e127e079a9271afd89..01603eec64d42431f182b33008206facfc7f800e:/src/src/daemon.c diff --git a/src/src/daemon.c b/src/src/daemon.c index 476ed296b..0b4d347b9 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -106,10 +106,10 @@ Returns: nothing static void never_error(uschar *log_msg, uschar *smtp_msg, int was_errno) { -uschar *emsg = (was_errno <= 0)? US"" : - string_sprintf(": %s", strerror(was_errno)); +uschar *emsg = was_errno <= 0 + ? US"" : string_sprintf(": %s", strerror(was_errno)); log_write(0, LOG_MAIN|LOG_PANIC, "%s%s", log_msg, emsg); -if (smtp_out != NULL) smtp_printf("421 %s\r\n", FALSE, smtp_msg); +if (smtp_out) smtp_printf("421 %s\r\n", FALSE, smtp_msg); } @@ -202,11 +202,11 @@ memory is reclaimed. */ whofrom = string_append(NULL, 3, "[", sender_host_address, "]"); if (LOGGING(incoming_port)) - whofrom = string_append(whofrom, 2, ":", string_sprintf("%d", sender_host_port)); + whofrom = string_fmt_append(whofrom, ":%d", sender_host_port); if (LOGGING(incoming_interface)) - whofrom = string_append(whofrom, 4, " I=[", - interface_address, "]:", string_sprintf("%d", interface_port)); + whofrom = string_fmt_append(whofrom, " I=[%s]:%d", + interface_address, interface_port); (void) string_from_gstring(whofrom); /* Terminate the newly-built string */ @@ -259,7 +259,7 @@ if (smtp_accept_max_per_host != NULL) uschar *expanded = expand_string(smtp_accept_max_per_host); if (expanded == NULL) { - if (!expand_string_forcedfail) + if (!f.expand_string_forcedfail) log_write(0, LOG_MAIN|LOG_PANIC, "expansion of smtp_accept_max_per_host " "failed for %s: %s", whofrom->s, expand_string_message); } @@ -282,11 +282,10 @@ count of *other* connections, not including this one. */ if ((max_for_this_host > 0) && (smtp_accept_count >= max_for_this_host)) { - int i; int host_accept_count = 0; int other_host_count = 0; /* keep a count of non matches to optimise */ - for (i = 0; i < smtp_accept_max; ++i) + for (int i = 0; i < smtp_accept_max; ++i) if (smtp_slots[i].host_address) { if (Ustrcmp(sender_host_address, smtp_slots[i].host_address) == 0) @@ -387,7 +386,7 @@ if (pid == 0) uschar * nah = expand_string(raw_active_hostname); if (!nah) { - if (!expand_string_forcedfail) + if (!f.expand_string_forcedfail) { log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand \"%s\" " "(smtp_active_hostname): %s", raw_active_hostname, @@ -441,7 +440,7 @@ if (pid == 0) finding the id, but turn it on again afterwards so that information about the incoming connection is output. */ - if (debug_daemon) debug_selector = 0; + if (f.debug_daemon) debug_selector = 0; verify_get_ident(IDENT_PORT); host_build_sender_fullhost(); debug_selector = save_debug_selector; @@ -453,7 +452,7 @@ if (pid == 0) /* Now disable debugging permanently if it's required only for the daemon process. */ - if (debug_daemon) debug_selector = 0; + if (f.debug_daemon) debug_selector = 0; /* If there are too many child processes for immediate delivery, set the session_local_queue_only flag, which is initialized from the @@ -518,13 +517,13 @@ if (pid == 0) { if (smtp_out) { - int i, fd = fileno(smtp_in); + int fd = fileno(smtp_in); uschar buf[128]; mac_smtp_fflush(); /* drain socket, for clean TCP FINs */ if (fcntl(fd, F_SETFL, O_NONBLOCK) == 0) - for(i = 16; read(fd, buf, sizeof(buf)) > 0 && i > 0; ) i--; + for(int i = 16; read(fd, buf, sizeof(buf)) > 0 && i > 0; ) i--; } cancel_cutthrough_connection(TRUE, US"message setup dropped"); search_tidyup(); @@ -540,13 +539,12 @@ if (pid == 0) DEBUG(D_receive) { - int i; if (sender_address) debug_printf("Sender: %s\n", sender_address); if (recipients_list) { 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); } } @@ -563,18 +561,13 @@ if (pid == 0) /* Reclaim up the store used in accepting this message */ - return_path = sender_address = NULL; - authenticated_sender = NULL; - sending_ip_address = NULL; - deliver_host_address = deliver_host = - deliver_domain_orig = deliver_localpart_orig = NULL; - dnslist_domain = dnslist_matched = NULL; - callout_address = NULL; -#ifndef DISABLE_DKIM - dkim_cur_signer = NULL; -#endif - acl_var_m = NULL; - store_reset(reset_point); + { + int r = receive_messagecount; + BOOL q = f.queue_only_policy; + smtp_reset(reset_point); + f.queue_only_policy = q; + receive_messagecount = r; + } /* If queue_only is set or if there are too many incoming connections in existence, session_local_queue_only will be TRUE. If it is not, check @@ -634,7 +627,7 @@ if (pid == 0) If we are not root, we have to re-exec exim unless deliveries are being done unprivileged. */ - else if (!queue_only_policy && !deliver_freeze) + else if (!f.queue_only_policy && !f.deliver_freeze) { pid_t dpid; @@ -652,8 +645,8 @@ if (pid == 0) /* Don't ever molest the parent's SSL connection, but do clean up the data structures if necessary. */ -#ifdef SUPPORT_TLS - tls_close(TRUE, TLS_NO_SHUTDOWN); +#ifndef DISABLE_TLS + tls_close(NULL, TLS_NO_SHUTDOWN); #endif /* Reset SIGHUP and SIGCHLD in the child in both cases. */ @@ -699,8 +692,7 @@ if (pid < 0) never_error(US"daemon: accept process fork failed", US"Fork failed", errno); else { - int i; - for (i = 0; i < smtp_accept_max; ++i) + for (int i = 0; i < smtp_accept_max; ++i) if (smtp_slots[i].pid <= 0) { smtp_slots[i].pid = pid; @@ -932,7 +924,7 @@ debugging lines get the pid added. */ DEBUG(D_any|D_v) debug_selector |= D_pid; -if (inetd_wait_mode) +if (f.inetd_wait_mode) { listen_socket_count = 1; listen_sockets = store_get(sizeof(int)); @@ -971,7 +963,7 @@ if (inetd_wait_mode) } -if (inetd_wait_mode || daemon_listen) +if (f.inetd_wait_mode || f.daemon_listen) { /* If any option requiring a load average to be available during the reception of a message is set, call os_getloadavg() while we are root @@ -1053,7 +1045,7 @@ The preparation code decodes options and sets up the relevant data. We do this first, so that we can return non-zero if there are any syntax errors, and also write to stderr. */ -if (daemon_listen && !inetd_wait_mode) +if (f.daemon_listen && !f.inetd_wait_mode) { int *default_smtp_port; int sep; @@ -1192,8 +1184,6 @@ if (daemon_listen && !inetd_wait_mode) for (ipa = addresses; ipa; ipa = ipa->next) { - int i; - if (Ustrcmp(ipa->address, "0.0.0.0") == 0) ipa->address[0] = 0; else if (Ustrcmp(ipa->address, "::0") == 0) @@ -1211,7 +1201,7 @@ if (daemon_listen && !inetd_wait_mode) ipa->address[1] == 0 ? US"\"all IPv6\"" : ipa->address); ipa->port = default_smtp_port[0]; - for (i = 1; default_smtp_port[i] > 0; i++) + for (int i = 1; default_smtp_port[i] > 0; i++) { ip_address_item *new = store_get(sizeof(ip_address_item)); @@ -1275,7 +1265,7 @@ if (daemon_listen && !inetd_wait_mode) } /* daemon_listen but not inetd_wait_mode */ -if (daemon_listen) +if (f.daemon_listen) { /* Do a sanity check on the max connects value just to save us from getting @@ -1294,9 +1284,8 @@ if (daemon_listen) if (smtp_accept_max > 0) { - int i; smtp_slots = store_get(smtp_accept_max * sizeof(smtp_slot)); - for (i = 0; i < smtp_accept_max; i++) smtp_slots[i] = empty_smtp_slot; + for (int i = 0; i < smtp_accept_max; i++) smtp_slots[i] = empty_smtp_slot; } } @@ -1315,7 +1304,7 @@ Then disconnect from the controlling terminal, Most modern Unixes seem to have setsid() for getting rid of the controlling terminal. For any OS that doesn't, setsid() can be #defined as a no-op, or as something else. */ -if (background_daemon || inetd_wait_mode) +if (f.background_daemon || f.inetd_wait_mode) { log_close_all(); /* Just in case anything was logged earlier */ search_tidyup(); /* Just in case any were used in reading the config. */ @@ -1326,7 +1315,7 @@ if (background_daemon || inetd_wait_mode) log_stderr = NULL; /* So no attempt to copy paniclog output */ } -if (background_daemon) +if (f.background_daemon) { /* If the parent process of this one has pid == 1, we are re-initializing the daemon as the result of a SIGHUP. In this case, there is no need to do @@ -1347,7 +1336,7 @@ if (background_daemon) /* We are now in the disconnected, daemon process (unless debugging). Set up the listening sockets if required. */ -if (daemon_listen && !inetd_wait_mode) +if (f.daemon_listen && !f.inetd_wait_mode) { int sk; ip_address_item *ipa; @@ -1425,7 +1414,7 @@ if (daemon_listen && !inetd_wait_mode) listen() stage instead. */ #ifdef TCP_FASTOPEN - tcp_fastopen_ok = TRUE; + f.tcp_fastopen_ok = TRUE; #endif for(;;) { @@ -1463,19 +1452,32 @@ if (daemon_listen && !inetd_wait_mode) else debug_printf("listening on %s port %d\n", ipa->address, ipa->port); -#ifdef TCP_FASTOPEN - if (setsockopt(listen_sockets[sk], IPPROTO_TCP, TCP_FASTOPEN, +#if defined(TCP_FASTOPEN) && !defined(__APPLE__) + if ( f.tcp_fastopen_ok + && setsockopt(listen_sockets[sk], IPPROTO_TCP, TCP_FASTOPEN, &smtp_connect_backlog, sizeof(smtp_connect_backlog))) { DEBUG(D_any) debug_printf("setsockopt FASTOPEN: %s\n", strerror(errno)); - tcp_fastopen_ok = FALSE; + f.tcp_fastopen_ok = FALSE; } #endif /* Start listening on the bound socket, establishing the maximum backlog of connections that is allowed. On success, continue to the next address. */ - if (listen(listen_sockets[sk], smtp_connect_backlog) >= 0) continue; + if (listen(listen_sockets[sk], smtp_connect_backlog) >= 0) + { +#if defined(TCP_FASTOPEN) && defined(__APPLE__) + if ( f.tcp_fastopen_ok + && setsockopt(listen_sockets[sk], IPPROTO_TCP, TCP_FASTOPEN, + &on, sizeof(on))) + { + DEBUG(D_any) debug_printf("setsockopt FASTOPEN: %s\n", strerror(errno)); + f.tcp_fastopen_ok = FALSE; + } +#endif + continue; + } /* Listening has failed. In an IPv6 environment, as for bind(), if listen() fails with the error EADDRINUSE and we are doing IPv4 wildcard listening @@ -1530,7 +1532,7 @@ automatically. Consequently, Exim 4 writes a pid file only The variable daemon_write_pid is used to control this. */ -if (running_in_test_harness || write_pid) +if (f.running_in_test_harness || write_pid) { FILE *f; @@ -1578,9 +1580,8 @@ of them (and also if we are doing queue runs). */ if (queue_interval > 0 && local_queue_run_max > 0) { - int i; queue_pid_slots = store_get(local_queue_run_max * sizeof(pid_t)); - for (i = 0; i < local_queue_run_max; i++) queue_pid_slots[i] = 0; + for (int i = 0; i < local_queue_run_max; i++) queue_pid_slots[i] = 0; } /* Set up the handler for termination of child processes. */ @@ -1596,7 +1597,7 @@ sigalrm_seen = (queue_interval > 0); /* Log the start up of a daemon - at least one of listening or queue running must be set up. */ -if (inetd_wait_mode) +if (f.inetd_wait_mode) { uschar *p = big_buffer; @@ -1614,13 +1615,12 @@ if (inetd_wait_mode) sigalrm_seen = 1; } -else if (daemon_listen) +else if (f.daemon_listen) { - int i, j; int smtp_ports = 0; int smtps_ports = 0; - ip_address_item * ipa, * i2; - uschar * p = big_buffer; + ip_address_item * ipa; + uschar * p; uschar * qinfo = queue_interval > 0 ? string_sprintf("-q%s", readconf_printtime(queue_interval)) : US"no queue runs"; @@ -1632,27 +1632,19 @@ else if (daemon_listen) deprecated protocol that starts TLS without using STARTTLS), and others listening for standard SMTP. Keep their listings separate. */ - for (j = 0; j < 2; j++) + for (int j = 0, i; j < 2; j++) { for (i = 0, ipa = addresses; i < 10 && ipa; i++, ipa = ipa->next) { /* First time round, look for SMTP ports; second time round, look for - SMTPS ports. For the first one of each, insert leading text. */ + SMTPS ports. Build IP+port strings. */ if (host_is_tls_on_connect_port(ipa->port) == (j > 0)) { if (j == 0) - { - if (smtp_ports++ == 0) - { - memcpy(p, "SMTP on", 8); - p += 7; - } - } + smtp_ports++; else - if (smtps_ports++ == 0) - p += sprintf(CS p, "%sSMTPS on", - smtp_ports == 0 ? "" : " and for "); + smtps_ports++; /* Now the information about the port (and sometimes interface) */ @@ -1661,40 +1653,67 @@ else if (daemon_listen) if (ipa->next && ipa->next->address[0] == 0 && ipa->next->port == ipa->port) { - p += sprintf(CS p, " port %d (IPv6 and IPv4)", ipa->port); - ipa = ipa->next; + ipa->log = string_sprintf(" port %d (IPv6 and IPv4)", ipa->port); + (ipa = ipa->next)->log = NULL; } else if (ipa->v6_include_v4) - p += sprintf(CS p, " port %d (IPv6 with IPv4)", ipa->port); + ipa->log = string_sprintf(" port %d (IPv6 with IPv4)", ipa->port); else - p += sprintf(CS p, " port %d (IPv6)", ipa->port); + ipa->log = string_sprintf(" port %d (IPv6)", ipa->port); } else if (ipa->address[0] == 0) /* v4 wildcard */ - p += sprintf(CS p, " port %d (IPv4)", ipa->port); + ipa->log = string_sprintf(" port %d (IPv4)", ipa->port); else /* check for previously-seen IP */ { + ip_address_item * i2; for (i2 = addresses; i2 != ipa; i2 = i2->next) if ( host_is_tls_on_connect_port(i2->port) == (j > 0) && Ustrcmp(ipa->address, i2->address) == 0 ) { /* found; append port to list */ - if (p[-1] == '}') p--; - while (isdigit(*--p)) ; - p += 1 + sprintf(CS p+1, "%s%d,%d}", *p == ',' ? "" : "{", - i2->port, ipa->port); + for (p = i2->log; *p; ) p++; /* end of existing string */ + if (*--p == '}') *p = '\0'; /* drop EOL */ + while (isdigit(*--p)) ; /* char before port */ + + i2->log = *p == ':' /* no list yet? */ + ? string_sprintf("%.*s{%s,%d}", + (int)(p - i2->log + 1), i2->log, p+1, ipa->port) + : string_sprintf("%s,%d}", i2->log, ipa->port); + ipa->log = NULL; break; } if (i2 == ipa) /* first-time IP */ - p += sprintf(CS p, " [%s]:%d", ipa->address, ipa->port); + ipa->log = string_sprintf(" [%s]:%d", ipa->address, ipa->port); } } } + } - if (ipa) + p = big_buffer; + for (int j = 0, i; j < 2; j++) + { + /* First time round, look for SMTP ports; second time round, look for + SMTPS ports. For the first one of each, insert leading text. */ + + if (j == 0) { - memcpy(p, " ...", 5); - p += 4; + if (smtp_ports > 0) + p += sprintf(CS p, "SMTP on"); } + else + if (smtps_ports > 0) + p += sprintf(CS p, "%sSMTPS on", + smtp_ports == 0 ? "" : " and for "); + + /* Now the information about the port (and sometimes interface) */ + + for (i = 0, ipa = addresses; i < 10 && ipa; i++, ipa = ipa->next) + if (host_is_tls_on_connect_port(ipa->port) == (j > 0)) + if (ipa->log) + p += sprintf(CS p, "%s", ipa->log); + + if (ipa) + p += sprintf(CS p, " ..."); } log_write(0, LOG_MAIN, @@ -1792,7 +1811,7 @@ for (;;) } sigalrm_seen = FALSE; - alarm(resignal_interval); + ALARM(resignal_interval); } else @@ -1808,8 +1827,6 @@ for (;;) { if ((pid = fork()) == 0) { - int sk; - DEBUG(D_any) debug_printf("Starting queue-runner: pid %d\n", (int)getpid()); @@ -1817,11 +1834,11 @@ for (;;) leave the above message, because it ties up with the "child ended" debugging messages. */ - if (debug_daemon) debug_selector = 0; + if (f.debug_daemon) debug_selector = 0; /* Close any open listening sockets in the child */ - for (sk = 0; sk < listen_socket_count; sk++) + for (int sk = 0; sk < listen_socket_count; sk++) (void)close(listen_sockets[sk]); /* Reset SIGHUP and SIGCHLD in the child in both cases. */ @@ -1842,11 +1859,11 @@ for (;;) signal(SIGALRM, SIG_DFL); *p++ = '-'; *p++ = 'q'; - if (queue_2stage) *p++ = 'q'; - if (queue_run_first_delivery) *p++ = 'i'; - if (queue_run_force) *p++ = 'f'; - if (deliver_force_thaw) *p++ = 'f'; - if (queue_run_local) *p++ = 'l'; + if (f.queue_2stage) *p++ = 'q'; + if (f.queue_run_first_delivery) *p++ = 'i'; + if (f.queue_run_force) *p++ = 'f'; + if (f.deliver_force_thaw) *p++ = 'f'; + if (f.queue_run_local) *p++ = 'l'; *p = 0; extra[0] = queue_name ? string_sprintf("%sG%s", opt, queue_name) : opt; @@ -1856,13 +1873,13 @@ for (;;) if (deliver_selectstring) { - extra[extracount++] = deliver_selectstring_regex ? US"-Rr" : US"-R"; + extra[extracount++] = f.deliver_selectstring_regex ? US"-Rr" : US"-R"; extra[extracount++] = deliver_selectstring; } if (deliver_selectstring_sender) { - extra[extracount++] = deliver_selectstring_sender_regex + extra[extracount++] = f.deliver_selectstring_sender_regex ? US"-Sr" : US"-S"; extra[extracount++] = deliver_selectstring_sender; } @@ -1889,8 +1906,7 @@ for (;;) } else { - int i; - for (i = 0; i < local_queue_run_max; ++i) + for (int i = 0; i < local_queue_run_max; ++i) if (queue_pid_slots[i] <= 0) { queue_pid_slots[i] = pid; @@ -1898,14 +1914,14 @@ for (;;) break; } DEBUG(D_any) debug_printf("%d queue-runner process%s running\n", - queue_run_count, (queue_run_count == 1)? "" : "es"); + queue_run_count, queue_run_count == 1 ? "" : "es"); } } /* Reset the alarm clock */ sigalrm_seen = FALSE; - alarm(queue_interval); + ALARM(queue_interval); } } /* sigalrm_seen */ @@ -1920,15 +1936,15 @@ for (;;) new OS. In fact, the later addition of listening on specific interfaces only requires this way of working anyway. */ - if (daemon_listen) + if (f.daemon_listen) { - int sk, lcount, select_errno; + int lcount, select_errno; int max_socket = 0; BOOL select_failed = FALSE; fd_set select_listen; FD_ZERO(&select_listen); - for (sk = 0; sk < listen_socket_count; sk++) + for (int sk = 0; sk < listen_socket_count; sk++) { FD_SET(listen_sockets[sk], &select_listen); if (listen_sockets[sk] > max_socket) max_socket = listen_sockets[sk]; @@ -1969,6 +1985,11 @@ for (;;) handle_ending_processes(); errno = select_errno; +#ifndef DISABLE_TLS + /* Create or rotate any required keys */ + tls_daemon_init(); +#endif + /* Loop for all the sockets that are currently ready to go. If select actually failed, we have set the count to 1 and select_failed=TRUE, so as to use the common error code for select/accept below. */ @@ -1978,7 +1999,7 @@ for (;;) int accept_socket = -1; if (!select_failed) - for (sk = 0; sk < listen_socket_count; sk++) + for (int sk = 0; sk < listen_socket_count; sk++) if (FD_ISSET(listen_sockets[sk], &select_listen)) { len = sizeof(accepted); @@ -2087,12 +2108,11 @@ for (;;) if (sighup_seen) { - int sk; log_write(0, LOG_MAIN, "pid %d: SIGHUP received: re-exec daemon", getpid()); - for (sk = 0; sk < listen_socket_count; sk++) + for (int sk = 0; sk < listen_socket_count; sk++) (void)close(listen_sockets[sk]); - alarm(0); + ALARM_CLR(0); signal(SIGHUP, SIG_IGN); sighup_argv[0] = exim_path; exim_nullstd();