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