Hi,
On Friday 15 February 2013, Carsten Wolff wrote:
> currently, all mail that
> - contains a "mailbomb"
> - contains encrypted parts
> - contains any other undecipherable parts
> falls under content category "UNCHECKED" and thus shares a final
> destination. I think it might be desirable to have different final
> destinations for these cases. Please take the attached (untested) patch to
> amavis 2.8 as a suggestion. It introduces two sub-cc's for UNCHECKED. One
> for mail that only contains encrypted parts (e.g. S/MIME), the other for
> mail that contains anything over limits (mailbombs?).
attached you'll find a tested version of the patch. I use it to defang
"mailbombs" like they were in earlier amavis Versions, by the following
configuration:
$defang_by_ccat{CC_UNCHECKED.",2"} = 1;
Please consider this patch, thank you.
Carsten
--- amavisd.orig 2012-06-30 15:43:31.000000000 +0200
+++ amavisd 2013-04-25 13:38:05.349532975 +0200
@@ -427,9 +427,9 @@
# referenced indirectly through *_by_ccat variables for compatibility
[qw(
$final_virus_destiny $final_banned_destiny $final_unchecked_destiny
- $final_spam_destiny $final_bad_header_destiny
- @virus_lovers_maps @spam_lovers_maps @unchecked_lovers_maps
- @banned_files_lovers_maps @bad_header_lovers_maps
+ $final_encrypted_destiny $final_mailbomb_destiny $final_spam_destiny
+ $final_bad_header_destiny @virus_lovers_maps @spam_lovers_maps
+ @unchecked_lovers_maps @banned_files_lovers_maps @bad_header_lovers_maps
$always_bcc $dsn_bcc
$mailfrom_notify_sender $mailfrom_notify_recip
$mailfrom_notify_admin $mailfrom_notify_spamadmin
@@ -1126,6 +1126,8 @@
$final_virus_destiny = D_DISCARD;
$final_banned_destiny = D_DISCARD;
$final_unchecked_destiny = D_PASS;
+ $final_encrypted_destiny = D_PASS;
+ $final_mailbomb_destiny = D_PASS;
$final_spam_destiny = D_PASS;
$final_bad_header_destiny = D_PASS;
@@ -1282,6 +1284,8 @@
CC_SPAMMY.',1','Spammy3', # tag3_level
CC_SPAM, 'Spam', # kill_level
CC_UNCHECKED, 'Unchecked',
+ CC_UNCHECKED.',1', 'UncheckedCrypted',
+ CC_UNCHECKED.',2', 'UncheckedOverLimits',
CC_BANNED, 'Banned',
CC_VIRUS, 'Virus',
);
@@ -1720,6 +1724,8 @@
CC_VIRUS, sub { c('final_virus_destiny') },
CC_BANNED, sub { c('final_banned_destiny') },
CC_UNCHECKED, sub { c('final_unchecked_destiny') },
+ CC_UNCHECKED.',1', sub { c('final_encrypted_destiny') },
+ CC_UNCHECKED.',2', sub { c('final_mailbomb_destiny') },
CC_SPAM, sub { c('final_spam_destiny') },
CC_BADH, sub { c('final_bad_header_destiny') },
CC_MTA.',1', D_TEMPFAIL,
@@ -1736,6 +1742,8 @@
CC_VIRUS, 'id=%n - INFECTED: %V',
CC_BANNED, 'id=%n - BANNED: %F',
CC_UNCHECKED, 'id=%n - UNCHECKED',
+ CC_UNCHECKED.',1', 'id=%n - UNCHECKED: encrypted message',
+ CC_UNCHECKED.',2', 'id=%n - UNCHECKED: possible mail bomb',
CC_SPAM, 'id=%n - spam',
CC_SPAMMY.',1', 'id=%n - spammy (tag3)',
CC_SPAMMY, 'id=%n - spammy',
@@ -12532,7 +12540,7 @@
# across some permanent problem making us unable to decide
# if the message is to be really delivered.
# is any mail component password protected or otherwise non-decodable?
- my $any_undecipherable = 0;
+ my $any_undecipherable = 0; my $all_crypted = 1; my $over_levels = 0;
my $mime_err; # undef, or MIME parsing error string as given by MIME::Parser
if (defined $last_task_completed_at) {
my $dt = $msginfo->rx_time - $last_task_completed_at;
@@ -12793,13 +12801,16 @@
$which_section = "parts_decode_ext";
snmp_count('OpsDec');
- ($hold,$any_undecipherable) =
+ ($hold,$any_undecipherable,$all_crypted,$over_levels) =
Amavis::Unpackers::decompose_mail($msginfo->mail_tempdir,
$file_generator_object);
if ($hold ne '' || $any_undecipherable) {
- $msginfo->add_contents_category(CC_UNCHECKED,0);
+ my $subcc = 0;
+ $subcc = 1 if ($any_undecipherable && $all_crypted);
+ $subcc = 2 if ($hold ne '' and $over_levels);
+ $msginfo->add_contents_category(CC_UNCHECKED,$subcc);
for my $r (@{$msginfo->per_recip_data}) {
- $r->add_contents_category(CC_UNCHECKED,0)
+ $r->add_contents_category(CC_UNCHECKED,$subcc)
if !$r->bypass_virus_checks;
}
}
@@ -27525,12 +27536,15 @@
my($tempdir,$file_generator_object) = @_;
my $hold; my(@parts); my $depth = 1; my $any_undecipherable = 0;
+ my $all_crypted = 1;
+ my $over_levels = 0;
my $which_section = "parts_decode";
# fetch all not-yet-visited part names, and start a new cycle
TIER:
while (@parts = @{$file_generator_object->parts_list}) {
if ($MAXLEVELS > 0 && $depth > $MAXLEVELS) {
$hold = "Maximum decoding depth ($MAXLEVELS) exceeded";
+ $over_levels = 1;
last;
}
$file_generator_object->parts_list_reset; # new cycle of names
@@ -27577,14 +27591,18 @@
}
for my $part (@parts) {
if ($part->exists && !defined($hold))
- { $hold = decompose_part($part, $tempdir) }
- $any_undecipherable++ if grep($_ eq 'U', @{ $part->attributes || [] });
+ { ( $hold, $over_levels ) = decompose_part($part, $tempdir) }
+ if ( grep($_ eq 'U', @{ $part->attributes || [] }) ) {
+ $any_undecipherable++;
+ if (! grep($_ eq 'C', @{ $part->attributes || [] }))
+ { $all_crypted = 0; }
+ }
}
last TIER if defined $hold;
$depth++;
}
section_time($which_section); prolong_timer($which_section);
- ($hold, $any_undecipherable);
+ ($hold, $any_undecipherable, $all_crypted, $over_levels);
}
# Decompose one part
@@ -27595,7 +27613,7 @@
# 0 - truly atomic or unknown or archiver failure; consider atomic
# 1 - some archive, successfully unpacked, result replaces original
# 2 - probably unpacked, but keep the original (eg self-extracting archive)
- my $hold; my $eval_stat; my $sts = 0; my $any_called = 0;
+ my $hold; my $eval_stat; my $sts = 0; my $any_called = 0; my $over_levels = 0;
eval {
my $type_short = $part->type_short;
my(@ts) = !defined $type_short ? ()
@@ -27618,7 +27636,7 @@
my $ll = -1;
if ($eval_stat =~ /\bExceeded storage quota\b.*\bbytes by/ ||
$eval_stat =~ /\bMaximum number of files\b.*\bexceeded/) {
- $hold = $eval_stat; $ll = 1;
+ $hold = $eval_stat; $ll = 1; $over_levels = 1;
}
do_log($ll,"Decoding of %s (%s) failed, leaving it unpacked: %s",
$part->base_name, $part->type_long, $eval_stat);
@@ -27643,7 +27661,7 @@
['atomic','archive, unpacked','source retained']->[$sts]);
section_time('decompose_part') if $any_called;
die $eval_stat if $eval_stat =~ /^timed out\b/; # resignal timeout
- $hold;
+ ( $hold, $over_levels );
}
# a trivial wrapper around mime_decode() to adjust arguments and result