2022-10-22 18:41:00 +08:00
/*
* Copyright ( C ) 2013 - 2022 Cisco Systems , Inc . and / or its affiliates . All rights reserved .
* Copyright ( C ) 2007 - 2013 Sourcefire , Inc .
*
* Authors : Tomasz Kojm
*
* Summary : Code to parse Clamav CVD database format .
*
* Acknowledgements : ClamAV untar code is based on a public domain minitar utility
* by Charles G . Waldman .
*
* 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 <string.h>
# include <stdlib.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif
# include "zlib.h"
# include <time.h>
# include <errno.h>
# include "clamav.h"
# include "others.h"
# include "dsig.h"
# include "str.h"
# include "cvd.h"
# include "readdb.h"
# include "default.h"
# define TAR_BLOCKSIZE 512
static void cli_untgz_cleanup ( char * path , gzFile infile , FILE * outfile , int fdd )
{
UNUSEDPARAM ( fdd ) ;
cli_dbgmsg ( " in cli_untgz_cleanup() \n " ) ;
if ( path ! = NULL )
free ( path ) ;
if ( infile ! = NULL )
gzclose ( infile ) ;
if ( outfile ! = NULL )
fclose ( outfile ) ;
}
static int cli_untgz ( int fd , const char * destdir )
{
char * path , osize [ 13 ] , name [ 101 ] , type ;
char block [ TAR_BLOCKSIZE ] ;
int nbytes , nread , nwritten , in_block = 0 , fdd = - 1 ;
unsigned int size , pathlen = strlen ( destdir ) + 100 + 5 ;
FILE * outfile = NULL ;
STATBUF foo ;
gzFile infile = NULL ;
cli_dbgmsg ( " in cli_untgz() \n " ) ;
if ( ( fdd = dup ( fd ) ) = = - 1 ) {
cli_errmsg ( " cli_untgz: Can't duplicate descriptor %d \n " , fd ) ;
return - 1 ;
}
if ( ( infile = gzdopen ( fdd , " rb " ) ) = = NULL ) {
cli_errmsg ( " cli_untgz: Can't gzdopen() descriptor %d, errno = %d \n " , fdd , errno ) ;
if ( FSTAT ( fdd , & foo ) = = 0 )
close ( fdd ) ;
return - 1 ;
}
path = ( char * ) cli_calloc ( sizeof ( char ) , pathlen ) ;
if ( ! path ) {
cli_errmsg ( " cli_untgz: Can't allocate memory for path \n " ) ;
cli_untgz_cleanup ( NULL , infile , NULL , fdd ) ;
return - 1 ;
}
while ( 1 ) {
nread = gzread ( infile , block , TAR_BLOCKSIZE ) ;
if ( ! in_block & & ! nread )
break ;
if ( nread ! = TAR_BLOCKSIZE ) {
cli_errmsg ( " cli_untgz: Incomplete block read \n " ) ;
cli_untgz_cleanup ( path , infile , outfile , fdd ) ;
return - 1 ;
}
if ( ! in_block ) {
if ( block [ 0 ] = = ' \0 ' ) /* We're done */
break ;
strncpy ( name , block , 100 ) ;
name [ 100 ] = ' \0 ' ;
if ( strchr ( name , ' / ' ) ) {
cli_errmsg ( " cli_untgz: Slash separators are not allowed in CVD \n " ) ;
cli_untgz_cleanup ( path , infile , outfile , fdd ) ;
return - 1 ;
}
snprintf ( path , pathlen , " %s " PATHSEP " %s " , destdir , name ) ;
cli_dbgmsg ( " cli_untgz: Unpacking %s \n " , path ) ;
type = block [ 156 ] ;
switch ( type ) {
case ' 0 ' :
case ' \0 ' :
break ;
case ' 5 ' :
cli_errmsg ( " cli_untgz: Directories are not supported in CVD \n " ) ;
cli_untgz_cleanup ( path , infile , outfile , fdd ) ;
return - 1 ;
default :
cli_errmsg ( " cli_untgz: Unknown type flag '%c' \n " , type ) ;
cli_untgz_cleanup ( path , infile , outfile , fdd ) ;
return - 1 ;
}
if ( outfile ) {
if ( fclose ( outfile ) ) {
cli_errmsg ( " cli_untgz: Cannot close file %s \n " , path ) ;
outfile = NULL ;
cli_untgz_cleanup ( path , infile , outfile , fdd ) ;
return - 1 ;
}
outfile = NULL ;
}
if ( ! ( outfile = fopen ( path , " wb " ) ) ) {
cli_errmsg ( " cli_untgz: Cannot create file %s \n " , path ) ;
cli_untgz_cleanup ( path , infile , outfile , fdd ) ;
return - 1 ;
}
strncpy ( osize , block + 124 , 12 ) ;
osize [ 12 ] = ' \0 ' ;
if ( ( sscanf ( osize , " %o " , & size ) ) = = 0 ) {
cli_errmsg ( " cli_untgz: Invalid size in header \n " ) ;
cli_untgz_cleanup ( path , infile , outfile , fdd ) ;
return - 1 ;
}
if ( size > 0 )
in_block = 1 ;
} else { /* write or continue writing file contents */
nbytes = size > TAR_BLOCKSIZE ? TAR_BLOCKSIZE : size ;
nwritten = fwrite ( block , 1 , nbytes , outfile ) ;
if ( nwritten ! = nbytes ) {
cli_errmsg ( " cli_untgz: Wrote %d instead of %d (%s) \n " , nwritten , nbytes , path ) ;
cli_untgz_cleanup ( path , infile , outfile , fdd ) ;
return - 1 ;
}
size - = nbytes ;
if ( size = = 0 )
in_block = 0 ;
}
}
cli_untgz_cleanup ( path , infile , outfile , fdd ) ;
return 0 ;
}
static void cli_tgzload_cleanup ( int comp , struct cli_dbio * dbio , int fdd )
{
UNUSEDPARAM ( fdd ) ;
cli_dbgmsg ( " in cli_tgzload_cleanup() \n " ) ;
if ( comp ) {
gzclose ( dbio - > gzs ) ;
dbio - > gzs = NULL ;
} else {
fclose ( dbio - > fs ) ;
dbio - > fs = NULL ;
}
if ( dbio - > buf ! = NULL ) {
free ( dbio - > buf ) ;
dbio - > buf = NULL ;
}
if ( dbio - > hashctx ) {
cl_hash_destroy ( dbio - > hashctx ) ;
dbio - > hashctx = NULL ;
}
}
static int cli_tgzload ( int fd , struct cl_engine * engine , unsigned int * signo , unsigned int options , struct cli_dbio * dbio , struct cli_dbinfo * dbinfo )
{
char osize [ 13 ] , name [ 101 ] ;
char block [ TAR_BLOCKSIZE ] ;
int nread , fdd , ret ;
unsigned int type , size , pad , compr = 1 ;
off_t off ;
struct cli_dbinfo * db ;
char hash [ 32 ] ;
cli_dbgmsg ( " in cli_tgzload() \n " ) ;
if ( lseek ( fd , 512 , SEEK_SET ) < 0 ) {
return CL_ESEEK ;
}
if ( cli_readn ( fd , block , 7 ) ! = 7 )
return CL_EFORMAT ; /* truncated file? */
if ( ! strncmp ( block , " COPYING " , 7 ) )
compr = 0 ;
if ( lseek ( fd , 512 , SEEK_SET ) < 0 ) {
return CL_ESEEK ;
}
if ( ( fdd = dup ( fd ) ) = = - 1 ) {
cli_errmsg ( " cli_tgzload: Can't duplicate descriptor %d \n " , fd ) ;
return CL_EDUP ;
}
if ( compr ) {
if ( ( dbio - > gzs = gzdopen ( fdd , " rb " ) ) = = NULL ) {
cli_errmsg ( " cli_tgzload: Can't gzdopen() descriptor %d, errno = %d \n " , fdd , errno ) ;
if ( fdd > - 1 )
close ( fdd ) ;
return CL_EOPEN ;
}
dbio - > fs = NULL ;
} else {
if ( ( dbio - > fs = fdopen ( fdd , " rb " ) ) = = NULL ) {
cli_errmsg ( " cli_tgzload: Can't fdopen() descriptor %d, errno = %d \n " , fdd , errno ) ;
if ( fdd > - 1 )
close ( fdd ) ;
return CL_EOPEN ;
}
dbio - > gzs = NULL ;
}
dbio - > bufsize = CLI_DEFAULT_DBIO_BUFSIZE ;
dbio - > buf = cli_malloc ( dbio - > bufsize ) ;
if ( ! dbio - > buf ) {
cli_errmsg ( " cli_tgzload: Can't allocate memory for dbio->buf \n " ) ;
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
}
dbio - > bufpt = NULL ;
dbio - > usebuf = 1 ;
dbio - > readpt = dbio - > buf ;
while ( 1 ) {
if ( compr )
nread = gzread ( dbio - > gzs , block , TAR_BLOCKSIZE ) ;
else
nread = fread ( block , 1 , TAR_BLOCKSIZE , dbio - > fs ) ;
if ( ! nread )
break ;
if ( nread ! = TAR_BLOCKSIZE ) {
cli_errmsg ( " cli_tgzload: Incomplete block read \n " ) ;
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
}
if ( block [ 0 ] = = ' \0 ' ) /* We're done */
break ;
strncpy ( name , block , 100 ) ;
name [ 100 ] = ' \0 ' ;
if ( strchr ( name , ' / ' ) ) {
cli_errmsg ( " cli_tgzload: Slash separators are not allowed in CVD \n " ) ;
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
}
type = block [ 156 ] ;
switch ( type ) {
case ' 0 ' :
case ' \0 ' :
break ;
case ' 5 ' :
cli_errmsg ( " cli_tgzload: Directories are not supported in CVD \n " ) ;
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
default :
cli_errmsg ( " cli_tgzload: Unknown type flag '%c' \n " , type ) ;
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
}
strncpy ( osize , block + 124 , 12 ) ;
osize [ 12 ] = ' \0 ' ;
if ( ( sscanf ( osize , " %o " , & size ) ) = = 0 ) {
cli_errmsg ( " cli_tgzload: Invalid size in header \n " ) ;
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
}
dbio - > size = size ;
dbio - > readsize = dbio - > size < dbio - > bufsize ? dbio - > size : dbio - > bufsize - 1 ;
dbio - > bufpt = NULL ;
dbio - > readpt = dbio - > buf ;
if ( ! ( dbio - > hashctx ) ) {
dbio - > hashctx = cl_hash_init ( " sha256 " ) ;
if ( ! ( dbio - > hashctx ) ) {
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
}
}
dbio - > bread = 0 ;
/* cli_dbgmsg("cli_tgzload: Loading %s, size: %u\n", name, size); */
if ( compr )
off = ( off_t ) gzseek ( dbio - > gzs , 0 , SEEK_CUR ) ;
else
off = ftell ( dbio - > fs ) ;
if ( ( ! dbinfo & & cli_strbcasestr ( name , " .info " ) ) | | ( dbinfo & & CLI_DBEXT ( name ) ) ) {
ret = cli_load ( name , engine , signo , options , dbio ) ;
if ( ret ) {
cli_errmsg ( " cli_tgzload: Can't load %s \n " , name ) ;
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
}
if ( ! dbinfo ) {
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_SUCCESS ;
} else {
db = dbinfo ;
while ( db & & strcmp ( db - > name , name ) )
db = db - > next ;
if ( ! db ) {
cli_errmsg ( " cli_tgzload: File %s not found in .info \n " , name ) ;
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
}
if ( dbio - > bread ) {
if ( db - > size ! = dbio - > bread ) {
cli_errmsg ( " cli_tgzload: File %s not correctly loaded \n " , name ) ;
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
}
cl_finish_hash ( dbio - > hashctx , hash ) ;
dbio - > hashctx = cl_hash_init ( " sha256 " ) ;
if ( ! ( dbio - > hashctx ) ) {
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
}
if ( memcmp ( db - > hash , hash , 32 ) ) {
cli_errmsg ( " cli_tgzload: Invalid checksum for file %s \n " , name ) ;
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
}
}
}
}
pad = size % TAR_BLOCKSIZE ? ( TAR_BLOCKSIZE - ( size % TAR_BLOCKSIZE ) ) : 0 ;
if ( compr ) {
if ( off = = gzseek ( dbio - > gzs , 0 , SEEK_CUR ) )
gzseek ( dbio - > gzs , size + pad , SEEK_CUR ) ;
else if ( pad )
gzseek ( dbio - > gzs , pad , SEEK_CUR ) ;
} else {
if ( off = = ftell ( dbio - > fs ) )
fseek ( dbio - > fs , size + pad , SEEK_CUR ) ;
else if ( pad )
fseek ( dbio - > fs , pad , SEEK_CUR ) ;
}
}
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_SUCCESS ;
}
struct cl_cvd * cl_cvdparse ( const char * head )
{
struct cl_cvd * cvd ;
char * pt ;
if ( strncmp ( head , " ClamAV-VDB: " , 11 ) ) {
cli_errmsg ( " cli_cvdparse: Not a CVD file \n " ) ;
return NULL ;
}
if ( ! ( cvd = ( struct cl_cvd * ) cli_malloc ( sizeof ( struct cl_cvd ) ) ) ) {
cli_errmsg ( " cl_cvdparse: Can't allocate memory for cvd \n " ) ;
return NULL ;
}
if ( ! ( cvd - > time = cli_strtok ( head , 1 , " : " ) ) ) {
cli_errmsg ( " cli_cvdparse: Can't parse the creation time \n " ) ;
free ( cvd ) ;
return NULL ;
}
if ( ! ( pt = cli_strtok ( head , 2 , " : " ) ) ) {
cli_errmsg ( " cli_cvdparse: Can't parse the version number \n " ) ;
free ( cvd - > time ) ;
free ( cvd ) ;
return NULL ;
}
cvd - > version = atoi ( pt ) ;
free ( pt ) ;
if ( ! ( pt = cli_strtok ( head , 3 , " : " ) ) ) {
cli_errmsg ( " cli_cvdparse: Can't parse the number of signatures \n " ) ;
free ( cvd - > time ) ;
free ( cvd ) ;
return NULL ;
}
cvd - > sigs = atoi ( pt ) ;
free ( pt ) ;
if ( ! ( pt = cli_strtok ( head , 4 , " : " ) ) ) {
cli_errmsg ( " cli_cvdparse: Can't parse the functionality level \n " ) ;
free ( cvd - > time ) ;
free ( cvd ) ;
return NULL ;
}
cvd - > fl = atoi ( pt ) ;
free ( pt ) ;
if ( ! ( cvd - > md5 = cli_strtok ( head , 5 , " : " ) ) ) {
cli_errmsg ( " cli_cvdparse: Can't parse the MD5 checksum \n " ) ;
free ( cvd - > time ) ;
free ( cvd ) ;
return NULL ;
}
if ( ! ( cvd - > dsig = cli_strtok ( head , 6 , " : " ) ) ) {
cli_errmsg ( " cli_cvdparse: Can't parse the digital signature \n " ) ;
free ( cvd - > time ) ;
free ( cvd - > md5 ) ;
free ( cvd ) ;
return NULL ;
}
if ( ! ( cvd - > builder = cli_strtok ( head , 7 , " : " ) ) ) {
cli_errmsg ( " cli_cvdparse: Can't parse the builder name \n " ) ;
free ( cvd - > time ) ;
free ( cvd - > md5 ) ;
free ( cvd - > dsig ) ;
free ( cvd ) ;
return NULL ;
}
if ( ( pt = cli_strtok ( head , 8 , " : " ) ) ) {
cvd - > stime = atoi ( pt ) ;
free ( pt ) ;
} else {
cli_dbgmsg ( " cli_cvdparse: No creation time in seconds (old file format) \n " ) ;
cvd - > stime = 0 ;
}
return cvd ;
}
struct cl_cvd * cl_cvdhead ( const char * file )
{
FILE * fs ;
char head [ 513 ] , * pt ;
int i ;
unsigned int bread ;
if ( ( fs = fopen ( file , " rb " ) ) = = NULL ) {
cli_errmsg ( " cl_cvdhead: Can't open file %s \n " , file ) ;
return NULL ;
}
if ( ! ( bread = fread ( head , 1 , 512 , fs ) ) ) {
cli_errmsg ( " cl_cvdhead: Can't read CVD header in %s \n " , file ) ;
fclose ( fs ) ;
return NULL ;
}
fclose ( fs ) ;
head [ bread ] = 0 ;
if ( ( pt = strpbrk ( head , " \n \r " ) ) )
* pt = 0 ;
for ( i = bread - 1 ; i > 0 & & ( head [ i ] = = ' ' | | head [ i ] = = ' \n ' | | head [ i ] = = ' \r ' ) ; head [ i ] = 0 , i - - )
;
return cl_cvdparse ( head ) ;
}
void cl_cvdfree ( struct cl_cvd * cvd )
{
free ( cvd - > time ) ;
free ( cvd - > md5 ) ;
free ( cvd - > dsig ) ;
free ( cvd - > builder ) ;
free ( cvd ) ;
}
2023-01-14 18:28:39 +08:00
/**
* @ brief Verify the signature of a CVD file .
*
* @ param fs CVD File stream to read from .
* @ param [ out ] cvdpt ( optional ) Pointer to a CVD header struct to fill in .
* @ param skipsig If non - zero , skip the signature verification .
* @ return cl_error_t CL_SUCCESS on success . CL_ECVD , CL_EMEM , or CL_EVERIFY on error .
*/
static cl_error_t cli_cvdverify ( FILE * fs , struct cl_cvd * cvdpt , unsigned int skipsig )
2022-10-22 18:41:00 +08:00
{
struct cl_cvd * cvd ;
char * md5 , head [ 513 ] ;
int i ;
fseek ( fs , 0 , SEEK_SET ) ;
if ( fread ( head , 1 , 512 , fs ) ! = 512 ) {
cli_errmsg ( " cli_cvdverify: Can't read CVD header \n " ) ;
return CL_ECVD ;
}
head [ 512 ] = 0 ;
for ( i = 511 ; i > 0 & & ( head [ i ] = = ' ' | | head [ i ] = = 10 ) ; head [ i ] = 0 , i - - )
;
if ( ( cvd = cl_cvdparse ( head ) ) = = NULL )
return CL_ECVD ;
if ( cvdpt )
memcpy ( cvdpt , cvd , sizeof ( struct cl_cvd ) ) ;
if ( skipsig ) {
cl_cvdfree ( cvd ) ;
return CL_SUCCESS ;
}
md5 = cli_hashstream ( fs , NULL , 1 ) ;
if ( md5 = = NULL ) {
cli_dbgmsg ( " cli_cvdverify: Cannot generate hash, out of memory \n " ) ;
cl_cvdfree ( cvd ) ;
return CL_EMEM ;
}
cli_dbgmsg ( " MD5(.tar.gz) = %s \n " , md5 ) ;
if ( strncmp ( md5 , cvd - > md5 , 32 ) ) {
cli_dbgmsg ( " cli_cvdverify: MD5 verification error \n " ) ;
free ( md5 ) ;
cl_cvdfree ( cvd ) ;
return CL_EVERIFY ;
}
if ( cli_versig ( md5 , cvd - > dsig ) ) {
cli_dbgmsg ( " cli_cvdverify: Digital signature verification error \n " ) ;
free ( md5 ) ;
cl_cvdfree ( cvd ) ;
return CL_EVERIFY ;
}
free ( md5 ) ;
cl_cvdfree ( cvd ) ;
return CL_SUCCESS ;
}
cl_error_t cl_cvdverify ( const char * file )
{
struct cl_engine * engine ;
FILE * fs ;
cl_error_t ret ;
int dbtype = 0 ;
if ( ( fs = fopen ( file , " rb " ) ) = = NULL ) {
cli_errmsg ( " cl_cvdverify: Can't open file %s \n " , file ) ;
return CL_EOPEN ;
}
if ( ! ( engine = cl_engine_new ( ) ) ) {
2023-01-14 18:28:39 +08:00
cli_errmsg ( " cl_cvdverify: Can't create new engine \n " ) ;
2022-10-22 18:41:00 +08:00
fclose ( fs ) ;
return CL_EMEM ;
}
engine - > cb_stats_submit = NULL ; /* Don't submit stats if we're just verifying a CVD */
if ( ! ! cli_strbcasestr ( file , " .cld " ) )
dbtype = 1 ;
else if ( ! ! cli_strbcasestr ( file , " .cud " ) )
dbtype = 2 ;
ret = cli_cvdload ( fs , engine , NULL , CL_DB_STDOPT | CL_DB_PUA , dbtype , file , 1 ) ;
cl_engine_free ( engine ) ;
fclose ( fs ) ;
return ret ;
}
2023-01-14 18:28:39 +08:00
cl_error_t cli_cvdload ( FILE * fs , struct cl_engine * engine , unsigned int * signo , unsigned int options , unsigned int dbtype , const char * filename , unsigned int chkonly )
2022-10-22 18:41:00 +08:00
{
struct cl_cvd cvd , dupcvd ;
FILE * dupfs ;
2023-01-14 18:28:39 +08:00
cl_error_t ret ;
2022-10-22 18:41:00 +08:00
time_t s_time ;
int cfd ;
struct cli_dbio dbio ;
struct cli_dbinfo * dbinfo = NULL ;
char * dupname ;
dbio . hashctx = NULL ;
cli_dbgmsg ( " in cli_cvdload() \n " ) ;
/* verify */
if ( ( ret = cli_cvdverify ( fs , & cvd , dbtype ) ) )
return ret ;
if ( dbtype < = 1 ) {
/* check for duplicate db */
dupname = cli_strdup ( filename ) ;
if ( ! dupname )
return CL_EMEM ;
dupname [ strlen ( dupname ) - 2 ] = ( dbtype = = 1 ? ' v ' : ' l ' ) ;
if ( ! access ( dupname , R_OK ) & & ( dupfs = fopen ( dupname , " rb " ) ) ) {
if ( ( ret = cli_cvdverify ( dupfs , & dupcvd , ! dbtype ) ) ) {
fclose ( dupfs ) ;
free ( dupname ) ;
return ret ;
}
fclose ( dupfs ) ;
if ( dupcvd . version > cvd . version ) {
cli_warnmsg ( " Detected duplicate databases %s and %s. The %s database is older and will not be loaded, you should manually remove it from the database directory. \n " , filename , dupname , filename ) ;
free ( dupname ) ;
return CL_SUCCESS ;
} else if ( dupcvd . version = = cvd . version & & ! dbtype ) {
cli_warnmsg ( " Detected duplicate databases %s and %s, please manually remove one of them \n " , filename , dupname ) ;
free ( dupname ) ;
return CL_SUCCESS ;
}
}
free ( dupname ) ;
}
if ( strstr ( filename , " daily. " ) ) {
time ( & s_time ) ;
if ( cvd . stime > s_time ) {
if ( cvd . stime - ( unsigned int ) s_time > 3600 ) {
cli_warnmsg ( " ****************************************************** \n " ) ;
cli_warnmsg ( " *** Virus database timestamp in the future! *** \n " ) ;
cli_warnmsg ( " *** Please check the timezone and clock settings *** \n " ) ;
cli_warnmsg ( " ****************************************************** \n " ) ;
}
} else if ( ( unsigned int ) s_time - cvd . stime > 604800 ) {
cli_warnmsg ( " ************************************************** \n " ) ;
cli_warnmsg ( " *** The virus database is older than 7 days! *** \n " ) ;
cli_warnmsg ( " *** Please update it as soon as possible. *** \n " ) ;
cli_warnmsg ( " ************************************************** \n " ) ;
}
engine - > dbversion [ 0 ] = cvd . version ;
engine - > dbversion [ 1 ] = cvd . stime ;
}
if ( cvd . fl > cl_retflevel ( ) ) {
cli_warnmsg ( " ******************************************************************* \n " ) ;
cli_warnmsg ( " *** This version of the ClamAV engine is outdated. *** \n " ) ;
cli_warnmsg ( " *** Read https://docs.clamav.net/manual/Installing.html *** \n " ) ;
cli_warnmsg ( " ******************************************************************* \n " ) ;
}
cfd = fileno ( fs ) ;
dbio . chkonly = 0 ;
if ( dbtype = = 2 )
ret = cli_tgzload ( cfd , engine , signo , options | CL_DB_UNSIGNED , & dbio , NULL ) ;
else
ret = cli_tgzload ( cfd , engine , signo , options | CL_DB_OFFICIAL , & dbio , NULL ) ;
if ( ret ! = CL_SUCCESS )
return ret ;
dbinfo = engine - > dbinfo ;
if ( ! dbinfo | | ! dbinfo - > cvd | | ( dbinfo - > cvd - > version ! = cvd . version ) | | ( dbinfo - > cvd - > sigs ! = cvd . sigs ) | | ( dbinfo - > cvd - > fl ! = cvd . fl ) | | ( dbinfo - > cvd - > stime ! = cvd . stime ) ) {
cli_errmsg ( " cli_cvdload: Corrupted CVD header \n " ) ;
return CL_EMALFDB ;
}
dbinfo = engine - > dbinfo ? engine - > dbinfo - > next : NULL ;
if ( ! dbinfo ) {
cli_errmsg ( " cli_cvdload: dbinfo error \n " ) ;
return CL_EMALFDB ;
}
dbio . chkonly = chkonly ;
if ( dbtype = = 2 )
options | = CL_DB_UNSIGNED ;
else
options | = CL_DB_SIGNED | CL_DB_OFFICIAL ;
ret = cli_tgzload ( cfd , engine , signo , options , & dbio , dbinfo ) ;
while ( engine - > dbinfo ) {
dbinfo = engine - > dbinfo ;
engine - > dbinfo = dbinfo - > next ;
MPOOL_FREE ( engine - > mempool , dbinfo - > name ) ;
MPOOL_FREE ( engine - > mempool , dbinfo - > hash ) ;
if ( dbinfo - > cvd )
cl_cvdfree ( dbinfo - > cvd ) ;
MPOOL_FREE ( engine - > mempool , dbinfo ) ;
}
return ret ;
}
2023-01-14 18:28:39 +08:00
static cl_error_t cli_cvdunpack ( const char * file , const char * dir )
2022-10-22 18:41:00 +08:00
{
int fd , ret ;
fd = open ( file , O_RDONLY | O_BINARY ) ;
if ( fd = = - 1 )
return - 1 ;
if ( lseek ( fd , 512 , SEEK_SET ) < 0 ) {
close ( fd ) ;
return - 1 ;
}
ret = cli_untgz ( fd , dir ) ;
close ( fd ) ;
return ret ;
}
2023-01-14 18:28:39 +08:00
cl_error_t cl_cvdunpack ( const char * file , const char * dir , bool dont_verify )
{
cl_error_t status = CL_SUCCESS ;
FILE * fs = NULL ;
fs = fopen ( file , " rb " ) ;
if ( NULL = = fs ) {
char err [ 128 ] ;
cli_errmsg ( " Can't open CVD: %s -- %s \n " , file , cli_strerror ( errno , err , sizeof ( err ) ) ) ;
return CL_EOPEN ;
}
if ( ! dont_verify ) {
status = cli_cvdverify ( fs , NULL , 0 ) ;
if ( CL_SUCCESS ! = status ) {
cli_errmsg ( " CVD verification failed for: %s \n " , file ) ;
goto done ;
}
}
status = cli_cvdunpack ( file , dir ) ;
if ( CL_SUCCESS ! = status ) {
cli_errmsg ( " CVD unpacking failed for: %s \n " , file ) ;
goto done ;
}
done :
if ( NULL ! = fs ) {
fclose ( fs ) ;
}
return status ;
}