• We value your experience with Plesk during 2024
    Plesk strives to perform even better in 2025. To help us improve further, please answer a few questions about your experience with Plesk Obsidian 2024.
    Please take this short survey:

    https://pt-research.typeform.com/to/AmZvSXkx
  • The Horde webmail has been deprecated. Its complete removal is scheduled for April 2025. For details and recommended actions, see the Feature and Deprecation Plan.
  • We’re working on enhancing the Monitoring feature in Plesk, and we could really use your expertise! If you’re open to sharing your experiences with server and website monitoring or providing feedback, we’d love to have a one-hour online meeting with you.

Question How to remove viruses with Clamav via Spamassassin

andreios

Regular Pleskian
This is Ubuntu LTS 20.04 with Plesk Obisidian Version 18.0.42
I have installed Clamav with Spamassassin like this. This moves every infected mail to the spam folder. But it adds the original mail including the virus as attachment. How do I remove the virus from this mail?

This is what I have done so far.
Code:
apt install clamav libclamav-client-perl clamav-unofficial-sigs


Added new file called /etc/spamassassin/clamav.pm with this content:

Perl:
package ClamAV;
use strict;

# version 2.0, 2010-01-07
#   - use SA public interface set_tag() and add_header, instead of
#     pushing a header field directly into $conf->{headers_spam}

# our $CLAMD_SOCK = 3310;               # for TCP-based usage
our $CLAMD_SOCK = "/var/run/clamav/clamd.ctl";

use Mail::SpamAssassin;
use Mail::SpamAssassin:lugin;
use Mail::SpamAssassin::Logger;
use File::Scan::ClamAV;
our @ISA = qw(Mail::SpamAssassin:lugin);

sub new {
  my ($class, $mailsa) = @_;
  $class = ref($class) || $class;
  my $self = $class->SUPER::new($mailsa);
  bless($self, $class);
  $self->register_eval_rule("check_clamav");
  return $self;
}

sub check_clamav {
  my($self, $pms, $fulltext) = @_;
  dbg("ClamAV: invoking File::Scan::ClamAV, port/socket: %s", $CLAMD_SOCK);
  my $clamav = new File::Scan::ClamAV(port => $CLAMD_SOCK);
  my($code, $virus) = $clamav->streamscan(${$fulltext});
  my $isspam = 0;
  my $header = "";
  if (!$code) {
    my $errstr = $clamav->errstr();
    $header = "Error ($errstr)";
  } elsif ($code eq 'OK') {
    $header = "No";
  } elsif ($code eq 'FOUND') {
    $header = "Yes ($virus)";
    $isspam = 1;
    # include the virus name in SpamAssassin's report
    $pms->test_log($virus);
  } else {
    $header = "Error (Unknown return code from ClamAV: $code)";
  }
  dbg("ClamAV: result - $header");
  $pms->set_tag('CLAMAVRESULT', $header);
  # add a metadatum so that rules can match against the result too
  $pms->{msg}->put_metadata('X-Spam-Virus',$header);
  return $isspam;
}

1;

Addedd on bottom of /etc/spamassassin/local.cf


Perl:
loadplugin ClamAV clamav.pm
full CLAMAV eval:check_clamav()
describe CLAMAV Clam AntiVirus detected a virus
score CLAMAV 15
add_header all Virus _CLAMAVRESULT_

Code:
service spamassassin restart
 
don't understand, why you are accept mails containing a virus.

There is a problem, if it isn't spam containing a virus, but mail from a user and his infected PC. You have to inform the sender in case you have accepted the mail. Better way IMHO is using REJECT.

This is maillog for ok mail
Mar 14 07:34:10 puck983 psa-pc-remote[17014]: 24B775CC0367: hitd-virus-handler: stderr: LOG HITDVIRUS ClamAV clean ( no virus )
Mar 14 07:34:10 puck983 psa-pc-remote[17014]: 24B775CC0367: hitd-virus-handler: stderr: LOG HITDVIRUS drweb Base timestamp: 2022-03-14
Mar 14 07:34:10 puck983 psa-pc-remote[17014]: 24B775CC0367: hitd-virus-handler: stderr: LOG HITDVIRUS drweb RC=0
Mar 14 07:34:10 puck983 psa-pc-remote[17014]: 24B775CC0367: hitd-virus-handler: stderr: LOG HITDVIRUS drweb STDERR Results: daemon return code 0x100000 (after scanning/curi
Mar 14 07:34:10 puck983 psa-pc-remote[17014]: 24B775CC0367: hitd-virus-handler: stderr: LOG HITDVIRUS result: PASS exit: 0
Mar 14 07:34:10 puck983 psa-pc-remote[17014]: 24B775CC0367: hitd-virus-handler: stderr: PASS

Same with test of EICAR, but disabled ClamAV to test drweb

Mar 7 06:35:29 puck983 psa-pc-remote[22326]: DBEC65CC12C1: spf: stderr: PASS
Mar 7 06:35:29 puck983 psa-pc-remote[22326]: DBEC65CC12C1: hitd-virus-handler: stderr: LOG HITDVIRUS drweb Base timestamp: 2022-03-06
Mar 7 06:35:30 puck983 psa-pc-remote[22326]: DBEC65CC12C1: hitd-virus-handler: stderr: LOG HITDVIRUS drweb RC=256
Mar 7 06:35:30 puck983 psa-pc-remote[22326]: DBEC65CC12C1: hitd-virus-handler: stderr: LOG HITDVIRUS drweb STDOUT ----- Dr.Web found viruses list begin -----
Mar 7 06:35:30 puck983 psa-pc-remote[22326]: DBEC65CC12C1: hitd-virus-handler: stderr: LOG HITDVIRUS drweb STDOUT Known virus(es):
Mar 7 06:35:30 puck983 psa-pc-remote[22326]: DBEC65CC12C1: hitd-virus-handler: stderr: LOG HITDVIRUS drweb STDOUT EICAR Test File (NOT a Virus!)
Mar 7 06:35:30 puck983 psa-pc-remote[22326]: DBEC65CC12C1: hitd-virus-handler: stderr: LOG HITDVIRUS drweb STDOUT ----- Dr.Web found viruses list end -----
Mar 7 06:35:30 puck983 psa-pc-remote[22326]: DBEC65CC12C1: hitd-virus-handler: stderr: LOG HITDVIRUS drweb STDERR Results: daemon return code 0x20 (known virus is found)
Mar 7 06:35:30 puck983 psa-pc-remote[22326]: DBEC65CC12C1: hitd-virus-handler: stderr: LOG HITDVIRUS drweb result: REJECT VIRUS EICAR Test File (NOT a Virus!)
Mar 7 06:35:30 puck983 psa-pc-remote[22326]: DBEC65CC12C1: hitd-virus-handler: stderr: REJECT VIRUS EICAR Test File (NOT a Virus!)
Mar 7 06:35:30 puck983 postfix/cleanup[32023]: DBEC65CC12C1: milter-reject: END-OF-MESSAGE from foxtrot452.startdedicated.de[85.25.141.40]: 5.7.1 Command rejected;
 

Attachments

  • hitd-virus-handler-06.tar.gz.zip
    10.3 KB · Views: 2
This is interesting, but I have no qmail on my system.
It's currently postfix, not qmail.
However, should work with qmail or postfix.

It is a official plesk feature for both, see:

 
To be honest I don't even know how the right way to implement this script. And what lies in /usr/local/etc/hitd-virus-handler.d/ ?
 
To be honest I don't even know how the right way to implement this script. And what lies in /usr/local/etc/hitd-virus-handler.d/ ?
nothing
Take first a look at:


This is the command to register a additional mailhandler. BTW: there nearby is deregister command also documented.

The 4 bash scripts hitd-virus-handler-receive-on, ...receive-off, ..send-on, ...send-off contains that command as most important part.
I'm using it, not to be forced to remember all the parameters for register a mailhandler.

--executable=/usr/local/sbin/hitd-virus-handler

tells plesk, where the mailhandler is located. You can choose freely. The perl script hitd-virus-handler goes to /usr/local/sbin in our case, but if you told plesk the right place during registering mailhandler, every place in filesystem is fine.

Next:

-context=/usr/local/etc/hitd-virus-handler.d/${CFG}.ini

${CFG} comes from $1
Example:

hitd-virus-handler-receive-on plesk.example.de

does register and enable the handler for domain plesk.example.de ( its the domain in use on the server )

plesk.example.de is translated to plesk_example_de by translate '.' -> '_'

Then append ".ini" and that is the context.
However, there is currently no need for a context.
Usualy this is used for config or init files, like in directsmtp or renattach handler done.

Here for hitd-virus-handler for all domains the same parameters are used, directly encoded within the perl script.

context is there only as a future extention, so by later upgrades is no need to reregister the script again.
because the perl-script does not ask for or use context, there is no need for /usr/local/etc/hitd-virus-handler.d and any content in it yet.

Next Step:
Verify some values within perl-script

Install clamav ( or not ), find the socket used by clamd, install and config updated like freshclam, config systemctl to start clamd automaticaly
next verify drweb socket. there is a conflict with port 3000 expecteted to use by drweb and grafana.

Test virusscanning. download eicar testfile use clamdscan from clamav-package and drwebdc tool.

my $clamd_socket = '/var/run/clamav/clamd.ctl'; # if empty: do not use clamav
#my $clamd_socket = 'localhost:3310'; # if empty: do not use clamav
#my $clamd_socket = ''; # if empty: do not use clamav

#my $sophos_socket = '/run/savdi/sssp.sock'; # if empty: do not use sophos AV
#my $sophos_socket = 'localhost:4010'; # if empty: do not use sophos AV
my $sophos_socket = ''; # if empty: do not use sophos AV

# PATH must be fixed because perl -T flag, using an usual path throws security exception
my $drweb_bin='/usr/bin/drwebdc';
my $drweb_path='/usr/bin';

The values above must be verified and can be used switching a virus scanner on/off to use. Example: if drweb_bin is empty ( i.e. my $drweb_bin=''; ) drweb 6 ( part of plesk ( current, independend drweb is version 11 ) )

note: sophos, works fine, but isn't free anymore (updates fails since about 2 month). sophos stated also to end antivirus for linux this year.
if using the savdid daemon ( independend part from sophos ) must be installed too. savdid is "Sophos AntiVirus Dynamicaly Interface Daemon" need to talk to sophos from a program.

hope that helps
Peter
 
Edit:
if drweb_bin is empty ( i.e. my $drweb_bin=''; ) drweb 6 ( part of plesk ( current, independend drweb is version 11 ) ) is not used.
 
So I have to enable this for sending and recivieng for each domain? That's much I have more than 50 domains.
 
So I have to enable this for sending and recivieng for each domain? That's much I have more than 50 domains.
i think no

plesk docu says:

# ./mail_handlers_control --add
--priority=<number>
--name=<handler name>
--mailname=<mailname>
--queue=<before-local|before-remote|before-queue|before-data>
--type=<sender|recipient|sender-domain|recipient-domain|global>
--executable=<executable file>
[ --context=<context> ]
[ --enabled ]

see --type=global

but i think

# /usr/local/bin/hitd-virus-handler-send-on ALL

does the job (ALL must be uppercase)

note: this is virus-scan for incoming and outgoing mail

hitd-virus-handler-send-off ALL

is the opposite.

You probably has to comment out lines with " --queue=before-sendmail --type=global". Just seen, isn't part of doc anymore. Was in the past for scaning outgoing mail. Maybe it doesn't work anymore or shouldn't used because of load. Usualy no need to scan outgoing messages.
I wrote it for a server some time ago with small load, so i checked incoming and outgoing email. Idea behind was the time gap between creating a virus and virus been known to antivirus programs. Maybe on day 1 a client is infected, at day 2 the virus is known. In that case we can't prevent infection. But if client sends out viruses on day 3 virus is recognized and therefor manual remedy is possible
 
BTW I think the new path is /usr/local/psa/admin/sbin and you can also call this through 'plesk sbin COMMANDNAME'
 
Well I tried the commands from your file but no change in mail handling also no error message, also can't see a virushandler with --list

plesk sbin mail_handlers_control --add --priority=45 --name=virushandler --queue=before-queue --type=global --executable=/usr/local/sbin/hitd-virus-handler
3366 16.3.2022 11:58 plesk sbin mail_handlers_control --enable --priority=45 --name=virushandler --queue=before-queue --type=global --executable=/usr/local/sbin/hitd-virus-handler

Will take a closer look when i have time
 
tried the commands you wrote

root@puck983:/home/p_heirich/hitd_virus_handler/bin# plesk sbin mail_handlers_control --add --priority=45 --name=virushandler --queue=before-queue --type=global --executable=/usr/local/sbin/hitd-virus-handler
root@puck983:/home/p_heirich/hitd_virus_handler/bin# plesk sbin mail_handlers_control --list | grep -i virus
| | X | 45 | all | virushandler | global | before-queue |
| X | X | 40 | secret1.de | virushandler | recipient-domain | before-queue |
| X | X | 40 | secret2.de | virushandler | recipient-domain | before-queue |
root@puck983:/home/p_heirich/hitd_virus_handler/bin# plesk sbin mail_handlers_control --enable --priority=45 --name=virushandler --queue=before-queue --type=global --executable=/usr/local/sbin/hitd-virus-handler
root@puck983:/home/p_heirich/hitd_virus_handler/bin# plesk sbin mail_handlers_control --list | grep -i virus
| X | X | 45 | all | virushandler | global | before-queue |
| X | X | 40 | secret1.de | virushandler | recipient-domain | before-queue |
| X | X | 40 | secret2.de | virushandler | recipient-domain | before-queue |
root@puck983:/home/p_heirich/hitd_virus_handler/bin#

at least --list shows ( only first line, the next both are old by domain and edited for privacy )

first command adds, second command enables works like expected

take a look at the log

Mar 16 13:09:41 puck983 spf[6646]: 36F6E5CC1394: Failed to query guess rules: Could not find a valid SPF record near 'a/24 mx/24'
Mar 16 13:09:41 puck983 psa-pc-remote[17657]: 36F6E5CC1394: spf: stderr: PASS
Mar 16 13:09:41 puck983 psa-pc-remote[17657]: 36F6E5CC1394: hitd-virus-handler: stderr: LOG HITDVIRUS ClamAV 0.103.5/26483/Wed Mar 16 09:27:50 2022
Mar 16 13:09:41 puck983 psa-pc-remote[17657]: 36F6E5CC1394: hitd-virus-handler: stderr: LOG HITDVIRUS ClamAV clean ( no virus )
Mar 16 13:09:41 puck983 psa-pc-remote[17657]: 36F6E5CC1394: hitd-virus-handler: stderr: LOG HITDVIRUS drweb Base timestamp: 2022-03-16
Mar 16 13:09:41 puck983 psa-pc-remote[17657]: 36F6E5CC1394: hitd-virus-handler: stderr: LOG HITDVIRUS drweb RC=0
Mar 16 13:09:41 puck983 psa-pc-remote[17657]: 36F6E5CC1394: hitd-virus-handler: stderr: LOG HITDVIRUS drweb STDERR Results: daemon return code 0x100000 (after scanning/curing composite object is clean)
Mar 16 13:09:41 puck983 psa-pc-remote[17657]: 36F6E5CC1394: hitd-virus-handler: stderr: LOG HITDVIRUS result: PASS exit: 0
Mar 16 13:09:41 puck983 psa-pc-remote[17657]: 36F6E5CC1394: hitd-virus-handler: stderr: PASS

seems to work and

X-Virus-Checker: Scanned by ClamAV 0.103.5/26483/Wed Mar 16 09:27:50 2022 drweb Base timestamp: 2022-03-16 on puck983 ( no virus );
Wed, 16 Mar 2022 13:09:41 +0100

noted in the mail header.
 
I have now something like this in my list.
| X | X | 45 | all | virushandler | global | before-queue |
| X | | 4 | all-recipients | add-from | global | before-sendmail |
| X | | 10 | all-recipients | check-quota | global | before-queue |
| X | | 10 | all-recipients | check-quota | global | before-sendmail |
| X | | 10 | all-recipients | spf | global | before-queue |

So viruhandler is there but when i try it with an EICAR test file it's gets trough any ways.
 
Mar 16 13:49:12 server psa-pc-remote[1579100]: A289045A4976: hitd-virus-handler: stderr: LOG HITDVIRUS spool_dir /var/spool/hitd-virus-handler does not exist and can not be created
Mar 16 13:49:13 server psa-pc-remote[1579100]: A289045A4976: hitd-virus-handler: stderr: LOG HITDVIRUS result: SKIP (because failsafe mode)
Mar 16 13:49:13 server psa-pc-remote[1579100]: A289045A4976: hitd-virus-handler: stderr: SKIP
Mar 16 13:49:13 server psa-pc-remote[1579100]: A289045A4976: dk_sign: stderr: PASS
 
I used it with these permissions now.
drwxrwx--- drweb popuser hitd-virus-handler
Now the script complains about drweb can't connect...
 
root@puck983:/var/spool# ls -l
insgesamt 20
drwxr-xr-x 3 root root 4096 Mär 20 2021 cron
drwxrwx--- 4 drweb popuser 4096 Mär 20 2021 drweb
drwxrwx--- 12 postfix popuser 4096 Mär 16 15:47 hitd-virus-handler
lrwxrwxrwx 1 root root 7 Mär 20 2021 mail -> ../mail
drwxr-xr-x 22 root root 4096 Mär 20 2021 postfix
drwx------ 2 root root 4096 Feb 26 2019 rsyslog
root@puck983:/var/spool#
 
I don't know, this seems to reject anything at the moment and I don't even think rejecting is the best method, it should be silently discarded or quarantined. I think I maybe try to use another approach with amavisd.
 
Now the script complains about drweb can't connect...
Maybe Dr.Web internal

try

1|root@puck983:~# cat eicar_com.zip | drwebdc -orv -
Results: daemon return code 0x20 (known virus is found)
----- Dr.Web found viruses list begin -----
Known virus(es):
EICAR Test File (NOT a Virus!)
----- Dr.Web found viruses list end -----

1|root@puck983:~#

to verify drweb's control-tool drwebdc

note:

root@puck983:~# netstat -lntp | grep :300
tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN 1593/drwebd.real
tcp 0 0 127.0.0.1:3001 0.0.0.0:* LISTEN 5231/grafana-server
root@puck983:~#

sometimes grafana-server catched port 3000, wich causes problems with drweb.

you can test also, mail handler are simple programs using stdin, stdout, stderr

root@puck983:~# cat eicar_com.zip | /usr/local/sbin/hitd-virus-handler
LOG HITDVIRUS ClamAV 0.103.5/26483/Wed Mar 16 09:27:50 2022
LOG HITDVIRUS ClamAV virus signature found: Win.Test.EICAR_HDB-1
LOG HITDVIRUS VIRUS ClamAV result: REJECT VIRUS Win.Test.EICAR_HDB-1
REJECT VIRUS Win.Test.EICAR_HDB-1
virus signature found ClamAV: Win.Test.EICAR_HDB-1

1|root@puck983:~# echo "test" | /usr/local/sbin/hitd-virus-handler
LOG HITDVIRUS ClamAV 0.103.5/26483/Wed Mar 16 09:27:50 2022
LOG HITDVIRUS ClamAV clean ( no virus )
LOG HITDVIRUS drweb Base timestamp: 2022-03-16
LOG HITDVIRUS drweb RC=0
LOG HITDVIRUS drweb STDERR Results: daemon return code 0x100000 (after scanning/curing composite object is clean)
LOG HITDVIRUS result: PASS exit: 0
X-Virus-Checker: Scanned by ClamAV 0.103.5/26483/Wed Mar 16 09:27:50 2022 drweb Base timestamp: 2022-03-16 on puck983 ( no virus );
Wed, 16 Mar 2022 16:14:43 +0100
test
PASS
root@puck983:~#

please note, that test is done clamav before drweb and if clamav found a virus, drweb isn't tested anymore
 
cat eicar-signature.txt| drwebdc -orv - [16:27:00]
dwlib: fd: connect() failed - Connection refused
dwlib: tcp: connecting to 127.0.0.1:3000 - failed
dwlib: cannot create connection with a DrWeb daemon
dwlib: fd: connect() failed - Connection refused
dwlib: tcp: connecting to 127.0.0.1:3000 - failed
dwlib: cannot create connection with a DrWeb daemon
ERROR: cannot retrieve daemon version
Error -12, cannot connect to daemon address
 
Back
Top