--- SPF.pm 2014-02-07 09:36:27.000000000 +0100 +++ SPF-softfail-v2-jessie.pm 2015-08-14 12:03:02.880612680 +0200 @@ -66,6 +66,9 @@ $self->register_eval_rule ("check_for_spf_helo_softfail"); $self->register_eval_rule ("check_for_spf_whitelist_from"); $self->register_eval_rule ("check_for_def_spf_whitelist_from"); +# --- TJ ---------------- + $self->register_eval_rule ("check_for_spf_softfail_whitelist_from"); +# ----------------------- $self->set_config($mailsaobject->{conf}); @@ -221,6 +224,22 @@ type => $Mail::SpamAssassin::Conf::CONF_TYPE_BOOL, }); +# --- TJ ------------------ + + push (@cmds, { + setting => 'whitelist_from_spf_softfail', + type => $Mail::SpamAssassin::Conf::CONF_TYPE_ADDRLIST + }); + + push(@cmds, { + setting => 'wl_ignore_spf_softfail', + is_admin => 1, + default => 0, + type => $Mail::SpamAssassin::Conf::CONF_TYPE_BOOL, + }); + +# ------------------------- + $conf->{parser}->register_commands(\@cmds); } @@ -303,11 +322,25 @@ $scanner->{def_spf_whitelist_from}; } +# --- TJ --------------------- +sub check_for_spf_softfail_whitelist_from { + my ($self, $scanner) = @_; + $self->_check_spf_softfail_whitelist($scanner) unless $scanner->{spf_softfail_whitelist_from_checked}; + $scanner->{spf_softfail_whitelist_from}; +} +# ---------------------------- + sub _check_spf { my ($self, $scanner, $ishelo) = @_; my $timer = $self->{main}->time_method("check_spf"); + # --- TJ ------ + if ($scanner->{conf}->{wl_ignore_spf_softfail}) { + dbg("spf: ignoring softfail from whitelist, by admin setting"); + } + # ------------- + # we can re-use results from any *INTERNAL* Received-SPF header in the message... # we can't use results from trusted but external hosts since (i) spf checks are # supposed to be done "on the domain boundary", (ii) even if an external header @@ -751,7 +784,10 @@ # if we've already checked for an SPF PASS and didn't get it don't waste time # checking to see if the sender address is in the spf whitelist - if ($scanner->{spf_checked} && !$scanner->{spf_pass}) { +# --- TJ ---------------------- +# if ($scanner->{spf_checked} && !$scanner->{spf_pass}) { + if ($scanner->{spf_checked} && ! ($scanner->{spf_pass} || ( $scanner->{conf}->{wl_ignore_spf_softfail} && $scanner->{spf_softfail} ) ) ) { +# ----------------------------- dbg("spf: whitelist_from_spf: already checked spf and didn't get pass, skipping whitelist check"); return; } @@ -770,7 +806,12 @@ # if the message doesn't pass SPF validation, it can't pass an SPF whitelist if ($scanner->{spf_whitelist_from}) { - if ($self->check_for_spf_pass($scanner)) { +# --- TJ --------------- +# if ($self->check_for_spf_pass($scanner)) { + if ( $self->check_for_spf_pass($scanner) || + ( $scanner->{conf}->{wl_ignore_spf_softfail} && $self->check_for_spf_softfail($scanner) ) + ) { +# ---------------------- dbg("spf: whitelist_from_spf: $scanner->{sender} is in user's WHITELIST_FROM_SPF and passed SPF check"); } else { dbg("spf: whitelist_from_spf: $scanner->{sender} is in user's WHITELIST_FROM_SPF but failed SPF check"); @@ -819,6 +860,47 @@ } } +# --- TJ -------------------- + +sub _check_spf_softfail_whitelist { + my ($self, $scanner) = @_; + + $scanner->{spf_softfail_whitelist_from_checked} = 1; + $scanner->{spf_softfail_whitelist_from} = 0; + + # if we've already checked for an SPF PASS and didn't get it don't waste time + # checking to see if the sender address is in the spf whitelist + if ($scanner->{spf_checked} && !( $scanner->{spf_pass} || $scanner->{spf_softfail} ) ) { + dbg("spf: whitelist_from_spf_softfail: already checked spf and didn't get pass, skipping whitelist check"); + return; + } + + $self->_get_sender($scanner) unless $scanner->{sender_got}; + + unless ($scanner->{sender}) { + dbg("spf: spf_softfail_whitelist_from: could not find useable envelope sender"); + return; + } + + $scanner->{spf_softfail_whitelist_from} = $self->_wlcheck($scanner,'whitelist_from_spf_softfail'); + + # We don't check de 'whitelist_auth' + + # if the message doesn't pass SPF validation, it can't pass an SPF whitelist + if ($scanner->{spf_softfail_whitelist_from}) { + if ( $self->check_for_spf_pass($scanner) || $self->check_for_spf_softfail($scanner) ) { + dbg("spf: whitelist_from_spf_softfail: $scanner->{sender} is in user's WHITELIST_FROM_SPF_SOFTFAIL and passed SPF check"); + } else { + dbg("spf: whitelist_from_spf_softfail: $scanner->{sender} is in user's WHITELIST_FROM_SPF_SOFTFAIL but failed SPF check"); + $scanner->{spf_softfail_whitelist_from} = 0; + } + } else { + dbg("spf: whitelist_from_spf_softfail: $scanner->{sender} is not in user's WHITELIST_FROM_SPF_SOFTFAIL"); + } +} + +# --------------------------- + sub _wlcheck { my ($self, $scanner, $param) = @_; if (defined ($scanner->{conf}->{$param}->{$scanner->{sender}})) {