X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/4ad401fb8100d20185c99aa00493e8bb49a53e45..44bbabb570db6e700a31469a0faf2ac27bf3bfe0:/src/src/exim.c diff --git a/src/src/exim.c b/src/src/exim.c index cf48c04b3..b4ea01dcd 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1,5 +1,3 @@ -/* $Cambridge: exim/src/src/exim.c,v 1.71 2010/06/07 00:12:42 pdp Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ @@ -140,6 +138,38 @@ return yield; +/************************************************* +* 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 * *************************************************/ @@ -149,6 +179,8 @@ what it is currently doing. It will only be used if the OS is capable of 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 */ @@ -156,10 +188,32 @@ 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); } @@ -348,35 +402,6 @@ if (exim_tvcmp(&now_tv, then_tv) <= 0) -/************************************************* -* 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(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 * *************************************************/ @@ -397,7 +422,7 @@ Returns: the fopened FILE or NULL */ FILE * -modefopen(uschar *filename, char *options, mode_t mode) +modefopen(const uschar *filename, const char *options, mode_t mode) { mode_t saved_umask = umask(0777); FILE *f = Ufopen(filename, options); @@ -570,17 +595,20 @@ if (euid == root_uid || euid != uid || egid != gid || igflag) DEBUG(D_uid) { - int group_count; + int group_count, save_errno; gid_t group_list[NGROUPS_MAX]; debug_printf("changed uid/gid: %s\n uid=%ld gid=%ld pid=%ld\n", msg, (long int)geteuid(), (long int)getegid(), (long int)getpid()); group_count = getgroups(NGROUPS_MAX, group_list); + save_errno = errno; debug_printf(" auxiliary group list:"); if (group_count > 0) { int i; for (i = 0; i < group_count; i++) debug_printf(" %d", (int)group_list[i]); } + else if (group_count < 0) + debug_printf(" ", strerror(save_errno)); else debug_printf(" "); debug_printf("\n"); } @@ -697,6 +725,8 @@ Returns: nothing 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) @@ -839,6 +869,9 @@ fprintf(f, "Authenticators:"); #ifdef AUTH_DOVECOT fprintf(f, " dovecot"); #endif +#ifdef AUTH_GSASL + fprintf(f, " gsasl"); +#endif #ifdef AUTH_PLAINTEXT fprintf(f, " plaintext"); #endif @@ -909,24 +942,37 @@ if (fixed_never_users[0] > 0) fprintf(f, "Size of off_t: " SIZE_T_FMT "\n", sizeof(off_t)); -/* This runtime check is to help diagnose library linkage mismatches which -result in segfaults and the like; as such, it's left until the end, -just in case. There will still be a "Configuration file is" line still to -come. */ -#ifdef SUPPORT_TLS -tls_version_report(f); -#endif - /* Everything else is details which are only worth reporting when debugging. Perhaps the tls_version_report should move into this too. */ DEBUG(D_any) do { int i; -#ifdef AUTH_CYRUS_SASL - auth_cyrus_sasl_version_report(f); +/* clang defines __GNUC__ (at least, for me) so test for it first */ +#if defined(__clang__) + fprintf(f, "Compiler: CLang [%s]\n", __clang_version__); +#elif defined(__GNUC__) + fprintf(f, "Compiler: GCC [%s]\n", +# ifdef __VERSION__ + __VERSION__ +# else + "? unknown version ?" +# endif + ); +#else + fprintf(f, "Compiler: \n"); #endif +#ifdef SUPPORT_TLS + tls_version_report(f); +#endif + + for (authi = auths_available; *authi->driver_name != '\0'; ++authi) { + if (authi->version_report) { + (*authi->version_report)(f); + } + } + fprintf(f, "Library version: PCRE: Compile: %d.%d%s\n" " Runtime: %s\n", PCRE_MAJOR, PCRE_MINOR, @@ -934,7 +980,9 @@ DEBUG(D_any) do { * unless its an ancient version of PCRE in which case it * is not defined */ #ifdef PCRE_PRERELEASE - PCRE_PRERELEASE "", +# define STRINGIFY(x) #x + STRINGIFY(PCRE_PRERELEASE) "", +# undef STRINGIFY #else "", #endif @@ -1035,19 +1083,23 @@ Returns: the dlopen handle or NULL on failure */ static void * -set_readline(char * (**fn_readline_ptr)(char *), - char * (**fn_addhist_ptr)(char *)) +set_readline(char * (**fn_readline_ptr)(const char *), + 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) { - *fn_readline_ptr = (char *(*)(char*))dlsym(dlhandle, "readline"); - *fn_addhist_ptr = (char *(*)(char*))dlsym(dlhandle, "add_history"); + /* Checked manual pages; at least in GNU Readline 6.1, the prototypes are: + * char * readline (const char *prompt); + * void add_history (const char *string); + */ + *fn_readline_ptr = (char *(*)(const char*))dlsym(dlhandle, "readline"); + *fn_addhist_ptr = (void(*)(const char*))dlsym(dlhandle, "add_history"); } else { @@ -1077,7 +1129,7 @@ Returns: pointer to dynamic memory, or NULL at end of file */ static uschar * -get_stdinput(char *(*fn_readline)(char *), char *(*fn_addhist)(char *)) +get_stdinput(char *(*fn_readline)(const char *), void(*fn_addhist)(const char *)) { int i; int size = 0; @@ -1281,7 +1333,7 @@ for (m = macros; m != NULL; m = m->next) return FALSE; } } -DEBUG(D_any) debug_printf("macros_trusted overriden to true by whitelisting\n"); +DEBUG(D_any) debug_printf("macros_trusted overridden to true by whitelisting\n"); return TRUE; #endif } @@ -1396,7 +1448,19 @@ if (route_finduser(US EXIM_USERNAME, &pw, &exim_uid)) EXIM_USERNAME); exit(EXIT_FAILURE); } - exim_gid = pw->pw_gid; + /* If ref:name uses a number as the name, route_finduser() returns + TRUE with exim_uid set and pw coerced to NULL. */ + if (pw) + exim_gid = pw->pw_gid; +#ifndef EXIM_GROUPNAME + else + { + fprintf(stderr, + "exim: ref:name should specify a usercode, not a group.\n" + "exim: can't let you get away with it unless you also specify a group.\n"); + exit(EXIT_FAILURE); + } +#endif } else { @@ -3281,6 +3345,11 @@ till after reading the config, which might specify the exim gid. Therefore, save the group list here first. */ group_count = getgroups(NGROUPS_MAX, group_list); +if (group_count < 0) + { + fprintf(stderr, "exim: getgroups() failed: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } /* There is a fundamental difference in some BSD systems in the matter of groups. FreeBSD and BSDI are known to be different; NetBSD and OpenBSD are @@ -4547,8 +4616,8 @@ if (expansion_test) else { - char *(*fn_readline)(char *) = NULL; - char *(*fn_addhist)(char *) = NULL; + char *(*fn_readline)(const char *) = NULL; + void (*fn_addhist)(const char *) = NULL; #ifdef USE_READLINE void *dlhandle = set_readline(&fn_readline, &fn_addhist);