2
* Copyright (C) 2007-2013 Sourcefire, Inc.
3
* Copyright (C) 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
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.
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.
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,
23
#include "clamav-config.h"
33
#include <sys/types.h>
38
#ifdef HAVE_SYS_PARAM_H
39
#include <sys/param.h>
43
#ifdef HAVE_SYS_TIMES_H
44
#include <sys/times.h>
47
#define DCONF_ARCH ctx->dconf->archive
48
#define DCONF_DOC ctx->dconf->doc
49
#define DCONF_MAIL ctx->dconf->mail
50
#define DCONF_OTHER ctx->dconf->other
56
#include "matcher-ac.h"
57
#include "matcher-bm.h"
59
#include "ole2_extract.h"
60
#include "vba_extract.h"
63
#include "chmunpack.h"
66
#include "filetypes.h"
71
/* #include "uuencode.h" */
80
#include "nsis/nulsft.h"
101
#include "xz_iface.h"
107
#include "json_api.h"
113
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
120
static int cli_scanfile(const char *filename, cli_ctx *ctx);
122
static int cli_scandir(const char *dirname, cli_ctx *ctx)
126
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
129
char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
134
unsigned int viruses_found = 0;
136
if((dd = opendir(dirname)) != NULL) {
137
#ifdef HAVE_READDIR_R_3
138
while(!readdir_r(dd, &result.d, &dent) && dent) {
139
#elif defined(HAVE_READDIR_R_2)
140
while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
142
while((dent = readdir(dd))) {
146
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
147
/* build the full name */
148
fname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
151
cli_dbgmsg("cli_scandir: Unable to allocate memory for filename\n");
155
sprintf(fname, "%s"PATHSEP"%s", dirname, dent->d_name);
158
if(LSTAT(fname, &statbuf) != -1) {
159
if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {
160
if(cli_scandir(fname, ctx) == CL_VIRUS) {
172
if(S_ISREG(statbuf.st_mode)) {
173
if(cli_scanfile(fname, ctx) == CL_VIRUS) {
192
cli_dbgmsg("cli_scandir: Can't open directory %s.\n", dirname);
197
if (SCAN_ALL && viruses_found)
202
static int cli_unrar_scanmetadata(int desc, unrar_metadata_t *metadata, cli_ctx *ctx, unsigned int files, uint32_t* sfx_check)
204
int ret = CL_SUCCESS;
206
if(files == 1 && sfx_check) {
207
if(*sfx_check == metadata->crc)
208
return CL_BREAK;/* break extract loop */
210
*sfx_check = metadata->crc;
213
cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %u, compressed: %u, normal: %u, method: %u, ratio: %u\n",
214
metadata->filename, metadata->crc, metadata->encrypted, (unsigned int) metadata->pack_size,
215
(unsigned int) metadata->unpack_size, metadata->method,
216
metadata->pack_size ? (unsigned int) (metadata->unpack_size / metadata->pack_size) : 0);
218
if(cli_matchmeta(ctx, metadata->filename, metadata->pack_size, metadata->unpack_size, metadata->encrypted, files, metadata->crc, NULL) == CL_VIRUS)
221
if(DETECT_ENCRYPTED && metadata->encrypted) {
222
cli_dbgmsg("RAR: Encrypted files found in archive.\n");
223
ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
224
if(ret != CL_VIRUS) {
225
cli_append_virus(ctx, "Heuristics.Encrypted.RAR");
233
static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
236
unrar_metadata_t *metadata, *metadata_tmp;
238
unrar_state_t rar_state;
239
unsigned int viruses_found = 0;
241
cli_dbgmsg("in scanrar()\n");
244
if(lseek(desc, sfx_offset, SEEK_SET) == -1)
247
/* generate the temporary directory */
248
if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
251
if(mkdir(dir, 0700)) {
252
cli_dbgmsg("RAR: Can't create temporary directory %s\n", dir);
257
if((ret = cli_unrar_open(desc, dir, &rar_state)) != UNRAR_OK) {
258
if(!ctx->engine->keeptmp)
261
if(ret == UNRAR_PASSWD) {
262
cli_dbgmsg("RAR: Encrypted main header\n");
263
if(DETECT_ENCRYPTED) {
264
if (lseek(desc, 0, SEEK_SET) == -1) {
265
cli_dbgmsg("RAR: call to lseek() failed\n");
268
ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
270
cli_append_virus(ctx, "Heuristics.Encrypted.RAR");
274
} if(ret == UNRAR_EMEM) {
284
ret = cli_unrar_extract_next_prepare(&rar_state,dir);
285
if(ret != UNRAR_OK) {
286
if(ret == UNRAR_BREAK)
288
else if(ret == UNRAR_EMEM)
294
if(ctx->engine->maxscansize && ctx->scansize >= ctx->engine->maxscansize) {
295
free(rar_state.file_header->filename);
296
free(rar_state.file_header);
300
if(ctx->engine->maxscansize && ctx->scansize + ctx->engine->maxfilesize >= ctx->engine->maxscansize)
301
rar_state.maxfilesize = ctx->engine->maxscansize - ctx->scansize;
303
rar_state.maxfilesize = ctx->engine->maxfilesize;
305
ret = cli_unrar_extract_next(&rar_state,dir);
308
else if(ret == UNRAR_EMEM)
313
if(rar_state.ofd > 0) {
314
if (lseek(rar_state.ofd,0,SEEK_SET) == -1) {
315
cli_dbgmsg("RAR: Call to lseek() failed\n");
318
rc = cli_magic_scandesc(rar_state.ofd,ctx);
319
close(rar_state.ofd);
320
if(!ctx->engine->keeptmp)
321
if (cli_unlink(rar_state.filename)) ret = CL_EUNLINK;
322
if(rc == CL_VIRUS ) {
323
cli_dbgmsg("RAR: infected with %s\n", cli_get_last_virus(ctx));
329
if(ret == CL_VIRUS) {
336
if(ret == CL_SUCCESS)
337
ret = cli_unrar_scanmetadata(desc,rar_state.metadata_tail, ctx, rar_state.file_count, sfx_check);
339
} while(ret == CL_SUCCESS);
344
metadata = metadata_tmp = rar_state.metadata;
346
if(cli_scandir(rar_state.comment_dir, ctx) == CL_VIRUS)
349
cli_unrar_close(&rar_state);
351
if(!ctx->engine->keeptmp)
356
metadata = metadata_tmp;
358
metadata_tmp = metadata->next;
359
free(metadata->filename);
361
metadata = metadata_tmp;
363
cli_dbgmsg("RAR: Exit code: %d\n", ret);
365
if (SCAN_ALL && viruses_found)
370
static int cli_scanarj(cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
372
int ret = CL_CLEAN, rc, file = 0;
373
arj_metadata_t metadata;
376
UNUSEDPARAM(sfx_check);
378
cli_dbgmsg("in cli_scanarj()\n");
380
/* generate the temporary directory */
381
if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
384
if(mkdir(dir, 0700)) {
385
cli_dbgmsg("ARJ: Can't create temporary directory %s\n", dir);
390
ret = cli_unarj_open(*ctx->fmap, dir, &metadata, sfx_offset);
391
if (ret != CL_SUCCESS) {
392
if(!ctx->engine->keeptmp)
395
cli_dbgmsg("ARJ: Error: %s\n", cl_strerror(ret));
400
metadata.filename = NULL;
401
ret = cli_unarj_prepare_file(dir, &metadata);
402
if (ret != CL_SUCCESS) {
403
cli_dbgmsg("ARJ: cli_unarj_prepare_file Error: %s\n", cl_strerror(ret));
407
if(cli_matchmeta(ctx, metadata.filename, metadata.comp_size, metadata.orig_size, metadata.encrypted, file, 0, NULL) == CL_VIRUS) {
413
if ((ret = cli_checklimits("ARJ", ctx, metadata.orig_size, metadata.comp_size, 0))!=CL_CLEAN) {
415
if (metadata.filename)
416
free(metadata.filename);
419
ret = cli_unarj_extract_file(dir, &metadata);
420
if (ret != CL_SUCCESS) {
421
cli_dbgmsg("ARJ: cli_unarj_extract_file Error: %s\n", cl_strerror(ret));
423
if (metadata.ofd >= 0) {
424
if (lseek(metadata.ofd, 0, SEEK_SET) == -1) {
425
cli_dbgmsg("ARJ: call to lseek() failed\n");
427
rc = cli_magic_scandesc(metadata.ofd, ctx);
429
if (rc == CL_VIRUS) {
430
cli_dbgmsg("ARJ: infected with %s\n", cli_get_last_virus(ctx));
432
if (metadata.filename) {
433
free(metadata.filename);
434
metadata.filename = NULL;
439
if (metadata.filename) {
440
free(metadata.filename);
441
metadata.filename = NULL;
444
} while(ret == CL_SUCCESS);
446
if(!ctx->engine->keeptmp)
450
if (metadata.filename) {
451
free(metadata.filename);
454
cli_dbgmsg("ARJ: Exit code: %d\n", ret);
462
static int cli_scangzip_with_zib_from_the_80s(cli_ctx *ctx, unsigned char *buff) {
463
int fd, ret, outsize = 0, bytes;
464
fmap_t *map = *ctx->fmap;
475
if(!(gz = gzdopen(fd, "rb"))) {
480
if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
481
cli_dbgmsg("GZip: Can't generate temporary file.\n");
487
while((bytes = gzread(gz, buff, FILEBUFF)) > 0) {
489
if(cli_checklimits("GZip", ctx, outsize, 0, 0)!=CL_CLEAN)
491
if(cli_writen(fd, buff, bytes) != bytes) {
494
if(cli_unlink(tmpname)) {
505
if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
506
cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx));
508
if(!ctx->engine->keeptmp) {
509
if (cli_unlink(tmpname)) {
518
if(!ctx->engine->keeptmp)
519
if (cli_unlink(tmpname)) ret = CL_EUNLINK;
524
static int cli_scangzip(cli_ctx *ctx)
526
int fd, ret = CL_CLEAN;
527
unsigned char buff[FILEBUFF];
530
size_t at = 0, outsize = 0;
531
fmap_t *map = *ctx->fmap;
533
cli_dbgmsg("in cli_scangzip()\n");
535
memset(&z, 0, sizeof(z));
536
if((ret = inflateInit2(&z, MAX_WBITS + 16)) != Z_OK) {
537
cli_dbgmsg("GZip: InflateInit failed: %d\n", ret);
538
return cli_scangzip_with_zib_from_the_80s(ctx, buff);
541
if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
542
cli_dbgmsg("GZip: Can't generate temporary file.\n");
547
while (at < map->len) {
548
unsigned int bytes = MIN(map->len - at, map->pgsz);
549
if(!(z.next_in = (void*)fmap_need_off_once(map, at, bytes))) {
550
cli_dbgmsg("GZip: Can't read %u bytes @ %lu.\n", bytes, (long unsigned)at);
553
if (cli_unlink(tmpname)) {
564
z.avail_out = sizeof(buff);
566
inf = inflate(&z, Z_NO_FLUSH);
567
if(inf != Z_OK && inf != Z_STREAM_END && inf != Z_BUF_ERROR) {
568
if (sizeof(buff) == z.avail_out) {
569
cli_dbgmsg("GZip: Bad stream, nothing in output buffer.\n");
574
cli_dbgmsg("GZip: Bad stream, data in output buffer.\n");
575
/* no break yet, flush extracted bytes to file */
578
if(cli_writen(fd, buff, sizeof(buff) - z.avail_out) < 0) {
581
if (cli_unlink(tmpname)) {
588
outsize += sizeof(buff) - z.avail_out;
589
if(cli_checklimits("GZip", ctx, outsize, 0, 0)!=CL_CLEAN) {
593
if(inf == Z_STREAM_END) {
598
else if(inf != Z_OK && inf != Z_BUF_ERROR) {
602
} while (z.avail_out == 0);
607
if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
608
cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx));
610
if(!ctx->engine->keeptmp) {
611
if (cli_unlink(tmpname)) {
620
if(!ctx->engine->keeptmp)
621
if (cli_unlink(tmpname)) ret = CL_EUNLINK;
627
static int cli_scanbzip(cli_ctx *ctx) {
628
cli_warnmsg("cli_scanbzip: bzip2 support not compiled in\n");
635
#define BZ2_bzDecompressInit bzDecompressInit
636
#define BZ2_bzDecompress bzDecompress
637
#define BZ2_bzDecompressEnd bzDecompressEnd
640
static int cli_scanbzip(cli_ctx *ctx)
642
int ret = CL_CLEAN, fd, rc;
643
unsigned long int size = 0;
650
memset(&strm, 0, sizeof(strm));
652
strm.avail_out = sizeof(buf);
653
rc = BZ2_bzDecompressInit(&strm, 0, 0);
655
cli_dbgmsg("Bzip: DecompressInit failed: %d\n", rc);
659
if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd))) {
660
cli_dbgmsg("Bzip: Can't generate temporary file.\n");
661
BZ2_bzDecompressEnd(&strm);
666
if (!strm.avail_in) {
667
strm.next_in = (void*)fmap_need_off_once_len(*ctx->fmap, off, FILEBUFF, &avail);
668
strm.avail_in = avail;
670
if (!strm.avail_in) {
671
cli_dbgmsg("Bzip: premature end of compressed stream\n");
676
rc = BZ2_bzDecompress(&strm);
677
if (BZ_OK != rc && BZ_STREAM_END != rc) {
678
cli_dbgmsg("Bzip: decompress error: %d\n", rc);
682
if (!strm.avail_out || BZ_STREAM_END == rc) {
683
size += sizeof(buf) - strm.avail_out;
685
if(cli_checklimits("Bzip", ctx, size + FILEBUFF, 0, 0)!=CL_CLEAN)
688
if(cli_writen(fd, buf, sizeof(buf) - strm.avail_out) != sizeof(buf) - strm.avail_out) {
689
cli_dbgmsg("Bzip: Can't write to file.\n");
690
BZ2_bzDecompressEnd(&strm);
692
if(!ctx->engine->keeptmp) {
693
if (cli_unlink(tmpname)) {
702
strm.avail_out = sizeof(buf);
704
} while (BZ_STREAM_END != rc);
706
BZ2_bzDecompressEnd(&strm);
708
if(ret == CL_VIRUS) {
710
if(!ctx->engine->keeptmp)
711
if (cli_unlink(tmpname)) ret = CL_EUNLINK;
716
if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
717
cli_dbgmsg("Bzip: Infected with %s\n", cli_get_last_virus(ctx));
720
if(!ctx->engine->keeptmp)
721
if (cli_unlink(tmpname)) ret = CL_EUNLINK;
728
static int cli_scanxz(cli_ctx *ctx)
730
int ret = CL_CLEAN, fd, rc;
731
unsigned long int size = 0;
738
buf = cli_malloc(CLI_XZ_OBUF_SIZE);
740
cli_errmsg("cli_scanxz: nomemory for decompress buffer.\n");
743
memset(&strm, 0x00, sizeof(struct CLI_XZ));
745
strm.avail_out = CLI_XZ_OBUF_SIZE;
746
rc = cli_XzInit(&strm);
747
if (rc != XZ_RESULT_OK) {
748
cli_errmsg("cli_scanxz: DecompressInit failed: %i\n", rc);
753
if ((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd))) {
754
cli_errmsg("cli_scanxz: Can't generate temporary file.\n");
755
cli_XzShutdown(&strm);
759
cli_dbgmsg("cli_scanxz: decompressing to file %s\n", tmpname);
762
/* set up input buffer */
763
if (!strm.avail_in) {
764
strm.next_in = (void*)fmap_need_off_once_len(*ctx->fmap, off, CLI_XZ_IBUF_SIZE, &avail);
765
strm.avail_in = avail;
767
if (!strm.avail_in) {
768
cli_errmsg("cli_scanxz: premature end of compressed stream\n");
774
/* xz decompress a chunk */
775
rc = cli_XzDecode(&strm);
776
if (XZ_RESULT_OK != rc && XZ_STREAM_END != rc) {
777
cli_errmsg("cli_scanxz: decompress error: %d\n", rc);
781
//cli_dbgmsg("cli_scanxz: xz decompressed %li of %li available bytes\n",
782
// avail - strm.avail_in, avail);
784
/* write decompress buffer */
785
if (!strm.avail_out || rc == XZ_STREAM_END) {
786
size_t towrite = CLI_XZ_OBUF_SIZE - strm.avail_out;
789
//cli_dbgmsg("Writing %li bytes to XZ decompress temp file(%li byte total)\n",
792
if((size_t)cli_writen(fd, buf, towrite) != towrite) {
793
cli_errmsg("cli_scanxz: Can't write to file.\n");
797
if (cli_checklimits("cli_scanxz", ctx, size, 0, 0) != CL_CLEAN) {
798
cli_warnmsg("cli_scanxz: decompress file size exceeds limits - "
799
"only scanning %li bytes\n", size);
803
strm.avail_out = CLI_XZ_OBUF_SIZE;
805
} while (XZ_STREAM_END != rc);
807
/* scan decompressed file */
808
if ((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
809
cli_dbgmsg("cli_scanxz: Infected with %s\n", cli_get_last_virus(ctx));
813
cli_XzShutdown(&strm);
815
if(!ctx->engine->keeptmp)
816
if (cli_unlink(tmpname) && ret == CL_CLEAN)
823
static int cli_scanszdd(cli_ctx *ctx)
829
cli_dbgmsg("in cli_scanszdd()\n");
831
if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &ofd))) {
832
cli_dbgmsg("MSEXPAND: Can't generate temporary file/descriptor\n");
836
ret = cli_msexpand(ctx, ofd);
838
if(ret != CL_SUCCESS) { /* CL_VIRUS or some error */
840
if(!ctx->engine->keeptmp)
841
if (cli_unlink(tmpname)) ret = CL_EUNLINK;
846
cli_dbgmsg("MSEXPAND: Decompressed into %s\n", tmpname);
847
ret = cli_magic_scandesc(ofd, ctx);
849
if(!ctx->engine->keeptmp)
850
if (cli_unlink(tmpname)) ret = CL_EUNLINK;
856
static int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset)
860
unsigned int files = 0;
861
struct cab_archive cab;
862
struct cab_file *file;
863
unsigned int corrupted_input;
864
unsigned int viruses_found = 0;
866
cli_dbgmsg("in cli_scanmscab()\n");
868
if((ret = cab_open(*ctx->fmap, sfx_offset, &cab)))
871
for(file = cab.files; file; file = file->next) {
874
if(cli_matchmeta(ctx, file->name, 0, file->length, 0, files, 0, NULL) == CL_VIRUS) {
882
if(ctx->engine->maxscansize && ctx->scansize >= ctx->engine->maxscansize) {
887
if(!(tempname = cli_gentemp(ctx->engine->tmpdir))) {
892
if(ctx->engine->maxscansize && ctx->scansize + ctx->engine->maxfilesize >= ctx->engine->maxscansize)
893
file->max_size = ctx->engine->maxscansize - ctx->scansize;
895
file->max_size = ctx->engine->maxfilesize ? ctx->engine->maxfilesize : 0xffffffff;
897
cli_dbgmsg("CAB: Extracting file %s to %s, size %u, max_size: %u\n", file->name, tempname, file->length, (unsigned int) file->max_size);
898
file->written_size = 0;
899
if((ret = cab_extract(file, tempname))) {
900
cli_dbgmsg("CAB: Failed to extract file: %s\n", cl_strerror(ret));
902
corrupted_input = ctx->corrupted_input;
903
if(file->length != file->written_size) {
904
cli_dbgmsg("CAB: Length from header %u but wrote %u bytes\n", (unsigned int) file->length, (unsigned int) file->written_size);
905
ctx->corrupted_input = 1;
907
ret = cli_scanfile(tempname, ctx);
908
ctx->corrupted_input = corrupted_input;
910
if(!ctx->engine->keeptmp) {
911
if (!access(tempname, R_OK) && cli_unlink(tempname)) {
918
if(ret == CL_VIRUS) {
932
static int vba_scandata(const unsigned char *data, unsigned int len, cli_ctx *ctx)
934
struct cli_matcher *groot = ctx->engine->root[0];
935
struct cli_matcher *troot = ctx->engine->root[2];
936
struct cli_ac_data gmdata, tmdata;
937
struct cli_ac_data *mdata[2];
939
unsigned int viruses_found = 0;
941
if((ret = cli_ac_initdata(&tmdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
944
if((ret = cli_ac_initdata(&gmdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) {
945
cli_ac_freedata(&tmdata);
951
ret = cli_scanbuff(data, len, 0, ctx, CL_TYPE_MSOLE2, mdata);
955
if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
956
ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL);
960
if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL))
961
ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL);
963
cli_ac_freedata(&tmdata);
964
cli_ac_freedata(&gmdata);
966
return (ret != CL_CLEAN)?ret:viruses_found?CL_VIRUS:CL_CLEAN;
969
static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
971
int ret = CL_CLEAN, i, j, fd, data_len, hasmacros = 0;
972
vba_project_t *vba_project;
975
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
978
char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
982
char *fullname, vbaname[1024];
986
unsigned int viruses_found = 0;
989
cli_dbgmsg("VBADir: %s\n", dirname);
990
hashcnt = uniq_get(U, "_vba_project", 12, NULL);
992
if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue;
994
for(i = 0; i < vba_project->count; i++) {
995
for(j = 0; (unsigned int)j < vba_project->colls[i]; j++) {
996
snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", vba_project->dir, vba_project->name[i], j);
997
vbaname[sizeof(vbaname)-1] = '\0';
998
fd = open(vbaname, O_RDONLY|O_BINARY);
999
if(fd == -1) continue;
1000
cli_dbgmsg("VBADir: Decompress VBA project '%s_%u'\n", vba_project->name[i], j);
1001
data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
1005
cli_dbgmsg("VBADir: WARNING: VBA project '%s_%u' decompressed to NULL\n", vba_project->name[i], j);
1007
/* cli_dbgmsg("Project content:\n%s", data); */
1009
*ctx->scanned += data_len / CL_COUNT_PRECISION;
1010
if(vba_scandata(data, data_len, ctx) == CL_VIRUS) {
1024
free(vba_project->name);
1025
free(vba_project->colls);
1026
free(vba_project->dir);
1027
free(vba_project->offset);
1029
if (ret == CL_VIRUS && !SCAN_ALL)
1033
if((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) &&
1034
(hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
1036
snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
1037
vbaname[sizeof(vbaname)-1] = '\0';
1038
fd = open(vbaname, O_RDONLY|O_BINARY);
1039
if (fd == -1) continue;
1040
if ((fullname = cli_ppt_vba_read(fd, ctx))) {
1041
if(cli_scandir(fullname, ctx) == CL_VIRUS) {
1045
if(!ctx->engine->keeptmp)
1046
cli_rmdirs(fullname);
1053
if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) &&
1054
(hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
1056
snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
1057
vbaname[sizeof(vbaname)-1] = '\0';
1058
fd = open(vbaname, O_RDONLY|O_BINARY);
1059
if (fd == -1) continue;
1061
if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) {
1066
for (i = 0; i < vba_project->count; i++) {
1067
cli_dbgmsg("VBADir: Decompress WM project macro:%d key:%d length:%d\n", i, vba_project->key[i], vba_project->length[i]);
1068
data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]);
1070
cli_dbgmsg("VBADir: WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i);
1072
cli_dbgmsg("Project content:\n%s", data);
1074
*ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION;
1075
if(vba_scandata(data, vba_project->length[i], ctx) == CL_VIRUS) {
1089
free(vba_project->name);
1090
free(vba_project->colls);
1091
free(vba_project->dir);
1092
free(vba_project->offset);
1093
free(vba_project->key);
1094
free(vba_project->length);
1096
if(ret == CL_VIRUS) {
1105
if(ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
1109
/* JSON Output Summary Information */
1110
if (ctx->options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL) {
1111
hashcnt = uniq_get(U, "_5_summaryinformation", 21, &hash);
1113
snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
1114
vbaname[sizeof(vbaname)-1] = '\0';
1116
fd = open(vbaname, O_RDONLY|O_BINARY);
1118
cli_dbgmsg("VBADir: detected a '_5_summaryinformation' stream\n");
1119
/* JSONOLE2 - what to do if something breaks? */
1120
cli_ole2_summary_json(ctx, fd, 0);
1125
hashcnt = uniq_get(U, "_5_documentsummaryinformation", 29, &hash);
1127
snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
1128
vbaname[sizeof(vbaname)-1] = '\0';
1130
fd = open(vbaname, O_RDONLY|O_BINARY);
1132
cli_dbgmsg("VBADir: detected a '_5_documentsummaryinformation' stream\n");
1133
/* JSONOLE2 - what to do if something breaks? */
1134
cli_ole2_summary_json(ctx, fd, 1);
1141
/* Check directory for embedded OLE objects */
1142
hashcnt = uniq_get(U, "_1_ole10native", 14, &hash);
1144
snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
1145
vbaname[sizeof(vbaname)-1] = '\0';
1147
fd = open(vbaname, O_RDONLY|O_BINARY);
1149
ret = cli_scan_ole10(fd, ctx);
1151
if(ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
1157
/* ACAB: since we now hash filenames and handle collisions we
1158
* could avoid recursion by removing the block below and by
1159
* flattening the paths in ole2_walk_property_tree (case 1) */
1161
if((dd = opendir(dirname)) != NULL) {
1162
#ifdef HAVE_READDIR_R_3
1163
while(!readdir_r(dd, &result.d, &dent) && dent) {
1164
#elif defined(HAVE_READDIR_R_2)
1165
while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
1167
while((dent = readdir(dd))) {
1171
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
1172
/* build the full name */
1173
fullname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
1175
cli_dbgmsg("cli_vba_scandir: Unable to allocate memory for fullname\n");
1179
sprintf(fullname, "%s"PATHSEP"%s", dirname, dent->d_name);
1182
if(LSTAT(fullname, &statbuf) != -1) {
1183
if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
1184
if (cli_vba_scandir(fullname, ctx, U) == CL_VIRUS) {
1199
cli_dbgmsg("VBADir: Can't open directory %s.\n", dirname);
1205
if (hasmacros && ctx->options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL)
1206
cli_jsonbool(ctx->wrkproperty, "HasMacros", 1);
1208
if(BLOCK_MACROS && hasmacros) {
1209
cli_append_virus(ctx, "Heuristics.OLE2.ContainsMacros");
1213
if (SCAN_ALL && viruses_found)
1218
static int cli_scanhtml(cli_ctx *ctx)
1220
char *tempname, fullname[1024];
1221
int ret=CL_CLEAN, fd;
1222
fmap_t *map = *ctx->fmap;
1223
unsigned int viruses_found = 0;
1224
uint64_t curr_len = map->len;
1226
cli_dbgmsg("in cli_scanhtml()\n");
1228
/* CL_ENGINE_MAX_HTMLNORMALIZE */
1229
if(curr_len > ctx->engine->maxhtmlnormalize) {
1230
cli_dbgmsg("cli_scanhtml: exiting (file larger than MaxHTMLNormalize)\n");
1234
if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
1237
if(mkdir(tempname, 0700)) {
1238
cli_errmsg("cli_scanhtml: Can't create temporary directory %s\n", tempname);
1243
cli_dbgmsg("cli_scanhtml: using tempdir %s\n", tempname);
1245
html_normalise_map(map, tempname, NULL, ctx->dconf);
1246
snprintf(fullname, 1024, "%s"PATHSEP"nocomment.html", tempname);
1247
fd = open(fullname, O_RDONLY|O_BINARY);
1249
if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
1254
if(ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
1255
/* CL_ENGINE_MAX_HTMLNOTAGS */
1256
curr_len = map->len;
1257
if (curr_len > ctx->engine->maxhtmlnotags) {
1258
/* we're not interested in scanning large files in notags form */
1259
/* TODO: don't even create notags if file is over limit */
1260
cli_dbgmsg("cli_scanhtml: skipping notags (normalized size over MaxHTMLNoTags)\n");
1263
snprintf(fullname, 1024, "%s"PATHSEP"notags.html", tempname);
1264
fd = open(fullname, O_RDONLY|O_BINARY);
1266
if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
1273
if(ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
1274
snprintf(fullname, 1024, "%s"PATHSEP"javascript", tempname);
1275
fd = open(fullname, O_RDONLY|O_BINARY);
1277
if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
1279
if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
1280
if ((ret = cli_scandesc(fd, ctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
1287
if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
1288
snprintf(fullname, 1024, "%s"PATHSEP"rfc2397", tempname);
1289
ret = cli_scandir(fullname, ctx);
1292
if(!ctx->engine->keeptmp)
1293
cli_rmdirs(tempname);
1296
if (SCAN_ALL && viruses_found)
1301
static int cli_scanscript(cli_ctx *ctx)
1303
const unsigned char *buff;
1304
unsigned char* normalized;
1305
struct text_norm_state state;
1306
char *tmpname = NULL;
1308
struct cli_matcher *troot;
1309
uint32_t maxpatlen, offset = 0;
1310
struct cli_matcher *groot;
1311
struct cli_ac_data gmdata, tmdata;
1312
struct cli_ac_data *mdata[2];
1315
unsigned int viruses_found = 0;
1317
struct cli_target_info info;
1319
if (!ctx || !ctx->engine->root)
1323
curr_len = map->len;
1324
groot = ctx->engine->root[0];
1325
troot = ctx->engine->root[7];
1326
maxpatlen = troot ? troot->maxpatlen : 0;
1328
cli_dbgmsg("in cli_scanscript()\n");
1330
/* CL_ENGINE_MAX_SCRIPTNORMALIZE */
1331
if(curr_len > ctx->engine->maxscriptnormalize) {
1332
cli_dbgmsg("cli_scanscript: exiting (file larger than MaxScriptSize)\n");
1336
/* dump to disk only if explicitly asked to,
1337
* otherwise we can process just in-memory */
1338
if(ctx->engine->keeptmp) {
1339
if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &ofd))) {
1340
cli_dbgmsg("cli_scanscript: Can't generate temporary file/descriptor\n");
1343
cli_dbgmsg("cli_scanscript: saving normalized file to %s\n", tmpname);
1346
if(!(normalized = cli_malloc(SCANBUFF + maxpatlen))) {
1347
cli_dbgmsg("cli_scanscript: Unable to malloc %u bytes\n", SCANBUFF);
1352
text_normalize_init(&state, normalized, SCANBUFF + maxpatlen);
1355
if ((ret = cli_ac_initdata(&tmdata, troot?troot->ac_partsigs:0, troot?troot->ac_lsigs:0, troot?troot->ac_reloff_num:0, CLI_DEFAULT_AC_TRACKLEN))) {
1361
cli_targetinfo(&info, 7, map);
1362
ret = cli_ac_caloff(troot, &tmdata, &info);
1364
cli_ac_freedata(&tmdata);
1370
if ((ret = cli_ac_initdata(&gmdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) {
1371
cli_ac_freedata(&tmdata);
1379
size_t len = MIN(map->pgsz, map->len - at);
1380
buff = fmap_need_off_once(map, at, len);
1382
if(!buff || !len || state.out_pos + len > state.out_len) {
1383
/* flush if error/EOF, or too little buffer space left */
1384
if((ofd != -1) && (write(ofd, state.out, state.out_pos) == -1)) {
1385
cli_errmsg("cli_scanscript: can't write to file %s\n",tmpname);
1388
/* we can continue to scan in memory */
1390
/* when we flush the buffer also scan */
1391
if(cli_scanbuff(state.out, state.out_pos, offset, ctx, CL_TYPE_TEXT_ASCII, mdata) == CL_VIRUS) {
1400
*ctx->scanned += state.out_pos / CL_COUNT_PRECISION;
1401
offset += state.out_pos;
1402
/* carry over maxpatlen from previous buffer */
1403
if (state.out_pos > maxpatlen)
1404
memmove(state.out, state.out + state.out_pos - maxpatlen, maxpatlen);
1405
text_normalize_reset(&state);
1406
state.out_pos = maxpatlen;
1409
if(!buff || text_normalize_buffer(&state, buff, len) != len) {
1410
cli_dbgmsg("cli_scanscript: short read during normalizing\n");
1413
if(ctx->engine->keeptmp) {
1419
if(ret != CL_VIRUS || SCAN_ALL) {
1420
if ((ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL)) == CL_VIRUS)
1422
if(ret != CL_VIRUS || SCAN_ALL)
1423
if ((ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL)) == CL_VIRUS)
1426
cli_ac_freedata(&tmdata);
1427
cli_ac_freedata(&gmdata);
1429
if (SCAN_ALL && viruses_found)
1434
static int cli_scanhtml_utf16(cli_ctx *ctx)
1436
char *tempname, *decoded;
1438
int ret = CL_CLEAN, fd, bytes;
1440
fmap_t *map = *ctx->fmap;
1442
cli_dbgmsg("in cli_scanhtml_utf16()\n");
1444
if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
1447
if((fd = open(tempname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
1448
cli_errmsg("cli_scanhtml_utf16: Can't create file %s\n", tempname);
1453
cli_dbgmsg("cli_scanhtml_utf16: using tempfile %s\n", tempname);
1455
while(at < map->len) {
1456
bytes = MIN(map->len - at, map->pgsz * 16);
1457
if(!(buff = fmap_need_off_once(map, at, bytes))) {
1459
cli_unlink(tempname);
1464
decoded = cli_utf16toascii(buff, bytes);
1466
if(write(fd, decoded, bytes / 2) == -1) {
1467
cli_errmsg("cli_scanhtml_utf16: Can't write to file %s\n", tempname);
1470
cli_unlink(tempname);
1478
*ctx->fmap = fmap(fd, 0, 0);
1480
ret = cli_scanhtml(ctx);
1483
cli_errmsg("cli_scanhtml_utf16: fmap of %s failed\n", tempname);
1488
if(!ctx->engine->keeptmp) {
1489
if (cli_unlink(tempname)) ret = CL_EUNLINK;
1491
cli_dbgmsg("cli_scanhtml_utf16: Decoded HTML data saved in %s\n", tempname);
1497
static int cli_scanole2(cli_ctx *ctx)
1501
struct uniq *vba = NULL;
1503
cli_dbgmsg("in cli_scanole2()\n");
1505
if(ctx->engine->maxreclevel && ctx->recursion >= ctx->engine->maxreclevel)
1508
/* generate the temporary directory */
1509
if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1512
if(mkdir(dir, 0700)) {
1513
cli_dbgmsg("OLE2: Can't create temporary directory %s\n", dir);
1518
ret = cli_ole2_extract(dir, ctx, &vba);
1519
if(ret!=CL_CLEAN && ret!=CL_VIRUS) {
1520
cli_dbgmsg("OLE2: %s\n", cl_strerror(ret));
1521
if(!ctx->engine->keeptmp)
1530
ret = cli_vba_scandir(dir, ctx, vba);
1533
if(cli_scandir(dir, ctx) == CL_VIRUS)
1538
if(!ctx->engine->keeptmp)
1544
static int cli_scantar(cli_ctx *ctx, unsigned int posix)
1550
cli_dbgmsg("in cli_scantar()\n");
1552
/* generate temporary directory */
1553
if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1556
if(mkdir(dir, 0700)) {
1557
cli_errmsg("Tar: Can't create temporary directory %s\n", dir);
1562
ret = cli_untar(dir, posix, ctx);
1564
if(!ctx->engine->keeptmp)
1571
static int cli_scanmschm(cli_ctx *ctx)
1573
int ret = CL_CLEAN, rc;
1574
chm_metadata_t metadata;
1576
unsigned int viruses_found = 0;
1578
cli_dbgmsg("in cli_scanmschm()\n");
1580
/* generate the temporary directory */
1581
if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1584
if(mkdir(dir, 0700)) {
1585
cli_dbgmsg("CHM: Can't create temporary directory %s\n", dir);
1590
ret = cli_chm_open(dir, &metadata, ctx);
1591
if (ret != CL_SUCCESS) {
1592
if(!ctx->engine->keeptmp)
1595
cli_dbgmsg("CHM: Error: %s\n", cl_strerror(ret));
1600
ret = cli_chm_prepare_file(&metadata);
1601
if (ret != CL_SUCCESS) {
1604
ret = cli_chm_extract_file(dir, &metadata, ctx);
1605
if (ret == CL_SUCCESS) {
1606
rc = cli_magic_scandesc(metadata.ofd, ctx);
1607
close(metadata.ofd);
1608
if (rc == CL_VIRUS) {
1609
cli_dbgmsg("CHM: infected with %s\n", cli_get_last_virus(ctx));
1619
} while(ret == CL_SUCCESS);
1621
cli_chm_close(&metadata);
1623
if(!ctx->engine->keeptmp)
1628
cli_dbgmsg("CHM: Exit code: %d\n", ret);
1629
if (ret == CL_BREAK)
1632
if (SCAN_ALL && viruses_found)
1637
static int cli_scanscrenc(cli_ctx *ctx)
1642
cli_dbgmsg("in cli_scanscrenc()\n");
1644
if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
1647
if(mkdir(tempname, 0700)) {
1648
cli_dbgmsg("CHM: Can't create temporary directory %s\n", tempname);
1653
if (html_screnc_decode(*ctx->fmap, tempname))
1654
ret = cli_scandir(tempname, ctx);
1656
if(!ctx->engine->keeptmp)
1657
cli_rmdirs(tempname);
1663
static int cli_scanriff(cli_ctx *ctx)
1667
if(cli_check_riff_exploit(ctx) == 2) {
1669
cli_append_virus(ctx, "Heuristics.Exploit.W32.MS05-002");
1675
static int cli_scanjpeg(cli_ctx *ctx)
1679
if(cli_check_jpeg_exploit(ctx, 0) == 1) {
1681
cli_append_virus(ctx, "Heuristics.Exploit.W32.MS04-028");
1687
static int cli_scancryptff(cli_ctx *ctx)
1689
int ret = CL_CLEAN, ndesc;
1691
const unsigned char *src;
1692
unsigned char *dest = NULL;
1698
/* Skip the CryptFF file header */
1701
if((dest = (unsigned char *) cli_malloc(FILEBUFF)) == NULL) {
1702
cli_dbgmsg("CryptFF: Can't allocate memory\n");
1706
if(!(tempfile = cli_gentemp(ctx->engine->tmpdir))) {
1711
if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
1712
cli_errmsg("CryptFF: Can't create file %s\n", tempfile);
1718
for(; (src = fmap_need_off_once_len(*ctx->fmap, pos, FILEBUFF, &bread)) && bread; pos += bread) {
1719
for (i=0;i<bread;i++)
1720
dest[i] = src[i] ^ (unsigned char) 0xff;
1721
if(cli_writen(ndesc, dest, bread) == -1) {
1722
cli_dbgmsg("CryptFF: Can't write to descriptor %d\n", ndesc);
1733
cli_dbgmsg("CryptFF: Scanning decrypted data\n");
1735
if((ret = cli_magic_scandesc(ndesc, ctx)) == CL_VIRUS)
1736
cli_dbgmsg("CryptFF: Infected with %s\n", cli_get_last_virus(ctx));
1740
if(ctx->engine->keeptmp)
1741
cli_dbgmsg("CryptFF: Decompressed data saved in %s\n", tempfile);
1743
if (cli_unlink(tempfile)) ret = CL_EUNLINK;
1749
static int cli_scanpdf(cli_ctx *ctx, off_t offset)
1752
char *dir = cli_gentemp(ctx->engine->tmpdir);
1757
if(mkdir(dir, 0700)) {
1758
cli_dbgmsg("Can't create temporary directory for PDF file %s\n", dir);
1763
ret = cli_pdf(dir, ctx, offset);
1765
if(!ctx->engine->keeptmp)
1772
static int cli_scantnef(cli_ctx *ctx)
1775
char *dir = cli_gentemp(ctx->engine->tmpdir);
1780
if(mkdir(dir, 0700)) {
1781
cli_dbgmsg("Can't create temporary directory for tnef file %s\n", dir);
1786
ret = cli_tnef(dir, ctx);
1789
ret = cli_scandir(dir, ctx);
1791
if(!ctx->engine->keeptmp)
1798
static int cli_scanuuencoded(cli_ctx *ctx)
1801
char *dir = cli_gentemp(ctx->engine->tmpdir);
1806
if(mkdir(dir, 0700)) {
1807
cli_dbgmsg("Can't create temporary directory for uuencoded file %s\n", dir);
1812
ret = cli_uuencode(dir, *ctx->fmap);
1815
ret = cli_scandir(dir, ctx);
1817
if(!ctx->engine->keeptmp)
1824
static int cli_scanmail(cli_ctx *ctx)
1828
unsigned int viruses_found = 0;
1830
cli_dbgmsg("Starting cli_scanmail(), recursion = %u\n", ctx->recursion);
1832
/* generate the temporary directory */
1833
if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1836
if(mkdir(dir, 0700)) {
1837
cli_dbgmsg("Mail: Can't create temporary directory %s\n", dir);
1843
* Extract the attachments into the temporary directory
1845
if((ret = cli_mbox(dir, ctx))) {
1846
if (ret == CL_VIRUS && SCAN_ALL)
1849
if(!ctx->engine->keeptmp)
1856
ret = cli_scandir(dir, ctx);
1858
if(!ctx->engine->keeptmp)
1862
if (SCAN_ALL && viruses_found)
1867
static int cli_scan_structured(cli_ctx *ctx)
1871
unsigned int cc_count = 0;
1872
unsigned int ssn_count = 0;
1876
int (*ccfunc)(const unsigned char *buffer, int length);
1877
int (*ssnfunc)(const unsigned char *buffer, int length);
1878
unsigned int viruses_found = 0;
1885
if(ctx->engine->min_cc_count == 1)
1886
ccfunc = dlp_has_cc;
1888
ccfunc = dlp_get_cc_count;
1890
switch((ctx->options & CL_SCAN_STRUCTURED_SSN_NORMAL) | (ctx->options & CL_SCAN_STRUCTURED_SSN_STRIPPED)) {
1892
case (CL_SCAN_STRUCTURED_SSN_NORMAL | CL_SCAN_STRUCTURED_SSN_STRIPPED):
1893
if(ctx->engine->min_ssn_count == 1)
1894
ssnfunc = dlp_has_ssn;
1896
ssnfunc = dlp_get_ssn_count;
1899
case CL_SCAN_STRUCTURED_SSN_NORMAL:
1900
if(ctx->engine->min_ssn_count == 1)
1901
ssnfunc = dlp_has_normal_ssn;
1903
ssnfunc = dlp_get_normal_ssn_count;
1906
case CL_SCAN_STRUCTURED_SSN_STRIPPED:
1907
if(ctx->engine->min_ssn_count == 1)
1908
ssnfunc = dlp_has_stripped_ssn;
1910
ssnfunc = dlp_get_stripped_ssn_count;
1917
while(!done && ((result = fmap_readn(map, buf, pos, 8191)) > 0)) {
1919
if((cc_count += ccfunc((const unsigned char *)buf, result)) >= ctx->engine->min_cc_count)
1922
if(ssnfunc && ((ssn_count += ssnfunc((const unsigned char *)buf, result)) >= ctx->engine->min_ssn_count))
1926
if(cc_count != 0 && cc_count >= ctx->engine->min_cc_count) {
1927
cli_dbgmsg("cli_scan_structured: %u credit card numbers detected\n", cc_count);
1928
cli_append_virus(ctx,"Heuristics.Structured.CreditCardNumber");
1935
if(ssn_count != 0 && ssn_count >= ctx->engine->min_ssn_count) {
1936
cli_dbgmsg("cli_scan_structured: %u social security numbers detected\n", ssn_count);
1937
cli_append_virus(ctx,"Heuristics.Structured.SSN");
1944
if (SCAN_ALL && viruses_found)
1949
static int cli_scanembpe(cli_ctx *ctx, off_t offset)
1951
int fd, bytes, ret = CL_CLEAN;
1952
unsigned long int size = 0, todo;
1955
fmap_t *map = *ctx->fmap;
1956
unsigned int corrupted_input;
1958
tmpname = cli_gentemp(ctx->engine->tmpdir);
1962
if((fd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
1963
cli_errmsg("cli_scanembpe: Can't create file %s\n", tmpname);
1968
todo = map->len - offset;
1970
bytes = MIN(todo, map->pgsz);
1974
if(!(buff = fmap_need_off_once(map, offset + size, bytes))) {
1976
if(!ctx->engine->keeptmp) {
1977
if (cli_unlink(tmpname)) {
1988
if(cli_checklimits("cli_scanembpe", ctx, size, 0, 0)!=CL_CLEAN)
1991
if(cli_writen(fd, buff, bytes) != bytes) {
1992
cli_dbgmsg("cli_scanembpe: Can't write to temporary file\n");
1994
if(!ctx->engine->keeptmp) {
1995
if (cli_unlink(tmpname)) {
2006
corrupted_input = ctx->corrupted_input;
2007
ctx->corrupted_input = 1;
2008
ret = cli_magic_scandesc(fd, ctx);
2009
ctx->corrupted_input = corrupted_input;
2010
if(ret == CL_VIRUS) {
2011
cli_dbgmsg("cli_scanembpe: Infected with %s\n", cli_get_last_virus(ctx));
2013
if(!ctx->engine->keeptmp) {
2014
if (cli_unlink(tmpname)) {
2025
if(!ctx->engine->keeptmp) {
2026
if (cli_unlink(tmpname)) {
2033
/* intentionally ignore possible errors from cli_magic_scandesc */
2038
#if defined(_WIN32) || defined(C_LINUX)
2039
#define PERF_MEASURE
2049
{PERFT_SCAN, "full scan", ev_time},
2050
{PERFT_PRECB, "prescan cb", ev_time},
2051
{PERFT_POSTCB, "postscan cb", ev_time},
2052
{PERFT_CACHE, "cache", ev_time},
2053
{PERFT_FT, "filetype", ev_time},
2054
{PERFT_CONTAINER, "container", ev_time},
2055
{PERFT_SCRIPT, "script", ev_time},
2056
{PERFT_PE, "pe", ev_time},
2057
{PERFT_RAW, "raw", ev_time},
2058
{PERFT_RAWTYPENO, "raw container", ev_time},
2059
{PERFT_MAP, "map", ev_time},
2060
{PERFT_BYTECODE,"bytecode", ev_time},
2061
{PERFT_KTIME,"kernel", ev_int},
2062
{PERFT_UTIME,"user", ev_int}
2065
static void get_thread_times(uint64_t *kt, uint64_t *ut)
2069
ULARGE_INTEGER kl,ul;
2070
if (!GetThreadTimes(GetCurrentThread(), &c, &e, &k, &u)) {
2074
kl.LowPart = k.dwLowDateTime;
2075
kl.HighPart = k.dwHighDateTime;
2076
ul.LowPart = u.dwLowDateTime;
2077
ul.HighPart = u.dwHighDateTime;
2078
*kt = kl.QuadPart / 10;
2079
*ut = ul.QuadPart / 10;
2082
if (times(&tbuf) != -1) {
2083
clock_t tck = sysconf(_SC_CLK_TCK);
2084
*kt = ((uint64_t)1000000)*tbuf.tms_stime / tck;
2085
*ut = ((uint64_t)1000000)*tbuf.tms_utime / tck;
2092
static inline void perf_init(cli_ctx *ctx)
2097
if (!(ctx->options & CL_SCAN_PERFORMANCE_INFO))
2100
ctx->perf = cli_events_new(PERFT_LAST);
2101
for (i=0;i<sizeof(perf_events)/sizeof(perf_events[0]);i++) {
2102
if (cli_event_define(ctx->perf, perf_events[i].id, perf_events[i].name,
2103
perf_events[i].type, multiple_sum) == -1)
2106
cli_event_time_start(ctx->perf, PERFT_SCAN);
2107
get_thread_times(&kt, &ut);
2108
cli_event_int(ctx->perf, PERFT_KTIME, -kt);
2109
cli_event_int(ctx->perf, PERFT_UTIME, -ut);
2112
static inline void perf_done(cli_ctx* ctx)
2119
cli_events_t *perf = ctx->perf;
2125
pend = timestr + sizeof(timestr) - 1;
2128
cli_event_time_stop(perf, PERFT_SCAN);
2129
get_thread_times(&kt, &ut);
2130
cli_event_int(perf, PERFT_KTIME, kt);
2131
cli_event_int(perf, PERFT_UTIME, ut);
2133
for (i=0;i<sizeof(perf_events)/sizeof(perf_events[0]);i++) {
2137
cli_event_get(perf, perf_events[i].id, &val, &count);
2139
p += snprintf(p, pend - p, "%s: %d.%03ums, ", perf_events[i].name,
2140
(signed)(val.v_int / 1000),
2141
(unsigned)(val.v_int % 1000));
2144
cli_infomsg(ctx, "performance: %s\n", timestr);
2147
cli_events_free(perf);
2151
static inline void perf_start(cli_ctx* ctx, int id)
2153
cli_event_time_start(ctx->perf, id);
2156
static inline void perf_stop(cli_ctx* ctx, int id)
2158
cli_event_time_stop(ctx->perf, id);
2161
static inline void perf_nested_start(cli_ctx* ctx, int id, int nestedid)
2163
cli_event_time_nested_start(ctx->perf, id, nestedid);
2166
static inline void perf_nested_stop(cli_ctx* ctx, int id, int nestedid)
2168
cli_event_time_nested_stop(ctx->perf, id, nestedid);
2173
static inline void perf_init(cli_ctx* ctx) { UNUSEDPARAM(ctx); }
2174
static inline void perf_start(cli_ctx* ctx, int id){ UNUSEDPARAM(ctx); UNUSEDPARAM(id); }
2175
static inline void perf_stop(cli_ctx* ctx, int id){ UNUSEDPARAM(ctx); UNUSEDPARAM(id); }
2176
static inline void perf_nested_start(cli_ctx* ctx, int id, int nestedid){ UNUSEDPARAM(ctx); UNUSEDPARAM(id); UNUSEDPARAM(nestedid); }
2177
static inline void perf_nested_stop(cli_ctx* ctx, int id, int nestedid){ UNUSEDPARAM(ctx); UNUSEDPARAM(id); UNUSEDPARAM(nestedid); }
2178
static inline void perf_done(cli_ctx* ctx){ UNUSEDPARAM(ctx); }
2182
static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_t *dettype, unsigned char *refhash)
2184
int ret = CL_CLEAN, nret = CL_CLEAN;
2185
struct cli_matched_type *ftoffset = NULL, *fpt;
2187
struct cli_exe_info peinfo;
2188
unsigned int acmode = AC_SCAN_VIR, break_loop = 0;
2189
fmap_t *map = *ctx->fmap;
2190
cli_file_t current_container_type = ctx->container_type;
2191
size_t current_container_size = ctx->container_size;
2194
if(ctx->engine->maxreclevel && ctx->recursion >= ctx->engine->maxreclevel)
2197
perf_start(ctx, PERFT_RAW);
2199
acmode |= AC_SCAN_FT;
2201
ret = cli_fmap_scandesc(ctx, type == CL_TYPE_TEXT_ASCII ? 0 : type, 0, &ftoffset, acmode, NULL, refhash);
2202
perf_stop(ctx, PERFT_RAW);
2204
if(ret >= CL_TYPENO) {
2205
perf_nested_start(ctx, PERFT_RAWTYPENO, PERFT_SCAN);
2207
lastrar = 0xdeadbeef;
2211
if(fpt->offset) switch(fpt->type) {
2213
ret = cli_scanxdp(ctx);
2215
case CL_TYPE_RARSFX:
2216
if(type != CL_TYPE_RAR && have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR)) {
2217
char *tmpname = NULL;
2218
int tmpfd = fmap_fd(map);
2219
ctx->container_type = CL_TYPE_RAR;
2220
ctx->container_size = map->len - fpt->offset; /* not precise */
2221
cli_dbgmsg("RAR/RAR-SFX signature found at %u\n", (unsigned int) fpt->offset);
2222
/* if map is not file-backed, have to dump to file for scanrar */
2224
nret = fmap_dump_to_file(map, ctx->engine->tmpdir, &tmpname, &tmpfd);
2225
if(nret != CL_SUCCESS) {
2226
cli_dbgmsg("cli_scanraw: failed to generate temporary file.\n");
2232
/* scan existing file */
2233
nret = cli_scanrar(tmpfd, ctx, fpt->offset, &lastrar);
2234
/* if dumped tempfile, need to cleanup */
2237
if(!ctx->engine->keeptmp) {
2238
if (cli_unlink(tmpname)) {
2239
ret = nret = CL_EUNLINK;
2248
case CL_TYPE_ZIPSFX:
2249
if(type != CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP)) {
2250
ctx->container_type = CL_TYPE_ZIP;
2251
ctx->container_size = map->len - fpt->offset; /* not precise */
2252
cli_dbgmsg("ZIP/ZIP-SFX signature found at %u\n", (unsigned int) fpt->offset);
2253
nret = cli_unzip_single(ctx, fpt->offset);
2257
case CL_TYPE_CABSFX:
2258
if(type != CL_TYPE_MSCAB && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB)) {
2259
ctx->container_type = CL_TYPE_MSCAB;
2260
ctx->container_size = map->len - fpt->offset; /* not precise */
2261
cli_dbgmsg("CAB/CAB-SFX signature found at %u\n", (unsigned int) fpt->offset);
2262
nret = cli_scanmscab(ctx, fpt->offset);
2266
case CL_TYPE_ARJSFX:
2267
if(type != CL_TYPE_ARJ && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ)) {
2268
ctx->container_type = CL_TYPE_ARJ;
2269
ctx->container_size = map->len - fpt->offset; /* not precise */
2270
cli_dbgmsg("ARJ-SFX signature found at %u\n", (unsigned int) fpt->offset);
2271
nret = cli_scanarj(ctx, fpt->offset, &lastrar);
2276
if(type != CL_TYPE_7Z && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z)) {
2277
ctx->container_type = CL_TYPE_7Z;
2278
ctx->container_size = map->len - fpt->offset; /* not precise */
2279
cli_dbgmsg("7Zip-SFX signature found at %u\n", (unsigned int) fpt->offset);
2280
nret = cli_7unz(ctx, fpt->offset);
2284
case CL_TYPE_ISO9660:
2285
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ISO9660)) {
2286
ctx->container_type = CL_TYPE_ISO9660;
2287
ctx->container_size = map->len - fpt->offset; /* not precise */
2288
cli_dbgmsg("ISO9660 signature found at %u\n", (unsigned int) fpt->offset);
2289
nret = cli_scaniso(ctx, fpt->offset);
2293
case CL_TYPE_NULSFT:
2294
if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_NSIS) &&
2296
ctx->container_type = CL_TYPE_NULSFT;
2297
ctx->container_size = map->len - fpt->offset; /* not precise */
2298
cli_dbgmsg("NSIS signature found at %u\n", (unsigned int) fpt->offset-4);
2299
nret = cli_scannulsft(ctx, fpt->offset - 4);
2303
case CL_TYPE_AUTOIT:
2304
if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_AUTOIT)) {
2305
ctx->container_type = CL_TYPE_AUTOIT;
2306
ctx->container_size = map->len - fpt->offset; /* not precise */
2307
cli_dbgmsg("AUTOIT signature found at %u\n", (unsigned int) fpt->offset);
2308
nret = cli_scanautoit(ctx, fpt->offset + 23);
2312
case CL_TYPE_ISHIELD_MSI:
2313
if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_ISHIELD)) {
2314
ctx->container_type = CL_TYPE_AUTOIT;
2315
ctx->container_size = map->len - fpt->offset; /* not precise */
2316
cli_dbgmsg("ISHIELD-MSI signature found at %u\n", (unsigned int) fpt->offset);
2317
nret = cli_scanishield_msi(ctx, fpt->offset + 14);
2322
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_DMG)) {
2323
ctx->container_type = CL_TYPE_DMG;
2324
nret = cli_scandmg(ctx);
2325
cli_dbgmsg("DMG signature found at %u\n", (unsigned int) fpt->offset);
2331
int iret = cli_mbr_check2(ctx, 0);
2332
if (iret == CL_TYPE_GPT) {
2333
cli_dbgmsg("Recognized GUID Partition Table file\n");
2334
ctx->container_type = CL_TYPE_GPT;
2335
nret = cli_scangpt(ctx, 0);
2336
cli_dbgmsg("GPT signature found at %u\n", (unsigned int) fpt->offset);
2338
else if (iret == CL_CLEAN) {
2339
ctx->container_type = CL_TYPE_MBR;
2340
nret = cli_scanmbr(ctx, 0);
2341
cli_dbgmsg("MBR signature found at %u\n", (unsigned int) fpt->offset);
2347
if(type != CL_TYPE_PDF && SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF)) {
2348
ctx->container_type = CL_TYPE_PDF;
2349
ctx->container_size = map->len - fpt->offset; /* not precise */
2350
cli_dbgmsg("PDF signature found at %u\n", (unsigned int) fpt->offset);
2351
nret = cli_scanpdf(ctx, fpt->offset);
2356
if(SCAN_PE && (type == CL_TYPE_MSEXE || type == CL_TYPE_ZIP || type == CL_TYPE_MSOLE2)
2357
&& ctx->dconf->pe) {
2358
uint64_t curr_len = map->len;
2359
/* CL_ENGINE_MAX_EMBEDDED_PE */
2360
if(curr_len > ctx->engine->maxembeddedpe) {
2361
cli_dbgmsg("cli_scanraw: MaxEmbeddedPE exceeded\n");
2364
ctx->container_type = CL_TYPE_MSEXE; /* PE is a container for another executable here */
2365
ctx->container_size = map->len - fpt->offset; /* not precise */
2366
memset(&peinfo, 0, sizeof(struct cli_exe_info));
2367
peinfo.offset = fpt->offset;
2368
if(cli_peheader(map, &peinfo) == 0) {
2369
cli_dbgmsg("*** Detected embedded PE file at %u ***\n",
2370
(unsigned int) fpt->offset);
2372
free(peinfo.section);
2373
cli_hashset_destroy(&peinfo.vinfo);
2375
nret = cli_scanembpe(ctx, fpt->offset);
2376
break_loop = 1; /* we can stop here and other
2377
* embedded executables will
2378
* be found recursively
2379
* through the above call
2386
cli_warnmsg("cli_scanraw: Type %u not handled in fpt loop\n", fpt->type);
2389
if(nret == CL_VIRUS || break_loop)
2394
ctx->container_type = current_container_type;
2395
ctx->container_size = current_container_size;
2397
if(nret != CL_VIRUS) switch(ret) {
2399
if (SCAN_HTML && (type == CL_TYPE_TEXT_ASCII || type == CL_TYPE_GRAPHICS) &&
2400
(DCONF_DOC & DOC_CONF_HTML)) {
2401
*dettype = CL_TYPE_HTML;
2402
nret = cli_scanhtml(ctx);
2407
ctx->container_type = CL_TYPE_MAIL;
2408
ctx->container_size = map->len;
2409
if(SCAN_MAIL && type == CL_TYPE_TEXT_ASCII && (DCONF_MAIL & MAIL_CONF_MBOX)) {
2410
*dettype = CL_TYPE_MAIL;
2411
nret = cli_scanmail(ctx);
2413
ctx->container_type = current_container_type;
2414
ctx->container_size = current_container_size;
2420
perf_nested_stop(ctx, PERFT_RAWTYPENO, PERFT_SCAN);
2427
ftoffset = ftoffset->next;
2432
cli_dbgmsg("%s found\n", cli_get_last_virus(ctx));
2438
static void emax_reached(cli_ctx *ctx) {
2439
fmap_t **ctx_fmap = ctx->fmap;
2443
fmap_t *map = *ctx_fmap;
2444
map->dont_cache_flag = 1;
2447
cli_dbgmsg("emax_reached: marked parents as non cacheable\n");
2450
#define LINESTR(x) #x
2451
#define LINESTR2(x) LINESTR(x)
2452
#define __AT__ " at line "LINESTR2(__LINE__)
2454
#define early_ret_from_magicscan(retcode) \
2456
cli_dbgmsg("cli_magic_scandesc: returning %d %s (no post, no cache)\n", retcode, __AT__); \
2460
static int magic_scandesc_cleanup(cli_ctx *ctx, cli_file_t type, unsigned char *hash, size_t hashed_size, int cache_clean, int retcode, void *parent_property)
2463
ctx->wrkproperty = (struct json_object *)(parent_property);
2465
UNUSEDPARAM(parent_property);
2470
cli_dbgmsg("cli_magic_scandesc: returning %d %s\n", retcode, __AT__);
2471
if(ctx->engine->cb_post_scan) {
2472
perf_start(ctx, PERFT_POSTCB);
2473
switch(ctx->engine->cb_post_scan(fmap_fd(*ctx->fmap), retcode, retcode == CL_VIRUS ? cli_get_last_virus(ctx) : NULL, ctx->cb_ctx)) {
2475
cli_dbgmsg("cli_magic_scandesc: file whitelisted by post_scan callback\n");
2476
perf_stop(ctx, PERFT_POSTCB);
2479
cli_dbgmsg("cli_magic_scandesc: file blacklisted by post_scan callback\n");
2480
cli_append_virus(ctx, "Detected.By.Callback");
2481
perf_stop(ctx, PERFT_POSTCB);
2482
if (retcode != CL_VIRUS)
2483
return cli_checkfp(hash, hashed_size, ctx);
2488
cli_warnmsg("cli_magic_scandesc: ignoring bad return code from post_scan callback\n");
2490
perf_stop(ctx, PERFT_POSTCB);
2492
if (retcode == CL_CLEAN && cache_clean) {
2493
perf_start(ctx, PERFT_CACHE);
2494
cache_add(hash, hashed_size, ctx);
2495
perf_stop(ctx, PERFT_CACHE);
2500
static int dispatch_prescan(clcb_pre_scan cb, cli_ctx *ctx, const char *filetype, bitset_t *old_hook_lsig_matches, void *parent_property, unsigned char *hash, size_t hashed_size, int *run_cleanup)
2504
UNUSEDPARAM(parent_property);
2506
UNUSEDPARAM(hashed_size);
2511
perf_start(ctx, PERFT_PRECB);
2512
switch(cb(fmap_fd(*ctx->fmap), filetype, ctx->cb_ctx)) {
2514
cli_dbgmsg("cli_magic_scandesc: file whitelisted by callback\n");
2515
perf_stop(ctx, PERFT_PRECB);
2516
ctx->hook_lsig_matches = old_hook_lsig_matches;
2519
cli_dbgmsg("cli_magic_scandesc: file blacklisted by callback\n");
2520
cli_append_virus(ctx, "Detected.By.Callback");
2521
perf_stop(ctx, PERFT_PRECB);
2522
ctx->hook_lsig_matches = old_hook_lsig_matches;
2528
cli_warnmsg("cli_magic_scandesc: ignoring bad return code from callback\n");
2531
perf_stop(ctx, PERFT_PRECB);
2537
static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2540
cli_file_t dettype = 0;
2541
uint8_t typercg = 1;
2542
cli_file_t current_container_type = ctx->container_type;
2543
size_t current_container_size = ctx->container_size, hashed_size;
2544
unsigned char hash[16];
2545
bitset_t *old_hook_lsig_matches;
2546
const char *filetype;
2547
int cache_clean = 0, res;
2548
int run_cleanup = 0;
2550
struct json_object *parent_property = NULL;
2552
void *parent_property = NULL;
2556
cli_errmsg("CRITICAL: engine == NULL\n");
2557
early_ret_from_magicscan(CL_ENULLARG);
2560
if(!(ctx->engine->dboptions & CL_DB_COMPILED)) {
2561
cli_errmsg("CRITICAL: engine not compiled\n");
2562
early_ret_from_magicscan(CL_EMALFDB);
2565
if(ctx->engine->maxreclevel && ctx->recursion > ctx->engine->maxreclevel) {
2566
cli_dbgmsg("cli_magic_scandesc: Archive recursion limit exceeded (%u, max: %u)\n", ctx->recursion, ctx->engine->maxreclevel);
2568
early_ret_from_magicscan(CL_CLEAN);
2571
if(cli_updatelimits(ctx, (*ctx->fmap)->len)!=CL_CLEAN) {
2573
early_ret_from_magicscan(CL_CLEAN);
2575
old_hook_lsig_matches = ctx->hook_lsig_matches;
2576
if(type == CL_TYPE_PART_ANY) {
2580
perf_start(ctx, PERFT_FT);
2581
if((type == CL_TYPE_ANY) || type == CL_TYPE_PART_ANY) {
2582
type = cli_filetype2(*ctx->fmap, ctx->engine, type);
2584
perf_stop(ctx, PERFT_FT);
2585
if(type == CL_TYPE_ERROR) {
2586
cli_dbgmsg("cli_magic_scandesc: cli_filetype2 returned CL_TYPE_ERROR\n");
2587
early_ret_from_magicscan(CL_EREAD);
2589
filetype = cli_ftname(type);
2592
if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
2593
json_object *arrobj;
2595
if (NULL == ctx->properties) {
2596
if (type == CL_TYPE_PDF || /* file types we collect properties about */
2597
type == CL_TYPE_MSOLE2 ||
2598
type == CL_TYPE_MSEXE ||
2599
//type == CL_TYPE_ZIP ||
2600
type == CL_TYPE_OOXML_WORD ||
2601
type == CL_TYPE_OOXML_PPT ||
2602
type == CL_TYPE_OOXML_XL) {
2603
ctx->properties = json_object_new_object();
2604
if (NULL == ctx->properties) {
2605
cli_errmsg("magic_scandesc: no memory for json properties object\n");
2606
early_ret_from_magicscan(CL_EMEM);
2608
ctx->wrkproperty = ctx->properties;
2609
ret = cli_jsonstr(ctx->properties, "Magic", "CLAMJSONv0");
2610
if (ret != CL_SUCCESS) {
2611
early_ret_from_magicscan(ret);
2613
ret = cli_jsonstr(ctx->properties, "RootFileType", filetype);
2614
if (ret != CL_SUCCESS) {
2615
early_ret_from_magicscan(ret);
2617
} else { /* turn off property collection flag for file types we don't care about */
2618
ctx->options &= ~CL_SCAN_FILE_PROPERTIES;
2622
parent_property = ctx->wrkproperty;
2623
if (!json_object_object_get_ex(parent_property, "ContainedObjects", &arrobj)) {
2624
arrobj = json_object_new_array();
2625
if (NULL == arrobj) {
2626
cli_errmsg("magic_scandesc: no memory for json properties object\n");
2627
early_ret_from_magicscan(CL_EMEM);
2629
json_object_object_add(parent_property, "ContainedObjects", arrobj);
2631
ctx->wrkproperty = json_object_new_object();
2632
if (NULL == ctx->wrkproperty) {
2633
cli_errmsg("magic_scandesc: no memory for json properties object\n");
2634
early_ret_from_magicscan(CL_EMEM);
2636
json_object_array_add(arrobj, ctx->wrkproperty);
2640
if (ctx->options & CL_SCAN_FILE_PROPERTIES) { /* separated for cases json is not tracked */
2641
ret = cli_jsonstr(ctx->wrkproperty, "FileType", filetype);
2642
if (ret != CL_SUCCESS) {
2643
early_ret_from_magicscan(ret);
2645
ret = cli_jsonint(ctx->wrkproperty, "FileSize", (*ctx->fmap)->len);
2646
if (ret != CL_SUCCESS) {
2647
early_ret_from_magicscan(ret);
2653
ret = dispatch_prescan(ctx->engine->cb_pre_cache, ctx, filetype, old_hook_lsig_matches, parent_property, hash, hashed_size, &run_cleanup);
2655
if (ret == CL_VIRUS)
2656
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, cli_checkfp(hash, hashed_size, ctx), parent_property);
2658
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_CLEAN, parent_property);
2661
perf_start(ctx, PERFT_CACHE);
2662
res = cache_check(hash, ctx);
2665
if (SCAN_PROPERTIES /* ctx.options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL */) {
2667
snprintf(hashstr, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]);
2669
ret = cli_jsonstr(ctx->wrkproperty, "FileMD5", hashstr);
2670
if (ret != CL_SUCCESS) {
2671
early_ret_from_magicscan(ret);
2676
if(res != CL_VIRUS) {
2677
perf_stop(ctx, PERFT_CACHE);
2679
ctx->wrkproperty = parent_property;
2681
early_ret_from_magicscan(res);
2684
perf_stop(ctx, PERFT_CACHE);
2685
hashed_size = (*ctx->fmap)->len;
2686
ctx->hook_lsig_matches = NULL;
2688
if(!(ctx->options&~CL_SCAN_ALLMATCHES) || (ctx->recursion == ctx->engine->maxreclevel)) { /* raw mode (stdin, etc.) or last level of recursion */
2689
if(ctx->recursion == ctx->engine->maxreclevel)
2690
cli_dbgmsg("cli_magic_scandesc: Hit recursion limit, only scanning raw file\n");
2692
cli_dbgmsg("Raw mode: No support for special files\n");
2694
ret = dispatch_prescan(ctx->engine->cb_pre_scan, ctx, filetype, old_hook_lsig_matches, parent_property, hash, hashed_size, &run_cleanup);
2696
if (ret == CL_VIRUS)
2697
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, cli_checkfp(hash, hashed_size, ctx), parent_property);
2699
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2701
/* ret_from_magicscan can be used below here*/
2702
if((ret = cli_fmap_scandesc(ctx, 0, 0, NULL, AC_SCAN_VIR, NULL, hash)) == CL_VIRUS)
2703
cli_dbgmsg("%s found in descriptor %d\n", cli_get_last_virus(ctx), fmap_fd(*ctx->fmap));
2704
else if(ret == CL_CLEAN) {
2705
if(ctx->recursion != ctx->engine->maxreclevel)
2706
cache_clean = 1; /* Only cache if limits are not reached */
2711
ctx->hook_lsig_matches = old_hook_lsig_matches;
2712
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2715
ret = dispatch_prescan(ctx->engine->cb_pre_scan, ctx, filetype, old_hook_lsig_matches, parent_property, hash, hashed_size, &run_cleanup);
2717
if (ret == CL_VIRUS)
2718
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, cli_checkfp(hash, hashed_size, ctx), parent_property);
2720
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2722
/* ret_from_magicscan can be used below here*/
2724
#ifdef HAVE__INTERNAL__SHA_COLLECT
2725
if(!ctx->sha_collect && type==CL_TYPE_MSEXE) ctx->sha_collect = 1;
2728
ctx->hook_lsig_matches = cli_bitset_init();
2729
if (!ctx->hook_lsig_matches) {
2730
ctx->hook_lsig_matches = old_hook_lsig_matches;
2731
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_EMEM, parent_property);
2734
if(type != CL_TYPE_IGNORED && ctx->engine->sdb) {
2735
if((ret = cli_scanraw(ctx, type, 0, &dettype, (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) ? NULL : hash)) == CL_VIRUS) {
2736
ret = cli_checkfp(hash, hashed_size, ctx);
2737
cli_bitset_free(ctx->hook_lsig_matches);
2738
ctx->hook_lsig_matches = old_hook_lsig_matches;
2739
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2744
perf_nested_start(ctx, PERFT_CONTAINER, PERFT_SCAN);
2745
ctx->container_size = (*ctx->fmap)->len;
2747
case CL_TYPE_IGNORED:
2751
ret = cli_scanxdp(ctx);
2755
ctx->container_type = CL_TYPE_RAR;
2756
if(have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR)) {
2757
char *tmpname = NULL;
2758
int desc = fmap_fd(*ctx->fmap);
2760
cli_dbgmsg("fmap not backed by file, dumping ...\n");
2761
ret = fmap_dump_to_file(*ctx->fmap, ctx->engine->tmpdir, &tmpname, &desc);
2762
if (ret != CL_SUCCESS) {
2763
cli_dbgmsg("fmap_fd: failed to generate temporary file.\n");
2767
ret = cli_scanrar(desc, ctx, 0, NULL);
2776
case CL_TYPE_OOXML_WORD:
2777
case CL_TYPE_OOXML_PPT:
2778
case CL_TYPE_OOXML_XL:
2780
if ((ctx->options & CL_SCAN_FILE_PROPERTIES) && (ctx->wrkproperty != NULL)) {
2781
ret = cli_process_ooxml(ctx);
2782
if (ret == CL_ETIMEOUT) {
2783
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2785
else if (ret != CL_SUCCESS) {
2786
/* JSONOOXML - what to do if something else fails? placeholder */
2792
ctx->container_type = CL_TYPE_ZIP;
2793
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
2794
ret = cli_unzip(ctx);
2798
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_GZ))
2799
ret = cli_scangzip(ctx);
2803
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BZ))
2804
ret = cli_scanbzip(ctx);
2808
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_XZ))
2809
ret = cli_scanxz(ctx);
2813
ret = cli_scangpt(ctx, 0);
2817
ret = cli_scanapm(ctx);
2821
ctx->container_type = CL_TYPE_ARJ;
2822
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ))
2823
ret = cli_scanarj(ctx, 0, NULL);
2826
case CL_TYPE_NULSFT:
2827
ctx->container_type = CL_TYPE_NULSFT;
2828
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_NSIS))
2829
ret = cli_scannulsft(ctx, 0);
2832
case CL_TYPE_AUTOIT:
2833
ctx->container_type = CL_TYPE_AUTOIT;
2834
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_AUTOIT))
2835
ret = cli_scanautoit(ctx, 23);
2838
case CL_TYPE_MSSZDD:
2839
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SZDD))
2840
ret = cli_scanszdd(ctx);
2844
ctx->container_type = CL_TYPE_MSCAB;
2845
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB))
2846
ret = cli_scanmscab(ctx, 0);
2850
if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
2851
ret = cli_scanhtml(ctx);
2854
case CL_TYPE_HTML_UTF16:
2855
if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
2856
ret = cli_scanhtml_utf16(ctx);
2859
case CL_TYPE_SCRIPT:
2860
if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML)
2861
ret = cli_scanscript(ctx);
2865
if(SCAN_SWF && (DCONF_DOC & DOC_CONF_SWF))
2866
ret = cli_scanswf(ctx);
2870
ctx->container_type = CL_TYPE_RTF;
2871
if(SCAN_ARCHIVE && (DCONF_DOC & DOC_CONF_RTF))
2872
ret = cli_scanrtf(ctx);
2876
ctx->container_type = CL_TYPE_MAIL;
2877
if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
2878
ret = cli_scanmail(ctx);
2882
if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_TNEF))
2883
ret = cli_scantnef(ctx);
2886
case CL_TYPE_UUENCODED:
2887
if(DCONF_OTHER & OTHER_CONF_UUENC)
2888
ret = cli_scanuuencoded(ctx);
2892
ctx->container_type = CL_TYPE_MSCHM;
2893
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CHM))
2894
ret = cli_scanmschm(ctx);
2897
case CL_TYPE_MSOLE2:
2898
ctx->container_type = CL_TYPE_MSOLE2;
2899
if(SCAN_OLE2 && (DCONF_ARCH & ARCH_CONF_OLE2))
2900
ret = cli_scanole2(ctx);
2904
ctx->container_type = CL_TYPE_7Z;
2905
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z))
2906
ret = cli_7unz(ctx, 0);
2909
case CL_TYPE_POSIX_TAR:
2910
ctx->container_type = CL_TYPE_POSIX_TAR;
2911
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
2912
ret = cli_scantar(ctx, 1);
2915
case CL_TYPE_OLD_TAR:
2916
ctx->container_type = CL_TYPE_OLD_TAR;
2917
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
2918
ret = cli_scantar(ctx, 0);
2921
case CL_TYPE_CPIO_OLD:
2922
ctx->container_type = CL_TYPE_CPIO_OLD;
2923
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2924
ret = cli_scancpio_old(ctx);
2927
case CL_TYPE_CPIO_ODC:
2928
ctx->container_type = CL_TYPE_CPIO_ODC;
2929
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2930
ret = cli_scancpio_odc(ctx);
2933
case CL_TYPE_CPIO_NEWC:
2934
ctx->container_type = CL_TYPE_CPIO_NEWC;
2935
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2936
ret = cli_scancpio_newc(ctx, 0);
2939
case CL_TYPE_CPIO_CRC:
2940
ctx->container_type = CL_TYPE_CPIO_CRC;
2941
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2942
ret = cli_scancpio_newc(ctx, 1);
2945
case CL_TYPE_BINHEX:
2946
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BINHEX))
2947
ret = cli_binhex(ctx);
2950
case CL_TYPE_SCRENC:
2951
if(DCONF_OTHER & OTHER_CONF_SCRENC)
2952
ret = cli_scanscrenc(ctx);
2956
if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_RIFF))
2957
ret = cli_scanriff(ctx);
2960
case CL_TYPE_GRAPHICS:
2961
if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_JPEG))
2962
ret = cli_scanjpeg(ctx);
2964
if(ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS)
2965
ret = cli_parsejpeg(ctx);
2967
if(ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS && ret != CL_EPARSE)
2968
ret = cli_parsepng(ctx);
2970
if(ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS && ret != CL_EPARSE)
2971
ret = cli_parsegif(ctx);
2974
case CL_TYPE_PDF: /* FIXMELIMITS: pdf should be an archive! */
2975
ctx->container_type = CL_TYPE_PDF;
2976
if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
2977
ret = cli_scanpdf(ctx, 0);
2980
case CL_TYPE_CRYPTFF:
2981
if(DCONF_OTHER & OTHER_CONF_CRYPTFF)
2982
ret = cli_scancryptff(ctx);
2986
if(SCAN_ELF && ctx->dconf->elf)
2987
ret = cli_scanelf(ctx);
2991
if(ctx->dconf->macho)
2992
ret = cli_scanmacho(ctx, NULL);
2995
case CL_TYPE_MACHO_UNIBIN:
2996
if(ctx->dconf->macho)
2997
ret = cli_scanmacho_unibin(ctx);
3001
ctx->container_type = CL_TYPE_SIS;
3002
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SIS))
3003
ret = cli_scansis(ctx);
3007
ctx->container_type = CL_TYPE_XAR;
3008
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_XAR))
3009
ret = cli_scanxar(ctx);
3012
case CL_TYPE_PART_HFSPLUS:
3013
ctx->container_type = CL_TYPE_PART_HFSPLUS;
3014
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_HFSPLUS))
3015
ret = cli_scanhfsplus(ctx);
3018
case CL_TYPE_BINARY_DATA:
3019
case CL_TYPE_TEXT_UTF16BE:
3020
if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_MYDOOMLOG))
3021
ret = cli_check_mydoom_log(ctx);
3024
case CL_TYPE_TEXT_ASCII:
3025
if(SCAN_STRUCTURED && (DCONF_OTHER & OTHER_CONF_DLP))
3026
/* TODO: consider calling this from cli_scanscript() for
3029
ret = cli_scan_structured(ctx);
3035
perf_nested_stop(ctx, PERFT_CONTAINER, PERFT_SCAN);
3037
ctx->container_type = current_container_type;
3038
ctx->container_size = current_container_size;
3040
if(ret == CL_VIRUS) {
3041
ret = cli_checkfp(hash, hashed_size, ctx);
3042
cli_bitset_free(ctx->hook_lsig_matches);
3043
ctx->hook_lsig_matches = old_hook_lsig_matches;
3044
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
3047
if(type == CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP)) {
3048
/* CL_ENGINE_MAX_ZIPTYPERCG */
3049
uint64_t curr_len = (*ctx->fmap)->len;
3050
if(curr_len > ctx->engine->maxziptypercg) {
3051
cli_dbgmsg("cli_magic_scandesc: Not checking for embedded PEs (zip file > MaxZipTypeRcg)\n");
3056
/* CL_TYPE_HTML: raw HTML files are not scanned, unless safety measure activated via DCONF */
3057
if(type != CL_TYPE_IGNORED && (type != CL_TYPE_HTML || !(DCONF_DOC & DOC_CONF_HTML_SKIPRAW)) && !ctx->engine->sdb) {
3058
res = cli_scanraw(ctx, type, typercg, &dettype, (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) ? NULL : hash);
3059
if(res != CL_CLEAN) {
3061
/* List of scan halts, runtime errors only! */
3071
cli_dbgmsg("Descriptor[%d]: cli_scanraw error %s\n", fmap_fd(*ctx->fmap), cl_strerror(res));
3072
cli_bitset_free(ctx->hook_lsig_matches);
3073
ctx->hook_lsig_matches = old_hook_lsig_matches;
3074
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
3075
/* CL_VIRUS = malware found, check FP and report */
3077
ret = cli_checkfp(hash, hashed_size, ctx);
3080
cli_bitset_free(ctx->hook_lsig_matches);
3081
ctx->hook_lsig_matches = old_hook_lsig_matches;
3082
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
3083
/* "MAX" conditions should still fully scan the current file */
3088
cli_dbgmsg("Descriptor[%d]: Continuing after cli_scanraw reached %s\n",
3089
fmap_fd(*ctx->fmap), cl_strerror(res));
3091
/* Other errors must not block further scans below
3092
* This specifically includes CL_EFORMAT & CL_EREAD & CL_EUNPACK
3093
* Malformed/truncated files could report as any of these three.
3097
cli_dbgmsg("Descriptor[%d]: Continuing after cli_scanraw error %s\n",
3098
fmap_fd(*ctx->fmap), cl_strerror(res));
3105
/* bytecode hooks triggered by a lsig must be a hook
3106
* called from one of the functions here */
3107
case CL_TYPE_TEXT_ASCII:
3108
case CL_TYPE_TEXT_UTF16BE:
3109
case CL_TYPE_TEXT_UTF16LE:
3110
case CL_TYPE_TEXT_UTF8:
3111
perf_nested_start(ctx, PERFT_SCRIPT, PERFT_SCAN);
3112
if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML && ret != CL_VIRUS)
3113
ret = cli_scanscript(ctx);
3114
if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX) && ret != CL_VIRUS && (ctx->container_type == CL_TYPE_MAIL || dettype == CL_TYPE_MAIL)) {
3115
ret = cli_fmap_scandesc(ctx, CL_TYPE_MAIL, 0, NULL, AC_SCAN_VIR, NULL, NULL);
3117
perf_nested_stop(ctx, PERFT_SCRIPT, PERFT_SCAN);
3119
/* Due to performance reasons all executables were first scanned
3120
* in raw mode. Now we will try to unpack them
3123
perf_nested_start(ctx, PERFT_PE, PERFT_SCAN);
3124
if(SCAN_PE && ctx->dconf->pe) {
3125
unsigned int corrupted_input = ctx->corrupted_input;
3126
ret = cli_scanpe(ctx);
3127
ctx->corrupted_input = corrupted_input;
3129
perf_nested_stop(ctx, PERFT_PE, PERFT_SCAN);
3136
ret = cli_checkfp(hash, hashed_size, ctx);
3138
cli_bitset_free(ctx->hook_lsig_matches);
3139
ctx->hook_lsig_matches = old_hook_lsig_matches;
3142
/* Malformed file cases */
3146
/* Limits exceeded */
3150
cli_dbgmsg("Descriptor[%d]: %s\n", fmap_fd(*ctx->fmap), cl_strerror(ret));
3152
ctx->wrkproperty = parent_property;
3154
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_CLEAN, parent_property);
3158
ctx->wrkproperty = parent_property;
3160
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_CLEAN, parent_property);
3162
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
3166
static int cli_base_scandesc(int desc, cli_ctx *ctx, cli_file_t type)
3171
#ifdef HAVE__INTERNAL__SHA_COLLECT
3172
if(ctx->sha_collect>0) ctx->sha_collect = 0;
3174
cli_dbgmsg("in cli_magic_scandesc (reclevel: %u/%u)\n", ctx->recursion, ctx->engine->maxreclevel);
3175
if(FSTAT(desc, &sb) == -1) {
3176
cli_errmsg("magic_scandesc: Can't fstat descriptor %d\n", desc);
3177
early_ret_from_magicscan(CL_ESTAT);
3179
if(sb.st_size <= 5) {
3180
cli_dbgmsg("Small data (%u bytes)\n", (unsigned int) sb.st_size);
3181
early_ret_from_magicscan(CL_CLEAN);
3185
perf_start(ctx, PERFT_MAP);
3186
if(!(*ctx->fmap = fmap(desc, 0, sb.st_size))) {
3187
cli_errmsg("CRITICAL: fmap() failed\n");
3189
perf_stop(ctx, PERFT_MAP);
3190
early_ret_from_magicscan(CL_EMEM);
3192
perf_stop(ctx, PERFT_MAP);
3194
ret = magic_scandesc(ctx, type);
3201
int cli_magic_scandesc(int desc, cli_ctx *ctx)
3203
return cli_base_scandesc(desc, ctx, CL_TYPE_ANY);
3206
/* Have to keep partition typing separate */
3207
int cli_partition_scandesc(int desc, cli_ctx *ctx)
3209
return cli_base_scandesc(desc, ctx, CL_TYPE_PART_ANY);
3212
int cli_magic_scandesc_type(cli_ctx *ctx, cli_file_t type)
3214
return magic_scandesc(ctx, type);
3217
int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
3219
return cl_scandesc_callback(desc, virname, scanned, engine, scanoptions, NULL);
3222
/* For map scans that may be forced to disk */
3223
int cli_map_scan(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx, cli_file_t type)
3225
off_t old_off = map->nested_offset;
3226
size_t old_len = map->len;
3229
cli_dbgmsg("cli_map_scan: [%ld, +%lu)\n",
3230
(long)offset, (unsigned long)length);
3231
if (offset < 0 || (size_t)offset >= old_len) {
3232
cli_dbgmsg("Invalid offset: %ld\n", (long)offset);
3236
if (ctx->engine->engine_options & ENGINE_OPTIONS_FORCE_TO_DISK) {
3237
/* if this is forced to disk, then need to write the nested map and scan it */
3238
const uint8_t *mapdata = NULL;
3239
char *tempfile = NULL;
3243
/* Then check length */
3244
if (!length) length = old_len - offset;
3245
if (length > old_len - offset) {
3246
cli_dbgmsg("cli_map_scan: Data truncated: %lu -> %lu\n",
3247
(unsigned long)length, (unsigned long)(old_len - offset));
3248
length = old_len - offset;
3251
cli_dbgmsg("cli_map_scan: Small data (%u bytes)\n", (unsigned int) length);
3254
if (!CLI_ISCONTAINED(old_off, old_len, old_off + offset, length)) {
3255
cli_dbgmsg("cli_map_scan: map error occurred [%ld, %lu]\n",
3256
(long)old_off, (unsigned long)old_len);
3260
/* Length checked, now get map */
3261
mapdata = fmap_need_off_once_len(map, offset, length, &nread);
3262
if (!mapdata || (nread != length)) {
3263
cli_errmsg("cli_map_scan: could not map sub-file\n");
3267
ret = cli_gentempfd(ctx->engine->tmpdir, &tempfile, &fd);
3268
if (ret != CL_SUCCESS) {
3272
cli_dbgmsg("cli_map_scan: writing nested map content to temp file %s\n", tempfile);
3273
if (cli_writen(fd, mapdata, length) < 0) {
3274
cli_errmsg("cli_map_scan: cli_writen error writing subdoc temporary file.\n");
3278
/* scan the temp file */
3279
ret = cli_base_scandesc(fd, ctx, type);
3281
/* remove the temp file, if needed */
3285
if(!ctx->engine->keeptmp) {
3286
if (cli_unlink(tempfile)) {
3287
cli_errmsg("cli_map_scan: error unlinking tempfile %s\n", tempfile);
3294
/* Not forced to disk, use nested map */
3295
ret = cli_map_scandesc(map, offset, length, ctx, type);
3300
/* For map scans that are not forced to disk */
3301
int cli_map_scandesc(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx, cli_file_t type)
3303
off_t old_off = map->nested_offset;
3304
size_t old_len = map->len;
3305
size_t old_real_len = map->real_len;
3308
cli_dbgmsg("cli_map_scandesc: [%ld, +%lu), [%ld, +%lu)\n",
3309
(long)old_off, (unsigned long)old_len,
3310
(long)offset, (unsigned long)length);
3311
if (offset < 0 || (size_t)offset >= old_len) {
3312
cli_dbgmsg("Invalid offset: %ld\n", (long)offset);
3316
if (!length) length = old_len - offset;
3317
if (length > old_len - offset) {
3318
cli_dbgmsg("Data truncated: %lu -> %lu\n",
3319
(unsigned long)length, old_len - offset);
3320
length = old_len - offset;
3324
cli_dbgmsg("Small data (%u bytes)\n", (unsigned int) length);
3329
/* can't change offset because then we'd have to discard/move cached
3330
* data, instead use another offset to reuse the already cached data */
3331
map->nested_offset += offset;
3333
map->real_len = map->nested_offset + length;
3334
if (CLI_ISCONTAINED(old_off, old_len, map->nested_offset, map->len)) {
3335
ret = magic_scandesc(ctx, type);
3337
long long len1, len2;
3338
len1 = old_off + old_len;
3339
len2 = map->nested_offset + map->len;
3340
cli_warnmsg("internal map error: %lu, %llu; %lu, %llu\n", (long unsigned)old_off,
3341
(long long unsigned)len1, (long unsigned)map->offset, (long long unsigned)len2);
3345
map->nested_offset = old_off;
3347
map->real_len = old_real_len;
3351
int cli_mem_scandesc(const void *buffer, size_t length, cli_ctx *ctx)
3354
fmap_t *map = cl_fmap_open_memory(buffer, length);
3358
ret = cli_map_scan(map, 0, length, ctx, CL_TYPE_ANY);
3363
static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
3369
/* We have a limit of around 2.17GB (INT_MAX - 2). Enforce it here. */
3371
if ((size_t)(map->real_len) > (size_t)(INT_MAX - 2))
3374
if (FSTAT(desc, &sb))
3377
if ((size_t)(sb.st_size) > (size_t)(INT_MAX - 2))
3381
memset(&ctx, '\0', sizeof(cli_ctx));
3382
ctx.engine = engine;
3383
ctx.virname = virname;
3384
ctx.scanned = scanned;
3385
ctx.options = scanoptions;
3386
#if 0 /* for development testing only */
3387
ctx.options |= CL_SCAN_FILE_PROPERTIES;
3389
ctx.found_possibly_unwanted = 0;
3390
ctx.container_type = CL_TYPE_ANY;
3391
ctx.container_size = 0;
3392
ctx.dconf = (struct cli_dconf *) engine->dconf;
3393
ctx.cb_ctx = context;
3394
ctx.fmap = cli_calloc(sizeof(fmap_t *), ctx.engine->maxreclevel + 2);
3397
if (!(ctx.hook_lsig_matches = cli_bitset_init())) {
3403
if (ctx.options & CL_SCAN_FILE_PROPERTIES && ctx.engine->time_limit != 0) {
3404
if (gettimeofday(&ctx.time_limit, NULL) == 0) {
3405
uint32_t secs = ctx.engine->time_limit / 1000;
3406
uint32_t usecs = (ctx.engine->time_limit % 1000) * 1000;
3407
ctx.time_limit.tv_sec += secs;
3408
ctx.time_limit.tv_usec += usecs;
3409
if (ctx.time_limit.tv_usec >= 1000000) {
3410
ctx.time_limit.tv_usec -= 1000000;
3411
ctx.time_limit.tv_sec++;
3415
cli_dbgmsg("scan_common; gettimeofday error: %s\n", cli_strerror(errno, buf, 64));
3419
#ifdef HAVE__INTERNAL__SHA_COLLECT
3420
if(scanoptions & CL_SCAN_INTERNAL_COLLECT_SHA) {
3425
snprintf(link, sizeof(link), "/proc/self/fd/%u", desc);
3426
link[sizeof(link)-1]='\0';
3427
if((linksz=readlink(link, ctx.entry_filename, sizeof(ctx.entry_filename)-1))==-1) {
3428
cli_errmsg("failed to resolve filename for descriptor %d (%s)\n", desc, link);
3429
strcpy(ctx.entry_filename, "NO_IDEA");
3431
ctx.entry_filename[linksz]='\0';
3435
cli_logg_setup(&ctx);
3436
rc = map ? cli_map_scandesc(map, 0, map->len, &ctx, CL_TYPE_ANY) : cli_magic_scandesc(desc, &ctx);
3439
if (ctx.options & CL_SCAN_FILE_PROPERTIES && ctx.properties!=NULL) {
3441
const char *jstring;
3443
/* set value of unique root object tag */
3444
if (json_object_object_get_ex(ctx.properties, "FileType", &jobj)) {
3445
enum json_type type;
3448
type = json_object_get_type(jobj);
3449
if (type == json_type_string) {
3450
jstr = json_object_get_string(jobj);
3451
cli_jsonstr(ctx.properties, "RootFileType", jstr);
3455
/* serialize json properties to string */
3456
jstring = json_object_to_json_string(ctx.properties);
3457
if (NULL == jstring) {
3458
cli_errmsg("scan_common: no memory for json serialization.\n");
3462
int ret = CL_SUCCESS;
3463
cli_dbgmsg("%s\n", jstring);
3465
/* Scan the json string unless a virus was detected */
3466
if (rc != CL_VIRUS) {
3467
ctx.options &= ~CL_SCAN_FILE_PROPERTIES;
3468
rc = cli_mem_scandesc(jstring, strlen(jstring), &ctx);
3471
/* Invoke file props callback */
3472
if (ctx.engine->cb_file_props != NULL) {
3473
ret = ctx.engine->cb_file_props(jstring, rc, ctx.engine->cb_file_props_data);
3474
if (ret != CL_SUCCESS)
3478
/* keeptmp file processing for file properties json string */
3479
if (ctx.engine->keeptmp) {
3481
char * tmpname = NULL;
3482
if ((ret = cli_gentempfd(ctx.engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
3483
cli_dbgmsg("scan_common: Can't create json properties file, ret = %i.\n", ret);
3485
if (cli_writen(fd, jstring, strlen(jstring)) < 0)
3486
cli_dbgmsg("scan_common: cli_writen error writing json properties file.\n");
3488
cli_dbgmsg("json written to: %s\n", tmpname);
3492
if (NULL != tmpname)
3496
json_object_put(ctx.properties); /* frees all json memory */
3498
// test code - to be deleted
3499
if (cli_checktimelimit(&ctx) != CL_SUCCESS) {
3500
cli_errmsg("scan_common: timeout!\n");
3507
if (ctx.options & CL_SCAN_ALLMATCHES) {
3508
*virname = (char *)ctx.virname; /* temp hack for scanall mode until api augmentation */
3509
if (rc == CL_CLEAN && ctx.num_viruses)
3513
cli_bitset_free(ctx.hook_lsig_matches);
3515
if(rc == CL_CLEAN && ctx.found_possibly_unwanted)
3522
int cl_scandesc_callback(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
3524
return scan_common(desc, NULL, virname, scanned, engine, scanoptions, context);
3527
int cl_scanmap_callback(cl_fmap_t *map, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
3529
return scan_common(-1, map, virname, scanned, engine, scanoptions, context);
3532
int cli_found_possibly_unwanted(cli_ctx* ctx)
3534
if(cli_get_last_virus(ctx)) {
3535
cli_dbgmsg("found Possibly Unwanted: %s\n", cli_get_last_virus(ctx));
3536
if(ctx->options & CL_SCAN_HEURISTIC_PRECEDENCE) {
3537
/* we found a heuristic match, don't scan further,
3538
* but consider it a virus. */
3539
cli_dbgmsg("cli_found_possibly_unwanted: CL_VIRUS\n");
3542
/* heuristic scan isn't taking precedence, keep scanning.
3543
* If this is part of an archive, and
3544
* we find a real malware we report that instead of the
3545
* heuristic match */
3546
ctx->found_possibly_unwanted = 1;
3548
cli_warnmsg("cli_found_possibly_unwanted called, but virname is not set\n");
3554
static int cli_scanfile(const char *filename, cli_ctx *ctx)
3558
/* internal version of cl_scanfile with arec/mrec preserved */
3559
if((fd = safe_open(filename, O_RDONLY|O_BINARY)) == -1)
3562
ret = cli_magic_scandesc(fd, ctx);
3568
int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
3570
return cl_scanfile_callback(filename, virname, scanned, engine, scanoptions, NULL);
3573
int cl_scanfile_callback(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
3576
const char *fname = cli_to_utf8_maybe_alloc(filename);
3581
if((fd = safe_open(fname, O_RDONLY|O_BINARY)) == -1)
3584
if(fname != filename)
3587
ret = cl_scandesc_callback(fd, virname, scanned, engine, scanoptions, context);