Using the ClamAV daemon to scan files placed in my Downloads directory in Gentoo Linux

In a previous post I explained how to automatically detect files placed in my Downloads directory in Linux and scan them for viruses. The method I described in that post used clamscan, the command-line anti-virus scanner of ClamAV. Now, in addition ClamAV has a daemon (a program that runs continuously in the background), clamdscan, that you can enable. So I decided to switch to using clamdscan, as its response to downloaded files is much faster because the process waiting for new files to appear in ~/Downloads/ does not have to load clamscan from disk each time a new file arrives. Anyway, if you want to monitor a download directory in Gentoo Linux (running OpenRC) by using the ClamAV daemon — which will also download virus signature database updates automatically — then the procedure to set this up is given below.

1. Install clamav if it is not installed already:

root # emerge clamav

2. Add the service to the default runlevel:

root # rc-update add clamd default

The daemon will be launched automatically next time the computer boots.

3. The first download of the virus database has to be done manually:

root # freshclam

4. Start the daemon now:

root # rc-service clamd start

5. Create the Bash script ~/monitorDownloadsGUI with the following contents:



# Get rid of old log file, if any
rm $HOME/virus-scan.log 2> /dev/null

IFS=$(echo -en "\n\b")

# Optionally, you can use shopt to avoid creating two processes due to the pipe
shopt -s lastpipe
inotifywait --quiet --monitor --event close_write,moved_to --recursive --format '%w%f' $DIR | while read FILE
# Added '--recursive' so that a directory copied into $DIR also triggers clamscan/clamdscan, although downloads
# from the Web would just be files, not directories.
     # Have to check file length is nonzero otherwise commands may be repeated
     if [ -s $FILE ]; then
          # Replace 'date >' with 'date >>' if you want to keep log file entries for previous scans.
          date > $HOME/virus-scan.log
          clamdscan --move=$HOME/virus-quarantine $FILE >> $HOME/virus-scan.log
          kdialog --title "Virus scan of $FILE" --msgbox "$(cat $HOME/virus-scan.log)"

Make it executable:

user $ chmod +x ~/monitorDownloadsGUI

6. Create the directory ~/virus-quarantine/ to store infected files pending investigation/deletion:

user $ mkdir ~/virus-quarantine

7. Install kdialog if it is not already installed:

root # emerge kdialog

8. Use ‘System Settings’ > ‘Startup and Shutdown’ > ‘Autostart’ to add the script ~/monitorDownloadsGUI to the list of script files that are automatically started each time you log in to KDE.

9. Log out then back in again, and you should see that everything is running as expected:

user $ rc-status | grep clam
 clamd                                                             [  started  ]

user $ ps -ef | grep clam | grep -v grep
clamav    1920     1  0 01:48 ?        00:00:00 /usr/sbin/clamd
clamav    1929     1  0 01:48 ?        00:00:00 /usr/bin/freshclam -d

user $ ps -ef | grep GUI | grep -v grep
fitzcarraldo      9143  8971  0 13:56 ?        00:00:00 /bin/bash /home/fitzcarraldo/.config/autostart-scripts/

10. To test, surf to and download one of the EICAR test files into your ~/Downloads/ directory. You should see a pop-up KDialog window with a message similar to the following:

Virus scan of /home/fitzcarraldo/Downloads/ — KDialog

Mon 27 Feb 14:05:26 GMT 2017
/home/fitzcarraldo/Downloads/ Eicar-Test-Signature FOUND
/home/fitzcarraldo/Downloads/ moved to ‘/home/fitzcarraldo/virus-quarantine/’

———– SCAN SUMMARY ———–
Infected files: 1
Time: 0.001 sec (0 m 0 s)

Note that the above-mentioned pop-up window may be preceded by one or more pop-up windows with an error message. I’m using the Chrome browser at the moment, but you may get a similar message if you are using another browser. Here is an example:

Virus scan of /home/fitzcarraldo/Downloads/ — KDialog ?

Mon 27 Feb 14:16:30 GMT 2017
/home/fitzcarraldo/Downloads/ Access denied. ERROR

———– SCAN SUMMARY ———–
Infected files: 0
Total errors: 1
Time: 0.000 sec (0 m 0 s)

Read the error message and click ‘OK’, as this is not an actual problem; it is inotifywait detecting temporary files in the ~/Downloads/ directory during the download process. With larger files sometimes several such messages are displayed, presumably because the file being downloaded is being opened and closed more than once during the downloading process. This issue does not occur if you copy or move a file into ~/Downloads/ from another directory in your installation; try it and see for yourself. Then you only get the one pop-up window with the scan result for the file you put in ~/Downloads/.

Also have a look in ~/virus-quarantine/ and you will see the EICAR test file in that directory. You can delete it if you want (it is not infected with a real virus, so does no harm).

In future be sure to read the messages in the pop-up windows before clicking ‘OK’, as they will inform you that an infected file has been moved to the quarantine directory.

That’s all there is to it. Very simple, and quite handy if you want to check quickly that files you download don’t have a malware payload. Just make sure you download all files into ~/Downloads/ or they will not be checked automatically. Also, if you are given e.g. a USB pen drive with a file on it, you can copy the file to ~/Downloads/ if you want it to be scanned for malware.

Thunderbird’s defective method of enabling anti-virus software to scan incoming POP3 e-mail messages

Thunderbird’s method of enabling anti-virus software to scan incoming e-mail messages is explained in the mozillaZine article ‘Download each e-mail to a separate file before adding to Inbox‘ and in Mozilla bug report no. 116443 (the bug report that resulted in the functionality being implemented). It is my contention that the design is deficient and is actually not a solution. In this post I explain why I believe this to be the case. Although here I will discuss Thunderbird in Linux, I believe the deficiency applies to Thunderbird in all OSs.

By default, Thunderbird inserts new incoming e-mail messages into an Inbox file. However, it is possible to configure Thunderbird to first create a temporary file containing each individual e-mail message in the /tmp directory, to enable external anti-virus software to scan each message before Thunderbird inserts it into the Inbox file. This approach only works for POP3 e-mail. The developers’ rationale for implementing this approach was to avoid the possibility of anti-virus software deleting or quarantining an entire Inbox.

In summary, if you want to scan incoming e-mails on your machine without running the risk of losing the entire Thunderbird Inbox, you must:

  1. configure Thunderbird so it creates temporary files /tmp/newmsg* (each file contains a single e-mail message containing ASCII characters);
  2. configure the anti-virus software not to scan the directory containing the Inbox;
  3. configure the anti-virus software to scan the /tmp directory.

Nevertheless, it seems Thunderbird developers would prefer you to disable local scanning of e-mail messages entirely: ‘mozillaZine – Email scanning – pros and cons‘.

Nowadays e-mail servers scan e-mail messages before you even download them. Some e-mail servers even send you an automated e-mail to inform you about an infected incoming e-mail or about an infected outgoing e-mail rejected by a receiving e-mail server. So local scanning of e-mail messages is far less important. Furthermore, I am not sure if the anti-virus software I use (ClamAV) is capable of detecting viruses in e-mail attachments encoded as ASCII characters. Anyway, purely out of curiosity I decided to investigate whether it would be possible to scan Thunderbird’s temporary files reliably.

To configure Thunderbird to create the temporary message files, it is necessary to select ‘Edit’ > ‘Preferences’ > ‘Security’ > ‘Antivirus’ and tick ‘Allow anti-virus clients to quarantine individual incoming messages’ (which sets mailnews.downloadToTempFile to true). Once that option has been selected, Thunderbird creates a temporary file /tmp/newmsg per message, which exists for a very brief (and inconstant) time before Thunderbird deletes it. When downloading several e-mail messages in very rapid succession, Thunderbird creates temporary files with different names (‘newmsg‘, ‘newmsg-1‘, ‘newmsg-2‘, ‘newmsg-3‘ and so on) to avoid overwriting messages, but usually one file named newmsg is sufficient to cater for the message download rate, as Thunderbird only keeps the temporary files for a very short time until it moves the message to the Inbox.

The problem with this approach is that Thunderbird does not provide any handshake mechanism to inform external anti-virus software that it has finished writing to a temporary file and that the file is available for scanning, nor does Thunderbird provide any handshake mechanism for external anti-virus software to inform Thunderbird when the scan of each temporary message file has finished (i.e. to tell Thunderbird that it can go ahead and delete the temporary file). In other words, the Thunderbird ‘solution’ is not a solution at all. In fact, I have found empirically that, if the anti-virus software is not fast enough, it can scan an incomplete temporary message file (i.e. the evaluation of the e-mail message would not be thorough and hence would be invalid). The Bash script below, for example, is sometimes able to scan an entire Thunderbird temporary file but at other times only manages to capture part of the file (it appears Thunderbird opens and closes the temporary file more than once) before Thunderbird deletes it:


# This script only works with Thunderbird.
# This script only works for POP3 e-mail.
# You must configure Thunderbird to create temporary files /tmp/newmsg*.
# To do that, set Edit > Preferences > Security > Antivirus and tick
# 'Allow anti-virus clients to quarantine individual incoming messages'
# which sets mailnews.downloadToTempFile to true.

mkdir $WORK 2> /dev/null
rm $WORK/* 2> /dev/null


# Watch for newmsg* file(s) created by Thunderbird in /tmp
inotifywait -q -m -e close_write --format '%f' /tmp | while read FILE
     if [ "${FILE:0:6}" = "newmsg" ] && [ -s /tmp/$FILE ]; then
          cp -p /tmp/$FILE $WORK/$TMPFILE
          # Do not let clamscan write temporary files to /tmp as inotifywait will detect them!
          clamscan --tempdir=$WORK $WORK/$TMPFILE

Below is an example of an incomplete newmsg file that the above script copied to the directory $WORK when Thunderbird downloaded an e-mail message:

From - Sun Feb 21 09:40:58 2016
X-Account-Key: account8
X-Mozilla-Status: 0000
X-Mozilla-Status2: 00000000

I began to wonder if a valid scan would be possible if the script were to lock the temporary file (e.g. using the chattr +i command) until it has completed copying it. The use of the chattr command in the script means it has to be executed by the root user. When I first did that with a modified version of the script using KDialog to display the result of ClamAV’s scan, the following error message was displayed and the script aborted:

kdialog(xxxxxx)/kdeui (kdelibs): Session bus not found
To circumvent this problem try the following command (with Linux and bash)
export $(dbus-launch)

I therefore added the line ‘export $(dbus-launch)‘ to the script as follows:


# This script must be launched by the root user.
export XAUTHORITY="/home/fitzcarraldo/.Xauthority"
export DISPLAY=":0"
export $(dbus-launch)

mkdir $WORK 2> /dev/null
rm $WORK/* 2> /dev/null

inotifywait -q -m -e modify --format '%f' /tmp | while read FILE
     # If file name begins with "newmsg" then copy it to work directory and scan it.
     if [ "${FILE:0:6}" = "newmsg" ] && [ -f /tmp/$FILE ]; then
          chattr +i /tmp/$FILE # Stop Thunderbird opening/deleting file.
          cp -p /tmp/$FILE $WORK/
          chattr -i /tmp/$FILE # Allow Thunderbird to open/delete file.
          clamscan --tempdir=$WORK $WORK/$FILE >> $WORK/$FILE.log
          kdialog --msgbox "$(cat $WORK/$FILE.log)"

However, when the above script was running, Thunderbird displayed a pop-up window if it attempted to copy the temporary file to the Inbox before the script released the lock on the file:

There was an error copying the downloaded message from the temporary download file. Perhaps it contained a virus, or you are low on disk space.
Subject: Test to see what happens if script locks newmsg file
Do you want to skip this message?

I clicked ‘No’ and the e-mail message in the file /tmp/newmsg was deleted without being copied to the Inbox, and the message was not deleted from the e-mail server. Subsequent attempts to re-download the message resulted in the same behaviour if the script had not finished processing the message before Thunderbird tried to move the message to the Inbox. Had I clicked ‘Yes’ I assume Thunderbird would simply have deleted the message on the mail server.

I did not bother looking into it further, but presumably the chattr command triggers inotifywait, in which case the script could cycle several times for the same file.

An approach that would probably work would be for Thunderbird to provide some sort of interlock so that it waits to delete newmsg* files until an anti-virus application gives the go-ahead.

An alternative approach would be for Thunderbird not to delete a temporary file after it writes the message to the Inbox and just leave it in the /tmp directory without overwriting it. An anti-virus application would quarantine infected temporary files and leave uninfected temporary files in /tmp, and therefore the anti-virus application would have to be written so that it deletes the temporary file once it has finished scanning it.

The second approach mentioned above would not be as good as the first approach for the following reasons:

  1. It would not stop Thunderbird adding a message to the Inbox (which would mean the user would have to delete a message manually from the Thunderbird Inbox if the virus scanner reported a message as infected).
  2. Thunderbird would have to use a different file name to any existing temporary files (at present it reuses ‘newmsg‘ if a file of that name does not already exist).
  3. The user would have to ensure the temporary files do not accumulate ad infinitum. In my case, the contents of the /tmp directory are deleted each time I reboot, but, in theory, a partition could become full if a user never switched off a machine and received a lot of e-mails.

Regarding the second reason listed above, Thunderbird already names the temporary files ‘newmsg‘, ‘newmsg-1‘, ‘newmsg-2‘ etc., so perhaps the existing Thunderbird code would automatically use a different file name if a file with the same name were still present, rather than overwriting it. If e.g. files newmsg and newmsg-2 happened to exist, I would hope Thunderbird would name the next temporary file ‘newmsg-1‘ or ‘newmsg-3‘.

I wondered if it would be possible to catch up with Thunderbird by just copying the temporary message files from the /tmp directory to another directory (see the script below), and then processing them afterwards with another script. However, even if a script just copies the temporary files to another directory without running ClamAV or KDialog, I found it is still not fast enough to catch all temporary files before Thunderbird deletes them. If Thunderbird downloads a single message and no others are waiting on the server(s) to be downloaded, it seems a script can copy the temporary messages successfully. However, if there are several messages waiting to be downloaded from the e-mail server(s) and Thunderbird downloads them in rapid succession, Thunderbird deletes some of the temporary messages before the script can copy them fully.


# Create work directory if it does not already exist
mkdir $WORK 2> /dev/null
# Delete old working files if they exist
rm $WORK/* 2> /dev/null


inotifywait -q -m -e close_write --format '%f' /tmp | while read FILE
     if [ "${FILE:0:6}" = "newmsg" ] && [ -s /tmp/$FILE ]; then
          cp -p /tmp/$FILE $WORK/$TMPFILE

Consider the following six messages copied to $HOME/clamtmp by the above script (the script adds the first character to the name of the copied file):

-rw-------   1 fitzcarraldo fitzcarraldo    3829 Feb 23 02:24 1newmsg
-rw-------   1 fitzcarraldo fitzcarraldo    3107 Feb 23 02:25 2newmsg
-rw-------   1 fitzcarraldo fitzcarraldo 1158576 Feb 23 02:26 3newmsg
-rw-------   1 fitzcarraldo fitzcarraldo     237 Feb 23 02:28 4newmsg
-rw-------   1 fitzcarraldo fitzcarraldo    2106 Feb 23 02:28 5newmsg-1
-rw-------   1 fitzcarraldo fitzcarraldo    3107 Feb 23 02:28 6newmsg-2

The first three messages were each the sole message on all three e-mail servers accessed, and the copied files newmsg -> 1newmsg, newmsg -> 2newmsg and newmsg -> 3newmsg were all complete messages. However, the last three messages were on three e-mail servers simultaneously waiting to be downloaded, and when I clicked on ‘Get All New Messages’ in Thunderbird, the copied files newmsg -> 4newmsg, newmsg-1 -> 5newmsg-1 and newmsg-2 -> 6newmsg-2 were downloaded by Thunderbird in rapid succession. The copy 4newmsg was incomplete, the copy 5newmsg-1 was complete and the copy 6newmsg-2 was complete. So, even with a faster script, there is no guarantee that a script can catch all the temporary message files. Therefore, as I mentioned earlier, the only way to guarantee that temporary message files are properly scanned would be to modify Thunderbird to provide either a handshake (e.g. a file lock or inter-application flag) or to leave each temporary message file on /tmp and give it a unique file name.

The downside with both the above-mentioned approaches would be that the anti-virus software developer would need to know about the method, and write the software to perform the appropriate actions. If the first approach were adopted, the anti-virus software would need to signal to Thunderbird that it had completed scanning the file (e.g. by releasing a file lock or by an inter-application message). If the second approach were adopted, the anti-virus software would need to delete the message file from /tmp once it had completed scanning the file. The second approach would be easier for a simple Bash script to use, and, had the Thunderbird source code not been so complicated, I would have had a go at patching it to leave temporary message files in the /tmp directory after Thunderbird copies their contents to the Inbox file. But, as e-mail servers already do a good job of scanning messages before Thunderbird downloads them, I will not spend more time on this. Some e-mail servers even send an e-mail to the user informing them about an infected e-mail (see examples below), so it is not worth bothering.

Example 1
Automated e-mail server message to warning him that the e-mail with an infected attachment he sent to was blocked by the receiving e-mail server.

Subject: Mail delivery failed: returning message to sender
Date: Wed, 17 Feb 2016 11:30:10 +0100
From: Mail Delivery System

This message was created automatically by mail delivery software.

A message that you sent could not be delivered to one or more of
its recipients. This is a permanent error. The following address

virus/suspect content found

— The header of the original message is following. —

Example 2
Automated e-mail server message to warning him that an e-mail with an infected attachment sent to him by was blocked by the receiving e-mail server.

Subject: VIRUS SUSPECTED: “Dave (Hotmail)”
Date: Wed, 17 Feb 2016 11:46:07 +0100 (CET)
From: Mail Delivery System

A virus was detected in the following e-mail!

Mail details:

From: “Dave (Hotmail)”
TO: John Smith
Date: Wed, 17 Feb 2016 10:45:55 +0000
Subject: EICAR test file attachment

The concerned e-mail has been handled according to your Virus Protection Settings.

Your E-mail Service Provider Team

[ This is an automatically generated email, do not reply to this sender. You may find more
information in the online help of your client. ]

Other articles of interest: mozillaZine – Antivirus software.

Automatically detecting files placed in my Downloads directory in Gentoo Linux and scanning them for viruses

I have been using Linux for almost a decade and have never been unduly concerned about viruses on my machines running Linux. However, I do receive files from people who use Windows and Mac OS, and some of those files might contain Windows or Mac OS viruses, so, as a matter of courtesy and assistance to others, it would make some sense to scan those files before passing them on. Furthermore, as I use some Windows applications under WINE, it would also make sense to scan received files for Windows viruses if I am going to use those files with a Windows application running under WINE.

External files could get into my Gentoo Linux installations via pen drives, memory cards, optical discs, e-mails, my Dropbox directory and downloads from Web sites. In this post I am going to concentrate on the last of these. All the various e-mail account providers I use already scan e-mails for viruses on their e-mail servers before I even download e-mail into the e-mail client on my laptop (standard practice these days), so e-mail is not a particular worry.

I have had ClamAV and its GUI, ClamTk, installed for a long time. Whilst ClamTk can be used to schedule a daily update of virus signatures and a daily scan of one’s home directory by ClamAV, I normally run ClamTk and ClamAV ad hoc. However, I can see some benefit in launching ClamAV automatically when I download a file from the Internet, so I decided to do the following …

Automatically scan a file downloaded via a Web browser

I use Firefox to browse the Web, and had configured it to download files to the directory /home/fitzcarraldo/Downloads/. I decided to monitor automatically the Downloads directory for the addition of any file. As I use the ext4 file system, the method I opted to use is inotify, specifically the inotifywait command which is available once you install the package sys-fs/inotify-tools.

It is surprisingly easy to create a shell script to detect files downloaded into a directory. The following script, running continuously in a terminal, would detect any files created in my /home/fitzcarraldo/Downloads directory, scan the new files with ClamAV and display a report in the terminal window:



inotifywait -q -m -e create --format '%w%f' $DIR | while read FILE
     echo "File $FILE has been detected. Scanning it for viruses now ..."
     clamscan $FILE

A usable script would need to be a bit more sophisticated than the one shown above, because an existing file in the directory could be overwritten by one with the same name, or opened and amended. Furthermore, the script above would need a permanently open terminal window. Therefore I created a script to run in the background and use a GUI dialogue tool to pop up a window with the virus scanner’s report when the script detects a new or changed file in the Downloads directory. As this laptop has KDE 4 installed I opted to use KDialog to display the pop-up window, but I could instead have used Zenity. The final script is shown below.



# Get rid of old log file
rm $HOME/virus-scan.log 2> /dev/null

inotifywait -q -m -e close_write,moved_to --format '%w%f' $DIR | while read FILE
     # Have to check file length is nonzero otherwise commands may be repeated
     if [ -s $FILE ]; then
          date > $HOME/virus-scan.log
          clamscan $FILE >> $HOME/virus-scan.log
          kdialog --title "Virus scan of $FILE" --msgbox "$(cat $HOME/virus-scan.log)"

Now when I download a file in Firefox, a window pops up, displaying a message similar to the following:

Virus scan of /home/fitzcarraldo/Downloads/ – KDialog

Fri 19 Feb 23:42:02 GMT 2016
/home/fitzcarraldo/Downloads/ Eicar-Test-Signature FOUND

———– SCAN SUMMARY ———–
Known viruses: 4259980
Engine version: 0.98.7
Scanned directories: 0
Scanned files: 1
Infected files: 1
Data scanned: 0.00 MB
Data read: 0.00 MB (ratio 0.00:1)
Time: 4.595 sec (0 m 4 s)

Notice in the above message that ClamAV detected a virus in a file that I downloaded from the European Expert Group for IT Security Web site (originally ‘European Institute for Computer Antivirus Research’). In fact the executable does not contain a real virus; it was designed to contain a known signature that virus scanner creators and users can use in checking anti-virus software. You can find out more about the virus test files on the EICAR Web site.

Of course, if I use applications other than Firefox to download files, I need to make sure they download the files into the applicable directory so that the script can detect and scan the files:

fitzcarraldo@clevow230ss ~ $ cd Downloads/
fitzcarraldo@clevow230ss ~/Downloads $ youtube-dl -o Carnavalito.mp4 -f 18
ZDUL3w7zFD4: Downloading webpage
ZDUL3w7zFD4: Downloading video info webpage
ZDUL3w7zFD4: Extracting video information
ZDUL3w7zFD4: Downloading MPD manifest
[download] Destination: Carnavalito.mp4
[download] 100% of 16.61MiB in 00:05

So, now I have a shell script that pops up a window informing me whether or not any file I put in $HOME/Downloads/ contains a virus. But I would like the script to be launched automatically when I login to the Desktop Environment. Therefore, as I use KDE 4, I selected ‘System Settings’ > ‘Startup and Shutdown’ and, in the ‘Autostart’ pane, clicked on ‘Add Script…’ and entered the path to my shell script (I left ‘create as symlink’ ticked). Now, every time I use KDE, any file placed (automatically or manually) into $HOME/Downloads/ is scanned for viruses automatically and a window pops up giving the result.

As my laptop is not always connected to the Internet, I prefer to update the ClamAV virus signatures database manually, which I do either using the ClamTk GUI or via the command line using the freshclam command:

fitzcarraldo@clevow230ss ~ $ su
clevow230ss fitzcarraldo # freshclam
ClamAV update process started at Sat Feb 20 10:51:01 2016
WARNING: Your ClamAV installation is OUTDATED!
WARNING: Local version: 0.98.7 Recommended version: 0.99
main.cvd is up to date (version: 55, sigs: 2424225, f-level: 60, builder: neo)
Downloading daily-21375.cdiff [100%]
Downloading daily-21376.cdiff [100%]
Downloading daily-21377.cdiff [100%]
Downloading daily-21378.cdiff [100%]
Downloading daily-21379.cdiff [100%]
Downloading daily-21380.cdiff [100%]
Downloading daily-21381.cdiff [100%]
Downloading daily-21382.cdiff [100%]
Downloading daily-21383.cdiff [100%]
Downloading daily-21384.cdiff [100%]
Downloading daily-21385.cdiff [100%]
Downloading daily-21386.cdiff [100%]
Downloading daily-21387.cdiff [100%]
Downloading daily-21388.cdiff [100%]
Downloading daily-21389.cdiff [100%]
Downloading daily-21390.cdiff [100%]
Downloading daily-21391.cdiff [100%]
daily.cld updated (version: 21391, sigs: 1850214, f-level: 63, builder: neo)
bytecode.cld is up to date (version: 271, sigs: 47, f-level: 63, builder: anvilleg)
Database updated (4274486 signatures) from (IP:
WARNING: Clamd was NOT notified: Can't connect to clamd through /var/run/clamav/clamd.sock: No such file or directory