You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by mm...@apache.org on 2009/09/02 13:18:24 UTC
svn commit: r810454 -
/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm
Author: mmartinec
Date: Wed Sep 2 11:18:24 2009
New Revision: 810454
URL: http://svn.apache.org/viewvc?rev=810454&view=rev
Log:
Plugin/DKIM.pm: check_dkim_signed and check_dkim_adsp eval rules
can now take an optional list of domain names, which limits their
action to listed domains only. It facilitates building DKIM-based
rules for specific domains, without having to resort to meta rules.
Modified:
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm?rev=810454&r1=810453&r2=810454&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/DKIM.pm Wed Sep 2 11:18:24 2009
@@ -23,11 +23,19 @@
loadplugin Mail::SpamAssassin::Plugin::DKIM [/path/to/DKIM.pm]
+Taking into account signatures from any signing domains:
full DKIM_SIGNED eval:check_dkim_signed()
full DKIM_VALID eval:check_dkim_valid()
full DKIM_VALID_AU eval:check_dkim_valid_author_sig()
+
+Taking into account signatures from specified signing domains only:
+ full DKIM_SIGNED_MY1 eval:check_dkim_signed('dom1','dom2',...)
+ full DKIM_VALID_MY1 eval:check_dkim_valid('dom1','dom2',...)
+ full DKIM_VALID_AU_MY1 eval:check_dkim_valid_author_sig('d1','d2',...)
+
full __DKIM_DEPENDABLE eval:check_dkim_dependable()
+Author Domain Signing Practices (ADSP) from any author domains:
header DKIM_ADSP_NXDOMAIN eval:check_dkim_adsp('N')
header DKIM_ADSP_ALL eval:check_dkim_adsp('A')
header DKIM_ADSP_DISCARD eval:check_dkim_adsp('D')
@@ -35,6 +43,9 @@
header DKIM_ADSP_CUSTOM_MED eval:check_dkim_adsp('2')
header DKIM_ADSP_CUSTOM_HIGH eval:check_dkim_adsp('3')
+Author Domain Signing Practices (ADSP) from specified author domains only:
+ header DKIM_ADSP_MY1 eval:check_dkim_adsp('*','dom1','dom2',...)
+
describe DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid
describe DKIM_VALID Message has at least one valid DKIM or DK signature
describe DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain
@@ -407,21 +418,45 @@
# ---------------------------------------------------------------------------
sub check_dkim_signed {
- my ($self, $pms) = @_;
- $self->_check_dkim_signature($pms) unless $pms->{dkim_checked_signature};
- return $pms->{dkim_signed};
+ my ($self, $pms, $full_ref, @acceptable_domains) = @_;
+ $self->_check_dkim_signature($pms) if !$pms->{dkim_checked_signature};
+ my $result = 0;
+ if (!$pms->{dkim_signed}) {
+ # don't bother
+ } elsif (!@acceptable_domains) {
+ $result = 1; # no additional constraints, any signing domain will do
+ } else {
+ $result = $self->_check_dkim_signed_by($pms,0,0,\@acceptable_domains);
+ }
+ return $result;
}
-sub check_dkim_valid_author_sig {
- my ($self, $pms) = @_;
- $self->_check_dkim_signature($pms) unless $pms->{dkim_checked_signature};
- return $pms->{dkim_has_valid_author_sig};
+sub check_dkim_valid {
+ my ($self, $pms, $full_ref, @acceptable_domains) = @_;
+ $self->_check_dkim_signature($pms) if !$pms->{dkim_checked_signature};
+ my $result = 0;
+ if (!$pms->{dkim_valid}) {
+ # don't bother
+ } elsif (!@acceptable_domains) {
+ $result = 1; # no additional constraints, any signing domain will do
+ } else {
+ $result = $self->_check_dkim_signed_by($pms,1,0,\@acceptable_domains);
+ }
+ return $result;
}
-sub check_dkim_valid {
- my ($self, $pms) = @_;
- $self->_check_dkim_signature($pms) unless $pms->{dkim_checked_signature};
- return $pms->{dkim_valid};
+sub check_dkim_valid_author_sig {
+ my ($self, $pms, $full_ref, @acceptable_domains) = @_;
+ $self->_check_dkim_signature($pms) if !$pms->{dkim_checked_signature};
+ my $result = 0;
+ if (!$pms->{dkim_has_valid_author_sig}) {
+ # don't bother
+ } elsif (!@acceptable_domains) {
+ $result = 1; # no additional constraints, any signing domain will do
+ } else {
+ $result = $self->_check_dkim_signed_by($pms,1,1,\@acceptable_domains);
+ }
+ return $result;
}
sub check_dkim_dependable {
@@ -432,20 +467,40 @@
# mosnomer, old synonym for check_dkim_valid, kept for compatibility
sub check_dkim_verified {
- my ($self, $pms) = @_;
- $self->_check_dkim_signature($pms) unless $pms->{dkim_checked_signature};
- return $pms->{dkim_valid};
+ return check_dkim_valid(@_);
}
# no valid author signature && ADSP matches the argument
sub check_dkim_adsp {
- my ($self, $pms, $adsp_char) = @_;
- $self->_check_dkim_signature($pms) unless $pms->{dkim_checked_signature};
- if ($pms->{dkim_signatures_ready} && !$pms->{dkim_has_valid_author_sig}) {
- $self->_check_dkim_adsp($pms) unless $pms->{dkim_checked_adsp};
- return 1 if $pms->{dkim_adsp} eq $adsp_char;
+ my ($self, $pms, $adsp_char, @selected_domains) = @_;
+ $self->_check_dkim_signature($pms) if !$pms->{dkim_checked_signature};
+ my $result = 0;
+ if (!$pms->{dkim_signatures_ready} || $pms->{dkim_has_valid_author_sig}) {
+ # don't bother
+ } else {
+ $self->_check_dkim_adsp($pms) if !$pms->{dkim_checked_adsp};
+ if ($adsp_char ne '*' && $pms->{dkim_adsp} ne $adsp_char) {
+ # not the right ADSP type
+ } elsif (!@selected_domains) {
+ $result = 1; # no additional constraints, any author domain will do
+ } else {
+ my @author_domains = map { defined($_) && /\@([^\@]*)\z/s ? lc($1) : () }
+ ( $pms->{dkim_author_address} );
+ foreach my $dom (@selected_domains) {
+ if ($dom =~ /^\.(.*)\z/s) { # domain or its subdomain
+ my $doms = lc $1;
+ if (grep { $_ eq $doms || /\.\Q$doms\E\z/s } @author_domains) {
+ $result = 1; last;
+ }
+ } else { # match on domain (not a subdomain)
+ if (grep { $_ eq lc $dom } @author_domains) {
+ $result = 1; last;
+ }
+ }
+ }
+ }
}
- return 0;
+ return $result;
}
# useless, semantically always true according to ADSP (RFC 5617)
@@ -529,6 +584,38 @@
# ---------------------------------------------------------------------------
+sub _check_dkim_signed_by {
+ my ($self, $pms, $must_be_valid, $must_be_author_domain_signature,
+ $acceptable_domains_ref) = @_;
+ my $result = 0;
+ my @authors = grep { defined $_ } ( $pms->{dkim_author_address} );
+ my $verifier = $pms->{dkim_verifier};
+ foreach my $sig (@{$pms->{dkim_signatures}}) {
+ next if !defined $sig;
+ if ($must_be_valid) {
+ next if ($sig->UNIVERSAL::can("result") ? $sig : $verifier)
+ ->result ne 'pass';
+ next if $sig->UNIVERSAL::can("check_expiration") &&
+ !$sig->check_expiration;
+ }
+ local $1;
+ my $d = lc($sig->domain);
+ if ($must_be_author_domain_signature) {
+ next if !grep { /\@([^\@]*)\z/s && lc($1) eq $d } @authors;
+ }
+ foreach my $ad (@$acceptable_domains_ref) {
+ if ($ad =~ /^\.(.*)\z/s) { # domain or its subdomain
+ my $ads = lc $1;
+ if ($d eq $ads || $d =~ /\.\Q$ads\E\z/s) { $result = 1; last }
+ } else { # match on domain (not a subdomain)
+ if ($d eq lc $ad) { $result = 1; last }
+ }
+ }
+ last if $result;
+ }
+ return $result;
+}
+
sub _check_dkim_signature {
my ($self, $pms) = @_;