diff options
author | Martin Matuska <mm@FreeBSD.org> | 2016-05-12 10:16:16 +0000 |
---|---|---|
committer | Martin Matuska <mm@FreeBSD.org> | 2016-05-12 10:16:16 +0000 |
commit | cdf63a700c77204252e3c2e38d7106965559f3c6 (patch) | |
tree | b8221b5b091ffc72b700d5da57daaa86ae023d82 /contrib/libarchive/libarchive/archive_read_support_format_rar.c | |
parent | 15c98ff2f1159f39e6c8fc585893734e4f74aa81 (diff) | |
parent | 4e579f6c9425c995106fbf72667f4ec7e5d5db85 (diff) | |
download | src-cdf63a700c77204252e3c2e38d7106965559f3c6.tar.gz src-cdf63a700c77204252e3c2e38d7106965559f3c6.zip |
Notes
Diffstat (limited to 'contrib/libarchive/libarchive/archive_read_support_format_rar.c')
-rw-r--r-- | contrib/libarchive/libarchive/archive_read_support_format_rar.c | 158 |
1 files changed, 122 insertions, 36 deletions
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_rar.c b/contrib/libarchive/libarchive/archive_read_support_format_rar.c index 99c57a0fc0eb..6450aac82785 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_rar.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_rar.c @@ -186,6 +186,7 @@ struct huffman_code { struct huffman_tree_node *tree; int numentries; + int numallocatedentries; int minlength; int maxlength; int tablesize; @@ -225,6 +226,7 @@ struct rar mode_t mode; char *filename; char *filename_save; + size_t filename_save_size; size_t filename_allocated; /* File header optional entries */ @@ -304,8 +306,15 @@ struct rar ssize_t avail_in; const unsigned char *next_in; } br; + + /* + * Custom field to denote that this archive contains encrypted entries + */ + int has_encrypted_entries; }; +static int archive_read_support_format_rar_capabilities(struct archive_read *); +static int archive_read_format_rar_has_encrypted_entries(struct archive_read *); static int archive_read_format_rar_bid(struct archive_read *, int); static int archive_read_format_rar_options(struct archive_read *, const char *, const char *); @@ -646,6 +655,12 @@ archive_read_support_format_rar(struct archive *_a) } memset(rar, 0, sizeof(*rar)); + /* + * Until enough data has been read, we cannot tell about + * any encrypted entries yet. + */ + rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; + r = __archive_read_register_format(a, rar, "rar", @@ -655,7 +670,9 @@ archive_read_support_format_rar(struct archive *_a) archive_read_format_rar_read_data, archive_read_format_rar_read_data_skip, archive_read_format_rar_seek_data, - archive_read_format_rar_cleanup); + archive_read_format_rar_cleanup, + archive_read_support_format_rar_capabilities, + archive_read_format_rar_has_encrypted_entries); if (r != ARCHIVE_OK) free(rar); @@ -663,6 +680,27 @@ archive_read_support_format_rar(struct archive *_a) } static int +archive_read_support_format_rar_capabilities(struct archive_read * a) +{ + (void)a; /* UNUSED */ + return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA + | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); +} + +static int +archive_read_format_rar_has_encrypted_entries(struct archive_read *_a) +{ + if (_a && _a->format) { + struct rar * rar = (struct rar *)_a->format->data; + if (rar) { + return rar->has_encrypted_entries; + } + } + return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; +} + + +static int archive_read_format_rar_bid(struct archive_read *a, int best_bid) { const char *p; @@ -755,7 +793,7 @@ archive_read_format_rar_options(struct archive_read *a, { struct rar *rar; int ret = ARCHIVE_FAILED; - + rar = (struct rar *)(a->format->data); if (strcmp(key, "hdrcharset") == 0) { if (val == NULL || val[0] == 0) @@ -790,6 +828,7 @@ archive_read_format_rar_read_header(struct archive_read *a, char head_type; int ret; unsigned flags; + unsigned long crc32_expected; a->archive.archive_format = ARCHIVE_FORMAT_RAR; if (a->archive.archive_format_name == NULL) @@ -797,6 +836,17 @@ archive_read_format_rar_read_header(struct archive_read *a, rar = (struct rar *)(a->format->data); + /* + * It should be sufficient to call archive_read_next_header() for + * a reader to determine if an entry is encrypted or not. If the + * encryption of an entry is only detectable when calling + * archive_read_data(), so be it. We'll do the same check there + * as well. + */ + if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { + rar->has_encrypted_entries = 0; + } + /* RAR files can be generated without EOF headers, so return ARCHIVE_EOF if * this fails. */ @@ -857,9 +907,14 @@ archive_read_format_rar_read_header(struct archive_read *a, sizeof(rar->reserved2)); } + /* Main header is password encrytped, so we cannot read any + file names or any other info about files from the header. */ if (rar->main_flags & MHD_PASSWORD) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + archive_entry_set_is_metadata_encrypted(entry, 1); + archive_entry_set_is_data_encrypted(entry, 1); + rar->has_encrypted_entries = 1; + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "RAR encryption support unavailable."); return (ARCHIVE_FATAL); } @@ -886,36 +941,50 @@ archive_read_format_rar_read_header(struct archive_read *a, skip = archive_le16dec(p + 5); if (skip < 7) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Invalid header size"); + "Invalid header size too small"); return (ARCHIVE_FATAL); } - if (skip > 7) { - if ((h = __archive_read_ahead(a, skip, NULL)) == NULL) - return (ARCHIVE_FATAL); - p = h; - } if (flags & HD_ADD_SIZE_PRESENT) { if (skip < 7 + 4) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Invalid header size"); + "Invalid header size too small"); return (ARCHIVE_FATAL); } - skip += archive_le32dec(p + 7); if ((h = __archive_read_ahead(a, skip, NULL)) == NULL) return (ARCHIVE_FATAL); p = h; + skip += archive_le32dec(p + 7); } - crc32_val = crc32(0, (const unsigned char *)p + 2, (unsigned)skip - 2); - if ((crc32_val & 0xffff) != archive_le16dec(p)) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Header CRC error"); - return (ARCHIVE_FATAL); + /* Skip over the 2-byte CRC at the beginning of the header. */ + crc32_expected = archive_le16dec(p); + __archive_read_consume(a, 2); + skip -= 2; + + /* Skim the entire header and compute the CRC. */ + crc32_val = 0; + while (skip > 0) { + size_t to_read = skip; + ssize_t did_read; + if (to_read > 32 * 1024) { + to_read = 32 * 1024; + } + if ((h = __archive_read_ahead(a, to_read, &did_read)) == NULL) { + return (ARCHIVE_FATAL); + } + p = h; + crc32_val = crc32(crc32_val, (const unsigned char *)p, (unsigned)did_read); + __archive_read_consume(a, did_read); + skip -= did_read; + } + if ((crc32_val & 0xffff) != crc32_expected) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Header CRC error"); + return (ARCHIVE_FATAL); } - __archive_read_consume(a, skip); if (head_type == ENDARC_HEAD) - return (ARCHIVE_EOF); + return (ARCHIVE_EOF); break; case NEWSUB_HEAD: @@ -938,14 +1007,18 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff, struct rar *rar = (struct rar *)(a->format->data); int ret; + if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { + rar->has_encrypted_entries = 0; + } + if (rar->bytes_unconsumed > 0) { /* Consume as much as the decompressor actually used. */ __archive_read_consume(a, rar->bytes_unconsumed); rar->bytes_unconsumed = 0; } + *buff = NULL; if (rar->entry_eof || rar->offset_seek >= rar->unp_size) { - *buff = NULL; *size = 0; *offset = rar->offset; if (*offset < rar->unp_size) @@ -957,7 +1030,7 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff, { case COMPRESS_METHOD_STORE: ret = read_data_stored(a, buff, size, offset); - break; + break; case COMPRESS_METHOD_FASTEST: case COMPRESS_METHOD_FAST: @@ -967,13 +1040,13 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff, ret = read_data_compressed(a, buff, size, offset); if (ret != ARCHIVE_OK && ret != ARCHIVE_WARN) __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc); - break; + break; default: archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Unsupported compression method for RAR file."); ret = ARCHIVE_FATAL; - break; + break; } return (ret); } @@ -1145,10 +1218,8 @@ archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset, ret -= rar->dbo[0].start_offset; /* Always restart reading the file after a seek */ - a->read_data_block = NULL; - a->read_data_offset = 0; - a->read_data_output_offset = 0; - a->read_data_remaining = 0; + __archive_reset_read_data(&a->archive); + rar->bytes_unconsumed = 0; rar->offset = 0; @@ -1290,9 +1361,14 @@ read_header(struct archive_read *a, struct archive_entry *entry, if (rar->file_flags & FHD_PASSWORD) { + archive_entry_set_is_data_encrypted(entry, 1); + rar->has_encrypted_entries = 1; archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "RAR encryption support unavailable."); - return (ARCHIVE_FATAL); + /* Since it is only the data part itself that is encrypted we can at least + extract information about the currently processed entry and don't need + to return ARCHIVE_FATAL here. */ + /*return (ARCHIVE_FATAL);*/ } if (rar->file_flags & FHD_LARGE) @@ -1377,7 +1453,7 @@ read_header(struct archive_read *a, struct archive_entry *entry, flagbyte = *(p + offset++); flagbits = 8; } - + flagbits -= 2; switch((flagbyte >> flagbits) & 3) { @@ -1469,6 +1545,7 @@ read_header(struct archive_read *a, struct archive_entry *entry, /* Split file in multivolume RAR. No more need to process header. */ if (rar->filename_save && + filename_size == rar->filename_save_size && !memcmp(rar->filename, rar->filename_save, filename_size + 1)) { __archive_read_consume(a, header_size - 7); @@ -1498,6 +1575,7 @@ read_header(struct archive_read *a, struct archive_entry *entry, rar->filename_save = (char*)realloc(rar->filename_save, filename_size + 1); memcpy(rar->filename_save, rar->filename, filename_size + 1); + rar->filename_save_size = filename_size; /* Set info for seeking */ free(rar->dbo); @@ -2345,6 +2423,8 @@ create_code(struct archive_read *a, struct huffman_code *code, { int i, j, codebits = 0, symbolsleft = numsymbols; + code->numentries = 0; + code->numallocatedentries = 0; if (new_node(code) < 0) { archive_set_error(&a->archive, ENOMEM, "Unable to allocate memory for node data."); @@ -2473,11 +2553,17 @@ static int new_node(struct huffman_code *code) { void *new_tree; - - new_tree = realloc(code->tree, (code->numentries + 1) * sizeof(*code->tree)); - if (new_tree == NULL) - return (-1); - code->tree = (struct huffman_tree_node *)new_tree; + if (code->numallocatedentries == code->numentries) { + int new_num_entries = 256; + if (code->numentries > 0) { + new_num_entries = code->numentries * 2; + } + new_tree = realloc(code->tree, new_num_entries * sizeof(*code->tree)); + if (new_tree == NULL) + return (-1); + code->tree = (struct huffman_tree_node *)new_tree; + code->numallocatedentries = new_num_entries; + } code->tree[code->numentries].branches[0] = -1; code->tree[code->numentries].branches[1] = -2; return 1; @@ -2611,7 +2697,7 @@ expand(struct archive_read *a, int64_t end) if ((symbol = read_next_symbol(a, &rar->maincode)) < 0) return (ARCHIVE_FATAL); rar->output_last_match = 0; - + if (symbol < 256) { lzss_emit_literal(rar, symbol); @@ -2834,8 +2920,8 @@ rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail) int ret; if (avail) { - if (a->read_data_is_posix_read && *avail > (ssize_t)a->read_data_requested) - *avail = a->read_data_requested; + if (a->archive.read_data_is_posix_read && *avail > (ssize_t)a->archive.read_data_requested) + *avail = a->archive.read_data_requested; if (*avail > rar->bytes_remaining) *avail = (ssize_t)rar->bytes_remaining; if (*avail < 0) |