From 4fdba9ad0059afc62c85e5650dfe8ae99ef77604 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sun, 23 Feb 2014 16:50:31 +0000 Subject: [PATCH] Refactor daemon socket opens Add documentation for "sock" scanner --- doc/doc-docbook/spec.xfpt | 18 +++ doc/doc-txt/ChangeLog | 2 + doc/doc-txt/NewStuff | 5 + src/src/malware.c | 330 ++++++++++++++++---------------------- 4 files changed, 166 insertions(+), 189 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index edb577a11..b8fbb1611 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -29777,6 +29777,24 @@ av_scanner = mksd:2 .endd You can safely omit this option (the default value is 1). +.vitem &%sock%& +.cindex "virus scanners" "simple socket-connected" +This is a general-purpose way of talking to simple scanner daemons +running on the local machine. +There are four options: +an address (which may be an IP addres and port, or the path of a Unix socket), +a commandline to send (may include a single %s which will be replaced with +the path to the mail file to be scanned), +an RE to trigger on from the returned data, +an RE to extract malware_name from the returned data. +For example: +.code +av_scanner = sock:127.0.0.1 6001:%s:(SPAM|VIRUS):(.*)\$ +.endd +Default for the socket specifier is &_/tmp/malware.sock_&. +Default for the commandline is &_%s\n_&. +Both regulat-expressions are required. + .vitem &%sophie%& .cindex "virus scanners" "Sophos and Sophie" Sophie is a daemon that uses Sophos' &%libsavi%& library to scan for viruses. diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index d5c09f4c5..79b46a206 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -32,6 +32,8 @@ JH/02 Add ${listextract {number}{list}{success}{fail}}. TL/03 Bugzilla 1433: Fix DMARC SEGV with specific From header contents. Properly escape header and check for NULL return. +JH/03 Add malware type "sock" for talking to simple daemon. + Exim version 4.82 ----------------- diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 11cfcffa0..a2adb4a90 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -14,6 +14,11 @@ Version 4.83 actual external source IP:host be used in exim instead of the IP of the proxy that is connecting to it. + 2. New malware type "sock". Talks over a Unix or TCP socket, sending one + command line and matching a regex against the return data for trigger + and a second regex to extract malware_name. The mail spoofile name can + be included in the command line. + Version 4.82 ------------ diff --git a/src/src/malware.c b/src/src/malware.c index 959ffe72f..73df68a57 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -26,11 +26,6 @@ typedef struct clamd_address_container { static int mksd_scan_packed(int sock, uschar *scan_filename); static int malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking); -/* SHUT_WR seems to be undefined on Unixware? */ -#ifndef SHUT_WR -# define SHUT_WR 1 -#endif - #ifndef nelements # define nelements(arr) (sizeof(arr) / sizeof(arr[0])) #endif @@ -48,13 +43,13 @@ static int malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) #define DERR_TIMEOUT (1<<9) /* scan timeout has run out */ #define DERR_BAD_CALL (1<<15) /* wrong command */ -/* Routine to check whether a system is big- or litte-endian. +/* Routine to check whether a system is big- or little-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 +static int test_byte_order(void); +static inline int test_byte_order() { short int word = 0x0001; @@ -173,8 +168,9 @@ fprotd_errlog_defer(const uschar * str) return m_scanner_errlog_defer("f-protd", str); } static int -drweb_errlog_defer(const uschar * str) +drweb_errlog_defer(const uschar * str, int fd_to_close) { + (void) close(fd_to_close); return m_scanner_errlog_defer("drweb", str); } static int @@ -188,8 +184,9 @@ fsec_errlog_defer(const uschar * str) return m_scanner_errlog_defer("fsecure", str); } static int -kavd_errlog_defer(const uschar * str) +kavd_errlog_defer(const uschar * str, int fd_to_close) { + if (fd_to_close >= 0) (void) close(fd_to_close); return m_scanner_errlog_defer("kavdaemon", str); } static int @@ -198,8 +195,9 @@ cmdl_errlog_defer(const uschar * str) return m_scanner_errlog_defer("commandline", str); } static int -soph_errlog_defer(const uschar * str) +soph_errlog_defer(const uschar * str, int fd_to_close) { + (void) close(fd_to_close); return m_scanner_errlog_defer("sophie", str); } static int @@ -213,8 +211,9 @@ mksd_errlog_defer(const uschar * str) return m_scanner_errlog_defer("mksd", str); } static int -sock_errlog_defer(const uschar * str) +sock_errlog_defer(const uschar * str, int fd_to_close) { + if (fd_to_close >= 0) (void) close(fd_to_close); return m_scanner_errlog_defer("sock", str); } @@ -281,6 +280,13 @@ m_unixsocket(const uschar * path, uschar ** errstr) return sock; } +static inline int +m_streamsocket(const uschar * spec, uschar ** errstr) +{ + return *spec == '/' + ? m_unixsocket(spec, errstr) : m_tcpsocket_fromdef(spec, errstr); +} + static int m_sock_send(int sock, uschar * buf, int cnt, uschar ** errstr) { @@ -339,24 +345,26 @@ m_pcre_nextinlist(uschar ** list, int * sep, char * listerr, uschar ** errstr) typedef enum {M_FPROTD, M_DRWEB, M_AVES, M_FSEC, M_KAVD, M_CMDL, M_SOPHIE, M_CLAMD, M_SOCK, M_MKSD} scanner_t; +typedef enum {MC_NONE, MC_TCP, MC_UNIX, MC_STRM} contype_t; static struct scan { scanner_t scancode; const uschar * name; const uschar * options_default; + contype_t conn; } m_scans[] = { - { M_FPROTD, US"f-protd", US"localhost 10200-10204" }, - { M_DRWEB, US"drweb", US"/usr/local/drweb/run/drwebd.sock" }, - { M_AVES, US"aveserver", US"/var/run/aveserver" }, - { M_FSEC, US"fsecure", US"/var/run/.fsav" }, - { M_KAVD, US"kavdaemon", US"/var/run/AvpCtl" }, - { M_CMDL, US"cmdline", NULL }, - { M_SOPHIE, US"sophie", US"/var/run/sophie" }, - { M_CLAMD, US"clamd", US"/tmp/clamd" }, - { M_SOCK, US"sock", US"/tmp/malware.sock" }, - { M_MKSD, US"mksd", NULL }, - { -1, NULL, NULL } /* end-marker */ + { M_FPROTD, US"f-protd", US"localhost 10200-10204", MC_TCP }, + { M_DRWEB, US"drweb", US"/usr/local/drweb/run/drwebd.sock", MC_STRM }, + { M_AVES, US"aveserver", US"/var/run/aveserver", MC_UNIX }, + { M_FSEC, US"fsecure", US"/var/run/.fsav", MC_UNIX }, + { M_KAVD, US"kavdaemon", US"/var/run/AvpCtl", MC_UNIX }, + { M_CMDL, US"cmdline", NULL, MC_NONE }, + { M_SOPHIE, US"sophie", US"/var/run/sophie", MC_UNIX }, + { M_CLAMD, US"clamd", US"/tmp/clamd", MC_NONE }, + { M_SOCK, US"sock", US"/tmp/malware.sock", MC_STRM }, + { M_MKSD, US"mksd", NULL, MC_NONE }, + { -1, NULL, NULL, MC_NONE } /* end-marker */ }; /* This is an internal interface for scanning an email; the normal interface @@ -385,6 +393,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) uschar * errstr; struct scan * scanent; const uschar * scanner_options; + int sock = -1; /* make sure the eml mbox file is spooled up */ if (!(mbox_file = spool_mbox(&mbox_size, faking ? eml_filename : NULL))) @@ -429,7 +438,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) malware_ok = FALSE; } - /* Do not scan twice. */ + /* Do not scan twice (unless av_scanner is dynamic). */ if (!malware_ok) { /* find the scanner type from the av_scanner option */ @@ -440,25 +449,32 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) if (!scanent->name) return malware_errlog_defer(string_sprintf("unknown scanner type '%s'", scanner_name)); - if (strcmpic(scanner_name, US scanent->name) == 0) + if (strcmpic(scanner_name, US scanent->name) != 0) + continue; + if (scanent->conn == MC_NONE) break; + if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0))) + scanner_options = scanent->options_default; + switch(scanent->conn) + { + case MC_TCP: sock = m_tcpsocket_fromdef(scanner_options, &errstr); break; + case MC_UNIX: sock = m_unixsocket(scanner_options, &errstr); break; + case MC_STRM: sock = m_streamsocket(scanner_options, &errstr); break; + } + if (sock < 0) + return m_scanner_errlog_defer(scanent->name, errstr); + break; } - if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0))) - scanner_options = scanent->options_default; switch (scanent->scancode) { case M_FPROTD: /* "f-protd" scanner type -------------------------------- */ { uschar *fp_scan_option; unsigned int detected=0, par_count=0; - int sock; uschar * scanrequest; uschar buf[32768], *strhelper, *strhelper2; uschar * malware_name_internal = NULL; - if ((sock = m_tcpsocket_fromdef(scanner_options, &errstr)) < 0) - return fprotd_errlog_defer(errstr); - DEBUG(D_acl) debug_printf("Malware scan: issuing %s GET\n", scanner_name); scanrequest = string_sprintf("GET %s", eml_filename); @@ -489,15 +505,14 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) ? malware_name_internal : NULL; } } - (void)close(sock); break; - } + } /* f-protd */ case M_DRWEB: /* "drweb" scanner type ----------------------------------- */ /* v0.1 - added support for tcp sockets */ /* v0.0 - initial release -- support for unix sockets */ { - int sock, result; + int result; unsigned int fsize; uschar * tmpbuf, *drweb_fbuf; int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd, @@ -505,31 +520,26 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) unsigned long bread; const pcre *drweb_re; - if (*scanner_options != '/') { - if ((sock = m_tcpsocket_fromdef(scanner_options, &errstr)) < 0) - return drweb_errlog_defer(errstr); + /* prepare variables */ + drweb_cmd = htonl(DRWEBD_SCAN_CMD); + drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL); - /* prepare variables */ - drweb_cmd = htonl(DRWEBD_SCAN_CMD); - drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL); + if (*scanner_options != '/') { /* calc file size */ - drweb_fd = open(CS eml_filename, O_RDONLY); - if (drweb_fd == -1) { - int err = errno; - (void)close(sock); + if ((drweb_fd = open(CS eml_filename, O_RDONLY)) == -1) return drweb_errlog_defer( string_sprintf("can't open spool file %s: %s", - eml_filename, strerror(err))); - } - fsize = lseek(drweb_fd, 0, SEEK_END); - if (fsize == -1) { + eml_filename, strerror(errno)), + sock); + + if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1) { int err = errno; - (void)close(sock); (void)close(drweb_fd); return drweb_errlog_defer( string_sprintf("can't seek spool file %s: %s", - eml_filename, strerror(err))); + eml_filename, strerror(err)), + sock); } drweb_slen = htonl(fsize); lseek(drweb_fd, 0, SEEK_SET); @@ -542,50 +552,42 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) (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)) { - (void)close(sock); (void)close(drweb_fd); return drweb_errlog_defer( - string_sprintf("unable to send commands to socket (%s)", scanner_options)); + string_sprintf("unable to send commands to socket (%s)", scanner_options), + sock); } - drweb_fbuf = (uschar *) malloc (fsize); - if (!drweb_fbuf) { - (void)close(sock); + if (!(drweb_fbuf = (uschar *) malloc (fsize))) { (void)close(drweb_fd); return drweb_errlog_defer( string_sprintf("unable to allocate memory %u for file (%s)", - fsize, eml_filename)); + fsize, eml_filename), + sock); } - result = read (drweb_fd, drweb_fbuf, fsize); - if (result == -1) { + if ((result = read (drweb_fd, drweb_fbuf, fsize)) == -1) { int err = errno; - (void)close(sock); (void)close(drweb_fd); free(drweb_fbuf); return drweb_errlog_defer( string_sprintf("can't read spool file %s: %s", - eml_filename, strerror(err))); + eml_filename, strerror(err)), + sock); } (void)close(drweb_fd); /* send file body to socket */ if (send(sock, drweb_fbuf, fsize, 0) < 0) { - (void)close(sock); free(drweb_fbuf); return drweb_errlog_defer( - string_sprintf("unable to send file body to socket (%s)", scanner_options)); + string_sprintf("unable to send file body to socket (%s)", scanner_options), + sock); } (void)close(drweb_fd); } else { - if((sock = m_unixsocket(scanner_options, &errstr)) < 0) - return drweb_errlog_defer(errstr); - - /* prepare variables */ - drweb_cmd = htonl(DRWEBD_SCAN_CMD); - drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL); drweb_slen = htonl(Ustrlen(eml_filename)); DEBUG(D_acl) debug_printf("Malware scan: issuing %s local scan [%s]\n", @@ -596,24 +598,20 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) || (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) || (send(sock, eml_filename, Ustrlen(eml_filename), 0) < 0) || - (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0)) { - (void)close(sock); + (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0)) return drweb_errlog_defer( - string_sprintf("unable to send commands to socket (%s)", scanner_options)); - } + string_sprintf("unable to send commands to socket (%s)", scanner_options), + sock); } /* wait for result */ - if ((bread = recv(sock, &drweb_rc, sizeof(drweb_rc), 0) != sizeof(drweb_rc))) { - (void)close(sock); - return drweb_errlog_defer(US"unable to read return code"); - } + if ((bread = recv(sock, &drweb_rc, sizeof(drweb_rc), 0) != sizeof(drweb_rc))) + return drweb_errlog_defer(US"unable to read return code", sock); drweb_rc = ntohl(drweb_rc); - if ((bread = recv(sock, &drweb_vnum, sizeof(drweb_vnum), 0) != sizeof(drweb_vnum))) { - (void)close(sock); - return drweb_errlog_defer(US"unable to read the number of viruses"); - } + if ((bread = recv(sock, &drweb_vnum, sizeof(drweb_vnum), 0) != sizeof(drweb_vnum))) + return drweb_errlog_defer(US"unable to read the number of viruses", + sock); drweb_vnum = ntohl(drweb_vnum); /* "virus(es) found" if virus number is > 0 */ @@ -631,18 +629,14 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) { int size = 0, off = 0, ovector[10*3]; /* read the size of report */ - if ((bread = recv(sock, &drweb_slen, sizeof(drweb_slen), 0) != sizeof(drweb_slen))) { - (void)close(sock); - return drweb_errlog_defer(US"cannot read report size"); - } + if ((bread = recv(sock, &drweb_slen, sizeof(drweb_slen), 0) != sizeof(drweb_slen))) + return drweb_errlog_defer(US"cannot read report size", sock); drweb_slen = ntohl(drweb_slen); tmpbuf = store_get(drweb_slen); /* read report body */ - if ((bread = recv(sock, tmpbuf, drweb_slen, 0)) != drweb_slen) { - (void)close(sock); - return drweb_errlog_defer(US"cannot read report string"); - } + if ((bread = recv(sock, tmpbuf, drweb_slen, 0)) != drweb_slen) + return drweb_errlog_defer(US"cannot read report string", sock); tmpbuf[drweb_slen] = '\0'; /* try matcher on the line, grab substring */ @@ -676,27 +670,22 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM, * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR * and others are ignored */ - if (drweb_s) { - (void)close(sock); + if (drweb_s) return drweb_errlog_defer( - string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s)); - } + string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s), + sock); + /* no virus found */ malware_name = NULL; } - (void)close(sock); break; - } + } /* drweb */ case M_AVES: /* "aveserver" scanner type -------------------------------- */ { uschar buf[32768]; - int sock; int result; - if((sock = m_unixsocket(scanner_options, &errstr)) < 0) - return aves_errlog_defer(errstr); - /* read aveserver's greeting and see if it is ready (2xx greeting) */ recv_line(sock, buf, sizeof(buf)); @@ -704,7 +693,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* aveserver is having problems */ (void)close(sock); return aves_errlog_defer( - string_sprintf("unavailable (Responded: %s).", ((buf[0] != 0) ? buf : (uschar *)"nothing") )); + string_sprintf("unavailable (Responded: %s).", + ((buf[0] != 0) ? buf : (uschar *)"nothing") )); } /* prepare our command */ @@ -751,15 +741,16 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) ((buf[0] != 0) ? buf : (uschar *)"nothing") )); } - (void)close(sock); - - if (result == DEFER) return DEFER; + if (result == DEFER) { + (void)close(sock); + return DEFER; + } break; - } + } /* aveserver */ case M_FSEC: /* "fsecure" scanner type ---------------------------------- */ { - int sock, i, j, bread = 0; + int i, j, bread = 0; uschar * file_name; uschar av_buffer[1024]; const pcre * fs_inf; @@ -770,16 +761,12 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) malware_name = NULL; - if((sock = m_unixsocket(scanner_options, &errstr)) < 0) - return fsec_errlog_defer(errstr); - DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan [%s]\n", scanner_name, scanner_options); /* pass options */ memset(av_buffer, 0, sizeof(av_buffer)); for (i=0; i != nelements(cmdopt); i++) { - /* debug_printf("send option \"%s\"",cmdopt[i]); */ if (m_sock_send(sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0) return fsec_errlog_defer(errstr); @@ -795,14 +782,11 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) for (j=0;j%s:%s", CS tmpbuf, eml_filename); p = Ustrrchr(scanrequest, '/'); @@ -870,31 +849,25 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* send scan request */ if (m_sock_send(sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0) - return kavd_errlog_defer(errstr); + return kavd_errlog_defer(errstr, -1); /* wait for result */ - if ((bread = recv(sock, tmpbuf, 2, 0) != 2)) { - (void)close(sock); - return kavd_errlog_defer(US"unable to read 2 bytes from socket."); - } + if ((bread = recv(sock, tmpbuf, 2, 0) != 2)) + return kavd_errlog_defer(US"unable to read 2 bytes from socket.", sock); /* get errorcode from one nibble */ kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F; - - /* improper kavdaemon configuration */ - if ( (kav_rc == 5) || (kav_rc == 6) ) { - (void)close(sock); - return kavd_errlog_defer(US"please reconfigure kavdaemon to NOT disinfect or remove infected files."); - } - - if (kav_rc == 1) { - (void)close(sock); - return kavd_errlog_defer(US"reported 'scanning not completed' (code 1)."); - } - - if (kav_rc == 7) { - (void)close(sock); - return kavd_errlog_defer(US"reported 'kavdaemon damaged' (code 7)."); + switch(kav_rc) + { + case 5: case 6: /* improper kavdaemon configuration */ + return kavd_errlog_defer(US"please reconfigure kavdaemon to NOT disinfect or remove infected files.", + sock); + case 1: + return kavd_errlog_defer(US"reported 'scanning not completed' (code 1).", + sock); + case 7: + return kavd_errlog_defer(US"reported 'kavdaemon damaged' (code 7).", + sock); } /* code 8 is not handled, since it is ambigous. It appears mostly on @@ -912,10 +885,8 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) /* read the report, if available */ if( report_flag == 1 ) { /* read report size */ - if ((bread = recv(sock, &kav_reportlen, 4, 0)) != 4) { - (void)close(sock); - return kavd_errlog_defer(US"cannot read report size"); - } + if ((bread = recv(sock, &kav_reportlen, 4, 0)) != 4) + return kavd_errlog_defer(US"cannot read report size", sock); /* it's possible that avp returns av_buffer[1] == 1 but the reportsize is 0 (!?) */ @@ -947,7 +918,6 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) else /* no virus found */ malware_name = NULL; - (void)close(sock); break; } @@ -1059,19 +1029,15 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) else /* no virus found */ malware_name = NULL; break; - } + } /* cmdline */ case M_SOPHIE: /* "sophie" scanner type --------------------------------- */ { int bread = 0; - int sock; uschar *p; uschar * file_name; uschar av_buffer[1024]; - if((sock = m_unixsocket(scanner_options, &errstr)) < 0) - return soph_errlog_defer(errstr); - /* pass the scan directory to sophie */ file_name = string_copy(eml_filename); if ((p = Ustrrchr(file_name, '/'))) @@ -1082,21 +1048,17 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) if ( write(sock, file_name, Ustrlen(file_name)) < 0 || write(sock, "\n", 1) != 1 - ) { - (void)close(sock); + ) return soph_errlog_defer( - string_sprintf("unable to write to UNIX socket (%s)", scanner_options)); - } + string_sprintf("unable to write to UNIX socket (%s)", scanner_options), + sock); /* wait for result */ memset(av_buffer, 0, sizeof(av_buffer)); - if ((!(bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT)) > 0)) { - (void)close(sock); + if ((!(bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT)) > 0)) return soph_errlog_defer( - string_sprintf("unable to read from UNIX socket (%s)", scanner_options)); - } - - (void)close(sock); + string_sprintf("unable to read from UNIX socket (%s)", scanner_options), + sock); /* infected ? */ if (av_buffer[0] == '1') { @@ -1106,9 +1068,10 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) malware_name = string_copy(&av_buffer[2]); } else if (!strncmp(CS av_buffer, "-1", 2)) - return soph_errlog_defer(US"scanner reported error"); + return soph_errlog_defer(US"scanner reported error", sock); else /* all ok, no virus */ malware_name = NULL; + break; } @@ -1127,7 +1090,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) * See Exim bug 926 for details. */ uschar *p, *vname, *result_tag, *response_end; - int sock, bread=0; + int bread=0; unsigned int port; uschar * file_name; uschar av_buffer[1024]; @@ -1242,7 +1205,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) return clmd_errlog_defer(US"all servers failed"); } else { - if((sock = m_unixsocket(scanner_options, &errstr)) < 0) + if ((sock = m_unixsocket(scanner_options, &errstr)) < 0) return clmd_errlog_defer(errstr); } @@ -1425,6 +1388,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) memset(av_buffer, 0, sizeof(av_buffer)); bread = ip_recv(sock, av_buffer, sizeof(av_buffer), MALWARE_TIMEOUT); (void)close(sock); + sock = -1; if (!(bread > 0)) return clmd_errlog_defer( @@ -1522,7 +1486,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) by David Saez and the cmdline code */ { - int sock, bread; + int bread; uschar * commandline; uschar av_buffer[1024]; uschar * linebuffer; @@ -1530,7 +1494,6 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) uschar sockline_scanner_default[] = "%s\n"; const pcre *sockline_trig_re; const pcre *sockline_name_re; - int err; /* find scanner command line */ if ((sockline_scanner = string_nextinlist(&av_scanner_work, &sep, @@ -1539,7 +1502,7 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) char * s = index(CS sockline_scanner, '%'); if (s++) if ((*s != 's' && *s != '%') || index(s+1, '%')) - return sock_errlog_defer(US"unsafe sock scanner call spec"); + return sock_errlog_defer(US"unsafe sock scanner call spec", sock); } else sockline_scanner = sockline_scanner_default; @@ -1548,42 +1511,34 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep, "missing trigger specification", &errstr); if (!sockline_trig_re) - return sock_errlog_defer(errstr); + return sock_errlog_defer(errstr, sock); /* find virus name regex */ sockline_name_re = m_pcre_nextinlist(&av_scanner_work, &sep, "missing virus name regex specification", &errstr); if (!sockline_name_re) - return sock_errlog_defer(errstr); + return sock_errlog_defer(errstr, sock); /* prepare scanner call - security depends on expansions check above */ 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); + return sock_errlog_defer(errstr, -1); /* Read the result */ memset(av_buffer, 0, sizeof(av_buffer)); bread = read(sock, av_buffer, sizeof(av_buffer)); - err = errno; - (void)close(sock); if (!(bread > 0)) return sock_errlog_defer( - string_sprintf("unable to read from socket (%s)", strerror(err))); + string_sprintf("unable to read from socket (%s)", strerror(errno)), + sock); if (bread == sizeof(av_buffer)) - return sock_errlog_defer(US"buffer too small"); + return sock_errlog_defer(US"buffer too small", sock); linebuffer = string_copy(av_buffer); /* try trigger match */ @@ -1621,14 +1576,16 @@ malware_internal(uschar **listptr, uschar *eml_filename, BOOL faking) DEBUG(D_acl) debug_printf("Malware scan: issuing %s scan\n", scanner_name); - retval = mksd_scan_packed(sock, eml_filename); - - if (retval != OK) + if ((retval = mksd_scan_packed(sock, eml_filename)) != OK) { + close (sock); return retval; + } break; } } + if (sock >= 0) + (void) close (sock); malware_ok = TRUE; /* set "been here, done that" marker */ } @@ -1665,7 +1622,7 @@ recv_line(int sock, uschar *buffer, int size) #include -static int +static inline int mksd_writev (int sock, struct iovec *iov, int iovcnt) { int i; @@ -1675,7 +1632,6 @@ mksd_writev (int sock, struct iovec *iov, int iovcnt) i = writev (sock, iov, iovcnt); while ((i < 0) && (errno == EINTR)); if (i <= 0) { - close (sock); malware_errlog(US"unable to write to mksd UNIX socket (/var/run/mksd/socket)"); return -1; } @@ -1694,7 +1650,7 @@ mksd_writev (int sock, struct iovec *iov, int iovcnt) } } -static int +static inline int mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size) { int offset = 0; @@ -1702,7 +1658,6 @@ mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size) do { if ((i = recv (sock, av_buffer+offset, av_buffer_size-offset, 0)) <= 0) { - close (sock); malware_errlog(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)"); return -1; } @@ -1710,7 +1665,6 @@ mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size) offset += i; /* offset == av_buffer_size -> buffer full */ if (offset == av_buffer_size) { - close (sock); malware_errlog(US"malformed reply received from mksd"); return -1; } @@ -1720,7 +1674,7 @@ mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size) return offset; } -static int +static inline int mksd_parse_line (char *line) { char *p; @@ -1770,8 +1724,6 @@ mksd_scan_packed(int sock, uschar *scan_filename) if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer)) < 0) return DEFER; - close (sock); - return mksd_parse_line (CS av_buffer); } -- 2.30.2