~ubuntu-branches/ubuntu/wily/clamav/wily-proposed

« back to all changes in this revision

Viewing changes to .pc/0007-libclamav-use-libmspack.patch/libclamav/scanners.c

  • Committer: Package Import Robot
  • Author(s): Scott Kitterman, Sebastian Andrzej Siewior, Andreas Cadhalpun, Scott Kitterman, Javier Fernández-Sanguino
  • Date: 2015-01-28 00:25:13 UTC
  • mfrom: (0.48.14 sid)
  • Revision ID: package-import@ubuntu.com-20150128002513-lil2oi74cooy4lzr
Tags: 0.98.6+dfsg-1
[ Sebastian Andrzej Siewior ]
* update "fix-ssize_t-size_t-off_t-printf-modifier", include of misc.h was
  missing but was pulled in via the systemd patch.
* Don't leak return codes from libmspack to clamav API. (Closes: #774686).

[ Andreas Cadhalpun ]
* Add patch to avoid emitting incremental progress messages when not
  outputting to a terminal. (Closes: #767350)
* Update lintian-overrides for unused-file-paragraph-in-dep5-copyright.
* clamav-base.postinst: always chown /var/log/clamav and /var/lib/clamav
  to clamav:clamav, not only on fresh installations. (Closes: #775400)
* Adapt the clamav-daemon and clamav-freshclam logrotate scripts,
  so that they correctly work under systemd.
* Move the PidFile variable from the clamd/freshclam configuration files
  to the init scripts. This makes the init scripts more robust against
  misconfiguration and avoids error messages with systemd. (Closes: #767353)
* debian/copyright: drop files from Files-Excluded only present in github
  tarballs
* Drop Workaround-a-bug-in-libc-on-Hurd.patch, because hurd got fixed.
  (see #752237)
* debian/rules: Remove useless --with-system-tommath --without-included-ltdl
  configure options.

[ Scott Kitterman ]
* Stop stripping llvm when repacking the tarball as the system llvm on some
  releases is too old to use
* New upstream bugfix release
  - Library shared object revisions.
  - Includes a patch from Sebastian Andrzej Siewior making ClamAV pid files
    compatible with systemd.
  - Fix a heap out of bounds condition with crafted Yoda's crypter files.
    This issue was discovered by Felix Groebert of the Google Security Team.
  - Fix a heap out of bounds condition with crafted mew packer files. This
    issue was discovered by Felix Groebert of the Google Security Team.
  - Fix a heap out of bounds condition with crafted upx packer files. This
    issue was discovered by Kevin Szkudlapski of Quarkslab.
  - Fix a heap out of bounds condition with crafted upack packer files. This
    issue was discovered by Sebastian Andrzej Siewior. CVE-2014-9328.
  - Compensate a crash due to incorrect compiler optimization when handling
    crafted petite packer files. This issue was discovered by Sebastian
    Andrzej Siewior.
* Update lintian override for embedded zlib to match new so version

[ Javier Fernández-Sanguino ]
* Updated Spanish Debconf template translation (Closes: #773563)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *  Copyright (C) 2007-2013 Sourcefire, Inc.
3
 
 *  Copyright (C) 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
4
 
 *
5
 
 *  Authors: Tomasz Kojm
6
 
 *
7
 
 *  This program is free software; you can redistribute it and/or modify
8
 
 *  it under the terms of the GNU General Public License version 2 as
9
 
 *  published by the Free Software Foundation.
10
 
 *
11
 
 *  This program is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with this program; if not, write to the Free Software
18
 
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 
 *  MA 02110-1301, USA.
20
 
 */
21
 
 
22
 
#if HAVE_CONFIG_H
23
 
#include "clamav-config.h"
24
 
#endif
25
 
 
26
 
#ifndef _WIN32
27
 
#include <sys/time.h>
28
 
#endif
29
 
#include <stdio.h>
30
 
#include <string.h>
31
 
#include <stdlib.h>
32
 
#include <errno.h>
33
 
#include <sys/types.h>
34
 
#include <sys/stat.h>
35
 
#ifdef  HAVE_UNISTD_H
36
 
#include <unistd.h>
37
 
#endif
38
 
#ifdef  HAVE_SYS_PARAM_H
39
 
#include <sys/param.h>
40
 
#endif
41
 
#include <fcntl.h>
42
 
#include <dirent.h>
43
 
#ifdef HAVE_SYS_TIMES_H
44
 
#include <sys/times.h>
45
 
#endif
46
 
 
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
51
 
 
52
 
#include "clamav.h"
53
 
#include "others.h"
54
 
#include "dconf.h"
55
 
#include "scanners.h"
56
 
#include "matcher-ac.h"
57
 
#include "matcher-bm.h"
58
 
#include "matcher.h"
59
 
#include "ole2_extract.h"
60
 
#include "vba_extract.h"
61
 
#include "msexpand.h"
62
 
#include "mbox.h"
63
 
#include "chmunpack.h"
64
 
#include "pe.h"
65
 
#include "elf.h"
66
 
#include "filetypes.h"
67
 
#include "htmlnorm.h"
68
 
#include "untar.h"
69
 
#include "special.h"
70
 
#include "binhex.h"
71
 
/* #include "uuencode.h" */
72
 
#include "tnef.h"
73
 
#include "sis.h"
74
 
#include "pdf.h"
75
 
#include "str.h"
76
 
#include "mspack.h"
77
 
#include "cab.h"
78
 
#include "rtf.h"
79
 
#include "unarj.h"
80
 
#include "nsis/nulsft.h"
81
 
#include "autoit.h"
82
 
#include "textnorm.h"
83
 
#include <zlib.h>
84
 
#include "unzip.h"
85
 
#include "dlp.h"
86
 
#include "default.h"
87
 
#include "cpio.h"
88
 
#include "macho.h"
89
 
#include "ishield.h"
90
 
#include "7z_iface.h"
91
 
#include "fmap.h"
92
 
#include "cache.h"
93
 
#include "events.h"
94
 
#include "swf.h"
95
 
#include "jpeg.h"
96
 
#include "png.h"
97
 
#include "iso9660.h"
98
 
#include "dmg.h"
99
 
#include "xar.h"
100
 
#include "hfsplus.h"
101
 
#include "xz_iface.h"
102
 
#include "mbr.h"
103
 
#include "gpt.h"
104
 
#include "apm.h"
105
 
#include "ooxml.h"
106
 
#include "xdp.h"
107
 
#include "json_api.h"
108
 
 
109
 
#ifdef HAVE_BZLIB_H
110
 
#include <bzlib.h>
111
 
#endif
112
 
 
113
 
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
114
 
#include <limits.h>
115
 
#include <stddef.h>
116
 
#endif
117
 
 
118
 
#include <string.h>
119
 
 
120
 
static int cli_scanfile(const char *filename, cli_ctx *ctx);
121
 
 
122
 
static int cli_scandir(const char *dirname, cli_ctx *ctx)
123
 
{
124
 
        DIR *dd;
125
 
        struct dirent *dent;
126
 
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
127
 
        union {
128
 
            struct dirent d;
129
 
            char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
130
 
        } result;
131
 
#endif
132
 
        STATBUF statbuf;
133
 
        char *fname;
134
 
        unsigned int viruses_found = 0;
135
 
 
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))) {
141
 
#else
142
 
        while((dent = readdir(dd))) {
143
 
#endif
144
 
            if(dent->d_ino)
145
 
            {
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);
149
 
                    if(!fname) {
150
 
                        closedir(dd);
151
 
            cli_dbgmsg("cli_scandir: Unable to allocate memory for filename\n");
152
 
                        return CL_EMEM;
153
 
                    }
154
 
 
155
 
                    sprintf(fname, "%s"PATHSEP"%s", dirname, dent->d_name);
156
 
 
157
 
                    /* stat the file */
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) {
161
 
                                free(fname);
162
 
 
163
 
                                if (SCAN_ALL) {
164
 
                                    viruses_found++;
165
 
                                    continue;
166
 
                                }
167
 
 
168
 
                                closedir(dd);
169
 
                                return CL_VIRUS;
170
 
                            }
171
 
                        } else {
172
 
                            if(S_ISREG(statbuf.st_mode)) {
173
 
                                if(cli_scanfile(fname, ctx) == CL_VIRUS) {
174
 
                                    free(fname);
175
 
 
176
 
                                    if (SCAN_ALL) {
177
 
                                        viruses_found++;
178
 
                                        continue;
179
 
                                    }
180
 
 
181
 
                                    closedir(dd);
182
 
                                    return CL_VIRUS;
183
 
                                }
184
 
                            }
185
 
                        }
186
 
                    }
187
 
                    free(fname);
188
 
                }
189
 
            }
190
 
        } 
191
 
    } else {
192
 
        cli_dbgmsg("cli_scandir: Can't open directory %s.\n", dirname);
193
 
        return CL_EOPEN;
194
 
    }
195
 
 
196
 
    closedir(dd);
197
 
    if (SCAN_ALL && viruses_found)
198
 
        return CL_VIRUS;
199
 
    return CL_CLEAN;
200
 
}
201
 
 
202
 
static int cli_unrar_scanmetadata(int desc, unrar_metadata_t *metadata, cli_ctx *ctx, unsigned int files, uint32_t* sfx_check)
203
 
{
204
 
        int ret = CL_SUCCESS;
205
 
 
206
 
    if(files == 1 && sfx_check) {
207
 
        if(*sfx_check == metadata->crc)
208
 
            return CL_BREAK;/* break extract loop */
209
 
        else
210
 
            *sfx_check = metadata->crc;
211
 
    }
212
 
 
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);
217
 
 
218
 
    if(cli_matchmeta(ctx, metadata->filename, metadata->pack_size, metadata->unpack_size, metadata->encrypted, files, metadata->crc, NULL) == CL_VIRUS)
219
 
        return CL_VIRUS;
220
 
 
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");
226
 
            return CL_VIRUS;
227
 
        }
228
 
    }
229
 
 
230
 
    return ret;
231
 
}
232
 
 
233
 
static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
234
 
{
235
 
        int ret = CL_CLEAN;
236
 
        unrar_metadata_t *metadata, *metadata_tmp;
237
 
        char *dir;
238
 
        unrar_state_t rar_state;
239
 
        unsigned int viruses_found = 0;
240
 
 
241
 
    cli_dbgmsg("in scanrar()\n");
242
 
 
243
 
    if(sfx_offset)
244
 
        if(lseek(desc, sfx_offset, SEEK_SET) == -1)
245
 
            return CL_ESEEK;
246
 
 
247
 
    /* generate the temporary directory */
248
 
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
249
 
        return CL_EMEM;
250
 
 
251
 
    if(mkdir(dir, 0700)) {
252
 
        cli_dbgmsg("RAR: Can't create temporary directory %s\n", dir);
253
 
        free(dir);
254
 
        return CL_ETMPDIR;
255
 
    }
256
 
 
257
 
    if((ret = cli_unrar_open(desc, dir, &rar_state)) != UNRAR_OK) {
258
 
        if(!ctx->engine->keeptmp)
259
 
            cli_rmdirs(dir);
260
 
        free(dir);
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");
266
 
            return CL_ESEEK;
267
 
        }
268
 
                ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
269
 
                if(ret != CL_VIRUS)
270
 
                    cli_append_virus(ctx, "Heuristics.Encrypted.RAR");
271
 
                return CL_VIRUS;
272
 
            }
273
 
            return CL_CLEAN;
274
 
        } if(ret == UNRAR_EMEM) {
275
 
            return CL_EMEM;
276
 
        } else {
277
 
            return CL_EUNPACK;
278
 
        }
279
 
    }
280
 
 
281
 
    do {
282
 
        int rc;
283
 
        rar_state.ofd = -1;
284
 
        ret = cli_unrar_extract_next_prepare(&rar_state,dir);
285
 
        if(ret != UNRAR_OK) {
286
 
            if(ret == UNRAR_BREAK)
287
 
                ret = CL_BREAK;
288
 
            else if(ret == UNRAR_EMEM)
289
 
                ret = CL_EMEM;
290
 
            else
291
 
                ret = CL_EUNPACK;
292
 
            break;
293
 
        }
294
 
        if(ctx->engine->maxscansize && ctx->scansize >= ctx->engine->maxscansize) {
295
 
            free(rar_state.file_header->filename);
296
 
            free(rar_state.file_header);
297
 
            ret = CL_CLEAN;
298
 
            break;
299
 
        }
300
 
        if(ctx->engine->maxscansize && ctx->scansize + ctx->engine->maxfilesize >= ctx->engine->maxscansize)
301
 
            rar_state.maxfilesize = ctx->engine->maxscansize - ctx->scansize;
302
 
        else
303
 
            rar_state.maxfilesize = ctx->engine->maxfilesize;
304
 
 
305
 
        ret = cli_unrar_extract_next(&rar_state,dir);
306
 
        if(ret == UNRAR_OK)
307
 
            ret = CL_SUCCESS;
308
 
        else if(ret == UNRAR_EMEM)
309
 
            ret = CL_EMEM;
310
 
        else
311
 
            ret = CL_EFORMAT;
312
 
 
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");
316
 
            ret = CL_ESEEK;
317
 
        }
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));
324
 
                ret = CL_VIRUS;
325
 
                viruses_found++;
326
 
            }
327
 
        }
328
 
 
329
 
        if(ret == CL_VIRUS) {
330
 
            if(SCAN_ALL)
331
 
                ret = CL_SUCCESS;
332
 
            else
333
 
                break;
334
 
        }
335
 
 
336
 
        if(ret == CL_SUCCESS)
337
 
            ret = cli_unrar_scanmetadata(desc,rar_state.metadata_tail, ctx, rar_state.file_count, sfx_check);
338
 
 
339
 
    } while(ret == CL_SUCCESS);
340
 
 
341
 
    if(ret == CL_BREAK)
342
 
        ret = CL_CLEAN;
343
 
 
344
 
    metadata = metadata_tmp = rar_state.metadata; 
345
 
 
346
 
    if(cli_scandir(rar_state.comment_dir, ctx) == CL_VIRUS)
347
 
        ret = CL_VIRUS;
348
 
 
349
 
    cli_unrar_close(&rar_state);
350
 
 
351
 
    if(!ctx->engine->keeptmp)
352
 
        cli_rmdirs(dir);
353
 
 
354
 
    free(dir);
355
 
 
356
 
    metadata = metadata_tmp;
357
 
    while (metadata) {
358
 
        metadata_tmp = metadata->next;
359
 
        free(metadata->filename);
360
 
        free(metadata);
361
 
        metadata = metadata_tmp;
362
 
    }
363
 
    cli_dbgmsg("RAR: Exit code: %d\n", ret);
364
 
 
365
 
    if (SCAN_ALL && viruses_found)
366
 
        return CL_VIRUS;
367
 
    return ret;
368
 
}
369
 
 
370
 
static int cli_scanarj(cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
371
 
{
372
 
        int ret = CL_CLEAN, rc, file = 0;
373
 
        arj_metadata_t metadata;
374
 
        char *dir;
375
 
 
376
 
    UNUSEDPARAM(sfx_check);
377
 
 
378
 
    cli_dbgmsg("in cli_scanarj()\n");
379
 
 
380
 
     /* generate the temporary directory */
381
 
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
382
 
        return CL_EMEM;
383
 
 
384
 
    if(mkdir(dir, 0700)) {
385
 
        cli_dbgmsg("ARJ: Can't create temporary directory %s\n", dir);
386
 
        free(dir);
387
 
        return CL_ETMPDIR;
388
 
    }
389
 
 
390
 
    ret = cli_unarj_open(*ctx->fmap, dir, &metadata, sfx_offset);
391
 
    if (ret != CL_SUCCESS) {
392
 
        if(!ctx->engine->keeptmp)
393
 
            cli_rmdirs(dir);
394
 
        free(dir);
395
 
        cli_dbgmsg("ARJ: Error: %s\n", cl_strerror(ret));
396
 
        return ret;
397
 
    }
398
 
    
399
 
   do {
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));
404
 
           break;
405
 
        }
406
 
        file++;
407
 
        if(cli_matchmeta(ctx, metadata.filename, metadata.comp_size, metadata.orig_size, metadata.encrypted, file, 0, NULL) == CL_VIRUS) {
408
 
        cli_rmdirs(dir);
409
 
        free(dir);
410
 
            return CL_VIRUS;
411
 
    }
412
 
 
413
 
        if ((ret = cli_checklimits("ARJ", ctx, metadata.orig_size, metadata.comp_size, 0))!=CL_CLEAN) {
414
 
            ret = CL_SUCCESS;
415
 
            if (metadata.filename)
416
 
                free(metadata.filename);
417
 
            continue;
418
 
        }
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));
422
 
        }
423
 
        if (metadata.ofd >= 0) {
424
 
            if (lseek(metadata.ofd, 0, SEEK_SET) == -1) {
425
 
            cli_dbgmsg("ARJ: call to lseek() failed\n");
426
 
        }
427
 
            rc = cli_magic_scandesc(metadata.ofd, ctx);
428
 
            close(metadata.ofd);
429
 
            if (rc == CL_VIRUS) {
430
 
                cli_dbgmsg("ARJ: infected with %s\n", cli_get_last_virus(ctx));
431
 
                ret = CL_VIRUS;
432
 
                if (metadata.filename) {
433
 
                    free(metadata.filename);
434
 
                    metadata.filename = NULL;
435
 
                }
436
 
                break;
437
 
            }
438
 
        }
439
 
        if (metadata.filename) {
440
 
                free(metadata.filename);
441
 
                metadata.filename = NULL;
442
 
        }
443
 
 
444
 
    } while(ret == CL_SUCCESS);
445
 
    
446
 
    if(!ctx->engine->keeptmp)
447
 
        cli_rmdirs(dir);
448
 
 
449
 
    free(dir);
450
 
    if (metadata.filename) {
451
 
        free(metadata.filename);
452
 
    }
453
 
 
454
 
    cli_dbgmsg("ARJ: Exit code: %d\n", ret);
455
 
    if (ret == CL_BREAK)
456
 
        ret = CL_CLEAN;
457
 
 
458
 
    return ret;
459
 
}
460
 
 
461
 
 
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;
465
 
    char *tmpname;
466
 
    gzFile gz;
467
 
 
468
 
    ret = fmap_fd(map);
469
 
    if(ret < 0)
470
 
        return CL_EDUP;
471
 
    fd = dup(ret);
472
 
    if(fd < 0)
473
 
        return CL_EDUP;
474
 
 
475
 
    if(!(gz = gzdopen(fd, "rb"))) {
476
 
        close(fd);
477
 
        return CL_EOPEN;
478
 
    }
479
 
 
480
 
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
481
 
        cli_dbgmsg("GZip: Can't generate temporary file.\n");
482
 
        gzclose(gz);
483
 
        close(fd);
484
 
        return ret;
485
 
    }
486
 
    
487
 
    while((bytes = gzread(gz, buff, FILEBUFF)) > 0) {
488
 
        outsize += bytes;
489
 
        if(cli_checklimits("GZip", ctx, outsize, 0, 0)!=CL_CLEAN)
490
 
            break;
491
 
        if(cli_writen(fd, buff, bytes) != bytes) {
492
 
            close(fd);
493
 
            gzclose(gz);
494
 
            if(cli_unlink(tmpname)) {
495
 
                free(tmpname);
496
 
                return CL_EUNLINK;
497
 
            }
498
 
            free(tmpname);
499
 
            return CL_EWRITE;
500
 
        }
501
 
    }
502
 
 
503
 
    gzclose(gz);
504
 
 
505
 
    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
506
 
        cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx));
507
 
        close(fd);
508
 
        if(!ctx->engine->keeptmp) {
509
 
            if (cli_unlink(tmpname)) {
510
 
                free(tmpname);
511
 
                return CL_EUNLINK;
512
 
            }
513
 
        }
514
 
        free(tmpname);
515
 
        return CL_VIRUS;
516
 
    }
517
 
    close(fd);
518
 
    if(!ctx->engine->keeptmp)
519
 
        if (cli_unlink(tmpname)) ret = CL_EUNLINK;
520
 
    free(tmpname);
521
 
    return ret;
522
 
}
523
 
 
524
 
static int cli_scangzip(cli_ctx *ctx)
525
 
{
526
 
        int fd, ret = CL_CLEAN;
527
 
        unsigned char buff[FILEBUFF];
528
 
        char *tmpname;
529
 
        z_stream z;
530
 
        size_t at = 0, outsize = 0;
531
 
        fmap_t *map = *ctx->fmap;
532
 
        
533
 
    cli_dbgmsg("in cli_scangzip()\n");
534
 
 
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);
539
 
    }
540
 
 
541
 
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
542
 
        cli_dbgmsg("GZip: Can't generate temporary file.\n");
543
 
        inflateEnd(&z);
544
 
        return ret;
545
 
    }
546
 
 
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);
551
 
            inflateEnd(&z);
552
 
            close(fd);
553
 
            if (cli_unlink(tmpname)) {
554
 
                free(tmpname);
555
 
                return CL_EUNLINK;
556
 
            }
557
 
            free(tmpname);
558
 
            return CL_EREAD;
559
 
        }
560
 
        at += bytes;
561
 
        z.avail_in = bytes;
562
 
        do {
563
 
            int inf;
564
 
            z.avail_out = sizeof(buff);
565
 
            z.next_out = 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");
570
 
                    at = map->len;
571
 
                    break;
572
 
                }
573
 
                else {
574
 
                    cli_dbgmsg("GZip: Bad stream, data in output buffer.\n");
575
 
                    /* no break yet, flush extracted bytes to file */
576
 
                }
577
 
            }
578
 
            if(cli_writen(fd, buff, sizeof(buff) - z.avail_out) < 0) {
579
 
                inflateEnd(&z);     
580
 
                close(fd);
581
 
                if (cli_unlink(tmpname)) {
582
 
                    free(tmpname);
583
 
                    return CL_EUNLINK;
584
 
                }
585
 
                free(tmpname);
586
 
                return CL_EWRITE;
587
 
            }
588
 
            outsize += sizeof(buff) - z.avail_out;
589
 
            if(cli_checklimits("GZip", ctx, outsize, 0, 0)!=CL_CLEAN) {
590
 
                at = map->len;
591
 
                break;
592
 
            }
593
 
            if(inf == Z_STREAM_END) {
594
 
                at -= z.avail_in;
595
 
                inflateReset(&z);
596
 
                break;
597
 
            }
598
 
            else if(inf != Z_OK && inf != Z_BUF_ERROR) {
599
 
                at = map->len;
600
 
                break;
601
 
            }
602
 
        } while (z.avail_out == 0);
603
 
    }
604
 
 
605
 
    inflateEnd(&z);         
606
 
 
607
 
    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
608
 
        cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx));
609
 
        close(fd);
610
 
        if(!ctx->engine->keeptmp) {
611
 
            if (cli_unlink(tmpname)) {
612
 
                free(tmpname);
613
 
                return CL_EUNLINK;
614
 
            }
615
 
        }
616
 
        free(tmpname);
617
 
        return CL_VIRUS;
618
 
    }
619
 
    close(fd);
620
 
    if(!ctx->engine->keeptmp)
621
 
        if (cli_unlink(tmpname)) ret = CL_EUNLINK;
622
 
    free(tmpname);
623
 
    return ret;
624
 
}
625
 
 
626
 
#ifndef HAVE_BZLIB_H
627
 
static int cli_scanbzip(cli_ctx *ctx) {
628
 
    cli_warnmsg("cli_scanbzip: bzip2 support not compiled in\n");
629
 
    return CL_CLEAN;
630
 
}
631
 
 
632
 
#else
633
 
 
634
 
#ifdef NOBZ2PREFIX
635
 
#define BZ2_bzDecompressInit bzDecompressInit
636
 
#define BZ2_bzDecompress bzDecompress
637
 
#define BZ2_bzDecompressEnd bzDecompressEnd
638
 
#endif
639
 
 
640
 
static int cli_scanbzip(cli_ctx *ctx)
641
 
{
642
 
    int ret = CL_CLEAN, fd, rc;
643
 
    unsigned long int size = 0;
644
 
    char *tmpname;
645
 
    bz_stream strm;
646
 
    size_t off = 0;
647
 
    size_t avail;
648
 
    char buf[FILEBUFF];
649
 
 
650
 
    memset(&strm, 0, sizeof(strm));
651
 
    strm.next_out = buf;
652
 
    strm.avail_out = sizeof(buf);
653
 
    rc = BZ2_bzDecompressInit(&strm, 0, 0);
654
 
    if (BZ_OK != rc) {
655
 
        cli_dbgmsg("Bzip: DecompressInit failed: %d\n", rc);
656
 
        return CL_EOPEN;
657
 
    }
658
 
 
659
 
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd))) {
660
 
        cli_dbgmsg("Bzip: Can't generate temporary file.\n");
661
 
        BZ2_bzDecompressEnd(&strm);
662
 
        return ret;
663
 
    }
664
 
 
665
 
    do {
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;
669
 
            off += avail;
670
 
            if (!strm.avail_in) {
671
 
                cli_dbgmsg("Bzip: premature end of compressed stream\n");
672
 
                break;
673
 
            }
674
 
        }
675
 
 
676
 
        rc = BZ2_bzDecompress(&strm);
677
 
        if (BZ_OK != rc && BZ_STREAM_END != rc) {
678
 
            cli_dbgmsg("Bzip: decompress error: %d\n", rc);
679
 
            break;
680
 
        }
681
 
 
682
 
        if (!strm.avail_out || BZ_STREAM_END == rc) {
683
 
            size += sizeof(buf) - strm.avail_out;
684
 
 
685
 
            if(cli_checklimits("Bzip", ctx, size + FILEBUFF, 0, 0)!=CL_CLEAN)
686
 
                break;
687
 
 
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);
691
 
                close(fd);
692
 
                if(!ctx->engine->keeptmp) {
693
 
                    if (cli_unlink(tmpname)) {
694
 
                        free(tmpname);
695
 
                        return CL_EUNLINK;
696
 
                    }
697
 
                }
698
 
                free(tmpname);
699
 
                return CL_EWRITE;
700
 
            }
701
 
            strm.next_out = buf;
702
 
            strm.avail_out = sizeof(buf);
703
 
        }
704
 
    } while (BZ_STREAM_END != rc);
705
 
 
706
 
    BZ2_bzDecompressEnd(&strm);
707
 
 
708
 
    if(ret == CL_VIRUS) {
709
 
        close(fd);
710
 
        if(!ctx->engine->keeptmp)
711
 
            if (cli_unlink(tmpname)) ret = CL_EUNLINK;
712
 
        free(tmpname);
713
 
        return ret;
714
 
    }
715
 
 
716
 
    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
717
 
        cli_dbgmsg("Bzip: Infected with %s\n", cli_get_last_virus(ctx));
718
 
    }
719
 
    close(fd);
720
 
    if(!ctx->engine->keeptmp)
721
 
        if (cli_unlink(tmpname)) ret = CL_EUNLINK;
722
 
    free(tmpname);
723
 
 
724
 
    return ret;
725
 
}
726
 
#endif
727
 
 
728
 
static int cli_scanxz(cli_ctx *ctx)
729
 
{
730
 
    int ret = CL_CLEAN, fd, rc;
731
 
    unsigned long int size = 0;
732
 
    char *tmpname;
733
 
    struct CLI_XZ strm;
734
 
    size_t off = 0;
735
 
    size_t avail;
736
 
    unsigned char *buf;
737
 
 
738
 
    buf = cli_malloc(CLI_XZ_OBUF_SIZE);
739
 
    if (buf == NULL) {
740
 
        cli_errmsg("cli_scanxz: nomemory for decompress buffer.\n");
741
 
        return CL_EMEM;
742
 
    }
743
 
    memset(&strm, 0x00, sizeof(struct CLI_XZ));
744
 
    strm.next_out = buf;
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);
749
 
        free(buf);
750
 
        return CL_EOPEN;
751
 
    }
752
 
 
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);
756
 
        free(buf);
757
 
        return ret;
758
 
    }
759
 
    cli_dbgmsg("cli_scanxz: decompressing to file %s\n", tmpname);
760
 
 
761
 
    do {
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;
766
 
            off += avail;
767
 
            if (!strm.avail_in) {
768
 
                cli_errmsg("cli_scanxz: premature end of compressed stream\n");
769
 
                ret = CL_EFORMAT;
770
 
                goto xz_exit;
771
 
            }
772
 
        }
773
 
 
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);
778
 
            ret = CL_EFORMAT;
779
 
            goto xz_exit;
780
 
        }
781
 
        //cli_dbgmsg("cli_scanxz: xz decompressed %li of %li available bytes\n",
782
 
        //           avail - strm.avail_in, avail);
783
 
        
784
 
        /* write decompress buffer */
785
 
        if (!strm.avail_out || rc == XZ_STREAM_END) {            
786
 
            size_t towrite = CLI_XZ_OBUF_SIZE - strm.avail_out;
787
 
            size += towrite;
788
 
 
789
 
            //cli_dbgmsg("Writing %li bytes to XZ decompress temp file(%li byte total)\n",
790
 
            //           towrite, size);
791
 
 
792
 
            if((size_t)cli_writen(fd, buf, towrite) != towrite) {
793
 
                cli_errmsg("cli_scanxz: Can't write to file.\n");
794
 
                ret = CL_EWRITE;
795
 
                goto xz_exit;
796
 
            }
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);
800
 
                break;
801
 
            }
802
 
            strm.next_out = buf;
803
 
            strm.avail_out = CLI_XZ_OBUF_SIZE;
804
 
        }
805
 
    } while (XZ_STREAM_END != rc);
806
 
 
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));
810
 
    }
811
 
 
812
 
 xz_exit:
813
 
    cli_XzShutdown(&strm);
814
 
    close(fd);
815
 
    if(!ctx->engine->keeptmp)
816
 
        if (cli_unlink(tmpname) && ret == CL_CLEAN)
817
 
            ret = CL_EUNLINK;
818
 
    free(tmpname);
819
 
    free(buf);
820
 
    return ret;
821
 
}
822
 
 
823
 
static int cli_scanszdd(cli_ctx *ctx)
824
 
{
825
 
        int ofd, ret;
826
 
        char *tmpname;
827
 
 
828
 
 
829
 
    cli_dbgmsg("in cli_scanszdd()\n");
830
 
 
831
 
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &ofd))) {
832
 
        cli_dbgmsg("MSEXPAND: Can't generate temporary file/descriptor\n");
833
 
        return ret;
834
 
    }
835
 
 
836
 
    ret = cli_msexpand(ctx, ofd);
837
 
 
838
 
    if(ret != CL_SUCCESS) { /* CL_VIRUS or some error */
839
 
        close(ofd);
840
 
        if(!ctx->engine->keeptmp)
841
 
            if (cli_unlink(tmpname)) ret = CL_EUNLINK;
842
 
        free(tmpname);  
843
 
        return ret;
844
 
    }
845
 
 
846
 
    cli_dbgmsg("MSEXPAND: Decompressed into %s\n", tmpname);
847
 
    ret = cli_magic_scandesc(ofd, ctx);
848
 
    close(ofd);
849
 
    if(!ctx->engine->keeptmp)
850
 
        if (cli_unlink(tmpname)) ret = CL_EUNLINK;
851
 
    free(tmpname);      
852
 
 
853
 
    return ret;
854
 
}
855
 
 
856
 
static int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset)
857
 
{
858
 
        char *tempname;
859
 
        int ret;
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;
865
 
 
866
 
    cli_dbgmsg("in cli_scanmscab()\n");
867
 
 
868
 
    if((ret = cab_open(*ctx->fmap, sfx_offset, &cab)))
869
 
        return ret;
870
 
 
871
 
    for(file = cab.files; file; file = file->next) {
872
 
        files++;
873
 
 
874
 
        if(cli_matchmeta(ctx, file->name, 0, file->length, 0, files, 0, NULL) == CL_VIRUS) {
875
 
            if (!SCAN_ALL) {
876
 
                ret = CL_VIRUS;
877
 
                break;
878
 
            }
879
 
            viruses_found++;
880
 
        }
881
 
 
882
 
        if(ctx->engine->maxscansize && ctx->scansize >= ctx->engine->maxscansize) {
883
 
            ret = CL_CLEAN;
884
 
            break;
885
 
        }
886
 
 
887
 
        if(!(tempname = cli_gentemp(ctx->engine->tmpdir))) {
888
 
            ret = CL_EMEM;
889
 
            break;
890
 
        }
891
 
 
892
 
        if(ctx->engine->maxscansize && ctx->scansize + ctx->engine->maxfilesize >= ctx->engine->maxscansize)
893
 
            file->max_size = ctx->engine->maxscansize - ctx->scansize;
894
 
        else
895
 
            file->max_size = ctx->engine->maxfilesize ? ctx->engine->maxfilesize : 0xffffffff;
896
 
 
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));
901
 
        } else {
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;
906
 
            }
907
 
            ret = cli_scanfile(tempname, ctx);
908
 
            ctx->corrupted_input = corrupted_input;
909
 
        }
910
 
        if(!ctx->engine->keeptmp) {
911
 
            if (!access(tempname, R_OK) && cli_unlink(tempname)) {
912
 
                free(tempname);
913
 
                ret = CL_EUNLINK;
914
 
                break;
915
 
            }
916
 
        }
917
 
        free(tempname);
918
 
        if(ret == CL_VIRUS) {
919
 
            if (SCAN_ALL)
920
 
                viruses_found++;
921
 
            else
922
 
                break;
923
 
        }
924
 
    }
925
 
 
926
 
    cab_free(&cab);
927
 
    if (viruses_found)
928
 
        return CL_VIRUS;
929
 
    return ret;
930
 
}
931
 
 
932
 
static int vba_scandata(const unsigned char *data, unsigned int len, cli_ctx *ctx)
933
 
{
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];
938
 
        int ret;
939
 
        unsigned int viruses_found = 0;
940
 
 
941
 
    if((ret = cli_ac_initdata(&tmdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
942
 
        return ret;
943
 
 
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);
946
 
        return ret;
947
 
    }
948
 
    mdata[0] = &tmdata;
949
 
    mdata[1] = &gmdata;
950
 
 
951
 
    ret = cli_scanbuff(data, len, 0, ctx, CL_TYPE_MSOLE2, mdata);
952
 
    if (ret == CL_VIRUS)
953
 
        viruses_found++;
954
 
 
955
 
    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
956
 
        ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL);
957
 
        if (ret == CL_VIRUS)
958
 
            viruses_found++;
959
 
 
960
 
        if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL))
961
 
            ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL);
962
 
    }
963
 
    cli_ac_freedata(&tmdata);
964
 
    cli_ac_freedata(&gmdata);
965
 
 
966
 
    return (ret != CL_CLEAN)?ret:viruses_found?CL_VIRUS:CL_CLEAN;
967
 
}
968
 
 
969
 
static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
970
 
{
971
 
        int ret = CL_CLEAN, i, j, fd, data_len, hasmacros = 0;
972
 
        vba_project_t *vba_project;
973
 
        DIR *dd;
974
 
        struct dirent *dent;
975
 
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
976
 
        union {
977
 
            struct dirent d;
978
 
            char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
979
 
        } result;
980
 
#endif
981
 
        STATBUF statbuf;
982
 
        char *fullname, vbaname[1024];
983
 
        unsigned char *data;
984
 
        char *hash;
985
 
        uint32_t hashcnt;
986
 
        unsigned int viruses_found = 0;
987
 
 
988
 
 
989
 
    cli_dbgmsg("VBADir: %s\n", dirname);
990
 
    hashcnt = uniq_get(U, "_vba_project", 12, NULL);
991
 
    while(hashcnt--) {
992
 
        if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue;
993
 
 
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);
1002
 
                close(fd);
1003
 
                hasmacros++;
1004
 
                if(!data) {
1005
 
                    cli_dbgmsg("VBADir: WARNING: VBA project '%s_%u' decompressed to NULL\n", vba_project->name[i], j);
1006
 
                } else {
1007
 
                    /* cli_dbgmsg("Project content:\n%s", data); */
1008
 
                    if(ctx->scanned)
1009
 
                        *ctx->scanned += data_len / CL_COUNT_PRECISION;
1010
 
                    if(vba_scandata(data, data_len, ctx) == CL_VIRUS) {
1011
 
                        if (SCAN_ALL) 
1012
 
                            viruses_found++;
1013
 
                        else {
1014
 
                            free(data);
1015
 
                            ret = CL_VIRUS;
1016
 
                            break;
1017
 
                        }
1018
 
                    }
1019
 
                    free(data);
1020
 
                }
1021
 
            }
1022
 
        }
1023
 
 
1024
 
        free(vba_project->name);
1025
 
        free(vba_project->colls);
1026
 
        free(vba_project->dir);
1027
 
        free(vba_project->offset);
1028
 
        free(vba_project);
1029
 
        if (ret == CL_VIRUS && !SCAN_ALL)
1030
 
            break;
1031
 
    }
1032
 
 
1033
 
    if((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) && 
1034
 
        (hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
1035
 
        while(hashcnt--) {
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) {
1042
 
                    ret = CL_VIRUS;
1043
 
                    viruses_found++;
1044
 
                }
1045
 
                if(!ctx->engine->keeptmp)
1046
 
                    cli_rmdirs(fullname);
1047
 
                free(fullname);
1048
 
            }
1049
 
            close(fd);
1050
 
        }
1051
 
    }
1052
 
 
1053
 
    if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) && 
1054
 
        (hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
1055
 
        while(hashcnt--) {
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;
1060
 
            
1061
 
            if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) {
1062
 
                close(fd);
1063
 
                continue;
1064
 
            }
1065
 
 
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]);
1069
 
                if(!data) {
1070
 
                        cli_dbgmsg("VBADir: WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i);
1071
 
                } else {
1072
 
                        cli_dbgmsg("Project content:\n%s", data);
1073
 
                        if(ctx->scanned)
1074
 
                            *ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION;
1075
 
                        if(vba_scandata(data, vba_project->length[i], ctx) == CL_VIRUS) {
1076
 
                            if (SCAN_ALL)
1077
 
                                viruses_found++;
1078
 
                            else {
1079
 
                                free(data);
1080
 
                                ret = CL_VIRUS;
1081
 
                                break;
1082
 
                            }
1083
 
                        }
1084
 
                        free(data);
1085
 
                }
1086
 
            }
1087
 
 
1088
 
            close(fd);
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);
1095
 
            free(vba_project);
1096
 
            if(ret == CL_VIRUS) {
1097
 
                if (SCAN_ALL)
1098
 
                    viruses_found++;
1099
 
                else
1100
 
                    break;
1101
 
            }
1102
 
        }
1103
 
    }
1104
 
 
1105
 
    if(ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
1106
 
        return ret;
1107
 
 
1108
 
#if HAVE_JSON
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);
1112
 
        while(hashcnt--) {
1113
 
            snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
1114
 
            vbaname[sizeof(vbaname)-1] = '\0';
1115
 
 
1116
 
            fd = open(vbaname, O_RDONLY|O_BINARY);
1117
 
            if (fd >= 0) {
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);
1121
 
                close(fd);
1122
 
            }
1123
 
        }
1124
 
 
1125
 
        hashcnt = uniq_get(U, "_5_documentsummaryinformation", 29, &hash);
1126
 
        while(hashcnt--) {
1127
 
            snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
1128
 
            vbaname[sizeof(vbaname)-1] = '\0';
1129
 
 
1130
 
            fd = open(vbaname, O_RDONLY|O_BINARY);
1131
 
            if (fd >= 0) {
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);
1135
 
                close(fd);
1136
 
            }
1137
 
        }
1138
 
    }
1139
 
#endif    
1140
 
 
1141
 
    /* Check directory for embedded OLE objects */
1142
 
    hashcnt = uniq_get(U, "_1_ole10native", 14, &hash);
1143
 
    while(hashcnt--) {
1144
 
        snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
1145
 
        vbaname[sizeof(vbaname)-1] = '\0';
1146
 
 
1147
 
        fd = open(vbaname, O_RDONLY|O_BINARY);
1148
 
        if (fd >= 0) {
1149
 
            ret = cli_scan_ole10(fd, ctx);
1150
 
            close(fd);
1151
 
            if(ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
1152
 
                return ret;
1153
 
        }
1154
 
    }
1155
 
 
1156
 
 
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) */
1160
 
 
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))) {
1166
 
#else
1167
 
        while((dent = readdir(dd))) {
1168
 
#endif
1169
 
            if(dent->d_ino)
1170
 
            {
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);
1174
 
                    if(!fullname) {
1175
 
                cli_dbgmsg("cli_vba_scandir: Unable to allocate memory for fullname\n");
1176
 
                        ret = CL_EMEM;
1177
 
                        break;
1178
 
                    }
1179
 
                    sprintf(fullname, "%s"PATHSEP"%s", dirname, dent->d_name);
1180
 
 
1181
 
                    /* stat the file */
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) {
1185
 
                              if (SCAN_ALL)
1186
 
                                  viruses_found++;
1187
 
                              else {
1188
 
                                  ret = CL_VIRUS;
1189
 
                                  free(fullname);
1190
 
                                  break;
1191
 
                              }
1192
 
                          }
1193
 
                    }
1194
 
                    free(fullname);
1195
 
                }
1196
 
            }
1197
 
        }
1198
 
    } else {
1199
 
        cli_dbgmsg("VBADir: Can't open directory %s.\n", dirname);
1200
 
        return CL_EOPEN;
1201
 
    }
1202
 
 
1203
 
    closedir(dd);
1204
 
#if HAVE_JSON
1205
 
    if (hasmacros && ctx->options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL)
1206
 
        cli_jsonbool(ctx->wrkproperty, "HasMacros", 1);
1207
 
#endif
1208
 
    if(BLOCK_MACROS && hasmacros) {
1209
 
        cli_append_virus(ctx, "Heuristics.OLE2.ContainsMacros");
1210
 
        ret = CL_VIRUS;
1211
 
        viruses_found++;
1212
 
    }
1213
 
    if (SCAN_ALL && viruses_found)
1214
 
        return CL_VIRUS;
1215
 
    return ret;
1216
 
}
1217
 
 
1218
 
static int cli_scanhtml(cli_ctx *ctx)
1219
 
{
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;
1225
 
 
1226
 
    cli_dbgmsg("in cli_scanhtml()\n");
1227
 
 
1228
 
    /* CL_ENGINE_MAX_HTMLNORMALIZE */
1229
 
    if(curr_len > ctx->engine->maxhtmlnormalize) {
1230
 
        cli_dbgmsg("cli_scanhtml: exiting (file larger than MaxHTMLNormalize)\n");
1231
 
        return CL_CLEAN;
1232
 
    }
1233
 
 
1234
 
    if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
1235
 
        return CL_EMEM;
1236
 
 
1237
 
    if(mkdir(tempname, 0700)) {
1238
 
        cli_errmsg("cli_scanhtml: Can't create temporary directory %s\n", tempname);
1239
 
        free(tempname);
1240
 
        return CL_ETMPDIR;
1241
 
    }
1242
 
 
1243
 
    cli_dbgmsg("cli_scanhtml: using tempdir %s\n", tempname);
1244
 
 
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);
1248
 
    if (fd >= 0) {
1249
 
        if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
1250
 
            viruses_found++;
1251
 
        close(fd);
1252
 
    }
1253
 
 
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");
1261
 
        }
1262
 
        else {
1263
 
            snprintf(fullname, 1024, "%s"PATHSEP"notags.html", tempname);
1264
 
            fd = open(fullname, O_RDONLY|O_BINARY);
1265
 
            if(fd >= 0) {
1266
 
                if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS) 
1267
 
                    viruses_found++;
1268
 
                close(fd);
1269
 
            }
1270
 
        }
1271
 
    }
1272
 
 
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);
1276
 
            if(fd >= 0) {
1277
 
                if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
1278
 
                    viruses_found++;
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)
1281
 
                        viruses_found++;
1282
 
                }
1283
 
                close(fd);
1284
 
            }
1285
 
    }
1286
 
 
1287
 
    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
1288
 
        snprintf(fullname, 1024, "%s"PATHSEP"rfc2397", tempname);
1289
 
        ret = cli_scandir(fullname, ctx);
1290
 
    }
1291
 
 
1292
 
    if(!ctx->engine->keeptmp)
1293
 
        cli_rmdirs(tempname);
1294
 
 
1295
 
    free(tempname);
1296
 
    if (SCAN_ALL && viruses_found)
1297
 
        return CL_VIRUS;
1298
 
    return ret;
1299
 
}
1300
 
 
1301
 
static int cli_scanscript(cli_ctx *ctx)
1302
 
{
1303
 
    const unsigned char *buff;
1304
 
    unsigned char* normalized;
1305
 
    struct text_norm_state state;
1306
 
    char *tmpname = NULL;
1307
 
    int ofd = -1, ret;
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];
1313
 
    fmap_t *map;
1314
 
    size_t at = 0;
1315
 
    unsigned int viruses_found = 0;
1316
 
    uint64_t curr_len;
1317
 
    struct cli_target_info info;
1318
 
 
1319
 
    if (!ctx || !ctx->engine->root)
1320
 
        return CL_ENULLARG;
1321
 
 
1322
 
    map = *ctx->fmap;
1323
 
    curr_len = map->len;
1324
 
    groot = ctx->engine->root[0];
1325
 
    troot = ctx->engine->root[7];
1326
 
    maxpatlen = troot ? troot->maxpatlen : 0;
1327
 
 
1328
 
    cli_dbgmsg("in cli_scanscript()\n");
1329
 
 
1330
 
    /* CL_ENGINE_MAX_SCRIPTNORMALIZE */
1331
 
    if(curr_len > ctx->engine->maxscriptnormalize) {
1332
 
        cli_dbgmsg("cli_scanscript: exiting (file larger than MaxScriptSize)\n");
1333
 
        return CL_CLEAN;
1334
 
    }
1335
 
 
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");
1341
 
                        return ret;
1342
 
                }
1343
 
                cli_dbgmsg("cli_scanscript: saving normalized file to %s\n", tmpname);
1344
 
        }
1345
 
 
1346
 
        if(!(normalized = cli_malloc(SCANBUFF + maxpatlen))) {
1347
 
                cli_dbgmsg("cli_scanscript: Unable to malloc %u bytes\n", SCANBUFF);
1348
 
        free(tmpname);
1349
 
                return CL_EMEM;
1350
 
        }
1351
 
 
1352
 
        text_normalize_init(&state, normalized, SCANBUFF + maxpatlen);
1353
 
        ret = CL_CLEAN;
1354
 
 
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))) {
1356
 
        free(tmpname);
1357
 
            return ret;
1358
 
        }
1359
 
 
1360
 
        if (troot) {
1361
 
            cli_targetinfo(&info, 7, map);
1362
 
            ret = cli_ac_caloff(troot, &tmdata, &info);
1363
 
            if (ret) {
1364
 
                cli_ac_freedata(&tmdata);
1365
 
        free(tmpname);
1366
 
                return ret;
1367
 
            }
1368
 
        }
1369
 
 
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);
1372
 
        free(tmpname);
1373
 
            return ret;
1374
 
        }
1375
 
        mdata[0] = &tmdata;
1376
 
        mdata[1] = &gmdata;
1377
 
 
1378
 
        while(1) {
1379
 
            size_t len = MIN(map->pgsz, map->len - at);
1380
 
            buff = fmap_need_off_once(map, at, len);
1381
 
            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);
1386
 
                    close(ofd);
1387
 
                    ofd = -1;
1388
 
                    /* we can continue to scan in memory */
1389
 
                }
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) {
1392
 
                    if (SCAN_ALL)
1393
 
                        viruses_found++;
1394
 
                    else {
1395
 
                        ret = CL_VIRUS;
1396
 
                        break;
1397
 
                    }
1398
 
                }
1399
 
                if(ctx->scanned)
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;
1407
 
            }
1408
 
            if(!len) break;
1409
 
            if(!buff || text_normalize_buffer(&state, buff, len) != len) {
1410
 
                cli_dbgmsg("cli_scanscript: short read during normalizing\n");
1411
 
            }
1412
 
        }
1413
 
        if(ctx->engine->keeptmp) {
1414
 
                free(tmpname);
1415
 
        if (ofd >= 0)
1416
 
            close(ofd);
1417
 
        }
1418
 
        free(normalized);
1419
 
        if(ret != CL_VIRUS || SCAN_ALL)  {
1420
 
            if ((ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL)) == CL_VIRUS)
1421
 
                viruses_found++;
1422
 
            if(ret != CL_VIRUS || SCAN_ALL)
1423
 
                if ((ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL)) == CL_VIRUS)
1424
 
                    viruses_found++;
1425
 
        }
1426
 
        cli_ac_freedata(&tmdata);
1427
 
        cli_ac_freedata(&gmdata);
1428
 
 
1429
 
        if (SCAN_ALL && viruses_found)
1430
 
            return CL_VIRUS;
1431
 
        return ret;
1432
 
}
1433
 
 
1434
 
static int cli_scanhtml_utf16(cli_ctx *ctx)
1435
 
{
1436
 
        char *tempname, *decoded;
1437
 
        const char *buff;
1438
 
        int ret = CL_CLEAN, fd, bytes;
1439
 
        size_t at = 0;
1440
 
        fmap_t *map = *ctx->fmap;
1441
 
 
1442
 
    cli_dbgmsg("in cli_scanhtml_utf16()\n");
1443
 
 
1444
 
    if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
1445
 
        return CL_EMEM;
1446
 
 
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);
1449
 
        free(tempname);
1450
 
        return CL_EOPEN;
1451
 
    }
1452
 
 
1453
 
    cli_dbgmsg("cli_scanhtml_utf16: using tempfile %s\n", tempname);
1454
 
 
1455
 
    while(at < map->len) {
1456
 
        bytes = MIN(map->len - at, map->pgsz * 16);
1457
 
        if(!(buff = fmap_need_off_once(map, at, bytes))) {
1458
 
            close(fd);
1459
 
            cli_unlink(tempname);
1460
 
            free(tempname);
1461
 
            return CL_EREAD;
1462
 
        }
1463
 
        at += bytes;
1464
 
        decoded = cli_utf16toascii(buff, bytes);
1465
 
        if(decoded) {
1466
 
            if(write(fd, decoded, bytes / 2) == -1) {
1467
 
                cli_errmsg("cli_scanhtml_utf16: Can't write to file %s\n", tempname);
1468
 
                free(decoded);
1469
 
                close(fd);
1470
 
                cli_unlink(tempname);
1471
 
                free(tempname);
1472
 
                return CL_EWRITE;
1473
 
            }
1474
 
            free(decoded);
1475
 
        }
1476
 
    }
1477
 
 
1478
 
    *ctx->fmap = fmap(fd, 0, 0);
1479
 
    if(*ctx->fmap) {
1480
 
        ret = cli_scanhtml(ctx);
1481
 
        funmap(*ctx->fmap);
1482
 
    } else
1483
 
        cli_errmsg("cli_scanhtml_utf16: fmap of %s failed\n", tempname);
1484
 
 
1485
 
    *ctx->fmap = map;
1486
 
    close(fd);
1487
 
 
1488
 
    if(!ctx->engine->keeptmp) {
1489
 
        if (cli_unlink(tempname)) ret = CL_EUNLINK;
1490
 
    } else
1491
 
        cli_dbgmsg("cli_scanhtml_utf16: Decoded HTML data saved in %s\n", tempname);
1492
 
    free(tempname);
1493
 
 
1494
 
    return ret;
1495
 
}
1496
 
 
1497
 
static int cli_scanole2(cli_ctx *ctx)
1498
 
{
1499
 
        char *dir;
1500
 
        int ret = CL_CLEAN;
1501
 
        struct uniq *vba = NULL;
1502
 
 
1503
 
    cli_dbgmsg("in cli_scanole2()\n");
1504
 
 
1505
 
    if(ctx->engine->maxreclevel && ctx->recursion >= ctx->engine->maxreclevel)
1506
 
        return CL_EMAXREC;
1507
 
 
1508
 
    /* generate the temporary directory */
1509
 
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1510
 
        return CL_EMEM;
1511
 
 
1512
 
    if(mkdir(dir, 0700)) {
1513
 
        cli_dbgmsg("OLE2: Can't create temporary directory %s\n", dir);
1514
 
        free(dir);
1515
 
        return CL_ETMPDIR;
1516
 
    }
1517
 
 
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)
1522
 
            cli_rmdirs(dir);
1523
 
        free(dir);
1524
 
        return ret;
1525
 
    }
1526
 
 
1527
 
    if (vba) {
1528
 
        ctx->recursion++;
1529
 
 
1530
 
        ret = cli_vba_scandir(dir, ctx, vba);
1531
 
        uniq_free(vba);
1532
 
        if(ret != CL_VIRUS)
1533
 
            if(cli_scandir(dir, ctx) == CL_VIRUS)
1534
 
                ret = CL_VIRUS;
1535
 
        ctx->recursion--;
1536
 
    }
1537
 
 
1538
 
    if(!ctx->engine->keeptmp)
1539
 
        cli_rmdirs(dir);
1540
 
    free(dir);
1541
 
    return ret;
1542
 
}
1543
 
 
1544
 
static int cli_scantar(cli_ctx *ctx, unsigned int posix)
1545
 
{
1546
 
        char *dir;
1547
 
        int ret = CL_CLEAN;
1548
 
 
1549
 
 
1550
 
    cli_dbgmsg("in cli_scantar()\n");
1551
 
 
1552
 
    /* generate temporary directory */
1553
 
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1554
 
        return CL_EMEM;
1555
 
 
1556
 
    if(mkdir(dir, 0700)) {
1557
 
        cli_errmsg("Tar: Can't create temporary directory %s\n", dir);
1558
 
        free(dir);
1559
 
        return CL_ETMPDIR;
1560
 
    }
1561
 
 
1562
 
    ret = cli_untar(dir, posix, ctx);
1563
 
 
1564
 
    if(!ctx->engine->keeptmp)
1565
 
        cli_rmdirs(dir);
1566
 
 
1567
 
    free(dir);
1568
 
    return ret;
1569
 
}
1570
 
 
1571
 
static int cli_scanmschm(cli_ctx *ctx)
1572
 
{
1573
 
        int ret = CL_CLEAN, rc;
1574
 
        chm_metadata_t metadata;
1575
 
        char *dir;
1576
 
        unsigned int viruses_found = 0;
1577
 
 
1578
 
    cli_dbgmsg("in cli_scanmschm()\n");
1579
 
 
1580
 
     /* generate the temporary directory */
1581
 
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1582
 
        return CL_EMEM;
1583
 
 
1584
 
    if(mkdir(dir, 0700)) {
1585
 
        cli_dbgmsg("CHM: Can't create temporary directory %s\n", dir);
1586
 
        free(dir);
1587
 
        return CL_ETMPDIR;
1588
 
    }
1589
 
 
1590
 
    ret = cli_chm_open(dir, &metadata, ctx);
1591
 
    if (ret != CL_SUCCESS) {
1592
 
        if(!ctx->engine->keeptmp)
1593
 
            cli_rmdirs(dir);
1594
 
        free(dir);
1595
 
        cli_dbgmsg("CHM: Error: %s\n", cl_strerror(ret));
1596
 
        return ret;
1597
 
    }
1598
 
 
1599
 
   do {
1600
 
        ret = cli_chm_prepare_file(&metadata);
1601
 
        if (ret != CL_SUCCESS) {
1602
 
           break;
1603
 
        }
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));
1610
 
                if (SCAN_ALL)
1611
 
                    viruses_found++;
1612
 
                else {
1613
 
                    ret = CL_VIRUS;
1614
 
                    break;
1615
 
                }
1616
 
            }
1617
 
        }
1618
 
 
1619
 
    } while(ret == CL_SUCCESS);
1620
 
 
1621
 
    cli_chm_close(&metadata);
1622
 
   
1623
 
    if(!ctx->engine->keeptmp)
1624
 
        cli_rmdirs(dir);
1625
 
 
1626
 
    free(dir);
1627
 
 
1628
 
    cli_dbgmsg("CHM: Exit code: %d\n", ret);
1629
 
    if (ret == CL_BREAK)
1630
 
        ret = CL_CLEAN;
1631
 
 
1632
 
    if (SCAN_ALL && viruses_found)
1633
 
        return CL_VIRUS;
1634
 
    return ret;
1635
 
}
1636
 
 
1637
 
static int cli_scanscrenc(cli_ctx *ctx)
1638
 
{
1639
 
        char *tempname;
1640
 
        int ret = CL_CLEAN;
1641
 
 
1642
 
    cli_dbgmsg("in cli_scanscrenc()\n");
1643
 
 
1644
 
    if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
1645
 
        return CL_EMEM;
1646
 
 
1647
 
    if(mkdir(tempname, 0700)) {
1648
 
        cli_dbgmsg("CHM: Can't create temporary directory %s\n", tempname);
1649
 
        free(tempname);
1650
 
        return CL_ETMPDIR;
1651
 
    }
1652
 
 
1653
 
    if (html_screnc_decode(*ctx->fmap, tempname))
1654
 
        ret = cli_scandir(tempname, ctx);
1655
 
 
1656
 
    if(!ctx->engine->keeptmp)
1657
 
        cli_rmdirs(tempname);
1658
 
 
1659
 
    free(tempname);
1660
 
    return ret;
1661
 
}
1662
 
 
1663
 
static int cli_scanriff(cli_ctx *ctx)
1664
 
{
1665
 
        int ret = CL_CLEAN;
1666
 
 
1667
 
    if(cli_check_riff_exploit(ctx) == 2) {
1668
 
        ret = CL_VIRUS;
1669
 
        cli_append_virus(ctx, "Heuristics.Exploit.W32.MS05-002");
1670
 
    }
1671
 
 
1672
 
    return ret;
1673
 
}
1674
 
 
1675
 
static int cli_scanjpeg(cli_ctx *ctx)
1676
 
{
1677
 
        int ret = CL_CLEAN;
1678
 
 
1679
 
        if(cli_check_jpeg_exploit(ctx, 0) == 1) {
1680
 
        ret = CL_VIRUS;
1681
 
        cli_append_virus(ctx, "Heuristics.Exploit.W32.MS04-028");
1682
 
    }
1683
 
 
1684
 
    return ret;
1685
 
}
1686
 
 
1687
 
static int cli_scancryptff(cli_ctx *ctx)
1688
 
{
1689
 
        int ret = CL_CLEAN, ndesc;
1690
 
        unsigned int i;
1691
 
        const unsigned char *src;
1692
 
        unsigned char *dest = NULL;
1693
 
        char *tempfile;
1694
 
        size_t pos;
1695
 
        size_t bread;
1696
 
 
1697
 
 
1698
 
    /* Skip the CryptFF file header */
1699
 
    pos = 0x10;
1700
 
 
1701
 
    if((dest = (unsigned char *) cli_malloc(FILEBUFF)) == NULL) {
1702
 
        cli_dbgmsg("CryptFF: Can't allocate memory\n");
1703
 
        return CL_EMEM;
1704
 
    }
1705
 
 
1706
 
    if(!(tempfile = cli_gentemp(ctx->engine->tmpdir))) {
1707
 
        free(dest);
1708
 
        return CL_EMEM;
1709
 
    }
1710
 
 
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);
1713
 
        free(dest);
1714
 
        free(tempfile);
1715
 
        return CL_ECREAT;
1716
 
    }
1717
 
 
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);
1723
 
            free(dest);
1724
 
            close(ndesc);
1725
 
            free(tempfile);
1726
 
            return CL_EWRITE;
1727
 
        }
1728
 
    }
1729
 
 
1730
 
    free(dest);
1731
 
 
1732
 
 
1733
 
    cli_dbgmsg("CryptFF: Scanning decrypted data\n");
1734
 
 
1735
 
    if((ret = cli_magic_scandesc(ndesc, ctx)) == CL_VIRUS)
1736
 
        cli_dbgmsg("CryptFF: Infected with %s\n", cli_get_last_virus(ctx));
1737
 
 
1738
 
    close(ndesc);
1739
 
 
1740
 
    if(ctx->engine->keeptmp)
1741
 
        cli_dbgmsg("CryptFF: Decompressed data saved in %s\n", tempfile);
1742
 
    else
1743
 
        if (cli_unlink(tempfile)) ret = CL_EUNLINK;
1744
 
 
1745
 
    free(tempfile);
1746
 
    return ret;
1747
 
}
1748
 
 
1749
 
static int cli_scanpdf(cli_ctx *ctx, off_t offset)
1750
 
{
1751
 
        int ret;
1752
 
        char *dir = cli_gentemp(ctx->engine->tmpdir);
1753
 
 
1754
 
    if(!dir)
1755
 
        return CL_EMEM;
1756
 
 
1757
 
    if(mkdir(dir, 0700)) {
1758
 
        cli_dbgmsg("Can't create temporary directory for PDF file %s\n", dir);
1759
 
        free(dir);
1760
 
        return CL_ETMPDIR;
1761
 
    }
1762
 
 
1763
 
    ret = cli_pdf(dir, ctx, offset);
1764
 
 
1765
 
    if(!ctx->engine->keeptmp)
1766
 
        cli_rmdirs(dir);
1767
 
 
1768
 
    free(dir);
1769
 
    return ret;
1770
 
}
1771
 
 
1772
 
static int cli_scantnef(cli_ctx *ctx)
1773
 
{
1774
 
        int ret;
1775
 
        char *dir = cli_gentemp(ctx->engine->tmpdir);
1776
 
 
1777
 
    if(!dir)
1778
 
        return CL_EMEM;
1779
 
 
1780
 
    if(mkdir(dir, 0700)) {
1781
 
        cli_dbgmsg("Can't create temporary directory for tnef file %s\n", dir);
1782
 
        free(dir);
1783
 
        return CL_ETMPDIR;
1784
 
    }
1785
 
 
1786
 
    ret = cli_tnef(dir, ctx);
1787
 
 
1788
 
    if(ret == CL_CLEAN)
1789
 
        ret = cli_scandir(dir, ctx);
1790
 
 
1791
 
    if(!ctx->engine->keeptmp)
1792
 
        cli_rmdirs(dir);
1793
 
 
1794
 
    free(dir);
1795
 
    return ret;
1796
 
}
1797
 
 
1798
 
static int cli_scanuuencoded(cli_ctx *ctx)
1799
 
{
1800
 
        int ret;
1801
 
        char *dir = cli_gentemp(ctx->engine->tmpdir);
1802
 
 
1803
 
    if(!dir)
1804
 
        return CL_EMEM;
1805
 
 
1806
 
    if(mkdir(dir, 0700)) {
1807
 
        cli_dbgmsg("Can't create temporary directory for uuencoded file %s\n", dir);
1808
 
        free(dir);
1809
 
        return CL_ETMPDIR;
1810
 
    }
1811
 
 
1812
 
    ret = cli_uuencode(dir, *ctx->fmap);
1813
 
 
1814
 
    if(ret == CL_CLEAN)
1815
 
        ret = cli_scandir(dir, ctx);
1816
 
 
1817
 
    if(!ctx->engine->keeptmp)
1818
 
        cli_rmdirs(dir);
1819
 
 
1820
 
    free(dir);
1821
 
    return ret;
1822
 
}
1823
 
 
1824
 
static int cli_scanmail(cli_ctx *ctx)
1825
 
{
1826
 
        char *dir;
1827
 
        int ret;
1828
 
        unsigned int viruses_found = 0;
1829
 
 
1830
 
    cli_dbgmsg("Starting cli_scanmail(), recursion = %u\n", ctx->recursion);
1831
 
 
1832
 
    /* generate the temporary directory */
1833
 
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1834
 
        return CL_EMEM;
1835
 
 
1836
 
    if(mkdir(dir, 0700)) {
1837
 
        cli_dbgmsg("Mail: Can't create temporary directory %s\n", dir);
1838
 
        free(dir);
1839
 
        return CL_ETMPDIR;
1840
 
    }
1841
 
 
1842
 
    /*
1843
 
     * Extract the attachments into the temporary directory
1844
 
     */
1845
 
    if((ret = cli_mbox(dir, ctx))) {
1846
 
        if (ret == CL_VIRUS && SCAN_ALL)
1847
 
            viruses_found++;
1848
 
        else {
1849
 
            if(!ctx->engine->keeptmp)
1850
 
                cli_rmdirs(dir);
1851
 
            free(dir);
1852
 
            return ret;
1853
 
        }
1854
 
    }
1855
 
 
1856
 
    ret = cli_scandir(dir, ctx);
1857
 
 
1858
 
    if(!ctx->engine->keeptmp)
1859
 
        cli_rmdirs(dir);
1860
 
 
1861
 
    free(dir);
1862
 
    if (SCAN_ALL && viruses_found)
1863
 
        return CL_VIRUS;
1864
 
    return ret;
1865
 
}
1866
 
 
1867
 
static int cli_scan_structured(cli_ctx *ctx)
1868
 
{
1869
 
        char buf[8192];
1870
 
        int result = 0;
1871
 
        unsigned int cc_count = 0;
1872
 
        unsigned int ssn_count = 0;
1873
 
        int done = 0;
1874
 
        fmap_t *map;
1875
 
        size_t pos = 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;
1879
 
 
1880
 
    if(ctx == NULL)
1881
 
        return CL_ENULLARG;
1882
 
 
1883
 
    map = *ctx->fmap;
1884
 
 
1885
 
    if(ctx->engine->min_cc_count == 1)
1886
 
        ccfunc = dlp_has_cc;
1887
 
    else
1888
 
        ccfunc = dlp_get_cc_count;
1889
 
 
1890
 
    switch((ctx->options & CL_SCAN_STRUCTURED_SSN_NORMAL) | (ctx->options & CL_SCAN_STRUCTURED_SSN_STRIPPED)) {
1891
 
 
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;
1895
 
            else
1896
 
                ssnfunc = dlp_get_ssn_count;
1897
 
            break;
1898
 
 
1899
 
        case CL_SCAN_STRUCTURED_SSN_NORMAL:
1900
 
            if(ctx->engine->min_ssn_count == 1)
1901
 
                ssnfunc = dlp_has_normal_ssn;
1902
 
            else
1903
 
                ssnfunc = dlp_get_normal_ssn_count;
1904
 
            break;
1905
 
 
1906
 
        case CL_SCAN_STRUCTURED_SSN_STRIPPED:
1907
 
            if(ctx->engine->min_ssn_count == 1)
1908
 
                ssnfunc = dlp_has_stripped_ssn;
1909
 
            else
1910
 
                ssnfunc = dlp_get_stripped_ssn_count;
1911
 
            break;
1912
 
 
1913
 
        default:
1914
 
            ssnfunc = NULL;
1915
 
    }
1916
 
 
1917
 
    while(!done && ((result = fmap_readn(map, buf, pos, 8191)) > 0)) {
1918
 
        pos += result;
1919
 
        if((cc_count += ccfunc((const unsigned char *)buf, result)) >= ctx->engine->min_cc_count)
1920
 
            done = 1;
1921
 
 
1922
 
        if(ssnfunc && ((ssn_count += ssnfunc((const unsigned char *)buf, result)) >= ctx->engine->min_ssn_count))
1923
 
            done = 1;
1924
 
    }
1925
 
 
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");
1929
 
        if (SCAN_ALL)
1930
 
            viruses_found++;
1931
 
        else
1932
 
            return CL_VIRUS;
1933
 
    }
1934
 
 
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");
1938
 
        if (SCAN_ALL)
1939
 
            viruses_found++;
1940
 
        else
1941
 
            return CL_VIRUS;
1942
 
    }
1943
 
 
1944
 
    if (SCAN_ALL && viruses_found)
1945
 
        return CL_VIRUS;
1946
 
    return CL_CLEAN;
1947
 
}
1948
 
 
1949
 
static int cli_scanembpe(cli_ctx *ctx, off_t offset)
1950
 
{
1951
 
        int fd, bytes, ret = CL_CLEAN;
1952
 
        unsigned long int size = 0, todo;
1953
 
        const char *buff;
1954
 
        char *tmpname;
1955
 
        fmap_t *map = *ctx->fmap;
1956
 
        unsigned int corrupted_input;
1957
 
 
1958
 
    tmpname = cli_gentemp(ctx->engine->tmpdir);
1959
 
    if(!tmpname)
1960
 
        return CL_EMEM;
1961
 
 
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);
1964
 
        free(tmpname);
1965
 
        return CL_ECREAT;
1966
 
    }
1967
 
 
1968
 
    todo = map->len - offset;
1969
 
    while(1) {
1970
 
        bytes = MIN(todo, map->pgsz);
1971
 
        if(!bytes)
1972
 
            break;
1973
 
 
1974
 
        if(!(buff = fmap_need_off_once(map, offset + size, bytes))) {
1975
 
            close(fd);
1976
 
            if(!ctx->engine->keeptmp) {
1977
 
                if (cli_unlink(tmpname)) {
1978
 
                    free(tmpname);
1979
 
                    return CL_EUNLINK;
1980
 
                }
1981
 
            }
1982
 
            free(tmpname);
1983
 
            return CL_EREAD;
1984
 
        }
1985
 
        size += bytes;
1986
 
        todo -= bytes;
1987
 
 
1988
 
        if(cli_checklimits("cli_scanembpe", ctx, size, 0, 0)!=CL_CLEAN)
1989
 
            break;
1990
 
 
1991
 
        if(cli_writen(fd, buff, bytes) != bytes) {
1992
 
            cli_dbgmsg("cli_scanembpe: Can't write to temporary file\n");
1993
 
            close(fd);
1994
 
            if(!ctx->engine->keeptmp) {
1995
 
                if (cli_unlink(tmpname)) {
1996
 
                    free(tmpname);
1997
 
                    return CL_EUNLINK;
1998
 
                }
1999
 
            }
2000
 
            free(tmpname);
2001
 
            return CL_EWRITE;
2002
 
        }
2003
 
    }
2004
 
 
2005
 
    ctx->recursion++;
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));
2012
 
        close(fd);
2013
 
        if(!ctx->engine->keeptmp) {
2014
 
            if (cli_unlink(tmpname)) {
2015
 
                free(tmpname);
2016
 
                return CL_EUNLINK;
2017
 
            }
2018
 
        }
2019
 
        free(tmpname);  
2020
 
        return CL_VIRUS;
2021
 
    }
2022
 
    ctx->recursion--;
2023
 
 
2024
 
    close(fd);
2025
 
    if(!ctx->engine->keeptmp) {
2026
 
        if (cli_unlink(tmpname)) {
2027
 
            free(tmpname);
2028
 
            return CL_EUNLINK;
2029
 
        }
2030
 
    }
2031
 
    free(tmpname);
2032
 
 
2033
 
    /* intentionally ignore possible errors from cli_magic_scandesc */
2034
 
    return CL_CLEAN;
2035
 
}
2036
 
 
2037
 
 
2038
 
#if defined(_WIN32) || defined(C_LINUX)
2039
 
#define PERF_MEASURE
2040
 
#endif
2041
 
 
2042
 
#ifdef PERF_MEASURE
2043
 
 
2044
 
static struct {
2045
 
    enum perfev id;
2046
 
    const char *name;
2047
 
    enum ev_type type;
2048
 
} perf_events[] = {
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}
2063
 
};
2064
 
 
2065
 
static void get_thread_times(uint64_t *kt, uint64_t *ut)
2066
 
{
2067
 
#ifdef _WIN32
2068
 
    FILETIME c,e,k,u;
2069
 
    ULARGE_INTEGER kl,ul;
2070
 
    if (!GetThreadTimes(GetCurrentThread(), &c, &e, &k, &u)) {
2071
 
        *kt = *ut = 0;
2072
 
        return;
2073
 
    }
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;
2080
 
#else
2081
 
    struct tms tbuf;
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;
2086
 
    } else {
2087
 
        *kt = *ut = 0;
2088
 
    }
2089
 
#endif
2090
 
}
2091
 
 
2092
 
static inline void perf_init(cli_ctx *ctx)
2093
 
{
2094
 
    uint64_t kt,ut;
2095
 
    unsigned i;
2096
 
 
2097
 
    if (!(ctx->options & CL_SCAN_PERFORMANCE_INFO))
2098
 
        return;
2099
 
 
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)
2104
 
            continue;
2105
 
    }
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);
2110
 
}
2111
 
 
2112
 
static inline void perf_done(cli_ctx* ctx)
2113
 
{
2114
 
    char timestr[512];
2115
 
    char *p;
2116
 
    unsigned i;
2117
 
    uint64_t kt,ut;
2118
 
    char *pend;
2119
 
    cli_events_t *perf = ctx->perf;
2120
 
 
2121
 
    if (!perf)
2122
 
        return;
2123
 
 
2124
 
    p = timestr;
2125
 
    pend = timestr + sizeof(timestr) - 1;
2126
 
    *pend = 0;
2127
 
 
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);
2132
 
 
2133
 
    for (i=0;i<sizeof(perf_events)/sizeof(perf_events[0]);i++) {
2134
 
        union ev_val val;
2135
 
        unsigned count;
2136
 
 
2137
 
        cli_event_get(perf, perf_events[i].id, &val, &count);
2138
 
        if (p < pend)
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));
2142
 
    }
2143
 
    *p = 0;
2144
 
    cli_infomsg(ctx, "performance: %s\n", timestr);
2145
 
 
2146
 
 
2147
 
    cli_events_free(perf);
2148
 
    ctx->perf = NULL;
2149
 
}
2150
 
 
2151
 
static inline void perf_start(cli_ctx* ctx, int id)
2152
 
{
2153
 
    cli_event_time_start(ctx->perf, id);
2154
 
}
2155
 
 
2156
 
static inline void perf_stop(cli_ctx* ctx, int id)
2157
 
{
2158
 
    cli_event_time_stop(ctx->perf, id);
2159
 
}
2160
 
 
2161
 
static inline void perf_nested_start(cli_ctx* ctx, int id, int nestedid)
2162
 
{
2163
 
    cli_event_time_nested_start(ctx->perf, id, nestedid);
2164
 
}
2165
 
 
2166
 
static inline void perf_nested_stop(cli_ctx* ctx, int id, int nestedid)
2167
 
{
2168
 
    cli_event_time_nested_stop(ctx->perf, id, nestedid);
2169
 
}
2170
 
 
2171
 
 
2172
 
#else
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); }
2179
 
#endif
2180
 
 
2181
 
 
2182
 
static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_t *dettype, unsigned char *refhash)
2183
 
{
2184
 
        int ret = CL_CLEAN, nret = CL_CLEAN;
2185
 
        struct cli_matched_type *ftoffset = NULL, *fpt;
2186
 
        uint32_t lastrar;
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;
2192
 
 
2193
 
 
2194
 
    if(ctx->engine->maxreclevel && ctx->recursion >= ctx->engine->maxreclevel)
2195
 
        return CL_EMAXREC;
2196
 
 
2197
 
    perf_start(ctx, PERFT_RAW);
2198
 
    if(typercg)
2199
 
        acmode |= AC_SCAN_FT;
2200
 
 
2201
 
    ret = cli_fmap_scandesc(ctx, type == CL_TYPE_TEXT_ASCII ? 0 : type, 0, &ftoffset, acmode, NULL, refhash);
2202
 
    perf_stop(ctx, PERFT_RAW);
2203
 
 
2204
 
    if(ret >= CL_TYPENO) {
2205
 
        perf_nested_start(ctx, PERFT_RAWTYPENO, PERFT_SCAN);
2206
 
        ctx->recursion++;
2207
 
        lastrar = 0xdeadbeef;
2208
 
        fpt = ftoffset;
2209
 
 
2210
 
        while(fpt) {
2211
 
            if(fpt->offset) switch(fpt->type) {
2212
 
                case CL_TYPE_XDP:
2213
 
                    ret = cli_scanxdp(ctx);
2214
 
                    break;
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 */
2223
 
                        if(tmpfd == -1) {
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");
2227
 
                                ret = nret;
2228
 
                                break_loop = 1;
2229
 
                                break;
2230
 
                            }
2231
 
                        }
2232
 
                        /* scan existing file */
2233
 
                        nret = cli_scanrar(tmpfd, ctx, fpt->offset, &lastrar);
2234
 
                        /* if dumped tempfile, need to cleanup */
2235
 
                        if(tmpname) {
2236
 
                            close(tmpfd);
2237
 
                            if(!ctx->engine->keeptmp) {
2238
 
                                if (cli_unlink(tmpname)) {
2239
 
                                    ret = nret = CL_EUNLINK;
2240
 
                                    break_loop = 1;
2241
 
                                }
2242
 
                            }
2243
 
                            free(tmpname);
2244
 
                        }
2245
 
                    }
2246
 
                    break;
2247
 
 
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);
2254
 
                    }
2255
 
                    break;
2256
 
 
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);
2263
 
                    }
2264
 
                    break;
2265
 
 
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);
2272
 
                    }
2273
 
                    break;
2274
 
 
2275
 
                case CL_TYPE_7ZSFX:
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);
2281
 
                    }
2282
 
                    break;
2283
 
 
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);
2290
 
                    }
2291
 
                    break;
2292
 
 
2293
 
                case CL_TYPE_NULSFT:
2294
 
                    if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_NSIS) &&
2295
 
                       fpt->offset > 4) {
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);
2300
 
                    }
2301
 
                    break;
2302
 
 
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);
2309
 
                    }
2310
 
                    break;
2311
 
 
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);
2318
 
                    }
2319
 
                    break;
2320
 
 
2321
 
                case CL_TYPE_DMG:
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);
2326
 
                    }
2327
 
                    break;
2328
 
 
2329
 
                case CL_TYPE_MBR:
2330
 
                    {
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);
2337
 
                        }
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);
2342
 
                        }
2343
 
                    }
2344
 
                    break;
2345
 
 
2346
 
                case CL_TYPE_PDF:
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);
2352
 
                    }
2353
 
                    break;
2354
 
 
2355
 
                case CL_TYPE_MSEXE:
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");
2362
 
                            break;
2363
 
                        }
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);
2371
 
                            if(peinfo.section)
2372
 
                                free(peinfo.section);
2373
 
                            cli_hashset_destroy(&peinfo.vinfo);
2374
 
 
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
2380
 
                                             */
2381
 
                        }
2382
 
                    }
2383
 
                    break;
2384
 
 
2385
 
                default:
2386
 
                    cli_warnmsg("cli_scanraw: Type %u not handled in fpt loop\n", fpt->type);
2387
 
                }
2388
 
 
2389
 
            if(nret == CL_VIRUS || break_loop)
2390
 
                break;
2391
 
 
2392
 
            fpt = fpt->next;
2393
 
        }
2394
 
        ctx->container_type = current_container_type;
2395
 
        ctx->container_size = current_container_size;
2396
 
        
2397
 
        if(nret != CL_VIRUS) switch(ret) {
2398
 
            case CL_TYPE_HTML:
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);
2403
 
                }
2404
 
                break;
2405
 
 
2406
 
            case CL_TYPE_MAIL:
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);
2412
 
                }
2413
 
                ctx->container_type = current_container_type;
2414
 
                ctx->container_size = current_container_size;
2415
 
                break;
2416
 
 
2417
 
            default:
2418
 
                break;
2419
 
        }
2420
 
        perf_nested_stop(ctx, PERFT_RAWTYPENO, PERFT_SCAN);
2421
 
        ctx->recursion--;
2422
 
        ret = nret;
2423
 
    }
2424
 
 
2425
 
    while(ftoffset) {
2426
 
        fpt = ftoffset;
2427
 
        ftoffset = ftoffset->next;
2428
 
        free(fpt);
2429
 
    }
2430
 
 
2431
 
    if(ret == CL_VIRUS)
2432
 
        cli_dbgmsg("%s found\n", cli_get_last_virus(ctx));
2433
 
 
2434
 
    return ret;
2435
 
}
2436
 
 
2437
 
 
2438
 
static void emax_reached(cli_ctx *ctx) {
2439
 
    fmap_t **ctx_fmap = ctx->fmap;
2440
 
    if (!ctx_fmap)
2441
 
        return;
2442
 
    while(*ctx_fmap) {
2443
 
        fmap_t *map = *ctx_fmap;
2444
 
        map->dont_cache_flag = 1;
2445
 
        ctx_fmap--;
2446
 
    }
2447
 
    cli_dbgmsg("emax_reached: marked parents as non cacheable\n");
2448
 
}
2449
 
 
2450
 
#define LINESTR(x) #x
2451
 
#define LINESTR2(x) LINESTR(x)
2452
 
#define __AT__  " at line "LINESTR2(__LINE__)
2453
 
 
2454
 
#define early_ret_from_magicscan(retcode)                               \
2455
 
    do {                                                                \
2456
 
        cli_dbgmsg("cli_magic_scandesc: returning %d %s (no post, no cache)\n", retcode, __AT__); \
2457
 
        return retcode;                                                 \
2458
 
    } while(0)
2459
 
 
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)
2461
 
{
2462
 
#if HAVE_JSON
2463
 
    ctx->wrkproperty = (struct json_object *)(parent_property);
2464
 
#else
2465
 
    UNUSEDPARAM(parent_property);
2466
 
#endif
2467
 
 
2468
 
    UNUSEDPARAM(type);
2469
 
 
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)) {
2474
 
        case CL_BREAK:
2475
 
            cli_dbgmsg("cli_magic_scandesc: file whitelisted by post_scan callback\n");
2476
 
            perf_stop(ctx, PERFT_POSTCB);
2477
 
            return CL_CLEAN;
2478
 
        case CL_VIRUS:
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);
2484
 
            return CL_VIRUS;
2485
 
        case CL_CLEAN:
2486
 
            break;
2487
 
        default:
2488
 
            cli_warnmsg("cli_magic_scandesc: ignoring bad return code from post_scan callback\n");
2489
 
        }
2490
 
        perf_stop(ctx, PERFT_POSTCB);
2491
 
    }
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);
2496
 
    }
2497
 
    return retcode;
2498
 
}
2499
 
 
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)
2501
 
{
2502
 
    int res=CL_CLEAN;
2503
 
 
2504
 
    UNUSEDPARAM(parent_property);
2505
 
    UNUSEDPARAM(hash);
2506
 
    UNUSEDPARAM(hashed_size);
2507
 
 
2508
 
    *run_cleanup = 0;
2509
 
 
2510
 
    if(cb) {
2511
 
        perf_start(ctx, PERFT_PRECB);
2512
 
        switch(cb(fmap_fd(*ctx->fmap), filetype, ctx->cb_ctx)) {
2513
 
        case CL_BREAK:
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;
2517
 
            *run_cleanup = 1;
2518
 
        case CL_VIRUS:
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;
2523
 
            *run_cleanup = 1;
2524
 
            res = CL_VIRUS;
2525
 
        case CL_CLEAN:
2526
 
            break;
2527
 
        default:
2528
 
            cli_warnmsg("cli_magic_scandesc: ignoring bad return code from callback\n");
2529
 
        }
2530
 
 
2531
 
        perf_stop(ctx, PERFT_PRECB);
2532
 
    }
2533
 
 
2534
 
    return res;
2535
 
}
2536
 
 
2537
 
static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2538
 
{
2539
 
        int ret = CL_CLEAN;
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;
2549
 
#if HAVE_JSON
2550
 
        struct json_object *parent_property = NULL;
2551
 
#else
2552
 
    void *parent_property = NULL;
2553
 
#endif
2554
 
 
2555
 
    if(!ctx->engine) {
2556
 
        cli_errmsg("CRITICAL: engine == NULL\n");
2557
 
        early_ret_from_magicscan(CL_ENULLARG);
2558
 
    }
2559
 
 
2560
 
    if(!(ctx->engine->dboptions & CL_DB_COMPILED)) {
2561
 
        cli_errmsg("CRITICAL: engine not compiled\n");
2562
 
        early_ret_from_magicscan(CL_EMALFDB);
2563
 
    }
2564
 
 
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);
2567
 
        emax_reached(ctx);
2568
 
        early_ret_from_magicscan(CL_CLEAN);
2569
 
    }
2570
 
 
2571
 
    if(cli_updatelimits(ctx, (*ctx->fmap)->len)!=CL_CLEAN) {
2572
 
        emax_reached(ctx);
2573
 
        early_ret_from_magicscan(CL_CLEAN);
2574
 
    }
2575
 
    old_hook_lsig_matches = ctx->hook_lsig_matches;
2576
 
    if(type == CL_TYPE_PART_ANY) {
2577
 
        typercg = 0;
2578
 
    }
2579
 
 
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);
2583
 
    }
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);
2588
 
    }
2589
 
    filetype = cli_ftname(type);
2590
 
 
2591
 
#if HAVE_JSON
2592
 
    if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
2593
 
        json_object *arrobj;
2594
 
 
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);       
2607
 
                }
2608
 
                ctx->wrkproperty = ctx->properties;
2609
 
                ret = cli_jsonstr(ctx->properties, "Magic", "CLAMJSONv0");
2610
 
                if (ret != CL_SUCCESS) {
2611
 
                    early_ret_from_magicscan(ret);
2612
 
                }
2613
 
                ret = cli_jsonstr(ctx->properties, "RootFileType", filetype);
2614
 
                if (ret != CL_SUCCESS) {
2615
 
                    early_ret_from_magicscan(ret);
2616
 
                }
2617
 
            } else { /* turn off property collection flag for file types we don't care about */
2618
 
                ctx->options &= ~CL_SCAN_FILE_PROPERTIES;       
2619
 
            }
2620
 
        }
2621
 
        else {
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);
2628
 
                }
2629
 
                json_object_object_add(parent_property, "ContainedObjects", arrobj);
2630
 
            }
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);
2635
 
            }
2636
 
            json_object_array_add(arrobj, ctx->wrkproperty);
2637
 
        }
2638
 
    }
2639
 
 
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);
2644
 
        }
2645
 
        ret = cli_jsonint(ctx->wrkproperty, "FileSize", (*ctx->fmap)->len);
2646
 
        if (ret != CL_SUCCESS) {
2647
 
            early_ret_from_magicscan(ret);
2648
 
        }
2649
 
    }
2650
 
#endif
2651
 
 
2652
 
    hashed_size = 0;
2653
 
    ret = dispatch_prescan(ctx->engine->cb_pre_cache, ctx, filetype, old_hook_lsig_matches, parent_property, hash, hashed_size, &run_cleanup);
2654
 
    if (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);
2657
 
        else
2658
 
            return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_CLEAN, parent_property);
2659
 
    }
2660
 
 
2661
 
    perf_start(ctx, PERFT_CACHE);
2662
 
    res = cache_check(hash, ctx);
2663
 
 
2664
 
#if HAVE_JSON
2665
 
    if (SCAN_PROPERTIES /* ctx.options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL */) {
2666
 
        char hashstr[33];
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]);
2668
 
 
2669
 
        ret = cli_jsonstr(ctx->wrkproperty, "FileMD5", hashstr);
2670
 
        if (ret != CL_SUCCESS) {
2671
 
            early_ret_from_magicscan(ret);
2672
 
        }
2673
 
    }
2674
 
#endif
2675
 
 
2676
 
    if(res != CL_VIRUS) {
2677
 
        perf_stop(ctx, PERFT_CACHE);
2678
 
#if HAVE_JSON
2679
 
        ctx->wrkproperty = parent_property;
2680
 
#endif
2681
 
        early_ret_from_magicscan(res);
2682
 
    }
2683
 
 
2684
 
    perf_stop(ctx, PERFT_CACHE);
2685
 
    hashed_size = (*ctx->fmap)->len;
2686
 
    ctx->hook_lsig_matches = NULL;
2687
 
 
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");
2691
 
        else
2692
 
            cli_dbgmsg("Raw mode: No support for special files\n");
2693
 
 
2694
 
    ret = dispatch_prescan(ctx->engine->cb_pre_scan, ctx, filetype, old_hook_lsig_matches, parent_property, hash, hashed_size, &run_cleanup);
2695
 
    if (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);
2698
 
        else
2699
 
            return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2700
 
    }
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 */
2707
 
            else
2708
 
                emax_reached(ctx);
2709
 
        }
2710
 
 
2711
 
        ctx->hook_lsig_matches = old_hook_lsig_matches;
2712
 
        return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2713
 
    }
2714
 
 
2715
 
    ret = dispatch_prescan(ctx->engine->cb_pre_scan, ctx, filetype, old_hook_lsig_matches, parent_property, hash, hashed_size, &run_cleanup);
2716
 
    if (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);
2719
 
        else
2720
 
            return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
2721
 
    }
2722
 
    /* ret_from_magicscan can be used below here*/
2723
 
 
2724
 
#ifdef HAVE__INTERNAL__SHA_COLLECT
2725
 
    if(!ctx->sha_collect && type==CL_TYPE_MSEXE) ctx->sha_collect = 1;
2726
 
#endif
2727
 
 
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);
2732
 
    }
2733
 
 
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);
2740
 
        }
2741
 
    }
2742
 
 
2743
 
    ctx->recursion++;
2744
 
    perf_nested_start(ctx, PERFT_CONTAINER, PERFT_SCAN);
2745
 
    ctx->container_size = (*ctx->fmap)->len;
2746
 
    switch(type) {
2747
 
        case CL_TYPE_IGNORED:
2748
 
            break;
2749
 
 
2750
 
    case CL_TYPE_XDP:
2751
 
        ret = cli_scanxdp(ctx);
2752
 
        break;
2753
 
 
2754
 
        case CL_TYPE_RAR:
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);
2759
 
                if (desc == -1) {
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");
2764
 
                        break;
2765
 
                    }
2766
 
                }
2767
 
                ret = cli_scanrar(desc, ctx, 0, NULL);
2768
 
                if (tmpname) {
2769
 
                    close(desc);
2770
 
                    unlink(tmpname);
2771
 
                    free(tmpname);
2772
 
                }
2773
 
            }
2774
 
            break;
2775
 
 
2776
 
        case CL_TYPE_OOXML_WORD:
2777
 
        case CL_TYPE_OOXML_PPT:
2778
 
        case CL_TYPE_OOXML_XL:
2779
 
#if HAVE_JSON
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);
2784
 
                }
2785
 
                else if (ret != CL_SUCCESS) {
2786
 
                    /* JSONOOXML - what to do if something else fails? placeholder */
2787
 
                    ret = CL_SUCCESS;
2788
 
                }
2789
 
            }
2790
 
#endif
2791
 
        case CL_TYPE_ZIP:
2792
 
            ctx->container_type = CL_TYPE_ZIP;
2793
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
2794
 
                ret = cli_unzip(ctx);
2795
 
            break;
2796
 
 
2797
 
        case CL_TYPE_GZ:
2798
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_GZ))
2799
 
                ret = cli_scangzip(ctx);
2800
 
            break;
2801
 
 
2802
 
        case CL_TYPE_BZ:
2803
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BZ))
2804
 
                ret = cli_scanbzip(ctx);
2805
 
            break;
2806
 
 
2807
 
        case CL_TYPE_XZ:
2808
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_XZ))
2809
 
                ret = cli_scanxz(ctx);
2810
 
            break;
2811
 
 
2812
 
        case CL_TYPE_GPT:
2813
 
            ret = cli_scangpt(ctx, 0);
2814
 
            break;
2815
 
 
2816
 
        case CL_TYPE_APM:
2817
 
            ret = cli_scanapm(ctx);
2818
 
            break;
2819
 
 
2820
 
        case CL_TYPE_ARJ:
2821
 
            ctx->container_type = CL_TYPE_ARJ;
2822
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ))
2823
 
                ret = cli_scanarj(ctx, 0, NULL);
2824
 
            break;
2825
 
 
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);
2830
 
            break;
2831
 
 
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);
2836
 
            break;
2837
 
 
2838
 
        case CL_TYPE_MSSZDD:
2839
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SZDD))
2840
 
                ret = cli_scanszdd(ctx);
2841
 
            break;
2842
 
 
2843
 
        case CL_TYPE_MSCAB:
2844
 
            ctx->container_type = CL_TYPE_MSCAB;
2845
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB))
2846
 
                ret = cli_scanmscab(ctx, 0);
2847
 
            break;
2848
 
 
2849
 
        case CL_TYPE_HTML:
2850
 
            if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
2851
 
                ret = cli_scanhtml(ctx);
2852
 
            break;
2853
 
 
2854
 
        case CL_TYPE_HTML_UTF16:
2855
 
            if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
2856
 
                ret = cli_scanhtml_utf16(ctx);
2857
 
            break;
2858
 
 
2859
 
        case CL_TYPE_SCRIPT:
2860
 
            if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML)
2861
 
                ret = cli_scanscript(ctx);
2862
 
            break;
2863
 
 
2864
 
        case CL_TYPE_SWF:
2865
 
            if(SCAN_SWF && (DCONF_DOC & DOC_CONF_SWF))
2866
 
                ret = cli_scanswf(ctx);
2867
 
            break;
2868
 
 
2869
 
        case CL_TYPE_RTF:
2870
 
            ctx->container_type = CL_TYPE_RTF;
2871
 
            if(SCAN_ARCHIVE && (DCONF_DOC & DOC_CONF_RTF))
2872
 
                ret = cli_scanrtf(ctx);
2873
 
            break;
2874
 
 
2875
 
        case CL_TYPE_MAIL:
2876
 
            ctx->container_type = CL_TYPE_MAIL;
2877
 
            if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
2878
 
                ret = cli_scanmail(ctx);
2879
 
            break;
2880
 
 
2881
 
        case CL_TYPE_TNEF:
2882
 
            if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_TNEF))
2883
 
                ret = cli_scantnef(ctx);
2884
 
            break;
2885
 
 
2886
 
        case CL_TYPE_UUENCODED:
2887
 
            if(DCONF_OTHER & OTHER_CONF_UUENC)
2888
 
                ret = cli_scanuuencoded(ctx);
2889
 
            break;
2890
 
 
2891
 
        case CL_TYPE_MSCHM:
2892
 
            ctx->container_type = CL_TYPE_MSCHM;
2893
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CHM))
2894
 
                ret = cli_scanmschm(ctx);
2895
 
            break;
2896
 
 
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);
2901
 
            break;
2902
 
 
2903
 
        case CL_TYPE_7Z:
2904
 
            ctx->container_type = CL_TYPE_7Z;
2905
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z))
2906
 
                ret = cli_7unz(ctx, 0);
2907
 
            break;
2908
 
 
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);
2913
 
            break;
2914
 
 
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);
2919
 
            break;
2920
 
 
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);
2925
 
            break;
2926
 
 
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);
2931
 
            break;
2932
 
 
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);
2937
 
            break;
2938
 
 
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);
2943
 
            break;
2944
 
 
2945
 
        case CL_TYPE_BINHEX:
2946
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BINHEX))
2947
 
                ret = cli_binhex(ctx);
2948
 
            break;
2949
 
 
2950
 
        case CL_TYPE_SCRENC:
2951
 
            if(DCONF_OTHER & OTHER_CONF_SCRENC)
2952
 
                ret = cli_scanscrenc(ctx);
2953
 
            break;
2954
 
 
2955
 
        case CL_TYPE_RIFF:
2956
 
            if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_RIFF))
2957
 
                ret = cli_scanriff(ctx);
2958
 
            break;
2959
 
 
2960
 
        case CL_TYPE_GRAPHICS:
2961
 
            if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_JPEG))
2962
 
                ret = cli_scanjpeg(ctx);
2963
 
 
2964
 
            if(ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS)
2965
 
                ret = cli_parsejpeg(ctx);
2966
 
 
2967
 
            if(ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS && ret != CL_EPARSE)
2968
 
                ret = cli_parsepng(ctx);
2969
 
 
2970
 
            if(ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS && ret != CL_EPARSE)
2971
 
                ret = cli_parsegif(ctx);
2972
 
            break;
2973
 
 
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);
2978
 
            break;
2979
 
 
2980
 
        case CL_TYPE_CRYPTFF:
2981
 
            if(DCONF_OTHER & OTHER_CONF_CRYPTFF)
2982
 
                ret = cli_scancryptff(ctx);
2983
 
            break;
2984
 
 
2985
 
        case CL_TYPE_ELF:
2986
 
            if(SCAN_ELF && ctx->dconf->elf)
2987
 
                ret = cli_scanelf(ctx);
2988
 
            break;
2989
 
 
2990
 
        case CL_TYPE_MACHO:
2991
 
            if(ctx->dconf->macho)
2992
 
                ret = cli_scanmacho(ctx, NULL);
2993
 
            break;
2994
 
 
2995
 
        case CL_TYPE_MACHO_UNIBIN:
2996
 
            if(ctx->dconf->macho)
2997
 
                ret = cli_scanmacho_unibin(ctx);
2998
 
            break;
2999
 
 
3000
 
        case CL_TYPE_SIS:
3001
 
            ctx->container_type = CL_TYPE_SIS;
3002
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SIS))
3003
 
                ret = cli_scansis(ctx);
3004
 
            break;
3005
 
 
3006
 
        case CL_TYPE_XAR:
3007
 
            ctx->container_type = CL_TYPE_XAR;
3008
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_XAR))
3009
 
                ret = cli_scanxar(ctx);
3010
 
            break;
3011
 
 
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);
3016
 
            break;
3017
 
 
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);
3022
 
            break;
3023
 
 
3024
 
        case CL_TYPE_TEXT_ASCII:
3025
 
            if(SCAN_STRUCTURED && (DCONF_OTHER & OTHER_CONF_DLP))
3026
 
                /* TODO: consider calling this from cli_scanscript() for
3027
 
                 * a normalised text
3028
 
                 */
3029
 
                ret = cli_scan_structured(ctx);
3030
 
            break;
3031
 
 
3032
 
        default:
3033
 
            break;
3034
 
    }
3035
 
    perf_nested_stop(ctx, PERFT_CONTAINER, PERFT_SCAN);
3036
 
    ctx->recursion--;
3037
 
    ctx->container_type = current_container_type;
3038
 
    ctx->container_size = current_container_size;
3039
 
 
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);
3045
 
    }
3046
 
 
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");
3052
 
            typercg = 0;
3053
 
        }
3054
 
    }
3055
 
 
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) {
3060
 
            switch(res) {
3061
 
                /* List of scan halts, runtime errors only! */
3062
 
                case CL_EUNLINK:
3063
 
                case CL_ESTAT:
3064
 
                case CL_ESEEK:
3065
 
                case CL_EWRITE:
3066
 
                case CL_EDUP:
3067
 
                case CL_ETMPFILE:
3068
 
                case CL_ETMPDIR:
3069
 
                case CL_EMEM:
3070
 
                case CL_ETIMEOUT:
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 */
3076
 
                case CL_VIRUS:
3077
 
                    ret = cli_checkfp(hash, hashed_size, ctx);
3078
 
                    if (SCAN_ALL)
3079
 
                        break;
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 */
3084
 
                case CL_EMAXREC:
3085
 
                case CL_EMAXSIZE:
3086
 
                case CL_EMAXFILES:
3087
 
                    ret = res;
3088
 
                    cli_dbgmsg("Descriptor[%d]: Continuing after cli_scanraw reached %s\n",
3089
 
                        fmap_fd(*ctx->fmap), cl_strerror(res));
3090
 
                    break;
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.
3094
 
                 */
3095
 
                default:
3096
 
                    ret = res;
3097
 
                    cli_dbgmsg("Descriptor[%d]: Continuing after cli_scanraw error %s\n",
3098
 
                        fmap_fd(*ctx->fmap), cl_strerror(res));
3099
 
            }
3100
 
        }
3101
 
    }
3102
 
 
3103
 
    ctx->recursion++;
3104
 
    switch(type) {
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);
3116
 
            }
3117
 
            perf_nested_stop(ctx, PERFT_SCRIPT, PERFT_SCAN);
3118
 
            break;
3119
 
        /* Due to performance reasons all executables were first scanned
3120
 
         * in raw mode. Now we will try to unpack them
3121
 
         */
3122
 
        case CL_TYPE_MSEXE:
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;
3128
 
            }
3129
 
            perf_nested_stop(ctx, PERFT_PE, PERFT_SCAN);
3130
 
            break;
3131
 
        default:
3132
 
            break;
3133
 
    }
3134
 
 
3135
 
    if(ret == CL_VIRUS)
3136
 
        ret = cli_checkfp(hash, hashed_size, ctx);
3137
 
    ctx->recursion--;
3138
 
    cli_bitset_free(ctx->hook_lsig_matches);
3139
 
    ctx->hook_lsig_matches = old_hook_lsig_matches;
3140
 
 
3141
 
    switch(ret) {
3142
 
        /* Malformed file cases */
3143
 
        case CL_EFORMAT:
3144
 
        case CL_EREAD:
3145
 
        case CL_EUNPACK:
3146
 
        /* Limits exceeded */
3147
 
        case CL_EMAXREC:
3148
 
        case CL_EMAXSIZE:
3149
 
        case CL_EMAXFILES:
3150
 
            cli_dbgmsg("Descriptor[%d]: %s\n", fmap_fd(*ctx->fmap), cl_strerror(ret));
3151
 
#if HAVE_JSON
3152
 
        ctx->wrkproperty = parent_property;
3153
 
#endif
3154
 
        return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_CLEAN, parent_property);
3155
 
        case CL_CLEAN:
3156
 
            cache_clean = 1;
3157
 
#if HAVE_JSON
3158
 
        ctx->wrkproperty = parent_property;
3159
 
#endif
3160
 
        return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_CLEAN, parent_property);
3161
 
        default:
3162
 
        return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
3163
 
    }
3164
 
}
3165
 
 
3166
 
static int cli_base_scandesc(int desc, cli_ctx *ctx, cli_file_t type)
3167
 
{
3168
 
    STATBUF sb;
3169
 
    int ret;
3170
 
 
3171
 
#ifdef HAVE__INTERNAL__SHA_COLLECT
3172
 
    if(ctx->sha_collect>0) ctx->sha_collect = 0;
3173
 
#endif
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);
3178
 
    }
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);
3182
 
    }
3183
 
 
3184
 
    ctx->fmap++;
3185
 
    perf_start(ctx, PERFT_MAP);
3186
 
    if(!(*ctx->fmap = fmap(desc, 0, sb.st_size))) {
3187
 
        cli_errmsg("CRITICAL: fmap() failed\n");
3188
 
        ctx->fmap--;
3189
 
        perf_stop(ctx, PERFT_MAP);
3190
 
        early_ret_from_magicscan(CL_EMEM);
3191
 
    }
3192
 
    perf_stop(ctx, PERFT_MAP);
3193
 
 
3194
 
    ret = magic_scandesc(ctx, type);
3195
 
 
3196
 
    funmap(*ctx->fmap);
3197
 
    ctx->fmap--;
3198
 
    return ret;
3199
 
}
3200
 
 
3201
 
int cli_magic_scandesc(int desc, cli_ctx *ctx)
3202
 
{
3203
 
    return cli_base_scandesc(desc, ctx, CL_TYPE_ANY);
3204
 
}
3205
 
 
3206
 
/* Have to keep partition typing separate */
3207
 
int cli_partition_scandesc(int desc, cli_ctx *ctx)
3208
 
{
3209
 
    return cli_base_scandesc(desc, ctx, CL_TYPE_PART_ANY);
3210
 
}
3211
 
 
3212
 
int cli_magic_scandesc_type(cli_ctx *ctx, cli_file_t type)
3213
 
{
3214
 
    return magic_scandesc(ctx, type);
3215
 
}
3216
 
 
3217
 
int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
3218
 
{
3219
 
    return cl_scandesc_callback(desc, virname, scanned, engine, scanoptions, NULL);
3220
 
}
3221
 
 
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)
3224
 
{
3225
 
    off_t old_off = map->nested_offset;
3226
 
    size_t old_len = map->len;
3227
 
    int ret = CL_CLEAN;
3228
 
 
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);
3233
 
        return CL_CLEAN;
3234
 
    }
3235
 
 
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;
3240
 
        int fd = -1;
3241
 
        size_t nread = 0;
3242
 
 
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;
3249
 
        }
3250
 
        if (length <= 5) {
3251
 
            cli_dbgmsg("cli_map_scan: Small data (%u bytes)\n", (unsigned int) length);
3252
 
            return CL_CLEAN;
3253
 
        }
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);
3257
 
            return CL_CLEAN;
3258
 
        }
3259
 
 
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");
3264
 
            return CL_EMAP;
3265
 
        }
3266
 
 
3267
 
        ret = cli_gentempfd(ctx->engine->tmpdir, &tempfile, &fd);
3268
 
        if (ret != CL_SUCCESS) {
3269
 
            return ret;
3270
 
        }
3271
 
 
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");
3275
 
            ret = CL_EWRITE;
3276
 
        }
3277
 
 
3278
 
        /* scan the temp file */
3279
 
        ret = cli_base_scandesc(fd, ctx, type);
3280
 
 
3281
 
        /* remove the temp file, if needed */
3282
 
        if (fd >= 0) {
3283
 
            close(fd);
3284
 
        }
3285
 
        if(!ctx->engine->keeptmp) {
3286
 
            if (cli_unlink(tempfile)) {
3287
 
                cli_errmsg("cli_map_scan: error unlinking tempfile %s\n", tempfile);
3288
 
                ret = CL_EUNLINK;
3289
 
            }
3290
 
        }
3291
 
        free(tempfile);
3292
 
    }
3293
 
    else {
3294
 
        /* Not forced to disk, use nested map */
3295
 
        ret = cli_map_scandesc(map, offset, length, ctx, type);
3296
 
    }
3297
 
    return ret;
3298
 
}
3299
 
 
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)
3302
 
{
3303
 
    off_t old_off = map->nested_offset;
3304
 
    size_t old_len = map->len;
3305
 
    size_t old_real_len = map->real_len;
3306
 
    int ret = CL_CLEAN;
3307
 
 
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);
3313
 
        return CL_CLEAN;
3314
 
    }
3315
 
 
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;
3321
 
    }
3322
 
 
3323
 
    if (length <= 5) {
3324
 
        cli_dbgmsg("Small data (%u bytes)\n", (unsigned int) length);
3325
 
        return CL_CLEAN;
3326
 
    }
3327
 
    ctx->fmap++;
3328
 
    *ctx->fmap = map;
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;
3332
 
    map->len = length;
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);
3336
 
    } else {
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);
3342
 
    }
3343
 
 
3344
 
    ctx->fmap--;
3345
 
    map->nested_offset = old_off;
3346
 
    map->len = old_len;
3347
 
    map->real_len = old_real_len;
3348
 
    return ret;
3349
 
}
3350
 
 
3351
 
int cli_mem_scandesc(const void *buffer, size_t length, cli_ctx *ctx)
3352
 
{
3353
 
    int ret;
3354
 
    fmap_t *map = cl_fmap_open_memory(buffer, length);
3355
 
    if (!map) {
3356
 
        return CL_EMAP;
3357
 
    }
3358
 
    ret = cli_map_scan(map, 0, length, ctx, CL_TYPE_ANY);
3359
 
    cl_fmap_close(map);
3360
 
    return ret;
3361
 
}
3362
 
 
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)
3364
 
{
3365
 
    cli_ctx ctx;
3366
 
    int rc;
3367
 
    STATBUF sb;
3368
 
 
3369
 
    /* We have a limit of around 2.17GB (INT_MAX - 2). Enforce it here. */
3370
 
    if (map != NULL) {
3371
 
        if ((size_t)(map->real_len) > (size_t)(INT_MAX - 2))
3372
 
            return CL_CLEAN;
3373
 
    } else {
3374
 
        if (FSTAT(desc, &sb))
3375
 
            return CL_ESTAT;
3376
 
 
3377
 
        if ((size_t)(sb.st_size) > (size_t)(INT_MAX - 2))
3378
 
            return CL_CLEAN;
3379
 
    }
3380
 
 
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;
3388
 
#endif
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);
3395
 
    if(!ctx.fmap)
3396
 
        return CL_EMEM;
3397
 
    if (!(ctx.hook_lsig_matches = cli_bitset_init())) {
3398
 
        free(ctx.fmap);
3399
 
        return CL_EMEM;
3400
 
    }
3401
 
    perf_init(&ctx);
3402
 
 
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++;
3412
 
            }
3413
 
        } else {
3414
 
            char buf[64];
3415
 
            cli_dbgmsg("scan_common; gettimeofday error: %s\n", cli_strerror(errno, buf, 64));
3416
 
        }
3417
 
    }
3418
 
 
3419
 
#ifdef HAVE__INTERNAL__SHA_COLLECT
3420
 
    if(scanoptions & CL_SCAN_INTERNAL_COLLECT_SHA) {
3421
 
        char link[32];
3422
 
        ssize_t linksz;
3423
 
 
3424
 
 
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");
3430
 
        } else
3431
 
            ctx.entry_filename[linksz]='\0';
3432
 
    } while(0);
3433
 
#endif
3434
 
 
3435
 
    cli_logg_setup(&ctx);
3436
 
    rc = map ? cli_map_scandesc(map, 0, map->len, &ctx, CL_TYPE_ANY) : cli_magic_scandesc(desc, &ctx);
3437
 
 
3438
 
#if HAVE_JSON
3439
 
    if (ctx.options & CL_SCAN_FILE_PROPERTIES && ctx.properties!=NULL) {
3440
 
        json_object *jobj;
3441
 
        const char *jstring;
3442
 
 
3443
 
        /* set value of unique root object tag */
3444
 
        if (json_object_object_get_ex(ctx.properties, "FileType", &jobj)) {
3445
 
            enum json_type type;
3446
 
            const char *jstr;
3447
 
 
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);
3452
 
            }
3453
 
        }
3454
 
 
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");
3459
 
            rc = CL_EMEM;
3460
 
        }
3461
 
        else {
3462
 
            int ret = CL_SUCCESS;
3463
 
            cli_dbgmsg("%s\n", jstring);
3464
 
 
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);
3469
 
            }
3470
 
 
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)
3475
 
                    rc = ret;
3476
 
            }
3477
 
 
3478
 
            /* keeptmp file processing for file properties json string */
3479
 
            if (ctx.engine->keeptmp) {
3480
 
                int fd = -1;
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);
3484
 
                } else {
3485
 
                    if (cli_writen(fd, jstring, strlen(jstring)) < 0)
3486
 
                        cli_dbgmsg("scan_common: cli_writen error writing json properties file.\n");
3487
 
                    else
3488
 
                        cli_dbgmsg("json written to: %s\n", tmpname);
3489
 
                }
3490
 
                if (fd != -1)
3491
 
                    close(fd);
3492
 
                if (NULL != tmpname)
3493
 
                    free(tmpname);
3494
 
            }
3495
 
        }
3496
 
        json_object_put(ctx.properties); /* frees all json memory */
3497
 
#if 0
3498
 
        // test code  - to be deleted
3499
 
        if (cli_checktimelimit(&ctx) != CL_SUCCESS) {
3500
 
            cli_errmsg("scan_common: timeout!\n");
3501
 
            rc = CL_ETIMEOUT;
3502
 
        }
3503
 
#endif
3504
 
    }
3505
 
#endif
3506
 
 
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)
3510
 
            rc = CL_VIRUS;
3511
 
    }
3512
 
 
3513
 
    cli_bitset_free(ctx.hook_lsig_matches);
3514
 
    free(ctx.fmap);
3515
 
    if(rc == CL_CLEAN && ctx.found_possibly_unwanted)
3516
 
        rc = CL_VIRUS;
3517
 
    cli_logg_unsetup();
3518
 
    perf_done(&ctx);
3519
 
    return rc;
3520
 
}
3521
 
 
3522
 
int cl_scandesc_callback(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
3523
 
{
3524
 
    return scan_common(desc, NULL, virname, scanned, engine, scanoptions, context);
3525
 
}
3526
 
 
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)
3528
 
{
3529
 
    return scan_common(-1, map, virname, scanned, engine, scanoptions, context);
3530
 
}
3531
 
 
3532
 
int cli_found_possibly_unwanted(cli_ctx* ctx)
3533
 
{
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");
3540
 
            return CL_VIRUS;
3541
 
        }
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;
3547
 
    } else {
3548
 
        cli_warnmsg("cli_found_possibly_unwanted called, but virname is not set\n");
3549
 
    }
3550
 
    emax_reached(ctx);
3551
 
    return CL_CLEAN;
3552
 
}
3553
 
 
3554
 
static int cli_scanfile(const char *filename, cli_ctx *ctx)
3555
 
{
3556
 
        int fd, ret;
3557
 
 
3558
 
    /* internal version of cl_scanfile with arec/mrec preserved */
3559
 
    if((fd = safe_open(filename, O_RDONLY|O_BINARY)) == -1)
3560
 
        return CL_EOPEN;
3561
 
 
3562
 
    ret = cli_magic_scandesc(fd, ctx);
3563
 
 
3564
 
    close(fd);
3565
 
    return ret;
3566
 
}
3567
 
 
3568
 
int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
3569
 
{
3570
 
    return cl_scanfile_callback(filename, virname, scanned, engine, scanoptions, NULL);
3571
 
}
3572
 
 
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)
3574
 
{
3575
 
        int fd, ret;
3576
 
        const char *fname = cli_to_utf8_maybe_alloc(filename);
3577
 
 
3578
 
    if(!fname)
3579
 
            return CL_EARG;
3580
 
 
3581
 
    if((fd = safe_open(fname, O_RDONLY|O_BINARY)) == -1)
3582
 
        return CL_EOPEN;
3583
 
 
3584
 
    if(fname != filename)
3585
 
        free((void*)fname);
3586
 
 
3587
 
    ret = cl_scandesc_callback(fd, virname, scanned, engine, scanoptions, context);
3588
 
    close(fd);
3589
 
 
3590
 
    return ret;
3591
 
}
3592
 
 
3593
 
/*
3594
 
Local Variables:
3595
 
   c-basic-offset: 4
3596
 
End:
3597
 
*/