[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#703391: Reduced debdiff



diff -Nru clamav-0.97.6+dfsg/ChangeLog clamav-0.97.7+dfsg/ChangeLog
--- clamav-0.97.6+dfsg/ChangeLog	2012-09-17 11:15:12.000000000 -0400
+++ clamav-0.97.7+dfsg/ChangeLog	2013-03-11 11:23:20.000000000 -0400
@@ -1,3 +1,8 @@
+Wed Feb 20 10:05:00 EDT 2012 (multiple)
+---------------------------------
+ * Bug reported by Felix Groebert, Mateusz Jurczyk and Gynvael Coldwind of the
+ Google Security Team.
+
 Mon Sep 6 12:32:00 EDT 2012 (dar)
 ---------------------------------
  * libclamav: bb#5751 - cl_scansis() may returan a file descriptor instead
diff -Nru clamav-0.97.6+dfsg/clamd/scanner.c clamav-0.97.7+dfsg/clamd/scanner.c
--- clamav-0.97.6+dfsg/clamd/scanner.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/clamd/scanner.c	2013-03-11 11:23:20.000000000 -0400
@@ -107,6 +107,7 @@
 {
     struct scan_cb_data *scandata = data->data;
     const char *virname;
+    const char **virpp = &virname;
     int ret;
     int type = scandata->type;
     struct cb_context context;
@@ -228,11 +229,18 @@
 			 type == TYPE_MULTISCAN ? "MULTISCANFILE" : NULL);
     context.filename = filename;
     context.virsize = 0;
-    ret = cl_scanfile_callback(filename, &virname, &scandata->scanned, scandata->engine, scandata->options, &context);
+    ret = cl_scanfile_callback(filename, virpp, &scandata->scanned, scandata->engine, scandata->options, &context);
     thrmgr_setactivetask(NULL, NULL);
 
+    if (scandata->options & CL_SCAN_ALLMATCHES) {
+	virpp = (const char **)*virpp; /* temp hack for scanall mode until api augmentation */
+	virname = virpp[0];
+    }
+
     if (thrmgr_group_need_terminate(scandata->conn->group)) {
 	free(filename);
+	if (ret == CL_VIRUS && scandata->options & CL_SCAN_ALLMATCHES)
+	    free((void *)virpp);
 	logg("*Client disconnected while scanjob was active\n");
 	return ret == CL_ETIMEOUT ? ret : CL_BREAK;
     }
@@ -241,8 +249,19 @@
 	scandata->infected++;
 	if (conn_reply_virus(scandata->conn, filename, virname) == -1) {
 	    free(filename);
+	    if (scandata->options & CL_SCAN_ALLMATCHES)
+		free((void *)virpp);
 	    return CL_ETIMEOUT;
 	}
+	if (scandata->options & CL_SCAN_ALLMATCHES && virpp[1] != NULL) {
+	    int i = 1;
+	    while (NULL != virpp[i])
+		if (conn_reply_virus(scandata->conn, filename, virpp[i++]) == -1) {
+		    free(filename);
+		    free((void *)virpp);
+		    return CL_ETIMEOUT;
+		}
+	}
 	if(context.virsize)
 	    detstats_add(virname, filename, context.virsize, context.virhash);
 	if(context.virsize && optget(scandata->opts, "ExtendedDetectionInfo")->enabled)
@@ -250,6 +269,11 @@
 	else
 	    logg("~%s: %s FOUND\n", filename, virname);
 	virusaction(filename, virname, scandata->opts);
+	if (scandata->options & CL_SCAN_ALLMATCHES && virpp[1] != NULL) {
+	    int i = 1;
+	    while (NULL != virpp[i])
+                logg("~%s: %s FOUND\n", filename, virpp[i++]);
+	}
     } else if (ret != CL_CLEAN) {
 	scandata->errors++;
 	if (conn_reply(scandata->conn, filename, cl_strerror(ret), "ERROR") == -1) {
@@ -262,6 +286,8 @@
     }
 
     free(filename);
+    if (ret == CL_VIRUS && scandata->options & CL_SCAN_ALLMATCHES)
+	free((void *)virpp);
     if(ret == CL_EMEM) /* stop scanning */
 	return ret;
 
diff -Nru clamav-0.97.6+dfsg/clamd/session.c clamav-0.97.7+dfsg/clamd/session.c
--- clamav-0.97.6+dfsg/clamd/session.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/clamd/session.c	2013-03-11 11:23:20.000000000 -0400
@@ -94,7 +94,8 @@
     {CMD16, sizeof(CMD16)-1,	COMMAND_IDSESSION,  0,	0, 1},
     {CMD17, sizeof(CMD17)-1,	COMMAND_INSTREAM,   0,	0, 1},
     {CMD19, sizeof(CMD19)-1,	COMMAND_DETSTATSCLEAR,	0, 1, 1},
-    {CMD20, sizeof(CMD20)-1,	COMMAND_DETSTATS,   0, 1, 1}
+    {CMD20, sizeof(CMD20)-1,	COMMAND_DETSTATS,   0, 1, 1},
+    {CMD21, sizeof(CMD21)-1,	COMMAND_ALLMATCHSCAN,  1, 0, 1}
 };
 
 enum commands parse_command(const char *cmd, const char **argument, int oldstyle)
@@ -346,7 +347,11 @@
 	    conn->scanfd = -1;
 	    cli_unlink(conn->filename);
 	    return ret;
-	default:
+	case COMMAND_ALLMATCHSCAN:
+	     thrmgr_setactivetask(NULL, "ALLMATCHSCAN");
+	     scandata.options |= CL_SCAN_ALLMATCHES;
+	     type = TYPE_SCAN;
+	     break;default:
 	    logg("!Invalid command distpached: %d\n", conn->cmdtype);
 	    return 1;
     }
@@ -420,6 +425,7 @@
 	case COMMAND_SCAN:
 	case COMMAND_CONTSCAN:
 	case COMMAND_MULTISCAN:
+        case COMMAND_ALLMATCHSCAN:
 	    dup_conn->filename = strdup(argument);
 	    if (!dup_conn->filename) {
 		logg("!Failed to allocate memory for filename\n");
@@ -591,6 +597,7 @@
 	case COMMAND_FILDES:
 	case COMMAND_SCAN:
 	case COMMAND_INSTREAMSCAN:
+	case COMMAND_ALLMATCHSCAN:
 	    return dispatch_command(conn, cmd, argument);
 	case COMMAND_IDSESSION:
 	    conn->group = thrmgr_group_new();
diff -Nru clamav-0.97.6+dfsg/clamd/session.h clamav-0.97.7+dfsg/clamd/session.h
--- clamav-0.97.6+dfsg/clamd/session.h	2012-06-12 09:03:26.000000000 -0400
+++ clamav-0.97.7+dfsg/clamd/session.h	2013-03-11 11:21:44.000000000 -0400
@@ -43,6 +43,8 @@
 #define CMD19 "DETSTATSCLEAR"
 #define CMD20 "DETSTATS"
 
+#define CMD21 "ALLMATCHSCAN"
+
 #include "libclamav/clamav.h"
 #include "shared/optparser.h"
 #include "server.h"
@@ -70,7 +72,8 @@
     COMMAND_DETSTATS,
     /* internal commands */
     COMMAND_MULTISCANFILE,
-    COMMAND_INSTREAMSCAN
+    COMMAND_INSTREAMSCAN,
+    COMMAND_ALLMATCHSCAN
 };
 
 typedef struct client_conn_tag {
diff -Nru clamav-0.97.6+dfsg/clamdscan/client.c clamav-0.97.7+dfsg/clamdscan/client.c
--- clamav-0.97.6+dfsg/clamdscan/client.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/clamdscan/client.c	2013-03-11 11:23:20.000000000 -0400
@@ -232,7 +232,9 @@
     if(remote || scandash) {
 	scantype = STREAM;
 	session = optget(opts, "multiscan")->enabled;
-    } else if(optget(opts, "multiscan")->enabled) scantype = MULTI;
+    } 
+    else if(optget(opts, "multiscan")->enabled) scantype = MULTI;
+    else if(optget(opts, "allmatch")->enabled) scantype = ALLMATCH;
     else scantype = CONT;
 
     maxrec = optget(clamdopts, "MaxDirectoryRecursion")->numarg;
diff -Nru clamav-0.97.6+dfsg/clamdscan/client.h clamav-0.97.7+dfsg/clamdscan/client.h
--- clamav-0.97.6+dfsg/clamdscan/client.h	2012-05-15 14:34:22.000000000 -0400
+++ clamav-0.97.7+dfsg/clamdscan/client.h	2013-03-11 11:21:44.000000000 -0400
@@ -27,7 +27,9 @@
     CONT,
     MULTI,
     STREAM,
-    FILDES
+    FILDES,
+    ALLMATCH,
+    MAX_SCANTYPE = ALLMATCH
 };
 
 int client(const struct optstruct *opts, int *infected, int *err);
diff -Nru clamav-0.97.6+dfsg/clamdscan/proto.c clamav-0.97.7+dfsg/clamdscan/proto.c
--- clamav-0.97.6+dfsg/clamdscan/proto.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/clamdscan/proto.c	2013-03-11 11:23:20.000000000 -0400
@@ -58,7 +58,7 @@
 int printinfected;
 extern struct optstruct *clamdopts;
 
-static const char *scancmd[] = { "CONTSCAN", "MULTISCAN" };
+static const char *scancmd[] = { "CONTSCAN", "MULTISCAN", "INSTREAM", "FILDES", "ALLMATCHSCAN" };
 
 /* Connects to clamd 
  * Returns a FD or -1 on error */
@@ -202,6 +202,11 @@
     switch(scantype) {
     case MULTI:
     case CONT:
+    case ALLMATCH:
+    if (!filename) {
+	logg("Filename cannot be NULL for MULTISCAN or CONTSCAN.\n");
+	return -1;
+    }
     len = strlen(filename) + strlen(scancmd[scantype]) + 3;
     if (!(bol = malloc(len))) {
 	logg("!Cannot allocate a command buffer: %s\n", strerror(errno));
@@ -247,7 +252,13 @@
 		colon = strrchr(bol, ':');
 	    }
 	    if(!colon) {
-		logg("Failed to parse reply\n");
+		char * unkco = "UNKNOWN COMMAND";
+		if (!strncmp(bol, unkco, sizeof(unkco) - 1))
+		    logg("clamd replied \"UNKNOWN COMMAND\". Command was %s\n", 
+			 (scantype < 0 || scantype > MAX_SCANTYPE) ? "unidentified" :
+			                                             scancmd[scantype]);
+		else
+		    logg("Failed to parse reply: \"%s\"\n", bol);
 		return -1;
 	    } else if(!memcmp(eol - 7, " FOUND", 6)) {
 		*(eol - 7) = 0;
diff -Nru clamav-0.97.6+dfsg/clamscan/manager.c clamav-0.97.7+dfsg/clamscan/manager.c
--- clamav-0.97.6+dfsg/clamscan/manager.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/clamscan/manager.c	2013-03-11 11:23:20.000000000 -0400
@@ -125,6 +125,7 @@
 	int ret = 0, fd, included, printclean = 1;
 	const struct optstruct *opt;
 	const char *virname;
+        const char **virpp = &virname; 
 	struct stat sb;
 
     if((opt = optget(opts, "exclude"))->enabled) {
@@ -190,7 +191,16 @@
     }
 
     if((ret = cl_scandesc(fd, &virname, &info.blocks, engine, options)) == CL_VIRUS) {
-	logg("~%s: %s FOUND\n", filename, virname);
+        if (options & CL_SCAN_ALLMATCHES) {                                                                               
+	    int i = 0;
+	    virpp = (const char **)*virpp; /* temp hack for allscan until API enhancement */
+	    virname = virpp[0];
+	    while (virpp[i])
+		logg("~%s: %s FOUND\n", filename, virpp[i++]);
+	    free((void *)virpp);
+	}
+	else
+	    logg("~%s: %s FOUND\n", filename, virname);
 	info.files++;
 	info.ifiles++;
 
@@ -319,6 +329,8 @@
 	int ret;
 	unsigned int fsize = 0;
 	const char *virname, *tmpdir;
+	const char **virpp = &virname;
+
 	char *file, buff[FILEBUFF];
 	size_t bread;
 	FILE *fs;
@@ -358,7 +370,17 @@
     info.rblocks += fsize / CL_COUNT_PRECISION;
 
     if((ret = cl_scanfile(file, &virname, &info.blocks, engine, options)) == CL_VIRUS) {
-	logg("stdin: %s FOUND\n", virname);
+        if (options & CL_SCAN_ALLMATCHES) {
+            int i = 0;
+            virpp = (const char **)*virpp; /* temp hack for scanall mode until api augmentation */
+            virname = virpp[0];
+            while (virpp[i])
+                logg("stdin: %s FOUND\n", virpp[i++]);
+            free((void *)virpp);
+        }
+	else
+	    logg("stdin: %s FOUND\n", virname);
+
 	info.ifiles++;
 
 	if(bell)
@@ -587,6 +609,9 @@
     }
 
     /* set scan options */
+    if(optget(opts, "allmatch")->enabled)
+	options |= CL_SCAN_ALLMATCHES;
+
     if(optget(opts,"phishing-ssl")->enabled)
 	options |= CL_SCAN_PHISHING_BLOCKSSL;
 
diff -Nru clamav-0.97.6+dfsg/configure.in clamav-0.97.7+dfsg/configure.in
--- clamav-0.97.6+dfsg/configure.in	2012-08-10 12:03:00.000000000 -0400
+++ clamav-0.97.7+dfsg/configure.in	2013-03-11 11:23:20.000000000 -0400
@@ -20,7 +20,7 @@
 AC_PREREQ([2.59])
 dnl For a release change [devel] to the real version [0.xy]
 dnl also change VERSION below
-AC_INIT([ClamAV], [0.97.6], [http://bugs.clamav.net/], [clamav], [http://www.clamav.net/])
+AC_INIT([ClamAV], [0.97.7], [http://bugs.clamav.net/], [clamav], [http://www.clamav.net/])
 
 AH_BOTTOM([#include "platform.h"])
 dnl put configure auxiliary into config
@@ -43,10 +43,10 @@
 
 dnl change this on a release
 dnl VERSION="devel-`date +%Y%m%d`"
-VERSION="0.97.6"
+VERSION="0.97.7"
 
 LC_CURRENT=7
-LC_REVISION=15
+LC_REVISION=16
 LC_AGE=1
 LIBCLAMAV_VERSION="$LC_CURRENT":"$LC_REVISION":"$LC_AGE"
 AC_SUBST([LIBCLAMAV_VERSION])
diff -Nru clamav-0.97.6+dfsg/debian/changelog clamav-0.97.7+dfsg/debian/changelog
--- clamav-0.97.6+dfsg/debian/changelog	2013-03-18 22:36:11.000000000 -0400
+++ clamav-0.97.7+dfsg/debian/changelog	2013-03-18 22:36:12.000000000 -0400
@@ -1,3 +1,10 @@
+clamav (0.97.7+dfsg-1) unstable; urgency=medium
+
+  * New upstream release
+  * Urgency medium due to security fixes
+
+ -- Scott Kitterman <scott@kitterman.com>  Mon, 18 Mar 2013 22:28:02 -0400
+
 clamav (0.97.6+dfsg-1) unstable; urgency=low
 
   * New upstream release (Closes: #689487)
diff -Nru clamav-0.97.6+dfsg/libclamav/blob.c clamav-0.97.7+dfsg/libclamav/blob.c
--- clamav-0.97.6+dfsg/libclamav/blob.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/blob.c	2013-03-11 11:23:20.000000000 -0400
@@ -575,7 +575,7 @@
 				fb->bytes_scanned += (unsigned long)len;
 				
 				if((len > 5) && cli_updatelimits(ctx, len)==CL_CLEAN && (cli_scanbuff(data, (unsigned int)len, 0, ctx->virname, ctx->engine, CL_TYPE_BINARY_DATA, NULL) == CL_VIRUS)) {
-					cli_dbgmsg("fileblobAddData: found %s\n", *ctx->virname);
+				    cli_dbgmsg("fileblobAddData: found %s\n", cli_get_last_virus_str(ctx));
 					fb->isInfected = 1;
 				}
 			}
diff -Nru clamav-0.97.6+dfsg/libclamav/bytecode_api.c clamav-0.97.7+dfsg/libclamav/bytecode_api.c
--- clamav-0.97.6+dfsg/libclamav/bytecode_api.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/bytecode_api.c	2013-03-11 11:23:20.000000000 -0400
@@ -511,8 +511,7 @@
 	cctx->recursion--;
 	cctx->container_type = current;
 	if (res == CL_VIRUS) {
-	    if (cctx->virname)
-		ctx->virname = *cctx->virname;
+	    ctx->virname = cli_get_last_virus(cctx);
 	    ctx->found = 1;
 	}
     }
diff -Nru clamav-0.97.6+dfsg/libclamav/bytecode.c clamav-0.97.7+dfsg/libclamav/bytecode.c
--- clamav-0.97.6+dfsg/libclamav/bytecode.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/bytecode.c	2013-03-11 11:23:20.000000000 -0400
@@ -2571,7 +2571,7 @@
 
 int cli_bytecode_runlsig(cli_ctx *cctx, struct cli_target_info *tinfo,
 			 const struct cli_all_bc *bcs, unsigned bc_idx,
-			 const char **virname, const uint32_t* lsigcnt,
+			 const uint32_t* lsigcnt,
 			 const uint32_t *lsigsuboff, fmap_t *map)
 {
     int ret;
@@ -2618,9 +2618,8 @@
     if (ctx.virname) {
 	int rc;
 	cli_dbgmsg("Bytecode found virus: %s\n", ctx.virname);
-	if (virname)
-	    *virname = ctx.virname;
-	if (!strncmp(*virname, "BC.Heuristics", 13))
+	cli_append_virus(cctx, ctx.virname);
+	if (!strncmp(ctx.virname, "BC.Heuristics", 13))
 	    rc = cli_found_possibly_unwanted(cctx);
 	else
 	    rc = CL_VIRUS;
@@ -2634,7 +2633,7 @@
 }
 
 int cli_bytecode_runhook(cli_ctx *cctx, const struct cl_engine *engine, struct cli_bc_ctx *ctx,
-			 unsigned id, fmap_t *map, const char **virname)
+			 unsigned id, fmap_t *map)
 {
     const unsigned *hooks = engine->hooks[id - _BC_START_HOOKS];
     unsigned i, hooks_cnt = engine->hooks_cnt[id - _BC_START_HOOKS];
@@ -2664,10 +2663,13 @@
 	}
 	if (ctx->virname) {
 	    cli_dbgmsg("Bytecode found virus: %s\n", ctx->virname);
-	    if (virname)
-		*virname = ctx->virname;
-	    cli_bytecode_context_clear(ctx);
-	    return CL_VIRUS;
+	    cli_append_virus(cctx, ctx->virname);
+	    if (!(cctx->options & CL_SCAN_ALLMATCHES)) {
+		cli_bytecode_context_clear(ctx);
+		return CL_VIRUS;
+	    }
+	    cli_bytecode_context_reset(ctx);
+	    continue;
 	}
 	ret = cli_bytecode_context_getresult_int(ctx);
 	/* TODO: use prefix here */
@@ -2700,10 +2702,15 @@
 		}
 		free(tempfile);
 		if (ret != CL_CLEAN) {
-		    if (ret == CL_VIRUS)
+		    if (ret == CL_VIRUS) {
 			cli_dbgmsg("Scanning unpacked file by bytecode %u found a virus\n", bc->id);
-		    cli_bytecode_context_clear(ctx);
-		    return ret;
+			if (cctx->options & CL_SCAN_ALLMATCHES) {
+			    cli_bytecode_context_reset(ctx);
+			    continue;
+			}
+			cli_bytecode_context_clear(ctx);
+		    	return ret;
+		    }
 		}
 		cli_bytecode_context_reset(ctx);
 		continue;
diff -Nru clamav-0.97.6+dfsg/libclamav/bytecode.h clamav-0.97.7+dfsg/libclamav/bytecode.h
--- clamav-0.97.6+dfsg/libclamav/bytecode.h	2012-05-15 14:34:22.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/bytecode.h	2013-03-11 11:23:20.000000000 -0400
@@ -118,8 +118,8 @@
 struct cli_exe_info;
 struct cli_ctx_tag;
 struct cli_target_info;
-int cli_bytecode_runlsig(struct cli_ctx_tag *ctx, struct cli_target_info *info, const struct cli_all_bc *bcs, unsigned bc_idx, const char **virname, const uint32_t* lsigcnt, const uint32_t *lsigsuboff, fmap_t *map);
-int cli_bytecode_runhook(struct cli_ctx_tag *cctx, const struct cl_engine *engine, struct cli_bc_ctx *ctx, unsigned id, fmap_t *map, const char **virname);
+int cli_bytecode_runlsig(struct cli_ctx_tag *ctx, struct cli_target_info *info, const struct cli_all_bc *bcs, unsigned bc_idx, const uint32_t* lsigcnt, const uint32_t *lsigsuboff, fmap_t *map);
+int cli_bytecode_runhook(struct cli_ctx_tag *cctx, const struct cl_engine *engine, struct cli_bc_ctx *ctx, unsigned id, fmap_t *map);
 
 #ifdef __cplusplus
 extern "C" {
diff -Nru clamav-0.97.6+dfsg/libclamav/clamav.h clamav-0.97.7+dfsg/libclamav/clamav.h
--- clamav-0.97.6+dfsg/libclamav/clamav.h	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/clamav.h	2013-03-11 11:23:21.000000000 -0400
@@ -119,6 +119,7 @@
 #define CL_SCAN_PARTIAL_MESSAGE         0x40000
 #define CL_SCAN_HEURISTIC_PRECEDENCE    0x80000
 #define CL_SCAN_BLOCKMACROS		0x100000
+#define CL_SCAN_ALLMATCHES		0x200000
 
 #define CL_SCAN_INTERNAL_COLLECT_SHA    0x80000000 /* Enables hash output in sha-collect builds - for internal use only */
 
diff -Nru clamav-0.97.6+dfsg/libclamav/elf.c clamav-0.97.7+dfsg/libclamav/elf.c
--- clamav-0.97.6+dfsg/libclamav/elf.c	2012-06-12 09:03:27.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/elf.c	2013-03-11 11:21:48.000000000 -0400
@@ -73,7 +73,7 @@
 	uint8_t conv = 0, err;
 	unsigned int format;
 	fmap_t *map = *ctx->fmap;
-
+	uint32_t viruses_found = 0;
 
     cli_dbgmsg("in cli_scanelf\n");
 
@@ -214,8 +214,7 @@
     if(phnum > 128) {
 	cli_dbgmsg("ELF: Suspicious number of program headers\n");
         if(DETECT_BROKEN) {
-	    if(ctx->virname)
-		*ctx->virname = "Heuristics.Broken.Executable";
+	    cli_append_virus(ctx, "Heuristics.Broken.Executable");
 	    return CL_VIRUS;
         }
 	return CL_EFORMAT;
@@ -227,8 +226,7 @@
 	if(phentsize != sizeof(struct elf_program_hdr32)) {
 	    cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr32)\n");
 	    if(DETECT_BROKEN) {
-		if(ctx->virname)
-		    *ctx->virname = "Heuristics.Broken.Executable";
+		cli_append_virus(ctx, "Heuristics.Broken.Executable");
 		return CL_VIRUS;
 	    }
 	    return CL_EFORMAT;
@@ -275,8 +273,7 @@
 		cli_dbgmsg("ELF: Possibly broken ELF file\n");
 		free(program_hdr);
 		if(DETECT_BROKEN) {
-		    if(ctx->virname)
-			*ctx->virname = "Heuristics.Broken.Executable";
+		    cli_append_virus(ctx, "Heuristics.Broken.Executable");
 		    return CL_VIRUS;
 		}
 		return CL_CLEAN;
@@ -296,8 +293,7 @@
 	if(err) {
 	    cli_dbgmsg("ELF: Can't calculate file offset of entry point\n");
 	    if(DETECT_BROKEN) {
-		if(ctx->virname)
-		    *ctx->virname = "Heuristics.Broken.Executable";
+                cli_append_virus(ctx, "Heuristics.Broken.Executable");
 		return CL_VIRUS;
 	    }
 	    return CL_EFORMAT;
@@ -319,8 +315,7 @@
     if(shentsize != sizeof(struct elf_section_hdr32)) {
 	cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr32)\n");
         if(DETECT_BROKEN) {
-	    if(ctx->virname)
-		*ctx->virname = "Heuristics.Broken.Executable";
+	    cli_append_virus(ctx, "Heuristics.Broken.Executable");
 	    return CL_VIRUS;
         }
 	return CL_EFORMAT;
@@ -369,8 +364,7 @@
             cli_dbgmsg("ELF: Possibly broken ELF file\n");
             free(section_hdr);
             if(DETECT_BROKEN) {
-                if(ctx->virname)
-                    *ctx->virname = "Heuristics.Broken.Executable";
+                cli_append_virus(ctx, "Heuristics.Broken.Executable");
 		return CL_VIRUS;
             }
             return CL_CLEAN;
diff -Nru clamav-0.97.6+dfsg/libclamav/macho.c clamav-0.97.7+dfsg/libclamav/macho.c
--- clamav-0.97.6+dfsg/libclamav/macho.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/macho.c	2013-03-11 11:23:21.000000000 -0400
@@ -174,8 +174,7 @@
     if(matcher)						    \
 	return -1;					    \
     if(DETECT_BROKEN) {					    \
-	if(ctx->virname)				    \
-	    *ctx->virname = "Heuristics.Broken.Executable"; \
+	cli_append_virus(ctx, "Heuristics.Broken.Executable"); \
 	return CL_VIRUS;				    \
     }							    \
     return CL_EFORMAT
diff -Nru clamav-0.97.6+dfsg/libclamav/matcher-ac.c clamav-0.97.7+dfsg/libclamav/matcher-ac.c
--- clamav-0.97.6+dfsg/libclamav/matcher-ac.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/matcher-ac.c	2013-03-11 11:23:21.000000000 -0400
@@ -1145,7 +1145,7 @@
 }
 
 
-int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int mode, const cli_ctx *ctx)
+int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int mode, cli_ctx *ctx)
 {
 	struct cli_ac_node *current;
 	struct cli_ac_patt *patt, *pt, *faillist;
@@ -1355,11 +1355,18 @@
 					pt = pt->next_same;
 					continue;
 				    } else {
-					if(virname)
-					    *virname = pt->virname;
+					if(virname) {
+					    if (ctx && SCAN_ALL && virname == ctx->virname)
+						cli_append_virus(ctx, (const char *)pt->virname);
+					    else
+						*virname = pt->virname;
+					}
 					if(customdata)
 					    *customdata = pt->customdata;
-					return CL_VIRUS;
+					if (!ctx || !SCAN_ALL)
+					    return CL_VIRUS;
+					pt = pt->next_same;
+					continue;
 				    }
 				}
 			    }
@@ -1398,11 +1405,18 @@
 				    pt = pt->next_same;
 				    continue;
 				} else {
-				    if(virname)
-					*virname = pt->virname;
+				    if(virname) {
+					if (ctx && SCAN_ALL && virname == ctx->virname)
+					    cli_append_virus(ctx, pt->virname);
+					else
+					    *virname = pt->virname;
+				    }
 				    if(customdata)
 					*customdata = pt->customdata;
-				    return CL_VIRUS;
+				    if (!ctx || !SCAN_ALL)
+					return CL_VIRUS;
+				    pt = pt->next_same;
+				    continue;
 				}
 			    }
 			}
diff -Nru clamav-0.97.6+dfsg/libclamav/matcher-ac.h clamav-0.97.7+dfsg/libclamav/matcher-ac.h
--- clamav-0.97.6+dfsg/libclamav/matcher-ac.h	2012-06-12 09:03:27.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/matcher-ac.h	2013-03-11 11:21:48.000000000 -0400
@@ -93,7 +93,7 @@
 void cli_ac_chkmacro(struct cli_matcher *root, struct cli_ac_data *data, unsigned lsigid1);
 int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigned int *cnt, uint64_t *ids, unsigned int parse_only);
 void cli_ac_freedata(struct cli_ac_data *data);
-int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int mode, const cli_ctx *ctx);
+int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int mode, cli_ctx *ctx);
 int cli_ac_buildtrie(struct cli_matcher *root);
 int cli_ac_init(struct cli_matcher *root, uint8_t mindepth, uint8_t maxdepth, uint8_t dconf_prefiltering);
 int cli_ac_caloff(const struct cli_matcher *root, struct cli_ac_data *data, const struct cli_target_info *info);
diff -Nru clamav-0.97.6+dfsg/libclamav/matcher-bm.c clamav-0.97.7+dfsg/libclamav/matcher-bm.c
--- clamav-0.97.6+dfsg/libclamav/matcher-bm.c	2012-06-12 09:03:27.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/matcher-bm.c	2013-03-11 11:21:48.000000000 -0400
@@ -244,7 +244,7 @@
     }
 }
 
-int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, const struct cli_target_info *info, struct cli_bm_off *offdata)
+int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, const struct cli_target_info *info, struct cli_bm_off *offdata, uint32_t *viroffset)
 {
 	uint32_t i, j, off, off_min, off_max;
 	uint8_t found, pchain, shift;
@@ -374,8 +374,11 @@
 			    continue;
 			}
 		    }
-		    if(virname)
+		    if(virname) {
 			*virname = p->virname;
+			if(viroffset)
+			    *viroffset = offset + i + j - BM_MIN_LENGTH + BM_BLOCK_SIZE;
+		    }
 		    if(patt)
 			*patt = p;
 		    return CL_VIRUS;
diff -Nru clamav-0.97.6+dfsg/libclamav/matcher-bm.h clamav-0.97.7+dfsg/libclamav/matcher-bm.h
--- clamav-0.97.6+dfsg/libclamav/matcher-bm.h	2012-05-15 14:34:23.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/matcher-bm.h	2013-03-11 11:21:48.000000000 -0400
@@ -47,7 +47,7 @@
 int cli_bm_init(struct cli_matcher *root);
 int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, const struct cli_target_info *info);
 void cli_bm_freeoff(struct cli_bm_off *data);
-int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, const struct cli_target_info *info, struct cli_bm_off *offdata);
+int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, const struct cli_target_info *info, struct cli_bm_off *offdata, uint32_t *viroffset);
 void cli_bm_free(struct cli_matcher *root);
 
 #endif
diff -Nru clamav-0.97.6+dfsg/libclamav/matcher.c clamav-0.97.7+dfsg/libclamav/matcher.c
--- clamav-0.97.6+dfsg/libclamav/matcher.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/matcher.c	2013-03-11 11:23:21.000000000 -0400
@@ -91,13 +91,16 @@
 			      unsigned int acmode,
 			      struct cli_ac_result **acres,
 			      fmap_t *map,
-			      struct cli_bm_off *offdata)
+			      struct cli_bm_off *offdata,
+			      uint32_t *viroffset,
+			      cli_ctx *ctx)
 {
     int ret;
     int32_t pos = 0;
     struct filter_match_info info;
     uint32_t orig_length, orig_offset;
     const unsigned char* orig_buffer;
+    unsigned int viruses_found = 0;
 
     if (root->filter) {
 	if(filter_search_ext(root->filter, buffer, length, &info) == -1) {
@@ -128,15 +131,28 @@
 	    /* Don't use prefiltering for BM offset mode, since BM keeps tracks
 	     * of offsets itself, and doesn't work if we skip chunks of input
 	     * data */
-	    ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata);
+	    ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata, viroffset);
 	} else {
-	    ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata);
+	    ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata, viroffset);
+	}
+	if (ret == CL_VIRUS) {
+	    if (ctx) {
+		cli_append_virus(ctx, *virname);
+		if (SCAN_ALL)
+		    viruses_found++;
+		else
+		    return ret;
+	    }
 	}
-	if (ret == CL_VIRUS)
-	    return ret;
     }
     PERF_LOG_TRIES(acmode, 0, length);
     ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, NULL);
+
+    if (ctx && ret == CL_VIRUS)
+	cli_append_virus(ctx, *virname);
+    if (ctx && SCAN_ALL && viruses_found)
+	return CL_VIRUS;
+
     return ret;
 }
 
@@ -146,7 +162,7 @@
 	unsigned int i;
 	struct cli_ac_data mdata;
 	struct cli_matcher *groot, *troot = NULL;
-	const char **virname=ctx->virname;
+	const char *virname = NULL;
 	const struct cl_engine *engine=ctx->engine;
 
     if(!engine) {
@@ -170,7 +186,7 @@
 	if(!acdata && (ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
 	    return ret;
 
-	ret = matcher_run(troot, buffer, length, virname, acdata ? (acdata[0]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL);
+	ret = matcher_run(troot, buffer, length, &virname, acdata ? (acdata[0]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL, NULL, ctx);
 
 	if(!acdata)
 	    cli_ac_freedata(&mdata);
@@ -179,10 +195,12 @@
 	    return ret;
     }
 
+    virname = NULL;
+
     if(!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
 	return ret;
 
-    ret = matcher_run(groot, buffer, length, virname, acdata ? (acdata[1]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL);
+    ret = matcher_run(groot, buffer, length, &virname, acdata ? (acdata[1]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL, NULL, ctx);
 
     if(!acdata)
 	cli_ac_freedata(&mdata);
@@ -396,7 +414,7 @@
     for(i = 0; i < 16; i++)
 	sprintf(md5 + i * 2, "%02x", digest[i]);
     md5[32] = 0;
-    cli_dbgmsg("FP SIGNATURE: %s:%u:%s\n", md5, (unsigned int) size, *ctx->virname ? *ctx->virname : "Name");
+    cli_dbgmsg("FP SIGNATURE: %s:%u:%s\n", md5, (unsigned int) size, cli_get_last_virus(ctx) ? cli_get_last_virus(ctx) : "Name");
 
     map = *ctx->fmap;
     have_sha1 = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, size);
@@ -442,7 +460,7 @@
             for(i=0; i<SHA1_HASH_SIZE; i++)
                 sprintf((char *)shash1+i*2, "%02x", shash1[SHA1_HASH_SIZE+i]);
 
-	    cli_errmsg("COLLECT:%s:%s:%u:%s:%s\n", shash256, shash1, size, *ctx->virname, ctx->entry_filename);
+	    cli_errmsg("COLLECT:%s:%s:%u:%s:%s\n", shash256, shash1, size, cli_get_last_virus(ctx), ctx->entry_filename);
         } else
             cli_errmsg("can't compute sha\n!");
         ctx->sha_collect = -1;
@@ -450,7 +468,7 @@
 #endif
 
     if (ctx->engine->cb_hash)
-	ctx->engine->cb_hash(ctx->fmap[0]->fd, size, md5, ctx->virname ? *ctx->virname : NULL, ctx->cb_ctx);
+	ctx->engine->cb_hash(ctx->fmap[0]->fd, size, md5, cli_get_last_virus(ctx), ctx->cb_ctx);
 
     return CL_VIRUS;
 }
@@ -535,6 +553,7 @@
 	unsigned int i, evalcnt;
 	uint64_t evalids;
 	fmap_t *map = *ctx->fmap;
+	unsigned int viruses_found = 0;
 
     for(i = 0; i < root->ac_lsigs; i++) {
 	evalcnt = 0;
@@ -561,6 +580,10 @@
 		    memcpy(ctx->handlertype_hash, hash, 16);
 		    if(cli_magic_scandesc_type(map->fd, ctx, root->ac_lsigtable[i]->tdb.handlertype[0]) == CL_VIRUS) {
 			ctx->recursion--;
+			if (SCAN_ALL) {
+			    viruses_found++;
+			    continue;
+			}
 			return CL_VIRUS;
 		    }
 		    ctx->recursion--;
@@ -573,25 +596,41 @@
 		    continue;
 		if(matchicon(ctx, &target_info->exeinfo, root->ac_lsigtable[i]->tdb.icongrp1, root->ac_lsigtable[i]->tdb.icongrp2) == CL_VIRUS) {
 		    if(!root->ac_lsigtable[i]->bc_idx) {
-			if(ctx->virname)
-			    *ctx->virname = root->ac_lsigtable[i]->virname;
+			cli_append_virus(ctx, root->ac_lsigtable[i]->virname);
+			if (SCAN_ALL) {
+                            viruses_found++;
+                            continue;
+                        }
 			return CL_VIRUS;
-		    } else if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, ctx->virname, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
+		    } else if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
+			if (SCAN_ALL) {
+                            viruses_found++;
+                            continue;
+                        }
 			return CL_VIRUS;
 		    }
 		}
 		continue;
 	    }
 	    if(!root->ac_lsigtable[i]->bc_idx) {
-		if(ctx->virname)
-		    *ctx->virname = root->ac_lsigtable[i]->virname;
-		return CL_VIRUS;
+		cli_append_virus(ctx, root->ac_lsigtable[i]->virname);
+		if (SCAN_ALL) {
+		    viruses_found++;
+		    continue;
+		}
+ 		return CL_VIRUS;
 	    }
-	    if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, ctx->virname, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
-		return CL_VIRUS;
+	    if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
+		if (SCAN_ALL) {
+		    viruses_found++;
+		    continue;
+		}
+ 		return CL_VIRUS;
 	    }
 	}
     }
+    if (SCAN_ALL && viruses_found)
+	return CL_VIRUS;
     return CL_CLEAN;
 }
 
@@ -611,6 +650,9 @@
 	struct cli_target_info info;
 	fmap_t *map = *ctx->fmap;
 	struct cli_matcher *hdb, *fp;
+	const char *virname = NULL;
+	uint32_t viroffset = 0;
+	uint32_t viruses_found = 0;
 
     if(!ctx->engine) {
 	cli_errmsg("cli_scandesc: engine == NULL\n");
@@ -712,9 +754,14 @@
 	    *ctx->scanned += bytes / CL_COUNT_PRECISION;
 
 	if(troot) {
-	    ret = matcher_run(troot, buff, bytes, ctx->virname, &tdata, offset, &info, ftype, ftoffset, acmode, acres, map, bm_offmode ? &toff : NULL);
+            virname = NULL;
+            viroffset = 0;
+	    ret = matcher_run(troot, buff, bytes, &virname, &tdata, offset, &info, ftype, ftoffset, acmode, acres, map, bm_offmode ? &toff : NULL, &viroffset, ctx);
 
-	    if(ret == CL_VIRUS || ret == CL_EMEM) {
+	    if (virname) {
+		viruses_found++;
+	    }
+	    if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
 		if(!ftonly)
 		    cli_ac_freedata(&gdata);
 		cli_ac_freedata(&tdata);
@@ -728,9 +775,14 @@
 	}
 
 	if(!ftonly) {
-	    ret = matcher_run(groot, buff, bytes, ctx->virname, &gdata, offset, &info, ftype, ftoffset, acmode, acres, map, NULL);
+	    virname = NULL;
+	    viroffset = 0;
+	    ret = matcher_run(groot, buff, bytes, &virname, &gdata, offset, &info, ftype, ftoffset, acmode, acres, map, NULL, &viroffset, ctx);
 
-	    if(ret == CL_VIRUS || ret == CL_EMEM) {
+            if (virname) {
+		viruses_found++;
+	    }
+	    if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
 		cli_ac_freedata(&gdata);
 		if(troot) {
 		    cli_ac_freedata(&tdata);
@@ -746,8 +798,8 @@
 		    type = ret;
 	    }
 
-	    if(hdb) {
-		void *data = buff + maxpatlen * (offset!=0);
+	    if(hdb && !SCAN_ALL) {
+		const void *data = buff + maxpatlen * (offset!=0);
 		uint32_t data_len = bytes - maxpatlen * (offset!=0);
 
 		if(compute_hash[CLI_HASH_MD5])
@@ -759,12 +811,16 @@
 	    }
 	}
 
+	if(SCAN_ALL && viroffset) {
+	    offset = viroffset;
+	    continue;
+	}
 	if(bytes < SCANBUFF) break;
 	offset += bytes - maxpatlen;
     }
 
     if(!ftonly && hdb) {
-	enum CLI_HASH_TYPE hashtype;
+	enum CLI_HASH_TYPE hashtype, hashtype2;
 
 	if(compute_hash[CLI_HASH_MD5])
 	    cli_md5_final(digest[CLI_HASH_MD5], &md5ctx);
@@ -775,31 +831,42 @@
 	if(compute_hash[CLI_HASH_SHA256])
 	    sha256_final(&sha256ctx, digest[CLI_HASH_SHA256]);
 
+	virname = NULL;
 	for(hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) {
-	    if(compute_hash[hashtype] && (ret = cli_hm_scan(digest[hashtype], map->len, ctx->virname, hdb, hashtype)) == CL_VIRUS)
-		break;
-	}
-
-	if(ret == CL_VIRUS && fp) {
-	    for(hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) {
-		if(compute_hash[hashtype] && cli_hm_scan(digest[hashtype], map->len, ctx->virname, fp, hashtype) == CL_VIRUS) {
-		    ret = CL_CLEAN;
-		    break;
+	    if(compute_hash[hashtype] &&
+	       (ret = cli_hm_scan(digest[hashtype], map->len, &virname, hdb, hashtype)) == CL_VIRUS) {
+		if(fp) {
+		    for(hashtype2 = CLI_HASH_MD5; hashtype2 < CLI_HASH_AVAIL_TYPES; hashtype2++) {
+			if(compute_hash[hashtype2] &&
+			   cli_hm_scan(digest[hashtype2], map->len, NULL, fp, hashtype2) == CL_VIRUS) {
+			    ret = CL_CLEAN;
+			    break;
+			}
+		    }
 		}
+		if (ret == CL_VIRUS) {
+		    viruses_found++;
+		    cli_append_virus(ctx, virname);
+		    if (!SCAN_ALL)
+			break;
+		}
+		virname = NULL;
 	    }
 	}
     }
 
     if(troot) {
-	if(ret != CL_VIRUS)
+	if(ret != CL_VIRUS || SCAN_ALL)
 	    ret = cli_lsig_eval(ctx, troot, &tdata, &info, refhash);
+	if (ret == CL_VIRUS)
+	    viruses_found++;
 	cli_ac_freedata(&tdata);
 	if(bm_offmode)
 	    cli_bm_freeoff(&toff);
     }
 
     if(groot) {
-	if(ret != CL_VIRUS)
+	if(ret != CL_VIRUS || SCAN_ALL)
 	    ret = cli_lsig_eval(ctx, groot, &gdata, &info, refhash);
 	cli_ac_freedata(&gdata);
     }
@@ -808,6 +875,8 @@
 	free(info.exeinfo.section);
     cli_hashset_destroy(&info.exeinfo.vinfo);
 
+    if (SCAN_ALL && viruses_found)
+	return CL_VIRUS;
     if(ret == CL_VIRUS)
 	return CL_VIRUS;
 
@@ -817,6 +886,7 @@
 int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer, int encrypted, unsigned int filepos, int res1, void *res2)
 {
 	const struct cli_cdb *cdb;
+	unsigned int viruses_found = 0;
 
     if(!(cdb = ctx->engine->cdb))
 	return CL_CLEAN;
@@ -848,10 +918,14 @@
 	if(cdb->name.re_magic && (!fname || cli_regexec(&cdb->name, fname, 0, NULL, 0) == REG_NOMATCH))
 	    continue;
 
-	*ctx->virname = cdb->virname;
-	return CL_VIRUS;
+	cli_append_virus(ctx, cdb->virname);
+	viruses_found++;
+	if(!SCAN_ALL)
+	    return CL_VIRUS;
 
     } while((cdb = cdb->next));
 
+    if (SCAN_ALL && viruses_found)
+	return CL_VIRUS;
     return CL_CLEAN;
 }
diff -Nru clamav-0.97.6+dfsg/libclamav/mbox.c clamav-0.97.7+dfsg/libclamav/mbox.c
--- clamav-0.97.6+dfsg/libclamav/mbox.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/mbox.c	2013-03-11 11:23:21.000000000 -0400
@@ -544,10 +544,11 @@
 		messageDestroy(body);
 	}
 
-	if((retcode == CL_CLEAN) && ctx->found_possibly_unwanted && (*ctx->virname == NULL)) {
-		*ctx->virname = "Heuristics.Phishing.Email";
-		ctx->found_possibly_unwanted = 0;
-		retcode = CL_VIRUS;
+	if((retcode == CL_CLEAN) && ctx->found_possibly_unwanted &&
+	   (*ctx->virname == NULL || SCAN_ALL)) {
+	    cli_append_virus(ctx, "Heuristics.Phishing.Email");
+	    ctx->found_possibly_unwanted = 0;
+	    retcode = CL_VIRUS;
 	}
 
 	cli_dbgmsg("cli_mbox returning %d\n", retcode);
diff -Nru clamav-0.97.6+dfsg/libclamav/others.c clamav-0.97.7+dfsg/libclamav/others.c
--- clamav-0.97.6+dfsg/libclamav/others.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/others.c	2013-03-11 11:23:21.000000000 -0400
@@ -752,6 +752,51 @@
 	return 0;
 }
 
+void cli_append_virus(cli_ctx * ctx, const char * virname)
+{
+    if (!ctx->virname)
+	return;
+    if (SCAN_ALL) {
+	if (ctx->size_viruses == 0) {
+	    ctx->size_viruses = 2;
+	    if (!(ctx->virname = malloc(ctx->size_viruses * sizeof(char *)))) {
+		cli_errmsg("cli_append_virus: fails on malloc() - virus %s virname not appended.\n", virname);
+		return;
+	    }
+	} else if (ctx->num_viruses+1 == ctx->size_viruses) {
+	    ctx->size_viruses *= 2;
+	    if ((ctx->virname = realloc((void *)ctx->virname, ctx->size_viruses * sizeof (char *))) == NULL) {
+		cli_errmsg("cli_append_virus: fails on realloc() - virus %s virname not appended.\n", virname);
+		return;
+	    }
+	}
+	ctx->virname[ctx->num_viruses++] = virname;
+	ctx->virname[ctx->num_viruses] = NULL;
+    }
+    else
+	*ctx->virname = virname;
+}
+
+const char * cli_get_last_virus(const cli_ctx * ctx)
+{
+    if (!ctx || !ctx->virname || !(*ctx->virname))
+	return NULL;
+
+    if (SCAN_ALL && ctx->num_viruses)
+	return ctx->virname[ctx->num_viruses-1];
+    else
+	return *ctx->virname;
+}
+
+const char * cli_get_last_virus_str(const cli_ctx * ctx)
+{
+    const char * ret;
+    if ((ret = cli_get_last_virus(ctx)))
+	return ret;
+    return "";
+}
+
+
 #ifdef	C_WINDOWS
 /*
  * Windows doesn't allow you to delete a directory while it is still open
@@ -955,7 +1000,7 @@
     cli_dbgmsg("DUMP&SCAN: File extracted to %s\n", name);
     lseek(newfd, 0, SEEK_SET);
     if((ret = cli_magic_scandesc(newfd, ctx)) == CL_VIRUS)
-	cli_dbgmsg("cli_dumpscan: Infected with %s\n", *ctx->virname);
+	cli_dbgmsg("cli_dumpscan: Infected with %s\n", cli_get_last_virus_str(ctx));
 
     close(newfd);
     if(!ctx->engine->keeptmp) {
diff -Nru clamav-0.97.6+dfsg/libclamav/others.h clamav-0.97.7+dfsg/libclamav/others.h
--- clamav-0.97.6+dfsg/libclamav/others.h	2012-08-10 12:02:00.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/others.h	2013-03-11 11:23:21.000000000 -0400
@@ -53,7 +53,7 @@
  * in re-enabling affected modules.
  */
 
-#define CL_FLEVEL 67
+#define CL_FLEVEL 68
 #define CL_FLEVEL_DCONF	CL_FLEVEL
 #define CL_FLEVEL_SIGTOOL CL_FLEVEL
 
@@ -109,6 +109,8 @@
 /* internal clamav context */
 typedef struct cli_ctx_tag {
     const char **virname;
+    unsigned int num_viruses;         /* manages virname when CL_SCAN_ALLMATCHES == 1 */
+    unsigned int size_viruses;        /* manages virname when CL_SCAN_ALLMATCHES == 1 */
     unsigned long int *scanned;
     const struct cli_matcher *root;
     const struct cl_engine *engine;
@@ -314,6 +316,7 @@
 #define DETECT_BROKEN	    (ctx->options & CL_SCAN_BLOCKBROKEN)
 #define BLOCK_MACROS	    (ctx->options & CL_SCAN_BLOCKMACROS)
 #define SCAN_STRUCTURED	    (ctx->options & CL_SCAN_STRUCTURED)
+#define SCAN_ALL            (ctx->options & CL_SCAN_ALLMATCHES)
 
 /* based on macros from A. Melnikoff */
 #define cbswap16(v) (((v & 0xff) << 8) | (((v) >> 8) & 0xff))
@@ -412,6 +415,10 @@
 }
 #endif
 
+void cli_append_virus(cli_ctx *ctx, const char *virname);
+const char *cli_get_last_virus(const cli_ctx *ctx);
+const char *cli_get_last_virus_str(const cli_ctx *ctx);
+
 /* used by: spin, yc (C) aCaB */
 #define __SHIFTBITS(a) (sizeof(a)<<3)
 #define __SHIFTMASK(a) (__SHIFTBITS(a)-1)
diff -Nru clamav-0.97.6+dfsg/libclamav/pdf.c clamav-0.97.7+dfsg/libclamav/pdf.c
--- clamav-0.97.6+dfsg/libclamav/pdf.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/pdf.c	2013-03-11 11:23:21.000000000 -0400
@@ -550,7 +550,7 @@
     cli_bytecode_context_setpdf(bc_ctx, phase, pdf->nobjs, pdf->objs,
 				&pdf->flags, pdf->size, pdf->startoff);
     cli_bytecode_context_setctx(bc_ctx, ctx);
-    ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PDF, map, ctx->virname);
+    ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PDF, map);
     cli_bytecode_context_destroy(bc_ctx);
     if (fd != -1) {
 	funmap(map);
@@ -876,6 +876,17 @@
 static char *pdf_readstring(const char *q0, int len, const char *key, unsigned *slen);
 static int pdf_readint(const char *q0, int len, const char *key);
 static const char *pdf_getdict(const char *q0, int* len, const char *key);
+
+static void pdf_parse_trailer(struct pdf_struct *pdf, const char *s, long length)
+{
+    char *newID;
+    newID = pdf_readstring(s, length, "/ID", &pdf->fileIDlen);
+    if (newID) {
+        free(pdf->fileID);
+        pdf->fileID = newID;
+    }
+}
+
 static void pdf_parseobj(struct pdf_struct *pdf, struct pdf_obj *obj)
 {
     /* enough to hold common pdf names, we don't need all the names */
@@ -960,9 +971,9 @@
 		if (trailer < 0) trailer = 0;
 		q2 = pdf->map + trailer;
 		cli_dbgmsg("cli_pdf: looking for trailer in linearized pdf: %ld - %ld\n", trailer, trailer_end);
-		pdf->fileID = pdf_readstring(q2, trailer_end - trailer, "/ID", &pdf->fileIDlen);
+		pdf_parse_trailer(pdf, q2, trailer_end - trailer);
 		if (pdf->fileID)
-		    cli_dbgmsg("found fileID\n");
+		    cli_dbgmsg("cli_pdf: found fileID\n");
 	    }
 	}
 	if (objstate == STATE_LAUNCHACTION)
@@ -1281,7 +1292,7 @@
 	if (!pdf->key)
 	    return;
 	memcpy(pdf->key, result, pdf->keylen);
-	dbg_printhex("md5", result, 32);
+	dbg_printhex("md5", result, 16);
 	dbg_printhex("Candidate encryption key", pdf->key, pdf->keylen);
 
 	/* 7.6.3.3 Algorithm 6 */
@@ -1521,7 +1532,7 @@
 		pdf.flags |= 1 << ENCRYPTED_PDF;
 		cli_dbgmsg("cli_pdf: encrypted pdf found, stream will probably fail to decompress!\n");
 		pdf_parse_encrypt(&pdf, enc, eof - enc);
-		pdf.fileID = pdf_readstring(eofmap, bytesleft, "/ID", &pdf.fileIDlen);
+		pdf_parse_trailer(&pdf, eofmap, bytesleft);
 	    }
 	    q += 9;
 	    while (q < eof && (*q == ' ' || *q == '\n' || *q == '\r')) { q++; }
@@ -1553,7 +1564,7 @@
     /* parse PDF and find obj offsets */
     while ((rc = pdf_findobj(&pdf)) > 0) {
 	struct pdf_obj *obj = &pdf.objs[pdf.nobjs-1];
-	cli_dbgmsg("found %d %d obj @%ld\n", obj->id >> 8, obj->id&0xff, obj->start + offset);
+	cli_dbgmsg("cli_pdf: found %d %d obj @%ld\n", obj->id >> 8, obj->id&0xff, obj->start + offset);
     }
     if (pdf.nobjs)
 	pdf.nobjs--;
@@ -1574,7 +1585,7 @@
 	/* It is encrypted, and a password/key needs to be supplied to decrypt.
 	 * This doesn't trigger for PDFs that are encrypted but don't need
 	 * a password to decrypt */
-	*ctx->virname = "Heuristics.Encrypted.PDF";
+	cli_append_virus(ctx, "Heuristics.Encrypted.PDF");
 	rc = CL_VIRUS;
     }
 
@@ -1596,7 +1607,7 @@
 	if (!rc && (ctx->options & CL_SCAN_ALGORITHMIC)) {
 	    if (pdf.flags & (1 << ESCAPED_COMMON_PDFNAME)) {
 		/* for example /Fl#61te#44#65#63#6f#64#65 instead of /FlateDecode */
-		*ctx->virname = "Heuristics.PDF.ObfuscatedNameObject";
+		cli_append_virus(ctx, "Heuristics.PDF.ObfuscatedNameObject");
 		rc = cli_found_possibly_unwanted(ctx);
 	    }
 	}
@@ -2260,7 +2271,7 @@
 	while(len > 0) {
 		int byte = (len--) ? (int)*ptr++ : EOF;
 
-		if((byte == '~') && (*ptr == '>'))
+		if((byte == '~') && (len > 0) && (*ptr == '>'))
 			byte = EOF;
 
 		if(byte >= '!' && byte <= 'u') {
@@ -2276,7 +2287,7 @@
 			}
 		} else if(byte == 'z') {
 			if(quintet) {
-				cli_dbgmsg("ascii85decode: unexpected 'z'\n");
+				cli_dbgmsg("cli_pdf: ascii85decode: unexpected 'z'\n");
 				return -1;
 			}
 			*output++ = '\0';
@@ -2285,12 +2296,12 @@
 			*output++ = '\0';
 			ret += 4;
 		} else if(byte == EOF) {
-			cli_dbgmsg("ascii85decode: quintet %d\n", quintet);
+			cli_dbgmsg("cli_pdf: ascii85decode: quintet %d\n", quintet);
 			if(quintet) {
 				int i;
 
 				if(quintet == 1) {
-					cli_dbgmsg("ascii85Decode: only 1 byte in last quintet\n");
+					cli_dbgmsg("cli_pdf: ascii85Decode: only 1 byte in last quintet\n");
 					return -1;
 				}
 				for(i = quintet; i < 5; i++)
@@ -2304,7 +2315,7 @@
 			}
 			break;
 		} else if(!isspace(byte)) {
-			cli_dbgmsg("ascii85Decode: invalid character 0x%x, len %lu\n",
+			cli_dbgmsg("cli_pdf: ascii85Decode: invalid character 0x%x, len %lu\n",
 				byte & 0xFF, (unsigned long)len);
 			return -1;
 		}
diff -Nru clamav-0.97.6+dfsg/libclamav/pe.c clamav-0.97.7+dfsg/libclamav/pe.c
--- clamav-0.97.6+dfsg/libclamav/pe.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/pe.c	2013-03-11 11:23:21.000000000 -0400
@@ -534,6 +534,8 @@
 #ifdef HAVE__INTERNAL__SHA_COLLECT
 	int sha_collect = ctx->sha_collect;
 #endif
+	const char * virname = NULL;
+	uint32_t viruses_found = 0;
 
     if(!ctx) {
 	cli_errmsg("cli_scanpe: ctx == NULL\n");
@@ -554,8 +556,7 @@
 	cli_dbgmsg("Can't read new header address\n");
 	/* truncated header? */
 	if(DETECT_BROKEN_PE) {
-	    if(ctx->virname)
-		*ctx->virname = "Heuristics.Broken.Executable";
+	    cli_append_virus(ctx,"Heuristics.Broken.Executable");
 	    return CL_VIRUS;
 	}
 	return CL_CLEAN;
@@ -684,8 +685,7 @@
     nsections = EC16(file_hdr.NumberOfSections);
     if(nsections < 1 || nsections > 96) {
 	if(DETECT_BROKEN_PE) {
-	    if(ctx->virname)
-		*ctx->virname = "Heuristics.Broken.Executable";
+	    cli_append_virus(ctx,"Heuristics.Broken.Executable");
 	    return CL_VIRUS;
 	}
 	if(!ctx->corrupted_input) {
@@ -706,8 +706,7 @@
     if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) {
         cli_dbgmsg("SizeOfOptionalHeader too small\n");
 	if(DETECT_BROKEN_PE) {
-	    if(ctx->virname)
-	        *ctx->virname = "Heuristics.Broken.Executable";
+	    cli_append_virus(ctx,"Heuristics.Broken.Executable");
 	    return CL_VIRUS;
 	}
 	return CL_CLEAN;
@@ -717,8 +716,7 @@
     if(fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) {
         cli_dbgmsg("Can't read optional file header\n");
 	if(DETECT_BROKEN_PE) {
-	    if(ctx->virname)
-	        *ctx->virname = "Heuristics.Broken.Executable";
+	    cli_append_virus(ctx,"Heuristics.Broken.Executable");
 	    return CL_VIRUS;
 	}
 	return CL_CLEAN;
@@ -731,8 +729,7 @@
 	    /* FIXME: need to play around a bit more with xp64 */
 	    cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n");
 	    if(DETECT_BROKEN_PE) {
-	        if(ctx->virname)
-		    *ctx->virname = "Heuristics.Broken.Executable";
+		cli_append_virus(ctx,"Heuristics.Broken.Executable");
 		return CL_VIRUS;
 	    }
 	    return CL_CLEAN;
@@ -774,8 +771,7 @@
         if(fmap_readn(map, &optional_hdr32 + 1, at, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) {
 	    cli_dbgmsg("Can't read optional file header\n");
 	    if(DETECT_BROKEN_PE) {
-	        if(ctx->virname)
-		    *ctx->virname = "Heuristics.Broken.Executable";
+		cli_append_virus(ctx,"Heuristics.Broken.Executable");
 		return CL_VIRUS;
 	    }
 	    return CL_CLEAN;
@@ -855,15 +851,13 @@
 
     if (DETECT_BROKEN_PE && !native && (!(pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment)) || (pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment))%0x1000)) {
         cli_dbgmsg("Bad virtual alignemnt\n");
-        if(ctx->virname)
-	    *ctx->virname = "Heuristics.Broken.Executable";
+	cli_append_virus(ctx,"Heuristics.Broken.Executable");
 	return CL_VIRUS;
     }
 
     if (DETECT_BROKEN_PE && !native && (!(pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment)) || (pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment))%0x200)) {
         cli_dbgmsg("Bad file alignemnt\n");
-	if(ctx->virname)
-	    *ctx->virname = "Heuristics.Broken.Executable";
+	cli_append_virus(ctx, "Heuristics.Broken.Executable");
 	return CL_VIRUS;
     }
 
@@ -893,8 +887,7 @@
 	free(section_hdr);
 	free(exe_sections);
 	if(DETECT_BROKEN_PE) {
-	    if(ctx->virname)
-		*ctx->virname = "Heuristics.Broken.Executable";
+	    cli_append_virus(ctx,"Heuristics.Broken.Executable");
 	    return CL_VIRUS;
 	}
 	return CL_CLEAN;
@@ -961,8 +954,7 @@
 
 	if (DETECT_BROKEN_PE && (!valign || (exe_sections[i].urva % valign))) { /* Bad virtual alignment */
 	    cli_dbgmsg("VirtualAddress is misaligned\n");
-	    if(ctx->virname)
-	        *ctx->virname = "Heuristics.Broken.Executable";
+	    cli_append_virus(ctx, "Heuristics.Broken.Executable");
 	    free(section_hdr);
 	    free(exe_sections);
 	    return CL_VIRUS;
@@ -974,8 +966,7 @@
 		free(section_hdr);
 		free(exe_sections);
 		if(DETECT_BROKEN_PE) {
-		    if(ctx->virname)
-		        *ctx->virname = "Heuristics.Broken.Executable";
+		    cli_append_virus(ctx, "Heuristics.Broken.Executable");
 		    return CL_VIRUS;
 		}
 		return CL_CLEAN; /* no ninjas to see here! move along! */
@@ -989,12 +980,16 @@
 		unsigned char md5_dig[16];
 		if(cli_hm_have_size(md5_sect, CLI_HASH_MD5, exe_sections[i].rsz) && 
 		   cli_md5sect(map, &exe_sections[i], md5_dig) &&
-		   cli_hm_scan(md5_dig, exe_sections[i].rsz, ctx->virname, md5_sect, CLI_HASH_MD5) == CL_VIRUS) {
+		   cli_hm_scan(md5_dig, exe_sections[i].rsz, &virname, md5_sect, CLI_HASH_MD5) == CL_VIRUS) {
+		    cli_append_virus(ctx, virname);
 		    if(cli_hm_scan(md5_dig, fsize, NULL, ctx->engine->hm_fp, CLI_HASH_MD5) != CL_VIRUS) {
-			free(section_hdr);
-			free(exe_sections);
-			return CL_VIRUS;
+			if (!SCAN_ALL) {
+			    free(section_hdr);
+			    free(exe_sections);
+			    return CL_VIRUS;
+			}
 		    }
+		    viruses_found++;
 		}
 	    }
 
@@ -1005,8 +1000,7 @@
 	    free(section_hdr);
 	    free(exe_sections);
 	    if(DETECT_BROKEN_PE) {
-	        if(ctx->virname)
-		    *ctx->virname = "Heuristics.Broken.Executable";
+		cli_append_virus(ctx, "Heuristics.Broken.Executable");
 		return CL_VIRUS;
 	    }
 	    return CL_CLEAN;
@@ -1015,8 +1009,7 @@
 	if(!i) {
 	    if (DETECT_BROKEN_PE && exe_sections[i].urva!=hdr_size) { /* Bad first section RVA */
 	        cli_dbgmsg("First section is in the wrong place\n");
-	        if(ctx->virname)
-		    *ctx->virname = "Heuristics.Broken.Executable";
+		cli_append_virus(ctx, "Heuristics.Broken.Executable");
 		free(section_hdr);
 		free(exe_sections);
 		return CL_VIRUS;
@@ -1026,8 +1019,7 @@
 	} else {
 	    if (DETECT_BROKEN_PE && exe_sections[i].urva - exe_sections[i-1].urva != exe_sections[i-1].vsz) { /* No holes, no overlapping, no virtual disorder */
 	        cli_dbgmsg("Virtually misplaced section (wrong order, overlapping, non contiguous)\n");
-	        if(ctx->virname)
-		    *ctx->virname = "Heuristics.Broken.Executable";
+		cli_append_virus(ctx, "Heuristics.Broken.Executable");
 		free(section_hdr);
 		free(exe_sections);
 		return CL_VIRUS;
@@ -1048,8 +1040,7 @@
 	cli_dbgmsg("EntryPoint out of file\n");
 	free(exe_sections);
 	if(DETECT_BROKEN_PE) {
-	    if(ctx->virname)
-		*ctx->virname = "Heuristics.Broken.Executable";
+	    cli_append_virus(ctx,"Heuristics.Broken.Executable");
 	    return CL_VIRUS;
 	}
 	return CL_CLEAN;
@@ -1109,7 +1100,7 @@
     }
     cli_bytecode_context_setpe(bc_ctx, &pedata, exe_sections);
     cli_bytecode_context_setctx(bc_ctx, ctx);
-    ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_ALL, map, ctx->virname);
+    ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_ALL, map);
     if (ret == CL_VIRUS || ret == CL_BREAK) {
 	free(exe_sections);
 	cli_bytecode_context_destroy(bc_ctx);
@@ -1125,9 +1116,12 @@
 	if(pt) {
 	    pt += 15;
 	    if((((uint32_t)cli_readint32(pt) ^ (uint32_t)cli_readint32(pt + 4)) == 0x505a4f) && (((uint32_t)cli_readint32(pt + 8) ^ (uint32_t)cli_readint32(pt + 12)) == 0xffffb) && (((uint32_t)cli_readint32(pt + 16) ^ (uint32_t)cli_readint32(pt + 20)) == 0xb8)) {
-	        *ctx->virname = "Heuristics.W32.Parite.B";
-		free(exe_sections);
-		return CL_VIRUS;
+	        cli_append_virus(ctx,"Heuristics.W32.Parite.B");
+		if (!SCAN_ALL) {
+		    free(exe_sections);
+		    return CL_VIRUS;
+		}
+		viruses_found++;
 	    }
 	}
     }
@@ -1208,9 +1202,11 @@
 		break;
 	    case KZSLOOP:
 		if (op==kzdsize+0x48 && *kzcode==0x75 && kzlen-(int8_t)kzcode[1]-3<=kzinitlen && kzlen-(int8_t)kzcode[1]>=kzxorlen) {
-		    *ctx->virname = "Heuristics.W32.Kriz";
+		    cli_append_virus(ctx,"Heuristics.W32.Kriz");
 		    free(exe_sections);
-		    return CL_VIRUS;
+		    if (!SCAN_ALL)
+			return CL_VIRUS;
+		    viruses_found++;
 		}
 		cli_dbgmsg("kriz: loop out of bounds, corrupted sample?\n");
 		kzstate++;
@@ -1235,10 +1231,12 @@
 
 	    if((tbuff = fmap_need_off_once(map, exe_sections[nsections - 1].raw + rsize - bw, 4096))) {
 		if(cli_memstr(tbuff, 4091, "\xe8\x2c\x61\x00\x00", 5)) {
-		    *ctx->virname = dam ? "Heuristics.W32.Magistr.A.dam" : "Heuristics.W32.Magistr.A";
+		    cli_append_virus(ctx, dam ? "Heuristics.W32.Magistr.A.dam" : "Heuristics.W32.Magistr.A");
 		    free(exe_sections);
-		    return CL_VIRUS;
-		} 
+		    if (!SCAN_ALL)
+			return CL_VIRUS;
+		    viruses_found++;
+		}
 	    }
 
 	} else if(rsize >= 0x7000 && vsize >= 0x7000 && ((vsize & 0xff) == 0xed)) {
@@ -1247,9 +1245,11 @@
 
 	    if((tbuff = fmap_need_off_once(map, exe_sections[nsections - 1].raw + rsize - bw, 4096))) {
 		if(cli_memstr(tbuff, 4091, "\xe8\x04\x72\x00\x00", 5)) {
-		    *ctx->virname = dam ? "Heuristics.W32.Magistr.B.dam" : "Heuristics.W32.Magistr.B";
+		    cli_append_virus(ctx,dam ? "Heuristics.W32.Magistr.B.dam" : "Heuristics.W32.Magistr.B");
 		    free(exe_sections);
-		    return CL_VIRUS;
+		    if (!SCAN_ALL)
+			return CL_VIRUS;
+		    viruses_found++;
 		} 
 	    }
 	}
@@ -1295,10 +1295,12 @@
 	for(i=0;i<xsjs;i++) {
 	    if(!(code = fmap_need_off_once(map, jumps[i], 9))) continue;
 	    if((jump=cli_readint32(code))==0x60ec8b55 || (code[4]==0x0ec && ((jump==0x83ec8b55 && code[6]==0x60) || (jump==0x81ec8b55 && !code[7] && !code[8])))) {
-		*ctx->virname = "Heuristics.W32.Polipos.A";
+		cli_append_virus(ctx,"Heuristics.W32.Polipos.A");
 		free(jumps);
 		free(exe_sections);
-		return CL_VIRUS;
+		if (!SCAN_ALL)
+		    return CL_VIRUS;
+		viruses_found++;
 	    }
 	}
 	free(jumps);
@@ -1317,13 +1319,16 @@
 		    else {
 			    cli_parseres_special(EC32(dirs[2].VirtualAddress), EC32(dirs[2].VirtualAddress), map, exe_sections, nsections, fsize, hdr_size, 0, 0, &m, stats);
 			    if ((ret = cli_detect_swizz(stats)) == CL_VIRUS) {
-				    *ctx->virname = "Heuristics.Trojan.Swizzor.Gen";
+				cli_append_virus(ctx,"Heuristics.Trojan.Swizzor.Gen");
 			    }
 			    free(stats);
 		    }
 		    if (ret != CL_CLEAN) {
+			if (!(ret == CL_VIRUS && SCAN_ALL)) {
 			    free(exe_sections);
 			    return ret;
+			}
+			viruses_found++;
 		    }
 	    }
     }
@@ -2080,23 +2085,23 @@
 	    !memcmp(epbuff+0x63+offset, "\xaa\xe2\xcc", 3) &&
 	    (fsize >= exe_sections[nsections-1].raw + 0xC6 + ecx + offset)) {
 
-	char *spinned;
+	    char *spinned;
 
-	if((spinned = (char *) cli_malloc(fsize)) == NULL) {
-	    free(exe_sections);
-	    return CL_EMEM;
-	}
+	    if((spinned = (char *) cli_malloc(fsize)) == NULL) {
+	      free(exe_sections);
+	      return CL_EMEM;
+	    }
 
-	if((size_t) fmap_readn(map, spinned, 0, fsize) != fsize) {
-	    cli_dbgmsg("yC: Can't read %lu bytes\n", (unsigned long)fsize);
-	    free(spinned);
-	    free(exe_sections);
-	    return CL_EREAD;
-	}
+	    if((size_t) fmap_readn(map, spinned, 0, fsize) != fsize) {
+	      cli_dbgmsg("yC: Can't read %lu bytes\n", (unsigned long)fsize);
+	      free(spinned);
+	      free(exe_sections);
+	      return CL_EREAD;
+	    }
 
-	cli_dbgmsg("%d,%d,%d,%d\n", nsections-1, e_lfanew, ecx, offset);
-	CLI_UNPTEMP("yC",(spinned,exe_sections,0));
-	CLI_UNPRESULTS("yC",(yc_decrypt(spinned, fsize, exe_sections, nsections-1, e_lfanew, ndesc, ecx, offset)),0,(spinned,0));
+	    cli_dbgmsg("%d,%d,%d,%d\n", nsections-1, e_lfanew, ecx, offset);
+	    CLI_UNPTEMP("yC",(spinned,exe_sections,0));
+	    CLI_UNPRESULTS("yC",(yc_decrypt(spinned, fsize, exe_sections, nsections-1, e_lfanew, ndesc, ecx, offset)),0,(spinned,0));
 	}
     }
 
@@ -2271,7 +2276,7 @@
     }
     cli_bytecode_context_setpe(bc_ctx, &pedata, exe_sections);
     cli_bytecode_context_setctx(bc_ctx, ctx);
-    ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_UNPACKER, map, ctx->virname);
+    ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_UNPACKER, map);
     switch (ret) {
 	case CL_VIRUS:
 	    free(exe_sections);
@@ -2289,6 +2294,8 @@
     }
 
     free(exe_sections);
+    if (SCAN_ALL && viruses_found)
+	return CL_VIRUS;
     return CL_CLEAN;
 }
 
diff -Nru clamav-0.97.6+dfsg/libclamav/pe_icons.c clamav-0.97.7+dfsg/libclamav/pe_icons.c
--- clamav-0.97.6+dfsg/libclamav/pe_icons.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/pe_icons.c	2013-03-11 11:23:21.000000000 -0400
@@ -1512,8 +1512,7 @@
 	if(confidence >= positivematch) {
 	    cli_dbgmsg("confidence: %u\n", confidence);
 
-	    if(ctx->virname) 
-		*ctx->virname = matcher->icons[enginesize][x].name;
+	    cli_append_virus(ctx,matcher->icons[enginesize][x].name);
 	    return CL_VIRUS;
 	}
     }
diff -Nru clamav-0.97.6+dfsg/libclamav/phishcheck.c clamav-0.97.7+dfsg/libclamav/phishcheck.c
--- clamav-0.97.6+dfsg/libclamav/phishcheck.c	2012-06-12 09:03:27.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/phishcheck.c	2013-03-11 11:23:21.000000000 -0400
@@ -735,7 +735,7 @@
 	if(!pchk || pchk->is_disabled)
 		return CL_CLEAN;
 
-	if(!ctx->found_possibly_unwanted)
+	if(!ctx->found_possibly_unwanted && !SCAN_ALL)
 		*ctx->virname=NULL;
 #if 0
 	FILE *f = fopen("/home/edwin/quarantine/urls","r");
@@ -810,29 +810,29 @@
 				case CL_PHISH_CLEAN:
 					continue;
 				case CL_PHISH_NUMERIC_IP:
-					*ctx->virname="Heuristics.Phishing.Email.Cloaked.NumericIP";
+				    cli_append_virus(ctx, "Heuristics.Phishing.Email.Cloaked.NumericIP");
 					break;
 				case CL_PHISH_CLOAKED_NULL:
-					*ctx->virname="Heuristics.Phishing.Email.Cloaked.Null";/*fakesite%01%00@fake.example.com*/
+				    cli_append_virus(ctx, "Heuristics.Phishing.Email.Cloaked.Null");/*fakesite%01%00@fake.example.com*/
 					break;
 				case CL_PHISH_SSL_SPOOF:
-					*ctx->virname="Heuristics.Phishing.Email.SSL-Spoof";
+				    cli_append_virus(ctx, "Heuristics.Phishing.Email.SSL-Spoof");
 					break;
 				case CL_PHISH_CLOAKED_UIU:
-					*ctx->virname="Heuristics.Phishing.Email.Cloaked.Username";/*http://banksite@fake.example.com*/
+				    cli_append_virus(ctx, "Heuristics.Phishing.Email.Cloaked.Username");/*http://banksite@fake.example.com*/
 					break;
 				case CL_PHISH_HASH0:
-					*ctx->virname="Heuristics.Safebrowsing.Suspected-malware_safebrowsing.clamav.net";
+				    cli_append_virus(ctx, "Heuristics.Safebrowsing.Suspected-malware_safebrowsing.clamav.net");
 					break;
 				case CL_PHISH_HASH1:
-					*ctx->virname="Heuristics.Phishing.URL.Blacklisted";
+				    cli_append_virus(ctx, "Heuristics.Phishing.URL.Blacklisted");
 					break;
 				case CL_PHISH_HASH2:
-					*ctx->virname="Heuristics.Safebrowsing.Suspected-phishing_safebrowsing.clamav.net";
+				    cli_append_virus(ctx, "Heuristics.Safebrowsing.Suspected-phishing_safebrowsing.clamav.net");
 					break;
 				case CL_PHISH_NOMATCH:
 				default:
-					*ctx->virname="Heuristics.Phishing.Email.SpoofedDomain";
+				    cli_append_virus(ctx, "Heuristics.Phishing.Email.SpoofedDomain");
 					break;
 			}
 			return cli_found_possibly_unwanted(ctx);
@@ -1207,14 +1207,14 @@
 	    cli_dbgmsg("Looking up hash %s for %s(%u)%s(%u)\n", h, host, (unsigned)hlen, path, (unsigned)plen);
 #if 0
 	    if (prefix_matched) {
-		if (cli_bm_scanbuff(sha256_dig, 4, &virname, NULL, &rlist->hostkey_prefix,0,NULL,NULL) == CL_VIRUS) {
+		if (cli_bm_scanbuff(sha256_dig, 4, &virname, NULL, &rlist->hostkey_prefix,0,NULL,NULL,NULL) == CL_VIRUS) {
 		    cli_dbgmsg("prefix matched\n");
 		    *prefix_matched = 1;
 		} else
 		    return CL_SUCCESS;
 	    }
 #endif
-	    if (cli_bm_scanbuff(sha256_dig, 32, &virname, NULL, &rlist->sha256_hashes,0,NULL,NULL) == CL_VIRUS) {
+	    if (cli_bm_scanbuff(sha256_dig, 32, &virname, NULL, &rlist->sha256_hashes,0,NULL,NULL,NULL) == CL_VIRUS) {
 		cli_dbgmsg("This hash matched: %s\n", h);
 		switch(*virname) {
 		    case 'W':
diff -Nru clamav-0.97.6+dfsg/libclamav/readdb.c clamav-0.97.7+dfsg/libclamav/readdb.c
--- clamav-0.97.6+dfsg/libclamav/readdb.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/readdb.c	2013-03-11 11:23:21.000000000 -0400
@@ -468,7 +468,7 @@
     if(!ignored || !signame || !entry)
 	return 0;
 
-    if(cli_bm_scanbuff((const unsigned char *) signame, strlen(signame), &md5_expected, NULL, ignored, 0, NULL, NULL) == CL_VIRUS) {
+    if(cli_bm_scanbuff((const unsigned char *) signame, strlen(signame), &md5_expected, NULL, ignored, 0, NULL, NULL,NULL) == CL_VIRUS) {
 	if(md5_expected) {
 	    cli_md5_init(&md5ctx);
             cli_md5_update(&md5ctx, entry, strlen(entry));
diff -Nru clamav-0.97.6+dfsg/libclamav/regex_list.c clamav-0.97.7+dfsg/libclamav/regex_list.c
--- clamav-0.97.6+dfsg/libclamav/regex_list.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/regex_list.c	2013-03-11 11:23:21.000000000 -0400
@@ -357,7 +357,7 @@
 
 	if (fl != 'W' && pat->length == 32 &&
 	    cli_hashset_contains(&matcher->sha256_pfx_set, cli_readint32(pat->pattern)) &&
-	    cli_bm_scanbuff(pat->pattern, 32, &vname, NULL, &matcher->sha256_hashes,0,NULL,NULL) == CL_VIRUS) {
+	    cli_bm_scanbuff(pat->pattern, 32, &vname, NULL, &matcher->sha256_hashes,0,NULL,NULL,NULL) == CL_VIRUS) {
 	    if (*vname == 'W') {
 		/* hash is whitelisted in local.gdb */
 		cli_dbgmsg("Skipping hash %s\n", pattern);
diff -Nru clamav-0.97.6+dfsg/libclamav/scanners.c clamav-0.97.7+dfsg/libclamav/scanners.c
--- clamav-0.97.6+dfsg/libclamav/scanners.c	2012-08-06 16:26:55.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/scanners.c	2013-03-11 11:23:21.000000000 -0400
@@ -111,7 +111,7 @@
 #endif
 	struct stat statbuf;
 	char *fname;
-
+	unsigned int viruses_found = 0;
 
     if((dd = opendir(dirname)) != NULL) {
 #ifdef HAVE_READDIR_R_3
@@ -138,16 +138,28 @@
 			if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {
 			    if(cli_scandir(fname, ctx) == CL_VIRUS) {
 				free(fname);
-				closedir(dd);
-				return CL_VIRUS;
-			    }
+
+				if (SCAN_ALL) {
+				    viruses_found++;
+				    continue;
+				}
+
+                                closedir(dd);
+                                return CL_VIRUS;
+ 			    }
 			} else {
 			    if(S_ISREG(statbuf.st_mode)) {
 				if(cli_scanfile(fname, ctx) == CL_VIRUS) {
 				    free(fname);
-				    closedir(dd);
-				    return CL_VIRUS;
-				}
+
+				    if (SCAN_ALL) {
+					viruses_found++;
+					continue;
+				    }
+
+                                    closedir(dd);
+                                    return CL_VIRUS;
+ 				}
 			    }
 			}
 		    }
@@ -161,6 +173,8 @@
     }
 
     closedir(dd);
+    if (SCAN_ALL && viruses_found)
+	return CL_VIRUS;
     return CL_CLEAN;
 }
 
@@ -188,7 +202,7 @@
 	lseek(desc, 0, SEEK_SET);
 	ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
 	if(ret != CL_VIRUS) {
-	    *ctx->virname = "Heuristics.Encrypted.RAR";
+	    cli_append_virus(ctx, "Heuristics.Encrypted.RAR");
 	    return CL_VIRUS;
 	}
     }
@@ -202,7 +216,7 @@
 	unrar_metadata_t *metadata, *metadata_tmp;
 	char *dir;
 	unrar_state_t rar_state;
-
+	unsigned int viruses_found = 0;
 
     cli_dbgmsg("in scanrar()\n");
 
@@ -230,7 +244,7 @@
 		lseek(desc, 0, SEEK_SET);
 		ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
 		if(ret != CL_VIRUS)
-		    *ctx->virname = "Heuristics.Encrypted.RAR";
+		    cli_append_virus(ctx, "Heuristics.Encrypted.RAR");
 		return CL_VIRUS;
 	    }
 	    return CL_CLEAN;
@@ -280,12 +294,19 @@
 	    if(!ctx->engine->keeptmp) 
 		if (cli_unlink(rar_state.filename)) ret = CL_EUNLINK;
 	    if(rc == CL_VIRUS ) {
-		cli_dbgmsg("RAR: infected with %s\n",*ctx->virname);
+		cli_dbgmsg("RAR: infected with %s\n", cli_get_last_virus(ctx));
 		ret = CL_VIRUS;
-		break;
+		viruses_found++;
 	    }
 	}
 
+	if(ret == CL_VIRUS) {
+	    if(SCAN_ALL)
+		ret = CL_SUCCESS;
+	    else
+		break;
+	}
+
 	if(ret == CL_SUCCESS)
 	    ret = cli_unrar_scanmetadata(desc,rar_state.metadata_tail, ctx, rar_state.file_count, sfx_check);
 
@@ -315,6 +336,8 @@
     }
     cli_dbgmsg("RAR: Exit code: %d\n", ret);
 
+    if (SCAN_ALL && viruses_found)
+	return CL_VIRUS;
     return ret;
 }
 
@@ -370,7 +393,7 @@
 	    rc = cli_magic_scandesc(metadata.ofd, ctx);
 	    close(metadata.ofd);
 	    if (rc == CL_VIRUS) {
-		cli_dbgmsg("ARJ: infected with %s\n",*ctx->virname);
+		cli_dbgmsg("ARJ: infected with %s\n", cli_get_last_virus(ctx));
 		ret = CL_VIRUS;
 		if (metadata.filename) {
 		    free(metadata.filename);
@@ -443,7 +466,7 @@
     gzclose(gz);
 
     if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
-	cli_dbgmsg("GZip: Infected with %s\n", *ctx->virname);
+	cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx));
 	close(fd);
 	if(!ctx->engine->keeptmp) {
 	    if (cli_unlink(tmpname)) {
@@ -535,7 +558,7 @@
     inflateEnd(&z);	    
 
     if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
-	cli_dbgmsg("GZip: Infected with %s\n", *ctx->virname);
+	cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx));
 	close(fd);
 	if(!ctx->engine->keeptmp) {
 	    if (cli_unlink(tmpname)) {
@@ -652,7 +675,7 @@
 
     lseek(fd, 0, SEEK_SET);
     if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
-	cli_dbgmsg("Bzip: Infected with %s\n", *ctx->virname);
+	cli_dbgmsg("Bzip: Infected with %s\n", cli_get_last_virus(ctx));
     }
     close(fd);
     if(!ctx->engine->keeptmp)
@@ -707,7 +730,7 @@
 	struct cab_archive cab;
 	struct cab_file *file;
 	unsigned int corrupted_input;
-
+	unsigned int viruses_found = 0;
 
     cli_dbgmsg("in cli_scanmscab()\n");
 
@@ -718,8 +741,11 @@
 	files++;
 
 	if(cli_matchmeta(ctx, file->name, 0, file->length, 0, files, 0, NULL) == CL_VIRUS) {
-	    ret = CL_VIRUS;
-	    break;
+	    if (!SCAN_ALL) {
+		ret = CL_VIRUS;
+		break;
+	    }
+	    viruses_found++;
 	}
 
 	if(ctx->engine->maxscansize && ctx->scansize >= ctx->engine->maxscansize) {
@@ -758,11 +784,17 @@
 	    }
 	}
 	free(tempname);
-	if(ret == CL_VIRUS)
-	    break;
+	if(ret == CL_VIRUS) {
+	    if (SCAN_ALL)
+		viruses_found++;
+	    else
+		break;
+	}
     }
 
     cab_free(&cab);
+    if (viruses_found)
+	return CL_VIRUS;
     return ret;
 }
 
@@ -773,6 +805,7 @@
 	struct cli_ac_data gmdata, tmdata;
 	struct cli_ac_data *mdata[2];
 	int ret;
+	unsigned int viruses_found = 0;
 
     if((ret = cli_ac_initdata(&tmdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
 	return ret;
@@ -786,14 +819,20 @@
 
     ret = cli_scanbuff(data, len, 0, ctx, CL_TYPE_MSOLE2, mdata);
 
-    if(ret != CL_VIRUS) {
+    if(ret != CL_VIRUS || SCAN_ALL) {
+	if (SCAN_ALL)
+	    viruses_found++;
 	ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL);
-	if(ret != CL_VIRUS)
+	if(ret != CL_VIRUS || SCAN_ALL)
+	    if (SCAN_ALL)
+		viruses_found++;
 	    ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL);
     }
     cli_ac_freedata(&tmdata);
     cli_ac_freedata(&gmdata);
 
+    if (viruses_found)
+	return CL_VIRUS;
     return ret;
 }
 
@@ -814,6 +853,7 @@
 	unsigned char *data;
 	char *hash;
 	uint32_t hashcnt;
+	unsigned int viruses_found = 0;
 
 
     cli_dbgmsg("VBADir: %s\n", dirname);
@@ -838,9 +878,13 @@
 		    if(ctx->scanned)
 			*ctx->scanned += data_len / CL_COUNT_PRECISION;
 		    if(vba_scandata(data, data_len, ctx) == CL_VIRUS) {
-			free(data);
-			ret = CL_VIRUS;
-			break;
+			if (SCAN_ALL) 
+			    viruses_found++;
+			else {
+			    free(data);
+			    ret = CL_VIRUS;
+			    break;
+			}
 		    }
 		    free(data);
 		}
@@ -852,10 +896,12 @@
 	free(vba_project->dir);
 	free(vba_project->offset);
 	free(vba_project);
-	if (ret == CL_VIRUS) break;
+	if (ret == CL_VIRUS && !SCAN_ALL)
+	    break;
     }
 
-    if(ret == CL_CLEAN && (hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
+    if((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) && 
+	(hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
 	while(hashcnt--) {
 	    snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
 	    vbaname[sizeof(vbaname)-1] = '\0';
@@ -864,6 +910,7 @@
 	    if ((fullname = cli_ppt_vba_read(fd, ctx))) {
 		if(cli_scandir(fullname, ctx) == CL_VIRUS) {
 		    ret = CL_VIRUS;
+		    viruses_found++;
 		}
 		if(!ctx->engine->keeptmp)
 		    cli_rmdirs(fullname);
@@ -873,7 +920,8 @@
 	}
     }
 
-    if (ret == CL_CLEAN && (hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
+    if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) && 
+	(hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
 	while(hashcnt--) {
 	    snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
 	    vbaname[sizeof(vbaname)-1] = '\0';
@@ -895,9 +943,13 @@
 			if(ctx->scanned)
 			    *ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION;
 			if(vba_scandata(data, vba_project->length[i], ctx) == CL_VIRUS) {
+			    if (SCAN_ALL)
+				viruses_found++;
+			    else {
 				free(data);
 				ret = CL_VIRUS;
 				break;
+			    }
 			}
 			free(data);
 		}
@@ -911,11 +963,16 @@
 	    free(vba_project->key);
 	    free(vba_project->length);
 	    free(vba_project);
-	    if(ret == CL_VIRUS) break;
+	    if(ret == CL_VIRUS) {
+		if (SCAN_ALL)
+		    viruses_found++;
+		else
+		    break;
+	    }
 	}
     }
 
-    if(ret != CL_CLEAN)
+    if(ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
     	return ret;
 
     /* Check directory for embedded OLE objects */
@@ -928,7 +985,7 @@
 	if (fd >= 0) {
 	    ret = cli_scan_ole10(fd, ctx);
 	    close(fd);
-	    if(ret != CL_CLEAN)
+	    if(ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
 		return ret;
 	}
     }
@@ -961,10 +1018,14 @@
 		    if(lstat(fullname, &statbuf) != -1) {
 			if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
 			  if (cli_vba_scandir(fullname, ctx, U) == CL_VIRUS) {
-			    	ret = CL_VIRUS;
-				free(fullname);
-				break;
-			    }
+			      if (SCAN_ALL)
+				  viruses_found++;
+			      else {
+				  ret = CL_VIRUS;
+				  free(fullname);
+				  break;
+			      }
+			  }
 		    }
 		    free(fullname);
 		}
@@ -977,9 +1038,12 @@
 
     closedir(dd);
     if(BLOCK_MACROS && hasmacros) {
-	*ctx->virname = "Heuristics.OLE2.ContainsMacros";
+	cli_append_virus(ctx, "Heuristics.OLE2.ContainsMacros");
 	ret = CL_VIRUS;
+	viruses_found++;
     }
+    if (SCAN_ALL && viruses_found)
+	return CL_VIRUS;
     return ret;
 }
 
@@ -988,6 +1052,7 @@
 	char *tempname, fullname[1024];
 	int ret=CL_CLEAN, fd;
 	fmap_t *map = *ctx->fmap;
+	unsigned int viruses_found = 0;
 
     cli_dbgmsg("in cli_scanhtml()\n");
 
@@ -1015,35 +1080,38 @@
     snprintf(fullname, 1024, "%s"PATHSEP"nocomment.html", tempname);
     fd = open(fullname, O_RDONLY|O_BINARY);
     if (fd >= 0) {
-	    ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
-	    close(fd);
+	if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
+	    viruses_found++;
+	close(fd);
     }
 
-    if(ret == CL_CLEAN && map->len < 2097152) {
+    if((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) && map->len < 2097152) {
 	    /* limit to 2 MB, we're not interesting in scanning large files in notags form */
 	    /* TODO: don't even create notags if file is over 2 MB */
 	    snprintf(fullname, 1024, "%s"PATHSEP"notags.html", tempname);
 	    fd = open(fullname, O_RDONLY|O_BINARY);
 	    if(fd >= 0) {
-		    ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
-		    close(fd);
+		if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS) 
+		    viruses_found++;
+		close(fd);
 	    }
     }
 
-    if(ret == CL_CLEAN) {
+    if(ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
 	    snprintf(fullname, 1024, "%s"PATHSEP"javascript", tempname);
 	    fd = open(fullname, O_RDONLY|O_BINARY);
 	    if(fd >= 0) {
-		    ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
-		    if (ret == CL_CLEAN) {
-			    lseek(fd, 0, SEEK_SET);
-			    ret = cli_scandesc(fd, ctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL);
-		    }
-		    close(fd);
+		if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
+		    viruses_found++;
+		if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
+		    if ((ret = cli_scandesc(fd, ctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
+			viruses_found++;
+		}
+		close(fd);
 	    }
     }
 
-    if (ret == CL_CLEAN) {
+    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
 	snprintf(fullname, 1024, "%s"PATHSEP"rfc2397", tempname);
 	ret = cli_scandir(fullname, ctx);
     }
@@ -1052,6 +1120,8 @@
         cli_rmdirs(tempname);
 
     free(tempname);
+    if (SCAN_ALL && viruses_found)
+	return CL_VIRUS;
     return ret;
 }
 
@@ -1069,6 +1139,7 @@
 	struct cli_ac_data *mdata[2];
 	fmap_t *map = *ctx->fmap;
 	size_t at = 0;
+        unsigned int viruses_found = 0;
 
 	cli_dbgmsg("in cli_scanscript()\n");
 
@@ -1119,8 +1190,12 @@
 		}
 		/* when we flush the buffer also scan */
 		if(cli_scanbuff(state.out, state.out_pos, offset, ctx, CL_TYPE_TEXT_ASCII, mdata) == CL_VIRUS) {
-		    ret = CL_VIRUS;
-		    break;
+		    if (SCAN_ALL)
+			viruses_found++;
+		    else {
+			ret = CL_VIRUS;
+			break;
+		    }
 		}
 		if(ctx->scanned)
 		    *ctx->scanned += state.out_pos / CL_COUNT_PRECISION;
@@ -1141,14 +1216,18 @@
 		close(ofd);
 	}
 	free(normalized);
-	if(ret != CL_VIRUS) {
-	    ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL);
-	    if(ret != CL_VIRUS)
-		ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL);
+	if(ret != CL_VIRUS || SCAN_ALL)  {
+	    if ((ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL)) == CL_VIRUS)
+		viruses_found++;
+	    if(ret != CL_VIRUS || SCAN_ALL)
+		if ((ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL)) == CL_VIRUS)
+		    viruses_found++;
 	}
 	cli_ac_freedata(&tmdata);
 	cli_ac_freedata(&gmdata);
 
+	if (SCAN_ALL && viruses_found)
+	    return CL_VIRUS;
 	return ret;
 }
 
@@ -1293,6 +1372,7 @@
 	int ret = CL_CLEAN, rc;
 	chm_metadata_t metadata;
 	char *dir;
+	unsigned int viruses_found = 0;
 
     cli_dbgmsg("in cli_scanmschm()\n");
 
@@ -1326,9 +1406,13 @@
 	    rc = cli_magic_scandesc(metadata.ofd, ctx);
 	    close(metadata.ofd);
 	    if (rc == CL_VIRUS) {
-		cli_dbgmsg("CHM: infected with %s\n",*ctx->virname);
-		ret = CL_VIRUS;
-		break;
+		cli_dbgmsg("CHM: infected with %s\n", cli_get_last_virus(ctx));
+		if (SCAN_ALL)
+		    viruses_found++;
+		else {
+		    ret = CL_VIRUS;
+		    break;
+		}
 	    }
 	}
 
@@ -1345,6 +1429,8 @@
     if (ret == CL_BREAK)
 	ret = CL_CLEAN;
 
+    if (SCAN_ALL && viruses_found)
+	return CL_VIRUS;
     return ret;
 }
 
@@ -1380,7 +1466,7 @@
 
     if(cli_check_riff_exploit(desc) == 2) {
 	ret = CL_VIRUS;
-	*ctx->virname = "Heuristics.Exploit.W32.MS05-002";
+	cli_append_virus(ctx, "Heuristics.Exploit.W32.MS05-002");
     }
 
     return ret;
@@ -1392,7 +1478,7 @@
 
     if(cli_check_jpeg_exploit(desc, ctx) == 1) {
 	ret = CL_VIRUS;
-	*ctx->virname = "Heuristics.Exploit.W32.MS04-028";
+	cli_append_virus(ctx, "Heuristics.Exploit.W32.MS04-028");
     }
 
     return ret;
@@ -1470,7 +1556,7 @@
     cli_dbgmsg("CryptFF: Scanning decrypted data\n");
 
     if((ret = cli_magic_scandesc(ndesc, ctx)) == CL_VIRUS)
-	cli_dbgmsg("CryptFF: Infected with %s\n", *ctx->virname);
+	cli_dbgmsg("CryptFF: Infected with %s\n", cli_get_last_virus_str(ctx));
 
     close(ndesc);
 
@@ -1562,7 +1648,7 @@
 {
 	char *dir;
 	int ret;
-
+	unsigned int viruses_found = 0;
 
     cli_dbgmsg("Starting cli_scanmail(), recursion = %u\n", ctx->recursion);
 
@@ -1580,10 +1666,14 @@
      * Extract the attachments into the temporary directory
      */
     if((ret = cli_mbox(dir, desc, ctx))) {
-	if(!ctx->engine->keeptmp)
-	    cli_rmdirs(dir);
-	free(dir);
-	return ret;
+	if (ret == CL_VIRUS && SCAN_ALL)
+	    viruses_found++;
+	else {
+	    if(!ctx->engine->keeptmp)
+		cli_rmdirs(dir);
+	    free(dir);
+	    return ret;
+	}
     }
 
     ret = cli_scandir(dir, ctx);
@@ -1592,6 +1682,8 @@
 	cli_rmdirs(dir);
 
     free(dir);
+    if (SCAN_ALL && viruses_found)
+	return CL_VIRUS;
     return ret;
 }
 
@@ -1604,7 +1696,7 @@
 	int done = 0;
 	int (*ccfunc)(const unsigned char *buffer, int length);
 	int (*ssnfunc)(const unsigned char *buffer, int length);
-
+	unsigned int viruses_found = 0;
 
     if(ctx == NULL)
 	return CL_ENULLARG;
@@ -1651,16 +1743,24 @@
 
     if(cc_count != 0 && cc_count >= ctx->engine->min_cc_count) {
 	cli_dbgmsg("cli_scan_structured: %u credit card numbers detected\n", cc_count);
-	*ctx->virname = "Heuristics.Structured.CreditCardNumber";
-	return CL_VIRUS;
+	cli_append_virus(ctx,"Heuristics.Structured.CreditCardNumber");
+	if (SCAN_ALL)
+	    viruses_found++;
+	else
+	    return CL_VIRUS;
     }
 
     if(ssn_count != 0 && ssn_count >= ctx->engine->min_ssn_count) {
 	cli_dbgmsg("cli_scan_structured: %u social security numbers detected\n", ssn_count);
-	*ctx->virname = "Heuristics.Structured.SSN";
-	return CL_VIRUS;
+	cli_append_virus(ctx,"Heuristics.Structured.SSN");
+	if (SCAN_ALL)
+	    viruses_found++;
+	else
+	    return CL_VIRUS;
     }
 
+    if (SCAN_ALL && viruses_found)
+	return CL_VIRUS;
     return CL_CLEAN;
 }
 
@@ -1727,7 +1827,7 @@
     ret = cli_magic_scandesc(fd, ctx);
     ctx->corrupted_input = corrupted_input;
     if(ret == CL_VIRUS) {
-	cli_dbgmsg("cli_scanembpe: Infected with %s\n", *ctx->virname);
+	cli_dbgmsg("cli_scanembpe: Infected with %s\n", cli_get_last_virus(ctx));
 	close(fd);
 	if(!ctx->engine->keeptmp) {
 	    if (cli_unlink(tmpname)) {
@@ -1921,7 +2021,7 @@
     }
 
     if(ret == CL_VIRUS)
-	cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, map->fd);
+	cli_dbgmsg("%s found\n", cli_get_last_virus(ctx));
 
     return ret;
 }
@@ -1945,14 +2045,13 @@
 #define ret_from_magicscan(retcode) do {							\
     cli_dbgmsg("cli_magic_scandesc: returning %d %s\n", retcode, __AT__);			\
     if(ctx->engine->cb_post_scan) {								\
-	switch(ctx->engine->cb_post_scan(desc, retcode, retcode == CL_VIRUS && ctx->virname ? *ctx->virname : NULL, ctx->cb_ctx)) {		\
+	switch(ctx->engine->cb_post_scan(desc, retcode, retcode == CL_VIRUS ? cli_get_last_virus(ctx) : NULL, ctx->cb_ctx)) { \
 	case CL_BREAK:										\
 	    cli_dbgmsg("cli_magic_scandesc: file whitelisted by callback\n");			\
 	    return CL_CLEAN;									\
 	case CL_VIRUS:										\
 	    cli_dbgmsg("cli_magic_scandesc: file blacklisted by callback\n");			\
-	    if(ctx->virname)									\
-		*ctx->virname = "Detected.By.Callback";						\
+	    cli_append_virus(ctx, "Detected.By.Callback");					\
 	    return CL_VIRUS;									\
 	case CL_CLEAN:										\
 	    break;										\
@@ -1973,6 +2072,7 @@
 	size_t current_container_size = ctx->container_size, hashed_size;
 	unsigned char hash[16];
 	bitset_t *old_hook_lsig_matches;
+	unsigned int viruses_found = 0;
 
 #ifdef HAVE__INTERNAL__SHA_COLLECT
     if(ctx->sha_collect>0) ctx->sha_collect = 0;
@@ -2026,8 +2126,7 @@
 	    ret_from_magicscan(CL_CLEAN);
 	case CL_VIRUS:
 	    cli_dbgmsg("cli_magic_scandesc: file blacklisted by callback\n");
-	    if(ctx->virname)
-		*ctx->virname = "Detected.By.Callback";
+	    cli_append_virus(ctx, "Detected.By.Callback");
 	    funmap(*ctx->fmap);
 	    ctx->fmap--;
 	    ret_from_magicscan(CL_VIRUS);
@@ -2048,14 +2147,14 @@
     old_hook_lsig_matches = ctx->hook_lsig_matches;
     ctx->hook_lsig_matches = NULL;
 
-    if(!ctx->options || (ctx->recursion == ctx->engine->maxreclevel)) { /* raw mode (stdin, etc.) or last level of recursion */
+    if(!(ctx->options&~CL_SCAN_ALLMATCHES) || (ctx->recursion == ctx->engine->maxreclevel)) { /* raw mode (stdin, etc.) or last level of recursion */
 	if(ctx->recursion == ctx->engine->maxreclevel)
 	    cli_dbgmsg("cli_magic_scandesc: Hit recursion limit, only scanning raw file\n");
 	else
 	    cli_dbgmsg("Raw mode: No support for special files\n");
 
 	if((ret = cli_fmap_scandesc(ctx, 0, 0, NULL, AC_SCAN_VIR, NULL, hash)) == CL_VIRUS)
-	    cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, desc);
+	    cli_dbgmsg("%s found in descriptor %d\n", cli_get_last_virus(ctx), desc);
 	else if(ret == CL_CLEAN) {
 	    if(ctx->recursion != ctx->engine->maxreclevel)
 		cache_add(hash, hashed_size, ctx); /* Only cache if limits are not reached */
@@ -2381,6 +2480,8 @@
 		/* CL_VIRUS = malware found, check FP and report */
 		case CL_VIRUS:
 		    ret = cli_checkfp(hash, hashed_size, ctx);
+		    if (SCAN_ALL)
+			break;
 		    funmap(*ctx->fmap);
 		    ctx->fmap--;
 		    cli_bitset_free(ctx->hook_lsig_matches);
@@ -2415,11 +2516,10 @@
 	case CL_TYPE_TEXT_UTF16BE:
 	case CL_TYPE_TEXT_UTF16LE:
 	case CL_TYPE_TEXT_UTF8:
-	    if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML)
+	    if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML && ret != CL_VIRUS)
 	        ret = cli_scanscript(ctx);
 	    if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX) && ret != CL_VIRUS && (ctx->container_type == CL_TYPE_MAIL || dettype == CL_TYPE_MAIL)) {
-		lseek(desc, 0, SEEK_SET);
-		ret = cli_scandesc(desc, ctx, CL_TYPE_MAIL, 0, NULL, AC_SCAN_VIR, NULL);
+		ret = cli_fmap_scandesc(ctx, CL_TYPE_MAIL, 0, NULL, AC_SCAN_VIR, NULL, NULL);
 	    }
 	    break;
 	/* Due to performance reasons all executables were first scanned
@@ -2519,6 +2619,12 @@
     cli_logg_setup(&ctx);
     rc = cli_magic_scandesc(desc, &ctx);
 
+    if (ctx.options & CL_SCAN_ALLMATCHES) {
+	*virname = (char *)ctx.virname; /* temp hack for scanall mode until api augmentation */
+	if (rc == CL_CLEAN && ctx.num_viruses)
+	    rc = CL_VIRUS;
+    }
+
     cli_bitset_free(ctx.hook_lsig_matches);
     free(ctx.fmap);
     if(rc == CL_CLEAN && ctx.found_possibly_unwanted)
@@ -2529,24 +2635,24 @@
 
 int cli_found_possibly_unwanted(cli_ctx* ctx)
 {
-	if(ctx->virname) {
-		cli_dbgmsg("found Possibly Unwanted: %s\n",*ctx->virname);
-		if(ctx->options & CL_SCAN_HEURISTIC_PRECEDENCE) {
-			/* we found a heuristic match, don't scan further,
-			 * but consider it a virus. */
-			cli_dbgmsg("cli_found_possibly_unwanted: CL_VIRUS\n");
-			return CL_VIRUS;
-		}
-		/* heuristic scan isn't taking precedence, keep scanning.
-		 * If this is part of an archive, and 
-		 * we find a real malware we report that instead of the 
-		 * heuristic match */
-		ctx->found_possibly_unwanted = 1;
-	} else {
-		cli_warnmsg("cli_found_possibly_unwanted called, but virname is not set\n");
+    if(cli_get_last_virus(ctx)) {
+	cli_dbgmsg("found Possibly Unwanted: %s\n", cli_get_last_virus(ctx));
+	if(ctx->options & CL_SCAN_HEURISTIC_PRECEDENCE) {
+	    /* we found a heuristic match, don't scan further,
+	     * but consider it a virus. */
+	    cli_dbgmsg("cli_found_possibly_unwanted: CL_VIRUS\n");
+	    return CL_VIRUS;
 	}
-	emax_reached(ctx);
-	return CL_CLEAN;
+	/* heuristic scan isn't taking precedence, keep scanning.
+	 * If this is part of an archive, and 
+	 * we find a real malware we report that instead of the 
+	 * heuristic match */
+	ctx->found_possibly_unwanted = 1;
+    } else {
+	cli_warnmsg("cli_found_possibly_unwanted called, but virname is not set\n");
+    }
+    emax_reached(ctx);
+    return CL_CLEAN;
 }
 
 static int cli_scanfile(const char *filename, cli_ctx *ctx)
diff -Nru clamav-0.97.6+dfsg/libclamav/special.c clamav-0.97.7+dfsg/libclamav/special.c
--- clamav-0.97.6+dfsg/libclamav/special.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/special.c	2013-03-11 11:23:21.000000000 -0400
@@ -77,7 +77,7 @@
     if (j < 2) {
 	retval = CL_CLEAN;
     } else if (retval==CL_VIRUS) {
-	*ctx->virname = "Heuristics.Worm.Mydoom.M.log";
+	cli_append_virus(ctx, "Heuristics.Worm.Mydoom.M.log");
     }
 
     return retval;
diff -Nru clamav-0.97.6+dfsg/libclamav/untar.c clamav-0.97.7+dfsg/libclamav/untar.c
--- clamav-0.97.6+dfsg/libclamav/untar.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/untar.c	2013-03-11 11:23:21.000000000 -0400
@@ -128,6 +128,7 @@
 	unsigned int files = 0;
 	char fullname[NAME_MAX + 1];
 	size_t currsize = 0;
+	unsigned int num_viruses = 0; 
 
 	cli_dbgmsg("In untar(%s, %d)\n", dir, desc);
 
@@ -159,8 +160,12 @@
 				close(fout);
 				if (!ctx->engine->keeptmp)
 					if (cli_unlink(fullname)) return CL_EUNLINK;
-				if (ret==CL_VIRUS)
+				if (ret==CL_VIRUS) {
+				    if (!SCAN_ALL)
 					return CL_VIRUS;
+				    else
+					num_viruses++;
+				}
 				fout = -1;
 			}
 
@@ -276,8 +281,12 @@
 
 			strncpy(name, block, 100);
 			name[100] = '\0';
-			if(cli_matchmeta(ctx, name, size, size, 0, files, 0, NULL) == CL_VIRUS)
-			    return CL_VIRUS;
+			if(cli_matchmeta(ctx, name, size, size, 0, files, 0, NULL) == CL_VIRUS) {
+			    if (!SCAN_ALL)
+				return CL_VIRUS;
+			    else
+				num_viruses++;
+			}
 
 			snprintf(fullname, sizeof(fullname)-1, "%s"PATHSEP"tar%02u", dir, files);
 			fullname[sizeof(fullname)-1] = '\0';
@@ -340,5 +349,7 @@
 		if (ret==CL_VIRUS)
 			return CL_VIRUS;
 	}
+	if (num_viruses)
+	    return CL_VIRUS;
 	return CL_CLEAN;
 }
diff -Nru clamav-0.97.6+dfsg/libclamav/unzip.c clamav-0.97.7+dfsg/libclamav/unzip.c
--- clamav-0.97.6+dfsg/libclamav/unzip.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/unzip.c	2013-03-11 11:23:21.000000000 -0400
@@ -350,7 +350,7 @@
 
   if(detect_encrypted && (LH_flags & F_ENCR) && DETECT_ENCRYPTED) {
     cli_dbgmsg("cli_unzip: Encrypted files found in archive.\n");
-    *ctx->virname = "Heuristics.Encrypted.Zip";
+    cli_append_virus(ctx, "Heuristics.Encrypted.Zip");
     *ret = CL_VIRUS;
     fmap_unneed_off(map, loff, SIZEOF_LH);
     return 0;
diff -Nru clamav-0.97.6+dfsg/libclamav/version.h clamav-0.97.7+dfsg/libclamav/version.h
--- clamav-0.97.6+dfsg/libclamav/version.h	2012-08-10 13:10:35.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/version.h	2013-03-11 12:02:27.000000000 -0400
@@ -1 +1 @@
-#define REPO_VERSION "devel-clamav-0.97.6"
+#define REPO_VERSION "devel-clamav-0.97.7"
diff -Nru clamav-0.97.6+dfsg/libclamav/wwunpack.c clamav-0.97.7+dfsg/libclamav/wwunpack.c
--- clamav-0.97.6+dfsg/libclamav/wwunpack.c	2012-05-15 14:34:23.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/wwunpack.c	2013-03-11 11:23:21.000000000 -0400
@@ -223,12 +223,22 @@
 
     structs = &exe[(0xffff&cli_readint32(&exe[pe+0x14]))+pe+0x18];
     for(i=0 ; i<scount ; i++) {
+	  if (!CLI_ISCONTAINED(exe, exesz, structs, 0x28)) {
+	    cli_dbgmsg("WWPack: structs pointer out of bounds\n");
+	    return CL_EFORMAT;
+	  }
+
       cli_writeint32(structs+8, sects[i].vsz);
       cli_writeint32(structs+12, sects[i].rva);
       cli_writeint32(structs+16, sects[i].vsz);
       cli_writeint32(structs+20, sects[i].rva);
       structs+=0x28;
     }
+	if (!CLI_ISCONTAINED(exe, exesz, structs, 0x28)) {
+	  cli_dbgmsg("WWPack: structs pointer out of bounds\n");
+	  return CL_EFORMAT;
+	}
+
     memset(structs, 0, 0x28);
     error = cli_writen(desc, exe, exesz)!=exesz;
   }
diff -Nru clamav-0.97.6+dfsg/libclamav/yc.c clamav-0.97.7+dfsg/libclamav/yc.c
--- clamav-0.97.6+dfsg/libclamav/yc.c	2012-05-15 14:34:23.000000000 -0400
+++ clamav-0.97.7+dfsg/libclamav/yc.c	2013-03-11 11:21:48.000000000 -0400
@@ -40,7 +40,7 @@
 /* ========================================================================== */
 /* "Emulates" the poly decryptors */
 
-static int yc_poly_emulator(char* decryptor_offset, char* code, unsigned int ecx)
+static int yc_poly_emulator(char* decryptor_offset, char* code, unsigned int ecx, uint32_t max_emu)
 {
 
   /* 
@@ -64,7 +64,7 @@
   unsigned char cl = ecx & 0xff;
   unsigned int j,i;
 
-  for(i=0;i<ecx;i++) /* Byte looper - Decrypts every byte and write it back */
+  for(i=0;i<ecx&&i<max_emu;i++) /* Byte looper - Decrypts every byte and write it back */
     {
       al = code[i];
 
@@ -168,7 +168,7 @@
   unsigned int i;
   struct pe_image_file_hdr *pe = (struct pe_image_file_hdr*) (fbuf + peoffset);
   char *sname = (char *)pe + EC16(pe->SizeOfOptionalHeader) + 0x18;
-
+  uint32_t max_emu;
   /* 
 
   First layer (decryptor of the section decryptor) in last section 
@@ -180,7 +180,7 @@
   */
   cli_dbgmsg("yC: offset: %x, length: %x\n", offset, ecx);
   cli_dbgmsg("yC: decrypting decryptor on sect %d\n", sectcount);
-  if (yc_poly_emulator(fbuf + ycsect + 0x93, fbuf + ycsect + 0xc6, ecx))
+  if (yc_poly_emulator(fbuf + ycsect + 0x93, fbuf + ycsect + 0xc6, ecx, ecx))
     return 1;
   filesize-=sections[sectcount].ursz;
 
@@ -190,31 +190,38 @@
 
   Start offset for analyze: Start of yC Section + 0x457
   End offset for analyze: Start of yC Section + 0x487
-  Lenght to decrypt - ECX = Raw Size of Section
+  Length to decrypt - ECX = Raw Size of Section
 
   */
 
 
   /* Loop through all sections and decrypt them... */
-  for(i=0;i<sectcount;i++)
-    {
-      uint32_t name = (uint32_t) cli_readint32(sname+i*0x28);
-      if (!sections[i].raw ||
-	  !sections[i].rsz ||
-	   name == 0x63727372 || /* rsrc */
-	   name == 0x7273722E || /* .rsr */
-	   name == 0x6F6C6572 || /* relo */
-	   name == 0x6C65722E || /* .rel */
-	   name == 0x6164652E || /* .eda */
-	   name == 0x6164722E || /* .rda */
-	   name == 0x6164692E || /* .ida */
-	   name == 0x736C742E || /* .tls */
-	   (name&0xffff) == 0x4379  /* yC */
+  for(i=0;i<sectcount;i++) {
+    uint32_t name = (uint32_t) cli_readint32(sname+i*0x28);
+    if (!sections[i].raw ||
+	!sections[i].rsz ||
+	name == 0x63727372 || /* rsrc */
+	name == 0x7273722E || /* .rsr */
+	name == 0x6F6C6572 || /* relo */
+	name == 0x6C65722E || /* .rel */
+	name == 0x6164652E || /* .eda */
+	name == 0x6164722E || /* .rda */
+	name == 0x6164692E || /* .ida */
+	name == 0x736C742E || /* .tls */
+	(name&0xffff) == 0x4379  /* yC */
 	) continue;
-      cli_dbgmsg("yC: decrypting sect%d\n",i);
-      if (yc_poly_emulator(fbuf + ycsect + (offset == -0x18 ? 0x3ea : 0x457), fbuf + sections[i].raw, sections[i].ursz))
-	  return 1;
+    cli_dbgmsg("yC: decrypting sect%d\n",i);
+    max_emu = filesize - sections[i].raw;
+    if (max_emu > filesize) {
+      cli_dbgmsg("yC: bad emulation length limit %u\n", max_emu);
+      return 1;
     }
+    if (yc_poly_emulator(fbuf + ycsect + (offset == -0x18 ? 0x3ea : 0x457), 
+			 fbuf + sections[i].raw, 
+			 sections[i].ursz, 
+			 max_emu))
+      return 1;
+  }
 
   /* Remove yC section */
   pe->NumberOfSections=EC16(sectcount);
diff -Nru clamav-0.97.6+dfsg/NEWS clamav-0.97.7+dfsg/NEWS
--- clamav-0.97.6+dfsg/NEWS	2012-09-17 11:16:40.000000000 -0400
+++ clamav-0.97.7+dfsg/NEWS	2013-03-11 11:23:20.000000000 -0400
@@ -1,9 +1,8 @@
-0.97.6
+0.97.7
 ------
-
-ClamAV 0.97.6 corrects two major bugs.  One is bb#5571, where an invalid return
-code was issued.  The other is 5252, where an error in processing certain data
-types occured.
+ClamAV 0.97.7 addresses several reported potential security bugs.  Thanks to
+Felix Groebert, Mateusz Jurczyk and Gynvael Coldwind of the Google Security
+Team for finding and reporting these issues.
 
 --
 The ClamAV team (http://www.clamav.net/team)
diff -Nru clamav-0.97.6+dfsg/README clamav-0.97.7+dfsg/README
--- clamav-0.97.6+dfsg/README	2012-09-17 11:02:22.000000000 -0400
+++ clamav-0.97.7+dfsg/README	2013-03-11 11:23:20.000000000 -0400
@@ -1,6 +1,12 @@
 Note: This README/NEWS file refers to the source tarball. Some things described
 here may not be available in binary packages.
 --
+0.97.7
+------
+ClamAV 0.97.7 addresses several reported potential security bugs.  Thanks to
+Felix Groebert, Mateusz Jurczyk and Gynvael Coldwind of the Google Security
+Team for finding and reporting these issues.
+
 0.97.6
 ------
 ClamAV 0.97.6 corrects bug 5252 "CL_EFORMAT: Bad format or broken data ERROR
diff -Nru clamav-0.97.6+dfsg/shared/optparser.c clamav-0.97.7+dfsg/shared/optparser.c
--- clamav-0.97.6+dfsg/shared/optparser.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/shared/optparser.c	2013-03-11 11:23:21.000000000 -0400
@@ -80,6 +80,7 @@
     { NULL, "multiscan", 'm', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMDSCAN, "", "" },
     { NULL, "fdpass", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMDSCAN, "", "" },
     { NULL, "stream", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMDSCAN, "", "" },
+    { NULL, "allmatch", 'z', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN | OPT_CLAMDSCAN, "", "" },
     { NULL, "database", 'd', TYPE_STRING, NULL, -1, DATADIR, FLAG_REQUIRED | FLAG_MULTIPLE, OPT_CLAMSCAN, "", "" }, /* merge it with DatabaseDirectory (and fix conflict with --datadir */
     { NULL, "recursive", 'r', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "", "" },
     { NULL, "follow-dir-symlinks", 0, TYPE_NUMBER, MATCH_NUMBER, 1, NULL, 0, OPT_CLAMSCAN, "", "" },
diff -Nru clamav-0.97.6+dfsg/sigtool/sigtool.c clamav-0.97.7+dfsg/sigtool/sigtool.c
--- clamav-0.97.6+dfsg/sigtool/sigtool.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/sigtool/sigtool.c	2013-03-11 11:23:21.000000000 -0400
@@ -108,6 +108,7 @@
     { "gdb",   1 },
     { "pdb",   1 },
     { "wdb",   0 },
+    { "crb", 1 },
 
     { NULL,	    0 }
 };
diff -Nru clamav-0.97.6+dfsg/unit_tests/check_bytecode.c clamav-0.97.7+dfsg/unit_tests/check_bytecode.c
--- clamav-0.97.6+dfsg/unit_tests/check_bytecode.c	2012-08-06 16:26:49.000000000 -0400
+++ clamav-0.97.7+dfsg/unit_tests/check_bytecode.c	2013-03-11 11:23:21.000000000 -0400
@@ -58,8 +58,11 @@
     uint64_t v;
     struct cl_engine *engine;
     int fdin = -1;
+    const char * virname = NULL;
 
     memset(&cctx, 0, sizeof(cctx));
+    cctx.options |= CL_SCAN_ALLMATCHES;
+    cctx.virname = &virname;
     cctx.engine = engine = cl_engine_new();
     fail_unless(!!cctx.engine, "cannot create engine");
     rc = cl_engine_compile(engine);
diff -Nru clamav-0.97.6+dfsg/unit_tests/check_matchers.c clamav-0.97.7+dfsg/unit_tests/check_matchers.c
--- clamav-0.97.6+dfsg/unit_tests/check_matchers.c	2012-05-15 14:34:23.000000000 -0400
+++ clamav-0.97.7+dfsg/unit_tests/check_matchers.c	2013-03-11 11:21:49.000000000 -0400
@@ -145,7 +145,83 @@
     ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, "*", 0, NULL, 0);
     fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed");
 
-    ret = cli_bm_scanbuff((const unsigned char*)"blah\xde\xad\xbe\xef", 12, &virname, NULL, root, 0, NULL, NULL);
+    ret = cli_bm_scanbuff((const unsigned char*)"blah\xde\xad\xbe\xef", 12, &virname, NULL, root, 0, NULL, NULL, NULL);
+    fail_unless(ret == CL_VIRUS, "cli_bm_scanbuff() failed");
+    fail_unless(!strncmp(virname, "Sig2", 4), "Incorrect signature matched in cli_bm_scanbuff()\n");
+}
+END_TEST
+
+START_TEST (test_ac_scanbuff_allscan) {
+	struct cli_ac_data mdata;
+	struct cli_matcher *root;
+	unsigned int i;
+	int ret;
+
+    root = ctx.engine->root[0];
+    fail_unless(root != NULL, "root == NULL");
+    root->ac_only = 1;
+
+#ifdef USE_MPOOL
+    root->mempool = mpool_create();
+#endif
+    ret = cli_ac_init(root, CLI_DEFAULT_AC_MINDEPTH, CLI_DEFAULT_AC_MAXDEPTH, 1);
+    fail_unless(ret == CL_SUCCESS, "cli_ac_init() failed");
+
+
+    for(i = 0; ac_testdata[i].data; i++) {
+	ret = cli_parse_add(root, ac_testdata[i].virname, ac_testdata[i].hexsig, 0, 0, "*", 0, NULL, 0);
+	fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed");
+    }
+
+    ret = cli_ac_buildtrie(root);
+    fail_unless(ret == CL_SUCCESS, "cli_ac_buildtrie() failed");
+
+    ret = cli_ac_initdata(&mdata, root->ac_partsigs, 0, 0, CLI_DEFAULT_AC_TRACKLEN);
+    fail_unless(ret == CL_SUCCESS, "cli_ac_initdata() failed");
+
+    ctx.options |= CL_SCAN_ALLMATCHES;
+    for(i = 0; ac_testdata[i].data; i++) {
+	ret = cli_ac_scanbuff((const unsigned char*)ac_testdata[i].data, strlen(ac_testdata[i].data), &virname, NULL, NULL, root, &mdata, 0, 0, NULL, AC_SCAN_VIR, NULL);
+	fail_unless_fmt(ret == CL_VIRUS, "cli_ac_scanbuff() failed for %s", ac_testdata[i].virname);
+	fail_unless_fmt(!strncmp(virname, ac_testdata[i].virname, strlen(ac_testdata[i].virname)), "Dataset %u matched with %s", i, virname);
+
+	ret = cli_scanbuff((const unsigned char*)ac_testdata[i].data, strlen(ac_testdata[i].data), 0, &ctx, 0, NULL);
+	fail_unless_fmt(ret == CL_VIRUS, "cli_scanbuff() failed for %s", ac_testdata[i].virname);
+	fail_unless_fmt(!strncmp(virname, ac_testdata[i].virname, strlen(ac_testdata[i].virname)), "Dataset %u matched with %s", i, virname);
+	if (ctx.num_viruses) {
+	    free((void *)ctx.virname);
+	    ctx.num_viruses = 0;
+	    ctx.size_viruses = 0;
+	}
+     }
+
+    cli_ac_freedata(&mdata);
+}
+END_TEST
+
+START_TEST (test_bm_scanbuff_allscan) {
+	struct cli_matcher *root;
+	const char *virname = NULL;
+	int ret;
+
+
+    root = ctx.engine->root[0];
+    fail_unless(root != NULL, "root == NULL");
+
+#ifdef USE_MPOOL
+    root->mempool = mpool_create();
+#endif
+    ret = cli_bm_init(root);
+    fail_unless(ret == CL_SUCCESS, "cli_bm_init() failed");
+
+    ret = cli_parse_add(root, "Sig1", "deadbabe", 0, 0, "*", 0, NULL, 0);
+    fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed");
+    ret = cli_parse_add(root, "Sig2", "deadbeef", 0, 0, "*", 0, NULL, 0);
+    fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed");
+    ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, "*", 0, NULL, 0);
+    fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed");
+
+    ret = cli_bm_scanbuff((const unsigned char*)"blah\xde\xad\xbe\xef", 12, &virname, NULL, root, 0, NULL, NULL, NULL);
     fail_unless(ret == CL_VIRUS, "cli_bm_scanbuff() failed");
     fail_unless(!strncmp(virname, "Sig2", 4), "Incorrect signature matched in cli_bm_scanbuff()\n");
 }
@@ -160,6 +236,8 @@
     tcase_add_checked_fixture (tc_matchers, setup, teardown);
     tcase_add_test(tc_matchers, test_ac_scanbuff);
     tcase_add_test(tc_matchers, test_bm_scanbuff);
+    tcase_add_test(tc_matchers, test_ac_scanbuff_allscan);
+    tcase_add_test(tc_matchers, test_bm_scanbuff_allscan);
     return s;
 }
 
diff -Nru clamav-0.97.6+dfsg/unit_tests/check_regex.c clamav-0.97.7+dfsg/unit_tests/check_regex.c
--- clamav-0.97.6+dfsg/unit_tests/check_regex.c	2012-05-15 14:34:23.000000000 -0400
+++ clamav-0.97.7+dfsg/unit_tests/check_regex.c	2013-03-11 11:21:49.000000000 -0400
@@ -425,12 +425,85 @@
 	}
 }
 
+static void do_phishing_test_allscan(const struct rtest *rtest)
+{
+	char *realurl;
+	cli_ctx ctx;
+	const char *virname = NULL;
+	tag_arguments_t hrefs;
+	int rc;
+
+	memset(&ctx, 0, sizeof(ctx));
+
+	realurl = cli_strdup(rtest->realurl);
+	fail_unless(!!realurl, "cli_strdup");
+
+	hrefs.count = 1;
+	hrefs.value = cli_malloc(sizeof(*hrefs.value));
+	fail_unless(!!hrefs.value, "cli_malloc");
+	hrefs.value[0] = (unsigned char*)realurl;
+	hrefs.contents = cli_malloc(sizeof(*hrefs.contents));
+	fail_unless(!!hrefs.contents, "cli_malloc");
+	hrefs.tag = cli_malloc(sizeof(*hrefs.tag));
+	fail_unless(!!hrefs.tag, "cli_malloc");
+	hrefs.tag[0] = (unsigned char*)cli_strdup("href");
+	hrefs.contents[0] = (unsigned char*)cli_strdup(rtest->displayurl);
+
+	ctx.engine = engine;
+	ctx.virname = &virname;
+	ctx.options |= CL_SCAN_ALLMATCHES;
+
+	rc = phishingScan(&ctx, &hrefs);
+
+	html_tag_arg_free(&hrefs);
+	fail_unless(rc == CL_CLEAN,"phishingScan");
+	switch(rtest->result) {
+		case 0:
+			fail_unless_fmt(ctx.found_possibly_unwanted,
+					"this should be phishing, realURL: %s, displayURL: %s",
+					rtest->realurl, rtest->displayurl);
+			break;
+		case 1:
+			fail_unless_fmt(!ctx.found_possibly_unwanted,
+					"this should be whitelisted, realURL: %s, displayURL: %s",
+					rtest->realurl, rtest->displayurl);
+			break;
+		case 2:
+			fail_unless_fmt(!ctx.found_possibly_unwanted,
+					"this should be clean, realURL: %s, displayURL: %s",
+					rtest->realurl, rtest->displayurl);
+			break;
+		case 3:
+			if(!loaded_2)
+				fail_unless_fmt(!ctx.found_possibly_unwanted,
+					"this should be clean, realURL: %s, displayURL: %s",
+					rtest->realurl, rtest->displayurl);
+			else {
+				fail_unless_fmt(ctx.found_possibly_unwanted,
+					"this should be blacklisted, realURL: %s, displayURL: %s",
+					rtest->realurl, rtest->displayurl);
+				if (*ctx.virname)
+				    fail_unless_fmt(!strstr((const char*)*ctx.virname,"Blacklisted"),
+						    "should be blacklisted, but is: %s\n", ctx.virname);
+			}
+			break;
+	}
+	if (ctx.num_viruses)
+	    free((void *)ctx.virname);
+}
+
 #ifdef CHECK_HAVE_LOOPS
 START_TEST (phishingScan_test)
 {
 	do_phishing_test(&rtests[_i]);
 }
 END_TEST
+
+START_TEST (phishingScan_test_allscan)
+{
+	do_phishing_test_allscan(&rtests[_i]);
+}
+END_TEST
 #endif
 
 #ifdef CHECK_HAVE_LOOPS
@@ -515,6 +588,27 @@
 }
 END_TEST
 
+START_TEST(phishing_fake_test_allscan)
+{
+	char buf[4096];
+	FILE *f = fdopen(open_testfile("input/daily.pdb"),"r");
+	fail_unless(!!f,"fopen daily.pdb");
+	while(fgets(buf, sizeof(buf), f)) {
+		struct rtest rtest;
+		const char *pdb = strchr(buf,':');
+		fail_unless(!!pdb, "missing : in pdb");
+		rtest.realurl = pdb;
+		rtest.displayurl = pdb;
+		rtest.result = 2;
+		do_phishing_test_allscan(&rtest);
+		rtest.realurl = "http://fake.example.com";;
+		rtest.result = 0;
+		do_phishing_test_allscan(&rtest);
+	}
+	fclose(f);
+}
+END_TEST
+
 Suite *test_regex_suite(void)
 {
 	Suite *s = suite_create("regex");
@@ -539,16 +633,20 @@
 	tcase_add_unchecked_fixture(tc_phish, psetup, pteardown);
 #ifdef CHECK_HAVE_LOOPS
 	tcase_add_loop_test(tc_phish, phishingScan_test, 0, sizeof(rtests)/sizeof(rtests[0]));
+	tcase_add_loop_test(tc_phish, phishingScan_test_allscan, 0, sizeof(rtests)/sizeof(rtests[0]));
 #endif
 	tcase_add_test(tc_phish, phishing_fake_test);
+	tcase_add_test(tc_phish, phishing_fake_test_allscan);
 
 	tc_phish2 = tcase_create("phishingScan with 2 dbs");
 	suite_add_tcase(s, tc_phish2);
 	tcase_add_unchecked_fixture(tc_phish2, psetup2, pteardown);
 #ifdef CHECK_HAVE_LOOPS
 	tcase_add_loop_test(tc_phish2, phishingScan_test, 0, sizeof(rtests)/sizeof(rtests[0]));
+	tcase_add_loop_test(tc_phish2, phishingScan_test_allscan, 0, sizeof(rtests)/sizeof(rtests[0]));
 #endif
 	tcase_add_test(tc_phish2, phishing_fake_test);
+	tcase_add_test(tc_phish2, phishing_fake_test_allscan);
 #ifdef CHECK_HAVE_LOOPS
 	tcase_add_loop_test(tc_phish, test_url_canon, 0, sizeof(uc)/sizeof(uc[0]));
 #endif

Reply to: