1 /*
2  *  Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3  *  Copyright (C) 2007-2013 Sourcefire, Inc.
4  *
5  *  Authors: Tomasz Kojm
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA 02110-1301, USA.
20  */
21 
22 #include "matcher.h"
23 
24 #ifndef __OTHERS_H_LC
25 #define __OTHERS_H_LC
26 
27 #if HAVE_CONFIG_H
28 #include "clamav-config.h"
29 #endif
30 
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 
35 #if HAVE_PTHREAD_H
36 #include <pthread.h>
37 #endif
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <stdbool.h>
42 
43 #ifdef HAVE_JSON
44 #include <json.h>
45 #endif
46 
47 #include "clamav.h"
48 #include "dconf.h"
49 #include "filetypes.h"
50 #include "fmap.h"
51 #include "regex/regex.h"
52 #include "bytecode.h"
53 #include "bytecode_api.h"
54 #include "events.h"
55 #include "crtmgr.h"
56 
57 #include "unrar_iface.h"
58 
59 #ifdef HAVE_YARA
60 #include "yara_clam.h"
61 #endif
62 
63 #if HAVE_LIBXML2
64 #define CLAMAV_MIN_XMLREADER_FLAGS (XML_PARSE_NOERROR | XML_PARSE_NONET)
65 #endif
66 
67 /*
68  * CL_FLEVEL is the signature f-level specific to the current code and
69  *	     should never be modified
70  * CL_FLEVEL_DCONF is used in the dconf module and can be bumped by
71  * distribution packagers provided they fix *all* security issues found
72  * in the old versions of ClamAV. Updating CL_FLEVEL_DCONF will result
73  * in re-enabling affected modules.
74  */
75 
76 #define CL_FLEVEL 142
77 #define CL_FLEVEL_DCONF CL_FLEVEL
78 #define CL_FLEVEL_SIGTOOL CL_FLEVEL
79 
80 extern uint8_t cli_debug_flag;
81 extern uint8_t cli_always_gen_section_hash;
82 
83 /*
84  * CLI_ISCONTAINED(bb, bb_size, sb, sb_size) checks if sb (small buffer) is
85  * within bb (big buffer).
86  *
87  * bb and sb are pointers (or offsets) for the main buffer and the
88  * sub-buffer respectively, and bb_size and sb_size are their sizes
89  *
90  * The macro can be used to protect against wraps.
91  */
92 #define CLI_ISCONTAINED(bb, bb_size, sb, sb_size)                            \
93     ((size_t)(bb_size) > 0 && (size_t)(sb_size) > 0 &&                       \
94      (size_t)(sb_size) <= (size_t)(bb_size) &&                               \
95      (size_t)(sb) >= (size_t)(bb) &&                                         \
96      (size_t)(sb) + (size_t)(sb_size) <= (size_t)(bb) + (size_t)(bb_size) && \
97      (size_t)(sb) + (size_t)(sb_size) > (size_t)(bb) &&                      \
98      (size_t)(sb) < (size_t)(bb) + (size_t)(bb_size))
99 
100 /*
101  * CLI_ISCONTAINED_0_TO(bb_size, sb, sb_size) checks if sb (small offset) is
102  * within bb (big offset) where the big offset always starts at 0.
103  *
104  * bb and sb are offsets for the main buffer and the
105  * sub-buffer respectively, and bb_size and sb_size are their sizes
106  *
107  * The macro can be used to protect against wraps.
108  *
109  * CLI_ISCONTAINED_0_TO is the same as CLI_ISCONTAINED except that `bb` is gone
110  * and assumed ot be zero.
111  */
112 #define CLI_ISCONTAINED_0_TO(bb_size, sb, sb_size)            \
113     ((size_t)(bb_size) > 0 && (size_t)(sb_size) > 0 &&        \
114      (size_t)(sb_size) <= (size_t)(bb_size) &&                \
115      (size_t)(sb) + (size_t)(sb_size) <= (size_t)(bb_size) && \
116      (size_t)(sb) < (size_t)(bb_size))
117 
118 /*
119  * CLI_ISCONTAINED_2(bb, bb_size, sb, sb_size) checks if sb (small buffer) is
120  * within bb (big buffer).
121  *
122  * CLI_ISCONTAINED_2 is the same as CLI_ISCONTAINED except that it allows for
123  * small-buffers with sb_size == 0.
124  */
125 #define CLI_ISCONTAINED_2(bb, bb_size, sb, sb_size)                          \
126     ((size_t)(bb_size) > 0 &&                                                \
127      (size_t)(sb_size) <= (size_t)(bb_size) &&                               \
128      (size_t)(sb) >= (size_t)(bb) &&                                         \
129      (size_t)(sb) + (size_t)(sb_size) <= (size_t)(bb) + (size_t)(bb_size) && \
130      (size_t)(sb) + (size_t)(sb_size) >= (size_t)(bb) &&                     \
131      (size_t)(sb) <= (size_t)(bb) + (size_t)(bb_size))
132 
133 #define CLI_MAX_ALLOCATION (182 * 1024 * 1024)
134 
135 #ifdef HAVE_SYS_PARAM_H
136 #include <sys/param.h> /* for NAME_MAX */
137 #endif
138 
139 /* Maximum filenames under various systems - njh */
140 #ifndef NAME_MAX  /* e.g. Linux */
141 #ifdef MAXNAMELEN /* e.g. Solaris */
142 #define NAME_MAX MAXNAMELEN
143 #else
144 #ifdef FILENAME_MAX /* e.g. SCO */
145 #define NAME_MAX FILENAME_MAX
146 #else
147 #define NAME_MAX 256
148 #endif
149 #endif
150 #endif
151 
152 #if NAME_MAX < 256
153 #undef NAME_MAX
154 #define NAME_MAX 256
155 #endif
156 
157 typedef struct bitset_tag {
158     unsigned char *bitset;
159     unsigned long length;
160 } bitset_t;
161 
162 typedef struct recursion_level_tag {
163     cli_file_t type;
164     size_t size;
165     cl_fmap_t *fmap;                      /* The fmap for this layer. This used to be in an array in the ctx. */
166     uint32_t recursion_level_buffer;      /* Which buffer layer in scan recursion. */
167     uint32_t recursion_level_buffer_fmap; /* Which fmap layer in this buffer. */
168     bool is_normalized_layer;             /* Indicates that the layer should be skipped when checking container and intermediate types. */
169 } recursion_level_t;
170 // #define CONTAINER_FLAG_VALID 0x01
171 
172 /* internal clamav context */
173 typedef struct cli_ctx_tag {
174     char *target_filepath;    /**< (optional) The filepath of the original scan target. */
175     const char *sub_filepath; /**< (optional) The filepath of the current file being parsed. May be a temp file. */
176     char *sub_tmpdir;         /**< The directory to store tmp files at this recursion depth. */
177     const char **virname;
178     unsigned int num_viruses;
179     unsigned long int *scanned;
180     const struct cli_matcher *root;
181     const struct cl_engine *engine;
182     uint64_t scansize;
183     struct cl_scan_options *options;
184     unsigned int scannedfiles;
185     unsigned int found_possibly_unwanted;
186     unsigned int corrupted_input;
187     unsigned int img_validate;
188     recursion_level_t *recursion_stack; /* Array of recursion levels used as a stack. */
189     uint32_t recursion_stack_size;      /* stack size must == engine->max_recursion_level */
190     uint32_t recursion_level;           /* Index into recursion_stack; current fmap recursion level from start of scan. */
191     fmap_t *fmap;                       /* Pointer to current fmap in recursion_stack, varies with recursion depth. For convenience. */
192     bool next_layer_is_normalized;      /* Indicate that the next fmap pushed to the stack is normalized and should be ignored when checking container/intermediate types */
193     unsigned char handlertype_hash[16];
194     struct cli_dconf *dconf;
195     bitset_t *hook_lsig_matches;
196     void *cb_ctx;
197     cli_events_t *perf;
198 #ifdef HAVE__INTERNAL__SHA_COLLECT
199     int sha_collect;
200 #endif
201 #ifdef HAVE_JSON
202     struct json_object *properties;
203     struct json_object *wrkproperty;
204 #endif
205     struct timeval time_limit;
206     bool limit_exceeded; /* To guard against alerting on limits exceeded more than once, or storing that in the JSON metadata more than once. */
207     bool abort_scan;     /* So we can guarantee a scan is aborted, even if CL_ETIMEOUT/etc. status is lost in the scan recursion stack. */
208 } cli_ctx;
209 
210 #define STATS_ANON_UUID "5b585e8f-3be5-11e3-bf0b-18037319526c"
211 #define STATS_MAX_SAMPLES 50
212 #define STATS_MAX_MEM 1024 * 1024
213 
214 typedef struct cli_flagged_sample {
215     char **virus_name;
216     char md5[16];
217     uint32_t size; /* A size of zero means size is unavailable (why would this ever happen?) */
218     uint32_t hits;
219     stats_section_t *sections;
220 
221     struct cli_flagged_sample *prev;
222     struct cli_flagged_sample *next;
223 } cli_flagged_sample_t;
224 
225 typedef struct cli_clamav_intel {
226     char *hostid;
227     char *host_info;
228     cli_flagged_sample_t *samples;
229     uint32_t nsamples;
230     uint32_t maxsamples;
231     uint32_t maxmem;
232     uint32_t timeout;
233     time_t nextupdate;
234     struct cl_engine *engine;
235 #ifdef CL_THREAD_SAFE
236     pthread_mutex_t mutex;
237 #endif
238 } cli_intel_t;
239 
240 typedef struct {
241     uint64_t v[2][4];
242 } icon_groupset;
243 
244 struct icomtr {
245     unsigned int group[2];
246     unsigned int color_avg[3];
247     unsigned int color_x[3];
248     unsigned int color_y[3];
249     unsigned int gray_avg[3];
250     unsigned int gray_x[3];
251     unsigned int gray_y[3];
252     unsigned int bright_avg[3];
253     unsigned int bright_x[3];
254     unsigned int bright_y[3];
255     unsigned int dark_avg[3];
256     unsigned int dark_x[3];
257     unsigned int dark_y[3];
258     unsigned int edge_avg[3];
259     unsigned int edge_x[3];
260     unsigned int edge_y[3];
261     unsigned int noedge_avg[3];
262     unsigned int noedge_x[3];
263     unsigned int noedge_y[3];
264     unsigned int rsum;
265     unsigned int gsum;
266     unsigned int bsum;
267     unsigned int ccount;
268     char *name;
269 };
270 
271 struct icon_matcher {
272     char **group_names[2];
273     unsigned int group_counts[2];
274     struct icomtr *icons[3];
275     unsigned int icon_counts[3];
276 };
277 
278 struct cli_dbinfo {
279     char *name;
280     char *hash;
281     size_t size;
282     struct cl_cvd *cvd;
283     struct cli_dbinfo *next;
284 };
285 
286 #define CLI_PWDB_COUNT 3
287 typedef enum {
288     CLI_PWDB_ANY = 0,
289     CLI_PWDB_ZIP = 1,
290     CLI_PWDB_RAR = 2
291 } cl_pwdb_t;
292 
293 struct cli_pwdb {
294     char *name;
295     char *passwd;
296     uint16_t length;
297     struct cli_pwdb *next;
298 };
299 
300 struct cl_engine {
301     uint32_t refcount; /* reference counter */
302     uint32_t sdb;
303     uint32_t dboptions;
304     uint32_t dbversion[2];
305     uint32_t ac_only;
306     uint32_t ac_mindepth;
307     uint32_t ac_maxdepth;
308     char *tmpdir;
309     uint32_t keeptmp;
310     uint64_t engine_options;
311 
312     /* Limits */
313     uint32_t maxscantime;         /* Time limit (in milliseconds) */
314     uint64_t maxscansize;         /* during the scanning of archives this size
315 				           * will never be exceeded
316 				           */
317     uint64_t maxfilesize;         /* compressed files will only be decompressed
318 				           * and scanned up to this size
319 				           */
320     uint32_t max_recursion_level; /* maximum recursion level for archives */
321     uint32_t maxfiles;            /* maximum number of files to be scanned
322 				           * within a single archive
323 				           */
324     /* This is for structured data detection.  You can set the minimum
325      * number of occurrences of an CC# or SSN before the system will
326      * generate a notification.
327      */
328     uint32_t min_cc_count;
329     uint32_t min_ssn_count;
330 
331     /* Roots table */
332     struct cli_matcher **root;
333 
334     /* hash matcher for standard MD5 sigs */
335     struct cli_matcher *hm_hdb;
336     /* hash matcher for MD5 sigs for PE sections */
337     struct cli_matcher *hm_mdb;
338     /* hash matcher for MD5 sigs for PE import tables */
339     struct cli_matcher *hm_imp;
340     /* hash matcher for allow list db */
341     struct cli_matcher *hm_fp;
342 
343     /* Container metadata */
344     struct cli_cdb *cdb;
345 
346     /* Phishing .pdb and .wdb databases*/
347     struct regex_matcher *allow_list_matcher;
348     struct regex_matcher *domain_list_matcher;
349     struct phishcheck *phishcheck;
350 
351     /* Dynamic configuration */
352     struct cli_dconf *dconf;
353 
354     /* Filetype definitions */
355     struct cli_ftype *ftypes;
356     struct cli_ftype *ptypes;
357 
358     /* Container password storage */
359     struct cli_pwdb **pwdbs;
360 
361     /* Pre-loading test matcher
362      * Test for presence before using; cleared on engine compile.
363      */
364     struct cli_matcher *test_root;
365 
366     /* Ignored signatures */
367     struct cli_matcher *ignored;
368 
369     /* PUA categories (to be included or excluded) */
370     char *pua_cats;
371 
372     /* Icon reference storage */
373     struct icon_matcher *iconcheck;
374 
375     /* Negative cache storage */
376     struct CACHE *cache;
377 
378     /* Database information from .info files */
379     struct cli_dbinfo *dbinfo;
380 
381     /* Signature counting, for progress callbacks */
382     size_t num_total_signatures;
383 
384     /* Used for memory pools */
385     mpool_t *mempool;
386 
387     /* crtmgr stuff */
388     crtmgr cmgr;
389 
390     /* Callback(s) */
391     clcb_pre_cache cb_pre_cache;
392     clcb_pre_scan cb_pre_scan;
393     clcb_post_scan cb_post_scan;
394     clcb_virus_found cb_virus_found;
395     clcb_sigload cb_sigload;
396     void *cb_sigload_ctx;
397     clcb_hash cb_hash;
398     clcb_meta cb_meta;
399     clcb_file_props cb_file_props;
400     clcb_progress cb_sigload_progress;
401     void *cb_sigload_progress_ctx;
402     clcb_progress cb_engine_compile_progress;
403     void *cb_engine_compile_progress_ctx;
404     clcb_progress cb_engine_free_progress;
405     void *cb_engine_free_progress_ctx;
406 
407     /* Used for bytecode */
408     struct cli_all_bc bcs;
409     unsigned *hooks[_BC_LAST_HOOK - _BC_START_HOOKS];
410     unsigned hooks_cnt[_BC_LAST_HOOK - _BC_START_HOOKS];
411     unsigned hook_lsig_ids;
412     enum bytecode_security bytecode_security;
413     uint32_t bytecode_timeout;
414     enum bytecode_mode bytecode_mode;
415 
416     /* Engine max settings */
417     uint64_t maxembeddedpe;      /* max size to scan MSEXE for PE */
418     uint64_t maxhtmlnormalize;   /* max size to normalize HTML */
419     uint64_t maxhtmlnotags;      /* max size for scanning normalized HTML */
420     uint64_t maxscriptnormalize; /* max size to normalize scripts */
421     uint64_t maxziptypercg;      /* max size to re-do zip filetype */
422 
423     /* Statistics/intelligence gathering */
424     void *stats_data;
425     clcb_stats_add_sample cb_stats_add_sample;
426     clcb_stats_remove_sample cb_stats_remove_sample;
427     clcb_stats_decrement_count cb_stats_decrement_count;
428     clcb_stats_submit cb_stats_submit;
429     clcb_stats_flush cb_stats_flush;
430     clcb_stats_get_num cb_stats_get_num;
431     clcb_stats_get_size cb_stats_get_size;
432     clcb_stats_get_hostid cb_stats_get_hostid;
433 
434     /* Raw disk image max settings */
435     uint32_t maxpartitions; /* max number of partitions to scan in a disk image */
436 
437     /* Engine max settings */
438     uint32_t maxiconspe; /* max number of icons to scan for PE */
439     uint32_t maxrechwp3; /* max recursive calls for HWP3 parsing */
440 
441     /* PCRE matching limitations */
442     uint64_t pcre_match_limit;
443     uint64_t pcre_recmatch_limit;
444     uint64_t pcre_max_filesize;
445 
446 #ifdef HAVE_YARA
447     /* YARA */
448     struct _yara_global *yara_global;
449 #endif
450 };
451 
452 struct cl_settings {
453     /* don't store dboptions here; it needs to be provided to cl_load() and
454      * can be optionally obtained with cl_engine_get() or from the original
455      * settings stored by the application
456      */
457     uint32_t ac_only;
458     uint32_t ac_mindepth;
459     uint32_t ac_maxdepth;
460     char *tmpdir;
461     uint32_t keeptmp;
462     uint32_t maxscantime;
463     uint64_t maxscansize;
464     uint64_t maxfilesize;
465     uint32_t max_recursion_level;
466     uint32_t maxfiles;
467     uint32_t min_cc_count;
468     uint32_t min_ssn_count;
469     enum bytecode_security bytecode_security;
470     uint32_t bytecode_timeout;
471     enum bytecode_mode bytecode_mode;
472     char *pua_cats;
473     uint64_t engine_options;
474 
475     /* callbacks */
476     clcb_pre_cache cb_pre_cache;
477     clcb_pre_scan cb_pre_scan;
478     clcb_post_scan cb_post_scan;
479     clcb_virus_found cb_virus_found;
480     clcb_sigload cb_sigload;
481     void *cb_sigload_ctx;
482     clcb_msg cb_msg;
483     clcb_hash cb_hash;
484     clcb_meta cb_meta;
485     clcb_file_props cb_file_props;
486     clcb_progress cb_sigload_progress;
487     void *cb_sigload_progress_ctx;
488     clcb_progress cb_engine_compile_progress;
489     void *cb_engine_compile_progress_ctx;
490     clcb_progress cb_engine_free_progress;
491     void *cb_engine_free_progress_ctx;
492 
493     /* Engine max settings */
494     uint64_t maxembeddedpe;      /* max size to scan MSEXE for PE */
495     uint64_t maxhtmlnormalize;   /* max size to normalize HTML */
496     uint64_t maxhtmlnotags;      /* max size for scanning normalized HTML */
497     uint64_t maxscriptnormalize; /* max size to normalize scripts */
498     uint64_t maxziptypercg;      /* max size to re-do zip filetype */
499 
500     /* Statistics/intelligence gathering */
501     void *stats_data;
502     clcb_stats_add_sample cb_stats_add_sample;
503     clcb_stats_remove_sample cb_stats_remove_sample;
504     clcb_stats_decrement_count cb_stats_decrement_count;
505     clcb_stats_submit cb_stats_submit;
506     clcb_stats_flush cb_stats_flush;
507     clcb_stats_get_num cb_stats_get_num;
508     clcb_stats_get_size cb_stats_get_size;
509     clcb_stats_get_hostid cb_stats_get_hostid;
510 
511     /* Raw disk image max settings */
512     uint32_t maxpartitions; /* max number of partitions to scan in a disk image */
513 
514     /* Engine max settings */
515     uint32_t maxiconspe; /* max number of icons to scan for PE */
516     uint32_t maxrechwp3; /* max recursive calls for HWP3 parsing */
517 
518     /* PCRE matching limitations */
519     uint64_t pcre_match_limit;
520     uint64_t pcre_recmatch_limit;
521     uint64_t pcre_max_filesize;
522 };
523 
524 extern cl_unrar_error_t (*cli_unrar_open)(const char *filename, void **hArchive, char **comment, uint32_t *comment_size, uint8_t debug_flag);
525 extern cl_unrar_error_t (*cli_unrar_peek_file_header)(void *hArchive, unrar_metadata_t *file_metadata);
526 extern cl_unrar_error_t (*cli_unrar_extract_file)(void *hArchive, const char *destPath, char *outputBuffer);
527 extern cl_unrar_error_t (*cli_unrar_skip_file)(void *hArchive);
528 extern void (*cli_unrar_close)(void *hArchive);
529 
530 extern LIBCLAMAV_EXPORT int have_rar;
531 
532 #define SCAN_ALLMATCHES (ctx->options->general & CL_SCAN_GENERAL_ALLMATCHES)
533 #define SCAN_COLLECT_METADATA (ctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA)
534 #define SCAN_HEURISTICS (ctx->options->general & CL_SCAN_GENERAL_HEURISTICS)
535 #define SCAN_HEURISTIC_PRECEDENCE (ctx->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE)
536 #define SCAN_UNPRIVILEGED (ctx->options->general & CL_SCAN_GENERAL_UNPRIVILEGED)
537 
538 #define SCAN_PARSE_ARCHIVE (ctx->options->parse & CL_SCAN_PARSE_ARCHIVE)
539 #define SCAN_PARSE_ELF (ctx->options->parse & CL_SCAN_PARSE_ELF)
540 #define SCAN_PARSE_PDF (ctx->options->parse & CL_SCAN_PARSE_PDF)
541 #define SCAN_PARSE_SWF (ctx->options->parse & CL_SCAN_PARSE_SWF)
542 #define SCAN_PARSE_HWP3 (ctx->options->parse & CL_SCAN_PARSE_HWP3)
543 #define SCAN_PARSE_XMLDOCS (ctx->options->parse & CL_SCAN_PARSE_XMLDOCS)
544 #define SCAN_PARSE_MAIL (ctx->options->parse & CL_SCAN_PARSE_MAIL)
545 #define SCAN_PARSE_OLE2 (ctx->options->parse & CL_SCAN_PARSE_OLE2)
546 #define SCAN_PARSE_HTML (ctx->options->parse & CL_SCAN_PARSE_HTML)
547 #define SCAN_PARSE_PE (ctx->options->parse & CL_SCAN_PARSE_PE)
548 
549 #define SCAN_HEURISTIC_BROKEN (ctx->options->heuristic & CL_SCAN_HEURISTIC_BROKEN)
550 #define SCAN_HEURISTIC_BROKEN_MEDIA (ctx->options->heuristic & CL_SCAN_HEURISTIC_BROKEN_MEDIA)
551 #define SCAN_HEURISTIC_EXCEEDS_MAX (ctx->options->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX)
552 #define SCAN_HEURISTIC_PHISHING_SSL_MISMATCH (ctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH)
553 #define SCAN_HEURISTIC_PHISHING_CLOAK (ctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_CLOAK)
554 #define SCAN_HEURISTIC_MACROS (ctx->options->heuristic & CL_SCAN_HEURISTIC_MACROS)
555 #define SCAN_HEURISTIC_ENCRYPTED_ARCHIVE (ctx->options->heuristic & CL_SCAN_HEURISTIC_ENCRYPTED_ARCHIVE)
556 #define SCAN_HEURISTIC_ENCRYPTED_DOC (ctx->options->heuristic & CL_SCAN_HEURISTIC_ENCRYPTED_DOC)
557 #define SCAN_HEURISTIC_PARTITION_INTXN (ctx->options->heuristic & CL_SCAN_HEURISTIC_PARTITION_INTXN)
558 #define SCAN_HEURISTIC_STRUCTURED (ctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED)
559 #define SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL (ctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL)
560 #define SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED (ctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED)
561 
562 #define SCAN_MAIL_PARTIAL_MESSAGE (ctx->options->mail & CL_SCAN_MAIL_PARTIAL_MESSAGE)
563 
564 #define SCAN_DEV_COLLECT_SHA (ctx->options->dev & CL_SCAN_DEV_COLLECT_SHA)
565 #define SCAN_DEV_COLLECT_PERF_INFO (ctx->options->dev & CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO)
566 
567 /* based on macros from A. Melnikoff */
568 #define cbswap16(v) (((v & 0xff) << 8) | (((v) >> 8) & 0xff))
569 #define cbswap32(v) ((((v)&0x000000ff) << 24) | (((v)&0x0000ff00) << 8) | \
570                      (((v)&0x00ff0000) >> 8) | (((v)&0xff000000) >> 24))
571 #define cbswap64(v) ((((v)&0x00000000000000ffULL) << 56) | \
572                      (((v)&0x000000000000ff00ULL) << 40) | \
573                      (((v)&0x0000000000ff0000ULL) << 24) | \
574                      (((v)&0x00000000ff000000ULL) << 8) |  \
575                      (((v)&0x000000ff00000000ULL) >> 8) |  \
576                      (((v)&0x0000ff0000000000ULL) >> 24) | \
577                      (((v)&0x00ff000000000000ULL) >> 40) | \
578                      (((v)&0xff00000000000000ULL) >> 56))
579 
580 #ifndef HAVE_ATTRIB_PACKED
581 #define __attribute__(x)
582 #endif
583 #ifdef HAVE_PRAGMA_PACK
584 #pragma pack(1)
585 #endif
586 #ifdef HAVE_PRAGMA_PACK_HPPA
587 #pragma pack 1
588 #endif
589 
590 union unaligned_64 {
591     uint64_t una_u64;
592     int64_t una_s64;
593 } __attribute__((packed));
594 
595 union unaligned_32 {
596     uint32_t una_u32;
597     int32_t una_s32;
598 } __attribute__((packed));
599 
600 union unaligned_16 {
601     uint16_t una_u16;
602     int16_t una_s16;
603 } __attribute__((packed));
604 
605 struct unaligned_ptr {
606     void *ptr;
607 } __attribute__((packed));
608 
609 #ifdef HAVE_PRAGMA_PACK
610 #pragma pack()
611 #endif
612 #ifdef HAVE_PRAGMA_PACK_HPPA
613 #pragma pack
614 #endif
615 
616 #if WORDS_BIGENDIAN == 0
617 /* Little endian */
618 #define le16_to_host(v) (v)
619 #define le32_to_host(v) (v)
620 #define le64_to_host(v) (v)
621 #define be16_to_host(v) cbswap16(v)
622 #define be32_to_host(v) cbswap32(v)
623 #define be64_to_host(v) cbswap64(v)
624 #define cli_readint64(buff) (((const union unaligned_64 *)(buff))->una_s64)
625 #define cli_readint32(buff) (((const union unaligned_32 *)(buff))->una_s32)
626 #define cli_readint16(buff) (((const union unaligned_16 *)(buff))->una_s16)
627 #define cli_writeint32(offset, value) (((union unaligned_32 *)(offset))->una_u32 = (uint32_t)(value))
628 #else
629 /* Big endian */
630 #define le16_to_host(v) cbswap16(v)
631 #define le32_to_host(v) cbswap32(v)
632 #define le64_to_host(v) cbswap64(v)
633 #define be16_to_host(v) (v)
634 #define be32_to_host(v) (v)
635 #define be64_to_host(v) (v)
636 
cli_readint64(const void * buff)637 static inline int64_t cli_readint64(const void *buff)
638 {
639     int64_t ret;
640     ret = (int64_t)((const char *)buff)[0] & 0xff;
641     ret |= (int64_t)(((const char *)buff)[1] & 0xff) << 8;
642     ret |= (int64_t)(((const char *)buff)[2] & 0xff) << 16;
643     ret |= (int64_t)(((const char *)buff)[3] & 0xff) << 24;
644 
645     ret |= (int64_t)(((const char *)buff)[4] & 0xff) << 32;
646     ret |= (int64_t)(((const char *)buff)[5] & 0xff) << 40;
647     ret |= (int64_t)(((const char *)buff)[6] & 0xff) << 48;
648     ret |= (int64_t)(((const char *)buff)[7] & 0xff) << 56;
649     return ret;
650 }
651 
cli_readint32(const void * buff)652 static inline int32_t cli_readint32(const void *buff)
653 {
654     int32_t ret;
655     ret = (int32_t)((const char *)buff)[0] & 0xff;
656     ret |= (int32_t)(((const char *)buff)[1] & 0xff) << 8;
657     ret |= (int32_t)(((const char *)buff)[2] & 0xff) << 16;
658     ret |= (int32_t)(((const char *)buff)[3] & 0xff) << 24;
659     return ret;
660 }
661 
cli_readint16(const void * buff)662 static inline int16_t cli_readint16(const void *buff)
663 {
664     int16_t ret;
665     ret = (int16_t)((const char *)buff)[0] & 0xff;
666     ret |= (int16_t)(((const char *)buff)[1] & 0xff) << 8;
667     return ret;
668 }
669 
cli_writeint32(void * offset,uint32_t value)670 static inline void cli_writeint32(void *offset, uint32_t value)
671 {
672     ((char *)offset)[0] = value & 0xff;
673     ((char *)offset)[1] = (value & 0xff00) >> 8;
674     ((char *)offset)[2] = (value & 0xff0000) >> 16;
675     ((char *)offset)[3] = (value & 0xff000000) >> 24;
676 }
677 #endif
678 
679 /**
680  * @brief Append an alert.
681  *
682  * An FP-check will verify that the file is not allowed.
683  * The allow list check does not happen before the scan because allowing files
684  * is so infrequent that such action would be detrimental to performance.
685  *
686  * TODO: Replace implementation with severity scale, and severity threshold
687  * wherein signatures that do not meet the threshold are documented in JSON
688  * metadata but do not halt the scan.
689  *
690  * @param ctx       The scan context.
691  * @param virname   The alert name.
692  * @return cl_error_t CL_VIRUS if scan should be halted due to an alert, CL_CLEAN if scan should continue.
693  */
694 cl_error_t cli_append_virus(cli_ctx *ctx, const char *virname);
695 
696 /**
697  * @brief Append a PUA (low severity) alert.
698  *
699  * This function will return CLEAN unless in all-match or Heuristic-precedence
700  * modes. The intention is for the scan to continue in case something more
701  * malicious is found.
702  *
703  * TODO: Replace implementation with severity scale, and severity threshold
704  * wherein signatures that do not meet the threshold are documented in JSON
705  * metadata but do not halt the scan.
706  *
707  * BUG: In normal scan mode (see above), the alert is not FP-checked!
708  *
709  * @param ctx       The scan context.
710  * @param virname   The alert name.
711  * @return cl_error_t CL_VIRUS if scan should be halted due to an alert, CL_CLEAN if scan should continue.
712  */
713 cl_error_t cli_append_possibly_unwanted(cli_ctx *ctx, const char *virname);
714 
715 const char *cli_get_last_virus(const cli_ctx *ctx);
716 const char *cli_get_last_virus_str(const cli_ctx *ctx);
717 void cli_virus_found_cb(cli_ctx *ctx);
718 
719 /**
720  * @brief Push a new fmap onto our scan recursion stack.
721  *
722  * May fail if we exceed max recursion depth.
723  *
724  * @param ctx           The scanning context.
725  * @param map           The fmap for the new layer.
726  * @param type          The file type. May be CL_TYPE_ANY if unknown. Can change it later with cli_recursion_stack_change_type().
727  * @param is_new_buffer true if the fmap represents a new buffer/file, and not some window into an existing fmap.
728  * @return cl_error_t   CL_SUCCESS if successful, else CL_EMAXREC if exceeding the max recursion depth.
729  */
730 cl_error_t cli_recursion_stack_push(cli_ctx *ctx, cl_fmap_t *map, cli_file_t type, bool is_new_buffer);
731 
732 /**
733  * @brief Pop off a layer of our scan recursion stack.
734  *
735  * Returns the fmap for the popped layer. Does NOT funmap() the fmap for you.
736  *
737  * @param ctx           The scanning context.
738  * @return cl_fmap_t*   A pointer to the fmap for the popped layer, may return NULL instead if the stack is empty.
739  */
740 cl_fmap_t *cli_recursion_stack_pop(cli_ctx *ctx);
741 
742 /**
743  * @brief Re-assign the type for the current layer.
744  *
745  * @param ctx   The scanning context.
746  * @param type  The new file type.
747  */
748 void cli_recursion_stack_change_type(cli_ctx *ctx, cli_file_t type);
749 
750 /**
751  * @brief Get the type of a specific layer.
752  *
753  * Ignores normalized layers internally.
754  *
755  * For index:
756  *  0 == the outermost (bottom) layer of the stack.
757  *  1 == the first layer (probably never explicitly used).
758  * -1 == the present innermost (top) layer of the stack.
759  * -2 == the parent layer (or "container"). That is, the second from the top of the stack.
760  *
761  * @param ctx           The scanning context.
762  * @param index         Desired index, will be converted internally as though the normalized layers were stripped out. Don't think too had about it. Or do. ¯\_(ツ)_/¯
763  * @return cli_file_t   The type of the requested layer,
764  *                      or returns CL_TYPE_ANY if a negative layer is requested,
765  *                      or returns CL_TYPE_IGNORED if requested layer too high.
766  */
767 cli_file_t cli_recursion_stack_get_type(cli_ctx *ctx, int index);
768 
769 /**
770  * @brief Get the size of a specific layer.
771  *
772  * Ignores normalized layers internally.
773  *
774  * For index:
775  *  0 == the outermost (bottom) layer of the stack.
776  *  1 == the first layer (probably never explicitly used).
777  * -1 == the present innermost (top) layer of the stack.
778  * -2 == the parent layer (or "container"). That is, the second from the top of the stack.
779  *
780  * @param ctx           The scanning context.
781  * @param index         Desired index, will be converted internally as though the normalized layers were stripped out. Don't think too had about it. Or do. ¯\_(ツ)_/¯
782  * @return cli_file_t   The size of the requested layer,
783  *                      or returns the size of the whole file if a negative layer is requested,
784  *                      or returns 0 if requested layer too high.
785  */
786 size_t cli_recursion_stack_get_size(cli_ctx *ctx, int index);
787 
788 /* used by: spin, yc (C) aCaB */
789 #define __SHIFTBITS(a) (sizeof(a) << 3)
790 #define __SHIFTMASK(a) (__SHIFTBITS(a) - 1)
791 #define CLI_ROL(a, b) a = (a << ((b)&__SHIFTMASK(a))) | (a >> ((__SHIFTBITS(a) - (b)) & __SHIFTMASK(a)))
792 #define CLI_ROR(a, b) a = (a >> ((b)&__SHIFTMASK(a))) | (a << ((__SHIFTBITS(a) - (b)) & __SHIFTMASK(a)))
793 
794 /* Implementation independent sign-extended signed right shift */
795 #ifdef HAVE_SAR
796 #define CLI_SRS(n, s) ((n) >> (s))
797 #else
798 #define CLI_SRS(n, s) ((((n) >> (s)) ^ (1 << (sizeof(n) * 8 - 1 - s))) - (1 << (sizeof(n) * 8 - 1 - s)))
799 #endif
800 #define CLI_SAR(n, s) n = CLI_SRS(n, s)
801 
802 #ifdef __GNUC__
803 void cli_warnmsg(const char *str, ...) __attribute__((format(printf, 1, 2)));
804 #else
805 void cli_warnmsg(const char *str, ...);
806 #endif
807 
808 #ifdef __GNUC__
809 void cli_errmsg(const char *str, ...) __attribute__((format(printf, 1, 2)));
810 #else
811 void cli_errmsg(const char *str, ...);
812 #endif
813 
814 #ifdef __GNUC__
815 void cli_infomsg(const cli_ctx *ctx, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
816 #else
817 void cli_infomsg(const cli_ctx *ctx, const char *fmt, ...);
818 #endif
819 
820 void cli_logg_setup(const cli_ctx *ctx);
821 void cli_logg_unsetup(void);
822 
823 /* tell compiler about branches that are very rarely taken,
824  * such as debug paths, and error paths */
825 #if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
826 #define UNLIKELY(cond) __builtin_expect(!!(cond), 0)
827 #define LIKELY(cond) __builtin_expect(!!(cond), 1)
828 #else
829 #define UNLIKELY(cond) (cond)
830 #define LIKELY(cond) (cond)
831 #endif
832 
833 #ifdef __GNUC__
834 #define always_inline inline __attribute__((always_inline))
835 #define never_inline __attribute__((noinline))
836 #else
837 #define never_inline
838 #define always_inline inline
839 #endif
840 
841 #if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
842 #define __hot__ __attribute__((hot))
843 #else
844 #define __hot__
845 #endif
846 
847 #define cli_dbgmsg (!UNLIKELY(cli_get_debug_flag())) ? (void)0 : cli_dbgmsg_internal
848 
849 #ifdef __GNUC__
850 void cli_dbgmsg_internal(const char *str, ...) __attribute__((format(printf, 1, 2)));
851 #else
852 void cli_dbgmsg_internal(const char *str, ...);
853 #endif
854 
855 #ifdef HAVE_CLI_GETPAGESIZE
856 #undef HAVE_CLI_GETPAGESIZE
857 #endif
858 
859 #ifdef _WIN32
cli_getpagesize(void)860 static inline int cli_getpagesize(void)
861 {
862     SYSTEM_INFO si;
863     GetSystemInfo(&si);
864     return si.dwPageSize;
865 }
866 #define HAVE_CLI_GETPAGESIZE 1
867 #else /* ! _WIN32 */
868 #if HAVE_SYSCONF_SC_PAGESIZE
cli_getpagesize(void)869 static inline int cli_getpagesize(void)
870 {
871     return sysconf(_SC_PAGESIZE);
872 }
873 #define HAVE_CLI_GETPAGESIZE 1
874 #else
875 #if HAVE_GETPAGESIZE
cli_getpagesize(void)876 static inline int cli_getpagesize(void)
877 {
878     return getpagesize();
879 }
880 #define HAVE_CLI_GETPAGESIZE 1
881 #endif /* HAVE_GETPAGESIZE */
882 #endif /* HAVE_SYSCONF_SC_PAGESIZE */
883 #endif /* _WIN32 */
884 
885 void *cli_malloc(size_t nmemb);
886 void *cli_calloc(size_t nmemb, size_t size);
887 void *cli_realloc(void *ptr, size_t size);
888 void *cli_realloc2(void *ptr, size_t size);
889 char *cli_strdup(const char *s);
890 int cli_rmdirs(const char *dirname);
891 char *cli_hashstream(FILE *fs, unsigned char *digcpy, int type);
892 char *cli_hashfile(const char *filename, int type);
893 int cli_unlink(const char *pathname);
894 size_t cli_readn(int fd, void *buff, size_t count);
895 size_t cli_writen(int fd, const void *buff, size_t count);
896 const char *cli_gettmpdir(void);
897 
898 /**
899  * @brief Sanitize a relative path, so it cannot have a negative depth.
900  *
901  * Caller is responsible for freeing the sanitized filepath.
902  * The optioal sanitized_filebase output param is a pointer into the filepath,
903  * if set, and does not need to be freed.
904  *
905  * @param filepath                  The filepath to sanitize
906  * @param filepath_len              The length of the filepath
907  * @param[out] sanitized_filebase   Pointer to the basename portion of the sanitized filepath. (optional)
908  * @return char*
909  */
910 char *cli_sanitize_filepath(const char *filepath, size_t filepath_len, char **sanitized_filebase);
911 
912 /**
913  * @brief Generate tempfile filename (no path) with a random MD5 hash.
914  *
915  * Caller is responsible for freeing the filename.
916  *
917  * @return char* filename or NULL.
918  */
919 char *cli_genfname(const char *prefix);
920 
921 /**
922  * @brief Generate a full tempfile filepath with a provided the name.
923  *
924  * Caller is responsible for freeing the filename.
925  * If the dir is not provided, the engine->tmpdir will be used.
926  *
927  * @param dir 	 Alternative directory. (optional)
928  * @return char* filename or NULL.
929  */
930 char *cli_newfilepath(const char *dir, const char *fname);
931 
932 /**
933  * @brief Generate a full tempfile filepath with a provided the name.
934  *
935  * Caller is responsible for freeing the filename.
936  * If the dir is not provided, the engine->tmpdir will be used.
937  *
938  * @param dir        Alternative temp directory (optional).
939  * @param fname  	 Filename for new file.
940  * @param[out] name  Allocated filepath, must be freed by caller.
941  * @param[out] fd    File descriptor of open temp file.
942  */
943 cl_error_t cli_newfilepathfd(const char *dir, char *fname, char **name, int *fd);
944 
945 /**
946  * @brief Generate a full tempfile filepath with a random MD5 hash and prefix the name, if provided.
947  *
948  * Caller is responsible for freeing the filename.
949  *
950  * @param dir 	 Alternative temp directory. (optional)
951  * @param prefix (Optional) Prefix for new file tempfile.
952  * @return char* filename or NULL.
953  */
954 char *cli_gentemp_with_prefix(const char *dir, const char *prefix);
955 
956 /**
957  * @brief Generate a full tempfile filepath with a random MD5 hash.
958  *
959  * Caller is responsible for freeing the filename.
960  *
961  * @param dir 	 Alternative temp directory. (optional)
962  * @return char* filename or NULL.
963  */
964 char *cli_gentemp(const char *dir);
965 
966 /**
967  * @brief Create a temp filename, create the file, open it, and pass back the filepath and open file descriptor.
968  *
969  * @param dir        Alternative temp directory (optional).
970  * @param[out] name  Allocated filepath, must be freed by caller.
971  * @param[out] fd    File descriptor of open temp file.
972  * @return cl_error_t CL_SUCCESS, CL_ECREAT, or CL_EMEM.
973  */
974 cl_error_t cli_gentempfd(const char *dir, char **name, int *fd);
975 
976 /**
977  * @brief Create a temp filename, create the file, open it, and pass back the filepath and open file descriptor.
978  *
979  * @param dir        Alternative temp directory (optional).
980  * @param prefix  	 (Optional) Prefix for new file tempfile.
981  * @param[out] name  Allocated filepath, must be freed by caller.
982  * @param[out] fd    File descriptor of open temp file.
983  * @return cl_error_t CL_SUCCESS, CL_ECREAT, or CL_EMEM.
984  */
985 cl_error_t cli_gentempfd_with_prefix(const char *dir, const char *prefix, char **name, int *fd);
986 
987 unsigned int cli_rndnum(unsigned int max);
988 int cli_filecopy(const char *src, const char *dest);
989 bitset_t *cli_bitset_init(void);
990 void cli_bitset_free(bitset_t *bs);
991 int cli_bitset_set(bitset_t *bs, unsigned long bit_offset);
992 int cli_bitset_test(bitset_t *bs, unsigned long bit_offset);
993 const char *cli_ctime(const time_t *timep, char *buf, const size_t bufsize);
994 void cli_append_virus_if_heur_exceedsmax(cli_ctx *, char *);
995 cl_error_t cli_checklimits(const char *, cli_ctx *, unsigned long, unsigned long, unsigned long);
996 
997 /**
998  * @brief Call before scanning a file to determine if we should scan it, skip it, or abort the entire scanning process.
999  *
1000  * If the verdict is CL_SUCCESS, then this function increments the # of scanned files, and increments the amount of scanned data.
1001  * If the verdict is that a limit has been exceeded, then ctx->
1002  *
1003  * @param ctx       The scanning context.
1004  * @param needed    The size of the file we're considering scanning.
1005  * @return cl_error_t CL_SUCCESS if we're good to keep scanning else an error status.
1006  */
1007 cl_error_t cli_updatelimits(cli_ctx *ctx, size_t needed);
1008 
1009 unsigned long cli_getsizelimit(cli_ctx *, unsigned long);
1010 int cli_matchregex(const char *str, const char *regex);
1011 void cli_qsort(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *));
1012 void cli_qsort_r(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *, const void *), void *arg);
1013 cl_error_t cli_checktimelimit(cli_ctx *ctx);
1014 
1015 /* symlink behaviour */
1016 #define CLI_FTW_FOLLOW_FILE_SYMLINK 0x01
1017 #define CLI_FTW_FOLLOW_DIR_SYMLINK 0x02
1018 
1019 /* if the callback needs the stat */
1020 #define CLI_FTW_NEED_STAT 0x04
1021 
1022 /* remove leading/trailing slashes */
1023 #define CLI_FTW_TRIM_SLASHES 0x08
1024 #define CLI_FTW_STD (CLI_FTW_NEED_STAT | CLI_FTW_TRIM_SLASHES)
1025 
1026 enum cli_ftw_reason {
1027     visit_file,
1028     visit_directory_toplev, /* this is a directory at toplevel of recursion */
1029     error_mem,              /* recommended to return CL_EMEM */
1030     /* recommended to return CL_SUCCESS below */
1031     error_stat,
1032     warning_skipped_link,
1033     warning_skipped_special,
1034     warning_skipped_dir
1035 };
1036 
1037 /* wrap void*, so that we don't mix it with some other pointer */
1038 struct cli_ftw_cbdata {
1039     void *data;
1040 };
1041 
1042 /**
1043  * @brief Callback to process each file in a file tree walk (FTW).
1044  *
1045  * The callback is responsible for freeing filename when it is done using it.
1046  *
1047  * Note that callback decides if directory traversal should continue
1048  * after an error, we call the callback with reason == error,
1049  * and if it returns CL_BREAK we break.
1050  *
1051  * Return:
1052  * - CL_BREAK to break out without an error,
1053  * - CL_SUCCESS to continue,
1054  * - any CL_E* to break out due to error.
1055  */
1056 typedef cl_error_t (*cli_ftw_cb)(STATBUF *stat_buf, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data);
1057 
1058 /**
1059  * @brief Callback to determine if a path in a file tree walk (FTW) should be skipped.
1060  * Has access to the same callback data as the main FTW callback function (above).
1061  *
1062  * Return:
1063  * - 1 if the path should be skipped (i.e. to not call the callback for the given path),
1064  * - 0 if the path should be processed (i.e. to call the callback for the given path).
1065  */
1066 typedef int (*cli_ftw_pathchk)(const char *path, struct cli_ftw_cbdata *data);
1067 
1068 /**
1069  * @brief Traverse a file path, calling the callback function on each file
1070  * within if the pathchk() check allows for it. Will skip certain file types:
1071  * -
1072  *
1073  * This is regardless of virus found/not, that is the callback's job to store.
1074  * Note that the callback may dispatch async the scan, so that when cli_ftw
1075  * returns we don't know the infected/notinfected status of the directory yet!
1076  *
1077  * Due to this if the callback scans synchronously it should store the infected
1078  * status in its cbdata.
1079  * This works for both files and directories. It stats the path to determine
1080  * which one it is.
1081  * If it is a file, it simply calls the callback once, otherwise recurses.
1082  *
1083  * @param base      The top level directory (or file) path to be processed
1084  * @param flags     A bitflag field for the CLI_FTW_* flag options (see above)
1085  * @param maxdepth  The max recursion depth.
1086  * @param callback  The cli_ftw_cb callback to invoke on each file AND directory.
1087  * @param data      Callback data for the callback function.
1088  * @param pathchk   A function used to determine if the callback should be run on the given file.
1089  * @return cl_error_t CL_SUCCESS if it traversed all files and subdirs
1090  * @return cl_error_t CL_BREAK if traversal has stopped at some point
1091  * @return cl_error_t CL_E* if error encountered during traversal and we had to break out
1092  */
1093 cl_error_t cli_ftw(char *base, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk);
1094 
1095 const char *cli_strerror(int errnum, char *buf, size_t len);
1096 
1097 #ifdef _WIN32
1098 /**
1099  * @brief   Attempt to get a filename from an open file handle.
1100  *
1101  * Windows only.
1102  *
1103  * @param hFile          File handle
1104  * @param[out] filepath  Will be set to file path if found, or NULL.
1105  * @return cl_error_t    CL_SUCCESS if found, else an error code.
1106  */
1107 cl_error_t cli_get_filepath_from_handle(HANDLE hFile, char **filepath);
1108 #endif
1109 
1110 /**
1111  * @brief   Attempt to get a filename from an open file descriptor.
1112  *
1113  * Caller is responsible for free'ing the filename.
1114  * Should work on Linux, macOS, Windows.
1115  *
1116  * @param desc           File descriptor
1117  * @param[out] filepath  Will be set to file path if found, or NULL.
1118  * @return cl_error_t    CL_SUCCESS if found, else an error code.
1119  */
1120 cl_error_t cli_get_filepath_from_filedesc(int desc, char **filepath);
1121 
1122 /**
1123  * @brief   Attempt to get the real path of a provided path (evaluating symlinks).
1124  *
1125  * Caller is responsible for free'ing the file path.
1126  * On posix systems this just calls realpath() under the hood.
1127  * On Win32, it opens a handle and uses cli_get_filepath_from_filedesc()
1128  * to get the real path.
1129  *
1130  * @param desc          A file path to evaluate.
1131  * @param[out] char*    A malloced string containing the real path.
1132  * @return cl_error_t   CL_SUCCESS if found, else an error code.
1133  */
1134 cl_error_t cli_realpath(const char *file_name, char **real_filename);
1135 
1136 /**
1137  * @brief   Get the libclamav debug flag (e.g. if debug logging is enabled)
1138  *
1139  * This is required for unit tests to be able to link with clamav.dll and not
1140  * directly manipulate libclamav global variables.
1141  */
1142 uint8_t cli_get_debug_flag();
1143 
1144 /**
1145  * @brief   Set the libclamav debug flag to a specific value.
1146  *
1147  * The public cl_debug() API will only ever enable debug mode, it won't disable debug mode.
1148  *
1149  * This is required for unit tests to be able to link with clamav.dll and not
1150  * directly manipulate libclamav global variables.
1151  */
1152 uint8_t cli_set_debug_flag(uint8_t debug_flag);
1153 
1154 #ifndef STRDUP
1155 #define STRDUP(buf, var, ...) \
1156     do {                      \
1157         var = strdup(buf);    \
1158         if (NULL == var) {    \
1159             do {              \
1160                 __VA_ARGS__;  \
1161             } while (0);      \
1162             goto done;        \
1163         }                     \
1164     } while (0)
1165 #endif
1166 
1167 #ifndef FREE
1168 #define FREE(var)          \
1169     do {                   \
1170         if (NULL != var) { \
1171             free(var);     \
1172             var = NULL;    \
1173         }                  \
1174     } while (0)
1175 #endif
1176 
1177 #ifndef MALLOC
1178 #define MALLOC(var, size, ...) \
1179     do {                       \
1180         var = malloc(size);    \
1181         if (NULL == var) {     \
1182             do {               \
1183                 __VA_ARGS__;   \
1184             } while (0);       \
1185             goto done;         \
1186         }                      \
1187     } while (0)
1188 #endif
1189 
1190 #ifndef CLI_MALLOC
1191 #define CLI_MALLOC(var, size, ...) \
1192     do {                           \
1193         var = cli_malloc(size);    \
1194         if (NULL == var) {         \
1195             do {                   \
1196                 __VA_ARGS__;       \
1197             } while (0);           \
1198             goto done;             \
1199         }                          \
1200     } while (0)
1201 #endif
1202 
1203 #ifndef CALLOC
1204 #define CALLOC(var, nmemb, size, ...) \
1205     do {                              \
1206         (var) = calloc(nmemb, size);  \
1207         if (NULL == var) {            \
1208             do {                      \
1209                 __VA_ARGS__;          \
1210             } while (0);              \
1211             goto done;                \
1212         }                             \
1213     } while (0)
1214 #endif
1215 
1216 #ifndef CLI_CALLOC
1217 #define CLI_CALLOC(var, nmemb, size, ...) \
1218     do {                                  \
1219         (var) = cli_calloc(nmemb, size);  \
1220         if (NULL == var) {                \
1221             do {                          \
1222                 __VA_ARGS__;              \
1223             } while (0);                  \
1224             goto done;                    \
1225         }                                 \
1226     } while (0)
1227 #endif
1228 
1229 #ifndef VERIFY_POINTER
1230 #define VERIFY_POINTER(ptr, ...) \
1231     do {                         \
1232         if (NULL == ptr) {       \
1233             do {                 \
1234                 __VA_ARGS__;     \
1235             } while (0);         \
1236             goto done;           \
1237         }                        \
1238     } while (0)
1239 #endif
1240 
1241 #endif
1242