Gitweb:
https://git.exim.org/exim.git/commitdiff/d85cdeb5e554b59bf4c43c54461409c15c6ee9c5
Commit: d85cdeb5e554b59bf4c43c54461409c15c6ee9c5
Parent: 4316e9b3b73ac3a042799bf20625dea0d70dde00
Author: Jeremy Harris <jgh146exb@???>
AuthorDate: Sat Oct 12 12:48:44 2019 +0100
Committer: Jeremy Harris <jgh146exb@???>
CommitDate: Sat Oct 12 14:55:49 2019 +0100
Reduce delivery process startup time
---
doc/doc-txt/ChangeLog | 8 +++++
src/src/daemon.c | 14 +++++++++
src/src/deliver.c | 43 ++------------------------
src/src/dkim.c | 6 ++++
src/src/exim.c | 43 +++++++++++---------------
src/src/functions.h | 4 ++-
src/src/globals.c | 1 +
src/src/globals.h | 1 +
src/src/readconf.c | 79 -----------------------------------------------
src/src/tls-gnu.c | 36 ++++++++++++++++-----
src/src/tls.c | 75 ++++++++++++++++++++++++++++++++++++++++++++
src/src/transports/smtp.c | 45 +++++++++++++++++++++++++++
src/src/verify.c | 4 +++
test/log/2120 | 4 ---
14 files changed, 206 insertions(+), 157 deletions(-)
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 93f4a1e..9a27e14 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -5,6 +5,14 @@ affect Exim's operation, with an unchanged configuration file. For new
options, and new features, see the NewStuff file next to this ChangeLog.
+Exim version 4.next
+-------------------
+
+JH/01 Avoid costly startup code when not strictly needed. This reduces time
+ for some exim process initialisations. It does mean that the logging
+ of TLS configuration problems is only done for the daemon startup.
+
+
Exim version 4.93
-----------------
diff --git a/src/src/daemon.c b/src/src/daemon.c
index 99fa909..3fc73ba 100644
--- a/src/src/daemon.c
+++ b/src/src/daemon.c
@@ -1740,6 +1740,20 @@ else
(eg: compile regex) */
dns_pattern_init();
+smtp_deliver_init(); /* Used for callouts */
+
+#ifndef DISABLE_DKIM
+ {
+# ifdef MEASURE_TIMING
+ struct timeval t0;
+ gettimeofday(&t0, NULL);
+# endif
+ dkim_exim_init();
+# ifdef MEASURE_TIMING
+ report_time_since(&t0, US"dkim_exim_init (delta)");
+# endif
+ }
+#endif
#ifdef WITH_CONTENT_SCAN
malware_init();
diff --git a/src/src/deliver.c b/src/src/deliver.c
index e228a0b..5fc7481 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -7146,7 +7146,7 @@ if (addr_remote)
/* Precompile some regex that are used to recognize parameters in response
to an EHLO command, if they aren't already compiled. */
- deliver_init();
+ smtp_deliver_init();
/* Now sort the addresses if required, and do the deliveries. The yield of
do_remote_deliveries is FALSE when mua_wrapper is set and all addresses
@@ -8484,52 +8484,13 @@ return final_yield;
void
-deliver_init(void)
+tcp_init(void)
{
#ifdef EXIM_TFO_PROBE
tfo_probe();
#else
f.tcp_fastopen_ok = TRUE;
#endif
-
-
-if (!regex_PIPELINING) regex_PIPELINING =
- regex_must_compile(US"\\n250[\\s\\-]PIPELINING(\\s|\\n|$)", FALSE, TRUE);
-
-if (!regex_SIZE) regex_SIZE =
- regex_must_compile(US"\\n250[\\s\\-]SIZE(\\s|\\n|$)", FALSE, TRUE);
-
-if (!regex_AUTH) regex_AUTH =
- regex_must_compile(AUTHS_REGEX, FALSE, TRUE);
-
-#ifndef DISABLE_TLS
-if (!regex_STARTTLS) regex_STARTTLS =
- regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
-#endif
-
-if (!regex_CHUNKING) regex_CHUNKING =
- regex_must_compile(US"\\n250[\\s\\-]CHUNKING(\\s|\\n|$)", FALSE, TRUE);
-
-#ifndef DISABLE_PRDR
-if (!regex_PRDR) regex_PRDR =
- regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
-#endif
-
-#ifdef SUPPORT_I18N
-if (!regex_UTF8) regex_UTF8 =
- regex_must_compile(US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE);
-#endif
-
-if (!regex_DSN) regex_DSN =
- regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE);
-
-if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA =
- regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE);
-
-#ifdef SUPPORT_PIPE_CONNECT
-if (!regex_EARLY_PIPE) regex_EARLY_PIPE =
- regex_must_compile(US"\\n250[\\s\\-]" EARLY_PIPE_FEATURE_NAME "(\\s|\\n|$)", FALSE, TRUE);
-#endif
}
diff --git a/src/src/dkim.c b/src/src/dkim.c
index 0651704..5c9d227 100644
--- a/src/src/dkim.c
+++ b/src/src/dkim.c
@@ -95,6 +95,8 @@ return NULL; /*XXX better error detail? logging? */
void
dkim_exim_init(void)
{
+if (f.dkim_init_done) return;
+f.dkim_init_done = TRUE;
pdkim_init();
}
@@ -103,6 +105,8 @@ pdkim_init();
void
dkim_exim_verify_init(BOOL dot_stuffing)
{
+dkim_exim_init();
+
/* There is a store-reset between header & body reception
so cannot use the main pool. Any allocs done by Exim
memory-handling must use the perm pool. */
@@ -569,6 +573,8 @@ void
dkim_exim_sign_init(void)
{
int old_pool = store_pool;
+
+dkim_exim_init();
store_pool = POOL_MAIN;
pdkim_init_context(&dkim_sign_ctx, FALSE, &dkim_exim_query_dns_txt);
store_pool = old_pool;
diff --git a/src/src/exim.c b/src/src/exim.c
index 2b6297b..68734e3 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -920,7 +920,7 @@ fprintf(fp, "Support for:");
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
@@ -4480,31 +4480,9 @@ if (list_config)
}
-/* Initialise subsystems as required */
-#ifndef DISABLE_DKIM
- {
-# ifdef MEASURE_TIMING
- struct timeval t0;
- gettimeofday(&t0, NULL);
-# endif
- dkim_exim_init();
-# ifdef MEASURE_TIMING
- report_time_since(&t0, US"dkim_exim_init (delta)");
-# endif
- }
-#endif
-
- {
-#ifdef MEASURE_TIMING
- struct timeval t0;
- gettimeofday(&t0, NULL);
-#endif
- deliver_init();
-#ifdef MEASURE_TIMING
- report_time_since(&t0, US"deliver_init (delta)");
-#endif
- }
+/* 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
@@ -4699,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();
}
diff --git a/src/src/functions.h b/src/src/functions.h
index 37f6b1b..488e84c 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -54,6 +54,7 @@ extern BOOL tls_client_start(client_conn_ctx *, smtp_connect_args *,
extern void tls_close(void *, int);
extern BOOL tls_could_read(void);
extern void tls_daemon_init(void);
+extern BOOL tls_dropprivs_validate_require_cipher(BOOL);
extern BOOL tls_export_cert(uschar *, size_t, void *);
extern int tls_feof(void);
extern int tls_ferror(void);
@@ -175,7 +176,6 @@ extern void debug_vprintf(int, const char *, va_list);
extern void decode_bits(unsigned int *, size_t, int *,
uschar *, bit_table *, int, uschar *, int);
extern address_item *deliver_make_addr(uschar *, BOOL);
-extern void deliver_init(void);
extern void delivery_log(int, address_item *, int, uschar *);
extern int deliver_message(uschar *, BOOL, BOOL);
extern void deliver_msglog(const char *, ...) PRINTF_FUNCTION(1,2);
@@ -445,6 +445,7 @@ extern void smtp_command_timeout_exit(void) NORETURN;
extern void smtp_command_sigterm_exit(void) NORETURN;
extern void smtp_data_timeout_exit(void) NORETURN;
extern void smtp_data_sigint_exit(void) NORETURN;
+extern void smtp_deliver_init(void);
extern uschar *smtp_cmd_hist(void);
extern int smtp_connect(smtp_connect_args *, const blob *);
extern int smtp_sock_connect(host_item *, int, int, uschar *,
@@ -538,6 +539,7 @@ extern int strcmpic(const uschar *, const uschar *);
extern int strncmpic(const uschar *, const uschar *, int);
extern uschar *strstric(uschar *, uschar *, BOOL);
+extern void tcp_init(void);
#ifdef EXIM_TFO_PROBE
extern void tfo_probe(void);
#endif
diff --git a/src/src/globals.c b/src/src/globals.c
index 24281f2..302e18e 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -238,6 +238,7 @@ struct global_flags f =
.disable_logging = FALSE,
#ifndef DISABLE_DKIM
.dkim_disable_verify = FALSE,
+ .dkim_init_done = FALSE,
#endif
#ifdef SUPPORT_DMARC
.dmarc_has_been_checked = FALSE,
diff --git a/src/src/globals.h b/src/src/globals.h
index e4725a7..27a4bd9 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -198,6 +198,7 @@ extern struct global_flags {
BOOL disable_logging :1; /* Disables log writing when TRUE */
#ifndef DISABLE_DKIM
BOOL dkim_disable_verify :1; /* Set via ACL control statement. When set, DKIM verification is disabled for the current message */
+ BOOL dkim_init_done :1; /* lazy-init status */
#endif
#ifdef SUPPORT_DMARC
BOOL dmarc_has_been_checked :1; /* Global variable to check if test has been called yet */
diff --git a/src/src/readconf.c b/src/src/readconf.c
index 2f78cd7..daa88d0 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -3075,80 +3075,6 @@ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "malformed ratelimit data: %s", s);
/*************************************************
-* Drop privs for checking TLS config *
-*************************************************/
-
-/* We want to validate TLS options during readconf, but do not want to be
-root when we call into the TLS library, in case of library linkage errors
-which cause segfaults; before this check, those were always done as the Exim
-runtime user and it makes sense to continue with that.
-
-Assumes: tls_require_ciphers has been set, if it will be
- exim_user has been set, if it will be
- exim_group has been set, if it will be
-
-Returns: bool for "okay"; false will cause caller to immediately exit.
-*/
-
-#ifndef DISABLE_TLS
-static BOOL
-tls_dropprivs_validate_require_cipher(BOOL nowarn)
-{
-const uschar *errmsg;
-pid_t pid;
-int rc, status;
-void (*oldsignal)(int);
-
-/* If TLS will never be used, no point checking ciphers */
-
-if ( !tls_advertise_hosts
- || !*tls_advertise_hosts
- || Ustrcmp(tls_advertise_hosts, ":") == 0
- )
- return TRUE;
-else if (!nowarn && !tls_certificate)
- log_write(0, LOG_MAIN,
- "Warning: No server certificate defined; will use a selfsigned one.\n"
- " Suggested action: either install a certificate or change tls_advertise_hosts option");
-
-oldsignal = signal(SIGCHLD, SIG_DFL);
-
-fflush(NULL);
-if ((pid = fork()) < 0)
- log_write(0, LOG_MAIN|LOG_PANIC_DIE, "fork failed for TLS check");
-
-if (pid == 0)
- {
- /* in some modes, will have dropped privilege already */
- if (!geteuid())
- exim_setugid(exim_uid, exim_gid, FALSE,
- US"calling tls_validate_require_cipher");
-
- if ((errmsg = tls_validate_require_cipher()))
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
- "tls_require_ciphers invalid: %s", errmsg);
- fflush(NULL);
- exim_underbar_exit(0);
- }
-
-do {
- rc = waitpid(pid, &status, 0);
-} while (rc < 0 && errno == EINTR);
-
-DEBUG(D_tls)
- debug_printf("tls_validate_require_cipher child %d ended: status=0x%x\n",
- (int)pid, status);
-
-signal(SIGCHLD, oldsignal);
-
-return status == 0;
-}
-#endif /*DISABLE_TLS*/
-
-
-
-
-/*************************************************
* Read main configuration options *
*************************************************/
@@ -3658,11 +3584,6 @@ if ((tls_verify_hosts || tls_try_verify_hosts) && !tls_verify_certificates)
"tls_%sverify_hosts is set, but tls_verify_certificates is not set",
tls_verify_hosts ? "" : "try_");
-/* 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 */
-if (!tls_dropprivs_validate_require_cipher(nowarn))
- exit(1);
-
/* Magic number: at time of writing, 1024 has been the long-standing value
used by so many clients, and what Exim used to use always, that it makes
sense to just min-clamp this max-clamp at that. */
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index deeb042..6cd9bf7 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -2385,9 +2385,20 @@ and sent an SMTP response. */
DEBUG(D_tls) debug_printf("initialising GnuTLS as a server\n");
-if ((rc = tls_init(NULL, tls_certificate, tls_privatekey,
- NULL, tls_verify_certificates, tls_crl,
- require_ciphers, &state, &tls_in, errstr)) != OK) return rc;
+ {
+#ifdef MEASURE_TIMING
+ struct timeval t0;
+ gettimeofday(&t0, NULL);
+#endif
+
+ if ((rc = tls_init(NULL, tls_certificate, tls_privatekey,
+ NULL, tls_verify_certificates, tls_crl,
+ require_ciphers, &state, &tls_in, errstr)) != OK) return rc;
+
+#ifdef MEASURE_TIMING
+ report_time_since(&t0, US"server tls_init (delta)");
+#endif
+ }
#ifdef EXPERIMENTAL_TLS_RESUME
tls_server_resume_prehandshake(state);
@@ -2821,10 +2832,21 @@ if (conn_args->dane && ob->dane_require_tls_ciphers)
if (!cipher_list)
cipher_list = ob->tls_require_ciphers;
-if (tls_init(host, ob->tls_certificate, ob->tls_privatekey,
- ob->tls_sni, ob->tls_verify_certificates, ob->tls_crl,
- cipher_list, &state, tlsp, errstr) != OK)
- return FALSE;
+ {
+#ifdef MEASURE_TIMING
+ struct timeval t0;
+ gettimeofday(&t0, NULL);
+#endif
+
+ if (tls_init(host, ob->tls_certificate, ob->tls_privatekey,
+ ob->tls_sni, ob->tls_verify_certificates, ob->tls_crl,
+ cipher_list, &state, tlsp, errstr) != OK)
+ return FALSE;
+
+#ifdef MEASURE_TIMING
+ report_time_since(&t0, US"client tls_init (delta)");
+#endif
+ }
{
int dh_min_bits = ob->tls_dh_min_bits;
diff --git a/src/src/tls.c b/src/src/tls.c
index 796bc6d..531d679 100644
--- a/src/src/tls.c
+++ b/src/src/tls.c
@@ -369,6 +369,81 @@ else if ((subjdn = tls_cert_subject(cert, NULL)))
}
return FALSE;
}
+
+
+
+/*************************************************
+* Drop privs for checking TLS config *
+*************************************************/
+
+/* We want to validate TLS options during readconf, but do not want to be
+root when we call into the TLS library, in case of library linkage errors
+which cause segfaults; before this check, those were always done as the Exim
+runtime user and it makes sense to continue with that.
+
+Assumes: tls_require_ciphers has been set, if it will be
+ exim_user has been set, if it will be
+ exim_group has been set, if it will be
+
+Returns: bool for "okay"; false will cause caller to immediately exit.
+*/
+
+BOOL
+tls_dropprivs_validate_require_cipher(BOOL nowarn)
+{
+const uschar *errmsg;
+pid_t pid;
+int rc, status;
+void (*oldsignal)(int);
+
+/* If TLS will never be used, no point checking ciphers */
+
+if ( !tls_advertise_hosts
+ || !*tls_advertise_hosts
+ || Ustrcmp(tls_advertise_hosts, ":") == 0
+ )
+ return TRUE;
+else if (!nowarn && !tls_certificate)
+ log_write(0, LOG_MAIN,
+ "Warning: No server certificate defined; will use a selfsigned one.\n"
+ " Suggested action: either install a certificate or change tls_advertise_hosts option");
+
+oldsignal = signal(SIGCHLD, SIG_DFL);
+
+fflush(NULL);
+if ((pid = fork()) < 0)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "fork failed for TLS check");
+
+if (pid == 0)
+ {
+ /* in some modes, will have dropped privilege already */
+ if (!geteuid())
+ exim_setugid(exim_uid, exim_gid, FALSE,
+ US"calling tls_validate_require_cipher");
+
+ if ((errmsg = tls_validate_require_cipher()))
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
+ "tls_require_ciphers invalid: %s", errmsg);
+ fflush(NULL);
+ exim_underbar_exit(0);
+ }
+
+do {
+ rc = waitpid(pid, &status, 0);
+} while (rc < 0 && errno == EINTR);
+
+DEBUG(D_tls)
+ debug_printf("tls_validate_require_cipher child %d ended: status=0x%x\n",
+ (int)pid, status);
+
+signal(SIGCHLD, oldsignal);
+
+return status == 0;
+}
+
+
+
+
#endif /*!DISABLE_TLS*/
#endif /*!MACRO_PREDEF*/
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index c547c87..b45da05 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -357,6 +357,51 @@ static BOOL pipelining_active; /* current transaction is in pipe mode */
static unsigned ehlo_response(uschar * buf, unsigned checks);
+/******************************************************************************/
+
+void
+smtp_deliver_init(void)
+{
+if (!regex_PIPELINING) regex_PIPELINING =
+ regex_must_compile(US"\\n250[\\s\\-]PIPELINING(\\s|\\n|$)", FALSE, TRUE);
+
+if (!regex_SIZE) regex_SIZE =
+ regex_must_compile(US"\\n250[\\s\\-]SIZE(\\s|\\n|$)", FALSE, TRUE);
+
+if (!regex_AUTH) regex_AUTH =
+ regex_must_compile(AUTHS_REGEX, FALSE, TRUE);
+
+#ifndef DISABLE_TLS
+if (!regex_STARTTLS) regex_STARTTLS =
+ regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
+#endif
+
+if (!regex_CHUNKING) regex_CHUNKING =
+ regex_must_compile(US"\\n250[\\s\\-]CHUNKING(\\s|\\n|$)", FALSE, TRUE);
+
+#ifndef DISABLE_PRDR
+if (!regex_PRDR) regex_PRDR =
+ regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
+#endif
+
+#ifdef SUPPORT_I18N
+if (!regex_UTF8) regex_UTF8 =
+ regex_must_compile(US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE);
+#endif
+
+if (!regex_DSN) regex_DSN =
+ regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE);
+
+if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA =
+ regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE);
+
+#ifdef SUPPORT_PIPE_CONNECT
+if (!regex_EARLY_PIPE) regex_EARLY_PIPE =
+ regex_must_compile(US"\\n250[\\s\\-]" EARLY_PIPE_FEATURE_NAME "(\\s|\\n|$)", FALSE, TRUE);
+#endif
+}
+
+
/*************************************************
* Setup entry point *
*************************************************/
diff --git a/src/src/verify.c b/src/src/verify.c
index 384739b..1a44de1 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -586,6 +586,10 @@ else
log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
"callout_random_local_part: %s", expand_string_message);
+ /* Compile regex' used by client-side smtp */
+
+ smtp_deliver_init();
+
/* Default the connect and overall callout timeouts if not set, and record the
time we are starting so that we can enforce it. */
diff --git a/test/log/2120 b/test/log/2120
index 6c4b0ca..8057655 100644
--- a/test/log/2120
+++ b/test/log/2120
@@ -1,8 +1,4 @@
-1999-03-02 09:44:33 Warning: No server certificate defined; will use a selfsigned one.
- Suggested action: either install a certificate or change tls_advertise_hosts option
1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@??? U=CALLER P=local S=sss
-1999-03-02 09:44:33 Warning: No server certificate defined; will use a selfsigned one.
- Suggested action: either install a certificate or change tls_advertise_hosts option
1999-03-02 09:44:33 Start queue run: pid=pppp -qf
1999-03-02 09:44:33 10HmaX-0005vi-00 [127.0.0.1] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=Exim Developers/CN=thishost.test.ex
1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@??? R=abc T=t1 H=thishost.test.ex [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=no DN="/C=UK/O=Exim Developers/CN=thishost.test.ex" C="250 OK id=10HmaY-0005vi-00"