Browse code

libclamav: add initial support for logical signatures (bb#896)

git-svn: trunk@3993

Tomasz Kojm authored on 2008/07/26 04:00:25
Showing 9 changed files
... ...
@@ -1,3 +1,7 @@
1
+Fri Jul 25 20:41:21 CEST 2008 (tk)
2
+----------------------------------
3
+  * libclamav: add initial support for logical signatures (bb#896)
4
+
1 5
 Fri Jul 25 02:24:53 CEST 2008 (acab)
2 6
 ------------------------------------
3 7
   * libclamav/scanners.c: warn if no bzip2 support - bb#1060
... ...
@@ -163,7 +163,7 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
163 163
 	if(!root)
164 164
 	    return ret;
165 165
 
166
-	if(cli_ac_initdata(&mdata, root->ac_partsigs, AC_DEFAULT_TRACKLEN))
166
+	if(cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, AC_DEFAULT_TRACKLEN))
167 167
 	    return ret;
168 168
 
169 169
 	sret = cli_ac_scanbuff(buff, bread, NULL, engine->root[0], &mdata, 0, ret, desc, NULL, AC_SCAN_FT, NULL);
... ...
@@ -173,7 +173,7 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
173 173
 	if(sret >= CL_TYPENO) {
174 174
 	    ret = sret;
175 175
 	} else {
176
-	    if(cli_ac_initdata(&mdata, root->ac_partsigs, AC_DEFAULT_TRACKLEN))
176
+	    if(cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, AC_DEFAULT_TRACKLEN))
177 177
 		return ret;
178 178
 
179 179
 	    decoded = (unsigned char *) cli_utf16toascii((char *) buff, bread);
... ...
@@ -208,7 +208,7 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
208 208
 			     * (just eliminating zeros and matching would introduce false positives */
209 209
 			    if(encoding_normalize_toascii(&in_area, encoding, &out_area) >= 0 && out_area.length > 0) {
210 210
 				    out_area.buffer[out_area.length] = '\0';
211
-				    if(cli_ac_initdata(&mdata, root->ac_partsigs, AC_DEFAULT_TRACKLEN))
211
+				    if(cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, AC_DEFAULT_TRACKLEN))
212 212
 					    return ret;
213 213
 
214 214
 				    if(out_area.length > 0) {
... ...
@@ -25,6 +25,7 @@
25 25
 #include <stdio.h>
26 26
 #include <string.h>
27 27
 #include <stdlib.h>
28
+#include <ctype.h>
28 29
 #ifdef	HAVE_UNISTD_H
29 30
 #include <unistd.h>
30 31
 #endif
... ...
@@ -373,6 +374,228 @@ void cli_ac_free(struct cli_matcher *root)
373 373
     }
374 374
 }
375 375
 
376
+/*
377
+ * In parse_only mode this function returns -1 on error or the max subsig id
378
+ */
379
+int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigned int *cnt, unsigned int parse_only)
380
+{
381
+	unsigned int i, len = end - expr, pth = 0, opoff = 0, op1off = 0, val;
382
+	unsigned int blkend = 0, id, modval, lcnt = 0, rcnt = 0, tcnt, modoff = 0;
383
+	int ret, lval, rval;
384
+	char op = 0, op1 = 0, mod = 0, blkmod = 0;
385
+	const char *lstart = expr, *lend = NULL, *rstart = NULL, *rend = end, *pt;
386
+
387
+
388
+    for(i = 0; i < len; i++) {
389
+	switch(expr[i]) {
390
+	    case '(':
391
+		pth++;
392
+		break;
393
+
394
+	    case ')':
395
+		if(!pth) {
396
+		    cli_errmsg("cli_ac_chklsig: Syntax error: Missing opening parenthesis\n");
397
+		    return -1;
398
+		}
399
+		pth--;
400
+
401
+	    case '>':
402
+	    case '<':
403
+	    case '=':
404
+		mod = expr[i];
405
+		modoff = i;
406
+		break;
407
+
408
+	    default:
409
+		if(strchr("&|", expr[i])) {
410
+		    if(!pth) {
411
+			op = expr[i];
412
+			opoff = i;
413
+		    } else if(pth == 1) {
414
+			op1 = expr[i];
415
+			op1off = i;
416
+		    }
417
+		}
418
+	}
419
+
420
+	if(op)
421
+	    break;
422
+
423
+	if(op1 && !pth) {
424
+	    blkend = i;
425
+	    if(expr[i + 1] == '>' || expr[i + 1] == '<' || expr[i + 1] == '=') {
426
+		blkmod = expr[i + 1];
427
+		ret = sscanf(&expr[i + 2], "%u", &modval);
428
+		if(!ret || ret == EOF) {
429
+		    cli_errmsg("chklexpr: Syntax error: Missing number after '%c'\n", expr[i + 1]);
430
+		    return -1;
431
+		}
432
+		for(i += 2; i + 1 < len && isdigit(expr[i + 1]); i++);
433
+	    }
434
+
435
+	    if(&expr[i + 1] == rend)
436
+		break;
437
+	    else
438
+		blkmod = 0;
439
+	}
440
+    }
441
+
442
+    if(pth) {
443
+	cli_errmsg("cli_ac_chklsig: Syntax error: Missing closing parenthesis\n");
444
+	return -1;
445
+    }
446
+
447
+    if(!op && !op1) {
448
+	if(expr[0] == '(')
449
+	    return cli_ac_chklsig(++expr, --end, lsigcnt, cnt, parse_only);
450
+
451
+	ret = sscanf(expr, "%u", &id);
452
+	if(!ret || ret == EOF) {
453
+	    cli_errmsg("cli_ac_chklsig: Can't parse %s\n", expr);
454
+	    return -1;
455
+	}
456
+
457
+	if(parse_only)
458
+	    val = id;
459
+	else
460
+	    val = lsigcnt[id];
461
+
462
+	if(mod) {
463
+	    pt = strchr(expr, mod) + modoff;
464
+	    ret = sscanf(pt, "%u", &modval);
465
+	    if(!ret || ret == EOF) {
466
+		cli_errmsg("chklexpr: Syntax error: Missing number after '%c'\n", mod);
467
+		return -1;
468
+	    }
469
+	    if(!parse_only) switch(mod) {
470
+		case '=':
471
+		    if(val == modval) {
472
+			*cnt += val;
473
+			return 1;
474
+		    } else {
475
+			return 0;
476
+		    }
477
+		    break;
478
+		case '<':
479
+		    if(val < modval) {
480
+			*cnt += val;
481
+			return 1;
482
+		    } else {
483
+			return 0;
484
+		    }
485
+		    break;
486
+		case '>':
487
+		    if(val > modval) {
488
+			*cnt += val;
489
+			return 1;
490
+		    } else {
491
+			return 0;
492
+		    }
493
+	    }
494
+	}
495
+
496
+	if(parse_only) {
497
+	    return val;
498
+	} else {
499
+	    *cnt += val;
500
+	    return val ? 1 : 0;
501
+	}
502
+    }
503
+
504
+    if(!op) {
505
+	op = op1;
506
+	opoff = op1off;
507
+	lstart++;
508
+	rend = &expr[blkend];
509
+    }
510
+
511
+    if(!opoff) {
512
+	cli_errmsg("cli_ac_chklsig: Syntax error: Missing left argument\n");
513
+	return -1;
514
+    }
515
+    lend = &expr[opoff];
516
+    if(opoff + 1 == len) {
517
+	cli_errmsg("cli_ac_chklsig: Syntax error: Missing right argument\n");
518
+	return -1;
519
+    }
520
+    rstart = &expr[opoff + 1];
521
+
522
+    lval = cli_ac_chklsig(lstart, lend, lsigcnt, &lcnt, parse_only);
523
+    if(lval == -1) {
524
+	cli_errmsg("cli_ac_chklsig: Calculation of lval failed\n");
525
+	return -1;
526
+    }
527
+
528
+    rval = cli_ac_chklsig(rstart, rend, lsigcnt, &rcnt, parse_only);
529
+    if(rval == -1) {
530
+	cli_errmsg("cli_ac_chklsig: Calculation of rval failed\n");
531
+	return -1;
532
+    }
533
+
534
+    if(parse_only) {
535
+	switch(op) {
536
+	    case '&':
537
+	    case '|':
538
+		return MAX(lval, rval);
539
+	    default:
540
+		cli_errmsg("cli_ac_chklsig: Incorrect operator type\n");
541
+		return -1;
542
+	}
543
+    } else {
544
+	switch(op) {
545
+	    case '&':
546
+		ret = lval && rval;
547
+		break;
548
+	    case '|':
549
+		ret = lval || rval;
550
+		break;
551
+	    default:
552
+		cli_errmsg("cli_ac_chklsig: Incorrect operator type\n");
553
+		return -1;
554
+	}
555
+
556
+	if(!blkmod) {
557
+	    if(ret)
558
+		*cnt += lcnt + rcnt;
559
+
560
+	    return ret;
561
+	} else {
562
+	    if(ret)
563
+		tcnt = lcnt + rcnt;
564
+	    else
565
+		tcnt = 0;
566
+
567
+	    switch(blkmod) {
568
+		case '=':
569
+		    if(tcnt == modval) {
570
+			*cnt += tcnt;
571
+			return 1;
572
+		    } else {
573
+			return 0;
574
+		    }
575
+		    break;
576
+		case '<':
577
+		    if(tcnt < modval) {
578
+			*cnt += tcnt;
579
+			return 1;
580
+		    } else {
581
+			return 0;
582
+		    }
583
+		    break;
584
+		case '>':
585
+		    if(tcnt > modval) {
586
+			*cnt += tcnt;
587
+			return 1;
588
+		    } else {
589
+			return 0;
590
+		    }
591
+		default:
592
+		    return 0;
593
+	    }
594
+	}
595
+    }
596
+}
597
+
376 598
 /* 
377 599
  * FIXME: the current support for string alternatives uses a brute-force
378 600
  *        approach and doesn't perform any kind of verification and
... ...
@@ -501,8 +724,10 @@ inline static int ac_findmatch(const unsigned char *buffer, uint32_t offset, uin
501 501
     return 1;
502 502
 }
503 503
 
504
-int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint8_t tracklen)
504
+int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint32_t lsigs, uint8_t tracklen)
505 505
 {
506
+	unsigned int i;
507
+
506 508
 
507 509
     if(!data) {
508 510
 	cli_errmsg("cli_ac_init: data == NULL\n");
... ...
@@ -511,15 +736,35 @@ int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint8_t trackle
511 511
 
512 512
     data->partsigs = partsigs;
513 513
 
514
-    if(!partsigs)
515
-	return CL_SUCCESS;
516
-
517
-    data->offmatrix = (int32_t ***) cli_calloc(partsigs, sizeof(int32_t **));
518
-    if(!data->offmatrix) {
519
-	cli_errmsg("cli_ac_init: Can't allocate memory for data->offmatrix\n");
520
-	return CL_EMEM;
514
+    if(partsigs) {
515
+	data->offmatrix = (int32_t ***) cli_calloc(partsigs, sizeof(int32_t **));
516
+	if(!data->offmatrix) {
517
+	    cli_errmsg("cli_ac_init: Can't allocate memory for data->offmatrix\n");
518
+	    return CL_EMEM;
519
+	}
521 520
     }
522
-
521
+ 
522
+    data->lsigs = lsigs;
523
+    if(lsigs) {
524
+	data->lsigcnt = (uint32_t **) cli_malloc(lsigs * sizeof(uint32_t *));
525
+	if(!data->lsigcnt) {
526
+	    if(partsigs)
527
+		free(data->offmatrix);
528
+	    cli_errmsg("cli_ac_init: Can't allocate memory for data->lsigcnt\n");
529
+	    return CL_EMEM;
530
+	}
531
+	data->lsigcnt[0] = (uint32_t *) cli_calloc(lsigs * 64, sizeof(uint32_t));
532
+	if(!data->lsigcnt[0]) {
533
+	    free(data->lsigcnt);
534
+	    if(partsigs)
535
+		free(data->offmatrix);
536
+	    cli_errmsg("cli_ac_init: Can't allocate memory for data->lsigcnt[0]\n");
537
+	    return CL_EMEM;
538
+	}
539
+	for(i = 1; i < lsigs; i++)
540
+	    data->lsigcnt[i] = data->lsigcnt[0] + 64 * i;
541
+     }
542
+ 
523 543
     return CL_SUCCESS;
524 544
 }
525 545
 
... ...
@@ -536,6 +781,13 @@ void cli_ac_freedata(struct cli_ac_data *data)
536 536
 	    }
537 537
 	}
538 538
 	free(data->offmatrix);
539
+	data->partsigs = 0;
540
+    }
541
+
542
+    if(data && data->lsigs) {
543
+	free(data->lsigcnt[0]);
544
+	free(data->lsigcnt);
545
+	data->lsigs = 0;
539 546
     }
540 547
 }
541 548
 
... ...
@@ -581,6 +833,7 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
581 581
 	uint8_t found;
582 582
 	struct cli_target_info info;
583 583
 	int type = CL_CLEAN;
584
+	unsigned int evalcnt;
584 585
 
585 586
 
586 587
     if(!root->ac_root)
... ...
@@ -707,6 +960,12 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
707 707
 				    }
708 708
 
709 709
 				} else { /* !pt->type */
710
+				    if(pt->lsigid[0]) {
711
+					mdata->lsigcnt[pt->lsigid[1]][pt->lsigid[2]]++;
712
+					pt = pt->next;
713
+					continue;
714
+				    }
715
+
710 716
 				    if(virname)
711 717
 					*virname = pt->virname;
712 718
 
... ...
@@ -738,6 +997,12 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
738 738
 				    }
739 739
 				}
740 740
 			    } else {
741
+				if(pt->lsigid[0]) {
742
+				    mdata->lsigcnt[pt->lsigid[1]][pt->lsigid[2]]++;
743
+				    pt = pt->next;
744
+				    continue;
745
+				}
746
+
741 747
 				if(virname)
742 748
 				    *virname = pt->virname;
743 749
 
... ...
@@ -757,11 +1022,20 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
757 757
     if(info.exeinfo.section)
758 758
 	free(info.exeinfo.section);
759 759
 
760
+    for(i = 0; i < root->ac_lsigs; i++) {
761
+	evalcnt = 0;
762
+	if(cli_ac_chklsig(root->ac_lsigtable[i]->logic, root->ac_lsigtable[i]->logic + strlen(root->ac_lsigtable[i]->logic), mdata->lsigcnt[i], &evalcnt, 0) == 1) {
763
+	    if(virname)
764
+		*virname = root->ac_lsigtable[i]->virname;
765
+	    return CL_VIRUS;
766
+	}
767
+    }
768
+
760 769
     return (mode & AC_SCAN_FT) ? type : CL_CLEAN;
761 770
 }
762 771
 
763 772
 /* FIXME: clean up the code */
764
-int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t rtype, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, uint8_t target, unsigned int options)
773
+int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t rtype, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, uint8_t target, const uint32_t *lsigid, unsigned int options)
765 774
 {
766 775
 	struct cli_ac_patt *new;
767 776
 	char *pt, *pt2, *hex = NULL, *hexcpy = NULL;
... ...
@@ -771,6 +1045,11 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
771 771
 	int ret, error = CL_SUCCESS;
772 772
 
773 773
 
774
+    if(!root) {
775
+	cli_errmsg("cli_ac_addsig: root == NULL\n");
776
+	return CL_ENULLARG;
777
+    }
778
+
774 779
     if(strlen(hexsig) / 2 < root->ac_mindepth)
775 780
 	return CL_EPATSHORT;
776 781
 
... ...
@@ -787,6 +1066,10 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
787 787
     new->target = target;
788 788
     new->ch[0] |= CLI_MATCH_IGNORE;
789 789
     new->ch[1] |= CLI_MATCH_IGNORE;
790
+    if(lsigid) {
791
+	new->lsigid[0] = 1;
792
+	memcpy(&new->lsigid[1], lsigid, 2 * sizeof(uint32_t));
793
+    }
790 794
 
791 795
     if(strchr(hexsig, '[')) {
792 796
 	if(!(hexcpy = cli_strdup(hexsig))) {
... ...
@@ -1068,6 +1351,9 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1068 1068
 	return CL_EMEM;
1069 1069
     }
1070 1070
 
1071
+    if(new->lsigid[0])
1072
+	root->ac_lsigtable[new->lsigid[1]]->virname = new->virname;
1073
+
1071 1074
     if(offset) {
1072 1075
 	new->offset = cli_strdup(offset);
1073 1076
 	if(!new->offset) {
... ...
@@ -37,7 +37,8 @@ extern uint8_t cli_ac_mindepth, cli_ac_maxdepth;
37 37
 
38 38
 struct cli_ac_data {
39 39
     int32_t ***offmatrix;
40
-    uint32_t partsigs;
40
+    uint32_t partsigs, lsigs;
41
+    uint32_t **lsigcnt;
41 42
 };
42 43
 
43 44
 struct cli_ac_alt {
... ...
@@ -51,6 +52,7 @@ struct cli_ac_patt {
51 51
     uint16_t *pattern, *prefix, length, prefix_length;
52 52
     uint32_t mindist, maxdist;
53 53
     uint32_t sigid;
54
+    uint32_t lsigid[3];
54 55
     char *virname, *offset;
55 56
     uint16_t ch[2];
56 57
     uint16_t ch_mindist[2];
... ...
@@ -72,13 +74,14 @@ struct cli_ac_node {
72 72
 #include "matcher.h"
73 73
 
74 74
 int cli_ac_addpatt(struct cli_matcher *root, struct cli_ac_patt *pattern);
75
-int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint8_t tracklen);
75
+int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint32_t lsigs, uint8_t tracklen);
76
+int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigned int *cnt, unsigned int parse_only);
76 77
 void cli_ac_freedata(struct cli_ac_data *data);
77 78
 int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, int fd, struct cli_matched_type **ftoffset, unsigned int mode, const cli_ctx *ctx);
78 79
 int cli_ac_buildtrie(struct cli_matcher *root);
79 80
 int cli_ac_init(struct cli_matcher *root, uint8_t mindepth, uint8_t maxdepth);
80 81
 void cli_ac_free(struct cli_matcher *root);
81
-int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t rtype, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, uint8_t target, unsigned int options);
82
+int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t rtype, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, uint8_t target, const uint32_t *lsigid, unsigned int options);
82 83
 void cli_ac_setdepth(uint8_t mindepth, uint8_t maxdepth);
83 84
 
84 85
 #endif
... ...
@@ -72,7 +72,7 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, cli_ctx *ctx, cli
72 72
 
73 73
     if(troot) {
74 74
 
75
-	if((ret = cli_ac_initdata(&mdata, troot->ac_partsigs, AC_DEFAULT_TRACKLEN)))
75
+	if((ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, AC_DEFAULT_TRACKLEN)))
76 76
 	    return ret;
77 77
 
78 78
 	if(troot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, troot, 0, ftype, -1)) != CL_VIRUS)
... ...
@@ -84,7 +84,7 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, cli_ctx *ctx, cli
84 84
 	    return ret;
85 85
     }
86 86
 
87
-    if((ret = cli_ac_initdata(&mdata, groot->ac_partsigs, AC_DEFAULT_TRACKLEN)))
87
+    if((ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, AC_DEFAULT_TRACKLEN)))
88 88
 	return ret;
89 89
 
90 90
     if(groot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, groot, 0, ftype, -1)) != CL_VIRUS)
... ...
@@ -295,11 +295,11 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc
295 295
 	return CL_EMEM;
296 296
     }
297 297
 
298
-    if(!ftonly && (ret = cli_ac_initdata(&gdata, groot->ac_partsigs, AC_DEFAULT_TRACKLEN)))
298
+    if(!ftonly && (ret = cli_ac_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, AC_DEFAULT_TRACKLEN)))
299 299
 	return ret;
300 300
 
301 301
     if(troot) {
302
-	if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, AC_DEFAULT_TRACKLEN)))
302
+	if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, groot->ac_lsigs, AC_DEFAULT_TRACKLEN)))
303 303
 	    return ret;
304 304
     }
305 305
 
... ...
@@ -41,6 +41,28 @@
41 41
 #define CLI_MATCH_NIBBLE_HIGH	0x0300
42 42
 #define CLI_MATCH_NIBBLE_LOW	0x0400
43 43
 
44
+struct cli_lsig_tdb {
45
+#define CLI_TDB_UINT	0
46
+#define CLI_TDB_RANGE	1
47
+#define CLI_TDB_STR	2
48
+#define CLI_TDB_RANGE2	3
49
+    uint32_t *val, *range;
50
+    char *str;
51
+    uint32_t cnt[3];
52
+
53
+    const uint32_t *target;
54
+    const uint32_t *engine, *nos, *ep;
55
+    const uint32_t *sectoff, *sectrva, *sectvsz, *sectraw, *sectrsz,
56
+		   *secturva, *sectuvsz, *secturaw, *sectursz;
57
+};
58
+
59
+struct cli_ac_lsig {
60
+    uint32_t id;
61
+    char *logic;
62
+    const char *virname;
63
+    struct cli_lsig_tdb tdb;
64
+};
65
+
44 66
 struct cli_matcher {
45 67
     /* Extended Boyer-Moore */
46 68
     uint8_t *bm_shift;
... ...
@@ -50,7 +72,8 @@ struct cli_matcher {
50 50
     uint32_t bm_patterns;
51 51
 
52 52
     /* Extended Aho-Corasick */
53
-    uint32_t ac_partsigs, ac_nodes, ac_patterns;
53
+    uint32_t ac_partsigs, ac_nodes, ac_patterns, ac_lsigs;
54
+    struct cli_ac_lsig **ac_lsigtable;
54 55
     struct cli_ac_node *ac_root, **ac_nodetable;
55 56
     struct cli_ac_patt **ac_pattable;
56 57
     uint8_t ac_mindepth, ac_maxdepth;
... ...
@@ -18,10 +18,6 @@
18 18
  *  MA 02110-1301, USA.
19 19
  */
20 20
 
21
-#ifdef _MSC_VER
22
-#include <winsock.h> /* for Sleep() */
23
-#endif
24
-
25 21
 #if HAVE_CONFIG_H
26 22
 #include "clamav-config.h"
27 23
 #endif
... ...
@@ -58,6 +54,7 @@
58 58
 #include "filetypes.h"
59 59
 #include "filetypes_int.h"
60 60
 #include "readdb.h"
61
+#include "cltypes.h"
61 62
 
62 63
 #include "phishcheck.h"
63 64
 #include "phish_whitelist.h"
... ...
@@ -143,7 +140,7 @@ char *cli_virname(char *virname, unsigned int official, unsigned int allocated)
143 143
     return virname;
144 144
 }
145 145
 
146
-static int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hexsig, uint16_t rtype, uint16_t type, const char *offset, uint8_t target, unsigned int options)
146
+static int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hexsig, uint16_t rtype, uint16_t type, const char *offset, uint8_t target, const uint32_t *lsigid, unsigned int options)
147 147
 {
148 148
 	struct cli_bm_patt *bm_new;
149 149
 	char *pt, *hexcpy, *start, *n;
... ...
@@ -186,7 +183,7 @@ static int cli_parse_add(struct cli_matcher *root, const char *virname, const ch
186 186
 		*pt++ = 0;
187 187
 	    }
188 188
 
189
-	    if((ret = cli_ac_addsig(root, virname, start, root->ac_partsigs, parts, i, rtype, type, mindist, maxdist, offset, target, options))) {
189
+	    if((ret = cli_ac_addsig(root, virname, start, root->ac_partsigs, parts, i, rtype, type, mindist, maxdist, offset, target, lsigid, options))) {
190 190
 		cli_errmsg("cli_parse_add(): Problem adding signature (1).\n");
191 191
 		error = 1;
192 192
 		break;
... ...
@@ -266,7 +263,7 @@ static int cli_parse_add(struct cli_matcher *root, const char *virname, const ch
266 266
 		return CL_EMALFDB;
267 267
 	    }
268 268
 
269
-	    if((ret = cli_ac_addsig(root, virname, pt, root->ac_partsigs, parts, i, rtype, type, 0, 0, offset, target, options))) {
269
+	    if((ret = cli_ac_addsig(root, virname, pt, root->ac_partsigs, parts, i, rtype, type, 0, 0, offset, target, lsigid, options))) {
270 270
 		cli_errmsg("cli_parse_add(): Problem adding signature (2).\n");
271 271
 		free(pt);
272 272
 		return ret;
... ...
@@ -275,8 +272,8 @@ static int cli_parse_add(struct cli_matcher *root, const char *virname, const ch
275 275
 	    free(pt);
276 276
 	}
277 277
 
278
-    } else if(root->ac_only || strpbrk(hexsig, "?(") || type) {
279
-	if((ret = cli_ac_addsig(root, virname, hexsig, 0, 0, 0, rtype, type, 0, 0, offset, target, options))) {
278
+    } else if(root->ac_only || strpbrk(hexsig, "?(") || type || lsigid) {
279
+	if((ret = cli_ac_addsig(root, virname, hexsig, 0, 0, 0, rtype, type, 0, 0, offset, target, lsigid, options))) {
280 280
 	    cli_errmsg("cli_parse_add(): Problem adding signature (3).\n");
281 281
 	    return ret;
282 282
 	}
... ...
@@ -490,7 +487,7 @@ static int cli_loaddb(FILE *fs, struct cl_engine **engine, unsigned int *signo,
490 490
 
491 491
 	if(*pt == '=') continue;
492 492
 
493
-	if((ret = cli_parse_add(root, start, pt, 0, 0, NULL, 0, options))) {
493
+	if((ret = cli_parse_add(root, start, pt, 0, 0, NULL, 0, NULL, options))) {
494 494
 	    ret = CL_EMALFDB;
495 495
 	    break;
496 496
 	}
... ...
@@ -669,7 +666,7 @@ static int cli_loadndb(FILE *fs, struct cl_engine **engine, unsigned int *signo,
669 669
 	    break;
670 670
 	}
671 671
 
672
-	if((ret = cli_parse_add(root, virname, sig, 0, 0, offset, target, options))) {
672
+	if((ret = cli_parse_add(root, virname, sig, 0, 0, offset, target, NULL, options))) {
673 673
 	    ret = CL_EMALFDB;
674 674
 	    break;
675 675
 	}
... ...
@@ -699,6 +696,335 @@ static int cli_loadndb(FILE *fs, struct cl_engine **engine, unsigned int *signo,
699 699
     return CL_SUCCESS;
700 700
 }
701 701
 
702
+struct lsig_attrib {
703
+    const char *name;
704
+    unsigned int type;
705
+    void **pt;
706
+};
707
+
708
+/* TODO: rework this */
709
+static int lsigattribs(char *attribs, struct cli_lsig_tdb *tdb)
710
+{
711
+	struct lsig_attrib attrtab[] = {
712
+#define ATTRIB_TOKENS	2
713
+	    { "Target",	    CLI_TDB_UINT,	(void **) &tdb->target	    },
714
+	    { "Engine",	    CLI_TDB_RANGE,	(void **) &tdb->engine	    },
715
+/*
716
+	    { "NoS",	    CLI_TDB_RANGE,	(void **) &tdb->nos	    },
717
+	    { "EP",	    CLI_TDB_RANGE,	(void **) &tdb->ep	    },
718
+	    { "SectOff",    CLI_TDB_RANGE2,	(void **) &tdb->sectoff	    },
719
+	    { "SectRVA",    CLI_TDB_RANGE2,	(void **) &tdb->sectrva	    },
720
+	    { "SectVSZ",    CLI_TDB_RANGE2,	(void **) &tdb->sectvsz	    },
721
+	    { "SectRAW",    CLI_TDB_RANGE2,	(void **) &tdb->sectraw	    },
722
+	    { "SectRSZ",    CLI_TDB_RANGE2,	(void **) &tdb->sectrsz	    },
723
+	    { "SectURVA",   CLI_TDB_RANGE2,	(void **) &tdb->secturva    },
724
+	    { "SectUVSZ",   CLI_TDB_RANGE2,	(void **) &tdb->sectuvsz    },
725
+	    { "SectURAW",   CLI_TDB_RANGE2,	(void **) &tdb->secturaw    },
726
+	    { "SectURSZ",   CLI_TDB_RANGE2,	(void **) &tdb->sectursz    },
727
+*/
728
+	    { NULL,	    0,			NULL,			    }
729
+	};
730
+	struct lsig_attrib *apt;
731
+	char *tokens[ATTRIB_TOKENS], *pt, *pt2;
732
+	unsigned int v1, v2, v3, i, j;
733
+	uint32_t cnt, off[ATTRIB_TOKENS];
734
+
735
+
736
+    cli_strtokenize(attribs, ',', ATTRIB_TOKENS, (const char **) tokens);
737
+
738
+    for(i = 0; tokens[i]; i++) {
739
+	if(!(pt = strchr(tokens[i], ':'))) {
740
+	    cli_errmsg("lsigattribs: Incorrect format of attribute '%s'\n", tokens[i]);
741
+	    return -1;
742
+	}
743
+	*pt++ = 0;
744
+
745
+	apt = NULL;
746
+	for(j = 0; attrtab[j].name; j++) {
747
+	    if(!strcmp(attrtab[j].name, tokens[i])) {
748
+		apt = &attrtab[j];
749
+		break;
750
+	    }
751
+	}
752
+
753
+	if(!apt) {
754
+	    cli_dbgmsg("lsigattribs: Unknown attribute name '%s'\n", tokens[i]);
755
+	    continue;
756
+	}
757
+
758
+	switch(apt->type) {
759
+	    case CLI_TDB_UINT:
760
+		off[i] = cnt = tdb->cnt[CLI_TDB_UINT]++;
761
+		tdb->val = (uint32_t *) cli_realloc2(tdb->val, tdb->cnt[CLI_TDB_UINT] * sizeof(uint32_t));
762
+		if(!tdb->val) {
763
+		    tdb->cnt[CLI_TDB_UINT] = 0;
764
+		    return -1;
765
+		}
766
+		tdb->val[cnt] = atoi(pt);
767
+		break;
768
+
769
+	    case CLI_TDB_RANGE:
770
+		if(!(pt2 = strchr(pt, '-'))) {
771
+		    cli_errmsg("lsigattribs: Incorrect parameters in '%s'\n", tokens[i]);
772
+		    return -1;
773
+		}
774
+		*pt2++ = 0;
775
+		off[i] = cnt = tdb->cnt[CLI_TDB_RANGE];
776
+		tdb->cnt[CLI_TDB_RANGE] += 2;
777
+		tdb->range = (uint32_t *) cli_realloc2(tdb->range, tdb->cnt[CLI_TDB_RANGE] * sizeof(uint32_t));
778
+		if(!tdb->range) {
779
+		    tdb->cnt[CLI_TDB_RANGE] = 0;
780
+		    return -1;
781
+		}
782
+		tdb->range[cnt] = atoi(pt);
783
+		tdb->range[cnt + 1] = atoi(pt2);
784
+		break;
785
+
786
+	    case CLI_TDB_RANGE2:
787
+		if(!strchr(pt, '-') || !strchr(pt, '.')) {
788
+		    cli_errmsg("lsigattribs: Incorrect parameters in '%s'\n", tokens[i]);
789
+		    return -1;
790
+		}
791
+		off[i] = cnt = tdb->cnt[CLI_TDB_RANGE];
792
+		tdb->cnt[CLI_TDB_RANGE] += 3;
793
+		tdb->range = (uint32_t *) cli_realloc2(tdb->range, tdb->cnt[CLI_TDB_RANGE] * sizeof(uint32_t));
794
+		if(!tdb->range) {
795
+		    tdb->cnt[CLI_TDB_RANGE] = 0;
796
+		    return -1;
797
+		}
798
+		if(sscanf(pt, "%u.%u-%u", &v1, &v2, &v3) != 3) {
799
+		    cli_errmsg("lsigattribs: Can't parse parameters in '%s'\n", tokens[i]);
800
+		    return -1;
801
+		}
802
+		tdb->range[cnt] = (uint32_t) v1;
803
+		tdb->range[cnt + 1] = (uint32_t) v2;
804
+		tdb->range[cnt + 2] = (uint32_t) v3;
805
+		break;
806
+
807
+	    case CLI_TDB_STR:
808
+		off[i] = cnt = tdb->cnt[CLI_TDB_STR];
809
+		tdb->cnt[CLI_TDB_STR] += strlen(pt) + 1;
810
+		tdb->str = (char *) cli_realloc2(tdb->str, tdb->cnt[CLI_TDB_STR] * sizeof(char));
811
+		if(!tdb->str) {
812
+		    cli_errmsg("lsigattribs: Can't allocate memory for tdb->str\n");
813
+		    return -1;
814
+		}
815
+		memcpy(&tdb->str[cnt], pt, strlen(pt));
816
+		tdb->str[tdb->cnt[CLI_TDB_STR] - 1] = 0;
817
+		break;
818
+	}
819
+    }
820
+
821
+    if(!i) {
822
+	cli_errmsg("lsigattribs: Empty TDB\n");
823
+	return -1;
824
+    }
825
+
826
+    for(i = 0; tokens[i]; i++) {
827
+	for(j = 0; attrtab[j].name; j++) {
828
+	    if(!strcmp(attrtab[j].name, tokens[i])) {
829
+		apt = &attrtab[j];
830
+		break;
831
+	    }
832
+	}
833
+	switch(apt->type) {
834
+	    case CLI_TDB_UINT:
835
+		*apt->pt = (uint32_t *) &tdb->val[off[i]];
836
+		break;
837
+
838
+	    case CLI_TDB_RANGE:
839
+	    case CLI_TDB_RANGE2:
840
+		*apt->pt = (uint32_t *) &tdb->range[off[i]];
841
+		break;
842
+
843
+	    case CLI_TDB_STR:
844
+		*apt->pt = (char *) &tdb->str[off[i]];
845
+		break;
846
+	}
847
+    }
848
+
849
+    return 0;
850
+}
851
+
852
+#define FREE_TDB(x)		\
853
+    if(x.cnt[CLI_TDB_UINT])	\
854
+	free(x.val);		\
855
+    if(x.cnt[CLI_TDB_RANGE])    \
856
+	free(x.range);		\
857
+    if(x.cnt[CLI_TDB_STR])	\
858
+	free(x.str);
859
+
860
+#define LDB_TOKENS 67
861
+static int cli_loadldb(FILE *fs, struct cl_engine **engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio, const char *dbname)
862
+{
863
+	char *tokens[LDB_TOKENS];
864
+	char buffer[32768], *pt;
865
+	const char *sig, *virname, *offset, *logic;
866
+	struct cli_matcher *root;
867
+	unsigned int line = 0, sigs = 0;
868
+	unsigned short target = 0;
869
+	struct cli_ac_lsig **newtable, *lsig;
870
+	uint32_t lsigid[2];
871
+	int ret = CL_SUCCESS, i, subsigs;
872
+	struct cli_lsig_tdb tdb;
873
+
874
+
875
+    if((ret = cli_initengine(engine, options))) {
876
+	cl_free(*engine);
877
+	return ret;
878
+    }
879
+
880
+    if((ret = cli_initroots(*engine, options))) {
881
+	cl_free(*engine);
882
+	return ret;
883
+    }
884
+
885
+    while(cli_dbgets(buffer, FILEBUFF, fs, dbio)) {
886
+	line++;
887
+	sigs++;
888
+	cli_chomp(buffer);
889
+
890
+	cli_strtokenize(buffer, ';', LDB_TOKENS, (const char **) tokens);
891
+
892
+	if(!(virname = tokens[0])) {
893
+	    ret = CL_EMALFDB;
894
+	    break;
895
+	}
896
+
897
+	if((*engine)->ignored && cli_chkign((*engine)->ignored, dbname, line, virname))
898
+	    continue;
899
+
900
+	if(!(logic = tokens[2])) {
901
+	    ret = CL_EMALFDB;
902
+	    break;
903
+	}
904
+
905
+	subsigs = cli_ac_chklsig(logic, logic + strlen(logic), NULL, NULL, 1);
906
+	if(subsigs == -1) {
907
+	    ret = CL_EMALFDB;
908
+	    break;
909
+	}
910
+	subsigs++;
911
+
912
+	if(subsigs > 64) {
913
+	    cli_errmsg("cli_loadldb: Broken logical expression or too many subsignatures\n");
914
+	    ret = CL_EMALFDB;
915
+	    break;
916
+	}
917
+
918
+	/* TDB */
919
+	memset(&tdb, 0, sizeof(tdb));
920
+
921
+	if(lsigattribs(tokens[1], &tdb) == -1) {
922
+	    FREE_TDB(tdb);
923
+	    ret = CL_EMALFDB;
924
+	    break;
925
+	}
926
+
927
+	if(tdb.engine) {
928
+	    if(tdb.engine[0] > cl_retflevel()) {
929
+		cli_dbgmsg("cli_loadldb: Signature for %s not loaded (required f-level: %u)\n", virname, tdb.engine[0]);
930
+		FREE_TDB(tdb);
931
+		sigs--;
932
+		continue;
933
+	    } else if(tdb.engine[1] < cl_retflevel()) {
934
+		FREE_TDB(tdb);
935
+		sigs--;
936
+		continue;
937
+	    }
938
+	}
939
+
940
+	if(!tdb.target) {
941
+	    cli_errmsg("cli_loadldb: No target specified in TDB\n");
942
+	    FREE_TDB(tdb);
943
+	    ret = CL_EMALFDB;
944
+	    break;
945
+	} else if(tdb.target[0] >= CLI_MTARGETS) {
946
+	    cli_dbgmsg("cli_loadldb: Not supported target type in logical signature for %s\n", virname);
947
+	    FREE_TDB(tdb);
948
+	    sigs--;
949
+	    continue;
950
+	}
951
+
952
+	root = (*engine)->root[tdb.target[0]];
953
+
954
+	lsig = (struct cli_ac_lsig *) cli_calloc(1, sizeof(struct cli_ac_lsig));
955
+	if(!lsig) {
956
+	    cli_errmsg("cli_loadldb: Can't allocate memory for lsig\n");
957
+	    FREE_TDB(tdb);
958
+	    ret = CL_EMEM;
959
+	    break;
960
+	}
961
+	lsig->logic = cli_strdup(logic);
962
+	if(!lsig->logic) {
963
+	    cli_errmsg("cli_loadldb: Can't allocate memory for lsig->logic\n");
964
+	    FREE_TDB(tdb);
965
+	    ret = CL_EMEM;
966
+	    free(lsig);
967
+	    break;
968
+	}
969
+
970
+	lsigid[0] = lsig->id = root->ac_lsigs;
971
+	memcpy(&lsig->tdb, &tdb, sizeof(tdb));
972
+
973
+	root->ac_lsigs++;
974
+	newtable = (struct cli_ac_lsig **) cli_realloc(root->ac_lsigtable, root->ac_lsigs * sizeof(struct cli_ac_lsig *));
975
+	if(!newtable) {
976
+	    root->ac_lsigs--;
977
+	    cli_errmsg("cli_loadldb: Can't realloc root->ac_lsigtable\n");
978
+	    FREE_TDB(tdb);
979
+	    free(lsig);
980
+	    ret = CL_EMEM;
981
+	    break;
982
+	}
983
+	newtable[root->ac_lsigs - 1] = lsig;
984
+	root->ac_lsigtable = newtable;
985
+
986
+	for(i = 0; i < subsigs; i++) {
987
+	    if(!tokens[3 + i]) {
988
+		cli_errmsg("cli_loadldb: Missing subsignature id %u\n", i);
989
+		ret = CL_EMALFDB;
990
+		break;
991
+	    }
992
+	    lsigid[1] = i;
993
+	    sig = tokens[3 + i];
994
+
995
+	    if((pt = strchr(tokens[3 + i], ':'))) {
996
+		*pt = 0;
997
+		sig = ++pt;
998
+		offset = tokens[3 + i];
999
+	    } else {
1000
+		offset = NULL;
1001
+		sig = tokens[3 + i];
1002
+	    }
1003
+
1004
+	    if((ret = cli_parse_add(root, virname, sig, 0, 0, offset, target, lsigid, options))) {
1005
+		ret = CL_EMALFDB;
1006
+		break;
1007
+	    }
1008
+	}
1009
+	if(ret)
1010
+	    break;
1011
+    }
1012
+
1013
+    if(!line) {
1014
+	cli_errmsg("Empty database file\n");
1015
+	cl_free(*engine);
1016
+	return CL_EMALFDB;
1017
+    }
1018
+
1019
+    if(ret) {
1020
+	cli_errmsg("Problem parsing database at line %u\n", line);
1021
+	cl_free(*engine);
1022
+	return ret;
1023
+    }
1024
+
1025
+    if(signo)
1026
+	*signo += sigs;
1027
+
1028
+    return CL_SUCCESS;
1029
+}
1030
+
702 1031
 #define FTM_TOKENS 8	
703 1032
 static int cli_loadftm(FILE *fs, struct cl_engine **engine, unsigned int options, unsigned int internal, struct cli_dbio *dbio)
704 1033
 {
... ...
@@ -766,7 +1092,7 @@ static int cli_loadftm(FILE *fs, struct cl_engine **engine, unsigned int options
766 766
 	}
767 767
 
768 768
 	if(atoi(tokens[0]) == 1) { /* A-C */
769
-	    if((ret = cli_parse_add((*engine)->root[0], tokens[3], tokens[2], rtype, type, strcmp(tokens[1], "*") ? tokens[1] : NULL, 0, options)))
769
+	    if((ret = cli_parse_add((*engine)->root[0], tokens[3], tokens[2], rtype, type, strcmp(tokens[1], "*") ? tokens[1] : NULL, 0, NULL, options)))
770 770
 		break;
771 771
 
772 772
 	} else if(atoi(tokens[0]) == 0) { /* memcmp() */
... ...
@@ -1324,6 +1650,15 @@ int cli_load(const char *filename, struct cl_engine **engine, unsigned int *sign
1324 1324
 	else
1325 1325
 	    ret = cli_loadndb(fs, engine, signo, 0, options, dbio, dbname);
1326 1326
 
1327
+    } else if(cli_strbcasestr(filename, ".ldb")) {
1328
+       ret = cli_loadldb(fs, engine, signo, options, dbio, dbname);
1329
+
1330
+    } else if(cli_strbcasestr(filename, ".ldu")) {
1331
+	if(options & CL_DB_PUA)
1332
+	    ret = cli_loadldb(fs, engine, signo, options, dbio, dbname);
1333
+	else
1334
+	    skipped = 1;
1335
+
1327 1336
     } else if(cli_strbcasestr(dbname, ".sdb")) {
1328 1337
 	ret = cli_loadndb(fs, engine, signo, 1, options, dbio, dbname);
1329 1338
 
... ...
@@ -1715,7 +2050,7 @@ int cl_statfree(struct cl_stat *dbstat)
1715 1715
 
1716 1716
 void cl_free(struct cl_engine *engine)
1717 1717
 {
1718
-	int i;
1718
+	unsigned int i, j;
1719 1719
 	struct cli_meta_node *metapt, *metah;
1720 1720
 	struct cli_matcher *root;
1721 1721
 
... ...
@@ -1749,6 +2084,14 @@ void cl_free(struct cl_engine *engine)
1749 1749
 		if(!root->ac_only)
1750 1750
 		    cli_bm_free(root);
1751 1751
 		cli_ac_free(root);
1752
+		if(root->ac_lsigtable) {
1753
+		    for(j = 0; j < root->ac_lsigs; j++) {
1754
+			free(root->ac_lsigtable[j]->logic);
1755
+			FREE_TDB(root->ac_lsigtable[j]->tdb);
1756
+			free(root->ac_lsigtable[j]);
1757
+		    }
1758
+		    free(root->ac_lsigtable);
1759
+		}
1752 1760
 		free(root);
1753 1761
 	    }
1754 1762
 	}
... ...
@@ -39,6 +39,8 @@
39 39
 	cli_strbcasestr(ext, ".mdu")   ||	\
40 40
 	cli_strbcasestr(ext, ".ndb")   ||	\
41 41
 	cli_strbcasestr(ext, ".ndu")   ||	\
42
+	cli_strbcasestr(ext, ".ldb")   ||	\
43
+	cli_strbcasestr(ext, ".ldu")   ||	\
42 44
 	cli_strbcasestr(ext, ".sdb")   ||	\
43 45
 	cli_strbcasestr(ext, ".zmd")   ||	\
44 46
 	cli_strbcasestr(ext, ".rmd")   ||	\
... ...
@@ -273,7 +273,7 @@ int regex_list_match(struct regex_matcher* matcher,char* real_url,const char* di
273 273
 		buffer[buffer_len]=0;
274 274
 		cli_dbgmsg("Looking up in regex_list: %s\n", buffer);
275 275
 
276
-		if((rc = cli_ac_initdata(&mdata, 0, AC_DEFAULT_TRACKLEN)))
276
+		if((rc = cli_ac_initdata(&mdata, 0, 0, AC_DEFAULT_TRACKLEN)))
277 277
 			return rc;
278 278
 
279 279
 		bufrev = cli_strdup(buffer);