- close(sock);
- }
- /* "fsecure" scanner type ------------------------------------------------- */
- else if (strcmpic(scanner_name,US"fsecure") == 0) {
- uschar *fsecure_options;
- uschar fsecure_options_buffer[1024];
- uschar fsecure_options_default[] = "/var/run/.fsav";
- struct sockaddr_un server;
- int sock, i, j, bread = 0;
- uschar file_name[1024];
- uschar av_buffer[1024];
- pcre *fs_inf;
- static uschar *cmdoptions[] = { "CONFIGURE\tARCHIVE\t1\n","CONFIGURE\tTIMEOUT\t0\n","CONFIGURE\tMAXARCH\t5\n","CONFIGURE\tMIME\t1\n" };
-
- malware_name = NULL;
- if ((fsecure_options = string_nextinlist(&av_scanner_work, &sep,
- fsecure_options_buffer,
- sizeof(fsecure_options_buffer))) == NULL) {
- /* no options supplied, use default options */
- fsecure_options = fsecure_options_default;
- };
-
- /* open the fsecure socket */
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock < 0) {
- log_write(0, LOG_MAIN|LOG_PANIC,
- "malware acl condition: unable to open fsecure socket %s (%s)",
- fsecure_options, strerror(errno));
- return DEFER;
- }
- server.sun_family = AF_UNIX;
- Ustrcpy(server.sun_path, fsecure_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 fsecure socket %s (%s)",
- fsecure_options, strerror(errno));
- return DEFER;
- }
-
- /* pass options */
- memset(av_buffer, 0, sizeof(av_buffer));
- for (i=0; i != 4; i++) {
- /* debug_printf("send option \"%s\"",cmdoptions[i]); */
- if (write(sock, cmdoptions[i], Ustrlen(cmdoptions[i])) < 0) {
- close(sock);
- log_write(0, LOG_MAIN|LOG_PANIC,
- "malware acl condition: unable to write fsecure option %d to %s (%s)",
- i, fsecure_options, strerror(errno));
- return DEFER;
- };
-
- bread = read(sock, av_buffer, sizeof(av_buffer));
- if (bread >0) av_buffer[bread]='\0';
- if (bread < 0) {
- close(sock);
- log_write(0, LOG_MAIN|LOG_PANIC,
- "malware acl condition: unable to read fsecure answer %d (%s)", i, strerror(errno));
- return DEFER;
- };
- for (j=0;j<bread;j++) if((av_buffer[j]=='\r')||(av_buffer[j]=='\n')) av_buffer[j] ='@';
- /* debug_printf("read answer %d read=%d \"%s\"\n", i, bread, av_buffer ); */
- /* while (Ustrstr(av_buffer, "OK\tServer configured.@") == NULL); */
- };
-
- /* pass the mailfile to fsecure */
- snprintf(CS file_name,1024,"SCAN\t%s/scan/%s/%s.eml\n", spool_directory, message_id, message_id);
- /* debug_printf("send scan %s",file_name); */
- if (write(sock, file_name, Ustrlen(file_name)) < 0) {
- close(sock);
- log_write(0, LOG_MAIN|LOG_PANIC,
- "malware acl condition: unable to write fsecure scan to %s (%s)",
- fsecure_options, strerror(errno));
- return DEFER;
- };
-
- /* set up match */
- /* todo also SUSPICION\t */
- fs_inf = pcre_compile("\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$", PCRE_COPT, (const char **)&rerror, &roffset, NULL);
-
- /* read report, linewise */
- do {
- int ovector[30];
- i = 0;
- memset(av_buffer, 0, sizeof(av_buffer));
- do {
- bread=read(sock, &av_buffer[i], 1);
- if (bread < 0) {
- close(sock);
- log_write(0, LOG_MAIN|LOG_PANIC,
- "malware acl condition: unable to read fsecure result (%s)", strerror(errno));
- return DEFER;
- };
- i++;
- }
- while ((i < sizeof(av_buffer)-1 ) && (av_buffer[i-1] != '\n'));
- av_buffer[i-1] = '\0';
- /* debug_printf("got line \"%s\"\n",av_buffer); */
-
- /* Really search for virus again? */
- if (malware_name == NULL) {
- /* try matcher on the line, grab substring */
- i = pcre_exec(fs_inf, NULL, CS av_buffer, Ustrlen(av_buffer), 0, 0, ovector, 30);
- if (i >= 2) {
- /* Got it */
- pcre_copy_substring(CS av_buffer, ovector, i, 1, CS malware_name_buffer, 255);
- malware_name = malware_name_buffer;
- };
- };
- }
- while (Ustrstr(av_buffer, "OK\tScan ok.") == NULL);
- close(sock);
- }
- /* ----------------------------------------------------------------------- */
-
- /* "kavdaemon" scanner type ------------------------------------------------ */
- else if (strcmpic(scanner_name,US"kavdaemon") == 0) {
- 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;
-
- if ((kav_options = string_nextinlist(&av_scanner_work, &sep,
- 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: 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++;
- };
- 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);
- }
- /* ----------------------------------------------------------------------- */
-
-
- /* "cmdline" scanner type ------------------------------------------------ */
- else if (strcmpic(scanner_name,US"cmdline") == 0) {
- 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];
-
- /* find scanner command line */
- if ((cmdline_scanner = string_nextinlist(&av_scanner_work, &sep,
- 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(&av_scanner_work, &sep,
- 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(&av_scanner_work, &sep,
- 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);
- 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;
- };
- }
- /* ----------------------------------------------------------------------- */
-
-
- /* "sophie" scanner type ------------------------------------------------- */
- else if (strcmpic(scanner_name,US"sophie") == 0) {
- 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(&av_scanner_work, &sep,
- 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;