[Clamav-devel] Override the CA bundle file when using freshclam.

2020-06-06 Thread Ladar Levison
I was having trouble using the latest freshclam version on CentOS 6,
because the system wide CA bundle file used by libcurl is unable to
validate the ClamAV HTTPS certificates.  So I fixed the problem with a
small patch that allows the user to override the CA bundle file
freshclam uses. You can set the path via the "CAFile" directive in the
freshclam.conf file, or dictate the path using freshclam command line,
as --ca=FILE" ... the patch is a little rough, I didn't test/document
the conf file option, and I haven't written unit tests for it, but since
it's a pretty important feature I'm submitting the patch to the list ... L~



diff --git a/freshclam/freshclam.c b/freshclam/freshclam.c
index b638ad7..1a15257 100644
--- a/freshclam/freshclam.c
+++ b/freshclam/freshclam.c
@@ -154,6 +154,7 @@ static void help(void)
 printf("\n");
 printf("--config-file=FILE   Read configuration from FILE.\n");
 printf("--log=FILE   -l FILE Log into FILE\n");
+printf("--ca=FILEOverride the certificate bundle FILE location\n");
 printf("--daemon -d  Run in daemon mode\n");
 printf("--pid=FILE   -p FILE Save daemon's pid in FILE\n");
 #ifndef _WIN32
@@ -856,6 +857,7 @@ static fc_error_t initialize(struct optstruct *opts)
 if ((optget(opts, "LocalIPAddress"))->enabled)
 fcConfig.localIP = (optget(opts, "LocalIPAddress"))->strarg;
 
+fcConfig.caFile = optget(opts, "CAFile")->strarg;
 fcConfig.databaseDirectory = optget(opts, "DatabaseDirectory")->strarg;
 
 /* Select a path for the temp directory:  databaseDirectory/tmp */
diff --git a/libfreshclam/libfreshclam.c b/libfreshclam/libfreshclam.c
index c32646c..23e70be 100644
--- a/libfreshclam/libfreshclam.c
+++ b/libfreshclam/libfreshclam.c
@@ -206,6 +206,9 @@ fc_error_t fc_initialize(fc_config *fcConfig)
 if (NULL != fcConfig->proxyPassword) {
 g_proxyPassword = cli_strdup(fcConfig->proxyPassword);
 }
+if (NULL != fcConfig->caFile) {
+g_caFile = cli_strdup(fcConfig->caFile);
+}
 
 #ifdef _WIN32
 if ((fcConfig->databaseDirectory[strlen(fcConfig->databaseDirectory) - 1] != '/') &&
@@ -270,6 +273,10 @@ void fc_cleanup(void)
 free(g_userAgent);
 g_userAgent = NULL;
 }
+if (NULL != g_caFile) {
+free(g_caFile);
+g_caFile = NULL;
+}
 if (NULL != g_proxyServer) {
 free(g_proxyServer);
 g_proxyServer = NULL;
diff --git a/libfreshclam/libfreshclam.h b/libfreshclam/libfreshclam.h
index a83a338..a32f29b 100644
--- a/libfreshclam/libfreshclam.h
+++ b/libfreshclam/libfreshclam.h
@@ -50,6 +50,7 @@ typedef struct fc_config_ {
 uint32_t connectTimeout; /**< CURLOPT_CONNECTTIMEOUT, Timeout for the. connection phase (seconds). */
 uint32_t requestTimeout; /**< CURLOPT_TIMEOUT, Timeout for libcurl transfer operation (seconds). */
 uint32_t bCompressLocalDatabase; /**< If set, will apply gz compression to CLD databases. */
+const char *caFile;  /**< (optional) CA file to use for certificate verification, if desired. */
 const char *logFile; /**< (optional) Filepath to use for log output, if desired. */
 const char *logFacility; /**< (optional) System logging facility (I.e. "syslog"), if desired. */
 const char *localIP; /**< (optional) client IP for multihomed systems. */
diff --git a/libfreshclam/libfreshclam_internal.c b/libfreshclam/libfreshclam_internal.c
index 9907254..3d98364 100644
--- a/libfreshclam/libfreshclam_internal.c
+++ b/libfreshclam/libfreshclam_internal.c
@@ -108,6 +108,7 @@ uint16_t g_proxyPort  = 0;
 char *g_proxyUsername = NULL;
 char *g_proxyPassword = NULL;
 
+char *g_caFile= NULL;
 char *g_tempDirectory = NULL;
 char *g_databaseDirectory = NULL;
 
@@ -422,6 +423,12 @@ static fc_error_t create_curl_handle(
 }
 }
 
+if (g_caFile) {
+if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_CAINFO, g_caFile)) {
+logg("!create_curl_handle: Failed to set CURLOPT_CAINFO (%s)!\n", g_caFile);
+}
+}
+
 #if defined(C_DARWIN) || defined(_WIN32)
 if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, *sslctx_function)) {
 logg("*create_curl_handle: Failed to set SSL CTX function. Your libcurl may use an SSL backend that does not support CURLOPT_SSL_CTX_FUNCTION.\n");
diff --git a/libfreshclam/libfreshclam_internal.h b/libfreshclam/libfreshclam_internal.h
index 747e3ee..1d01c62 100644
--- a/libfreshclam/libfreshclam_internal.h
+++ b/libfreshclam/libfreshclam_internal.h
@@ -46,6 +46,7 @@ extern uint16_t g_proxyPort;
 extern char *g_proxyUsername;
 extern char *g_proxyPassword;
 
+extern char *g_caFile;
 extern char *g_tempDirectory;
 extern char *g_databaseDirectory;
 
diff --git a/shared/optparser.c b/shared/optparser.c
index bb597c7..2c0ed39 100644
--- 

Re: [Clamav-devel] New Version of ClamAV

2013-03-20 Thread Ladar Levison
On 3/20/2013 9:47 AM, Eugene Crosser wrote:
 On 03/20/2013 06:35 PM, Matt Olney wrote:

 We're currently scoping out the next version of ClamAV.  We have a number
 of ideas in house, but I wanted to solicit some feedback from our users
 about what you might be interested in seeing.
 API to scan data that is already read (or, more practically, mmap()'ed)
 into memory, a la scan_buff(void *start, size_t length, ...options etc.)

 Thanks,

 Eugene



 
I second that! Right now we have to write an email message to disk just so we 
can pass in a file descriptor.

I'd also advocate better support/documentation/testing of a lite ClamAV build 
configuration. Namely geared towards systems
with limited memory and/or smaller than normal thread stack sizes, or strict 
security environments, yet still capable of
examining large file(s). This would include being designed to run (as 
effectively as possible) without the builtin runtime.
Security audits have flagged ClamAV in the past because it ships with LLVM code 
and could (theoretically) execute arbitrary code
from a compromised definitions file.

___
http://lurker.clamav.net/list/clamav-devel.html
Please submit your patches to our Bugzilla: http://bugs.clamav.net


Re: [Clamav-devel] Problem building 0.97.2 on FreeBSD

2011-08-03 Thread Ladar Levison

On 8/2/2011 9:23 AM, Renato Botelho wrote:

A FreeBSD user reported me he got following while building
0.97.2 on a recent -current system:

PASS: check1_clamscan.sh
FAIL: check2_clamd.sh
PASS: check3_clamd.sh



I encountered the same error under RHEL 6 = ERROR: Can't send to clamd: 
Broken pipe. Increasing the resource limits fixed the issue for me. 
Attached is the patch I used to workaround the problem with the 0.97.1 
and 0.97.2 releases.  See this bug report for information:


https://wwws.clamav.net/bugzilla/show_bug.cgi?id=1990


diff -U 3 -H -b -w -B -E -i -p -r -N -- clamav/unit_tests/check_common.sh 
clamav.lavabit/unit_tests/check_common.sh
--- clamav/unit_tests/check_common.sh   2011-05-13 06:25:31.0 -0500
+++ clamav.lavabit/unit_tests/check_common.sh   2011-06-09 13:42:00.570566000 
-0500
@@ -47,8 +47,6 @@ die()
 
 # Setup test directory to avoid temporary and output file clashes
 test_start() {
-ulimit -t 120 || true; ulimit -d 1024000 || true;
-ulimit -v 1024000 || true;
 (cd test-$1 2/dev/null  killclamd || true)
 rm -rf test-$1
 mkdir test-$1
___
http://lurker.clamav.net/list/clamav-devel.html
Please submit your patches to our Bugzilla: http://bugs.clamav.net

Re: [Clamav-devel] [QUESTION] How does clamAV updates the signature database on-the-fly?

2010-08-14 Thread Ladar Levison

 On 7/28/2010 6:18 PM, thyago wrote:

I'm researching ways of updating a signature database on-the-fly, so the way
clamAV does it, can really help me out...
I mean, what structures are there? how is it implemented?
Is there a data structure used to store the signatures on memory? If so, how
exactly is it updated?
what type of data structure? dynamic or static?
I need to know if you guys use a pointer to the structure, and then just set
it to point to the new updated structure,
and if for example, there's a condition, that limits when this pointer can
be changed...like a thread needing to finish first

I tried to look for the implementation on the code itself...but it's so
big...i don't know in which file to look =/



Thank you very much, for the help

Thyago



Attached is my implementation. As you can see I use a RW lock to 
minimize contention.
/**
 * @file /magma/providers/external/clamav.c
 *
 * @brief Interface for the ClamAV library.
 *
 * $Author: Ladar Levison $
 * $Date: 2010/08/13 10:32:38 $
 * $Revision: ecaee526d4ba88a141c5b889dd023b13c05c2654 $
 *
 */

#include magma.h

/**
 * The virus engine spool directory.
 */
char *virus_spool = NULL;

/**
 * The mask used to generate temporary file names.
 */
char *virus_spool_mask = NULL;

/**
 * The status of the signatures directory.
 */
struct cl_stat virus_stat;

/**
 * The number of signatures loaded by the virus engine.
 */
unsigned int virus_sigs = 0;

/**
 * The virus engine context pointer.
 */
struct cl_engine *virus_engine = NULL;

/**
 * The virus engine read/write lock.
 */
pthread_rwlock_t virus_lock = PTHREAD_RWLOCK_INITIALIZER;

/**
 * Obtains a virus engine read lock and records the number of virus signatures 
loaded by the active ClamAV engine context.
 *
 * @return Returns the number of virus signatures loaded by the active ClamAV 
engine context.
 */
uint64_t virus_sigs_loaded(void) {

uint64_t loaded = 0;

pthread_rwlock_rdlock(virus_lock);
loaded = virus_sigs;
pthread_rwlock_unlock(virus_lock);

return loaded;
}

/**
 * Counts the number of official signatures available inside the ClamAV 
database folder.
 *
 * @return Returns the number of official signatures available inside the 
ClamAV database folder.
 */
uint64_t virus_sigs_total(void) {

int state;
unsigned int total = 0;

if ((state = cl_countsigs_d(magma.iface.virus.signatures, 
CL_COUNTSIGS_OFFICIAL, total)) != CL_SUCCESS) {
log_error(ClamAV was unable to count the number of available 
signatures. {cl_countsigs = %i = %s}, state, cl_strerror_d(state));
return 0;
}

return total;
}

/**
 * Frees a ClamAV engine context and sets the pointer to NULL.
 *
 * @param target A doubly referenced pointer to a ClamAV engine context.
 */
void virus_engine_destroy(struct cl_engine **target) {
log_check(!target || !*target);
cl_engine_free_d(*target);
*target = NULL;
return;
}


/**
 * Generates a new ClamAV engine context.
 *
 * @param   signatures An optional pointer which will be used to record the 
number of signatures loaded.
 * @return Returns a pointer to the newly created context or NULL if an error 
occurs.
 */
struct cl_engine * virus_engine_create(uint64_t *signatures) {

int state;
unsigned int loaded = 0;
struct cl_engine *target = NULL;

// Reset the signatures pointer if one was passed in.
if (*signatures) {
*signatures = 0;
}

// Allocate ClamAV engine context.
if ((target = cl_engine_new_d()) == NULL) {
log_error(ClamAV returned an error while allocating the engine 
context. {cl_engine = NULL});
return NULL;
}

// Load the current signature database.
if ((state = cl_load_d(magma.iface.virus.signatures, target, loaded, 
CL_DB_STDOPT)) != CL_SUCCESS) {
log_error(ClamAV returned an error while loading the database. 
{cl_load = %i = %s}, state, cl_strerror_d(state));
cl_engine_free_d(target);
return NULL;
}

// Compile the internal lookup structures.
if ((state = cl_engine_compile_d(target)) != CL_SUCCESS) {
log_error(ClamAV database compilation error. 
{cl_engine_compile = %i = %s}, state, cl_strerror_d(state));
cl_engine_free_d(target);
return NULL;
}

// Max scan size. 2048 MB.
// Sets the maximum amount of data to be scanned for each input file.
if ((state = cl_engine_set_num_d(target, CL_ENGINE_MAX_SCANSIZE, 2048ll 
* 1048576ll)) != CL_SUCCESS) {
log_error(ClamAV configuration error. {cl_engine_set_num = %i 
= %s}, state, cl_strerror_d(state));
cl_engine_free_d(target);
return NULL;
}

// Max file size. 512 MB.
// Files larger than this limit won't be scanned

Re: [Clamav-devel] [QUESTION] How does clamAV updates the signature database on-the-fly?

2010-08-14 Thread Ladar Levison

 On 8/14/2010 3:19 AM, Török Edwin wrote:


// Scan the message. The OLE code has a bug in it that causes segfaults.


What bug ??


That comment was related to a bug I found in Feb/2008 and v0.92.1, but 
has long since been patched. See this email thread for details:


http://marc.info/?l=clamav-develm=120442553919615

I had an internal patch floating around for awhile that fixed the issue 
inside ole2_walk_property_tree() by incrementing rec_level. Somewhere 
along the line the issue was fixed, but I never removed the comment. The 
relevant lines in v0.96.2 increment rec_level just like my patch did. I 
never submitted the patch because back in 2008 because you indicated 
that wasn't the best solution.



// We ignore email that ClamAV thinks is a phishing
based on scanner's internal heuristic checks. else if
(starts_ci_bl_bl(Phishing, 8, virname, ns_get_length(virname)) ||
starts_ci_bl_bl(Joke, 4, virname, ns_get_length(virname)))
{ pthread_rwlock_unlock(virus_lock);
stats_increment_by_name(provider.virus.scan.total);
stats_increment_by_name(provider.virus.scan.clean); close(fd);
return 0; }


This is incorrect, if you want to match the heuristic Phishing
detection use Heuristics.Phishing.
There are signatures which contain *Phishing*, and *Joke*. ClamAV stops
on first match.

So if you get a zip that contains something ClamAV detects as
Phishing/Joke as first element in zip followed a real malware, then it
will only report the first match (Phishing/Joke). Your code will mark
it as clean, when in fact it could be infected.
(Note that this is not the case for Heuristics.Phishing where ClamAV
keeps on scanning and only reports the heuristics if it didn't find
anything else).

The proper way to deal with this is to not load the Phishing signatures
at all, there is an option you can pass to cl_load() for that.
For *Joke* there is no flag that you can pass though.


Is it possible to determine when ClamAV detects more than one virus and 
iterate through the resulting names? I revisited the ex1.c file, and the 
clamscan/manager.c file and they seem to suffer from the same issue. In 
the case of clamscan, it only outputs the first virus name, which like 
you pointed out could be innocuous compared to what else lies farther 
along in the file.


If we are limited to only a single result, wouldn't it make more sense 
to have a precendence order in place? Presumably malware would rate 
ahead of phishing or jokes.


--
Ladar Levison
Lavabit LLC
http://lavabit.com





___
http://lurker.clamav.net/list/clamav-devel.html
Please submit your patches to our Bugzilla: http://bugs.clamav.net


Re: [Clamav-devel] [QUESTION] How does clamAV updates the signature database on-the-fly?

2010-08-14 Thread Ladar Levison

 On 8/14/2010 5:30 AM, Török Edwin wrote:

Heuristics.Phishing.* will not stop the scan, and report only if
nothing else is found.
Other engine detections could be changed to behave the same way.
Signature based detections however always stop on first match, and that
is not configurable.
If you want to ignore certain signature categories, it is best to not
load them in the first place. To do that you can unpack the DBs, and
remove the sigs you don't want.



What I'm trying to do is let the user decide whether to enable a 
specific category, so removing the signatures from the database isn't an 
option for me. For awhile now, our users have been able to use the 
preferences portal on our website to enable/disable malware checks 
and/or phishing checks. The malware category is usually a reliable 
reason to send a message to the bit bucket. While the latter 
Phishing/Heuristic/Joke categories are more likely to generate a false 
positive. Perhaps its just me, but I would consider the ability to 
reliably determine what ClamAV found important.


--
Ladar Levison
Lavabit LLC
http://lavabit.com





___
http://lurker.clamav.net/list/clamav-devel.html
Please submit your patches to our Bugzilla: http://bugs.clamav.net

Re: [Clamav-devel] The upcoming 15 April kill-switch

2010-04-08 Thread Ladar Levison

On 4/7/2010 4:05 PM, David F. Skoll wrote:

o The server could look at the Freshclam user-agent version number and
not serve up the new database if it's too old.
   


Wouldn't this provide a solution? I checked, and freshclam does provide 
the version number in the User-Agent string. I used the trusty packet 
sniffer to check first. And while I'm not sure what the end result/error 
would be, couldn't the servers be easily configured to redirect requests 
from old clients? Or better yet, somehow return the last valid/working 
image for  0.94.2 clients?


I understand that F/OSS projects like ClamAV are at the mercy of what 
the developers would like to work on, and that generally means pushing 
the code forward rather than maintaining past releases; but common 
cutesy says they also shouldn't knowingly make technical decisions that 
will result their code exploding into a burst of flames at some 
arbitrary point in the future. As someone who regularly gets parachuted 
into burning buildings with a keyboard and a water bucket; I 
instinctively frown upon the people who go about setting fires on purpose.


There is a big difference between a product that is no longer 
updated/maintained past a certain date but continues to provide the same 
humble functionality it had when it was abandoned, and one that refuses 
past a certain date.


Personally speaking, I have a few servers in production right now that 
use 0.94.2 because moving past that point will require updating code to 
use the new library interface. I had assumed on those servers that 
ClamAV would simply continue working past the 15th, but would just be 
stuck using whatever ends up being the last compatible signatures 
database. This thread made me realize that if I don't disable freshclam 
on the 14th, I might be needing the water bucket on the 15th.


For those sysadmins who don't notice this thread; I hope all that ends 
up happening is inbound mail gets delivered without being scanned. And 
that they are are able to revert their database to a working version or 
update their installs before the bad guys realize which systems are no 
longer scanning for viruses.


Of course the unlucky ones will only hear the bells that ring when the 
bits stop flowing.


Anyone feel like volunteering to create a wrapped version of ClamAV that 
is binary compatible with pre 0.95 installs?




___
http://lurker.clamav.net/list/clamav-devel.html
Please submit your patches to our Bugzilla: http://bugs.clamav.net


Re: [Clamav-devel] [Clamav] Cannot dlopen: file not found - unrar support unavailable

2009-03-25 Thread Ladar Levison
Eugene Crosser wrote:
 I suspect that this may break on AMD64. It's more picky about PIC/non-PIC code
 (no pun intended), attempt to link objects from .a into .so often fails.
   

I haven't tested this method on any AMD64 servers, but it wouldn't 
surprise if you were right. When I tried using this method on a Cent OS 
5 system, I had to link 1-2 or other libraries before dlopen() would 
accept it.

Any thoughts on a better way of accomplishing the same task? I like to 
combine all of the f/oss libraries my daemon uses into a single library 
(clamav, openssl, memcached, etc). It makes deployments easier 
(executable, f/oss library and config file).

___
http://lurker.clamav.net/list/clamav-devel.html
Please submit your patches to our Bugzilla: http://bugs.clamav.net


[Clamav-devel] API concerns

2009-03-13 Thread Ladar Levison
There currently is no function call available via the public libclamav 
API to return the total number of signatures in the database directory. 
To find this number a developer would need to manually pass the file 
names to the CVD functions. Since there are multiple files stored in the 
directory, and filenames change, I don't feel that is a stable interface 
model.

Why not store the number as part of the cl_stat structure, and return it 
with a simple function call:

unsigned int cl_statsigtotal(const struct cl_stat *dbstat);

I like to write this total to the log files so I periodically check to 
make sure the database is up to date, and has been refreshed inside the 
daemon. Checking the number against the one on the clamav.net home page 
is easiest, since I don't have freshclam installed on every server.

I used to use the number of signatures returned by the cl_load function, 
but that function only returns the number of signatures loaded, not the 
number of signatures available. (When I first implemented my interface, 
there was no distinction.)


___
http://lurker.clamav.net/list/clamav-devel.html
Please submit your patches to our Bugzilla: http://bugs.clamav.net