2003-09-29 11:44:52 +00:00
/*
2022-01-06 16:53:44 -08:00
* Copyright ( C ) 2013 - 2022 Cisco Systems , Inc . and / or its affiliates . All rights reserved .
2019-01-25 10:15:50 -05:00
* Copyright ( C ) 2007 - 2013 Sourcefire , Inc .
2003-09-29 11:44:52 +00:00
*
2008-04-02 15:24:51 +00:00
* Authors : Tomasz Kojm
2019-05-03 18:16:03 -04:00
*
2018-03-05 16:34:35 -05:00
* Summary : Code to parse Clamav CVD database format .
2019-05-03 18:16:03 -04:00
*
2018-03-05 16:34:35 -05:00
* Acknowledgements : ClamAV untar code is based on a public domain minitar utility
* by Charles G . Waldman .
2003-09-29 11:44:52 +00:00
*
* This program is free software ; you can redistribute it and / or modify
2007-03-31 20:31:04 +00:00
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
2003-09-29 11:44:52 +00:00
*
* 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
2006-04-09 19:59:28 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston ,
* MA 02110 - 1301 , USA .
2003-09-29 11:44:52 +00:00
*/
2004-02-06 13:46:08 +00:00
# if HAVE_CONFIG_H
# include "clamav-config.h"
# endif
2003-09-29 11:44:52 +00:00
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
2018-12-03 12:40:13 -05:00
# ifdef HAVE_UNISTD_H
2006-06-16 09:21:02 +00:00
# include <unistd.h>
2006-10-09 15:23:50 +00:00
# endif
# include "zlib.h"
2004-09-01 01:36:02 +00:00
# include <time.h>
2006-10-09 15:23:50 +00:00
# include <errno.h>
2003-09-29 11:44:52 +00:00
# include "clamav.h"
2003-10-08 10:40:53 +00:00
# include "others.h"
# include "dsig.h"
2003-10-26 06:01:03 +00:00
# include "str.h"
2005-12-10 18:50:26 +00:00
# include "cvd.h"
2007-12-18 19:23:56 +00:00
# include "readdb.h"
2009-07-28 20:23:31 +02:00
# include "default.h"
2003-09-29 11:44:52 +00:00
# define TAR_BLOCKSIZE 512
2012-06-22 16:55:29 -04:00
static void cli_untgz_cleanup ( char * path , gzFile infile , FILE * outfile , int fdd )
{
2014-07-10 18:11:49 -04:00
UNUSEDPARAM ( fdd ) ;
2012-06-22 16:55:29 -04:00
cli_dbgmsg ( " in cli_untgz_cleanup() \n " ) ;
if ( path ! = NULL )
2018-12-03 12:40:13 -05:00
free ( path ) ;
if ( infile ! = NULL )
gzclose ( infile ) ;
2012-06-22 16:55:29 -04:00
if ( outfile ! = NULL )
fclose ( outfile ) ;
}
2009-02-03 18:47:18 +00:00
static int cli_untgz ( int fd , const char * destdir )
2003-09-29 11:44:52 +00:00
{
2018-12-03 12:40:13 -05:00
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 ;
2007-08-31 19:55:09 +00:00
2003-09-29 11:44:52 +00:00
cli_dbgmsg ( " in cli_untgz() \n " ) ;
2018-12-03 12:40:13 -05:00
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 ;
}
2003-09-29 11:44:52 +00:00
}
2012-06-22 16:55:29 -04:00
cli_untgz_cleanup ( path , infile , outfile , fdd ) ;
2003-09-29 11:44:52 +00:00
return 0 ;
}
2012-06-22 16:55:29 -04:00
static void cli_tgzload_cleanup ( int comp , struct cli_dbio * dbio , int fdd )
{
2014-07-10 18:11:49 -04:00
UNUSEDPARAM ( fdd ) ;
2012-06-22 16:55:29 -04:00
cli_dbgmsg ( " in cli_tgzload_cleanup() \n " ) ;
2018-12-03 12:40:13 -05:00
if ( comp ) {
2012-06-22 16:55:29 -04:00
gzclose ( dbio - > gzs ) ;
dbio - > gzs = NULL ;
2018-12-03 12:40:13 -05:00
} else {
2012-06-22 16:55:29 -04:00
fclose ( dbio - > fs ) ;
dbio - > fs = NULL ;
}
2018-12-03 12:40:13 -05:00
if ( dbio - > buf ! = NULL ) {
2012-06-22 16:55:29 -04:00
free ( dbio - > buf ) ;
dbio - > buf = NULL ;
}
2014-02-12 17:42:48 -05:00
if ( dbio - > hashctx ) {
2014-02-28 12:12:30 -05:00
cl_hash_destroy ( dbio - > hashctx ) ;
2014-02-12 17:42:48 -05:00
dbio - > hashctx = NULL ;
}
2012-06-22 16:55:29 -04:00
}
2010-01-20 22:10:56 +01:00
static int cli_tgzload ( int fd , struct cl_engine * engine , unsigned int * signo , unsigned int options , struct cli_dbio * dbio , struct cli_dbinfo * dbinfo )
2007-12-18 19:23:56 +00:00
{
2018-12-03 12:40:13 -05:00
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 ] ;
2007-12-18 19:23:56 +00:00
2007-12-19 22:06:32 +00:00
cli_dbgmsg ( " in cli_tgzload() \n " ) ;
2007-12-18 19:23:56 +00:00
2018-12-03 12:40:13 -05:00
if ( lseek ( fd , 512 , SEEK_SET ) < 0 ) {
2013-02-12 17:33:21 -05:00
return CL_ESEEK ;
}
2018-12-03 12:40:13 -05:00
if ( cli_readn ( fd , block , 7 ) ! = 7 )
return CL_EFORMAT ; /* truncated file? */
2008-04-21 14:58:36 +00:00
2018-12-03 12:40:13 -05:00
if ( ! strncmp ( block , " COPYING " , 7 ) )
compr = 0 ;
2008-04-21 14:58:36 +00:00
2018-12-03 12:40:13 -05:00
if ( lseek ( fd , 512 , SEEK_SET ) < 0 ) {
2013-02-12 17:33:21 -05:00
return CL_ESEEK ;
}
2008-05-18 21:32:27 +00:00
2018-12-03 12:40:13 -05:00
if ( ( fdd = dup ( fd ) ) = = - 1 ) {
cli_errmsg ( " cli_tgzload: Can't duplicate descriptor %d \n " , fd ) ;
return CL_EDUP ;
2007-12-18 19:23:56 +00:00
}
2018-12-03 12:40:13 -05:00
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 ;
2008-05-18 21:32:27 +00:00
} else {
2018-12-03 12:40:13 -05:00
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 ;
2007-12-18 19:23:56 +00:00
}
2010-01-20 22:10:56 +01:00
dbio - > bufsize = CLI_DEFAULT_DBIO_BUFSIZE ;
2018-12-03 12:40:13 -05:00
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 ;
2009-07-28 20:23:31 +02:00
}
2018-12-03 12:40:13 -05:00
dbio - > bufpt = NULL ;
2010-01-20 22:10:56 +01:00
dbio - > usebuf = 1 ;
dbio - > readpt = dbio - > buf ;
2009-07-28 20:23:31 +02:00
2018-12-03 12:40:13 -05:00
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 " ) ;
2014-02-12 17:42:48 -05:00
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
}
2018-12-03 12:40:13 -05:00
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 ) ) {
2014-02-28 12:12:30 -05:00
dbio - > hashctx = cl_hash_init ( " sha256 " ) ;
if ( ! ( dbio - > hashctx ) ) {
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
return CL_EMALFDB ;
}
2018-12-03 12:40:13 -05:00
}
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 ) ;
PE parsing code improvements, db loading bug fixes
Consolidate the PE parsing code into one function. I tried to preserve all existing functionality from the previous, distinct implementations to a large extent (with the exceptions mentioned below). If I noticed potential bugs/improvements, I added a TODO statement about those so that they can be fixed in a smaller commit later. Also, there are more TODOs in places where I'm not entirely sure why certain actions are performed - more research is needed for these.
I'm submitting a pull request now so that regression testing can be done, and because merging what I have thus far now will likely have fewer conflicts than if I try to merge later
PE parsing code improvements:
- PEs without all 16 data directories are parsed more appropriately now
- Added lots more debug statements
Also:
- Allow MAX_BC and MAX_TRACKED_PCRE to be specified via CFLAGS
When doing performance testing with the latest CVD, MAX_BC and
MAX_TRACKED_PCRE need to be raised to track all the events.
Allow these to be specified via CFLAGS by not redefining them
if they are already defined
- Fix an issue preventing wildcard sizes in .MDB/.MSB rules
I'm not sure what the original intent of the check I removed was,
but it prevents using wildcard sizes in .MDB/.MSB rules. AFAICT
these wildcard sizes should be handled appropriately by the MD5
section hash computation code, so I don't think a check on that
is needed.
- Fix several issues related to db loading
- .imp files will now get loaded if they exist in a directory passed
via clamscan's '-d' flag
- .pwdb files will now get loaded if they exist in a directory passed
via clamscan's '-d' flag even when compiling without yara support
- Changes to .imp, .ign, and .ign2 files will now be reflected in calls
to cl_statinidir and cl_statchkdir (and also .pwdb files, even when
compiling without yara support)
- The contents of .sfp files won't be included in some of the signature
counts, and the contents of .cud files will be
- Any local.gdb files will no longer be loaded twice
- For .imp files, you are no longer required to specify a minimum flevel for wildcard rules, since this isn't needed
2019-01-08 00:09:08 -05:00
if ( ( ! dbinfo & & cli_strbcasestr ( name , " .info " ) ) | | ( dbinfo & & CLI_DBEXT ( name ) ) ) {
2018-12-03 12:40:13 -05:00
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 ) ;
}
2007-12-18 19:23:56 +00:00
}
2012-06-22 16:55:29 -04:00
cli_tgzload_cleanup ( compr , dbio , fdd ) ;
2008-05-18 21:32:27 +00:00
return CL_SUCCESS ;
2007-12-18 19:23:56 +00:00
}
2003-10-26 06:01:03 +00:00
struct cl_cvd * cl_cvdparse ( const char * head )
2003-09-29 11:44:52 +00:00
{
2018-12-03 12:40:13 -05:00
struct cl_cvd * cvd ;
char * pt ;
2003-10-08 10:40:53 +00:00
2018-12-03 12:40:13 -05:00
if ( strncmp ( head , " ClamAV-VDB: " , 11 ) ) {
cli_errmsg ( " cli_cvdparse: Not a CVD file \n " ) ;
return NULL ;
2003-10-08 10:40:53 +00:00
}
2003-09-29 11:44:52 +00:00
2018-12-03 12:40:13 -05:00
if ( ! ( cvd = ( struct cl_cvd * ) cli_malloc ( sizeof ( struct cl_cvd ) ) ) ) {
cli_errmsg ( " cl_cvdparse: Can't allocate memory for cvd \n " ) ;
return NULL ;
2006-06-17 21:00:44 +00:00
}
2003-09-29 11:44:52 +00:00
2018-12-03 12:40:13 -05:00
if ( ! ( cvd - > time = cli_strtok ( head , 1 , " : " ) ) ) {
cli_errmsg ( " cli_cvdparse: Can't parse the creation time \n " ) ;
free ( cvd ) ;
return NULL ;
2003-11-24 16:19:39 +00:00
}
2018-12-03 12:40:13 -05:00
if ( ! ( pt = cli_strtok ( head , 2 , " : " ) ) ) {
cli_errmsg ( " cli_cvdparse: Can't parse the version number \n " ) ;
free ( cvd - > time ) ;
free ( cvd ) ;
return NULL ;
2003-11-24 16:19:39 +00:00
}
2003-09-29 11:44:52 +00:00
cvd - > version = atoi ( pt ) ;
free ( pt ) ;
2018-12-03 12:40:13 -05:00
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 ;
2003-11-24 16:19:39 +00:00
}
2003-09-29 11:44:52 +00:00
cvd - > sigs = atoi ( pt ) ;
free ( pt ) ;
2018-12-03 12:40:13 -05:00
if ( ! ( pt = cli_strtok ( head , 4 , " : " ) ) ) {
cli_errmsg ( " cli_cvdparse: Can't parse the functionality level \n " ) ;
free ( cvd - > time ) ;
free ( cvd ) ;
return NULL ;
2003-11-24 16:19:39 +00:00
}
2006-11-01 16:04:54 +00:00
cvd - > fl = atoi ( pt ) ;
2003-09-29 11:44:52 +00:00
free ( pt ) ;
2018-12-03 12:40:13 -05:00
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 ;
2003-11-24 16:19:39 +00:00
}
2018-12-03 12:40:13 -05:00
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 ;
2003-11-24 16:19:39 +00:00
}
2018-12-03 12:40:13 -05:00
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 ;
2003-11-24 16:19:39 +00:00
}
2003-09-29 11:44:52 +00:00
2018-12-03 12:40:13 -05:00
if ( ( pt = cli_strtok ( head , 8 , " : " ) ) ) {
cvd - > stime = atoi ( pt ) ;
free ( pt ) ;
2007-08-31 19:55:09 +00:00
} else {
2018-12-03 12:40:13 -05:00
cli_dbgmsg ( " cli_cvdparse: No creation time in seconds (old file format) \n " ) ;
cvd - > stime = 0 ;
2007-08-31 19:55:09 +00:00
}
2004-09-01 01:36:02 +00:00
2003-09-29 11:44:52 +00:00
return cvd ;
}
struct cl_cvd * cl_cvdhead ( const char * file )
{
2018-12-03 12:40:13 -05:00
FILE * fs ;
char head [ 513 ] , * pt ;
int i ;
unsigned int bread ;
2003-09-29 11:44:52 +00:00
2018-12-03 12:40:13 -05:00
if ( ( fs = fopen ( file , " rb " ) ) = = NULL ) {
cli_errmsg ( " cl_cvdhead: Can't open file %s \n " , file ) ;
return NULL ;
2003-09-29 11:44:52 +00:00
}
2018-12-03 12:40:13 -05:00
if ( ! ( bread = fread ( head , 1 , 512 , fs ) ) ) {
cli_errmsg ( " cl_cvdhead: Can't read CVD header in %s \n " , file ) ;
fclose ( fs ) ;
return NULL ;
2003-10-26 06:01:03 +00:00
}
2006-06-08 18:56:22 +00:00
fclose ( fs ) ;
2003-10-26 06:01:03 +00:00
2006-07-25 16:34:40 +00:00
head [ bread ] = 0 ;
2018-12-03 12:40:13 -05:00
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 - - )
;
2003-10-26 06:01:03 +00:00
return cl_cvdparse ( head ) ;
2003-09-29 11:44:52 +00:00
}
void cl_cvdfree ( struct cl_cvd * cvd )
{
free ( cvd - > time ) ;
free ( cvd - > md5 ) ;
free ( cvd - > dsig ) ;
free ( cvd - > builder ) ;
free ( cvd ) ;
}
2011-05-10 21:29:49 +02:00
static int cli_cvdverify ( FILE * fs , struct cl_cvd * cvdpt , unsigned int skipsig )
2003-10-08 10:40:53 +00:00
{
2018-12-03 12:40:13 -05:00
struct cl_cvd * cvd ;
char * md5 , head [ 513 ] ;
int i ;
2007-08-31 19:55:09 +00:00
2006-06-08 18:56:22 +00:00
fseek ( fs , 0 , SEEK_SET ) ;
2018-12-03 12:40:13 -05:00
if ( fread ( head , 1 , 512 , fs ) ! = 512 ) {
cli_errmsg ( " cli_cvdverify: Can't read CVD header \n " ) ;
return CL_ECVD ;
2003-10-26 06:01:03 +00:00
}
head [ 512 ] = 0 ;
2018-12-03 12:40:13 -05:00
for ( i = 511 ; i > 0 & & ( head [ i ] = = ' ' | | head [ i ] = = 10 ) ; head [ i ] = 0 , i - - )
;
2003-10-08 10:40:53 +00:00
2018-12-03 12:40:13 -05:00
if ( ( cvd = cl_cvdparse ( head ) ) = = NULL )
return CL_ECVD ;
2003-10-08 10:40:53 +00:00
2018-12-03 12:40:13 -05:00
if ( cvdpt )
memcpy ( cvdpt , cvd , sizeof ( struct cl_cvd ) ) ;
2003-10-08 10:40:53 +00:00
2018-12-03 12:40:13 -05:00
if ( skipsig ) {
cl_cvdfree ( cvd ) ;
return CL_SUCCESS ;
2007-12-19 22:06:32 +00:00
}
2011-01-18 15:00:37 +01:00
md5 = cli_hashstream ( fs , NULL , 1 ) ;
2013-04-10 15:28:20 -04:00
if ( md5 = = NULL ) {
2018-12-03 12:40:13 -05:00
cli_dbgmsg ( " cli_cvdverify: Cannot generate hash, out of memory \n " ) ;
cl_cvdfree ( cvd ) ;
return CL_EMEM ;
2013-04-10 15:28:20 -04:00
}
2003-10-08 10:40:53 +00:00
cli_dbgmsg ( " MD5(.tar.gz) = %s \n " , md5 ) ;
2018-12-03 12:40:13 -05:00
if ( strncmp ( md5 , cvd - > md5 , 32 ) ) {
cli_dbgmsg ( " cli_cvdverify: MD5 verification error \n " ) ;
free ( md5 ) ;
cl_cvdfree ( cvd ) ;
return CL_EVERIFY ;
2003-10-08 10:40:53 +00:00
}
2018-12-03 12:40:13 -05:00
if ( cli_versig ( md5 , cvd - > dsig ) ) {
cli_dbgmsg ( " cli_cvdverify: Digital signature verification error \n " ) ;
free ( md5 ) ;
cl_cvdfree ( cvd ) ;
return CL_EVERIFY ;
2003-10-08 10:40:53 +00:00
}
2003-10-26 06:01:03 +00:00
free ( md5 ) ;
2003-12-01 19:28:40 +00:00
cl_cvdfree ( cvd ) ;
2007-12-19 22:06:32 +00:00
return CL_SUCCESS ;
2003-10-08 10:40:53 +00:00
}
2020-04-18 10:46:57 -04:00
cl_error_t cl_cvdverify ( const char * file )
2003-10-08 10:40:53 +00:00
{
2018-12-03 12:40:13 -05:00
struct cl_engine * engine ;
FILE * fs ;
2020-04-18 10:46:57 -04:00
cl_error_t ret ;
int dbtype = 0 ;
2007-08-31 19:55:09 +00:00
2018-12-03 12:40:13 -05:00
if ( ( fs = fopen ( file , " rb " ) ) = = NULL ) {
cli_errmsg ( " cl_cvdverify: Can't open file %s \n " , file ) ;
return CL_EOPEN ;
2003-10-08 10:40:53 +00:00
}
2018-12-03 12:40:13 -05:00
if ( ! ( engine = cl_engine_new ( ) ) ) {
cli_errmsg ( " cld_cvdverify: Can't create new engine \n " ) ;
fclose ( fs ) ;
return CL_EMEM ;
2011-01-17 19:06:57 +01:00
}
2014-01-07 15:14:17 -05:00
engine - > cb_stats_submit = NULL ; /* Don't submit stats if we're just verifying a CVD */
2011-01-17 19:06:57 +01:00
2015-10-29 17:44:43 -04:00
if ( ! ! cli_strbcasestr ( file , " .cld " ) )
2018-12-03 12:40:13 -05:00
dbtype = 1 ;
2015-10-29 17:44:43 -04:00
else if ( ! ! cli_strbcasestr ( file , " .cud " ) )
2018-12-03 12:40:13 -05:00
dbtype = 2 ;
2015-10-29 17:44:43 -04:00
ret = cli_cvdload ( fs , engine , NULL , CL_DB_STDOPT | CL_DB_PUA , dbtype , file , 1 ) ;
2003-10-26 06:01:03 +00:00
2011-01-17 19:06:57 +01:00
cl_engine_free ( engine ) ;
fclose ( fs ) ;
2003-10-26 06:01:03 +00:00
return ret ;
2003-10-08 10:40:53 +00:00
}
2011-05-10 21:29:49 +02:00
int cli_cvdload ( FILE * fs , struct cl_engine * engine , unsigned int * signo , unsigned int options , unsigned int dbtype , const char * filename , unsigned int chkonly )
2003-09-29 11:44:52 +00:00
{
2018-12-03 12:40:13 -05:00
struct cl_cvd cvd , dupcvd ;
FILE * dupfs ;
int ret ;
time_t s_time ;
int cfd ;
struct cli_dbio dbio ;
struct cli_dbinfo * dbinfo = NULL ;
char * dupname ;
2003-09-29 11:44:52 +00:00
2014-02-12 17:42:48 -05:00
dbio . hashctx = NULL ;
2003-09-29 11:44:52 +00:00
cli_dbgmsg ( " in cli_cvdload() \n " ) ;
2003-10-08 10:40:53 +00:00
/* verify */
2018-12-03 12:40:13 -05:00
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 " ) ;
2021-07-17 13:33:13 -07:00
cli_warnmsg ( " *** Read https://docs.clamav.net/manual/Installing.html *** \n " ) ;
2018-12-03 12:40:13 -05:00
cli_warnmsg ( " ******************************************************************* \n " ) ;
}
cfd = fileno ( fs ) ;
2011-01-17 19:06:57 +01:00
dbio . chkonly = 0 ;
2018-12-03 12:40:13 -05:00
if ( dbtype = = 2 )
ret = cli_tgzload ( cfd , engine , signo , options | CL_DB_UNSIGNED , & dbio , NULL ) ;
2011-05-10 21:29:49 +02:00
else
2018-12-03 12:40:13 -05:00
ret = cli_tgzload ( cfd , engine , signo , options | CL_DB_OFFICIAL , & dbio , NULL ) ;
if ( ret ! = CL_SUCCESS )
return ret ;
2010-01-20 22:10:56 +01:00
2010-02-16 16:42:13 +01:00
dbinfo = engine - > dbinfo ;
2018-12-03 12:40:13 -05:00
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 ;
2010-01-25 13:28:19 +01:00
}
2010-02-16 16:42:13 +01:00
dbinfo = engine - > dbinfo ? engine - > dbinfo - > next : NULL ;
2018-12-03 12:40:13 -05:00
if ( ! dbinfo ) {
cli_errmsg ( " cli_cvdload: dbinfo error \n " ) ;
return CL_EMALFDB ;
2012-08-10 10:17:22 -04:00
}
2010-02-16 16:42:13 +01:00
2011-01-17 19:06:57 +01:00
dbio . chkonly = chkonly ;
2018-12-03 12:40:13 -05:00
if ( dbtype = = 2 )
options | = CL_DB_UNSIGNED ;
2011-05-10 21:29:49 +02:00
else
2018-12-03 12:40:13 -05:00
options | = CL_DB_SIGNED | CL_DB_OFFICIAL ;
2011-05-10 21:29:49 +02:00
ret = cli_tgzload ( cfd , engine , signo , options , & dbio , dbinfo ) ;
2010-01-20 22:10:56 +01:00
2018-12-03 12:40:13 -05:00
while ( engine - > dbinfo ) {
dbinfo = engine - > dbinfo ;
engine - > dbinfo = dbinfo - > next ;
2019-05-03 18:16:03 -04:00
MPOOL_FREE ( engine - > mempool , dbinfo - > name ) ;
MPOOL_FREE ( engine - > mempool , dbinfo - > hash ) ;
2018-12-03 12:40:13 -05:00
if ( dbinfo - > cvd )
cl_cvdfree ( dbinfo - > cvd ) ;
2019-05-03 18:16:03 -04:00
MPOOL_FREE ( engine - > mempool , dbinfo ) ;
2008-11-04 18:45:48 +00:00
}
2010-01-20 22:10:56 +01:00
return ret ;
2003-09-29 11:44:52 +00:00
}
2009-02-03 18:47:18 +00:00
int cli_cvdunpack ( const char * file , const char * dir )
{
2018-12-03 12:40:13 -05:00
int fd , ret ;
2009-02-03 18:47:18 +00:00
2018-12-03 12:40:13 -05:00
fd = open ( file , O_RDONLY | O_BINARY ) ;
if ( fd = = - 1 )
return - 1 ;
2009-02-03 18:47:18 +00:00
2018-12-03 12:40:13 -05:00
if ( lseek ( fd , 512 , SEEK_SET ) < 0 ) {
close ( fd ) ;
return - 1 ;
2009-02-03 18:47:18 +00:00
}
ret = cli_untgz ( fd , dir ) ;
close ( fd ) ;
return ret ;
}