diff --git a/spamassassin/files/ClamAV.pm b/spamassassin/files/ClamAV.pm new file mode 100644 index 0000000..414b8b0 --- /dev/null +++ b/spamassassin/files/ClamAV.pm @@ -0,0 +1,111 @@ + +=head1 NAME + +ClamAV - ClamAV anti-virus check + +=head1 SYNOPSIS + + loadplugin Mail::SpamAssassin::Plugin::ClamAV + + full CLAMAV eval:check_clamav() + score CLAMAV 5 + + add_header all Virus _CLAMAV_ + +=head1 DESCRIPTION + +This plugin sends the mail to locally running ClamAV daemon for virus +detection. + +=cut + +package Mail::SpamAssassin::Plugin::ClamAV; + +use Mail::SpamAssassin::Plugin; +use Mail::SpamAssassin::Logger; + +use IO::Socket::UNIX; + +use strict; +use warnings; + +use vars qw(@ISA); +@ISA = qw(Mail::SpamAssassin::Plugin); + +sub new { + my $class = shift; + my $mailsa = shift; + + $class = ref($class) || $class; + my $self = $class->SUPER::new($mailsa); + bless ($self, $class); + + dbg("ClamAV: Registering ClamAV plugin rules"); + $self->register_eval_rule("check_clamav"); + + $self->set_config($mailsa->{conf}); + + return $self; +} + +sub set_config { + my ($self, $conf) = @_; + my @cmds; + +=head1 ADMINISTRATOR SETTINGS + +=over + +=item clamav_socket STRING (default: /var/run/clamav/clamd.sock) + +Full path to locally running ClamAV daemon socket. + +=cut + + push (@cmds, { + setting => "clamav_socket", + is_admin => 1, + default => "/var/run/clamav/clamd.sock", + type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING, + }); + + $conf->{parser}->register_commands(\@cmds); + +} + +sub check_clamav { + my ($self, $permsg, $fulltext) = @_; + + my $socket = IO::Socket::UNIX->new( + Type => SOCK_STREAM, + Peer => $self->{main}->{conf}->{clamav_socket} + ) || info("ClamAV: Failed to connect socket, skipping virus check"); + + $socket->send("nINSTREAM\n"); + $socket->send(pack("N", length($$fulltext))); + $socket->send($$fulltext); + $socket->send(pack("N", 0)); + + my $result = $socket->getline(); + if ($result =~ /^stream: (.+) FOUND/i) { + info("ClamAV: Found virus " . $1); + $permsg->set_tag("CLAMAV", $1); + my $rulename = $permsg->get_current_eval_rule_name(); + $permsg->{conf}->{descriptions}->{$rulename} = "Found virus " . $1; + $result = 1; + } elsif ($result =~ /^(.*) ERROR/i) { + $permsg->set_tag("CLAMAV", "Error during scanning"); + info("ClamAV: Error in scanning: " . $1); + $result = 0; + } else { + $permsg->set_tag("CLAMAV", "Clean"); + dbg("ClamAV: Message clean"); + $result = 0; + } + + $socket->send("QUIT\n"); + close $socket; + return $result; +} + +1; diff --git a/spamassassin/files/clamav.cf b/spamassassin/files/clamav.cf new file mode 100644 index 0000000..1c7c06d --- /dev/null +++ b/spamassassin/files/clamav.cf @@ -0,0 +1,6 @@ +loadplugin Mail::SpamAssassin::Plugin::ClamAV ClamAV.pm + +full CLAMAV eval:check_clamav() +score CLAMAV 5 + +add_header all Virus _CLAMAV_ diff --git a/spamassassin/manifests/init.pp b/spamassassin/manifests/init.pp index fc1b815..948e44d 100644 --- a/spamassassin/manifests/init.pp +++ b/spamassassin/manifests/init.pp @@ -110,6 +110,40 @@ class spamassassin::milter($options="") { } +# Install ClamAV plugin for spamassassin +# +class spamassassin::plugin::clamav { + + include spamassassin::common + + file { "/etc/mail/spamassassin/ClamAV.pm": + ensure => present, + source => "puppet:///modules/spamassassin/ClamAV.pm", + mode => "0644", + owner => "root", + group => $::operatingsystem ? { + "openbsd" => "wheel", + default => "root", + }, + } + + file { "/etc/mail/spamassassin/clamav.cf": + ensure => present, + source => "puppet:///modules/spamassassin/clamav.cf", + mode => "0644", + owner => "root", + group => $::operatingsystem ? { + "openbsd" => "wheel", + default => "root", + }, + require => [ File["/etc/mail/spamassassin/ClamAV.pm"], + Package["spamassassin"], ], + notify => Service["spamassassin"], + } + +} + + # Install iXhash plugin for spamassassin # class spamassassin::plugin::ixhash {