/*
* Copyright ( C ) 2007 - 2010 Sourcefire , Inc .
*
* Authors : Tomasz Kojm
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* 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
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston ,
* MA 02110 - 1301 , USA .
*/
# if HAVE_CONFIG_H
# include "clamav-config.h"
# endif
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif
# include <dirent.h>
# include <sys/types.h>
# include <sys/stat.h>
# ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
# endif
# include <fcntl.h>
# include <zlib.h>
# include <errno.h>
# include "clamav.h"
# include "cvd.h"
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
# include "matcher-ac.h"
# include "matcher-bm.h"
# include "matcher-md5.h"
# include "matcher.h"
# include "others.h"
# include "str.h"
# include "dconf.h"
# include "filetypes.h"
# include "filetypes_int.h"
# include "readdb.h"
# include "cltypes.h"
# include "default.h"
# include "md5.h"
# include "sha256.h"
# include "dsig.h"
# include "phishcheck.h"
# include "phish_whitelist.h"
# include "phish_domaincheck_db.h"
# include "regex_list.h"
# include "hashtab.h"
# if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
# include <limits.h>
# include <stddef.h>
# endif
# include "mpool.h"
# include "bytecode.h"
# include "bytecode_api.h"
# include "bytecode_priv.h"
# include "cache.h"
# ifdef CL_THREAD_SAFE
# include <pthread.h>
static pthread_mutex_t cli_ref_mutex = PTHREAD_MUTEX_INITIALIZER ;
# endif
char * cli_virname ( char * virname , unsigned int official )
{
char * newname , * pt ;
if ( ! virname )
return NULL ;
if ( ( pt = strstr ( virname , " (Clam) " ) ) )
* pt = ' \0 ' ;
if ( ! virname [ 0 ] ) {
cli_errmsg ( " cli_virname: Empty virus name \n " ) ;
return NULL ;
}
if ( official )
return cli_strdup ( virname ) ;
newname = ( char * ) cli_malloc ( strlen ( virname ) + 11 + 1 ) ;
if ( ! newname ) {
cli_errmsg ( " cli_virname: Can't allocate memory for newname \n " ) ;
return NULL ;
}
sprintf ( newname , " %s.UNOFFICIAL " , virname ) ;
return newname ;
}
int cli_parse_add ( struct cli_matcher * root , const char * virname , const char * hexsig , uint16_t rtype , uint16_t type , const char * offset , uint8_t target , const uint32_t * lsigid , unsigned int options )
{
struct cli_bm_patt * bm_new ;
char * pt , * hexcpy , * start , * n ;
int ret , asterisk = 0 ;
unsigned int i , j , hexlen , parts = 0 ;
int mindist = 0 , maxdist = 0 , error = 0 ;
hexlen = strlen ( hexsig ) ;
if ( hexsig [ 0 ] = = ' $ ' ) {
/* macro */
unsigned smin , smax , tid ;
struct cli_ac_patt * patt ;
if ( hexsig [ hexlen - 1 ] ! = ' $ ' ) {
cli_errmsg ( " cli_parseadd(): missing terminator $ \n " ) ;
return CL_EMALFDB ;
}
if ( ! lsigid ) {
cli_errmsg ( " cli_parseadd(): macro signatures only valid inside logical signatures \n " ) ;
return CL_EMALFDB ;
}
if ( sscanf ( hexsig , " ${%u-%u}%u$ " ,
& smin , & smax , & tid ) ! = 3 ) {
cli_errmsg ( " cli_parseadd(): invalid macro signature format \n " ) ;
return CL_EMALFDB ;
}
if ( tid > = 32 ) {
cli_errmsg ( " cli_parseadd(): only 32 macro groups are supported \n " ) ;
return CL_EMALFDB ;
}
patt = mpool_calloc ( root - > mempool , 1 , sizeof ( * patt ) ) ;
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 ;
patt - > sigid = tid ;
patt - > length = root - > ac_mindepth ;
/* dummy */
patt - > pattern = mpool_calloc ( root - > mempool , patt - > length , sizeof ( * patt - > pattern ) ) ;
if ( patt - > pattern ) {
free ( patt ) ;
return CL_EMEM ;
}
if ( ( ret = cli_ac_addpatt ( root , patt ) ) ) {
mpool_free ( root - > mempool , patt - > pattern ) ;
free ( patt ) ;
return ret ;
}
return CL_SUCCESS ;
}
if ( strchr ( hexsig , ' { ' ) ) {
root - > ac_partsigs + + ;
if ( ! ( hexcpy = cli_strdup ( hexsig ) ) )
return CL_EMEM ;
for ( i = 0 ; i < hexlen ; i + + )
if ( hexsig [ i ] = = ' { ' | | hexsig [ i ] = = ' * ' )
parts + + ;
if ( parts )
parts + + ;
start = pt = hexcpy ;
for ( i = 1 ; i < = parts ; i + + ) {
if ( i ! = parts ) {
for ( j = 0 ; j < strlen ( start ) ; j + + ) {
if ( start [ j ] = = ' { ' ) {
asterisk = 0 ;
pt = start + j ;
break ;
}
if ( start [ j ] = = ' * ' ) {
asterisk = 1 ;
pt = start + j ;
break ;
}
}
* pt + + = 0 ;
}
if ( ( ret = cli_ac_addsig ( root , virname , start , root - > ac_partsigs , parts , i , rtype , type , mindist , maxdist , offset , lsigid , options ) ) ) {
cli_errmsg ( " cli_parse_add(): Problem adding signature (1). \n " ) ;
error = 1 ;
break ;
}
if ( i = = parts )
break ;
mindist = maxdist = 0 ;
if ( asterisk ) {
start = pt ;
continue ;
}
if ( ! ( start = strchr ( pt , ' } ' ) ) ) {
error = 1 ;
break ;
}
* start + + = 0 ;
if ( ! pt ) {
error = 1 ;
break ;
}
if ( ! strchr ( pt , ' - ' ) ) {
if ( ! cli_isnumber ( pt ) | | ( mindist = maxdist = atoi ( pt ) ) < 0 ) {
error = 1 ;
break ;
}
} else {
if ( ( n = cli_strtok ( pt , 0 , " - " ) ) ) {
if ( ! cli_isnumber ( n ) | | ( mindist = atoi ( n ) ) < 0 ) {
error = 1 ;
free ( n ) ;
break ;
}
free ( n ) ;
}
if ( ( n = cli_strtok ( pt , 1 , " - " ) ) ) {
if ( ! cli_isnumber ( n ) | | ( maxdist = atoi ( n ) ) < 0 ) {
error = 1 ;
free ( n ) ;
break ;
}
free ( n ) ;
}
if ( ( n = cli_strtok ( pt , 2 , " - " ) ) ) { /* strict check */
error = 1 ;
free ( n ) ;
break ;
}
}
}
free ( hexcpy ) ;
if ( error )
return CL_EMALFDB ;
} else if ( strchr ( hexsig , ' * ' ) ) {
root - > ac_partsigs + + ;
for ( i = 0 ; i < hexlen ; i + + )
if ( hexsig [ i ] = = ' * ' )
parts + + ;
if ( parts )
parts + + ;
for ( i = 1 ; i < = parts ; i + + ) {
if ( ( pt = cli_strtok ( hexsig , i - 1 , " * " ) ) = = NULL ) {
cli_errmsg ( " Can't extract part %d of partial signature. \n " , i ) ;
return CL_EMALFDB ;
}
if ( ( ret = cli_ac_addsig ( root , virname , pt , root - > ac_partsigs , parts , i , rtype , type , 0 , 0 , offset , lsigid , options ) ) ) {
cli_errmsg ( " cli_parse_add(): Problem adding signature (2). \n " ) ;
free ( pt ) ;
return ret ;
}
free ( pt ) ;
}
} else if ( root - > ac_only | | type | | lsigid | | strpbrk ( hexsig , " ?([ " ) | | ( root - > bm_offmode & & ( ! strcmp ( offset , " * " ) | | strchr ( offset , ' , ' ) ) ) | | strstr ( offset , " VI " ) | | strchr ( offset , ' $ ' ) ) {
if ( ( ret = cli_ac_addsig ( root , virname , hexsig , 0 , 0 , 0 , rtype , type , 0 , 0 , offset , lsigid , options ) ) ) {
cli_errmsg ( " cli_parse_add(): Problem adding signature (3). \n " ) ;
return ret ;
}
} else {
bm_new = ( struct cli_bm_patt * ) mpool_calloc ( root - > mempool , 1 , sizeof ( struct cli_bm_patt ) ) ;
if ( ! bm_new )
return CL_EMEM ;
bm_new - > pattern = ( unsigned char * ) cli_mpool_hex2str ( root - > mempool , hexsig ) ;
if ( ! bm_new - > pattern ) {
mpool_free ( root - > mempool , bm_new ) ;
return CL_EMALFDB ;
}
bm_new - > length = hexlen / 2 ;
bm_new - > virname = cli_mpool_virname ( root - > mempool , virname , options & CL_DB_OFFICIAL ) ;
if ( ! bm_new - > virname ) {
mpool_free ( root - > mempool , bm_new - > pattern ) ;
mpool_free ( root - > mempool , bm_new ) ;
return CL_EMEM ;
}
if ( bm_new - > length > root - > maxpatlen ) {
root - > maxpatlen = bm_new - > length ;
}
if ( ( ret = cli_bm_addpatt ( root , bm_new , offset ) ) ) {
cli_errmsg ( " cli_parse_add(): Problem adding signature (4). \n " ) ;
mpool_free ( root - > mempool , bm_new - > pattern ) ;
mpool_free ( root - > mempool , bm_new - > virname ) ;
mpool_free ( root - > mempool , bm_new ) ;
return ret ;
}
}
return CL_SUCCESS ;
}
int cli_initroots ( struct cl_engine * engine , unsigned int options )
{
int i , ret ;
struct cli_matcher * root ;
for ( i = 0 ; i < CLI_MTARGETS ; i + + ) {
if ( ! engine - > root [ i ] ) {
cli_dbgmsg ( " Initializing engine->root[%d] \n " , i ) ;
root = engine - > root [ i ] = ( struct cli_matcher * ) mpool_calloc ( engine - > mempool , 1 , sizeof ( struct cli_matcher ) ) ;
if ( ! root ) {
cli_errmsg ( " cli_initroots: Can't allocate memory for cli_matcher \n " ) ;
return CL_EMEM ;
}
# ifdef USE_MPOOL
root - > mempool = engine - > mempool ;
# endif
root - > type = i ;
if ( cli_mtargets [ i ] . ac_only | | engine - > ac_only )
root - > ac_only = 1 ;
cli_dbgmsg ( " Initialising AC pattern matcher of root[%d] \n " , i ) ;
if ( ( ret = cli_ac_init ( root , engine - > ac_mindepth , engine - > ac_maxdepth , engine - > dconf - > other & OTHER_CONF_PREFILTERING ) ) ) {
/* 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 ) ;
if ( ( ret = cli_bm_init ( root ) ) ) {
cli_errmsg ( " cli_initroots: Can't initialise BM pattern matcher \n " ) ;
return ret ;
}
}
}
}
engine - > root [ 1 ] - > bm_offmode = 1 ; /* BM offset mode for PE files */
return CL_SUCCESS ;
}
char * cli_dbgets ( char * buff , unsigned int size , FILE * fs , struct cli_dbio * dbio )
{
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: gzread() failed \n " ) ;
return NULL ;
}
}
if ( ! bread )
return NULL ;
dbio - > readpt [ bread ] = 0 ;
dbio - > bufpt = dbio - > buf ;
dbio - > size - = bread ;
dbio - > bread + = bread ;
sha256_update ( & dbio - > sha256ctx , dbio - > readpt , bread ) ;
}
nl = strchr ( dbio - > bufpt , ' \n ' ) ;
if ( nl ) {
if ( nl - dbio - > bufpt > = size ) {
cli_errmsg ( " cli_dbgets: Line too long for provided buffer \n " ) ;
return NULL ;
}
strncpy ( buff , dbio - > bufpt , nl - dbio - > bufpt ) ;
buff [ nl - dbio - > bufpt ] = 0 ;
if ( nl < dbio - > buf + dbio - > bufsize ) {
dbio - > bufpt = + + nl ;
} else {
dbio - > bufpt = NULL ;
dbio - > readpt = dbio - > buf ;
dbio - > readsize = dbio - > size < dbio - > bufsize ? dbio - > size : dbio - > bufsize - 1 ;
}
return buff ;
} else {
unsigned int remain = dbio - > buf + dbio - > bufsize - 1 - dbio - > bufpt ;
if ( dbio - > bufpt = = dbio - > buf ) {
cli_errmsg ( " cli_dbgets: Invalid data or internal buffer too small \n " ) ;
return NULL ;
}
memmove ( dbio - > buf , dbio - > bufpt , remain ) ;
dbio - > readpt = dbio - > buf + remain ;
dbio - > readsize = dbio - > bufsize - remain ;
dbio - > readsize = dbio - > size < dbio - > bufsize - remain ? dbio - > size : dbio - > bufsize - remain - 1 ;
dbio - > bufpt = NULL ;
}
}
} else { /* use gzgets/fgets */
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 ;
sha256_update ( & dbio - > sha256ctx , buff , bs ) ;
return pt ;
}
}
static int cli_chkign ( const struct cli_matcher * ignored , const char * signame , const char * entry )
{
const char * md5_expected = NULL ;
cli_md5_ctx md5ctx ;
unsigned char digest [ 16 ] ;
if ( ! ignored | | ! signame | | ! entry )
return 0 ;
if ( cli_bm_scanbuff ( ( const unsigned char * ) signame , strlen ( signame ) , & md5_expected , NULL , ignored , 0 , NULL , NULL ) = = CL_VIRUS ) {
if ( md5_expected ) {
cli_md5_init ( & md5ctx ) ;
cli_md5_update ( & md5ctx , entry , strlen ( entry ) ) ;
cli_md5_final ( digest , & md5ctx ) ;
if ( memcmp ( digest , ( const unsigned char * ) md5_expected , 16 ) )
return 0 ;
}
cli_dbgmsg ( " Ignoring signature %s \n " , signame ) ;
return 1 ;
}
return 0 ;
}
static int cli_chkpua ( const char * signame , const char * pua_cats , unsigned int options )
{
char cat [ 32 ] , * pt ;
const char * sig ;
int ret ;
if ( strncmp ( signame , " PUA. " , 4 ) ) {
cli_dbgmsg ( " Skipping signature %s - no PUA prefix \n " , signame ) ;
return 1 ;
}
sig = signame + 3 ;
if ( ! ( pt = strchr ( sig + 1 , ' . ' ) ) ) {
cli_dbgmsg ( " Skipping signature %s - bad syntax \n " , signame ) ;
return 1 ;
}
if ( ( unsigned int ) ( pt - sig + 2 ) > sizeof ( cat ) ) {
cli_dbgmsg ( " Skipping signature %s - too long category name \n " , signame ) ;
return 1 ;
}
strncpy ( cat , sig , pt - signame + 1 ) ;
cat [ pt - sig + 1 ] = 0 ;
pt = strstr ( pua_cats , cat ) ;
if ( options & CL_DB_PUA_INCLUDE )
ret = pt ? 0 : 1 ;
else
ret = pt ? 1 : 0 ;
if ( ret )
cli_dbgmsg ( " Skipping PUA signature %s - excluded category \n " , signame ) ;
return ret ;
}
static int cli_loaddb ( FILE * fs , struct cl_engine * engine , unsigned int * signo , unsigned int options , struct cli_dbio * dbio , const char * dbname )
{
char buffer [ FILEBUFF ] , * buffer_cpy = NULL , * pt , * start ;
unsigned int line = 0 , sigs = 0 ;
int ret = 0 ;
struct cli_matcher * root ;
if ( ( ret = cli_initroots ( engine , options ) ) )
return ret ;
root = engine - > root [ 0 ] ;
if ( engine - > ignored )
if ( ! ( buffer_cpy = cli_malloc ( FILEBUFF ) ) )
return CL_EMEM ;
while ( cli_dbgets ( buffer , FILEBUFF , fs , dbio ) ) {
line + + ;
cli_chomp ( buffer ) ;
if ( engine - > ignored )
strcpy ( buffer_cpy , buffer ) ;
pt = strchr ( buffer , ' = ' ) ;
if ( ! pt ) {
cli_errmsg ( " Malformed pattern line %d \n " , line ) ;
ret = CL_EMALFDB ;
break ;
}
start = buffer ;
* pt + + = 0 ;
if ( engine - > ignored & & cli_chkign ( engine - > ignored , start , buffer_cpy ) )
continue ;
if ( engine - > cb_sigload & & engine - > cb_sigload ( " db " , start , engine - > cb_sigload_ctx ) ) {
cli_dbgmsg ( " cli_loaddb: skipping %s due to callback \n " , start ) ;
continue ;
}
if ( * pt = = ' = ' ) continue ;
if ( ( ret = cli_parse_add ( root , start , pt , 0 , 0 , " * " , 0 , NULL , options ) ) ) {
ret = CL_EMALFDB ;
break ;
}
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 ;
return CL_SUCCESS ;
}
# define ICO_TOKENS 4
static int cli_loadidb ( FILE * fs , struct cl_engine * engine , unsigned int * signo , unsigned int options , struct cli_dbio * dbio )
{
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 ;
if ( ! ( matcher = ( struct icon_matcher * ) mpool_calloc ( engine - > mempool , sizeof ( * matcher ) , 1 ) ) )
return CL_EMEM ;
if ( engine - > ignored )
if ( ! ( buffer_cpy = cli_malloc ( FILEBUFF ) ) ) {
mpool_free ( engine - > mempool , matcher ) ;
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 ] , 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 ;
metric = ( struct icomtr * ) mpool_realloc ( engine - > mempool , matcher - > icons [ enginesize ] , sizeof ( struct icomtr ) * ( matcher - > icon_counts [ enginesize ] + 1 ) ) ;
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 ;
}
if ( ! ( metric - > name = cli_mpool_strdup ( engine - > mempool , tokens [ 0 ] ) ) ) {
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 ] ) {
if ( ! ( matcher - > group_names [ 0 ] = mpool_realloc ( engine - > mempool , matcher - > group_names [ 0 ] , sizeof ( char * ) * ( i + 1 ) ) ) | |
! ( matcher - > group_names [ 0 ] [ i ] = cli_mpool_strdup ( engine - > mempool , tokens [ 1 ] ) ) ) {
ret = CL_EMEM ;
break ;
}
matcher - > group_counts [ 0 ] + + ;
}
metric - > group [ 0 ] = i ;
for ( i = 0 ; i < matcher - > group_counts [ 1 ] ; i + + ) {
if ( ! strcmp ( tokens [ 2 ] , matcher - > group_names [ 1 ] [ i ] ) )
break ;
}
if ( i = = matcher - > group_counts [ 1 ] ) {
if ( ! ( matcher - > group_names [ 1 ] = mpool_realloc ( engine - > mempool , matcher - > group_names [ 1 ] , sizeof ( char * ) * ( i + 1 ) ) ) | |
! ( matcher - > group_names [ 1 ] [ i ] = cli_mpool_strdup ( engine - > mempool , tokens [ 2 ] ) ) ) {
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 ;
engine - > iconcheck = matcher ;
return CL_SUCCESS ;
}
static int cli_loadwdb ( FILE * fs , struct cl_engine * engine , unsigned int options , struct cli_dbio * dbio )
{
int ret = 0 ;
if ( ! ( engine - > dconf - > phishing & PHISHING_CONF_ENGINE ) )
return CL_SUCCESS ;
if ( ! engine - > whitelist_matcher ) {
if ( ( ret = init_whitelist ( engine ) ) ) {
return ret ;
}
}
if ( ( ret = load_regex_matcher ( engine , engine - > whitelist_matcher , fs , NULL , options , 1 , dbio , engine - > dconf - > other & OTHER_CONF_PREFILTERING ) ) ) {
return ret ;
}
return CL_SUCCESS ;
}
static int cli_loadpdb ( FILE * fs , struct cl_engine * engine , unsigned int * signo , unsigned int options , struct cli_dbio * dbio )
{
int ret = 0 ;
if ( ! ( engine - > dconf - > phishing & PHISHING_CONF_ENGINE ) )
return CL_SUCCESS ;
if ( ! engine - > domainlist_matcher ) {
if ( ( ret = init_domainlist ( engine ) ) ) {
return ret ;
}
}
if ( ( ret = load_regex_matcher ( engine , engine - > domainlist_matcher , fs , signo , options , 0 , dbio , engine - > dconf - > other & OTHER_CONF_PREFILTERING ) ) ) {
return ret ;
}
return CL_SUCCESS ;
}
# define NDB_TOKENS 6
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 )
{
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 ;
if ( ( ret = cli_initroots ( engine , options ) ) )
return ret ;
if ( engine - > ignored )
if ( ! ( buffer_cpy = cli_malloc ( FILEBUFF ) ) )
return CL_EMEM ;
while ( cli_dbgets ( buffer , FILEBUFF , fs , dbio ) ) {
line + + ;
if ( ! phish )
if ( ! strncmp ( buffer , " HTML.Phishing " , 13 ) | | ! strncmp ( buffer , " Email.Phishing " , 14 ) )
continue ;
cli_chomp ( buffer ) ;
if ( engine - > ignored )
strcpy ( buffer_cpy , buffer ) ;
tokens_count = cli_strtokenize ( buffer , ' : ' , NDB_TOKENS + 1 , tokens ) ;
if ( tokens_count < 4 | | tokens_count > 6 ) {
ret = CL_EMALFDB ;
break ;
}
virname = tokens [ 0 ] ;
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 ;
if ( engine - > ignored & & cli_chkign ( engine - > ignored , virname , buffer_cpy ) )
continue ;
if ( ! sdb & & engine - > cb_sigload & & engine - > cb_sigload ( " ndb " , virname , engine - > cb_sigload_ctx ) ) {
cli_dbgmsg ( " cli_loadndb: skipping %s due to callback \n " , virname ) ;
continue ;
}
if ( tokens_count > 4 ) { /* min version */
pt = tokens [ 4 ] ;
if ( ! cli_isnumber ( pt ) ) {
ret = CL_EMALFDB ;
break ;
}
if ( ( unsigned int ) atoi ( pt ) > cl_retflevel ( ) ) {
cli_dbgmsg ( " Signature for %s not loaded (required f-level: %d) \n " , virname , atoi ( pt ) ) ;
continue ;
}
if ( tokens_count = = 6 ) { /* max version */
pt = tokens [ 5 ] ;
if ( ! cli_isnumber ( pt ) ) {
ret = CL_EMALFDB ;
break ;
}
if ( ( unsigned int ) atoi ( pt ) < cl_retflevel ( ) ) {
continue ;
}
}
}
if ( ! ( pt = tokens [ 1 ] ) | | ( strcmp ( pt , " * " ) & & ! cli_isnumber ( pt ) ) ) {
ret = CL_EMALFDB ;
break ;
}
target = ( unsigned short ) atoi ( pt ) ;
if ( target > = CLI_MTARGETS ) {
cli_dbgmsg ( " Not supported target type in signature for %s \n " , virname ) ;
continue ;
}
root = engine - > root [ target ] ;
offset = tokens [ 2 ] ;
sig = tokens [ 3 ] ;
if ( ( ret = cli_parse_add ( root , virname , sig , 0 , 0 , offset , target , NULL , options ) ) ) {
ret = CL_EMALFDB ;
break ;
}
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 ;
if ( sdb & & sigs & & ! engine - > sdb ) {
engine - > sdb = 1 ;
cli_dbgmsg ( " *** Self protection mechanism activated. \n " ) ;
}
return CL_SUCCESS ;
}
struct lsig_attrib {
const char * name ;
unsigned int type ;
void * * pt ;
} ;
/* TODO: rework this */
static int lsigattribs ( char * attribs , struct cli_lsig_tdb * tdb )
{
struct lsig_attrib attrtab [ ] = {
# define ATTRIB_TOKENS 8
{ " Target " , CLI_TDB_UINT , ( void * * ) & tdb - > target } ,
{ " Engine " , CLI_TDB_RANGE , ( void * * ) & tdb - > engine } ,
{ " FileSize " , CLI_TDB_RANGE , ( void * * ) & tdb - > filesize } ,
{ " EntryPoint " , CLI_TDB_RANGE , ( void * * ) & tdb - > ep } ,
{ " NumberOfSections " , CLI_TDB_RANGE , ( void * * ) & tdb - > nos } ,
{ " IconGroup1 " , CLI_TDB_STR , ( void * * ) & tdb - > icongrp1 } ,
{ " IconGroup2 " , CLI_TDB_STR , ( void * * ) & tdb - > icongrp2 } ,
{ " Container " , CLI_TDB_FTYPE , ( void * * ) & tdb - > container } ,
/*
{ " SectOff " , CLI_TDB_RANGE2 , ( void * * ) & tdb - > sectoff } ,
{ " SectRVA " , CLI_TDB_RANGE2 , ( void * * ) & tdb - > sectrva } ,
{ " SectVSZ " , CLI_TDB_RANGE2 , ( void * * ) & tdb - > sectvsz } ,
{ " SectRAW " , CLI_TDB_RANGE2 , ( void * * ) & tdb - > sectraw } ,
{ " SectRSZ " , CLI_TDB_RANGE2 , ( void * * ) & tdb - > sectrsz } ,
{ " SectURVA " , CLI_TDB_RANGE2 , ( void * * ) & tdb - > secturva } ,
{ " SectUVSZ " , CLI_TDB_RANGE2 , ( void * * ) & tdb - > sectuvsz } ,
{ " SectURAW " , CLI_TDB_RANGE2 , ( void * * ) & tdb - > secturaw } ,
{ " SectURSZ " , CLI_TDB_RANGE2 , ( void * * ) & tdb - > sectursz } ,
*/
{ NULL , 0 , NULL , }
} ;
struct lsig_attrib * apt ;
char * tokens [ ATTRIB_TOKENS ] , * pt , * pt2 ;
unsigned int v1 , v2 , v3 , i , j , tokens_count , have_newext = 0 ;
uint32_t cnt , off [ ATTRIB_TOKENS ] ;
tokens_count = cli_strtokenize ( attribs , ' , ' , ATTRIB_TOKENS , ( const char * * ) tokens ) ;
for ( i = 0 ; i < tokens_count ; i + + ) {
if ( ! ( pt = strchr ( tokens [ i ] , ' : ' ) ) ) {
cli_errmsg ( " lsigattribs: Incorrect format of attribute '%s' \n " , tokens [ i ] ) ;
return - 1 ;
}
* pt + + = 0 ;
apt = NULL ;
for ( j = 0 ; attrtab [ j ] . name ; j + + ) {
if ( ! strcmp ( attrtab [ j ] . name , tokens [ i ] ) ) {
apt = & attrtab [ j ] ;
break ;
}
}
if ( ! apt ) {
cli_dbgmsg ( " lsigattribs: Unknown attribute name '%s' \n " , tokens [ i ] ) ;
return 1 ;
}
if ( ! strcmp ( apt - > name , " Engine " ) ) {
if ( i ) {
cli_errmsg ( " lsigattribs: For backward compatibility the Engine attribute must be on the first position \n " ) ;
return - 1 ;
}
} else if ( strcmp ( apt - > name , " Target " ) )
have_newext = 1 ;
switch ( apt - > type ) {
case CLI_TDB_UINT :
if ( ! cli_isnumber ( pt ) ) {
cli_errmsg ( " lsigattribs: Invalid argument for %s \n " , tokens [ i ] ) ;
return - 1 ;
}
off [ i ] = cnt = tdb - > cnt [ CLI_TDB_UINT ] + + ;
tdb - > val = ( uint32_t * ) mpool_realloc2 ( tdb - > mempool , tdb - > val , tdb - > cnt [ CLI_TDB_UINT ] * sizeof ( uint32_t ) ) ;
if ( ! tdb - > val ) {
tdb - > cnt [ CLI_TDB_UINT ] = 0 ;
return - 1 ;
}
tdb - > val [ cnt ] = atoi ( pt ) ;
break ;
case CLI_TDB_FTYPE :
if ( ( v1 = cli_ftcode ( pt ) ) = = CL_TYPE_ERROR ) {
cli_dbgmsg ( " lsigattribs: Unknown file type in %s \n " , tokens [ i ] ) ;
return 1 ; /* skip */
}
off [ i ] = cnt = tdb - > cnt [ CLI_TDB_UINT ] + + ;
tdb - > val = ( uint32_t * ) mpool_realloc2 ( tdb - > mempool , tdb - > val , tdb - > cnt [ CLI_TDB_UINT ] * sizeof ( uint32_t ) ) ;
if ( ! tdb - > val ) {
tdb - > cnt [ CLI_TDB_UINT ] = 0 ;
return - 1 ;
}
tdb - > val [ cnt ] = v1 ;
break ;
case CLI_TDB_RANGE :
if ( ! ( pt2 = strchr ( pt , ' - ' ) ) ) {
cli_errmsg ( " lsigattribs: Incorrect parameters in '%s' \n " , tokens [ i ] ) ;
return - 1 ;
}
* pt2 + + = 0 ;
off [ i ] = cnt = tdb - > cnt [ CLI_TDB_RANGE ] ;
tdb - > cnt [ CLI_TDB_RANGE ] + = 2 ;
tdb - > range = ( uint32_t * ) mpool_realloc2 ( tdb - > mempool , tdb - > range , tdb - > cnt [ CLI_TDB_RANGE ] * sizeof ( uint32_t ) ) ;
if ( ! tdb - > range ) {
tdb - > cnt [ CLI_TDB_RANGE ] = 0 ;
return - 1 ;
}
if ( ! cli_isnumber ( pt ) | | ! cli_isnumber ( pt2 ) ) {
cli_errmsg ( " lsigattribs: Invalid argument for %s \n " , tokens [ i ] ) ;
return - 1 ;
}
tdb - > range [ cnt ] = atoi ( pt ) ;
tdb - > range [ cnt + 1 ] = atoi ( pt2 ) ;
break ;
case CLI_TDB_RANGE2 :
if ( ! strchr ( pt , ' - ' ) | | ! strchr ( pt , ' . ' ) ) {
cli_errmsg ( " lsigattribs: Incorrect parameters in '%s' \n " , tokens [ i ] ) ;
return - 1 ;
}
off [ i ] = cnt = tdb - > cnt [ CLI_TDB_RANGE ] ;
tdb - > cnt [ CLI_TDB_RANGE ] + = 3 ;
tdb - > range = ( uint32_t * ) mpool_realloc2 ( tdb - > mempool , tdb - > range , tdb - > cnt [ CLI_TDB_RANGE ] * sizeof ( uint32_t ) ) ;
if ( ! tdb - > range ) {
tdb - > cnt [ CLI_TDB_RANGE ] = 0 ;
return - 1 ;
}
if ( sscanf ( pt , " %u.%u-%u " , & v1 , & v2 , & v3 ) ! = 3 ) {
cli_errmsg ( " lsigattribs: Can't parse parameters in '%s' \n " , tokens [ i ] ) ;
return - 1 ;
}
tdb - > range [ cnt ] = ( uint32_t ) v1 ;
tdb - > range [ cnt + 1 ] = ( uint32_t ) v2 ;
tdb - > range [ cnt + 2 ] = ( uint32_t ) v3 ;
break ;
case CLI_TDB_STR :
off [ i ] = cnt = tdb - > cnt [ CLI_TDB_STR ] ;
tdb - > cnt [ CLI_TDB_STR ] + = strlen ( pt ) + 1 ;
tdb - > str = ( char * ) mpool_realloc2 ( tdb - > mempool , tdb - > str , tdb - > cnt [ CLI_TDB_STR ] * sizeof ( char ) ) ;
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 ;
}
}
if ( ! i ) {
cli_errmsg ( " lsigattribs: Empty TDB \n " ) ;
return - 1 ;
}
for ( i = 0 ; i < tokens_count ; i + + ) {
for ( j = 0 ; attrtab [ j ] . name ; j + + ) {
if ( ! strcmp ( attrtab [ j ] . name , tokens [ i ] ) ) {
apt = & attrtab [ j ] ;
break ;
}
}
if ( ! apt )
continue ;
switch ( apt - > type ) {
case CLI_TDB_UINT :
case CLI_TDB_FTYPE :
* apt - > pt = ( uint32_t * ) & tdb - > val [ off [ i ] ] ;
break ;
case CLI_TDB_RANGE :
case CLI_TDB_RANGE2 :
* apt - > pt = ( uint32_t * ) & tdb - > range [ off [ i ] ] ;
break ;
case CLI_TDB_STR :
* apt - > pt = ( char * ) & tdb - > str [ off [ i ] ] ;
break ;
}
}
if ( have_newext & & ( ! tdb - > engine | | tdb - > engine [ 0 ] < 51 ) ) {
cli_errmsg ( " lsigattribs: For backward compatibility all signatures using new attributes must have the Engine attribute present and set to min_level of at least 51 (0.96) \n " ) ;
return - 1 ;
}
return 0 ;
}
# define FREE_TDB(x) do { \
if ( x . cnt [ CLI_TDB_UINT ] ) \
mpool_free ( x . mempool , x . val ) ; \
if ( x . cnt [ CLI_TDB_RANGE ] ) \
mpool_free ( x . mempool , x . range ) ; \
if ( x . cnt [ CLI_TDB_STR ] ) \
mpool_free ( x . mempool , x . str ) ; \
if ( x . macro_ptids ) \
mpool_free ( x . mempool , x . macro_ptids ) ; \
} while ( 0 ) ;
# define LDB_TOKENS 67
static int load_oneldb ( char * buffer , int chkpua , int chkign , struct cl_engine * engine , unsigned int options , const char * dbname , unsigned int line , unsigned int * sigs , unsigned bc_idx , const char * buffer_cpy )
{
const char * sig , * virname , * offset , * logic ;
struct cli_ac_lsig * * newtable , * lsig ;
char * tokens [ LDB_TOKENS + 1 ] , * pt ;
int i , subsigs , tokens_count ;
unsigned short target = 0 ;
struct cli_matcher * root ;
struct cli_lsig_tdb tdb ;
uint32_t lsigid [ 2 ] ;
int ret ;
tokens_count = cli_strtokenize ( buffer , ' ; ' , LDB_TOKENS + 1 , ( const char * * ) tokens ) ;
if ( tokens_count < 4 ) {
return CL_EMALFDB ;
}
virname = tokens [ 0 ] ;
logic = tokens [ 2 ] ;
if ( chkpua & & cli_chkpua ( virname , engine - > pua_cats , options ) )
return CL_SUCCESS ;
if ( chkign & & cli_chkign ( engine - > ignored , virname , buffer_cpy ) )
return CL_SUCCESS ;
if ( engine - > cb_sigload & & engine - > cb_sigload ( " ldb " , virname , engine - > cb_sigload_ctx ) ) {
cli_dbgmsg ( " cli_loadldb: skipping %s due to callback \n " , virname ) ;
( * sigs ) - - ;
return CL_SUCCESS ;
}
subsigs = cli_ac_chklsig ( logic , logic + strlen ( logic ) , NULL , NULL , NULL , 1 ) ;
if ( subsigs = = - 1 ) {
return CL_EMALFDB ;
}
subsigs + + ;
if ( subsigs > 64 ) {
cli_errmsg ( " cli_loadldb: Broken logical expression or too many subsignatures \n " ) ;
return CL_EMALFDB ;
}
if ( ! line ) {
/* This is a logical signature from the bytecode, we need all
* subsignatures , even if not referenced from the logical expression */
if ( subsigs > tokens_count - 3 ) {
cli_errmsg ( " load_oneldb: Too many subsignatures: %u (max %u) \n " ,
subsigs , tokens_count - 3 ) ;
return CL_EMALFDB ;
}
subsigs = tokens_count - 3 ;
} else if ( subsigs ! = tokens_count - 3 ) {
cli_errmsg ( " cli_loadldb: The number of subsignatures (== %u) doesn't match the IDs in the logical expression (== %u) \n " , tokens_count - 3 , subsigs ) ;
return CL_EMALFDB ;
}
/* TDB */
memset ( & tdb , 0 , sizeof ( tdb ) ) ;
# ifdef USE_MPOOL
tdb . mempool = engine - > mempool ;
# endif
if ( ( ret = lsigattribs ( tokens [ 1 ] , & tdb ) ) ) {
FREE_TDB ( tdb ) ;
if ( ret = = 1 ) {
cli_dbgmsg ( " cli_loadldb: Not supported attribute(s) in logical signature for %s, skipping \n " , virname ) ;
( * sigs ) - - ;
return CL_SUCCESS ;
}
return CL_EMALFDB ;
}
if ( ! tdb . target ) {
cli_errmsg ( " cli_loadldb: No target specified in TDB \n " ) ;
FREE_TDB ( tdb ) ;
return CL_EMALFDB ;
} else if ( tdb . target [ 0 ] > = CLI_MTARGETS ) {
cli_dbgmsg ( " cli_loadldb: Not supported target type in logical signature for %s, skipping \n " , virname ) ;
FREE_TDB ( tdb ) ;
( * sigs ) - - ;
return CL_SUCCESS ;
}
if ( ( tdb . icongrp1 | | tdb . icongrp2 ) & & tdb . target [ 0 ] ! = 1 ) {
cli_errmsg ( " cli_loadldb: IconGroup is only supported in PE (target 1) signatures \n " ) ;
FREE_TDB ( tdb ) ;
return CL_EMALFDB ;
}
if ( ( tdb . ep | | tdb . nos ) & & tdb . target [ 0 ] ! = 1 & & tdb . target [ 0 ] ! = 6 & & tdb . target [ 0 ] ! = 9 ) {
cli_errmsg ( " cli_loadldb: EntryPoint/NumberOfSections is only supported in PE/ELF/Mach-O signatures \n " ) ;
FREE_TDB ( tdb ) ;
return CL_EMALFDB ;
}
root = engine - > root [ tdb . target [ 0 ] ] ;
lsig = ( struct cli_ac_lsig * ) mpool_calloc ( engine - > mempool , 1 , sizeof ( struct cli_ac_lsig ) ) ;
if ( ! lsig ) {
cli_errmsg ( " cli_loadldb: Can't allocate memory for lsig \n " ) ;
FREE_TDB ( tdb ) ;
return CL_EMEM ;
}
lsig - > logic = cli_mpool_strdup ( engine - > mempool , logic ) ;
if ( ! lsig - > logic ) {
cli_errmsg ( " cli_loadldb: Can't allocate memory for lsig->logic \n " ) ;
FREE_TDB ( tdb ) ;
mpool_free ( engine - > mempool , lsig ) ;
return CL_EMEM ;
}
lsigid [ 0 ] = lsig - > id = root - > ac_lsigs ;
root - > ac_lsigs + + ;
newtable = ( struct cli_ac_lsig * * ) mpool_realloc ( engine - > mempool , root - > ac_lsigtable , root - > ac_lsigs * sizeof ( struct cli_ac_lsig * ) ) ;
if ( ! newtable ) {
root - > ac_lsigs - - ;
cli_errmsg ( " cli_loadldb: Can't realloc root->ac_lsigtable \n " ) ;
FREE_TDB ( tdb ) ;
mpool_free ( engine - > mempool , lsig ) ;
return CL_EMEM ;
}
/* 0 marks no bc, we can't use a pointer to bc, since that is
* realloced / moved during load */
lsig - > bc_idx = bc_idx ;
newtable [ root - > ac_lsigs - 1 ] = lsig ;
root - > ac_lsigtable = newtable ;
tdb . subsigs = subsigs ;
for ( i = 0 ; i < subsigs ; i + + ) {
lsigid [ 1 ] = i ;
sig = tokens [ 3 + i ] ;
if ( ( pt = strchr ( tokens [ 3 + i ] , ' : ' ) ) ) {
* pt = 0 ;
sig = + + pt ;
offset = tokens [ 3 + i ] ;
} else {
offset = " * " ;
sig = tokens [ 3 + i ] ;
}
if ( ( ret = cli_parse_add ( root , virname , sig , 0 , 0 , offset , target , lsigid , options ) ) )
return ret ;
if ( sig [ 0 ] = = ' $ ' & & i ) {
/* allow mapping from lsig back to pattern for macros */
if ( ! tdb . macro_ptids )
tdb . macro_ptids = mpool_calloc ( root - > mempool , subsigs , sizeof ( * tdb . macro_ptids ) ) ;
if ( ! tdb . macro_ptids )
return CL_EMEM ;
tdb . macro_ptids [ i - 1 ] = root - > ac_patterns - 1 ;
}
if ( tdb . engine ) {
if ( tdb . engine [ 0 ] > cl_retflevel ( ) ) {
cli_dbgmsg ( " cli_loadldb: Signature for %s not loaded (required f-level: %u) \n " , virname , tdb . engine [ 0 ] ) ;
FREE_TDB ( tdb ) ;
( * sigs ) - - ;
return CL_SUCCESS ;
} else if ( tdb . engine [ 1 ] < cl_retflevel ( ) ) {
FREE_TDB ( tdb ) ;
( * sigs ) - - ;
return CL_SUCCESS ;
}
}
}
memcpy ( & lsig - > tdb , & tdb , sizeof ( tdb ) ) ;
return CL_SUCCESS ;
}
static int cli_loadldb ( FILE * fs , struct cl_engine * engine , unsigned int * signo , unsigned int options , struct cli_dbio * dbio , const char * dbname )
{
char buffer [ CLI_DEFAULT_LSIG_BUFSIZE + 1 ] , * buffer_cpy = NULL ;
unsigned int line = 0 , sigs = 0 ;
int ret ;
if ( ( ret = cli_initroots ( engine , options ) ) )
return ret ;
if ( engine - > ignored )
if ( ! ( buffer_cpy = cli_malloc ( sizeof ( buffer ) ) ) )
return CL_EMEM ;
while ( cli_dbgets ( buffer , sizeof ( buffer ) , fs , dbio ) ) {
line + + ;
sigs + + ;
cli_chomp ( buffer ) ;
if ( engine - > ignored )
strcpy ( buffer_cpy , buffer ) ;
ret = load_oneldb ( buffer ,
engine - > pua_cats & & ( options & CL_DB_PUA_MODE ) & & ( options & ( CL_DB_PUA_INCLUDE | CL_DB_PUA_EXCLUDE ) ) ,
! ! engine - > ignored ,
engine , options , dbname , line , & sigs , 0 , buffer_cpy ) ;
if ( ret )
break ;
}
if ( engine - > ignored )
free ( buffer_cpy ) ;
if ( ! line ) {
cli_errmsg ( " Empty database file \n " ) ;
return CL_EMALFDB ;
}
if ( ret ) {
cli_errmsg ( " Problem parsing database at line %u \n " , line ) ;
return ret ;
}
if ( signo )
* signo + = sigs ;
return CL_SUCCESS ;
}
static int cli_loadcbc ( FILE * fs , struct cl_engine * engine , unsigned int * signo , unsigned int options , struct cli_dbio * dbio , const char * dbname )
{
char buf [ 4096 ] ;
int rc ;
struct cli_all_bc * bcs = & engine - > bcs ;
struct cli_bc * bc ;
unsigned sigs = 0 ;
unsigned security_trust = 0 ;
Introduce BC_STARTUP bytecode (bb #2101, #2078).
This bytecode will be run in interpreter mode on startup:
it can disable the JIT, or disable all further bytecodes.
There will be a builtin copy of it that is loaded if
no BC_STARTUP bytecodes were loaded (like filetypes_int.h and daily.ftm).
Only one BC_STARTUP bytecode is accepted, so as soon as bytecode.cvd will
contain one, it won't be overridable!
This bytecode will replace all the JIT checks (CPU, selinux, pax) etc.,
and allows to disable the JIT on just specific OS/arch/compiler/etc.
combinations. There are too many combinations to have a dconf flag for each.
Also fix the bytecode dconf so that the individual JIT_* flags actually work
(previously we could disable the entire JIT, or none at all).
Also introduce preliminary support for bytecode test mode (we already have
auto, jit and interpreter mode, introducing another mode here is easiest).
The test mode doesn't actually compare the outputs yet, but it does fail if
the JIT is disabled / falls back to interpreter.
15 years ago
unsigned i ;
/* TODO: virusname have a common prefix, and whitelist by that */
if ( ( rc = cli_initroots ( engine , options ) ) )
return rc ;
if ( ! ( engine - > dconf - > bytecode & BYTECODE_ENGINE_MASK ) ) {
return CL_SUCCESS ;
}
if ( engine - > cb_sigload & & engine - > cb_sigload ( " cbc " , dbname , engine - > cb_sigload_ctx ) ) {
cli_dbgmsg ( " cli_loadcbc: skipping %s due to callback \n " , dbname ) ;
return CL_SUCCESS ;
}
# ifndef CL_BCUNSIGNED
if ( ! ( options & CL_DB_SIGNED ) ) {
cli_warnmsg ( " Only loading signed bytecode, skipping load of unsigned bytecode! \n " ) ;
return CL_SUCCESS ;
}
# endif
bcs - > all_bcs = cli_realloc2 ( bcs - > all_bcs , sizeof ( * bcs - > all_bcs ) * ( bcs - > count + 1 ) ) ;
if ( ! bcs - > all_bcs ) {
cli_errmsg ( " cli_loadcbc: Can't allocate memory for bytecode entry \n " ) ;
return CL_EMEM ;
}
bcs - > count + + ;
bc = & bcs - > all_bcs [ bcs - > count - 1 ] ;
switch ( engine - > bytecode_security ) {
case CL_BYTECODE_TRUST_ALL :
security_trust = 1 ;
cli_dbgmsg ( " bytecode: trusting all bytecode! \n " ) ;
break ;
case CL_BYTECODE_TRUST_SIGNED :
security_trust = ! ! ( options & CL_DB_SIGNED ) ;
break ;
default :
security_trust = 0 ;
}
rc = cli_bytecode_load ( bc , fs , dbio , security_trust ) ;
/* read remainder of DB, needed because cvd.c checks that we read the entire
* file */
while ( cli_dbgets ( buf , sizeof ( buf ) , fs , dbio ) ) { }
if ( rc ! = CL_SUCCESS ) {
cli_bytecode_destroy ( bc ) ;
cli_errmsg ( " Unable to load %s bytecode: %s \n " , dbname , cl_strerror ( rc ) ) ;
return rc ;
}
if ( bc - > state = = bc_skip ) {
cli_bytecode_destroy ( bc ) ;
bcs - > count - - ;
return CL_SUCCESS ;
}
bc - > id = bcs - > count ; /* must set after _load, since load zeroes */
sigs + + ;
if ( bc - > kind = = BC_LOGICAL | | bc - > lsig ) {
unsigned oldsigs = sigs ;
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 , 0 , engine , options , dbname , 0 , & sigs , bcs - > count , NULL ) ;
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 ( sigs ! = oldsigs ) {
/* compiler ensures Engine field in lsig matches the one in bytecode,
* so this should never happen . */
cli_errmsg ( " Bytecode logical signature skipped, but bytecode itself not? " ) ;
return CL_EMALFDB ;
}
}
if ( bc - > kind ! = BC_LOGICAL ) {
if ( bc - > lsig ) {
/* runlsig will only flip a status bit, not report a match,
* when the hooks are executed we only execute the hook if its
* status bit is on */
bc - > hook_lsig_id = + + engine - > hook_lsig_ids ;
}
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 ) {
Introduce BC_STARTUP bytecode (bb #2101, #2078).
This bytecode will be run in interpreter mode on startup:
it can disable the JIT, or disable all further bytecodes.
There will be a builtin copy of it that is loaded if
no BC_STARTUP bytecodes were loaded (like filetypes_int.h and daily.ftm).
Only one BC_STARTUP bytecode is accepted, so as soon as bytecode.cvd will
contain one, it won't be overridable!
This bytecode will replace all the JIT checks (CPU, selinux, pax) etc.,
and allows to disable the JIT on just specific OS/arch/compiler/etc.
combinations. There are too many combinations to have a dconf flag for each.
Also fix the bytecode dconf so that the individual JIT_* flags actually work
(previously we could disable the entire JIT, or none at all).
Also introduce preliminary support for bytecode test mode (we already have
auto, jit and interpreter mode, introducing another mode here is easiest).
The test mode doesn't actually compare the outputs yet, but it does fail if
the JIT is disabled / falls back to interpreter.
15 years ago
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 ,
Introduce BC_STARTUP bytecode (bb #2101, #2078).
This bytecode will be run in interpreter mode on startup:
it can disable the JIT, or disable all further bytecodes.
There will be a builtin copy of it that is loaded if
no BC_STARTUP bytecodes were loaded (like filetypes_int.h and daily.ftm).
Only one BC_STARTUP bytecode is accepted, so as soon as bytecode.cvd will
contain one, it won't be overridable!
This bytecode will replace all the JIT checks (CPU, selinux, pax) etc.,
and allows to disable the JIT on just specific OS/arch/compiler/etc.
combinations. There are too many combinations to have a dconf flag for each.
Also fix the bytecode dconf so that the individual JIT_* flags actually work
(previously we could disable the entire JIT, or none at all).
Also introduce preliminary support for bytecode test mode (we already have
auto, jit and interpreter mode, introducing another mode here is easiest).
The test mode doesn't actually compare the outputs yet, but it does fail if
the JIT is disabled / falls back to interpreter.
15 years ago
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 ,
Introduce BC_STARTUP bytecode (bb #2101, #2078).
This bytecode will be run in interpreter mode on startup:
it can disable the JIT, or disable all further bytecodes.
There will be a builtin copy of it that is loaded if
no BC_STARTUP bytecodes were loaded (like filetypes_int.h and daily.ftm).
Only one BC_STARTUP bytecode is accepted, so as soon as bytecode.cvd will
contain one, it won't be overridable!
This bytecode will replace all the JIT checks (CPU, selinux, pax) etc.,
and allows to disable the JIT on just specific OS/arch/compiler/etc.
combinations. There are too many combinations to have a dconf flag for each.
Also fix the bytecode dconf so that the individual JIT_* flags actually work
(previously we could disable the entire JIT, or none at all).
Also introduce preliminary support for bytecode test mode (we already have
auto, jit and interpreter mode, introducing another mode here is easiest).
The test mode doesn't actually compare the outputs yet, but it does fail if
the JIT is disabled / falls back to interpreter.
15 years ago
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 ;
}
}
if ( signo )
* signo + = sigs ;
return CL_SUCCESS ;
}
# define FTM_TOKENS 8
static int cli_loadftm ( FILE * fs , struct cl_engine * engine , unsigned int options , unsigned int internal , struct cli_dbio * dbio )
{
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 ;
if ( ( ret = cli_initroots ( engine , options ) ) )
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 ;
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 ;
}
if ( atoi ( tokens [ 0 ] ) = = 1 ) { /* A-C */
if ( ( ret = cli_parse_add ( engine - > root [ 0 ] , tokens [ 3 ] , tokens [ 2 ] , rtype , type , tokens [ 1 ] , 0 , NULL , options ) ) )
break ;
} else if ( atoi ( tokens [ 0 ] ) = = 0 ) { /* memcmp() */
if ( ! cli_isnumber ( tokens [ 1 ] ) ) {
cli_errmsg ( " cli_loadftm: Invalid offset \n " ) ;
ret = CL_EMALFDB ;
break ;
}
new = ( struct cli_ftype * ) mpool_malloc ( engine - > mempool , sizeof ( struct cli_ftype ) ) ;
if ( ! new ) {
ret = CL_EMEM ;
break ;
}
new - > type = type ;
new - > offset = atoi ( tokens [ 1 ] ) ;
new - > magic = ( unsigned char * ) cli_mpool_hex2str ( engine - > mempool , tokens [ 2 ] ) ;
if ( ! new - > magic ) {
cli_errmsg ( " cli_loadftm: Can't decode the hex string \n " ) ;
ret = CL_EMALFDB ;
mpool_free ( engine - > mempool , new ) ;
break ;
}
new - > length = strlen ( tokens [ 2 ] ) / 2 ;
new - > tname = cli_mpool_strdup ( engine - > mempool , tokens [ 3 ] ) ;
if ( ! new - > tname ) {
mpool_free ( engine - > mempool , new - > magic ) ;
mpool_free ( engine - > mempool , new ) ;
ret = CL_EMEM ;
break ;
}
new - > next = engine - > ftypes ;
engine - > ftypes = new ;
} else {
cli_dbgmsg ( " cli_loadftm: Unsupported mode %u \n " , atoi ( tokens [ 0 ] ) ) ;
continue ;
}
sigs + + ;
}
if ( ret ) {
cli_errmsg ( " Problem parsing %s filetype database at line %u \n " , internal ? " built-in " : " external " , line ) ;
return ret ;
}
if ( ! sigs ) {
cli_errmsg ( " Empty %s filetype database \n " , internal ? " built-in " : " external " ) ;
return CL_EMALFDB ;
}
cli_dbgmsg ( " Loaded %u filetype definitions \n " , sigs ) ;
return CL_SUCCESS ;
}
# define INFO_NSTR "11088894983048545473659556106627194923928941791795047620591658697413581043322715912172496806525381055880964520618400224333320534660299233983755341740679502866829909679955734391392668378361221524205396631090105151641270857277080310734320951653700508941717419168723942507890702904702707587451621691050754307850383399865346487203798464178537392211402786481359824461197231102895415093770394216666324484593935762408468516826633192140826667923494822045805347809932848454845886971706424360558667862775876072059437703365380209101697738577515476935085469455279994113145977994084618328482151013142393373316337519977244732747977"
# define INFO_ESTR "100002049"
# define INFO_TOKENS 3
static int cli_loadinfo ( FILE * fs , struct cl_engine * engine , unsigned int options , struct cli_dbio * dbio )
{
const char * tokens [ INFO_TOKENS + 1 ] ;
char buffer [ FILEBUFF ] ;
unsigned int line = 0 , tokens_count , len ;
unsigned char hash [ 32 ] ;
struct cli_dbinfo * last = NULL , * new ;
int ret = CL_SUCCESS , dsig = 0 ;
SHA256_CTX ctx ;
if ( ! dbio ) {
cli_errmsg ( " cli_loadinfo: .info files can only be loaded from within database container files \n " ) ;
return CL_EMALFDB ;
}
sha256_init ( & ctx ) ;
while ( cli_dbgets ( buffer , FILEBUFF , fs , dbio ) ) {
line + + ;
if ( ! strncmp ( buffer , " DSIG: " , 5 ) ) {
dsig = 1 ;
sha256_final ( & ctx , hash ) ;
if ( cli_versig2 ( hash , buffer + 5 , INFO_NSTR , INFO_ESTR ) ! = CL_SUCCESS ) {
cli_errmsg ( " cli_loadinfo: Incorrect digital signature \n " ) ;
ret = CL_EMALFDB ;
}
break ;
}
len = strlen ( buffer ) ;
if ( dbio - > usebuf & & buffer [ len - 1 ] ! = ' \n ' & & len + 1 < FILEBUFF ) {
/* cli_dbgets in buffered mode strips \n */
buffer [ len ] = ' \n ' ;
buffer [ len + 1 ] = 0 ;
}
sha256_update ( & 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 ;
}
last = engine - > dbinfo = ( struct cli_dbinfo * ) mpool_calloc ( engine - > mempool , 1 , sizeof ( struct cli_bm_patt ) ) ;
if ( ! engine - > dbinfo ) {
ret = CL_EMEM ;
break ;
}
engine - > dbinfo - > cvd = cl_cvdparse ( buffer ) ;
if ( ! engine - > dbinfo - > cvd ) {
cli_errmsg ( " cli_loadinfo: Can't parse header entry \n " ) ;
ret = CL_EMALFDB ;
break ;
}
continue ;
}
if ( ! last ) {
cli_errmsg ( " cli_loadinfo: Incorrect file format \n " ) ;
ret = CL_EMALFDB ;
break ;
}
tokens_count = cli_strtokenize ( buffer , ' : ' , INFO_TOKENS + 1 , tokens ) ;
if ( tokens_count ! = INFO_TOKENS ) {
ret = CL_EMALFDB ;
break ;
}
new = ( struct cli_dbinfo * ) mpool_calloc ( engine - > mempool , 1 , sizeof ( struct cli_dbinfo ) ) ;
if ( ! new ) {
ret = CL_EMEM ;
break ;
}
new - > name = cli_mpool_strdup ( engine - > mempool , tokens [ 0 ] ) ;
if ( ! new - > name ) {
mpool_free ( engine - > mempool , new ) ;
ret = CL_EMEM ;
break ;
}
if ( ! cli_isnumber ( tokens [ 1 ] ) ) {
cli_errmsg ( " cli_loadinfo: Invalid value in the size field \n " ) ;
mpool_free ( engine - > mempool , new - > name ) ;
mpool_free ( engine - > mempool , new ) ;
ret = CL_EMALFDB ;
break ;
}
new - > size = atoi ( tokens [ 1 ] ) ;
if ( strlen ( tokens [ 2 ] ) ! = 64 | | ! ( new - > hash = cli_mpool_hex2str ( engine - > mempool , tokens [ 2 ] ) ) ) {
cli_errmsg ( " cli_loadinfo: Malformed SHA256 string at line %u \n " , line ) ;
mpool_free ( engine - > mempool , new - > name ) ;
mpool_free ( engine - > mempool , new ) ;
ret = CL_EMALFDB ;
break ;
}
last - > next = new ;
last = new ;
}
if ( ! 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 ;
}
return CL_SUCCESS ;
}
# define IGN_MAX_TOKENS 3
static int cli_loadign ( FILE * fs , struct cl_engine * engine , unsigned int options , struct cli_dbio * dbio )
{
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 ;
if ( ! engine - > ignored ) {
engine - > ignored = ( struct cli_matcher * ) mpool_calloc ( engine - > mempool , 1 , sizeof ( struct cli_matcher ) ) ;
if ( ! engine - > ignored )
return CL_EMEM ;
# ifdef USE_MPOOL
engine - > ignored - > mempool = engine - > mempool ;
# endif
if ( ( ret = cli_bm_init ( engine - > ignored ) ) ) {
cli_errmsg ( " cli_loadign: Can't initialise AC pattern matcher \n " ) ;
return ret ;
}
}
while ( cli_dbgets ( buffer , FILEBUFF , fs , dbio ) ) {
line + + ;
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 ;
}
new = ( struct cli_bm_patt * ) mpool_calloc ( engine - > mempool , 1 , sizeof ( struct cli_bm_patt ) ) ;
if ( ! new ) {
ret = CL_EMEM ;
break ;
}
new - > pattern = ( unsigned char * ) cli_mpool_strdup ( engine - > mempool , signame ) ;
if ( ! new - > pattern ) {
mpool_free ( engine - > mempool , new ) ;
ret = CL_EMEM ;
break ;
}
if ( hash ) {
if ( strlen ( hash ) ! = 32 | | ! ( new - > virname = ( char * ) cli_mpool_hex2str ( engine - > mempool , hash ) ) ) {
cli_errmsg ( " cli_loadign: Malformed MD5 string at line %u \n " , line ) ;
mpool_free ( engine - > mempool , new - > pattern ) ;
mpool_free ( engine - > mempool , new ) ;
ret = CL_EMALFDB ;
break ;
}
}
new - > length = len ;
new - > boundary | = BM_BOUNDARY_EOL ;
if ( ( ret = cli_bm_addpatt ( engine - > ignored , new , " 0 " ) ) ) {
if ( hash )
mpool_free ( engine - > mempool , new - > virname ) ;
mpool_free ( engine - > mempool , new - > pattern ) ;
mpool_free ( engine - > mempool , new ) ;
break ;
}
}
if ( ret ) {
cli_errmsg ( " cli_loadign: Problem parsing database at line %u \n " , line ) ;
return ret ;
}
return CL_SUCCESS ;
}
# define MD5_HDB 0
# define MD5_MDB 1
# define MD5_FP 2
static int cli_md5db_init ( struct cl_engine * engine , unsigned int mode )
{
struct cli_matcher * bm = NULL ;
int ret ;
if ( mode = = MD5_HDB ) {
bm = engine - > md5_hdb = ( struct cli_matcher * ) mpool_calloc ( engine - > mempool , sizeof ( struct cli_matcher ) , 1 ) ;
} else if ( mode = = MD5_MDB ) {
bm = engine - > md5_mdb = ( struct cli_matcher * ) mpool_calloc ( engine - > mempool , sizeof ( struct cli_matcher ) , 1 ) ;
} else {
bm = engine - > md5_fp = ( struct cli_matcher * ) mpool_calloc ( engine - > mempool , sizeof ( struct cli_matcher ) , 1 ) ;
}
if ( ! bm )
return CL_EMEM ;
# ifdef USE_MPOOL
bm - > mempool = engine - > mempool ;
# endif
if ( ( ret = cli_md5m_init ( bm ) ) ) {
cli_errmsg ( " cli_md5db_init: Failed to initialize MD5 matcher \n " ) ;
return ret ;
}
return CL_SUCCESS ;
}
# define MD5_DB \
if ( mode = = MD5_HDB ) \
db = engine - > md5_hdb ; \
else if ( mode = = MD5_MDB ) \
db = engine - > md5_mdb ; \
else \
db = engine - > md5_fp ;
# define MD5_TOKENS 3
static int cli_loadmd5 ( FILE * fs , struct cl_engine * engine , unsigned int * signo , unsigned int mode , unsigned int options , struct cli_dbio * dbio , const char * dbname )
{
const char * tokens [ MD5_TOKENS + 1 ] ;
char buffer [ FILEBUFF ] , * buffer_cpy = NULL ;
const char * pt ;
unsigned char * md5 ;
int ret = CL_SUCCESS ;
unsigned int size_field = 1 , md5_field = 0 , line = 0 , sigs = 0 , tokens_count ;
struct cli_md5m_patt * new ;
struct cli_matcher * db = NULL ;
if ( mode = = MD5_MDB ) {
size_field = 0 ;
md5_field = 1 ;
}
if ( engine - > ignored )
if ( ! ( buffer_cpy = cli_malloc ( FILEBUFF ) ) )
return CL_EMEM ;
while ( cli_dbgets ( buffer , FILEBUFF , fs , dbio ) ) {
line + + ;
cli_chomp ( buffer ) ;
if ( engine - > ignored )
strcpy ( buffer_cpy , buffer ) ;
tokens_count = cli_strtokenize ( buffer , ' : ' , MD5_TOKENS + 1 , tokens ) ;
if ( tokens_count ! = MD5_TOKENS ) {
ret = CL_EMALFDB ;
break ;
}
if ( ! cli_isnumber ( tokens [ size_field ] ) ) {
cli_errmsg ( " cli_loadmd5: Invalid value for the size field \n " ) ;
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 , engine - > cb_sigload_ctx ) ) {
cli_dbgmsg ( " cli_loadmd5: skipping %s due to callback \n " , pt ) ;
continue ;
}
}
new = ( struct cli_md5m_patt * ) mpool_calloc ( engine - > mempool , 1 , sizeof ( struct cli_md5m_patt ) ) ;
if ( ! new ) {
ret = CL_EMEM ;
break ;
}
pt = tokens [ md5_field ] ; /* md5 */
if ( strlen ( pt ) ! = 32 | | ! ( md5 = ( unsigned char * ) cli_mpool_hex2str ( engine - > mempool , pt ) ) ) {
cli_errmsg ( " cli_loadmd5: Malformed MD5 string at line %u \n " , line ) ;
mpool_free ( engine - > mempool , new ) ;
ret = CL_EMALFDB ;
break ;
}
memcpy ( new - > md5 , md5 , 16 ) ;
mpool_free ( engine - > mempool , md5 ) ;
new - > filesize = atoi ( tokens [ size_field ] ) ;
new - > virname = cli_mpool_virname ( engine - > mempool , tokens [ 2 ] , options & CL_DB_OFFICIAL ) ;
if ( ! new - > virname ) {
mpool_free ( engine - > mempool , new ) ;
ret = CL_EMALFDB ;
break ;
}
MD5_DB ;
if ( ! db & & ( ret = cli_md5db_init ( engine , mode ) ) ) {
mpool_free ( engine - > mempool , new - > virname ) ;
mpool_free ( engine - > mempool , new ) ;
break ;
} else {
MD5_DB ;
}
if ( ( ret = cli_md5m_addpatt ( db , new ) ) ) {
cli_errmsg ( " cli_loadmd5: Error adding BM pattern \n " ) ;
mpool_free ( engine - > mempool , new - > virname ) ;
mpool_free ( engine - > mempool , new ) ;
break ;
}
if ( mode = = MD5_MDB ) { /* section MD5 */
if ( ! db - > md5_sizes_hs . capacity ) {
cli_hashset_init ( & db - > md5_sizes_hs , 65536 , 80 ) ;
}
cli_hashset_addkey ( & db - > md5_sizes_hs , new - > filesize ) ;
}
sigs + + ;
}
if ( engine - > ignored )
free ( buffer_cpy ) ;
if ( ! line ) {
cli_errmsg ( " cli_loadmd5: Empty database file \n " ) ;
return CL_EMALFDB ;
}
if ( ret ) {
cli_errmsg ( " cli_loadmd5: Problem parsing database at line %u \n " , line ) ;
return ret ;
}
if ( signo )
* signo + = sigs ;
return CL_SUCCESS ;
}
# define MD_TOKENS 9
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 )
{
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 ;
if ( engine - > ignored )
if ( ! ( buffer_cpy = cli_malloc ( FILEBUFF ) ) )
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 ;
}
new = ( struct cli_cdb * ) mpool_calloc ( engine - > mempool , 1 , sizeof ( struct cli_cdb ) ) ;
if ( ! new ) {
ret = CL_EMEM ;
break ;
}
new - > virname = cli_mpool_virname ( engine - > mempool , tokens [ 0 ] , options & CL_DB_OFFICIAL ) ;
if ( ! new - > virname ) {
mpool_free ( engine - > mempool , new ) ;
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*/ ) ) {
mpool_free ( engine - > mempool , new - > virname ) ;
mpool_free ( engine - > mempool , new ) ;
continue ;
}
if ( engine - > cb_sigload & & engine - > cb_sigload ( " md " , new - > virname , engine - > cb_sigload_ctx ) ) {
cli_dbgmsg ( " cli_loadmd: skipping %s due to callback \n " , new - > virname ) ;
mpool_free ( engine - > mempool , new - > virname ) ;
mpool_free ( engine - > mempool , new ) ;
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 ] ) ;
mpool_free ( engine - > mempool , new - > virname ) ;
mpool_free ( engine - > mempool , new ) ;
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 ) {
mpool_free ( engine - > mempool , new - > virname ) ;
mpool_free ( engine - > mempool , new ) ;
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 ] , " * " ) ? atoi ( tokens [ 7 ] ) : ( 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 ;
return CL_SUCCESS ;
}
/* 0 1 2 3 4 5 6 7 8 9 10 11
* VirusName : ContainerType : ContainerSize : FileNameREGEX : FileSizeInContainer : FileSizeReal : IsEncrypted : FilePos : Res1 : Res2 [ : MinFL [ : MaxFL ] ]
*/
# define CDB_TOKENS 12
static int cli_loadcdb ( FILE * fs , struct cl_engine * engine , unsigned int * signo , unsigned int options , struct cli_dbio * dbio )
{
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 ) ) )
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 ;
}
}
new = ( struct cli_cdb * ) mpool_calloc ( engine - > mempool , 1 , sizeof ( struct cli_cdb ) ) ;
if ( ! new ) {
ret = CL_EMEM ;
break ;
}
new - > virname = cli_mpool_virname ( engine - > mempool , tokens [ 0 ] , options & CL_DB_OFFICIAL ) ;
if ( ! new - > virname ) {
mpool_free ( engine - > mempool , new ) ;
ret = CL_EMEM ;
break ;
}
if ( engine - > ignored & & cli_chkign ( engine - > ignored , new - > virname , buffer /*_cpy*/ ) ) {
mpool_free ( engine - > mempool , new - > virname ) ;
mpool_free ( engine - > mempool , new ) ;
continue ;
}
if ( engine - > cb_sigload & & engine - > cb_sigload ( " cdb " , new - > virname , engine - > cb_sigload_ctx ) ) {
cli_dbgmsg ( " cli_loadcdb: skipping %s due to callback \n " , new - > virname ) ;
mpool_free ( engine - > mempool , new - > virname ) ;
mpool_free ( engine - > mempool , new ) ;
continue ;
}
if ( ! strcmp ( tokens [ 1 ] , " * " ) ) {
new - > ctype = CL_TYPE_ANY ;
} else if ( ( new - > ctype = cli_ftcode ( tokens [ 1 ] ) ) = = CL_TYPE_ERROR ) {
cli_dbgmsg ( " cli_loadcdb: Unknown container type %s in signature for %s, skipping \n " , tokens [ 1 ] , tokens [ 0 ] ) ;
mpool_free ( engine - > mempool , new - > virname ) ;
mpool_free ( engine - > mempool , new ) ;
continue ;
}
if ( strcmp ( tokens [ 3 ] , " * " ) & & cli_regcomp ( & new - > name , tokens [ 3 ] , REG_EXTENDED | REG_NOSUB ) ) {
cli_errmsg ( " cli_loadcdb: Can't compile regular expression %s in signature for %s \n " , tokens [ 3 ] , tokens [ 0 ] ) ;
mpool_free ( engine - > mempool , new - > virname ) ;
mpool_free ( engine - > mempool , new ) ;
ret = CL_EMEM ;
break ;
}
# define CDBRANGE(token_str, dest) \
if ( strcmp ( token_str , " * " ) ) { \
if ( strchr ( token_str , ' - ' ) ) { \
if ( sscanf ( token_str , " %u-%u " , & n0 , & n1 ) ! = 2 ) { \
ret = CL_EMALFDB ; \
} else { \
dest [ 0 ] = n0 ; \
dest [ 1 ] = n1 ; \
} \
} else { \
if ( ! cli_isnumber ( token_str ) ) \
ret = CL_EMALFDB ; \
else \
dest [ 0 ] = dest [ 1 ] = atoi ( token_str ) ; \
} \
if ( ret ! = CL_SUCCESS ) { \
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 ) ; \
mpool_free ( engine - > mempool , new - > virname ) ; \
mpool_free ( engine - > mempool , new ) ; \
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 ) ;
mpool_free ( engine - > mempool , new - > virname ) ;
mpool_free ( engine - > mempool , new ) ;
ret = CL_EMEM ;
break ;
}
new - > encrypted = * tokens [ 6 ] - 0x30 ;
}
if ( strcmp ( tokens [ 9 ] , " * " ) ) {
new - > res2 = cli_mpool_strdup ( engine - > mempool , tokens [ 9 ] ) ;
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 ) ;
mpool_free ( engine - > mempool , new - > virname ) ;
mpool_free ( engine - > mempool , new ) ;
ret = CL_EMEM ;
break ;
}
}
new - > next = engine - > cdb ;
engine - > cdb = new ;
sigs + + ;
}
if ( engine - > ignored )
free ( buffer_cpy ) ;
if ( ! line ) {
cli_errmsg ( " Empty database file \n " ) ;
return CL_EMALFDB ;
}
if ( ret ) {
cli_errmsg ( " Problem parsing database at line %u \n " , line ) ;
return ret ;
}
if ( signo )
* signo + = sigs ;
return CL_SUCCESS ;
}
static int cli_loaddbdir ( const char * dirname , struct cl_engine * engine , unsigned int * signo , unsigned int options ) ;
int cli_load ( const char * filename , struct cl_engine * engine , unsigned int * signo , unsigned int options , struct cli_dbio * dbio )
{
FILE * fs = NULL ;
int ret = CL_SUCCESS ;
uint8_t skipped = 0 ;
const char * dbname ;
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 ;
}
if ( ( dbname = strrchr ( filename , * PATHSEP ) ) )
dbname + + ;
else
dbname = filename ;
if ( cli_strbcasestr ( dbname , " .db " ) ) {
ret = cli_loaddb ( fs , engine , signo , options , dbio , dbname ) ;
} else if ( cli_strbcasestr ( dbname , " .cvd " ) ) {
ret = cli_cvdload ( fs , engine , signo , options , 0 , filename ) ;
} else if ( cli_strbcasestr ( dbname , " .cld " ) ) {
ret = cli_cvdload ( fs , engine , signo , options , 1 , filename ) ;
} else if ( cli_strbcasestr ( dbname , " .hdb " ) ) {
ret = cli_loadmd5 ( fs , engine , signo , MD5_HDB , options , dbio , dbname ) ;
} else if ( cli_strbcasestr ( dbname , " .hdu " ) ) {
if ( options & CL_DB_PUA )
ret = cli_loadmd5 ( fs , engine , signo , MD5_HDB , options | CL_DB_PUA_MODE , dbio , dbname ) ;
else
skipped = 1 ;
} else if ( cli_strbcasestr ( dbname , " .fp " ) ) {
ret = cli_loadmd5 ( fs , engine , signo , MD5_FP , options , dbio , dbname ) ;
} else if ( cli_strbcasestr ( dbname , " .mdb " ) ) {
ret = cli_loadmd5 ( fs , engine , signo , MD5_MDB , options , dbio , dbname ) ;
} else if ( cli_strbcasestr ( dbname , " .mdu " ) ) {
if ( options & CL_DB_PUA )
ret = cli_loadmd5 ( 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 {
cli_dbgmsg ( " cli_load: unknown extension - assuming old database format \n " ) ;
ret = cli_loaddb ( fs , engine , signo , options , dbio , dbname ) ;
}
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 ) ;
}
if ( fs )
fclose ( fs ) ;
return ret ;
}
static int cli_loaddbdir ( const char * dirname , struct cl_engine * engine , unsigned int * signo , unsigned int options )
{
DIR * dd ;
struct dirent * dent ;
# if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
union {
struct dirent d ;
char b [ offsetof ( struct dirent , d_name ) + NAME_MAX + 1 ] ;
} result ;
# endif
char * dbfile ;
int ret = CL_EOPEN , have_cld ;
struct cl_cvd * daily_cld , * daily_cvd ;
cli_dbgmsg ( " Loading databases from %s \n " , dirname ) ;
if ( ( dd = opendir ( dirname ) ) = = NULL ) {
cli_errmsg ( " cli_loaddbdir(): Can't open directory %s \n " , dirname ) ;
return CL_EOPEN ;
}
/* first round - load .ign and .ign2 files */
# ifdef HAVE_READDIR_R_3
while ( ! readdir_r ( dd , & result . d , & dent ) & & dent ) {
# elif defined(HAVE_READDIR_R_2)
while ( ( dent = ( struct dirent * ) readdir_r ( dd , & result . d ) ) ) {
# else
while ( ( dent = readdir ( dd ) ) ) {
# endif
if ( dent - > d_ino )
{
if ( cli_strbcasestr ( dent - > d_name , " .ign " ) | | cli_strbcasestr ( dent - > d_name , " .ign2 " ) ) {
dbfile = ( char * ) cli_malloc ( strlen ( dent - > d_name ) + strlen ( dirname ) + 2 ) ;
if ( ! dbfile ) {
cli_dbgmsg ( " cli_loaddbdir(): dbfile == NULL \n " ) ;
closedir ( dd ) ;
return CL_EMEM ;
}
sprintf ( dbfile , " %s " PATHSEP " %s " , dirname , dent - > d_name ) ;
ret = cli_load ( dbfile , engine , signo , options , NULL ) ;
if ( ret ) {
cli_dbgmsg ( " cli_loaddbdir(): error loading database %s \n " , dbfile ) ;
free ( dbfile ) ;
closedir ( dd ) ;
return ret ;
}
free ( dbfile ) ;
}
}
}
/* the daily db must be loaded before main */
dbfile = ( char * ) cli_malloc ( strlen ( dirname ) + 20 ) ;
if ( ! dbfile ) {
closedir ( dd ) ;
return CL_EMEM ;
}
sprintf ( dbfile , " %s " PATHSEP " daily.cld " , dirname ) ;
have_cld = ! access ( dbfile , R_OK ) ;
if ( have_cld ) {
daily_cld = cl_cvdhead ( dbfile ) ;
if ( ! daily_cld ) {
cli_errmsg ( " cli_loaddbdir(): error parsing header of %s \n " , dbfile ) ;
free ( dbfile ) ;
closedir ( dd ) ;
return CL_EMALFDB ;
}
}
sprintf ( dbfile , " %s " PATHSEP " daily.cvd " , dirname ) ;
if ( ! access ( dbfile , R_OK ) ) {
if ( have_cld ) {
daily_cvd = cl_cvdhead ( dbfile ) ;
if ( ! daily_cvd ) {
cli_errmsg ( " cli_loaddbdir(): error parsing header of %s \n " , dbfile ) ;
free ( dbfile ) ;
cl_cvdfree ( daily_cld ) ;
closedir ( dd ) ;
return CL_EMALFDB ;
}
if ( daily_cld - > version > daily_cvd - > version )
sprintf ( dbfile , " %s " PATHSEP " daily.cld " , dirname ) ;
cl_cvdfree ( daily_cvd ) ;
}
} else {
sprintf ( dbfile , " %s " PATHSEP " daily.cld " , dirname ) ;
}
if ( have_cld )
cl_cvdfree ( daily_cld ) ;
if ( ! access ( dbfile , R_OK ) & & ( ret = cli_load ( dbfile , engine , signo , options , NULL ) ) ) {
free ( dbfile ) ;
closedir ( dd ) ;
return ret ;
}
/* try to load local.gdb next */
sprintf ( dbfile , " %s " PATHSEP " local.gdb " , dirname ) ;
if ( ! access ( dbfile , R_OK ) & & ( ret = cli_load ( dbfile , engine , signo , options , NULL ) ) ) {
free ( dbfile ) ;
closedir ( dd ) ;
return ret ;
}
/* check for and load daily.cfg */
sprintf ( dbfile , " %s " PATHSEP " daily.cfg " , dirname ) ;
if ( ! access ( dbfile , R_OK ) & & ( ret = cli_load ( dbfile , engine , signo , options , NULL ) ) ) {
free ( dbfile ) ;
closedir ( dd ) ;
return ret ;
}
free ( dbfile ) ;
/* second round - load everything else */
rewinddir ( dd ) ;
# ifdef HAVE_READDIR_R_3
while ( ! readdir_r ( dd , & result . d , & dent ) & & dent ) {
# elif defined(HAVE_READDIR_R_2)
while ( ( dent = ( struct dirent * ) readdir_r ( dd , & result . d ) ) ) {
# else
while ( ( dent = readdir ( dd ) ) ) {
# endif
if ( dent - > d_ino )
{
if ( strcmp ( dent - > d_name , " . " ) & & strcmp ( dent - > d_name , " .. " ) & & strcmp ( dent - > d_name , " daily.cvd " ) & & strcmp ( dent - > d_name , " daily.cld " ) & & strcmp ( dent - > d_name , " daily.cfg " ) & & CLI_DBEXT ( dent - > d_name ) ) {
if ( ( options & CL_DB_OFFICIAL_ONLY ) & & ! strstr ( dirname , " clamav- " ) & & ! cli_strbcasestr ( dent - > d_name , " .cld " ) & & ! cli_strbcasestr ( dent - > d_name , " .cvd " ) ) {
cli_dbgmsg ( " Skipping unofficial database %s \n " , dent - > d_name ) ;
continue ;
}
dbfile = ( char * ) cli_malloc ( strlen ( dent - > d_name ) + strlen ( dirname ) + 2 ) ;
if ( ! dbfile ) {
cli_dbgmsg ( " cli_loaddbdir(): dbfile == NULL \n " ) ;
closedir ( dd ) ;
return CL_EMEM ;
}
sprintf ( dbfile , " %s " PATHSEP " %s " , dirname , dent - > d_name ) ;
ret = cli_load ( dbfile , engine , signo , options , NULL ) ;
if ( ret ) {
cli_dbgmsg ( " cli_loaddbdir(): error loading database %s \n " , dbfile ) ;
free ( dbfile ) ;
closedir ( dd ) ;
return ret ;
}
free ( dbfile ) ;
}
}
}
closedir ( dd ) ;
if ( ret = = CL_EOPEN )
cli_errmsg ( " cli_loaddb(): No supported database files found in %s \n " , dirname ) ;
return ret ;
}
int cl_load ( const char * path , struct cl_engine * engine , unsigned int * signo , unsigned int dboptions )
{
struct stat sb ;
int ret ;
if ( ! engine ) {
cli_errmsg ( " cl_load: engine == NULL \n " ) ;
return CL_ENULLARG ;
}
if ( engine - > dboptions & CL_DB_COMPILED ) {
cli_errmsg ( " cl_load(): can't load new databases when engine is already compiled \n " ) ;
return CL_EARG ;
}
if ( stat ( path , & sb ) = = - 1 ) {
cli_errmsg ( " cl_load(): Can't get status of %s \n " , path ) ;
return CL_ESTAT ;
}
if ( ( dboptions & CL_DB_PHISHING_URLS ) & & ! engine - > phishcheck & & ( engine - > dconf - > phishing & PHISHING_CONF_ENGINE ) )
if ( ( ret = phishing_init ( engine ) ) )
return ret ;
if ( ( dboptions & CL_DB_BYTECODE ) & & ! engine - > bcs . inited ) {
if ( ( ret = cli_bytecode_init ( & engine - > bcs ) ) )
return ret ;
} else {
cli_dbgmsg ( " Bytecode engine disabled \n " ) ;
}
if ( cli_cache_init ( engine ) )
return CL_EMEM ;
engine - > dboptions | = dboptions ;
switch ( sb . st_mode & S_IFMT ) {
case S_IFREG :
ret = cli_load ( path , engine , signo , dboptions , NULL ) ;
break ;
case S_IFDIR :
ret = cli_loaddbdir ( path , engine , signo , dboptions | CL_DB_DIRECTORY ) ;
break ;
default :
cli_errmsg ( " cl_load(%s): Not supported database file type \n " , path ) ;
return CL_EOPEN ;
}
return ret ;
}
const char * cl_retdbdir ( void )
{
return DATADIR ;
}
int cl_statinidir ( const char * dirname , struct cl_stat * dbstat )
{
DIR * dd ;
const struct dirent * dent ;
# if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
union {
struct dirent d ;
char b [ offsetof ( struct dirent , d_name ) + NAME_MAX + 1 ] ;
} result ;
# endif
char * fname ;
if ( dbstat ) {
dbstat - > entries = 0 ;
dbstat - > stattab = NULL ;
dbstat - > statdname = NULL ;
dbstat - > dir = cli_strdup ( dirname ) ;
} else {
cli_errmsg ( " cl_statdbdir(): Null argument passed. \n " ) ;
return CL_ENULLARG ;
}
if ( ( dd = opendir ( dirname ) ) = = NULL ) {
cli_errmsg ( " cl_statdbdir(): Can't open directory %s \n " , dirname ) ;
cl_statfree ( dbstat ) ;
return CL_EOPEN ;
}
cli_dbgmsg ( " Stat()ing files in %s \n " , dirname ) ;
# ifdef HAVE_READDIR_R_3
while ( ! readdir_r ( dd , & result . d , & dent ) & & dent ) {
# elif defined(HAVE_READDIR_R_2)
while ( ( dent = ( struct dirent * ) readdir_r ( dd , & result . d ) ) ) {
# else
while ( ( dent = readdir ( dd ) ) ) {
# endif
if ( dent - > d_ino )
{
if ( strcmp ( dent - > d_name , " . " ) & & strcmp ( dent - > d_name , " .. " ) & & CLI_DBEXT ( dent - > d_name ) ) {
dbstat - > entries + + ;
dbstat - > stattab = ( struct stat * ) cli_realloc2 ( dbstat - > stattab , dbstat - > entries * sizeof ( struct stat ) ) ;
if ( ! dbstat - > stattab ) {
cl_statfree ( dbstat ) ;
closedir ( dd ) ;
return CL_EMEM ;
}
# ifdef _WIN32
dbstat - > statdname = ( char * * ) cli_realloc2 ( dbstat - > statdname , dbstat - > entries * sizeof ( char * ) ) ;
if ( ! dbstat - > statdname ) {
cl_statfree ( dbstat ) ;
closedir ( dd ) ;
return CL_EMEM ;
}
# endif
fname = cli_malloc ( strlen ( dirname ) + strlen ( dent - > d_name ) + 32 ) ;
if ( ! fname ) {
cl_statfree ( dbstat ) ;
closedir ( dd ) ;
return CL_EMEM ;
}
sprintf ( fname , " %s " PATHSEP " %s " , dirname , dent - > d_name ) ;
# ifdef _WIN32
dbstat - > statdname [ dbstat - > entries - 1 ] = ( char * ) cli_malloc ( strlen ( dent - > d_name ) + 1 ) ;
if ( ! dbstat - > statdname [ dbstat - > entries - 1 ] ) {
cl_statfree ( dbstat ) ;
closedir ( dd ) ;
return CL_EMEM ;
}
strcpy ( dbstat - > statdname [ dbstat - > entries - 1 ] , dent - > d_name ) ;
# endif
stat ( fname , & dbstat - > stattab [ dbstat - > entries - 1 ] ) ;
free ( fname ) ;
}
}
}
closedir ( dd ) ;
return CL_SUCCESS ;
}
int cl_statchkdir ( const struct cl_stat * dbstat )
{
DIR * dd ;
struct dirent * dent ;
# if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
union {
struct dirent d ;
char b [ offsetof ( struct dirent , d_name ) + NAME_MAX + 1 ] ;
} result ;
# endif
struct stat sb ;
unsigned int i , found ;
char * fname ;
if ( ! dbstat | | ! dbstat - > dir ) {
cli_errmsg ( " cl_statdbdir(): Null argument passed. \n " ) ;
return CL_ENULLARG ;
}
if ( ( dd = opendir ( dbstat - > dir ) ) = = NULL ) {
cli_errmsg ( " cl_statdbdir(): Can't open directory %s \n " , dbstat - > dir ) ;
return CL_EOPEN ;
}
cli_dbgmsg ( " Stat()ing files in %s \n " , dbstat - > dir ) ;
# ifdef HAVE_READDIR_R_3
while ( ! readdir_r ( dd , & result . d , & dent ) & & dent ) {
# elif defined(HAVE_READDIR_R_2)
while ( ( dent = ( struct dirent * ) readdir_r ( dd , & result . d ) ) ) {
# else
while ( ( dent = readdir ( dd ) ) ) {
# endif
if ( dent - > d_ino )
{
if ( strcmp ( dent - > d_name , " . " ) & & strcmp ( dent - > d_name , " .. " ) & & CLI_DBEXT ( dent - > d_name ) ) {
fname = cli_malloc ( strlen ( dbstat - > dir ) + strlen ( dent - > d_name ) + 32 ) ;
if ( ! fname ) {
closedir ( dd ) ;
return CL_EMEM ;
}
sprintf ( fname , " %s " PATHSEP " %s " , dbstat - > dir , dent - > d_name ) ;
stat ( fname , & sb ) ;
free ( fname ) ;
found = 0 ;
for ( i = 0 ; i < dbstat - > entries ; i + + )
# ifdef _WIN32
if ( ! strcmp ( dbstat - > statdname [ i ] , dent - > d_name ) ) {
# else
if ( dbstat - > stattab [ i ] . st_ino = = sb . st_ino ) {
# endif
found = 1 ;
if ( dbstat - > stattab [ i ] . st_mtime ! = sb . st_mtime ) {
closedir ( dd ) ;
return 1 ;
}
}
if ( ! found ) {
closedir ( dd ) ;
return 1 ;
}
}
}
}
closedir ( dd ) ;
return CL_SUCCESS ;
}
int cl_statfree ( struct cl_stat * dbstat )
{
if ( dbstat ) {
# ifdef _WIN32
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 ;
}
# endif
if ( dbstat - > stattab ) {
free ( dbstat - > stattab ) ;
dbstat - > stattab = NULL ;
}
dbstat - > entries = 0 ;
if ( dbstat - > dir ) {
free ( dbstat - > dir ) ;
dbstat - > dir = NULL ;
}
} else {
cli_errmsg ( " cl_statfree(): Null argument passed \n " ) ;
return CL_ENULLARG ;
}
return CL_SUCCESS ;
}
int cl_engine_free ( struct cl_engine * engine )
{
unsigned int i , j ;
struct cli_matcher * root ;
if ( ! engine ) {
cli_errmsg ( " cl_free: engine == NULL \n " ) ;
return CL_ENULLARG ;
}
# ifdef CL_THREAD_SAFE
pthread_mutex_lock ( & cli_ref_mutex ) ;
# endif
if ( engine - > refcount )
engine - > refcount - - ;
if ( engine - > refcount ) {
# ifdef CL_THREAD_SAFE
pthread_mutex_unlock ( & cli_ref_mutex ) ;
# endif
return CL_SUCCESS ;
}
# ifdef CL_THREAD_SAFE
pthread_mutex_unlock ( & cli_ref_mutex ) ;
# endif
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 + + ) {
mpool_free ( engine - > mempool , root - > ac_lsigtable [ j ] - > logic ) ;
FREE_TDB ( root - > ac_lsigtable [ j ] - > tdb ) ;
mpool_free ( engine - > mempool , root - > ac_lsigtable [ j ] ) ;
}
mpool_free ( engine - > mempool , root - > ac_lsigtable ) ;
}
mpool_free ( engine - > mempool , root ) ;
}
}
mpool_free ( engine - > mempool , engine - > root ) ;
}
if ( ( root = engine - > md5_hdb ) ) {
cli_md5m_free ( root ) ;
mpool_free ( engine - > mempool , root ) ;
}
if ( ( root = engine - > md5_mdb ) ) {
cli_md5m_free ( root ) ;
mpool_free ( engine - > mempool , root - > soff ) ;
if ( root - > md5_sizes_hs . capacity ) {
cli_hashset_destroy ( & root - > md5_sizes_hs ) ;
}
mpool_free ( engine - > mempool , root ) ;
}
if ( ( root = engine - > md5_fp ) ) {
cli_md5m_free ( root ) ;
mpool_free ( engine - > mempool , root ) ;
}
while ( engine - > cdb ) {
struct cli_cdb * pt = engine - > cdb ;
engine - > cdb = pt - > next ;
if ( pt - > name . re_magic )
cli_regfree ( & pt - > name ) ;
mpool_free ( engine - > mempool , pt - > res2 ) ;
mpool_free ( engine - > mempool , pt - > virname ) ;
mpool_free ( engine - > mempool , pt ) ;
}
while ( engine - > dbinfo ) {
struct cli_dbinfo * pt = engine - > dbinfo ;
engine - > dbinfo = pt - > next ;
mpool_free ( engine - > mempool , pt - > name ) ;
mpool_free ( engine - > mempool , pt - > hash ) ;
if ( pt - > cvd )
cl_cvdfree ( pt - > cvd ) ;
mpool_free ( engine - > mempool , pt ) ;
}
if ( engine - > dconf - > bytecode & BYTECODE_ENGINE_MASK ) {
if ( engine - > bcs . all_bcs )
for ( i = 0 ; i < engine - > bcs . count ; i + + )
cli_bytecode_destroy ( & engine - > bcs . all_bcs [ i ] ) ;
cli_bytecode_done ( & engine - > bcs ) ;
free ( engine - > bcs . all_bcs ) ;
for ( i = 0 ; i < _BC_LAST_HOOK - _BC_START_HOOKS ; i + + ) {
free ( engine - > hooks [ i ] ) ;
}
}
if ( engine - > dconf - > phishing & PHISHING_CONF_ENGINE )
phishing_done ( engine ) ;
if ( engine - > dconf )
mpool_free ( engine - > mempool , engine - > dconf ) ;
if ( engine - > pua_cats )
mpool_free ( engine - > mempool , engine - > pua_cats ) ;
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 ] ;
mpool_free ( engine - > mempool , metric [ j ] . name ) ;
}
mpool_free ( engine - > mempool , iconcheck - > icons [ i ] ) ;
}
}
if ( iconcheck - > group_names [ 0 ] ) {
for ( i = 0 ; i < iconcheck - > group_counts [ 0 ] ; i + + )
mpool_free ( engine - > mempool , iconcheck - > group_names [ 0 ] [ i ] ) ;
mpool_free ( engine - > mempool , iconcheck - > group_names [ 0 ] ) ;
}
if ( iconcheck - > group_names [ 1 ] ) {
for ( i = 0 ; i < iconcheck - > group_counts [ 1 ] ; i + + )
mpool_free ( engine - > mempool , iconcheck - > group_names [ 1 ] [ i ] ) ;
mpool_free ( engine - > mempool , iconcheck - > group_names [ 1 ] ) ;
}
mpool_free ( engine - > mempool , iconcheck ) ;
}
if ( engine - > tmpdir )
mpool_free ( engine - > mempool , engine - > tmpdir ) ;
if ( engine - > cache )
cli_cache_destroy ( engine ) ;
cli_ftfree ( engine ) ;
if ( engine - > ignored ) {
cli_bm_free ( engine - > ignored ) ;
mpool_free ( engine - > mempool , engine - > ignored ) ;
}
# ifdef USE_MPOOL
if ( engine - > mempool ) mpool_destroy ( engine - > mempool ) ;
# endif
free ( engine ) ;
return CL_SUCCESS ;
}
static void cli_md5db_build ( struct cli_matcher * root )
{
if ( root & & root - > md5_sizes_hs . capacity ) {
/* TODO: use hashset directly, instead of the array when matching*/
cli_dbgmsg ( " Converting hashset to array: %u entries \n " , root - > md5_sizes_hs . count ) ;
# ifdef USE_MPOOL
{
uint32_t * mpoolht ;
unsigned int mpoolhtsz = root - > md5_sizes_hs . count * sizeof ( * mpoolht ) ;
root - > soff = mpool_malloc ( root - > mempool , mpoolhtsz ) ;
root - > soff_len = cli_hashset_toarray ( & root - > md5_sizes_hs , & mpoolht ) ;
memcpy ( root - > soff , mpoolht , mpoolhtsz ) ;
free ( mpoolht ) ;
}
# else
root - > soff_len = cli_hashset_toarray ( & root - > md5_sizes_hs , & root - > soff ) ;
# endif
cli_hashset_destroy ( & root - > md5_sizes_hs ) ;
cli_qsort ( root - > soff , root - > soff_len , sizeof ( uint32_t ) , NULL ) ;
}
}
int cl_engine_compile ( struct cl_engine * engine )
{
unsigned int i ;
int ret ;
struct cli_matcher * root ;
if ( ! engine )
return CL_ENULLARG ;
if ( ! engine - > ftypes )
if ( ( ret = cli_loadftm ( 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 ;
cli_dbgmsg ( " Matcher[%u]: %s: AC sigs: %u (reloff: %u, absoff: %u) BM sigs: %u (reloff: %u, absoff: %u) maxpatlen %u %s \n " , i , cli_mtargets [ i ] . name , root - > ac_patterns , root - > ac_reloff_num , root - > ac_absoff_num , root - > bm_patterns , root - > bm_reloff_num , root - > bm_absoff_num , root - > maxpatlen , root - > ac_only ? " (ac_only mode) " : " " ) ;
}
}
if ( engine - > md5_hdb )
cli_dbgmsg ( " MD5 sigs (files): %u \n " , engine - > md5_hdb - > md5_patterns ) ;
if ( engine - > md5_mdb )
cli_dbgmsg ( " MD5 sigs (PE sections): %u \n " , engine - > md5_mdb - > md5_patterns ) ;
if ( ( ret = cli_build_regex_list ( engine - > whitelist_matcher ) ) ) {
return ret ;
}
if ( ( ret = cli_build_regex_list ( engine - > domainlist_matcher ) ) ) {
return ret ;
}
cli_md5db_build ( engine - > md5_mdb ) ;
if ( engine - > ignored ) {
cli_bm_free ( engine - > ignored ) ;
mpool_free ( engine - > mempool , engine - > ignored ) ;
engine - > ignored = NULL ;
}
cli_dconf_print ( engine - > dconf ) ;
mpool_flush ( engine - > mempool ) ;
/* Compile bytecode */
if ( ( ret = cli_bytecode_prepare ( engine , & engine - > bcs , engine - > dconf - > bytecode ) ) ) {
cli_errmsg ( " Unable to compile/load bytecode: %s \n " , cl_strerror ( ret ) ) ;
return ret ;
}
engine - > dboptions | = CL_DB_COMPILED ;
return CL_SUCCESS ;
}
int cl_engine_addref ( struct cl_engine * engine )
{
if ( ! engine ) {
cli_errmsg ( " cl_engine_addref: engine == NULL \n " ) ;
return CL_ENULLARG ;
}
# ifdef CL_THREAD_SAFE
pthread_mutex_lock ( & cli_ref_mutex ) ;
# endif
engine - > refcount + + ;
# ifdef CL_THREAD_SAFE
pthread_mutex_unlock ( & cli_ref_mutex ) ;
# endif
return CL_SUCCESS ;
}
static int countentries ( const char * dbname , unsigned int * sigs )
{
char buffer [ CLI_DEFAULT_LSIG_BUFSIZE + 1 ] ;
FILE * fs ;
unsigned int entry = 0 ;
fs = fopen ( dbname , " r " ) ;
if ( ! fs ) {
cli_errmsg ( " countentries: Can't open file %s \n " , dbname ) ;
return CL_EOPEN ;
}
while ( fgets ( buffer , sizeof ( buffer ) , fs ) ) {
if ( buffer [ 0 ] = = ' # ' )
continue ;
entry + + ;
}
fclose ( fs ) ;
* sigs + = entry ;
return CL_SUCCESS ;
}
static int countsigs ( const char * dbname , unsigned int options , unsigned int * sigs )
{
if ( ( cli_strbcasestr ( dbname , " .cvd " ) | | cli_strbcasestr ( dbname , " .cld " ) ) ) {
if ( options & CL_COUNTSIGS_OFFICIAL ) {
struct cl_cvd * cvd = cl_cvdhead ( dbname ) ;
if ( ! cvd ) {
cli_errmsg ( " countsigs: Can't parse %s \n " , dbname ) ;
return CL_ECVD ;
}
* sigs + = cvd - > sigs ;
cl_cvdfree ( cvd ) ;
}
} else if ( cli_strbcasestr ( dbname , " .cbc " ) ) {
if ( options & CL_COUNTSIGS_UNOFFICIAL )
( * sigs ) + + ;
} else if ( cli_strbcasestr ( dbname , " .wdb " ) | | cli_strbcasestr ( dbname , " .fp " ) | | cli_strbcasestr ( dbname , " .ftm " ) | | cli_strbcasestr ( dbname , " .cfg " ) ) {
/* ignore */
} else if ( ( options & CL_COUNTSIGS_UNOFFICIAL ) & & CLI_DBEXT ( dbname ) ) {
return countentries ( dbname , sigs ) ;
}
return CL_SUCCESS ;
}
int cl_countsigs ( const char * path , unsigned int countoptions , unsigned int * sigs )
{
struct stat sb ;
char fname [ 1024 ] ;
struct dirent * dent ;
# if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
union {
struct dirent d ;
char b [ offsetof ( struct dirent , d_name ) + NAME_MAX + 1 ] ;
} result ;
# endif
DIR * dd ;
int ret ;
if ( ! sigs )
return CL_ENULLARG ;
if ( stat ( path , & sb ) = = - 1 ) {
cli_errmsg ( " cl_countsigs: Can't stat %s \n " , path ) ;
return CL_ESTAT ;
}
if ( ( sb . st_mode & S_IFMT ) = = S_IFREG ) {
return countsigs ( path , countoptions , sigs ) ;
} else if ( ( sb . st_mode & S_IFMT ) = = S_IFDIR ) {
if ( ( dd = opendir ( path ) ) = = NULL ) {
cli_errmsg ( " cl_countsigs: Can't open directory %s \n " , path ) ;
return CL_EOPEN ;
}
# ifdef HAVE_READDIR_R_3
while ( ! readdir_r ( dd , & result . d , & dent ) & & dent ) {
# elif defined(HAVE_READDIR_R_2)
while ( ( dent = ( struct dirent * ) readdir_r ( dd , & result . d ) ) ) {
# else
while ( ( dent = readdir ( dd ) ) ) {
# endif
if ( dent - > d_ino ) {
if ( strcmp ( dent - > d_name , " . " ) & & strcmp ( dent - > d_name , " .. " ) & & CLI_DBEXT ( dent - > d_name ) ) {
snprintf ( fname , sizeof ( fname ) , " %s " PATHSEP " %s " , path , dent - > d_name ) ;
fname [ sizeof ( fname ) - 1 ] = 0 ;
ret = countsigs ( fname , countoptions , sigs ) ;
if ( ret ! = CL_SUCCESS ) {
closedir ( dd ) ;
return ret ;
}
}
}
}
closedir ( dd ) ;
} else {
cli_errmsg ( " cl_countsigs: Unsupported file type \n " ) ;
return CL_EARG ;
}
return CL_SUCCESS ;
}