更新libclamav库1.0.0版本

This commit is contained in:
2023-01-14 18:28:39 +08:00
parent b879ee0b2e
commit 45fe15f472
8531 changed files with 1222046 additions and 177272 deletions

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
View 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
View 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
View 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
View 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 */

View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

29
clamav/clamscan/manager.h Normal file
View 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

View 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
View 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
View 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
View 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
View 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

View 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
View 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
View 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
View 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;
}

View 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
View 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
View 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
View 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
View 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
View 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

View 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

View 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);

View 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;
}

View 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
View 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(&reg, 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(&reg, fname, 0, NULL, 0) == REG_NOMATCH) ? 0 : 1;
cli_regfree(&reg);
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
View 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

File diff suppressed because it is too large Load Diff

95
clamav/common/optparser.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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;
}

View 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
View 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 = .

View 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

View 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
}

View 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

File diff suppressed because it is too large Load Diff

176
clamav/freshclam/notify.c Normal file
View 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
View 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
View 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

View 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);
}

View 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

View 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;
}

View 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

View 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;
}

View 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;
}

View 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

View 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
View 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;
}

View 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;
}

View 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

File diff suppressed because it is too large Load Diff

View 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;
}

View 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

View 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
View 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;
}

View 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
View 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
View 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

View 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;
}

View 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;
}

View 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

View 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

View 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);
}

View 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

View 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;
}

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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
View 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
View 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

View 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);
}
}

View 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
View 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
View 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
View 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

View 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));
}

View 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
View 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
View 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;
}

View 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
View 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;
}

View 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

View 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
View 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
View 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
View 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