diff options
author | Todd Lyons <tlyons@exim.org> | 2014-05-26 12:14:16 -0700 |
---|---|---|
committer | Todd Lyons <tlyons@exim.org> | 2014-05-26 12:14:16 -0700 |
commit | 5b7a7c051c9ab9ee7c924a611f90ef2be03e0ad0 (patch) | |
tree | 18486f503facc9bf41244f63ab08da5cfb684d44 /src | |
parent | 69aca2feaca1ebbc55c6f1adaee4738dc328ae90 (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.c | 43 |
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; } } |