e3aaff8e |
/* |
e1cbc270 |
* Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
14e2247b |
* Copyright (C) 2007-2013 Sourcefire, Inc. |
e1cbc270 |
* Copyright (C) 2002-2007 Tomasz Kojm <tkojm@clamav.net> |
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> |
b289385d |
#include <stdint.h> |
e3aaff8e |
#include <stdlib.h>
#include <string.h>
#include <ctype.h> |
288057e9 |
#ifdef HAVE_UNISTD_H |
e3aaff8e |
#include <unistd.h> |
b58fdfc2 |
#endif |
e3aaff8e |
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h> |
288057e9 |
#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" |
288057e9 |
#ifdef HAVE_STRINGS_H |
b58fdfc2 |
#include <strings.h>
#endif |
8000d078 |
#include "matcher-ac.h"
#include "matcher-bm.h" |
6f594861 |
#include "matcher-pcre.h" |
9cb3e8eb |
#include "matcher-byte-comp.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" |
4367454d |
#include "default.h" |
de351ee1 |
#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 |
|
b94e66c4 |
#include "mpool.h" |
52dd3a6b |
#include "bytecode.h" |
ab636570 |
#include "bytecode_api.h" |
52dd3a6b |
#include "bytecode_priv.h" |
261e29da |
#include "cache.h" |
2abe7362 |
#include "openioc.h" |
baeb6253 |
|
f51e962f |
#ifdef CL_THREAD_SAFE |
288057e9 |
#include <pthread.h> |
f51e962f |
static pthread_mutex_t cli_ref_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif |
baeb6253 |
#ifdef HAVE_YARA |
186d22d1 |
#include "yara_clam.h" |
5842265f |
#include "yara_compiler.h" |
b289385d |
#include "yara_grammar.h"
#include "yara_lexer.h" |
baeb6253 |
#endif |
bc3a2c0f |
|
b9af0434 |
#define MAX_LDB_SUBSIGS 64
|
86eddf11 |
char *cli_virname(const char *virname, unsigned int official) |
b5513f8d |
{ |
288057e9 |
char *newname, *pt; |
b5513f8d |
|
288057e9 |
if (!virname)
return NULL; |
b5513f8d |
|
288057e9 |
if ((pt = strstr(virname, " (Clam)")))
*pt = '\0'; |
b5513f8d |
|
288057e9 |
if (!virname[0]) {
cli_errmsg("cli_virname: Empty virus name\n");
return NULL; |
b5513f8d |
}
|
288057e9 |
if (official) |
d6e1ef16 |
return cli_strdup(virname); |
b5513f8d |
|
288057e9 |
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 |
}
|
102cd430 |
cl_error_t cli_sigopts_handler(struct cli_matcher *root, const char *virname, const char *hexsig, uint8_t sigopts, uint16_t rtype, uint16_t type, const char *offset, uint8_t target, const uint32_t *lsigid, unsigned int options) |
8ea34681 |
{ |
9cb3e8eb |
char *hexcpy, *start, *end, *mid; |
d0cba11e |
unsigned int i;
int ret = CL_SUCCESS; |
8ea34681 |
|
5d9cac7b |
/* |
c31a98d5 |
* cyclic loops with cli_parse_add are impossible now as cli_parse_add |
b2197a09 |
* no longer calls cli_sigopts_handler; leaving here for safety |
a1482b98 |
*/ |
6dea5b04 |
if (sigopts & ACPATT_OPTION_ONCE) { |
b2197a09 |
cli_errmsg("cli_sigopts_handler: invalidly called multiple times!\n"); |
6dea5b04 |
return CL_EPARSE;
}
hexcpy = cli_strdup(hexsig);
if (!hexcpy)
return CL_EMEM; |
8ea34681 |
|
6dea5b04 |
sigopts |= ACPATT_OPTION_ONCE; |
8ea34681 |
|
6dea5b04 |
/* REGEX testing and sigopt handling */
start = strchr(hexcpy, '/'); |
288057e9 |
end = strrchr(hexcpy, '/'); |
6dea5b04 |
if (start != end) {
/* FULLWORD regex sigopt handling */ |
8ea34681 |
if (sigopts & ACPATT_OPTION_FULLWORD) { |
288057e9 |
size_t ovrlen = strlen(hexcpy) + 21;
char *hexovr = cli_calloc(ovrlen, sizeof(char)); |
13a232b5 |
if (!hexovr) {
free(hexcpy); |
8ea34681 |
return CL_EMEM; |
13a232b5 |
} |
8ea34681 |
|
6dea5b04 |
*start++ = '\0'; |
288057e9 |
*end++ = '\0'; |
8ea34681 |
|
16ec6d8d |
snprintf(hexovr, ovrlen, "%s/([\\W_]|\\A)%s([\\W_]|\\Z)/%s", hexcpy, start, end); |
8ea34681 |
free(hexcpy);
hexcpy = hexovr;
} |
6dea5b04 |
/* NOCASE sigopt is passed onto the regex-opt handler */
if (sigopts & ACPATT_OPTION_NOCASE) { |
288057e9 |
size_t ovrlen = strlen(hexcpy) + 2;
char *hexovr = cli_calloc(ovrlen, sizeof(char)); |
13a232b5 |
if (!hexovr) {
free(hexcpy); |
8ea34681 |
return CL_EMEM; |
13a232b5 |
} |
8ea34681 |
|
6dea5b04 |
snprintf(hexovr, ovrlen, "%si", hexcpy); |
8ea34681 |
|
6dea5b04 |
free(hexcpy);
hexcpy = hexovr;
}
/* WIDE sigopt is unsupported */
if (sigopts & ACPATT_OPTION_WIDE) {
cli_errmsg("cli_parse_add: wide modifier [w] is not supported for regex subsigs\n"); |
9c9b52f8 |
free(hexcpy); |
6dea5b04 |
return CL_EMALFDB;
} |
8ea34681 |
|
6dea5b04 |
ret = cli_parse_add(root, virname, hexcpy, sigopts, rtype, type, offset, target, lsigid, options);
free(hexcpy);
return ret;
} |
8ea34681 |
|
9cb3e8eb |
/* BCOMP sigopt handling */
start = strchr(hexcpy, '#'); |
288057e9 |
end = strrchr(hexcpy, '#');
mid = strchr(hexcpy, '('); |
9cb3e8eb |
|
288057e9 |
if (start != end && mid && (*(++mid) == '#' || !strncmp(mid, ">>", 2) || !strncmp(mid, "<<", 2) || !strncmp(mid, "0#", 2))) { |
9cb3e8eb |
/* TODO byte compare currently does not have support for sigopts, pass through */
ret = cli_parse_add(root, virname, hexcpy, sigopts, rtype, type, offset, target, lsigid, options);
free(hexcpy);
return ret;
}
|
6dea5b04 |
/* NORMAL HEXSIG sigopt handling */
/* FULLWORD sigopt handling - only happens once */
if (sigopts & ACPATT_OPTION_FULLWORD) {
char *rechar; |
288057e9 |
size_t ovrlen = strlen(hexcpy) + 7;
char *hexovr = cli_calloc(ovrlen, sizeof(char)); |
6dea5b04 |
if (!hexovr) {
free(hexcpy);
return CL_EMEM;
}
snprintf(hexovr, ovrlen, "(W)%s(W)", hexcpy);
/* change the '[' and ']' to '{' and '}' since there are now two bytes */
rechar = hexovr;
while ((rechar = strchr(rechar, '['))) { //TEST TODO
*rechar = '{';
if (!(rechar = strchr(rechar, ']'))) {
cli_errmsg("cli_parse_add: unmatched '[' in signature %s\n", virname); |
8ea34681 |
free(hexcpy); |
6dea5b04 |
free(hexovr);
return CL_EMALFDB; |
8ea34681 |
} |
6dea5b04 |
*rechar = '}'; |
8ea34681 |
} |
a1482b98 |
free(hexcpy); |
6dea5b04 |
hexcpy = hexovr;
}
/* WIDE sigopt handling - only happens once (after fullword)
* TODO - consider handling in cli_ac_addpatt? (two pattern possibility)
*/
if (sigopts & ACPATT_OPTION_WIDE) { |
288057e9 |
size_t ovrlen = 2 * strlen(hexcpy) + 1;
char *hexovr = cli_calloc(ovrlen, sizeof(char)); |
6dea5b04 |
if (!hexovr) {
free(hexcpy);
return CL_EMEM;
}
/* clamav-specific wildcards need to be handled here! */
for (i = 0; i < strlen(hexcpy); ++i) { |
288057e9 |
size_t len = strlen(hexovr); |
6dea5b04 |
if (hexcpy[i] == '*' || hexcpy[i] == '|' || hexcpy[i] == ')') {
hexovr[len] = hexcpy[i];
} else if (hexcpy[i] == '[') {
/* change the '[' and ']' to '{' and '}' since there are now two bytes */
hexovr[len++] = '{';
++i;
while (i < strlen(hexcpy) && hexcpy[i] != ']')
hexovr[len++] = hexcpy[i++];
hexovr[len] = '}';
} else if (hexcpy[i] == '{') {
while (i < strlen(hexcpy) && hexcpy[i] != '}')
hexovr[len++] = hexcpy[i++];
hexovr[len] = '}';
} else if (hexcpy[i] == '!' || hexcpy[i] == '(') {
if (hexcpy[i] == '!')
hexovr[len++] = hexcpy[i++];
/* copies '(' */
hexovr[len] = hexcpy[i];
|
288057e9 |
if (hexcpy[i + 1] == 'B' || hexcpy[i + 1] == 'L' || hexcpy[i + 1] == 'W') {
++len;
++i; |
6dea5b04 |
hexovr[len++] = hexcpy[i++];
if (hexcpy[i] != ')') {
free(hexcpy);
free(hexovr);
return CL_EMALFDB;
}
hexovr[len] = hexcpy[i];
}
} else {
//snprintf(hexovr+len, ovrlen-len, "%02x%c%c", 0, hexcpy[i], hexcpy[i+1]); |
288057e9 |
snprintf(hexovr + len, ovrlen - len, "%c%c%02x", hexcpy[i], hexcpy[i + 1], 0); |
6dea5b04 |
++i;
}
}
/* NOCASE sigopt is handled in cli_ac_addsig */
ret = cli_parse_add(root, virname, hexovr, sigopts, rtype, type, offset, target, lsigid, options);
free(hexovr);
if (ret != CL_SUCCESS || !(sigopts & ACPATT_OPTION_ASCII)) {
free(hexcpy);
return ret;
} else {
/* disable wide sigopt for ascii variant */
sigopts &= ~ACPATT_OPTION_WIDE;
} |
8ea34681 |
}
|
6dea5b04 |
/* ASCII sigopt; NOCASE sigopt is handled in cli_ac_addsig */
ret = cli_parse_add(root, virname, hexcpy, sigopts, rtype, type, offset, target, lsigid, options);
free(hexcpy);
return ret; |
8ea34681 |
}
|
5843ac79 |
#define PCRE_TOKENS 4 |
102cd430 |
cl_error_t cli_parse_add(struct cli_matcher *root, const char *virname, const char *hexsig, uint8_t sigopts, uint16_t rtype, uint16_t type, const char *offset, uint8_t target, const uint32_t *lsigid, unsigned int options) |
888f5794 |
{ |
2b543108 |
struct cli_bm_patt *bm_new; |
9cb3e8eb |
char *pt, *hexcpy, *start = NULL, *mid = NULL, *end = NULL, *n, l, r; |
2b543108 |
const char *wild;
int ret, asterisk = 0, range; |
2ade8f42 |
unsigned int i, j, hexlen, nest, parts = 0; |
2b543108 |
int mindist = 0, maxdist = 0, error = 0; |
084ee140 |
|
33872a43 |
hexlen = strlen(hexsig); |
ab893605 |
if (hexsig[0] == '$') { |
2b543108 |
/* macro */ |
448a6672 |
unsigned int smin, smax, tid; |
2b543108 |
struct cli_ac_patt *patt;
|
288057e9 |
if (hexsig[hexlen - 1] != '$') { |
2b543108 |
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;
}
|
288057e9 |
if (sscanf(hexsig, "${%u-%u}%u$", &smin, &smax, &tid) != 3) { |
2b543108 |
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;
}
|
544fa973 |
patt = MPOOL_CALLOC(root->mempool, 1, sizeof(*patt)); |
2b543108 |
if (!patt)
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 */
patt->ch_mindist[0] = smin;
patt->ch_maxdist[0] = smax; |
288057e9 |
patt->sigid = tid;
patt->length[0] = root->ac_mindepth; |
2b543108 |
/* dummy */ |
544fa973 |
patt->pattern = MPOOL_CALLOC(root->mempool, patt->length[0], sizeof(*patt->pattern)); |
2b543108 |
if (!patt->pattern) {
free(patt);
return CL_EMEM;
}
if ((ret = cli_ac_addpatt(root, patt))) { |
544fa973 |
MPOOL_FREE(root->mempool, patt->pattern); |
2b543108 |
free(patt);
return ret;
}
|
448a6672 |
return CL_SUCCESS; |
ab893605 |
} |
09942544 |
/* expected format => ^offset:trigger/regex/[cflags]$ */ |
e15ebb76 |
if (strchr(hexsig, '/')) { |
5d9cac7b |
char *start, *end; |
09942544 |
const char *trigger, *pattern, *cflags; |
448a6672 |
|
5843ac79 |
/* get copied */ |
a98b86c3 |
hexcpy = cli_strdup(hexsig); |
288057e9 |
if (!hexcpy) |
35a05ff8 |
return CL_EMEM;
|
15464f6c |
/* get delimiters-ed */
start = strchr(hexcpy, '/'); |
288057e9 |
end = strrchr(hexcpy, '/'); |
39597f25 |
|
a02acd50 |
/* get pcre-ed */ |
5d9cac7b |
if (start == end) {
cli_errmsg("cli_parseadd(): PCRE subsig mismatched '/' delimiter\n"); |
214d750e |
free(hexcpy); |
5d9cac7b |
return CL_EMALFDB;
} |
a02acd50 |
#if HAVE_PCRE |
5d9cac7b |
/* get checked */
if (hexsig[0] == '/') {
cli_errmsg("cli_parseadd(): PCRE subsig must contain logical trigger\n"); |
214d750e |
free(hexcpy); |
5d9cac7b |
return CL_EMALFDB;
} |
15464f6c |
|
5d9cac7b |
/* get NULL-ed */
*start = '\0'; |
288057e9 |
*end = '\0'; |
a02acd50 |
|
5d9cac7b |
/* get tokens-ed */
trigger = hexcpy; |
288057e9 |
pattern = start + 1;
cflags = end + 1; |
5d9cac7b |
if (*cflags == '\0') /* get compat-ed */
cflags = NULL; |
a02acd50 |
|
5d9cac7b |
/* normal trigger, get added */
ret = cli_pcre_addpatt(root, virname, trigger, pattern, cflags, offset, lsigid, options);
free(hexcpy);
return ret; |
7afaa9bd |
#else |
5d9cac7b |
free(hexcpy);
cli_errmsg("cli_parseadd(): cannot parse PCRE subsig without PCRE support\n");
return CL_EPARSE; |
7afaa9bd |
#endif |
288057e9 |
} else if ((wild = strchr(hexsig, '{'))) {
if (sscanf(wild, "%c%u%c", &l, &range, &r) == 3 && l == '{' && r == '}' && range > 0 && range < 128) { |
2b543108 |
hexcpy = cli_calloc(hexlen + 2 * range, sizeof(char)); |
288057e9 |
if (!hexcpy) |
2b543108 |
return CL_EMEM; |
888f5794 |
|
2b543108 |
strncpy(hexcpy, hexsig, wild - hexsig); |
288057e9 |
for (i = 0; i < (unsigned int)range; i++) |
2b543108 |
strcat(hexcpy, "??"); |
084ee140 |
|
288057e9 |
if (!(wild = strchr(wild, '}'))) { |
2b543108 |
cli_errmsg("cli_parse_add(): Problem adding signature: missing bracket\n");
free(hexcpy);
return CL_EMALFDB;
} |
084ee140 |
|
2b543108 |
strcat(hexcpy, ++wild); |
a02acd50 |
ret = cli_parse_add(root, virname, hexcpy, sigopts, rtype, type, offset, target, lsigid, options); |
2b543108 |
free(hexcpy); |
084ee140 |
|
2b543108 |
return ret;
} |
084ee140 |
|
2b543108 |
root->ac_partsigs++; |
084ee140 |
|
288057e9 |
if (!(hexcpy = cli_strdup(hexsig))) |
2b543108 |
return CL_EMEM; |
084ee140 |
|
2ade8f42 |
nest = 0; |
288057e9 |
for (i = 0; i < hexlen; i++) {
if (hexsig[i] == '(') |
2ade8f42 |
nest++; |
288057e9 |
else if (hexsig[i] == ')') |
2ade8f42 |
nest--; |
288057e9 |
else if (hexsig[i] == '{') { |
2ade8f42 |
if (nest) {
cli_errmsg("cli_parse_add(): Alternative match contains unsupported ranged wildcard\n"); |
004eadf6 |
free(hexcpy); |
2ade8f42 |
return CL_EMALFDB;
}
parts++; |
288057e9 |
} else if (hexsig[i] == '*') { |
2ade8f42 |
if (nest) {
cli_errmsg("cli_parse_add(): Alternative match cannot contain unbounded wildcards\n"); |
004eadf6 |
free(hexcpy); |
2ade8f42 |
return CL_EMALFDB;
} |
2b543108 |
parts++; |
2ade8f42 |
}
} |
2b543108 |
|
288057e9 |
if (parts) |
2b543108 |
parts++;
start = pt = hexcpy; |
288057e9 |
for (i = 1; i <= parts; i++) {
if (i != parts) {
for (j = 0; j < strlen(start); j++) {
if (start[j] == '{') { |
2b543108 |
asterisk = 0; |
288057e9 |
pt = start + j; |
2b543108 |
break;
}
|
288057e9 |
if (start[j] == '*') { |
2b543108 |
asterisk = 1; |
288057e9 |
pt = start + j; |
2b543108 |
break;
}
} |
084ee140 |
|
2b543108 |
*pt++ = 0;
} |
084ee140 |
|
288057e9 |
if ((ret = cli_ac_addsig(root, virname, start, sigopts, root->ac_partsigs, parts, i, rtype, type, mindist, maxdist, offset, lsigid, options))) { |
2b543108 |
cli_errmsg("cli_parse_add(): Problem adding signature (1).\n");
error = 1;
break;
} |
a8f79297 |
|
288057e9 |
if (i == parts) |
2b543108 |
break; |
a8f79297 |
|
2b543108 |
mindist = maxdist = 0; |
084ee140 |
|
288057e9 |
if (asterisk) { |
2b543108 |
start = pt;
continue;
} |
084ee140 |
|
288057e9 |
if (!(start = strchr(pt, '}'))) { |
2b543108 |
error = 1;
break;
} |
084ee140 |
|
2b543108 |
*start++ = 0; |
a3fe2c5b |
|
288057e9 |
if (!pt) { |
2b543108 |
error = 1;
break;
} |
084ee140 |
|
288057e9 |
if (!strchr(pt, '-')) {
if (!cli_isnumber(pt) || (mindist = maxdist = atoi(pt)) < 0) { |
2b543108 |
error = 1;
break;
}
} else { |
288057e9 |
if ((n = cli_strtok(pt, 0, "-"))) {
if (!cli_isnumber(n) || (mindist = atoi(n)) < 0) { |
2b543108 |
error = 1;
free(n);
break;
}
free(n);
} |
084ee140 |
|
288057e9 |
if ((n = cli_strtok(pt, 1, "-"))) {
if (!cli_isnumber(n) || (maxdist = atoi(n)) < 0) { |
2b543108 |
error = 1;
free(n);
break;
} |
888f5794 |
|
2b543108 |
free(n);
} |
888f5794 |
|
288057e9 |
if ((n = cli_strtok(pt, 2, "-"))) { /* strict check */ |
2b543108 |
error = 1;
free(n);
break;
}
}
} |
888f5794 |
|
2b543108 |
free(hexcpy); |
288057e9 |
if (error) { |
2b543108 |
cli_errmsg("cli_parseadd(): Problem adding signature (1b).\n");
return CL_EMALFDB;
} |
288057e9 |
} else if (strchr(hexsig, '*')) { |
2b543108 |
root->ac_partsigs++; |
888f5794 |
|
2ade8f42 |
nest = 0; |
288057e9 |
for (i = 0; i < hexlen; i++) {
if (hexsig[i] == '(') |
2ade8f42 |
nest++; |
288057e9 |
else if (hexsig[i] == ')') |
2ade8f42 |
nest--; |
288057e9 |
else if (hexsig[i] == '*') { |
2ade8f42 |
if (nest) {
cli_errmsg("cli_parse_add(): Alternative match cannot contain unbounded wildcards\n");
return CL_EMALFDB;
} |
2b543108 |
parts++; |
2ade8f42 |
}
} |
888f5794 |
|
288057e9 |
if (parts) |
2b543108 |
parts++; |
888f5794 |
|
288057e9 |
for (i = 1; i <= parts; i++) {
if ((pt = cli_strtok(hexsig, i - 1, "*")) == NULL) { |
2ade8f42 |
cli_errmsg("cli_parse_add():Can't extract part %d of partial signature.\n", i); |
2b543108 |
return CL_EMALFDB;
} |
8000d078 |
|
288057e9 |
if ((ret = cli_ac_addsig(root, virname, pt, sigopts, root->ac_partsigs, parts, i, rtype, type, 0, 0, offset, lsigid, options))) { |
2b543108 |
cli_errmsg("cli_parse_add(): Problem adding signature (2).\n");
free(pt);
return ret;
}
free(pt);
} |
288057e9 |
} else if ((start = strchr(hexsig, '(')) && (mid = strchr(hexsig, '#')) && (end = strrchr(hexsig, '#')) && mid != end) { |
9cb3e8eb |
/* format seems to match byte_compare */ |
102cd430 |
if (CL_SUCCESS != (ret = cli_bcomp_addpatt(root, virname, hexsig, lsigid, options))) { |
9cb3e8eb |
cli_errmsg("cli_parse_add(): Problem adding signature (2b).\n");
return ret;
}
|
288057e9 |
} else if (root->ac_only || type || lsigid || sigopts || strpbrk(hexsig, "?([") || (root->bm_offmode && (!strcmp(offset, "*") || strchr(offset, ','))) || strstr(offset, "VI") || strchr(offset, '$')) { |
102cd430 |
if (CL_SUCCESS != (ret = cli_ac_addsig(root, virname, hexsig, sigopts, 0, 0, 0, rtype, type, 0, 0, offset, lsigid, options))) { |
ac09aa7d |
cli_errmsg("cli_parse_add(): Problem adding signature (3).\n"); |
2b543108 |
return ret;
} |
8000d078 |
} else { |
544fa973 |
bm_new = (struct cli_bm_patt *)MPOOL_CALLOC(root->mempool, 1, sizeof(struct cli_bm_patt)); |
288057e9 |
if (!bm_new) |
2b543108 |
return CL_EMEM;
|
544fa973 |
bm_new->pattern = (unsigned char *)CLI_MPOOL_HEX2STR(root->mempool, hexsig); |
288057e9 |
if (!bm_new->pattern) { |
544fa973 |
MPOOL_FREE(root->mempool, bm_new); |
2b543108 |
return CL_EMALFDB;
} |
8000d078 |
|
2b543108 |
bm_new->length = hexlen / 2; |
8000d078 |
|
544fa973 |
bm_new->virname = CLI_MPOOL_VIRNAME(root->mempool, virname, options & CL_DB_OFFICIAL); |
288057e9 |
if (!bm_new->virname) { |
544fa973 |
MPOOL_FREE(root->mempool, bm_new->pattern);
MPOOL_FREE(root->mempool, bm_new); |
2b543108 |
return CL_EMEM;
} |
8000d078 |
|
288057e9 |
if (bm_new->length > root->maxpatlen) |
2b543108 |
root->maxpatlen = bm_new->length;
|
102cd430 |
if (CL_SUCCESS != (ret = cli_bm_addpatt(root, bm_new, offset))) { |
2b543108 |
cli_errmsg("cli_parse_add(): Problem adding signature (4).\n"); |
544fa973 |
MPOOL_FREE(root->mempool, bm_new->pattern);
MPOOL_FREE(root->mempool, bm_new->virname);
MPOOL_FREE(root->mempool, bm_new); |
2b543108 |
return ret;
} |
888f5794 |
}
|
8d3aca30 |
return CL_SUCCESS; |
888f5794 |
} |
e3aaff8e |
|
102cd430 |
cl_error_t cli_initroots(struct cl_engine *engine, unsigned int options) |
5612732c |
{ |
288057e9 |
int i, ret;
struct cli_matcher *root; |
5612732c |
|
cd94be7a |
UNUSEDPARAM(options); |
5612732c |
|
288057e9 |
for (i = 0; i < CLI_MTARGETS; i++) {
if (!engine->root[i]) {
cli_dbgmsg("Initializing engine->root[%d]\n", i); |
544fa973 |
root = engine->root[i] = (struct cli_matcher *)MPOOL_CALLOC(engine->mempool, 1, sizeof(struct cli_matcher)); |
288057e9 |
if (!root) {
cli_errmsg("cli_initroots: Can't allocate memory for cli_matcher\n");
return CL_EMEM;
} |
33872a43 |
#ifdef USE_MPOOL |
288057e9 |
root->mempool = engine->mempool; |
33872a43 |
#endif |
288057e9 |
root->type = i;
if (cli_mtargets[i].ac_only || engine->ac_only)
root->ac_only = 1;
cli_dbgmsg("Initializing AC pattern matcher of root[%d]\n", i); |
102cd430 |
if (CL_SUCCESS != (ret = cli_ac_init(root, engine->ac_mindepth, engine->ac_maxdepth, engine->dconf->other & OTHER_CONF_PREFILTERING))) { |
288057e9 |
/* no need to free previously allocated memory here */
cli_errmsg("cli_initroots: Can't initialise AC pattern matcher\n");
return ret;
}
if (!root->ac_only) {
cli_dbgmsg("cli_initroots: Initializing BM tables of root[%d]\n", i); |
102cd430 |
if (CL_SUCCESS != (ret = cli_bm_init(root))) { |
288057e9 |
cli_errmsg("cli_initroots: Can't initialise BM pattern matcher\n");
return ret;
}
}
} |
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 |
{ |
288057e9 |
if (fs)
return fgets(buff, size, fs);
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)) {
cli_errmsg("cli_dbgets: fread() failed\n");
return NULL;
}
}
if (!bread)
return NULL;
dbio->readpt[bread] = 0;
dbio->bufpt = dbio->buf;
dbio->size -= bread;
dbio->bread += bread;
if (dbio->hashctx)
cl_update_hash(dbio->hashctx, dbio->readpt, bread);
}
if (dbio->chkonly && dbio->bufpt) {
dbio->bufpt = NULL;
dbio->readsize = dbio->size < dbio->bufsize ? dbio->size : dbio->bufsize - 1;
continue;
}
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;
}
} |
a6a98456 |
} else { /* use gzgets/fgets */ |
288057e9 |
char *pt;
unsigned int bs;
if (!dbio->size)
return NULL;
bs = dbio->size < size ? dbio->size + 1 : size;
if (dbio->gzs)
pt = gzgets(dbio->gzs, buff, bs);
else
pt = fgets(buff, bs, dbio->fs);
if (!pt) {
cli_errmsg("cli_dbgets: Preliminary end of data\n");
return pt;
}
bs = strlen(buff);
dbio->size -= bs;
dbio->bread += bs;
if (dbio->hashctx)
cl_update_hash(dbio->hashctx, buff, bs);
return pt; |
056d95dc |
}
}
|
5989b715 |
static char *cli_signorm(const char *signame)
{
char *new_signame = NULL; |
288057e9 |
size_t pad = 0; |
5989b715 |
size_t nsz; |
5f86ff20 |
|
5989b715 |
if (!signame)
return NULL; |
a0fb6419 |
|
5989b715 |
nsz = strlen(signame); |
5f86ff20 |
|
288057e9 |
if (nsz > 3 && signame[nsz - 1] == '}') { |
b2f59861 |
char *pt = strstr(signame, ".{"); |
288057e9 |
if (pt) /* strip the ".{ }" clause at the end of signame */ |
b2f59861 |
nsz = pt - signame;
else
return NULL;
} else if (nsz > 11) { |
288057e9 |
if (!strncmp(signame + nsz - 11, ".UNOFFICIAL", 11)) |
5989b715 |
nsz -= 11;
else
return NULL;
} else if (nsz > 2)
return NULL; |
288057e9 |
|
5989b715 |
if (nsz < 3) {
pad = 3 - nsz;
nsz = 3;
} |
5f86ff20 |
|
68f41bb8 |
new_signame = cli_calloc((nsz + 1), sizeof(char)); |
288057e9 |
if (!new_signame) |
5989b715 |
return NULL; |
5f86ff20 |
|
288057e9 |
memcpy(new_signame, signame, nsz - pad); |
5989b715 |
new_signame[nsz] = '\0'; |
a0fb6419 |
|
5989b715 |
while (pad > 0) |
288057e9 |
new_signame[nsz - pad--] = '\x20'; |
5989b715 |
return new_signame; |
5f86ff20 |
}
|
04133ff9 |
static int cli_chkign(const struct cli_matcher *ignored, const char *signame, const char *entry) |
ed9753e9 |
{ |
5f86ff20 |
|
b2e7c931 |
const char *md5_expected = NULL; |
5989b715 |
char *norm_signame; |
b2e7c931 |
unsigned char digest[16]; |
5989b715 |
int ret = 0; |
ed9753e9 |
|
288057e9 |
if (!ignored || !signame || !entry) |
b2e7c931 |
return 0; |
ed9753e9 |
|
5989b715 |
norm_signame = cli_signorm(signame);
if (norm_signame != NULL) |
288057e9 |
signame = norm_signame; |
5f86ff20 |
|
288057e9 |
if (cli_bm_scanbuff((const unsigned char *)signame, strlen(signame), &md5_expected, NULL, ignored, 0, NULL, NULL, NULL) == CL_VIRUS) |
5989b715 |
do { |
288057e9 |
if (md5_expected) { |
5989b715 |
cl_hash_data("md5", entry, strlen(entry), digest, NULL); |
288057e9 |
if (memcmp(digest, (const unsigned char *)md5_expected, 16)) |
5989b715 |
break;
} |
288057e9 |
|
5989b715 |
cli_dbgmsg("Ignoring signature %s\n", signame);
ret = 1;
} while (0); |
ed9753e9 |
|
5989b715 |
if (norm_signame) |
288057e9 |
free(norm_signame); |
5989b715 |
return ret; |
ed9753e9 |
}
|
b023c36d |
static int cli_chkpua(const char *signame, const char *pua_cats, unsigned int options)
{ |
288057e9 |
char cat[32], *pt;
const char *sig;
int ret; |
b023c36d |
|
288057e9 |
if (strncmp(signame, "PUA.", 4)) {
cli_dbgmsg("Skipping signature %s - no PUA prefix\n", signame);
return 1; |
b023c36d |
}
sig = signame + 3; |
288057e9 |
if (!(pt = strchr(sig + 1, '.'))) {
cli_dbgmsg("Skipping signature %s - bad syntax\n", signame);
return 1; |
b023c36d |
}
|
288057e9 |
if ((unsigned int)(pt - sig + 2) > sizeof(cat)) {
cli_dbgmsg("Skipping signature %s - too long category name\n", signame);
return 1; |
b023c36d |
}
strncpy(cat, sig, pt - signame + 1);
cat[pt - sig + 1] = 0; |
288057e9 |
pt = strstr(pua_cats, cat); |
b023c36d |
|
288057e9 |
if (options & CL_DB_PUA_INCLUDE)
ret = pt ? 0 : 1; |
b023c36d |
else |
288057e9 |
ret = pt ? 1 : 0; |
b023c36d |
|
288057e9 |
if (ret)
cli_dbgmsg("Skipping PUA signature %s - excluded category\n", signame); |
b023c36d |
return ret;
}
|
102cd430 |
static cl_error_t cli_loaddb(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio, const char *dbname) |
5612732c |
{ |
288057e9 |
char buffer[FILEBUFF], *buffer_cpy = NULL, *pt, *start;
unsigned int line = 0, sigs = 0;
int ret = 0;
struct cli_matcher *root; |
5612732c |
|
cd94be7a |
UNUSEDPARAM(dbname); |
5612732c |
|
102cd430 |
if (CL_SUCCESS != (ret = cli_initroots(engine, options))) |
288057e9 |
return ret; |
5612732c |
|
15850fc6 |
root = engine->root[0]; |
5612732c |
|
288057e9 |
if (engine->ignored)
if (!(buffer_cpy = cli_malloc(FILEBUFF))) {
cli_errmsg("cli_loaddb: Can't allocate memory for buffer_cpy\n");
return CL_EMEM;
} |
04133ff9 |
|
288057e9 |
while (cli_dbgets(buffer, FILEBUFF, fs, dbio)) {
line++;
if (buffer[0] == '#')
continue;
cli_chomp(buffer);
if (engine->ignored)
strcpy(buffer_cpy, buffer); |
4048c4f6 |
|
288057e9 |
pt = strchr(buffer, '=');
if (!pt) {
cli_errmsg("Malformed pattern line %d\n", line);
ret = CL_EMALFDB;
break;
} |
4048c4f6 |
|
288057e9 |
start = buffer;
*pt++ = 0; |
ee039e40 |
|
288057e9 |
if (engine->ignored && cli_chkign(engine->ignored, start, buffer_cpy))
continue; |
ed9753e9 |
|
288057e9 |
if (engine->cb_sigload && engine->cb_sigload("db", start, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) {
cli_dbgmsg("cli_loaddb: skipping %s due to callback\n", start);
continue;
} |
eb422a03 |
|
288057e9 |
if (*pt == '=') continue; |
ee039e40 |
|
102cd430 |
if (CL_SUCCESS != (ret = cli_parse_add(root, start, pt, 0, 0, 0, "*", 0, NULL, options))) { |
288057e9 |
cli_dbgmsg("cli_loaddb: cli_parse_add failed on line %d\n", line);
ret = CL_EMALFDB;
break;
}
sigs++; |
b68d11d2 |
}
|
288057e9 |
if (engine->ignored)
free(buffer_cpy); |
04133ff9 |
|
288057e9 |
if (!line) {
cli_errmsg("Empty database file\n");
return CL_EMALFDB; |
b68d11d2 |
}
|
288057e9 |
if (ret) {
cli_errmsg("Problem parsing database at line %d\n", line);
return ret; |
b68d11d2 |
}
|
288057e9 |
if (signo)
*signo += sigs; |
b68d11d2 |
|
8d3aca30 |
return CL_SUCCESS; |
b68d11d2 |
}
|
cca29953 |
#define ICO_TOKENS 4 |
102cd430 |
static cl_error_t cli_loadidb(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio) |
73d8cded |
{ |
288057e9 |
const char *tokens[ICO_TOKENS + 1];
char buffer[FILEBUFF], *buffer_cpy = NULL;
uint8_t *hash;
int ret = CL_SUCCESS;
unsigned int line = 0, sigs = 0, tokens_count, i, size, enginesize;
struct icomtr *metric;
struct icon_matcher *matcher;
|
544fa973 |
if (!(matcher = (struct icon_matcher *)MPOOL_CALLOC(engine->mempool, sizeof(*matcher), 1))) |
288057e9 |
return CL_EMEM;
if (engine->ignored)
if (!(buffer_cpy = cli_malloc(FILEBUFF))) {
cli_errmsg("cli_loadidb: Can't allocate memory for buffer_cpy\n"); |
544fa973 |
MPOOL_FREE(engine->mempool, matcher); |
288057e9 |
return CL_EMEM;
}
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, ':', ICO_TOKENS + 1, tokens);
if (tokens_count != ICO_TOKENS) {
cli_errmsg("cli_loadidb: Malformed hash at line %u (wrong token count)\n", line);
ret = CL_EMALFDB;
break;
}
if (strlen(tokens[3]) != 124) {
cli_errmsg("cli_loadidb: Malformed hash at line %u (wrong length)\n", line);
ret = CL_EMALFDB;
break;
}
if (engine->ignored && cli_chkign(engine->ignored, tokens[0], buffer_cpy))
continue;
if (engine->cb_sigload && engine->cb_sigload("idb", tokens[0], ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) {
cli_dbgmsg("cli_loadidb: skipping %s due to callback\n", tokens[0]);
continue;
}
hash = (uint8_t *)tokens[3];
if (cli_hexnibbles((char *)hash, 124)) {
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;
}
enginesize = (size >> 3) - 2;
hash += 2;
|
544fa973 |
metric = (struct icomtr *)MPOOL_REALLOC(engine->mempool, matcher->icons[enginesize], sizeof(struct icomtr) * (matcher->icon_counts[enginesize] + 1)); |
288057e9 |
if (!metric) {
ret = CL_EMEM;
break;
}
matcher->icons[enginesize] = metric;
metric += matcher->icon_counts[enginesize];
matcher->icon_counts[enginesize]++;
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;
if ((metric->bright_y[i] = (hash[4] << 4) | hash[5]) > size - size / 8)
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;
if ((metric->dark_y[i] = (hash[4] << 4) | hash[5]) > size - size / 8)
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;
if ((metric->edge_y[i] = (hash[4] << 4) | hash[5]) > size - size / 8)
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;
if ((metric->noedge_y[i] = (hash[4] << 4) | hash[5]) > size - size / 8)
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];
if (metric->rsum + metric->gsum + metric->bsum > 103 || metric->ccount > 100) {
cli_errmsg("cli_loadidb: Malformed hash at line %u (bad spread data)\n", line);
ret = CL_EMALFDB;
break;
}
|
544fa973 |
if (!(metric->name = CLI_MPOOL_STRDUP(engine->mempool, tokens[0]))) { |
288057e9 |
ret = CL_EMEM;
break;
}
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]) { |
544fa973 |
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]))) { |
288057e9 |
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]) { |
544fa973 |
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]))) { |
288057e9 |
ret = CL_EMEM;
break;
}
matcher->group_counts[1]++;
}
metric->group[1] = i;
if (matcher->group_counts[0] > 256 || matcher->group_counts[1] > 256) {
cli_errmsg("cli_loadidb: too many icon groups!\n");
ret = CL_EMALFDB;
break;
}
sigs++;
}
if (engine->ignored)
free(buffer_cpy);
if (!line) {
cli_errmsg("cli_loadidb: Empty database file\n");
return CL_EMALFDB;
}
if (ret) {
cli_errmsg("cli_loadidb: Problem parsing database at line %u\n", line);
return ret;
}
if (signo)
*signo += sigs; |
73d8cded |
|
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 |
{ |
288057e9 |
int ret = 0; |
ec481027 |
|
288057e9 |
if (!(engine->dconf->phishing & PHISHING_CONF_ENGINE))
return CL_SUCCESS; |
692bda68 |
|
288057e9 |
if (!engine->whitelist_matcher) { |
102cd430 |
if (CL_SUCCESS != (ret = init_whitelist(engine))) { |
288057e9 |
return ret;
} |
ec481027 |
} |
3da4dd4c |
|
102cd430 |
if (CL_SUCCESS != (ret = load_regex_matcher(engine, engine->whitelist_matcher, fs, NULL, options, 1, dbio, engine->dconf->other & OTHER_CONF_PREFILTERING))) { |
288057e9 |
return ret; |
ec481027 |
} |
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 |
{ |
288057e9 |
int ret = 0; |
ec481027 |
|
288057e9 |
if (!(engine->dconf->phishing & PHISHING_CONF_ENGINE))
return CL_SUCCESS; |
692bda68 |
|
288057e9 |
if (!engine->domainlist_matcher) { |
102cd430 |
if (CL_SUCCESS != (ret = init_domainlist(engine))) { |
288057e9 |
return ret;
} |
ec481027 |
} |
3da4dd4c |
|
102cd430 |
if (CL_SUCCESS != (ret = load_regex_matcher(engine, engine->domainlist_matcher, fs, signo, options, 0, dbio, engine->dconf->other & OTHER_CONF_PREFILTERING))) { |
288057e9 |
return ret; |
ec481027 |
}
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 |
{ |
288057e9 |
const char *tokens[NDB_TOKENS + 1];
char buffer[FILEBUFF], *buffer_cpy = NULL;
const char *sig, *virname, *offset, *pt;
struct cli_matcher *root;
int line = 0, sigs = 0, ret = 0, tokens_count;
unsigned short target;
unsigned int phish = options & CL_DB_PHISHING; |
b68d11d2 |
|
cd94be7a |
UNUSEDPARAM(dbname); |
b68d11d2 |
|
102cd430 |
if (CL_SUCCESS != (ret = cli_initroots(engine, options))) |
288057e9 |
return ret; |
b68d11d2 |
|
288057e9 |
if (engine->ignored)
if (!(buffer_cpy = cli_malloc(FILEBUFF))) {
cli_errmsg("cli_loadndb: Can't allocate memory for buffer_cpy\n");
return CL_EMEM;
} |
04133ff9 |
|
288057e9 |
while (cli_dbgets(buffer, FILEBUFF, fs, dbio)) {
line++;
if (buffer[0] == '#')
continue; |
7afdc309 |
|
288057e9 |
if (!phish)
if (!strncmp(buffer, "HTML.Phishing", 13) || !strncmp(buffer, "Email.Phishing", 14))
continue; |
d6449522 |
|
288057e9 |
cli_chomp(buffer);
if (engine->ignored)
strcpy(buffer_cpy, buffer); |
b68d11d2 |
|
288057e9 |
tokens_count = cli_strtokenize(buffer, ':', NDB_TOKENS + 1, tokens);
if (tokens_count < 4 || tokens_count > 6) {
ret = CL_EMALFDB;
break;
} |
b68d11d2 |
|
288057e9 |
virname = tokens[0]; |
72fb25ea |
|
288057e9 |
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))
continue; |
b023c36d |
|
288057e9 |
if (engine->ignored && cli_chkign(engine->ignored, virname, buffer_cpy))
continue; |
ed9753e9 |
|
288057e9 |
if (!sdb && engine->cb_sigload && engine->cb_sigload("ndb", virname, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) {
cli_dbgmsg("cli_loadndb: skipping %s due to callback\n", virname);
continue;
} |
eb422a03 |
|
288057e9 |
if (tokens_count > 4) { /* min version */
pt = tokens[4]; |
039c9565 |
|
288057e9 |
if (!cli_isnumber(pt)) {
ret = CL_EMALFDB;
break;
} |
95083a4f |
|
288057e9 |
if ((unsigned int)atoi(pt) > cl_retflevel()) {
cli_dbgmsg("Signature for %s not loaded (required f-level: %d)\n", virname, atoi(pt));
continue;
} |
95083a4f |
|
288057e9 |
if (tokens_count == 6) { /* max version */
pt = tokens[5];
if (!cli_isnumber(pt)) {
ret = CL_EMALFDB;
break;
} |
555c5390 |
|
288057e9 |
if ((unsigned int)atoi(pt) < cl_retflevel()) {
continue;
}
}
} |
95083a4f |
|
288057e9 |
if (!(pt = tokens[1]) || (strcmp(pt, "*") && !cli_isnumber(pt))) {
ret = CL_EMALFDB;
break;
}
target = (unsigned short)atoi(pt); |
b68d11d2 |
|
288057e9 |
if (target >= CLI_MTARGETS) {
cli_dbgmsg("Not supported target type in signature for %s\n", virname);
continue;
} |
5612732c |
|
288057e9 |
root = engine->root[target]; |
5612732c |
|
288057e9 |
offset = tokens[2];
sig = tokens[3]; |
b68d11d2 |
|
102cd430 |
if (CL_SUCCESS != (ret = cli_parse_add(root, virname, sig, 0, 0, 0, offset, target, NULL, options))) { |
288057e9 |
ret = CL_EMALFDB;
break;
}
sigs++; |
ee039e40 |
} |
288057e9 |
if (engine->ignored)
free(buffer_cpy); |
ee039e40 |
|
288057e9 |
if (!line) {
cli_errmsg("Empty database file\n");
return CL_EMALFDB; |
4048c4f6 |
} |
8139fd99 |
|
288057e9 |
if (ret) {
cli_errmsg("Problem parsing database at line %d\n", line);
return ret; |
8139fd99 |
}
|
288057e9 |
if (signo)
*signo += sigs; |
4048c4f6 |
|
288057e9 |
if (sdb && sigs && !engine->sdb) {
engine->sdb = 1;
cli_dbgmsg("*** Self protection mechanism activated.\n"); |
555c5390 |
}
|
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)
{ |
27948a03 |
// clang-format off |
87b2a1a9 |
#define ATTRIB_TOKENS 10
#define EXPR_TOKEN_MAX 16 |
27948a03 |
struct lsig_attrib attrtab[] = {
{ "Target", CLI_TDB_UINT, (void **) &tdb->target },
{ "Engine", CLI_TDB_RANGE, (void **) &tdb->engine }, |
0f7ba617 |
|
27948a03 |
{ "FileSize", CLI_TDB_RANGE, (void **) &tdb->filesize },
{ "EntryPoint", CLI_TDB_RANGE, (void **) &tdb->ep },
{ "NumberOfSections", CLI_TDB_RANGE, (void **) &tdb->nos }, |
17cfd76f |
|
27948a03 |
{ "IconGroup1", CLI_TDB_STR, (void **) &tdb->icongrp1 },
{ "IconGroup2", CLI_TDB_STR, (void **) &tdb->icongrp2 }, |
0f7ba617 |
|
27948a03 |
{ "Container", CLI_TDB_FTYPE, (void **) &tdb->container },
{ "HandlerType", CLI_TDB_FTYPE, (void **) &tdb->handlertype },
{ "Intermediates", CLI_TDB_FTYPE_EXPR, (void **) &tdb->intermediates }, |
677fc4ba |
/* |
27948a03 |
{ "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 }, |
677fc4ba |
*/ |
27948a03 |
{ NULL, 0, NULL, } |
a2bfd1a0 |
}; |
288057e9 |
// clang-format on |
27948a03 |
|
a2bfd1a0 |
struct lsig_attrib *apt;
char *tokens[ATTRIB_TOKENS], *pt, *pt2;
unsigned int v1, v2, v3, i, j, tokens_count, have_newext = 0;
uint32_t cnt, off[ATTRIB_TOKENS]; |
677fc4ba |
|
288057e9 |
tokens_count = cli_strtokenize(attribs, ',', ATTRIB_TOKENS, (const char **)tokens); |
677fc4ba |
|
288057e9 |
for (i = 0; i < tokens_count; i++) {
if (!(pt = strchr(tokens[i], ':'))) { |
a2bfd1a0 |
cli_errmsg("lsigattribs: Incorrect format of attribute '%s'\n", tokens[i]);
return -1;
}
*pt++ = 0;
apt = NULL; |
288057e9 |
for (j = 0; attrtab[j].name; j++) {
if (!strcmp(attrtab[j].name, tokens[i])) { |
a2bfd1a0 |
apt = &attrtab[j];
break;
}
} |
677fc4ba |
|
288057e9 |
if (!apt) { |
a2bfd1a0 |
cli_dbgmsg("lsigattribs: Unknown attribute name '%s'\n", tokens[i]);
return 1;
} |
677fc4ba |
|
288057e9 |
if (!strcmp(apt->name, "Engine")) {
if (i) { |
a2bfd1a0 |
cli_errmsg("lsigattribs: For backward compatibility the Engine attribute must be on the first position\n");
return -1;
} |
288057e9 |
} else if (strcmp(apt->name, "Target")) { |
a2bfd1a0 |
have_newext = 1;
} |
bebd86a6 |
|
288057e9 |
switch (apt->type) {
case CLI_TDB_UINT:
if (!cli_isnumber(pt)) {
cli_errmsg("lsigattribs: Invalid argument for %s\n", tokens[i]);
return -1;
} |
a2bfd1a0 |
|
288057e9 |
off[i] = cnt = tdb->cnt[CLI_TDB_UINT]++; |
544fa973 |
tdb->val = (uint32_t *)MPOOL_REALLOC2(tdb->mempool, tdb->val, tdb->cnt[CLI_TDB_UINT] * sizeof(uint32_t)); |
288057e9 |
if (!tdb->val) {
tdb->cnt[CLI_TDB_UINT] = 0;
return -1;
} |
a2bfd1a0 |
|
288057e9 |
tdb->val[cnt] = atoi(pt);
break; |
a2bfd1a0 |
|
288057e9 |
case CLI_TDB_FTYPE:
if ((v1 = cli_ftcode(pt)) == CL_TYPE_ERROR) {
cli_dbgmsg("lsigattribs: Unknown file type '%s' in %s\n", pt, tokens[i]);
return 1; /* skip */
} |
a2bfd1a0 |
|
288057e9 |
off[i] = cnt = tdb->cnt[CLI_TDB_UINT]++; |
544fa973 |
tdb->val = (uint32_t *)MPOOL_REALLOC2(tdb->mempool, tdb->val, tdb->cnt[CLI_TDB_UINT] * sizeof(uint32_t)); |
288057e9 |
if (!tdb->val) {
tdb->cnt[CLI_TDB_UINT] = 0;
return -1;
} |
a2bfd1a0 |
|
288057e9 |
tdb->val[cnt] = v1;
break; |
a2bfd1a0 |
|
288057e9 |
case CLI_TDB_FTYPE_EXPR: { |
87b2a1a9 |
char *ftypes[EXPR_TOKEN_MAX];
unsigned int ftypes_count;
|
a7129066 |
off[i] = cnt = tdb->cnt[CLI_TDB_UINT]; |
288057e9 |
ftypes_count = cli_strtokenize(pt, '>', EXPR_TOKEN_MAX, (const char **)ftypes);
if (!ftypes_count) { |
631cb6a0 |
cli_dbgmsg("lsigattribs: No intermediate container tokens found.");
return 1;
} |
a7129066 |
tdb->cnt[CLI_TDB_UINT] += (ftypes_count + 1); |
544fa973 |
tdb->val = (uint32_t *)MPOOL_REALLOC2(tdb->mempool, tdb->val, tdb->cnt[CLI_TDB_UINT] * sizeof(uint32_t)); |
288057e9 |
if (!tdb->val) { |
a7129066 |
tdb->cnt[CLI_TDB_UINT] = 0;
return -1;
} |
87b2a1a9 |
|
a7129066 |
tdb->val[cnt++] = ftypes_count; |
288057e9 |
for (j = 0; j < ftypes_count; j++) {
if ((v1 = cli_ftcode(ftypes[j])) == CL_TYPE_ERROR) { |
87b2a1a9 |
cli_dbgmsg("lsigattribs: Unknown file type '%s' in %s\n", ftypes[j], tokens[i]);
return 1; /* skip */
} |
a7129066 |
tdb->val[cnt++] = v1; |
87b2a1a9 |
} |
288057e9 |
} break; |
87b2a1a9 |
|
288057e9 |
case CLI_TDB_RANGE:
if (!(pt2 = strchr(pt, '-'))) {
cli_errmsg("lsigattribs: Incorrect parameters in '%s'\n", tokens[i]);
return -1;
} |
a2bfd1a0 |
|
288057e9 |
*pt2++ = 0;
off[i] = cnt = tdb->cnt[CLI_TDB_RANGE];
tdb->cnt[CLI_TDB_RANGE] += 2; |
544fa973 |
tdb->range = (uint32_t *)MPOOL_REALLOC2(tdb->mempool, tdb->range, tdb->cnt[CLI_TDB_RANGE] * sizeof(uint32_t)); |
288057e9 |
if (!tdb->range) {
tdb->cnt[CLI_TDB_RANGE] = 0;
return -1;
} |
a2bfd1a0 |
|
288057e9 |
if (!cli_isnumber(pt) || !cli_isnumber(pt2)) {
cli_errmsg("lsigattribs: Invalid argument for %s\n", tokens[i]);
return -1;
} |
a2bfd1a0 |
|
288057e9 |
tdb->range[cnt] = atoi(pt);
tdb->range[cnt + 1] = atoi(pt2);
break; |
a2bfd1a0 |
|
288057e9 |
case CLI_TDB_RANGE2:
if (!strchr(pt, '-') || !strchr(pt, '.')) {
cli_errmsg("lsigattribs: Incorrect parameters in '%s'\n", tokens[i]);
return -1;
} |
a2bfd1a0 |
|
288057e9 |
off[i] = cnt = tdb->cnt[CLI_TDB_RANGE];
tdb->cnt[CLI_TDB_RANGE] += 3; |
544fa973 |
tdb->range = (uint32_t *)MPOOL_REALLOC2(tdb->mempool, tdb->range, tdb->cnt[CLI_TDB_RANGE] * sizeof(uint32_t)); |
288057e9 |
if (!tdb->range) {
tdb->cnt[CLI_TDB_RANGE] = 0;
return -1;
} |
a2bfd1a0 |
|
288057e9 |
if (sscanf(pt, "%u.%u-%u", &v1, &v2, &v3) != 3) {
cli_errmsg("lsigattribs: Can't parse parameters in '%s'\n", tokens[i]);
return -1;
} |
a2bfd1a0 |
|
288057e9 |
tdb->range[cnt] = (uint32_t)v1;
tdb->range[cnt + 1] = (uint32_t)v2;
tdb->range[cnt + 2] = (uint32_t)v3;
break; |
a2bfd1a0 |
|
288057e9 |
case CLI_TDB_STR:
off[i] = cnt = tdb->cnt[CLI_TDB_STR];
tdb->cnt[CLI_TDB_STR] += strlen(pt) + 1; |
544fa973 |
tdb->str = (char *)MPOOL_REALLOC2(tdb->mempool, tdb->str, tdb->cnt[CLI_TDB_STR] * sizeof(char)); |
288057e9 |
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; |
a2bfd1a0 |
|
288057e9 |
default:
/* All known TDB types handled above, skip unknown */
cli_dbgmsg("lsigattribs: Unknown attribute type '%u'\n", apt->type);
return 1; /* +1 = skip */ |
a2bfd1a0 |
} |
677fc4ba |
}
|
288057e9 |
if (!i) { |
a2bfd1a0 |
cli_errmsg("lsigattribs: Empty TDB\n");
return -1; |
677fc4ba |
}
|
288057e9 |
for (i = 0; i < tokens_count; i++) {
for (j = 0; attrtab[j].name; j++) {
if (!strcmp(attrtab[j].name, tokens[i])) { |
a2bfd1a0 |
apt = &attrtab[j];
break;
}
} |
677fc4ba |
|
288057e9 |
if (!apt) |
a2bfd1a0 |
continue; |
677fc4ba |
|
288057e9 |
switch (apt->type) {
case CLI_TDB_UINT:
case CLI_TDB_FTYPE:
case CLI_TDB_FTYPE_EXPR:
*apt->pt = (uint32_t *)&tdb->val[off[i]];
break; |
a2bfd1a0 |
|
288057e9 |
case CLI_TDB_RANGE:
case CLI_TDB_RANGE2:
*apt->pt = (uint32_t *)&tdb->range[off[i]];
break; |
a2bfd1a0 |
|
288057e9 |
case CLI_TDB_STR:
*apt->pt = (char *)&tdb->str[off[i]];
break; |
a2bfd1a0 |
} |
677fc4ba |
}
|
288057e9 |
if (have_newext && (!tdb->engine || tdb->engine[0] < 51)) { |
a2bfd1a0 |
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; |
fa4d6353 |
} |
a2bfd1a0 |
|
677fc4ba |
return 0;
}
|
288057e9 |
#define FREE_TDB(x) \
do { \
if (x.cnt[CLI_TDB_UINT]) \ |
544fa973 |
MPOOL_FREE(x.mempool, x.val); \ |
288057e9 |
if (x.cnt[CLI_TDB_RANGE]) \ |
544fa973 |
MPOOL_FREE(x.mempool, x.range); \ |
288057e9 |
if (x.cnt[CLI_TDB_STR]) \ |
544fa973 |
MPOOL_FREE(x.mempool, x.str); \ |
288057e9 |
if (x.macro_ptids) \ |
544fa973 |
MPOOL_FREE(x.mempool, x.macro_ptids); \ |
288057e9 |
} while (0);
#define FREE_TDB_P(x) \
do { \
if (x->cnt[CLI_TDB_UINT]) \ |
544fa973 |
MPOOL_FREE(x->mempool, x->val); \ |
288057e9 |
if (x->cnt[CLI_TDB_RANGE]) \ |
544fa973 |
MPOOL_FREE(x->mempool, x->range); \ |
288057e9 |
if (x->cnt[CLI_TDB_STR]) \ |
544fa973 |
MPOOL_FREE(x->mempool, x->str); \ |
288057e9 |
if (x->macro_ptids) \ |
544fa973 |
MPOOL_FREE(x->mempool, x->macro_ptids); \ |
288057e9 |
} while (0); |
a684f7d8 |
|
9caff17a |
static inline int init_tdb(struct cli_lsig_tdb *tdb, struct cl_engine *engine, char *target, const char *virname) |
a684f7d8 |
{
int ret;
#ifdef USE_MPOOL
tdb->mempool = engine->mempool; |
544fa973 |
#else
UNUSEDPARAM(engine); |
a684f7d8 |
#endif |
544fa973 |
|
102cd430 |
if (CL_SUCCESS != (ret = lsigattribs(target, tdb))) { |
a684f7d8 |
FREE_TDB_P(tdb); |
288057e9 |
if (ret == 1) { |
a684f7d8 |
cli_dbgmsg("init_tdb: Not supported attribute(s) in signature for %s, skipping\n", virname);
return CL_BREAK;
}
return CL_EMALFDB;
}
|
288057e9 |
if (tdb->engine) {
if (tdb->engine[0] > cl_retflevel()) { |
a684f7d8 |
FREE_TDB_P(tdb);
cli_dbgmsg("init_tdb: Signature for %s not loaded (required f-level: %u)\n", virname, tdb->engine[0]);
return CL_BREAK; |
288057e9 |
} else if (tdb->engine[1] < cl_retflevel()) { |
a684f7d8 |
FREE_TDB_P(tdb);
return CL_BREAK;
}
}
|
288057e9 |
if (!tdb->target) { |
a684f7d8 |
FREE_TDB_P(tdb);
cli_errmsg("init_tdb: No target specified in TDB\n");
return CL_EMALFDB; |
288057e9 |
} else if (tdb->target[0] >= CLI_MTARGETS) { |
a684f7d8 |
FREE_TDB_P(tdb);
cli_dbgmsg("init_tdb: Not supported target type in signature for %s, skipping\n", virname);
return CL_BREAK;
}
|
288057e9 |
if ((tdb->icongrp1 || tdb->icongrp2) && tdb->target[0] != 1) { |
a684f7d8 |
FREE_TDB_P(tdb);
cli_errmsg("init_tdb: IconGroup is only supported in PE (target 1) signatures\n");
return CL_EMALFDB;
}
|
288057e9 |
if ((tdb->ep || tdb->nos) && tdb->target[0] != 1 && tdb->target[0] != 6 && tdb->target[0] != 9) { |
a684f7d8 |
FREE_TDB_P(tdb);
cli_errmsg("init_tdb: EntryPoint/NumberOfSections is only supported in PE/ELF/Mach-O signatures\n");
return CL_EMALFDB;
}
return CL_SUCCESS;
}
|
3a65b26b |
/* 0 1 2 3 4 5 ... (max 66) |
5d9cac7b |
* VirusName;Attributes;Logic;SubSig1[;SubSig2[;SubSig3 ... ]] |
b9af0434 |
* NOTE: Maximum of 64(see MAX_LDB_SUBSIGS) subsignatures (last would be token 66) |
3a65b26b |
*/ |
677fc4ba |
#define LDB_TOKENS 67 |
71e13645 |
#define SUB_TOKENS 4 |
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 |
{ |
71e13645 |
const char *sig, *virname, *offset, *logic, *sigopts; |
df8af6d3 |
struct cli_ac_lsig **newtable, *lsig; |
288057e9 |
char *tokens[LDB_TOKENS + 1], *subtokens[SUB_TOKENS + 1]; |
71e13645 |
int i, j, subsigs, tokens_count, subtokens_count; |
df8af6d3 |
unsigned short target = 0;
struct cli_matcher *root;
struct cli_lsig_tdb tdb;
uint32_t lsigid[2]; |
5d9cac7b |
uint8_t subsig_opts; |
df8af6d3 |
int ret; |
677fc4ba |
|
cd94be7a |
UNUSEDPARAM(dbname);
|
288057e9 |
tokens_count = cli_ldbtokenize(buffer, ';', LDB_TOKENS + 1, (const char **)tokens, 2);
if (tokens_count < 4) { |
71e13645 |
cli_errmsg("Invalid or unsupported ldb signature format\n"); |
32957e2f |
return CL_EMALFDB; |
df8af6d3 |
} |
32957e2f |
|
df8af6d3 |
virname = tokens[0]; |
288057e9 |
logic = tokens[2]; |
677fc4ba |
|
df8af6d3 |
if (chkpua && cli_chkpua(virname, engine->pua_cats, options)) |
32957e2f |
return CL_SUCCESS; |
04133ff9 |
|
d510390f |
if (engine->ignored && cli_chkign(engine->ignored, virname, buffer_cpy ? buffer_cpy : virname)) { |
288057e9 |
if (skip) |
32957e2f |
*skip = 1;
return CL_SUCCESS; |
d510390f |
} |
677fc4ba |
|
288057e9 |
if (engine->cb_sigload && engine->cb_sigload("ldb", virname, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) { |
32957e2f |
cli_dbgmsg("cli_loadldb: skipping %s due to callback\n", virname);
(*sigs)--;
return CL_SUCCESS; |
eb422a03 |
}
|
df8af6d3 |
subsigs = cli_ac_chklsig(logic, logic + strlen(logic), NULL, NULL, NULL, 1); |
288057e9 |
if (subsigs == -1) { |
71e13645 |
cli_errmsg("Invalid or unsupported ldb logic\n"); |
32957e2f |
return CL_EMALFDB; |
df8af6d3 |
}
subsigs++; |
0ab27124 |
|
d38d6dad |
if (!line) { |
32957e2f |
/* This is a logical signature from the bytecode, we need all
* subsignatures, even if not referenced from the logical expression */ |
288057e9 |
if (subsigs > tokens_count - 3) { |
32957e2f |
cli_errmsg("load_oneldb: Too many subsignatures: %u (max %u)\n", |
288057e9 |
subsigs, tokens_count - 3); |
32957e2f |
return CL_EMALFDB;
} |
288057e9 |
subsigs = tokens_count - 3;
} else if (subsigs != tokens_count - 3) { |
32957e2f |
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 |
|
098114ca |
#if !HAVE_PCRE
/* Regex Usage and Support Check */
for (i = 0; i < subsigs; ++i) {
char *slash = strchr(tokens[i + 3], '/');
if (slash && strchr(slash + 1, '/')) {
cli_warnmsg("cli_loadldb: logical signature for %s uses PCREs but support is disabled, skipping\n", virname);
(*sigs)--;
return CL_SUCCESS;
}
}
#endif
|
b9af0434 |
/* enforce MAX_LDB_SUBSIGS(currently 64) subsig cap */ |
288057e9 |
if (subsigs > MAX_LDB_SUBSIGS) { |
71e13645 |
cli_errmsg("cli_loadldb: Broken logical expression or too many subsignatures\n");
return CL_EMALFDB; |
7afaa9bd |
}
|
df8af6d3 |
/* TDB */
memset(&tdb, 0, sizeof(tdb)); |
102cd430 |
if (CL_SUCCESS != (ret = init_tdb(&tdb, engine, tokens[1], virname)) != CL_SUCCESS) { |
32957e2f |
(*sigs)--; |
9caff17a |
if (ret == CL_BREAK)
return CL_SUCCESS;
return ret; |
17cfd76f |
}
|
df8af6d3 |
root = engine->root[tdb.target[0]]; |
b023c36d |
|
544fa973 |
lsig = (struct cli_ac_lsig *)MPOOL_CALLOC(engine->mempool, 1, sizeof(struct cli_ac_lsig)); |
288057e9 |
if (!lsig) { |
32957e2f |
cli_errmsg("cli_loadldb: Can't allocate memory for lsig\n");
FREE_TDB(tdb);
return CL_EMEM; |
df8af6d3 |
} |
677fc4ba |
|
288057e9 |
lsig->type = CLI_LSIG_NORMAL; |
544fa973 |
lsig->u.logic = CLI_MPOOL_STRDUP(engine->mempool, logic); |
288057e9 |
if (!lsig->u.logic) { |
32957e2f |
cli_errmsg("cli_loadldb: Can't allocate memory for lsig->logic\n");
FREE_TDB(tdb); |
544fa973 |
MPOOL_FREE(engine->mempool, lsig); |
32957e2f |
return CL_EMEM; |
df8af6d3 |
} |
677fc4ba |
|
df8af6d3 |
lsigid[0] = lsig->id = root->ac_lsigs; |
677fc4ba |
|
984f90ca |
if (bc_idx)
root->linked_bcs++; |
df8af6d3 |
root->ac_lsigs++; |
544fa973 |
newtable = (struct cli_ac_lsig **)MPOOL_REALLOC(engine->mempool, root->ac_lsigtable, root->ac_lsigs * sizeof(struct cli_ac_lsig *)); |
288057e9 |
if (!newtable) { |
984f90ca |
if (bc_idx)
root->linked_bcs--; |
32957e2f |
root->ac_lsigs--;
cli_errmsg("cli_loadldb: Can't realloc root->ac_lsigtable\n");
FREE_TDB(tdb); |
544fa973 |
MPOOL_FREE(engine->mempool, lsig); |
32957e2f |
return CL_EMEM; |
df8af6d3 |
} |
32957e2f |
|
57f14280 |
/* 0 marks no bc, we can't use a pointer to bc, since that is
* realloced/moved during load */ |
288057e9 |
lsig->bc_idx = bc_idx; |
df8af6d3 |
newtable[root->ac_lsigs - 1] = lsig; |
288057e9 |
root->ac_lsigtable = newtable;
tdb.subsigs = subsigs; |
5ccfa0b7 |
|
288057e9 |
for (i = 0; i < subsigs; i++) { |
32957e2f |
lsigid[1] = i; |
288057e9 |
offset = "*"; |
5d9cac7b |
|
288057e9 |
sigopts = NULL; |
71e13645 |
subsig_opts = 0;
|
288057e9 |
subtokens_count = cli_ldbtokenize(tokens[3 + i], ':', SUB_TOKENS + 1, (const char **)subtokens, 0);
if (!subtokens_count) { |
71e13645 |
cli_errmsg("Invalid or unsupported ldb subsignature format\n");
return CL_EMALFDB;
}
|
288057e9 |
if ((subtokens_count % 2) == 0) |
71e13645 |
offset = subtokens[0]; |
5d9cac7b |
|
288057e9 |
if (subtokens_count == 3) |
71e13645 |
sigopts = subtokens[2]; |
288057e9 |
else if (subtokens_count == 4) |
71e13645 |
sigopts = subtokens[3];
|
288057e9 |
if (sigopts) { /* signature modifiers */
for (j = 0; j < (int)strlen(sigopts); j++)
switch (sigopts[j]) {
case 'i':
subsig_opts |= ACPATT_OPTION_NOCASE;
break;
case 'f':
subsig_opts |= ACPATT_OPTION_FULLWORD;
break;
case 'w':
subsig_opts |= ACPATT_OPTION_WIDE;
break;
case 'a':
subsig_opts |= ACPATT_OPTION_ASCII;
break;
default:
cli_errmsg("cli_loadldb: Signature for %s uses invalid option: %02x\n", virname, sigopts[j]);
return CL_EMALFDB; |
5d9cac7b |
} |
32957e2f |
} |
677fc4ba |
|
71e13645 |
sig = (subtokens_count % 2) ? subtokens[0] : subtokens[1];
|
288057e9 |
if (subsig_opts) |
b2197a09 |
ret = cli_sigopts_handler(root, virname, sig, subsig_opts, 0, 0, offset, target, lsigid, options); |
5d9cac7b |
else
ret = cli_parse_add(root, virname, sig, 0, 0, 0, offset, target, lsigid, options); |
d8de9115 |
|
288057e9 |
if (ret) |
32957e2f |
return ret;
|
288057e9 |
if (sig[0] == '$' && i) { |
32957e2f |
/* allow mapping from lsig back to pattern for macros */
if (!tdb.macro_ptids) |
544fa973 |
tdb.macro_ptids = MPOOL_CALLOC(root->mempool, subsigs, sizeof(*tdb.macro_ptids)); |
32957e2f |
if (!tdb.macro_ptids)
return CL_EMEM;
|
288057e9 |
tdb.macro_ptids[i - 1] = root->ac_patterns - 1; |
32957e2f |
} |
df8af6d3 |
} |
32957e2f |
|
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)
{ |
a2bfd1a0 |
char buffer[CLI_DEFAULT_LSIG_BUFSIZE + 1], *buffer_cpy = NULL;
unsigned int line = 0, sigs = 0;
int ret; |
677fc4ba |
|
102cd430 |
if (CL_SUCCESS != (ret = cli_initroots(engine, options))) |
a2bfd1a0 |
return ret; |
677fc4ba |
|
288057e9 |
if (engine->ignored) {
if (!(buffer_cpy = cli_malloc(sizeof(buffer)))) { |
a2bfd1a0 |
cli_errmsg("cli_loadldb: Can't allocate memory for buffer_cpy\n");
return CL_EMEM;
} |
241e7eb1 |
} |
a2bfd1a0 |
|
288057e9 |
while (cli_dbgets(buffer, sizeof(buffer), fs, dbio)) { |
a2bfd1a0 |
line++; |
288057e9 |
if (buffer[0] == '#') |
a2bfd1a0 |
continue; |
677fc4ba |
|
a2bfd1a0 |
sigs++;
cli_chomp(buffer);
|
288057e9 |
if (engine->ignored) |
a2bfd1a0 |
strcpy(buffer_cpy, buffer);
ret = load_oneldb(buffer, |
288057e9 |
engine->pua_cats && (options & CL_DB_PUA_MODE) && (options & (CL_DB_PUA_INCLUDE | CL_DB_PUA_EXCLUDE)),
engine, options, dbname, line, &sigs, 0, buffer_cpy, NULL); |
a2bfd1a0 |
if (ret)
break; |
677fc4ba |
} |
a2bfd1a0 |
|
288057e9 |
if (engine->ignored) |
a2bfd1a0 |
free(buffer_cpy); |
677fc4ba |
|
288057e9 |
if (!line) { |
a2bfd1a0 |
cli_errmsg("Empty database file\n");
return CL_EMALFDB; |
677fc4ba |
}
|
288057e9 |
if (ret) { |
a2bfd1a0 |
cli_errmsg("Problem parsing database at line %u\n", line);
return ret; |
677fc4ba |
}
|
288057e9 |
if (signo) |
a2bfd1a0 |
*signo += sigs; |
677fc4ba |
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; |
288057e9 |
unsigned sigs = 0; |
be43f951 |
unsigned security_trust = 0; |
d5ffa2ac |
unsigned i; |
be43f951 |
|
ab636570 |
/* TODO: virusname have a common prefix, and whitelist by that */ |
288057e9 |
if ((rc = cli_initroots(engine, options)))
return rc; |
459b13ed |
|
288057e9 |
if (!(engine->dconf->bytecode & BYTECODE_ENGINE_MASK)) {
return CL_SUCCESS; |
52dd3a6b |
} |
2d78fb7c |
|
288057e9 |
if (engine->cb_sigload && engine->cb_sigload("cbc", dbname, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) {
cli_dbgmsg("cli_loadcbc: skipping %s due to callback\n", dbname);
return CL_SUCCESS; |
2d78fb7c |
}
|
62315ce6 |
if (!(options & CL_DB_BYTECODE_UNSIGNED) && !(options & CL_DB_SIGNED)) { |
288057e9 |
cli_warnmsg("Only loading signed bytecode, skipping load of unsigned bytecode!\n");
cli_warnmsg("Turn on BytecodeUnsigned/--bytecode-unsigned to enable loading of unsigned bytecode\n");
return CL_SUCCESS; |
9c92344b |
} |
62315ce6 |
|
288057e9 |
bcs->all_bcs = cli_realloc2(bcs->all_bcs, sizeof(*bcs->all_bcs) * (bcs->count + 1)); |
52dd3a6b |
if (!bcs->all_bcs) { |
288057e9 |
cli_errmsg("cli_loadcbc: Can't allocate memory for bytecode entry\n");
return CL_EMEM; |
52dd3a6b |
}
bcs->count++; |
288057e9 |
bc = &bcs->all_bcs[bcs->count - 1]; |
be43f951 |
switch (engine->bytecode_security) { |
288057e9 |
case CL_BYTECODE_TRUST_SIGNED:
security_trust = !!(options & CL_DB_SIGNED);
break;
default:
security_trust = 0; |
be43f951 |
}
|
288057e9 |
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 */ |
288057e9 |
while (cli_dbgets(buf, sizeof(buf), fs, dbio)) {
} |
1453c0a3 |
|
52dd3a6b |
if (rc != CL_SUCCESS) { |
288057e9 |
cli_bytecode_destroy(bc);
cli_errmsg("Unable to load %s bytecode: %s\n", dbname, cl_strerror(rc));
return rc; |
52dd3a6b |
} |
039af772 |
if (bc->state == bc_skip) { |
288057e9 |
cli_bytecode_destroy(bc);
bcs->count--;
return CL_SUCCESS; |
039af772 |
} |
288057e9 |
bc->id = bcs->count; /* must set after _load, since load zeroes */ |
3ccff6f2 |
if (engine->bytecode_mode == CL_BYTECODE_MODE_TEST) |
288057e9 |
cli_infomsg(NULL, "bytecode %u -> %s\n", bc->id, dbname); |
f4e34215 |
if (bc->kind == BC_LOGICAL || bc->lsig) { |
3735fda1 |
unsigned oldsigs = sigs; |
288057e9 |
if (!bc->lsig) {
cli_errmsg("Bytecode %s has logical kind, but missing logical signature!\n", dbname);
return CL_EMALFDB;
}
cli_dbgmsg("Bytecode %s(%u) has logical signature: %s\n", dbname, bc->id, bc->lsig);
rc = load_oneldb(bc->lsig, 0, engine, options, dbname, 0, &sigs, bcs->count, NULL, &skip);
if (rc != CL_SUCCESS) {
cli_errmsg("Problem parsing logical signature %s for bytecode %s: %s\n",
bc->lsig, dbname, cl_strerror(rc));
return rc;
}
if (skip) {
cli_bytecode_destroy(bc);
bcs->count--;
return CL_SUCCESS;
} |
3735fda1 |
if (sigs != oldsigs) { |
288057e9 |
/* compiler ensures Engine field in lsig matches the one in bytecode, |
3735fda1 |
* so this should never happen. */ |
288057e9 |
cli_errmsg("Bytecode logical signature skipped, but bytecode itself not?");
return CL_EMALFDB; |
3735fda1 |
} |
f4e34215 |
} |
d510390f |
sigs++; |
f4e34215 |
if (bc->kind != BC_LOGICAL) { |
288057e9 |
if (bc->lsig) {
/* runlsig will only flip a status bit, not report a match, |
f4e34215 |
* when the hooks are executed we only execute the hook if its
* status bit is on */ |
288057e9 |
bc->hook_lsig_id = ++engine->hook_lsig_ids;
}
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) {
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",
bc0->id, (uint32_t)bc0->metadata.timestamp,
bc0->metadata.sigmaker ? bc0->metadata.sigmaker : "N/A");
cli_warnmsg("Conflicting BC_STARTUP: %d %d by %s\n",
bc->id, (uint32_t)bc->metadata.timestamp,
bc->metadata.sigmaker ? bc->metadata.sigmaker : "N/A");
return CL_EMALFDB;
}
break;
default:
cli_errmsg("Bytecode: unhandled bytecode kind %u\n", bc->kind);
return CL_EMALFDB;
} |
df8af6d3 |
} |
459b13ed |
if (signo) |
288057e9 |
*signo += sigs; |
52dd3a6b |
return CL_SUCCESS;
}
|
3a65b26b |
/* 0 1 2 3 4 5 6 7
* MagicType:Offset:HexSig:Name:RequiredType:DetectedType[:MinFL[:MaxFL]]
*/ |
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 |
{ |
288057e9 |
const char *tokens[FTM_TOKENS + 1], *pt;
char buffer[FILEBUFF];
unsigned int line = 0, sigs = 0, tokens_count;
struct cli_ftype *new;
cli_file_t rtype, type;
int ret;
int magictype;
|
102cd430 |
if (CL_SUCCESS != (ret = cli_initroots(engine, options))) |
288057e9 |
return ret;
while (1) {
if (internal) {
options |= CL_DB_OFFICIAL;
if (!ftypes_int[line])
break;
strncpy(buffer, ftypes_int[line], sizeof(buffer));
buffer[sizeof(buffer) - 1] = '\0';
} else {
if (!cli_dbgets(buffer, FILEBUFF, fs, dbio))
break;
if (buffer[0] == '#')
continue;
cli_chomp(buffer);
}
line++;
tokens_count = cli_strtokenize(buffer, ':', FTM_TOKENS + 1, tokens);
if (tokens_count < 6 || tokens_count > 8) {
ret = CL_EMALFDB;
break;
}
if (tokens_count > 6) { /* min version */
pt = tokens[6];
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;
}
if (tokens_count == 8) { /* max version */
pt = tokens[7];
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) {
ret = CL_EMALFDB;
break;
}
if (!cli_isnumber(tokens[0])) {
cli_errmsg("cli_loadftm: Invalid value for the first field\n");
ret = CL_EMALFDB;
break;
} |
039c9565 |
|
1d1c4b15 |
magictype = atoi(tokens[0]); |
288057e9 |
if (magictype == 1) { /* A-C */ |
102cd430 |
if (CL_SUCCESS != (ret = cli_parse_add(engine->root[0], tokens[3], tokens[2], 0, rtype, type, tokens[1], 0, NULL, options))) |
288057e9 |
break;
} else if ((magictype == 0) || (magictype == 4)) { /* memcmp() */
if (!cli_isnumber(tokens[1])) {
cli_errmsg("cli_loadftm: Invalid offset\n");
ret = CL_EMALFDB;
break;
} |
544fa973 |
new = (struct cli_ftype *)MPOOL_MALLOC(engine->mempool, sizeof(struct cli_ftype)); |
288057e9 |
if (!new) {
ret = CL_EMEM;
break;
}
new->type = type;
new->offset = atoi(tokens[1]); |
544fa973 |
new->magic = (unsigned char *)CLI_MPOOL_HEX2STR(engine->mempool, tokens[2]); |
288057e9 |
if (!new->magic) {
cli_errmsg("cli_loadftm: Can't decode the hex string\n");
ret = CL_EMALFDB; |
544fa973 |
MPOOL_FREE(engine->mempool, new); |
288057e9 |
break;
}
new->length = (uint16_t)strlen(tokens[2]) / 2; |
544fa973 |
new->tname = CLI_MPOOL_STRDUP(engine->mempool, tokens[3]); |
288057e9 |
if (!new->tname) { |
544fa973 |
MPOOL_FREE(engine->mempool, new->magic);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
ret = CL_EMEM;
break;
} |
1d1c4b15 |
/* files => ftypes, partitions => ptypes */ |
288057e9 |
if (magictype == 4) {
new->next = engine->ptypes;
engine->ptypes = new;
} else {
new->next = engine->ftypes;
engine->ftypes = new; |
1d1c4b15 |
} |
288057e9 |
} else {
cli_dbgmsg("cli_loadftm: Unsupported mode %u\n", atoi(tokens[0]));
continue;
}
sigs++; |
7021b545 |
}
|
288057e9 |
if (ret) {
cli_errmsg("Problem parsing %s filetype database at line %u\n", internal ? "built-in" : "external", line);
return ret; |
7021b545 |
}
|
288057e9 |
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)
{ |
288057e9 |
const char *tokens[INFO_TOKENS + 1];
char buffer[FILEBUFF];
unsigned int line = 0, tokens_count, len;
char hash[32]; |
7b1f1aaf |
struct cli_dbinfo *last = NULL, *new; |
288057e9 |
int ret = CL_SUCCESS, dsig = 0; |
da6e06dd |
void *ctx; |
ace26bfe |
|
288057e9 |
if (!dbio) {
cli_errmsg("cli_loadinfo: .info files can only be loaded from within database container files\n");
return CL_EMALFDB; |
7eb6bac7 |
} |
b2e7c931 |
|
da6e06dd |
ctx = cl_hash_init("sha256"); |
b2e7c931 |
if (!(ctx))
return CL_EMALFDB;
|
288057e9 |
while (cli_dbgets(buffer, FILEBUFF, fs, dbio)) {
line++;
if (!(options & CL_DB_UNSIGNED) && !strncmp(buffer, "DSIG:", 5)) {
dsig = 1;
cl_finish_hash(ctx, hash);
if (cli_versig2((unsigned char *)hash, buffer + 5, INFO_NSTR, INFO_ESTR) != CL_SUCCESS) {
cli_errmsg("cli_loadinfo: Incorrect digital signature\n");
ret = CL_EMALFDB;
}
break;
}
len = strlen(buffer);
if (!len) {
buffer[len] = '\n'; |
110714bb |
buffer[len + 1] = 0; |
288057e9 |
} 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;
}
}
cl_update_hash(ctx, buffer, strlen(buffer));
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;
} |
544fa973 |
last = engine->dbinfo = (struct cli_dbinfo *)MPOOL_CALLOC(engine->mempool, 1, sizeof(struct cli_bm_patt)); |
288057e9 |
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;
}
tokens_count = cli_strtokenize(buffer, ':', INFO_TOKENS + 1, tokens);
if (tokens_count != INFO_TOKENS) {
ret = CL_EMALFDB;
break;
} |
544fa973 |
new = (struct cli_dbinfo *)MPOOL_CALLOC(engine->mempool, 1, sizeof(struct cli_dbinfo)); |
288057e9 |
if (!new) {
ret = CL_EMEM;
break;
} |
544fa973 |
new->name = CLI_MPOOL_STRDUP(engine->mempool, tokens[0]); |
288057e9 |
if (!new->name) { |
544fa973 |
MPOOL_FREE(engine->mempool, new); |
288057e9 |
ret = CL_EMEM;
break;
}
if (!cli_isnumber(tokens[1])) {
cli_errmsg("cli_loadinfo: Invalid value in the size field\n"); |
544fa973 |
MPOOL_FREE(engine->mempool, new->name);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
ret = CL_EMALFDB;
break;
}
new->size = atoi(tokens[1]);
|
544fa973 |
if (strlen(tokens[2]) != 64 || !(new->hash = CLI_MPOOL_HEX2STR(engine->mempool, tokens[2]))) { |
288057e9 |
cli_errmsg("cli_loadinfo: Malformed SHA256 string at line %u\n", line); |
544fa973 |
MPOOL_FREE(engine->mempool, new->name);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
ret = CL_EMALFDB;
break; |
110714bb |
} |
288057e9 |
last->next = new;
last = new; |
110714bb |
} |
288057e9 |
if (!(options & CL_DB_UNSIGNED) && !dsig) {
cli_errmsg("cli_loadinfo: Digital signature not found\n");
return CL_EMALFDB;
}
if (ret) {
cli_errmsg("cli_loadinfo: Problem parsing database at line %u\n", line);
return ret; |
ace26bfe |
}
return CL_SUCCESS;
}
|
288057e9 |
#define IGN_MAX_TOKENS 3 |
15850fc6 |
static int cli_loadign(FILE *fs, struct cl_engine *engine, unsigned int options, struct cli_dbio *dbio) |
ed9753e9 |
{ |
288057e9 |
const char *tokens[IGN_MAX_TOKENS + 1], *signame, *hash = NULL;
char buffer[FILEBUFF];
unsigned int line = 0, tokens_count, len;
struct cli_bm_patt *new;
int ret = CL_SUCCESS; |
ed9753e9 |
|
cd94be7a |
UNUSEDPARAM(options);
|
288057e9 |
if (!engine->ignored) { |
544fa973 |
engine->ignored = (struct cli_matcher *)MPOOL_CALLOC(engine->mempool, 1, sizeof(struct cli_matcher)); |
288057e9 |
if (!engine->ignored)
return CL_EMEM; |
04133ff9 |
#ifdef USE_MPOOL |
288057e9 |
engine->ignored->mempool = engine->mempool; |
04133ff9 |
#endif |
102cd430 |
if (CL_SUCCESS != (ret = cli_bm_init(engine->ignored))) { |
288057e9 |
cli_errmsg("cli_loadign: Can't initialise AC pattern matcher\n");
return ret;
}
}
while (cli_dbgets(buffer, FILEBUFF, fs, dbio)) {
line++;
if (buffer[0] == '#')
continue;
cli_chomp(buffer);
tokens_count = cli_strtokenize(buffer, ':', IGN_MAX_TOKENS + 1, tokens);
if (tokens_count > IGN_MAX_TOKENS) {
ret = CL_EMALFDB;
break;
}
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");
ret = CL_EMALFDB;
break;
} |
5989b715 |
if (len < 3) {
int pad = 3 - len; |
288057e9 |
/* patch-up for Boyer-Moore minimum length of 3: pad with spaces */ |
5989b715 |
if (signame != buffer) { |
288057e9 |
strncpy(buffer, signame, len); |
5989b715 |
signame = buffer;
}
buffer[3] = '\0';
while (pad > 0) |
288057e9 |
buffer[3 - pad--] = '\x20'; |
5989b715 |
len = 3;
} |
039c9565 |
|
544fa973 |
new = (struct cli_bm_patt *)MPOOL_CALLOC(engine->mempool, 1, sizeof(struct cli_bm_patt)); |
288057e9 |
if (!new) {
ret = CL_EMEM;
break;
} |
544fa973 |
new->pattern = (unsigned char *)CLI_MPOOL_STRDUP(engine->mempool, signame); |
288057e9 |
if (!new->pattern) { |
544fa973 |
MPOOL_FREE(engine->mempool, new); |
288057e9 |
ret = CL_EMEM;
break;
}
if (hash) { |
544fa973 |
if (strlen(hash) != 32 || !(new->virname = CLI_MPOOL_HEX2STR(engine->mempool, hash))) { |
288057e9 |
cli_errmsg("cli_loadign: Malformed MD5 string at line %u\n", line); |
544fa973 |
MPOOL_FREE(engine->mempool, new->pattern);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
ret = CL_EMALFDB;
break;
}
}
new->length = len;
new->boundary |= BM_BOUNDARY_EOL;
|
102cd430 |
if (CL_SUCCESS != (ret = cli_bm_addpatt(engine->ignored, new, "0"))) { |
288057e9 |
if (hash) |
544fa973 |
MPOOL_FREE(engine->mempool, new->virname);
MPOOL_FREE(engine->mempool, new->pattern);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
break;
}
}
if (ret) {
cli_errmsg("cli_loadign: Problem parsing database at line %u\n", line);
return ret; |
ed9753e9 |
}
return CL_SUCCESS;
}
|
288057e9 |
#define MD5_HDB 0
#define MD5_MDB 1
#define MD5_FP 2
#define MD5_IMP 3 |
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; |
288057e9 |
int ret = CL_SUCCESS; |
e37613ad |
unsigned int size_field = 1, md5_field = 0, line = 0, sigs = 0, tokens_count; |
288057e9 |
unsigned int req_fl = 0; |
e37613ad |
struct cli_matcher *db;
unsigned long size; |
c802edd5 |
|
288057e9 |
if (mode == MD5_MDB) {
size_field = 0;
md5_field = 1;
db = engine->hm_mdb;
} else if (mode == MD5_HDB)
db = engine->hm_hdb;
else if (mode == MD5_IMP)
db = engine->hm_imp; |
004735cb |
else |
288057e9 |
db = engine->hm_fp; |
004735cb |
|
288057e9 |
if (!db) { |
544fa973 |
if (!(db = MPOOL_CALLOC(engine->mempool, 1, sizeof(*db)))) |
288057e9 |
return CL_EMEM; |
004735cb |
#ifdef USE_MPOOL |
288057e9 |
db->mempool = engine->mempool; |
004735cb |
#endif |
288057e9 |
if (mode == MD5_HDB)
engine->hm_hdb = db;
else if (mode == MD5_MDB)
engine->hm_mdb = db;
else if (mode == MD5_IMP)
engine->hm_imp = db;
else
engine->hm_fp = db;
}
if (engine->ignored)
if (!(buffer_cpy = cli_malloc(FILEBUFF))) {
cli_errmsg("cli_loadhash: Can't allocate memory for buffer_cpy\n");
return CL_EMEM;
}
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, ':', MD5_TOKENS + 1, tokens);
if (tokens_count < 3) {
ret = CL_EMALFDB;
break;
}
if (tokens_count > MD5_TOKENS - 2) {
req_fl = atoi(tokens[MD5_TOKENS - 2]);
if (tokens_count > MD5_TOKENS) {
ret = CL_EMALFDB;
break;
}
if (cl_retflevel() < req_fl)
continue;
if (tokens_count == MD5_TOKENS) {
int max_fl = atoi(tokens[MD5_TOKENS - 1]);
if (cl_retflevel() > (unsigned int)max_fl)
continue;
}
}
|
afe940da |
if (strcmp(tokens[size_field], "*")) { |
288057e9 |
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; |
afe940da |
// The wildcard feature was added in FLEVEL 73, so for backwards
// compatibility with older clients, ensure that a minimum FLEVEL
// is specified. This check doesn't apply to .imp rules, though,
// since this rule category wasn't introduced until FLEVEL 90, and
// has always supported wildcard usage in rules.
if (mode != MD5_IMP && ((tokens_count < MD5_TOKENS - 1) || (req_fl < 73))) { |
288057e9 |
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;
}
}
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++;
if (engine->cb_sigload(dot, pt, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) {
cli_dbgmsg("cli_loadhash: skipping %s (%s) due to callback\n", pt, dot);
continue;
}
}
|
544fa973 |
virname = CLI_MPOOL_VIRNAME(engine->mempool, pt, options & CL_DB_OFFICIAL); |
288057e9 |
if (!virname) {
ret = CL_EMALFDB;
break;
}
|
102cd430 |
if (CL_SUCCESS != (ret = hm_addhash_str(db, tokens[md5_field], size, virname))) { |
288057e9 |
cli_errmsg("cli_loadhash: Malformed hash string at line %u\n", line); |
544fa973 |
MPOOL_FREE(engine->mempool, (void *)virname); |
288057e9 |
break;
}
sigs++;
}
if (engine->ignored)
free(buffer_cpy);
if (!line) {
cli_errmsg("cli_loadhash: Empty database file\n");
return CL_EMALFDB;
}
if (ret) {
cli_errmsg("cli_loadhash: Problem parsing database at line %u\n", line);
return ret;
}
if (signo)
*signo += sigs; |
c802edd5 |
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 |
{ |
288057e9 |
const char *tokens[MD_TOKENS + 1];
char buffer[FILEBUFF], *buffer_cpy = NULL;
unsigned int line = 0, sigs = 0, tokens_count;
int ret = CL_SUCCESS;
struct cli_cdb *new; |
e5916a51 |
|
cd94be7a |
UNUSEDPARAM(dbname); |
e5916a51 |
|
288057e9 |
if (engine->ignored)
if (!(buffer_cpy = cli_malloc(FILEBUFF))) {
cli_errmsg("cli_loadmd: Can't allocate memory for buffer_cpy\n");
return CL_EMEM;
}
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, ':', MD_TOKENS + 1, tokens);
if (tokens_count != MD_TOKENS) {
ret = CL_EMALFDB;
break;
}
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;
}
|
544fa973 |
new = (struct cli_cdb *)MPOOL_CALLOC(engine->mempool, 1, sizeof(struct cli_cdb)); |
288057e9 |
if (!new) {
ret = CL_EMEM;
break;
}
|
544fa973 |
new->virname = CLI_MPOOL_VIRNAME(engine->mempool, tokens[0], options & CL_DB_OFFICIAL); |
288057e9 |
if (!new->virname) { |
544fa973 |
MPOOL_FREE(engine->mempool, new); |
288057e9 |
ret = CL_EMEM;
break;
}
new->ctype = (type == 1) ? CL_TYPE_ZIP : CL_TYPE_RAR;
if (engine->ignored && cli_chkign(engine->ignored, new->virname, buffer /*_cpy*/)) { |
544fa973 |
MPOOL_FREE(engine->mempool, new->virname);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
continue;
}
if (engine->cb_sigload && engine->cb_sigload("md", new->virname, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) {
cli_dbgmsg("cli_loadmd: skipping %s due to callback\n", new->virname); |
544fa973 |
MPOOL_FREE(engine->mempool, new->virname);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
continue;
}
new->encrypted = strcmp(tokens[1], "*") ? atoi(tokens[1]) : 2;
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]); |
544fa973 |
MPOOL_FREE(engine->mempool, new->virname);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
ret = CL_EMEM;
break;
}
new->csize[0] = new->csize[1] = CLI_OFF_ANY;
if (!strcmp(tokens[3], "*"))
new->fsizer[0] = new->fsizer[1] = CLI_OFF_ANY;
else
new->fsizer[0] = new->fsizer[1] = atoi(tokens[3]);
if (!strcmp(tokens[4], "*"))
new->fsizec[0] = new->fsizec[1] = CLI_OFF_ANY;
else
new->fsizec[0] = new->fsizec[1] = atoi(tokens[4]);
if (strcmp(tokens[5], "*")) {
new->res1 = cli_hex2num(tokens[5]);
if (new->res1 == -1) { |
544fa973 |
MPOOL_FREE(engine->mempool, new->virname);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
if (new->name.re_magic)
cli_regfree(&new->name);
ret = CL_EMALFDB;
break;
}
}
/* tokens[6] - not used */
new->filepos[0] = new->filepos[1] = strcmp(tokens[7], "*") ? (unsigned int)atoi(tokens[7]) : (unsigned int)CLI_OFF_ANY;
/* tokens[8] - not used */
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 %d\n", line);
return ret;
}
if (signo)
*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)
{ |
288057e9 |
const char *tokens[CDB_TOKENS + 1];
char buffer[FILEBUFF], *buffer_cpy = NULL;
unsigned int line = 0, sigs = 0, tokens_count, n0, n1;
int ret = CL_SUCCESS;
struct cli_cdb *new;
if (engine->ignored)
if (!(buffer_cpy = cli_malloc(FILEBUFF))) {
cli_errmsg("cli_loadcdb: Can't allocate memory for buffer_cpy\n");
return CL_EMEM;
}
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);
if (tokens_count > CDB_TOKENS || tokens_count < CDB_TOKENS - 2) {
ret = CL_EMALFDB;
break;
}
if (tokens_count > 10) { /* min version */
if (!cli_isnumber(tokens[10])) {
ret = CL_EMALFDB;
break;
}
if ((unsigned int)atoi(tokens[10]) > cl_retflevel()) {
cli_dbgmsg("cli_loadcdb: Container signature for %s not loaded (required f-level: %u)\n", tokens[0], atoi(tokens[10]));
continue;
}
if (tokens_count == CDB_TOKENS) { /* max version */
if (!cli_isnumber(tokens[11])) {
ret = CL_EMALFDB;
break;
}
if ((unsigned int)atoi(tokens[11]) < cl_retflevel())
continue;
}
}
|
544fa973 |
new = (struct cli_cdb *)MPOOL_CALLOC(engine->mempool, 1, sizeof(struct cli_cdb)); |
288057e9 |
if (!new) {
ret = CL_EMEM;
break;
}
|
544fa973 |
new->virname = CLI_MPOOL_VIRNAME(engine->mempool, tokens[0], options & CL_DB_OFFICIAL); |
288057e9 |
if (!new->virname) { |
544fa973 |
MPOOL_FREE(engine->mempool, new); |
288057e9 |
ret = CL_EMEM;
break;
}
if (engine->ignored && cli_chkign(engine->ignored, new->virname, buffer /*_cpy*/)) { |
544fa973 |
MPOOL_FREE(engine->mempool, new->virname);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
continue;
}
if (engine->cb_sigload && engine->cb_sigload("cdb", new->virname, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) {
cli_dbgmsg("cli_loadcdb: skipping %s due to callback\n", new->virname); |
544fa973 |
MPOOL_FREE(engine->mempool, new->virname);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
continue;
}
if (!strcmp(tokens[1], "*")) {
new->ctype = CL_TYPE_ANY;
} else if ((new->ctype = cli_ftcode(tokens[1])) == CL_TYPE_ERROR) {
cli_errmsg("cli_loadcdb: Unknown container type %s in signature for %s, skipping\n", tokens[1], tokens[0]); |
fd0ad260 |
ret = CL_EMALFDB; |
544fa973 |
MPOOL_FREE(engine->mempool, new->virname);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
break;
}
if (strcmp(tokens[3], "*") && cli_regcomp(&new->name, tokens[3], REG_EXTENDED | REG_NOSUB)) {
cli_errmsg("cli_loadcdb: Can't compile regular expression %s in signature for %s\n", tokens[3], tokens[0]); |
544fa973 |
MPOOL_FREE(engine->mempool, new->virname);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
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] = (unsigned int)atoi(token_str); \
} \
if (ret != CL_SUCCESS) { \
cli_errmsg("cli_loadcdb: Invalid value %s in signature for %s\n", \
token_str, tokens[0]); \
if (new->name.re_magic) \
cli_regfree(&new->name); \ |
544fa973 |
MPOOL_FREE(engine->mempool, new->virname); \
MPOOL_FREE(engine->mempool, new); \ |
288057e9 |
ret = CL_EMEM; \
break; \
} \
} else { \
dest[0] = dest[1] = CLI_OFF_ANY; \
}
CDBRANGE(tokens[2], new->csize);
CDBRANGE(tokens[4], new->fsizec);
CDBRANGE(tokens[5], new->fsizer);
CDBRANGE(tokens[7], new->filepos);
if (!strcmp(tokens[6], "*")) {
new->encrypted = 2;
} else {
if (strcmp(tokens[6], "0") && strcmp(tokens[6], "1")) {
cli_errmsg("cli_loadcdb: Invalid encryption flag value in signature for %s\n", tokens[0]);
if (new->name.re_magic)
cli_regfree(&new->name); |
544fa973 |
MPOOL_FREE(engine->mempool, new->virname);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
ret = CL_EMEM;
break;
}
new->encrypted = *tokens[6] - 0x30;
}
if (strcmp(tokens[9], "*")) { |
544fa973 |
new->res2 = CLI_MPOOL_STRDUP(engine->mempool, tokens[9]); |
288057e9 |
if (!new->res2) {
cli_errmsg("cli_loadcdb: Can't allocate memory for res2 in signature for %s\n", tokens[0]);
if (new->name.re_magic)
cli_regfree(&new->name); |
544fa973 |
MPOOL_FREE(engine->mempool, new->virname);
MPOOL_FREE(engine->mempool, new); |
288057e9 |
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; |
55094a9c |
return CL_SUCCESS;
}
|
c31a98d5 |
/* |
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 |
288057e9 |
static int cli_loadcrt(FILE *fs, struct cl_engine *engine, struct cli_dbio *dbio)
{ |
d12f1646 |
char buffer[FILEBUFF]; |
288057e9 |
char *tokens[CRT_TOKENS + 1];
size_t line = 0, tokens_count; |
d12f1646 |
cli_crt ca; |
288057e9 |
int ret = CL_SUCCESS;
char *subject = NULL, *pubkey = NULL, *serial = NULL; |
d12f1646 |
const uint8_t exp[] = "\x01\x00\x01";
|
d92c0129 |
if (!(engine->dconf->pe & PE_CONF_CERTS)) {
cli_dbgmsg("cli_loadcrt: Ignoring .crb sigs due to DCONF configuration\n");
return ret;
}
if (engine->engine_options & ENGINE_OPTIONS_DISABLE_PE_CERTS) {
cli_dbgmsg("cli_loadcrt: Ignoring .crb sigs due to engine options\n");
return ret;
}
|
d12f1646 |
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) { |
288057e9 |
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;
} |
288057e9 |
if ((unsigned int)atoi(tokens[CRT_TOKENS - 1]) > cl_retflevel()) { |
ee07fcd6 |
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)); |
288057e9 |
if (mp_read_unsigned_bin(&(ca.n), (const unsigned char *)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]); |
288057e9 |
ca.not_after = (-1U) >> 1; |
d12f1646 |
|
a133cd8e |
ca.hashtype = CLI_HASHTYPE_ANY; |
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;
}
|
288057e9 |
static int cli_loadmscat(FILE *fs, const char *dbname, struct cl_engine *engine, unsigned int options, struct cli_dbio *dbio)
{ |
5d49bd06 |
fmap_t *map;
|
cd94be7a |
UNUSEDPARAM(options);
UNUSEDPARAM(dbio);
|
d92c0129 |
/* If loading in signatures stored in .cat files is disabled, then skip.
* If Authenticoded signature parsing in general is disabled, then also
* skip. */
if (!(engine->dconf->pe & PE_CONF_CATALOG) || !(engine->dconf->pe & PE_CONF_CERTS)) {
cli_dbgmsg("cli_loadmscat: Ignoring .cat sigs due to DCONF configuration\n");
return 0;
}
if (engine->engine_options & ENGINE_OPTIONS_DISABLE_PE_CERTS) {
cli_dbgmsg("cli_loadmscat: Ignoring .cat sigs due to engine options\n");
return 0;
}
|
288057e9 |
if (!(map = fmap(fileno(fs), 0, 0))) {
cli_dbgmsg("Can't map cat: %s\n", dbname);
return 0; |
ccb37138 |
} |
5d49bd06 |
|
288057e9 |
if (asn1_load_mscat(map, engine))
cli_dbgmsg("Failed to load certificates from cat: %s\n", dbname); |
5d49bd06 |
funmap(map); |
5b48b665 |
return 0;
}
|
ad8ddf98 |
static int cli_loadopenioc(FILE *fs, const char *dbname, struct cl_engine *engine, unsigned int options) |
2abe7362 |
{
int rc; |
ad8ddf98 |
rc = openioc_parse(dbname, fileno(fs), engine, options); |
2abe7362 |
if (rc != CL_SUCCESS)
return CL_EMALFDB; |
53506979 |
return rc; |
2abe7362 |
}
|
baeb6253 |
#ifdef HAVE_YARA |
1215ac0f |
#define YARA_DEBUG 1 |
5765c290 |
#if (YARA_DEBUG == 2) |
f4265e07 |
#define cli_yaramsg(...) cli_errmsg(__VA_ARGS__) |
5765c290 |
#elif (YARA_DEBUG == 1) |
f4265e07 |
#define cli_yaramsg(...) cli_dbgmsg(__VA_ARGS__)
#else |
288057e9 |
#define cli_yaramsg(...) |
f4265e07 |
#endif
|
a576a036 |
static char *parse_yara_hex_string(YR_STRING *string, int *ret); |
8faddbe6 |
|
a576a036 |
static char *parse_yara_hex_string(YR_STRING *string, int *ret) |
8faddbe6 |
{ |
06bd11e1 |
char *res, *str, *ovr; |
288057e9 |
size_t slen, reslen = 0, i, j; |
8faddbe6 |
|
a576a036 |
if (!(string) || !(string->string)) {
if (ret) *ret = CL_ENULLARG; |
8faddbe6 |
return NULL; |
a576a036 |
} |
8faddbe6 |
|
a576a036 |
if (!STRING_IS_HEX(string)) {
if (ret) *ret = CL_EARG; |
8faddbe6 |
return NULL; |
a576a036 |
} |
8faddbe6 |
|
5e8993e9 |
str = (char *)(string->string); |
8faddbe6 |
|
4d1a9fa5 |
if ((slen = string->length) == 0) { |
a576a036 |
if (ret) *ret = CL_EARG; |
f2da4b5b |
return NULL; |
a576a036 |
} |
f2da4b5b |
|
288057e9 |
str = strchr(str, '{') + 1; |
f2da4b5b |
|
288057e9 |
for (i = 0; i < slen - 1; i++) { |
f2da4b5b |
switch (str[i]) { |
288057e9 |
case ' ':
case '\t':
case '\r':
case '\n':
case '}': /* end of hex string */
break;
default:
reslen++;
break; |
8faddbe6 |
}
}
|
f2da4b5b |
reslen++;
res = cli_calloc(reslen, 1); |
a576a036 |
if (!(res)) {
if (ret) *ret = CL_EMEM; |
f2da4b5b |
return NULL; |
a576a036 |
} |
5e8993e9 |
|
288057e9 |
for (i = 0, j = 0; i < slen - 1 && j < reslen; i++) { |
f2da4b5b |
switch (str[i]) { |
288057e9 |
case ' ':
case '\t':
case '\r':
case '\n':
case '}':
break;
case '[':
/* unbounded range check */
if ((i + 2 < slen - 1) && (str[i + 1] == '-') && (str[i + 2] == ']')) {
res[j++] = '*';
i += 2;
} else {
res[j++] = '{';
}
break;
case ']':
res[j++] = '}';
break;
default:
res[j++] = str[i];
break; |
5e8993e9 |
} |
8faddbe6 |
}
|
c31a98d5 |
/* FIXME: removing this code because anchored bytes are not sufficiently |
0ea036ad |
general for the purposes of yara rule to ClamAV sig conversions.
1. ClamAV imposes a maximum value for the upper range limit of 32:
#define AC_CH_MAXDIST 32
Values larger cause an error in matcher-ac.c
2. If the upper range values is not present, ClamAV sets the missing
range value to be equal to the lower range value. This changes the
semantic of yara jumps.
*/
#ifdef YARA_ANCHOR_SUPPORT |
06bd11e1 |
/* backward anchor overwrite, 2 (hex chars in one byte) */
if ((ovr = strchr(res, '{')) && ((ovr - res) == 2)) {
*ovr = '[';
if ((ovr = strchr(ovr, '}')))
*ovr = ']';
else { |
628c2bbb |
free(res); |
06bd11e1 |
if (ret) *ret = CL_EMALFDB;
return NULL;
}
}
/* forward anchor overwrite, 2 (hex chars in one byte) +1 (NULL char) */ |
288057e9 |
if ((ovr = strrchr(res, '}')) && ((res + j - ovr) == 3)) { |
06bd11e1 |
*ovr = ']';
if ((ovr = strrchr(res, '{')))
*ovr = '[';
else { |
628c2bbb |
free(res); |
06bd11e1 |
if (ret) *ret = CL_EMALFDB;
return NULL;
}
} |
0ea036ad |
#else
if (((ovr = strchr(res, '{')) && ((ovr - res) == 2)) || |
288057e9 |
((ovr = strrchr(res, '}')) && ((res + j - ovr) == 3))) { |
0ea036ad |
cli_errmsg("parse_yara_hex_string: Single byte subpatterns unsupported in ClamAV\n");
free(res);
if (ret != NULL)
*ret = CL_EMALFDB;
return NULL;
}
#endif |
06bd11e1 |
|
a576a036 |
if (ret)
*ret = CL_SUCCESS; |
f2da4b5b |
return res; |
8faddbe6 |
}
|
5765c290 |
struct cli_ytable_entry {
char *offset;
char *hexstr; |
dc70379a |
uint8_t sigopts; |
5765c290 |
}; |
f4265e07 |
|
5765c290 |
struct cli_ytable {
struct cli_ytable_entry **table; |
c58e2fdb |
int32_t tbl_cnt; |
5765c290 |
}; |
f4265e07 |
|
39e05dbd |
static int32_t ytable_lookup(const char *hexsig) |
c58e2fdb |
{ |
288057e9 |
(void)hexsig; |
c58e2fdb |
/* TODO - WRITE ME! */
return -1;
}
|
102cd430 |
static cl_error_t ytable_add_attrib(struct cli_ytable *ytable, const char *hexsig, const char *value, int type) |
c58e2fdb |
{
int32_t lookup;
if (!ytable || !value)
return CL_ENULLARG;
if (!hexsig) |
288057e9 |
lookup = ytable->tbl_cnt - 1; /* assuming to attach to current string */ |
c58e2fdb |
else
lookup = ytable_lookup(hexsig);
if (lookup < 0) { |
a684f7d8 |
cli_yaramsg("ytable_add_attrib: hexsig cannot be found\n"); |
c58e2fdb |
return CL_EARG;
}
|
a684f7d8 |
if (type) { |
dc70379a |
/* add to sigopts */
switch (*value) { |
288057e9 |
case 'i':
ytable->table[lookup]->sigopts |= ACPATT_OPTION_NOCASE;
break;
case 'f':
ytable->table[lookup]->sigopts |= ACPATT_OPTION_FULLWORD;
break;
case 'w':
ytable->table[lookup]->sigopts |= ACPATT_OPTION_WIDE;
break;
case 'a':
ytable->table[lookup]->sigopts |= ACPATT_OPTION_ASCII;
break;
default:
cli_yaramsg("ytable_add_attrib: invalid sigopt %02x\n", *value);
return CL_EARG; |
a684f7d8 |
} |
288057e9 |
} else { |
a684f7d8 |
/* overwrite the previous offset */
if (ytable->table[lookup]->offset)
free(ytable->table[lookup]->offset); |
c58e2fdb |
|
a684f7d8 |
ytable->table[lookup]->offset = cli_strdup(value);
if (!ytable->table[lookup]->offset) {
cli_yaramsg("ytable_add_attrib: ran out of memory for offset\n");
return CL_EMEM;
} |
c58e2fdb |
}
return CL_SUCCESS;
}
|
39e05dbd |
/* function is dumb - TODO - rewrite using hashtable */
static int ytable_add_string(struct cli_ytable *ytable, const char *hexsig)
{
struct cli_ytable_entry *new;
struct cli_ytable_entry **newtable;
int ret;
if (!ytable || !hexsig)
return CL_ENULLARG;
new = cli_calloc(1, sizeof(struct cli_ytable_entry));
if (!new) {
cli_yaramsg("ytable_add_string: out of memory for new ytable entry\n");
return CL_EMEM;
}
new->hexstr = cli_strdup(hexsig);
if (!new->hexstr) {
cli_yaramsg("ytable_add_string: out of memory for hexsig copy\n");
free(new);
return CL_EMEM;
}
ytable->tbl_cnt++;
newtable = cli_realloc(ytable->table, ytable->tbl_cnt * sizeof(struct cli_ytable_entry *));
if (!newtable) {
cli_yaramsg("ytable_add_string: failed to reallocate new ytable table\n");
free(new->hexstr);
free(new);
ytable->tbl_cnt--;
return CL_EMEM;
}
|
288057e9 |
newtable[ytable->tbl_cnt - 1] = new;
ytable->table = newtable; |
39e05dbd |
|
102cd430 |
if (CL_SUCCESS != (ret = ytable_add_attrib(ytable, NULL, "*", 0)) != CL_SUCCESS) { |
39e05dbd |
cli_yaramsg("ytable_add_string: failed to add default offset\n");
free(new->hexstr);
free(new);
ytable->tbl_cnt--;
return ret;
}
return CL_SUCCESS;
}
static void ytable_delete(struct cli_ytable *ytable) |
f4265e07 |
{ |
d0cba11e |
int32_t i; |
5765c290 |
if (!ytable)
return; |
f4265e07 |
|
5765c290 |
if (ytable->table) { |
c58e2fdb |
for (i = 0; i < ytable->tbl_cnt; ++i) {
free(ytable->table[i]->offset);
free(ytable->table[i]->hexstr); |
5765c290 |
free(ytable->table[i]); |
c58e2fdb |
} |
5765c290 |
free(ytable->table); |
f4265e07 |
}
}
|
16d69534 |
/* should only operate on HEX STRINGS */ |
e8ab1083 |
static int yara_hexstr_verify(YR_STRING *string, const char *hexstr, uint32_t *lsigid, struct cl_engine *engine, unsigned int options) |
16d69534 |
{
int ret = CL_SUCCESS;
/* Quick Check 1: NULL String */
if (!hexstr || !string) {
cli_warnmsg("load_oneyara[verify]: string is empty\n");
return CL_ENULLARG;
}
/* Quick Check 2: String Too Short */ |
288057e9 |
if (strlen(hexstr) / 2 < CLI_DEFAULT_AC_MINDEPTH) { |
e8ab1083 |
cli_warnmsg("load_oneyara[verify]: string is too short: %s\n", string->identifier); |
16d69534 |
return CL_EMALFDB;
}
|
e8ab1083 |
/* Long Check: Attempt to load hexstr */ |
102cd430 |
if (CL_SUCCESS != (ret = cli_sigopts_handler(engine->test_root, "test-hex", hexstr, 0, 0, 0, "*", 0, lsigid, options)) != CL_SUCCESS) { |
e8ab1083 |
if (ret == CL_EMALFDB) {
cli_warnmsg("load_oneyara[verify]: recovered from database loading error\n");
/* TODO: if necessary, reset testing matcher if error occurs */
cli_warnmsg("load_oneyara[verify]: string failed test insertion: %s\n", string->identifier); |
bcf780fc |
} |
e8ab1083 |
return ret; |
16d69534 |
}
|
bcf780fc |
return CL_SUCCESS; |
16d69534 |
}
|
94ac324e |
static unsigned int yara_total, yara_loaded, yara_malform, yara_empty, yara_complex; |
f4265e07 |
#define YARATARGET0 "Target:0"
#define YARATARGET1 "Target:1"
#define EPSTR "EP+0:" |
e9b611f8 |
|
f4265e07 |
/* yara has no apparent cap on the number of strings; TODO - should we have one? */
/* function base off load_oneldb */ |
5adf3903 |
static int load_oneyara(YR_RULE *rule, int chkpua, struct cl_engine *engine, unsigned int options, unsigned int *sigs) |
186d22d1 |
{ |
f4265e07 |
YR_STRING *string; |
ddc4030f |
struct cli_ytable ytable; |
d0cba11e |
size_t i;
int str_error = 0, ret = CL_SUCCESS; |
f4265e07 |
struct cli_lsig_tdb tdb;
uint32_t lsigid[2];
struct cli_matcher *root; |
e8ab1083 |
struct cli_ac_lsig **newtable, *lsig, *tsig = NULL; |
f4265e07 |
unsigned short target = 0; |
a684f7d8 |
char *logic = NULL, *target_str = NULL; |
3fdd7d01 |
char *newident = NULL; |
288057e9 |
/* size_t lsize; */ // only used in commented out code
/* char *exp_op = "|"; */ // only used in commented out code |
ade8279c |
|
7f749109 |
cli_yaramsg("load_oneyara: attempting to load %s\n", rule->identifier); |
6e767879 |
|
f4265e07 |
if (!rule) {
cli_errmsg("load_oneyara: empty rule passed as argument\n");
return CL_ENULLARG;
} |
ade8279c |
|
5adf3903 |
/* PUA and IGN checks */
if (chkpua && cli_chkpua(rule->identifier, engine->pua_cats, options)) |
f4265e07 |
return CL_SUCCESS;
|
5adf3903 |
if (engine->ignored && cli_chkign(engine->ignored, rule->identifier, rule->identifier)) { |
f4265e07 |
return CL_SUCCESS;
} |
311a0b10 |
|
3fdd7d01 |
newident = cli_malloc(strlen(rule->identifier) + 5 + 1); |
288057e9 |
if (!newident) { |
0ae43cf3 |
cli_errmsg("cli_loadyara(): newident == NULL\n");
return CL_EMEM; |
3fdd7d01 |
}
|
0ae43cf3 |
snprintf(newident, strlen(rule->identifier) + 5 + 1, "YARA.%s", rule->identifier); |
3fdd7d01 |
|
288057e9 |
if (engine->cb_sigload && engine->cb_sigload("yara", newident, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) { |
3fdd7d01 |
cli_dbgmsg("cli_loadyara: skipping %s due to callback\n", newident);
free(newident); |
311a0b10 |
(*sigs)--;
return CL_SUCCESS;
} |
5adf3903 |
memset(&ytable, 0, sizeof(ytable)); |
f4265e07 |
/*** rule specific checks ***/ |
bec92cfc |
#ifdef YARA_FINISHED
if (RULE_IS_PRIVATE(rule)) {
cli_warnmsg("load_oneyara: private modifier for yara rule is unsupported\n");
cli_yaramsg("RULE_IS_PRIVATE yes\n");
}
if (RULE_IS_GLOBAL(rule)) {
cli_warnmsg("load_oneyara: global modifier for yara rule is unsupported\n");
cli_yaramsg("RULE_IS_GLOBAL yes\n");
}
if ((rule->g_flags) & RULE_GFLAGS_REQUIRE_FILE) {
cli_warnmsg("load_oneyara: RULE_GFLAGS_REQUIRE_FILE for yara rule is unsupported\n");
cli_yaramsg("RULE_GFLAGS_REQUIRE_FILE yes\n");
}
if (RULE_IS_NULL(rule) || ((rule->g_flags) & RULE_GFLAGS_REQUIRE_EXECUTABLE)) { |
f4265e07 |
|
3fdd7d01 |
cli_warnmsg("load_oneyara: skipping %s due to unsupported rule gflags\n", newident); |
5765c290 |
cli_yaramsg("RULE_IS_NULL %s\n", RULE_IS_NULL(rule) ? "yes" : "no");
cli_yaramsg("RULE_GFLAGS_REQUIRE_EXECUTABLE %s\n", ((rule->g_flags) & RULE_GFLAGS_REQUIRE_EXECUTABLE) ? "yes" : "no");
|
3fdd7d01 |
free(newident); |
f4265e07 |
(*sigs)--;
return CL_SUCCESS;
} |
f88cffca |
#else
/*
cli_warnmsg("load_oneyara: yara support is incomplete, rule flags are ignored\n");
if (RULE_IS_PRIVATE(rule))
cli_yaramsg("RULE_IS_PRIVATE yes\n");
if (RULE_IS_GLOBAL(rule))
cli_yaramsg("RULE_IS_GLOBAL yes\n");
if (RULE_IS_NULL(rule))
cli_yaramsg("RULE_IS_NULL yes\n");
if ((rule->g_flags) & RULE_GFLAGS_REQUIRE_FILE)
cli_yaramsg("RULE_GFLAGS_REQUIRE_FILE yes\n");
if ((rule->g_flags) & RULE_GFLAGS_REQUIRE_EXECUTABLE)
cli_yaramsg("RULE_GFLAGS_REQUIRE_EXECUTABLE yes\n");
*/ |
bec92cfc |
#endif |
f4265e07 |
|
288057e9 |
if (engine->cb_sigload && engine->cb_sigload("yara", newident, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) { |
3fdd7d01 |
cli_dbgmsg("load_oneyara: skipping %s due to callback\n", newident); |
f4265e07 |
(*sigs)--; |
3fdd7d01 |
free(newident); |
f4265e07 |
return CL_SUCCESS;
}
/*** verification step - can clamav load it? ***/
/*** initial population pass for the strings table ***/ |
288057e9 |
STAILQ_FOREACH(string, &rule->strings, link)
{ |
a576a036 |
char *substr = NULL; |
f4265e07 |
/* string type handler */
if (STRING_IS_NULL(string)) { |
3fdd7d01 |
cli_warnmsg("load_oneyara: skipping NULL string %s\n", newident); |
f4265e07 |
//str_error++; /* kill the insertion? */
continue; |
bec92cfc |
#ifdef YARA_FINISHED
} else if (STRING_IS_LITERAL(string)) {
/* TODO - handle literal strings, short-circuits other string type handling */ |
abec1002 |
cli_yaramsg("load_oneyara: literal string: [%.*s] => [%s]\n", string->length, string->string, substr); |
f88cffca |
#else
} else if (STRING_IS_LITERAL(string)) {
cli_errmsg("load_oneyara: literal strings are unsupported, reorganize existing code\n"); |
bec92cfc |
#endif |
f4265e07 |
} else if (STRING_IS_HEX(string)) { |
a576a036 |
substr = parse_yara_hex_string(string, &ret);
if (ret != CL_SUCCESS) {
cli_errmsg("load_oneyara: error in parsing yara hex string\n");
str_error++;
break;
} |
a684f7d8 |
|
16d69534 |
/* handle lack of hexstr support here in order to suppress */ |
7cd9337a |
/* initialize testing matcher */ |
e8ab1083 |
if (!engine->test_root) { |
544fa973 |
engine->test_root = (struct cli_matcher *)MPOOL_CALLOC(engine->mempool, 1, sizeof(struct cli_matcher)); |
e8ab1083 |
if (!engine->test_root) {
cli_errmsg("load_oneyara[verify]: cannot allocate memory for test cli_matcher\n"); |
50876732 |
free(substr); |
e8ab1083 |
return CL_EMEM;
}
#ifdef USE_MPOOL
engine->test_root->mempool = engine->mempool;
#endif |
102cd430 |
if (CL_SUCCESS != (ret = cli_ac_init(engine->test_root, engine->ac_mindepth, engine->ac_maxdepth, engine->dconf->other & OTHER_CONF_PREFILTERING))) { |
e8ab1083 |
cli_errmsg("load_oneyara: cannot initialize test ac root\n"); |
50876732 |
free(substr); |
e8ab1083 |
return ret;
}
}
/* generate a test lsig if one does not exist */
if (!tsig) {
/*** populating lsig ***/ |
544fa973 |
tsig = (struct cli_ac_lsig *)MPOOL_CALLOC(engine->mempool, 1, sizeof(struct cli_ac_lsig)); |
288057e9 |
if (!tsig) { |
e8ab1083 |
cli_errmsg("load_oneyara: cannot allocate memory for test lsig\n"); |
50876732 |
free(substr); |
e8ab1083 |
return CL_EMEM;
}
root = engine->test_root;
tsig->type = CLI_YARA_NORMAL;
lsigid[0] = tsig->id = root->ac_lsigs;
root->ac_lsigs++; |
544fa973 |
newtable = (struct cli_ac_lsig **)MPOOL_REALLOC(engine->mempool, root->ac_lsigtable, root->ac_lsigs * sizeof(struct cli_ac_lsig *)); |
288057e9 |
if (!newtable) { |
e8ab1083 |
root->ac_lsigs--;
cli_errmsg("load_oneyara: cannot allocate test root->ac_lsigtable\n"); |
544fa973 |
MPOOL_FREE(engine->mempool, tsig); |
50876732 |
free(substr); |
e8ab1083 |
return CL_EMEM;
}
newtable[root->ac_lsigs - 1] = tsig; |
288057e9 |
root->ac_lsigtable = newtable; |
e8ab1083 |
}
/* attempt to insert hexsig */
lsigid[1] = 0; |
288057e9 |
ret = yara_hexstr_verify(string, substr, lsigid, engine, options); |
16d69534 |
if (ret != CL_SUCCESS) { |
a576a036 |
str_error++; |
b62dd1dd |
free(substr); |
16d69534 |
break; |
f901b0ad |
} |
a576a036 |
|
abec1002 |
cli_yaramsg("load_oneyara: hex string: [%.*s] => [%s]\n", string->length, string->string, substr); |
a576a036 |
ytable_add_string(&ytable, substr);
free(substr); |
f4265e07 |
} else if (STRING_IS_REGEXP(string)) { |
b62dd1dd |
/* TODO - rewrite to NOT use PCRE_BYPASS */ |
311a0b10 |
#if HAVE_PCRE |
4d1a9fa5 |
size_t length = strlen(PCRE_BYPASS) + string->length + 3; |
b62dd1dd |
substr = cli_calloc(length, sizeof(char));
if (!substr) {
cli_errmsg("load_oneyara: cannot allocate memory for converted regex string\n");
str_error++;
ret = CL_EMEM;
break;
}
|
abec1002 |
snprintf(substr, length, "%s/%.*s/", PCRE_BYPASS, string->length, string->string); |
b62dd1dd |
|
abec1002 |
cli_yaramsg("load_oneyara: regex string: [%.*s] => [%s]\n", string->length, string->string, substr); |
b62dd1dd |
ytable_add_string(&ytable, substr);
free(substr); |
311a0b10 |
#else |
3fdd7d01 |
cli_warnmsg("cli_loadyara: %s uses PCREs but support is disabled\n", newident); |
311a0b10 |
str_error++;
ret = CL_SUCCESS;
break;
#endif |
f4265e07 |
} else { |
b6731915 |
/* TODO - extract the string length to handle NULL hex-escaped characters
* For now, we'll just use the strlen we get which crudely finds the length
*/ |
288057e9 |
size_t length = string->length;
size_t totsize = 2 * length + 1; |
b6731915 |
|
f88cffca |
if (length < CLI_DEFAULT_AC_MINDEPTH) { |
3fdd7d01 |
cli_warnmsg("load_oneyara: string is too short %s\n", newident); |
b6731915 |
str_error++;
continue;
}
substr = cli_calloc(totsize, sizeof(char));
if (!substr) {
cli_errmsg("load_oneyara: cannot allocate memory for converted generic string\n");
str_error++;
ret = CL_EMEM;
break;
}
|
288057e9 |
for (i = 0; i < length; ++i) { |
b6731915 |
size_t len = strlen(substr); |
288057e9 |
snprintf(substr + len, totsize - len, "%02x", string->string[i]); |
b6731915 |
}
|
abec1002 |
cli_yaramsg("load_oneyara: generic string: [%.*s] => [%s]\n", string->length, string->string, substr); |
b6731915 |
ytable_add_string(&ytable, substr);
free(substr); |
ade8279c |
}
|
f4265e07 |
/* modifier handler */
if (STRING_IS_NO_CASE(string)) { |
b6731915 |
cli_yaramsg("STRING_IS_NO_CASE %s\n", STRING_IS_SINGLE_MATCH(string) ? "yes" : "no"); |
102cd430 |
if (CL_SUCCESS != (ret = ytable_add_attrib(&ytable, NULL, "i", 1)) != CL_SUCCESS) { |
16d69534 |
cli_warnmsg("load_oneyara: failed to add 'nocase' sigopt\n"); |
72747e08 |
str_error++;
break;
} |
f4265e07 |
}
if (STRING_IS_ASCII(string)) { |
b6731915 |
cli_yaramsg("STRING_IS_ASCII %s\n", STRING_IS_SINGLE_MATCH(string) ? "yes" : "no"); |
102cd430 |
if (CL_SUCCESS != (ret = ytable_add_attrib(&ytable, NULL, "a", 1)) != CL_SUCCESS) { |
16d69534 |
cli_warnmsg("load_oneyara: failed to add 'ascii' sigopt\n"); |
dc70379a |
str_error++;
break;
} |
f4265e07 |
}
if (STRING_IS_WIDE(string)) { |
b6731915 |
cli_yaramsg("STRING_IS_WIDE %s\n", STRING_IS_SINGLE_MATCH(string) ? "yes" : "no"); |
16d69534 |
/* handle lack of 'wide' support for regex here in order to suppress */
if (STRING_IS_REGEXP(string)) {
cli_warnmsg("load_oneyara[verify]: wide modifier [w] is not supported for regex subsigs\n");
str_error++;
break;
} |
102cd430 |
if (CL_SUCCESS != (ret = ytable_add_attrib(&ytable, NULL, "w", 1)) != CL_SUCCESS) { |
16d69534 |
cli_warnmsg("load_oneyara: failed to add 'wide' sigopt\n"); |
72747e08 |
str_error++;
break;
} |
f4265e07 |
}
if (STRING_IS_FULL_WORD(string)) { |
b6731915 |
cli_yaramsg("STRING_IS_FULL_WORD %s\n", STRING_IS_SINGLE_MATCH(string) ? "yes" : "no"); |
102cd430 |
if (CL_SUCCESS != (ret = ytable_add_attrib(&ytable, NULL, "f", 1)) != CL_SUCCESS) { |
16d69534 |
cli_warnmsg("load_oneyara: failed to add 'fullword' sigopt\n"); |
72747e08 |
str_error++;
break;
} |
f4265e07 |
}
|
bec92cfc |
#ifdef YARA_FINISHED |
f4265e07 |
/* special modifier handler */ |
5765c290 |
if (STRING_IS_ANONYMOUS(string))
cli_yaramsg("STRING_IS_ANONYMOUS %s\n", STRING_IS_SINGLE_MATCH(string) ? "yes" : "no"); |
f4265e07 |
/* unsupported(?) modifier handler */ |
5765c290 |
if (STRING_IS_SINGLE_MATCH(string))
cli_yaramsg("STRING_IS_SINGLE_MATCH %s\n", STRING_IS_SINGLE_MATCH(string) ? "yes" : "no");
if (STRING_IS_REFERENCED(string) || STRING_IS_FAST_HEX_REGEXP(string) || STRING_IS_CHAIN_PART(string) ||
STRING_IS_CHAIN_TAIL(string) || STRING_FITS_IN_ATOM(string)) {
|
3fdd7d01 |
cli_warnmsg("load_oneyara: skipping unsupported string %s\n", newident); |
5765c290 |
cli_yaramsg("STRING_IS_REFERENCED %s\n", STRING_IS_REFERENCED(string) ? "yes" : "no");
cli_yaramsg("STRING_IS_FAST_HEX_REGEXP %s\n", STRING_IS_FAST_HEX_REGEXP(string) ? "yes" : "no");
cli_yaramsg("STRING_IS_CHAIN_PART %s\n", STRING_IS_CHAIN_PART(string) ? "yes" : "no");
cli_yaramsg("STRING_IS_CHAIN_TAIL %s\n", STRING_IS_CHAIN_TAIL(string) ? "yes" : "no");
cli_yaramsg("STRING_FITS_IN_ATOM %s\n", STRING_FITS_IN_ATOM(string) ? "yes" : "no");
|
f4265e07 |
str_error++; |
b9af0434 |
continue;
} |
f88cffca |
#else
/*
cli_warnmsg("load_oneyara: yara support is incomplete, rule flags are ignored\n");
if (STRING_IS_ANONYMOUS(string))
cli_yaramsg("STRING_IS_ANONYMOUS yes\n");
if (STRING_IS_SINGLE_MATCH(string))
cli_yaramsg("STRING_IS_SINGLE_MATCH yes\n");
if (STRING_IS_REFERENCED(string))
cli_yaramsg("STRING_IS_REFERENCED yes\n");
if (STRING_IS_FAST_HEX_REGEXP(string))
cli_yaramsg("STRING_IS_FAST_HEX_REGEXP yes\n");
if (STRING_IS_CHAIN_PART(string))
cli_yaramsg("STRING_IS_CHAIN_PART yes\n");
if (STRING_IS_CHAIN_TAIL(string))
cli_yaramsg("STRING_IS_CHAIN_TAIL yes\n");
if (STRING_FITS_IN_ATOM(string))
cli_yaramsg("STRING_FITS_IN_ATOM yes\n");
*/ |
bec92cfc |
#endif |
288057e9 |
string->subsig_id = ytable.tbl_cnt - 1; |
f4265e07 |
} |
b9af0434 |
|
f4265e07 |
if (str_error > 0) { |
3fdd7d01 |
cli_warnmsg("load_oneyara: clamav cannot support %d input strings, skipping %s\n", str_error, newident); |
ea6e8cc9 |
yara_malform++; |
5765c290 |
ytable_delete(&ytable); |
3fdd7d01 |
free(newident); |
f4265e07 |
(*sigs)--; |
4ff617c3 |
return ret; |
5765c290 |
} else if (ytable.tbl_cnt == 0) { |
3fdd7d01 |
cli_warnmsg("load_oneyara: yara rule contains no supported strings, skipping %s\n", newident); |
814931b9 |
yara_malform++; |
5765c290 |
ytable_delete(&ytable); |
3fdd7d01 |
free(newident); |
f4265e07 |
(*sigs)--;
return CL_SUCCESS; /* TODO - kill signature instead? */ |
4ff617c3 |
} else if (ytable.tbl_cnt > MAX_LDB_SUBSIGS) { |
3fdd7d01 |
cli_warnmsg("load_oneyara: yara rule contains too many subsigs (%d, max: %d), skipping %s\n", ytable.tbl_cnt, MAX_LDB_SUBSIGS, newident); |
4ff617c3 |
yara_malform++;
ytable_delete(&ytable); |
3fdd7d01 |
free(newident); |
4ff617c3 |
(*sigs)--;
return CL_SUCCESS; |
f4265e07 |
} |
ade8279c |
|
f4265e07 |
/*** conditional verification step (ex. do we define too many strings versus used?) ***/
/*** additional string table population (ex. offsets), second translation table pass ***/ |
e10659a6 |
#if 0 |
b7999b89 |
if (rule->cl_flags & RULE_ALL || rule->cl_flags & RULE_ANY) { |
f51f42e9 |
lsize = 3*ytable.tbl_cnt;
logic = cli_calloc(lsize, sizeof(char));
if (!logic) {
cli_errmsg("load_oneyara: cannot allocate memory for logic statement\n");
ytable_delete(&ytable);
return CL_EMEM;
} |
c31a98d5 |
|
b7999b89 |
if (rule->cl_flags & RULE_ALL && rule->cl_flags & RULE_THEM) |
f51f42e9 |
exp_op = "&";
else {
exp_op = "|"; |
b7999b89 |
if ((!(rule->cl_flags & RULE_ANY && rule->cl_flags & RULE_THEM) && ytable.tbl_cnt > 1) &&
!(rule->cl_flags & RULE_EP && ytable.tbl_cnt == 1)) |
f51f42e9 |
yara_complex++;
} |
c31a98d5 |
|
f51f42e9 |
for (i=0; i<ytable.tbl_cnt; i++) {
size_t len=strlen(logic);
snprintf(logic+len, lsize-len, "%u%s", i, (i+1 == ytable.tbl_cnt) ? "" : exp_op); |
c31a98d5 |
}
|
f51f42e9 |
/*** END CONDITIONAL HANDLING ***/ |
f4265e07 |
} |
e10659a6 |
|
f4265e07 |
/* TDB */ |
b7999b89 |
if (rule->cl_flags & RULE_EP && ytable.tbl_cnt == 1) |
814931b9 |
target_str = cli_strdup(YARATARGET1);
else |
b7999b89 |
#endif |
288057e9 |
target_str = cli_strdup(YARATARGET0); |
814931b9 |
|
bb2ebd67 |
memset(&tdb, 0, sizeof(tdb)); |
102cd430 |
if (CL_SUCCESS != (ret = init_tdb(&tdb, engine, target_str, newident)) != CL_SUCCESS) { |
5765c290 |
ytable_delete(&ytable); |
f4265e07 |
free(logic); |
a684f7d8 |
free(target_str); |
3fdd7d01 |
free(newident); |
f4265e07 |
(*sigs)--; |
a684f7d8 |
if (ret == CL_BREAK)
return CL_SUCCESS;
return ret; |
f4265e07 |
} |
a684f7d8 |
free(target_str); |
f4265e07 |
/*** populating lsig ***/ |
a684f7d8 |
root = engine->root[tdb.target[0]]; |
f4265e07 |
|
544fa973 |
lsig = (struct cli_ac_lsig *)MPOOL_CALLOC(engine->mempool, 1, sizeof(struct cli_ac_lsig)); |
288057e9 |
if (!lsig) { |
f4265e07 |
cli_errmsg("load_oneyara: Can't allocate memory for lsig\n");
FREE_TDB(tdb); |
5765c290 |
ytable_delete(&ytable); |
f4265e07 |
free(logic); |
3fdd7d01 |
free(newident); |
f4265e07 |
return CL_EMEM;
}
if (logic) { |
c58e2fdb |
cli_yaramsg("normal lsig triggered yara: %s\n", logic);
|
288057e9 |
lsig->type = CLI_LSIG_NORMAL; |
544fa973 |
lsig->u.logic = CLI_MPOOL_STRDUP(engine->mempool, logic); |
f51f42e9 |
free(logic); |
288057e9 |
if (!lsig->u.logic) { |
f4265e07 |
cli_errmsg("load_oneyara: Can't allocate memory for lsig->logic\n");
FREE_TDB(tdb); |
5765c290 |
ytable_delete(&ytable); |
544fa973 |
MPOOL_FREE(engine->mempool, lsig); |
3fdd7d01 |
free(newident); |
f4265e07 |
return CL_EMEM; |
ade8279c |
} |
f4265e07 |
} else { |
f51f42e9 |
if (NULL != (lsig->u.code_start = rule->code_start)) { |
b7999b89 |
lsig->type = (rule->cl_flags & RULE_OFFSETS) ? CLI_YARA_OFFSET : CLI_YARA_NORMAL; |
7665e02d |
if (RULE_IS_PRIVATE(rule))
lsig->flag |= CLI_LSIG_FLAG_PRIVATE; |
f51f42e9 |
} else {
cli_errmsg("load_oneyara: code start is NULL\n");
FREE_TDB(tdb);
ytable_delete(&ytable); |
544fa973 |
MPOOL_FREE(engine->mempool, lsig); |
3fdd7d01 |
free(newident); |
f51f42e9 |
return CL_EMEM;
} |
f4265e07 |
} |
22b54fdb |
|
f4265e07 |
lsigid[0] = lsig->id = root->ac_lsigs; |
ade8279c |
|
f4265e07 |
root->ac_lsigs++; |
544fa973 |
newtable = (struct cli_ac_lsig **)MPOOL_REALLOC(engine->mempool, root->ac_lsigtable, root->ac_lsigs * sizeof(struct cli_ac_lsig *)); |
288057e9 |
if (!newtable) { |
f4265e07 |
root->ac_lsigs--;
cli_errmsg("cli_loadldb: Can't realloc root->ac_lsigtable\n");
FREE_TDB(tdb); |
5765c290 |
ytable_delete(&ytable); |
544fa973 |
MPOOL_FREE(engine->mempool, lsig); |
3fdd7d01 |
free(newident); |
f4265e07 |
return CL_EMEM;
} |
ade8279c |
|
f4265e07 |
newtable[root->ac_lsigs - 1] = lsig; |
288057e9 |
root->ac_lsigtable = newtable;
tdb.subsigs = ytable.tbl_cnt; |
b9af0434 |
|
f4265e07 |
/*** loading step - put things into the AC trie ***/ |
d0cba11e |
for (i = 0; i < (size_t)ytable.tbl_cnt; ++i) { |
f4265e07 |
lsigid[1] = i; |
f2da4b5b |
|
d0cba11e |
cli_yaramsg("%zu: [%s] [%s] [%s%s%s%s]\n", i, ytable.table[i]->hexstr, ytable.table[i]->offset, |
8ea34681 |
(ytable.table[i]->sigopts & ACPATT_OPTION_NOCASE) ? "i" : "",
(ytable.table[i]->sigopts & ACPATT_OPTION_FULLWORD) ? "f" : "",
(ytable.table[i]->sigopts & ACPATT_OPTION_WIDE) ? "w" : "",
(ytable.table[i]->sigopts & ACPATT_OPTION_ASCII) ? "a" : ""); |
c58e2fdb |
|
102cd430 |
if (CL_SUCCESS != (ret = cli_sigopts_handler(root, newident, ytable.table[i]->hexstr, ytable.table[i]->sigopts, 0, 0, ytable.table[i]->offset, target, lsigid, options)) != CL_SUCCESS) { |
a1482b98 |
root->ac_lsigs--;
FREE_TDB(tdb);
ytable_delete(&ytable); |
544fa973 |
MPOOL_FREE(engine->mempool, lsig); |
a1482b98 |
|
814931b9 |
yara_malform++; |
3fdd7d01 |
free(newident); |
a684f7d8 |
return ret; |
814931b9 |
} |
f4265e07 |
} |
ade8279c |
|
f4265e07 |
memcpy(&lsig->tdb, &tdb, sizeof(tdb)); |
5765c290 |
ytable_delete(&ytable); |
814931b9 |
|
7665e02d |
rule->lsigid = root->ac_lsigs - 1; |
814931b9 |
yara_loaded++; |
3fdd7d01 |
cli_yaramsg("load_oneyara: successfully loaded %s\n", newident);
free(newident); |
f4265e07 |
return CL_SUCCESS;
} |
ade8279c |
|
b6ad4322 |
struct _yara_global { |
288057e9 |
YR_ARENA *the_arena;
YR_HASH_TABLE *rules_table;
YR_HASH_TABLE *objects_table;
YR_HASH_TABLE *db_table; |
b6ad4322 |
}; |
5842265f |
|
102cd430 |
cl_error_t cli_yara_init(struct cl_engine *engine) |
5842265f |
{
/* Initialize YARA */ |
b6ad4322 |
engine->yara_global = cli_calloc(1, sizeof(struct _yara_global));
if (NULL == engine->yara_global) {
cli_errmsg("cli_yara_init: failed to create YARA global\n"); |
5842265f |
return CL_EMEM; |
b6ad4322 |
}
if (ERROR_SUCCESS != yr_arena_create(1024, 0, &engine->yara_global->the_arena)) {
cli_errmsg("cli_yara_init: failed to create the YARA arena\n");
free(engine->yara_global);
engine->yara_global = NULL; |
5842265f |
return CL_EMEM;
} |
b6ad4322 |
if (ERROR_SUCCESS != yr_hash_table_create(10007, &engine->yara_global->rules_table)) {
cli_errmsg("cli_yara_init: failed to create the YARA rules table\n");
yr_arena_destroy(engine->yara_global->the_arena);
engine->yara_global->the_arena = NULL;
free(engine->yara_global);
engine->yara_global = NULL; |
5842265f |
return CL_EMEM;
} |
b6ad4322 |
if (ERROR_SUCCESS != yr_hash_table_create(10007, &engine->yara_global->objects_table)) {
cli_errmsg("cli_yara_init: failed to create the YARA objects table\n");
yr_hash_table_destroy(engine->yara_global->rules_table, NULL);
yr_arena_destroy(engine->yara_global->the_arena);
engine->yara_global->rules_table = NULL; |
288057e9 |
engine->yara_global->the_arena = NULL; |
b6ad4322 |
free(engine->yara_global);
engine->yara_global = NULL;
engine->yara_global = NULL;
return CL_EMEM;
}
if (ERROR_SUCCESS != yr_hash_table_create(10007, &engine->yara_global->db_table)) {
cli_errmsg("cli_yara_init: failed to create the YARA objects table\n");
yr_hash_table_destroy(engine->yara_global->objects_table, NULL);
yr_hash_table_destroy(engine->yara_global->rules_table, NULL);
yr_arena_destroy(engine->yara_global->the_arena);
engine->yara_global->objects_table = NULL; |
288057e9 |
engine->yara_global->rules_table = NULL;
engine->yara_global->the_arena = NULL; |
b6ad4322 |
free(engine->yara_global);
engine->yara_global = NULL; |
5842265f |
return CL_EMEM;
}
return CL_SUCCESS;
}
|
288057e9 |
void cli_yara_free(struct cl_engine *engine) |
5842265f |
{ |
b6ad4322 |
if (engine->yara_global != NULL) {
if (engine->yara_global->db_table != NULL) {
yr_hash_table_destroy(engine->yara_global->db_table, NULL);
engine->yara_global->db_table = NULL;
}
if (engine->yara_global->rules_table != NULL) {
yr_hash_table_destroy(engine->yara_global->rules_table, NULL);
engine->yara_global->rules_table = NULL;
}
if (engine->yara_global->objects_table != NULL) {
yr_hash_table_destroy(engine->yara_global->objects_table, NULL);
engine->yara_global->objects_table = NULL; |
288057e9 |
} |
b6ad4322 |
if (engine->yara_global->the_arena != NULL) {
yr_arena_destroy(engine->yara_global->the_arena);
engine->yara_global->the_arena = NULL;
}
free(engine->yara_global);
engine->yara_global = NULL; |
288057e9 |
} |
5842265f |
}
|
f4265e07 |
//TODO - pua? dbio? |
b72292f1 |
static int cli_loadyara(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio, const char *filename) |
f4265e07 |
{ |
d0cba11e |
YR_COMPILER compiler; |
324fabbb |
YR_NAMESPACE ns; |
f4265e07 |
YR_RULE *rule; |
5891f834 |
unsigned int sigs = 0, rules = 0, rule_errors = 0; |
f4265e07 |
int rc; |
f901b0ad |
|
f4265e07 |
UNUSEDPARAM(dbio); |
ade8279c |
|
288057e9 |
if ((rc = cli_initroots(engine, options))) |
f4265e07 |
return rc; |
ade8279c |
|
d0cba11e |
memset(&compiler, 0, sizeof(YR_COMPILER));
|
f4265e07 |
compiler.last_result = ERROR_SUCCESS; |
3ca6d4c0 |
STAILQ_INIT(&compiler.rule_q);
STAILQ_INIT(&compiler.current_rule_string_q);
|
d03c18be |
rc = yr_arena_create(65536, 0, &compiler.sz_arena); |
3ca6d4c0 |
if (rc == ERROR_SUCCESS) |
39d0a152 |
rc = yr_arena_create(65536, 0, &compiler.rules_arena);
if (rc == ERROR_SUCCESS) |
3ca6d4c0 |
rc = yr_arena_create(65536, 0, &compiler.code_arena);
if (rc == ERROR_SUCCESS)
rc = yr_arena_create(65536, 0, &compiler.strings_arena); |
cc1c1c7d |
if (rc == ERROR_SUCCESS)
rc = yr_arena_create(65536, 0, &compiler.metas_arena); |
3ca6d4c0 |
if (rc != ERROR_SUCCESS)
return CL_EMEM; |
324fabbb |
compiler.loop_for_of_mem_offset = -1; |
288057e9 |
ns.name = "default";
compiler.current_namespace = &ns;
compiler.the_arena = engine->yara_global->the_arena;
compiler.rules_table = engine->yara_global->rules_table;
compiler.objects_table = engine->yara_global->objects_table;
compiler.allow_includes = 1; |
b72292f1 |
_yr_compiler_push_file_name(&compiler, filename); |
ade8279c |
|
f4265e07 |
rc = yr_lex_parse_rules_file(fs, &compiler);
if (rc > 0) { /* rc = number of errors */ |
288057e9 |
/* TODO - handle the various errors? */ |
5891f834 |
#ifdef YARA_FINISHED |
b72292f1 |
cli_errmsg("cli_loadyara: failed to parse rules file %s, error count %i\n", filename, rc); |
590a43e8 |
if (compiler.sz_arena != NULL)
yr_arena_destroy(compiler.sz_arena);
if (compiler.rules_arena != NULL)
yr_arena_destroy(compiler.rules_arena);
if (compiler.code_arena != NULL)
yr_arena_destroy(compiler.code_arena);
if (compiler.strings_arena != NULL)
yr_arena_destroy(compiler.strings_arena);
if (compiler.metas_arena != NULL)
yr_arena_destroy(compiler.metas_arena); |
4400490c |
_yr_compiler_pop_file_name(&compiler); |
f4265e07 |
return CL_EMALFDB; |
311a0b10 |
#else |
f0b357ee |
if (compiler.last_result == ERROR_INSUFICIENT_MEMORY) |
590a43e8 |
return CL_EMEM; |
5891f834 |
rule_errors = rc; |
288057e9 |
rc = CL_SUCCESS; |
90941cad |
#endif |
f4265e07 |
} |
fdd7f801 |
|
3ca6d4c0 |
while (!STAILQ_EMPTY(&compiler.rule_q)) {
rule = STAILQ_FIRST(&compiler.rule_q);
STAILQ_REMOVE(&compiler.rule_q, rule, _yc_rule, link); |
f4265e07 |
rules++; |
f597585b |
sigs++; /* can be decremented by load_oneyara */ |
f4265e07 |
|
5adf3903 |
rc = load_oneyara(rule,
engine->pua_cats && (options & CL_DB_PUA_MODE) && (options & (CL_DB_PUA_INCLUDE | CL_DB_PUA_EXCLUDE)),
engine, options, &sigs); |
f597585b |
if (rc != CL_SUCCESS) { |
b72292f1 |
cli_warnmsg("cli_loadyara: problem parsing yara file %s, yara rule %s\n", filename, rule->identifier); |
758e74cf |
continue; |
f597585b |
}
} |
3dafe297 |
|
5891f834 |
if (0 != rule_errors) |
288057e9 |
cli_warnmsg("cli_loadyara: failed to parse or load %u yara rules from file %s, successfully loaded %u rules.\n", rule_errors + rules - sigs, filename, sigs); |
5891f834 |
|
b6ad4322 |
yr_arena_append(engine->yara_global->the_arena, compiler.sz_arena);
yr_arena_append(engine->yara_global->the_arena, compiler.rules_arena);
yr_arena_append(engine->yara_global->the_arena, compiler.strings_arena); |
3ca6d4c0 |
yr_arena_destroy(compiler.code_arena); |
cc1c1c7d |
yr_arena_destroy(compiler.metas_arena); |
4400490c |
_yr_compiler_pop_file_name(&compiler); |
ade8279c |
|
288057e9 |
if (rc) |
f4265e07 |
return rc;
|
311a0b10 |
#ifdef YARA_FINISHED |
288057e9 |
if (!rules) { |
f4265e07 |
cli_errmsg("cli_loadyara: empty database file\n");
return CL_EMALFDB;
} |
94ac324e |
#else |
288057e9 |
if (!rules) { |
94ac324e |
cli_warnmsg("cli_loadyara: empty database file\n");
yara_empty++;
}
#endif |
f4265e07 |
|
814931b9 |
/* globals */
yara_total += rules;
|
288057e9 |
if (signo) |
f4265e07 |
*signo += sigs;
|
b72292f1 |
cli_yaramsg("cli_loadyara: loaded %u of %u yara signatures from %s\n", sigs, rules, filename); |
f4265e07 |
return CL_SUCCESS; |
186d22d1 |
} |
baeb6253 |
#endif |
f4265e07 |
|
ac0cbde8 |
/* 0 1 2 3
* PasswordName;Attributes;PWStorageType;Password
*/
#define PWDB_TOKENS 4
static int cli_loadpwdb(FILE *fs, struct cl_engine *engine, unsigned int options, unsigned int internal, struct cli_dbio *dbio)
{ |
5d77f15a |
const char *tokens[PWDB_TOKENS + 1], *passname; |
ac0cbde8 |
char *attribs;
char buffer[FILEBUFF];
unsigned int line = 0, skip = 0, pwcnt = 0, tokens_count; |
d0cba11e |
struct cli_pwdb *new; |
038cb67a |
cl_pwdb_t container; |
ac0cbde8 |
struct cli_lsig_tdb tdb;
int ret = CL_SUCCESS, pwstype;
|
288057e9 |
while (1) {
if (internal) { |
ac0cbde8 |
options |= CL_DB_OFFICIAL;
/* TODO - read default passwords */
return CL_SUCCESS;
} else { |
288057e9 |
if (!cli_dbgets(buffer, FILEBUFF, fs, dbio)) |
ac0cbde8 |
break; |
288057e9 |
if (buffer[0] == '#') |
ac0cbde8 |
continue;
cli_chomp(buffer);
}
line++;
tokens_count = cli_strtokenize(buffer, ';', PWDB_TOKENS, tokens);
|
288057e9 |
if (tokens_count != PWDB_TOKENS) { |
ac0cbde8 |
ret = CL_EMALFDB;
break;
}
passname = tokens[0];
/* check if password is ignored, note that name is not stored */
if (engine->ignored && cli_chkign(engine->ignored, passname, passname)) {
skip++;
continue;
}
|
288057e9 |
if (engine->cb_sigload && engine->cb_sigload("pwdb", passname, ~options & CL_DB_OFFICIAL, engine->cb_sigload_ctx)) { |
ac0cbde8 |
cli_dbgmsg("cli_loadpwdb: skipping %s due to callback\n", passname);
skip++;
continue;
}
|
5d77f15a |
/* append target type 0 to tdb string if needed */
if ((tokens[1][0] == '\0') || (strstr(tokens[1], "Target:") != NULL)) {
attribs = cli_strdup(tokens[1]); |
288057e9 |
if (!attribs) { |
5d77f15a |
cli_errmsg("cli_loadpwdb: Can't allocate memory for attributes\n");
ret = CL_EMEM;
break;
}
} else {
size_t attlen = strlen(tokens[1]) + 10; |
288057e9 |
attribs = cli_calloc(attlen, sizeof(char));
if (!attribs) { |
5d77f15a |
cli_errmsg("cli_loadpwdb: Can't allocate memory for attributes\n");
ret = CL_EMEM;
break;
}
snprintf(attribs, attlen, "%s,Target:0", tokens[1]); |
37141e88 |
}
|
ac0cbde8 |
/* use the tdb to track filetypes and check flevels */ |
5d77f15a |
memset(&tdb, 0, sizeof(tdb)); |
ac0cbde8 |
ret = init_tdb(&tdb, engine, attribs, passname);
free(attribs); |
288057e9 |
if (ret != CL_SUCCESS) { |
80df0da4 |
skip++; |
ac0cbde8 |
if (ret == CL_BREAK)
continue;
else
break;
}
|
37141e88 |
/* check container type */
if (!tdb.container) {
container = CLI_PWDB_ANY;
} else {
switch (*(tdb.container)) { |
288057e9 |
case CL_TYPE_ANY:
container = CLI_PWDB_ANY;
break;
case CL_TYPE_ZIP:
container = CLI_PWDB_ZIP;
break;
case CL_TYPE_RAR:
container = CLI_PWDB_RAR;
break;
default:
cli_errmsg("cli_loadpwdb: Invalid container specified to .pwdb signature\n");
return CL_EMALFDB; |
37141e88 |
}
}
FREE_TDB(tdb); |
038cb67a |
|
ac0cbde8 |
/* check the PWStorageType */ |
288057e9 |
if (!cli_isnumber(tokens[2])) { |
ac0cbde8 |
cli_errmsg("cli_loadpwdb: Invalid value for PWStorageType (third entry)\n");
ret = CL_EMALFDB;
break;
}
pwstype = atoi(tokens[2]); |
288057e9 |
if ((pwstype == 0) || (pwstype == 1)) { |
544fa973 |
new = (struct cli_pwdb *)MPOOL_CALLOC(engine->mempool, 1, sizeof(struct cli_pwdb)); |
288057e9 |
if (!new) { |
ac0cbde8 |
ret = CL_EMEM;
break;
} |
0a631ee9 |
/* copy passwd name */ |
544fa973 |
new->name = CLI_MPOOL_STRDUP(engine->mempool, tokens[0]); |
0a631ee9 |
if (!new->name) {
ret = CL_EMEM; |
544fa973 |
MPOOL_FREE(engine->mempool, new); |
0a631ee9 |
break;
}
|
288057e9 |
if (pwstype == 0) { /* cleartext */ |
544fa973 |
new->passwd = CLI_MPOOL_STRDUP(engine->mempool, tokens[3]); |
8efbf4a0 |
new->length = (uint16_t)strlen(tokens[3]); |
ac0cbde8 |
} else { /* 1 => hex-encoded */ |
544fa973 |
new->passwd = CLI_MPOOL_HEX2STR(engine->mempool, tokens[3]); |
8efbf4a0 |
new->length = (uint16_t)strlen(tokens[3]) / 2; |
ac0cbde8 |
} |
288057e9 |
if (!new->passwd) { |
ac0cbde8 |
cli_errmsg("cli_loadpwdb: Can't decode or add new password entry\n"); |
288057e9 |
if (pwstype == 0) |
ac0cbde8 |
ret = CL_EMEM;
else
ret = CL_EMALFDB; |
544fa973 |
MPOOL_FREE(engine->mempool, new->name);
MPOOL_FREE(engine->mempool, new); |
ac0cbde8 |
break;
}
/* add to the engine list, sorted by target type */ |
288057e9 |
new->next = engine->pwdbs[container];
engine->pwdbs[container] = new; |
ac0cbde8 |
} else {
cli_dbgmsg("cli_loadpwdb: Unsupported PWStorageType %u\n", pwstype);
continue;
}
pwcnt++;
}
/* error reporting */ |
288057e9 |
if (ret) { |
ac0cbde8 |
cli_errmsg("Problem processing %s password database at line %u\n", internal ? "built-in" : "external", line);
return ret;
}
|
288057e9 |
if (!pwcnt) { |
ac0cbde8 |
cli_errmsg("Empty %s password database\n", internal ? "built-in" : "external");
return CL_EMALFDB;
}
cli_dbgmsg("Loaded %u (%u skipped) password entries\n", pwcnt, skip);
return CL_SUCCESS;
}
|
66166776 |
static cl_error_t cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned int *signo, unsigned int options); |
52c67b86 |
|
102cd430 |
cl_error_t cli_load(const char *filename, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio) |
e3aaff8e |
{ |
66166776 |
cl_error_t ret = CL_SUCCESS;
|
288057e9 |
FILE *fs = NULL;
uint8_t skipped = 0;
const char *dbname;
char buff[FILEBUFF];
if (dbio && dbio->chkonly) {
while (cli_dbgets(buff, FILEBUFF, NULL, dbio)) continue;
return CL_SUCCESS; |
f8202681 |
}
|
288057e9 |
if (!dbio && (fs = fopen(filename, "rb")) == NULL) {
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;
}
}
}
cli_errmsg("cli_load(): Can't open file %s\n", filename);
return CL_EOPEN; |
4048c4f6 |
}
|
288057e9 |
if ((dbname = strrchr(filename, *PATHSEP)))
dbname++; |
ed9753e9 |
else |
288057e9 |
dbname = filename; |
4048c4f6 |
|
bbfac258 |
#ifdef HAVE_YARA |
288057e9 |
if (options & CL_DB_YARA_ONLY) {
if (cli_strbcasestr(dbname, ".yar") || cli_strbcasestr(dbname, ".yara"))
ret = cli_loadyara(fs, engine, signo, options, dbio, filename);
else
skipped = 1; |
bbfac258 |
} else
#endif |
288057e9 |
if (cli_strbcasestr(dbname, ".db")) {
ret = cli_loaddb(fs, engine, signo, options, dbio, dbname); |
ed9753e9 |
|
288057e9 |
} else if (cli_strbcasestr(dbname, ".cvd")) {
ret = cli_cvdload(fs, engine, signo, options, 0, filename, 0); |
9d193ff2 |
|
288057e9 |
} else if (cli_strbcasestr(dbname, ".cld")) {
ret = cli_cvdload(fs, engine, signo, options, 1, filename, 0); |
4048c4f6 |
|
288057e9 |
} else if (cli_strbcasestr(dbname, ".cud")) {
ret = cli_cvdload(fs, engine, signo, options, 2, filename, 0); |
cdddd014 |
|
c05ac24f |
} else if (cli_strbcasestr(dbname, ".crb")) { |
d12f1646 |
ret = cli_loadcrt(fs, engine, dbio);
|
288057e9 |
} 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")) {
if (options & CL_DB_PUA)
ret = cli_loadhash(fs, engine, signo, MD5_HDB, options | CL_DB_PUA_MODE, dbio, dbname);
else
skipped = 1;
} 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);
} else if (cli_strbcasestr(dbname, ".imp")) {
ret = cli_loadhash(fs, engine, signo, MD5_IMP, options, dbio, dbname);
} else if (cli_strbcasestr(dbname, ".mdu") || cli_strbcasestr(dbname, ".msu")) {
if (options & CL_DB_PUA)
ret = cli_loadhash(fs, engine, signo, MD5_MDB, options | CL_DB_PUA_MODE, dbio, dbname);
else
skipped = 1;
} else if (cli_strbcasestr(dbname, ".ndb")) {
ret = cli_loadndb(fs, engine, signo, 0, options, dbio, dbname);
} else if (cli_strbcasestr(dbname, ".ndu")) {
if (!(options & CL_DB_PUA))
skipped = 1;
else
ret = cli_loadndb(fs, engine, signo, 0, options | CL_DB_PUA_MODE, dbio, dbname);
} 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)
ret = cli_loadldb(fs, engine, signo, options | CL_DB_PUA_MODE, dbio, dbname);
else
skipped = 1;
} else if (cli_strbcasestr(filename, ".cbc")) {
if (options & CL_DB_BYTECODE)
ret = cli_loadcbc(fs, engine, signo, options, dbio, dbname);
else
skipped = 1;
} else if (cli_strbcasestr(dbname, ".sdb")) {
ret = cli_loadndb(fs, engine, signo, 1, options, dbio, dbname);
} else if (cli_strbcasestr(dbname, ".zmd")) {
ret = cli_loadmd(fs, engine, signo, 1, options, dbio, dbname);
} else if (cli_strbcasestr(dbname, ".rmd")) {
ret = cli_loadmd(fs, engine, signo, 2, options, dbio, dbname);
} else if (cli_strbcasestr(dbname, ".cfg")) {
ret = cli_dconf_load(fs, engine, options, dbio);
} else if (cli_strbcasestr(dbname, ".info")) {
ret = cli_loadinfo(fs, engine, options, dbio);
} else if (cli_strbcasestr(dbname, ".wdb")) {
if (options & CL_DB_PHISHING_URLS) {
ret = cli_loadwdb(fs, engine, options, dbio);
} else
skipped = 1;
} else if (cli_strbcasestr(dbname, ".pdb") || cli_strbcasestr(dbname, ".gdb")) {
if (options & CL_DB_PHISHING_URLS) {
ret = cli_loadpdb(fs, engine, signo, options, dbio);
} else
skipped = 1;
} else if (cli_strbcasestr(dbname, ".ftm")) {
ret = cli_loadftm(fs, engine, options, 0, dbio);
} else if (cli_strbcasestr(dbname, ".ign") || cli_strbcasestr(dbname, ".ign2")) {
ret = cli_loadign(fs, engine, options, dbio);
} else if (cli_strbcasestr(dbname, ".idb")) {
ret = cli_loadidb(fs, engine, signo, options, dbio);
} else if (cli_strbcasestr(dbname, ".cdb")) {
ret = cli_loadcdb(fs, engine, signo, options, dbio);
} else if (cli_strbcasestr(dbname, ".cat")) {
ret = cli_loadmscat(fs, dbname, engine, options, dbio);
} else if (cli_strbcasestr(dbname, ".ioc")) {
ret = cli_loadopenioc(fs, dbname, engine, options); |
baeb6253 |
#ifdef HAVE_YARA |
288057e9 |
} else if (cli_strbcasestr(dbname, ".yar") || cli_strbcasestr(dbname, ".yara")) {
if (!(options & CL_DB_YARA_EXCLUDE))
ret = cli_loadyara(fs, engine, signo, options, dbio, filename);
else
skipped = 1; |
baeb6253 |
#endif |
288057e9 |
} else if (cli_strbcasestr(dbname, ".pwdb")) { |
ac0cbde8 |
ret = cli_loadpwdb(fs, engine, options, 0, dbio); |
4048c4f6 |
} else { |
288057e9 |
cli_warnmsg("cli_load: unknown extension - skipping %s\n", filename);
skipped = 1;
} |
4048c4f6 |
|
288057e9 |
if (ret) {
cli_errmsg("Can't load %s: %s\n", filename, cl_strerror(ret));
} else {
if (skipped)
cli_dbgmsg("%s skipped\n", filename);
else
cli_dbgmsg("%s loaded\n", filename); |
4efca56b |
} |
4048c4f6 |
|
288057e9 |
if (fs)
fclose(fs); |
056d95dc |
|
4048c4f6 |
return ret; |
e3aaff8e |
}
|
368e6282 |
struct db_ll_entry {
char *path;
unsigned int load_priority;
struct db_ll_entry *next;
};
static void
cli_insertdbtoll(struct db_ll_entry **head, struct db_ll_entry *entry)
{
struct db_ll_entry *iter, *prev;
if (NULL == *head) {
*head = entry;
entry->next = NULL;
return;
}
for (prev = NULL, iter = *head; iter != NULL; prev = iter, iter = iter->next) {
if (entry->load_priority < iter->load_priority) {
if (NULL == prev) {
*head = entry;
} else {
prev->next = entry;
}
entry->next = iter;
return;
}
}
prev->next = entry;
entry->next = NULL;
return;
}
|
66166776 |
static cl_error_t cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned int *signo, unsigned int options) |
e3aaff8e |
{ |
66166776 |
cl_error_t ret = CL_EOPEN;
|
368e6282 |
DIR *dd = NULL; |
288057e9 |
struct dirent *dent; |
66166776 |
char *dbfile = NULL;
int ends_with_sep = 0; |
288057e9 |
size_t dirname_len; |
368e6282 |
struct cl_cvd *daily_cld = NULL;
struct cl_cvd *daily_cvd = NULL;
struct db_ll_entry *head = NULL;
struct db_ll_entry *iter;
struct db_ll_entry *next; |
e3aaff8e |
|
0eacacec |
cli_dbgmsg("Loading databases from %s\n", dirname); |
04133ff9 |
|
288057e9 |
if ((dd = opendir(dirname)) == NULL) { |
04133ff9 |
cli_errmsg("cli_loaddbdir(): Can't open directory %s\n", dirname); |
368e6282 |
ret = CL_EOPEN; |
8650c790 |
goto done; |
04133ff9 |
}
|
dbfbe0f1 |
dirname_len = strlen(dirname); |
288057e9 |
if (dirname_len >= strlen(PATHSEP)) {
if (strcmp(dirname + dirname_len - strlen(PATHSEP), PATHSEP) == 0) { |
dbfbe0f1 |
cli_dbgmsg("cli_loaddbdir(): dirname ends with separator\n");
ends_with_sep = 1;
}
}
|
288057e9 |
while ((dent = readdir(dd))) { |
368e6282 |
struct db_ll_entry *entry;
unsigned int load_priority;
if (!dent->d_ino) {
continue;
}
if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) {
continue;
}
if (!CLI_DBEXT(dent->d_name)) {
continue;
}
dbfile = (char *)cli_malloc(strlen(dent->d_name) + dirname_len + 2);
if (!dbfile) {
cli_errmsg("cli_loaddbdir(): dbfile == NULL\n");
ret = CL_EMEM; |
8650c790 |
goto done; |
368e6282 |
}
if (ends_with_sep)
sprintf(dbfile, "%s%s", dirname, dent->d_name);
else
sprintf(dbfile, "%s" PATHSEP "%s", dirname, dent->d_name);
#define DB_LOAD_PRIORITY_IGN 1
#define DB_LOAD_PRIORITY_DAILY_CLD 2
#define DB_LOAD_PRIORITY_DAILY_CVD 3
#define DB_LOAD_PRIORITY_LOCAL_GDB 4
#define DB_LOAD_PRIORITY_DAILY_CFG 5
#define DB_LOAD_PRIORITY_CRB 6
#define DB_LOAD_PRIORITY_NORMAL 7
if (cli_strbcasestr(dent->d_name, ".ign") || cli_strbcasestr(dent->d_name, ".ign2")) {
/* load .ign and .ign2 files first */
load_priority = DB_LOAD_PRIORITY_IGN;
} else if (!strcmp(dent->d_name, "daily.cld")) { |
66166776 |
/* The daily db must be loaded before main, this way, the
daily ign & ign2 signatures prevent ign'ored signatures
in all databases from being loaded. */ |
368e6282 |
load_priority = DB_LOAD_PRIORITY_DAILY_CLD;
|
66166776 |
if (0 == access(dbfile, R_OK)) { |
368e6282 |
daily_cld = cl_cvdhead(dbfile);
if (!daily_cld) {
cli_errmsg("cli_loaddbdir(): error parsing header of %s\n", dbfile);
ret = CL_EMALFDB; |
8650c790 |
goto done; |
288057e9 |
} |
368e6282 |
}
} else if (!strcmp(dent->d_name, "daily.cvd")) {
load_priority = DB_LOAD_PRIORITY_DAILY_CVD;
|
66166776 |
if (0 == access(dbfile, R_OK)) { |
368e6282 |
daily_cvd = cl_cvdhead(dbfile);
if (!daily_cvd) {
cli_errmsg("cli_loaddbdir(): error parsing header of %s\n", dbfile);
ret = CL_EMALFDB; |
8650c790 |
goto done; |
288057e9 |
}
} |
04133ff9 |
|
368e6282 |
} else if (!strcmp(dent->d_name, "local.gdb")) {
load_priority = DB_LOAD_PRIORITY_LOCAL_GDB; |
ed9753e9 |
|
368e6282 |
} else if (!strcmp(dent->d_name, "daily.cfg")) {
load_priority = DB_LOAD_PRIORITY_DAILY_CFG;
|
66166776 |
} else if ((options & CL_DB_OFFICIAL_ONLY) &&
!strstr(dirname, "clamav-") && // Official databases that are temp-files (in the process of updating).
!cli_strbcasestr(dent->d_name, ".cld") && // Official databases that have been updated using incremental updates.
!cli_strbcasestr(dent->d_name, ".cvd")) { // Official databases. |
368e6282 |
// TODO Should this be higher up in the list? Should we
// ignore .ign/.ign2 files and the local.gdb file when this
// flag is set?
cli_dbgmsg("Skipping unofficial database %s\n", dent->d_name); |
288057e9 |
free(dbfile); |
368e6282 |
dbfile = NULL;
continue;
} else if (cli_strbcasestr(dent->d_name, ".crb")) {
/* .cat files cannot be loaded successfully unless there are .crb |
66166776 |
* rules that whitelist the certs used to sign the catalog files.
* Therefore, we need to ensure the .crb rules are loaded prior */ |
368e6282 |
load_priority = DB_LOAD_PRIORITY_CRB;
} else {
load_priority = DB_LOAD_PRIORITY_NORMAL;
}
entry = malloc(sizeof(*entry));
if (NULL == entry) {
cli_errmsg("cli_loaddbdir(): entry == NULL\n");
ret = CL_EMEM; |
8650c790 |
goto done; |
288057e9 |
} |
368e6282 |
entry->path = dbfile;
dbfile = NULL;
entry->load_priority = load_priority;
cli_insertdbtoll(&head, entry); |
288057e9 |
} |
368e6282 |
/* The list entries are stored in priority order, so now just loop through
* and load everything.
* NOTE: If there's a daily.cld and a daily.cvd, we'll only load whichever |
8650c790 |
* has the highest version number. If they have the same version number
* we load daily.cld, since that will load faster (it won't attempt to
* verify the digital signature of the db). |
66166776 |
* |
8650c790 |
* TODO It'd be ideal if we treated all cld/cvd pairs like we do the daily
* ones, and only loaded the one with the highest version. */ |
368e6282 |
for (iter = head; iter != NULL; iter = iter->next) {
|
66166776 |
if (DB_LOAD_PRIORITY_DAILY_CLD == iter->load_priority) {
/* iter is the daily.cld. If we also have the cvd and the cvd is newer, skip the cld. */
if ((NULL != daily_cvd) && (daily_cld->version < daily_cvd->version)) { |
368e6282 |
continue; |
288057e9 |
} |
368e6282 |
|
66166776 |
} else if (DB_LOAD_PRIORITY_DAILY_CVD == iter->load_priority) {
/* iter is the daily.cvd. If we also have the cld and the cld is same or newer, skip the cvd. */
if ((NULL != daily_cld) && (daily_cld->version >= daily_cvd->version)) { |
368e6282 |
continue; |
288057e9 |
}
} |
368e6282 |
ret = cli_load(iter->path, engine, signo, options, NULL);
if (ret) {
cli_errmsg("cli_loaddbdir(): error loading database %s\n", iter->path); |
8650c790 |
goto done; |
368e6282 |
} |
284e1ee4 |
}
|
8650c790 |
done: |
368e6282 |
for (iter = head; iter != NULL; iter = next) {
next = iter->next;
free(iter->path);
free(iter); |
ed9753e9 |
}
|
368e6282 |
if (NULL != dbfile) { |
288057e9 |
free(dbfile); |
816d66a8 |
}
|
368e6282 |
if (NULL != dd) { |
288057e9 |
closedir(dd); |
0eacacec |
} |
afe940da |
|
368e6282 |
if (NULL != daily_cld) {
cl_cvdfree(daily_cld);
} |
288057e9 |
|
368e6282 |
if (NULL != daily_cvd) {
cl_cvdfree(daily_cvd); |
e3aaff8e |
} |
368e6282 |
|
288057e9 |
if (ret == CL_EOPEN)
cli_errmsg("cli_loaddbdir(): No supported database files found in %s\n", dirname); |
d6898042 |
return ret; |
e3aaff8e |
}
|
2accc66f |
int cl_load(const char *path, struct cl_engine *engine, unsigned int *signo, unsigned int dboptions) |
04933acd |
{ |
288057e9 |
STATBUF sb;
int ret; |
04933acd |
|
288057e9 |
if (!engine) {
cli_errmsg("cl_load: engine == NULL\n");
return CL_ENULLARG; |
724b2bf7 |
} |
04933acd |
|
288057e9 |
if (engine->dboptions & CL_DB_COMPILED) {
cli_errmsg("cl_load(): can't load new databases when engine is already compiled\n");
return CL_EARG; |
d7c3f6e2 |
}
|
288057e9 |
if (CLAMSTAT(path, &sb) == -1) { |
65332152 |
switch (errno) {
#if defined(EACCES)
case EACCES:
cli_errmsg("cl_load(): Access denied for path: %s\n", path);
break;
#endif
#if defined(ENOENT)
case ENOENT:
cli_errmsg("cl_load(): No such file or directory: %s\n", path);
break;
#endif
#if defined(ELOOP)
case ELOOP:
cli_errmsg("cl_load(): Too many symbolic links encountered in path: %s\n", path);
break;
#endif
#if defined(EOVERFLOW)
case EOVERFLOW:
cli_errmsg("cl_load(): File size is too large to be recognized. Path: %s\n", path);
break;
#endif
#if defined(EIO)
case EIO:
cli_errmsg("cl_load(): An I/O error occurred while reading from path: %s\n", path);
break;
#endif
default:
cli_errmsg("cl_load: Can't get status of: %s\n", path);
break;
} |
871177cd |
return CL_ESTAT; |
04933acd |
}
|
288057e9 |
if ((dboptions & CL_DB_PHISHING_URLS) && !engine->phishcheck && (engine->dconf->phishing & PHISHING_CONF_ENGINE)) |
102cd430 |
if (CL_SUCCESS != (ret = phishing_init(engine))) |
288057e9 |
return ret; |
f7470773 |
|
288057e9 |
if ((dboptions & CL_DB_BYTECODE) && !engine->bcs.inited) { |
102cd430 |
if (CL_SUCCESS != (ret = cli_bytecode_init(&engine->bcs))) |
288057e9 |
return ret; |
52dd3a6b |
} else { |
288057e9 |
cli_dbgmsg("Bytecode engine disabled\n"); |
52dd3a6b |
}
|
8650c790 |
if (!engine->cache && cli_cache_init(engine)) |
288057e9 |
return CL_EMEM; |
6223810b |
|
d7c3f6e2 |
engine->dboptions |= dboptions; |
616bc3b9 |
|
288057e9 |
switch (sb.st_mode & S_IFMT) {
case S_IFREG:
ret = cli_load(path, engine, signo, dboptions, NULL);
break; |
04933acd |
|
288057e9 |
case S_IFDIR:
ret = cli_loaddbdir(path, engine, signo, dboptions | CL_DB_DIRECTORY);
break; |
04933acd |
|
288057e9 |
default:
cli_errmsg("cl_load(%s): Not supported database file type\n", path);
return CL_EOPEN; |
04933acd |
} |
d03c18be |
|
e9b611f8 |
#ifdef YARA_PROTO |
a0ab171d |
if (yara_total) {
cli_yaramsg("$$$$$$$$$$$$ YARA $$$$$$$$$$$$\n");
cli_yaramsg("\tTotal Rules: %u\n", yara_total);
cli_yaramsg("\tRules Loaded: %u\n", yara_loaded); |
f88cffca |
cli_yaramsg("\tComplex Conditions: %u\n", yara_complex);
cli_yaramsg("\tMalformed/Unsupported Rules: %u\n", yara_malform); |
94ac324e |
cli_yaramsg("\tEmpty Rules: %u\n", yara_empty); |
a0ab171d |
cli_yaramsg("$$$$$$$$$$$$ YARA $$$$$$$$$$$$\n");
} |
e9b611f8 |
#endif |
bc93eda0 |
return ret; |
04933acd |
}
|
4048c4f6 |
const char *cl_retdbdir(void)
{
return DATADIR;
}
|
e3aaff8e |
int cl_statinidir(const char *dirname, struct cl_stat *dbstat)
{ |
288057e9 |
DIR *dd;
struct dirent *dent;
char *fname; |
e3aaff8e |
|
288057e9 |
if (dbstat) {
dbstat->entries = 0;
dbstat->stattab = NULL;
dbstat->statdname = NULL;
dbstat->dir = cli_strdup(dirname); |
e3aaff8e |
} else {
cli_errmsg("cl_statdbdir(): Null argument passed.\n"); |
288057e9 |
return CL_ENULLARG; |
e3aaff8e |
}
|
288057e9 |
if ((dd = opendir(dirname)) == NULL) { |
e3aaff8e |
cli_errmsg("cl_statdbdir(): Can't open directory %s\n", dirname); |
288057e9 |
cl_statfree(dbstat); |
e3aaff8e |
return CL_EOPEN;
}
cli_dbgmsg("Stat()ing files in %s\n", dirname);
|
288057e9 |
while ((dent = readdir(dd))) {
if (dent->d_ino) {
if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") && CLI_DBEXT(dent->d_name)) {
dbstat->entries++;
dbstat->stattab = (STATBUF *)cli_realloc2(dbstat->stattab, dbstat->entries * sizeof(STATBUF));
if (!dbstat->stattab) {
cl_statfree(dbstat);
closedir(dd);
return CL_EMEM;
} |
cd69cf20 |
|
b2354dc1 |
#ifdef _WIN32 |
288057e9 |
dbstat->statdname = (char **)cli_realloc2(dbstat->statdname, dbstat->entries * sizeof(char *));
if (!dbstat->statdname) {
cli_errmsg("cl_statinidir: Can't allocate memory for dbstat->statdname\n");
cl_statfree(dbstat);
closedir(dd);
return CL_EMEM;
} |
75ccac9f |
#endif
|
0eacacec |
fname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 32); |
288057e9 |
if (!fname) {
cli_errmsg("cl_statinidir: Cant' allocate memory for fname\n");
cl_statfree(dbstat);
closedir(dd);
return CL_EMEM;
}
sprintf(fname, "%s" PATHSEP "%s", dirname, dent->d_name); |
b2354dc1 |
#ifdef _WIN32 |
288057e9 |
dbstat->statdname[dbstat->entries - 1] = (char *)cli_malloc(strlen(dent->d_name) + 1);
if (!dbstat->statdname[dbstat->entries - 1]) {
cli_errmsg("cli_statinidir: Can't allocate memory for dbstat->statdname\n");
cl_statfree(dbstat);
closedir(dd);
return CL_EMEM;
}
strcpy(dbstat->statdname[dbstat->entries - 1], dent->d_name); |
75ccac9f |
#endif |
288057e9 |
CLAMSTAT(fname, &dbstat->stattab[dbstat->entries - 1]);
free(fname);
}
} |
e3aaff8e |
}
closedir(dd); |
8d3aca30 |
return CL_SUCCESS; |
e3aaff8e |
}
int cl_statchkdir(const struct cl_stat *dbstat)
{ |
288057e9 |
DIR *dd;
struct dirent *dent;
STATBUF sb;
unsigned int i, found;
char *fname; |
e3aaff8e |
|
288057e9 |
if (!dbstat || !dbstat->dir) { |
e3aaff8e |
cli_errmsg("cl_statdbdir(): Null argument passed.\n"); |
288057e9 |
return CL_ENULLARG; |
e3aaff8e |
}
|
288057e9 |
if ((dd = opendir(dbstat->dir)) == NULL) { |
e3aaff8e |
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);
|
288057e9 |
while ((dent = readdir(dd))) {
if (dent->d_ino) {
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); |
288057e9 |
if (!fname) {
cli_errmsg("cl_statchkdir: can't allocate memory for fname\n");
closedir(dd);
return CL_EMEM;
}
sprintf(fname, "%s" PATHSEP "%s", dbstat->dir, dent->d_name);
CLAMSTAT(fname, &sb);
free(fname);
found = 0;
for (i = 0; i < dbstat->entries; i++) |
b2354dc1 |
#ifdef _WIN32 |
288057e9 |
if (!strcmp(dbstat->statdname[i], dent->d_name)) { |
75ccac9f |
#else |
288057e9 |
if (dbstat->stattab[i].st_ino == sb.st_ino) { |
75ccac9f |
#endif |
288057e9 |
found = 1;
if (dbstat->stattab[i].st_mtime != sb.st_mtime) {
closedir(dd);
return 1;
}
} |
e3aaff8e |
|
288057e9 |
if (!found) {
closedir(dd);
return 1;
}
}
} |
e3aaff8e |
}
closedir(dd); |
8d3aca30 |
return CL_SUCCESS; |
e3aaff8e |
}
|
038cb67a |
void cli_pwdb_list_free(struct cl_engine *engine, struct cli_pwdb *pwdb) |
ac0cbde8 |
{ |
038cb67a |
struct cli_pwdb *thiz, *that; |
ac0cbde8 |
|
544fa973 |
#ifndef USE_MPOOL
UNUSEDPARAM(engine);
#endif
|
038cb67a |
thiz = pwdb;
while (thiz) { |
288057e9 |
that = thiz->next; |
038cb67a |
|
544fa973 |
MPOOL_FREE(engine->mempool, thiz->name);
MPOOL_FREE(engine->mempool, thiz->passwd);
MPOOL_FREE(engine->mempool, thiz); |
038cb67a |
|
288057e9 |
thiz = that; |
ac0cbde8 |
}
}
|
e3aaff8e |
int cl_statfree(struct cl_stat *dbstat)
{
|
288057e9 |
if (dbstat) { |
75ccac9f |
|
b2354dc1 |
#ifdef _WIN32 |
288057e9 |
int i;
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
|
288057e9 |
if (dbstat->stattab) {
free(dbstat->stattab);
dbstat->stattab = NULL;
}
dbstat->entries = 0; |
cd69cf20 |
|
288057e9 |
if (dbstat->dir) {
free(dbstat->dir);
dbstat->dir = NULL;
} |
e3aaff8e |
} else { |
8000d078 |
cli_errmsg("cl_statfree(): Null argument passed\n"); |
288057e9 |
return CL_ENULLARG; |
e3aaff8e |
}
|
8d3aca30 |
return CL_SUCCESS; |
e3aaff8e |
} |
f51e962f |
|
724b2bf7 |
int cl_engine_free(struct cl_engine *engine) |
f51e962f |
{ |
288057e9 |
unsigned int i, j;
struct cli_matcher *root; |
f51e962f |
|
288057e9 |
if (!engine) {
cli_errmsg("cl_free: engine == NULL\n");
return CL_ENULLARG; |
f51e962f |
}
#ifdef CL_THREAD_SAFE
pthread_mutex_lock(&cli_ref_mutex);
#endif
|
288057e9 |
if (engine->refcount)
engine->refcount--; |
04ba76d2 |
|
288057e9 |
if (engine->refcount) { |
f51e962f |
#ifdef CL_THREAD_SAFE |
288057e9 |
pthread_mutex_unlock(&cli_ref_mutex); |
f51e962f |
#endif |
288057e9 |
return CL_SUCCESS; |
f51e962f |
}
|
f2571e34 |
if (engine->cb_stats_submit)
engine->cb_stats_submit(engine, engine->stats_data);
|
f51e962f |
#ifdef CL_THREAD_SAFE |
e6bcbd5a |
if (engine->stats_data) {
cli_intel_t *intel = (cli_intel_t *)(engine->stats_data);
pthread_mutex_destroy(&(intel->mutex));
}
|
f51e962f |
pthread_mutex_unlock(&cli_ref_mutex);
#endif |
e6bcbd5a |
if (engine->stats_data)
free(engine->stats_data);
|
288057e9 |
if (engine->root) {
for (i = 0; i < CLI_MTARGETS; i++) {
if ((root = engine->root[i])) {
if (!root->ac_only)
cli_bm_free(root);
cli_ac_free(root);
if (root->ac_lsigtable) {
for (j = 0; j < root->ac_lsigs; j++) {
if (root->ac_lsigtable[j]->type == CLI_LSIG_NORMAL) |
544fa973 |
MPOOL_FREE(engine->mempool, root->ac_lsigtable[j]->u.logic); |
288057e9 |
FREE_TDB(root->ac_lsigtable[j]->tdb); |
544fa973 |
MPOOL_FREE(engine->mempool, root->ac_lsigtable[j]); |
288057e9 |
} |
544fa973 |
MPOOL_FREE(engine->mempool, root->ac_lsigtable); |
288057e9 |
} |
7afaa9bd |
#if HAVE_PCRE |
35a05ff8 |
cli_pcre_freetable(root); |
7afaa9bd |
#endif /* HAVE_PCRE */ |
544fa973 |
MPOOL_FREE(engine->mempool, root); |
288057e9 |
}
} |
544fa973 |
MPOOL_FREE(engine->mempool, engine->root); |
f51e962f |
}
|
288057e9 |
if ((root = engine->hm_hdb)) {
hm_free(root); |
544fa973 |
MPOOL_FREE(engine->mempool, root); |
f51e962f |
}
|
288057e9 |
if ((root = engine->hm_mdb)) {
hm_free(root); |
544fa973 |
MPOOL_FREE(engine->mempool, root); |
2f942502 |
}
|
8650c790 |
if ((root = engine->hm_imp)) {
hm_free(root); |
544fa973 |
MPOOL_FREE(engine->mempool, root); |
8650c790 |
}
|
288057e9 |
if ((root = engine->hm_fp)) {
hm_free(root); |
544fa973 |
MPOOL_FREE(engine->mempool, root); |
2b459819 |
}
|
f05aa165 |
crtmgr_free(&engine->cmgr);
|
288057e9 |
while (engine->cdb) {
struct cli_cdb *pt = engine->cdb;
engine->cdb = pt->next;
if (pt->name.re_magic)
cli_regfree(&pt->name); |
544fa973 |
MPOOL_FREE(engine->mempool, pt->res2);
MPOOL_FREE(engine->mempool, pt->virname);
MPOOL_FREE(engine->mempool, pt); |
55094a9c |
}
|
288057e9 |
while (engine->dbinfo) {
struct cli_dbinfo *pt = engine->dbinfo;
engine->dbinfo = pt->next; |
544fa973 |
MPOOL_FREE(engine->mempool, pt->name);
MPOOL_FREE(engine->mempool, pt->hash); |
288057e9 |
if (pt->cvd)
cl_cvdfree(pt->cvd); |
544fa973 |
MPOOL_FREE(engine->mempool, pt); |
ace26bfe |
}
|
288057e9 |
if (engine->dconf) {
if (engine->dconf->bytecode & BYTECODE_ENGINE_MASK) { |
1f19b713 |
if (engine->bcs.all_bcs) |
288057e9 |
for (i = 0; i < engine->bcs.count; i++) |
1f19b713 |
cli_bytecode_destroy(&engine->bcs.all_bcs[i]);
cli_bytecode_done(&engine->bcs);
free(engine->bcs.all_bcs); |
288057e9 |
for (i = 0; i < _BC_LAST_HOOK - _BC_START_HOOKS; i++) {
free(engine->hooks[i]); |
1f19b713 |
}
}
|
288057e9 |
if (engine->dconf->phishing & PHISHING_CONF_ENGINE) |
1f19b713 |
phishing_done(engine);
|
544fa973 |
MPOOL_FREE(engine->mempool, engine->dconf); |
1f19b713 |
} |
bc93eda0 |
|
288057e9 |
if (engine->pwdbs) {
for (i = 0; i < CLI_PWDB_COUNT; i++)
if (engine->pwdbs[i]) |
038cb67a |
cli_pwdb_list_free(engine, engine->pwdbs[i]); |
544fa973 |
MPOOL_FREE(engine->mempool, engine->pwdbs); |
288057e9 |
}
if (engine->pua_cats) |
544fa973 |
MPOOL_FREE(engine->mempool, engine->pua_cats); |
288057e9 |
if (engine->iconcheck) {
struct icon_matcher *iconcheck = engine->iconcheck;
for (i = 0; i < 3; i++) {
if (iconcheck->icons[i]) {
for (j = 0; j < iconcheck->icon_counts[i]; j++) {
struct icomtr *metric = iconcheck->icons[i]; |
544fa973 |
MPOOL_FREE(engine->mempool, metric[j].name); |
288057e9 |
} |
544fa973 |
MPOOL_FREE(engine->mempool, iconcheck->icons[i]); |
288057e9 |
}
}
if (iconcheck->group_names[0]) {
for (i = 0; i < iconcheck->group_counts[0]; i++) |
544fa973 |
MPOOL_FREE(engine->mempool, iconcheck->group_names[0][i]);
MPOOL_FREE(engine->mempool, iconcheck->group_names[0]); |
288057e9 |
}
if (iconcheck->group_names[1]) {
for (i = 0; i < iconcheck->group_counts[1]; i++) |
544fa973 |
MPOOL_FREE(engine->mempool, iconcheck->group_names[1][i]);
MPOOL_FREE(engine->mempool, iconcheck->group_names[1]); |
288057e9 |
} |
544fa973 |
MPOOL_FREE(engine->mempool, iconcheck); |
288057e9 |
}
if (engine->tmpdir) |
544fa973 |
MPOOL_FREE(engine->mempool, engine->tmpdir); |
288057e9 |
if (engine->cache)
cli_cache_destroy(engine); |
6223810b |
|
0d9dbdef |
cli_ftfree(engine); |
288057e9 |
if (engine->ignored) {
cli_bm_free(engine->ignored); |
544fa973 |
MPOOL_FREE(engine->mempool, engine->ignored); |
288057e9 |
}
if (engine->test_root) {
root = engine->test_root;
if (!root->ac_only)
cli_bm_free(root);
cli_ac_free(root);
if (root->ac_lsigtable) {
for (i = 0; i < root->ac_lsigs; i++) {
if (root->ac_lsigtable[i]->type == CLI_LSIG_NORMAL) |
544fa973 |
MPOOL_FREE(engine->mempool, root->ac_lsigtable[i]->u.logic); |
288057e9 |
FREE_TDB(root->ac_lsigtable[i]->tdb); |
544fa973 |
MPOOL_FREE(engine->mempool, root->ac_lsigtable[i]); |
288057e9 |
} |
544fa973 |
MPOOL_FREE(engine->mempool, root->ac_lsigtable); |
288057e9 |
} |
e8ab1083 |
#if HAVE_PCRE |
288057e9 |
cli_pcre_freetable(root); |
e8ab1083 |
#endif /* HAVE_PCRE */ |
544fa973 |
MPOOL_FREE(engine->mempool, root); |
e8ab1083 |
} |
04133ff9 |
|
0d9dbdef |
#ifdef USE_MPOOL |
288057e9 |
if (engine->mempool) mpool_destroy(engine->mempool); |
e21657df |
#endif |
d03c18be |
|
baeb6253 |
#ifdef HAVE_YARA |
b6ad4322 |
cli_yara_free(engine); |
baeb6253 |
#endif |
d03c18be |
|
f51e962f |
free(engine); |
724b2bf7 |
return CL_SUCCESS; |
f51e962f |
}
|
724b2bf7 |
int cl_engine_compile(struct cl_engine *engine) |
f51e962f |
{ |
288057e9 |
unsigned int i;
int ret;
struct cli_matcher *root; |
f51e962f |
|
288057e9 |
if (!engine)
return CL_ENULLARG; |
baeb6253 |
#ifdef HAVE_YARA |
d03c18be |
/* Free YARA hash tables - only needed for parse and load */ |
b6ad4322 |
if (engine->yara_global != NULL) {
if (engine->yara_global->rules_table)
yr_hash_table_destroy(engine->yara_global->rules_table, NULL);
if (engine->yara_global->objects_table)
yr_hash_table_destroy(engine->yara_global->objects_table, NULL);
engine->yara_global->rules_table = engine->yara_global->objects_table = NULL;
} |
baeb6253 |
#endif |
d03c18be |
|
288057e9 |
if (!engine->ftypes)
if ((ret = cli_loadftm(NULL, engine, 0, 1, NULL)))
return ret; |
f51e962f |
|
ac0cbde8 |
/* handle default passwords */ |
288057e9 |
if (!engine->pwdbs[0] && !engine->pwdbs[1] && !engine->pwdbs[2])
if ((ret = cli_loadpwdb(NULL, engine, 0, 1, NULL)))
return ret;
for (i = 0; i < CLI_MTARGETS; i++) {
if ((root = engine->root[i])) {
if ((ret = cli_ac_buildtrie(root)))
return ret; |
7afaa9bd |
#if HAVE_PCRE |
288057e9 |
if ((ret = cli_pcre_build(root, engine->pcre_match_limit, engine->pcre_recmatch_limit, engine->dconf))) |
9bc7c138 |
return ret;
|
288057e9 |
cli_dbgmsg("Matcher[%u]: %s: AC sigs: %u (reloff: %u, absoff: %u) BM sigs: %u (reloff: %u, absoff: %u) PCREs: %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->pcre_metas, root->pcre_reloff_num, root->pcre_absoff_num, root->maxpatlen, root->ac_only ? "(ac_only mode)" : ""); |
7afaa9bd |
#else |
288057e9 |
cli_dbgmsg("Matcher[%u]: %s: AC sigs: %u (reloff: %u, absoff: %u) BM sigs: %u (reloff: %u, absoff: %u) maxpatlen %u PCREs: 0 (disabled) %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)" : ""); |
7afaa9bd |
#endif |
288057e9 |
}
}
if (engine->hm_hdb)
hm_flush(engine->hm_hdb);
if (engine->hm_mdb)
hm_flush(engine->hm_mdb);
|
8650c790 |
if (engine->hm_imp)
hm_flush(engine->hm_imp);
|
288057e9 |
if (engine->hm_fp)
hm_flush(engine->hm_fp);
if ((ret = cli_build_regex_list(engine->whitelist_matcher))) {
return ret;
}
if ((ret = cli_build_regex_list(engine->domainlist_matcher))) {
return ret;
}
if (engine->ignored) {
cli_bm_free(engine->ignored); |
544fa973 |
MPOOL_FREE(engine->mempool, engine->ignored); |
288057e9 |
engine->ignored = NULL;
}
if (engine->test_root) {
root = engine->test_root;
if (!root->ac_only)
cli_bm_free(root);
cli_ac_free(root);
if (root->ac_lsigtable) {
for (i = 0; i < root->ac_lsigs; i++) {
if (root->ac_lsigtable[i]->type == CLI_LSIG_NORMAL) |
544fa973 |
MPOOL_FREE(engine->mempool, root->ac_lsigtable[i]->u.logic); |
288057e9 |
FREE_TDB(root->ac_lsigtable[i]->tdb); |
544fa973 |
MPOOL_FREE(engine->mempool, root->ac_lsigtable[i]); |
288057e9 |
} |
544fa973 |
MPOOL_FREE(engine->mempool, root->ac_lsigtable); |
288057e9 |
} |
e8ab1083 |
#if HAVE_PCRE |
288057e9 |
cli_pcre_freetable(root); |
e8ab1083 |
#endif /* HAVE_PCRE */ |
544fa973 |
MPOOL_FREE(engine->mempool, root); |
288057e9 |
engine->test_root = NULL; |
e8ab1083 |
} |
02ce73de |
cli_dconf_print(engine->dconf); |
544fa973 |
MPOOL_FLUSH(engine->mempool); |
02ce73de |
|
52dd3a6b |
/* Compile bytecode */ |
288057e9 |
if ((ret = cli_bytecode_prepare2(engine, &engine->bcs, engine->dconf->bytecode))) {
cli_errmsg("Unable to compile/load bytecode: %s\n", cl_strerror(ret));
return ret; |
52dd3a6b |
}
|
b3df93db |
engine->dboptions |= CL_DB_COMPILED; |
8d3aca30 |
return CL_SUCCESS; |
f51e962f |
}
|
b8fe70b3 |
int cl_engine_addref(struct cl_engine *engine) |
f51e962f |
{ |
288057e9 |
if (!engine) {
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)
{ |
288057e9 |
char buffer[CLI_DEFAULT_LSIG_BUFSIZE + 1];
FILE *fs;
unsigned int entry = 0; |
d46cdd59 |
fs = fopen(dbname, "r"); |
288057e9 |
if (!fs) {
cli_errmsg("countentries: Can't open file %s\n", dbname);
return CL_EOPEN; |
d46cdd59 |
} |
288057e9 |
while (fgets(buffer, sizeof(buffer), fs)) {
if (buffer[0] == '#')
continue;
entry++; |
d46cdd59 |
}
fclose(fs);
*sigs += entry;
return CL_SUCCESS;
}
static int countsigs(const char *dbname, unsigned int options, unsigned int *sigs)
{ |
288057e9 |
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);
} |
afe940da |
} else if ((cli_strbcasestr(dbname, ".cud"))) {
if (options & CL_COUNTSIGS_UNOFFICIAL) {
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);
} |
288057e9 |
} else if (cli_strbcasestr(dbname, ".cbc")) {
if (options & CL_COUNTSIGS_UNOFFICIAL)
(*sigs)++;
|
afe940da |
} else if (cli_strbcasestr(dbname, ".wdb") || cli_strbcasestr(dbname, ".fp") || cli_strbcasestr(dbname, ".sfp") || cli_strbcasestr(dbname, ".ign") || cli_strbcasestr(dbname, ".ign2") || cli_strbcasestr(dbname, ".ftm") || cli_strbcasestr(dbname, ".cfg") || cli_strbcasestr(dbname, ".cat")) {
/* ignore whitelist/FP signatures and metadata files */
// TODO .crb sigs can contain both whitelist and blacklist signatures.
// For now we will just include both in the count by not excluding this
// sig type here, but in the future we could extract just the number of
// blacklist rules manually so that the count is more accurate. |
288057e9 |
|
afe940da |
// NOTE: We implicitly ignore .info files because they aren't currently
// in the list of ones checked for by CLI_DBEXT |
288057e9 |
} else if ((options & CL_COUNTSIGS_UNOFFICIAL) && CLI_DBEXT(dbname)) {
return countentries(dbname, sigs); |
d46cdd59 |
}
return CL_SUCCESS;
}
int cl_countsigs(const char *path, unsigned int countoptions, unsigned int *sigs)
{ |
288057e9 |
STATBUF sb;
char fname[1024];
struct dirent *dent;
DIR *dd;
int ret; |
d46cdd59 |
|
288057e9 |
if (!sigs)
return CL_ENULLARG; |
d46cdd59 |
|
288057e9 |
if (CLAMSTAT(path, &sb) == -1) {
cli_errmsg("cl_countsigs: Can't stat %s\n", path);
return CL_ESTAT; |
d46cdd59 |
}
|
288057e9 |
if ((sb.st_mode & S_IFMT) == S_IFREG) {
return countsigs(path, countoptions, sigs); |
d46cdd59 |
|
288057e9 |
} 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;
}
while ((dent = readdir(dd))) {
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); |
d46cdd59 |
} else { |
288057e9 |
cli_errmsg("cl_countsigs: Unsupported file type\n");
return CL_EARG; |
d46cdd59 |
}
return CL_SUCCESS;
} |