libclamav/others.h
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.
  */
 
eeea7843
 #define CL_FLEVEL 110
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 */
288057e9
     uint64_t maxscansize; /* during the scanning of archives this size
724b2bf7
 				     * will never be exceeded
 				     */
288057e9
     uint64_t maxfilesize; /* compressed files will only be decompressed
724b2bf7
 				     * 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
724b2bf7
 				     * within a single archive
 				     */
     /* 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
 
     /* millisecond time limit for preclassification scanning */
     uint32_t time_limit;
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;
     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);
328a3325
 int cli_mapscan(fmap_t *map, off_t offset, size_t size, cli_ctx *ctx, cli_file_t type);
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);
b80ae277
 int cli_checklimits(const char *, cli_ctx *, unsigned long, unsigned long, unsigned long);
 int 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);
49b33289
 int cli_checktimelimit(cli_ctx *ctx);
288057e9
 int 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