Browse code

clam4win update

aCaB authored on 2010/07/09 08:38:56
Showing 3 changed files
... ...
@@ -1897,7 +1897,7 @@ static void emax_reached(cli_ctx *ctx) {
1897 1897
 #define ret_from_magicscan(retcode) do {							\
1898 1898
     cli_dbgmsg("cli_magic_scandesc: returning %d %s\n", retcode, __AT__);			\
1899 1899
     if(ctx->engine->cb_post_scan) {								\
1900
-	switch(ctx->engine->cb_post_scan(desc, retcode, ctx->virname ? *ctx->virname : NULL, ctx->cb_ctx)) {		\
1900
+	switch(ctx->engine->cb_post_scan(desc, retcode, retcode == CL_VIRUS && ctx->virname ? *ctx->virname : NULL, ctx->cb_ctx)) {		\
1901 1901
 	case CL_BREAK:										\
1902 1902
 	    cli_dbgmsg("cli_magic_scandesc: file whitelisted by callback\n");			\
1903 1903
 	    return CL_CLEAN;									\
... ...
@@ -1,12 +1,3 @@
1
-//TODO:
2
-// unify refcounting
3
-// check scan funcs
4
-// after scan returns and ret!=CL_VIRUS pInfoList NULL or unchanged?
5
-// changed set option value to 0 or non 0
6
-// restore file position
7
-// cb context per instance or per scanobj ??
8
-// optional shit to really be OPTIONAL!
9
-
10 1
 /*
11 2
  * Copyright (C) 2010 Sourcefire, Inc.
12 3
  * Authors: aCaB <acab@clamav.net>
... ...
@@ -40,34 +31,147 @@
40 40
 #define WIN() do { logg("%s completed successfully\n", __FUNCTION__); return CLAMAPI_SUCCESS; } while(0)
41 41
 #define INFN() do { logg("in %s\n", __FUNCTION__); } while(0)
42 42
 
43
-HANDLE engine_event; /* refcount = 0 event */
43
+HANDLE engine_event; /* engine unused event */
44 44
 
45 45
 HANDLE engine_mutex;
46 46
 /* protects the following items */
47 47
 struct cl_engine *engine = NULL;
48 48
 struct cl_stat dbstat;
49 49
 char dbdir[PATH_MAX];
50
-unsigned int engine_refcnt;
51 50
 /* end of protected items */
52 51
 
52
+typedef struct {
53
+    CLAM_SCAN_CALLBACK scancb;
54
+    void *scancb_ctx;
55
+    unsigned int scanopts;
56
+} instance;
57
+
58
+struct {
59
+    instance *inst;
60
+    unsigned int refcnt;
61
+} *instances = NULL;
62
+unsigned int ninsts_total = 0;
63
+unsigned int ninsts_avail = 0;
64
+HANDLE instance_mutex;
65
+
53 66
 #define lock_engine()(WaitForSingleObject(engine_mutex, INFINITE) == WAIT_FAILED)
54 67
 #define unlock_engine() do {ReleaseMutex(engine_mutex);} while(0)
55 68
 
69
+#define lock_instances()(WaitForSingleObject(instance_mutex, INFINITE) == WAIT_FAILED)
70
+#define unlock_instances() do {ReleaseMutex(instance_mutex);} while(0)
71
+
56 72
 cl_error_t prescan_cb(int fd, void *context);
57 73
 cl_error_t postscan_cb(int fd, int result, const char *virname, void *context);
58 74
 
75
+static int add_instance(instance *inst) {
76
+    unsigned int i;
77
+
78
+    INFN();
79
+    if(lock_instances()) {
80
+	logg("add_instance: failed to lock instances\n");
81
+	return 1;
82
+    }
83
+    if(!ninsts_avail) {
84
+	void *freeme, *new_instances = calloc(ninsts_total + 256, sizeof(*instances));
85
+	if(!new_instances) {
86
+	    unlock_instances();
87
+	    logg("add_instance: failed to grow instances\n");
88
+	    return 1;
89
+	}
90
+	freeme = instances;
91
+	if(instances && ninsts_total)
92
+	    memcpy(new_instances, instances, ninsts_total * sizeof(*instances));
93
+	ninsts_total += 256;
94
+	ninsts_avail += 256;
95
+	instances = new_instances;
96
+	if(freeme)
97
+	    free(freeme);
98
+	logg("add_instance: instances grown to %u\n", ninsts_total);
99
+    }
100
+    for(i=0; i<ninsts_total; i++) {
101
+	if(instances[i].inst)
102
+	    continue;
103
+	instances[i].inst = inst;
104
+	instances[i].refcnt = 0;
105
+	ninsts_avail--;
106
+	unlock_instances();
107
+	ResetEvent(engine_event);
108
+	return 0;
109
+    }
110
+    logg("add_instances: you should not be reading this\n");
111
+    unlock_instances();
112
+    return 1;
113
+}
114
+
115
+static int del_instance(instance *inst) {
116
+    unsigned int i;
117
+
118
+    INFN();
119
+    if(lock_instances()) {
120
+	logg("del_instance: failed to lock instances\n");
121
+	return 1;
122
+    }
123
+    for(i=0; i<ninsts_total; i++) {
124
+	if(instances[i].inst != inst)
125
+	    continue;
126
+	if(instances[i].refcnt) {
127
+	    logg("del_instance: attempted to free instance with %d active scanners\n", instances[i].refcnt);
128
+	    unlock_instances();
129
+	    return 1;
130
+	}
131
+	instances[i].inst = NULL;
132
+	instances[i].refcnt = 0;
133
+	ninsts_avail++;
134
+	if(ninsts_avail == ninsts_total)
135
+	    ResetEvent(engine_event);
136
+	unlock_instances();
137
+	return 0;
138
+    }
139
+    logg("del_instances: instance not found\n");
140
+    unlock_instances();
141
+    return 1;
142
+}
143
+
144
+/* To be called with the instances locked */
145
+static int is_instance(instance *inst) {
146
+    unsigned int i;
147
+    INFN();
148
+    for(i=0; i<ninsts_total; i++)
149
+	if(instances[i].inst == inst)
150
+	    return 1;
151
+    logg("FAILED INSTANCE %p\n", inst);
152
+    return 0;
153
+}
154
+
59 155
 BOOL interface_setup(void) {
60 156
     if(!(engine_mutex = CreateMutex(NULL, FALSE, NULL)))
61 157
 	return FALSE;
62
-    if(!(engine_event = CreateEvent(NULL, TRUE, TRUE, NULL)))
158
+    if(!(engine_event = CreateEvent(NULL, TRUE, TRUE, NULL))) {
159
+	CloseHandle(engine_mutex);
160
+	return FALSE;
161
+    }
162
+    if(!(instance_mutex = CreateMutex(NULL, FALSE, NULL))) {
163
+	CloseHandle(engine_mutex);
164
+	CloseHandle(engine_event);
63 165
 	return FALSE;
166
+    }
64 167
     return TRUE;
65 168
 }
66 169
 
170
+static int sigload_callback(const char *type, const char *name, void *context) {
171
+    if(!strncmp(name, "Exploit.PDF", 11) || !strncmp(name, "DOS.", 4) || !strcmp(type, "db")) /* FIXME */
172
+	return 1;
173
+    return 0;
174
+}
175
+
176
+/* Must be called with engine_mutex locked ! */
67 177
 static int load_db(void) {
68 178
     int ret;
179
+    unsigned int signo = 0;
69 180
     INFN();
70
-    if((ret = cl_load(dbdir, engine, NULL, CL_DB_STDOPT)) != CL_SUCCESS) {
181
+
182
+    cl_engine_set_clcb_sigload(engine, sigload_callback, NULL);
183
+    if((ret = cl_load(dbdir, engine, &signo, CL_DB_STDOPT & ~CL_DB_PHISHING & ~CL_DB_PHISHING_URLS & CL_DB_OFFICIAL_ONLY)) != CL_SUCCESS) {
71 184
 	engine = NULL;
72 185
 	FAIL(ret, "Failed to load database: %s", cl_strerror(ret));
73 186
     }
... ...
@@ -78,7 +182,7 @@ static int load_db(void) {
78 78
 	FAIL(ret, "Failed to compile engine: %s", cl_strerror(ret));
79 79
     }
80 80
 
81
-    engine_refcnt = 0;
81
+    logg("load_db: loaded %d signatures\n", signo);
82 82
     memset(&dbstat, 0, sizeof(dbstat));
83 83
     cl_statinidir(dbdir, &dbstat);
84 84
     WIN();
... ...
@@ -89,26 +193,33 @@ DWORD WINAPI reload(void *param) {
89 89
     while(1) {
90 90
 	Sleep(1000*60);
91 91
 	if(WaitForSingleObject(engine_event, INFINITE) == WAIT_FAILED) {
92
-	    logg("Failed to wait on reload event");
92
+	    logg("reload: failed to wait on reload event");
93 93
 	    continue;
94 94
 	}
95 95
 	while(1) {
96 96
 	    if(lock_engine()) {
97
-		logg("Failed to lock engine");
97
+		logg("reload: failed to lock engine");
98 98
 		break;
99 99
 	    }
100 100
 	    if(!engine || !cl_statchkdir(&dbstat)) {
101 101
 		unlock_engine();
102 102
 		break;
103 103
 	    }
104
-	    if(engine_refcnt) {
104
+	    if(lock_instances()) {
105
+		unlock_engine();
106
+		logg("reload: failed to lock instances\n");
107
+		break;
108
+	    }
109
+	    if(ninsts_avail != ninsts_total) {
105 110
 		unlock_engine();
106
-		Sleep(0);
111
+		unlock_instances();
112
+		Sleep(5000);
107 113
 		continue;
108 114
 	    }
109 115
 	    cl_engine_free(engine);
110 116
 	    load_db();
111 117
 	    unlock_engine();
118
+	    unlock_instances();
112 119
 	    break;
113 120
 	}
114 121
     }
... ...
@@ -125,13 +236,18 @@ int CLAMAPI Scan_Initialize(const wchar_t *pEnginesFolder, const wchar_t *pTempR
125 125
     BOOL cant_convert;
126 126
     int ret;
127 127
 
128
-    INFN();
128
+    logg("In Scan_Initialize(pEnginesFolder = %S, pTempRoot = %S)\n", pEnginesFolder, pTempRoot);
129
+    if(!pEnginesFolder)
130
+	FAIL(CL_ENULLARG, "pEnginesFolder is NULL");
131
+    if(!pTempRoot)
132
+	FAIL(CL_ENULLARG, "pTempRoot is NULL");
129 133
     if(lock_engine())
130
-	FAIL(CL_EMEM, "Engine mutex fail");
134
+	FAIL(CL_EMEM, "failed to lock engine");
131 135
     if(engine) {
132 136
 	unlock_engine();
133 137
 	FAIL(CL_EARG, "Already initialized");
134 138
     }
139
+
135 140
     if(!(engine = cl_engine_new())) {
136 141
 	unlock_engine();
137 142
 	FAIL(CL_EMEM, "Not enough memory for a new engine");
... ...
@@ -150,9 +266,9 @@ int CLAMAPI Scan_Initialize(const wchar_t *pEnginesFolder, const wchar_t *pTempR
150 150
 	free_engine_and_unlock();
151 151
 	FAIL(CL_EARG, "Can't translate pEnginesFolder");
152 152
     }
153
-    logg("Scan_Initialize(%s)\n", dbdir);
154 153
     ret = load_db();
155 154
     unlock_engine();
155
+    logg("Scan_Initialize: returning %d\n", ret);
156 156
     return ret;
157 157
 }
158 158
 
... ...
@@ -165,31 +281,33 @@ int CLAMAPI Scan_Uninitialize(void) {
165 165
  //   logg("%x", rett);
166 166
     INFN();
167 167
     if(lock_engine())
168
-	FAIL(CL_EMEM, "Engine mutex fail");
168
+	FAIL(CL_EMEM, "failed to lock engine");
169 169
     if(!engine) {
170 170
 	unlock_engine();
171
-	FAIL(CL_EARG, "Attempted to uninit a NULL engine");
171
+	FAIL(CL_EARG, "attempted to uninit a NULL engine");
172
+    }
173
+   if(lock_instances()) {
174
+	unlock_engine();
175
+	FAIL(CL_EMEM, "failed to lock instances");
172 176
     }
173
-    if(engine_refcnt) {
174
-	volatile unsigned int refs = engine_refcnt;
177
+    if(ninsts_avail != ninsts_total) {
178
+	volatile unsigned int refcnt = ninsts_total - ninsts_avail;
179
+	unlock_instances();
175 180
 	unlock_engine();
176
-	FAIL(CL_EARG, "Attempted to uninit the engine with %u active instances", engine_refcnt);
181
+	FAIL(CL_EARG, "Attempted to uninit the engine with %u active instances", refcnt);
177 182
     }
183
+    unlock_instances();
178 184
     free_engine_and_unlock();
179 185
     WIN();
180 186
 }
181 187
 
182
-typedef struct {
183
-    CLAM_SCAN_CALLBACK scancb;
184
-    void *scancb_ctx;
185
-    void *callback2;
186
-    LONG refcnt;
187
-    unsigned int scanopts;
188
-} instance;
189
-
190 188
 int CLAMAPI Scan_CreateInstance(CClamAVScanner **ppScanner) {
191
-    instance *inst = calloc(1, sizeof(*inst));
189
+    instance *inst;
190
+
192 191
     INFN();
192
+    if(!ppScanner)
193
+	FAIL(CL_ENULLARG, "NULL pScanner");
194
+    inst = calloc(1, sizeof(*inst));
193 195
     if(!inst)
194 196
 	FAIL(CL_EMEM, "CreateInstance: OOM");
195 197
     if(lock_engine()) {
... ...
@@ -201,50 +319,66 @@ int CLAMAPI Scan_CreateInstance(CClamAVScanner **ppScanner) {
201 201
 	unlock_engine();
202 202
 	FAIL(CL_ENULLARG, "Create instance called with no engine");
203 203
     }
204
-    engine_refcnt++;
205
-    ResetEvent(engine_event);
204
+    if(add_instance(inst)) {
205
+	free(inst);
206
+	unlock_engine();
207
+	FAIL(CL_EMEM, "add_instance failed");
208
+    }
206 209
     unlock_engine();
207 210
     inst->scanopts = CL_SCAN_STDOPT;
208 211
     *ppScanner = (CClamAVScanner *)inst;
212
+    logg("NEW INSTANCE %p\n", inst);
209 213
     WIN();
210 214
 }
211 215
 
212 216
 int CLAMAPI Scan_DestroyInstance(CClamAVScanner *pScanner) {
213
-    instance *inst = (instance *)pScanner;
214
-    volatile LONG refcnt = InterlockedCompareExchange(&inst->refcnt, 0, 0);
215 217
     INFN();
216
-    if(refcnt)
217
-	FAIL(CL_EARG, "Attemped to destroy an instance with active scanners");
218
+    if(!pScanner)
219
+	FAIL(CL_ENULLARG, "NULL pScanner");
220
+    if(del_instance((instance *)pScanner))
221
+	FAIL(CL_EMEM, "del_instance failed");
218 222
     free(pScanner);
219
-    if(lock_engine())
220
-	FAIL(CL_EMEM, "Failed to lock engine");
221
-    if(!engine) {
222
-	unlock_engine();
223
-	FAIL(CL_ENULLARG, "Destroy instance called with no engine");
224
-    }
225
-    if(!--engine_refcnt)
226
-	SetEvent(engine_event);
227
-    unlock_engine();
223
+    logg("DEL INSTANCE %p\n", pScanner);
228 224
     WIN();
229 225
 }
230 226
 
231 227
 int CLAMAPI Scan_SetScanCallback(CClamAVScanner *pScanner, CLAM_SCAN_CALLBACK pfnCallback, void *pContext) {
232
-    instance *inst = (instance *)pScanner;
228
+    instance *inst;
229
+
233 230
     INFN();
234
-    InterlockedIncrement(&inst->refcnt);
235
-    inst->scancb = pfnCallback;
236
-    inst->scancb_ctx = pContext;
237
-    InterlockedDecrement(&inst->refcnt);
238
-    
239
-    WIN();
231
+    if(!pScanner)
232
+	FAIL(CL_ENULLARG, "NULL pScanner");
233
+    if(lock_instances())
234
+	FAIL(CL_EMEM, "failed to lock instances");
235
+
236
+    inst = (instance *)pScanner;
237
+    if(is_instance(inst)) {
238
+	inst->scancb = pfnCallback;
239
+	inst->scancb_ctx = pContext;
240
+	unlock_instances();
241
+	WIN();
242
+    }
243
+    unlock_instances();
244
+    FAIL(CL_EARG, "invalid instance %p", inst);
240 245
 }
241 246
 
242 247
 int CLAMAPI Scan_SetOption(CClamAVScanner *pScanner, int option, void *value, unsigned long inputLength) {
243
-    instance *inst = (instance *)pScanner;
248
+    instance *inst;
244 249
     unsigned int whichopt, newval;
245 250
     
246 251
     INFN();
247
-    InterlockedIncrement(&inst->refcnt);
252
+    if(!pScanner)
253
+	FAIL(CL_ENULLARG, "NULL pScanner");
254
+    if(!value)
255
+	FAIL(CL_ENULLARG, "NULL value");
256
+    if(lock_instances())
257
+	FAIL(CL_EMEM, "failed to lock instances");
258
+
259
+    inst = (instance *)pScanner;
260
+    if(!is_instance(inst)) {
261
+	unlock_instances();
262
+	FAIL(CL_EARG, "invalid instance %p", inst);
263
+    }
248 264
     switch(option) {
249 265
 	case CLAM_OPTION_SCAN_ARCHIVE:
250 266
 	    whichopt = CL_SCAN_ARCHIVE;
... ...
@@ -271,8 +405,8 @@ int CLAMAPI Scan_SetOption(CClamAVScanner *pScanner, int option, void *value, un
271 271
 	    whichopt = CL_SCAN_ELF;
272 272
 	    break;
273 273
 	default:
274
-	    InterlockedDecrement(&inst->refcnt);
275
-	    FAIL(CL_EARG, "Unsupported set option: %d", option);
274
+	    unlock_instances();
275
+	    FAIL(CL_EARG, "Unsupported option: %d", option);
276 276
     }
277 277
 
278 278
     newval = *(unsigned int *)value;
... ...
@@ -280,16 +414,27 @@ int CLAMAPI Scan_SetOption(CClamAVScanner *pScanner, int option, void *value, un
280 280
 	inst->scanopts &= ~whichopt;
281 281
     else
282 282
 	inst->scanopts |= whichopt;
283
-    InterlockedDecrement(&inst->refcnt);
283
+    unlock_instances();
284 284
     WIN();
285 285
 }
286 286
 
287 287
 int CLAMAPI Scan_GetOption(CClamAVScanner *pScanner, int option, void *value, unsigned long inputLength, unsigned long *outLength) {
288
-    instance *inst = (instance *)pScanner;
288
+    instance *inst;
289 289
     unsigned int whichopt;
290 290
 
291 291
     INFN();
292
-    InterlockedIncrement(&inst->refcnt);
292
+    if(!pScanner)
293
+	FAIL(CL_ENULLARG, "NULL pScanner");
294
+    if(!value || !inputLength)
295
+	FAIL(CL_ENULLARG, "NULL value");
296
+    if(lock_instances())
297
+	FAIL(CL_EMEM, "failed to lock instances");
298
+
299
+    inst = (instance *)pScanner;
300
+    if(!is_instance(inst)) {
301
+	unlock_instances();
302
+	FAIL(CL_EARG, "invalid instance %p", inst);
303
+    }
293 304
     switch(option) {
294 305
 	case CLAM_OPTION_SCAN_ARCHIVE:
295 306
 	    whichopt = CL_SCAN_ARCHIVE;
... ...
@@ -316,12 +461,12 @@ int CLAMAPI Scan_GetOption(CClamAVScanner *pScanner, int option, void *value, un
316 316
 	    whichopt = CL_SCAN_ELF;
317 317
 	    break;
318 318
 	default:
319
-	    InterlockedDecrement(&inst->refcnt);
320
-	    FAIL(CL_EARG, "Unsupported set option: %d", option);
319
+	    unlock_instances();
320
+	    FAIL(CL_EARG, "Unsupported option: %d", option);
321 321
     }
322 322
 
323 323
     *(unsigned int *)value = (inst->scanopts & whichopt) != 0;
324
-    InterlockedDecrement(&inst->refcnt);
324
+    unlock_instances();
325 325
     WIN();
326 326
 }
327 327
 
... ...
@@ -333,17 +478,12 @@ int CLAMAPI Scan_ScanObject(CClamAVScanner *pScanner, const wchar_t *pObjectPath
333 333
     instance *inst = (instance *)pScanner;
334 334
 
335 335
     INFN();
336
-    InterlockedIncrement(&inst->refcnt);
337
-
338
-    if((fhdl = CreateFileW(pObjectPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL)) == INVALID_HANDLE_VALUE) {
339
-	InterlockedDecrement(&inst->refcnt);
336
+    if((fhdl = CreateFileW(pObjectPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL)) == INVALID_HANDLE_VALUE)
340 337
 	FAIL(CL_EOPEN, "open() failed");
341
-    }
342 338
 
343 339
     res = Scan_ScanObjectByHandle(pScanner, fhdl, pScanStatus, pInfoList);
344 340
 
345 341
     CloseHandle(fhdl);
346
-    InterlockedDecrement(&inst->refcnt);
347 342
     return res;
348 343
 }
349 344
 
... ...
@@ -353,56 +493,82 @@ struct scan_ctx {
353 353
 };
354 354
 
355 355
 int CLAMAPI Scan_ScanObjectByHandle(CClamAVScanner *pScanner, HANDLE object, int *pScanStatus, PCLAM_SCAN_INFO_LIST *pInfoList) {
356
-    instance *inst = (instance *)pScanner;
356
+    instance *inst;
357 357
     HANDLE duphdl, self;
358 358
     char *virname;
359 359
     int fd, res;
360
+    unsigned int i;
360 361
     struct scan_ctx sctx;
361 362
 
362 363
     INFN();
363
-    InterlockedIncrement(&inst->refcnt);
364
+
365
+    if(!pScanner)
366
+	FAIL(CL_ENULLARG, "NULL pScanner");
367
+    if(!pScanStatus)
368
+	FAIL(CL_ENULLARG, "NULL pScanStatus");
369
+ //   if(!pInfoList)
370
+	//FAIL(CL_ENULLARG, "NULL pInfoList");
364 371
 
365 372
     self = GetCurrentProcess();
366
-    if(!DuplicateHandle(self, object, self, &duphdl, GENERIC_READ, FALSE, 0)) {
367
-	InterlockedDecrement(&inst->refcnt);
373
+    if(!DuplicateHandle(self, object, self, &duphdl, GENERIC_READ, FALSE, 0))
368 374
 	FAIL(CL_EDUP, "Duplicate handle failed");
369
-    }
370 375
 
371 376
     if((fd = _open_osfhandle((intptr_t)duphdl, _O_RDONLY)) == -1) {
372
-	InterlockedDecrement(&inst->refcnt);
373 377
 	CloseHandle(duphdl);
374 378
 	FAIL(CL_EOPEN, "Open handle failed");
375 379
     }
376 380
 
381
+    if(lock_instances()) {
382
+	close(fd);
383
+	FAIL(CL_EMEM, "failed to lock instances");
384
+    }
385
+    inst = (instance *)pScanner;
386
+    for(i=0; i<ninsts_total; i++) {
387
+	if(instances[i].inst == inst)
388
+	    break;
389
+    }
390
+    if(i == ninsts_total) {
391
+	unlock_instances();
392
+	close(fd);
393
+	FAIL(CL_EARG, "invalid instance %p", inst);
394
+    }
395
+    instances[i].refcnt++;
396
+    unlock_instances();
397
+
377 398
     sctx.entryfd = fd;
378 399
     sctx.inst = inst;
379 400
     res = cl_scandesc_callback(fd, &virname, NULL, engine, inst->scanopts, &sctx);
380
-    InterlockedDecrement(&inst->refcnt);
381 401
     close(fd);
382 402
 
403
+    if(lock_instances())
404
+	FAIL(CL_EMEM, "failed to lock instances");
405
+    instances[i].refcnt--;
406
+    unlock_instances();
407
+
383 408
     if(res == CL_VIRUS) {
384
-	CLAM_SCAN_INFO_LIST *infolist = calloc(1, sizeof(CLAM_SCAN_INFO_LIST) + sizeof(CLAM_SCAN_INFO) + MAX_VIRNAME_LEN);
385
-	PCLAM_SCAN_INFO scaninfo;
386
-	wchar_t *wvirname;
387
-
388
-        if(!infolist)
389
-	    FAIL(CL_EMEM, "ScanByHandle: OOM");
390
-
391
-	scaninfo = (PCLAM_SCAN_INFO)(infolist + 1);
392
-	infolist->cbCount = 1;
393
-	scaninfo->cbSize = sizeof(*scaninfo);
394
-	scaninfo->scanPhase = SCAN_PHASE_FINAL;
395
-	scaninfo->errorCode = CLAMAPI_SUCCESS;
396
-	scaninfo->pThreatType = L"FIXME";
397
-	wvirname = (wchar_t *)(scaninfo + 1);
398
-	scaninfo->pThreatName = wvirname;
399
-	if(!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, virname, -1, wvirname, MAX_VIRNAME_LEN))
400
-	    scaninfo->pThreatName = L"INFECTED";
401
-	logg("FOUND: %s\n", virname);
402
-	*pInfoList = infolist;
409
+	if(pInfoList) {
410
+	    CLAM_SCAN_INFO_LIST *infolist = calloc(1, sizeof(CLAM_SCAN_INFO_LIST) + sizeof(CLAM_SCAN_INFO) + MAX_VIRNAME_LEN * 2);
411
+	    PCLAM_SCAN_INFO scaninfo;
412
+	    wchar_t *wvirname;
413
+
414
+	    if(!infolist)
415
+		FAIL(CL_EMEM, "ScanByHandle: OOM");
416
+	    scaninfo = (PCLAM_SCAN_INFO)(infolist + 1);
417
+	    infolist->cbCount = 1;
418
+	    scaninfo->cbSize = sizeof(*scaninfo);
419
+	    scaninfo->scanPhase = SCAN_PHASE_FINAL;
420
+	    scaninfo->errorCode = CLAMAPI_SUCCESS;
421
+	    scaninfo->pThreatType = L"FIXME";
422
+	    wvirname = (wchar_t *)(scaninfo + 1);
423
+	    scaninfo->pThreatName = wvirname;
424
+	    if(!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, virname, -1, wvirname, MAX_VIRNAME_LEN))
425
+		scaninfo->pThreatName = L"INFECTED";
426
+	    logg("FOUND: %s\n", virname);
427
+	    *pInfoList = infolist;
428
+	}
403 429
 	*pScanStatus = CLAM_INFECTED;
404 430
     } else {
405
-        *pInfoList = NULL;
431
+        if(pInfoList) *pInfoList = NULL;
406 432
 	*pScanStatus = CLAM_CLEAN;
407 433
     }
408 434
     WIN();
... ...
@@ -411,6 +577,21 @@ int CLAMAPI Scan_ScanObjectByHandle(CClamAVScanner *pScanner, HANDLE object, int
411 411
 
412 412
 int CLAMAPI Scan_DeleteScanInfo(CClamAVScanner *pScanner, PCLAM_SCAN_INFO_LIST pInfoList) {
413 413
     INFN();
414
+    if(!pScanner)
415
+	FAIL(CL_ENULLARG, "NULL pScanner");
416
+    if(!pInfoList)
417
+	FAIL(CL_ENULLARG, "NULL pInfoList");
418
+    /* FIXME checking this is pointelss as the infolist is independent from pscanner */
419
+ //   if(lock_instances())
420
+	//FAIL(CL_EMEM, "failed to lock instances");
421
+
422
+ //   inst = (instance *)pScanner;
423
+ //   if(!is_instance(inst)) {
424
+	//unlock_instances();
425
+	//FAIL(CL_EARG, "invalid instance");
426
+ //   }
427
+ //   unlock_instances();
428
+
414 429
     free(pInfoList);
415 430
     WIN();
416 431
 }
... ...
@@ -420,6 +601,8 @@ cl_error_t prescan_cb(int fd, void *context) {
420 420
     instance *inst = sctx->inst;
421 421
     CLAM_SCAN_INFO si;
422 422
     CLAM_ACTION act;
423
+    HANDLE fdhdl;
424
+    LONG lo = 0, hi = 0, hi2 = 0;
423 425
 
424 426
     logg("in prescan cb with %d %p\n", fd, context);
425 427
     si.cbSize = sizeof(si);
... ...
@@ -428,9 +611,13 @@ cl_error_t prescan_cb(int fd, void *context) {
428 428
     si.errorCode = CLAMAPI_SUCCESS;
429 429
     si.pThreatType = NULL;
430 430
     si.pThreatName = NULL;
431
-    si.object = (HANDLE)_get_osfhandle(fd);
431
+    fdhdl = si.object = (HANDLE)_get_osfhandle(fd);
432 432
     si.pInnerObjectPath = NULL;
433
+
434
+    lo = SetFilePointer(fdhdl, 0, &hi, FILE_CURRENT);
435
+    SetFilePointer(fdhdl, 0, &hi2, FILE_BEGIN);
433 436
     inst->scancb(&si, &act, inst->scancb_ctx);
437
+    SetFilePointer(fdhdl, lo, &hi, FILE_BEGIN);
434 438
     return CL_CLEAN; /* FIXME: remove me */
435 439
     switch(act) {
436 440
 	case CLAM_ACTION_SKIP:
... ...
@@ -452,6 +639,8 @@ cl_error_t postscan_cb(int fd, int result, const char *virname, void *context) {
452 452
     instance *inst = sctx->inst;
453 453
     CLAM_SCAN_INFO si;
454 454
     CLAM_ACTION act;
455
+    HANDLE fdhdl;
456
+    LONG lo = 0, hi = 0, hi2 = 0;
455 457
 
456 458
     logg("in postscan cb with %d %d %s %p\n", fd, result, virname, context);
457 459
     si.cbSize = sizeof(si);
... ...
@@ -460,9 +649,12 @@ cl_error_t postscan_cb(int fd, int result, const char *virname, void *context) {
460 460
     si.errorCode = CLAMAPI_SUCCESS;
461 461
     si.pThreatType = NULL;
462 462
     si.pThreatName = (result == CL_VIRUS) ? L"Fixme" : NULL; /* FIXME */
463
-    si.object = (HANDLE)_get_osfhandle(fd);
463
+    fdhdl = si.object = (HANDLE)_get_osfhandle(fd);
464 464
     si.pInnerObjectPath = NULL;
465
+    lo = SetFilePointer(fdhdl, 0, &hi, FILE_CURRENT);
466
+    SetFilePointer(fdhdl, 0, &hi2, FILE_BEGIN);
465 467
     inst->scancb(&si, &act, inst->scancb_ctx);
468
+    SetFilePointer(fdhdl, lo, &hi, FILE_BEGIN);
466 469
     switch(act) {
467 470
 	case CLAM_ACTION_SKIP:
468 471
 	    logg("postscan cb result: SKIP\n");
... ...
@@ -35,6 +35,7 @@ EXPORTS cl_strerror @27
35 35
 EXPORTS cl_engine_set_clcb_pre_scan @28
36 36
 EXPORTS cl_engine_set_clcb_post_scan @29
37 37
 EXPORTS cl_scandesc_callback @30
38
+EXPORTS cl_engine_set_clcb_sigload @31
38 39
 
39 40
 
40 41
 ; path variables
... ...
@@ -122,6 +123,8 @@ EXPORTS cli_hex2ui @44263 NONAME
122 122
 EXPORTS mpool_getstats @44264 NONAME
123 123
 EXPORTS cli_fmap_scandesc @44340
124 124
 EXPORTS cli_hashset_destroy @44341
125
+EXPORTS cli_scandesc_stats @44342
126
+EXPORTS cli_scanfile_stats @44343
125 127
 
126 128
 ; compatibility layer, tommath, zlib
127 129
 EXPORTS w32_srand @44265 NONAME