c561d2a3 |
/*
* Extract component parts of OLE2 files (e.g. MS Office Documents)
*
* Copyright (C) 2004 trog@uncon.org
*
* This code is based on the OpenOffice and libgsf sources.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
|
8b242bb9 |
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
|
c561d2a3 |
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
#include <clamav.h>
|
df5ddd11 |
#if HAVE_MMAP
#if HAVE_SYS_MMAN_H
#include <sys/mman.h>
#else /* HAVE_SYS_MMAN_H */
#undef HAVE_MMAP
#endif
#endif
|
1f301ecc |
#include "cltypes.h" |
3f3c6eb5 |
#include "others.h" |
1f301ecc |
|
06f64aa7 |
#ifndef FALSE |
c561d2a3 |
#define FALSE (0)
#define TRUE (1) |
06f64aa7 |
#endif |
c561d2a3 |
|
06f64aa7 |
#ifndef MIN |
c561d2a3 |
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) |
06f64aa7 |
#endif |
c561d2a3 |
|
06bc4839 |
#if WORDS_BIGENDIAN == 0 |
04d18609 |
#define ole2_endian_convert_16(v) (v)
#else |
6537bb75 |
static uint16_t ole2_endian_convert_16(uint16_t v)
{
return ((v >> 8) + (v << 8));
}
#endif
|
06bc4839 |
#if WORDS_BIGENDIAN == 0 |
6537bb75 |
#define ole2_endian_convert_32(v) (v)
#else
static uint32_t ole2_endian_convert_32(uint32_t v)
{
return ((v >> 24) | ((v & 0x00FF0000) >> 8) |
((v & 0x0000FF00) << 8) | (v << 24));
}
#endif
|
3f3c6eb5 |
#ifndef HAVE_ATTRIB_PACKED
#define __attribute__(x)
#endif
#ifdef HAVE_PRAGMA_PACK
#pragma pack(1)
#endif
|
c561d2a3 |
typedef struct ole2_header_tag
{ |
06f64aa7 |
unsigned char magic[8] __attribute__ ((packed)); /* should be: 0xd0cf11e0a1b11ae1 */
unsigned char clsid[16] __attribute__ ((packed));
uint16_t minor_version __attribute__ ((packed));
uint16_t dll_version __attribute__ ((packed));
int16_t byte_order __attribute__ ((packed)); /* -2=intel */ |
c561d2a3 |
|
06f64aa7 |
uint16_t log2_big_block_size __attribute__ ((packed)); /* usually 9 (2^9 = 512) */
uint32_t log2_small_block_size __attribute__ ((packed)); /* usually 6 (2^6 = 128) */ |
c561d2a3 |
|
06f64aa7 |
int32_t reserved[2] __attribute__ ((packed));
int32_t bat_count __attribute__ ((packed));
int32_t prop_start __attribute__ ((packed)); |
c561d2a3 |
|
06f64aa7 |
uint32_t signature __attribute__ ((packed));
uint32_t sbat_cutoff __attribute__ ((packed)); /* cutoff for files held in small blocks (4096) */ |
c561d2a3 |
|
06f64aa7 |
int32_t sbat_start __attribute__ ((packed));
int32_t sbat_block_count __attribute__ ((packed));
int32_t xbat_start __attribute__ ((packed));
int32_t xbat_count __attribute__ ((packed));
int32_t bat_array[109] __attribute__ ((packed)); |
ee5c926e |
/* not part of the ole2 header, but stuff we need in order to decode */
/* must take account of the size of variables below here when
reading the header */ |
06f64aa7 |
int32_t sbat_root_start __attribute__ ((packed)); |
df5ddd11 |
unsigned char *m_area;
off_t m_length; |
06f64aa7 |
} ole2_header_t; |
c561d2a3 |
typedef struct property_tag
{ |
06f64aa7 |
unsigned char name[64] __attribute__ ((packed)); /* in unicode */
int16_t name_size __attribute__ ((packed));
unsigned char type __attribute__ ((packed)); /* 1=dir 2=file 5=root */
unsigned char color __attribute__ ((packed)); /* black or red */
int32_t prev __attribute__ ((packed));
int32_t next __attribute__ ((packed));
int32_t child __attribute__ ((packed));
unsigned char clsid[16] __attribute__ ((packed));
uint32_t user_flags __attribute__ ((packed));
uint32_t create_lowdate __attribute__ ((packed));
uint32_t create_highdate __attribute__ ((packed));
uint32_t mod_lowdate __attribute__ ((packed));
uint32_t mod_highdate __attribute__ ((packed));
int32_t start_block __attribute__ ((packed));
int32_t size __attribute__ ((packed));
unsigned char reserved[4] __attribute__ ((packed));
} property_t; |
c561d2a3 |
|
3f3c6eb5 |
#ifdef HAVE_PRAGMA_PACK
#pragma pack()
#endif
unsigned char magic_id[] = { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1}; |
c561d2a3 |
|
06f64aa7 |
static char *get_property_name(char *name, int size) |
c561d2a3 |
{
int i, j;
char *newname;
|
77ca88c6 |
if (*name == 0 || size <= 0 || size > 64) { |
c561d2a3 |
return NULL;
}
|
ee5c926e |
newname = (char *) cli_malloc(size*2); |
c561d2a3 |
if (!newname) {
return NULL;
}
j=0;
/* size-2 to ignore trailing NULL */
for (i=0 ; i < size-2; i+=2) {
if (isprint(name[i])) {
newname[j++] = name[i];
} else {
if (name[i] < 10 && name[i] >= 0) {
newname[j++] = '_';
newname[j++] = name[i] + '0';
}
newname[j++] = '_';
}
}
newname[j] = '\0'; |
ee5c926e |
if (strlen(newname) == 0) {
free(newname);
return NULL;
} |
c561d2a3 |
return newname;
} |
06f64aa7 |
static void print_property_name(char *pname, int size) |
655b1363 |
{
char *name;
name = get_property_name(pname, size);
if (!name) {
return;
} |
21aa0b4d |
cli_dbgmsg("%34s ", name); |
655b1363 |
free(name);
return;
} |
c561d2a3 |
|
06f64aa7 |
static void print_ole2_property(property_t *property) |
c561d2a3 |
{ |
655b1363 |
if (property->name_size > 64) {
cli_dbgmsg("[err name len: %d]\n", property->name_size);
return;
}
print_property_name(property->name, property->name_size); |
c561d2a3 |
switch (property->type) {
case 2: |
21aa0b4d |
cli_dbgmsg(" [file] "); |
c561d2a3 |
break;
case 1: |
21aa0b4d |
cli_dbgmsg(" [dir ] "); |
c561d2a3 |
break;
case 5: |
21aa0b4d |
cli_dbgmsg(" [root] "); |
c561d2a3 |
break;
default:
cli_dbgmsg(" [%d]", property->type);
}
switch (property->color) {
case 0: |
21aa0b4d |
cli_dbgmsg(" r "); |
c561d2a3 |
break;
case 1: |
21aa0b4d |
cli_dbgmsg(" b "); |
c561d2a3 |
break;
default: |
21aa0b4d |
cli_dbgmsg(" u "); |
c561d2a3 |
}
cli_dbgmsg(" %d %x\n", property->size, property->user_flags);
}
|
06f64aa7 |
static void print_ole2_header(ole2_header_t *hdr) |
c561d2a3 |
{
int i;
if (!hdr) {
return;
}
cli_dbgmsg("\nMagic:\t\t\t0x");
for (i=0 ; i<8; i++) {
cli_dbgmsg("%x", hdr->magic[i]);
}
cli_dbgmsg("\n");
cli_dbgmsg("CLSID:\t\t\t{");
for (i=0 ; i<16; i++) {
cli_dbgmsg("%x ", hdr->clsid[i]);
}
cli_dbgmsg("}\n");
cli_dbgmsg("Minor version:\t\t0x%x\n", hdr->minor_version);
cli_dbgmsg("DLL version:\t\t0x%x\n", hdr->dll_version);
cli_dbgmsg("Byte Order:\t\t%d\n", hdr->byte_order);
cli_dbgmsg("Big Block Size:\t\t%i\n", hdr->log2_big_block_size);
cli_dbgmsg("Small Block Size:\t%i\n", hdr->log2_small_block_size);
cli_dbgmsg("BAT count:\t\t%d\n", hdr->bat_count);
cli_dbgmsg("Prop start:\t\t%d\n", hdr->prop_start);
cli_dbgmsg("SBAT cutoff:\t\t%d\n", hdr->sbat_cutoff);
cli_dbgmsg("SBat start:\t\t%d\n", hdr->sbat_start);
cli_dbgmsg("SBat block count:\t%d\n", hdr->sbat_block_count);
cli_dbgmsg("XBat start:\t\t%d\n", hdr->xbat_start);
cli_dbgmsg("XBat block count:\t%d\n\n", hdr->xbat_count);
return;
}
|
06f64aa7 |
static int ole2_read_block(int fd, ole2_header_t *hdr, void *buff, int32_t blockno) |
c561d2a3 |
{ |
27af0365 |
off_t offset, offend; |
c561d2a3 |
|
e02e9f9e |
if (blockno < 0) {
return FALSE;
}
|
8a05efc5 |
/* other methods: (blockno+1) * 512 or (blockno * block_size) + 512; */ |
c561d2a3 |
offset = (blockno << hdr->log2_big_block_size) + 512; /* 512 is header size */ |
df5ddd11 |
if (hdr->m_area == NULL) {
if (lseek(fd, offset, SEEK_SET) != offset) {
return FALSE;
}
if (cli_readn(fd, buff, (1 << hdr->log2_big_block_size)) != (1 << hdr->log2_big_block_size)) {
return FALSE;
}
} else { |
27af0365 |
offend = offset + (1 << hdr->log2_big_block_size);
if ((offend <= 0) || (offend > hdr->m_length)) { |
df5ddd11 |
return FALSE;
}
memcpy(buff, hdr->m_area+offset, (1 << hdr->log2_big_block_size)); |
c561d2a3 |
}
return TRUE;
}
|
06f64aa7 |
static int32_t ole2_get_next_bat_block(int fd, ole2_header_t *hdr, int32_t current_block) |
c561d2a3 |
{ |
3f3c6eb5 |
int32_t bat_array_index; |
c561d2a3 |
uint32_t bat[128];
|
e02e9f9e |
if (current_block < 0) {
return -1;
}
|
c561d2a3 |
bat_array_index = current_block / 128;
if (bat_array_index > hdr->bat_count) {
cli_dbgmsg("bat_array index error\n");
return -10;
} |
e02e9f9e |
if (!ole2_read_block(fd, hdr, &bat,
ole2_endian_convert_32(hdr->bat_array[bat_array_index]))) {
return -1;
} |
6537bb75 |
return ole2_endian_convert_32(bat[current_block-(bat_array_index * 128)]); |
c561d2a3 |
}
|
06f64aa7 |
static int32_t ole2_get_next_xbat_block(int fd, ole2_header_t *hdr, int32_t current_block) |
c561d2a3 |
{ |
3f3c6eb5 |
int32_t xbat_index, xbat_block_index, bat_index, bat_blockno; |
c561d2a3 |
uint32_t xbat[128], bat[128];
|
e02e9f9e |
if (current_block < 0) {
return -1;
}
|
c561d2a3 |
xbat_index = current_block / 128;
/* NB: The last entry in each XBAT points to the next XBAT block.
This reduces the number of entries in each block by 1.
*/
xbat_block_index = (xbat_index - 109) / 127;
bat_blockno = (xbat_index - 109) % 127;
bat_index = current_block % 128;
|
e02e9f9e |
if (!ole2_read_block(fd, hdr, &xbat, hdr->xbat_start)) {
return -1;
} |
c561d2a3 |
/* Follow the chain of XBAT blocks */
while (xbat_block_index > 0) { |
e02e9f9e |
if (!ole2_read_block(fd, hdr, &xbat,
ole2_endian_convert_32(xbat[127]))) {
return -1;
} |
c561d2a3 |
xbat_block_index--;
}
|
e02e9f9e |
if (!ole2_read_block(fd, hdr, &bat, xbat[bat_blockno])) {
return -1;
} |
c561d2a3 |
|
6537bb75 |
return ole2_endian_convert_32(bat[bat_index]); |
c561d2a3 |
}
|
06f64aa7 |
static int32_t ole2_get_next_block_number(int fd, ole2_header_t *hdr, int32_t current_block) |
c561d2a3 |
{ |
e02e9f9e |
if (current_block < 0) {
return -1;
}
|
c561d2a3 |
if ((current_block / 128) > 108) {
return ole2_get_next_xbat_block(fd, hdr, current_block);
} else {
return ole2_get_next_bat_block(fd, hdr, current_block);
}
}
|
06f64aa7 |
static int32_t ole2_get_next_sbat_block(int fd, ole2_header_t *hdr, int32_t current_block) |
3f3c6eb5 |
{
int32_t iter, current_bat_block;
uint32_t sbat[128];
|
e02e9f9e |
if (current_block < 0) {
return -1;
}
|
3f3c6eb5 |
current_bat_block = hdr->sbat_start;
iter = current_block / 128;
while (iter > 0) {
current_bat_block = ole2_get_next_block_number(fd, hdr, current_bat_block);
iter--;
} |
e02e9f9e |
if (!ole2_read_block(fd, hdr, &sbat, current_bat_block)) {
return -1;
} |
3f3c6eb5 |
return ole2_endian_convert_32(sbat[current_block % 128]);
}
|
c561d2a3 |
/* Retrieve the block containing the data for the given sbat index */ |
06f64aa7 |
static int32_t ole2_get_sbat_data_block(int fd, ole2_header_t *hdr, void *buff, int32_t sbat_index) |
c561d2a3 |
{ |
3f3c6eb5 |
int32_t block_count, current_block; |
c561d2a3 |
|
e02e9f9e |
if (sbat_index < 0) {
return FALSE;
}
|
ee5c926e |
if (hdr->sbat_root_start < 0) { |
c561d2a3 |
cli_errmsg("No root start block\n");
return FALSE;
}
|
8a05efc5 |
block_count = sbat_index / 8; /* 8 small blocks per big block */ |
ee5c926e |
current_block = hdr->sbat_root_start; |
c561d2a3 |
while (block_count > 0) { |
3f3c6eb5 |
current_block = ole2_get_next_block_number(fd, hdr, current_block); |
c561d2a3 |
block_count--;
}
/* current_block now contains the block number of the sbat array
containing the entry for the required small block */
return(ole2_read_block(fd, hdr, buff, current_block));
}
/* Read the property tree.
It is read as just an array rather than a tree */ |
06f64aa7 |
static void ole2_read_property_tree(int fd, ole2_header_t *hdr, const char *dir, |
655b1363 |
int (*handler)(int fd, ole2_header_t *hdr, property_t *prop, const char *dir)) |
c561d2a3 |
{
property_t prop_block[4]; |
655b1363 |
int32_t index, current_block, count=0; |
c561d2a3 |
current_block = hdr->prop_start;
while(current_block >= 0) { |
e02e9f9e |
if (!ole2_read_block(fd, hdr, prop_block,
current_block)) {
return;
} |
c561d2a3 |
for (index=0 ; index < 4 ; index++) { |
ee5c926e |
if (prop_block[index].type > 0) { |
6537bb75 |
prop_block[index].name_size = ole2_endian_convert_16(prop_block[index].name_size);
prop_block[index].prev = ole2_endian_convert_32(prop_block[index].prev);
prop_block[index].next = ole2_endian_convert_32(prop_block[index].next);
prop_block[index].child = ole2_endian_convert_32(prop_block[index].child); |
736af806 |
prop_block[index].user_flags = ole2_endian_convert_32(prop_block[index].user_flags); |
6537bb75 |
prop_block[index].create_lowdate = ole2_endian_convert_32(prop_block[index].create_lowdate);
prop_block[index].create_highdate = ole2_endian_convert_32(prop_block[index].create_highdate);
prop_block[index].mod_lowdate = ole2_endian_convert_32(prop_block[index].mod_lowdate);
prop_block[index].mod_highdate = ole2_endian_convert_32(prop_block[index].mod_highdate);
prop_block[index].start_block = ole2_endian_convert_32(prop_block[index].start_block);
prop_block[index].size = ole2_endian_convert_32(prop_block[index].size); |
655b1363 |
if (prop_block[index].type > 5) {
cli_dbgmsg("ERROR: invalid property type: %d\n", prop_block[index].type);
return;
} |
c561d2a3 |
if (prop_block[index].type == 5) { |
ee5c926e |
hdr->sbat_root_start = prop_block[index].start_block; |
c561d2a3 |
}
print_ole2_property(&prop_block[index]); |
655b1363 |
if (!handler(fd, hdr, &prop_block[index], dir)) {
cli_dbgmsg("ERROR: handler failed\n");
return;
} |
c561d2a3 |
}
}
current_block = ole2_get_next_block_number(fd, hdr, current_block); |
655b1363 |
/* Loop detection */
if (++count > 100000) {
cli_dbgmsg("ERROR: loop detected\n");
return;
} |
c561d2a3 |
}
return;
}
|
17874bd1 |
static void ole2_walk_property_tree(int fd, ole2_header_t *hdr, const char *dir, int32_t prop_index,
int (*handler)(int fd, ole2_header_t *hdr, property_t *prop, const char *dir), |
21aa0b4d |
int rec_level, int *file_count, const struct cl_limits *limits) |
17874bd1 |
{
property_t prop_block[4]; |
ad1366af |
int32_t index, current_block, i; |
17874bd1 |
unsigned char *dirname;
current_block = hdr->prop_start;
|
21aa0b4d |
if ((prop_index < 0) || (rec_level > 100) || (*file_count > 100000)) {
return;
}
|
5a14dab6 |
if (limits && limits->maxfiles && (*file_count > limits->maxfiles)) { |
21aa0b4d |
cli_dbgmsg("OLE2: File limit reached (max: %d)\n", limits->maxfiles); |
17874bd1 |
return;
}
|
5a14dab6 |
if (limits && limits->maxreclevel && (rec_level > limits->maxreclevel)) {
cli_dbgmsg("OLE2: Recursion limit reached (max: %d)\n", limits->maxreclevel);
return;
}
|
17874bd1 |
index = prop_index / 4;
for (i=0 ; i < index ; i++) {
current_block = ole2_get_next_block_number(fd, hdr, current_block);
if (current_block < 0) {
return;
}
}
index = prop_index % 4;
if (!ole2_read_block(fd, hdr, prop_block,
current_block)) {
return;
}
if (prop_block[index].type <= 0) {
return;
}
prop_block[index].name_size = ole2_endian_convert_16(prop_block[index].name_size);
prop_block[index].prev = ole2_endian_convert_32(prop_block[index].prev);
prop_block[index].next = ole2_endian_convert_32(prop_block[index].next);
prop_block[index].child = ole2_endian_convert_32(prop_block[index].child);
prop_block[index].user_flags = ole2_endian_convert_32(prop_block[index].user_flags);
prop_block[index].create_lowdate = ole2_endian_convert_32(prop_block[index].create_lowdate);
prop_block[index].create_highdate = ole2_endian_convert_32(prop_block[index].create_highdate);
prop_block[index].mod_lowdate = ole2_endian_convert_32(prop_block[index].mod_lowdate);
prop_block[index].mod_highdate = ole2_endian_convert_32(prop_block[index].mod_highdate);
prop_block[index].start_block = ole2_endian_convert_32(prop_block[index].start_block);
prop_block[index].size = ole2_endian_convert_32(prop_block[index].size);
print_ole2_property(&prop_block[index]);
switch (prop_block[index].type) {
case 5: /* Root Entry */ |
87d79d4e |
if ((prop_index != 0) || (rec_level !=0) || |
21aa0b4d |
(*file_count != 0)) { |
17874bd1 |
/* Can only have RootEntry as the top */
cli_dbgmsg("ERROR: illegal Root Entry\n");
return;
}
hdr->sbat_root_start = prop_block[index].start_block;
ole2_walk_property_tree(fd, hdr, dir, |
21aa0b4d |
prop_block[index].prev, handler, rec_level+1, file_count, limits); |
17874bd1 |
ole2_walk_property_tree(fd, hdr, dir, |
21aa0b4d |
prop_block[index].next, handler, rec_level+1, file_count, limits); |
17874bd1 |
ole2_walk_property_tree(fd, hdr, dir, |
21aa0b4d |
prop_block[index].child, handler, rec_level+1, file_count, limits); |
17874bd1 |
break;
case 2: /* File */ |
21aa0b4d |
(*file_count)++; |
17874bd1 |
if (!handler(fd, hdr, &prop_block[index], dir)) {
cli_dbgmsg("ERROR: handler failed\n"); |
27af0365 |
/* If we don't return on this error then
we can sometimes pull VBA code
from corrupted files.
*/ |
21aa0b4d |
|
17874bd1 |
}
ole2_walk_property_tree(fd, hdr, dir, |
21aa0b4d |
prop_block[index].prev, handler, rec_level, file_count, limits); |
17874bd1 |
ole2_walk_property_tree(fd, hdr, dir, |
21aa0b4d |
prop_block[index].next, handler, rec_level, file_count, limits); |
17874bd1 |
ole2_walk_property_tree(fd, hdr, dir, |
21aa0b4d |
prop_block[index].child, handler, rec_level, file_count, limits); |
17874bd1 |
break;
case 1: /* Directory */
dirname = (char *) cli_malloc(strlen(dir)+8);
if (!dirname) {
return;
}
snprintf(dirname, strlen(dir)+8, "%s/%.6d", dir, prop_index); |
87d79d4e |
if (mkdir(dirname, 0700) != 0) {
free(dirname);
return;
} |
17874bd1 |
cli_dbgmsg("OLE2 dir entry: %s\n",dirname); |
a19f21b6 |
ole2_walk_property_tree(fd, hdr, dir, |
21aa0b4d |
prop_block[index].prev, handler, rec_level+1, file_count, limits); |
a19f21b6 |
ole2_walk_property_tree(fd, hdr, dir, |
21aa0b4d |
prop_block[index].next, handler, rec_level+1, file_count, limits); |
17874bd1 |
ole2_walk_property_tree(fd, hdr, dirname, |
21aa0b4d |
prop_block[index].child, handler, rec_level+1, file_count, limits); |
17874bd1 |
free(dirname);
break;
default: |
3214b258 |
cli_dbgmsg("ERROR: unknown OLE2 entry type: %d\n", prop_block[index].type); |
17874bd1 |
break;
}
return;
} |
c561d2a3 |
/* Write file Handler - write the contents of the entry to a file */ |
06f64aa7 |
static int handler_writefile(int fd, ole2_header_t *hdr, property_t *prop, const char *dir) |
c561d2a3 |
{ |
f09bbad9 |
unsigned char *buff; |
3f3c6eb5 |
int32_t current_block, ofd, len, offset; |
c561d2a3 |
char *name, *newname;
if (prop->type != 2) { |
8a05efc5 |
/* Not a file */ |
655b1363 |
return TRUE;
}
if (prop->name_size > 64) {
cli_dbgmsg("\nERROR: property name too long: %d\n", prop->name_size);
return FALSE; |
c561d2a3 |
}
if (! (name = get_property_name(prop->name, prop->name_size))) { |
ee5c926e |
/* File without a name - create a name for it */ |
ad1366af |
off_t i; |
ee5c926e |
i = lseek(fd, 0, SEEK_CUR); |
655b1363 |
name = (char *) cli_malloc(11); |
ee5c926e |
if (!name) { |
655b1363 |
return FALSE; |
ee5c926e |
} |
ad1366af |
snprintf(name, 11, "%.10ld", i + (long int) prop); |
5f90b618 |
} else {
/* Sanitize the file name */
for(newname = name; *newname; newname++) { |
12b1b744 |
#ifdef C_DARWIN |
01ad7049 |
*newname &= '\177'; |
12b1b744 |
#endif |
193c72c5 |
#if defined(MSDOS) || defined(C_CYGWIN) || defined(WIN32) || defined(C_OS2) |
5f90b618 |
if(strchr("/*?<>|\"+=,;: ", *newname))
#else
if(*newname == '/')
#endif
*newname = '_';
} |
c561d2a3 |
}
|
5f90b618 |
|
c561d2a3 |
newname = (char *) cli_malloc(strlen(name) + strlen(dir) + 2); |
acf6a6ea |
if (!newname) {
free(name);
return FALSE;
} |
c561d2a3 |
sprintf(newname, "%s/%s", dir, name);
free(name);
ofd = open(newname, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
if (ofd < 0) { |
873b5271 |
cli_errmsg("ERROR: failed to create file: %s\n", newname);
free(newname); |
655b1363 |
return FALSE; |
c561d2a3 |
}
free(newname);
current_block = prop->start_block;
len = prop->size;
|
f09bbad9 |
buff = (unsigned char *) cli_malloc(1 << hdr->log2_big_block_size);
if (!buff) {
close(ofd);
return FALSE;
}
|
c561d2a3 |
while((current_block >= 0) && (len > 0)) { |
cfa196eb |
if (prop->size < (int64_t)hdr->sbat_cutoff) { |
8a05efc5 |
/* Small block file */ |
f09bbad9 |
if (!ole2_get_sbat_data_block(fd, hdr, buff, current_block)) { |
c561d2a3 |
cli_dbgmsg("ole2_get_sbat_data_block failed\n");
close(ofd); |
f09bbad9 |
free(buff); |
655b1363 |
return FALSE; |
c561d2a3 |
} |
8a05efc5 |
/* buff now contains the block with 8 small blocks in it */ |
c561d2a3 |
offset = 64 * (current_block % 8); |
66fcd9f8 |
if (cli_writen(ofd, &buff[offset], MIN(len,64)) != MIN(len,64)) { |
c561d2a3 |
close(ofd); |
f09bbad9 |
free(buff); |
655b1363 |
return FALSE; |
c561d2a3 |
}
len -= MIN(len,64);
current_block = ole2_get_next_sbat_block(fd, hdr, current_block);
} else { |
8a05efc5 |
/* Big block file */ |
f09bbad9 |
if (!ole2_read_block(fd, hdr, buff, current_block)) { |
c561d2a3 |
close(ofd); |
f09bbad9 |
free(buff); |
655b1363 |
return FALSE; |
c561d2a3 |
} |
f09bbad9 |
if (cli_writen(ofd, buff, MIN(len,(1 << hdr->log2_big_block_size))) != |
ee5c926e |
MIN(len,(1 << hdr->log2_big_block_size))) { |
c561d2a3 |
close(ofd); |
f09bbad9 |
free(buff); |
655b1363 |
return FALSE; |
c561d2a3 |
}
current_block = ole2_get_next_block_number(fd, hdr, current_block); |
ee5c926e |
len -= MIN(len,(1 << hdr->log2_big_block_size)); |
c561d2a3 |
}
}
close(ofd); |
f09bbad9 |
free(buff); |
655b1363 |
return TRUE; |
c561d2a3 |
}
|
06f64aa7 |
static int ole2_read_header(int fd, ole2_header_t *hdr) |
3f3c6eb5 |
{
int i;
|
66fcd9f8 |
if (cli_readn(fd, &hdr->magic, 8) != 8) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->clsid, 16) != 16) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->minor_version, 2) != 2) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->dll_version, 2) != 2) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->byte_order, 2) != 2) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->log2_big_block_size, 2) != 2) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->log2_small_block_size, 4) != 4) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->reserved, 8) != 8) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->bat_count, 4) != 4) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->prop_start, 4) != 4) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->signature, 4) != 4) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->sbat_cutoff, 4) != 4) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->sbat_start, 4) != 4) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->sbat_block_count, 4) != 4) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->xbat_start, 4) != 4) { |
3f3c6eb5 |
return FALSE;
} |
66fcd9f8 |
if (cli_readn(fd, &hdr->xbat_count, 4) != 4) { |
3f3c6eb5 |
return FALSE;
}
for (i=0 ; i < 109 ; i++) { |
66fcd9f8 |
if (cli_readn(fd, &hdr->bat_array[i], 4) != 4) { |
3f3c6eb5 |
return FALSE;
}
}
return TRUE;
}
|
21aa0b4d |
int cli_ole2_extract(int fd, const char *dirname, const struct cl_limits *limits) |
c561d2a3 |
{
ole2_header_t hdr; |
3f3c6eb5 |
int hdr_size; |
df5ddd11 |
struct stat statbuf; |
21aa0b4d |
int file_count=0; |
3f3c6eb5 |
|
c561d2a3 |
cli_dbgmsg("in cli_ole2_extract()\n"); |
3f3c6eb5 |
|
ee5c926e |
/* size of header - size of other values in struct */ |
df5ddd11 |
hdr_size = sizeof(struct ole2_header_tag) - sizeof(int32_t) -
sizeof(unsigned char *) - sizeof(off_t); |
3f3c6eb5 |
|
df5ddd11 |
hdr.m_area = NULL;
#ifdef HAVE_MMAP
if (fstat(fd, &statbuf) == 0) { |
d15bc08f |
if (statbuf.st_size < hdr_size) {
return 0;
} |
df5ddd11 |
hdr.m_length = statbuf.st_size;
hdr.m_area = (unsigned char *) mmap(NULL, hdr.m_length, PROT_READ, MAP_PRIVATE, fd, 0);
if (hdr.m_area == MAP_FAILED) {
hdr.m_area = NULL; |
e1d357c4 |
} else {
cli_dbgmsg("mmap'ed file\n");
memcpy(&hdr, hdr.m_area, hdr_size); |
df5ddd11 |
} |
3f3c6eb5 |
}
#endif |
ee5c926e |
|
df5ddd11 |
if (hdr.m_area == NULL) {
#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK)
if (cli_readn(fd, &hdr, hdr_size) != hdr_size) {
return 0;
}
#else
if (!ole2_read_header(fd, &hdr)) {
return 0;
}
#endif
}
|
6537bb75 |
hdr.minor_version = ole2_endian_convert_16(hdr.minor_version);
hdr.dll_version = ole2_endian_convert_16(hdr.dll_version);
hdr.byte_order = ole2_endian_convert_16(hdr.byte_order);
hdr.log2_big_block_size = ole2_endian_convert_16(hdr.log2_big_block_size);
hdr.log2_small_block_size = ole2_endian_convert_32(hdr.log2_small_block_size);
hdr.bat_count = ole2_endian_convert_32(hdr.bat_count);
hdr.prop_start = ole2_endian_convert_32(hdr.prop_start);
hdr.sbat_cutoff = ole2_endian_convert_32(hdr.sbat_cutoff);
hdr.sbat_start = ole2_endian_convert_32(hdr.sbat_start);
hdr.sbat_block_count = ole2_endian_convert_32(hdr.sbat_block_count);
hdr.xbat_start = ole2_endian_convert_32(hdr.xbat_start);
hdr.xbat_count = ole2_endian_convert_32(hdr.xbat_count);
|
ee5c926e |
hdr.sbat_root_start = -1; |
df5ddd11 |
|
c561d2a3 |
if (strncmp(hdr.magic, magic_id, 8) != 0) {
cli_dbgmsg("OLE2 magic failed!\n"); |
873b5271 |
#ifdef HAVE_MMAP
if (hdr.m_area != NULL) {
munmap(hdr.m_area, hdr.m_length);
}
#endif |
c561d2a3 |
return CL_EOLE2;
}
if (hdr.log2_big_block_size != 9) { |
aa6994e7 |
cli_errmsg("WARNING: not scanned; untested big block size - please report\n");
goto abort; |
c561d2a3 |
}
if (hdr.log2_small_block_size != 6) { |
aa6994e7 |
cli_errmsg("WARNING: not scanned; untested small block size - please report\n");
goto abort; |
c561d2a3 |
}
if (hdr.sbat_cutoff != 4096) { |
aa6994e7 |
cli_errmsg("WARNING: not scanned; untested sbat cutoff - please report\n");
goto abort; |
c561d2a3 |
} |
df5ddd11 |
|
c561d2a3 |
print_ole2_header(&hdr);
|
17874bd1 |
/* NOTE: Select only ONE of the following two methods */
|
a19f21b6 |
/* ole2_read_property_tree(fd, &hdr, dirname, handler_writefile); */ |
17874bd1 |
/* OR */
|
21aa0b4d |
ole2_walk_property_tree(fd, &hdr, dirname, 0, handler_writefile, 0, &file_count, limits); |
df5ddd11 |
|
aa6994e7 |
abort: |
df5ddd11 |
#ifdef HAVE_MMAP
if (hdr.m_area != NULL) {
munmap(hdr.m_area, hdr.m_length);
}
#endif |
c561d2a3 |
return 0;
} |