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

« back to all changes in this revision

Viewing changes to libclamav/vba_extract.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
2
 *  Extract VBA source code for component MS Office Documents
3
3
 *
4
 
 *  Copyright (C) 2007-2008 Sourcefire, Inc.
5
 
 *
6
 
 *  Authors: Trog, Nigel Horne
7
 
 *
 
4
 *  Copyright (C) 2004-2005 trog@uncon.org
 
5
 *
 
6
 *  This code is based on the OpenOffice and libgsf sources.
 
7
 *                  
8
8
 *  This program is free software; you can redistribute it and/or modify
9
 
 *  it under the terms of the GNU General Public License version 2 as
10
 
 *  published by the Free Software Foundation.
 
9
 *  it under the terms of the GNU General Public License as published by
 
10
 *  the Free Software Foundation; either version 2 of the License, or
 
11
 *  (at your option) any later version.
11
12
 *
12
13
 *  This program is distributed in the hope that it will be useful,
13
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20
21
 *  MA 02110-1301, USA.
21
22
 */
22
23
 
23
 
#if HAVE_CONFIG_H
24
 
#include "clamav-config.h"
25
 
#endif
26
 
 
27
24
#include <stdio.h>
28
25
#include <string.h>
29
26
#ifdef  HAVE_UNISTD_H
30
27
#include <unistd.h>
31
28
#endif
 
29
#include <sys/types.h>
 
30
#include <sys/stat.h>
32
31
#include <fcntl.h>
33
32
#include <stdlib.h>
34
33
#include <ctype.h>
36
35
 
37
36
#include "clamav.h"
38
37
 
 
38
#if HAVE_CONFIG_H
 
39
#include "clamav-config.h"
 
40
#endif
 
41
 
 
42
#include "vba_extract.h"
39
43
#include "others.h"
40
 
#include "scanners.h"
41
 
#include "vba_extract.h"
42
 
#ifdef  CL_DEBUG
43
 
#include "mbox.h"
44
 
#endif
45
 
#include "blob.h"
46
 
 
47
 
#define PPT_LZW_BUFFSIZE 8192
48
 
#define VBA_COMPRESSION_WINDOW 4096
49
 
#define MIDDLE_SIZE     20
50
 
#define MAX_VBA_COUNT   1000    /* If there's more than 1000 macros something's up! */
51
 
 
52
 
#ifndef HAVE_ATTRIB_PACKED
53
 
#define __attribute__(x)
54
 
#endif
55
 
 
56
 
/*
57
 
 * VBA (Visual Basic for Applications), versions 5 and 6
58
 
 */
59
 
struct vba56_header {
60
 
        unsigned char magic[2];
61
 
        unsigned char version[4];
62
 
        unsigned char ignore[28];
63
 
};
64
 
 
65
 
typedef struct {
66
 
        uint32_t sig;
67
 
        const char *ver;
68
 
        int     big_endian;     /* e.g. MAC Office */
 
44
 
 
45
#ifndef O_BINARY
 
46
#define O_BINARY        0
 
47
#endif
 
48
 
 
49
typedef struct vba_version_tag {
 
50
        unsigned char signature[4];
 
51
        const char *name;
 
52
        int vba_version;
 
53
        int is_mac;
69
54
} vba_version_t;
70
55
 
71
 
static  int     skip_past_nul(int fd);
72
 
static  int     read_uint16(int fd, uint16_t *u, int big_endian);
73
 
static  int     read_uint32(int fd, uint32_t *u, int big_endian);
74
 
static  int     seekandread(int fd, off_t offset, int whence, void *data, size_t len);
75
 
static  vba_project_t   *create_vba_project(int record_count, const char *dir, struct uniq *U);
76
56
 
77
 
static uint16_t
78
 
vba_endian_convert_16(uint16_t value, int big_endian)
 
57
static uint16_t vba_endian_convert_16(uint16_t value, int is_mac)
79
58
{
80
 
        if (big_endian)
81
 
                return (uint16_t)be16_to_host(value);
 
59
        if (is_mac)
 
60
                return be16_to_host(value);
82
61
        else
83
62
                return le16_to_host(value);
84
63
}
85
 
 
86
 
/* Seems to be a duplicate of riff_endian_convert_32() */
87
 
static uint32_t
88
 
vba_endian_convert_32(uint32_t value, int big_endian)
 
64
 
 
65
static uint32_t vba_endian_convert_32(uint32_t value, int is_mac)
89
66
{
90
 
        if (big_endian)
 
67
        if (is_mac)
91
68
                return be32_to_host(value);
92
69
        else
93
70
                return le32_to_host(value);
94
71
}
95
72
 
96
 
 
97
 
static char *
98
 
get_unicode_name(const char *name, int size, int big_endian)
 
73
typedef struct byte_array_tag {
 
74
        unsigned int length;
 
75
        unsigned char *data;
 
76
} byte_array_t;
 
77
 
 
78
#define NUM_VBA_VERSIONS 14
 
79
vba_version_t vba_version[] = {
 
80
        { { 0x5e, 0x00, 0x00, 0x01 }, "Office 97",              5, FALSE},
 
81
        { { 0x5f, 0x00, 0x00, 0x01 }, "Office 97 SR1",          5, FALSE },
 
82
        { { 0x65, 0x00, 0x00, 0x01 }, "Office 2000 alpha?",     6, FALSE },
 
83
        { { 0x6b, 0x00, 0x00, 0x01 }, "Office 2000 beta?",      6, FALSE },
 
84
        { { 0x6d, 0x00, 0x00, 0x01 }, "Office 2000",            6, FALSE },
 
85
        { { 0x6f, 0x00, 0x00, 0x01 }, "Office 2000",            6, FALSE },
 
86
        { { 0x70, 0x00, 0x00, 0x01 }, "Office XP beta 1/2",     6, FALSE },
 
87
        { { 0x73, 0x00, 0x00, 0x01 }, "Office XP",              6, FALSE },
 
88
        { { 0x76, 0x00, 0x00, 0x01 }, "Office 2003",            6, FALSE },
 
89
        { { 0x79, 0x00, 0x00, 0x01 }, "Office 2003",            6, FALSE },
 
90
        { { 0x60, 0x00, 0x00, 0x0e }, "MacOffice 98",           5, TRUE },
 
91
        { { 0x62, 0x00, 0x00, 0x0e }, "MacOffice 2001",         5, TRUE },
 
92
        { { 0x63, 0x00, 0x00, 0x0e }, "MacOffice X",            6, TRUE },
 
93
        { { 0x64, 0x00, 0x00, 0x0e }, "MacOffice 2004",         6, TRUE },
 
94
};
 
95
 
 
96
#define VBA56_DIRENT_RECORD_COUNT (2 + /* magic */              \
 
97
                                   4 + /* version */            \
 
98
                                   2 + /* 0x00 0xff */          \
 
99
                                  22)  /* unknown */
 
100
#define VBA56_DIRENT_HEADER_SIZE (VBA56_DIRENT_RECORD_COUNT +   \
 
101
                                  2 +  /* type1 record count */ \
 
102
                                  2)   /* unknown */
 
103
 
 
104
static char *get_unicode_name(char *name, int size, int is_mac)
99
105
{
100
 
        int i, increment;
101
 
        char *newname, *ret;
102
 
 
103
 
        if((name == NULL) || (*name == '\0') || (size <= 0))
104
 
                return NULL;
105
 
 
106
 
        newname = (char *)cli_malloc(size * 7 + 1);
107
 
        if(newname == NULL)
108
 
                return NULL;
109
 
 
110
 
        if((!big_endian) && (size & 0x1)) {
111
 
                cli_dbgmsg("get_unicode_name: odd number of bytes %d\n", size);
112
 
                --size;
113
 
        }
114
 
 
115
 
        increment = (big_endian) ? 1 : 2;
116
 
        ret = newname;
117
 
 
118
 
        for(i = 0; i < size; i += increment) {
119
 
                if((!(name[i]&0x80)) && isprint(name[i])) {
120
 
                        *ret++ = tolower(name[i]);
121
 
                } else {
122
 
                        if((name[i] < 10) && (name[i] >= 0)) {
123
 
                                *ret++ = '_';
124
 
                                *ret++ = (char)(name[i] + '0');
125
 
                        } else {
126
 
                                const uint16_t x = (uint16_t)((name[i] << 8) | name[i + 1]);
127
 
 
128
 
                                *ret++ = '_';
129
 
                                *ret++ = (char)('a'+((x&0xF)));
130
 
                                *ret++ = (char)('a'+((x>>4)&0xF));
131
 
                                *ret++ = (char)('a'+((x>>8)&0xF));
132
 
                                *ret++ = 'a';
133
 
                                *ret++ = 'a';
 
106
        int i, j;
 
107
        char *newname;
 
108
 
 
109
        if (!name || *name == 0 || size <= 0) {
 
110
                return NULL;
 
111
        }
 
112
 
 
113
        newname = (char *) cli_malloc(size*7);
 
114
        if (!newname) {
 
115
                return NULL;
 
116
        }
 
117
        j=0;
 
118
        for (i=0 ; i < size; i += (is_mac ? 1 : 2) ) {
 
119
                if (isprint(name[i])) {
 
120
                        newname[j++] = name[i];
 
121
                } else {
 
122
                        if (name[i] < 10 && name[i] >= 0) {
 
123
                                newname[j++] = '_';
 
124
                                newname[j++] = name[i] + '0';
 
125
                        }
 
126
                        else {
 
127
                                const uint16_t x = (((uint16_t)name[i]) << 8) | name[i+1];
 
128
                                newname[j++] = '_';
 
129
                                newname[j++] = 'a'+((x&0xF));
 
130
                                newname[j++] = 'a'+((x>>4)&0xF);
 
131
                                newname[j++] = 'a'+((x>>8)&0xF);
 
132
                                newname[j++] = 'a'+((x>>16)&0xF);
 
133
                                newname[j++] = 'a'+((x>>24)&0xF);
134
134
                        }
135
 
                        *ret++ = '_';
136
 
                }
137
 
        }
138
 
 
139
 
        *ret = '\0';
140
 
 
141
 
        /* Saves a lot of memory */
142
 
        ret = cli_realloc(newname, (ret - newname) + 1);
143
 
        return ret ? ret : newname;
 
135
                        newname[j++] = '_';
 
136
                }
 
137
        }
 
138
        newname[j] = '\0';
 
139
        return newname;
144
140
}
145
141
 
146
 
 
147
142
static void vba56_test_middle(int fd)
148
143
{
149
 
        char test_middle[MIDDLE_SIZE];
 
144
        char test_middle[20];
150
145
 
151
146
        /* MacOffice middle */
152
 
        static const uint8_t middle1_str[MIDDLE_SIZE] = {
 
147
        static const uint8_t middle1_str[20] = {
153
148
                0x00, 0x01, 0x0d, 0x45, 0x2e, 0xe1, 0xe0, 0x8f, 0x10, 0x1a,
154
149
                0x85, 0x2e, 0x02, 0x60, 0x8c, 0x4d, 0x0b, 0xb4, 0x00, 0x00
155
150
        };
156
151
        /* MS Office middle */
157
 
        static const uint8_t middle2_str[MIDDLE_SIZE] = {
158
 
                0x00, 0x00, 0xe1, 0x2e, 0x45, 0x0d, 0x8f, 0xe0, 0x1a, 0x10,
 
152
        static const uint8_t middle2_str[20] = {
 
153
                0x00, 0x00, 0xe1, 0x2e, 0x45, 0x0d, 0x8f, 0xe0, 0x1a, 0x10, 
159
154
                0x85, 0x2e, 0x02, 0x60, 0x8c, 0x4d, 0x0b, 0xb4, 0x00, 0x00
160
155
        };
161
156
 
162
 
        if(cli_readn(fd, &test_middle, MIDDLE_SIZE) != MIDDLE_SIZE)
163
 
                return;
 
157
        if (cli_readn(fd, &test_middle, 20) != 20) {
 
158
                return;
 
159
        }
164
160
 
165
 
        if((memcmp(test_middle, middle1_str, MIDDLE_SIZE) != 0) &&
166
 
           (memcmp(test_middle, middle2_str, MIDDLE_SIZE) != 0)) {
 
161
        if ((memcmp(test_middle, middle1_str, 20) != 0) &&
 
162
                (memcmp(test_middle, middle2_str, 20) != 0)) {
167
163
                cli_dbgmsg("middle not found\n");
168
 
                lseek(fd, -MIDDLE_SIZE, SEEK_CUR);
169
 
        } else
 
164
                lseek(fd, -20, SEEK_CUR);
 
165
        } else {
170
166
                cli_dbgmsg("middle found\n");
 
167
        }
 
168
        return;
171
169
}
172
170
 
173
 
static int
174
 
vba_read_project_strings(int fd, int big_endian)
 
171
static int vba_read_project_strings(int fd, int is_mac)
175
172
{
176
 
        unsigned char *buf = NULL;
177
 
        uint16_t buflen = 0;
178
 
        int ret = 0;
179
 
 
180
 
        for(;;) {
181
 
                off_t offset;
182
 
                uint16_t length;
183
 
                char *name;
184
 
 
185
 
                if(!read_uint16(fd, &length, big_endian))
186
 
                        break;
187
 
 
 
173
        uint16_t length;
 
174
        unsigned char *buff, *name;
 
175
        uint32_t offset;
 
176
 
 
177
        for (;;) {
 
178
                if (cli_readn(fd, &length, 2) != 2) {
 
179
                        return FALSE;
 
180
                }
 
181
                length = vba_endian_convert_16(length, is_mac);
188
182
                if (length < 6) {
189
183
                        lseek(fd, -2, SEEK_CUR);
190
184
                        break;
191
185
                }
192
 
                if(length > buflen) {
193
 
                        unsigned char *newbuf = (unsigned char *)cli_realloc(buf, length);
194
 
                        if(newbuf == NULL) {
195
 
                                if(buf)
196
 
                                        free(buf);
197
 
                                return 0;
198
 
                        }
199
 
                        buflen = length;
200
 
                        buf = newbuf;
 
186
                cli_dbgmsg ("length: %d, ", length);
 
187
                buff = (unsigned char *) cli_malloc(length);
 
188
                if (!buff) {
 
189
                        cli_errmsg("cli_malloc failed\n");
 
190
                        return FALSE;
201
191
                }
202
 
 
203
192
                offset = lseek(fd, 0, SEEK_CUR);
204
 
 
205
 
                if(cli_readn(fd, buf, length) != (int)length) {
 
193
                if (cli_readn(fd, buff, length) != length) {
206
194
                        cli_dbgmsg("read name failed - rewinding\n");
207
195
                        lseek(fd, offset, SEEK_SET);
 
196
                        free(buff);
208
197
                        break;
209
198
                }
210
 
                name = get_unicode_name((const char *)buf, length, big_endian);
211
 
                cli_dbgmsg("length: %d, name: %s\n", length, (name) ? name : "[null]");
 
199
                name = get_unicode_name(buff, length, is_mac);
 
200
                if (name) {
 
201
                        cli_dbgmsg("name: %s\n", name);
 
202
                } else {
 
203
                        cli_dbgmsg("name: [null]\n");
 
204
                }
 
205
                free(buff);
212
206
 
213
 
                if((name == NULL) || (memcmp("*\\", name, 2) != 0) ||
214
 
                   (strchr("ghcd", name[2]) == NULL)) {
215
 
                        /* Not a string */
 
207
                /* Ignore twelve bytes from entries of type 'G'.
 
208
                   Type 'C' entries come in pairs, the second also
 
209
                   having a 12 byte trailer */
 
210
                /* TODO: Need to check if types H(same as G) and D(same as C) exist */
 
211
                if (name && (!strncmp ("*\\G", name, 3) || !strncmp ("*\\H", name, 3)
 
212
                                || !strncmp("*\\C", name, 3) || !strncmp("*\\D", name, 3))) {
 
213
                        if (cli_readn(fd, &length, 2) != 2) {
 
214
                                return FALSE;
 
215
                        }
 
216
                        length = vba_endian_convert_16(length, is_mac);
 
217
                        if ((length != 0) && (length != 65535)) {
 
218
                                lseek(fd, -2, SEEK_CUR);
 
219
                                free(name);
 
220
                                continue;
 
221
                        }
 
222
                        buff = (unsigned char *) cli_malloc(10);
 
223
                        if (!buff) {
 
224
                                free(name);
 
225
                                close(fd);
 
226
                                return FALSE;
 
227
                        }
 
228
                        if (cli_readn(fd, buff, 10) != 10) {
 
229
                                cli_errmsg("failed to read blob\n");
 
230
                                free(buff);
 
231
                                free(name);
 
232
                                close(fd);
 
233
                                return FALSE;
 
234
                        }
 
235
                        free(buff);
 
236
                } else {
 
237
                        /* Unknown type - probably ran out of strings - rewind */
216
238
                        lseek(fd, -(length+2), SEEK_CUR);
217
 
                        if(name)
 
239
                        if (name) {
218
240
                                free(name);
 
241
                        }
219
242
                        break;
220
243
                }
221
244
                free(name);
222
 
 
223
 
                if(!read_uint16(fd, &length, big_endian)) {
224
 
                        if(buf) {
225
 
                                free(buf);
226
 
                                buf = NULL;
227
 
                        }
228
 
                        break;
229
 
                }
230
 
 
231
 
                ret++;
232
 
 
233
 
                if ((length != 0) && (length != 65535)) {
234
 
                        lseek(fd, -2, SEEK_CUR);
235
 
                        continue;
236
 
                }
237
 
                offset = lseek(fd, 10, SEEK_CUR);
238
 
                cli_dbgmsg("offset: %lu\n", (unsigned long)offset);
 
245
                offset = lseek(fd, 0, SEEK_CUR);
 
246
                cli_dbgmsg("offset: %u\n", offset);
239
247
                vba56_test_middle(fd);
240
248
        }
241
 
        if(buf)
242
 
                free(buf);
243
 
        return ret;
 
249
        return TRUE;
244
250
}
245
251
 
246
 
vba_project_t *
247
 
cli_vba_readdir(const char *dir, struct uniq *U, uint32_t which)
 
252
vba_project_t *vba56_dir_read(const char *dir)
248
253
{
249
 
        unsigned char *buf;
250
 
        const unsigned char vba56_signature[] = { 0xcc, 0x61 };
251
 
        uint16_t record_count, buflen, ffff, byte_count;
 
254
        unsigned char magic[2];
 
255
        unsigned char version[4];
 
256
        unsigned char *buff;
 
257
        unsigned char vba56_signature[] = { 0xcc, 0x61 };
 
258
        uint16_t record_count, length;
 
259
        uint16_t ooff;
 
260
        uint16_t byte_count;
252
261
        uint32_t offset;
253
 
        int i, j, fd, big_endian = FALSE;
 
262
        uint32_t LidA;  /* Language identifiers */
 
263
        uint32_t LidB;
 
264
        uint16_t CharSet;
 
265
        uint16_t LenA;
 
266
        uint32_t UnknownB;
 
267
        uint32_t UnknownC;
 
268
        uint16_t LenB;
 
269
        uint16_t LenC;
 
270
        uint16_t LenD;
 
271
        int i, j, fd, is_mac;
254
272
        vba_project_t *vba_project;
255
 
        struct vba56_header v56h;
256
 
        off_t seekback;
257
 
        char fullname[1024], *hash;
258
 
 
259
 
        cli_dbgmsg("in cli_vba_readdir()\n");
260
 
 
261
 
        if(dir == NULL)
262
 
                return NULL;
263
 
 
264
 
        /*
265
 
         * _VBA_PROJECT files are embedded within office documents (OLE2)
266
 
         */
 
273
        char *fullname;
 
274
 
 
275
        cli_dbgmsg("in vba56_dir_read()\n");
 
276
 
 
277
        fullname = (char *) cli_malloc(strlen(dir) + 14);
 
278
        if (!fullname) {
 
279
                return NULL;
 
280
        }
 
281
        sprintf(fullname, "%s/_VBA_PROJECT", dir);
 
282
        fd = open(fullname, O_RDONLY|O_BINARY);
 
283
 
 
284
        if (fd == -1) {
 
285
                cli_dbgmsg("Can't open %s\n", fullname);
 
286
                free(fullname);
 
287
                /* vba56_old_dir_read(dir); */
 
288
                return NULL;
 
289
        }
 
290
        free(fullname);
 
291
 
 
292
        if (cli_readn(fd, &magic, 2) != 2) {
 
293
                close(fd);
 
294
                return NULL;
 
295
        }
 
296
        if (memcmp(magic, vba56_signature, 2) != 0) {
 
297
                close(fd);
 
298
                return NULL;
 
299
        }
 
300
 
 
301
        if (cli_readn(fd, &version, 4) != 4) {
 
302
                close(fd);
 
303
                return NULL;
 
304
        }
 
305
        for (i=0 ; i < NUM_VBA_VERSIONS ; i++) {
 
306
                if (memcmp(version, vba_version[i].signature, 4) == 0) {
 
307
                        break;
 
308
                }
 
309
        }
 
310
 
 
311
        if (i == NUM_VBA_VERSIONS) {
 
312
                cli_warnmsg("Unknown VBA version signature %x %x %x %x\n",
 
313
                        version[0], version[1], version[2], version[3]);
 
314
                if (version[3] == 0x01) {
 
315
                        cli_warnmsg("Guessing little-endian\n");
 
316
                        is_mac = FALSE;
 
317
                } else if (version[3] == 0x0e) {
 
318
                        cli_warnmsg("Guessing big-endian\n");
 
319
                        is_mac = TRUE;
 
320
                } else {
 
321
                        cli_warnmsg("Unable to guess VBA type\n");
 
322
                        close(fd);
 
323
                        return NULL;
 
324
                }       
 
325
        } else {
 
326
                cli_dbgmsg("VBA Project: %s, VBA Version=%d\n", vba_version[i].name,
 
327
                                vba_version[i].vba_version);
 
328
                is_mac = vba_version[i].is_mac;
 
329
        }
 
330
 
 
331
        /*****************************************/
 
332
 
 
333
        /* two bytes, should be equal to 0x00ff */
 
334
        if (cli_readn(fd, &ooff, 2) != 2) {
 
335
                close(fd);
 
336
                return NULL;
 
337
        }
 
338
 
 
339
        if (cli_readn(fd, &LidA, 4) != 4) {
 
340
                close(fd);
 
341
                return NULL;
 
342
        }
 
343
 
 
344
        if (cli_readn(fd, &LidB, 4) != 4) {
 
345
                close(fd);
 
346
                return NULL;
 
347
        }
 
348
 
 
349
        if (cli_readn(fd, &CharSet, 2) != 2) {
 
350
                close(fd);
 
351
                return NULL;
 
352
        }
 
353
        if (cli_readn(fd, &LenA, 2) != 2) {
 
354
                close(fd);
 
355
                return NULL;
 
356
        }
 
357
 
 
358
        if (cli_readn(fd, &UnknownB, 4) != 4) {
 
359
                close(fd);
 
360
                return NULL;
 
361
        }
 
362
        if (cli_readn(fd, &UnknownC, 4) != 4) {
 
363
                close(fd);
 
364
                return NULL;
 
365
        }
 
366
 
 
367
        if (cli_readn(fd, &LenB, 2) != 2) {
 
368
                close(fd);
 
369
                return NULL;
 
370
        }
 
371
        if (cli_readn(fd, &LenC, 2) != 2) {
 
372
                close(fd);
 
373
                return NULL;
 
374
        }
 
375
        if (cli_readn(fd, &LenD, 2) != 2) {
 
376
                close(fd);
 
377
                return NULL;
 
378
        }
 
379
 
 
380
        LidA = vba_endian_convert_32(LidA, is_mac);
 
381
        LidB = vba_endian_convert_32(LidB, is_mac);
 
382
        CharSet = vba_endian_convert_16(CharSet, is_mac);
 
383
        LenA = vba_endian_convert_16(LenA, is_mac);
 
384
        LenB = vba_endian_convert_16(LenB, is_mac);
 
385
        LenC = vba_endian_convert_16(LenC, is_mac);
 
386
        LenD = vba_endian_convert_16(LenD, is_mac);
 
387
 
 
388
        cli_dbgmsg(" LidA: %d\n LidB: %d\n CharSet: %d\n", LidA, LidB, CharSet);
 
389
        cli_dbgmsg(" LenA: %d\n UnknownB: %d\n UnknownC: %d\n", LenA, UnknownB, UnknownC);
 
390
        cli_dbgmsg(" LenB: %d\n LenC: %d\n LenD: %d\n", LenB, LenC, LenD);
 
391
 
 
392
        record_count = LenC;
 
393
 
 
394
        if (!vba_read_project_strings(fd, is_mac)) {
 
395
                close(fd);
 
396
                return NULL;
 
397
        }
267
398
        
268
 
        if (!uniq_get(U, "_vba_project", 12, &hash))
269
 
                return NULL;
270
 
        snprintf(fullname, sizeof(fullname), "%s"PATHSEP"%s_%u", dir, hash, which);
271
 
        fullname[sizeof(fullname)-1] = '\0';
272
 
        fd = open(fullname, O_RDONLY|O_BINARY);
273
 
 
274
 
        if(fd == -1)
275
 
                return NULL;
276
 
 
277
 
        if(cli_readn(fd, &v56h, sizeof(struct vba56_header)) != sizeof(struct vba56_header)) {
278
 
                close(fd);
279
 
                return NULL;
280
 
        }
281
 
        if (memcmp(v56h.magic, vba56_signature, sizeof(v56h.magic)) != 0) {
282
 
                close(fd);
283
 
                return NULL;
284
 
        }
285
 
 
286
 
        i = vba_read_project_strings(fd, TRUE);
287
 
        seekback = lseek(fd, 0, SEEK_CUR);
288
 
        if (lseek(fd, sizeof(struct vba56_header), SEEK_SET) == -1) {
289
 
                close(fd);
290
 
                return NULL;
291
 
        }
292
 
        j = vba_read_project_strings(fd, FALSE);
293
 
        if(!i && !j) {
294
 
                close(fd);
295
 
                cli_dbgmsg("vba_readdir: Unable to guess VBA type\n");
296
 
                return NULL;
297
 
        }
298
 
        if (i > j) {
299
 
                big_endian = TRUE;
300
 
                lseek(fd, seekback, SEEK_SET);
301
 
                cli_dbgmsg("vba_readdir: Guessing big-endian\n");
302
 
        } else {
303
 
                cli_dbgmsg("vba_readdir: Guessing little-endian\n");
304
 
        }
305
 
 
306
399
        /* junk some more stuff */
307
 
        do
308
 
                if (cli_readn(fd, &ffff, 2) != 2) {
 
400
        do {
 
401
                if (cli_readn(fd, &ooff, 2) != 2) {
309
402
                        close(fd);
310
403
                        return NULL;
311
404
                }
312
 
        while(ffff != 0xFFFF);
 
405
        } while(ooff != 0xFFFF);
313
406
 
314
407
        /* check for alignment error */
315
 
        if(!seekandread(fd, -3, SEEK_CUR, &ffff, sizeof(uint16_t))) {
316
 
                close(fd);
 
408
        lseek(fd, -3, SEEK_CUR);
 
409
        if (cli_readn(fd, &ooff, 2) != 2) {
 
410
                close(fd);
317
411
                return NULL;
318
412
        }
319
 
        if (ffff != 0xFFFF)
 
413
        if (ooff != 0xFFFF) {
320
414
                lseek(fd, 1, SEEK_CUR);
321
 
 
322
 
        if(!read_uint16(fd, &ffff, big_endian)) {
323
 
                close(fd);
324
 
                return NULL;
325
 
        }
326
 
 
327
 
        if(ffff != 0xFFFF)
328
 
                lseek(fd, ffff, SEEK_CUR);
329
 
 
330
 
        if(!read_uint16(fd, &ffff, big_endian)) {
331
 
                close(fd);
332
 
                return NULL;
333
 
        }
334
 
 
335
 
        if(ffff == 0xFFFF)
336
 
                ffff = 0;
337
 
 
338
 
        lseek(fd, ffff + 100, SEEK_CUR);
339
 
 
340
 
        if(!read_uint16(fd, &record_count, big_endian)) {
341
 
                close(fd);
342
 
                return NULL;
343
 
        }
344
 
        cli_dbgmsg("vba_readdir: VBA Record count %d\n", record_count);
 
415
        }
 
416
        
 
417
        if (cli_readn(fd, &ooff, 2) != 2) {
 
418
                close(fd);
 
419
                return NULL;
 
420
        }
 
421
 
 
422
        /* no idea what this stuff is */
 
423
        if (ooff != 0xFFFF) {
 
424
                ooff = vba_endian_convert_16(ooff, is_mac);
 
425
                lseek(fd, ooff, SEEK_CUR);
 
426
        }
 
427
        if (cli_readn(fd, &ooff, 2) != 2) {
 
428
                close(fd);
 
429
                return NULL;
 
430
        }
 
431
        if (ooff != 0xFFFF) {
 
432
                ooff = vba_endian_convert_16(ooff, is_mac);
 
433
                lseek(fd, ooff, SEEK_CUR);
 
434
        }
 
435
        lseek(fd, 100, SEEK_CUR);
 
436
 
 
437
        if (cli_readn(fd, &record_count, 2) != 2) {
 
438
                close(fd);
 
439
                return NULL;
 
440
        }
 
441
        record_count = vba_endian_convert_16(record_count, is_mac);
 
442
        cli_dbgmsg("\nVBA Record count: %d\n", record_count);
345
443
        if (record_count == 0) {
346
 
                /* No macros, assume clean */
347
444
                close(fd);
348
 
                return NULL;
349
 
        }
350
 
        if (record_count > MAX_VBA_COUNT) {
 
445
                return NULL;
 
446
        }
 
447
        if (record_count > 1000) {
351
448
                /* Almost certainly an error */
352
 
                cli_dbgmsg("vba_readdir: VBA Record count too big\n");
353
 
                close(fd);
354
 
                return NULL;
355
 
        }
356
 
 
357
 
        vba_project = create_vba_project(record_count, dir, U);
358
 
        if(vba_project == NULL) {
359
 
                close(fd);
360
 
                return NULL;
361
 
        }
362
 
        buf = NULL;
363
 
        buflen = 0;
364
 
        for(i = 0; i < record_count; i++) {
365
 
                uint16_t length;
366
 
                char *ptr;
367
 
 
368
 
                vba_project->colls[i] = 0;
369
 
                if(!read_uint16(fd, &length, big_endian))
370
 
                        break;
371
 
 
 
449
                cli_dbgmsg("\nVBA Record count too big");
 
450
                close(fd);
 
451
                return NULL;
 
452
        }
 
453
        
 
454
        vba_project = (vba_project_t *) cli_malloc(sizeof(struct vba_project_tag));
 
455
        if (!vba_project) {
 
456
                close(fd);
 
457
                return NULL;
 
458
        }
 
459
        vba_project->name = (char **) cli_malloc(sizeof(char *) * record_count);
 
460
        if (!vba_project->name) {
 
461
                free(vba_project);
 
462
                close(fd);
 
463
                return NULL;
 
464
        }
 
465
        vba_project->dir = cli_strdup(dir);
 
466
        vba_project->offset = (uint32_t *) cli_malloc (sizeof(uint32_t) *
 
467
                                        record_count);
 
468
        if (!vba_project->offset) {
 
469
                free(vba_project->dir);
 
470
                free(vba_project->name);
 
471
                free(vba_project);
 
472
                close(fd);
 
473
                return NULL;
 
474
        }
 
475
        vba_project->count = record_count;
 
476
        for (i=0 ; i < record_count ; i++) {
 
477
                if (cli_readn(fd, &length, 2) != 2) {
 
478
                        goto out_error;
 
479
                }
 
480
                length = vba_endian_convert_16(length, is_mac);
372
481
                if (length == 0) {
373
 
                        cli_dbgmsg("vba_readdir: zero name length\n");
374
 
                        break;
375
 
                }
376
 
                if(length > buflen) {
377
 
                        unsigned char *newbuf = (unsigned char *)cli_realloc(buf, length);
378
 
                        if(newbuf == NULL)
379
 
                                break;
380
 
                        buflen = length;
381
 
                        buf = newbuf;
382
 
                }
383
 
                if (cli_readn(fd, buf, length) != length) {
384
 
                        cli_dbgmsg("vba_readdir: read name failed\n");
385
 
                        break;
386
 
                }
387
 
                ptr = get_unicode_name((const char *)buf, length, big_endian);
388
 
                if(ptr == NULL) break;
389
 
                if (!(vba_project->colls[i]=uniq_get(U, ptr, strlen(ptr), &hash))) {
390
 
                        cli_dbgmsg("vba_readdir: cannot find project %s (%s)\n", ptr, hash);
391
 
                        break;
392
 
                }
393
 
                cli_dbgmsg("vba_readdir: project name: %s (%s)\n", ptr, hash);
394
 
                free(ptr);
395
 
                vba_project->name[i] = hash;
396
 
                if(!read_uint16(fd, &length, big_endian))
397
 
                        break;
 
482
                        cli_dbgmsg("zero name length\n");
 
483
                        goto out_error;
 
484
                }
 
485
                buff = (unsigned char *) cli_malloc(length);
 
486
                if (!buff) {
 
487
                        cli_dbgmsg("cli_malloc failed\n");
 
488
                        goto out_error;
 
489
                }
 
490
                if (cli_readn(fd, buff, length) != length) {
 
491
                        cli_dbgmsg("read name failed\n");
 
492
                        free(buff);
 
493
                        goto out_error;
 
494
                }
 
495
                vba_project->name[i] = get_unicode_name(buff, length, is_mac);
 
496
                if (!vba_project->name[i]) {
 
497
                        offset = lseek(fd, 0, SEEK_CUR);
 
498
                        vba_project->name[i] = (char *) cli_malloc(18);
 
499
                        snprintf(vba_project->name[i], 18, "clamav-%.10d", offset);
 
500
                }
 
501
                cli_dbgmsg("project name: %s, ", vba_project->name[i]);
 
502
                free(buff);
 
503
 
 
504
                /* some kind of string identifier ?? */
 
505
                if (cli_readn(fd, &length, 2) != 2) {
 
506
                        free(vba_project->name[i]);
 
507
                        goto out_error;
 
508
                }
 
509
                length = vba_endian_convert_16(length, is_mac);
398
510
                lseek(fd, length, SEEK_CUR);
399
511
 
400
 
                if(!read_uint16(fd, &ffff, big_endian))
401
 
                        break;
402
 
                if (ffff == 0xFFFF) {
 
512
                /* unknown stuff */
 
513
                if (cli_readn(fd, &ooff, 2) != 2) {
 
514
                        free(vba_project->name[i]);
 
515
                        goto out_error;
 
516
                }
 
517
                ooff = vba_endian_convert_16(ooff, is_mac);
 
518
                if (ooff == 0xFFFF) {
403
519
                        lseek(fd, 2, SEEK_CUR);
404
 
                        if(!read_uint16(fd, &ffff, big_endian))
405
 
                                break;
406
 
                        lseek(fd, ffff + 8, SEEK_CUR);
407
 
                } else
408
 
                        lseek(fd, ffff + 10, SEEK_CUR);
 
520
                        if (cli_readn(fd, &ooff, 2) != 2) {
 
521
                                free(vba_project->name[i]);
 
522
                                goto out_error;
 
523
                        }
 
524
                        ooff = vba_endian_convert_16(ooff, is_mac);
 
525
                        lseek(fd, ooff, SEEK_CUR);
 
526
                } else {
 
527
                        lseek(fd, 2 + ooff, SEEK_CUR);
 
528
                }
409
529
 
410
 
                if(!read_uint16(fd, &byte_count, big_endian))
411
 
                        break;
412
 
                lseek(fd, (8 * byte_count) + 5, SEEK_CUR);
413
 
                if(!read_uint32(fd, &offset, big_endian))
414
 
                        break;
415
 
                cli_dbgmsg("vba_readdir: offset: %u\n", (unsigned int)offset);
 
530
                lseek(fd, 8, SEEK_CUR);
 
531
                if (cli_readn(fd, &byte_count, 2) != 2) {
 
532
                        free(vba_project->name[i]);
 
533
                        goto out_error;
 
534
                }
 
535
                byte_count = vba_endian_convert_16(byte_count, is_mac);
 
536
                for (j=0 ; j<byte_count; j++) {
 
537
                        lseek(fd, 8, SEEK_CUR);
 
538
                }
 
539
                lseek(fd, 5, SEEK_CUR);
 
540
                if (cli_readn(fd, &offset, 4) != 4) {
 
541
                        free(vba_project->name[i]);
 
542
                        goto out_error;
 
543
                }
 
544
                offset = vba_endian_convert_32(offset, is_mac);
416
545
                vba_project->offset[i] = offset;
 
546
                cli_dbgmsg("offset:%u\n", offset);
417
547
                lseek(fd, 2, SEEK_CUR);
418
548
        }
419
 
 
420
 
        if(buf)
421
 
                free(buf);
422
 
 
 
549
        
 
550
        
 
551
        { /* There appears to be some code in here */
 
552
        
 
553
        off_t foffset;
 
554
 
 
555
                foffset = lseek(fd, 0, SEEK_CUR);
 
556
                cli_dbgmsg("\nOffset: 0x%x\n", (unsigned int)foffset);
 
557
        }
423
558
        close(fd);
424
 
 
425
 
        if(i < record_count) {
426
 
                free(vba_project->name);
427
 
                free(vba_project->colls);
428
 
                free(vba_project->dir);
429
 
                free(vba_project->offset);
430
 
                free(vba_project);
431
 
                return NULL;
432
 
        }
433
 
 
434
559
        return vba_project;
435
 
}
436
 
 
437
 
unsigned char *
438
 
cli_vba_inflate(int fd, off_t offset, int *size)
439
 
{
440
 
        unsigned int pos, shift, mask, distance, clean;
 
560
 
 
561
out_error:
 
562
        /* Note: only to be called from the above loop
 
563
           when i == number of allocated stings */
 
564
        for (j=0 ; j<i ; j++) {
 
565
                free(vba_project->name[j]);
 
566
        }
 
567
        free(vba_project->name);
 
568
        free(vba_project->dir);
 
569
        free(vba_project->offset);
 
570
        free(vba_project);
 
571
        close(fd);
 
572
        return NULL;
 
573
}
 
574
 
 
575
#define VBA_COMPRESSION_WINDOW 4096
 
576
 
 
577
static void byte_array_append(byte_array_t *array, unsigned char *src, unsigned int len)
 
578
{
 
579
        if (array->length == 0) {
 
580
                array->data = (unsigned char *) cli_malloc(len);
 
581
                if (!array->data) {
 
582
                        return;
 
583
                }
 
584
                array->length = len;
 
585
                memcpy(array->data, src, len);
 
586
        } else {
 
587
                array->data = realloc(array->data, array->length+len);
 
588
                if (!array->data) {
 
589
                        return;
 
590
                }       
 
591
                memcpy(array->data+array->length, src, len);
 
592
                array->length += len;
 
593
        }
 
594
}
 
595
 
 
596
unsigned char *vba_decompress(int fd, uint32_t offset, int *size)
 
597
{
 
598
        unsigned int i, pos=0, shift, win_pos, clean=TRUE, mask, distance;
441
599
        uint8_t flag;
442
 
        uint16_t token;
443
 
        blob *b;
 
600
        uint16_t token, len;
444
601
        unsigned char buffer[VBA_COMPRESSION_WINDOW];
445
 
 
446
 
        if(fd < 0)
447
 
                return NULL;
448
 
 
449
 
        b = blobCreate();
450
 
 
451
 
        if(b == NULL)
452
 
                return NULL;
453
 
 
454
 
        lseek(fd, offset+3, SEEK_SET); /* 1byte ?? , 2byte length ?? */
455
 
        clean = TRUE;
456
 
        pos = 0;
457
 
 
 
602
        byte_array_t result;
 
603
        
 
604
        result.length=0;
 
605
        result.data=NULL;
 
606
        
 
607
        lseek(fd, offset+3, SEEK_SET); /* 1byte ?? , 2byte length ?? */ 
 
608
        
458
609
        while (cli_readn(fd, &flag, 1) == 1) {
459
 
                for(mask = 1; mask < 0x100; mask<<=1) {
460
 
                        unsigned int winpos = pos % VBA_COMPRESSION_WINDOW;
 
610
                for (mask = 1; mask < 0x100; mask<<=1) {
461
611
                        if (flag & mask) {
462
 
                                uint16_t len;
463
 
                                unsigned int srcpos;
464
 
 
465
 
                                if(!read_uint16(fd, &token, FALSE)) {
466
 
                                        blobDestroy(b);
467
 
                                        if(size)
 
612
                                if (cli_readn(fd, &token, 2) != 2) {
 
613
                                        if (result.data) {
 
614
                                                free(result.data);
 
615
                                        }
 
616
                                        if (size) {
468
617
                                                *size = 0;
 
618
                                        }
469
619
                                        return NULL;
470
620
                                }
471
 
                                shift = 12 - (winpos > 0x10)
472
 
                                                - (winpos > 0x20)
473
 
                                                - (winpos > 0x40)
474
 
                                                - (winpos > 0x80)
475
 
                                                - (winpos > 0x100)
476
 
                                                - (winpos > 0x200)
477
 
                                                - (winpos > 0x400)
478
 
                                                - (winpos > 0x800);
479
 
                                len = (uint16_t)((token & ((1 << shift) - 1)) + 3);
 
621
                                token = vba_endian_convert_16(token, FALSE);
 
622
                                win_pos = pos % VBA_COMPRESSION_WINDOW;
 
623
                                if (win_pos <= 0x80) {
 
624
                                        if (win_pos <= 0x20) {
 
625
                                                shift = (win_pos <= 0x10) ? 12:11;
 
626
                                        } else {
 
627
                                                shift = (win_pos <= 0x40) ? 10:9;
 
628
                                        }
 
629
                                } else {
 
630
                                        if (win_pos <= 0x200) {
 
631
                                                shift = (win_pos <= 0x100) ? 8:7;
 
632
                                        } else if (win_pos <= 0x800) {
 
633
                                                shift = (win_pos <= 0x400) ? 6:5;
 
634
                                        } else {
 
635
                                                shift = 4;
 
636
                                        }
 
637
                                }
 
638
                                len = (token & ((1 << shift) -1)) + 3;
480
639
                                distance = token >> shift;
481
 
 
482
 
                                srcpos = pos - distance - 1;
483
 
                                if((((srcpos + len) % VBA_COMPRESSION_WINDOW) < winpos) &&
484
 
                                   ((winpos + len) < VBA_COMPRESSION_WINDOW) &&
485
 
                                   (((srcpos % VBA_COMPRESSION_WINDOW) + len) < VBA_COMPRESSION_WINDOW) &&
486
 
                                   (len <= VBA_COMPRESSION_WINDOW)) {
487
 
                                        srcpos %= VBA_COMPRESSION_WINDOW;
488
 
                                        memcpy(&buffer[winpos], &buffer[srcpos],
489
 
                                                len);
490
 
                                        pos += len;
491
 
                                } else
492
 
                                        while(len-- > 0) {
493
 
                                                srcpos = (pos - distance - 1) % VBA_COMPRESSION_WINDOW;
494
 
                                                buffer[pos++ % VBA_COMPRESSION_WINDOW] = buffer[srcpos];
495
 
                                        }
 
640
                                clean = TRUE;
 
641
                                
 
642
                                for (i=0 ; i < len; i++) {
 
643
                                        unsigned int srcpos;
 
644
                                        unsigned char c;
 
645
                                        
 
646
                                        srcpos = (pos - distance - 1) % VBA_COMPRESSION_WINDOW;
 
647
                                        c = buffer[srcpos];
 
648
                                        buffer[pos++ % VBA_COMPRESSION_WINDOW]= c;
 
649
                                }
496
650
                        } else {
497
 
                                if((pos != 0) && (winpos == 0) && clean) {
 
651
                                if ((pos != 0) &&
 
652
                                        ((pos % VBA_COMPRESSION_WINDOW) == 0) && clean) {
 
653
                                        
498
654
                                        if (cli_readn(fd, &token, 2) != 2) {
499
 
                                                blobDestroy(b);
500
 
                                                if(size)
501
 
                                                        *size = 0;
 
655
                                                if (result.data) {
 
656
                                                        free(result.data);
 
657
                                                }
 
658
                                                if (size) {
 
659
                                                       *size = 0;
 
660
                                                }
502
661
                                                return NULL;
503
662
                                        }
504
 
                                        (void)blobAddData(b, buffer, VBA_COMPRESSION_WINDOW);
505
663
                                        clean = FALSE;
 
664
                                        byte_array_append(&result, buffer, VBA_COMPRESSION_WINDOW);
506
665
                                        break;
507
666
                                }
508
 
                                if(cli_readn(fd, &buffer[winpos], 1) == 1)
 
667
                                if (cli_readn(fd, buffer+(pos%VBA_COMPRESSION_WINDOW), 1) == 1){
509
668
                                        pos++;
 
669
                                }
 
670
                                clean = TRUE;
510
671
                        }
511
 
                        clean = TRUE;
512
672
                }
513
673
        }
514
 
 
515
 
        if(blobAddData(b, buffer, pos%VBA_COMPRESSION_WINDOW) < 0) {
516
 
                blobDestroy(b);
517
 
                if(size)
518
 
                        *size = 0;
519
 
                return NULL;
520
 
        }
521
 
 
522
 
        if(size)
523
 
                *size = (int)blobGetDataSize(b);
524
 
        return (unsigned char *)blobToMem(b);
525
 
}
526
 
 
527
 
/*
528
 
 * See also cli_filecopy()
529
 
 */
530
 
static void
531
 
ole_copy_file_data(int s, int d, uint32_t len)
532
 
{
533
 
        unsigned char data[FILEBUFF];
534
 
 
535
 
        while(len > 0) {
536
 
                int todo = MIN(sizeof(data), len);
537
 
 
538
 
                if(cli_readn(s, data, (unsigned int)todo) != todo)
539
 
                        break;
540
 
                if(cli_writen(d, data, (unsigned int)todo) != todo)
541
 
                        break;
542
 
                len -= todo;
543
 
        }
544
 
}
545
 
 
546
 
int
547
 
cli_scan_ole10(int fd, cli_ctx *ctx)
548
 
{
549
 
        int ofd, ret;
 
674
                        
 
675
        if (pos % VBA_COMPRESSION_WINDOW) {
 
676
                byte_array_append(&result, buffer, pos % VBA_COMPRESSION_WINDOW);
 
677
        }
 
678
        if (size) {
 
679
                *size = result.length;
 
680
        }
 
681
        return result.data;
 
682
 
 
683
}
 
684
 
 
685
static uint32_t ole_copy_file_data(int ifd, int ofd, uint32_t len)
 
686
{
 
687
        unsigned char data[8192];
 
688
        unsigned int count, rem;
 
689
        unsigned int todo;
 
690
 
 
691
        rem = len;
 
692
 
 
693
        while (rem > 0) {
 
694
                todo = MIN(8192, rem);
 
695
                count = cli_readn(ifd, data, todo);
 
696
                if (count != todo) {
 
697
                        return len-rem;
 
698
                }
 
699
                if (cli_writen(ofd, data, count) != count) {
 
700
                        return len-rem-count;
 
701
                }
 
702
                rem -= count;
 
703
        }
 
704
        return len;
 
705
}
 
706
 
 
707
int cli_decode_ole_object(int fd, const char *dir)
 
708
{
 
709
        int ofd;
 
710
        struct stat statbuf;
 
711
        char ch, *fullname;
550
712
        uint32_t object_size;
551
 
        struct stat statbuf;
552
 
        char *fullname;
553
 
 
554
 
        if(fd < 0)
555
 
                return CL_CLEAN;
556
 
 
557
 
        lseek(fd, 0, SEEK_SET);
558
 
        if(!read_uint32(fd, &object_size, FALSE))
559
 
                return CL_CLEAN;
560
 
 
561
 
        if(fstat(fd, &statbuf) == -1)
562
 
                return CL_ESTAT;
563
 
 
564
 
        if ((statbuf.st_size - object_size) >= 4) {
 
713
 
 
714
        if (fstat(fd, &statbuf) == -1) {
 
715
                return -1;
 
716
        }
 
717
        
 
718
        if (cli_readn(fd, &object_size, 4) != 4) {
 
719
                return -1;
 
720
        }
 
721
        object_size = vba_endian_convert_32(object_size, FALSE);
 
722
 
 
723
        if ((statbuf.st_size -  object_size) >= 4) {
565
724
                /* Probably the OLE type id */
566
725
                if (lseek(fd, 2, SEEK_CUR) == -1) {
567
 
                        return CL_CLEAN;
568
 
                }
569
 
 
570
 
                /* Attachment name */
571
 
                if(!skip_past_nul(fd))
572
 
                        return CL_CLEAN;
573
 
 
574
 
                /* Attachment full path */
575
 
                if(!skip_past_nul(fd))
576
 
                        return CL_CLEAN;
577
 
 
578
 
                /* ??? */
579
 
                if(lseek(fd, 8, SEEK_CUR) == -1)
580
 
                        return CL_CLEAN;
581
 
 
582
 
                /* Attachment full path */
583
 
                if(!skip_past_nul(fd))
584
 
                        return CL_CLEAN;
585
 
 
586
 
                if(!read_uint32(fd, &object_size, FALSE))
587
 
                        return CL_CLEAN;
588
 
        }
589
 
        if(!(fullname = cli_gentemp(ctx ? ctx->engine->tmpdir : NULL))) {
590
 
                return CL_EMEM;
591
 
        }
592
 
        ofd = open(fullname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY|O_EXCL,
593
 
                S_IWUSR|S_IRUSR);
594
 
        if (ofd < 0) {
595
 
                cli_warnmsg("cli_decode_ole_object: can't create %s\n", fullname);
596
 
                free(fullname);
597
 
                return CL_ECREAT;
598
 
        }
599
 
        cli_dbgmsg("cli_decode_ole_object: decoding to %s\n", fullname);
 
726
                        return -1;
 
727
                }
 
728
                
 
729
                /* Skip attachment name */
 
730
                do {
 
731
                        if (cli_readn(fd, &ch, 1) != 1) {
 
732
                                return -1;
 
733
                        }
 
734
                } while (ch);
 
735
                
 
736
                /* Skip attachment full path */
 
737
                do {
 
738
                        if (cli_readn(fd, &ch, 1) != 1) {
 
739
                                return -1;
 
740
                        }
 
741
                } while (ch);
 
742
                
 
743
                /* Skip unknown data */
 
744
                if (lseek(fd, 8, SEEK_CUR) == -1) {
 
745
                        return -1;
 
746
                }
 
747
                
 
748
                /* Skip attachment full path */
 
749
                do {
 
750
                        if (cli_readn(fd, &ch, 1) != 1) {
 
751
                                return -1;
 
752
                        }
 
753
                } while (ch);
 
754
                
 
755
                if (cli_readn(fd, &object_size, 4) != 4) {
 
756
                        return -1;
 
757
                }
 
758
                object_size = vba_endian_convert_32(object_size, FALSE);
 
759
        }
 
760
        fullname = cli_malloc(strlen(dir) + 18);
 
761
        sprintf(fullname, "%s/_clam_ole_object", dir);
 
762
        ofd = open(fullname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600);
 
763
        free(fullname);
 
764
        if (ofd < 0) {
 
765
                return -1;
 
766
        }
600
767
        ole_copy_file_data(fd, ofd, object_size);
601
768
        lseek(ofd, 0, SEEK_SET);
602
 
        ret = cli_magic_scandesc(ofd, ctx);
603
 
        close(ofd);
604
 
        if(ctx && !ctx->engine->keeptmp)
605
 
          if (cli_unlink(fullname))
606
 
            ret = CL_EUNLINK;
607
 
        free(fullname);
608
 
        return ret;
 
769
        return ofd;
609
770
}
610
771
 
611
 
/*
612
 
 * Powerpoint files
613
 
 */
614
 
typedef struct {
 
772
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 
773
/* Code to extract Power Point Embedded OLE2 Objects                 */
 
774
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 
775
 
 
776
typedef struct atom_header_tag {
 
777
        off_t foffset;
 
778
        uint16_t ver_inst;
 
779
        uint8_t version;
 
780
        uint16_t instance;
615
781
        uint16_t type;
616
782
        uint32_t length;
617
783
} atom_header_t;
618
784
 
619
 
static int
620
 
ppt_read_atom_header(int fd, atom_header_t *atom_header)
 
785
static int ppt_read_atom_header(int fd, atom_header_t *atom_header)
621
786
{
622
 
        uint16_t v;
623
 
        struct ppt_header {
624
 
                uint16_t ver;
625
 
                uint16_t type;
626
 
                uint32_t length;
627
 
        } h;
628
 
 
629
 
        cli_dbgmsg("in ppt_read_atom_header\n");
630
 
        if(cli_readn(fd, &h, sizeof(struct ppt_header)) != sizeof(struct ppt_header)) {
631
 
                cli_dbgmsg("read ppt_header failed\n");
632
 
                return FALSE;
633
 
        }
634
 
        v = vba_endian_convert_16(h.ver, FALSE);
635
 
        cli_dbgmsg("\tversion: 0x%.2x\n", v & 0xF);
636
 
        cli_dbgmsg("\tinstance: 0x%.2x\n", v >> 4);
637
 
 
638
 
        atom_header->type = vba_endian_convert_16(h.type, FALSE);
639
 
        cli_dbgmsg("\ttype: 0x%.4x\n", atom_header->type);
640
 
        atom_header->length = vba_endian_convert_32(h.length, FALSE);
641
 
        cli_dbgmsg("\tlength: 0x%.8x\n", (int)atom_header->length);
642
 
 
 
787
        atom_header->foffset = lseek(fd, 0, SEEK_CUR);
 
788
        if (cli_readn(fd, &atom_header->ver_inst, 2) != 2) {
 
789
                cli_dbgmsg("read ppt_current_user failed\n");
 
790
                return FALSE;
 
791
        }
 
792
        atom_header->ver_inst = vba_endian_convert_16(atom_header->ver_inst, FALSE);
 
793
        atom_header->version = atom_header->ver_inst & 0x000f;
 
794
        atom_header->instance = atom_header->ver_inst >> 4;
 
795
        if (cli_readn(fd, &atom_header->type, 2) != 2) {
 
796
                cli_dbgmsg("read ppt_current_user failed\n");
 
797
                return FALSE;
 
798
        }
 
799
        if (cli_readn(fd, &atom_header->length, 4) != 4) {
 
800
                cli_dbgmsg("read ppt_current_user failed\n");
 
801
                return FALSE;
 
802
        }
 
803
        atom_header->type = vba_endian_convert_16(atom_header->type, FALSE);
 
804
        atom_header->length = vba_endian_convert_32(atom_header->length, FALSE);
643
805
        return TRUE;
644
806
}
645
807
 
646
 
/*
647
 
 * TODO: combine shared code with flatedecode() or cli_unzip_single()
648
 
 *      Needs cli_unzip_single to have a "length" argument
649
 
 */
650
 
static int
651
 
ppt_unlzw(const char *dir, int fd, uint32_t length)
652
 
{
653
 
        int ofd;
 
808
static void ppt_print_atom_header(atom_header_t *atom_header)
 
809
{
 
810
        cli_dbgmsg("Atom Hdr:\n");
 
811
        cli_dbgmsg("  Version: 0x%.2x\n", atom_header->version);
 
812
        cli_dbgmsg("  Instance: 0x%.4x\n", atom_header->instance);
 
813
        cli_dbgmsg("  Type: 0x%.4x\n", atom_header->type);
 
814
        cli_dbgmsg("  Length: 0x%.8x\n", atom_header->length);
 
815
}
 
816
 
 
817
#define PPT_LZW_BUFFSIZE 8192
 
818
static int ppt_unlzw(const char *dir, int fd, uint32_t length)
 
819
{
 
820
        int ofd, retval;
 
821
        unsigned char inbuff[PPT_LZW_BUFFSIZE], outbuff[PPT_LZW_BUFFSIZE];
 
822
        char *fullname;
 
823
        uint32_t bufflen;
654
824
        z_stream stream;
655
 
        unsigned char inbuff[PPT_LZW_BUFFSIZE], outbuff[PPT_LZW_BUFFSIZE];
656
 
        char fullname[NAME_MAX + 1];
657
 
 
658
 
        snprintf(fullname, sizeof(fullname) - 1, "%s"PATHSEP"ppt%.8lx.doc",
659
 
                dir, (long)lseek(fd, 0L, SEEK_CUR));
660
 
 
661
 
        ofd = open(fullname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY|O_EXCL,
662
 
                S_IWUSR|S_IRUSR);
663
 
        if (ofd == -1) {
664
 
                cli_warnmsg("ppt_unlzw: can't create %s\n", fullname);
 
825
        
 
826
        fullname = cli_malloc(strlen(dir) + 17);
 
827
        if (!fullname) {
665
828
                return FALSE;
666
829
        }
667
 
 
 
830
        sprintf(fullname, "%s/ppt%.8lx.doc", dir, lseek(fd, 0, SEEK_CUR));
 
831
        
 
832
        ofd = open(fullname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600);
 
833
        free(fullname);
 
834
        if (ofd == -1) {
 
835
                cli_dbgmsg("ppt_unlzw Open outfile failed\n");
 
836
                return FALSE;
 
837
        }
 
838
        
668
839
        stream.zalloc = Z_NULL;
669
840
        stream.zfree = Z_NULL;
670
 
        stream.opaque = (void *)NULL;
671
 
        stream.next_in = (Bytef *)inbuff;
 
841
        stream.opaque = (void *)0;
 
842
        
 
843
        stream.next_in = inbuff;
 
844
        bufflen = stream.avail_in = MIN(length, PPT_LZW_BUFFSIZE);
 
845
        
 
846
        if (cli_readn(fd, inbuff, stream.avail_in) != (int64_t)stream.avail_in) {
 
847
                close(ofd);
 
848
                return FALSE;
 
849
        }
 
850
        length -= stream.avail_in;
 
851
        
 
852
        retval = inflateInit(&stream);
 
853
        if (retval != Z_OK) {
 
854
                cli_dbgmsg(" ppt_unlzw !Z_OK: %d\n", retval);
 
855
        }
 
856
        
672
857
        stream.next_out = outbuff;
673
 
        stream.avail_out = sizeof(outbuff);
674
 
        stream.avail_in = MIN(length, PPT_LZW_BUFFSIZE);
675
 
 
676
 
        if(cli_readn(fd, inbuff, stream.avail_in) != (int)stream.avail_in) {
677
 
                close(ofd);
678
 
                cli_unlink(fullname);
679
 
                return FALSE;
680
 
        }
681
 
        length -= stream.avail_in;
682
 
 
683
 
        if(inflateInit(&stream) != Z_OK) {
684
 
                close(ofd);
685
 
                cli_unlink(fullname);
686
 
                cli_warnmsg("ppt_unlzw: inflateInit failed\n");
687
 
                return FALSE;
688
 
        }
689
 
 
 
858
        stream.avail_out = PPT_LZW_BUFFSIZE;
 
859
        
690
860
        do {
691
861
                if (stream.avail_out == 0) {
692
862
                        if (cli_writen(ofd, outbuff, PPT_LZW_BUFFSIZE)
700
870
                }
701
871
                if (stream.avail_in == 0) {
702
872
                        stream.next_in = inbuff;
703
 
                        stream.avail_in = MIN(length, PPT_LZW_BUFFSIZE);
704
 
                        if (cli_readn(fd, inbuff, stream.avail_in) != (int)stream.avail_in) {
 
873
                        bufflen = stream.avail_in = MIN(length, PPT_LZW_BUFFSIZE);
 
874
                        if (cli_readn(fd, inbuff, stream.avail_in) != (int64_t)stream.avail_in) {
705
875
                                close(ofd);
706
876
                                inflateEnd(&stream);
707
877
                                return FALSE;
708
878
                        }
709
879
                        length -= stream.avail_in;
710
880
                }
711
 
        } while(inflate(&stream, Z_NO_FLUSH) == Z_OK);
712
 
 
713
 
        if (cli_writen(ofd, outbuff, PPT_LZW_BUFFSIZE-stream.avail_out) != (int)(PPT_LZW_BUFFSIZE-stream.avail_out)) {
 
881
                retval = inflate(&stream, Z_NO_FLUSH);
 
882
        } while (retval == Z_OK);
 
883
        
 
884
        if (cli_writen(ofd, outbuff, bufflen) != (int64_t)bufflen) {
714
885
                close(ofd);
715
886
                inflateEnd(&stream);
716
887
                return FALSE;
717
888
        }
 
889
        inflateEnd(&stream);
718
890
        close(ofd);
719
 
        return inflateEnd(&stream) == Z_OK;
 
891
        return TRUE;
720
892
}
721
893
 
722
 
static const char *
723
 
ppt_stream_iter(int fd, const char *dir)
 
894
static char *ppt_stream_iter(int fd)
724
895
{
725
896
        atom_header_t atom_header;
726
 
 
727
 
        while(ppt_read_atom_header(fd, &atom_header)) {
728
 
                if(atom_header.length == 0)
 
897
        uint32_t ole_id;
 
898
        char *out_dir;
 
899
        off_t offset;
 
900
        
 
901
        /* Create a directory to store the extracted OLE2 objects */
 
902
        out_dir = cli_gentemp(NULL);
 
903
        if(mkdir(out_dir, 0700)) {
 
904
            printf("ScanOLE2 -> Can't create temporary directory %s\n", out_dir);
 
905
            free(out_dir);
 
906
            close(fd);
 
907
            return NULL;
 
908
        }
 
909
 
 
910
        while (1) {
 
911
                if (!ppt_read_atom_header(fd, &atom_header)) {
 
912
                        break;
 
913
                }
 
914
                ppt_print_atom_header(&atom_header);
 
915
 
 
916
                if (atom_header.length == 0) {
 
917
                        cli_rmdirs(out_dir);
 
918
                        free(out_dir);
729
919
                        return NULL;
730
 
 
731
 
                if(atom_header.type == 0x1011) {
732
 
                        uint32_t length;
733
 
 
734
 
                        /* Skip over ID */
735
 
                        if(lseek(fd, sizeof(uint32_t), SEEK_CUR) == -1) {
736
 
                                cli_dbgmsg("ppt_stream_iter: seek failed\n");
 
920
                }
 
921
 
 
922
                if (atom_header.type == 0x1011) {
 
923
                        if (cli_readn(fd, &ole_id, 4) != 4) {
 
924
                                cli_dbgmsg("read ole_id failed\n");
 
925
                                cli_rmdirs(out_dir);
 
926
                                free(out_dir);
737
927
                                return NULL;
738
928
                        }
739
 
                        length = atom_header.length - 4;
740
 
                        cli_dbgmsg("length: %d\n", (int)length);
741
 
                        if (!ppt_unlzw(dir, fd, length)) {
 
929
                        ole_id = vba_endian_convert_32(ole_id, FALSE);
 
930
                        cli_dbgmsg("OleID: %d, length: %d\n",
 
931
                                        ole_id, atom_header.length-4);
 
932
                        if (!ppt_unlzw(out_dir, fd, atom_header.length-4)) {
742
933
                                cli_dbgmsg("ppt_unlzw failed\n");
 
934
                                cli_rmdirs(out_dir);
 
935
                                free(out_dir);
743
936
                                return NULL;
744
937
                        }
 
938
 
745
939
                } else {
746
 
                        off_t offset = lseek(fd, 0, SEEK_CUR);
 
940
                        offset = lseek(fd, 0, SEEK_CUR);
747
941
                        /* Check we don't wrap */
748
942
                        if ((offset + (off_t)atom_header.length) < offset) {
749
943
                                break;
750
944
                        }
751
945
                        offset += atom_header.length;
752
 
                        if (lseek(fd, offset, SEEK_SET) != offset) {
 
946
                        if (lseek(fd, offset, SEEK_SET) != offset ) {
753
947
                                break;
754
948
                        }
755
949
                }
756
950
        }
757
 
        return dir;
 
951
        return out_dir;
758
952
}
759
953
 
760
 
char *
761
 
cli_ppt_vba_read(int ifd, cli_ctx *ctx)
 
954
char *ppt_vba_read(const char *dir)
762
955
{
763
 
        char *dir;
764
 
        const char *ret;
 
956
        char *fullname, *out_dir;
 
957
        int fd;
765
958
 
766
 
        /* Create a directory to store the extracted OLE2 objects */
767
 
        dir = cli_gentemp(ctx ? ctx->engine->tmpdir : NULL);
768
 
        if(dir == NULL)
769
 
                return NULL;
770
 
        if(mkdir(dir, 0700)) {
771
 
                cli_errmsg("cli_ppt_vba_read: Can't create temporary directory %s\n", dir);
772
 
                free(dir);
773
 
                return NULL;
774
 
        }
775
 
        ret = ppt_stream_iter(ifd, dir);
776
 
        if(ret == NULL) {
777
 
                cli_rmdirs(dir);
778
 
                free(dir);
779
 
                return NULL;
780
 
        }
781
 
        return dir;
 
959
        fullname = (char *) cli_malloc(strlen(dir) + 21);
 
960
        if (!fullname) {
 
961
                return NULL;
 
962
        }
 
963
        sprintf(fullname, "%s/PowerPoint Document", dir);
 
964
        fd = open(fullname, O_RDONLY|O_BINARY);
 
965
        free(fullname);
 
966
        if (fd == -1) {
 
967
                cli_dbgmsg("Open  PowerPoint Document failed\n");
 
968
                return NULL;
 
969
        }
 
970
        
 
971
        out_dir = ppt_stream_iter(fd);
 
972
        close(fd);
 
973
        return out_dir;
782
974
}
783
975
 
784
 
/*
785
 
 * Word 6 macros
786
 
 */
787
 
typedef struct {
788
 
        unsigned        char unused[12];
789
 
        uint32_t        macro_offset;
790
 
        uint32_t        macro_len;
 
976
 
 
977
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 
978
/* Code to extract Word6 macros                                      */
 
979
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 
980
 
 
981
typedef struct mso_fib_tag {
 
982
        uint16_t magic;
 
983
        uint16_t version;
 
984
        uint16_t product;
 
985
        uint16_t lid;
 
986
        uint16_t next;
 
987
        uint16_t status;
 
988
        /* block of 268 bytes - ignore */
 
989
        uint32_t macro_offset;
 
990
        uint32_t macro_len;
791
991
} mso_fib_t;
792
992
 
793
993
typedef struct macro_entry_tag {
 
994
        unsigned char version;
 
995
        unsigned char key;
 
996
        uint16_t intname_i;
 
997
        uint16_t extname_i;
 
998
        uint16_t xname_i;
 
999
        uint32_t unknown;
794
1000
        uint32_t len;
 
1001
        uint32_t state;
795
1002
        uint32_t offset;
796
 
        unsigned char key;
797
1003
} macro_entry_t;
798
1004
 
799
1005
typedef struct macro_info_tag {
800
 
        struct macro_entry_tag *entries;
801
1006
        uint16_t count;
 
1007
        struct macro_entry_tag *macro_entry;
802
1008
} macro_info_t;
803
1009
 
804
 
static int
805
 
word_read_fib(int fd, mso_fib_t *fib)
806
 
{
807
 
        struct {
808
 
                uint32_t offset;
809
 
                uint32_t len;
810
 
        } macro_details;
811
 
 
812
 
        if(!seekandread(fd, 0x118, SEEK_SET, &macro_details, sizeof(macro_details))) {
813
 
                cli_dbgmsg("read word_fib failed\n");
814
 
                return FALSE;
815
 
        }
816
 
        fib->macro_offset = vba_endian_convert_32(macro_details.offset, FALSE);
817
 
        fib->macro_len = vba_endian_convert_32(macro_details.len, FALSE);
818
 
 
819
 
        return TRUE;
820
 
}
821
 
 
822
 
static int
823
 
word_read_macro_entry(int fd, macro_info_t *macro_info)
824
 
{
825
 
        int msize;
826
 
        int count = macro_info->count;
827
 
        macro_entry_t *macro_entry;
828
 
#ifdef HAVE_PRAGMA_PACK
829
 
#pragma pack(1)
830
 
#endif
831
 
 
832
 
#ifdef HAVE_PRAGMA_PACK_HPPA
833
 
#pragma pack 1
834
 
#endif
835
 
        struct macro {
836
 
                unsigned char version;
837
 
                unsigned char key;
838
 
                unsigned char ignore[10];
839
 
                uint32_t len    __attribute__ ((packed));
840
 
                uint32_t state  __attribute__ ((packed));
841
 
                uint32_t offset __attribute__ ((packed));
842
 
        } *m;
843
 
        const struct macro *n;
844
 
#ifdef HAVE_PRAGMA_PACK
845
 
#pragma pack()
846
 
#endif
847
 
 
848
 
#ifdef HAVE_PRAGMA_PACK_HPPA
849
 
#pragma pack
850
 
#endif
851
 
        if(count == 0)
852
 
                return TRUE;
853
 
 
854
 
        msize = count * sizeof(struct macro);
855
 
        m = cli_malloc(msize);
856
 
        if(m == NULL)
857
 
                return FALSE;
858
 
 
859
 
        if(cli_readn(fd, m, msize) != msize) {
860
 
                free(m);
861
 
                cli_warnmsg("read %d macro_entries failed\n", count);
862
 
                return FALSE;
863
 
        }
864
 
        macro_entry = macro_info->entries;
865
 
        n = m;
866
 
        do {
867
 
                macro_entry->key = n->key;
868
 
                macro_entry->len = vba_endian_convert_32(n->len, FALSE);
869
 
                macro_entry->offset = vba_endian_convert_32(n->offset, FALSE);
870
 
                macro_entry++;
871
 
                n++;
872
 
        } while(--count > 0);
873
 
        free(m);
874
 
        return TRUE;
875
 
}
876
 
 
877
 
static macro_info_t *
878
 
word_read_macro_info(int fd, macro_info_t *macro_info)
879
 
{
880
 
        if(!read_uint16(fd, &macro_info->count, FALSE)) {
 
1010
typedef struct macro_extname_tag {
 
1011
        uint8_t length;
 
1012
        unsigned char *extname;
 
1013
        uint16_t numref;
 
1014
} macro_extname_t;
 
1015
 
 
1016
typedef struct macro_extnames_tag {
 
1017
        uint16_t count;
 
1018
        struct macro_extname_tag *macro_extname;
 
1019
} macro_extnames_t;
 
1020
 
 
1021
typedef struct macro_intnames_tag {
 
1022
        uint16_t count;
 
1023
        struct macro_intname_tag *macro_intname;
 
1024
} macro_intnames_t;
 
1025
 
 
1026
typedef struct macro_intname_tag {
 
1027
        uint16_t id;
 
1028
        uint8_t length;
 
1029
        unsigned char *intname;
 
1030
} macro_intname_t;
 
1031
 
 
1032
typedef struct menu_entry_tag {
 
1033
        uint16_t context;
 
1034
        uint16_t menu;
 
1035
        uint16_t extname_i;
 
1036
        uint16_t unknown;
 
1037
        uint16_t intname_i;
 
1038
        uint16_t pos;
 
1039
} menu_entry_t;
 
1040
 
 
1041
typedef struct menu_info_tag {
 
1042
        uint16_t count;
 
1043
        struct menu_entry_tag *menu_entry;
 
1044
} menu_info_t;
 
1045
 
 
1046
typedef struct mac_token_tag {
 
1047
        unsigned char token;
 
1048
        unsigned char *str;
 
1049
} mac_token_t;
 
1050
 
 
1051
typedef struct mac_token2_tag {
 
1052
        uint16_t token;
 
1053
        unsigned char *str;
 
1054
 
 
1055
} mac_token2_t;
 
1056
 
 
1057
static void wm_print_fib(mso_fib_t *fib)
 
1058
{
 
1059
        cli_dbgmsg("magic: 0x%.4x\n", fib->magic);
 
1060
        cli_dbgmsg("version: 0x%.4x\n", fib->version);
 
1061
        cli_dbgmsg("product: 0x%.4x\n", fib->product);
 
1062
        cli_dbgmsg("lid: 0x%.4x\n", fib->lid);
 
1063
        cli_dbgmsg("macro offset: 0x%.4x\n", fib->macro_offset);
 
1064
        cli_dbgmsg("macro len: 0x%.4x\n\n", fib->macro_len);
 
1065
}
 
1066
        
 
1067
static int wm_read_fib(int fd, mso_fib_t *fib)
 
1068
{
 
1069
        if (cli_readn(fd, &fib->magic, 2) != 2) {
 
1070
                cli_dbgmsg("read wm_fib failed\n");
 
1071
                return FALSE;
 
1072
        }
 
1073
        if (cli_readn(fd, &fib->version, 2) != 2) {
 
1074
                cli_dbgmsg("read wm_fib failed\n");
 
1075
                return FALSE;
 
1076
        }
 
1077
        if (cli_readn(fd, &fib->product, 2) != 2) {
 
1078
                cli_dbgmsg("read wm_fib failed\n");
 
1079
                return FALSE;
 
1080
        }
 
1081
        if (cli_readn(fd, &fib->lid, 2) != 2) {
 
1082
                cli_dbgmsg("read wm_fib failed\n");
 
1083
                return FALSE;
 
1084
        }       
 
1085
        if (cli_readn(fd, &fib->next, 2) != 2) {
 
1086
                cli_dbgmsg("read wm_fib failed\n");
 
1087
                return FALSE;
 
1088
        }
 
1089
        if (cli_readn(fd, &fib->status, 2) != 2) {
 
1090
                cli_dbgmsg("read wm_fib failed\n");
 
1091
                return FALSE;
 
1092
        }
 
1093
        
 
1094
        /* don't need the information is this block, so seek forward */
 
1095
        if (lseek(fd, 0x118, SEEK_SET) != 0x118) {
 
1096
                cli_dbgmsg("lseek wm_fib failed\n");
 
1097
                return FALSE;
 
1098
        }
 
1099
        
 
1100
        if (cli_readn(fd, &fib->macro_offset, 4) != 4) {
 
1101
                cli_dbgmsg("read wm_fib failed\n");
 
1102
                return FALSE;
 
1103
        }
 
1104
        if (cli_readn(fd, &fib->macro_len, 4) != 4) {
 
1105
                cli_dbgmsg("read wm_fib failed\n");
 
1106
                return FALSE;
 
1107
        }
 
1108
        fib->magic = vba_endian_convert_16(fib->magic, FALSE);
 
1109
        fib->version = vba_endian_convert_16(fib->version, FALSE);
 
1110
        fib->product = vba_endian_convert_16(fib->product, FALSE);
 
1111
        fib->lid = vba_endian_convert_16(fib->lid, FALSE);
 
1112
        fib->next = vba_endian_convert_16(fib->next, FALSE);
 
1113
        fib->status = vba_endian_convert_16(fib->status, FALSE);
 
1114
        fib->macro_offset = vba_endian_convert_32(fib->macro_offset, FALSE);
 
1115
        fib->macro_len = vba_endian_convert_32(fib->macro_len, FALSE);
 
1116
        
 
1117
        return TRUE;
 
1118
}
 
1119
 
 
1120
static int wm_read_macro_entry(int fd, macro_entry_t *macro_entry)
 
1121
{
 
1122
        if (cli_readn(fd, &macro_entry->version, 1) != 1) {
 
1123
                cli_dbgmsg("read macro_entry failed\n");
 
1124
                return FALSE;
 
1125
        }
 
1126
        if (cli_readn(fd, &macro_entry->key, 1) != 1) {
 
1127
                cli_dbgmsg("read macro_entry failed\n");
 
1128
                return FALSE;
 
1129
        }
 
1130
        if (cli_readn(fd, &macro_entry->intname_i, 2) != 2) {
 
1131
                cli_dbgmsg("read macro_entry failed\n");
 
1132
                return FALSE;
 
1133
        }       
 
1134
        if (cli_readn(fd, &macro_entry->extname_i, 2) != 2) {
 
1135
                cli_dbgmsg("read macro_entry failed\n");
 
1136
                return FALSE;
 
1137
        }
 
1138
        if (cli_readn(fd, &macro_entry->xname_i, 2) != 2) {
 
1139
                cli_dbgmsg("read macro_entry failed\n");
 
1140
                return FALSE;
 
1141
        }
 
1142
        if (cli_readn(fd, &macro_entry->unknown, 4) != 4) {
 
1143
                cli_dbgmsg("read macro_entry failed\n");
 
1144
                return FALSE;
 
1145
        }
 
1146
        if (cli_readn(fd, &macro_entry->len, 4) != 4) {
 
1147
                cli_dbgmsg("read macro_entry failed\n");
 
1148
                return FALSE;
 
1149
        }
 
1150
        if (cli_readn(fd, &macro_entry->state, 4) != 4) {
 
1151
                cli_dbgmsg("read macro_entry failed\n");
 
1152
                return FALSE;
 
1153
        }
 
1154
        if (cli_readn(fd, &macro_entry->offset, 4) != 4) {
 
1155
                cli_dbgmsg("read macro_entry failed\n");
 
1156
                return FALSE;
 
1157
        }
 
1158
        
 
1159
        macro_entry->intname_i = vba_endian_convert_16(macro_entry->intname_i, FALSE);
 
1160
        macro_entry->extname_i = vba_endian_convert_16(macro_entry->extname_i, FALSE);
 
1161
        macro_entry->xname_i = vba_endian_convert_16(macro_entry->xname_i, FALSE);
 
1162
        macro_entry->len = vba_endian_convert_32(macro_entry->len, FALSE);
 
1163
        macro_entry->state = vba_endian_convert_32(macro_entry->state, FALSE);
 
1164
        macro_entry->offset = vba_endian_convert_32(macro_entry->offset, FALSE);
 
1165
        return TRUE;
 
1166
}
 
1167
 
 
1168
static macro_info_t *wm_read_macro_info(int fd)
 
1169
{
 
1170
        int i;
 
1171
        macro_info_t *macro_info;
 
1172
 
 
1173
        macro_info = (macro_info_t *) cli_malloc(sizeof(macro_info_t));
 
1174
        if (!macro_info) {
 
1175
                return NULL;
 
1176
        }
 
1177
        if (cli_readn(fd, &macro_info->count, 2) != 2) {
881
1178
                cli_dbgmsg("read macro_info failed\n");
882
 
                macro_info->count = 0;
 
1179
                free(macro_info);
883
1180
                return NULL;
884
1181
        }
 
1182
        macro_info->count = vba_endian_convert_16(macro_info->count, FALSE);
885
1183
        cli_dbgmsg("macro count: %d\n", macro_info->count);
886
 
        if(macro_info->count == 0)
887
 
                return NULL;
888
 
        macro_info->entries = (macro_entry_t *)cli_malloc(sizeof(macro_entry_t) * macro_info->count);
889
 
        if(macro_info->entries == NULL) {
890
 
                macro_info->count = 0;
 
1184
        macro_info->macro_entry = (macro_entry_t *)
 
1185
                        cli_malloc(sizeof(macro_entry_t) * macro_info->count);
 
1186
        if (!macro_info->macro_entry) {
 
1187
                free(macro_info);
891
1188
                return NULL;
892
1189
        }
893
 
        if(!word_read_macro_entry(fd, macro_info)) {
894
 
                free(macro_info->entries);
895
 
                macro_info->count = 0;
896
 
                return NULL;
 
1190
        for (i=0 ; i < macro_info->count ; i++) {
 
1191
                if (!wm_read_macro_entry(fd,
 
1192
                                &macro_info->macro_entry[i])) {
 
1193
                        free(macro_info->macro_entry);
 
1194
                        free(macro_info);
 
1195
                        return NULL;
 
1196
                }
897
1197
        }
898
1198
        return macro_info;
899
1199
}
900
1200
 
901
 
static int
902
 
word_skip_oxo3(int fd)
 
1201
static void wm_free_macro_info(macro_info_t *macro_info)
 
1202
{
 
1203
        if (macro_info) {
 
1204
                free(macro_info->macro_entry);
 
1205
                free(macro_info);
 
1206
        }
 
1207
        return;
 
1208
}
 
1209
 
 
1210
static int wm_read_oxo3(int fd)
903
1211
{
904
1212
        uint8_t count;
905
1213
 
907
1215
                cli_dbgmsg("read oxo3 record1 failed\n");
908
1216
                return FALSE;
909
1217
        }
 
1218
        if (lseek(fd, count*14, SEEK_CUR) == -1) {
 
1219
                cli_dbgmsg("lseek oxo3 record1 failed\n");
 
1220
                return FALSE;
 
1221
        }
910
1222
        cli_dbgmsg("oxo3 records1: %d\n", count);
911
 
 
912
 
        if(!seekandread(fd, count * 14, SEEK_CUR, &count, 1)) {
 
1223
        
 
1224
        if (cli_readn(fd, &count, 1) != 1) {
913
1225
                cli_dbgmsg("read oxo3 record2 failed\n");
914
1226
                return FALSE;
915
1227
        }
916
 
 
917
 
        if(count == 0) {
918
 
                uint8_t twobytes[2];
919
 
 
920
 
                if(cli_readn(fd, twobytes, 2) != 2) {
 
1228
        if (count == 0) {
 
1229
                if (cli_readn(fd, &count, 1) != 1) {
921
1230
                        cli_dbgmsg("read oxo3 failed\n");
922
1231
                        return FALSE;
923
1232
                }
924
 
                if(twobytes[0] != 2) {
925
 
                        lseek(fd, -2, SEEK_CUR);
 
1233
                if (count != 2) {
 
1234
                        lseek(fd, -1, SEEK_CUR);
926
1235
                        return TRUE;
927
1236
                }
928
 
                count = twobytes[1];
 
1237
                if (cli_readn(fd, &count, 1) != 1) {
 
1238
                        cli_dbgmsg("read oxo3 failed\n");
 
1239
                        return FALSE;
 
1240
                }
929
1241
        }
930
 
        if(count > 0)
 
1242
        if (count > 0) {
931
1243
                if (lseek(fd, (count*4)+1, SEEK_CUR) == -1) {
932
1244
                        cli_dbgmsg("lseek oxo3 failed\n");
933
1245
                        return FALSE;
934
1246
                }
935
 
 
 
1247
        }                               
936
1248
        cli_dbgmsg("oxo3 records2: %d\n", count);
937
1249
        return TRUE;
938
1250
}
939
1251
 
940
 
static int
941
 
word_skip_menu_info(int fd)
 
1252
static menu_info_t *wm_read_menu_info(int fd)
942
1253
{
943
 
        uint16_t count;
944
 
 
945
 
        if(!read_uint16(fd, &count, FALSE)) {
 
1254
        int i;
 
1255
        menu_info_t *menu_info;
 
1256
        menu_entry_t *menu_entry;
 
1257
        
 
1258
        menu_info = (menu_info_t *) cli_malloc(sizeof(menu_info_t));
 
1259
        if (!menu_info) {
 
1260
                return NULL;
 
1261
        }
 
1262
        
 
1263
        if (cli_readn(fd, &menu_info->count, 2) != 2) {
946
1264
                cli_dbgmsg("read menu_info failed\n");
947
 
                return FALSE;
948
 
        }
949
 
        cli_dbgmsg("menu_info count: %d\n", count);
950
 
 
951
 
        if(count)
952
 
                if(lseek(fd, count * 12, SEEK_CUR) == -1)
953
 
                        return FALSE;
954
 
        return TRUE;
955
 
}
956
 
 
957
 
static int
958
 
word_skip_macro_extnames(int fd)
959
 
{
960
 
        int is_unicode, nbytes;
 
1265
                free(menu_info);
 
1266
                return NULL;
 
1267
        }
 
1268
        menu_info->count = vba_endian_convert_16(menu_info->count, FALSE);
 
1269
        cli_dbgmsg("menu_info count: %d\n", menu_info->count);
 
1270
        
 
1271
        menu_info->menu_entry =
 
1272
                (menu_entry_t *) cli_malloc(sizeof(menu_entry_t) * menu_info->count);
 
1273
        if (!menu_info->menu_entry) {
 
1274
                free(menu_info);
 
1275
                return NULL;
 
1276
        }
 
1277
        
 
1278
        for (i=0 ; i < menu_info->count ; i++) {
 
1279
                menu_entry = &menu_info->menu_entry[i];
 
1280
                if (cli_readn(fd, &menu_entry->context, 2) != 2) {
 
1281
                        goto abort;
 
1282
                }
 
1283
                if (cli_readn(fd, &menu_entry->menu, 2) != 2) {
 
1284
                        goto abort;
 
1285
                }
 
1286
                if (cli_readn(fd, &menu_entry->extname_i, 2) != 2) {
 
1287
                        goto abort;
 
1288
                }
 
1289
                if (cli_readn(fd, &menu_entry->unknown, 2) != 2) {
 
1290
                        goto abort;
 
1291
                }
 
1292
                if (cli_readn(fd, &menu_entry->intname_i, 2) != 2) {
 
1293
                        goto abort;
 
1294
                }
 
1295
                if (cli_readn(fd, &menu_entry->pos, 2) != 2) {
 
1296
                        goto abort;
 
1297
                }
 
1298
                menu_entry->context = vba_endian_convert_16(menu_entry->context, FALSE);
 
1299
                menu_entry->menu = vba_endian_convert_16(menu_entry->menu, FALSE);
 
1300
                menu_entry->extname_i = vba_endian_convert_16(menu_entry->extname_i, FALSE);
 
1301
                menu_entry->intname_i = vba_endian_convert_16(menu_entry->intname_i, FALSE);
 
1302
                menu_entry->pos = vba_endian_convert_16(menu_entry->pos, FALSE);
 
1303
                cli_dbgmsg("menu entry: %d.%d\n", menu_entry->menu, menu_entry->pos);
 
1304
        }
 
1305
        return menu_info;
 
1306
        
 
1307
abort:
 
1308
        cli_dbgmsg("read menu_entry failed\n");
 
1309
        free(menu_info->menu_entry);
 
1310
        free(menu_info);
 
1311
        return NULL;
 
1312
}
 
1313
 
 
1314
static void wm_free_menu_info(menu_info_t *menu_info)
 
1315
{
 
1316
        if (menu_info) {
 
1317
                free(menu_info->menu_entry);
 
1318
                free(menu_info);
 
1319
        }
 
1320
        return;
 
1321
}
 
1322
 
 
1323
static macro_extnames_t *wm_read_macro_extnames(int fd)
 
1324
{
 
1325
        int i, is_unicode=0;
961
1326
        int16_t size;
962
 
 
963
 
        if(!read_uint16(fd, (uint16_t *)&size, FALSE)) {
 
1327
        off_t offset_end;       
 
1328
        macro_extnames_t *macro_extnames;
 
1329
        macro_extname_t *macro_extname;
 
1330
        unsigned char *name_tmp;
 
1331
        
 
1332
        macro_extnames = (macro_extnames_t *) cli_malloc(sizeof(macro_extnames_t));
 
1333
        if (!macro_extnames) {
 
1334
                return NULL;
 
1335
        }
 
1336
        macro_extnames->count = 0;
 
1337
        macro_extnames->macro_extname = NULL;
 
1338
        
 
1339
        offset_end = lseek(fd, 0, SEEK_CUR);
 
1340
        if (cli_readn(fd, &size, 2) != 2) {
964
1341
                cli_dbgmsg("read macro_extnames failed\n");
965
 
                return FALSE;
 
1342
                free(macro_extnames);
 
1343
                return NULL;
966
1344
        }
 
1345
        size = vba_endian_convert_16(size, FALSE);
967
1346
        if (size == -1) { /* Unicode flag */
968
 
                if(!read_uint16(fd, (uint16_t *)&size, FALSE)) {
 
1347
                is_unicode=1;
 
1348
                if (cli_readn(fd, &size, 2) != 2) {
969
1349
                        cli_dbgmsg("read macro_extnames failed\n");
970
 
                        return FALSE;
 
1350
                        free(macro_extnames);
 
1351
                        return NULL;
971
1352
                }
972
 
                is_unicode = 1;
973
 
        } else
974
 
                is_unicode = 0;
975
 
 
 
1353
                size = vba_endian_convert_16(size, FALSE);
 
1354
        }
976
1355
        cli_dbgmsg("ext names size: 0x%x\n", size);
977
1356
 
978
 
        nbytes = size;
979
 
        while(nbytes > 0) {
980
 
                uint8_t length;
981
 
                off_t offset;
982
 
 
983
 
                if (cli_readn(fd, &length, 1) != 1) {
984
 
                        cli_dbgmsg("read macro_extnames failed\n");
985
 
                        return FALSE;
986
 
                }
987
 
 
988
 
                if(is_unicode)
989
 
                        offset = (off_t)length * 2 + 1;
990
 
                else
991
 
                        offset = (off_t)length;
992
 
 
993
 
                /* ignore numref as well */
994
 
                if(lseek(fd, offset + sizeof(uint16_t), SEEK_CUR) == -1) {
995
 
                        cli_dbgmsg("read macro_extnames failed to seek\n");
996
 
                        return FALSE;
997
 
                }
998
 
                nbytes -= size;
999
 
        }
1000
 
        return TRUE;
1001
 
}
1002
 
 
1003
 
static int
1004
 
word_skip_macro_intnames(int fd)
1005
 
{
1006
 
        uint16_t count;
1007
 
 
1008
 
        if(!read_uint16(fd, &count, FALSE)) {
 
1357
        offset_end += size;
 
1358
        while (lseek(fd, 0, SEEK_CUR) < offset_end) {
 
1359
                macro_extnames->count++;
 
1360
                macro_extnames->macro_extname = (macro_extname_t *)
 
1361
                        cli_realloc(macro_extnames->macro_extname,
 
1362
                                sizeof(macro_extname_t) * macro_extnames->count);
 
1363
                if (macro_extnames->macro_extname == NULL) {
 
1364
                        cli_dbgmsg("read macro_extnames failed\n");
 
1365
                        goto abort;;
 
1366
                }
 
1367
 
 
1368
                macro_extname = &macro_extnames->macro_extname[macro_extnames->count-1];
 
1369
                if (is_unicode) {
 
1370
                        if (cli_readn(fd, &macro_extname->length, 1) != 1) {
 
1371
                                cli_dbgmsg("read macro_extnames failed\n");
 
1372
                                goto abort;
 
1373
                        }
 
1374
                        lseek(fd, 1, SEEK_CUR);
 
1375
                        if (macro_extname->length > 0) {
 
1376
                            name_tmp = (char *) cli_malloc(macro_extname->length*2);
 
1377
                            if (name_tmp == NULL) {
 
1378
                                goto abort;
 
1379
                            }
 
1380
                            if (cli_readn(fd, name_tmp, macro_extname->length*2) != 
 
1381
                                                macro_extname->length*2) {
 
1382
                                cli_dbgmsg("read macro_extnames failed\n");
 
1383
                                free(name_tmp);
 
1384
                                goto abort;
 
1385
                            }
 
1386
                            macro_extname->extname =
 
1387
                                get_unicode_name(name_tmp, macro_extname->length*2, FALSE);
 
1388
                            free(name_tmp);
 
1389
                        } else {
 
1390
                            macro_extname->extname = cli_strdup("[no name]");
 
1391
                            macro_extname->length = 10;
 
1392
                        }
 
1393
                } else {
 
1394
                        if (cli_readn(fd, &macro_extname->length, 1) != 1) {
 
1395
                                cli_dbgmsg("read macro_extnames failed\n");
 
1396
                                goto abort;
 
1397
                        }
 
1398
                        if (macro_extname->length > 0) {
 
1399
                            macro_extname->extname = (char *) cli_malloc(macro_extname->length+1);
 
1400
                            if (!macro_extname->extname) {
 
1401
                                goto abort;
 
1402
                            }
 
1403
                            if (cli_readn(fd, macro_extname->extname, macro_extname->length) != 
 
1404
                                                macro_extname->length) {
 
1405
                                cli_dbgmsg("read macro_extnames failed\n");
 
1406
                                free(macro_extname->extname);
 
1407
                                goto abort;
 
1408
                            }
 
1409
                            macro_extname->extname[macro_extname->length] = '\0';
 
1410
                        } else {
 
1411
                            macro_extname->extname = cli_strdup("[no name]");
 
1412
                            macro_extname->length = 10;
 
1413
                        }
 
1414
                }
 
1415
                if (cli_readn(fd, &macro_extname->numref, 2) != 2) {
 
1416
                        cli_dbgmsg("read macro_extnames failed\n");
 
1417
                        return NULL;
 
1418
                }       
 
1419
                macro_extname->numref = vba_endian_convert_16(macro_extname->numref, FALSE);
 
1420
                cli_dbgmsg("ext name: %s\n", macro_extname->extname);
 
1421
        }
 
1422
        return macro_extnames;
 
1423
        
 
1424
abort:
 
1425
        if (macro_extnames->macro_extname != NULL) {
 
1426
                for (i=0 ; i < macro_extnames->count-1 ; i++) {
 
1427
                        free(macro_extnames->macro_extname[i].extname);
 
1428
                }
 
1429
                free(macro_extnames->macro_extname);
 
1430
        }
 
1431
        free(macro_extnames);
 
1432
        return NULL;
 
1433
}
 
1434
 
 
1435
static void wm_free_extnames(macro_extnames_t *macro_extnames)
 
1436
{
 
1437
        int i;
 
1438
        
 
1439
        if (macro_extnames) {
 
1440
                for (i=0 ; i < macro_extnames->count ; i++) {
 
1441
                        free(macro_extnames->macro_extname[i].extname);
 
1442
                }
 
1443
                free(macro_extnames->macro_extname);
 
1444
                free(macro_extnames);
 
1445
        }
 
1446
        return;
 
1447
}
 
1448
 
 
1449
static macro_intnames_t *wm_read_macro_intnames(int fd)
 
1450
{
 
1451
        int i;
 
1452
        macro_intnames_t *macro_intnames;
 
1453
        macro_intname_t *macro_intname;
 
1454
        uint16_t junk;
 
1455
        
 
1456
        macro_intnames = (macro_intnames_t *) cli_malloc(sizeof(macro_intnames_t));
 
1457
        if (!macro_intnames) {
 
1458
                return NULL;
 
1459
        }
 
1460
        
 
1461
        if (cli_readn(fd, &macro_intnames->count, 2) != 2) {
1009
1462
                cli_dbgmsg("read macro_intnames failed\n");
1010
 
                return FALSE;
1011
 
        }
1012
 
        cli_dbgmsg("intnames count: %u\n", (unsigned int)count);
1013
 
 
1014
 
        while(count-- > 0) {
1015
 
                uint8_t length;
1016
 
 
1017
 
                /* id */
1018
 
                if(!seekandread(fd, sizeof(uint16_t), SEEK_CUR, &length, sizeof(uint8_t))) {
1019
 
                        cli_dbgmsg("skip_macro_intnames failed\n");
1020
 
                        return FALSE;
1021
 
                }
1022
 
 
1023
 
                /* Internal name, plus one byte of unknown data */
1024
 
                if(lseek(fd, length + 1, SEEK_CUR) == -1) {
1025
 
                        cli_dbgmsg("skip_macro_intnames failed\n");
1026
 
                        return FALSE;
1027
 
                }
1028
 
        }
1029
 
        return TRUE;
1030
 
}
1031
 
 
1032
 
vba_project_t *
1033
 
cli_wm_readdir(int fd)
1034
 
{
1035
 
        int done;
 
1463
                return NULL;
 
1464
        }
 
1465
        macro_intnames->count = vba_endian_convert_16(macro_intnames->count, FALSE);
 
1466
        cli_dbgmsg("int names count: %d\n", macro_intnames->count);
 
1467
        
 
1468
        macro_intnames->macro_intname =
 
1469
                (macro_intname_t *) cli_malloc(sizeof(macro_intname_t) * macro_intnames->count);
 
1470
        if (!macro_intnames->macro_intname) {
 
1471
                free(macro_intnames);
 
1472
                return NULL;
 
1473
        }
 
1474
        for (i=0 ; i < macro_intnames->count ; i++) {
 
1475
                macro_intname = &macro_intnames->macro_intname[i];
 
1476
                if (cli_readn(fd, &macro_intname->id, 2) != 2) {
 
1477
                        cli_dbgmsg("read macro_intnames failed\n");
 
1478
                        macro_intnames->count = i;
 
1479
                        goto abort;
 
1480
                }
 
1481
                macro_intname->id = vba_endian_convert_16(macro_intname->id, FALSE);
 
1482
                if (cli_readn(fd, &macro_intname->length, 1) != 1) {
 
1483
                        cli_dbgmsg("read macro_intnames failed\n");
 
1484
                        macro_intnames->count = i;
 
1485
                        goto abort;;
 
1486
                }       
 
1487
                macro_intname->intname = (char *) cli_malloc(macro_intname->length+1);
 
1488
                if (!macro_intname->intname) {
 
1489
                        macro_intnames->count = i;
 
1490
                        goto abort;
 
1491
                }
 
1492
                if (cli_readn(fd, macro_intname->intname, macro_intname->length) != macro_intname->length) {
 
1493
                        cli_dbgmsg("read macro_intnames failed\n");
 
1494
                        macro_intnames->count = i+1;
 
1495
                        goto abort;
 
1496
                }
 
1497
                macro_intname->intname[macro_intname->length] = '\0';
 
1498
                if (cli_readn(fd, &junk, 1) != 1) {
 
1499
                        cli_dbgmsg("read macro_intnames failed\n");
 
1500
                        macro_intnames->count = i+1;
 
1501
                        goto abort;
 
1502
                }
 
1503
                cli_dbgmsg("int name: %s\n", macro_intname->intname);
 
1504
        }
 
1505
        return macro_intnames;
 
1506
abort:
 
1507
        for (i=0 ; i < macro_intnames->count ; i++) {
 
1508
                free(macro_intnames->macro_intname[i].intname);
 
1509
        }
 
1510
        free(macro_intnames->macro_intname);
 
1511
        free(macro_intnames);
 
1512
        return NULL;
 
1513
}
 
1514
 
 
1515
static void wm_free_intnames(macro_intnames_t *macro_intnames)
 
1516
{
 
1517
        int i;
 
1518
        
 
1519
        if (macro_intnames) {
 
1520
                for (i=0 ; i < macro_intnames->count ; i++) {
 
1521
                        free(macro_intnames->macro_intname[i].intname);
 
1522
                }
 
1523
                free(macro_intnames->macro_intname);
 
1524
                free(macro_intnames);
 
1525
        }
 
1526
        return;
 
1527
}
 
1528
 
 
1529
vba_project_t *wm_dir_read(const char *dir)
 
1530
{
 
1531
        int fd, done=FALSE, i;
 
1532
        mso_fib_t fib;
1036
1533
        off_t end_offset;
1037
 
        unsigned char info_id;
1038
 
        macro_info_t macro_info;
1039
 
        vba_project_t *vba_project;
1040
 
        mso_fib_t fib;
1041
 
 
1042
 
        if (!word_read_fib(fd, &fib))
1043
 
                return NULL;
1044
 
 
1045
 
        if(fib.macro_len == 0) {
1046
 
                cli_dbgmsg("wm_readdir: No macros detected\n");
1047
 
                /* Must be clean */
1048
 
                return NULL;
1049
 
        }
1050
 
        cli_dbgmsg("wm_readdir: macro offset: 0x%.4x\n", (int)fib.macro_offset);
1051
 
        cli_dbgmsg("wm_readdir: macro len: 0x%.4x\n\n", (int)fib.macro_len);
1052
 
 
1053
 
        /* Go one past the start to ignore start_id */
1054
 
        if (lseek(fd, fib.macro_offset + 1, SEEK_SET) != (off_t)(fib.macro_offset + 1)) {
1055
 
                cli_dbgmsg("wm_readdir: lseek macro_offset failed\n");
1056
 
                return NULL;
1057
 
        }
1058
 
 
 
1534
        unsigned char start_id, info_id;
 
1535
        macro_info_t *macro_info=NULL;
 
1536
        menu_info_t *menu_info=NULL;
 
1537
        macro_extnames_t *macro_extnames=NULL;
 
1538
        macro_intnames_t *macro_intnames=NULL;
 
1539
        vba_project_t *vba_project=NULL;
 
1540
        char *fullname;
 
1541
        
 
1542
        fullname = (char *) cli_malloc(strlen(dir) + 14);
 
1543
        if (!fullname) {
 
1544
                return NULL;
 
1545
        }
 
1546
        sprintf(fullname, "%s/WordDocument", dir);
 
1547
        fd = open(fullname, O_RDONLY|O_BINARY);
 
1548
        free(fullname);
 
1549
        if (fd == -1) {
 
1550
                cli_dbgmsg("Open WordDocument failed\n");
 
1551
                return NULL;
 
1552
        }
 
1553
        
 
1554
        if (!wm_read_fib(fd, &fib)) {
 
1555
                close(fd);
 
1556
                return NULL;
 
1557
        }
 
1558
        wm_print_fib(&fib);
 
1559
        
 
1560
        if (lseek(fd, fib.macro_offset, SEEK_SET) != (int64_t)fib.macro_offset) {
 
1561
                cli_dbgmsg("lseek macro_offset failed\n");
 
1562
                close(fd);
 
1563
                return NULL;
 
1564
        }
 
1565
        
1059
1566
        end_offset = fib.macro_offset + fib.macro_len;
1060
 
        done = FALSE;
1061
 
        memset(&macro_info, '\0', sizeof(macro_info));
1062
 
 
1063
 
        while((lseek(fd, 0, SEEK_CUR) < end_offset) && !done) {
 
1567
        
 
1568
        if (cli_readn(fd, &start_id, 1) != 1) {
 
1569
                cli_dbgmsg("read start_id failed\n");
 
1570
                close(fd);
 
1571
                return NULL;
 
1572
        }
 
1573
        cli_dbgmsg("start_id: %d\n", start_id);
 
1574
        
 
1575
        while ((lseek(fd, 0, SEEK_CUR) < end_offset) && !done) {
1064
1576
                if (cli_readn(fd, &info_id, 1) != 1) {
1065
 
                        cli_dbgmsg("wm_readdir: read macro_info failed\n");
1066
 
                        break;
 
1577
                        cli_dbgmsg("read macro_info failed\n");
 
1578
                        close(fd);
 
1579
                        return NULL;
1067
1580
                }
1068
1581
                switch (info_id) {
1069
1582
                        case 0x01:
1070
 
                                if(macro_info.count)
1071
 
                                        free(macro_info.entries);
1072
 
                                word_read_macro_info(fd, &macro_info);
1073
 
                                done = TRUE;
 
1583
                                macro_info = wm_read_macro_info(fd);
 
1584
                                if (macro_info == NULL) {
 
1585
                                        done = TRUE;
 
1586
                                }
1074
1587
                                break;
1075
1588
                        case 0x03:
1076
 
                                if(!word_skip_oxo3(fd))
 
1589
                                if (!wm_read_oxo3(fd)) {
1077
1590
                                        done = TRUE;
 
1591
                                }
1078
1592
                                break;
1079
1593
                        case 0x05:
1080
 
                                if(!word_skip_menu_info(fd))
 
1594
                                menu_info = wm_read_menu_info(fd);
 
1595
                                if (menu_info == NULL) {
1081
1596
                                        done = TRUE;
 
1597
                                }
1082
1598
                                break;
1083
1599
                        case 0x10:
1084
 
                                if(!word_skip_macro_extnames(fd))
 
1600
                                macro_extnames = wm_read_macro_extnames(fd);
 
1601
                                if (macro_extnames == NULL) {
1085
1602
                                        done = TRUE;
 
1603
                                }
1086
1604
                                break;
1087
1605
                        case 0x11:
1088
 
                                if(!word_skip_macro_intnames(fd))
 
1606
                                macro_intnames = wm_read_macro_intnames(fd);
 
1607
                                if (macro_intnames == NULL) {
1089
1608
                                        done = TRUE;
1090
 
                                break;
1091
 
                        case 0x40:      /* end marker */
1092
 
                        case 0x12:      /* ??? */
1093
 
                                done = TRUE;
 
1609
                                }                               
 
1610
                                break;
 
1611
                        case 0x12:
 
1612
                                /* No sure about these, always seems to
 
1613
                                come after the macros though, so finish
 
1614
                                */
 
1615
                                done = 1;
 
1616
                                break;
 
1617
                        case 0x40:
 
1618
                                /* end marker */
 
1619
                                done = 1;
1094
1620
                                break;
1095
1621
                        default:
1096
 
                                cli_dbgmsg("wm_readdir: unknown type: 0x%x\n", info_id);
1097
 
                                done = TRUE;
1098
 
                }
1099
 
        }
1100
 
 
1101
 
 
1102
 
        if(macro_info.count == 0)
1103
 
                return NULL;
1104
 
 
1105
 
        vba_project = create_vba_project(macro_info.count, "", NULL);
1106
 
 
1107
 
        if(vba_project) {
1108
 
                vba_project->length = (uint32_t *)cli_malloc(sizeof(uint32_t) *
1109
 
                                macro_info.count);
1110
 
                vba_project->key = (unsigned char *)cli_malloc(sizeof(unsigned char) *
1111
 
                                macro_info.count);
1112
 
                if((vba_project->length != NULL) &&
1113
 
                   (vba_project->key != NULL)) {
1114
 
                        int i;
1115
 
                        const macro_entry_t *m = macro_info.entries;
1116
 
 
1117
 
                        for(i = 0; i < macro_info.count; i++) {
1118
 
                                vba_project->offset[i] = m->offset;
1119
 
                                vba_project->length[i] = m->len;
1120
 
                                vba_project->key[i] = m->key;
1121
 
                                m++;
1122
 
                        }
1123
 
                } else {
1124
 
                        free(vba_project->name);
1125
 
                        free(vba_project->colls);
1126
 
                        free(vba_project->dir);
1127
 
                        free(vba_project->offset);
1128
 
                        if(vba_project->length)
1129
 
                                free(vba_project->length);
1130
 
                        if(vba_project->key)
1131
 
                                free(vba_project->key);
1132
 
                        free(vba_project);
1133
 
                        vba_project = NULL;
1134
 
                }
1135
 
        }
1136
 
        free(macro_info.entries);
1137
 
 
 
1622
                                cli_dbgmsg("\nunknown type: 0x%x\n", info_id);
 
1623
                                done = 1;
 
1624
                }
 
1625
        }
 
1626
        
 
1627
        if (macro_info) {
 
1628
                vba_project = (vba_project_t *) cli_malloc(sizeof(struct vba_project_tag));
 
1629
                if (!vba_project) {
 
1630
                        goto abort;
 
1631
                }
 
1632
                vba_project->name = (char **) cli_malloc(sizeof(char *) *macro_info->count);
 
1633
                if (!vba_project->name) {
 
1634
                        free(vba_project);
 
1635
                        vba_project = NULL;
 
1636
                        goto abort;
 
1637
                }
 
1638
                vba_project->dir = cli_strdup(dir);
 
1639
                vba_project->offset = (uint32_t *) cli_malloc(sizeof(uint32_t) *
 
1640
                                        macro_info->count);
 
1641
                if (!vba_project->offset) {
 
1642
                        free(vba_project->name);
 
1643
                        free(vba_project->dir);
 
1644
                        free(vba_project);
 
1645
                        vba_project = NULL;
 
1646
                        goto abort;
 
1647
                }
 
1648
                vba_project->length = (uint32_t *) cli_malloc(sizeof(uint32_t) *
 
1649
                                        macro_info->count);
 
1650
                if (!vba_project->length) {
 
1651
                        free(vba_project->offset);
 
1652
                        free(vba_project->name);
 
1653
                        free(vba_project->dir);
 
1654
                        free(vba_project);
 
1655
                        vba_project = NULL;
 
1656
                        goto abort;
 
1657
                }
 
1658
                vba_project->key = (unsigned char *) cli_malloc(sizeof(unsigned char) *
 
1659
                                        macro_info->count);
 
1660
                if (!vba_project->key) {
 
1661
                        free(vba_project->length);
 
1662
                        free(vba_project->offset);
 
1663
                        free(vba_project->name);
 
1664
                        free(vba_project->dir);
 
1665
                        free(vba_project);
 
1666
                        vba_project = NULL;
 
1667
                        goto abort;
 
1668
                }
 
1669
                vba_project->count = macro_info->count;
 
1670
                for (i=0 ; i < macro_info->count ; i++) {
 
1671
                        vba_project->name[i] = cli_strdup("WordDocument");
 
1672
                        vba_project->offset[i] = macro_info->macro_entry[i].offset;
 
1673
                        vba_project->length[i] = macro_info->macro_entry[i].len;
 
1674
                        vba_project->key[i] = macro_info->macro_entry[i].key;
 
1675
                }
 
1676
        }
 
1677
        /* Fall through */
 
1678
abort:
 
1679
        if (macro_info) {
 
1680
                wm_free_macro_info(macro_info);
 
1681
        }
 
1682
        if (menu_info) {
 
1683
                wm_free_menu_info(menu_info);
 
1684
        }
 
1685
        if (macro_extnames) {
 
1686
                wm_free_extnames(macro_extnames);
 
1687
        }
 
1688
        if (macro_intnames) {
 
1689
                wm_free_intnames(macro_intnames);
 
1690
        }
 
1691
        close(fd);
1138
1692
        return vba_project;
1139
1693
}
1140
1694
 
1141
 
unsigned char *
1142
 
cli_wm_decrypt_macro(int fd, off_t offset, uint32_t len, unsigned char key)
 
1695
unsigned char *wm_decrypt_macro(int fd, uint32_t offset, uint32_t len,
 
1696
                                        unsigned char key)
1143
1697
{
1144
1698
        unsigned char *buff;
1145
 
 
1146
 
        if(len == 0)
1147
 
                return NULL;
1148
 
 
1149
 
        if(fd < 0)
1150
 
                return NULL;
1151
 
 
1152
 
        buff = (unsigned char *)cli_malloc(len);
1153
 
        if(buff == NULL)
1154
 
                return NULL;
1155
 
 
1156
 
        if(!seekandread(fd, offset, SEEK_SET, buff, len)) {
 
1699
        uint32_t i;
 
1700
        
 
1701
        if (lseek(fd, offset, SEEK_SET) != (int64_t)offset) {
 
1702
                return NULL;
 
1703
        }
 
1704
        buff = (unsigned char *) cli_malloc(len);
 
1705
        if (!buff) {
 
1706
                return NULL;
 
1707
        }
 
1708
 
 
1709
        if (cli_readn(fd, buff, len) != (int64_t)len) {
1157
1710
                free(buff);
1158
1711
                return NULL;
1159
1712
        }
1160
 
        if(key) {
1161
 
                unsigned char *p;
1162
 
 
1163
 
                for(p = buff; p < &buff[len]; p++)
1164
 
                        *p ^= key;
 
1713
        if (key != 0) {
 
1714
                for (i=0 ; i < len; i++) {
 
1715
                        buff[i] = buff[i] ^ key;
 
1716
                }
1165
1717
        }
1166
1718
        return buff;
1167
1719
}
1168
 
 
1169
 
/*
1170
 
 * Keep reading bytes until we reach a NUL. Returns 0 if none is found
1171
 
 */
1172
 
static int
1173
 
skip_past_nul(int fd)
1174
 
{
1175
 
    char *end;
1176
 
    char smallbuf[128];
1177
 
 
1178
 
    do {
1179
 
        int nread = cli_readn(fd, smallbuf, sizeof(smallbuf));
1180
 
        if (nread <= 0)
1181
 
            return FALSE;
1182
 
        end = memchr(smallbuf, '\0', nread);
1183
 
        if (end) {
1184
 
            if (lseek(fd, 1 + (end-smallbuf) - nread, SEEK_CUR) < 0)
1185
 
                return FALSE;
1186
 
            return TRUE;
1187
 
        }
1188
 
    } while (1);
1189
 
}
1190
 
 
1191
 
/*
1192
 
 * Read 2 bytes as a 16-bit number, host byte order. Return success or fail
1193
 
 */
1194
 
static int
1195
 
read_uint16(int fd, uint16_t *u, int big_endian)
1196
 
{
1197
 
        if(cli_readn(fd, u, sizeof(uint16_t)) != sizeof(uint16_t))
1198
 
                return FALSE;
1199
 
 
1200
 
        *u = vba_endian_convert_16(*u, big_endian);
1201
 
 
1202
 
        return TRUE;
1203
 
}
1204
 
 
1205
 
/*
1206
 
 * Read 4 bytes as a 32-bit number, host byte order. Return success or fail
1207
 
 */
1208
 
static int
1209
 
read_uint32(int fd, uint32_t *u, int big_endian)
1210
 
{
1211
 
        if(cli_readn(fd, u, sizeof(uint32_t)) != sizeof(uint32_t))
1212
 
                return FALSE;
1213
 
 
1214
 
        *u = vba_endian_convert_32(*u, big_endian);
1215
 
 
1216
 
        return TRUE;
1217
 
}
1218
 
 
1219
 
/*
1220
 
 * Miss some bytes then read a bit
1221
 
 */
1222
 
static int
1223
 
seekandread(int fd, off_t offset, int whence, void *data, size_t len)
1224
 
{
1225
 
        if(lseek(fd, offset, whence) == (off_t)-1) {
1226
 
                cli_dbgmsg("lseek failed\n");
1227
 
                return FALSE;
1228
 
        }
1229
 
        return cli_readn(fd, data, (unsigned int)len) == (int)len;
1230
 
}
1231
 
 
1232
 
/*
1233
 
 * Create and initialise a vba_project structure
1234
 
 */
1235
 
static vba_project_t *
1236
 
create_vba_project(int record_count, const char *dir, struct uniq *U)
1237
 
{
1238
 
        vba_project_t *ret;
1239
 
 
1240
 
        ret = (vba_project_t *) cli_malloc(sizeof(struct vba_project_tag));
1241
 
 
1242
 
        if(ret == NULL)
1243
 
                return NULL;
1244
 
 
1245
 
        ret->name = (char **)cli_malloc(sizeof(char *) * record_count);
1246
 
        ret->colls = (uint32_t *)cli_malloc(sizeof(uint32_t) * record_count);
1247
 
        ret->dir = cli_strdup(dir);
1248
 
        ret->offset = (uint32_t *)cli_malloc (sizeof(uint32_t) * record_count);
1249
 
 
1250
 
        if((ret->name == NULL) || (ret->dir == NULL) || (ret->offset == NULL)) {
1251
 
                if(ret->dir)
1252
 
                        free(ret->dir);
1253
 
                if(ret->colls)
1254
 
                        free(ret->colls);
1255
 
                if(ret->name)
1256
 
                        free(ret->name);
1257
 
                if(ret->offset)
1258
 
                        free(ret->offset);
1259
 
                free(ret);
1260
 
                return NULL;
1261
 
        }
1262
 
        ret->count = record_count;
1263
 
        ret->U = U;
1264
 
 
1265
 
        return ret;
1266
 
}