更新libclamav库1.0.0版本
This commit is contained in:
319
clamav/build-libclamav.sh
Normal file
319
clamav/build-libclamav.sh
Normal file
File diff suppressed because one or more lines are too long
617
clamav/clamav-config.h
Normal file
617
clamav/clamav-config.h
Normal file
@@ -0,0 +1,617 @@
|
||||
/* clamav-config.h.cmake.in. Autoconf compatibility layer for CMake. */
|
||||
|
||||
/* Define if building universal (internal helper macro) */
|
||||
/* #undef AC_APPLE_UNIVERSAL_BUILD */
|
||||
|
||||
/* mmap flag for anonymous maps */
|
||||
#define ANONYMOUS_MAP MAP_ANONYMOUS
|
||||
|
||||
/* bind 8 compatibility mode, required on some systems to get T_TXT, etc from nameser_compat.h */
|
||||
/* #undef BIND_8_COMPAT */
|
||||
|
||||
/* name of the clamav group */
|
||||
#define CLAMAVGROUP "clamav"
|
||||
|
||||
/* name of the clamav user */
|
||||
#define CLAMAVUSER "clamav"
|
||||
|
||||
/* enable debugging */
|
||||
/* #undef CL_DEBUG */
|
||||
|
||||
/* enable experimental code */
|
||||
/* #undef CL_EXPERIMENTAL */
|
||||
|
||||
/* thread safe */
|
||||
#define CL_THREAD_SAFE 1
|
||||
|
||||
/* curses header location */
|
||||
#define CURSES_INCLUDE <ncurses.h>
|
||||
|
||||
/* os is aix */
|
||||
/* #undef C_AIX */
|
||||
|
||||
/* os is beos */
|
||||
/* #undef C_BEOS */
|
||||
|
||||
/* Increase thread stack size. */
|
||||
/* #undef C_BIGSTACK */
|
||||
|
||||
/* os is bsd flavor */
|
||||
/* #undef C_BSD */
|
||||
|
||||
/* os is darwin */
|
||||
/* #undef C_DARWIN */
|
||||
|
||||
/* target is gnu-hurd */
|
||||
/* #undef C_GNU_HURD */
|
||||
|
||||
/* os is hpux */
|
||||
/* #undef C_HPUX */
|
||||
|
||||
/* os is interix */
|
||||
/* #undef C_INTERIX */
|
||||
|
||||
/* os is irix */
|
||||
/* #undef C_IRIX */
|
||||
|
||||
/* target is kfreebsd-gnu */
|
||||
/* #undef C_KFREEBSD_GNU */
|
||||
|
||||
/* target is linux */
|
||||
#define C_LINUX 1
|
||||
|
||||
/* os is OS/2 */
|
||||
/* #undef C_OS2 */
|
||||
|
||||
/* os is osf/tru64 */
|
||||
/* #undef C_OSF */
|
||||
|
||||
/* os is QNX 6.x.x */
|
||||
/* #undef C_QNX6 */
|
||||
|
||||
/* os is solaris */
|
||||
/* #undef C_SOLARIS */
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Path to virus database directory. */
|
||||
#define DATADIR "/var/lib/clamav"
|
||||
|
||||
/* where to look for the config file */
|
||||
#define CONFDIR "/etc/clamav"
|
||||
#endif
|
||||
|
||||
/* Have sys/fanotify.h */
|
||||
#define HAVE_SYS_FANOTIFY_H 1
|
||||
|
||||
/* whether _XOPEN_SOURCE needs to be defined for fd passing to work */
|
||||
/* #undef FDPASS_NEED_XOPEN */
|
||||
|
||||
/* file i/o buffer size */
|
||||
#define FILEBUFF 8192
|
||||
|
||||
/* scan buffer size */
|
||||
#define SCANBUFF 131072
|
||||
|
||||
/* enable workaround for broken DNS servers */
|
||||
/* #undef FRESHCLAM_DNS_FIX */
|
||||
|
||||
/* use "Cache-Control: no-cache" in freshclam */
|
||||
/* #undef FRESHCLAM_NO_CACHE */
|
||||
|
||||
/* attrib aligned */
|
||||
#define HAVE_ATTRIB_ALIGNED 1
|
||||
|
||||
/* attrib packed */
|
||||
#define HAVE_ATTRIB_PACKED 1
|
||||
|
||||
/* have bzip2 */
|
||||
#define HAVE_BZLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the `ctime_r' function. */
|
||||
/* #undef HAVE_CTIME_R */
|
||||
|
||||
/* ctime_r takes 2 arguments */
|
||||
/* #undef HAVE_CTIME_R_2 */
|
||||
|
||||
/* ctime_r takes 3 arguments */
|
||||
/* #undef HAVE_CTIME_R_3 */
|
||||
|
||||
/* Define to 1 if you have the declaration of `cygwin_conv_path', and to 0 if
|
||||
you don't. */
|
||||
/* #undef HAVE_DECL_CYGWIN_CONV_PATH */
|
||||
|
||||
/* Define to 1 if you have a deprecated version of the 'libjson' library
|
||||
(-ljson). */
|
||||
/* #undef HAVE_DEPRECATED_JSON */
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file. */
|
||||
#define HAVE_DIRENT_H 1
|
||||
|
||||
/* Define if you have the GNU dld library. */
|
||||
/* #undef HAVE_DLD */
|
||||
|
||||
/* Define to 1 if you have the <dld.h> header file. */
|
||||
/* #undef HAVE_DLD_H */
|
||||
|
||||
/* Define to 1 if you have the `dlerror' function. */
|
||||
/* #undef HAVE_DLERROR */
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have the <dl.h> header file. */
|
||||
/* #undef HAVE_DL_H */
|
||||
|
||||
/* Define if you have the _dyld_func_lookup function. */
|
||||
/* #undef HAVE_DYLD */
|
||||
|
||||
/* Define to 1 if you have the `enable_extended_FILE_stdio' function. */
|
||||
/* #undef HAVE_ENABLE_EXTENDED_FILE_STDIO */
|
||||
|
||||
/* Define to 1 if the system has the type `error_t'. */
|
||||
/* #undef HAVE_ERROR_T */
|
||||
|
||||
/* have working file descriptor passing support */
|
||||
#define HAVE_FD_PASSING 1
|
||||
|
||||
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
|
||||
#define HAVE_FSEEKO 1
|
||||
|
||||
/* have getaddrinfo() */
|
||||
#define HAVE_GETADDRINFO 1
|
||||
|
||||
/* Define to 1 if you have the `getnameinfo' function. */
|
||||
/* #undef HAVE_GETNAMEINFO */
|
||||
|
||||
/* Define to 1 if getpagesize() is available */
|
||||
#define HAVE_GETPAGESIZE 1
|
||||
|
||||
/* Define to 1 if you have the <grp.h> header file. */
|
||||
#define HAVE_GRP_H 1
|
||||
|
||||
/* Define if you have the iconv() function and it works. */
|
||||
#define HAVE_ICONV 1
|
||||
|
||||
/* Define to 1 if you have the `initgroups' function. */
|
||||
#define HAVE_INITGROUPS 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file (for libjson-c). */
|
||||
#define JSON_C_HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the 'libjson' library (-ljson). */
|
||||
#define HAVE_JSON 1
|
||||
|
||||
/* Define to '1' if you have the check.h library */
|
||||
/* #undef HAVE_LIBCHECK */
|
||||
|
||||
/* Define to '1' if you have the ncurses.h library */
|
||||
#define HAVE_LIBNCURSES 1
|
||||
|
||||
/* Define to '1' if you have the curses.h library */
|
||||
/* #undef HAVE_LIBPDCURSES */
|
||||
|
||||
/* Define to 1 if you have the `ssl' library (-lssl). */
|
||||
#define HAVE_LIBSSL 1
|
||||
|
||||
/* Define to 1 if you have the 'libxml2' library (-lxml2). */
|
||||
#define HAVE_LIBXML2 1
|
||||
|
||||
/* Define to 1 if you have the `z' library (-lz). */
|
||||
#define HAVE_LIBZ 1
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define to 1 if you have the `madvise' function. */
|
||||
/* #undef HAVE_MADVISE */
|
||||
|
||||
/* Define to 1 if you have the `mallinfo' function. */
|
||||
/* #undef HAVE_MALLINFO */
|
||||
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#define HAVE_MALLOC_H 1
|
||||
|
||||
/* Define to 1 if you have the `mkstemp' function. */
|
||||
/* #undef HAVE_MKSTEMP */
|
||||
|
||||
/* Define to 1 if you have a working `mmap' system call that supports
|
||||
MAP_PRIVATE. */
|
||||
#define HAVE_MMAP 1
|
||||
|
||||
/* Define to 1 if you have a pcre library (-lpcre). */
|
||||
#define HAVE_PCRE 1
|
||||
|
||||
/* Define to 1 if you using the pcre2 library. */
|
||||
#define USING_PCRE2 1
|
||||
|
||||
/* Define to 1 if you have the `poll' function. */
|
||||
#define HAVE_POLL 1
|
||||
|
||||
/* Define to 1 if you have the <poll.h> header file. */
|
||||
#define HAVE_POLL_H 1
|
||||
|
||||
/* "pragma pack" */
|
||||
/* #undef HAVE_PRAGMA_PACK */
|
||||
|
||||
/* "pragma pack hppa/hp-ux style" */
|
||||
/* #undef HAVE_PRAGMA_PACK_HPPA */
|
||||
|
||||
/* Define if libtool can extract symbol lists from object files. */
|
||||
/* #undef HAVE_PRELOADED_SYMBOLS */
|
||||
|
||||
/* Define to 1 if you have the <pthread.h> header file */
|
||||
#define HAVE_PTHREAD_H 1
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#define HAVE_PWD_H 1
|
||||
|
||||
/* Define to 1 if you have the `readdir' function. */
|
||||
/* #undef HAVE_READDIR */
|
||||
|
||||
/* Define to 1 if you have the `recvmsg' function. */
|
||||
#define HAVE_RECVMSG 1
|
||||
|
||||
/* have resolv.h */
|
||||
#define HAVE_RESOLV_H 1
|
||||
|
||||
/* Define signed right shift implementation */
|
||||
#define HAVE_SAR 1
|
||||
|
||||
/* Define to 1 if you have the `sched_yield' function. */
|
||||
/* #undef HAVE_SCHED_YIELD */
|
||||
|
||||
/* Define to 1 if you have the `sendmsg' function. */
|
||||
#define HAVE_SENDMSG 1
|
||||
|
||||
/* Define to 1 if you have the `setgroups' function. */
|
||||
/* #undef HAVE_SETGROUPS */
|
||||
|
||||
/* Define to 1 if you have the `setsid' function. */
|
||||
#define HAVE_SETSID 1
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#define HAVE_SNPRINTF 1
|
||||
|
||||
/* enable stat64 */
|
||||
/* #undef HAVE_STAT64 */
|
||||
|
||||
/* Define to 1 if you have the <stdbool.h> header file. */
|
||||
#define HAVE_STDBOOL_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the `strcasestr' function. */
|
||||
/* #undef HAVE_STRCASESTR */
|
||||
|
||||
/* Define to 1 if you have the `strerror_r' function. */
|
||||
#define HAVE_STRERROR_R 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the `strlcat' function. */
|
||||
/* #undef HAVE_STRLCAT */
|
||||
|
||||
/* Define to 1 if you have the `strlcpy' function. */
|
||||
/* #undef HAVE_STRLCPY */
|
||||
|
||||
/* Define to 1 if you have the `strndup' function. */
|
||||
#define HAVE_STRNDUP 1
|
||||
|
||||
/* using internal strn functions */
|
||||
/* #undef HAVE_STRNI */
|
||||
|
||||
/* Define to 1 if you have the `strnlen' function. */
|
||||
#define HAVE_STRNLEN 1
|
||||
|
||||
/* Define to 1 if you have the `strnstr' function. */
|
||||
/* #undef HAVE_STRNSTR */
|
||||
|
||||
/* Define to 1 if sysconf(_SC_PAGESIZE) is available */
|
||||
#define HAVE_SYSCONF_SC_PAGESIZE 1
|
||||
|
||||
/* Define to 1 if you have the `sysctlbyname' function. */
|
||||
/* #undef HAVE_SYSCTLBYNAME */
|
||||
|
||||
/* systemd is supported */
|
||||
#define HAVE_SYSTEMD 1
|
||||
|
||||
/* Use private fts() implementation which is LFS safe */
|
||||
#define HAVE_SYSTEM_LFS_FTS 1
|
||||
|
||||
/* Define to 1 if you have the <sys/cdefs.h> header file. */
|
||||
#define HAVE_SYS_CDEFS_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/dl.h> header file. */
|
||||
/* #undef HAVE_SYS_DL_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/filio.h> header file. */
|
||||
/* #undef HAVE_SYS_FILIO_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/inttypes.h> header file. */
|
||||
/* #undef HAVE_SYS_INTTYPES_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/int_types.h> header file. */
|
||||
/* #undef HAVE_SYS_INT_TYPES_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/mman.h> header file. */
|
||||
#define HAVE_SYS_MMAN_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/queue.h> header file. */
|
||||
#define HAVE_SYS_QUEUE_H 1
|
||||
|
||||
/* "have <sys/select.h>" */
|
||||
#define HAVE_SYS_SELECT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/times.h> header file. */
|
||||
#define HAVE_SYS_TIMES_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/uio.h> header file. */
|
||||
#define HAVE_SYS_UIO_H 1
|
||||
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
#define HAVE_TERMIOS_H 1
|
||||
|
||||
/* Define to 1 if you have the `timegm' function. */
|
||||
#define HAVE_TIMEGM 1
|
||||
|
||||
/* Define this if uname(2) is POSIX */
|
||||
#define HAVE_UNAME_SYSCALL 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the `vsnprintf' function. */
|
||||
#define HAVE_VSNPRINTF 1
|
||||
|
||||
/* This value is set to 1 to indicate that the system argz facility works */
|
||||
/* #undef HAVE_WORKING_ARGZ */
|
||||
|
||||
/* yara sources are compiled in */
|
||||
#define HAVE_YARA 1
|
||||
|
||||
/* Define to 1 if you have the <zlib.h> header file. */
|
||||
#define HAVE_ZLIB_H 1
|
||||
|
||||
/* For internal use only - DO NOT DEFINE */
|
||||
/* #undef HAVE__INTERNAL__SHA_COLLECT */
|
||||
|
||||
/* Define as const if the declaration of iconv() needs const. */
|
||||
/* #undef ICONV_CONST */
|
||||
|
||||
/* Define if UNRAR is linked instead of loaded. */
|
||||
/* #undef UNRAR_LINKED */
|
||||
|
||||
/* Define if UNRAR is linked instead of loaded. */
|
||||
/* #undef HAVE_SYSTEM_TOMSFASTMATH */
|
||||
|
||||
/* "Full clamav library version number" */
|
||||
#define LIBCLAMAV_FULLVER "11.0.0"
|
||||
|
||||
/* "Major clamav library version number" */
|
||||
#define LIBCLAMAV_MAJORVER 11
|
||||
|
||||
/* "Full freshclam library version number" */
|
||||
#define LIBFRESHCLAM_FULLVER "2.0.2"
|
||||
|
||||
/* "Major freshclam library version number" */
|
||||
#define LIBFRESHCLAM_MAJORVER 2
|
||||
|
||||
/* The archive extension */
|
||||
#define LT_LIBEXT ".a"
|
||||
|
||||
/* The archive prefix */
|
||||
#define LT_LIBPREFIX "lib"
|
||||
|
||||
/* Define to the extension used for runtime loadable modules, say, ".so" or ".dylib". */
|
||||
#define LT_MODULE_EXT ".so"
|
||||
|
||||
/* Define to the name of the environment variable that determines the run-time
|
||||
module search path. */
|
||||
#ifdef _WIN32
|
||||
#define SEARCH_LIBDIR "/usr"
|
||||
#else
|
||||
#define SEARCH_LIBDIR "/usr/lib/x86_64-linux-gnu"
|
||||
#endif
|
||||
|
||||
/* Define to the shared library suffix, say, ".dylib". */
|
||||
#define LT_SHARED_EXT ".so"
|
||||
|
||||
/* disable assertions */
|
||||
/* #undef NDEBUG */
|
||||
|
||||
/* Define if dlsym() requires a leading underscore in symbol names. */
|
||||
/* #undef NEED_USCORE */
|
||||
|
||||
/* bzip funtions do not have bz2 prefix */
|
||||
/* #undef NOBZ2PREFIX */
|
||||
|
||||
/* "no fd_set" */
|
||||
/* #undef NO_FD_SET */
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "ClamAV"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "https://github.com/Cisco-Talos/clamav/issues"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "ClamAV"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "ClamAV 1.0.0"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
/* #undef PACKAGE_TARNAME */
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL "https://www.clamav.net/"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "1.0.0"
|
||||
|
||||
/* Libprelude support enabled */
|
||||
/* #undef PRELUDE */
|
||||
|
||||
/* Define whether application use libtool >= 2.0 */
|
||||
/* #undef PRELUDE_APPLICATION_USE_LIBTOOL2 */
|
||||
|
||||
/* Define to if the `setpgrp' function takes no argument. */
|
||||
/* #undef SETPGRP_VOID */
|
||||
|
||||
/* The number of bytes in type int */
|
||||
#define SIZEOF_INT 4
|
||||
|
||||
/* The number of bytes in type long */
|
||||
#define SIZEOF_LONG 8
|
||||
|
||||
/* The number of bytes in type long long */
|
||||
#define SIZEOF_LONG_LONG 8
|
||||
|
||||
/* The number of bytes in type short */
|
||||
#define SIZEOF_SHORT 2
|
||||
|
||||
/* The number of bytes in type void * */
|
||||
#define SIZEOF_VOID_P 8
|
||||
|
||||
/* Define to if you have the ANSI C header files. */
|
||||
/* #undef STDC_HEADERS */
|
||||
|
||||
/* Support for IPv6 */
|
||||
/* #undef SUPPORT_IPv6 */
|
||||
|
||||
/* enable memory pools */
|
||||
#define USE_MPOOL 1
|
||||
|
||||
/* use syslog */
|
||||
#define USE_SYSLOG 1
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
#ifndef _ALL_SOURCE
|
||||
/* #undef _ALL_SOURCE */
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
/* #undef _POSIX_PTHREAD_SEMANTICS */
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
/* #undef _TANDEM_SOURCE */
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
/* #undef __EXTENSIONS__ */
|
||||
#endif
|
||||
|
||||
/* LLVM version (if found) */
|
||||
/* #undef LLVM_VERSION */
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "1.0.0"
|
||||
|
||||
/* Version suffix for package */
|
||||
#define VERSION_SUFFIX ""
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
# if defined __BIG_ENDIAN__
|
||||
# define WORDS_BIGENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
/* #undef WORDS_BIGENDIAN */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
|
||||
`char[]'. */
|
||||
/* #undef YYTEXT_POINTER */
|
||||
|
||||
/* Enable large inode numbers on Mac OS X 10.5. */
|
||||
#ifndef _DARWIN_USE_64_BIT_INODE
|
||||
# define _DARWIN_USE_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
/* #undef _FILE_OFFSET_BITS */
|
||||
|
||||
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
|
||||
/* #undef _LARGEFILE_SOURCE */
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
/* #undef _LARGE_FILES */
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
/* #undef _MINIX */
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
/* #undef _POSIX_1_SOURCE */
|
||||
|
||||
/* POSIX compatibility */
|
||||
/* #undef _POSIX_PII_SOCKET */
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
/* #undef _POSIX_SOURCE */
|
||||
|
||||
/* thread safe */
|
||||
#define _REENTRANT 1
|
||||
|
||||
/* Define so that glibc/gnulib argp.h does not typedef error_t. */
|
||||
/* #undef __error_t_defined */
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#define inline inline
|
||||
#endif
|
||||
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
/* #undef off_t */
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
/* #undef ssize_t */
|
||||
|
||||
/* Define to the equivalent of the C99 'restrict' keyword, or to
|
||||
nothing if this is not supported. Do not define if restrict is
|
||||
supported directly. */
|
||||
#define restrict __restrict
|
||||
|
||||
/* Work around a bug in Sun C++: it does not support _Restrict or
|
||||
__restrict__, even though the corresponding Sun C compiler ends up with
|
||||
"#define restrict _Restrict" or "#define restrict __restrict__" in the
|
||||
previous line. Perhaps some future version of Sun C++ will work with
|
||||
restrict; if so, hopefully it defines __RESTRICT like Sun C does. */
|
||||
#if defined __SUNPRO_CC && !defined __RESTRICT
|
||||
# define _Restrict
|
||||
# define __restrict__
|
||||
#endif
|
||||
|
||||
/* Define to "int" if <sys/socket.h> does not define. */
|
||||
/* #undef socklen_t */
|
||||
|
||||
#include "platform.h"
|
||||
84
clamav/clamav-types.h
Normal file
84
clamav/clamav-types.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2007-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: Tomasz Kojm, Micah Snyder
|
||||
*
|
||||
* WARNING: This file was generated by CMake. Do not edit!
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __CLAMAV_TYPES_H
|
||||
#define __CLAMAV_TYPES_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Ensure we have print format types */
|
||||
/* PRIu64 should be in <inttypes.h> */
|
||||
#ifndef _SF64_PREFIX
|
||||
#define _SF64_PREFIX "l"
|
||||
#endif
|
||||
|
||||
#ifndef PRIu64
|
||||
#define PRIu64 _SF64_PREFIX "u"
|
||||
#endif
|
||||
#ifndef PRIx64
|
||||
#define PRIx64 _SF64_PREFIX "i"
|
||||
#endif
|
||||
#ifndef PRIi64
|
||||
#define PRIi64 _SF64_PREFIX "x"
|
||||
#endif
|
||||
|
||||
#ifndef STDu64
|
||||
#define STDu64 "%" PRIu64
|
||||
#define STDi64 "%" PRIi64
|
||||
#define STDx64 "%" PRIx64
|
||||
#endif
|
||||
|
||||
/* PRIu32 should also be in <inttypes.h> */
|
||||
#ifndef PRIu32
|
||||
#ifndef _SF32_PREFIX
|
||||
#define _SF32_PREFIX ""
|
||||
#endif
|
||||
|
||||
#define PRIu32 _SF32_PREFIX "u"
|
||||
#define PRIi32 _SF32_PREFIX "i"
|
||||
#define PRIx32 _SF32_PREFIX "x"
|
||||
#endif
|
||||
|
||||
#ifndef STDu32
|
||||
#define STDu32 "%" PRIu32
|
||||
#define STDi32 "%" PRIi32
|
||||
#define STDx32 "%" PRIx32
|
||||
#endif
|
||||
|
||||
#ifndef INT32_MAX
|
||||
#define INT32_MAX 2147483647
|
||||
#endif
|
||||
|
||||
#endif
|
||||
68
clamav/clamav-version.h
Normal file
68
clamav/clamav-version.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Authors: Micah Snyder
|
||||
*
|
||||
* WARNING: This file was generated by CMake. Do not edit!
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CLAMAV_VER_H
|
||||
#define CLAMAV_VER_H
|
||||
|
||||
/**
|
||||
* @macro
|
||||
* Version number of the clamav package release
|
||||
*/
|
||||
#define CLAMAV_VERSION "1.0.0"
|
||||
|
||||
/**
|
||||
* @macro
|
||||
* Numerical representation of the version number of the clamav package
|
||||
* release. This is a 24 bit number with 8 bits for major number, 8 bits
|
||||
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
|
||||
*/
|
||||
#define CLAMAV_VERSION_NUM 0x010000
|
||||
|
||||
/**
|
||||
* @macro
|
||||
* Version number of the clamav library release
|
||||
*/
|
||||
#define LIBCLAMAV_VERSION "11.0.0"
|
||||
|
||||
/**
|
||||
* @macro
|
||||
* Numerical representation of the version number of the libclamav library
|
||||
* release. This is a 24 bit number with 8 bits for major number, 8 bits
|
||||
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
|
||||
*/
|
||||
#define LIBCLAMAV_VERSION_NUM 0x0b0000
|
||||
|
||||
/**
|
||||
* @macro
|
||||
* Version number of the clamav library release
|
||||
*/
|
||||
#define LIBFRESHCLAM_VERSION "2.0.2"
|
||||
|
||||
/**
|
||||
* @macro
|
||||
* Numerical representation of the version number of the libfreshclam library
|
||||
* release. This is a 24 bit number with 8 bits for major number, 8 bits
|
||||
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
|
||||
*/
|
||||
#define LIBFRESHCLAM_VERSION_NUM 0x020200
|
||||
|
||||
#endif /* CLAMAV_VER_H */
|
||||
208
clamav/clamav_rust.h
Normal file
208
clamav/clamav_rust.h
Normal file
@@ -0,0 +1,208 @@
|
||||
/* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved. */
|
||||
|
||||
#ifndef __CLAMAV_RUST_H
|
||||
#define __CLAMAV_RUST_H
|
||||
|
||||
/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "clamav.h"
|
||||
#include "matcher-ac.h"
|
||||
typedef struct cli_matcher cli_matcher; typedef struct cli_ctx_tag cli_ctx;
|
||||
|
||||
typedef enum IndicatorType {
|
||||
/**
|
||||
* For hash-based indicators.
|
||||
*/
|
||||
IndicatorType_Strong,
|
||||
/**
|
||||
* For potentially unwanted applications/programs that are not malicious but may be used maliciously.
|
||||
*/
|
||||
IndicatorType_PotentiallyUnwanted,
|
||||
/**
|
||||
* Weak indicators that together with other indicators can be used to form a stronger indicator.
|
||||
* This type of indicator should NEVER alert the user on its own.
|
||||
*/
|
||||
IndicatorType_Weak,
|
||||
} IndicatorType;
|
||||
|
||||
/**
|
||||
* A generic container for any error that implements `Into<std::error::Error>`
|
||||
*/
|
||||
typedef struct FFIError FFIError;
|
||||
|
||||
bool script2cdiff(const char *script, const char *builder, const char *server);
|
||||
|
||||
/**
|
||||
* This function is only meant to be called from sigtool.c
|
||||
*/
|
||||
int32_t cdiff_apply(int32_t fd, uint16_t mode);
|
||||
|
||||
/**
|
||||
* Initialize a match vector
|
||||
*/
|
||||
evidence_t evidence_new(void);
|
||||
|
||||
/**
|
||||
* Free the evidence
|
||||
*/
|
||||
void evidence_free(evidence_t evidence);
|
||||
|
||||
/**
|
||||
* C interface for Evidence::render_verdict().
|
||||
* Handles all the unsafe ffi stuff.
|
||||
*
|
||||
* Render a verdict based on the evidence, depending on the severity of the
|
||||
* indicators found and the scan configuration.
|
||||
*
|
||||
* The individual alerting-indicators would have already been printed at this point.
|
||||
*
|
||||
* # Safety
|
||||
*
|
||||
* No parameters may be NULL
|
||||
*/
|
||||
bool evidence_render_verdict(evidence_t evidence);
|
||||
|
||||
/**
|
||||
* C interface to get a string name for one of the alerts.
|
||||
* Will first check for one from the strong indicators, then pua.
|
||||
*
|
||||
* # Safety
|
||||
*
|
||||
* Returns a string that is either static, or allocated when reading the database.
|
||||
* So the lifetime of the string is good at least until you reload or unload the databases.
|
||||
*
|
||||
* No parameters may be NULL
|
||||
*/
|
||||
const char *evidence_get_last_alert(evidence_t evidence);
|
||||
|
||||
/**
|
||||
* C interface to get a string name for one of the alerts.
|
||||
* Will first check for one from the strong indicators, then pua.
|
||||
*
|
||||
* # Safety
|
||||
*
|
||||
* Returns a string that is either static, or allocated when reading the database.
|
||||
* So the lifetime of the string is good at least until you reload or unload the databases.
|
||||
*
|
||||
* No parameters may be NULL
|
||||
*/
|
||||
const char *evidence_get_indicator(evidence_t evidence,
|
||||
enum IndicatorType indicator_type,
|
||||
uintptr_t index);
|
||||
|
||||
/**
|
||||
* C interface to check number of alerting indicators in evidence.
|
||||
*
|
||||
* # Safety
|
||||
*
|
||||
* No parameters may be NULL
|
||||
*/
|
||||
uintptr_t evidence_num_alerts(evidence_t evidence);
|
||||
|
||||
/**
|
||||
* C interface to check number of indicators in evidence.
|
||||
* Handles all the unsafe ffi stuff.
|
||||
*
|
||||
* # Safety
|
||||
*
|
||||
* No parameters may be NULL
|
||||
*/
|
||||
uintptr_t evidence_num_indicators_type(evidence_t evidence, enum IndicatorType indicator_type);
|
||||
|
||||
/**
|
||||
* C interface for Evidence::add_indicator().
|
||||
* Handles all the unsafe ffi stuff.
|
||||
*
|
||||
* Add an indicator to the evidence.
|
||||
*
|
||||
* # Safety
|
||||
*
|
||||
* `hexsig` and `err` must not be NULL
|
||||
*/
|
||||
bool evidence_add_indicator(evidence_t evidence,
|
||||
const char *name,
|
||||
enum IndicatorType indicator_type,
|
||||
struct FFIError **err);
|
||||
|
||||
/**
|
||||
* Compute (and cache) a formatted error string from the provided [`FFIError`] pointer.
|
||||
*
|
||||
* # Safety
|
||||
*
|
||||
* `err` must not be NULL
|
||||
*/
|
||||
const char *ffierror_fmt(struct FFIError *err);
|
||||
|
||||
/**
|
||||
* Free a [`FFIError`] structure
|
||||
*
|
||||
* # Safety
|
||||
*
|
||||
* `err` must not be NULL
|
||||
*/
|
||||
void ffierror_free(struct FFIError *err);
|
||||
|
||||
/**
|
||||
* Initialize the hashmap
|
||||
*/
|
||||
fuzzyhashmap_t fuzzy_hashmap_new(void);
|
||||
|
||||
/**
|
||||
* Free the hashmap
|
||||
*/
|
||||
void fuzzy_hash_free_hashmap(fuzzyhashmap_t fuzzy_hashmap);
|
||||
|
||||
/**
|
||||
* C interface for FuzzyHashMap::check().
|
||||
* Handles all the unsafe ffi stuff.
|
||||
*
|
||||
* # Safety
|
||||
*
|
||||
* No parameters may be NULL
|
||||
*/
|
||||
bool fuzzy_hash_check(fuzzyhashmap_t fuzzy_hashmap,
|
||||
cli_ac_data *mdata,
|
||||
image_fuzzy_hash_t image_fuzzy_hash);
|
||||
|
||||
/**
|
||||
* C interface for FuzzyHashMap::load_subsignature().
|
||||
* Handles all the unsafe ffi stuff.
|
||||
*
|
||||
* # Safety
|
||||
*
|
||||
* `hexsig` and `err` must not be NULL
|
||||
*/
|
||||
bool fuzzy_hash_load_subsignature(fuzzyhashmap_t fuzzy_hashmap,
|
||||
const char *hexsig,
|
||||
uint32_t lsig_id,
|
||||
uint32_t subsig_id,
|
||||
struct FFIError **err);
|
||||
|
||||
/**
|
||||
* C interface for fuzzy_hash_calculate_image().
|
||||
* Handles all the unsafe ffi stuff.
|
||||
*
|
||||
* # Safety
|
||||
*
|
||||
* `file_bytes` and `hash_out` must not be NULL
|
||||
*/
|
||||
bool fuzzy_hash_calculate_image(const uint8_t *file_bytes,
|
||||
uintptr_t file_size,
|
||||
uint8_t *hash_out,
|
||||
uintptr_t hash_out_len,
|
||||
struct FFIError **err);
|
||||
|
||||
bool clrs_log_init(void);
|
||||
|
||||
/**
|
||||
* API exported for C code to log to standard error using Rust.
|
||||
* This would be be an alternative to fputs, and reliably prints
|
||||
* non-ASCII UTF8 characters on Windows, where fputs does not.
|
||||
*/
|
||||
void clrs_eprint(const char *c_buf);
|
||||
|
||||
#endif /* __CLAMAV_RUST_H */
|
||||
48
clamav/clamscan/CMakeLists.txt
Normal file
48
clamav/clamscan/CMakeLists.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
# Copyright (C) 2020-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
|
||||
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
|
||||
|
||||
# Windows compatibility headers
|
||||
include_directories(${CMAKE_SOURCE_DIR}/win32/compat)
|
||||
endif()
|
||||
|
||||
# The clamscan executable.
|
||||
add_executable( clamscan )
|
||||
target_sources( clamscan
|
||||
PRIVATE
|
||||
clamscan.c
|
||||
manager.c
|
||||
manager.h
|
||||
global.h )
|
||||
if(WIN32)
|
||||
target_sources( clamscan
|
||||
PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/win32/res/clamscan.rc
|
||||
${CMAKE_SOURCE_DIR}/win32/res/clam.manifest )
|
||||
endif()
|
||||
target_include_directories( clamscan
|
||||
PRIVATE ${CMAKE_BINARY_DIR} # For clamav-config.h
|
||||
)
|
||||
set_target_properties( clamscan PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}" )
|
||||
|
||||
if (APPLE AND CLAMAV_SIGN_FILE)
|
||||
set_target_properties( clamscan PROPERTIES
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ${CODE_SIGN_IDENTITY}
|
||||
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${DEVELOPMENT_TEAM_ID}
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries( clamscan
|
||||
PRIVATE
|
||||
ClamAV::libclamav
|
||||
ClamAV::common )
|
||||
if(WIN32)
|
||||
install(TARGETS clamscan DESTINATION . COMPONENT programs)
|
||||
install(FILES $<TARGET_PDB_FILE:clamscan> DESTINATION . OPTIONAL COMPONENT programs)
|
||||
else()
|
||||
install(TARGETS clamscan DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT programs)
|
||||
endif()
|
||||
21
clamav/clamscan/Doxyfile
Normal file
21
clamav/clamscan/Doxyfile
Normal file
@@ -0,0 +1,21 @@
|
||||
PROJECT_NAME = ClamAV - Clamscan
|
||||
OUTPUT_DIRECTORY = ../docs/clamscan
|
||||
WARNINGS = YES
|
||||
FILE_PATTERNS = *.c *.h
|
||||
PERL_PATH = /usr/bin/perl
|
||||
SEARCHENGINE = YES
|
||||
|
||||
GENERATE_LATEX=NO
|
||||
OPTIMIZE_OUTPUT_FOR_C=YES
|
||||
HAVE_DOT=YES
|
||||
CALL_GRAPH=YES
|
||||
CALLER_GRAPH=YES
|
||||
JAVADOC_AUTOBRIEF=YES
|
||||
GENERATE_MAN=NO
|
||||
EXAMPLE_PATH=examples
|
||||
|
||||
DOT_CLEANUP=NO
|
||||
MAX_DOT_GRAPH_DEPTH=3
|
||||
|
||||
EXTRACT_ALL=YES
|
||||
INPUT = .
|
||||
346
clamav/clamscan/clamscan.c
Normal file
346
clamav/clamscan/clamscan.c
Normal file
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2007-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: Tomasz Kojm
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <locale.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#ifdef C_LINUX
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
// libclamav
|
||||
#include "clamav.h"
|
||||
#include "others.h"
|
||||
#include "str.h"
|
||||
|
||||
// common
|
||||
#include "misc.h"
|
||||
#include "output.h"
|
||||
#include "actions.h"
|
||||
#include "optparser.h"
|
||||
|
||||
#include "global.h"
|
||||
#include "manager.h"
|
||||
|
||||
void help(void);
|
||||
|
||||
struct s_info info;
|
||||
short recursion = 0, bell = 0;
|
||||
short printinfected = 0, printclean = 1;
|
||||
|
||||
int _clamscan(int argc, char **argv)
|
||||
{
|
||||
int ds, dms, ret;
|
||||
double mb, rmb;
|
||||
struct timeval t1, t2;
|
||||
time_t date_start, date_end;
|
||||
|
||||
char buffer[26];
|
||||
#ifndef _WIN32
|
||||
sigset_t sigset;
|
||||
#endif
|
||||
struct optstruct *opts;
|
||||
const struct optstruct *opt;
|
||||
|
||||
if (check_flevel())
|
||||
exit(2);
|
||||
|
||||
#if !defined(_WIN32)
|
||||
if (!setlocale(LC_CTYPE, "")) {
|
||||
mprintf(LOGG_WARNING, "Failed to set locale\n");
|
||||
}
|
||||
#if !defined(C_BEOS)
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGXFSZ);
|
||||
sigprocmask(SIG_SETMASK, &sigset, NULL);
|
||||
#endif /* !C_BEOS */
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
cl_initialize_crypto();
|
||||
|
||||
if ((opts = optparse(NULL, argc, argv, 1, OPT_CLAMSCAN, 0, NULL)) == NULL) {
|
||||
mprintf(LOGG_ERROR, "Can't parse command line options\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (optget(opts, "verbose")->enabled) {
|
||||
mprintf_verbose = 1;
|
||||
logg_verbose = 1;
|
||||
}
|
||||
|
||||
if (optget(opts, "quiet")->enabled)
|
||||
mprintf_quiet = 1;
|
||||
|
||||
if (optget(opts, "stdout")->enabled)
|
||||
mprintf_stdout = 1;
|
||||
|
||||
if (optget(opts, "debug")->enabled) {
|
||||
#if defined(C_LINUX)
|
||||
/* njh@bandsman.co.uk: create a dump if needed */
|
||||
struct rlimit rlim;
|
||||
|
||||
rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
|
||||
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
|
||||
perror("setrlimit");
|
||||
#endif
|
||||
cl_debug(); /* enable debug messages */
|
||||
}
|
||||
|
||||
if (optget(opts, "gen-mdb")->enabled) {
|
||||
cl_always_gen_section_hash();
|
||||
}
|
||||
|
||||
if (optget(opts, "version")->enabled) {
|
||||
print_version(optget(opts, "database")->strarg);
|
||||
optfree(opts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (optget(opts, "help")->enabled) {
|
||||
optfree(opts);
|
||||
help();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (optget(opts, "recursive")->enabled)
|
||||
recursion = 1;
|
||||
|
||||
if (optget(opts, "infected")->enabled)
|
||||
printinfected = 1;
|
||||
|
||||
if (optget(opts, "suppress-ok-results")->enabled)
|
||||
printclean = 0;
|
||||
|
||||
if (optget(opts, "bell")->enabled)
|
||||
bell = 1;
|
||||
|
||||
/* initialize logger */
|
||||
if ((opt = optget(opts, "log"))->enabled) {
|
||||
logg_file = opt->strarg;
|
||||
if (logg(LOGG_INFO_NF, "\n-------------------------------------------------------------------------------\n\n")) {
|
||||
mprintf(LOGG_ERROR, "Problem with internal logger.\n");
|
||||
optfree(opts);
|
||||
return 2;
|
||||
}
|
||||
} else
|
||||
logg_file = NULL;
|
||||
|
||||
if (actsetup(opts)) {
|
||||
optfree(opts);
|
||||
logg_close();
|
||||
exit(2);
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(struct s_info));
|
||||
|
||||
date_start = time(NULL);
|
||||
gettimeofday(&t1, NULL);
|
||||
|
||||
ret = scanmanager(opts);
|
||||
|
||||
if (!optget(opts, "no-summary")->enabled) {
|
||||
struct tm tmp;
|
||||
|
||||
date_end = time(NULL);
|
||||
gettimeofday(&t2, NULL);
|
||||
ds = t2.tv_sec - t1.tv_sec;
|
||||
dms = t2.tv_usec - t1.tv_usec;
|
||||
ds -= (dms < 0) ? (1) : (0);
|
||||
dms += (dms < 0) ? (1000000) : (0);
|
||||
logg(LOGG_INFO, "\n----------- SCAN SUMMARY -----------\n");
|
||||
logg(LOGG_INFO, "Known viruses: %u\n", info.sigs);
|
||||
logg(LOGG_INFO, "Engine version: %s\n", get_version());
|
||||
logg(LOGG_INFO, "Scanned directories: %u\n", info.dirs);
|
||||
logg(LOGG_INFO, "Scanned files: %u\n", info.files);
|
||||
logg(LOGG_INFO, "Infected files: %u\n", info.ifiles);
|
||||
if (info.errors)
|
||||
logg(LOGG_INFO, "Total errors: %u\n", info.errors);
|
||||
if (notremoved) {
|
||||
logg(LOGG_INFO, "Not removed: %u\n", notremoved);
|
||||
}
|
||||
if (notmoved) {
|
||||
logg(LOGG_INFO, "Not %s: %u\n", optget(opts, "copy")->enabled ? "moved" : "copied", notmoved);
|
||||
}
|
||||
mb = info.blocks * (CL_COUNT_PRECISION / 1024) / 1024.0;
|
||||
logg(LOGG_INFO, "Data scanned: %2.2lf MB\n", mb);
|
||||
rmb = info.rblocks * (CL_COUNT_PRECISION / 1024) / 1024.0;
|
||||
logg(LOGG_INFO, "Data read: %2.2lf MB (ratio %.2f:1)\n", rmb, info.rblocks ? (double)info.blocks / (double)info.rblocks : 0);
|
||||
logg(LOGG_INFO, "Time: %u.%3.3u sec (%u m %u s)\n", ds, dms / 1000, ds / 60, ds % 60);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (0 != localtime_s(&tmp, &date_start)) {
|
||||
#else
|
||||
if (!localtime_r(&date_start, &tmp)) {
|
||||
#endif
|
||||
logg(LOGG_ERROR, "Failed to get local time for Start Date.\n");
|
||||
}
|
||||
strftime(buffer, sizeof(buffer), "%Y:%m:%d %H:%M:%S", &tmp);
|
||||
logg(LOGG_INFO, "Start Date: %s\n", buffer);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (0 != localtime_s(&tmp, &date_end)) {
|
||||
#else
|
||||
if (!localtime_r(&date_end, &tmp)) {
|
||||
#endif
|
||||
logg(LOGG_ERROR, "Failed to get local time for End Date.\n");
|
||||
}
|
||||
strftime(buffer, sizeof(buffer), "%Y:%m:%d %H:%M:%S", &tmp);
|
||||
logg(LOGG_INFO, "End Date: %s\n", buffer);
|
||||
}
|
||||
|
||||
optfree(opts);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void help(void)
|
||||
{
|
||||
mprintf_stdout = 1;
|
||||
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, " Clam AntiVirus: Scanner %s\n", get_version());
|
||||
mprintf(LOGG_INFO, " By The ClamAV Team: https://www.clamav.net/about.html#credits\n");
|
||||
mprintf(LOGG_INFO, " (C) 2022 Cisco Systems, Inc.\n");
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, " clamscan [options] [file/directory/-]\n");
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, " --help -h Show this help\n");
|
||||
mprintf(LOGG_INFO, " --version -V Print version number\n");
|
||||
mprintf(LOGG_INFO, " --verbose -v Be verbose\n");
|
||||
mprintf(LOGG_INFO, " --archive-verbose -a Show filenames inside scanned archives\n");
|
||||
mprintf(LOGG_INFO, " --debug Enable libclamav's debug messages\n");
|
||||
mprintf(LOGG_INFO, " --quiet Only output error messages\n");
|
||||
mprintf(LOGG_INFO, " --stdout Write to stdout instead of stderr. Does not affect 'debug' messages.\n");
|
||||
mprintf(LOGG_INFO, " --no-summary Disable summary at end of scanning\n");
|
||||
mprintf(LOGG_INFO, " --infected -i Only print infected files\n");
|
||||
mprintf(LOGG_INFO, " --suppress-ok-results -o Skip printing OK files\n");
|
||||
mprintf(LOGG_INFO, " --bell Sound bell on virus detection\n");
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, " --tempdir=DIRECTORY Create temporary files in DIRECTORY\n");
|
||||
mprintf(LOGG_INFO, " --leave-temps[=yes/no(*)] Do not remove temporary files\n");
|
||||
mprintf(LOGG_INFO, " --gen-json[=yes/no(*)] Generate JSON metadata for the scanned file(s). For testing & development use ONLY.\n");
|
||||
mprintf(LOGG_INFO, " JSON will be printed if --debug is enabled.\n");
|
||||
mprintf(LOGG_INFO, " A JSON file will dropped to the temp directory if --leave-temps is enabled.\n");
|
||||
mprintf(LOGG_INFO, " --database=FILE/DIR -d FILE/DIR Load virus database from FILE or load all supported db files from DIR\n");
|
||||
mprintf(LOGG_INFO, " --official-db-only[=yes/no(*)] Only load official signatures\n");
|
||||
mprintf(LOGG_INFO, " --log=FILE -l FILE Save scan report to FILE\n");
|
||||
mprintf(LOGG_INFO, " --recursive[=yes/no(*)] -r Scan subdirectories recursively\n");
|
||||
mprintf(LOGG_INFO, " --allmatch[=yes/no(*)] -z Continue scanning within file after finding a match\n");
|
||||
mprintf(LOGG_INFO, " --cross-fs[=yes(*)/no] Scan files and directories on other filesystems\n");
|
||||
mprintf(LOGG_INFO, " --follow-dir-symlinks[=0/1(*)/2] Follow directory symlinks (0 = never, 1 = direct, 2 = always)\n");
|
||||
mprintf(LOGG_INFO, " --follow-file-symlinks[=0/1(*)/2] Follow file symlinks (0 = never, 1 = direct, 2 = always)\n");
|
||||
mprintf(LOGG_INFO, " --file-list=FILE -f FILE Scan files from FILE\n");
|
||||
mprintf(LOGG_INFO, " --remove[=yes/no(*)] Remove infected files. Be careful!\n");
|
||||
mprintf(LOGG_INFO, " --move=DIRECTORY Move infected files into DIRECTORY\n");
|
||||
mprintf(LOGG_INFO, " --copy=DIRECTORY Copy infected files into DIRECTORY\n");
|
||||
mprintf(LOGG_INFO, " --exclude=REGEX Don't scan file names matching REGEX\n");
|
||||
mprintf(LOGG_INFO, " --exclude-dir=REGEX Don't scan directories matching REGEX\n");
|
||||
mprintf(LOGG_INFO, " --include=REGEX Only scan file names matching REGEX\n");
|
||||
mprintf(LOGG_INFO, " --include-dir=REGEX Only scan directories matching REGEX\n");
|
||||
#ifdef _WIN32
|
||||
mprintf(LOGG_INFO, " --memory Scan loaded executable modules\n");
|
||||
mprintf(LOGG_INFO, " --kill Kill/Unload infected loaded modules\n");
|
||||
mprintf(LOGG_INFO, " --unload Unload infected modules from processes\n");
|
||||
#endif
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, " --bytecode[=yes(*)/no] Load bytecode from the database\n");
|
||||
mprintf(LOGG_INFO, " --bytecode-unsigned[=yes/no(*)] Load unsigned bytecode\n");
|
||||
mprintf(LOGG_INFO, " **Caution**: You should NEVER run bytecode signatures from untrusted sources.\n");
|
||||
mprintf(LOGG_INFO, " Doing so may result in arbitrary code execution.\n");
|
||||
mprintf(LOGG_INFO, " --bytecode-timeout=N Set bytecode timeout (in milliseconds)\n");
|
||||
mprintf(LOGG_INFO, " --statistics[=none(*)/bytecode/pcre] Collect and print execution statistics\n");
|
||||
mprintf(LOGG_INFO, " --detect-pua[=yes/no(*)] Detect Possibly Unwanted Applications\n");
|
||||
mprintf(LOGG_INFO, " --exclude-pua=CAT Skip PUA sigs of category CAT\n");
|
||||
mprintf(LOGG_INFO, " --include-pua=CAT Load PUA sigs of category CAT\n");
|
||||
mprintf(LOGG_INFO, " --detect-structured[=yes/no(*)] Detect structured data (SSN, Credit Card)\n");
|
||||
mprintf(LOGG_INFO, " --structured-ssn-format=X SSN format (0=normal,1=stripped,2=both)\n");
|
||||
mprintf(LOGG_INFO, " --structured-ssn-count=N Min SSN count to generate a detect\n");
|
||||
mprintf(LOGG_INFO, " --structured-cc-count=N Min CC count to generate a detect\n");
|
||||
mprintf(LOGG_INFO, " --structured-cc-mode=X CC mode (0=credit debit and private label, 1=credit cards only\n");
|
||||
mprintf(LOGG_INFO, " --scan-mail[=yes(*)/no] Scan mail files\n");
|
||||
mprintf(LOGG_INFO, " --phishing-sigs[=yes(*)/no] Enable email signature-based phishing detection\n");
|
||||
mprintf(LOGG_INFO, " --phishing-scan-urls[=yes(*)/no] Enable URL signature-based phishing detection\n");
|
||||
mprintf(LOGG_INFO, " --heuristic-alerts[=yes(*)/no] Heuristic alerts\n");
|
||||
mprintf(LOGG_INFO, " --heuristic-scan-precedence[=yes/no(*)] Stop scanning as soon as a heuristic match is found\n");
|
||||
mprintf(LOGG_INFO, " --normalize[=yes(*)/no] Normalize html, script, and text files. Use normalize=no for yara compatibility\n");
|
||||
mprintf(LOGG_INFO, " --scan-pe[=yes(*)/no] Scan PE files\n");
|
||||
mprintf(LOGG_INFO, " --scan-elf[=yes(*)/no] Scan ELF files\n");
|
||||
mprintf(LOGG_INFO, " --scan-ole2[=yes(*)/no] Scan OLE2 containers\n");
|
||||
mprintf(LOGG_INFO, " --scan-pdf[=yes(*)/no] Scan PDF files\n");
|
||||
mprintf(LOGG_INFO, " --scan-swf[=yes(*)/no] Scan SWF files\n");
|
||||
mprintf(LOGG_INFO, " --scan-html[=yes(*)/no] Scan HTML files\n");
|
||||
mprintf(LOGG_INFO, " --scan-xmldocs[=yes(*)/no] Scan xml-based document files\n");
|
||||
mprintf(LOGG_INFO, " --scan-hwp3[=yes(*)/no] Scan HWP3 files\n");
|
||||
mprintf(LOGG_INFO, " --scan-archive[=yes(*)/no] Scan archive files (supported by libclamav)\n");
|
||||
mprintf(LOGG_INFO, " --alert-broken[=yes/no(*)] Alert on broken executable files (PE & ELF)\n");
|
||||
mprintf(LOGG_INFO, " --alert-broken-media[=yes/no(*)] Alert on broken graphics files (JPEG, TIFF, PNG, GIF)\n");
|
||||
mprintf(LOGG_INFO, " --alert-encrypted[=yes/no(*)] Alert on encrypted archives and documents\n");
|
||||
mprintf(LOGG_INFO, " --alert-encrypted-archive[=yes/no(*)] Alert on encrypted archives\n");
|
||||
mprintf(LOGG_INFO, " --alert-encrypted-doc[=yes/no(*)] Alert on encrypted documents\n");
|
||||
mprintf(LOGG_INFO, " --alert-macros[=yes/no(*)] Alert on OLE2 files containing VBA macros\n");
|
||||
mprintf(LOGG_INFO, " --alert-exceeds-max[=yes/no(*)] Alert on files that exceed max file size, max scan size, or max recursion limit\n");
|
||||
mprintf(LOGG_INFO, " --alert-phishing-ssl[=yes/no(*)] Alert on emails containing SSL mismatches in URLs\n");
|
||||
mprintf(LOGG_INFO, " --alert-phishing-cloak[=yes/no(*)] Alert on emails containing cloaked URLs\n");
|
||||
mprintf(LOGG_INFO, " --alert-partition-intersection[=yes/no(*)] Alert on raw DMG image files containing partition intersections\n");
|
||||
mprintf(LOGG_INFO, " --nocerts Disable authenticode certificate chain verification in PE files\n");
|
||||
mprintf(LOGG_INFO, " --dumpcerts Dump authenticode certificate chain in PE files\n");
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, " --max-scantime=#n Scan time longer than this will be skipped and assumed clean (milliseconds)\n");
|
||||
mprintf(LOGG_INFO, " --max-filesize=#n Files larger than this will be skipped and assumed clean\n");
|
||||
mprintf(LOGG_INFO, " --max-scansize=#n The maximum amount of data to scan for each container file (**)\n");
|
||||
mprintf(LOGG_INFO, " --max-files=#n The maximum number of files to scan for each container file (**)\n");
|
||||
mprintf(LOGG_INFO, " --max-recursion=#n Maximum archive recursion level for container file (**)\n");
|
||||
mprintf(LOGG_INFO, " --max-dir-recursion=#n Maximum directory recursion level\n");
|
||||
mprintf(LOGG_INFO, " --max-embeddedpe=#n Maximum size file to check for embedded PE\n");
|
||||
mprintf(LOGG_INFO, " --max-htmlnormalize=#n Maximum size of HTML file to normalize\n");
|
||||
mprintf(LOGG_INFO, " --max-htmlnotags=#n Maximum size of normalized HTML file to scan\n");
|
||||
mprintf(LOGG_INFO, " --max-scriptnormalize=#n Maximum size of script file to normalize\n");
|
||||
mprintf(LOGG_INFO, " --max-ziptypercg=#n Maximum size zip to type reanalyze\n");
|
||||
mprintf(LOGG_INFO, " --max-partitions=#n Maximum number of partitions in disk image to be scanned\n");
|
||||
mprintf(LOGG_INFO, " --max-iconspe=#n Maximum number of icons in PE file to be scanned\n");
|
||||
mprintf(LOGG_INFO, " --max-rechwp3=#n Maximum recursive calls to HWP3 parsing function\n");
|
||||
#if HAVE_PCRE
|
||||
mprintf(LOGG_INFO, " --pcre-match-limit=#n Maximum calls to the PCRE match function.\n");
|
||||
mprintf(LOGG_INFO, " --pcre-recmatch-limit=#n Maximum recursive calls to the PCRE match function.\n");
|
||||
mprintf(LOGG_INFO, " --pcre-max-filesize=#n Maximum size file to perform PCRE subsig matching.\n");
|
||||
#endif /* HAVE_PCRE */
|
||||
mprintf(LOGG_INFO, " --disable-cache Disable caching and cache checks for hash sums of scanned files.\n");
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, "Pass in - as the filename for stdin.\n");
|
||||
mprintf(LOGG_INFO, "\n");
|
||||
mprintf(LOGG_INFO, "(*) Default scan settings\n");
|
||||
mprintf(LOGG_INFO, "(**) Certain files (e.g. documents, archives, etc.) may in turn contain other\n");
|
||||
mprintf(LOGG_INFO, " files inside. The above options ensure safe processing of this kind of data.\n\n");
|
||||
}
|
||||
39
clamav/clamscan/global.h
Normal file
39
clamav/clamscan/global.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2007-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: Tomasz Kojm
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __GLOBAL_H
|
||||
#define __GLOBAL_H
|
||||
|
||||
struct s_info {
|
||||
unsigned int sigs; /* number of signatures */
|
||||
unsigned int dirs; /* number of scanned directories */
|
||||
unsigned int files; /* number of scanned files */
|
||||
unsigned int ifiles; /* number of infected files */
|
||||
unsigned int errors; /* number of errors */
|
||||
unsigned long int blocks; /* number of *scanned* 16kb blocks */
|
||||
unsigned long int rblocks; /* number of *read* 16kb blocks */
|
||||
};
|
||||
|
||||
extern struct s_info info;
|
||||
extern short recursion, bell;
|
||||
extern short printinfected, printclean;
|
||||
|
||||
#endif
|
||||
1676
clamav/clamscan/manager.c
Normal file
1676
clamav/clamscan/manager.c
Normal file
File diff suppressed because it is too large
Load Diff
29
clamav/clamscan/manager.h
Normal file
29
clamav/clamscan/manager.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2007-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: Tomasz Kojm
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __MANAGER_H
|
||||
#define __MANAGER_H
|
||||
|
||||
#include "optparser.h"
|
||||
|
||||
int scanmanager(const struct optstruct *opts);
|
||||
|
||||
#endif
|
||||
84
clamav/common/CMakeLists.txt
Normal file
84
clamav/common/CMakeLists.txt
Normal file
@@ -0,0 +1,84 @@
|
||||
# Copyright (C) 2020-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
|
||||
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
|
||||
|
||||
# Windows compatibility headers
|
||||
include_directories(${CMAKE_SOURCE_DIR}/win32/compat)
|
||||
endif()
|
||||
|
||||
# The "common" static library.
|
||||
add_library( common STATIC )
|
||||
target_sources( common
|
||||
PRIVATE
|
||||
cert_util.c
|
||||
actions.c
|
||||
clamdcom.c
|
||||
getopt.c
|
||||
hostid.c
|
||||
idmef_logging.c
|
||||
misc.c
|
||||
optparser.c
|
||||
output.c
|
||||
tar.c
|
||||
PUBLIC
|
||||
cert_util.h
|
||||
actions.h
|
||||
clamdcom.h
|
||||
fdpassing.h
|
||||
getopt.h
|
||||
hostid.h
|
||||
idmef_logging.h
|
||||
misc.h
|
||||
optparser.h
|
||||
output.h
|
||||
tar.h )
|
||||
|
||||
target_include_directories( common
|
||||
PRIVATE ${CMAKE_BINARY_DIR}
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
|
||||
if(FOUND_SYSTEMD)
|
||||
target_include_directories( common
|
||||
PRIVATE ${SYSTEMD_INCLUDE_DIRS} )
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
target_sources( common PRIVATE mac/cert_util_mac.m )
|
||||
elseif(WIN32)
|
||||
target_sources( common
|
||||
PRIVATE service.c scanmem.c exescanner.c
|
||||
PUBLIC service.h scanmem.h exescanner.h )
|
||||
target_sources( common PRIVATE win/cert_util_win.c )
|
||||
else()
|
||||
target_sources( common PRIVATE linux/cert_util_linux.c )
|
||||
endif()
|
||||
|
||||
target_link_libraries( common
|
||||
PUBLIC
|
||||
ClamAV::libclamav
|
||||
ZLIB::ZLIB
|
||||
CURL::libcurl
|
||||
OpenSSL::SSL
|
||||
OpenSSL::Crypto )
|
||||
if(WIN32)
|
||||
target_link_libraries( common
|
||||
PUBLIC
|
||||
crypt32
|
||||
psapi)
|
||||
endif()
|
||||
|
||||
if(HAVE_SYSTEMD)
|
||||
target_link_libraries( common
|
||||
PRIVATE
|
||||
SYSTEMD::systemd )
|
||||
endif()
|
||||
|
||||
set_target_properties( common PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}" )
|
||||
if(WIN32)
|
||||
set_target_properties(common PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
endif()
|
||||
|
||||
add_library( ClamAV::common ALIAS common )
|
||||
717
clamav/common/actions.c
Normal file
717
clamav/common/actions.c
Normal file
@@ -0,0 +1,717 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2009-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Author: aCaB, Micah Snyder
|
||||
*
|
||||
* These functions are actions that may be taken when a sample alerts.
|
||||
* The user may wish to:
|
||||
* - move file to destination directory.
|
||||
* - copy file to destination directory.
|
||||
* - remove (delete) the file.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "clamav-config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
|
||||
// libclamav
|
||||
#include "clamav.h"
|
||||
#include "str.h"
|
||||
#include "others.h"
|
||||
#include "optparser.h"
|
||||
#include "output.h"
|
||||
#include "misc.h"
|
||||
#include "actions.h"
|
||||
|
||||
void (*action)(const char *) = NULL;
|
||||
unsigned int notmoved = 0, notremoved = 0;
|
||||
|
||||
static char *actarget;
|
||||
static int targlen;
|
||||
|
||||
static int getdest(const char *fullpath, char **newname)
|
||||
{
|
||||
char *tmps, *filename;
|
||||
int fd, i;
|
||||
|
||||
tmps = strdup(fullpath);
|
||||
if (!tmps) {
|
||||
*newname = NULL;
|
||||
return -1;
|
||||
}
|
||||
filename = basename(tmps);
|
||||
|
||||
if (!(*newname = (char *)malloc(targlen + strlen(filename) + 6))) {
|
||||
free(tmps);
|
||||
return -1;
|
||||
}
|
||||
sprintf(*newname, "%s" PATHSEP "%s", actarget, filename);
|
||||
for (i = 1; i < 1000; i++) {
|
||||
fd = open(*newname, O_WRONLY | O_CREAT | O_EXCL, 0600);
|
||||
if (fd >= 0) {
|
||||
free(tmps);
|
||||
return fd;
|
||||
}
|
||||
if (errno != EEXIST) break;
|
||||
sprintf(*newname, "%s" PATHSEP "%s.%03u", actarget, filename, i);
|
||||
}
|
||||
free(tmps);
|
||||
free(*newname);
|
||||
*newname = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
typedef LONG (*PNTCF)(
|
||||
PHANDLE FileHandle, // OUT
|
||||
ACCESS_MASK DesiredAccess,
|
||||
POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
PIO_STATUS_BLOCK IoStatusBlock, // OUT
|
||||
PLARGE_INTEGER AllocationSize,
|
||||
ULONG FileAttributes,
|
||||
ULONG ShareAccess,
|
||||
ULONG CreateDisposition,
|
||||
ULONG CreateOptions,
|
||||
PVOID EaBuffer,
|
||||
ULONG EaLength);
|
||||
|
||||
typedef void (*PRIUS)(
|
||||
PUNICODE_STRING DestinationString,
|
||||
PCWSTR SourceString);
|
||||
|
||||
/**
|
||||
* @brief A openat equivalent for Win32 with a check to NOFOLLOW soft-links.
|
||||
*
|
||||
* The caller is resposible for closing the HANDLE.
|
||||
*
|
||||
* For the desiredAccess, fileAttributes, createOptions, and shareAccess parameters
|
||||
* see https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntcreatefile
|
||||
*
|
||||
* @param current_handle The current handle. If set to NULL, then filename should be a drive letter.
|
||||
* @param filename The directory to open. If current_handle is valid, should be a directory found in the current directory.
|
||||
* @param pNtCreateFile A function pointer to the NtCreateFile Win32 Native API.
|
||||
* @param pRtlInitUnicodeString A function pointer to the RtlInitUnicodeString Win32 Native API.
|
||||
* @param desiredAccess The DesiredAccess option for NtCreateFile
|
||||
* @param fileAttributes The FileAttributes option for NtCreateFile
|
||||
* @param createOptions The CreateOptions option for NtCreateFile
|
||||
* @param shareAccess The ShareAccess option for NtCreateFile
|
||||
* @return HANDLE A handle on success, NULL on failure.
|
||||
*/
|
||||
static HANDLE win32_openat(
|
||||
HANDLE current_handle,
|
||||
const char *filename,
|
||||
PNTCF pNtCreateFile,
|
||||
PRIUS pRtlInitUnicodeString,
|
||||
ACCESS_MASK desiredAccess,
|
||||
ULONG fileAttributes,
|
||||
ULONG createOptions,
|
||||
ULONG shareAccess)
|
||||
{
|
||||
HANDLE next_handle = NULL;
|
||||
|
||||
LONG ntStatus;
|
||||
WCHAR *filenameW = NULL;
|
||||
UNICODE_STRING filenameU;
|
||||
int cchNextDirectoryName = 0;
|
||||
IO_STATUS_BLOCK ioStatusBlock = {0};
|
||||
OBJECT_ATTRIBUTES objAttributes = {0};
|
||||
FILE_ATTRIBUTE_TAG_INFO tagInfo = {0};
|
||||
|
||||
/* Convert filename to a UNICODE_STRING, required by the native API NtCreateFile() */
|
||||
cchNextDirectoryName = MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
|
||||
filenameW = malloc(cchNextDirectoryName * sizeof(WCHAR));
|
||||
if (NULL == filenameW) {
|
||||
logg(LOGG_INFO, "win32_openat: failed to allocate memory for next directory name UTF16LE string\n");
|
||||
goto done;
|
||||
}
|
||||
if (0 == MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, cchNextDirectoryName)) {
|
||||
logg(LOGG_INFO, "win32_openat: failed to allocate buffer for unicode version of intermediate directory name.\n");
|
||||
goto done;
|
||||
}
|
||||
pRtlInitUnicodeString(&filenameU, filenameW);
|
||||
|
||||
InitializeObjectAttributes(
|
||||
&objAttributes, // ObjectAttributes
|
||||
&filenameU, // ObjectName
|
||||
OBJ_CASE_INSENSITIVE, // Attributes
|
||||
current_handle, // Root directory
|
||||
NULL); // SecurityDescriptor
|
||||
|
||||
ntStatus = pNtCreateFile(
|
||||
&next_handle, // FileHandle
|
||||
desiredAccess, // DesiredAccess
|
||||
&objAttributes, // ObjectAttributes
|
||||
&ioStatusBlock, // [out] status
|
||||
0, // AllocationSize
|
||||
fileAttributes, // FileAttributes
|
||||
shareAccess, // ShareAccess
|
||||
FILE_OPEN, // CreateDisposition
|
||||
createOptions, // CreateOptions
|
||||
NULL, // EaBuffer
|
||||
0); // EaLength
|
||||
if (!NT_SUCCESS(ntStatus) || (NULL == next_handle)) {
|
||||
logg(LOGG_INFO, "win32_openat: Failed to open file '%s'. \nError: 0x%x \nioStatusBlock: 0x%x\n", filename, ntStatus, ioStatusBlock.Information);
|
||||
goto done;
|
||||
}
|
||||
logg(LOGG_DEBUG, "win32_openat: Opened file \"%s\"\n", filename);
|
||||
|
||||
if (0 == GetFileInformationByHandleEx(
|
||||
next_handle, // hFile,
|
||||
FileAttributeTagInfo, // FileInformationClass
|
||||
&tagInfo, // lpFileInformation
|
||||
sizeof(FILE_ATTRIBUTE_TAG_INFO))) { // dwBufferSize
|
||||
logg(LOGG_INFO, "win32_openat: Failed to get file information by handle '%s'. Error: %d.\n", filename, GetLastError());
|
||||
|
||||
CloseHandle(next_handle);
|
||||
next_handle = NULL;
|
||||
goto done;
|
||||
}
|
||||
logg(LOGG_DEBUG, "win32_openat: tagInfo.FileAttributes: 0x%0x\n", tagInfo.FileAttributes);
|
||||
logg(LOGG_DEBUG, "win32_openat: tagInfo.ReparseTag: 0x%0x\n", tagInfo.ReparseTag);
|
||||
if (0 != (tagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
|
||||
logg(LOGG_INFO, "win32_openat: File is a soft link: '%s' Aborting path traversal.\n\n", filename);
|
||||
|
||||
CloseHandle(next_handle);
|
||||
next_handle = NULL;
|
||||
goto done;
|
||||
}
|
||||
logg(LOGG_DEBUG, "win32_openat: File or directory is not a soft link.\n\n");
|
||||
|
||||
done:
|
||||
if (NULL != filenameW) {
|
||||
free(filenameW);
|
||||
}
|
||||
|
||||
return next_handle;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Traverse from root to the specified directory without following symlinks.
|
||||
*
|
||||
* The intention is so you can use `unlinkat` or `rename_at` to safely move or
|
||||
* delete the target directory.
|
||||
*
|
||||
* The caller is responsible for closing the output file descriptor if the
|
||||
* traversal succeeded.
|
||||
*
|
||||
* @param directory The directory to traverse to (must be NULL terminated).
|
||||
* @param want_directory_handle Set to true to get the directory handle containing the file, false to get the file handle.
|
||||
* @param[out] out_handle An open file descriptor or HANDLE (win32) for the directory.
|
||||
* @return 0 Traverse succeeded.
|
||||
* @return -1 Traverse failed.
|
||||
*/
|
||||
#ifndef _WIN32
|
||||
static int traverse_to(const char *directory, bool want_directory_handle, int *out_handle)
|
||||
#else
|
||||
static int traverse_to(const char *directory, bool want_directory_handle, HANDLE *out_handle)
|
||||
#endif
|
||||
{
|
||||
int status = -1;
|
||||
size_t tokens_count;
|
||||
const char *tokens[PATH_MAX / 2];
|
||||
size_t i;
|
||||
char *tokenized_directory = NULL;
|
||||
#ifndef _WIN32
|
||||
int current_handle = -1;
|
||||
int next_handle = -1;
|
||||
#else
|
||||
bool bNeedDeleteFileAccess = false;
|
||||
|
||||
HMODULE ntdll = NULL;
|
||||
PNTCF pNtCreateFile = NULL;
|
||||
PRIUS pRtlInitUnicodeString = NULL;
|
||||
|
||||
PHANDLE current_handle = NULL;
|
||||
PHANDLE next_handle = NULL;
|
||||
|
||||
ACCESS_MASK desiredAccess = STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE | SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_READ_EA;
|
||||
ULONG fileAttributes = FILE_ATTRIBUTE_DIRECTORY;
|
||||
ULONG createOptions = FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT;
|
||||
ULONG shareAccess = FILE_SHARE_READ;
|
||||
#endif
|
||||
|
||||
if (NULL == directory || NULL == out_handle) {
|
||||
logg(LOGG_INFO, "traverse_to: Invalid arguments!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
ntdll = LoadLibraryA("ntdll.dll");
|
||||
if (NULL == ntdll) {
|
||||
logg(LOGG_INFO, "traverse_to: failed to load ntdll!\n");
|
||||
goto done;
|
||||
}
|
||||
pNtCreateFile = (PNTCF)GetProcAddress(ntdll, "NtCreateFile");
|
||||
if (NULL == pNtCreateFile) {
|
||||
logg(LOGG_INFO, "traverse_to: failed to get NtCreateFile proc address!\n");
|
||||
goto done;
|
||||
}
|
||||
pRtlInitUnicodeString = (PRIUS)GetProcAddress(ntdll, "RtlInitUnicodeString");
|
||||
if (NULL == pRtlInitUnicodeString) {
|
||||
logg(LOGG_INFO, "traverse_to: failed to get pRtlInitUnicodeString proc address!\n");
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
tokenized_directory = strdup(directory);
|
||||
if (NULL == tokenized_directory) {
|
||||
logg(LOGG_INFO, "traverse_to: Failed to get copy of directory path to be tokenized!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
tokens_count = cli_strtokenize(tokenized_directory, *PATHSEP, PATH_MAX / 2, tokens);
|
||||
if (0 == tokens_count) {
|
||||
logg(LOGG_INFO, "traverse_to: tokenize of target directory returned 0 tokens!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/*
|
||||
* Open the root(/) directory, because it won't be the first token like a
|
||||
* drive letter (i.e. "C:") would be on Windows.
|
||||
*/
|
||||
current_handle = open("/", O_RDONLY | O_NOFOLLOW);
|
||||
if (-1 == current_handle) {
|
||||
logg(LOGG_INFO, "traverse_to: Failed to open file descriptor for '/' directory.\n");
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (true == want_directory_handle) {
|
||||
tokens_count -= 1;
|
||||
}
|
||||
|
||||
if (0 == tokens_count) {
|
||||
logg(LOGG_INFO, "traverse_to: Failed to get copy of directory path to be tokenized!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < tokens_count; i++) {
|
||||
if (0 == strlen(tokens[i])) {
|
||||
/* Empty token, likely first / or double // */
|
||||
continue;
|
||||
}
|
||||
#ifndef _WIN32
|
||||
next_handle = openat(current_handle, tokens[i], O_RDONLY | O_NOFOLLOW);
|
||||
if (-1 == next_handle) {
|
||||
logg(LOGG_INFO, "traverse_to: Failed open %s\n", tokens[i]);
|
||||
goto done;
|
||||
}
|
||||
close(current_handle);
|
||||
current_handle = next_handle;
|
||||
next_handle = -1;
|
||||
#else
|
||||
if (true != want_directory_handle) {
|
||||
if (i == tokens_count - 1) {
|
||||
/* Change createfile options for our target file instead of an intermediate directory. */
|
||||
desiredAccess = FILE_GENERIC_READ | DELETE;
|
||||
fileAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||
createOptions = FILE_NON_DIRECTORY_FILE;
|
||||
shareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
}
|
||||
}
|
||||
if (i == 0) {
|
||||
/* NtCreateFile requires the \???\ prefix on drive letters. Eg: \???\C:\ */
|
||||
size_t driveroot_len = strlen("\\??\\\\") + strlen(tokens[0]) + 1;
|
||||
char *driveroot = malloc(driveroot_len);
|
||||
snprintf(driveroot, driveroot_len + 1, "\\??\\%s\\", tokens[0]);
|
||||
next_handle = win32_openat(current_handle,
|
||||
driveroot,
|
||||
pNtCreateFile,
|
||||
pRtlInitUnicodeString,
|
||||
desiredAccess,
|
||||
fileAttributes,
|
||||
createOptions,
|
||||
shareAccess);
|
||||
free(driveroot);
|
||||
} else {
|
||||
next_handle = win32_openat(current_handle,
|
||||
tokens[i],
|
||||
pNtCreateFile,
|
||||
pRtlInitUnicodeString,
|
||||
desiredAccess,
|
||||
fileAttributes,
|
||||
createOptions,
|
||||
shareAccess);
|
||||
}
|
||||
if (NULL == next_handle) {
|
||||
logg(LOGG_INFO, "traverse_to: Failed open %s\n", tokens[i]);
|
||||
goto done;
|
||||
}
|
||||
CloseHandle(current_handle);
|
||||
current_handle = next_handle;
|
||||
next_handle = NULL;
|
||||
#endif
|
||||
logg(LOGG_DEBUG, "traverse_to: Handle opened for '%s' directory.\n", tokens[i]);
|
||||
}
|
||||
|
||||
status = 0;
|
||||
*out_handle = current_handle;
|
||||
|
||||
done:
|
||||
#ifndef _WIN32
|
||||
if ((-1 == status) && (-1 != current_handle)) {
|
||||
close(current_handle);
|
||||
}
|
||||
#else
|
||||
if ((-1 == status) && (NULL != current_handle)) {
|
||||
CloseHandle(current_handle);
|
||||
}
|
||||
#endif
|
||||
if (NULL != tokenized_directory) {
|
||||
free(tokenized_directory);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Rename (move) a file from Source to Destination without following symlinks.
|
||||
*
|
||||
* This approach mitigates the possibility that one of the directories
|
||||
* in the path has been replaces with a malicious symlink.
|
||||
*
|
||||
* @param source Source pathname.
|
||||
* @param destination Destination pathname (including file name)
|
||||
* @return 0 Rename succeeded.
|
||||
* @return -1 Rename failed.
|
||||
*/
|
||||
static int traverse_rename(const char *source, const char *destination)
|
||||
{
|
||||
int status = -1;
|
||||
#ifndef _WIN32
|
||||
cl_error_t ret;
|
||||
int source_directory_fd = -1;
|
||||
char *source_basename = NULL;
|
||||
#else
|
||||
FILE_RENAME_INFO *fileInfo = NULL;
|
||||
HANDLE source_file_handle = NULL;
|
||||
HANDLE destination_dir_handle = NULL;
|
||||
WCHAR *destFilepathW = NULL;
|
||||
int cchDestFilepath = 0;
|
||||
#endif
|
||||
|
||||
if (NULL == source || NULL == destination) {
|
||||
logg(LOGG_INFO, "traverse_rename: Invalid arguments!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
if (0 != traverse_to(source, true, &source_directory_fd)) {
|
||||
logg(LOGG_INFO, "traverse_rename: Failed to open file descriptor for source directory!\n");
|
||||
goto done;
|
||||
}
|
||||
#else
|
||||
if (0 != traverse_to(source, false, &source_file_handle)) {
|
||||
logg(LOGG_INFO, "traverse_rename: Failed to open file descriptor for source file!\n");
|
||||
goto done;
|
||||
}
|
||||
if (0 != traverse_to(destination, true, &destination_dir_handle)) {
|
||||
logg(LOGG_INFO, "traverse_rename: Failed to open file descriptor for destination directory!\n");
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
ret = cli_basename(source, strlen(source), &source_basename);
|
||||
if (CL_SUCCESS != ret) {
|
||||
logg(LOGG_INFO, "traverse_rename: Failed to get basename of source path:%s\n\tError: %d\n", source, (int)ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (0 != renameat(source_directory_fd, source_basename, -1, destination)) {
|
||||
logg(LOGG_INFO, "traverse_rename: Failed to rename: %s\n\tto: %s\nError:%s\n", source, destination, strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
#else
|
||||
/* Convert destination filepath to a PWCHAR */
|
||||
cchDestFilepath = MultiByteToWideChar(CP_UTF8, 0, destination, strlen(destination), NULL, 0);
|
||||
destFilepathW = calloc(cchDestFilepath * sizeof(WCHAR), 1);
|
||||
if (NULL == destFilepathW) {
|
||||
logg(LOGG_INFO, "traverse_rename: failed to allocate memory for destination basename UTF16LE string\n");
|
||||
goto done;
|
||||
}
|
||||
if (0 == MultiByteToWideChar(CP_UTF8, 0, destination, strlen(destination), destFilepathW, cchDestFilepath)) {
|
||||
logg(LOGG_INFO, "traverse_rename: failed to allocate buffer for UTF16LE version of destination file basename.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
fileInfo = calloc(1, sizeof(FILE_RENAME_INFO) + cchDestFilepath * sizeof(WCHAR));
|
||||
if (NULL == fileInfo) {
|
||||
logg(LOGG_INFO, "traverse_rename: failed to allocate memory for fileInfo struct\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
fileInfo->ReplaceIfExists = TRUE;
|
||||
fileInfo->RootDirectory = NULL;
|
||||
memcpy(fileInfo->FileName, destFilepathW, cchDestFilepath * sizeof(WCHAR));
|
||||
fileInfo->FileNameLength = cchDestFilepath;
|
||||
if (FALSE == SetFileInformationByHandle(
|
||||
source_file_handle, // FileHandle
|
||||
FileRenameInfo, // FileInformationClass
|
||||
fileInfo, // FileInformation
|
||||
sizeof(FILE_RENAME_INFO) + cchDestFilepath * sizeof(WCHAR))) { // Length
|
||||
|
||||
logg(LOGG_INFO, "traverse_rename: Failed to set file rename info for '%s' to '%s'.\nError: %d\n", source, destination, GetLastError());
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
status = 0;
|
||||
|
||||
done:
|
||||
|
||||
#ifndef _WIN32
|
||||
if (NULL != source_basename) {
|
||||
free(source_basename);
|
||||
}
|
||||
|
||||
if (-1 != source_directory_fd) {
|
||||
close(source_directory_fd);
|
||||
}
|
||||
#else
|
||||
if (NULL != fileInfo) {
|
||||
free(fileInfo);
|
||||
}
|
||||
if (NULL != destFilepathW) {
|
||||
free(destFilepathW);
|
||||
}
|
||||
if (NULL != source_file_handle) {
|
||||
CloseHandle(source_file_handle);
|
||||
}
|
||||
if (NULL != destination_dir_handle) {
|
||||
CloseHandle(destination_dir_handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unlink (delete) a target file without following symlinks.
|
||||
*
|
||||
* This approach mitigates the possibility that one of the directories
|
||||
* in the path has been replaces with a malicious symlink.
|
||||
*
|
||||
* @param target A file to be deleted.
|
||||
* @return 0 Unlink succeeded.
|
||||
* @return -1 Unlink failed.
|
||||
*/
|
||||
static int traverse_unlink(const char *target)
|
||||
{
|
||||
int status = -1;
|
||||
cl_error_t ret;
|
||||
#ifndef _WIN32
|
||||
int target_directory_fd = -1;
|
||||
#else
|
||||
FILE_DISPOSITION_INFO fileInfo = {0};
|
||||
HANDLE target_file_handle = NULL;
|
||||
#endif
|
||||
char *target_basename = NULL;
|
||||
|
||||
if (NULL == target) {
|
||||
logg(LOGG_INFO, "traverse_unlink: Invalid arguments!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/* On posix, we want a file descriptor for the directory */
|
||||
if (0 != traverse_to(target, true, &target_directory_fd)) {
|
||||
#else
|
||||
/* On Windows, we want a handle to the file, not the directory */
|
||||
if (0 != traverse_to(target, false, &target_file_handle)) {
|
||||
#endif
|
||||
logg(LOGG_INFO, "traverse_unlink: Failed to open file descriptor for target directory!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = cli_basename(target, strlen(target), &target_basename);
|
||||
if (CL_SUCCESS != ret) {
|
||||
logg(LOGG_INFO, "traverse_unlink: Failed to get basename of target path: %s\n\tError: %d\n", target, (int)ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
if (0 != unlinkat(target_directory_fd, target_basename, 0)) {
|
||||
logg(LOGG_INFO, "traverse_unlink: Failed to unlink: %s\nError:%s\n", target, strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
#else
|
||||
fileInfo.DeleteFileA = TRUE;
|
||||
if (FALSE == SetFileInformationByHandle(
|
||||
target_file_handle, // FileHandle
|
||||
FileDispositionInfo, // FileInformationClass
|
||||
&fileInfo, // FileInformation
|
||||
sizeof(FILE_DISPOSITION_INFO))) { // Length
|
||||
|
||||
logg(LOGG_INFO, "traverse_unlink: Failed to set file disposition to 'DELETE' for '%s'.\n", target);
|
||||
goto done;
|
||||
}
|
||||
if (FALSE == CloseHandle(target_file_handle)) {
|
||||
logg(LOGG_INFO, "traverse_unlink: Failed to set close & delete file '%s'.\n", target);
|
||||
goto done;
|
||||
}
|
||||
target_file_handle = NULL;
|
||||
#endif
|
||||
|
||||
status = 0;
|
||||
|
||||
done:
|
||||
|
||||
if (NULL != target_basename) {
|
||||
free(target_basename);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
if (-1 != target_directory_fd) {
|
||||
close(target_directory_fd);
|
||||
}
|
||||
#else
|
||||
if (NULL != target_file_handle) {
|
||||
CloseHandle(target_file_handle);
|
||||
}
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
static void action_move(const char *filename)
|
||||
{
|
||||
char *nuname = NULL;
|
||||
char *real_filename = NULL;
|
||||
int fd = -1;
|
||||
int copied = 0;
|
||||
|
||||
if (NULL == filename) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
fd = getdest(filename, &nuname);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (fd < 0 || (0 != traverse_rename(filename, nuname) && ((copied = 1)) && filecopy(filename, nuname))) {
|
||||
#else
|
||||
if (fd < 0 || (((copied = 1)) && filecopy(filename, nuname))) {
|
||||
#endif
|
||||
logg(LOGG_ERROR, "Can't move file %s to %s\n", filename, nuname);
|
||||
notmoved++;
|
||||
if (nuname) traverse_unlink(nuname);
|
||||
} else {
|
||||
if (copied && (0 != traverse_unlink(filename)))
|
||||
logg(LOGG_ERROR, "Can't unlink '%s' after copy: %s\n", filename, strerror(errno));
|
||||
else
|
||||
logg(LOGG_INFO, "%s: moved to '%s'\n", filename, nuname);
|
||||
}
|
||||
|
||||
done:
|
||||
if (NULL != real_filename) free(real_filename);
|
||||
if (fd >= 0) close(fd);
|
||||
if (NULL != nuname) free(nuname);
|
||||
return;
|
||||
}
|
||||
|
||||
static void action_copy(const char *filename)
|
||||
{
|
||||
char *nuname;
|
||||
int fd = getdest(filename, &nuname);
|
||||
|
||||
if (fd < 0 || filecopy(filename, nuname)) {
|
||||
logg(LOGG_ERROR, "Can't copy file '%s'\n", filename);
|
||||
notmoved++;
|
||||
if (nuname) traverse_unlink(nuname);
|
||||
} else
|
||||
logg(LOGG_INFO, "%s: copied to '%s'\n", filename, nuname);
|
||||
|
||||
if (fd >= 0) close(fd);
|
||||
if (nuname) free(nuname);
|
||||
}
|
||||
|
||||
static void action_remove(const char *filename)
|
||||
{
|
||||
char *real_filename = NULL;
|
||||
|
||||
if (NULL == filename) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (0 != traverse_unlink(filename)) {
|
||||
logg(LOGG_ERROR, "Can't remove file '%s'\n", filename);
|
||||
notremoved++;
|
||||
} else {
|
||||
logg(LOGG_INFO, "%s: Removed.\n", filename);
|
||||
}
|
||||
|
||||
done:
|
||||
if (NULL != real_filename) free(real_filename);
|
||||
return;
|
||||
}
|
||||
|
||||
static int isdir(void)
|
||||
{
|
||||
STATBUF sb;
|
||||
if (CLAMSTAT(actarget, &sb) || !S_ISDIR(sb.st_mode)) {
|
||||
logg(LOGG_ERROR, "'%s' doesn't exist or is not a directory\n", actarget);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this function at the beginning to configure the user preference.
|
||||
* Later, call the "action" callback function to perform the selection action.
|
||||
*/
|
||||
int actsetup(const struct optstruct *opts)
|
||||
{
|
||||
int move = optget(opts, "move")->enabled;
|
||||
if (move || optget(opts, "copy")->enabled) {
|
||||
#ifndef _WIN32
|
||||
cl_error_t ret;
|
||||
#endif
|
||||
actarget = optget(opts, move ? "move" : "copy")->strarg;
|
||||
#ifndef _WIN32
|
||||
ret = cli_realpath((const char *)actarget, &actarget);
|
||||
if (CL_SUCCESS != ret || NULL == actarget) {
|
||||
logg(LOGG_INFO, "action_setup: Failed to get realpath of %s\n", actarget);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (!isdir()) return 1;
|
||||
action = move ? action_move : action_copy;
|
||||
targlen = strlen(actarget);
|
||||
} else if (optget(opts, "remove")->enabled)
|
||||
action = action_remove;
|
||||
return 0;
|
||||
}
|
||||
51
clamav/common/actions.h
Normal file
51
clamav/common/actions.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2009-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: aCaB
|
||||
*
|
||||
* These functions are actions that may be taken when a sample alerts.
|
||||
* The user may wish to:
|
||||
* - move file to destination directory.
|
||||
* - copy file to destination directory.
|
||||
* - remove (delete) the file.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ACTIONS_H
|
||||
#define ACTIONS_H
|
||||
|
||||
#include "optparser.h"
|
||||
|
||||
/**
|
||||
* @brief Callback function to perform the action requested when actsetup() was invoked.
|
||||
*
|
||||
* @param filename
|
||||
*/
|
||||
extern void (*action)(const char *);
|
||||
|
||||
/**
|
||||
* @brief Select the appropriate callback function based on the configuration options.
|
||||
*
|
||||
* @param opts Application configuration options.
|
||||
* @return int 0 if success.
|
||||
* @return int 1 if move or copy were selected but the destination directory does not exist.
|
||||
*/
|
||||
int actsetup(const struct optstruct *opts);
|
||||
|
||||
extern unsigned int notremoved, notmoved;
|
||||
|
||||
#endif
|
||||
699
clamav/common/cert_util.c
Normal file
699
clamav/common/cert_util.c
Normal file
@@ -0,0 +1,699 @@
|
||||
/*
|
||||
* OpenSSL certificate caching.
|
||||
*
|
||||
* Copyright (C) 2016-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Authors: Russ Kubik
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "cert_util.h"
|
||||
#include "cert_util_internal.h"
|
||||
|
||||
#include "output.h"
|
||||
|
||||
static cert_store_t _cert_store = {
|
||||
.mutex = PTHREAD_MUTEX_INITIALIZER};
|
||||
|
||||
static cl_error_t _x509_to_pem(X509 *cert,
|
||||
char **data,
|
||||
int *len)
|
||||
{
|
||||
cl_error_t ret = CL_EFORMAT;
|
||||
|
||||
BIO *out = NULL;
|
||||
long pem_len = 0;
|
||||
char *pem_data = NULL;
|
||||
|
||||
if (cert == NULL || data == NULL || len == NULL) {
|
||||
mprintf(LOGG_ERROR, "_x509_to_pem: Invalid argument\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Output the certs to a new BIO using the PEM format */
|
||||
out = BIO_new(BIO_s_mem());
|
||||
if (!out) {
|
||||
mprintf(LOGG_ERROR, "BIO_new failed\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
PEM_write_bio_X509(out, cert);
|
||||
|
||||
(void)BIO_flush(out);
|
||||
|
||||
/* Convert the BIO to char* */
|
||||
pem_len = BIO_get_mem_data(out, &pem_data);
|
||||
if (pem_len <= 0 || !pem_data) {
|
||||
mprintf(LOGG_ERROR, "BIO_new: BIO_get_mem_data failed\n");
|
||||
BIO_free_all(out);
|
||||
goto done;
|
||||
}
|
||||
|
||||
*data = calloc(1, pem_len + 1);
|
||||
if (!*data) {
|
||||
mprintf(LOGG_ERROR, "BIO_new: malloc failed\n");
|
||||
BIO_free_all(out);
|
||||
goto done;
|
||||
}
|
||||
memcpy(*data, pem_data, pem_len);
|
||||
(*data)[pem_len] = '\0';
|
||||
|
||||
*len = (int)pem_len;
|
||||
|
||||
BIO_free_all(out);
|
||||
|
||||
ret = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This method will convert a X509 certificate to PEM format and append
|
||||
* it to a string buffer.
|
||||
*
|
||||
* @note If realloc fails to reserve memory for *cert_data it will free whatever
|
||||
* is currently in *cert_data before returning. total_buf_len is also set
|
||||
* to 0 (zero) in this case.
|
||||
*
|
||||
* @param[in] *ca_cert Pointer to CA certificate
|
||||
* @param[out] **cert_data Pointer to allocated string buffer
|
||||
* @param[out] *total_buf_len Total of string buffer length after appending
|
||||
* CA certificate (ca_cert)
|
||||
* @param[in,out] *remaining_buf_len Remaining data left allowed in CA certificate
|
||||
* chain after appending CA certificate
|
||||
* (ca_cert)
|
||||
*
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
static cl_error_t _x509_to_pem_append(X509 *ca_cert,
|
||||
char **cert_data,
|
||||
int *total_buf_len,
|
||||
size_t *remaining_buf_len)
|
||||
{
|
||||
char *pem_data = NULL;
|
||||
char *tmp;
|
||||
int pem_data_len = 0;
|
||||
cl_error_t ret = CL_EOPEN;
|
||||
int current_len = 0;
|
||||
|
||||
if (ca_cert == NULL || total_buf_len == NULL ||
|
||||
remaining_buf_len == NULL || *cert_data == NULL) {
|
||||
mprintf(LOGG_ERROR, "NULL parameter given\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
current_len = *total_buf_len;
|
||||
|
||||
if (CL_SUCCESS != _x509_to_pem(ca_cert, &pem_data, &pem_data_len)) {
|
||||
mprintf(LOGG_ERROR, "Failed to convert x509 certificate to PEM\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (pem_data_len > (int)*remaining_buf_len) {
|
||||
tmp = realloc(*cert_data, current_len + pem_data_len + 1);
|
||||
if (tmp == NULL) {
|
||||
mprintf(LOGG_ERROR, "Could not realloc enough memory for PEM "
|
||||
"certificate\n");
|
||||
|
||||
free(*cert_data);
|
||||
*cert_data = NULL;
|
||||
*total_buf_len = 0;
|
||||
|
||||
goto done;
|
||||
}
|
||||
*cert_data = tmp;
|
||||
tmp = NULL;
|
||||
*remaining_buf_len = 0;
|
||||
} else {
|
||||
*remaining_buf_len -= pem_data_len;
|
||||
}
|
||||
|
||||
memcpy(&((*cert_data)[current_len]), pem_data, pem_data_len);
|
||||
*total_buf_len = current_len + pem_data_len;
|
||||
(*cert_data)[*total_buf_len] = '\0';
|
||||
|
||||
ret = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
|
||||
free(pem_data);
|
||||
pem_data = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
cert_store_t *cert_store_get_int(void)
|
||||
{
|
||||
return &_cert_store;
|
||||
}
|
||||
|
||||
void cert_store_unload_int(void)
|
||||
{
|
||||
if (_cert_store.loaded) {
|
||||
cert_store_free_cert_list_int(&_cert_store.system_certs);
|
||||
cert_store_free_cert_list_int(&_cert_store.trusted_certs);
|
||||
_cert_store.loaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
void cert_store_free_cert_list_int(cert_list_t *cert_list)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (cert_list && cert_list->certificates) {
|
||||
for (i = 0; i < cert_list->count; ++i) {
|
||||
X509_free(cert_list->certificates[i]);
|
||||
cert_list->certificates[i] = NULL;
|
||||
}
|
||||
|
||||
free(cert_list->certificates);
|
||||
cert_list->certificates = NULL;
|
||||
cert_list->count = 0L;
|
||||
}
|
||||
}
|
||||
|
||||
void cert_store_unload(void)
|
||||
{
|
||||
int pt_err;
|
||||
|
||||
pt_err = pthread_mutex_lock(&_cert_store.mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex lock failed\n");
|
||||
}
|
||||
|
||||
cert_store_unload_int();
|
||||
|
||||
pt_err = pthread_mutex_unlock(&_cert_store.mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0+ */
|
||||
static cl_error_t x509_cert_name_cmp(X509 *cert_a, X509 *cert_b, int *cmp_out)
|
||||
{
|
||||
cl_error_t status = CL_EMEM;
|
||||
|
||||
X509_NAME *a = NULL;
|
||||
X509_NAME *b = NULL;
|
||||
|
||||
BIO *bio_out_a = NULL;
|
||||
BIO *bio_out_b = NULL;
|
||||
|
||||
BUF_MEM *biomem_a;
|
||||
BUF_MEM *biomem_b;
|
||||
|
||||
bio_out_a = BIO_new(BIO_s_mem());
|
||||
if (!bio_out_a)
|
||||
goto done;
|
||||
|
||||
bio_out_b = BIO_new(BIO_s_mem());
|
||||
if (!bio_out_b)
|
||||
goto done;
|
||||
|
||||
a = X509_get_subject_name(cert_a);
|
||||
|
||||
if (-1 == X509_NAME_print_ex(bio_out_a, a, 0, XN_FLAG_SEP_SPLUS_SPC)) {
|
||||
mprintf(LOGG_ERROR, "Failed to print x509 certificate name!\n");
|
||||
goto done;
|
||||
}
|
||||
BIO_get_mem_ptr(bio_out_a, &biomem_a);
|
||||
|
||||
b = X509_get_subject_name(cert_b);
|
||||
|
||||
if (-1 == X509_NAME_print_ex(bio_out_b, b, 0, XN_FLAG_SEP_SPLUS_SPC)) {
|
||||
mprintf(LOGG_ERROR, "Failed to print x509 certificate name!\n");
|
||||
goto done;
|
||||
}
|
||||
BIO_get_mem_ptr(bio_out_b, &biomem_b);
|
||||
|
||||
*cmp_out = strncmp(biomem_a->data, biomem_b->data, MIN(biomem_a->length, biomem_b->length));
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
if (NULL != bio_out_a)
|
||||
BIO_free(bio_out_a);
|
||||
if (NULL != bio_out_b)
|
||||
BIO_free(bio_out_b);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
cl_error_t x509_get_cert_name(X509 *cert, char **name)
|
||||
{
|
||||
cl_error_t status = CL_EMEM;
|
||||
|
||||
X509_NAME *a = NULL;
|
||||
BIO *bio_out = NULL;
|
||||
BUF_MEM *biomem;
|
||||
char *cert_name = NULL;
|
||||
|
||||
if (NULL == cert || NULL == name) {
|
||||
status = CL_EARG;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*name = NULL;
|
||||
|
||||
bio_out = BIO_new(BIO_s_mem());
|
||||
if (!bio_out)
|
||||
goto done;
|
||||
|
||||
a = X509_get_subject_name(cert);
|
||||
|
||||
if (-1 == X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC)) {
|
||||
mprintf(LOGG_ERROR, "Failed to print x509 certificate name!\n");
|
||||
goto done;
|
||||
}
|
||||
BIO_get_mem_ptr(bio_out, &biomem);
|
||||
|
||||
cert_name = malloc(biomem->length + 1);
|
||||
if (!cert_name) {
|
||||
mprintf(LOGG_ERROR, "Failed to allocate memory for certificate name biomem structure!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(cert_name, biomem->data, biomem->length);
|
||||
cert_name[biomem->length] = '\0';
|
||||
|
||||
*name = cert_name;
|
||||
status = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
if (NULL != bio_out)
|
||||
BIO_free(bio_out);
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
cl_error_t cert_store_export_pem(char **cert_data,
|
||||
int *cert_data_len,
|
||||
X509 *additional_ca_cert)
|
||||
{
|
||||
const uint32_t STARTING_RAW_PEM_LENGTH = 350 * 1024;
|
||||
uint32_t i;
|
||||
cl_error_t ret = CL_EOPEN;
|
||||
bool locked = false;
|
||||
int pt_err;
|
||||
|
||||
size_t remaining_buf_len = STARTING_RAW_PEM_LENGTH;
|
||||
bool add_additional_ca_cert = true;
|
||||
|
||||
if ((cert_data == NULL) || (cert_data_len == NULL)) {
|
||||
mprintf(LOGG_ERROR, "One or more arguments are NULL\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
*cert_data = calloc(1, STARTING_RAW_PEM_LENGTH + 1);
|
||||
if (*cert_data == NULL) {
|
||||
mprintf(LOGG_ERROR, "Could not allocate memory for PEM certs\n");
|
||||
goto done;
|
||||
}
|
||||
*cert_data_len = 0;
|
||||
|
||||
pt_err = pthread_mutex_lock(&_cert_store.mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex lock failed\n");
|
||||
}
|
||||
locked = true;
|
||||
|
||||
if (!_cert_store.loaded) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Load system root ca certs into list */
|
||||
for (i = 0; i < _cert_store.system_certs.count; ++i) {
|
||||
if (_x509_to_pem_append(_cert_store.system_certs.certificates[i],
|
||||
cert_data,
|
||||
cert_data_len,
|
||||
&remaining_buf_len) != 0) {
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* Two certs by the same name can cause conflicts. Trust the
|
||||
* one in the OS certificate/key store if the additional CA
|
||||
* name matches that of one in the store.
|
||||
*/
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
/* OpenSSL >= 1.1.0 */
|
||||
if (additional_ca_cert) {
|
||||
int cmp = 0;
|
||||
if (CL_SUCCESS == x509_cert_name_cmp(_cert_store.system_certs.certificates[i],
|
||||
additional_ca_cert,
|
||||
&cmp)) {
|
||||
if (0 == cmp)
|
||||
add_additional_ca_cert = false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* OpenSSL <= 1.0.2 */
|
||||
if (additional_ca_cert && additional_ca_cert->cert_info &&
|
||||
(strcmp(_cert_store.system_certs.certificates[i]->name,
|
||||
additional_ca_cert->name) == 0)) {
|
||||
add_additional_ca_cert = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Load trusted ca certs into list */
|
||||
for (i = 0; i < _cert_store.trusted_certs.count; ++i) {
|
||||
if (_x509_to_pem_append(_cert_store.trusted_certs.certificates[i],
|
||||
cert_data,
|
||||
cert_data_len,
|
||||
&remaining_buf_len) != 0) {
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* Two certs by the same name can cause conflicts. Trust the
|
||||
* one in the OS certificate/key store if the additional CA
|
||||
* name matches that of one in the store.
|
||||
*/
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
/* OpenSSL >= 1.1.0 */
|
||||
if (additional_ca_cert) {
|
||||
int cmp = 0;
|
||||
if (CL_SUCCESS == x509_cert_name_cmp(_cert_store.trusted_certs.certificates[i],
|
||||
additional_ca_cert,
|
||||
&cmp)) {
|
||||
if (0 == cmp)
|
||||
add_additional_ca_cert = false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* OpenSSL <= 1.0.2 */
|
||||
if (additional_ca_cert && additional_ca_cert->cert_info &&
|
||||
(strcmp(_cert_store.trusted_certs.certificates[i]->name,
|
||||
additional_ca_cert->name) == 0)) {
|
||||
add_additional_ca_cert = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* End with the additional CA certificate if provided */
|
||||
if (additional_ca_cert && add_additional_ca_cert && *cert_data) {
|
||||
/* Return an error only if we were unable to allocate memory */
|
||||
if (_x509_to_pem_append(additional_ca_cert,
|
||||
cert_data,
|
||||
cert_data_len,
|
||||
&remaining_buf_len) != 0) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ret = CL_SUCCESS;
|
||||
done:
|
||||
if (locked) {
|
||||
pt_err = pthread_mutex_unlock(&_cert_store.mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
|
||||
}
|
||||
locked = false;
|
||||
}
|
||||
|
||||
if (ret != CL_SUCCESS && cert_data && *cert_data) {
|
||||
free(*cert_data);
|
||||
*cert_data = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
cl_error_t cert_store_set_trusted_int(X509 **trusted_certs, size_t trusted_cert_count)
|
||||
{
|
||||
cl_error_t ret = CL_EOPEN;
|
||||
size_t i, j;
|
||||
cert_list_t tmp_trusted = {0};
|
||||
|
||||
do {
|
||||
if ((trusted_certs == NULL) || (trusted_cert_count == 0)) {
|
||||
mprintf(LOGG_ERROR, "Empty trusted certificate list\n");
|
||||
break;
|
||||
}
|
||||
|
||||
tmp_trusted.certificates = calloc(trusted_cert_count,
|
||||
sizeof(*tmp_trusted.certificates));
|
||||
if (!tmp_trusted.certificates) {
|
||||
mprintf(LOGG_ERROR, "Failed to reserve memory for trusted certs\n");
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < trusted_cert_count; ++i) {
|
||||
bool found = false;
|
||||
|
||||
/* Check if certificate already exists in system root cert list */
|
||||
for (j = 0; j < _cert_store.system_certs.count; ++j) {
|
||||
if (X509_cmp(trusted_certs[i],
|
||||
_cert_store.system_certs.certificates[j]) == 0) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
continue; /* certificate is already found in cert store */
|
||||
}
|
||||
|
||||
tmp_trusted.certificates[tmp_trusted.count] =
|
||||
X509_dup(trusted_certs[i]);
|
||||
if (!tmp_trusted.certificates[tmp_trusted.count]) {
|
||||
mprintf(LOGG_ERROR, "X509_dup failed at index: %zu\n", i);
|
||||
continue; /* continue on error */
|
||||
}
|
||||
|
||||
tmp_trusted.count++;
|
||||
}
|
||||
|
||||
cert_store_free_cert_list_int(&_cert_store.trusted_certs);
|
||||
|
||||
_cert_store.trusted_certs.certificates = tmp_trusted.certificates;
|
||||
_cert_store.trusted_certs.count = tmp_trusted.count;
|
||||
|
||||
tmp_trusted.certificates = NULL;
|
||||
tmp_trusted.count = 0;
|
||||
|
||||
ret = CL_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
cl_error_t cert_store_set_trusted(X509 **trusted_certs, size_t trusted_cert_count)
|
||||
{
|
||||
cl_error_t ret = CL_EOPEN;
|
||||
int pt_err;
|
||||
|
||||
pt_err = pthread_mutex_lock(&_cert_store.mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex lock failed\n");
|
||||
}
|
||||
|
||||
if (_cert_store.loaded) {
|
||||
ret = cert_store_set_trusted_int(trusted_certs, trusted_cert_count);
|
||||
}
|
||||
|
||||
pt_err = pthread_mutex_unlock(&_cert_store.mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t cert_store_remove_trusted(void)
|
||||
{
|
||||
size_t count = 0;
|
||||
int pt_err;
|
||||
|
||||
pt_err = pthread_mutex_lock(&_cert_store.mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex lock failed\n");
|
||||
}
|
||||
|
||||
if (_cert_store.loaded) {
|
||||
count = _cert_store.trusted_certs.count;
|
||||
cert_store_free_cert_list_int(&_cert_store.trusted_certs);
|
||||
}
|
||||
|
||||
pt_err = pthread_mutex_unlock(&_cert_store.mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void cert_fill_X509_store(X509_STORE *store, X509 **certs, size_t cert_count)
|
||||
{
|
||||
size_t i;
|
||||
unsigned long err;
|
||||
|
||||
if (store && certs && cert_count > 0) {
|
||||
for (i = 0; i < cert_count; ++i) {
|
||||
if (!certs[i]) {
|
||||
mprintf(LOGG_ERROR, "NULL cert at index %zu in X509 cert list; skipping\n", i);
|
||||
continue;
|
||||
}
|
||||
if (X509_STORE_add_cert(store, certs[i]) != 1) {
|
||||
char *name = NULL;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
x509_get_cert_name(certs[i], &name);
|
||||
#else
|
||||
name = certs[i]->name;
|
||||
#endif
|
||||
err = ERR_get_error();
|
||||
if (X509_R_CERT_ALREADY_IN_HASH_TABLE == ERR_GET_REASON(err)) {
|
||||
mprintf(LOGG_DEBUG, "Certificate skipped; already exists in store: %s\n",
|
||||
(name ? name : ""));
|
||||
} else {
|
||||
mprintf(LOGG_ERROR, "Failed to add certificate to store: %s (%lu) [%s]\n",
|
||||
ERR_error_string(err, NULL), err,
|
||||
(name ? name : ""));
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
if (NULL != name) {
|
||||
free(name);
|
||||
name = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cert_store_export_certs(X509_STORE *store, X509 *additional_ca_cert)
|
||||
{
|
||||
cert_store_t *cert_store = NULL;
|
||||
int pt_err;
|
||||
|
||||
do {
|
||||
if (!store) {
|
||||
mprintf(LOGG_ERROR, "NULL X509 store\n");
|
||||
break;
|
||||
}
|
||||
|
||||
cert_store = cert_store_get_int();
|
||||
if (!cert_store) {
|
||||
mprintf(LOGG_ERROR, "Failed to retrieve cert store\n");
|
||||
break;
|
||||
}
|
||||
|
||||
pt_err = pthread_mutex_lock(&cert_store->mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex lock failed\n");
|
||||
}
|
||||
|
||||
if (!cert_store->loaded) {
|
||||
mprintf(LOGG_ERROR, "Cert store not loaded\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* On Linux, system certificates are loaded by OpenSSL */
|
||||
#if defined(_WIN32) || defined(DARWIN)
|
||||
cert_fill_X509_store(store,
|
||||
cert_store->system_certs.certificates,
|
||||
cert_store->system_certs.count);
|
||||
#endif
|
||||
|
||||
cert_fill_X509_store(store,
|
||||
cert_store->trusted_certs.certificates,
|
||||
cert_store->trusted_certs.count);
|
||||
|
||||
/* Adding the additional CA cert to the trustchain */
|
||||
if ((additional_ca_cert != NULL) &&
|
||||
(X509_STORE_add_cert(store, additional_ca_cert) != 1)) {
|
||||
char *name = NULL;
|
||||
unsigned long err = ERR_get_error();
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
x509_get_cert_name(additional_ca_cert, &name);
|
||||
#else
|
||||
name = additional_ca_cert->name;
|
||||
#endif
|
||||
if (X509_R_CERT_ALREADY_IN_HASH_TABLE == ERR_GET_REASON(err)) {
|
||||
mprintf(LOGG_INFO, "Certificate is already in trust [%s]\n",
|
||||
(name ? name : ""));
|
||||
} else {
|
||||
mprintf(LOGG_ERROR, "Failed to add CA certificate for the SSL context. "
|
||||
"Error: %d [%s]\n",
|
||||
ERR_GET_REASON(err),
|
||||
(name ? name : ""));
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
if (NULL != name) {
|
||||
free(name);
|
||||
name = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (cert_store) {
|
||||
pt_err = pthread_mutex_unlock(&cert_store->mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CURLcode sslctx_function(CURL *curl, void *ssl_ctx, void *userptr)
|
||||
{
|
||||
CURLcode status = CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
cert_store_t *cert_store = NULL;
|
||||
|
||||
UNUSEDPARAM(curl);
|
||||
UNUSEDPARAM(userptr);
|
||||
|
||||
cert_store = cert_store_get_int();
|
||||
if (!cert_store) {
|
||||
mprintf(LOGG_ERROR, "Failed to retrieve cert store\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!cert_store->loaded) {
|
||||
if (CL_SUCCESS != cert_store_load(NULL, 0)) {
|
||||
mprintf(LOGG_ERROR, "Failed to load cert store\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
X509_STORE *store = SSL_CTX_get_cert_store((SSL_CTX *)ssl_ctx);
|
||||
|
||||
cert_store_export_certs(store, NULL);
|
||||
|
||||
status = CURLE_OK;
|
||||
|
||||
done:
|
||||
|
||||
return status;
|
||||
}
|
||||
130
clamav/common/cert_util.h
Normal file
130
clamav/common/cert_util.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* OpenSSL certificate store
|
||||
*
|
||||
* @file cert_util.h
|
||||
*
|
||||
* @author Russ Kubik
|
||||
* @date 2016-05-11
|
||||
* @copyright Copyright (c) 2016 Cisco Systems, Inc.
|
||||
*
|
||||
* @section DESCRIPTION
|
||||
* OpenSSL certificate store
|
||||
*/
|
||||
#ifndef _CERT_UTIL_H
|
||||
#define _CERT_UTIL_H
|
||||
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "clamav.h"
|
||||
|
||||
/* As defined by ub-common-name in https://www.ietf.org/rfc/rfc3280.txt */
|
||||
#define X509_COMMON_NAME_MAX_LEN (64)
|
||||
|
||||
#if !(defined(C_DARWIN) || defined(_WIN32))
|
||||
/**
|
||||
* @brief Set the tls ca bundle to a custom value using the CURL_CA_BUNDLE env var
|
||||
*
|
||||
* @param curl Pointer to the curl connection handle.
|
||||
*/
|
||||
void set_tls_ca_bundle(CURL *curl);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Load system and trusted root certificates into memory. Any errors
|
||||
* while loading trusted certificates will be ignored. If error checking
|
||||
* is required for trusted certificates please use cert_store_set_trusted
|
||||
* directly.
|
||||
*
|
||||
* @details To load the certificate store with system certificates only pass
|
||||
* NULL for trusted_certs and 0 (zero) for trusted_cert_count. The
|
||||
* certificates store will then only load root certificates from the
|
||||
* system and skip setting trusted certificates (which are
|
||||
* optional and can be set later with cert_store_set_trusted).
|
||||
*
|
||||
* @param[in] trusted_certs - List of X509 trusted root certificates (NULL for
|
||||
* empty or no trusted certificates)
|
||||
* @param[in] trusted_cert_count - Number of trusted root certificates (0 for
|
||||
* empty or no trusted certificates)
|
||||
*
|
||||
* @return 0 on success or if the cert store is already loaded, -1 on error
|
||||
*/
|
||||
cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count);
|
||||
|
||||
/**
|
||||
* @brief Free system and trusted root certificates.
|
||||
*/
|
||||
void cert_store_unload(void);
|
||||
|
||||
/**
|
||||
* @brief Set trusted root certificates in the cert store. If trusted
|
||||
* certificates already exist then they are removed.
|
||||
*
|
||||
* @param[in] trusted_certs - List of trusted X509 root certificates
|
||||
* @param[in] trusted_cert_count - Number of trusted X509 root certificates
|
||||
*
|
||||
* @return 0 on success or -1 on error
|
||||
*/
|
||||
cl_error_t cert_store_set_trusted(X509 **trusted_certs, size_t trusted_cert_count);
|
||||
|
||||
/**
|
||||
* @brief Remove trusted root certificates from the cert store.
|
||||
*
|
||||
* @return a count of how many trusted certificates were removed. 0 (zero) will
|
||||
* be returned if the cert store is not initialized
|
||||
*/
|
||||
size_t cert_store_remove_trusted(void);
|
||||
|
||||
/**
|
||||
* @brief Export all system and trusted root certificates from the cert store
|
||||
* into an SSL X509_STORE. The additional_ca_cert will also be exported
|
||||
* if provided (not NULL).
|
||||
*
|
||||
* @param[out] store - SSL X509 store context
|
||||
* @param[in] additional_ca_cert - additional CA certificate to append (if not
|
||||
* NULL)
|
||||
*/
|
||||
void cert_store_export_certs(X509_STORE *store, X509 *additional_ca_cert);
|
||||
|
||||
/**
|
||||
* @brief Export all system and trusted root certificates from the cert store as
|
||||
* a null-terminated string. Certificates within the string will be
|
||||
* PEM-encoded.
|
||||
*
|
||||
* @details An example user of this method is the EST library which, as part of
|
||||
* its initialization, will ensure that the length of the CA chain
|
||||
* matches a given length.
|
||||
*
|
||||
* @link common/est/src/src/est_client.c
|
||||
*
|
||||
* @param[out] cert_data - Root CA certificate PEM buffer
|
||||
* @param[out] cert_data_len - Length of cert_data buffer
|
||||
* @param[in] additional_ca_cert - an additional CA certificate to append
|
||||
*
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
cl_error_t cert_store_export_pem(char **cert_data,
|
||||
int *cert_data_len,
|
||||
X509 *additional_ca_cert);
|
||||
|
||||
/**
|
||||
* @brief Add certificates to X509 store. Duplicate certificates are skipped
|
||||
* and errors are printed to the log.
|
||||
*
|
||||
* @param[in] store - Pointer to X509 store
|
||||
* @param[in] certs - List of X509 certificates
|
||||
* @param[in] cert_count - Number of X509 certificates
|
||||
*/
|
||||
void cert_fill_X509_store(X509_STORE *store, X509 **certs, size_t cert_count);
|
||||
|
||||
/**
|
||||
* @brief Callback function for libcurl to verify certificates for HTTPS connections.
|
||||
*
|
||||
* @param[in] curl - handle for curl connection.
|
||||
* @param[in] ssl_ctx - List of X509 certificates
|
||||
* @param[in] userptr - Number of X509 certificates
|
||||
*/
|
||||
CURLcode sslctx_function(CURL *curl, void *ssl_ctx, void *userptr);
|
||||
|
||||
#endif
|
||||
93
clamav/common/cert_util_internal.h
Normal file
93
clamav/common/cert_util_internal.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Internal certificate utility methods and data structures.
|
||||
*
|
||||
* Copyright (C) 2016-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Authors: Russ Kubik
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _CERT_UTIL_INT_H
|
||||
#define _CERT_UTIL_INT_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "clamav.h"
|
||||
|
||||
typedef struct {
|
||||
X509 **certificates;
|
||||
size_t count;
|
||||
} cert_list_t;
|
||||
|
||||
typedef struct {
|
||||
pthread_mutex_t mutex;
|
||||
bool loaded;
|
||||
cert_list_t system_certs;
|
||||
cert_list_t trusted_certs;
|
||||
} cert_store_t;
|
||||
|
||||
/**
|
||||
* @brief Accessor method for cert store.
|
||||
*
|
||||
* @return Pointer to cert store
|
||||
*/
|
||||
cert_store_t *cert_store_get_int(void);
|
||||
|
||||
/**
|
||||
* @brief Free all certificates loaded by config_store_load.
|
||||
*
|
||||
* @details This method does not hold the cert store lock and should not be
|
||||
* called outside of cert_util.
|
||||
*/
|
||||
void cert_store_unload_int(void);
|
||||
|
||||
/**
|
||||
* @brief Free memory allocated by a cert_list_t structure.
|
||||
*
|
||||
* @param[in] cert_list - Pointer to a cert_list_t structure
|
||||
*/
|
||||
void cert_store_free_cert_list_int(cert_list_t *cert_list);
|
||||
|
||||
/**
|
||||
* @brief Set trusted root certificates in the cert store. If trusted
|
||||
* certificates already exist in the cert store then they are removed.
|
||||
*
|
||||
* @details This method does not hold the cert store lock and should not be
|
||||
* called outside of cert_util.
|
||||
*
|
||||
* @param[in] trusted_certs - List of X509 trusted root certificates
|
||||
* @param[in] trusted_cert_count - Number of trusted root certificates
|
||||
*
|
||||
* @return 0 on success or -1 on error
|
||||
*/
|
||||
cl_error_t cert_store_set_trusted_int(X509 **trusted_certs, size_t trusted_cert_count);
|
||||
|
||||
/**
|
||||
* @brief Get the name from an X509 certificate.
|
||||
* Required if OPENSSL_VERSION_NUMBER >= 0x10100000L ( 1.1.0+ )
|
||||
* because the X509 structure is now opaque.
|
||||
*
|
||||
* The name must be free()'d by the caller.
|
||||
*
|
||||
* @param[in] cert - The cert in question.
|
||||
* @param[out] name - The NULL terminated name.
|
||||
* @return cl_error_t CL_SUCCESS on success.
|
||||
*/
|
||||
cl_error_t x509_get_cert_name(X509 *cert, char **name);
|
||||
|
||||
#endif
|
||||
483
clamav/common/clamdcom.c
Normal file
483
clamav/common/clamdcom.c
Normal file
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2009-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Author: aCaB
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include "clamav.h"
|
||||
#include "actions.h"
|
||||
#include "output.h"
|
||||
#include "clamdcom.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
struct sockaddr_un nixsock;
|
||||
#endif
|
||||
|
||||
static const char *scancmd[] = {"CONTSCAN", "MULTISCAN", "INSTREAM", "FILDES", "ALLMATCHSCAN"};
|
||||
|
||||
/* Sends bytes over a socket
|
||||
* Returns 0 on success */
|
||||
int sendln(int sockd, const char *line, unsigned int len)
|
||||
{
|
||||
while (len) {
|
||||
int sent = send(sockd, line, len, 0);
|
||||
if (sent <= 0) {
|
||||
if (sent && errno == EINTR) continue;
|
||||
logg(LOGG_ERROR, "Can't send to clamd: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
line += sent;
|
||||
len -= sent;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Inits a RECVLN struct before it can be used in recvln() - see below */
|
||||
void recvlninit(struct RCVLN *s, int sockd)
|
||||
{
|
||||
s->sockd = sockd;
|
||||
s->bol = s->cur = s->buf;
|
||||
s->r = 0;
|
||||
}
|
||||
|
||||
/* Receives a full (terminated with \0) line from a socket
|
||||
* Sets rbol to the begin of the received line, and optionally
|
||||
* reol to the end of line.
|
||||
* Should be called repeatedly until all input is consumed
|
||||
* Returns:
|
||||
* - the length of the line (a positive number) on success
|
||||
* - 0 if the connection is closed
|
||||
* - -1 on error
|
||||
*/
|
||||
int recvln(struct RCVLN *s, char **rbol, char **reol)
|
||||
{
|
||||
char *eol;
|
||||
|
||||
while (1) {
|
||||
if (!s->r) {
|
||||
s->r = recv(s->sockd, s->cur, sizeof(s->buf) - (s->cur - s->buf), 0);
|
||||
if (s->r <= 0) {
|
||||
if (s->r && errno == EINTR) {
|
||||
s->r = 0;
|
||||
continue;
|
||||
}
|
||||
if (s->r || s->cur != s->buf) {
|
||||
*s->cur = '\0';
|
||||
if (strcmp(s->buf, "UNKNOWN COMMAND\n"))
|
||||
logg(LOGG_ERROR, "Communication error\n");
|
||||
else
|
||||
logg(LOGG_ERROR, "Command rejected by clamd (wrong clamd version?)\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if ((eol = memchr(s->cur, 0, s->r))) {
|
||||
int ret = 0;
|
||||
eol++;
|
||||
s->r -= eol - s->cur;
|
||||
*rbol = s->bol;
|
||||
if (reol) *reol = eol;
|
||||
ret = eol - s->bol;
|
||||
if (s->r)
|
||||
s->bol = s->cur = eol;
|
||||
else
|
||||
s->bol = s->cur = s->buf;
|
||||
return ret;
|
||||
}
|
||||
s->r += s->cur - s->bol;
|
||||
if (!eol && s->r == sizeof(s->buf)) {
|
||||
logg(LOGG_ERROR, "Overlong reply from clamd\n");
|
||||
return -1;
|
||||
}
|
||||
if (!eol) {
|
||||
if (s->buf != s->bol) { /* old memmove sux */
|
||||
memmove(s->buf, s->bol, s->r);
|
||||
s->bol = s->buf;
|
||||
}
|
||||
s->cur = &s->bol[s->r];
|
||||
s->r = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determines if a path should be excluded
|
||||
* 0: scan, 1: skip */
|
||||
int chkpath(const char *path, struct optstruct *clamdopts)
|
||||
{
|
||||
int status = 0;
|
||||
const struct optstruct *opt;
|
||||
char *real_path = NULL;
|
||||
|
||||
if (!path) {
|
||||
status = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((opt = optget(clamdopts, "ExcludePath"))->enabled) {
|
||||
while (opt) {
|
||||
if (match_regex(path, opt->strarg) == 1) {
|
||||
logg(LOGG_DEBUG, "%s: Excluded\n", path);
|
||||
status = 1;
|
||||
goto done;
|
||||
}
|
||||
opt = opt->nextarg;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (NULL != real_path) {
|
||||
free(real_path);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FD_PASSING
|
||||
/* Issues a FILDES command and pass a FD to clamd
|
||||
* Returns >0 on success, 0 soft fail, -1 hard fail */
|
||||
int send_fdpass(int sockd, const char *filename)
|
||||
{
|
||||
struct iovec iov[1];
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmsg;
|
||||
unsigned char fdbuf[CMSG_SPACE(sizeof(int))];
|
||||
char dummy[] = "";
|
||||
int fd;
|
||||
const char zFILDES[] = "zFILDES";
|
||||
|
||||
if (filename) {
|
||||
if ((fd = open(filename, O_RDONLY)) < 0) {
|
||||
logg(LOGG_INFO, "%s: Failed to open file\n", filename);
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
fd = 0;
|
||||
if (sendln(sockd, zFILDES, sizeof(zFILDES))) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
iov[0].iov_base = dummy;
|
||||
iov[0].iov_len = 1;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_control = fdbuf;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_controllen = CMSG_LEN(sizeof(int));
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
*(int *)CMSG_DATA(cmsg) = fd;
|
||||
if (sendmsg(sockd, &msg, 0) == -1) {
|
||||
logg(LOGG_ERROR, "FD send failed: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Issues an INSTREAM command to clamd and streams the given file
|
||||
* Returns >0 on success, 0 soft fail, -1 hard fail */
|
||||
int send_stream(int sockd, const char *filename, struct optstruct *clamdopts)
|
||||
{
|
||||
uint32_t buf[BUFSIZ / sizeof(uint32_t)];
|
||||
int fd, len;
|
||||
unsigned long int todo = optget(clamdopts, "StreamMaxLength")->numarg;
|
||||
const char zINSTREAM[] = "zINSTREAM";
|
||||
|
||||
if (filename) {
|
||||
if ((fd = safe_open(filename, O_RDONLY | O_BINARY)) < 0) {
|
||||
logg(LOGG_INFO, "%s: Failed to open file. ERROR\n", filename);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* Read stream from STDIN */
|
||||
fd = 0;
|
||||
}
|
||||
|
||||
if (sendln(sockd, zINSTREAM, sizeof(zINSTREAM))) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((len = read(fd, &buf[1], sizeof(buf) - sizeof(uint32_t))) > 0) {
|
||||
if ((unsigned int)len > todo) len = todo;
|
||||
buf[0] = htonl(len);
|
||||
if (sendln(sockd, (const char *)buf, len + sizeof(uint32_t))) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
todo -= len;
|
||||
if (!todo) {
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
if (len) {
|
||||
logg(LOGG_ERROR, "Failed to read from %s.\n", filename ? filename : "STDIN");
|
||||
return 0;
|
||||
}
|
||||
*buf = 0;
|
||||
sendln(sockd, (const char *)buf, 4);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Connects to clamd
|
||||
* Returns a FD or -1 on error */
|
||||
int dconnect(struct optstruct *clamdopts)
|
||||
{
|
||||
int sockd, res;
|
||||
const struct optstruct *opt;
|
||||
struct addrinfo hints, *info, *p;
|
||||
char port[10];
|
||||
char *ipaddr;
|
||||
|
||||
#ifndef _WIN32
|
||||
opt = optget(clamdopts, "LocalSocket");
|
||||
if (opt->enabled) {
|
||||
if ((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) {
|
||||
if (connect(sockd, (struct sockaddr *)&nixsock, sizeof(nixsock)) == 0)
|
||||
return sockd;
|
||||
else {
|
||||
logg(LOGG_ERROR, "Could not connect to clamd on LocalSocket %s: %s\n", opt->strarg, strerror(errno));
|
||||
close(sockd);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
snprintf(port, sizeof(port), "%lld", optget(clamdopts, "TCPSocket")->numarg);
|
||||
|
||||
opt = optget(clamdopts, "TCPAddr");
|
||||
while (opt) {
|
||||
if (opt->enabled) {
|
||||
ipaddr = NULL;
|
||||
if (opt->strarg)
|
||||
ipaddr = (!strcmp(opt->strarg, "any") ? NULL : opt->strarg);
|
||||
|
||||
memset(&hints, 0x00, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if ((res = getaddrinfo(ipaddr, port, &hints, &info))) {
|
||||
logg(LOGG_ERROR, "Could not lookup %s: %s\n", ipaddr ? ipaddr : "", gai_strerror(res));
|
||||
opt = opt->nextarg;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (p = info; p != NULL; p = p->ai_next) {
|
||||
if ((sockd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) {
|
||||
logg(LOGG_ERROR, "Can't create the socket: %s\n", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (connect(sockd, p->ai_addr, p->ai_addrlen) < 0) {
|
||||
logg(LOGG_ERROR, "Could not connect to clamd on %s: %s\n", opt->strarg, strerror(errno));
|
||||
closesocket(sockd);
|
||||
continue;
|
||||
}
|
||||
|
||||
freeaddrinfo(info);
|
||||
return sockd;
|
||||
}
|
||||
|
||||
freeaddrinfo(info);
|
||||
}
|
||||
opt = opt->nextarg;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Sends a proper scan request to clamd and parses its replies
|
||||
* This is used only in non IDSESSION mode
|
||||
* Returns the number of infected files or -1 on error
|
||||
* NOTE: filename may be NULL for STREAM scantype. */
|
||||
int dsresult(int sockd, int scantype, const char *filename, int *printok, int *errors, struct optstruct *clamdopts)
|
||||
{
|
||||
int infected = 0, len = 0, beenthere = 0;
|
||||
char *bol, *eol;
|
||||
struct RCVLN rcv;
|
||||
STATBUF sb;
|
||||
|
||||
if (filename) {
|
||||
if (1 == chkpath(filename, clamdopts)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
recvlninit(&rcv, sockd);
|
||||
|
||||
switch (scantype) {
|
||||
case MULTI:
|
||||
case CONT:
|
||||
case ALLMATCH:
|
||||
if (!filename) {
|
||||
logg(LOGG_INFO, "Filename cannot be NULL for MULTISCAN or CONTSCAN.\n");
|
||||
infected = -1;
|
||||
goto done;
|
||||
}
|
||||
len = strlen(filename) + strlen(scancmd[scantype]) + 3;
|
||||
if (!(bol = malloc(len))) {
|
||||
logg(LOGG_ERROR, "Cannot allocate a command buffer: %s\n", strerror(errno));
|
||||
infected = -1;
|
||||
goto done;
|
||||
}
|
||||
sprintf(bol, "z%s %s", scancmd[scantype], filename);
|
||||
if (sendln(sockd, bol, len)) {
|
||||
free(bol);
|
||||
infected = -1;
|
||||
goto done;
|
||||
}
|
||||
free(bol);
|
||||
break;
|
||||
|
||||
case STREAM:
|
||||
/* NULL filename safe in send_stream() */
|
||||
len = send_stream(sockd, filename, clamdopts);
|
||||
break;
|
||||
#ifdef HAVE_FD_PASSING
|
||||
case FILDES:
|
||||
/* NULL filename safe in send_fdpass() */
|
||||
len = send_fdpass(sockd, filename);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (len <= 0) {
|
||||
if (printok)
|
||||
*printok = 0;
|
||||
if (errors)
|
||||
(*errors)++;
|
||||
infected = len;
|
||||
goto done;
|
||||
}
|
||||
|
||||
while ((len = recvln(&rcv, &bol, &eol))) {
|
||||
if (len == -1) {
|
||||
infected = -1;
|
||||
goto done;
|
||||
}
|
||||
beenthere = 1;
|
||||
if (!filename) logg(LOGG_INFO, "%s\n", bol);
|
||||
if (len > 7) {
|
||||
char *colon = strrchr(bol, ':');
|
||||
if (colon && colon[1] != ' ') {
|
||||
char *br;
|
||||
*colon = 0;
|
||||
br = strrchr(bol, '(');
|
||||
if (br)
|
||||
*br = 0;
|
||||
colon = strrchr(bol, ':');
|
||||
}
|
||||
if (!colon) {
|
||||
char *unkco = "UNKNOWN COMMAND";
|
||||
if (!strncmp(bol, unkco, sizeof(unkco) - 1))
|
||||
logg(LOGG_INFO, "clamd replied \"UNKNOWN COMMAND\". Command was %s\n",
|
||||
(scantype < 0 || scantype > MAX_SCANTYPE) ? "unidentified" : scancmd[scantype]);
|
||||
else
|
||||
logg(LOGG_INFO, "Failed to parse reply: \"%s\"\n", bol);
|
||||
infected = -1;
|
||||
goto done;
|
||||
} else if (!memcmp(eol - 7, " FOUND", 6)) {
|
||||
static char last_filename[PATH_MAX + 1] = {'\0'};
|
||||
*(eol - 7) = 0;
|
||||
if (printok)
|
||||
*printok = 0;
|
||||
if (scantype != ALLMATCH) {
|
||||
infected++;
|
||||
} else {
|
||||
if (filename != NULL && strcmp(filename, last_filename)) {
|
||||
infected++;
|
||||
strncpy(last_filename, filename, PATH_MAX);
|
||||
last_filename[PATH_MAX] = '\0';
|
||||
}
|
||||
}
|
||||
if (filename) {
|
||||
if (scantype >= STREAM) {
|
||||
logg(LOGG_INFO, "%s%s FOUND\n", filename, colon);
|
||||
if (action) action(filename);
|
||||
} else {
|
||||
logg(LOGG_INFO, "%s FOUND\n", bol);
|
||||
*colon = '\0';
|
||||
if (action)
|
||||
action(bol);
|
||||
}
|
||||
}
|
||||
} else if (!memcmp(eol - 7, " ERROR", 6)) {
|
||||
if (errors)
|
||||
(*errors)++;
|
||||
if (printok)
|
||||
*printok = 0;
|
||||
if (filename) {
|
||||
if (scantype >= STREAM)
|
||||
logg(LOGG_INFO, "%s%s\n", filename, colon);
|
||||
else
|
||||
logg(LOGG_INFO, "%s\n", bol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!beenthere) {
|
||||
if (!filename) {
|
||||
logg(LOGG_INFO, "STDIN: noreply from clamd\n.");
|
||||
infected = -1;
|
||||
goto done;
|
||||
}
|
||||
if (CLAMSTAT(filename, &sb) == -1) {
|
||||
logg(LOGG_INFO, "%s: stat() failed with %s, clamd may not be responding\n",
|
||||
filename, strerror(errno));
|
||||
infected = -1;
|
||||
goto done;
|
||||
}
|
||||
if (!S_ISDIR(sb.st_mode)) {
|
||||
logg(LOGG_INFO, "%s: no reply from clamd\n", filename);
|
||||
infected = -1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return infected;
|
||||
}
|
||||
67
clamav/common/clamdcom.h
Normal file
67
clamav/common/clamdcom.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2009-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Author: aCaB
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __CLAMDCOM_H
|
||||
#define __CLAMDCOM_H
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "clamav-config.h"
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
enum {
|
||||
CONT,
|
||||
MULTI,
|
||||
STREAM,
|
||||
FILDES,
|
||||
ALLMATCH,
|
||||
MAX_SCANTYPE = ALLMATCH
|
||||
};
|
||||
|
||||
struct RCVLN {
|
||||
char buf[PATH_MAX + 1024]; /* FIXME must match that in clamd - bb1349 */
|
||||
int sockd;
|
||||
int r;
|
||||
char *cur;
|
||||
char *bol;
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
extern struct sockaddr_un nixsock;
|
||||
#endif
|
||||
|
||||
int sendln(int sockd, const char *line, unsigned int len);
|
||||
void recvlninit(struct RCVLN *s, int sockd);
|
||||
int recvln(struct RCVLN *s, char **rbol, char **reol);
|
||||
|
||||
int chkpath(const char *path, struct optstruct *clamdopts);
|
||||
#ifdef HAVE_FD_PASSING
|
||||
int send_fdpass(int sockd, const char *filename);
|
||||
#endif
|
||||
int send_stream(int sockd, const char *filename, struct optstruct *clamdopts);
|
||||
int dconnect(struct optstruct *clamdopts);
|
||||
int dsresult(int sockd, int scantype, const char *filename, int *printok, int *errors, struct optstruct *clamdopts);
|
||||
#endif
|
||||
330
clamav/common/exeScanner.c
Normal file
330
clamav/common/exeScanner.c
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2005-2010 Gianluigi Tiesi <sherpya@netfarm.it>
|
||||
*
|
||||
* Authors: Gianluigi Tiesi
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "exescanner.h"
|
||||
|
||||
/* -1 = wildchar - -2 = stop here */
|
||||
sigs_t signatures[] = {
|
||||
{{0x60, 0xbe, -1, -1, -1, -1, 0x8d, 0xbe, -1, -1, -1, 0xff, 0x57, -2},
|
||||
"UPX",
|
||||
.0f},
|
||||
{{0x94, 0xbc, 0x5d, 0x07, 0x42, 0x00, 0xb9, 0x1d, 0x00, 0x00, 0x00, 0x80,
|
||||
0x34, 0x0c, 0x44, 0xe2},
|
||||
"UPXSHiT",
|
||||
.0f},
|
||||
{{0xbe, 0xa4, 0x01, 0x40, 0x00, 0xad, 0x93, 0xad, 0x97, 0xad, 0x56, 0x96,
|
||||
0xb2, 0x80, 0xa4, 0xb6},
|
||||
"FSG 1.33",
|
||||
.0f},
|
||||
{{0x4d, 0x5a, -1, -1, -1, -1, -1, -1, -1, -1, 0x00, 0x00, 0x50, 0x45, 0x00,
|
||||
0x00},
|
||||
"FSG 2.00",
|
||||
.0f},
|
||||
{{0x4d, 0x5a, 0x4b, 0x45, 0x52, 0x4e, 0x45, 0x4c, 0x33, 0x32, 0x2e, 0x44,
|
||||
0x4c, 0x4c, 0x00, 0x00},
|
||||
"WinUpack 0.39",
|
||||
.0f},
|
||||
{{0xbe, 0x88, 0x01, 0x40, 0x00, 0xad, 0x8b, 0xf8, 0x95, 0xad, 0x91, 0xf3,
|
||||
0xa5, 0xad, 0xb5, 0x1c},
|
||||
"Upack 2.4/2.9",
|
||||
.0f},
|
||||
{{0xbe, 0x48, 0x01, 0x40, 0x00, 0xad, 0x8b, 0xf8, 0x95, 0xa5, 0x33, 0xc0,
|
||||
0x33, 0xc9, 0xab, 0x48},
|
||||
"Upack 1.1/1.2",
|
||||
.0f},
|
||||
{{0x83, 0xec, 0x20, 0x53, 0x55, 0x56, 0x33, 0xdb, 0x57, 0x89, 0x5c, 0x24,
|
||||
0x18, 0xc7, 0x44, 0x24},
|
||||
"NullSoft PiMP",
|
||||
.0f},
|
||||
{{0xe9, -1, -1, -1, 0xff, 0x0c, -1, -1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00},
|
||||
"Mew 11 1.2",
|
||||
.0f},
|
||||
{{0x60, 0xe9, 0x3d, 0x04, 0x00, 0x00, -2}, "ASPack 2.11", .0f},
|
||||
{{0x60, 0xe8, 0x03, 0x00, 0x00, 0x00, 0xe9, 0xeb, 0x04, 0x5d, 0x45, 0x55,
|
||||
0xc3, 0xe8, 0x01, 0x00},
|
||||
"ASPack 2.12",
|
||||
.0f},
|
||||
{{0x55, 0x83, 0xc4, 0x04, 0x76, 0x08, 0x7a, 0x06, 0x74, 0x04, 0x66, 0x83,
|
||||
0xea, 0x00, 0xf5, 0x50},
|
||||
"Morphine 1.4/2.7",
|
||||
.0f},
|
||||
{{0x56, 0x72, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x0b, 0xd2, 0xf9,
|
||||
0x84, 0xdb, 0x68, 0x34},
|
||||
"Morphine 1.4/2.7 [2]",
|
||||
.0f},
|
||||
{{0x53, 0x51, 0x52, 0x56, 0x57, 0x55, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x5d,
|
||||
0x8b, 0xd5, 0x81, 0xed},
|
||||
"PEDiminisher 0.1",
|
||||
.0f},
|
||||
|
||||
{{0xe8, 0xf6, 0x03, 0x00, 0x00, 0xe9, 0x9e, 0xfd, 0xff, 0xff, 0xcc, 0xcc,
|
||||
0xcc, 0xcc, 0xcc, 0xcc},
|
||||
"MSVC8 Release",
|
||||
-1.0f},
|
||||
{{0xe9, -1, -1, -1, 0x00, 0xe9, -1, -1, -1, 0x00, 0xe9, -1, -1, -1, 0x00,
|
||||
0xe9},
|
||||
"MSVC8 Debug",
|
||||
-1.0f},
|
||||
|
||||
{{0xe8, -1, -1, 0x00, 0x00, 0xe9, 0x16, 0xfe, 0xff, 0xff, -2},
|
||||
"MSVC6 Release",
|
||||
-2.0f},
|
||||
|
||||
{{0xe9, 0x96, 0xee, 0x0e, 0x00, 0xb8, 0x6c, 0x02, 0x58, 0x00, 0xe8, 0xae,
|
||||
0xe4, 0x0e, 0x00, 0x83},
|
||||
"MSVC6 Release (2)",
|
||||
-1.0f},
|
||||
{{0x55, 0x8b, 0xec, 0x6a, 0xff, 0x68, 0xb0, 0x41, 0x40, 0x00, 0x68, 0x10,
|
||||
0x36, 0x40, 0x00, 0x64},
|
||||
"MSVC6 Release (3)",
|
||||
-1.0f},
|
||||
{{0x55, 0x8b, 0xec, 0x53, 0x8b, 0x5d, 0x08, 0x56, 0x8b, 0x75, 0x0c, 0x57,
|
||||
0x8b, 0x7d, 0x10, 0x85},
|
||||
"MSVC6 Release (4)",
|
||||
-1.0f},
|
||||
|
||||
{{0x83, 0x7c, 0x24, 0x08, 0x01, 0x75, 0x05, 0xe8, -1, -1, 0x00, 0x00, 0xff,
|
||||
0x74, 0x24, 0x04},
|
||||
"MSVC6 Release DLL",
|
||||
-1.0f},
|
||||
{{0xff, 0x25, -1, -1, -1, -1, 0xcc, 0xcc, 0x03, 0x30, 0x01, 0x00, 0x07,
|
||||
0x00, 0x00, 0x00},
|
||||
"DotNet",
|
||||
-1.0f},
|
||||
{{0x55, 0x89, 0xe5, -2}, "MinGW", -1.0f},
|
||||
{{0}, 0, 0}};
|
||||
|
||||
int sigcmp(const uint8_t *data, const int16_t *sig, size_t n)
|
||||
{
|
||||
uint8_t *d = (uint8_t *)data;
|
||||
int16_t *s = (int16_t *)sig;
|
||||
while (n-- != 0) {
|
||||
if (*s == -2)
|
||||
return 0;
|
||||
if ((*s != -1) && (*d != *s))
|
||||
return (*d < *s) ? -1 : +1;
|
||||
d++;
|
||||
s++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sigs_t *checksig(uint8_t *data)
|
||||
{
|
||||
int i = 0;
|
||||
while (signatures[i].name) {
|
||||
if (!sigcmp(data, signatures[i].sig, 16))
|
||||
return &signatures[i];
|
||||
i++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
double calc_entropy(const unsigned char *data, size_t size)
|
||||
{
|
||||
double entropy = .0f;
|
||||
size_t p[256];
|
||||
size_t c, i;
|
||||
|
||||
memset(p, 0, sizeof(p));
|
||||
|
||||
for (c = 0; c < size; c++)
|
||||
p[data[c]]++;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
if (p[i])
|
||||
entropy -= ((double)p[i] / size) * log((double)p[i] / size);
|
||||
return entropy;
|
||||
}
|
||||
|
||||
#define FILLBYTES(dst) \
|
||||
if (IsBadReadPtr(seek, sizeof(dst))) { \
|
||||
logg(LOGG_ERROR, "exeScanner: Bad pointer!!!\n"); \
|
||||
goto cleanup; \
|
||||
} \
|
||||
memcpy(&dst, seek, sizeof(dst));
|
||||
|
||||
/* Packed exe heuristic detection, errors are handled as like of non packed data
|
||||
*/
|
||||
int is_packed(const char *filename)
|
||||
{
|
||||
int packed = 0;
|
||||
int i = 0, c = 0;
|
||||
int badsection = 0;
|
||||
double entropy = 0.0;
|
||||
sigs_t *sig = NULL;
|
||||
uint16_t e_mz;
|
||||
uint32_t e_lfanew, e_magic;
|
||||
uint32_t epoff = 0;
|
||||
unsigned char *seek = NULL, *s_start = NULL, *ep = NULL, *lpMapAddress = NULL;
|
||||
PIMAGE_FILE_HEADER pehdr;
|
||||
PIMAGE_OPTIONAL_HEADER32 opthdr;
|
||||
PIMAGE_SECTION_HEADER sechdr;
|
||||
char secname[IMAGE_SIZEOF_SHORT_NAME];
|
||||
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE, hMapFile = NULL;
|
||||
|
||||
hFile = CreateFileA(filename, GENERIC_READ, 0, NULL, OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
elogg(LOGG_INFO, "exeScanner: CreateFileA failed %lu\n", GetLastError());
|
||||
return packed; /* Returning packed, the module is loaded so it must exists
|
||||
on disk */
|
||||
}
|
||||
|
||||
hMapFile = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, "exeScanner");
|
||||
if (!hMapFile) {
|
||||
elogg(LOGG_INFO, "exeScanner: CreateFileMappingA() failed %lu\n", GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
lpMapAddress = (LPBYTE)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
|
||||
if (!lpMapAddress) {
|
||||
elogg(LOGG_INFO, "exeScanner: MapViewOfFile() failed %lu\n", GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
seek = lpMapAddress;
|
||||
|
||||
/* DOS Signature 'MZ' */
|
||||
FILLBYTES(e_mz);
|
||||
if (e_mz != IMAGE_DOS_SIGNATURE) {
|
||||
elogg(LOGG_INFO, "exeScanner: DOS Signature not found\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
seek += 0x3c;
|
||||
|
||||
FILLBYTES(e_lfanew);
|
||||
if (!e_lfanew) {
|
||||
elogg(LOGG_INFO, "exeScanner: Invalid PE offset\n");
|
||||
goto cleanup;
|
||||
}
|
||||
seek = lpMapAddress + e_lfanew;
|
||||
|
||||
/* PE Signature 'PE' */
|
||||
FILLBYTES(e_magic);
|
||||
if (e_magic != IMAGE_NT_SIGNATURE) {
|
||||
elogg(LOGG_INFO, "exeScanner: PE Signature not found\n");
|
||||
goto cleanup;
|
||||
}
|
||||
seek += sizeof(e_magic);
|
||||
|
||||
if (IsBadReadPtr(seek, sizeof(IMAGE_FILE_HEADER)))
|
||||
goto cleanup;
|
||||
pehdr = (PIMAGE_FILE_HEADER)seek;
|
||||
seek += sizeof(IMAGE_FILE_HEADER);
|
||||
|
||||
if (IsBadReadPtr(seek, sizeof(IMAGE_OPTIONAL_HEADER32)))
|
||||
goto cleanup;
|
||||
opthdr = (PIMAGE_OPTIONAL_HEADER32)seek;
|
||||
seek += sizeof(IMAGE_OPTIONAL_HEADER32);
|
||||
|
||||
if (pehdr->Machine != IMAGE_FILE_MACHINE_I386) {
|
||||
elogg(LOGG_INFO, "exeScanner: Not an x86 executable\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Invalid sections number */
|
||||
if ((pehdr->NumberOfSections < 1) || (pehdr->NumberOfSections > 32)) {
|
||||
elogg(LOGG_INFO, "exeScanner: Invalid sections number\n");
|
||||
packed = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < pehdr->NumberOfSections; i++) {
|
||||
double section_entropy = .0f;
|
||||
if (IsBadReadPtr(seek, sizeof(IMAGE_SECTION_HEADER)))
|
||||
goto cleanup;
|
||||
sechdr = (PIMAGE_SECTION_HEADER)seek;
|
||||
seek += sizeof(IMAGE_SECTION_HEADER);
|
||||
|
||||
if (opthdr->AddressOfEntryPoint >= sechdr->VirtualAddress)
|
||||
epoff = opthdr->AddressOfEntryPoint - sechdr->VirtualAddress +
|
||||
sechdr->PointerToRawData;
|
||||
|
||||
s_start = lpMapAddress + sechdr->PointerToRawData;
|
||||
if (!IsBadReadPtr(s_start, sechdr->SizeOfRawData))
|
||||
section_entropy = calc_entropy(s_start, sechdr->SizeOfRawData);
|
||||
|
||||
entropy = MAX(entropy, section_entropy);
|
||||
|
||||
/* Sanitize the section name */
|
||||
memcpy(secname, sechdr->Name, IMAGE_SIZEOF_SHORT_NAME);
|
||||
for (c = 0; (c < IMAGE_SIZEOF_SHORT_NAME) && secname[c]; c++)
|
||||
if (!isprint(secname[c]))
|
||||
secname[c] = '?';
|
||||
secname[IMAGE_SIZEOF_SHORT_NAME - 1] = 0;
|
||||
|
||||
elogg(LOGG_INFO, "exeScanner: Section name: [%s] - Entropy %f\n", secname,
|
||||
section_entropy);
|
||||
|
||||
if (!sechdr->SizeOfRawData)
|
||||
badsection = 1;
|
||||
}
|
||||
|
||||
elogg(LOGG_INFO, "exeScanner: Max entropy = %f\n", entropy);
|
||||
/* EP Check */
|
||||
elogg(LOGG_INFO, "exeScanner: Entry Point rva: 0x%lx - raw: 0x%lx\n",
|
||||
opthdr->AddressOfEntryPoint, epoff);
|
||||
|
||||
ep = lpMapAddress + epoff;
|
||||
if (!IsBadReadPtr(ep, EP_SIGNATURE_SIZE)) {
|
||||
#ifdef DUMP_SIGNATURE
|
||||
int i;
|
||||
for (i = 0; i < EP_SIGNATURE_SIZE; i++)
|
||||
elogg(LOGG_INFO, "%02x ", ep[i]);
|
||||
elogg(LOGG_INFO, "\n[C Code]: ");
|
||||
for (i = 0; i < EP_SIGNATURE_SIZE - 1; i++)
|
||||
elogg(LOGG_INFO, "0x%02x, ", ep[i]);
|
||||
elogg(LOGG_INFO, "0x%02x\n", ep[i]);
|
||||
#endif
|
||||
if ((sig = checksig(ep))) {
|
||||
elogg(LOGG_INFO, "exeScanner: Signature check: %s\n", sig->name);
|
||||
entropy += sig->score;
|
||||
packed = (sig->score >= .0f);
|
||||
if (sig->score < .0f)
|
||||
elogg(
|
||||
"exeScanner: Whitelisted signature found, lowering entropy to %f\n",
|
||||
entropy);
|
||||
} else
|
||||
elogg(LOGG_INFO, "exeScanner: Signature check: Nothing found\n");
|
||||
} else
|
||||
elogg(LOGG_INFO, "exeScanner: Invalid address of Entry Point\n");
|
||||
|
||||
if (badsection) {
|
||||
if ((entropy == .0f) || (entropy > ENTROPY_THRESHOLD)) {
|
||||
elogg(LOGG_INFO, "exeScanner: found zero SizeOfRawData and entropy %f\n", entropy);
|
||||
packed = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (lpMapAddress)
|
||||
UnmapViewOfFile(lpMapAddress);
|
||||
if (hMapFile)
|
||||
CloseHandle(hMapFile);
|
||||
CloseHandle(hFile);
|
||||
return packed;
|
||||
}
|
||||
72
clamav/common/exeScanner.h
Normal file
72
clamav/common/exeScanner.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2006-2008 Gianluigi Tiesi <sherpya@netfarm.it>
|
||||
*
|
||||
* Authors: Gianluigi Tiesi
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _EXESCANNER_H_
|
||||
#define _EXESCANNER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#ifdef EXESCANNER_STANDALONE
|
||||
#define DUMP_SIGNATURE
|
||||
#include <windows.h>
|
||||
#define logg printf
|
||||
#define elogg printf
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int16 int16_t;
|
||||
#else
|
||||
#include "output.h"
|
||||
#include <others.h>
|
||||
static inline void elogg(const char *fmt, ...){};
|
||||
#endif /* EXESCANNER_STANDALONE */
|
||||
|
||||
#define ENTROPY_THRESHOLD 4.0
|
||||
#define EP_SIGNATURE_SIZE 16
|
||||
|
||||
#ifndef IMAGE_DOS_SIGNATURE
|
||||
#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
typedef struct _sigs_t {
|
||||
int16_t sig[16];
|
||||
const char *name;
|
||||
double score;
|
||||
} sigs_t;
|
||||
|
||||
extern int is_packed(const char *filename);
|
||||
|
||||
static const char screv[] =
|
||||
{
|
||||
0x65, 0x78, 0x65, 0x53, 0x63, 0x61, 0x6e, 0x6e,
|
||||
0x65, 0x72, 0x7c, 0x47, 0x50, 0x4c, 0x7c, 0x47,
|
||||
0x69, 0x61, 0x6e, 0x6c, 0x75, 0x69, 0x67, 0x69,
|
||||
0x20, 0x54, 0x69, 0x65, 0x73, 0x69, 0x7c, 0x3c,
|
||||
0x73, 0x68, 0x65, 0x72, 0x70, 0x79, 0x61, 0x40,
|
||||
0x6e, 0x65, 0x74, 0x66, 0x61, 0x72, 0x6d, 0x2e,
|
||||
0x69, 0x74, 0x3e};
|
||||
|
||||
#endif /* _EXESCANNER_H_ */
|
||||
52
clamav/common/fdpassing.h
Normal file
52
clamav/common/fdpassing.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2009-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: Török Edvin
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef FDPASSING_H
|
||||
#define FDPASSING_H
|
||||
|
||||
#ifdef HAVE_FD_PASSING
|
||||
|
||||
#ifdef FDPASS_NEED_XOPEN
|
||||
/* to expose BSD 4.4/Unix98 semantics instead of BSD 4.3 semantics */
|
||||
#define _XOPEN_SOURCE 500
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
/* Solaris 8 */
|
||||
#if !defined CMSG_SPACE || !defined CMSG_LEN
|
||||
#ifndef ALIGN
|
||||
#define ALIGN(len) len
|
||||
#endif
|
||||
|
||||
#ifndef CMSG_SPACE
|
||||
#define CMSG_SPACE(len) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(len))
|
||||
#endif
|
||||
|
||||
#ifndef CMSG_LEN
|
||||
#define CMSG_LEN(len) (ALIGN(sizeof(struct cmsghdr)) + len)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
302
clamav/common/getopt.c
Normal file
302
clamav/common/getopt.c
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* getopt.c - my re-implementation of getopt.
|
||||
* Copyright 1997, 2000, 2001, 2002, 2006, Benjamin Sittler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "clamav-config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "getopt.h"
|
||||
|
||||
int optind = 1, opterr = 1, optopt = 0;
|
||||
char *optarg = 0;
|
||||
|
||||
/* reset argument parser to start-up values */
|
||||
/*
|
||||
int getopt_reset(void)
|
||||
{
|
||||
optind = 1;
|
||||
opterr = 1;
|
||||
optopt = 0;
|
||||
optarg = 0;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
/* this is the plain old UNIX getopt, with GNU-style extensions. */
|
||||
/* if you're porting some piece of UNIX software, this is all you need. */
|
||||
/* this supports GNU-style permution and optional arguments */
|
||||
|
||||
int my_getopt(int argc, char *argvc[], const char *opts)
|
||||
{
|
||||
char **argv = (char **)argvc;
|
||||
static int charind = 0;
|
||||
const char *s;
|
||||
char mode, colon_mode;
|
||||
int off = 0, opt = -1;
|
||||
|
||||
if (getenv("POSIXLY_CORRECT"))
|
||||
colon_mode = mode = '+';
|
||||
else {
|
||||
if ((colon_mode = *opts) == ':') off++;
|
||||
if (((mode = opts[off]) == '+') || (mode == '-')) {
|
||||
off++;
|
||||
if ((colon_mode != ':') && ((colon_mode = opts[off]) == ':'))
|
||||
off++;
|
||||
}
|
||||
}
|
||||
optarg = 0;
|
||||
if (charind) {
|
||||
optopt = argv[optind][charind];
|
||||
for (s = opts + off; *s; s++)
|
||||
if (optopt == *s) {
|
||||
charind++;
|
||||
if ((*(++s) == ':') || ((optopt == 'W') && (*s == ';'))) {
|
||||
if (argv[optind][charind]) {
|
||||
optarg = &(argv[optind++][charind]);
|
||||
charind = 0;
|
||||
} else if (*(++s) != ':') {
|
||||
charind = 0;
|
||||
if (++optind >= argc) {
|
||||
if (opterr) fprintf(stderr,
|
||||
"%s: option requires an argument -- %c\n",
|
||||
argv[0], optopt);
|
||||
opt = (colon_mode == ':') ? ':' : '?';
|
||||
goto getopt_ok;
|
||||
}
|
||||
optarg = argv[optind++];
|
||||
}
|
||||
}
|
||||
opt = optopt;
|
||||
goto getopt_ok;
|
||||
}
|
||||
if (opterr) fprintf(stderr,
|
||||
"%s: illegal option -- %c\n",
|
||||
argv[0], optopt);
|
||||
opt = '?';
|
||||
if (argv[optind][++charind] == '\0') {
|
||||
optind++;
|
||||
charind = 0;
|
||||
}
|
||||
getopt_ok:
|
||||
if (charind && !argv[optind][charind]) {
|
||||
optind++;
|
||||
charind = 0;
|
||||
}
|
||||
} else if ((optind >= argc) ||
|
||||
((argv[optind][0] == '-') &&
|
||||
(argv[optind][1] == '-') &&
|
||||
(argv[optind][2] == '\0'))) {
|
||||
optind++;
|
||||
opt = -1;
|
||||
} else if ((argv[optind][0] != '-') ||
|
||||
(argv[optind][1] == '\0')) {
|
||||
char *tmp;
|
||||
int i, j, k;
|
||||
|
||||
if (mode == '+')
|
||||
opt = -1;
|
||||
else if (mode == '-') {
|
||||
optarg = argv[optind++];
|
||||
charind = 0;
|
||||
opt = 1;
|
||||
} else {
|
||||
for (i = j = optind; i < argc; i++)
|
||||
if ((argv[i][0] == '-') &&
|
||||
(argv[i][1] != '\0')) {
|
||||
optind = i;
|
||||
opt = my_getopt(argc, argv, opts);
|
||||
while (i > j) {
|
||||
tmp = argv[--i];
|
||||
for (k = i; k + 1 < optind; k++) argv[k] = argv[k + 1];
|
||||
argv[--optind] = tmp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (i == argc) opt = -1;
|
||||
}
|
||||
} else {
|
||||
charind++;
|
||||
opt = my_getopt(argc, argv, opts);
|
||||
}
|
||||
if (optind > argc) optind = argc;
|
||||
return opt;
|
||||
}
|
||||
|
||||
/* this is the extended getopt_long{,_only}, with some GNU-like
|
||||
* extensions. Implements _getopt_internal in case any programs
|
||||
* expecting GNU libc getopt call it.
|
||||
*/
|
||||
|
||||
static int _getopt_internal(int argc, char *argv[], const char *shortopts,
|
||||
const struct option *longopts, int *longind,
|
||||
int long_only)
|
||||
{
|
||||
char mode, colon_mode;
|
||||
int shortoff = 0, opt = -1;
|
||||
|
||||
if (getenv("POSIXLY_CORRECT")) {
|
||||
colon_mode = mode = '+';
|
||||
} else {
|
||||
if ((colon_mode = *shortopts) == ':') shortoff++;
|
||||
if (((mode = shortopts[shortoff]) == '+') || (mode == '-')) {
|
||||
shortoff++;
|
||||
if ((colon_mode != ':') && ((colon_mode = shortopts[shortoff]) == ':'))
|
||||
shortoff++;
|
||||
}
|
||||
}
|
||||
optarg = 0;
|
||||
if ((optind >= argc) ||
|
||||
((argv[optind][0] == '-') &&
|
||||
(argv[optind][1] == '-') &&
|
||||
(argv[optind][2] == '\0'))) {
|
||||
optind++;
|
||||
opt = -1;
|
||||
} else if ((argv[optind][0] != '-') ||
|
||||
(argv[optind][1] == '\0')) {
|
||||
char *tmp;
|
||||
int i, j, k;
|
||||
|
||||
opt = -1;
|
||||
if (mode == '+')
|
||||
return -1;
|
||||
else if (mode == '-') {
|
||||
optarg = argv[optind++];
|
||||
return 1;
|
||||
}
|
||||
for (i = j = optind; i < argc; i++)
|
||||
if ((argv[i][0] == '-') &&
|
||||
(argv[i][1] != '\0')) {
|
||||
optind = i;
|
||||
|
||||
opt = _getopt_internal(argc, argv, shortopts,
|
||||
longopts, longind,
|
||||
long_only);
|
||||
while (i > j) {
|
||||
tmp = argv[--i];
|
||||
for (k = i; k + 1 < optind; k++)
|
||||
argv[k] = argv[k + 1];
|
||||
argv[--optind] = tmp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if ((!long_only) && (argv[optind][1] != '-'))
|
||||
opt = my_getopt(argc, argv, shortopts);
|
||||
else {
|
||||
int charind, offset;
|
||||
int found = 0, ind, hits = 0;
|
||||
|
||||
if (((optopt = argv[optind][1]) != '-') && !argv[optind][2]) {
|
||||
int c;
|
||||
|
||||
ind = shortoff;
|
||||
while ((c = shortopts[ind++])) {
|
||||
if (((shortopts[ind] == ':') ||
|
||||
((c == 'W') && (shortopts[ind] == ';'))) &&
|
||||
(shortopts[++ind] == ':'))
|
||||
ind++;
|
||||
if (optopt == c) return my_getopt(argc, argv, shortopts);
|
||||
}
|
||||
}
|
||||
offset = 2 - (argv[optind][1] != '-');
|
||||
for (charind = offset;
|
||||
(argv[optind][charind] != '\0') &&
|
||||
(argv[optind][charind] != '=');
|
||||
charind++)
|
||||
;
|
||||
for (ind = 0; longopts[ind].name && !hits; ind++)
|
||||
if ((strlen(longopts[ind].name) == (size_t)(charind - offset)) &&
|
||||
(strncmp(longopts[ind].name,
|
||||
argv[optind] + offset, charind - offset) == 0))
|
||||
found = ind, hits++;
|
||||
if (!hits)
|
||||
for (ind = 0; longopts[ind].name; ind++)
|
||||
if (strncmp(longopts[ind].name,
|
||||
argv[optind] + offset, charind - offset) == 0)
|
||||
found = ind, hits++;
|
||||
if (hits == 1) {
|
||||
opt = 0;
|
||||
|
||||
if (argv[optind][charind] == '=') {
|
||||
if (longopts[found].has_arg == 0) {
|
||||
opt = '?';
|
||||
if (opterr) fprintf(stderr,
|
||||
"%s: option `--%s' doesn't allow an argument\n",
|
||||
argv[0], longopts[found].name);
|
||||
} else {
|
||||
optarg = argv[optind] + ++charind;
|
||||
// charind = 0; // Never used again past here
|
||||
}
|
||||
} else if (longopts[found].has_arg == 1) {
|
||||
if (++optind >= argc) {
|
||||
opt = (colon_mode == ':') ? ':' : '?';
|
||||
if (opterr) fprintf(stderr,
|
||||
"%s: option `--%s' requires an argument\n",
|
||||
argv[0], longopts[found].name);
|
||||
} else
|
||||
optarg = argv[optind];
|
||||
}
|
||||
if (!opt) {
|
||||
if (longind) *longind = found;
|
||||
if (!longopts[found].flag)
|
||||
opt = longopts[found].val;
|
||||
else
|
||||
*(longopts[found].flag) = longopts[found].val;
|
||||
}
|
||||
optind++;
|
||||
} else if (!hits) {
|
||||
if (offset == 1)
|
||||
opt = my_getopt(argc, argv, shortopts);
|
||||
else {
|
||||
opt = '?';
|
||||
if (opterr) fprintf(stderr,
|
||||
"%s: unrecognized option `%s'\n",
|
||||
argv[0], argv[optind++]);
|
||||
}
|
||||
} else {
|
||||
opt = '?';
|
||||
if (opterr) fprintf(stderr,
|
||||
"%s: option `%s' is ambiguous\n",
|
||||
argv[0], argv[optind++]);
|
||||
}
|
||||
}
|
||||
if (optind > argc) optind = argc;
|
||||
return opt;
|
||||
}
|
||||
|
||||
int my_getopt_long(int argc, char *argv[], const char *shortopts,
|
||||
const struct option *longopts, int *longind)
|
||||
{
|
||||
return _getopt_internal(argc, argv, shortopts, longopts, longind, 0);
|
||||
}
|
||||
|
||||
int my_getopt_long_only(int argc, char *argv[], const char *shortopts,
|
||||
const struct option *longopts, int *longind)
|
||||
{
|
||||
return _getopt_internal(argc, argv, shortopts, longopts, longind, 1);
|
||||
}
|
||||
65
clamav/common/getopt.h
Normal file
65
clamav/common/getopt.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* getopt.h - interface to my re-implementation of getopt.
|
||||
* Copyright 1997, 2000, 2001, 2002, 2006, Benjamin Sittler
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy,
|
||||
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _GETOPT_H_INCLUDED
|
||||
#define _GETOPT_H_INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* UNIX-style short-argument parser */
|
||||
extern int my_getopt(int argc, char *argv[], const char *opts);
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
extern char *optarg;
|
||||
|
||||
struct option {
|
||||
const char *name;
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* human-readable values for has_arg */
|
||||
#undef no_argument
|
||||
#define no_argument 0
|
||||
#undef required_argument
|
||||
#define required_argument 1
|
||||
#undef optional_argument
|
||||
#define optional_argument 2
|
||||
|
||||
/* GNU-style long-argument parsers */
|
||||
extern int my_getopt_long(int argc, char *argv[], const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
|
||||
extern int my_getopt_long_only(int argc, char *argv[], const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _GETOPT_H_INCLUDED */
|
||||
64
clamav/common/hostid.c
Normal file
64
clamav/common/hostid.c
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2022 Cisco and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Author: Shawn Webb
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// libclamav
|
||||
#include "others.h"
|
||||
|
||||
#include "output.h"
|
||||
|
||||
char hostid[37];
|
||||
|
||||
int is_valid_hostid(void)
|
||||
{
|
||||
int count, i;
|
||||
|
||||
if (strlen(hostid) != 36)
|
||||
return 0;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < 36; i++)
|
||||
if (hostid[i] == '-')
|
||||
count++;
|
||||
|
||||
if (count != 4)
|
||||
return 0;
|
||||
|
||||
if (hostid[8] != '-' || hostid[13] != '-' || hostid[18] != '-' || hostid[23] != '-')
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *get_hostid(void *cbdata)
|
||||
{
|
||||
UNUSEDPARAM(cbdata);
|
||||
|
||||
if (!strcmp(hostid, "none"))
|
||||
return NULL;
|
||||
|
||||
if (!is_valid_hostid())
|
||||
return strdup(STATS_ANON_UUID);
|
||||
|
||||
logg(LOGG_INFO, "HostID is valid: %s\n", hostid);
|
||||
|
||||
return strdup(hostid);
|
||||
}
|
||||
41
clamav/common/hostid.h
Normal file
41
clamav/common/hostid.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2022 Cisco and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Author: Shawn Webb
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LIBFRESHCLAM_H
|
||||
#define __LIBFRESHCLAM_H
|
||||
|
||||
extern char hostid[37];
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int is_valid_hostid(void);
|
||||
|
||||
/**
|
||||
* @brief Get the hostid object
|
||||
*
|
||||
* @param cbdata
|
||||
* @return char*
|
||||
*/
|
||||
char *get_hostid(void *cbdata);
|
||||
|
||||
#endif //__LIBFRESHCLAM_H
|
||||
258
clamav/common/idmef_logging.c
Normal file
258
clamav/common/idmef_logging.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: Selim Menouar, Verene Houdebine
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "clamav.h"
|
||||
#include "misc.h"
|
||||
#include "output.h"
|
||||
|
||||
#ifndef PRELUDE
|
||||
void prelude_logging(const char *filename, const char *virname, const char *virhash, int virsize)
|
||||
{
|
||||
UNUSEDPARAM(filename);
|
||||
UNUSEDPARAM(virname);
|
||||
UNUSEDPARAM(virhash);
|
||||
UNUSEDPARAM(virsize);
|
||||
|
||||
logg(LOGG_INFO, "You have to compile with libprelude using ./configure --enable-prelude\n");
|
||||
}
|
||||
#else
|
||||
|
||||
#include <libprelude/prelude.h>
|
||||
|
||||
#define ANALYZER_MODEL "ClamAV"
|
||||
#define ANALYZER_CLASS "AntiVirus"
|
||||
#define ANALYZER_MANUFACTURER "http://www.sourcefire.com"
|
||||
|
||||
static prelude_client_t *prelude_client;
|
||||
|
||||
int idmef_analyzer_setup(idmef_analyzer_t *analyzer, const char *analyzer_name)
|
||||
{
|
||||
int ret;
|
||||
prelude_string_t *str;
|
||||
|
||||
/* alert->analyzer->name */
|
||||
ret = idmef_analyzer_new_name(analyzer, &str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
prelude_string_set_constant(str, analyzer_name);
|
||||
|
||||
/* alert->analyzer->model */
|
||||
ret = idmef_analyzer_new_model(analyzer, &str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
prelude_string_set_constant(str, ANALYZER_MODEL);
|
||||
|
||||
/* alert->analyzer->class */
|
||||
ret = idmef_analyzer_new_class(analyzer, &str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
prelude_string_set_constant(str, ANALYZER_CLASS);
|
||||
|
||||
/* alert->analyzer->manufacturer */
|
||||
ret = idmef_analyzer_new_manufacturer(analyzer, &str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
prelude_string_set_constant(str, ANALYZER_MANUFACTURER);
|
||||
|
||||
/* alert->analyzer->version */
|
||||
ret = idmef_analyzer_new_version(analyzer, &str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
prelude_string_set_constant(str, get_version());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prelude_initialize_client(const char *analyzer_name)
|
||||
{
|
||||
int ret;
|
||||
|
||||
prelude_client = NULL;
|
||||
|
||||
ret = prelude_init(0, NULL);
|
||||
if (ret < 0) {
|
||||
logg(LOGG_INFO, "Unable to initialize the prelude library : %s", prelude_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = prelude_client_new(&prelude_client, analyzer_name);
|
||||
if (ret < 0) {
|
||||
logg(LOGG_INFO, "Unable to create a prelude client object : %s", prelude_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = idmef_analyzer_setup(prelude_client_get_analyzer(prelude_client), analyzer_name);
|
||||
if (ret < 0) {
|
||||
logg(LOGG_INFO, "%s", prelude_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = prelude_client_start(prelude_client);
|
||||
if (ret < 0 || !prelude_client) {
|
||||
logg(LOGG_INFO, "Unable to start prelude client : %s", prelude_strerror(ret));
|
||||
prelude_client_destroy(prelude_client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = prelude_client_set_flags(prelude_client, PRELUDE_CLIENT_FLAGS_ASYNC_SEND | PRELUDE_CLIENT_FLAGS_ASYNC_TIMER);
|
||||
if (ret < 0) {
|
||||
logg(LOGG_INFO, "Unable to send asynchronous send and timer : %s", prelude_strerror(ret));
|
||||
prelude_client_destroy(prelude_client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_string_additional_data(idmef_alert_t *alert, const char *meaning, const char *ptr)
|
||||
{
|
||||
int ret;
|
||||
prelude_string_t *str;
|
||||
idmef_additional_data_t *ad;
|
||||
idmef_data_t *data;
|
||||
|
||||
ret = idmef_alert_new_additional_data(alert, &ad, IDMEF_LIST_APPEND);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
idmef_additional_data_set_type(ad, IDMEF_ADDITIONAL_DATA_TYPE_STRING);
|
||||
|
||||
idmef_additional_data_new_data(ad, &data);
|
||||
|
||||
ret = idmef_data_set_char_string_ref(data, ptr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = idmef_additional_data_new_meaning(ad, &str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = prelude_string_set_ref(str, meaning);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_int_additional_data(idmef_alert_t *alert, const char *meaning, int data)
|
||||
{
|
||||
int ret;
|
||||
prelude_string_t *str;
|
||||
idmef_additional_data_t *ad;
|
||||
|
||||
ret = idmef_alert_new_additional_data(alert, &ad, IDMEF_LIST_APPEND);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
idmef_additional_data_set_integer(ad, data);
|
||||
|
||||
ret = idmef_additional_data_new_meaning(ad, &str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = prelude_string_set_ref(str, meaning);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void prelude_logging(const char *filename, const char *virname, const char *virhash, int virsize)
|
||||
{
|
||||
int ret;
|
||||
idmef_message_t *idmef = NULL;
|
||||
idmef_alert_t *alert;
|
||||
idmef_classification_t *class;
|
||||
prelude_string_t *str;
|
||||
idmef_target_t *target;
|
||||
idmef_file_t *file;
|
||||
|
||||
ret = idmef_message_new(&idmef);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = idmef_message_new_alert(idmef, &alert);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = idmef_alert_new_classification(alert, &class);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = idmef_classification_new_text(class, &str);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
prelude_string_set_constant(str, "Virus Found");
|
||||
|
||||
ret = idmef_alert_new_target(alert, &target, 0);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = idmef_target_new_file(target, &file, 0);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = idmef_file_new_path(file, &str);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
prelude_string_set_ref(str, filename);
|
||||
|
||||
if (virname != NULL) {
|
||||
ret = add_string_additional_data(alert, "virname", virname);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (virhash != NULL) {
|
||||
ret = add_string_additional_data(alert, "virhash", virhash);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = add_int_additional_data(alert, "virsize", virsize);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
logg(LOGG_INFO, "le client : %s", prelude_client_get_config_filename(prelude_client));
|
||||
prelude_client_send_idmef(prelude_client, idmef);
|
||||
idmef_message_destroy(idmef);
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
if (idmef != NULL)
|
||||
idmef_message_destroy(idmef);
|
||||
|
||||
logg(LOGG_INFO, "%s error: %s", prelude_strsource(ret), prelude_strerror(ret));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
29
clamav/common/idmef_logging.h
Normal file
29
clamav/common/idmef_logging.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: Selim Menouar, Verene Houdebine
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __IDMEF_LOGGING_H_
|
||||
#define __IDMEF_LOGGING_H_
|
||||
#endif
|
||||
|
||||
#ifdef PRELUDE
|
||||
int prelude_initialize_client(const char *analyzer_name);
|
||||
#endif
|
||||
|
||||
void prelude_logging(const char *filename, const char *virname, const char *virhash, int virsize);
|
||||
102
clamav/common/linux/cert_util_linux.c
Normal file
102
clamav/common/linux/cert_util_linux.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* OpenSSL certificate verification for Linux.
|
||||
*
|
||||
* Copyright (C) 2016-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Authors: Russ Kubik
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "output.h"
|
||||
#include "cert_util.h"
|
||||
#include "cert_util_internal.h"
|
||||
|
||||
void set_tls_ca_bundle(CURL *curl)
|
||||
{
|
||||
char *ca_bundle;
|
||||
|
||||
ca_bundle = getenv("CURL_CA_BUNDLE");
|
||||
if (ca_bundle == NULL)
|
||||
return;
|
||||
|
||||
if (curl_easy_setopt(curl, CURLOPT_CAINFO, ca_bundle) != CURLE_OK) {
|
||||
fprintf(stderr, "Failed to set CURLOPT_CAINFO!\n");
|
||||
}
|
||||
}
|
||||
|
||||
cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
|
||||
{
|
||||
cl_error_t ret = CL_EOPEN;
|
||||
cert_store_t *store = NULL;
|
||||
int pt_err;
|
||||
|
||||
do {
|
||||
store = cert_store_get_int();
|
||||
if (!store) {
|
||||
mprintf(LOGG_ERROR, "Failed to retrieve cert store\n");
|
||||
break;
|
||||
}
|
||||
|
||||
pt_err = pthread_mutex_lock(&store->mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex lock failed\n");
|
||||
}
|
||||
|
||||
if (store->loaded) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* System certs do not need to be added as they can be accessed directly
|
||||
* by the SSL library. */
|
||||
store->system_certs.count = 0;
|
||||
store->system_certs.certificates = NULL;
|
||||
|
||||
if (trusted_certs && trusted_cert_count > 0) {
|
||||
if (cert_store_set_trusted_int(trusted_certs, trusted_cert_count) == 0) {
|
||||
mprintf(LOGG_DEBUG, "Trusted certificates loaded: %zu\n",
|
||||
store->trusted_certs.count);
|
||||
} else {
|
||||
mprintf(LOGG_WARNING, "Continuing without trusted certificates\n");
|
||||
/* proceed as if we succeeded using only certificates from the
|
||||
* system */
|
||||
}
|
||||
}
|
||||
|
||||
store->loaded = true;
|
||||
ret = 0;
|
||||
} while (0);
|
||||
|
||||
if (store) {
|
||||
pt_err = pthread_mutex_unlock(&store->mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
402
clamav/common/mac/cert_util_mac.m
Normal file
402
clamav/common/mac/cert_util_mac.m
Normal file
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* OpenSSL certificate verification for macOS.
|
||||
*
|
||||
* Copyright (C) 2016-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Authors: Russ Kubik
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
#import <Security/SecRequirement.h>
|
||||
#import <Security/SecBase.h>
|
||||
#import <Security/SecCode.h>
|
||||
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
#include <Security/Security.h>
|
||||
|
||||
#include <sys/syslimits.h>
|
||||
#import <sys/proc_info.h>
|
||||
#import <libproc.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <libgen.h>
|
||||
#include <mach-o/dyld.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "output.h"
|
||||
|
||||
#include "cert_util.h"
|
||||
#include "cert_util_internal.h"
|
||||
|
||||
/* Macro to obtain the number of elements in a fixed sized array that was either
|
||||
* statically declared or declared on the stack in the same scope. The macro
|
||||
* will generate a divide-by-zero compiler warning if the input is a pointer.
|
||||
*
|
||||
* See also:
|
||||
* http://stackoverflow.com/questions/8018843/macro-definition-array-size
|
||||
*/
|
||||
#define ARRAY_SIZE(a) ((sizeof(a) / sizeof(*(a))) / ((size_t)(!(sizeof(a) % sizeof(*(a))))))
|
||||
|
||||
/* Keychain types available on macOS. User specific keychains are omitted for
|
||||
* simplicity. */
|
||||
typedef enum keychain_type {
|
||||
KEYCHAIN_TYPE_SYSTEM_ROOT,
|
||||
KEYCHAIN_TYPE_SYSTEM
|
||||
} keychain_type_t;
|
||||
|
||||
/* Basic information about a keychain */
|
||||
typedef struct keychain_info {
|
||||
const char *name;
|
||||
const char *file_path;
|
||||
} keychain_info_t;
|
||||
|
||||
/* Table to support name and file path lookup for each keychain type */
|
||||
static const keychain_info_t _KEYCHAIN_INFO[] =
|
||||
{
|
||||
{.name = "system root",
|
||||
.file_path = "/System/Library/Keychains/SystemRootCertificates.keychain"},
|
||||
{.name = "system",
|
||||
.file_path = "/Library/Keychains/System.keychain"}};
|
||||
|
||||
/*!
|
||||
* @brief Get basic information about the specified keychain.
|
||||
* @param[in] keychain_type Keychain type
|
||||
* @return The keychain information. All pointers contained in this
|
||||
* point to read only data and so do not need to be freed.
|
||||
*/
|
||||
static keychain_info_t _get_keychain_info(keychain_type_t keychain_type)
|
||||
{
|
||||
return _KEYCHAIN_INFO[keychain_type];
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get a reference to an allocated array of certifcates contained
|
||||
* in the specified keychain.
|
||||
* @param[in] keychain_type Keychain type
|
||||
* @return If successful, reference to allocated array of certifcates. The
|
||||
* caller is responsible for calling CFRelease on the returned
|
||||
* reference after use.
|
||||
* @return NULL otherwise
|
||||
*/
|
||||
static CFTypeRef _get_cert_ref(keychain_type_t keychain_type)
|
||||
{
|
||||
keychain_info_t kc_info = _get_keychain_info(keychain_type);
|
||||
|
||||
CFTypeRef keys[] = {
|
||||
kSecMatchSearchList,
|
||||
kSecClass,
|
||||
kSecReturnRef,
|
||||
kSecMatchLimit,
|
||||
kSecMatchTrustedOnly,
|
||||
kSecMatchValidOnDate,
|
||||
};
|
||||
CFTypeRef values[] = {
|
||||
/* NOTE: must match the order specified above */
|
||||
kCFNull, /* place holder for match search list */
|
||||
kSecClassCertificate, /* kSecClass */
|
||||
kCFBooleanTrue, /* kSecReturnRef */
|
||||
kSecMatchLimitAll, /* kSecMatchLimit */
|
||||
kCFBooleanTrue, /* kSecMatchTrustedOnly */
|
||||
kCFNull, /* kSecMatchValidOnDate */
|
||||
};
|
||||
|
||||
CFDictionaryRef query = NULL;
|
||||
CFTypeRef items = NULL;
|
||||
|
||||
SecKeychainRef keychain = NULL;
|
||||
CFArrayRef search_list = NULL;
|
||||
|
||||
SecKeychainStatus keychainStatus = 0;
|
||||
|
||||
OSStatus status;
|
||||
|
||||
status = SecKeychainOpen(kc_info.file_path, &keychain);
|
||||
|
||||
if (status != errSecSuccess) {
|
||||
mprintf(LOGG_ERROR, "Failed to open %s keychain: %s (%d)\n",
|
||||
kc_info.name,
|
||||
kc_info.file_path,
|
||||
status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = SecKeychainGetStatus(keychain, &keychainStatus);
|
||||
if (status != errSecSuccess) {
|
||||
mprintf(LOGG_ERROR, "Failed to get the status of the %s keychain: %d\n",
|
||||
kc_info.name,
|
||||
status);
|
||||
goto done;
|
||||
}
|
||||
if (!(keychainStatus & kSecReadPermStatus)) {
|
||||
mprintf(LOGG_ERROR, "The %s keychain is not readable: %" PRIu32 "\n",
|
||||
kc_info.name,
|
||||
keychainStatus);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (keychain_type == KEYCHAIN_TYPE_SYSTEM_ROOT) {
|
||||
/*
|
||||
* The SystemRootCertificates.keychain is a system keychain file that should be locked
|
||||
* and should definitely not have writable permissions. This may indicate that the file
|
||||
* has been tampered with.
|
||||
*/
|
||||
if (keychainStatus & (kSecUnlockStateStatus | kSecWritePermStatus)) {
|
||||
mprintf(LOGG_ERROR, "System Root Certificates Keychain has invalid permissions: %" PRIu32 "\n",
|
||||
keychainStatus);
|
||||
/* continue on error */
|
||||
}
|
||||
}
|
||||
|
||||
search_list = CFArrayCreate(kCFAllocatorDefault,
|
||||
(const void **)&keychain, 1, &kCFTypeArrayCallBacks);
|
||||
if (search_list == NULL) {
|
||||
mprintf(LOGG_ERROR, "Failed to create %s keychain search list\n",
|
||||
kc_info.name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* set the search list for the secItemCopyMatching call */
|
||||
values[0] = search_list;
|
||||
|
||||
query = CFDictionaryCreate(NULL, keys, values, ARRAY_SIZE(keys),
|
||||
&kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
if (query == NULL) {
|
||||
mprintf(LOGG_ERROR, "Failed to create %s keychain query dictionary\n",
|
||||
kc_info.name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = SecItemCopyMatching(query, &items);
|
||||
if (status != errSecSuccess) {
|
||||
if (status == errSecItemNotFound) {
|
||||
mprintf(LOGG_DEBUG, "No items found in %s keychain\n",
|
||||
kc_info.name);
|
||||
} else {
|
||||
mprintf(LOGG_ERROR, "Unable to copy certificates from %s keychain (%d)\n",
|
||||
kc_info.name,
|
||||
status);
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(query);
|
||||
query = NULL;
|
||||
done:
|
||||
if (keychain) {
|
||||
CFRelease(keychain);
|
||||
keychain = NULL;
|
||||
}
|
||||
if (search_list) {
|
||||
CFRelease(search_list);
|
||||
search_list = NULL;
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
|
||||
{
|
||||
static const keychain_type_t keychains[] = {
|
||||
KEYCHAIN_TYPE_SYSTEM_ROOT,
|
||||
KEYCHAIN_TYPE_SYSTEM};
|
||||
|
||||
typedef struct keychain_cert_data {
|
||||
CFArrayRef certs;
|
||||
CFIndex certs_count;
|
||||
} keychain_cert_data_t;
|
||||
|
||||
keychain_cert_data_t keychain_cert_data_array[ARRAY_SIZE(keychains)] = {
|
||||
{.certs = NULL,
|
||||
.certs_count = 0},
|
||||
/* All other array values initialized to 0 by default */
|
||||
};
|
||||
|
||||
size_t kc_index = 0;
|
||||
|
||||
cl_error_t ret = CL_EOPEN;
|
||||
int pt_err;
|
||||
|
||||
cert_store_t *store = NULL;
|
||||
CFIndex total_certificates = 0;
|
||||
CFIndex i = 0;
|
||||
bool locked = false;
|
||||
|
||||
store = cert_store_get_int();
|
||||
if (!store) {
|
||||
mprintf(LOGG_ERROR, "Failed to retrieve cert store\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Load certificates from keychains before entering the critical section.
|
||||
* On a default 10.12 installation loading the the system roots keychain
|
||||
* could take up to 300 ms to complete. */
|
||||
|
||||
for (kc_index = 0; kc_index < ARRAY_SIZE(keychains); kc_index++) {
|
||||
keychain_type_t kc = keychains[kc_index];
|
||||
keychain_info_t kc_info = _get_keychain_info(kc);
|
||||
keychain_cert_data_t *kc_data = &keychain_cert_data_array[kc_index];
|
||||
CFTypeRef items = NULL;
|
||||
|
||||
items = _get_cert_ref(kc);
|
||||
if (!items) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CFGetTypeID(items) != CFArrayGetTypeID()) {
|
||||
mprintf(LOGG_ERROR, "Expected array of certificates from %s keychain, "
|
||||
"got type %lu\n",
|
||||
kc_info.name,
|
||||
CFGetTypeID(items));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CFArrayGetCount(items) < 1) {
|
||||
CFRelease(items);
|
||||
items = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
kc_data->certs = (CFArrayRef)items;
|
||||
kc_data->certs_count = CFArrayGetCount(items);
|
||||
|
||||
mprintf(LOGG_DEBUG, "Found %ld certificates from %s keychain\n",
|
||||
kc_data->certs_count,
|
||||
kc_info.name);
|
||||
|
||||
total_certificates += kc_data->certs_count;
|
||||
}
|
||||
|
||||
if (total_certificates < 1) {
|
||||
mprintf(LOGG_ERROR, "No certificate found in keychains. Expect at least one "
|
||||
"certificate to be found in system root and system "
|
||||
"keychains\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
store = cert_store_get_int();
|
||||
if (!store) {
|
||||
mprintf(LOGG_ERROR, "Failed to retrieve cert store\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
pt_err = pthread_mutex_lock(&store->mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex lock failed\n");
|
||||
}
|
||||
locked = true;
|
||||
|
||||
if (store->loaded) {
|
||||
mprintf(LOGG_DEBUG, "Cert store already loaded\n");
|
||||
ret = CL_SUCCESS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
store->system_certs.count = 0;
|
||||
store->system_certs.certificates = calloc(total_certificates,
|
||||
sizeof(*store->system_certs.certificates));
|
||||
if (store->system_certs.certificates == NULL) {
|
||||
mprintf(LOGG_ERROR, "Failed to reserve memory for system cert list\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (kc_index = 0; kc_index < ARRAY_SIZE(keychains); kc_index++) {
|
||||
keychain_type_t kc = keychains[kc_index];
|
||||
keychain_info_t kc_info = _get_keychain_info(kc);
|
||||
keychain_cert_data_t *kc_data = &keychain_cert_data_array[kc_index];
|
||||
|
||||
for (i = 0; i < kc_data->certs_count; i++) {
|
||||
const void *value = CFArrayGetValueAtIndex(kc_data->certs, i);
|
||||
|
||||
if (CFGetTypeID(value) == SecCertificateGetTypeID()) {
|
||||
SecCertificateRef cert = (SecCertificateRef)value;
|
||||
CFDataRef cert_data = SecCertificateCopyData(cert); /* DER representation of X.509 */
|
||||
|
||||
if (cert_data) {
|
||||
const unsigned char *der = CFDataGetBytePtr(cert_data);
|
||||
CFIndex length = CFDataGetLength(cert_data);
|
||||
|
||||
char *name = NULL;
|
||||
X509 *x509 = d2i_X509(NULL, &der, length);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
x509_get_cert_name(x509, &name);
|
||||
#else
|
||||
name = x509->name;
|
||||
#endif
|
||||
|
||||
if (x509) {
|
||||
mprintf(LOGG_DEBUG, "Found %s trusted certificate %s\n",
|
||||
kc_info.name,
|
||||
(name ? name : "<no name>"));
|
||||
|
||||
store->system_certs.certificates[store->system_certs.count++] = x509;
|
||||
} else {
|
||||
mprintf(LOGG_ERROR, "Failed conversion of DER format to X.509\n");
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
if (NULL != name) {
|
||||
free(name);
|
||||
name = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
CFRelease(cert_data);
|
||||
cert_data = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trusted_certs && trusted_cert_count > 0) {
|
||||
if (cert_store_set_trusted_int(trusted_certs, trusted_cert_count) == 0) {
|
||||
mprintf(LOGG_DEBUG, "Trusted certificates loaded: %zu\n",
|
||||
store->trusted_certs.count);
|
||||
} else {
|
||||
mprintf(LOGG_WARNING, "Continuing without trusted certificates\n");
|
||||
/* proceed as if we succeeded using only certificates from the
|
||||
* system */
|
||||
}
|
||||
}
|
||||
|
||||
store->loaded = true;
|
||||
ret = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
if (locked) {
|
||||
pt_err = pthread_mutex_unlock(&store->mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
|
||||
}
|
||||
locked = false;
|
||||
}
|
||||
|
||||
for (kc_index = 0; kc_index < ARRAY_SIZE(keychains); kc_index++) {
|
||||
keychain_cert_data_t *kc_data = &keychain_cert_data_array[kc_index];
|
||||
|
||||
if (kc_data->certs) {
|
||||
CFRelease(kc_data->certs);
|
||||
kc_data->certs = NULL;
|
||||
kc_data->certs_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
489
clamav/common/misc.c
Normal file
489
clamav/common/misc.c
Normal file
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2007-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: Tomasz Kojm
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/socket.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
// libclamav
|
||||
#include "clamav.h"
|
||||
#include "cvd.h"
|
||||
#include "others.h" /* for cli_rmdirs() */
|
||||
#include "regex/regex.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "optparser.h"
|
||||
#include "output.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#ifndef REPO_VERSION
|
||||
#define REPO_VERSION "exported"
|
||||
#endif
|
||||
|
||||
const char *get_version(void)
|
||||
{
|
||||
if (!strncmp("devel-", VERSION, 6) && strcmp("exported", REPO_VERSION)) {
|
||||
return REPO_VERSION "" VERSION_SUFFIX;
|
||||
}
|
||||
/* it is a release, or we have nothing better */
|
||||
return VERSION "" VERSION_SUFFIX;
|
||||
}
|
||||
|
||||
char *freshdbdir(void)
|
||||
{
|
||||
struct cl_cvd *d1, *d2;
|
||||
struct optstruct *opts;
|
||||
const struct optstruct *opt;
|
||||
const char *dbdir;
|
||||
char *retdir;
|
||||
|
||||
/* try to find the most up-to-date db directory */
|
||||
dbdir = cl_retdbdir();
|
||||
if ((opts = optparse(CONFDIR_FRESHCLAM, 0, NULL, 0, OPT_FRESHCLAM, 0, NULL))) {
|
||||
if ((opt = optget(opts, "DatabaseDirectory"))->enabled) {
|
||||
if (strcmp(dbdir, opt->strarg)) {
|
||||
char *daily = (char *)malloc(strlen(opt->strarg) + strlen(dbdir) + 30);
|
||||
if (daily == NULL) {
|
||||
fprintf(stderr, "Unable to allocate memory for db directory...\n");
|
||||
return NULL;
|
||||
}
|
||||
sprintf(daily, "%s" PATHSEP "daily.cvd", opt->strarg);
|
||||
if (access(daily, R_OK))
|
||||
sprintf(daily, "%s" PATHSEP "daily.cld", opt->strarg);
|
||||
|
||||
if (!access(daily, R_OK) && (d1 = cl_cvdhead(daily))) {
|
||||
sprintf(daily, "%s" PATHSEP "daily.cvd", dbdir);
|
||||
if (access(daily, R_OK))
|
||||
sprintf(daily, "%s" PATHSEP "daily.cld", dbdir);
|
||||
|
||||
if (!access(daily, R_OK) && (d2 = cl_cvdhead(daily))) {
|
||||
free(daily);
|
||||
if (d1->version > d2->version)
|
||||
dbdir = opt->strarg;
|
||||
cl_cvdfree(d2);
|
||||
} else {
|
||||
free(daily);
|
||||
dbdir = opt->strarg;
|
||||
}
|
||||
cl_cvdfree(d1);
|
||||
} else {
|
||||
free(daily);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retdir = strdup(dbdir);
|
||||
|
||||
if (opts)
|
||||
optfree(opts);
|
||||
|
||||
return retdir;
|
||||
}
|
||||
|
||||
void print_version(const char *dbdir)
|
||||
{
|
||||
char *fdbdir = NULL, *path;
|
||||
const char *pt;
|
||||
struct cl_cvd *daily;
|
||||
time_t db_time;
|
||||
unsigned int db_version = 0;
|
||||
|
||||
if (dbdir)
|
||||
pt = dbdir;
|
||||
else
|
||||
pt = fdbdir = freshdbdir();
|
||||
|
||||
if (!pt) {
|
||||
printf("ClamAV %s\n", get_version());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(path = malloc(strlen(pt) + 11))) {
|
||||
if (!dbdir)
|
||||
free(fdbdir);
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(path, "%s" PATHSEP "daily.cvd", pt);
|
||||
if (!access(path, R_OK)) {
|
||||
daily = cl_cvdhead(path);
|
||||
if (daily) {
|
||||
db_version = daily->version;
|
||||
db_time = daily->stime;
|
||||
cl_cvdfree(daily);
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(path, "%s" PATHSEP "daily.cld", pt);
|
||||
if (!access(path, R_OK)) {
|
||||
daily = cl_cvdhead(path);
|
||||
if (daily) {
|
||||
if (daily->version > db_version) {
|
||||
db_version = daily->version;
|
||||
db_time = daily->stime;
|
||||
}
|
||||
cl_cvdfree(daily);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dbdir)
|
||||
free(fdbdir);
|
||||
|
||||
if (db_version) {
|
||||
printf("ClamAV %s/%u/%s", get_version(), db_version, ctime(&db_time));
|
||||
} else {
|
||||
printf("ClamAV %s\n", get_version());
|
||||
}
|
||||
|
||||
free(path);
|
||||
}
|
||||
|
||||
int check_flevel(void)
|
||||
{
|
||||
if (cl_retflevel() < CL_FLEVEL) {
|
||||
fprintf(stderr, "ERROR: This tool requires libclamav with functionality level %u or higher (current f-level: %u)\n", CL_FLEVEL, cl_retflevel());
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *filelist(const struct optstruct *opts, int *err)
|
||||
{
|
||||
static char buff[1025];
|
||||
static unsigned int cnt = 0;
|
||||
const struct optstruct *opt;
|
||||
static FILE *fs = NULL;
|
||||
size_t len;
|
||||
|
||||
if (!cnt && (opt = optget(opts, "file-list"))->enabled) {
|
||||
if (!fs) {
|
||||
fs = fopen(opt->strarg, "r");
|
||||
if (!fs) {
|
||||
fprintf(stderr, "ERROR: --file-list: Can't open file %s\n", opt->strarg);
|
||||
if (err)
|
||||
*err = 54;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (fgets(buff, 1024, fs)) {
|
||||
buff[1024] = 0;
|
||||
len = strlen(buff);
|
||||
if (!len) {
|
||||
fclose(fs);
|
||||
return NULL;
|
||||
}
|
||||
len--;
|
||||
while (len && ((buff[len] == '\n') || (buff[len] == '\r')))
|
||||
buff[len--] = '\0';
|
||||
return buff;
|
||||
} else {
|
||||
fclose(fs);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return opts->filename ? opts->filename[cnt++] : NULL;
|
||||
}
|
||||
|
||||
int filecopy(const char *src, const char *dest)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (!CopyFileA(src, dest, 0));
|
||||
#elif defined(C_DARWIN)
|
||||
pid_t pid;
|
||||
|
||||
/* On Mac OS X use ditto and copy resource fork, too. */
|
||||
switch (pid = fork()) {
|
||||
case -1:
|
||||
return -1;
|
||||
case 0:
|
||||
execl("/usr/bin/ditto", "ditto", src, dest, NULL);
|
||||
perror("execl(ditto)");
|
||||
break;
|
||||
default:
|
||||
wait(NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
#else /* C_DARWIN */
|
||||
return cli_filecopy(src, dest);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
int close_std_descriptors()
|
||||
{
|
||||
int fds[3], i;
|
||||
|
||||
fds[0] = open("/dev/null", O_RDONLY);
|
||||
fds[1] = open("/dev/null", O_WRONLY);
|
||||
fds[2] = open("/dev/null", O_WRONLY);
|
||||
if (fds[0] == -1 || fds[1] == -1 || fds[2] == -1) {
|
||||
fputs("Can't open /dev/null\n", stderr);
|
||||
for (i = 0; i <= 2; i++)
|
||||
if (fds[i] != -1)
|
||||
close(fds[i]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i <= 2; i++) {
|
||||
if (dup2(fds[i], i) == -1) {
|
||||
fprintf(stderr, "dup2(%d, %d) failed\n", fds[i], i); /* may not be printed */
|
||||
for (i = 0; i <= 2; i++)
|
||||
if (fds[i] != -1)
|
||||
close(fds[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i <= 2; i++)
|
||||
if (fds[i] > 2)
|
||||
close(fds[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int daemonize_all_return(void)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
|
||||
if (0 == pid) {
|
||||
setsid();
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
int daemonize(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = close_std_descriptors();
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = daemonize_all_return();
|
||||
pid_t pid = (pid_t)ret;
|
||||
/*parent process.*/
|
||||
if (pid > 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
static void daemonize_child_initialized_handler(int sig)
|
||||
{
|
||||
(void)(sig);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int daemonize_parent_wait(const char *const user, const char *const log_file)
|
||||
{
|
||||
int daemonizePid = daemonize_all_return();
|
||||
if (daemonizePid == -1) {
|
||||
return -1;
|
||||
} else if (daemonizePid) { // parent
|
||||
/* The parent will wait until either the child process
|
||||
* exits, or signals the parent that it's initialization is
|
||||
* complete. If it exits, it is due to an error condition,
|
||||
* so the parent should exit with the same error code as the child.
|
||||
* If the child signals the parent that initialization is complete, it
|
||||
* the parent will exit from the signal handler (initDoneSignalHandler)
|
||||
* with exit code 0.
|
||||
*/
|
||||
struct sigaction sig;
|
||||
memset(&sig, 0, sizeof(sig));
|
||||
sigemptyset(&(sig.sa_mask));
|
||||
sig.sa_handler = daemonize_child_initialized_handler;
|
||||
|
||||
if (0 != sigaction(SIGINT, &sig, NULL)) {
|
||||
perror("sigaction");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NULL != user) {
|
||||
if (drop_privileges(user, log_file)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int exitStatus;
|
||||
wait(&exitStatus);
|
||||
if (WIFEXITED(exitStatus)) { // error
|
||||
exitStatus = WEXITSTATUS(exitStatus);
|
||||
exit(exitStatus);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void daemonize_signal_parent(pid_t parentPid)
|
||||
{
|
||||
close_std_descriptors();
|
||||
kill(parentPid, SIGINT);
|
||||
}
|
||||
|
||||
int drop_privileges(const char *const user_name, const char *const log_file)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
/*This function is called in a bunch of places, and rather than change the error checking
|
||||
* in every function, we are just going to return success if there is no work to do.
|
||||
*/
|
||||
if ((0 == geteuid()) && (NULL != user_name)) {
|
||||
struct passwd *user = NULL;
|
||||
|
||||
if ((user = getpwnam(user_name)) == NULL) {
|
||||
logg(LOGG_WARNING, "Can't get information about user %s.\n", user_name);
|
||||
fprintf(stderr, "ERROR: Can't get information about user %s.\n", user_name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef HAVE_INITGROUPS
|
||||
if (initgroups(user_name, user->pw_gid)) {
|
||||
fprintf(stderr, "ERROR: initgroups() failed.\n");
|
||||
logg(LOGG_WARNING, "initgroups() failed.\n");
|
||||
goto done;
|
||||
}
|
||||
#elif HAVE_SETGROUPS
|
||||
if (setgroups(1, &user->pw_gid)) {
|
||||
fprintf(stderr, "ERROR: setgroups() failed.\n");
|
||||
logg(LOGG_WARNING, "setgroups() failed.\n");
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*Change ownership of the log file to the user we are going to switch to.*/
|
||||
if (NULL != log_file) {
|
||||
int ret = lchown(log_file, user->pw_uid, user->pw_gid);
|
||||
if (ret) {
|
||||
fprintf(stderr, "ERROR: lchown to user '%s' failed on\n", user->pw_name);
|
||||
fprintf(stderr, "log file '%s'.\n", log_file);
|
||||
fprintf(stderr, "Error was '%s'\n", strerror(errno));
|
||||
logg(LOGG_WARNING, "lchown to user '%s' failed on log file '%s'. Error was '%s'\n",
|
||||
user->pw_name, log_file, strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (setgid(user->pw_gid)) {
|
||||
fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int)user->pw_gid);
|
||||
logg(LOGG_WARNING, "setgid(%d) failed.\n", (int)user->pw_gid);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (setuid(user->pw_uid)) {
|
||||
fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int)user->pw_uid);
|
||||
logg(LOGG_WARNING, "setuid(%d) failed.\n", (int)user->pw_uid);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
#endif /*_WIN32*/
|
||||
|
||||
int match_regex(const char *filename, const char *pattern)
|
||||
{
|
||||
regex_t reg;
|
||||
int match, flags = REG_EXTENDED | REG_NOSUB;
|
||||
char fname[513];
|
||||
#ifdef _WIN32
|
||||
flags |= REG_ICASE; /* case insensitive on Windows */
|
||||
#endif
|
||||
if (cli_regcomp(®, pattern, flags) != 0)
|
||||
return 2;
|
||||
|
||||
if (pattern[strlen(pattern) - 1] == *PATHSEP) {
|
||||
snprintf(fname, 511, "%s" PATHSEP, filename);
|
||||
fname[512] = 0;
|
||||
} else {
|
||||
strncpy(fname, filename, 513);
|
||||
fname[512] = '\0';
|
||||
}
|
||||
|
||||
match = (cli_regexec(®, fname, 0, NULL, 0) == REG_NOMATCH) ? 0 : 1;
|
||||
cli_regfree(®);
|
||||
return match;
|
||||
}
|
||||
|
||||
int cli_is_abspath(const char *path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int len = strlen(path);
|
||||
return (len > 2 && path[0] == '\\' && path[1] == '\\') || (len >= 2 && ((*path >= 'a' && *path <= 'z') || (*path >= 'A' && *path <= 'Z')) && path[1] == ':');
|
||||
#else
|
||||
return *path == '/';
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int countlines(const char *filename)
|
||||
{
|
||||
FILE *fh;
|
||||
char buff[1024];
|
||||
unsigned int lines = 0;
|
||||
|
||||
if ((fh = fopen(filename, "r")) == NULL)
|
||||
return 0;
|
||||
|
||||
while (fgets(buff, sizeof(buff), fh)) {
|
||||
if (buff[0] == '#') continue;
|
||||
lines++;
|
||||
}
|
||||
|
||||
fclose(fh);
|
||||
return lines;
|
||||
}
|
||||
108
clamav/common/misc.h
Normal file
108
clamav/common/misc.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2007-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: Tomasz Kojm
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __MISC_H
|
||||
#define __MISC_H
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "platform.h"
|
||||
#include "optparser.h"
|
||||
/* Maximum filenames under various systems - njh */
|
||||
#ifndef NAME_MAX /* e.g. Linux */
|
||||
#ifdef MAXNAMELEN /* e.g. Solaris */
|
||||
#define NAME_MAX MAXNAMELEN
|
||||
#else
|
||||
#ifdef FILENAME_MAX /* e.g. SCO */
|
||||
#define NAME_MAX FILENAME_MAX
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYSTEMD
|
||||
#include <systemd/sd-daemon.h>
|
||||
#else
|
||||
#define sd_listen_fds(u) 0
|
||||
#define SD_LISTEN_FDS_START 3
|
||||
#define sd_is_socket(f, a, s, l) 1
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 1024
|
||||
#endif
|
||||
|
||||
#ifndef ADDR_LEN
|
||||
#define ADDR_LEN 13
|
||||
#endif
|
||||
|
||||
char *freshdbdir(void);
|
||||
void print_version(const char *dbdir);
|
||||
int check_flevel(void);
|
||||
const char *filelist(const struct optstruct *opts, int *err);
|
||||
int filecopy(const char *src, const char *dest);
|
||||
|
||||
#ifndef _WIN32
|
||||
/*Returns 0 on success (only the child process returns.*/
|
||||
int daemonize(void);
|
||||
|
||||
/*closes stdin, stdout, stderr. This is called by daemonize, but not
|
||||
* daemonize_all_return. Users of daemonize_all_return should call this
|
||||
* when initialization is complete.*/
|
||||
int close_std_descriptors(void);
|
||||
|
||||
/*Returns the return value of fork. All processes return */
|
||||
int daemonize_all_return(void);
|
||||
|
||||
/*Parent waits for a SIGINT or the child process to exit. If
|
||||
* it receives a SIGINT, it exits with exit code 0. If the child
|
||||
* exits (error), it exits with the child process's exit code.
|
||||
*
|
||||
* @param user If user is supplied and this function is being called
|
||||
* as root, daemonize_parent_wait will change the parent process
|
||||
* to user before calling wait so that the child process can signal
|
||||
* the parent when it is time to exit. The child process will still
|
||||
* return as root.
|
||||
*
|
||||
* @param log_file If user AND log_file are both supplied and this
|
||||
* function is being called as root, the ownership of log_file will
|
||||
* be changed to user.
|
||||
*/
|
||||
int daemonize_parent_wait(const char *const user, const char *const log_file);
|
||||
|
||||
/*Sends a SIGINT to the parent process. It also closes stdin, stdout,
|
||||
* and stderr.*/
|
||||
void daemonize_signal_parent(pid_t parentPid);
|
||||
|
||||
int drop_privileges(const char *const user, const char *const log_file);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
const char *get_version(void);
|
||||
int match_regex(const char *filename, const char *pattern);
|
||||
int cli_is_abspath(const char *path);
|
||||
unsigned int countlines(const char *filename);
|
||||
|
||||
#endif
|
||||
1483
clamav/common/optparser.c
Normal file
1483
clamav/common/optparser.c
Normal file
File diff suppressed because it is too large
Load Diff
95
clamav/common/optparser.h
Normal file
95
clamav/common/optparser.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2008-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Author: Tomasz Kojm <tkojm@clamav.net>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __OPTPARSER_H
|
||||
#define __OPTPARSER_H
|
||||
|
||||
/* don't share bits! */
|
||||
// clang-format off
|
||||
#define OPT_CLAMD 1
|
||||
#define OPT_FRESHCLAM 2
|
||||
#define OPT_MILTER 4
|
||||
#define OPT_CLAMSCAN 8
|
||||
#define OPT_CLAMDSCAN 16
|
||||
#define OPT_SIGTOOL 32
|
||||
#define OPT_CLAMCONF 64
|
||||
#define OPT_CLAMDTOP 128
|
||||
#define OPT_CLAMBC 256
|
||||
#define OPT_CLAMONACC 512
|
||||
#define OPT_DEPRECATED 1024
|
||||
|
||||
#define CLOPT_TYPE_STRING 1 /* quoted/regular string */
|
||||
#define CLOPT_TYPE_NUMBER 2 /* raw number */
|
||||
#define CLOPT_TYPE_SIZE 3 /* number possibly followed by modifiers (M/m or K/k) */
|
||||
#define CLOPT_TYPE_BOOL 4 /* boolean */
|
||||
|
||||
#ifdef _WIN32
|
||||
extern char _DATADIR[MAX_PATH];
|
||||
extern char _CONFDIR[MAX_PATH];
|
||||
extern char _CONFDIR_CLAMD[MAX_PATH];
|
||||
extern char _CONFDIR_FRESHCLAM[MAX_PATH];
|
||||
extern char _CONFDIR_MILTER[MAX_PATH];
|
||||
|
||||
#define DATADIR _DATADIR
|
||||
#define CONFDIR _CONFDIR
|
||||
#define CONFDIR_CLAMD _CONFDIR_CLAMD
|
||||
#define CONFDIR_FRESHCLAM _CONFDIR_FRESHCLAM
|
||||
#define CONFDIR_MILTER _CONFDIR_MILTER
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
struct optstruct {
|
||||
char *name;
|
||||
char *cmd;
|
||||
char *strarg;
|
||||
long long numarg;
|
||||
int enabled;
|
||||
int active;
|
||||
int flags;
|
||||
int idx;
|
||||
struct optstruct *nextarg;
|
||||
struct optstruct *next;
|
||||
|
||||
char **filename; /* cmdline */
|
||||
};
|
||||
|
||||
struct clam_option {
|
||||
const char *name;
|
||||
const char *longopt;
|
||||
char shortopt;
|
||||
int argtype;
|
||||
const char *regex;
|
||||
long long numarg;
|
||||
const char *strarg;
|
||||
int flags;
|
||||
int owner;
|
||||
const char *description;
|
||||
const char *suggested;
|
||||
};
|
||||
|
||||
const struct optstruct *optget(const struct optstruct *opts, const char *name);
|
||||
|
||||
void optfree(struct optstruct *opts);
|
||||
|
||||
struct optstruct *optparse(const char *cfgfile, int argc, char **argv, int verbose, int toolmask, int ignore, struct optstruct *oldopts);
|
||||
struct optstruct *optadditem(const char *name, const char *arg, int verbose, int toolmask, int ignore, struct optstruct *oldopts);
|
||||
|
||||
#endif
|
||||
617
clamav/common/output.c
Normal file
617
clamav/common/output.c
Normal file
@@ -0,0 +1,617 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2007-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: Tomasz Kojm
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#if defined(USE_SYSLOG) && !defined(C_AIX)
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
// libclamav
|
||||
#include "clamav.h"
|
||||
#include "others.h"
|
||||
#include "str.h"
|
||||
|
||||
#include "output.h"
|
||||
|
||||
#ifdef CL_THREAD_SAFE
|
||||
#include <pthread.h>
|
||||
pthread_mutex_t logg_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_t mdprintf_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
#if defined(C_LINUX) && defined(HAVE_LIBINTL_H)
|
||||
#include <libintl.h>
|
||||
#include <locale.h>
|
||||
|
||||
#define gettext_noop(s) s
|
||||
#define _(s) gettext(s)
|
||||
#define N_(s) gettext_noop(s)
|
||||
|
||||
#else
|
||||
|
||||
#define _(s) s
|
||||
#define N_(s) s
|
||||
|
||||
#endif
|
||||
|
||||
FILE *logg_fp = NULL;
|
||||
|
||||
short int logg_verbose = 0, logg_nowarn = 0, logg_lock = 1, logg_time = 0, logg_foreground = 1, logg_noflush = 0, logg_rotate = 0;
|
||||
off_t logg_size = 0;
|
||||
const char *logg_file = NULL;
|
||||
#if defined(USE_SYSLOG) && !defined(C_AIX)
|
||||
short logg_syslog;
|
||||
#endif
|
||||
|
||||
short int mprintf_disabled = 0, mprintf_verbose = 0, mprintf_quiet = 0,
|
||||
mprintf_stdout = 0, mprintf_nowarn = 0, mprintf_send_timeout = 100, mprintf_progress = 0;
|
||||
|
||||
#define ARGLEN(args, str, len) \
|
||||
{ \
|
||||
size_t arglen = 1, i; \
|
||||
char *pt; \
|
||||
va_start(args, str); \
|
||||
len = strlen(str); \
|
||||
for (i = 0; i < len - 1; i++) { \
|
||||
if (str[i] == '%') { \
|
||||
switch (str[++i]) { \
|
||||
case 's': \
|
||||
pt = va_arg(args, char *); \
|
||||
if (pt) \
|
||||
arglen += strlen(pt); \
|
||||
break; \
|
||||
case 'f': \
|
||||
va_arg(args, double); \
|
||||
arglen += 25; \
|
||||
break; \
|
||||
case 'l': \
|
||||
va_arg(args, long); \
|
||||
arglen += 20; \
|
||||
break; \
|
||||
default: \
|
||||
va_arg(args, int); \
|
||||
arglen += 10; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
va_end(args); \
|
||||
len += arglen; \
|
||||
}
|
||||
|
||||
int mdprintf(int desc, const char *str, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buffer[512], *abuffer = NULL, *buff;
|
||||
int bytes, todo, ret = 0;
|
||||
size_t len;
|
||||
|
||||
ARGLEN(args, str, len);
|
||||
if (len <= sizeof(buffer)) {
|
||||
len = sizeof(buffer);
|
||||
buff = buffer;
|
||||
} else {
|
||||
abuffer = malloc(len);
|
||||
if (!abuffer) {
|
||||
len = sizeof(buffer);
|
||||
buff = buffer;
|
||||
} else {
|
||||
buff = abuffer;
|
||||
}
|
||||
}
|
||||
va_start(args, str);
|
||||
bytes = vsnprintf(buff, len, str, args);
|
||||
va_end(args);
|
||||
buff[len - 1] = 0;
|
||||
|
||||
if (bytes < 0) {
|
||||
if (len > sizeof(buffer))
|
||||
free(abuffer);
|
||||
return bytes;
|
||||
}
|
||||
if ((size_t)bytes >= len)
|
||||
bytes = len - 1;
|
||||
|
||||
todo = bytes;
|
||||
#ifdef CL_THREAD_SAFE
|
||||
/* make sure we don't mix sends from multiple threads,
|
||||
* important for IDSESSION */
|
||||
pthread_mutex_lock(&mdprintf_mutex);
|
||||
#endif
|
||||
while (todo > 0) {
|
||||
ret = send(desc, buff, bytes, 0);
|
||||
if (ret < 0) {
|
||||
struct timeval tv;
|
||||
if (errno != EWOULDBLOCK)
|
||||
break;
|
||||
/* didn't send anything yet */
|
||||
#ifdef CL_THREAD_SAFE
|
||||
pthread_mutex_unlock(&mdprintf_mutex);
|
||||
#endif
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = mprintf_send_timeout * 1000;
|
||||
do {
|
||||
fd_set wfds;
|
||||
FD_ZERO(&wfds);
|
||||
FD_SET(desc, &wfds);
|
||||
ret = select(desc + 1, NULL, &wfds, NULL, &tv);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
#ifdef CL_THREAD_SAFE
|
||||
pthread_mutex_lock(&mdprintf_mutex);
|
||||
#endif
|
||||
if (!ret) {
|
||||
/* timed out */
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
todo -= ret;
|
||||
buff += ret;
|
||||
}
|
||||
}
|
||||
#ifdef CL_THREAD_SAFE
|
||||
pthread_mutex_unlock(&mdprintf_mutex);
|
||||
#endif
|
||||
|
||||
if (len > sizeof(buffer))
|
||||
free(abuffer);
|
||||
|
||||
return ret < 0 ? -1 : bytes;
|
||||
}
|
||||
|
||||
static int rename_logg(STATBUF *sb)
|
||||
{
|
||||
char *rotate_file;
|
||||
size_t rotate_file_len;
|
||||
time_t t;
|
||||
struct tm tmp;
|
||||
|
||||
if (!logg_rotate) {
|
||||
if (logg_fp) {
|
||||
fprintf(logg_fp, "Log size = %lld, max = %lld\n", (long long int)sb->st_size, (long long int)logg_size);
|
||||
fprintf(logg_fp, "WARNING: Log size limit met but log file rotation turned off. Forcing log file rotation anyways.\n");
|
||||
}
|
||||
|
||||
logg_rotate = 1;
|
||||
}
|
||||
|
||||
rotate_file_len = strlen(logg_file) + strlen("-YYYY-MM-DD_HH:MM:SS.log");
|
||||
rotate_file = calloc(1, rotate_file_len + 1);
|
||||
if (!rotate_file) {
|
||||
if (logg_fp)
|
||||
fprintf(logg_fp, "Need to rotate log file due to size but ran out of memory.\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
t = time(NULL);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (0 != localtime_s(&tmp, &t)) {
|
||||
#else
|
||||
if (!localtime_r(&t, &tmp)) {
|
||||
#endif
|
||||
if (logg_fp)
|
||||
fprintf(logg_fp, "Need to rotate log file due to size but could not get local time.\n");
|
||||
|
||||
free(rotate_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(rotate_file, logg_file);
|
||||
strftime(rotate_file + strlen(rotate_file) - strlen(".log"), rotate_file_len - strlen(rotate_file), "-%Y%m%d_%H%M%S.log", &tmp);
|
||||
|
||||
if (logg_fp) {
|
||||
fclose(logg_fp);
|
||||
logg_fp = NULL;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (0 == MoveFileA(logg_file, rotate_file)) {
|
||||
fprintf(stderr, "Failed to rename file with error code: %d\n", GetLastError());
|
||||
#else
|
||||
if (rename(logg_file, rotate_file)) {
|
||||
#endif
|
||||
free(rotate_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(rotate_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int logg_open(void)
|
||||
{
|
||||
STATBUF sb;
|
||||
|
||||
if (logg_file)
|
||||
if (logg_size > 0)
|
||||
if (CLAMSTAT(logg_file, &sb) != -1)
|
||||
if (sb.st_size > logg_size)
|
||||
if (rename_logg(&sb))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void logg_close(void)
|
||||
{
|
||||
#if defined(USE_SYSLOG) && !defined(C_AIX)
|
||||
if (logg_syslog)
|
||||
closelog();
|
||||
#endif
|
||||
|
||||
#ifdef CL_THREAD_SAFE
|
||||
pthread_mutex_lock(&logg_mutex);
|
||||
#endif
|
||||
if (logg_fp) {
|
||||
fclose(logg_fp);
|
||||
logg_fp = NULL;
|
||||
}
|
||||
#ifdef CL_THREAD_SAFE
|
||||
pthread_mutex_unlock(&logg_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
int logg(loglevel_t loglevel, const char *str, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buffer[1025], *abuffer = NULL, *buff;
|
||||
time_t currtime;
|
||||
size_t len;
|
||||
mode_t old_umask;
|
||||
#ifdef F_WRLCK
|
||||
struct flock fl;
|
||||
#endif
|
||||
|
||||
if ((loglevel == LOGG_DEBUG_NV && logg_verbose < 2) ||
|
||||
(loglevel == LOGG_DEBUG && !logg_verbose))
|
||||
return 0;
|
||||
|
||||
ARGLEN(args, str, len);
|
||||
if (len <= sizeof(buffer)) {
|
||||
len = sizeof(buffer);
|
||||
buff = buffer;
|
||||
} else {
|
||||
abuffer = malloc(len);
|
||||
if (!abuffer) {
|
||||
len = sizeof(buffer);
|
||||
buff = buffer;
|
||||
} else {
|
||||
buff = abuffer;
|
||||
}
|
||||
}
|
||||
va_start(args, str);
|
||||
vsnprintf(buff, len, str, args);
|
||||
va_end(args);
|
||||
buff[len - 1] = 0;
|
||||
|
||||
#ifdef CL_THREAD_SAFE
|
||||
pthread_mutex_lock(&logg_mutex);
|
||||
#endif
|
||||
|
||||
logg_open();
|
||||
|
||||
if (!logg_fp && logg_file) {
|
||||
old_umask = umask(0037);
|
||||
if ((logg_fp = fopen(logg_file, "at")) == NULL) {
|
||||
umask(old_umask);
|
||||
#ifdef CL_THREAD_SAFE
|
||||
pthread_mutex_unlock(&logg_mutex);
|
||||
#endif
|
||||
printf("ERROR: Can't open %s in append mode (check permissions!).\n", logg_file);
|
||||
if (len > sizeof(buffer))
|
||||
free(abuffer);
|
||||
return -1;
|
||||
} else
|
||||
umask(old_umask);
|
||||
|
||||
#ifdef F_WRLCK
|
||||
if (logg_lock) {
|
||||
memset(&fl, 0, sizeof(fl));
|
||||
fl.l_type = F_WRLCK;
|
||||
if (fcntl(fileno(logg_fp), F_SETLK, &fl) == -1) {
|
||||
#ifdef EOPNOTSUPP
|
||||
if (errno == EOPNOTSUPP)
|
||||
printf("WARNING: File locking not supported (NFS?)\n");
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef CL_THREAD_SAFE
|
||||
pthread_mutex_unlock(&logg_mutex);
|
||||
#endif
|
||||
printf("ERROR: %s is locked by another process\n", logg_file);
|
||||
if (len > sizeof(buffer))
|
||||
free(abuffer);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (logg_fp) {
|
||||
char flush = !logg_noflush;
|
||||
/* Need to avoid logging time for verbose messages when logverbose
|
||||
is not set or we get a bunch of timestamps in the log without
|
||||
newlines... */
|
||||
if (logg_time && ((loglevel != LOGG_DEBUG) || logg_verbose)) {
|
||||
char timestr[32];
|
||||
time(&currtime);
|
||||
cli_ctime(&currtime, timestr, sizeof(timestr));
|
||||
/* cut trailing \n */
|
||||
timestr[strlen(timestr) - 1] = '\0';
|
||||
fprintf(logg_fp, "%s -> ", timestr);
|
||||
}
|
||||
|
||||
if (loglevel == LOGG_ERROR) {
|
||||
fprintf(logg_fp, "ERROR: %s", buff);
|
||||
flush = 1;
|
||||
} else if (loglevel == LOGG_WARNING) {
|
||||
if (!logg_nowarn)
|
||||
fprintf(logg_fp, "WARNING: %s", buff);
|
||||
flush = 1;
|
||||
} else if (loglevel == LOGG_DEBUG || loglevel == LOGG_DEBUG_NV) {
|
||||
fprintf(logg_fp, "%s", buff);
|
||||
} else if (loglevel == LOGG_INFO_NF || loglevel == LOGG_INFO) {
|
||||
fprintf(logg_fp, "%s", buff);
|
||||
} else
|
||||
fprintf(logg_fp, "%s", buff);
|
||||
|
||||
if (flush)
|
||||
fflush(logg_fp);
|
||||
}
|
||||
|
||||
if (logg_foreground) {
|
||||
if (loglevel != LOGG_INFO_NF) {
|
||||
if (logg_time) {
|
||||
char timestr[32];
|
||||
time(&currtime);
|
||||
cli_ctime(&currtime, timestr, sizeof(timestr));
|
||||
/* cut trailing \n */
|
||||
timestr[strlen(timestr) - 1] = '\0';
|
||||
mprintf(loglevel, "%s -> %s", timestr, buff);
|
||||
} else {
|
||||
mprintf(loglevel, "%s", buff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(USE_SYSLOG) && !defined(C_AIX)
|
||||
if (logg_syslog) {
|
||||
cli_chomp(buff);
|
||||
if (loglevel == LOGG_ERROR) {
|
||||
syslog(LOG_ERR, "%s", buff);
|
||||
} else if (loglevel == LOGG_WARNING) {
|
||||
if (!logg_nowarn)
|
||||
syslog(LOG_WARNING, "%s", buff);
|
||||
} else if (loglevel == LOGG_DEBUG || loglevel == LOGG_DEBUG_NV) {
|
||||
syslog(LOG_DEBUG, "%s", buff);
|
||||
} else
|
||||
syslog(LOG_INFO, "%s", buff);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CL_THREAD_SAFE
|
||||
pthread_mutex_unlock(&logg_mutex);
|
||||
#endif
|
||||
|
||||
if (len > sizeof(buffer))
|
||||
free(abuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mprintf(loglevel_t loglevel, const char *str, ...)
|
||||
{
|
||||
va_list args;
|
||||
FILE *fd;
|
||||
char buffer[512], *abuffer = NULL, *buff;
|
||||
size_t len;
|
||||
|
||||
if (mprintf_disabled)
|
||||
return;
|
||||
|
||||
fd = stdout;
|
||||
|
||||
ARGLEN(args, str, len);
|
||||
if (len <= sizeof(buffer)) {
|
||||
len = sizeof(buffer);
|
||||
buff = buffer;
|
||||
} else {
|
||||
abuffer = malloc(len);
|
||||
if (!abuffer) {
|
||||
len = sizeof(buffer);
|
||||
buff = buffer;
|
||||
} else {
|
||||
buff = abuffer;
|
||||
}
|
||||
}
|
||||
va_start(args, str);
|
||||
vsnprintf(buff, len, str, args);
|
||||
va_end(args);
|
||||
buff[len - 1] = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
do {
|
||||
int tmplen = len + 1;
|
||||
wchar_t *tmpw = malloc(tmplen * sizeof(wchar_t));
|
||||
char *nubuff;
|
||||
if (!tmpw)
|
||||
break;
|
||||
if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, buff, -1, tmpw, tmplen)) {
|
||||
free(tmpw);
|
||||
break;
|
||||
}
|
||||
/* FIXME CHECK IT'S REALLY UTF8 */
|
||||
nubuff = (char *)malloc(tmplen);
|
||||
if (!nubuff) {
|
||||
free(tmpw);
|
||||
break;
|
||||
}
|
||||
if (!WideCharToMultiByte(CP_OEMCP, 0, tmpw, -1, nubuff, tmplen, NULL, NULL)) {
|
||||
free(nubuff);
|
||||
free(tmpw);
|
||||
break;
|
||||
}
|
||||
free(tmpw);
|
||||
if (len > sizeof(buffer))
|
||||
free(abuffer);
|
||||
abuffer = buff = nubuff;
|
||||
len = sizeof(buffer) + 1;
|
||||
} while (0);
|
||||
#endif
|
||||
if (loglevel == LOGG_ERROR) {
|
||||
if (!mprintf_stdout)
|
||||
fd = stderr;
|
||||
fprintf(fd, "ERROR: %s", buff);
|
||||
} else if (!mprintf_quiet) {
|
||||
if (loglevel == LOGG_WARNING) {
|
||||
if (!mprintf_nowarn) {
|
||||
if (!mprintf_stdout)
|
||||
fd = stderr;
|
||||
fprintf(fd, "WARNING: %s", buff);
|
||||
}
|
||||
} else if (loglevel == LOGG_DEBUG) {
|
||||
if (mprintf_verbose)
|
||||
fprintf(fd, "%s", buff);
|
||||
} else if (loglevel == LOGG_INFO) {
|
||||
fprintf(fd, "%s", buff);
|
||||
} else
|
||||
fprintf(fd, "%s", buff);
|
||||
}
|
||||
|
||||
if (fd == stdout)
|
||||
fflush(stdout);
|
||||
|
||||
if (len > sizeof(buffer))
|
||||
free(abuffer);
|
||||
}
|
||||
|
||||
struct facstruct {
|
||||
const char *name;
|
||||
int code;
|
||||
};
|
||||
|
||||
#if defined(USE_SYSLOG) && !defined(C_AIX)
|
||||
static const struct facstruct facilitymap[] = {
|
||||
#ifdef LOG_AUTH
|
||||
{"LOG_AUTH", LOG_AUTH},
|
||||
#endif
|
||||
#ifdef LOG_AUTHPRIV
|
||||
{"LOG_AUTHPRIV", LOG_AUTHPRIV},
|
||||
#endif
|
||||
#ifdef LOG_CRON
|
||||
{"LOG_CRON", LOG_CRON},
|
||||
#endif
|
||||
#ifdef LOG_DAEMON
|
||||
{"LOG_DAEMON", LOG_DAEMON},
|
||||
#endif
|
||||
#ifdef LOG_FTP
|
||||
{"LOG_FTP", LOG_FTP},
|
||||
#endif
|
||||
#ifdef LOG_KERN
|
||||
{"LOG_KERN", LOG_KERN},
|
||||
#endif
|
||||
#ifdef LOG_LPR
|
||||
{"LOG_LPR", LOG_LPR},
|
||||
#endif
|
||||
#ifdef LOG_MAIL
|
||||
{"LOG_MAIL", LOG_MAIL},
|
||||
#endif
|
||||
#ifdef LOG_NEWS
|
||||
{"LOG_NEWS", LOG_NEWS},
|
||||
#endif
|
||||
#ifdef LOG_AUTH
|
||||
{"LOG_AUTH", LOG_AUTH},
|
||||
#endif
|
||||
#ifdef LOG_SYSLOG
|
||||
{"LOG_SYSLOG", LOG_SYSLOG},
|
||||
#endif
|
||||
#ifdef LOG_USER
|
||||
{"LOG_USER", LOG_USER},
|
||||
#endif
|
||||
#ifdef LOG_UUCP
|
||||
{"LOG_UUCP", LOG_UUCP},
|
||||
#endif
|
||||
#ifdef LOG_LOCAL0
|
||||
{"LOG_LOCAL0", LOG_LOCAL0},
|
||||
#endif
|
||||
#ifdef LOG_LOCAL1
|
||||
{"LOG_LOCAL1", LOG_LOCAL1},
|
||||
#endif
|
||||
#ifdef LOG_LOCAL2
|
||||
{"LOG_LOCAL2", LOG_LOCAL2},
|
||||
#endif
|
||||
#ifdef LOG_LOCAL3
|
||||
{"LOG_LOCAL3", LOG_LOCAL3},
|
||||
#endif
|
||||
#ifdef LOG_LOCAL4
|
||||
{"LOG_LOCAL4", LOG_LOCAL4},
|
||||
#endif
|
||||
#ifdef LOG_LOCAL5
|
||||
{"LOG_LOCAL5", LOG_LOCAL5},
|
||||
#endif
|
||||
#ifdef LOG_LOCAL6
|
||||
{"LOG_LOCAL6", LOG_LOCAL6},
|
||||
#endif
|
||||
#ifdef LOG_LOCAL7
|
||||
{"LOG_LOCAL7", LOG_LOCAL7},
|
||||
#endif
|
||||
{NULL, -1}};
|
||||
|
||||
int logg_facility(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; facilitymap[i].name; i++)
|
||||
if (!strcmp(facilitymap[i].name, name))
|
||||
return facilitymap[i].code;
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
97
clamav/common/output.h
Normal file
97
clamav/common/output.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2007-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: Tomasz Kojm
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __OUTPUT_H
|
||||
#define __OUTPUT_H
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "clamav-config.h"
|
||||
#endif
|
||||
|
||||
#if HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
int mdprintf(int desc, const char *str, ...) __attribute__((format(printf, 2, 3)));
|
||||
#else
|
||||
int mdprintf(int desc, const char *str, ...);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* legend:
|
||||
* NAME EXPLAIN
|
||||
* LOGG_INFO normal
|
||||
* LOGG_INFO_NF normal, no foreground (logfile and syslog only)
|
||||
* LOGG_DEBUG debug, verbose
|
||||
* LOGG_DEBUG_NV debug, non-verbose
|
||||
* LOGG_WARNING warning
|
||||
* LOGG_ERROR ERROR
|
||||
*/
|
||||
typedef enum loglevel {
|
||||
LOGG_INFO,
|
||||
LOGG_INFO_NF,
|
||||
LOGG_DEBUG,
|
||||
LOGG_DEBUG_NV,
|
||||
LOGG_WARNING,
|
||||
LOGG_ERROR
|
||||
} loglevel_t;
|
||||
|
||||
/*
|
||||
* @param loglevel legend:
|
||||
* NAME EXPLAIN
|
||||
* LOGG_INFO normal
|
||||
* LOGG_INFO_NF normal, no foreground (logfile and syslog only)
|
||||
* LOGG_DEBUG debug, verbose
|
||||
* LOGG_DEBUG_NV debug, non-verbose
|
||||
* LOGG_WARNING warning
|
||||
* LOGG_ERROR ERROR
|
||||
*
|
||||
* @return 0 fur success and -1 for error, e.g. log file access problems
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
int logg(loglevel_t loglevel, const char *str, ...) __attribute__((format(printf, 2, 3)));
|
||||
#else
|
||||
int logg(loglevel_t loglevel, const char *str, ...);
|
||||
#endif
|
||||
|
||||
void logg_close(void);
|
||||
extern short int logg_verbose, logg_nowarn, logg_lock, logg_time, logg_noflush, logg_rotate;
|
||||
extern off_t logg_size;
|
||||
extern const char *logg_file;
|
||||
|
||||
#if defined(USE_SYSLOG) && !defined(C_AIX)
|
||||
extern short logg_syslog;
|
||||
int logg_facility(const char *name);
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
void mprintf(loglevel_t loglevel, const char *str, ...) __attribute__((format(printf, 2, 3)));
|
||||
#else
|
||||
void mprintf(loglevel_t loglevel, const char *str, ...);
|
||||
#endif
|
||||
|
||||
extern short int mprintf_disabled, mprintf_verbose, mprintf_quiet, mprintf_nowarn, mprintf_stdout, mprintf_send_timeout, mprintf_progress;
|
||||
|
||||
#endif
|
||||
710
clamav/common/scanmem.c
Normal file
710
clamav/common/scanmem.c
Normal file
@@ -0,0 +1,710 @@
|
||||
/*
|
||||
* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2005-2010 Gianluigi Tiesi <sherpya@netfarm.it>
|
||||
*
|
||||
* Authors: Gianluigi Tiesi
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
#include <psapi.h>
|
||||
#include <windns.h>
|
||||
|
||||
#include <clamav.h>
|
||||
#include <others.h>
|
||||
|
||||
#include "actions.h"
|
||||
#include "output.h"
|
||||
#include "clamdcom.h"
|
||||
#include "exescanner.h"
|
||||
#include "scanmem.h"
|
||||
|
||||
typedef int (*proc_callback)(PROCESSENTRY32 ProcStruct, MODULEENTRY32 me32, void *data, struct mem_info *info);
|
||||
int sock;
|
||||
struct optstruct *clamdopts;
|
||||
|
||||
static inline int lookup_cache(filelist_t **list, const char *filename)
|
||||
{
|
||||
filelist_t *current = *list;
|
||||
while (current) {
|
||||
/* Cache hit */
|
||||
if (!_stricmp(filename, current->filename)) {
|
||||
return current->res;
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void insert_cache(filelist_t **list, const char *filename,
|
||||
int res)
|
||||
{
|
||||
filelist_t *current = *list, *prev = NULL;
|
||||
|
||||
if (!current) /* New */
|
||||
*list = current = malloc(sizeof(filelist_t));
|
||||
else {
|
||||
while (current->next)
|
||||
current = current->next;
|
||||
prev = current;
|
||||
prev->next = current = malloc(sizeof(filelist_t));
|
||||
}
|
||||
|
||||
current->next = NULL;
|
||||
current->res = res;
|
||||
current->filename[0] = 0;
|
||||
strncat(current->filename, filename,
|
||||
MAX_PATH - 1 - strlen(current->filename));
|
||||
current->filename[MAX_PATH - 1] = 0;
|
||||
}
|
||||
|
||||
static inline void free_cache(filelist_t **list)
|
||||
{
|
||||
filelist_t *current, *prev;
|
||||
current = prev = *list;
|
||||
|
||||
if (!current)
|
||||
return;
|
||||
|
||||
do {
|
||||
prev = current;
|
||||
current = prev->next;
|
||||
free(prev);
|
||||
} while (current);
|
||||
}
|
||||
|
||||
static inline char *wc2mb(const wchar_t *wc, DWORD flags)
|
||||
{
|
||||
BOOL invalid = FALSE;
|
||||
DWORD len = 0, res = 0;
|
||||
char *mb = NULL;
|
||||
|
||||
len = WideCharToMultiByte(CP_ACP, flags, wc, -1, NULL, 0, NULL, &invalid);
|
||||
if (!len && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
|
||||
fprintf(stderr, "WideCharToMultiByte() failed with %d\n", GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mb = cli_malloc(len + 1);
|
||||
if (!mb) return NULL;
|
||||
|
||||
res = WideCharToMultiByte(CP_ACP, flags, wc, -1, mb, len, NULL, &invalid);
|
||||
if (res && ((!invalid || (flags != WC_NO_BEST_FIT_CHARS)))) return mb;
|
||||
free(mb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Needed to Scan System Processes */
|
||||
int EnablePrivilege(LPCSTR PrivilegeName, DWORD yesno)
|
||||
{
|
||||
HANDLE hToken;
|
||||
TOKEN_PRIVILEGES tp;
|
||||
LUID luid;
|
||||
|
||||
if (!LoadLibraryA("advapi32.dll")) {
|
||||
logg(LOGG_WARNING, "EnablePrivilege functions are missing\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!OpenProcessToken(
|
||||
GetCurrentProcess(),
|
||||
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ, &hToken))
|
||||
return 0;
|
||||
|
||||
if (!LookupPrivilegeValue(NULL, PrivilegeName, &luid))
|
||||
return 0;
|
||||
|
||||
tp.PrivilegeCount = 1;
|
||||
tp.Privileges[0].Luid = luid;
|
||||
tp.Privileges[0].Attributes = yesno;
|
||||
|
||||
AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
|
||||
|
||||
CloseHandle(hToken);
|
||||
return (GetLastError() == ERROR_SUCCESS) ? 1 : 0;
|
||||
}
|
||||
|
||||
static char *getaltpath(const wchar_t *filename)
|
||||
{
|
||||
WIN32_FIND_DATAW wfdw;
|
||||
HANDLE hf = INVALID_HANDLE_VALUE;
|
||||
wchar_t *part = _wcsdup(filename);
|
||||
wchar_t comprev[MAX_PATH + 1] = L"", compose[MAX_PATH + 1];
|
||||
wchar_t *rev = comprev, *slash = part, *c = NULL;
|
||||
size_t l, la;
|
||||
size_t i;
|
||||
|
||||
do {
|
||||
if (slash != part)
|
||||
*slash = 0;
|
||||
|
||||
/* c: d: etc */
|
||||
if ((wcslen(part) == 2) && (part[1] == L':')) {
|
||||
*rev++ = L':';
|
||||
*rev++ = part[0];
|
||||
break;
|
||||
}
|
||||
|
||||
hf = FindFirstFileW(part, &wfdw);
|
||||
if (hf == INVALID_HANDLE_VALUE) /* Network path */
|
||||
{
|
||||
for (i = wcslen(part); i > 0; i--)
|
||||
*rev++ = part[i - 1];
|
||||
break;
|
||||
}
|
||||
FindClose(hf);
|
||||
l = wcslen(wfdw.cFileName);
|
||||
la = wcslen(wfdw.cAlternateFileName);
|
||||
|
||||
if (la)
|
||||
for (i = la; i > 0; i--)
|
||||
*rev++ = *(wfdw.cAlternateFileName + i - 1);
|
||||
else
|
||||
for (i = l; i > 0; i--)
|
||||
*rev++ = *(wfdw.cFileName + i - 1);
|
||||
*rev++ = '\\';
|
||||
|
||||
} while ((slash = wcsrchr(part, L'\\')));
|
||||
|
||||
rev = comprev;
|
||||
c = compose;
|
||||
for (i = wcslen(rev); i > 0; i--)
|
||||
*c++ = *(rev + i - 1);
|
||||
*c = 0;
|
||||
|
||||
free(part);
|
||||
return wc2mb(compose, WC_NO_BEST_FIT_CHARS);
|
||||
}
|
||||
|
||||
int walkmodules_th(proc_callback callback, void *data, struct mem_info *info)
|
||||
{
|
||||
HANDLE hSnap = INVALID_HANDLE_VALUE, hModuleSnap = INVALID_HANDLE_VALUE;
|
||||
PROCESSENTRY32 ps;
|
||||
MODULEENTRY32 me32;
|
||||
|
||||
logg(LOGG_INFO, " *** Memory Scan: using ToolHelp ***\n\n");
|
||||
|
||||
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (hSnap == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
|
||||
ps.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
if (!Process32First(hSnap, &ps)) {
|
||||
CloseHandle(hSnap);
|
||||
return -1;
|
||||
}
|
||||
|
||||
do {
|
||||
/* system process */
|
||||
if (!ps.th32ProcessID)
|
||||
continue;
|
||||
hModuleSnap = CreateToolhelp32Snapshot(
|
||||
TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, ps.th32ProcessID);
|
||||
if (hModuleSnap == INVALID_HANDLE_VALUE)
|
||||
continue;
|
||||
|
||||
me32.dwSize = sizeof(MODULEENTRY32);
|
||||
if (!Module32First(hModuleSnap, &me32)) {
|
||||
CloseHandle(hModuleSnap);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check and transform non ANSI filenames to ANSI using altnames */
|
||||
if (GetModuleFileNameEx) {
|
||||
HANDLE hFile = CreateFile(
|
||||
me32.szExePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
DWORD err = GetLastError();
|
||||
wchar_t name[MAX_PATH + 1];
|
||||
char *converted = NULL;
|
||||
HANDLE p;
|
||||
|
||||
if (err == ERROR_BAD_NETPATH) {
|
||||
logg(LOGG_WARNING, "Warning scanning files on non-ansi network paths is not "
|
||||
"supported\n");
|
||||
logg(LOGG_WARNING, "File: %s\n", me32.szExePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((err != ERROR_INVALID_NAME) && (err != ERROR_PATH_NOT_FOUND)) {
|
||||
logg(LOGG_WARNING, "Expected ERROR_INVALID_NAME/ERROR_PATH_NOT_FOUND but got %d\n",
|
||||
err);
|
||||
continue;
|
||||
}
|
||||
|
||||
p = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
|
||||
ps.th32ProcessID);
|
||||
if (!GetModuleFileNameEx(p, NULL, name, MAX_PATH)) {
|
||||
logg(LOGG_WARNING, "GetModuleFileNameExW() failed %d\n", GetLastError());
|
||||
CloseHandle(p);
|
||||
continue;
|
||||
}
|
||||
CloseHandle(p);
|
||||
|
||||
if (!(converted = getaltpath(name))) {
|
||||
logg(LOGG_WARNING, "Cannot map filename to ANSI codepage\n");
|
||||
continue;
|
||||
}
|
||||
strcpy(me32.szExePath, converted);
|
||||
free(converted);
|
||||
} else
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
do
|
||||
if (callback(ps, me32, data, info))
|
||||
break;
|
||||
while (Module32Next(hModuleSnap, &me32));
|
||||
|
||||
CloseHandle(hModuleSnap);
|
||||
} while (Process32Next(hSnap, &ps));
|
||||
CloseHandle(hSnap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int walkmodules_psapi(proc_callback callback, void *data, struct mem_info *info)
|
||||
{
|
||||
DWORD procs[1024], needed, nprocs, mneeded;
|
||||
HANDLE hProc;
|
||||
HMODULE mods[1024];
|
||||
PROCESSENTRY32 ps;
|
||||
MODULEENTRY32 me32;
|
||||
MODULEINFO mi;
|
||||
int i, j;
|
||||
|
||||
logg(LOGG_INFO, " *** Memory Scan: using PsApi ***\n\n");
|
||||
|
||||
if (!EnumProcesses(procs, sizeof(procs), &needed))
|
||||
return -1;
|
||||
|
||||
nprocs = needed / sizeof(DWORD);
|
||||
|
||||
memset(&ps, 0, sizeof(PROCESSENTRY32));
|
||||
memset(&me32, 0, sizeof(MODULEENTRY32));
|
||||
ps.dwSize = sizeof(PROCESSENTRY32);
|
||||
me32.dwSize = sizeof(MODULEENTRY32);
|
||||
|
||||
for (i = 0; i < nprocs; i++) {
|
||||
if (!procs[i])
|
||||
continue; /* System process */
|
||||
|
||||
hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
|
||||
procs[i]);
|
||||
|
||||
if (!hProc)
|
||||
continue;
|
||||
|
||||
if (!EnumProcessModules(hProc, mods, sizeof(mods),
|
||||
&mneeded)) {
|
||||
CloseHandle(hProc);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!GetModuleBaseName(hProc, mods[0], ps.szExeFile,
|
||||
MAX_PATH - 1)) {
|
||||
CloseHandle(hProc);
|
||||
continue;
|
||||
}
|
||||
|
||||
ps.th32ProcessID = procs[i];
|
||||
|
||||
for (j = 0; j < (mneeded / sizeof(HMODULE)); j++) {
|
||||
if (!GetModuleBaseNameA(hProc, mods[j], me32.szModule,
|
||||
MAX_PATH - 1))
|
||||
continue;
|
||||
|
||||
if (!GetModuleFileNameExA(hProc, mods[j], me32.szExePath,
|
||||
MAX_PATH - 1))
|
||||
continue;
|
||||
|
||||
if (!GetModuleInformation(hProc, mods[j], &mi,
|
||||
sizeof(mi)))
|
||||
continue;
|
||||
|
||||
me32.hModule = mods[j];
|
||||
me32.th32ProcessID = procs[i];
|
||||
me32.modBaseAddr = mi.lpBaseOfDll;
|
||||
me32.modBaseSize = mi.SizeOfImage;
|
||||
if (callback(ps, me32, data, info))
|
||||
break;
|
||||
}
|
||||
CloseHandle(hProc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kill_process(DWORD pid)
|
||||
{
|
||||
HANDLE hProc;
|
||||
if (GetCurrentProcessId() == pid) {
|
||||
logg(LOGG_WARNING, "Don't want to kill myself\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((hProc = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, pid))) {
|
||||
TerminateProcess(hProc, 0);
|
||||
if (WaitForSingleObject(hProc, TIMEOUT_MODULE) != WAIT_OBJECT_0)
|
||||
logg(LOGG_WARNING, "Unable to unload process from memory\n");
|
||||
CloseHandle(hProc);
|
||||
} else
|
||||
logg(LOGG_WARNING, "OpenProcess() failed %lu\n", GetLastError());
|
||||
return 1; /* Skip to next process anyway */
|
||||
}
|
||||
|
||||
/* Not so safe ;) */
|
||||
int unload_module(DWORD pid, HANDLE hModule)
|
||||
{
|
||||
DWORD rc = 1;
|
||||
HANDLE ht;
|
||||
HANDLE hProc;
|
||||
|
||||
if (GetCurrentProcessId() == pid) {
|
||||
logg(LOGG_WARNING, "Don't want to unload modules from myself\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hProc = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
|
||||
PROCESS_VM_WRITE | PROCESS_VM_READ,
|
||||
FALSE, pid);
|
||||
|
||||
if (!hProc) {
|
||||
logg(LOGG_WARNING, "OpenProcess() failed %lu\n", GetLastError());
|
||||
return 1; /* Skip to next process */
|
||||
}
|
||||
|
||||
if ((ht = CreateRemoteThread(
|
||||
hProc, 0, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, hModule, 0,
|
||||
&rc))) {
|
||||
if (WaitForSingleObject(ht, TIMEOUT_MODULE) == WAIT_TIMEOUT) {
|
||||
CloseHandle(ht);
|
||||
CloseHandle(hProc);
|
||||
logg(LOGG_INFO, "The module may trying to trick us, killing the process, please "
|
||||
"rescan\n");
|
||||
return kill_process(pid);
|
||||
}
|
||||
CloseHandle(ht);
|
||||
rc = 0; /* Continue scanning this process */
|
||||
} else {
|
||||
DWORD res = GetLastError();
|
||||
if (res == ERROR_CALL_NOT_IMPLEMENTED) {
|
||||
logg(LOGG_WARNING, "Module unloading is not supported on this OS\n");
|
||||
rc = -1; /* Don't complain about removing/moving the file */
|
||||
} else {
|
||||
logg(LOGG_ERROR, "CreateRemoteThread() failed %lu\n", res);
|
||||
rc = 1; /* Skip to next process */
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(hProc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define FILLBYTES(dst) \
|
||||
if (IsBadReadPtr(seek, sizeof(dst))) { \
|
||||
logg(LOGG_ERROR, "ScanMem Align: Bad pointer!!!\n"); \
|
||||
return 1; \
|
||||
} \
|
||||
memcpy(&dst, seek, sizeof(dst))
|
||||
|
||||
/* PE Realignment - FIXME: a lot of code is copy/paste from exeScanner.c */
|
||||
int align_pe(unsigned char *buffer, size_t size)
|
||||
{
|
||||
int i = 0;
|
||||
uint16_t e_mz;
|
||||
uint32_t e_lfanew, e_magic;
|
||||
unsigned char *seek = buffer;
|
||||
PIMAGE_FILE_HEADER pehdr;
|
||||
PIMAGE_OPTIONAL_HEADER32 opthdr;
|
||||
PIMAGE_SECTION_HEADER sechdr;
|
||||
|
||||
FILLBYTES(e_mz);
|
||||
if (e_mz != IMAGE_DOS_SIGNATURE) {
|
||||
/* cli_dbgmsg("ScanMem Align: DOS Signature not found\n"); */
|
||||
return 0;
|
||||
}
|
||||
|
||||
seek += 0x3c;
|
||||
|
||||
FILLBYTES(e_lfanew);
|
||||
if (!e_lfanew) {
|
||||
/* cli_dbgmsg("ScanMem Align: Invalid PE offset\n"); */
|
||||
return 0;
|
||||
}
|
||||
seek = buffer + e_lfanew;
|
||||
|
||||
/* PE Signature 'PE' */
|
||||
FILLBYTES(e_magic);
|
||||
if (e_magic != IMAGE_NT_SIGNATURE) {
|
||||
/* cli_dbgmsg("ScanMem Align: PE Signature not found\n"); */
|
||||
return 0;
|
||||
}
|
||||
seek += sizeof(e_magic);
|
||||
|
||||
if (IsBadReadPtr(seek, sizeof(IMAGE_FILE_HEADER)))
|
||||
return 0;
|
||||
pehdr = (PIMAGE_FILE_HEADER)seek;
|
||||
seek += sizeof(IMAGE_FILE_HEADER);
|
||||
|
||||
if (IsBadReadPtr(seek, sizeof(IMAGE_OPTIONAL_HEADER32)))
|
||||
return 0;
|
||||
opthdr = (PIMAGE_OPTIONAL_HEADER32)seek;
|
||||
seek += sizeof(IMAGE_OPTIONAL_HEADER32);
|
||||
|
||||
/* Invalid sections number */
|
||||
if ((pehdr->NumberOfSections < 1) || (pehdr->NumberOfSections > 32)) {
|
||||
/* cli_dbgmsg("ScanMem Align: Invalid sections number\n"); */
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < pehdr->NumberOfSections; i++) {
|
||||
if (IsBadWritePtr(seek, sizeof(IMAGE_SECTION_HEADER)))
|
||||
return 0;
|
||||
sechdr = (PIMAGE_SECTION_HEADER)seek;
|
||||
seek += sizeof(IMAGE_SECTION_HEADER);
|
||||
sechdr->PointerToRawData = sechdr->VirtualAddress;
|
||||
sechdr->SizeOfRawData = sechdr->Misc.VirtualSize;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dump_pe(const char *filename, PROCESSENTRY32 ProcStruct,
|
||||
MODULEENTRY32 me32)
|
||||
{
|
||||
#ifdef _WIN64 /* MinGW has a broken header for ReadProcessMemory() */
|
||||
size_t bytesread = 0;
|
||||
#else
|
||||
DWORD bytesread = 0;
|
||||
#endif
|
||||
DWORD byteswrite = 0;
|
||||
int ret = -1;
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE, hProc = NULL;
|
||||
unsigned char *buffer = NULL;
|
||||
|
||||
if (!(hProc = OpenProcess(PROCESS_VM_READ, FALSE, ProcStruct.th32ProcessID)))
|
||||
return -1;
|
||||
|
||||
buffer = malloc((size_t)me32.modBaseSize);
|
||||
if (!ReadProcessMemory(hProc, me32.modBaseAddr, buffer,
|
||||
(size_t)me32.modBaseSize, &bytesread)) {
|
||||
free(buffer);
|
||||
CloseHandle(hProc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
CloseHandle(hProc);
|
||||
|
||||
/* PE Realignment */
|
||||
align_pe(buffer, me32.modBaseSize);
|
||||
|
||||
hFile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
logg(LOGG_INFO, "Error creating %s\n", filename);
|
||||
free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (WriteFile(hFile, buffer, (DWORD)bytesread, &byteswrite, NULL))
|
||||
ret = _open_osfhandle((intptr_t)hFile, O_RDONLY | O_BINARY);
|
||||
free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int scanfile(const char *filename, scanmem_data *scan_data, struct mem_info *info)
|
||||
{
|
||||
int fd;
|
||||
int scantype;
|
||||
int ret = CL_CLEAN;
|
||||
const char *virname = NULL;
|
||||
|
||||
logg(LOGG_DEBUG, "Scanning %s\n", filename);
|
||||
|
||||
if ((fd = safe_open(filename, O_RDONLY | O_BINARY)) == -1) {
|
||||
logg(LOGG_WARNING, "Can't open file %s, %s\n", filename, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (info->d) { // clamdscan
|
||||
if (optget(info->opts, "stream")->enabled)
|
||||
scantype = STREAM;
|
||||
else if (optget(info->opts, "multiscan")->enabled)
|
||||
scantype = MULTI;
|
||||
else if (optget(info->opts, "allmatch")->enabled)
|
||||
scantype = ALLMATCH;
|
||||
else
|
||||
scantype = CONT;
|
||||
|
||||
if ((sock = dconnect(clamdopts)) < 0) {
|
||||
info->errors++;
|
||||
return -1;
|
||||
}
|
||||
if (dsresult(sock, scantype, filename, NULL, &info->errors, clamdopts) > 0) {
|
||||
info->ifiles++;
|
||||
ret = CL_VIRUS;
|
||||
}
|
||||
} else { // clamscan
|
||||
ret = cl_scandesc(fd, filename, &virname, &info->blocks, info->engine, info->options);
|
||||
if (ret == CL_VIRUS) {
|
||||
logg(LOGG_INFO, "%s: %s FOUND\n", filename, virname);
|
||||
info->ifiles++;
|
||||
} else if (scan_data->printclean) {
|
||||
logg(LOGG_INFO, "%s: OK \n", filename);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int scanmem_cb(PROCESSENTRY32 ProcStruct, MODULEENTRY32 me32, void *data, struct mem_info *info)
|
||||
{
|
||||
scanmem_data *scan_data = data;
|
||||
int rc = 0;
|
||||
int isprocess = 0;
|
||||
char modulename[MAX_PATH] = "";
|
||||
char expandmodule[MAX_PATH] = "";
|
||||
|
||||
if (!scan_data)
|
||||
return 0;
|
||||
scan_data->res = CL_CLEAN;
|
||||
|
||||
modulename[0] = 0;
|
||||
/* Special case, btw why I get \SystemRoot\ in process szExePath?
|
||||
There are also other cases? */
|
||||
if ((strlen(me32.szExePath) > 12) &&
|
||||
!strncmp(me32.szExePath, "\\SystemRoot\\", 12)) {
|
||||
expandmodule[0] = 0;
|
||||
strncat(expandmodule, me32.szExePath, MAX_PATH - 1 - strlen(expandmodule));
|
||||
expandmodule[MAX_PATH - 1] = 0;
|
||||
snprintf(expandmodule, MAX_PATH - 1, "%%SystemRoot%%\\%s",
|
||||
&me32.szExePath[12]);
|
||||
expandmodule[MAX_PATH - 1] = 0;
|
||||
ExpandEnvironmentStrings(expandmodule, modulename, MAX_PATH - 1);
|
||||
modulename[MAX_PATH - 1] = 0;
|
||||
}
|
||||
|
||||
if (!modulename[0]) {
|
||||
strncpy(modulename, me32.szExePath, MAX_PATH - 1);
|
||||
modulename[MAX_PATH - 1] = 0;
|
||||
}
|
||||
|
||||
scan_data->res = lookup_cache(&scan_data->files, modulename);
|
||||
isprocess = !_stricmp(ProcStruct.szExeFile, modulename) ||
|
||||
!_stricmp(ProcStruct.szExeFile, me32.szModule);
|
||||
|
||||
if (scan_data->res == -1) {
|
||||
if (isprocess)
|
||||
scan_data->processes++;
|
||||
else
|
||||
scan_data->modules++;
|
||||
|
||||
info->files++;
|
||||
|
||||
/* check for module exclusion */
|
||||
scan_data->res = CL_CLEAN;
|
||||
if (!(scan_data->exclude && chkpath(modulename, clamdopts)))
|
||||
scan_data->res = scanfile(modulename, scan_data, info);
|
||||
|
||||
if ((scan_data->res != CL_VIRUS) && is_packed(modulename)) {
|
||||
char *dumped = cli_gentemp(NULL);
|
||||
int fd = -1;
|
||||
if ((fd = dump_pe(dumped, ProcStruct, me32)) > 0) {
|
||||
close(fd);
|
||||
scan_data->res = scanfile(dumped, scan_data, info);
|
||||
DeleteFile(dumped);
|
||||
}
|
||||
free(dumped);
|
||||
}
|
||||
insert_cache(&scan_data->files, modulename, scan_data->res);
|
||||
}
|
||||
|
||||
if (scan_data->res == CL_VIRUS) {
|
||||
if (isprocess && scan_data->kill) {
|
||||
logg(LOGG_INFO, "Unloading program %s from memory\n", modulename);
|
||||
rc = kill_process(ProcStruct.th32ProcessID);
|
||||
} else if (scan_data->unload) {
|
||||
logg(LOGG_INFO, "Unloading module %s from %s\n", me32.szModule, modulename);
|
||||
if ((rc = unload_module(ProcStruct.th32ProcessID, me32.hModule)) == -1)
|
||||
/* CreateProcessThread() is not implemented */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (action)
|
||||
action(modulename);
|
||||
return rc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int scanmem(struct mem_info *info)
|
||||
{
|
||||
scanmem_data data;
|
||||
data.files = NULL;
|
||||
data.printclean = 1;
|
||||
data.kill = 0;
|
||||
data.unload = 0;
|
||||
data.exclude = 0;
|
||||
data.res = CL_CLEAN;
|
||||
data.processes = 0;
|
||||
data.modules = 0;
|
||||
|
||||
HMODULE psapi_ok = LoadLibrary("psapi.dll");
|
||||
HMODULE k32_ok = LoadLibrary("kernel32.dll");
|
||||
|
||||
if (!(psapi_ok || k32_ok)) {
|
||||
logg(LOGG_INFO, " *** Memory Scanning is not supported on this OS ***\n\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (optget(info->opts, "infected")->enabled)
|
||||
data.printclean = 0;
|
||||
if (optget(info->opts, "kill")->enabled)
|
||||
data.kill = 1;
|
||||
if (optget(info->opts, "unload")->enabled)
|
||||
data.unload = 1;
|
||||
if (optget(info->opts, "exclude")->enabled)
|
||||
data.exclude = 1;
|
||||
|
||||
if (info->d) {
|
||||
if ((sock = dconnect(clamdopts)) < 0) {
|
||||
info->errors++;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
logg(LOGG_INFO, " *** Scanning Programs in Computer Memory ***\n");
|
||||
|
||||
if (!EnablePrivilege(SE_DEBUG_NAME, SE_PRIVILEGE_ENABLED))
|
||||
logg(LOGG_INFO, "---Please login as an Administrator to scan System processes loaded "
|
||||
"in computer memory---\n");
|
||||
|
||||
if (k32_ok)
|
||||
walkmodules_th(scanmem_cb, (void *)&data, info);
|
||||
else
|
||||
walkmodules_psapi(scanmem_cb, (void *)&data, info);
|
||||
free_cache(&data.files);
|
||||
|
||||
logg(LOGG_INFO, "\n *** Scanned %lu processes - %lu modules ***\n", data.processes,
|
||||
data.modules);
|
||||
logg(LOGG_INFO, " *** Computer Memory Scan Completed ***\n\n");
|
||||
return data.res;
|
||||
}
|
||||
68
clamav/common/scanmem.h
Normal file
68
clamav/common/scanmem.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2005-2010 Gianluigi Tiesi <sherpya@netfarm.it>
|
||||
*
|
||||
* Authors: Gianluigi Tiesi
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __SCANMEM_H
|
||||
#define __SCANMEM_H
|
||||
|
||||
#ifndef TH32CS_SNAPMODULE32
|
||||
#define TH32CS_SNAPMODULE32 0x00000010
|
||||
#endif
|
||||
|
||||
#define TIMEOUT_MODULE 30000
|
||||
|
||||
int scanmem(struct mem_info *info);
|
||||
|
||||
/* cache helpers */
|
||||
typedef struct _filelist_t {
|
||||
char filename[MAX_PATH];
|
||||
int res;
|
||||
struct _filelist_t *next;
|
||||
} filelist_t;
|
||||
|
||||
/* Callback */
|
||||
typedef struct _cb_data_t {
|
||||
const char *filename;
|
||||
size_t size, count;
|
||||
int oldvalue;
|
||||
int fd;
|
||||
} cb_data_t;
|
||||
|
||||
typedef struct _scanmem_data_t {
|
||||
filelist_t *files;
|
||||
int printclean, kill, unload, exclude;
|
||||
int res;
|
||||
uint32_t processes, modules;
|
||||
|
||||
} scanmem_data;
|
||||
|
||||
struct mem_info {
|
||||
unsigned int d; /*1 = clamdscan, 0 = clamscan */
|
||||
unsigned int files; /* number of scanned files */
|
||||
unsigned int ifiles; /* number of infected files */
|
||||
unsigned long int blocks; /* number of *scanned* 16kb blocks */
|
||||
unsigned int errors;
|
||||
|
||||
struct cl_engine *engine;
|
||||
const struct optstruct *opts;
|
||||
struct cl_scan_options *options;
|
||||
};
|
||||
|
||||
#endif
|
||||
228
clamav/common/service.c
Normal file
228
clamav/common/service.c
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2008-2010 Gianluigi Tiesi <sherpya@netfarm.it>
|
||||
*
|
||||
* Authors: Gianluigi Tiesi
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <platform.h>
|
||||
#include <winsvc.h>
|
||||
|
||||
#include "service.h"
|
||||
#include "output.h"
|
||||
|
||||
static SERVICE_STATUS svc;
|
||||
static SERVICE_STATUS_HANDLE svc_handle;
|
||||
static SERVICE_TABLE_ENTRYA DT[] = {{"Service", ServiceMain}, {NULL, NULL}};
|
||||
|
||||
static HANDLE evStart;
|
||||
static HANDLE DispatcherThread;
|
||||
static int checkpoint_every = 5000;
|
||||
|
||||
int svc_uninstall(const char *name, int verbose)
|
||||
{
|
||||
SC_HANDLE sm, svc;
|
||||
int ret = 1;
|
||||
|
||||
if (!(sm = OpenSCManagerA(NULL, NULL, DELETE))) {
|
||||
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
|
||||
fprintf(stderr, "Windows Services are not supported on this Platform\n");
|
||||
else
|
||||
fprintf(stderr, "Unable to Open SCManager (%d)\n", GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((svc = OpenServiceA(sm, name, DELETE))) {
|
||||
if (DeleteService(svc)) {
|
||||
if (verbose) printf("Service %s successfully removed\n", name);
|
||||
} else {
|
||||
fprintf(stderr, "Unable to Open Service %s (%d)\n", name, GetLastError());
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) {
|
||||
if (verbose) printf("Service %s does not exist\n", name);
|
||||
} else {
|
||||
fprintf(stderr, "Unable to Open Service %s (%d)\n", name, GetLastError());
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (svc) CloseServiceHandle(svc);
|
||||
CloseServiceHandle(sm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int svc_install(const char *name, const char *dname, const char *desc)
|
||||
{
|
||||
SC_HANDLE sm, svc;
|
||||
char modulepath[MAX_PATH];
|
||||
char binpath[MAX_PATH];
|
||||
SERVICE_DESCRIPTIONA sdesc = {(char *)desc};
|
||||
|
||||
if (!GetModuleFileName(NULL, modulepath, MAX_PATH - 1)) {
|
||||
fprintf(stderr, "Unable to get the executable name (%d)\n", GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!svc_uninstall(name, 0)) return 0;
|
||||
|
||||
if (!(sm = OpenSCManagerA(NULL, NULL, SC_MANAGER_CREATE_SERVICE | DELETE))) {
|
||||
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
|
||||
fprintf(stderr, "Windows Services are not supported on this Platform\n");
|
||||
else
|
||||
fprintf(stderr, "Unable to Open SCManager (%d)\n", GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strchr(modulepath, ' '))
|
||||
snprintf(binpath, MAX_PATH - 1, "\"%s\" --daemon --service-mode", modulepath);
|
||||
else
|
||||
snprintf(binpath, MAX_PATH - 1, "%s --daemon --service-mode", modulepath);
|
||||
|
||||
svc = CreateServiceA(sm, name, dname, SERVICE_CHANGE_CONFIG,
|
||||
SERVICE_WIN32_OWN_PROCESS,
|
||||
SERVICE_DEMAND_START,
|
||||
SERVICE_ERROR_NORMAL,
|
||||
binpath,
|
||||
NULL, /* Load group order */
|
||||
NULL, /* Tag Id */
|
||||
NULL, /* Dependencies */
|
||||
NULL, /* User -> Local System */
|
||||
"");
|
||||
|
||||
if (!svc) {
|
||||
fprintf(stderr, "Unable to Create Service %s (%d)\n", name, GetLastError());
|
||||
CloseServiceHandle(sm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ChangeServiceConfig2A() */
|
||||
if (!ChangeServiceConfig2A(svc, SERVICE_CONFIG_DESCRIPTION, &sdesc))
|
||||
fprintf(stderr, "Unable to set description for Service %s (%d)\n", name, GetLastError());
|
||||
|
||||
CloseServiceHandle(svc);
|
||||
CloseServiceHandle(sm);
|
||||
|
||||
printf("Service %s successfully created.\n", name);
|
||||
printf("Use 'net start %s' and 'net stop %s' to start/stop the service.\n", name, name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void svc_getcpvalue(const char *name)
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD dwType;
|
||||
DWORD value, vlen = sizeof(DWORD);
|
||||
char subkey[MAX_PATH];
|
||||
|
||||
snprintf(subkey, MAX_PATH - 1, "SYSTEM\\CurrentControlSet\\Services\\%s", name);
|
||||
|
||||
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subkey, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
if ((RegQueryValueExA(hKey, "Checkpoint", NULL, &dwType, (LPBYTE)&value, &vlen) == ERROR_SUCCESS) &&
|
||||
(vlen == sizeof(DWORD) && (dwType == REG_DWORD)))
|
||||
checkpoint_every = value;
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
void svc_register(const char *name)
|
||||
{
|
||||
DWORD tid;
|
||||
DT->lpServiceName = (char *)name;
|
||||
svc_getcpvalue(name);
|
||||
|
||||
evStart = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
DispatcherThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartServiceCtrlDispatcherA, (LPVOID)DT, 0, &tid);
|
||||
}
|
||||
|
||||
void svc_ready(void)
|
||||
{
|
||||
WaitForSingleObject(evStart, INFINITE);
|
||||
|
||||
svc.dwCurrentState = SERVICE_RUNNING;
|
||||
svc.dwControlsAccepted |= SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
||||
svc.dwCheckPoint = 0;
|
||||
|
||||
if (!SetServiceStatus(svc_handle, &svc)) {
|
||||
logg(LOGG_INFO, "[service] SetServiceStatus() failed with %d\n", GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int svc_checkpoint(const char *type, const char *name, unsigned int custom, void *context)
|
||||
{
|
||||
if (svc.dwCurrentState == SERVICE_START_PENDING) {
|
||||
svc.dwCheckPoint++;
|
||||
if ((svc.dwCheckPoint % checkpoint_every) == 0)
|
||||
SetServiceStatus(svc_handle, &svc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WINAPI ServiceCtrlHandler(DWORD code)
|
||||
{
|
||||
switch (code) {
|
||||
case SERVICE_CONTROL_STOP:
|
||||
case SERVICE_CONTROL_SHUTDOWN:
|
||||
svc.dwCurrentState = SERVICE_STOPPED;
|
||||
svc.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
|
||||
SetServiceStatus(svc_handle, &svc);
|
||||
return;
|
||||
case SERVICE_CONTROL_INTERROGATE:
|
||||
break;
|
||||
}
|
||||
|
||||
SetServiceStatus(svc_handle, &svc);
|
||||
}
|
||||
|
||||
BOOL WINAPI cw_stop_ctrl_handler(DWORD CtrlType)
|
||||
{
|
||||
if (CtrlType == CTRL_C_EVENT) {
|
||||
SetConsoleCtrlHandler(cw_stop_ctrl_handler, FALSE);
|
||||
fprintf(stderr, "Control+C pressed, aborting...\n");
|
||||
exit(0);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv)
|
||||
{
|
||||
svc.dwServiceType = SERVICE_WIN32;
|
||||
svc.dwCurrentState = SERVICE_START_PENDING;
|
||||
svc.dwControlsAccepted = 0;
|
||||
svc.dwWin32ExitCode = NO_ERROR;
|
||||
svc.dwServiceSpecificExitCode = 0;
|
||||
svc.dwCheckPoint = 0;
|
||||
svc.dwWaitHint = 0;
|
||||
|
||||
if (!(svc_handle = RegisterServiceCtrlHandlerA(DT->lpServiceName, ServiceCtrlHandler))) {
|
||||
logg(LOGG_INFO, "[service] RegisterServiceCtrlHandler() failed with %d\n", GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!SetServiceStatus(svc_handle, &svc)) {
|
||||
logg(LOGG_INFO, "[service] SetServiceStatus() failed with %d\n", GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SetEvent(evStart);
|
||||
WaitForSingleObject(DispatcherThread, INFINITE);
|
||||
cw_stop_ctrl_handler(CTRL_C_EVENT);
|
||||
}
|
||||
38
clamav/common/service.h
Normal file
38
clamav/common/service.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2008-2010 Gianluigi Tiesi <sherpya@netfarm.it>
|
||||
*
|
||||
* Authors: Gianluigi Tiesi
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __SERVICE_H
|
||||
#define __SERVICE_H
|
||||
|
||||
#include <platform.h>
|
||||
#include <winsvc.h>
|
||||
|
||||
int svc_uninstall(const char *name, int verbose);
|
||||
int svc_install(const char *name, const char *dname, const char *desc);
|
||||
static void svc_getcpvalue(const char *name);
|
||||
void svc_register(const char *name);
|
||||
void svc_ready(void);
|
||||
int svc_checkpoint(const char *type, const char *name, unsigned int custom, void *context);
|
||||
void WINAPI ServiceCtrlHandler(DWORD code);
|
||||
BOOL WINAPI cw_stop_ctrl_handler(DWORD CtrlType);
|
||||
void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv);
|
||||
|
||||
#endif
|
||||
120
clamav/common/tar.c
Normal file
120
clamav/common/tar.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* A minimalistic tar archiver for sigtool and freshclam.
|
||||
*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2007-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Author: Tomasz Kojm <tkojm@clamav.net>
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <zlib.h>
|
||||
|
||||
// libclamav
|
||||
#include "clamav.h"
|
||||
|
||||
#include "tar.h"
|
||||
|
||||
struct tar_header {
|
||||
char name[100]; /* File name */
|
||||
char mode[8]; /* File mode */
|
||||
char uid[8]; /* UID */
|
||||
char gid[8]; /* GID */
|
||||
char size[12]; /* File size (octal) */
|
||||
char mtime[12]; /* Last modification */
|
||||
char chksum[8]; /* Header checksum */
|
||||
char type[1]; /* File type */
|
||||
char lname[100]; /* Linked file name */
|
||||
char pad[255];
|
||||
};
|
||||
#define TARBLK 512
|
||||
|
||||
int tar_addfile(int fd, gzFile gzs, const char *file)
|
||||
{
|
||||
int s, bytes;
|
||||
struct tar_header hdr;
|
||||
STATBUF sb;
|
||||
unsigned char buff[FILEBUFF], *pt;
|
||||
unsigned int i, chksum = 0;
|
||||
|
||||
if ((s = open(file, O_RDONLY | O_BINARY)) == -1)
|
||||
return -1;
|
||||
|
||||
if (FSTAT(s, &sb) == -1) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&hdr, 0, TARBLK);
|
||||
strncpy(hdr.name, file, 100);
|
||||
hdr.name[99] = '\0';
|
||||
snprintf(hdr.size, 12, "%o", (unsigned int)sb.st_size);
|
||||
pt = (unsigned char *)&hdr;
|
||||
for (i = 0; i < TARBLK; i++)
|
||||
chksum += *pt++;
|
||||
snprintf(hdr.chksum, 8, "%06o", chksum + 256);
|
||||
|
||||
if (gzs) {
|
||||
if (!gzwrite(gzs, &hdr, TARBLK)) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (write(fd, &hdr, TARBLK) != TARBLK) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
while ((bytes = read(s, buff, FILEBUFF)) > 0) {
|
||||
if (gzs) {
|
||||
if (!gzwrite(gzs, buff, bytes)) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (write(fd, buff, bytes) != bytes) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
close(s);
|
||||
|
||||
if (sb.st_size % TARBLK) {
|
||||
memset(&hdr, 0, TARBLK);
|
||||
if (gzs) {
|
||||
if (!gzwrite(gzs, &hdr, TARBLK - (sb.st_size % TARBLK)))
|
||||
return -1;
|
||||
} else {
|
||||
if (write(fd, &hdr, TARBLK - (sb.st_size % TARBLK)) == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
31
clamav/common/tar.h
Normal file
31
clamav/common/tar.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* A minimalistic tar archiver for sigtool and freshclam.
|
||||
*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2007-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Author: Tomasz Kojm <tkojm@clamav.net>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __TAR_H
|
||||
#define __TAR_H
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
int tar_addfile(int fd, gzFile gzs, const char *file);
|
||||
|
||||
#endif
|
||||
172
clamav/common/win/cert_util_win.c
Normal file
172
clamav/common/win/cert_util_win.c
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* OpenSSL certificate verification for Windows.
|
||||
*
|
||||
* Copyright (C) 2019-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Authors: Micah Snyder
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <Windows.h>
|
||||
#include <wincrypt.h>
|
||||
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "output.h"
|
||||
|
||||
#include "cert_util.h"
|
||||
#include "cert_util_internal.h"
|
||||
|
||||
cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
|
||||
{
|
||||
uint32_t numCertificatesFound = 0;
|
||||
DWORD lastError;
|
||||
|
||||
HCERTSTORE hStore = NULL;
|
||||
PCCERT_CONTEXT pWinCertContext = NULL;
|
||||
X509 *x509 = NULL;
|
||||
|
||||
cl_error_t ret = CL_EOPEN;
|
||||
int pt_err;
|
||||
|
||||
cert_store_t *store = NULL;
|
||||
bool locked = false;
|
||||
|
||||
hStore = CertOpenSystemStoreA(NULL, "ROOT");
|
||||
if (NULL == hStore) {
|
||||
mprintf(LOGG_ERROR, "Failed to open system certificate store.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
store = cert_store_get_int();
|
||||
if (!store) {
|
||||
mprintf(LOGG_ERROR, "Failed to retrieve cert store\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
pt_err = pthread_mutex_lock(&store->mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex lock failed\n");
|
||||
}
|
||||
locked = true;
|
||||
|
||||
if (store->loaded) {
|
||||
mprintf(LOGG_INFO, "Cert store already loaded\n");
|
||||
ret = CL_SUCCESS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
store->system_certs.count = 0;
|
||||
store->system_certs.certificates = NULL;
|
||||
|
||||
while (NULL != (pWinCertContext = CertEnumCertificatesInStore(hStore, pWinCertContext))) {
|
||||
int addCertResult = 0;
|
||||
const unsigned char *encoded_cert = pWinCertContext->pbCertEncoded;
|
||||
|
||||
x509 = NULL;
|
||||
x509 = d2i_X509(NULL, &encoded_cert, pWinCertContext->cbCertEncoded);
|
||||
if (NULL == x509) {
|
||||
mprintf(LOGG_ERROR, "Failed to convert system certificate to x509.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
store->system_certs.certificates = realloc(
|
||||
store->system_certs.certificates,
|
||||
(numCertificatesFound + 1) * sizeof(*store->system_certs.certificates));
|
||||
if (store->system_certs.certificates == NULL) {
|
||||
mprintf(LOGG_ERROR, "Failed to reserve memory for system cert list\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
store->system_certs.certificates[store->system_certs.count++] = x509;
|
||||
|
||||
if (mprintf_verbose) {
|
||||
char *issuer = NULL;
|
||||
size_t issuerLen = 0;
|
||||
issuerLen = CertGetNameStringA(pWinCertContext, CERT_NAME_FRIENDLY_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
|
||||
|
||||
issuer = malloc(issuerLen);
|
||||
if (NULL == issuer) {
|
||||
mprintf(LOGG_ERROR, "Failed to allocate memory for certificate name.\n");
|
||||
ret = CURLE_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (0 == CertGetNameStringA(pWinCertContext, CERT_NAME_FRIENDLY_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, issuer, issuerLen)) {
|
||||
mprintf(LOGG_ERROR, "Failed to get friendly display name for certificate.\n");
|
||||
} else {
|
||||
mprintf(LOGG_INFO, "Certificate loaded from Windows certificate store: %s\n", issuer);
|
||||
}
|
||||
|
||||
free(issuer);
|
||||
}
|
||||
|
||||
numCertificatesFound++;
|
||||
}
|
||||
|
||||
lastError = GetLastError();
|
||||
switch (lastError) {
|
||||
case E_INVALIDARG:
|
||||
mprintf(LOGG_ERROR, "The handle in the hCertStore parameter is not the same as that in the certificate context pointed to by pPrevCertContext.\n");
|
||||
break;
|
||||
case CRYPT_E_NOT_FOUND:
|
||||
case ERROR_NO_MORE_FILES:
|
||||
if (0 == numCertificatesFound) {
|
||||
mprintf(LOGG_ERROR, "No certificates were found.\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mprintf(LOGG_ERROR, "Unexpected error code from CertEnumCertificatesInStore()\n");
|
||||
}
|
||||
|
||||
if (trusted_certs && trusted_cert_count > 0) {
|
||||
if (cert_store_set_trusted_int(trusted_certs, trusted_cert_count) == 0) {
|
||||
mprintf(LOGG_DEBUG, "Trusted certificates loaded: %zu\n",
|
||||
store->trusted_certs.count);
|
||||
} else {
|
||||
mprintf(LOGG_WARNING, "Continuing without trusted certificates\n");
|
||||
/* proceed as if we succeeded using only certificates from the
|
||||
* system */
|
||||
}
|
||||
}
|
||||
|
||||
store->loaded = true;
|
||||
ret = CL_SUCCESS;
|
||||
|
||||
done:
|
||||
if (locked) {
|
||||
pt_err = pthread_mutex_unlock(&store->mutex);
|
||||
if (pt_err) {
|
||||
errno = pt_err;
|
||||
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
|
||||
}
|
||||
locked = false;
|
||||
}
|
||||
|
||||
if (NULL != pWinCertContext) {
|
||||
CertFreeCertificateContext(pWinCertContext);
|
||||
}
|
||||
if (NULL != hStore) {
|
||||
CertCloseStore(hStore, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
64
clamav/freshclam/CMakeLists.txt
Normal file
64
clamav/freshclam/CMakeLists.txt
Normal file
@@ -0,0 +1,64 @@
|
||||
# Copyright (C) 2020-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
|
||||
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
|
||||
|
||||
# Windows compatibility headers
|
||||
include_directories(${CMAKE_SOURCE_DIR}/win32/compat)
|
||||
endif()
|
||||
|
||||
# The freshclam executable.
|
||||
add_executable( freshclam-bin )
|
||||
target_sources( freshclam-bin
|
||||
PRIVATE
|
||||
freshclam.c
|
||||
execute.c
|
||||
execute.h
|
||||
notify.c
|
||||
notify.h )
|
||||
if(WIN32)
|
||||
target_sources( freshclam-bin
|
||||
PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/win32/res/freshclam.rc
|
||||
${CMAKE_SOURCE_DIR}/win32/res/clam.manifest )
|
||||
endif()
|
||||
set_target_properties( freshclam-bin PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}" )
|
||||
|
||||
if (APPLE AND CLAMAV_SIGN_FILE)
|
||||
set_target_properties( freshclam-bin PROPERTIES
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ${CODE_SIGN_IDENTITY}
|
||||
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${DEVELOPMENT_TEAM_ID}
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(freshclam-bin
|
||||
PRIVATE
|
||||
ClamAV::libfreshclam
|
||||
ClamAV::libclamav
|
||||
ClamAV::common )
|
||||
if(WIN32)
|
||||
install(TARGETS freshclam-bin DESTINATION . COMPONENT programs)
|
||||
install(FILES $<TARGET_PDB_FILE:freshclam-bin> DESTINATION . OPTIONAL COMPONENT programs)
|
||||
else()
|
||||
install(TARGETS freshclam-bin DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT programs)
|
||||
endif()
|
||||
|
||||
# Install an empty database directory
|
||||
INSTALL(CODE "FILE(MAKE_DIRECTORY \${ENV}\${CMAKE_INSTALL_PREFIX}/\${DATABASE_DIRECTORY})" COMPONENT programs)
|
||||
|
||||
# Now we rename freshclam-bin executable to freshclam using target properties
|
||||
set_target_properties( freshclam-bin
|
||||
PROPERTIES OUTPUT_NAME freshclam )
|
||||
|
||||
if(SYSTEMD_FOUND)
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/clamav-freshclam.service.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/clamav-freshclam.service @ONLY)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/clamav-freshclam.service
|
||||
DESTINATION ${SYSTEMD_UNIT_DIR}
|
||||
COMPONENT programs)
|
||||
endif()
|
||||
21
clamav/freshclam/Doxyfile
Normal file
21
clamav/freshclam/Doxyfile
Normal file
@@ -0,0 +1,21 @@
|
||||
PROJECT_NAME = ClamAV - FreshClam
|
||||
OUTPUT_DIRECTORY = ../docs/freshclam
|
||||
WARNINGS = YES
|
||||
FILE_PATTERNS = *.c *.h
|
||||
PERL_PATH = /usr/bin/perl
|
||||
SEARCHENGINE = YES
|
||||
|
||||
GENERATE_LATEX=NO
|
||||
OPTIMIZE_OUTPUT_FOR_C=YES
|
||||
HAVE_DOT=YES
|
||||
CALL_GRAPH=YES
|
||||
CALLER_GRAPH=YES
|
||||
JAVADOC_AUTOBRIEF=YES
|
||||
GENERATE_MAN=NO
|
||||
EXAMPLE_PATH=examples
|
||||
|
||||
DOT_CLEANUP=NO
|
||||
MAX_DOT_GRAPH_DEPTH=3
|
||||
|
||||
EXTRACT_ALL=YES
|
||||
INPUT = .
|
||||
13
clamav/freshclam/clamav-freshclam.service.in
Normal file
13
clamav/freshclam/clamav-freshclam.service.in
Normal file
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=ClamAV virus database updater
|
||||
Documentation=man:freshclam(1) man:freshclam.conf(5) https://docs.clamav.net/
|
||||
# If user wants it run from cron, don't start the daemon.
|
||||
ConditionPathExists=!/etc/cron.d/clamav-freshclam
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@prefix@/bin/freshclam -d --foreground=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
79
clamav/freshclam/execute.c
Normal file
79
clamav/freshclam/execute.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* By Per Jessen <per@computer.org> with changes by the ClamAV team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "clamav-config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "output.h"
|
||||
#include "optparser.h"
|
||||
#include "execute.h"
|
||||
|
||||
#define MAX_CHILDREN 5
|
||||
|
||||
int g_active_children;
|
||||
|
||||
void execute(const char *type, const char *text, int bDaemonized)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!bDaemonized) {
|
||||
if (sscanf(text, "EXIT_%d", &ret) == 1) {
|
||||
logg(LOGG_DEBUG, "%s: EXIT_%d\n", type, ret);
|
||||
exit(ret);
|
||||
}
|
||||
if (system(text) == -1)
|
||||
logg(LOGG_INFO, "%s: system(%s) failed\n", type, text);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (system(text) == -1) {
|
||||
logg(LOGG_WARNING, "%s: couldn't execute \"%s\".\n", type, text);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (g_active_children < MAX_CHILDREN) {
|
||||
pid_t pid;
|
||||
switch (pid = fork()) {
|
||||
case 0:
|
||||
if (-1 == system(text)) {
|
||||
logg(LOGG_WARNING, "%s: couldn't execute \"%s\".\n", type, text);
|
||||
}
|
||||
exit(0);
|
||||
case -1:
|
||||
logg(LOGG_WARNING, "%s::fork() failed, %s.\n", type, strerror(errno));
|
||||
break;
|
||||
default:
|
||||
g_active_children++;
|
||||
}
|
||||
} else {
|
||||
logg(LOGG_WARNING, "%s: already %d processes active.\n", type, g_active_children);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
29
clamav/freshclam/execute.h
Normal file
29
clamav/freshclam/execute.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* By Per Jessen <per@computer.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __EXECUTE_H
|
||||
#define __EXECUTE_H
|
||||
|
||||
#include "optparser.h"
|
||||
|
||||
extern int g_active_children;
|
||||
|
||||
void execute(const char *type, const char *text, int bDaemonized);
|
||||
|
||||
#endif
|
||||
2114
clamav/freshclam/freshclam.c
Normal file
2114
clamav/freshclam/freshclam.c
Normal file
File diff suppressed because it is too large
Load Diff
176
clamav/freshclam/notify.c
Normal file
176
clamav/freshclam/notify.c
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2002-2013 Sourcefire, Inc.
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "optparser.h"
|
||||
#include "output.h"
|
||||
#include "clamdcom.h"
|
||||
|
||||
#include "notify.h"
|
||||
|
||||
int clamd_connect(const char *cfgfile, const char *option)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct sockaddr_un server;
|
||||
#endif
|
||||
|
||||
struct addrinfo hints, *res, *p;
|
||||
char port[6];
|
||||
int ret;
|
||||
|
||||
struct optstruct *opts;
|
||||
const struct optstruct *opt;
|
||||
int sockd;
|
||||
|
||||
if ((opts = optparse(cfgfile, 0, NULL, 1, OPT_CLAMD, 0, NULL)) == NULL) {
|
||||
logg(LOGG_ERROR, "%s: Can't find or parse configuration file %s\n", option,
|
||||
cfgfile);
|
||||
return -11;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
if ((opt = optget(opts, "LocalSocket"))->enabled) {
|
||||
memset(&server, 0x00, sizeof(server));
|
||||
server.sun_family = AF_UNIX;
|
||||
strncpy(server.sun_path, opt->strarg, sizeof(server.sun_path));
|
||||
server.sun_path[sizeof(server.sun_path) - 1] = '\0';
|
||||
|
||||
if ((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
logg(LOGG_WARNING, "Clamd was NOT notified: Can't create socket endpoint for %s: %s\n",
|
||||
opt->strarg, strerror(errno));
|
||||
optfree(opts);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(sockd, (struct sockaddr *)&server,
|
||||
sizeof(struct sockaddr_un)) < 0) {
|
||||
logg(LOGG_WARNING, "Clamd was NOT notified: Can't connect to clamd through %s: %s\n",
|
||||
opt->strarg, strerror(errno));
|
||||
closesocket(sockd);
|
||||
optfree(opts);
|
||||
return -11;
|
||||
}
|
||||
|
||||
return sockd;
|
||||
|
||||
} else
|
||||
#endif
|
||||
if ((opt = optget(opts, "TCPSocket"))->enabled) {
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
snprintf(port, sizeof(port), "%u", (unsigned int)opt->numarg);
|
||||
port[5] = 0;
|
||||
|
||||
opt = optget(opts, "TCPAddr");
|
||||
while (opt) {
|
||||
ret = getaddrinfo(opt->strarg, port, &hints, &res);
|
||||
|
||||
if (ret) {
|
||||
logg(LOGG_ERROR, "%s: Can't resolve hostname %s (%s)\n", option,
|
||||
opt->strarg ? opt->strarg : "",
|
||||
(ret ==
|
||||
EAI_SYSTEM)
|
||||
? strerror(errno)
|
||||
: gai_strerror(ret));
|
||||
opt = opt->nextarg;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (p = res; p != NULL; p = p->ai_next) {
|
||||
if ((sockd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) {
|
||||
logg(LOGG_ERROR, "%s: Can't create TCP socket to connect to %s: %s\n",
|
||||
option, opt->strarg ? opt->strarg : "localhost", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (connect(sockd, p->ai_addr, p->ai_addrlen) == -1) {
|
||||
logg(LOGG_ERROR, "%s: Can't connect to clamd on %s:%s: %s\n", option,
|
||||
opt->strarg ? opt->strarg : "localhost", port, strerror(errno));
|
||||
closesocket(sockd);
|
||||
continue;
|
||||
}
|
||||
|
||||
optfree(opts);
|
||||
freeaddrinfo(res);
|
||||
|
||||
return sockd;
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
opt = opt->nextarg;
|
||||
}
|
||||
} else {
|
||||
logg(LOGG_ERROR, "%s: No communication socket specified in %s\n", option,
|
||||
cfgfile);
|
||||
optfree(opts);
|
||||
return 1;
|
||||
}
|
||||
|
||||
optfree(opts);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int notify(const char *cfgfile)
|
||||
{
|
||||
char buff[20];
|
||||
int sockd, bread;
|
||||
|
||||
if ((sockd = clamd_connect(cfgfile, "NotifyClamd")) < 0)
|
||||
return 1;
|
||||
|
||||
if (sendln(sockd, "RELOAD", 7) < 0) {
|
||||
logg(LOGG_ERROR, "NotifyClamd: Could not write to clamd socket: %s\n", strerror(errno));
|
||||
closesocket(sockd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(buff, 0, sizeof(buff));
|
||||
if ((bread = recv(sockd, buff, sizeof(buff), 0)) > 0) {
|
||||
if (!strstr(buff, "RELOADING")) {
|
||||
logg(LOGG_ERROR, "NotifyClamd: Unknown answer from clamd: '%s'\n", buff);
|
||||
closesocket(sockd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
closesocket(sockd);
|
||||
logg(LOGG_INFO, "Clamd successfully notified about the update.\n");
|
||||
return 0;
|
||||
}
|
||||
27
clamav/freshclam/notify.h
Normal file
27
clamav/freshclam/notify.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2007-2013 Sourcefire, Inc.
|
||||
* Copyright (C) 2002-2007 Tomasz Kojm <tkojm@clamav.net>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __NOTIFY_H
|
||||
#define __NOTIFY_H
|
||||
|
||||
int notify(const char *cfgfile);
|
||||
int clamd_connect(const char *cfgfile, const char *option);
|
||||
|
||||
#endif
|
||||
203
clamav/libclamav/7z/7z.h
Normal file
203
clamav/libclamav/7z/7z.h
Normal file
@@ -0,0 +1,203 @@
|
||||
/* 7z.h -- 7z interface
|
||||
2010-03-11 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_H
|
||||
#define __7Z_H
|
||||
|
||||
#include "7zBuf.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#define k7zStartHeaderSize 0x20
|
||||
#define k7zSignatureSize 6
|
||||
extern Byte k7zSignature[k7zSignatureSize];
|
||||
#define k7zMajorVersion 0
|
||||
|
||||
enum EIdEnum
|
||||
{
|
||||
k7zIdEnd,
|
||||
k7zIdHeader,
|
||||
k7zIdArchiveProperties,
|
||||
k7zIdAdditionalStreamsInfo,
|
||||
k7zIdMainStreamsInfo,
|
||||
k7zIdFilesInfo,
|
||||
k7zIdPackInfo,
|
||||
k7zIdUnpackInfo,
|
||||
k7zIdSubStreamsInfo,
|
||||
k7zIdSize,
|
||||
k7zIdCRC,
|
||||
k7zIdFolder,
|
||||
k7zIdCodersUnpackSize,
|
||||
k7zIdNumUnpackStream,
|
||||
k7zIdEmptyStream,
|
||||
k7zIdEmptyFile,
|
||||
k7zIdAnti,
|
||||
k7zIdName,
|
||||
k7zIdCTime,
|
||||
k7zIdATime,
|
||||
k7zIdMTime,
|
||||
k7zIdWinAttributes,
|
||||
k7zIdComment,
|
||||
k7zIdEncodedHeader,
|
||||
k7zIdStartPos,
|
||||
k7zIdDummy
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 NumInStreams;
|
||||
UInt32 NumOutStreams;
|
||||
UInt64 MethodID;
|
||||
CBuf Props;
|
||||
} CSzCoderInfo;
|
||||
|
||||
void SzCoderInfo_Init(CSzCoderInfo *p);
|
||||
void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 InIndex;
|
||||
UInt32 OutIndex;
|
||||
} CSzBindPair;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CSzCoderInfo *Coders;
|
||||
CSzBindPair *BindPairs;
|
||||
UInt32 *PackStreams;
|
||||
UInt64 *UnpackSizes;
|
||||
UInt32 NumCoders;
|
||||
UInt32 NumBindPairs;
|
||||
UInt32 NumPackStreams;
|
||||
int UnpackCRCDefined;
|
||||
UInt32 UnpackCRC;
|
||||
|
||||
UInt32 NumUnpackStreams;
|
||||
} CSzFolder;
|
||||
|
||||
void SzFolder_Init(CSzFolder *p);
|
||||
UInt64 SzFolder_GetUnpackSize(CSzFolder *p);
|
||||
int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex);
|
||||
UInt32 SzFolder_GetNumOutStreams(CSzFolder *p);
|
||||
UInt64 SzFolder_GetUnpackSize(CSzFolder *p);
|
||||
|
||||
SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes,
|
||||
ILookInStream *stream, UInt64 startPos,
|
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 Low;
|
||||
UInt32 High;
|
||||
} CNtfsFileTime;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CNtfsFileTime MTime;
|
||||
UInt64 Size;
|
||||
UInt32 Crc;
|
||||
UInt32 Attrib;
|
||||
Byte HasStream;
|
||||
Byte IsDir;
|
||||
Byte IsAnti;
|
||||
Byte CrcDefined;
|
||||
Byte MTimeDefined;
|
||||
Byte AttribDefined;
|
||||
} CSzFileItem;
|
||||
|
||||
void SzFile_Init(CSzFileItem *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt64 *PackSizes;
|
||||
Byte *PackCRCsDefined;
|
||||
UInt32 *PackCRCs;
|
||||
CSzFolder *Folders;
|
||||
CSzFileItem *Files;
|
||||
UInt32 NumPackStreams;
|
||||
UInt32 NumFolders;
|
||||
UInt32 NumFiles;
|
||||
} CSzAr;
|
||||
|
||||
void SzAr_Init(CSzAr *p);
|
||||
void SzAr_Free(CSzAr *p, ISzAlloc *alloc);
|
||||
|
||||
|
||||
/*
|
||||
SzExtract extracts file from archive
|
||||
|
||||
*outBuffer must be 0 before first call for each new archive.
|
||||
|
||||
Extracting cache:
|
||||
If you need to decompress more than one file, you can send
|
||||
these values from previous call:
|
||||
*blockIndex,
|
||||
*outBuffer,
|
||||
*outBufferSize
|
||||
You can consider "*outBuffer" as cache of solid block. If your archive is solid,
|
||||
it will increase decompression speed.
|
||||
|
||||
If you use external function, you can declare these 3 cache variables
|
||||
(blockIndex, outBuffer, outBufferSize) as static in that external function.
|
||||
|
||||
Free *outBuffer and set *outBuffer to 0, if you want to flush cache.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CSzAr db;
|
||||
|
||||
UInt64 startPosAfterHeader;
|
||||
UInt64 dataPos;
|
||||
|
||||
UInt32 *FolderStartPackStreamIndex;
|
||||
UInt64 *PackStreamStartPositions;
|
||||
UInt32 *FolderStartFileIndex;
|
||||
UInt32 *FileIndexToFolderIndexMap;
|
||||
|
||||
size_t *FileNameOffsets; /* in 2-byte steps */
|
||||
CBuf FileNames; /* UTF-16-LE */
|
||||
} CSzArEx;
|
||||
|
||||
void SzArEx_Init(CSzArEx *p);
|
||||
void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc);
|
||||
UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder);
|
||||
int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize);
|
||||
|
||||
/*
|
||||
if dest == NULL, the return value specifies the required size of the buffer,
|
||||
in 16-bit characters, including the null-terminating character.
|
||||
if dest != NULL, the return value specifies the number of 16-bit characters that
|
||||
are written to the dest, including the null-terminating character. */
|
||||
|
||||
size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
|
||||
|
||||
SRes SzArEx_Extract(
|
||||
const CSzArEx *db,
|
||||
ILookInStream *inStream,
|
||||
UInt32 fileIndex, /* index of file */
|
||||
UInt32 *blockIndex, /* index of solid block */
|
||||
Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
|
||||
size_t *outBufferSize, /* buffer size for output buffer */
|
||||
size_t *offset, /* offset of stream for required file in *outBuffer */
|
||||
size_t *outSizeProcessed, /* size of file in *outBuffer */
|
||||
ISzAlloc *allocMain,
|
||||
ISzAlloc *allocTemp);
|
||||
|
||||
|
||||
/*
|
||||
SzArEx_Open Errors:
|
||||
SZ_ERROR_NO_ARCHIVE
|
||||
SZ_ERROR_ARCHIVE
|
||||
SZ_ERROR_UNSUPPORTED
|
||||
SZ_ERROR_MEM
|
||||
SZ_ERROR_CRC
|
||||
SZ_ERROR_INPUT_EOF
|
||||
SZ_ERROR_FAIL
|
||||
*/
|
||||
|
||||
SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
82
clamav/libclamav/7z/7zAlloc.c
Normal file
82
clamav/libclamav/7z/7zAlloc.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/* 7zAlloc.c -- Allocation functions
|
||||
2010-10-29 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "7zAlloc.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
/* #define _SZ_ALLOC_DEBUG */
|
||||
/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
|
||||
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
int g_allocCount = 0;
|
||||
int g_allocCountTemp = 0;
|
||||
|
||||
#endif
|
||||
#include "clamav.h"
|
||||
|
||||
void *SzAlloc(void *p, size_t size)
|
||||
{
|
||||
UNUSEDPARAM(p);
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount);
|
||||
g_allocCount++;
|
||||
#endif
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void SzFree(void *p, void *address)
|
||||
{
|
||||
UNUSEDPARAM(p);
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
if (address != 0)
|
||||
{
|
||||
g_allocCount--;
|
||||
fprintf(stderr, "\nFree; count = %10d", g_allocCount);
|
||||
}
|
||||
#endif
|
||||
free(address);
|
||||
}
|
||||
|
||||
void *SzAllocTemp(void *p, size_t size)
|
||||
{
|
||||
UNUSEDPARAM(p);
|
||||
if (size == 0)
|
||||
return 0;
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
fprintf(stderr, "\nAlloc_temp %10d bytes; count = %10d", size, g_allocCountTemp);
|
||||
g_allocCountTemp++;
|
||||
#ifdef _WIN32
|
||||
return HeapAlloc(GetProcessHeap(), 0, size);
|
||||
#endif
|
||||
#endif
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void SzFreeTemp(void *p, void *address)
|
||||
{
|
||||
UNUSEDPARAM(p);
|
||||
#ifdef _SZ_ALLOC_DEBUG
|
||||
if (address != 0)
|
||||
{
|
||||
g_allocCountTemp--;
|
||||
fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
HeapFree(GetProcessHeap(), 0, address);
|
||||
return;
|
||||
#endif
|
||||
#endif
|
||||
free(address);
|
||||
}
|
||||
15
clamav/libclamav/7z/7zAlloc.h
Normal file
15
clamav/libclamav/7z/7zAlloc.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/* 7zAlloc.h -- Allocation functions
|
||||
2010-10-29 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_ALLOC_H
|
||||
#define __7Z_ALLOC_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void *SzAlloc(void *p, size_t size);
|
||||
void SzFree(void *p, void *address);
|
||||
|
||||
void *SzAllocTemp(void *p, size_t size);
|
||||
void SzFreeTemp(void *p, void *address);
|
||||
|
||||
#endif
|
||||
36
clamav/libclamav/7z/7zBuf.c
Normal file
36
clamav/libclamav/7z/7zBuf.c
Normal file
@@ -0,0 +1,36 @@
|
||||
/* 7zBuf.c -- Byte Buffer
|
||||
2008-03-28
|
||||
Igor Pavlov
|
||||
Public domain */
|
||||
|
||||
#include "7zBuf.h"
|
||||
|
||||
void Buf_Init(CBuf *p)
|
||||
{
|
||||
p->data = 0;
|
||||
p->size = 0;
|
||||
}
|
||||
|
||||
int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc)
|
||||
{
|
||||
p->size = 0;
|
||||
if (size == 0)
|
||||
{
|
||||
p->data = 0;
|
||||
return 1;
|
||||
}
|
||||
p->data = (Byte *)alloc->Alloc(alloc, size);
|
||||
if (p->data != 0)
|
||||
{
|
||||
p->size = size;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Buf_Free(CBuf *p, ISzAlloc *alloc)
|
||||
{
|
||||
alloc->Free(alloc, p->data);
|
||||
p->data = 0;
|
||||
p->size = 0;
|
||||
}
|
||||
39
clamav/libclamav/7z/7zBuf.h
Normal file
39
clamav/libclamav/7z/7zBuf.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 7zBuf.h -- Byte Buffer
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_BUF_H
|
||||
#define __7Z_BUF_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte *data;
|
||||
size_t size;
|
||||
} CBuf;
|
||||
|
||||
void Buf_Init(CBuf *p);
|
||||
int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc);
|
||||
void Buf_Free(CBuf *p, ISzAlloc *alloc);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte *data;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
} CDynBuf;
|
||||
|
||||
void DynBuf_Construct(CDynBuf *p);
|
||||
void DynBuf_SeekToBeg(CDynBuf *p);
|
||||
int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc);
|
||||
void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
51
clamav/libclamav/7z/7zBuf2.c
Normal file
51
clamav/libclamav/7z/7zBuf2.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/* 7zBuf2.c -- Byte Buffer
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "7zBuf.h"
|
||||
|
||||
void DynBuf_Construct(CDynBuf *p)
|
||||
{
|
||||
p->data = 0;
|
||||
p->size = 0;
|
||||
p->pos = 0;
|
||||
}
|
||||
|
||||
void DynBuf_SeekToBeg(CDynBuf *p)
|
||||
{
|
||||
p->pos = 0;
|
||||
}
|
||||
|
||||
int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc)
|
||||
{
|
||||
if (size > p->size - p->pos)
|
||||
{
|
||||
size_t newSize = p->pos + size;
|
||||
Byte *data;
|
||||
newSize += newSize / 4;
|
||||
data = (Byte *)alloc->Alloc(alloc, newSize);
|
||||
if (data == 0)
|
||||
return 0;
|
||||
p->size = newSize;
|
||||
memcpy(data, p->data, p->pos);
|
||||
alloc->Free(alloc, p->data);
|
||||
p->data = data;
|
||||
}
|
||||
memcpy(p->data + p->pos, buf, size);
|
||||
p->pos += size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc)
|
||||
{
|
||||
alloc->Free(alloc, p->data);
|
||||
p->data = 0;
|
||||
p->size = 0;
|
||||
p->pos = 0;
|
||||
}
|
||||
27
clamav/libclamav/7z/7zCrc.c
Normal file
27
clamav/libclamav/7z/7zCrc.c
Normal file
@@ -0,0 +1,27 @@
|
||||
/* 7zCrc.c -- CRC32 calculation
|
||||
2009-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "7zCrc.h"
|
||||
#include "CpuArch.h"
|
||||
|
||||
const UInt32 g_CrcTable[256] = { 0x0, 0x77073096, 0xee0e612c, 0x990951ba, 0x76dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0xedb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x9b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x1db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x6b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0xf00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x86d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x3b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x4db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0xd6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0xa00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x26d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x5005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0xcb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0xbdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d };
|
||||
|
||||
#define CRC_UPDATE_BYTE_2(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
|
||||
{
|
||||
return CrcUpdate(CRC_INIT_VAL, data, size) ^ CRC_INIT_VAL;
|
||||
}
|
||||
22
clamav/libclamav/7z/7zCrc.h
Normal file
22
clamav/libclamav/7z/7zCrc.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/* 7zCrc.h -- CRC32 calculation
|
||||
2009-11-21 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_CRC_H
|
||||
#define __7Z_CRC_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
extern const UInt32 g_CrcTable[];
|
||||
|
||||
#define CRC_INIT_VAL 0xFFFFFFFF
|
||||
#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
|
||||
#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size);
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
39
clamav/libclamav/7z/7zCrcOpt.c
Normal file
39
clamav/libclamav/7z/7zCrcOpt.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 7zCrcOpt.c -- CRC32 calculation : optimized version
|
||||
2009-11-23 : Igor Pavlov : Public domain */
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "CpuArch.h"
|
||||
|
||||
#ifdef MY_CPU_LE
|
||||
|
||||
#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
for (; size >= 4; size -= 4, p += 4)
|
||||
{
|
||||
v ^= *(const UInt32 *)p;
|
||||
v =
|
||||
table[0x300 + (v & 0xFF)] ^
|
||||
table[0x200 + ((v >> 8) & 0xFF)] ^
|
||||
table[0x100 + ((v >> 16) & 0xFF)] ^
|
||||
table[0x000 + ((v >> 24))];
|
||||
}
|
||||
for (; size > 0; size--, p++)
|
||||
v = CRC_UPDATE_BYTE_2(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
{
|
||||
return CrcUpdateT4(v, data, size, table);
|
||||
}
|
||||
|
||||
#endif
|
||||
481
clamav/libclamav/7z/7zDec.c
Normal file
481
clamav/libclamav/7z/7zDec.c
Normal file
@@ -0,0 +1,481 @@
|
||||
/* 7zDec.c -- Decoding from 7z folder
|
||||
2010-11-02 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#define _7ZIP_PPMD_SUPPPORT
|
||||
|
||||
#include "7z.h"
|
||||
|
||||
#include "Bcj2.h"
|
||||
#include "Bra.h"
|
||||
#include "CpuArch.h"
|
||||
#include "LzmaDec.h"
|
||||
#include "Lzma2Dec.h"
|
||||
#ifdef _7ZIP_PPMD_SUPPPORT
|
||||
#include "Ppmd7.h"
|
||||
#endif
|
||||
|
||||
#define k_Copy 0
|
||||
#define k_LZMA2 0x21
|
||||
#define k_LZMA 0x30101
|
||||
#define k_BCJ 0x03030103
|
||||
#define k_PPC 0x03030205
|
||||
#define k_ARM 0x03030501
|
||||
#define k_ARMT 0x03030701
|
||||
#define k_SPARC 0x03030805
|
||||
#define k_BCJ2 0x0303011B
|
||||
|
||||
#ifdef _7ZIP_PPMD_SUPPPORT
|
||||
|
||||
#define k_PPMD 0x30401
|
||||
|
||||
typedef struct
|
||||
{
|
||||
IByteIn p;
|
||||
const Byte *cur;
|
||||
const Byte *end;
|
||||
const Byte *begin;
|
||||
UInt64 processed;
|
||||
Bool extra;
|
||||
SRes res;
|
||||
ILookInStream *inStream;
|
||||
} CByteInToLook;
|
||||
|
||||
static Byte ReadByte(void *pp)
|
||||
{
|
||||
CByteInToLook *p = (CByteInToLook *)pp;
|
||||
if (p->cur != p->end)
|
||||
return *p->cur++;
|
||||
if (p->res == SZ_OK)
|
||||
{
|
||||
size_t size = p->cur - p->begin;
|
||||
p->processed += size;
|
||||
p->res = p->inStream->Skip(p->inStream, size);
|
||||
size = (1 << 25);
|
||||
p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size);
|
||||
p->cur = p->begin;
|
||||
p->end = p->begin + size;
|
||||
if (size != 0)
|
||||
return *p->cur++;;
|
||||
}
|
||||
p->extra = True;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SRes SzDecodePpmd(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
|
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
CPpmd7 ppmd;
|
||||
CByteInToLook s;
|
||||
SRes res = SZ_OK;
|
||||
|
||||
s.p.Read = ReadByte;
|
||||
s.inStream = inStream;
|
||||
s.begin = s.end = s.cur = NULL;
|
||||
s.extra = False;
|
||||
s.res = SZ_OK;
|
||||
s.processed = 0;
|
||||
|
||||
if (coder->Props.size != 5)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
|
||||
{
|
||||
unsigned order = coder->Props.data[0];
|
||||
UInt32 memSize = GetUi32(coder->Props.data + 1);
|
||||
if (order < PPMD7_MIN_ORDER ||
|
||||
order > PPMD7_MAX_ORDER ||
|
||||
memSize < PPMD7_MIN_MEM_SIZE ||
|
||||
memSize > PPMD7_MAX_MEM_SIZE)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
Ppmd7_Construct(&ppmd);
|
||||
if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
|
||||
return SZ_ERROR_MEM;
|
||||
Ppmd7_Init(&ppmd, order);
|
||||
}
|
||||
{
|
||||
CPpmd7z_RangeDec rc;
|
||||
Ppmd7z_RangeDec_CreateVTable(&rc);
|
||||
rc.Stream = &s.p;
|
||||
if (!Ppmd7z_RangeDec_Init(&rc))
|
||||
res = SZ_ERROR_DATA;
|
||||
else if (s.extra)
|
||||
res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
|
||||
else
|
||||
{
|
||||
SizeT i;
|
||||
for (i = 0; i < outSize; i++)
|
||||
{
|
||||
int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p);
|
||||
if (s.extra || sym < 0)
|
||||
break;
|
||||
outBuffer[i] = (Byte)sym;
|
||||
}
|
||||
if (i != outSize)
|
||||
res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
|
||||
else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
|
||||
res = SZ_ERROR_DATA;
|
||||
}
|
||||
}
|
||||
Ppmd7_Free(&ppmd, allocMain);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static SRes SzDecodeLzma(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
|
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
CLzmaDec state;
|
||||
SRes res = SZ_OK;
|
||||
|
||||
LzmaDec_Construct(&state);
|
||||
RINOK(LzmaDec_AllocateProbs(&state, coder->Props.data, (unsigned)coder->Props.size, allocMain));
|
||||
state.dic = outBuffer;
|
||||
state.dicBufSize = outSize;
|
||||
LzmaDec_Init(&state);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Byte *inBuf = NULL;
|
||||
size_t lookahead = (1 << 18);
|
||||
if (lookahead > inSize)
|
||||
lookahead = (size_t)inSize;
|
||||
res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
|
||||
{
|
||||
SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
|
||||
ELzmaStatus status;
|
||||
res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
|
||||
lookahead -= inProcessed;
|
||||
inSize -= inProcessed;
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
|
||||
{
|
||||
if (state.dicBufSize != outSize || lookahead != 0 ||
|
||||
(status != LZMA_STATUS_FINISHED_WITH_MARK &&
|
||||
status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
|
||||
res = SZ_ERROR_DATA;
|
||||
break;
|
||||
}
|
||||
res = inStream->Skip((void *)inStream, inProcessed);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LzmaDec_FreeProbs(&state, allocMain);
|
||||
return res;
|
||||
}
|
||||
|
||||
static SRes SzDecodeLzma2(CSzCoderInfo *coder, UInt64 inSize, ILookInStream *inStream,
|
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
CLzma2Dec state;
|
||||
SRes res = SZ_OK;
|
||||
|
||||
Lzma2Dec_Construct(&state);
|
||||
if (coder->Props.size != 1)
|
||||
return SZ_ERROR_DATA;
|
||||
RINOK(Lzma2Dec_AllocateProbs(&state, coder->Props.data[0], allocMain));
|
||||
state.decoder.dic = outBuffer;
|
||||
state.decoder.dicBufSize = outSize;
|
||||
Lzma2Dec_Init(&state);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Byte *inBuf = NULL;
|
||||
size_t lookahead = (1 << 18);
|
||||
if (lookahead > inSize)
|
||||
lookahead = (size_t)inSize;
|
||||
res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
|
||||
{
|
||||
SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
|
||||
ELzmaStatus status;
|
||||
res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
|
||||
lookahead -= inProcessed;
|
||||
inSize -= inProcessed;
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
|
||||
{
|
||||
if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
|
||||
(status != LZMA_STATUS_FINISHED_WITH_MARK))
|
||||
res = SZ_ERROR_DATA;
|
||||
break;
|
||||
}
|
||||
res = inStream->Skip((void *)inStream, inProcessed);
|
||||
if (res != SZ_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Lzma2Dec_FreeProbs(&state, allocMain);
|
||||
return res;
|
||||
}
|
||||
|
||||
static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
|
||||
{
|
||||
while (inSize > 0)
|
||||
{
|
||||
void *inBuf;
|
||||
size_t curSize = (1 << 18);
|
||||
if (curSize > inSize)
|
||||
curSize = (size_t)inSize;
|
||||
RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize));
|
||||
if (curSize == 0)
|
||||
return SZ_ERROR_INPUT_EOF;
|
||||
memcpy(outBuffer, inBuf, curSize);
|
||||
outBuffer += curSize;
|
||||
inSize -= curSize;
|
||||
RINOK(inStream->Skip((void *)inStream, curSize));
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static Bool IS_MAIN_METHOD(UInt32 m)
|
||||
{
|
||||
switch(m)
|
||||
{
|
||||
case k_Copy:
|
||||
case k_LZMA:
|
||||
case k_LZMA2:
|
||||
#ifdef _7ZIP_PPMD_SUPPPORT
|
||||
case k_PPMD:
|
||||
#endif
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
|
||||
{
|
||||
return
|
||||
c->NumInStreams == 1 &&
|
||||
c->NumOutStreams == 1 &&
|
||||
c->MethodID <= (UInt32)0xFFFFFFFF &&
|
||||
IS_MAIN_METHOD((UInt32)c->MethodID);
|
||||
}
|
||||
|
||||
#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
|
||||
|
||||
static SRes CheckSupportedFolder(const CSzFolder *f)
|
||||
{
|
||||
if (f->NumCoders < 1 || f->NumCoders > 4)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
|
||||
if (f->Coders[0].MethodID == 0x06F10701) /* ACAB */
|
||||
return SZ_ERROR_ENCRYPTED;
|
||||
|
||||
if (!IS_SUPPORTED_CODER(&f->Coders[0]))
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
if (f->NumCoders == 1)
|
||||
{
|
||||
if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (f->NumCoders == 2)
|
||||
{
|
||||
CSzCoderInfo *c = &f->Coders[1];
|
||||
if (c->MethodID > (UInt32)0xFFFFFFFF ||
|
||||
c->NumInStreams != 1 ||
|
||||
c->NumOutStreams != 1 ||
|
||||
f->NumPackStreams != 1 ||
|
||||
f->PackStreams[0] != 0 ||
|
||||
f->NumBindPairs != 1 ||
|
||||
f->BindPairs[0].InIndex != 1 ||
|
||||
f->BindPairs[0].OutIndex != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
switch ((UInt32)c->MethodID)
|
||||
{
|
||||
case k_BCJ:
|
||||
case k_ARM:
|
||||
break;
|
||||
default:
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
if (f->NumCoders == 4)
|
||||
{
|
||||
if (!IS_SUPPORTED_CODER(&f->Coders[1]) ||
|
||||
!IS_SUPPORTED_CODER(&f->Coders[2]) ||
|
||||
!IS_BCJ2(&f->Coders[3]))
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
if (f->NumPackStreams != 4 ||
|
||||
f->PackStreams[0] != 2 ||
|
||||
f->PackStreams[1] != 6 ||
|
||||
f->PackStreams[2] != 1 ||
|
||||
f->PackStreams[3] != 0 ||
|
||||
f->NumBindPairs != 3 ||
|
||||
f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
|
||||
f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
|
||||
f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
return SZ_OK;
|
||||
}
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static UInt64 GetSum(const UInt64 *values, UInt32 index)
|
||||
{
|
||||
UInt64 sum = 0;
|
||||
UInt32 i;
|
||||
for (i = 0; i < index; i++)
|
||||
sum += values[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
|
||||
|
||||
static SRes SzFolder_Decode2(const CSzFolder *folder, const UInt64 *packSizes,
|
||||
ILookInStream *inStream, UInt64 startPos,
|
||||
Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
|
||||
Byte *tempBuf[])
|
||||
{
|
||||
UInt32 ci;
|
||||
SizeT tempSizes[3] = { 0, 0, 0};
|
||||
SizeT tempSize3 = 0;
|
||||
Byte *tempBuf3 = 0;
|
||||
|
||||
RINOK(CheckSupportedFolder(folder));
|
||||
|
||||
for (ci = 0; ci < folder->NumCoders; ci++)
|
||||
{
|
||||
CSzCoderInfo *coder = &folder->Coders[ci];
|
||||
|
||||
if (IS_MAIN_METHOD((UInt32)coder->MethodID))
|
||||
{
|
||||
UInt32 si = 0;
|
||||
UInt64 offset;
|
||||
UInt64 inSize;
|
||||
Byte *outBufCur = outBuffer;
|
||||
SizeT outSizeCur = outSize;
|
||||
if (folder->NumCoders == 4)
|
||||
{
|
||||
UInt32 indices[] = { 3, 2, 0 };
|
||||
UInt64 unpackSize = folder->UnpackSizes[ci];
|
||||
si = indices[ci];
|
||||
if (ci < 2)
|
||||
{
|
||||
Byte *temp;
|
||||
outSizeCur = (SizeT)unpackSize;
|
||||
if (outSizeCur != unpackSize)
|
||||
return SZ_ERROR_MEM;
|
||||
temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
|
||||
if (temp == 0 && outSizeCur != 0)
|
||||
return SZ_ERROR_MEM;
|
||||
outBufCur = tempBuf[1 - ci] = temp;
|
||||
tempSizes[1 - ci] = outSizeCur;
|
||||
}
|
||||
else if (ci == 2)
|
||||
{
|
||||
if (unpackSize > outSize) /* check it */
|
||||
return SZ_ERROR_PARAM;
|
||||
tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
|
||||
tempSize3 = outSizeCur = (SizeT)unpackSize;
|
||||
}
|
||||
else
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
if (!packSizes)
|
||||
return SZ_ERROR_FAIL;
|
||||
offset = GetSum(packSizes, si);
|
||||
inSize = packSizes[si];
|
||||
RINOK(LookInStream_SeekTo(inStream, startPos + offset));
|
||||
|
||||
if (coder->MethodID == k_Copy)
|
||||
{
|
||||
if (inSize != outSizeCur) /* check it */
|
||||
return SZ_ERROR_DATA;
|
||||
RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
|
||||
}
|
||||
else if (coder->MethodID == k_LZMA)
|
||||
{
|
||||
RINOK(SzDecodeLzma(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
|
||||
}
|
||||
else if (coder->MethodID == k_LZMA2)
|
||||
{
|
||||
RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _7ZIP_PPMD_SUPPPORT
|
||||
RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, allocMain));
|
||||
#else
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (coder->MethodID == k_BCJ2)
|
||||
{
|
||||
UInt64 offset = GetSum(packSizes, 1);
|
||||
UInt64 s3Size = packSizes[1];
|
||||
SRes res;
|
||||
if (ci != 3)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
RINOK(LookInStream_SeekTo(inStream, startPos + offset));
|
||||
tempSizes[2] = (SizeT)s3Size;
|
||||
if (tempSizes[2] != s3Size)
|
||||
return SZ_ERROR_MEM;
|
||||
tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
|
||||
if (tempBuf[2] == 0 && tempSizes[2] != 0)
|
||||
return SZ_ERROR_MEM;
|
||||
res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
|
||||
RINOK(res)
|
||||
|
||||
res = Bcj2_Decode(
|
||||
tempBuf3, tempSize3,
|
||||
tempBuf[0], tempSizes[0],
|
||||
tempBuf[1], tempSizes[1],
|
||||
tempBuf[2], tempSizes[2],
|
||||
outBuffer, outSize);
|
||||
RINOK(res)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ci != 1)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
switch(coder->MethodID)
|
||||
{
|
||||
case k_BCJ:
|
||||
{
|
||||
UInt32 state;
|
||||
x86_Convert_Init(state);
|
||||
x86_Convert(outBuffer, outSize, 0, &state, 0);
|
||||
break;
|
||||
}
|
||||
CASE_BRA_CONV(ARM)
|
||||
default:
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes SzFolder_Decode(const CSzFolder *folder, const UInt64 *packSizes,
|
||||
ILookInStream *inStream, UInt64 startPos,
|
||||
Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
|
||||
{
|
||||
Byte *tempBuf[3] = { 0, 0, 0};
|
||||
int i;
|
||||
SRes res = SzFolder_Decode2(folder, packSizes, inStream, startPos,
|
||||
outBuffer, (SizeT)outSize, allocMain, tempBuf);
|
||||
for (i = 0; i < 3; i++)
|
||||
IAlloc_Free(allocMain, tempBuf[i]);
|
||||
return res;
|
||||
}
|
||||
258
clamav/libclamav/7z/7zFile.c
Normal file
258
clamav/libclamav/7z/7zFile.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/* 7zFile.c -- File IO
|
||||
2009-11-24 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "7zFile.h"
|
||||
|
||||
#ifndef USE_WINDOWS_FILE
|
||||
|
||||
#ifndef UNDER_CE
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
ReadFile and WriteFile functions in Windows have BUG:
|
||||
If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
|
||||
from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
|
||||
(Insufficient system resources exist to complete the requested service).
|
||||
Probably in some version of Windows there are problems with other sizes:
|
||||
for 32 MB (maybe also for 16 MB).
|
||||
And message can be "Network connection was lost"
|
||||
*/
|
||||
|
||||
#define kChunkSizeMax (1 << 22)
|
||||
|
||||
#endif
|
||||
|
||||
void File_Construct(CSzFile *p)
|
||||
{
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
p->handle = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
p->file = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
|
||||
static WRes File_Open(CSzFile *p, const char *name, int writeMode)
|
||||
{
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
p->handle = CreateFileA(name,
|
||||
writeMode ? GENERIC_WRITE : GENERIC_READ,
|
||||
FILE_SHARE_READ, NULL,
|
||||
writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
|
||||
#else
|
||||
p->file = fopen(name, writeMode ? "wb+" : "rb");
|
||||
return (p->file != 0) ? 0 :
|
||||
#ifdef UNDER_CE
|
||||
2; /* ENOENT */
|
||||
#else
|
||||
errno;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
|
||||
WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); }
|
||||
#endif
|
||||
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode)
|
||||
{
|
||||
p->handle = CreateFileW(name,
|
||||
writeMode ? GENERIC_WRITE : GENERIC_READ,
|
||||
FILE_SHARE_READ, NULL,
|
||||
writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
|
||||
}
|
||||
WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); }
|
||||
WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); }
|
||||
#endif
|
||||
|
||||
WRes File_Close(CSzFile *p)
|
||||
{
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
if (p->handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (!CloseHandle(p->handle))
|
||||
return GetLastError();
|
||||
p->handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
#else
|
||||
if (p->file != NULL)
|
||||
{
|
||||
int res = fclose(p->file);
|
||||
if (res != 0)
|
||||
return res;
|
||||
p->file = NULL;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
WRes File_Read(CSzFile *p, void *data, size_t *size)
|
||||
{
|
||||
size_t originalSize = *size;
|
||||
if (originalSize == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
|
||||
*size = 0;
|
||||
do
|
||||
{
|
||||
DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
|
||||
DWORD processed = 0;
|
||||
BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
|
||||
data = (void *)((Byte *)data + processed);
|
||||
originalSize -= processed;
|
||||
*size += processed;
|
||||
if (!res)
|
||||
return GetLastError();
|
||||
if (processed == 0)
|
||||
break;
|
||||
}
|
||||
while (originalSize > 0);
|
||||
return 0;
|
||||
|
||||
#else
|
||||
|
||||
*size = fread(data, 1, originalSize, p->file);
|
||||
if (*size == originalSize)
|
||||
return 0;
|
||||
return ferror(p->file);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
WRes File_Write(CSzFile *p, const void *data, size_t *size)
|
||||
{
|
||||
size_t originalSize = *size;
|
||||
if (originalSize == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
|
||||
*size = 0;
|
||||
do
|
||||
{
|
||||
DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
|
||||
DWORD processed = 0;
|
||||
BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
|
||||
data = (void *)((Byte *)data + processed);
|
||||
originalSize -= processed;
|
||||
*size += processed;
|
||||
if (!res)
|
||||
return GetLastError();
|
||||
if (processed == 0)
|
||||
break;
|
||||
}
|
||||
while (originalSize > 0);
|
||||
return 0;
|
||||
|
||||
#else
|
||||
|
||||
*size = fwrite(data, 1, originalSize, p->file);
|
||||
if (*size == originalSize)
|
||||
return 0;
|
||||
return ferror(p->file);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
|
||||
{
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
|
||||
LARGE_INTEGER value;
|
||||
DWORD moveMethod;
|
||||
value.LowPart = (DWORD)*pos;
|
||||
value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
|
||||
switch (origin)
|
||||
{
|
||||
case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break;
|
||||
case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break;
|
||||
case SZ_SEEK_END: moveMethod = FILE_END; break;
|
||||
default: return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod);
|
||||
if (value.LowPart == 0xFFFFFFFF)
|
||||
{
|
||||
WRes res = GetLastError();
|
||||
if (res != NO_ERROR)
|
||||
return res;
|
||||
}
|
||||
*pos = ((Int64)value.HighPart << 32) | value.LowPart;
|
||||
return 0;
|
||||
|
||||
#else
|
||||
|
||||
int moveMethod;
|
||||
int res;
|
||||
switch (origin)
|
||||
{
|
||||
case SZ_SEEK_SET: moveMethod = SEEK_SET; break;
|
||||
case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break;
|
||||
case SZ_SEEK_END: moveMethod = SEEK_END; break;
|
||||
default: return 1;
|
||||
}
|
||||
res = fseek(p->file, (long)*pos, moveMethod);
|
||||
*pos = ftell(p->file);
|
||||
return res;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* ---------- FileSeqInStream ---------- */
|
||||
|
||||
static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size)
|
||||
{
|
||||
CFileSeqInStream *p = (CFileSeqInStream *)pp;
|
||||
return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ;
|
||||
}
|
||||
|
||||
void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
|
||||
{
|
||||
p->s.Read = FileSeqInStream_Read;
|
||||
}
|
||||
|
||||
|
||||
/* ---------- FileInStream ---------- */
|
||||
|
||||
static SRes FileInStream_Read(void *pp, void *buf, size_t *size)
|
||||
{
|
||||
CFileInStream *p = (CFileInStream *)pp;
|
||||
return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ;
|
||||
}
|
||||
|
||||
static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin)
|
||||
{
|
||||
CFileInStream *p = (CFileInStream *)pp;
|
||||
return File_Seek(&p->file, pos, origin);
|
||||
}
|
||||
|
||||
void FileInStream_CreateVTable(CFileInStream *p)
|
||||
{
|
||||
p->s.Read = FileInStream_Read;
|
||||
p->s.Seek = FileInStream_Seek;
|
||||
}
|
||||
|
||||
|
||||
/* ---------- FileOutStream ---------- */
|
||||
|
||||
static size_t FileOutStream_Write(void *pp, const void *data, size_t size)
|
||||
{
|
||||
CFileOutStream *p = (CFileOutStream *)pp;
|
||||
File_Write(&p->file, data, &size);
|
||||
return size;
|
||||
}
|
||||
|
||||
void FileOutStream_CreateVTable(CFileOutStream *p)
|
||||
{
|
||||
p->s.Write = FileOutStream_Write;
|
||||
}
|
||||
83
clamav/libclamav/7z/7zFile.h
Normal file
83
clamav/libclamav/7z/7zFile.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/* 7zFile.h -- File IO
|
||||
2009-11-24 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_FILE_H
|
||||
#define __7Z_FILE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#define USE_WINDOWS_FILE
|
||||
#endif
|
||||
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
/* ---------- File ---------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
HANDLE handle;
|
||||
#else
|
||||
FILE *file;
|
||||
#endif
|
||||
fmap_t *fmap;
|
||||
} CSzFile;
|
||||
|
||||
void File_Construct(CSzFile *p);
|
||||
#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
|
||||
WRes InFile_Open(CSzFile *p, const char *name);
|
||||
WRes OutFile_Open(CSzFile *p, const char *name);
|
||||
#endif
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
WRes InFile_OpenW(CSzFile *p, const WCHAR *name);
|
||||
WRes OutFile_OpenW(CSzFile *p, const WCHAR *name);
|
||||
#endif
|
||||
WRes File_Close(CSzFile *p);
|
||||
|
||||
/* reads max(*size, remain file's size) bytes */
|
||||
WRes File_Read(CSzFile *p, void *data, size_t *size);
|
||||
|
||||
/* writes *size bytes */
|
||||
WRes File_Write(CSzFile *p, const void *data, size_t *size);
|
||||
|
||||
WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin);
|
||||
|
||||
|
||||
/* ---------- FileInStream ---------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeqInStream s;
|
||||
CSzFile file;
|
||||
} CFileSeqInStream;
|
||||
|
||||
void FileSeqInStream_CreateVTable(CFileSeqInStream *p);
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeekInStream s;
|
||||
CSzFile file;
|
||||
} CFileInStream;
|
||||
|
||||
void FileInStream_CreateVTable(CFileInStream *p);
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeqOutStream s;
|
||||
CSzFile file;
|
||||
} CFileOutStream;
|
||||
|
||||
void FileOutStream_CreateVTable(CFileOutStream *p);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
1477
clamav/libclamav/7z/7zIn.c
Normal file
1477
clamav/libclamav/7z/7zIn.c
Normal file
File diff suppressed because it is too large
Load Diff
169
clamav/libclamav/7z/7zStream.c
Normal file
169
clamav/libclamav/7z/7zStream.c
Normal file
@@ -0,0 +1,169 @@
|
||||
/* 7zStream.c -- 7z Stream functions
|
||||
2010-03-11 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType)
|
||||
{
|
||||
while (size != 0)
|
||||
{
|
||||
size_t processed = size;
|
||||
RINOK(stream->Read(stream, buf, &processed));
|
||||
if (processed == 0)
|
||||
return errorType;
|
||||
buf = (void *)((Byte *)buf + processed);
|
||||
size -= processed;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size)
|
||||
{
|
||||
return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
|
||||
}
|
||||
|
||||
SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf)
|
||||
{
|
||||
size_t processed = 1;
|
||||
RINOK(stream->Read(stream, buf, &processed));
|
||||
return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF;
|
||||
}
|
||||
|
||||
SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset)
|
||||
{
|
||||
Int64 t = offset;
|
||||
return stream->Seek(stream, &t, SZ_SEEK_SET);
|
||||
}
|
||||
|
||||
SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size)
|
||||
{
|
||||
const void *lookBuf;
|
||||
if (*size == 0)
|
||||
return SZ_OK;
|
||||
RINOK(stream->Look(stream, &lookBuf, size));
|
||||
memcpy(buf, lookBuf, *size);
|
||||
return stream->Skip(stream, *size);
|
||||
}
|
||||
|
||||
SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType)
|
||||
{
|
||||
while (size != 0)
|
||||
{
|
||||
size_t processed = size;
|
||||
RINOK(stream->Read(stream, buf, &processed));
|
||||
if (processed == 0)
|
||||
return errorType;
|
||||
buf = (void *)((Byte *)buf + processed);
|
||||
size -= processed;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size)
|
||||
{
|
||||
return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
|
||||
}
|
||||
|
||||
static SRes LookToRead_Look_Lookahead(void *pp, const void **buf, size_t *size)
|
||||
{
|
||||
SRes res = SZ_OK;
|
||||
CLookToRead *p = (CLookToRead *)pp;
|
||||
size_t size2 = p->size - p->pos;
|
||||
if (size2 == 0 && *size > 0)
|
||||
{
|
||||
p->pos = 0;
|
||||
size2 = LookToRead_BUF_SIZE;
|
||||
res = p->realStream->Read(p->realStream, p->buf, &size2);
|
||||
p->size = size2;
|
||||
}
|
||||
if (size2 < *size)
|
||||
*size = size2;
|
||||
*buf = p->buf + p->pos;
|
||||
return res;
|
||||
}
|
||||
|
||||
static SRes LookToRead_Look_Exact(void *pp, const void **buf, size_t *size)
|
||||
{
|
||||
SRes res = SZ_OK;
|
||||
CLookToRead *p = (CLookToRead *)pp;
|
||||
size_t size2 = p->size - p->pos;
|
||||
if (size2 == 0 && *size > 0)
|
||||
{
|
||||
p->pos = 0;
|
||||
if (*size > LookToRead_BUF_SIZE)
|
||||
*size = LookToRead_BUF_SIZE;
|
||||
res = p->realStream->Read(p->realStream, p->buf, size);
|
||||
size2 = p->size = *size;
|
||||
}
|
||||
if (size2 < *size)
|
||||
*size = size2;
|
||||
*buf = p->buf + p->pos;
|
||||
return res;
|
||||
}
|
||||
|
||||
static SRes LookToRead_Skip(void *pp, size_t offset)
|
||||
{
|
||||
CLookToRead *p = (CLookToRead *)pp;
|
||||
p->pos += offset;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static SRes LookToRead_Read(void *pp, void *buf, size_t *size)
|
||||
{
|
||||
CLookToRead *p = (CLookToRead *)pp;
|
||||
size_t rem = p->size - p->pos;
|
||||
if (rem == 0)
|
||||
return p->realStream->Read(p->realStream, buf, size);
|
||||
if (rem > *size)
|
||||
rem = *size;
|
||||
memcpy(buf, p->buf + p->pos, rem);
|
||||
p->pos += rem;
|
||||
*size = rem;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static SRes LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin)
|
||||
{
|
||||
CLookToRead *p = (CLookToRead *)pp;
|
||||
p->pos = p->size = 0;
|
||||
return p->realStream->Seek(p->realStream, pos, origin);
|
||||
}
|
||||
|
||||
void LookToRead_CreateVTable(CLookToRead *p, int lookahead)
|
||||
{
|
||||
p->s.Look = lookahead ?
|
||||
LookToRead_Look_Lookahead :
|
||||
LookToRead_Look_Exact;
|
||||
p->s.Skip = LookToRead_Skip;
|
||||
p->s.Read = LookToRead_Read;
|
||||
p->s.Seek = LookToRead_Seek;
|
||||
}
|
||||
|
||||
void LookToRead_Init(CLookToRead *p)
|
||||
{
|
||||
p->pos = p->size = 0;
|
||||
}
|
||||
|
||||
static SRes SecToLook_Read(void *pp, void *buf, size_t *size)
|
||||
{
|
||||
CSecToLook *p = (CSecToLook *)pp;
|
||||
return LookInStream_LookRead(p->realStream, buf, size);
|
||||
}
|
||||
|
||||
void SecToLook_CreateVTable(CSecToLook *p)
|
||||
{
|
||||
p->s.Read = SecToLook_Read;
|
||||
}
|
||||
|
||||
static SRes SecToRead_Read(void *pp, void *buf, size_t *size)
|
||||
{
|
||||
CSecToRead *p = (CSecToRead *)pp;
|
||||
return p->realStream->Read(p->realStream, buf, size);
|
||||
}
|
||||
|
||||
void SecToRead_CreateVTable(CSecToRead *p)
|
||||
{
|
||||
p->s.Read = SecToRead_Read;
|
||||
}
|
||||
7
clamav/libclamav/7z/7zVersion.h
Normal file
7
clamav/libclamav/7z/7zVersion.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#define MY_VER_MAJOR 9
|
||||
#define MY_VER_MINOR 20
|
||||
#define MY_VER_BUILD 0
|
||||
#define MY_VERSION "9.20"
|
||||
#define MY_DATE "2010-11-18"
|
||||
#define MY_COPYRIGHT ": Igor Pavlov : Public domain"
|
||||
#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE
|
||||
38
clamav/libclamav/7z/Alloc.h
Normal file
38
clamav/libclamav/7z/Alloc.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Alloc.h -- Memory allocation functions
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __COMMON_ALLOC_H
|
||||
#define __COMMON_ALLOC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void *MyAlloc(size_t size);
|
||||
void MyFree(void *address);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void SetLargePageSize();
|
||||
|
||||
void *MidAlloc(size_t size);
|
||||
void MidFree(void *address);
|
||||
void *BigAlloc(size_t size);
|
||||
void BigFree(void *address);
|
||||
|
||||
#else
|
||||
|
||||
#define MidAlloc(size) MyAlloc(size)
|
||||
#define MidFree(address) MyFree(address)
|
||||
#define BigAlloc(size) MyAlloc(size)
|
||||
#define BigFree(address) MyFree(address)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
132
clamav/libclamav/7z/Bcj2.c
Normal file
132
clamav/libclamav/7z/Bcj2.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/* Bcj2.c -- Converter for x86 code (BCJ2)
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Bcj2.h"
|
||||
|
||||
#ifdef _LZMA_PROB32
|
||||
#define CProb UInt32
|
||||
#else
|
||||
#define CProb UInt16
|
||||
#endif
|
||||
|
||||
#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80)
|
||||
#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1))
|
||||
|
||||
#define kNumTopBits 24
|
||||
#define kTopValue ((UInt32)1 << kNumTopBits)
|
||||
|
||||
#define kNumBitModelTotalBits 11
|
||||
#define kBitModelTotal (1 << kNumBitModelTotalBits)
|
||||
#define kNumMoveBits 5
|
||||
|
||||
#define RC_READ_BYTE (*buffer++)
|
||||
#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
|
||||
#define RC_INIT2 code = 0; range = 0xFFFFFFFF; \
|
||||
{ int i; for (i = 0; i < 5; i++) { RC_TEST; code = (code << 8) | RC_READ_BYTE; }}
|
||||
|
||||
#define NORMALIZE if (range < kTopValue) { RC_TEST; range <<= 8; code = (code << 8) | RC_READ_BYTE; }
|
||||
|
||||
#define IF_BIT_0(p) ttt = *(p); bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
|
||||
#define UPDATE_0(p) range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE;
|
||||
#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE;
|
||||
|
||||
int Bcj2_Decode(
|
||||
const Byte *buf0, SizeT size0,
|
||||
const Byte *buf1, SizeT size1,
|
||||
const Byte *buf2, SizeT size2,
|
||||
const Byte *buf3, SizeT size3,
|
||||
Byte *outBuf, SizeT outSize)
|
||||
{
|
||||
CProb p[256 + 2];
|
||||
SizeT inPos = 0, outPos = 0;
|
||||
|
||||
const Byte *buffer, *bufferLim;
|
||||
UInt32 range, code;
|
||||
Byte prevByte = 0;
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(p) / sizeof(p[0]); i++)
|
||||
p[i] = kBitModelTotal >> 1;
|
||||
|
||||
buffer = buf3;
|
||||
bufferLim = buffer + size3;
|
||||
RC_INIT2
|
||||
|
||||
if (outSize == 0)
|
||||
return SZ_OK;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Byte b;
|
||||
CProb *prob;
|
||||
UInt32 bound;
|
||||
UInt32 ttt;
|
||||
|
||||
SizeT limit = size0 - inPos;
|
||||
if (outSize - outPos < limit)
|
||||
limit = outSize - outPos;
|
||||
while (limit != 0)
|
||||
{
|
||||
Byte b = buf0[inPos];
|
||||
outBuf[outPos++] = b;
|
||||
if (IsJ(prevByte, b))
|
||||
break;
|
||||
inPos++;
|
||||
prevByte = b;
|
||||
limit--;
|
||||
}
|
||||
|
||||
if (limit == 0 || outPos == outSize)
|
||||
break;
|
||||
|
||||
b = buf0[inPos++];
|
||||
|
||||
if (b == 0xE8)
|
||||
prob = p + prevByte;
|
||||
else if (b == 0xE9)
|
||||
prob = p + 256;
|
||||
else
|
||||
prob = p + 257;
|
||||
|
||||
IF_BIT_0(prob)
|
||||
{
|
||||
UPDATE_0(prob)
|
||||
prevByte = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 dest;
|
||||
const Byte *v;
|
||||
UPDATE_1(prob)
|
||||
if (b == 0xE8)
|
||||
{
|
||||
v = buf1;
|
||||
if (size1 < 4)
|
||||
return SZ_ERROR_DATA;
|
||||
buf1 += 4;
|
||||
size1 -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = buf2;
|
||||
if (size2 < 4)
|
||||
return SZ_ERROR_DATA;
|
||||
buf2 += 4;
|
||||
size2 -= 4;
|
||||
}
|
||||
dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) |
|
||||
((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4);
|
||||
outBuf[outPos++] = (Byte)dest;
|
||||
if (outPos == outSize)
|
||||
break;
|
||||
outBuf[outPos++] = (Byte)(dest >> 8);
|
||||
if (outPos == outSize)
|
||||
break;
|
||||
outBuf[outPos++] = (Byte)(dest >> 16);
|
||||
if (outPos == outSize)
|
||||
break;
|
||||
outBuf[outPos++] = prevByte = (Byte)(dest >> 24);
|
||||
}
|
||||
}
|
||||
return (outPos == outSize) ? SZ_OK : SZ_ERROR_DATA;
|
||||
}
|
||||
38
clamav/libclamav/7z/Bcj2.h
Normal file
38
clamav/libclamav/7z/Bcj2.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Bcj2.h -- Converter for x86 code (BCJ2)
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __BCJ2_H
|
||||
#define __BCJ2_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
Conditions:
|
||||
outSize <= FullOutputSize,
|
||||
where FullOutputSize is full size of output stream of x86_2 filter.
|
||||
|
||||
If buf0 overlaps outBuf, there are two required conditions:
|
||||
1) (buf0 >= outBuf)
|
||||
2) (buf0 + size0 >= outBuf + FullOutputSize).
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
SZ_ERROR_DATA - Data error
|
||||
*/
|
||||
|
||||
int Bcj2_Decode(
|
||||
const Byte *buf0, SizeT size0,
|
||||
const Byte *buf1, SizeT size1,
|
||||
const Byte *buf2, SizeT size2,
|
||||
const Byte *buf3, SizeT size3,
|
||||
Byte *outBuf, SizeT outSize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
133
clamav/libclamav/7z/Bra.c
Normal file
133
clamav/libclamav/7z/Bra.c
Normal file
@@ -0,0 +1,133 @@
|
||||
/* Bra.c -- Converters for RISC code
|
||||
2010-04-16 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Bra.h"
|
||||
|
||||
SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
|
||||
{
|
||||
SizeT i;
|
||||
if (size < 4)
|
||||
return 0;
|
||||
size -= 4;
|
||||
ip += 8;
|
||||
for (i = 0; i <= size; i += 4)
|
||||
{
|
||||
if (data[i + 3] == 0xEB)
|
||||
{
|
||||
UInt32 dest;
|
||||
UInt32 src = ((UInt32)data[i + 2] << 16) | ((UInt32)data[i + 1] << 8) | (data[i + 0]);
|
||||
src <<= 2;
|
||||
if (encoding)
|
||||
dest = ip + (UInt32)i + src;
|
||||
else
|
||||
dest = src - (ip + (UInt32)i);
|
||||
dest >>= 2;
|
||||
data[i + 2] = (Byte)(dest >> 16);
|
||||
data[i + 1] = (Byte)(dest >> 8);
|
||||
data[i + 0] = (Byte)dest;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
|
||||
{
|
||||
SizeT i;
|
||||
if (size < 4)
|
||||
return 0;
|
||||
size -= 4;
|
||||
ip += 4;
|
||||
for (i = 0; i <= size; i += 2)
|
||||
{
|
||||
if ((data[i + 1] & 0xF8) == 0xF0 &&
|
||||
(data[i + 3] & 0xF8) == 0xF8)
|
||||
{
|
||||
UInt32 dest;
|
||||
UInt32 src =
|
||||
(((UInt32)data[i + 1] & 0x7) << 19) |
|
||||
((UInt32)data[i + 0] << 11) |
|
||||
(((UInt32)data[i + 3] & 0x7) << 8) |
|
||||
(data[i + 2]);
|
||||
|
||||
src <<= 1;
|
||||
if (encoding)
|
||||
dest = ip + (UInt32)i + src;
|
||||
else
|
||||
dest = src - (ip + (UInt32)i);
|
||||
dest >>= 1;
|
||||
|
||||
data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7));
|
||||
data[i + 0] = (Byte)(dest >> 11);
|
||||
data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7));
|
||||
data[i + 2] = (Byte)dest;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
|
||||
{
|
||||
SizeT i;
|
||||
if (size < 4)
|
||||
return 0;
|
||||
size -= 4;
|
||||
for (i = 0; i <= size; i += 4)
|
||||
{
|
||||
if ((data[i] >> 2) == 0x12 && (data[i + 3] & 3) == 1)
|
||||
{
|
||||
UInt32 src = ((UInt32)(data[i + 0] & 3) << 24) |
|
||||
((UInt32)data[i + 1] << 16) |
|
||||
((UInt32)data[i + 2] << 8) |
|
||||
((UInt32)data[i + 3] & (~3));
|
||||
|
||||
UInt32 dest;
|
||||
if (encoding)
|
||||
dest = ip + (UInt32)i + src;
|
||||
else
|
||||
dest = src - (ip + (UInt32)i);
|
||||
data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3));
|
||||
data[i + 1] = (Byte)(dest >> 16);
|
||||
data[i + 2] = (Byte)(dest >> 8);
|
||||
data[i + 3] &= 0x3;
|
||||
data[i + 3] |= dest;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
|
||||
{
|
||||
UInt32 i;
|
||||
if (size < 4)
|
||||
return 0;
|
||||
size -= 4;
|
||||
for (i = 0; i <= size; i += 4)
|
||||
{
|
||||
if ((data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00) ||
|
||||
(data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0))
|
||||
{
|
||||
UInt32 src =
|
||||
((UInt32)data[i + 0] << 24) |
|
||||
((UInt32)data[i + 1] << 16) |
|
||||
((UInt32)data[i + 2] << 8) |
|
||||
((UInt32)data[i + 3]);
|
||||
UInt32 dest;
|
||||
|
||||
src <<= 2;
|
||||
if (encoding)
|
||||
dest = ip + i + src;
|
||||
else
|
||||
dest = src - (ip + i);
|
||||
dest >>= 2;
|
||||
|
||||
dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000;
|
||||
|
||||
data[i + 0] = (Byte)(dest >> 24);
|
||||
data[i + 1] = (Byte)(dest >> 16);
|
||||
data[i + 2] = (Byte)(dest >> 8);
|
||||
data[i + 3] = (Byte)dest;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
68
clamav/libclamav/7z/Bra.h
Normal file
68
clamav/libclamav/7z/Bra.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* Bra.h -- Branch converters for executables
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __BRA_H
|
||||
#define __BRA_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
These functions convert relative addresses to absolute addresses
|
||||
in CALL instructions to increase the compression ratio.
|
||||
|
||||
In:
|
||||
data - data buffer
|
||||
size - size of data
|
||||
ip - current virtual Instruction Pinter (IP) value
|
||||
state - state variable for x86 converter
|
||||
encoding - 0 (for decoding), 1 (for encoding)
|
||||
|
||||
Out:
|
||||
state - state variable for x86 converter
|
||||
|
||||
Returns:
|
||||
The number of processed bytes. If you call these functions with multiple calls,
|
||||
you must start next call with first byte after block of processed bytes.
|
||||
|
||||
Type Endian Alignment LookAhead
|
||||
|
||||
x86 little 1 4
|
||||
ARMT little 2 2
|
||||
ARM little 4 0
|
||||
PPC big 4 0
|
||||
SPARC big 4 0
|
||||
IA64 little 16 0
|
||||
|
||||
size must be >= Alignment + LookAhead, if it's not last block.
|
||||
If (size < Alignment + LookAhead), converter returns 0.
|
||||
|
||||
Example:
|
||||
|
||||
UInt32 ip = 0;
|
||||
for ()
|
||||
{
|
||||
; size must be >= Alignment + LookAhead, if it's not last block
|
||||
SizeT processed = Convert(data, size, ip, 1);
|
||||
data += processed;
|
||||
size -= processed;
|
||||
ip += processed;
|
||||
}
|
||||
*/
|
||||
|
||||
#define x86_Convert_Init(state) { state = 0; }
|
||||
SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding);
|
||||
SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
85
clamav/libclamav/7z/Bra86.c
Normal file
85
clamav/libclamav/7z/Bra86.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/* Bra86.c -- Converter for x86 code (BCJ)
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Bra.h"
|
||||
|
||||
#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
|
||||
|
||||
const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
|
||||
const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
|
||||
|
||||
SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding)
|
||||
{
|
||||
SizeT bufferPos = 0, prevPosT;
|
||||
UInt32 prevMask = *state & 0x7;
|
||||
if (size < 5)
|
||||
return 0;
|
||||
ip += 5;
|
||||
prevPosT = (SizeT)0 - 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Byte *p = data + bufferPos;
|
||||
Byte *limit = data + size - 4;
|
||||
for (; p < limit; p++)
|
||||
if ((*p & 0xFE) == 0xE8)
|
||||
break;
|
||||
bufferPos = (SizeT)(p - data);
|
||||
if (p >= limit)
|
||||
break;
|
||||
prevPosT = bufferPos - prevPosT;
|
||||
if (prevPosT > 3)
|
||||
prevMask = 0;
|
||||
else
|
||||
{
|
||||
prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
|
||||
if (prevMask != 0)
|
||||
{
|
||||
Byte b = p[4 - kMaskToBitNumber[prevMask]];
|
||||
if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b))
|
||||
{
|
||||
prevPosT = bufferPos;
|
||||
prevMask = ((prevMask << 1) & 0x7) | 1;
|
||||
bufferPos++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
prevPosT = bufferPos;
|
||||
|
||||
if (Test86MSByte(p[4]))
|
||||
{
|
||||
UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
|
||||
UInt32 dest;
|
||||
for (;;)
|
||||
{
|
||||
Byte b;
|
||||
int index;
|
||||
if (encoding)
|
||||
dest = (ip + (UInt32)bufferPos) + src;
|
||||
else
|
||||
dest = src - (ip + (UInt32)bufferPos);
|
||||
if (prevMask == 0)
|
||||
break;
|
||||
index = kMaskToBitNumber[prevMask] * 8;
|
||||
b = (Byte)(dest >> (24 - index));
|
||||
if (!Test86MSByte(b))
|
||||
break;
|
||||
src = dest ^ ((1 << (32 - index)) - 1);
|
||||
}
|
||||
p[4] = (Byte)(~(((dest >> 24) & 1) - 1));
|
||||
p[3] = (Byte)(dest >> 16);
|
||||
p[2] = (Byte)(dest >> 8);
|
||||
p[1] = (Byte)dest;
|
||||
bufferPos += 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
prevMask = ((prevMask << 1) & 0x7) | 1;
|
||||
bufferPos++;
|
||||
}
|
||||
}
|
||||
prevPosT = bufferPos - prevPosT;
|
||||
*state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7));
|
||||
return bufferPos;
|
||||
}
|
||||
67
clamav/libclamav/7z/BraIA64.c
Normal file
67
clamav/libclamav/7z/BraIA64.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/* BraIA64.c -- Converter for IA-64 code
|
||||
2008-10-04 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Bra.h"
|
||||
|
||||
static const Byte kBranchTable[32] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
4, 4, 6, 6, 0, 0, 7, 7,
|
||||
4, 4, 0, 0, 4, 4, 0, 0
|
||||
};
|
||||
|
||||
SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
|
||||
{
|
||||
SizeT i;
|
||||
if (size < 16)
|
||||
return 0;
|
||||
size -= 16;
|
||||
for (i = 0; i <= size; i += 16)
|
||||
{
|
||||
UInt32 instrTemplate = data[i] & 0x1F;
|
||||
UInt32 mask = kBranchTable[instrTemplate];
|
||||
UInt32 bitPos = 5;
|
||||
int slot;
|
||||
for (slot = 0; slot < 3; slot++, bitPos += 41)
|
||||
{
|
||||
UInt32 bytePos, bitRes;
|
||||
UInt64 instruction, instNorm;
|
||||
int j;
|
||||
if (((mask >> slot) & 1) == 0)
|
||||
continue;
|
||||
bytePos = (bitPos >> 3);
|
||||
bitRes = bitPos & 0x7;
|
||||
instruction = 0;
|
||||
for (j = 0; j < 6; j++)
|
||||
instruction += (UInt64)data[i + j + bytePos] << (8 * j);
|
||||
|
||||
instNorm = instruction >> bitRes;
|
||||
if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0)
|
||||
{
|
||||
UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF);
|
||||
UInt32 dest;
|
||||
src |= ((UInt32)(instNorm >> 36) & 1) << 20;
|
||||
|
||||
src <<= 4;
|
||||
|
||||
if (encoding)
|
||||
dest = ip + (UInt32)i + src;
|
||||
else
|
||||
dest = src - (ip + (UInt32)i);
|
||||
|
||||
dest >>= 4;
|
||||
|
||||
instNorm &= ~((UInt64)(0x8FFFFF) << 13);
|
||||
instNorm |= ((UInt64)(dest & 0xFFFFF) << 13);
|
||||
instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20));
|
||||
|
||||
instruction &= (1 << bitRes) - 1;
|
||||
instruction |= (instNorm << bitRes);
|
||||
for (j = 0; j < 6; j++)
|
||||
data[i + j + bytePos] = (Byte)(instruction >> (8 * j));
|
||||
}
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
173
clamav/libclamav/7z/CpuArch.c
Normal file
173
clamav/libclamav/7z/CpuArch.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/* CpuArch.c -- CPU specific code
|
||||
2010-10-26: Igor Pavlov : Public domain */
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "CpuArch.h"
|
||||
|
||||
#ifdef MY_CPU_X86_OR_AMD64
|
||||
|
||||
#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
|
||||
#define USE_ASM
|
||||
#endif
|
||||
|
||||
#if defined(USE_ASM) && !defined(MY_CPU_AMD64)
|
||||
static UInt32 CheckFlag(UInt32 flag)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
__asm pushfd;
|
||||
__asm pop EAX;
|
||||
__asm mov EDX, EAX;
|
||||
__asm xor EAX, flag;
|
||||
__asm push EAX;
|
||||
__asm popfd;
|
||||
__asm pushfd;
|
||||
__asm pop EAX;
|
||||
__asm xor EAX, EDX;
|
||||
__asm push EDX;
|
||||
__asm popfd;
|
||||
__asm and flag, EAX;
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
"pushf\n\t"
|
||||
"pop %%EAX\n\t"
|
||||
"movl %%EAX,%%EDX\n\t"
|
||||
"xorl %0,%%EAX\n\t"
|
||||
"push %%EAX\n\t"
|
||||
"popf\n\t"
|
||||
"pushf\n\t"
|
||||
"pop %%EAX\n\t"
|
||||
"xorl %%EDX,%%EAX\n\t"
|
||||
"push %%EDX\n\t"
|
||||
"popf\n\t"
|
||||
"andl %%EAX, %0\n\t":
|
||||
"=c" (flag) : "c" (flag));
|
||||
#endif
|
||||
return flag;
|
||||
}
|
||||
#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
|
||||
#else
|
||||
#define CHECK_CPUID_IS_SUPPORTED
|
||||
#endif
|
||||
|
||||
static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
|
||||
{
|
||||
#ifdef USE_ASM
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
UInt32 a2, b2, c2, d2;
|
||||
__asm xor EBX, EBX;
|
||||
__asm xor ECX, ECX;
|
||||
__asm xor EDX, EDX;
|
||||
__asm mov EAX, function;
|
||||
__asm cpuid;
|
||||
__asm mov a2, EAX;
|
||||
__asm mov b2, EBX;
|
||||
__asm mov c2, ECX;
|
||||
__asm mov d2, EDX;
|
||||
|
||||
*a = a2;
|
||||
*b = b2;
|
||||
*c = c2;
|
||||
*d = d2;
|
||||
|
||||
#else
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"cpuid"
|
||||
: "=a" (*a) ,
|
||||
"=b" (*b) ,
|
||||
"=c" (*c) ,
|
||||
"=d" (*d)
|
||||
: "0" (function)) ;
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
int CPUInfo[4];
|
||||
__cpuid(CPUInfo, function);
|
||||
*a = CPUInfo[0];
|
||||
*b = CPUInfo[1];
|
||||
*c = CPUInfo[2];
|
||||
*d = CPUInfo[3];
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
Bool x86cpuid_CheckAndRead(Cx86cpuid *p)
|
||||
{
|
||||
CHECK_CPUID_IS_SUPPORTED
|
||||
MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
|
||||
MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
|
||||
return True;
|
||||
}
|
||||
|
||||
static UInt32 kVendors[][3] =
|
||||
{
|
||||
{ 0x756E6547, 0x49656E69, 0x6C65746E},
|
||||
{ 0x68747541, 0x69746E65, 0x444D4163},
|
||||
{ 0x746E6543, 0x48727561, 0x736C7561}
|
||||
};
|
||||
|
||||
int x86cpuid_GetFirm(const Cx86cpuid *p)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
|
||||
{
|
||||
const UInt32 *v = kVendors[i];
|
||||
if (v[0] == p->vendor[0] &&
|
||||
v[1] == p->vendor[1] &&
|
||||
v[2] == p->vendor[2])
|
||||
return (int)i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Bool CPU_Is_InOrder()
|
||||
{
|
||||
Cx86cpuid p;
|
||||
int firm;
|
||||
UInt32 family, model;
|
||||
if (!x86cpuid_CheckAndRead(&p))
|
||||
return True;
|
||||
family = x86cpuid_GetFamily(&p);
|
||||
model = x86cpuid_GetModel(&p);
|
||||
firm = x86cpuid_GetFirm(&p);
|
||||
switch (firm)
|
||||
{
|
||||
case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && model == 0x100C));
|
||||
case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
|
||||
case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
#if !defined(MY_CPU_AMD64) && defined(_WIN32)
|
||||
static Bool CPU_Sys_Is_SSE_Supported()
|
||||
{
|
||||
OSVERSIONINFO vi;
|
||||
vi.dwOSVersionInfoSize = sizeof(vi);
|
||||
if (!GetVersionEx(&vi))
|
||||
return False;
|
||||
return (vi.dwMajorVersion >= 5);
|
||||
}
|
||||
#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
|
||||
#else
|
||||
#define CHECK_SYS_SSE_SUPPORT
|
||||
#endif
|
||||
|
||||
Bool CPU_Is_Aes_Supported()
|
||||
{
|
||||
Cx86cpuid p;
|
||||
CHECK_SYS_SSE_SUPPORT
|
||||
if (!x86cpuid_CheckAndRead(&p))
|
||||
return False;
|
||||
return (p.c >> 25) & 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
37
clamav/libclamav/7z/CpuArch.h
Normal file
37
clamav/libclamav/7z/CpuArch.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* CpuArch.h -- CPU specific code
|
||||
2010-10-26: Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __CPU_ARCH_H
|
||||
#define __CPU_ARCH_H
|
||||
|
||||
#include "Types.h"
|
||||
#include "others.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
/*
|
||||
MY_CPU_LE means that CPU is LITTLE ENDIAN.
|
||||
If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN).
|
||||
|
||||
MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
|
||||
If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform.
|
||||
*/
|
||||
|
||||
#define GetUi16(p) (cli_readint16(p))
|
||||
#define GetUi32(p) (cli_readint32(p))
|
||||
|
||||
#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
|
||||
|
||||
#define SetUi16(p, d) { UInt32 _x_ = (d); \
|
||||
((Byte *)(p))[0] = (Byte)_x_; \
|
||||
((Byte *)(p))[1] = (Byte)(_x_ >> 8); }
|
||||
|
||||
#define SetUi32(p, d) (cli_writeint32(p, d))
|
||||
|
||||
#define SetUi64(p, d) { UInt64 _x64_ = (d); \
|
||||
SetUi32(p, (UInt32)_x64_); \
|
||||
SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); }
|
||||
|
||||
#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])
|
||||
|
||||
#endif
|
||||
62
clamav/libclamav/7z/Delta.c
Normal file
62
clamav/libclamav/7z/Delta.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/* Delta.c -- Delta converter
|
||||
2009-05-26 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "Delta.h"
|
||||
|
||||
void Delta_Init(Byte *state)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < DELTA_STATE_SIZE; i++)
|
||||
state[i] = 0;
|
||||
}
|
||||
|
||||
static void MyMemCpy(Byte *dest, const Byte *src, unsigned size)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < size; i++)
|
||||
dest[i] = src[i];
|
||||
}
|
||||
|
||||
void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size)
|
||||
{
|
||||
Byte buf[DELTA_STATE_SIZE];
|
||||
unsigned j = 0;
|
||||
MyMemCpy(buf, state, delta);
|
||||
{
|
||||
SizeT i;
|
||||
for (i = 0; i < size;)
|
||||
{
|
||||
for (j = 0; j < delta && i < size; i++, j++)
|
||||
{
|
||||
Byte b = data[i];
|
||||
data[i] = (Byte)(b - buf[j]);
|
||||
buf[j] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j == delta)
|
||||
j = 0;
|
||||
MyMemCpy(state, buf + j, delta - j);
|
||||
MyMemCpy(state + delta - j, buf, j);
|
||||
}
|
||||
|
||||
void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size)
|
||||
{
|
||||
Byte buf[DELTA_STATE_SIZE];
|
||||
unsigned j = 0;
|
||||
MyMemCpy(buf, state, delta);
|
||||
{
|
||||
SizeT i;
|
||||
for (i = 0; i < size;)
|
||||
{
|
||||
for (j = 0; j < delta && i < size; i++, j++)
|
||||
{
|
||||
buf[j] = data[i] = (Byte)(buf[j] + data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j == delta)
|
||||
j = 0;
|
||||
MyMemCpy(state, buf + j, delta - j);
|
||||
MyMemCpy(state + delta - j, buf, j);
|
||||
}
|
||||
23
clamav/libclamav/7z/Delta.h
Normal file
23
clamav/libclamav/7z/Delta.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/* Delta.h -- Delta converter
|
||||
2009-04-15 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __DELTA_H
|
||||
#define __DELTA_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DELTA_STATE_SIZE 256
|
||||
|
||||
void Delta_Init(Byte *state);
|
||||
void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size);
|
||||
void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
356
clamav/libclamav/7z/Lzma2Dec.c
Normal file
356
clamav/libclamav/7z/Lzma2Dec.c
Normal file
@@ -0,0 +1,356 @@
|
||||
/* Lzma2Dec.c -- LZMA2 Decoder
|
||||
2009-05-03 : Igor Pavlov : Public domain */
|
||||
|
||||
/* #define SHOW_DEBUG_INFO */
|
||||
|
||||
#ifdef SHOW_DEBUG_INFO
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Lzma2Dec.h"
|
||||
|
||||
/*
|
||||
00000000 - EOS
|
||||
00000001 U U - Uncompressed Reset Dic
|
||||
00000010 U U - Uncompressed No Reset
|
||||
100uuuuu U U P P - LZMA no reset
|
||||
101uuuuu U U P P - LZMA reset state
|
||||
110uuuuu U U P P S - LZMA reset state + new prop
|
||||
111uuuuu U U P P S - LZMA reset state + new prop + reset dic
|
||||
|
||||
u, U - Unpack Size
|
||||
P - Pack Size
|
||||
S - Props
|
||||
*/
|
||||
|
||||
#define LZMA2_CONTROL_LZMA (1 << 7)
|
||||
#define LZMA2_CONTROL_COPY_NO_RESET 2
|
||||
#define LZMA2_CONTROL_COPY_RESET_DIC 1
|
||||
#define LZMA2_CONTROL_EOF 0
|
||||
|
||||
#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & LZMA2_CONTROL_LZMA) == 0)
|
||||
|
||||
#define LZMA2_GET_LZMA_MODE(p) (((p)->control >> 5) & 3)
|
||||
#define LZMA2_IS_THERE_PROP(mode) ((mode) >= 2)
|
||||
|
||||
#define LZMA2_LCLP_MAX 4
|
||||
#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))
|
||||
|
||||
#ifdef SHOW_DEBUG_INFO
|
||||
#define PRF(x) x
|
||||
#else
|
||||
#define PRF(x)
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LZMA2_STATE_CONTROL,
|
||||
LZMA2_STATE_UNPACK0,
|
||||
LZMA2_STATE_UNPACK1,
|
||||
LZMA2_STATE_PACK0,
|
||||
LZMA2_STATE_PACK1,
|
||||
LZMA2_STATE_PROP,
|
||||
LZMA2_STATE_DATA,
|
||||
LZMA2_STATE_DATA_CONT,
|
||||
LZMA2_STATE_FINISHED,
|
||||
LZMA2_STATE_ERROR
|
||||
} ELzma2State;
|
||||
|
||||
static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props)
|
||||
{
|
||||
UInt32 dicSize;
|
||||
if (prop > 40)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop);
|
||||
props[0] = (Byte)LZMA2_LCLP_MAX;
|
||||
props[1] = (Byte)(dicSize);
|
||||
props[2] = (Byte)(dicSize >> 8);
|
||||
props[3] = (Byte)(dicSize >> 16);
|
||||
props[4] = (Byte)(dicSize >> 24);
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc)
|
||||
{
|
||||
Byte props[LZMA_PROPS_SIZE];
|
||||
RINOK(Lzma2Dec_GetOldProps(prop, props));
|
||||
return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
|
||||
}
|
||||
|
||||
SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc)
|
||||
{
|
||||
Byte props[LZMA_PROPS_SIZE];
|
||||
RINOK(Lzma2Dec_GetOldProps(prop, props));
|
||||
return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
|
||||
}
|
||||
|
||||
void Lzma2Dec_Init(CLzma2Dec *p)
|
||||
{
|
||||
p->state = LZMA2_STATE_CONTROL;
|
||||
p->needInitDic = True;
|
||||
p->needInitState = True;
|
||||
p->needInitProp = True;
|
||||
LzmaDec_Init(&p->decoder);
|
||||
}
|
||||
|
||||
static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b)
|
||||
{
|
||||
switch(p->state)
|
||||
{
|
||||
case LZMA2_STATE_CONTROL:
|
||||
p->control = b;
|
||||
PRF(printf("\n %4X ", p->decoder.dicPos));
|
||||
PRF(printf(" %2X", b));
|
||||
if (p->control == 0)
|
||||
return LZMA2_STATE_FINISHED;
|
||||
if (LZMA2_IS_UNCOMPRESSED_STATE(p))
|
||||
{
|
||||
if ((p->control & 0x7F) > 2)
|
||||
return LZMA2_STATE_ERROR;
|
||||
p->unpackSize = 0;
|
||||
}
|
||||
else
|
||||
p->unpackSize = (UInt32)(p->control & 0x1F) << 16;
|
||||
return LZMA2_STATE_UNPACK0;
|
||||
|
||||
case LZMA2_STATE_UNPACK0:
|
||||
p->unpackSize |= (UInt32)b << 8;
|
||||
return LZMA2_STATE_UNPACK1;
|
||||
|
||||
case LZMA2_STATE_UNPACK1:
|
||||
p->unpackSize |= (UInt32)b;
|
||||
p->unpackSize++;
|
||||
PRF(printf(" %8d", p->unpackSize));
|
||||
return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0;
|
||||
|
||||
case LZMA2_STATE_PACK0:
|
||||
p->packSize = (UInt32)b << 8;
|
||||
return LZMA2_STATE_PACK1;
|
||||
|
||||
case LZMA2_STATE_PACK1:
|
||||
p->packSize |= (UInt32)b;
|
||||
p->packSize++;
|
||||
PRF(printf(" %8d", p->packSize));
|
||||
return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP:
|
||||
(p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA);
|
||||
|
||||
case LZMA2_STATE_PROP:
|
||||
{
|
||||
int lc, lp;
|
||||
if (b >= (9 * 5 * 5))
|
||||
return LZMA2_STATE_ERROR;
|
||||
lc = b % 9;
|
||||
b /= 9;
|
||||
p->decoder.prop.pb = b / 5;
|
||||
lp = b % 5;
|
||||
if (lc + lp > LZMA2_LCLP_MAX)
|
||||
return LZMA2_STATE_ERROR;
|
||||
p->decoder.prop.lc = lc;
|
||||
p->decoder.prop.lp = lp;
|
||||
p->needInitProp = False;
|
||||
return LZMA2_STATE_DATA;
|
||||
}
|
||||
}
|
||||
return LZMA2_STATE_ERROR;
|
||||
}
|
||||
|
||||
static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size)
|
||||
{
|
||||
memcpy(p->dic + p->dicPos, src, size);
|
||||
p->dicPos += size;
|
||||
if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size)
|
||||
p->checkDicSize = p->prop.dicSize;
|
||||
p->processedPos += (UInt32)size;
|
||||
}
|
||||
|
||||
void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState);
|
||||
|
||||
SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
|
||||
{
|
||||
SizeT inSize = *srcLen;
|
||||
*srcLen = 0;
|
||||
*status = LZMA_STATUS_NOT_SPECIFIED;
|
||||
|
||||
while (p->state != LZMA2_STATE_FINISHED)
|
||||
{
|
||||
SizeT dicPos = p->decoder.dicPos;
|
||||
if (p->state == LZMA2_STATE_ERROR)
|
||||
return SZ_ERROR_DATA;
|
||||
if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY)
|
||||
{
|
||||
*status = LZMA_STATUS_NOT_FINISHED;
|
||||
return SZ_OK;
|
||||
}
|
||||
if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT)
|
||||
{
|
||||
if (*srcLen == inSize)
|
||||
{
|
||||
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||
return SZ_OK;
|
||||
}
|
||||
(*srcLen)++;
|
||||
p->state = Lzma2Dec_UpdateState(p, *src++);
|
||||
continue;
|
||||
}
|
||||
{
|
||||
SizeT destSizeCur = dicLimit - dicPos;
|
||||
SizeT srcSizeCur = inSize - *srcLen;
|
||||
ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY;
|
||||
|
||||
if (p->unpackSize <= destSizeCur)
|
||||
{
|
||||
destSizeCur = (SizeT)p->unpackSize;
|
||||
curFinishMode = LZMA_FINISH_END;
|
||||
}
|
||||
|
||||
if (LZMA2_IS_UNCOMPRESSED_STATE(p))
|
||||
{
|
||||
if (*srcLen == inSize)
|
||||
{
|
||||
*status = LZMA_STATUS_NEEDS_MORE_INPUT;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
if (p->state == LZMA2_STATE_DATA)
|
||||
{
|
||||
Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC);
|
||||
if (initDic)
|
||||
p->needInitProp = p->needInitState = True;
|
||||
else if (p->needInitDic)
|
||||
return SZ_ERROR_DATA;
|
||||
p->needInitDic = False;
|
||||
LzmaDec_InitDicAndState(&p->decoder, initDic, False);
|
||||
}
|
||||
|
||||
if (srcSizeCur > destSizeCur)
|
||||
srcSizeCur = destSizeCur;
|
||||
|
||||
if (srcSizeCur == 0)
|
||||
return SZ_ERROR_DATA;
|
||||
|
||||
LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur);
|
||||
|
||||
src += srcSizeCur;
|
||||
*srcLen += srcSizeCur;
|
||||
p->unpackSize -= (UInt32)srcSizeCur;
|
||||
p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT;
|
||||
}
|
||||
else
|
||||
{
|
||||
SizeT outSizeProcessed;
|
||||
SRes res;
|
||||
|
||||
if (p->state == LZMA2_STATE_DATA)
|
||||
{
|
||||
int mode = LZMA2_GET_LZMA_MODE(p);
|
||||
Bool initDic = (mode == 3);
|
||||
Bool initState = (mode > 0);
|
||||
if ((!initDic && p->needInitDic) || (!initState && p->needInitState))
|
||||
return SZ_ERROR_DATA;
|
||||
|
||||
LzmaDec_InitDicAndState(&p->decoder, initDic, initState);
|
||||
p->needInitDic = False;
|
||||
p->needInitState = False;
|
||||
p->state = LZMA2_STATE_DATA_CONT;
|
||||
}
|
||||
if (srcSizeCur > p->packSize)
|
||||
srcSizeCur = (SizeT)p->packSize;
|
||||
|
||||
res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status);
|
||||
|
||||
src += srcSizeCur;
|
||||
*srcLen += srcSizeCur;
|
||||
p->packSize -= (UInt32)srcSizeCur;
|
||||
|
||||
outSizeProcessed = p->decoder.dicPos - dicPos;
|
||||
p->unpackSize -= (UInt32)outSizeProcessed;
|
||||
|
||||
RINOK(res);
|
||||
if (*status == LZMA_STATUS_NEEDS_MORE_INPUT)
|
||||
return res;
|
||||
|
||||
if (srcSizeCur == 0 && outSizeProcessed == 0)
|
||||
{
|
||||
if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ||
|
||||
p->unpackSize != 0 || p->packSize != 0)
|
||||
return SZ_ERROR_DATA;
|
||||
p->state = LZMA2_STATE_CONTROL;
|
||||
}
|
||||
if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
|
||||
*status = LZMA_STATUS_NOT_FINISHED;
|
||||
}
|
||||
}
|
||||
}
|
||||
*status = LZMA_STATUS_FINISHED_WITH_MARK;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
|
||||
{
|
||||
SizeT outSize = *destLen, inSize = *srcLen;
|
||||
*srcLen = *destLen = 0;
|
||||
for (;;)
|
||||
{
|
||||
SizeT srcSizeCur = inSize, outSizeCur, dicPos;
|
||||
ELzmaFinishMode curFinishMode;
|
||||
SRes res;
|
||||
if (p->decoder.dicPos == p->decoder.dicBufSize)
|
||||
p->decoder.dicPos = 0;
|
||||
dicPos = p->decoder.dicPos;
|
||||
if (outSize > p->decoder.dicBufSize - dicPos)
|
||||
{
|
||||
outSizeCur = p->decoder.dicBufSize;
|
||||
curFinishMode = LZMA_FINISH_ANY;
|
||||
}
|
||||
else
|
||||
{
|
||||
outSizeCur = dicPos + outSize;
|
||||
curFinishMode = finishMode;
|
||||
}
|
||||
|
||||
res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status);
|
||||
src += srcSizeCur;
|
||||
inSize -= srcSizeCur;
|
||||
*srcLen += srcSizeCur;
|
||||
outSizeCur = p->decoder.dicPos - dicPos;
|
||||
memcpy(dest, p->decoder.dic + dicPos, outSizeCur);
|
||||
dest += outSizeCur;
|
||||
outSize -= outSizeCur;
|
||||
*destLen += outSizeCur;
|
||||
if (res != 0)
|
||||
return res;
|
||||
if (outSizeCur == 0 || outSize == 0)
|
||||
return SZ_OK;
|
||||
}
|
||||
}
|
||||
|
||||
SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc)
|
||||
{
|
||||
CLzma2Dec decoder;
|
||||
SRes res;
|
||||
SizeT outSize = *destLen, inSize = *srcLen;
|
||||
Byte props[LZMA_PROPS_SIZE];
|
||||
|
||||
Lzma2Dec_Construct(&decoder);
|
||||
|
||||
*destLen = *srcLen = 0;
|
||||
*status = LZMA_STATUS_NOT_SPECIFIED;
|
||||
decoder.decoder.dic = dest;
|
||||
decoder.decoder.dicBufSize = outSize;
|
||||
|
||||
RINOK(Lzma2Dec_GetOldProps(prop, props));
|
||||
RINOK(LzmaDec_AllocateProbs(&decoder.decoder, props, LZMA_PROPS_SIZE, alloc));
|
||||
|
||||
*srcLen = inSize;
|
||||
res = Lzma2Dec_DecodeToDic(&decoder, outSize, src, srcLen, finishMode, status);
|
||||
*destLen = decoder.decoder.dicPos;
|
||||
if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
|
||||
res = SZ_ERROR_INPUT_EOF;
|
||||
|
||||
LzmaDec_FreeProbs(&decoder.decoder, alloc);
|
||||
return res;
|
||||
}
|
||||
84
clamav/libclamav/7z/Lzma2Dec.h
Normal file
84
clamav/libclamav/7z/Lzma2Dec.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/* Lzma2Dec.h -- LZMA2 Decoder
|
||||
2009-05-03 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __LZMA2_DEC_H
|
||||
#define __LZMA2_DEC_H
|
||||
|
||||
#include "LzmaDec.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ---------- State Interface ---------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CLzmaDec decoder;
|
||||
UInt32 packSize;
|
||||
UInt32 unpackSize;
|
||||
int state;
|
||||
Byte control;
|
||||
Bool needInitDic;
|
||||
Bool needInitState;
|
||||
Bool needInitProp;
|
||||
} CLzma2Dec;
|
||||
|
||||
#define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder)
|
||||
#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc);
|
||||
#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc);
|
||||
|
||||
SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc);
|
||||
SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc);
|
||||
void Lzma2Dec_Init(CLzma2Dec *p);
|
||||
|
||||
|
||||
/*
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (*destLen or dicLimit).
|
||||
LZMA_FINISH_ANY - use smallest number of input bytes
|
||||
LZMA_FINISH_END - read EndOfStream marker after decoding
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
status:
|
||||
LZMA_STATUS_FINISHED_WITH_MARK
|
||||
LZMA_STATUS_NOT_FINISHED
|
||||
LZMA_STATUS_NEEDS_MORE_INPUT
|
||||
SZ_ERROR_DATA - Data error
|
||||
*/
|
||||
|
||||
SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||
|
||||
SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||
|
||||
|
||||
/* ---------- One Call Interface ---------- */
|
||||
|
||||
/*
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (*destLen).
|
||||
LZMA_FINISH_ANY - use smallest number of input bytes
|
||||
LZMA_FINISH_END - read EndOfStream marker after decoding
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
status:
|
||||
LZMA_STATUS_FINISHED_WITH_MARK
|
||||
LZMA_STATUS_NOT_FINISHED
|
||||
SZ_ERROR_DATA - Data error
|
||||
SZ_ERROR_MEM - Memory allocation error
|
||||
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||
SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
|
||||
*/
|
||||
|
||||
SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1001
clamav/libclamav/7z/LzmaDec.c
Normal file
1001
clamav/libclamav/7z/LzmaDec.c
Normal file
File diff suppressed because it is too large
Load Diff
231
clamav/libclamav/7z/LzmaDec.h
Normal file
231
clamav/libclamav/7z/LzmaDec.h
Normal file
@@ -0,0 +1,231 @@
|
||||
/* LzmaDec.h -- LZMA Decoder
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __LZMA_DEC_H
|
||||
#define __LZMA_DEC_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* #define _LZMA_PROB32 */
|
||||
/* _LZMA_PROB32 can increase the speed on some CPUs,
|
||||
but memory usage for CLzmaDec::probs will be doubled in that case */
|
||||
|
||||
#ifdef _LZMA_PROB32
|
||||
#define CLzmaProb UInt32
|
||||
#else
|
||||
#define CLzmaProb UInt16
|
||||
#endif
|
||||
|
||||
|
||||
/* ---------- LZMA Properties ---------- */
|
||||
|
||||
#define LZMA_PROPS_SIZE 5
|
||||
|
||||
typedef struct _CLzmaProps
|
||||
{
|
||||
unsigned lc, lp, pb;
|
||||
UInt32 dicSize;
|
||||
} CLzmaProps;
|
||||
|
||||
/* LzmaProps_Decode - decodes properties
|
||||
Returns:
|
||||
SZ_OK
|
||||
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||
*/
|
||||
|
||||
SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
|
||||
|
||||
|
||||
/* ---------- LZMA Decoder state ---------- */
|
||||
|
||||
/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
|
||||
Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
|
||||
|
||||
#define LZMA_REQUIRED_INPUT_MAX 20
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CLzmaProps prop;
|
||||
CLzmaProb *probs;
|
||||
Byte *dic;
|
||||
const Byte *buf;
|
||||
UInt32 range, code;
|
||||
SizeT dicPos;
|
||||
SizeT dicBufSize;
|
||||
UInt32 processedPos;
|
||||
UInt32 checkDicSize;
|
||||
unsigned state;
|
||||
UInt32 reps[4];
|
||||
unsigned remainLen;
|
||||
int needFlush;
|
||||
int needInitState;
|
||||
UInt32 numProbs;
|
||||
unsigned tempBufSize;
|
||||
Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
|
||||
} CLzmaDec;
|
||||
|
||||
#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
|
||||
|
||||
void LzmaDec_Init(CLzmaDec *p);
|
||||
|
||||
/* There are two types of LZMA streams:
|
||||
0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
|
||||
1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LZMA_FINISH_ANY, /* finish at any point */
|
||||
LZMA_FINISH_END /* block must be finished at the end */
|
||||
} ELzmaFinishMode;
|
||||
|
||||
/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
|
||||
|
||||
You must use LZMA_FINISH_END, when you know that current output buffer
|
||||
covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
|
||||
|
||||
If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
|
||||
and output value of destLen will be less than output buffer size limit.
|
||||
You can check status result also.
|
||||
|
||||
You can use multiple checks to test data integrity after full decompression:
|
||||
1) Check Result and "status" variable.
|
||||
2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
|
||||
3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
|
||||
You must use correct finish mode in that case. */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
|
||||
LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
|
||||
LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
|
||||
LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
|
||||
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
|
||||
} ELzmaStatus;
|
||||
|
||||
/* ELzmaStatus is used only as output value for function call */
|
||||
|
||||
|
||||
/* ---------- Interfaces ---------- */
|
||||
|
||||
/* There are 3 levels of interfaces:
|
||||
1) Dictionary Interface
|
||||
2) Buffer Interface
|
||||
3) One Call Interface
|
||||
You can select any of these interfaces, but don't mix functions from different
|
||||
groups for same object. */
|
||||
|
||||
|
||||
/* There are two variants to allocate state for Dictionary Interface:
|
||||
1) LzmaDec_Allocate / LzmaDec_Free
|
||||
2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
|
||||
You can use variant 2, if you set dictionary buffer manually.
|
||||
For Buffer Interface you must always use variant 1.
|
||||
|
||||
LzmaDec_Allocate* can return:
|
||||
SZ_OK
|
||||
SZ_ERROR_MEM - Memory allocation error
|
||||
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||
*/
|
||||
|
||||
SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
|
||||
void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
|
||||
|
||||
SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
|
||||
void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
|
||||
|
||||
/* ---------- Dictionary Interface ---------- */
|
||||
|
||||
/* You can use it, if you want to eliminate the overhead for data copying from
|
||||
dictionary to some other external buffer.
|
||||
You must work with CLzmaDec variables directly in this interface.
|
||||
|
||||
STEPS:
|
||||
LzmaDec_Constr()
|
||||
LzmaDec_Allocate()
|
||||
for (each new stream)
|
||||
{
|
||||
LzmaDec_Init()
|
||||
while (it needs more decompression)
|
||||
{
|
||||
LzmaDec_DecodeToDic()
|
||||
use data from CLzmaDec::dic and update CLzmaDec::dicPos
|
||||
}
|
||||
}
|
||||
LzmaDec_Free()
|
||||
*/
|
||||
|
||||
/* LzmaDec_DecodeToDic
|
||||
|
||||
The decoding to internal dictionary buffer (CLzmaDec::dic).
|
||||
You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
|
||||
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (dicLimit).
|
||||
LZMA_FINISH_ANY - Decode just dicLimit bytes.
|
||||
LZMA_FINISH_END - Stream must be finished after dicLimit.
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
status:
|
||||
LZMA_STATUS_FINISHED_WITH_MARK
|
||||
LZMA_STATUS_NOT_FINISHED
|
||||
LZMA_STATUS_NEEDS_MORE_INPUT
|
||||
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
|
||||
SZ_ERROR_DATA - Data error
|
||||
*/
|
||||
|
||||
SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||
|
||||
|
||||
/* ---------- Buffer Interface ---------- */
|
||||
|
||||
/* It's zlib-like interface.
|
||||
See LzmaDec_DecodeToDic description for information about STEPS and return results,
|
||||
but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
|
||||
to work with CLzmaDec variables manually.
|
||||
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (*destLen).
|
||||
LZMA_FINISH_ANY - Decode just destLen bytes.
|
||||
LZMA_FINISH_END - Stream must be finished after (*destLen).
|
||||
*/
|
||||
|
||||
SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
|
||||
const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
|
||||
|
||||
|
||||
/* ---------- One Call Interface ---------- */
|
||||
|
||||
/* LzmaDecode
|
||||
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (*destLen).
|
||||
LZMA_FINISH_ANY - Decode just destLen bytes.
|
||||
LZMA_FINISH_END - Stream must be finished after (*destLen).
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
status:
|
||||
LZMA_STATUS_FINISHED_WITH_MARK
|
||||
LZMA_STATUS_NOT_FINISHED
|
||||
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
|
||||
SZ_ERROR_DATA - Data error
|
||||
SZ_ERROR_MEM - Memory allocation error
|
||||
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||
SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
|
||||
*/
|
||||
|
||||
SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
|
||||
ELzmaStatus *status, ISzAlloc *alloc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
81
clamav/libclamav/7z/Ppmd.h
Normal file
81
clamav/libclamav/7z/Ppmd.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/* Ppmd.h -- PPMD codec common code
|
||||
2010-03-12 : Igor Pavlov : Public domain
|
||||
This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
|
||||
|
||||
#ifndef __PPMD_H
|
||||
#define __PPMD_H
|
||||
|
||||
#include "Types.h"
|
||||
#include "CpuArch.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#ifdef MY_CPU_32BIT
|
||||
#define PPMD_32BIT
|
||||
#endif
|
||||
|
||||
#define PPMD_INT_BITS 7
|
||||
#define PPMD_PERIOD_BITS 7
|
||||
#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS))
|
||||
|
||||
#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift))
|
||||
#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2)
|
||||
#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob))
|
||||
#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob))
|
||||
|
||||
#define PPMD_N1 4
|
||||
#define PPMD_N2 4
|
||||
#define PPMD_N3 4
|
||||
#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4)
|
||||
#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4)
|
||||
|
||||
/* SEE-contexts for PPM-contexts with masked symbols */
|
||||
typedef struct
|
||||
{
|
||||
UInt16 Summ; /* Freq */
|
||||
Byte Shift; /* Speed of Freq change; low Shift is for fast change */
|
||||
Byte Count; /* Count to next change of Shift */
|
||||
} CPpmd_See;
|
||||
|
||||
#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \
|
||||
{ (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); }
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte Symbol;
|
||||
Byte Freq;
|
||||
UInt16 SuccessorLow;
|
||||
UInt16 SuccessorHigh;
|
||||
} CPpmd_State;
|
||||
|
||||
typedef
|
||||
#ifdef PPMD_32BIT
|
||||
CPpmd_State *
|
||||
#else
|
||||
UInt32
|
||||
#endif
|
||||
CPpmd_State_Ref;
|
||||
|
||||
typedef
|
||||
#ifdef PPMD_32BIT
|
||||
void *
|
||||
#else
|
||||
UInt32
|
||||
#endif
|
||||
CPpmd_Void_Ref;
|
||||
|
||||
typedef
|
||||
#ifdef PPMD_32BIT
|
||||
Byte *
|
||||
#else
|
||||
UInt32
|
||||
#endif
|
||||
CPpmd_Byte_Ref;
|
||||
|
||||
#define PPMD_SetAllBitsIn256Bytes(p) \
|
||||
{ unsigned i; for (i = 0; i < 256 / sizeof(p[0]); i += 8) { \
|
||||
p[i+7] = p[i+6] = p[i+5] = p[i+4] = p[i+3] = p[i+2] = p[i+1] = p[i+0] = ~(size_t)0; }}
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
713
clamav/libclamav/7z/Ppmd7.c
Normal file
713
clamav/libclamav/7z/Ppmd7.c
Normal file
@@ -0,0 +1,713 @@
|
||||
/* Ppmd7.c -- PPMdH codec
|
||||
2010-03-12 : Igor Pavlov : Public domain
|
||||
This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#include "Ppmd7.h"
|
||||
|
||||
const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
|
||||
static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
|
||||
|
||||
#define MAX_FREQ 124
|
||||
#define UNIT_SIZE 12
|
||||
|
||||
#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
|
||||
#define U2I(nu) (p->Units2Indx[(nu) - 1])
|
||||
#define I2U(indx) (p->Indx2Units[indx])
|
||||
|
||||
#ifdef PPMD_32BIT
|
||||
#define REF(ptr) (ptr)
|
||||
#else
|
||||
#define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
|
||||
#endif
|
||||
|
||||
#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
|
||||
|
||||
#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
|
||||
#define STATS(ctx) Ppmd7_GetStats(p, ctx)
|
||||
#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx)
|
||||
#define SUFFIX(ctx) CTX((ctx)->Suffix)
|
||||
|
||||
typedef CPpmd7_Context * CTX_PTR;
|
||||
|
||||
struct CPpmd7_Node_;
|
||||
|
||||
typedef
|
||||
#ifdef PPMD_32BIT
|
||||
struct CPpmd7_Node_ *
|
||||
#else
|
||||
UInt32
|
||||
#endif
|
||||
CPpmd7_Node_Ref;
|
||||
|
||||
typedef struct CPpmd7_Node_
|
||||
{
|
||||
UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */
|
||||
UInt16 NU;
|
||||
CPpmd7_Node_Ref Next; /* must be at offset >= 4 */
|
||||
CPpmd7_Node_Ref Prev;
|
||||
} CPpmd7_Node;
|
||||
|
||||
union NodeOrRef {
|
||||
CPpmd7_Node node;
|
||||
CPpmd7_Node_Ref ref;
|
||||
};
|
||||
|
||||
#ifdef PPMD_32BIT
|
||||
#define NODE(ptr) (ptr)
|
||||
#else
|
||||
#define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs)))
|
||||
#endif
|
||||
|
||||
void Ppmd7_Construct(CPpmd7 *p)
|
||||
{
|
||||
unsigned i, k, m;
|
||||
|
||||
p->Base = 0;
|
||||
|
||||
for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
|
||||
{
|
||||
unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
|
||||
do { p->Units2Indx[k++] = (Byte)i; } while(--step);
|
||||
p->Indx2Units[i] = (Byte)k;
|
||||
}
|
||||
|
||||
p->NS2BSIndx[0] = (0 << 1);
|
||||
p->NS2BSIndx[1] = (1 << 1);
|
||||
memset(p->NS2BSIndx + 2, (2 << 1), 9);
|
||||
memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
p->NS2Indx[i] = (Byte)i;
|
||||
for (m = i, k = 1; i < 256; i++)
|
||||
{
|
||||
p->NS2Indx[i] = (Byte)m;
|
||||
if (--k == 0)
|
||||
k = (++m) - 2;
|
||||
}
|
||||
|
||||
memset(p->HB2Flag, 0, 0x40);
|
||||
memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40);
|
||||
}
|
||||
|
||||
void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc)
|
||||
{
|
||||
alloc->Free(alloc, p->Base);
|
||||
p->Size = 0;
|
||||
p->Base = 0;
|
||||
}
|
||||
|
||||
Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc)
|
||||
{
|
||||
if (p->Base == 0 || p->Size != size)
|
||||
{
|
||||
Ppmd7_Free(p, alloc);
|
||||
p->AlignOffset =
|
||||
#ifdef PPMD_32BIT
|
||||
(4 - size) & 3;
|
||||
#else
|
||||
4 - (size & 3);
|
||||
#endif
|
||||
if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size
|
||||
#ifndef PPMD_32BIT
|
||||
+ UNIT_SIZE
|
||||
#endif
|
||||
)) == 0)
|
||||
return False;
|
||||
p->Size = size;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
static void InsertNode(CPpmd7 *p, void *node, unsigned indx)
|
||||
{
|
||||
*((CPpmd_Void_Ref *)node) = p->FreeList[indx];
|
||||
p->FreeList[indx] = REF(node);
|
||||
}
|
||||
|
||||
static void *RemoveNode(CPpmd7 *p, unsigned indx)
|
||||
{
|
||||
CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]);
|
||||
p->FreeList[indx] = *node;
|
||||
return node;
|
||||
}
|
||||
|
||||
static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
|
||||
{
|
||||
unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
|
||||
ptr = (Byte *)ptr + U2B(I2U(newIndx));
|
||||
if (I2U(i = U2I(nu)) != nu)
|
||||
{
|
||||
unsigned k = I2U(--i);
|
||||
InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
|
||||
}
|
||||
InsertNode(p, ptr, i);
|
||||
}
|
||||
|
||||
static void GlueFreeBlocks(CPpmd7 *p)
|
||||
{
|
||||
#ifdef PPMD_32BIT
|
||||
CPpmd7_Node headItem;
|
||||
CPpmd7_Node_Ref head = &headItem;
|
||||
#else
|
||||
CPpmd7_Node_Ref head = p->AlignOffset + p->Size;
|
||||
#endif
|
||||
|
||||
CPpmd7_Node_Ref n = head;
|
||||
unsigned i;
|
||||
|
||||
p->GlueCount = 255;
|
||||
|
||||
/* create doubly-linked list of free blocks */
|
||||
for (i = 0; i < PPMD_NUM_INDEXES; i++)
|
||||
{
|
||||
UInt16 nu = I2U(i);
|
||||
CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i];
|
||||
p->FreeList[i] = 0;
|
||||
while (next != 0)
|
||||
{
|
||||
CPpmd7_Node *node = NODE(next);
|
||||
node->Next = n;
|
||||
n = NODE(n)->Prev = next;
|
||||
next = ((const union NodeOrRef *)node)->ref;
|
||||
node->Stamp = 0;
|
||||
node->NU = (UInt16)nu;
|
||||
}
|
||||
}
|
||||
NODE(head)->Stamp = 1;
|
||||
NODE(head)->Next = n;
|
||||
NODE(n)->Prev = head;
|
||||
if (p->LoUnit != p->HiUnit)
|
||||
((CPpmd7_Node *)p->LoUnit)->Stamp = 1;
|
||||
|
||||
/* Glue free blocks */
|
||||
while (n != head)
|
||||
{
|
||||
CPpmd7_Node *node = NODE(n);
|
||||
UInt32 nu = (UInt32)node->NU;
|
||||
for (;;)
|
||||
{
|
||||
CPpmd7_Node *node2 = NODE(n) + nu;
|
||||
nu += node2->NU;
|
||||
if (node2->Stamp != 0 || nu >= 0x10000)
|
||||
break;
|
||||
NODE(node2->Prev)->Next = node2->Next;
|
||||
NODE(node2->Next)->Prev = node2->Prev;
|
||||
node->NU = (UInt16)nu;
|
||||
}
|
||||
n = node->Next;
|
||||
}
|
||||
|
||||
/* Fill lists of free blocks */
|
||||
for (n = NODE(head)->Next; n != head;)
|
||||
{
|
||||
CPpmd7_Node *node = NODE(n);
|
||||
unsigned nu;
|
||||
CPpmd7_Node_Ref next = node->Next;
|
||||
for (nu = node->NU; nu > 128; nu -= 128, node += 128)
|
||||
InsertNode(p, node, PPMD_NUM_INDEXES - 1);
|
||||
if (I2U(i = U2I(nu)) != nu)
|
||||
{
|
||||
unsigned k = I2U(--i);
|
||||
InsertNode(p, node + k, nu - k - 1);
|
||||
}
|
||||
InsertNode(p, node, i);
|
||||
n = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void *AllocUnitsRare(CPpmd7 *p, unsigned indx)
|
||||
{
|
||||
unsigned i;
|
||||
void *retVal;
|
||||
if (p->GlueCount == 0)
|
||||
{
|
||||
GlueFreeBlocks(p);
|
||||
if (p->FreeList[indx] != 0)
|
||||
return RemoveNode(p, indx);
|
||||
}
|
||||
i = indx;
|
||||
do
|
||||
{
|
||||
if (++i == PPMD_NUM_INDEXES)
|
||||
{
|
||||
UInt32 numBytes = U2B(I2U(indx));
|
||||
p->GlueCount--;
|
||||
return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);
|
||||
}
|
||||
}
|
||||
while (p->FreeList[i] == 0);
|
||||
retVal = RemoveNode(p, i);
|
||||
SplitBlock(p, retVal, i, indx);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static void *AllocUnits(CPpmd7 *p, unsigned indx)
|
||||
{
|
||||
UInt32 numBytes;
|
||||
if (p->FreeList[indx] != 0)
|
||||
return RemoveNode(p, indx);
|
||||
numBytes = U2B(I2U(indx));
|
||||
if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))
|
||||
{
|
||||
void *retVal = p->LoUnit;
|
||||
p->LoUnit += numBytes;
|
||||
return retVal;
|
||||
}
|
||||
return AllocUnitsRare(p, indx);
|
||||
}
|
||||
|
||||
#define MyMem12Cpy(dest, src, num) \
|
||||
{ UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \
|
||||
do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); }
|
||||
|
||||
static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
|
||||
{
|
||||
unsigned i0 = U2I(oldNU);
|
||||
unsigned i1 = U2I(newNU);
|
||||
if (i0 == i1)
|
||||
return oldPtr;
|
||||
if (p->FreeList[i1] != 0)
|
||||
{
|
||||
void *ptr = RemoveNode(p, i1);
|
||||
MyMem12Cpy(ptr, oldPtr, newNU);
|
||||
InsertNode(p, oldPtr, i0);
|
||||
return ptr;
|
||||
}
|
||||
SplitBlock(p, oldPtr, i0, i1);
|
||||
return oldPtr;
|
||||
}
|
||||
|
||||
#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))
|
||||
|
||||
static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
|
||||
{
|
||||
(p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);
|
||||
(p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);
|
||||
}
|
||||
|
||||
static void RestartModel(CPpmd7 *p)
|
||||
{
|
||||
unsigned i, k, m;
|
||||
|
||||
memset(p->FreeList, 0, sizeof(p->FreeList));
|
||||
p->Text = p->Base + p->AlignOffset;
|
||||
p->HiUnit = p->Text + p->Size;
|
||||
p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
|
||||
p->GlueCount = 0;
|
||||
|
||||
p->OrderFall = p->MaxOrder;
|
||||
p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
|
||||
p->PrevSuccess = 0;
|
||||
|
||||
p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
|
||||
p->MinContext->Suffix = 0;
|
||||
p->MinContext->NumStats = 256;
|
||||
p->MinContext->SummFreq = 256 + 1;
|
||||
p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */
|
||||
p->LoUnit += U2B(256 / 2);
|
||||
p->MinContext->Stats = REF(p->FoundState);
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
CPpmd_State *s = &p->FoundState[i];
|
||||
s->Symbol = (Byte)i;
|
||||
s->Freq = 1;
|
||||
SetSuccessor(s, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
UInt16 *dest = p->BinSumm[i] + k;
|
||||
UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2));
|
||||
for (m = 0; m < 64; m += 8)
|
||||
dest[m] = val;
|
||||
}
|
||||
|
||||
for (i = 0; i < 25; i++)
|
||||
for (k = 0; k < 16; k++)
|
||||
{
|
||||
CPpmd_See *s = &p->See[i][k];
|
||||
s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4));
|
||||
s->Count = 4;
|
||||
}
|
||||
}
|
||||
|
||||
void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder)
|
||||
{
|
||||
p->MaxOrder = maxOrder;
|
||||
RestartModel(p);
|
||||
p->DummySee.Shift = PPMD_PERIOD_BITS;
|
||||
p->DummySee.Summ = 0; /* unused */
|
||||
p->DummySee.Count = 64; /* unused */
|
||||
}
|
||||
|
||||
static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip)
|
||||
{
|
||||
CPpmd_State upState;
|
||||
CTX_PTR c = p->MinContext;
|
||||
CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
|
||||
CPpmd_State *ps[PPMD7_MAX_ORDER];
|
||||
unsigned numPs = 0;
|
||||
|
||||
if (!skip)
|
||||
ps[numPs++] = p->FoundState;
|
||||
|
||||
while (c->Suffix)
|
||||
{
|
||||
CPpmd_Void_Ref successor;
|
||||
CPpmd_State *s;
|
||||
c = SUFFIX(c);
|
||||
if (c->NumStats != 1)
|
||||
{
|
||||
for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);
|
||||
}
|
||||
else
|
||||
s = ONE_STATE(c);
|
||||
successor = SUCCESSOR(s);
|
||||
if (successor != upBranch)
|
||||
{
|
||||
c = CTX(successor);
|
||||
if (numPs == 0)
|
||||
return c;
|
||||
break;
|
||||
}
|
||||
ps[numPs++] = s;
|
||||
}
|
||||
|
||||
upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch);
|
||||
SetSuccessor(&upState, upBranch + 1);
|
||||
|
||||
if (c->NumStats == 1)
|
||||
upState.Freq = ONE_STATE(c)->Freq;
|
||||
else
|
||||
{
|
||||
UInt32 cf, s0;
|
||||
CPpmd_State *s;
|
||||
for (s = STATS(c); s->Symbol != upState.Symbol; s++);
|
||||
cf = s->Freq - 1;
|
||||
s0 = c->SummFreq - c->NumStats - cf;
|
||||
upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))));
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
/* Create Child */
|
||||
CTX_PTR c1; /* = AllocContext(p); */
|
||||
if (p->HiUnit != p->LoUnit)
|
||||
c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);
|
||||
else if (p->FreeList[0] != 0)
|
||||
c1 = (CTX_PTR)RemoveNode(p, 0);
|
||||
else
|
||||
{
|
||||
c1 = (CTX_PTR)AllocUnitsRare(p, 0);
|
||||
if (!c1)
|
||||
return NULL;
|
||||
}
|
||||
c1->NumStats = 1;
|
||||
*ONE_STATE(c1) = upState;
|
||||
c1->Suffix = REF(c);
|
||||
SetSuccessor(ps[--numPs], REF(c1));
|
||||
c = c1;
|
||||
}
|
||||
while (numPs != 0);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)
|
||||
{
|
||||
CPpmd_State tmp = *t1;
|
||||
*t1 = *t2;
|
||||
*t2 = tmp;
|
||||
}
|
||||
|
||||
static void UpdateModel(CPpmd7 *p)
|
||||
{
|
||||
CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);
|
||||
CTX_PTR c;
|
||||
unsigned s0, ns;
|
||||
|
||||
if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
|
||||
{
|
||||
c = SUFFIX(p->MinContext);
|
||||
|
||||
if (c->NumStats == 1)
|
||||
{
|
||||
CPpmd_State *s = ONE_STATE(c);
|
||||
if (s->Freq < 32)
|
||||
s->Freq++;
|
||||
}
|
||||
else
|
||||
{
|
||||
CPpmd_State *s = STATS(c);
|
||||
if (s->Symbol != p->FoundState->Symbol)
|
||||
{
|
||||
do { s++; } while (s->Symbol != p->FoundState->Symbol);
|
||||
if (s[0].Freq >= s[-1].Freq)
|
||||
{
|
||||
SwapStates(&s[0], &s[-1]);
|
||||
s--;
|
||||
}
|
||||
}
|
||||
if (s->Freq < MAX_FREQ - 9)
|
||||
{
|
||||
s->Freq += 2;
|
||||
c->SummFreq += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p->OrderFall == 0)
|
||||
{
|
||||
p->MinContext = p->MaxContext = CreateSuccessors(p, True);
|
||||
if (p->MinContext == 0)
|
||||
{
|
||||
RestartModel(p);
|
||||
return;
|
||||
}
|
||||
SetSuccessor(p->FoundState, REF(p->MinContext));
|
||||
return;
|
||||
}
|
||||
|
||||
*p->Text++ = p->FoundState->Symbol;
|
||||
successor = REF(p->Text);
|
||||
if (p->Text >= p->UnitsStart)
|
||||
{
|
||||
RestartModel(p);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fSuccessor)
|
||||
{
|
||||
if (fSuccessor <= successor)
|
||||
{
|
||||
CTX_PTR cs = CreateSuccessors(p, False);
|
||||
if (cs == NULL)
|
||||
{
|
||||
RestartModel(p);
|
||||
return;
|
||||
}
|
||||
fSuccessor = REF(cs);
|
||||
}
|
||||
if (--p->OrderFall == 0)
|
||||
{
|
||||
successor = fSuccessor;
|
||||
p->Text -= (p->MaxContext != p->MinContext);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSuccessor(p->FoundState, successor);
|
||||
fSuccessor = REF(p->MinContext);
|
||||
}
|
||||
|
||||
s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1);
|
||||
|
||||
for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c))
|
||||
{
|
||||
unsigned ns1;
|
||||
UInt32 cf, sf;
|
||||
if ((ns1 = c->NumStats) != 1)
|
||||
{
|
||||
if ((ns1 & 1) == 0)
|
||||
{
|
||||
/* Expand for one UNIT */
|
||||
unsigned oldNU = ns1 >> 1;
|
||||
unsigned i = U2I(oldNU);
|
||||
if (i != U2I(oldNU + 1))
|
||||
{
|
||||
void *ptr = AllocUnits(p, i + 1);
|
||||
void *oldPtr;
|
||||
if (!ptr)
|
||||
{
|
||||
RestartModel(p);
|
||||
return;
|
||||
}
|
||||
oldPtr = STATS(c);
|
||||
MyMem12Cpy(ptr, oldPtr, oldNU);
|
||||
InsertNode(p, oldPtr, i);
|
||||
c->Stats = STATS_REF(ptr);
|
||||
}
|
||||
}
|
||||
c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0);
|
||||
if (!s)
|
||||
{
|
||||
RestartModel(p);
|
||||
return;
|
||||
}
|
||||
*s = *ONE_STATE(c);
|
||||
c->Stats = REF(s);
|
||||
if (s->Freq < MAX_FREQ / 4 - 1)
|
||||
s->Freq <<= 1;
|
||||
else
|
||||
s->Freq = MAX_FREQ - 4;
|
||||
c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3));
|
||||
}
|
||||
cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6);
|
||||
sf = (UInt32)s0 + c->SummFreq;
|
||||
if (cf < 6 * sf)
|
||||
{
|
||||
cf = 1 + (cf > sf) + (cf >= 4 * sf);
|
||||
c->SummFreq += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf);
|
||||
c->SummFreq = (UInt16)(c->SummFreq + cf);
|
||||
}
|
||||
{
|
||||
CPpmd_State *s = STATS(c) + ns1;
|
||||
SetSuccessor(s, successor);
|
||||
s->Symbol = p->FoundState->Symbol;
|
||||
s->Freq = (Byte)cf;
|
||||
c->NumStats = (UInt16)(ns1 + 1);
|
||||
}
|
||||
}
|
||||
p->MaxContext = p->MinContext = CTX(fSuccessor);
|
||||
}
|
||||
|
||||
static void Rescale(CPpmd7 *p)
|
||||
{
|
||||
unsigned i, adder, sumFreq, escFreq;
|
||||
CPpmd_State *stats = STATS(p->MinContext);
|
||||
CPpmd_State *s = p->FoundState;
|
||||
{
|
||||
CPpmd_State tmp = *s;
|
||||
for (; s != stats; s--)
|
||||
s[0] = s[-1];
|
||||
*s = tmp;
|
||||
}
|
||||
escFreq = p->MinContext->SummFreq - s->Freq;
|
||||
s->Freq += 4;
|
||||
adder = (p->OrderFall != 0);
|
||||
s->Freq = (Byte)((s->Freq + adder) >> 1);
|
||||
sumFreq = s->Freq;
|
||||
|
||||
i = p->MinContext->NumStats - 1;
|
||||
do
|
||||
{
|
||||
escFreq -= (++s)->Freq;
|
||||
s->Freq = (Byte)((s->Freq + adder) >> 1);
|
||||
sumFreq += s->Freq;
|
||||
if (s[0].Freq > s[-1].Freq)
|
||||
{
|
||||
CPpmd_State *s1 = s;
|
||||
CPpmd_State tmp = *s1;
|
||||
do
|
||||
s1[0] = s1[-1];
|
||||
while (--s1 != stats && tmp.Freq > s1[-1].Freq);
|
||||
*s1 = tmp;
|
||||
}
|
||||
}
|
||||
while (--i);
|
||||
|
||||
if (s->Freq == 0)
|
||||
{
|
||||
unsigned numStats = p->MinContext->NumStats;
|
||||
unsigned n0, n1;
|
||||
do { i++; } while ((--s)->Freq == 0);
|
||||
escFreq += i;
|
||||
p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i);
|
||||
if (p->MinContext->NumStats == 1)
|
||||
{
|
||||
CPpmd_State tmp = *stats;
|
||||
do
|
||||
{
|
||||
tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1));
|
||||
escFreq >>= 1;
|
||||
}
|
||||
while (escFreq > 1);
|
||||
InsertNode(p, stats, U2I(((numStats + 1) >> 1)));
|
||||
*(p->FoundState = ONE_STATE(p->MinContext)) = tmp;
|
||||
return;
|
||||
}
|
||||
n0 = (numStats + 1) >> 1;
|
||||
n1 = (p->MinContext->NumStats + 1) >> 1;
|
||||
if (n0 != n1)
|
||||
p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
|
||||
}
|
||||
p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
|
||||
p->FoundState = STATS(p->MinContext);
|
||||
}
|
||||
|
||||
CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq)
|
||||
{
|
||||
CPpmd_See *see;
|
||||
unsigned nonMasked = p->MinContext->NumStats - numMasked;
|
||||
if (p->MinContext->NumStats != 256)
|
||||
{
|
||||
see = p->See[p->NS2Indx[nonMasked - 1]] +
|
||||
(nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) +
|
||||
2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) +
|
||||
4 * (numMasked > nonMasked) +
|
||||
p->HiBitsFlag;
|
||||
{
|
||||
unsigned r = (see->Summ >> see->Shift);
|
||||
see->Summ = (UInt16)(see->Summ - r);
|
||||
*escFreq = r + (r == 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
see = &p->DummySee;
|
||||
*escFreq = 1;
|
||||
}
|
||||
return see;
|
||||
}
|
||||
|
||||
static void NextContext(CPpmd7 *p)
|
||||
{
|
||||
CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
|
||||
if (p->OrderFall == 0 && (Byte *)c > p->Text)
|
||||
p->MinContext = p->MaxContext = c;
|
||||
else
|
||||
UpdateModel(p);
|
||||
}
|
||||
|
||||
void Ppmd7_Update1(CPpmd7 *p)
|
||||
{
|
||||
CPpmd_State *s = p->FoundState;
|
||||
s->Freq += 4;
|
||||
p->MinContext->SummFreq += 4;
|
||||
if (s[0].Freq > s[-1].Freq)
|
||||
{
|
||||
SwapStates(&s[0], &s[-1]);
|
||||
p->FoundState = --s;
|
||||
if (s->Freq > MAX_FREQ)
|
||||
Rescale(p);
|
||||
}
|
||||
NextContext(p);
|
||||
}
|
||||
|
||||
void Ppmd7_Update1_0(CPpmd7 *p)
|
||||
{
|
||||
p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq);
|
||||
p->RunLength += p->PrevSuccess;
|
||||
p->MinContext->SummFreq += 4;
|
||||
if ((p->FoundState->Freq += 4) > MAX_FREQ)
|
||||
Rescale(p);
|
||||
NextContext(p);
|
||||
}
|
||||
|
||||
void Ppmd7_UpdateBin(CPpmd7 *p)
|
||||
{
|
||||
p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0));
|
||||
p->PrevSuccess = 1;
|
||||
p->RunLength++;
|
||||
NextContext(p);
|
||||
}
|
||||
|
||||
void Ppmd7_Update2(CPpmd7 *p)
|
||||
{
|
||||
p->MinContext->SummFreq += 4;
|
||||
if ((p->FoundState->Freq += 4) > MAX_FREQ)
|
||||
Rescale(p);
|
||||
p->RunLength = p->InitRL;
|
||||
UpdateModel(p);
|
||||
}
|
||||
140
clamav/libclamav/7z/Ppmd7.h
Normal file
140
clamav/libclamav/7z/Ppmd7.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/* Ppmd7.h -- PPMdH compression codec
|
||||
2010-03-12 : Igor Pavlov : Public domain
|
||||
This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
|
||||
|
||||
/* This code supports virtual RangeDecoder and includes the implementation
|
||||
of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H.
|
||||
If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */
|
||||
|
||||
#ifndef __PPMD7_H
|
||||
#define __PPMD7_H
|
||||
|
||||
#include "Ppmd.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#define PPMD7_MIN_ORDER 2
|
||||
#define PPMD7_MAX_ORDER 64
|
||||
|
||||
#define PPMD7_MIN_MEM_SIZE (1 << 11)
|
||||
#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3)
|
||||
|
||||
struct CPpmd7_Context_;
|
||||
|
||||
typedef
|
||||
#ifdef PPMD_32BIT
|
||||
struct CPpmd7_Context_ *
|
||||
#else
|
||||
UInt32
|
||||
#endif
|
||||
CPpmd7_Context_Ref;
|
||||
|
||||
typedef struct CPpmd7_Context_
|
||||
{
|
||||
UInt16 NumStats;
|
||||
UInt16 SummFreq;
|
||||
CPpmd_State_Ref Stats;
|
||||
CPpmd7_Context_Ref Suffix;
|
||||
} CPpmd7_Context;
|
||||
|
||||
#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CPpmd7_Context *MinContext, *MaxContext;
|
||||
CPpmd_State *FoundState;
|
||||
unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag;
|
||||
Int32 RunLength, InitRL; /* must be 32-bit at least */
|
||||
|
||||
UInt32 Size;
|
||||
UInt32 GlueCount;
|
||||
Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
|
||||
UInt32 AlignOffset;
|
||||
|
||||
Byte Indx2Units[PPMD_NUM_INDEXES];
|
||||
Byte Units2Indx[128];
|
||||
CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
|
||||
Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
|
||||
CPpmd_See DummySee, See[25][16];
|
||||
UInt16 BinSumm[128][64];
|
||||
} CPpmd7;
|
||||
|
||||
void Ppmd7_Construct(CPpmd7 *p);
|
||||
Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc);
|
||||
void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc);
|
||||
void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder);
|
||||
#define Ppmd7_WasAllocated(p) ((p)->Base != NULL)
|
||||
|
||||
|
||||
/* ---------- Internal Functions ---------- */
|
||||
|
||||
extern const Byte PPMD7_kExpEscape[16];
|
||||
|
||||
#ifdef PPMD_32BIT
|
||||
#define Ppmd7_GetPtr(p, ptr) (ptr)
|
||||
#define Ppmd7_GetContext(p, ptr) (ptr)
|
||||
#define Ppmd7_GetStats(p, ctx) ((ctx)->Stats)
|
||||
#else
|
||||
#define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
|
||||
#define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs)))
|
||||
#define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats)))
|
||||
#endif
|
||||
|
||||
void Ppmd7_Update1(CPpmd7 *p);
|
||||
void Ppmd7_Update1_0(CPpmd7 *p);
|
||||
void Ppmd7_Update2(CPpmd7 *p);
|
||||
void Ppmd7_UpdateBin(CPpmd7 *p);
|
||||
|
||||
#define Ppmd7_GetBinSumm(p) \
|
||||
&p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \
|
||||
p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \
|
||||
(p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \
|
||||
2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \
|
||||
((p->RunLength >> 26) & 0x20)]
|
||||
|
||||
CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale);
|
||||
|
||||
|
||||
/* ---------- Decode ---------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 (*GetThreshold)(void *p, UInt32 total);
|
||||
void (*Decode)(void *p, UInt32 start, UInt32 size);
|
||||
UInt32 (*DecodeBit)(void *p, UInt32 size0);
|
||||
} IPpmd7_RangeDec;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
IPpmd7_RangeDec p;
|
||||
UInt32 Range;
|
||||
UInt32 Code;
|
||||
IByteIn *Stream;
|
||||
} CPpmd7z_RangeDec;
|
||||
|
||||
void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p);
|
||||
Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p);
|
||||
#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
|
||||
|
||||
int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc);
|
||||
|
||||
|
||||
/* ---------- Encode ---------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt64 Low;
|
||||
UInt32 Range;
|
||||
Byte Cache;
|
||||
UInt64 CacheSize;
|
||||
IByteOut *Stream;
|
||||
} CPpmd7z_RangeEnc;
|
||||
|
||||
void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p);
|
||||
void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p);
|
||||
|
||||
void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
187
clamav/libclamav/7z/Ppmd7Dec.c
Normal file
187
clamav/libclamav/7z/Ppmd7Dec.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/* Ppmd7Dec.c -- PPMdH Decoder
|
||||
2010-03-12 : Igor Pavlov : Public domain
|
||||
This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
|
||||
|
||||
#include "Ppmd7.h"
|
||||
|
||||
#define kTopValue (1 << 24)
|
||||
|
||||
Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p)
|
||||
{
|
||||
unsigned i;
|
||||
p->Code = 0;
|
||||
p->Range = 0xFFFFFFFF;
|
||||
if (p->Stream->Read((void *)p->Stream) != 0)
|
||||
return False;
|
||||
for (i = 0; i < 4; i++)
|
||||
p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
|
||||
return (p->Code < 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static UInt32 Range_GetThreshold(void *pp, UInt32 total)
|
||||
{
|
||||
CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
|
||||
return (p->Code) / (p->Range /= total);
|
||||
}
|
||||
|
||||
static void Range_Normalize(CPpmd7z_RangeDec *p)
|
||||
{
|
||||
if (p->Range < kTopValue)
|
||||
{
|
||||
p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
|
||||
p->Range <<= 8;
|
||||
if (p->Range < kTopValue)
|
||||
{
|
||||
p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
|
||||
p->Range <<= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Range_Decode(void *pp, UInt32 start, UInt32 size)
|
||||
{
|
||||
CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
|
||||
p->Code -= start * p->Range;
|
||||
p->Range *= size;
|
||||
Range_Normalize(p);
|
||||
}
|
||||
|
||||
static UInt32 Range_DecodeBit(void *pp, UInt32 size0)
|
||||
{
|
||||
CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
|
||||
UInt32 newBound = (p->Range >> 14) * size0;
|
||||
UInt32 symbol;
|
||||
if (p->Code < newBound)
|
||||
{
|
||||
symbol = 0;
|
||||
p->Range = newBound;
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol = 1;
|
||||
p->Code -= newBound;
|
||||
p->Range -= newBound;
|
||||
}
|
||||
Range_Normalize(p);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p)
|
||||
{
|
||||
p->p.GetThreshold = Range_GetThreshold;
|
||||
p->p.Decode = Range_Decode;
|
||||
p->p.DecodeBit = Range_DecodeBit;
|
||||
}
|
||||
|
||||
|
||||
#define MASK(sym) ((signed char *)charMask)[sym]
|
||||
|
||||
int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc)
|
||||
{
|
||||
size_t charMask[256 / sizeof(size_t)];
|
||||
if (p->MinContext->NumStats != 1)
|
||||
{
|
||||
CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
|
||||
unsigned i;
|
||||
UInt32 count, hiCnt;
|
||||
if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq))
|
||||
{
|
||||
Byte symbol;
|
||||
rc->Decode(rc, 0, s->Freq);
|
||||
p->FoundState = s;
|
||||
symbol = s->Symbol;
|
||||
Ppmd7_Update1_0(p);
|
||||
return symbol;
|
||||
}
|
||||
p->PrevSuccess = 0;
|
||||
i = p->MinContext->NumStats - 1;
|
||||
do
|
||||
{
|
||||
if ((hiCnt += (++s)->Freq) > count)
|
||||
{
|
||||
Byte symbol;
|
||||
rc->Decode(rc, hiCnt - s->Freq, s->Freq);
|
||||
p->FoundState = s;
|
||||
symbol = s->Symbol;
|
||||
Ppmd7_Update1(p);
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
while (--i);
|
||||
if (count >= p->MinContext->SummFreq)
|
||||
return -2;
|
||||
p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
|
||||
rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt);
|
||||
PPMD_SetAllBitsIn256Bytes(charMask);
|
||||
MASK(s->Symbol) = 0;
|
||||
i = p->MinContext->NumStats - 1;
|
||||
do { MASK((--s)->Symbol) = 0; } while (--i);
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt16 *prob = Ppmd7_GetBinSumm(p);
|
||||
if (rc->DecodeBit(rc, *prob) == 0)
|
||||
{
|
||||
Byte symbol;
|
||||
*prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
|
||||
symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;
|
||||
Ppmd7_UpdateBin(p);
|
||||
return symbol;
|
||||
}
|
||||
*prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
|
||||
p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
|
||||
PPMD_SetAllBitsIn256Bytes(charMask);
|
||||
MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;
|
||||
p->PrevSuccess = 0;
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
CPpmd_State *ps[256], *s;
|
||||
UInt32 freqSum, count, hiCnt;
|
||||
CPpmd_See *see;
|
||||
unsigned i, num, numMasked = p->MinContext->NumStats;
|
||||
do
|
||||
{
|
||||
p->OrderFall++;
|
||||
if (!p->MinContext->Suffix)
|
||||
return -1;
|
||||
p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
|
||||
}
|
||||
while (p->MinContext->NumStats == numMasked);
|
||||
hiCnt = 0;
|
||||
s = Ppmd7_GetStats(p, p->MinContext);
|
||||
i = 0;
|
||||
num = p->MinContext->NumStats - numMasked;
|
||||
do
|
||||
{
|
||||
int k = (int)(MASK(s->Symbol));
|
||||
hiCnt += (s->Freq & k);
|
||||
ps[i] = s++;
|
||||
i -= k;
|
||||
}
|
||||
while (i != num);
|
||||
|
||||
see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);
|
||||
freqSum += hiCnt;
|
||||
count = rc->GetThreshold(rc, freqSum);
|
||||
|
||||
if (count < hiCnt)
|
||||
{
|
||||
Byte symbol;
|
||||
CPpmd_State **pps = ps;
|
||||
for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);
|
||||
s = *pps;
|
||||
rc->Decode(rc, hiCnt - s->Freq, s->Freq);
|
||||
Ppmd_See_Update(see);
|
||||
p->FoundState = s;
|
||||
symbol = s->Symbol;
|
||||
Ppmd7_Update2(p);
|
||||
return symbol;
|
||||
}
|
||||
if (count >= freqSum)
|
||||
return -2;
|
||||
rc->Decode(rc, hiCnt, freqSum - hiCnt);
|
||||
see->Summ = (UInt16)(see->Summ + freqSum);
|
||||
do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);
|
||||
}
|
||||
}
|
||||
20
clamav/libclamav/7z/RotateDefs.h
Normal file
20
clamav/libclamav/7z/RotateDefs.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/* RotateDefs.h -- Rotate functions
|
||||
2009-02-07 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __ROTATE_DEFS_H
|
||||
#define __ROTATE_DEFS_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#include <stdlib.h>
|
||||
#define rotlFixed(x, n) _rotl((x), (n))
|
||||
#define rotrFixed(x, n) _rotr((x), (n))
|
||||
|
||||
#else
|
||||
|
||||
#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
262
clamav/libclamav/7z/Types.h
Normal file
262
clamav/libclamav/7z/Types.h
Normal file
@@ -0,0 +1,262 @@
|
||||
/* Types.h -- Basic types
|
||||
2010-10-09 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __7Z_TYPES_H
|
||||
#define __7Z_TYPES_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <zconf.h>
|
||||
|
||||
#ifndef EXTERN_C_BEGIN
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN_C_BEGIN extern "C" {
|
||||
#define EXTERN_C_END }
|
||||
#else
|
||||
#define EXTERN_C_BEGIN
|
||||
#define EXTERN_C_END
|
||||
#endif
|
||||
#endif
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
#include "fmap.h"
|
||||
#define SZ_OK 0
|
||||
|
||||
#define SZ_ERROR_DATA 1
|
||||
#define SZ_ERROR_MEM 2
|
||||
#define SZ_ERROR_CRC 3
|
||||
#define SZ_ERROR_UNSUPPORTED 4
|
||||
#define SZ_ERROR_PARAM 5
|
||||
#define SZ_ERROR_INPUT_EOF 6
|
||||
#define SZ_ERROR_OUTPUT_EOF 7
|
||||
#define SZ_ERROR_READ 8
|
||||
#define SZ_ERROR_WRITE 9
|
||||
#define SZ_ERROR_PROGRESS 10
|
||||
#define SZ_ERROR_FAIL 11
|
||||
#define SZ_ERROR_THREAD 12
|
||||
|
||||
#define SZ_ERROR_ARCHIVE 16
|
||||
#define SZ_ERROR_NO_ARCHIVE 17
|
||||
|
||||
/* ACAB */
|
||||
#define SZ_ERROR_ENCRYPTED 18
|
||||
|
||||
typedef int SRes;
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef DWORD WRes;
|
||||
#else
|
||||
typedef int WRes;
|
||||
#endif
|
||||
|
||||
#ifndef RINOK
|
||||
#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
|
||||
#endif
|
||||
|
||||
/* aCaB -- use Byte defined in zconf.h
|
||||
typedef unsigned char Byte;
|
||||
*/
|
||||
typedef short Int16;
|
||||
typedef unsigned short UInt16;
|
||||
|
||||
#ifdef _LZMA_UINT32_IS_ULONG
|
||||
typedef long Int32;
|
||||
typedef unsigned long UInt32;
|
||||
#else
|
||||
typedef int Int32;
|
||||
typedef unsigned int UInt32;
|
||||
#endif
|
||||
|
||||
#ifdef _SZ_NO_INT_64
|
||||
|
||||
/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
|
||||
NOTES: Some code will work incorrectly in that case! */
|
||||
|
||||
typedef long Int64;
|
||||
typedef unsigned long UInt64;
|
||||
|
||||
#else
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
typedef __int64 Int64;
|
||||
typedef unsigned __int64 UInt64;
|
||||
#define UINT64_CONST(n) n
|
||||
#else
|
||||
typedef long long int Int64;
|
||||
typedef unsigned long long int UInt64;
|
||||
#define UINT64_CONST(n) n ## ULL
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _LZMA_NO_SYSTEM_SIZE_T
|
||||
typedef UInt32 SizeT;
|
||||
#else
|
||||
typedef size_t SizeT;
|
||||
#endif
|
||||
|
||||
typedef int Bool;
|
||||
#define True 1
|
||||
#define False 0
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MY_STD_CALL __stdcall
|
||||
#else
|
||||
#define MY_STD_CALL
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#if _MSC_VER >= 1300
|
||||
#define MY_NO_INLINE __declspec(noinline)
|
||||
#else
|
||||
#define MY_NO_INLINE
|
||||
#endif
|
||||
|
||||
#define MY_CDECL __cdecl
|
||||
#define MY_FAST_CALL __fastcall
|
||||
|
||||
#else
|
||||
|
||||
#define MY_CDECL
|
||||
#define MY_FAST_CALL
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* The following interfaces use first parameter as pointer to structure */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */
|
||||
} IByteIn;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*Write)(void *p, Byte b);
|
||||
} IByteOut;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Read)(void *p, void *buf, size_t *size);
|
||||
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
|
||||
(output(*size) < input(*size)) is allowed */
|
||||
} ISeqInStream;
|
||||
|
||||
/* it can return SZ_ERROR_INPUT_EOF */
|
||||
SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
|
||||
SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
|
||||
SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t (*Write)(void *p, const void *buf, size_t size);
|
||||
/* Returns: result - the number of actually written bytes.
|
||||
(result < size) means error */
|
||||
} ISeqOutStream;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SZ_SEEK_SET = 0,
|
||||
SZ_SEEK_CUR = 1,
|
||||
SZ_SEEK_END = 2
|
||||
} ESzSeek;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
|
||||
SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
|
||||
off_t curpos;
|
||||
} ISeekInStream;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Look)(void *p, const void **buf, size_t *size);
|
||||
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
|
||||
(output(*size) > input(*size)) is not allowed
|
||||
(output(*size) < input(*size)) is allowed */
|
||||
SRes (*Skip)(void *p, size_t offset);
|
||||
/* offset must be <= output(*size) of Look */
|
||||
|
||||
SRes (*Read)(void *p, void *buf, size_t *size);
|
||||
/* reads directly (without buffer). It's same as ISeqInStream::Read */
|
||||
SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
|
||||
} ILookInStream;
|
||||
|
||||
SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
|
||||
SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
|
||||
|
||||
/* reads via ILookInStream::Read */
|
||||
SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
|
||||
SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
|
||||
|
||||
#define LookToRead_BUF_SIZE (1 << 14)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ILookInStream s;
|
||||
ISeekInStream *realStream;
|
||||
size_t pos;
|
||||
size_t size;
|
||||
Byte buf[LookToRead_BUF_SIZE];
|
||||
} CLookToRead;
|
||||
|
||||
void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
|
||||
void LookToRead_Init(CLookToRead *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeqInStream s;
|
||||
ILookInStream *realStream;
|
||||
} CSecToLook;
|
||||
|
||||
void SecToLook_CreateVTable(CSecToLook *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISeqInStream s;
|
||||
ILookInStream *realStream;
|
||||
} CSecToRead;
|
||||
|
||||
void SecToRead_CreateVTable(CSecToRead *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
|
||||
/* Returns: result. (result != SZ_OK) means break.
|
||||
Value (UInt64)(Int64)-1 for size means unknown value. */
|
||||
} ICompressProgress;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *(*Alloc)(void *p, size_t size);
|
||||
void (*Free)(void *p, void *address); /* address can be 0 */
|
||||
} ISzAlloc;
|
||||
|
||||
#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
|
||||
#define IAlloc_Free(p, a) (p)->Free((p), a)
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define CHAR_PATH_SEPARATOR '\\'
|
||||
#define WCHAR_PATH_SEPARATOR L'\\'
|
||||
#define STRING_PATH_SEPARATOR "\\"
|
||||
#define WSTRING_PATH_SEPARATOR L"\\"
|
||||
|
||||
#else
|
||||
|
||||
#define CHAR_PATH_SEPARATOR '/'
|
||||
#define WCHAR_PATH_SEPARATOR L'/'
|
||||
#define STRING_PATH_SEPARATOR "/"
|
||||
#define WSTRING_PATH_SEPARATOR L"/"
|
||||
|
||||
#endif
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
102
clamav/libclamav/7z/Xz.c
Normal file
102
clamav/libclamav/7z/Xz.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/* Xz.c - Xz
|
||||
2009-04-15 : Igor Pavlov : Public domain */
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "7zCrc.h"
|
||||
#include "CpuArch.h"
|
||||
#include "Xz.h"
|
||||
#include "XzCrc64.h"
|
||||
|
||||
Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 };
|
||||
Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' };
|
||||
|
||||
unsigned Xz_WriteVarInt(Byte *buf, UInt64 v)
|
||||
{
|
||||
unsigned i = 0;
|
||||
do
|
||||
{
|
||||
buf[i++] = (Byte)((v & 0x7F) | 0x80);
|
||||
v >>= 7;
|
||||
}
|
||||
while (v != 0);
|
||||
buf[i - 1] &= 0x7F;
|
||||
return i;
|
||||
}
|
||||
|
||||
void Xz_Construct(CXzStream *p)
|
||||
{
|
||||
p->numBlocks = p->numBlocksAllocated = 0;
|
||||
p->blocks = 0;
|
||||
p->flags = 0;
|
||||
}
|
||||
|
||||
void Xz_Free(CXzStream *p, ISzAlloc *alloc)
|
||||
{
|
||||
alloc->Free(alloc, p->blocks);
|
||||
p->numBlocks = p->numBlocksAllocated = 0;
|
||||
p->blocks = 0;
|
||||
}
|
||||
|
||||
unsigned XzFlags_GetCheckSize(CXzStreamFlags f)
|
||||
{
|
||||
int t = XzFlags_GetCheckType(f);
|
||||
return (t == 0) ? 0 : (4 << ((t - 1) / 3));
|
||||
}
|
||||
|
||||
void XzCheck_Init(CXzCheck *p, int mode)
|
||||
{
|
||||
p->mode = mode;
|
||||
switch (mode)
|
||||
{
|
||||
case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break;
|
||||
case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break;
|
||||
case XZ_CHECK_SHA256:
|
||||
p->sha = cl_hash_init("sha256");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void XzCheck_Update(CXzCheck *p, const void *data, size_t size)
|
||||
{
|
||||
switch (p->mode)
|
||||
{
|
||||
case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break;
|
||||
case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break;
|
||||
case XZ_CHECK_SHA256:
|
||||
if ((p->sha))
|
||||
cl_update_hash(p->sha, (void *)data, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int XzCheck_Final(CXzCheck *p, Byte *digest)
|
||||
{
|
||||
switch (p->mode)
|
||||
{
|
||||
case XZ_CHECK_CRC32:
|
||||
SetUi32(digest, CRC_GET_DIGEST(p->crc));
|
||||
break;
|
||||
case XZ_CHECK_CRC64:
|
||||
{
|
||||
int i;
|
||||
UInt64 v = CRC64_GET_DIGEST(p->crc64);
|
||||
for (i = 0; i < 8; i++, v >>= 8)
|
||||
digest[i] = (Byte)(v & 0xFF);
|
||||
break;
|
||||
}
|
||||
case XZ_CHECK_SHA256:
|
||||
if (!(p->sha))
|
||||
return 0;
|
||||
|
||||
cl_finish_hash(p->sha, digest);
|
||||
p->sha = NULL;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
254
clamav/libclamav/7z/Xz.h
Normal file
254
clamav/libclamav/7z/Xz.h
Normal file
@@ -0,0 +1,254 @@
|
||||
/* Xz.h - Xz interface
|
||||
2010-09-17 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __XZ_H
|
||||
#define __XZ_H
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
#define XZ_ID_Subblock 1
|
||||
#define XZ_ID_Delta 3
|
||||
#define XZ_ID_X86 4
|
||||
#define XZ_ID_PPC 5
|
||||
#define XZ_ID_IA64 6
|
||||
#define XZ_ID_ARM 7
|
||||
#define XZ_ID_ARMT 8
|
||||
#define XZ_ID_SPARC 9
|
||||
#define XZ_ID_LZMA2 0x21
|
||||
|
||||
unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value);
|
||||
unsigned Xz_WriteVarInt(Byte *buf, UInt64 v);
|
||||
|
||||
/* ---------- xz block ---------- */
|
||||
|
||||
#define XZ_BLOCK_HEADER_SIZE_MAX 1024
|
||||
|
||||
#define XZ_NUM_FILTERS_MAX 4
|
||||
#define XZ_BF_NUM_FILTERS_MASK 3
|
||||
#define XZ_BF_PACK_SIZE (1 << 6)
|
||||
#define XZ_BF_UNPACK_SIZE (1 << 7)
|
||||
|
||||
#define XZ_FILTER_PROPS_SIZE_MAX 20
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt64 id;
|
||||
UInt32 propsSize;
|
||||
Byte props[XZ_FILTER_PROPS_SIZE_MAX];
|
||||
} CXzFilter;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt64 packSize;
|
||||
UInt64 unpackSize;
|
||||
Byte flags;
|
||||
CXzFilter filters[XZ_NUM_FILTERS_MAX];
|
||||
} CXzBlock;
|
||||
|
||||
#define XzBlock_GetNumFilters(p) (((p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1)
|
||||
#define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0)
|
||||
#define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0)
|
||||
|
||||
SRes XzBlock_Parse(CXzBlock *p, const Byte *header);
|
||||
SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes);
|
||||
|
||||
/* ---------- xz stream ---------- */
|
||||
|
||||
#define XZ_SIG_SIZE 6
|
||||
#define XZ_FOOTER_SIG_SIZE 2
|
||||
|
||||
extern Byte XZ_SIG[XZ_SIG_SIZE];
|
||||
extern Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE];
|
||||
|
||||
#define XZ_STREAM_FLAGS_SIZE 2
|
||||
#define XZ_STREAM_CRC_SIZE 4
|
||||
|
||||
#define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE)
|
||||
#define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4)
|
||||
|
||||
#define XZ_CHECK_MASK 0xF
|
||||
#define XZ_CHECK_NO 0
|
||||
#define XZ_CHECK_CRC32 1
|
||||
#define XZ_CHECK_CRC64 4
|
||||
#define XZ_CHECK_SHA256 10
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int mode;
|
||||
UInt32 crc;
|
||||
UInt64 crc64;
|
||||
void *sha;
|
||||
} CXzCheck;
|
||||
|
||||
void XzCheck_Init(CXzCheck *p, int mode);
|
||||
void XzCheck_Update(CXzCheck *p, const void *data, size_t size);
|
||||
int XzCheck_Final(CXzCheck *p, Byte *digest);
|
||||
|
||||
typedef UInt16 CXzStreamFlags;
|
||||
|
||||
#define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK)
|
||||
#define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK)
|
||||
#define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32)
|
||||
unsigned XzFlags_GetCheckSize(CXzStreamFlags f);
|
||||
|
||||
SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf);
|
||||
SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt64 unpackSize;
|
||||
UInt64 totalSize;
|
||||
} CXzBlockSizes;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CXzStreamFlags flags;
|
||||
size_t numBlocks;
|
||||
size_t numBlocksAllocated;
|
||||
CXzBlockSizes *blocks;
|
||||
UInt64 startOffset;
|
||||
} CXzStream;
|
||||
|
||||
void Xz_Construct(CXzStream *p);
|
||||
void Xz_Free(CXzStream *p, ISzAlloc *alloc);
|
||||
|
||||
#define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1)
|
||||
|
||||
UInt64 Xz_GetUnpackSize(const CXzStream *p);
|
||||
UInt64 Xz_GetPackSize(const CXzStream *p);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t num;
|
||||
size_t numAllocated;
|
||||
CXzStream *streams;
|
||||
} CXzs;
|
||||
|
||||
void Xzs_Construct(CXzs *p);
|
||||
void Xzs_Free(CXzs *p, ISzAlloc *alloc);
|
||||
SRes Xzs_ReadBackward(CXzs *p, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc);
|
||||
|
||||
UInt64 Xzs_GetNumBlocks(const CXzs *p);
|
||||
UInt64 Xzs_GetUnpackSize(const CXzs *p);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */
|
||||
CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
|
||||
CODER_STATUS_NOT_FINISHED, /* stream was not finished */
|
||||
CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */
|
||||
} ECoderStatus;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CODER_FINISH_ANY, /* finish at any point */
|
||||
CODER_FINISH_END /* block must be finished at the end */
|
||||
} ECoderFinishMode;
|
||||
|
||||
typedef struct _IStateCoder
|
||||
{
|
||||
void *p;
|
||||
void (*Free)(void *p, ISzAlloc *alloc);
|
||||
SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAlloc *alloc);
|
||||
void (*Init)(void *p);
|
||||
SRes (*Code)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished);
|
||||
} IStateCoder;
|
||||
|
||||
#define MIXCODER_NUM_FILTERS_MAX 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ISzAlloc *alloc;
|
||||
Byte *buf;
|
||||
int numCoders;
|
||||
int finished[MIXCODER_NUM_FILTERS_MAX - 1];
|
||||
size_t pos[MIXCODER_NUM_FILTERS_MAX - 1];
|
||||
size_t size[MIXCODER_NUM_FILTERS_MAX - 1];
|
||||
UInt64 ids[MIXCODER_NUM_FILTERS_MAX];
|
||||
IStateCoder coders[MIXCODER_NUM_FILTERS_MAX];
|
||||
} CMixCoder;
|
||||
|
||||
void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc);
|
||||
void MixCoder_Free(CMixCoder *p);
|
||||
void MixCoder_Init(CMixCoder *p);
|
||||
SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId);
|
||||
SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen,
|
||||
const Byte *src, SizeT *srcLen, int srcWasFinished,
|
||||
ECoderFinishMode finishMode, ECoderStatus *status);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XZ_STATE_STREAM_HEADER,
|
||||
XZ_STATE_STREAM_INDEX,
|
||||
XZ_STATE_STREAM_INDEX_CRC,
|
||||
XZ_STATE_STREAM_FOOTER,
|
||||
XZ_STATE_STREAM_PADDING,
|
||||
XZ_STATE_BLOCK_HEADER,
|
||||
XZ_STATE_BLOCK,
|
||||
XZ_STATE_BLOCK_FOOTER
|
||||
} EXzState;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
EXzState state;
|
||||
UInt32 pos;
|
||||
unsigned alignPos;
|
||||
unsigned indexPreSize;
|
||||
|
||||
CXzStreamFlags streamFlags;
|
||||
|
||||
UInt32 blockHeaderSize;
|
||||
UInt64 packSize;
|
||||
UInt64 unpackSize;
|
||||
|
||||
UInt64 numBlocks;
|
||||
UInt64 indexSize;
|
||||
UInt64 indexPos;
|
||||
UInt64 padSize;
|
||||
|
||||
UInt64 numStreams;
|
||||
|
||||
UInt32 crc;
|
||||
CMixCoder decoder;
|
||||
CXzBlock block;
|
||||
CXzCheck check;
|
||||
void *sha;
|
||||
Byte shaDigest[SHA256_DIGEST_SIZE];
|
||||
Byte buf[XZ_BLOCK_HEADER_SIZE_MAX];
|
||||
} CXzUnpacker;
|
||||
|
||||
SRes XzUnpacker_Create(CXzUnpacker *p, ISzAlloc *alloc);
|
||||
void XzUnpacker_Free(CXzUnpacker *p);
|
||||
|
||||
/*
|
||||
finishMode:
|
||||
It has meaning only if the decoding reaches output limit (*destLen).
|
||||
LZMA_FINISH_ANY - use smallest number of input bytes
|
||||
LZMA_FINISH_END - read EndOfStream marker after decoding
|
||||
|
||||
Returns:
|
||||
SZ_OK
|
||||
status:
|
||||
LZMA_STATUS_FINISHED_WITH_MARK
|
||||
LZMA_STATUS_NOT_FINISHED
|
||||
SZ_ERROR_DATA - Data error
|
||||
SZ_ERROR_MEM - Memory allocation error
|
||||
SZ_ERROR_UNSUPPORTED - Unsupported properties
|
||||
SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
|
||||
*/
|
||||
|
||||
|
||||
SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
||||
const Byte *src, SizeT *srcLen, /* int srcWasFinished, */ int finishMode,
|
||||
ECoderStatus *status);
|
||||
|
||||
Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
33
clamav/libclamav/7z/XzCrc64.c
Normal file
33
clamav/libclamav/7z/XzCrc64.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/* XzCrc64.c -- CRC64 calculation
|
||||
2010-04-16 : Igor Pavlov : Public domain */
|
||||
|
||||
#include "XzCrc64.h"
|
||||
|
||||
#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42)
|
||||
UInt64 g_Crc64Table[256];
|
||||
|
||||
void MY_FAST_CALL Crc64GenerateTable(void)
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
UInt64 r = i;
|
||||
int j;
|
||||
for (j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ ((UInt64)kCrc64Poly & ~((r & 1) - 1));
|
||||
g_Crc64Table[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
UInt64 MY_FAST_CALL Crc64Update(UInt64 v, const void *data, size_t size)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0 ; size--, p++)
|
||||
v = CRC64_UPDATE_BYTE(v, *p);
|
||||
return v;
|
||||
}
|
||||
|
||||
UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size)
|
||||
{
|
||||
return CRC64_GET_DIGEST(Crc64Update(CRC64_INIT_VAL, data, size));
|
||||
}
|
||||
26
clamav/libclamav/7z/XzCrc64.h
Normal file
26
clamav/libclamav/7z/XzCrc64.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* XzCrc64.h -- CRC64 calculation
|
||||
2010-04-16 : Igor Pavlov : Public domain */
|
||||
|
||||
#ifndef __XZ_CRC64_H
|
||||
#define __XZ_CRC64_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
extern UInt64 g_Crc64Table[];
|
||||
|
||||
void MY_FAST_CALL Crc64GenerateTable(void);
|
||||
|
||||
#define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF)
|
||||
#define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL)
|
||||
#define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
UInt64 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size);
|
||||
UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
905
clamav/libclamav/7z/XzDec.c
Normal file
905
clamav/libclamav/7z/XzDec.c
Normal file
@@ -0,0 +1,905 @@
|
||||
/* XzDec.c -- Xz Decode
|
||||
2010-04-16 : Igor Pavlov : Public domain */
|
||||
|
||||
/* #define XZ_DUMP */
|
||||
|
||||
#ifdef XZ_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "clamav.h"
|
||||
#include "7zCrc.h"
|
||||
#include "Alloc.h"
|
||||
#include "Bra.h"
|
||||
#include "CpuArch.h"
|
||||
#include "Delta.h"
|
||||
#include "Lzma2Dec.h"
|
||||
|
||||
#ifdef USE_SUBBLOCK
|
||||
#include "SbDec.h"
|
||||
#endif
|
||||
|
||||
#include "Xz.h"
|
||||
|
||||
#define XZ_CHECK_SIZE_MAX 64
|
||||
|
||||
#define CODER_BUF_SIZE (1 << 17)
|
||||
|
||||
void BraState_Free(void *pp, ISzAlloc *alloc);
|
||||
SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc);
|
||||
void BraState_Init(void *pp);
|
||||
SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, ISzAlloc *alloc);
|
||||
|
||||
unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value)
|
||||
{
|
||||
int i, limit;
|
||||
*value = 0;
|
||||
limit = (maxSize > 9) ? 9 : (int)maxSize;
|
||||
|
||||
for (i = 0; i < limit;)
|
||||
{
|
||||
Byte b = p[i];
|
||||
*value |= (UInt64)(b & 0x7F) << (7 * i++);
|
||||
if ((b & 0x80) == 0)
|
||||
return (b == 0 && i != 1) ? 0 : i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------- BraState ---------- */
|
||||
|
||||
#define BRA_BUF_SIZE (1 << 14)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t bufPos;
|
||||
size_t bufConv;
|
||||
size_t bufTotal;
|
||||
|
||||
UInt32 methodId;
|
||||
int encodeMode;
|
||||
UInt32 delta;
|
||||
UInt32 ip;
|
||||
UInt32 x86State;
|
||||
Byte deltaState[DELTA_STATE_SIZE];
|
||||
|
||||
Byte buf[BRA_BUF_SIZE];
|
||||
} CBraState;
|
||||
|
||||
void BraState_Free(void *pp, ISzAlloc *alloc)
|
||||
{
|
||||
alloc->Free(alloc, pp);
|
||||
}
|
||||
|
||||
SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
|
||||
{
|
||||
CBraState *p = ((CBraState *)pp);
|
||||
UNUSEDPARAM(alloc);
|
||||
p->encodeMode = 0;
|
||||
p->ip = 0;
|
||||
if (p->methodId == XZ_ID_Delta)
|
||||
{
|
||||
if (propSize != 1)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
p->delta = (unsigned)props[0] + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (propSize == 4)
|
||||
{
|
||||
UInt32 v = GetUi32(props);
|
||||
switch(p->methodId)
|
||||
{
|
||||
case XZ_ID_PPC:
|
||||
case XZ_ID_ARM:
|
||||
case XZ_ID_SPARC:
|
||||
if ((v & 3) != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
break;
|
||||
case XZ_ID_ARMT:
|
||||
if ((v & 1) != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
break;
|
||||
case XZ_ID_IA64:
|
||||
if ((v & 0xF) != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
break;
|
||||
}
|
||||
p->ip = v;
|
||||
}
|
||||
else if (propSize != 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
void BraState_Init(void *pp)
|
||||
{
|
||||
CBraState *p = ((CBraState *)pp);
|
||||
p->bufPos = p->bufConv = p->bufTotal = 0;
|
||||
x86_Convert_Init(p->x86State);
|
||||
if (p->methodId == XZ_ID_Delta)
|
||||
Delta_Init(p->deltaState);
|
||||
}
|
||||
|
||||
#define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: p->bufConv = isa ## _Convert(p->buf, p->bufTotal, p->ip, p->encodeMode); break;
|
||||
|
||||
static SRes BraState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
|
||||
{
|
||||
CBraState *p = ((CBraState *)pp);
|
||||
SizeT destLenOrig = *destLen;
|
||||
SizeT srcLenOrig = *srcLen;
|
||||
UNUSEDPARAM(finishMode);
|
||||
*destLen = 0;
|
||||
*srcLen = 0;
|
||||
*wasFinished = 0;
|
||||
while (destLenOrig > 0)
|
||||
{
|
||||
if (p->bufPos != p->bufConv)
|
||||
{
|
||||
size_t curSize = p->bufConv - p->bufPos;
|
||||
if (curSize > destLenOrig)
|
||||
curSize = destLenOrig;
|
||||
memcpy(dest, p->buf + p->bufPos, curSize);
|
||||
p->bufPos += curSize;
|
||||
*destLen += curSize;
|
||||
dest += curSize;
|
||||
destLenOrig -= curSize;
|
||||
continue;
|
||||
}
|
||||
p->bufTotal -= p->bufPos;
|
||||
memmove(p->buf, p->buf + p->bufPos, p->bufTotal);
|
||||
p->bufPos = 0;
|
||||
p->bufConv = 0;
|
||||
{
|
||||
size_t curSize = BRA_BUF_SIZE - p->bufTotal;
|
||||
if (curSize > srcLenOrig)
|
||||
curSize = srcLenOrig;
|
||||
memcpy(p->buf + p->bufTotal, src, curSize);
|
||||
*srcLen += curSize;
|
||||
src += curSize;
|
||||
srcLenOrig -= curSize;
|
||||
p->bufTotal += curSize;
|
||||
}
|
||||
if (p->bufTotal == 0)
|
||||
break;
|
||||
switch(p->methodId)
|
||||
{
|
||||
case XZ_ID_Delta:
|
||||
if (p->encodeMode)
|
||||
Delta_Encode(p->deltaState, p->delta, p->buf, p->bufTotal);
|
||||
else
|
||||
Delta_Decode(p->deltaState, p->delta, p->buf, p->bufTotal);
|
||||
p->bufConv = p->bufTotal;
|
||||
break;
|
||||
case XZ_ID_X86:
|
||||
p->bufConv = x86_Convert(p->buf, p->bufTotal, p->ip, &p->x86State, p->encodeMode);
|
||||
break;
|
||||
CASE_BRA_CONV(PPC)
|
||||
CASE_BRA_CONV(IA64)
|
||||
CASE_BRA_CONV(ARM)
|
||||
CASE_BRA_CONV(ARMT)
|
||||
CASE_BRA_CONV(SPARC)
|
||||
default:
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
p->ip += (UInt32)p->bufConv;
|
||||
|
||||
if (p->bufConv == 0)
|
||||
{
|
||||
if (!srcWasFinished)
|
||||
break;
|
||||
p->bufConv = p->bufTotal;
|
||||
}
|
||||
}
|
||||
if (p->bufTotal == p->bufPos && srcLenOrig == 0 && srcWasFinished)
|
||||
*wasFinished = 1;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, ISzAlloc *alloc)
|
||||
{
|
||||
CBraState *decoder;
|
||||
if (id != XZ_ID_Delta &&
|
||||
id != XZ_ID_X86 &&
|
||||
id != XZ_ID_PPC &&
|
||||
id != XZ_ID_IA64 &&
|
||||
id != XZ_ID_ARM &&
|
||||
id != XZ_ID_ARMT &&
|
||||
id != XZ_ID_SPARC)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
p->p = 0;
|
||||
decoder = alloc->Alloc(alloc, sizeof(CBraState));
|
||||
if (decoder == 0)
|
||||
return SZ_ERROR_MEM;
|
||||
decoder->methodId = (UInt32)id;
|
||||
p->p = decoder;
|
||||
p->Free = BraState_Free;
|
||||
p->SetProps = BraState_SetProps;
|
||||
p->Init = BraState_Init;
|
||||
p->Code = BraState_Code;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
/* ---------- SbState ---------- */
|
||||
|
||||
#ifdef USE_SUBBLOCK
|
||||
|
||||
static void SbState_Free(void *pp, ISzAlloc *alloc)
|
||||
{
|
||||
CSubblockDec *p = (CSubblockDec *)pp;
|
||||
SubblockDec_Free(p, alloc);
|
||||
alloc->Free(alloc, pp);
|
||||
}
|
||||
|
||||
static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
|
||||
{
|
||||
pp = pp;
|
||||
props = props;
|
||||
alloc = alloc;
|
||||
return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static void SbState_Init(void *pp)
|
||||
{
|
||||
SubblockDec_Init((CSubblockDec *)pp);
|
||||
}
|
||||
|
||||
static SRes SbState_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
|
||||
{
|
||||
ECoderStatus status;
|
||||
SRes res = SubblockDec_Decode((CSubblockDec *)pp, dest, destLen, src, srcLen, finishMode, &status);
|
||||
srcWasFinished = srcWasFinished;
|
||||
*wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK);
|
||||
return res;
|
||||
}
|
||||
|
||||
SRes SbState_SetFromMethod(IStateCoder *p, ISzAlloc *alloc)
|
||||
{
|
||||
CSubblockDec *decoder;
|
||||
p->p = 0;
|
||||
decoder = alloc->Alloc(alloc, sizeof(CSubblockDec));
|
||||
if (decoder == 0)
|
||||
return SZ_ERROR_MEM;
|
||||
p->p = decoder;
|
||||
p->Free = SbState_Free;
|
||||
p->SetProps = SbState_SetProps;
|
||||
p->Init = SbState_Init;
|
||||
p->Code = SbState_Code;
|
||||
SubblockDec_Construct(decoder);
|
||||
return SZ_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ---------- Lzma2State ---------- */
|
||||
|
||||
static void Lzma2State_Free(void *pp, ISzAlloc *alloc)
|
||||
{
|
||||
Lzma2Dec_Free((CLzma2Dec *)pp, alloc);
|
||||
alloc->Free(alloc, pp);
|
||||
}
|
||||
|
||||
static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc)
|
||||
{
|
||||
if (propSize != 1)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
return Lzma2Dec_Allocate((CLzma2Dec *)pp, props[0], alloc);
|
||||
}
|
||||
|
||||
static void Lzma2State_Init(void *pp)
|
||||
{
|
||||
Lzma2Dec_Init((CLzma2Dec *)pp);
|
||||
}
|
||||
|
||||
static SRes Lzma2State_Code(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
|
||||
int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
|
||||
{
|
||||
ELzmaStatus status;
|
||||
/* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */
|
||||
SRes res = Lzma2Dec_DecodeToBuf((CLzma2Dec *)pp, dest, destLen, src, srcLen, finishMode, &status);
|
||||
UNUSEDPARAM(srcWasFinished);
|
||||
*wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK);
|
||||
return res;
|
||||
}
|
||||
|
||||
static SRes Lzma2State_SetFromMethod(IStateCoder *p, ISzAlloc *alloc)
|
||||
{
|
||||
CLzma2Dec *decoder = alloc->Alloc(alloc, sizeof(CLzma2Dec));
|
||||
p->p = decoder;
|
||||
if (decoder == 0)
|
||||
return SZ_ERROR_MEM;
|
||||
p->Free = Lzma2State_Free;
|
||||
p->SetProps = Lzma2State_SetProps;
|
||||
p->Init = Lzma2State_Init;
|
||||
p->Code = Lzma2State_Code;
|
||||
Lzma2Dec_Construct(decoder);
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
|
||||
void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc)
|
||||
{
|
||||
int i;
|
||||
p->alloc = alloc;
|
||||
p->buf = NULL;
|
||||
p->numCoders = 0;
|
||||
for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
|
||||
p->coders[i].p = NULL;
|
||||
}
|
||||
|
||||
void MixCoder_Free(CMixCoder *p)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < p->numCoders; i++)
|
||||
{
|
||||
IStateCoder *sc = &p->coders[i];
|
||||
if (p->alloc && sc->p)
|
||||
sc->Free(sc->p, p->alloc);
|
||||
}
|
||||
p->numCoders = 0;
|
||||
if (p->buf)
|
||||
{
|
||||
p->alloc->Free(p->alloc, p->buf);
|
||||
p->buf = NULL; /* 9.31: the BUG was fixed */
|
||||
}
|
||||
}
|
||||
|
||||
void MixCoder_Init(CMixCoder *p)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < p->numCoders - 1; i++)
|
||||
{
|
||||
p->size[i] = 0;
|
||||
p->pos[i] = 0;
|
||||
p->finished[i] = 0;
|
||||
}
|
||||
for (i = 0; i < p->numCoders; i++)
|
||||
{
|
||||
IStateCoder *coder = &p->coders[i];
|
||||
coder->Init(coder->p);
|
||||
}
|
||||
}
|
||||
|
||||
SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId)
|
||||
{
|
||||
IStateCoder *sc = &p->coders[coderIndex];
|
||||
p->ids[coderIndex] = methodId;
|
||||
switch(methodId)
|
||||
{
|
||||
case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, p->alloc);
|
||||
#ifdef USE_SUBBLOCK
|
||||
case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc);
|
||||
#endif
|
||||
}
|
||||
if (coderIndex == 0)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
return BraState_SetFromMethod(sc, methodId, p->alloc);
|
||||
}
|
||||
|
||||
SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen,
|
||||
const Byte *src, SizeT *srcLen, int srcWasFinished,
|
||||
ECoderFinishMode finishMode, ECoderStatus *status)
|
||||
{
|
||||
SizeT destLenOrig = *destLen;
|
||||
SizeT srcLenOrig = *srcLen;
|
||||
Bool allFinished = True;
|
||||
*destLen = 0;
|
||||
*srcLen = 0;
|
||||
*status = CODER_STATUS_NOT_FINISHED;
|
||||
|
||||
if (p->buf == 0)
|
||||
{
|
||||
p->buf = p->alloc->Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1));
|
||||
if (p->buf == 0)
|
||||
return SZ_ERROR_MEM;
|
||||
}
|
||||
|
||||
if (p->numCoders != 1)
|
||||
finishMode = CODER_FINISH_ANY;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Bool processed = False;
|
||||
int i;
|
||||
/*
|
||||
if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY)
|
||||
break;
|
||||
*/
|
||||
|
||||
for (i = 0; i < p->numCoders; i++)
|
||||
{
|
||||
SRes res;
|
||||
IStateCoder *coder = &p->coders[i];
|
||||
Byte *destCur;
|
||||
SizeT destLenCur, srcLenCur;
|
||||
const Byte *srcCur;
|
||||
int srcFinishedCur;
|
||||
int encodingWasFinished;
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
srcCur = src;
|
||||
srcLenCur = srcLenOrig - *srcLen;
|
||||
srcFinishedCur = srcWasFinished;
|
||||
}
|
||||
else
|
||||
{
|
||||
srcCur = p->buf + (CODER_BUF_SIZE * (i - 1)) + p->pos[i - 1];
|
||||
srcLenCur = p->size[i - 1] - p->pos[i - 1];
|
||||
srcFinishedCur = p->finished[i - 1];
|
||||
}
|
||||
|
||||
if (i == p->numCoders - 1)
|
||||
{
|
||||
destCur = dest;
|
||||
destLenCur = destLenOrig - *destLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p->pos[i] != p->size[i])
|
||||
continue;
|
||||
destCur = p->buf + (CODER_BUF_SIZE * i);
|
||||
destLenCur = CODER_BUF_SIZE;
|
||||
}
|
||||
|
||||
res = coder->Code(coder->p, destCur, &destLenCur, srcCur, &srcLenCur, srcFinishedCur, finishMode, &encodingWasFinished);
|
||||
|
||||
if (!encodingWasFinished)
|
||||
allFinished = False;
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
*srcLen += srcLenCur;
|
||||
src += srcLenCur;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->pos[i - 1] += srcLenCur;
|
||||
}
|
||||
|
||||
if (i == p->numCoders - 1)
|
||||
{
|
||||
*destLen += destLenCur;
|
||||
dest += destLenCur;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->size[i] = destLenCur;
|
||||
p->pos[i] = 0;
|
||||
p->finished[i] = encodingWasFinished;
|
||||
}
|
||||
|
||||
if (res != SZ_OK)
|
||||
return res;
|
||||
|
||||
if (destLenCur != 0 || srcLenCur != 0)
|
||||
processed = True;
|
||||
}
|
||||
if (!processed)
|
||||
break;
|
||||
}
|
||||
if (allFinished)
|
||||
*status = CODER_STATUS_FINISHED_WITH_MARK;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf)
|
||||
{
|
||||
*p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE);
|
||||
if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) !=
|
||||
GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE))
|
||||
return SZ_ERROR_NO_ARCHIVE;
|
||||
return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static Bool Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf)
|
||||
{
|
||||
return
|
||||
indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2) &&
|
||||
(GetUi32(buf) == CrcCalc(buf + 4, 6) &&
|
||||
flags == GetBe16(buf + 8) &&
|
||||
memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0);
|
||||
}
|
||||
|
||||
#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
|
||||
{ unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
|
||||
if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
|
||||
|
||||
|
||||
SRes XzBlock_Parse(CXzBlock *p, const Byte *header)
|
||||
{
|
||||
unsigned pos;
|
||||
int numFilters, i;
|
||||
UInt32 headerSize = (UInt32)header[0] << 2;
|
||||
|
||||
if (CrcCalc(header, headerSize) != GetUi32(header + headerSize))
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
|
||||
pos = 1;
|
||||
if (pos == headerSize)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
p->flags = header[pos++];
|
||||
|
||||
if (XzBlock_HasPackSize(p))
|
||||
{
|
||||
READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize);
|
||||
if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
}
|
||||
|
||||
if (XzBlock_HasUnpackSize(p))
|
||||
READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize);
|
||||
|
||||
numFilters = XzBlock_GetNumFilters(p);
|
||||
for (i = 0; i < numFilters; i++)
|
||||
{
|
||||
CXzFilter *filter = p->filters + i;
|
||||
UInt64 size;
|
||||
READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id);
|
||||
READ_VARINT_AND_CHECK(header, pos, headerSize, &size);
|
||||
if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
filter->propsSize = (UInt32)size;
|
||||
memcpy(filter->props, header + pos, (size_t)size);
|
||||
pos += (unsigned)size;
|
||||
|
||||
#ifdef XZ_DUMP
|
||||
printf("\nf[%d] = %2X: ", i, filter->id);
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
printf(" %2X", filter->props[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while (pos < headerSize)
|
||||
if (header[pos++] != 0)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes XzDec_Init(CMixCoder *p, const CXzBlock *block)
|
||||
{
|
||||
int i;
|
||||
Bool needReInit = True;
|
||||
int numFilters = XzBlock_GetNumFilters(block);
|
||||
if (numFilters == p->numCoders)
|
||||
{
|
||||
for (i = 0; i < numFilters; i++)
|
||||
if (p->ids[i] != block->filters[numFilters - 1 - i].id)
|
||||
break;
|
||||
needReInit = (i != numFilters);
|
||||
}
|
||||
if (needReInit)
|
||||
{
|
||||
MixCoder_Free(p);
|
||||
p->numCoders = numFilters;
|
||||
for (i = 0; i < numFilters; i++)
|
||||
{
|
||||
const CXzFilter *f = &block->filters[numFilters - 1 - i];
|
||||
RINOK(MixCoder_SetFromMethod(p, i, f->id));
|
||||
}
|
||||
}
|
||||
for (i = 0; i < numFilters; i++)
|
||||
{
|
||||
const CXzFilter *f = &block->filters[numFilters - 1 - i];
|
||||
IStateCoder *sc = &p->coders[i];
|
||||
RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc));
|
||||
}
|
||||
MixCoder_Init(p);
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
SRes XzUnpacker_Create(CXzUnpacker *p, ISzAlloc *alloc)
|
||||
{
|
||||
MixCoder_Construct(&p->decoder, alloc);
|
||||
p->state = XZ_STATE_STREAM_HEADER;
|
||||
p->pos = 0;
|
||||
p->numStreams = 0;
|
||||
p->numBlocks = 0;
|
||||
p->padSize = 0;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
void XzUnpacker_Free(CXzUnpacker *p)
|
||||
{
|
||||
if (!p)
|
||||
return;
|
||||
MixCoder_Free(&p->decoder);
|
||||
cl_hash_destroy(p->check.sha);
|
||||
cl_hash_destroy(p->sha);
|
||||
p->sha = NULL;
|
||||
}
|
||||
|
||||
SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
||||
const Byte *src, SizeT *srcLen, int finishMode, ECoderStatus *status)
|
||||
{
|
||||
SizeT destLenOrig = *destLen;
|
||||
SizeT srcLenOrig = *srcLen;
|
||||
*destLen = 0;
|
||||
*srcLen = 0;
|
||||
*status = CODER_STATUS_NOT_SPECIFIED;
|
||||
for (;;)
|
||||
{
|
||||
SizeT srcRem = srcLenOrig - *srcLen;
|
||||
|
||||
if (p->state == XZ_STATE_BLOCK)
|
||||
{
|
||||
SizeT destLen2 = destLenOrig - *destLen;
|
||||
SizeT srcLen2 = srcLenOrig - *srcLen;
|
||||
SRes res;
|
||||
if (srcLen2 == 0 && destLen2 == 0)
|
||||
{
|
||||
*status = CODER_STATUS_NOT_FINISHED;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
res = MixCoder_Code(&p->decoder, dest, &destLen2, src, &srcLen2, False, finishMode, status);
|
||||
XzCheck_Update(&p->check, dest, destLen2);
|
||||
|
||||
(*srcLen) += srcLen2;
|
||||
src += srcLen2;
|
||||
p->packSize += srcLen2;
|
||||
|
||||
(*destLen) += destLen2;
|
||||
dest += destLen2;
|
||||
p->unpackSize += destLen2;
|
||||
|
||||
RINOK(res);
|
||||
|
||||
if (*status == CODER_STATUS_FINISHED_WITH_MARK)
|
||||
{
|
||||
Byte temp[32];
|
||||
unsigned num = Xz_WriteVarInt(temp, p->packSize + p->blockHeaderSize + XzFlags_GetCheckSize(p->streamFlags));
|
||||
num += Xz_WriteVarInt(temp + num, p->unpackSize);
|
||||
if ((p->sha))
|
||||
cl_update_hash(p->sha, temp, num);
|
||||
p->indexSize += num;
|
||||
p->numBlocks++;
|
||||
|
||||
p->state = XZ_STATE_BLOCK_FOOTER;
|
||||
p->pos = 0;
|
||||
p->alignPos = 0;
|
||||
}
|
||||
else if (srcLen2 == 0 && destLen2 == 0)
|
||||
return SZ_OK;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (srcRem == 0)
|
||||
{
|
||||
*status = CODER_STATUS_NEEDS_MORE_INPUT;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
switch(p->state)
|
||||
{
|
||||
case XZ_STATE_STREAM_HEADER:
|
||||
{
|
||||
if (p->pos < XZ_STREAM_HEADER_SIZE)
|
||||
{
|
||||
if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos])
|
||||
return SZ_ERROR_NO_ARCHIVE;
|
||||
p->buf[p->pos++] = *src++;
|
||||
(*srcLen)++;
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(Xz_ParseHeader(&p->streamFlags, p->buf));
|
||||
p->state = XZ_STATE_BLOCK_HEADER;
|
||||
p->sha = cl_hash_init("sha256");
|
||||
p->indexSize = 0;
|
||||
p->numBlocks = 0;
|
||||
p->pos = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case XZ_STATE_BLOCK_HEADER:
|
||||
{
|
||||
if (p->pos == 0)
|
||||
{
|
||||
p->buf[p->pos++] = *src++;
|
||||
(*srcLen)++;
|
||||
if (p->buf[0] == 0)
|
||||
{
|
||||
p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks);
|
||||
p->indexPos = p->indexPreSize;
|
||||
p->indexSize += p->indexPreSize;
|
||||
if ((p->sha)) {
|
||||
cl_finish_hash(p->sha, p->shaDigest);
|
||||
p->sha = cl_hash_init("sha256");
|
||||
}
|
||||
p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize);
|
||||
p->state = XZ_STATE_STREAM_INDEX;
|
||||
}
|
||||
p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4;
|
||||
}
|
||||
else if (p->pos != p->blockHeaderSize)
|
||||
{
|
||||
UInt32 cur = p->blockHeaderSize - p->pos;
|
||||
if (cur > srcRem)
|
||||
cur = (UInt32)srcRem;
|
||||
memcpy(p->buf + p->pos, src, cur);
|
||||
p->pos += cur;
|
||||
(*srcLen) += cur;
|
||||
src += cur;
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(XzBlock_Parse(&p->block, p->buf));
|
||||
p->state = XZ_STATE_BLOCK;
|
||||
p->packSize = 0;
|
||||
p->unpackSize = 0;
|
||||
XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags));
|
||||
RINOK(XzDec_Init(&p->decoder, &p->block));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case XZ_STATE_BLOCK_FOOTER:
|
||||
{
|
||||
if (((p->packSize + p->alignPos) & 3) != 0)
|
||||
{
|
||||
(*srcLen)++;
|
||||
p->alignPos++;
|
||||
if (*src++ != 0)
|
||||
return SZ_ERROR_CRC;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags);
|
||||
UInt32 cur = checkSize - p->pos;
|
||||
if (cur != 0)
|
||||
{
|
||||
if (cur > srcRem)
|
||||
cur = (UInt32)srcRem;
|
||||
memcpy(p->buf + p->pos, src, cur);
|
||||
p->pos += cur;
|
||||
(*srcLen) += cur;
|
||||
src += cur;
|
||||
}
|
||||
else
|
||||
{
|
||||
Byte digest[XZ_CHECK_SIZE_MAX];
|
||||
p->state = XZ_STATE_BLOCK_HEADER;
|
||||
p->pos = 0;
|
||||
if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0)
|
||||
return SZ_ERROR_CRC;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case XZ_STATE_STREAM_INDEX:
|
||||
{
|
||||
if (p->pos < p->indexPreSize)
|
||||
{
|
||||
(*srcLen)++;
|
||||
if (*src++ != p->buf[p->pos++])
|
||||
return SZ_ERROR_CRC;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p->indexPos < p->indexSize)
|
||||
{
|
||||
UInt64 cur = p->indexSize - p->indexPos;
|
||||
if (srcRem > cur)
|
||||
srcRem = (SizeT)cur;
|
||||
p->crc = CrcUpdate(p->crc, src, srcRem);
|
||||
if ((p->sha))
|
||||
cl_update_hash(p->sha, (void *)src, srcRem);
|
||||
(*srcLen) += srcRem;
|
||||
src += srcRem;
|
||||
p->indexPos += srcRem;
|
||||
}
|
||||
else if ((p->indexPos & 3) != 0)
|
||||
{
|
||||
Byte b = *src++;
|
||||
p->crc = CRC_UPDATE_BYTE(p->crc, b);
|
||||
(*srcLen)++;
|
||||
p->indexPos++;
|
||||
p->indexSize++;
|
||||
if (b != 0)
|
||||
return SZ_ERROR_CRC;
|
||||
}
|
||||
else
|
||||
{
|
||||
Byte digest[SHA256_DIGEST_SIZE];
|
||||
memset(&digest, 0, SHA256_DIGEST_SIZE);
|
||||
p->state = XZ_STATE_STREAM_INDEX_CRC;
|
||||
p->indexSize += 4;
|
||||
p->pos = 0;
|
||||
if ((p->sha)) {
|
||||
cl_finish_hash(p->sha, digest);
|
||||
p->sha = NULL;
|
||||
}
|
||||
|
||||
if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0)
|
||||
return SZ_ERROR_CRC;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case XZ_STATE_STREAM_INDEX_CRC:
|
||||
{
|
||||
if (p->pos < 4)
|
||||
{
|
||||
(*srcLen)++;
|
||||
p->buf[p->pos++] = *src++;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->state = XZ_STATE_STREAM_FOOTER;
|
||||
p->pos = 0;
|
||||
if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf))
|
||||
return SZ_ERROR_CRC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case XZ_STATE_STREAM_FOOTER:
|
||||
{
|
||||
UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos;
|
||||
if (cur > srcRem)
|
||||
cur = (UInt32)srcRem;
|
||||
memcpy(p->buf + p->pos, src, cur);
|
||||
p->pos += cur;
|
||||
(*srcLen) += cur;
|
||||
src += cur;
|
||||
if (p->pos == XZ_STREAM_FOOTER_SIZE)
|
||||
{
|
||||
p->state = XZ_STATE_STREAM_PADDING;
|
||||
p->numStreams++;
|
||||
p->padSize = 0;
|
||||
if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf))
|
||||
return SZ_ERROR_CRC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case XZ_STATE_STREAM_PADDING:
|
||||
{
|
||||
if (*src != 0)
|
||||
{
|
||||
if (((UInt32)p->padSize & 3) != 0)
|
||||
return SZ_ERROR_NO_ARCHIVE;
|
||||
p->pos = 0;
|
||||
p->state = XZ_STATE_STREAM_HEADER;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*srcLen)++;
|
||||
src++;
|
||||
p->padSize++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case XZ_STATE_BLOCK: break; /* to disable GCC warning */
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (p->state == XZ_STATE_FINISHED)
|
||||
*status = CODER_STATUS_FINISHED_WITH_MARK;
|
||||
return SZ_OK;
|
||||
*/
|
||||
}
|
||||
|
||||
Bool XzUnpacker_IsStreamWasFinished(CXzUnpacker *p)
|
||||
{
|
||||
return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0);
|
||||
}
|
||||
312
clamav/libclamav/7z/XzIn.c
Normal file
312
clamav/libclamav/7z/XzIn.c
Normal file
@@ -0,0 +1,312 @@
|
||||
/* XzIn.c - Xz input
|
||||
2009-06-19 : Igor Pavlov : Public domain */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "clamav.h"
|
||||
#include "7zCrc.h"
|
||||
#include "CpuArch.h"
|
||||
#include "Xz.h"
|
||||
|
||||
SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream)
|
||||
{
|
||||
Byte sig[XZ_STREAM_HEADER_SIZE];
|
||||
RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE));
|
||||
if (memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0)
|
||||
return SZ_ERROR_NO_ARCHIVE;
|
||||
return Xz_ParseHeader(p, sig);
|
||||
}
|
||||
|
||||
#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
|
||||
{ unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
|
||||
if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
|
||||
|
||||
SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, Bool *isIndex, UInt32 *headerSizeRes)
|
||||
{
|
||||
Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
|
||||
unsigned headerSize;
|
||||
*headerSizeRes = 0;
|
||||
RINOK(SeqInStream_ReadByte(inStream, &header[0]));
|
||||
headerSize = ((unsigned)header[0] << 2) + 4;
|
||||
if (headerSize == 0)
|
||||
{
|
||||
*headerSizeRes = 1;
|
||||
*isIndex = True;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
*isIndex = False;
|
||||
*headerSizeRes = headerSize;
|
||||
RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1));
|
||||
return XzBlock_Parse(p, header);
|
||||
}
|
||||
|
||||
#define ADD_SIZE_CHECH(size, val) \
|
||||
{ UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; }
|
||||
|
||||
UInt64 Xz_GetUnpackSize(const CXzStream *p)
|
||||
{
|
||||
UInt64 size = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < p->numBlocks; i++)
|
||||
ADD_SIZE_CHECH(size, p->blocks[i].unpackSize);
|
||||
return size;
|
||||
}
|
||||
|
||||
UInt64 Xz_GetPackSize(const CXzStream *p)
|
||||
{
|
||||
UInt64 size = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < p->numBlocks; i++)
|
||||
ADD_SIZE_CHECH(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3);
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream)
|
||||
{
|
||||
return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f));
|
||||
}
|
||||
*/
|
||||
|
||||
static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAlloc *alloc)
|
||||
{
|
||||
size_t i, numBlocks, crcStartPos, pos = 1;
|
||||
UInt32 crc;
|
||||
|
||||
if (size < 5 || buf[0] != 0)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
|
||||
size -= 4;
|
||||
crc = CrcCalc(buf, size);
|
||||
if (crc != GetUi32(buf + size))
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
|
||||
{
|
||||
UInt64 numBlocks64;
|
||||
READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64);
|
||||
numBlocks = (size_t)numBlocks64;
|
||||
if (numBlocks != numBlocks64 || numBlocks * 2 > size)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
}
|
||||
|
||||
crcStartPos = pos;
|
||||
Xz_Free(p, alloc);
|
||||
if (numBlocks != 0)
|
||||
{
|
||||
p->numBlocks = numBlocks;
|
||||
p->numBlocksAllocated = numBlocks;
|
||||
p->blocks = alloc->Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);
|
||||
if (p->blocks == 0)
|
||||
return SZ_ERROR_MEM;
|
||||
for (i = 0; i < numBlocks; i++)
|
||||
{
|
||||
CXzBlockSizes *block = &p->blocks[i];
|
||||
READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize);
|
||||
READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize);
|
||||
if (block->totalSize == 0)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
}
|
||||
}
|
||||
while ((pos & 3) != 0)
|
||||
if (buf[pos++] != 0)
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
|
||||
}
|
||||
|
||||
static SRes Xz_ReadIndex(CXzStream *p, ILookInStream *stream, UInt64 indexSize, ISzAlloc *alloc)
|
||||
{
|
||||
SRes res;
|
||||
size_t size;
|
||||
Byte *buf;
|
||||
if (indexSize > ((UInt32)1 << 31))
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
size = (size_t)indexSize;
|
||||
if (size != indexSize)
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
buf = alloc->Alloc(alloc, size);
|
||||
if (buf == 0)
|
||||
return SZ_ERROR_MEM;
|
||||
res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED);
|
||||
if (res == SZ_OK)
|
||||
res = Xz_ReadIndex2(p, buf, size, alloc);
|
||||
alloc->Free(alloc, buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
static SRes SeekFromCur(ILookInStream *inStream, Int64 *res)
|
||||
{
|
||||
return inStream->Seek(inStream, res, SZ_SEEK_CUR);
|
||||
}
|
||||
|
||||
static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAlloc *alloc)
|
||||
{
|
||||
UInt64 indexSize;
|
||||
Byte buf[XZ_STREAM_FOOTER_SIZE];
|
||||
|
||||
if ((*startOffset & 3) != 0 || *startOffset < XZ_STREAM_FOOTER_SIZE)
|
||||
return SZ_ERROR_NO_ARCHIVE;
|
||||
*startOffset = -XZ_STREAM_FOOTER_SIZE;
|
||||
RINOK(SeekFromCur(stream, startOffset));
|
||||
|
||||
RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE));
|
||||
|
||||
if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
|
||||
{
|
||||
Int64 i = 0;
|
||||
*startOffset += XZ_STREAM_FOOTER_SIZE;
|
||||
for (;;)
|
||||
{
|
||||
int j;
|
||||
size_t processedSize;
|
||||
#define TEMP_BUF_SIZE (1 << 10)
|
||||
Byte tempBuf[TEMP_BUF_SIZE];
|
||||
if (*startOffset < XZ_STREAM_FOOTER_SIZE || i > (1 << 16))
|
||||
return SZ_ERROR_NO_ARCHIVE;
|
||||
processedSize = (*startOffset > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)*startOffset;
|
||||
i += processedSize;
|
||||
*startOffset = -(Int64)processedSize;
|
||||
RINOK(SeekFromCur(stream, startOffset));
|
||||
RINOK(LookInStream_Read2(stream, tempBuf, processedSize, SZ_ERROR_NO_ARCHIVE));
|
||||
for (j = (int)processedSize; j >= 0; j--)
|
||||
if (tempBuf[j -1] != 0)
|
||||
break;
|
||||
if (j != 0)
|
||||
{
|
||||
if ((j & 3) != 0)
|
||||
return SZ_ERROR_NO_ARCHIVE;
|
||||
*startOffset += j;
|
||||
if (*startOffset < XZ_STREAM_FOOTER_SIZE)
|
||||
return SZ_ERROR_NO_ARCHIVE;
|
||||
*startOffset -= XZ_STREAM_FOOTER_SIZE;
|
||||
RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET));
|
||||
RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE));
|
||||
if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0)
|
||||
return SZ_ERROR_NO_ARCHIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p->flags = (CXzStreamFlags)GetBe16(buf + 8);
|
||||
|
||||
if (!XzFlags_IsSupported(p->flags))
|
||||
return SZ_ERROR_UNSUPPORTED;
|
||||
|
||||
if (GetUi32(buf) != CrcCalc(buf + 4, 6))
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
|
||||
indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2;
|
||||
|
||||
*startOffset = -(Int64)(indexSize + XZ_STREAM_FOOTER_SIZE);
|
||||
RINOK(SeekFromCur(stream, startOffset));
|
||||
|
||||
RINOK(Xz_ReadIndex(p, stream, indexSize, alloc));
|
||||
|
||||
{
|
||||
UInt64 totalSize = Xz_GetPackSize(p);
|
||||
UInt64 sum = XZ_STREAM_HEADER_SIZE + totalSize + indexSize;
|
||||
if (totalSize == XZ_SIZE_OVERFLOW ||
|
||||
sum >= ((UInt64)1 << 63) ||
|
||||
totalSize >= ((UInt64)1 << 63))
|
||||
return SZ_ERROR_ARCHIVE;
|
||||
*startOffset = -(Int64)sum;
|
||||
RINOK(SeekFromCur(stream, startOffset));
|
||||
}
|
||||
{
|
||||
CXzStreamFlags headerFlags;
|
||||
CSecToRead secToRead;
|
||||
SecToRead_CreateVTable(&secToRead);
|
||||
secToRead.realStream = stream;
|
||||
|
||||
RINOK(Xz_ReadHeader(&headerFlags, &secToRead.s));
|
||||
return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ---------- Xz Streams ---------- */
|
||||
|
||||
void Xzs_Construct(CXzs *p)
|
||||
{
|
||||
p->num = p->numAllocated = 0;
|
||||
p->streams = 0;
|
||||
}
|
||||
|
||||
void Xzs_Free(CXzs *p, ISzAlloc *alloc)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < p->num; i++)
|
||||
Xz_Free(&p->streams[i], alloc);
|
||||
alloc->Free(alloc, p->streams);
|
||||
p->num = p->numAllocated = 0;
|
||||
p->streams = 0;
|
||||
}
|
||||
|
||||
UInt64 Xzs_GetNumBlocks(const CXzs *p)
|
||||
{
|
||||
UInt64 num = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < p->num; i++)
|
||||
num += p->streams[i].numBlocks;
|
||||
return num;
|
||||
}
|
||||
|
||||
UInt64 Xzs_GetUnpackSize(const CXzs *p)
|
||||
{
|
||||
UInt64 size = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < p->num; i++)
|
||||
ADD_SIZE_CHECH(size, Xz_GetUnpackSize(&p->streams[i]));
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
UInt64 Xzs_GetPackSize(const CXzs *p)
|
||||
{
|
||||
UInt64 size = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < p->num; i++)
|
||||
ADD_SIZE_CHECH(size, Xz_GetTotalSize(&p->streams[i]));
|
||||
return size;
|
||||
}
|
||||
*/
|
||||
|
||||
SRes Xzs_ReadBackward(CXzs *p, ILookInStream *stream, Int64 *startOffset, ICompressProgress *progress, ISzAlloc *alloc)
|
||||
{
|
||||
Int64 endOffset = 0;
|
||||
RINOK(stream->Seek(stream, &endOffset, SZ_SEEK_END));
|
||||
*startOffset = endOffset;
|
||||
for (;;)
|
||||
{
|
||||
CXzStream st;
|
||||
SRes res;
|
||||
Xz_Construct(&st);
|
||||
res = Xz_ReadBackward(&st, stream, startOffset, alloc);
|
||||
st.startOffset = *startOffset;
|
||||
RINOK(res);
|
||||
if (p->num == p->numAllocated)
|
||||
{
|
||||
size_t newNum = p->num + p->num / 4 + 1;
|
||||
Byte *data = (Byte *)alloc->Alloc(alloc, newNum * sizeof(CXzStream));
|
||||
if (data == 0)
|
||||
return SZ_ERROR_MEM;
|
||||
p->numAllocated = newNum;
|
||||
memcpy(data, p->streams, p->num * sizeof(CXzStream));
|
||||
alloc->Free(alloc, p->streams);
|
||||
p->streams = (CXzStream *)data;
|
||||
}
|
||||
p->streams[p->num++] = st;
|
||||
if (*startOffset == 0)
|
||||
break;
|
||||
RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET));
|
||||
if (progress && progress->Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK)
|
||||
return SZ_ERROR_PROGRESS;
|
||||
}
|
||||
return SZ_OK;
|
||||
}
|
||||
339
clamav/libclamav/7z/lzma.diff
Normal file
339
clamav/libclamav/7z/lzma.diff
Normal file
@@ -0,0 +1,339 @@
|
||||
diff -wu lzma_orig//7zCrc.c 7z/7zCrc.c
|
||||
--- lzma_orig//7zCrc.c 2011-06-18 01:48:31.343602685 +0200
|
||||
+++ 7z/7zCrc.c 2011-06-18 01:27:02.221109100 +0200
|
||||
@@ -4,24 +4,12 @@
|
||||
#include "7zCrc.h"
|
||||
#include "CpuArch.h"
|
||||
|
||||
-#define kCrcPoly 0xEDB88320
|
||||
+const UInt32 g_CrcTable[256] = { 0x0, 0x77073096, 0xee0e612c, 0x990951ba, 0x76dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0xedb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x9b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x1db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x6b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0xf00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x86d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x3b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x4db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0xd6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0xa00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x26d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x5005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0xcb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0xbdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d };
|
||||
|
||||
-#ifdef MY_CPU_LE
|
||||
-#define CRC_NUM_TABLES 8
|
||||
-#else
|
||||
-#define CRC_NUM_TABLES 1
|
||||
-#endif
|
||||
|
||||
-typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
+#define CRC_UPDATE_BYTE_2(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
-static CRC_FUNC g_CrcUpdate;
|
||||
-UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
|
||||
-
|
||||
-#if CRC_NUM_TABLES == 1
|
||||
-
|
||||
-#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
-
|
||||
-static UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table)
|
||||
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
|
||||
{
|
||||
const Byte *p = (const Byte *)data;
|
||||
for (; size > 0; size--, p++)
|
||||
@@ -29,46 +17,7 @@
|
||||
return v;
|
||||
}
|
||||
|
||||
-#else
|
||||
-
|
||||
-UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
-UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
|
||||
-
|
||||
-#endif
|
||||
-
|
||||
-UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
|
||||
-{
|
||||
- return g_CrcUpdate(v, data, size, g_CrcTable);
|
||||
-}
|
||||
-
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
|
||||
{
|
||||
- return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL;
|
||||
-}
|
||||
-
|
||||
-void MY_FAST_CALL CrcGenerateTable()
|
||||
-{
|
||||
- UInt32 i;
|
||||
- for (i = 0; i < 256; i++)
|
||||
- {
|
||||
- UInt32 r = i;
|
||||
- unsigned j;
|
||||
- for (j = 0; j < 8; j++)
|
||||
- r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
|
||||
- g_CrcTable[i] = r;
|
||||
- }
|
||||
- #if CRC_NUM_TABLES == 1
|
||||
- g_CrcUpdate = CrcUpdateT1;
|
||||
- #else
|
||||
- for (; i < 256 * CRC_NUM_TABLES; i++)
|
||||
- {
|
||||
- UInt32 r = g_CrcTable[i - 256];
|
||||
- g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
|
||||
- }
|
||||
- g_CrcUpdate = CrcUpdateT4;
|
||||
- #ifdef MY_CPU_X86_OR_AMD64
|
||||
- if (!CPU_Is_InOrder())
|
||||
- g_CrcUpdate = CrcUpdateT8;
|
||||
- #endif
|
||||
- #endif
|
||||
+ return CrcUpdate(CRC_INIT_VAL, data, size) ^ CRC_INIT_VAL;
|
||||
}
|
||||
diff -wu lzma_orig//7zCrc.h 7z/7zCrc.h
|
||||
--- lzma_orig//7zCrc.h 2011-06-18 01:48:31.343602685 +0200
|
||||
+++ 7z/7zCrc.h 2011-06-18 01:27:02.229109090 +0200
|
||||
@@ -8,14 +8,7 @@
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
-extern UInt32 g_CrcTable[];
|
||||
-
|
||||
-/* Call CrcGenerateTable one time before other CRC functions */
|
||||
-void MY_FAST_CALL CrcGenerateTable(void);
|
||||
-
|
||||
#define CRC_INIT_VAL 0xFFFFFFFF
|
||||
-#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
|
||||
-#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
|
||||
|
||||
UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size);
|
||||
UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size);
|
||||
diff -wu lzma_orig//7zDec.c 7z/7zDec.c
|
||||
--- lzma_orig//7zDec.c 2011-06-18 01:48:31.347602680 +0200
|
||||
+++ 7z/7zDec.c 2011-06-18 01:27:02.229109090 +0200
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
-/* #define _7ZIP_PPMD_SUPPPORT */
|
||||
+#define _7ZIP_PPMD_SUPPPORT
|
||||
|
||||
#include "7z.h"
|
||||
|
||||
diff -wu lzma_orig//7zFile.c 7z/7zFile.c
|
||||
--- lzma_orig//7zFile.h 2011-06-18 01:48:31.347602680 +0200
|
||||
+++ 7z/7zFile.h 2013-08-13 14:29:34.193054251 +0200
|
||||
@@ -207,32 +207,6 @@
|
||||
#endif
|
||||
}
|
||||
|
||||
-WRes File_GetLength(CSzFile *p, UInt64 *length)
|
||||
-{
|
||||
- #ifdef USE_WINDOWS_FILE
|
||||
-
|
||||
- DWORD sizeHigh;
|
||||
- DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
|
||||
- if (sizeLow == 0xFFFFFFFF)
|
||||
- {
|
||||
- DWORD res = GetLastError();
|
||||
- if (res != NO_ERROR)
|
||||
- return res;
|
||||
- }
|
||||
- *length = (((UInt64)sizeHigh) << 32) + sizeLow;
|
||||
- return 0;
|
||||
-
|
||||
- #else
|
||||
-
|
||||
- long pos = ftell(p->file);
|
||||
- int res = fseek(p->file, 0, SEEK_END);
|
||||
- *length = ftell(p->file);
|
||||
- fseek(p->file, pos, SEEK_SET);
|
||||
- return res;
|
||||
-
|
||||
- #endif
|
||||
-}
|
||||
-
|
||||
|
||||
/* ---------- FileSeqInStream ---------- */
|
||||
|
||||
diff -wu lzma_orig//7zFile.h 7z/7zFile.h
|
||||
--- lzma_orig//7zFile.h 2011-06-18 01:48:31.347602680 +0200
|
||||
+++ 7z/7zFile.h 2013-08-13 14:27:14.856436384 +0200
|
||||
@@ -27,6 +27,7 @@
|
||||
#else
|
||||
FILE *file;
|
||||
#endif
|
||||
+ fmap_t *fmap;
|
||||
} CSzFile;
|
||||
|
||||
void File_Construct(CSzFile *p);
|
||||
@@ -48,7 +48,6 @@
|
||||
WRes File_Write(CSzFile *p, const void *data, size_t *size);
|
||||
|
||||
WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin);
|
||||
-WRes File_GetLength(CSzFile *p, UInt64 *length);
|
||||
|
||||
|
||||
/* ---------- FileInStream ---------- */
|
||||
diff -wu lzma_orig//CpuArch.h 7z/CpuArch.h
|
||||
--- lzma_orig//CpuArch.h 2011-06-18 01:48:31.363602662 +0200
|
||||
+++ 7z/CpuArch.h 2011-06-18 01:27:02.229109090 +0200
|
||||
@@ -5,6 +5,7 @@
|
||||
#define __CPU_ARCH_H
|
||||
|
||||
#include "Types.h"
|
||||
+#include "others.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
@@ -16,68 +17,8 @@
|
||||
If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform.
|
||||
*/
|
||||
|
||||
-#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
|
||||
-#define MY_CPU_AMD64
|
||||
-#endif
|
||||
-
|
||||
-#if defined(MY_CPU_AMD64) || defined(_M_IA64)
|
||||
-#define MY_CPU_64BIT
|
||||
-#endif
|
||||
-
|
||||
-#if defined(_M_IX86) || defined(__i386__)
|
||||
-#define MY_CPU_X86
|
||||
-#endif
|
||||
-
|
||||
-#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
|
||||
-#define MY_CPU_X86_OR_AMD64
|
||||
-#endif
|
||||
-
|
||||
-#if defined(MY_CPU_X86) || defined(_M_ARM)
|
||||
-#define MY_CPU_32BIT
|
||||
-#endif
|
||||
-
|
||||
-#if defined(_WIN32) && defined(_M_ARM)
|
||||
-#define MY_CPU_ARM_LE
|
||||
-#endif
|
||||
-
|
||||
-#if defined(_WIN32) && defined(_M_IA64)
|
||||
-#define MY_CPU_IA64_LE
|
||||
-#endif
|
||||
-
|
||||
-#if defined(MY_CPU_X86_OR_AMD64)
|
||||
-#define MY_CPU_LE_UNALIGN
|
||||
-#endif
|
||||
-
|
||||
-#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__)
|
||||
-#define MY_CPU_LE
|
||||
-#endif
|
||||
-
|
||||
-#if defined(__BIG_ENDIAN__)
|
||||
-#define MY_CPU_BE
|
||||
-#endif
|
||||
-
|
||||
-#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
|
||||
-Stop_Compiling_Bad_Endian
|
||||
-#endif
|
||||
-
|
||||
-#ifdef MY_CPU_LE_UNALIGN
|
||||
-
|
||||
-#define GetUi16(p) (*(const UInt16 *)(p))
|
||||
-#define GetUi32(p) (*(const UInt32 *)(p))
|
||||
-#define GetUi64(p) (*(const UInt64 *)(p))
|
||||
-#define SetUi16(p, d) *(UInt16 *)(p) = (d);
|
||||
-#define SetUi32(p, d) *(UInt32 *)(p) = (d);
|
||||
-#define SetUi64(p, d) *(UInt64 *)(p) = (d);
|
||||
-
|
||||
-#else
|
||||
-
|
||||
-#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8))
|
||||
-
|
||||
-#define GetUi32(p) ( \
|
||||
- ((const Byte *)(p))[0] | \
|
||||
- ((UInt32)((const Byte *)(p))[1] << 8) | \
|
||||
- ((UInt32)((const Byte *)(p))[2] << 16) | \
|
||||
- ((UInt32)((const Byte *)(p))[3] << 24))
|
||||
+#define GetUi16(p) (cli_readint16(p))
|
||||
+#define GetUi32(p) (cli_readint32(p))
|
||||
|
||||
#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
|
||||
|
||||
@@ -85,71 +26,12 @@
|
||||
((Byte *)(p))[0] = (Byte)_x_; \
|
||||
((Byte *)(p))[1] = (Byte)(_x_ >> 8); }
|
||||
|
||||
-#define SetUi32(p, d) { UInt32 _x_ = (d); \
|
||||
- ((Byte *)(p))[0] = (Byte)_x_; \
|
||||
- ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \
|
||||
- ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \
|
||||
- ((Byte *)(p))[3] = (Byte)(_x_ >> 24); }
|
||||
+#define SetUi32(p, d) (cli_writeint32(p, d))
|
||||
|
||||
#define SetUi64(p, d) { UInt64 _x64_ = (d); \
|
||||
SetUi32(p, (UInt32)_x64_); \
|
||||
SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); }
|
||||
|
||||
-#endif
|
||||
-
|
||||
-#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300)
|
||||
-
|
||||
-#pragma intrinsic(_byteswap_ulong)
|
||||
-#pragma intrinsic(_byteswap_uint64)
|
||||
-#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
|
||||
-#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
|
||||
-
|
||||
-#else
|
||||
-
|
||||
-#define GetBe32(p) ( \
|
||||
- ((UInt32)((const Byte *)(p))[0] << 24) | \
|
||||
- ((UInt32)((const Byte *)(p))[1] << 16) | \
|
||||
- ((UInt32)((const Byte *)(p))[2] << 8) | \
|
||||
- ((const Byte *)(p))[3] )
|
||||
-
|
||||
-#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
|
||||
-
|
||||
-#endif
|
||||
-
|
||||
-#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])
|
||||
-
|
||||
-
|
||||
-#ifdef MY_CPU_X86_OR_AMD64
|
||||
-
|
||||
-typedef struct
|
||||
-{
|
||||
- UInt32 maxFunc;
|
||||
- UInt32 vendor[3];
|
||||
- UInt32 ver;
|
||||
- UInt32 b;
|
||||
- UInt32 c;
|
||||
- UInt32 d;
|
||||
-} Cx86cpuid;
|
||||
-
|
||||
-enum
|
||||
-{
|
||||
- CPU_FIRM_INTEL,
|
||||
- CPU_FIRM_AMD,
|
||||
- CPU_FIRM_VIA
|
||||
-};
|
||||
-
|
||||
-Bool x86cpuid_CheckAndRead(Cx86cpuid *p);
|
||||
-int x86cpuid_GetFirm(const Cx86cpuid *p);
|
||||
-
|
||||
-#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F)
|
||||
-#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F)
|
||||
-#define x86cpuid_GetStepping(p) ((p)->ver & 0xF)
|
||||
-
|
||||
-Bool CPU_Is_InOrder();
|
||||
-Bool CPU_Is_Aes_Supported();
|
||||
-
|
||||
-#endif
|
||||
-
|
||||
EXTERN_C_END
|
||||
|
||||
#endif
|
||||
diff -wu lzma_orig//Types.h 7z/Types.h
|
||||
--- lzma_orig//Types.h 2011-06-18 01:48:31.379602643 +0200
|
||||
+++ 7z/Types.h 2011-06-18 01:27:02.229109090 +0200
|
||||
@@ -21,7 +21,7 @@
|
||||
#endif
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
-
|
||||
+#include "fmap.h"
|
||||
#define SZ_OK 0
|
||||
|
||||
#define SZ_ERROR_DATA 1
|
||||
@@ -164,6 +164,7 @@
|
||||
{
|
||||
SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
|
||||
SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
|
||||
+ off_t curpos;
|
||||
} ISeekInStream;
|
||||
|
||||
typedef struct
|
||||
222
clamav/libclamav/7z_iface.c
Normal file
222
clamav/libclamav/7z_iface.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2011-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: aCaB
|
||||
*
|
||||
* 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 defined(_WIN32)
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "clamav.h"
|
||||
#include "7z_iface.h"
|
||||
#include "lzma_iface.h"
|
||||
#include "scanners.h"
|
||||
#include "others.h"
|
||||
#include "fmap.h"
|
||||
|
||||
#include "7z/7z.h"
|
||||
#include "7z/7zAlloc.h"
|
||||
#include "7z/7zFile.h"
|
||||
|
||||
static ISzAlloc allocImp = {__lzma_wrap_alloc, __lzma_wrap_free}, allocTempImp = {__lzma_wrap_alloc, __lzma_wrap_free};
|
||||
|
||||
static SRes FileInStream_fmap_Read(void *pp, void *buf, size_t *size)
|
||||
{
|
||||
CFileInStream *p = (CFileInStream *)pp;
|
||||
size_t read_sz;
|
||||
|
||||
if (*size == 0)
|
||||
return 0;
|
||||
|
||||
read_sz = fmap_readn(p->file.fmap, buf, p->s.curpos, *size);
|
||||
if (read_sz == (size_t)-1) {
|
||||
*size = 0;
|
||||
return SZ_ERROR_READ;
|
||||
}
|
||||
|
||||
p->s.curpos += read_sz;
|
||||
|
||||
*size = read_sz;
|
||||
return SZ_OK;
|
||||
}
|
||||
|
||||
static SRes FileInStream_fmap_Seek(void *pp, Int64 *pos, ESzSeek origin)
|
||||
{
|
||||
CFileInStream *p = (CFileInStream *)pp;
|
||||
|
||||
switch (origin) {
|
||||
case SZ_SEEK_SET:
|
||||
p->s.curpos = *pos;
|
||||
break;
|
||||
case SZ_SEEK_CUR:
|
||||
p->s.curpos += *pos;
|
||||
*pos = p->s.curpos;
|
||||
break;
|
||||
case SZ_SEEK_END:
|
||||
p->s.curpos = p->file.fmap->len + *pos;
|
||||
*pos = p->s.curpos;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define UTFBUFSZ 256
|
||||
int cli_7unz(cli_ctx *ctx, size_t offset)
|
||||
{
|
||||
CFileInStream archiveStream;
|
||||
CLookToRead lookStream;
|
||||
CSzArEx db;
|
||||
SRes res;
|
||||
UInt16 utf16buf[UTFBUFSZ], *utf16name = utf16buf;
|
||||
int namelen = UTFBUFSZ;
|
||||
cl_error_t found = CL_CLEAN;
|
||||
Int64 begin_of_archive = offset;
|
||||
|
||||
/* Replacement for
|
||||
FileInStream_CreateVTable(&archiveStream); */
|
||||
archiveStream.s.Read = FileInStream_fmap_Read;
|
||||
archiveStream.s.Seek = FileInStream_fmap_Seek;
|
||||
archiveStream.s.curpos = 0;
|
||||
archiveStream.file.fmap = ctx->fmap;
|
||||
|
||||
LookToRead_CreateVTable(&lookStream, False);
|
||||
|
||||
if (archiveStream.s.Seek(&archiveStream.s, &begin_of_archive, SZ_SEEK_SET) != 0)
|
||||
return CL_CLEAN;
|
||||
|
||||
lookStream.realStream = &archiveStream.s;
|
||||
LookToRead_Init(&lookStream);
|
||||
|
||||
SzArEx_Init(&db);
|
||||
res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp);
|
||||
if (res == SZ_ERROR_ENCRYPTED && SCAN_HEURISTIC_ENCRYPTED_ARCHIVE) {
|
||||
cli_dbgmsg("cli_7unz: Encrypted header found in archive.\n");
|
||||
found = cli_append_potentially_unwanted(ctx, "Heuristics.Encrypted.7Zip");
|
||||
} else if (res == SZ_OK) {
|
||||
UInt32 i, blockIndex = 0xFFFFFFFF;
|
||||
Byte *outBuffer = 0;
|
||||
size_t outBufferSize = 0;
|
||||
unsigned int encrypted = 0;
|
||||
|
||||
for (i = 0; i < db.db.NumFiles; i++) {
|
||||
size_t offset = 0;
|
||||
size_t outSizeProcessed = 0;
|
||||
const CSzFileItem *f = db.db.Files + i;
|
||||
char *name;
|
||||
char *tmp_name;
|
||||
size_t j;
|
||||
int newnamelen, fd;
|
||||
|
||||
// abort if we would exceed max files or max scan time.
|
||||
if ((found = cli_checklimits("7unz", ctx, 0, 0, 0)))
|
||||
break;
|
||||
|
||||
if (f->IsDir)
|
||||
continue;
|
||||
|
||||
// skip this file if we would exceed max file size or max scan size. (we already checked for the max files and max scan time)
|
||||
if (cli_checklimits("7unz", ctx, f->Size, 0, 0))
|
||||
continue;
|
||||
|
||||
if (!db.FileNameOffsets)
|
||||
newnamelen = 0; /* no filename */
|
||||
else {
|
||||
newnamelen = SzArEx_GetFileNameUtf16(&db, i, NULL);
|
||||
if (newnamelen > namelen) {
|
||||
if (namelen > UTFBUFSZ)
|
||||
free(utf16name);
|
||||
utf16name = cli_malloc(newnamelen * 2);
|
||||
if (!utf16name) {
|
||||
found = CL_EMEM;
|
||||
break;
|
||||
}
|
||||
namelen = newnamelen;
|
||||
}
|
||||
SzArEx_GetFileNameUtf16(&db, i, utf16name);
|
||||
}
|
||||
|
||||
name = (char *)utf16name;
|
||||
for (j = 0; j < (size_t)newnamelen; j++) /* FIXME */
|
||||
name[j] = utf16name[j];
|
||||
name[j] = 0;
|
||||
cli_dbgmsg("cli_7unz: extracting %s\n", name);
|
||||
|
||||
res = SzArEx_Extract(&db, &lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize, &offset, &outSizeProcessed, &allocImp, &allocTempImp);
|
||||
if (res == SZ_ERROR_ENCRYPTED) {
|
||||
encrypted = 1;
|
||||
if (SCAN_HEURISTIC_ENCRYPTED_ARCHIVE) {
|
||||
cli_dbgmsg("cli_7unz: Encrypted files found in archive.\n");
|
||||
found = cli_append_potentially_unwanted(ctx, "Heuristics.Encrypted.7Zip");
|
||||
if (found != CL_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CL_VIRUS == cli_matchmeta(ctx, name, 0, f->Size, encrypted, i, f->CrcDefined ? f->Crc : 0, NULL)) {
|
||||
found = CL_VIRUS;
|
||||
break;
|
||||
}
|
||||
if (res != SZ_OK)
|
||||
cli_dbgmsg("cli_unz: extraction failed with %d\n", res);
|
||||
else if ((outBuffer == NULL) || (outSizeProcessed == 0)) {
|
||||
cli_dbgmsg("cli_unz: extracted empty file\n");
|
||||
} else {
|
||||
if ((found = cli_gentempfd(ctx->sub_tmpdir, &tmp_name, &fd)))
|
||||
break;
|
||||
|
||||
cli_dbgmsg("cli_7unz: Saving to %s\n", tmp_name);
|
||||
if (cli_writen(fd, outBuffer + offset, outSizeProcessed) != outSizeProcessed) {
|
||||
found = CL_EWRITE;
|
||||
}
|
||||
|
||||
found = cli_magic_scan_desc(fd, tmp_name, ctx, name, LAYER_ATTRIBUTES_NONE);
|
||||
|
||||
close(fd);
|
||||
if (!ctx->engine->keeptmp && cli_unlink(tmp_name))
|
||||
found = CL_EUNLINK;
|
||||
|
||||
free(tmp_name);
|
||||
if (found != CL_SUCCESS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
IAlloc_Free(&allocImp, outBuffer);
|
||||
}
|
||||
SzArEx_Free(&db, &allocImp);
|
||||
if (namelen > UTFBUFSZ)
|
||||
free(utf16name);
|
||||
|
||||
if (res == SZ_OK)
|
||||
cli_dbgmsg("cli_7unz: completed successfully\n");
|
||||
else if (res == SZ_ERROR_UNSUPPORTED)
|
||||
cli_dbgmsg("cli_7unz: unsupported\n");
|
||||
else if (res == SZ_ERROR_MEM)
|
||||
cli_dbgmsg("cli_7unz: oom\n");
|
||||
else if (res == SZ_ERROR_CRC)
|
||||
cli_dbgmsg("cli_7unz: crc mismatch\n");
|
||||
else if (res == SZ_ERROR_ENCRYPTED)
|
||||
cli_dbgmsg("cli_7unz: encrypted\n");
|
||||
else
|
||||
cli_dbgmsg("cli_7unz: error %d\n", res);
|
||||
|
||||
return found;
|
||||
}
|
||||
33
clamav/libclamav/7z_iface.h
Normal file
33
clamav/libclamav/7z_iface.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2011-2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: aCaB
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __7Z_IFACE_H
|
||||
#define __7Z_IFACE_H
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "clamav-config.h"
|
||||
#endif
|
||||
|
||||
#include "others.h"
|
||||
|
||||
int cli_7unz(cli_ctx *, size_t);
|
||||
|
||||
#endif
|
||||
689
clamav/libclamav/CMakeLists.txt
Normal file
689
clamav/libclamav/CMakeLists.txt
Normal file
@@ -0,0 +1,689 @@
|
||||
# Copyright (C) 2020-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
|
||||
include_directories(
|
||||
${LIBXML2_INCLUDE_DIR}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
$<TARGET_PROPERTY:ClamAV::libunrar_iface_iface,INTERFACE_INCLUDE_DIRECTORIES>
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
)
|
||||
|
||||
configure_file(version.h.in version.h)
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
|
||||
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
|
||||
|
||||
# Windows compatibility headers
|
||||
include_directories(${CMAKE_SOURCE_DIR}/win32/compat)
|
||||
endif()
|
||||
|
||||
add_definitions(-DTHIS_IS_LIBCLAMAV)
|
||||
|
||||
# Enable overflow checks in TomsFastMath's fp_exptmod() function.
|
||||
add_definitions(-DTFM_CHECK)
|
||||
|
||||
# Just enable ASM in in TomsFastMath's on x86-64 where we know it works.
|
||||
# on i686 we run out of registers with -fPIC, and on ia64 we miscompile.
|
||||
if(NOT CMAKE_COMPILER_IS_GNUCC OR NOT (CMAKE_SIZEOF_VOID_P EQUAL 8))
|
||||
add_definitions(-DTFM_NO_ASM)
|
||||
endif()
|
||||
|
||||
# 3rd party libraries included in libclamav
|
||||
add_library( regex OBJECT )
|
||||
target_sources( regex
|
||||
PRIVATE
|
||||
regex/strlcpy.c
|
||||
regex/regcomp.c
|
||||
regex/regerror.c
|
||||
regex/regexec.c
|
||||
regex/regfree.c
|
||||
PUBLIC
|
||||
regex/cclass.h
|
||||
regex/cname.h
|
||||
regex/regex.h
|
||||
regex/regex2.h
|
||||
regex/utils.h )
|
||||
target_include_directories( regex
|
||||
PRIVATE ${CMAKE_BINARY_DIR}
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
|
||||
set_target_properties( regex PROPERTIES
|
||||
COMPILE_FLAGS "${WARNCFLAGS}" )
|
||||
target_link_libraries( regex
|
||||
PRIVATE
|
||||
PCRE2::pcre2
|
||||
JSONC::jsonc )
|
||||
|
||||
add_library( lzma_sdk OBJECT )
|
||||
target_sources( lzma_sdk
|
||||
PRIVATE
|
||||
7z/7zAlloc.c
|
||||
7z/7zBuf.c
|
||||
7z/7zBuf2.c
|
||||
7z/7zCrc.c
|
||||
7z/7zCrcOpt.c
|
||||
7z/7zDec.c
|
||||
7z/7zFile.c
|
||||
7z/7zIn.c
|
||||
7z/7zStream.c
|
||||
7z/Bcj2.c
|
||||
7z/Bra.c
|
||||
7z/Bra86.c
|
||||
7z/BraIA64.c
|
||||
7z/CpuArch.c
|
||||
7z/Delta.c
|
||||
7z/Lzma2Dec.c
|
||||
7z/LzmaDec.c
|
||||
7z/Ppmd7.c
|
||||
7z/Ppmd7Dec.c
|
||||
7z/Xz.c
|
||||
7z/XzCrc64.c
|
||||
7z/XzDec.c
|
||||
7z/XzIn.c
|
||||
PUBLIC
|
||||
7z/7z.h
|
||||
7z/Xz.h
|
||||
7z/Alloc.h
|
||||
7z/7zFile.h
|
||||
7z/XzCrc64.h
|
||||
7z/RotateDefs.h
|
||||
7z/Types.h
|
||||
7z/Ppmd7.h
|
||||
7z/LzmaDec.h
|
||||
7z/Ppmd.h
|
||||
7z/Lzma2Dec.h
|
||||
7z/Delta.h
|
||||
7z/CpuArch.h
|
||||
7z/CpuArch.h
|
||||
7z/Bra.h
|
||||
7z/Bcj2.h
|
||||
7z/7zVersion.h
|
||||
7z/7zCrc.h
|
||||
7z/7zBuf.h
|
||||
7z/7zAlloc.h )
|
||||
target_include_directories( lzma_sdk
|
||||
PRIVATE ${CMAKE_BINARY_DIR}
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
|
||||
set_target_properties( lzma_sdk PROPERTIES
|
||||
COMPILE_FLAGS "${WARNCFLAGS}" )
|
||||
target_link_libraries( lzma_sdk
|
||||
PRIVATE
|
||||
PCRE2::pcre2
|
||||
JSONC::jsonc )
|
||||
|
||||
if(MAINTAINER_MODE)
|
||||
bison_target( yara_grammar
|
||||
yara_grammar.y ${CMAKE_CURRENT_SOURCE_DIR}/yara_grammar.c )
|
||||
flex_target( yara_lexer
|
||||
yara_lexer.l ${CMAKE_CURRENT_SOURCE_DIR}/yara_lexer.c )
|
||||
add_flex_bison_dependency( yara_lexer yara_grammar )
|
||||
endif()
|
||||
|
||||
add_library( yara OBJECT )
|
||||
target_sources( yara
|
||||
PRIVATE
|
||||
yara_compiler.c
|
||||
yara_exec.c
|
||||
yara_hash.c
|
||||
yara_parser.c
|
||||
yara_arena.c
|
||||
${BISON_yara_grammar_OUTPUTS}
|
||||
${FLEX_yara_lexer_OUTPUTS}
|
||||
PUBLIC
|
||||
yara_arena.h
|
||||
yara_compiler.h
|
||||
yara_clam.h
|
||||
yara_hash.h
|
||||
yara_exec.h
|
||||
yara_parser.h )
|
||||
|
||||
if(MAINTAINER_MODE)
|
||||
target_sources( yara
|
||||
PRIVATE
|
||||
${BISON_yara_grammar_OUTPUTS}
|
||||
${FLEX_yara_lexer_OUTPUTS} )
|
||||
else()
|
||||
target_sources( yara
|
||||
PRIVATE
|
||||
yara_grammar.c
|
||||
yara_lexer.c )
|
||||
endif()
|
||||
|
||||
target_include_directories( yara
|
||||
PRIVATE
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR} )
|
||||
set_target_properties( yara PROPERTIES
|
||||
COMPILE_FLAGS "${WARNCFLAGS}" )
|
||||
target_link_libraries( yara
|
||||
PRIVATE
|
||||
PCRE2::pcre2
|
||||
JSONC::jsonc )
|
||||
|
||||
add_library( tomsfastmath OBJECT )
|
||||
target_sources( tomsfastmath
|
||||
PRIVATE
|
||||
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
|
||||
tomsfastmath/addsub/fp_cmp_mag.c
|
||||
tomsfastmath/addsub/fp_sub.c
|
||||
tomsfastmath/addsub/fp_sub_d.c
|
||||
tomsfastmath/addsub/fp_submod.c
|
||||
tomsfastmath/addsub/s_fp_add.c
|
||||
tomsfastmath/addsub/s_fp_sub.c
|
||||
tomsfastmath/bin/fp_radix_size.c
|
||||
tomsfastmath/bin/fp_read_radix.c
|
||||
tomsfastmath/bin/fp_read_signed_bin.c
|
||||
tomsfastmath/bin/fp_read_unsigned_bin.c
|
||||
tomsfastmath/bin/fp_reverse.c
|
||||
tomsfastmath/bin/fp_s_rmap.c
|
||||
tomsfastmath/bin/fp_signed_bin_size.c
|
||||
tomsfastmath/bin/fp_to_signed_bin.c
|
||||
tomsfastmath/bin/fp_to_unsigned_bin.c
|
||||
tomsfastmath/bin/fp_toradix.c
|
||||
tomsfastmath/bin/fp_toradix_n.c
|
||||
tomsfastmath/bin/fp_unsigned_bin_size.c
|
||||
tomsfastmath/bit/fp_cnt_lsb.c
|
||||
tomsfastmath/bit/fp_count_bits.c
|
||||
tomsfastmath/bit/fp_div_2.c
|
||||
tomsfastmath/bit/fp_div_2d.c
|
||||
tomsfastmath/bit/fp_lshd.c
|
||||
tomsfastmath/bit/fp_mod_2d.c
|
||||
tomsfastmath/bit/fp_rshd.c
|
||||
tomsfastmath/divide/fp_div.c
|
||||
tomsfastmath/divide/fp_div_d.c
|
||||
tomsfastmath/divide/fp_mod.c
|
||||
tomsfastmath/divide/fp_mod_d.c
|
||||
tomsfastmath/exptmod/fp_2expt.c
|
||||
tomsfastmath/exptmod/fp_exptmod.c
|
||||
tomsfastmath/misc/fp_ident.c
|
||||
tomsfastmath/misc/fp_set.c
|
||||
tomsfastmath/mont/fp_montgomery_calc_normalization.c
|
||||
tomsfastmath/mont/fp_montgomery_reduce.c
|
||||
tomsfastmath/mont/fp_montgomery_setup.c
|
||||
tomsfastmath/mul/fp_mul.c
|
||||
tomsfastmath/mul/fp_mul_comba.c
|
||||
tomsfastmath/mul/fp_mul_2.c
|
||||
tomsfastmath/mul/fp_mul_2d.c
|
||||
tomsfastmath/mul/fp_mul_comba_12.c
|
||||
tomsfastmath/mul/fp_mul_comba_17.c
|
||||
tomsfastmath/mul/fp_mul_comba_20.c
|
||||
tomsfastmath/mul/fp_mul_comba_24.c
|
||||
tomsfastmath/mul/fp_mul_comba_28.c
|
||||
tomsfastmath/mul/fp_mul_comba_3.c
|
||||
tomsfastmath/mul/fp_mul_comba_32.c
|
||||
tomsfastmath/mul/fp_mul_comba_4.c
|
||||
tomsfastmath/mul/fp_mul_comba_48.c
|
||||
tomsfastmath/mul/fp_mul_comba_6.c
|
||||
tomsfastmath/mul/fp_mul_comba_64.c
|
||||
tomsfastmath/mul/fp_mul_comba_7.c
|
||||
tomsfastmath/mul/fp_mul_comba_8.c
|
||||
tomsfastmath/mul/fp_mul_comba_9.c
|
||||
tomsfastmath/mul/fp_mul_comba_small_set.c
|
||||
tomsfastmath/mul/fp_mul_d.c
|
||||
tomsfastmath/mul/fp_mulmod.c
|
||||
tomsfastmath/numtheory/fp_invmod.c
|
||||
tomsfastmath/sqr/fp_sqr.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_12.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_17.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_20.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_24.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_28.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_3.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_32.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_4.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_48.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_6.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_64.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_7.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_8.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_9.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_generic.c
|
||||
tomsfastmath/sqr/fp_sqr_comba_small_set.c
|
||||
tomsfastmath/sqr/fp_sqrmod.c
|
||||
PUBLIC
|
||||
bignum.h )
|
||||
target_include_directories( tomsfastmath
|
||||
PRIVATE
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tomsfastmath/headers
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
|
||||
set_target_properties( tomsfastmath PROPERTIES
|
||||
COMPILE_FLAGS "${WARNCFLAGS}" )
|
||||
|
||||
# Bytecode Runtime
|
||||
add_library( bytecode_runtime OBJECT )
|
||||
if(LLVM_FOUND)
|
||||
target_sources( bytecode_runtime
|
||||
PRIVATE
|
||||
c++/detect.cpp
|
||||
c++/bytecode2llvm.cpp
|
||||
bytecode_priv.h
|
||||
bytecode.h )
|
||||
set_target_properties( bytecode_runtime PROPERTIES
|
||||
COMPILE_FLAGS "${WARNCXXFLAGS} ${CXX1XCXXFLAGS}" )
|
||||
target_compile_definitions( bytecode_runtime PRIVATE -D LLVM_VERSION=${LLVM_VERSION} )
|
||||
target_include_directories( bytecode_runtime PRIVATE ${LLVM_INCLUDE_DIRS} )
|
||||
else()
|
||||
target_sources( bytecode_runtime
|
||||
PRIVATE
|
||||
bytecode_nojit.c
|
||||
bytecode_priv.h
|
||||
bytecode.h )
|
||||
set_target_properties( bytecode_runtime PROPERTIES
|
||||
COMPILE_FLAGS "${WARNCFLAGS}" )
|
||||
endif()
|
||||
target_include_directories( bytecode_runtime
|
||||
PRIVATE ${CMAKE_BINARY_DIR}
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
|
||||
target_link_libraries( bytecode_runtime
|
||||
PRIVATE
|
||||
PCRE2::pcre2
|
||||
JSONC::jsonc )
|
||||
|
||||
# not using an object library for the sake of Xcode compatibility
|
||||
# See: https://cmake.org/pipermail/cmake/2016-May/063479.html
|
||||
set(LIBCLAMAV_SOURCES
|
||||
# Utils
|
||||
blob.c blob.h
|
||||
conv.c conv.h
|
||||
fpu.c fpu.h
|
||||
hashtab.c hashtab.h
|
||||
iowrap.c iowrap.h
|
||||
json_api.c json_api.h
|
||||
jsparse/textbuf.h
|
||||
others_common.c others.h
|
||||
qsort.c
|
||||
sf_base64decode.c sf_base64decode.h
|
||||
str.c str.h
|
||||
strlcat.c
|
||||
table.c table.h
|
||||
text.c text.h
|
||||
uniq.c uniq.h
|
||||
www.c www.h
|
||||
# Utils Disasm
|
||||
disasm-common.h disasm.c disasm.h disasmpriv.h
|
||||
# Matcher
|
||||
filtering.c filtering.h
|
||||
matcher-ac.c matcher-ac.h
|
||||
matcher-bm.c matcher-bm.h
|
||||
matcher-byte-comp.c matcher-byte-comp.h
|
||||
matcher-hash.c matcher-hash.h matcher-hash-types.h
|
||||
matcher-pcre.c matcher-pcre.h
|
||||
matcher.c matcher.h
|
||||
regex_pcre.c regex_pcre.h
|
||||
# Database
|
||||
cvd.c cvd.h
|
||||
dconf.c dconf.h
|
||||
dsig.c dsig.h
|
||||
readdb.c readdb.h
|
||||
# Core
|
||||
cache.c cache.h
|
||||
crtmgr.c crtmgr.h
|
||||
crypto.c
|
||||
default.h
|
||||
filetypes_int.h filetypes.c filetypes.h
|
||||
fmap.c fmap.h
|
||||
mpool.c mpool.h
|
||||
others.c
|
||||
perflogging.c perflogging.h
|
||||
scanners.c scanners.h
|
||||
textdet.c textdet.h
|
||||
version.c
|
||||
# file normalization (for matching)
|
||||
htmlnorm.c htmlnorm.h
|
||||
jsparse/generated/keywords.h
|
||||
jsparse/generated/operators.h
|
||||
jsparse/js-norm.c
|
||||
jsparse/js-norm.h
|
||||
jsparse/lexglobal.h
|
||||
textnorm.c textnorm.h
|
||||
# heuristics (hardcoded exploit/malware detection)
|
||||
partition_intersection.c partition_intersection.h
|
||||
special.c special.h
|
||||
# clamav statistics
|
||||
hostid_internal.c hostid_internal.h
|
||||
stats_json.c stats_json.h
|
||||
stats.c stats.h
|
||||
# clamav bytecode support
|
||||
bcfeatures.h
|
||||
builtin_bytecodes.h
|
||||
bytecode_api_decl.c
|
||||
bytecode_api_impl.h
|
||||
bytecode_api.c bytecode_api.h
|
||||
bytecode_detect.c bytecode_detect.h
|
||||
bytecode_hooks.h
|
||||
bytecode_priv.h
|
||||
bytecode_vm.c
|
||||
bytecode.c bytecode.h
|
||||
events.c events.h
|
||||
type_desc.h
|
||||
# utils: compression
|
||||
7z_iface.c 7z_iface.h
|
||||
explode.c explode.h
|
||||
inffixed64.h
|
||||
inflate64_priv.h inflate64.c inflate64.h
|
||||
lzma_iface.c lzma_iface.h
|
||||
lzw/lzwdec.c lzw/lzwdec.h
|
||||
xz_iface.c xz_iface.h
|
||||
# utils: encryption
|
||||
arc4.c arc4.h
|
||||
rijndael.c rijndael.h
|
||||
# utils: text conversion
|
||||
encoding_aliases.h
|
||||
entconv.c entconv.h
|
||||
entitylist.h
|
||||
# Data-Loss-Prevention
|
||||
dlp.c dlp.h
|
||||
#
|
||||
# FILE PARSERS
|
||||
#
|
||||
# autoit
|
||||
autoit.c autoit.h
|
||||
# binhex
|
||||
binhex.c binhex.h
|
||||
# cpio
|
||||
cpio.c cpio.h
|
||||
# install shield
|
||||
ishield.c ishield.h
|
||||
# cab / chm
|
||||
libmspack.c libmspack.h
|
||||
# msszdd
|
||||
msexpand.c msexpand.h
|
||||
# nsis
|
||||
nsis/bzlib_private.h
|
||||
nsis/bzlib.c
|
||||
nsis/infblock.c
|
||||
nsis/nsis_bzlib.h
|
||||
nsis/nsis_zconf.h
|
||||
nsis/nsis_zlib.h
|
||||
nsis/nsis_zutil.h
|
||||
nsis/nulsft.c nsis/nulsft.h
|
||||
# office docs
|
||||
hwp.c hwp.h
|
||||
msdoc.c msdoc.h
|
||||
msxml_parser.c msxml_parser.h
|
||||
msxml.c msxml.h
|
||||
ole2_extract.c ole2_extract.h
|
||||
xlm_extract.c xlm_extract.h
|
||||
ooxml.c ooxml.h
|
||||
rtf.c rtf.h
|
||||
vba_extract.c vba_extract.h
|
||||
# executables
|
||||
asn1.c asn1.h
|
||||
elf.c elf.h
|
||||
execs.c execs.h
|
||||
macho.c macho.h
|
||||
pe_icons.c pe_icons.h
|
||||
pe_structs.h
|
||||
pe.c pe.h
|
||||
rebuildpe.c rebuildpe.h
|
||||
# executable unpackers
|
||||
aspack.c aspack.h
|
||||
fsg.c fsg.h
|
||||
mew.c mew.h
|
||||
packlibs.c packlibs.h
|
||||
petite.c petite.h
|
||||
spin.c spin.h
|
||||
unsp.c unsp.h
|
||||
upack.c upack.h
|
||||
upx.c upx.h
|
||||
wwunpack.c wwunpack.h
|
||||
yc.c yc.h
|
||||
# mail & phishing
|
||||
iana_cctld.h
|
||||
iana_tld.h
|
||||
line.c line.h
|
||||
mbox.c mbox.h
|
||||
message.c message.h
|
||||
phish_domaincheck_db.c phish_domaincheck_db.h
|
||||
phish_allow_list.c phish_allow_list.h
|
||||
phishcheck.c phishcheck.h
|
||||
regex_list.c regex_list.h
|
||||
regex_suffix.c regex_suffix.h
|
||||
# sis
|
||||
sis.c sis.h
|
||||
# tnef
|
||||
tnef.c tnef.h
|
||||
# uuencode
|
||||
uuencode.c uuencode.h
|
||||
# swf (flash)
|
||||
swf.c swf.h
|
||||
# pdf
|
||||
pdf.c pdf.h
|
||||
pdfng.c
|
||||
pdfdecode.c pdfdecode.h
|
||||
# xdp
|
||||
xdp.c xdp.h
|
||||
# ARJ archive
|
||||
unarj.c unarj.h
|
||||
# TAR archive
|
||||
is_tar.c is_tar.h
|
||||
untar.c untar.h
|
||||
# ZIP archive
|
||||
unzip.c unzip.h
|
||||
# DMG archive
|
||||
adc.c adc.h
|
||||
dmg.c dmg.h
|
||||
# XAR archive
|
||||
xar.c xar.h
|
||||
# EGG archive
|
||||
egg.c egg.h
|
||||
# Master Boot Record partition
|
||||
mbr.c mbr.h
|
||||
# GUID Parition Table partition
|
||||
gpt.c gpt.h
|
||||
# Apple Partition Map partition
|
||||
apm.c apm.h
|
||||
# HFS+ partition
|
||||
hfsplus.c hfsplus.h
|
||||
# iso9660 partition
|
||||
iso9660.c iso9660.h
|
||||
# OpenIOC
|
||||
openioc.c openioc.h
|
||||
# JPEG image format checker
|
||||
jpeg.c jpeg.h
|
||||
# PNG image format checker
|
||||
png.c png.h
|
||||
# TIFF image format checker
|
||||
tiff.c tiff.h
|
||||
# GIF image format checker
|
||||
gif.c gif.h
|
||||
)
|
||||
|
||||
if(ENABLE_SHARED_LIB)
|
||||
# The clamav shared library.
|
||||
add_library( clamav SHARED )
|
||||
set_target_properties( clamav PROPERTIES
|
||||
VERSION ${LIBCLAMAV_VERSION}
|
||||
SOVERSION ${LIBCLAMAV_SOVERSION} )
|
||||
target_sources( clamav
|
||||
PRIVATE
|
||||
${LIBCLAMAV_SOURCES}
|
||||
PUBLIC
|
||||
clamav.h )
|
||||
if(WIN32)
|
||||
target_sources( clamav PRIVATE libclamav_main.c )
|
||||
endif()
|
||||
|
||||
target_include_directories( clamav
|
||||
PRIVATE ${CMAKE_BINARY_DIR} ${JSONC_INCLUDE_DIRS}
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
INTERFACE ${CMAKE_BINARY_DIR} )
|
||||
|
||||
target_link_libraries( clamav
|
||||
PUBLIC
|
||||
regex
|
||||
lzma_sdk
|
||||
yara
|
||||
tomsfastmath
|
||||
bytecode_runtime
|
||||
${LIBMSPACK}
|
||||
ClamAV::libclamav_rust
|
||||
ClamAV::libunrar_iface_iface
|
||||
OpenSSL::SSL
|
||||
OpenSSL::Crypto
|
||||
ZLIB::ZLIB
|
||||
BZip2::BZip2
|
||||
PCRE2::pcre2
|
||||
LibXml2::LibXml2
|
||||
JSONC::jsonc )
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries( clamav
|
||||
PUBLIC
|
||||
PThreadW32::pthreadw32
|
||||
ClamAV::win32_compat
|
||||
wsock32 ws2_32 bcrypt )
|
||||
else()
|
||||
target_link_libraries( clamav
|
||||
PUBLIC
|
||||
Threads::Threads
|
||||
Iconv::Iconv
|
||||
${CMAKE_DL_LIBS}
|
||||
m )
|
||||
endif()
|
||||
set_target_properties( clamav PROPERTIES
|
||||
COMPILE_FLAGS "${WARNCFLAGS}"
|
||||
VERSION ${LIBCLAMAV_VERSION} SOVERSION ${LIBCLAMAV_SOVERSION} )
|
||||
|
||||
if (APPLE AND CLAMAV_SIGN_FILE)
|
||||
set_target_properties( clamav PROPERTIES
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ${CODE_SIGN_IDENTITY}
|
||||
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${DEVELOPMENT_TEAM_ID}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set_target_properties( clamav PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
||||
else()
|
||||
target_link_libraries( clamav PUBLIC Iconv::Iconv )
|
||||
endif()
|
||||
if(WIN32)
|
||||
install( TARGETS clamav DESTINATION . COMPONENT libraries )
|
||||
install( FILES $<TARGET_PDB_FILE:clamav> DESTINATION . OPTIONAL COMPONENT libraries )
|
||||
# Also install shared library (DLL) dependencies
|
||||
install( CODE [[
|
||||
file(GET_RUNTIME_DEPENDENCIES
|
||||
LIBRARIES
|
||||
$<TARGET_FILE:ClamAV::libclamav>
|
||||
RESOLVED_DEPENDENCIES_VAR _r_deps
|
||||
UNRESOLVED_DEPENDENCIES_VAR _u_deps
|
||||
DIRECTORIES
|
||||
$<TARGET_FILE_DIR:OpenSSL::SSL>
|
||||
$<TARGET_FILE_DIR:OpenSSL::Crypto>
|
||||
$<TARGET_FILE_DIR:ZLIB::ZLIB>
|
||||
$<TARGET_FILE_DIR:BZip2::BZip2>
|
||||
$<TARGET_FILE_DIR:PCRE2::pcre2>
|
||||
$<TARGET_FILE_DIR:LibXml2::LibXml2>
|
||||
$<TARGET_FILE_DIR:JSONC::jsonc>
|
||||
)
|
||||
foreach(_file ${_r_deps})
|
||||
string(TOLOWER ${_file} _file_lower)
|
||||
if(NOT ${_file_lower} MATCHES "c:[\\/]windows[\\/]system32.*")
|
||||
file(INSTALL
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}"
|
||||
TYPE SHARED_LIBRARY
|
||||
FOLLOW_SYMLINK_CHAIN
|
||||
FILES "${_file}"
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
#message("UNRESOLVED_DEPENDENCIES_VAR: ${_u_deps}")
|
||||
]]
|
||||
COMPONENT libraries )
|
||||
else()
|
||||
install( TARGETS clamav DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries )
|
||||
endif()
|
||||
|
||||
if(LLVM_FOUND)
|
||||
target_link_directories( clamav PUBLIC ${LLVM_LIBRARY_DIRS} )
|
||||
target_link_libraries( clamav PUBLIC ${LLVM_LIBRARIES} )
|
||||
endif()
|
||||
|
||||
add_library( ClamAV::libclamav ALIAS clamav )
|
||||
endif()
|
||||
|
||||
if(ENABLE_STATIC_LIB)
|
||||
# The clamav static library.
|
||||
add_library( clamav_static STATIC)
|
||||
target_sources( clamav_static
|
||||
PRIVATE
|
||||
${LIBCLAMAV_SOURCES}
|
||||
PUBLIC
|
||||
clamav.h )
|
||||
if(WIN32)
|
||||
target_sources( clamav_static PRIVATE libclamav_main.c )
|
||||
endif()
|
||||
|
||||
target_include_directories( clamav_static
|
||||
PRIVATE ${CMAKE_BINARY_DIR} ${JSONC_INCLUDE_DIRS}
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
INTERFACE ${CMAKE_BINARY_DIR} )
|
||||
|
||||
target_link_libraries( clamav_static
|
||||
PUBLIC
|
||||
regex
|
||||
lzma_sdk
|
||||
yara
|
||||
tomsfastmath
|
||||
bytecode_runtime
|
||||
${LIBMSPACK}
|
||||
ClamAV::libclamav_rust
|
||||
OpenSSL::SSL
|
||||
OpenSSL::Crypto
|
||||
ZLIB::ZLIB
|
||||
BZip2::BZip2
|
||||
PCRE2::pcre2
|
||||
LibXml2::LibXml2
|
||||
JSONC::jsonc )
|
||||
if (ENABLE_UNRAR)
|
||||
target_link_libraries( clamav_static PUBLIC ClamAV::libunrar_iface_static ClamAV::libunrar_iface_iface)
|
||||
endif()
|
||||
if (WIN32)
|
||||
target_link_libraries( clamav_static
|
||||
PUBLIC
|
||||
PThreadW32::pthreadw32
|
||||
ClamAV::win32_compat
|
||||
wsock32 ws2_32 bcrypt )
|
||||
else()
|
||||
target_link_libraries( clamav_static
|
||||
PUBLIC
|
||||
Threads::Threads
|
||||
Iconv::Iconv
|
||||
${CMAKE_DL_LIBS}
|
||||
m )
|
||||
endif()
|
||||
set_target_properties( clamav_static PROPERTIES
|
||||
ARCHIVE_OUTPUT_NAME clamav_static
|
||||
COMPILE_FLAGS "${WARNCFLAGS}"
|
||||
VERSION ${LIBCLAMAV_VERSION} SOVERSION ${LIBCLAMAV_SOVERSION} )
|
||||
target_compile_definitions( clamav_static PUBLIC clamav_staticLIB )
|
||||
if(WIN32)
|
||||
install( TARGETS clamav_static DESTINATION . COMPONENT libraries )
|
||||
else()
|
||||
install( TARGETS clamav_static DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries )
|
||||
endif()
|
||||
|
||||
add_library( ClamAV::libclamav_static ALIAS clamav_static )
|
||||
if(NOT ENABLE_SHARED_LIB)
|
||||
add_library( ClamAV::libclamav ALIAS clamav_static )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES
|
||||
clamav.h
|
||||
${CMAKE_BINARY_DIR}/clamav-types.h
|
||||
${CMAKE_BINARY_DIR}/clamav-version.h
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
COMPONENT libraries)
|
||||
125
clamav/libclamav/Doxyfile
Normal file
125
clamav/libclamav/Doxyfile
Normal file
@@ -0,0 +1,125 @@
|
||||
PROJECT_NAME = ClamAV - Libclamav
|
||||
OUTPUT_DIRECTORY = ../docs/libclamav
|
||||
WARNINGS = YES
|
||||
FILE_PATTERNS = *.c *.h
|
||||
PERL_PATH = /usr/bin/perl
|
||||
SEARCHENGINE = YES
|
||||
|
||||
GENERATE_LATEX=NO
|
||||
OPTIMIZE_OUTPUT_FOR_C=YES
|
||||
HAVE_DOT=YES
|
||||
CALL_GRAPH=YES
|
||||
CALLER_GRAPH=YES
|
||||
JAVADOC_AUTOBRIEF=YES
|
||||
GENERATE_MAN=NO
|
||||
EXAMPLE_PATH=examples
|
||||
|
||||
DOT_CLEANUP=NO
|
||||
MAX_DOT_GRAPH_DEPTH=3
|
||||
|
||||
EXTRACT_ALL=YES
|
||||
INPUT = . \
|
||||
7z \
|
||||
c++ \
|
||||
c++/config \
|
||||
c++/llvm \
|
||||
c++/llvm/autoconf \
|
||||
c++/llvm/autoconf/m4 \
|
||||
c++/llvm/cmake \
|
||||
c++/llvm/cmake/modules \
|
||||
c++/llvm/docs \
|
||||
c++/llvm/include \
|
||||
c++/llvm/include/llvm \
|
||||
c++/llvm/include/llvm/ADT \
|
||||
c++/llvm/include/llvm/Analysis \
|
||||
c++/llvm/include/llvm/Assembly \
|
||||
c++/llvm/include/llvm/Bitcode \
|
||||
c++/llvm/include/llvm-c \
|
||||
c++/llvm/include/llvm/CodeGen \
|
||||
c++/llvm/include/llvm/CompilerDriver \
|
||||
c++/llvm/include/llvm/Config \
|
||||
c++/llvm/include/llvm-c/Transforms \
|
||||
c++/llvm/include/llvm/ExecutionEngine \
|
||||
c++/llvm/include/llvm/MC \
|
||||
c++/llvm/include/llvm/MC/MCParser \
|
||||
c++/llvm/include/llvm/Support \
|
||||
c++/llvm/include/llvm/System \
|
||||
c++/llvm/include/llvm/Target \
|
||||
c++/llvm/include/llvm/Transforms \
|
||||
c++/llvm/include/llvm/Transforms/IPO \
|
||||
c++/llvm/include/llvm/Transforms/Utils \
|
||||
c++/llvm/lib \
|
||||
c++/llvm/lib/Analysis \
|
||||
c++/llvm/lib/Analysis/IPA \
|
||||
c++/llvm/lib/CodeGen \
|
||||
c++/llvm/lib/CodeGen/PBQP \
|
||||
c++/llvm/lib/CodeGen/PBQP/Heuristics \
|
||||
c++/llvm/lib/CodeGen/SelectionDAG \
|
||||
c++/llvm/lib/ExecutionEngine \
|
||||
c++/llvm/lib/ExecutionEngine/JIT \
|
||||
c++/llvm/lib/MC \
|
||||
c++/llvm/lib/Support \
|
||||
c++/llvm/lib/System \
|
||||
c++/llvm/lib/System/Unix \
|
||||
c++/llvm/lib/System/Win32 \
|
||||
c++/llvm/lib/Target \
|
||||
c++/llvm/lib/Target/PowerPC \
|
||||
c++/llvm/lib/Target/PowerPC/TargetInfo \
|
||||
c++/llvm/lib/Target/X86 \
|
||||
c++/llvm/lib/Target/X86/TargetInfo \
|
||||
c++/llvm/lib/Transforms \
|
||||
c++/llvm/lib/Transforms/Hello \
|
||||
c++/llvm/lib/Transforms/Instrumentation \
|
||||
c++/llvm/lib/Transforms/IPO \
|
||||
c++/llvm/lib/Transforms/Scalar \
|
||||
c++/llvm/lib/Transforms/Utils \
|
||||
c++/llvm/lib/VMCore \
|
||||
c++/llvm/utils \
|
||||
c++/llvm/utils/bugpoint \
|
||||
c++/llvm/utils/buildit \
|
||||
c++/llvm/utils/count \
|
||||
c++/llvm/utils/crosstool \
|
||||
c++/llvm/utils/crosstool/ARM \
|
||||
c++/llvm/utils/emacs \
|
||||
c++/llvm/utils/git \
|
||||
c++/llvm/utils/jedit \
|
||||
c++/llvm/utils/lint \
|
||||
c++/llvm/utils/lit \
|
||||
c++/llvm/utils/lit/lit \
|
||||
c++/llvm/utils/lit/lit/ExampleTests \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/Clang \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/LLVM.InTree \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/LLVM.InTree/test \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/LLVM.InTree/test/Bar \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/LLVM.OutOfTree \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/LLVM.OutOfTree/obj/test/Foo \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/LLVM.OutOfTree/src/test/Foo \
|
||||
c++/llvm/utils/lit/lit/ExampleTests.ObjDir \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/ShExternal \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/ShInternal \
|
||||
c++/llvm/utils/lit/lit/ExampleTests/TclTest \
|
||||
c++/llvm/utils/llvm-lit \
|
||||
c++/llvm/utils/Misc \
|
||||
c++/llvm/utils/TableGen \
|
||||
c++/llvm/utils/valgrind \
|
||||
c++/llvm/utils/vim \
|
||||
c++/m4 \
|
||||
jsparse \
|
||||
jsparse/generated \
|
||||
nsis \
|
||||
regex \
|
||||
tomsfastmath \
|
||||
tomsfastmath/addsub \
|
||||
tomsfastmath/bin \
|
||||
tomsfastmath/bit \
|
||||
tomsfastmath/divide \
|
||||
tomsfastmath/exptmod \
|
||||
tomsfastmath/misc \
|
||||
tomsfastmath/mont \
|
||||
tomsfastmath/mul \
|
||||
tomsfastmath/numtheory \
|
||||
tomsfastmath/sqr
|
||||
286
clamav/libclamav/adc.c
Normal file
286
clamav/libclamav/adc.c
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: David Raynor <draynor@sourcefire.com>
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <errno.h>
|
||||
#if HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "clamav.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 %llu avail_out %llu state %u\n",
|
||||
(long long unsigned)strm->avail_in, (long long unsigned)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;
|
||||
}
|
||||
74
clamav/libclamav/adc.h
Normal file
74
clamav/libclamav/adc.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
* Copyright (C) 2013 Sourcefire, Inc.
|
||||
*
|
||||
* Authors: David Raynor <draynor@sourcefire.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user