summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTodd Lyons <tlyons@exim.org>2014-05-26 12:14:16 -0700
committerTodd Lyons <tlyons@exim.org>2014-05-26 12:14:16 -0700
commit5b7a7c051c9ab9ee7c924a611f90ef2be03e0ad0 (patch)
tree18486f503facc9bf41244f63ab08da5cfb684d44 /src
parent69aca2feaca1ebbc55c6f1adaee4738dc328ae90 (diff)
SECURITY: DMARC uses From header untrusted dataexim-4_82_1
CVE-2014-2957 To find the sending domain, expand_string() was used to directly parse the contents of the From header. This passes untrusted data directly into an internal function. Convert to use standard internal parsing functions.
Diffstat (limited to 'src')
-rw-r--r--src/src/dmarc.c43
1 files changed, 24 insertions, 19 deletions
diff --git a/src/src/dmarc.c b/src/src/dmarc.c
index 6e516525f..c6190613e 100644
--- a/src/src/dmarc.c
+++ b/src/src/dmarc.c
@@ -168,26 +168,31 @@ int dmarc_process() {
dmarc_abort = TRUE;
else
{
- /* I strongly encourage anybody who can make this better to contact me directly!
- * <cannonball> Is this an insane way to extract the email address from the From: header?
- * <jgh_hm> it's sure a horrid layer-crossing....
- * <cannonball> I'm not denying that :-/
- * <jgh_hm> there may well be no better though
- */
- header_from_sender = expand_string(
- string_sprintf("${domain:${extract{1}{:}{${addresses:%s}}}}",
- from_header->text) );
- /* The opendmarc library extracts the domain from the email address, but
- * only try to store it if it's not empty. Otherwise, skip out of DMARC. */
- if (strcmp( CCS header_from_sender, "") == 0)
- dmarc_abort = TRUE;
- libdm_status = (dmarc_abort == TRUE) ?
- DMARC_PARSE_OKAY :
- opendmarc_policy_store_from_domain(dmarc_pctx, header_from_sender);
- if (libdm_status != DMARC_PARSE_OKAY)
+ uschar * errormsg;
+ int dummy, domain;
+ uschar * p;
+ uschar saveend;
+
+ parse_allow_group = TRUE;
+ p = parse_find_address_end(from_header->text, FALSE);
+ saveend = *p; *p = '\0';
+ if ((header_from_sender = parse_extract_address(from_header->text, &errormsg,
+ &dummy, &dummy, &domain, FALSE)))
+ header_from_sender += domain;
+ *p = saveend;
+
+ /* The opendmarc library extracts the domain from the email address, but
+ * only try to store it if it's not empty. Otherwise, skip out of DMARC. */
+ if (!header_from_sender || (strcmp( CCS header_from_sender, "") == 0))
+ dmarc_abort = TRUE;
+ libdm_status = dmarc_abort ?
+ DMARC_PARSE_OKAY :
+ opendmarc_policy_store_from_domain(dmarc_pctx, header_from_sender);
+ if (libdm_status != DMARC_PARSE_OKAY)
{
- log_write(0, LOG_MAIN|LOG_PANIC, "failure to store header From: in DMARC: %s, header was '%s'",
- opendmarc_policy_status_to_str(libdm_status), from_header->text);
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "failure to store header From: in DMARC: %s, header was '%s'",
+ opendmarc_policy_status_to_str(libdm_status), from_header->text);
dmarc_abort = TRUE;
}
}