Browse code

integrate CHM unpacker

git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@676 77e5149b-7576-45b1-b177-96237e5ba77b

Tomasz Kojm authored on 2004/07/20 10:31:25
Showing 8 changed files
... ...
@@ -1,3 +1,7 @@
1
+Tue Jul 20 03:26:38 CEST 2004 (tk)
2
+----------------------------------
3
+  * libclamav: integrate CHM decoder from Trog
4
+
1 5
 Mon Jul 19 21:24:18 CEST 2004 (tk)
2 6
 ----------------------------------
3 7
   * libclamav: pe: fix memory leak (Martin Blapp <mb*imp.ch>)
... ...
@@ -102,6 +102,8 @@ libclamav_la_SOURCES = \
102 102
 	upx.c \
103 103
 	upx.h \
104 104
 	htmlnorm.c \
105
-	htmlnorm.h
105
+	htmlnorm.h \
106
+	chmunpack.c \
107
+	chmunpack.h
106 108
 
107 109
 lib_LTLIBRARIES = libclamav.la
... ...
@@ -78,15 +78,17 @@ am_libclamav_la_OBJECTS = matcher-ac.lo matcher-bm.lo matcher.lo \
78 78
 	zzip-info.lo zzip-io.lo zzip-stat.lo zzip-zip.lo strc.lo \
79 79
 	blob.lo mbox.lo message.lo snprintf.lo strrcpy.lo table.lo \
80 80
 	text.lo ole2_extract.lo vba_extract.lo msexpand.lo pe.lo \
81
-	cabd.lo lzxd.lo mszipd.lo qtmd.lo system.lo upx.lo htmlnorm.lo
81
+	cabd.lo lzxd.lo mszipd.lo qtmd.lo system.lo upx.lo htmlnorm.lo \
82
+	chmunpack.lo
82 83
 libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS)
83 84
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
84 85
 depcomp = $(SHELL) $(top_srcdir)/depcomp
85 86
 am__depfiles_maybe = depfiles
86 87
 @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/blob.Plo ./$(DEPDIR)/cabd.Plo \
87
-@AMDEP_TRUE@	./$(DEPDIR)/cvd.Plo ./$(DEPDIR)/dsig.Plo \
88
-@AMDEP_TRUE@	./$(DEPDIR)/filetypes.Plo ./$(DEPDIR)/htmlnorm.Plo \
89
-@AMDEP_TRUE@	./$(DEPDIR)/lzxd.Plo ./$(DEPDIR)/matcher-ac.Plo \
88
+@AMDEP_TRUE@	./$(DEPDIR)/chmunpack.Plo ./$(DEPDIR)/cvd.Plo \
89
+@AMDEP_TRUE@	./$(DEPDIR)/dsig.Plo ./$(DEPDIR)/filetypes.Plo \
90
+@AMDEP_TRUE@	./$(DEPDIR)/htmlnorm.Plo ./$(DEPDIR)/lzxd.Plo \
91
+@AMDEP_TRUE@	./$(DEPDIR)/matcher-ac.Plo \
90 92
 @AMDEP_TRUE@	./$(DEPDIR)/matcher-bm.Plo ./$(DEPDIR)/matcher.Plo \
91 93
 @AMDEP_TRUE@	./$(DEPDIR)/mbox.Plo ./$(DEPDIR)/md5.Plo \
92 94
 @AMDEP_TRUE@	./$(DEPDIR)/message.Plo ./$(DEPDIR)/msexpand.Plo \
... ...
@@ -308,7 +310,9 @@ libclamav_la_SOURCES = \
308 308
 	upx.c \
309 309
 	upx.h \
310 310
 	htmlnorm.c \
311
-	htmlnorm.h
311
+	htmlnorm.h \
312
+	chmunpack.c \
313
+	chmunpack.h
312 314
 
313 315
 lib_LTLIBRARIES = libclamav.la
314 316
 all: all-am
... ...
@@ -382,6 +386,7 @@ distclean-compile:
382 382
 
383 383
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blob.Plo@am__quote@
384 384
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cabd.Plo@am__quote@
385
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chmunpack.Plo@am__quote@
385 386
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cvd.Plo@am__quote@
386 387
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsig.Plo@am__quote@
387 388
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filetypes.Plo@am__quote@
388 389
new file mode 100644
... ...
@@ -0,0 +1,1078 @@
0
+/*
1
+ *  Extract component parts of MS CHM files
2
+ *
3
+ *  Copyright (C) 2004 trog@uncon.org
4
+ *
5
+ *  This program is free software; you can redistribute it and/or modify
6
+ *  it under the terms of the GNU General Public License as published by
7
+ *  the Free Software Foundation; either version 2 of the License, or
8
+ *  (at your option) any later version.
9
+ *
10
+ *  This program is distributed in the hope that it will be useful,
11
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ *  GNU General Public License for more details.
14
+ *
15
+ *  You should have received a copy of the GNU General Public License
16
+ *  along with this program; if not, write to the Free Software
17
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
+ */
19
+ 
20
+#if HAVE_CONFIG_H
21
+#include "clamav-config.h"
22
+#endif
23
+
24
+#include <stdio.h>
25
+#include <sys/types.h>
26
+#include <sys/stat.h>
27
+#include <fcntl.h>
28
+#include <unistd.h>
29
+#include <string.h>
30
+
31
+#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK)
32
+#if HAVE_MMAP
33
+#if HAVE_SYS_MMAN_H
34
+#include <sys/mman.h>
35
+#else /* HAVE_SYS_MMAN_H */
36
+#undef HAVE_MMAP
37
+#endif /* HAVE_SYS_MMAN_H */
38
+#endif /* HAVE_MMAP */
39
+#else/* PACKED */
40
+#undef HAVE_MMAP
41
+#endif
42
+
43
+#include "others.h"
44
+#include "mspack/mspack.h"
45
+#include "mspack/lzx.h"
46
+
47
+#define FALSE (0)
48
+#define TRUE (1)
49
+
50
+#ifndef HAVE_ATTRIB_PACKED
51
+#define __attribute__(x)
52
+#endif
53
+
54
+#ifdef HAVE_PRAGMA_PACK
55
+#pragma pack(1)
56
+#endif
57
+
58
+#define CHM_ITSF_MIN_LEN (0x60)
59
+typedef struct itsf_header_tag
60
+{
61
+	unsigned char signature[4] __attribute__ ((packed));
62
+	int32_t version __attribute__ ((packed));
63
+	int32_t header_len __attribute__ ((packed));
64
+	uint32_t unknown __attribute__ ((packed));
65
+	uint32_t last_modified __attribute__ ((packed));
66
+	uint32_t lang_id __attribute__ ((packed));
67
+	unsigned char dir_clsid[16] __attribute__ ((packed));
68
+	unsigned char stream_clsid[16] __attribute__ ((packed));
69
+	uint64_t sec0_offset __attribute__ ((packed));
70
+	uint64_t sec0_len __attribute__ ((packed));
71
+	uint64_t dir_offset __attribute__ ((packed));
72
+	uint64_t dir_len __attribute__ ((packed));
73
+	uint64_t data_offset __attribute__ ((packed));
74
+} itsf_header_t;
75
+
76
+#define CHM_ITSP_LEN (0x54)
77
+typedef struct itsp_header_tag
78
+{
79
+	unsigned char signature[4] __attribute__ ((packed));
80
+	int32_t version __attribute__ ((packed));
81
+	int32_t header_len __attribute__ ((packed));
82
+	int32_t unknown1 __attribute__ ((packed));
83
+	uint32_t block_len __attribute__ ((packed));
84
+	int32_t blockidx_intvl __attribute__ ((packed));
85
+	int32_t index_depth __attribute__ ((packed));
86
+	int32_t index_root __attribute__ ((packed));
87
+	int32_t index_head __attribute__ ((packed));
88
+	int32_t index_tail __attribute__ ((packed));
89
+	int32_t unknown2 __attribute__ ((packed));
90
+	uint32_t num_blocks __attribute__ ((packed));
91
+	uint32_t lang_id __attribute__ ((packed));
92
+	unsigned char system_clsid[16] __attribute__ ((packed));
93
+	unsigned char unknown4[16] __attribute__ ((packed));
94
+} itsp_header_t;
95
+
96
+#define CHM_CHUNK_HDR_LEN (0x14)
97
+typedef struct chunk_header_tag
98
+{
99
+	unsigned char signature[4] __attribute__ ((packed));
100
+	uint32_t free_space __attribute__ ((packed));
101
+	uint32_t unknown __attribute__ ((packed));
102
+	int32_t block_prev __attribute__ ((packed));
103
+	int32_t block_next __attribute__ ((packed));
104
+	unsigned char *chunk_data;
105
+	uint16_t num_entries;
106
+} chunk_header_t;
107
+
108
+typedef struct file_list_tag
109
+{
110
+	unsigned char *name;
111
+	uint64_t section;
112
+	uint64_t offset;
113
+	uint64_t length;
114
+	struct file_list_tag *next;
115
+} file_list_t;
116
+
117
+#define CHM_CONTROL_LEN (0x18)
118
+typedef struct lzx_control_tag {
119
+	uint32_t length __attribute__ ((packed));
120
+	unsigned char signature[4] __attribute__ ((packed));
121
+	uint32_t version __attribute__ ((packed));
122
+	uint32_t reset_interval __attribute__ ((packed));
123
+	uint32_t window_size __attribute__ ((packed));
124
+	uint32_t cache_size __attribute__ ((packed));
125
+} lzx_control_t;
126
+
127
+/* Don't need to include rt_offset in the strucuture len*/
128
+#define CHM_RESET_TABLE_LEN (0x24)
129
+typedef struct lzx_reset_table_tag {
130
+	uint32_t num_entries __attribute__ ((packed));
131
+	uint32_t entry_size __attribute__ ((packed));
132
+	uint32_t table_offset __attribute__ ((packed));
133
+	uint64_t uncom_len __attribute__ ((packed));
134
+	uint64_t com_len __attribute__ ((packed));
135
+	uint64_t frame_len __attribute__ ((packed));
136
+	off_t rt_offset __attribute__ ((packed));
137
+} lzx_reset_table_t;
138
+
139
+typedef struct lzx_content_tag {
140
+	uint64_t offset;
141
+	uint64_t length;
142
+} lzx_content_t;
143
+
144
+#ifdef HAVE_PRAGMA_PACK
145
+#pragma pack()
146
+#endif
147
+
148
+#if WORDS_BIGENDIAN == 0
149
+#define chm_endian_convert_16(v)	(v)
150
+#else
151
+static uint16_t chm_endian_convert_16(uint16_t v)
152
+{
153
+	return ((v >> 8) + (v << 8));
154
+}
155
+#endif
156
+
157
+#if WORDS_BIGENDIAN == 0
158
+#define chm_endian_convert_32(v)    (v)
159
+#else
160
+static uint32_t chm_endian_convert_32(uint32_t v)
161
+{
162
+        return ((v >> 24) | ((v & 0x00FF0000) >> 8) |
163
+                ((v & 0x0000FF00) << 8) | (v << 24));
164
+}
165
+#endif
166
+
167
+#if WORDS_BIGENDIAN == 0
168
+#define chm_endian_convert_64(v)    (v)
169
+#else
170
+static uint64_t chm_endian_convert_64(uint64_t v)
171
+{
172
+	return ((v >> 56) | ((v & 0x00FF000000000000) >> 40) |
173
+		((v & 0x0000FF0000000000) >> 24) |
174
+		((v & 0x000000FF00000000) >> 8) |
175
+		((v & 0x00000000FF000000) << 8) |
176
+		((v & 0x0000000000FF0000) << 24) |
177
+		((v & 0x000000000000FF00) << 40) |
178
+		(v << 56));
179
+}
180
+#endif
181
+
182
+/* Read in a block of data from either the mmap area or the given fd */
183
+int chm_read_data(int fd, unsigned char *dest, off_t offset, uint32_t len,
184
+			unsigned char *m_area, off_t m_length)
185
+{
186
+	if (m_area != NULL) {
187
+		if ((offset+len) > m_length) {
188
+			return FALSE;
189
+		}
190
+		memcpy(dest, m_area+offset, len);
191
+	} else {
192
+		if (lseek(fd, offset, SEEK_SET) != offset) {
193
+			return FALSE;
194
+		}
195
+		if (cli_readn(fd, dest, len) != len) {
196
+			return FALSE;
197
+		}
198
+	}
199
+	return TRUE;
200
+}
201
+
202
+static void free_file_list(file_list_t *file_l)
203
+{
204
+	file_list_t *next;
205
+	
206
+	while (file_l) {
207
+		next = file_l->next;
208
+		if (file_l->name) {
209
+			free(file_l->name);
210
+		}
211
+		free(file_l);
212
+		file_l = next;
213
+	}
214
+}
215
+
216
+static void itsf_print_header(itsf_header_t *itsf_hdr)
217
+{
218
+	if (!itsf_hdr) {
219
+		return;
220
+	}
221
+	
222
+	cli_dbgmsg("---- ITSF ----\n");
223
+	cli_dbgmsg("Signature:\t%c%c%c%c\n", itsf_hdr->signature[0],
224
+		itsf_hdr->signature[1],itsf_hdr->signature[2],itsf_hdr->signature[3]);
225
+	cli_dbgmsg("Version:\t%d\n", itsf_hdr->version);
226
+	cli_dbgmsg("Header len:\t%ld\n", itsf_hdr->header_len);
227
+	cli_dbgmsg("Lang ID:\t%d\n", itsf_hdr->lang_id);
228
+	cli_dbgmsg("Sec0 offset:\t%llu\n", itsf_hdr->sec0_offset);
229
+	cli_dbgmsg("Sec0 len:\t%llu\n", itsf_hdr->sec0_len);
230
+	cli_dbgmsg("Dir offset:\t%llu\n", itsf_hdr->dir_offset);
231
+	cli_dbgmsg("Dir len:\t%llu\n", itsf_hdr->dir_len);
232
+	if (itsf_hdr->version > 2) {
233
+		cli_dbgmsg("Data offset:\t%llu\n\n", itsf_hdr->data_offset);
234
+	}
235
+}
236
+
237
+static int itsf_read_header(int fd, itsf_header_t *itsf_hdr, unsigned char *m_area, off_t m_length)
238
+{
239
+#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK)
240
+	if (!chm_read_data(fd, (unsigned char *) itsf_hdr, 0, CHM_ITSF_MIN_LEN,
241
+				m_area,	m_length)) {
242
+		return FALSE;
243
+	}
244
+#else
245
+	if (cli_readn(fd, &itsf_hdr->signature, 4) != 4) {
246
+		return FALSE;
247
+	}
248
+	if (cli_readn(fd, &itsf_hdr->version, 4) != 4) {
249
+		return FALSE;
250
+	}
251
+	if (cli_readn(fd, &itsf_hdr->header_len, 4) != 4) {
252
+		return FALSE;
253
+	}
254
+	if (cli_readn(fd, &itsf_hdr->unknown, 4) != 4) {
255
+		return FALSE;
256
+	}
257
+	if (cli_readn(fd, &itsf_hdr->last_modified, 4) != 4) {
258
+		return FALSE;
259
+	}
260
+	if (cli_readn(fd, &itsf_hdr->lang_id, 4) != 4) {
261
+		return FALSE;
262
+	}
263
+	if (cli_readn(fd, &itsf_hdr->dir_clsid, 16) != 16) {
264
+		return FALSE;
265
+	}
266
+	if (cli_readn(fd, &itsf_hdr->stream_clsid, 16) != 16) {
267
+		return FALSE;
268
+	}
269
+	if (cli_readn(fd, &itsf_hdr->sec0_offset, 8) != 8) {
270
+		return FALSE;
271
+	}
272
+	if (cli_readn(fd, &itsf_hdr->sec0_len, 8) != 8) {
273
+		return FALSE;
274
+	}
275
+	if (cli_readn(fd, &itsf_hdr->dir_offset, 8) != 8) {
276
+		return FALSE;
277
+	}
278
+	if (cli_readn(fd, &itsf_hdr->dir_len, 8) != 8) {
279
+		return FALSE;
280
+	}
281
+	if (itsf_hdr->version > 2) {
282
+		if (cli_readn(fd, &itsf_hdr->data_offset, 8) != 8) {
283
+			return FALSE;
284
+		}
285
+	}
286
+#endif
287
+	if (memcmp(itsf_hdr->signature, "ITSF", 4) != 0) {
288
+		cli_dbgmsg("ITSF signature mismatch\n");
289
+		return FALSE;
290
+	}
291
+	itsf_hdr->version = chm_endian_convert_32(itsf_hdr->version);
292
+	itsf_hdr->header_len = chm_endian_convert_32(itsf_hdr->header_len);
293
+	itsf_hdr->last_modified = chm_endian_convert_32(itsf_hdr->last_modified);
294
+	itsf_hdr->lang_id = chm_endian_convert_32(itsf_hdr->lang_id);
295
+	itsf_hdr->sec0_offset = chm_endian_convert_64(itsf_hdr->sec0_offset);
296
+	itsf_hdr->sec0_len = chm_endian_convert_64(itsf_hdr->sec0_len);
297
+	itsf_hdr->dir_offset = chm_endian_convert_64(itsf_hdr->dir_offset);
298
+	itsf_hdr->dir_len = chm_endian_convert_64(itsf_hdr->dir_len);
299
+	if (itsf_hdr->version > 2) {
300
+		itsf_hdr->data_offset = chm_endian_convert_64(itsf_hdr->data_offset);
301
+	}
302
+	return TRUE;
303
+}
304
+
305
+static void itsp_print_header(itsp_header_t *itsp_hdr)
306
+{
307
+	if (!itsp_hdr) {
308
+		return;
309
+	}
310
+	
311
+	cli_dbgmsg("---- ITSP ----\n");
312
+	cli_dbgmsg("Signature:\t%c%c%c%c\n", itsp_hdr->signature[0],
313
+		itsp_hdr->signature[1],itsp_hdr->signature[2],itsp_hdr->signature[3]);
314
+	cli_dbgmsg("Version:\t%d\n", itsp_hdr->version);
315
+	cli_dbgmsg("Block len:\t%ld\n", itsp_hdr->block_len);
316
+	cli_dbgmsg("Block idx int:\t%d\n", itsp_hdr->blockidx_intvl);
317
+	cli_dbgmsg("Index depth:\t%d\n", itsp_hdr->index_depth);
318
+	cli_dbgmsg("Index root:\t%d\n", itsp_hdr->index_root);
319
+	cli_dbgmsg("Index head:\t%u\n", itsp_hdr->index_head);
320
+	cli_dbgmsg("Index tail:\t%u\n", itsp_hdr->index_tail);
321
+	cli_dbgmsg("Num Blocks:\t%u\n", itsp_hdr->num_blocks);
322
+	cli_dbgmsg("Lang ID:\t%lu\n\n", itsp_hdr->lang_id);
323
+}
324
+
325
+static int itsp_read_header(int fd, itsp_header_t *itsp_hdr, off_t offset,
326
+				unsigned char *m_area, off_t m_length)
327
+{
328
+#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK)
329
+	if (!chm_read_data(fd, (unsigned char *) itsp_hdr, offset, CHM_ITSP_LEN,
330
+				m_area,	m_length)) {
331
+		return FALSE;
332
+	}
333
+#else
334
+	if (lseek(fd, offset, SEEK_SET) != offset) {
335
+		return FALSE;
336
+	}
337
+	if (cli_readn(fd, &itsp_hdr->signature, 4) != 4) {
338
+		return FALSE;
339
+	}
340
+	if (cli_readn(fd, &itsp_hdr->version, 4) != 4) {
341
+		return FALSE;
342
+	}
343
+	if (cli_readn(fd, &itsp_hdr->header_len, 4) != 4) {
344
+		return FALSE;
345
+	}
346
+	if (cli_readn(fd, &itsp_hdr->unknown1, 4) != 4) {
347
+		return FALSE;
348
+	}
349
+	if (cli_readn(fd, &itsp_hdr->block_len, 4) != 4) {
350
+		return FALSE;
351
+	}
352
+	if (cli_readn(fd, &itsp_hdr->blockidx_intvl, 4) != 4) {
353
+		return FALSE;
354
+	}
355
+	if (cli_readn(fd, &itsp_hdr->index_depth, 4) != 4) {
356
+		return FALSE;
357
+	}
358
+	if (cli_readn(fd, &itsp_hdr->index_root, 4) != 4) {
359
+		return FALSE;
360
+	}
361
+	if (cli_readn(fd, &itsp_hdr->index_head, 4) != 4) {
362
+		return FALSE;
363
+	}
364
+	if (cli_readn(fd, &itsp_hdr->index_tail, 4) != 4) {
365
+		return FALSE;
366
+	}
367
+	if (cli_readn(fd, &itsp_hdr->unknown2, 4) != 4) {
368
+		return FALSE;
369
+	}
370
+	if (cli_readn(fd, &itsp_hdr->num_blocks, 4) != 4) {
371
+		return FALSE;
372
+	}
373
+	if (cli_readn(fd, &itsp_hdr->lang_id, 4) != 4) {
374
+		return FALSE;
375
+	}
376
+	if (cli_readn(fd, &itsp_hdr->system_clsid, 16) != 16) {
377
+		return FALSE;
378
+	}
379
+	if (cli_readn(fd, &itsp_hdr->unknown4, 16) != 16) {
380
+		return FALSE;
381
+	}
382
+#endif
383
+	if (memcmp(itsp_hdr->signature, "ITSP", 4) != 0) {
384
+		cli_dbgmsg("ITSP signature mismatch\n");
385
+		return FALSE;
386
+	}
387
+	
388
+	itsp_hdr->version = chm_endian_convert_32(itsp_hdr->version);
389
+	itsp_hdr->header_len = chm_endian_convert_32(itsp_hdr->header_len);
390
+	itsp_hdr->block_len = chm_endian_convert_32(itsp_hdr->block_len);
391
+	itsp_hdr->blockidx_intvl = chm_endian_convert_32(itsp_hdr->blockidx_intvl);
392
+	itsp_hdr->index_depth = chm_endian_convert_32(itsp_hdr->index_depth);
393
+	itsp_hdr->index_root = chm_endian_convert_32(itsp_hdr->index_root);
394
+	itsp_hdr->index_head = chm_endian_convert_32(itsp_hdr->index_head);
395
+	itsp_hdr->index_tail = chm_endian_convert_32(itsp_hdr->index_tail);
396
+	itsp_hdr->num_blocks = chm_endian_convert_32(itsp_hdr->num_blocks);
397
+	itsp_hdr->lang_id = chm_endian_convert_32(itsp_hdr->lang_id);
398
+	
399
+	if ((itsp_hdr->version != 1) || (itsp_hdr->header_len != CHM_ITSP_LEN)) {
400
+		cli_dbgmsg("ITSP header mismatch\n");
401
+		return FALSE;
402
+	}
403
+	return TRUE;
404
+}
405
+
406
+static uint64_t read_enc_int(unsigned char **start, unsigned char *end)
407
+{
408
+	uint64_t retval=0;
409
+	unsigned char *current;
410
+	
411
+	current = *start;
412
+	
413
+	if (current > end) {
414
+		return -1;
415
+	}
416
+	
417
+	do {
418
+		if (current > end) {
419
+			return -1;
420
+		}
421
+		retval = (retval << 7) | (*current & 0x7f);
422
+	} while (*current++ & 0x80);
423
+	
424
+	*start = current;
425
+	return retval;
426
+}
427
+
428
+/* Read chunk entries */
429
+/* Note: the file lists end up in reverse order to the order in the chunk */
430
+static int read_chunk_entries(unsigned char *chunk, uint32_t chunk_len,
431
+					uint16_t num_entries,
432
+					file_list_t *file_l, file_list_t *sys_file_l)
433
+{
434
+	unsigned char *current, *end;
435
+	uint64_t length, offset, section, name_len;
436
+	file_list_t *file_e;
437
+
438
+	end = chunk + chunk_len;
439
+	current = chunk + CHM_CHUNK_HDR_LEN;
440
+	
441
+	while (num_entries--) {
442
+		if (current > end) {
443
+			cli_dbgmsg("read chunk entries failed\n");
444
+			return FALSE;
445
+		}
446
+
447
+		file_e = (file_list_t *) cli_malloc(sizeof(file_list_t));
448
+		if (!file_e) {
449
+			return FALSE;
450
+		}
451
+		file_e->next = NULL;
452
+		
453
+		if ((name_len = read_enc_int(&current, end)) < 0) return FALSE;
454
+		file_e->name = (unsigned char *) cli_malloc(name_len+1);
455
+		if (!file_e->name) {
456
+			free(file_e);
457
+			return FALSE;
458
+		}
459
+		strncpy(file_e->name, current, name_len);
460
+		file_e->name[name_len] = '\0';
461
+		current += name_len;
462
+		if ((file_e->section = read_enc_int(&current, end)) < 0) {
463
+			free(file_e->name);
464
+			free(file_e);
465
+			return FALSE;
466
+		}
467
+		if ((file_e->offset = read_enc_int(&current, end)) < 0) {
468
+			free(file_e->name);
469
+			free(file_e);
470
+			return FALSE;
471
+		}
472
+		if ((file_e->length = read_enc_int(&current, end)) < 0) {
473
+			free(file_e->name);
474
+			free(file_e);
475
+			return FALSE;
476
+		}
477
+		if ((name_len >= 2) && (file_e->name[0] == ':') &&
478
+				(file_e->name[1] == ':')) {
479
+			file_e->next = sys_file_l->next;
480
+			sys_file_l->next = file_e;
481
+		} else {
482
+			file_e->next = file_l->next;
483
+			file_l->next = file_e;
484
+		}
485
+		cli_dbgmsg("Section: %llu Offset: %llu Length: %llu, Name: %s\n",
486
+					file_e->section, file_e->offset,
487
+					file_e->length, file_e->name);
488
+	}
489
+}
490
+
491
+static void print_chunk(chunk_header_t *chunk)
492
+{
493
+
494
+	cli_dbgmsg("---- Chunk ----\n");
495
+	cli_dbgmsg("Signature:\t%c%c%c%c\n", chunk->signature[0],
496
+		chunk->signature[1],chunk->signature[2],chunk->signature[3]);
497
+	cli_dbgmsg("Free Space:\t%u\n", chunk->free_space);
498
+	if (memcmp(chunk->signature, "PMGL", 4) == 0) {
499
+		cli_dbgmsg("Prev Block:\t%d\n", chunk->block_prev);
500
+		cli_dbgmsg("Next Block:\t%d\n", chunk->block_next);
501
+		cli_dbgmsg("Num entries:\t%d\n\n", chunk->num_entries);
502
+	}
503
+	return;
504
+}
505
+
506
+static int read_chunk(int fd, off_t offset, uint32_t chunk_len,
507
+					unsigned char *m_area, off_t m_length,
508
+					file_list_t *file_l, file_list_t *sys_file_l)
509
+{
510
+	chunk_header_t *chunk_hdr;
511
+	int retval = FALSE;
512
+	
513
+	if (chunk_len < 8) {
514
+		return FALSE;
515
+	}
516
+	
517
+	chunk_hdr = (chunk_header_t *) cli_malloc(sizeof(chunk_header_t));
518
+	if (!chunk_hdr) {
519
+		return FALSE;
520
+	}
521
+	
522
+	chunk_hdr->chunk_data = (unsigned char *) cli_malloc(chunk_len);
523
+	if (!chunk_hdr->chunk_data) {
524
+		free(chunk_hdr);
525
+		return FALSE;
526
+	}
527
+	
528
+#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK)
529
+	/* 8 bytes reads the signature and the free_space */
530
+	if (!chm_read_data(fd, chunk_hdr->signature, offset, 8,
531
+				m_area,	m_length)) {
532
+		goto abort;
533
+	}
534
+	if (!chm_read_data(fd, chunk_hdr->chunk_data, offset, chunk_len,
535
+				m_area,	m_length)) {
536
+		goto abort;
537
+	}
538
+#else	
539
+	if (lseek(fd, offset, SEEK_SET) != offset) {
540
+		goto abort;
541
+	}
542
+	if (cli_readn(fd, chunk_hdr->chunk_data, chunk_len) != chunk_len) {
543
+		goto abort;
544
+	}
545
+	if (lseek(fd, offset, SEEK_SET) != offset) {
546
+		goto abort;
547
+	}
548
+	if (cli_readn(fd, &chunk_hdr->signature, 4) != 4) {
549
+		goto abort;
550
+	}
551
+	if (cli_readn(fd, &chunk_hdr->free_space, 4) != 4) {
552
+		goto abort;
553
+	}
554
+#endif
555
+	chunk_hdr->free_space = chm_endian_convert_32(chunk_hdr->free_space);
556
+	
557
+	if (memcmp(chunk_hdr->signature, "PMGL", 4) == 0) {
558
+#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK)
559
+		if (!chm_read_data(fd, (unsigned char *) &chunk_hdr->unknown, offset+8, 12,
560
+					m_area,	m_length)) {
561
+			goto abort;
562
+		}
563
+#else
564
+		if (cli_readn(fd, &chunk_hdr->unknown, 4) != 4) {
565
+			goto abort;
566
+		}
567
+		if (cli_readn(fd, &chunk_hdr->block_next, 4) != 4) {
568
+			goto abort;
569
+		}
570
+		if (cli_readn(fd, &chunk_hdr->block_prev, 4) != 4) {
571
+			goto abort;
572
+		}
573
+#endif
574
+		chunk_hdr->block_next = chm_endian_convert_32(chunk_hdr->block_next);
575
+		chunk_hdr->block_prev = chm_endian_convert_32(chunk_hdr->block_prev);
576
+		
577
+		chunk_hdr->num_entries = (uint16_t)((((uint8_t const *)(chunk_hdr->chunk_data))[chunk_len-2] << 0)
578
+					| (((uint8_t const *)(chunk_hdr->chunk_data))[chunk_len-1] << 8));
579
+		/*chunk_hdr->num_entries = chm_endian_convert_32(chunk_hdr->num_entries);*/
580
+	} else if (memcmp(chunk_hdr->signature, "PMGI", 4) != 0) {
581
+		goto abort;
582
+	}
583
+	read_chunk_entries(chunk_hdr->chunk_data, chunk_len,
584
+			chunk_hdr->num_entries, file_l, sys_file_l);
585
+			
586
+	print_chunk(chunk_hdr);
587
+	retval=TRUE;
588
+abort:
589
+	free(chunk_hdr->chunk_data);
590
+	free(chunk_hdr);
591
+	return retval;
592
+}
593
+
594
+static void print_sys_control(lzx_control_t *lzx_control)
595
+{
596
+	if (!lzx_control) {
597
+		return;
598
+	}
599
+
600
+	cli_dbgmsg("---- Control ----\n");	
601
+	cli_dbgmsg("Length:\t\t%lu\n", lzx_control->length);
602
+	cli_dbgmsg("Signature:\t%c%c%c%c\n", lzx_control->signature[0],
603
+		lzx_control->signature[1],lzx_control->signature[2],lzx_control->signature[3]);
604
+	cli_dbgmsg("Version:\t%d\n", lzx_control->version);
605
+	cli_dbgmsg("Reset Interval:\t%d\n", lzx_control->reset_interval);
606
+	cli_dbgmsg("Window Size:\t%d\n", lzx_control->window_size);
607
+	cli_dbgmsg("Cache Size:\t%d\n\n", lzx_control->cache_size);
608
+}
609
+
610
+static lzx_control_t *read_sys_control(int fd, itsf_header_t *itsf_hdr, file_list_t *file_e,
611
+					unsigned char *m_area, off_t m_length)
612
+{
613
+	off_t offset;
614
+	lzx_control_t *lzx_control;
615
+	
616
+	if (file_e->length != 28) {
617
+		return NULL;
618
+	}
619
+	offset = itsf_hdr->data_offset + file_e->offset;
620
+	if ((offset < 0) || (offset < itsf_hdr->sec0_offset)) {
621
+		return NULL;
622
+	}
623
+
624
+	lzx_control = (lzx_control_t *) cli_malloc(sizeof(lzx_control_t));
625
+	if (!lzx_control) {
626
+		return NULL;
627
+	}
628
+#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK)
629
+	if (!chm_read_data(fd, (unsigned char *) lzx_control, offset, CHM_CONTROL_LEN,
630
+				m_area,	m_length)) {
631
+		goto abort;
632
+	}
633
+#else
634
+	if (lseek(fd, offset, SEEK_SET) != offset) {
635
+		goto abort;
636
+	}
637
+	if (cli_readn(fd, &lzx_control->length, 4) != 4) {
638
+		goto abort;
639
+	}
640
+	if (cli_readn(fd, &lzx_control->signature, 4) != 4) {
641
+		goto abort;
642
+	}
643
+	if (cli_readn(fd, &lzx_control->version, 4) != 4) {
644
+		goto abort;
645
+	}
646
+	if (cli_readn(fd, &lzx_control->reset_interval, 4) != 4) {
647
+		goto abort;
648
+	}
649
+	if (cli_readn(fd, &lzx_control->window_size, 4) != 4) {
650
+		goto abort;
651
+	}
652
+	if (cli_readn(fd, &lzx_control->cache_size, 4) != 4) {
653
+		goto abort;
654
+	}
655
+#endif
656
+	lzx_control->length = chm_endian_convert_32(lzx_control->length);
657
+	lzx_control->version = chm_endian_convert_32(lzx_control->version);
658
+	lzx_control->reset_interval = chm_endian_convert_32(lzx_control->reset_interval);
659
+	lzx_control->window_size = chm_endian_convert_32(lzx_control->window_size);
660
+	lzx_control->cache_size = chm_endian_convert_32(lzx_control->cache_size);
661
+	
662
+	if (strncmp("LZXC", lzx_control->signature, 4) != 0) {
663
+		cli_dbgmsg("bad sys_control signature");
664
+		goto abort;
665
+	}
666
+	switch(lzx_control->version) {
667
+		case 1:
668
+			break;
669
+		case 2:
670
+			lzx_control->reset_interval *= LZX_FRAME_SIZE;
671
+			lzx_control->window_size *= LZX_FRAME_SIZE;
672
+			break;
673
+		default:
674
+			cli_dbgmsg("Unknown sys_control version:%d\n", lzx_control->version);
675
+			goto abort;
676
+	}
677
+			
678
+	print_sys_control(lzx_control);
679
+	return lzx_control;
680
+abort:
681
+	free(lzx_control);
682
+	return NULL;
683
+}
684
+
685
+static void print_sys_content(lzx_content_t *lzx_content)
686
+{
687
+	if (!lzx_content) {
688
+		return;
689
+	}
690
+	
691
+	cli_dbgmsg("---- Content ----\n");
692
+	cli_dbgmsg("Offset:\t%llu\n", lzx_content->offset);
693
+	cli_dbgmsg("Length:\t%llu\n\n", lzx_content->length);
694
+}
695
+
696
+static lzx_content_t *read_sys_content(int fd, itsf_header_t *itsf_hdr, file_list_t *file_e)
697
+{
698
+	lzx_content_t *lzx_content;
699
+	
700
+	lzx_content = (lzx_content_t *) cli_malloc(sizeof(lzx_content_t));
701
+	if (!lzx_content) {
702
+		return NULL;
703
+	}
704
+	lzx_content->offset = itsf_hdr->data_offset + file_e->offset;
705
+	lzx_content->length = file_e->length;
706
+	
707
+	print_sys_content(lzx_content);
708
+	return lzx_content;
709
+}
710
+
711
+static void print_sys_reset_table(lzx_reset_table_t *lzx_reset_table)
712
+{
713
+	if (!lzx_reset_table) {
714
+		return;
715
+	}
716
+	
717
+	cli_dbgmsg("---- Reset Table ----\n");
718
+	cli_dbgmsg("Num Entries:\t%lu\n", lzx_reset_table->num_entries);
719
+	cli_dbgmsg("Entry Size:\t%lu\n", lzx_reset_table->entry_size);
720
+	cli_dbgmsg("Table Offset:\t%lu\n", lzx_reset_table->table_offset);
721
+	cli_dbgmsg("Uncom Len:\t%llu\n", lzx_reset_table->uncom_len);
722
+	cli_dbgmsg("Com Len:\t%llu\n", lzx_reset_table->com_len);
723
+	cli_dbgmsg("Frame Len:\t%llu\n\n", lzx_reset_table->frame_len);
724
+}
725
+
726
+static lzx_reset_table_t *read_sys_reset_table(int fd, itsf_header_t *itsf_hdr, file_list_t *file_e,
727
+						unsigned char *m_area, off_t m_length)
728
+{
729
+	off_t offset;
730
+	lzx_reset_table_t *lzx_reset_table;
731
+
732
+	if (file_e->length < 40) {
733
+		return NULL;
734
+	}
735
+	/* Skip past unknown entry in offset calc */
736
+	offset = itsf_hdr->data_offset + file_e->offset + 4;
737
+	
738
+	if ((offset < 0) || (offset < itsf_hdr->sec0_offset)) {
739
+		return NULL;
740
+	}
741
+
742
+	lzx_reset_table = (lzx_reset_table_t *) cli_malloc(sizeof(lzx_reset_table_t));
743
+	if (!lzx_reset_table) {
744
+		return NULL;
745
+	}
746
+	
747
+	/* Save the entry offset for later use */
748
+	lzx_reset_table->rt_offset = offset-4;
749
+
750
+#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK)
751
+	if (!chm_read_data(fd, (unsigned char *) lzx_reset_table, offset, CHM_RESET_TABLE_LEN,
752
+				m_area,	m_length)) {
753
+		goto abort;
754
+	}
755
+#else	
756
+	if (lseek(fd, offset, SEEK_SET) != offset) {
757
+		goto abort;
758
+	}
759
+	if (cli_readn(fd, &lzx_reset_table->num_entries, 4) != 4) {
760
+		goto abort;
761
+	}
762
+	if (cli_readn(fd, &lzx_reset_table->entry_size, 4) != 4) {
763
+		goto abort;
764
+	}
765
+	if (cli_readn(fd, &lzx_reset_table->table_offset, 4) != 4) {
766
+		goto abort;
767
+	}
768
+	if (cli_readn(fd, &lzx_reset_table->uncom_len, 8) != 8) {
769
+		goto abort;
770
+	}
771
+	if (cli_readn(fd, &lzx_reset_table->com_len, 8) != 8) {
772
+		goto abort;
773
+	}
774
+	if (cli_readn(fd, &lzx_reset_table->frame_len, 8) != 8) {
775
+		goto abort;
776
+	}
777
+#endif
778
+	lzx_reset_table->num_entries = chm_endian_convert_32(lzx_reset_table->num_entries);
779
+	lzx_reset_table->entry_size = chm_endian_convert_32(lzx_reset_table->entry_size);
780
+	lzx_reset_table->table_offset = chm_endian_convert_32(lzx_reset_table->table_offset);
781
+	lzx_reset_table->uncom_len = chm_endian_convert_64(lzx_reset_table->uncom_len);
782
+	lzx_reset_table->com_len = chm_endian_convert_64(lzx_reset_table->com_len);
783
+	lzx_reset_table->frame_len = chm_endian_convert_64(lzx_reset_table->frame_len);
784
+
785
+	if (lzx_reset_table->frame_len != LZX_FRAME_SIZE) {
786
+		cli_dbgmsg("bad sys_reset_table frame_len: 0x%x\n",lzx_reset_table->frame_len);
787
+		goto abort;
788
+	}
789
+	if ((lzx_reset_table->entry_size != 4) && (lzx_reset_table->entry_size != 8)) {
790
+		cli_dbgmsg("bad sys_reset_table entry_size: 0x%x\n",lzx_reset_table->entry_size);
791
+		goto abort;
792
+	}
793
+	print_sys_reset_table(lzx_reset_table);
794
+	return lzx_reset_table;
795
+abort:
796
+	free(lzx_reset_table);
797
+	return NULL;
798
+}
799
+
800
+/* ******************************************************************
801
+/* This section interfaces to the mspack files. As such, this is a */
802
+/* little bit dirty compared to my usual code */
803
+
804
+#define CHM_SYS_CONTROL_NAME "::DataSpace/Storage/MSCompressed/ControlData"
805
+#define CHM_SYS_CONTENT_NAME "::DataSpace/Storage/MSCompressed/Content"
806
+#define CHM_SYS_RESETTABLE_NAME "::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable"
807
+
808
+struct mspack_file_p {
809
+  FILE *fh;
810
+  char *name;
811
+  int desc;
812
+};
813
+
814
+extern struct mspack_system *mspack_default_system;
815
+
816
+static int chm_decompress_stream(int fd, const char *dirname, itsf_header_t *itsf_hdr,
817
+				file_list_t *file_l, file_list_t *sys_file_l,
818
+				unsigned char *m_area, off_t m_length)
819
+{
820
+	file_list_t *entry;
821
+	lzx_content_t *lzx_content=NULL;
822
+	lzx_reset_table_t *lzx_reset_table=NULL;
823
+	lzx_control_t *lzx_control=NULL;
824
+	int window_bits, length, ofd, retval=FALSE;
825
+	uint64_t offset, com_offset;
826
+	struct mspack_file_p mf_in, mf_out;
827
+	struct lzxd_stream * stream;
828
+	unsigned char *data, filename[1024];
829
+	
830
+	mf_in.fh = fdopen(fd, "r");
831
+	if (!mf_in.fh) {
832
+		return FALSE;
833
+	}
834
+	mf_in.desc = fd;
835
+	mf_in.name = strdup("input");
836
+	
837
+	snprintf(filename, 1024, "%s/clamav-unchm.bin", dirname);
838
+	mf_out.desc = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
839
+	if (!mf_out.desc) {
840
+		cli_dbgmsg("open failed\n", filename);
841
+		free(mf_in.name);
842
+		fclose(mf_in.fh);
843
+		return FALSE;
844
+	}
845
+	mf_out.fh = fdopen(mf_out.desc, "w");
846
+	if (!mf_out.fh) {
847
+		cli_dbgmsg("fdopen failed\n", filename);
848
+		free(mf_in.name);
849
+		fclose(mf_in.fh);
850
+		return FALSE;
851
+	}
852
+		
853
+	mf_out.name = strdup("output");
854
+	
855
+	entry = sys_file_l->next;
856
+	while (entry) {
857
+		if (strcmp(entry->name, CHM_SYS_CONTROL_NAME) == 0) {
858
+			lzx_control = read_sys_control(fd, itsf_hdr, entry, m_area, m_length);
859
+		} else if (strcmp(entry->name, CHM_SYS_CONTENT_NAME) == 0) {
860
+			lzx_content = read_sys_content(fd, itsf_hdr, entry);
861
+		} else if (strcmp(entry->name, CHM_SYS_RESETTABLE_NAME) == 0) {
862
+			lzx_reset_table = read_sys_reset_table(fd, itsf_hdr, entry, m_area, m_length);
863
+		}
864
+		entry = entry->next;
865
+	}
866
+	
867
+	if (!lzx_content || !lzx_reset_table || !lzx_control) {
868
+		goto abort;
869
+	}
870
+	
871
+	switch (lzx_control->window_size) {
872
+		case 0x008000:
873
+			window_bits = 15;
874
+			break;
875
+		case 0x010000:
876
+			window_bits = 16;
877
+			break;
878
+		case 0x020000:
879
+			window_bits = 17;
880
+			break;
881
+		case 0x040000:
882
+			window_bits = 18;
883
+			break;
884
+		case 0x080000:
885
+			window_bits = 19;
886
+			break;
887
+		case 0x100000:
888
+			window_bits = 20;
889
+			break;
890
+		case 0x200000:
891
+			window_bits = 21;
892
+			break;
893
+		default:
894
+			cli_dbgmsg("bad control window size: 0x%x\n", lzx_control->window_size);
895
+			goto abort;
896
+	}
897
+	
898
+	if (lzx_control->reset_interval % LZX_FRAME_SIZE) {
899
+		cli_dbgmsg("bad reset_interval: 0x%x\n", lzx_control->window_size);
900
+		goto abort;
901
+	}
902
+	
903
+	length = lzx_reset_table->uncom_len;
904
+	length += lzx_control->reset_interval;
905
+	length &= -lzx_control->reset_interval;
906
+	
907
+	com_offset = lzx_content->offset;
908
+	cli_dbgmsg("Compressed offset: %llu\n", com_offset);
909
+	
910
+	stream = lzxd_init(mspack_default_system, (struct mspack_file *) &mf_in, (struct mspack_file *) &mf_out, window_bits,
911
+			lzx_control->reset_interval / LZX_FRAME_SIZE,
912
+			4096, length);
913
+	lseek(fd, com_offset, SEEK_SET);
914
+	if (!stream) {
915
+		cli_dbgmsg("lzxd_init failed\n");
916
+		goto abort;
917
+	}
918
+	
919
+	lzxd_decompress(stream, length);
920
+	lzxd_free(stream);
921
+	
922
+	entry = file_l->next;
923
+	close(mf_out.desc);
924
+	
925
+	/* Reopen the file for reading */
926
+	mf_out.desc = open(filename, O_RDONLY);
927
+	if (mf_out.desc < 0) {
928
+		cli_dbgmsg("re-open output failed\n");
929
+		goto abort;
930
+	}
931
+	while(entry) {
932
+		if (entry->section != 1) {
933
+			entry = entry->next;
934
+			continue;
935
+		}
936
+		if (lseek(mf_out.desc, entry->offset, SEEK_SET) != entry->offset) {
937
+			cli_dbgmsg("seek in output failed\n");
938
+			entry = entry->next;
939
+			continue;
940
+		}
941
+		data = (unsigned char *) cli_malloc(entry->length);
942
+		if (!data) {
943
+			goto abort;
944
+		}
945
+		snprintf(filename, 1024, "%s/%llu.chm", dirname, entry->offset);
946
+		ofd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
947
+		if (ofd < 0) {
948
+			free(data);
949
+			entry = entry->next;
950
+			continue;
951
+		}
952
+		if ((length=cli_readn(mf_out.desc, data, entry->length)) != entry->length) {
953
+			cli_dbgmsg("read %d of %d\n", length, entry->length);
954
+		}
955
+		cli_writen(ofd, data, length);
956
+		close(ofd);
957
+		free(data);
958
+		
959
+		entry = entry->next;
960
+	}
961
+		
962
+	retval = TRUE;
963
+	
964
+abort:
965
+	if (lzx_content) {
966
+		free(lzx_content);
967
+	}
968
+	if (lzx_reset_table) {
969
+		free(lzx_reset_table);
970
+	}
971
+	if (lzx_control) {
972
+		free(lzx_control);
973
+	}
974
+	free(mf_in.name);
975
+	fclose(mf_in.fh);
976
+	free(mf_out.name);
977
+	fclose(mf_out.fh);
978
+	close(mf_out.desc);
979
+	return retval;
980
+}
981
+
982
+/* ************ End dirty section ********************/
983
+
984
+int chm_unpack(int fd, const char *dirname)
985
+{
986
+	int retval=FALSE;
987
+	unsigned char *m_area=NULL;
988
+	off_t m_length, offset;
989
+	file_list_t *file_l, *sys_file_l;
990
+	struct stat statbuf;
991
+	itsf_header_t itsf_hdr;
992
+	itsp_header_t itsp_hdr;
993
+	uint32_t num_chunks;
994
+	chunk_header_t *chunk;
995
+
996
+	/* These two lists contain the list of files and system files in
997
+	the archive. The first entry in the list is an empty entry */
998
+	
999
+        file_l = (file_list_t *) cli_malloc(sizeof(file_list_t));
1000
+	if (!file_l) {
1001
+		return FALSE;
1002
+	}
1003
+	file_l->next = NULL;
1004
+	file_l->name = NULL;
1005
+	sys_file_l = (file_list_t *) cli_malloc(sizeof(file_list_t));
1006
+	if (!sys_file_l) {
1007
+		free(file_l);
1008
+		return FALSE;
1009
+	}
1010
+	sys_file_l->next = NULL;
1011
+	sys_file_l->name = NULL;
1012
+	
1013
+#ifdef HAVE_MMAP
1014
+	if (fstat(fd, &statbuf) == 0) {
1015
+		if (statbuf.st_size < CHM_ITSF_MIN_LEN) {
1016
+			goto abort;
1017
+		}
1018
+		m_length = statbuf.st_size;
1019
+		m_area = (unsigned char *) mmap(NULL, m_length, PROT_READ, MAP_PRIVATE, fd, 0);
1020
+		if (m_area == MAP_FAILED) {
1021
+			m_area = NULL;
1022
+		}
1023
+	}
1024
+#endif
1025
+
1026
+	if (!itsf_read_header(fd, &itsf_hdr, m_area, m_length)) {
1027
+		goto abort;
1028
+	}
1029
+	itsf_print_header(&itsf_hdr);
1030
+
1031
+	if (!itsp_read_header(fd, &itsp_hdr, itsf_hdr.dir_offset, m_area, m_length)) {
1032
+		goto abort;
1033
+	}
1034
+	itsp_print_header(&itsp_hdr);
1035
+	
1036
+	offset = itsf_hdr.dir_offset+CHM_ITSP_LEN;
1037
+	
1038
+	/* TODO: need to check this first calculation,
1039
+		currently have no files of this type */
1040
+	if (itsp_hdr.index_head > 0) {
1041
+		offset += itsp_hdr.index_head * itsp_hdr.block_len;
1042
+	}
1043
+
1044
+	num_chunks = itsp_hdr.index_tail - itsp_hdr.index_head + 1;
1045
+	
1046
+	/* Versions before 3 didn't have a data_offset */
1047
+	/* TODO: need to check this calculation,
1048
+		 currently have no files of this type */
1049
+	if (itsf_hdr.version < 3) {
1050
+		itsf_hdr.data_offset = itsf_hdr.dir_offset + CHM_ITSP_LEN + (itsp_hdr.block_len*itsp_hdr.num_blocks);
1051
+	}
1052
+
1053
+	while (num_chunks) {
1054
+		if (!read_chunk(fd, offset, itsp_hdr.block_len, m_area,
1055
+					m_length, file_l, sys_file_l)) {
1056
+			goto abort;
1057
+		}
1058
+
1059
+		num_chunks--;
1060
+		offset += itsp_hdr.block_len;
1061
+	}
1062
+
1063
+	chm_decompress_stream(fd, dirname, &itsf_hdr, file_l, sys_file_l, m_area, m_length);
1064
+
1065
+	/* Signal success */
1066
+	retval = TRUE;
1067
+abort:
1068
+	free_file_list(file_l);
1069
+	free_file_list(sys_file_l);
1070
+
1071
+#ifdef HAVE_MMAP
1072
+	if (m_area) {
1073
+		munmap(m_area, m_length);
1074
+	}
1075
+#endif
1076
+	return retval;
1077
+}
0 1078
new file mode 100644
... ...
@@ -0,0 +1,26 @@
0
+/*
1
+ *  Extract component parts of MS CHM files
2
+ *
3
+ *  Copyright (C) 2004 trog@uncon.org
4
+ *
5
+ *  This program is free software; you can redistribute it and/or modify
6
+ *  it under the terms of the GNU General Public License as published by
7
+ *  the Free Software Foundation; either version 2 of the License, or
8
+ *  (at your option) any later version.
9
+ *
10
+ *  This program is distributed in the hope that it will be useful,
11
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ *  GNU General Public License for more details.
14
+ *
15
+ *  You should have received a copy of the GNU General Public License
16
+ *  along with this program; if not, write to the Free Software
17
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
+ */
19
+ 
20
+#ifndef __CHM_UNPACK_H
21
+#define __CHM_UNPACK_H
22
+ 
23
+int chm_unpack(int fd, const char *dirname);
24
+
25
+#endif
... ...
@@ -58,6 +58,7 @@ static const struct cli_magic_s cli_magic[] = {
58 58
     {0,  "BZh",				3,  "BZip",		  CL_BZFILE},
59 59
     {0,  "SZDD",			4,  "compress.exe'd",	  CL_MSCFILE},
60 60
     {0,  "MSCF",			4,  "MS CAB",		  CL_MSCABFILE},
61
+    {0,  "ITSF",			4,  "MS CHM",             CL_MSCHMFILE},
61 62
 
62 63
     /* Mail */
63 64
 
... ...
@@ -34,6 +34,7 @@ typedef enum {
34 34
     CL_MSCFILE,
35 35
     CL_OLE2FILE,
36 36
     CL_MSCABFILE,
37
+    CL_MSCHMFILE,
37 38
 
38 39
     /* bigger numbers have higher priority (in o-t-f detection) */
39 40
     CL_HTMLFILE, /* on the fly */
... ...
@@ -58,6 +58,7 @@ extern int cli_mbox(const char *dir, int desc); /* FIXME */
58 58
 #include "ole2_extract.h"
59 59
 #include "vba_extract.h"
60 60
 #include "msexpand.h"
61
+#include "chmunpack.h"
61 62
 #include "pe.h"
62 63
 #include "filetypes.h"
63 64
 #include "htmlnorm.h"
... ...
@@ -906,6 +907,39 @@ static int cli_scanole2(int desc, const char **virname, long int *scanned, const
906 906
     return ret;
907 907
 }
908 908
 
909
+static int cli_scanmschm(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, int options, int *arec, int *mrec)
910
+{
911
+	const char *tmpdir;
912
+	char *tempname;
913
+	int ret = CL_CLEAN;
914
+
915
+
916
+    cli_dbgmsg("in cli_scanmschm()\n");	
917
+
918
+    if((tmpdir = getenv("TMPDIR")) == NULL)
919
+#ifdef P_tmpdir
920
+	tmpdir = P_tmpdir;
921
+#else
922
+	tmpdir = "/tmp";
923
+#endif
924
+
925
+    tempname = cli_gentemp(tmpdir);
926
+
927
+    if(mkdir(tempname, 0700)) {
928
+	cli_dbgmsg("ScanCHM -> Can't create temporary directory %s\n", tempname);
929
+	return CL_ETMPDIR;
930
+    }
931
+
932
+    if(chm_unpack(desc, tempname))
933
+	ret = cli_scandir(tempname, virname, scanned, root, limits, options, arec, mrec);
934
+
935
+    if(!cli_leavetemps_flag)
936
+	cli_rmdirs(tempname);
937
+
938
+    free(tempname);
939
+    return ret;
940
+}
941
+
909 942
 static int cli_scanmail(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, int options, int *arec, int *mrec)
910 943
 {
911 944
 	const char *tmpdir;
... ...
@@ -983,7 +1017,6 @@ static int cli_magic_scandesc(int desc, const char **virname, long int *scanned,
983 983
     lseek(desc, 0, SEEK_SET);
984 984
 
985 985
     if(bread != MAGIC_BUFFER_SIZE) {
986
-	cli_dbgmsg("File recognition failed: bread != MAGIC_BUFFER_SIZE (%d != %d)\n", bread, MAGIC_BUFFER_SIZE);
987 986
 	/* short read: No need to do magic */
988 987
 	if((ret = cli_scandesc(desc, virname, scanned, root, 0) == CL_VIRUS))
989 988
 	    cli_dbgmsg("%s virus found in descriptor %d.\n", *virname, desc);
... ...
@@ -1032,6 +1065,11 @@ static int cli_magic_scandesc(int desc, const char **virname, long int *scanned,
1032 1032
 		ret = cli_scanmail(desc, virname, scanned, root, limits, options, arec, mrec);
1033 1033
 	    break;
1034 1034
 
1035
+	case CL_MSCHMFILE:
1036
+	    if(SCAN_ARCHIVE)
1037
+		ret = cli_scanmschm(desc, virname, scanned, root, limits, options, arec, mrec);
1038
+	    break;
1039
+
1035 1040
 	case CL_OLE2FILE:
1036 1041
 	    if(SCAN_OLE2)
1037 1042
 		ret = cli_scanole2(desc, virname, scanned, root, limits, options, arec, mrec);