+ case M_SOCK: /* "sock" scanner type ------------------------------------- */
+ /* This code was derived by Martin Poole from the clamd code contributed
+ by David Saez and the cmdline code
+ */
+ {
+ int sock, bread=0;
+ uschar * commandline;
+ uschar av_buffer[1024];
+ uschar * linebuffer;
+ uschar *sockline_scanner;
+ uschar sockline_scanner_default[] = "%s\n";
+ uschar *sockline_trigger;
+ const pcre *sockline_trigger_re;
+ uschar *sockline_regex;
+ const pcre *sockline_regex_re;
+ int result;
+ int ovector[10*3];
+
+ /* find scanner command line */
+ if (!(sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
+ NULL, 0)))
+ sockline_scanner = sockline_scanner_default;
+
+ /* find scanner output trigger */
+ if (!(sockline_trigger = string_nextinlist(&av_scanner_work, &sep,
+ NULL, 0)))
+ return sock_errlog_defer("missing trigger specification");
+
+ /* precompile trigger regex */
+ sockline_trigger_re = pcre_compile(CS sockline_trigger, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
+ if (sockline_trigger_re == NULL)
+ return sock_errlog_defer(
+ string_sprintf("regular expression error in '%s': %s at offset %d",
+ sockline_trigger, rerror, roffset));
+
+ /* find virus name regex */
+ if (!(sockline_regex = string_nextinlist(&av_scanner_work, &sep,
+ NULL, 0)))
+ return sock_errlog_defer("missing virus name regex specification");
+
+ /* precompile name regex */
+ sockline_regex_re = pcre_compile(CS sockline_regex, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
+ if (sockline_regex_re == NULL)
+ return sock_errlog_defer(
+ string_sprintf("regular expression error in '%s': %s at offset %d",
+ sockline_regex, rerror, roffset));
+
+ /* prepare scanner call */
+ commandline = string_sprintf("%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
+ commandline = string_sprintf( CS sockline_scanner, CS commandline);
+
+
+ /* socket does not start with '/' -> network socket */
+ sock = *scanner_options != '/'
+ ? m_tcpsocket_fromdef(scanner_options, &errstr)
+ : m_unixsocket(scanner_options, &errstr);
+ if (sock < 0)
+ return sock_errlog_defer(errstr);
+
+ /* Pass the command string to the socket */
+ if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
+ return sock_errlog_defer(errstr);
+
+ /* We're done sending, close socket for writing. */
+ /* shutdown(sock, SHUT_WR); */
+
+ /* Read the result */
+ memset(av_buffer, 0, sizeof(av_buffer));
+ bread = read(sock, av_buffer, sizeof(av_buffer));
+ (void)close(sock);
+
+ if (!(bread > 0))
+ return sock_errlog_defer(
+ string_sprintf("unable to read from socket (%s)", strerror(errno)));
+
+ if (bread == sizeof(av_buffer))
+ return sock_errlog_defer("buffer too small");
+ linebuffer = string_copy(av_buffer);
+
+ /* try trigger match */
+ if (regex_match_and_setup(sockline_trigger_re, linebuffer, 0, -1)) {
+ result = pcre_exec(sockline_regex_re, NULL,
+ CS av_buffer, Ustrlen(av_buffer), 0, 0,
+ ovector, nelements(ovector));
+ if (result >= 2)
+ pcre_get_substring(CS av_buffer, ovector, result, 1,
+ (const char **)&malware_name);
+ else
+ malware_name = US "unknown";
+ }
+ else /* no virus found */
+ malware_name = NULL;
+ }
+