[Exim] Re: Exiscan Patch - multiple spamd servers and/or vir… |
Wiadomość jest częścią wątku: | |
---|---|
pełne drzewo wątku posortowane wg daty | |
Dagfinn Ilmari Mannsåker at | |
diff -ur exim-4.34/src/malware.c exiscan-4.34-22/src/malware.c --- exim-4.34/src/malware.c 2004-06-19 01:45:36.000000000 +0200 +++ exiscan-4.34-22/src/malware.c 2004-06-19 02:00:42.000000000 +0200 @@ -24,16 +24,16 @@ #define DRWEBD_SCAN_CMD 0x0001 #define DRWEBD_RETURN_VIRUSES 0x0001
-/* Routine to check whether a system is big- or litte-endian. +/* 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. */ #define BIG_MY_ENDIAN 0 #define LITTLE_MY_ENDIAN 1 int test_byte_order(void); int test_byte_order() { - short int word = 0x0001; - char *byte = (char *) &word; - return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN); + short int word = 0x0001; + char *byte = (char *) &word; + return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN); }
uschar malware_name_buffer[256]; @@ -61,35 +61,35 @@ int roffset; const pcre *re; const uschar *rerror; - + /* make sure the eml mbox file is spooled up */ mbox_file = spool_mbox(&mbox_size); if (mbox_file == NULL) { /* error while spooling */ log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: error while creating mbox spool file"); - return DEFER; + "malware acl condition: error while creating mbox spool file"); + return DEFER; }; /* none of our current scanners need the mbox file as a stream, so we can close it right away */ fclose(mbox_file); - + /* extract the malware regex to match against from the option list */ if ((malware_regex = string_nextinlist(&list, &sep, malware_regex_buffer, sizeof(malware_regex_buffer))) != NULL) { - + /* parse 1st option */ - if ( (strcmpic(malware_regex,US"false") == 0) || - (Ustrcmp(malware_regex,"0") == 0) ) { + if ((strcmpic(malware_regex, US "false") == 0) || + (Ustrcmp(malware_regex, "0") == 0)) { /* explicitly no matching */ return FAIL; }; - + /* special cases (match anything except empty) */ - if ( (strcmpic(malware_regex,US"true") == 0) || - (Ustrcmp(malware_regex,"*") == 0) || - (Ustrcmp(malware_regex,"1") == 0) ) { + if ((strcmpic(malware_regex, US "true") == 0) || + (Ustrcmp(malware_regex, "*") == 0) || + (Ustrcmp(malware_regex, "1") == 0)) { malware_regex = malware_regex_default; }; } @@ -99,10 +99,14 @@ };
/* compile the regex, see if it works */ - re = pcre_compile(CS malware_regex, PCRE_COPT, (const char **)&rerror, &roffset, NULL); + re = pcre_compile(CS malware_regex, + PCRE_COPT, + (const char **)&rerror, + &roffset, NULL); if (re == NULL) { log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: regular expression error in '%s': %s at offset %d", malware_regex, rerror, roffset); + "malware acl condition: regular expression error in '%s': %s at offset %d", + malware_regex, rerror, roffset); return DEFER; };
@@ -122,6 +126,7 @@ if (rc != OK) return rc; } + /* "kavdaemon" scanner type ------------------------------------------------ */ else if (strcmpic(scanner_name, US "kavdaemon") == 0) { rc = scan_kavdaemon(&av_scanner_work, &sep); @@ -164,15 +169,15 @@ return DEFER; } n++; - } + };
if (malware_name == NULL && n == 0) { /* no scanner given */ log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: av_scanner configuration variable is empty"); + "malware acl condition: av_scanner configuration variable is empty"); return DEFER; }; - + /* set "been here, done that" marker */ malware_ok = 1; }; @@ -187,884 +192,901 @@ }; }
- /* "drweb" scanner type ----------------------------------------------- */ - /* v0.1 - added support for tcp sockets */ - /* v0.0 - initial release -- support for unix sockets */ -static int scan_drweb(uschar ** pscanner, int *psep) -{ - uschar *drweb_options; - uschar drweb_options_buffer[1024]; - uschar drweb_options_default[] = "/usr/local/drweb/run/drwebd.sock"; - struct sockaddr_un server; - int sock, port, result, ovector[30]; - unsigned int fsize; - uschar tmpbuf[1024], *drweb_fbuf; - uschar scanrequest[1024]; - uschar drweb_match_string[128]; - int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd, - drweb_vnum, drweb_slen, drweb_fin = 0x0000; - unsigned long bread; - uschar hostname[256]; - struct hostent *he; - struct in_addr in; - pcre *drweb_re; - int roffset; - uschar *rerror; - - if ((drweb_options = string_nextinlist(pscanner, psep, - drweb_options_buffer, sizeof(drweb_options_buffer))) == NULL) { - /* no options supplied, use default options */ - drweb_options = drweb_options_default; - }; - - if (*drweb_options != '/') { - - /* extract host and port part */ - if( sscanf(CS drweb_options, "%s %u", hostname, &port) != 2 ) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: invalid socket '%s'", drweb_options); - return DEFER; - } - - /* Lookup the host */ - if((he = gethostbyname(CS hostname)) == 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: failed to lookup host '%s'", hostname); - return DEFER; - } - - in = *(struct in_addr *) he->h_addr_list[0]; - - /* Open the drwebd TCP socket */ - if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to acquire socket (%s)", - strerror(errno)); - return DEFER; - } - - if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: connection to %s, port %u failed (%s)", - inet_ntoa(in), port, strerror(errno)); - return DEFER; - } - - /* prepare variables */ - drweb_cmd = htonl(DRWEBD_SCAN_CMD); - drweb_flags = htonl(DRWEBD_RETURN_VIRUSES); - snprintf(CS scanrequest, 1024,CS"%s/scan/%s/%s.eml", - spool_directory, message_id, message_id); - - /* calc file size */ - drweb_fd = open(CS scanrequest, O_RDONLY); - if (drweb_fd == -1) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: can't open spool file %s: %s", - scanrequest, strerror(errno)); - return DEFER; - } - fsize = lseek(drweb_fd, 0, SEEK_END); - if (fsize == -1) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: can't seek spool file %s: %s", - scanrequest, strerror(errno)); - return DEFER; - } - drweb_slen = htonl(fsize); - lseek(drweb_fd, 0, SEEK_SET); - - /* send scan request */ - if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) || - (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) || - (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) || - (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0)) { - close(sock); - close(drweb_fd); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to send commands to socket (%s)", drweb_options); - return DEFER; - } - - drweb_fbuf = (uschar *) malloc (fsize); - if (!drweb_fbuf) { - close(sock); - close(drweb_fd); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to allocate memory %u for file (%s)", - fsize, scanrequest); - return DEFER; - } - - result = read (drweb_fd, drweb_fbuf, fsize); - if (result == -1) { - close(sock); - close(drweb_fd); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: can't read spool file %s: %s", - scanrequest, strerror(errno)); - return DEFER; - } - - /* send file body to socket */ - if (send(sock, drweb_fbuf, fsize, 0) < 0) { - close(sock); - 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 */ - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: can't open UNIX socket"); - return DEFER; - } - server.sun_family = AF_UNIX; - Ustrcpy(server.sun_path, drweb_options); - if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to connect to socket (%s). errno=%d", drweb_options, errno); - return DEFER; - } - - /* prepare variables */ - drweb_cmd = htonl(DRWEBD_SCAN_CMD); - drweb_flags = htonl(DRWEBD_RETURN_VIRUSES); - snprintf(CS scanrequest, 1024,CS"%s/scan/%s/%s.eml", spool_directory, message_id, message_id); - drweb_slen = htonl(Ustrlen(scanrequest)); - - /* send scan request */ - if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) || - (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) || - (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) || - (send(sock, scanrequest, Ustrlen(scanrequest), 0) < 0) || - (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0)) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to send commands to socket (%s)", drweb_options); - return DEFER; - } - } - - /* wait for result */ - if ((bread = recv(sock, &drweb_rc, sizeof(drweb_rc), 0) != sizeof(drweb_rc))) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to read return code"); - return DEFER; - } - drweb_rc = ntohl(drweb_rc); - - if ((bread = recv(sock, &drweb_vnum, sizeof(drweb_vnum), 0) != sizeof(drweb_vnum))) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: unable to read the number of viruses"); - return DEFER; - } - drweb_vnum = ntohl(drweb_vnum); - - /* "virus(es) found" if virus number is > 0 */ - if (drweb_vnum) - { - int i; - uschar pre_malware_nb[256]; - - malware_name = malware_name_buffer; - - /* setup default virus name */ - Ustrcpy(malware_name_buffer,"unknown"); - - /* read and concatenate virus names into one string */ - for (i=0;i<drweb_vnum;i++) - { - /* read the size of report */ - if ((bread = recv(sock, &drweb_slen, sizeof(drweb_slen), 0) != sizeof(drweb_slen))) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: cannot read report size"); - return DEFER; - }; - drweb_slen = ntohl(drweb_slen); - - /* read report body */ - if ((bread = recv(sock, tmpbuf, drweb_slen, 0)) != drweb_slen) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: drweb: cannot read report string"); - return DEFER; - }; - tmpbuf[drweb_slen] = '\0'; - - /* set up match regex, depends on retcode */ - Ustrcpy(drweb_match_string, "infected\\swith\\s*(.+?)$"); - - drweb_re = pcre_compile( CS drweb_match_string, - PCRE_COPT, - (const char **)&rerror, - &roffset, - NULL ); - - /* try matcher on the line, grab substring */ - result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0, ovector, 30); - if (result >= 2) { - pcre_copy_substring(CS tmpbuf, ovector, result, 1, CS pre_malware_nb, 255); - } - /* the first name we just copy to malware_name */ - if (i==0) - Ustrcpy(CS malware_name_buffer, CS pre_malware_nb); - else { - /* concatenate each new virus name to previous */ - int slen = Ustrlen(malware_name_buffer); - if (slen < (slen+Ustrlen(pre_malware_nb))) { - Ustrcat(malware_name_buffer, "/"); - Ustrcat(malware_name_buffer, pre_malware_nb); - } - } - } - } - else { - /* no virus found */ - malware_name = NULL; - }; - close(sock); - return OK; -} - - /* "kavdaemon" scanner type ------------------------------------------------ */ -static int scan_kavdaemon(uschar ** pscanner, int *psep) -{ - uschar *kav_options; - uschar kav_options_buffer[1024]; - uschar kav_options_default[] = "/var/run/AvpCtl"; - struct sockaddr_un server; - int sock; - time_t t; - uschar tmpbuf[1024]; - uschar scanrequest[1024]; - uschar kav_match_string[128]; - int kav_rc; - unsigned long kav_reportlen, bread; - pcre *kav_re; - int roffset; - uschar *rerror; - - if ((kav_options = string_nextinlist(pscanner, psep, - kav_options_buffer, - sizeof(kav_options_buffer))) == NULL) { - /* no options supplied, use default options */ - kav_options = kav_options_default; - }; - - /* open the kavdaemon socket */ - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: can't open UNIX socket."); - return DEFER; - } - server.sun_family = AF_UNIX; - Ustrcpy(server.sun_path, kav_options); - if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to connect to kavdaemon UNIX socket (%s). errno=%d", kav_options, errno); - return DEFER; - } - - /* get current date and time, build scan request */ - time(&t); - strftime(CS tmpbuf, sizeof(tmpbuf), "<0>%d %b %H:%M:%S:%%s/scan/%%s", localtime(&t)); - snprintf(CS scanrequest, 1024,CS tmpbuf, spool_directory, message_id); - - /* send scan request */ - if (send(sock, scanrequest, Ustrlen(scanrequest)+1, 0) < 0) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to write to kavdaemon UNIX socket (%s)", kav_options); - return DEFER; - } - - /* wait for result */ - if ((bread = recv(sock, tmpbuf, 2, 0) != 2)) { +/* "drweb" scanner type ----------------------------------------------- */ +/* v0.1 - added support for tcp sockets */ +/* v0.0 - initial release -- support for unix sockets */ +static int scan_drweb(uschar ** pscanner, int *psep) { + uschar *drweb_options; + uschar drweb_options_buffer[1024]; + uschar drweb_options_default[] = "/usr/local/drweb/run/drwebd.sock"; + struct sockaddr_un server; + int sock, port, result, ovector[30]; + unsigned int fsize; + uschar tmpbuf[1024], *drweb_fbuf; + uschar scanrequest[1024]; + uschar drweb_match_string[128]; + int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd, + drweb_vnum, drweb_slen, drweb_fin = 0x0000; + unsigned long bread; + uschar hostname[256]; + struct hostent *he; + struct in_addr in; + pcre *drweb_re; + int roffset; + uschar *rerror; + + if ((drweb_options = string_nextinlist(pscanner, psep, + drweb_options_buffer, + sizeof(drweb_options_buffer))) == NULL) { + /* no options supplied, use default options */ + drweb_options = drweb_options_default; + }; + + if (*drweb_options != '/') { + + /* extract host and port part */ + if (sscanf(CS drweb_options, "%s %u", hostname, &port) != 2) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: invalid socket '%s'", drweb_options); + return DEFER; + }; + + /* Lookup the host */ + if ((he = gethostbyname(CS hostname)) == 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: failed to lookup host '%s'", hostname); + return DEFER; + }; + + in = *(struct in_addr *) he->h_addr_list[0]; + + /* Open the drwebd TCP socket */ + if ((sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: unable to acquire socket (%s)", + strerror(errno)); + return DEFER; + }; + + if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: connection to %s, port %u failed (%s)", + inet_ntoa(in), port, strerror(errno)); + return DEFER; + }; + + /* prepare variables */ + drweb_cmd = htonl(DRWEBD_SCAN_CMD); + drweb_flags = htonl(DRWEBD_RETURN_VIRUSES); + snprintf(CS scanrequest, 1024, CS "%s/scan/%s/%s.eml", + spool_directory, message_id, message_id); + + /* calc file size */ + drweb_fd = open(CS scanrequest, O_RDONLY); + if (drweb_fd == -1) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: can't open spool file %s: %s", + scanrequest, strerror(errno)); + return DEFER; + }; + fsize = lseek(drweb_fd, 0, SEEK_END); + if (fsize == -1) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: can't seek spool file %s: %s", + scanrequest, strerror(errno)); + return DEFER; + }; + drweb_slen = htonl(fsize); + lseek(drweb_fd, 0, SEEK_SET); + + /* send scan request */ + if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) || + (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) || + (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) || + (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0)) { + close(sock); + close(drweb_fd); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: unable to send commands to socket (%s)", + drweb_options); + return DEFER; + }; + + drweb_fbuf = (uschar *) malloc (fsize); + if (!drweb_fbuf) { + close(sock); + close(drweb_fd); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: unable to allocate memory %u for file (%s)", + fsize, scanrequest); + return DEFER; + }; + + result = read(drweb_fd, drweb_fbuf, fsize); + if (result == -1) { + close(sock); + close(drweb_fd); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: can't read spool file %s: %s", + scanrequest, strerror(errno)); + return DEFER; + }; + + /* send file body to socket */ + if (send(sock, drweb_fbuf, fsize, 0) < 0) { + close(sock); + 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 */ + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: can't open UNIX socket"); + return DEFER; + }; + server.sun_family = AF_UNIX; + Ustrcpy(server.sun_path, drweb_options); + if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: unable to connect to socket (%s). errno=%d", + drweb_options, errno); + return DEFER; + }; + + /* prepare variables */ + drweb_cmd = htonl(DRWEBD_SCAN_CMD); + drweb_flags = htonl(DRWEBD_RETURN_VIRUSES); + snprintf(CS scanrequest, 1024, CS "%s/scan/%s/%s.eml", + spool_directory, message_id, message_id); + drweb_slen = htonl(Ustrlen(scanrequest)); + + /* send scan request */ + if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) || + (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) || + (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) || + (send(sock, scanrequest, Ustrlen(scanrequest), 0) < 0) || + (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0)) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: unable to send commands to socket (%s)", + drweb_options); + return DEFER; + }; + }; + + /* wait for result */ + if ((bread = recv(sock, &drweb_rc, sizeof(drweb_rc), 0) != sizeof(drweb_rc))) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: unable to read return code"); + return DEFER; + }; + drweb_rc = ntohl(drweb_rc); + + if ((bread = recv(sock, &drweb_vnum, sizeof(drweb_vnum), 0) != sizeof(drweb_vnum))) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: drweb: unable to read the number of viruses"); + return DEFER; + }; + drweb_vnum = ntohl(drweb_vnum); + + /* "virus(es) found" if virus number is > 0 */ + if (drweb_vnum) { + int i; + uschar pre_malware_nb[256]; + + malware_name = malware_name_buffer; + + /* setup default virus name */ + Ustrcpy(malware_name_buffer, "unknown"); + + /* read and concatenate virus names into one string */ + for (i=0;i<drweb_vnum;i++) { + /* read the size of report */ + if ((bread = recv(sock, &drweb_slen, sizeof(drweb_slen), 0) != sizeof(drweb_slen))) { close(sock); log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to read 2 bytes from kavdaemon socket."); + "malware acl condition: drweb: cannot read report size"); return DEFER; - } - - /* get errorcode from one nibble */ - if (test_byte_order() == LITTLE_MY_ENDIAN) { - kav_rc = tmpbuf[0] & 0x0F; - } - else { - kav_rc = tmpbuf[1] & 0x0F; }; - - /* improper kavdaemon configuration */ - if ( (kav_rc == 5) || (kav_rc == 6) ) { + drweb_slen = ntohl(drweb_slen); + + /* read report body */ + if ((bread = recv(sock, tmpbuf, drweb_slen, 0)) != drweb_slen) { close(sock); log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: please reconfigure kavdaemon to NOT disinfect or remove infected files."); + "malware acl condition: drweb: cannot read report string"); return DEFER; }; - - if (kav_rc == 1) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: kavdaemon reported 'scanning not completed' (code 1)."); - return DEFER; + tmpbuf[drweb_slen] = '\0'; + + /* set up match regex, depends on retcode */ + Ustrcpy(drweb_match_string, "infected\\swith\\s*(.+?)$"); + + drweb_re = pcre_compile(CS drweb_match_string, + PCRE_COPT, + (const char **)&rerror, + &roffset, + NULL); + + /* try matcher on the line, grab substring */ + result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0, ovector, 30); + if (result >= 2) { + pcre_copy_substring(CS tmpbuf, ovector, result, 1, CS pre_malware_nb, 255); }; - - if (kav_rc == 7) { + /* the first name we just copy to malware_name */ + if (i==0) + Ustrcpy(CS malware_name_buffer, CS pre_malware_nb); + else { + /* concatenate each new virus name to previous */ + int slen = Ustrlen(malware_name_buffer); + if (slen < (slen+Ustrlen(pre_malware_nb))) { + Ustrcat(malware_name_buffer, "/"); + Ustrcat(malware_name_buffer, pre_malware_nb); + }; + }; + }; + } + else { + /* no virus found */ + malware_name = NULL; + }; + close(sock); + return OK; +} + +/* "kavdaemon" scanner type ------------------------------------------------ */ +static int scan_kavdaemon(uschar ** pscanner, int *psep) { + uschar *kav_options; + uschar kav_options_buffer[1024]; + uschar kav_options_default[] = "/var/run/AvpCtl"; + struct sockaddr_un server; + int sock; + time_t t; + uschar tmpbuf[1024]; + uschar scanrequest[1024]; + uschar kav_match_string[128]; + int kav_rc; + unsigned long kav_reportlen, bread; + pcre *kav_re; + int roffset; + uschar *rerror; + + if ((kav_options = string_nextinlist(pscanner, psep, + kav_options_buffer, + sizeof(kav_options_buffer))) == NULL) { + /* no options supplied, use default options */ + kav_options = kav_options_default; + }; + + /* open the kavdaemon socket */ + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: can't open UNIX socket."); + return DEFER; + }; + server.sun_family = AF_UNIX; + Ustrcpy(server.sun_path, kav_options); + if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: unable to connect to kavdaemon UNIX socket (%s). errno=%d", + kav_options, errno); + return DEFER; + }; + + /* get current date and time, build scan request */ + time(&t); + strftime(CS tmpbuf, sizeof(tmpbuf), "<0>%d %b %H:%M:%S:%%s/scan/%%s", localtime(&t)); + snprintf(CS scanrequest, 1024, CS tmpbuf, spool_directory, message_id); + + /* send scan request */ + if (send(sock, scanrequest, Ustrlen(scanrequest)+1, 0) < 0) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: unable to write to kavdaemon UNIX socket (%s)", + kav_options); + return DEFER; + }; + + /* wait for result */ + if ((bread = recv(sock, tmpbuf, 2, 0) != 2)) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: unable to read 2 bytes from kavdaemon socket."); + return DEFER; + }; + + /* get errorcode from one nibble */ + if (test_byte_order() == LITTLE_MY_ENDIAN) { + kav_rc = tmpbuf[0] & 0x0F; + } + else { + kav_rc = tmpbuf[1] & 0x0F; + }; + + /* improper kavdaemon configuration */ + if ((kav_rc == 5) || (kav_rc == 6)) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: please reconfigure kavdaemon to NOT disinfect or remove infected files."); + return DEFER; + }; + + if (kav_rc == 1) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: kavdaemon reported 'scanning not completed' (code 1)."); + return DEFER; + }; + + if (kav_rc == 7) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: kavdaemon reported 'kavdaemon damaged' (code 7)."); + return DEFER; + }; + + /* code 8 is not handled, since it is ambigous. It appears mostly on + bounces where part of a file has been cut off */ + + /* "virus found" return codes (2-4) */ + if ((kav_rc > 1) && (kav_rc < 5)) { + int report_flag = 0; + + /* setup default virus name */ + Ustrcpy(malware_name_buffer, "unknown"); + malware_name = malware_name_buffer; + + if (test_byte_order() == LITTLE_MY_ENDIAN) { + report_flag = tmpbuf[1]; + } + else { + report_flag = tmpbuf[0]; + }; + + /* read the report, if available */ + if (report_flag == 1) { + /* read report size */ + if ((bread = recv(sock, &kav_reportlen, 4, 0)) != 4) { close(sock); log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: kavdaemon reported 'kavdaemon damaged' (code 7)."); + "malware acl condition: cannot read report size from kavdaemon"); return DEFER; }; - - /* code 8 is not handled, since it is ambigous. It appears mostly on - bounces where part of a file has been cut off */ - - /* "virus found" return codes (2-4) */ - if ((kav_rc > 1) && (kav_rc < 5)) { - int report_flag = 0; - - /* setup default virus name */ - Ustrcpy(malware_name_buffer,"unknown"); - malware_name = malware_name_buffer; - - if (test_byte_order() == LITTLE_MY_ENDIAN) { - report_flag = tmpbuf[1]; - } - else { - report_flag = tmpbuf[0]; - }; - - /* read the report, if available */ - if( report_flag == 1 ) { - /* read report size */ - if ((bread = recv(sock, &kav_reportlen, 4, 0)) != 4) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: cannot read report size from kavdaemon"); - return DEFER; + + /* it's possible that avp returns av_buffer[1] == 1 but the + reportsize is 0 (!?) */ + if (kav_reportlen > 0) { + /* set up match regex, depends on retcode */ + if (kav_rc == 3) + Ustrcpy(kav_match_string, "suspicion:\\s*(.+?)\\s*$"); + else + Ustrcpy(kav_match_string, "infected:\\s*(.+?)\\s*$"); + + kav_re = pcre_compile(CS kav_match_string, + PCRE_COPT, + (const char **)&rerror, + &roffset, + NULL); + + /* read report, linewise */ + while (kav_reportlen > 0) { + int result = 0; + int ovector[30]; + + bread = 0; + while (recv(sock, &tmpbuf[bread], 1, 0) == 1) { + kav_reportlen--; + if ((tmpbuf[bread] == '\n') || (bread > 1021)) break; + bread++; }; - - /* it's possible that avp returns av_buffer[1] == 1 but the - reportsize is 0 (!?) */ - if (kav_reportlen > 0) { - /* set up match regex, depends on retcode */ - if( kav_rc == 3 ) - Ustrcpy(kav_match_string, "suspicion:\\s*(.+?)\\s*$"); - else - Ustrcpy(kav_match_string, "infected:\\s*(.+?)\\s*$"); - - kav_re = pcre_compile( CS kav_match_string, - PCRE_COPT, - (const char **)&rerror, - &roffset, - NULL ); - - /* read report, linewise */ - while (kav_reportlen > 0) { - int result = 0; - int ovector[30]; - - bread = 0; - while ( recv(sock, &tmpbuf[bread], 1, 0) == 1 ) { - kav_reportlen--; - if ( (tmpbuf[bread] == '\n') || (bread > 1021) ) break; - bread++; - }; - bread++; - tmpbuf[bread] = '\0'; - - /* try matcher on the line, grab substring */ - result = pcre_exec(kav_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0, ovector, 30); - if (result >= 2) { - pcre_copy_substring(CS tmpbuf, ovector, result, 1, CS malware_name_buffer, 255); - break; - }; - }; + bread++; + tmpbuf[bread] = '\0'; + + /* try matcher on the line, grab substring */ + result = pcre_exec(kav_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0, ovector, 30); + if (result >= 2) { + pcre_copy_substring(CS tmpbuf, ovector, result, 1, CS malware_name_buffer, 255); + break; }; }; - } - else { - /* no virus found */ - malware_name = NULL; }; - - close(sock); - return OK; + }; + } + else { + /* no virus found */ + malware_name = NULL; + }; + + close(sock); + return OK; } - - /* "cmdline" scanner type ------------------------------------------------ */ -static int scan_cmdline(uschar ** pscanner, int *psep) -{ - uschar *cmdline_scanner; - uschar cmdline_scanner_buffer[1024]; - uschar *cmdline_trigger; - uschar cmdline_trigger_buffer[1024]; - const pcre *cmdline_trigger_re; - uschar *cmdline_regex; - uschar cmdline_regex_buffer[1024]; - const pcre *cmdline_regex_re; - uschar file_name[1024]; - uschar commandline[1024]; - void (*eximsigchld)(int); - void (*eximsigpipe)(int); - FILE *scanner_out = NULL; - FILE *scanner_record = NULL; - uschar linebuffer[32767]; - int trigger = 0; - int result; - int ovector[30]; - int roffset; - const uschar *rerror; - - /* find scanner command line */ - if ((cmdline_scanner = string_nextinlist(pscanner, psep, - cmdline_scanner_buffer, - sizeof(cmdline_scanner_buffer))) == NULL) { - /* no command line supplied */ - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: missing commandline specification for cmdline scanner type."); - return DEFER; - }; - - /* find scanner output trigger */ - if ((cmdline_trigger = string_nextinlist(pscanner, psep, - cmdline_trigger_buffer, - sizeof(cmdline_trigger_buffer))) == NULL) { - /* no trigger regex supplied */ - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: missing trigger specification for cmdline scanner type."); - return DEFER; - }; - - /* precompile trigger regex */ - cmdline_trigger_re = pcre_compile(CS cmdline_trigger, PCRE_COPT, (const char **)&rerror, &roffset, NULL); - if (cmdline_trigger_re == NULL) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: regular expression error in '%s': %s at offset %d", cmdline_trigger_re, rerror, roffset); - return DEFER; - }; - - /* find scanner name regex */ - if ((cmdline_regex = string_nextinlist(pscanner, psep, - cmdline_regex_buffer, - sizeof(cmdline_regex_buffer))) == NULL) { - /* no name regex supplied */ - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: missing virus name regex specification for cmdline scanner type."); - return DEFER; - }; - - /* precompile name regex */ - cmdline_regex_re = pcre_compile(CS cmdline_regex, PCRE_COPT, (const char **)&rerror, &roffset, NULL); - if (cmdline_regex_re == NULL) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: regular expression error in '%s': %s at offset %d", cmdline_regex_re, rerror, roffset); - return DEFER; - }; - - /* prepare scanner call */ - snprintf(CS file_name,1024,"%s/scan/%s", spool_directory, message_id); - snprintf(CS commandline,1024, CS cmdline_scanner,file_name); - /* redirect STDERR too */ - Ustrcat(commandline," 2>&1"); - - /* store exims signal handlers */ - eximsigchld = signal(SIGCHLD,SIG_DFL); - eximsigpipe = signal(SIGPIPE,SIG_DFL); - - scanner_out = popen(CS commandline,"r"); - if (scanner_out == NULL) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: calling cmdline scanner (%s) failed: %s.", commandline, strerror(errno)); - signal(SIGCHLD,eximsigchld); - signal(SIGPIPE,eximsigpipe); - return DEFER; - }; - - snprintf(CS file_name,1024,"%s/scan/%s/%s_scanner_output", spool_directory, message_id, message_id); - scanner_record = fopen(CS file_name,"w"); - - if (scanner_record == NULL) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: opening scanner output file (%s) failed: %s.", file_name, strerror(errno)); - pclose(scanner_out); - signal(SIGCHLD,eximsigchld); - signal(SIGPIPE,eximsigpipe); - return DEFER; - }; - - /* look for trigger while recording output */ - while(fgets(CS linebuffer,32767,scanner_out) != NULL) { - if ( Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record) ) { - /* short write */ - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: short write on scanner output file (%s).", file_name); - pclose(scanner_out); - signal(SIGCHLD,eximsigchld); - signal(SIGPIPE,eximsigpipe); - return DEFER; - }; - /* try trigger match */ - if (!trigger && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)) - trigger = 1; - }; - - fclose(scanner_record); + +/* "cmdline" scanner type ------------------------------------------------ */ +static int scan_cmdline(uschar ** pscanner, int *psep) { + uschar *cmdline_scanner; + uschar cmdline_scanner_buffer[1024]; + uschar *cmdline_trigger; + uschar cmdline_trigger_buffer[1024]; + const pcre *cmdline_trigger_re; + uschar *cmdline_regex; + uschar cmdline_regex_buffer[1024]; + const pcre *cmdline_regex_re; + uschar file_name[1024]; + uschar commandline[1024]; + void (*eximsigchld)(int); + void (*eximsigpipe)(int); + FILE *scanner_out = NULL; + FILE *scanner_record = NULL; + uschar linebuffer[32767]; + int trigger = 0; + int result; + int ovector[30]; + int roffset; + const uschar *rerror; + + /* find scanner command line */ + if ((cmdline_scanner = string_nextinlist(pscanner, psep, + cmdline_scanner_buffer, + sizeof(cmdline_scanner_buffer))) == NULL) { + /* no command line supplied */ + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: missing commandline specification for cmdline scanner type."); + return DEFER; + }; + + /* find scanner output trigger */ + if ((cmdline_trigger = string_nextinlist(pscanner, psep, + cmdline_trigger_buffer, + sizeof(cmdline_trigger_buffer))) == NULL) { + /* no trigger regex supplied */ + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: missing trigger specification for cmdline scanner type."); + return DEFER; + }; + + /* precompile trigger regex */ + cmdline_trigger_re = pcre_compile(CS cmdline_trigger, + PCRE_COPT, + (const char **)&rerror, + &roffset, + NULL); + if (cmdline_trigger_re == NULL) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: regular expression error in '%s': %s at offset %d", + cmdline_trigger_re, rerror, roffset); + return DEFER; + }; + + /* find scanner name regex */ + if ((cmdline_regex = string_nextinlist(pscanner, psep, + cmdline_regex_buffer, + sizeof(cmdline_regex_buffer))) == NULL) { + /* no name regex supplied */ + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: missing virus name regex specification for cmdline scanner type."); + return DEFER; + }; + + /* precompile name regex */ + cmdline_regex_re = pcre_compile(CS cmdline_regex, + PCRE_COPT, + (const char **)&rerror, + &roffset, NULL); + if (cmdline_regex_re == NULL) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: regular expression error in '%s': %s at offset %d", + cmdline_regex_re, rerror, roffset); + return DEFER; + }; + + /* prepare scanner call */ + snprintf(CS file_name, 1024, "%s/scan/%s", spool_directory, message_id); + snprintf(CS commandline, 1024, CS cmdline_scanner, file_name); + /* redirect STDERR too */ + Ustrcat(commandline, " 2>&1"); + + /* store exims signal handlers */ + eximsigchld = signal(SIGCHLD, SIG_DFL); + eximsigpipe = signal(SIGPIPE, SIG_DFL); + + scanner_out = popen(CS commandline, "r"); + if (scanner_out == NULL) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: calling cmdline scanner (%s) failed: %s.", + commandline, strerror(errno)); + signal(SIGCHLD, eximsigchld); + signal(SIGPIPE, eximsigpipe); + return DEFER; + }; + + snprintf(CS file_name, 1024, "%s/scan/%s/%s_scanner_output", + spool_directory, message_id, message_id); + scanner_record = fopen(CS file_name, "w"); + + if (scanner_record == NULL) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: opening scanner output file (%s) failed: %s.", + file_name, strerror(errno)); + pclose(scanner_out); + signal(SIGCHLD, eximsigchld); + signal(SIGPIPE, eximsigpipe); + return DEFER; + }; + + /* look for trigger while recording output */ + while (fgets(CS linebuffer, 32767, scanner_out) != NULL) { + if (Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record)) { + /* short write */ + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: short write on scanner output file (%s).", file_name); pclose(scanner_out); - signal(SIGCHLD,eximsigchld); - signal(SIGPIPE,eximsigpipe); - - if (trigger) { - /* setup default virus name */ - Ustrcpy(malware_name_buffer,"unknown"); - malware_name = malware_name_buffer; - - /* re-open the scanner output file, look for name match */ - scanner_record = fopen(CS file_name,"r"); - while(fgets(CS linebuffer,32767,scanner_record) != NULL) { - /* try match */ - result = pcre_exec(cmdline_regex_re, NULL, CS linebuffer, Ustrlen(linebuffer), 0, 0, ovector, 30); - if (result >= 2) { - pcre_copy_substring(CS linebuffer, ovector, result, 1, CS malware_name_buffer, 255); - }; - }; - fclose(scanner_record); - } - else { - /* no virus found */ - malware_name = NULL; + signal(SIGCHLD, eximsigchld); + signal(SIGPIPE, eximsigpipe); + return DEFER; + }; + /* try trigger match */ + if (!trigger && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1)) + trigger = 1; + }; + + fclose(scanner_record); + pclose(scanner_out); + signal(SIGCHLD, eximsigchld); + signal(SIGPIPE, eximsigpipe); + + if (trigger) { + /* setup default virus name */ + Ustrcpy(malware_name_buffer, "unknown"); + malware_name = malware_name_buffer; + + /* re-open the scanner output file, look for name match */ + scanner_record = fopen(CS file_name, "r"); + while (fgets(CS linebuffer, 32767, scanner_record) != NULL) { + /* try match */ + result = pcre_exec(cmdline_regex_re, NULL, CS linebuffer, + Ustrlen(linebuffer), 0, 0, ovector, 30); + if (result >= 2) { + pcre_copy_substring(CS linebuffer, ovector, result, 1, CS malware_name_buffer, 255); }; - return OK; + }; + fclose(scanner_record); + } + else { + /* no virus found */ + malware_name = NULL; + }; + return OK; } - - /* "sophie" scanner type ------------------------------------------------- */ -static int scan_sophie(uschar ** pscanner, int *psep) -{ - uschar *sophie_options; - uschar sophie_options_buffer[1024]; - uschar sophie_options_default[] = "/var/run/sophie"; - int bread = 0; - struct sockaddr_un server; - int sock; - uschar file_name[1024]; - uschar av_buffer[1024]; - - if ((sophie_options = string_nextinlist(pscanner, psep, + +/* "sophie" scanner type ------------------------------------------------- */ +static int scan_sophie(uschar ** pscanner, int *psep) { + uschar *sophie_options; + uschar sophie_options_buffer[1024]; + uschar sophie_options_default[] = "/var/run/sophie"; + int bread = 0; + struct sockaddr_un server; + int sock; + uschar file_name[1024]; + uschar av_buffer[1024]; + + if ((sophie_options = string_nextinlist(pscanner, psep, sophie_options_buffer, sizeof(sophie_options_buffer))) == NULL) { - /* no options supplied, use default options */ - sophie_options = sophie_options_default; - }; - - /* open the sophie socket */ - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: can't open UNIX socket."); - return DEFER; - } - server.sun_family = AF_UNIX; - Ustrcpy(server.sun_path, sophie_options); - if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to connect to sophie UNIX socket (%s). errno=%d", sophie_options, errno); - return DEFER; - } - - /* pass the scan directory to sophie */ - snprintf(CS file_name,1024,"%s/scan/%s", spool_directory, message_id); - if (write(sock, file_name, Ustrlen(file_name)) < 0) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to write to sophie UNIX socket (%s)", sophie_options); - return DEFER; - }; - - write(sock, "\n", 1); - - /* wait for result */ - memset(av_buffer, 0, sizeof(av_buffer)); - if ((!(bread = read(sock, av_buffer, sizeof(av_buffer))) > 0)) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to read from sophie UNIX socket (%s)", sophie_options); - return DEFER; - }; - - close(sock); - - /* infected ? */ - if (av_buffer[0] == '1') { - if (Ustrchr(av_buffer, '\n')) *Ustrchr(av_buffer, '\n') = '\0'; - Ustrcpy(malware_name_buffer,&av_buffer[2]); - malware_name = malware_name_buffer; - } - else if (!strncmp(CS av_buffer, "-1", 2)) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: malware acl condition: sophie reported error"); - return DEFER; - } - else { - /* all ok, no virus */ - malware_name = NULL; - }; - return OK; + /* no options supplied, use default options */ + sophie_options = sophie_options_default; + }; + + /* open the sophie socket */ + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: can't open UNIX socket."); + return DEFER; + }; + server.sun_family = AF_UNIX; + Ustrcpy(server.sun_path, sophie_options); + if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: unable to connect to sophie UNIX socket (%s). errno=%d", + sophie_options, errno); + return DEFER; + }; + + /* pass the scan directory to sophie */ + snprintf(CS file_name, 1024, "%s/scan/%s", spool_directory, message_id); + if (write(sock, file_name, Ustrlen(file_name)) < 0) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: unable to write to sophie UNIX socket (%s)", + sophie_options); + return DEFER; + }; + + write(sock, "\n", 1); + + /* wait for result */ + memset(av_buffer, 0, sizeof(av_buffer)); + if ((!(bread = read(sock, av_buffer, sizeof(av_buffer))) > 0)) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: unable to read from sophie UNIX socket (%s)", + sophie_options); + return DEFER; + }; + + close(sock); + + /* infected ? */ + if (av_buffer[0] == '1') { + if (Ustrchr(av_buffer, '\n')) *Ustrchr(av_buffer, '\n') = '\0'; + Ustrcpy(malware_name_buffer, &av_buffer[2]); + malware_name = malware_name_buffer; + } + else if (!strncmp(CS av_buffer, "-1", 2)) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: malware acl condition: sophie reported error"); + return DEFER; + } + else { + /* all ok, no virus */ + malware_name = NULL; + }; + return OK; }
- /* "clamd" scanner type ------------------------------------------------- */ - /* This code was contributed by David Saez <david@???> */ -static int scan_clamd(uschar ** pscanner, int *psep) -{ - uschar *clamd_options; - uschar clamd_options_buffer[1024]; - uschar clamd_options_default[] = "/tmp/clamd"; - uschar *p,*vname; - struct sockaddr_un server; - int sock,port,bread=0; - uschar file_name[1024]; - uschar av_buffer[1024]; - uschar hostname[256]; - struct hostent *he; - struct in_addr in; - - if ((clamd_options = string_nextinlist(pscanner, psep, - clamd_options_buffer, - sizeof(clamd_options_buffer))) == NULL) { - /* no options supplied, use default options */ - clamd_options = clamd_options_default; - } - - /* socket does not start with '/' -> network socket */ - if (*clamd_options != '/') { - - /* extract host and port part */ - if( sscanf(CS clamd_options, "%s %u", hostname, &port) != 2 ) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: invalid socket '%s'", clamd_options); - return DEFER; - }; - - /* Lookup the host */ - if((he = gethostbyname(CS hostname)) == 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: failed to lookup host '%s'", hostname); - return DEFER; - } - - in = *(struct in_addr *) he->h_addr_list[0]; - - /* Open the ClamAV Socket */ - if ( (sock = 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(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) { - close(sock); - 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; - } - } - else { - /* open the local socket */ - if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unable to acquire socket (%s)", - strerror(errno)); - return DEFER; - } - - server.sun_family = AF_UNIX; - Ustrcpy(server.sun_path, clamd_options); - - if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unable to connect to UNIX socket %s (%s)", - clamd_options, strerror(errno) ); - return DEFER; - } - } - - /* 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; - } - - /* - We're done sending, close socket for writing. - - One user reported that clamd 0.70 does not like this any more ... - - */ - - /* shutdown(sock, SHUT_WR); */ - - /* Read the result */ - memset(av_buffer, 0, sizeof(av_buffer)); - bread = read(sock, av_buffer, sizeof(av_buffer)); +/* "clamd" scanner type ------------------------------------------------- */ +/* This code was contributed by David Saez <david@???> */ +static int scan_clamd(uschar ** pscanner, int *psep) { + uschar *clamd_options; + uschar clamd_options_buffer[1024]; + uschar clamd_options_default[] = "/tmp/clamd"; + uschar *p, *vname; + struct sockaddr_un server; + int sock, port, bread=0; + uschar file_name[1024]; + uschar av_buffer[1024]; + uschar hostname[256]; + struct hostent *he; + struct in_addr in; + + if ((clamd_options = string_nextinlist(pscanner, psep, + clamd_options_buffer, + sizeof(clamd_options_buffer))) == NULL) { + /* no options supplied, use default options */ + clamd_options = clamd_options_default; + }; + + /* socket does not start with '/' -> network socket */ + if (*clamd_options != '/') { + + /* extract host and port part */ + if (sscanf(CS clamd_options, "%s %u", hostname, &port) != 2) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: clamd: invalid socket '%s'", clamd_options); + return DEFER; + }; + + /* Lookup the host */ + if ((he = gethostbyname(CS hostname)) == 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: clamd: failed to lookup host '%s'", hostname); + return DEFER; + }; + + in = *(struct in_addr *) he->h_addr_list[0]; + + /* Open the ClamAV Socket */ + if ((sock = 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(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) { close(sock); + 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; + }; + } + else { + /* open the local socket */ + if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: clamd: unable to acquire socket (%s)", + strerror(errno)); + return DEFER; + };
- if (!(bread > 0)) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: unable to read 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; - } - - /* Check the result. ClamAV Returns - infected: -> "<filename>: <virusname> FOUND" - not-infected: -> "<filename>: OK" - error: -> "<filename>: <errcode> ERROR */ - - if (!(*av_buffer)) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: ClamAV returned null"); - return DEFER; - } - - /* colon in returned output? */ - if((p = Ustrrchr(av_buffer,':')) == NULL) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: ClamAV returned malformed result: %s", - av_buffer); - return DEFER; - } - - /* strip filename strip CR at the end */ - ++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; - for (;*vname==32;vname++); - Ustrcpy(malware_name_buffer,vname); - malware_name = malware_name_buffer; - } - else { - if (Ustrstr(vname, "ERROR")!=NULL) { - /* ClamAV reports ERROR - Find line start */ - for (;*vname!='\n' && vname>av_buffer; vname--); - if (*vname=='\n') vname++; - - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: clamd: ClamAV returned %s",vname); - return DEFER; - } - else { - /* Everything should be OK */ - malware_name = NULL; - } - } - return OK; -} - - /* "mksd" scanner type --------------------------------------------------- */ -static int scan_mksd(uschar ** pscanner, int *psep) -{ - uschar *mksd_options; - char *mksd_options_end; - uschar mksd_options_buffer[32]; - int mksd_maxproc = 1; /* default, if no option supplied */ - struct sockaddr_un server; - int sock; - int retval; - - if ((mksd_options = string_nextinlist(pscanner, psep, - mksd_options_buffer, - sizeof(mksd_options_buffer))) != NULL) { - mksd_maxproc = (int) strtol(CS mksd_options, &mksd_options_end, 10); - if ((*mksd_options == '\0') || (*mksd_options_end != '\0') || - (mksd_maxproc < 1) || (mksd_maxproc > 32)) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: mksd: invalid option '%s'", mksd_options); - return DEFER; - } - } - - /* open the mksd socket */ - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: can't open UNIX socket."); - return DEFER; - } - server.sun_family = AF_UNIX; - Ustrcpy(server.sun_path, "/var/run/mksd/socket"); - if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { - close(sock); - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: unable to connect to mksd UNIX socket (/var/run/mksd/socket). errno=%d", errno); - return DEFER; - } - + server.sun_family = AF_UNIX; + Ustrcpy(server.sun_path, clamd_options); + + if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: clamd: unable to connect to UNIX socket %s (%s)", + clamd_options, strerror(errno)); + return DEFER; + }; + }; + + /* 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; + }; + + /* + We're done sending, close socket for writing. + + One user reported that clamd 0.70 does not like this any more ... + + */ + + /* shutdown(sock, SHUT_WR); */ + + /* Read the result */ + memset(av_buffer, 0, sizeof(av_buffer)); + bread = read(sock, av_buffer, sizeof(av_buffer)); + close(sock); + + if (!(bread > 0)) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: clamd: unable to read 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; + }; + + /* Check the result. ClamAV Returns + infected: -> "<filename>: <virusname> FOUND" + not-infected: -> "<filename>: OK" + error: -> "<filename>: <errcode> ERROR */ + + if (!(*av_buffer)) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: clamd: ClamAV returned null"); + return DEFER; + }; + + /* colon in returned output? */ + if ((p = Ustrrchr(av_buffer, ':')) == NULL) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: clamd: ClamAV returned malformed result: %s", + av_buffer); + return DEFER; + }; + + /* strip filename strip CR at the end */ + ++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; + for (;*vname==32;vname++); + Ustrcpy(malware_name_buffer, vname); + malware_name = malware_name_buffer; + } + else { + if (Ustrstr(vname, "ERROR")!=NULL) { + /* ClamAV reports ERROR + Find line start */ + for (;*vname!='\n' && vname>av_buffer; vname--); + if (*vname=='\n') vname++; + + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: clamd: ClamAV returned %s", vname); + return DEFER; + } + else { + /* Everything should be OK */ malware_name = NULL; - - /* choose the appropriate scan routine */ - retval = demime_ok ? - mksd_scan_unpacked(sock, mksd_maxproc) : - mksd_scan_packed(sock); - - if (retval != OK) - return retval; - - return OK; + }; + }; + return OK; +} + +/* "mksd" scanner type --------------------------------------------------- */ +static int scan_mksd(uschar ** pscanner, int *psep) { + uschar *mksd_options; + char *mksd_options_end; + uschar mksd_options_buffer[32]; + int mksd_maxproc = 1; /* default, if no option supplied */ + struct sockaddr_un server; + int sock; + int retval; + + if ((mksd_options = string_nextinlist(pscanner, psep, + mksd_options_buffer, + sizeof(mksd_options_buffer))) != NULL) { + mksd_maxproc = (int) strtol(CS mksd_options, &mksd_options_end, 10); + if ((*mksd_options == '\0') || (*mksd_options_end != '\0') || + (mksd_maxproc < 1) || (mksd_maxproc > 32)) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: mksd: invalid option '%s'", mksd_options); + return DEFER; + }; + }; + + /* open the mksd socket */ + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: can't open UNIX socket."); + return DEFER; + }; + server.sun_family = AF_UNIX; + Ustrcpy(server.sun_path, "/var/run/mksd/socket"); + if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) { + close(sock); + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: unable to connect to mksd UNIX socket (/var/run/mksd/socket). errno=%d", + errno); + return DEFER; + }; + + malware_name = NULL; + + /* choose the appropriate scan routine */ + retval = demime_ok ? + mksd_scan_unpacked(sock, mksd_maxproc) : + mksd_scan_packed(sock); + + if (retval != OK) + return retval; + + return OK; }
-int mksd_writev (int sock, struct iovec *iov, int iovcnt) -{ +int mksd_writev(int sock, struct iovec *iov, int iovcnt) { int i; - + for (;;) { do - i = writev (sock, iov, iovcnt); + i = writev(sock, iov, iovcnt); while ((i < 0) && (errno == EINTR)); if (i <= 0) { - close (sock); + close(sock); log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: unable to write to mksd UNIX socket (/var/run/mksd/socket)"); return -1; - } - + }; + for (;;) if (i >= iov->iov_len) { if (--iovcnt == 0) @@ -1075,103 +1097,99 @@ iov->iov_len -= i; iov->iov_base = CS iov->iov_base + i; break; - } - } + }; + }; }
-int mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size) -{ +int mksd_read_lines(int sock, uschar *av_buffer, int av_buffer_size) { int offset = 0; int i; - + do { - if ((i = recv (sock, av_buffer+offset, av_buffer_size-offset, 0)) <= 0) { - close (sock); + if ((i = recv(sock, av_buffer+offset, av_buffer_size-offset, 0)) <= 0) { + close(sock); log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: unable to read from mksd UNIX socket (/var/run/mksd/socket)"); return -1; - } - + }; + offset += i; /* offset == av_buffer_size -> buffer full */ if (offset == av_buffer_size) { - close (sock); + close(sock); log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: malformed reply received from mksd"); return -1; - } + }; } while (av_buffer[offset-1] != '\n'); - + av_buffer[offset] = '\0'; return offset; }
-int mksd_parse_line (char *line) -{ +int mksd_parse_line(char *line) { char *p; - + switch (*line) { - case 'O': - /* OK */ - return OK; - case 'E': - case 'A': - /* ERR */ - if ((p = strchr (line, '\n')) != NULL) - (*p) = '\0'; - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: mksd scanner failed: %s", line); - return DEFER; - default: - /* VIR */ - if ((p = strchr (line, '\n')) != NULL) { - (*p) = '\0'; - if (((p-line) > 5) && ((p-line) < sizeof (malware_name_buffer)) && (line[3] == ' ')) - if (((p = strchr (line+4, ' ')) != NULL) && ((p-line) > 4)) { - (*p) = '\0'; - Ustrcpy (malware_name_buffer, line+4); - malware_name = malware_name_buffer; - return OK; - } - } - log_write(0, LOG_MAIN|LOG_PANIC, - "malware acl condition: malformed reply received from mksd: %s", line); - return DEFER; - } + case 'O': + /* OK */ + return OK; + case 'E': + case 'A': + /* ERR */ + if ((p = strchr(line, '\n')) != NULL) + (*p) = '\0'; + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: mksd scanner failed: %s", line); + return DEFER; + default: + /* VIR */ + if ((p = strchr(line, '\n')) != NULL) { + (*p) = '\0'; + if (((p-line) > 5) && ((p-line) < sizeof(malware_name_buffer)) && (line[3] == ' ')) + if (((p = strchr(line+4, ' ')) != NULL) && ((p-line) > 4)) { + (*p) = '\0'; + Ustrcpy(malware_name_buffer, line+4); + malware_name = malware_name_buffer; + return OK; + }; + }; + log_write(0, LOG_MAIN|LOG_PANIC, + "malware acl condition: malformed reply received from mksd: %s", line); + return DEFER; + }; }
-int mksd_scan_packed (int sock) -{ +int mksd_scan_packed(int sock) { struct iovec iov[7]; char *cmd = "MSQ/scan/.eml\n"; uschar av_buffer[1024]; - + iov[0].iov_base = cmd; iov[0].iov_len = 3; iov[1].iov_base = CS spool_directory; - iov[1].iov_len = Ustrlen (spool_directory); + iov[1].iov_len = Ustrlen(spool_directory); iov[2].iov_base = cmd + 3; iov[2].iov_len = 6; iov[3].iov_base = iov[5].iov_base = CS message_id; - iov[3].iov_len = iov[5].iov_len = Ustrlen (message_id); + iov[3].iov_len = iov[5].iov_len = Ustrlen(message_id); iov[4].iov_base = cmd + 3; iov[4].iov_len = 1; iov[6].iov_base = cmd + 9; iov[6].iov_len = 5; - - if (mksd_writev (sock, iov, 7) < 0) + + if (mksd_writev(sock, iov, 7) < 0) return DEFER; - - if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer)) < 0) + + if (mksd_read_lines(sock, av_buffer, sizeof(av_buffer)) < 0) return DEFER; - - close (sock); - - return mksd_parse_line (CS av_buffer); + + close(sock); + + return mksd_parse_line(CS av_buffer); }
-int mksd_scan_unpacked (int sock, int maxproc) -{ +int mksd_scan_unpacked(int sock, int maxproc) { struct iovec iov[5]; char *cmd = "\nSQ/"; DIR *unpdir; @@ -1182,80 +1200,80 @@ uschar mbox_name[1024]; uschar unpackdir[1024]; uschar av_buffer[16384]; - - snprintf (CS mbox_name, sizeof (mbox_name), "%s.eml", CS message_id); - snprintf (CS unpackdir, sizeof (unpackdir), "%s/scan/%s", CS spool_directory, CS message_id); - - if ((unpdir = opendir (CS unpackdir)) == NULL) { - close (sock); + + snprintf(CS mbox_name, sizeof(mbox_name), "%s.eml", CS message_id); + snprintf(CS unpackdir, sizeof(unpackdir), "%s/scan/%s", CS spool_directory, CS message_id); + + if ((unpdir = opendir(CS unpackdir)) == NULL) { + close(sock); log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: unable to scan spool directory"); return DEFER; - } - + }; + iov[0].iov_base = cmd; iov[0].iov_len = 3; iov[1].iov_base = CS unpackdir; - iov[1].iov_len = Ustrlen (unpackdir); + iov[1].iov_len = Ustrlen(unpackdir); iov[2].iov_base = cmd + 3; iov[2].iov_len = 1; iov[4].iov_base = cmd; iov[4].iov_len = 1; - + /* main loop */ while ((unpdir != NULL) || (pending > 0)) { - + /* write loop */ while ((pending < maxproc) && (unpdir != NULL)) { - if ((entry = readdir (unpdir)) != NULL) { - if ((Ustrcmp (entry->d_name, ".") != 0) && - (Ustrcmp (entry->d_name, "..") != 0) && - (Ustrcmp (entry->d_name, mbox_name) != 0)) { + if ((entry = readdir(unpdir)) != NULL) { + if ((Ustrcmp(entry->d_name, ".") != 0) && + (Ustrcmp(entry->d_name, "..") != 0) && + (Ustrcmp(entry->d_name, mbox_name) != 0)) { iov[3].iov_base = entry->d_name; - iov[3].iov_len = strlen (entry->d_name); - if (mksd_writev (sock, iov, 5) < 0) { - closedir (unpdir); + iov[3].iov_len = strlen(entry->d_name); + if (mksd_writev(sock, iov, 5) < 0) { + closedir(unpdir); return DEFER; - } + }; iov[0].iov_base = cmd + 1; iov[0].iov_len = 2; pending++; - } + }; } else { - closedir (unpdir); + closedir(unpdir); unpdir = NULL; - } - } - + }; + }; + /* read and parse */ if (pending > 0) { - if ((offset = mksd_read_lines (sock, av_buffer, sizeof (av_buffer))) < 0) { + if ((offset = mksd_read_lines(sock, av_buffer, sizeof(av_buffer))) < 0) { if (unpdir != NULL) - closedir (unpdir); + closedir(unpdir); return DEFER; - } + }; line = av_buffer; do { - if (((i = mksd_parse_line (CS line)) != OK) || (malware_name != NULL)) { - close (sock); + if (((i = mksd_parse_line(CS line)) != OK) || (malware_name != NULL)) { + close(sock); if (unpdir != NULL) - closedir (unpdir); + closedir(unpdir); return i; - } + }; pending--; - if ((line = Ustrchr (line, '\n')) == NULL) { - close (sock); + if ((line = Ustrchr(line, '\n')) == NULL) { + close(sock); if (unpdir != NULL) - closedir (unpdir); + closedir(unpdir); log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: unterminated line received from mksd"); return DEFER; - } + }; } while (++line != (av_buffer + offset)); offset = 0; - } - } - - close (sock); + }; + }; + + close(sock); return OK; }
Wiadomość została wysłana do następujących list mailowych: | ||||
---|---|---|---|---|
Exim-users Informacja o liście mailowej | Najbliższe wiadomości | Re: [Exim] exim 3.x treatment of failure in transport_filter | Re: [Exim] Sieve filters and vacation msgs |
Tahini and Hummus and Cumin Development Archives administrowana przez cumin Admins | Lurker (wersja 2.3) |