summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Kistner <tom@duncanthrax.net>2005-01-05 13:33:58 +0000
committerTom Kistner <tom@duncanthrax.net>2005-01-05 13:33:58 +0000
commit2376f2f55f7f8e1df38b44908b6d39181a88a65e (patch)
tree573268174c9be0e0a2d6d15c6f7c5148aa33a30c
parent533244aff041c5fd9d193947f533a4c0150a9c9e (diff)
Added patches for remote clamd operation and improved drwebd error handling. Contributed by Alex Miller
-rw-r--r--src/src/malware.c163
1 files changed, 161 insertions, 2 deletions
diff --git a/src/src/malware.c b/src/src/malware.c
index 82111557c..b9a641c94 100644
--- a/src/src/malware.c
+++ b/src/src/malware.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/malware.c,v 1.3 2004/12/17 14:52:44 ph10 Exp $ */
+/* $Cambridge: exim/src/src/malware.c,v 1.4 2005/01/05 13:33:58 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -24,6 +24,11 @@ int mksd_scan_packed(int sock);
#define DRWEBD_RETURN_VIRUSES (1<<0) /* ask daemon return to us viruses names from report */
#define DRWEBD_IS_MAIL (1<<19) /* say to daemon that format is "archive MAIL" */
+#define DERR_READ_ERR (1<<0) /* read error */
+#define DERR_NOMEMORY (1<<2) /* no memory */
+#define DERR_TIMEOUT (1<<9) /* scan timeout has run out */
+#define DERR_BAD_CALL (1<<15) /* wrong command */
+
/* Routine to check whether a system is big- or litte-endian.
Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html
Needed for proper kavdaemon implementation. Sigh. */
@@ -197,6 +202,7 @@ int malware(uschar **listptr) {
/* calc file size */
drweb_fd = open(CS scanrequest, O_RDONLY);
if (drweb_fd == -1) {
+ close(sock);
log_write(0, LOG_MAIN|LOG_PANIC,
"malware acl condition: drweb: can't open spool file %s: %s",
scanrequest, strerror(errno));
@@ -204,6 +210,8 @@ int malware(uschar **listptr) {
}
fsize = lseek(drweb_fd, 0, SEEK_END);
if (fsize == -1) {
+ close(sock);
+ close(drweb_fd);
log_write(0, LOG_MAIN|LOG_PANIC,
"malware acl condition: drweb: can't seek spool file %s: %s",
scanrequest, strerror(errno));
@@ -238,21 +246,23 @@ int malware(uschar **listptr) {
if (result == -1) {
close(sock);
close(drweb_fd);
+ free(drweb_fbuf);
log_write(0, LOG_MAIN|LOG_PANIC,
"malware acl condition: drweb: can't read spool file %s: %s",
scanrequest, strerror(errno));
return DEFER;
}
+ close(drweb_fd);
/* send file body to socket */
if (send(sock, drweb_fbuf, fsize, 0) < 0) {
close(sock);
+ free(drweb_fbuf);
log_write(0, LOG_MAIN|LOG_PANIC,
"malware acl condition: drweb: unable to send file body to socket (%s)", drweb_options);
return DEFER;
}
close(drweb_fd);
- free(drweb_fbuf);
}
else {
/* open the drwebd UNIX socket */
@@ -367,6 +377,22 @@ int malware(uschar **listptr) {
}
}
else {
+ char *drweb_s = NULL;
+
+ if (drweb_rc & DERR_READ_ERR) drweb_s = "read error";
+ if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory";
+ if (drweb_rc & DERR_TIMEOUT) drweb_s = "timeout";
+ if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command";
+ /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED.
+ * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM,
+ * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR
+ * and others are ignored */
+ if (drweb_s) {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "malware acl condition: drweb: drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s);
+ close(sock);
+ return DEFER;
+ }
/* no virus found */
malware_name = NULL;
};
@@ -956,6 +982,14 @@ int malware(uschar **listptr) {
uschar hostname[256];
struct hostent *he;
struct in_addr in;
+ uschar *clamd_options2;
+ uschar clamd_options2_buffer[1024];
+ uschar clamd_options2_default[] = "";
+ uschar av_buffer2[1024];
+ uschar *clamav_fbuf;
+ uschar scanrequest[1024];
+ int sockData, clam_fd, result;
+ unsigned int fsize;
if ((clamd_options = string_nextinlist(&av_scanner_work, &sep,
clamd_options_buffer,
@@ -963,6 +997,11 @@ int malware(uschar **listptr) {
/* no options supplied, use default options */
clamd_options = clamd_options_default;
}
+ if ((clamd_options2 = string_nextinlist(&av_scanner_work, &sep,
+ clamd_options2_buffer,
+ sizeof(clamd_options2_buffer))) == NULL) {
+ clamd_options2 = clamd_options2_default;
+ }
/* socket does not start with '/' -> network socket */
if (*clamd_options != '/') {
@@ -998,6 +1037,126 @@ int malware(uschar **listptr) {
inet_ntoa(in), port, strerror(errno));
return DEFER;
}
+
+ if (strcmpic(clamd_options2,US"local") == 0) {
+
+ /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
+
+ snprintf(CS file_name,1024,"SCAN %s/scan/%s\n", spool_directory, message_id);
+
+ if (send(sock, file_name, Ustrlen(file_name), 0) < 0) {
+ close(sock);
+ log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)",
+ strerror(errno));
+ return DEFER;
+ }
+ } else {
+
+ /* Pass the string to ClamAV (7 = "STREAM\n") */
+
+ if (send(sock, "STREAM\n", 7, 0) < 0) {
+ close(sock);
+ log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)",
+ strerror(errno));
+ return DEFER;
+ }
+ memset(av_buffer2, 0, sizeof(av_buffer2));
+ bread = read(sock, av_buffer2, sizeof(av_buffer2));
+
+ if (bread < 0) {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "malware acl condition: clamd: unable to read PORT from socket (%s)",
+ strerror(errno));
+ return DEFER;
+ }
+
+ if (bread == sizeof(av_buffer)) {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "malware acl condition: clamd: buffer too small");
+ return DEFER;
+ }
+
+ if (!(*av_buffer2)) {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "malware acl condition: clamd: ClamAV returned null");
+ return DEFER;
+ }
+
+ av_buffer2[bread] = '\0';
+ if( sscanf(CS av_buffer2, "PORT %hu\n", &port) != 1 ) {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "malware acl condition: clamd: Expected port information from clamd, got '%s'", av_buffer2);
+ return DEFER;
+ };
+
+ if ( (sockData = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "malware acl condition: clamd: unable to acquire socket (%s)",
+ strerror(errno));
+ return DEFER;
+ }
+
+ if (ip_connect(sockData, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
+ close(sockData);
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "malware acl condition: clamd: connection to %s, port %u failed (%s)",
+ inet_ntoa(in), port, strerror(errno));
+ return DEFER;
+ }
+
+ snprintf(CS scanrequest, 1024,CS"%s/scan/%s/%s.eml",
+ spool_directory, message_id, message_id);
+
+ /* calc file size */
+ clam_fd = open(CS scanrequest, O_RDONLY);
+ if (clam_fd == -1) {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "malware acl condition: clamd: can't open spool file %s: %s",
+ scanrequest, strerror(errno));
+ return DEFER;
+ }
+ fsize = lseek(clam_fd, 0, SEEK_END);
+ if (fsize == -1) {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "malware acl condition: clamd: can't seek spool file %s: %s",
+ scanrequest, strerror(errno));
+ return DEFER;
+ }
+ lseek(clam_fd, 0, SEEK_SET);
+
+ clamav_fbuf = (uschar *) malloc (fsize);
+ if (!clamav_fbuf) {
+ close(sockData);
+ close(clam_fd);
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "malware acl condition: clamd: unable to allocate memory %u for file (%s)",
+ fsize, scanrequest);
+ return DEFER;
+ }
+
+ result = read (clam_fd, clamav_fbuf, fsize);
+ if (result == -1) {
+ close(sockData);
+ close(clam_fd);
+ free(clamav_fbuf);
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "malware acl condition: clamd: can't read spool file %s: %s",
+ scanrequest, strerror(errno));
+ return DEFER;
+ }
+ close(clam_fd);
+
+ /* send file body to socket */
+ if (send(sockData, clamav_fbuf, fsize, 0) < 0) {
+ close(sockData);
+ free(clamav_fbuf);
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "malware acl condition: clamd: unable to send file body to socket (%s:%u)", hostname, port);
+ return DEFER;
+ }
+ free(clamav_fbuf);
+ close(sockData);
+ }
}
else {
/* open the local socket */