+/*************************************************
+* 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(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");
+
+ 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 */
+
+
+
+
+/*************************************************/
+/* Create compile-time feature macros */
+static void
+readconf_features(void)
+{
+/* Probably we could work out a static initialiser for wherever
+macros are stored, but this will do for now. Some names are awkward
+due to conflicts with other common macros. */
+
+#ifdef SUPPORT_CRYPTEQ
+ read_macro_assignment("_HAVE_CRYPTEQ=y");
+#endif
+#if HAVE_ICONV
+ read_macro_assignment("_HAVE_ICONV=y");
+#endif
+#if HAVE_IPV6
+ read_macro_assignment("_HAVE_IPV6=y");
+#endif
+#ifdef HAVE_SETCLASSRESOURCES
+ read_macro_assignment("_HAVE_SETCLASSRESOURCES=y");
+#endif
+#ifdef SUPPORT_PAM
+ read_macro_assignment("_HAVE_PAM=y");
+#endif
+#ifdef EXIM_PERL
+ read_macro_assignment("_HAVE_PERL=y");
+#endif
+#ifdef EXPAND_DLFUNC
+ read_macro_assignment("_HAVE_DLFUNC=y");
+#endif
+#ifdef USE_TCP_WRAPPERS
+ read_macro_assignment("_HAVE_TCPWRAPPERS=y");
+#endif
+#ifdef SUPPORT_TLS
+ read_macro_assignment("_HAVE_TLS=y");
+# ifdef USE_GNUTLS
+ read_macro_assignment("_HAVE_GNUTLS=y");
+# else
+ read_macro_assignment("_HAVE_OPENSSL=y");
+# endif
+#endif
+#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
+ read_macro_assignment("_HAVE_TRANSLATE_IP_ADDRESS=y");
+#endif
+#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
+ read_macro_assignment("_HAVE_MOVE_FROZEN_MESSAGES=y");
+#endif
+#ifdef WITH_CONTENT_SCAN
+ read_macro_assignment("_HAVE_CONTENT_SCANNING=y");
+#endif
+#ifndef DISABLE_DKIM
+ read_macro_assignment("_HAVE_DKIM=y");
+#endif
+#ifndef DISABLE_DNSSEC
+ read_macro_assignment("_HAVE_DNSSEC=y");
+#endif
+#ifndef DISABLE_EVENT
+ read_macro_assignment("_HAVE_Event=y");
+#endif
+#ifdef SUPPORT_I18N
+ read_macro_assignment("_HAVE_I18N=y");
+#endif
+#ifndef DISABLE_OCSP
+ read_macro_assignment("_HAVE_OCSP=y");
+#endif
+#ifndef DISABLE_PRDR
+ read_macro_assignment("_HAVE_PRDR=y");
+#endif
+#ifdef SUPPORT_PROXY
+ read_macro_assignment("_HAVE_PROXY=y");
+#endif
+#ifdef SUPPORT_SOCKS
+ read_macro_assignment("_HAVE_SOCKS=y");
+#endif
+#ifdef EXPERIMENTAL_LMDB
+ read_macro_assignment("_HAVE_LMDB=y");
+#endif
+#ifdef EXPERIMENTAL_SPF
+ read_macro_assignment("_HAVE_SPF=y");
+#endif
+#ifdef EXPERIMENTAL_SRS
+ read_macro_assignment("_HAVE_SRS=y");
+#endif
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+ read_macro_assignment("_HAVE_BRIGHTMAIL=y");
+#endif
+#ifdef EXPERIMENTAL_DANE
+ read_macro_assignment("_HAVE_DANE=y");
+#endif
+#ifdef EXPERIMENTAL_DCC
+ read_macro_assignment("_HAVE_DCC=y");
+#endif
+#ifdef EXPERIMENTAL_DMARC
+ read_macro_assignment("_HAVE_DMARC=y");
+#endif
+#ifdef EXPERIMENTAL_DSN_INFO
+ read_macro_assignment("_HAVE_DSN_INFO=y");
+#endif
+
+#ifdef LOOKUP_LSEARCH
+ read_macro_assignment("_HAVE_LKUP_LSEARCH=y");
+#endif
+#ifdef LOOKUP_CDB
+ read_macro_assignment("_HAVE_LKUP_CDB=y");
+#endif
+#ifdef LOOKUP_DBM
+ read_macro_assignment("_HAVE_LKUP_DBM=y");
+#endif
+#ifdef LOOKUP_DNSDB
+ read_macro_assignment("_HAVE_LKUP_DNSDB=y");
+#endif
+#ifdef LOOKUP_DSEARCH
+ read_macro_assignment("_HAVE_LKUP_DSEARCH=y");
+#endif
+#ifdef LOOKUP_IBASE
+ read_macro_assignment("_HAVE_LKUP_IBASE=y");
+#endif
+#ifdef LOOKUP_LDAP
+ read_macro_assignment("_HAVE_LKUP_LDAP=y");
+#endif
+#ifdef EXPERIMENTAL_LMDB
+ read_macro_assignment("_HAVE_LKUP_LMDB=y");
+#endif
+#ifdef LOOKUP_MYSQL
+ read_macro_assignment("_HAVE_LKUP_MYSQL=y");
+#endif
+#ifdef LOOKUP_NIS
+ read_macro_assignment("_HAVE_LKUP_NIS=y");
+#endif
+#ifdef LOOKUP_NISPLUS
+ read_macro_assignment("_HAVE_LKUP_NISPLUS=y");
+#endif
+#ifdef LOOKUP_ORACLE
+ read_macro_assignment("_HAVE_LKUP_ORACLE=y");
+#endif
+#ifdef LOOKUP_PASSWD
+ read_macro_assignment("_HAVE_LKUP_PASSWD=y");
+#endif
+#ifdef LOOKUP_PGSQL
+ read_macro_assignment("_HAVE_LKUP_PGSQL=y");
+#endif
+#ifdef LOOKUP_REDIS
+ read_macro_assignment("_HAVE_LKUP_REDIS=y");
+#endif
+#ifdef LOOKUP_SQLITE
+ read_macro_assignment("_HAVE_LKUP_SQLITE=y");
+#endif
+#ifdef LOOKUP_TESTDB
+ read_macro_assignment("_HAVE_LKUP_TESTDB=y");
+#endif
+#ifdef LOOKUP_WHOSON
+ read_macro_assignment("_HAVE_LKUP_WHOSON=y");
+#endif
+
+#ifdef AUTH_CRAM_MD5
+ read_macro_assignment("_HAVE_AUTH_CRAM_MD5=y");
+#endif
+#ifdef AUTH_CYRUS_SASL
+ read_macro_assignment("_HAVE_AUTH_CYRUS_SASL=y");
+#endif
+#ifdef AUTH_DOVECOT
+ read_macro_assignment("_HAVE_AUTH_DOVECOT=y");
+#endif
+#ifdef AUTH_GSASL
+ read_macro_assignment("_HAVE_AUTH_GSASL=y");
+#endif
+#ifdef AUTH_HEIMDAL_GSSAPI
+ read_macro_assignment("_HAVE_AUTH_HEIMDAL_GSSAPI=y");
+#endif
+#ifdef AUTH_PLAINTEXT
+ read_macro_assignment("_HAVE_AUTH_PLAINTEXT=y");
+#endif
+#ifdef AUTH_SPA
+ read_macro_assignment("_HAVE_AUTH_SPA=y");
+#endif
+#ifdef AUTH_TLS
+ read_macro_assignment("_HAVE_AUTH_TLS=y");
+#endif
+
+#ifdef ROUTER_ACCEPT
+ read_macro_assignment("_HAVE_RTR_ACCEPT=y");
+#endif
+#ifdef ROUTER_DNSLOOKUP
+ read_macro_assignment("_HAVE_RTR_DNSLOOKUP=y");
+#endif
+#ifdef ROUTER_IPLITERAL
+ read_macro_assignment("_HAVE_RTR_IPLITERAL=y");
+#endif
+#ifdef ROUTER_IPLOOKUP
+ read_macro_assignment("_HAVE_RTR_IPLOOKUP=y");
+#endif
+#ifdef ROUTER_MANUALROUTE
+ read_macro_assignment("_HAVE_RTR_MANUALROUTE=y");
+#endif
+#ifdef ROUTER_QUERYPROGRAM
+ read_macro_assignment("_HAVE_RTR_QUERYPROGRAM=y");
+#endif
+#ifdef ROUTER_REDIRECT
+ read_macro_assignment("_HAVE_RTR_REDRCT=y");
+#endif
+
+#ifdef TRANSPORT_APPENDFILE
+ read_macro_assignment("_HAVE_TPT_APPENDFILE=y");
+# ifdef SUPPORT_MAILDIR
+ read_macro_assignment("_HAVE_TPT_APPEND_MAILDR=y");
+# endif
+# ifdef SUPPORT_MAILSTORE
+ read_macro_assignment("_HAVE_TPT_APPEND_MAILSTORE=y");
+# endif
+# ifdef SUPPORT_MBX
+ read_macro_assignment("_HAVE_TPT_APPEND_MBX=y");
+# endif
+#endif
+#ifdef TRANSPORT_AUTOREPLY
+ read_macro_assignment("_HAVE_TPT_AUTOREPLY=y");
+#endif
+#ifdef TRANSPORT_LMTP
+ read_macro_assignment("_HAVE_TPT_LMTP=y");
+#endif
+#ifdef TRANSPORT_PIPE
+ read_macro_assignment("_HAVE_TPT_PIPE=y");
+#endif
+#ifdef TRANSPORT_SMTP
+ read_macro_assignment("_HAVE_TPT_SMTP=y");
+#endif
+}
+
+