# HG changeset patch # User Carl Byington # Date 1482108693 28800 # Node ID 5e4b5540c8cc9de6502a4ee05a806d97be34d0a4 # Parent 28b6e0d97c5b70aa5a678968a62915cc6debc8c4 allow multiple dkim signers in authentication results diff -r 28b6e0d97c5b -r 5e4b5540c8cc src/context.cpp --- a/src/context.cpp Sat Dec 17 21:59:23 2016 -0800 +++ b/src/context.cpp Sun Dec 18 16:51:33 2016 -0800 @@ -1099,36 +1099,43 @@ } -bool CONTEXT::acceptable_content(recorder &memory, int score, int bulk, const char *signer, const char *from, string& msg) { - const char *st = find_dkim_signer(signer); +bool CONTEXT::acceptable_content(recorder &memory, int score, int bulk, string_set &signers, const char *from, string& msg) { + DKIMP dk = find_dkim_from(from); + bool requirement = false; + for (string_set::iterator s=signers.begin(); s!=signers.end(); s++) { + const char *st = find_dkim_signer(*s); + // signed by a white listed signer if (st == token_white) return true; + // signed by a black listed signer if (st == token_black) { char buf[maxlen]; - snprintf(buf, sizeof(buf), "Mail rejected - dkim signed by %s", signer); + snprintf(buf, sizeof(buf), "Mail rejected - dkim signed by %s", *s); msg = string(buf); return false; } - DKIMP dk = find_dkim_from(from); if (dk) { st = dk->action; // signed by a white listed signer - if ((st == token_signed_white) && (strcasecmp(signer,dk->signer) == 0)) return true; - // not signed by the required signer - if ((st == token_require_signed) && (strcasecmp(signer,dk->signer) != 0)) { - char buf[maxlen]; - snprintf(buf, sizeof(buf), "Mail rejected - not dkim signed by %s", dk->signer); - msg = string(buf); - return false; - } + if ((st == token_signed_white) && (strcasecmp(*s,dk->signer) == 0)) return true; + // is it signed by the required signer + if ((st == token_require_signed) && (strcasecmp(*s,dk->signer) == 0)) requirement = true; // signed by a black listed signer - if ((st == token_signed_black) && (strcasecmp(signer,dk->signer) == 0)) { + if ((st == token_signed_black) && (strcasecmp(*s,dk->signer) == 0)) { char buf[maxlen]; snprintf(buf, sizeof(buf), "Mail rejected - dkim signed by %s", dk->signer); msg = string(buf); return false; } } + } + + if (dk && (dk->action == token_require_signed) && !requirement) { + char buf[maxlen]; + snprintf(buf, sizeof(buf), "Mail rejected - not dkim signed by %s", dk->signer); + msg = string(buf); + return false; + } if (spamassassin_limit && (score > spamassassin_limit)) { char buf[maxlen]; diff -r 28b6e0d97c5b -r 5e4b5540c8cc src/context.h --- a/src/context.h Sat Dec 17 21:59:23 2016 -0800 +++ b/src/context.h Sun Dec 18 16:51:33 2016 -0800 @@ -312,7 +312,7 @@ dnsblp_list& get_dnsbl_list(); dnswlp_list& get_dnswl_list(); - bool acceptable_content(recorder &memory, int score, int bulk, const char *signer, const char *from, string& msg); + bool acceptable_content(recorder &memory, int score, int bulk, string_set &signers, const char *from, string& msg); bool ignore_host(const char *host); void dump(bool isdefault, bool &spamass, int level = 0); diff -r 28b6e0d97c5b -r 5e4b5540c8cc src/dnsbl.cpp --- a/src/dnsbl.cpp Sat Dec 17 21:59:23 2016 -0800 +++ b/src/dnsbl.cpp Sun Dec 18 16:51:33 2016 -0800 @@ -525,7 +525,6 @@ fromaddr = NULL; header_count = 0; dkim_ok = true; - dkim_signer = NULL; queueid = NULL; authenticated = NULL; client_name = NULL; @@ -574,11 +573,11 @@ } if (mailaddr) free((void*)mailaddr); if (fromaddr) free((void*)fromaddr); - if (dkim_signer) free((void*)dkim_signer); if (queueid) free((void*)queueid); if (authenticated) free((void*)authenticated); if (client_name) free((void*)client_name); if (client_dns_name) free((void*)client_dns_name); + discard(dkim_signers); discard(hosts_uribl); delayer.clear(); discard(env_to); @@ -593,7 +592,6 @@ fromaddr = NULL; header_count = 0; dkim_ok = true; - dkim_signer = NULL; queueid = NULL; authenticated = NULL; client_name = NULL; @@ -1474,14 +1472,17 @@ if (priv.dkim_ok) { const int nmatch = 2; regmatch_t match[nmatch]; + while (true) { if (0 == regexec(&dkim_pattern, msg, nmatch, match, 0)) { int s1 = match[1].rm_so; // domain int e1 = match[1].rm_eo; if (s1 != -1) { msg[e1] = '\0'; - priv.dkim_signer = strdup(msg+s1); + priv.dkim_signers.insert(strdup(msg+s1)); } } + else break; + } } } if ((priv.header_count > 2) && (strcasecmp(headerf, "from"))) { @@ -1582,13 +1583,23 @@ string_set alive; bool random = false; int limit = 0; - snprintf(buf, sizeof(buf), "acceptable content from %s signer %s", (priv.fromaddr) ? priv.fromaddr : token_asterisk, (priv.dkim_signer) ? priv.dkim_signer : token_asterisk); + if (priv.dkim_signers.empty()) { + snprintf(buf, sizeof(buf), "acceptable content from %s signer *", + (priv.fromaddr) ? priv.fromaddr : token_asterisk); my_syslog(&priv, buf); + } + else { + for (string_set::iterator s=priv.dkim_signers.begin(); s!=priv.dkim_signers.end(); s++) { + snprintf(buf, sizeof(buf), "acceptable content from %s signer %s", + (priv.fromaddr) ? priv.fromaddr : token_asterisk, *s); + my_syslog(&priv, buf); + } + } for (context_map::iterator i=priv.env_to.begin(); i!=priv.env_to.end(); i++) { const char *rcpt = (*i).first; CONTEXT &con = *((*i).second); - if (!con.acceptable_content(*priv.memory, score, bulk, priv.dkim_signer, priv.fromaddr, msg)) { + if (!con.acceptable_content(*priv.memory, score, bulk, priv.dkim_signers, priv.fromaddr, msg)) { // bad html tags or excessive hosts or // high spam assassin score or dcc bulk threshold exceedeed // or signed by a dkim signer that we don't like diff -r 28b6e0d97c5b -r 5e4b5540c8cc src/dnsbl.h --- a/src/dnsbl.h Sat Dec 17 21:59:23 2016 -0800 +++ b/src/dnsbl.h Sun Dec 18 16:51:33 2016 -0800 @@ -42,7 +42,7 @@ const char *fromaddr; // header from value, set by mlfi_header() int header_count; // count of headers already seen bool dkim_ok; // ok to proceed with dkim checking - const char *dkim_signer; // non null if message was validly signed + string_set dkim_signers; // non empty if message was validly signed, set of signers const char *queueid; // sendmail queue id const char *authenticated; // client authenticated? if so, suppress all dnsbl checks, but check rate limits const char *client_name; // fully qualified host name of the smtp client xxx [ip.ad.dr.es] (may be forged)