Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,29 @@ if(ENABLE_STATIC_LIB)
target_link_libraries( ex1_static PUBLIC ${LLVM_LIBRARIES} )
endif()
endif()

add_executable(ex_cl_cvdunpack)
target_sources(ex_cl_cvdunpack
PRIVATE ex_cl_cvdunpack.c)
set_target_properties( ex_cl_cvdunpack PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}" )
target_link_libraries(ex_cl_cvdunpack
PRIVATE
ClamAV::libclamav)
if(LLVM_FOUND)
target_link_directories( ex_cl_cvdunpack PUBLIC ${LLVM_LIBRARY_DIRS} )
target_link_libraries( ex_cl_cvdunpack PUBLIC ${LLVM_LIBRARIES} )
endif()

if(ENABLE_STATIC_LIB)
add_executable(ex_cl_cvdunpack_static)
set_target_properties( ex_cl_cvdunpack_static PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}" )
target_sources(ex_cl_cvdunpack_static
PRIVATE ex_cl_cvdunpack.c)
target_link_libraries(ex_cl_cvdunpack_static
PRIVATE
ClamAV::libclamav_static)
if(LLVM_FOUND)
target_link_directories( ex_cl_cvdunpack_static PUBLIC ${LLVM_LIBRARY_DIRS} )
target_link_libraries( ex_cl_cvdunpack_static PUBLIC ${LLVM_LIBRARIES} )
endif()
endif()
90 changes: 90 additions & 0 deletions examples/ex_cl_cvdunpack.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Compilation: gcc -Wall ex1.c -o ex1 -lclamav
*
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2007-2013 Sourcefire, Inc.
* Author: Tomasz Kojm <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <clamav.h>

#ifndef O_BINARY
#define O_BINARY 0
#endif

/*
* Exit codes: 0 is success. See `cl_error_t` enum from clamav.h.
*/
int main(int argc, char **argv)
{
int fd;
cl_error_t ret;

const char *filename;
const char *destination_directory;
bool dont_verify = false;

char dest_buff[1024];

unsigned long int size = 0;
unsigned int sigs = 0;
long double mb;
const char *virname;
struct cl_engine *engine;
struct cl_scan_options options;

switch (argc) {
case 2:
filename = argv[1];
destination_directory = ".";
break;
case 3:
filename = argv[1];
destination_directory = argv[2];
break;
case 4:
if (strcmp(argv[1], "--no-verify") == 0) {
filename = argv[2];
destination_directory = argv[3];
dont_verify = true;
} else {
printf("Usage: %s [--no-verify] file [destination_directory]\n", argv[0]);
return CL_EARG;
}
break;
default:
printf("Usage: %s [--no-verify] file [destination_directory]\n", argv[0]);
return CL_EARG;
}

ret = cl_cvdunpack(filename, destination_directory, dont_verify);
if (ret != CL_SUCCESS) {
printf("ERROR: %s\n", cl_strerror(ret));
}

return (int)ret;
}
13 changes: 13 additions & 0 deletions libclamav/clamav.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@

#include <sys/types.h>
#include <sys/stat.h>
#include <stdbool.h>

#include "clamav-types.h"
#include "clamav-version.h"
Expand Down Expand Up @@ -1073,6 +1074,18 @@ extern cl_error_t cl_cvdverify(const char *file);
*/
extern void cl_cvdfree(struct cl_cvd *cvd);

/**
* @brief Unpack a CVD file.
*
* Will verify the CVD is correctly signed unless the `dont_verify` parameter is true.
*
* @param file Filepath of CVD file.
* @param dir Destination directory.
* @param dont_verify If true, don't verify the CVD.
* @return cl_error_t CL_SUCCESS if success, else a CL_E* error code.
*/
extern cl_error_t cl_cvdunpack(const char *file, const char *dir, bool dont_verify);

/* ----------------------------------------------------------------------------
* DB directory stat functions.
* Use these functions to watch for database changes.
Expand Down
52 changes: 47 additions & 5 deletions libclamav/cvd.c
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,15 @@ void cl_cvdfree(struct cl_cvd *cvd)
free(cvd);
}

static int cli_cvdverify(FILE *fs, struct cl_cvd *cvdpt, unsigned int skipsig)
/**
* @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)
{
struct cl_cvd *cvd;
char *md5, head[513];
Expand Down Expand Up @@ -585,7 +593,7 @@ cl_error_t cl_cvdverify(const char *file)
}

if (!(engine = cl_engine_new())) {
cli_errmsg("cld_cvdverify: Can't create new engine\n");
cli_errmsg("cl_cvdverify: Can't create new engine\n");
fclose(fs);
return CL_EMEM;
}
Expand All @@ -603,11 +611,11 @@ cl_error_t cl_cvdverify(const char *file)
return ret;
}

int cli_cvdload(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, unsigned int dbtype, const char *filename, unsigned int chkonly)
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)
{
struct cl_cvd cvd, dupcvd;
FILE *dupfs;
int ret;
cl_error_t ret;
time_t s_time;
int cfd;
struct cli_dbio dbio;
Expand Down Expand Up @@ -715,7 +723,7 @@ int cli_cvdload(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigne
return ret;
}

int cli_cvdunpack(const char *file, const char *dir)
static cl_error_t cli_cvdunpack(const char *file, const char *dir)
{
int fd, ret;

Expand All @@ -732,3 +740,37 @@ int cli_cvdunpack(const char *file, const char *dir)
close(fd);
return ret;
}

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];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this cli_strerror call use err[128] when the others do not? This is not a static function or anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our cli_strerror is a wrapper for the poorly standardized strerror system function, not to be confused with cl_strerror, which is the clamav API for converting the clam error enum to a message.

The err[128] approach is something I copypasted from elsewhere in the code. Such as: https://github.com/Cisco-Talos/clamav/blob/main/libclamav/untar.c#L318-L319

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;
}
3 changes: 1 addition & 2 deletions libclamav/cvd.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ struct cli_dbio {
void *hashctx;
};

int cli_cvdload(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, unsigned int dbtype, const char *filename, unsigned int chkonly);
int cli_cvdunpack(const char *file, const char *dir);
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);

#endif
12 changes: 9 additions & 3 deletions libfreshclam/libfreshclam_internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1498,9 +1498,12 @@ static fc_error_t getcvd(
}

/**
* @brief Change to the temp dir for storing CDIFFs for incremental database update.
* @brief Create a temp dir for storing CDIFFs for incremental database update.
*
* Will create the temp dir if it does not already exist.
* Will create the temp dir if it does not already exist and populate it with the
* unpacked CVD. Then it will chdir to that directory.
*
* But if that directory already exists, it will simply chdir to it.
*
* @param database The database we're updating.
* @param[out] tmpdir The name of the temp dir to use.
Expand Down Expand Up @@ -1555,7 +1558,10 @@ static fc_error_t mkdir_and_chdir_for_cdiff_tmp(const char *database, const char
goto done;
}

if (-1 == cli_cvdunpack(cvdfile, tmpdir)) {
/*
* 3) Unpack the existing CVD/CLD database to this directory.
*/
if (CL_SUCCESS != cl_cvdunpack(cvdfile, tmpdir, false)) {
logg(LOGG_ERROR, "mkdir_and_chdir_for_cdiff_tmp: Can't unpack %s into %s\n", cvdfile, tmpdir);
cli_rmdirs(tmpdir);
goto done;
Expand Down
14 changes: 7 additions & 7 deletions sigtool/sigtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,7 @@ static int build(const struct optstruct *opts)
return -1;
}

if (cli_cvdunpack(olddb, pt) == -1) {
if (CL_SUCCESS != cl_cvdunpack(olddb, pt, false)) {
mprintf(LOGG_ERROR, "build: Can't unpack CVD file %s\n", olddb);
cli_rmdirs(pt);
free(pt);
Expand All @@ -1120,7 +1120,7 @@ static int build(const struct optstruct *opts)
return -1;
}

if (cli_cvdunpack(newcvd, pt) == -1) {
if (CL_SUCCESS != cl_cvdunpack(newcvd, pt, false)) {
mprintf(LOGG_ERROR, "build: Can't unpack CVD file %s\n", newcvd);
cli_rmdirs(pt);
free(pt);
Expand Down Expand Up @@ -1194,7 +1194,7 @@ static int unpack(const struct optstruct *opts)
return -1;
}

if (cli_cvdunpack(name, ".") == -1) {
if (CL_SUCCESS != cl_cvdunpack(name, ".", false)) {
mprintf(LOGG_ERROR, "unpack: Can't unpack file %s\n", name);
return -1;
}
Expand Down Expand Up @@ -1348,7 +1348,7 @@ static int listdb(const char *filename, const regex_t *regex)
return -1;
}

if (cli_cvdunpack(filename, dir) == -1) {
if (CL_SUCCESS != cl_cvdunpack(filename, dir, false)) {
mprintf(LOGG_ERROR, "listdb: Can't unpack CVD file %s\n", filename);
cli_rmdirs(dir);
free(dir);
Expand Down Expand Up @@ -1981,7 +1981,7 @@ static int verifydiff(const char *diff, const char *cvd, const char *incdir)
}

if (cvd) {
if (cli_cvdunpack(cvd, tempdir) == -1) {
if (CL_SUCCESS != cl_cvdunpack(cvd, tempdir, false)) {
mprintf(LOGG_ERROR, "verifydiff: Can't unpack CVD file %s\n", cvd);
cli_rmdirs(tempdir);
free(tempdir);
Expand Down Expand Up @@ -3196,7 +3196,7 @@ static int makediff(const struct optstruct *opts)
return -1;
}

if (cli_cvdunpack(optget(opts, "diff")->strarg, odir) == -1) {
if (CL_SUCCESS != cl_cvdunpack(optget(opts, "diff")->strarg, odir, false)) {
mprintf(LOGG_ERROR, "makediff: Can't unpack CVD file %s\n", optget(opts, "diff")->strarg);
cli_rmdirs(odir);
free(odir);
Expand All @@ -3219,7 +3219,7 @@ static int makediff(const struct optstruct *opts)
return -1;
}

if (cli_cvdunpack(opts->filename[0], ndir) == -1) {
if (CL_SUCCESS != cl_cvdunpack(opts->filename[0], ndir, false)) {
mprintf(LOGG_ERROR, "makediff: Can't unpack CVD file %s\n", opts->filename[0]);
cli_rmdirs(odir);
cli_rmdirs(ndir);
Expand Down
11 changes: 11 additions & 0 deletions unit_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,17 @@ if(ENABLE_APP)
endif()
endif()

if(ENABLE_EXAMPLES)
add_test(NAME examples COMMAND ${PythonTest_COMMAND};examples
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
set_property(TEST examples PROPERTY ENVIRONMENT ${ENVIRONMENT})
if(Valgrind_FOUND)
add_test(NAME examples_valgrind COMMAND ${PythonTest_COMMAND};examples
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
set_property(TEST examples_valgrind PROPERTY ENVIRONMENT ${ENVIRONMENT} VALGRIND=${Valgrind_EXECUTABLE})
endif()
endif()

if(WIN32)
#
# Prepare a test install, with all our DLL dependencies co-located with our EXEs and DLLs
Expand Down
Loading