X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/b07e6aa3aa6749ab57c214efd155bb29614394eb..5ca6d115da010e279c2f928990b3c8d220378f24:/src/src/malware.c diff --git a/src/src/malware.c b/src/src/malware.c index ca9c3dfeb..9b1bd334d 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/malware.c,v 1.12 2005/08/01 14:41:25 ph10 Exp $ */ +/* $Cambridge: exim/src/src/malware.c,v 1.17 2009/11/05 19:40:51 nm4 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -20,6 +20,10 @@ int mksd_scan_packed(int sock); #define SHUT_WR 1 #endif + +#define MALWARE_TIMEOUT 120 + + #define DRWEBD_SCAN_CMD (1) /* scan file, buffer or diskfile */ #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" */ @@ -135,10 +139,117 @@ int malware(uschar **listptr) { return DEFER; }; + /* "f-protd" scanner type ----------------------------------------------- */ + if (strcmpic(scanner_name, US"f-protd") == 0) { + uschar *fp_options, *fp_scan_option; + uschar fp_scan_option_buffer[1024]; + uschar fp_options_buffer[1024]; + uschar fp_options_default[] = "localhost 10200-10204"; + uschar hostname[256]; + unsigned int port, portlow, porthigh, connect_ok=0, detected=0, par_count = 0; + struct hostent *he; + struct in_addr in; + int sock; + uschar scanrequest[2048], buf[32768], *strhelper, *strhelper2; + + if ((fp_options = string_nextinlist(&av_scanner_work, &sep, + fp_options_buffer, sizeof(fp_options_buffer))) == NULL) { + /* no options supplied, use default options */ + fp_options = fp_options_default; + }; + + /* extract host and port part */ + if ( sscanf(CS fp_options, "%s %u-%u", hostname, &portlow, &porthigh) != 3 ) { + if ( sscanf(CS fp_options, "%s %u", hostname, &portlow) != 2 ) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: f-protd: invalid socket '%s'", fp_options); + return DEFER; + } + porthigh = portlow; + } + + /* Lookup the host */ + if((he = gethostbyname(CS hostname)) == 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: f-protd: failed to lookup host '%s'", hostname); + return DEFER; + } + + in = *(struct in_addr *) he->h_addr_list[0]; + port = portlow; + + + /* Open the f-protd TCP socket */ + if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: f-protd: unable to acquire socket (%s)", + strerror(errno)); + return DEFER; + } + + /* Try to connect to all portslow-high until connection is established */ + for (port = portlow; !connect_ok && port < porthigh; port++) { + if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) >= 0) { + connect_ok = 1; + } + } + + if ( !connect_ok ) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: f-protd: connection to %s, port %u-%u failed (%s)", + inet_ntoa(in), portlow, porthigh, strerror(errno)); + (void)close(sock); + return DEFER; + } + + (void)string_format(scanrequest, 1024, CS"GET %s/scan/%s/%s.eml", + spool_directory, message_id, message_id); + + while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep, + fp_scan_option_buffer, sizeof(fp_scan_option_buffer))) != NULL) { + if ( par_count ) { + Ustrcat(scanrequest, "%20"); + } else { + Ustrcat(scanrequest, "?"); + } + Ustrcat(scanrequest, fp_scan_option); + par_count++; + } + Ustrcat(scanrequest, " HTTP/1.0\r\n\r\n"); + + /* send scan request */ + if (send(sock, &scanrequest, Ustrlen(scanrequest)+1, 0) < 0) { + (void)close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: f-protd: unable to send command to socket (%s)", scanrequest); + return DEFER; + } + + /* We get a lot of empty lines, so we need this hack to check for any data at all */ + while( recv(sock, buf, 1, MSG_PEEK) > 0 ) { + if ( recv_line(sock, buf, 32768) > 0) { + if ( Ustrstr(buf, US"")) ) { + if (strhelper2 = (Ustrstr(buf, US""))) { + *strhelper2 = '\0'; + Ustrcpy(malware_name_buffer, strhelper + 6); + } + } else if ( Ustrstr(buf, US"") ) { + malware_name = malware_name_buffer; + } else { + malware_name = NULL; + } + } + } + } + (void)close(sock); + } /* "drweb" scanner type ----------------------------------------------- */ /* v0.1 - added support for tcp sockets */ /* v0.0 - initial release -- support for unix sockets */ - if (strcmpic(scanner_name,US"drweb") == 0) { + else if (strcmpic(scanner_name,US"drweb") == 0) { uschar *drweb_options; uschar drweb_options_buffer[1024]; uschar drweb_options_default[] = "/usr/local/drweb/run/drwebd.sock"; @@ -557,7 +668,7 @@ int malware(uschar **listptr) { return DEFER; }; - bread = read(sock, av_buffer, sizeof(av_buffer)); + bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT); if (bread >0) av_buffer[bread]='\0'; if (bread < 0) { (void)close(sock); @@ -591,7 +702,7 @@ int malware(uschar **listptr) { i = 0; memset(av_buffer, 0, sizeof(av_buffer)); do { - bread=read(sock, &av_buffer[i], 1); + bread=ip_recv(sock, &av_buffer[i], 1, MALWARE_TIMEOUT); if (bread < 0) { (void)close(sock); log_write(0, LOG_MAIN|LOG_PANIC, @@ -873,7 +984,7 @@ int malware(uschar **listptr) { }; (void)string_format(file_name,1024,"%s/scan/%s/%s_scanner_output", spool_directory, message_id, message_id); - scanner_record = fopen(CS file_name,"wb"); + scanner_record = modefopen(file_name,"wb",SPOOL_MODE); if (scanner_record == NULL) { log_write(0, LOG_MAIN|LOG_PANIC, @@ -976,7 +1087,7 @@ int malware(uschar **listptr) { /* wait for result */ memset(av_buffer, 0, sizeof(av_buffer)); - if ((!(bread = read(sock, av_buffer, sizeof(av_buffer))) > 0)) { + if ((!(bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT)) > 0)) { (void)close(sock); log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: unable to read from sophie UNIX socket (%s)", sophie_options); @@ -1098,7 +1209,7 @@ int malware(uschar **listptr) { return DEFER; } memset(av_buffer2, 0, sizeof(av_buffer2)); - bread = read(sock, av_buffer2, sizeof(av_buffer2)); + bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), MALWARE_TIMEOUT); if (bread < 0) { log_write(0, LOG_MAIN|LOG_PANIC, @@ -1238,7 +1349,7 @@ int malware(uschar **listptr) { /* Read the result */ memset(av_buffer, 0, sizeof(av_buffer)); - bread = read(sock, av_buffer, sizeof(av_buffer)); + bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT); (void)close(sock); if (!(bread > 0)) { @@ -1265,6 +1376,10 @@ int malware(uschar **listptr) { return DEFER; } + /* strip newline at the end */ + p = av_buffer + Ustrlen(av_buffer) - 1; + if( *p == '\n' ) *p = '\0'; + /* colon in returned output? */ if((p = Ustrrchr(av_buffer,':')) == NULL) { log_write(0, LOG_MAIN|LOG_PANIC, @@ -1273,13 +1388,10 @@ int malware(uschar **listptr) { return DEFER; } - /* strip filename strip CR at the end */ + /* strip filename */ ++p; while (*p == ' ') ++p; vname = p; - p = vname + Ustrlen(vname) - 1; - if( *p == '\n' ) *p = '\0'; - if ((p = Ustrstr(vname, "FOUND"))!=NULL) { *p=0; for (--p;p>vname && *p<=32;p--) *p=0;