[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#989324: unblock: opendmarc/1.4.0~beta1+dfsg-4



Package: release.debian.org
Severity: normal
User: release.debian.org@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 <dbuergin@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
  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 <msk@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 <msk@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 <msk@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

Reply to: