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

« back to all changes in this revision

Viewing changes to .pc/0007-fix-ssize_t-size_t-off_t-printf-modifier.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 "libmspack.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 "rtf.h"
 
77
#include "unarj.h"
 
78
#include "nsis/nulsft.h"
 
79
#include "autoit.h"
 
80
#include "textnorm.h"
 
81
#include <zlib.h>
 
82
#include "unzip.h"
 
83
#include "dlp.h"
 
84
#include "default.h"
 
85
#include "cpio.h"
 
86
#include "macho.h"
 
87
#include "ishield.h"
 
88
#include "7z_iface.h"
 
89
#include "fmap.h"
 
90
#include "cache.h"
 
91
#include "events.h"
 
92
#include "swf.h"
 
93
#include "jpeg.h"
 
94
#include "png.h"
 
95
#include "iso9660.h"
 
96
#include "dmg.h"
 
97
#include "xar.h"
 
98
#include "hfsplus.h"
 
99
#include "xz_iface.h"
 
100
#include "mbr.h"
 
101
#include "gpt.h"
 
102
#include "apm.h"
 
103
#include "ooxml.h"
 
104
#include "xdp.h"
 
105
#include "json_api.h"
 
106
 
 
107
#ifdef HAVE_BZLIB_H
 
108
#include <bzlib.h>
 
109
#endif
 
110
 
 
111
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
 
112
#include <limits.h>
 
113
#include <stddef.h>
 
114
#endif
 
115
 
 
116
#include <string.h>
 
117
 
 
118
static int cli_scanfile(const char *filename, cli_ctx *ctx);
 
119
 
 
120
static int cli_scandir(const char *dirname, cli_ctx *ctx)
 
121
{
 
122
        DIR *dd;
 
123
        struct dirent *dent;
 
124
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
 
125
        union {
 
126
            struct dirent d;
 
127
            char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
 
128
        } result;
 
129
#endif
 
130
        STATBUF statbuf;
 
131
        char *fname;
 
132
        unsigned int viruses_found = 0;
 
133
 
 
134
    if((dd = opendir(dirname)) != NULL) {
 
135
#ifdef HAVE_READDIR_R_3
 
136
        while(!readdir_r(dd, &result.d, &dent) && dent) {
 
137
#elif defined(HAVE_READDIR_R_2)
 
138
        while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
 
139
#else
 
140
        while((dent = readdir(dd))) {
 
141
#endif
 
142
            if(dent->d_ino)
 
143
            {
 
144
                if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
 
145
                    /* build the full name */
 
146
                    fname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
 
147
                    if(!fname) {
 
148
                        closedir(dd);
 
149
            cli_dbgmsg("cli_scandir: Unable to allocate memory for filename\n");
 
150
                        return CL_EMEM;
 
151
                    }
 
152
 
 
153
                    sprintf(fname, "%s"PATHSEP"%s", dirname, dent->d_name);
 
154
 
 
155
                    /* stat the file */
 
156
                    if(LSTAT(fname, &statbuf) != -1) {
 
157
                        if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {
 
158
                            if(cli_scandir(fname, ctx) == CL_VIRUS) {
 
159
                                free(fname);
 
160
 
 
161
                                if (SCAN_ALL) {
 
162
                                    viruses_found++;
 
163
                                    continue;
 
164
                                }
 
165
 
 
166
                                closedir(dd);
 
167
                                return CL_VIRUS;
 
168
                            }
 
169
                        } else {
 
170
                            if(S_ISREG(statbuf.st_mode)) {
 
171
                                if(cli_scanfile(fname, ctx) == CL_VIRUS) {
 
172
                                    free(fname);
 
173
 
 
174
                                    if (SCAN_ALL) {
 
175
                                        viruses_found++;
 
176
                                        continue;
 
177
                                    }
 
178
 
 
179
                                    closedir(dd);
 
180
                                    return CL_VIRUS;
 
181
                                }
 
182
                            }
 
183
                        }
 
184
                    }
 
185
                    free(fname);
 
186
                }
 
187
            }
 
188
        } 
 
189
    } else {
 
190
        cli_dbgmsg("cli_scandir: Can't open directory %s.\n", dirname);
 
191
        return CL_EOPEN;
 
192
    }
 
193
 
 
194
    closedir(dd);
 
195
    if (SCAN_ALL && viruses_found)
 
196
        return CL_VIRUS;
 
197
    return CL_CLEAN;
 
198
}
 
199
 
 
200
static int cli_unrar_scanmetadata(int desc, unrar_metadata_t *metadata, cli_ctx *ctx, unsigned int files, uint32_t* sfx_check)
 
201
{
 
202
        int ret = CL_SUCCESS;
 
203
 
 
204
    if(files == 1 && sfx_check) {
 
205
        if(*sfx_check == metadata->crc)
 
206
            return CL_BREAK;/* break extract loop */
 
207
        else
 
208
            *sfx_check = metadata->crc;
 
209
    }
 
210
 
 
211
    cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %u, compressed: %u, normal: %u, method: %u, ratio: %u\n",
 
212
        metadata->filename, metadata->crc, metadata->encrypted, (unsigned int) metadata->pack_size,
 
213
        (unsigned int) metadata->unpack_size, metadata->method,
 
214
        metadata->pack_size ? (unsigned int) (metadata->unpack_size / metadata->pack_size) : 0);
 
215
 
 
216
    if(cli_matchmeta(ctx, metadata->filename, metadata->pack_size, metadata->unpack_size, metadata->encrypted, files, metadata->crc, NULL) == CL_VIRUS)
 
217
        return CL_VIRUS;
 
218
 
 
219
    if(DETECT_ENCRYPTED && metadata->encrypted) {
 
220
        cli_dbgmsg("RAR: Encrypted files found in archive.\n");
 
221
        ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
 
222
        if(ret != CL_VIRUS) {
 
223
            cli_append_virus(ctx, "Heuristics.Encrypted.RAR");
 
224
            return CL_VIRUS;
 
225
        }
 
226
    }
 
227
 
 
228
    return ret;
 
229
}
 
230
 
 
231
static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
 
232
{
 
233
        int ret = CL_CLEAN;
 
234
        unrar_metadata_t *metadata, *metadata_tmp;
 
235
        char *dir;
 
236
        unrar_state_t rar_state;
 
237
        unsigned int viruses_found = 0;
 
238
 
 
239
    cli_dbgmsg("in scanrar()\n");
 
240
 
 
241
    if(sfx_offset)
 
242
        if(lseek(desc, sfx_offset, SEEK_SET) == -1)
 
243
            return CL_ESEEK;
 
244
 
 
245
    /* generate the temporary directory */
 
246
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
 
247
        return CL_EMEM;
 
248
 
 
249
    if(mkdir(dir, 0700)) {
 
250
        cli_dbgmsg("RAR: Can't create temporary directory %s\n", dir);
 
251
        free(dir);
 
252
        return CL_ETMPDIR;
 
253
    }
 
254
 
 
255
    if((ret = cli_unrar_open(desc, dir, &rar_state)) != UNRAR_OK) {
 
256
        if(!ctx->engine->keeptmp)
 
257
            cli_rmdirs(dir);
 
258
        free(dir);
 
259
        if(ret == UNRAR_PASSWD) {
 
260
            cli_dbgmsg("RAR: Encrypted main header\n");
 
261
            if(DETECT_ENCRYPTED) {
 
262
                if (lseek(desc, 0, SEEK_SET) == -1) {
 
263
            cli_dbgmsg("RAR: call to lseek() failed\n");
 
264
            return CL_ESEEK;
 
265
        }
 
266
                ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
 
267
                if(ret != CL_VIRUS)
 
268
                    cli_append_virus(ctx, "Heuristics.Encrypted.RAR");
 
269
                return CL_VIRUS;
 
270
            }
 
271
            return CL_CLEAN;
 
272
        } if(ret == UNRAR_EMEM) {
 
273
            return CL_EMEM;
 
274
        } else {
 
275
            return CL_EUNPACK;
 
276
        }
 
277
    }
 
278
 
 
279
    do {
 
280
        int rc;
 
281
        rar_state.ofd = -1;
 
282
        ret = cli_unrar_extract_next_prepare(&rar_state,dir);
 
283
        if(ret != UNRAR_OK) {
 
284
            if(ret == UNRAR_BREAK)
 
285
                ret = CL_BREAK;
 
286
            else if(ret == UNRAR_EMEM)
 
287
                ret = CL_EMEM;
 
288
            else
 
289
                ret = CL_EUNPACK;
 
290
            break;
 
291
        }
 
292
        if(ctx->engine->maxscansize && ctx->scansize >= ctx->engine->maxscansize) {
 
293
            free(rar_state.file_header->filename);
 
294
            free(rar_state.file_header);
 
295
            ret = CL_CLEAN;
 
296
            break;
 
297
        }
 
298
        if(ctx->engine->maxscansize && ctx->scansize + ctx->engine->maxfilesize >= ctx->engine->maxscansize)
 
299
            rar_state.maxfilesize = ctx->engine->maxscansize - ctx->scansize;
 
300
        else
 
301
            rar_state.maxfilesize = ctx->engine->maxfilesize;
 
302
 
 
303
        ret = cli_unrar_extract_next(&rar_state,dir);
 
304
        if(ret == UNRAR_OK)
 
305
            ret = CL_SUCCESS;
 
306
        else if(ret == UNRAR_EMEM)
 
307
            ret = CL_EMEM;
 
308
        else
 
309
            ret = CL_EFORMAT;
 
310
 
 
311
        if(rar_state.ofd > 0) {
 
312
            if (lseek(rar_state.ofd,0,SEEK_SET) == -1) {
 
313
            cli_dbgmsg("RAR: Call to lseek() failed\n");
 
314
            ret = CL_ESEEK;
 
315
        }
 
316
            rc = cli_magic_scandesc(rar_state.ofd,ctx);
 
317
            close(rar_state.ofd);
 
318
            if(!ctx->engine->keeptmp) 
 
319
                if (cli_unlink(rar_state.filename)) ret = CL_EUNLINK;
 
320
            if(rc == CL_VIRUS ) {
 
321
                cli_dbgmsg("RAR: infected with %s\n", cli_get_last_virus(ctx));
 
322
                ret = CL_VIRUS;
 
323
                viruses_found++;
 
324
            }
 
325
        }
 
326
 
 
327
        if(ret == CL_VIRUS) {
 
328
            if(SCAN_ALL)
 
329
                ret = CL_SUCCESS;
 
330
            else
 
331
                break;
 
332
        }
 
333
 
 
334
        if(ret == CL_SUCCESS)
 
335
            ret = cli_unrar_scanmetadata(desc,rar_state.metadata_tail, ctx, rar_state.file_count, sfx_check);
 
336
 
 
337
    } while(ret == CL_SUCCESS);
 
338
 
 
339
    if(ret == CL_BREAK)
 
340
        ret = CL_CLEAN;
 
341
 
 
342
    metadata = metadata_tmp = rar_state.metadata; 
 
343
 
 
344
    if(cli_scandir(rar_state.comment_dir, ctx) == CL_VIRUS)
 
345
        ret = CL_VIRUS;
 
346
 
 
347
    cli_unrar_close(&rar_state);
 
348
 
 
349
    if(!ctx->engine->keeptmp)
 
350
        cli_rmdirs(dir);
 
351
 
 
352
    free(dir);
 
353
 
 
354
    metadata = metadata_tmp;
 
355
    while (metadata) {
 
356
        metadata_tmp = metadata->next;
 
357
        free(metadata->filename);
 
358
        free(metadata);
 
359
        metadata = metadata_tmp;
 
360
    }
 
361
    cli_dbgmsg("RAR: Exit code: %d\n", ret);
 
362
 
 
363
    if (SCAN_ALL && viruses_found)
 
364
        return CL_VIRUS;
 
365
    return ret;
 
366
}
 
367
 
 
368
static int cli_scanarj(cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
 
369
{
 
370
        int ret = CL_CLEAN, rc, file = 0;
 
371
        arj_metadata_t metadata;
 
372
        char *dir;
 
373
 
 
374
    UNUSEDPARAM(sfx_check);
 
375
 
 
376
    cli_dbgmsg("in cli_scanarj()\n");
 
377
 
 
378
     /* generate the temporary directory */
 
379
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
 
380
        return CL_EMEM;
 
381
 
 
382
    if(mkdir(dir, 0700)) {
 
383
        cli_dbgmsg("ARJ: Can't create temporary directory %s\n", dir);
 
384
        free(dir);
 
385
        return CL_ETMPDIR;
 
386
    }
 
387
 
 
388
    ret = cli_unarj_open(*ctx->fmap, dir, &metadata, sfx_offset);
 
389
    if (ret != CL_SUCCESS) {
 
390
        if(!ctx->engine->keeptmp)
 
391
            cli_rmdirs(dir);
 
392
        free(dir);
 
393
        cli_dbgmsg("ARJ: Error: %s\n", cl_strerror(ret));
 
394
        return ret;
 
395
    }
 
396
    
 
397
   do {
 
398
        metadata.filename = NULL;
 
399
        ret = cli_unarj_prepare_file(dir, &metadata);
 
400
        if (ret != CL_SUCCESS) {
 
401
           cli_dbgmsg("ARJ: cli_unarj_prepare_file Error: %s\n", cl_strerror(ret));
 
402
           break;
 
403
        }
 
404
        file++;
 
405
        if(cli_matchmeta(ctx, metadata.filename, metadata.comp_size, metadata.orig_size, metadata.encrypted, file, 0, NULL) == CL_VIRUS) {
 
406
        cli_rmdirs(dir);
 
407
        free(dir);
 
408
            return CL_VIRUS;
 
409
    }
 
410
 
 
411
        if ((ret = cli_checklimits("ARJ", ctx, metadata.orig_size, metadata.comp_size, 0))!=CL_CLEAN) {
 
412
            ret = CL_SUCCESS;
 
413
            if (metadata.filename)
 
414
                free(metadata.filename);
 
415
            continue;
 
416
        }
 
417
        ret = cli_unarj_extract_file(dir, &metadata);
 
418
        if (ret != CL_SUCCESS) {
 
419
           cli_dbgmsg("ARJ: cli_unarj_extract_file Error: %s\n", cl_strerror(ret));
 
420
        }
 
421
        if (metadata.ofd >= 0) {
 
422
            if (lseek(metadata.ofd, 0, SEEK_SET) == -1) {
 
423
            cli_dbgmsg("ARJ: call to lseek() failed\n");
 
424
        }
 
425
            rc = cli_magic_scandesc(metadata.ofd, ctx);
 
426
            close(metadata.ofd);
 
427
            if (rc == CL_VIRUS) {
 
428
                cli_dbgmsg("ARJ: infected with %s\n", cli_get_last_virus(ctx));
 
429
                ret = CL_VIRUS;
 
430
                if (metadata.filename) {
 
431
                    free(metadata.filename);
 
432
                    metadata.filename = NULL;
 
433
                }
 
434
                break;
 
435
            }
 
436
        }
 
437
        if (metadata.filename) {
 
438
                free(metadata.filename);
 
439
                metadata.filename = NULL;
 
440
        }
 
441
 
 
442
    } while(ret == CL_SUCCESS);
 
443
    
 
444
    if(!ctx->engine->keeptmp)
 
445
        cli_rmdirs(dir);
 
446
 
 
447
    free(dir);
 
448
    if (metadata.filename) {
 
449
        free(metadata.filename);
 
450
    }
 
451
 
 
452
    cli_dbgmsg("ARJ: Exit code: %d\n", ret);
 
453
    if (ret == CL_BREAK)
 
454
        ret = CL_CLEAN;
 
455
 
 
456
    return ret;
 
457
}
 
458
 
 
459
 
 
460
static int cli_scangzip_with_zib_from_the_80s(cli_ctx *ctx, unsigned char *buff) {
 
461
    int fd, ret, outsize = 0, bytes;
 
462
    fmap_t *map = *ctx->fmap;
 
463
    char *tmpname;
 
464
    gzFile gz;
 
465
 
 
466
    ret = fmap_fd(map);
 
467
    if(ret < 0)
 
468
        return CL_EDUP;
 
469
    fd = dup(ret);
 
470
    if(fd < 0)
 
471
        return CL_EDUP;
 
472
 
 
473
    if(!(gz = gzdopen(fd, "rb"))) {
 
474
        close(fd);
 
475
        return CL_EOPEN;
 
476
    }
 
477
 
 
478
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
 
479
        cli_dbgmsg("GZip: Can't generate temporary file.\n");
 
480
        gzclose(gz);
 
481
        close(fd);
 
482
        return ret;
 
483
    }
 
484
    
 
485
    while((bytes = gzread(gz, buff, FILEBUFF)) > 0) {
 
486
        outsize += bytes;
 
487
        if(cli_checklimits("GZip", ctx, outsize, 0, 0)!=CL_CLEAN)
 
488
            break;
 
489
        if(cli_writen(fd, buff, bytes) != bytes) {
 
490
            close(fd);
 
491
            gzclose(gz);
 
492
            if(cli_unlink(tmpname)) {
 
493
                free(tmpname);
 
494
                return CL_EUNLINK;
 
495
            }
 
496
            free(tmpname);
 
497
            return CL_EWRITE;
 
498
        }
 
499
    }
 
500
 
 
501
    gzclose(gz);
 
502
 
 
503
    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
 
504
        cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx));
 
505
        close(fd);
 
506
        if(!ctx->engine->keeptmp) {
 
507
            if (cli_unlink(tmpname)) {
 
508
                free(tmpname);
 
509
                return CL_EUNLINK;
 
510
            }
 
511
        }
 
512
        free(tmpname);
 
513
        return CL_VIRUS;
 
514
    }
 
515
    close(fd);
 
516
    if(!ctx->engine->keeptmp)
 
517
        if (cli_unlink(tmpname)) ret = CL_EUNLINK;
 
518
    free(tmpname);
 
519
    return ret;
 
520
}
 
521
 
 
522
static int cli_scangzip(cli_ctx *ctx)
 
523
{
 
524
        int fd, ret = CL_CLEAN;
 
525
        unsigned char buff[FILEBUFF];
 
526
        char *tmpname;
 
527
        z_stream z;
 
528
        size_t at = 0, outsize = 0;
 
529
        fmap_t *map = *ctx->fmap;
 
530
        
 
531
    cli_dbgmsg("in cli_scangzip()\n");
 
532
 
 
533
    memset(&z, 0, sizeof(z));
 
534
    if((ret = inflateInit2(&z, MAX_WBITS + 16)) != Z_OK) {
 
535
        cli_dbgmsg("GZip: InflateInit failed: %d\n", ret);
 
536
        return cli_scangzip_with_zib_from_the_80s(ctx, buff);
 
537
    }
 
538
 
 
539
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
 
540
        cli_dbgmsg("GZip: Can't generate temporary file.\n");
 
541
        inflateEnd(&z);
 
542
        return ret;
 
543
    }
 
544
 
 
545
    while (at < map->len) {
 
546
        unsigned int bytes = MIN(map->len - at, map->pgsz);
 
547
        if(!(z.next_in = (void*)fmap_need_off_once(map, at, bytes))) {
 
548
            cli_dbgmsg("GZip: Can't read %u bytes @ %lu.\n", bytes, (long unsigned)at);
 
549
            inflateEnd(&z);
 
550
            close(fd);
 
551
            if (cli_unlink(tmpname)) {
 
552
                free(tmpname);
 
553
                return CL_EUNLINK;
 
554
            }
 
555
            free(tmpname);
 
556
            return CL_EREAD;
 
557
        }
 
558
        at += bytes;
 
559
        z.avail_in = bytes;
 
560
        do {
 
561
            int inf;
 
562
            z.avail_out = sizeof(buff);
 
563
            z.next_out = buff;
 
564
            inf = inflate(&z, Z_NO_FLUSH);
 
565
            if(inf != Z_OK && inf != Z_STREAM_END && inf != Z_BUF_ERROR) {
 
566
                if (sizeof(buff) == z.avail_out) {
 
567
                    cli_dbgmsg("GZip: Bad stream, nothing in output buffer.\n");
 
568
                    at = map->len;
 
569
                    break;
 
570
                }
 
571
                else {
 
572
                    cli_dbgmsg("GZip: Bad stream, data in output buffer.\n");
 
573
                    /* no break yet, flush extracted bytes to file */
 
574
                }
 
575
            }
 
576
            if(cli_writen(fd, buff, sizeof(buff) - z.avail_out) < 0) {
 
577
                inflateEnd(&z);     
 
578
                close(fd);
 
579
                if (cli_unlink(tmpname)) {
 
580
                    free(tmpname);
 
581
                    return CL_EUNLINK;
 
582
                }
 
583
                free(tmpname);
 
584
                return CL_EWRITE;
 
585
            }
 
586
            outsize += sizeof(buff) - z.avail_out;
 
587
            if(cli_checklimits("GZip", ctx, outsize, 0, 0)!=CL_CLEAN) {
 
588
                at = map->len;
 
589
                break;
 
590
            }
 
591
            if(inf == Z_STREAM_END) {
 
592
                at -= z.avail_in;
 
593
                inflateReset(&z);
 
594
                break;
 
595
            }
 
596
            else if(inf != Z_OK && inf != Z_BUF_ERROR) {
 
597
                at = map->len;
 
598
                break;
 
599
            }
 
600
        } while (z.avail_out == 0);
 
601
    }
 
602
 
 
603
    inflateEnd(&z);         
 
604
 
 
605
    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
 
606
        cli_dbgmsg("GZip: Infected with %s\n", cli_get_last_virus(ctx));
 
607
        close(fd);
 
608
        if(!ctx->engine->keeptmp) {
 
609
            if (cli_unlink(tmpname)) {
 
610
                free(tmpname);
 
611
                return CL_EUNLINK;
 
612
            }
 
613
        }
 
614
        free(tmpname);
 
615
        return CL_VIRUS;
 
616
    }
 
617
    close(fd);
 
618
    if(!ctx->engine->keeptmp)
 
619
        if (cli_unlink(tmpname)) ret = CL_EUNLINK;
 
620
    free(tmpname);
 
621
    return ret;
 
622
}
 
623
 
 
624
#ifndef HAVE_BZLIB_H
 
625
static int cli_scanbzip(cli_ctx *ctx) {
 
626
    cli_warnmsg("cli_scanbzip: bzip2 support not compiled in\n");
 
627
    return CL_CLEAN;
 
628
}
 
629
 
 
630
#else
 
631
 
 
632
#ifdef NOBZ2PREFIX
 
633
#define BZ2_bzDecompressInit bzDecompressInit
 
634
#define BZ2_bzDecompress bzDecompress
 
635
#define BZ2_bzDecompressEnd bzDecompressEnd
 
636
#endif
 
637
 
 
638
static int cli_scanbzip(cli_ctx *ctx)
 
639
{
 
640
    int ret = CL_CLEAN, fd, rc;
 
641
    unsigned long int size = 0;
 
642
    char *tmpname;
 
643
    bz_stream strm;
 
644
    size_t off = 0;
 
645
    size_t avail;
 
646
    char buf[FILEBUFF];
 
647
 
 
648
    memset(&strm, 0, sizeof(strm));
 
649
    strm.next_out = buf;
 
650
    strm.avail_out = sizeof(buf);
 
651
    rc = BZ2_bzDecompressInit(&strm, 0, 0);
 
652
    if (BZ_OK != rc) {
 
653
        cli_dbgmsg("Bzip: DecompressInit failed: %d\n", rc);
 
654
        return CL_EOPEN;
 
655
    }
 
656
 
 
657
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd))) {
 
658
        cli_dbgmsg("Bzip: Can't generate temporary file.\n");
 
659
        BZ2_bzDecompressEnd(&strm);
 
660
        return ret;
 
661
    }
 
662
 
 
663
    do {
 
664
        if (!strm.avail_in) {
 
665
            strm.next_in = (void*)fmap_need_off_once_len(*ctx->fmap, off, FILEBUFF, &avail);
 
666
            strm.avail_in = avail;
 
667
            off += avail;
 
668
            if (!strm.avail_in) {
 
669
                cli_dbgmsg("Bzip: premature end of compressed stream\n");
 
670
                break;
 
671
            }
 
672
        }
 
673
 
 
674
        rc = BZ2_bzDecompress(&strm);
 
675
        if (BZ_OK != rc && BZ_STREAM_END != rc) {
 
676
            cli_dbgmsg("Bzip: decompress error: %d\n", rc);
 
677
            break;
 
678
        }
 
679
 
 
680
        if (!strm.avail_out || BZ_STREAM_END == rc) {
 
681
            size += sizeof(buf) - strm.avail_out;
 
682
 
 
683
            if(cli_checklimits("Bzip", ctx, size + FILEBUFF, 0, 0)!=CL_CLEAN)
 
684
                break;
 
685
 
 
686
            if(cli_writen(fd, buf, sizeof(buf) - strm.avail_out) != sizeof(buf) - strm.avail_out) {
 
687
                cli_dbgmsg("Bzip: Can't write to file.\n");
 
688
                BZ2_bzDecompressEnd(&strm);
 
689
                close(fd);
 
690
                if(!ctx->engine->keeptmp) {
 
691
                    if (cli_unlink(tmpname)) {
 
692
                        free(tmpname);
 
693
                        return CL_EUNLINK;
 
694
                    }
 
695
                }
 
696
                free(tmpname);
 
697
                return CL_EWRITE;
 
698
            }
 
699
            strm.next_out = buf;
 
700
            strm.avail_out = sizeof(buf);
 
701
        }
 
702
    } while (BZ_STREAM_END != rc);
 
703
 
 
704
    BZ2_bzDecompressEnd(&strm);
 
705
 
 
706
    if(ret == CL_VIRUS) {
 
707
        close(fd);
 
708
        if(!ctx->engine->keeptmp)
 
709
            if (cli_unlink(tmpname)) ret = CL_EUNLINK;
 
710
        free(tmpname);
 
711
        return ret;
 
712
    }
 
713
 
 
714
    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
 
715
        cli_dbgmsg("Bzip: Infected with %s\n", cli_get_last_virus(ctx));
 
716
    }
 
717
    close(fd);
 
718
    if(!ctx->engine->keeptmp)
 
719
        if (cli_unlink(tmpname)) ret = CL_EUNLINK;
 
720
    free(tmpname);
 
721
 
 
722
    return ret;
 
723
}
 
724
#endif
 
725
 
 
726
static int cli_scanxz(cli_ctx *ctx)
 
727
{
 
728
    int ret = CL_CLEAN, fd, rc;
 
729
    unsigned long int size = 0;
 
730
    char *tmpname;
 
731
    struct CLI_XZ strm;
 
732
    size_t off = 0;
 
733
    size_t avail;
 
734
    unsigned char *buf;
 
735
 
 
736
    buf = cli_malloc(CLI_XZ_OBUF_SIZE);
 
737
    if (buf == NULL) {
 
738
        cli_errmsg("cli_scanxz: nomemory for decompress buffer.\n");
 
739
        return CL_EMEM;
 
740
    }
 
741
    memset(&strm, 0x00, sizeof(struct CLI_XZ));
 
742
    strm.next_out = buf;
 
743
    strm.avail_out = CLI_XZ_OBUF_SIZE;
 
744
    rc = cli_XzInit(&strm);
 
745
    if (rc != XZ_RESULT_OK) {
 
746
        cli_errmsg("cli_scanxz: DecompressInit failed: %i\n", rc);
 
747
        free(buf);
 
748
        return CL_EOPEN;
 
749
    }
 
750
 
 
751
    if ((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd))) {
 
752
        cli_errmsg("cli_scanxz: Can't generate temporary file.\n");
 
753
        cli_XzShutdown(&strm);
 
754
        free(buf);
 
755
        return ret;
 
756
    }
 
757
    cli_dbgmsg("cli_scanxz: decompressing to file %s\n", tmpname);
 
758
 
 
759
    do {
 
760
        /* set up input buffer */
 
761
        if (!strm.avail_in) {
 
762
            strm.next_in = (void*)fmap_need_off_once_len(*ctx->fmap, off, CLI_XZ_IBUF_SIZE, &avail);
 
763
            strm.avail_in = avail;
 
764
            off += avail;
 
765
            if (!strm.avail_in) {
 
766
                cli_errmsg("cli_scanxz: premature end of compressed stream\n");
 
767
                ret = CL_EFORMAT;
 
768
                goto xz_exit;
 
769
            }
 
770
        }
 
771
 
 
772
        /* xz decompress a chunk */
 
773
        rc = cli_XzDecode(&strm);
 
774
        if (XZ_RESULT_OK != rc && XZ_STREAM_END != rc) {
 
775
            cli_errmsg("cli_scanxz: decompress error: %d\n", rc);
 
776
            ret = CL_EFORMAT;
 
777
            goto xz_exit;
 
778
        }
 
779
        //cli_dbgmsg("cli_scanxz: xz decompressed %li of %li available bytes\n",
 
780
        //           avail - strm.avail_in, avail);
 
781
        
 
782
        /* write decompress buffer */
 
783
        if (!strm.avail_out || rc == XZ_STREAM_END) {            
 
784
            size_t towrite = CLI_XZ_OBUF_SIZE - strm.avail_out;
 
785
            size += towrite;
 
786
 
 
787
            //cli_dbgmsg("Writing %li bytes to XZ decompress temp file(%li byte total)\n",
 
788
            //           towrite, size);
 
789
 
 
790
            if((size_t)cli_writen(fd, buf, towrite) != towrite) {
 
791
                cli_errmsg("cli_scanxz: Can't write to file.\n");
 
792
                ret = CL_EWRITE;
 
793
                goto xz_exit;
 
794
            }
 
795
            if (cli_checklimits("cli_scanxz", ctx, size, 0, 0) != CL_CLEAN) {
 
796
                cli_warnmsg("cli_scanxz: decompress file size exceeds limits - "
 
797
                            "only scanning %li bytes\n", size);
 
798
                break;
 
799
            }
 
800
            strm.next_out = buf;
 
801
            strm.avail_out = CLI_XZ_OBUF_SIZE;
 
802
        }
 
803
    } while (XZ_STREAM_END != rc);
 
804
 
 
805
    /* scan decompressed file */
 
806
    if ((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
 
807
        cli_dbgmsg("cli_scanxz: Infected with %s\n", cli_get_last_virus(ctx));
 
808
    }
 
809
 
 
810
 xz_exit:
 
811
    cli_XzShutdown(&strm);
 
812
    close(fd);
 
813
    if(!ctx->engine->keeptmp)
 
814
        if (cli_unlink(tmpname) && ret == CL_CLEAN)
 
815
            ret = CL_EUNLINK;
 
816
    free(tmpname);
 
817
    free(buf);
 
818
    return ret;
 
819
}
 
820
 
 
821
static int cli_scanszdd(cli_ctx *ctx)
 
822
{
 
823
        int ofd, ret;
 
824
        char *tmpname;
 
825
 
 
826
 
 
827
    cli_dbgmsg("in cli_scanszdd()\n");
 
828
 
 
829
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &ofd))) {
 
830
        cli_dbgmsg("MSEXPAND: Can't generate temporary file/descriptor\n");
 
831
        return ret;
 
832
    }
 
833
 
 
834
    ret = cli_msexpand(ctx, ofd);
 
835
 
 
836
    if(ret != CL_SUCCESS) { /* CL_VIRUS or some error */
 
837
        close(ofd);
 
838
        if(!ctx->engine->keeptmp)
 
839
            if (cli_unlink(tmpname)) ret = CL_EUNLINK;
 
840
        free(tmpname);  
 
841
        return ret;
 
842
    }
 
843
 
 
844
    cli_dbgmsg("MSEXPAND: Decompressed into %s\n", tmpname);
 
845
    ret = cli_magic_scandesc(ofd, ctx);
 
846
    close(ofd);
 
847
    if(!ctx->engine->keeptmp)
 
848
        if (cli_unlink(tmpname)) ret = CL_EUNLINK;
 
849
    free(tmpname);      
 
850
 
 
851
    return ret;
 
852
}
 
853
 
 
854
static int vba_scandata(const unsigned char *data, unsigned int len, cli_ctx *ctx)
 
855
{
 
856
        struct cli_matcher *groot = ctx->engine->root[0];
 
857
        struct cli_matcher *troot = ctx->engine->root[2];
 
858
        struct cli_ac_data gmdata, tmdata;
 
859
        struct cli_ac_data *mdata[2];
 
860
        int ret;
 
861
        unsigned int viruses_found = 0;
 
862
 
 
863
    if((ret = cli_ac_initdata(&tmdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
 
864
        return ret;
 
865
 
 
866
    if((ret = cli_ac_initdata(&gmdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) {
 
867
        cli_ac_freedata(&tmdata);
 
868
        return ret;
 
869
    }
 
870
    mdata[0] = &tmdata;
 
871
    mdata[1] = &gmdata;
 
872
 
 
873
    ret = cli_scanbuff(data, len, 0, ctx, CL_TYPE_MSOLE2, mdata);
 
874
    if (ret == CL_VIRUS)
 
875
        viruses_found++;
 
876
 
 
877
    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
 
878
        ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL);
 
879
        if (ret == CL_VIRUS)
 
880
            viruses_found++;
 
881
 
 
882
        if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL))
 
883
            ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL);
 
884
    }
 
885
    cli_ac_freedata(&tmdata);
 
886
    cli_ac_freedata(&gmdata);
 
887
 
 
888
    return (ret != CL_CLEAN)?ret:viruses_found?CL_VIRUS:CL_CLEAN;
 
889
}
 
890
 
 
891
static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
 
892
{
 
893
        int ret = CL_CLEAN, i, j, fd, data_len, hasmacros = 0;
 
894
        vba_project_t *vba_project;
 
895
        DIR *dd;
 
896
        struct dirent *dent;
 
897
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
 
898
        union {
 
899
            struct dirent d;
 
900
            char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
 
901
        } result;
 
902
#endif
 
903
        STATBUF statbuf;
 
904
        char *fullname, vbaname[1024];
 
905
        unsigned char *data;
 
906
        char *hash;
 
907
        uint32_t hashcnt;
 
908
        unsigned int viruses_found = 0;
 
909
 
 
910
 
 
911
    cli_dbgmsg("VBADir: %s\n", dirname);
 
912
    hashcnt = uniq_get(U, "_vba_project", 12, NULL);
 
913
    while(hashcnt--) {
 
914
        if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue;
 
915
 
 
916
        for(i = 0; i < vba_project->count; i++) {
 
917
            for(j = 0; (unsigned int)j < vba_project->colls[i]; j++) {
 
918
                snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", vba_project->dir, vba_project->name[i], j);
 
919
                vbaname[sizeof(vbaname)-1] = '\0';
 
920
                fd = open(vbaname, O_RDONLY|O_BINARY);
 
921
                if(fd == -1) continue;
 
922
                cli_dbgmsg("VBADir: Decompress VBA project '%s_%u'\n", vba_project->name[i], j);
 
923
                data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
 
924
                close(fd);
 
925
                hasmacros++;
 
926
                if(!data) {
 
927
                    cli_dbgmsg("VBADir: WARNING: VBA project '%s_%u' decompressed to NULL\n", vba_project->name[i], j);
 
928
                } else {
 
929
                    /* cli_dbgmsg("Project content:\n%s", data); */
 
930
                    if(ctx->scanned)
 
931
                        *ctx->scanned += data_len / CL_COUNT_PRECISION;
 
932
                    if(vba_scandata(data, data_len, ctx) == CL_VIRUS) {
 
933
                        if (SCAN_ALL) 
 
934
                            viruses_found++;
 
935
                        else {
 
936
                            free(data);
 
937
                            ret = CL_VIRUS;
 
938
                            break;
 
939
                        }
 
940
                    }
 
941
                    free(data);
 
942
                }
 
943
            }
 
944
        }
 
945
 
 
946
        free(vba_project->name);
 
947
        free(vba_project->colls);
 
948
        free(vba_project->dir);
 
949
        free(vba_project->offset);
 
950
        free(vba_project);
 
951
        if (ret == CL_VIRUS && !SCAN_ALL)
 
952
            break;
 
953
    }
 
954
 
 
955
    if((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) && 
 
956
        (hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
 
957
        while(hashcnt--) {
 
958
            snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
 
959
            vbaname[sizeof(vbaname)-1] = '\0';
 
960
            fd = open(vbaname, O_RDONLY|O_BINARY);
 
961
            if (fd == -1) continue;
 
962
            if ((fullname = cli_ppt_vba_read(fd, ctx))) {
 
963
                if(cli_scandir(fullname, ctx) == CL_VIRUS) {
 
964
                    ret = CL_VIRUS;
 
965
                    viruses_found++;
 
966
                }
 
967
                if(!ctx->engine->keeptmp)
 
968
                    cli_rmdirs(fullname);
 
969
                free(fullname);
 
970
            }
 
971
            close(fd);
 
972
        }
 
973
    }
 
974
 
 
975
    if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) && 
 
976
        (hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
 
977
        while(hashcnt--) {
 
978
            snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
 
979
            vbaname[sizeof(vbaname)-1] = '\0';
 
980
            fd = open(vbaname, O_RDONLY|O_BINARY);
 
981
            if (fd == -1) continue;
 
982
            
 
983
            if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) {
 
984
                close(fd);
 
985
                continue;
 
986
            }
 
987
 
 
988
            for (i = 0; i < vba_project->count; i++) {
 
989
                cli_dbgmsg("VBADir: Decompress WM project macro:%d key:%d length:%d\n", i, vba_project->key[i], vba_project->length[i]);
 
990
                data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]);
 
991
                if(!data) {
 
992
                        cli_dbgmsg("VBADir: WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i);
 
993
                } else {
 
994
                        cli_dbgmsg("Project content:\n%s", data);
 
995
                        if(ctx->scanned)
 
996
                            *ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION;
 
997
                        if(vba_scandata(data, vba_project->length[i], ctx) == CL_VIRUS) {
 
998
                            if (SCAN_ALL)
 
999
                                viruses_found++;
 
1000
                            else {
 
1001
                                free(data);
 
1002
                                ret = CL_VIRUS;
 
1003
                                break;
 
1004
                            }
 
1005
                        }
 
1006
                        free(data);
 
1007
                }
 
1008
            }
 
1009
 
 
1010
            close(fd);
 
1011
            free(vba_project->name);
 
1012
            free(vba_project->colls);
 
1013
            free(vba_project->dir);
 
1014
            free(vba_project->offset);
 
1015
            free(vba_project->key);
 
1016
            free(vba_project->length);
 
1017
            free(vba_project);
 
1018
            if(ret == CL_VIRUS) {
 
1019
                if (SCAN_ALL)
 
1020
                    viruses_found++;
 
1021
                else
 
1022
                    break;
 
1023
            }
 
1024
        }
 
1025
    }
 
1026
 
 
1027
    if(ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
 
1028
        return ret;
 
1029
 
 
1030
#if HAVE_JSON
 
1031
    /* JSON Output Summary Information */
 
1032
    if (ctx->options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL) {
 
1033
        hashcnt = uniq_get(U, "_5_summaryinformation", 21, &hash);
 
1034
        while(hashcnt--) {
 
1035
            snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
 
1036
            vbaname[sizeof(vbaname)-1] = '\0';
 
1037
 
 
1038
            fd = open(vbaname, O_RDONLY|O_BINARY);
 
1039
            if (fd >= 0) {
 
1040
                cli_dbgmsg("VBADir: detected a '_5_summaryinformation' stream\n");
 
1041
                /* JSONOLE2 - what to do if something breaks? */
 
1042
                cli_ole2_summary_json(ctx, fd, 0);
 
1043
                close(fd);
 
1044
            }
 
1045
        }
 
1046
 
 
1047
        hashcnt = uniq_get(U, "_5_documentsummaryinformation", 29, &hash);
 
1048
        while(hashcnt--) {
 
1049
            snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
 
1050
            vbaname[sizeof(vbaname)-1] = '\0';
 
1051
 
 
1052
            fd = open(vbaname, O_RDONLY|O_BINARY);
 
1053
            if (fd >= 0) {
 
1054
                cli_dbgmsg("VBADir: detected a '_5_documentsummaryinformation' stream\n");
 
1055
                /* JSONOLE2 - what to do if something breaks? */
 
1056
                cli_ole2_summary_json(ctx, fd, 1);
 
1057
                close(fd);
 
1058
            }
 
1059
        }
 
1060
    }
 
1061
#endif    
 
1062
 
 
1063
    /* Check directory for embedded OLE objects */
 
1064
    hashcnt = uniq_get(U, "_1_ole10native", 14, &hash);
 
1065
    while(hashcnt--) {
 
1066
        snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
 
1067
        vbaname[sizeof(vbaname)-1] = '\0';
 
1068
 
 
1069
        fd = open(vbaname, O_RDONLY|O_BINARY);
 
1070
        if (fd >= 0) {
 
1071
            ret = cli_scan_ole10(fd, ctx);
 
1072
            close(fd);
 
1073
            if(ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
 
1074
                return ret;
 
1075
        }
 
1076
    }
 
1077
 
 
1078
 
 
1079
    /* ACAB: since we now hash filenames and handle collisions we
 
1080
     * could avoid recursion by removing the block below and by
 
1081
     * flattening the paths in ole2_walk_property_tree (case 1) */
 
1082
 
 
1083
    if((dd = opendir(dirname)) != NULL) {
 
1084
#ifdef HAVE_READDIR_R_3
 
1085
        while(!readdir_r(dd, &result.d, &dent) && dent) {
 
1086
#elif defined(HAVE_READDIR_R_2)
 
1087
        while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
 
1088
#else
 
1089
        while((dent = readdir(dd))) {
 
1090
#endif
 
1091
            if(dent->d_ino)
 
1092
            {
 
1093
                if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
 
1094
                    /* build the full name */
 
1095
                    fullname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
 
1096
                    if(!fullname) {
 
1097
                cli_dbgmsg("cli_vba_scandir: Unable to allocate memory for fullname\n");
 
1098
                        ret = CL_EMEM;
 
1099
                        break;
 
1100
                    }
 
1101
                    sprintf(fullname, "%s"PATHSEP"%s", dirname, dent->d_name);
 
1102
 
 
1103
                    /* stat the file */
 
1104
                    if(LSTAT(fullname, &statbuf) != -1) {
 
1105
                        if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
 
1106
                          if (cli_vba_scandir(fullname, ctx, U) == CL_VIRUS) {
 
1107
                              if (SCAN_ALL)
 
1108
                                  viruses_found++;
 
1109
                              else {
 
1110
                                  ret = CL_VIRUS;
 
1111
                                  free(fullname);
 
1112
                                  break;
 
1113
                              }
 
1114
                          }
 
1115
                    }
 
1116
                    free(fullname);
 
1117
                }
 
1118
            }
 
1119
        }
 
1120
    } else {
 
1121
        cli_dbgmsg("VBADir: Can't open directory %s.\n", dirname);
 
1122
        return CL_EOPEN;
 
1123
    }
 
1124
 
 
1125
    closedir(dd);
 
1126
#if HAVE_JSON
 
1127
    if (hasmacros && ctx->options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL)
 
1128
        cli_jsonbool(ctx->wrkproperty, "HasMacros", 1);
 
1129
#endif
 
1130
    if(BLOCK_MACROS && hasmacros) {
 
1131
        cli_append_virus(ctx, "Heuristics.OLE2.ContainsMacros");
 
1132
        ret = CL_VIRUS;
 
1133
        viruses_found++;
 
1134
    }
 
1135
    if (SCAN_ALL && viruses_found)
 
1136
        return CL_VIRUS;
 
1137
    return ret;
 
1138
}
 
1139
 
 
1140
static int cli_scanhtml(cli_ctx *ctx)
 
1141
{
 
1142
    char *tempname, fullname[1024];
 
1143
    int ret=CL_CLEAN, fd;
 
1144
    fmap_t *map = *ctx->fmap;
 
1145
    unsigned int viruses_found = 0;
 
1146
    uint64_t curr_len = map->len;
 
1147
 
 
1148
    cli_dbgmsg("in cli_scanhtml()\n");
 
1149
 
 
1150
    /* CL_ENGINE_MAX_HTMLNORMALIZE */
 
1151
    if(curr_len > ctx->engine->maxhtmlnormalize) {
 
1152
        cli_dbgmsg("cli_scanhtml: exiting (file larger than MaxHTMLNormalize)\n");
 
1153
        return CL_CLEAN;
 
1154
    }
 
1155
 
 
1156
    if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
 
1157
        return CL_EMEM;
 
1158
 
 
1159
    if(mkdir(tempname, 0700)) {
 
1160
        cli_errmsg("cli_scanhtml: Can't create temporary directory %s\n", tempname);
 
1161
        free(tempname);
 
1162
        return CL_ETMPDIR;
 
1163
    }
 
1164
 
 
1165
    cli_dbgmsg("cli_scanhtml: using tempdir %s\n", tempname);
 
1166
 
 
1167
    html_normalise_map(map, tempname, NULL, ctx->dconf);
 
1168
    snprintf(fullname, 1024, "%s"PATHSEP"nocomment.html", tempname);
 
1169
    fd = open(fullname, O_RDONLY|O_BINARY);
 
1170
    if (fd >= 0) {
 
1171
        if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
 
1172
            viruses_found++;
 
1173
        close(fd);
 
1174
    }
 
1175
 
 
1176
    if(ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
 
1177
        /* CL_ENGINE_MAX_HTMLNOTAGS */
 
1178
        curr_len = map->len;
 
1179
        if (curr_len > ctx->engine->maxhtmlnotags) {
 
1180
            /* we're not interested in scanning large files in notags form */
 
1181
            /* TODO: don't even create notags if file is over limit */
 
1182
            cli_dbgmsg("cli_scanhtml: skipping notags (normalized size over MaxHTMLNoTags)\n");
 
1183
        }
 
1184
        else {
 
1185
            snprintf(fullname, 1024, "%s"PATHSEP"notags.html", tempname);
 
1186
            fd = open(fullname, O_RDONLY|O_BINARY);
 
1187
            if(fd >= 0) {
 
1188
                if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS) 
 
1189
                    viruses_found++;
 
1190
                close(fd);
 
1191
            }
 
1192
        }
 
1193
    }
 
1194
 
 
1195
    if(ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
 
1196
            snprintf(fullname, 1024, "%s"PATHSEP"javascript", tempname);
 
1197
            fd = open(fullname, O_RDONLY|O_BINARY);
 
1198
            if(fd >= 0) {
 
1199
                if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
 
1200
                    viruses_found++;
 
1201
                if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
 
1202
                    if ((ret = cli_scandesc(fd, ctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
 
1203
                        viruses_found++;
 
1204
                }
 
1205
                close(fd);
 
1206
            }
 
1207
    }
 
1208
 
 
1209
    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) {
 
1210
        snprintf(fullname, 1024, "%s"PATHSEP"rfc2397", tempname);
 
1211
        ret = cli_scandir(fullname, ctx);
 
1212
    }
 
1213
 
 
1214
    if(!ctx->engine->keeptmp)
 
1215
        cli_rmdirs(tempname);
 
1216
 
 
1217
    free(tempname);
 
1218
    if (SCAN_ALL && viruses_found)
 
1219
        return CL_VIRUS;
 
1220
    return ret;
 
1221
}
 
1222
 
 
1223
static int cli_scanscript(cli_ctx *ctx)
 
1224
{
 
1225
    const unsigned char *buff;
 
1226
    unsigned char* normalized;
 
1227
    struct text_norm_state state;
 
1228
    char *tmpname = NULL;
 
1229
    int ofd = -1, ret;
 
1230
    struct cli_matcher *troot;
 
1231
    uint32_t maxpatlen, offset = 0;
 
1232
    struct cli_matcher *groot;
 
1233
    struct cli_ac_data gmdata, tmdata;
 
1234
    struct cli_ac_data *mdata[2];
 
1235
    fmap_t *map;
 
1236
    size_t at = 0;
 
1237
    unsigned int viruses_found = 0;
 
1238
    uint64_t curr_len;
 
1239
    struct cli_target_info info;
 
1240
 
 
1241
    if (!ctx || !ctx->engine->root)
 
1242
        return CL_ENULLARG;
 
1243
 
 
1244
    map = *ctx->fmap;
 
1245
    curr_len = map->len;
 
1246
    groot = ctx->engine->root[0];
 
1247
    troot = ctx->engine->root[7];
 
1248
    maxpatlen = troot ? troot->maxpatlen : 0;
 
1249
 
 
1250
    cli_dbgmsg("in cli_scanscript()\n");
 
1251
 
 
1252
    /* CL_ENGINE_MAX_SCRIPTNORMALIZE */
 
1253
    if(curr_len > ctx->engine->maxscriptnormalize) {
 
1254
        cli_dbgmsg("cli_scanscript: exiting (file larger than MaxScriptSize)\n");
 
1255
        return CL_CLEAN;
 
1256
    }
 
1257
 
 
1258
        /* dump to disk only if explicitly asked to,
 
1259
         * otherwise we can process just in-memory */
 
1260
        if(ctx->engine->keeptmp) {
 
1261
                if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &ofd))) {
 
1262
                        cli_dbgmsg("cli_scanscript: Can't generate temporary file/descriptor\n");
 
1263
                        return ret;
 
1264
                }
 
1265
                cli_dbgmsg("cli_scanscript: saving normalized file to %s\n", tmpname);
 
1266
        }
 
1267
 
 
1268
        if(!(normalized = cli_malloc(SCANBUFF + maxpatlen))) {
 
1269
                cli_dbgmsg("cli_scanscript: Unable to malloc %u bytes\n", SCANBUFF);
 
1270
        free(tmpname);
 
1271
                return CL_EMEM;
 
1272
        }
 
1273
 
 
1274
        text_normalize_init(&state, normalized, SCANBUFF + maxpatlen);
 
1275
        ret = CL_CLEAN;
 
1276
 
 
1277
        if ((ret = cli_ac_initdata(&tmdata, troot?troot->ac_partsigs:0, troot?troot->ac_lsigs:0, troot?troot->ac_reloff_num:0, CLI_DEFAULT_AC_TRACKLEN))) {
 
1278
        free(tmpname);
 
1279
            return ret;
 
1280
        }
 
1281
 
 
1282
        if (troot) {
 
1283
            cli_targetinfo(&info, 7, map);
 
1284
            ret = cli_ac_caloff(troot, &tmdata, &info);
 
1285
            if (ret) {
 
1286
                cli_ac_freedata(&tmdata);
 
1287
        free(tmpname);
 
1288
                return ret;
 
1289
            }
 
1290
        }
 
1291
 
 
1292
        if ((ret = cli_ac_initdata(&gmdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) {
 
1293
            cli_ac_freedata(&tmdata);
 
1294
        free(tmpname);
 
1295
            return ret;
 
1296
        }
 
1297
        mdata[0] = &tmdata;
 
1298
        mdata[1] = &gmdata;
 
1299
 
 
1300
        while(1) {
 
1301
            size_t len = MIN(map->pgsz, map->len - at);
 
1302
            buff = fmap_need_off_once(map, at, len);
 
1303
            at += len;
 
1304
            if(!buff || !len || state.out_pos + len > state.out_len) {
 
1305
                /* flush if error/EOF, or too little buffer space left */
 
1306
                if((ofd != -1) && (write(ofd, state.out, state.out_pos) == -1)) {
 
1307
                    cli_errmsg("cli_scanscript: can't write to file %s\n",tmpname);
 
1308
                    close(ofd);
 
1309
                    ofd = -1;
 
1310
                    /* we can continue to scan in memory */
 
1311
                }
 
1312
                /* when we flush the buffer also scan */
 
1313
                if(cli_scanbuff(state.out, state.out_pos, offset, ctx, CL_TYPE_TEXT_ASCII, mdata) == CL_VIRUS) {
 
1314
                    if (SCAN_ALL)
 
1315
                        viruses_found++;
 
1316
                    else {
 
1317
                        ret = CL_VIRUS;
 
1318
                        break;
 
1319
                    }
 
1320
                }
 
1321
                if(ctx->scanned)
 
1322
                    *ctx->scanned += state.out_pos / CL_COUNT_PRECISION;
 
1323
                offset += state.out_pos;
 
1324
                /* carry over maxpatlen from previous buffer */
 
1325
                if (state.out_pos > maxpatlen)
 
1326
                    memmove(state.out, state.out + state.out_pos - maxpatlen, maxpatlen); 
 
1327
                text_normalize_reset(&state);
 
1328
                state.out_pos = maxpatlen;
 
1329
            }
 
1330
            if(!len) break;
 
1331
            if(!buff || text_normalize_buffer(&state, buff, len) != len) {
 
1332
                cli_dbgmsg("cli_scanscript: short read during normalizing\n");
 
1333
            }
 
1334
        }
 
1335
        if(ctx->engine->keeptmp) {
 
1336
                free(tmpname);
 
1337
        if (ofd >= 0)
 
1338
            close(ofd);
 
1339
        }
 
1340
        free(normalized);
 
1341
        if(ret != CL_VIRUS || SCAN_ALL)  {
 
1342
            if ((ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL)) == CL_VIRUS)
 
1343
                viruses_found++;
 
1344
            if(ret != CL_VIRUS || SCAN_ALL)
 
1345
                if ((ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL)) == CL_VIRUS)
 
1346
                    viruses_found++;
 
1347
        }
 
1348
        cli_ac_freedata(&tmdata);
 
1349
        cli_ac_freedata(&gmdata);
 
1350
 
 
1351
        if (SCAN_ALL && viruses_found)
 
1352
            return CL_VIRUS;
 
1353
        return ret;
 
1354
}
 
1355
 
 
1356
static int cli_scanhtml_utf16(cli_ctx *ctx)
 
1357
{
 
1358
        char *tempname, *decoded;
 
1359
        const char *buff;
 
1360
        int ret = CL_CLEAN, fd, bytes;
 
1361
        size_t at = 0;
 
1362
        fmap_t *map = *ctx->fmap;
 
1363
 
 
1364
    cli_dbgmsg("in cli_scanhtml_utf16()\n");
 
1365
 
 
1366
    if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
 
1367
        return CL_EMEM;
 
1368
 
 
1369
    if((fd = open(tempname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
 
1370
        cli_errmsg("cli_scanhtml_utf16: Can't create file %s\n", tempname);
 
1371
        free(tempname);
 
1372
        return CL_EOPEN;
 
1373
    }
 
1374
 
 
1375
    cli_dbgmsg("cli_scanhtml_utf16: using tempfile %s\n", tempname);
 
1376
 
 
1377
    while(at < map->len) {
 
1378
        bytes = MIN(map->len - at, map->pgsz * 16);
 
1379
        if(!(buff = fmap_need_off_once(map, at, bytes))) {
 
1380
            close(fd);
 
1381
            cli_unlink(tempname);
 
1382
            free(tempname);
 
1383
            return CL_EREAD;
 
1384
        }
 
1385
        at += bytes;
 
1386
        decoded = cli_utf16toascii(buff, bytes);
 
1387
        if(decoded) {
 
1388
            if(write(fd, decoded, bytes / 2) == -1) {
 
1389
                cli_errmsg("cli_scanhtml_utf16: Can't write to file %s\n", tempname);
 
1390
                free(decoded);
 
1391
                close(fd);
 
1392
                cli_unlink(tempname);
 
1393
                free(tempname);
 
1394
                return CL_EWRITE;
 
1395
            }
 
1396
            free(decoded);
 
1397
        }
 
1398
    }
 
1399
 
 
1400
    *ctx->fmap = fmap(fd, 0, 0);
 
1401
    if(*ctx->fmap) {
 
1402
        ret = cli_scanhtml(ctx);
 
1403
        funmap(*ctx->fmap);
 
1404
    } else
 
1405
        cli_errmsg("cli_scanhtml_utf16: fmap of %s failed\n", tempname);
 
1406
 
 
1407
    *ctx->fmap = map;
 
1408
    close(fd);
 
1409
 
 
1410
    if(!ctx->engine->keeptmp) {
 
1411
        if (cli_unlink(tempname)) ret = CL_EUNLINK;
 
1412
    } else
 
1413
        cli_dbgmsg("cli_scanhtml_utf16: Decoded HTML data saved in %s\n", tempname);
 
1414
    free(tempname);
 
1415
 
 
1416
    return ret;
 
1417
}
 
1418
 
 
1419
static int cli_scanole2(cli_ctx *ctx)
 
1420
{
 
1421
        char *dir;
 
1422
        int ret = CL_CLEAN;
 
1423
        struct uniq *vba = NULL;
 
1424
 
 
1425
    cli_dbgmsg("in cli_scanole2()\n");
 
1426
 
 
1427
    if(ctx->engine->maxreclevel && ctx->recursion >= ctx->engine->maxreclevel)
 
1428
        return CL_EMAXREC;
 
1429
 
 
1430
    /* generate the temporary directory */
 
1431
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
 
1432
        return CL_EMEM;
 
1433
 
 
1434
    if(mkdir(dir, 0700)) {
 
1435
        cli_dbgmsg("OLE2: Can't create temporary directory %s\n", dir);
 
1436
        free(dir);
 
1437
        return CL_ETMPDIR;
 
1438
    }
 
1439
 
 
1440
    ret = cli_ole2_extract(dir, ctx, &vba);
 
1441
    if(ret!=CL_CLEAN && ret!=CL_VIRUS) {
 
1442
        cli_dbgmsg("OLE2: %s\n", cl_strerror(ret));
 
1443
        if(!ctx->engine->keeptmp)
 
1444
            cli_rmdirs(dir);
 
1445
        free(dir);
 
1446
        return ret;
 
1447
    }
 
1448
 
 
1449
    if (vba) {
 
1450
        ctx->recursion++;
 
1451
 
 
1452
        ret = cli_vba_scandir(dir, ctx, vba);
 
1453
        uniq_free(vba);
 
1454
        if(ret != CL_VIRUS)
 
1455
            if(cli_scandir(dir, ctx) == CL_VIRUS)
 
1456
                ret = CL_VIRUS;
 
1457
        ctx->recursion--;
 
1458
    }
 
1459
 
 
1460
    if(!ctx->engine->keeptmp)
 
1461
        cli_rmdirs(dir);
 
1462
    free(dir);
 
1463
    return ret;
 
1464
}
 
1465
 
 
1466
static int cli_scantar(cli_ctx *ctx, unsigned int posix)
 
1467
{
 
1468
        char *dir;
 
1469
        int ret = CL_CLEAN;
 
1470
 
 
1471
 
 
1472
    cli_dbgmsg("in cli_scantar()\n");
 
1473
 
 
1474
    /* generate temporary directory */
 
1475
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
 
1476
        return CL_EMEM;
 
1477
 
 
1478
    if(mkdir(dir, 0700)) {
 
1479
        cli_errmsg("Tar: Can't create temporary directory %s\n", dir);
 
1480
        free(dir);
 
1481
        return CL_ETMPDIR;
 
1482
    }
 
1483
 
 
1484
    ret = cli_untar(dir, posix, ctx);
 
1485
 
 
1486
    if(!ctx->engine->keeptmp)
 
1487
        cli_rmdirs(dir);
 
1488
 
 
1489
    free(dir);
 
1490
    return ret;
 
1491
}
 
1492
 
 
1493
static int cli_scanscrenc(cli_ctx *ctx)
 
1494
{
 
1495
        char *tempname;
 
1496
        int ret = CL_CLEAN;
 
1497
 
 
1498
    cli_dbgmsg("in cli_scanscrenc()\n");
 
1499
 
 
1500
    if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
 
1501
        return CL_EMEM;
 
1502
 
 
1503
    if(mkdir(tempname, 0700)) {
 
1504
        cli_dbgmsg("CHM: Can't create temporary directory %s\n", tempname);
 
1505
        free(tempname);
 
1506
        return CL_ETMPDIR;
 
1507
    }
 
1508
 
 
1509
    if (html_screnc_decode(*ctx->fmap, tempname))
 
1510
        ret = cli_scandir(tempname, ctx);
 
1511
 
 
1512
    if(!ctx->engine->keeptmp)
 
1513
        cli_rmdirs(tempname);
 
1514
 
 
1515
    free(tempname);
 
1516
    return ret;
 
1517
}
 
1518
 
 
1519
static int cli_scanriff(cli_ctx *ctx)
 
1520
{
 
1521
        int ret = CL_CLEAN;
 
1522
 
 
1523
    if(cli_check_riff_exploit(ctx) == 2) {
 
1524
        ret = CL_VIRUS;
 
1525
        cli_append_virus(ctx, "Heuristics.Exploit.W32.MS05-002");
 
1526
    }
 
1527
 
 
1528
    return ret;
 
1529
}
 
1530
 
 
1531
static int cli_scanjpeg(cli_ctx *ctx)
 
1532
{
 
1533
        int ret = CL_CLEAN;
 
1534
 
 
1535
        if(cli_check_jpeg_exploit(ctx, 0) == 1) {
 
1536
        ret = CL_VIRUS;
 
1537
        cli_append_virus(ctx, "Heuristics.Exploit.W32.MS04-028");
 
1538
    }
 
1539
 
 
1540
    return ret;
 
1541
}
 
1542
 
 
1543
static int cli_scancryptff(cli_ctx *ctx)
 
1544
{
 
1545
        int ret = CL_CLEAN, ndesc;
 
1546
        unsigned int i;
 
1547
        const unsigned char *src;
 
1548
        unsigned char *dest = NULL;
 
1549
        char *tempfile;
 
1550
        size_t pos;
 
1551
        size_t bread;
 
1552
 
 
1553
 
 
1554
    /* Skip the CryptFF file header */
 
1555
    pos = 0x10;
 
1556
 
 
1557
    if((dest = (unsigned char *) cli_malloc(FILEBUFF)) == NULL) {
 
1558
        cli_dbgmsg("CryptFF: Can't allocate memory\n");
 
1559
        return CL_EMEM;
 
1560
    }
 
1561
 
 
1562
    if(!(tempfile = cli_gentemp(ctx->engine->tmpdir))) {
 
1563
        free(dest);
 
1564
        return CL_EMEM;
 
1565
    }
 
1566
 
 
1567
    if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
 
1568
        cli_errmsg("CryptFF: Can't create file %s\n", tempfile);
 
1569
        free(dest);
 
1570
        free(tempfile);
 
1571
        return CL_ECREAT;
 
1572
    }
 
1573
 
 
1574
    for(; (src = fmap_need_off_once_len(*ctx->fmap, pos, FILEBUFF, &bread)) && bread; pos += bread) {
 
1575
        for (i=0;i<bread;i++)
 
1576
            dest[i] = src[i] ^ (unsigned char) 0xff;
 
1577
        if(cli_writen(ndesc, dest, bread) == -1) {
 
1578
            cli_dbgmsg("CryptFF: Can't write to descriptor %d\n", ndesc);
 
1579
            free(dest);
 
1580
            close(ndesc);
 
1581
            free(tempfile);
 
1582
            return CL_EWRITE;
 
1583
        }
 
1584
    }
 
1585
 
 
1586
    free(dest);
 
1587
 
 
1588
 
 
1589
    cli_dbgmsg("CryptFF: Scanning decrypted data\n");
 
1590
 
 
1591
    if((ret = cli_magic_scandesc(ndesc, ctx)) == CL_VIRUS)
 
1592
        cli_dbgmsg("CryptFF: Infected with %s\n", cli_get_last_virus(ctx));
 
1593
 
 
1594
    close(ndesc);
 
1595
 
 
1596
    if(ctx->engine->keeptmp)
 
1597
        cli_dbgmsg("CryptFF: Decompressed data saved in %s\n", tempfile);
 
1598
    else
 
1599
        if (cli_unlink(tempfile)) ret = CL_EUNLINK;
 
1600
 
 
1601
    free(tempfile);
 
1602
    return ret;
 
1603
}
 
1604
 
 
1605
static int cli_scanpdf(cli_ctx *ctx, off_t offset)
 
1606
{
 
1607
        int ret;
 
1608
        char *dir = cli_gentemp(ctx->engine->tmpdir);
 
1609
 
 
1610
    if(!dir)
 
1611
        return CL_EMEM;
 
1612
 
 
1613
    if(mkdir(dir, 0700)) {
 
1614
        cli_dbgmsg("Can't create temporary directory for PDF file %s\n", dir);
 
1615
        free(dir);
 
1616
        return CL_ETMPDIR;
 
1617
    }
 
1618
 
 
1619
    ret = cli_pdf(dir, ctx, offset);
 
1620
 
 
1621
    if(!ctx->engine->keeptmp)
 
1622
        cli_rmdirs(dir);
 
1623
 
 
1624
    free(dir);
 
1625
    return ret;
 
1626
}
 
1627
 
 
1628
static int cli_scantnef(cli_ctx *ctx)
 
1629
{
 
1630
        int ret;
 
1631
        char *dir = cli_gentemp(ctx->engine->tmpdir);
 
1632
 
 
1633
    if(!dir)
 
1634
        return CL_EMEM;
 
1635
 
 
1636
    if(mkdir(dir, 0700)) {
 
1637
        cli_dbgmsg("Can't create temporary directory for tnef file %s\n", dir);
 
1638
        free(dir);
 
1639
        return CL_ETMPDIR;
 
1640
    }
 
1641
 
 
1642
    ret = cli_tnef(dir, ctx);
 
1643
 
 
1644
    if(ret == CL_CLEAN)
 
1645
        ret = cli_scandir(dir, ctx);
 
1646
 
 
1647
    if(!ctx->engine->keeptmp)
 
1648
        cli_rmdirs(dir);
 
1649
 
 
1650
    free(dir);
 
1651
    return ret;
 
1652
}
 
1653
 
 
1654
static int cli_scanuuencoded(cli_ctx *ctx)
 
1655
{
 
1656
        int ret;
 
1657
        char *dir = cli_gentemp(ctx->engine->tmpdir);
 
1658
 
 
1659
    if(!dir)
 
1660
        return CL_EMEM;
 
1661
 
 
1662
    if(mkdir(dir, 0700)) {
 
1663
        cli_dbgmsg("Can't create temporary directory for uuencoded file %s\n", dir);
 
1664
        free(dir);
 
1665
        return CL_ETMPDIR;
 
1666
    }
 
1667
 
 
1668
    ret = cli_uuencode(dir, *ctx->fmap);
 
1669
 
 
1670
    if(ret == CL_CLEAN)
 
1671
        ret = cli_scandir(dir, ctx);
 
1672
 
 
1673
    if(!ctx->engine->keeptmp)
 
1674
        cli_rmdirs(dir);
 
1675
 
 
1676
    free(dir);
 
1677
    return ret;
 
1678
}
 
1679
 
 
1680
static int cli_scanmail(cli_ctx *ctx)
 
1681
{
 
1682
        char *dir;
 
1683
        int ret;
 
1684
        unsigned int viruses_found = 0;
 
1685
 
 
1686
    cli_dbgmsg("Starting cli_scanmail(), recursion = %u\n", ctx->recursion);
 
1687
 
 
1688
    /* generate the temporary directory */
 
1689
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
 
1690
        return CL_EMEM;
 
1691
 
 
1692
    if(mkdir(dir, 0700)) {
 
1693
        cli_dbgmsg("Mail: Can't create temporary directory %s\n", dir);
 
1694
        free(dir);
 
1695
        return CL_ETMPDIR;
 
1696
    }
 
1697
 
 
1698
    /*
 
1699
     * Extract the attachments into the temporary directory
 
1700
     */
 
1701
    if((ret = cli_mbox(dir, ctx))) {
 
1702
        if (ret == CL_VIRUS && SCAN_ALL)
 
1703
            viruses_found++;
 
1704
        else {
 
1705
            if(!ctx->engine->keeptmp)
 
1706
                cli_rmdirs(dir);
 
1707
            free(dir);
 
1708
            return ret;
 
1709
        }
 
1710
    }
 
1711
 
 
1712
    ret = cli_scandir(dir, ctx);
 
1713
 
 
1714
    if(!ctx->engine->keeptmp)
 
1715
        cli_rmdirs(dir);
 
1716
 
 
1717
    free(dir);
 
1718
    if (SCAN_ALL && viruses_found)
 
1719
        return CL_VIRUS;
 
1720
    return ret;
 
1721
}
 
1722
 
 
1723
static int cli_scan_structured(cli_ctx *ctx)
 
1724
{
 
1725
        char buf[8192];
 
1726
        int result = 0;
 
1727
        unsigned int cc_count = 0;
 
1728
        unsigned int ssn_count = 0;
 
1729
        int done = 0;
 
1730
        fmap_t *map;
 
1731
        size_t pos = 0;
 
1732
        int (*ccfunc)(const unsigned char *buffer, int length);
 
1733
        int (*ssnfunc)(const unsigned char *buffer, int length);
 
1734
        unsigned int viruses_found = 0;
 
1735
 
 
1736
    if(ctx == NULL)
 
1737
        return CL_ENULLARG;
 
1738
 
 
1739
    map = *ctx->fmap;
 
1740
 
 
1741
    if(ctx->engine->min_cc_count == 1)
 
1742
        ccfunc = dlp_has_cc;
 
1743
    else
 
1744
        ccfunc = dlp_get_cc_count;
 
1745
 
 
1746
    switch((ctx->options & CL_SCAN_STRUCTURED_SSN_NORMAL) | (ctx->options & CL_SCAN_STRUCTURED_SSN_STRIPPED)) {
 
1747
 
 
1748
        case (CL_SCAN_STRUCTURED_SSN_NORMAL | CL_SCAN_STRUCTURED_SSN_STRIPPED):
 
1749
            if(ctx->engine->min_ssn_count == 1)
 
1750
                ssnfunc = dlp_has_ssn;
 
1751
            else
 
1752
                ssnfunc = dlp_get_ssn_count;
 
1753
            break;
 
1754
 
 
1755
        case CL_SCAN_STRUCTURED_SSN_NORMAL:
 
1756
            if(ctx->engine->min_ssn_count == 1)
 
1757
                ssnfunc = dlp_has_normal_ssn;
 
1758
            else
 
1759
                ssnfunc = dlp_get_normal_ssn_count;
 
1760
            break;
 
1761
 
 
1762
        case CL_SCAN_STRUCTURED_SSN_STRIPPED:
 
1763
            if(ctx->engine->min_ssn_count == 1)
 
1764
                ssnfunc = dlp_has_stripped_ssn;
 
1765
            else
 
1766
                ssnfunc = dlp_get_stripped_ssn_count;
 
1767
            break;
 
1768
 
 
1769
        default:
 
1770
            ssnfunc = NULL;
 
1771
    }
 
1772
 
 
1773
    while(!done && ((result = fmap_readn(map, buf, pos, 8191)) > 0)) {
 
1774
        pos += result;
 
1775
        if((cc_count += ccfunc((const unsigned char *)buf, result)) >= ctx->engine->min_cc_count)
 
1776
            done = 1;
 
1777
 
 
1778
        if(ssnfunc && ((ssn_count += ssnfunc((const unsigned char *)buf, result)) >= ctx->engine->min_ssn_count))
 
1779
            done = 1;
 
1780
    }
 
1781
 
 
1782
    if(cc_count != 0 && cc_count >= ctx->engine->min_cc_count) {
 
1783
        cli_dbgmsg("cli_scan_structured: %u credit card numbers detected\n", cc_count);
 
1784
        cli_append_virus(ctx,"Heuristics.Structured.CreditCardNumber");
 
1785
        if (SCAN_ALL)
 
1786
            viruses_found++;
 
1787
        else
 
1788
            return CL_VIRUS;
 
1789
    }
 
1790
 
 
1791
    if(ssn_count != 0 && ssn_count >= ctx->engine->min_ssn_count) {
 
1792
        cli_dbgmsg("cli_scan_structured: %u social security numbers detected\n", ssn_count);
 
1793
        cli_append_virus(ctx,"Heuristics.Structured.SSN");
 
1794
        if (SCAN_ALL)
 
1795
            viruses_found++;
 
1796
        else
 
1797
            return CL_VIRUS;
 
1798
    }
 
1799
 
 
1800
    if (SCAN_ALL && viruses_found)
 
1801
        return CL_VIRUS;
 
1802
    return CL_CLEAN;
 
1803
}
 
1804
 
 
1805
static int cli_scanembpe(cli_ctx *ctx, off_t offset)
 
1806
{
 
1807
        int fd, bytes, ret = CL_CLEAN;
 
1808
        unsigned long int size = 0, todo;
 
1809
        const char *buff;
 
1810
        char *tmpname;
 
1811
        fmap_t *map = *ctx->fmap;
 
1812
        unsigned int corrupted_input;
 
1813
 
 
1814
    tmpname = cli_gentemp(ctx->engine->tmpdir);
 
1815
    if(!tmpname)
 
1816
        return CL_EMEM;
 
1817
 
 
1818
    if((fd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
 
1819
        cli_errmsg("cli_scanembpe: Can't create file %s\n", tmpname);
 
1820
        free(tmpname);
 
1821
        return CL_ECREAT;
 
1822
    }
 
1823
 
 
1824
    todo = map->len - offset;
 
1825
    while(1) {
 
1826
        bytes = MIN(todo, map->pgsz);
 
1827
        if(!bytes)
 
1828
            break;
 
1829
 
 
1830
        if(!(buff = fmap_need_off_once(map, offset + size, bytes))) {
 
1831
            close(fd);
 
1832
            if(!ctx->engine->keeptmp) {
 
1833
                if (cli_unlink(tmpname)) {
 
1834
                    free(tmpname);
 
1835
                    return CL_EUNLINK;
 
1836
                }
 
1837
            }
 
1838
            free(tmpname);
 
1839
            return CL_EREAD;
 
1840
        }
 
1841
        size += bytes;
 
1842
        todo -= bytes;
 
1843
 
 
1844
        if(cli_checklimits("cli_scanembpe", ctx, size, 0, 0)!=CL_CLEAN)
 
1845
            break;
 
1846
 
 
1847
        if(cli_writen(fd, buff, bytes) != bytes) {
 
1848
            cli_dbgmsg("cli_scanembpe: Can't write to temporary file\n");
 
1849
            close(fd);
 
1850
            if(!ctx->engine->keeptmp) {
 
1851
                if (cli_unlink(tmpname)) {
 
1852
                    free(tmpname);
 
1853
                    return CL_EUNLINK;
 
1854
                }
 
1855
            }
 
1856
            free(tmpname);
 
1857
            return CL_EWRITE;
 
1858
        }
 
1859
    }
 
1860
 
 
1861
    ctx->recursion++;
 
1862
    corrupted_input = ctx->corrupted_input;
 
1863
    ctx->corrupted_input = 1;
 
1864
    ret = cli_magic_scandesc(fd, ctx);
 
1865
    ctx->corrupted_input = corrupted_input;
 
1866
    if(ret == CL_VIRUS) {
 
1867
        cli_dbgmsg("cli_scanembpe: Infected with %s\n", cli_get_last_virus(ctx));
 
1868
        close(fd);
 
1869
        if(!ctx->engine->keeptmp) {
 
1870
            if (cli_unlink(tmpname)) {
 
1871
                free(tmpname);
 
1872
                return CL_EUNLINK;
 
1873
            }
 
1874
        }
 
1875
        free(tmpname);  
 
1876
        return CL_VIRUS;
 
1877
    }
 
1878
    ctx->recursion--;
 
1879
 
 
1880
    close(fd);
 
1881
    if(!ctx->engine->keeptmp) {
 
1882
        if (cli_unlink(tmpname)) {
 
1883
            free(tmpname);
 
1884
            return CL_EUNLINK;
 
1885
        }
 
1886
    }
 
1887
    free(tmpname);
 
1888
 
 
1889
    /* intentionally ignore possible errors from cli_magic_scandesc */
 
1890
    return CL_CLEAN;
 
1891
}
 
1892
 
 
1893
 
 
1894
#if defined(_WIN32) || defined(C_LINUX)
 
1895
#define PERF_MEASURE
 
1896
#endif
 
1897
 
 
1898
#ifdef PERF_MEASURE
 
1899
 
 
1900
static struct {
 
1901
    enum perfev id;
 
1902
    const char *name;
 
1903
    enum ev_type type;
 
1904
} perf_events[] = {
 
1905
    {PERFT_SCAN, "full scan", ev_time},
 
1906
    {PERFT_PRECB, "prescan cb", ev_time},
 
1907
    {PERFT_POSTCB, "postscan cb", ev_time},
 
1908
    {PERFT_CACHE, "cache", ev_time},
 
1909
    {PERFT_FT, "filetype", ev_time},
 
1910
    {PERFT_CONTAINER, "container", ev_time},
 
1911
    {PERFT_SCRIPT, "script", ev_time},
 
1912
    {PERFT_PE, "pe", ev_time},
 
1913
    {PERFT_RAW, "raw", ev_time},
 
1914
    {PERFT_RAWTYPENO, "raw container", ev_time},
 
1915
    {PERFT_MAP, "map", ev_time},
 
1916
    {PERFT_BYTECODE,"bytecode", ev_time},
 
1917
    {PERFT_KTIME,"kernel", ev_int},
 
1918
    {PERFT_UTIME,"user", ev_int}
 
1919
};
 
1920
 
 
1921
static void get_thread_times(uint64_t *kt, uint64_t *ut)
 
1922
{
 
1923
#ifdef _WIN32
 
1924
    FILETIME c,e,k,u;
 
1925
    ULARGE_INTEGER kl,ul;
 
1926
    if (!GetThreadTimes(GetCurrentThread(), &c, &e, &k, &u)) {
 
1927
        *kt = *ut = 0;
 
1928
        return;
 
1929
    }
 
1930
    kl.LowPart = k.dwLowDateTime;
 
1931
    kl.HighPart = k.dwHighDateTime;
 
1932
    ul.LowPart = u.dwLowDateTime;
 
1933
    ul.HighPart = u.dwHighDateTime;
 
1934
    *kt = kl.QuadPart / 10;
 
1935
    *ut = ul.QuadPart / 10;
 
1936
#else
 
1937
    struct tms tbuf;
 
1938
    if (times(&tbuf) != -1) {
 
1939
        clock_t tck = sysconf(_SC_CLK_TCK);
 
1940
        *kt = ((uint64_t)1000000)*tbuf.tms_stime / tck;
 
1941
        *ut = ((uint64_t)1000000)*tbuf.tms_utime / tck;
 
1942
    } else {
 
1943
        *kt = *ut = 0;
 
1944
    }
 
1945
#endif
 
1946
}
 
1947
 
 
1948
static inline void perf_init(cli_ctx *ctx)
 
1949
{
 
1950
    uint64_t kt,ut;
 
1951
    unsigned i;
 
1952
 
 
1953
    if (!(ctx->options & CL_SCAN_PERFORMANCE_INFO))
 
1954
        return;
 
1955
 
 
1956
    ctx->perf = cli_events_new(PERFT_LAST);
 
1957
    for (i=0;i<sizeof(perf_events)/sizeof(perf_events[0]);i++) {
 
1958
        if (cli_event_define(ctx->perf, perf_events[i].id, perf_events[i].name,
 
1959
                             perf_events[i].type, multiple_sum) == -1)
 
1960
            continue;
 
1961
    }
 
1962
    cli_event_time_start(ctx->perf, PERFT_SCAN);
 
1963
    get_thread_times(&kt, &ut);
 
1964
    cli_event_int(ctx->perf, PERFT_KTIME, -kt);
 
1965
    cli_event_int(ctx->perf, PERFT_UTIME, -ut);
 
1966
}
 
1967
 
 
1968
static inline void perf_done(cli_ctx* ctx)
 
1969
{
 
1970
    char timestr[512];
 
1971
    char *p;
 
1972
    unsigned i;
 
1973
    uint64_t kt,ut;
 
1974
    char *pend;
 
1975
    cli_events_t *perf = ctx->perf;
 
1976
 
 
1977
    if (!perf)
 
1978
        return;
 
1979
 
 
1980
    p = timestr;
 
1981
    pend = timestr + sizeof(timestr) - 1;
 
1982
    *pend = 0;
 
1983
 
 
1984
    cli_event_time_stop(perf, PERFT_SCAN);
 
1985
    get_thread_times(&kt, &ut);
 
1986
    cli_event_int(perf, PERFT_KTIME, kt);
 
1987
    cli_event_int(perf, PERFT_UTIME, ut);
 
1988
 
 
1989
    for (i=0;i<sizeof(perf_events)/sizeof(perf_events[0]);i++) {
 
1990
        union ev_val val;
 
1991
        unsigned count;
 
1992
 
 
1993
        cli_event_get(perf, perf_events[i].id, &val, &count);
 
1994
        if (p < pend)
 
1995
            p += snprintf(p, pend - p, "%s: %d.%03ums, ", perf_events[i].name,
 
1996
                          (signed)(val.v_int / 1000),
 
1997
                          (unsigned)(val.v_int % 1000));
 
1998
    }
 
1999
    *p = 0;
 
2000
    cli_infomsg(ctx, "performance: %s\n", timestr);
 
2001
 
 
2002
 
 
2003
    cli_events_free(perf);
 
2004
    ctx->perf = NULL;
 
2005
}
 
2006
 
 
2007
static inline void perf_start(cli_ctx* ctx, int id)
 
2008
{
 
2009
    cli_event_time_start(ctx->perf, id);
 
2010
}
 
2011
 
 
2012
static inline void perf_stop(cli_ctx* ctx, int id)
 
2013
{
 
2014
    cli_event_time_stop(ctx->perf, id);
 
2015
}
 
2016
 
 
2017
static inline void perf_nested_start(cli_ctx* ctx, int id, int nestedid)
 
2018
{
 
2019
    cli_event_time_nested_start(ctx->perf, id, nestedid);
 
2020
}
 
2021
 
 
2022
static inline void perf_nested_stop(cli_ctx* ctx, int id, int nestedid)
 
2023
{
 
2024
    cli_event_time_nested_stop(ctx->perf, id, nestedid);
 
2025
}
 
2026
 
 
2027
 
 
2028
#else
 
2029
static inline void perf_init(cli_ctx* ctx) { UNUSEDPARAM(ctx); }
 
2030
static inline void perf_start(cli_ctx* ctx, int id){ UNUSEDPARAM(ctx); UNUSEDPARAM(id); }
 
2031
static inline void perf_stop(cli_ctx* ctx, int id){ UNUSEDPARAM(ctx); UNUSEDPARAM(id); }
 
2032
static inline void perf_nested_start(cli_ctx* ctx, int id, int nestedid){ UNUSEDPARAM(ctx); UNUSEDPARAM(id); UNUSEDPARAM(nestedid); }
 
2033
static inline void perf_nested_stop(cli_ctx* ctx, int id, int nestedid){ UNUSEDPARAM(ctx); UNUSEDPARAM(id); UNUSEDPARAM(nestedid); }
 
2034
static inline void perf_done(cli_ctx* ctx){ UNUSEDPARAM(ctx); }
 
2035
#endif
 
2036
 
 
2037
 
 
2038
static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_t *dettype, unsigned char *refhash)
 
2039
{
 
2040
        int ret = CL_CLEAN, nret = CL_CLEAN;
 
2041
        struct cli_matched_type *ftoffset = NULL, *fpt;
 
2042
        uint32_t lastrar;
 
2043
        struct cli_exe_info peinfo;
 
2044
        unsigned int acmode = AC_SCAN_VIR, break_loop = 0;
 
2045
        fmap_t *map = *ctx->fmap;
 
2046
        cli_file_t current_container_type = ctx->container_type;
 
2047
        size_t current_container_size = ctx->container_size;
 
2048
 
 
2049
 
 
2050
    if(ctx->engine->maxreclevel && ctx->recursion >= ctx->engine->maxreclevel)
 
2051
        return CL_EMAXREC;
 
2052
 
 
2053
    perf_start(ctx, PERFT_RAW);
 
2054
    if(typercg)
 
2055
        acmode |= AC_SCAN_FT;
 
2056
 
 
2057
    ret = cli_fmap_scandesc(ctx, type == CL_TYPE_TEXT_ASCII ? 0 : type, 0, &ftoffset, acmode, NULL, refhash);
 
2058
    perf_stop(ctx, PERFT_RAW);
 
2059
 
 
2060
    if(ret >= CL_TYPENO) {
 
2061
        perf_nested_start(ctx, PERFT_RAWTYPENO, PERFT_SCAN);
 
2062
        ctx->recursion++;
 
2063
        lastrar = 0xdeadbeef;
 
2064
        fpt = ftoffset;
 
2065
 
 
2066
        while(fpt) {
 
2067
            if(fpt->offset) switch(fpt->type) {
 
2068
                case CL_TYPE_XDP:
 
2069
                    ret = cli_scanxdp(ctx);
 
2070
                    break;
 
2071
                case CL_TYPE_RARSFX:
 
2072
                    if(type != CL_TYPE_RAR && have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR)) {
 
2073
                        char *tmpname = NULL;
 
2074
                        int tmpfd = fmap_fd(map);
 
2075
                        ctx->container_type = CL_TYPE_RAR;
 
2076
                        ctx->container_size = map->len - fpt->offset; /* not precise */
 
2077
                        cli_dbgmsg("RAR/RAR-SFX signature found at %u\n", (unsigned int) fpt->offset);
 
2078
                        /* if map is not file-backed, have to dump to file for scanrar */
 
2079
                        if(tmpfd == -1) {
 
2080
                            nret = fmap_dump_to_file(map, ctx->engine->tmpdir, &tmpname, &tmpfd);
 
2081
                            if(nret != CL_SUCCESS) {
 
2082
                                cli_dbgmsg("cli_scanraw: failed to generate temporary file.\n");
 
2083
                                ret = nret;
 
2084
                                break_loop = 1;
 
2085
                                break;
 
2086
                            }
 
2087
                        }
 
2088
                        /* scan existing file */
 
2089
                        nret = cli_scanrar(tmpfd, ctx, fpt->offset, &lastrar);
 
2090
                        /* if dumped tempfile, need to cleanup */
 
2091
                        if(tmpname) {
 
2092
                            close(tmpfd);
 
2093
                            if(!ctx->engine->keeptmp) {
 
2094
                                if (cli_unlink(tmpname)) {
 
2095
                                    ret = nret = CL_EUNLINK;
 
2096
                                    break_loop = 1;
 
2097
                                }
 
2098
                            }
 
2099
                            free(tmpname);
 
2100
                        }
 
2101
                    }
 
2102
                    break;
 
2103
 
 
2104
                case CL_TYPE_ZIPSFX:
 
2105
                    if(type != CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP)) {
 
2106
                        ctx->container_type = CL_TYPE_ZIP;
 
2107
                        ctx->container_size = map->len - fpt->offset; /* not precise */
 
2108
                        cli_dbgmsg("ZIP/ZIP-SFX signature found at %u\n", (unsigned int) fpt->offset);
 
2109
                        nret = cli_unzip_single(ctx, fpt->offset);
 
2110
                    }
 
2111
                    break;
 
2112
 
 
2113
                case CL_TYPE_CABSFX:
 
2114
                    if(type != CL_TYPE_MSCAB && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB)) {
 
2115
                        ctx->container_type = CL_TYPE_MSCAB;
 
2116
                        ctx->container_size = map->len - fpt->offset; /* not precise */
 
2117
                        cli_dbgmsg("CAB/CAB-SFX signature found at %u\n", (unsigned int) fpt->offset);
 
2118
                        nret = cli_scanmscab(ctx, fpt->offset);
 
2119
                    }
 
2120
                    break;
 
2121
 
 
2122
                case CL_TYPE_ARJSFX:
 
2123
                    if(type != CL_TYPE_ARJ && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ)) {
 
2124
                        ctx->container_type = CL_TYPE_ARJ;
 
2125
                        ctx->container_size = map->len - fpt->offset; /* not precise */
 
2126
                        cli_dbgmsg("ARJ-SFX signature found at %u\n", (unsigned int) fpt->offset);
 
2127
                        nret = cli_scanarj(ctx, fpt->offset, &lastrar);
 
2128
                    }
 
2129
                    break;
 
2130
 
 
2131
                case CL_TYPE_7ZSFX:
 
2132
                    if(type != CL_TYPE_7Z && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z)) {
 
2133
                        ctx->container_type = CL_TYPE_7Z;
 
2134
                        ctx->container_size = map->len - fpt->offset; /* not precise */
 
2135
                        cli_dbgmsg("7Zip-SFX signature found at %u\n", (unsigned int) fpt->offset);
 
2136
                        nret = cli_7unz(ctx, fpt->offset);
 
2137
                    }
 
2138
                    break;
 
2139
 
 
2140
                case CL_TYPE_ISO9660:
 
2141
                    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ISO9660)) {
 
2142
                        ctx->container_type = CL_TYPE_ISO9660;
 
2143
                        ctx->container_size = map->len - fpt->offset; /* not precise */
 
2144
                        cli_dbgmsg("ISO9660 signature found at %u\n", (unsigned int) fpt->offset);
 
2145
                        nret = cli_scaniso(ctx, fpt->offset);
 
2146
                    }
 
2147
                    break;
 
2148
 
 
2149
                case CL_TYPE_NULSFT:
 
2150
                    if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_NSIS) &&
 
2151
                       fpt->offset > 4) {
 
2152
                        ctx->container_type = CL_TYPE_NULSFT;
 
2153
                        ctx->container_size = map->len - fpt->offset; /* not precise */
 
2154
                        cli_dbgmsg("NSIS signature found at %u\n", (unsigned int) fpt->offset-4);
 
2155
                        nret = cli_scannulsft(ctx, fpt->offset - 4);
 
2156
                    }
 
2157
                    break;
 
2158
 
 
2159
                case CL_TYPE_AUTOIT:
 
2160
                    if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_AUTOIT)) {
 
2161
                        ctx->container_type = CL_TYPE_AUTOIT;
 
2162
                        ctx->container_size = map->len - fpt->offset; /* not precise */
 
2163
                        cli_dbgmsg("AUTOIT signature found at %u\n", (unsigned int) fpt->offset);
 
2164
                        nret = cli_scanautoit(ctx, fpt->offset + 23);
 
2165
                    }
 
2166
                    break;
 
2167
 
 
2168
                case CL_TYPE_ISHIELD_MSI:
 
2169
                    if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_ISHIELD)) {
 
2170
                        ctx->container_type = CL_TYPE_AUTOIT;
 
2171
                        ctx->container_size = map->len - fpt->offset; /* not precise */
 
2172
                        cli_dbgmsg("ISHIELD-MSI signature found at %u\n", (unsigned int) fpt->offset);
 
2173
                        nret = cli_scanishield_msi(ctx, fpt->offset + 14);
 
2174
                    }
 
2175
                    break;
 
2176
 
 
2177
                case CL_TYPE_DMG:
 
2178
                    if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_DMG)) {
 
2179
                        ctx->container_type = CL_TYPE_DMG;
 
2180
                        nret = cli_scandmg(ctx);
 
2181
                        cli_dbgmsg("DMG signature found at %u\n", (unsigned int) fpt->offset);
 
2182
                    }
 
2183
                    break;
 
2184
 
 
2185
                case CL_TYPE_MBR:
 
2186
                    {
 
2187
                        int iret = cli_mbr_check2(ctx, 0);
 
2188
                        if (iret == CL_TYPE_GPT) {
 
2189
                            cli_dbgmsg("Recognized GUID Partition Table file\n");
 
2190
                            ctx->container_type = CL_TYPE_GPT;
 
2191
                            nret = cli_scangpt(ctx, 0);
 
2192
                            cli_dbgmsg("GPT signature found at %u\n", (unsigned int) fpt->offset);
 
2193
                        }
 
2194
                        else if (iret == CL_CLEAN) {
 
2195
                            ctx->container_type = CL_TYPE_MBR;
 
2196
                            nret = cli_scanmbr(ctx, 0);
 
2197
                            cli_dbgmsg("MBR signature found at %u\n", (unsigned int) fpt->offset);
 
2198
                        }
 
2199
                    }
 
2200
                    break;
 
2201
 
 
2202
                case CL_TYPE_PDF:
 
2203
                    if(type != CL_TYPE_PDF && SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF)) {
 
2204
                        ctx->container_type = CL_TYPE_PDF;
 
2205
                        ctx->container_size = map->len - fpt->offset; /* not precise */
 
2206
                        cli_dbgmsg("PDF signature found at %u\n", (unsigned int) fpt->offset);
 
2207
                        nret = cli_scanpdf(ctx, fpt->offset);
 
2208
                    }
 
2209
                    break;
 
2210
 
 
2211
                case CL_TYPE_MSEXE:
 
2212
                    if(SCAN_PE && (type == CL_TYPE_MSEXE || type == CL_TYPE_ZIP || type == CL_TYPE_MSOLE2)
 
2213
                       && ctx->dconf->pe) {
 
2214
                        uint64_t curr_len = map->len;
 
2215
                        /* CL_ENGINE_MAX_EMBEDDED_PE */
 
2216
                        if(curr_len > ctx->engine->maxembeddedpe) {
 
2217
                            cli_dbgmsg("cli_scanraw: MaxEmbeddedPE exceeded\n");
 
2218
                            break;
 
2219
                        }
 
2220
                        ctx->container_type = CL_TYPE_MSEXE; /* PE is a container for another executable here */
 
2221
                        ctx->container_size = map->len - fpt->offset; /* not precise */
 
2222
                        memset(&peinfo, 0, sizeof(struct cli_exe_info));
 
2223
                        peinfo.offset = fpt->offset;
 
2224
                        if(cli_peheader(map, &peinfo) == 0) {
 
2225
                            cli_dbgmsg("*** Detected embedded PE file at %u ***\n", 
 
2226
                                       (unsigned int) fpt->offset);
 
2227
                            if(peinfo.section)
 
2228
                                free(peinfo.section);
 
2229
                            cli_hashset_destroy(&peinfo.vinfo);
 
2230
 
 
2231
                            nret = cli_scanembpe(ctx, fpt->offset);
 
2232
                            break_loop = 1; /* we can stop here and other
 
2233
                                             * embedded executables will
 
2234
                                             * be found recursively
 
2235
                                             * through the above call
 
2236
                                             */
 
2237
                        }
 
2238
                    }
 
2239
                    break;
 
2240
 
 
2241
                default:
 
2242
                    cli_warnmsg("cli_scanraw: Type %u not handled in fpt loop\n", fpt->type);
 
2243
                }
 
2244
 
 
2245
            if(nret == CL_VIRUS || break_loop)
 
2246
                break;
 
2247
 
 
2248
            fpt = fpt->next;
 
2249
        }
 
2250
        ctx->container_type = current_container_type;
 
2251
        ctx->container_size = current_container_size;
 
2252
        
 
2253
        if(nret != CL_VIRUS) switch(ret) {
 
2254
            case CL_TYPE_HTML:
 
2255
                if (SCAN_HTML && (type == CL_TYPE_TEXT_ASCII || type == CL_TYPE_GRAPHICS) &&
 
2256
                    (DCONF_DOC & DOC_CONF_HTML)) {
 
2257
                    *dettype = CL_TYPE_HTML;
 
2258
                    nret = cli_scanhtml(ctx);
 
2259
                }
 
2260
                break;
 
2261
 
 
2262
            case CL_TYPE_MAIL:
 
2263
                ctx->container_type = CL_TYPE_MAIL;
 
2264
                ctx->container_size = map->len;
 
2265
                if(SCAN_MAIL && type == CL_TYPE_TEXT_ASCII && (DCONF_MAIL & MAIL_CONF_MBOX)) {
 
2266
                    *dettype = CL_TYPE_MAIL;
 
2267
                    nret = cli_scanmail(ctx);
 
2268
                }
 
2269
                ctx->container_type = current_container_type;
 
2270
                ctx->container_size = current_container_size;
 
2271
                break;
 
2272
 
 
2273
            default:
 
2274
                break;
 
2275
        }
 
2276
        perf_nested_stop(ctx, PERFT_RAWTYPENO, PERFT_SCAN);
 
2277
        ctx->recursion--;
 
2278
        ret = nret;
 
2279
    }
 
2280
 
 
2281
    while(ftoffset) {
 
2282
        fpt = ftoffset;
 
2283
        ftoffset = ftoffset->next;
 
2284
        free(fpt);
 
2285
    }
 
2286
 
 
2287
    if(ret == CL_VIRUS)
 
2288
        cli_dbgmsg("%s found\n", cli_get_last_virus(ctx));
 
2289
 
 
2290
    return ret;
 
2291
}
 
2292
 
 
2293
 
 
2294
static void emax_reached(cli_ctx *ctx) {
 
2295
    fmap_t **ctx_fmap = ctx->fmap;
 
2296
    if (!ctx_fmap)
 
2297
        return;
 
2298
    while(*ctx_fmap) {
 
2299
        fmap_t *map = *ctx_fmap;
 
2300
        map->dont_cache_flag = 1;
 
2301
        ctx_fmap--;
 
2302
    }
 
2303
    cli_dbgmsg("emax_reached: marked parents as non cacheable\n");
 
2304
}
 
2305
 
 
2306
#define LINESTR(x) #x
 
2307
#define LINESTR2(x) LINESTR(x)
 
2308
#define __AT__  " at line "LINESTR2(__LINE__)
 
2309
 
 
2310
#define early_ret_from_magicscan(retcode)                               \
 
2311
    do {                                                                \
 
2312
        cli_dbgmsg("cli_magic_scandesc: returning %d %s (no post, no cache)\n", retcode, __AT__); \
 
2313
        return retcode;                                                 \
 
2314
    } while(0)
 
2315
 
 
2316
static int magic_scandesc_cleanup(cli_ctx *ctx, cli_file_t type, unsigned char *hash, size_t hashed_size, int cache_clean, int retcode, void *parent_property)
 
2317
{
 
2318
#if HAVE_JSON
 
2319
    ctx->wrkproperty = (struct json_object *)(parent_property);
 
2320
#else
 
2321
    UNUSEDPARAM(parent_property);
 
2322
#endif
 
2323
 
 
2324
    UNUSEDPARAM(type);
 
2325
 
 
2326
    cli_dbgmsg("cli_magic_scandesc: returning %d %s\n", retcode, __AT__);
 
2327
    if(ctx->engine->cb_post_scan) {
 
2328
        perf_start(ctx, PERFT_POSTCB);
 
2329
        switch(ctx->engine->cb_post_scan(fmap_fd(*ctx->fmap), retcode, retcode == CL_VIRUS ? cli_get_last_virus(ctx) : NULL, ctx->cb_ctx)) {
 
2330
        case CL_BREAK:
 
2331
            cli_dbgmsg("cli_magic_scandesc: file whitelisted by post_scan callback\n");
 
2332
            perf_stop(ctx, PERFT_POSTCB);
 
2333
            return CL_CLEAN;
 
2334
        case CL_VIRUS:
 
2335
            cli_dbgmsg("cli_magic_scandesc: file blacklisted by post_scan callback\n");
 
2336
            cli_append_virus(ctx, "Detected.By.Callback");
 
2337
            perf_stop(ctx, PERFT_POSTCB);
 
2338
            if (retcode != CL_VIRUS)
 
2339
                return cli_checkfp(hash, hashed_size, ctx);
 
2340
            return CL_VIRUS;
 
2341
        case CL_CLEAN:
 
2342
            break;
 
2343
        default:
 
2344
            cli_warnmsg("cli_magic_scandesc: ignoring bad return code from post_scan callback\n");
 
2345
        }
 
2346
        perf_stop(ctx, PERFT_POSTCB);
 
2347
    }
 
2348
    if (retcode == CL_CLEAN && cache_clean) {
 
2349
        perf_start(ctx, PERFT_CACHE);
 
2350
        cache_add(hash, hashed_size, ctx);
 
2351
        perf_stop(ctx, PERFT_CACHE);
 
2352
    }
 
2353
    return retcode;
 
2354
}
 
2355
 
 
2356
static int dispatch_prescan(clcb_pre_scan cb, cli_ctx *ctx, const char *filetype, bitset_t *old_hook_lsig_matches, void *parent_property, unsigned char *hash, size_t hashed_size, int *run_cleanup)
 
2357
{
 
2358
    int res=CL_CLEAN;
 
2359
 
 
2360
    UNUSEDPARAM(parent_property);
 
2361
    UNUSEDPARAM(hash);
 
2362
    UNUSEDPARAM(hashed_size);
 
2363
 
 
2364
    *run_cleanup = 0;
 
2365
 
 
2366
    if(cb) {
 
2367
        perf_start(ctx, PERFT_PRECB);
 
2368
        switch(cb(fmap_fd(*ctx->fmap), filetype, ctx->cb_ctx)) {
 
2369
        case CL_BREAK:
 
2370
            cli_dbgmsg("cli_magic_scandesc: file whitelisted by callback\n");
 
2371
            perf_stop(ctx, PERFT_PRECB);
 
2372
            ctx->hook_lsig_matches = old_hook_lsig_matches;
 
2373
            /* returns CL_CLEAN */
 
2374
            *run_cleanup = 1;
 
2375
            break;
 
2376
        case CL_VIRUS:
 
2377
            cli_dbgmsg("cli_magic_scandesc: file blacklisted by callback\n");
 
2378
            cli_append_virus(ctx, "Detected.By.Callback");
 
2379
            perf_stop(ctx, PERFT_PRECB);
 
2380
            ctx->hook_lsig_matches = old_hook_lsig_matches;
 
2381
            *run_cleanup = 1;
 
2382
            res = CL_VIRUS;
 
2383
            break;
 
2384
        case CL_CLEAN:
 
2385
            break;
 
2386
        default:
 
2387
            cli_warnmsg("cli_magic_scandesc: ignoring bad return code from callback\n");
 
2388
        }
 
2389
 
 
2390
        perf_stop(ctx, PERFT_PRECB);
 
2391
    }
 
2392
 
 
2393
    return res;
 
2394
}
 
2395
 
 
2396
static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
 
2397
{
 
2398
        int ret = CL_CLEAN;
 
2399
        cli_file_t dettype = 0;
 
2400
        uint8_t typercg = 1;
 
2401
        cli_file_t current_container_type = ctx->container_type;
 
2402
        size_t current_container_size = ctx->container_size, hashed_size;
 
2403
        unsigned char hash[16];
 
2404
        bitset_t *old_hook_lsig_matches;
 
2405
        const char *filetype;
 
2406
        int cache_clean = 0, res;
 
2407
    int run_cleanup = 0;
 
2408
#if HAVE_JSON
 
2409
        struct json_object *parent_property = NULL;
 
2410
#else
 
2411
    void *parent_property = NULL;
 
2412
#endif
 
2413
 
 
2414
    if(!ctx->engine) {
 
2415
        cli_errmsg("CRITICAL: engine == NULL\n");
 
2416
        early_ret_from_magicscan(CL_ENULLARG);
 
2417
    }
 
2418
 
 
2419
    if(!(ctx->engine->dboptions & CL_DB_COMPILED)) {
 
2420
        cli_errmsg("CRITICAL: engine not compiled\n");
 
2421
        early_ret_from_magicscan(CL_EMALFDB);
 
2422
    }
 
2423
 
 
2424
    if(ctx->engine->maxreclevel && ctx->recursion > ctx->engine->maxreclevel) {
 
2425
        cli_dbgmsg("cli_magic_scandesc: Archive recursion limit exceeded (%u, max: %u)\n", ctx->recursion, ctx->engine->maxreclevel);
 
2426
        emax_reached(ctx);
 
2427
        early_ret_from_magicscan(CL_CLEAN);
 
2428
    }
 
2429
 
 
2430
    if(cli_updatelimits(ctx, (*ctx->fmap)->len)!=CL_CLEAN) {
 
2431
        emax_reached(ctx);
 
2432
        early_ret_from_magicscan(CL_CLEAN);
 
2433
    }
 
2434
    old_hook_lsig_matches = ctx->hook_lsig_matches;
 
2435
    if(type == CL_TYPE_PART_ANY) {
 
2436
        typercg = 0;
 
2437
    }
 
2438
 
 
2439
    perf_start(ctx, PERFT_FT);
 
2440
    if((type == CL_TYPE_ANY) || type == CL_TYPE_PART_ANY) {
 
2441
        type = cli_filetype2(*ctx->fmap, ctx->engine, type);
 
2442
    }
 
2443
    perf_stop(ctx, PERFT_FT);
 
2444
    if(type == CL_TYPE_ERROR) {
 
2445
        cli_dbgmsg("cli_magic_scandesc: cli_filetype2 returned CL_TYPE_ERROR\n");
 
2446
        early_ret_from_magicscan(CL_EREAD);
 
2447
    }
 
2448
    filetype = cli_ftname(type);
 
2449
 
 
2450
#if HAVE_JSON
 
2451
    if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
 
2452
        json_object *arrobj;
 
2453
 
 
2454
        if (NULL == ctx->properties) {
 
2455
            if (type == CL_TYPE_PDF ||   /* file types we collect properties about */
 
2456
                type == CL_TYPE_MSOLE2 ||
 
2457
                type == CL_TYPE_MSEXE ||
 
2458
                //type == CL_TYPE_ZIP ||
 
2459
                type == CL_TYPE_OOXML_WORD ||
 
2460
                type == CL_TYPE_OOXML_PPT ||
 
2461
                type == CL_TYPE_OOXML_XL) { 
 
2462
                ctx->properties = json_object_new_object();
 
2463
                if (NULL == ctx->properties) {
 
2464
                    cli_errmsg("magic_scandesc: no memory for json properties object\n");
 
2465
                    early_ret_from_magicscan(CL_EMEM);       
 
2466
                }
 
2467
                ctx->wrkproperty = ctx->properties;
 
2468
                ret = cli_jsonstr(ctx->properties, "Magic", "CLAMJSONv0");
 
2469
                if (ret != CL_SUCCESS) {
 
2470
                    early_ret_from_magicscan(ret);
 
2471
                }
 
2472
                ret = cli_jsonstr(ctx->properties, "RootFileType", filetype);
 
2473
                if (ret != CL_SUCCESS) {
 
2474
                    early_ret_from_magicscan(ret);
 
2475
                }
 
2476
            } else { /* turn off property collection flag for file types we don't care about */
 
2477
                ctx->options &= ~CL_SCAN_FILE_PROPERTIES;       
 
2478
            }
 
2479
        }
 
2480
        else {
 
2481
            parent_property = ctx->wrkproperty;
 
2482
            if (!json_object_object_get_ex(parent_property, "ContainedObjects", &arrobj)) {
 
2483
                arrobj = json_object_new_array();
 
2484
                if (NULL == arrobj) {
 
2485
                    cli_errmsg("magic_scandesc: no memory for json properties object\n");
 
2486
                    early_ret_from_magicscan(CL_EMEM);
 
2487
                }
 
2488
                json_object_object_add(parent_property, "ContainedObjects", arrobj);
 
2489
            }
 
2490
            ctx->wrkproperty = json_object_new_object();
 
2491
            if (NULL == ctx->wrkproperty) {
 
2492
                cli_errmsg("magic_scandesc: no memory for json properties object\n");
 
2493
                early_ret_from_magicscan(CL_EMEM);
 
2494
            }
 
2495
            json_object_array_add(arrobj, ctx->wrkproperty);
 
2496
        }
 
2497
    }
 
2498
 
 
2499
    if (ctx->options & CL_SCAN_FILE_PROPERTIES) { /* separated for cases json is not tracked */
 
2500
        ret = cli_jsonstr(ctx->wrkproperty, "FileType", filetype);
 
2501
        if (ret != CL_SUCCESS) {
 
2502
            early_ret_from_magicscan(ret);
 
2503
        }
 
2504
        ret = cli_jsonint(ctx->wrkproperty, "FileSize", (*ctx->fmap)->len);
 
2505
        if (ret != CL_SUCCESS) {
 
2506
            early_ret_from_magicscan(ret);
 
2507
        }
 
2508
    }
 
2509
#endif
 
2510
 
 
2511
    hashed_size = 0;
 
2512
    ret = dispatch_prescan(ctx->engine->cb_pre_cache, ctx, filetype, old_hook_lsig_matches, parent_property, hash, hashed_size, &run_cleanup);
 
2513
    if (run_cleanup) {
 
2514
        if (ret == CL_VIRUS)
 
2515
            return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, cli_checkfp(hash, hashed_size, ctx), parent_property);
 
2516
        else
 
2517
            return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_CLEAN, parent_property);
 
2518
    }
 
2519
 
 
2520
    perf_start(ctx, PERFT_CACHE);
 
2521
    res = cache_check(hash, ctx);
 
2522
 
 
2523
#if HAVE_JSON
 
2524
    if (SCAN_PROPERTIES /* ctx.options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL */) {
 
2525
        char hashstr[33];
 
2526
        snprintf(hashstr, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]);
 
2527
 
 
2528
        ret = cli_jsonstr(ctx->wrkproperty, "FileMD5", hashstr);
 
2529
        if (ret != CL_SUCCESS) {
 
2530
            early_ret_from_magicscan(ret);
 
2531
        }
 
2532
    }
 
2533
#endif
 
2534
 
 
2535
    if(res != CL_VIRUS) {
 
2536
        perf_stop(ctx, PERFT_CACHE);
 
2537
#if HAVE_JSON
 
2538
        ctx->wrkproperty = parent_property;
 
2539
#endif
 
2540
        early_ret_from_magicscan(res);
 
2541
    }
 
2542
 
 
2543
    perf_stop(ctx, PERFT_CACHE);
 
2544
    hashed_size = (*ctx->fmap)->len;
 
2545
    ctx->hook_lsig_matches = NULL;
 
2546
 
 
2547
    if(!(ctx->options&~CL_SCAN_ALLMATCHES) || (ctx->recursion == ctx->engine->maxreclevel)) { /* raw mode (stdin, etc.) or last level of recursion */
 
2548
        if(ctx->recursion == ctx->engine->maxreclevel)
 
2549
            cli_dbgmsg("cli_magic_scandesc: Hit recursion limit, only scanning raw file\n");
 
2550
        else
 
2551
            cli_dbgmsg("Raw mode: No support for special files\n");
 
2552
 
 
2553
    ret = dispatch_prescan(ctx->engine->cb_pre_scan, ctx, filetype, old_hook_lsig_matches, parent_property, hash, hashed_size, &run_cleanup);
 
2554
    if (run_cleanup) {
 
2555
        if (ret == CL_VIRUS)
 
2556
            return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, cli_checkfp(hash, hashed_size, ctx), parent_property);
 
2557
        else
 
2558
            return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
 
2559
    }
 
2560
        /* ret_from_magicscan can be used below here*/
 
2561
        if((ret = cli_fmap_scandesc(ctx, 0, 0, NULL, AC_SCAN_VIR, NULL, hash)) == CL_VIRUS)
 
2562
            cli_dbgmsg("%s found in descriptor %d\n", cli_get_last_virus(ctx), fmap_fd(*ctx->fmap));
 
2563
        else if(ret == CL_CLEAN) {
 
2564
            if(ctx->recursion != ctx->engine->maxreclevel)
 
2565
                cache_clean = 1; /* Only cache if limits are not reached */
 
2566
            else
 
2567
                emax_reached(ctx);
 
2568
        }
 
2569
 
 
2570
        ctx->hook_lsig_matches = old_hook_lsig_matches;
 
2571
        return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
 
2572
    }
 
2573
 
 
2574
    ret = dispatch_prescan(ctx->engine->cb_pre_scan, ctx, filetype, old_hook_lsig_matches, parent_property, hash, hashed_size, &run_cleanup);
 
2575
    if (run_cleanup) {
 
2576
        if (ret == CL_VIRUS)
 
2577
            return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, cli_checkfp(hash, hashed_size, ctx), parent_property);
 
2578
        else
 
2579
            return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
 
2580
    }
 
2581
    /* ret_from_magicscan can be used below here*/
 
2582
 
 
2583
#ifdef HAVE__INTERNAL__SHA_COLLECT
 
2584
    if(!ctx->sha_collect && type==CL_TYPE_MSEXE) ctx->sha_collect = 1;
 
2585
#endif
 
2586
 
 
2587
    ctx->hook_lsig_matches = cli_bitset_init();
 
2588
    if (!ctx->hook_lsig_matches) {
 
2589
        ctx->hook_lsig_matches = old_hook_lsig_matches;
 
2590
    return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_EMEM, parent_property);
 
2591
    }
 
2592
 
 
2593
    if(type != CL_TYPE_IGNORED && ctx->engine->sdb) {
 
2594
        if((ret = cli_scanraw(ctx, type, 0, &dettype, (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) ? NULL : hash)) == CL_VIRUS) {
 
2595
            ret = cli_checkfp(hash, hashed_size, ctx);
 
2596
            cli_bitset_free(ctx->hook_lsig_matches);
 
2597
            ctx->hook_lsig_matches = old_hook_lsig_matches;
 
2598
        return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
 
2599
        }
 
2600
    }
 
2601
 
 
2602
    ctx->recursion++;
 
2603
    perf_nested_start(ctx, PERFT_CONTAINER, PERFT_SCAN);
 
2604
    ctx->container_size = (*ctx->fmap)->len;
 
2605
    switch(type) {
 
2606
        case CL_TYPE_IGNORED:
 
2607
            break;
 
2608
 
 
2609
    case CL_TYPE_XDP:
 
2610
        ret = cli_scanxdp(ctx);
 
2611
        break;
 
2612
 
 
2613
        case CL_TYPE_RAR:
 
2614
            ctx->container_type = CL_TYPE_RAR;
 
2615
            if(have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR)) {
 
2616
                char *tmpname = NULL;
 
2617
                int desc = fmap_fd(*ctx->fmap);
 
2618
                if (desc == -1) {
 
2619
                    cli_dbgmsg("fmap not backed by file, dumping ...\n");
 
2620
                    ret = fmap_dump_to_file(*ctx->fmap, ctx->engine->tmpdir, &tmpname, &desc);
 
2621
                    if (ret != CL_SUCCESS) {
 
2622
                        cli_dbgmsg("fmap_fd: failed to generate temporary file.\n");
 
2623
                        break;
 
2624
                    }
 
2625
                }
 
2626
                ret = cli_scanrar(desc, ctx, 0, NULL);
 
2627
                if (tmpname) {
 
2628
                    close(desc);
 
2629
                    unlink(tmpname);
 
2630
                    free(tmpname);
 
2631
                }
 
2632
            }
 
2633
            break;
 
2634
 
 
2635
        case CL_TYPE_OOXML_WORD:
 
2636
        case CL_TYPE_OOXML_PPT:
 
2637
        case CL_TYPE_OOXML_XL:
 
2638
#if HAVE_JSON
 
2639
            if ((ctx->options & CL_SCAN_FILE_PROPERTIES) && (ctx->wrkproperty != NULL)) {
 
2640
                ret = cli_process_ooxml(ctx);
 
2641
                if (ret == CL_EMEM || ret == CL_ENULLARG) {
 
2642
                    /* critical error */
 
2643
                    break;
 
2644
                }
 
2645
                else if (ret != CL_SUCCESS) {
 
2646
                    /* allow for the CL_TYPE_ZIP scan to occur; cli_process_ooxml other possible returns: */
 
2647
                    /* CL_ETIMEOUT, CL_EMAXSIZE, CL_EMAXFILES, CL_EPARSE, CL_EFORMAT, CL_BREAK, CL_ESTAT  */
 
2648
                    ret = CL_SUCCESS;
 
2649
                }
 
2650
            }
 
2651
#endif
 
2652
        case CL_TYPE_ZIP:
 
2653
            ctx->container_type = CL_TYPE_ZIP;
 
2654
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
 
2655
                ret = cli_unzip(ctx);
 
2656
            break;
 
2657
 
 
2658
        case CL_TYPE_GZ:
 
2659
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_GZ))
 
2660
                ret = cli_scangzip(ctx);
 
2661
            break;
 
2662
 
 
2663
        case CL_TYPE_BZ:
 
2664
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BZ))
 
2665
                ret = cli_scanbzip(ctx);
 
2666
            break;
 
2667
 
 
2668
        case CL_TYPE_XZ:
 
2669
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_XZ))
 
2670
                ret = cli_scanxz(ctx);
 
2671
            break;
 
2672
 
 
2673
        case CL_TYPE_GPT:
 
2674
            ret = cli_scangpt(ctx, 0);
 
2675
            break;
 
2676
 
 
2677
        case CL_TYPE_APM:
 
2678
            ret = cli_scanapm(ctx);
 
2679
            break;
 
2680
 
 
2681
        case CL_TYPE_ARJ:
 
2682
            ctx->container_type = CL_TYPE_ARJ;
 
2683
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ))
 
2684
                ret = cli_scanarj(ctx, 0, NULL);
 
2685
            break;
 
2686
 
 
2687
        case CL_TYPE_NULSFT:
 
2688
            ctx->container_type = CL_TYPE_NULSFT;
 
2689
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_NSIS))
 
2690
                ret = cli_scannulsft(ctx, 0);
 
2691
            break;
 
2692
 
 
2693
        case CL_TYPE_AUTOIT:
 
2694
            ctx->container_type = CL_TYPE_AUTOIT;
 
2695
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_AUTOIT))
 
2696
                ret = cli_scanautoit(ctx, 23);
 
2697
            break;
 
2698
 
 
2699
        case CL_TYPE_MSSZDD:
 
2700
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SZDD))
 
2701
                ret = cli_scanszdd(ctx);
 
2702
            break;
 
2703
 
 
2704
        case CL_TYPE_MSCAB:
 
2705
            ctx->container_type = CL_TYPE_MSCAB;
 
2706
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB))
 
2707
                ret = cli_scanmscab(ctx, 0);
 
2708
            break;
 
2709
 
 
2710
        case CL_TYPE_HTML:
 
2711
            if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
 
2712
                ret = cli_scanhtml(ctx);
 
2713
            break;
 
2714
 
 
2715
        case CL_TYPE_HTML_UTF16:
 
2716
            if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
 
2717
                ret = cli_scanhtml_utf16(ctx);
 
2718
            break;
 
2719
 
 
2720
        case CL_TYPE_SCRIPT:
 
2721
            if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML)
 
2722
                ret = cli_scanscript(ctx);
 
2723
            break;
 
2724
 
 
2725
        case CL_TYPE_SWF:
 
2726
            if(SCAN_SWF && (DCONF_DOC & DOC_CONF_SWF))
 
2727
                ret = cli_scanswf(ctx);
 
2728
            break;
 
2729
 
 
2730
        case CL_TYPE_RTF:
 
2731
            ctx->container_type = CL_TYPE_RTF;
 
2732
            if(SCAN_ARCHIVE && (DCONF_DOC & DOC_CONF_RTF))
 
2733
                ret = cli_scanrtf(ctx);
 
2734
            break;
 
2735
 
 
2736
        case CL_TYPE_MAIL:
 
2737
            ctx->container_type = CL_TYPE_MAIL;
 
2738
            if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
 
2739
                ret = cli_scanmail(ctx);
 
2740
            break;
 
2741
 
 
2742
        case CL_TYPE_TNEF:
 
2743
            if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_TNEF))
 
2744
                ret = cli_scantnef(ctx);
 
2745
            break;
 
2746
 
 
2747
        case CL_TYPE_UUENCODED:
 
2748
            if(DCONF_OTHER & OTHER_CONF_UUENC)
 
2749
                ret = cli_scanuuencoded(ctx);
 
2750
            break;
 
2751
 
 
2752
        case CL_TYPE_MSCHM:
 
2753
            ctx->container_type = CL_TYPE_MSCHM;
 
2754
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CHM))
 
2755
                ret = cli_scanmschm(ctx);
 
2756
            break;
 
2757
 
 
2758
        case CL_TYPE_MSOLE2:
 
2759
            ctx->container_type = CL_TYPE_MSOLE2;
 
2760
            if(SCAN_OLE2 && (DCONF_ARCH & ARCH_CONF_OLE2))
 
2761
                ret = cli_scanole2(ctx);
 
2762
            break;
 
2763
 
 
2764
        case CL_TYPE_7Z:
 
2765
            ctx->container_type = CL_TYPE_7Z;
 
2766
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z))
 
2767
                ret = cli_7unz(ctx, 0);
 
2768
            break;
 
2769
 
 
2770
        case CL_TYPE_POSIX_TAR:
 
2771
            ctx->container_type = CL_TYPE_POSIX_TAR;
 
2772
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
 
2773
                ret = cli_scantar(ctx, 1);
 
2774
            break;
 
2775
 
 
2776
        case CL_TYPE_OLD_TAR:
 
2777
            ctx->container_type = CL_TYPE_OLD_TAR;
 
2778
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
 
2779
                ret = cli_scantar(ctx, 0);
 
2780
            break;
 
2781
 
 
2782
        case CL_TYPE_CPIO_OLD:
 
2783
            ctx->container_type = CL_TYPE_CPIO_OLD;
 
2784
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
 
2785
                ret = cli_scancpio_old(ctx);
 
2786
            break;
 
2787
 
 
2788
        case CL_TYPE_CPIO_ODC:
 
2789
            ctx->container_type = CL_TYPE_CPIO_ODC;
 
2790
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
 
2791
                ret = cli_scancpio_odc(ctx);
 
2792
            break;
 
2793
 
 
2794
        case CL_TYPE_CPIO_NEWC:
 
2795
            ctx->container_type = CL_TYPE_CPIO_NEWC;
 
2796
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
 
2797
                ret = cli_scancpio_newc(ctx, 0);
 
2798
            break;
 
2799
 
 
2800
        case CL_TYPE_CPIO_CRC:
 
2801
            ctx->container_type = CL_TYPE_CPIO_CRC;
 
2802
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
 
2803
                ret = cli_scancpio_newc(ctx, 1);
 
2804
            break;
 
2805
 
 
2806
        case CL_TYPE_BINHEX:
 
2807
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BINHEX))
 
2808
                ret = cli_binhex(ctx);
 
2809
            break;
 
2810
 
 
2811
        case CL_TYPE_SCRENC:
 
2812
            if(DCONF_OTHER & OTHER_CONF_SCRENC)
 
2813
                ret = cli_scanscrenc(ctx);
 
2814
            break;
 
2815
 
 
2816
        case CL_TYPE_RIFF:
 
2817
            if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_RIFF))
 
2818
                ret = cli_scanriff(ctx);
 
2819
            break;
 
2820
 
 
2821
        case CL_TYPE_GRAPHICS:
 
2822
            if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_JPEG))
 
2823
                ret = cli_scanjpeg(ctx);
 
2824
 
 
2825
            if(ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS)
 
2826
                ret = cli_parsejpeg(ctx);
 
2827
 
 
2828
            if(ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS && ret != CL_EPARSE)
 
2829
                ret = cli_parsepng(ctx);
 
2830
 
 
2831
            if(ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS && ret != CL_EPARSE)
 
2832
                ret = cli_parsegif(ctx);
 
2833
            break;
 
2834
 
 
2835
        case CL_TYPE_PDF: /* FIXMELIMITS: pdf should be an archive! */
 
2836
            ctx->container_type = CL_TYPE_PDF;
 
2837
            if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
 
2838
                ret = cli_scanpdf(ctx, 0);
 
2839
            break;
 
2840
 
 
2841
        case CL_TYPE_CRYPTFF:
 
2842
            if(DCONF_OTHER & OTHER_CONF_CRYPTFF)
 
2843
                ret = cli_scancryptff(ctx);
 
2844
            break;
 
2845
 
 
2846
        case CL_TYPE_ELF:
 
2847
            if(SCAN_ELF && ctx->dconf->elf)
 
2848
                ret = cli_scanelf(ctx);
 
2849
            break;
 
2850
 
 
2851
        case CL_TYPE_MACHO:
 
2852
            if(ctx->dconf->macho)
 
2853
                ret = cli_scanmacho(ctx, NULL);
 
2854
            break;
 
2855
 
 
2856
        case CL_TYPE_MACHO_UNIBIN:
 
2857
            if(ctx->dconf->macho)
 
2858
                ret = cli_scanmacho_unibin(ctx);
 
2859
            break;
 
2860
 
 
2861
        case CL_TYPE_SIS:
 
2862
            ctx->container_type = CL_TYPE_SIS;
 
2863
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SIS))
 
2864
                ret = cli_scansis(ctx);
 
2865
            break;
 
2866
 
 
2867
        case CL_TYPE_XAR:
 
2868
            ctx->container_type = CL_TYPE_XAR;
 
2869
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_XAR))
 
2870
                ret = cli_scanxar(ctx);
 
2871
            break;
 
2872
 
 
2873
        case CL_TYPE_PART_HFSPLUS:
 
2874
            ctx->container_type = CL_TYPE_PART_HFSPLUS;
 
2875
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_HFSPLUS))
 
2876
                ret = cli_scanhfsplus(ctx);
 
2877
            break;
 
2878
 
 
2879
        case CL_TYPE_BINARY_DATA:
 
2880
        case CL_TYPE_TEXT_UTF16BE:
 
2881
            if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_MYDOOMLOG))
 
2882
                ret = cli_check_mydoom_log(ctx);
 
2883
            break;
 
2884
 
 
2885
        case CL_TYPE_TEXT_ASCII:
 
2886
            if(SCAN_STRUCTURED && (DCONF_OTHER & OTHER_CONF_DLP))
 
2887
                /* TODO: consider calling this from cli_scanscript() for
 
2888
                 * a normalised text
 
2889
                 */
 
2890
                ret = cli_scan_structured(ctx);
 
2891
            break;
 
2892
 
 
2893
        default:
 
2894
            break;
 
2895
    }
 
2896
    perf_nested_stop(ctx, PERFT_CONTAINER, PERFT_SCAN);
 
2897
    ctx->recursion--;
 
2898
    ctx->container_type = current_container_type;
 
2899
    ctx->container_size = current_container_size;
 
2900
 
 
2901
    if(ret == CL_VIRUS) {
 
2902
        ret = cli_checkfp(hash, hashed_size, ctx);
 
2903
        cli_bitset_free(ctx->hook_lsig_matches);
 
2904
        ctx->hook_lsig_matches = old_hook_lsig_matches;
 
2905
    return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
 
2906
    }
 
2907
 
 
2908
    if(type == CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP)) {
 
2909
        /* CL_ENGINE_MAX_ZIPTYPERCG */
 
2910
        uint64_t curr_len = (*ctx->fmap)->len;
 
2911
        if(curr_len > ctx->engine->maxziptypercg) {
 
2912
            cli_dbgmsg("cli_magic_scandesc: Not checking for embedded PEs (zip file > MaxZipTypeRcg)\n");
 
2913
            typercg = 0;
 
2914
        }
 
2915
    }
 
2916
 
 
2917
    /* CL_TYPE_HTML: raw HTML files are not scanned, unless safety measure activated via DCONF */
 
2918
    if(type != CL_TYPE_IGNORED && (type != CL_TYPE_HTML || !(DCONF_DOC & DOC_CONF_HTML_SKIPRAW)) && !ctx->engine->sdb) {
 
2919
        res = cli_scanraw(ctx, type, typercg, &dettype, (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) ? NULL : hash);
 
2920
        if(res != CL_CLEAN) {
 
2921
            switch(res) {
 
2922
                /* List of scan halts, runtime errors only! */
 
2923
                case CL_EUNLINK:
 
2924
                case CL_ESTAT:
 
2925
                case CL_ESEEK:
 
2926
                case CL_EWRITE:
 
2927
                case CL_EDUP:
 
2928
                case CL_ETMPFILE:
 
2929
                case CL_ETMPDIR:
 
2930
                case CL_EMEM:
 
2931
                case CL_ETIMEOUT:
 
2932
                    cli_dbgmsg("Descriptor[%d]: cli_scanraw error %s\n", fmap_fd(*ctx->fmap), cl_strerror(res));
 
2933
                    cli_bitset_free(ctx->hook_lsig_matches);
 
2934
                    ctx->hook_lsig_matches = old_hook_lsig_matches;
 
2935
            return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
 
2936
                /* CL_VIRUS = malware found, check FP and report */
 
2937
                case CL_VIRUS:
 
2938
                    ret = cli_checkfp(hash, hashed_size, ctx);
 
2939
                    if (SCAN_ALL)
 
2940
                        break;
 
2941
                    cli_bitset_free(ctx->hook_lsig_matches);
 
2942
                    ctx->hook_lsig_matches = old_hook_lsig_matches;
 
2943
            return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
 
2944
                /* "MAX" conditions should still fully scan the current file */
 
2945
                case CL_EMAXREC:
 
2946
                case CL_EMAXSIZE:
 
2947
                case CL_EMAXFILES:
 
2948
                    ret = res;
 
2949
                    cli_dbgmsg("Descriptor[%d]: Continuing after cli_scanraw reached %s\n",
 
2950
                        fmap_fd(*ctx->fmap), cl_strerror(res));
 
2951
                    break;
 
2952
                /* Other errors must not block further scans below
 
2953
                 * This specifically includes CL_EFORMAT & CL_EREAD & CL_EUNPACK
 
2954
                 * Malformed/truncated files could report as any of these three.
 
2955
                 */
 
2956
                default:
 
2957
                    ret = res;
 
2958
                    cli_dbgmsg("Descriptor[%d]: Continuing after cli_scanraw error %s\n",
 
2959
                        fmap_fd(*ctx->fmap), cl_strerror(res));
 
2960
            }
 
2961
        }
 
2962
    }
 
2963
 
 
2964
    ctx->recursion++;
 
2965
    switch(type) {
 
2966
        /* bytecode hooks triggered by a lsig must be a hook
 
2967
         * called from one of the functions here */
 
2968
        case CL_TYPE_TEXT_ASCII:
 
2969
        case CL_TYPE_TEXT_UTF16BE:
 
2970
        case CL_TYPE_TEXT_UTF16LE:
 
2971
        case CL_TYPE_TEXT_UTF8:
 
2972
            perf_nested_start(ctx, PERFT_SCRIPT, PERFT_SCAN);
 
2973
            if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML && ret != CL_VIRUS)
 
2974
                ret = cli_scanscript(ctx);
 
2975
            if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX) && ret != CL_VIRUS && (ctx->container_type == CL_TYPE_MAIL || dettype == CL_TYPE_MAIL)) {
 
2976
                ret = cli_fmap_scandesc(ctx, CL_TYPE_MAIL, 0, NULL, AC_SCAN_VIR, NULL, NULL);
 
2977
            }
 
2978
            perf_nested_stop(ctx, PERFT_SCRIPT, PERFT_SCAN);
 
2979
            break;
 
2980
        /* Due to performance reasons all executables were first scanned
 
2981
         * in raw mode. Now we will try to unpack them
 
2982
         */
 
2983
        case CL_TYPE_MSEXE:
 
2984
            perf_nested_start(ctx, PERFT_PE, PERFT_SCAN);
 
2985
            if(SCAN_PE && ctx->dconf->pe) {
 
2986
                unsigned int corrupted_input = ctx->corrupted_input;
 
2987
                ret = cli_scanpe(ctx);
 
2988
                ctx->corrupted_input = corrupted_input;
 
2989
            }
 
2990
            perf_nested_stop(ctx, PERFT_PE, PERFT_SCAN);
 
2991
            break;
 
2992
        default:
 
2993
            break;
 
2994
    }
 
2995
 
 
2996
    if(ret == CL_VIRUS)
 
2997
        ret = cli_checkfp(hash, hashed_size, ctx);
 
2998
    ctx->recursion--;
 
2999
    cli_bitset_free(ctx->hook_lsig_matches);
 
3000
    ctx->hook_lsig_matches = old_hook_lsig_matches;
 
3001
 
 
3002
    switch(ret) {
 
3003
        /* Malformed file cases */
 
3004
        case CL_EFORMAT:
 
3005
        case CL_EREAD:
 
3006
        case CL_EUNPACK:
 
3007
        /* Limits exceeded */
 
3008
        case CL_EMAXREC:
 
3009
        case CL_EMAXSIZE:
 
3010
        case CL_EMAXFILES:
 
3011
            cli_dbgmsg("Descriptor[%d]: %s\n", fmap_fd(*ctx->fmap), cl_strerror(ret));
 
3012
#if HAVE_JSON
 
3013
        ctx->wrkproperty = parent_property;
 
3014
#endif
 
3015
        return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_CLEAN, parent_property);
 
3016
        case CL_CLEAN:
 
3017
            cache_clean = 1;
 
3018
#if HAVE_JSON
 
3019
        ctx->wrkproperty = parent_property;
 
3020
#endif
 
3021
        return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, CL_CLEAN, parent_property);
 
3022
        default:
 
3023
        return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
 
3024
    }
 
3025
}
 
3026
 
 
3027
static int cli_base_scandesc(int desc, cli_ctx *ctx, cli_file_t type)
 
3028
{
 
3029
    STATBUF sb;
 
3030
    int ret;
 
3031
 
 
3032
#ifdef HAVE__INTERNAL__SHA_COLLECT
 
3033
    if(ctx->sha_collect>0) ctx->sha_collect = 0;
 
3034
#endif
 
3035
    cli_dbgmsg("in cli_magic_scandesc (reclevel: %u/%u)\n", ctx->recursion, ctx->engine->maxreclevel);
 
3036
    if(FSTAT(desc, &sb) == -1) {
 
3037
        cli_errmsg("magic_scandesc: Can't fstat descriptor %d\n", desc);
 
3038
        early_ret_from_magicscan(CL_ESTAT);
 
3039
    }
 
3040
    if(sb.st_size <= 5) {
 
3041
        cli_dbgmsg("Small data (%u bytes)\n", (unsigned int) sb.st_size);
 
3042
        early_ret_from_magicscan(CL_CLEAN);
 
3043
    }
 
3044
 
 
3045
    ctx->fmap++;
 
3046
    perf_start(ctx, PERFT_MAP);
 
3047
    if(!(*ctx->fmap = fmap(desc, 0, sb.st_size))) {
 
3048
        cli_errmsg("CRITICAL: fmap() failed\n");
 
3049
        ctx->fmap--;
 
3050
        perf_stop(ctx, PERFT_MAP);
 
3051
        early_ret_from_magicscan(CL_EMEM);
 
3052
    }
 
3053
    perf_stop(ctx, PERFT_MAP);
 
3054
 
 
3055
    ret = magic_scandesc(ctx, type);
 
3056
 
 
3057
    funmap(*ctx->fmap);
 
3058
    ctx->fmap--;
 
3059
    return ret;
 
3060
}
 
3061
 
 
3062
int cli_magic_scandesc(int desc, cli_ctx *ctx)
 
3063
{
 
3064
    return cli_base_scandesc(desc, ctx, CL_TYPE_ANY);
 
3065
}
 
3066
 
 
3067
/* Have to keep partition typing separate */
 
3068
int cli_partition_scandesc(int desc, cli_ctx *ctx)
 
3069
{
 
3070
    return cli_base_scandesc(desc, ctx, CL_TYPE_PART_ANY);
 
3071
}
 
3072
 
 
3073
int cli_magic_scandesc_type(cli_ctx *ctx, cli_file_t type)
 
3074
{
 
3075
    return magic_scandesc(ctx, type);
 
3076
}
 
3077
 
 
3078
int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
 
3079
{
 
3080
    return cl_scandesc_callback(desc, virname, scanned, engine, scanoptions, NULL);
 
3081
}
 
3082
 
 
3083
/* For map scans that may be forced to disk */
 
3084
int cli_map_scan(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx, cli_file_t type)
 
3085
{
 
3086
    off_t old_off = map->nested_offset;
 
3087
    size_t old_len = map->len;
 
3088
    int ret = CL_CLEAN;
 
3089
 
 
3090
    cli_dbgmsg("cli_map_scan: [%ld, +%lu)\n",
 
3091
               (long)offset, (unsigned long)length);
 
3092
    if (offset < 0 || (size_t)offset >= old_len) {
 
3093
        cli_dbgmsg("Invalid offset: %ld\n", (long)offset);
 
3094
        return CL_CLEAN;
 
3095
    }
 
3096
 
 
3097
    if (ctx->engine->engine_options & ENGINE_OPTIONS_FORCE_TO_DISK) {
 
3098
        /* if this is forced to disk, then need to write the nested map and scan it */
 
3099
        const uint8_t *mapdata = NULL;
 
3100
        char *tempfile = NULL;
 
3101
        int fd = -1;
 
3102
        size_t nread = 0;
 
3103
 
 
3104
        /* Then check length */
 
3105
        if (!length) length = old_len - offset;
 
3106
        if (length > old_len - offset) {
 
3107
            cli_dbgmsg("cli_map_scan: Data truncated: %lu -> %lu\n",
 
3108
                       (unsigned long)length, (unsigned long)(old_len - offset));
 
3109
            length = old_len - offset;
 
3110
        }
 
3111
        if (length <= 5) {
 
3112
            cli_dbgmsg("cli_map_scan: Small data (%u bytes)\n", (unsigned int) length);
 
3113
            return CL_CLEAN;
 
3114
        }
 
3115
        if (!CLI_ISCONTAINED(old_off, old_len, old_off + offset, length)) {
 
3116
            cli_dbgmsg("cli_map_scan: map error occurred [%ld, %lu]\n",
 
3117
                       (long)old_off, (unsigned long)old_len);
 
3118
            return CL_CLEAN;
 
3119
        }
 
3120
 
 
3121
        /* Length checked, now get map */
 
3122
        mapdata = fmap_need_off_once_len(map, offset, length, &nread);
 
3123
        if (!mapdata || (nread != length)) {
 
3124
            cli_errmsg("cli_map_scan: could not map sub-file\n");
 
3125
            return CL_EMAP;
 
3126
        }
 
3127
 
 
3128
        ret = cli_gentempfd(ctx->engine->tmpdir, &tempfile, &fd);
 
3129
        if (ret != CL_SUCCESS) {
 
3130
            return ret;
 
3131
        }
 
3132
 
 
3133
        cli_dbgmsg("cli_map_scan: writing nested map content to temp file %s\n", tempfile);
 
3134
        if (cli_writen(fd, mapdata, length) < 0) {
 
3135
            cli_errmsg("cli_map_scan: cli_writen error writing subdoc temporary file.\n");
 
3136
            ret = CL_EWRITE;
 
3137
        }
 
3138
 
 
3139
        /* scan the temp file */
 
3140
        ret = cli_base_scandesc(fd, ctx, type);
 
3141
 
 
3142
        /* remove the temp file, if needed */
 
3143
        if (fd >= 0) {
 
3144
            close(fd);
 
3145
        }
 
3146
        if(!ctx->engine->keeptmp) {
 
3147
            if (cli_unlink(tempfile)) {
 
3148
                cli_errmsg("cli_map_scan: error unlinking tempfile %s\n", tempfile);
 
3149
                ret = CL_EUNLINK;
 
3150
            }
 
3151
        }
 
3152
        free(tempfile);
 
3153
    }
 
3154
    else {
 
3155
        /* Not forced to disk, use nested map */
 
3156
        ret = cli_map_scandesc(map, offset, length, ctx, type);
 
3157
    }
 
3158
    return ret;
 
3159
}
 
3160
 
 
3161
/* For map scans that are not forced to disk */
 
3162
int cli_map_scandesc(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx, cli_file_t type)
 
3163
{
 
3164
    off_t old_off = map->nested_offset;
 
3165
    size_t old_len = map->len;
 
3166
    size_t old_real_len = map->real_len;
 
3167
    int ret = CL_CLEAN;
 
3168
 
 
3169
    cli_dbgmsg("cli_map_scandesc: [%ld, +%lu), [%ld, +%lu)\n",
 
3170
               (long)old_off, (unsigned long)old_len,
 
3171
               (long)offset, (unsigned long)length);
 
3172
    if (offset < 0 || (size_t)offset >= old_len) {
 
3173
        cli_dbgmsg("Invalid offset: %ld\n", (long)offset);
 
3174
        return CL_CLEAN;
 
3175
    }
 
3176
 
 
3177
    if (!length) length = old_len - offset;
 
3178
    if (length > old_len - offset) {
 
3179
        cli_dbgmsg("Data truncated: %lu -> %lu\n",
 
3180
                   (unsigned long)length, old_len - offset);
 
3181
        length = old_len - offset;
 
3182
    }
 
3183
 
 
3184
    if (length <= 5) {
 
3185
        cli_dbgmsg("Small data (%u bytes)\n", (unsigned int) length);
 
3186
        return CL_CLEAN;
 
3187
    }
 
3188
    ctx->fmap++;
 
3189
    *ctx->fmap = map;
 
3190
    /* can't change offset because then we'd have to discard/move cached
 
3191
     * data, instead use another offset to reuse the already cached data */
 
3192
    map->nested_offset += offset;
 
3193
    map->len = length;
 
3194
    map->real_len = map->nested_offset + length;
 
3195
    if (CLI_ISCONTAINED(old_off, old_len, map->nested_offset, map->len)) {
 
3196
        ret = magic_scandesc(ctx, type);
 
3197
    } else {
 
3198
        long long len1, len2;
 
3199
        len1 = old_off + old_len;
 
3200
        len2 = map->nested_offset + map->len;
 
3201
        cli_warnmsg("internal map error: %lu, %llu; %lu, %llu\n", (long unsigned)old_off,
 
3202
                    (long long unsigned)len1, (long unsigned)map->offset, (long long unsigned)len2);
 
3203
    }
 
3204
 
 
3205
    ctx->fmap--;
 
3206
    map->nested_offset = old_off;
 
3207
    map->len = old_len;
 
3208
    map->real_len = old_real_len;
 
3209
    return ret;
 
3210
}
 
3211
 
 
3212
int cli_mem_scandesc(const void *buffer, size_t length, cli_ctx *ctx)
 
3213
{
 
3214
    int ret;
 
3215
    fmap_t *map = cl_fmap_open_memory(buffer, length);
 
3216
    if (!map) {
 
3217
        return CL_EMAP;
 
3218
    }
 
3219
    ret = cli_map_scan(map, 0, length, ctx, CL_TYPE_ANY);
 
3220
    cl_fmap_close(map);
 
3221
    return ret;
 
3222
}
 
3223
 
 
3224
static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
 
3225
{
 
3226
    cli_ctx ctx;
 
3227
    int rc;
 
3228
    STATBUF sb;
 
3229
 
 
3230
    /* We have a limit of around 2.17GB (INT_MAX - 2). Enforce it here. */
 
3231
    if (map != NULL) {
 
3232
        if ((size_t)(map->real_len) > (size_t)(INT_MAX - 2))
 
3233
            return CL_CLEAN;
 
3234
    } else {
 
3235
        if (FSTAT(desc, &sb))
 
3236
            return CL_ESTAT;
 
3237
 
 
3238
        if ((size_t)(sb.st_size) > (size_t)(INT_MAX - 2))
 
3239
            return CL_CLEAN;
 
3240
    }
 
3241
 
 
3242
    memset(&ctx, '\0', sizeof(cli_ctx));
 
3243
    ctx.engine = engine;
 
3244
    ctx.virname = virname;
 
3245
    ctx.scanned = scanned;
 
3246
    ctx.options = scanoptions;
 
3247
#if 0 /* for development testing only */
 
3248
    ctx.options |= CL_SCAN_FILE_PROPERTIES;
 
3249
#endif
 
3250
    ctx.found_possibly_unwanted = 0;
 
3251
    ctx.container_type = CL_TYPE_ANY;
 
3252
    ctx.container_size = 0;
 
3253
    ctx.dconf = (struct cli_dconf *) engine->dconf;
 
3254
    ctx.cb_ctx = context;
 
3255
    ctx.fmap = cli_calloc(sizeof(fmap_t *), ctx.engine->maxreclevel + 2);
 
3256
    if(!ctx.fmap)
 
3257
        return CL_EMEM;
 
3258
    if (!(ctx.hook_lsig_matches = cli_bitset_init())) {
 
3259
        free(ctx.fmap);
 
3260
        return CL_EMEM;
 
3261
    }
 
3262
    perf_init(&ctx);
 
3263
 
 
3264
    if (ctx.options & CL_SCAN_FILE_PROPERTIES && ctx.engine->time_limit != 0) {
 
3265
        if (gettimeofday(&ctx.time_limit, NULL) == 0) {
 
3266
            uint32_t secs = ctx.engine->time_limit / 1000;
 
3267
            uint32_t usecs = (ctx.engine->time_limit % 1000) * 1000;
 
3268
            ctx.time_limit.tv_sec += secs;
 
3269
            ctx.time_limit.tv_usec += usecs;
 
3270
            if (ctx.time_limit.tv_usec >= 1000000) {
 
3271
                ctx.time_limit.tv_usec -= 1000000;
 
3272
                ctx.time_limit.tv_sec++;
 
3273
            }
 
3274
        } else {
 
3275
            char buf[64];
 
3276
            cli_dbgmsg("scan_common; gettimeofday error: %s\n", cli_strerror(errno, buf, 64));
 
3277
        }
 
3278
    }
 
3279
 
 
3280
#ifdef HAVE__INTERNAL__SHA_COLLECT
 
3281
    if(scanoptions & CL_SCAN_INTERNAL_COLLECT_SHA) {
 
3282
        char link[32];
 
3283
        ssize_t linksz;
 
3284
 
 
3285
 
 
3286
        snprintf(link, sizeof(link), "/proc/self/fd/%u", desc);
 
3287
        link[sizeof(link)-1]='\0';
 
3288
        if((linksz=readlink(link, ctx.entry_filename, sizeof(ctx.entry_filename)-1))==-1) {
 
3289
            cli_errmsg("failed to resolve filename for descriptor %d (%s)\n", desc, link);
 
3290
            strcpy(ctx.entry_filename, "NO_IDEA");
 
3291
        } else
 
3292
            ctx.entry_filename[linksz]='\0';
 
3293
    } while(0);
 
3294
#endif
 
3295
 
 
3296
    cli_logg_setup(&ctx);
 
3297
    rc = map ? cli_map_scandesc(map, 0, map->len, &ctx, CL_TYPE_ANY) : cli_magic_scandesc(desc, &ctx);
 
3298
 
 
3299
#if HAVE_JSON
 
3300
    if (ctx.options & CL_SCAN_FILE_PROPERTIES && ctx.properties!=NULL) {
 
3301
        json_object *jobj;
 
3302
        const char *jstring;
 
3303
 
 
3304
        /* set value of unique root object tag */
 
3305
        if (json_object_object_get_ex(ctx.properties, "FileType", &jobj)) {
 
3306
            enum json_type type;
 
3307
            const char *jstr;
 
3308
 
 
3309
            type = json_object_get_type(jobj);
 
3310
            if (type == json_type_string) {
 
3311
                jstr = json_object_get_string(jobj);
 
3312
                cli_jsonstr(ctx.properties, "RootFileType", jstr);
 
3313
            }
 
3314
        }
 
3315
 
 
3316
        /* serialize json properties to string */
 
3317
        jstring = json_object_to_json_string(ctx.properties);
 
3318
        if (NULL == jstring) {
 
3319
            cli_errmsg("scan_common: no memory for json serialization.\n");
 
3320
            rc = CL_EMEM;
 
3321
        }
 
3322
        else {
 
3323
            int ret = CL_SUCCESS;
 
3324
            cli_dbgmsg("%s\n", jstring);
 
3325
 
 
3326
           /* Scan the json string unless a virus was detected */ 
 
3327
            if (rc != CL_VIRUS) {
 
3328
                ctx.options &= ~CL_SCAN_FILE_PROPERTIES;
 
3329
                rc = cli_mem_scandesc(jstring, strlen(jstring), &ctx);
 
3330
            }
 
3331
 
 
3332
            /* Invoke file props callback */
 
3333
            if (ctx.engine->cb_file_props != NULL) {
 
3334
                ret = ctx.engine->cb_file_props(jstring, rc, ctx.engine->cb_file_props_data);
 
3335
                if (ret != CL_SUCCESS)
 
3336
                    rc = ret;
 
3337
            }
 
3338
 
 
3339
            /* keeptmp file processing for file properties json string */
 
3340
            if (ctx.engine->keeptmp) {
 
3341
                int fd = -1;
 
3342
                char * tmpname = NULL;
 
3343
                if ((ret = cli_gentempfd(ctx.engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
 
3344
                    cli_dbgmsg("scan_common: Can't create json properties file, ret = %i.\n", ret);
 
3345
                } else {
 
3346
                    if (cli_writen(fd, jstring, strlen(jstring)) < 0)
 
3347
                        cli_dbgmsg("scan_common: cli_writen error writing json properties file.\n");
 
3348
                    else
 
3349
                        cli_dbgmsg("json written to: %s\n", tmpname);
 
3350
                }
 
3351
                if (fd != -1)
 
3352
                    close(fd);
 
3353
                if (NULL != tmpname)
 
3354
                    free(tmpname);
 
3355
            }
 
3356
        }
 
3357
        json_object_put(ctx.properties); /* frees all json memory */
 
3358
#if 0
 
3359
        // test code  - to be deleted
 
3360
        if (cli_checktimelimit(&ctx) != CL_SUCCESS) {
 
3361
            cli_errmsg("scan_common: timeout!\n");
 
3362
            rc = CL_ETIMEOUT;
 
3363
        }
 
3364
#endif
 
3365
    }
 
3366
#endif
 
3367
 
 
3368
    if (ctx.options & CL_SCAN_ALLMATCHES) {
 
3369
        *virname = (char *)ctx.virname; /* temp hack for scanall mode until api augmentation */
 
3370
        if (rc == CL_CLEAN && ctx.num_viruses)
 
3371
            rc = CL_VIRUS;
 
3372
    }
 
3373
 
 
3374
    cli_bitset_free(ctx.hook_lsig_matches);
 
3375
    free(ctx.fmap);
 
3376
    if(rc == CL_CLEAN && ctx.found_possibly_unwanted)
 
3377
        rc = CL_VIRUS;
 
3378
    cli_logg_unsetup();
 
3379
    perf_done(&ctx);
 
3380
    return rc;
 
3381
}
 
3382
 
 
3383
int cl_scandesc_callback(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
 
3384
{
 
3385
    return scan_common(desc, NULL, virname, scanned, engine, scanoptions, context);
 
3386
}
 
3387
 
 
3388
int cl_scanmap_callback(cl_fmap_t *map, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
 
3389
{
 
3390
    return scan_common(-1, map, virname, scanned, engine, scanoptions, context);
 
3391
}
 
3392
 
 
3393
int cli_found_possibly_unwanted(cli_ctx* ctx)
 
3394
{
 
3395
    if(cli_get_last_virus(ctx)) {
 
3396
        cli_dbgmsg("found Possibly Unwanted: %s\n", cli_get_last_virus(ctx));
 
3397
        if(ctx->options & CL_SCAN_HEURISTIC_PRECEDENCE) {
 
3398
            /* we found a heuristic match, don't scan further,
 
3399
             * but consider it a virus. */
 
3400
            cli_dbgmsg("cli_found_possibly_unwanted: CL_VIRUS\n");
 
3401
            return CL_VIRUS;
 
3402
        }
 
3403
        /* heuristic scan isn't taking precedence, keep scanning.
 
3404
         * If this is part of an archive, and 
 
3405
         * we find a real malware we report that instead of the 
 
3406
         * heuristic match */
 
3407
        ctx->found_possibly_unwanted = 1;
 
3408
    } else {
 
3409
        cli_warnmsg("cli_found_possibly_unwanted called, but virname is not set\n");
 
3410
    }
 
3411
    emax_reached(ctx);
 
3412
    return CL_CLEAN;
 
3413
}
 
3414
 
 
3415
static int cli_scanfile(const char *filename, cli_ctx *ctx)
 
3416
{
 
3417
        int fd, ret;
 
3418
 
 
3419
    /* internal version of cl_scanfile with arec/mrec preserved */
 
3420
    if((fd = safe_open(filename, O_RDONLY|O_BINARY)) == -1)
 
3421
        return CL_EOPEN;
 
3422
 
 
3423
    ret = cli_magic_scandesc(fd, ctx);
 
3424
 
 
3425
    close(fd);
 
3426
    return ret;
 
3427
}
 
3428
 
 
3429
int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
 
3430
{
 
3431
    return cl_scanfile_callback(filename, virname, scanned, engine, scanoptions, NULL);
 
3432
}
 
3433
 
 
3434
int cl_scanfile_callback(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
 
3435
{
 
3436
        int fd, ret;
 
3437
        const char *fname = cli_to_utf8_maybe_alloc(filename);
 
3438
 
 
3439
    if(!fname)
 
3440
            return CL_EARG;
 
3441
 
 
3442
    if((fd = safe_open(fname, O_RDONLY|O_BINARY)) == -1)
 
3443
        return CL_EOPEN;
 
3444
 
 
3445
    if(fname != filename)
 
3446
        free((void*)fname);
 
3447
 
 
3448
    ret = cl_scandesc_callback(fd, virname, scanned, engine, scanoptions, context);
 
3449
    close(fd);
 
3450
 
 
3451
    return ret;
 
3452
}
 
3453
 
 
3454
/*
 
3455
Local Variables:
 
3456
   c-basic-offset: 4
 
3457
End:
 
3458
*/