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 "libmspack.h"
66
#include "filetypes.h"
71
/* #include "uuencode.h" */
78
#include "nsis/nulsft.h"
105
#include "json_api.h"
111
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
118
static int cli_scanfile(const char *filename, cli_ctx *ctx);
120
static int cli_scandir(const char *dirname, cli_ctx *ctx)
124
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
127
char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
132
unsigned int viruses_found = 0;
134
if((dd = opendir(dirname)) != NULL) {
135
#ifdef HAVE_READDIR_R_3
136
while(!readdir_r(dd, &result.d, &dent) && dent) {
137
#elif defined(HAVE_READDIR_R_2)
138
while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
140
while((dent = readdir(dd))) {
144
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
145
/* build the full name */
146
fname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
149
cli_dbgmsg("cli_scandir: Unable to allocate memory for filename\n");
153
sprintf(fname, "%s"PATHSEP"%s", dirname, dent->d_name);
156
if(LSTAT(fname, &statbuf) != -1) {
157
if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {
158
if(cli_scandir(fname, ctx) == CL_VIRUS) {
170
if(S_ISREG(statbuf.st_mode)) {
171
if(cli_scanfile(fname, ctx) == CL_VIRUS) {
190
cli_dbgmsg("cli_scandir: Can't open directory %s.\n", dirname);
195
if (SCAN_ALL && viruses_found)
200
static int cli_unrar_scanmetadata(int desc, unrar_metadata_t *metadata, cli_ctx *ctx, unsigned int files, uint32_t* sfx_check)
202
int ret = CL_SUCCESS;
204
if(files == 1 && sfx_check) {
205
if(*sfx_check == metadata->crc)
206
return CL_BREAK;/* break extract loop */
208
*sfx_check = metadata->crc;
211
cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %u, compressed: %u, normal: %u, method: %u, ratio: %u\n",
212
metadata->filename, metadata->crc, metadata->encrypted, (unsigned int) metadata->pack_size,
213
(unsigned int) metadata->unpack_size, metadata->method,
214
metadata->pack_size ? (unsigned int) (metadata->unpack_size / metadata->pack_size) : 0);
216
if(cli_matchmeta(ctx, metadata->filename, metadata->pack_size, metadata->unpack_size, metadata->encrypted, files, metadata->crc, NULL) == CL_VIRUS)
219
if(DETECT_ENCRYPTED && metadata->encrypted) {
220
cli_dbgmsg("RAR: Encrypted files found in archive.\n");
221
ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
222
if(ret != CL_VIRUS) {
223
cli_append_virus(ctx, "Heuristics.Encrypted.RAR");
231
static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
234
unrar_metadata_t *metadata, *metadata_tmp;
236
unrar_state_t rar_state;
237
unsigned int viruses_found = 0;
239
cli_dbgmsg("in scanrar()\n");
242
if(lseek(desc, sfx_offset, SEEK_SET) == -1)
245
/* generate the temporary directory */
246
if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
249
if(mkdir(dir, 0700)) {
250
cli_dbgmsg("RAR: Can't create temporary directory %s\n", dir);
255
if((ret = cli_unrar_open(desc, dir, &rar_state)) != UNRAR_OK) {
256
if(!ctx->engine->keeptmp)
259
if(ret == UNRAR_PASSWD) {
260
cli_dbgmsg("RAR: Encrypted main header\n");
261
if(DETECT_ENCRYPTED) {
262
if (lseek(desc, 0, SEEK_SET) == -1) {
263
cli_dbgmsg("RAR: call to lseek() failed\n");
266
ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
268
cli_append_virus(ctx, "Heuristics.Encrypted.RAR");
272
} if(ret == UNRAR_EMEM) {
282
ret = cli_unrar_extract_next_prepare(&rar_state,dir);
283
if(ret != UNRAR_OK) {
284
if(ret == UNRAR_BREAK)
286
else if(ret == UNRAR_EMEM)
292
if(ctx->engine->maxscansize && ctx->scansize >= ctx->engine->maxscansize) {
293
free(rar_state.file_header->filename);
294
free(rar_state.file_header);
298
if(ctx->engine->maxscansize && ctx->scansize + ctx->engine->maxfilesize >= ctx->engine->maxscansize)
299
rar_state.maxfilesize = ctx->engine->maxscansize - ctx->scansize;
301
rar_state.maxfilesize = ctx->engine->maxfilesize;
303
ret = cli_unrar_extract_next(&rar_state,dir);
306
else if(ret == UNRAR_EMEM)
311
if(rar_state.ofd > 0) {
312
if (lseek(rar_state.ofd,0,SEEK_SET) == -1) {
313
cli_dbgmsg("RAR: Call to lseek() failed\n");
316
rc = cli_magic_scandesc(rar_state.ofd,ctx);
317
close(rar_state.ofd);
318
if(!ctx->engine->keeptmp)
319
if (cli_unlink(rar_state.filename)) ret = CL_EUNLINK;
320
if(rc == CL_VIRUS ) {
321
cli_dbgmsg("RAR: infected with %s\n", cli_get_last_virus(ctx));
327
if(ret == CL_VIRUS) {
334
if(ret == CL_SUCCESS)
335
ret = cli_unrar_scanmetadata(desc,rar_state.metadata_tail, ctx, rar_state.file_count, sfx_check);
337
} while(ret == CL_SUCCESS);
342
metadata = metadata_tmp = rar_state.metadata;
344
if(cli_scandir(rar_state.comment_dir, ctx) == CL_VIRUS)
347
cli_unrar_close(&rar_state);
349
if(!ctx->engine->keeptmp)
354
metadata = metadata_tmp;
356
metadata_tmp = metadata->next;
357
free(metadata->filename);
359
metadata = metadata_tmp;
361
cli_dbgmsg("RAR: Exit code: %d\n", ret);
363
if (SCAN_ALL && viruses_found)
368
static int cli_scanarj(cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
370
int ret = CL_CLEAN, rc, file = 0;
371
arj_metadata_t metadata;
374
UNUSEDPARAM(sfx_check);
376
cli_dbgmsg("in cli_scanarj()\n");
378
/* generate the temporary directory */
379
if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
382
if(mkdir(dir, 0700)) {
383
cli_dbgmsg("ARJ: Can't create temporary directory %s\n", dir);
388
ret = cli_unarj_open(*ctx->fmap, dir, &metadata, sfx_offset);
389
if (ret != CL_SUCCESS) {
390
if(!ctx->engine->keeptmp)
393
cli_dbgmsg("ARJ: Error: %s\n", cl_strerror(ret));
398
metadata.filename = NULL;
399
ret = cli_unarj_prepare_file(dir, &metadata);
400
if (ret != CL_SUCCESS) {
401
cli_dbgmsg("ARJ: cli_unarj_prepare_file Error: %s\n", cl_strerror(ret));
405
if(cli_matchmeta(ctx, metadata.filename, metadata.comp_size, metadata.orig_size, metadata.encrypted, file, 0, NULL) == CL_VIRUS) {
411
if ((ret = cli_checklimits("ARJ", ctx, metadata.orig_size, metadata.comp_size, 0))!=CL_CLEAN) {
413
if (metadata.filename)
414
free(metadata.filename);
417
ret = cli_unarj_extract_file(dir, &metadata);
418
if (ret != CL_SUCCESS) {
419
cli_dbgmsg("ARJ: cli_unarj_extract_file Error: %s\n", cl_strerror(ret));
421
if (metadata.ofd >= 0) {
422
if (lseek(metadata.ofd, 0, SEEK_SET) == -1) {
423
cli_dbgmsg("ARJ: call to lseek() failed\n");
425
rc = cli_magic_scandesc(metadata.ofd, ctx);
427
if (rc == CL_VIRUS) {
428
cli_dbgmsg("ARJ: infected with %s\n", cli_get_last_virus(ctx));
430
if (metadata.filename) {
431
free(metadata.filename);
432
metadata.filename = NULL;
437
if (metadata.filename) {
438
free(metadata.filename);
439
metadata.filename = NULL;
442
} while(ret == CL_SUCCESS);
444
if(!ctx->engine->keeptmp)
448
if (metadata.filename) {
449
free(metadata.filename);
452
cli_dbgmsg("ARJ: Exit code: %d\n", ret);
460
static int cli_scangzip_with_zib_from_the_80s(cli_ctx *ctx, unsigned char *buff) {
461
int fd, ret, outsize = 0, bytes;
462
fmap_t *map = *ctx->fmap;
473
if(!(gz = gzdopen(fd, "rb"))) {
478
if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
479
cli_dbgmsg("GZip: Can't generate temporary file.\n");
485
while((bytes = gzread(gz, buff, FILEBUFF)) > 0) {
487
if(cli_checklimits("GZip", ctx, outsize, 0, 0)!=CL_CLEAN)
489
if(cli_writen(fd, buff, bytes) != bytes) {
492
if(cli_unlink(tmpname)) {
503
if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
504
cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx));
506
if(!ctx->engine->keeptmp) {
507
if (cli_unlink(tmpname)) {
516
if(!ctx->engine->keeptmp)
517
if (cli_unlink(tmpname)) ret = CL_EUNLINK;
522
static int cli_scangzip(cli_ctx *ctx)
524
int fd, ret = CL_CLEAN;
525
unsigned char buff[FILEBUFF];
528
size_t at = 0, outsize = 0;
529
fmap_t *map = *ctx->fmap;
531
cli_dbgmsg("in cli_scangzip()\n");
533
memset(&z, 0, sizeof(z));
534
if((ret = inflateInit2(&z, MAX_WBITS + 16)) != Z_OK) {
535
cli_dbgmsg("GZip: InflateInit failed: %d\n", ret);
536
return cli_scangzip_with_zib_from_the_80s(ctx, buff);
539
if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
540
cli_dbgmsg("GZip: Can't generate temporary file.\n");
545
while (at < map->len) {
546
unsigned int bytes = MIN(map->len - at, map->pgsz);
547
if(!(z.next_in = (void*)fmap_need_off_once(map, at, bytes))) {
548
cli_dbgmsg("GZip: Can't read %u bytes @ %lu.\n", bytes, (long unsigned)at);
551
if (cli_unlink(tmpname)) {
562
z.avail_out = sizeof(buff);
564
inf = inflate(&z, Z_NO_FLUSH);
565
if(inf != Z_OK && inf != Z_STREAM_END && inf != Z_BUF_ERROR) {
566
if (sizeof(buff) == z.avail_out) {
567
cli_dbgmsg("GZip: Bad stream, nothing in output buffer.\n");
572
cli_dbgmsg("GZip: Bad stream, data in output buffer.\n");
573
/* no break yet, flush extracted bytes to file */
576
if(cli_writen(fd, buff, sizeof(buff) - z.avail_out) < 0) {
579
if (cli_unlink(tmpname)) {
586
outsize += sizeof(buff) - z.avail_out;
587
if(cli_checklimits("GZip", ctx, outsize, 0, 0)!=CL_CLEAN) {
591
if(inf == Z_STREAM_END) {
596
else if(inf != Z_OK && inf != Z_BUF_ERROR) {
600
} while (z.avail_out == 0);
605
if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
606
cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx));
608
if(!ctx->engine->keeptmp) {
609
if (cli_unlink(tmpname)) {
618
if(!ctx->engine->keeptmp)
619
if (cli_unlink(tmpname)) ret = CL_EUNLINK;
625
static int cli_scanbzip(cli_ctx *ctx) {
626
cli_warnmsg("cli_scanbzip: bzip2 support not compiled in\n");
633
#define BZ2_bzDecompressInit bzDecompressInit
634
#define BZ2_bzDecompress bzDecompress
635
#define BZ2_bzDecompressEnd bzDecompressEnd
638
static int cli_scanbzip(cli_ctx *ctx)
640
int ret = CL_CLEAN, fd, rc;
641
unsigned long int size = 0;
648
memset(&strm, 0, sizeof(strm));
650
strm.avail_out = sizeof(buf);
651
rc = BZ2_bzDecompressInit(&strm, 0, 0);
653
cli_dbgmsg("Bzip: DecompressInit failed: %d\n", rc);
657
if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd))) {
658
cli_dbgmsg("Bzip: Can't generate temporary file.\n");
659
BZ2_bzDecompressEnd(&strm);
664
if (!strm.avail_in) {
665
strm.next_in = (void*)fmap_need_off_once_len(*ctx->fmap, off, FILEBUFF, &avail);
666
strm.avail_in = avail;
668
if (!strm.avail_in) {
669
cli_dbgmsg("Bzip: premature end of compressed stream\n");
674
rc = BZ2_bzDecompress(&strm);
675
if (BZ_OK != rc && BZ_STREAM_END != rc) {
676
cli_dbgmsg("Bzip: decompress error: %d\n", rc);
680
if (!strm.avail_out || BZ_STREAM_END == rc) {
681
size += sizeof(buf) - strm.avail_out;
683
if(cli_checklimits("Bzip", ctx, size + FILEBUFF, 0, 0)!=CL_CLEAN)
686
if(cli_writen(fd, buf, sizeof(buf) - strm.avail_out) != sizeof(buf) - strm.avail_out) {
687
cli_dbgmsg("Bzip: Can't write to file.\n");
688
BZ2_bzDecompressEnd(&strm);
690
if(!ctx->engine->keeptmp) {
691
if (cli_unlink(tmpname)) {
700
strm.avail_out = sizeof(buf);
702
} while (BZ_STREAM_END != rc);
704
BZ2_bzDecompressEnd(&strm);
706
if(ret == CL_VIRUS) {
708
if(!ctx->engine->keeptmp)
709
if (cli_unlink(tmpname)) ret = CL_EUNLINK;
714
if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
715
cli_dbgmsg("Bzip: Infected with %s\n", cli_get_last_virus(ctx));
718
if(!ctx->engine->keeptmp)
719
if (cli_unlink(tmpname)) ret = CL_EUNLINK;
726
static int cli_scanxz(cli_ctx *ctx)
728
int ret = CL_CLEAN, fd, rc;
729
unsigned long int size = 0;
736
buf = cli_malloc(CLI_XZ_OBUF_SIZE);
738
cli_errmsg("cli_scanxz: nomemory for decompress buffer.\n");
741
memset(&strm, 0x00, sizeof(struct CLI_XZ));
743
strm.avail_out = CLI_XZ_OBUF_SIZE;
744
rc = cli_XzInit(&strm);
745
if (rc != XZ_RESULT_OK) {
746
cli_errmsg("cli_scanxz: DecompressInit failed: %i\n", rc);
751
if ((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd))) {
752
cli_errmsg("cli_scanxz: Can't generate temporary file.\n");
753
cli_XzShutdown(&strm);
757
cli_dbgmsg("cli_scanxz: decompressing to file %s\n", tmpname);
760
/* set up input buffer */
761
if (!strm.avail_in) {
762
strm.next_in = (void*)fmap_need_off_once_len(*ctx->fmap, off, CLI_XZ_IBUF_SIZE, &avail);
763
strm.avail_in = avail;
765
if (!strm.avail_in) {
766
cli_errmsg("cli_scanxz: premature end of compressed stream\n");
772
/* xz decompress a chunk */
773
rc = cli_XzDecode(&strm);
774
if (XZ_RESULT_OK != rc && XZ_STREAM_END != rc) {
775
cli_errmsg("cli_scanxz: decompress error: %d\n", rc);
779
//cli_dbgmsg("cli_scanxz: xz decompressed %li of %li available bytes\n",
780
// avail - strm.avail_in, avail);
782
/* write decompress buffer */
783
if (!strm.avail_out || rc == XZ_STREAM_END) {
784
size_t towrite = CLI_XZ_OBUF_SIZE - strm.avail_out;
787
//cli_dbgmsg("Writing %li bytes to XZ decompress temp file(%li byte total)\n",
790
if((size_t)cli_writen(fd, buf, towrite) != towrite) {
791
cli_errmsg("cli_scanxz: Can't write to file.\n");
795
if (cli_checklimits("cli_scanxz", ctx, size, 0, 0) != CL_CLEAN) {
796
cli_warnmsg("cli_scanxz: decompress file size exceeds limits - "
797
"only scanning %li bytes\n", size);
801
strm.avail_out = CLI_XZ_OBUF_SIZE;
803
} while (XZ_STREAM_END != rc);
805
/* scan decompressed file */
806
if ((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
807
cli_dbgmsg("cli_scanxz: Infected with %s\n", cli_get_last_virus(ctx));
811
cli_XzShutdown(&strm);
813
if(!ctx->engine->keeptmp)
814
if (cli_unlink(tmpname) && ret == CL_CLEAN)
821
static int cli_scanszdd(cli_ctx *ctx)
827
cli_dbgmsg("in cli_scanszdd()\n");
829
if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &ofd))) {
830
cli_dbgmsg("MSEXPAND: Can't generate temporary file/descriptor\n");
834
ret = cli_msexpand(ctx, ofd);
836
if(ret != CL_SUCCESS) { /* CL_VIRUS or some error */
838
if(!ctx->engine->keeptmp)
839
if (cli_unlink(tmpname)) ret = CL_EUNLINK;
844
cli_dbgmsg("MSEXPAND: Decompressed into %s\n", tmpname);
845
ret = cli_magic_scandesc(ofd, ctx);
847
if(!ctx->engine->keeptmp)
848
if (cli_unlink(tmpname)) ret = CL_EUNLINK;
854
static int vba_scandata(const unsigned char *data, unsigned int len, cli_ctx *ctx)
856
struct cli_matcher *groot = ctx->engine->root[0];
857
struct cli_matcher *troot = ctx->engine->root[2];
858
struct cli_ac_data gmdata, tmdata;
859
struct cli_ac_data *mdata[2];
861
unsigned int viruses_found = 0;
863
if((ret = cli_ac_initdata(&tmdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
866
if((ret = cli_ac_initdata(&gmdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) {
867
cli_ac_freedata(&tmdata);
873
ret = cli_scanbuff(data, len, 0, ctx, CL_TYPE_MSOLE2, mdata);
877
if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
878
ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL);
882
if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL))
883
ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL);
885
cli_ac_freedata(&tmdata);
886
cli_ac_freedata(&gmdata);
888
return (ret != CL_CLEAN)?ret:viruses_found?CL_VIRUS:CL_CLEAN;
891
static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
893
int ret = CL_CLEAN, i, j, fd, data_len, hasmacros = 0;
894
vba_project_t *vba_project;
897
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
900
char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
904
char *fullname, vbaname[1024];
908
unsigned int viruses_found = 0;
911
cli_dbgmsg("VBADir: %s\n", dirname);
912
hashcnt = uniq_get(U, "_vba_project", 12, NULL);
914
if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue;
916
for(i = 0; i < vba_project->count; i++) {
917
for(j = 0; (unsigned int)j < vba_project->colls[i]; j++) {
918
snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", vba_project->dir, vba_project->name[i], j);
919
vbaname[sizeof(vbaname)-1] = '\0';
920
fd = open(vbaname, O_RDONLY|O_BINARY);
921
if(fd == -1) continue;
922
cli_dbgmsg("VBADir: Decompress VBA project '%s_%u'\n", vba_project->name[i], j);
923
data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
927
cli_dbgmsg("VBADir: WARNING: VBA project '%s_%u' decompressed to NULL\n", vba_project->name[i], j);
929
/* cli_dbgmsg("Project content:\n%s", data); */
931
*ctx->scanned += data_len / CL_COUNT_PRECISION;
932
if(vba_scandata(data, data_len, ctx) == CL_VIRUS) {
946
free(vba_project->name);
947
free(vba_project->colls);
948
free(vba_project->dir);
949
free(vba_project->offset);
951
if (ret == CL_VIRUS && !SCAN_ALL)
955
if((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) &&
956
(hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
958
snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
959
vbaname[sizeof(vbaname)-1] = '\0';
960
fd = open(vbaname, O_RDONLY|O_BINARY);
961
if (fd == -1) continue;
962
if ((fullname = cli_ppt_vba_read(fd, ctx))) {
963
if(cli_scandir(fullname, ctx) == CL_VIRUS) {
967
if(!ctx->engine->keeptmp)
968
cli_rmdirs(fullname);
975
if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) &&
976
(hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
978
snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
979
vbaname[sizeof(vbaname)-1] = '\0';
980
fd = open(vbaname, O_RDONLY|O_BINARY);
981
if (fd == -1) continue;
983
if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) {
988
for (i = 0; i < vba_project->count; i++) {
989
cli_dbgmsg("VBADir: Decompress WM project macro:%d key:%d length:%d\n", i, vba_project->key[i], vba_project->length[i]);
990
data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]);
992
cli_dbgmsg("VBADir: WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i);
994
cli_dbgmsg("Project content:\n%s", data);
996
*ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION;
997
if(vba_scandata(data, vba_project->length[i], ctx) == CL_VIRUS) {
1011
free(vba_project->name);
1012
free(vba_project->colls);
1013
free(vba_project->dir);
1014
free(vba_project->offset);
1015
free(vba_project->key);
1016
free(vba_project->length);
1018
if(ret == CL_VIRUS) {
1027
if(ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
1031
/* JSON Output Summary Information */
1032
if (ctx->options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL) {
1033
hashcnt = uniq_get(U, "_5_summaryinformation", 21, &hash);
1035
snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
1036
vbaname[sizeof(vbaname)-1] = '\0';
1038
fd = open(vbaname, O_RDONLY|O_BINARY);
1040
cli_dbgmsg("VBADir: detected a '_5_summaryinformation' stream\n");
1041
/* JSONOLE2 - what to do if something breaks? */
1042
cli_ole2_summary_json(ctx, fd, 0);
1047
hashcnt = uniq_get(U, "_5_documentsummaryinformation", 29, &hash);
1049
snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
1050
vbaname[sizeof(vbaname)-1] = '\0';
1052
fd = open(vbaname, O_RDONLY|O_BINARY);
1054
cli_dbgmsg("VBADir: detected a '_5_documentsummaryinformation' stream\n");
1055
/* JSONOLE2 - what to do if something breaks? */
1056
cli_ole2_summary_json(ctx, fd, 1);
1063
/* Check directory for embedded OLE objects */
1064
hashcnt = uniq_get(U, "_1_ole10native", 14, &hash);
1066
snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
1067
vbaname[sizeof(vbaname)-1] = '\0';
1069
fd = open(vbaname, O_RDONLY|O_BINARY);
1071
ret = cli_scan_ole10(fd, ctx);
1073
if(ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
1079
/* ACAB: since we now hash filenames and handle collisions we
1080
* could avoid recursion by removing the block below and by
1081
* flattening the paths in ole2_walk_property_tree (case 1) */
1083
if((dd = opendir(dirname)) != NULL) {
1084
#ifdef HAVE_READDIR_R_3
1085
while(!readdir_r(dd, &result.d, &dent) && dent) {
1086
#elif defined(HAVE_READDIR_R_2)
1087
while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
1089
while((dent = readdir(dd))) {
1093
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
1094
/* build the full name */
1095
fullname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
1097
cli_dbgmsg("cli_vba_scandir: Unable to allocate memory for fullname\n");
1101
sprintf(fullname, "%s"PATHSEP"%s", dirname, dent->d_name);
1104
if(LSTAT(fullname, &statbuf) != -1) {
1105
if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
1106
if (cli_vba_scandir(fullname, ctx, U) == CL_VIRUS) {
1121
cli_dbgmsg("VBADir: Can't open directory %s.\n", dirname);
1127
if (hasmacros && ctx->options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL)
1128
cli_jsonbool(ctx->wrkproperty, "HasMacros", 1);
1130
if(BLOCK_MACROS && hasmacros) {
1131
cli_append_virus(ctx, "Heuristics.OLE2.ContainsMacros");
1135
if (SCAN_ALL && viruses_found)
1140
static int cli_scanhtml(cli_ctx *ctx)
1142
char *tempname, fullname[1024];
1143
int ret=CL_CLEAN, fd;
1144
fmap_t *map = *ctx->fmap;
1145
unsigned int viruses_found = 0;
1146
uint64_t curr_len = map->len;
1148
cli_dbgmsg("in cli_scanhtml()\n");
1150
/* CL_ENGINE_MAX_HTMLNORMALIZE */
1151
if(curr_len > ctx->engine->maxhtmlnormalize) {
1152
cli_dbgmsg("cli_scanhtml: exiting (file larger than MaxHTMLNormalize)\n");
1156
if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
1159
if(mkdir(tempname, 0700)) {
1160
cli_errmsg("cli_scanhtml: Can't create temporary directory %s\n", tempname);
1165
cli_dbgmsg("cli_scanhtml: using tempdir %s\n", tempname);
1167
html_normalise_map(map, tempname, NULL, ctx->dconf);
1168
snprintf(fullname, 1024, "%s"PATHSEP"nocomment.html", tempname);
1169
fd = open(fullname, O_RDONLY|O_BINARY);
1171
if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
1176
if(ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
1177
/* CL_ENGINE_MAX_HTMLNOTAGS */
1178
curr_len = map->len;
1179
if (curr_len > ctx->engine->maxhtmlnotags) {
1180
/* we're not interested in scanning large files in notags form */
1181
/* TODO: don't even create notags if file is over limit */
1182
cli_dbgmsg("cli_scanhtml: skipping notags (normalized size over MaxHTMLNoTags)\n");
1185
snprintf(fullname, 1024, "%s"PATHSEP"notags.html", tempname);
1186
fd = open(fullname, O_RDONLY|O_BINARY);
1188
if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
1195
if(ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
1196
snprintf(fullname, 1024, "%s"PATHSEP"javascript", tempname);
1197
fd = open(fullname, O_RDONLY|O_BINARY);
1199
if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
1201
if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
1202
if ((ret = cli_scandesc(fd, ctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
1209
if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
1210
snprintf(fullname, 1024, "%s"PATHSEP"rfc2397", tempname);
1211
ret = cli_scandir(fullname, ctx);
1214
if(!ctx->engine->keeptmp)
1215
cli_rmdirs(tempname);
1218
if (SCAN_ALL && viruses_found)
1223
static int cli_scanscript(cli_ctx *ctx)
1225
const unsigned char *buff;
1226
unsigned char* normalized;
1227
struct text_norm_state state;
1228
char *tmpname = NULL;
1230
struct cli_matcher *troot;
1231
uint32_t maxpatlen, offset = 0;
1232
struct cli_matcher *groot;
1233
struct cli_ac_data gmdata, tmdata;
1234
struct cli_ac_data *mdata[2];
1237
unsigned int viruses_found = 0;
1239
struct cli_target_info info;
1241
if (!ctx || !ctx->engine->root)
1245
curr_len = map->len;
1246
groot = ctx->engine->root[0];
1247
troot = ctx->engine->root[7];
1248
maxpatlen = troot ? troot->maxpatlen : 0;
1250
cli_dbgmsg("in cli_scanscript()\n");
1252
/* CL_ENGINE_MAX_SCRIPTNORMALIZE */
1253
if(curr_len > ctx->engine->maxscriptnormalize) {
1254
cli_dbgmsg("cli_scanscript: exiting (file larger than MaxScriptSize)\n");
1258
/* dump to disk only if explicitly asked to,
1259
* otherwise we can process just in-memory */
1260
if(ctx->engine->keeptmp) {
1261
if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &ofd))) {
1262
cli_dbgmsg("cli_scanscript: Can't generate temporary file/descriptor\n");
1265
cli_dbgmsg("cli_scanscript: saving normalized file to %s\n", tmpname);
1268
if(!(normalized = cli_malloc(SCANBUFF + maxpatlen))) {
1269
cli_dbgmsg("cli_scanscript: Unable to malloc %u bytes\n", SCANBUFF);
1274
text_normalize_init(&state, normalized, SCANBUFF + maxpatlen);
1277
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))) {
1283
cli_targetinfo(&info, 7, map);
1284
ret = cli_ac_caloff(troot, &tmdata, &info);
1286
cli_ac_freedata(&tmdata);
1292
if ((ret = cli_ac_initdata(&gmdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) {
1293
cli_ac_freedata(&tmdata);
1301
size_t len = MIN(map->pgsz, map->len - at);
1302
buff = fmap_need_off_once(map, at, len);
1304
if(!buff || !len || state.out_pos + len > state.out_len) {
1305
/* flush if error/EOF, or too little buffer space left */
1306
if((ofd != -1) && (write(ofd, state.out, state.out_pos) == -1)) {
1307
cli_errmsg("cli_scanscript: can't write to file %s\n",tmpname);
1310
/* we can continue to scan in memory */
1312
/* when we flush the buffer also scan */
1313
if(cli_scanbuff(state.out, state.out_pos, offset, ctx, CL_TYPE_TEXT_ASCII, mdata) == CL_VIRUS) {
1322
*ctx->scanned += state.out_pos / CL_COUNT_PRECISION;
1323
offset += state.out_pos;
1324
/* carry over maxpatlen from previous buffer */
1325
if (state.out_pos > maxpatlen)
1326
memmove(state.out, state.out + state.out_pos - maxpatlen, maxpatlen);
1327
text_normalize_reset(&state);
1328
state.out_pos = maxpatlen;
1331
if(!buff || text_normalize_buffer(&state, buff, len) != len) {
1332
cli_dbgmsg("cli_scanscript: short read during normalizing\n");
1335
if(ctx->engine->keeptmp) {
1341
if(ret != CL_VIRUS || SCAN_ALL) {
1342
if ((ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL)) == CL_VIRUS)
1344
if(ret != CL_VIRUS || SCAN_ALL)
1345
if ((ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL)) == CL_VIRUS)
1348
cli_ac_freedata(&tmdata);
1349
cli_ac_freedata(&gmdata);
1351
if (SCAN_ALL && viruses_found)
1356
static int cli_scanhtml_utf16(cli_ctx *ctx)
1358
char *tempname, *decoded;
1360
int ret = CL_CLEAN, fd, bytes;
1362
fmap_t *map = *ctx->fmap;
1364
cli_dbgmsg("in cli_scanhtml_utf16()\n");
1366
if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
1369
if((fd = open(tempname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
1370
cli_errmsg("cli_scanhtml_utf16: Can't create file %s\n", tempname);
1375
cli_dbgmsg("cli_scanhtml_utf16: using tempfile %s\n", tempname);
1377
while(at < map->len) {
1378
bytes = MIN(map->len - at, map->pgsz * 16);
1379
if(!(buff = fmap_need_off_once(map, at, bytes))) {
1381
cli_unlink(tempname);
1386
decoded = cli_utf16toascii(buff, bytes);
1388
if(write(fd, decoded, bytes / 2) == -1) {
1389
cli_errmsg("cli_scanhtml_utf16: Can't write to file %s\n", tempname);
1392
cli_unlink(tempname);
1400
*ctx->fmap = fmap(fd, 0, 0);
1402
ret = cli_scanhtml(ctx);
1405
cli_errmsg("cli_scanhtml_utf16: fmap of %s failed\n", tempname);
1410
if(!ctx->engine->keeptmp) {
1411
if (cli_unlink(tempname)) ret = CL_EUNLINK;
1413
cli_dbgmsg("cli_scanhtml_utf16: Decoded HTML data saved in %s\n", tempname);
1419
static int cli_scanole2(cli_ctx *ctx)
1423
struct uniq *vba = NULL;
1425
cli_dbgmsg("in cli_scanole2()\n");
1427
if(ctx->engine->maxreclevel && ctx->recursion >= ctx->engine->maxreclevel)
1430
/* generate the temporary directory */
1431
if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1434
if(mkdir(dir, 0700)) {
1435
cli_dbgmsg("OLE2: Can't create temporary directory %s\n", dir);
1440
ret = cli_ole2_extract(dir, ctx, &vba);
1441
if(ret!=CL_CLEAN && ret!=CL_VIRUS) {
1442
cli_dbgmsg("OLE2: %s\n", cl_strerror(ret));
1443
if(!ctx->engine->keeptmp)
1452
ret = cli_vba_scandir(dir, ctx, vba);
1455
if(cli_scandir(dir, ctx) == CL_VIRUS)
1460
if(!ctx->engine->keeptmp)
1466
static int cli_scantar(cli_ctx *ctx, unsigned int posix)
1472
cli_dbgmsg("in cli_scantar()\n");
1474
/* generate temporary directory */
1475
if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1478
if(mkdir(dir, 0700)) {
1479
cli_errmsg("Tar: Can't create temporary directory %s\n", dir);
1484
ret = cli_untar(dir, posix, ctx);
1486
if(!ctx->engine->keeptmp)
1493
static int cli_scanscrenc(cli_ctx *ctx)
1498
cli_dbgmsg("in cli_scanscrenc()\n");
1500
if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
1503
if(mkdir(tempname, 0700)) {
1504
cli_dbgmsg("CHM: Can't create temporary directory %s\n", tempname);
1509
if (html_screnc_decode(*ctx->fmap, tempname))
1510
ret = cli_scandir(tempname, ctx);
1512
if(!ctx->engine->keeptmp)
1513
cli_rmdirs(tempname);
1519
static int cli_scanriff(cli_ctx *ctx)
1523
if(cli_check_riff_exploit(ctx) == 2) {
1525
cli_append_virus(ctx, "Heuristics.Exploit.W32.MS05-002");
1531
static int cli_scanjpeg(cli_ctx *ctx)
1535
if(cli_check_jpeg_exploit(ctx, 0) == 1) {
1537
cli_append_virus(ctx, "Heuristics.Exploit.W32.MS04-028");
1543
static int cli_scancryptff(cli_ctx *ctx)
1545
int ret = CL_CLEAN, ndesc;
1547
const unsigned char *src;
1548
unsigned char *dest = NULL;
1554
/* Skip the CryptFF file header */
1557
if((dest = (unsigned char *) cli_malloc(FILEBUFF)) == NULL) {
1558
cli_dbgmsg("CryptFF: Can't allocate memory\n");
1562
if(!(tempfile = cli_gentemp(ctx->engine->tmpdir))) {
1567
if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
1568
cli_errmsg("CryptFF: Can't create file %s\n", tempfile);
1574
for(; (src = fmap_need_off_once_len(*ctx->fmap, pos, FILEBUFF, &bread)) && bread; pos += bread) {
1575
for (i=0;i<bread;i++)
1576
dest[i] = src[i] ^ (unsigned char) 0xff;
1577
if(cli_writen(ndesc, dest, bread) == -1) {
1578
cli_dbgmsg("CryptFF: Can't write to descriptor %d\n", ndesc);
1589
cli_dbgmsg("CryptFF: Scanning decrypted data\n");
1591
if((ret = cli_magic_scandesc(ndesc, ctx)) == CL_VIRUS)
1592
cli_dbgmsg("CryptFF: Infected with %s\n", cli_get_last_virus(ctx));
1596
if(ctx->engine->keeptmp)
1597
cli_dbgmsg("CryptFF: Decompressed data saved in %s\n", tempfile);
1599
if (cli_unlink(tempfile)) ret = CL_EUNLINK;
1605
static int cli_scanpdf(cli_ctx *ctx, off_t offset)
1608
char *dir = cli_gentemp(ctx->engine->tmpdir);
1613
if(mkdir(dir, 0700)) {
1614
cli_dbgmsg("Can't create temporary directory for PDF file %s\n", dir);
1619
ret = cli_pdf(dir, ctx, offset);
1621
if(!ctx->engine->keeptmp)
1628
static int cli_scantnef(cli_ctx *ctx)
1631
char *dir = cli_gentemp(ctx->engine->tmpdir);
1636
if(mkdir(dir, 0700)) {
1637
cli_dbgmsg("Can't create temporary directory for tnef file %s\n", dir);
1642
ret = cli_tnef(dir, ctx);
1645
ret = cli_scandir(dir, ctx);
1647
if(!ctx->engine->keeptmp)
1654
static int cli_scanuuencoded(cli_ctx *ctx)
1657
char *dir = cli_gentemp(ctx->engine->tmpdir);
1662
if(mkdir(dir, 0700)) {
1663
cli_dbgmsg("Can't create temporary directory for uuencoded file %s\n", dir);
1668
ret = cli_uuencode(dir, *ctx->fmap);
1671
ret = cli_scandir(dir, ctx);
1673
if(!ctx->engine->keeptmp)
1680
static int cli_scanmail(cli_ctx *ctx)
1684
unsigned int viruses_found = 0;
1686
cli_dbgmsg("Starting cli_scanmail(), recursion = %u\n", ctx->recursion);
1688
/* generate the temporary directory */
1689
if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1692
if(mkdir(dir, 0700)) {
1693
cli_dbgmsg("Mail: Can't create temporary directory %s\n", dir);
1699
* Extract the attachments into the temporary directory
1701
if((ret = cli_mbox(dir, ctx))) {
1702
if (ret == CL_VIRUS && SCAN_ALL)
1705
if(!ctx->engine->keeptmp)
1712
ret = cli_scandir(dir, ctx);
1714
if(!ctx->engine->keeptmp)
1718
if (SCAN_ALL && viruses_found)
1723
static int cli_scan_structured(cli_ctx *ctx)
1727
unsigned int cc_count = 0;
1728
unsigned int ssn_count = 0;
1732
int (*ccfunc)(const unsigned char *buffer, int length);
1733
int (*ssnfunc)(const unsigned char *buffer, int length);
1734
unsigned int viruses_found = 0;
1741
if(ctx->engine->min_cc_count == 1)
1742
ccfunc = dlp_has_cc;
1744
ccfunc = dlp_get_cc_count;
1746
switch((ctx->options & CL_SCAN_STRUCTURED_SSN_NORMAL) | (ctx->options & CL_SCAN_STRUCTURED_SSN_STRIPPED)) {
1748
case (CL_SCAN_STRUCTURED_SSN_NORMAL | CL_SCAN_STRUCTURED_SSN_STRIPPED):
1749
if(ctx->engine->min_ssn_count == 1)
1750
ssnfunc = dlp_has_ssn;
1752
ssnfunc = dlp_get_ssn_count;
1755
case CL_SCAN_STRUCTURED_SSN_NORMAL:
1756
if(ctx->engine->min_ssn_count == 1)
1757
ssnfunc = dlp_has_normal_ssn;
1759
ssnfunc = dlp_get_normal_ssn_count;
1762
case CL_SCAN_STRUCTURED_SSN_STRIPPED:
1763
if(ctx->engine->min_ssn_count == 1)
1764
ssnfunc = dlp_has_stripped_ssn;
1766
ssnfunc = dlp_get_stripped_ssn_count;
1773
while(!done && ((result = fmap_readn(map, buf, pos, 8191)) > 0)) {
1775
if((cc_count += ccfunc((const unsigned char *)buf, result)) >= ctx->engine->min_cc_count)
1778
if(ssnfunc && ((ssn_count += ssnfunc((const unsigned char *)buf, result)) >= ctx->engine->min_ssn_count))
1782
if(cc_count != 0 && cc_count >= ctx->engine->min_cc_count) {
1783
cli_dbgmsg("cli_scan_structured: %u credit card numbers detected\n", cc_count);
1784
cli_append_virus(ctx,"Heuristics.Structured.CreditCardNumber");
1791
if(ssn_count != 0 && ssn_count >= ctx->engine->min_ssn_count) {
1792
cli_dbgmsg("cli_scan_structured: %u social security numbers detected\n", ssn_count);
1793
cli_append_virus(ctx,"Heuristics.Structured.SSN");
1800
if (SCAN_ALL && viruses_found)
1805
static int cli_scanembpe(cli_ctx *ctx, off_t offset)
1807
int fd, bytes, ret = CL_CLEAN;
1808
unsigned long int size = 0, todo;
1811
fmap_t *map = *ctx->fmap;
1812
unsigned int corrupted_input;
1814
tmpname = cli_gentemp(ctx->engine->tmpdir);
1818
if((fd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
1819
cli_errmsg("cli_scanembpe: Can't create file %s\n", tmpname);
1824
todo = map->len - offset;
1826
bytes = MIN(todo, map->pgsz);
1830
if(!(buff = fmap_need_off_once(map, offset + size, bytes))) {
1832
if(!ctx->engine->keeptmp) {
1833
if (cli_unlink(tmpname)) {
1844
if(cli_checklimits("cli_scanembpe", ctx, size, 0, 0)!=CL_CLEAN)
1847
if(cli_writen(fd, buff, bytes) != bytes) {
1848
cli_dbgmsg("cli_scanembpe: Can't write to temporary file\n");
1850
if(!ctx->engine->keeptmp) {
1851
if (cli_unlink(tmpname)) {
1862
corrupted_input = ctx->corrupted_input;
1863
ctx->corrupted_input = 1;
1864
ret = cli_magic_scandesc(fd, ctx);
1865
ctx->corrupted_input = corrupted_input;
1866
if(ret == CL_VIRUS) {
1867
cli_dbgmsg("cli_scanembpe: Infected with %s\n", cli_get_last_virus(ctx));
1869
if(!ctx->engine->keeptmp) {
1870
if (cli_unlink(tmpname)) {
1881
if(!ctx->engine->keeptmp) {
1882
if (cli_unlink(tmpname)) {
1889
/* intentionally ignore possible errors from cli_magic_scandesc */
1894
#if defined(_WIN32) || defined(C_LINUX)
1895
#define PERF_MEASURE
1905
{PERFT_SCAN, "full scan", ev_time},
1906
{PERFT_PRECB, "prescan cb", ev_time},
1907
{PERFT_POSTCB, "postscan cb", ev_time},
1908
{PERFT_CACHE, "cache", ev_time},
1909
{PERFT_FT, "filetype", ev_time},
1910
{PERFT_CONTAINER, "container", ev_time},
1911
{PERFT_SCRIPT, "script", ev_time},
1912
{PERFT_PE, "pe", ev_time},
1913
{PERFT_RAW, "raw", ev_time},
1914
{PERFT_RAWTYPENO, "raw container", ev_time},
1915
{PERFT_MAP, "map", ev_time},
1916
{PERFT_BYTECODE,"bytecode", ev_time},
1917
{PERFT_KTIME,"kernel", ev_int},
1918
{PERFT_UTIME,"user", ev_int}
1921
static void get_thread_times(uint64_t *kt, uint64_t *ut)
1925
ULARGE_INTEGER kl,ul;
1926
if (!GetThreadTimes(GetCurrentThread(), &c, &e, &k, &u)) {
1930
kl.LowPart = k.dwLowDateTime;
1931
kl.HighPart = k.dwHighDateTime;
1932
ul.LowPart = u.dwLowDateTime;
1933
ul.HighPart = u.dwHighDateTime;
1934
*kt = kl.QuadPart / 10;
1935
*ut = ul.QuadPart / 10;
1938
if (times(&tbuf) != -1) {
1939
clock_t tck = sysconf(_SC_CLK_TCK);
1940
*kt = ((uint64_t)1000000)*tbuf.tms_stime / tck;
1941
*ut = ((uint64_t)1000000)*tbuf.tms_utime / tck;
1948
static inline void perf_init(cli_ctx *ctx)
1953
if (!(ctx->options & CL_SCAN_PERFORMANCE_INFO))
1956
ctx->perf = cli_events_new(PERFT_LAST);
1957
for (i=0;i<sizeof(perf_events)/sizeof(perf_events[0]);i++) {
1958
if (cli_event_define(ctx->perf, perf_events[i].id, perf_events[i].name,
1959
perf_events[i].type, multiple_sum) == -1)
1962
cli_event_time_start(ctx->perf, PERFT_SCAN);
1963
get_thread_times(&kt, &ut);
1964
cli_event_int(ctx->perf, PERFT_KTIME, -kt);
1965
cli_event_int(ctx->perf, PERFT_UTIME, -ut);
1968
static inline void perf_done(cli_ctx* ctx)
1975
cli_events_t *perf = ctx->perf;
1981
pend = timestr + sizeof(timestr) - 1;
1984
cli_event_time_stop(perf, PERFT_SCAN);
1985
get_thread_times(&kt, &ut);
1986
cli_event_int(perf, PERFT_KTIME, kt);
1987
cli_event_int(perf, PERFT_UTIME, ut);
1989
for (i=0;i<sizeof(perf_events)/sizeof(perf_events[0]);i++) {
1993
cli_event_get(perf, perf_events[i].id, &val, &count);
1995
p += snprintf(p, pend - p, "%s: %d.%03ums, ", perf_events[i].name,
1996
(signed)(val.v_int / 1000),
1997
(unsigned)(val.v_int % 1000));
2000
cli_infomsg(ctx, "performance: %s\n", timestr);
2003
cli_events_free(perf);
2007
static inline void perf_start(cli_ctx* ctx, int id)
2009
cli_event_time_start(ctx->perf, id);
2012
static inline void perf_stop(cli_ctx* ctx, int id)
2014
cli_event_time_stop(ctx->perf, id);
2017
static inline void perf_nested_start(cli_ctx* ctx, int id, int nestedid)
2019
cli_event_time_nested_start(ctx->perf, id, nestedid);
2022
static inline void perf_nested_stop(cli_ctx* ctx, int id, int nestedid)
2024
cli_event_time_nested_stop(ctx->perf, id, nestedid);
2029
static inline void perf_init(cli_ctx* ctx) { UNUSEDPARAM(ctx); }
2030
static inline void perf_start(cli_ctx* ctx, int id){ UNUSEDPARAM(ctx); UNUSEDPARAM(id); }
2031
static inline void perf_stop(cli_ctx* ctx, int id){ UNUSEDPARAM(ctx); UNUSEDPARAM(id); }
2032
static inline void perf_nested_start(cli_ctx* ctx, int id, int nestedid){ UNUSEDPARAM(ctx); UNUSEDPARAM(id); UNUSEDPARAM(nestedid); }
2033
static inline void perf_nested_stop(cli_ctx* ctx, int id, int nestedid){ UNUSEDPARAM(ctx); UNUSEDPARAM(id); UNUSEDPARAM(nestedid); }
2034
static inline void perf_done(cli_ctx* ctx){ UNUSEDPARAM(ctx); }
2038
static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_t *dettype, unsigned char *refhash)
2040
int ret = CL_CLEAN, nret = CL_CLEAN;
2041
struct cli_matched_type *ftoffset = NULL, *fpt;
2043
struct cli_exe_info peinfo;
2044
unsigned int acmode = AC_SCAN_VIR, break_loop = 0;
2045
fmap_t *map = *ctx->fmap;
2046
cli_file_t current_container_type = ctx->container_type;
2047
size_t current_container_size = ctx->container_size;
2050
if(ctx->engine->maxreclevel && ctx->recursion >= ctx->engine->maxreclevel)
2053
perf_start(ctx, PERFT_RAW);
2055
acmode |= AC_SCAN_FT;
2057
ret = cli_fmap_scandesc(ctx, type == CL_TYPE_TEXT_ASCII ? 0 : type, 0, &ftoffset, acmode, NULL, refhash);
2058
perf_stop(ctx, PERFT_RAW);
2060
if(ret >= CL_TYPENO) {
2061
perf_nested_start(ctx, PERFT_RAWTYPENO, PERFT_SCAN);
2063
lastrar = 0xdeadbeef;
2067
if(fpt->offset) switch(fpt->type) {
2069
ret = cli_scanxdp(ctx);
2071
case CL_TYPE_RARSFX:
2072
if(type != CL_TYPE_RAR && have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR)) {
2073
char *tmpname = NULL;
2074
int tmpfd = fmap_fd(map);
2075
ctx->container_type = CL_TYPE_RAR;
2076
ctx->container_size = map->len - fpt->offset; /* not precise */
2077
cli_dbgmsg("RAR/RAR-SFX signature found at %u\n", (unsigned int) fpt->offset);
2078
/* if map is not file-backed, have to dump to file for scanrar */
2080
nret = fmap_dump_to_file(map, ctx->engine->tmpdir, &tmpname, &tmpfd);
2081
if(nret != CL_SUCCESS) {
2082
cli_dbgmsg("cli_scanraw: failed to generate temporary file.\n");
2088
/* scan existing file */
2089
nret = cli_scanrar(tmpfd, ctx, fpt->offset, &lastrar);
2090
/* if dumped tempfile, need to cleanup */
2093
if(!ctx->engine->keeptmp) {
2094
if (cli_unlink(tmpname)) {
2095
ret = nret = CL_EUNLINK;
2104
case CL_TYPE_ZIPSFX:
2105
if(type != CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP)) {
2106
ctx->container_type = CL_TYPE_ZIP;
2107
ctx->container_size = map->len - fpt->offset; /* not precise */
2108
cli_dbgmsg("ZIP/ZIP-SFX signature found at %u\n", (unsigned int) fpt->offset);
2109
nret = cli_unzip_single(ctx, fpt->offset);
2113
case CL_TYPE_CABSFX:
2114
if(type != CL_TYPE_MSCAB && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB)) {
2115
ctx->container_type = CL_TYPE_MSCAB;
2116
ctx->container_size = map->len - fpt->offset; /* not precise */
2117
cli_dbgmsg("CAB/CAB-SFX signature found at %u\n", (unsigned int) fpt->offset);
2118
nret = cli_scanmscab(ctx, fpt->offset);
2122
case CL_TYPE_ARJSFX:
2123
if(type != CL_TYPE_ARJ && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ)) {
2124
ctx->container_type = CL_TYPE_ARJ;
2125
ctx->container_size = map->len - fpt->offset; /* not precise */
2126
cli_dbgmsg("ARJ-SFX signature found at %u\n", (unsigned int) fpt->offset);
2127
nret = cli_scanarj(ctx, fpt->offset, &lastrar);
2132
if(type != CL_TYPE_7Z && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z)) {
2133
ctx->container_type = CL_TYPE_7Z;
2134
ctx->container_size = map->len - fpt->offset; /* not precise */
2135
cli_dbgmsg("7Zip-SFX signature found at %u\n", (unsigned int) fpt->offset);
2136
nret = cli_7unz(ctx, fpt->offset);
2140
case CL_TYPE_ISO9660:
2141
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ISO9660)) {
2142
ctx->container_type = CL_TYPE_ISO9660;
2143
ctx->container_size = map->len - fpt->offset; /* not precise */
2144
cli_dbgmsg("ISO9660 signature found at %u\n", (unsigned int) fpt->offset);
2145
nret = cli_scaniso(ctx, fpt->offset);
2149
case CL_TYPE_NULSFT:
2150
if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_NSIS) &&
2152
ctx->container_type = CL_TYPE_NULSFT;
2153
ctx->container_size = map->len - fpt->offset; /* not precise */
2154
cli_dbgmsg("NSIS signature found at %u\n", (unsigned int) fpt->offset-4);
2155
nret = cli_scannulsft(ctx, fpt->offset - 4);
2159
case CL_TYPE_AUTOIT:
2160
if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_AUTOIT)) {
2161
ctx->container_type = CL_TYPE_AUTOIT;
2162
ctx->container_size = map->len - fpt->offset; /* not precise */
2163
cli_dbgmsg("AUTOIT signature found at %u\n", (unsigned int) fpt->offset);
2164
nret = cli_scanautoit(ctx, fpt->offset + 23);
2168
case CL_TYPE_ISHIELD_MSI:
2169
if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_ISHIELD)) {
2170
ctx->container_type = CL_TYPE_AUTOIT;
2171
ctx->container_size = map->len - fpt->offset; /* not precise */
2172
cli_dbgmsg("ISHIELD-MSI signature found at %u\n", (unsigned int) fpt->offset);
2173
nret = cli_scanishield_msi(ctx, fpt->offset + 14);
2178
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_DMG)) {
2179
ctx->container_type = CL_TYPE_DMG;
2180
nret = cli_scandmg(ctx);
2181
cli_dbgmsg("DMG signature found at %u\n", (unsigned int) fpt->offset);
2187
int iret = cli_mbr_check2(ctx, 0);
2188
if (iret == CL_TYPE_GPT) {
2189
cli_dbgmsg("Recognized GUID Partition Table file\n");
2190
ctx->container_type = CL_TYPE_GPT;
2191
nret = cli_scangpt(ctx, 0);
2192
cli_dbgmsg("GPT signature found at %u\n", (unsigned int) fpt->offset);
2194
else if (iret == CL_CLEAN) {
2195
ctx->container_type = CL_TYPE_MBR;
2196
nret = cli_scanmbr(ctx, 0);
2197
cli_dbgmsg("MBR signature found at %u\n", (unsigned int) fpt->offset);
2203
if(type != CL_TYPE_PDF && SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF)) {
2204
ctx->container_type = CL_TYPE_PDF;
2205
ctx->container_size = map->len - fpt->offset; /* not precise */
2206
cli_dbgmsg("PDF signature found at %u\n", (unsigned int) fpt->offset);
2207
nret = cli_scanpdf(ctx, fpt->offset);
2212
if(SCAN_PE && (type == CL_TYPE_MSEXE || type == CL_TYPE_ZIP || type == CL_TYPE_MSOLE2)
2213
&& ctx->dconf->pe) {
2214
uint64_t curr_len = map->len;
2215
/* CL_ENGINE_MAX_EMBEDDED_PE */
2216
if(curr_len > ctx->engine->maxembeddedpe) {
2217
cli_dbgmsg("cli_scanraw: MaxEmbeddedPE exceeded\n");
2220
ctx->container_type = CL_TYPE_MSEXE; /* PE is a container for another executable here */
2221
ctx->container_size = map->len - fpt->offset; /* not precise */
2222
memset(&peinfo, 0, sizeof(struct cli_exe_info));
2223
peinfo.offset = fpt->offset;
2224
if(cli_peheader(map, &peinfo) == 0) {
2225
cli_dbgmsg("*** Detected embedded PE file at %u ***\n",
2226
(unsigned int) fpt->offset);
2228
free(peinfo.section);
2229
cli_hashset_destroy(&peinfo.vinfo);
2231
nret = cli_scanembpe(ctx, fpt->offset);
2232
break_loop = 1; /* we can stop here and other
2233
* embedded executables will
2234
* be found recursively
2235
* through the above call
2242
cli_warnmsg("cli_scanraw: Type %u not handled in fpt loop\n", fpt->type);
2245
if(nret == CL_VIRUS || break_loop)
2250
ctx->container_type = current_container_type;
2251
ctx->container_size = current_container_size;
2253
if(nret != CL_VIRUS) switch(ret) {
2255
if (SCAN_HTML && (type == CL_TYPE_TEXT_ASCII || type == CL_TYPE_GRAPHICS) &&
2256
(DCONF_DOC & DOC_CONF_HTML)) {
2257
*dettype = CL_TYPE_HTML;
2258
nret = cli_scanhtml(ctx);
2263
ctx->container_type = CL_TYPE_MAIL;
2264
ctx->container_size = map->len;
2265
if(SCAN_MAIL && type == CL_TYPE_TEXT_ASCII && (DCONF_MAIL & MAIL_CONF_MBOX)) {
2266
*dettype = CL_TYPE_MAIL;
2267
nret = cli_scanmail(ctx);
2269
ctx->container_type = current_container_type;
2270
ctx->container_size = current_container_size;
2276
perf_nested_stop(ctx, PERFT_RAWTYPENO, PERFT_SCAN);
2283
ftoffset = ftoffset->next;
2288
cli_dbgmsg("%s found\n", cli_get_last_virus(ctx));
2294
static void emax_reached(cli_ctx *ctx) {
2295
fmap_t **ctx_fmap = ctx->fmap;
2299
fmap_t *map = *ctx_fmap;
2300
map->dont_cache_flag = 1;
2303
cli_dbgmsg("emax_reached: marked parents as non cacheable\n");
2306
#define LINESTR(x) #x
2307
#define LINESTR2(x) LINESTR(x)
2308
#define __AT__ " at line "LINESTR2(__LINE__)
2310
#define early_ret_from_magicscan(retcode) \
2312
cli_dbgmsg("cli_magic_scandesc: returning %d %s (no post, no cache)\n", retcode, __AT__); \
2316
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)
2319
ctx->wrkproperty = (struct json_object *)(parent_property);
2321
UNUSEDPARAM(parent_property);
2326
cli_dbgmsg("cli_magic_scandesc: returning %d %s\n", retcode, __AT__);
2327
if(ctx->engine->cb_post_scan) {
2328
perf_start(ctx, PERFT_POSTCB);
2329
switch(ctx->engine->cb_post_scan(fmap_fd(*ctx->fmap), retcode, retcode == CL_VIRUS ? cli_get_last_virus(ctx) : NULL, ctx->cb_ctx)) {
2331
cli_dbgmsg("cli_magic_scandesc: file whitelisted by post_scan callback\n");
2332
perf_stop(ctx, PERFT_POSTCB);
2335
cli_dbgmsg("cli_magic_scandesc: file blacklisted by post_scan callback\n");
2336
cli_append_virus(ctx, "Detected.By.Callback");
2337
perf_stop(ctx, PERFT_POSTCB);
2338
if (retcode != CL_VIRUS)
2339
return cli_checkfp(hash, hashed_size, ctx);
2344
cli_warnmsg("cli_magic_scandesc: ignoring bad return code from post_scan callback\n");
2346
perf_stop(ctx, PERFT_POSTCB);
2348
if (retcode == CL_CLEAN && cache_clean) {
2349
perf_start(ctx, PERFT_CACHE);
2350
cache_add(hash, hashed_size, ctx);
2351
perf_stop(ctx, PERFT_CACHE);
2356
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)
2360
UNUSEDPARAM(parent_property);
2362
UNUSEDPARAM(hashed_size);
2367
perf_start(ctx, PERFT_PRECB);
2368
switch(cb(fmap_fd(*ctx->fmap), filetype, ctx->cb_ctx)) {
2370
cli_dbgmsg("cli_magic_scandesc: file whitelisted by callback\n");
2371
perf_stop(ctx, PERFT_PRECB);
2372
ctx->hook_lsig_matches = old_hook_lsig_matches;
2373
/* returns CL_CLEAN */
2377
cli_dbgmsg("cli_magic_scandesc: file blacklisted by callback\n");
2378
cli_append_virus(ctx, "Detected.By.Callback");
2379
perf_stop(ctx, PERFT_PRECB);
2380
ctx->hook_lsig_matches = old_hook_lsig_matches;
2387
cli_warnmsg("cli_magic_scandesc: ignoring bad return code from callback\n");
2390
perf_stop(ctx, PERFT_PRECB);
2396
static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2399
cli_file_t dettype = 0;
2400
uint8_t typercg = 1;
2401
cli_file_t current_container_type = ctx->container_type;
2402
size_t current_container_size = ctx->container_size, hashed_size;
2403
unsigned char hash[16];
2404
bitset_t *old_hook_lsig_matches;
2405
const char *filetype;
2406
int cache_clean = 0, res;
2407
int run_cleanup = 0;
2409
struct json_object *parent_property = NULL;
2411
void *parent_property = NULL;
2415
cli_errmsg("CRITICAL: engine == NULL\n");
2416
early_ret_from_magicscan(CL_ENULLARG);
2419
if(!(ctx->engine->dboptions & CL_DB_COMPILED)) {
2420
cli_errmsg("CRITICAL: engine not compiled\n");
2421
early_ret_from_magicscan(CL_EMALFDB);
2424
if(ctx->engine->maxreclevel && ctx->recursion > ctx->engine->maxreclevel) {
2425
cli_dbgmsg("cli_magic_scandesc: Archive recursion limit exceeded (%u, max: %u)\n", ctx->recursion, ctx->engine->maxreclevel);
2427
early_ret_from_magicscan(CL_CLEAN);
2430
if(cli_updatelimits(ctx, (*ctx->fmap)->len)!=CL_CLEAN) {
2432
early_ret_from_magicscan(CL_CLEAN);
2434
old_hook_lsig_matches = ctx->hook_lsig_matches;
2435
if(type == CL_TYPE_PART_ANY) {
2439
perf_start(ctx, PERFT_FT);
2440
if((type == CL_TYPE_ANY) || type == CL_TYPE_PART_ANY) {
2441
type = cli_filetype2(*ctx->fmap, ctx->engine, type);
2443
perf_stop(ctx, PERFT_FT);
2444
if(type == CL_TYPE_ERROR) {
2445
cli_dbgmsg("cli_magic_scandesc: cli_filetype2 returned CL_TYPE_ERROR\n");
2446
early_ret_from_magicscan(CL_EREAD);
2448
filetype = cli_ftname(type);
2451
if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
2452
json_object *arrobj;
2454
if (NULL == ctx->properties) {
2455
if (type == CL_TYPE_PDF || /* file types we collect properties about */
2456
type == CL_TYPE_MSOLE2 ||
2457
type == CL_TYPE_MSEXE ||
2458
//type == CL_TYPE_ZIP ||
2459
type == CL_TYPE_OOXML_WORD ||
2460
type == CL_TYPE_OOXML_PPT ||
2461
type == CL_TYPE_OOXML_XL) {
2462
ctx->properties = json_object_new_object();
2463
if (NULL == ctx->properties) {
2464
cli_errmsg("magic_scandesc: no memory for json properties object\n");
2465
early_ret_from_magicscan(CL_EMEM);
2467
ctx->wrkproperty = ctx->properties;
2468
ret = cli_jsonstr(ctx->properties, "Magic", "CLAMJSONv0");
2469
if (ret != CL_SUCCESS) {
2470
early_ret_from_magicscan(ret);
2472
ret = cli_jsonstr(ctx->properties, "RootFileType", filetype);
2473
if (ret != CL_SUCCESS) {
2474
early_ret_from_magicscan(ret);
2476
} else { /* turn off property collection flag for file types we don't care about */
2477
ctx->options &= ~CL_SCAN_FILE_PROPERTIES;
2481
parent_property = ctx->wrkproperty;
2482
if (!json_object_object_get_ex(parent_property, "ContainedObjects", &arrobj)) {
2483
arrobj = json_object_new_array();
2484
if (NULL == arrobj) {
2485
cli_errmsg("magic_scandesc: no memory for json properties object\n");
2486
early_ret_from_magicscan(CL_EMEM);
2488
json_object_object_add(parent_property, "ContainedObjects", arrobj);
2490
ctx->wrkproperty = json_object_new_object();
2491
if (NULL == ctx->wrkproperty) {
2492
cli_errmsg("magic_scandesc: no memory for json properties object\n");
2493
early_ret_from_magicscan(CL_EMEM);
2495
json_object_array_add(arrobj, ctx->wrkproperty);
2499
if (ctx->options & CL_SCAN_FILE_PROPERTIES) { /* separated for cases json is not tracked */
2500
ret = cli_jsonstr(ctx->wrkproperty, "FileType", filetype);
2501
if (ret != CL_SUCCESS) {
2502
early_ret_from_magicscan(ret);
2504
ret = cli_jsonint(ctx->wrkproperty, "FileSize", (*ctx->fmap)->len);
2505
if (ret != CL_SUCCESS) {
2506
early_ret_from_magicscan(ret);
2512
ret = dispatch_prescan(ctx->engine->cb_pre_cache, ctx, filetype, old_hook_lsig_matches, parent_property, hash, hashed_size, &run_cleanup);
2514
if (ret == CL_VIRUS)
2515
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, cli_checkfp(hash, hashed_size, ctx), parent_property);
2517
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_CLEAN, parent_property);
2520
perf_start(ctx, PERFT_CACHE);
2521
res = cache_check(hash, ctx);
2524
if (SCAN_PROPERTIES /* ctx.options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL */) {
2526
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]);
2528
ret = cli_jsonstr(ctx->wrkproperty, "FileMD5", hashstr);
2529
if (ret != CL_SUCCESS) {
2530
early_ret_from_magicscan(ret);
2535
if(res != CL_VIRUS) {
2536
perf_stop(ctx, PERFT_CACHE);
2538
ctx->wrkproperty = parent_property;
2540
early_ret_from_magicscan(res);
2543
perf_stop(ctx, PERFT_CACHE);
2544
hashed_size = (*ctx->fmap)->len;
2545
ctx->hook_lsig_matches = NULL;
2547
if(!(ctx->options&~CL_SCAN_ALLMATCHES) || (ctx->recursion == ctx->engine->maxreclevel)) { /* raw mode (stdin, etc.) or last level of recursion */
2548
if(ctx->recursion == ctx->engine->maxreclevel)
2549
cli_dbgmsg("cli_magic_scandesc: Hit recursion limit, only scanning raw file\n");
2551
cli_dbgmsg("Raw mode: No support for special files\n");
2553
ret = dispatch_prescan(ctx->engine->cb_pre_scan, ctx, filetype, old_hook_lsig_matches, parent_property, hash, hashed_size, &run_cleanup);
2555
if (ret == CL_VIRUS)
2556
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, cli_checkfp(hash, hashed_size, ctx), parent_property);
2558
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2560
/* ret_from_magicscan can be used below here*/
2561
if((ret = cli_fmap_scandesc(ctx, 0, 0, NULL, AC_SCAN_VIR, NULL, hash)) == CL_VIRUS)
2562
cli_dbgmsg("%s found in descriptor %d\n", cli_get_last_virus(ctx), fmap_fd(*ctx->fmap));
2563
else if(ret == CL_CLEAN) {
2564
if(ctx->recursion != ctx->engine->maxreclevel)
2565
cache_clean = 1; /* Only cache if limits are not reached */
2570
ctx->hook_lsig_matches = old_hook_lsig_matches;
2571
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2574
ret = dispatch_prescan(ctx->engine->cb_pre_scan, ctx, filetype, old_hook_lsig_matches, parent_property, hash, hashed_size, &run_cleanup);
2576
if (ret == CL_VIRUS)
2577
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, cli_checkfp(hash, hashed_size, ctx), parent_property);
2579
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2581
/* ret_from_magicscan can be used below here*/
2583
#ifdef HAVE__INTERNAL__SHA_COLLECT
2584
if(!ctx->sha_collect && type==CL_TYPE_MSEXE) ctx->sha_collect = 1;
2587
ctx->hook_lsig_matches = cli_bitset_init();
2588
if (!ctx->hook_lsig_matches) {
2589
ctx->hook_lsig_matches = old_hook_lsig_matches;
2590
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_EMEM, parent_property);
2593
if(type != CL_TYPE_IGNORED && ctx->engine->sdb) {
2594
if((ret = cli_scanraw(ctx, type, 0, &dettype, (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) ? NULL : hash)) == CL_VIRUS) {
2595
ret = cli_checkfp(hash, hashed_size, ctx);
2596
cli_bitset_free(ctx->hook_lsig_matches);
2597
ctx->hook_lsig_matches = old_hook_lsig_matches;
2598
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2603
perf_nested_start(ctx, PERFT_CONTAINER, PERFT_SCAN);
2604
ctx->container_size = (*ctx->fmap)->len;
2606
case CL_TYPE_IGNORED:
2610
ret = cli_scanxdp(ctx);
2614
ctx->container_type = CL_TYPE_RAR;
2615
if(have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR)) {
2616
char *tmpname = NULL;
2617
int desc = fmap_fd(*ctx->fmap);
2619
cli_dbgmsg("fmap not backed by file, dumping ...\n");
2620
ret = fmap_dump_to_file(*ctx->fmap, ctx->engine->tmpdir, &tmpname, &desc);
2621
if (ret != CL_SUCCESS) {
2622
cli_dbgmsg("fmap_fd: failed to generate temporary file.\n");
2626
ret = cli_scanrar(desc, ctx, 0, NULL);
2635
case CL_TYPE_OOXML_WORD:
2636
case CL_TYPE_OOXML_PPT:
2637
case CL_TYPE_OOXML_XL:
2639
if ((ctx->options & CL_SCAN_FILE_PROPERTIES) && (ctx->wrkproperty != NULL)) {
2640
ret = cli_process_ooxml(ctx);
2641
if (ret == CL_EMEM || ret == CL_ENULLARG) {
2642
/* critical error */
2645
else if (ret != CL_SUCCESS) {
2646
/* allow for the CL_TYPE_ZIP scan to occur; cli_process_ooxml other possible returns: */
2647
/* CL_ETIMEOUT, CL_EMAXSIZE, CL_EMAXFILES, CL_EPARSE, CL_EFORMAT, CL_BREAK, CL_ESTAT */
2653
ctx->container_type = CL_TYPE_ZIP;
2654
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
2655
ret = cli_unzip(ctx);
2659
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_GZ))
2660
ret = cli_scangzip(ctx);
2664
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BZ))
2665
ret = cli_scanbzip(ctx);
2669
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_XZ))
2670
ret = cli_scanxz(ctx);
2674
ret = cli_scangpt(ctx, 0);
2678
ret = cli_scanapm(ctx);
2682
ctx->container_type = CL_TYPE_ARJ;
2683
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ))
2684
ret = cli_scanarj(ctx, 0, NULL);
2687
case CL_TYPE_NULSFT:
2688
ctx->container_type = CL_TYPE_NULSFT;
2689
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_NSIS))
2690
ret = cli_scannulsft(ctx, 0);
2693
case CL_TYPE_AUTOIT:
2694
ctx->container_type = CL_TYPE_AUTOIT;
2695
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_AUTOIT))
2696
ret = cli_scanautoit(ctx, 23);
2699
case CL_TYPE_MSSZDD:
2700
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SZDD))
2701
ret = cli_scanszdd(ctx);
2705
ctx->container_type = CL_TYPE_MSCAB;
2706
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB))
2707
ret = cli_scanmscab(ctx, 0);
2711
if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
2712
ret = cli_scanhtml(ctx);
2715
case CL_TYPE_HTML_UTF16:
2716
if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
2717
ret = cli_scanhtml_utf16(ctx);
2720
case CL_TYPE_SCRIPT:
2721
if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML)
2722
ret = cli_scanscript(ctx);
2726
if(SCAN_SWF && (DCONF_DOC & DOC_CONF_SWF))
2727
ret = cli_scanswf(ctx);
2731
ctx->container_type = CL_TYPE_RTF;
2732
if(SCAN_ARCHIVE && (DCONF_DOC & DOC_CONF_RTF))
2733
ret = cli_scanrtf(ctx);
2737
ctx->container_type = CL_TYPE_MAIL;
2738
if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
2739
ret = cli_scanmail(ctx);
2743
if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_TNEF))
2744
ret = cli_scantnef(ctx);
2747
case CL_TYPE_UUENCODED:
2748
if(DCONF_OTHER & OTHER_CONF_UUENC)
2749
ret = cli_scanuuencoded(ctx);
2753
ctx->container_type = CL_TYPE_MSCHM;
2754
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CHM))
2755
ret = cli_scanmschm(ctx);
2758
case CL_TYPE_MSOLE2:
2759
ctx->container_type = CL_TYPE_MSOLE2;
2760
if(SCAN_OLE2 && (DCONF_ARCH & ARCH_CONF_OLE2))
2761
ret = cli_scanole2(ctx);
2765
ctx->container_type = CL_TYPE_7Z;
2766
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z))
2767
ret = cli_7unz(ctx, 0);
2770
case CL_TYPE_POSIX_TAR:
2771
ctx->container_type = CL_TYPE_POSIX_TAR;
2772
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
2773
ret = cli_scantar(ctx, 1);
2776
case CL_TYPE_OLD_TAR:
2777
ctx->container_type = CL_TYPE_OLD_TAR;
2778
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
2779
ret = cli_scantar(ctx, 0);
2782
case CL_TYPE_CPIO_OLD:
2783
ctx->container_type = CL_TYPE_CPIO_OLD;
2784
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2785
ret = cli_scancpio_old(ctx);
2788
case CL_TYPE_CPIO_ODC:
2789
ctx->container_type = CL_TYPE_CPIO_ODC;
2790
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2791
ret = cli_scancpio_odc(ctx);
2794
case CL_TYPE_CPIO_NEWC:
2795
ctx->container_type = CL_TYPE_CPIO_NEWC;
2796
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2797
ret = cli_scancpio_newc(ctx, 0);
2800
case CL_TYPE_CPIO_CRC:
2801
ctx->container_type = CL_TYPE_CPIO_CRC;
2802
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2803
ret = cli_scancpio_newc(ctx, 1);
2806
case CL_TYPE_BINHEX:
2807
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BINHEX))
2808
ret = cli_binhex(ctx);
2811
case CL_TYPE_SCRENC:
2812
if(DCONF_OTHER & OTHER_CONF_SCRENC)
2813
ret = cli_scanscrenc(ctx);
2817
if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_RIFF))
2818
ret = cli_scanriff(ctx);
2821
case CL_TYPE_GRAPHICS:
2822
if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_JPEG))
2823
ret = cli_scanjpeg(ctx);
2825
if(ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS)
2826
ret = cli_parsejpeg(ctx);
2828
if(ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS && ret != CL_EPARSE)
2829
ret = cli_parsepng(ctx);
2831
if(ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS && ret != CL_EPARSE)
2832
ret = cli_parsegif(ctx);
2835
case CL_TYPE_PDF: /* FIXMELIMITS: pdf should be an archive! */
2836
ctx->container_type = CL_TYPE_PDF;
2837
if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
2838
ret = cli_scanpdf(ctx, 0);
2841
case CL_TYPE_CRYPTFF:
2842
if(DCONF_OTHER & OTHER_CONF_CRYPTFF)
2843
ret = cli_scancryptff(ctx);
2847
if(SCAN_ELF && ctx->dconf->elf)
2848
ret = cli_scanelf(ctx);
2852
if(ctx->dconf->macho)
2853
ret = cli_scanmacho(ctx, NULL);
2856
case CL_TYPE_MACHO_UNIBIN:
2857
if(ctx->dconf->macho)
2858
ret = cli_scanmacho_unibin(ctx);
2862
ctx->container_type = CL_TYPE_SIS;
2863
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SIS))
2864
ret = cli_scansis(ctx);
2868
ctx->container_type = CL_TYPE_XAR;
2869
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_XAR))
2870
ret = cli_scanxar(ctx);
2873
case CL_TYPE_PART_HFSPLUS:
2874
ctx->container_type = CL_TYPE_PART_HFSPLUS;
2875
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_HFSPLUS))
2876
ret = cli_scanhfsplus(ctx);
2879
case CL_TYPE_BINARY_DATA:
2880
case CL_TYPE_TEXT_UTF16BE:
2881
if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_MYDOOMLOG))
2882
ret = cli_check_mydoom_log(ctx);
2885
case CL_TYPE_TEXT_ASCII:
2886
if(SCAN_STRUCTURED && (DCONF_OTHER & OTHER_CONF_DLP))
2887
/* TODO: consider calling this from cli_scanscript() for
2890
ret = cli_scan_structured(ctx);
2896
perf_nested_stop(ctx, PERFT_CONTAINER, PERFT_SCAN);
2898
ctx->container_type = current_container_type;
2899
ctx->container_size = current_container_size;
2901
if(ret == CL_VIRUS) {
2902
ret = cli_checkfp(hash, hashed_size, ctx);
2903
cli_bitset_free(ctx->hook_lsig_matches);
2904
ctx->hook_lsig_matches = old_hook_lsig_matches;
2905
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2908
if(type == CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP)) {
2909
/* CL_ENGINE_MAX_ZIPTYPERCG */
2910
uint64_t curr_len = (*ctx->fmap)->len;
2911
if(curr_len > ctx->engine->maxziptypercg) {
2912
cli_dbgmsg("cli_magic_scandesc: Not checking for embedded PEs (zip file > MaxZipTypeRcg)\n");
2917
/* CL_TYPE_HTML: raw HTML files are not scanned, unless safety measure activated via DCONF */
2918
if(type != CL_TYPE_IGNORED && (type != CL_TYPE_HTML || !(DCONF_DOC & DOC_CONF_HTML_SKIPRAW)) && !ctx->engine->sdb) {
2919
res = cli_scanraw(ctx, type, typercg, &dettype, (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) ? NULL : hash);
2920
if(res != CL_CLEAN) {
2922
/* List of scan halts, runtime errors only! */
2932
cli_dbgmsg("Descriptor[%d]: cli_scanraw error %s\n", fmap_fd(*ctx->fmap), cl_strerror(res));
2933
cli_bitset_free(ctx->hook_lsig_matches);
2934
ctx->hook_lsig_matches = old_hook_lsig_matches;
2935
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2936
/* CL_VIRUS = malware found, check FP and report */
2938
ret = cli_checkfp(hash, hashed_size, ctx);
2941
cli_bitset_free(ctx->hook_lsig_matches);
2942
ctx->hook_lsig_matches = old_hook_lsig_matches;
2943
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2944
/* "MAX" conditions should still fully scan the current file */
2949
cli_dbgmsg("Descriptor[%d]: Continuing after cli_scanraw reached %s\n",
2950
fmap_fd(*ctx->fmap), cl_strerror(res));
2952
/* Other errors must not block further scans below
2953
* This specifically includes CL_EFORMAT & CL_EREAD & CL_EUNPACK
2954
* Malformed/truncated files could report as any of these three.
2958
cli_dbgmsg("Descriptor[%d]: Continuing after cli_scanraw error %s\n",
2959
fmap_fd(*ctx->fmap), cl_strerror(res));
2966
/* bytecode hooks triggered by a lsig must be a hook
2967
* called from one of the functions here */
2968
case CL_TYPE_TEXT_ASCII:
2969
case CL_TYPE_TEXT_UTF16BE:
2970
case CL_TYPE_TEXT_UTF16LE:
2971
case CL_TYPE_TEXT_UTF8:
2972
perf_nested_start(ctx, PERFT_SCRIPT, PERFT_SCAN);
2973
if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML && ret != CL_VIRUS)
2974
ret = cli_scanscript(ctx);
2975
if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX) && ret != CL_VIRUS && (ctx->container_type == CL_TYPE_MAIL || dettype == CL_TYPE_MAIL)) {
2976
ret = cli_fmap_scandesc(ctx, CL_TYPE_MAIL, 0, NULL, AC_SCAN_VIR, NULL, NULL);
2978
perf_nested_stop(ctx, PERFT_SCRIPT, PERFT_SCAN);
2980
/* Due to performance reasons all executables were first scanned
2981
* in raw mode. Now we will try to unpack them
2984
perf_nested_start(ctx, PERFT_PE, PERFT_SCAN);
2985
if(SCAN_PE && ctx->dconf->pe) {
2986
unsigned int corrupted_input = ctx->corrupted_input;
2987
ret = cli_scanpe(ctx);
2988
ctx->corrupted_input = corrupted_input;
2990
perf_nested_stop(ctx, PERFT_PE, PERFT_SCAN);
2997
ret = cli_checkfp(hash, hashed_size, ctx);
2999
cli_bitset_free(ctx->hook_lsig_matches);
3000
ctx->hook_lsig_matches = old_hook_lsig_matches;
3003
/* Malformed file cases */
3007
/* Limits exceeded */
3011
cli_dbgmsg("Descriptor[%d]: %s\n", fmap_fd(*ctx->fmap), cl_strerror(ret));
3013
ctx->wrkproperty = parent_property;
3015
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_CLEAN, parent_property);
3019
ctx->wrkproperty = parent_property;
3021
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_CLEAN, parent_property);
3023
return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
3027
static int cli_base_scandesc(int desc, cli_ctx *ctx, cli_file_t type)
3032
#ifdef HAVE__INTERNAL__SHA_COLLECT
3033
if(ctx->sha_collect>0) ctx->sha_collect = 0;
3035
cli_dbgmsg("in cli_magic_scandesc (reclevel: %u/%u)\n", ctx->recursion, ctx->engine->maxreclevel);
3036
if(FSTAT(desc, &sb) == -1) {
3037
cli_errmsg("magic_scandesc: Can't fstat descriptor %d\n", desc);
3038
early_ret_from_magicscan(CL_ESTAT);
3040
if(sb.st_size <= 5) {
3041
cli_dbgmsg("Small data (%u bytes)\n", (unsigned int) sb.st_size);
3042
early_ret_from_magicscan(CL_CLEAN);
3046
perf_start(ctx, PERFT_MAP);
3047
if(!(*ctx->fmap = fmap(desc, 0, sb.st_size))) {
3048
cli_errmsg("CRITICAL: fmap() failed\n");
3050
perf_stop(ctx, PERFT_MAP);
3051
early_ret_from_magicscan(CL_EMEM);
3053
perf_stop(ctx, PERFT_MAP);
3055
ret = magic_scandesc(ctx, type);
3062
int cli_magic_scandesc(int desc, cli_ctx *ctx)
3064
return cli_base_scandesc(desc, ctx, CL_TYPE_ANY);
3067
/* Have to keep partition typing separate */
3068
int cli_partition_scandesc(int desc, cli_ctx *ctx)
3070
return cli_base_scandesc(desc, ctx, CL_TYPE_PART_ANY);
3073
int cli_magic_scandesc_type(cli_ctx *ctx, cli_file_t type)
3075
return magic_scandesc(ctx, type);
3078
int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
3080
return cl_scandesc_callback(desc, virname, scanned, engine, scanoptions, NULL);
3083
/* For map scans that may be forced to disk */
3084
int cli_map_scan(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx, cli_file_t type)
3086
off_t old_off = map->nested_offset;
3087
size_t old_len = map->len;
3090
cli_dbgmsg("cli_map_scan: [%ld, +%lu)\n",
3091
(long)offset, (unsigned long)length);
3092
if (offset < 0 || (size_t)offset >= old_len) {
3093
cli_dbgmsg("Invalid offset: %ld\n", (long)offset);
3097
if (ctx->engine->engine_options & ENGINE_OPTIONS_FORCE_TO_DISK) {
3098
/* if this is forced to disk, then need to write the nested map and scan it */
3099
const uint8_t *mapdata = NULL;
3100
char *tempfile = NULL;
3104
/* Then check length */
3105
if (!length) length = old_len - offset;
3106
if (length > old_len - offset) {
3107
cli_dbgmsg("cli_map_scan: Data truncated: %lu -> %lu\n",
3108
(unsigned long)length, (unsigned long)(old_len - offset));
3109
length = old_len - offset;
3112
cli_dbgmsg("cli_map_scan: Small data (%u bytes)\n", (unsigned int) length);
3115
if (!CLI_ISCONTAINED(old_off, old_len, old_off + offset, length)) {
3116
cli_dbgmsg("cli_map_scan: map error occurred [%ld, %lu]\n",
3117
(long)old_off, (unsigned long)old_len);
3121
/* Length checked, now get map */
3122
mapdata = fmap_need_off_once_len(map, offset, length, &nread);
3123
if (!mapdata || (nread != length)) {
3124
cli_errmsg("cli_map_scan: could not map sub-file\n");
3128
ret = cli_gentempfd(ctx->engine->tmpdir, &tempfile, &fd);
3129
if (ret != CL_SUCCESS) {
3133
cli_dbgmsg("cli_map_scan: writing nested map content to temp file %s\n", tempfile);
3134
if (cli_writen(fd, mapdata, length) < 0) {
3135
cli_errmsg("cli_map_scan: cli_writen error writing subdoc temporary file.\n");
3139
/* scan the temp file */
3140
ret = cli_base_scandesc(fd, ctx, type);
3142
/* remove the temp file, if needed */
3146
if(!ctx->engine->keeptmp) {
3147
if (cli_unlink(tempfile)) {
3148
cli_errmsg("cli_map_scan: error unlinking tempfile %s\n", tempfile);
3155
/* Not forced to disk, use nested map */
3156
ret = cli_map_scandesc(map, offset, length, ctx, type);
3161
/* For map scans that are not forced to disk */
3162
int cli_map_scandesc(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx, cli_file_t type)
3164
off_t old_off = map->nested_offset;
3165
size_t old_len = map->len;
3166
size_t old_real_len = map->real_len;
3169
cli_dbgmsg("cli_map_scandesc: [%ld, +%lu), [%ld, +%lu)\n",
3170
(long)old_off, (unsigned long)old_len,
3171
(long)offset, (unsigned long)length);
3172
if (offset < 0 || (size_t)offset >= old_len) {
3173
cli_dbgmsg("Invalid offset: %ld\n", (long)offset);
3177
if (!length) length = old_len - offset;
3178
if (length > old_len - offset) {
3179
cli_dbgmsg("Data truncated: %lu -> %lu\n",
3180
(unsigned long)length, old_len - offset);
3181
length = old_len - offset;
3185
cli_dbgmsg("Small data (%u bytes)\n", (unsigned int) length);
3190
/* can't change offset because then we'd have to discard/move cached
3191
* data, instead use another offset to reuse the already cached data */
3192
map->nested_offset += offset;
3194
map->real_len = map->nested_offset + length;
3195
if (CLI_ISCONTAINED(old_off, old_len, map->nested_offset, map->len)) {
3196
ret = magic_scandesc(ctx, type);
3198
long long len1, len2;
3199
len1 = old_off + old_len;
3200
len2 = map->nested_offset + map->len;
3201
cli_warnmsg("internal map error: %lu, %llu; %lu, %llu\n", (long unsigned)old_off,
3202
(long long unsigned)len1, (long unsigned)map->offset, (long long unsigned)len2);
3206
map->nested_offset = old_off;
3208
map->real_len = old_real_len;
3212
int cli_mem_scandesc(const void *buffer, size_t length, cli_ctx *ctx)
3215
fmap_t *map = cl_fmap_open_memory(buffer, length);
3219
ret = cli_map_scan(map, 0, length, ctx, CL_TYPE_ANY);
3224
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)
3230
/* We have a limit of around 2.17GB (INT_MAX - 2). Enforce it here. */
3232
if ((size_t)(map->real_len) > (size_t)(INT_MAX - 2))
3235
if (FSTAT(desc, &sb))
3238
if ((size_t)(sb.st_size) > (size_t)(INT_MAX - 2))
3242
memset(&ctx, '\0', sizeof(cli_ctx));
3243
ctx.engine = engine;
3244
ctx.virname = virname;
3245
ctx.scanned = scanned;
3246
ctx.options = scanoptions;
3247
#if 0 /* for development testing only */
3248
ctx.options |= CL_SCAN_FILE_PROPERTIES;
3250
ctx.found_possibly_unwanted = 0;
3251
ctx.container_type = CL_TYPE_ANY;
3252
ctx.container_size = 0;
3253
ctx.dconf = (struct cli_dconf *) engine->dconf;
3254
ctx.cb_ctx = context;
3255
ctx.fmap = cli_calloc(sizeof(fmap_t *), ctx.engine->maxreclevel + 2);
3258
if (!(ctx.hook_lsig_matches = cli_bitset_init())) {
3264
if (ctx.options & CL_SCAN_FILE_PROPERTIES && ctx.engine->time_limit != 0) {
3265
if (gettimeofday(&ctx.time_limit, NULL) == 0) {
3266
uint32_t secs = ctx.engine->time_limit / 1000;
3267
uint32_t usecs = (ctx.engine->time_limit % 1000) * 1000;
3268
ctx.time_limit.tv_sec += secs;
3269
ctx.time_limit.tv_usec += usecs;
3270
if (ctx.time_limit.tv_usec >= 1000000) {
3271
ctx.time_limit.tv_usec -= 1000000;
3272
ctx.time_limit.tv_sec++;
3276
cli_dbgmsg("scan_common; gettimeofday error: %s\n", cli_strerror(errno, buf, 64));
3280
#ifdef HAVE__INTERNAL__SHA_COLLECT
3281
if(scanoptions & CL_SCAN_INTERNAL_COLLECT_SHA) {
3286
snprintf(link, sizeof(link), "/proc/self/fd/%u", desc);
3287
link[sizeof(link)-1]='\0';
3288
if((linksz=readlink(link, ctx.entry_filename, sizeof(ctx.entry_filename)-1))==-1) {
3289
cli_errmsg("failed to resolve filename for descriptor %d (%s)\n", desc, link);
3290
strcpy(ctx.entry_filename, "NO_IDEA");
3292
ctx.entry_filename[linksz]='\0';
3296
cli_logg_setup(&ctx);
3297
rc = map ? cli_map_scandesc(map, 0, map->len, &ctx, CL_TYPE_ANY) : cli_magic_scandesc(desc, &ctx);
3300
if (ctx.options & CL_SCAN_FILE_PROPERTIES && ctx.properties!=NULL) {
3302
const char *jstring;
3304
/* set value of unique root object tag */
3305
if (json_object_object_get_ex(ctx.properties, "FileType", &jobj)) {
3306
enum json_type type;
3309
type = json_object_get_type(jobj);
3310
if (type == json_type_string) {
3311
jstr = json_object_get_string(jobj);
3312
cli_jsonstr(ctx.properties, "RootFileType", jstr);
3316
/* serialize json properties to string */
3317
jstring = json_object_to_json_string(ctx.properties);
3318
if (NULL == jstring) {
3319
cli_errmsg("scan_common: no memory for json serialization.\n");
3323
int ret = CL_SUCCESS;
3324
cli_dbgmsg("%s\n", jstring);
3326
/* Scan the json string unless a virus was detected */
3327
if (rc != CL_VIRUS) {
3328
ctx.options &= ~CL_SCAN_FILE_PROPERTIES;
3329
rc = cli_mem_scandesc(jstring, strlen(jstring), &ctx);
3332
/* Invoke file props callback */
3333
if (ctx.engine->cb_file_props != NULL) {
3334
ret = ctx.engine->cb_file_props(jstring, rc, ctx.engine->cb_file_props_data);
3335
if (ret != CL_SUCCESS)
3339
/* keeptmp file processing for file properties json string */
3340
if (ctx.engine->keeptmp) {
3342
char * tmpname = NULL;
3343
if ((ret = cli_gentempfd(ctx.engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
3344
cli_dbgmsg("scan_common: Can't create json properties file, ret = %i.\n", ret);
3346
if (cli_writen(fd, jstring, strlen(jstring)) < 0)
3347
cli_dbgmsg("scan_common: cli_writen error writing json properties file.\n");
3349
cli_dbgmsg("json written to: %s\n", tmpname);
3353
if (NULL != tmpname)
3357
json_object_put(ctx.properties); /* frees all json memory */
3359
// test code - to be deleted
3360
if (cli_checktimelimit(&ctx) != CL_SUCCESS) {
3361
cli_errmsg("scan_common: timeout!\n");
3368
if (ctx.options & CL_SCAN_ALLMATCHES) {
3369
*virname = (char *)ctx.virname; /* temp hack for scanall mode until api augmentation */
3370
if (rc == CL_CLEAN && ctx.num_viruses)
3374
cli_bitset_free(ctx.hook_lsig_matches);
3376
if(rc == CL_CLEAN && ctx.found_possibly_unwanted)
3383
int cl_scandesc_callback(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
3385
return scan_common(desc, NULL, virname, scanned, engine, scanoptions, context);
3388
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)
3390
return scan_common(-1, map, virname, scanned, engine, scanoptions, context);
3393
int cli_found_possibly_unwanted(cli_ctx* ctx)
3395
if(cli_get_last_virus(ctx)) {
3396
cli_dbgmsg("found Possibly Unwanted: %s\n", cli_get_last_virus(ctx));
3397
if(ctx->options & CL_SCAN_HEURISTIC_PRECEDENCE) {
3398
/* we found a heuristic match, don't scan further,
3399
* but consider it a virus. */
3400
cli_dbgmsg("cli_found_possibly_unwanted: CL_VIRUS\n");
3403
/* heuristic scan isn't taking precedence, keep scanning.
3404
* If this is part of an archive, and
3405
* we find a real malware we report that instead of the
3406
* heuristic match */
3407
ctx->found_possibly_unwanted = 1;
3409
cli_warnmsg("cli_found_possibly_unwanted called, but virname is not set\n");
3415
static int cli_scanfile(const char *filename, cli_ctx *ctx)
3419
/* internal version of cl_scanfile with arec/mrec preserved */
3420
if((fd = safe_open(filename, O_RDONLY|O_BINARY)) == -1)
3423
ret = cli_magic_scandesc(fd, ctx);
3429
int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
3431
return cl_scanfile_callback(filename, virname, scanned, engine, scanoptions, NULL);
3434
int cl_scanfile_callback(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
3437
const char *fname = cli_to_utf8_maybe_alloc(filename);
3442
if((fd = safe_open(fname, O_RDONLY|O_BINARY)) == -1)
3445
if(fname != filename)
3448
ret = cl_scandesc_callback(fd, virname, scanned, engine, scanoptions, context);