summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/clamsmtpd.821
-rw-r--r--src/clamsmtpd.c74
3 files changed, 85 insertions, 14 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index c8efa41..28671aa 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,3 +6,7 @@ clamsmtpd_SOURCES = clamsmtpd.c clamsmtpd.h util.c util.h sock_any.h sock_any.c
man_MANS = clamsmtpd.8
EXTRA_DIST = $(man_MANS)
+
+all-local:
+ @echo "NOTE: Ignore any warnings about mktemp(). It's used safely in this case."
+ @echo \ No newline at end of file
diff --git a/src/clamsmtpd.8 b/src/clamsmtpd.8
index 3ded807..9594624 100644
--- a/src/clamsmtpd.8
+++ b/src/clamsmtpd.8
@@ -42,6 +42,7 @@
.Nd an SMTP server for scanning viruses via clamd
.Sh SYNOPSIS
.Nm
+.Op Fl bq
.Op Fl c Ar clamaddr
.Op Fl d Ar level
.Op Fl D Ar tmpdir
@@ -58,8 +59,8 @@ is an SMTP filter that allows you to check for viruses using the ClamAV
anti-virus software. It accepts SMTP connections and forwards the SMTP commands
and responses to another SMTP server.
.Pp
-The DATA email body is intercepted and scanned before forwarding. Email with
-viruses are rejected and logged without any additional action taken.
+The DATA email body is intercepted and scanned before forwarding. By default email
+with viruses are dropped silently and logged without any additional action taken.
.Pp
.Nm
aims to be lightweight and simple rather than have a myriad of options. Your
@@ -125,6 +126,12 @@ to write a file with the daemon's process id, which can be used to stop the
daemon.
.Ar pidfile
is the location of the file.
+.It Fl q
+Quarantine files that contain viruses by leaving them in the
+.Ar tmpdir
+directory. The file names look like this (where X is a random
+character or number):
+.Pa virus.XXXXXX
.It Fl t
.Ar timeout
is the number of seconds to wait while reading data from network connections.
@@ -145,12 +152,14 @@ option.
In some cases it's advantagous to consolidate the virus scanning and filtering
for several mail servers on one machine.
.Nm
-allows this by providing a loopback feature to connect back to the IP that a
-SMTP connection comes from. If only a port is specified for the
+allows this by providing a loopback feature to connect back to the IP that an
+SMTP connection comes in from.
+.Pp
+To use this feature specify only a port number (no IP address) for the
.Ar serveraddr
-(without IP) then
+in which case
.Nm
-passes the email to the incoming peer's IP address on the said port.
+will pass the email back to the said port on the incoming IP address.
.Pp
Make sure the
.Ar maxconn
diff --git a/src/clamsmtpd.c b/src/clamsmtpd.c
index b3decb0..b66366c 100644
--- a/src/clamsmtpd.c
+++ b/src/clamsmtpd.c
@@ -142,8 +142,9 @@ const char* g_clamname = DEFAULT_CLAMAV;
const char* g_header = DEFAULT_HEADER; /* The header to add to email */
const char* g_directory = _PATH_TMP; /* The directory for temp files */
-unsigned int g_unique_id = 0x00001000; /* For connection ids */
+unsigned int g_unique_id = 0x00100000; /* For connection ids */
int g_bounce = 0; /* Send back a reject line */
+int g_quarantine = 0; /* Leave virus files in temp dir */
/* For main loop and signal handlers */
int g_quit = 0;
@@ -167,6 +168,7 @@ static int connect_clam(clamsmtp_context_t* ctx);
static int disconnect_clam(clamsmtp_context_t* ctx);
static void add_to_logline(char* logline, char* prefix, char* line);
static int avcheck_data(clamsmtp_context_t* ctx, char* logline);
+static int quarantine_virus(clamsmtp_context_t* ctx, char* tempname);
static int complete_data_transfer(clamsmtp_context_t* ctx, const char* tempname);
static int transfer_to_file(clamsmtp_context_t* ctx, char* tempname);
static int transfer_from_file(clamsmtp_context_t* ctx, const char* filename);
@@ -191,7 +193,7 @@ int main(int argc, char* argv[])
char* t;
/* Parse the arguments nicely */
- while((ch = getopt(argc, argv, "bc:d:D:h:l:m:p:t:")) != -1)
+ while((ch = getopt(argc, argv, "bc:d:D:h:l:m:p:qt:")) != -1)
{
switch(ch)
{
@@ -251,6 +253,11 @@ int main(int argc, char* argv[])
errx(1, "invalid timeout: %s", optarg);
break;
+ /* Leave virus files in directory */
+ case 'q':
+ g_quarantine = 1;
+ break;
+
/* Usage information */
case '?':
default:
@@ -460,7 +467,7 @@ static void on_quit(int signal)
static int usage()
{
- fprintf(stderr, "clamsmtpd [-b] [-c clamaddr] [-d debuglevel] [-D tmpdir] [-h header] "
+ fprintf(stderr, "clamsmtpd [-bq] [-c clamaddr] [-d debuglevel] [-D tmpdir] [-h header] "
"[-l listenaddr] [-m maxconn] [-p pidfile] [-t timeout] serveraddr\n");
exit(2);
}
@@ -602,7 +609,6 @@ cleanup:
static int smtp_passthru(clamsmtp_context_t* ctx)
{
char logline[LINE_LENGTH];
- int processing = 0;
int r, ret = 0;
int first_rsp = 1;
fd_set mask;
@@ -759,10 +765,7 @@ static int smtp_passthru(clamsmtp_context_t* ctx)
cleanup:
if(ret == -1 && ctx->client != -1)
- {
- write_data(ctx, &(ctx->client),
- processing ? SMTP_FAILED : SMTP_STARTFAILED);
- }
+ write_data(ctx, &(ctx->client), SMTP_FAILED);
return ret;
}
@@ -964,6 +967,9 @@ static int avcheck_data(clamsmtp_context_t* ctx, char* logline)
if(write_data(ctx, &(ctx->client),
g_bounce ? SMTP_DATAVIRUS : SMTP_DATAVIRUSOK) == -1)
RETURN(-1);
+
+ /* Any special post operation actions on the virus */
+ quarantine_virus(ctx, buf);
break;
default:
@@ -1022,6 +1028,58 @@ static int complete_data_transfer(clamsmtp_context_t* ctx, const char* tempname)
return 0;
}
+static int quarantine_virus(clamsmtp_context_t* ctx, char* tempname)
+{
+ char buf[MAXPATHLEN];
+ char* t;
+
+ if(!g_quarantine)
+ return 0;
+
+ strlcpy(buf, g_directory, MAXPATHLEN);
+ strlcat(buf, "/virus.", MAXPATHLEN);
+
+ /* Points to null terminator */
+ t = buf + strlen(buf);
+
+ /*
+ * Yes, I know we're using mktemp. And yet we're doing it in
+ * a safe manner due to the link command below not overwriting
+ * existing files.
+ */
+ for(;;)
+ {
+ /* Null terminate off the ending, and replace with X's for mktemp */
+ *t = 0;
+ strlcat(buf, "XXXXXX", MAXPATHLEN);
+
+ if(!mktemp(buf))
+ {
+ message(ctx, LOG_ERR, "couldn't create quarantine file name");
+ return -1;
+ }
+
+ /* Try to link the file over to the temp */
+ if(link(tempname, buf) == -1)
+ {
+ /* We don't want to allow race conditions */
+ if(errno == EEXIST)
+ {
+ message(ctx, LOG_WARNING, "race condition when quarantining virus file: %s", buf);
+ continue;
+ }
+
+ message(ctx, LOG_ERR, "couldn't quarantine virus file");
+ return -1;
+ }
+
+ break;
+ }
+
+ messagex(ctx, LOG_INFO, "quarantined virus file as: %s", buf);
+ return 0;
+}
+
static int transfer_to_file(clamsmtp_context_t* ctx, char* tempname)
{
/* If there aren't any lines in the message and just an