diff --git a/ChangeLog b/ChangeLog
index d782c62a8..47320ecf7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Thu Oct 3 10:49:11 2013 EDT 2013 (dar)
+------------------------------------
+ * bb #1570: Support ADC compression in DMG
+
Wed Oct 2 11:22:40 2013 EDT 2013 (dar)
------------------------------------
* bb #9053: ClamAV 0.98 can't be compiled on FreeBSD 7
diff --git a/docs/clamdoc.tex b/docs/clamdoc.tex
index 9609c2f6a..259988b7f 100644
--- a/docs/clamdoc.tex
+++ b/docs/clamdoc.tex
@@ -316,6 +316,7 @@
\begin{verbatim}
$ ./configure --enable-milter
\end{verbatim}
+ See section /ref{sec:clamavmilter} for more details on clamav-milter.
\subsection{Running unit tests}\label{unit-testing}
ClamAV includes unit tests that allow you to test that the compiled binaries work correctly on your platform.
@@ -391,8 +392,36 @@ $ CK_FORK=no ./libtool --mode=execute valgrind unit_tests/check-clamav
\end{verbatim}
\end{itemize}
+ \subsection{Obtain Latest ClamAV anti-virus signature databases}
+ Before you can run ClamAV in daemon mode (clamd), 'clamdscan',
+ or 'clamscan' which is ClamAV's command line virus scanner,
+ you must have ClamAV Virus Database (.cvd) file(s) installed
+ in the appropriate location on your system. The default
+ location for these database files are /usr/local/share/clamav
+ (in Linux/Unix).
+ \\\\
+ Here is a listing of currently available ClamAV Virus Database Files:
+ \\\\
+ bytecode.cvd (signatures to detect bytecode in files)
+ main.cvd (main ClamAV virus database file)
+ daily.cvd (daily update file for ClamAV virus databases)
+ safebrowsing.cvd (virus signatures for safe browsing)
+ \\\\
+ These files can be downloaded via HTTP from the main ClamAV website
+ or via the 'freshclam' utility on a periodic basis. Using 'freshclam'
+ is the preferred method of keeping the ClamAV virus database files
+ up to date without manual intervention (see section \ref{conf:freshclam} for
+ information on how to configure 'freshclam' for automatic updating and section
+ \ref{sec:freshclam} for additional details on freshclam).
+
\section{Configuration}
+ \subsubsection{clamconf}
+ Before proceeding with the steps below, you should
+ run the 'clamconf' command, which gives important information
+ about your ClamAV configuration. See section \ref{sec:clamconf}
+ for more details.
+
\subsection{clamd}
Before you start using the daemon you have to edit the configuration file
(in other case \verb+clamd+ won't run):
@@ -437,14 +466,31 @@ $ CK_FORK=no ./libtool --mode=execute valgrind unit_tests/check-clamav
Now configure Clamuko in \verb+clamd.conf+ and read the \ref{clamuko}
section.
- \subsection{clamav-milter}
+ \subsection{clamav-milter}\label{sec:clamavmilter}
ClamAV $\ge0.95$ includes a new, redesigned clamav-milter. The most notable
difference is that the internal mode has been dropped and now a working
clamd companion is required. The second important difference is that now
- the milter has got its own configuration and log files. To compile ClamAV
- with the clamav-milter just run \verb+./configure+ \verb+--enable-milter+
- and make as usual. Please consult your MTA's manual on how to connect it
- with the milter.
+ the milter has got its own configuration and log files.
+
+ To compile ClamAV with the clamav-milter just run \verb+./configure+
+ \verb+--enable-milter+ and make as usual. In order to use the
+ '--enable-milter' option with 'configure', your system MUST have the milter
+ library installed. If you use the '--enable-milter' option without the
+ library being installed, you will most likely see output like this during
+ 'configure':
+ \begin{verbatim}
+ checking for libiconv_open in -liconv... no
+ checking for iconv... yes
+ checking whether in_port_t is defined... yes
+ checking for in_addr_t definition... yes
+ checking for mi_stop in -lmilter... no
+ checking for library containing strlcpy... no
+ checking for mi_stop in -lmilter... no
+ configure: error: Cannot find libmilter
+ \end{verbatim}
+ At which point the 'configure' script will stop processing.
+ \\\\
+ Please consult your MTA's manual on how to connect ClamAV with the milter.
\subsection{Testing}
Try to scan recursively the source directory:
@@ -462,7 +508,7 @@ $ CK_FORK=no ./libtool --mode=execute valgrind unit_tests/check-clamav
Please note that the scanned files must be accessible by the user running
\verb+clamd+ or you will get an error.
- \subsection{Setting up auto-updating}
+ \subsection{Setting up auto-updating}\label{conf:freshclam}
\verb+freshclam+ is the automatic database update tool for Clam AntiVirus.
It can work in two modes:
\begin{itemize}
@@ -704,6 +750,108 @@ N * * * * /usr/local/bin/freshclam --quiet
more better and safe idea is to use the \textbf{samba-vscan} module.
NFS is not supported because Dazuko doesn't intercept NFS access calls.
+ \subsection{Clamdtop}
+ \verb+clamdtop+ is a tool to monitor one or multiple instances of clamd. It
+ has a (color) ncurses interface, that shows the jobs in clamd's queue,
+ memory usage, and information about the loaded signature database.
+ You can specify on the command-line to which clamd(s) it should connect
+ to. By default it will attempt to connect to the local clamd as defined
+ in clamd.conf.
+ \\\\
+ For more detailed help, type 'man clamdtop' or 'clamdtop --help'.
+
+ \subsection{Clamscan}
+ \verb+clamscan+ is ClamAV's command line virus scanner. It can be used to
+ scan files and/or directories for viruses. In order for clamscan
+ to work proper, the ClamAV virus database files must be installed on
+ the system you are using clamscan on.
+ \\\\
+ The general usage of clamscan is: clamscan [options] [file/directory/-]
+ \\\\
+ For more detailed help, type 'man clamscan' or 'clamscan --help'.
+
+ \subsection{ClamBC}
+ \verb+clambc+ is Clam Anti-Virus' bytecode testing tool. It can be
+ used to test files which contain bytecode. For more detailed help,
+ type 'man clambc' or 'clambc --help'.
+
+ \subsection{Freshclam}\ref{sec:freshclam}
+ \verb+freshclam+ is ClamAV's virus database update tool and reads it's
+ configuration from the file 'freshclam.conf' (this may be
+ overriden by command line options). Here is a sample usage including cdiffs:
+ \begin{verbatim}
+ $ freshclam
+
+ ClamAV update process started at Mon Oct 7 08:15:10 2013
+ main.cld is up to date (version: 55, sigs: 2424225, f-level: 60, builder: neo)
+ Downloading daily-17945.cdiff [100%]
+ Downloading daily-17946.cdiff [100%]
+ Downloading daily-17947.cdiff [100%]
+ daily.cld updated (version: 17947, sigs: 406951, f-level: 63, builder: neo)
+ Downloading bytecode-227.cdiff [100%]
+ Downloading bytecode-228.cdiff [100%]
+ bytecode.cld updated (version: 228, sigs: 43, f-level: 63, builder: neo)
+ Database updated (2831219 signatures) from database.clamav.net (IP: 64.6.100.177)
+ \end{verbatim}
+ For more detailed help, type 'man clamscan' or 'clamscan --help'.
+
+ \subsection{Clamconf}\label{sec:clamconf}
+ \verb+clamconf+ is the Clam Anti-Virus configuration utility. It is used
+ for displaying values of configurations options in ClamAV, which
+ will show the contents of clamd.conf (or tell you if it is not
+ properly configured), the contents of freshclam.conf, and display
+ information about software settings, database, platform, and build
+ information. Here is a sample clamconf output:
+ \begin{verbatim}
+ $ clamconf
+
+ Checking configuration files in /etc/clamav
+
+ Config file: clamd.conf
+ -----------------------
+ ERROR: Please edit the example config file /etc/clamav/clamd.conf
+
+ Config file: freshclam.conf
+ ---------------------------
+ ERROR: Please edit the example config file /etc/clamav/freshclam.conf
+
+ clamav-milter.conf not found
+
+ Software settings
+ -----------------
+ Version: 0.97.6
+ Optional features supported: MEMPOOL IPv6 CLAMUKO AUTOIT_EA06 BZIP2 RAR JIT
+
+ Database information
+ --------------------
+ Database directory: /usr/local/share/clamav
+ WARNING: freshclam.conf and clamd.conf point to different database directories
+ print_dbs: Can't open directory /usr/local/share/clamav
+
+ Platform information
+ --------------------
+ uname: Linux 2.6.32-279.el6.x86_64 #1 SMP Fri Jun 22 12:19:21 UTC 2012 x86_64
+ OS: linux-gnu, ARCH: x86_64, CPU: x86_64
+ Full OS version: ``CentOS release 6.3 (Final)''
+ zlib version: 1.2.3 (1.2.3), compile flags: a9
+ Triple: x86_64-unknown-linux-gnu
+ CPU: amdfam10, Little-endian
+ platform id: 0x0a2143430804040607040406
+
+ Build information
+ -----------------
+ GNU C: 4.4.6 20120305 (Red Hat 4.4.6-4) (4.4.6)
+ GNU C++: 4.4.6 20120305 (Red Hat 4.4.6-4) (4.4.6)
+ CPPFLAGS:
+ CFLAGS: -g -O2 -fno-strict-aliasing
+ CXXFLAGS:
+ LDFLAGS:
+ Configure: '--enable-check' '--sysconfdir=/etc/clamav'
+ --enable-ltdl-convenience
+ sizeof(void*) = 8
+ \end{verbatim}
+ For more detailed help, type 'man clamconf' or 'clamconf --help'.
+
\subsection{Output format}
\subsubsection{clamscan}
@@ -723,7 +871,7 @@ N * * * * /usr/local/bin/freshclam --quiet
\verb+FOUND+ strings. In case of archives the scanner depends on libclamav
and only prints the first virus found within an archive:
\begin{verbatim}
- zolw@localhost:/tmp$ clamscan malware.zip
+ $ clamscan malware.zip
malware.zip: Worm.Mydoom.U FOUND
\end{verbatim}
When using the --allmatch(-z) flag, clamscan may print multiple virus
@@ -732,7 +880,7 @@ N * * * * /usr/local/bin/freshclam --quiet
\subsubsection{clamd}
The output format of \verb+clamd+ is very similar to \verb+clamscan+.
\begin{verbatim}
- zolw@localhost:~$ telnet localhost 3310
+ $ telnet localhost 3310
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
@@ -823,8 +971,14 @@ N * * * * /usr/local/bin/freshclam --quiet
decoding and normalization is only performed for HTML files.
\subsubsection{Data Loss Prevention}
- Libclamav includes a DLP module which can detect credit card and
- social security numbers inside text files.
+ Libclamav includes a DLP module which can detect the following
+ credit card issuers: AMEX, VISA, MasterCard, Discover, Diner's Club,
+ and JCB and U.S. social security numbers inside text files.
+ \\\\
+ Future versions of Libclamav may include additional features to
+ detect other credit cards and other forms of PII (Personally
+ Identifiable Information) which may be transmitted without the
+ benefit of being encrypted.
\subsubsection{Others}
Libclamav can handle various obfuscators, encoders, files vulnerable to
@@ -1115,9 +1269,9 @@ const char *cl_engine_get_str(const struct cl_engine *engine,
\subsubsection{clamav-config}
Use \verb+clamav-config+ to check compilation information for libclamav.
\begin{verbatim}
- zolw@localhost:~$ clamav-config --libs
+ $ clamav-config --libs
-L/usr/local/lib -lz -lbz2 -lgmp -lpthread
- zolw@localhost:~$ clamav-config --cflags
+ $ clamav-config --cflags
-I/usr/local/include -g -O2
\end{verbatim}
@@ -1139,7 +1293,7 @@ level required:MD5 checksum:digital signature:builder name:build time (sec)
\end{verbatim}
\verb+sigtool --info+ displays detailed information on CVD files:
\begin{verbatim}
-zolw@localhost:/usr/local/share/clamav$ sigtool -i daily.cvd
+$ sigtool -i daily.cvd
File: daily.cvd
Build time: 10 Mar 2008 10:45 +0000
Version: 6191
diff --git a/docs/html/node45.html b/docs/html/node45.html
index bb0822cf1..2ebfee34f 100644
--- a/docs/html/node45.html
+++ b/docs/html/node45.html
@@ -64,6 +64,9 @@ Initialization
struct cl_engine *cl_engine_new(void);
int cl_engine_free(struct cl_engine *engine);
+ At this time, cl_init()
only supports the CL_INIT_DEFAULT
option
+ which intializes libclamav with the default settings.
+
cl_init()
and cl_engine_free()
return CL_SUCCESS
on success or another code on error. cl_engine_new()
return
a pointer or NULL if there's not enough memory to allocate a new
diff --git a/docs/html/node46.html b/docs/html/node46.html
index 393be2402..8a9435975 100644
--- a/docs/html/node46.html
+++ b/docs/html/node46.html
@@ -108,7 +108,7 @@ Load bytecode.
unsigned int sigs = 0;
int ret;
- if((ret = cl_init()) != CL_SUCCESS) {
+ if((ret = cl_init(CL_INIT_DEFAULT)) != CL_SUCCESS) {
printf("cl_init() error: %s\n", cl_strerror(ret));
return 1;
}
diff --git a/etc/clamd.conf.sample b/etc/clamd.conf.sample
index 9aab51ab2..ca6d85db1 100644
--- a/etc/clamd.conf.sample
+++ b/etc/clamd.conf.sample
@@ -222,8 +222,8 @@ Example
#DetectPUA yes
# Exclude a specific PUA category. This directive can be used multiple times.
-# See http://www.clamav.net/support/pua for the complete list of PUA
-# categories.
+# See https://github.com/vrtadmin/clamav-faq/blob/master/faq/faq-pua.md for
+# the complete list of PUA categories.
# Default: Load all categories (if DetectPUA is activated)
#ExcludePUA NetTool
#ExcludePUA PWTool
diff --git a/libclamav/Makefile.am b/libclamav/Makefile.am
index 51a67f0d8..131a0423d 100644
--- a/libclamav/Makefile.am
+++ b/libclamav/Makefile.am
@@ -386,6 +386,8 @@ libclamav_la_SOURCES = \
builtin_bytecodes.h\
events.c\
events.h \
+ adc.c \
+ adc.h \
dmg.c \
dmg.h \
xar.c \
diff --git a/libclamav/Makefile.in b/libclamav/Makefile.in
index 81d9f2a0c..2597a0324 100644
--- a/libclamav/Makefile.in
+++ b/libclamav/Makefile.in
@@ -172,10 +172,10 @@ am_libclamav_la_OBJECTS = libclamav_la-matcher-ac.lo \
libclamav_la-macho.lo libclamav_la-ishield.lo \
libclamav_la-bytecode_api.lo libclamav_la-bytecode_api_decl.lo \
libclamav_la-cache.lo libclamav_la-bytecode_detect.lo \
- libclamav_la-events.lo libclamav_la-dmg.lo libclamav_la-xar.lo \
- libclamav_la-xz_iface.lo libclamav_la-sf_base64decode.lo \
- libclamav_la-hfsplus.lo libclamav_la-swf.lo \
- libclamav_la-jpeg.lo libclamav_la-png.lo \
+ libclamav_la-events.lo libclamav_la-adc.lo libclamav_la-dmg.lo \
+ libclamav_la-xar.lo libclamav_la-xz_iface.lo \
+ libclamav_la-sf_base64decode.lo libclamav_la-hfsplus.lo \
+ libclamav_la-swf.lo libclamav_la-jpeg.lo libclamav_la-png.lo \
libclamav_la-iso9660.lo libclamav_la-arc4.lo \
libclamav_la-rijndael.lo libclamav_la-crtmgr.lo \
libclamav_la-asn1.lo libclamav_la-fp_add.lo \
@@ -697,11 +697,11 @@ libclamav_la_SOURCES = clamav.h matcher-ac.c matcher-ac.h matcher-bm.c \
bcfeatures.h bytecode_api.c bytecode_api_decl.c bytecode_api.h \
bytecode_api_impl.h bytecode_hooks.h cache.c cache.h \
bytecode_detect.c bytecode_detect.h builtin_bytecodes.h \
- events.c events.h dmg.c dmg.h xar.c xar.h xz_iface.c \
- xz_iface.h sf_base64decode.c sf_base64decode.h hfsplus.c \
- hfsplus.h swf.c swf.h jpeg.c jpeg.h png.c png.h iso9660.c \
- iso9660.h arc4.c arc4.h rijndael.c rijndael.h crtmgr.c \
- crtmgr.h asn1.c asn1.h bignum.h bignum_fast.h \
+ events.c events.h adc.c adc.h dmg.c dmg.h xar.c xar.h \
+ xz_iface.c xz_iface.h sf_base64decode.c sf_base64decode.h \
+ hfsplus.c hfsplus.h swf.c swf.h jpeg.c jpeg.h png.c png.h \
+ iso9660.c iso9660.h arc4.c arc4.h rijndael.c rijndael.h \
+ crtmgr.c crtmgr.h asn1.c asn1.h bignum.h bignum_fast.h \
tomsfastmath/addsub/fp_add.c tomsfastmath/addsub/fp_add_d.c \
tomsfastmath/addsub/fp_addmod.c tomsfastmath/addsub/fp_cmp.c \
tomsfastmath/addsub/fp_cmp_d.c \
@@ -911,6 +911,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-XzCrc64.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-XzDec.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-XzIn.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-adc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-arc4.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-asn1.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-aspack.Plo@am__quote@
@@ -1907,6 +1908,13 @@ libclamav_la-events.lo: events.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-events.lo `test -f 'events.c' || echo '$(srcdir)/'`events.c
+libclamav_la-adc.lo: adc.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-adc.lo -MD -MP -MF $(DEPDIR)/libclamav_la-adc.Tpo -c -o libclamav_la-adc.lo `test -f 'adc.c' || echo '$(srcdir)/'`adc.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-adc.Tpo $(DEPDIR)/libclamav_la-adc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='adc.c' object='libclamav_la-adc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-adc.lo `test -f 'adc.c' || echo '$(srcdir)/'`adc.c
+
libclamav_la-dmg.lo: dmg.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-dmg.lo -MD -MP -MF $(DEPDIR)/libclamav_la-dmg.Tpo -c -o libclamav_la-dmg.lo `test -f 'dmg.c' || echo '$(srcdir)/'`dmg.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-dmg.Tpo $(DEPDIR)/libclamav_la-dmg.Plo
diff --git a/libclamav/adc.c b/libclamav/adc.c
new file mode 100644
index 000000000..06290db84
--- /dev/null
+++ b/libclamav/adc.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2013 Sourcefire, Inc.
+ *
+ * Authors: David Raynor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include
+#include
+#if HAVE_STRING_H
+#include
+#endif
+
+#include "cltypes.h"
+#include "others.h"
+#include "adc.h"
+
+/* #define DEBUG_ADC */
+
+#ifdef DEBUG_ADC
+# define adc_dbgmsg(...) cli_dbgmsg( __VA_ARGS__ )
+#else
+# define adc_dbgmsg(...) ;
+#endif
+
+/* Initialize values and collect buffer
+ * NOTE: buffer size must be larger than largest lookback offset */
+int adc_decompressInit(adc_stream *strm)
+{
+ if (strm == NULL) {
+ return ADC_IO_ERROR;
+ }
+ if (strm->state != ADC_STATE_UNINIT) {
+ return ADC_DATA_ERROR;
+ }
+
+ /* Have to buffer maximum backward lookup */
+ strm->buffer = (uint8_t *)calloc(ADC_BUFF_SIZE, 1);
+ if (strm->buffer == NULL) {
+ return ADC_MEM_ERROR;
+ }
+ strm->buffered = 0;
+ strm->state = ADC_STATE_GETTYPE;
+ strm->length = 0;
+ strm->offset = 0;
+ strm->curr = strm->buffer;
+
+ return ADC_OK;
+}
+
+/* Decompress routine
+ * NOTE: Reaching end of input buffer does not mean end of output.
+ * It may fill the output buffer but have more to output.
+ * It will only return ADC_STREAM_END if output buffer is not full.
+ * It will return ADC_DATA_ERROR if it ends in the middle of a phrase
+ * (i.e. in the middle of a lookback code or data run)
+ */
+int adc_decompress(adc_stream *strm)
+{
+ uint8_t bData;
+ uint8_t didNothing = 1;
+
+ /* first, the error returns based on strm */
+ if ((strm == NULL) || (strm->next_in == NULL) || (strm->next_out == NULL)) {
+ return ADC_IO_ERROR;
+ }
+ if (strm->state == ADC_STATE_UNINIT) {
+ return ADC_DATA_ERROR;
+ }
+
+ cli_dbgmsg("adc_decompress: avail_in %lu avail_out %lu state %u\n", strm->avail_in, strm->avail_out, strm->state);
+
+ while (strm->avail_out) {
+ /* Exit if needs more in bytes and none available */
+ int needsInput;
+ switch (strm->state) {
+ case ADC_STATE_SHORTLOOK:
+ case ADC_STATE_LONGLOOK:
+ needsInput = 0;
+ break;
+ default:
+ needsInput = 1;
+ break;
+ }
+ if (needsInput && (strm->avail_in == 0)) {
+ break;
+ }
+ else {
+ didNothing = 0;
+ }
+
+ /* Find or execute statecode */
+ switch (strm->state) {
+ case ADC_STATE_GETTYPE: {
+ /* Grab action code */
+ bData = *(strm->next_in);
+ strm->next_in++;
+ strm->avail_in--;
+ if (bData & 0x80) {
+ strm->state = ADC_STATE_RAWDATA;
+ strm->offset = 0;
+ strm->length = (bData & 0x7F) + 1;
+ }
+ else if (bData & 0x40) {
+ strm->state = ADC_STATE_LONGOP2;
+ strm->offset = 0;
+ strm->length = (bData & 0x3F) + 4;
+ }
+ else {
+ strm->state = ADC_STATE_SHORTOP;
+ strm->offset = (bData & 0x3) * 0x100;
+ strm->length = ((bData & 0x3C) >> 2) + 3;
+ }
+ adc_dbgmsg("adc_decompress: GETTYPE bData %x state %u offset %u length %u\n",
+ bData, strm->state, strm->offset, strm->length);
+ break;
+ }
+ case ADC_STATE_LONGOP2: {
+ /* Grab first offset byte */
+ bData = *(strm->next_in);
+ strm->next_in++;
+ strm->avail_in--;
+ strm->offset = bData * 0x100;
+ strm->state = ADC_STATE_LONGOP1;
+ adc_dbgmsg("adc_decompress: LONGOP2 bData %x state %u offset %u length %u\n",
+ bData, strm->state, strm->offset, strm->length);
+ break;
+ }
+ case ADC_STATE_LONGOP1: {
+ /* Grab second offset byte */
+ bData = *(strm->next_in);
+ strm->next_in++;
+ strm->avail_in--;
+ strm->offset += bData + 1;
+ strm->state = ADC_STATE_LONGLOOK;
+ adc_dbgmsg("adc_decompress: LONGOP1 bData %x state %u offset %u length %u\n",
+ bData, strm->state, strm->offset, strm->length);
+ break;
+ }
+ case ADC_STATE_SHORTOP: {
+ /* Grab offset byte */
+ bData = *(strm->next_in);
+ strm->next_in++;
+ strm->avail_in--;
+ strm->offset += bData + 1;
+ strm->state = ADC_STATE_SHORTLOOK;
+ adc_dbgmsg("adc_decompress: SHORTOP bData %x state %u offset %u length %u\n",
+ bData, strm->state, strm->offset, strm->length);
+ break;
+ }
+
+ case ADC_STATE_RAWDATA: {
+ /* Grab data */
+ adc_dbgmsg("adc_decompress: RAWDATA offset %u length %u\n", strm->offset, strm->length);
+ while ((strm->avail_in > 0) && (strm->avail_out > 0) && (strm->length > 0)) {
+ bData = *(strm->next_in);
+ strm->next_in++;
+ strm->avail_in--;
+ /* store to output */
+ *(strm->next_out) = bData;
+ strm->next_out++;
+ strm->avail_out--;
+ /* store to buffer */
+ if (strm->curr >= (strm->buffer + ADC_BUFF_SIZE)) {
+ strm->curr = strm->buffer;
+ }
+ *(strm->curr) = bData;
+ strm->curr++;
+ if (strm->buffered < ADC_BUFF_SIZE) {
+ strm->buffered++;
+ }
+ strm->length--;
+ }
+ if (strm->length == 0) {
+ /* adc_dbgmsg("adc_decompress: RAWDATADONE buffered %u avail_in %u avail_out %u \n",
+ strm->buffered, strm->avail_in, strm->avail_out); */
+ strm->state = ADC_STATE_GETTYPE;
+ }
+ break;
+ }
+
+ case ADC_STATE_SHORTLOOK:
+ case ADC_STATE_LONGLOOK: {
+ /* Copy data */
+ adc_dbgmsg("adc_decompress: LOOKBACK offset %u length %u avail_in %u avail_out %u\n",
+ strm->offset, strm->length, strm->avail_in, strm->avail_out);
+ while ((strm->avail_out > 0) && (strm->length > 0)) {
+ /* state validation first */
+ if (strm->offset > 0x10000) {
+ cli_dbgmsg("adc_decompress: bad LOOKBACK offset %u\n", strm->offset);
+ return ADC_DATA_ERROR;
+ }
+ else if ((strm->state == ADC_STATE_SHORTLOOK) && (strm->offset > 0x400)) {
+ cli_dbgmsg("adc_decompress: bad LOOKBACK offset %u\n", strm->offset);
+ return ADC_DATA_ERROR;
+ }
+ if (strm->offset > strm->buffered) {
+ cli_dbgmsg("adc_decompress: too large LOOKBACK offset %u\n", strm->offset);
+ return ADC_DATA_ERROR;
+ }
+ /* retrieve byte */
+ if (strm->curr >= (strm->buffer + ADC_BUFF_SIZE)) {
+ strm->curr = strm->buffer;
+ }
+ if (strm->curr > (strm->buffer + strm->offset)) {
+ bData = *(uint8_t *)(strm->curr - strm->offset);
+ }
+ else {
+ bData = *(uint8_t *)(strm->curr + ADC_BUFF_SIZE - strm->offset);
+ }
+ /* store to output */
+ *(strm->next_out) = bData;
+ strm->next_out++;
+ strm->avail_out--;
+ /* store to buffer */
+ *(strm->curr) = bData;
+ strm->curr++;
+ if (strm->buffered < ADC_BUFF_SIZE) {
+ strm->buffered++;
+ }
+ strm->length--;
+ }
+ if (strm->length == 0) {
+ strm->state = ADC_STATE_GETTYPE;
+ /* adc_dbgmsg("adc_decompress: LOOKBACKDONE buffered %u avail_in %u avail_out %u \n",
+ strm->buffered, strm->avail_in, strm->avail_out); */
+ }
+ break;
+ }
+
+ default: {
+ /* bad state */
+ cli_errmsg("adc_decompress: invalid state %u\n", strm->state);
+ return ADC_DATA_ERROR;
+ }
+ } /* end switch */
+ } /* end while */
+
+ /* There really isn't a terminator, just end of data */
+ if (didNothing && strm->avail_out) {
+ if (strm->state == ADC_STATE_GETTYPE) {
+ /* Nothing left to do */
+ return ADC_STREAM_END;
+ }
+ else {
+ /* Ended mid phrase */
+ cli_dbgmsg("adc_decompress: stream ended mid-phrase, state %u\n", strm->state);
+ return ADC_DATA_ERROR;
+ }
+ }
+ return ADC_OK;
+}
+
+/* Cleanup routine, frees buffer */
+int adc_decompressEnd(adc_stream *strm)
+{
+ if (strm == NULL) {
+ return ADC_IO_ERROR;
+ }
+ if (strm->state == ADC_STATE_UNINIT) {
+ return ADC_DATA_ERROR;
+ }
+
+ if (strm->buffer != NULL) {
+ free(strm->buffer);
+ }
+ strm->buffered = 0;
+ strm->state = ADC_STATE_UNINIT;
+ strm->length = 0;
+ strm->offset = 0;
+
+ return ADC_OK;
+}
+
diff --git a/libclamav/adc.h b/libclamav/adc.h
new file mode 100644
index 000000000..f63b74a8f
--- /dev/null
+++ b/libclamav/adc.h
@@ -0,0 +1,55 @@
+
+
+#ifndef CLAM_ADC_H
+#define CLAM_ADC_H
+
+struct adc_stream {
+ uint8_t *next_in;
+ size_t avail_in;
+ size_t total_in;
+
+ uint8_t *next_out;
+ size_t avail_out;
+ size_t total_out;
+
+ /* internals */
+ uint8_t *buffer;
+ uint8_t *curr;
+
+ uint32_t buffered;
+ uint16_t state;
+ uint16_t length;
+ uint32_t offset;
+};
+typedef struct adc_stream adc_stream;
+
+#define ADC_BUFF_SIZE 65536
+
+#define ADC_MEM_ERROR -1
+#define ADC_DATA_ERROR -2
+#define ADC_IO_ERROR -3
+#define ADC_OK 0
+#define ADC_STREAM_END 1
+
+enum adc_state {
+ ADC_STATE_UNINIT = 0,
+ ADC_STATE_GETTYPE = 1,
+ ADC_STATE_RAWDATA = 2,
+ ADC_STATE_SHORTOP = 3,
+ ADC_STATE_LONGOP2 = 4,
+ ADC_STATE_LONGOP1 = 5,
+ ADC_STATE_SHORTLOOK = 6,
+ ADC_STATE_LONGLOOK = 7
+};
+
+/* Compression phrases
+ * store phrase - 1 byte header + data, first byte 0x80-0xFF, max length 0x80 (7 bits + 1), no offset
+ * short phrase - 2 byte header + data, first byte 0x00-0x3F, max length 0x12 (4 bits + 3), max offset 0x3FF (10 bits)
+ * long phrase - 3 byte header + data, first byte 0x40-0x7F, max length 0x43 (6 bits + 4), max offset 0xFFFF (16 bits)
+ */
+
+int adc_decompressInit(adc_stream *strm);
+int adc_decompress(adc_stream *strm);
+int adc_decompressEnd(adc_stream *strm);
+
+#endif
diff --git a/libclamav/dmg.c b/libclamav/dmg.c
index 3defbf687..a13bafb21 100644
--- a/libclamav/dmg.c
+++ b/libclamav/dmg.c
@@ -54,9 +54,10 @@
#include "dmg.h"
#include "scanners.h"
#include "sf_base64decode.h"
+#include "adc.h"
-// #define DEBUG_DMG_PARSE
-// #define DEBUG_DMG_BZIP
+/* #define DEBUG_DMG_PARSE */
+/* #define DEBUG_DMG_BZIP */
#ifdef DEBUG_DMG_PARSE
# define dmg_parsemsg(...) cli_dbgmsg( __VA_ARGS__)
@@ -710,10 +711,84 @@ static int dmg_stripe_store(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mis
/* Stripe handling: ADC block (type 0x80000004) */
static int dmg_stripe_adc(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish_with_stripes *mish_set)
{
- /* Temporary stub */
- cli_dbgmsg("dmg_stripe_adc: stripe " STDu32 "\n", index);
- /* Return as format error to prevent scan for now */
- return CL_EFORMAT;
+ int ret = CL_CLEAN, adcret;
+ adc_stream strm;
+ size_t off = mish_set->stripes[index].dataOffset;
+ size_t len = mish_set->stripes[index].dataLength;
+ uint64_t size_so_far = 0;
+ uint64_t expected_len = mish_set->stripes[index].sectorCount * DMG_SECTOR_SIZE;
+ uint8_t obuf[BUFSIZ];
+
+ cli_dbgmsg("dmg_stripe_adc: stripe " STDu32 " initial len " STDu64 " expected len " STDu64 "\n",
+ index, len, expected_len);
+ if (len == 0)
+ return CL_CLEAN;
+
+ memset(&strm, 0, sizeof(strm));
+ strm.next_in = (void*)fmap_need_off_once(*ctx->fmap, off, len);
+ if (!strm.next_in) {
+ cli_warnmsg("dmg_stripe_adc: fmap need failed on stripe " STDu32 "\n", index);
+ return CL_EMAP;
+ }
+ strm.avail_in = len;
+ strm.next_out = obuf;
+ strm.avail_out = sizeof(obuf);
+
+ adcret = adc_decompressInit(&strm);
+ if(adcret != ADC_OK) {
+ cli_warnmsg("dmg_stripe_adc: adc_decompressInit failed\n");
+ return CL_EMEM;
+ }
+
+ while(adcret == ADC_OK) {
+ int written;
+ if (size_so_far > expected_len) {
+ cli_warnmsg("dmg_stripe_adc: expected size exceeded!\n");
+ adc_decompressEnd(&strm);
+ return CL_EFORMAT;
+ }
+ adcret = adc_decompress(&strm);
+ switch(adcret) {
+ case ADC_OK:
+ if(strm.avail_out == 0) {
+ if ((written=cli_writen(fd, obuf, sizeof(obuf)))!=sizeof(obuf)) {
+ cli_errmsg("dmg_stripe_adc: failed write to output file\n");
+ adc_decompressEnd(&strm);
+ return CL_EWRITE;
+ }
+ size_so_far += written;
+ strm.next_out = obuf;
+ strm.avail_out = sizeof(obuf);
+ }
+ continue;
+ case ADC_STREAM_END:
+ default:
+ written = sizeof(obuf) - strm.avail_out;
+ if (written) {
+ if ((cli_writen(fd, obuf, written))!=written) {
+ cli_errmsg("dmg_stripe_adc: failed write to output file\n");
+ adc_decompressEnd(&strm);
+ return CL_EWRITE;
+ }
+ size_so_far += written;
+ strm.next_out = obuf;
+ strm.avail_out = sizeof(obuf);
+ }
+ if (adcret == Z_STREAM_END)
+ break;
+ cli_dbgmsg("dmg_stripe_adc: after writing " STDu64 " bytes, "
+ "got error %d decompressing stripe " STDu32 "\n",
+ size_so_far, adcret, index);
+ adc_decompressEnd(&strm);
+ return CL_EFORMAT;
+ }
+ break;
+ }
+
+ adc_decompressEnd(&strm);
+ cli_dbgmsg("dmg_stripe_adc: stripe " STDu32 " actual len " STDu64 " expected len " STDu64 "\n",
+ index, size_so_far, expected_len);
+ return CL_CLEAN;
}
/* Stripe handling: deflate block (type 0x80000005) */
diff --git a/libclamav/hfsplus.c b/libclamav/hfsplus.c
index d162b766b..7dc74362b 100644
--- a/libclamav/hfsplus.c
+++ b/libclamav/hfsplus.c
@@ -651,6 +651,8 @@ static int hfsplus_walk_catalog(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader, hf
}
memcpy(&fileRec, &(nodeBuf[recordStart+keylen+2]), sizeof(hfsPlusCatalogFile));
+ /* Only scan files */
+ fileRec.permissions.fileMode = be16_to_host(fileRec.permissions.fileMode);
if ((fileRec.permissions.fileMode & HFS_MODE_TYPEMASK) == HFS_MODE_FILE) {
/* Convert forks and scan */
forkdata_to_host(&(fileRec.dataFork));
@@ -658,36 +660,41 @@ static int hfsplus_walk_catalog(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader, hf
if (fileRec.dataFork.logicalSize) {
ret = hfsplus_scanfile(ctx, volHeader, extHeader, &(fileRec.dataFork), dirname);
}
+ /* Check return code */
+ if (ret == CL_VIRUS) {
+ has_alerts = 1;
+ if (SCAN_ALL) {
+ /* Continue scanning in SCAN_ALL mode */
+ cli_dbgmsg("hfsplus_walk_catalog: data fork alert, continuing");
+ ret = CL_CLEAN;
+ }
+ }
if (ret != CL_CLEAN) {
cli_dbgmsg("hfsplus_walk_catalog: data fork retcode %d", ret);
- if (ret == CL_VIRUS) {
- has_alerts = 1;
- if (SCAN_ALL) {
- /* Continue scanning in SCAN_ALL mode */
- ret = CL_CLEAN;
- }
- }
break;
}
+ /* Scan resource fork */
forkdata_to_host(&(fileRec.resourceFork));
forkdata_print("resource fork:", &(fileRec.resourceFork));
if (fileRec.resourceFork.logicalSize) {
ret = hfsplus_scanfile(ctx, volHeader, extHeader, &(fileRec.resourceFork), dirname);
}
+ /* Check return code */
+ if (ret == CL_VIRUS) {
+ has_alerts = 1;
+ if (SCAN_ALL) {
+ /* Continue scanning in SCAN_ALL mode */
+ cli_dbgmsg("hfsplus_walk_catalog: resource fork alert, continuing");
+ ret = CL_CLEAN;
+ }
+ }
if (ret != CL_CLEAN) {
cli_dbgmsg("hfsplus_walk_catalog: resource fork retcode %d", ret);
- if (ret == CL_VIRUS) {
- has_alerts = 1;
- if (SCAN_ALL) {
- /* Continue scanning in SCAN_ALL mode */
- ret = CL_CLEAN;
- }
- }
break;
}
}
else {
- cli_dbgmsg("hfsplus_walk_catalog: record mode is not File\n");
+ cli_dbgmsg("hfsplus_walk_catalog: record mode %o is not File\n", fileRec.permissions.fileMode);
}
}
/* if return code, exit loop, message already logged */
diff --git a/libclamav/mpool.c b/libclamav/mpool.c
index 18b58b68b..b0ed837b4 100644
--- a/libclamav/mpool.c
+++ b/libclamav/mpool.c
@@ -452,12 +452,6 @@ struct MP *mpool_create() {
sz = align_to_pagesize(&mp, MIN_FRAGSIZE);
mp.u.mpm.usize = sizeof(struct MPMAP);
mp.u.mpm.size = sz - sizeof(mp);
-#ifndef _WIN32
- if ((mpool_p = (struct MP *)mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE|ANONYMOUS_MAP, -1, 0)) == MAP_FAILED)
-#else
- if(!(mpool_p = (struct MP *)VirtualAlloc(NULL, sz, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)))
-#endif
- return NULL;
if (FRAGSBITS > 255) {
cli_errmsg("At most 255 frags possible!\n");
return NULL;
@@ -466,6 +460,12 @@ struct MP *mpool_create() {
cli_errmsg("fragsz[0] too small!\n");
return NULL;
}
+#ifndef _WIN32
+ if ((mpool_p = (struct MP *)mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE|ANONYMOUS_MAP, -1, 0)) == MAP_FAILED)
+#else
+ if(!(mpool_p = (struct MP *)VirtualAlloc(NULL, sz, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)))
+#endif
+ return NULL;
#ifdef CL_DEBUG
memset(mpool_p, ALLOCPOISON, sz);
#endif
diff --git a/libclamav/readdb.c b/libclamav/readdb.c
index 8e3764e95..a5ad07308 100644
--- a/libclamav/readdb.c
+++ b/libclamav/readdb.c
@@ -2909,7 +2909,36 @@ int cl_load(const char *path, struct cl_engine *engine, unsigned int *signo, uns
}
if(CLAMSTAT(path, &sb) == -1) {
- cli_errmsg("cl_load(): Can't get status of %s\n", path);
+ switch (errno) {
+#if defined(EACCES)
+ case EACCES:
+ cli_errmsg("cl_load(): Access denied for path: %s\n", path);
+ break;
+#endif
+#if defined(ENOENT)
+ case ENOENT:
+ cli_errmsg("cl_load(): No such file or directory: %s\n", path);
+ break;
+#endif
+#if defined(ELOOP)
+ case ELOOP:
+ cli_errmsg("cl_load(): Too many symbolic links encountered in path: %s\n", path);
+ break;
+#endif
+#if defined(EOVERFLOW)
+ case EOVERFLOW:
+ cli_errmsg("cl_load(): File size is too large to be recognized. Path: %s\n", path);
+ break;
+#endif
+#if defined(EIO)
+ case EIO:
+ cli_errmsg("cl_load(): An I/O error occurred while reading from path: %s\n", path);
+ break;
+#endif
+ default:
+ cli_errmsg("cl_load: Can't get status of: %s\n", path);
+ break;
+ }
return CL_ESTAT;
}
diff --git a/win32/libclamav.vcxproj b/win32/libclamav.vcxproj
index 024cf742c..ed2445bc4 100644
--- a/win32/libclamav.vcxproj
+++ b/win32/libclamav.vcxproj
@@ -282,6 +282,7 @@
+
@@ -470,4 +471,4 @@
-
\ No newline at end of file
+
diff --git a/win32/libclamav.vcxproj.filters b/win32/libclamav.vcxproj.filters
index 23e35fc55..c030cf66d 100644
--- a/win32/libclamav.vcxproj.filters
+++ b/win32/libclamav.vcxproj.filters
@@ -51,6 +51,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -841,4 +844,4 @@
Source Files\libxml2
-
\ No newline at end of file
+