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.