~ubuntu-branches/ubuntu/feisty/clamav/feisty

« back to all changes in this revision

Viewing changes to libclamav/scanners.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2007-02-20 10:33:44 UTC
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20070220103344-zgcu2psnx9d98fpa
Tags: upstream-0.90
ImportĀ upstreamĀ versionĀ 0.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 *  Copyright (C) 2007-2008 Sourcefire, Inc.
3
 
 *
4
 
 *  Authors: Tomasz Kojm
 
2
 *  Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm@clamav.net>
5
3
 *
6
4
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License version 2 as
8
 
 *  published by the Free Software Foundation.
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation; either version 2 of the License, or
 
7
 *  (at your option) any later version.
9
8
 *
10
9
 *  This program is distributed in the hope that it will be useful,
11
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
22
21
#include "clamav-config.h"
23
22
#endif
24
23
 
25
 
#ifndef _WIN32
26
 
#include <sys/time.h>
27
 
#endif
28
24
#include <stdio.h>
29
25
#include <string.h>
30
26
#include <stdlib.h>
31
 
#include <errno.h>
32
27
#include <sys/types.h>
33
28
#include <sys/stat.h>
34
29
#ifdef  HAVE_UNISTD_H
38
33
#include <sys/param.h>
39
34
#endif
40
35
#include <fcntl.h>
 
36
#ifndef C_WINDOWS
41
37
#include <dirent.h>
 
38
#include <netinet/in.h>
 
39
#endif
 
40
 
 
41
#if HAVE_MMAP
 
42
#if HAVE_SYS_MMAN_H
 
43
#include <sys/mman.h>
 
44
#else /* HAVE_SYS_MMAN_H */
 
45
#undef HAVE_MMAP
 
46
#endif
 
47
#endif
 
48
 
 
49
#ifndef O_BINARY
 
50
#define O_BINARY        0
 
51
#endif
 
52
 
 
53
extern short cli_leavetemps_flag;
42
54
 
43
55
#define DCONF_ARCH  ctx->dconf->archive
44
56
#define DCONF_DOC   ctx->dconf->doc
52
64
#include "matcher-ac.h"
53
65
#include "matcher-bm.h"
54
66
#include "matcher.h"
 
67
#include "unrar.h"
55
68
#include "ole2_extract.h"
56
69
#include "vba_extract.h"
57
70
#include "msexpand.h"
72
85
#include "mspack.h"
73
86
#include "cab.h"
74
87
#include "rtf.h"
75
 
#include "unarj.h"
76
 
#include "nsis/nulsft.h"
77
 
#include "autoit.h"
78
 
#include "textnorm.h"
 
88
 
 
89
#ifdef HAVE_ZLIB_H
79
90
#include <zlib.h>
80
91
#include "unzip.h"
81
 
#include "dlp.h"
82
 
#include "default.h"
83
 
#include "cpio.h"
84
 
#include "macho.h"
85
 
#include "ishield.h"
86
 
#include "7z.h"
87
 
#include "fmap.h"
88
 
#include "cache.h"
 
92
#endif
89
93
 
90
94
#ifdef HAVE_BZLIB_H
91
95
#include <bzlib.h>
96
100
#include <stddef.h>
97
101
#endif
98
102
 
 
103
/* Maximum filenames under various systems - njh */
 
104
#ifndef NAME_MAX        /* e.g. Linux */
 
105
# ifdef MAXNAMELEN      /* e.g. Solaris */
 
106
#   define      NAME_MAX        MAXNAMELEN
 
107
# else
 
108
#   ifdef       FILENAME_MAX    /* e.g. SCO */
 
109
#     define    NAME_MAX        FILENAME_MAX
 
110
#   else
 
111
#     define    NAME_MAX        256
 
112
#   endif
 
113
# endif
 
114
#endif
 
115
 
 
116
#define MAX_MAIL_RECURSION  15
 
117
 
99
118
static int cli_scanfile(const char *filename, cli_ctx *ctx);
100
119
 
101
 
static int cli_scandir(const char *dirname, cli_ctx *ctx)
102
 
{
103
 
        DIR *dd;
104
 
        struct dirent *dent;
105
 
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
106
 
        union {
107
 
            struct dirent d;
108
 
            char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
109
 
        } result;
110
 
#endif
111
 
        struct stat statbuf;
112
 
        char *fname;
113
 
 
114
 
 
115
 
    if((dd = opendir(dirname)) != NULL) {
116
 
#ifdef HAVE_READDIR_R_3
117
 
        while(!readdir_r(dd, &result.d, &dent) && dent) {
118
 
#elif defined(HAVE_READDIR_R_2)
119
 
        while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
120
 
#else
121
 
        while((dent = readdir(dd))) {
122
 
#endif
123
 
            if(dent->d_ino)
124
 
            {
125
 
                if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
126
 
                    /* build the full name */
127
 
                    fname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
128
 
                    if(!fname) {
129
 
                        closedir(dd);
130
 
                        return CL_EMEM;
131
 
                    }
132
 
 
133
 
                    sprintf(fname, "%s"PATHSEP"%s", dirname, dent->d_name);
134
 
 
135
 
                    /* stat the file */
136
 
                    if(lstat(fname, &statbuf) != -1) {
137
 
                        if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {
138
 
                            if(cli_scandir(fname, ctx) == CL_VIRUS) {
139
 
                                free(fname);
140
 
                                closedir(dd);
141
 
                                return CL_VIRUS;
142
 
                            }
143
 
                        } else {
144
 
                            if(S_ISREG(statbuf.st_mode)) {
145
 
                                if(cli_scanfile(fname, ctx) == CL_VIRUS) {
146
 
                                    free(fname);
147
 
                                    closedir(dd);
148
 
                                    return CL_VIRUS;
149
 
                                }
150
 
                            }
151
 
                        }
152
 
                    }
153
 
                    free(fname);
154
 
                }
155
 
            }
156
 
        }
157
 
    } else {
158
 
        cli_dbgmsg("cli_scandir: Can't open directory %s.\n", dirname);
159
 
        return CL_EOPEN;
160
 
    }
161
 
 
162
 
    closedir(dd);
163
 
    return CL_CLEAN;
164
 
}
165
 
 
166
 
static int cli_unrar_scanmetadata(int desc, unrar_metadata_t *metadata, cli_ctx *ctx, unsigned int files, uint32_t* sfx_check)
 
120
static int cli_unrar_scanmetadata(int desc, rar_metadata_t *metadata, cli_ctx *ctx, unsigned int files, uint32_t* sfx_check)
167
121
{
168
122
        int ret = CL_SUCCESS;
 
123
        struct cli_meta_node* mdata;
 
124
 
169
125
 
170
126
    if(files == 1 && sfx_check) {
171
127
        if(*sfx_check == metadata->crc)
174
130
            *sfx_check = metadata->crc;
175
131
    }
176
132
 
177
 
    cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %u, compressed: %u, normal: %u, method: %u, ratio: %u\n",
178
 
        metadata->filename, metadata->crc, metadata->encrypted, (unsigned int) metadata->pack_size,
179
 
        (unsigned int) metadata->unpack_size, metadata->method,
180
 
        metadata->pack_size ? (unsigned int) (metadata->unpack_size / metadata->pack_size) : 0);
181
 
 
182
 
    if(cli_matchmeta(ctx, metadata->filename, metadata->pack_size, metadata->unpack_size, metadata->encrypted, files, metadata->crc, NULL) == CL_VIRUS)
183
 
        return CL_VIRUS;
 
133
    cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %d, compressed: %u, normal: %u, method: %d, ratio: %d (max: %d)\n",
 
134
        metadata->filename, metadata->crc, metadata->encrypted, metadata->pack_size,
 
135
        metadata->unpack_size, metadata->method,
 
136
        metadata->pack_size ? ((unsigned int) metadata->unpack_size / (unsigned int) metadata->pack_size) : 0, ctx->limits ? ctx->limits->maxratio : 0);
 
137
 
 
138
    /* Scan metadata */
 
139
    mdata = ctx->engine->rar_mlist;
 
140
    if(mdata) do {
 
141
        if(mdata->encrypted != metadata->encrypted)
 
142
            continue;
 
143
 
 
144
        if(mdata->crc32 && (unsigned int) mdata->crc32 != metadata->crc)
 
145
            continue;
 
146
 
 
147
        if(mdata->csize > 0 && (unsigned int) mdata->csize != metadata->pack_size)
 
148
            continue;
 
149
 
 
150
        if(mdata->size >= 0 && (unsigned int) mdata->size != metadata->unpack_size)
 
151
            continue;
 
152
 
 
153
        if(mdata->method >= 0 && mdata->method != metadata->method)
 
154
            continue;
 
155
 
 
156
        if(mdata->fileno && mdata->fileno != files)
 
157
            continue;
 
158
 
 
159
        if(mdata->maxdepth && ctx->arec > mdata->maxdepth)
 
160
            continue;
 
161
 
 
162
        /* TODO add support for regex */
 
163
        /*if(mdata->filename && !strstr(zdirent.d_name, mdata->filename))*/
 
164
        if(mdata->filename && strcmp((char *) metadata->filename, mdata->filename))
 
165
            continue;
 
166
 
 
167
        break; /* matched */
 
168
 
 
169
    } while((mdata = mdata->next));
 
170
 
 
171
    if(mdata) {
 
172
        *ctx->virname = mdata->virname;
 
173
        return CL_VIRUS;           
 
174
    }
184
175
 
185
176
    if(DETECT_ENCRYPTED && metadata->encrypted) {
186
177
        cli_dbgmsg("RAR: Encrypted files found in archive.\n");
187
178
        lseek(desc, 0, SEEK_SET);
188
 
        ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
 
179
        ret = cli_scandesc(desc, ctx, 0, 0, 0, NULL);
189
180
        if(ret != CL_VIRUS) {
190
 
            *ctx->virname = "Heuristics.Encrypted.RAR";
 
181
            *ctx->virname = "Encrypted.RAR";
191
182
            return CL_VIRUS;
192
183
        }
193
184
    }
194
185
 
 
186
/*
 
187
    TROG - TODO: multi-volume files
 
188
    if((rarlist->item.Flags & 0x03) != 0) {
 
189
        cli_dbgmsg("RAR: Skipping %s (split)\n", rarlist->item.Name);
 
190
        rarlist = rarlist->next;
 
191
        continue;
 
192
    }
 
193
*/
195
194
    return ret;
196
195
}
197
196
 
 
197
static int cli_unrar_checklimits(const cli_ctx *ctx, const rar_metadata_t *metadata, unsigned int files)
 
198
{
 
199
    if(ctx->limits) {
 
200
        if(ctx->limits->maxratio && metadata->unpack_size && metadata->pack_size) {
 
201
            if(metadata->unpack_size / metadata->pack_size >= ctx->limits->maxratio) {
 
202
                cli_dbgmsg("RAR: Max ratio reached (normal: %Lu, compressed: %Lu, max: %u)\n", metadata->unpack_size, metadata->pack_size, ctx->limits->maxratio);
 
203
                if(BLOCKMAX) {
 
204
                    *ctx->virname = "Oversized.RAR";
 
205
                    return CL_VIRUS;
 
206
                }
 
207
                return CL_EMAXSIZE;
 
208
            }
 
209
        }
 
210
 
 
211
        if(ctx->limits->maxfilesize && (metadata->unpack_size > ctx->limits->maxfilesize)) {
 
212
            cli_dbgmsg("RAR: %s: Size exceeded (%Lu, max: %lu)\n", metadata->filename, metadata->unpack_size, ctx->limits->maxfilesize);
 
213
            if(BLOCKMAX) {
 
214
                *ctx->virname = "RAR.ExceededFileSize";
 
215
                return CL_VIRUS;
 
216
            }
 
217
            return CL_EMAXSIZE;
 
218
        }
 
219
 
 
220
        if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
 
221
            cli_dbgmsg("RAR: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
 
222
            if(BLOCKMAX) {
 
223
                *ctx->virname = "RAR.ExceededFilesLimit";
 
224
                return CL_VIRUS;
 
225
            }
 
226
            return CL_EMAXFILES;
 
227
        }
 
228
    }
 
229
 
 
230
    return CL_SUCCESS;
 
231
}
 
232
 
198
233
static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
199
234
{
200
235
        int ret = CL_CLEAN;
201
 
        unrar_metadata_t *metadata, *metadata_tmp;
 
236
        rar_metadata_t *metadata, *metadata_tmp;
202
237
        char *dir;
203
 
        unrar_state_t rar_state;
 
238
        rar_state_t rar_state;
204
239
 
205
240
 
206
241
    cli_dbgmsg("in scanrar()\n");
207
242
 
208
 
    if(sfx_offset)
209
 
        if(lseek(desc, sfx_offset, SEEK_SET) == -1)
210
 
            return CL_ESEEK;
211
 
 
212
243
    /* generate the temporary directory */
213
 
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
214
 
        return CL_EMEM;
215
 
 
 
244
    dir = cli_gentemp(NULL);
216
245
    if(mkdir(dir, 0700)) {
217
246
        cli_dbgmsg("RAR: Can't create temporary directory %s\n", dir);
218
247
        free(dir);
219
248
        return CL_ETMPDIR;
220
249
    }
221
250
 
222
 
    if((ret = cli_unrar_open(desc, dir, &rar_state)) != UNRAR_OK) {
223
 
        if(!ctx->engine->keeptmp)
 
251
    if(sfx_offset)
 
252
        lseek(desc, sfx_offset, SEEK_SET);
 
253
 
 
254
    if((ret = cli_unrar_open(desc, dir, &rar_state)) != CL_SUCCESS) {
 
255
        if(!cli_leavetemps_flag)
224
256
            cli_rmdirs(dir);
225
257
        free(dir);
226
 
        if(ret == UNRAR_PASSWD) {
227
 
            cli_dbgmsg("RAR: Encrypted main header\n");
228
 
            if(DETECT_ENCRYPTED) {
229
 
                lseek(desc, 0, SEEK_SET);
230
 
                ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
231
 
                if(ret != CL_VIRUS)
232
 
                    *ctx->virname = "Heuristics.Encrypted.RAR";
233
 
                return CL_VIRUS;
234
 
            }
235
 
            return CL_CLEAN;
236
 
        } if(ret == UNRAR_EMEM) {
237
 
            return CL_EMEM;
238
 
        } else {
239
 
            return CL_EUNPACK;
240
 
        }
 
258
        cli_dbgmsg("RAR: Error: %s\n", cl_strerror(ret));
 
259
        return ret;
241
260
    }
242
261
 
243
262
    do {
244
263
        int rc;
245
 
        rar_state.ofd = -1;
 
264
        rar_state.unpack_data->ofd = -1;
246
265
        ret = cli_unrar_extract_next_prepare(&rar_state,dir);
247
 
        if(ret != UNRAR_OK) {
248
 
            if(ret == UNRAR_BREAK)
249
 
                ret = CL_BREAK;
250
 
            else if(ret == UNRAR_EMEM)
251
 
                ret = CL_EMEM;
252
 
            else
253
 
                ret = CL_EUNPACK;
 
266
        if(ret != CL_SUCCESS) 
254
267
            break;
255
 
        }
256
 
        if(ctx->engine->maxscansize && ctx->scansize >= ctx->engine->maxscansize) {
 
268
        ret = cli_unrar_checklimits(ctx, rar_state.metadata_tail, rar_state.file_count);
 
269
        if(ret && ret != CL_VIRUS) {
257
270
            free(rar_state.file_header->filename);
258
271
            free(rar_state.file_header);
259
272
            ret = CL_CLEAN;
 
273
            continue;
 
274
        } else if(ret == CL_VIRUS) {
 
275
            /* needed since we didn't reach unrar_extract_next to clean this up*/
 
276
            free(rar_state.file_header->filename);
 
277
            free(rar_state.file_header);           
260
278
            break;
261
279
        }
262
 
        if(ctx->engine->maxscansize && ctx->scansize + ctx->engine->maxfilesize >= ctx->engine->maxscansize)
263
 
            rar_state.maxfilesize = ctx->engine->maxscansize - ctx->scansize;
264
 
        else
265
 
            rar_state.maxfilesize = ctx->engine->maxfilesize;
266
 
 
267
280
        ret = cli_unrar_extract_next(&rar_state,dir);
268
 
        if(ret == UNRAR_OK)
269
 
            ret = CL_SUCCESS;
270
 
        else if(ret == UNRAR_EMEM)
271
 
            ret = CL_EMEM;
272
 
        else
273
 
            ret = CL_EFORMAT;
274
 
 
275
 
        if(rar_state.ofd > 0) {
276
 
            lseek(rar_state.ofd,0,SEEK_SET);
277
 
            rc = cli_magic_scandesc(rar_state.ofd,ctx);
278
 
            close(rar_state.ofd);
279
 
            if(!ctx->engine->keeptmp) 
280
 
                if (cli_unlink(rar_state.filename)) ret = CL_EUNLINK;
 
281
        if(rar_state.unpack_data->ofd > 0) {
 
282
            lseek(rar_state.unpack_data->ofd,0,SEEK_SET);
 
283
            rc = cli_magic_scandesc(rar_state.unpack_data->ofd,ctx);
 
284
            close(rar_state.unpack_data->ofd);
 
285
            if(!cli_leavetemps_flag) 
 
286
                unlink(rar_state.filename);
281
287
            if(rc == CL_VIRUS ) {
282
288
                cli_dbgmsg("RAR: infected with %s\n",*ctx->virname);
283
289
                ret = CL_VIRUS;
300
306
 
301
307
    cli_unrar_close(&rar_state);
302
308
 
303
 
    if(!ctx->engine->keeptmp)
 
309
    if(!cli_leavetemps_flag)
304
310
        cli_rmdirs(dir);
305
311
 
306
312
    free(dir);
317
323
    return ret;
318
324
}
319
325
 
320
 
static int cli_scanarj(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
 
326
#ifdef HAVE_ZLIB_H
 
327
static int cli_scanzip(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
321
328
{
322
 
        int ret = CL_CLEAN, rc, file = 0;
323
 
        arj_metadata_t metadata;
324
 
        char *dir;
325
 
 
326
 
    cli_dbgmsg("in cli_scanarj()\n");
327
 
 
328
 
     /* generate the temporary directory */
329
 
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
 
329
        zip_dir *zdir;
 
330
        zip_dirent zdirent;
 
331
        zip_file *zfp;
 
332
        FILE *tmp = NULL;
 
333
        char *tmpname = NULL, *buff;
 
334
        int fd, bytes, ret = CL_CLEAN;
 
335
        unsigned long int size = 0;
 
336
        unsigned int files = 0, encrypted, bfcnt;
 
337
        struct stat source;
 
338
        struct cli_meta_node *mdata;
 
339
        int err;
 
340
        uint8_t swarning = 0, fail, success;
 
341
 
 
342
 
 
343
    cli_dbgmsg("in scanzip()\n");
 
344
 
 
345
    if((zdir = zip_dir_open(desc, sfx_offset, &err)) == NULL) {
 
346
        cli_dbgmsg("Zip: zip_dir_open() return code: %d\n", err);
 
347
        /* no return with CL_EZIP due to password protected zips */
 
348
        return CL_CLEAN;
 
349
    }
 
350
 
 
351
    fstat(desc, &source);
 
352
 
 
353
    if(!(buff = (char *) cli_malloc(FILEBUFF))) {
 
354
        cli_dbgmsg("Zip: unable to malloc(%u)\n", FILEBUFF);
 
355
        zip_dir_close(zdir);
330
356
        return CL_EMEM;
331
 
 
332
 
    if(mkdir(dir, 0700)) {
333
 
        cli_dbgmsg("ARJ: Can't create temporary directory %s\n", dir);
334
 
        free(dir);
335
 
        return CL_ETMPDIR;
336
 
    }
337
 
 
338
 
    if(sfx_offset)
339
 
        lseek(desc, sfx_offset, SEEK_SET);
340
 
 
341
 
    ret = cli_unarj_open(desc, dir);
342
 
    if (ret != CL_SUCCESS) {
343
 
        if(!ctx->engine->keeptmp)
344
 
            cli_rmdirs(dir);
345
 
        free(dir);
346
 
        cli_dbgmsg("ARJ: Error: %s\n", cl_strerror(ret));
347
 
        return ret;
348
 
    }
349
 
    
350
 
   do {
351
 
        metadata.filename = NULL;
352
 
        ret = cli_unarj_prepare_file(desc, dir, &metadata);
353
 
        if (ret != CL_SUCCESS) {
354
 
           break;
355
 
        }
356
 
        file++;
357
 
        if(cli_matchmeta(ctx, metadata.filename, metadata.comp_size, metadata.orig_size, metadata.encrypted, file, 0, NULL) == CL_VIRUS)
358
 
            return CL_VIRUS;
359
 
 
360
 
        if ((ret = cli_checklimits("ARJ", ctx, metadata.orig_size, metadata.comp_size, 0))!=CL_CLEAN) {
361
 
            ret = CL_SUCCESS;
362
 
            if (metadata.filename)
363
 
                free(metadata.filename);
364
 
            continue;
365
 
        }
366
 
        ret = cli_unarj_extract_file(desc, dir, &metadata);
367
 
        if (metadata.ofd >= 0) {
368
 
            lseek(metadata.ofd, 0, SEEK_SET);
369
 
            rc = cli_magic_scandesc(metadata.ofd, ctx);
370
 
            close(metadata.ofd);
371
 
            if (rc == CL_VIRUS) {
372
 
                cli_dbgmsg("ARJ: infected with %s\n",*ctx->virname);
373
 
                ret = CL_VIRUS;
374
 
                if (metadata.filename) {
375
 
                    free(metadata.filename);
376
 
                    metadata.filename = NULL;
377
 
                }
378
 
                break;
379
 
            }
380
 
        }
381
 
        if (metadata.filename) {
382
 
                free(metadata.filename);
383
 
                metadata.filename = NULL;
384
 
        }
385
 
 
386
 
    } while(ret == CL_SUCCESS);
387
 
    
388
 
    if(!ctx->engine->keeptmp)
389
 
        cli_rmdirs(dir);
390
 
 
391
 
    free(dir);
392
 
    if (metadata.filename) {
393
 
        free(metadata.filename);
394
 
    }
395
 
 
396
 
    cli_dbgmsg("ARJ: Exit code: %d\n", ret);
397
 
    if (ret == CL_BREAK)
398
 
        ret = CL_CLEAN;
399
 
 
400
 
    return ret;
401
 
}
402
 
 
403
 
 
404
 
static int cli_scangzip_with_zib_from_the_80s(cli_ctx *ctx, unsigned char *buff) {
405
 
    int fd, ret, outsize = 0, bytes;
406
 
    fmap_t *map = *ctx->fmap;
407
 
    char *tmpname;
408
 
    gzFile gz;
409
 
 
410
 
    fd = dup(map->fd);
411
 
    if(fd < 0)
412
 
        return CL_EDUP;
413
 
 
414
 
    lseek(fd, 0, SEEK_SET);
415
 
    if(!(gz = gzdopen(fd, "rb"))) {
416
 
        close(fd);
417
 
        return CL_EOPEN;
418
 
    }
419
 
 
420
 
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
421
 
        cli_dbgmsg("GZip: Can't generate temporary file.\n");
422
 
        gzclose(gz);
423
 
        return ret;
424
 
    }
425
 
    
426
 
    while((bytes = gzread(gz, buff, FILEBUFF)) > 0) {
427
 
        outsize += bytes;
428
 
        if(cli_checklimits("GZip", ctx, outsize, 0, 0)!=CL_CLEAN)
429
 
            break;
430
 
        if(cli_writen(fd, buff, bytes) != bytes) {
431
 
            close(fd);
432
 
            gzclose(gz);
433
 
            if(cli_unlink(tmpname)) {
 
357
    }
 
358
 
 
359
    while(zip_dir_read(zdir, &zdirent)) {
 
360
        files++;
 
361
 
 
362
        if(files == 1 && sfx_check) {
 
363
            if(*sfx_check == zdirent.d_crc32)
 
364
                break;
 
365
            else
 
366
                *sfx_check = zdirent.d_crc32;
 
367
        }
 
368
 
 
369
        if(!zdirent.d_name) {
 
370
            cli_dbgmsg("Zip: zdirent.d_name == NULL\n");
 
371
            *ctx->virname = "Suspect.Zip";
 
372
            ret = CL_VIRUS;
 
373
            break;
 
374
        }
 
375
 
 
376
        /* Bit 0: file is encrypted
 
377
         * Bit 6: Strong encryption was used
 
378
         * Bit 13: Encrypted central directory
 
379
         */
 
380
        encrypted = ((zdirent.d_flags & 0x2041) != 0);
 
381
 
 
382
        cli_dbgmsg("Zip: %s, crc32: 0x%x, offset: %d, encrypted: %d, compressed: %u, normal: %u, method: %d, ratio: %d (max: %d)\n", zdirent.d_name, zdirent.d_crc32, zdirent.d_off, encrypted, zdirent.d_csize, zdirent.st_size, zdirent.d_compr, zdirent.d_csize ? (zdirent.st_size / zdirent.d_csize) : 0, ctx->limits ? ctx->limits->maxratio : 0);
 
383
 
 
384
        if(!zdirent.st_size) {
 
385
            if(zdirent.d_crc32) {
 
386
                cli_dbgmsg("Zip: Broken file or modified information in local header part of archive\n");
 
387
                *ctx->virname = "Exploit.Zip.ModifiedHeaders";
 
388
                ret = CL_VIRUS;
 
389
                break;
 
390
            }
 
391
            continue;
 
392
        }
 
393
 
 
394
        /* Scan metadata */
 
395
        mdata = ctx->engine->zip_mlist;
 
396
        if(mdata) do {
 
397
            if(mdata->encrypted != encrypted)
 
398
                continue;
 
399
 
 
400
            if(mdata->crc32 && mdata->crc32 != zdirent.d_crc32)
 
401
                continue;
 
402
 
 
403
            if(mdata->csize > 0 && (uint32_t) mdata->csize != zdirent.d_csize)
 
404
                continue;
 
405
 
 
406
            if(mdata->size >= 0 && (uint32_t) mdata->size != zdirent.st_size)
 
407
                continue;
 
408
 
 
409
            if(mdata->method >= 0 && (uint16_t) mdata->method != zdirent.d_compr)
 
410
                continue;
 
411
 
 
412
            if(mdata->fileno && mdata->fileno != files)
 
413
                continue;
 
414
 
 
415
            if(mdata->maxdepth && ctx->arec > mdata->maxdepth)
 
416
                continue;
 
417
 
 
418
            /* TODO add support for regex */
 
419
            /*if(mdata->filename && !strstr(zdirent.d_name, mdata->filename))*/
 
420
            if(mdata->filename && strcmp(zdirent.d_name, mdata->filename))
 
421
                continue;
 
422
 
 
423
            break; /* matched */
 
424
 
 
425
        } while((mdata = mdata->next));
 
426
 
 
427
        if(mdata) {
 
428
            *ctx->virname = mdata->virname;
 
429
            ret = CL_VIRUS;
 
430
            break;
 
431
        }
 
432
 
 
433
        /* 
 
434
         * Workaround for archives created with ICEOWS.
 
435
         * ZZIP_DIRENT does not contain information on file type
 
436
         * so we try to determine a directory via a filename
 
437
         */
 
438
        if(zdirent.d_name[strlen(zdirent.d_name) - 1] == '/') {
 
439
            cli_dbgmsg("Zip: Directory entry with st_size != 0\n");
 
440
            continue;
 
441
        }
 
442
 
 
443
        if(!zdirent.d_csize) {
 
444
            cli_dbgmsg("Zip: Malformed file (d_csize == 0 but st_size != 0)\n");
 
445
            *ctx->virname = "Suspect.Zip";
 
446
            ret = CL_VIRUS;
 
447
            break;
 
448
        }
 
449
 
 
450
        if(ctx->limits && ctx->limits->maxratio > 0 && ((unsigned) zdirent.st_size / (unsigned) zdirent.d_csize) >= ctx->limits->maxratio) {
 
451
            *ctx->virname = "Oversized.Zip";
 
452
            ret = CL_VIRUS;
 
453
            break;
 
454
        }
 
455
 
 
456
        if(DETECT_ENCRYPTED && encrypted) {
 
457
            cli_dbgmsg("Zip: Encrypted files found in archive.\n");
 
458
            lseek(desc, 0, SEEK_SET);
 
459
            ret = cli_scandesc(desc, ctx, 0, 0, 0, NULL);
 
460
            if(ret < 0) {
 
461
                break;
 
462
            } else if(ret != CL_VIRUS) {
 
463
                *ctx->virname = "Encrypted.Zip";
 
464
                ret = CL_VIRUS;
 
465
            }
 
466
            break;
 
467
        }
 
468
 
 
469
        if(ctx->limits) {
 
470
            if(ctx->limits->maxfilesize && ((unsigned int) zdirent.st_size > ctx->limits->maxfilesize)) {
 
471
                cli_dbgmsg("Zip: %s: Size exceeded (%d, max: %ld)\n", zdirent.d_name, zdirent.st_size, ctx->limits->maxfilesize);
 
472
                /* ret = CL_EMAXSIZE; */
 
473
                if(BLOCKMAX) {
 
474
                    *ctx->virname = "Zip.ExceededFileSize";
 
475
                    ret = CL_VIRUS;
 
476
                    break;
 
477
                }
 
478
                continue; /* continue scanning */
 
479
            }
 
480
 
 
481
            if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
 
482
                cli_dbgmsg("Zip: Files limit reached (max: %d)\n", ctx->limits->maxfiles);
 
483
                if(BLOCKMAX) {
 
484
                    *ctx->virname = "Zip.ExceededFilesLimit";
 
485
                    ret = CL_VIRUS;
 
486
                    break;
 
487
                }
 
488
                break;
 
489
            }
 
490
        }
 
491
 
 
492
        if((zfp = zip_file_open(zdir, zdirent.d_name, zdirent.d_off)) == NULL) {
 
493
            if(zdir->errcode == CL_ESUPPORT) {
 
494
                ret = CL_ESUPPORT;
 
495
                if(!swarning) {
 
496
                    cli_warnmsg("Not supported compression method in one or more files\n");
 
497
                    swarning = 1;
 
498
                }
 
499
                continue;
 
500
            } else {
 
501
                cli_dbgmsg("Zip: Can't open file %s\n", zdirent.d_name);
 
502
                ret = CL_EZIP;
 
503
                break;
 
504
            }
 
505
        }
 
506
 
 
507
        bfcnt = 0;
 
508
        success = 0;
 
509
        while(1) {
 
510
            fail = 0;
 
511
 
 
512
            /* generate temporary file and get its descriptor */
 
513
            if((tmpname = cli_gentempstream(NULL, &tmp)) == NULL) {
 
514
                cli_dbgmsg("Zip: Can't generate tmpfile().\n");
 
515
                ret = CL_ETMPFILE;
 
516
                break;
 
517
            }
 
518
 
 
519
            size = 0;
 
520
            while((bytes = zip_file_read(zfp, buff, FILEBUFF)) > 0) {
 
521
                size += bytes;
 
522
                if(fwrite(buff, 1, bytes, tmp) != (size_t) bytes) {
 
523
                    cli_dbgmsg("Zip: Can't write to file.\n");
 
524
                    ret = CL_EIO;
 
525
                    break;
 
526
                }
 
527
            }
 
528
 
 
529
            if(!encrypted) {
 
530
                if(size != zdirent.st_size) {
 
531
                    cli_dbgmsg("Zip: Incorrectly decompressed (%d != %d)\n", size, zdirent.st_size);
 
532
                    if(zfp->bf[0] == -1) {
 
533
                        ret = CL_EZIP;
 
534
                        break;
 
535
                    } else {
 
536
                        fail = 1;
 
537
                    }
 
538
                } else {
 
539
                    cli_dbgmsg("Zip: File decompressed to %s\n", tmpname);
 
540
                    success = 1;
 
541
                }
 
542
            }
 
543
 
 
544
            if(!fail) {
 
545
                if(fflush(tmp) != 0) {
 
546
                    cli_dbgmsg("Zip: fflush() failed\n");
 
547
                    ret = CL_EFSYNC;
 
548
                    break;
 
549
                }
 
550
 
 
551
                fd = fileno(tmp);
 
552
 
 
553
                lseek(fd, 0, SEEK_SET);
 
554
 
 
555
                if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
 
556
                    cli_dbgmsg("Zip: Infected with %s\n", *ctx->virname);
 
557
                    ret = CL_VIRUS;
 
558
                    break;
 
559
                }
 
560
 
 
561
            }
 
562
 
 
563
            if(tmp) {
 
564
                fclose(tmp);
 
565
                if(!cli_leavetemps_flag)
 
566
                    unlink(tmpname);
434
567
                free(tmpname);
435
 
                return CL_EUNLINK;
 
568
                tmp = NULL;
436
569
            }
437
 
            free(tmpname);
438
 
            return CL_EWRITE;
439
 
        }
 
570
 
 
571
            if(zfp->bf[bfcnt] == -1)
 
572
                break;
 
573
 
 
574
            zfp->method = (uint16_t) zfp->bf[bfcnt];
 
575
            cli_dbgmsg("Zip: Brute force mode - checking compression method %u\n", zfp->method);
 
576
            bfcnt++;
 
577
        }
 
578
        zip_file_close(zfp);
 
579
 
 
580
 
 
581
        if(!ret && !encrypted && !success) { /* brute-force decompression failed */
 
582
            cli_dbgmsg("Zip: All attempts to decompress file failed\n");
 
583
            ret = CL_EZIP;
 
584
        }
 
585
 
 
586
        if(ret) 
 
587
            break;
440
588
    }
441
589
 
442
 
    gzclose(gz);
443
 
 
444
 
    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
445
 
        cli_dbgmsg("GZip: Infected with %s\n", *ctx->virname);
446
 
        close(fd);
447
 
        if(!ctx->engine->keeptmp) {
448
 
            if (cli_unlink(tmpname)) {
449
 
                free(tmpname);
450
 
                return CL_EUNLINK;
451
 
            }
452
 
        }
 
590
    zip_dir_close(zdir);
 
591
    if(tmp) {
 
592
        fclose(tmp);
 
593
        if(!cli_leavetemps_flag)
 
594
            unlink(tmpname);
453
595
        free(tmpname);
454
 
        return CL_VIRUS;
 
596
        tmp = NULL;
455
597
    }
456
 
    close(fd);
457
 
    if(!ctx->engine->keeptmp)
458
 
        if (cli_unlink(tmpname)) ret = CL_EUNLINK;
459
 
    free(tmpname);
 
598
 
 
599
    free(buff);
460
600
    return ret;
461
601
}
462
602
 
463
 
static int cli_scangzip(cli_ctx *ctx)
 
603
static int cli_scangzip(int desc, cli_ctx *ctx)
464
604
{
465
 
        int fd, ret = CL_CLEAN;
466
 
        unsigned char buff[FILEBUFF];
 
605
        int fd, bytes, ret = CL_CLEAN;
 
606
        unsigned long int size = 0;
 
607
        char *buff;
 
608
        FILE *tmp = NULL;
467
609
        char *tmpname;
468
 
        z_stream z;
469
 
        size_t at = 0, outsize = 0;
470
 
        fmap_t *map = *ctx->fmap;
471
 
        
 
610
        gzFile gd;
 
611
 
 
612
 
472
613
    cli_dbgmsg("in cli_scangzip()\n");
473
614
 
474
 
    memset(&z, 0, sizeof(z));
475
 
    if((ret = inflateInit2(&z, MAX_WBITS + 16)) != Z_OK) {
476
 
        cli_dbgmsg("GZip: InflateInit failed: %d\n", ret);
477
 
        return cli_scangzip_with_zib_from_the_80s(ctx, buff);
 
615
    if((gd = gzdopen(dup(desc), "rb")) == NULL) {
 
616
        cli_dbgmsg("GZip: Can't open descriptor %d\n", desc);
 
617
        return CL_EGZIP;
478
618
    }
479
619
 
480
 
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
 
620
    if((tmpname = cli_gentempstream(NULL, &tmp)) == NULL) {
481
621
        cli_dbgmsg("GZip: Can't generate temporary file.\n");
482
 
        inflateEnd(&z);
 
622
        gzclose(gd);
 
623
        return CL_ETMPFILE;
 
624
    }
 
625
    fd = fileno(tmp);
 
626
 
 
627
    if(!(buff = (char *) cli_malloc(FILEBUFF))) {
 
628
        cli_dbgmsg("GZip: Unable to malloc %d bytes.\n", FILEBUFF);
 
629
        gzclose(gd);
 
630
        fclose(tmp);
 
631
        if(!cli_leavetemps_flag)
 
632
            unlink(tmpname);
 
633
        free(tmpname);  
 
634
        return CL_EMEM;
 
635
    }
 
636
 
 
637
    while((bytes = gzread(gd, buff, FILEBUFF)) > 0) {
 
638
        size += bytes;
 
639
 
 
640
        if(ctx->limits)
 
641
            if(ctx->limits->maxfilesize && (size + FILEBUFF > ctx->limits->maxfilesize)) {
 
642
                cli_dbgmsg("GZip: Size exceeded (stopped at %ld, max: %ld)\n", size, ctx->limits->maxfilesize);
 
643
                if(BLOCKMAX) {
 
644
                    *ctx->virname = "GZip.ExceededFileSize";
 
645
                    ret = CL_VIRUS;
 
646
                }
 
647
                break;
 
648
            }
 
649
 
 
650
        if(cli_writen(fd, buff, bytes) != bytes) {
 
651
            cli_dbgmsg("GZip: Can't write to file.\n");
 
652
            fclose(tmp);
 
653
            if(!cli_leavetemps_flag)
 
654
                unlink(tmpname);
 
655
            free(tmpname);      
 
656
            gzclose(gd);
 
657
            free(buff);
 
658
            return CL_EGZIP;
 
659
        }
 
660
    }
 
661
 
 
662
    free(buff);
 
663
    gzclose(gd);
 
664
 
 
665
    if(ret == CL_VIRUS) {
 
666
        fclose(tmp);
 
667
        if(!cli_leavetemps_flag)
 
668
            unlink(tmpname);
 
669
        free(tmpname);  
483
670
        return ret;
484
671
    }
485
672
 
486
 
    while (at < map->len) {
487
 
        unsigned int bytes = MIN(map->len - at, map->pgsz);
488
 
        if(!(z.next_in = fmap_need_off_once(map, at, bytes))) {
489
 
            cli_dbgmsg("GZip: Can't read %u bytes @ %lu.\n", bytes, (long unsigned)at);
490
 
            inflateEnd(&z);
491
 
            close(fd);
492
 
            if (cli_unlink(tmpname)) {
493
 
                free(tmpname);
494
 
                return CL_EUNLINK;
495
 
            }
496
 
            free(tmpname);
497
 
            return CL_EREAD;
498
 
        }
499
 
        at += bytes;
500
 
        z.avail_in = bytes;
501
 
        do {
502
 
            int inf;
503
 
            z.avail_out = sizeof(buff);
504
 
            z.next_out = buff;
505
 
            inf = inflate(&z, Z_NO_FLUSH);
506
 
            if(inf != Z_OK && inf != Z_STREAM_END && inf != Z_BUF_ERROR) {
507
 
                cli_dbgmsg("GZip: Bad stream.\n");
508
 
                at = map->len;
509
 
                break;
510
 
            }
511
 
            if(cli_writen(fd, buff, sizeof(buff) - z.avail_out) < 0) {
512
 
                inflateEnd(&z);     
513
 
                close(fd);
514
 
                if (cli_unlink(tmpname)) {
515
 
                    free(tmpname);
516
 
                    return CL_EUNLINK;
517
 
                }
518
 
                free(tmpname);
519
 
                return CL_EWRITE;
520
 
            }
521
 
            outsize += sizeof(buff) - z.avail_out;
522
 
            if(cli_checklimits("GZip", ctx, outsize, 0, 0)!=CL_CLEAN) {
523
 
                at = map->len;
524
 
                break;
525
 
            }
526
 
            if(inf == Z_STREAM_END) {
527
 
                at -= z.avail_in;
528
 
                inflateReset(&z);
529
 
                break;
530
 
            }
531
 
        } while (z.avail_out == 0);
 
673
    if(fsync(fd) == -1) {
 
674
        cli_dbgmsg("GZip: Can't synchronise descriptor %d\n", fd);
 
675
        fclose(tmp);
 
676
        if(!cli_leavetemps_flag)
 
677
            unlink(tmpname);
 
678
        free(tmpname);  
 
679
        return CL_EFSYNC;
532
680
    }
533
681
 
534
 
    inflateEnd(&z);         
535
 
 
536
 
    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
 
682
    lseek(fd, 0, SEEK_SET);
 
683
    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
537
684
        cli_dbgmsg("GZip: Infected with %s\n", *ctx->virname);
538
 
        close(fd);
539
 
        if(!ctx->engine->keeptmp) {
540
 
            if (cli_unlink(tmpname)) {
541
 
                free(tmpname);
542
 
                return CL_EUNLINK;
543
 
            }
544
 
        }
545
 
        free(tmpname);
 
685
        fclose(tmp);
 
686
        if(!cli_leavetemps_flag)
 
687
            unlink(tmpname);
 
688
        free(tmpname);  
546
689
        return CL_VIRUS;
547
690
    }
548
 
    close(fd);
549
 
    if(!ctx->engine->keeptmp)
550
 
        if (cli_unlink(tmpname)) ret = CL_EUNLINK;
551
 
    free(tmpname);
 
691
    fclose(tmp);
 
692
    if(!cli_leavetemps_flag)
 
693
        unlink(tmpname);
 
694
    free(tmpname);      
 
695
 
552
696
    return ret;
553
697
}
554
 
 
555
 
 
556
 
#ifndef HAVE_BZLIB_H
557
 
static int cli_scanbzip(int desc, cli_ctx *ctx) {
558
 
    cli_warnmsg("cli_scanbzip: bzip2 support not compiled in\n");
559
 
    return CL_CLEAN;
560
 
}
561
 
 
562
 
#else
 
698
#endif
 
699
 
 
700
#ifdef HAVE_BZLIB_H
563
701
 
564
702
#ifdef NOBZ2PREFIX
565
703
#define BZ2_bzReadOpen bzReadOpen
570
708
static int cli_scanbzip(int desc, cli_ctx *ctx)
571
709
{
572
710
        int fd, bytes, ret = CL_CLEAN, bzerror = 0;
 
711
        short memlim = 0;
573
712
        unsigned long int size = 0;
574
713
        char *buff;
575
 
        FILE *fs;
 
714
        FILE *fs, *tmp = NULL;
576
715
        char *tmpname;
577
716
        BZFILE *bfd;
578
717
 
579
718
 
580
719
    if((fs = fdopen(dup(desc), "rb")) == NULL) {
581
720
        cli_dbgmsg("Bzip: Can't open descriptor %d.\n", desc);
582
 
        return CL_EOPEN;
 
721
        return CL_EBZIP;
583
722
    }
584
723
 
585
 
    if((bfd = BZ2_bzReadOpen(&bzerror, fs, 0, 0, NULL, 0)) == NULL) {
 
724
    if(ctx->limits)
 
725
        if(ctx->limits->archivememlim)
 
726
            memlim = 1;
 
727
 
 
728
    if((bfd = BZ2_bzReadOpen(&bzerror, fs, 0, memlim, NULL, 0)) == NULL) {
586
729
        cli_dbgmsg("Bzip: Can't initialize bzip2 library (descriptor: %d).\n", desc);
587
730
        fclose(fs);
588
 
        return CL_EOPEN;
 
731
        return CL_EBZIP;
589
732
    }
590
733
 
591
 
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd))) {
 
734
    if((tmpname = cli_gentempstream(NULL, &tmp)) == NULL) {
592
735
        cli_dbgmsg("Bzip: Can't generate temporary file.\n");
593
736
        BZ2_bzReadClose(&bzerror, bfd);
594
737
        fclose(fs);
595
 
        return ret;
 
738
        return CL_ETMPFILE;
596
739
    }
 
740
    fd = fileno(tmp);
597
741
 
598
742
    if(!(buff = (char *) cli_malloc(FILEBUFF))) {
599
743
        cli_dbgmsg("Bzip: Unable to malloc %u bytes.\n", FILEBUFF);
600
 
        close(fd);
601
 
        if(!ctx->engine->keeptmp) {
602
 
            if (cli_unlink(tmpname)) {
603
 
                free(tmpname);
604
 
                fclose(fs);
605
 
                BZ2_bzReadClose(&bzerror, bfd);
606
 
                return CL_EUNLINK;
607
 
            }
608
 
        }
 
744
        fclose(tmp);
 
745
        if(!cli_leavetemps_flag)
 
746
            unlink(tmpname);
609
747
        free(tmpname);  
610
748
        fclose(fs);
611
749
        BZ2_bzReadClose(&bzerror, bfd);
615
753
    while((bytes = BZ2_bzRead(&bzerror, bfd, buff, FILEBUFF)) > 0) {
616
754
        size += bytes;
617
755
 
618
 
        if(cli_checklimits("Bzip", ctx, size + FILEBUFF, 0, 0)!=CL_CLEAN)
619
 
            break;
 
756
        if(ctx->limits)
 
757
            if(ctx->limits->maxfilesize && (size + FILEBUFF > ctx->limits->maxfilesize)) {
 
758
                cli_dbgmsg("Bzip: Size exceeded (stopped at %ld, max: %ld)\n", size, ctx->limits->maxfilesize);
 
759
                if(BLOCKMAX) {
 
760
                    *ctx->virname = "BZip.ExceededFileSize";
 
761
                    ret = CL_VIRUS;
 
762
                }
 
763
                break;
 
764
            }
620
765
 
621
766
        if(cli_writen(fd, buff, bytes) != bytes) {
622
767
            cli_dbgmsg("Bzip: Can't write to file.\n");
623
768
            BZ2_bzReadClose(&bzerror, bfd);
624
 
            close(fd);
625
 
            if(!ctx->engine->keeptmp) {
626
 
                if (cli_unlink(tmpname)) {
627
 
                    free(tmpname);
628
 
                    free(buff);
629
 
                    fclose(fs);
630
 
                    return CL_EUNLINK;
631
 
                }
632
 
            }
 
769
            fclose(tmp);
 
770
            if(!cli_leavetemps_flag)
 
771
                unlink(tmpname);
633
772
            free(tmpname);      
634
773
            free(buff);
635
774
            fclose(fs);
636
 
            return CL_EWRITE;
 
775
            return CL_EGZIP;
637
776
        }
638
777
    }
639
778
 
641
780
    BZ2_bzReadClose(&bzerror, bfd);
642
781
 
643
782
    if(ret == CL_VIRUS) {
644
 
        close(fd);
645
 
        if(!ctx->engine->keeptmp)
646
 
            if (cli_unlink(tmpname)) ret = CL_EUNLINK;
 
783
        fclose(tmp);
 
784
        if(!cli_leavetemps_flag)
 
785
            unlink(tmpname);
647
786
        free(tmpname);  
648
787
        fclose(fs);
649
788
        return ret;
650
789
    }
651
790
 
 
791
    if(fsync(fd) == -1) {
 
792
        cli_dbgmsg("Bzip: Synchronisation failed for descriptor %d\n", fd);
 
793
        fclose(tmp);
 
794
        if(!cli_leavetemps_flag)
 
795
            unlink(tmpname);
 
796
        free(tmpname);  
 
797
        fclose(fs);
 
798
        return CL_EFSYNC;
 
799
    }
 
800
 
652
801
    lseek(fd, 0, SEEK_SET);
653
802
    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
654
803
        cli_dbgmsg("Bzip: Infected with %s\n", *ctx->virname);
655
804
    }
656
 
    close(fd);
657
 
    if(!ctx->engine->keeptmp)
658
 
        if (cli_unlink(tmpname)) ret = CL_EUNLINK;
 
805
    fclose(tmp);
 
806
    if(!cli_leavetemps_flag)
 
807
        unlink(tmpname);
659
808
    free(tmpname);      
660
809
    fclose(fs);
661
810
 
665
814
 
666
815
static int cli_scanszdd(int desc, cli_ctx *ctx)
667
816
{
668
 
        int ofd, ret;
 
817
        int fd, ret = CL_CLEAN, dcpy;
 
818
        FILE *tmp = NULL, *in;
669
819
        char *tmpname;
670
820
 
671
821
 
672
822
    cli_dbgmsg("in cli_scanszdd()\n");
673
823
 
674
 
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &ofd))) {
675
 
        cli_dbgmsg("MSEXPAND: Can't generate temporary file/descriptor\n");
676
 
        return ret;
677
 
    }
678
 
 
679
 
    lseek(desc, 0, SEEK_SET);
680
 
    ret = cli_msexpand(desc, ofd, ctx);
681
 
 
682
 
    if(ret != CL_SUCCESS) { /* CL_VIRUS or some error */
683
 
        close(ofd);
684
 
        if(!ctx->engine->keeptmp)
685
 
            if (cli_unlink(tmpname)) ret = CL_EUNLINK;
686
 
        free(tmpname);  
687
 
        return ret;
688
 
    }
689
 
 
690
 
    cli_dbgmsg("MSEXPAND: Decompressed into %s\n", tmpname);
691
 
    lseek(ofd, 0, SEEK_SET);
692
 
    ret = cli_magic_scandesc(ofd, ctx);
693
 
    close(ofd);
694
 
    if(!ctx->engine->keeptmp)
695
 
        if (cli_unlink(tmpname)) ret = CL_EUNLINK;
 
824
    if((dcpy = dup(desc)) == -1) {
 
825
        cli_dbgmsg("SZDD: Can't duplicate descriptor %d\n", desc);
 
826
        return CL_EIO;
 
827
    }
 
828
 
 
829
    if((in = fdopen(dcpy, "rb")) == NULL) {
 
830
        cli_dbgmsg("SZDD: Can't open descriptor %d\n", desc);
 
831
        close(dcpy);
 
832
        return CL_EMSCOMP;
 
833
    }
 
834
 
 
835
    if((tmpname = cli_gentempstream(NULL, &tmp)) == NULL) {
 
836
        cli_dbgmsg("SZDD: Can't generate temporary file.\n");
 
837
        fclose(in);
 
838
        return CL_ETMPFILE;
 
839
    }
 
840
 
 
841
    if(cli_msexpand(in, tmp) == -1) {
 
842
        cli_dbgmsg("SZDD: msexpand failed.\n");
 
843
        fclose(in);
 
844
        fclose(tmp);
 
845
        if(!cli_leavetemps_flag)
 
846
            unlink(tmpname);
 
847
        free(tmpname);  
 
848
        return CL_EMSCOMP;
 
849
    }
 
850
 
 
851
    fclose(in);
 
852
    if(fflush(tmp)) {
 
853
        cli_dbgmsg("SZDD: fflush() failed.\n");
 
854
        fclose(tmp);
 
855
        if(!cli_leavetemps_flag)
 
856
            unlink(tmpname);
 
857
        free(tmpname);  
 
858
        return CL_EFSYNC;
 
859
    }
 
860
 
 
861
    fd = fileno(tmp);
 
862
    lseek(fd, 0, SEEK_SET);
 
863
    if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
 
864
        cli_dbgmsg("SZDD: Infected with %s\n", *ctx->virname);
 
865
        fclose(tmp);
 
866
        if(!cli_leavetemps_flag)
 
867
            unlink(tmpname);
 
868
        free(tmpname);  
 
869
        return CL_VIRUS;
 
870
    }
 
871
 
 
872
    fclose(tmp);
 
873
    if(!cli_leavetemps_flag)
 
874
        unlink(tmpname);
696
875
    free(tmpname);      
697
 
 
698
876
    return ret;
699
877
}
700
878
 
705
883
        unsigned int files = 0;
706
884
        struct cab_archive cab;
707
885
        struct cab_file *file;
708
 
        unsigned int corrupted_input;
709
886
 
710
887
 
711
888
    cli_dbgmsg("in cli_scanmscab()\n");
716
893
    for(file = cab.files; file; file = file->next) {
717
894
        files++;
718
895
 
719
 
        if(cli_matchmeta(ctx, file->name, 0, file->length, 0, files, 0, NULL) == CL_VIRUS) {
720
 
            ret = CL_VIRUS;
721
 
            break;
722
 
        }
723
 
 
724
 
        if(ctx->engine->maxscansize && ctx->scansize >= ctx->engine->maxscansize) {
725
 
            ret = CL_CLEAN;
726
 
            break;
727
 
        }
728
 
 
729
 
        if(!(tempname = cli_gentemp(ctx->engine->tmpdir))) {
730
 
            ret = CL_EMEM;
731
 
            break;
732
 
        }
733
 
 
734
 
        if(ctx->engine->maxscansize && ctx->scansize + ctx->engine->maxfilesize >= ctx->engine->maxscansize)
735
 
            file->max_size = ctx->engine->maxscansize - ctx->scansize;
736
 
        else
737
 
            file->max_size = ctx->engine->maxfilesize ? ctx->engine->maxfilesize : 0xffffffff;
738
 
 
739
 
        cli_dbgmsg("CAB: Extracting file %s to %s, size %u, max_size: %u\n", file->name, tempname, file->length, (unsigned int) file->max_size);
740
 
        file->written_size = 0;
741
 
        if((ret = cab_extract(file, tempname))) {
 
896
        if(ctx->limits && ctx->limits->maxfilesize && (file->length > ctx->limits->maxfilesize)) {
 
897
            cli_dbgmsg("CAB: %s: Size exceeded (%u, max: %u)\n", file->name, file->length, ctx->limits->maxfilesize);
 
898
            if(BLOCKMAX) {
 
899
                *ctx->virname = "CAB.ExceededFileSize";
 
900
                cab_free(&cab);
 
901
                return CL_VIRUS;
 
902
            }
 
903
            continue;
 
904
        }
 
905
 
 
906
        if(ctx->limits && ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
 
907
            cli_dbgmsg("CAB: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
 
908
            cab_free(&cab);
 
909
            if(BLOCKMAX) {
 
910
                *ctx->virname = "CAB.ExceededFilesLimit";
 
911
                return CL_VIRUS;
 
912
            }
 
913
            return CL_CLEAN;
 
914
        }
 
915
 
 
916
        tempname = cli_gentemp(NULL);
 
917
        cli_dbgmsg("CAB: Extracting file %s to %s, size %u\n", file->name, tempname, file->length);
 
918
        if((ret = cab_extract(file, tempname)))
742
919
            cli_dbgmsg("CAB: Failed to extract file: %s\n", cl_strerror(ret));
743
 
        } else {
744
 
            corrupted_input = ctx->corrupted_input;
745
 
            if(file->length != file->written_size) {
746
 
                cli_dbgmsg("CAB: Length from header %u but wrote %u bytes\n", (unsigned int) file->length, (unsigned int) file->written_size);
747
 
                ctx->corrupted_input = 1;
748
 
            }
 
920
        else
749
921
            ret = cli_scanfile(tempname, ctx);
750
 
            ctx->corrupted_input = corrupted_input;
751
 
        }
752
 
        if(!ctx->engine->keeptmp) {
753
 
            if (!access(tempname, R_OK) && cli_unlink(tempname)) {
754
 
                free(tempname);
755
 
                ret = CL_EUNLINK;
756
 
                break;
757
 
            }
758
 
        }
 
922
 
 
923
        if(!cli_leavetemps_flag)
 
924
            unlink(tempname);
759
925
        free(tempname);
760
926
        if(ret == CL_VIRUS)
761
927
            break;
765
931
    return ret;
766
932
}
767
933
 
768
 
static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
769
 
{
770
 
        int ret = CL_CLEAN, i, j, fd, data_len, hasmacros = 0;
 
934
int cli_scandir(const char *dirname, cli_ctx *ctx)
 
935
{
 
936
        DIR *dd;
 
937
        struct dirent *dent;
 
938
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
 
939
        union {
 
940
            struct dirent d;
 
941
            char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
 
942
        } result;
 
943
#endif
 
944
        struct stat statbuf;
 
945
        char *fname;
 
946
 
 
947
 
 
948
    if((dd = opendir(dirname)) != NULL) {
 
949
#ifdef HAVE_READDIR_R_3
 
950
        while(!readdir_r(dd, &result.d, &dent) && dent) {
 
951
#elif defined(HAVE_READDIR_R_2)
 
952
        while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
 
953
#else
 
954
        while((dent = readdir(dd))) {
 
955
#endif
 
956
#if     (!defined(C_CYGWIN)) && (!defined(C_INTERIX)) && (!defined(C_WINDOWS))
 
957
            if(dent->d_ino)
 
958
#endif
 
959
            {
 
960
                if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
 
961
                    /* build the full name */
 
962
                    fname = cli_calloc(strlen(dirname) + strlen(dent->d_name) + 2, sizeof(char));
 
963
                    if(!fname) {
 
964
                        closedir(dd);
 
965
                        return CL_EMEM;
 
966
                    }
 
967
 
 
968
                    sprintf(fname, "%s/%s", dirname, dent->d_name);
 
969
 
 
970
                    /* stat the file */
 
971
                    if(lstat(fname, &statbuf) != -1) {
 
972
                        if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {
 
973
                            if (cli_scandir(fname, ctx) == CL_VIRUS) {
 
974
                                free(fname);
 
975
                                closedir(dd);
 
976
                                return CL_VIRUS;
 
977
                            }
 
978
                        } else
 
979
                            if(S_ISREG(statbuf.st_mode))
 
980
                                if(cli_scanfile(fname, ctx) == CL_VIRUS) {
 
981
                                    free(fname);
 
982
                                    closedir(dd);
 
983
                                    return CL_VIRUS;
 
984
                                }
 
985
 
 
986
                    }
 
987
                    free(fname);
 
988
                }
 
989
            }
 
990
        }
 
991
    } else {
 
992
        cli_dbgmsg("ScanDir: Can't open directory %s.\n", dirname);
 
993
        return CL_EOPEN;
 
994
    }
 
995
 
 
996
    closedir(dd);
 
997
    return 0;
 
998
}
 
999
 
 
1000
static int cli_vba_scandir(const char *dirname, cli_ctx *ctx)
 
1001
{
 
1002
        int ret = CL_CLEAN, i, fd, ofd, data_len;
771
1003
        vba_project_t *vba_project;
772
1004
        DIR *dd;
773
1005
        struct dirent *dent;
778
1010
        } result;
779
1011
#endif
780
1012
        struct stat statbuf;
781
 
        char *fullname, vbaname[1024];
 
1013
        char *fname, *fullname;
782
1014
        unsigned char *data;
783
 
        char *hash;
784
 
        uint32_t hashcnt;
785
1015
 
786
1016
 
787
1017
    cli_dbgmsg("VBADir: %s\n", dirname);
788
 
    hashcnt = uniq_get(U, "_vba_project", 12, NULL);
789
 
    while(hashcnt--) {
790
 
        if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue;
 
1018
    if((vba_project = (vba_project_t *) vba56_dir_read(dirname))) {
791
1019
 
792
1020
        for(i = 0; i < vba_project->count; i++) {
793
 
            for(j = 0; (unsigned int)j < vba_project->colls[i]; j++) {
794
 
                snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", vba_project->dir, vba_project->name[i], j);
795
 
                vbaname[sizeof(vbaname)-1] = '\0';
796
 
                fd = open(vbaname, O_RDONLY|O_BINARY);
797
 
                if(fd == -1) continue;
798
 
                cli_dbgmsg("VBADir: Decompress VBA project '%s_%u'\n", vba_project->name[i], j);
799
 
                data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
800
 
                close(fd);
801
 
                hasmacros++;
802
 
                if(!data) {
803
 
                    cli_dbgmsg("VBADir: WARNING: VBA project '%s_%u' decompressed to NULL\n", vba_project->name[i], j);
804
 
                } else {
805
 
                    /* cli_dbgmsg("Project content:\n%s", data); */
806
 
                    if(ctx->scanned)
807
 
                        *ctx->scanned += data_len / CL_COUNT_PRECISION;
808
 
                    if(cli_scanbuff(data, data_len, 0, ctx, CL_TYPE_MSOLE2, NULL) == CL_VIRUS) {
809
 
                        free(data);
810
 
                        ret = CL_VIRUS;
811
 
                        break;
812
 
                    }
 
1021
            fullname = (char *) cli_malloc(strlen(vba_project->dir) + strlen(vba_project->name[i]) + 2);
 
1022
            if(!fullname) {
 
1023
                ret = CL_EMEM;
 
1024
                break;
 
1025
            }
 
1026
            sprintf(fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
 
1027
            fd = open(fullname, O_RDONLY|O_BINARY);
 
1028
            if(fd == -1) {
 
1029
                cli_dbgmsg("VBADir: Can't open file %s\n", fullname);
 
1030
                free(fullname);
 
1031
                ret = CL_EOPEN;
 
1032
                break;
 
1033
            }
 
1034
            free(fullname);
 
1035
            cli_dbgmsg("VBADir: Decompress VBA project '%s'\n", vba_project->name[i]);
 
1036
            data = (unsigned char *) vba_decompress(fd, vba_project->offset[i], &data_len);
 
1037
            close(fd);
 
1038
 
 
1039
            if(!data) {
 
1040
                cli_dbgmsg("VBADir: WARNING: VBA project '%s' decompressed to NULL\n", vba_project->name[i]);
 
1041
            } else {
 
1042
                if(ctx->scanned)
 
1043
                    *ctx->scanned += data_len / CL_COUNT_PRECISION;
 
1044
 
 
1045
                if(cli_scanbuff(data, data_len, ctx->virname, ctx->engine, CL_TYPE_MSOLE2) == CL_VIRUS) {
813
1046
                    free(data);
 
1047
                    ret = CL_VIRUS;
 
1048
                    break;
814
1049
                }
 
1050
 
 
1051
                free(data);
815
1052
            }
816
1053
        }
817
1054
 
 
1055
        for(i = 0; i < vba_project->count; i++)
 
1056
            free(vba_project->name[i]);
818
1057
        free(vba_project->name);
819
 
        free(vba_project->colls);
820
1058
        free(vba_project->dir);
821
1059
        free(vba_project->offset);
822
1060
        free(vba_project);
823
 
        if (ret == CL_VIRUS) break;
824
 
    }
825
 
 
826
 
    if(ret == CL_CLEAN && (hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
827
 
        while(hashcnt--) {
828
 
            snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
829
 
            vbaname[sizeof(vbaname)-1] = '\0';
830
 
            fd = open(vbaname, O_RDONLY|O_BINARY);
831
 
            if (fd == -1) continue;
832
 
            if ((fullname = cli_ppt_vba_read(fd, ctx))) {
833
 
                hasmacros++;
834
 
                if(cli_scandir(fullname, ctx) == CL_VIRUS) {
835
 
                    ret = CL_VIRUS;
836
 
                }
837
 
                if(!ctx->engine->keeptmp)
838
 
                    cli_rmdirs(fullname);
 
1061
    } else if ((fullname = ppt_vba_read(dirname))) {
 
1062
        if(cli_scandir(fullname, ctx) == CL_VIRUS) {
 
1063
            ret = CL_VIRUS;
 
1064
        }
 
1065
        if(!cli_leavetemps_flag)
 
1066
            cli_rmdirs(fullname);
 
1067
        free(fullname);
 
1068
    } else if ((vba_project = (vba_project_t *) wm_dir_read(dirname))) {
 
1069
        for (i = 0; i < vba_project->count; i++) {
 
1070
                fullname = (char *) cli_malloc(strlen(vba_project->dir) + strlen(vba_project->name[i]) + 2);
 
1071
                if(!fullname) {
 
1072
                    ret = CL_EMEM;
 
1073
                    break;
 
1074
                }
 
1075
                sprintf(fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
 
1076
                fd = open(fullname, O_RDONLY|O_BINARY);
 
1077
                if(fd == -1) {
 
1078
                        cli_dbgmsg("VBADir: Can't open file %s\n", fullname);
 
1079
                        free(fullname);
 
1080
                        ret = CL_EOPEN;
 
1081
                        break;
 
1082
                }
839
1083
                free(fullname);
840
 
            }
841
 
            close(fd);
842
 
        }
843
 
    }
844
 
 
845
 
    if (ret == CL_CLEAN && (hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
846
 
        while(hashcnt--) {
847
 
            snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
848
 
            vbaname[sizeof(vbaname)-1] = '\0';
849
 
            fd = open(vbaname, O_RDONLY|O_BINARY);
850
 
            if (fd == -1) continue;
851
 
            
852
 
            if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) {
 
1084
                cli_dbgmsg("VBADir: Decompress WM project '%s' macro:%d key:%d length:%d\n", vba_project->name[i], i, vba_project->key[i], vba_project->length[i]);
 
1085
                if(vba_project->length[i])
 
1086
                    data = (unsigned char *) wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]);
 
1087
                else
 
1088
                    data = NULL;
853
1089
                close(fd);
854
 
                continue;
855
 
            }
856
 
 
857
 
            for (i = 0; i < vba_project->count; i++) {
858
 
                cli_dbgmsg("VBADir: Decompress WM project macro:%d key:%d length:%d\n", i, vba_project->key[i], vba_project->length[i]);
859
 
                data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]);
860
 
                hasmacros++;
 
1090
                
861
1091
                if(!data) {
862
1092
                        cli_dbgmsg("VBADir: WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i);
863
1093
                } else {
864
 
                        cli_dbgmsg("Project content:\n%s", data);
865
1094
                        if(ctx->scanned)
866
1095
                            *ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION;
867
 
                        if(cli_scanbuff(data, vba_project->length[i], 0, ctx, CL_TYPE_MSOLE2, NULL) == CL_VIRUS) {
 
1096
                        if(cli_scanbuff(data, vba_project->length[i], ctx->virname, ctx->engine, CL_TYPE_MSOLE2) == CL_VIRUS) {
868
1097
                                free(data);
869
1098
                                ret = CL_VIRUS;
870
1099
                                break;
871
1100
                        }
872
1101
                        free(data);
873
1102
                }
874
 
            }
875
 
 
876
 
            close(fd);
877
 
            free(vba_project->name);
878
 
            free(vba_project->colls);
879
 
            free(vba_project->dir);
880
 
            free(vba_project->offset);
881
 
            free(vba_project->key);
882
 
            free(vba_project->length);
883
 
            free(vba_project);
884
 
            if(ret == CL_VIRUS) break;
885
1103
        }
 
1104
        for(i = 0; i < vba_project->count; i++)
 
1105
            free(vba_project->name[i]);
 
1106
        free(vba_project->key);
 
1107
        free(vba_project->length);
 
1108
        free(vba_project->offset);
 
1109
        free(vba_project->name);
 
1110
        free(vba_project->dir);
 
1111
        free(vba_project);
886
1112
    }
887
1113
 
888
1114
    if(ret != CL_CLEAN)
889
1115
        return ret;
890
1116
 
891
1117
    /* Check directory for embedded OLE objects */
892
 
    hashcnt = uniq_get(U, "_1_ole10native", 14, &hash);
893
 
    while(hashcnt--) {
894
 
        snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
895
 
        vbaname[sizeof(vbaname)-1] = '\0';
 
1118
    fullname = (char *) cli_malloc(strlen(dirname) + 16);
 
1119
    if(!fullname)
 
1120
        return CL_EMEM;
896
1121
 
897
 
        fd = open(vbaname, O_RDONLY|O_BINARY);
898
 
        if (fd >= 0) {
899
 
            ret = cli_scan_ole10(fd, ctx);
900
 
            close(fd);
901
 
            if(ret != CL_CLEAN)
902
 
                return ret;
 
1122
    sprintf(fullname, "%s/_1_Ole10Native", dirname);
 
1123
    fd = open(fullname, O_RDONLY|O_BINARY);
 
1124
    free(fullname);
 
1125
    if (fd >= 0) {
 
1126
        ofd = cli_decode_ole_object(fd, dirname);
 
1127
        if (ofd >= 0) {
 
1128
                ret = cli_scandesc(ofd, ctx, 0, 0, 0, NULL);
 
1129
                close(ofd);
903
1130
        }
 
1131
        close(fd);
 
1132
        if(ret != CL_CLEAN)
 
1133
            return ret;
904
1134
    }
905
1135
 
906
 
 
907
 
    /* ACAB: since we now hash filenames and handle collisions we
908
 
     * could avoid recursion by removing the block below and by
909
 
     * flattening the paths in ole2_walk_property_tree (case 1) */
910
 
 
911
1136
    if((dd = opendir(dirname)) != NULL) {
912
1137
#ifdef HAVE_READDIR_R_3
913
1138
        while(!readdir_r(dd, &result.d, &dent) && dent) {
916
1141
#else
917
1142
        while((dent = readdir(dd))) {
918
1143
#endif
 
1144
#if     (!defined(C_CYGWIN)) && (!defined(C_INTERIX)) && (!defined(C_WINDOWS))
919
1145
            if(dent->d_ino)
 
1146
#endif
920
1147
            {
921
1148
                if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
922
1149
                    /* build the full name */
923
 
                    fullname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
924
 
                    if(!fullname) {
 
1150
                    fname = cli_calloc(strlen(dirname) + strlen(dent->d_name) + 2, sizeof(char));
 
1151
                    if(!fname) {
925
1152
                        ret = CL_EMEM;
926
1153
                        break;
927
1154
                    }
928
 
                    sprintf(fullname, "%s"PATHSEP"%s", dirname, dent->d_name);
 
1155
                    sprintf(fname, "%s/%s", dirname, dent->d_name);
929
1156
 
930
1157
                    /* stat the file */
931
 
                    if(lstat(fullname, &statbuf) != -1) {
 
1158
                    if(lstat(fname, &statbuf) != -1) {
932
1159
                        if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
933
 
                          if (cli_vba_scandir(fullname, ctx, U) == CL_VIRUS) {
 
1160
                            if (cli_vba_scandir(fname, ctx) == CL_VIRUS) {
934
1161
                                ret = CL_VIRUS;
935
 
                                free(fullname);
 
1162
                                free(fname);
936
1163
                                break;
937
1164
                            }
938
1165
                    }
939
 
                    free(fullname);
 
1166
                    free(fname);
940
1167
                }
941
1168
            }
942
1169
        }
946
1173
    }
947
1174
 
948
1175
    closedir(dd);
949
 
    if(BLOCK_MACROS && hasmacros) {
950
 
        *ctx->virname = "Heuristics.OLE2.ContainsMacros";
951
 
        ret = CL_VIRUS;
952
 
    }
953
1176
    return ret;
954
1177
}
955
1178
 
956
 
static int cli_scanhtml(cli_ctx *ctx)
 
1179
static int cli_scanhtml(int desc, cli_ctx *ctx)
957
1180
{
958
1181
        char *tempname, fullname[1024];
959
1182
        int ret=CL_CLEAN, fd;
960
 
        fmap_t *map = *ctx->fmap;
 
1183
        struct stat sb;
 
1184
 
961
1185
 
962
1186
    cli_dbgmsg("in cli_scanhtml()\n");
963
1187
 
 
1188
    if(fstat(desc, &sb) == -1) {
 
1189
        cli_errmsg("cli_scanhtml: fstat() failed for descriptor %d\n", desc);
 
1190
        return CL_EIO;
 
1191
    }
 
1192
 
964
1193
    /* Because HTML detection is FP-prone and html_normalise_fd() needs to
965
1194
     * mmap the file don't normalise files larger than 10 MB.
966
1195
     */
967
 
 
968
 
    if(map->len > 10485760) {
 
1196
    if(sb.st_size > 10485760) {
969
1197
        cli_dbgmsg("cli_scanhtml: exiting (file larger than 10 MB)\n");
970
1198
        return CL_CLEAN;
971
1199
    }
972
1200
 
973
 
    if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
974
 
        return CL_EMEM;
975
 
 
 
1201
    tempname = cli_gentemp(NULL);
976
1202
    if(mkdir(tempname, 0700)) {
977
1203
        cli_errmsg("cli_scanhtml: Can't create temporary directory %s\n", tempname);
978
1204
        free(tempname);
979
1205
        return CL_ETMPDIR;
980
1206
    }
981
1207
 
982
 
    cli_dbgmsg("cli_scanhtml: using tempdir %s\n", tempname);
983
 
 
984
 
    html_normalise_map(map, tempname, NULL, ctx->dconf);
985
 
    snprintf(fullname, 1024, "%s"PATHSEP"nocomment.html", tempname);
 
1208
    html_normalise_fd(desc, tempname, NULL);
 
1209
    snprintf(fullname, 1024, "%s/comment.html", tempname);
986
1210
    fd = open(fullname, O_RDONLY|O_BINARY);
987
1211
    if (fd >= 0) {
988
 
            ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
989
 
            close(fd);
990
 
    }
991
 
 
992
 
    if(ret == CL_CLEAN && map->len < 2097152) {
993
 
            /* limit to 2 MB, we're not interesting in scanning large files in notags form */
994
 
            /* TODO: don't even create notags if file is over 2 MB */
995
 
            snprintf(fullname, 1024, "%s"PATHSEP"notags.html", tempname);
996
 
            fd = open(fullname, O_RDONLY|O_BINARY);
997
 
            if(fd >= 0) {
998
 
                    ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
999
 
                    close(fd);
1000
 
            }
1001
 
    }
1002
 
 
1003
 
    if(ret == CL_CLEAN) {
1004
 
            snprintf(fullname, 1024, "%s"PATHSEP"javascript", tempname);
1005
 
            fd = open(fullname, O_RDONLY|O_BINARY);
1006
 
            if(fd >= 0) {
1007
 
                    ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
1008
 
                    if (ret == CL_CLEAN) {
1009
 
                            lseek(fd, 0, SEEK_SET);
1010
 
                            ret = cli_scandesc(fd, ctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL);
1011
 
                    }
1012
 
                    close(fd);
1013
 
            }
1014
 
    }
1015
 
 
1016
 
    if (ret == CL_CLEAN) {
1017
 
        snprintf(fullname, 1024, "%s"PATHSEP"rfc2397", tempname);
1018
 
        ret = cli_scandir(fullname, ctx);
1019
 
    }
1020
 
 
1021
 
    if(!ctx->engine->keeptmp)
 
1212
        ret = cli_scandesc(fd, ctx, 0, CL_TYPE_HTML, 0, NULL);
 
1213
        close(fd);
 
1214
    }
 
1215
 
 
1216
    if(ret < 0 || ret == CL_VIRUS) {
 
1217
        if(!cli_leavetemps_flag)
 
1218
            cli_rmdirs(tempname);
 
1219
        free(tempname);
 
1220
        return ret;
 
1221
    }
 
1222
 
 
1223
    if (ret == CL_CLEAN) {
 
1224
        snprintf(fullname, 1024, "%s/nocomment.html", tempname);
 
1225
        fd = open(fullname, O_RDONLY|O_BINARY);
 
1226
        if (fd >= 0) {
 
1227
            ret = cli_scandesc(fd, ctx, 0, CL_TYPE_HTML, 0, NULL);
 
1228
            close(fd);
 
1229
        }
 
1230
    }
 
1231
 
 
1232
    if(ret < 0 || ret == CL_VIRUS) {
 
1233
        if(!cli_leavetemps_flag)
 
1234
            cli_rmdirs(tempname);
 
1235
        free(tempname);
 
1236
        return ret;
 
1237
    }
 
1238
 
 
1239
    if (ret == CL_CLEAN) {
 
1240
        snprintf(fullname, 1024, "%s/script.html", tempname);
 
1241
        fd = open(fullname, O_RDONLY|O_BINARY);
 
1242
        if (fd >= 0) {
 
1243
            ret = cli_scandesc(fd, ctx, 0, CL_TYPE_HTML, 0, NULL);
 
1244
            close(fd);
 
1245
        }
 
1246
    }
 
1247
 
 
1248
    if(ret < 0 || ret == CL_VIRUS) {
 
1249
        if(!cli_leavetemps_flag)
 
1250
            cli_rmdirs(tempname);
 
1251
        free(tempname);
 
1252
        return ret;
 
1253
    }
 
1254
 
 
1255
    if (ret == CL_CLEAN) {
 
1256
        snprintf(fullname, 1024, "%s/rfc2397", tempname);
 
1257
        ret = cli_scandir(fullname, ctx);
 
1258
    }
 
1259
 
 
1260
    if(!cli_leavetemps_flag)
1022
1261
        cli_rmdirs(tempname);
1023
1262
 
1024
1263
    free(tempname);
1025
1264
    return ret;
1026
1265
}
1027
1266
 
1028
 
static int cli_scanscript(cli_ctx *ctx)
1029
 
{
1030
 
        unsigned char *buff;
1031
 
        unsigned char* normalized;
1032
 
        struct text_norm_state state;
1033
 
        char *tmpname = NULL;
1034
 
        int ofd = -1, ret;
1035
 
        struct cli_matcher *troot = ctx->engine->root[7];
1036
 
        uint32_t maxpatlen = troot ? troot->maxpatlen : 0, offset = 0;
1037
 
        struct cli_matcher *groot = ctx->engine->root[0];
1038
 
        struct cli_ac_data gmdata, tmdata;
1039
 
        struct cli_ac_data *mdata[2];
1040
 
        fmap_t *map = *ctx->fmap;
1041
 
        size_t at = 0;
1042
 
 
1043
 
        cli_dbgmsg("in cli_scanscript()\n");
1044
 
 
1045
 
        if(map->len > 5242880) {
1046
 
                cli_dbgmsg("cli_scanscript: exiting (file larger than 5 MB)\n");
1047
 
                return CL_CLEAN;
1048
 
        }
1049
 
 
1050
 
        /* dump to disk only if explicitly asked to,
1051
 
         * otherwise we can process just in-memory */
1052
 
        if(ctx->engine->keeptmp) {
1053
 
                if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &ofd))) {
1054
 
                        cli_dbgmsg("cli_scanscript: Can't generate temporary file/descriptor\n");
1055
 
                        return ret;
1056
 
                }
1057
 
                cli_dbgmsg("cli_scanscript: saving normalized file to %s\n", tmpname);
1058
 
        }
1059
 
 
1060
 
        if(!(normalized = cli_malloc(SCANBUFF + maxpatlen))) {
1061
 
                cli_dbgmsg("cli_scanscript: Unable to malloc %u bytes\n", SCANBUFF);
1062
 
                return CL_EMEM;
1063
 
        }
1064
 
 
1065
 
        text_normalize_init(&state, normalized, SCANBUFF + maxpatlen);
1066
 
        ret = CL_CLEAN;
1067
 
 
1068
 
        if ((ret = cli_ac_initdata(&tmdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
1069
 
            return ret;
1070
 
 
1071
 
        if ((ret = cli_ac_initdata(&gmdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) {
1072
 
            cli_ac_freedata(&tmdata);
1073
 
            return ret;
1074
 
        }
1075
 
        mdata[0] = &tmdata;
1076
 
        mdata[1] = &gmdata;
1077
 
 
1078
 
        while(1) {
1079
 
            size_t len = MIN(map->pgsz, map->len - at);
1080
 
            buff = fmap_need_off_once(map, at, len);
1081
 
            at += len;
1082
 
            if(!buff || !len || state.out_pos + len > state.out_len) {
1083
 
                /* flush if error/EOF, or too little buffer space left */
1084
 
                if((ofd != -1) && (write(ofd, state.out, state.out_pos) == -1)) {
1085
 
                    cli_errmsg("cli_scanscript: can't write to file %s\n",tmpname);
1086
 
                    close(ofd);
1087
 
                    ofd = -1;
1088
 
                    /* we can continue to scan in memory */
1089
 
                }
1090
 
                /* when we flush the buffer also scan */
1091
 
                if(cli_scanbuff(state.out, state.out_pos, offset, ctx, CL_TYPE_TEXT_ASCII, mdata) == CL_VIRUS) {
1092
 
                    ret = CL_VIRUS;
1093
 
                    break;
1094
 
                }
1095
 
                if(ctx->scanned)
1096
 
                    *ctx->scanned += state.out_pos / CL_COUNT_PRECISION;
1097
 
                offset += state.out_pos;
1098
 
                /* carry over maxpatlen from previous buffer */
1099
 
                if (state.out_pos > maxpatlen)
1100
 
                    memmove(state.out, state.out + state.out_pos - maxpatlen, maxpatlen); 
1101
 
                text_normalize_reset(&state);
1102
 
                state.out_pos = maxpatlen;
1103
 
            }
1104
 
            if(!len) break;
1105
 
            if(text_normalize_buffer(&state, buff, len) != len) {
1106
 
                cli_dbgmsg("cli_scanscript: short read during normalizing\n");
1107
 
            }
1108
 
        }
1109
 
        if(ctx->engine->keeptmp) {
1110
 
                free(tmpname);
1111
 
                close(ofd);
1112
 
        }
1113
 
        free(normalized);
1114
 
        if(ret != CL_VIRUS) {
1115
 
            ret = cli_lsig_eval(ctx, troot, &tmdata, NULL, NULL);
1116
 
            if(ret != CL_VIRUS)
1117
 
                ret = cli_lsig_eval(ctx, groot, &gmdata, NULL, NULL);
1118
 
        }
1119
 
        cli_ac_freedata(&tmdata);
1120
 
        cli_ac_freedata(&gmdata);
1121
 
 
1122
 
        return ret;
1123
 
}
1124
 
 
1125
 
static int cli_scanhtml_utf16(cli_ctx *ctx)
1126
 
{
1127
 
        char *tempname, *decoded, *buff;
 
1267
static int cli_scanhtml_utf16(int desc, cli_ctx *ctx)
 
1268
{
 
1269
        char *tempname, buff[512], *decoded;
1128
1270
        int ret = CL_CLEAN, fd, bytes;
1129
 
        size_t at = 0;
1130
 
        fmap_t *map = *ctx->fmap;
 
1271
 
1131
1272
 
1132
1273
    cli_dbgmsg("in cli_scanhtml_utf16()\n");
1133
1274
 
1134
 
    if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
1135
 
        return CL_EMEM;
1136
 
 
 
1275
    tempname = cli_gentemp(NULL);
1137
1276
    if((fd = open(tempname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
1138
1277
        cli_errmsg("cli_scanhtml_utf16: Can't create file %s\n", tempname);
1139
1278
        free(tempname);
1140
 
        return CL_EOPEN;
 
1279
        return CL_EIO;
1141
1280
    }
1142
1281
 
1143
 
    cli_dbgmsg("cli_scanhtml_utf16: using tempfile %s\n", tempname);
1144
 
 
1145
 
    while(at < map->len) {
1146
 
        bytes = MIN(map->len - at, map->pgsz * 16);
1147
 
        if(!(buff = fmap_need_off_once(map, at, bytes))) {
1148
 
            close(fd);
1149
 
            cli_unlink(tempname);
1150
 
            free(tempname);
1151
 
            return CL_EREAD;
1152
 
        }
1153
 
        at += bytes;
 
1282
    while((bytes = read(desc, buff, sizeof(buff))) > 0) {
1154
1283
        decoded = cli_utf16toascii(buff, bytes);
1155
1284
        if(decoded) {
1156
 
            if(write(fd, decoded, bytes / 2) == -1) {
 
1285
            if(write(fd, decoded, strlen(decoded)) == -1) {
1157
1286
                cli_errmsg("cli_scanhtml_utf16: Can't write to file %s\n", tempname);
1158
1287
                free(decoded);
1159
 
                close(fd);
1160
 
                cli_unlink(tempname);
 
1288
                unlink(tempname);
1161
1289
                free(tempname);
1162
 
                return CL_EWRITE;
 
1290
                close(fd);
 
1291
                return CL_EIO;
1163
1292
            }
1164
1293
            free(decoded);
1165
1294
        }
1166
1295
    }
1167
1296
 
1168
 
    *ctx->fmap = fmap(fd, 0, 0);
1169
 
    if(*ctx->fmap) {
1170
 
        ret = cli_scanhtml(ctx);
1171
 
        funmap(*ctx->fmap);
1172
 
    } else
1173
 
        cli_errmsg("cli_scanhtml_utf16: fmap of %s failed\n", tempname);
1174
 
 
1175
 
    *ctx->fmap = map;
 
1297
    fsync(fd);
 
1298
    lseek(fd, 0, SEEK_SET);
 
1299
    ret = cli_scanhtml(fd, ctx);
1176
1300
    close(fd);
1177
1301
 
1178
 
    if(!ctx->engine->keeptmp) {
1179
 
        if (cli_unlink(tempname)) ret = CL_EUNLINK;
1180
 
    } else
 
1302
    if(!cli_leavetemps_flag)
 
1303
        unlink(tempname);
 
1304
    else
1181
1305
        cli_dbgmsg("cli_scanhtml_utf16: Decoded HTML data saved in %s\n", tempname);
1182
1306
    free(tempname);
1183
1307
 
1184
1308
    return ret;
1185
1309
}
1186
1310
 
1187
 
static int cli_scanole2(cli_ctx *ctx)
 
1311
static int cli_scanole2(int desc, cli_ctx *ctx)
1188
1312
{
1189
1313
        char *dir;
1190
1314
        int ret = CL_CLEAN;
1191
 
        struct uniq *vba = NULL;
 
1315
 
1192
1316
 
1193
1317
    cli_dbgmsg("in cli_scanole2()\n");
1194
1318
 
1195
 
    if(ctx->engine->maxreclevel && ctx->recursion >= ctx->engine->maxreclevel)
1196
 
        return CL_EMAXREC;
1197
 
 
1198
1319
    /* generate the temporary directory */
1199
 
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1200
 
        return CL_EMEM;
1201
 
 
 
1320
    dir = cli_gentemp(NULL);
1202
1321
    if(mkdir(dir, 0700)) {
1203
1322
        cli_dbgmsg("OLE2: Can't create temporary directory %s\n", dir);
1204
1323
        free(dir);
1205
1324
        return CL_ETMPDIR;
1206
1325
    }
1207
1326
 
1208
 
    ret = cli_ole2_extract(dir, ctx, &vba);
1209
 
    if(ret!=CL_CLEAN && ret!=CL_VIRUS) {
 
1327
    if((ret = cli_ole2_extract(desc, dir, ctx->limits))) {
1210
1328
        cli_dbgmsg("OLE2: %s\n", cl_strerror(ret));
1211
 
        if(!ctx->engine->keeptmp)
 
1329
        if(!cli_leavetemps_flag)
1212
1330
            cli_rmdirs(dir);
1213
1331
        free(dir);
1214
1332
        return ret;
1215
1333
    }
1216
1334
 
1217
 
    if (vba) {
1218
 
        ctx->recursion++;
1219
 
 
1220
 
        ret = cli_vba_scandir(dir, ctx, vba);
1221
 
        uniq_free(vba);
1222
 
        if(ret != CL_VIRUS)
1223
 
            if(cli_scandir(dir, ctx) == CL_VIRUS)
1224
 
                ret = CL_VIRUS;
1225
 
        ctx->recursion--;
 
1335
    if((ret = cli_vba_scandir(dir, ctx)) != CL_VIRUS) {
 
1336
        if(cli_scandir(dir, ctx) == CL_VIRUS) {
 
1337
            ret = CL_VIRUS;
 
1338
        }
1226
1339
    }
1227
1340
 
1228
 
    if(!ctx->engine->keeptmp)
 
1341
    if(!cli_leavetemps_flag)
1229
1342
        cli_rmdirs(dir);
1230
1343
    free(dir);
1231
1344
    return ret;
1240
1353
    cli_dbgmsg("in cli_scantar()\n");
1241
1354
 
1242
1355
    /* generate temporary directory */
1243
 
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1244
 
        return CL_EMEM;
1245
 
 
 
1356
    dir = cli_gentemp(NULL);
1246
1357
    if(mkdir(dir, 0700)) {
1247
1358
        cli_errmsg("Tar: Can't create temporary directory %s\n", dir);
1248
1359
        free(dir);
1249
1360
        return CL_ETMPDIR;
1250
1361
    }
1251
1362
 
1252
 
    ret = cli_untar(dir, desc, posix, ctx);
1253
 
 
1254
 
    if(!ctx->engine->keeptmp)
 
1363
    if((ret = cli_untar(dir, desc, posix, ctx->limits)))
 
1364
        cli_dbgmsg("Tar: %s\n", cl_strerror(ret));
 
1365
    else
 
1366
        ret = cli_scandir(dir, ctx);
 
1367
 
 
1368
    if(!cli_leavetemps_flag)
 
1369
        cli_rmdirs(dir);
 
1370
 
 
1371
    free(dir);
 
1372
    return ret;
 
1373
}
 
1374
 
 
1375
static int cli_scanbinhex(int desc, cli_ctx *ctx)
 
1376
{
 
1377
        char *dir;
 
1378
        int ret = CL_CLEAN;
 
1379
 
 
1380
 
 
1381
    cli_dbgmsg("in cli_scanbinhex()\n");
 
1382
 
 
1383
    /* generate temporary directory */
 
1384
    dir = cli_gentemp(NULL);
 
1385
 
 
1386
    if(mkdir(dir, 0700)) {
 
1387
        cli_errmsg("Binhex: Can't create temporary directory %s\n", dir);
 
1388
        free(dir);
 
1389
        return CL_ETMPDIR;
 
1390
    }
 
1391
 
 
1392
    if((ret = cli_binhex(dir, desc)))
 
1393
        cli_dbgmsg("Binhex: %s\n", cl_strerror(ret));
 
1394
    else
 
1395
        ret = cli_scandir(dir, ctx);
 
1396
 
 
1397
    if(!cli_leavetemps_flag)
1255
1398
        cli_rmdirs(dir);
1256
1399
 
1257
1400
    free(dir);
1260
1403
 
1261
1404
static int cli_scanmschm(int desc, cli_ctx *ctx)
1262
1405
{
1263
 
        int ret = CL_CLEAN, rc;
1264
 
        chm_metadata_t metadata;
1265
 
        char *dir;
1266
 
 
1267
 
    cli_dbgmsg("in cli_scanmschm()\n");
1268
 
 
1269
 
     /* generate the temporary directory */
1270
 
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1271
 
        return CL_EMEM;
1272
 
 
1273
 
    if(mkdir(dir, 0700)) {
1274
 
        cli_dbgmsg("CHM: Can't create temporary directory %s\n", dir);
1275
 
        free(dir);
 
1406
        char *tempname;
 
1407
        int ret = CL_CLEAN;
 
1408
 
 
1409
 
 
1410
    cli_dbgmsg("in cli_scanmschm()\n"); 
 
1411
 
 
1412
    tempname = cli_gentemp(NULL);
 
1413
    if(mkdir(tempname, 0700)) {
 
1414
        cli_dbgmsg("CHM: Can't create temporary directory %s\n", tempname);
 
1415
        free(tempname);
1276
1416
        return CL_ETMPDIR;
1277
1417
    }
1278
1418
 
1279
 
    ret = cli_chm_open(desc, dir, &metadata, ctx);
1280
 
    if (ret != CL_SUCCESS) {
1281
 
        if(!ctx->engine->keeptmp)
1282
 
            cli_rmdirs(dir);
1283
 
        free(dir);
1284
 
        cli_dbgmsg("CHM: Error: %s\n", cl_strerror(ret));
1285
 
        return ret;
1286
 
    }
1287
 
 
1288
 
   do {
1289
 
        ret = cli_chm_prepare_file(&metadata);
1290
 
        if (ret != CL_SUCCESS) {
1291
 
           break;
1292
 
        }
1293
 
        ret = cli_chm_extract_file(dir, &metadata, ctx);
1294
 
        if (ret == CL_SUCCESS) {
1295
 
            lseek(metadata.ofd, 0, SEEK_SET);
1296
 
            rc = cli_magic_scandesc(metadata.ofd, ctx);
1297
 
            close(metadata.ofd);
1298
 
            if (rc == CL_VIRUS) {
1299
 
                cli_dbgmsg("CHM: infected with %s\n",*ctx->virname);
1300
 
                ret = CL_VIRUS;
1301
 
                break;
1302
 
            }
1303
 
        }
1304
 
 
1305
 
    } while(ret == CL_SUCCESS);
1306
 
 
1307
 
    cli_chm_close(&metadata);
1308
 
   
1309
 
    if(!ctx->engine->keeptmp)
1310
 
        cli_rmdirs(dir);
1311
 
 
1312
 
    free(dir);
1313
 
 
1314
 
    cli_dbgmsg("CHM: Exit code: %d\n", ret);
1315
 
    if (ret == CL_BREAK)
1316
 
        ret = CL_CLEAN;
1317
 
 
 
1419
    if(chm_unpack(desc, tempname))
 
1420
        ret = cli_scandir(tempname, ctx);
 
1421
 
 
1422
    if(!cli_leavetemps_flag)
 
1423
        cli_rmdirs(tempname);
 
1424
 
 
1425
    free(tempname);
1318
1426
    return ret;
1319
1427
}
1320
1428
 
1325
1433
 
1326
1434
    cli_dbgmsg("in cli_scanscrenc()\n");
1327
1435
 
1328
 
    if(!(tempname = cli_gentemp(ctx->engine->tmpdir)))
1329
 
        return CL_EMEM;
1330
 
 
 
1436
    tempname = cli_gentemp(NULL);
1331
1437
    if(mkdir(tempname, 0700)) {
1332
1438
        cli_dbgmsg("CHM: Can't create temporary directory %s\n", tempname);
1333
1439
        free(tempname);
1337
1443
    if (html_screnc_decode(desc, tempname))
1338
1444
        ret = cli_scandir(tempname, ctx);
1339
1445
 
1340
 
    if(!ctx->engine->keeptmp)
 
1446
    if(!cli_leavetemps_flag)
1341
1447
        cli_rmdirs(tempname);
1342
1448
 
1343
1449
    free(tempname);
1344
1450
    return ret;
1345
1451
}
1346
1452
 
1347
 
static int cli_scanriff(int desc, cli_ctx *ctx)
 
1453
static int cli_scanriff(int desc, const char **virname)
1348
1454
{
1349
1455
        int ret = CL_CLEAN;
1350
1456
 
1351
1457
    if(cli_check_riff_exploit(desc) == 2) {
1352
1458
        ret = CL_VIRUS;
1353
 
        *ctx->virname = "Heuristics.Exploit.W32.MS05-002";
 
1459
        *virname = "Exploit.W32.MS05-002";
1354
1460
    }
1355
1461
 
1356
1462
    return ret;
1357
1463
}
1358
1464
 
1359
 
static int cli_scanjpeg(int desc, cli_ctx *ctx)
 
1465
static int cli_scanjpeg(int desc, const char **virname)
1360
1466
{
1361
1467
        int ret = CL_CLEAN;
1362
1468
 
1363
 
    if(cli_check_jpeg_exploit(desc, ctx) == 1) {
 
1469
    if(cli_check_jpeg_exploit(desc) == 1) {
1364
1470
        ret = CL_VIRUS;
1365
 
        *ctx->virname = "Heuristics.Exploit.W32.MS04-028";
 
1471
        *virname = "Exploit.W32.MS04-028";
1366
1472
    }
1367
1473
 
1368
1474
    return ret;
1379
1485
 
1380
1486
    if(fstat(desc, &sb) == -1) {
1381
1487
        cli_errmsg("CryptFF: Can't fstat descriptor %d\n", desc);
1382
 
        return CL_ESTAT;
 
1488
        return CL_EIO;
1383
1489
    }
1384
1490
 
1385
1491
    /* Skip the CryptFF file header */
1405
1511
        cli_dbgmsg("CryptFF: Can't read from descriptor %d\n", desc);
1406
1512
        free(dest);
1407
1513
        free(src);
1408
 
        return CL_EREAD;
 
1514
        return CL_EIO;
1409
1515
    }
1410
1516
 
1411
1517
    for(i = 0; i < length; i++)
1413
1519
 
1414
1520
    free(src);
1415
1521
 
1416
 
    if(!(tempfile = cli_gentemp(ctx->engine->tmpdir))) {
1417
 
        free(dest);
1418
 
        return CL_EMEM;
1419
 
    }
1420
 
 
 
1522
    tempfile = cli_gentemp(NULL);
1421
1523
    if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
1422
1524
        cli_errmsg("CryptFF: Can't create file %s\n", tempfile);
1423
1525
        free(dest);
1424
1526
        free(tempfile);
1425
 
        return CL_ECREAT;
 
1527
        return CL_EIO;
1426
1528
    }
1427
1529
 
1428
1530
    if(write(ndesc, dest, length) == -1) {
1430
1532
        free(dest);
1431
1533
        close(ndesc);
1432
1534
        free(tempfile);
1433
 
        return CL_EWRITE;
 
1535
        return CL_EIO;
1434
1536
    }
1435
1537
 
1436
1538
    free(dest);
1437
1539
 
 
1540
    if(fsync(ndesc) == -1) {
 
1541
        cli_errmsg("CryptFF: Can't fsync descriptor %d\n", ndesc);
 
1542
        close(ndesc);
 
1543
        free(tempfile);
 
1544
        return CL_EIO;
 
1545
    }
 
1546
 
1438
1547
    lseek(ndesc, 0, SEEK_SET);
1439
1548
 
1440
1549
    cli_dbgmsg("CryptFF: Scanning decrypted data\n");
1444
1553
 
1445
1554
    close(ndesc);
1446
1555
 
1447
 
    if(ctx->engine->keeptmp)
 
1556
    if(cli_leavetemps_flag)
1448
1557
        cli_dbgmsg("CryptFF: Decompressed data saved in %s\n", tempfile);
1449
1558
    else
1450
 
        if (cli_unlink(tempfile)) ret = CL_EUNLINK;
 
1559
        unlink(tempfile);
1451
1560
 
1452
1561
    free(tempfile);
1453
1562
    return ret;
1454
1563
}
1455
1564
 
1456
 
static int cli_scanpdf(cli_ctx *ctx, off_t offset)
 
1565
static int cli_scanpdf(int desc, cli_ctx *ctx)
1457
1566
{
1458
1567
        int ret;
1459
 
        char *dir = cli_gentemp(ctx->engine->tmpdir);
 
1568
        char *dir = cli_gentemp(NULL);
1460
1569
 
1461
 
    if(!dir)
1462
 
        return CL_EMEM;
1463
1570
 
1464
1571
    if(mkdir(dir, 0700)) {
1465
1572
        cli_dbgmsg("Can't create temporary directory for PDF file %s\n", dir);
1467
1574
        return CL_ETMPDIR;
1468
1575
    }
1469
1576
 
1470
 
    ret = cli_pdf(dir, ctx, offset);
1471
 
 
1472
 
    if(!ctx->engine->keeptmp)
 
1577
    ret = cli_pdf(dir, desc, ctx);
 
1578
 
 
1579
    if(ret == CL_CLEAN)
 
1580
        ret = cli_scandir(dir, ctx);
 
1581
 
 
1582
    if(!cli_leavetemps_flag)
1473
1583
        cli_rmdirs(dir);
1474
1584
 
1475
1585
    free(dir);
1479
1589
static int cli_scantnef(int desc, cli_ctx *ctx)
1480
1590
{
1481
1591
        int ret;
1482
 
        char *dir = cli_gentemp(ctx->engine->tmpdir);
 
1592
        char *dir = cli_gentemp(NULL);
1483
1593
 
1484
 
    if(!dir)
1485
 
        return CL_EMEM;
1486
1594
 
1487
1595
    if(mkdir(dir, 0700)) {
1488
1596
        cli_dbgmsg("Can't create temporary directory for tnef file %s\n", dir);
1490
1598
        return CL_ETMPDIR;
1491
1599
    }
1492
1600
 
1493
 
    ret = cli_tnef(dir, desc, ctx);
 
1601
    ret = cli_tnef(dir, desc);
1494
1602
 
1495
1603
    if(ret == CL_CLEAN)
1496
1604
        ret = cli_scandir(dir, ctx);
1497
1605
 
1498
 
    if(!ctx->engine->keeptmp)
 
1606
    if(!cli_leavetemps_flag)
1499
1607
        cli_rmdirs(dir);
1500
1608
 
1501
1609
    free(dir);
1502
1610
    return ret;
1503
1611
}
1504
1612
 
1505
 
static int cli_scanuuencoded(cli_ctx *ctx)
 
1613
static int cli_scanuuencoded(int desc, cli_ctx *ctx)
1506
1614
{
1507
1615
        int ret;
1508
 
        char *dir = cli_gentemp(ctx->engine->tmpdir);
1509
 
 
1510
 
    if(!dir)
1511
 
        return CL_EMEM;
 
1616
        char *dir = cli_gentemp(NULL);
1512
1617
 
1513
1618
    if(mkdir(dir, 0700)) {
1514
1619
        cli_dbgmsg("Can't create temporary directory for uuencoded file %s\n", dir);
1516
1621
        return CL_ETMPDIR;
1517
1622
    }
1518
1623
 
1519
 
    ret = cli_uuencode(dir, *ctx->fmap);
 
1624
    ret = cli_uuencode(dir, desc);
1520
1625
 
1521
1626
    if(ret == CL_CLEAN)
1522
1627
        ret = cli_scandir(dir, ctx);
1523
1628
 
1524
 
    if(!ctx->engine->keeptmp)
 
1629
    if(!cli_leavetemps_flag)
1525
1630
        cli_rmdirs(dir);
1526
1631
 
1527
1632
    free(dir);
1534
1639
        int ret;
1535
1640
 
1536
1641
 
1537
 
    cli_dbgmsg("Starting cli_scanmail(), recursion = %u\n", ctx->recursion);
 
1642
    cli_dbgmsg("Starting cli_scanmail(), mrec == %d, arec == %d\n", ctx->mrec, ctx->arec);
1538
1643
 
1539
1644
    /* generate the temporary directory */
1540
 
    if(!(dir = cli_gentemp(ctx->engine->tmpdir)))
1541
 
        return CL_EMEM;
1542
 
 
 
1645
    dir = cli_gentemp(NULL);
1543
1646
    if(mkdir(dir, 0700)) {
1544
1647
        cli_dbgmsg("Mail: Can't create temporary directory %s\n", dir);
1545
1648
        free(dir);
1550
1653
     * Extract the attachments into the temporary directory
1551
1654
     */
1552
1655
    if((ret = cli_mbox(dir, desc, ctx))) {
1553
 
        if(!ctx->engine->keeptmp)
 
1656
        if(!cli_leavetemps_flag)
1554
1657
            cli_rmdirs(dir);
1555
1658
        free(dir);
1556
1659
        return ret;
1558
1661
 
1559
1662
    ret = cli_scandir(dir, ctx);
1560
1663
 
1561
 
    if(!ctx->engine->keeptmp)
 
1664
    if(!cli_leavetemps_flag)
1562
1665
        cli_rmdirs(dir);
1563
1666
 
1564
1667
    free(dir);
1565
1668
    return ret;
1566
1669
}
1567
1670
 
1568
 
static int cli_scan_structured(int desc, cli_ctx *ctx)
1569
 
{
1570
 
        char buf[8192];
1571
 
        int result = 0;
1572
 
        unsigned int cc_count = 0;
1573
 
        unsigned int ssn_count = 0;
1574
 
        int done = 0;
1575
 
        int (*ccfunc)(const unsigned char *buffer, int length);
1576
 
        int (*ssnfunc)(const unsigned char *buffer, int length);
1577
 
 
1578
 
 
1579
 
    if(ctx == NULL)
1580
 
        return CL_ENULLARG;
1581
 
 
1582
 
    if(ctx->engine->min_cc_count == 1)
1583
 
        ccfunc = dlp_has_cc;
1584
 
    else
1585
 
        ccfunc = dlp_get_cc_count;
1586
 
 
1587
 
    switch((ctx->options & CL_SCAN_STRUCTURED_SSN_NORMAL) | (ctx->options & CL_SCAN_STRUCTURED_SSN_STRIPPED)) {
1588
 
 
1589
 
        case (CL_SCAN_STRUCTURED_SSN_NORMAL | CL_SCAN_STRUCTURED_SSN_STRIPPED):
1590
 
            if(ctx->engine->min_ssn_count == 1)
1591
 
                ssnfunc = dlp_has_ssn;
1592
 
            else
1593
 
                ssnfunc = dlp_get_ssn_count;
1594
 
            break;
1595
 
 
1596
 
        case CL_SCAN_STRUCTURED_SSN_NORMAL:
1597
 
            if(ctx->engine->min_ssn_count == 1)
1598
 
                ssnfunc = dlp_has_normal_ssn;
1599
 
            else
1600
 
                ssnfunc = dlp_get_normal_ssn_count;
1601
 
            break;
1602
 
 
1603
 
        case CL_SCAN_STRUCTURED_SSN_STRIPPED:
1604
 
            if(ctx->engine->min_ssn_count == 1)
1605
 
                ssnfunc = dlp_has_stripped_ssn;
1606
 
            else
1607
 
                ssnfunc = dlp_get_stripped_ssn_count;
1608
 
            break;
1609
 
 
1610
 
        default:
1611
 
            ssnfunc = NULL;
1612
 
    }
1613
 
 
1614
 
    while(!done && ((result = cli_readn(desc, buf, 8191)) > 0)) {
1615
 
        if((cc_count += ccfunc((const unsigned char *)buf, result)) >= ctx->engine->min_cc_count)
1616
 
            done = 1;
1617
 
 
1618
 
        if(ssnfunc && ((ssn_count += ssnfunc((const unsigned char *)buf, result)) >= ctx->engine->min_ssn_count))
1619
 
            done = 1;
1620
 
    }
1621
 
 
1622
 
    if(cc_count != 0 && cc_count >= ctx->engine->min_cc_count) {
1623
 
        cli_dbgmsg("cli_scan_structured: %u credit card numbers detected\n", cc_count);
1624
 
        *ctx->virname = "Heuristics.Structured.CreditCardNumber";
1625
 
        return CL_VIRUS;
1626
 
    }
1627
 
 
1628
 
    if(ssn_count != 0 && ssn_count >= ctx->engine->min_ssn_count) {
1629
 
        cli_dbgmsg("cli_scan_structured: %u social security numbers detected\n", ssn_count);
1630
 
        *ctx->virname = "Heuristics.Structured.SSN";
1631
 
        return CL_VIRUS;
1632
 
    }
1633
 
 
1634
 
    return CL_CLEAN;
1635
 
}
1636
 
 
1637
 
static int cli_scanembpe(cli_ctx *ctx, off_t offset)
1638
 
{
1639
 
        int fd, bytes, ret = CL_CLEAN;
1640
 
        unsigned long int size = 0, todo;
1641
 
        char *buff;
1642
 
        char *tmpname;
1643
 
        fmap_t *map = *ctx->fmap;
1644
 
        unsigned int corrupted_input;
1645
 
 
1646
 
    tmpname = cli_gentemp(ctx->engine->tmpdir);
1647
 
    if(!tmpname)
1648
 
        return CL_EMEM;
1649
 
 
1650
 
    if((fd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
1651
 
        cli_errmsg("cli_scanembpe: Can't create file %s\n", tmpname);
1652
 
        free(tmpname);
1653
 
        return CL_ECREAT;
1654
 
    }
1655
 
 
1656
 
    todo = map->len - offset;
1657
 
    while(1) {
1658
 
        bytes = MIN(todo, map->pgsz);
1659
 
        if(!bytes)
1660
 
            break;
1661
 
 
1662
 
        if(!(buff = fmap_need_off_once(map, offset + size, bytes))) {
1663
 
            close(fd);
1664
 
            if(!ctx->engine->keeptmp) {
1665
 
                if (cli_unlink(tmpname)) {
1666
 
                    free(tmpname);
1667
 
                    return CL_EUNLINK;
1668
 
                }
1669
 
            }
1670
 
            free(tmpname);
1671
 
            return CL_EREAD;
1672
 
        }
1673
 
        size += bytes;
1674
 
        todo -= bytes;
1675
 
 
1676
 
        if(cli_checklimits("cli_scanembpe", ctx, size, 0, 0)!=CL_CLEAN)
1677
 
            break;
1678
 
 
1679
 
        if(cli_writen(fd, buff, bytes) != bytes) {
1680
 
            cli_dbgmsg("cli_scanembpe: Can't write to temporary file\n");
1681
 
            close(fd);
1682
 
            if(!ctx->engine->keeptmp) {
1683
 
                if (cli_unlink(tmpname)) {
1684
 
                    free(tmpname);
1685
 
                    return CL_EUNLINK;
1686
 
                }
1687
 
            }
1688
 
            free(tmpname);
1689
 
            return CL_EWRITE;
1690
 
        }
1691
 
    }
1692
 
 
1693
 
    ctx->recursion++;
1694
 
    lseek(fd, 0, SEEK_SET);
1695
 
    corrupted_input = ctx->corrupted_input;
1696
 
    ctx->corrupted_input = 1;
1697
 
    ret = cli_magic_scandesc(fd, ctx);
1698
 
    ctx->corrupted_input = corrupted_input;
1699
 
    if(ret == CL_VIRUS) {
1700
 
        cli_dbgmsg("cli_scanembpe: Infected with %s\n", *ctx->virname);
1701
 
        close(fd);
1702
 
        if(!ctx->engine->keeptmp) {
1703
 
            if (cli_unlink(tmpname)) {
1704
 
                free(tmpname);
1705
 
                return CL_EUNLINK;
1706
 
            }
1707
 
        }
1708
 
        free(tmpname);  
1709
 
        return CL_VIRUS;
1710
 
    }
1711
 
    ctx->recursion--;
1712
 
 
1713
 
    close(fd);
1714
 
    if(!ctx->engine->keeptmp) {
1715
 
        if (cli_unlink(tmpname)) {
1716
 
            free(tmpname);
1717
 
            return CL_EUNLINK;
1718
 
        }
1719
 
    }
1720
 
    free(tmpname);
1721
 
 
1722
 
    /* intentionally ignore possible errors from cli_magic_scandesc */
1723
 
    return CL_CLEAN;
1724
 
}
1725
 
 
1726
 
static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_t *dettype, unsigned char *refhash)
 
1671
static int cli_scanraw(int desc, cli_ctx *ctx, cli_file_t type)
1727
1672
{
1728
1673
        int ret = CL_CLEAN, nret = CL_CLEAN;
 
1674
        unsigned short ftrec;
1729
1675
        struct cli_matched_type *ftoffset = NULL, *fpt;
1730
1676
        uint32_t lastzip, lastrar;
1731
 
        struct cli_exe_info peinfo;
1732
 
        unsigned int acmode = AC_SCAN_VIR, break_loop = 0;
1733
 
        fmap_t *map = *ctx->fmap;
1734
 
        cli_file_t current_container_type = ctx->container_type;
1735
 
        size_t current_container_size = ctx->container_size;
1736
 
 
1737
 
 
1738
 
    if(ctx->engine->maxreclevel && ctx->recursion >= ctx->engine->maxreclevel)
1739
 
        return CL_EMAXREC;
1740
 
 
1741
 
    if(typercg)
1742
 
        acmode |= AC_SCAN_FT;
1743
 
 
1744
 
    ret = cli_fmap_scandesc(ctx, type == CL_TYPE_TEXT_ASCII ? 0 : type, 0, &ftoffset, acmode, NULL, refhash);
1745
 
 
1746
 
    if(ret >= CL_TYPENO) {
1747
 
        ctx->recursion++;
1748
 
        if(nret != CL_VIRUS) {
1749
 
            lastzip = lastrar = 0xdeadbeef;
1750
 
            fpt = ftoffset;
1751
 
            while(fpt) {
1752
 
                if(fpt->offset) switch(fpt->type) {
1753
 
                    case CL_TYPE_RARSFX:
1754
 
                        if(type != CL_TYPE_RAR && have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR)) {
1755
 
                            ctx->container_type = CL_TYPE_RAR;
1756
 
                            ctx->container_size = map->len - fpt->offset; /* not precise */
1757
 
                            cli_dbgmsg("RAR/RAR-SFX signature found at %u\n", (unsigned int) fpt->offset);
1758
 
                            nret = cli_scanrar(map->fd, ctx, fpt->offset, &lastrar);
1759
 
                        }
1760
 
                        break;
1761
 
 
1762
 
                    case CL_TYPE_ZIPSFX:
1763
 
                        if(type != CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP)) {
1764
 
                            ctx->container_type = CL_TYPE_ZIP;
1765
 
                            ctx->container_size = map->len - fpt->offset; /* not precise */
1766
 
                            cli_dbgmsg("ZIP/ZIP-SFX signature found at %u\n", (unsigned int) fpt->offset);
1767
 
                            nret = cli_unzip_single(ctx, fpt->offset);
1768
 
                        }
1769
 
                        break;
1770
 
 
1771
 
                    case CL_TYPE_CABSFX:
1772
 
                        if(type != CL_TYPE_MSCAB && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB)) {
1773
 
                            ctx->container_type = CL_TYPE_MSCAB;
1774
 
                            ctx->container_size = map->len - fpt->offset; /* not precise */
1775
 
                            cli_dbgmsg("CAB/CAB-SFX signature found at %u\n", (unsigned int) fpt->offset);
1776
 
                            nret = cli_scanmscab(map->fd, ctx, fpt->offset);
1777
 
                        }
1778
 
                        break;
1779
 
                    case CL_TYPE_ARJSFX:
1780
 
                        if(type != CL_TYPE_ARJ && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ)) {
1781
 
                            ctx->container_type = CL_TYPE_ARJ;
1782
 
                            ctx->container_size = map->len - fpt->offset; /* not precise */
1783
 
                            cli_dbgmsg("ARJ-SFX signature found at %u\n", (unsigned int) fpt->offset);
1784
 
                            nret = cli_scanarj(map->fd, ctx, fpt->offset, &lastrar);
1785
 
                        }
1786
 
                        break;
1787
 
 
1788
 
                    case CL_TYPE_NULSFT:
1789
 
                        if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_NSIS) && fpt->offset > 4) {
1790
 
                            ctx->container_type = CL_TYPE_NULSFT;
1791
 
                            ctx->container_size = map->len - fpt->offset; /* not precise */
1792
 
                            cli_dbgmsg("NSIS signature found at %u\n", (unsigned int) fpt->offset-4);
1793
 
                            nret = cli_scannulsft(map->fd, ctx, fpt->offset - 4);
1794
 
                        }
1795
 
                        break;
1796
 
 
1797
 
                    case CL_TYPE_AUTOIT:
1798
 
                        if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_AUTOIT)) {
1799
 
                            ctx->container_type = CL_TYPE_AUTOIT;
1800
 
                            ctx->container_size = map->len - fpt->offset; /* not precise */
1801
 
                            cli_dbgmsg("AUTOIT signature found at %u\n", (unsigned int) fpt->offset);
1802
 
                            nret = cli_scanautoit(ctx, fpt->offset + 23);
1803
 
                        }
1804
 
                        break;
1805
 
 
1806
 
                    case CL_TYPE_ISHIELD_MSI:
1807
 
                        if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_ISHIELD)) {
1808
 
                            ctx->container_type = CL_TYPE_AUTOIT;
1809
 
                            ctx->container_size = map->len - fpt->offset; /* not precise */
1810
 
                            cli_dbgmsg("ISHIELD-MSI signature found at %u\n", (unsigned int) fpt->offset);
1811
 
                            nret = cli_scanishield_msi(ctx, fpt->offset + 14);
1812
 
                        }
1813
 
                        break;
1814
 
 
1815
 
                    case CL_TYPE_PDF:
1816
 
                        if(type != CL_TYPE_PDF && SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF)) {
1817
 
                            ctx->container_type = CL_TYPE_PDF;
1818
 
                            ctx->container_size = map->len - fpt->offset; /* not precise */
1819
 
                            cli_dbgmsg("PDF signature found at %u\n", (unsigned int) fpt->offset);
1820
 
                            nret = cli_scanpdf(ctx, fpt->offset);
1821
 
                        }
1822
 
                        break;
1823
 
 
1824
 
                    case CL_TYPE_MSEXE:
1825
 
                        if(SCAN_PE && (type == CL_TYPE_MSEXE || type == CL_TYPE_ZIP || type == CL_TYPE_MSOLE2) && ctx->dconf->pe) {
1826
 
                            if(map->len > 10485760)
1827
 
                                break;
1828
 
                            ctx->container_type = CL_TYPE_MSEXE; /* PE is a container for another executable here */
1829
 
                            ctx->container_size = map->len - fpt->offset; /* not precise */
1830
 
                            memset(&peinfo, 0, sizeof(struct cli_exe_info));
1831
 
                            peinfo.offset = fpt->offset;
1832
 
                            if(cli_peheader(map, &peinfo) == 0) {
1833
 
                                cli_dbgmsg("*** Detected embedded PE file at %u ***\n", (unsigned int) fpt->offset);
1834
 
                                if(peinfo.section)
1835
 
                                    free(peinfo.section);
1836
 
                                cli_hashset_destroy(&peinfo.vinfo);
1837
 
 
1838
 
                                nret = cli_scanembpe(ctx, fpt->offset);
1839
 
                                break_loop = 1; /* we can stop here and other
1840
 
                                                 * embedded executables will
1841
 
                                                 * be found recursively
1842
 
                                                 * through the above call
1843
 
                                                 */
1844
 
                            }
1845
 
                        }
1846
 
                        break;
1847
 
 
1848
 
                    default:
1849
 
                        cli_warnmsg("cli_scanraw: Type %u not handled in fpt loop\n", fpt->type);
1850
 
                }
1851
 
 
1852
 
                if(nret == CL_VIRUS || break_loop)
1853
 
                    break;
1854
 
 
1855
 
                fpt = fpt->next;
1856
 
            }
1857
 
            ctx->container_type = current_container_type;
1858
 
            ctx->container_size = current_container_size;
 
1677
 
 
1678
 
 
1679
    switch(type) {
 
1680
        case CL_TYPE_UNKNOWN_TEXT:
 
1681
        case CL_TYPE_MSEXE:
 
1682
            ftrec = 1;
 
1683
            break;
 
1684
        default:
 
1685
            ftrec = 0;
 
1686
    }
 
1687
 
 
1688
    if(lseek(desc, 0, SEEK_SET) < 0) {
 
1689
        cli_errmsg("cli_scanraw: lseek() failed\n");
 
1690
        return CL_EIO;
 
1691
    }
 
1692
 
 
1693
    if((ret = cli_scandesc(desc, ctx, ftrec, type, 0, &ftoffset)) == CL_VIRUS) {
 
1694
        cli_dbgmsg("%s found in descriptor %d.\n", *ctx->virname, desc);
 
1695
        return CL_VIRUS;
 
1696
 
 
1697
    } else if(ret < 0) {
 
1698
        return ret;
 
1699
 
 
1700
    } else if(ret >= CL_TYPENO) {
 
1701
        lseek(desc, 0, SEEK_SET);
 
1702
 
 
1703
        if((nret = cli_scandesc(desc, ctx, 0, ret, 1, NULL)) == CL_VIRUS) {
 
1704
            cli_dbgmsg("%s found in descriptor %d when scanning file type %u\n", *ctx->virname, desc, ret);
 
1705
            return CL_VIRUS;
1859
1706
        }
1860
1707
 
1861
 
        if(nret != CL_VIRUS) switch(ret) {
 
1708
        ret == CL_TYPE_MAIL ? ctx->mrec++ : ctx->arec++;
 
1709
        switch(ret) {
1862
1710
            case CL_TYPE_HTML:
1863
 
                if(SCAN_HTML && type == CL_TYPE_TEXT_ASCII && (DCONF_DOC & DOC_CONF_HTML)) {
1864
 
                    *dettype = CL_TYPE_HTML;
1865
 
                    nret = cli_scanhtml(ctx);
1866
 
                }
 
1711
                if(SCAN_HTML && type == CL_TYPE_UNKNOWN_TEXT && (DCONF_DOC & DOC_CONF_HTML))
 
1712
                    if((nret = cli_scanhtml(desc, ctx)) == CL_VIRUS)
 
1713
                        return CL_VIRUS;
1867
1714
                break;
1868
1715
 
1869
1716
            case CL_TYPE_MAIL:
1870
 
                ctx->container_type = CL_TYPE_MAIL;
1871
 
                ctx->container_size = map->len;
1872
 
                if(SCAN_MAIL && type == CL_TYPE_TEXT_ASCII && (DCONF_MAIL & MAIL_CONF_MBOX)) {
1873
 
                    *dettype = CL_TYPE_MAIL;
1874
 
                    nret = cli_scanmail(map->fd, ctx);
 
1717
                if(SCAN_MAIL && type == CL_TYPE_UNKNOWN_TEXT && (DCONF_MAIL & MAIL_CONF_MBOX))
 
1718
                    if((nret = cli_scanmail(desc, ctx)) == CL_VIRUS)
 
1719
                        return CL_VIRUS;
 
1720
                break;
 
1721
 
 
1722
            case CL_TYPE_RARSFX:
 
1723
            case CL_TYPE_ZIPSFX:
 
1724
            case CL_TYPE_CABSFX:
 
1725
                if(type == CL_TYPE_MSEXE) {
 
1726
                    if(SCAN_ARCHIVE) {
 
1727
                        lastzip = lastrar = 0xdeadbeef;
 
1728
                        fpt = ftoffset;
 
1729
                        while(fpt) {
 
1730
                            if(fpt->type == CL_TYPE_RARSFX && (DCONF_ARCH & ARCH_CONF_RAR)) {
 
1731
                                cli_dbgmsg("RAR-SFX signature found at %d\n", fpt->offset);
 
1732
                                if((nret = cli_scanrar(desc, ctx, fpt->offset, &lastrar)) == CL_VIRUS)
 
1733
                                    break;
 
1734
                            } else if(fpt->type == CL_TYPE_ZIPSFX && (DCONF_ARCH & ARCH_CONF_ZIP)) {
 
1735
                                cli_dbgmsg("ZIP-SFX signature found at %d\n", fpt->offset);
 
1736
                                if((nret = cli_scanzip(desc, ctx, fpt->offset, &lastzip)) == CL_VIRUS)
 
1737
                                    break;
 
1738
                            } else if(fpt->type == CL_TYPE_CABSFX && (DCONF_ARCH & ARCH_CONF_CAB)) {
 
1739
                                cli_dbgmsg("CAB-SFX signature found at %d\n", fpt->offset);
 
1740
                                if((nret = cli_scanmscab(desc, ctx, fpt->offset)) == CL_VIRUS)
 
1741
                                    break;
 
1742
                            }
 
1743
 
 
1744
                            fpt = fpt->next;
 
1745
                        }
 
1746
                    }
 
1747
 
 
1748
                    while(ftoffset) {
 
1749
                        fpt = ftoffset;
 
1750
                        ftoffset = ftoffset->next;
 
1751
                        free(fpt);
 
1752
                    }
 
1753
 
 
1754
                    if(nret == CL_VIRUS)
 
1755
                        return nret;
1875
1756
                }
1876
 
                ctx->container_type = current_container_type;
1877
 
                ctx->container_size = current_container_size;
1878
1757
                break;
1879
1758
 
1880
1759
            default:
1881
1760
                break;
1882
1761
        }
1883
 
        ctx->recursion--;
 
1762
        ret == CL_TYPE_MAIL ? ctx->mrec-- : ctx->arec--;
1884
1763
        ret = nret;
1885
1764
    }
1886
1765
 
1887
 
    while(ftoffset) {
1888
 
        fpt = ftoffset;
1889
 
        ftoffset = ftoffset->next;
1890
 
        free(fpt);
1891
 
    }
1892
 
 
1893
 
    if(ret == CL_VIRUS)
1894
 
        cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, map->fd);
1895
 
 
1896
1766
    return ret;
1897
1767
}
1898
1768
 
1899
 
 
1900
 
static void emax_reached(cli_ctx *ctx) {
1901
 
    fmap_t **ctx_fmap = ctx->fmap;
1902
 
    if (!ctx_fmap)
1903
 
        return;
1904
 
    while(*ctx_fmap) {
1905
 
        fmap_t *map = *ctx_fmap;
1906
 
        map->dont_cache_flag = 1;
1907
 
        ctx_fmap--;
1908
 
    }
1909
 
    cli_dbgmsg("emax_reached: marked parents as non cacheable\n");
1910
 
}
1911
 
 
1912
 
#define LINESTR(x) #x
1913
 
#define LINESTR2(x) LINESTR(x)
1914
 
#define __AT__  " at line "LINESTR2(__LINE__)
1915
 
#define ret_from_magicscan(retcode) do {                                                        \
1916
 
    cli_dbgmsg("cli_magic_scandesc: returning %d %s\n", retcode, __AT__);                       \
1917
 
    if(ctx->engine->cb_post_scan) {                                                             \
1918
 
        switch(ctx->engine->cb_post_scan(desc, retcode, retcode == CL_VIRUS && ctx->virname ? *ctx->virname : NULL, ctx->cb_ctx)) {             \
1919
 
        case CL_BREAK:                                                                          \
1920
 
            cli_dbgmsg("cli_magic_scandesc: file whitelisted by callback\n");                   \
1921
 
            return CL_CLEAN;                                                                    \
1922
 
        case CL_VIRUS:                                                                          \
1923
 
            cli_dbgmsg("cli_magic_scandesc: file blacklisted by callback\n");                   \
1924
 
            if(ctx->virname)                                                                    \
1925
 
                *ctx->virname = "Detected.By.Callback";                                         \
1926
 
            return CL_VIRUS;                                                                    \
1927
 
        case CL_CLEAN:                                                                          \
1928
 
            break;                                                                              \
1929
 
        default:                                                                                \
1930
 
            cli_warnmsg("cli_magic_scandesc: ignoring bad return code from callback\n");        \
1931
 
        }                                                                                       \
1932
 
    }\
1933
 
    return retcode;                                                                             \
1934
 
    } while(0)
1935
 
 
1936
 
static int magic_scandesc(int desc, cli_ctx *ctx, cli_file_t type)
 
1769
int cli_magic_scandesc(int desc, cli_ctx *ctx)
1937
1770
{
1938
1771
        int ret = CL_CLEAN;
1939
 
        cli_file_t dettype = 0;
 
1772
        cli_file_t type;
1940
1773
        struct stat sb;
1941
 
        uint8_t typercg = 1;
1942
 
        cli_file_t current_container_type = ctx->container_type;
1943
 
        size_t current_container_size = ctx->container_size, hashed_size;
1944
 
        unsigned char hash[16];
1945
 
        bitset_t *old_hook_lsig_matches;
1946
 
 
1947
 
#ifdef HAVE__INTERNAL__SHA_COLLECT
1948
 
    if(ctx->sha_collect>0) ctx->sha_collect = 0;
1949
 
#endif
1950
 
 
1951
 
    cli_dbgmsg("in cli_magic_scandesc (reclevel: %u/%u)\n", ctx->recursion, ctx->engine->maxreclevel);
1952
 
    if(ctx->engine->maxreclevel && ctx->recursion > ctx->engine->maxreclevel) {
1953
 
        cli_dbgmsg("cli_magic_scandesc: Archive recursion limit exceeded (%u, max: %u)\n", ctx->recursion, ctx->engine->maxreclevel);
1954
 
        emax_reached(ctx);
1955
 
        ret_from_magicscan(CL_CLEAN);
1956
 
    }
 
1774
 
1957
1775
 
1958
1776
    if(fstat(desc, &sb) == -1) {
1959
 
        cli_errmsg("magic_scandesc: Can't fstat descriptor %d\n", desc);
1960
 
        ret_from_magicscan(CL_ESTAT);
 
1777
        cli_errmsg("Can't fstat descriptor %d\n", desc);
 
1778
        return CL_EIO;
1961
1779
    }
1962
1780
 
1963
1781
    if(sb.st_size <= 5) {
1964
 
        cli_dbgmsg("Small data (%u bytes)\n", (unsigned int) sb.st_size);
1965
 
        ret_from_magicscan(CL_CLEAN);
 
1782
        cli_dbgmsg("Small data (%d bytes)\n", sb.st_size);
 
1783
        return CL_CLEAN;
1966
1784
    }
1967
1785
 
1968
1786
    if(!ctx->engine) {
1969
1787
        cli_errmsg("CRITICAL: engine == NULL\n");
1970
 
        ret_from_magicscan(CL_ENULLARG);
1971
 
    }
1972
 
 
1973
 
    if(!(ctx->engine->dboptions & CL_DB_COMPILED)) {
1974
 
        cli_errmsg("CRITICAL: engine not compiled\n");
1975
 
        ret_from_magicscan(CL_EMALFDB);
1976
 
    }
1977
 
 
1978
 
    if(cli_updatelimits(ctx, sb.st_size)!=CL_CLEAN) {
1979
 
        emax_reached(ctx);
1980
 
        ret_from_magicscan(CL_CLEAN);
1981
 
    }
1982
 
 
1983
 
    ctx->fmap++;
1984
 
    if(!(*ctx->fmap = fmap(desc, 0, sb.st_size))) {
1985
 
        cli_errmsg("CRITICAL: fmap() failed\n");
1986
 
        ctx->fmap--;
1987
 
        ret_from_magicscan(CL_EMEM);
1988
 
    }
1989
 
 
1990
 
    if(ctx->engine->cb_pre_scan) {
1991
 
        switch(ctx->engine->cb_pre_scan(desc, ctx->cb_ctx)) {
1992
 
        case CL_BREAK:
1993
 
            cli_dbgmsg("cli_magic_scandesc: file whitelisted by callback\n");
1994
 
            funmap(*ctx->fmap);
1995
 
            ctx->fmap--;
1996
 
            ret_from_magicscan(CL_CLEAN);
1997
 
        case CL_VIRUS:
1998
 
            cli_dbgmsg("cli_magic_scandesc: file blacklisted by callback\n");
1999
 
            if(ctx->virname)
2000
 
                *ctx->virname = "Detected.By.Callback";
2001
 
            funmap(*ctx->fmap);
2002
 
            ctx->fmap--;
2003
 
            ret_from_magicscan(CL_VIRUS);
2004
 
        case CL_CLEAN:
2005
 
            break;
2006
 
        default:
2007
 
            cli_warnmsg("cli_magic_scandesc: ignoring bad return code from callback\n");
2008
 
        }
2009
 
    }
2010
 
 
2011
 
    if(cache_check(hash, ctx) == CL_CLEAN) {
2012
 
        funmap(*ctx->fmap);
2013
 
        ctx->fmap--;
2014
 
        ret_from_magicscan(CL_CLEAN);
2015
 
    }
2016
 
    hashed_size = (*ctx->fmap)->len;
2017
 
    old_hook_lsig_matches = ctx->hook_lsig_matches;
2018
 
    ctx->hook_lsig_matches = NULL;
2019
 
 
2020
 
    if(!ctx->options || (ctx->recursion == ctx->engine->maxreclevel)) { /* raw mode (stdin, etc.) or last level of recursion */
2021
 
        if(ctx->recursion == ctx->engine->maxreclevel)
2022
 
            cli_dbgmsg("cli_magic_scandesc: Hit recursion limit, only scanning raw file\n");
2023
 
        else
2024
 
            cli_dbgmsg("Raw mode: No support for special files\n");
2025
 
 
2026
 
        if((ret = cli_fmap_scandesc(ctx, 0, 0, NULL, AC_SCAN_VIR, NULL, hash)) == CL_VIRUS)
 
1788
        return CL_EMALFDB;
 
1789
    }
 
1790
 
 
1791
    if(!ctx->options) { /* raw mode (stdin, etc.) */
 
1792
        cli_dbgmsg("Raw mode: No support for special files\n");
 
1793
        if((ret = cli_scandesc(desc, ctx, 0, 0, 0, NULL)) == CL_VIRUS)
2027
1794
            cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, desc);
2028
 
        else if(ret == CL_CLEAN) {
2029
 
            if(ctx->recursion != ctx->engine->maxreclevel)
2030
 
                cache_add(hash, hashed_size, ctx); /* Only cache if limits are not reached */
2031
 
            else 
2032
 
                emax_reached(ctx);
2033
 
        }
2034
 
 
2035
 
        ctx->hook_lsig_matches = old_hook_lsig_matches;
2036
 
        funmap(*ctx->fmap);
2037
 
        ctx->fmap--;
2038
 
        ret_from_magicscan(ret);
2039
 
    }
2040
 
 
2041
 
    if(type == CL_TYPE_ANY)
2042
 
        type = cli_filetype2(*ctx->fmap, ctx->engine); /* FIXMEFMAP: port to fmap */
2043
 
    if(type == CL_TYPE_ERROR) {
2044
 
        cli_dbgmsg("cli_magic_scandesc: cli_filetype2 returned CL_TYPE_ERROR\n");
2045
 
        funmap(*ctx->fmap);
2046
 
        ctx->fmap--;
2047
 
        ctx->hook_lsig_matches = old_hook_lsig_matches;
2048
 
        ret_from_magicscan(CL_EREAD);
2049
 
    }
2050
 
 
2051
 
#ifdef HAVE__INTERNAL__SHA_COLLECT
2052
 
    if(!ctx->sha_collect && type==CL_TYPE_MSEXE) ctx->sha_collect = 1;
2053
 
#endif
2054
 
    lseek(desc, 0, SEEK_SET); /* FIXMEFMAP: remove ? */
2055
 
 
2056
 
    ctx->hook_lsig_matches = cli_bitset_init();
2057
 
    if (!ctx->hook_lsig_matches) {
2058
 
        ctx->hook_lsig_matches = old_hook_lsig_matches;
2059
 
        ctx->fmap--;
2060
 
        ret_from_magicscan(CL_EMEM);
2061
 
    }
2062
 
 
2063
 
    if(type != CL_TYPE_IGNORED && ctx->engine->sdb) {
2064
 
        if((ret = cli_scanraw(ctx, type, 0, &dettype, hash)) == CL_VIRUS) {
2065
 
            ret = cli_checkfp(hash, hashed_size, ctx);
2066
 
            funmap(*ctx->fmap);
2067
 
            ctx->fmap--;
2068
 
            cli_bitset_free(ctx->hook_lsig_matches);
2069
 
            ctx->hook_lsig_matches = old_hook_lsig_matches;
2070
 
            ret_from_magicscan(ret);
2071
 
        }
2072
 
        lseek(desc, 0, SEEK_SET); /* FIXMEFMAP: remove ? */
2073
 
    }
2074
 
 
2075
 
    ctx->recursion++;
 
1795
        return ret;
 
1796
    }
 
1797
 
 
1798
    if(SCAN_ARCHIVE && ctx->limits && ctx->limits->maxreclevel)
 
1799
        if(ctx->arec > ctx->limits->maxreclevel) {
 
1800
            cli_dbgmsg("Archive recursion limit exceeded (arec == %d).\n", ctx->arec);
 
1801
            if(BLOCKMAX) {
 
1802
                *ctx->virname = "Archive.ExceededRecursionLimit";
 
1803
                return CL_VIRUS;
 
1804
            }
 
1805
            return CL_CLEAN;
 
1806
        }
 
1807
 
 
1808
    if(SCAN_MAIL)
 
1809
        if(ctx->mrec > MAX_MAIL_RECURSION) {
 
1810
            cli_dbgmsg("Mail recursion level exceeded (mrec == %d).\n", ctx->mrec);
 
1811
            /* return CL_EMAXREC; */
 
1812
            return CL_CLEAN;
 
1813
        }
 
1814
 
 
1815
    lseek(desc, 0, SEEK_SET);
 
1816
    type = cli_filetype2(desc, ctx->engine);
 
1817
    lseek(desc, 0, SEEK_SET);
 
1818
 
 
1819
    if(type != CL_TYPE_DATA && ctx->engine->sdb) {
 
1820
        if((ret = cli_scanraw(desc, ctx, type)) == CL_VIRUS)
 
1821
            return CL_VIRUS;
 
1822
        lseek(desc, 0, SEEK_SET);
 
1823
    }
 
1824
 
 
1825
    type == CL_TYPE_MAIL ? ctx->mrec++ : ctx->arec++;
 
1826
 
2076
1827
    switch(type) {
2077
 
        case CL_TYPE_IGNORED:
2078
 
            break;
2079
 
 
2080
1828
        case CL_TYPE_RAR:
2081
 
            ctx->container_type = CL_TYPE_RAR;
2082
 
            ctx->container_size = sb.st_size;
2083
 
            if(have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR))
 
1829
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR))
2084
1830
                ret = cli_scanrar(desc, ctx, 0, NULL);
2085
1831
            break;
2086
1832
 
2087
1833
        case CL_TYPE_ZIP:
2088
 
            ctx->container_type = CL_TYPE_ZIP;
2089
 
            ctx->container_size = sb.st_size;
2090
1834
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
2091
 
                ret = cli_unzip(ctx);
 
1835
                ret = cli_scanzip(desc, ctx, 0, NULL);
2092
1836
            break;
2093
1837
 
2094
1838
        case CL_TYPE_GZ:
2095
1839
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_GZ))
2096
 
                ret = cli_scangzip(ctx);
 
1840
                ret = cli_scangzip(desc, ctx);
2097
1841
            break;
2098
1842
 
2099
1843
        case CL_TYPE_BZ:
 
1844
#ifdef HAVE_BZLIB_H
2100
1845
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BZ))
2101
1846
                ret = cli_scanbzip(desc, ctx);
2102
 
            break;
2103
 
 
2104
 
        case CL_TYPE_ARJ:
2105
 
            ctx->container_type = CL_TYPE_ARJ;
2106
 
            ctx->container_size = sb.st_size;
2107
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ))
2108
 
                ret = cli_scanarj(desc, ctx, 0, NULL);
2109
 
            break;
2110
 
 
2111
 
        case CL_TYPE_NULSFT:
2112
 
            ctx->container_type = CL_TYPE_NULSFT;
2113
 
            ctx->container_size = sb.st_size;
2114
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_NSIS))
2115
 
                ret = cli_scannulsft(desc, ctx, 0);
2116
 
            break;
2117
 
 
2118
 
        case CL_TYPE_AUTOIT:
2119
 
            ctx->container_type = CL_TYPE_AUTOIT;
2120
 
            ctx->container_size = sb.st_size;
2121
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_AUTOIT))
2122
 
                ret = cli_scanautoit(ctx, 23);
 
1847
#endif
2123
1848
            break;
2124
1849
 
2125
1850
        case CL_TYPE_MSSZDD:
2128
1853
            break;
2129
1854
 
2130
1855
        case CL_TYPE_MSCAB:
2131
 
            ctx->container_type = CL_TYPE_MSCAB;
2132
 
            ctx->container_size = sb.st_size;
2133
1856
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB))
2134
1857
                ret = cli_scanmscab(desc, ctx, 0);
2135
1858
            break;
2136
1859
 
2137
1860
        case CL_TYPE_HTML:
2138
1861
            if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
2139
 
                ret = cli_scanhtml(ctx);
 
1862
                ret = cli_scanhtml(desc, ctx);
2140
1863
            break;
2141
1864
 
2142
1865
        case CL_TYPE_HTML_UTF16:
2143
1866
            if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
2144
 
                ret = cli_scanhtml_utf16(ctx);
2145
 
            break;
2146
 
 
2147
 
        case CL_TYPE_SCRIPT:
2148
 
            if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML)
2149
 
                ret = cli_scanscript(ctx);
 
1867
                ret = cli_scanhtml_utf16(desc, ctx);
2150
1868
            break;
2151
1869
 
2152
1870
        case CL_TYPE_RTF:
2153
 
            ctx->container_type = CL_TYPE_RTF;
2154
 
            ctx->container_size = sb.st_size;
2155
 
            if(SCAN_ARCHIVE && (DCONF_DOC & DOC_CONF_RTF))
 
1871
            if(DCONF_DOC & DOC_CONF_RTF)
2156
1872
                ret = cli_scanrtf(desc, ctx);
2157
1873
            break;
2158
1874
 
2159
1875
        case CL_TYPE_MAIL:
2160
 
            ctx->container_type = CL_TYPE_MAIL;
2161
 
            ctx->container_size = sb.st_size;
2162
1876
            if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
2163
1877
                ret = cli_scanmail(desc, ctx);
2164
1878
            break;
2170
1884
 
2171
1885
        case CL_TYPE_UUENCODED:
2172
1886
            if(DCONF_OTHER & OTHER_CONF_UUENC)
2173
 
                ret = cli_scanuuencoded(ctx);
 
1887
                ret = cli_scanuuencoded(desc, ctx);
2174
1888
            break;
2175
1889
 
2176
1890
        case CL_TYPE_MSCHM:
2177
 
            ctx->container_type = CL_TYPE_MSCHM;
2178
 
            ctx->container_size = sb.st_size;
2179
1891
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CHM))
2180
1892
                ret = cli_scanmschm(desc, ctx);
2181
1893
            break;
2182
1894
 
2183
1895
        case CL_TYPE_MSOLE2:
2184
 
            ctx->container_type = CL_TYPE_MSOLE2;
2185
 
            ctx->container_size = sb.st_size;
2186
1896
            if(SCAN_OLE2 && (DCONF_ARCH & ARCH_CONF_OLE2))
2187
 
                ret = cli_scanole2(ctx);
2188
 
            break;
2189
 
 
2190
 
        case CL_TYPE_7Z:
2191
 
            ctx->container_type = CL_TYPE_7Z;
2192
 
            ctx->container_size = sb.st_size;
2193
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z))
2194
 
                ret = cli_7unz(desc, ctx);
 
1897
                ret = cli_scanole2(desc, ctx);
2195
1898
            break;
2196
1899
 
2197
1900
        case CL_TYPE_POSIX_TAR:
2198
 
            ctx->container_type = CL_TYPE_POSIX_TAR;
2199
 
            ctx->container_size = sb.st_size;
2200
1901
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
2201
1902
                ret = cli_scantar(desc, ctx, 1);
2202
1903
            break;
2203
1904
 
2204
1905
        case CL_TYPE_OLD_TAR:
2205
 
            ctx->container_type = CL_TYPE_OLD_TAR;
2206
 
            ctx->container_size = sb.st_size;
2207
1906
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
2208
1907
                ret = cli_scantar(desc, ctx, 0);
2209
1908
            break;
2210
1909
 
2211
 
        case CL_TYPE_CPIO_OLD:
2212
 
            ctx->container_type = CL_TYPE_CPIO_OLD;
2213
 
            ctx->container_size = sb.st_size;
2214
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2215
 
                ret = cli_scancpio_old(desc, ctx);
2216
 
            break;
2217
 
 
2218
 
        case CL_TYPE_CPIO_ODC:
2219
 
            ctx->container_type = CL_TYPE_CPIO_ODC;
2220
 
            ctx->container_size = sb.st_size;
2221
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2222
 
                ret = cli_scancpio_odc(desc, ctx);
2223
 
            break;
2224
 
 
2225
 
        case CL_TYPE_CPIO_NEWC:
2226
 
            ctx->container_type = CL_TYPE_CPIO_NEWC;
2227
 
            ctx->container_size = sb.st_size;
2228
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2229
 
                ret = cli_scancpio_newc(desc, ctx, 0);
2230
 
            break;
2231
 
 
2232
 
        case CL_TYPE_CPIO_CRC:
2233
 
            ctx->container_type = CL_TYPE_CPIO_CRC;
2234
 
            ctx->container_size = sb.st_size;
2235
 
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
2236
 
                ret = cli_scancpio_newc(desc, ctx, 1);
2237
 
            break;
2238
 
 
2239
1910
        case CL_TYPE_BINHEX:
2240
1911
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BINHEX))
2241
 
                ret = cli_binhex(ctx);
 
1912
                ret = cli_scanbinhex(desc, ctx);
2242
1913
            break;
2243
1914
 
2244
1915
        case CL_TYPE_SCRENC:
2248
1919
 
2249
1920
        case CL_TYPE_RIFF:
2250
1921
            if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_RIFF))
2251
 
                ret = cli_scanriff(desc, ctx);
 
1922
                ret = cli_scanriff(desc, ctx->virname);
2252
1923
            break;
2253
1924
 
2254
1925
        case CL_TYPE_GRAPHICS:
2255
1926
            if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_JPEG))
2256
 
                ret = cli_scanjpeg(desc, ctx);
 
1927
                ret = cli_scanjpeg(desc, ctx->virname);
2257
1928
            break;
2258
1929
 
2259
 
        case CL_TYPE_PDF: /* FIXMELIMITS: pdf should be an archive! */
2260
 
            ctx->container_type = CL_TYPE_PDF;
2261
 
            ctx->container_size = sb.st_size;
2262
 
            if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
2263
 
                ret = cli_scanpdf(ctx, 0);
 
1930
        case CL_TYPE_PDF:
 
1931
            if(SCAN_ARCHIVE && (DCONF_DOC & DOC_CONF_PDF))    /* you may wish to change this line */
 
1932
                ret = cli_scanpdf(desc, ctx);
2264
1933
            break;
2265
1934
 
2266
1935
        case CL_TYPE_CRYPTFF:
2270
1939
 
2271
1940
        case CL_TYPE_ELF:
2272
1941
            if(SCAN_ELF && ctx->dconf->elf)
2273
 
                ret = cli_scanelf(ctx);
2274
 
            break;
2275
 
 
2276
 
        case CL_TYPE_MACHO:
2277
 
            if(ctx->dconf->macho)
2278
 
                ret = cli_scanmacho(ctx, NULL);
2279
 
            break;
2280
 
 
2281
 
        case CL_TYPE_MACHO_UNIBIN:
2282
 
            if(ctx->dconf->macho)
2283
 
                ret = cli_scanmacho_unibin(ctx);
 
1942
                ret = cli_scanelf(desc, ctx);
2284
1943
            break;
2285
1944
 
2286
1945
        case CL_TYPE_SIS:
2287
 
            ctx->container_type = CL_TYPE_SIS;
2288
 
            ctx->container_size = sb.st_size;
2289
1946
            if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SIS))
2290
1947
                ret = cli_scansis(desc, ctx);
2291
1948
            break;
2292
1949
 
2293
 
        case CL_TYPE_BINARY_DATA:
2294
 
            if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_MYDOOMLOG))
2295
 
                ret = cli_check_mydoom_log(desc, ctx);
2296
 
            break;
 
1950
        case CL_TYPE_DATA:
 
1951
            /* it could be a false positive and a standard DOS .COM file */
 
1952
            {
 
1953
                struct stat s;
 
1954
                if(fstat(desc, &s) == 0 && S_ISREG(s.st_mode) && s.st_size < 65536)
 
1955
                type = CL_TYPE_UNKNOWN_DATA;
 
1956
            }
2297
1957
 
2298
 
        case CL_TYPE_TEXT_ASCII:
2299
 
            if(SCAN_STRUCTURED && (DCONF_OTHER & OTHER_CONF_DLP))
2300
 
                /* TODO: consider calling this from cli_scanscript() for
2301
 
                 * a normalised text
2302
 
                 */
2303
 
                ret = cli_scan_structured(desc, ctx);
 
1958
        case CL_TYPE_UNKNOWN_DATA:
 
1959
            ret = cli_check_mydoom_log(desc, ctx->virname);
2304
1960
            break;
2305
1961
 
2306
1962
        default:
2307
1963
            break;
2308
1964
    }
2309
 
    ctx->recursion--;
2310
 
    ctx->container_type = current_container_type;
2311
 
    ctx->container_size = current_container_size;
2312
 
 
2313
 
    if(ret == CL_VIRUS) {
2314
 
        ret = cli_checkfp(hash, hashed_size, ctx);
2315
 
        funmap(*ctx->fmap);
2316
 
        ctx->fmap--;
2317
 
        cli_bitset_free(ctx->hook_lsig_matches);
2318
 
        ctx->hook_lsig_matches = old_hook_lsig_matches;
2319
 
        ret_from_magicscan(ret);
2320
 
    }
2321
 
 
2322
 
    if(type == CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP)) {
2323
 
        if(sb.st_size > 1048576) {
2324
 
            cli_dbgmsg("cli_magic_scandesc: Not checking for embedded PEs (zip file > 1 MB)\n");
2325
 
            typercg = 0;
2326
 
        }
2327
 
    }
2328
 
 
2329
 
    /* CL_TYPE_HTML: raw HTML files are not scanned, unless safety measure activated via DCONF */
2330
 
    if(type != CL_TYPE_IGNORED && (type != CL_TYPE_HTML || !(DCONF_DOC & DOC_CONF_HTML_SKIPRAW)) && !ctx->engine->sdb) {
2331
 
        if(cli_scanraw(ctx, type, typercg, &dettype, hash) == CL_VIRUS) {
2332
 
            ret =  cli_checkfp(hash, hashed_size, ctx);
2333
 
            funmap(*ctx->fmap);
2334
 
            ctx->fmap--;
2335
 
            cli_bitset_free(ctx->hook_lsig_matches);
2336
 
            ctx->hook_lsig_matches = old_hook_lsig_matches;
2337
 
            ret_from_magicscan(ret);
2338
 
        }
2339
 
    }
2340
 
 
2341
 
    ctx->recursion++;
 
1965
 
 
1966
    type == CL_TYPE_MAIL ? ctx->mrec-- : ctx->arec--;
 
1967
 
 
1968
    if(type != CL_TYPE_DATA && ret != CL_VIRUS && !ctx->engine->sdb) {
 
1969
        if(cli_scanraw(desc, ctx, type) == CL_VIRUS)
 
1970
            return CL_VIRUS;
 
1971
    }
 
1972
 
 
1973
    ctx->arec++;
2342
1974
    lseek(desc, 0, SEEK_SET);
2343
1975
    switch(type) {
2344
 
        /* bytecode hooks triggered by a lsig must be a hook
2345
 
         * called from one of the functions here */
2346
 
        case CL_TYPE_TEXT_ASCII:
2347
 
        case CL_TYPE_TEXT_UTF16BE:
2348
 
        case CL_TYPE_TEXT_UTF16LE:
2349
 
        case CL_TYPE_TEXT_UTF8:
2350
 
            if((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML)
2351
 
                ret = cli_scanscript(ctx);
2352
 
            if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX) && ret != CL_VIRUS && (ctx->container_type == CL_TYPE_MAIL || dettype == CL_TYPE_MAIL)) {
2353
 
                lseek(desc, 0, SEEK_SET);
2354
 
                ret = cli_scandesc(desc, ctx, CL_TYPE_MAIL, 0, NULL, AC_SCAN_VIR, NULL);
2355
 
            }
2356
 
            break;
2357
1976
        /* Due to performance reasons all executables were first scanned
2358
1977
         * in raw mode. Now we will try to unpack them
2359
1978
         */
2360
1979
        case CL_TYPE_MSEXE:
2361
 
            if(SCAN_PE && ctx->dconf->pe) {
2362
 
                unsigned int corrupted_input = ctx->corrupted_input;
2363
 
                ret = cli_scanpe(ctx);
2364
 
                ctx->corrupted_input = corrupted_input;
2365
 
            }
2366
 
            break;
2367
 
        default:
2368
 
            break;
2369
 
    }
2370
 
 
2371
 
    if(ret == CL_VIRUS)
2372
 
        ret = cli_checkfp(hash, hashed_size, ctx);
2373
 
    ctx->recursion--;
2374
 
    funmap(*ctx->fmap);
2375
 
    ctx->fmap--;
2376
 
    cli_bitset_free(ctx->hook_lsig_matches);
2377
 
    ctx->hook_lsig_matches = old_hook_lsig_matches;
2378
 
 
2379
 
    switch(ret) {
2380
 
        case CL_EFORMAT:
2381
 
        case CL_EMAXREC:
2382
 
        case CL_EMAXSIZE:
2383
 
        case CL_EMAXFILES:
2384
 
            cli_dbgmsg("Descriptor[%d]: %s\n", desc, cl_strerror(ret));
2385
 
        case CL_CLEAN:
2386
 
            cache_add(hash, hashed_size, ctx);
2387
 
            ret_from_magicscan(CL_CLEAN);
2388
 
        default:
2389
 
            ret_from_magicscan(ret);
2390
 
    }
2391
 
}
2392
 
 
2393
 
int cli_magic_scandesc(int desc, cli_ctx *ctx)
2394
 
{
2395
 
    return magic_scandesc(desc, ctx, CL_TYPE_ANY);
2396
 
}
2397
 
 
2398
 
int cli_magic_scandesc_type(int desc, cli_ctx *ctx, cli_file_t type)
2399
 
{
2400
 
    return magic_scandesc(desc, ctx, type);
2401
 
}
2402
 
 
2403
 
int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
2404
 
{
2405
 
    return cl_scandesc_callback(desc, virname, scanned, engine, scanoptions, NULL);
2406
 
}
2407
 
 
2408
 
int cl_scandesc_callback(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
 
1980
            if(SCAN_PE && ctx->dconf->pe)
 
1981
                ret = cli_scanpe(desc, ctx);
 
1982
            break;
 
1983
 
 
1984
        default:
 
1985
            break;
 
1986
    }
 
1987
    ctx->arec--;
 
1988
 
 
1989
    if(ret == CL_EFORMAT) {
 
1990
        cli_dbgmsg("Descriptor[%d]: %s\n", desc, cl_strerror(CL_EFORMAT));
 
1991
        return CL_CLEAN;
 
1992
    } else {
 
1993
        return ret;
 
1994
    }
 
1995
}
 
1996
 
 
1997
int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options)
2409
1998
{
2410
1999
    cli_ctx ctx;
2411
 
    int rc;
2412
2000
 
2413
2001
    memset(&ctx, '\0', sizeof(cli_ctx));
2414
2002
    ctx.engine = engine;
2415
2003
    ctx.virname = virname;
 
2004
    ctx.limits = limits;
2416
2005
    ctx.scanned = scanned;
2417
 
    ctx.options = scanoptions;
2418
 
    ctx.found_possibly_unwanted = 0;
2419
 
    ctx.container_type = CL_TYPE_ANY;
2420
 
    ctx.container_size = 0;
 
2006
    ctx.options = options;
2421
2007
    ctx.dconf = (struct cli_dconf *) engine->dconf;
2422
 
    ctx.cb_ctx = context;
2423
 
    ctx.fmap = cli_calloc(sizeof(fmap_t *), ctx.engine->maxreclevel + 2);
2424
 
    if(!ctx.fmap)
2425
 
        return CL_EMEM;
2426
 
    if (!(ctx.hook_lsig_matches = cli_bitset_init())) {
2427
 
        free(ctx.fmap);
2428
 
        return CL_EMEM;
2429
 
    }
2430
 
 
2431
 
#ifdef HAVE__INTERNAL__SHA_COLLECT
2432
 
    if(scanoptions & CL_SCAN_INTERNAL_COLLECT_SHA) {
2433
 
        char link[32];
2434
 
        ssize_t linksz;
2435
 
 
2436
 
        snprintf(link, sizeof(link), "/proc/self/fd/%u", desc);
2437
 
        link[sizeof(link)-1]='\0';
2438
 
        if((linksz=readlink(link, ctx.entry_filename, sizeof(ctx.entry_filename)))==-1) {
2439
 
            cli_errmsg("failed to resolve filename for descriptor %d (%s)\n", desc, link);
2440
 
            strcpy(ctx.entry_filename, "NO_IDEA");
2441
 
        } else
2442
 
            ctx.entry_filename[linksz]='\0';
2443
 
    } while(0);
2444
 
#endif
2445
 
 
2446
 
    cli_logg_setup(&ctx);
2447
 
    rc = cli_magic_scandesc(desc, &ctx);
2448
 
 
2449
 
    cli_bitset_free(ctx.hook_lsig_matches);
2450
 
    free(ctx.fmap);
2451
 
    if(rc == CL_CLEAN && ctx.found_possibly_unwanted)
2452
 
        rc = CL_VIRUS;
2453
 
    cli_logg_unsetup();
2454
 
    return rc;
2455
 
}
2456
 
 
2457
 
int cli_found_possibly_unwanted(cli_ctx* ctx)
2458
 
{
2459
 
        if(ctx->virname) {
2460
 
                cli_dbgmsg("found Possibly Unwanted: %s\n",*ctx->virname);
2461
 
                if(ctx->options & CL_SCAN_HEURISTIC_PRECEDENCE) {
2462
 
                        /* we found a heuristic match, don't scan further,
2463
 
                         * but consider it a virus. */
2464
 
                        cli_dbgmsg("cli_found_possibly_unwanted: CL_VIRUS\n");
2465
 
                        return CL_VIRUS;
2466
 
                }
2467
 
                /* heuristic scan isn't taking precedence, keep scanning.
2468
 
                 * If this is part of an archive, and 
2469
 
                 * we find a real malware we report that instead of the 
2470
 
                 * heuristic match */
2471
 
                ctx->found_possibly_unwanted = 1;
2472
 
        } else {
2473
 
                cli_warnmsg("cli_found_possibly_unwanted called, but virname is not set\n");
2474
 
        }
2475
 
        emax_reached(ctx);
2476
 
        return CL_CLEAN;
 
2008
 
 
2009
    return cli_magic_scandesc(desc, &ctx);
2477
2010
}
2478
2011
 
2479
2012
static int cli_scanfile(const char *filename, cli_ctx *ctx)
2481
2014
        int fd, ret;
2482
2015
 
2483
2016
    /* internal version of cl_scanfile with arec/mrec preserved */
2484
 
    if((fd = safe_open(filename, O_RDONLY|O_BINARY)) == -1)
 
2017
    if((fd = open(filename, O_RDONLY|O_BINARY)) == -1)
2485
2018
        return CL_EOPEN;
2486
2019
 
2487
2020
    ret = cli_magic_scandesc(fd, ctx);
2490
2023
    return ret;
2491
2024
}
2492
2025
 
2493
 
int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
2494
 
{
2495
 
    return cl_scanfile_callback(filename, virname, scanned, engine, scanoptions, NULL);
2496
 
}
2497
 
 
2498
 
int cl_scanfile_callback(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
 
2026
int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options)
2499
2027
{
2500
2028
        int fd, ret;
2501
2029
 
2502
 
    if((fd = safe_open(filename, O_RDONLY|O_BINARY)) == -1)
 
2030
 
 
2031
    if((fd = open(filename, O_RDONLY|O_BINARY)) == -1)
2503
2032
        return CL_EOPEN;
2504
2033
 
2505
 
    ret = cl_scandesc_callback(fd, virname, scanned, engine, scanoptions, context);
 
2034
    ret = cl_scandesc(fd, virname, scanned, engine, limits, options);
2506
2035
    close(fd);
2507
2036
 
2508
2037
    return ret;
2509
2038
}
2510
 
 
2511
 
/*
2512
 
Local Variables:
2513
 
   c-basic-offset: 4
2514
 
End:
2515
 
*/