-/* $Cambridge: exim/src/src/readconf.c,v 1.45 2010/06/12 17:56:32 jetmore Exp $ */
-
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2012 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for reading the configuration file, and for displaying
{ "gecos_pattern", opt_stringptr, &gecos_pattern },
#ifdef SUPPORT_TLS
{ "gnutls_compat_mode", opt_bool, &gnutls_compat_mode },
+ /* These three gnutls_require_* options stopped working in Exim 4.80 */
{ "gnutls_require_kx", opt_stringptr, &gnutls_require_kx },
{ "gnutls_require_mac", opt_stringptr, &gnutls_require_mac },
{ "gnutls_require_protocols", opt_stringptr, &gnutls_require_proto },
{ "tls_advertise_hosts", opt_stringptr, &tls_advertise_hosts },
{ "tls_certificate", opt_stringptr, &tls_certificate },
{ "tls_crl", opt_stringptr, &tls_crl },
+ { "tls_dh_max_bits", opt_int, &tls_dh_max_bits },
{ "tls_dhparam", opt_stringptr, &tls_dhparam },
+#if defined(EXPERIMENTAL_OCSP) && !defined(USE_GNUTLS)
+ { "tls_ocsp_file", opt_stringptr, &tls_ocsp_file },
+#endif
{ "tls_on_connect_ports", opt_stringptr, &tls_on_connect_ports },
{ "tls_privatekey", opt_stringptr, &tls_privatekey },
{ "tls_remember_esmtp", opt_bool, &tls_remember_esmtp },
{
if (namelen >= sizeof(name) - 1)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
- "macro name too long (maximum is %d characters)", sizeof(name) - 1);
+ "macro name too long (maximum is " SIZE_T_FMT " characters)", sizeof(name) - 1);
name[namelen++] = *s++;
}
name[namelen] = 0;
+/*************************************************
+* 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.
+*/
+
+#ifdef SUPPORT_TLS
+static BOOL
+tls_dropprivs_validate_require_cipher(void)
+{
+const uschar *errmsg;
+pid_t pid;
+int rc, status;
+void (*oldsignal)(int);
+
+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");
+
+ errmsg = tls_validate_require_cipher();
+ if (errmsg)
+ {
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
+ "tls_require_ciphers invalid: %s", errmsg);
+ }
+ fflush(NULL);
+ _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 /* SUPPORT_TLS */
+
+
+
+
/*************************************************
* Read main configuration options *
*************************************************/
if (host_number_string != NULL)
{
+ long int n;
uschar *end;
uschar *s = expand_string(host_number_string);
- long int n = Ustrtol(s, &end, 0);
+ if (s == NULL)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+ "failed to expand localhost_number \"%s\": %s",
+ host_number_string, expand_string_message);
+ n = Ustrtol(s, &end, 0);
while (isspace(*end)) end++;
if (*end != 0)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"tls_%sverify_hosts is set, but tls_verify_certificates is not set",
(tls_verify_hosts != NULL)? "" : "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())
+ 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. */
+if (tls_dh_max_bits < 1024)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
+ "tls_dh_max_bits is too small, must be at least 1024 for interop");
+
/* If openssl_options is set, validate it */
if (openssl_options != NULL)
{
*basic_errno = ERRNO_TLSREQUIRED;
else if (len != 1 || Ustrncmp(pp, "*", 1) != 0)
- return string_sprintf("unknown or malformed retry error \"%.*s\"", p-pp, pp);
+ return string_sprintf("unknown or malformed retry error \"%.*s\"", (int) (p-pp), pp);
return NULL;
}