havp/scanners/f-protscanner.cpp
changeset 0 8baf084f58c5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/havp/scanners/f-protscanner.cpp	Wed Jun 18 16:16:36 2014 +0200
@@ -0,0 +1,365 @@
+/***************************************************************************
+                          f-protscanner.cpp  -  description
+                             -------------------
+    begin                : Mit Jun 29 2005
+    copyright            : (C) 2005 by Christian Hilgers
+    email                : christian@hilgers.ag
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include "f-protscanner.h"
+
+
+bool FProtScanner::InitDatabase()
+{
+    return true;
+}
+int FProtScanner::ReloadDatabase()
+{
+    return 0;
+}
+void FProtScanner::FreeDatabase()
+{
+}
+
+
+string FProtScanner::Scan( const char *FileName )
+{
+    if ( Connected == false && ConnectScanner() == false )
+    {
+        ScannerAnswer = "2Could not connect to scanner";
+        return ScannerAnswer;
+    }
+
+    if ( Version == 0 )
+    {
+        Version = TestVersion();
+
+        if ( Version == 0 )
+        {
+            ScannerAnswer = "2Could not connect to scanner";
+            return ScannerAnswer;
+        }
+
+        if ( Connected == false && ConnectScanner() == false )
+        {
+            ScannerAnswer = "2Could not connect to scanner";
+            return ScannerAnswer;
+        }
+    }
+
+    if ( Version == 6 ) return ScanV6( FileName );
+
+    return ScanV4( FileName );
+}
+
+
+string FProtScanner::ScanV6( const char *FileName )
+{
+    //Construct command for scanner
+    ScannerCmd = "SCAN ";
+    ScannerCmd += Opts;
+    ScannerCmd += "FILE ";
+    ScannerCmd += FileName;
+    ScannerCmd += "\n";
+
+    if ( Scanner.Send( ScannerCmd ) == false )
+    {
+        Scanner.Close();
+        Connected = false;
+
+        LogFile::ErrorMessage("%s: Could not call scanner\n", ScannerNameShort.c_str());
+        ScannerAnswer = "2Could not call scanner";
+        return ScannerAnswer;
+    }
+
+    string Response;
+
+    if ( Scanner.GetLine( Response, "\n", 600 ) == false )
+    {
+        Scanner.Close();
+        Connected = false;
+
+        LogFile::ErrorMessage("%s: Could not read scanner response\n", ScannerNameShort.c_str());
+        ScannerAnswer = "2Could not read scanner response";
+        return ScannerAnswer;
+    }
+
+    if ( MatchBegin( Response, "0 ", 2 ) )
+    {
+        ScannerAnswer = "0Clean";
+        return ScannerAnswer;
+    }
+
+    int status = 0;
+    if ( sscanf(Response.substr(0,4).c_str(), "%d ", &status) != 1 ) status = 0;
+
+    if ( status & 1 ||
+         MatchBegin( Response, "1 ", 2 ) ||
+         Response.find("<unwanted") != string::npos )
+    {
+        string VirusName = "unknown";
+
+        string::size_type PosEnd = Response.find( ">" );
+
+        if ( PosEnd != string::npos && PosEnd > 3 )
+        {
+            VirusName = Response.substr( 3, PosEnd - 3 );
+        }
+
+        SearchReplace( VirusName, "contains infected objects: ", "" );
+        SearchReplace( VirusName, "infected: ", "" );
+
+        //Reports "clean" for broken ZIPs with viruses?
+        //Sadly it is the case when MAXSCANSIZE it reached too..
+        if ( VirusName == "clean" ) VirusName = "virus inside archive";
+
+        ScannerAnswer = "1" + VirusName;
+        return ScannerAnswer;
+    }
+
+    //Code 2 for archive bombs etc
+    //Different codes for encrypted files etc, but they are reported "clean"
+    if ( MatchBegin( Response, "2 ", 2 ) ||
+         Response.find("<clean>") != string::npos )
+    {
+        ScannerAnswer = "0Clean";
+        return ScannerAnswer;
+    }
+
+    LogFile::ErrorMessage("%s: Error response: %s\n", ScannerNameShort.c_str(), Response.c_str());
+    ScannerAnswer = "2Scanner error";
+    return ScannerAnswer;
+}
+
+string FProtScanner::ScanV4( const char *FileName )
+{
+    //Construct command for scanner
+    ScannerCmd = "GET ";
+    ScannerCmd += FileName;
+    ScannerCmd += " HTTP/1.0\r\n\r\n";
+
+    if ( Scanner.Send( ScannerCmd ) == false )
+    {
+        Scanner.Close();
+        Connected = false;
+
+        LogFile::ErrorMessage("%s: Could not call scanner\n", ScannerNameShort.c_str());
+        ScannerAnswer = "2Could not call scanner";
+        return ScannerAnswer;
+    }
+
+    string Response;
+    int ret;
+
+    while ( (ret = Scanner.Recv( Response, true, 600 )) != 0 )
+    {
+        if ( ret < 0 )
+        {
+            Scanner.Close();
+            Connected = false;
+
+            LogFile::ErrorMessage("%s: Could not read scanner response\n", ScannerNameShort.c_str());
+            ScannerAnswer = "2Could not read scanner response";
+            return ScannerAnswer;
+        }
+    }
+
+    Scanner.Close();
+    Connected = false;
+
+    string::size_type PositionEnd;
+
+    if ( (PositionEnd = Response.rfind( "</summary>", string::npos )) == string::npos )
+    {
+        LogFile::ErrorMessage("%s: Invalid response from scanner\n", ScannerNameShort.c_str());
+        ScannerAnswer = "2Invalid response from scanner";
+        return ScannerAnswer;
+    }
+
+    string::size_type Position;
+
+    if ( (Position = Response.rfind( ">", PositionEnd )) == string::npos )
+    {
+        LogFile::ErrorMessage("%s: Invalid response from scanner\n", ScannerNameShort.c_str());
+        ScannerAnswer = "2Invalid response from scanner";
+        return ScannerAnswer;
+    }
+
+    string SummaryCode = Response.substr( Position + 1, PositionEnd - (Position + 1) );
+
+    if ( SummaryCode == "clean" )
+    {
+        ScannerAnswer = "0Clean";
+        return ScannerAnswer;
+    }
+    else if ( SummaryCode == "infected" )
+    {
+        if ( (PositionEnd = Response.rfind( "</name>" )) != string::npos )
+        {
+            if ( (Position = Response.rfind( ">", PositionEnd )) == string::npos )
+            {
+                ScannerAnswer = "1Unknown";
+                return ScannerAnswer;
+            }
+
+            ScannerAnswer = "1" + Response.substr( Position+1, PositionEnd - (Position + 1) );
+            return ScannerAnswer;
+        }
+        else if ( (PositionEnd = Response.rfind( "</message>" )) != string::npos )
+        {
+            if ( (Position = Response.rfind( ">", PositionEnd )) == string::npos )
+            {
+                ScannerAnswer = "1Unknown";
+                return ScannerAnswer;
+            }
+
+            ScannerAnswer = "1" + Response.substr( Position+1, PositionEnd - (Position + 1) );
+            return ScannerAnswer;
+        }
+        else
+        {
+            ScannerAnswer = "1Unknown";
+            return ScannerAnswer;
+        }
+    }
+
+    ScannerAnswer = "2Unknown response from scanner";
+    return ScannerAnswer;
+}
+
+
+int FProtScanner::TestVersion()
+{
+    //Construct command for scanner
+    ScannerCmd = "HELP\nQUIT\n";
+
+    if ( Scanner.Send( ScannerCmd ) == false )
+    {
+        Scanner.Close();
+        Connected = false;
+
+        LogFile::ErrorMessage("%s: Could not call scanner\n", ScannerNameShort.c_str());
+        return 0;
+    }
+
+    string Response;
+    int ret = Scanner.Recv( Response, true, 30 );
+
+    Scanner.Close();
+    Connected = false;
+
+    if ( ret < 0 )
+    {
+        LogFile::ErrorMessage("%s: Could not read scanner response\n", ScannerNameShort.c_str());
+        return 0;
+    }
+
+    if ( MatchBegin( Response, "FPSCAND:6", 9 ) )
+    {
+        return 6;
+    }
+    
+    return 4;
+}
+
+
+bool FProtScanner::ConnectScanner()
+{
+    if ( Version == 4 )
+    {
+        if ( Scanner.SetDomainAndPort( ServerHost, ServerPort ) == false )
+        {
+            LogFile::ErrorMessage("%s: Could not resolve scanner host", ScannerNameShort.c_str());
+            return false;
+        }
+    }
+
+    if ( Scanner.ConnectToServer() == false )
+    {
+        if ( Version == 4 )
+        {
+            //Old F-Prot version might be updating, try next port..
+            if ( Scanner.SetDomainAndPort( ServerHost, ServerPort + 1 ) == false )
+            {
+                LogFile::ErrorMessage("%s: Could not resolve scanner host", ScannerNameShort.c_str());
+                return false;
+            }
+        }
+        else
+        {
+            sleep(1);
+        }
+
+        if ( Scanner.ConnectToServer() == false )
+        {
+            Scanner.Close();
+            Connected = false;
+
+            //Prevent log flooding, show error only once per minute
+            if ( (LastError == 0) || (LastError + 60 < time(NULL)) )
+            {
+                LogFile::ErrorMessage("%s: Could not connect to scanner! Scanner down?\n", ScannerNameShort.c_str());
+                LastError = time(NULL);
+            }
+
+            return false;
+        }
+    }
+
+    Connected = true;
+    return true;
+}
+
+
+//Close persistent connection from HAVP scanner initialization
+//Needed because it will fork later
+void FProtScanner::CloseSocket()
+{
+    Scanner.Close();
+    Connected = false;
+}
+
+
+//Constructor
+FProtScanner::FProtScanner()
+{
+    ScannerName = "F-Prot Socket Scanner";
+    ScannerNameShort = "F-Prot";
+
+    LastError = 0;
+    Version = 0;
+    Connected = false;
+
+    ServerHost = Params::GetConfigString("FPROTSERVER");
+    ServerPort = Params::GetConfigInt("FPROTPORT");
+    Version = Params::GetConfigInt("FPROTVERSION");
+
+    Opts = "";
+    if ( Params::GetConfigString("FPROTOPTIONS") != "" )
+    {
+        Opts = Params::GetConfigString("FPROTOPTIONS") + " ";
+    }
+
+    if ( Scanner.SetDomainAndPort( ServerHost, ServerPort ) == false )
+    {
+        LogFile::ErrorMessage("%s: Could not resolve scanner host", ScannerNameShort.c_str());
+    }
+
+    ScannerAnswer.reserve(100);
+}
+
+
+//Destructor
+FProtScanner::~FProtScanner()
+{
+}
+