libclamav/readdb.c
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;
 }