{
return m_scanner_errlog_defer("mksd", str);
}
+static int
+sock_errlog_defer(const uschar * str)
+{
+ return m_scanner_errlog_defer("sock", str);
+}
static void
clmd_errlog(const uschar * str)
static int
m_unixsocket(const uschar * path, uschar ** errstr)
{
-int sock;
-struct sockaddr_un server;
-
-if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
- *errstr = "can't open UNIX socket.";
- return -1;
-}
+ int sock;
+ struct sockaddr_un server;
-server.sun_family = AF_UNIX;
-Ustrcpy(server.sun_path, path);
-if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
- int err = errno;
- (void)close(sock);
- *errstr = string_sprintf("unable to connect to UNIX socket (%s): %s",
- path, strerror(err));
- return -1;
+ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ *errstr = "can't open UNIX socket.";
+ return -1;
}
-return sock;
+
+ server.sun_family = AF_UNIX;
+ Ustrcpy(server.sun_path, path);
+ if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
+ int err = errno;
+ (void)close(sock);
+ *errstr = string_sprintf("unable to connect to UNIX socket (%s): %s",
+ path, strerror(err));
+ return -1;
+ }
+ return sock;
}
static int
m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr)
{
-if (send(sock, buf, cnt, 0) < 0) {
- int err = errno;
- (void)close(sock);
- *errstr = string_sprintf("unable to send to socket (%s): %s",
- buf, strerror(err));
- return -1;
- }
-return sock;
+ if (send(sock, buf, cnt, 0) < 0) {
+ int err = errno;
+ (void)close(sock);
+ *errstr = string_sprintf("unable to send to socket (%s): %s",
+ buf, strerror(err));
+ return -1;
+ }
+ return sock;
}
/*************************************************
*************************************************/
typedef enum {M_FPROTD, M_DRWEB, M_AVES, M_FSEC, M_KAVD, M_CMDL,
- M_SOPHIE, M_CLAMD, M_MKSD} scanner_t;
+ M_SOPHIE, M_CLAMD, M_SOCK, M_MKSD} scanner_t;
static struct scan
{
scanner_t scancode;
{ M_CMDL, "cmdline", NULL },
{ M_SOPHIE, "sophie", "/var/run/sophie" },
{ M_CLAMD, "clamd", "/tmp/clamd" },
+ { M_SOCK, "sock", "/tmp/malware.sock" },
{ M_MKSD, "mksd", NULL },
{ -1, NULL, NULL } /* end-marker */
};
break;
} /* clamd */
+ 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;
+ }
+
case M_MKSD: /* "mksd" scanner type ------------------------------------- */
{
char *mksd_options_end;
int mksd_maxproc = 1; /* default, if no option supplied */
- struct sockaddr_un server;
int sock;
int retval;