e3aaff8e |
/* |
e1cbc270 |
* Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
221825fd |
* Copyright (C) 2007-2013 Sourcefire, Inc. |
24555841 |
* |
2023340a |
* Authors: Tomasz Kojm |
e3aaff8e |
*
* This program is free software; you can redistribute it and/or modify |
bb34cb31 |
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. |
e3aaff8e |
*
* 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 |
48b7b4a7 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA. |
e3aaff8e |
*/
|
724b2bf7 |
#include "matcher.h"
|
8000d078 |
#ifndef __OTHERS_H_LC
#define __OTHERS_H_LC |
e3aaff8e |
|
a087f040 |
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
|
0c8d7368 |
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
|
fbc144c0 |
#if HAVE_PTHREAD_H
#include <pthread.h>
#endif
|
d9e258d5 |
#include <stdio.h> |
e3aaff8e |
#include <stdlib.h>
|
375beda4 |
#include "clamav.h" |
bc93eda0 |
#include "dconf.h" |
cb680655 |
#include "filetypes.h" |
998bcfa7 |
#include "fmap.h" |
f5a4018b |
#include "libclamunrar_iface/unrar_iface.h" |
2bc065d4 |
#include "regex/regex.h" |
52dd3a6b |
#include "bytecode.h" |
ab636570 |
#include "bytecode_api.h" |
63feb6cd |
#include "events.h" |
8997495d |
#include "crtmgr.h" |
baeb6253 |
|
e56f0949 |
#ifdef HAVE_JSON |
891d45ce |
#include "json-c/json.h" |
e56f0949 |
#endif |
baeb6253 |
#ifdef HAVE_YARA |
d03c18be |
#include "yara_clam.h" |
baeb6253 |
#endif |
375beda4 |
|
d3e752ad |
#if HAVE_LIBXML2
#define CLAMAV_MIN_XMLREADER_FLAGS (XML_PARSE_NOERROR | XML_PARSE_NONET)
#endif
|
a37a861e |
/*
* CL_FLEVEL is the signature f-level specific to the current code and
* should never be modified
* CL_FLEVEL_DCONF is used in the dconf module and can be bumped by
* distribution packagers provided they fix *all* security issues found
* in the old versions of ClamAV. Updating CL_FLEVEL_DCONF will result
* in re-enabling affected modules.
*/
|
a02a7ef2 |
#define CL_FLEVEL 111 |
288057e9 |
#define CL_FLEVEL_DCONF CL_FLEVEL |
fc8d26a1 |
#define CL_FLEVEL_SIGTOOL CL_FLEVEL |
a37a861e |
|
33068e09 |
extern uint8_t cli_debug_flag; |
3ca11170 |
extern uint8_t cli_always_gen_section_hash; |
a7ac5978 |
|
9c291186 |
/* |
4cd97da4 |
* CLI_ISCONTAINED(bb, bb_size, sb, sb_size) checks if sb (sub buffer) is contained
* within bb (buffer). |
9c291186 |
* |
4cd97da4 |
* bb and sb are pointers (or offsets) for the main buffer and the
* sub-buffer respectively, and bb_size and sb_size are their sizes |
9c291186 |
*
* The macro can be used to protect against wraps.
*/ |
4cd97da4 |
#define CLI_ISCONTAINED(bb, bb_size, sb, sb_size) \
( \
(size_t)(bb_size) > 0 && (size_t)(sb_size) > 0 && \
(size_t)(sb_size) <= (size_t)(bb_size) && \
(ptrdiff_t)(sb) >= (ptrdiff_t)(bb) && \
(ptrdiff_t)(sb) + (ptrdiff_t)(sb_size) <= (ptrdiff_t)(bb) + (ptrdiff_t)(bb_size) && \
(ptrdiff_t)(sb) + (ptrdiff_t)(sb_size) > (ptrdiff_t)(bb) && \ |
288057e9 |
(ptrdiff_t)(sb) < (ptrdiff_t)(bb) + (ptrdiff_t)(bb_size)) |
1f280d21 |
|
4cd97da4 |
/*
* CLI_ISCONTAINED2(bb, bb_size, sb, sb_size) checks if sb (sub buffer) is contained
* within bb (buffer).
*
* CLI_ISCONTAINED2 is the same as CLI_ISCONTAINED except that it allows for sub-
* buffers with sb_size == 0.
*/
#define CLI_ISCONTAINED2(bb, bb_size, sb, sb_size) \
( \
(size_t)(bb_size) > 0 && (size_t)(sb_size) >= 0 && \
(size_t)(sb_size) <= (size_t)(bb_size) && \
(ptrdiff_t)(sb) >= (ptrdiff_t)(bb) && \
(ptrdiff_t)(sb) + (ptrdiff_t)(sb_size) <= (ptrdiff_t)(bb) + (ptrdiff_t)(bb_size) && \
(ptrdiff_t)(sb) + (ptrdiff_t)(sb_size) >= (ptrdiff_t)(bb) && \ |
288057e9 |
(ptrdiff_t)(sb) < (ptrdiff_t)(bb) + (ptrdiff_t)(bb_size)) |
941c735c |
|
288057e9 |
#define CLI_MAX_ALLOCATION (182 * 1024 * 1024) |
1e9c4900 |
|
288057e9 |
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h> /* for NAME_MAX */ |
a087f040 |
#endif
|
06646acf |
/* Maximum filenames under various systems - njh */ |
288057e9 |
#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
#else
#define NAME_MAX 256
#endif
#endif |
06646acf |
#endif
|
7d34797b |
#if NAME_MAX < 256
#undef NAME_MAX
#define NAME_MAX 256
#endif
|
288057e9 |
typedef struct bitset_tag {
unsigned char *bitset;
unsigned long length; |
f4e34215 |
} bitset_t;
|
031fe00a |
typedef struct cli_ctx_container_tag {
cli_file_t type;
size_t size; |
167c0079 |
unsigned char flag; |
031fe00a |
} cli_ctx_container; |
167c0079 |
#define CONTAINER_FLAG_VALID 0x01 |
031fe00a |
|
3c91998b |
/* internal clamav context */ |
f4e34215 |
typedef struct cli_ctx_tag { |
01eebc13 |
char *target_filepath;
const char *sub_filepath; |
3c91998b |
const char **virname; |
1f1bf36b |
unsigned int num_viruses; |
3c91998b |
unsigned long int *scanned;
const struct cli_matcher *root;
const struct cl_engine *engine; |
bf45cebe |
unsigned long scansize; |
048a88e6 |
struct cl_scan_options *options; |
4ad62d4e |
unsigned int recursion; |
d91ab809 |
unsigned int scannedfiles; |
25380806 |
unsigned int found_possibly_unwanted; |
c6b9d863 |
unsigned int corrupted_input; |
b44fb658 |
unsigned int img_validate; |
031fe00a |
cli_ctx_container *containers; /* set container type after recurse */ |
b240ee01 |
unsigned char handlertype_hash[16]; |
bc93eda0 |
struct cli_dconf *dconf; |
49cc1e3c |
fmap_t **fmap; |
288057e9 |
bitset_t *hook_lsig_matches; |
aa7380df |
void *cb_ctx; |
288057e9 |
cli_events_t *perf; |
16b28d07 |
#ifdef HAVE__INTERNAL__SHA_COLLECT
int sha_collect;
#endif |
e56f0949 |
#ifdef HAVE_JSON
struct json_object *properties; |
4e683628 |
struct json_object *wrkproperty; |
e56f0949 |
#endif |
49b33289 |
struct timeval time_limit; |
312b7e53 |
int limit_exceeded; |
3c91998b |
} cli_ctx;
|
f2571e34 |
#define STATS_ANON_UUID "5b585e8f-3be5-11e3-bf0b-18037319526c" |
30bdcf4e |
#define STATS_MAX_SAMPLES 50 |
288057e9 |
#define STATS_MAX_MEM 1024 * 1024 |
f2571e34 |
typedef struct cli_flagged_sample {
char **virus_name;
char md5[16]; |
b3c40dc6 |
uint32_t size; /* A size of zero means size is unavailable (why would this ever happen?) */ |
f2571e34 |
uint32_t hits; |
3c29ca0b |
stats_section_t *sections; |
f2571e34 |
struct cli_flagged_sample *prev;
struct cli_flagged_sample *next;
} cli_flagged_sample_t;
typedef struct cli_clamav_intel {
char *hostid; |
dbc6d4b2 |
char *host_info; |
f2571e34 |
cli_flagged_sample_t *samples;
uint32_t nsamples;
uint32_t maxsamples;
uint32_t maxmem; |
4e1236c8 |
uint32_t timeout; |
f2571e34 |
time_t nextupdate;
struct cl_engine *engine;
#ifdef CL_THREAD_SAFE
pthread_mutex_t mutex;
#endif
} cli_intel_t; |
419e2be4 |
|
288057e9 |
typedef struct {
uint64_t v[2][4];
} icon_groupset; |
419e2be4 |
|
a8d621cf |
struct icomtr { |
419e2be4 |
unsigned int group[2]; |
a8d621cf |
unsigned int color_avg[3];
unsigned int color_x[3];
unsigned int color_y[3];
unsigned int gray_avg[3];
unsigned int gray_x[3];
unsigned int gray_y[3];
unsigned int bright_avg[3];
unsigned int bright_x[3];
unsigned int bright_y[3];
unsigned int dark_avg[3];
unsigned int dark_x[3];
unsigned int dark_y[3];
unsigned int edge_avg[3];
unsigned int edge_x[3];
unsigned int edge_y[3];
unsigned int noedge_avg[3];
unsigned int noedge_x[3];
unsigned int noedge_y[3];
unsigned int rsum;
unsigned int gsum;
unsigned int bsum;
unsigned int ccount;
char *name;
};
|
cca29953 |
struct icon_matcher {
char **group_names[2];
unsigned int group_counts[2];
struct icomtr *icons[3];
unsigned int icon_counts[3];
};
|
ace26bfe |
struct cli_dbinfo {
char *name; |
7b1f1aaf |
char *hash; |
ace26bfe |
size_t size;
struct cl_cvd *cvd;
struct cli_dbinfo *next;
};
|
038cb67a |
#define CLI_PWDB_COUNT 3
typedef enum {
CLI_PWDB_ANY = 0,
CLI_PWDB_ZIP = 1,
CLI_PWDB_RAR = 2
} cl_pwdb_t;
struct cli_pwdb { |
0a631ee9 |
char *name; |
7b1f1aaf |
char *passwd; |
ac0cbde8 |
uint16_t length; |
038cb67a |
struct cli_pwdb *next; |
ac0cbde8 |
};
|
724b2bf7 |
struct cl_engine {
uint32_t refcount; /* reference counter */
uint32_t sdb;
uint32_t dboptions;
uint32_t dbversion[2]; |
ab0d2f05 |
uint32_t ac_only;
uint32_t ac_mindepth;
uint32_t ac_maxdepth; |
33068e09 |
char *tmpdir;
uint32_t keeptmp; |
34e9acb0 |
uint64_t engine_options; |
724b2bf7 |
/* Limits */ |
b056e8e4 |
uint32_t maxscantime; /* Time limit (in milliseconds) */ |
288057e9 |
uint64_t maxscansize; /* during the scanning of archives this size |
b056e8e4 |
* will never be exceeded
*/ |
288057e9 |
uint64_t maxfilesize; /* compressed files will only be decompressed |
b056e8e4 |
* and scanned up to this size
*/ |
288057e9 |
uint32_t maxreclevel; /* maximum recursion level for archives */
uint32_t maxfiles; /* maximum number of files to be scanned |
b056e8e4 |
* within a single archive
*/ |
724b2bf7 |
/* This is for structured data detection. You can set the minimum |
22cb38ed |
* number of occurrences of an CC# or SSN before the system will |
724b2bf7 |
* generate a notification.
*/
uint32_t min_cc_count;
uint32_t min_ssn_count;
/* Roots table */
struct cli_matcher **root;
|
c802edd5 |
/* hash matcher for standard MD5 sigs */
struct cli_matcher *hm_hdb;
/* hash matcher for MD5 sigs for PE sections */
struct cli_matcher *hm_mdb; |
66c20d21 |
/* hash matcher for MD5 sigs for PE import tables */ |
832d44e7 |
struct cli_matcher *hm_imp; |
c802edd5 |
/* hash matcher for whitelist db */
struct cli_matcher *hm_fp;
|
55094a9c |
/* Container metadata */
struct cli_cdb *cdb; |
724b2bf7 |
/* Phishing .pdb and .wdb databases*/
struct regex_matcher *whitelist_matcher;
struct regex_matcher *domainlist_matcher;
struct phishcheck *phishcheck;
/* Dynamic configuration */
struct cli_dconf *dconf;
/* Filetype definitions */
struct cli_ftype *ftypes; |
1d1c4b15 |
struct cli_ftype *ptypes; |
724b2bf7 |
|
ac0cbde8 |
/* Container password storage */ |
038cb67a |
struct cli_pwdb **pwdbs; |
ac0cbde8 |
|
e8ab1083 |
/* Pre-loading test matcher
* Test for presence before using; cleared on engine compile.
*/
struct cli_matcher *test_root;
|
724b2bf7 |
/* Ignored signatures */ |
04133ff9 |
struct cli_matcher *ignored; |
724b2bf7 |
/* PUA categories (to be included or excluded) */
char *pua_cats;
|
a8d621cf |
/* Icon reference storage */ |
cca29953 |
struct icon_matcher *iconcheck; |
a8d621cf |
|
6223810b |
/* Negative cache storage */
struct CACHE *cache;
|
ace26bfe |
/* Database information from .info files */
struct cli_dbinfo *dbinfo;
|
724b2bf7 |
/* Used for memory pools */ |
47d40feb |
mpool_t *mempool; |
52dd3a6b |
|
8997495d |
/* crtmgr stuff */
crtmgr cmgr;
|
eb422a03 |
/* Callback(s) */ |
a217d9a7 |
clcb_pre_cache cb_pre_cache; |
eb422a03 |
clcb_pre_scan cb_pre_scan;
clcb_post_scan cb_post_scan; |
1f1bf36b |
clcb_virus_found cb_virus_found; |
eb422a03 |
clcb_sigload cb_sigload;
void *cb_sigload_ctx; |
769f37a6 |
clcb_hash cb_hash; |
e86311ab |
clcb_meta cb_meta; |
6606d050 |
clcb_file_props cb_file_props; |
eb422a03 |
|
52dd3a6b |
/* Used for bytecode */
struct cli_all_bc bcs; |
ab636570 |
unsigned *hooks[_BC_LAST_HOOK - _BC_START_HOOKS];
unsigned hooks_cnt[_BC_LAST_HOOK - _BC_START_HOOKS]; |
f4e34215 |
unsigned hook_lsig_ids; |
be43f951 |
enum bytecode_security bytecode_security; |
b63681a5 |
uint32_t bytecode_timeout; |
927d0548 |
enum bytecode_mode bytecode_mode; |
b2726a53 |
/* Engine max settings */ |
288057e9 |
uint64_t maxembeddedpe; /* max size to scan MSEXE for PE */
uint64_t maxhtmlnormalize; /* max size to normalize HTML */
uint64_t maxhtmlnotags; /* max size for scanning normalized HTML */ |
b2726a53 |
uint64_t maxscriptnormalize; /* max size to normalize scripts */ |
288057e9 |
uint64_t maxziptypercg; /* max size to re-do zip filetype */ |
f2571e34 |
/* Statistics/intelligence gathering */
void *stats_data;
clcb_stats_add_sample cb_stats_add_sample;
clcb_stats_remove_sample cb_stats_remove_sample;
clcb_stats_decrement_count cb_stats_decrement_count;
clcb_stats_submit cb_stats_submit;
clcb_stats_flush cb_stats_flush;
clcb_stats_get_num cb_stats_get_num;
clcb_stats_get_size cb_stats_get_size;
clcb_stats_get_hostid cb_stats_get_hostid; |
97fbb02b |
|
067bce5f |
/* Raw disk image max settings */ |
f30d3008 |
uint32_t maxpartitions; /* max number of partitions to scan in a disk image */ |
067bce5f |
/* Engine max settings */
uint32_t maxiconspe; /* max number of icons to scan for PE */ |
731c8e62 |
uint32_t maxrechwp3; /* max recursive calls for HWP3 parsing */ |
49b33289 |
|
9bc7c138 |
/* PCRE matching limitations */
uint64_t pcre_match_limit;
uint64_t pcre_recmatch_limit; |
37415732 |
uint64_t pcre_max_filesize; |
b6ad4322 |
|
baeb6253 |
#ifdef HAVE_YARA |
b6ad4322 |
/* YARA */ |
288057e9 |
struct _yara_global *yara_global; |
baeb6253 |
#endif |
724b2bf7 |
};
|
99f817e7 |
struct cl_settings {
/* don't store dboptions here; it needs to be provided to cl_load() and
* can be optionally obtained with cl_engine_get() or from the original
* settings stored by the application
*/
uint32_t ac_only;
uint32_t ac_mindepth;
uint32_t ac_maxdepth;
char *tmpdir;
uint32_t keeptmp; |
b056e8e4 |
uint32_t maxscantime; |
99f817e7 |
uint64_t maxscansize;
uint64_t maxfilesize;
uint32_t maxreclevel;
uint32_t maxfiles;
uint32_t min_cc_count;
uint32_t min_ssn_count; |
df6ce9ab |
enum bytecode_security bytecode_security;
uint32_t bytecode_timeout;
enum bytecode_mode bytecode_mode; |
99f817e7 |
char *pua_cats; |
34e9acb0 |
uint64_t engine_options; |
2e3e4acc |
/* callbacks */ |
a217d9a7 |
clcb_pre_cache cb_pre_cache; |
2e3e4acc |
clcb_pre_scan cb_pre_scan;
clcb_post_scan cb_post_scan; |
1f1bf36b |
clcb_virus_found cb_virus_found; |
2e3e4acc |
clcb_sigload cb_sigload;
void *cb_sigload_ctx;
clcb_msg cb_msg;
clcb_hash cb_hash; |
ad9eee77 |
clcb_meta cb_meta; |
6606d050 |
clcb_file_props cb_file_props; |
b2726a53 |
/* Engine max settings */ |
288057e9 |
uint64_t maxembeddedpe; /* max size to scan MSEXE for PE */
uint64_t maxhtmlnormalize; /* max size to normalize HTML */
uint64_t maxhtmlnotags; /* max size for scanning normalized HTML */ |
b2726a53 |
uint64_t maxscriptnormalize; /* max size to normalize scripts */ |
288057e9 |
uint64_t maxziptypercg; /* max size to re-do zip filetype */ |
a1094954 |
/* Statistics/intelligence gathering */
void *stats_data;
clcb_stats_add_sample cb_stats_add_sample;
clcb_stats_remove_sample cb_stats_remove_sample;
clcb_stats_decrement_count cb_stats_decrement_count;
clcb_stats_submit cb_stats_submit;
clcb_stats_flush cb_stats_flush;
clcb_stats_get_num cb_stats_get_num;
clcb_stats_get_size cb_stats_get_size;
clcb_stats_get_hostid cb_stats_get_hostid; |
97fbb02b |
|
067bce5f |
/* Raw disk image max settings */
uint32_t maxpartitions; /* max number of partitions to scan in a disk image */
/* Engine max settings */
uint32_t maxiconspe; /* max number of icons to scan for PE */ |
731c8e62 |
uint32_t maxrechwp3; /* max recursive calls for HWP3 parsing */ |
9bc7c138 |
/* PCRE matching limitations */
uint64_t pcre_match_limit;
uint64_t pcre_recmatch_limit; |
37415732 |
uint64_t pcre_max_filesize; |
99f817e7 |
};
|
01eebc13 |
extern cl_unrar_error_t (*cli_unrar_open)(const char *filename, void **hArchive, char **comment, uint32_t *comment_size, uint8_t debug_flag);
extern cl_unrar_error_t (*cli_unrar_peek_file_header)(void *hArchive, unrar_metadata_t *file_metadata); |
288057e9 |
extern cl_unrar_error_t (*cli_unrar_extract_file)(void *hArchive, const char *destPath, char *outputBuffer); |
01eebc13 |
extern cl_unrar_error_t (*cli_unrar_skip_file)(void *hArchive);
extern void (*cli_unrar_close)(void *hArchive);
|
f5a4018b |
extern int have_rar;
|
288057e9 |
#define SCAN_ALLMATCHES (ctx->options->general & CL_SCAN_GENERAL_ALLMATCHES)
#define SCAN_COLLECT_METADATA (ctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA)
#define SCAN_HEURISTICS (ctx->options->general & CL_SCAN_GENERAL_HEURISTICS)
#define SCAN_HEURISTIC_PRECEDENCE (ctx->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE)
#define SCAN_PARSE_ARCHIVE (ctx->options->parse & CL_SCAN_PARSE_ARCHIVE)
#define SCAN_PARSE_ELF (ctx->options->parse & CL_SCAN_PARSE_ELF)
#define SCAN_PARSE_PDF (ctx->options->parse & CL_SCAN_PARSE_PDF)
#define SCAN_PARSE_SWF (ctx->options->parse & CL_SCAN_PARSE_SWF)
#define SCAN_PARSE_HWP3 (ctx->options->parse & CL_SCAN_PARSE_HWP3)
#define SCAN_PARSE_XMLDOCS (ctx->options->parse & CL_SCAN_PARSE_XMLDOCS)
#define SCAN_PARSE_MAIL (ctx->options->parse & CL_SCAN_PARSE_MAIL)
#define SCAN_PARSE_OLE2 (ctx->options->parse & CL_SCAN_PARSE_OLE2)
#define SCAN_PARSE_HTML (ctx->options->parse & CL_SCAN_PARSE_HTML)
#define SCAN_PARSE_PE (ctx->options->parse & CL_SCAN_PARSE_PE)
#define SCAN_HEURISTIC_BROKEN (ctx->options->heuristic & CL_SCAN_HEURISTIC_BROKEN)
#define SCAN_HEURISTIC_EXCEEDS_MAX (ctx->options->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX)
#define SCAN_HEURISTIC_PHISHING_SSL_MISMATCH (ctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH)
#define SCAN_HEURISTIC_PHISHING_CLOAK (ctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_CLOAK)
#define SCAN_HEURISTIC_MACROS (ctx->options->heuristic & CL_SCAN_HEURISTIC_MACROS)
#define SCAN_HEURISTIC_ENCRYPTED_ARCHIVE (ctx->options->heuristic & CL_SCAN_HEURISTIC_ENCRYPTED_ARCHIVE)
#define SCAN_HEURISTIC_ENCRYPTED_DOC (ctx->options->heuristic & CL_SCAN_HEURISTIC_ENCRYPTED_DOC)
#define SCAN_HEURISTIC_PARTITION_INTXN (ctx->options->heuristic & CL_SCAN_HEURISTIC_PARTITION_INTXN)
#define SCAN_HEURISTIC_STRUCTURED (ctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED)
#define SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL (ctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL)
#define SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED (ctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED)
#define SCAN_MAIL_PARTIAL_MESSAGE (ctx->options->mail & CL_SCAN_MAIL_PARTIAL_MESSAGE)
#define SCAN_DEV_COLLECT_SHA (ctx->options->dev & CL_SCAN_DEV_COLLECT_SHA)
#define SCAN_DEV_COLLECT_PERF_INFO (ctx->options->dev & CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO) |
3c91998b |
|
1266e3e0 |
/* based on macros from A. Melnikoff */
#define cbswap16(v) (((v & 0xff) << 8) | (((v) >> 8) & 0xff)) |
288057e9 |
#define cbswap32(v) ((((v)&0x000000ff) << 24) | (((v)&0x0000ff00) << 8) | \
(((v)&0x00ff0000) >> 8) | (((v)&0xff000000) >> 24))
#define cbswap64(v) ((((v)&0x00000000000000ffULL) << 56) | \
(((v)&0x000000000000ff00ULL) << 40) | \
(((v)&0x0000000000ff0000ULL) << 24) | \
(((v)&0x00000000ff000000ULL) << 8) | \
(((v)&0x000000ff00000000ULL) >> 8) | \
(((v)&0x0000ff0000000000ULL) >> 24) | \
(((v)&0x00ff000000000000ULL) >> 40) | \
(((v)&0xff00000000000000ULL) >> 56))
#ifndef HAVE_ATTRIB_PACKED |
e3540e0a |
#define __attribute__(x)
#endif
#ifdef HAVE_PRAGMA_PACK
#pragma pack(1)
#endif
#ifdef HAVE_PRAGMA_PACK_HPPA
#pragma pack 1
#endif |
1266e3e0 |
|
72617ba2 |
union unaligned_64 { |
288057e9 |
uint64_t una_u64;
int64_t una_s64; |
72617ba2 |
} __attribute__((packed));
union unaligned_32 { |
288057e9 |
uint32_t una_u32;
int32_t una_s32; |
72617ba2 |
} __attribute__((packed));
union unaligned_16 { |
288057e9 |
uint16_t una_u16;
int16_t una_s16; |
72617ba2 |
} __attribute__((packed)); |
415543ef |
|
d068119a |
struct unaligned_ptr {
void *ptr;
} __attribute__((packed));
|
415543ef |
#ifdef HAVE_PRAGMA_PACK
#pragma pack()
#endif
#ifdef HAVE_PRAGMA_PACK_HPPA
#pragma pack
#endif |
e3540e0a |
#if WORDS_BIGENDIAN == 0 |
288057e9 |
/* Little endian */
#define le16_to_host(v) (v)
#define le32_to_host(v) (v)
#define le64_to_host(v) (v)
#define be16_to_host(v) cbswap16(v)
#define be32_to_host(v) cbswap32(v)
#define be64_to_host(v) cbswap64(v)
#define cli_readint64(buff) (((const union unaligned_64 *)(buff))->una_s64)
#define cli_readint32(buff) (((const union unaligned_32 *)(buff))->una_s32)
#define cli_readint16(buff) (((const union unaligned_16 *)(buff))->una_s16)
#define cli_writeint32(offset, value) (((union unaligned_32 *)(offset))->una_u32 = (uint32_t)(value)) |
75282b5c |
#else |
288057e9 |
/* Big endian */
#define le16_to_host(v) cbswap16(v)
#define le32_to_host(v) cbswap32(v)
#define le64_to_host(v) cbswap64(v)
#define be16_to_host(v) (v)
#define be32_to_host(v) (v)
#define be64_to_host(v) (v)
static inline int64_t cli_readint64(const void *buff)
{
int64_t ret;
ret = (int64_t)((const char *)buff)[0] & 0xff;
ret |= (int64_t)(((const char *)buff)[1] & 0xff) << 8;
ret |= (int64_t)(((const char *)buff)[2] & 0xff) << 16;
ret |= (int64_t)(((const char *)buff)[3] & 0xff) << 24;
ret |= (int64_t)(((const char *)buff)[4] & 0xff) << 32;
ret |= (int64_t)(((const char *)buff)[5] & 0xff) << 40;
ret |= (int64_t)(((const char *)buff)[6] & 0xff) << 48;
ret |= (int64_t)(((const char *)buff)[7] & 0xff) << 56;
return ret;
}
static inline int32_t cli_readint32(const void *buff)
{
int32_t ret;
ret = (int32_t)((const char *)buff)[0] & 0xff;
ret |= (int32_t)(((const char *)buff)[1] & 0xff) << 8;
ret |= (int32_t)(((const char *)buff)[2] & 0xff) << 16;
ret |= (int32_t)(((const char *)buff)[3] & 0xff) << 24;
return ret;
}
static inline int16_t cli_readint16(const void *buff)
{
int16_t ret;
ret = (int16_t)((const char *)buff)[0] & 0xff;
ret |= (int16_t)(((const char *)buff)[1] & 0xff) << 8;
return ret;
}
static inline void cli_writeint32(void *offset, uint32_t value)
{
((char *)offset)[0] = value & 0xff;
((char *)offset)[1] = (value & 0xff00) >> 8;
((char *)offset)[2] = (value & 0xff0000) >> 16;
((char *)offset)[3] = (value & 0xff000000) >> 24;
} |
75282b5c |
#endif
|
102cd430 |
cl_error_t cli_append_virus(cli_ctx *ctx, const char *virname); |
6ad45a29 |
const char *cli_get_last_virus(const cli_ctx *ctx); |
b81cbc26 |
const char *cli_get_last_virus_str(const cli_ctx *ctx); |
cbf5017a |
void cli_virus_found_cb(cli_ctx *ctx); |
6ad45a29 |
|
031fe00a |
void cli_set_container(cli_ctx *ctx, cli_file_t type, size_t size); |
167c0079 |
cli_file_t cli_get_container(cli_ctx *ctx, int index); |
031fe00a |
size_t cli_get_container_size(cli_ctx *ctx, int index); |
167c0079 |
cli_file_t cli_get_container_intermediate(cli_ctx *ctx, int index); |
031fe00a |
|
75282b5c |
/* used by: spin, yc (C) aCaB */ |
288057e9 |
#define __SHIFTBITS(a) (sizeof(a) << 3)
#define __SHIFTMASK(a) (__SHIFTBITS(a) - 1)
#define CLI_ROL(a, b) a = (a << ((b)&__SHIFTMASK(a))) | (a >> ((__SHIFTBITS(a) - (b)) & __SHIFTMASK(a)))
#define CLI_ROR(a, b) a = (a >> ((b)&__SHIFTMASK(a))) | (a << ((__SHIFTBITS(a) - (b)) & __SHIFTMASK(a))) |
75282b5c |
|
35eb6354 |
/* Implementation independent sign-extended signed right shift */
#ifdef HAVE_SAR |
288057e9 |
#define CLI_SRS(n, s) ((n) >> (s)) |
35eb6354 |
#else |
288057e9 |
#define CLI_SRS(n, s) ((((n) >> (s)) ^ (1 << (sizeof(n) * 8 - 1 - s))) - (1 << (sizeof(n) * 8 - 1 - s))) |
35eb6354 |
#endif |
288057e9 |
#define CLI_SAR(n, s) n = CLI_SRS(n, s) |
35eb6354 |
|
3c30b19b |
#ifdef __GNUC__
void cli_warnmsg(const char *str, ...) __attribute__((format(printf, 1, 2)));
#else |
e3aaff8e |
void cli_warnmsg(const char *str, ...); |
3c30b19b |
#endif
#ifdef __GNUC__
void cli_errmsg(const char *str, ...) __attribute__((format(printf, 1, 2)));
#else |
e3aaff8e |
void cli_errmsg(const char *str, ...); |
3c30b19b |
#endif
|
94de6a9a |
#ifdef __GNUC__ |
288057e9 |
void cli_infomsg(const cli_ctx *ctx, const char *fmt, ...) __attribute__((format(printf, 2, 3))); |
94de6a9a |
#else |
288057e9 |
void cli_infomsg(const cli_ctx *ctx, const char *fmt, ...); |
94de6a9a |
#endif
|
288057e9 |
void cli_logg_setup(const cli_ctx *ctx); |
0d79b7dc |
void cli_logg_unsetup(void); |
94de6a9a |
|
7be8d871 |
/* tell compiler about branches that are very rarely taken,
* such as debug paths, and error paths */
#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
#define UNLIKELY(cond) __builtin_expect(!!(cond), 0) |
65c740d7 |
#define LIKELY(cond) __builtin_expect(!!(cond), 1) |
7be8d871 |
#else
#define UNLIKELY(cond) (cond) |
65c740d7 |
#define LIKELY(cond) (cond) |
7be8d871 |
#endif
|
cfec3d90 |
#ifdef __GNUC__
#define always_inline inline __attribute__((always_inline)) |
9cbece5c |
#define never_inline __attribute__((noinline)) |
cfec3d90 |
#else |
46a63329 |
#define never_inline |
cfec3d90 |
#define always_inline inline
#endif
|
288057e9 |
#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) |
40103a30 |
#define __hot__ __attribute__((hot)) |
e0ac80ab |
#else |
40103a30 |
#define __hot__ |
e0ac80ab |
#endif
|
aeebf2ea |
#define cli_dbgmsg (!UNLIKELY(cli_debug_flag)) ? (void)0 : cli_dbgmsg_internal |
7be8d871 |
|
3c30b19b |
#ifdef __GNUC__ |
7be8d871 |
void cli_dbgmsg_internal(const char *str, ...) __attribute__((format(printf, 1, 2))); |
3c30b19b |
#else |
7be8d871 |
void cli_dbgmsg_internal(const char *str, ...); |
3c30b19b |
#endif
|
46026ca7 |
#ifdef HAVE_CLI_GETPAGESIZE
#undef HAVE_CLI_GETPAGESIZE
#endif
|
b0fc218f |
#ifdef _WIN32 |
288057e9 |
static inline int cli_getpagesize(void)
{ |
8618abc1 |
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwPageSize;
} |
b0fc218f |
#else /* ! _WIN32 */ |
86d59b24 |
#if HAVE_SYSCONF_SC_PAGESIZE |
288057e9 |
static inline int cli_getpagesize(void)
{
return sysconf(_SC_PAGESIZE);
} |
86d59b24 |
#define HAVE_CLI_GETPAGESIZE 1
#else
#if HAVE_GETPAGESIZE |
288057e9 |
static inline int cli_getpagesize(void)
{
return getpagesize();
} |
86d59b24 |
#define HAVE_CLI_GETPAGESIZE 1 |
8618abc1 |
#endif /* HAVE_GETPAGESIZE */
#endif /* HAVE_SYSCONF_SC_PAGESIZE */ |
b0fc218f |
#endif /* _WIN32 */ |
86d59b24 |
|
e3aaff8e |
void *cli_malloc(size_t nmemb);
void *cli_calloc(size_t nmemb, size_t size); |
8139fd99 |
void *cli_realloc(void *ptr, size_t size); |
423d6b6a |
void *cli_realloc2(void *ptr, size_t size); |
786b43b6 |
char *cli_strdup(const char *s); |
e3aaff8e |
int cli_rmdirs(const char *dirname); |
d5fde2eb |
char *cli_hashstream(FILE *fs, unsigned char *digcpy, int type);
char *cli_hashfile(const char *filename, int type); |
997a0e0b |
int cli_unlink(const char *pathname); |
6c03dc5d |
size_t cli_readn(int fd, void *buff, size_t count);
size_t cli_writen(int fd, const void *buff, size_t count); |
081f6473 |
const char *cli_gettmpdir(void); |
01eebc13 |
/** |
f8b3d2e5 |
* @brief Sanitize a relative path, so it cannot have a negative depth.
*
* Caller is responsible for freeing the filename.
*
* @return char* filename or NULL.
*/
char *cli_sanitize_filepath(const char *filepath, size_t filepath_len);
/** |
01eebc13 |
* @brief Generate tempfile filename (no path) with a random MD5 hash. |
f8b3d2e5 |
* |
01eebc13 |
* Caller is responsible for freeing the filename. |
f8b3d2e5 |
* |
01eebc13 |
* @return char* filename or NULL.
*/
char *cli_genfname(const char *prefix);
/**
* @brief Generate a full tempfile filepath with a random MD5 hash and prefix the name, if provided. |
f8b3d2e5 |
* |
01eebc13 |
* Caller is responsible for freeing the filename. |
f8b3d2e5 |
* |
01eebc13 |
* @param dir Alternative temp directory. (optional)
* @return char* filename or NULL.
*/ |
288057e9 |
char *cli_gentemp_with_prefix(const char *dir, const char *prefix); |
01eebc13 |
/**
* @brief Generate a full tempfile filepath with a random MD5 hash. |
f8b3d2e5 |
* |
01eebc13 |
* Caller is responsible for freeing the filename. |
f8b3d2e5 |
* |
01eebc13 |
* @param dir Alternative temp directory. (optional)
* @return char* filename or NULL.
*/ |
8000d078 |
char *cli_gentemp(const char *dir); |
01eebc13 |
/**
* @brief Create a temp filename, create the file, open it, and pass back the filepath and open file descriptor.
*
* @param dir Alternative temp directory (optional).
* @param[out] name Allocated filepath, must be freed by caller.
* @param[out] fd File descriptor of open temp file. |
f8b3d2e5 |
* @return cl_error_t CL_SUCCESS, CL_ECREAT, or CL_EMEM. |
01eebc13 |
*/
cl_error_t cli_gentempfd(const char *dir, char **name, int *fd);
/**
* @brief Create a temp filename, create the file, open it, and pass back the filepath and open file descriptor. |
f8b3d2e5 |
* |
01eebc13 |
* @param dir Alternative temp directory (optional).
* @param prefix (Optional) Prefix for new file tempfile.
* @param[out] name Allocated filepath, must be freed by caller.
* @param[out] fd File descriptor of open temp file. |
f8b3d2e5 |
* @return cl_error_t CL_SUCCESS, CL_ECREAT, or CL_EMEM. |
01eebc13 |
*/ |
288057e9 |
cl_error_t cli_gentempfd_with_prefix(const char *dir, char *prefix, char **name, int *fd); |
01eebc13 |
|
8000d078 |
unsigned int cli_rndnum(unsigned int max); |
b067a7dd |
int cli_filecopy(const char *src, const char *dest); |
079229d6 |
bitset_t *cli_bitset_init(void); |
8a9c2d19 |
void cli_bitset_free(bitset_t *bs);
int cli_bitset_set(bitset_t *bs, unsigned long bit_offset);
int cli_bitset_test(bitset_t *bs, unsigned long bit_offset); |
288057e9 |
const char *cli_ctime(const time_t *timep, char *buf, const size_t bufsize); |
312b7e53 |
void cli_check_blockmax(cli_ctx *, int); |
b056e8e4 |
cl_error_t cli_checklimits(const char *, cli_ctx *, unsigned long, unsigned long, unsigned long);
cl_error_t cli_updatelimits(cli_ctx *, unsigned long); |
d91ab809 |
unsigned long cli_getsizelimit(cli_ctx *, unsigned long); |
92f585fb |
int cli_matchregex(const char *str, const char *regex); |
424d41d3 |
void cli_qsort(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *)); |
288057e9 |
void cli_qsort_r(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *, const void *), void *arg); |
b056e8e4 |
cl_error_t cli_checktimelimit(cli_ctx *ctx);
cl_error_t cli_append_possibly_unwanted(cli_ctx *ctx, const char *virname); |
e5e4a554 |
/* symlink behaviour */
#define CLI_FTW_FOLLOW_FILE_SYMLINK 0x01 |
288057e9 |
#define CLI_FTW_FOLLOW_DIR_SYMLINK 0x02 |
e5e4a554 |
/* if the callback needs the stat */ |
288057e9 |
#define CLI_FTW_NEED_STAT 0x04 |
e5e4a554 |
|
a1598d7c |
/* remove leading/trailing slashes */ |
288057e9 |
#define CLI_FTW_TRIM_SLASHES 0x08 |
a1598d7c |
#define CLI_FTW_STD (CLI_FTW_NEED_STAT | CLI_FTW_TRIM_SLASHES) |
e5e4a554 |
enum cli_ftw_reason {
visit_file,
visit_directory_toplev, /* this is a directory at toplevel of recursion */ |
288057e9 |
error_mem, /* recommended to return CL_EMEM */ |
e5e4a554 |
/* recommended to return CL_SUCCESS below */
error_stat,
warning_skipped_link,
warning_skipped_special,
warning_skipped_dir
};
/* wrap void*, so that we don't mix it with some other pointer */
struct cli_ftw_cbdata {
void *data;
};
|
f8b3d2e5 |
/* |
e5e4a554 |
* return CL_BREAK to break out without an error, CL_SUCCESS to continue,
* or any CL_E* to break out due to error.
* The callback is responsible for freeing filename when it is done using it. |
f8b3d2e5 |
* Note that callback decides if directory traversal should continue |
e5e4a554 |
* after an error, we call the callback with reason == error,
* and if it returns CL_BREAK we break.
*/ |
a2a004df |
typedef int (*cli_ftw_cb)(STATBUF *stat_buf, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data); |
e5e4a554 |
/* |
51bbedb1 |
* returns 1 if the path should be skipped and 0 otherwise
* uses callback data
*/
typedef int (*cli_ftw_pathchk)(const char *path, struct cli_ftw_cbdata *data);
/* |
f8b3d2e5 |
* returns |
e5e4a554 |
* CL_SUCCESS if it traversed all files and subdirs
* CL_BREAK if traversal has stopped at some point
* CL_E* if error encountered during traversal and we had to break out
* This is regardless of virus found/not, that is the callback's job to store.
* Note that the callback may dispatch async the scan, so that when cli_ftw
* returns we don't know the infected/notinfected status of the directory yet!
* Due to this if the callback scans synchronously it should store the infected
* status in its cbdata.
* This works for both files and directories. It stats the path to determine
* which one it is.
* If it is a file, it simply calls the callback once, otherwise recurses.
*/ |
51bbedb1 |
int cli_ftw(char *base, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk); |
e5e4a554 |
|
288057e9 |
const char *cli_strerror(int errnum, char *buf, size_t len); |
01eebc13 |
/**
* @brief Attempt to get a filename from an open file descriptor. |
f8b3d2e5 |
* |
01eebc13 |
* Caller is responsible for free'ing the filename.
* Should work on Linux, macOS, Windows. |
f8b3d2e5 |
* |
01eebc13 |
* @param desc File descriptor
* @param[out] filepath Will be set to file path if found, or NULL.
* @return cl_error_t CL_SUCCESS if found, else an error code.
*/ |
288057e9 |
cl_error_t cli_get_filepath_from_filedesc(int desc, char **filepath); |
01eebc13 |
|
e3aaff8e |
#endif |