Making ClamAV and Kmail Work Together
A Simple Hack for Older Versions of Kmail
by William Keeley
Even though viruses and malware are almost completely ineffective against Linux, I wanted
to implement an antivirus solution in case any email might be forwarded to Windows users. My version
of kmail is 3.2.0. Newer versions do have the ability to plug in virus protection. Even
though this is the case, I do not want to take the time to download and install the
latest version of KDE due to the fact that only dialup is available in my area. While
there are other hacks on the Net, these have several dependencies which again, I do not
want to take the time to meet. I needed something quick and dirty, so I hacked together
my own program.
Keep in mind that this program is a hack, and it works perfectly for me. However, it
not work perfectly for you (although I cannot see why not). I'm not claiming that
this code is better than or as good as anyone else's code. I only offer it in the hopes
that someone somewhere will find it useful. You must accept all responsibility for anything
that results from running this code. This code is licenced under the GPL.
What my program does is insert a header into the incoming message. The value of this
header is determined by the results of clamav's scan of the incoming message. If the
incoming message contains detected malware, the header
X-Clamscan-Status: Infection Present
is inserted into the incoming message.
If there is no malware detected, then the header
X-Clamscan-Status: No Infection
is inserted.
The program works by taking advantage of kmail's filtering feature which allows piping
an incoming message through external programs. Another feature of kmail's filtering
allows further handling of incoming messages based on the contents of the incoming
message's headers, body, size, message date, etc. With simply two filters set, a user
can scan incoming messages for malware and isolate infected messages in a separate kmail
folder. I am writing these instruction using kmail version 3.2.0. Other versions of
kmail may be different. After listing general instructions, I will provide a setup example
based on my home computer's configuration.
To set up the "Infected" folder:
1. Open Kmail.
2. Click on the Folder menu item.
3. From the drop down menu, select New Folder...
4. Name it "Infected".
5. Click OK.
To download, compile, and install kmailscan:
1. Download the code from here and save it to your home directory. The code below is
for example only.
2. Edit the code so that it has the correct location of the clamscan program. The part that
needs editing is colored green.
3. If your email system uses a different line terminating characher enter the character's ACSII code
in the area that is colored red.
4. If you want to change the line number where the header appears, change the blue
colored number.
5. From a console or xterm window, type in gcc -o kmailscan kmailscan.c
//Begin Code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef CLAMPATH
#define CLAMPATH "/usr/local/bin/clamscan"
#endif
#ifndef LINENUMBERFORHEADER
#define LINENUMBERFORHEADER 14
#endif
#ifndef ENDOFLINECHARACTER
#define ENDOFLINECHARACTER 10
#endif
int main()
{
int fd; //file descriptor of temporay file where email is dumped and scanned
int cmd; //Value that is returned by clamscan. If 0 there is no detected infection
int ctr; //Used by program to count line numbers in the email
char buff[2]; //used to input and output information to kmail and files
char tmpfile[100]; //Name of a temporary file where email is dumped and scanned
char clampath[255]; //Full path to the clamscan command
char command[365]; //Full name with paramerters and name of temporary file to scan
sprintf(clampath, "%s", CLAMPATH); //Get full path to clamscan command
sprintf(tmpfile, "/tmp/kmailscan%d-%d", getuid(), getpid()); //make up name for temporary file
sprintf(command, "%s --quiet %s", clampath, tmpfile); // create command for scanning temporary file
fd=open(tmpfile, O_EXCL | O_CREAT | O_WRONLY, S_IWUSR | S_IRUSR); // create temporary file
if(fd<0) return -1; //If we could create temp file no need to continue. exit to prevent bollixing of message
ctr=0; //Set the line counter to 0
while(read(0, buff, 1)>0) //Read file from pipe and store to temprary file
{
write(fd, buff, 1);
}
close(fd); //Close temp file. Will open later to send to stdout
cmd=system(command); // Scan file with clamav and retrieve status of scan
fd=open(tmpfile, O_RDONLY); //Reopen file for output to stdout
while(read(fd, buff, 1)>0) //Read file while there is bytes available
{
write(1, buff, 1); //write byte to stdout
if(buff[0]==ENDOFLINECHARACTER && ctr<LINENUMBERFORHEADER) ctr++; // Check for end of line and count if less than
// header location
if(ctr==LINENUMBERFORHEADER) //If this is where the new header goes, insert it
{
if (cmd==0) write(1, "X-Clamscan-Status: No Infection ", 32); //Write this if no infection detected
else write(1, "X-Clamscan-Status: Infection Present ", 37); //Write this if infection or other problem
buff[0]=ENDOFLINECHARACTER; //set variable to end of line character
write(1, buff, 1); //write the end of line character
ctr++; //Increase the count so that it is greater than header location
}
}
close(fd); // Finished with reading file so close it
unlink(tmpfile); //Finished with file altogether so get rid of it
return 0; // Return 0 to kamil so that kmail will use output of this program intead of original
}
//End Code
To set up the first filter:
1. On The Kmail main screen, click on the Settings menu item.
2. On the drop down menu, click on Configure Filters.
3. In the resulting window, Click on the New button. The button has an icon that looks
like a sheet of paper with the upper right corner folded.
4. Click in the circle next to Match all of the Following...
5. In the first drop down box under Match all of the Following..., select
<size in bytes>.
6. In the select box to the immediate right, select is greater than.
7. In the edit box to the right of the select box type in 0.
8. In the drop down box under Filter action, select pipe through.
9. In the box to the right of that, browse to where the compiled kmailscan program is and select it.
10. Make sure that the boxes for to incoming messages, on manual filtering, and
Add this filter to the Apply Filter Action menu are marked.
11. Make sure there is NO mark next to If this filter matches, stop processing here.
12. Click the Apply button.
13. Click the OK button.
To set up the second filter:
1. On The Kmail main screen, click on the Settings menu item.
2. On the drop down menu, click on Configure Filters.
3. In the resulting window, Click on the New button. The button has an icon that looks
like a sheet of paper with the upper right corner folded.
4. Click in the circle next to Match all of the Following...
5. In the first drop down box under Match all of the Following..., select
<any header>.
6. In the select box to the immediate right, select contains.
7. In the edit box to the right of the select box type in Infection Present.
8. In the drop down box under Filter action, select file into folder.
9. In the box to the right of that, select infected.
10. Make sure that the boxes for to incoming messages, on manual filtering, and
If this filter matches, stop processing here are marked.
11. Click the Apply button.
12. Click the OK button.