* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2017 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
va_end(ap);
}
+/***********************************************
+* Handler for SIGTERM *
+***********************************************/
+static void
+term_handler(int sig)
+{
+ exit(1);
+}
/*************************************************
{
if (smtp_input)
{
- #ifdef SUPPORT_TLS
- tls_close(TRUE, FALSE); /* Shut down the TLS library */
- #endif
+#ifdef SUPPORT_TLS
+ tls_close(NULL, TLS_NO_SHUTDOWN); /* Shut down the TLS library */
+#endif
(void)close(fileno(smtp_in));
(void)close(fileno(smtp_out));
smtp_in = NULL;
#ifdef WITH_CONTENT_SCAN
fprintf(f, " Content_Scanning");
#endif
+#ifdef SUPPORT_DANE
+ fprintf(f, " DANE");
+#endif
#ifndef DISABLE_DKIM
fprintf(f, " DKIM");
#endif
#ifdef EXPERIMENTAL_SRS
fprintf(f, " Experimental_SRS");
#endif
+#ifdef EXPERIMENTAL_ARC
+ fprintf(f, " Experimental_ARC");
+#endif
#ifdef EXPERIMENTAL_BRIGHTMAIL
fprintf(f, " Experimental_Brightmail");
#endif
-#ifdef EXPERIMENTAL_DANE
- fprintf(f, " Experimental_DANE");
-#endif
#ifdef EXPERIMENTAL_DCC
fprintf(f, " Experimental_DCC");
#endif
* Validate that the macros given are okay *
*************************************************/
-#ifdef WHITELIST_D_MACROS
-static void
-wlist_check(uschar * name, uschar * val, void * ctx)
-{
-uschar ** w, ** whites = ctx;
-unsigned len;
-int n;
-
-for (w = whites; *w; ++w)
- if (Ustrcmp(*w, name) == 0) break;
-if (*w)
- {
- if (!val || !*val) return;
- len = Ustrlen(val);
- if ((n = pcre_exec(regex_whitelisted_macro, NULL, CS val, len,
- 0, PCRE_EOPT, NULL, 0)) >= 0)
- return;
- if (n != PCRE_ERROR_NOMATCH)
- debug_printf("macros_trusted checking %s returned %d\n", name, n);
- }
-*whites = NULL;
-return;
-}
-#endif
-
-
/* Typically, Exim will drop privileges if macros are supplied. In some
cases, we want to not do so.
{
#ifdef WHITELIST_D_MACROS
macro_item *m;
-uschar *whitelisted, *end, *p, **whites;
+uschar *whitelisted, *end, *p, **whites, **w;
int white_count, i, n;
size_t len;
BOOL prev_char_item, found;
}
whites[i] = NULL;
-tree_walk(tree_macros, wlist_check, whites);
-if (!*whites) return FALSE;
-
+/* The list of commandline macros should be very short.
+Accept the N*M complexity. */
+for (m = macros_user; m; m = m->next) if (m->command_line)
+ {
+ found = FALSE;
+ for (w = whites; *w; ++w)
+ if (Ustrcmp(*w, m->name) == 0)
+ {
+ found = TRUE;
+ break;
+ }
+ if (!found)
+ return FALSE;
+ if (!m->replacement)
+ continue;
+ if ((len = m->replen) == 0)
+ continue;
+ n = pcre_exec(regex_whitelisted_macro, NULL, CS m->replacement, len,
+ 0, PCRE_EOPT, NULL, 0);
+ if (n < 0)
+ {
+ if (n != PCRE_ERROR_NOMATCH)
+ debug_printf("macros_trusted checking %s returned %d\n", m->name, n);
+ return FALSE;
+ }
+ }
DEBUG(D_any) debug_printf("macros_trusted overridden to true by whitelisting\n");
return TRUE;
#endif
if (isupper(big_buffer[0]))
{
if (macro_read_assignment(big_buffer))
- {
- uschar * s = Ustrchr(big_buffer, '=');
- printf("Defined macro '%.*s'\n", s - big_buffer, big_buffer);
- }
+ printf("Defined macro '%s'\n", mlast->name);
}
else
if ((line = expand_string(big_buffer))) printf("%s\n", CS line);
running_in_test_harness =
*running_status == '<' && Ustrcmp(running_status, "<<<testing>>>") == 0;
+if (running_in_test_harness)
+ debug_store = TRUE;
/* The C standard says that the equivalent of setlocale(LC_ALL, "C") is obeyed
at the start of a program; however, it seems that some environments do not
set_process_info("initializing");
os_restarting_signal(SIGUSR1, usr1_handler);
+/* If running in a dockerized environment, the TERM signal is only
+delegated to the PID 1 if we request it by setting an signal handler */
+if (getpid() == 1) signal(SIGTERM, term_handler);
+
/* SIGHUP is used to get the daemon to reconfigure. It gets set as appropriate
in the daemon code. For the rest of Exim's uses, we ignore it. */
while (isspace(*s)) s++;
}
- if (macro_search(name))
- {
- fprintf(stderr, "exim: duplicated -D in command line\n");
- exit(EXIT_FAILURE);
- }
+ for (m = macros_user; m; m = m->next)
+ if (Ustrcmp(m->name, name) == 0)
+ {
+ fprintf(stderr, "exim: duplicated -D in command line\n");
+ exit(EXIT_FAILURE);
+ }
m = macro_create(name, s, TRUE);
fprintf(stderr, "exim: too many -D options on command line\n");
exit(EXIT_FAILURE);
}
- clmacros[clmacro_count++] = string_sprintf("-D%s=%s",
- m->tnode.name, m->tnode.data.ptr);
+ clmacros[clmacro_count++] = string_sprintf("-D%s=%s", m->name,
+ m->replacement);
}
#endif
break;
Don't attempt it if logging is disabled, or if listing variables or if
verifying/testing addresses or expansions. */
-if (((debug_selector & D_any) != 0 || LOGGING(arguments))
- && really_exim && !list_options && !checking)
+if ( (debug_selector & D_any || LOGGING(arguments))
+ && really_exim && !list_options && !checking)
{
int i;
uschar *p = big_buffer;
Ustrcpy(p, "cwd= (failed)");
- Ustrncpy(p + 4, initial_cwd, big_buffer_size-5);
+ if (!initial_cwd)
+ p += 13;
+ else
+ {
+ Ustrncpy(p + 4, initial_cwd, big_buffer_size-5);
+ p += 4 + Ustrlen(initial_cwd);
+ /* in case p is near the end and we don't provide enough space for
+ * string_format to be willing to write. */
+ *p = '\0';
+ }
- while (*p) p++;
(void)string_format(p, big_buffer_size - (p - big_buffer), " %d args:", argc);
while (*p) p++;
for (i = 0; i < argc; i++)
if (list_options)
{
+ BOOL fail = FALSE;
set_process_info("listing variables");
- if (recipients_arg >= argc) readconf_print(US"all", NULL, flag_n);
- else for (i = recipients_arg; i < argc; i++)
+ if (recipients_arg >= argc)
+ fail = !readconf_print(US"all", NULL, flag_n);
+ else for (i = recipients_arg; i < argc; i++)
+ {
+ if (i < argc - 1 &&
+ (Ustrcmp(argv[i], "router") == 0 ||
+ Ustrcmp(argv[i], "transport") == 0 ||
+ Ustrcmp(argv[i], "authenticator") == 0 ||
+ Ustrcmp(argv[i], "macro") == 0 ||
+ Ustrcmp(argv[i], "environment") == 0))
{
- if (i < argc - 1 &&
- (Ustrcmp(argv[i], "router") == 0 ||
- Ustrcmp(argv[i], "transport") == 0 ||
- Ustrcmp(argv[i], "authenticator") == 0 ||
- Ustrcmp(argv[i], "macro") == 0 ||
- Ustrcmp(argv[i], "environment") == 0))
- {
- readconf_print(argv[i+1], argv[i], flag_n);
- i++;
- }
- else readconf_print(argv[i], NULL, flag_n);
+ fail |= !readconf_print(argv[i+1], argv[i], flag_n);
+ i++;
}
- exim_exit(EXIT_SUCCESS, US"main");
+ else
+ fail = !readconf_print(argv[i], NULL, flag_n);
+ }
+ exim_exit(fail ? EXIT_FAILURE : EXIT_SUCCESS, US"main");
}
if (list_config)
{
set_process_info("listing config");
- readconf_print(US"config", NULL, flag_n);
- exim_exit(EXIT_SUCCESS, US"main");
+ exim_exit(readconf_print(US"config", NULL, flag_n)
+ ? EXIT_SUCCESS : EXIT_FAILURE, US"main");
}
/* Only admin users may see config-file macros this way */
- if (!admin_user) tree_macros = NULL;
+ if (!admin_user) macros_user = macros = mlast = NULL;
/* Allow $recipients for this testing */
{
if (version_printed)
{
+ if (Ustrchr(config_main_filelist, ':'))
+ printf("Configuration file search path is %s\n", config_main_filelist);
printf("Configuration file is %s\n", config_main_filename);
return EXIT_SUCCESS;
}
case when it is forced by -oMa. However, we must flag that it isn't a socket,
so that the test for IP options is skipped for -bs input. */
-if (sender_host_address != NULL && sender_fullhost == NULL)
+if (sender_host_address && !sender_fullhost)
{
host_build_sender_fullhost();
set_process_info("handling incoming connection from %s via -oMa",