git-svn: trunk@3437
Trog authored on 2007/12/19 20:00:41... | ... |
@@ -1,3 +1,8 @@ |
1 |
+Wed Dec 19 10:17:02 GMT 2007 (trog) |
|
2 |
+----------------------------------- |
|
3 |
+ * libclamav/chmunpack.[ch], scanners.c: re-structure CHM unpacker. Uses no |
|
4 |
+ dynamic memory when mmap() available. |
|
5 |
+ |
|
1 | 6 |
Tue Dec 18 19:55:13 CET 2007 (acab) |
2 | 7 |
----------------------------------- |
3 | 8 |
* libclamav/unzip.c: Fix mmap leaks in unzip |
... | ... |
@@ -65,63 +65,7 @@ |
65 | 65 |
#define O_BINARY 0 |
66 | 66 |
#endif |
67 | 67 |
|
68 |
-#define CHM_ITSF_MIN_LEN (0x60) |
|
69 |
-typedef struct itsf_header_tag |
|
70 |
-{ |
|
71 |
- unsigned char signature[4]; |
|
72 |
- int32_t version __attribute__ ((packed)); |
|
73 |
- int32_t header_len __attribute__ ((packed)); |
|
74 |
- uint32_t unknown __attribute__ ((packed)); |
|
75 |
- uint32_t last_modified __attribute__ ((packed)); |
|
76 |
- uint32_t lang_id __attribute__ ((packed)); |
|
77 |
- unsigned char dir_clsid[16]; |
|
78 |
- unsigned char stream_clsid[16]; |
|
79 |
- uint64_t sec0_offset __attribute__ ((packed)); |
|
80 |
- uint64_t sec0_len __attribute__ ((packed)); |
|
81 |
- uint64_t dir_offset __attribute__ ((packed)); |
|
82 |
- uint64_t dir_len __attribute__ ((packed)); |
|
83 |
- uint64_t data_offset __attribute__ ((packed)); |
|
84 |
-} itsf_header_t; |
|
85 |
- |
|
86 |
-#define CHM_ITSP_LEN (0x54) |
|
87 |
-typedef struct itsp_header_tag |
|
88 |
-{ |
|
89 |
- unsigned char signature[4]; |
|
90 |
- int32_t version __attribute__ ((packed)); |
|
91 |
- int32_t header_len __attribute__ ((packed)); |
|
92 |
- int32_t unknown1 __attribute__ ((packed)); |
|
93 |
- uint32_t block_len __attribute__ ((packed)); |
|
94 |
- int32_t blockidx_intvl __attribute__ ((packed)); |
|
95 |
- int32_t index_depth __attribute__ ((packed)); |
|
96 |
- int32_t index_root __attribute__ ((packed)); |
|
97 |
- int32_t index_head __attribute__ ((packed)); |
|
98 |
- int32_t index_tail __attribute__ ((packed)); |
|
99 |
- int32_t unknown2 __attribute__ ((packed)); |
|
100 |
- uint32_t num_blocks __attribute__ ((packed)); |
|
101 |
- uint32_t lang_id __attribute__ ((packed)); |
|
102 |
- unsigned char system_clsid[16]; |
|
103 |
- unsigned char unknown4[16]; |
|
104 |
-} itsp_header_t; |
|
105 |
- |
|
106 | 68 |
#define CHM_CHUNK_HDR_LEN (0x14) |
107 |
-typedef struct chunk_header_tag |
|
108 |
-{ |
|
109 |
- char signature[4]; |
|
110 |
- uint32_t free_space __attribute__ ((packed)); |
|
111 |
- uint32_t unknown __attribute__ ((packed)); |
|
112 |
- int32_t block_prev __attribute__ ((packed)); |
|
113 |
- int32_t block_next __attribute__ ((packed)); |
|
114 |
- char *chunk_data; |
|
115 |
- uint16_t num_entries; |
|
116 |
-} chunk_header_t; |
|
117 |
- |
|
118 |
-typedef struct file_list_tag |
|
119 |
-{ |
|
120 |
- uint64_t section; |
|
121 |
- uint64_t offset; |
|
122 |
- uint64_t length; |
|
123 |
- struct file_list_tag *next; |
|
124 |
-} file_list_t; |
|
125 | 69 |
|
126 | 70 |
#define CHM_CONTROL_LEN (0x18) |
127 | 71 |
typedef struct lzx_control_tag { |
... | ... |
@@ -215,18 +159,7 @@ static uint64_t chm_copy_file_data(int ifd, int ofd, uint64_t len) |
215 | 215 |
return len; |
216 | 216 |
} |
217 | 217 |
|
218 |
-static void free_file_list(file_list_t *file_l) |
|
219 |
-{ |
|
220 |
- file_list_t *next; |
|
221 |
- |
|
222 |
- while (file_l) { |
|
223 |
- next = file_l->next; |
|
224 |
- free(file_l); |
|
225 |
- file_l = next; |
|
226 |
- } |
|
227 |
-} |
|
228 |
- |
|
229 |
-static void itsf_print_header(itsf_header_t *itsf_hdr) |
|
218 |
+static void itsf_print_header(chm_itsf_header_t *itsf_hdr) |
|
230 | 219 |
{ |
231 | 220 |
if (!itsf_hdr) { |
232 | 221 |
return; |
... | ... |
@@ -247,7 +180,7 @@ static void itsf_print_header(itsf_header_t *itsf_hdr) |
247 | 247 |
} |
248 | 248 |
} |
249 | 249 |
|
250 |
-static int itsf_read_header(int fd, itsf_header_t *itsf_hdr, char *m_area, off_t m_length) |
|
250 |
+static int itsf_read_header(int fd, chm_itsf_header_t *itsf_hdr, char *m_area, off_t m_length) |
|
251 | 251 |
{ |
252 | 252 |
#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA) |
253 | 253 |
if (!chm_read_data(fd, (char *) itsf_hdr, 0, CHM_ITSF_MIN_LEN, |
... | ... |
@@ -315,7 +248,7 @@ static int itsf_read_header(int fd, itsf_header_t *itsf_hdr, char *m_area, off_t |
315 | 315 |
return TRUE; |
316 | 316 |
} |
317 | 317 |
|
318 |
-static void itsp_print_header(itsp_header_t *itsp_hdr) |
|
318 |
+static void itsp_print_header(chm_itsp_header_t *itsp_hdr) |
|
319 | 319 |
{ |
320 | 320 |
if (!itsp_hdr) { |
321 | 321 |
return; |
... | ... |
@@ -335,7 +268,7 @@ static void itsp_print_header(itsp_header_t *itsp_hdr) |
335 | 335 |
cli_dbgmsg("Lang ID:\t%u\n\n", itsp_hdr->lang_id); |
336 | 336 |
} |
337 | 337 |
|
338 |
-static int itsp_read_header(int fd, itsp_header_t *itsp_hdr, off_t offset, |
|
338 |
+static int itsp_read_header(int fd, chm_itsp_header_t *itsp_hdr, off_t offset, |
|
339 | 339 |
char *m_area, off_t m_length) |
340 | 340 |
{ |
341 | 341 |
#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA) |
... | ... |
@@ -438,167 +371,128 @@ static uint64_t read_enc_int(char **start, char *end) |
438 | 438 |
return retval; |
439 | 439 |
} |
440 | 440 |
|
441 |
-/* Read chunk entries */ |
|
442 |
-/* Note: the file lists end up in reverse order to the order in the chunk */ |
|
443 |
-static int read_chunk_entries(char *chunk, uint32_t chunk_len, |
|
444 |
- uint16_t num_entries, |
|
445 |
- file_list_t *file_l, file_list_t *sys_file_l) |
|
441 |
+/* Read control entries */ |
|
442 |
+static int read_control_entries(chm_metadata_t *metadata) |
|
446 | 443 |
{ |
447 |
- char *current, *end; |
|
448 |
- uint64_t name_len; |
|
449 |
- file_list_t *file_e; |
|
444 |
+ char *name; |
|
445 |
+ uint64_t name_len, section, offset, length; |
|
450 | 446 |
|
451 |
- end = chunk + chunk_len; |
|
452 |
- current = chunk + CHM_CHUNK_HDR_LEN; |
|
453 |
- |
|
454 |
- while (num_entries--) { |
|
455 |
- if (current > end) { |
|
447 |
+ while (metadata->chunk_entries--) { |
|
448 |
+ if (metadata->chunk_current > metadata->chunk_end) { |
|
456 | 449 |
cli_dbgmsg("read chunk entries failed\n"); |
457 | 450 |
return FALSE; |
458 | 451 |
} |
459 | 452 |
|
460 |
- name_len = read_enc_int(¤t, end); |
|
461 |
- if (((current + name_len) > end) || ((current + name_len) < chunk)) { |
|
453 |
+ name_len = read_enc_int(&metadata->chunk_current, metadata->chunk_end); |
|
454 |
+ if (((metadata->chunk_current + name_len) > metadata->chunk_end) || ((metadata->chunk_current + name_len) < metadata->chunk_data)) { |
|
462 | 455 |
cli_dbgmsg("Bad CHM name_len detected\n"); |
463 | 456 |
return FALSE; |
464 | 457 |
} |
465 |
- if ((name_len >= 2) && (current[0] == ':') && |
|
466 |
- (current[1] == ':')) { |
|
467 |
- if ((name_len == CHM_SYS_CONTROL_LEN) && (strcmp(current, CHM_SYS_CONTROL_NAME) == 0)) { |
|
468 |
- current += name_len; |
|
469 |
- sys_file_l[0].section = read_enc_int(¤t, end); |
|
470 |
- sys_file_l[0].offset = read_enc_int(¤t, end); |
|
471 |
- sys_file_l[0].length = read_enc_int(¤t, end); |
|
472 |
- } else if ((name_len == CHM_SYS_CONTENT_LEN) && (strcmp(current, CHM_SYS_CONTENT_NAME) == 0)) { |
|
473 |
- current += name_len; |
|
474 |
- sys_file_l[1].section = read_enc_int(¤t, end); |
|
475 |
- sys_file_l[1].offset = read_enc_int(¤t, end); |
|
476 |
- sys_file_l[1].length = read_enc_int(¤t, end); |
|
477 |
- } else if ((name_len == CHM_SYS_RESETTABLE_LEN) && (strcmp(current, CHM_SYS_RESETTABLE_NAME) == 0)) { |
|
478 |
- current += name_len; |
|
479 |
- sys_file_l[2].section = read_enc_int(¤t, end); |
|
480 |
- sys_file_l[2].offset = read_enc_int(¤t, end); |
|
481 |
- sys_file_l[2].length = read_enc_int(¤t, end); |
|
482 |
- } |
|
483 |
- } else { |
|
484 |
- current += name_len; |
|
485 |
- file_e = (file_list_t *) cli_malloc(sizeof(file_list_t)); |
|
486 |
- if (!file_e) { |
|
487 |
- return FALSE; |
|
458 |
+ name = metadata->chunk_current; |
|
459 |
+ metadata->chunk_current += name_len; |
|
460 |
+ section = read_enc_int(&metadata->chunk_current, metadata->chunk_end); |
|
461 |
+ offset = read_enc_int(&metadata->chunk_current, metadata->chunk_end); |
|
462 |
+ length = read_enc_int(&metadata->chunk_current, metadata->chunk_end); |
|
463 |
+ |
|
464 |
+ /* CHM_SYS_CONTENT_LEN is the shortest name we are searching for */ |
|
465 |
+ if ((name_len >= CHM_SYS_CONTENT_LEN) && (name[0] == ':') && |
|
466 |
+ (name[1] == ':')) { |
|
467 |
+ if ((name_len == CHM_SYS_CONTROL_LEN) && (strcmp(name, CHM_SYS_CONTROL_NAME) == 0)) { |
|
468 |
+ cli_dbgmsg("found CHM_SYS_CONTROL_NAME\n"); |
|
469 |
+ metadata->sys_control.offset = offset; |
|
470 |
+ metadata->sys_control.length = length; |
|
471 |
+ } else if ((name_len == CHM_SYS_CONTENT_LEN) && (strcmp(name, CHM_SYS_CONTENT_NAME) == 0)) { |
|
472 |
+ cli_dbgmsg("found CHM_SYS_CONTENT_NAME\n"); |
|
473 |
+ metadata->sys_content.offset = offset; |
|
474 |
+ metadata->sys_content.length = length; |
|
475 |
+ } else if ((name_len == CHM_SYS_RESETTABLE_LEN) && (strcmp(name, CHM_SYS_RESETTABLE_NAME) == 0)) { |
|
476 |
+ cli_dbgmsg("found CHM_SYS_RESETTABLE_NAME\n"); |
|
477 |
+ metadata->sys_reset.offset = offset; |
|
478 |
+ metadata->sys_reset.length = length; |
|
488 | 479 |
} |
489 |
- file_e->section = read_enc_int(¤t, end); |
|
490 |
- file_e->offset = read_enc_int(¤t, end); |
|
491 |
- file_e->length = read_enc_int(¤t, end); |
|
492 |
- file_e->next = file_l->next; |
|
493 |
- file_l->next = file_e; |
|
494 |
- cli_dbgmsg("Section: %llu Offset: %llu Length: %llu\n", |
|
495 |
- file_e->section, file_e->offset, |
|
496 |
- file_e->length); |
|
497 | 480 |
} |
498 | 481 |
} |
499 | 482 |
return TRUE; |
500 | 483 |
} |
501 | 484 |
|
502 |
-static void print_chunk(chunk_header_t *chunk) |
|
485 |
+static int prepare_file(int fd, chm_metadata_t *metadata) |
|
503 | 486 |
{ |
487 |
+ uint64_t name_len, section; |
|
504 | 488 |
|
505 |
- cli_dbgmsg("---- Chunk ----\n"); |
|
506 |
- cli_dbgmsg("Signature:\t%c%c%c%c\n", chunk->signature[0], |
|
507 |
- chunk->signature[1],chunk->signature[2],chunk->signature[3]); |
|
508 |
- cli_dbgmsg("Free Space:\t%u\n", chunk->free_space); |
|
509 |
- if (memcmp(chunk->signature, "PMGL", 4) == 0) { |
|
510 |
- cli_dbgmsg("Prev Block:\t%d\n", chunk->block_prev); |
|
511 |
- cli_dbgmsg("Next Block:\t%d\n", chunk->block_next); |
|
512 |
- cli_dbgmsg("Num entries:\t%d\n\n", chunk->num_entries); |
|
489 |
+ while (metadata->chunk_entries--) { |
|
490 |
+ if (metadata->chunk_current >= metadata->chunk_end) { |
|
491 |
+ return CL_EFORMAT; |
|
492 |
+ } |
|
493 |
+ |
|
494 |
+ name_len = read_enc_int(&metadata->chunk_current, metadata->chunk_end); |
|
495 |
+ if (((metadata->chunk_current + name_len) >= metadata->chunk_end) || |
|
496 |
+ ((metadata->chunk_current + name_len) < metadata->chunk_data)) { |
|
497 |
+ cli_dbgmsg("Bad CHM name_len detected\n"); |
|
498 |
+ return CL_EFORMAT; |
|
499 |
+ } |
|
500 |
+ metadata->chunk_current += name_len; |
|
501 |
+ section = read_enc_int(&metadata->chunk_current, metadata->chunk_end); |
|
502 |
+ metadata->file_offset = read_enc_int(&metadata->chunk_current, metadata->chunk_end); |
|
503 |
+ metadata->file_length = read_enc_int(&metadata->chunk_current, metadata->chunk_end); |
|
504 |
+ if (section == 1) { |
|
505 |
+ return CL_SUCCESS; |
|
506 |
+ } |
|
513 | 507 |
} |
514 |
- return; |
|
508 |
+ |
|
509 |
+ return CL_BREAK; |
|
515 | 510 |
} |
516 | 511 |
|
517 |
-static int read_chunk(int fd, off_t offset, uint32_t chunk_len, |
|
518 |
- char *m_area, off_t m_length, |
|
519 |
- file_list_t *file_l, file_list_t *sys_file_l) |
|
512 |
+static int read_chunk(chm_metadata_t *metadata, int fd) |
|
520 | 513 |
{ |
521 |
- chunk_header_t *chunk_hdr; |
|
522 |
- int retval = FALSE; |
|
523 |
- |
|
524 |
- if (chunk_len < 8 || chunk_len > 33554432) { |
|
525 |
- return FALSE; |
|
526 |
- } |
|
527 |
- |
|
528 |
- chunk_hdr = (chunk_header_t *) cli_malloc(sizeof(chunk_header_t)); |
|
529 |
- if (!chunk_hdr) { |
|
530 |
- return FALSE; |
|
531 |
- } |
|
532 |
- |
|
533 |
- chunk_hdr->chunk_data = (char *) cli_malloc(chunk_len); |
|
534 |
- if (!chunk_hdr->chunk_data) { |
|
535 |
- free(chunk_hdr); |
|
514 |
+ cli_dbgmsg("in read_chunk\n"); |
|
515 |
+ |
|
516 |
+ if (metadata->itsp_hdr.block_len < 8 || metadata->itsp_hdr.block_len > 33554432) { |
|
536 | 517 |
return FALSE; |
537 | 518 |
} |
538 |
- |
|
539 |
-#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA) |
|
540 |
- /* 8 bytes reads the signature and the free_space */ |
|
541 |
- if (!chm_read_data(fd, chunk_hdr->signature, offset, 8, |
|
542 |
- m_area, m_length)) { |
|
543 |
- goto abort; |
|
544 |
- } |
|
545 |
- if (!chm_read_data(fd, chunk_hdr->chunk_data, offset, chunk_len, |
|
546 |
- m_area, m_length)) { |
|
547 |
- goto abort; |
|
548 |
- } |
|
549 |
-#else |
|
550 |
- if (lseek(fd, offset, SEEK_SET) != offset) { |
|
551 |
- goto abort; |
|
552 |
- } |
|
553 |
- if (cli_readn(fd, chunk_hdr->chunk_data, chunk_len) != chunk_len) { |
|
554 |
- goto abort; |
|
555 |
- } |
|
556 |
- if (lseek(fd, offset, SEEK_SET) != offset) { |
|
557 |
- goto abort; |
|
558 |
- } |
|
559 |
- if (cli_readn(fd, &chunk_hdr->signature, 4) != 4) { |
|
560 |
- goto abort; |
|
561 |
- } |
|
562 |
- if (cli_readn(fd, &chunk_hdr->free_space, 4) != 4) { |
|
563 |
- goto abort; |
|
564 |
- } |
|
565 |
-#endif |
|
566 |
- chunk_hdr->free_space = chm_endian_convert_32(chunk_hdr->free_space); |
|
567 |
- |
|
568 |
- if (memcmp(chunk_hdr->signature, "PMGL", 4) == 0) { |
|
569 |
-#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA) |
|
570 |
- if (!chm_read_data(fd, (char *) &chunk_hdr->unknown, offset+8, 12, |
|
571 |
- m_area, m_length)) { |
|
572 |
- goto abort; |
|
519 |
+ |
|
520 |
+ if (metadata->m_area != NULL) { |
|
521 |
+ if (metadata->chunk_offset > metadata->m_length) { |
|
522 |
+ return CL_EFORMAT; |
|
573 | 523 |
} |
574 |
-#else |
|
575 |
- if (cli_readn(fd, &chunk_hdr->unknown, 4) != 4) { |
|
576 |
- goto abort; |
|
524 |
+ if ((metadata->chunk_offset + metadata->itsp_hdr.block_len) > metadata->m_length) { |
|
525 |
+ return CL_EFORMAT; |
|
577 | 526 |
} |
578 |
- if (cli_readn(fd, &chunk_hdr->block_next, 4) != 4) { |
|
579 |
- goto abort; |
|
527 |
+ metadata->chunk_data = metadata->m_area + metadata->chunk_offset; |
|
528 |
+ |
|
529 |
+ } else { |
|
530 |
+ if (!metadata->chunk_data) { |
|
531 |
+ metadata->chunk_data = (char *) cli_malloc(metadata->itsp_hdr.block_len); |
|
532 |
+ if (!metadata->chunk_data) { |
|
533 |
+ return CL_EMEM; |
|
534 |
+ } |
|
580 | 535 |
} |
581 |
- if (cli_readn(fd, &chunk_hdr->block_prev, 4) != 4) { |
|
582 |
- goto abort; |
|
536 |
+ if (lseek(fd, metadata->chunk_offset, SEEK_SET) != metadata->chunk_offset) { |
|
537 |
+ goto abort; |
|
538 |
+ } |
|
539 |
+ if (cli_readn(fd, metadata->chunk_data, metadata->itsp_hdr.block_len) != metadata->itsp_hdr.block_len) { |
|
540 |
+ goto abort; |
|
541 |
+ } |
|
542 |
+ } |
|
543 |
+ metadata->chunk_current = metadata->chunk_data + CHM_CHUNK_HDR_LEN; |
|
544 |
+ metadata->chunk_end = metadata->chunk_data + metadata->itsp_hdr.block_len; |
|
545 |
+ |
|
546 |
+ if (memcmp(metadata->chunk_data, "PMGL", 4) == 0) { |
|
547 |
+ metadata->chunk_entries = (uint16_t)((((uint8_t const *)(metadata->chunk_data))[metadata->itsp_hdr.block_len-2] << 0) |
|
548 |
+ | (((uint8_t const *)(metadata->chunk_data))[metadata->itsp_hdr.block_len-1] << 8)); |
|
549 |
+ } else if (memcmp(metadata->chunk_data, "PMGI", 4) != 0) { |
|
550 |
+ if (metadata->m_area != NULL) { |
|
551 |
+ free(metadata->chunk_data); |
|
583 | 552 |
} |
584 |
-#endif |
|
585 |
- chunk_hdr->block_next = chm_endian_convert_32(chunk_hdr->block_next); |
|
586 |
- chunk_hdr->block_prev = chm_endian_convert_32(chunk_hdr->block_prev); |
|
587 |
- |
|
588 |
- chunk_hdr->num_entries = (uint16_t)((((uint8_t const *)(chunk_hdr->chunk_data))[chunk_len-2] << 0) |
|
589 |
- | (((uint8_t const *)(chunk_hdr->chunk_data))[chunk_len-1] << 8)); |
|
590 |
- read_chunk_entries(chunk_hdr->chunk_data, chunk_len, |
|
591 |
- chunk_hdr->num_entries, file_l, sys_file_l); |
|
592 |
- } else if (memcmp(chunk_hdr->signature, "PMGI", 4) != 0) { |
|
593 |
- goto abort; |
|
553 |
+ return CL_BREAK; |
|
594 | 554 |
} |
595 | 555 |
|
596 |
- print_chunk(chunk_hdr); |
|
597 |
- retval=TRUE; |
|
556 |
+ return CL_SUCCESS; |
|
598 | 557 |
abort: |
599 |
- free(chunk_hdr->chunk_data); |
|
600 |
- free(chunk_hdr); |
|
601 |
- return retval; |
|
558 |
+ if (metadata->m_area != NULL) { |
|
559 |
+ free(metadata->chunk_data); |
|
560 |
+ metadata->chunk_data = NULL; |
|
561 |
+ } |
|
562 |
+ return CL_EFORMAT; |
|
602 | 563 |
} |
603 | 564 |
|
604 | 565 |
static void print_sys_control(lzx_control_t *lzx_control) |
... | ... |
@@ -617,50 +511,44 @@ static void print_sys_control(lzx_control_t *lzx_control) |
617 | 617 |
cli_dbgmsg("Cache Size:\t%d\n\n", lzx_control->cache_size); |
618 | 618 |
} |
619 | 619 |
|
620 |
-static lzx_control_t *read_sys_control(int fd, itsf_header_t *itsf_hdr, file_list_t *file_e, |
|
621 |
- char *m_area, off_t m_length) |
|
620 |
+static int read_sys_control(int fd, chm_metadata_t *metadata, lzx_control_t *lzx_control) |
|
622 | 621 |
{ |
623 | 622 |
off_t offset; |
624 |
- lzx_control_t *lzx_control; |
|
625 | 623 |
|
626 |
- if (file_e->length != 28) { |
|
627 |
- return NULL; |
|
624 |
+ if (metadata->sys_control.length != 28) { |
|
625 |
+ return FALSE; |
|
628 | 626 |
} |
629 |
- offset = itsf_hdr->data_offset + file_e->offset; |
|
627 |
+ offset = metadata->itsf_hdr.data_offset + metadata->sys_control.offset; |
|
630 | 628 |
if (offset < 0) { |
631 |
- return NULL; |
|
629 |
+ return FALSE; |
|
632 | 630 |
} |
633 | 631 |
|
634 |
- lzx_control = (lzx_control_t *) cli_malloc(sizeof(lzx_control_t)); |
|
635 |
- if (!lzx_control) { |
|
636 |
- return NULL; |
|
637 |
- } |
|
638 | 632 |
#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA) |
639 | 633 |
if (!chm_read_data(fd, (char *) lzx_control, offset, CHM_CONTROL_LEN, |
640 |
- m_area, m_length)) { |
|
641 |
- goto abort; |
|
634 |
+ metadata->m_area, metadata->m_length)) { |
|
635 |
+ return FALSE; |
|
642 | 636 |
} |
643 | 637 |
#else |
644 | 638 |
if (lseek(fd, offset, SEEK_SET) != offset) { |
645 |
- goto abort; |
|
639 |
+ return FALSE; |
|
646 | 640 |
} |
647 | 641 |
if (cli_readn(fd, &lzx_control->length, 4) != 4) { |
648 |
- goto abort; |
|
642 |
+ return FALSE; |
|
649 | 643 |
} |
650 | 644 |
if (cli_readn(fd, &lzx_control->signature, 4) != 4) { |
651 |
- goto abort; |
|
645 |
+ return FALSE; |
|
652 | 646 |
} |
653 | 647 |
if (cli_readn(fd, &lzx_control->version, 4) != 4) { |
654 |
- goto abort; |
|
648 |
+ return FALSE; |
|
655 | 649 |
} |
656 | 650 |
if (cli_readn(fd, &lzx_control->reset_interval, 4) != 4) { |
657 |
- goto abort; |
|
651 |
+ return FALSE; |
|
658 | 652 |
} |
659 | 653 |
if (cli_readn(fd, &lzx_control->window_size, 4) != 4) { |
660 |
- goto abort; |
|
654 |
+ return FALSE; |
|
661 | 655 |
} |
662 | 656 |
if (cli_readn(fd, &lzx_control->cache_size, 4) != 4) { |
663 |
- goto abort; |
|
657 |
+ return FALSE; |
|
664 | 658 |
} |
665 | 659 |
#endif |
666 | 660 |
lzx_control->length = chm_endian_convert_32(lzx_control->length); |
... | ... |
@@ -671,7 +559,7 @@ static lzx_control_t *read_sys_control(int fd, itsf_header_t *itsf_hdr, file_lis |
671 | 671 |
|
672 | 672 |
if (strncmp((const char *) "LZXC", (const char *) lzx_control->signature, 4) != 0) { |
673 | 673 |
cli_dbgmsg("bad sys_control signature"); |
674 |
- goto abort; |
|
674 |
+ return FALSE; |
|
675 | 675 |
} |
676 | 676 |
switch(lzx_control->version) { |
677 | 677 |
case 1: |
... | ... |
@@ -682,14 +570,11 @@ static lzx_control_t *read_sys_control(int fd, itsf_header_t *itsf_hdr, file_lis |
682 | 682 |
break; |
683 | 683 |
default: |
684 | 684 |
cli_dbgmsg("Unknown sys_control version:%d\n", lzx_control->version); |
685 |
- goto abort; |
|
685 |
+ return FALSE; |
|
686 | 686 |
} |
687 | 687 |
|
688 | 688 |
print_sys_control(lzx_control); |
689 |
- return lzx_control; |
|
690 |
-abort: |
|
691 |
- free(lzx_control); |
|
692 |
- return NULL; |
|
689 |
+ return TRUE; |
|
693 | 690 |
} |
694 | 691 |
|
695 | 692 |
static void print_sys_content(lzx_content_t *lzx_content) |
... | ... |
@@ -703,19 +588,13 @@ static void print_sys_content(lzx_content_t *lzx_content) |
703 | 703 |
cli_dbgmsg("Length:\t%llu\n\n", lzx_content->length); |
704 | 704 |
} |
705 | 705 |
|
706 |
-static lzx_content_t *read_sys_content(int fd, itsf_header_t *itsf_hdr, file_list_t *file_e) |
|
706 |
+static int read_sys_content(int fd, chm_metadata_t *metadata, lzx_content_t *lzx_content) |
|
707 | 707 |
{ |
708 |
- lzx_content_t *lzx_content; |
|
709 |
- |
|
710 |
- lzx_content = (lzx_content_t *) cli_malloc(sizeof(lzx_content_t)); |
|
711 |
- if (!lzx_content) { |
|
712 |
- return NULL; |
|
713 |
- } |
|
714 |
- lzx_content->offset = itsf_hdr->data_offset + file_e->offset; |
|
715 |
- lzx_content->length = file_e->length; |
|
708 |
+ lzx_content->offset = metadata->itsf_hdr.data_offset + metadata->sys_content.offset; |
|
709 |
+ lzx_content->length = metadata->sys_content.length; |
|
716 | 710 |
|
717 | 711 |
print_sys_content(lzx_content); |
718 |
- return lzx_content; |
|
712 |
+ return TRUE; |
|
719 | 713 |
} |
720 | 714 |
|
721 | 715 |
static void print_sys_reset_table(lzx_reset_table_t *lzx_reset_table) |
... | ... |
@@ -733,25 +612,18 @@ static void print_sys_reset_table(lzx_reset_table_t *lzx_reset_table) |
733 | 733 |
cli_dbgmsg("Frame Len:\t%llu\n\n", lzx_reset_table->frame_len); |
734 | 734 |
} |
735 | 735 |
|
736 |
-static lzx_reset_table_t *read_sys_reset_table(int fd, itsf_header_t *itsf_hdr, file_list_t *file_e, |
|
737 |
- char *m_area, off_t m_length) |
|
736 |
+static int read_sys_reset_table(int fd, chm_metadata_t *metadata, lzx_reset_table_t *lzx_reset_table) |
|
738 | 737 |
{ |
739 | 738 |
off_t offset; |
740 |
- lzx_reset_table_t *lzx_reset_table; |
|
741 | 739 |
|
742 |
- if (file_e->length < 40) { |
|
743 |
- return NULL; |
|
740 |
+ if (metadata->sys_reset.length < 40) { |
|
741 |
+ return FALSE; |
|
744 | 742 |
} |
745 | 743 |
/* Skip past unknown entry in offset calc */ |
746 |
- offset = itsf_hdr->data_offset + file_e->offset + 4; |
|
744 |
+ offset = metadata->itsf_hdr.data_offset + metadata->sys_reset.offset + 4; |
|
747 | 745 |
|
748 | 746 |
if (offset < 0) { |
749 |
- return NULL; |
|
750 |
- } |
|
751 |
- |
|
752 |
- lzx_reset_table = (lzx_reset_table_t *) cli_malloc(sizeof(lzx_reset_table_t)); |
|
753 |
- if (!lzx_reset_table) { |
|
754 |
- return NULL; |
|
747 |
+ return FALSE; |
|
755 | 748 |
} |
756 | 749 |
|
757 | 750 |
/* Save the entry offset for later use */ |
... | ... |
@@ -759,30 +631,30 @@ static lzx_reset_table_t *read_sys_reset_table(int fd, itsf_header_t *itsf_hdr, |
759 | 759 |
|
760 | 760 |
#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA) |
761 | 761 |
if (!chm_read_data(fd, (char *) lzx_reset_table, offset, CHM_RESET_TABLE_LEN, |
762 |
- m_area, m_length)) { |
|
763 |
- goto abort; |
|
762 |
+ metadata->m_area, metadata->m_length)) { |
|
763 |
+ return FALSE; |
|
764 | 764 |
} |
765 | 765 |
#else |
766 | 766 |
if (lseek(fd, offset, SEEK_SET) != offset) { |
767 |
- goto abort; |
|
767 |
+ return FALSE; |
|
768 | 768 |
} |
769 | 769 |
if (cli_readn(fd, &lzx_reset_table->num_entries, 4) != 4) { |
770 |
- goto abort; |
|
770 |
+ return FALSE; |
|
771 | 771 |
} |
772 | 772 |
if (cli_readn(fd, &lzx_reset_table->entry_size, 4) != 4) { |
773 |
- goto abort; |
|
773 |
+ return FALSE; |
|
774 | 774 |
} |
775 | 775 |
if (cli_readn(fd, &lzx_reset_table->table_offset, 4) != 4) { |
776 |
- goto abort; |
|
776 |
+ return FALSE; |
|
777 | 777 |
} |
778 | 778 |
if (cli_readn(fd, &lzx_reset_table->uncom_len, 8) != 8) { |
779 |
- goto abort; |
|
779 |
+ return FALSE; |
|
780 | 780 |
} |
781 | 781 |
if (cli_readn(fd, &lzx_reset_table->com_len, 8) != 8) { |
782 |
- goto abort; |
|
782 |
+ return FALSE; |
|
783 | 783 |
} |
784 | 784 |
if (cli_readn(fd, &lzx_reset_table->frame_len, 8) != 8) { |
785 |
- goto abort; |
|
785 |
+ return FALSE; |
|
786 | 786 |
} |
787 | 787 |
#endif |
788 | 788 |
lzx_reset_table->num_entries = chm_endian_convert_32(lzx_reset_table->num_entries); |
... | ... |
@@ -794,56 +666,52 @@ static lzx_reset_table_t *read_sys_reset_table(int fd, itsf_header_t *itsf_hdr, |
794 | 794 |
|
795 | 795 |
if (lzx_reset_table->frame_len != LZX_FRAME_SIZE) { |
796 | 796 |
cli_dbgmsg("bad sys_reset_table frame_len: 0x%lx\n", (long unsigned int) lzx_reset_table->frame_len); |
797 |
- goto abort; |
|
797 |
+ return FALSE; |
|
798 | 798 |
} |
799 | 799 |
if ((lzx_reset_table->entry_size != 4) && (lzx_reset_table->entry_size != 8)) { |
800 | 800 |
cli_dbgmsg("bad sys_reset_table entry_size: 0x%x\n",lzx_reset_table->entry_size); |
801 |
- goto abort; |
|
801 |
+ return FALSE; |
|
802 | 802 |
} |
803 | 803 |
print_sys_reset_table(lzx_reset_table); |
804 |
- return lzx_reset_table; |
|
805 |
-abort: |
|
806 |
- free(lzx_reset_table); |
|
807 |
- return NULL; |
|
804 |
+ return TRUE; |
|
808 | 805 |
} |
809 | 806 |
|
810 | 807 |
/* *****************************************************************/ |
811 | 808 |
/* This section interfaces to the mspack files. As such, this is a */ |
812 | 809 |
/* little bit dirty compared to my usual code */ |
813 | 810 |
|
814 |
-static int chm_decompress_stream(int fd, const char *dirname, itsf_header_t *itsf_hdr, |
|
815 |
- file_list_t *file_l, file_list_t *sys_file_l, |
|
816 |
- char *m_area, off_t m_length) |
|
811 |
+static int chm_decompress_stream(int fd, chm_metadata_t *metadata, const char *dirname) |
|
817 | 812 |
{ |
818 |
- file_list_t *entry; |
|
819 |
- lzx_content_t *lzx_content=NULL; |
|
820 |
- lzx_reset_table_t *lzx_reset_table=NULL; |
|
821 |
- lzx_control_t *lzx_control=NULL; |
|
822 |
- int window_bits, count, length, tmpfd, ofd, retval=FALSE; |
|
823 |
- uint64_t com_offset; |
|
813 |
+ lzx_content_t lzx_content; |
|
814 |
+ lzx_reset_table_t lzx_reset_table; |
|
815 |
+ lzx_control_t lzx_control; |
|
816 |
+ int window_bits, length, tmpfd, retval=-1; |
|
824 | 817 |
struct lzx_stream * stream; |
825 | 818 |
char filename[1024]; |
826 | 819 |
|
827 | 820 |
snprintf(filename, 1024, "%s/clamav-unchm.bin", dirname); |
828 |
- tmpfd = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU); |
|
821 |
+ tmpfd = open(filename, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU); |
|
829 | 822 |
if (tmpfd<0) { |
830 | 823 |
cli_dbgmsg("open failed for %s\n", filename); |
831 |
- return FALSE; |
|
824 |
+ return -1; |
|
832 | 825 |
} |
833 | 826 |
|
834 |
- if (!sys_file_l[0].length || !sys_file_l[1].length ||!sys_file_l[2].length) { |
|
827 |
+ if (!metadata->sys_control.length || !metadata->sys_content.length ||!metadata->sys_reset.length) { |
|
828 |
+ cli_dbgmsg("Control file missing\n"); |
|
835 | 829 |
goto abort; |
836 | 830 |
} |
837 | 831 |
|
838 |
- lzx_control = read_sys_control(fd, itsf_hdr, &sys_file_l[0], m_area, m_length); |
|
839 |
- lzx_content = read_sys_content(fd, itsf_hdr, &sys_file_l[1]); |
|
840 |
- lzx_reset_table = read_sys_reset_table(fd, itsf_hdr, &sys_file_l[2], m_area, m_length); |
|
841 |
- |
|
842 |
- if (!lzx_content || !lzx_reset_table || !lzx_control) { |
|
832 |
+ if (!read_sys_control(fd, metadata, &lzx_control)) { |
|
833 |
+ goto abort; |
|
834 |
+ } |
|
835 |
+ if (!read_sys_content(fd, metadata, &lzx_content)) { |
|
836 |
+ goto abort; |
|
837 |
+ } |
|
838 |
+ if (!read_sys_reset_table(fd, metadata, &lzx_reset_table)) { |
|
843 | 839 |
goto abort; |
844 | 840 |
} |
845 | 841 |
|
846 |
- switch (lzx_control->window_size) { |
|
842 |
+ switch (lzx_control.window_size) { |
|
847 | 843 |
case 0x008000: |
848 | 844 |
window_bits = 15; |
849 | 845 |
break; |
... | ... |
@@ -866,26 +734,27 @@ static int chm_decompress_stream(int fd, const char *dirname, itsf_header_t *its |
866 | 866 |
window_bits = 21; |
867 | 867 |
break; |
868 | 868 |
default: |
869 |
- cli_dbgmsg("bad control window size: 0x%x\n", lzx_control->window_size); |
|
869 |
+ cli_dbgmsg("bad control window size: 0x%x\n", lzx_control.window_size); |
|
870 | 870 |
goto abort; |
871 | 871 |
} |
872 | 872 |
|
873 |
- if (lzx_control->reset_interval % LZX_FRAME_SIZE) { |
|
874 |
- cli_dbgmsg("bad reset_interval: 0x%x\n", lzx_control->window_size); |
|
873 |
+ if (lzx_control.reset_interval % LZX_FRAME_SIZE) { |
|
874 |
+ cli_dbgmsg("bad reset_interval: 0x%x\n", lzx_control.window_size); |
|
875 | 875 |
goto abort; |
876 | 876 |
} |
877 | 877 |
|
878 |
- length = lzx_reset_table->uncom_len; |
|
879 |
- length += lzx_control->reset_interval; |
|
880 |
- length &= -lzx_control->reset_interval; |
|
878 |
+ length = lzx_reset_table.uncom_len; |
|
879 |
+ length += lzx_control.reset_interval; |
|
880 |
+ length &= -lzx_control.reset_interval; |
|
881 | 881 |
|
882 |
- com_offset = lzx_content->offset; |
|
883 |
- cli_dbgmsg("Compressed offset: %llu\n", com_offset); |
|
882 |
+ cli_dbgmsg("Compressed offset: %llu\n", lzx_content.offset); |
|
883 |
+ if (lseek(fd, lzx_content.offset, SEEK_SET) != lzx_content.offset) { |
|
884 |
+ goto abort; |
|
885 |
+ } |
|
884 | 886 |
|
885 | 887 |
stream = lzx_init(fd, tmpfd, window_bits, |
886 |
- lzx_control->reset_interval / LZX_FRAME_SIZE, |
|
888 |
+ lzx_control.reset_interval / LZX_FRAME_SIZE, |
|
887 | 889 |
4096, length, NULL, NULL); |
888 |
- lseek(fd, com_offset, SEEK_SET); |
|
889 | 890 |
if (!stream) { |
890 | 891 |
cli_dbgmsg("lzx_init failed\n"); |
891 | 892 |
goto abort; |
... | ... |
@@ -894,149 +763,175 @@ static int chm_decompress_stream(int fd, const char *dirname, itsf_header_t *its |
894 | 894 |
lzx_decompress(stream, length); |
895 | 895 |
lzx_free(stream); |
896 | 896 |
|
897 |
- entry = file_l->next; |
|
898 |
- close(tmpfd); |
|
899 |
- |
|
900 |
- /* Reopen the file for reading */ |
|
901 |
- tmpfd = open(filename, O_RDONLY|O_BINARY); |
|
902 |
- if (tmpfd < 0) { |
|
903 |
- cli_dbgmsg("re-open output failed\n"); |
|
904 |
- goto abort; |
|
905 |
- } |
|
906 |
- |
|
907 | 897 |
/* Delete the file */ |
908 | 898 |
unlink(filename); |
909 |
- |
|
910 |
- count=0; |
|
911 |
- while(entry) { |
|
912 |
- if (entry->section != 1) { |
|
913 |
- entry = entry->next; |
|
914 |
- continue; |
|
915 |
- } |
|
916 |
- if (lseek(tmpfd, entry->offset, SEEK_SET) != (off_t)entry->offset) { |
|
917 |
- cli_dbgmsg("seek in output failed\n"); |
|
918 |
- entry = entry->next; |
|
919 |
- continue; |
|
920 |
- } |
|
921 |
- |
|
922 |
- snprintf(filename, 1024, "%s/%d-%llu.chm", dirname, count, entry->offset); |
|
923 |
- ofd = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU); |
|
924 |
- if (ofd < 0) { |
|
925 |
- entry = entry->next; |
|
926 |
- continue; |
|
927 |
- } |
|
928 |
- if (chm_copy_file_data(tmpfd, ofd, entry->length) != entry->length) { |
|
929 |
- cli_dbgmsg("failed to copy %lu bytes\n", (long unsigned int) entry->length); |
|
930 |
- } |
|
931 |
- |
|
932 |
- close(ofd); |
|
933 |
- entry = entry->next; |
|
934 |
- count++; |
|
935 |
- } |
|
936 |
- close(tmpfd); |
|
937 |
- tmpfd=-1; |
|
938 |
- retval = TRUE; |
|
899 |
+ retval = tmpfd; |
|
939 | 900 |
|
940 | 901 |
abort: |
941 |
- if (tmpfd>=0) { |
|
902 |
+ if ((retval == -1) && (tmpfd >= 0)) { |
|
942 | 903 |
close(tmpfd); |
943 | 904 |
} |
944 |
- if (lzx_content) { |
|
945 |
- free(lzx_content); |
|
905 |
+ return retval; |
|
906 |
+} |
|
907 |
+ |
|
908 |
+/* ************ End dirty section ********************/ |
|
909 |
+ |
|
910 |
+static int chm_init_metadata(chm_metadata_t *metadata) |
|
911 |
+{ |
|
912 |
+ if (!metadata) { |
|
913 |
+ return CL_ENULLARG; |
|
946 | 914 |
} |
947 |
- if (lzx_reset_table) { |
|
948 |
- free(lzx_reset_table); |
|
915 |
+ |
|
916 |
+ metadata->sys_control.length = metadata->sys_content.length = metadata->sys_reset.length = 0; |
|
917 |
+ metadata->m_area = NULL; |
|
918 |
+ metadata->m_area = 0; |
|
919 |
+ metadata->ufd = -1; |
|
920 |
+ metadata->num_chunks = metadata->chunk_entries = 0; |
|
921 |
+ metadata->chunk_data = NULL; |
|
922 |
+ return CL_SUCCESS; |
|
923 |
+} |
|
924 |
+ |
|
925 |
+void cli_chm_close(chm_metadata_t *metadata) |
|
926 |
+{ |
|
927 |
+ if (metadata->ufd >= 0) { |
|
928 |
+ close(metadata->ufd); |
|
949 | 929 |
} |
950 |
- if (lzx_control) { |
|
951 |
- free(lzx_control); |
|
930 |
+ if (!metadata->m_area && metadata->chunk_data) { |
|
931 |
+ free(metadata->chunk_data); |
|
952 | 932 |
} |
953 |
- return retval; |
|
933 |
+#ifdef HAVE_MMAP |
|
934 |
+ if (metadata->m_area) { |
|
935 |
+ munmap(metadata->m_area, metadata-> m_length); |
|
936 |
+ } |
|
937 |
+#endif |
|
954 | 938 |
} |
955 | 939 |
|
956 |
-/* ************ End dirty section ********************/ |
|
940 |
+int cli_chm_extract_file(int fd, char *dirname, chm_metadata_t *metadata) |
|
941 |
+{ |
|
942 |
+ char filename[1024]; |
|
943 |
+ |
|
944 |
+ cli_dbgmsg("in cli_chm_extract_file\n"); |
|
945 |
+ |
|
946 |
+ if (lseek(metadata->ufd, metadata->file_offset, SEEK_SET) != (off_t) metadata->file_offset) { |
|
947 |
+ cli_dbgmsg("seek in uncompressed stream failed\n"); |
|
948 |
+ return CL_EFORMAT; |
|
949 |
+ } |
|
950 |
+ snprintf(filename, 1024, "%s/%llu.chm", dirname, metadata->file_offset); |
|
951 |
+ metadata->ofd = open(filename, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU); |
|
952 |
+ if (metadata->ofd < 0) { |
|
953 |
+ return CL_EIO; |
|
954 |
+ } |
|
955 |
+ if (chm_copy_file_data(metadata->ufd, metadata->ofd, metadata->file_length) != metadata->file_length) { |
|
956 |
+ cli_dbgmsg("failed to copy %lu bytes\n", (long unsigned int) metadata->file_length); |
|
957 |
+ close(metadata->ofd); |
|
958 |
+ return CL_EIO; |
|
959 |
+ } |
|
960 |
+ |
|
961 |
+ return CL_SUCCESS; |
|
962 |
+} |
|
957 | 963 |
|
958 |
-int chm_unpack(int fd, const char *dirname) |
|
964 |
+int cli_chm_prepare_file(int fd, char *dirname, chm_metadata_t *metadata) |
|
965 |
+{ |
|
966 |
+ int retval; |
|
967 |
+ |
|
968 |
+ cli_dbgmsg("in cli_chm_prepare_file\n"); |
|
969 |
+ |
|
970 |
+ if (metadata->chunk_entries == 0) { |
|
971 |
+ if (metadata->num_chunks == 0) { |
|
972 |
+ return CL_BREAK; |
|
973 |
+ } |
|
974 |
+ if ((retval = read_chunk(metadata, fd)) != CL_SUCCESS) { |
|
975 |
+ return retval; |
|
976 |
+ } |
|
977 |
+ } |
|
978 |
+ |
|
979 |
+ return prepare_file(fd, metadata); |
|
980 |
+} |
|
981 |
+ |
|
982 |
+int cli_chm_open(int fd, const char *dirname, chm_metadata_t *metadata) |
|
959 | 983 |
{ |
960 |
- int retval=FALSE; |
|
961 |
- char *m_area=NULL; |
|
962 |
- off_t m_length=0, offset; |
|
963 |
- file_list_t *file_l, sys_file_l[3]; |
|
964 | 984 |
struct stat statbuf; |
965 |
- itsf_header_t itsf_hdr; |
|
966 |
- itsp_header_t itsp_hdr; |
|
967 |
- uint32_t num_chunks; |
|
985 |
+ int retval; |
|
968 | 986 |
|
969 |
- /* These two lists contain the list of files and system files in |
|
970 |
- the archive. The first entry in the list is an empty entry */ |
|
987 |
+ cli_dbgmsg("in cli_chm_open\n"); |
|
971 | 988 |
|
972 |
- file_l = (file_list_t *) cli_malloc(sizeof(file_list_t)); |
|
973 |
- if (!file_l) { |
|
974 |
- return FALSE; |
|
989 |
+ if ((retval = chm_init_metadata(metadata)) != CL_SUCCESS) { |
|
990 |
+ return retval; |
|
975 | 991 |
} |
976 |
- file_l->next = NULL; |
|
977 |
- sys_file_l[0].length = sys_file_l[1].length = sys_file_l[2].length = 0; |
|
978 |
- |
|
992 |
+ |
|
979 | 993 |
#ifdef HAVE_MMAP |
980 | 994 |
if (fstat(fd, &statbuf) == 0) { |
981 | 995 |
if (statbuf.st_size < CHM_ITSF_MIN_LEN) { |
982 | 996 |
goto abort; |
983 | 997 |
} |
984 |
- m_length = statbuf.st_size; |
|
985 |
- m_area = (char *) mmap(NULL, m_length, PROT_READ, MAP_PRIVATE, fd, 0); |
|
986 |
- if (m_area == MAP_FAILED) { |
|
987 |
- m_area = NULL; |
|
998 |
+ metadata->m_length = statbuf.st_size; |
|
999 |
+ metadata->m_area = (char *) mmap(NULL, metadata->m_length, PROT_READ, MAP_PRIVATE, fd, 0); |
|
1000 |
+ if (metadata->m_area == MAP_FAILED) { |
|
1001 |
+ metadata->m_area = NULL; |
|
988 | 1002 |
} |
989 | 1003 |
} |
990 | 1004 |
#endif |
991 | 1005 |
|
992 |
- if (!itsf_read_header(fd, &itsf_hdr, m_area, m_length)) { |
|
1006 |
+ if (!itsf_read_header(fd, &metadata->itsf_hdr, metadata->m_area, metadata->m_length)) { |
|
993 | 1007 |
goto abort; |
994 | 1008 |
} |
995 |
- itsf_print_header(&itsf_hdr); |
|
1009 |
+ itsf_print_header(&metadata->itsf_hdr); |
|
996 | 1010 |
|
997 |
- if (!itsp_read_header(fd, &itsp_hdr, itsf_hdr.dir_offset, m_area, m_length)) { |
|
1011 |
+ if (!itsp_read_header(fd, &metadata->itsp_hdr, metadata->itsf_hdr.dir_offset, metadata->m_area, metadata->m_length)) { |
|
998 | 1012 |
goto abort; |
999 | 1013 |
} |
1000 |
- itsp_print_header(&itsp_hdr); |
|
1001 |
- |
|
1002 |
- offset = itsf_hdr.dir_offset+CHM_ITSP_LEN; |
|
1014 |
+ itsp_print_header(&metadata->itsp_hdr); |
|
1015 |
+ |
|
1016 |
+ metadata->chunk_offset = metadata->itsf_hdr.dir_offset+CHM_ITSP_LEN; |
|
1003 | 1017 |
|
1004 | 1018 |
/* TODO: need to check this first calculation, |
1005 | 1019 |
currently have no files of this type */ |
1006 |
- if (itsp_hdr.index_head > 0) { |
|
1007 |
- offset += itsp_hdr.index_head * itsp_hdr.block_len; |
|
1020 |
+ if (metadata->itsp_hdr.index_head > 0) { |
|
1021 |
+ metadata->chunk_offset += metadata->itsp_hdr.index_head * metadata->itsp_hdr.block_len; |
|
1008 | 1022 |
} |
1009 | 1023 |
|
1010 |
- num_chunks = itsp_hdr.index_tail - itsp_hdr.index_head + 1; |
|
1024 |
+ metadata->num_chunks = metadata->itsp_hdr.index_tail - metadata->itsp_hdr.index_head + 1; |
|
1011 | 1025 |
|
1012 | 1026 |
/* Versions before 3 didn't have a data_offset */ |
1013 | 1027 |
/* TODO: need to check this calculation, |
1014 | 1028 |
currently have no files of this type */ |
1015 |
- if (itsf_hdr.version < 3) { |
|
1016 |
- itsf_hdr.data_offset = itsf_hdr.dir_offset + CHM_ITSP_LEN + (itsp_hdr.block_len*itsp_hdr.num_blocks); |
|
1029 |
+ if (metadata->itsf_hdr.version < 3) { |
|
1030 |
+ metadata->itsf_hdr.data_offset = metadata->itsf_hdr.dir_offset + CHM_ITSP_LEN + |
|
1031 |
+ (metadata->itsp_hdr.block_len*metadata->itsp_hdr.num_blocks); |
|
1017 | 1032 |
} |
1018 |
- |
|
1019 |
- while (num_chunks) { |
|
1020 |
- if (!read_chunk(fd, offset, itsp_hdr.block_len, m_area, |
|
1021 |
- m_length, file_l, sys_file_l)) { |
|
1033 |
+ |
|
1034 |
+ while (metadata->num_chunks) { |
|
1035 |
+ if (read_chunk(metadata, fd) != CL_SUCCESS) { |
|
1036 |
+ cli_dbgmsg("read_chunk failed"); |
|
1022 | 1037 |
goto abort; |
1023 | 1038 |
} |
1039 |
+ read_control_entries(metadata); |
|
1040 |
+ metadata->num_chunks--; |
|
1041 |
+ metadata->chunk_offset += metadata->itsp_hdr.block_len; |
|
1042 |
+ } |
|
1024 | 1043 |
|
1025 |
- num_chunks--; |
|
1026 |
- offset += itsp_hdr.block_len; |
|
1044 |
+ if (!metadata->sys_content.length || !metadata->sys_control.length || !metadata->sys_reset.length) { |
|
1045 |
+ cli_dbgmsg("sys file missing"); |
|
1046 |
+ goto abort; |
|
1027 | 1047 |
} |
1048 |
+ |
|
1049 |
+ metadata->ufd = chm_decompress_stream(fd, metadata, dirname); |
|
1050 |
+ if (metadata->ufd == -1) { |
|
1051 |
+ goto abort; |
|
1052 |
+ } |
|
1053 |
+ |
|
1054 |
+ metadata->chunk_entries = 0; |
|
1055 |
+ metadata->chunk_data = NULL; |
|
1056 |
+ metadata->chunk_offset = metadata->itsf_hdr.dir_offset+CHM_ITSP_LEN; |
|
1057 |
+ metadata->num_chunks = metadata->itsp_hdr.index_tail - metadata->itsp_hdr.index_head + 1; |
|
1028 | 1058 |
|
1029 |
- chm_decompress_stream(fd, dirname, &itsf_hdr, file_l, sys_file_l, m_area, m_length); |
|
1059 |
+ return CL_SUCCESS; |
|
1030 | 1060 |
|
1031 |
- /* Signal success */ |
|
1032 |
- retval = TRUE; |
|
1033 | 1061 |
abort: |
1034 |
- free_file_list(file_l); |
|
1035 |
- |
|
1036 | 1062 |
#ifdef HAVE_MMAP |
1037 |
- if (m_area) { |
|
1038 |
- munmap(m_area, m_length); |
|
1063 |
+ if (metadata->m_area) { |
|
1064 |
+ munmap(metadata->m_area, metadata->m_length); |
|
1039 | 1065 |
} |
1040 | 1066 |
#endif |
1041 |
- return retval; |
|
1067 |
+ return CL_EFORMAT; |
|
1042 | 1068 |
} |
... | ... |
@@ -21,7 +21,71 @@ |
21 | 21 |
|
22 | 22 |
#ifndef __CHM_UNPACK_H |
23 | 23 |
#define __CHM_UNPACK_H |
24 |
- |
|
24 |
+ |
|
25 |
+#define CHM_ITSF_MIN_LEN (0x60) |
|
26 |
+typedef struct chm_itsf_header_tag |
|
27 |
+{ |
|
28 |
+ unsigned char signature[4]; |
|
29 |
+ int32_t version __attribute__ ((packed)); |
|
30 |
+ int32_t header_len __attribute__ ((packed)); |
|
31 |
+ uint32_t unknown __attribute__ ((packed)); |
|
32 |
+ uint32_t last_modified __attribute__ ((packed)); |
|
33 |
+ uint32_t lang_id __attribute__ ((packed)); |
|
34 |
+ unsigned char dir_clsid[16]; |
|
35 |
+ unsigned char stream_clsid[16]; |
|
36 |
+ uint64_t sec0_offset __attribute__ ((packed)); |
|
37 |
+ uint64_t sec0_len __attribute__ ((packed)); |
|
38 |
+ uint64_t dir_offset __attribute__ ((packed)); |
|
39 |
+ uint64_t dir_len __attribute__ ((packed)); |
|
40 |
+ uint64_t data_offset __attribute__ ((packed)); |
|
41 |
+} chm_itsf_header_t; |
|
42 |
+ |
|
43 |
+#define CHM_ITSP_LEN (0x54) |
|
44 |
+typedef struct chm_itsp_header_tag |
|
45 |
+{ |
|
46 |
+ unsigned char signature[4]; |
|
47 |
+ int32_t version __attribute__ ((packed)); |
|
48 |
+ int32_t header_len __attribute__ ((packed)); |
|
49 |
+ int32_t unknown1 __attribute__ ((packed)); |
|
50 |
+ uint32_t block_len __attribute__ ((packed)); |
|
51 |
+ int32_t blockidx_intvl __attribute__ ((packed)); |
|
52 |
+ int32_t index_depth __attribute__ ((packed)); |
|
53 |
+ int32_t index_root __attribute__ ((packed)); |
|
54 |
+ int32_t index_head __attribute__ ((packed)); |
|
55 |
+ int32_t index_tail __attribute__ ((packed)); |
|
56 |
+ int32_t unknown2 __attribute__ ((packed)); |
|
57 |
+ uint32_t num_blocks __attribute__ ((packed)); |
|
58 |
+ uint32_t lang_id __attribute__ ((packed)); |
|
59 |
+ unsigned char system_clsid[16]; |
|
60 |
+ unsigned char unknown4[16]; |
|
61 |
+} chm_itsp_header_t; |
|
62 |
+ |
|
63 |
+typedef struct chm_sys_entry_tag |
|
64 |
+{ |
|
65 |
+ uint64_t offset; |
|
66 |
+ uint64_t length; |
|
67 |
+} chm_sys_entry_t; |
|
68 |
+ |
|
69 |
+typedef struct chm_metadata_tag { |
|
70 |
+ chm_sys_entry_t sys_control; |
|
71 |
+ chm_sys_entry_t sys_content; |
|
72 |
+ chm_sys_entry_t sys_reset; |
|
73 |
+ off_t m_length; |
|
74 |
+ char *m_area; |
|
75 |
+ chm_itsf_header_t itsf_hdr; |
|
76 |
+ chm_itsp_header_t itsp_hdr; |
|
77 |
+ int ufd; |
|
78 |
+ int ofd; |
|
79 |
+ uint32_t num_chunks; |
|
80 |
+ off_t chunk_offset; |
|
81 |
+ char *chunk_data; |
|
82 |
+ char *chunk_current; |
|
83 |
+ char *chunk_end; |
|
84 |
+ uint16_t chunk_entries; |
|
85 |
+ uint64_t file_length; |
|
86 |
+ uint64_t file_offset; |
|
87 |
+} chm_metadata_t; |
|
88 |
+ |
|
25 | 89 |
int chm_unpack(int fd, const char *dirname); |
26 | 90 |
|
27 | 91 |
#endif |
... | ... |
@@ -376,7 +376,7 @@ static int cli_scanarj(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c |
376 | 376 |
/* generate the temporary directory */ |
377 | 377 |
dir = cli_gentemp(NULL); |
378 | 378 |
if(mkdir(dir, 0700)) { |
379 |
- cli_dbgmsg("RAR: Can't create temporary directory %s\n", dir); |
|
379 |
+ cli_dbgmsg("ARJ: Can't create temporary directory %s\n", dir); |
|
380 | 380 |
free(dir); |
381 | 381 |
return CL_ETMPDIR; |
382 | 382 |
} |
... | ... |
@@ -1204,26 +1204,60 @@ static int cli_scanbinhex(int desc, cli_ctx *ctx) |
1204 | 1204 |
|
1205 | 1205 |
static int cli_scanmschm(int desc, cli_ctx *ctx) |
1206 | 1206 |
{ |
1207 |
- char *tempname; |
|
1208 |
- int ret = CL_CLEAN; |
|
1209 |
- |
|
1207 |
+ int ret = CL_CLEAN, rc; |
|
1208 |
+ chm_metadata_t metadata; |
|
1209 |
+ char *dir; |
|
1210 |
+ unsigned int file_count = 1; |
|
1210 | 1211 |
|
1211 |
- cli_dbgmsg("in cli_scanmschm()\n"); |
|
1212 |
+ cli_dbgmsg("in cli_scanmschm()\n"); |
|
1212 | 1213 |
|
1213 |
- tempname = cli_gentemp(NULL); |
|
1214 |
- if(mkdir(tempname, 0700)) { |
|
1215 |
- cli_dbgmsg("CHM: Can't create temporary directory %s\n", tempname); |
|
1216 |
- free(tempname); |
|
1214 |
+ /* generate the temporary directory */ |
|
1215 |
+ dir = cli_gentemp(NULL); |
|
1216 |
+ if(mkdir(dir, 0700)) { |
|
1217 |
+ cli_dbgmsg("CHM: Can't create temporary directory %s\n", dir); |
|
1218 |
+ free(dir); |
|
1217 | 1219 |
return CL_ETMPDIR; |
1218 | 1220 |
} |
1219 | 1221 |
|
1220 |
- if(chm_unpack(desc, tempname)) |
|
1221 |
- ret = cli_scandir(tempname, ctx); |
|
1222 |
+ ret = cli_chm_open(desc, dir, &metadata); |
|
1223 |
+ if (ret != CL_SUCCESS) { |
|
1224 |
+ if(!cli_leavetemps_flag) |
|
1225 |
+ cli_rmdirs(dir); |
|
1226 |
+ free(dir); |
|
1227 |
+ cli_dbgmsg("CHM: Error: %s\n", cl_strerror(ret)); |
|
1228 |
+ return ret; |
|
1229 |
+ } |
|
1222 | 1230 |
|
1231 |
+ do { |
|
1232 |
+ ret = cli_chm_prepare_file(desc, dir, &metadata); |
|
1233 |
+ if (ret != CL_SUCCESS) { |
|
1234 |
+ break; |
|
1235 |
+ } |
|
1236 |
+ ret = cli_chm_extract_file(desc, dir, &metadata); |
|
1237 |
+ if (ret == CL_SUCCESS) { |
|
1238 |
+ lseek(metadata.ofd, 0, SEEK_SET); |
|
1239 |
+ rc = cli_magic_scandesc(metadata.ofd, ctx); |
|
1240 |
+ close(metadata.ofd); |
|
1241 |
+ if (rc == CL_VIRUS) { |
|
1242 |
+ cli_dbgmsg("CHM: infected with %s\n",*ctx->virname); |
|
1243 |
+ ret = CL_VIRUS; |
|
1244 |
+ break; |
|
1245 |
+ } |
|
1246 |
+ } |
|
1247 |
+ |
|
1248 |
+ } while(ret == CL_SUCCESS); |
|
1249 |
+ |
|
1223 | 1250 |
if(!cli_leavetemps_flag) |
1224 |
- cli_rmdirs(tempname); |
|
1251 |
+ cli_rmdirs(dir); |
|
1252 |
+ |
|
1253 |
+ free(dir); |
|
1254 |
+ |
|
1255 |
+ cli_chm_close(&metadata); |
|
1256 |
+ |
|
1257 |
+ cli_dbgmsg("CHM: Exit code: %d\n", ret); |
|
1258 |
+ if (ret == CL_BREAK) |
|
1259 |
+ ret = CL_CLEAN; |
|
1225 | 1260 |
|
1226 |
- free(tempname); |
|
1227 | 1261 |
return ret; |
1228 | 1262 |
} |
1229 | 1263 |
|