Control: tags -1 moreinfo On 2021-06-01 10:34:59, David Bürgin wrote: > Package: release.debian.org > Severity: normal > User: release.debian....@packages.debian.org > Usertags: unblock > > Please unblock package opendmarc > > Fixes for three CVEs have recently been released by the OpenDMARC > developers. The fixes themselves are spread over more than a dozen > commits, so I referred to the final code from upstream version 1.4.1.1. > Detailed description of the CVEs and their resolution can be found at: > https://github.com/trusteddomainproject/OpenDMARC/tree/rel-opendmarc-1-4-1-1/SECURITY > > [ Reason ] > Fixes for several CVEs have been released in OpenDMARC 1.4.1.1. > > [ Impact ] > Current opendmarc 1.4.0~beta1+dfsg-3 contains vulnerabilities that need > patching. > > [ Tests ] > Version 1.4.0~beta1+dfsg-4 is running ‘in production’ (on my small > personal mail server), rudimentary manual testing. > > [ Risks ] > The patches are not small but relatively self-contained and easy to > read. > > [ Checklist ] > [x] all changes are documented in the d/changelog > [x] I reviewed all changes and I approve them > [x] attach debdiff against the package in testing > > unblock opendmarc/1.4.0~beta1+dfsg-4
> diff -Nru opendmarc-1.4.0~beta1+dfsg/debian/changelog > opendmarc-1.4.0~beta1+dfsg/debian/changelog > --- opendmarc-1.4.0~beta1+dfsg/debian/changelog 2020-09-19 > 08:40:47.000000000 +0200 > +++ opendmarc-1.4.0~beta1+dfsg/debian/changelog 2021-05-29 > 16:22:50.000000000 +0200 > @@ -1,3 +1,12 @@ > +opendmarc (1.4.0~beta1+dfsg-4) unstable; urgency=high > + > + * Backport patches from upstream version 1.4.1.1 (Closes: #977766, > #977767): > + - CVE-2019-16378: Fix handling of multi-valued From headers > + - CVE-2019-20790: Validate incoming SPF headers > + - CVE-2020-12272: Check DKIM and SPF domain syntax > + > + -- David Bürgin <dbuer...@gluet.ch> Sat, 29 May 2021 16:22:50 +0200 > + > opendmarc (1.4.0~beta1+dfsg-3) unstable; urgency=high > > * Cherry-pick patch for CVE-2020-12460 from upstream: > diff -Nru opendmarc-1.4.0~beta1+dfsg/debian/libopendmarc2.symbols > opendmarc-1.4.0~beta1+dfsg/debian/libopendmarc2.symbols > --- opendmarc-1.4.0~beta1+dfsg/debian/libopendmarc2.symbols 2020-06-16 > 20:41:13.000000000 +0200 > +++ opendmarc-1.4.0~beta1+dfsg/debian/libopendmarc2.symbols 2021-05-29 > 15:03:47.000000000 +0200 > @@ -1,5 +1,6 @@ > libopendmarc.so.2 libopendmarc2 #MINVER# > * Build-Depends-Package: libopendmarc-dev > + check_domain@Base 1.4.0~beta1+dfsg If check_domain is really supposed to be part of the public ABI, then this should by versioned as 1.4.0~beta1+dfsg-4~ as it is introduced in a patch. Since check_domain is an overly generic name and it is not exposed in any header, I suspect that it is not intended to be public. In that case, sticking a static to the definition of check_domain will remove the symbol from the public ABI. It's only used inside libopendmarc/opendmarc_policy.c anyway. Please remove it from the public ABI or fix the version in the symbols file. Cheers > dmarc_dns_get_record@Base 1.1.0~beta2 > dmarc_strlcat@Base 1.1.0~beta2 > dmarc_strlcpy@Base 1.1.0~beta2 > diff -Nru opendmarc-1.4.0~beta1+dfsg/debian/patches/cve-2019-16378.patch > opendmarc-1.4.0~beta1+dfsg/debian/patches/cve-2019-16378.patch > --- opendmarc-1.4.0~beta1+dfsg/debian/patches/cve-2019-16378.patch > 1970-01-01 01:00:00.000000000 +0100 > +++ opendmarc-1.4.0~beta1+dfsg/debian/patches/cve-2019-16378.patch > 2021-05-29 16:22:50.000000000 +0200 > @@ -0,0 +1,321 @@ > +Description: CVE-2019-16378: Handle multi-valued From header, add > RejectMultiValueFrom parameter > +Author: Murray S. Kucherawy <m...@trusteddomain.org> > +Origin: backport, > https://github.com/trusteddomainproject/OpenDMARC/releases/tag/rel-opendmarc-1-4-1-1 > + > +--- a/opendmarc/parse.c > ++++ b/opendmarc/parse.c > +@@ -12,10 +12,18 @@ > + #include <string.h> > + #include <limits.h> > + #include <stdio.h> > ++#include <stdlib.h> > + > + /* opendmarc includes */ > + #include "util.h" > + > ++#ifndef FALSE > ++# define FALSE 0 > ++#endif /* ! FALSE */ > ++#ifndef TRUE > ++# define TRUE 1 > ++#endif /* ! TRUE */ > ++ > + /* types */ > + typedef unsigned long cmap_elem_type; > + > +@@ -24,6 +32,7 @@ > + #define MAILPARSE_ERR_PUNBALANCED 1 /* unbalanced parentheses */ > + #define MAILPARSE_ERR_QUNBALANCED 2 /* unbalanced quotes */ > + #define MAILPARSE_ERR_SUNBALANCED 3 /* unbalanced sq. brackets */ > ++#define MAILPARSE_ERR_MULTIVALUE 4 /* multiple possible values */ > + > + /* a bitmap for the "specials" character class */ > + #define CMAP_NBITS (sizeof(cmap_elem_type) * CHAR_BIT) > +@@ -466,6 +475,160 @@ > + } > + } > + > ++/* > ++** DMARCF_MAIL_PARSE_MULTI -- extract the local-part and hostname from a > mail > ++** header field that might contain multiple > ++** values, e.g. "To:", "Cc:" > ++** > ++** Parameters: > ++** line -- input line > ++** users_out -- array of pointers to "local-part" (returned) > ++** domains_out -- array of pointers to hostname (returned) > ++** > ++** Return value: > ++** 0 on success, or an DKIM_MAILPARSE_ERR_* on failure. > ++** > ++** Notes: > ++** Input string is modified. > ++*/ > ++ > ++int > ++dmarcf_mail_parse_multi(unsigned char *line, unsigned char ***users_out, > ++ unsigned char ***domains_out) > ++{ > ++ _Bool escaped = FALSE; > ++ _Bool quoted = FALSE; > ++ _Bool done = FALSE; > ++ int a = 0; > ++ int n = 0; > ++ int status; > ++ int parens = 0; > ++ char *p; > ++ char *addr; > ++ unsigned char **uout = NULL; > ++ unsigned char **dout = NULL; > ++ unsigned char *u; > ++ unsigned char *d; > ++ > ++ /* walk the input string looking for unenclosed commas */ > ++ addr = line; > ++ for (p = line; !done; p++) > ++ { > ++ if (escaped) > ++ { > ++ escaped = FALSE; > ++ continue; > ++ } > ++ > ++ switch (*p) > ++ { > ++ case '\\': > ++ escaped = TRUE; > ++ continue; > ++ > ++ case '"': > ++ quoted = !quoted; > ++ continue; > ++ > ++ case '(': > ++ parens++; > ++ continue; > ++ > ++ case ')': > ++ parens--; > ++ continue; > ++ > ++ case ',': > ++ /* skip it if it's quoted or in a comment */ > ++ if (parens != 0 || quoted) > ++ continue; > ++ /* FALLTHROUGH */ > ++ > ++ case '\0': > ++ if (*p == '\0') > ++ done = TRUE; > ++ else > ++ *p = '\0'; > ++ > ++ status = dmarcf_mail_parse(addr, &u, &d); > ++ if (status != 0) > ++ { > ++ if (uout != NULL) > ++ { > ++ free(uout); > ++ free(dout); > ++ } > ++ > ++ return status; > ++ } > ++ > ++ if (n == 0) > ++ { > ++ size_t newsize = 2 * sizeof(unsigned char *); > ++ > ++ uout = (unsigned char **) malloc(newsize); > ++ if (uout == NULL) > ++ return -1; > ++ > ++ dout = (unsigned char **) malloc(newsize); > ++ if (dout == NULL) > ++ { > ++ free(uout); > ++ return -1; > ++ } > ++ > ++ a = 2; > ++ } > ++ else if (n + 1 == a) > ++ { > ++ unsigned char **new; > ++ > ++ size_t newsize = a * 2 * sizeof(unsigned char > *); > ++ > ++ new = (unsigned char **) realloc(uout, newsize); > ++ if (new == NULL) > ++ { > ++ free(uout); > ++ free(dout); > ++ return -1; > ++ } > ++ > ++ uout = new; > ++ > ++ new = (unsigned char **) realloc(dout, newsize); > ++ if (new == NULL) > ++ { > ++ free(uout); > ++ free(dout); > ++ return -1; > ++ } > ++ > ++ dout = new; > ++ > ++ a *= 2; > ++ } > ++ > ++ uout[n] = u; > ++ dout[n++] = d; > ++ > ++ uout[n] = (char *) NULL; > ++ dout[n] = (char *) NULL; > ++ > ++ addr = p + 1; > ++ > ++ break; > ++ > ++ default: > ++ break; > ++ } > ++ } > ++ > ++ *users_out = uout; > ++ *domains_out = dout; > ++ > ++ return 0; > ++} > ++ > + #ifdef MAILPARSE_TEST > + int > + main(int argc, char **argv) > +--- a/opendmarc/opendmarc.c > ++++ b/opendmarc/opendmarc.c > +@@ -177,6 +177,7 @@ > + _Bool conf_spfselfvalidate; > + #endif /* WITH_SPF */ > + _Bool conf_ignoreauthclients; > ++ _Bool conf_reject_multi_from; > + unsigned int conf_refcnt; > + unsigned int conf_dnstimeout; > + struct config * conf_data; > +@@ -1365,6 +1366,10 @@ > + &conf->conf_afrf, > + sizeof conf->conf_afrf); > + > ++ (void) config_get(data, "RejectMultiValueFrom", > ++ &conf->conf_reject_multi_from, > ++ sizeof conf->conf_reject_multi_from); > ++ > + (void) config_get(data, "FailureReportsOnNone", > + &conf->conf_afrfnone, > + sizeof conf->conf_afrfnone); > +@@ -2291,8 +2296,10 @@ > + struct dmarcf_header *from; > + struct arcseal_header *as_hdr; > + u_char *reqhdrs_error = NULL; > +- u_char *user; > +- u_char *domain; > ++ u_char *user = NULL; > ++ u_char **users; > ++ u_char *domain = NULL; > ++ u_char **domains; > + u_char *bang; > + u_char **ruv; > + unsigned char header[MAXHEADER + 1]; > +@@ -2414,10 +2421,36 @@ > + return SMFIS_ACCEPT; > + } > + > +- /* extract From: domain */ > ++ /* extract From: addresses */ > + memset(addrbuf, '\0', sizeof addrbuf); > + strncpy(addrbuf, from->hdr_value, sizeof addrbuf - 1); > +- status = dmarcf_mail_parse(addrbuf, &user, &domain); > ++ status = dmarcf_mail_parse_multi(addrbuf, &users, &domains); > ++ if (status == 0 && (users[0] != NULL || domains[0] != NULL)) > ++ { > ++ /* > ++ ** Enact special handling for a multi-valued from if > ++ ** the domains are not all the same. > ++ */ > ++ > ++ for (c = 1; users[c] != NULL; c++) > ++ { > ++ if (strcasecmp(domains[0], domains[c]) != 0) > ++ { > ++ syslog(LOG_ERR, > ++ "%s: multi-valued From field detected", > ++ dfc->mctx_jobid); > ++ } > ++ > ++ if (conf->conf_reject_multi_from) > ++ return SMFIS_REJECT; > ++ else > ++ return SMFIS_ACCEPT; > ++ } > ++ > ++ user = users[0]; > ++ domain = domains[0]; > ++ } > ++ > + if (status != 0 || user == NULL || domain == NULL) > + { > + if (conf->conf_dolog) > +--- a/opendmarc/opendmarc-config.h > ++++ b/opendmarc/opendmarc-config.h > +@@ -46,6 +46,7 @@ > + { "RecordAllMessages", CONFIG_TYPE_BOOLEAN, FALSE }, > + { "RequiredHeaders", CONFIG_TYPE_BOOLEAN, FALSE }, > + { "RejectFailures", CONFIG_TYPE_BOOLEAN, FALSE }, > ++ { "RejectMultiValueFrom", CONFIG_TYPE_BOOLEAN, FALSE }, > + { "RejectString", CONFIG_TYPE_STRING, FALSE }, > + { "ReportCommand", CONFIG_TYPE_STRING, FALSE }, > + { "Socket", CONFIG_TYPE_STRING, FALSE }, > +--- a/opendmarc/opendmarc.conf.5.in > ++++ b/opendmarc/opendmarc.conf.5.in > +@@ -251,6 +251,12 @@ > + The default is "false". > + > + .TP > ++.I RejectMultiValueFrom (Boolean) > ++If set, messages with multiple addresses in the From: field of the message > ++will be rejected unless all domain names in that field are the same. They > ++will otherwise be ignored by the filter (the default). > ++ > ++.TP > + .I RejectString (string) > + This string describes the reason of reject at SMTP level. > + The message MUST contain the word "%s" once, which will be replaced by > +--- a/opendmarc/opendmarc.conf.sample > ++++ b/opendmarc/opendmarc.conf.sample > +@@ -295,6 +295,15 @@ > + # > + # RejectFailures false > + > ++## RejectMultiValueFrom { true | false } > ++## default "false" > ++## > ++## If set, messages with multiple addresses in the From: field of the > message > ++## will be rejected unless all domains in the field are the same. They > will > ++## otherwise be ignored by the filter (the default). > ++# > ++# RejectMultiValueFrom false > ++ > + ## RejectString string > + ## default ("rejected by DMARC policy for %s") > + ## > +--- a/opendmarc/parse.h > ++++ b/opendmarc/parse.h > +@@ -22,5 +22,8 @@ > + /* prototypes */ > + extern int dmarcf_mail_parse __P((unsigned char *, unsigned char **, > + unsigned char **)); > ++extern int dmarcf_mail_parse_multi __P((char *, unsigned char ***, > ++ unsigned char ***)); > ++ > + > + #endif /* ! _DMARCF_MAILPARSE_H_ */ > diff -Nru opendmarc-1.4.0~beta1+dfsg/debian/patches/cve-2019-20790.patch > opendmarc-1.4.0~beta1+dfsg/debian/patches/cve-2019-20790.patch > --- opendmarc-1.4.0~beta1+dfsg/debian/patches/cve-2019-20790.patch > 1970-01-01 01:00:00.000000000 +0100 > +++ opendmarc-1.4.0~beta1+dfsg/debian/patches/cve-2019-20790.patch > 2021-05-29 16:22:50.000000000 +0200 > @@ -0,0 +1,300 @@ > +Description: CVE-2019-20790: Properly validate incoming headers that carry > SPF results > +Author: Murray S. Kucherawy <m...@trusteddomain.org> > +Origin: backport, > https://github.com/trusteddomainproject/OpenDMARC/releases/tag/rel-opendmarc-1-4-1-1 > + > +--- a/opendmarc/opendmarc.c > ++++ b/opendmarc/opendmarc.c > +@@ -435,25 +435,46 @@ > + ** > + ** Parameters: > + ** str -- the value of the Received-SPF field to analyze > ++** envdomain -- envelope sender domain against which to test > + ** > + ** Return value: > + ** A ARES_RESULT_* constant. > ++** > ++** Notes: > ++** We will not accept a result delivered via a discovered > Received-SPF > ++** header field unless (a) it includes the "identity" key and its > ++** value is "mailfrom", AND (b) it includes the "envelope-from" > key and > ++** its value matches the envelope sender we got via milter. If > either > ++** of those tests fails, a "pass" or a "fail" is interpreted as > "neutral". > ++** This is necessary to be compliant with RFC 7489 Section 4.1, > ++** which says the SPF evaluation of MAIL FROM is what DMARC > consumes. > + */ > + > + int > +-dmarcf_parse_received_spf(char *str) > ++dmarcf_parse_received_spf(char *str, char *envdomain) > + { > +- _Bool copying = FALSE; > ++ _Bool in_result = TRUE; > + _Bool escaped = FALSE; > ++ _Bool quoting = FALSE; > + int parens = 0; > + char *p; > + char *r; > + char *end; > + char result[MAXSPFRESULT + 1]; > ++ char spf_envdomain[BUFRSZ + 1]; > ++ char key[BUFRSZ + 1]; > ++ char value[BUFRSZ + 1]; > ++ char identity[BUFRSZ + 1]; > + > + assert(str != NULL); > + > ++ memset(spf_envdomain, '\0', sizeof spf_envdomain); > ++ memset(key, '\0', sizeof key); > ++ memset(value, '\0', sizeof value); > ++ memset(identity, '\0', sizeof identity); > + memset(result, '\0', sizeof result); > ++ > ++ /* first thing we get is the result token */ > + r = result; > + end = &result[sizeof result - 1]; > + > +@@ -461,33 +482,13 @@ > + { > + if (escaped) > + { > +- if (copying) > +- { > +- if (r < end) > +- *r++ = *p; > +- } > +- > ++ if (parens == 0 && r < end) > ++ *r++ = *p; > + escaped = FALSE; > + } > +- else if (copying) > ++ else if (*p == '\\') > + { > +- if (!escaped && *p == '\\') > +- { > +- escaped = TRUE; > +- } > +- else if (*p == '(') > +- { > +- copying = FALSE; > +- parens++; > +- } > +- else if (isascii(*p) && isspace(*p)) > +- { > +- copying = FALSE; > +- } > +- else if (r < end) > +- { > +- *r++ = *p; > +- } > ++ escaped = TRUE; > + } > + else if (*p == '(') > + { > +@@ -499,35 +500,117 @@ > + } > + else if (parens == 0) > + { > ++ if (*p == '"') > ++ { > ++ /* entering/leaving a quoted substring */ > ++ quoting = !quoting; > ++ continue; > ++ } > ++ > ++ /* a possibly meaningful character */ > + if (isascii(*p) && isspace(*p)) > ++ { > ++ /* a space while quoting; just continue */ > ++ if (quoting) > ++ continue; > ++ > ++ if (in_result) > ++ { > ++ in_result = FALSE; > ++ r = key; > ++ end = &key[sizeof key - 1]; > ++ } > + continue; > ++ } > + > +- if (!copying) > ++ if (!in_result && *p == '=') > + { > +- if (result[0] != '\0') > +- break; > ++ r = value; > ++ end = &value[sizeof value - 1]; > ++ } > ++ else if (!in_result && *p == ';') > ++ { > ++ if (strcasecmp(key, "identity") == 0) > ++ { > ++ strlcpy(identity, value, > ++ sizeof identity); > ++ } > ++ > ++ if (strcasecmp(key, "envelope-from") == 0) > ++ { > ++ strlcpy(spf_envdomain, value, > ++ sizeof spf_envdomain); > ++ } > ++ > ++ memset(key, '\0', sizeof key); > ++ memset(value, '\0', sizeof value); > + > +- copying = TRUE; > +- if (r < end) > +- *r++ = *p; > ++ r = key; > ++ end = &key[sizeof key - 1]; > ++ } > ++ else if (r < end) > ++ { > ++ *r++ = *p; > + } > + } > + } > + > +- if (strcasecmp(result, "pass") == 0) > ++ if (key[0] != '\0') > ++ { > ++ if (strcasecmp(key, "identity") == 0) > ++ strlcpy(identity, value, sizeof identity); > ++ if (strcasecmp(key, "envelope-from") == 0) > ++ strlcpy(spf_envdomain, value, sizeof spf_envdomain); > ++ } > ++ > ++ p = strchr(spf_envdomain, '@'); > ++ if (p != NULL) > ++ { > ++ r = spf_envdomain; > ++ p = p + 1; > ++ for (;;) > ++ { > ++ *r = *p; > ++ if (*p == '\0') > ++ break; > ++ r++; > ++ p++; > ++ } > ++ } > ++ > ++ if (strcasecmp(identity, "mailfrom") != 0 || > ++ strcasecmp(spf_envdomain, envdomain) != 0) > ++ { > ++ return ARES_RESULT_NEUTRAL; > ++ } > ++ else if (strcasecmp(result, "pass") == 0) > ++ { > + return ARES_RESULT_PASS; > ++ } > + else if (strcasecmp(result, "fail") == 0) > ++ { > + return ARES_RESULT_FAIL; > ++ } > + else if (strcasecmp(result, "softfail") == 0) > ++ { > + return ARES_RESULT_SOFTFAIL; > ++ } > + else if (strcasecmp(result, "neutral") == 0) > ++ { > + return ARES_RESULT_NEUTRAL; > ++ } > + else if (strcasecmp(result, "temperror") == 0) > ++ { > + return ARES_RESULT_TEMPERROR; > ++ } > + else if (strcasecmp(result, "none") == 0) > ++ { > + return ARES_RESULT_NONE; > ++ } > + else > ++ { > + return ARES_RESULT_PERMERROR; > ++ } > + } > + > + /* > +@@ -2678,13 +2761,47 @@ > + #endif > + ) > + { > ++ _Bool envfrom_match = FALSE; > + int spfmode; > ++ int i; > + > + dfc->mctx_spfresult = > ar.ares_result[c].result_result; > + > + if (ar.ares_result[c].result_result != > ARES_RESULT_PASS) > + continue; > + > ++ /* > ++ ** Confirm the method used was "smtp.mailfrom" > ++ ** and it matches our envelope sender. > ++ */ > ++ > ++ for (i = 0; > ++ i < ar.ares_result[c].result_props; > ++ i++) > ++ { > ++ if (ar.ares_result[c].result_ptype[i] > == ARES_PTYPE_SMTP && > ++ > strcasecmp(ar.ares_result[c].result_property[i], > ++ "mailfrom") == 0) > ++ { > ++ char *d; > ++ > ++ d = > strchr(ar.ares_result[c].result_value[i], > ++ '@'); > ++ if (d == NULL) > ++ d = > ar.ares_result[c].result_value[i]; > ++ > ++ if (strcasecmp(d, > ++ > dfc->mctx_envdomain) == 0) > ++ { > ++ envfrom_match = TRUE; > ++ break; > ++ } > ++ } > ++ } > ++ > ++ if (!envfrom_match) > ++ continue; > ++ > + spfaddr = NULL; > + spfmode = DMARC_POLICY_SPF_ORIGIN_HELO; > + > +@@ -2928,7 +3045,8 @@ > + else > + spfmode = > DMARC_POLICY_SPF_ORIGIN_MAILFROM; > + > +- spfres = > dmarcf_parse_received_spf(hdr->hdr_value); > ++ spfres = > dmarcf_parse_received_spf(hdr->hdr_value, > ++ > dfc->mctx_envdomain); > + > + dmarcf_dstring_printf(dfc->mctx_histbuf, > + "spf %d\n", spfres); > +@@ -3002,7 +3120,7 @@ > + &used_mfrom); > + if (used_mfrom == TRUE) > + { > +- use_domain = dfc->mctx_envfrom; > ++ use_domain = dfc->mctx_envdomain; > + spf_mode = DMARC_POLICY_SPF_ORIGIN_MAILFROM; > + } > + else > +@@ -3011,10 +3129,10 @@ > + spf_mode = DMARC_POLICY_SPF_ORIGIN_HELO; > + } > + ostatus = opendmarc_policy_store_spf(cc->cctx_dmarc, > +- use_domain, > +- spf_result, > +- spf_mode, > +- human); > ++ use_domain, > ++ spf_result, > ++ spf_mode, > ++ human); > + switch (spf_result) > + { > + case DMARC_POLICY_SPF_OUTCOME_PASS: > diff -Nru opendmarc-1.4.0~beta1+dfsg/debian/patches/cve-2020-12272.patch > opendmarc-1.4.0~beta1+dfsg/debian/patches/cve-2020-12272.patch > --- opendmarc-1.4.0~beta1+dfsg/debian/patches/cve-2020-12272.patch > 1970-01-01 01:00:00.000000000 +0100 > +++ opendmarc-1.4.0~beta1+dfsg/debian/patches/cve-2020-12272.patch > 2021-05-29 16:22:50.000000000 +0200 > @@ -0,0 +1,67 @@ > +Description: CVE-2020-12272: Check syntax of DKIM and SPF domain names > +Author: Murray S. Kucherawy <m...@trusteddomain.org> > +Origin: backport, > https://github.com/trusteddomainproject/OpenDMARC/releases/tag/rel-opendmarc-1-4-1-1 > + > +--- a/libopendmarc/opendmarc_policy.c > ++++ b/libopendmarc/opendmarc_policy.c > +@@ -4,6 +4,8 @@ > + ** Copyright (c) 2012-2016, 2018, The Trusted Domain Project. All rights > reserved. > + **************************************************************************/ > + > ++#include <ctype.h> > ++ > + #include "opendmarc_internal.h" > + #include "dmarc.h" > + > +@@ -22,6 +24,33 @@ > + # include <opendmarc_strl.h> > + #endif /* USE_DMARCSTRL_H */ > + > ++/* > ++** CHECK_DOMAIN -- check for syntactical validity of a domain name > ++** > ++** Parameters: > ++** domain -- domain name to check > ++** > ++** Return value: > ++** TRUE if the syntax was fine, FALSE otherwise. > ++*/ > ++ > ++bool check_domain(u_char *domain) > ++{ > ++ u_char *dp; > ++ > ++ for (dp = domain; *dp != '\0'; dp++) > ++ { > ++ if (!(isalpha(*dp) || > ++ isdigit(*dp) || > ++ *dp == '.' || > ++ *dp == '-' || > ++ *dp == '_')) > ++ return FALSE; > ++ } > ++ > ++ return TRUE; > ++} > ++ > + /************************************************************************** > + ** OPENDMARC_POLICY_LIBRARY_INIT -- Initialize The Library > + ** Parameters: > +@@ -388,6 +417,8 @@ > + dp = opendmarc_util_finddomain(domain, domain_buf, sizeof domain_buf); > + if (dp == NULL) > + return DMARC_PARSE_ERROR_NO_DOMAIN; > ++ if (!check_domain(dp)) > ++ return DMARC_PARSE_ERROR_BAD_VALUE; > + if (human_readable != NULL) > + pctx->spf_human_outcome = strdup((char *)human_readable); > + pctx->spf_domain = strdup((char *)dp); > +@@ -454,6 +485,8 @@ > + return DMARC_PARSE_ERROR_NULL_CTX; > + if (d_equal_domain == NULL || strlen((char *)d_equal_domain) == 0) > + return DMARC_PARSE_ERROR_EMPTY; > ++ if (!check_domain(d_equal_domain)) > ++ return DMARC_PARSE_ERROR_BAD_VALUE; > + > + switch (dkim_result) > + { > diff -Nru opendmarc-1.4.0~beta1+dfsg/debian/patches/series > opendmarc-1.4.0~beta1+dfsg/debian/patches/series > --- opendmarc-1.4.0~beta1+dfsg/debian/patches/series 2020-09-19 > 08:34:33.000000000 +0200 > +++ opendmarc-1.4.0~beta1+dfsg/debian/patches/series 2021-05-29 > 15:51:16.000000000 +0200 > @@ -9,3 +9,6 @@ > ticket227.patch > pull48.patch > cve-2020-12460.patch > +cve-2019-16378.patch > +cve-2020-12272.patch > +cve-2019-20790.patch -- Sebastian Ramacher