e3aaff8e |
/* |
54402320 |
* Copyright (C) 2007-2012 Sourcefire, Inc. |
4addba22 |
* |
2023340a |
* Authors: Tomasz Kojm |
e3aaff8e |
*
* This program is free software; you can redistribute it and/or modify |
bb34cb31 |
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. |
e3aaff8e |
*
* 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> |
b58fdfc2 |
#ifdef HAVE_UNISTD_H |
e3aaff8e |
#include <unistd.h> |
b58fdfc2 |
#endif |
e3aaff8e |
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h> |
b58fdfc2 |
#ifdef HAVE_SYS_PARAM_H |
15edd45f |
#include <sys/param.h> |
b58fdfc2 |
#endif |
e3aaff8e |
#include <fcntl.h> |
056d95dc |
#include <zlib.h> |
99ca7f53 |
#include <errno.h> |
e3aaff8e |
#include "clamav.h" |
e4ae7726 |
#include "cvd.h" |
b58fdfc2 |
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif |
8000d078 |
#include "matcher-ac.h"
#include "matcher-bm.h" |
c802edd5 |
#include "matcher-hash.h" |
bedc58de |
#include "matcher.h" |
e3aaff8e |
#include "others.h"
#include "str.h" |
bc93eda0 |
#include "dconf.h" |
7021b545 |
#include "filetypes.h"
#include "filetypes_int.h" |
fc83da82 |
#include "readdb.h" |
677fc4ba |
#include "cltypes.h" |
4367454d |
#include "default.h" |
04133ff9 |
#include "md5.h" |
de351ee1 |
#include "sha256.h"
#include "dsig.h" |
5b48b665 |
#include "asn1.h" |
e3aaff8e |
|
fc83da82 |
#include "phishcheck.h" |
7dec7955 |
#include "phish_whitelist.h"
#include "phish_domaincheck_db.h" |
3da4dd4c |
#include "regex_list.h" |
c3671221 |
#include "hashtab.h" |
7dec7955 |
|
2bb229f6 |
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
#include <limits.h> |
88794204 |
#include <stddef.h> |
2bb229f6 |
#endif
|
b94e66c4 |
#include "mpool.h" |
52dd3a6b |
#include "bytecode.h" |
ab636570 |
#include "bytecode_api.h" |
52dd3a6b |
#include "bytecode_priv.h" |
261e29da |
#include "cache.h" |
f51e962f |
#ifdef CL_THREAD_SAFE
# include <pthread.h>
static pthread_mutex_t cli_ref_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
|
d6e1ef16 |
char *cli_virname(char *virname, unsigned int official) |
b5513f8d |
{
char *newname, *pt;
if(!virname)
return NULL;
if((pt = strstr(virname, " (Clam)"))) |
d6e1ef16 |
*pt='\0'; |
b5513f8d |
|
d6e1ef16 |
if(!virname[0]) { |
b5513f8d |
cli_errmsg("cli_virname: Empty virus name\n");
return NULL;
}
|
d6e1ef16 |
if(official)
return cli_strdup(virname); |
b5513f8d |
|
d6e1ef16 |
newname = (char *) cli_malloc(strlen(virname) + 11 + 1);
if(!newname) {
cli_errmsg("cli_virname: Can't allocate memory for newname\n");
return NULL; |
b5513f8d |
} |
d6e1ef16 |
sprintf(newname, "%s.UNOFFICIAL", virname);
return newname; |
b5513f8d |
}
|
ec285505 |
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) |
888f5794 |
{ |
8000d078 |
struct cli_bm_patt *bm_new; |
7b324eb3 |
char *pt, *hexcpy, *start, *n, l, r;
const char *wild;
int ret, asterisk = 0, range; |
33872a43 |
unsigned int i, j, hexlen, parts = 0; |
084ee140 |
int mindist = 0, maxdist = 0, error = 0;
|
888f5794 |
|
33872a43 |
hexlen = strlen(hexsig); |
ab893605 |
if (hexsig[0] == '$') {
/* macro */
unsigned smin, smax, tid; |
2979de20 |
struct cli_ac_patt *patt; |
ab893605 |
if (hexsig[hexlen-1] != '$') {
cli_errmsg("cli_parseadd(): missing terminator $\n");
return CL_EMALFDB;
}
if (!lsigid) {
cli_errmsg("cli_parseadd(): macro signatures only valid inside logical signatures\n");
return CL_EMALFDB;
}
if (sscanf(hexsig,"${%u-%u}%u$",
&smin, &smax, &tid) != 3) {
cli_errmsg("cli_parseadd(): invalid macro signature format\n");
return CL_EMALFDB;
}
if (tid >= 32) {
cli_errmsg("cli_parseadd(): only 32 macro groups are supported\n");
return CL_EMALFDB;
} |
2979de20 |
patt = mpool_calloc(root->mempool, 1, sizeof(*patt));
if (!patt) |
ab893605 |
return CL_EMEM;
/* this is not a pattern that will be matched by AC itself, rather it is a
* pattern checked by the lsig code */ |
2979de20 |
patt->ch_mindist[0] = smin;
patt->ch_maxdist[0] = smax;
patt->sigid = tid;
patt->length = root->ac_mindepth; |
ab893605 |
/* dummy */ |
2979de20 |
patt->pattern = mpool_calloc(root->mempool, patt->length, sizeof(*patt->pattern)); |
e522909e |
if (!patt->pattern) { |
2979de20 |
free(patt); |
cc4b3fca |
return CL_EMEM;
} |
2979de20 |
if ((ret = cli_ac_addpatt(root, patt))) {
mpool_free(root->mempool, patt->pattern);
free(patt); |
ab893605 |
return ret;
}
return CL_SUCCESS;
} |
7b324eb3 |
if((wild = strchr(hexsig, '{'))) {
if(sscanf(wild, "%c%u%c", &l, &range, &r) == 3 && l == '{' && r == '}' && range > 0 && range < 128) {
hexcpy = cli_calloc(hexlen + 2 * range, sizeof(char));
if(!hexcpy)
return CL_EMEM;
strncpy(hexcpy, hexsig, wild - hexsig);
for(i = 0; i < (unsigned int) range; i++)
strcat(hexcpy, "??");
if(!(wild = strchr(wild, '}'))) {
cli_errmsg("cli_parse_add(): Problem adding signature: missing bracket\n");
free(hexcpy);
return CL_EMALFDB;
}
strcat(hexcpy, ++wild);
ret = cli_parse_add(root, virname, hexcpy, rtype, type, offset, target, lsigid, options);
free(hexcpy);
return ret;
} |
888f5794 |
|
8000d078 |
root->ac_partsigs++; |
084ee140 |
|
6f38c939 |
if(!(hexcpy = cli_strdup(hexsig))) |
084ee140 |
return CL_EMEM;
|
33872a43 |
for(i = 0; i < hexlen; 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;
}
|
341faf60 |
if((ret = cli_ac_addsig(root, virname, start, root->ac_partsigs, parts, i, rtype, type, mindist, maxdist, offset, lsigid, options))) { |
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, '-')) { |
a3fe2c5b |
if(!cli_isnumber(pt) || (mindist = maxdist = atoi(pt)) < 0) { |
084ee140 |
error = 1;
break;
}
} else { |
b68d11d2 |
if((n = cli_strtok(pt, 0, "-"))) { |
a3fe2c5b |
if(!cli_isnumber(n) || (mindist = atoi(n)) < 0) { |
084ee140 |
error = 1;
free(n);
break;
}
free(n);
}
|
b68d11d2 |
if((n = cli_strtok(pt, 1, "-"))) { |
a3fe2c5b |
if(!cli_isnumber(n) || (maxdist = atoi(n)) < 0) { |
084ee140 |
error = 1;
free(n);
break;
}
free(n);
} |
a3fe2c5b |
if((n = cli_strtok(pt, 2, "-"))) { /* strict check */
error = 1;
free(n); |
9b0004bf |
break; |
a3fe2c5b |
} |
084ee140 |
}
}
free(hexcpy); |
e828f534 |
if(error) {
cli_errmsg("cli_parseadd(): Problem adding signature (1b).\n"); |
084ee140 |
return CL_EMALFDB; |
e828f534 |
} |
084ee140 |
} else if(strchr(hexsig, '*')) { |
8000d078 |
root->ac_partsigs++; |
888f5794 |
|
33872a43 |
for(i = 0; i < hexlen; i++) |
888f5794 |
if(hexsig[i] == '*')
parts++;
|
8000d078 |
if(parts) |
888f5794 |
parts++;
for(i = 1; i <= parts; i++) {
if((pt = cli_strtok(hexsig, i - 1, "*")) == NULL) { |
3ed92fe1 |
cli_errmsg("Can't extract part %d of partial signature.\n", i); |
888f5794 |
return CL_EMALFDB;
}
|
341faf60 |
if((ret = cli_ac_addsig(root, virname, pt, root->ac_partsigs, parts, i, rtype, type, 0, 0, offset, lsigid, options))) { |
a8f79297 |
cli_errmsg("cli_parse_add(): Problem adding signature (2).\n"); |
888f5794 |
free(pt);
return ret;
}
free(pt);
}
|
ab893605 |
} else if(root->ac_only || type || lsigid || strpbrk(hexsig, "?([") || (root->bm_offmode && (!strcmp(offset, "*") || strchr(offset, ','))) || strstr(offset, "VI") || strchr(offset, '$')) { |
341faf60 |
if((ret = cli_ac_addsig(root, virname, hexsig, 0, 0, 0, rtype, type, 0, 0, offset, lsigid, options))) { |
a8f79297 |
cli_errmsg("cli_parse_add(): Problem adding signature (3).\n"); |
8000d078 |
return ret;
}
} else { |
47d40feb |
bm_new = (struct cli_bm_patt *) mpool_calloc(root->mempool, 1, sizeof(struct cli_bm_patt)); |
8000d078 |
if(!bm_new)
return CL_EMEM; |
47d40feb |
bm_new->pattern = (unsigned char *) cli_mpool_hex2str(root->mempool, hexsig); |
b583d6ed |
if(!bm_new->pattern) { |
47d40feb |
mpool_free(root->mempool, bm_new); |
8000d078 |
return CL_EMALFDB; |
091df0e3 |
} |
33872a43 |
bm_new->length = hexlen / 2; |
8000d078 |
|
12c6a97e |
bm_new->virname = cli_mpool_virname(root->mempool, virname, options & CL_DB_OFFICIAL); |
b5513f8d |
if(!bm_new->virname) { |
47d40feb |
mpool_free(root->mempool, bm_new->pattern);
mpool_free(root->mempool, bm_new); |
8000d078 |
return CL_EMEM;
}
|
3b33bd68 |
if(bm_new->length > root->maxpatlen) { |
8000d078 |
root->maxpatlen = bm_new->length; |
3b33bd68 |
} |
8000d078 |
|
33872a43 |
if((ret = cli_bm_addpatt(root, bm_new, offset))) { |
a8f79297 |
cli_errmsg("cli_parse_add(): Problem adding signature (4).\n"); |
47d40feb |
mpool_free(root->mempool, bm_new->pattern);
mpool_free(root->mempool, bm_new->virname);
mpool_free(root->mempool, bm_new); |
888f5794 |
return ret;
}
}
|
8d3aca30 |
return CL_SUCCESS; |
888f5794 |
} |
e3aaff8e |
|
a96eead4 |
int cli_initroots(struct cl_engine *engine, unsigned int options) |
5612732c |
{
int i, ret;
struct cli_matcher *root;
|
4addba22 |
for(i = 0; i < CLI_MTARGETS; i++) { |
5612732c |
if(!engine->root[i]) {
cli_dbgmsg("Initializing engine->root[%d]\n", i); |
47d40feb |
root = engine->root[i] = (struct cli_matcher *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_matcher)); |
5612732c |
if(!root) { |
0a3d4094 |
cli_errmsg("cli_initroots: Can't allocate memory for cli_matcher\n"); |
5612732c |
return CL_EMEM;
} |
33872a43 |
#ifdef USE_MPOOL
root->mempool = engine->mempool;
#endif
root->type = i; |
ab0d2f05 |
if(cli_mtargets[i].ac_only || engine->ac_only) |
83fa5305 |
root->ac_only = 1;
|
5612732c |
cli_dbgmsg("Initialising AC pattern matcher of root[%d]\n", i); |
5b74e89a |
if((ret = cli_ac_init(root, engine->ac_mindepth, engine->ac_maxdepth, engine->dconf->other&OTHER_CONF_PREFILTERING))) { |
5612732c |
/* no need to free previously allocated memory here */ |
0a3d4094 |
cli_errmsg("cli_initroots: Can't initialise AC pattern matcher\n"); |
fbcef1b0 |
return ret; |
5612732c |
}
|
83fa5305 |
if(!root->ac_only) { |
0a3d4094 |
cli_dbgmsg("cli_initroots: Initializing BM tables of root[%d]\n", i); |
83fa5305 |
if((ret = cli_bm_init(root))) { |
0a3d4094 |
cli_errmsg("cli_initroots: Can't initialise BM pattern matcher\n"); |
83fa5305 |
return ret;
} |
5612732c |
} |
8000d078 |
}
} |
9995c517 |
engine->root[1]->bm_offmode = 1; /* BM offset mode for PE files */ |
8d3aca30 |
return CL_SUCCESS; |
5612732c |
}
|
e8ae4fae |
char *cli_dbgets(char *buff, unsigned int size, FILE *fs, struct cli_dbio *dbio) |
056d95dc |
{ |
a6a98456 |
if(fs) |
056d95dc |
return fgets(buff, size, fs);
|
a6a98456 |
if(dbio->usebuf) {
int bread;
char *nl;
while(1) {
if(!dbio->bufpt) {
if(!dbio->size)
return NULL;
if(dbio->gzs) {
bread = gzread(dbio->gzs, dbio->readpt, dbio->readsize);
if(bread == -1) {
cli_errmsg("cli_dbgets: gzread() failed\n");
return NULL;
}
} else {
bread = fread(dbio->readpt, 1, dbio->readsize, dbio->fs);
if(!bread && ferror(dbio->fs)) { |
234d0f34 |
cli_errmsg("cli_dbgets: fread() failed\n"); |
a6a98456 |
return NULL;
}
}
if(!bread)
return NULL;
dbio->readpt[bread] = 0;
dbio->bufpt = dbio->buf;
dbio->size -= bread; |
ace26bfe |
dbio->bread += bread; |
de351ee1 |
sha256_update(&dbio->sha256ctx, dbio->readpt, bread); |
a6a98456 |
} |
f8202681 |
if(dbio->chkonly && dbio->bufpt) {
dbio->bufpt = NULL;
dbio->readsize = dbio->size < dbio->bufsize ? dbio->size : dbio->bufsize - 1;
continue;
} |
a6a98456 |
nl = strchr(dbio->bufpt, '\n');
if(nl) {
if(nl - dbio->bufpt >= size) {
cli_errmsg("cli_dbgets: Line too long for provided buffer\n");
return NULL;
}
strncpy(buff, dbio->bufpt, nl - dbio->bufpt);
buff[nl - dbio->bufpt] = 0;
if(nl < dbio->buf + dbio->bufsize) {
dbio->bufpt = ++nl;
} else {
dbio->bufpt = NULL;
dbio->readpt = dbio->buf;
dbio->readsize = dbio->size < dbio->bufsize ? dbio->size : dbio->bufsize - 1;
}
return buff;
} else {
unsigned int remain = dbio->buf + dbio->bufsize - 1 - dbio->bufpt;
if(dbio->bufpt == dbio->buf) {
cli_errmsg("cli_dbgets: Invalid data or internal buffer too small\n");
return NULL;
}
memmove(dbio->buf, dbio->bufpt, remain);
dbio->readpt = dbio->buf + remain;
dbio->readsize = dbio->bufsize - remain;
dbio->readsize = dbio->size < dbio->bufsize - remain ? dbio->size : dbio->bufsize - remain - 1;
dbio->bufpt = NULL;
}
}
} else { /* use gzgets/fgets */ |
056d95dc |
char *pt;
unsigned int bs;
|
e8ae4fae |
if(!dbio->size) |
056d95dc |
return NULL;
|
e8ae4fae |
bs = dbio->size < size ? dbio->size + 1 : size;
if(dbio->gzs)
pt = gzgets(dbio->gzs, buff, bs);
else
pt = fgets(buff, bs, dbio->fs);
|
ace26bfe |
if(!pt) { |
056d95dc |
cli_errmsg("cli_dbgets: Preliminary end of data\n"); |
ace26bfe |
return pt;
}
bs = strlen(buff);
dbio->size -= bs;
dbio->bread += bs; |
de351ee1 |
sha256_update(&dbio->sha256ctx, buff, bs); |
056d95dc |
return pt;
}
}
|
04133ff9 |
static int cli_chkign(const struct cli_matcher *ignored, const char *signame, const char *entry) |
ed9753e9 |
{ |
04133ff9 |
const char *md5_expected = NULL;
cli_md5_ctx md5ctx;
unsigned char digest[16]; |
ed9753e9 |
|
04133ff9 |
if(!ignored || !signame || !entry) |
ed9753e9 |
return 0;
|
6ad45a29 |
if(cli_bm_scanbuff((const unsigned char *) signame, strlen(signame), &md5_expected, NULL, ignored, 0, NULL, NULL,NULL) == CL_VIRUS) { |
04133ff9 |
if(md5_expected) {
cli_md5_init(&md5ctx);
cli_md5_update(&md5ctx, entry, strlen(entry));
cli_md5_final(digest, &md5ctx);
if(memcmp(digest, (const unsigned char *) md5_expected, 16))
return 0; |
ed9753e9 |
} |
04133ff9 |
cli_dbgmsg("Ignoring signature %s\n", signame);
return 1; |
ed9753e9 |
}
return 0;
}
|
b023c36d |
static int cli_chkpua(const char *signame, const char *pua_cats, unsigned int options)
{
char cat[32], *pt;
const char *sig;
int ret;
if(strncmp(signame, "PUA.", 4)) {
cli_dbgmsg("Skipping signature %s - no PUA prefix\n", signame);
return 1;
}
sig = signame + 3;
if(!(pt = strchr(sig + 1, '.'))) {
cli_dbgmsg("Skipping signature %s - bad syntax\n", signame);
return 1;
}
|
a45c7039 |
if((unsigned int) (pt - sig + 2) > sizeof(cat)) { |
b023c36d |
cli_dbgmsg("Skipping signature %s - too long category name\n", signame);
return 1;
}
strncpy(cat, sig, pt - signame + 1);
cat[pt - sig + 1] = 0;
pt = strstr(pua_cats, cat);
if(options & CL_DB_PUA_INCLUDE)
ret = pt ? 0 : 1;
else
ret = pt ? 1 : 0;
if(ret)
cli_dbgmsg("Skipping PUA signature %s - excluded category\n", signame);
return ret;
}
|
15850fc6 |
static int cli_loaddb(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio, const char *dbname) |
5612732c |
{ |
12c6a97e |
char buffer[FILEBUFF], *buffer_cpy = NULL, *pt, *start; |
ed9753e9 |
unsigned int line = 0, sigs = 0;
int ret = 0; |
5612732c |
struct cli_matcher *root;
|
15850fc6 |
if((ret = cli_initroots(engine, options))) |
5612732c |
return ret;
|
15850fc6 |
root = engine->root[0]; |
5612732c |
|
04133ff9 |
if(engine->ignored) |
241e7eb1 |
if(!(buffer_cpy = cli_malloc(FILEBUFF))) {
cli_errmsg("cli_loaddb: Can't allocate memory for buffer_cpy\n"); |
04133ff9 |
return CL_EMEM; |
241e7eb1 |
} |
04133ff9 |
|
e8ae4fae |
while(cli_dbgets(buffer, FILEBUFF, fs, dbio)) { |
4048c4f6 |
line++; |
cfacfb45 |
if(buffer[0] == '#')
continue; |
4048c4f6 |
cli_chomp(buffer); |
04133ff9 |
if(engine->ignored)
strcpy(buffer_cpy, buffer); |
4048c4f6 |
pt = strchr(buffer, '=');
if(!pt) {
cli_errmsg("Malformed pattern line %d\n", line);
ret = CL_EMALFDB;
break;
}
start = buffer;
*pt++ = 0; |
ee039e40 |
|
04133ff9 |
if(engine->ignored && cli_chkign(engine->ignored, start, buffer_cpy)) |
ed9753e9 |
continue;
|
f206d31a |
if(engine->cb_sigload && engine->cb_sigload("db", start, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) { |
eb422a03 |
cli_dbgmsg("cli_loaddb: skipping %s due to callback\n", start);
continue;
}
|
4048c4f6 |
if(*pt == '=') continue; |
ee039e40 |
|
33872a43 |
if((ret = cli_parse_add(root, start, pt, 0, 0, "*", 0, NULL, options))) { |
e828f534 |
cli_dbgmsg("cli_loaddb: cli_parse_add failed on line %d\n", line); |
b68d11d2 |
ret = CL_EMALFDB;
break;
} |
ed9753e9 |
sigs++; |
b68d11d2 |
}
|
04133ff9 |
if(engine->ignored)
free(buffer_cpy);
|
b68d11d2 |
if(!line) {
cli_errmsg("Empty database file\n");
return CL_EMALFDB;
}
if(ret) {
cli_errmsg("Problem parsing database at line %d\n", line);
return ret;
}
if(signo) |
ed9753e9 |
*signo += sigs; |
b68d11d2 |
|
8d3aca30 |
return CL_SUCCESS; |
b68d11d2 |
}
|
cca29953 |
#define ICO_TOKENS 4 |
182e40db |
static int cli_loadidb(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio) |
73d8cded |
{
const char *tokens[ICO_TOKENS + 1]; |
12c6a97e |
char buffer[FILEBUFF], *buffer_cpy = NULL; |
182e40db |
uint8_t *hash; |
73d8cded |
int ret = CL_SUCCESS; |
182e40db |
unsigned int line = 0, sigs = 0, tokens_count, i, size, enginesize; |
73d8cded |
struct icomtr *metric; |
cca29953 |
struct icon_matcher *matcher; |
73d8cded |
|
cca29953 |
if(!(matcher = (struct icon_matcher *)mpool_calloc(engine->mempool, sizeof(*matcher),1)))
return CL_EMEM;
|
73d8cded |
if(engine->ignored) |
a2f709da |
if(!(buffer_cpy = cli_malloc(FILEBUFF))) { |
6c014152 |
cli_errmsg("cli_loadidb: Can't allocate memory for buffer_cpy\n"); |
a2f709da |
mpool_free(engine->mempool, matcher); |
73d8cded |
return CL_EMEM; |
a2f709da |
} |
73d8cded |
while(cli_dbgets(buffer, FILEBUFF, fs, dbio)) {
line++; |
1a1ee68a |
if(buffer[0] == '#')
continue;
|
73d8cded |
cli_chomp(buffer);
if(engine->ignored)
strcpy(buffer_cpy, buffer);
tokens_count = cli_strtokenize(buffer, ':', ICO_TOKENS + 1, tokens);
if(tokens_count != ICO_TOKENS) { |
419e2be4 |
cli_errmsg("cli_loadidb: Malformed hash at line %u (wrong token count)\n", line); |
73d8cded |
ret = CL_EMALFDB;
break;
}
|
cca29953 |
if(strlen(tokens[3]) != 124) { |
419e2be4 |
cli_errmsg("cli_loadidb: Malformed hash at line %u (wrong length)\n", line); |
73d8cded |
ret = CL_EMALFDB;
break;
}
if(engine->ignored && cli_chkign(engine->ignored, tokens[0], buffer_cpy))
continue;
|
f206d31a |
if(engine->cb_sigload && engine->cb_sigload("idb", tokens[0], ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) { |
eb422a03 |
cli_dbgmsg("cli_loadidb: skipping %s due to callback\n", tokens[0]);
continue;
}
|
cca29953 |
hash = (uint8_t *)tokens[3]; |
4e968cd3 |
if(cli_hexnibbles((char *)hash, 124)) { |
73d8cded |
cli_errmsg("cli_loadidb: Malformed hash at line %u (bad chars)\n", line);
ret = CL_EMALFDB;
break;
}
size = (hash[0] << 4) + hash[1];
if(size != 32 && size != 24 && size != 16) {
cli_errmsg("cli_loadidb: Malformed hash at line %u (bad size)\n", line);
ret = CL_EMALFDB;
break;
} |
182e40db |
enginesize = (size >> 3) - 2; |
73d8cded |
hash+=2;
|
cca29953 |
metric = (struct icomtr *)mpool_realloc(engine->mempool, matcher->icons[enginesize], sizeof(struct icomtr) * (matcher->icon_counts[enginesize] + 1)); |
73d8cded |
if(!metric) {
ret = CL_EMEM;
break;
}
|
cca29953 |
matcher->icons[enginesize] = metric;
metric += matcher->icon_counts[enginesize];
matcher->icon_counts[enginesize]++; |
73d8cded |
for(i=0; i<3; i++) {
if((metric->color_avg[i] = (hash[0] << 8) | (hash[1] << 4) | hash[2]) > 4072)
break;
if((metric->color_x[i] = (hash[3] << 4) | hash[4]) > size - size / 8)
break;
if((metric->color_y[i] = (hash[5] << 4) | hash[6]) > size - size / 8)
break;
hash += 7;
}
if(i!=3) {
cli_errmsg("cli_loadidb: Malformed hash at line %u (bad color data)\n", line);
ret = CL_EMALFDB;
break;
}
for(i=0; i<3; i++) {
if((metric->gray_avg[i] = (hash[0] << 8) | (hash[1] << 4) | hash[2]) > 4072)
break;
if((metric->gray_x[i] = (hash[3] << 4) | hash[4]) > size - size / 8)
break;
if((metric->gray_y[i] = (hash[5] << 4) | hash[6]) > size - size / 8)
break;
hash += 7;
}
if(i!=3) {
cli_errmsg("cli_loadidb: Malformed hash at line %u (bad gray data)\n", line);
ret = CL_EMALFDB;
break;
}
for(i=0; i<3; i++) {
metric->bright_avg[i] = (hash[0] << 4) | hash[1];
if((metric->bright_x[i] = (hash[2] << 4) | hash[3]) > size - size / 8)
break; |
182e40db |
if((metric->bright_y[i] = (hash[4] << 4) | hash[5]) > size - size / 8) |
73d8cded |
break;
hash += 6;
}
if(i!=3) {
cli_errmsg("cli_loadidb: Malformed hash at line %u (bad bright data)\n", line);
ret = CL_EMALFDB;
break;
}
for(i=0; i<3; i++) {
metric->dark_avg[i] = (hash[0] << 4) | hash[1];
if((metric->dark_x[i] = (hash[2] << 4) | hash[3]) > size - size / 8)
break; |
182e40db |
if((metric->dark_y[i] = (hash[4] << 4) | hash[5]) > size - size / 8) |
73d8cded |
break;
hash += 6;
}
if(i!=3) {
cli_errmsg("cli_loadidb: Malformed hash at line %u (bad dark data)\n", line);
ret = CL_EMALFDB;
break;
}
for(i=0; i<3; i++) {
metric->edge_avg[i] = (hash[0] << 4) | hash[1];
if((metric->edge_x[i] = (hash[2] << 4) | hash[3]) > size - size / 8)
break; |
182e40db |
if((metric->edge_y[i] = (hash[4] << 4) | hash[5]) > size - size / 8) |
73d8cded |
break;
hash += 6;
}
if(i!=3) {
cli_errmsg("cli_loadidb: Malformed hash at line %u (bad edge data)\n", line);
ret = CL_EMALFDB;
break;
}
for(i=0; i<3; i++) {
metric->noedge_avg[i] = (hash[0] << 4) | hash[1];
if((metric->noedge_x[i] = (hash[2] << 4) | hash[3]) > size - size / 8)
break; |
182e40db |
if((metric->noedge_y[i] = (hash[4] << 4) | hash[5]) > size - size / 8) |
73d8cded |
break;
hash += 6;
}
if(i!=3) {
cli_errmsg("cli_loadidb: Malformed hash at line %u (bad noedge data)\n", line);
ret = CL_EMALFDB;
break;
}
metric->rsum = (hash[0] << 4) | hash[1];
metric->gsum = (hash[2] << 4) | hash[3];
metric->bsum = (hash[4] << 4) | hash[5];
metric->ccount = (hash[6] << 4) | hash[7]; |
fd183cf9 |
if(metric->rsum + metric->gsum + metric->bsum > 103 || metric->ccount > 100) { |
73d8cded |
cli_errmsg("cli_loadidb: Malformed hash at line %u (bad spread data)\n", line);
ret = CL_EMALFDB;
break;
}
if(!(metric->name = cli_mpool_strdup(engine->mempool, tokens[0]))) {
ret = CL_EMEM;
break;
}
|
cca29953 |
for(i=0; i<matcher->group_counts[0]; i++) {
if(!strcmp(tokens[1], matcher->group_names[0][i]))
break;
}
if(i==matcher->group_counts[0]) {
if(!(matcher->group_names[0] = mpool_realloc(engine->mempool, matcher->group_names[0], sizeof(char *) * (i + 1))) ||
!(matcher->group_names[0][i] = cli_mpool_strdup(engine->mempool, tokens[1]))) {
ret = CL_EMEM;
break;
}
matcher->group_counts[0]++;
}
metric->group[0] = i;
for(i=0; i<matcher->group_counts[1]; i++) {
if(!strcmp(tokens[2], matcher->group_names[1][i]))
break;
}
if(i==matcher->group_counts[1]) {
if(!(matcher->group_names[1] = mpool_realloc(engine->mempool, matcher->group_names[1], sizeof(char *) * (i + 1))) ||
!(matcher->group_names[1][i] = cli_mpool_strdup(engine->mempool, tokens[2]))) { |
419e2be4 |
ret = CL_EMEM; |
cca29953 |
break;
}
matcher->group_counts[1]++;
}
metric->group[1] = i; |
419e2be4 |
if(matcher->group_counts[0] > 256 || matcher->group_counts[1] > 256) {
cli_errmsg("cli_loadidb: too many icon groups!\n");
ret = CL_EMALFDB;
break;
} |
cca29953 |
|
73d8cded |
sigs++;
}
if(engine->ignored)
free(buffer_cpy);
if(!line) { |
182e40db |
cli_errmsg("cli_loadidb: Empty database file\n"); |
73d8cded |
return CL_EMALFDB;
}
if(ret) { |
182e40db |
cli_errmsg("cli_loadidb: Problem parsing database at line %u\n", line); |
73d8cded |
return ret;
}
if(signo)
*signo += sigs;
|
cca29953 |
engine->iconcheck = matcher; |
73d8cded |
return CL_SUCCESS;
} |
a8d621cf |
|
15850fc6 |
static int cli_loadwdb(FILE *fs, struct cl_engine *engine, unsigned int options, struct cli_dbio *dbio) |
3da4dd4c |
{
int ret = 0;
|
ec481027 |
|
15850fc6 |
if(!(engine->dconf->phishing & PHISHING_CONF_ENGINE)) |
692bda68 |
return CL_SUCCESS;
|
15850fc6 |
if(!engine->whitelist_matcher) {
if((ret = init_whitelist(engine))) { |
ec481027 |
return ret; |
3da4dd4c |
} |
ec481027 |
} |
3da4dd4c |
|
9f497be6 |
if((ret = load_regex_matcher(engine, engine->whitelist_matcher, fs, NULL, options, 1, dbio, engine->dconf->other&OTHER_CONF_PREFILTERING))) { |
ec481027 |
return ret;
} |
3da4dd4c |
|
ec481027 |
return CL_SUCCESS; |
3da4dd4c |
}
|
03527bee |
static int cli_loadpdb(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio) |
3da4dd4c |
{
int ret = 0;
|
ec481027 |
|
15850fc6 |
if(!(engine->dconf->phishing & PHISHING_CONF_ENGINE)) |
692bda68 |
return CL_SUCCESS;
|
15850fc6 |
if(!engine->domainlist_matcher) {
if((ret = init_domainlist(engine))) { |
ec481027 |
return ret; |
3da4dd4c |
} |
ec481027 |
} |
3da4dd4c |
|
9f497be6 |
if((ret = load_regex_matcher(engine, engine->domainlist_matcher, fs, signo, options, 0, dbio, engine->dconf->other&OTHER_CONF_PREFILTERING))) { |
ec481027 |
return ret;
}
return CL_SUCCESS; |
3da4dd4c |
} |
ec481027 |
|
e4e8366f |
#define NDB_TOKENS 6 |
15850fc6 |
static int cli_loadndb(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned short sdb, unsigned int options, struct cli_dbio *dbio, const char *dbname) |
b68d11d2 |
{ |
72fb25ea |
const char *tokens[NDB_TOKENS + 1]; |
12c6a97e |
char buffer[FILEBUFF], *buffer_cpy = NULL; |
e4e8366f |
const char *sig, *virname, *offset, *pt; |
5612732c |
struct cli_matcher *root; |
72fb25ea |
int line = 0, sigs = 0, ret = 0, tokens_count; |
b68d11d2 |
unsigned short target; |
9f8098c0 |
unsigned int phish = options & CL_DB_PHISHING; |
b68d11d2 |
|
15850fc6 |
if((ret = cli_initroots(engine, options))) |
5612732c |
return ret; |
b68d11d2 |
|
04133ff9 |
if(engine->ignored) |
241e7eb1 |
if(!(buffer_cpy = cli_malloc(FILEBUFF))) {
cli_errmsg("cli_loadndb: Can't allocate memory for buffer_cpy\n"); |
04133ff9 |
return CL_EMEM; |
241e7eb1 |
} |
04133ff9 |
|
e8ae4fae |
while(cli_dbgets(buffer, FILEBUFF, fs, dbio)) { |
b68d11d2 |
line++; |
cfacfb45 |
if(buffer[0] == '#')
continue; |
7afdc309 |
|
9f8098c0 |
if(!phish) |
d6449522 |
if(!strncmp(buffer, "HTML.Phishing", 13) || !strncmp(buffer, "Email.Phishing", 14))
continue;
|
b68d11d2 |
cli_chomp(buffer); |
04133ff9 |
if(engine->ignored)
strcpy(buffer_cpy, buffer); |
b68d11d2 |
|
72fb25ea |
tokens_count = cli_strtokenize(buffer, ':', NDB_TOKENS + 1, tokens); |
486fd3da |
if(tokens_count < 4 || tokens_count > 6) { |
b68d11d2 |
ret = CL_EMALFDB;
break;
}
|
72fb25ea |
virname = tokens[0];
|
15850fc6 |
if(engine->pua_cats && (options & CL_DB_PUA_MODE) && (options & (CL_DB_PUA_INCLUDE | CL_DB_PUA_EXCLUDE)))
if(cli_chkpua(virname, engine->pua_cats, options)) |
b023c36d |
continue;
|
04133ff9 |
if(engine->ignored && cli_chkign(engine->ignored, virname, buffer_cpy)) |
ed9753e9 |
continue;
|
f206d31a |
if(!sdb && engine->cb_sigload && engine->cb_sigload("ndb", virname, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) { |
eb422a03 |
cli_dbgmsg("cli_loadndb: skipping %s due to callback\n", virname);
continue;
}
|
72fb25ea |
if(tokens_count > 4) { /* min version */
pt = tokens[4]; |
039c9565 |
if(!cli_isnumber(pt)) { |
95083a4f |
ret = CL_EMALFDB;
break;
}
|
53721687 |
if((unsigned int) atoi(pt) > cl_retflevel()) { |
38d1d109 |
cli_dbgmsg("Signature for %s not loaded (required f-level: %d)\n", virname, atoi(pt)); |
95083a4f |
continue;
}
|
72fb25ea |
if(tokens_count == 6) { /* max version */
pt = tokens[5]; |
039c9565 |
if(!cli_isnumber(pt)) { |
555c5390 |
ret = CL_EMALFDB;
break;
}
|
53721687 |
if((unsigned int) atoi(pt) < cl_retflevel()) { |
555c5390 |
continue;
}
} |
95083a4f |
}
|
039c9565 |
if(!(pt = tokens[1]) || (strcmp(pt, "*") && !cli_isnumber(pt))) { |
b68d11d2 |
ret = CL_EMALFDB;
break;
}
target = (unsigned short) atoi(pt);
|
4addba22 |
if(target >= CLI_MTARGETS) { |
5612732c |
cli_dbgmsg("Not supported target type in signature for %s\n", virname);
continue;
}
|
15850fc6 |
root = engine->root[target]; |
5612732c |
|
72fb25ea |
offset = tokens[2];
sig = tokens[3]; |
b68d11d2 |
|
677fc4ba |
if((ret = cli_parse_add(root, virname, sig, 0, 0, offset, target, NULL, options))) { |
4048c4f6 |
ret = CL_EMALFDB;
break;
} |
ed9753e9 |
sigs++; |
ee039e40 |
} |
04133ff9 |
if(engine->ignored)
free(buffer_cpy); |
ee039e40 |
|
4048c4f6 |
if(!line) {
cli_errmsg("Empty database file\n");
return CL_EMALFDB;
} |
8139fd99 |
|
4048c4f6 |
if(ret) { |
b68d11d2 |
cli_errmsg("Problem parsing database at line %d\n", line); |
8139fd99 |
return ret;
}
|
3805ebcb |
if(signo) |
95083a4f |
*signo += sigs; |
4048c4f6 |
|
15850fc6 |
if(sdb && sigs && !engine->sdb) {
engine->sdb = 1; |
555c5390 |
cli_dbgmsg("*** Self protection mechanism activated.\n");
}
|
8d3aca30 |
return CL_SUCCESS; |
4048c4f6 |
}
|
677fc4ba |
struct lsig_attrib {
const char *name;
unsigned int type;
void **pt;
};
/* TODO: rework this */
static int lsigattribs(char *attribs, struct cli_lsig_tdb *tdb)
{
struct lsig_attrib attrtab[] = { |
7770d314 |
#define ATTRIB_TOKENS 9 |
17cfd76f |
{ "Target", CLI_TDB_UINT, (void **) &tdb->target },
{ "Engine", CLI_TDB_RANGE, (void **) &tdb->engine }, |
0f7ba617 |
|
17cfd76f |
{ "FileSize", CLI_TDB_RANGE, (void **) &tdb->filesize },
{ "EntryPoint", CLI_TDB_RANGE, (void **) &tdb->ep },
{ "NumberOfSections", CLI_TDB_RANGE, (void **) &tdb->nos },
{ "IconGroup1", CLI_TDB_STR, (void **) &tdb->icongrp1 },
{ "IconGroup2", CLI_TDB_STR, (void **) &tdb->icongrp2 }, |
0f7ba617 |
|
4168b010 |
{ "Container", CLI_TDB_FTYPE, (void **) &tdb->container }, |
7770d314 |
{ "HandlerType", CLI_TDB_FTYPE, (void **) &tdb->handlertype }, |
677fc4ba |
/*
{ "SectOff", CLI_TDB_RANGE2, (void **) &tdb->sectoff },
{ "SectRVA", CLI_TDB_RANGE2, (void **) &tdb->sectrva },
{ "SectVSZ", CLI_TDB_RANGE2, (void **) &tdb->sectvsz },
{ "SectRAW", CLI_TDB_RANGE2, (void **) &tdb->sectraw },
{ "SectRSZ", CLI_TDB_RANGE2, (void **) &tdb->sectrsz },
{ "SectURVA", CLI_TDB_RANGE2, (void **) &tdb->secturva },
{ "SectUVSZ", CLI_TDB_RANGE2, (void **) &tdb->sectuvsz },
{ "SectURAW", CLI_TDB_RANGE2, (void **) &tdb->secturaw },
{ "SectURSZ", CLI_TDB_RANGE2, (void **) &tdb->sectursz },
*/
{ NULL, 0, NULL, }
};
struct lsig_attrib *apt;
char *tokens[ATTRIB_TOKENS], *pt, *pt2; |
fa4d6353 |
unsigned int v1, v2, v3, i, j, tokens_count, have_newext = 0; |
677fc4ba |
uint32_t cnt, off[ATTRIB_TOKENS];
|
72fb25ea |
tokens_count = cli_strtokenize(attribs, ',', ATTRIB_TOKENS, (const char **) tokens); |
677fc4ba |
|
72fb25ea |
for(i = 0; i < tokens_count; i++) { |
677fc4ba |
if(!(pt = strchr(tokens[i], ':'))) {
cli_errmsg("lsigattribs: Incorrect format of attribute '%s'\n", tokens[i]);
return -1;
}
*pt++ = 0;
apt = NULL;
for(j = 0; attrtab[j].name; j++) {
if(!strcmp(attrtab[j].name, tokens[i])) {
apt = &attrtab[j];
break;
}
}
if(!apt) {
cli_dbgmsg("lsigattribs: Unknown attribute name '%s'\n", tokens[i]); |
8d2654bb |
return 1; |
677fc4ba |
}
|
fa4d6353 |
if(!strcmp(apt->name, "Engine")) {
if(i) {
cli_errmsg("lsigattribs: For backward compatibility the Engine attribute must be on the first position\n");
return -1;
}
} else if(strcmp(apt->name, "Target"))
have_newext = 1;
|
677fc4ba |
switch(apt->type) {
case CLI_TDB_UINT: |
039c9565 |
if(!cli_isnumber(pt)) {
cli_errmsg("lsigattribs: Invalid argument for %s\n", tokens[i]);
return -1;
} |
677fc4ba |
off[i] = cnt = tdb->cnt[CLI_TDB_UINT]++; |
47d40feb |
tdb->val = (uint32_t *) mpool_realloc2(tdb->mempool, tdb->val, tdb->cnt[CLI_TDB_UINT] * sizeof(uint32_t)); |
677fc4ba |
if(!tdb->val) {
tdb->cnt[CLI_TDB_UINT] = 0;
return -1;
}
tdb->val[cnt] = atoi(pt);
break;
|
4168b010 |
case CLI_TDB_FTYPE:
if((v1 = cli_ftcode(pt)) == CL_TYPE_ERROR) {
cli_dbgmsg("lsigattribs: Unknown file type in %s\n", tokens[i]);
return 1; /* skip */
}
off[i] = cnt = tdb->cnt[CLI_TDB_UINT]++;
tdb->val = (uint32_t *) mpool_realloc2(tdb->mempool, tdb->val, tdb->cnt[CLI_TDB_UINT] * sizeof(uint32_t));
if(!tdb->val) {
tdb->cnt[CLI_TDB_UINT] = 0;
return -1;
}
tdb->val[cnt] = v1;
break;
|
677fc4ba |
case CLI_TDB_RANGE:
if(!(pt2 = strchr(pt, '-'))) {
cli_errmsg("lsigattribs: Incorrect parameters in '%s'\n", tokens[i]);
return -1;
}
*pt2++ = 0;
off[i] = cnt = tdb->cnt[CLI_TDB_RANGE];
tdb->cnt[CLI_TDB_RANGE] += 2; |
47d40feb |
tdb->range = (uint32_t *) mpool_realloc2(tdb->mempool, tdb->range, tdb->cnt[CLI_TDB_RANGE] * sizeof(uint32_t)); |
677fc4ba |
if(!tdb->range) {
tdb->cnt[CLI_TDB_RANGE] = 0;
return -1;
} |
039c9565 |
if(!cli_isnumber(pt) || !cli_isnumber(pt2)) {
cli_errmsg("lsigattribs: Invalid argument for %s\n", tokens[i]);
return -1;
} |
677fc4ba |
tdb->range[cnt] = atoi(pt);
tdb->range[cnt + 1] = atoi(pt2);
break;
case CLI_TDB_RANGE2:
if(!strchr(pt, '-') || !strchr(pt, '.')) {
cli_errmsg("lsigattribs: Incorrect parameters in '%s'\n", tokens[i]);
return -1;
}
off[i] = cnt = tdb->cnt[CLI_TDB_RANGE];
tdb->cnt[CLI_TDB_RANGE] += 3; |
47d40feb |
tdb->range = (uint32_t *) mpool_realloc2(tdb->mempool, tdb->range, tdb->cnt[CLI_TDB_RANGE] * sizeof(uint32_t)); |
677fc4ba |
if(!tdb->range) {
tdb->cnt[CLI_TDB_RANGE] = 0;
return -1;
}
if(sscanf(pt, "%u.%u-%u", &v1, &v2, &v3) != 3) {
cli_errmsg("lsigattribs: Can't parse parameters in '%s'\n", tokens[i]);
return -1;
}
tdb->range[cnt] = (uint32_t) v1;
tdb->range[cnt + 1] = (uint32_t) v2;
tdb->range[cnt + 2] = (uint32_t) v3;
break;
case CLI_TDB_STR:
off[i] = cnt = tdb->cnt[CLI_TDB_STR];
tdb->cnt[CLI_TDB_STR] += strlen(pt) + 1; |
47d40feb |
tdb->str = (char *) mpool_realloc2(tdb->mempool, tdb->str, tdb->cnt[CLI_TDB_STR] * sizeof(char)); |
677fc4ba |
if(!tdb->str) {
cli_errmsg("lsigattribs: Can't allocate memory for tdb->str\n");
return -1;
}
memcpy(&tdb->str[cnt], pt, strlen(pt));
tdb->str[tdb->cnt[CLI_TDB_STR] - 1] = 0;
break; |
bebd86a6 |
default:
/* All known TDB types handled above, skip unknown */
cli_dbgmsg("lsigattribs: Unknown attribute type '%u'\n", apt->type);
return 1; /* +1 = skip */ |
677fc4ba |
}
}
if(!i) {
cli_errmsg("lsigattribs: Empty TDB\n");
return -1;
}
|
72fb25ea |
for(i = 0; i < tokens_count; i++) { |
677fc4ba |
for(j = 0; attrtab[j].name; j++) {
if(!strcmp(attrtab[j].name, tokens[i])) {
apt = &attrtab[j];
break;
}
} |
c9157be3 |
if(!apt)
continue; |
677fc4ba |
switch(apt->type) {
case CLI_TDB_UINT: |
4168b010 |
case CLI_TDB_FTYPE: |
677fc4ba |
*apt->pt = (uint32_t *) &tdb->val[off[i]];
break;
case CLI_TDB_RANGE:
case CLI_TDB_RANGE2:
*apt->pt = (uint32_t *) &tdb->range[off[i]];
break;
case CLI_TDB_STR:
*apt->pt = (char *) &tdb->str[off[i]];
break;
}
}
|
fa4d6353 |
if(have_newext && (!tdb->engine || tdb->engine[0] < 51)) {
cli_errmsg("lsigattribs: For backward compatibility all signatures using new attributes must have the Engine attribute present and set to min_level of at least 51 (0.96)\n");
return -1;
} |
677fc4ba |
return 0;
}
|
0d9dbdef |
#define FREE_TDB(x) do { \
if(x.cnt[CLI_TDB_UINT]) \ |
47d40feb |
mpool_free(x.mempool, x.val); \ |
0d9dbdef |
if(x.cnt[CLI_TDB_RANGE]) \ |
47d40feb |
mpool_free(x.mempool, x.range); \ |
0d9dbdef |
if(x.cnt[CLI_TDB_STR]) \ |
47d40feb |
mpool_free(x.mempool, x.str); \ |
ab893605 |
if(x.macro_ptids)\
mpool_free(x.mempool, x.macro_ptids);\ |
0d9dbdef |
} while(0); |
677fc4ba |
#define LDB_TOKENS 67 |
d510390f |
static int load_oneldb(char *buffer, int chkpua, struct cl_engine *engine, unsigned int options, const char *dbname, unsigned int line, unsigned int *sigs, unsigned bc_idx, const char *buffer_cpy, int *skip) |
677fc4ba |
{ |
df8af6d3 |
const char *sig, *virname, *offset, *logic;
struct cli_ac_lsig **newtable, *lsig; |
1d406931 |
char *tokens[LDB_TOKENS+1], *pt; |
df8af6d3 |
int i, subsigs, tokens_count;
unsigned short target = 0;
struct cli_matcher *root;
struct cli_lsig_tdb tdb;
uint32_t lsigid[2];
int ret; |
677fc4ba |
|
8d2654bb |
tokens_count = cli_strtokenize(buffer, ';', LDB_TOKENS + 1, (const char **) tokens); |
df8af6d3 |
if(tokens_count < 4) {
return CL_EMALFDB;
}
virname = tokens[0];
logic = tokens[2]; |
677fc4ba |
|
df8af6d3 |
if (chkpua && cli_chkpua(virname, engine->pua_cats, options))
return CL_SUCCESS; |
04133ff9 |
|
d510390f |
if (engine->ignored && cli_chkign(engine->ignored, virname, buffer_cpy ? buffer_cpy : virname)) {
if(skip)
*skip = 1; |
df8af6d3 |
return CL_SUCCESS; |
d510390f |
} |
677fc4ba |
|
f206d31a |
if(engine->cb_sigload && engine->cb_sigload("ldb", virname, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) { |
eb422a03 |
cli_dbgmsg("cli_loadldb: skipping %s due to callback\n", virname); |
2d78fb7c |
(*sigs)--; |
eb422a03 |
return CL_SUCCESS;
}
|
df8af6d3 |
subsigs = cli_ac_chklsig(logic, logic + strlen(logic), NULL, NULL, NULL, 1);
if(subsigs == -1) {
return CL_EMALFDB;
}
subsigs++;
if(subsigs > 64) {
cli_errmsg("cli_loadldb: Broken logical expression or too many subsignatures\n");
return CL_EMALFDB;
} |
d38d6dad |
if (!line) {
/* This is a logical signature from the bytecode, we need all
* subsignatures, even if not referenced from the logical expression */
if (subsigs > tokens_count-3) {
cli_errmsg("load_oneldb: Too many subsignatures: %u (max %u)\n",
subsigs, tokens_count-3);
return CL_EMALFDB; |
677fc4ba |
} |
d38d6dad |
subsigs = tokens_count-3; |
74b00233 |
} else if(subsigs != tokens_count - 3) {
cli_errmsg("cli_loadldb: The number of subsignatures (== %u) doesn't match the IDs in the logical expression (== %u)\n", tokens_count - 3, subsigs);
return CL_EMALFDB; |
d38d6dad |
} |
677fc4ba |
|
df8af6d3 |
/* TDB */
memset(&tdb, 0, sizeof(tdb));
#ifdef USE_MPOOL
tdb.mempool = engine->mempool;
#endif |
8d2654bb |
if((ret = lsigattribs(tokens[1], &tdb))) { |
df8af6d3 |
FREE_TDB(tdb); |
8d2654bb |
if(ret == 1) {
cli_dbgmsg("cli_loadldb: Not supported attribute(s) in logical signature for %s, skipping\n", virname); |
12c6a97e |
(*sigs)--; |
8d2654bb |
return CL_SUCCESS;
} |
df8af6d3 |
return CL_EMALFDB;
} |
8d2654bb |
|
87acc263 |
if(tdb.engine) {
if(tdb.engine[0] > cl_retflevel()) {
cli_dbgmsg("cli_loadldb: Signature for %s not loaded (required f-level: %u)\n", virname, tdb.engine[0]);
FREE_TDB(tdb);
(*sigs)--;
return CL_SUCCESS;
} else if(tdb.engine[1] < cl_retflevel()) {
FREE_TDB(tdb);
(*sigs)--;
return CL_SUCCESS;
}
}
|
df8af6d3 |
if(!tdb.target) {
cli_errmsg("cli_loadldb: No target specified in TDB\n");
FREE_TDB(tdb);
return CL_EMALFDB;
} else if(tdb.target[0] >= CLI_MTARGETS) { |
8d2654bb |
cli_dbgmsg("cli_loadldb: Not supported target type in logical signature for %s, skipping\n", virname); |
df8af6d3 |
FREE_TDB(tdb); |
12c6a97e |
(*sigs)--; |
df8af6d3 |
return CL_SUCCESS;
} |
72fb25ea |
|
0f7ba617 |
if((tdb.icongrp1 || tdb.icongrp2) && tdb.target[0] != 1) {
cli_errmsg("cli_loadldb: IconGroup is only supported in PE (target 1) signatures\n");
FREE_TDB(tdb);
return CL_EMALFDB;
}
|
17cfd76f |
if((tdb.ep || tdb.nos) && tdb.target[0] != 1 && tdb.target[0] != 6 && tdb.target[0] != 9) { |
01b695fd |
cli_errmsg("cli_loadldb: EntryPoint/NumberOfSections is only supported in PE/ELF/Mach-O signatures\n"); |
17cfd76f |
FREE_TDB(tdb);
return CL_EMALFDB;
}
|
df8af6d3 |
root = engine->root[tdb.target[0]]; |
b023c36d |
|
df8af6d3 |
lsig = (struct cli_ac_lsig *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_ac_lsig));
if(!lsig) {
cli_errmsg("cli_loadldb: Can't allocate memory for lsig\n");
FREE_TDB(tdb);
return CL_EMEM;
} |
677fc4ba |
|
df8af6d3 |
lsig->logic = cli_mpool_strdup(engine->mempool, logic);
if(!lsig->logic) {
cli_errmsg("cli_loadldb: Can't allocate memory for lsig->logic\n");
FREE_TDB(tdb);
mpool_free(engine->mempool, lsig);
return CL_EMEM;
} |
677fc4ba |
|
df8af6d3 |
lsigid[0] = lsig->id = root->ac_lsigs; |
677fc4ba |
|
df8af6d3 |
root->ac_lsigs++;
newtable = (struct cli_ac_lsig **) mpool_realloc(engine->mempool, root->ac_lsigtable, root->ac_lsigs * sizeof(struct cli_ac_lsig *));
if(!newtable) {
root->ac_lsigs--;
cli_errmsg("cli_loadldb: Can't realloc root->ac_lsigtable\n");
FREE_TDB(tdb);
mpool_free(engine->mempool, lsig);
return CL_EMEM;
} |
57f14280 |
/* 0 marks no bc, we can't use a pointer to bc, since that is
* realloced/moved during load */
lsig->bc_idx = bc_idx; |
df8af6d3 |
newtable[root->ac_lsigs - 1] = lsig;
root->ac_lsigtable = newtable; |
ab893605 |
tdb.subsigs = subsigs; |
5ccfa0b7 |
|
df8af6d3 |
for(i = 0; i < subsigs; i++) {
lsigid[1] = i;
sig = tokens[3 + i]; |
677fc4ba |
|
df8af6d3 |
if((pt = strchr(tokens[3 + i], ':'))) {
*pt = 0;
sig = ++pt;
offset = tokens[3 + i];
} else {
offset = "*";
sig = tokens[3 + i];
} |
677fc4ba |
|
8d2654bb |
if((ret = cli_parse_add(root, virname, sig, 0, 0, offset, target, lsigid, options)))
return ret; |
ab893605 |
if(sig[0] == '$' && i) {
/* allow mapping from lsig back to pattern for macros */
if (!tdb.macro_ptids)
tdb.macro_ptids = mpool_calloc(root->mempool, subsigs, sizeof(*tdb.macro_ptids));
if (!tdb.macro_ptids)
return CL_EMEM;
tdb.macro_ptids[i-1] = root->ac_patterns-1;
} |
df8af6d3 |
} |
ab893605 |
memcpy(&lsig->tdb, &tdb, sizeof(tdb)); |
df8af6d3 |
return CL_SUCCESS;
} |
677fc4ba |
|
df8af6d3 |
static int cli_loadldb(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio, const char *dbname)
{ |
12c6a97e |
char buffer[CLI_DEFAULT_LSIG_BUFSIZE + 1], *buffer_cpy = NULL; |
df8af6d3 |
unsigned int line = 0, sigs = 0;
int ret; |
677fc4ba |
|
df8af6d3 |
if((ret = cli_initroots(engine, options)))
return ret; |
677fc4ba |
|
72a03f9b |
if(engine->ignored) |
241e7eb1 |
if(!(buffer_cpy = cli_malloc(sizeof(buffer)))) {
cli_errmsg("cli_loadldb: Can't allocate memory for buffer_cpy\n"); |
72a03f9b |
return CL_EMEM; |
241e7eb1 |
} |
df8af6d3 |
while(cli_dbgets(buffer, sizeof(buffer), fs, dbio)) {
line++; |
cfacfb45 |
if(buffer[0] == '#')
continue; |
df8af6d3 |
sigs++;
cli_chomp(buffer); |
677fc4ba |
|
72a03f9b |
if(engine->ignored)
strcpy(buffer_cpy, buffer); |
df8af6d3 |
ret = load_oneldb(buffer,
engine->pua_cats && (options & CL_DB_PUA_MODE) && (options & (CL_DB_PUA_INCLUDE | CL_DB_PUA_EXCLUDE)), |
d510390f |
engine, options, dbname, line, &sigs, 0, buffer_cpy, NULL); |
df8af6d3 |
if (ret) |
677fc4ba |
break;
} |
04133ff9 |
if(engine->ignored)
free(buffer_cpy); |
677fc4ba |
if(!line) {
cli_errmsg("Empty database file\n");
return CL_EMALFDB;
}
if(ret) {
cli_errmsg("Problem parsing database at line %u\n", line);
return ret;
}
if(signo)
*signo += sigs;
return CL_SUCCESS;
}
|
52dd3a6b |
static int cli_loadcbc(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio, const char *dbname)
{ |
1453c0a3 |
char buf[4096]; |
d510390f |
int rc, skip = 0; |
52dd3a6b |
struct cli_all_bc *bcs = &engine->bcs;
struct cli_bc *bc; |
459b13ed |
unsigned sigs = 0; |
be43f951 |
unsigned security_trust = 0; |
d5ffa2ac |
unsigned i; |
be43f951 |
|
459b13ed |
|
ab636570 |
/* TODO: virusname have a common prefix, and whitelist by that */ |
459b13ed |
if((rc = cli_initroots(engine, options)))
return rc;
|
52dd3a6b |
if(!(engine->dconf->bytecode & BYTECODE_ENGINE_MASK)) {
return CL_SUCCESS;
} |
2d78fb7c |
|
f206d31a |
if(engine->cb_sigload && engine->cb_sigload("cbc", dbname, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) { |
2d78fb7c |
cli_dbgmsg("cli_loadcbc: skipping %s due to callback\n", dbname);
return CL_SUCCESS;
}
|
62315ce6 |
if (!(options & CL_DB_BYTECODE_UNSIGNED) && !(options & CL_DB_SIGNED)) { |
9c92344b |
cli_warnmsg("Only loading signed bytecode, skipping load of unsigned bytecode!\n"); |
62315ce6 |
cli_warnmsg("Turn on BytecodeUnsigned/--bytecode-unsigned to enable loading of unsigned bytecode\n"); |
9c92344b |
return CL_SUCCESS;
} |
62315ce6 |
|
52dd3a6b |
bcs->all_bcs = cli_realloc2(bcs->all_bcs, sizeof(*bcs->all_bcs)*(bcs->count+1));
if (!bcs->all_bcs) {
cli_errmsg("cli_loadcbc: Can't allocate memory for bytecode entry\n");
return CL_EMEM;
}
bcs->count++;
bc = &bcs->all_bcs[bcs->count-1]; |
be43f951 |
switch (engine->bytecode_security) {
case CL_BYTECODE_TRUST_SIGNED: |
de351ee1 |
security_trust = !!(options & CL_DB_SIGNED); |
be43f951 |
break;
default:
security_trust = 0;
}
|
54402320 |
rc = cli_bytecode_load(bc, fs, dbio, security_trust, options&CL_DB_BYTECODE_STATS); |
1453c0a3 |
/* read remainder of DB, needed because cvd.c checks that we read the entire
* file */
while (cli_dbgets(buf, sizeof(buf), fs, dbio)) {}
|
52dd3a6b |
if (rc != CL_SUCCESS) { |
cbb9db19 |
cli_bytecode_destroy(bc); |
ab636570 |
cli_errmsg("Unable to load %s bytecode: %s\n", dbname, cl_strerror(rc)); |
52dd3a6b |
return rc;
} |
039af772 |
if (bc->state == bc_skip) {
cli_bytecode_destroy(bc);
bcs->count--;
return CL_SUCCESS;
} |
57f14280 |
bc->id = bcs->count;/* must set after _load, since load zeroes */ |
3ccff6f2 |
if (engine->bytecode_mode == CL_BYTECODE_MODE_TEST)
cli_infomsg(NULL, "bytecode %u -> %s\n", bc->id, dbname); |
f4e34215 |
if (bc->kind == BC_LOGICAL || bc->lsig) { |
3735fda1 |
unsigned oldsigs = sigs; |
ab636570 |
if (!bc->lsig) {
cli_errmsg("Bytecode %s has logical kind, but missing logical signature!\n", dbname);
return CL_EMALFDB;
} |
a35cfe51 |
cli_dbgmsg("Bytecode %s(%u) has logical signature: %s\n", dbname, bc->id, bc->lsig); |
d510390f |
rc = load_oneldb(bc->lsig, 0, engine, options, dbname, 0, &sigs, bcs->count, NULL, &skip); |
459b13ed |
if (rc != CL_SUCCESS) { |
ab636570 |
cli_errmsg("Problem parsing logical signature %s for bytecode %s: %s\n",
bc->lsig, dbname, cl_strerror(rc)); |
459b13ed |
return rc;
} |
d510390f |
if (skip) {
cli_bytecode_destroy(bc);
bcs->count--;
return CL_SUCCESS;
} |
3735fda1 |
if (sigs != oldsigs) {
/* compiler ensures Engine field in lsig matches the one in bytecode,
* so this should never happen. */
cli_errmsg("Bytecode logical signature skipped, but bytecode itself not?");
return CL_EMALFDB;
} |
f4e34215 |
} |
d510390f |
sigs++; |
f4e34215 |
if (bc->kind != BC_LOGICAL) { |
ab636570 |
if (bc->lsig) { |
f4e34215 |
/* runlsig will only flip a status bit, not report a match,
* when the hooks are executed we only execute the hook if its
* status bit is on */
bc->hook_lsig_id = ++engine->hook_lsig_ids; |
ab636570 |
}
if (bc->kind >= _BC_START_HOOKS && bc->kind < _BC_LAST_HOOK) {
unsigned hook = bc->kind - _BC_START_HOOKS;
unsigned cnt = ++engine->hooks_cnt[hook];
engine->hooks[hook] = cli_realloc2(engine->hooks[hook],
sizeof(*engine->hooks[0])*cnt);
if (!engine->hooks[hook]) {
cli_errmsg("Out of memory allocating memory for hook %u", hook);
return CL_EMEM;
}
engine->hooks[hook][cnt-1] = bcs->count-1;
} else switch (bc->kind) { |
d5ffa2ac |
case BC_STARTUP:
for (i=0;i<bcs->count-1;i++)
if (bcs->all_bcs[i].kind == BC_STARTUP) {
struct cli_bc *bc0 = &bcs->all_bcs[i];
cli_errmsg("Can only load 1 BC_STARTUP bytecode, attempted to load 2nd!\n");
cli_warnmsg("Previous BC_STARTUP: %d %d by %s\n", |
88d54dcb |
bc0->id, (uint32_t)bc0->metadata.timestamp, |
d5ffa2ac |
bc0->metadata.sigmaker ? bc0->metadata.sigmaker : "N/A");
cli_warnmsg("Conflicting BC_STARTUP: %d %d by %s\n", |
88d54dcb |
bc->id, (uint32_t)bc->metadata.timestamp, |
d5ffa2ac |
bc->metadata.sigmaker ? bc->metadata.sigmaker : "N/A");
return CL_EMALFDB;
}
break; |
ab636570 |
default:
cli_errmsg("Bytecode: unhandled bytecode kind %u\n", bc->kind);
return CL_EMALFDB;
} |
df8af6d3 |
} |
459b13ed |
if (signo)
*signo += sigs; |
52dd3a6b |
return CL_SUCCESS;
}
|
72fb25ea |
#define FTM_TOKENS 8 |
15850fc6 |
static int cli_loadftm(FILE *fs, struct cl_engine *engine, unsigned int options, unsigned int internal, struct cli_dbio *dbio) |
7021b545 |
{ |
72fb25ea |
const char *tokens[FTM_TOKENS + 1], *pt; |
7021b545 |
char buffer[FILEBUFF]; |
72fb25ea |
unsigned int line = 0, sigs = 0, tokens_count; |
7021b545 |
struct cli_ftype *new; |
6038397e |
cli_file_t rtype, type; |
7021b545 |
int ret; |
1d1c4b15 |
int magictype; |
7021b545 |
|
15850fc6 |
if((ret = cli_initroots(engine, options))) |
7021b545 |
return ret;
while(1) {
if(internal) { |
8dd6c63c |
options |= CL_DB_OFFICIAL; |
7021b545 |
if(!ftypes_int[line])
break;
strncpy(buffer, ftypes_int[line], sizeof(buffer)); |
72ce4b70 |
buffer[sizeof(buffer)-1]='\0'; |
7021b545 |
} else { |
e8ae4fae |
if(!cli_dbgets(buffer, FILEBUFF, fs, dbio)) |
7021b545 |
break; |
cfacfb45 |
if(buffer[0] == '#')
continue; |
7021b545 |
cli_chomp(buffer);
}
line++; |
72fb25ea |
tokens_count = cli_strtokenize(buffer, ':', FTM_TOKENS + 1, tokens); |
7021b545 |
|
72fb25ea |
if(tokens_count < 6 || tokens_count > 8) { |
7021b545 |
ret = CL_EMALFDB;
break;
}
|
72fb25ea |
if(tokens_count > 6) { /* min version */
pt = tokens[6]; |
6038397e |
if(!cli_isnumber(pt)) {
ret = CL_EMALFDB;
break;
}
if((unsigned int) atoi(pt) > cl_retflevel()) {
cli_dbgmsg("cli_loadftm: File type signature for %s not loaded (required f-level: %u)\n", tokens[3], atoi(pt));
continue;
} |
72fb25ea |
if(tokens_count == 8) { /* max version */
pt = tokens[7]; |
6038397e |
if(!cli_isnumber(pt)) {
ret = CL_EMALFDB;
break;
}
if((unsigned int) atoi(pt) < cl_retflevel())
continue;
}
}
rtype = cli_ftcode(tokens[4]);
type = cli_ftcode(tokens[5]);
if(rtype == CL_TYPE_ERROR || type == CL_TYPE_ERROR) { |
7021b545 |
ret = CL_EMALFDB;
break;
}
|
039c9565 |
if(!cli_isnumber(tokens[0])) {
cli_errmsg("cli_loadftm: Invalid value for the first field\n");
ret = CL_EMALFDB;
break;
}
|
1d1c4b15 |
magictype = atoi(tokens[0]);
if(magictype == 1) { /* A-C */ |
33872a43 |
if((ret = cli_parse_add(engine->root[0], tokens[3], tokens[2], rtype, type, tokens[1], 0, NULL, options))) |
7021b545 |
break;
|
1d1c4b15 |
} else if ((magictype == 0) || (magictype == 4)) { /* memcmp() */ |
039c9565 |
if(!cli_isnumber(tokens[1])) {
cli_errmsg("cli_loadftm: Invalid offset\n");
ret = CL_EMALFDB;
break;
} |
47d40feb |
new = (struct cli_ftype *) mpool_malloc(engine->mempool, sizeof(struct cli_ftype)); |
7021b545 |
if(!new) {
ret = CL_EMEM;
break;
}
new->type = type; |
6038397e |
new->offset = atoi(tokens[1]); |
47d40feb |
new->magic = (unsigned char *) cli_mpool_hex2str(engine->mempool, tokens[2]); |
7021b545 |
if(!new->magic) { |
6038397e |
cli_errmsg("cli_loadftm: Can't decode the hex string\n"); |
7021b545 |
ret = CL_EMALFDB; |
47d40feb |
mpool_free(engine->mempool, new); |
7021b545 |
break;
} |
6038397e |
new->length = strlen(tokens[2]) / 2; |
47d40feb |
new->tname = cli_mpool_strdup(engine->mempool, tokens[3]); |
7021b545 |
if(!new->tname) { |
47d40feb |
mpool_free(engine->mempool, new->magic);
mpool_free(engine->mempool, new); |
7021b545 |
ret = CL_EMEM;
break;
} |
1d1c4b15 |
/* files => ftypes, partitions => ptypes */
if(magictype == 4) {
new->next = engine->ptypes;
engine->ptypes = new;
}
else {
new->next = engine->ftypes;
engine->ftypes = new;
} |
6038397e |
} else {
cli_dbgmsg("cli_loadftm: Unsupported mode %u\n", atoi(tokens[0]));
continue; |
7021b545 |
} |
6038397e |
sigs++; |
7021b545 |
}
|
6038397e |
if(ret) {
cli_errmsg("Problem parsing %s filetype database at line %u\n", internal ? "built-in" : "external", line);
return ret; |
7021b545 |
}
|
6038397e |
if(!sigs) {
cli_errmsg("Empty %s filetype database\n", internal ? "built-in" : "external");
return CL_EMALFDB; |
7021b545 |
}
|
6038397e |
cli_dbgmsg("Loaded %u filetype definitions\n", sigs); |
7021b545 |
return CL_SUCCESS;
}
|
de351ee1 |
#define INFO_NSTR "11088894983048545473659556106627194923928941791795047620591658697413581043322715912172496806525381055880964520618400224333320534660299233983755341740679502866829909679955734391392668378361221524205396631090105151641270857277080310734320951653700508941717419168723942507890702904702707587451621691050754307850383399865346487203798464178537392211402786481359824461197231102895415093770394216666324484593935762408468516826633192140826667923494822045805347809932848454845886971706424360558667862775876072059437703365380209101697738577515476935085469455279994113145977994084618328482151013142393373316337519977244732747977"
#define INFO_ESTR "100002049"
#define INFO_TOKENS 3 |
ace26bfe |
static int cli_loadinfo(FILE *fs, struct cl_engine *engine, unsigned int options, struct cli_dbio *dbio)
{ |
de351ee1 |
const char *tokens[INFO_TOKENS + 1]; |
ace26bfe |
char buffer[FILEBUFF]; |
de351ee1 |
unsigned int line = 0, tokens_count, len;
unsigned char hash[32]; |
ace26bfe |
struct cli_dbinfo *last = NULL, *new; |
de351ee1 |
int ret = CL_SUCCESS, dsig = 0;
SHA256_CTX ctx; |
ace26bfe |
|
7eb6bac7 |
if(!dbio) {
cli_errmsg("cli_loadinfo: .info files can only be loaded from within database container files\n");
return CL_EMALFDB;
} |
de351ee1 |
sha256_init(&ctx); |
ace26bfe |
while(cli_dbgets(buffer, FILEBUFF, fs, dbio)) {
line++; |
cdddd014 |
if(!(options & CL_DB_UNSIGNED) && !strncmp(buffer, "DSIG:", 5)) { |
de351ee1 |
dsig = 1;
sha256_final(&ctx, hash);
if(cli_versig2(hash, buffer + 5, INFO_NSTR, INFO_ESTR) != CL_SUCCESS) {
cli_errmsg("cli_loadinfo: Incorrect digital signature\n");
ret = CL_EMALFDB;
}
break;
}
len = strlen(buffer); |
110714bb |
if (!len) {
buffer[len] = '\n';
buffer[len+1] = 0;
} else {
if(dbio->usebuf && buffer[len - 1] != '\n' && len + 1 < FILEBUFF) {
/* cli_dbgets in buffered mode strips \n */
buffer[len] = '\n';
buffer[len + 1] = 0;
}
} |
de351ee1 |
sha256_update(&ctx, buffer, strlen(buffer)); |
ace26bfe |
cli_chomp(buffer);
if(!strncmp("ClamAV-VDB:", buffer, 11)) {
if(engine->dbinfo) { /* shouldn't be initialized at this point */
cli_errmsg("cli_loadinfo: engine->dbinfo already initialized\n");
ret = CL_EMALFDB;
break;
}
last = engine->dbinfo = (struct cli_dbinfo *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_bm_patt));
if(!engine->dbinfo) {
ret = CL_EMEM;
break;
}
engine->dbinfo->cvd = cl_cvdparse(buffer);
if(!engine->dbinfo->cvd) {
cli_errmsg("cli_loadinfo: Can't parse header entry\n");
ret = CL_EMALFDB;
break;
}
continue;
}
if(!last) {
cli_errmsg("cli_loadinfo: Incorrect file format\n");
ret = CL_EMALFDB;
break;
} |
de351ee1 |
tokens_count = cli_strtokenize(buffer, ':', INFO_TOKENS + 1, tokens);
if(tokens_count != INFO_TOKENS) { |
ace26bfe |
ret = CL_EMALFDB;
break;
}
new = (struct cli_dbinfo *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_dbinfo));
if(!new) {
ret = CL_EMEM;
break;
} |
e4a0f2c9 |
new->name = cli_mpool_strdup(engine->mempool, tokens[0]); |
ace26bfe |
if(!new->name) {
mpool_free(engine->mempool, new);
ret = CL_EMEM;
break;
}
|
de351ee1 |
if(!cli_isnumber(tokens[1])) {
cli_errmsg("cli_loadinfo: Invalid value in the size field\n"); |
ace26bfe |
mpool_free(engine->mempool, new->name);
mpool_free(engine->mempool, new);
ret = CL_EMALFDB;
break;
} |
de351ee1 |
new->size = atoi(tokens[1]); |
ace26bfe |
|
de351ee1 |
if(strlen(tokens[2]) != 64 || !(new->hash = cli_mpool_hex2str(engine->mempool, tokens[2]))) {
cli_errmsg("cli_loadinfo: Malformed SHA256 string at line %u\n", line);
mpool_free(engine->mempool, new->name);
mpool_free(engine->mempool, new);
ret = CL_EMALFDB;
break;
} |
ace26bfe |
last->next = new;
last = new;
}
|
cdddd014 |
if(!(options & CL_DB_UNSIGNED) && !dsig) { |
de351ee1 |
cli_errmsg("cli_loadinfo: Digital signature not found\n");
return CL_EMALFDB;
}
|
ace26bfe |
if(ret) {
cli_errmsg("cli_loadinfo: Problem parsing database at line %u\n", line);
return ret;
}
return CL_SUCCESS;
}
|
04133ff9 |
#define IGN_MAX_TOKENS 3 |
15850fc6 |
static int cli_loadign(FILE *fs, struct cl_engine *engine, unsigned int options, struct cli_dbio *dbio) |
ed9753e9 |
{ |
04133ff9 |
const char *tokens[IGN_MAX_TOKENS + 1], *signame, *hash = NULL; |
b9b47784 |
char buffer[FILEBUFF]; |
12c6a97e |
unsigned int line = 0, tokens_count, len; |
04133ff9 |
struct cli_bm_patt *new; |
ac1b219c |
int ret = CL_SUCCESS; |
ed9753e9 |
|
15850fc6 |
if(!engine->ignored) { |
04133ff9 |
engine->ignored = (struct cli_matcher *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_matcher));
if(!engine->ignored) |
ed9753e9 |
return CL_EMEM; |
04133ff9 |
#ifdef USE_MPOOL
engine->ignored->mempool = engine->mempool;
#endif
if((ret = cli_bm_init(engine->ignored))) {
cli_errmsg("cli_loadign: Can't initialise AC pattern matcher\n");
return ret;
} |
ed9753e9 |
}
|
e8ae4fae |
while(cli_dbgets(buffer, FILEBUFF, fs, dbio)) { |
ed9753e9 |
line++; |
cfacfb45 |
if(buffer[0] == '#')
continue; |
ed9753e9 |
cli_chomp(buffer); |
04133ff9 |
tokens_count = cli_strtokenize(buffer, ':', IGN_MAX_TOKENS + 1, tokens);
if(tokens_count > IGN_MAX_TOKENS) { |
72fb25ea |
ret = CL_EMALFDB;
break;
} |
d6e1ef16 |
|
04133ff9 |
if(tokens_count == 1) {
signame = buffer;
} else if(tokens_count == 2) {
signame = tokens[0];
hash = tokens[1];
} else { /* old mode */
signame = tokens[2];
}
if(!(len = strlen(signame))) {
cli_errmsg("cli_loadign: No signature name provided\n"); |
039c9565 |
ret = CL_EMALFDB;
break;
}
|
04133ff9 |
new = (struct cli_bm_patt *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_bm_patt)); |
ed9753e9 |
if(!new) {
ret = CL_EMEM;
break;
} |
12c6a97e |
new->pattern = (unsigned char *) cli_mpool_strdup(engine->mempool, signame); |
04133ff9 |
if(!new->pattern) { |
47d40feb |
mpool_free(engine->mempool, new); |
04133ff9 |
ret = CL_EMEM; |
ed9753e9 |
break;
} |
04133ff9 |
if(hash) { |
12c6a97e |
if(strlen(hash) != 32 || !(new->virname = (char *) cli_mpool_hex2str(engine->mempool, hash))) { |
04133ff9 |
cli_errmsg("cli_loadign: Malformed MD5 string at line %u\n", line);
mpool_free(engine->mempool, new->pattern);
mpool_free(engine->mempool, new);
ret = CL_EMALFDB;
break;
}
}
new->length = len;
new->boundary |= BM_BOUNDARY_EOL; |
ed9753e9 |
|
04133ff9 |
if((ret = cli_bm_addpatt(engine->ignored, new, "0"))) {
if(hash)
mpool_free(engine->mempool, new->virname);
mpool_free(engine->mempool, new->pattern); |
47d40feb |
mpool_free(engine->mempool, new); |
ed9753e9 |
break;
}
}
if(ret) {
cli_errmsg("cli_loadign: Problem parsing database at line %u\n", line);
return ret;
}
return CL_SUCCESS;
}
|
3dad68eb |
#define MD5_HDB 0
#define MD5_MDB 1
#define MD5_FP 2 |
2b459819 |
|
72bbfaf5 |
#define MD5_TOKENS 5 |
c802edd5 |
static int cli_loadhash(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int mode, unsigned int options, struct cli_dbio *dbio, const char *dbname)
{ |
e37613ad |
const char *tokens[MD5_TOKENS + 1];
char buffer[FILEBUFF], *buffer_cpy = NULL;
const char *pt, *virname;
int ret = CL_SUCCESS;
unsigned int size_field = 1, md5_field = 0, line = 0, sigs = 0, tokens_count;
unsigned int req_fl = 0;
struct cli_matcher *db;
unsigned long size; |
c802edd5 |
if(mode == MD5_MDB) {
size_field = 0;
md5_field = 1; |
004735cb |
db = engine->hm_mdb; |
0c35b7cd |
} else if(mode == MD5_HDB)
db = engine->hm_hdb; |
004735cb |
else
db = engine->hm_fp;
if(!db) {
if(!(db = mpool_calloc(engine->mempool, 1, sizeof(*db))))
return CL_EMEM;
#ifdef USE_MPOOL
db->mempool = engine->mempool;
#endif
if(mode == MD5_HDB)
engine->hm_hdb = db;
else if(mode == MD5_MDB)
engine->hm_mdb = db;
else
engine->hm_fp = db; |
c802edd5 |
}
if(engine->ignored) |
241e7eb1 |
if(!(buffer_cpy = cli_malloc(FILEBUFF))) {
cli_errmsg("cli_loadhash: Can't allocate memory for buffer_cpy\n"); |
c802edd5 |
return CL_EMEM; |
241e7eb1 |
} |
c802edd5 |
while(cli_dbgets(buffer, FILEBUFF, fs, dbio)) {
line++; |
cfacfb45 |
if(buffer[0] == '#')
continue; |
c802edd5 |
cli_chomp(buffer);
if(engine->ignored)
strcpy(buffer_cpy, buffer);
tokens_count = cli_strtokenize(buffer, ':', MD5_TOKENS + 1, tokens); |
72bbfaf5 |
if(tokens_count < 3) { |
c802edd5 |
ret = CL_EMALFDB;
break;
} |
72bbfaf5 |
if(tokens_count > MD5_TOKENS - 2) { |
e37613ad |
req_fl = atoi(tokens[MD5_TOKENS - 2]); |
72bbfaf5 |
if(tokens_count > MD5_TOKENS) {
ret = CL_EMALFDB;
break;
}
if(cl_retflevel() < req_fl)
continue;
if(tokens_count == MD5_TOKENS) { |
e37613ad |
int max_fl = atoi(tokens[MD5_TOKENS - 1]);
if(cl_retflevel() > max_fl) |
72bbfaf5 |
continue;
}
} |
c802edd5 |
|
e37613ad |
if((mode == MD5_MDB) || strcmp(tokens[size_field],"*")) {
size = strtoul(tokens[size_field], (char **)&pt, 10);
if(*pt || !size || size >= 0xffffffff) {
cli_errmsg("cli_loadhash: Invalid value for the size field\n");
ret = CL_EMALFDB;
break;
}
}
else {
size = 0;
if((tokens_count < MD5_TOKENS - 1) || (req_fl < 73)) {
cli_errmsg("cli_loadhash: Minimum FLEVEL field must be at least 73 for wildcard size hash signatures."
" For reference, running FLEVEL is %d\n", cl_retflevel());
ret = CL_EMALFDB;
break;
} |
c802edd5 |
}
pt = tokens[2]; /* virname */
if(engine->pua_cats && (options & CL_DB_PUA_MODE) && (options & (CL_DB_PUA_INCLUDE | CL_DB_PUA_EXCLUDE)))
if(cli_chkpua(pt, engine->pua_cats, options))
continue;
if(engine->ignored && cli_chkign(engine->ignored, pt, buffer_cpy))
continue;
if(engine->cb_sigload) {
const char *dot = strchr(dbname, '.');
if(!dot)
dot = dbname;
else
dot++; |
f206d31a |
if(engine->cb_sigload(dot, pt, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) { |
c802edd5 |
cli_dbgmsg("cli_loadhash: skipping %s (%s) due to callback\n", pt, dot);
continue;
}
}
virname = cli_mpool_virname(engine->mempool, pt, options & CL_DB_OFFICIAL);
if(!virname) {
ret = CL_EMALFDB;
break;
}
|
7cb86faf |
if((ret = hm_addhash_str(db, tokens[md5_field], size, virname))) { |
004735cb |
cli_errmsg("cli_loadhash: Malformed hash string at line %u\n", line); |
c802edd5 |
mpool_free(engine->mempool, (void *)virname);
break;
}
sigs++;
}
if(engine->ignored)
free(buffer_cpy);
if(!line) { |
2296ab0f |
cli_errmsg("cli_loadhash: Empty database file\n"); |
c802edd5 |
return CL_EMALFDB;
}
if(ret) { |
2296ab0f |
cli_errmsg("cli_loadhash: Problem parsing database at line %u\n", line); |
c802edd5 |
return ret;
}
if(signo)
*signo += sigs;
return CL_SUCCESS;
}
|
d6e1ef16 |
#define MD_TOKENS 9 |
15850fc6 |
static int cli_loadmd(FILE *fs, struct cl_engine *engine, unsigned int *signo, int type, unsigned int options, struct cli_dbio *dbio, const char *dbname) |
e5916a51 |
{ |
72fb25ea |
const char *tokens[MD_TOKENS + 1]; |
12c6a97e |
char buffer[FILEBUFF], *buffer_cpy = NULL; |
72fb25ea |
unsigned int line = 0, sigs = 0, tokens_count; |
12c6a97e |
int ret = CL_SUCCESS; |
15f413d1 |
struct cli_cdb *new; |
e5916a51 |
|
04133ff9 |
if(engine->ignored) |
241e7eb1 |
if(!(buffer_cpy = cli_malloc(FILEBUFF))) {
cli_errmsg("cli_loadmd: Can't allocate memory for buffer_cpy\n"); |
04133ff9 |
return CL_EMEM; |
241e7eb1 |
} |
04133ff9 |
|
e8ae4fae |
while(cli_dbgets(buffer, FILEBUFF, fs, dbio)) { |
e5916a51 |
line++; |
ed9753e9 |
if(buffer[0] == '#') |
e5916a51 |
continue;
cli_chomp(buffer); |
04133ff9 |
if(engine->ignored)
strcpy(buffer_cpy, buffer);
|
72fb25ea |
tokens_count = cli_strtokenize(buffer, ':', MD_TOKENS + 1, tokens);
if(tokens_count != MD_TOKENS) {
ret = CL_EMALFDB;
break;
} |
e5916a51 |
|
039c9565 |
if(strcmp(tokens[1], "*") && !cli_isnumber(tokens[1])) {
cli_errmsg("cli_loadmd: Invalid value for the 'encrypted' field\n");
ret = CL_EMALFDB;
break;
}
if(strcmp(tokens[3], "*") && !cli_isnumber(tokens[3])) {
cli_errmsg("cli_loadmd: Invalid value for the 'original size' field\n");
ret = CL_EMALFDB;
break;
}
if(strcmp(tokens[4], "*") && !cli_isnumber(tokens[4])) {
cli_errmsg("cli_loadmd: Invalid value for the 'compressed size' field\n");
ret = CL_EMALFDB;
break;
}
if(strcmp(tokens[6], "*") && !cli_isnumber(tokens[6])) {
cli_errmsg("cli_loadmd: Invalid value for the 'compression method' field\n");
ret = CL_EMALFDB;
break;
}
if(strcmp(tokens[7], "*") && !cli_isnumber(tokens[7])) {
cli_errmsg("cli_loadmd: Invalid value for the 'file number' field\n");
ret = CL_EMALFDB;
break;
}
if(strcmp(tokens[8], "*") && !cli_isnumber(tokens[8])) {
cli_errmsg("cli_loadmd: Invalid value for the 'max depth' field\n");
ret = CL_EMALFDB;
break;
}
|
15f413d1 |
new = (struct cli_cdb *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_cdb)); |
e5916a51 |
if(!new) {
ret = CL_EMEM;
break;
}
|
12c6a97e |
new->virname = cli_mpool_virname(engine->mempool, tokens[0], options & CL_DB_OFFICIAL); |
0728972e |
if(!new->virname) { |
47d40feb |
mpool_free(engine->mempool, new); |
b5513f8d |
ret = CL_EMEM; |
e5916a51 |
break;
} |
15f413d1 |
new->ctype = (type == 1) ? CL_TYPE_ZIP : CL_TYPE_RAR; |
e5916a51 |
|
04133ff9 |
if(engine->ignored && cli_chkign(engine->ignored, new->virname, buffer/*_cpy*/)) { |
47d40feb |
mpool_free(engine->mempool, new->virname);
mpool_free(engine->mempool, new); |
ed9753e9 |
continue;
}
|
f206d31a |
if(engine->cb_sigload && engine->cb_sigload("md", new->virname, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) { |
eb422a03 |
cli_dbgmsg("cli_loadmd: skipping %s due to callback\n", new->virname);
mpool_free(engine->mempool, new->virname);
mpool_free(engine->mempool, new);
continue;
}
|
545247af |
new->encrypted = strcmp(tokens[1], "*") ? atoi(tokens[1]) : 2; |
15f413d1 |
if(strcmp(tokens[2], "*") && cli_regcomp(&new->name, tokens[2], REG_EXTENDED | REG_NOSUB)) {
cli_errmsg("cli_loadmd: Can't compile regular expression %s in signature for %s\n", tokens[2], tokens[0]); |
47d40feb |
mpool_free(engine->mempool, new->virname);
mpool_free(engine->mempool, new); |
15f413d1 |
ret = CL_EMEM; |
e5916a51 |
break;
} |
15f413d1 |
new->csize[0] = new->csize[1] = CLI_OFF_ANY; |
e5916a51 |
|
d6e1ef16 |
if(!strcmp(tokens[3], "*")) |
15f413d1 |
new->fsizer[0] = new->fsizer[1] = CLI_OFF_ANY; |
d6e1ef16 |
else |
15f413d1 |
new->fsizer[0] = new->fsizer[1] = atoi(tokens[3]); |
e5916a51 |
|
d6e1ef16 |
if(!strcmp(tokens[4], "*")) |
15f413d1 |
new->fsizec[0] = new->fsizec[1] = CLI_OFF_ANY; |
d6e1ef16 |
else |
15f413d1 |
new->fsizec[0] = new->fsizec[1] = atoi(tokens[4]); |
e5916a51 |
|
15f413d1 |
if(strcmp(tokens[5], "*")) {
new->res1 = cli_hex2num(tokens[5]);
if(new->res1 == -1) {
mpool_free(engine->mempool, new->virname);
mpool_free(engine->mempool, new);
if(new->name.re_magic)
cli_regfree(&new->name); |
d6e1ef16 |
ret = CL_EMALFDB;
break; |
e5916a51 |
}
}
|
15f413d1 |
/* tokens[6] - not used */ |
e5916a51 |
|
bb1e844c |
new->filepos[0] = new->filepos[1] = strcmp(tokens[7], "*") ? atoi(tokens[7]) : (int) CLI_OFF_ANY; |
19e2ac07 |
|
15f413d1 |
/* tokens[8] - not used */ |
ed9753e9 |
|
15f413d1 |
new->next = engine->cdb;
engine->cdb = new; |
ed9753e9 |
sigs++; |
e5916a51 |
} |
04133ff9 |
if(engine->ignored)
free(buffer_cpy); |
e5916a51 |
if(!line) {
cli_errmsg("Empty database file\n");
return CL_EMALFDB;
}
if(ret) {
cli_errmsg("Problem parsing database at line %d\n", line);
return ret;
}
if(signo) |
ed9753e9 |
*signo += sigs; |
e5916a51 |
|
8d3aca30 |
return CL_SUCCESS; |
e5916a51 |
}
|
570b1d00 |
/* 0 1 2 3 4 5 6 7 8 9 10 11
* VirusName:ContainerType:ContainerSize:FileNameREGEX:FileSizeInContainer:FileSizeReal:IsEncrypted:FilePos:Res1:Res2[:MinFL[:MaxFL]] |
55094a9c |
*/ |
570b1d00 |
#define CDB_TOKENS 12 |
55094a9c |
static int cli_loadcdb(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio)
{ |
20e41993 |
const char *tokens[CDB_TOKENS + 1]; |
12c6a97e |
char buffer[FILEBUFF], *buffer_cpy = NULL; |
55094a9c |
unsigned int line = 0, sigs = 0, tokens_count, n0, n1;
int ret = CL_SUCCESS;
struct cli_cdb *new;
if(engine->ignored) |
241e7eb1 |
if(!(buffer_cpy = cli_malloc(FILEBUFF))) {
cli_errmsg("cli_loadcdb: Can't allocate memory for buffer_cpy\n"); |
55094a9c |
return CL_EMEM; |
241e7eb1 |
} |
55094a9c |
while(cli_dbgets(buffer, FILEBUFF, fs, dbio)) {
line++;
if(buffer[0] == '#')
continue;
cli_chomp(buffer);
if(engine->ignored)
strcpy(buffer_cpy, buffer);
tokens_count = cli_strtokenize(buffer, ':', CDB_TOKENS + 1, tokens); |
15f413d1 |
if(tokens_count > CDB_TOKENS || tokens_count < CDB_TOKENS - 2) { |
55094a9c |
ret = CL_EMALFDB;
break;
}
|
570b1d00 |
if(tokens_count > 10) { /* min version */
if(!cli_isnumber(tokens[10])) { |
55094a9c |
ret = CL_EMALFDB;
break;
} |
570b1d00 |
if((unsigned int) atoi(tokens[10]) > cl_retflevel()) { |
55094a9c |
cli_dbgmsg("cli_loadcdb: Container signature for %s not loaded (required f-level: %u)\n", tokens[0], atoi(tokens[10]));
continue;
} |
570b1d00 |
if(tokens_count == CDB_TOKENS) { /* max version */
if(!cli_isnumber(tokens[11])) { |
55094a9c |
ret = CL_EMALFDB;
break;
} |
570b1d00 |
if((unsigned int) atoi(tokens[11]) < cl_retflevel()) |
55094a9c |
continue;
}
}
new = (struct cli_cdb *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_cdb));
if(!new) {
ret = CL_EMEM;
break;
}
|
12c6a97e |
new->virname = cli_mpool_virname(engine->mempool, tokens[0], options & CL_DB_OFFICIAL); |
55094a9c |
if(!new->virname) {
mpool_free(engine->mempool, new);
ret = CL_EMEM;
break;
}
if(engine->ignored && cli_chkign(engine->ignored, new->virname, buffer/*_cpy*/)) {
mpool_free(engine->mempool, new->virname);
mpool_free(engine->mempool, new);
continue;
}
|
f206d31a |
if(engine->cb_sigload && engine->cb_sigload("cdb", new->virname, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) { |
eb422a03 |
cli_dbgmsg("cli_loadcdb: skipping %s due to callback\n", new->virname);
mpool_free(engine->mempool, new->virname);
mpool_free(engine->mempool, new);
continue;
}
|
55094a9c |
if(!strcmp(tokens[1], "*")) {
new->ctype = CL_TYPE_ANY;
} else if((new->ctype = cli_ftcode(tokens[1])) == CL_TYPE_ERROR) { |
15f413d1 |
cli_dbgmsg("cli_loadcdb: Unknown container type %s in signature for %s, skipping\n", tokens[1], tokens[0]); |
55094a9c |
mpool_free(engine->mempool, new->virname);
mpool_free(engine->mempool, new);
continue;
}
if(strcmp(tokens[3], "*") && cli_regcomp(&new->name, tokens[3], REG_EXTENDED | REG_NOSUB)) { |
15f413d1 |
cli_errmsg("cli_loadcdb: Can't compile regular expression %s in signature for %s\n", tokens[3], tokens[0]); |
55094a9c |
mpool_free(engine->mempool, new->virname);
mpool_free(engine->mempool, new);
ret = CL_EMEM;
break;
}
#define CDBRANGE(token_str, dest) \
if(strcmp(token_str, "*")) { \
if(strchr(token_str, '-')) { \
if(sscanf(token_str, "%u-%u", &n0, &n1) != 2) { \
ret = CL_EMALFDB; \
} else { \
dest[0] = n0; \
dest[1] = n1; \
} \
} else { \
if(!cli_isnumber(token_str)) \
ret = CL_EMALFDB; \
else \
dest[0] = dest[1] = atoi(token_str); \
} \
if(ret != CL_SUCCESS) { \ |
15f413d1 |
cli_errmsg("cli_loadcdb: Invalid value %s in signature for %s\n",\ |
55094a9c |
token_str, tokens[0]); \
if(new->name.re_magic) \
cli_regfree(&new->name); \
mpool_free(engine->mempool, new->virname); \
mpool_free(engine->mempool, new); \
ret = CL_EMEM; \
break; \
} \
} else { \
dest[0] = dest[1] = CLI_OFF_ANY; \
}
|
570b1d00 |
CDBRANGE(tokens[2], new->csize);
CDBRANGE(tokens[4], new->fsizec);
CDBRANGE(tokens[5], new->fsizer);
CDBRANGE(tokens[7], new->filepos); |
55094a9c |
|
570b1d00 |
if(!strcmp(tokens[6], "*")) { |
55094a9c |
new->encrypted = 2;
} else { |
570b1d00 |
if(strcmp(tokens[6], "0") && strcmp(tokens[6], "1")) { |
15f413d1 |
cli_errmsg("cli_loadcdb: Invalid encryption flag value in signature for %s\n", tokens[0]); |
55094a9c |
if(new->name.re_magic)
cli_regfree(&new->name);
mpool_free(engine->mempool, new->virname);
mpool_free(engine->mempool, new);
ret = CL_EMEM;
break;
} |
570b1d00 |
new->encrypted = *tokens[6] - 0x30; |
55094a9c |
}
|
570b1d00 |
if(strcmp(tokens[9], "*")) {
new->res2 = cli_mpool_strdup(engine->mempool, tokens[9]); |
55094a9c |
if(!new->res2) { |
15f413d1 |
cli_errmsg("cli_loadcdb: Can't allocate memory for res2 in signature for %s\n", tokens[0]); |
55094a9c |
if(new->name.re_magic)
cli_regfree(&new->name);
mpool_free(engine->mempool, new->virname);
mpool_free(engine->mempool, new);
ret = CL_EMEM;
break;
}
}
new->next = engine->cdb;
engine->cdb = new;
sigs++;
}
if(engine->ignored)
free(buffer_cpy);
if(!line) {
cli_errmsg("Empty database file\n");
return CL_EMALFDB;
}
if(ret) {
cli_errmsg("Problem parsing database at line %u\n", line);
return ret;
}
if(signo)
*signo += sigs;
return CL_SUCCESS;
}
|
d12f1646 |
/* |
62023156 |
* name;trusted;subject;serial;pubkey;exp;codesign;timesign;certsign;notbefore;comment[;minFL[;maxFL]] |
d12f1646 |
* Name and comment are ignored. They're just for the end user. |
ee07fcd6 |
* Exponent is ignored for now and hardcoded to \x01\x00\x01. |
d12f1646 |
*/ |
62023156 |
#define CRT_TOKENS 13 |
d12f1646 |
static int cli_loadcrt(FILE *fs, struct cl_engine *engine, struct cli_dbio *dbio) {
char buffer[FILEBUFF];
char *tokens[CRT_TOKENS+1];
size_t line=0, tokens_count, i, j;
cli_crt ca;
int ret=CL_SUCCESS; |
dfa2b2c3 |
char *subject=NULL, *pubkey=NULL, *exponent=NULL, *serial=NULL; |
d12f1646 |
const uint8_t exp[] = "\x01\x00\x01";
char c;
cli_crt_init(&ca); |
878cece5 |
memset(ca.issuer, 0xca, sizeof(ca.issuer)); |
d12f1646 |
while (cli_dbgets(buffer, FILEBUFF, fs, dbio)) {
line++;
if (buffer[0] == '#')
continue;
cli_chomp(buffer);
if (!strlen(buffer))
continue;
tokens_count = cli_strtokenize(buffer, ';', CRT_TOKENS + 1, (const char **)tokens);
if (tokens_count > CRT_TOKENS || tokens_count < CRT_TOKENS - 2) { |
59a60382 |
cli_errmsg("cli_loadcrt: line %u: Invalid number of tokens: %u\n", (unsigned int)line, (unsigned int)tokens_count); |
d12f1646 |
ret = CL_EMALFDB;
goto end;
}
|
ee07fcd6 |
if (tokens_count > CRT_TOKENS - 2) {
if (!cli_isnumber(tokens[CRT_TOKENS-1])) { |
59a60382 |
cli_errmsg("cli_loadcrt: line %u: Invalid minimum feature level\n", (unsigned int)line); |
ee07fcd6 |
ret = CL_EMALFDB;
goto end;
}
if ((unsigned int)atoi(tokens[CRT_TOKENS-1]) > cl_retflevel()) {
cli_dbgmsg("cli_loadcrt: Cert %s not loaded (required f-level: %u)\n", tokens[0], cl_retflevel());
continue;
}
if (tokens_count == CRT_TOKENS) {
if (!cli_isnumber(tokens[CRT_TOKENS])) { |
59a60382 |
cli_errmsg("cli_loadcrt: line %u: Invalid maximum feature level\n", (unsigned int)line); |
ee07fcd6 |
ret = CL_EMALFDB;
goto end;
}
|
2c2e89e1 |
if ((unsigned int)atoi(tokens[CRT_TOKENS]) < cl_retflevel()) { |
ee07fcd6 |
cli_dbgmsg("cli_ladcrt: Cert %s not loaded (maximum f-level: %s)\n", tokens[0], tokens[CRT_TOKENS]);
continue;
}
}
}
|
d12f1646 |
switch (tokens[1][0]) {
case '1':
ca.isBlacklisted = 0;
break;
case '0':
ca.isBlacklisted = 1;
break;
default: |
59a60382 |
cli_errmsg("cli_loadcrt: line %u: Invalid trust specification. Expected 0 or 1\n", (unsigned int)line); |
d12f1646 |
ret = CL_EMALFDB;
goto end;
}
subject = cli_hex2str(tokens[2]); |
62023156 |
if (strlen(tokens[3])) {
serial = cli_hex2str(tokens[3]);
if (!serial) { |
59a60382 |
cli_errmsg("cli_loadcrt: line %u: Cannot convert serial to binary string\n", (unsigned int)line); |
62023156 |
ret = CL_EMALFDB;
goto end;
}
memcpy(ca.serial, serial, sizeof(ca.serial));
free(serial);
} else { |
c2fac6e9 |
memset(ca.serial, 0xca, sizeof(ca.serial)); |
62023156 |
}
pubkey = cli_hex2str(tokens[4]);
cli_dbgmsg("cli_loadcrt: subject: %s\n", tokens[2]);
cli_dbgmsg("cli_loadcrt: public key: %s\n", tokens[4]); |
d12f1646 |
if (!subject) { |
59a60382 |
cli_errmsg("cli_loadcrt: line %u: Cannot convert subject to binary string\n", (unsigned int)line); |
d12f1646 |
ret = CL_EMALFDB;
goto end;
}
if (!pubkey) { |
59a60382 |
cli_errmsg("cli_loadcrt: line %u: Cannot convert public key to binary string\n", (unsigned int)line); |
d12f1646 |
ret = CL_EMALFDB;
goto end;
}
memcpy(ca.subject, subject, sizeof(ca.subject)); |
62023156 |
if (mp_read_unsigned_bin(&(ca.n), pubkey, strlen(tokens[4])/2) || mp_read_unsigned_bin(&(ca.e), exp, sizeof(exp)-1)) { |
59a60382 |
cli_errmsg("cli_loadcrt: line %u: Cannot convert exponent to binary data\n", (unsigned int)line); |
d12f1646 |
ret = CL_EMALFDB;
goto end;
}
|
62023156 |
switch (tokens[6][0]) { |
d12f1646 |
case '1':
ca.codeSign = 1;
break;
case '0':
ca.codeSign = 0;
break;
default: |
59a60382 |
cli_errmsg("cli_loadcrt: line %u: Invalid code sign specification. Expected 0 or 1\n", (unsigned int)line); |
d12f1646 |
ret = CL_EMALFDB;
goto end;
}
|
62023156 |
switch (tokens[7][0]) { |
d12f1646 |
case '1':
ca.timeSign = 1;
break;
case '0':
ca.timeSign = 0;
break;
default: |
59a60382 |
cli_errmsg("cli_loadcrt: line %u: Invalid time sign specification. Expected 0 or 1\n", (unsigned int)line); |
d12f1646 |
ret = CL_EMALFDB;
goto end;
}
|
62023156 |
switch (tokens[8][0]) {
case '1':
ca.certSign = 1;
break;
case '0':
ca.certSign = 0;
break;
default: |
59a60382 |
cli_errmsg("cli_loadcrt: line %u: Invalid cert sign specification. Expected 0 or 1\n", (unsigned int)line); |
62023156 |
ret = CL_EMALFDB;
goto end;
}
|
0f418a13 |
if (strlen(tokens[0]))
ca.name = tokens[0];
else
ca.name = NULL;
|
62023156 |
if (strlen(tokens[9]))
ca.not_before = atoi(tokens[8]); |
d12f1646 |
ca.not_after = (-1U)>>1;
|
dfa2b2c3 |
ca.hashtype = CLI_SHA1RSA; |
d12f1646 |
crtmgr_add(&(engine->cmgr), &ca); |
59a60382 |
free(subject);
free(pubkey); |
c2fac6e9 |
subject = pubkey = NULL; |
d12f1646 |
}
end: |
c2fac6e9 |
if (subject)
free(subject);
if (pubkey)
free(pubkey);
|
d12f1646 |
cli_dbgmsg("Number of certs: %d\n", engine->cmgr.items);
cli_crt_clear(&ca);
return ret;
}
|
71d2c4ce |
static int cli_loadmscat(FILE *fs, const char *dbname, struct cl_engine *engine, unsigned int options, struct cli_dbio *dbio) { |
5d49bd06 |
fmap_t *map;
|
ccb37138 |
if(!(map = fmap(fileno(fs), 0, 0))) { |
57dbcca2 |
cli_dbgmsg("Can't map cat: %s\n", dbname); |
ccb37138 |
return 0;
} |
5d49bd06 |
|
0393aa56 |
if(asn1_load_mscat(map, engine)) |
57dbcca2 |
cli_dbgmsg("Failed to load certificates from cat: %s\n", dbname); |
5d49bd06 |
funmap(map); |
5b48b665 |
return 0;
}
|
15850fc6 |
static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned int *signo, unsigned int options); |
52c67b86 |
|
15850fc6 |
int cli_load(const char *filename, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio) |
e3aaff8e |
{ |
056d95dc |
FILE *fs = NULL; |
f51e962f |
int ret = CL_SUCCESS; |
4efca56b |
uint8_t skipped = 0; |
ed9753e9 |
const char *dbname; |
f8202681 |
char buff[FILEBUFF]; |
f51e962f |
|
4048c4f6 |
|
f8202681 |
if(dbio && dbio->chkonly) {
while(cli_dbgets(buff, FILEBUFF, NULL, dbio));
return CL_SUCCESS;
}
|
e8ae4fae |
if(!dbio && (fs = fopen(filename, "rb")) == NULL) { |
99ca7f53 |
if(options & CL_DB_DIRECTORY) { /* bb#1624 */
if(access(filename, R_OK)) {
if(errno == ENOENT) {
cli_dbgmsg("Detected race condition, ignoring old file %s\n", filename);
return CL_SUCCESS;
}
}
} |
f51e962f |
cli_errmsg("cli_load(): Can't open file %s\n", filename); |
4048c4f6 |
return CL_EOPEN;
}
|
58481352 |
if((dbname = strrchr(filename, *PATHSEP))) |
ed9753e9 |
dbname++;
else
dbname = filename; |
4048c4f6 |
|
ed9753e9 |
if(cli_strbcasestr(dbname, ".db")) { |
e8ae4fae |
ret = cli_loaddb(fs, engine, signo, options, dbio, dbname); |
ed9753e9 |
} else if(cli_strbcasestr(dbname, ".cvd")) { |
f8202681 |
ret = cli_cvdload(fs, engine, signo, options, 0, filename, 0); |
9d193ff2 |
|
ed9753e9 |
} else if(cli_strbcasestr(dbname, ".cld")) { |
f8202681 |
ret = cli_cvdload(fs, engine, signo, options, 1, filename, 0); |
4048c4f6 |
|
cdddd014 |
} else if(cli_strbcasestr(dbname, ".cud")) {
ret = cli_cvdload(fs, engine, signo, options, 2, filename, 0);
|
c05ac24f |
} else if (cli_strbcasestr(dbname, ".crb")) { |
d12f1646 |
ret = cli_loadcrt(fs, engine, dbio);
|
3faa9783 |
} else if(cli_strbcasestr(dbname, ".hdb") || cli_strbcasestr(dbname, ".hsb")) {
ret = cli_loadhash(fs, engine, signo, MD5_HDB, options, dbio, dbname);
} else if(cli_strbcasestr(dbname, ".hdu") || cli_strbcasestr(dbname, ".hsu")) { |
70edb085 |
if(options & CL_DB_PUA) |
3faa9783 |
ret = cli_loadhash(fs, engine, signo, MD5_HDB, options | CL_DB_PUA_MODE, dbio, dbname); |
70edb085 |
else
skipped = 1;
|
3faa9783 |
} else if(cli_strbcasestr(dbname, ".fp") || cli_strbcasestr(dbname, ".sfp")) {
ret = cli_loadhash(fs, engine, signo, MD5_FP, options, dbio, dbname);
} else if(cli_strbcasestr(dbname, ".mdb") || cli_strbcasestr(dbname, ".msb")) {
ret = cli_loadhash(fs, engine, signo, MD5_MDB, options, dbio, dbname); |
c09d6c19 |
|
3faa9783 |
} else if(cli_strbcasestr(dbname, ".mdu") || cli_strbcasestr(dbname, ".msu")) { |
70edb085 |
if(options & CL_DB_PUA) |
3faa9783 |
ret = cli_loadhash(fs, engine, signo, MD5_MDB, options | CL_DB_PUA_MODE, dbio, dbname); |
70edb085 |
else
skipped = 1;
|
ed9753e9 |
} else if(cli_strbcasestr(dbname, ".ndb")) { |
e8ae4fae |
ret = cli_loadndb(fs, engine, signo, 0, options, dbio, dbname); |
555c5390 |
|
ed9753e9 |
} else if(cli_strbcasestr(dbname, ".ndu")) { |
09eab32a |
if(!(options & CL_DB_PUA)) |
70edb085 |
skipped = 1;
else |
b023c36d |
ret = cli_loadndb(fs, engine, signo, 0, options | CL_DB_PUA_MODE, dbio, dbname); |
70edb085 |
|
677fc4ba |
} else if(cli_strbcasestr(filename, ".ldb")) {
ret = cli_loadldb(fs, engine, signo, options, dbio, dbname);
} else if(cli_strbcasestr(filename, ".ldu")) {
if(options & CL_DB_PUA) |
b023c36d |
ret = cli_loadldb(fs, engine, signo, options | CL_DB_PUA_MODE, dbio, dbname); |
677fc4ba |
else
skipped = 1; |
52dd3a6b |
} else if(cli_strbcasestr(filename, ".cbc")) {
if(options & CL_DB_BYTECODE)
ret = cli_loadcbc(fs, engine, signo, options, dbio, dbname);
else
skipped = 1; |
ed9753e9 |
} else if(cli_strbcasestr(dbname, ".sdb")) { |
e8ae4fae |
ret = cli_loadndb(fs, engine, signo, 1, options, dbio, dbname); |
b68d11d2 |
|
ed9753e9 |
} else if(cli_strbcasestr(dbname, ".zmd")) { |
e8ae4fae |
ret = cli_loadmd(fs, engine, signo, 1, options, dbio, dbname); |
a62ae54f |
|
ed9753e9 |
} else if(cli_strbcasestr(dbname, ".rmd")) { |
e8ae4fae |
ret = cli_loadmd(fs, engine, signo, 2, options, dbio, dbname); |
e5916a51 |
|
ed9753e9 |
} else if(cli_strbcasestr(dbname, ".cfg")) { |
e8ae4fae |
ret = cli_dconf_load(fs, engine, options, dbio); |
bc93eda0 |
|
ace26bfe |
} else if(cli_strbcasestr(dbname, ".info")) {
ret = cli_loadinfo(fs, engine, options, dbio);
|
ed9753e9 |
} else if(cli_strbcasestr(dbname, ".wdb")) { |
056d95dc |
if(options & CL_DB_PHISHING_URLS) { |
e8ae4fae |
ret = cli_loadwdb(fs, engine, options, dbio); |
056d95dc |
} else |
7dec7955 |
skipped = 1; |
0810d861 |
} else if(cli_strbcasestr(dbname, ".pdb") || cli_strbcasestr(dbname, ".gdb")) { |
056d95dc |
if(options & CL_DB_PHISHING_URLS) { |
03527bee |
ret = cli_loadpdb(fs, engine, signo, options, dbio); |
056d95dc |
} else |
7dec7955 |
skipped = 1; |
6038397e |
} else if(cli_strbcasestr(dbname, ".ftm")) { |
e8ae4fae |
ret = cli_loadftm(fs, engine, options, 0, dbio); |
7021b545 |
|
04133ff9 |
} else if(cli_strbcasestr(dbname, ".ign") || cli_strbcasestr(dbname, ".ign2")) { |
e8ae4fae |
ret = cli_loadign(fs, engine, options, dbio); |
ed9753e9 |
|
182e40db |
} else if(cli_strbcasestr(dbname, ".idb")) {
ret = cli_loadidb(fs, engine, signo, options, dbio); |
a8d621cf |
|
55094a9c |
} else if(cli_strbcasestr(dbname, ".cdb")) {
ret = cli_loadcdb(fs, engine, signo, options, dbio); |
5b48b665 |
} else if(cli_strbcasestr(dbname, ".cat")) { |
71d2c4ce |
ret = cli_loadmscat(fs, dbname, engine, options, dbio); |
4048c4f6 |
} else { |
f51e962f |
cli_dbgmsg("cli_load: unknown extension - assuming old database format\n"); |
e8ae4fae |
ret = cli_loaddb(fs, engine, signo, options, dbio, dbname); |
5b48b665 |
} |
4048c4f6 |
|
4efca56b |
if(ret) { |
975ef8ce |
cli_errmsg("Can't load %s: %s\n", filename, cl_strerror(ret)); |
4efca56b |
} else {
if(skipped)
cli_dbgmsg("%s skipped\n", filename);
else
cli_dbgmsg("%s loaded\n", filename);
} |
4048c4f6 |
|
056d95dc |
if(fs)
fclose(fs);
|
4048c4f6 |
return ret; |
e3aaff8e |
}
|
15850fc6 |
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; |
284e1ee4 |
int ret = CL_EOPEN, have_cld;
struct cl_cvd *daily_cld, *daily_cvd; |
e3aaff8e |
|
0eacacec |
cli_dbgmsg("Loading databases from %s\n", dirname); |
04133ff9 |
if((dd = opendir(dirname)) == NULL) {
cli_errmsg("cli_loaddbdir(): Can't open directory %s\n", dirname);
return CL_EOPEN;
}
/* first round - load .ign and .ign2 files */
#ifdef HAVE_READDIR_R_3
while(!readdir_r(dd, &result.d, &dent) && dent) {
#elif defined(HAVE_READDIR_R_2)
while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
#else
while((dent = readdir(dd))) {
#endif
if(dent->d_ino)
{
if(cli_strbcasestr(dent->d_name, ".ign") || cli_strbcasestr(dent->d_name, ".ign2")) {
dbfile = (char *) cli_malloc(strlen(dent->d_name) + strlen(dirname) + 2);
if(!dbfile) { |
241e7eb1 |
cli_errmsg("cli_loaddbdir(): dbfile == NULL\n"); |
04133ff9 |
closedir(dd);
return CL_EMEM;
}
sprintf(dbfile, "%s"PATHSEP"%s", dirname, dent->d_name);
ret = cli_load(dbfile, engine, signo, options, NULL);
if(ret) { |
241e7eb1 |
cli_errmsg("cli_loaddbdir(): error loading database %s\n", dbfile); |
04133ff9 |
free(dbfile);
closedir(dd);
return ret;
}
free(dbfile);
}
}
}
/* the daily db must be loaded before main */ |
ed9753e9 |
dbfile = (char *) cli_malloc(strlen(dirname) + 20); |
04133ff9 |
if(!dbfile) {
closedir(dd); |
241e7eb1 |
cli_errmsg("cli_loaddbdir: Can't allocate memory for dbfile\n"); |
0eacacec |
return CL_EMEM; |
ed9753e9 |
}
|
58481352 |
sprintf(dbfile, "%s"PATHSEP"daily.cld", dirname); |
284e1ee4 |
have_cld = !access(dbfile, R_OK);
if(have_cld) {
daily_cld = cl_cvdhead(dbfile);
if(!daily_cld) {
cli_errmsg("cli_loaddbdir(): error parsing header of %s\n", dbfile);
free(dbfile);
closedir(dd);
return CL_EMALFDB;
}
}
sprintf(dbfile, "%s"PATHSEP"daily.cvd", dirname);
if(!access(dbfile, R_OK)) {
if(have_cld) {
daily_cvd = cl_cvdhead(dbfile);
if(!daily_cvd) {
cli_errmsg("cli_loaddbdir(): error parsing header of %s\n", dbfile);
free(dbfile); |
2979de20 |
cl_cvdfree(daily_cld); |
284e1ee4 |
closedir(dd);
return CL_EMALFDB;
}
if(daily_cld->version > daily_cvd->version)
sprintf(dbfile, "%s"PATHSEP"daily.cld", dirname);
cl_cvdfree(daily_cvd);
}
} else {
sprintf(dbfile, "%s"PATHSEP"daily.cld", dirname);
}
if(have_cld)
cl_cvdfree(daily_cld);
|
e8ae4fae |
if(!access(dbfile, R_OK) && (ret = cli_load(dbfile, engine, signo, options, NULL))) { |
ed9753e9 |
free(dbfile); |
04133ff9 |
closedir(dd); |
ed9753e9 |
return ret;
}
|
816d66a8 |
/* try to load local.gdb next */ |
58481352 |
sprintf(dbfile, "%s"PATHSEP"local.gdb", dirname); |
816d66a8 |
if(!access(dbfile, R_OK) && (ret = cli_load(dbfile, engine, signo, options, NULL))) {
free(dbfile); |
04133ff9 |
closedir(dd); |
816d66a8 |
return ret;
}
|
ed9753e9 |
/* check for and load daily.cfg */ |
58481352 |
sprintf(dbfile, "%s"PATHSEP"daily.cfg", dirname); |
e8ae4fae |
if(!access(dbfile, R_OK) && (ret = cli_load(dbfile, engine, signo, options, NULL))) { |
ed9753e9 |
free(dbfile); |
04133ff9 |
closedir(dd); |
ed9753e9 |
return ret; |
0eacacec |
}
free(dbfile);
|
04133ff9 |
/* second round - load everything else */
rewinddir(dd); |
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 |
if(dent->d_ino)
{ |
04133ff9 |
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") && strcmp(dent->d_name, "daily.cvd") && strcmp(dent->d_name, "daily.cld") && strcmp(dent->d_name, "daily.cfg") && CLI_DBEXT(dent->d_name)) { |
208ceae5 |
if((options & CL_DB_OFFICIAL_ONLY) && !strstr(dirname, "clamav-") && !cli_strbcasestr(dent->d_name, ".cld") && !cli_strbcasestr(dent->d_name, ".cvd")) {
cli_dbgmsg("Skipping unofficial database %s\n", dent->d_name);
continue;
}
|
0eacacec |
dbfile = (char *) cli_malloc(strlen(dent->d_name) + strlen(dirname) + 2); |
e3aaff8e |
if(!dbfile) { |
241e7eb1 |
cli_errmsg("cli_loaddbdir(): dbfile == NULL\n"); |
e3aaff8e |
closedir(dd);
return CL_EMEM;
} |
58481352 |
sprintf(dbfile, "%s"PATHSEP"%s", dirname, dent->d_name); |
e8ae4fae |
ret = cli_load(dbfile, engine, signo, options, NULL); |
3dad68eb |
if(ret) { |
241e7eb1 |
cli_errmsg("cli_loaddbdir(): error loading database %s\n", dbfile); |
e3aaff8e |
free(dbfile);
closedir(dd);
return ret;
}
free(dbfile);
}
}
}
closedir(dd); |
871177cd |
if(ret == CL_EOPEN) |
d6898042 |
cli_errmsg("cli_loaddb(): No supported database files found in %s\n", dirname);
return ret; |
e3aaff8e |
}
|
2accc66f |
int cl_load(const char *path, struct cl_engine *engine, unsigned int *signo, unsigned int dboptions) |
04933acd |
{ |
a2a004df |
STATBUF sb; |
f7470773 |
int ret; |
04933acd |
|
15850fc6 |
if(!engine) { |
724b2bf7 |
cli_errmsg("cl_load: engine == NULL\n");
return CL_ENULLARG;
} |
04933acd |
|
d7c3f6e2 |
if(engine->dboptions & CL_DB_COMPILED) {
cli_errmsg("cl_load(): can't load new databases when engine is already compiled\n");
return CL_EARG;
}
|
a2a004df |
if(STAT(path, &sb) == -1) { |
ac1b219c |
cli_errmsg("cl_load(): Can't get status of %s\n", path); |
871177cd |
return CL_ESTAT; |
04933acd |
}
|
2accc66f |
if((dboptions & CL_DB_PHISHING_URLS) && !engine->phishcheck && (engine->dconf->phishing & PHISHING_CONF_ENGINE)) |
15850fc6 |
if((ret = phishing_init(engine))) |
724b2bf7 |
return ret; |
f7470773 |
|
927d0548 |
if((dboptions & CL_DB_BYTECODE) && !engine->bcs.inited) {
if((ret = cli_bytecode_init(&engine->bcs))) |
52dd3a6b |
return ret;
} else {
cli_dbgmsg("Bytecode engine disabled\n");
}
|
6223810b |
if(cli_cache_init(engine))
return CL_EMEM;
|
d7c3f6e2 |
engine->dboptions |= dboptions; |
616bc3b9 |
|
f51e962f |
switch(sb.st_mode & S_IFMT) { |
52dd3a6b |
case S_IFREG: |
2accc66f |
ret = cli_load(path, engine, signo, dboptions, NULL); |
bc93eda0 |
break; |
04933acd |
case S_IFDIR: |
99ca7f53 |
ret = cli_loaddbdir(path, engine, signo, dboptions | CL_DB_DIRECTORY); |
bc93eda0 |
break; |
04933acd |
default: |
bc93eda0 |
cli_errmsg("cl_load(%s): Not supported database file type\n", path); |
04933acd |
return CL_EOPEN;
} |
bc93eda0 |
return ret; |
04933acd |
}
|
4048c4f6 |
const char *cl_retdbdir(void)
{
return DATADIR;
}
|
e3aaff8e |
int cl_statinidir(const char *dirname, struct cl_stat *dbstat)
{
DIR *dd; |
43f1a140 |
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) { |
b5134815 |
dbstat->entries = 0; |
e3aaff8e |
dbstat->stattab = NULL; |
75ccac9f |
dbstat->statdname = NULL; |
6f38c939 |
dbstat->dir = cli_strdup(dirname); |
e3aaff8e |
} 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); |
cd69cf20 |
cl_statfree(dbstat); |
e3aaff8e |
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 |
if(dent->d_ino)
{ |
3dad68eb |
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") && CLI_DBEXT(dent->d_name)) { |
b5134815 |
dbstat->entries++; |
a2a004df |
dbstat->stattab = (STATBUF *) cli_realloc2(dbstat->stattab, dbstat->entries * sizeof(STATBUF)); |
cd69cf20 |
if(!dbstat->stattab) {
cl_statfree(dbstat);
closedir(dd);
return CL_EMEM;
}
|
b2354dc1 |
#ifdef _WIN32 |
84fd5a61 |
dbstat->statdname = (char **) cli_realloc2(dbstat->statdname, dbstat->entries * sizeof(char *)); |
cd69cf20 |
if(!dbstat->statdname) { |
241e7eb1 |
cli_errmsg("cl_statinidir: Can't allocate memory for dbstat->statdname\n"); |
cd69cf20 |
cl_statfree(dbstat);
closedir(dd);
return CL_EMEM;
} |
75ccac9f |
#endif
|
0eacacec |
fname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 32); |
cd69cf20 |
if(!fname) { |
241e7eb1 |
cli_errmsg("cl_statinidir: Cant' allocate memory for fname\n"); |
cd69cf20 |
cl_statfree(dbstat);
closedir(dd);
return CL_EMEM;
} |
58481352 |
sprintf(fname, "%s"PATHSEP"%s", dirname, dent->d_name); |
b2354dc1 |
#ifdef _WIN32 |
0eacacec |
dbstat->statdname[dbstat->entries - 1] = (char *) cli_malloc(strlen(dent->d_name) + 1); |
cd69cf20 |
if(!dbstat->statdname[dbstat->entries - 1]) { |
241e7eb1 |
cli_errmsg("cli_statinidir: Can't allocate memory for dbstat->statdname\n"); |
cd69cf20 |
cl_statfree(dbstat);
closedir(dd);
return CL_EMEM;
}
|
b5134815 |
strcpy(dbstat->statdname[dbstat->entries - 1], dent->d_name); |
75ccac9f |
#endif |
a2a004df |
STAT(fname, &dbstat->stattab[dbstat->entries - 1]); |
e3aaff8e |
free(fname);
}
}
}
closedir(dd); |
8d3aca30 |
return CL_SUCCESS; |
e3aaff8e |
}
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 |
a2a004df |
STATBUF sb; |
53721687 |
unsigned int i, found; |
e3aaff8e |
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 |
if(dent->d_ino)
{ |
3dad68eb |
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") && CLI_DBEXT(dent->d_name)) { |
0eacacec |
fname = cli_malloc(strlen(dbstat->dir) + strlen(dent->d_name) + 32); |
cd69cf20 |
if(!fname) { |
241e7eb1 |
cli_errmsg("cl_statchkdir: can't allocate memory for fname\n"); |
cd69cf20 |
closedir(dd);
return CL_EMEM;
}
|
58481352 |
sprintf(fname, "%s"PATHSEP"%s", dbstat->dir, dent->d_name); |
a2a004df |
STAT(fname, &sb); |
e3aaff8e |
free(fname);
found = 0; |
b5134815 |
for(i = 0; i < dbstat->entries; i++) |
b2354dc1 |
#ifdef _WIN32 |
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); |
8d3aca30 |
return CL_SUCCESS; |
e3aaff8e |
}
int cl_statfree(struct cl_stat *dbstat)
{
if(dbstat) { |
75ccac9f |
|
b2354dc1 |
#ifdef _WIN32 |
75ccac9f |
int i;
|
cd69cf20 |
if(dbstat->statdname) {
for(i = 0; i < dbstat->entries; i++) {
if(dbstat->statdname[i])
free(dbstat->statdname[i]);
dbstat->statdname[i] = NULL;
}
free(dbstat->statdname);
dbstat->statdname = NULL; |
75ccac9f |
}
#endif
|
cd69cf20 |
if(dbstat->stattab) {
free(dbstat->stattab);
dbstat->stattab = NULL;
} |
b5134815 |
dbstat->entries = 0; |
cd69cf20 |
|
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;
}
|
8d3aca30 |
return CL_SUCCESS; |
e3aaff8e |
} |
f51e962f |
|
724b2bf7 |
int cl_engine_free(struct cl_engine *engine) |
f51e962f |
{ |
677fc4ba |
unsigned int i, j; |
f51e962f |
struct cli_matcher *root; |
c9c463fe |
|
f51e962f |
if(!engine) {
cli_errmsg("cl_free: engine == NULL\n"); |
724b2bf7 |
return CL_ENULLARG; |
f51e962f |
}
#ifdef CL_THREAD_SAFE
pthread_mutex_lock(&cli_ref_mutex);
#endif
|
04ba76d2 |
if(engine->refcount)
engine->refcount--;
|
f51e962f |
if(engine->refcount) {
#ifdef CL_THREAD_SAFE
pthread_mutex_unlock(&cli_ref_mutex);
#endif |
724b2bf7 |
return CL_SUCCESS; |
f51e962f |
}
#ifdef CL_THREAD_SAFE
pthread_mutex_unlock(&cli_ref_mutex);
#endif |
bc93eda0 |
if(engine->root) { |
4addba22 |
for(i = 0; i < CLI_MTARGETS; i++) { |
bc93eda0 |
if((root = engine->root[i])) { |
bedc58de |
if(!root->ac_only) |
bc93eda0 |
cli_bm_free(root); |
bedc58de |
cli_ac_free(root); |
677fc4ba |
if(root->ac_lsigtable) {
for(j = 0; j < root->ac_lsigs; j++) { |
47d40feb |
mpool_free(engine->mempool, root->ac_lsigtable[j]->logic); |
677fc4ba |
FREE_TDB(root->ac_lsigtable[j]->tdb); |
47d40feb |
mpool_free(engine->mempool, root->ac_lsigtable[j]); |
677fc4ba |
} |
47d40feb |
mpool_free(engine->mempool, root->ac_lsigtable); |
677fc4ba |
} |
47d40feb |
mpool_free(engine->mempool, root); |
bc93eda0 |
} |
f51e962f |
} |
47d40feb |
mpool_free(engine->mempool, engine->root); |
f51e962f |
}
|
3faa9783 |
if((root = engine->hm_hdb)) {
hm_free(root); |
47d40feb |
mpool_free(engine->mempool, root); |
f51e962f |
}
|
3faa9783 |
if((root = engine->hm_mdb)) {
hm_free(root); |
47d40feb |
mpool_free(engine->mempool, root); |
2f942502 |
}
|
3faa9783 |
if((root = engine->hm_fp)) {
hm_free(root); |
47d40feb |
mpool_free(engine->mempool, root); |
2b459819 |
}
|
f05aa165 |
crtmgr_free(&engine->cmgr);
|
55094a9c |
while(engine->cdb) {
struct cli_cdb *pt = engine->cdb;
engine->cdb = pt->next;
if(pt->name.re_magic)
cli_regfree(&pt->name);
mpool_free(engine->mempool, pt->res2);
mpool_free(engine->mempool, pt->virname);
mpool_free(engine->mempool, pt);
}
|
ace26bfe |
while(engine->dbinfo) {
struct cli_dbinfo *pt = engine->dbinfo;
engine->dbinfo = pt->next;
mpool_free(engine->mempool, pt->name);
mpool_free(engine->mempool, pt->hash); |
4f3997d6 |
if(pt->cvd)
cl_cvdfree(pt->cvd); |
ace26bfe |
mpool_free(engine->mempool, pt);
}
|
52dd3a6b |
if(engine->dconf->bytecode & BYTECODE_ENGINE_MASK) {
if (engine->bcs.all_bcs)
for(i=0;i<engine->bcs.count;i++)
cli_bytecode_destroy(&engine->bcs.all_bcs[i]);
cli_bytecode_done(&engine->bcs);
free(engine->bcs.all_bcs); |
ab636570 |
for (i=0;i<_BC_LAST_HOOK - _BC_START_HOOKS;i++) {
free (engine->hooks[i]);
} |
52dd3a6b |
} |
15850fc6 |
if(engine->dconf->phishing & PHISHING_CONF_ENGINE) |
692bda68 |
phishing_done(engine); |
bc93eda0 |
if(engine->dconf) |
47d40feb |
mpool_free(engine->mempool, engine->dconf); |
bc93eda0 |
|
b023c36d |
if(engine->pua_cats) |
47d40feb |
mpool_free(engine->mempool, engine->pua_cats); |
b023c36d |
|
cca29953 |
if(engine->iconcheck) {
struct icon_matcher *iconcheck = engine->iconcheck;
for(i=0; i<3; i++) {
if(iconcheck->icons[i]) { |
a2f709da |
for (j=0;j<iconcheck->icon_counts[i];j++) {
struct icomtr* metric = iconcheck->icons[i];
mpool_free(engine->mempool, metric[j].name);
} |
cca29953 |
mpool_free(engine->mempool, iconcheck->icons[i]);
} |
d1a0a37b |
} |
cca29953 |
if(iconcheck->group_names[0]) {
for(i=0; i<iconcheck->group_counts[0]; i++)
mpool_free(engine->mempool, iconcheck->group_names[0][i]);
mpool_free(engine->mempool, iconcheck->group_names[0]);
}
if(iconcheck->group_names[1]) {
for(i=0; i<iconcheck->group_counts[1]; i++)
mpool_free(engine->mempool, iconcheck->group_names[1][i]);
mpool_free(engine->mempool, iconcheck->group_names[1]);
}
mpool_free(engine->mempool, iconcheck);
} |
c318ce5b |
|
33068e09 |
if(engine->tmpdir) |
47d40feb |
mpool_free(engine->mempool, engine->tmpdir); |
33068e09 |
|
6223810b |
if(engine->cache)
cli_cache_destroy(engine);
|
0d9dbdef |
cli_ftfree(engine); |
04133ff9 |
if(engine->ignored) {
cli_bm_free(engine->ignored);
mpool_free(engine->mempool, engine->ignored);
}
|
0d9dbdef |
#ifdef USE_MPOOL |
47d40feb |
if(engine->mempool) mpool_destroy(engine->mempool); |
e21657df |
#endif |
f51e962f |
free(engine); |
724b2bf7 |
return CL_SUCCESS; |
f51e962f |
}
|
724b2bf7 |
int cl_engine_compile(struct cl_engine *engine) |
f51e962f |
{ |
7021b545 |
unsigned int i;
int ret; |
f51e962f |
struct cli_matcher *root;
|
7021b545 |
if(!engine)
return CL_ENULLARG;
if(!engine->ftypes) |
15850fc6 |
if((ret = cli_loadftm(NULL, engine, 0, 1, NULL))) |
7021b545 |
return ret; |
f51e962f |
|
4addba22 |
for(i = 0; i < CLI_MTARGETS; i++) {
if((root = engine->root[i])) {
if((ret = cli_ac_buildtrie(root)))
return ret; |
44712fcb |
cli_dbgmsg("Matcher[%u]: %s: AC sigs: %u (reloff: %u, absoff: %u) BM sigs: %u (reloff: %u, absoff: %u) maxpatlen %u %s\n", i, cli_mtargets[i].name, root->ac_patterns, root->ac_reloff_num, root->ac_absoff_num, root->bm_patterns, root->bm_reloff_num, root->bm_absoff_num, root->maxpatlen, root->ac_only ? "(ac_only mode)" : ""); |
4addba22 |
}
} |
0fcc8112 |
if(engine->hm_hdb)
hm_flush(engine->hm_hdb);
if(engine->hm_mdb)
hm_flush(engine->hm_mdb);
if(engine->hm_fp)
hm_flush(engine->hm_fp);
|
2e11bcdf |
if((ret = cli_build_regex_list(engine->whitelist_matcher))) {
return ret;
}
if((ret = cli_build_regex_list(engine->domainlist_matcher))) {
return ret;
} |
04133ff9 |
if(engine->ignored) {
cli_bm_free(engine->ignored);
mpool_free(engine->mempool, engine->ignored);
engine->ignored = NULL;
} |
02ce73de |
cli_dconf_print(engine->dconf); |
47d40feb |
mpool_flush(engine->mempool); |
02ce73de |
|
52dd3a6b |
/* Compile bytecode */ |
540fc128 |
if((ret = cli_bytecode_prepare2(engine, &engine->bcs, engine->dconf->bytecode))) { |
ab636570 |
cli_errmsg("Unable to compile/load bytecode: %s\n", cl_strerror(ret)); |
52dd3a6b |
return ret;
}
|
b3df93db |
engine->dboptions |= CL_DB_COMPILED; |
8d3aca30 |
return CL_SUCCESS; |
f51e962f |
}
|
b8fe70b3 |
int cl_engine_addref(struct cl_engine *engine) |
f51e962f |
{
if(!engine) { |
b8fe70b3 |
cli_errmsg("cl_engine_addref: engine == NULL\n");
return CL_ENULLARG; |
f51e962f |
}
#ifdef CL_THREAD_SAFE
pthread_mutex_lock(&cli_ref_mutex);
#endif
engine->refcount++;
#ifdef CL_THREAD_SAFE
pthread_mutex_unlock(&cli_ref_mutex);
#endif
|
b8fe70b3 |
return CL_SUCCESS; |
f51e962f |
} |
d46cdd59 |
static int countentries(const char *dbname, unsigned int *sigs)
{
char buffer[CLI_DEFAULT_LSIG_BUFSIZE + 1];
FILE *fs;
unsigned int entry = 0;
fs = fopen(dbname, "r");
if(!fs) {
cli_errmsg("countentries: Can't open file %s\n", dbname);
return CL_EOPEN;
}
while(fgets(buffer, sizeof(buffer), fs)) {
if(buffer[0] == '#')
continue;
entry++;
}
fclose(fs);
*sigs += entry;
return CL_SUCCESS;
}
static int countsigs(const char *dbname, unsigned int options, unsigned int *sigs)
{
if((cli_strbcasestr(dbname, ".cvd") || cli_strbcasestr(dbname, ".cld"))) {
if(options & CL_COUNTSIGS_OFFICIAL) {
struct cl_cvd *cvd = cl_cvdhead(dbname);
if(!cvd) {
cli_errmsg("countsigs: Can't parse %s\n", dbname);
return CL_ECVD;
}
*sigs += cvd->sigs;
cl_cvdfree(cvd);
}
} else if(cli_strbcasestr(dbname, ".cbc")) {
if(options & CL_COUNTSIGS_UNOFFICIAL)
(*sigs)++;
|
b0357255 |
} else if(cli_strbcasestr(dbname, ".wdb") || cli_strbcasestr(dbname, ".fp") || cli_strbcasestr(dbname, ".ftm") || cli_strbcasestr(dbname, ".cfg") || cli_strbcasestr(dbname, ".cat")) { |
d46cdd59 |
/* ignore */
} else if((options & CL_COUNTSIGS_UNOFFICIAL) && CLI_DBEXT(dbname)) {
return countentries(dbname, sigs);
}
return CL_SUCCESS;
}
int cl_countsigs(const char *path, unsigned int countoptions, unsigned int *sigs)
{ |
a2a004df |
STATBUF sb; |
d46cdd59 |
char fname[1024];
struct dirent *dent;
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
union {
struct dirent d;
char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
} result;
#endif
DIR *dd;
int ret;
if(!sigs)
return CL_ENULLARG;
|
a2a004df |
if(STAT(path, &sb) == -1) { |
d46cdd59 |
cli_errmsg("cl_countsigs: Can't stat %s\n", path);
return CL_ESTAT;
}
if((sb.st_mode & S_IFMT) == S_IFREG) {
return countsigs(path, countoptions, sigs);
} else if((sb.st_mode & S_IFMT) == S_IFDIR) {
if((dd = opendir(path)) == NULL) {
cli_errmsg("cl_countsigs: Can't open directory %s\n", path);
return CL_EOPEN;
}
#ifdef HAVE_READDIR_R_3
while(!readdir_r(dd, &result.d, &dent) && dent) {
#elif defined(HAVE_READDIR_R_2)
while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
#else
while((dent = readdir(dd))) {
#endif
if(dent->d_ino) {
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") && CLI_DBEXT(dent->d_name)) {
snprintf(fname, sizeof(fname), "%s"PATHSEP"%s", path, dent->d_name);
fname[sizeof(fname) - 1] = 0;
ret = countsigs(fname, countoptions, sigs);
if(ret != CL_SUCCESS) {
closedir(dd);
return ret;
}
}
}
}
closedir(dd);
} else {
cli_errmsg("cl_countsigs: Unsupported file type\n");
return CL_EARG;
}
return CL_SUCCESS;
} |