e3aaff8e |
/* |
f51e962f |
* Copyright (C) 2002 - 2006 Tomasz Kojm <tkojm@clamav.net> |
e3aaff8e |
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software |
48b7b4a7 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA. |
e3aaff8e |
*/
|
6d6e8271 |
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
|
e3aaff8e |
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h> |
15edd45f |
#include <sys/param.h> |
e3aaff8e |
#include <fcntl.h>
#include "clamav.h" |
e4ae7726 |
#include "cvd.h" |
e3aaff8e |
#include "strings.h" |
8000d078 |
#include "matcher-ac.h"
#include "matcher-bm.h" |
e3aaff8e |
#include "others.h"
#include "str.h"
#include "defaults.h"
|
2bb229f6 |
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
#include <limits.h> |
88794204 |
#include <stddef.h> |
2bb229f6 |
#endif
|
15edd45f |
/* Maximum filenames under various systems - njh */
#ifndef NAME_MAX /* e.g. Linux */
# ifdef MAXNAMELEN /* e.g. Solaris */
# define NAME_MAX MAXNAMELEN
# else
# ifdef FILENAME_MAX /* e.g. SCO */
# define NAME_MAX FILENAME_MAX |
3d42cc7a |
# else
# define NAME_MAX 256 |
15edd45f |
# endif
# endif
#endif
|
f51e962f |
#ifdef CL_THREAD_SAFE
# include <pthread.h>
static pthread_mutex_t cli_ref_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
#ifdef HAVE_HWACCEL
#include <sn_sigscan/sn_sigscan.h>
#endif
|
8000d078 |
/* TODO: clean up the code */ |
888f5794 |
|
5612732c |
static int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, int sigid, int parts, int partno, unsigned short type, unsigned int mindist, unsigned int maxdist, char *offset, unsigned short target) |
e3aaff8e |
{ |
8000d078 |
struct cli_ac_patt *new; |
084ee140 |
char *pt, *hex; |
33f89aa5 |
int virlen, ret, error = 0;
unsigned int i; |
e3aaff8e |
|
8000d078 |
if((new = (struct cli_ac_patt *) cli_calloc(1, sizeof(struct cli_ac_patt))) == NULL) |
e3aaff8e |
return CL_EMEM;
|
888f5794 |
new->type = type; |
e3aaff8e |
new->sigid = sigid;
new->parts = parts;
new->partno = partno; |
084ee140 |
new->mindist = mindist;
new->maxdist = maxdist; |
b68d11d2 |
new->target = target;
new->offset = offset; |
e3aaff8e |
|
084ee140 |
if(strchr(hexsig, '(')) { |
4048c4f6 |
char *hexcpy, *hexnew, *start, *h, *c; |
084ee140 |
if(!(hexcpy = strdup(hexsig))) {
free(new);
return CL_EMEM;
}
if(!(hexnew = (char *) cli_calloc(strlen(hexsig) + 1, 1))) {
free(hexcpy);
free(new);
return CL_EMEM;
}
start = pt = hexcpy;
while((pt = strchr(start, '('))) {
*pt++ = 0;
if(!start) {
error = 1;
break;
}
strcat(hexnew, start);
strcat(hexnew, "@@");
if(!(start = strchr(pt, ')'))) {
error = 1;
break;
}
*start++ = 0;
new->alt++; |
87fa90f0 |
new->altn = (unsigned short int *) realloc(new->altn, new->alt * sizeof(unsigned short int)); |
084ee140 |
new->altn[new->alt - 1] = 0; |
d0cb1e9c |
new->altc = (char **) realloc(new->altc, new->alt * sizeof(char *)); |
58744aab |
new->altc[new->alt - 1] = NULL; |
084ee140 |
for(i = 0; i < strlen(pt); i++)
if(pt[i] == '|')
new->altn[new->alt - 1]++;
if(!new->altn[new->alt - 1]) {
error = 1;
break;
} else
new->altn[new->alt - 1]++;
if(!(new->altc[new->alt - 1] = (char *) cli_calloc(new->altn[new->alt - 1], 1))) {
error = 1;
break;
}
for(i = 0; i < new->altn[new->alt - 1]; i++) {
if((h = cli_strtok(pt, i, "|")) == NULL) {
error = 1;
break;
}
|
4048c4f6 |
if((c = cli_hex2str(h)) == NULL) { |
084ee140 |
free(h);
error = 1;
break;
}
|
4048c4f6 |
new->altc[new->alt - 1][i] = *c; |
084ee140 |
free(c);
free(h);
}
if(error)
break;
}
if(start)
strcat(hexnew, start);
hex = hexnew;
free(hexcpy);
if(error) {
free(hexnew);
if(new->alt) {
free(new->altn);
for(i = 0; i < new->alt; i++) |
58744aab |
if(new->altc[i])
free(new->altc[i]); |
084ee140 |
free(new->altc);
}
free(new);
return CL_EMALFDB;
}
} else
hex = (char *) hexsig;
new->length = strlen(hex) / 2; |
e3aaff8e |
if(new->length > root->maxpatlen)
root->maxpatlen = new->length;
|
4048c4f6 |
if((new->pattern = cli_hex2si(hex)) == NULL) { |
084ee140 |
if(new->alt) {
free(new->altn);
for(i = 0; i < new->alt; i++)
free(new->altc[i]);
free(new->altc);
free(hex);
} |
e3aaff8e |
free(new);
return CL_EMALFDB;
}
if((pt = strstr(virname, "(Clam)")))
virlen = strlen(virname) - strlen(pt) - 1;
else
virlen = strlen(virname);
|
831b61bf |
if(virlen <= 0) { |
4332ab2b |
free(new->pattern); |
084ee140 |
if(new->alt) {
free(new->altn);
for(i = 0; i < new->alt; i++)
free(new->altc[i]);
free(new->altc);
free(hex);
} |
831b61bf |
free(new);
return CL_EMALFDB;
}
|
ee039e40 |
if((new->virname = cli_calloc(virlen + 1, sizeof(char))) == NULL) { |
4332ab2b |
free(new->pattern); |
084ee140 |
if(new->alt) {
free(new->altn);
for(i = 0; i < new->alt; i++)
free(new->altc[i]);
free(new->altc);
free(hex);
} |
ee039e40 |
free(new); |
e3aaff8e |
return CL_EMEM; |
ee039e40 |
}
|
658f19f8 |
strncpy(new->virname, virname, virlen); |
e3aaff8e |
|
8000d078 |
if((ret = cli_ac_addpatt(root, new))) { |
4332ab2b |
free(new->pattern); |
ee039e40 |
free(new->virname); |
084ee140 |
if(new->alt) {
free(new->altn);
for(i = 0; i < new->alt; i++)
free(new->altc[i]);
free(new->altc);
free(hex);
} |
ee039e40 |
free(new); |
e3aaff8e |
return ret; |
ee039e40 |
} |
e3aaff8e |
|
084ee140 |
if(new->alt)
free(hex);
|
e3aaff8e |
return 0;
}
|
5612732c |
int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hexsig, unsigned short type, char *offset, unsigned short target) |
888f5794 |
{ |
8000d078 |
struct cli_bm_patt *bm_new; |
084ee140 |
char *pt, *hexcpy, *start, *n; |
33f89aa5 |
int ret, virlen, asterisk = 0;
unsigned int i, j, len, parts = 0; |
084ee140 |
int mindist = 0, maxdist = 0, error = 0;
|
888f5794 |
|
084ee140 |
if(strchr(hexsig, '{')) { |
888f5794 |
|
8000d078 |
root->ac_partsigs++; |
084ee140 |
if(!(hexcpy = strdup(hexsig)))
return CL_EMEM;
len = strlen(hexsig);
for(i = 0; i < len; i++) |
a8f79297 |
if(hexsig[i] == '{' || hexsig[i] == '*') |
084ee140 |
parts++;
if(parts)
parts++;
start = pt = hexcpy;
for(i = 1; i <= parts; i++) {
if(i != parts) { |
a8f79297 |
for(j = 0; j < strlen(start); j++) {
if(start[j] == '{') {
asterisk = 0;
pt = start + j;
break;
}
if(start[j] == '*') {
asterisk = 1;
pt = start + j;
break;
}
} |
084ee140 |
*pt++ = 0;
}
|
b68d11d2 |
if((ret = cli_ac_addsig(root, virname, start, root->ac_partsigs, parts, i, type, mindist, maxdist, offset, target))) { |
a8f79297 |
cli_errmsg("cli_parse_add(): Problem adding signature (1).\n"); |
084ee140 |
error = 1;
break;
}
if(i == parts)
break;
|
a8f79297 |
mindist = maxdist = 0;
if(asterisk) {
start = pt;
continue;
}
|
084ee140 |
if(!(start = strchr(pt, '}'))) {
error = 1;
break;
}
*start++ = 0;
if(!pt) {
error = 1;
break;
}
if(!strchr(pt, '-')) {
if((mindist = maxdist = atoi(pt)) < 0) {
error = 1;
break;
}
} else { |
b68d11d2 |
if((n = cli_strtok(pt, 0, "-"))) { |
084ee140 |
if((mindist = atoi(n)) < 0) {
error = 1;
free(n);
break;
}
free(n);
}
|
b68d11d2 |
if((n = cli_strtok(pt, 1, "-"))) { |
084ee140 |
if((maxdist = atoi(n)) < 0) {
error = 1;
free(n);
break;
}
free(n);
}
}
}
free(hexcpy);
if(error)
return CL_EMALFDB;
} else if(strchr(hexsig, '*')) { |
8000d078 |
root->ac_partsigs++; |
888f5794 |
len = strlen(hexsig);
for(i = 0; i < len; i++)
if(hexsig[i] == '*')
parts++;
|
8000d078 |
if(parts) |
888f5794 |
parts++;
for(i = 1; i <= parts; i++) {
if((pt = cli_strtok(hexsig, i - 1, "*")) == NULL) {
cli_errmsg("Can't extract part %d of partial signature.\n", i + 1);
return CL_EMALFDB;
}
|
b68d11d2 |
if((ret = cli_ac_addsig(root, virname, pt, root->ac_partsigs, parts, i, type, 0, 0, offset, target))) { |
a8f79297 |
cli_errmsg("cli_parse_add(): Problem adding signature (2).\n"); |
888f5794 |
free(pt);
return ret;
}
free(pt);
}
|
83fa5305 |
} else if(root->ac_only || strpbrk(hexsig, "?(") || type) { |
b68d11d2 |
if((ret = cli_ac_addsig(root, virname, hexsig, 0, 0, 0, type, 0, 0, offset, target))) { |
a8f79297 |
cli_errmsg("cli_parse_add(): Problem adding signature (3).\n"); |
8000d078 |
return ret;
}
} else {
bm_new = (struct cli_bm_patt *) calloc(1, sizeof(struct cli_bm_patt));
if(!bm_new)
return CL_EMEM;
|
091df0e3 |
if(!(bm_new->pattern = cli_hex2str(hexsig))) {
free(bm_new); |
8000d078 |
return CL_EMALFDB; |
091df0e3 |
} |
8000d078 |
bm_new->length = strlen(hexsig) / 2;
if((pt = strstr(virname, "(Clam)")))
virlen = strlen(virname) - strlen(pt) - 1;
else
virlen = strlen(virname);
if(virlen <= 0) { |
091df0e3 |
free(bm_new->pattern); |
8000d078 |
free(bm_new);
return CL_EMALFDB;
}
if((bm_new->virname = cli_calloc(virlen + 1, sizeof(char))) == NULL) { |
091df0e3 |
free(bm_new->pattern); |
8000d078 |
free(bm_new);
return CL_EMEM;
}
strncpy(bm_new->virname, virname, virlen);
|
b68d11d2 |
bm_new->offset = offset;
bm_new->target = target;
|
8000d078 |
if(bm_new->length > root->maxpatlen)
root->maxpatlen = bm_new->length;
if((ret = cli_bm_addpatt(root, bm_new))) { |
a8f79297 |
cli_errmsg("cli_parse_add(): Problem adding signature (4).\n"); |
091df0e3 |
free(bm_new->pattern);
free(bm_new->virname);
free(bm_new); |
888f5794 |
return ret;
}
}
return 0;
} |
e3aaff8e |
|
83fa5305 |
static int cli_initengine(struct cl_engine **engine, unsigned int options) |
e3aaff8e |
{ |
5612732c |
struct cli_matcher *root;
int i, ret; |
e3aaff8e |
|
5612732c |
if(!*engine) {
cli_dbgmsg("Initializing the engine structure\n");
*engine = (struct cl_engine *) cli_calloc(1, sizeof(struct cl_engine));
if(!*engine) {
cli_errmsg("Can't allocate memory for the engine structure!\n"); |
4048c4f6 |
return CL_EMEM; |
5612732c |
}
(*engine)->refcount = 1; |
e3aaff8e |
|
5612732c |
(*engine)->root = (struct cli_matcher **) cli_calloc(CL_TARGET_TABLE_SIZE, sizeof(struct cli_matcher *));
if(!(*engine)->root) {
/* no need to free previously allocated memory here */
cli_errmsg("Can't allocate memory for roots!\n"); |
4048c4f6 |
return CL_EMEM;
} |
ee039e40 |
} |
f7148839 |
|
5612732c |
return 0;
}
|
83fa5305 |
static int cli_initroots(struct cl_engine *engine, unsigned int options) |
5612732c |
{
int i, ret;
struct cli_matcher *root;
for(i = 0; i < CL_TARGET_TABLE_SIZE; i++) {
if(!engine->root[i]) {
cli_dbgmsg("Initializing engine->root[%d]\n", i);
root = engine->root[i] = (struct cli_matcher *) cli_calloc(1, sizeof(struct cli_matcher));
if(!root) {
cli_errmsg("Can't initialise AC pattern matcher\n");
return CL_EMEM;
}
|
83fa5305 |
if(options & CL_DB_ACONLY) {
cli_dbgmsg("Only using AC pattern matcher.\n");
root->ac_only = 1;
}
|
5612732c |
cli_dbgmsg("Initialising AC pattern matcher of root[%d]\n", i);
root->ac_root = (struct cli_ac_node *) cli_calloc(1, sizeof(struct cli_ac_node));
if(!root->ac_root) {
/* no need to free previously allocated memory here */
cli_errmsg("Can't initialise AC pattern matcher\n");
return CL_EMEM;
}
|
83fa5305 |
if(!root->ac_only) {
cli_dbgmsg("Initializing BM tables of root[%d]\n", i);
if((ret = cli_bm_init(root))) {
cli_errmsg("Can't initialise BM pattern matcher\n");
return ret;
} |
5612732c |
} |
8000d078 |
}
}
|
5612732c |
return 0;
}
|
15e1a7cd |
static int cli_loaddb(FILE *fd, struct cl_engine **engine, unsigned int *signo, unsigned int options) |
5612732c |
{
char buffer[FILEBUFF], *pt, *start;
int line = 0, ret = 0;
struct cli_matcher *root;
|
83fa5305 |
if((ret = cli_initengine(engine, options))) { |
5612732c |
cl_free(*engine);
return ret;
}
|
83fa5305 |
if((ret = cli_initroots(*engine, options))) { |
5612732c |
cl_free(*engine);
return ret;
}
root = (*engine)->root[0];
|
4048c4f6 |
while(fgets(buffer, FILEBUFF, fd)) {
line++;
cli_chomp(buffer);
pt = strchr(buffer, '=');
if(!pt) {
cli_errmsg("Malformed pattern line %d\n", line);
ret = CL_EMALFDB;
break;
}
start = buffer;
*pt++ = 0; |
ee039e40 |
|
4048c4f6 |
if(*pt == '=') continue; |
ee039e40 |
|
5612732c |
if((ret = cli_parse_add(root, start, pt, 0, NULL, 0))) { |
b68d11d2 |
cli_errmsg("Problem parsing signature at line %d\n", line);
ret = CL_EMALFDB;
break;
}
}
if(!line) {
cli_errmsg("Empty database file\n"); |
5612732c |
cl_free(*engine); |
b68d11d2 |
return CL_EMALFDB;
}
if(ret) {
cli_errmsg("Problem parsing database at line %d\n", line); |
5612732c |
cl_free(*engine); |
b68d11d2 |
return ret;
}
if(signo)
*signo += line;
return 0;
}
|
555c5390 |
static int cli_loadndb(FILE *fd, struct cl_engine **engine, unsigned int *signo, unsigned short sdb, unsigned int options) |
b68d11d2 |
{
char buffer[FILEBUFF], *sig, *virname, *offset, *pt; |
5612732c |
struct cli_matcher *root; |
95083a4f |
int line = 0, sigs = 0, ret = 0; |
b68d11d2 |
unsigned short target; |
d6449522 |
unsigned int nophish = options & CL_DB_NOPHISHING; |
b68d11d2 |
|
83fa5305 |
if((ret = cli_initengine(engine, options))) { |
5612732c |
cl_free(*engine);
return ret; |
b68d11d2 |
}
|
83fa5305 |
if((ret = cli_initroots(*engine, options))) { |
5612732c |
cl_free(*engine);
return ret; |
b68d11d2 |
}
while(fgets(buffer, FILEBUFF, fd)) {
line++; |
7afdc309 |
if(!strncmp(buffer, "Exploit.JPEG.Comment", 20)) /* temporary */
continue;
|
d6449522 |
if(nophish)
if(!strncmp(buffer, "HTML.Phishing", 13) || !strncmp(buffer, "Email.Phishing", 14))
continue;
|
95083a4f |
sigs++; |
b68d11d2 |
cli_chomp(buffer);
if(!(virname = cli_strtok(buffer, 0, ":"))) {
ret = CL_EMALFDB;
break;
}
|
555c5390 |
if((pt = cli_strtok(buffer, 4, ":"))) { /* min version */ |
95083a4f |
if(!isdigit(*pt)) {
free(virname);
free(pt);
ret = CL_EMALFDB;
break;
}
if(atoi(pt) > cl_retflevel()) { |
5612732c |
cli_dbgmsg("Signature for %s requires new ClamAV version. Please update!\n", virname); |
95083a4f |
sigs--;
free(virname);
free(pt);
continue;
}
free(pt); |
555c5390 |
if((pt = cli_strtok(buffer, 5, ":"))) { /* max version */
if(!isdigit(*pt)) {
free(virname);
free(pt);
ret = CL_EMALFDB;
break;
}
if(atoi(pt) < cl_retflevel()) {
sigs--;
free(virname);
free(pt);
continue;
}
free(pt);
} |
95083a4f |
}
|
b68d11d2 |
if(!(pt = cli_strtok(buffer, 1, ":")) || !isdigit(*pt)) {
free(virname); |
95083a4f |
if(pt)
free(pt); |
b68d11d2 |
ret = CL_EMALFDB;
break;
}
target = (unsigned short) atoi(pt);
free(pt);
|
5612732c |
if(target >= CL_TARGET_TABLE_SIZE) {
cli_dbgmsg("Not supported target type in signature for %s\n", virname);
sigs--;
free(virname);
free(pt);
continue;
}
root = (*engine)->root[target];
|
b68d11d2 |
if(!(offset = cli_strtok(buffer, 2, ":"))) {
free(virname);
ret = CL_EMALFDB;
break; |
7ec67e94 |
} else if(!strcmp(offset, "*")) {
free(offset);
offset = NULL; |
b68d11d2 |
}
if(!(sig = cli_strtok(buffer, 3, ":"))) {
free(virname);
free(offset);
ret = CL_EMALFDB;
break;
}
|
5612732c |
if((ret = cli_parse_add(root, virname, sig, 0, offset, target))) { |
4048c4f6 |
cli_errmsg("Problem parsing signature at line %d\n", line); |
b68d11d2 |
free(virname);
free(offset);
free(sig); |
4048c4f6 |
ret = CL_EMALFDB;
break;
} |
b68d11d2 |
free(virname);
free(sig); |
ee039e40 |
}
|
4048c4f6 |
if(!line) {
cli_errmsg("Empty database file\n"); |
5612732c |
cl_free(*engine); |
4048c4f6 |
return CL_EMALFDB;
} |
8139fd99 |
|
4048c4f6 |
if(ret) { |
b68d11d2 |
cli_errmsg("Problem parsing database at line %d\n", line); |
5612732c |
cl_free(*engine); |
8139fd99 |
return ret;
}
|
3805ebcb |
if(signo) |
95083a4f |
*signo += sigs; |
4048c4f6 |
|
555c5390 |
if(sdb && sigs && !(*engine)->sdb) {
(*engine)->sdb = 1;
cli_dbgmsg("*** Self protection mechanism activated.\n");
}
|
4048c4f6 |
return 0;
}
|
15e1a7cd |
static int cli_loadhdb(FILE *fd, struct cl_engine **engine, unsigned int *signo, unsigned short fp, unsigned int options) |
4048c4f6 |
{ |
8000d078 |
char buffer[FILEBUFF], *pt; |
4048c4f6 |
int line = 0, ret = 0;
struct cli_md5_node *new; |
e3aaff8e |
|
4048c4f6 |
|
83fa5305 |
if((ret = cli_initengine(engine, options))) { |
5612732c |
cl_free(*engine);
return ret; |
4048c4f6 |
}
while(fgets(buffer, FILEBUFF, fd)) { |
e3aaff8e |
line++;
cli_chomp(buffer);
|
4048c4f6 |
new = (struct cli_md5_node *) cli_calloc(1, sizeof(struct cli_md5_node));
if(!new) {
ret = CL_EMEM;
break; |
e3aaff8e |
}
|
db65451b |
new->fp = fp;
|
4048c4f6 |
if(!(pt = cli_strtok(buffer, 0, ":"))) {
free(new);
ret = CL_EMALFDB;
break;
} |
e3aaff8e |
|
058ccefe |
if(!(new->md5 = (unsigned char *) cli_hex2str(pt))) { |
4048c4f6 |
cli_errmsg("Malformed MD5 string at line %d\n", line);
free(pt);
free(new);
ret = CL_EMALFDB;
break; |
e3aaff8e |
} |
4048c4f6 |
free(pt); |
e3aaff8e |
|
022a21cf |
if(!(pt = cli_strtok(buffer, 1, ":"))) {
free(new->md5);
free(new);
ret = CL_EMALFDB;
break;
}
new->size = atoi(pt);
free(pt);
if(!(new->virname = cli_strtok(buffer, 2, ":"))) { |
4048c4f6 |
free(new->md5);
free(new);
ret = CL_EMALFDB;
break; |
e3aaff8e |
} |
4048c4f6 |
|
022a21cf |
new->viralias = cli_strtok(buffer, 3, ":"); /* aliases are optional */ |
4048c4f6 |
|
5612732c |
if(!(*engine)->md5_hlist) { |
8000d078 |
cli_dbgmsg("Initializing md5 list structure\n"); |
5612732c |
(*engine)->md5_hlist = (struct cli_md5_node **) cli_calloc(256, sizeof(struct cli_md5_node *));
if(!(*engine)->md5_hlist) { |
8000d078 |
ret = CL_EMEM;
break;
}
}
|
5612732c |
new->next = (*engine)->md5_hlist[new->md5[0] & 0xff];
(*engine)->md5_hlist[new->md5[0] & 0xff] = new; |
e3aaff8e |
}
|
4048c4f6 |
if(!line) {
cli_errmsg("Empty database file\n"); |
5612732c |
cl_free(*engine); |
4048c4f6 |
return CL_EMALFDB;
} |
e3aaff8e |
|
4048c4f6 |
if(ret) { |
b68d11d2 |
cli_errmsg("Problem parsing database at line %d\n", line); |
5612732c |
cl_free(*engine); |
4048c4f6 |
return ret;
} |
ee039e40 |
|
3805ebcb |
if(signo)
*signo += line; |
3365db23 |
|
e3aaff8e |
return 0;
}
|
15e1a7cd |
static int cli_loadmd(FILE *fd, struct cl_engine **engine, unsigned int *signo, int type, unsigned int options) |
e5916a51 |
{
char buffer[FILEBUFF], *pt;
int line = 0, comments = 0, ret = 0; |
a62ae54f |
struct cli_meta_node *new; |
e5916a51 |
|
83fa5305 |
if((ret = cli_initengine(engine, options))) { |
5612732c |
cl_free(*engine);
return ret; |
e5916a51 |
}
while(fgets(buffer, FILEBUFF, fd)) {
line++;
if(buffer[0] == '#') {
comments++;
continue;
}
cli_chomp(buffer);
|
a62ae54f |
new = (struct cli_meta_node *) cli_calloc(1, sizeof(struct cli_meta_node)); |
e5916a51 |
if(!new) {
ret = CL_EMEM;
break;
}
if(!(new->virname = cli_strtok(buffer, 0, ":"))) {
free(new);
ret = CL_EMALFDB;
break;
}
if(!(pt = cli_strtok(buffer, 1, ":"))) {
free(new->virname);
free(new);
ret = CL_EMALFDB;
break;
} else {
new->encrypted = atoi(pt);
free(pt);
}
if(!(new->filename = cli_strtok(buffer, 2, ":"))) {
free(new->virname);
free(new);
ret = CL_EMALFDB;
break;
} else {
if(!strcmp(new->filename, "*")) {
free(new->filename);
new->filename = NULL;
}
}
if(!(pt = cli_strtok(buffer, 3, ":"))) {
free(new->filename);
free(new->virname);
free(new);
ret = CL_EMALFDB;
break;
} else {
if(!strcmp(pt, "*"))
new->size = -1;
else
new->size = atoi(pt);
free(pt);
}
if(!(pt = cli_strtok(buffer, 4, ":"))) {
free(new->filename);
free(new->virname);
free(new);
ret = CL_EMALFDB;
break;
} else {
if(!strcmp(pt, "*"))
new->csize = -1;
else
new->csize = atoi(pt);
free(pt);
}
if(!(pt = cli_strtok(buffer, 5, ":"))) {
free(new->filename);
free(new->virname);
free(new);
ret = CL_EMALFDB;
break;
} else {
if(!strcmp(pt, "*")) {
new->crc32 = 0;
} else {
new->crc32 = cli_hex2num(pt);
if(new->crc32 == -1) {
ret = CL_EMALFDB;
break;
}
}
free(pt);
}
if(!(pt = cli_strtok(buffer, 6, ":"))) {
free(new->filename);
free(new->virname);
free(new);
ret = CL_EMALFDB;
break;
} else {
if(!strcmp(pt, "*")) |
a62ae54f |
new->method = -1; |
e5916a51 |
else |
a62ae54f |
new->method = atoi(pt); |
e5916a51 |
free(pt);
}
|
19e2ac07 |
if(!(pt = cli_strtok(buffer, 7, ":"))) {
free(new->filename);
free(new->virname);
free(new);
ret = CL_EMALFDB;
break;
} else {
if(!strcmp(pt, "*"))
new->fileno = 0;
else
new->fileno = atoi(pt);
free(pt);
}
if(!(pt = cli_strtok(buffer, 8, ":"))) {
free(new->filename);
free(new->virname);
free(new);
ret = CL_EMALFDB;
break;
} else {
if(!strcmp(pt, "*"))
new->maxdepth = 0;
else
new->maxdepth = atoi(pt);
free(pt);
}
|
a62ae54f |
if(type == 1) { |
5612732c |
new->next = (*engine)->zip_mlist;
(*engine)->zip_mlist = new; |
a62ae54f |
} else { |
5612732c |
new->next = (*engine)->rar_mlist;
(*engine)->rar_mlist = new; |
a62ae54f |
} |
e5916a51 |
}
if(!line) {
cli_errmsg("Empty database file\n"); |
5612732c |
cl_free(*engine); |
e5916a51 |
return CL_EMALFDB;
}
if(ret) {
cli_errmsg("Problem parsing database at line %d\n", line); |
5612732c |
cl_free(*engine); |
e5916a51 |
return ret;
}
if(signo)
*signo += (line - comments);
return 0;
}
|
f51e962f |
#ifdef HAVE_HWACCEL
static int cli_loadhw(const char *filename, struct cl_engine **engine, unsigned int *signo, unsigned int options)
{
int ret = 0;
if((ret = cli_initengine(engine, options))) {
cl_free(*engine);
return ret;
}
if((ret = sn_sigscan_initdb(&(*engine)->hwdb)) < 0) {
cli_errmsg("hwaccel: error initializing the matcher: %d\n", ret);
cl_free(*engine);
return CL_EHWINIT;
}
(*engine)->hwaccel = 1;
if((ret = sn_sigscan_loaddb((*engine)->hwdb, filename, 0, signo)) < 0) {
cli_errmsg("hwaccel: can't load hardware database: %d\n", ret);
cl_free(*engine);
return CL_EHWLOAD;
}
return CL_SUCCESS;
}
#endif /* HAVE_HWACCEL */
|
04933acd |
static int cli_load(const char *filename, struct cl_engine **engine, unsigned int *signo, unsigned int options) |
e3aaff8e |
{ |
4048c4f6 |
FILE *fd; |
f51e962f |
int ret = CL_SUCCESS;
|
4048c4f6 |
|
f51e962f |
#ifdef HAVE_HWACCEL
if(options & CL_DB_HWACCEL) {
if(cli_strbcasestr(filename, ".hw")) {
cli_dbgmsg("Loading %s\n", filename);
ret = cli_loadhw(filename, engine, signo, options);
} else {
cli_dbgmsg("Ignoring %s\n", filename);
}
return ret;
}
#endif /* HAVE_HWACCEL */ |
4048c4f6 |
if((fd = fopen(filename, "rb")) == NULL) { |
f51e962f |
cli_errmsg("cli_load(): Can't open file %s\n", filename); |
4048c4f6 |
return CL_EOPEN;
}
cli_dbgmsg("Loading %s\n", filename);
if(cli_strbcasestr(filename, ".db") || cli_strbcasestr(filename, ".db2") || cli_strbcasestr(filename, ".db3")) { |
15e1a7cd |
ret = cli_loaddb(fd, engine, signo, options); |
4048c4f6 |
} else if(cli_strbcasestr(filename, ".cvd")) { |
37743d67 |
int warn = 0;
if(!strcmp(filename, "daily.cvd"))
warn = 1;
|
15e1a7cd |
ret = cli_cvdload(fd, engine, signo, warn, options); |
4048c4f6 |
|
26720e3f |
} else if(cli_strbcasestr(filename, ".hdb")) { |
15e1a7cd |
ret = cli_loadhdb(fd, engine, signo, 0, options); |
db65451b |
} else if(cli_strbcasestr(filename, ".fp")) { |
15e1a7cd |
ret = cli_loadhdb(fd, engine, signo, 1, options); |
4048c4f6 |
|
b68d11d2 |
} else if(cli_strbcasestr(filename, ".ndb")) { |
555c5390 |
ret = cli_loadndb(fd, engine, signo, 0, options);
} else if(cli_strbcasestr(filename, ".sdb")) {
ret = cli_loadndb(fd, engine, signo, 1, options); |
b68d11d2 |
|
e5916a51 |
} else if(cli_strbcasestr(filename, ".zmd")) { |
15e1a7cd |
ret = cli_loadmd(fd, engine, signo, 1, options); |
a62ae54f |
} else if(cli_strbcasestr(filename, ".rmd")) { |
15e1a7cd |
ret = cli_loadmd(fd, engine, signo, 2, options); |
e5916a51 |
|
8df99ec7 |
} else if(cli_strbcasestr(filename, ".hw")) {
/* ignore */
|
4048c4f6 |
} else { |
f51e962f |
cli_dbgmsg("cli_load: unknown extension - assuming old database format\n"); |
15e1a7cd |
ret = cli_loaddb(fd, engine, signo, options); |
4048c4f6 |
}
if(ret) |
975ef8ce |
cli_errmsg("Can't load %s: %s\n", filename, cl_strerror(ret)); |
4048c4f6 |
fclose(fd);
return ret; |
e3aaff8e |
}
|
04933acd |
int cl_loaddb(const char *filename, struct cl_engine **engine, unsigned int *signo) {
return cli_load(filename, engine, signo, 0);
}
static int cli_loaddbdir(const char *dirname, struct cl_engine **engine, unsigned int *signo, unsigned int options) |
e3aaff8e |
{
DIR *dd;
struct dirent *dent; |
72a1b240 |
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2) |
88794204 |
union {
struct dirent d;
char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
} result; |
2bb229f6 |
#endif |
e3aaff8e |
char *dbfile;
int ret;
if((dd = opendir(dirname)) == NULL) { |
15e1a7cd |
cli_errmsg("cli_loaddbdir(): Can't open directory %s\n", dirname); |
e3aaff8e |
return CL_EOPEN;
}
cli_dbgmsg("Loading databases from %s\n", dirname);
|
72a1b240 |
#ifdef HAVE_READDIR_R_3 |
88794204 |
while(!readdir_r(dd, &result.d, &dent) && dent) { |
72a1b240 |
#elif defined(HAVE_READDIR_R_2) |
88794204 |
while((dent = (struct dirent *) readdir_r(dd, &result.d))) { |
72a1b240 |
#else |
e3aaff8e |
while((dent = readdir(dd))) { |
72a1b240 |
#endif |
feeaa333 |
#ifndef C_INTERIX
if(dent->d_ino)
#endif
{ |
8139fd99 |
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") && |
cfeb200c |
(cli_strbcasestr(dent->d_name, ".db") ||
cli_strbcasestr(dent->d_name, ".db2") ||
cli_strbcasestr(dent->d_name, ".db3") ||
cli_strbcasestr(dent->d_name, ".hdb") || |
a62ae54f |
cli_strbcasestr(dent->d_name, ".fp") || |
cfeb200c |
cli_strbcasestr(dent->d_name, ".ndb") || |
555c5390 |
cli_strbcasestr(dent->d_name, ".sdb") || |
19e2ac07 |
cli_strbcasestr(dent->d_name, ".zmd") || |
a62ae54f |
cli_strbcasestr(dent->d_name, ".rmd") || |
f51e962f |
cli_strbcasestr(dent->d_name, ".hw") || |
8139fd99 |
cli_strbcasestr(dent->d_name, ".cvd"))) {
|
e3aaff8e |
dbfile = (char *) cli_calloc(strlen(dent->d_name) + strlen(dirname) + 2, sizeof(char));
if(!dbfile) { |
15e1a7cd |
cli_dbgmsg("cli_loaddbdir(): dbfile == NULL\n"); |
e3aaff8e |
closedir(dd);
return CL_EMEM;
}
sprintf(dbfile, "%s/%s", dirname, dent->d_name); |
15e1a7cd |
if((ret = cli_load(dbfile, engine, signo, options))) {
cli_dbgmsg("cli_loaddbdir(): error loading database %s\n", dbfile); |
e3aaff8e |
free(dbfile);
closedir(dd);
return ret;
}
free(dbfile);
}
}
}
closedir(dd);
return 0;
}
|
04933acd |
int cl_loaddbdir(const char *dirname, struct cl_engine **engine, unsigned int *signo) {
return cli_loaddbdir(dirname, engine, signo, 0);
}
int cl_load(const char *path, struct cl_engine **engine, unsigned int *signo, unsigned int options)
{
struct stat sb; |
f7470773 |
int ret; |
04933acd |
if(stat(path, &sb) == -1) {
cli_errmsg("cl_loaddbdir(): Can't get status of %s\n", path);
return CL_EIO;
}
|
83fa5305 |
if((ret = cli_initengine(engine, options))) { |
f7470773 |
cl_free(*engine);
return ret;
}
|
f51e962f |
switch(sb.st_mode & S_IFMT) { |
04933acd |
case S_IFREG:
return cli_load(path, engine, signo, options);
case S_IFDIR:
return cli_loaddbdir(path, engine, signo, options);
default:
cli_errmsg("cl_load(): Not supported database file type\n");
return CL_EOPEN;
}
}
|
4048c4f6 |
const char *cl_retdbdir(void)
{
return DATADIR;
}
|
e3aaff8e |
int cl_statinidir(const char *dirname, struct cl_stat *dbstat)
{
DIR *dd; |
2bb229f6 |
const struct dirent *dent; |
72a1b240 |
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2) |
88794204 |
union {
struct dirent d;
char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
} result; |
2bb229f6 |
#endif |
e3aaff8e |
char *fname;
if(dbstat) {
dbstat->no = 0;
dbstat->stattab = NULL; |
75ccac9f |
dbstat->statdname = NULL; |
e3aaff8e |
dbstat->dir = strdup(dirname);
} else {
cli_errmsg("cl_statdbdir(): Null argument passed.\n");
return CL_ENULLARG;
}
if((dd = opendir(dirname)) == NULL) {
cli_errmsg("cl_statdbdir(): Can't open directory %s\n", dirname);
return CL_EOPEN;
}
cli_dbgmsg("Stat()ing files in %s\n", dirname);
|
72a1b240 |
#ifdef HAVE_READDIR_R_3 |
88794204 |
while(!readdir_r(dd, &result.d, &dent) && dent) { |
72a1b240 |
#elif defined(HAVE_READDIR_R_2) |
88794204 |
while((dent = (struct dirent *) readdir_r(dd, &result.d))) { |
72a1b240 |
#else |
e3aaff8e |
while((dent = readdir(dd))) { |
72a1b240 |
#endif |
feeaa333 |
#ifndef C_INTERIX
if(dent->d_ino)
#endif
{ |
8000d078 |
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") &&
(cli_strbcasestr(dent->d_name, ".db") ||
cli_strbcasestr(dent->d_name, ".db2") ||
cli_strbcasestr(dent->d_name, ".db3") ||
cli_strbcasestr(dent->d_name, ".hdb") || |
f51e962f |
cli_strbcasestr(dent->d_name, ".fp") || |
b68d11d2 |
cli_strbcasestr(dent->d_name, ".ndb") || |
555c5390 |
cli_strbcasestr(dent->d_name, ".sdb") || |
19e2ac07 |
cli_strbcasestr(dent->d_name, ".zmd") || |
a62ae54f |
cli_strbcasestr(dent->d_name, ".rmd") || |
f51e962f |
cli_strbcasestr(dent->d_name, ".hw") || |
8000d078 |
cli_strbcasestr(dent->d_name, ".cvd"))) { |
e3aaff8e |
dbstat->no++;
dbstat->stattab = (struct stat *) realloc(dbstat->stattab, dbstat->no * sizeof(struct stat)); |
e871e527 |
#if defined(C_INTERIX) || defined(C_OS2) |
75ccac9f |
dbstat->statdname = (char **) realloc(dbstat->statdname, dbstat->no * sizeof(char *));
#endif
|
e3aaff8e |
fname = cli_calloc(strlen(dirname) + strlen(dent->d_name) + 2, sizeof(char));
sprintf(fname, "%s/%s", dirname, dent->d_name); |
e871e527 |
#if defined(C_INTERIX) || defined(C_OS2) |
75ccac9f |
dbstat->statdname[dbstat->no - 1] = (char *) calloc(strlen(dent->d_name) + 1, sizeof(char));
strcpy(dbstat->statdname[dbstat->no - 1], dent->d_name);
#endif |
e3aaff8e |
stat(fname, &dbstat->stattab[dbstat->no - 1]);
free(fname);
}
}
}
closedir(dd);
return 0;
}
int cl_statchkdir(const struct cl_stat *dbstat)
{
DIR *dd;
struct dirent *dent; |
72a1b240 |
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2) |
88794204 |
union {
struct dirent d;
char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
} result; |
2bb229f6 |
#endif |
e3aaff8e |
struct stat sb;
int i, found;
char *fname;
if(!dbstat || !dbstat->dir) {
cli_errmsg("cl_statdbdir(): Null argument passed.\n");
return CL_ENULLARG;
}
if((dd = opendir(dbstat->dir)) == NULL) {
cli_errmsg("cl_statdbdir(): Can't open directory %s\n", dbstat->dir);
return CL_EOPEN;
}
cli_dbgmsg("Stat()ing files in %s\n", dbstat->dir);
|
72a1b240 |
#ifdef HAVE_READDIR_R_3 |
88794204 |
while(!readdir_r(dd, &result.d, &dent) && dent) { |
72a1b240 |
#elif defined(HAVE_READDIR_R_2) |
88794204 |
while((dent = (struct dirent *) readdir_r(dd, &result.d))) { |
72a1b240 |
#else |
e3aaff8e |
while((dent = readdir(dd))) { |
72a1b240 |
#endif |
feeaa333 |
#ifndef C_INTERIX
if(dent->d_ino)
#endif
{ |
8000d078 |
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") &&
(cli_strbcasestr(dent->d_name, ".db") ||
cli_strbcasestr(dent->d_name, ".db2") ||
cli_strbcasestr(dent->d_name, ".db3") ||
cli_strbcasestr(dent->d_name, ".hdb") || |
f51e962f |
cli_strbcasestr(dent->d_name, ".fp") || |
b68d11d2 |
cli_strbcasestr(dent->d_name, ".ndb") || |
555c5390 |
cli_strbcasestr(dent->d_name, ".sdb") || |
19e2ac07 |
cli_strbcasestr(dent->d_name, ".zmd") || |
a62ae54f |
cli_strbcasestr(dent->d_name, ".rmd") || |
f51e962f |
cli_strbcasestr(dent->d_name, ".hw") || |
8000d078 |
cli_strbcasestr(dent->d_name, ".cvd"))) { |
e3aaff8e |
fname = cli_calloc(strlen(dbstat->dir) + strlen(dent->d_name) + 2, sizeof(char));
sprintf(fname, "%s/%s", dbstat->dir, dent->d_name);
stat(fname, &sb);
free(fname);
found = 0;
for(i = 0; i < dbstat->no; i++) |
e871e527 |
#if defined(C_INTERIX) || defined(C_OS2) |
75ccac9f |
if(!strcmp(dbstat->statdname[i], dent->d_name)) {
#else |
e3aaff8e |
if(dbstat->stattab[i].st_ino == sb.st_ino) { |
75ccac9f |
#endif |
e3aaff8e |
found = 1; |
e3f0de57 |
if(dbstat->stattab[i].st_mtime != sb.st_mtime) {
closedir(dd); |
e3aaff8e |
return 1; |
e3f0de57 |
} |
e3aaff8e |
}
|
e3f0de57 |
if(!found) {
closedir(dd); |
e3aaff8e |
return 1; |
e3f0de57 |
} |
e3aaff8e |
}
}
}
closedir(dd);
return 0;
}
int cl_statfree(struct cl_stat *dbstat)
{
if(dbstat) { |
75ccac9f |
|
e871e527 |
#if defined(C_INTERIX) || defined(C_OS2) |
75ccac9f |
int i;
for(i = 0;i < dbstat->no; i++) {
free(dbstat->statdname[i]);
dbstat->statdname[i] = NULL;
}
free(dbstat->statdname);
dbstat->statdname = NULL;
#endif
|
e3aaff8e |
free(dbstat->stattab);
dbstat->stattab = NULL;
dbstat->no = 0; |
9e431a95 |
if(dbstat->dir) { |
e3aaff8e |
free(dbstat->dir); |
9e431a95 |
dbstat->dir = NULL;
} |
e3aaff8e |
} else { |
8000d078 |
cli_errmsg("cl_statfree(): Null argument passed\n"); |
e3aaff8e |
return CL_ENULLARG;
}
return 0;
} |
f51e962f |
void cl_free(struct cl_engine *engine)
{
int i, ret;
struct cli_md5_node *md5pt, *md5h;
struct cli_meta_node *metapt, *metah;
struct cli_matcher *root;
if(!engine) {
cli_errmsg("cl_free: engine == NULL\n");
return;
}
#ifdef CL_THREAD_SAFE
pthread_mutex_lock(&cli_ref_mutex);
#endif
engine->refcount--;
if(engine->refcount) {
#ifdef CL_THREAD_SAFE
pthread_mutex_unlock(&cli_ref_mutex);
#endif
return;
}
#ifdef CL_THREAD_SAFE
pthread_mutex_unlock(&cli_ref_mutex);
#endif
#ifdef HAVE_HWACCEL
if(engine->hwaccel) {
if((ret = sn_sigscan_closedb(engine->hwdb)) < 0) {
cli_errmsg("cl_free: can't close hardware database: %d\n", ret);
}
}
#endif
for(i = 0; i < CL_TARGET_TABLE_SIZE; i++) {
if((root = engine->root[i])) {
cli_ac_free(root);
if(!engine->root[i]->ac_only)
cli_bm_free(root);
}
}
if(engine->md5_hlist) {
for(i = 0; i < 256; i++) {
md5pt = engine->md5_hlist[i];
while(md5pt) {
md5h = md5pt;
md5pt = md5pt->next;
free(md5h->md5);
free(md5h->virname);
if(md5h->viralias)
free(md5h->viralias);
free(md5h);
}
}
free(engine->md5_hlist);
}
metapt = engine->zip_mlist;
while(metapt) {
metah = metapt;
metapt = metapt->next;
free(metah->virname);
if(metah->filename)
free(metah->filename);
free(metah);
}
metapt = engine->rar_mlist;
while(metapt) {
metah = metapt;
metapt = metapt->next;
free(metah->virname);
if(metah->filename)
free(metah->filename);
free(metah);
}
free(engine);
}
int cl_build(struct cl_engine *engine)
{
int i, ret;
struct cli_matcher *root;
if((ret = cli_addtypesigs(engine)))
return ret;
for(i = 0; i < CL_TARGET_TABLE_SIZE; i++)
if((root = engine->root[i]))
cli_ac_buildtrie(root);
/* FIXME: check return values of cli_ac_buildtree */
return 0;
}
struct cl_engine *cl_dup(struct cl_engine *engine)
{
if(!engine) {
cli_errmsg("cl_dup: engine == NULL\n");
return NULL;
}
#ifdef CL_THREAD_SAFE
pthread_mutex_lock(&cli_ref_mutex);
#endif
engine->refcount++;
#ifdef CL_THREAD_SAFE
pthread_mutex_unlock(&cli_ref_mutex);
#endif
return engine;
} |