freshclam: load database in subprocess (bb #2147).

0.96
Török Edvin 15 years ago
parent 51e69a14b9
commit 536cf542bb
  1. 4
      ChangeLog
  2. 9
      freshclam/freshclam.c
  3. 166
      freshclam/manager.c

@ -1,3 +1,7 @@
Thu Nov 4 19:47:17 EET 2010 (edwin)
------------------------------------
* freshclam: load database in subprocess (bb #2147).
Wed Nov 3 13:38:47 CET 2010 (tk)
---------------------------------
* clamd: add new commands DETSTATS and DETSTATSCLEAR (part of bb#2312)

@ -64,17 +64,25 @@ extern int active_children;
static short foreground = 1;
char updtmpdir[512];
int sigchld_wait = 1;
static void sighandler(int sig) {
switch(sig) {
#ifdef SIGCHLD
case SIGCHLD:
if (sigchld_wait)
waitpid(-1, NULL, WNOHANG);
active_children--;
break;
#endif
#ifdef SIGPIPE
case SIGPIPE:
/* no action, app will get EPIPE */
break;
#endif
#ifdef SIGALRM
case SIGALRM:
terminate = -1;
@ -396,6 +404,7 @@ int main(int argc, char **argv)
memset(&sigact, 0, sizeof(struct sigaction));
sigact.sa_handler = sighandler;
sigaction(SIGINT, &sigact, NULL);
sigaction(SIGPIPE, &sigact, NULL);
#endif
if(optget(opts, "daemon")->enabled) {
int bigsleep, checks;

@ -1519,11 +1519,128 @@ static int buildcld(const char *tmpdir, const char *dbname, const char *newfile,
return 0;
}
static int test_database(const char *newfile, const char *newdb, int bytecode)
{
struct cl_engine *engine;
unsigned newsigs = 0;
int ret;
logg("*Loading signatures from %s\n", newdb);
if(!(engine = cl_engine_new())) {
return 55;
}
if((ret = cl_load(newfile, engine, &newsigs, CL_DB_PHISHING | CL_DB_PHISHING_URLS | CL_DB_BYTECODE | CL_DB_PUA)) != CL_SUCCESS) {
logg("!Failed to load new database: %s\n", cl_strerror(ret));
cl_engine_free(engine);
return 55;
}
if(bytecode && (ret = cli_bytecode_prepare2(engine, &engine->bcs, engine->dconf->bytecode/*FIXME: dconf has no sense here*/))) {
logg("!Failed to compile/load bytecode: %s\n", cl_strerror(ret));
cl_engine_free(engine);
return 55;
}
logg("*Properly loaded %u signatures from new %s\n", newsigs, newdb);
if(engine->domainlist_matcher && engine->domainlist_matcher->sha256_pfx_set.keys)
cli_hashset_destroy(&engine->domainlist_matcher->sha256_pfx_set);
cl_engine_free(engine);
return 0;
}
#ifndef WIN32
static int test_database_wrap(const char *file, const char *newdb, int bytecode)
{
char firstline[256];
char lastline[256];
int pipefd[2];
pid_t pid;
int status = 0;
FILE *f;
if (pipe(pipefd) == -1) {
logg("^pipe() failed: %s\n", strerror(errno));
return test_database(file, newdb, bytecode);
}
switch ( pid = fork() ) {
case 0:
close(pipefd[0]);
dup2(pipefd[1], 2);
exit(test_database(file, newdb, bytecode));
case -1:
close(pipefd[0]);
close(pipefd[1]);
logg("^fork() failed: %s\n", strerror(errno));
return test_database(file, newdb, bytecode);
default:
/* read first / last line printed by child*/
close(pipefd[1]);
f = fdopen(pipefd[0], "r");
firstline[0] = 0;
lastline[0] = 0;
do {
fgets(firstline, sizeof(firstline), f);
/* ignore warning messages, otherwise the outdated warning will
* make us miss the important part of the error message */
} while (!strncmp(firstline, "LibClamAV Warning:", 18));
/* must read entire output, child doesn't like EPIPE */
while (fgets(lastline, sizeof(firstline), f)) {
/* print the full output only when LogVerbose or -v is given */
logg("*%s", lastline);
}
fclose(f);
if (waitpid(pid, &status, 0) == -1 && errno != ECHILD)
logg("^waitpid() failed: %s\n", strerror(errno));
cli_chomp(firstline);
cli_chomp(lastline);
if (firstline[0]) {
logg("!During database load : %s%s%s\n",
firstline, lastline[0] ? " [...] " : "",
lastline);
}
if (WIFEXITED(status)) {
int ret = WEXITSTATUS(status);
if (ret) {
logg("^Database load exited with status %d\n", ret);
return ret;
}
if (firstline[0])
logg("^Database successfully loaded, but there is stderr output\n");
return 0;
}
if (WIFSIGNALED(status)) {
logg("!Database load killed by signal %d\n", WTERMSIG(status));
return 55;
}
logg("^Unknown status from wait: %d\n", status);
return 55;
}
}
#else
static int test_database_wrap(const char *file, const char *newdb, int bytecode)
{
int ret = 55;
__try
{
ret = test_database(file, newdb, bytecode);
}
__finally {
if (AbnormalTermination())
logg("!Exception during database testing, code %08x at %08x\n",
GetExceptionCode(), GetExceptionInformation()->ExceptionRecord->ExceptionAddress);
}
return ret;
}
#endif
extern int sigchld_wait;
static int updatedb(const char *dbname, const char *hostname, char *ip, int *signo, const struct optstruct *opts, const char *dnsreply, char *localip, int outdated, struct mirdat *mdat, int logerr, int extra)
{
struct cl_cvd *current, *remote;
const struct optstruct *opt;
unsigned int nodb = 0, currver = 0, newver = 0, port = 0, i, j, newsigs = 0;
unsigned int nodb = 0, currver = 0, newver = 0, port = 0, i, j;
int ret, ims = -1;
char *pt, cvdfile[32], localname[32], *tmpdir = NULL, *newfile, *newfile2, newdb[32];
char extradbinfo[64], *extradnsreply = NULL;
@ -1531,7 +1648,6 @@ static int updatedb(const char *dbname, const char *hostname, char *ip, int *sig
unsigned int flevel = cl_retflevel(), remote_flevel = 0, maxattempts;
unsigned int can_whitelist = 0;
int ctimeout, rtimeout;
struct cl_engine *engine;
snprintf(cvdfile, sizeof(cvdfile), "%s.cvd", dbname);
@ -1775,16 +1891,11 @@ static int updatedb(const char *dbname, const char *hostname, char *ip, int *sig
}
if(optget(opts, "TestDatabases")->enabled && strlen(newfile) > 4) {
if(!(engine = cl_engine_new())) {
unlink(newfile);
free(newfile);
return 55;
}
newfile2 = strdup(newfile);
if(!newfile2) {
logg("!Can't allocate memory for filename!\n");
unlink(newfile);
free(newfile);
cl_engine_free(engine);
return 55;
}
newfile2[strlen(newfile2) - 4] = '.';
@ -1796,29 +1907,18 @@ static int updatedb(const char *dbname, const char *hostname, char *ip, int *sig
unlink(newfile);
free(newfile);
free(newfile2);
cl_engine_free(engine);
return 57;
}
free(newfile);
newfile = newfile2;
if((ret = cl_load(newfile, engine, &newsigs, CL_DB_PHISHING | CL_DB_PHISHING_URLS | CL_DB_BYTECODE | CL_DB_PUA)) != CL_SUCCESS) {
sigchld_wait = 0;/* we need to wait() for the child ourselves */
if (test_database_wrap(newfile, newdb, optget(opts, "Bytecode")->enabled)) {
logg("!Failed to load new database: %s\n", cl_strerror(ret));
unlink(newfile);
free(newfile);
cl_engine_free(engine);
return 55;
}
if(optget(opts, "Bytecode")->enabled && (ret = cli_bytecode_prepare2(engine, &engine->bcs, engine->dconf->bytecode/*FIXME: dconf has no sense here*/))) {
logg("!Failed to compile/load bytecode: %s\n", cl_strerror(ret));
unlink(newfile);
free(newfile);
cl_engine_free(engine);
return 55;
}
logg("*Properly loaded %u signatures from new %s\n", newsigs, newdb);
if(engine->domainlist_matcher && engine->domainlist_matcher->sha256_pfx_set.keys)
cli_hashset_destroy(&engine->domainlist_matcher->sha256_pfx_set);
cl_engine_free(engine);
sigchld_wait = 1;
}
#ifdef _WIN32
@ -1872,7 +1972,6 @@ static int updatecustomdb(const char *url, int *signo, const struct optstruct *o
char *pt, *host, urlcpy[256], *newfile = NULL, mtime[36], *newfile2;
const char *proxy = NULL, *user = NULL, *pass = NULL, *uas = NULL, *rpath, *dbname;
int ctimeout, rtimeout;
struct cl_engine *engine;
struct stat sb;
struct cl_cvd *cvd;
@ -1982,29 +2081,14 @@ static int updatecustomdb(const char *url, int *signo, const struct optstruct *o
}
free(newfile);
newfile = newfile2;
if(!(engine = cl_engine_new())) {
unlink(newfile);
free(newfile);
return 55;
}
if((ret = cl_load(newfile, engine, &newsigs, CL_DB_PHISHING | CL_DB_PHISHING_URLS | CL_DB_BYTECODE | CL_DB_PUA)) != CL_SUCCESS) {
sigchld_wait = 0;/* we need to wait() for the child ourselves */
if (test_database_wrap(newfile, dbname, optget(opts, "Bytecode")->enabled)) {
logg("!Failed to load new database: %s\n", cl_strerror(ret));
unlink(newfile);
free(newfile);
cl_engine_free(engine);
return 55;
}
if(optget(opts, "Bytecode")->enabled && (ret = cli_bytecode_prepare2(engine, &engine->bcs, engine->dconf->bytecode/*FIXME: dconf has no sense here*/))) {
logg("!Failed to compile/load bytecode: %s\n", cl_strerror(ret));
unlink(newfile);
free(newfile);
cl_engine_free(engine);
return 55;
}
logg("*Properly loaded %u signatures from new (custom) %s\n", newsigs, dbname);
if(engine->domainlist_matcher && engine->domainlist_matcher->sha256_pfx_set.keys)
cli_hashset_destroy(&engine->domainlist_matcher->sha256_pfx_set);
cl_engine_free(engine);
sigchld_wait = 1;
}
#ifdef _WIN32

Loading…
Cancel
Save