*/
void
-set_process_info(char *format, ...)
+set_process_info(const char *format, ...)
{
int len;
va_list ap;
*/
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);
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(" <error: %s>", strerror(save_errno));
else debug_printf(" <none>");
debug_printf("\n");
}
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;
+/* 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: <unknown>\n");
+#endif
+
+#ifdef SUPPORT_TLS
+ tls_version_report(f);
+#endif
+
#ifdef AUTH_CYRUS_SASL
auth_cyrus_sasl_version_report(f);
#endif
" Runtime: %s\n",
PCRE_MAJOR, PCRE_MINOR,
/* PRE_PRERELEASE is either defined and empty or a string.
- * This should work: */
+ * unless its an ancient version of PCRE in which case it
+ * is not defined */
+#ifdef PCRE_PRERELEASE
PCRE_PRERELEASE "",
+#else
+ "",
+#endif
pcre_version());
init_lookup_list();
lookup_list[i]->version_report(f);
}
+#ifdef WHITELIST_D_MACROS
+ fprintf(f, "WHITELIST_D_MACROS: \"%s\"\n", WHITELIST_D_MACROS);
+#else
+ fprintf(f, "WHITELIST_D_MACROS unset\n");
+#endif
+#ifdef TRUSTED_CONFIG_LIST
+ fprintf(f, "TRUSTED_CONFIG_LIST: \"%s\"\n", TRUSTED_CONFIG_LIST);
+#else
+ fprintf(f, "TRUSTED_CONFIG_LIST unset\n");
+#endif
+
} while (0);
}
*/
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);
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
{
*/
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;
return FALSE;
}
}
-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
}
int filter_sfd = -1;
int filter_ufd = -1;
int group_count;
-int i;
+int i, rv;
int list_queue_option = 0;
int msg_action = 0;
int msg_action_arg = -1;
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
{
if (real_uid == root_uid)
{
- setgid(real_gid);
- setuid(real_uid);
+ rv = setgid(real_gid);
+ if (rv)
+ {
+ fprintf(stderr, "exim: setgid(%ld) failed: %s\n",
+ (long int)real_gid, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ rv = setuid(real_uid);
+ if (rv)
+ {
+ fprintf(stderr, "exim: setuid(%ld) failed: %s\n",
+ (long int)real_uid, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
}
/* If neither the original real uid nor the original euid was root, Exim is
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
and should be used for any logging information because attempts to write
to the log will usually fail. To arrange this, we unset really_exim. However,
if no stderr is available there is no point - we might as well have a go
- at the log (if it fails, syslog will be written). */
+ at the log (if it fails, syslog will be written).
- if (log_stderr != NULL) really_exim = FALSE;
+ Note that if the invoker is Exim, the logs remain available. Messing with
+ this causes unlogged successful deliveries. */
+
+ if ((log_stderr != NULL) && (real_uid != exim_uid))
+ really_exim = FALSE;
}
/* Privilege is to be retained for the moment. It may be dropped later,
/* When we are retaining a privileged uid, we still change to the exim gid. */
-else setgid(exim_gid);
+else
+ {
+ int rv;
+ rv = setgid(exim_gid);
+ /* Impact of failure is that some stuff might end up with an incorrect group.
+ We track this for failures from root, since any attempt to change privilege
+ by root should succeed and failures should be examined. For non-root,
+ there's no security risk. For me, it's { exim -bV } on a just-built binary,
+ no need to complain then. */
+ if (rv == -1)
+ {
+ if (!(unprivileged || removed_privilege))
+ {
+ fprintf(stderr,
+ "exim: changing group failed: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ else
+ DEBUG(D_any) debug_printf("changing group to %ld failed: %s\n",
+ (long int)exim_gid, strerror(errno));
+ }
+ }
/* Handle a request to scan a file for malware */
if (malware_test_file)
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);