# DISABLE_D_OPTION=yes
+#------------------------------------------------------------------------------
+# By contrast, you might be maintaining a system which relies upon the ability
+# to override values with -D and assumes that these will be passed through to
+# the delivery processes. As of Exim 4.73, this is no longer the case by
+# default. Going forward, we strongly recommend that you use a shim Exim
+# configuration file owned by root stored under TRUSTED_CONFIG_PREFIX_LIST.
+# That shim can set macros before .include'ing your main configuration file.
+#
+# As a strictly transient measure to ease migration to 4.73, the
+# WHITELIST_D_MACROS value definies a colon-separated list of macro-names
+# which are permitted to be overriden from the command-line which will be
+# honoured by the Exim user. So these are macros that can persist to delivery
+# time.
+# Examples might be -DTLS or -DSPOOL=/some/dir. The values on the
+# command-line are filtered to only permit: [A-Za-z0-9_/.-]*
+#
+# This option is highly likely to be removed in a future release. It exists
+# only to make 4.73 as easy as possible to migrate to. If you use it, we
+# encourage you to schedule time to rework your configuration to not depend
+# upon it. Most people should not need to use this.
+#
+# By default, no macros are whitelisted for -D usage.
+
+# WHITELIST_D_MACROS=TLS:SPOOL
+
#------------------------------------------------------------------------------
# Exim has support for the AUTH (authentication) extension of the SMTP
# protocol, as defined by RFC 2554. If you don't know what SMTP authentication
fprintf(new, "\"%s\"\n", value);
}
- /* Timezone values HEADERS_CHARSET, and TCP_WRAPPERS_DAEMON_NAME get quoted */
+ /* Timezone values HEADERS_CHARSET, TCP_WRAPPERS_DAEMON_NAME and
+ WHITELIST_D_MACROS get quoted */
else if (strcmp(name, "TIMEZONE_DEFAULT") == 0||
strcmp(name, "TCP_WRAPPERS_DAEMON_NAME") == 0||
- strcmp(name, "HEADERS_CHARSET") == 0)
+ strcmp(name, "HEADERS_CHARSET") == 0||
+ strcmp(name, "WHITELIST_D_MACROS") == 0)
fprintf(new, "\"%s\"\n", value);
/* For others, quote any paths and don't quote anything else */
+/*************************************************
+* Validate that the macros given are okay *
+*************************************************/
+
+/* Typically, Exim will drop privileges if macros are supplied. In some
+cases, we want to not do so.
+
+Arguments: none (macros is a global)
+Returns: true if trusted, false otherwise
+*/
+
+static BOOL
+macros_trusted(void)
+{
+#ifdef WHITELIST_D_MACROS
+macro_item *m;
+uschar *whitelisted, *end, *p, **whites, **w;
+int white_count, i, n;
+size_t len;
+BOOL prev_char_item, found;
+#endif
+
+if (macros == NULL)
+ return TRUE;
+#ifndef WHITELIST_D_MACROS
+return FALSE;
+#else
+
+/* Get a list of macros which are whitelisted */
+whitelisted = string_copy_malloc(US WHITELIST_D_MACROS);
+prev_char_item = FALSE;
+white_count = 0;
+for (p = whitelisted; *p != '\0'; ++p)
+ {
+ if (*p == ':' || isspace(*p))
+ {
+ *p = '\0';
+ if (prev_char_item)
+ ++white_count;
+ prev_char_item = FALSE;
+ continue;
+ }
+ if (!prev_char_item)
+ prev_char_item = TRUE;
+ }
+end = p;
+if (prev_char_item)
+ ++white_count;
+if (!white_count)
+ return FALSE;
+whites = store_malloc(sizeof(uschar *) * (white_count+1));
+for (p = whitelisted, i = 0; (p != end) && (i < white_count); ++p)
+ {
+ if (*p != '\0')
+ {
+ whites[i++] = p;
+ if (i == white_count)
+ break;
+ while (*p != '\0' && p < end)
+ ++p;
+ }
+ }
+whites[i] = NULL;
+
+/* The list of macros should be very short. Accept the N*M complexity. */
+for (m = macros; m != NULL; m = m->next)
+ {
+ found = FALSE;
+ for (w = whites; *w; ++w)
+ if (Ustrcmp(*w, m->name) == 0)
+ {
+ found = TRUE;
+ break;
+ }
+ if (!found)
+ return FALSE;
+ if (m->replacement == NULL)
+ continue;
+ len = Ustrlen(m->replacement);
+ if (len == 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_printf("macros_trusted overriden to true by whitelisting\n");
+return TRUE;
+#endif
+}
+
+
/*************************************************
* Entry point and high-level code *
*************************************************/
regex_must_compile(US"^\\d\\d\\d\\s(?:\\d\\.\\d\\d?\\d?\\.\\d\\d?\\d?\\s)?",
FALSE, TRUE);
+#ifdef WHITELIST_D_MACROS
+/* Precompile the regular expression used to filter the content of macros
+given to -D for permissibility. */
+
+regex_whitelisted_macro =
+ regex_must_compile(US"^[A-Za-z0-9_/.-]*$", FALSE, TRUE);
+#endif
+
+
/* If the program is called as "mailq" treat it as equivalent to "exim -bp";
this seems to be a generally accepted convention, since one finds symbolic
links called "mailq" in standard OS configurations. */
configuration file changes and macro definitions haven't happened. */
if (( /* EITHER */
- (!trusted_config || macros != NULL) && /* Config changed, and */
+ (!trusted_config || /* Config changed, or */
+ !macros_trusted()) && /* impermissible macros and */
real_uid != root_uid && /* Not root, and */
!running_in_test_harness /* Not fudged */
) || /* OR */