/* Copyright (c) The Exim Maintainers 2020 - 2022 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/* The main function: entry point, initialization, and high-level control.
}
+static void *
+function_store_get(PCRE2_SIZE size, void * tag)
+{
+return store_get((int)size, GET_UNTAINTED); /* loses track of taint */
+}
-
-/*************************************************
-* Enums for cmdline interface *
-*************************************************/
-
-enum commandline_info { CMDINFO_NONE=0,
- CMDINFO_HELP, CMDINFO_SIEVE, CMDINFO_DSCP };
+static void
+function_store_nullfree(void * block, void * tag)
+{
+}
/*************************************************
-* Compile regular expression and panic on fail *
+* Enums for cmdline interface *
*************************************************/
-/* This function is called when failure to compile a regular expression leads
-to a panic exit. In other cases, pcre_compile() is called directly. In many
-cases where this function is used, the results of the compilation are to be
-placed in long-lived store, so we temporarily reset the store management
-functions that PCRE uses if the use_malloc flag is set.
-
-Argument:
- pattern the pattern to compile
- caseless TRUE if caseless matching is required
- use_malloc TRUE if compile into malloc store
-
-Returns: pointer to the compiled pattern
-*/
-
-const pcre2_code *
-regex_must_compile(const uschar * pattern, BOOL caseless, BOOL use_malloc)
-{
-size_t offset;
-int options = caseless ? PCRE_COPT|PCRE2_CASELESS : PCRE_COPT;
-const pcre2_code * yield;
-int err;
-pcre2_general_context * gctx;
-pcre2_compile_context * cctx;
-
-if (use_malloc)
- {
- gctx = pcre2_general_context_create(function_store_malloc, function_store_free, NULL);
- cctx = pcre2_compile_context_create(gctx);
- }
-else
- cctx = pcre_cmp_ctx;
+enum commandline_info { CMDINFO_NONE=0,
+ CMDINFO_HELP, CMDINFO_SIEVE, CMDINFO_DSCP };
-if (!(yield = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, options,
- &err, &offset, cctx)))
- {
- uschar errbuf[128];
- pcre2_get_error_message(err, errbuf, sizeof(errbuf));
- log_write(0, LOG_MAIN|LOG_PANIC_DIE, "regular expression error: "
- "%s at offset %ld while compiling %s", errbuf, (long)offset, pattern);
- }
-if (use_malloc)
- {
- pcre2_compile_context_free(cctx);
- pcre2_general_context_free(gctx);
- }
-return yield;
-}
static void
pcre_init(void)
{
-pcre_gen_ctx = pcre2_general_context_create(function_store_malloc, function_store_free, NULL);
-pcre_cmp_ctx = pcre2_compile_context_create(pcre_gen_ctx);
-pcre_mtc_ctx = pcre2_match_context_create(pcre_gen_ctx);
+pcre_mlc_ctx = pcre2_general_context_create(function_store_malloc, function_store_free, NULL);
+pcre_gen_ctx = pcre2_general_context_create(function_store_get, function_store_nullfree, NULL);
+
+pcre_mlc_cmp_ctx = pcre2_compile_context_create(pcre_mlc_ctx);
+pcre_gen_cmp_ctx = pcre2_compile_context_create(pcre_gen_ctx);
+
+pcre_gen_mtc_ctx = pcre2_match_context_create(pcre_gen_ctx);
}
/* This function runs a regular expression match, and sets up the pointers to
the matched substrings. The matched strings are copied so the lifetime of
-the subject is not a problem.
+the subject is not a problem. Matched strings will have the same taint status
+as the subject string (this is not a de-taint method, and must not be made so
+given the support for wildcards in REs).
Arguments:
re the compiled expression
{
pcre2_match_data * md = pcre2_match_data_create_from_pattern(re, pcre_gen_ctx);
int res = pcre2_match(re, (PCRE2_SPTR)subject, PCRE2_ZERO_TERMINATED, 0,
- PCRE_EOPT | options, md, pcre_mtc_ctx);
+ PCRE_EOPT | options, md, pcre_gen_mtc_ctx);
BOOL yield;
if ((yield = (res >= 0)))
{
+ PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
res = pcre2_get_ovector_count(md);
expand_nmax = setup < 0 ? 0 : setup + 1;
for (int matchnum = setup < 0 ? 0 : 1; matchnum < res; matchnum++)
{
- PCRE2_SIZE len;
- pcre2_substring_get_bynumber(md, matchnum,
- (PCRE2_UCHAR **)&expand_nstring[expand_nmax], &len);
- expand_nlength[expand_nmax++] = (int)len;
+ /* Although PCRE2 has a pcre2_substring_get_bynumber() conveneience, it
+ seems to return a bad pointer when a capture group had no data, eg. (.*)
+ matching zero letters. So use the underlying ovec and hope (!) that the
+ offsets are sane (including that case). Should we go further and range-
+ check each one vs. the subject string length? */
+ int off = matchnum * 2;
+ int len = ovec[off + 1] - ovec[off];
+ expand_nstring[expand_nmax] = string_copyn(subject + ovec[off], len);
+ expand_nlength[expand_nmax++] = len;
}
expand_nmax--;
}
pcre2_get_error_message(res, errbuf, sizeof(errbuf));
debug_printf_indent("pcre2: %s\n", errbuf);
}
-pcre2_match_data_free(md);
+/* pcre2_match_data_free(md); gen ctx needs no free */
return yield;
}
pcre2_match_data * md = pcre2_match_data_create(1, pcre_gen_ctx);
int rc = pcre2_match(re, (PCRE2_SPTR)subject,
slen >= 0 ? slen : PCRE2_ZERO_TERMINATED,
- 0, PCRE_EOPT, md, pcre_mtc_ctx);
+ 0, PCRE_EOPT, md, pcre_gen_mtc_ctx);
PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
-if (rc < 0)
- return FALSE;
-if (rptr)
- *rptr = string_copyn(subject + ovec[0], ovec[1] - ovec[0]);
-return TRUE;
+BOOL ret = FALSE;
+
+if (rc >= 0)
+ {
+ if (rptr)
+ *rptr = string_copyn(subject + ovec[0], ovec[1] - ovec[0]);
+ ret = TRUE;
+ }
+/* pcre2_match_data_free(md); gen ctx needs no free */
+return ret;
}
***********************************************/
#define STACKDUMP_MAX 24
-static void
+void
stackdump(void)
{
#ifndef NO_EXECINFO
char ** ss;
int nptrs = backtrace(buf, STACKDUMP_MAX);
-log_write(0, LOG_MAIN|LOG_PANIC, "backtrace\n");
-log_write(0, LOG_MAIN|LOG_PANIC, "---\n");
+log_write(0, LOG_MAIN|LOG_PANIC, "backtrace");
+log_write(0, LOG_MAIN|LOG_PANIC, "---");
if ((ss = backtrace_symbols(buf, nptrs)))
{
for (int i = 0; i < nptrs; i++)
- log_write(0, LOG_MAIN|LOG_PANIC, "\t%s\n", ss[i]);
+ log_write(0, LOG_MAIN|LOG_PANIC, "\t%s", ss[i]);
free(ss);
}
else
- log_write(0, LOG_MAIN|LOG_PANIC, "backtrace_symbols: %s\n", strerror(errno));
-log_write(0, LOG_MAIN|LOG_PANIC, "---\n");
+ log_write(0, LOG_MAIN|LOG_PANIC, "backtrace_symbols: %s", strerror(errno));
+log_write(0, LOG_MAIN|LOG_PANIC, "---");
#endif
}
#undef STACKDUMP_MAX
if (macro_read_assignment(big_buffer))
printf("Defined macro '%s'\n", mlast->name);
}
+else if (Ustrncmp(big_buffer, "set ", 4) == 0)
+ printf("%s\n", acl_standalone_setvar(big_buffer+4));
else
if ((s = expand_string(big_buffer))) printf("%s\n", CS s);
else printf("Failed: %s\n", expand_string_message);
using mac_ismsgid, which uses this. */
regex_ismsgid =
- regex_must_compile(US"^(?:[^\\W_]{6}-){2}[^\\W_]{2}$", FALSE, TRUE);
+ regex_must_compile(US"^(?:[^\\W_]{6}-){2}[^\\W_]{2}$", MCS_NOFLAGS, TRUE);
/* Precompile the regular expression that is used for matching an SMTP error
code, possibly extended, at the start of an error message. Note that the
regex_smtp_code =
regex_must_compile(US"^\\d\\d\\d\\s(?:\\d\\.\\d\\d?\\d?\\.\\d\\d?\\d?\\s)?",
- FALSE, TRUE);
+ MCS_NOFLAGS, 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);
+ regex_must_compile(US"^[A-Za-z0-9_/.-]*$", MCS_NOFLAGS, TRUE);
#endif
-for (i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
-
/* 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. */
-bdf: Ditto, but in the foreground.
*/
case 'd':
- f.daemon_listen = TRUE;
+ f.daemon_listen = f.daemon_scion = TRUE;
if (*argrest == 'f') f.background_daemon = FALSE;
else if (*argrest) badarg = TRUE;
break;
case 'w':
f.inetd_wait_mode = TRUE;
f.background_daemon = FALSE;
- f.daemon_listen = TRUE;
+ f.daemon_listen = f.daemon_scion = TRUE;
if (*argrest)
if ((inetd_wait_timeout = readconf_readtime(argrest, 0, FALSE)) <= 0)
exim_fail("exim: bad time value %s: abandoned\n", argv[i]);
else if (Ustrcmp(argrest, "ai") == 0)
authenticated_id = string_copy_taint(
- exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"),
+ exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMai"),
GET_TAINTED);
/* -oMi: Set incoming interface address */
{
int old_pool = store_pool;
#ifdef MEASURE_TIMING
- struct timeval t0, diff;
+ struct timeval t0;
(void)gettimeofday(&t0, NULL);
#endif
{
int old_pool = store_pool;
#ifdef MEASURE_TIMING
- struct timeval t0, diff;
+ struct timeval t0;
(void)gettimeofday(&t0, NULL);
#endif
if (gecos_pattern && gecos_name)
{
const pcre2_code *re;
- re = regex_must_compile(gecos_pattern, FALSE, TRUE); /* Use malloc */
+ re = regex_must_compile(gecos_pattern, MCS_NOFLAGS, TRUE); /* Use malloc */
if (regex_match_and_setup(re, name, 0, -1))
{
routines in it, so call even if tls_require_ciphers is unset */
{
# ifdef MEASURE_TIMING
- struct timeval t0, diff;
+ struct timeval t0;
(void)gettimeofday(&t0, NULL);
# endif
if (!tls_dropprivs_validate_require_cipher(FALSE))
memset(sender_host_cache, 0, sizeof(sender_host_cache));
if (verify_check_host(&hosts_connection_nolog) == OK)
+ {
BIT_CLEAR(log_selector, log_selector_size, Li_smtp_connection);
+ BIT_CLEAR(log_selector, log_selector_size, Li_smtp_no_mail);
+ }
log_write(L_smtp_connection, LOG_MAIN, "%s", smtp_get_connection_info());
/* NOTE: We do *not* call smtp_log_no_mail() if smtp_start_session() fails,
smtp_out = stdout;
memset(sender_host_cache, 0, sizeof(sender_host_cache));
if (verify_check_host(&hosts_connection_nolog) == OK)
+ {
BIT_CLEAR(log_selector, log_selector_size, Li_smtp_connection);
+ BIT_CLEAR(log_selector, log_selector_size, Li_smtp_no_mail);
+ }
log_write(L_smtp_connection, LOG_MAIN, "%s", smtp_get_connection_info());
if (!smtp_start_session())
{
dnslist_domain = dnslist_matched = NULL;
#ifdef WITH_CONTENT_SCAN
malware_name = NULL;
+ regex_vars_clear();
#endif
callout_address = NULL;
sending_ip_address = NULL;
deliver_localpart_data = deliver_domain_data =
recipient_data = sender_data = NULL;
acl_var_m = NULL;
- for(int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
store_reset(reset_point);
}