~louis/ubuntu/trusty/clamav/lp799623_fix_logrotate

« back to all changes in this revision

Viewing changes to libclamav/binhex.c

  • Committer: Bazaar Package Importer
  • Author(s): Scott Kitterman
  • Date: 2010-03-12 11:30:04 UTC
  • mfrom: (0.41.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100312113004-b0fop4bkycszdd0z
Tags: 0.96~rc1+dfsg-0ubuntu1
* New upstream RC - FFE (LP: #537636):
  - Add OfficialDatabaseOnly option to clamav-base.postinst.in
  - Add LocalSocketGroup option to clamav-base.postinst.in
  - Add LocalSocketMode option to clamav-base.postinst.in
  - Add CrossFilesystems option to clamav-base.postinst.in
  - Add ClamukoScannerCount option to clamav-base.postinst.in
  - Add BytecodeSecurity opiton to clamav-base.postinst.in
  - Add DetectionStatsHostID option to clamav-freshclam.postinst.in
  - Add Bytecode option to clamav-freshclam.postinst.in
  - Add MilterSocketGroup option to clamav-milter.postinst.in
  - Add MilterSocketMode option to clamav-milter.postinst.in
  - Add ReportHostname option to clamav-milter.postinst.in
  - Bump libclamav SO version to 6.1.0 in libclamav6.install
  - Drop clamdmon from clamav.examples (no longer shipped by upstream)
  - Drop libclamav.a from libclamav-dev.install (not built by upstream)
  - Update SO version for lintian override for libclamav6
  - Add new Bytecode Testing Tool, usr/bin/clambc, to clamav.install
  - Add build-depends on python and python-setuptools for new test suite
  - Update debian/copyright for the embedded copy of llvm (using the system
    llvm is not currently feasible)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 *  Copyright (C) 2007-2008 Sourcefire, Inc.
 
2
 *  Copyright (C) 2010 Sourcefire, Inc.
3
3
 *
4
 
 *  Authors: Nigel Horne
 
4
 *  Authors: aCaB <acab@clamav.net>
5
5
 *
6
6
 *  This program is free software; you can redistribute it and/or modify
7
7
 *  it under the terms of the GNU General Public License version 2 as
17
17
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18
18
 *  MA 02110-1301, USA.
19
19
 *
20
 
 * Change History:
21
 
 * $Log: binhex.c,v $
22
 
 * Revision 1.23  2007/02/12 20:46:08  njh
23
 
 * Various tidy
24
 
 *
25
 
 * Revision 1.22  2006/07/31 09:19:52  njh
26
 
 * Use MAP_PRIVATE
27
 
 *
28
 
 * Revision 1.21  2006/07/01 16:17:35  njh
29
 
 * Added destroy flag
30
 
 *
31
 
 * Revision 1.20  2006/07/01 03:47:50  njh
32
 
 * Don't loop if binhex runs out of memory
33
 
 *
34
 
 * Revision 1.19  2006/05/19 11:02:12  njh
35
 
 * Just include mbox.h
36
 
 *
37
 
 * Revision 1.18  2006/04/09 19:59:27  kojm
38
 
 * update GPL headers with new address for FSF
39
 
 *
40
 
 * Revision 1.17  2005/11/06 14:03:26  nigelhorne
41
 
 * Ensure NAME_MAX isn't redefined on BeOS
42
 
 *
43
 
 * Revision 1.16  2005/05/14 16:13:25  nigelhorne
44
 
 * Ensure munmap is the right size
45
 
 *
46
 
 * Revision 1.15  2005/05/13 19:30:34  nigelhorne
47
 
 * Clean cli_realloc call
48
 
 *
49
 
 * Revision 1.14  2005/03/10 08:51:30  nigelhorne
50
 
 * Tidy
51
 
 *
52
 
 * Revision 1.13  2005/01/19 05:29:41  nigelhorne
53
 
 * tidy
54
 
 *
55
 
 * Revision 1.12  2004/12/27 14:17:14  nigelhorne
56
 
 * Fix segfault if write to temporary file fails
57
 
 *
58
 
 * Revision 1.11  2004/12/17 12:03:38  nigelhorne
59
 
 * Tidy up for machines without MMAP
60
 
 *
61
 
 * Revision 1.10  2004/12/16 15:29:51  nigelhorne
62
 
 * Tidy
63
 
 *
64
 
 * Revision 1.9  2004/11/28 22:06:39  nigelhorne
65
 
 * Tidy space only headers code
66
 
 *
67
 
 * Revision 1.8  2004/11/28 21:05:50  nigelhorne
68
 
 * Handle headers with only spaces
69
 
 *
70
 
 * Revision 1.7  2004/11/23 09:05:26  nigelhorne
71
 
 * Fix crash in base64 encoded binhex files
72
 
 *
73
 
 * Revision 1.6  2004/11/22 15:16:53  nigelhorne
74
 
 * Use cli_realloc instead of many cli_mallocs
75
 
 *
76
 
 * Revision 1.5  2004/11/18 20:11:34  nigelhorne
77
 
 * Fix segfault
78
 
 *
79
 
 * Revision 1.4  2004/11/18 19:30:29  kojm
80
 
 * add support for Mac's HQX file format
81
 
 *
82
 
 * Revision 1.3  2004/11/18 18:24:45  nigelhorne
83
 
 * Added binhex.h
84
 
 *
85
 
 * Revision 1.2  2004/11/18 18:09:06  nigelhorne
86
 
 * First draft of binhex.c
87
 
 *
88
20
 */
89
 
static  char    const   rcsid[] = "$Id: binhex.c,v 1.23 2007/02/12 20:46:08 njh Exp $";
90
 
 
91
 
#include "clamav.h"
92
21
 
93
22
#if HAVE_CONFIG_H
94
23
#include "clamav-config.h"
95
24
#endif
96
25
 
97
 
#ifdef CL_THREAD_SAFE
98
 
#ifndef _REENTRANT
99
 
#define _REENTRANT      /* for Solaris 2.8 */
100
 
#endif
101
 
#endif
102
 
 
103
 
#ifdef  HAVE_MMAP
104
 
#if HAVE_SYS_MMAN_H
105
 
#include <sys/mman.h>
106
 
#else /* HAVE_SYS_MMAN_H */
107
 
#undef HAVE_MMAP
108
 
#endif
109
 
#endif
110
 
 
111
 
#include <stdio.h>
112
 
#include <memory.h>
113
 
#include <sys/stat.h>
 
26
#include <string.h>
 
27
 
 
28
#include "scanners.h"
 
29
#include "cltypes.h"
114
30
#include "others.h"
115
 
 
116
 
#include "mbox.h"
117
 
#include "binhex.h"
118
 
 
119
 
int
120
 
cli_binhex(const char *dir, int desc)
121
 
{
122
 
#ifndef HAVE_MMAP
123
 
        cli_warnmsg("File not decoded - binhex decoding needs mmap() (for now)\n");
124
 
        return CL_CLEAN;
125
 
#else
126
 
        struct stat statb;
127
 
        char *buf, *start, *line;
128
 
        size_t size;
129
 
        long bytesleft;
130
 
        message *m;
131
 
        fileblob *fb;
132
 
 
133
 
        if(fstat(desc, &statb) < 0)
134
 
                return CL_EOPEN;
135
 
 
136
 
        size = (size_t)statb.st_size;
137
 
 
138
 
        if(size == 0)
139
 
                return CL_CLEAN;
140
 
 
141
 
        m = messageCreate();
142
 
        if(m == NULL)
143
 
                return CL_EMEM;
144
 
 
145
 
        start = buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, desc, 0);
146
 
        if(buf == MAP_FAILED) {
147
 
                messageDestroy(m);
148
 
                return CL_EMAP;
149
 
        }
150
 
 
151
 
        cli_dbgmsg("mmap'ed binhex file\n");
152
 
 
153
 
        bytesleft = (long)size;
154
 
        line = NULL;
155
 
 
156
 
        while(bytesleft > 0) {
157
 
                int length = 0;
158
 
                char *ptr, *newline;
159
 
 
160
 
                /*printf("%d: ", bytesleft);*/
161
 
 
162
 
                for(ptr = buf; bytesleft && (*ptr != '\n') && (*ptr != '\r'); ptr++) {
163
 
                        length++;
164
 
                        --bytesleft;
165
 
                }
166
 
 
167
 
                /*printf("%d: ", length);*/
168
 
 
169
 
                newline = cli_realloc(line, (size_t)(length + 1));
170
 
                if(newline == NULL)
171
 
                        break;
172
 
 
173
 
                line = newline;
174
 
 
175
 
                memcpy(line, buf, length);
176
 
                line[length] = '\0';
177
 
 
178
 
                /*puts(line);*/
179
 
 
180
 
                if(messageAddStr(m, line) < 0)
181
 
                        break;
182
 
 
183
 
                if((bytesleft > 0) && (*ptr == '\r')) {
184
 
                        ptr++;
185
 
                        bytesleft--;
186
 
                }
187
 
                buf = ++ptr;
188
 
                bytesleft--;
189
 
        }
190
 
        munmap(start, size);
191
 
 
192
 
        if(line)
193
 
                free(line);
194
 
 
195
 
        if(binhexBegin(m) == NULL) {
196
 
                messageDestroy(m);
197
 
                cli_dbgmsg("No binhex line found\n");
198
 
                return CL_EFORMAT;
199
 
        }
200
 
 
201
 
        /* similar to binhexMessage */
202
 
        messageSetEncoding(m, "x-binhex");
203
 
 
204
 
        fb = messageToFileblob(m, dir, 1);
205
 
        if(fb) {
206
 
                cli_dbgmsg("Binhex file decoded to %s\n", fileblobGetFilename(fb));
207
 
                fileblobDestroy(fb);
208
 
        } else
209
 
                cli_errmsg("Couldn't decode binhex file to %s\n", dir);
210
 
        messageDestroy(m);
211
 
 
212
 
        if(fb)
213
 
                return CL_CLEAN;        /* a lie - but it gets things going */
214
 
        /* return CL_EIO; */    /* probably CL_EMEM, but we can't tell at this layer */
215
 
        return CL_EMEM;
216
 
#endif
 
31
#include "clamav.h"
 
32
#include "fmap.h"
 
33
 
 
34
 
 
35
static const uint8_t hqxtbl[] = {
 
36
    /*           00   01   02   03   04   05   06   07   08   09   0a   0b   0c   0d   0e   0f */
 
37
    /* 00-0f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 
38
    /* 10-1f */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 
39
    /* 20-2f */ 0xff,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0xff,0xff,
 
40
    /* 30-3f */ 0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0xff,0x14,0x15,0xff,0xff,0xff,0xff,0xff,0xff,
 
41
    /* 40-4f */ 0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0xff,
 
42
    /* 50-5f */ 0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0xff,0x2c,0x2d,0x2e,0x2f,0xff,0xff,0xff,0xff,
 
43
    /* 60-6f */ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0xff,0x37,0x38,0x39,0x3a,0x3b,0x3c,0xff,0xff,
 
44
    /* 70-7f */ 0x3d,0x3e,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
 
45
};
 
46
 
 
47
#define BH_FLUSH_SZ (BUFSIZ - 256)
 
48
 
 
49
int cli_binhex(cli_ctx *ctx) {
 
50
    fmap_t *map = *ctx->fmap;
 
51
    uint8_t *encoded, decoded[BUFSIZ], spare_bits, last_byte=0, this_byte, offset=0;
 
52
    size_t enc_done=0, enc_todo=map->len;
 
53
    unsigned int dec_done=0, chunksz = 0, chunkoff=0;
 
54
    uint32_t datalen, reslen;
 
55
    int in_data = 0, in_run = 0, datafd, resfd, ret = CL_CLEAN;
 
56
    enum binhex_phase { IN_BANNER, IN_HEADER, IN_DATA, IN_LIMBO1, IN_LIMBO2, IN_RES } write_phase = IN_BANNER;
 
57
    char *dname, *rname;
 
58
 
 
59
    cli_dbgmsg("in cli_binhex\n");
 
60
    if(!map->len) return CL_CLEAN;
 
61
 
 
62
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &dname, &datafd)) != CL_SUCCESS)
 
63
        return ret;
 
64
 
 
65
    if((ret = cli_gentempfd(ctx->engine->tmpdir, &rname, &resfd)) != CL_SUCCESS) {
 
66
        close(datafd);
 
67
        if(cli_unlink(dname)) ret = CL_EUNLINK;
 
68
        free(dname);
 
69
        return ret;
 
70
    }
 
71
 
 
72
    while(1) {
 
73
        uint8_t b;
 
74
        if(!enc_todo || dec_done >= BH_FLUSH_SZ) {
 
75
            if(write_phase == IN_HEADER) {
 
76
                uint32_t namelen = (uint32_t)decoded[0], hdrlen = 1 + namelen + 1 + 4 + 4 + 2;
 
77
                if(!dec_done) {
 
78
                    cli_dbgmsg("cli_binhex: file is empty\n");
 
79
                    break;
 
80
                }
 
81
                datalen = (decoded[hdrlen]<<24) | (decoded[hdrlen+1]<<16) | (decoded[hdrlen+2]<<8) | decoded[hdrlen+3];
 
82
                hdrlen += 4;
 
83
                reslen = (decoded[hdrlen]<<24) | (decoded[hdrlen+1]<<16) | (decoded[hdrlen+2]<<8) | decoded[hdrlen+3];
 
84
                hdrlen += 4 + 2;
 
85
                decoded[namelen+1] = 0;
 
86
                if(dec_done <= hdrlen) {
 
87
                    cli_dbgmsg("cli_binhex: file too short for header\n");
 
88
                    break;
 
89
                }
 
90
                if((ret = cli_checklimits("cli_binhex(data)", ctx, datalen, 0, 0)) != CL_CLEAN)
 
91
                    break;
 
92
                if(cli_checklimits("cli_binhex(resources)", ctx, reslen, 0, 0) != CL_CLEAN)
 
93
                    reslen = 0;
 
94
                cli_dbgmsg("cli_binhex: decoding '%s' - %u bytes of data to %s - %u bytes or resources to %s\n", decoded+1, datalen, dname, reslen, rname);
 
95
                memmove(decoded, &decoded[hdrlen], dec_done - hdrlen);
 
96
                dec_done -= hdrlen;
 
97
                write_phase++;
 
98
            }
 
99
            if(dec_done && write_phase == IN_DATA) {
 
100
                unsigned int todo = MIN(dec_done, datalen);
 
101
                datalen -= todo;
 
102
                dec_done -= todo;
 
103
                if(cli_writen(datafd, decoded, todo)!=(int)todo) {
 
104
                    ret = CL_EWRITE;
 
105
                    break;
 
106
                }
 
107
                if(!datalen) {
 
108
                    write_phase++;
 
109
                    lseek(datafd, 0, SEEK_SET);
 
110
                    ret = cli_magic_scandesc(datafd, ctx);
 
111
                    if(ret == CL_VIRUS) break;
 
112
                }
 
113
                if(dec_done)
 
114
                    memmove(decoded, &decoded[todo], dec_done);
 
115
            }
 
116
            if(dec_done && write_phase == IN_LIMBO1) {
 
117
                if(dec_done > 1) {
 
118
                    if(reslen<5) {
 
119
                        cli_dbgmsg("cli_binhex: skipping resources (too small)\n");
 
120
                        break;
 
121
                    }
 
122
                    dec_done-=2;
 
123
                    write_phase+=2;
 
124
                    if(dec_done)
 
125
                        memmove(decoded, &decoded[2], dec_done);
 
126
                } else {
 
127
                    dec_done--;
 
128
                    write_phase++;
 
129
                    if(dec_done)
 
130
                        memmove(decoded, &decoded[1], dec_done);
 
131
                }
 
132
            }
 
133
            if(dec_done && write_phase == IN_LIMBO2) {
 
134
                if(reslen<5) {
 
135
                    cli_dbgmsg("cli_binhex: skipping resources (too small)\n");
 
136
                    break;
 
137
                }
 
138
                write_phase++;
 
139
                if(--dec_done)
 
140
                    memmove(decoded, &decoded[1], dec_done);
 
141
            }
 
142
            if(dec_done && write_phase == IN_RES) {
 
143
                unsigned int todo = MIN(dec_done, reslen);
 
144
                reslen -= todo;
 
145
                dec_done -= todo;
 
146
                if(cli_writen(resfd, decoded, todo)!=(int)todo) {
 
147
                    ret = CL_EWRITE;
 
148
                    break;
 
149
                }
 
150
                if(!reslen) {
 
151
                    lseek(resfd, 0, SEEK_SET);
 
152
                    ret = cli_magic_scandesc(resfd, ctx);
 
153
                    break;
 
154
                }
 
155
            }
 
156
            if(!enc_todo) {
 
157
                if(write_phase == IN_DATA) {
 
158
                    cli_dbgmsg("cli_binhex: scanning partially extracted data fork\n");
 
159
                    lseek(datafd, 0, SEEK_SET);
 
160
                    ret = cli_magic_scandesc(datafd, ctx);
 
161
                } else if(write_phase == IN_RES) {
 
162
                    cli_dbgmsg("cli_binhex: scanning partially extracted resource fork\n");
 
163
                    lseek(resfd, 0, SEEK_SET);
 
164
                    ret = cli_magic_scandesc(resfd, ctx);
 
165
                }
 
166
                break;
 
167
            }
 
168
        }
 
169
 
 
170
        if(!chunksz) {
 
171
            chunksz = MIN(enc_todo, map->pgsz);
 
172
            encoded = fmap_need_off_once(map, enc_done, chunksz);
 
173
            if(!encoded) {
 
174
                ret = CL_EREAD;
 
175
                break;
 
176
            }
 
177
            chunkoff = 0;
 
178
        }
 
179
        chunksz--;
 
180
 
 
181
        b = encoded[chunkoff++];
 
182
        enc_done++;
 
183
        enc_todo--;
 
184
 
 
185
        if((char)b == '\r' || (char)b == '\n') {
 
186
            in_data = 1;
 
187
            continue;
 
188
        }
 
189
        if(!in_data) continue;
 
190
        if(write_phase == IN_BANNER) {
 
191
            if((char)b != ':') {
 
192
                cli_dbgmsg("cli_binhex: broken file (missing stream start identifier)\n");
 
193
                break;
 
194
            }
 
195
            write_phase++;
 
196
        }
 
197
        if((char)b == ':')
 
198
            continue;
 
199
        if(b > 0x7f || (b = hqxtbl[b]) == 0xff) {
 
200
            cli_dbgmsg("cli_binhex: Invalid character (%02x)\n", encoded[chunkoff-1]);
 
201
            break;
 
202
        }
 
203
        switch((offset++) & 3) { /* 6 bits per char */
 
204
        case 0: /* left-6h */
 
205
            spare_bits = b<<2;
 
206
            continue;
 
207
        case 1: /* left-2l + middle-4h */
 
208
            this_byte = spare_bits | (b>>4);
 
209
            spare_bits = b<<4;
 
210
            break;
 
211
        case 2: /* middle-4l + right-2h */
 
212
            this_byte = spare_bits | (b>>2);
 
213
            spare_bits = b<<6;
 
214
            break;
 
215
        case 3: /* right-6l */
 
216
            this_byte = spare_bits | b;
 
217
        }
 
218
 
 
219
        if(in_run) {
 
220
            in_run = 0;
 
221
            if(!this_byte)
 
222
                this_byte = 0x90;
 
223
            else {
 
224
                while(--this_byte) 
 
225
                    decoded[dec_done++] = last_byte;
 
226
                continue;
 
227
            }
 
228
        } else if(this_byte == 0x90) {
 
229
            in_run = 1;
 
230
            continue;
 
231
        }
 
232
        decoded[dec_done++] = this_byte;
 
233
        last_byte = this_byte;
 
234
    }
 
235
 
 
236
    close(datafd);
 
237
    close(resfd);
 
238
    if(!ctx->engine->keeptmp) {
 
239
        if(cli_unlink(dname) && ret != CL_VIRUS) ret = CL_EUNLINK;
 
240
        if(cli_unlink(rname) && ret != CL_VIRUS) ret = CL_EUNLINK;
 
241
    }
 
242
    free(dname);
 
243
    free(rname);
 
244
    return ret;
217
245
}