libclamav: add missing symbol

clamav-for-windows: API update
0.96
aCaB 15 years ago
parent 70b3c2cc86
commit 5b9d7d31b9
  1. 8
      win32/clamav-for-windows.vcproj
  2. 311
      win32/clamav-for-windows/clscanapi.h
  3. 237
      win32/clamav-for-windows/interface.c
  4. 53
      win32/clamav-for-windows/main.c
  5. 1
      win32/libclamav.def

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Version="9,00"
Name="clamav-for-windows"
ProjectGUID="{AF1A81DA-5AF3-4D09-BF27-220D539381C7}"
RootNamespace="clamavforwindows"
@ -45,7 +45,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)..\libclamav&quot;;&quot;$(SolutionDir)compat&quot;;&quot;$(SolutionDir)3rdparty\zlib&quot;;&quot;$(SolutionDir)3rdparty\pthreads&quot;;&quot;$(SolutionDir)..&quot;"
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;HAVE_CONFIG_H;_BIND_TO_CURRENT_VCLIBS_VERSION=1"
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;HAVE_CONFIG_H;_BIND_TO_CURRENT_VCLIBS_VERSION=1;CLAMAV_EXPORTS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
@ -68,6 +68,7 @@
Name="VCLinkerTool"
OutputFile="$(OutDir)\clamav.dll"
LinkIncremental="1"
DelayLoadDLLs="libclamav.dll"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="1"
@ -122,7 +123,7 @@
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)..\libclamav&quot;;&quot;$(SolutionDir)compat&quot;;&quot;$(SolutionDir)3rdparty\zlib&quot;;&quot;$(SolutionDir)3rdparty\pthreads&quot;;&quot;$(SolutionDir)..&quot;"
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;HAVE_CONFIG_H;_BIND_TO_CURRENT_VCLIBS_VERSION=1"
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;HAVE_CONFIG_H;_BIND_TO_CURRENT_VCLIBS_VERSION=1;CLAMAV_EXPORTS"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
@ -144,6 +145,7 @@
Name="VCLinkerTool"
OutputFile="$(OutDir)\clamav.dll"
LinkIncremental="1"
DelayLoadDLLs="libclamav.dll"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"

@ -17,159 +17,156 @@
* USA
*/
// Template for 3rd party engines to integrate with Immunet
// TODO: Replace <MOD> with engine specific name
/*
Engine/API Requirements:
R1) Ability to invoke scans
- with callbacks where callback is invoked several times (even during scanning a single PE file). The scan engine could invoke callbacks during the following states:
- state 1: after unpacking (if packed)
- state 2: after emulation (if emulation is supported)
- state 3: after scan is complete
- state 4: after requested action is performed (only in case of infection)
For archive, installers, compound files the callback should be invoked for each file. Each file may cause the callback to be invoked more than once.
- without callbacks, it should be possible to retrieve additional information about file that was scanned
i) infections found after the scan (ex: using MOD_SCAN_INFO_LIST)
ii) Unpacked file (in case the original file was packed)
There probably will be some settings to limit large memory usage in this case. For example, if a large archive file with 1000 infected files
is scanned, it may be unrealistic to return information for all the files. Probably MAX_INFECTION_COUNT setting will exist to limit passing
back such information
R2) The callbacks should be asynchronous (i.e. a separate thread with same engine instance should be able to scan a file without waiting
even when the first file callback has not returned
Use case: Typically, in callback it is expected to make connection to the cloud before taking action. Since, the cloud query can take few ms, it
should be possible for another thread with same engine instance to scan a separate file without any interference.
R3) The disinfection/delete should be supported asynchronously. The engine should be able to perform state 1 to state 3 in sequence and state 4
could be performed at a later stage.
Use case: In case of system scans, drive scans there is a good chance that more than one infection is found. Instead of asking user each time
a list can be generated in the end giving the user the choice to take action. If the user chooses to disinfect/delete the disinfection action
should happen without performing any additional scan.
R4) The definitions should ideally not consume more than 30MB in memory
R5) The scan engine should ideally not consume more than 50ms for scanning individual files in most cases
*/
#ifndef _CLAM_SCAN_API_H
#define _CLAM_SCAN_API_H
#ifndef _CLSCANAPI_H
#define _CLSCANAPI_H
/**************************************************************************************
CLAMAPI interface
***************************************************************************************/
/* CLAMAPI declspec */
#ifdef CLAMAV_EXPORTS
#define CLAMAPI __declspec(dllexport)
#else
#define CLAMAPI __declspec(dllimport)
#endif
/* CLAMAPI calling convention. Please do not touch */
#ifndef CALL_CONVENTION
#define CALL_CONVENTION __cdecl
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: define constants like type of malware, type of object, error code etc here
#define CLAMAPI_SUCCESS 0
#define CLAMAPI_FAILURE 1
#define CLAMAPI_OBJECT_TYPE_FILE 1
#define CLAM_OPTION_SCAN_MODE 0x0
#define CLAM_SCAN_FULL 0x0
#define CLAM_SCAN_LIGHT 0x1
#define CLAM_OPTION_SCAN_ARCHIVE 0x00000001
#define CLAM_OPTION_SCAN_PACKED 0x00000002
#define CLAM_OPTION_SCAN_EMAIL 0x00000004
#define CLAM_OPTION_SCAN_DEEP 0x00000008
/* CLAMAPI - return codes */
/* Always check for the return value of CLAMAPI's
* Possible values are:
* - return_value == CLAMAPI_SUCCESS: API succeded
* - return_value != CLAMAPI_SUCCESS: API failed (call ClamGetErrorMsg(return_value) to retrieve the error message)
*/
#define CLAMAPI_SUCCESS 0
#define CLAMAPI_DISINFECT_ONLY 0x10
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// An example structure that external module should fill. This can be used by Immunet interface either during callback
// or once the scan API function has completed
// TODO: Add any fields as required
typedef struct _CLAM_SCAN_INFO
/* CLAMAPI SCAN OPTIONS */
/* List of options settable via Scan_SetOption and retrievable via Scan_GetOption (see below)
* All the options have a corresponding unsigned int value (0 = option disabled / non 0 = option enabled)
*/
enum CLAM_SCAN_OPTIONS {
CLAM_OPTION_SCAN_ARCHIVE, /* Enable/disable scanning of archive files (zip, arj, rar, cab, etc.) */
CLAM_OPTION_SCAN_MAIL, /* Enable/disable scanning of archive mail files (mbox, eml) */
CLAM_OPTION_SCAN_OLE2, /* Enable/disable scanning of OLE2 files (mostly msi and doc) */
CLAM_OPTION_SCAN_HTML, /* Enable/disable scanning of html files */
CLAM_OPTION_SCAN_PE, /* Enable/disable scanning of archive PE (aka windows) executables */
CLAM_OPTION_SCAN_ALGORITHMIC, /* Enable/disable scanning for certain viruses and exploits */
CLAM_OPTION_SCAN_ELF, /* Enable/disable scanning of archive ELF (aka linux) executables */ /* FIXME: is this needed */
CLAM_OPTION_SCAN_PDF /* Enable/disable scanning of Adobe PDF files */
};
/* NOTE: by default (i.e. before calling Scan_SetOption) ALL the options are ENABLED! */
/* CLAMAPI SCAN PHASES */
/* Define the scan phase to which the returned results refer to */
typedef enum _CLAM_SCAN_PHASE {
SCAN_PHASE_PRESCAN, /* Right before ClamAV starts scanning the current file - in scan callback mode only */
SCAN_PHASE_POSTSCAN, /* After ClamAV has scanned the current file - in scan callback mode only */
SCAN_PHASE_FINAL /* Upon returning from ScanObject */
} CLAM_SCAN_PHASE;
/* CLAMAPI SCAN RESULT VALUES */
/* Value returned by ScanObject */
#define CLAM_CLEAN 0
#define CLAM_INFECTED 1
/* CLAMAPI RESULT DEFINITIONS */
/* The CLAM_SCAN_INFO structure is used:
* - to return scan results
* - to pass progress data and results to the scan callback
*/
typedef struct _CLAM_SCAN_INFO {
/** The size of this structure: to be set to sizeof(CLAM_SCAN_INFO) **/
/* Presence: ALWAYS */
int cbSize;
/** The phase to which the results refer to **/
/* Presence: ALWAYS */
CLAM_SCAN_PHASE scanPhase;
/** Error condition **/
/* Possible values: CLAMAPI_SUCCESS if no error; call ClamGetErrorMsg(errorCode)
* to retrieve the error message */
/* Presence: ALWAYS */
int errorCode;
/** The type of threat (e.g. "Adware", "Trojan", etc.) **/
/* For clean files this is set to NULL */
/* Presence: SCAN_PHASE_POSTSCAN, SCAN_PHASE_FINAL */
const wchar_t *pThreatType;
/** The name of threat (i.e. virus name) **/
/* For clean files this is set to NULL */
/* Presence: SCAN_PHASE_POSTSCAN, SCAN_PHASE_FINAL */
const wchar_t *pThreatName;
/** The handle of the file being processed **/
/* Note #1: the handle MUST NOT BE CLOSED by the callback
* Note #2: the handle has got GENERIC_READ access
* Note #3: the file pointer is guaranteed to be set at the begin of
* the file and its position needs not to be reset
* Note #4: the file may already be mapped into memory, entirely or just partially */
/* Presence: SCAN_PHASE_PRESCAN, SCAN_PHASE_POSTSCAN */
HANDLE object;
/** The path of inner file relative to file being scanned **/
/* This applies only to archive for which internal names can be retrieved and is NULL otherwise */
/* Presence: ALWAYS */
const wchar_t *pInnerObjectPath;
} CLAM_SCAN_INFO, *PCLAM_SCAN_INFO;
/* NOTE: all the objects within the above structure are guaranteed to be available and
* valid until the callback returns (SCAN_PHASE_PRESCAN and SCAN_PHASE_POSTSCAN) or
* Scan_DeleteScanInfo is called (SCAN_PHASE_FINAL) */
/* List of CLAM_SCAN_INFO items */
/* Typical use: If no callback is registered and an archive file is scanned, this list corresponds to each infected file found */
typedef struct _CLAM_SCAN_INFO_LIST
{
// size of this structure
int cbSize;
// Based on this type, pObject field is interpreted
// ex: stream in a compound object, file in an archive, embedded file in installer etc
int objectType;
// archive flags. In case the file being scanned is archive file set the flags accordingly
int archiveFlags;
// compressionFlags flags. In case the file being scanned is packed set the flags accordingly
int compressionFlags;
// installerFlags flags. In case the file being scanned is an installer (MSI, NSIS etc) set the flags accordingly
int installerFlags;
// path to the file being scanned (C:\test.zip)
const wchar_t *pObjectPath;
// path of inner file relative to file being scanned
// valid only for certain object types (ex: installers, compound objects, archive files etc
const wchar_t *pInnerObjectPath;
// a state machine kind of variable
// If a callback is registered, it can be called during any one of the following states
// unpack complete -> emulation complete -> scan complete -> action result complete
int scanStatus;
// status code corresponding to scanStatus
int errorCode;
// interpretation could depend on objectType. Maybe just base pointer to file loaded in memory.
// Can this work for all cases?
void *pObject;
// size of object
unsigned long objectLength;
/* Number of CLAM_SCAN_INFO structures present */
int cbCount;
// type of threat (adware, malware etc)
int threatType;
/* Pointer to first CLAM_SCAN_INFO structure */
PCLAM_SCAN_INFO pInfoList;
} CLAM_SCAN_INFO_LIST, *PCLAM_SCAN_INFO_LIST;
// threatname
const wchar_t *pThreatName;
}CLAM_SCAN_INFO, *PCLAM_SCAN_INFO;
// list of CLAM_SCAN_INFO items
// Typical use: If no callback is registered and an archive file is scanned, this list corresponds to each infected file found
typedef struct _CLAM_SCAN_INFO_LIST
{
// number of CLAM_SCAN_INFO structures present
int cbCount;
// pointer to first CLAM_SCAN_INFO structure
PCLAM_SCAN_INFO pInfoList;
}CLAM_SCAN_INFO_LIST, *PCLAM_SCAN_INFO_LIST;
/**************************************************************************************
CLAMAPI scan callback
***************************************************************************************/
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Callback prototypes
/* SCAN CALLBACK ACTIONS */
/* The following actions can be requested by the scan callback */
typedef enum _CLAM_ACTION {
CLAM_ACTION_CONTINUE, /* Keep on scanning */
CLAM_ACTION_SKIP, /* Skip the current file */
CLAM_ACTION_ABORT /* Early terminate the scan process */
} CLAM_ACTION;
/*
* MANDATORY SUPPORT
* callback that can be registered to be invoked by the scan engine
* Callback that can be registered to be invoked by the scan engine on each inner file.
* Parameters:
* INPUT @param pObjectInfo : all relevant information of the file being scanned
* OUTPUT @param scanAction : action to be taken as determined by callback
* INPUT @param context : any context to be passed to scan callback
*/
typedef void (CALL_CONVENTION *CLAM_SCAN_CALLBACK)(const CLAM_SCAN_INFO *pObjectInfo, int *scanAction, void *context);
typedef void (CALL_CONVENTION *CLAM_SCAN_CALLBACK)(const CLAM_SCAN_INFO *pObjectInfo, CLAM_ACTION *scanAction, void *context);
/*
* OPTIONAL SUPPORT
* callback that can be registered to be invoked by the scan engine
* Parameters:
* INPUT @param objectType : object type
* INPUT @param pObjectName : name of object (typically filename)
* INPUT @param pPassword : input buffer to hold password
* INPUT/OUTPUT @param pPasswordLen : on input consists of length of password buffer. The callback fills this with actual length.
* INPUT @param context : any context to be passed to scan callback
*/
typedef void (CALL_CONVENTION *CLAM_PASSWORD_CALLBACK)(int objectType, const wchar_t *pObjectName, wchar_t *pPassword, int *pPasswordLen, void *context);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Function prototypes
/**************************************************************************************
CLAMAPI functions
***************************************************************************************/
#ifdef __cplusplus
extern "C" {
@ -184,9 +181,10 @@ extern "C" {
* Load scan engine defs
* Parameters:
* INPUT @param pEnginesFolder : path where defs are located
* INPUT @param pTempRoot : path in which temporary files must be created
* INPUT @param pLicenseKey : license key blob
*/
int CLAMAPI Scan_Initialize(const wchar_t *pEnginesFolder, const wchar_t *pLicenseKey);
int CLAMAPI Scan_Initialize(const wchar_t *pEnginesFolder, const wchar_t *pTempRoot, const wchar_t *pLicenseKey);
/*
* MANDATORY SUPPORT
@ -214,11 +212,6 @@ int CLAMAPI Scan_DestroyInstance(CClamAVScanner *pScanner);
/*
* MANDATORY SUPPORT
* Set callback that is invoked when file is being scanned
* The callback can be invoked multiple times while scanning a file
* - state 1: after unpacking (if packed)
* - state 2: after emulation (if emulation is supported)
* - state 3: after scan is complete
* - state 4: after requested action is performed (only in case of infection)
* For archive, installers, compound files the callback should be invoked for each file. Each file can cause the callback to be invoked more than once.
* INPUT @param pScanner : opaque object
* INPUT @param pfnCallback : callback function
@ -226,54 +219,25 @@ int CLAMAPI Scan_DestroyInstance(CClamAVScanner *pScanner);
*/
int CLAMAPI Scan_SetScanCallback(CClamAVScanner *pScanner, CLAM_SCAN_CALLBACK pfnCallback, void *pContext);
/*
* OPTIONAL SUPPORT. Required only if password callbacks are supported
* Set callback that is invoked if the file to be scanned requires password input
* INPUT @param pScanner : opaque object
* INPUT @param pfnCallback : callback function
* INPUT @param pContext : context to be passed to callback function
*/
int CLAMAPI Scan_SetPasswordCallback(CClamAVScanner *pScanner, CLAM_PASSWORD_CALLBACK pfnCallback, void *pContext);
/*
* MANDATORY SUPPORT
* Scan object using path
* INPUT @param pScanner : opaque object
* INPUT @param pObjectPath : path to object
* INPUT @param objectType : object type
* INPUT @param action : attempt cleanup (default action is taken if this is not set and no callback is registered)
* INPUT @param impersonatePID : impersonate the process (incase file is not accessible to current thread)
* OUTPUT @param pScanStatus : indicates status of scan
* OUTPUT @param pInfoList : list containing additional information about file that was scanned
* OUTPUT @param pScanStatus : indicates status of scan (CLAM_CLEAN or CLAM_INFECTED)
* OUTPUT @param pInfoList : list containing additional information about file that was scanned (ONLY valid in *pScanStatus == CLAM_INFECTED)
*/
int CLAMAPI Scan_ScanObject(CClamAVScanner *pScanner, const wchar_t *pObjectPath, int objectType, int action, int impersonatePID, int *pScanStatus, PCLAM_SCAN_INFO_LIST *pInfoList);
int CLAMAPI Scan_ScanObject(CClamAVScanner *pScanner, const wchar_t *pObjectPath, int *pScanStatus, PCLAM_SCAN_INFO_LIST *pInfoList);
/*
* MANDATORY SUPPORT
* Scan object using object handle
* INPUT @param pScanner : opaque object
* INPUT @param pObject : handle to object
* INPUT @param objectType : object type
* INPUT @param action : attempt cleanup (default action is taken if this is not set and no callback is registered)
* INPUT @param impersonatePID : impersonate the process (incase file is not accessible to current thread)
* OUTPUT @param pScanStatus : indicates status of scan
* OUTPUT @param pInfoList : list containing additional information about file that was scanned
*/
int CLAMAPI Scan_ScanObjectByHandle(CClamAVScanner *pScanner, const void *pObject, int objectType, int action, int impersonatePID, int *pScanStatus, PCLAM_SCAN_INFO_LIST *pInfoList);
/*
* OPTIONAL SUPPORT
* Scan object in memory
* INPUT @param pScanner : opaque object
* INPUT @param pObject : handle to object
* INPUT @param objectSize : size of object in memory
* INPUT @param objectType : object type
* INPUT @param action : attempt cleanup (default action is taken if this is not set and no callback is registered)
* INPUT @param impersonatePID : impersonate the process (incase file is not accessible to current thread)
* INPUT @param object : handle to object
* OUTPUT @param pScanStatus : indicates status of scan
* OUTPUT @param pInfoList : list containing additional information about file that was scanned
* OUTPUT @param pInfoList : list containing additional information about file that was scanned (ONLY valid in *pScanStatus == CLAM_INFECTED)
*/
int CLAMAPI Scan_ScanObjectInMemory(CClamAVScanner *pScanner, const void *pObject, unsigned int objectSize, int objectType, int action, int impersonatePID, int *pScanStatus, PCLAM_SCAN_INFO_LIST *pInfoList);
int CLAMAPI Scan_ScanObjectByHandle(CClamAVScanner *pScanner, HANDLE object, int *pScanStatus, PCLAM_SCAN_INFO_LIST *pInfoList);
/*
* MANDATORY SUPPORT
@ -304,10 +268,15 @@ int CLAMAPI Scan_GetOption(CClamAVScanner *pScanner, int option, void *value, un
*/
int CLAMAPI Scan_SetOption(CClamAVScanner *pScanner, int option, void *value, unsigned long inputLength);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
* Convert a ClamAV error code into a string
* INPUT @param errorCode
* NOTE: the returned string is not to be freed!
*/
const wchar_t *ClamGetErrorMsg(int errorCode);
#ifdef __cplusplus
}; /* extern "C" */
#endif
#endif /* _CLAM_SCAN_API_H */
#endif /* _CLSCANAPI_H */

@ -1,3 +1,9 @@
//TODO:
// unify refcounting
// check scan funcs
// after scan returns and ret!=CL_VIRUS pInfoList NULL or unchanged?
// changed set option value to 0 or non 0
/*
* Copyright (C) 2010 Sourcefire, Inc.
* Authors: aCaB <acab@clamav.net>
@ -27,7 +33,7 @@
#include "interface.h"
#define FMT(s) __FUNCTION__": "s"\n"
#define FAIL(fmt, ...) do { logg(FMT(fmt), __VA_ARGS__); return CLAMAPI_FAILURE; } while(0)
#define FAIL(errcode, fmt, ...) do { logg(FMT(fmt), __VA_ARGS__); return (errcode); } while(0)
#define WIN() do { logg("%s completed successfully\n", __FUNCTION__); return CLAMAPI_SUCCESS; } while(0)
HANDLE engine_event; /* refcount = 0 event */
@ -44,20 +50,10 @@ unsigned int engine_refcnt;
#define unlock_engine() do {ReleaseMutex(engine_mutex);} while(0)
BOOL interface_setup(void) {
if(cl_init(CL_INIT_DEFAULT))
return FALSE;
if(!(engine_mutex = CreateMutex(NULL, FALSE, NULL)))
return FALSE;
if(!(engine_event = CreateEvent(NULL, TRUE, TRUE, NULL)))
return FALSE;
logg_verbose = 1;
logg_nowarn = 0;
logg_lock = 0;
logg_time = 1;
logg_size = -1;
logg_file = "C:\\clam4win.log";
logg("ClamAV support initialized\n");
return TRUE;
}
@ -65,13 +61,13 @@ static int load_db(void) {
int ret;
if((ret = cl_load(dbdir, engine, NULL, CL_DB_STDOPT)) != CL_SUCCESS) {
engine = NULL;
FAIL("Failed to load database: %s", cl_strerror(ret));
FAIL(ret, "Failed to load database: %s", cl_strerror(ret));
}
if((ret = cl_engine_compile(engine))) {
cl_engine_free(engine);
engine = NULL;
FAIL("Failed to compile engine: %s", cl_strerror(ret));
FAIL(ret, "Failed to compile engine: %s", cl_strerror(ret));
}
engine_refcnt = 0;
@ -116,23 +112,32 @@ static void free_engine_and_unlock(void) {
unlock_engine();
}
int CLAMAPI Scan_Initialize(const wchar_t *pEnginesFolder, const wchar_t *pLicenseKey) {
int CLAMAPI Scan_Initialize(const wchar_t *pEnginesFolder, const wchar_t *pTempRoot, const wchar_t *pLicenseKey) {
char tmpdir[PATH_MAX];
BOOL cant_convert;
int ret;
if(lock_engine())
FAIL("Engine mutex fail");
FAIL(CL_EMEM, "Engine mutex fail");
if(engine) {
unlock_engine();
FAIL("Already initialized");
FAIL(CL_EARG, "Already initialized");
}
if(!(engine = cl_engine_new())) {
unlock_engine();
FAIL("Not enough memory for a new engine");
FAIL(CL_EMEM, "Not enough memory for a new engine");
}
if(!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pTempRoot, -1, tmpdir, sizeof(tmpdir), NULL, &cant_convert) || cant_convert) {
free_engine_and_unlock();
FAIL(CL_EARG, "Can't translate pTempRoot");
}
if((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, tmpdir))) {
free_engine_and_unlock();
FAIL(ret, "Failed to set engine tempdir: %s", cl_strerror(ret));
}
if(!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pEnginesFolder, -1, dbdir, sizeof(dbdir), NULL, &cant_convert) || cant_convert) {
free_engine_and_unlock();
FAIL("Can't translate pEnginesFolder");
FAIL(CL_EARG, "Can't translate pEnginesFolder");
}
logg("Scan_Initialize(%s)\n", dbdir);
ret = load_db();
@ -148,15 +153,15 @@ int CLAMAPI Scan_Uninitialize(void) {
// }
// logg("%x", rett);
if(lock_engine())
FAIL("Engine mutex fail");
FAIL(CL_EMEM, "Engine mutex fail");
if(!engine) {
unlock_engine();
FAIL("Attempted to uninit a NULL engine");
FAIL(CL_EARG, "Attempted to uninit a NULL engine");
}
if(engine_refcnt) {
volatile unsigned int refs = engine_refcnt;
unlock_engine();
FAIL("Attempted to uninit the engine with %u active instances", engine_refcnt);
FAIL(CL_EARG, "Attempted to uninit the engine with %u active instances", engine_refcnt);
}
free_engine_and_unlock();
WIN();
@ -167,25 +172,26 @@ typedef struct {
void *scancb_ctx;
void *callback2;
LONG refcnt;
int scanmode;
unsigned int scanopts;
} instance;
int CLAMAPI Scan_CreateInstance(CClamAVScanner **ppScanner) {
instance *inst = calloc(1, sizeof(*inst));
if(!inst)
FAIL("CreateInstance: OOM");
FAIL(CL_EMEM, "CreateInstance: OOM");
if(lock_engine()) {
free(inst);
FAIL("Failed to lock engine");
FAIL(CL_EMEM, "Failed to lock engine");
}
if(!engine) {
free(inst);
unlock_engine();
FAIL("Create instance called with no engine");
FAIL(CL_ENULLARG, "Create instance called with no engine");
}
engine_refcnt++;
ResetEvent(engine_event);
unlock_engine();
inst->scanopts = CL_SCAN_STDOPT;
*ppScanner = (CClamAVScanner *)inst;
WIN();
}
@ -194,13 +200,13 @@ int CLAMAPI Scan_DestroyInstance(CClamAVScanner *pScanner) {
instance *inst = (instance *)pScanner;
volatile LONG refcnt = InterlockedCompareExchange(&inst->refcnt, 0, 0);
if(refcnt)
FAIL("Attemped to destroy an instance with active scanners");
FAIL(CL_EARG, "Attemped to destroy an instance with active scanners");
free(pScanner);
if(lock_engine())
FAIL("Failed to lock engine");
FAIL(CL_EMEM, "Failed to lock engine");
if(!engine) {
unlock_engine();
FAIL("Destroy instance called with no engine");
FAIL(CL_ENULLARG, "Destroy instance called with no engine");
}
if(!--engine_refcnt)
SetEvent(engine_event);
@ -217,133 +223,158 @@ int CLAMAPI Scan_SetScanCallback(CClamAVScanner *pScanner, CLAM_SCAN_CALLBACK pf
int CLAMAPI Scan_SetOption(CClamAVScanner *pScanner, int option, void *value, unsigned long inputLength) {
instance *inst = (instance *)pScanner;
unsigned int whichopt, newval;
InterlockedIncrement(&inst->refcnt);
switch(option) {
case CLAM_OPTION_SCAN_MODE: {
int newmode;
if(inputLength != sizeof(int))
FAIL("Bad scanmode value size: %lu", inputLength);
memcpy(&newmode, value, sizeof(int)); /* not sure about alignment */
if(newmode != CLAM_SCAN_FULL && newmode != CLAM_SCAN_LIGHT)
FAIL("Bad scanmode: %d", newmode);
inst->scanmode = newmode;
WIN();
}
case CLAM_OPTION_SCAN_ARCHIVE:
case CLAM_OPTION_SCAN_PACKED:
case CLAM_OPTION_SCAN_EMAIL:
case CLAM_OPTION_SCAN_DEEP:
/* make up my mind */
WIN();
whichopt = CL_SCAN_ARCHIVE;
break;
case CLAM_OPTION_SCAN_MAIL:
whichopt = CL_SCAN_MAIL;
break;
case CLAM_OPTION_SCAN_OLE2:
whichopt = CL_SCAN_OLE2;
break;
case CLAM_OPTION_SCAN_HTML:
whichopt = CL_SCAN_HTML;
break;
case CLAM_OPTION_SCAN_PE:
whichopt = CL_SCAN_PE;
break;
case CLAM_OPTION_SCAN_PDF:
whichopt = CL_SCAN_PDF;
break;
case CLAM_OPTION_SCAN_ALGORITHMIC:
whichopt = CL_SCAN_ALGORITHMIC;
break;
case CLAM_OPTION_SCAN_ELF:
whichopt = CL_SCAN_ELF;
break;
default:
FAIL("Unsupported option: %d", option);
InterlockedDecrement(&inst->refcnt);
FAIL(CL_EARG, "Unsupported set option: %d", option);
}
newval = *(unsigned int *)value;
if(!newval)
inst->scanopts &= ~whichopt;
else
inst->scanopts |= whichopt;
InterlockedDecrement(&inst->refcnt);
WIN();
}
int CLAMAPI Scan_GetOption(CClamAVScanner *pScanner, int option, void *value, unsigned long inputLength, unsigned long *outLength) {
instance *inst = (instance *)pScanner;
switch(option) {
case CLAM_OPTION_SCAN_MODE:
*outLength = sizeof(int);
if(inputLength < sizeof(int)) {
FAIL("Bad scanmode value size: inputLength");
}
memcpy(value, &inst->scanmode, sizeof(int));
WIN();
unsigned int whichopt;
InterlockedIncrement(&inst->refcnt);
switch(option) {
case CLAM_OPTION_SCAN_ARCHIVE:
whichopt = CL_SCAN_ARCHIVE;
break;
case CLAM_OPTION_SCAN_MAIL:
whichopt = CL_SCAN_MAIL;
break;
case CLAM_OPTION_SCAN_OLE2:
whichopt = CL_SCAN_OLE2;
break;
case CLAM_OPTION_SCAN_HTML:
whichopt = CL_SCAN_HTML;
break;
case CLAM_OPTION_SCAN_PE:
whichopt = CL_SCAN_PE;
break;
case CLAM_OPTION_SCAN_PDF:
whichopt = CL_SCAN_PDF;
break;
case CLAM_OPTION_SCAN_ALGORITHMIC:
whichopt = CL_SCAN_ALGORITHMIC;
break;
case CLAM_OPTION_SCAN_ELF:
whichopt = CL_SCAN_ELF;
break;
default:
FAIL("Unsupported option");
InterlockedDecrement(&inst->refcnt);
FAIL(CL_EARG, "Unsupported set option: %d", option);
}
*(unsigned int *)value = (inst->scanopts & whichopt) != 0;
InterlockedDecrement(&inst->refcnt);
WIN();
}
#define CLAM_LIGHT_OPTS (CL_SCAN_STDOPT & ~(CL_SCAN_ARCHIVE | CL_SCAN_MAIL | CL_SCAN_ELF))
#define MAX_VIRNAME_LEN 1024
int CLAMAPI Scan_ScanObject(CClamAVScanner *pScanner, const wchar_t *pObjectPath, int objectType, int action, int impersonatePID, int *pScanStatus, PCLAM_SCAN_INFO_LIST *pInfoList) {
int CLAMAPI Scan_ScanObject(CClamAVScanner *pScanner, const wchar_t *pObjectPath, int *pScanStatus, PCLAM_SCAN_INFO_LIST *pInfoList) {
HANDLE fhdl;
int res;
instance *inst = (instance *)pScanner;
InterlockedIncrement(&inst->refcnt);
if(objectType != CLAMAPI_OBJECT_TYPE_FILE) {
InterlockedDecrement(&inst->refcnt);
FAIL("Unsupported object type: %d", objectType);
}
if((fhdl = CreateFileW(pObjectPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL)) == INVALID_HANDLE_VALUE) {
InterlockedDecrement(&inst->refcnt);
FAIL("open() failed");
FAIL(CL_EOPEN, "open() failed");
}
res = Scan_ScanObjectByHandle(pScanner, &fhdl, objectType, action, impersonatePID, pScanStatus, pInfoList);
res = Scan_ScanObjectByHandle(pScanner, fhdl, pScanStatus, pInfoList);
CloseHandle(fhdl);
InterlockedDecrement(&inst->refcnt);
return res;
}
int CLAMAPI Scan_ScanObjectByHandle(CClamAVScanner *pScanner, const void *pObject, int objectType, int action, int impersonatePID, int *pScanStatus, PCLAM_SCAN_INFO_LIST *pInfoList) {
int CLAMAPI Scan_ScanObjectByHandle(CClamAVScanner *pScanner, HANDLE object, int *pScanStatus, PCLAM_SCAN_INFO_LIST *pInfoList) {
instance *inst = (instance *)pScanner;
HANDLE duphdl, self;
char *virname;
int fd, res;
CLAM_SCAN_INFO_LIST *infolist;
PCLAM_SCAN_INFO scaninfo;
InterlockedIncrement(&inst->refcnt);
if(objectType != CLAMAPI_OBJECT_TYPE_FILE) {
InterlockedDecrement(&inst->refcnt);
FAIL("Unsupported object type: %d", objectType);
}
infolist = calloc(1, sizeof(CLAM_SCAN_INFO_LIST) + sizeof(CLAM_SCAN_INFO) + MAX_VIRNAME_LEN);
if(!infolist) {
InterlockedDecrement(&inst->refcnt);
FAIL("ScanByHandle: OOM");
}
self = GetCurrentProcess();
if(!DuplicateHandle(self, *(HANDLE *)pObject, self, &duphdl, GENERIC_READ, FALSE, 0)) {
if(!DuplicateHandle(self, object, self, &duphdl, GENERIC_READ, FALSE, 0)) {
InterlockedDecrement(&inst->refcnt);
free(infolist);
FAIL("Duplicate handle failed");
FAIL(CL_EDUP, "Duplicate handle failed");
}
if((fd = _open_osfhandle((intptr_t)duphdl, _O_RDONLY)) == -1) {
InterlockedDecrement(&inst->refcnt);
CloseHandle(duphdl);
free(infolist);
FAIL("open handle failed");
FAIL(CL_EOPEN, "Open handle failed");
}
res = cl_scandesc(fd, &virname, NULL, engine, (inst->scanmode == CLAM_SCAN_FULL) ? CL_SCAN_STDOPT : CLAM_LIGHT_OPTS);
res = cl_scandesc(fd, &virname, NULL, engine, inst->scanopts);
InterlockedDecrement(&inst->refcnt);
close(fd);
scaninfo = (PCLAM_SCAN_INFO)(infolist + 1);
infolist->cbCount = 1;
scaninfo->cbSize = sizeof(*scaninfo);
scaninfo->objectType = objectType;
scaninfo->pObjectPath = L"FIXME";
scaninfo->scanStatus = 3;
if(res == CL_VIRUS) {
wchar_t *wvirname = (wchar_t *)(scaninfo + 1);
CLAM_SCAN_INFO_LIST *infolist = calloc(1, sizeof(CLAM_SCAN_INFO_LIST) + sizeof(CLAM_SCAN_INFO) + MAX_VIRNAME_LEN);
PCLAM_SCAN_INFO scaninfo;
wchar_t *wvirname;
if(!infolist)
FAIL(CL_EMEM, "ScanByHandle: OOM");
scaninfo = (PCLAM_SCAN_INFO)(infolist + 1);
infolist->cbCount = 1;
scaninfo->cbSize = sizeof(*scaninfo);
scaninfo->scanPhase = SCAN_PHASE_FINAL;
scaninfo->errorCode = CLAMAPI_SUCCESS;
scaninfo->pThreatType = L"FIXME";
wvirname = (wchar_t *)(scaninfo + 1);
scaninfo->pThreatName = wvirname;
if(!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, virname, -1, wvirname, MAX_VIRNAME_LEN))
scaninfo->pThreatName = L"INFECTED";
logg("FOUND: %s\n", virname);
}
InterlockedDecrement(&inst->refcnt);
if(inst->scancb) {
int cb_act = 0;
inst->scancb(scaninfo, &cb_act, inst->scancb_ctx);
logg("scancb returned %d\n", cb_act);
free(infolist);
} else {
*pInfoList = infolist;
*pScanStatus = CLAM_INFECTED;
} else {
*pInfoList = NULL;
*pScanStatus = CLAM_CLEAN;
}
WIN();
}
@ -354,11 +385,3 @@ int CLAMAPI Scan_DeleteScanInfo(CClamAVScanner *pScanner, PCLAM_SCAN_INFO_LIST p
WIN();
}
int CLAMAPI Scan_SetPasswordCallback(CClamAVScanner *pScanner, CLAM_PASSWORD_CALLBACK pfnCallback, void *pContext) {
FAIL("I DON'T BELONG HERE");
}
int CLAMAPI Scan_ScanObjectInMemory(CClamAVScanner *pScanner, const void *pObject, unsigned int objectSize, int objectType, int action, int impersonatePID, int *pScanStatus, PCLAM_SCAN_INFO_LIST *pInfoList) {
FAIL("I DON'T BELONG HERE");
}

@ -21,17 +21,66 @@
#include "clamav-config.h"
#endif
#include "clamav.h"
#include "shared/output.h"
#include "interface.h"
EXTERN_C IMAGE_DOS_HEADER __ImageBase; /* Reloc safe! */
BOOL init() {
char whereami[PATH_MAX], *slash;
int ret;
ret = GetModuleFileName((HINSTANCE)&__ImageBase, whereami, sizeof(whereami) -1);
if(!ret || ret == sizeof(whereami) -1)
return FALSE;
whereami[sizeof(whereami)-1] = '\0';
slash = strrchr(whereami, '\\');
if(!slash)
return FALSE;
slash++;
*slash='\0';
SetDllDirectory(whereami);
__try {
ret = cl_init(CL_INIT_DEFAULT);
}
__except(EXCEPTION_EXECUTE_HANDLER) { ret = 1; }
SetDllDirectory(NULL);
if(ret)
return FALSE;
strncpy(slash, "clamav.log", sizeof(whereami) - (slash - whereami));
whereami[sizeof(whereami)-1] = '\0';
logg_verbose = 1;
logg_nowarn = 0;
logg_lock = 0;
logg_time = 1;
logg_size = -1;
logg_file = strdup(whereami);
if(!logg_file)
return FALSE;
if(logg("ClamAV core initialized\n"))
return FALSE;
ret = interface_setup();
logg("ClamAV module %s\n", ret == TRUE ? "initialized" : "failed! Aborting...");
return ret;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
return interface_setup();
return init();
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
logg("ClamAV module shutting down\n");
}
return TRUE;
}

@ -118,6 +118,7 @@ EXPORTS cli_hex2str @44262 NONAME
EXPORTS cli_hex2ui @44263 NONAME
EXPORTS mpool_getstats @44264 NONAME
EXPORTS cli_fmap_scandesc @44340
EXPORTS cli_hashset_destroy @44341
; compatibility layer, tommath, zlib
EXPORTS w32_srand @44265 NONAME

Loading…
Cancel
Save