-/* $Cambridge: exim/src/src/exim.c,v 1.71 2010/06/07 00:12:42 pdp 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. */
+/*************************************************
+* Set up processing details *
+*************************************************/
+
+/* Save a text string for dumping when SIGUSR1 is received.
+Do checks for overruns.
+
+Arguments: format and arguments, as for printf()
+Returns: nothing
+*/
+
+void
+set_process_info(const char *format, ...)
+{
+int len;
+va_list ap;
+sprintf(CS process_info, "%5d ", (int)getpid());
+len = Ustrlen(process_info);
+va_start(ap, format);
+if (!string_vformat(process_info + len, PROCESS_INFO_SIZE - len - 2, format, ap))
+ Ustrcpy(process_info + len, "**** string overflowed buffer ****");
+len = Ustrlen(process_info);
+process_info[len+0] = '\n';
+process_info[len+1] = '\0';
+process_info_len = len + 1;
+DEBUG(D_process_info) debug_printf("set_process_info: %s", process_info);
+va_end(ap);
+}
+
+
+
+
/*************************************************
* Handler for SIGUSR1 *
*************************************************/
setting up a handler that causes automatic restarting of any system call
that is in progress at the time.
+This function takes care to be signal-safe.
+
Argument: the signal number (SIGUSR1)
Returns: nothing
*/
static void
usr1_handler(int sig)
{
-sig = sig; /* Keep picky compilers happy */
-log_write(0, LOG_PROCESS, "%s", process_info);
-log_close_all();
-os_restarting_signal(SIGUSR1, usr1_handler);
+int fd;
+
+os_restarting_signal(sig, usr1_handler);
+
+fd = Uopen(process_log_path, O_APPEND|O_WRONLY, LOG_MODE);
+if (fd < 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
+ root, do the creation in an exim:exim subprocess. */
+
+ int euid = geteuid();
+ if (euid == exim_uid)
+ fd = Uopen(process_log_path, O_CREAT|O_APPEND|O_WRONLY, LOG_MODE);
+ else if (euid == root_uid)
+ fd = log_create_as_exim(process_log_path);
+ }
+
+/* If we are neither exim nor root, or if we failed to create the log file,
+give up. There is not much useful we can do with errors, since we don't want
+to disrupt whatever is going on outside the signal handler. */
+
+if (fd < 0) return;
+
+(void)write(fd, process_info, process_info_len);
+(void)close(fd);
}
-/*************************************************
-* Set up processing details *
-*************************************************/
-
-/* Save a text string for dumping when SIGUSR1 is received.
-Do checks for overruns.
-
-Arguments: format and arguments, as for printf()
-Returns: nothing
-*/
-
-void
-set_process_info(const char *format, ...)
-{
-int len;
-va_list ap;
-sprintf(CS process_info, "%5d ", (int)getpid());
-len = Ustrlen(process_info);
-va_start(ap, format);
-if (!string_vformat(process_info + len, PROCESS_INFO_SIZE - len, format, ap))
- Ustrcpy(process_info + len, "**** string overflowed buffer ****");
-DEBUG(D_process_info) debug_printf("set_process_info: %s\n", process_info);
-va_end(ap);
-}
-
-
-
-
-
/*************************************************
* Call fopen() with umask 777 and adjust mode *
*************************************************/
static void
show_whats_supported(FILE *f)
{
+ auth_info *authi;
+
#ifdef DB_VERSION_STRING
fprintf(f, "Berkeley DB: %s\n", DB_VERSION_STRING);
#elif defined(BTREEVERSION) && defined(HASHVERSION)
fprintf(f, " cdb");
#endif
#if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
- fprintf(f, " dbm dbmnz");
+ fprintf(f, " dbm dbmjz dbmnz");
#endif
#if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
fprintf(f, " dnsdb");
#ifdef AUTH_DOVECOT
fprintf(f, " dovecot");
#endif
+#ifdef AUTH_GSASL
+ fprintf(f, " gsasl");
+#endif
+#ifdef AUTH_HEIMDAL_GSSAPI
+ fprintf(f, " heimdal_gssapi");
+#endif
#ifdef AUTH_PLAINTEXT
fprintf(f, " plaintext");
#endif
tls_version_report(f);
#endif
-#ifdef AUTH_CYRUS_SASL
- auth_cyrus_sasl_version_report(f);
-#endif
+ for (authi = auths_available; *authi->driver_name != '\0'; ++authi) {
+ if (authi->version_report) {
+ (*authi->version_report)(f);
+ }
+ }
+ /* PCRE_PRERELEASE is either defined and empty or a bare sequence of
+ characters; unless it's an ancient version of PCRE in which case it
+ is not defined. */
+#ifndef PCRE_PRERELEASE
+#define PCRE_PRERELEASE
+#endif
+#define QUOTE(X) #X
+#define EXPAND_AND_QUOTE(X) QUOTE(X)
fprintf(f, "Library version: PCRE: Compile: %d.%d%s\n"
" Runtime: %s\n",
PCRE_MAJOR, PCRE_MINOR,
- /* PRE_PRERELEASE is either defined and empty or a string.
- * unless its an ancient version of PCRE in which case it
- * is not defined */
-#ifdef PCRE_PRERELEASE
- PCRE_PRERELEASE "",
-#else
- "",
-#endif
+ EXPAND_AND_QUOTE(PCRE_PRERELEASE) "",
pcre_version());
+#undef QUOTE
+#undef EXPAND_AND_QUOTE
init_lookup_list();
for (i = 0; i < lookup_list_count; i++)
void (**fn_addhist_ptr)(const char *))
{
void *dlhandle;
-void *dlhandle_curses = dlopen("libcurses.so", RTLD_GLOBAL|RTLD_LAZY);
+void *dlhandle_curses = dlopen("libcurses." DYNLIB_FN_EXT, RTLD_GLOBAL|RTLD_LAZY);
-dlhandle = dlopen("libreadline.so", RTLD_GLOBAL|RTLD_NOW);
+dlhandle = dlopen("libreadline." DYNLIB_FN_EXT, RTLD_GLOBAL|RTLD_NOW);
if (dlhandle_curses != NULL) dlclose(dlhandle_curses);
if (dlhandle != NULL)
show_whats_supported(stdout);
}
+ /* -bw: inetd wait mode, accept a listening socket as stdin */
+
+ else if (*argrest == 'w')
+ {
+ inetd_wait_mode = TRUE;
+ background_daemon = FALSE;
+ daemon_listen = TRUE;
+ if (*(++argrest) != '\0')
+ {
+ inetd_wait_timeout = readconf_readtime(argrest, 0, FALSE);
+ if (inetd_wait_timeout <= 0)
+ {
+ fprintf(stderr, "exim: bad time value %s: abandoned\n", argv[i]);
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
else badarg = TRUE;
break;
daemon_listen && queue_interval == 0
) ||
(
+ inetd_wait_mode && queue_interval >= 0
+ ) ||
+ (
list_options &&
(checking || smtp_input || extract_recipients ||
filter_test != FTEST_NONE || bi_option)
}
}
+/* Initialise lookup_list
+If debugging, already called above via version reporting.
+In either case, we initialise the list of available lookups while running
+as root. All dynamically modules are loaded from a directory which is
+hard-coded into the binary and is code which, if not a module, would be
+part of Exim already. Ability to modify the content of the directory
+is equivalent to the ability to modify a setuid binary!
+
+This needs to happen before we read the main configuration. */
+init_lookup_list();
+
/* Read the main runtime configuration data; this gives up if there
is a failure. It leaves the configuration file open so that the subsequent
configuration data for delivery can be read if needed. */
}
#endif /* EXIM_PERL */
-/* Initialise lookup_list
-If debugging, already called above via version reporting.
-This does mean that debugging causes the list to be initialised while root.
-This *should* be harmless -- all modules are loaded from a fixed dir and
-it's code that would, if not a module, be part of Exim already. */
-init_lookup_list();
-
/* Log the arguments of the call if the configuration file said so. This is
a debugging feature for finding out what arguments certain MUAs actually use.
Don't attempt it if logging is disabled, or if listing variables or if
for incoming messages via the daemon. The daemon cannot be run in mua_wrapper
mode. */
-if (daemon_listen || queue_interval > 0)
+if (daemon_listen || inetd_wait_mode || queue_interval > 0)
{
if (mua_wrapper)
{