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

Reply via email to