6b7abaa7 |
/*
* Copyright (C) 2010 Sourcefire, Inc.
* Authors: aCaB <acab@clamav.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#include "clamav.h" |
23281981 |
#include "others.h" |
6b7abaa7 |
#include "shared/output.h" |
d9641dd3 |
#include "mpool.h" |
6b7abaa7 |
#include "clscanapi.h"
#include "interface.h"
|
4d08b6d6 |
const char *types[] = { |
996fb478 |
"<<rsvd>>", /* 0 */ |
99f01b4b |
"MSEXE", /* 1 */
"HTML", /* 2 */
"HTML_UTF16", /* 3 */
"GRAPHICS", /* 4 */
"TEXT_ASCII", /* 5 */
"TEXT_UTF8", /* 6 */
"TEXT_UTF16LE", /* 7 */
"TEXT_UTF16BE", /* 8 */
"PDF", /* 9 */
"SCRIPT", /* 10 */
"RTF", /* 11 */
"RIFF", /* 12 */
"MSCHM", /* 13 */
"MSCAB", /* 14 */
"MSOLE2", /* 15 */
"MSSZDD", /* 16 */
"ZIP", /* 17 */
"RAR", /* 18 */
"7Z", /* 19 */
"BZ", /* 20 */
"GZ", /* 21 */
"ARJ", /* 22 */
"ZIPSFX", /* 23 */
"RARSFX", /* 24 */
"CABSFX", /* 25 */
"ARJSFX", /* 26 */
"NULSFT", /* 27 */
"AUTOIT", /* 28 */
"ISHIELD_MSI", /* 29 */
"SFX", /* 30 */
"BINHEX", /* 31 */
"MAIL", /* 32 */
"TNEF", /* 33 */
"BINARY_DATA", /* 34 */
"CRYPTFF", /* 35 */
"UUENCODED", /* 36 */
"SCRENC", /* 37 */
"POSIX_TAR", /* 38 */
"OLD_TAR", /* 39 */
"ELF", /* 40 */
"MACHO", /* 41 */
"MACHO_UNIBIN", /* 42 */
"SIS", /* 43 */
"SWF", /* 44 */
"CPIO_ODC", /* 45 */
"CPIO_NEWC", /* 46 */
"CPIO_CRC", /* 47 */ |
a8afbec8 |
NULL |
4d08b6d6 |
};
|
68c3f799 |
int WINAPI SHCreateDirectoryExA(HWND, LPCTSTR, SECURITY_ATTRIBUTES *); /* cannot include Shlobj.h due to DATADIR collision */ |
b81ed285 |
|
c8baa1b9 |
#define FMT(s) "!"__FUNCTION__": "s"\n" |
5b9d7d31 |
#define FAIL(errcode, fmt, ...) do { logg(FMT(fmt), __VA_ARGS__); return (errcode); } while(0) |
f675a85d |
#define WIN() do { logg("*%s completed successfully\n", __FUNCTION__); return CLAMAPI_SUCCESS; } while(0)
#define INFN() do { logg("*in %s\n", __FUNCTION__); } while(0) |
6b7abaa7 |
|
d3c908c7 |
#define MAX_VIRNAME_LEN 1024
|
f26ba7fa |
HANDLE reload_event;
volatile LONG reload_waiters = 0; |
c8abf221 |
|
32952445 |
HANDLE monitor_event;
HANDLE monitor_hdl = NULL;
|
6b7abaa7 |
HANDLE engine_mutex; |
c8abf221 |
/* protects the following items */
struct cl_engine *engine = NULL;
char dbdir[PATH_MAX]; |
219e22e6 |
char tmpdir[PATH_MAX]; |
32952445 |
FILETIME last_chk_time = {0, 0}; |
c8abf221 |
/* end of protected items */
|
7a5baa31 |
typedef struct {
CLAM_SCAN_CALLBACK scancb;
void *scancb_ctx;
unsigned int scanopts; |
4d08b6d6 |
_int64 *filetype; |
7a5baa31 |
} instance;
struct {
instance *inst;
unsigned int refcnt;
} *instances = NULL;
unsigned int ninsts_total = 0;
unsigned int ninsts_avail = 0; |
7c254329 |
unsigned int official_sigs, custom_sigs; |
7a5baa31 |
HANDLE instance_mutex;
|
ff72e2d2 |
BOOL minimal_definitions = FALSE;
|
c8abf221 |
#define lock_engine()(WaitForSingleObject(engine_mutex, INFINITE) == WAIT_FAILED)
#define unlock_engine() do {ReleaseMutex(engine_mutex);} while(0) |
6b7abaa7 |
|
7a5baa31 |
#define lock_instances()(WaitForSingleObject(instance_mutex, INFINITE) == WAIT_FAILED)
#define unlock_instances() do {ReleaseMutex(instance_mutex);} while(0)
|
4d08b6d6 |
cl_error_t filetype_cb(int fd, const char *detected_file_type, void *context); |
b9765d43 |
cl_error_t prescan_cb(int fd, const char *detected_file_type, void *context); |
aa7380df |
cl_error_t postscan_cb(int fd, int result, const char *virname, void *context);
|
32952445 |
DWORD WINAPI monitor_thread(VOID *p) {
char watchme[PATH_MAX];
HANDLE harr[2], fff;
if(lock_engine()) { |
f675a85d |
logg("^monitor_thread: failed to lock engine\n"); |
32952445 |
return 0;
}
snprintf(watchme, sizeof(watchme), "%s\\forcerld", dbdir);
watchme[sizeof(watchme)-1] = '\0';
harr[0] = monitor_event; |
3709a4ce |
harr[1] = FindFirstChangeNotification(dbdir, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME); |
32952445 |
unlock_engine();
if(harr[1] == INVALID_HANDLE_VALUE) { |
1a401901 |
logg("^monitor_thread: failed to monitor directory changes on %s\n", dbdir); |
32952445 |
return 0;
}
|
1a401901 |
logg("monitor_thread: watching directory changes on %s\n", dbdir);
|
32952445 |
while(1) {
WIN32_FIND_DATA wfd;
SYSTEMTIME st;
switch(WaitForMultipleObjects(2, harr, FALSE, INFINITE)) {
case WAIT_OBJECT_0: |
1a401901 |
logg("*monitor_thread: terminating upon request\n"); |
89c78883 |
FindCloseChangeNotification(harr[1]); |
32952445 |
return 0;
case WAIT_OBJECT_0 + 1:
break;
default: |
1a401901 |
logg("*monitor_thread: unexpected wait failure - %u\n", GetLastError()); |
32952445 |
Sleep(1000);
continue;
} |
89c78883 |
FindNextChangeNotification(harr[1]);
if((fff = FindFirstFile(watchme, &wfd)) == INVALID_HANDLE_VALUE) |
32952445 |
continue;
FindClose(fff);
GetSystemTime(&st);
SystemTimeToFileTime(&st, &wfd.ftCreationTime);
if(CompareFileTime(&wfd.ftLastWriteTime, &wfd.ftCreationTime) > 0)
wfd.ftLastWriteTime = wfd.ftCreationTime;
if(CompareFileTime(&wfd.ftLastWriteTime, &last_chk_time) <= 0)
continue;
|
1a401901 |
logg("monitor_thread: reload requested!\n"); |
f66130c9 |
Scan_ReloadDatabase(minimal_definitions); |
32952445 |
GetSystemTime(&st);
SystemTimeToFileTime(&st, &last_chk_time); /* FIXME: small race here */
}
}
|
d3c908c7 |
static wchar_t *threat_type(const char *virname) {
if(!virname)
return NULL;
if(!strncmp(virname, "Trojan", 6))
return L"Trojan";
if(!strncmp(virname, "Worm", 4))
return L"Worm";
if(!strncmp(virname, "Exploit", 7))
return L"Exploit";
if(!strncmp(virname, "Adware", 6))
return L"Adware";
return L"Malware";
}
|
7a5baa31 |
static int add_instance(instance *inst) {
unsigned int i;
INFN();
if(lock_instances()) { |
c8baa1b9 |
logg("!add_instance: failed to lock instances\n"); |
7a5baa31 |
return 1;
}
if(!ninsts_avail) {
void *freeme, *new_instances = calloc(ninsts_total + 256, sizeof(*instances));
if(!new_instances) {
unlock_instances(); |
c8baa1b9 |
logg("!add_instance: failed to grow instances\n"); |
7a5baa31 |
return 1;
}
freeme = instances;
if(instances && ninsts_total)
memcpy(new_instances, instances, ninsts_total * sizeof(*instances));
ninsts_total += 256;
ninsts_avail += 256;
instances = new_instances;
if(freeme)
free(freeme); |
f675a85d |
logg("*add_instance: instances grown to %u\n", ninsts_total); |
7a5baa31 |
}
for(i=0; i<ninsts_total; i++) {
if(instances[i].inst)
continue;
instances[i].inst = inst;
instances[i].refcnt = 0;
ninsts_avail--; |
f675a85d |
logg("*add_instance: now %u/%u instances available\n", ninsts_avail, ninsts_total); |
7a5baa31 |
unlock_instances();
return 0;
} |
c8baa1b9 |
logg("!add_instances: you should not be reading this\n"); |
7a5baa31 |
unlock_instances();
return 1;
}
static int del_instance(instance *inst) {
unsigned int i;
INFN();
if(lock_instances()) { |
c8baa1b9 |
logg("!del_instance: failed to lock instances\n"); |
1f87ea8f |
return CL_ELOCK; |
7a5baa31 |
}
for(i=0; i<ninsts_total; i++) {
if(instances[i].inst != inst)
continue;
if(instances[i].refcnt) { |
f675a85d |
logg("^del_instance: attempted to free instance with %d active scanners\n", instances[i].refcnt); |
7a5baa31 |
unlock_instances(); |
1f87ea8f |
return CL_EBUSY; |
7a5baa31 |
}
instances[i].inst = NULL;
instances[i].refcnt = 0;
ninsts_avail++; |
f675a85d |
logg("*del_instance: %u / %u instances now available\n", ninsts_avail, ninsts_total); |
7a5baa31 |
unlock_instances(); |
1f87ea8f |
return CL_SUCCESS; |
7a5baa31 |
} |
1a401901 |
logg("!del_instances: instance %p not found\n", inst); |
7a5baa31 |
unlock_instances(); |
1f87ea8f |
return CL_EARG; |
7a5baa31 |
}
/* To be called with the instances locked */
static int is_instance(instance *inst) {
unsigned int i;
INFN();
for(i=0; i<ninsts_total; i++)
if(instances[i].inst == inst)
return 1; |
c8baa1b9 |
logg("^is_instance: lookup failed for instance %p\n", inst); |
7a5baa31 |
return 0;
}
|
6b7abaa7 |
BOOL interface_setup(void) {
if(!(engine_mutex = CreateMutex(NULL, FALSE, NULL)))
return FALSE; |
f26ba7fa |
if(!(reload_event = CreateEvent(NULL, TRUE, TRUE, NULL))) { |
7a5baa31 |
CloseHandle(engine_mutex);
return FALSE;
} |
32952445 |
if(!(monitor_event = CreateEvent(NULL, TRUE, FALSE, NULL))) {
CloseHandle(reload_event);
CloseHandle(engine_mutex);
return FALSE;
} |
7a5baa31 |
if(!(instance_mutex = CreateMutex(NULL, FALSE, NULL))) { |
32952445 |
CloseHandle(monitor_event);
CloseHandle(reload_event); |
7a5baa31 |
CloseHandle(engine_mutex); |
6b7abaa7 |
return FALSE; |
7a5baa31 |
} |
6b7abaa7 |
return TRUE;
}
|
88d09f48 |
static int sigload_callback(const char *type, const char *name, unsigned int custom, void *context) { |
f206d31a |
if(!strcmp(type, "fp"))
return 0;
if(minimal_definitions && !custom) |
7a5baa31 |
return 1; |
7c254329 |
if(custom)
custom_sigs++; |
f206d31a |
else |
7c254329 |
official_sigs++; |
7a5baa31 |
return 0;
}
|
48075ec2 |
const char* cli_ctime(const time_t *timep, char *buf, const size_t bufsize); |
32952445 |
/* Must be called with engine_mutex locked ! */ |
48075ec2 |
static void touch_last_update(unsigned signo) { |
32952445 |
char touchme[PATH_MAX];
HANDLE h;
snprintf(touchme, sizeof(touchme), "%s\\lastupd", dbdir);
touchme[sizeof(touchme)-1] = '\0';
if((h = CreateFile(touchme, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) {
DWORD d; |
48075ec2 |
int err;
unsigned ver = (unsigned)cl_engine_get_num(engine, CL_ENGINE_DB_VERSION, &err);
if (ver) {
char timestr[32];
const char *tstr;
time_t t;
t = cl_engine_get_num(engine, CL_ENGINE_DB_TIME, NULL);
tstr = cli_ctime(&t, timestr, sizeof(timestr));
/* cut trailing \n */
timestr[strlen(tstr)-1] = '\0';
snprintf(touchme, sizeof(touchme), "daily %u/%u sigs\n"
"Database version: %u/%s\n"
"Known viruses: %u\n"
"Reloaded at: %d\n",
ver, signo, ver, tstr, signo, (unsigned)time(NULL));
} else {
snprintf(touchme, sizeof(touchme), "no daily/%u sigs\n"
"Known viruses: %u\n"
"Reloaded at: %d\n",
signo, signo, (unsigned)time(NULL));
} |
32952445 |
touchme[sizeof(touchme)-1] = '\0';
if(WriteFile(h, touchme, strlen(touchme), &d, NULL)) {
/* SetEndOfFile(h); */
GetFileTime(h, NULL, NULL, &last_chk_time);
}
CloseHandle(h);
} else |
1a401901 |
logg("^touch_last_lastcheck: failed to touch lastreload\n"); |
32952445 |
}
|
7a5baa31 |
/* Must be called with engine_mutex locked ! */ |
c8abf221 |
static int load_db(void) { |
7a5baa31 |
unsigned int signo = 0; |
32952445 |
size_t used, total;
int ret;
|
1f37f717 |
INFN(); |
7a5baa31 |
cl_engine_set_clcb_sigload(engine, sigload_callback, NULL); |
7c254329 |
official_sigs = custom_sigs = 0; |
d9641dd3 |
if((ret = cl_load(dbdir, engine, &signo, CL_DB_STDOPT & ~CL_DB_PHISHING & ~CL_DB_PHISHING_URLS)) != CL_SUCCESS) { |
bc7db351 |
cl_engine_free(engine); |
c8abf221 |
engine = NULL; |
5b9d7d31 |
FAIL(ret, "Failed to load database: %s", cl_strerror(ret)); |
c8abf221 |
}
if((ret = cl_engine_compile(engine))) {
cl_engine_free(engine);
engine = NULL; |
5b9d7d31 |
FAIL(ret, "Failed to compile engine: %s", cl_strerror(ret)); |
c8abf221 |
}
|
c4190741 |
logg("load_db: loaded %d signatures (%u official, %u custom)\n", signo, official_sigs, custom_sigs); |
32952445 |
if (!mpool_getstats(engine, &used, &total))
logg("load_db: memory %.3f MB / %.3f MB\n", used/(1024*1024.0), total/(1024*1024.0));
|
48075ec2 |
touch_last_update(signo); |
32952445 |
|
c8abf221 |
WIN();
}
|
7c254329 |
int CLAMAPI Scan_HaveSigs(unsigned int *official, unsigned int *custom) {
int ret;
if(lock_engine()) |
f206d31a |
FAIL(CL_ELOCK, "failed to lock engine"); |
7c254329 |
if(!engine) {
unlock_engine(); |
f206d31a |
FAIL(CL_ESTATE, "Engine unavailable"); |
7c254329 |
}
ret = ((official_sigs + custom_sigs) > 0);
if(official) *official = official_sigs;
if(custom) *custom = custom_sigs;
unlock_engine();
return ret;
}
|
6b7abaa7 |
static void free_engine_and_unlock(void) {
cl_engine_free(engine);
engine = NULL;
unlock_engine();
}
|
ff72e2d2 |
int CLAMAPI Scan_Initialize(const wchar_t *pEnginesFolder, const wchar_t *pTempRoot, const wchar_t *pLicenseKey, BOOL bLoadMinDefs) { |
6b7abaa7 |
BOOL cant_convert;
int ret;
|
1a401901 |
logg("*in Scan_Initialize(pEnginesFolder = %S, pTempRoot = %S)\n", pEnginesFolder, pTempRoot); |
7a5baa31 |
if(!pEnginesFolder)
FAIL(CL_ENULLARG, "pEnginesFolder is NULL");
if(!pTempRoot)
FAIL(CL_ENULLARG, "pTempRoot is NULL"); |
6b7abaa7 |
if(lock_engine()) |
1f87ea8f |
FAIL(CL_ELOCK, "failed to lock engine"); |
6b7abaa7 |
if(engine) {
unlock_engine(); |
1f87ea8f |
FAIL(CL_ESTATE, "Already initialized"); |
6b7abaa7 |
} |
7a5baa31 |
|
6b7abaa7 |
if(!(engine = cl_engine_new())) {
unlock_engine(); |
5b9d7d31 |
FAIL(CL_EMEM, "Not enough memory for a new engine");
} |
4d08b6d6 |
cl_engine_set_clcb_pre_cache(engine, filetype_cb);
cl_engine_set_clcb_pre_scan(engine, prescan_cb); |
1f37f717 |
cl_engine_set_clcb_post_scan(engine, postscan_cb); |
ff72e2d2 |
minimal_definitions = bLoadMinDefs;
if(bLoadMinDefs) |
1a401901 |
logg("^MINIMAL DEFINITIONS MODE ON!\n"); |
ff72e2d2 |
|
5b9d7d31 |
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");
} |
23281981 |
ret = strlen(tmpdir);
while(ret>0 && tmpdir[--ret] == '\\')
tmpdir[ret] = '\0';
if(!ret || ret + 8 + 1 >= sizeof(tmpdir)) {
free_engine_and_unlock();
FAIL(CL_EARG, "Bad or too long pTempRoot '%s'", tmpdir);
}
memcpy(&tmpdir[ret+1], "\\clamtmp", 9);
cli_rmdirs(tmpdir); |
68c3f799 |
if((ret = SHCreateDirectoryExA(NULL, tmpdir, NULL) != ERROR_SUCCESS) && ret != ERROR_ALREADY_EXISTS) { |
b81ed285 |
free_engine_and_unlock();
FAIL(CL_ETMPDIR, "Cannot create pTempRoot '%s': error %d", tmpdir, ret); |
23281981 |
} |
5b9d7d31 |
if((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, tmpdir))) {
free_engine_and_unlock(); |
23281981 |
FAIL(ret, "Failed to set engine tempdir to '%s': %s", tmpdir, cl_strerror(ret)); |
6b7abaa7 |
}
if(!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pEnginesFolder, -1, dbdir, sizeof(dbdir), NULL, &cant_convert) || cant_convert) {
free_engine_and_unlock(); |
5b9d7d31 |
FAIL(CL_EARG, "Can't translate pEnginesFolder"); |
6b7abaa7 |
} |
c8abf221 |
ret = load_db(); |
6b7abaa7 |
unlock_engine(); |
32952445 |
|
a183ba35 |
if(!ret) {
ResetEvent(monitor_event);
if(!(monitor_hdl = CreateThread(NULL, 0, monitor_thread, NULL, 0, NULL)))
logg("^Failed to start db monitoring thread\n");
} |
32952445 |
|
f675a85d |
logg("*Scan_Initialize: returning %d\n", ret); |
c8abf221 |
return ret; |
6b7abaa7 |
}
|
5bdde179 |
int uninitialize_called = 0; |
6b7abaa7 |
int CLAMAPI Scan_Uninitialize(void) { |
c8abf221 |
// int rett;
// __asm {
//MOV eax, [ebp + 4]
//mov rett, eax
// }
// logg("%x", rett); |
5bdde179 |
uninitialize_called = 1; |
1f37f717 |
INFN(); |
faea131e |
if(monitor_hdl) {
SetEvent(monitor_event);
if(WaitForSingleObject(monitor_hdl, 5000) != WAIT_OBJECT_0) { |
1a401901 |
logg("^Scan_Uninitialize: forcibly terminating monitor thread after 5 seconds\n"); |
faea131e |
TerminateThread(monitor_hdl, 0);
}
}
monitor_hdl = NULL;
|
a183ba35 |
if(lock_engine())
FAIL(CL_ELOCK, "failed to lock engine");
if(!engine) {
unlock_engine();
FAIL(CL_ESTATE, "attempted to uninit a NULL engine");
}
|
faea131e |
if(lock_instances()) { |
7a5baa31 |
unlock_engine(); |
1f87ea8f |
FAIL(CL_ELOCK, "failed to lock instances"); |
6b7abaa7 |
} |
7a5baa31 |
if(ninsts_avail != ninsts_total) {
volatile unsigned int refcnt = ninsts_total - ninsts_avail;
unlock_instances(); |
6b7abaa7 |
unlock_engine(); |
1f87ea8f |
FAIL(CL_EBUSY, "Attempted to uninit the engine with %u active instances", refcnt); |
6b7abaa7 |
} |
7a5baa31 |
unlock_instances(); |
6b7abaa7 |
free_engine_and_unlock(); |
32952445 |
|
6b7abaa7 |
WIN();
}
int CLAMAPI Scan_CreateInstance(CClamAVScanner **ppScanner) { |
7a5baa31 |
instance *inst;
|
1f37f717 |
INFN(); |
7a5baa31 |
if(!ppScanner)
FAIL(CL_ENULLARG, "NULL pScanner"); |
4d08b6d6 |
inst = (instance *)calloc(1, sizeof(*inst)); |
6b7abaa7 |
if(!inst) |
5b9d7d31 |
FAIL(CL_EMEM, "CreateInstance: OOM"); |
6b7abaa7 |
if(lock_engine()) {
free(inst); |
1f87ea8f |
FAIL(CL_ELOCK, "Failed to lock engine"); |
6b7abaa7 |
}
if(!engine) {
free(inst);
unlock_engine(); |
1f87ea8f |
FAIL(CL_ESTATE, "Create instance called with no engine"); |
6b7abaa7 |
} |
7a5baa31 |
if(add_instance(inst)) {
free(inst);
unlock_engine();
FAIL(CL_EMEM, "add_instance failed");
} |
6b7abaa7 |
unlock_engine(); |
3b35bf25 |
inst->scanopts = CL_SCAN_STDOPT;
if (logg_verbose)
inst->scanopts |= CL_SCAN_PERFORMANCE_INFO; |
6b7abaa7 |
*ppScanner = (CClamAVScanner *)inst; |
1a401901 |
logg("Created new instance %p\n", inst); |
6b7abaa7 |
WIN();
}
|
faea131e |
// Caller: if we return error will retry once after 2 seconds.
// No point in retrying more times since we are shutting down anyway. |
6b7abaa7 |
int CLAMAPI Scan_DestroyInstance(CClamAVScanner *pScanner) { |
1f87ea8f |
int rc; |
1f37f717 |
INFN(); |
7a5baa31 |
if(!pScanner)
FAIL(CL_ENULLARG, "NULL pScanner"); |
faea131e |
if((rc = del_instance((instance *)pScanner))) {
if (rc == CL_EBUSY) {
// wait for one of the scanner threads to finish, and retry again,
// thats better than caller always waiting 2 seconds to retry.
if (WaitForSingleObject(reload_event, 1000) != WAIT_OBJECT_0)
logg("Scan_DestroyInstance: timeout");
rc = del_instance((instance *)pScanner);
}
if (rc)
FAIL(rc, "del_instance failed for %p", pScanner);
} |
6b7abaa7 |
free(pScanner); |
1a401901 |
logg("in Scan_DestroyInstance: Instance %p destroyed\n", pScanner); |
6b7abaa7 |
WIN();
}
int CLAMAPI Scan_SetScanCallback(CClamAVScanner *pScanner, CLAM_SCAN_CALLBACK pfnCallback, void *pContext) { |
7a5baa31 |
instance *inst;
|
f675a85d |
logg("*in SetScanCallback(pScanner = %p, pfnCallback = %p, pContext = %p)\n", pScanner, pfnCallback, pContext); |
7a5baa31 |
if(!pScanner)
FAIL(CL_ENULLARG, "NULL pScanner");
if(lock_instances()) |
1f87ea8f |
FAIL(CL_ELOCK, "failed to lock instances for instance %p", pScanner); |
7a5baa31 |
inst = (instance *)pScanner;
if(is_instance(inst)) {
inst->scancb = pfnCallback;
inst->scancb_ctx = pContext;
unlock_instances();
WIN();
}
unlock_instances();
FAIL(CL_EARG, "invalid instance %p", inst); |
6b7abaa7 |
}
int CLAMAPI Scan_SetOption(CClamAVScanner *pScanner, int option, void *value, unsigned long inputLength) { |
7a5baa31 |
instance *inst; |
5b9d7d31 |
unsigned int whichopt, newval; |
1f37f717 |
INFN(); |
7a5baa31 |
if(!pScanner)
FAIL(CL_ENULLARG, "NULL pScanner");
if(!value)
FAIL(CL_ENULLARG, "NULL value");
if(lock_instances()) |
1f87ea8f |
FAIL(CL_ELOCK, "failed to lock instances"); |
7a5baa31 |
inst = (instance *)pScanner;
if(!is_instance(inst)) {
unlock_instances();
FAIL(CL_EARG, "invalid instance %p", inst);
} |
c8baa1b9 |
newval = *(unsigned int *)value; |
6b7abaa7 |
switch(option) { |
c8abf221 |
case CLAM_OPTION_SCAN_ARCHIVE: |
c8baa1b9 |
logg("CLAM_OPTION_SCAN_ARCHIVE: %s on instance %p\n", newval ? "enabled" : "disabled", inst); |
5b9d7d31 |
whichopt = CL_SCAN_ARCHIVE;
break;
case CLAM_OPTION_SCAN_MAIL: |
c8baa1b9 |
logg("CLAM_OPTION_SCAN_MAIL: %s on instance %p\n", newval ? "enabled" : "disabled", inst); |
5b9d7d31 |
whichopt = CL_SCAN_MAIL;
break;
case CLAM_OPTION_SCAN_OLE2: |
c8baa1b9 |
logg("CLAM_OPTION_SCAN_OLE2: %s on instance %p\n", newval ? "enabled" : "disabled", inst); |
5b9d7d31 |
whichopt = CL_SCAN_OLE2;
break;
case CLAM_OPTION_SCAN_HTML: |
c8baa1b9 |
logg("CLAM_OPTION_SCAN_HTML: %s on instance %p\n", newval ? "enabled" : "disabled", inst); |
5b9d7d31 |
whichopt = CL_SCAN_HTML;
break;
case CLAM_OPTION_SCAN_PE: |
c8baa1b9 |
logg("CLAM_OPTION_SCAN_PE: %s on instance %p\n", newval ? "enabled" : "disabled", inst); |
5b9d7d31 |
whichopt = CL_SCAN_PE;
break;
case CLAM_OPTION_SCAN_PDF: |
c8baa1b9 |
logg("CLAM_OPTION_SCAN_PDF: %s on instance %p\n", newval ? "enabled" : "disabled", inst); |
5b9d7d31 |
whichopt = CL_SCAN_PDF;
break;
case CLAM_OPTION_SCAN_ALGORITHMIC: |
c8baa1b9 |
logg("CLAM_OPTION_SCAN_ALGORITHMIC: %s on instance %p\n", newval ? "enabled" : "disabled", inst); |
5b9d7d31 |
whichopt = CL_SCAN_ALGORITHMIC;
break;
case CLAM_OPTION_SCAN_ELF: |
c8baa1b9 |
logg("CLAM_OPTION_SCAN_ELF: %s on instance %p\n", newval ? "enabled" : "disabled", inst); |
5b9d7d31 |
whichopt = CL_SCAN_ELF;
break; |
1e41fdba |
case CLAM_OPTION_SCAN_SWF:
logg("CLAM_OPTION_SCAN_SWF: %s on instance %p\n", newval ? "enabled" : "disabled", inst);
whichopt = CL_SCAN_SWF;
break; |
6b7abaa7 |
default: |
7a5baa31 |
unlock_instances();
FAIL(CL_EARG, "Unsupported option: %d", option); |
6b7abaa7 |
} |
5b9d7d31 |
if(!newval)
inst->scanopts &= ~whichopt;
else
inst->scanopts |= whichopt; |
7a5baa31 |
unlock_instances(); |
5b9d7d31 |
WIN(); |
6b7abaa7 |
}
int CLAMAPI Scan_GetOption(CClamAVScanner *pScanner, int option, void *value, unsigned long inputLength, unsigned long *outLength) { |
7a5baa31 |
instance *inst; |
5b9d7d31 |
unsigned int whichopt; |
6b7abaa7 |
|
1f37f717 |
INFN(); |
7a5baa31 |
if(!pScanner)
FAIL(CL_ENULLARG, "NULL pScanner");
if(!value || !inputLength)
FAIL(CL_ENULLARG, "NULL value");
if(lock_instances()) |
1f87ea8f |
FAIL(CL_ELOCK, "failed to lock instances"); |
7a5baa31 |
inst = (instance *)pScanner;
if(!is_instance(inst)) {
unlock_instances();
FAIL(CL_EARG, "invalid instance %p", inst);
} |
5b9d7d31 |
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; |
1e41fdba |
case CLAM_OPTION_SCAN_SWF:
whichopt = CL_SCAN_SWF;
break; |
6b7abaa7 |
default: |
7a5baa31 |
unlock_instances();
FAIL(CL_EARG, "Unsupported option: %d", option); |
6b7abaa7 |
} |
5b9d7d31 |
*(unsigned int *)value = (inst->scanopts & whichopt) != 0; |
7a5baa31 |
unlock_instances(); |
5b9d7d31 |
WIN(); |
6b7abaa7 |
}
|
d4afcf98 |
int CLAMAPI Scan_GetLimit(int option, unsigned int *value) {
enum cl_engine_field limit;
long long curlimit;
int err;
INFN();
if(lock_engine()) |
1f87ea8f |
FAIL(CL_ELOCK, "Failed to lock engine"); |
d4afcf98 |
if(!engine) {
unlock_engine(); |
1f87ea8f |
FAIL(CL_ESTATE, "Engine is NULL"); |
d4afcf98 |
}
switch((enum CLAM_LIMIT_TYPE)option) {
case CLAM_LIMIT_FILESIZE:
limit = CL_ENGINE_MAX_FILESIZE;
break;
case CLAM_LIMIT_SCANSIZE:
limit = CL_ENGINE_MAX_SCANSIZE;
break;
case CLAM_LIMIT_RECURSION:
limit = CL_ENGINE_MAX_SCANSIZE;
break;
default:
unlock_engine();
FAIL(CL_EARG, "Unsupported limit type: %d", option);
}
curlimit = cl_engine_get_num(engine, limit, &err);
if(err) {
unlock_engine();
FAIL(err, "Failed to get engine value: %s", cl_strerror(err));
}
if(curlimit > 0xffffffff)
*value = 0xffffffff;
else
*value = (unsigned int)curlimit;
unlock_engine();
WIN();
}
int CLAMAPI Scan_SetLimit(int option, unsigned int value) {
enum cl_engine_field limit;
int err;
INFN();
if(lock_engine()) |
1f87ea8f |
FAIL(CL_ELOCK, "Failed to lock engine"); |
d4afcf98 |
if(!engine) {
unlock_engine(); |
1f87ea8f |
FAIL(CL_ESTATE, "Engine is NULL"); |
d4afcf98 |
}
switch((enum CLAM_LIMIT_TYPE)option) {
case CLAM_LIMIT_FILESIZE: |
f675a85d |
logg("CLAM_LIMIT_FILESIZE: set to %u\n", value); |
d4afcf98 |
limit = CL_ENGINE_MAX_FILESIZE;
break;
case CLAM_LIMIT_SCANSIZE: |
f675a85d |
logg("CLAM_LIMIT_SCANSIZE: set to %u\n", value); |
d4afcf98 |
limit = CL_ENGINE_MAX_SCANSIZE;
break;
case CLAM_LIMIT_RECURSION: |
f675a85d |
logg("CLAM_LIMIT_RECURSION: set to %u\n", value); |
d4afcf98 |
limit = CL_ENGINE_MAX_SCANSIZE;
break;
default:
unlock_engine();
FAIL(CL_EARG, "Unsupported limit type: %d", option);
}
err = cl_engine_set_num(engine, limit, (long long)value);
unlock_engine();
if(err)
FAIL(err, "Failed to set engine value: %s", cl_strerror(err));
WIN();
}
|
cf85afda |
static wchar_t *uncpathw(const wchar_t *path) {
DWORD len = 0;
unsigned int pathlen;
wchar_t *stripme, *strip_from, *dest = malloc((PATH_MAX + 1) * sizeof(wchar_t));
if(!dest)
return NULL;
pathlen = wcslen(path);
if(wcsncmp(path, L"\\\\", 2)) {
/* NOT already UNC */
memcpy(dest, L"\\\\?\\", 8);
if(pathlen < 2 || path[1] != L':' || *path < L'A' || *path > L'z' || (*path > L'Z' && *path < L'a')) {
/* Relative path */
len = GetCurrentDirectoryW(PATH_MAX - 5, &dest[4]);
if(!len || len > PATH_MAX - 5) {
free(dest);
return NULL;
}
if(*path == L'\\')
len = 6; /* Current drive root */
else {
len += 4; /* A 'really' relative path */
dest[len] = L'\\';
len++;
}
} else {
/* C:\ and friends */
len = 4;
}
} else {
/* UNC already */
len = 0;
}
if(pathlen >= PATH_MAX - len) {
free(dest);
return NULL;
}
wcscpy(&dest[len], path);
len = wcslen(dest);
strip_from = &dest[3];
/* append a backslash to naked drives and get rid of . and .. */
if(!wcsncmp(dest, L"\\\\?\\", 4) && (dest[5] == L':') && ((dest[4] >= L'A' && dest[4] <= L'Z') || (dest[4] >= L'a' && dest[4] <= L'z'))) {
if(len == 6) {
dest[6] = L'\\';
dest[7] = L'\0';
}
strip_from = &dest[6];
}
while((stripme = wcsstr(strip_from, L"\\."))) {
wchar_t *copy_from, *copy_to;
if(!stripme[2] || stripme[2] == L'\\') {
copy_from = &stripme[2];
copy_to = stripme;
} else if (stripme[2] == L'.' && (!stripme[3] || stripme[3] == L'\\')) {
*stripme = L'\0';
copy_from = &stripme[3];
copy_to = wcsrchr(strip_from, L'\\');
if(!copy_to)
copy_to = stripme;
} else {
strip_from = &stripme[1];
continue;
}
while(1) {
*copy_to = *copy_from;
if(!*copy_from) break;
copy_to++;
copy_from++;
}
}
/* strip double slashes */
if((stripme = wcsstr(&dest[4], L"\\\\"))) {
strip_from = stripme;
while(1) {
wchar_t c = *strip_from;
strip_from++;
if(c == L'\\' && *strip_from == L'\\')
continue;
*stripme = c;
stripme++;
if(!c)
break;
}
}
if(wcslen(dest) == 6 && !wcsncmp(dest, L"\\\\?\\", 4) && (dest[5] == L':') && ((dest[4] >= L'A' && dest[4] <= L'Z') || (dest[4] >= L'a' && dest[4] <= L'z'))) {
dest[6] = L'\\';
dest[7] = L'\0';
}
return dest;
}
|
5b9d7d31 |
int CLAMAPI Scan_ScanObject(CClamAVScanner *pScanner, const wchar_t *pObjectPath, int *pScanStatus, PCLAM_SCAN_INFO_LIST *pInfoList) { |
6b7abaa7 |
HANDLE fhdl;
int res; |
c8abf221 |
instance *inst = (instance *)pScanner; |
6b7abaa7 |
|
f675a85d |
logg("*in Scan_ScanObject(pScanner = %p, pObjectPath = %S)\n", pScanner, pObjectPath); |
8557628a |
if((fhdl = CreateFileW(pObjectPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL)) == INVALID_HANDLE_VALUE) { |
cf85afda |
wchar_t *uncfname = uncpathw(pObjectPath);
if(!uncfname)
FAIL(CL_EMEM, "uncpathw() failed"); |
8557628a |
fhdl = CreateFileW(uncfname, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL); |
cf85afda |
logg("*Scan_ScanObject translating '%S' to '%S'\n", pObjectPath, uncfname);
free(uncfname);
if(fhdl == INVALID_HANDLE_VALUE)
FAIL(CL_EOPEN, "open() failed");
} |
f675a85d |
logg("*Scan_ScanObject (instance %p) invoking Scan_ScanObjectByHandle for handle %p (%S)\n", pScanner, fhdl, pObjectPath); |
5b9d7d31 |
res = Scan_ScanObjectByHandle(pScanner, fhdl, pScanStatus, pInfoList); |
f675a85d |
logg("*Scan_ScanObject (instance %p) invoking Scan_ScanObjectByHandle returned %d\n", pScanner, res); |
6b7abaa7 |
CloseHandle(fhdl);
return res;
}
|
aa7380df |
struct scan_ctx {
int entryfd;
instance *inst; |
593e71c0 |
DWORD cb_times; |
cefb07dc |
DWORD copy_times; |
aa7380df |
};
|
5b9d7d31 |
int CLAMAPI Scan_ScanObjectByHandle(CClamAVScanner *pScanner, HANDLE object, int *pScanStatus, PCLAM_SCAN_INFO_LIST *pInfoList) { |
7a5baa31 |
instance *inst; |
6b7abaa7 |
HANDLE duphdl, self; |
9f3ff0a4 |
char *virname = NULL; |
6b7abaa7 |
int fd, res; |
7a5baa31 |
unsigned int i; |
aa7380df |
struct scan_ctx sctx; |
c8baa1b9 |
DWORD perf; |
c8abf221 |
|
f675a85d |
logg("*in Scan_ScanObjectByHandle(pScanner = %p, HANDLE = %p, pScanStatus = %p, pInfoList = %p)\n", pScanner, object, pScanStatus, pInfoList); |
7a5baa31 |
if(!pScanner)
FAIL(CL_ENULLARG, "NULL pScanner");
if(!pScanStatus) |
c8baa1b9 |
FAIL(CL_ENULLARG, "NULL pScanStatus on instance %p", pScanner); |
6b7abaa7 |
self = GetCurrentProcess(); |
7a5baa31 |
if(!DuplicateHandle(self, object, self, &duphdl, GENERIC_READ, FALSE, 0)) |
c8baa1b9 |
FAIL(CL_EDUP, "Duplicate handle failed for instance %p", pScanner); |
6b7abaa7 |
if((fd = _open_osfhandle((intptr_t)duphdl, _O_RDONLY)) == -1) {
CloseHandle(duphdl); |
c8baa1b9 |
FAIL(CL_EOPEN, "Open handle failed for instance %p", pScanner); |
6b7abaa7 |
}
|
7a5baa31 |
if(lock_instances()) {
close(fd); |
1f87ea8f |
FAIL(CL_ELOCK, "failed to lock instances for instance %p", pScanner); |
7a5baa31 |
}
inst = (instance *)pScanner;
for(i=0; i<ninsts_total; i++) {
if(instances[i].inst == inst)
break;
}
if(i == ninsts_total) {
unlock_instances();
close(fd);
FAIL(CL_EARG, "invalid instance %p", inst);
}
instances[i].refcnt++; |
219e22e6 |
ResetEvent(reload_event); |
7a5baa31 |
unlock_instances();
|
aa7380df |
sctx.entryfd = fd;
sctx.inst = inst; |
593e71c0 |
sctx.cb_times = 0; |
cefb07dc |
sctx.copy_times = 0; |
f675a85d |
logg("*Scan_ScanObjectByHandle (instance %p) invoking cl_scandesc with clamav context %p\n", inst, &sctx); |
c8baa1b9 |
perf = GetTickCount(); |
aa7380df |
res = cl_scandesc_callback(fd, &virname, NULL, engine, inst->scanopts, &sctx); |
c31cb63d |
|
4d08b6d6 |
if(!inst->filetype) do { |
c31cb63d |
CLAM_SCAN_INFO si;
CLAM_ACTION act;
DWORD cbperf; |
8aacea51 |
wchar_t wvirname[MAX_VIRNAME_LEN] = L"Clam."; |
c31cb63d |
LONG lo = 0, hi = 0, hi2 = 0;
si.cbSize = sizeof(si);
si.flags = 0;
si.scanPhase = SCAN_PHASE_FINAL;
si.errorCode = CLAMAPI_SUCCESS;
if(res == CL_VIRUS) { |
8aacea51 |
if(MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, virname, -1, &wvirname[5], MAX_VIRNAME_LEN - 5)) |
c31cb63d |
si.pThreatName = wvirname;
else |
b4053863 |
si.pThreatName = L"Clam.UNOFFICIAL"; |
c31cb63d |
} else
si.pThreatName = NULL; |
f675a85d |
logg("*in final_cb with clamav context %p, instance %p, fd %d, result %d, virusname %S)\n", &sctx, inst, fd, res, si.pThreatName); |
c31cb63d |
si.pThreatType = threat_type(virname); |
1aff6a35 |
si.object = INVALID_HANDLE_VALUE;
si.objectId = INVALID_HANDLE_VALUE; |
c31cb63d |
si.pInnerObjectPath = NULL;
lo = SetFilePointer(duphdl, 0, &hi, FILE_CURRENT);
SetFilePointer(duphdl, 0, &hi2, FILE_BEGIN); |
f675a85d |
logg("*final_cb (clamav context %p, instance %p) invoking callback %p with context %p\n", &sctx, inst, inst->scancb, inst->scancb_ctx); |
c31cb63d |
cbperf = GetTickCount();
inst->scancb(&si, &act, inst->scancb_ctx);
cbperf = GetTickCount() - cbperf; |
593e71c0 |
sctx.cb_times += cbperf; |
f675a85d |
logg("*final_cb (clamav context %p, instance %p) callback completed with %u (result ignored) in %u ms\n", &sctx, inst, act, cbperf); |
c31cb63d |
SetFilePointer(duphdl, lo, &hi, FILE_BEGIN);
} while(0);
|
c8baa1b9 |
perf = GetTickCount() - perf; |
6b7abaa7 |
close(fd); |
45684758 |
logg("*Scan_ScanObjectByHandle (instance %p): cl_scandesc returned %d in %u ms (%d ms own, %d ms copy)\n", inst, res, perf, perf - sctx.cb_times - sctx.copy_times, sctx.copy_times); |
6b7abaa7 |
|
7a5baa31 |
if(lock_instances()) |
1f87ea8f |
FAIL(CL_ELOCK, "failed to lock instances for instance %p", pScanner); |
7a5baa31 |
instances[i].refcnt--; |
219e22e6 |
if(!instances[i].refcnt)
SetEvent(reload_event); |
7a5baa31 |
unlock_instances();
|
6b7abaa7 |
if(res == CL_VIRUS) { |
1a401901 |
logg("Scan_ScanObjectByHandle (instance %p): file is INFECTED with %s\n", inst, virname); |
7a5baa31 |
if(pInfoList) { |
4d08b6d6 |
CLAM_SCAN_INFO_LIST *infolist = (CLAM_SCAN_INFO_LIST *)calloc(1, sizeof(CLAM_SCAN_INFO_LIST) + sizeof(CLAM_SCAN_INFO) + MAX_VIRNAME_LEN * 2); |
7a5baa31 |
PCLAM_SCAN_INFO scaninfo;
wchar_t *wvirname;
if(!infolist) |
c8baa1b9 |
FAIL(CL_EMEM, "ScanByHandle (instance %p): OOM while allocating result list", inst); |
7a5baa31 |
scaninfo = (PCLAM_SCAN_INFO)(infolist + 1);
infolist->cbCount = 1;
scaninfo->cbSize = sizeof(*scaninfo);
scaninfo->scanPhase = SCAN_PHASE_FINAL;
scaninfo->errorCode = CLAMAPI_SUCCESS; |
d3c908c7 |
scaninfo->pThreatType = threat_type(virname); |
1aff6a35 |
scaninfo->object = INVALID_HANDLE_VALUE;
scaninfo->objectId = INVALID_HANDLE_VALUE; |
7a5baa31 |
wvirname = (wchar_t *)(scaninfo + 1);
scaninfo->pThreatName = wvirname; |
8aacea51 |
memcpy(wvirname, L"Clam.", 10);
if(!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, virname, -1, &wvirname[5], MAX_VIRNAME_LEN-5)) |
b4053863 |
scaninfo->pThreatName = L"Clam.UNOFFICIAL"; |
7a5baa31 |
*pInfoList = infolist; |
1a401901 |
logg("*Scan_ScanObjectByHandle (instance %p): created result list %p\n", inst, infolist); |
7a5baa31 |
} |
5b9d7d31 |
*pScanStatus = CLAM_INFECTED; |
c8baa1b9 |
} else if(res == CL_CLEAN) { |
f675a85d |
logg("*Scan_ScanObjectByHandle (instance %p): file is CLEAN\n", inst); |
7a5baa31 |
if(pInfoList) *pInfoList = NULL; |
5b9d7d31 |
*pScanStatus = CLAM_CLEAN; |
c8baa1b9 |
} else {
FAIL(res, "Scan failed for instance %p: %s", inst, cl_strerror(res)); |
6b7abaa7 |
}
WIN();
}
|
4d08b6d6 |
int CLAMAPI Scan_GetFileType(HANDLE hFile, _int64 *filetype) {
instance *inst;
int status, ret = Scan_CreateInstance((CClamAVScanner **)&inst); |
8bf75982 |
logg("*in Scan_GetFileType(HANDLE = %x, filetype = %p)\n", hFile, filetype);
if(ret != CLAMAPI_SUCCESS) {
FAIL(ret, "Failed to create instance, error %d", ret);
} |
4d08b6d6 |
inst->filetype = filetype;
ret = Scan_ScanObjectByHandle((CClamAVScanner *)inst, hFile, &status, NULL); |
8bf75982 |
logg("Scan_GetFileType: Scan_ScanObjectByHandle returned %d, type %016llx%016llx\n", ret, filetype[1], filetype[0]); |
4d08b6d6 |
Scan_DestroyInstance((CClamAVScanner *)inst);
return ret;
} |
6b7abaa7 |
int CLAMAPI Scan_DeleteScanInfo(CClamAVScanner *pScanner, PCLAM_SCAN_INFO_LIST pInfoList) { |
f675a85d |
logg("*in Scan_DeleteScanInfo(pScanner = %p, pInfoList = %p)\n", pScanner, pInfoList); |
7a5baa31 |
if(!pScanner)
FAIL(CL_ENULLARG, "NULL pScanner");
if(!pInfoList)
FAIL(CL_ENULLARG, "NULL pInfoList");
/* FIXME checking this is pointelss as the infolist is independent from pscanner */
// if(lock_instances())
//FAIL(CL_EMEM, "failed to lock instances");
// inst = (instance *)pScanner;
// if(!is_instance(inst)) {
//unlock_instances();
//FAIL(CL_EARG, "invalid instance");
// }
// unlock_instances();
|
6b7abaa7 |
free(pInfoList);
WIN();
} |
c8abf221 |
|
a8afbec8 |
static void ftype_bits(const char *type, _int64 *filetype) {
int i; |
8bf75982 |
if(!strncmp(type, "CL_TYPE_", 8)) { |
99f01b4b |
for(i=1; types[i]; i++) { |
a8afbec8 |
if(!strcmp(&type[8], types[i]))
break;
}
if(!types[i]) i = -1;
} else
i = -1;
if(i<0) {
filetype[0] = 0;
filetype[1] = 0;
} else if(i<64) {
filetype[0] = 1LL << i;
filetype[1] = 0;
} else {
filetype[0] = 0;
filetype[1] = 1LL << (i-64);
} |
8bf75982 |
logg("*ftype_bits setting type to %016llx%016llx\n", filetype[1], filetype[0]); |
a8afbec8 |
}
|
4d08b6d6 |
cl_error_t filetype_cb(int fd, const char *type, void *context) {
struct scan_ctx *sctx = (struct scan_ctx *)context;
if(sctx && sctx->inst && sctx->inst->filetype) { |
a8afbec8 |
ftype_bits(type, sctx->inst->filetype); |
8bf75982 |
logg("*in filetype_cb with clamav context %p, instance %p, fd %d, type %s, typenum %016llx%016llx)\n", context, sctx->inst, fd, type, sctx->inst->filetype[1], sctx->inst->filetype[0]); |
4d08b6d6 |
return CL_BREAK;
}
return CL_CLEAN;
}
|
b9765d43 |
cl_error_t prescan_cb(int fd, const char *type, void *context) { |
aa7380df |
struct scan_ctx *sctx = (struct scan_ctx *)context; |
8038c673 |
char tmpf[4096]; |
c8baa1b9 |
instance *inst; |
aa7380df |
CLAM_SCAN_INFO si;
CLAM_ACTION act; |
7a5baa31 |
HANDLE fdhdl; |
cefb07dc |
DWORD perf, perf2 = 0; |
aa7380df |
|
c8baa1b9 |
if(!context) {
logg("!prescan_cb called with NULL clamav context\n");
return CL_CLEAN;
}
inst = sctx->inst; |
4d08b6d6 |
if(inst && inst->filetype)
return CL_CLEAN; /* Just in case, this shouldn't happen */
|
b9765d43 |
logg("*in prescan_cb with clamav context %p, instance %p, fd %d, type %s)\n", context, inst, fd, type); |
a8afbec8 |
ftype_bits(type, si.filetype); |
aa7380df |
si.cbSize = sizeof(si);
si.flags = 0;
si.scanPhase = (fd == sctx->entryfd) ? SCAN_PHASE_INITIAL : SCAN_PHASE_PRESCAN;
si.errorCode = CLAMAPI_SUCCESS;
si.pThreatType = NULL;
si.pThreatName = NULL;
si.pInnerObjectPath = NULL; |
7a5baa31 |
|
1aff6a35 |
if(si.scanPhase == SCAN_PHASE_PRESCAN) {
long fpos;
int rsz; |
45684758 |
perf2 = GetTickCount(); |
1aff6a35 |
while(1) {
static int tmpn;
snprintf(tmpf, sizeof(tmpf), "%s\\%08x.tmp", tmpdir, ++tmpn);
tmpf[sizeof(tmpf)-1] = '\0'; |
694a6384 |
fdhdl = CreateFile(tmpf, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); |
1aff6a35 |
if(fdhdl != INVALID_HANDLE_VALUE) {
logg("*prescan_cb: dumping content to tempfile %s (handle %p)\n", tmpf, fdhdl);
break;
}
if((perf = GetLastError()) != ERROR_FILE_EXISTS) {
logg("!prescan_cb: failed to create tempfile %s - error %u\n", tmpf, perf);
return CL_CLEAN;
} |
cf6c69a0 |
} |
8038c673 |
|
1aff6a35 |
fpos = lseek(fd, 0, SEEK_CUR);
lseek(fd, 0, SEEK_SET);
while((rsz = read(fd, tmpf, sizeof(tmpf))) > 0) {
int wsz = 0;
while(wsz != rsz) {
DWORD rwsz;
if(!WriteFile(fdhdl, &tmpf[wsz], rsz - wsz, &rwsz, NULL)) {
logg("!prescan_cb: failed to write to tempfile %s - error %u\n", GetLastError());
lseek(fd, fpos, SEEK_SET);
CloseHandle(fdhdl);
return CL_CLEAN;
}
wsz += rwsz; |
8038c673 |
} |
cf6c69a0 |
} |
1aff6a35 |
if(rsz) {
logg("!prescan_cb: failed to read from clamav tempfile - errno = %d\n", errno);
lseek(fd, fpos, SEEK_SET);
CloseHandle(fdhdl);
return CL_CLEAN;
} |
cf6c69a0 |
lseek(fd, fpos, SEEK_SET); |
1aff6a35 |
SetFilePointer(fdhdl, 0, NULL, FILE_BEGIN);
si.object = fdhdl;
si.objectId = (HANDLE)_get_osfhandle(fd); |
cefb07dc |
perf2 = GetTickCount() - perf2; |
6b4faa63 |
sctx->copy_times += perf2; |
1aff6a35 |
} else { /* SCAN_PHASE_INITIAL */
si.object = INVALID_HANDLE_VALUE;
si.objectId = INVALID_HANDLE_VALUE; |
8038c673 |
} |
f675a85d |
logg("*prescan_cb (clamav context %p, instance %p) invoking callback %p with context %p\n", context, inst, inst->scancb, inst->scancb_ctx); |
c8baa1b9 |
perf = GetTickCount(); |
aa7380df |
inst->scancb(&si, &act, inst->scancb_ctx); |
c8baa1b9 |
perf = GetTickCount() - perf; |
593e71c0 |
sctx->cb_times += perf; |
cefb07dc |
logg("*prescan_cb (clamav context %p, instance %p) callback completed with %u in %u + %u ms\n", context, inst, act, perf, perf2); |
aa7380df |
switch(act) {
case CLAM_ACTION_SKIP: |
f675a85d |
logg("*prescan_cb (clamav context %p, instance %p) cb result: SKIP\n", context, inst); |
aa7380df |
return CL_BREAK;
case CLAM_ACTION_ABORT: |
f675a85d |
logg("*prescan_cb (clamav context %p, instance %p) cb result: ABORT\n", context, inst); |
aa7380df |
return CL_VIRUS;
case CLAM_ACTION_CONTINUE: |
f675a85d |
logg("*prescan_cb (clamav context %p, instance %p) cb result: CONTINUE\n", context, inst); |
c8baa1b9 |
return CL_CLEAN;
default:
logg("^prescan_cb (clamav context %p, instance %p) cb result: INVALID result %d, assuming continue\n", context, inst, act); |
aa7380df |
return CL_CLEAN;
}
}
cl_error_t postscan_cb(int fd, int result, const char *virname, void *context) {
struct scan_ctx *sctx = (struct scan_ctx *)context; |
c8baa1b9 |
instance *inst; |
aa7380df |
CLAM_SCAN_INFO si;
CLAM_ACTION act; |
c8baa1b9 |
DWORD perf; |
8aacea51 |
wchar_t wvirname[MAX_VIRNAME_LEN] = L"Clam."; |
aa7380df |
|
c8baa1b9 |
if(!context) {
logg("!postscan_cb called with NULL clamav context\n");
return CL_CLEAN;
} |
4d08b6d6 |
inst = sctx->inst;
if(inst && inst->filetype)
return CL_CLEAN; /* No callback, we are just filetyping */
|
c31cb63d |
if(fd == sctx->entryfd)
return CL_CLEAN; /* Moved to after cl_scandesc returns due to heuristic results not being yet set in magicscan */
|
aa7380df |
si.cbSize = sizeof(si);
si.flags = 0; |
c31cb63d |
si.scanPhase = SCAN_PHASE_POSTSCAN; |
aa7380df |
si.errorCode = CLAMAPI_SUCCESS; |
d3c908c7 |
if(result == CL_VIRUS) { |
8aacea51 |
if(MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, virname, -1, &wvirname[5], MAX_VIRNAME_LEN-5)) |
d3c908c7 |
si.pThreatName = wvirname;
else |
b4053863 |
si.pThreatName = L"Clam.UNOFFICIAL"; |
d3c908c7 |
} else
si.pThreatName = NULL; |
f675a85d |
logg("*in postscan_cb with clamav context %p, instance %p, fd %d, result %d, virusname %S)\n", context, inst, fd, result, si.pThreatName); |
d3c908c7 |
si.pThreatType = threat_type(virname); |
8038c673 |
si.objectId = (HANDLE)_get_osfhandle(fd);
si.object = INVALID_HANDLE_VALUE; |
aa7380df |
si.pInnerObjectPath = NULL; |
f675a85d |
logg("*postscan_cb (clamav context %p, instance %p) invoking callback %p with context %p\n", context, inst, inst->scancb, inst->scancb_ctx); |
c8baa1b9 |
perf = GetTickCount(); |
aa7380df |
inst->scancb(&si, &act, inst->scancb_ctx); |
c8baa1b9 |
perf = GetTickCount() - perf; |
593e71c0 |
sctx->cb_times += perf; |
f675a85d |
logg("*postscan_cb (clamav context %p, instance %p) callback completed with %u in %u ms\n", context, inst, act, perf); |
aa7380df |
switch(act) {
case CLAM_ACTION_SKIP: |
f675a85d |
logg("*postscan_cb (clamav context %p, instance %p) cb result: SKIP\n", context, inst); |
aa7380df |
return CL_BREAK;
case CLAM_ACTION_ABORT: |
f675a85d |
logg("*postscan_cb (clamav context %p, instance %p) cb result: ABORT\n", context, inst); |
aa7380df |
return CL_VIRUS;
case CLAM_ACTION_CONTINUE: |
f675a85d |
logg("*postscan_cb (clamav context %p, instance %p) cb result: CONTINUE\n", context, inst); |
c8baa1b9 |
return CL_CLEAN;
default:
logg("^postscan_cb (clamav context %p, instance %p) cb result: INVALID result %d, assuming continue\n", context, inst, act); |
aa7380df |
return CL_CLEAN;
}
} |
8f415c86 |
|
ce048a0a |
CLAMAPI void Scan_ReloadDatabase(BOOL bLoadMinDefs) { |
f26ba7fa |
if(InterlockedIncrement(&reload_waiters)==1) {
int reload_ok = 0; |
f675a85d |
logg("*Scan_ReloadDatabase: Database reload requested received, waiting for idle state\n"); |
f26ba7fa |
while(1) { |
219e22e6 |
unsigned int i; |
f2d1cf00 |
struct cl_settings *settings; |
eebe17b2 |
|
f26ba7fa |
if(WaitForSingleObject(reload_event, INFINITE) == WAIT_FAILED) { |
219e22e6 |
logg("!Scan_ReloadDatabase: failed to wait on reload event\n"); |
f26ba7fa |
continue;
} |
f675a85d |
logg("*Scan_ReloadDatabase: Now idle, acquiring engine lock\n"); |
f26ba7fa |
if(lock_engine()) { |
219e22e6 |
logg("!Scan_ReloadDatabase: failed to lock engine\n"); |
f26ba7fa |
break;
}
if(!engine) { |
219e22e6 |
logg("!Scan_ReloadDatabase: engine is NULL\n"); |
f26ba7fa |
unlock_engine();
break;
} |
f675a85d |
logg("*Scan_ReloadDatabase: Engine locked, acquiring instance lock\n"); |
f26ba7fa |
if(lock_instances()) { |
219e22e6 |
logg("!Scan_ReloadDatabase: failed to lock instances\n"); |
f26ba7fa |
unlock_engine();
break;
} |
219e22e6 |
for(i=0; i<ninsts_total; i++) {
if(instances[i].inst && instances[i].refcnt)
break;
}
if(i!=ninsts_total) {
logg("Scan_ScanObjectByHandle: some instances are still in use\n");
ResetEvent(reload_event); |
f26ba7fa |
unlock_instances(); |
219e22e6 |
unlock_engine(); |
f26ba7fa |
continue;
} |
eebe17b2 |
settings = cl_engine_settings_copy(engine);
if (!settings) {
logg("!Scan_ReloadDatabase: Not enough memory for engine settings\n");
unlock_instances();
unlock_engine();
break;
}
|
1a401901 |
logg("Scan_ReloadDatabase: Destroying old engine\n"); |
f26ba7fa |
cl_engine_free(engine); |
ce048a0a |
minimal_definitions = bLoadMinDefs; |
1a401901 |
logg("Scan_ReloadDatabase: Loading new engine\n"); |
219e22e6 |
// NEW STUFF //
if(!(engine = cl_engine_new())) {
logg("!Scan_ReloadDatabase: Not enough memory for a new engine\n");
unlock_instances();
unlock_engine();
break;
} |
eebe17b2 |
cl_engine_settings_apply(engine, settings);
cl_engine_settings_free(settings); |
219e22e6 |
|
f26ba7fa |
load_db(); /* FIXME: FIAL? */
unlock_instances(); |
219e22e6 |
unlock_engine(); |
f26ba7fa |
reload_ok = 1;
break;
}
if(reload_ok) |
1a401901 |
logg("Scan_ReloadDatabase: Database successfully reloaded\n"); |
f26ba7fa |
else |
219e22e6 |
logg("!Scan_ReloadDatabase: Database reload failed\n"); |
f26ba7fa |
} else |
1a401901 |
logg("*Database reload requested received while reload is pending\n"); |
f26ba7fa |
InterlockedDecrement(&reload_waiters); |
8f415c86 |
} |
1f1b1318 |
void msg_callback(enum cl_msg severity, const char *fullmsg, const char *msg, void *ctx)
{
struct scan_ctx *sctx = (struct scan_ctx*)ctx;
const void *instance = sctx ? sctx->inst : NULL;
int fd = sctx ? sctx->entryfd : -1;
char sv;
switch (severity) {
case CL_MSG_ERROR:
sv = '!';
break;
case CL_MSG_WARN:
sv = '^';
break;
default:
sv = '*';
break;
}
logg("%c[LibClamAV] (instance %p, clamav context %p, fd %d): %s",
sv, instance, sctx, fd, msg);
} |