package Mail::SpamAssassin::Plugin::WLBLEval;
use Mail::SpamAssassin::Plugin;
use Mail::SpamAssassin::Logger;
use strict;
use warnings;
use bytes;
use vars qw(@ISA);
@ISA = qw(Mail::SpamAssassin::Plugin);
sub new {
my $class = shift;
my $mailsaobject = shift;
$class = ref($class) || $class;
my $self = $class->SUPER::new($mailsaobject);
bless ($self, $class);
$self->register_eval_rule("check_from_in_blacklist");
$self->register_eval_rule("check_to_in_blacklist");
$self->register_eval_rule("check_to_in_whitelist");
$self->register_eval_rule("check_to_in_more_spam");
$self->register_eval_rule("check_to_in_all_spam");
$self->register_eval_rule("check_from_in_list");
$self->register_eval_rule("check_to_in_list");
$self->register_eval_rule("check_from_in_whitelist");
$self->register_eval_rule("check_forged_in_whitelist");
$self->register_eval_rule("check_from_in_default_whitelist");
$self->register_eval_rule("check_forged_in_default_whitelist");
return $self;
}
sub check_from_in_blacklist {
my ($self, $pms) = @_;
local ($_);
foreach $_ ($pms->all_from_addrs()) {
if ($self->_check_whitelist ($self->{main}->{conf}->{blacklist_from}, $_)) {
return 1;
}
}
}
sub check_to_in_blacklist {
my ($self, $pms) = @_;
local ($_);
foreach $_ ($pms->all_to_addrs()) {
if ($self->_check_whitelist ($self->{main}->{conf}->{blacklist_to}, $_)) {
return 1;
}
}
}
sub check_to_in_whitelist {
my ($self, $pms) = @_;
local ($_);
foreach $_ ($pms->all_to_addrs()) {
if ($self->_check_whitelist ($self->{main}->{conf}->{whitelist_to}, $_)) {
return 1;
}
}
}
sub check_to_in_more_spam {
my ($self, $pms) = @_;
local ($_);
foreach $_ ($pms->all_to_addrs()) {
if ($self->_check_whitelist ($self->{main}->{conf}->{more_spam_to}, $_)) {
return 1;
}
}
}
sub check_to_in_all_spam {
my ($self, $pms) = @_;
local ($_);
foreach $_ ($pms->all_to_addrs()) {
if ($self->_check_whitelist ($self->{main}->{conf}->{all_spam_to}, $_)) {
return 1;
}
}
}
sub check_from_in_list {
my ($self, $pms, $list) = @_;
my $list_ref = $self->{main}{conf}{$list};
unless (defined $list_ref) {
warn "eval: could not find list $list";
return;
}
foreach my $addr ($pms->all_from_addrs()) {
if ($self->_check_whitelist ($list_ref, $addr)) {
return 1;
}
}
return 0;
}
sub check_wb_list {
my ($self, $params) = @_;
return unless (defined $params->{permsgstatus});
return unless (defined $params->{type});
return unless (defined $params->{list});
if (lc $params->{type} eq "to") {
return $self->check_to_in_list($params->{permsgstatus}, $params->{list});
}
elsif (lc $params->{type} eq "from") {
return $self->check_from_in_list($params->{permsgstatus}, $params->{list});
}
return;
}
sub check_to_in_list {
my ($self,$pms,$list) = @_;
my $list_ref = $self->{main}{conf}{$list};
unless (defined $list_ref) {
warn "eval: could not find list $list";
return;
}
foreach my $addr ($pms->all_to_addrs()) {
if ($self->_check_whitelist ($list_ref, $addr)) {
return 1;
}
}
return 0;
}
sub check_from_in_whitelist {
my ($self, $pms) = @_;
$self->_check_from_in_whitelist($pms) unless exists $pms->{from_in_whitelist};
return ($pms->{from_in_whitelist} > 0);
}
sub check_forged_in_whitelist {
my ($self, $pms) = @_;
$self->_check_from_in_whitelist($pms) unless exists $pms->{from_in_whitelist};
$self->_check_from_in_default_whitelist($pms) unless exists $pms->{from_in_default_whitelist};
return ($pms->{from_in_whitelist} < 0) && ($pms->{from_in_default_whitelist} == 0);
}
sub check_from_in_default_whitelist {
my ($self, $pms) = @_;
$self->_check_from_in_default_whitelist($pms) unless exists $pms->{from_in_default_whitelist};
return ($pms->{from_in_default_whitelist} > 0);
}
sub check_forged_in_default_whitelist {
my ($self, $pms) = @_;
$self->_check_from_in_default_whitelist($pms) unless exists $pms->{from_in_default_whitelist};
$self->_check_from_in_whitelist($pms) unless exists $pms->{from_in_whitelist};
return ($pms->{from_in_default_whitelist} < 0) && ($pms->{from_in_whitelist} == 0);
}
sub _check_from_in_whitelist {
my ($self, $pms) = @_;
my $found_match = 0;
local ($_);
foreach $_ ($pms->all_from_addrs()) {
if ($self->_check_whitelist ($self->{main}->{conf}->{whitelist_from}, $_)) {
$pms->{from_in_whitelist} = 1;
return;
}
my $wh = $self->_check_whitelist_rcvd ($pms, $self->{main}->{conf}->{whitelist_from_rcvd}, $_);
if ($wh == 1) {
$pms->{from_in_whitelist} = 1;
return;
}
elsif ($wh == -1) {
$found_match = -1;
}
}
$pms->{from_in_whitelist} = $found_match;
return;
}
sub _check_from_in_default_whitelist {
my ($self, $pms) = @_;
my $found_match = 0;
local ($_);
foreach $_ ($pms->all_from_addrs()) {
my $wh = $self->_check_whitelist_rcvd ($pms, $self->{main}->{conf}->{def_whitelist_from_rcvd}, $_);
if ($wh == 1) {
$pms->{from_in_default_whitelist} = 1;
return;
}
elsif ($wh == -1) {
$found_match = -1;
}
}
$pms->{from_in_default_whitelist} = $found_match;
return;
}
sub _check_whitelist_rcvd {
my ($self, $pms, $list, $addr) = @_;
return 0 unless ($pms->{num_relays_untrusted}+$pms->{num_relays_trusted} > 0);
my @relays = ();
if ($pms->{num_relays_untrusted} > 0) {
@relays = $pms->{relays_untrusted}->[0];
}
if ($pms->{num_relays_trusted} > 0 && !$pms->{num_relays_untrusted} ) {
push (@relays, @{$pms->{relays_trusted}});
}
$addr = lc $addr;
my $found_forged = 0;
foreach my $white_addr (keys %{$list}) {
my $regexp = qr/$list->{$white_addr}{re}/i;
foreach my $domain (@{$list->{$white_addr}{domain}}) {
if ($addr =~ $regexp) {
foreach my $lastunt (@relays) {
my $rdns = $lastunt->{lc_rdns};
if ($rdns =~ /(?:^|\.)\Q${domain}\E$/i) {
dbg("rules: address $addr matches (def_)whitelist_from_rcvd $list->{$white_addr}{re} ${domain}");
return 1;
}
}
$found_forged = -1;
}
}
}
if ($found_forged) { my $wlist = $self->{main}->{conf}->{whitelist_allows_relays};
foreach my $fuzzy_addr (values %{$wlist}) {
if ($addr =~ /$fuzzy_addr/i) {
$found_forged = 0;
last;
}
}
}
return $found_forged;
}
sub _check_whitelist {
my ($self, $list, $addr) = @_;
$addr = lc $addr;
if (defined ($list->{$addr})) { return 1; }
study $addr;
foreach my $regexp (values %{$list}) {
if ($addr =~ qr/$regexp/i) {
dbg("rules: address $addr matches whitelist or blacklist regexp: $regexp");
return 1;
}
}
return 0;
}
1;