2
* Interface to libclamunrar
3
* Copyright (C) 2007 Sourcefire, Inc.
4
* Authors: Trog, Torok Edvin, Tomasz Kojm
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License version 2.1 as published by the Free Software Foundation.
10
* This library 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 GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
21
#include "clamav-config.h"
24
/* TODO: Add support for dlopen()&Co. */
28
#include <sys/types.h>
35
#include "libclamunrar/unrar.h"
37
#include "unrar_iface.h"
39
#if WORDS_BIGENDIAN == 0
40
#define unrar_endian_convert_16(v) (v)
41
#define unrar_endian_convert_32(v) (v)
43
static uint16_t unrar_endian_convert_16(uint16_t v)
45
return ((v >> 8) + (v << 8));
47
static uint32_t unrar_endian_convert_32(uint32_t v)
49
return ((v >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | (v << 24));
57
/* FIXME: allow this to be controlled from unrar_open or so */
59
#define unrar_dbgmsg printf
61
static void unrar_dbgmsg(const char* fmt,...){}
64
static void *read_header(int fd, header_type hdr_type)
66
unsigned char encrypt_ver;
71
unrar_main_header_t *main_hdr;
73
main_hdr = (unrar_main_header_t *) malloc(sizeof(unrar_main_header_t));
77
if(read(fd, main_hdr, SIZEOF_NEWMHD) != SIZEOF_NEWMHD) {
81
main_hdr->flags = unrar_endian_convert_16(main_hdr->flags);
82
main_hdr->head_size = unrar_endian_convert_16(main_hdr->head_size);
83
main_hdr->head_crc = unrar_endian_convert_16(main_hdr->head_crc);
84
if(main_hdr->flags & MHD_ENCRYPTVER) {
85
if(read(fd, &encrypt_ver, sizeof(unsigned char)) != sizeof(unsigned char)) {
89
unrar_dbgmsg("UNRAR: RAR Encrypt version: %d\n", encrypt_ver);
94
unrar_fileheader_t *file_hdr;
96
file_hdr = (unrar_fileheader_t *) malloc(sizeof(unrar_fileheader_t));
100
if(read(fd, file_hdr, SIZEOF_NEWLHD) != SIZEOF_NEWLHD) {
104
file_hdr->flags = unrar_endian_convert_16(file_hdr->flags);
105
file_hdr->head_size = unrar_endian_convert_16(file_hdr->head_size);
106
file_hdr->pack_size = unrar_endian_convert_32(file_hdr->pack_size);
107
file_hdr->unpack_size = unrar_endian_convert_32(file_hdr->unpack_size);
108
file_hdr->file_crc = unrar_endian_convert_32(file_hdr->file_crc);
109
file_hdr->name_size = unrar_endian_convert_16(file_hdr->name_size);
110
if(file_hdr->flags & 0x100) {
111
if(read(fd, (char *) file_hdr + SIZEOF_NEWLHD, 8) != 8) {
115
file_hdr->high_pack_size = unrar_endian_convert_32(file_hdr->high_pack_size);
116
file_hdr->high_unpack_size = unrar_endian_convert_32(file_hdr->high_unpack_size);
118
file_hdr->high_pack_size = 0;
119
file_hdr->high_unpack_size = 0;
124
unrar_comment_header_t *comment_hdr;
126
comment_hdr = (unrar_comment_header_t *) malloc(sizeof(unrar_comment_header_t));
130
if(read(fd, comment_hdr, SIZEOF_COMMHEAD) != SIZEOF_COMMHEAD) {
134
comment_hdr->unpack_size = unrar_endian_convert_16(comment_hdr->unpack_size);
135
comment_hdr->comm_crc = unrar_endian_convert_16(comment_hdr->comm_crc);
139
unrar_dbgmsg("UNRAR: ERROR: Unknown header type requested\n");
145
static unrar_fileheader_t *read_block(int fd, header_type hdr_type)
147
unrar_fileheader_t *file_header;
152
offset = lseek(fd, 0, SEEK_CUR);
153
file_header = read_header(fd, FILE_HEAD);
157
file_header->start_offset = offset;
158
file_header->next_offset = offset + file_header->head_size;
159
if(file_header->flags & LONG_BLOCK)
160
file_header->next_offset += file_header->pack_size;
162
if(file_header->next_offset <= offset) {
167
/* Check if the block is of the requested type */
168
if(file_header->head_type == hdr_type) {
169
/* TODO check what to do with SUBBLOCKS */
173
unrar_dbgmsg("UNRAR: Found block type: 0x%x\n", file_header->head_type);
174
unrar_dbgmsg("UNRAR: Head Size: %.4x\n", file_header->head_size);
175
if(lseek(fd, file_header->next_offset, SEEK_SET) != file_header->next_offset) {
176
unrar_dbgmsg("seek: %ld\n", file_header->next_offset);
183
unrar_dbgmsg("UNRAR: read_block out offset=%ld\n", lseek(fd, 0, SEEK_CUR));
184
unrar_dbgmsg("UNRAR: Found file block.\n");
185
unrar_dbgmsg("UNRAR: Pack Size: %u\n", file_header->pack_size);
186
unrar_dbgmsg("UNRAR: UnPack Version: 0x%.2x\n", file_header->unpack_ver);
187
unrar_dbgmsg("UNRAR: Pack Method: 0x%.2x\n", file_header->method);
188
file_header->filename = (char *) malloc(file_header->name_size+1);
189
if(!file_header->filename) {
193
if(read(fd, file_header->filename, file_header->name_size) != file_header->name_size) {
194
free(file_header->filename);
198
file_header->filename[file_header->name_size] = '\0';
199
unrar_dbgmsg("Filename: %s\n", file_header->filename);
204
static int is_rar_archive(int fd)
207
const mark_header_t rar_hdr[2] = {{0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00}, {'U', 'n', 'i', 'q', 'u', 'E', '!'}};
210
if(read(fd, &mark, SIZEOF_MARKHEAD) != SIZEOF_MARKHEAD)
213
if(memcmp(&mark, &rar_hdr[0], SIZEOF_MARKHEAD) == 0)
216
if(memcmp(&mark, &rar_hdr[1], SIZEOF_MARKHEAD) == 0)
219
unrar_dbgmsg("UNRAR: Not a RAR archive\n");
223
static void unpack_free_data(unpack_data_t *unpack_data)
228
/*init_filters(unpack_data);*/
229
rarvm_free(&unpack_data->rarvm_data);
232
static unsigned int copy_file_data(int ifd, int ofd, unsigned int len)
234
unsigned char data[8192];
235
unsigned int todo, count, rem;
239
todo = MIN(8192, rem);
240
count = read(ifd, data, todo);
244
if(write(ofd, data, count) != (ssize_t) count)
245
return len-rem-count;
252
int unrar_open(int fd, const char *dirname, unrar_state_t *state)
256
unpack_data_t *unpack_data;
257
unrar_main_header_t *main_hdr;
264
if(!is_rar_archive(fd))
267
unpack_data = (unpack_data_t *) malloc(sizeof(unpack_data_t));
269
unrar_dbgmsg("UNRAR: malloc failed for unpack_data\n");
272
unpack_data->rarvm_data.mem = NULL;
273
unpack_data->old_filter_lengths = NULL;
274
unpack_data->PrgStack.array = unpack_data->Filters.array = NULL;
275
unpack_data->PrgStack.num_items = unpack_data->Filters.num_items = 0;
276
unpack_data->unp_crc = 0xffffffff;
278
ppm_constructor(&unpack_data->ppm_data);
279
main_hdr = read_header(fd, MAIN_HEAD);
281
ppm_destructor(&unpack_data->ppm_data);
282
rar_init_filters(unpack_data);
283
unpack_free_data(unpack_data);
287
unrar_dbgmsg("UNRAR: Head CRC: %.4x\n", main_hdr->head_crc);
288
unrar_dbgmsg("UNRAR: Head Type: %.2x\n", main_hdr->head_type);
289
unrar_dbgmsg("UNRAR: Flags: %.4x\n", main_hdr->flags);
290
unrar_dbgmsg("UNRAR: Head Size: %.4x\n", main_hdr->head_size);
292
snprintf(filename,1024,"%s/comments", dirname);
293
if(mkdir(filename,0700)) {
294
unrar_dbgmsg("UNRAR: Unable to create comment temporary directory\n");
296
ppm_destructor(&unpack_data->ppm_data);
297
rar_init_filters(unpack_data);
298
unpack_free_data(unpack_data);
302
state->comment_dir = strdup(filename);
303
if(!state->comment_dir) {
305
ppm_destructor(&unpack_data->ppm_data);
306
rar_init_filters(unpack_data);
307
unpack_free_data(unpack_data);
312
if(main_hdr->head_size < SIZEOF_NEWMHD) {
314
ppm_destructor(&unpack_data->ppm_data);
315
rar_init_filters(unpack_data);
316
unpack_free_data(unpack_data);
318
free(state->comment_dir);
322
if(main_hdr->flags & MHD_COMMENT) {
323
unrar_comment_header_t *comment_header;
324
unrar_dbgmsg("UNRAR: RAR main comment\n");
325
offset = lseek(fd, 0, SEEK_CUR);
326
unrar_dbgmsg("UNRAR: Offset: %x\n", offset);
327
comment_header = read_header(fd, COMM_HEAD);
329
unrar_dbgmsg("UNRAR: Comment type: 0x%.2x\n", comment_header->head_type);
330
unrar_dbgmsg("UNRAR: Head size: 0x%.4x\n", comment_header->head_size);
331
unrar_dbgmsg("UNRAR: UnPack Size: 0x%.4x\n", comment_header->unpack_size);
332
unrar_dbgmsg("UNRAR: UnPack Version: 0x%.2x\n", comment_header->unpack_ver);
333
unrar_dbgmsg("UNRAR: Pack Method: 0x%.2x\n", comment_header->method);
334
snprintf(filename, 1024, "%s/main.cmt", state->comment_dir);
335
ofd = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600);
337
unrar_dbgmsg("UNRAR: ERROR: Failed to open output file\n");
338
free(comment_header);
340
ppm_destructor(&unpack_data->ppm_data);
341
rar_init_filters(unpack_data);
342
unpack_free_data(unpack_data);
344
free(state->comment_dir);
347
if(comment_header->method == 0x30) {
348
unrar_dbgmsg("UNRAR: Copying stored comment (not packed)\n");
349
copy_file_data(fd, ofd, comment_header->unpack_size);
351
unpack_data->ofd = ofd;
352
unpack_data->dest_unp_size = comment_header->unpack_size;
353
unpack_data->pack_size = comment_header->head_size - SIZEOF_COMMHEAD;
354
retval = rar_unpack(fd, comment_header->unpack_ver, FALSE, unpack_data);
355
unpack_free_data(unpack_data);
359
free(comment_header);
361
lseek(fd, offset, SEEK_SET);
364
if(main_hdr->head_size > SIZEOF_NEWMHD) {
365
if(!lseek(fd, main_hdr->head_size - SIZEOF_NEWMHD, SEEK_CUR)) {
367
ppm_destructor(&unpack_data->ppm_data);
368
rar_init_filters(unpack_data);
369
unpack_free_data(unpack_data);
371
free(state->comment_dir);
376
state->unpack_data = unpack_data;
377
state->main_hdr = main_hdr;
378
state->metadata_tail = state->metadata = NULL;
379
state->file_count = 1;
380
state->offset = offset;
386
int unrar_extract_next_prepare(unrar_state_t *state, const char *dirname)
390
unrar_metadata_t *new_metadata;
391
unpack_data_t *unpack_data;
394
state->file_header = read_block(state->fd, FILE_HEAD);
395
if(!state->file_header)
396
return UNRAR_BREAK; /* end of archive */
398
new_metadata = (unrar_metadata_t *) malloc(sizeof(unrar_metadata_t));
402
new_metadata->pack_size = state->file_header->high_pack_size * 0x100000000 + state->file_header->pack_size;
403
new_metadata->unpack_size = state->file_header->high_unpack_size * 0x100000000 + state->file_header->unpack_size;
404
new_metadata->crc = state->file_header->file_crc;
405
new_metadata->method = state->file_header->method;
406
new_metadata->filename = strdup(state->file_header->filename);
407
if(!new_metadata->filename) {
411
new_metadata->next = NULL;
412
new_metadata->encrypted = FALSE;
413
if(state->metadata_tail == NULL) {
414
state->metadata_tail = state->metadata = new_metadata;
416
state->metadata_tail->next = new_metadata;
417
state->metadata_tail = new_metadata;
419
if(state->file_header->flags & LHD_COMMENT) {
420
unrar_comment_header_t *comment_header;
422
unrar_dbgmsg("UNRAR: File comment present\n");
423
comment_header = read_header(state->fd, COMM_HEAD);
425
unrar_dbgmsg("UNRAR: Comment type: 0x%.2x\n", comment_header->head_type);
426
unrar_dbgmsg("UNRAR: Head size: 0x%.4x\n", comment_header->head_size);
427
unrar_dbgmsg("UNRAR: UnPack Size: 0x%.4x\n", comment_header->unpack_size);
428
unrar_dbgmsg("UNRAR: UnPack Version: 0x%.2x\n", comment_header->unpack_ver);
429
unrar_dbgmsg("UNRAR: Pack Method: 0x%.2x\n", comment_header->method);
431
if((comment_header->unpack_ver < 15) || (comment_header->unpack_ver > 29) || (comment_header->method > 0x30)) {
432
unrar_dbgmsg("UNRAR: Can't process file comment - skipping\n");
434
snprintf(filename, 1024, "%s/%lu.cmt", state->comment_dir, state->file_count);
435
ofd = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600);
437
free(comment_header);
438
unrar_dbgmsg("UNRAR: ERROR: Failed to open output file\n");
440
unrar_dbgmsg("UNRAR: Copying file comment (not packed)\n");
441
copy_file_data(state->fd, ofd, comment_header->unpack_size);
445
free(comment_header);
452
int unrar_extract_next(unrar_state_t *state, const char *dirname)
456
unpack_data_t *unpack_data;
459
if(lseek(state->fd, state->file_header->start_offset+state->file_header->head_size, SEEK_SET) != state->file_header->start_offset+state->file_header->head_size) {
460
unrar_dbgmsg("UNRAR: Seek failed: %ld\n", state->offset+state->file_header->head_size);
461
free(state->file_header->filename);
462
free(state->file_header);
466
if(state->file_header->flags & LHD_PASSWORD) {
467
unrar_dbgmsg("UNRAR: PASSWORDed file: %s\n", state->file_header->filename);
468
state->metadata_tail->encrypted = TRUE;
469
} else if(state->file_header->flags & (LHD_SPLIT_BEFORE | LHD_SPLIT_AFTER)) {
470
unrar_dbgmsg("UNRAR: Skipping split file\n");
472
} else if((state->main_hdr->flags & MHD_VOLUME) && (state->main_hdr->flags & MHD_SOLID)) {
473
unrar_dbgmsg("UNRAR: Skipping file inside multi-volume solid archive\n");
476
snprintf(state->filename, 1024, "%s/%lu.ura", dirname, state->file_count);
477
ofd = open(state->filename, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600);
479
free(state->file_header->filename);
480
free(state->file_header);
481
unrar_dbgmsg("UNRAR: ERROR: Failed to open output file\n");
484
unpack_data = (unpack_data_t *) state->unpack_data;
485
state->ofd = unpack_data->ofd = ofd;
486
if(state->file_header->method == 0x30) {
487
unrar_dbgmsg("UNRAR: Copying stored file (not packed)\n");
488
copy_file_data(state->fd, ofd, state->file_header->pack_size);
490
unpack_data->dest_unp_size = state->file_header->unpack_size;
491
unpack_data->pack_size = state->file_header->pack_size;
492
if(state->file_header->unpack_ver <= 15) {
493
retval = rar_unpack(state->fd, 15, (state->file_count>1) && ((state->main_hdr->flags&MHD_SOLID)!=0), unpack_data);
495
if((state->file_count == 1) && (state->file_header->flags & LHD_SOLID)) {
496
unrar_dbgmsg("UNRAR: Bad header. First file can't be SOLID.\n");
497
unrar_dbgmsg("UNRAR: Clearing flag and continuing.\n");
498
state->file_header->flags -= LHD_SOLID;
500
retval = rar_unpack(state->fd, state->file_header->unpack_ver, state->file_header->flags & LHD_SOLID, unpack_data);
502
unrar_dbgmsg("UNRAR: Expected File CRC: 0x%x\n", state->file_header->file_crc);
503
unrar_dbgmsg("UNRAR: Computed File CRC: 0x%x\n", unpack_data->unp_crc^0xffffffff);
504
if(unpack_data->unp_crc != 0xffffffff) {
505
if(state->file_header->file_crc != (unpack_data->unp_crc^0xffffffff)) {
506
unrar_dbgmsg("UNRAR: RAR CRC error. If the file is not corrupted, please report at http://bugs.clamav.net/\n");
510
unrar_dbgmsg("UNRAR: Corrupt file detected\n");
511
if(state->file_header->flags & LHD_SOLID) {
512
unrar_dbgmsg("UNRAR: SOLID archive, can't continue\n");
513
free(state->file_header->filename);
514
free(state->file_header);
521
if(lseek(state->fd, state->file_header->next_offset, SEEK_SET) != state->file_header->next_offset) {
522
unrar_dbgmsg("UNRAR: ERROR: seek failed: %ld\n", state->file_header->next_offset);
523
free(state->file_header->filename);
524
free(state->file_header);
528
free(state->file_header->filename);
529
free(state->file_header);
530
unpack_free_data(state->unpack_data);
535
void unrar_close(unrar_state_t *state)
537
unpack_data_t *unpack_data = state->unpack_data;
539
ppm_destructor(&unpack_data->ppm_data);
540
free(state->main_hdr);
541
rar_init_filters(state->unpack_data);
542
unpack_free_data(state->unpack_data);
543
free(state->unpack_data);
544
free(state->comment_dir);