332 changes: 270 additions & 62 deletions tsk3/img/ewf.c
@@ -1,10 +1,12 @@
/*
* Joachim Metz <forensics@hoffmannbv.nl>, Hoffmann Investigations
* Copyright (c) 2006 Joachim Metz. All rights reserved
* The Sleuth Kit - Add on for Expert Witness Compression Format (EWF) image support
*
* ewf
* Copyright (c) 2006, 2011 Joachim Metz <jbmetz@users.sourceforge.net>
*
* This software is distributed under the Common Public License 1.0
*
* Based on raw image support of the Sleuth Kit from
* Brian Carrier.
*/

/** \file ewf.c
Expand All @@ -16,10 +18,37 @@
#if HAVE_LIBEWF
#include "ewf.h"

#define TSK_EWF_ERROR_STRING_SIZE 512


#if defined( HAVE_LIBEWF_V2_API )
/**
* Get error string from libewf and make buffer emtpy if that didn't work.
* @returns 1 if error message was not set
*/
static uint8_t
getError(libewf_error_t * ewf_error,
char error_string[TSK_EWF_ERROR_STRING_SIZE])
{
int retval;
error_string[0] = '\0';
retval = libewf_error_backtrace_sprint(ewf_error,
error_string, TSK_EWF_ERROR_STRING_SIZE);
if (retval)
return 1;
return 0;
}
#endif

static ssize_t
ewf_image_read(TSK_IMG_INFO * img_info, TSK_OFF_T offset, char *buf,
size_t len)
{
#if defined( HAVE_LIBEWF_V2_API )
char error_string[TSK_EWF_ERROR_STRING_SIZE];
libewf_error_t *ewf_error = NULL;
#endif

ssize_t cnt;
IMG_EWF_INFO *ewf_info = (IMG_EWF_INFO *) img_info;

Expand All @@ -36,17 +65,35 @@ ewf_image_read(TSK_IMG_INFO * img_info, TSK_OFF_T offset, char *buf,
}

tsk_take_lock(&(ewf_info->read_lock));
cnt = libewf_read_random(ewf_info->handle, buf, len, offset);
tsk_release_lock(&(ewf_info->read_lock));
#if defined( HAVE_LIBEWF_V2_API )
cnt = libewf_handle_read_random(ewf_info->handle,
buf, len, offset, &ewf_error);
if (cnt < 0) {
char *errmsg = NULL;
tsk_error_reset();
// @@@ Add more specific error message
tsk_error_set_errno(TSK_ERR_IMG_READ);
if (getError(ewf_error, error_string))
errmsg = strerror(errno);
else
errmsg = error_string;

tsk_error_set_errstr("ewf_image_read - offset: %" PRIuOFF
" - len: %" PRIuSIZE " - %s", offset, len, errmsg);
tsk_release_lock(&(ewf_info->read_lock));
return -1;
}
#else
cnt = libewf_read_random(ewf_info->handle, buf, len, offset);
if (cnt < 0) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_IMG_READ);
tsk_error_set_errstr("ewf_image_read - offset: %" PRIuOFF
" - len: %" PRIuSIZE " - %s", offset, len, strerror(errno));
tsk_release_lock(&(ewf_info->read_lock));
return -1;
}
#endif
tsk_release_lock(&(ewf_info->read_lock));

return cnt;
}
Expand Down Expand Up @@ -74,7 +121,14 @@ ewf_image_close(TSK_IMG_INFO * img_info)
int i;
IMG_EWF_INFO *ewf_info = (IMG_EWF_INFO *) img_info;

#if defined ( HAVE_LIBEWF_V2_API)
libewf_handle_close(ewf_info->handle, NULL);
libewf_handle_free(&(ewf_info->handle), NULL);

#else
libewf_close(ewf_info->handle);
#endif

// this stuff crashes if we used glob. v2 of the API has a free method.
// not clear from the docs what we should do in v1...
// @@@ Probably a memory leak in v1 unless libewf_close deals with it
Expand All @@ -84,6 +138,7 @@ ewf_image_close(TSK_IMG_INFO * img_info)
}
free(ewf_info->images);
}

tsk_deinit_lock(&(ewf_info->read_lock));
free(img_info);
}
Expand Down Expand Up @@ -132,43 +187,83 @@ img_file_header_signature_ncmp(const char *filename,
#endif



TSK_IMG_INFO *
ewf_open(int a_num_img, const TSK_TCHAR * const a_images[],
unsigned int a_ssize)
ewf_open(int a_num_img,
const TSK_TCHAR * const a_images[], unsigned int a_ssize)
{
IMG_EWF_INFO *ewf_info;
TSK_IMG_INFO *img_info;
#if defined( HAVE_LIBEWF_V2_API )
char error_string[TSK_EWF_ERROR_STRING_SIZE];

#if !defined( LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5 )
libewf_error_t *ewf_error = NULL;
int result = 0;
#elif !defined( LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5 )
uint8_t md5_hash[16];
#endif

IMG_EWF_INFO *ewf_info = NULL;
TSK_IMG_INFO *img_info = NULL;

#if !defined( HAVE_LIBEWF_V2_API)
if (tsk_verbose)
libewf_set_notify_values(stderr, 1);

#endif

if ((ewf_info =
(IMG_EWF_INFO *) tsk_img_malloc(sizeof(IMG_EWF_INFO))) ==
NULL) {
return NULL;
}

img_info = (TSK_IMG_INFO *) ewf_info;


// See if they specified only the first of the set...
ewf_info->used_ewf_glob = 0;
if (a_num_img == 1) {
#if defined( HAVE_LIBEWF_V2_API)
#ifdef TSK_WIN32
if (libewf_glob_wide(a_images[0], TSTRLEN(a_images[0]),
LIBEWF_FORMAT_UNKNOWN, &ewf_info->images, & ewf_info->num_imgs, &ewf_error) == -1) {
#else
if (libewf_glob(a_images[0], TSTRLEN(a_images[0]),
LIBEWF_FORMAT_UNKNOWN, &ewf_info->images, &ewf_info->num_imgs, &ewf_error) == -1) {
#endif
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_IMG_MAGIC);

getError(ewf_error, error_string);
tsk_error_set_errstr("ewf_open: Not an E01 glob name (%s)",
error_string);
libewf_error_free(&ewf_error);
free(ewf_info);
return NULL;
}

#else //use v1

#ifdef TSK_WIN32
ewf_info->num_imgs = libewf_glob_wide(a_images[0], TSTRLEN(a_images[0]), LIBEWF_FORMAT_UNKNOWN, &ewf_info->images);
ewf_info->num_imgs =
libewf_glob_wide(a_images[0], TSTRLEN(a_images[0]),
LIBEWF_FORMAT_UNKNOWN, &ewf_info->images);
#else
ewf_info->num_imgs = libewf_glob(a_images[0], TSTRLEN(a_images[0]), LIBEWF_FORMAT_UNKNOWN, &ewf_info->images);
ewf_info->num_imgs =
libewf_glob(a_images[0], TSTRLEN(a_images[0]),
LIBEWF_FORMAT_UNKNOWN, &ewf_info->images);
#endif
if (ewf_info->num_imgs <= 0) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_IMG_MAGIC);
tsk_error_set_errstr("ewf_open: Not an E01 glob name");

free(ewf_info);
return NULL;
}
#endif // end v1

ewf_info->used_ewf_glob = 1;
if (tsk_verbose)
tsk_fprintf(stderr, "ewf_open: found %d segment files via libewf_glob\n", ewf_info->num_imgs);
tsk_fprintf(stderr,
"ewf_open: found %d segment files via libewf_glob\n",
ewf_info->num_imgs);
}
else {
int i;
Expand All @@ -192,14 +287,119 @@ ewf_open(int a_num_img, const TSK_TCHAR * const a_images[],
}


/* check the magic before we call the library open */
//if (img_file_header_signature_ncmp(images[0],
// "\x45\x56\x46\x09\x0d\x0a\xff\x00", 8) != 1) {
#if defined (TSK_WIN32)
if (libewf_check_file_signature_wide(ewf_info->images[0]) == 0) {
#if defined( HAVE_LIBEWF_V2_API )

// Check the file signature before we call the library open
#if defined( TSK_WIN32 )
if (libewf_check_file_signature_wide(a_images[0], &ewf_error) != 1)
#else
if (libewf_check_file_signature(a_images[0], &ewf_error) != 1)
#endif
{
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_IMG_MAGIC);

getError(ewf_error, error_string);
tsk_error_set_errstr("ewf_open: Not an EWF file (%s)",
error_string);
libewf_error_free(&ewf_error);

free(ewf_info);

if (tsk_verbose != 0) {
tsk_fprintf(stderr, "Not an EWF file\n");
}
return (NULL);
}

if (libewf_handle_initialize(&(ewf_info->handle), &ewf_error) != 1) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_IMG_OPEN);

getError(ewf_error, error_string);
tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
": Error initializing handle (%s)", a_images[0], error_string);
libewf_error_free(&ewf_error);

free(ewf_info);

if (tsk_verbose != 0) {
tsk_fprintf(stderr, "Unable to create EWF handle\n");
}
return (NULL);
}
#if defined( TSK_WIN32 )
if (libewf_handle_open_wide(ewf_info->handle,
(wchar_t * const *) ewf_info->images,
ewf_info->num_imgs, LIBEWF_OPEN_READ, &ewf_error) != 1)
#else
if (libewf_handle_open(ewf_info->handle,
(char *const *) ewf_info->images,
ewf_info->num_imgs, LIBEWF_OPEN_READ, &ewf_error) != 1)
#endif
{
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_IMG_OPEN);

getError(ewf_error, error_string);
tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
": Error opening (%s)", a_images[0], error_string);
libewf_error_free(&ewf_error);

free(ewf_info);

if (tsk_verbose != 0) {
tsk_fprintf(stderr, "Error opening EWF file\n");
}
return (NULL);
}
if (libewf_handle_get_media_size(ewf_info->handle,
(size64_t *) & (img_info->size), &ewf_error) != 1) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_IMG_OPEN);

getError(ewf_error, error_string);
tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
": Error getting size of image (%s)", a_images[0], error_string);
libewf_error_free(&ewf_error);

free(ewf_info);

if (tsk_verbose != 0) {
tsk_fprintf(stderr, "Error getting size of EWF file\n");
}
return (NULL);
}
result = libewf_handle_get_utf8_hash_value_md5(ewf_info->handle,
(uint8_t *) ewf_info->md5hash, 33, &ewf_error);

if (result == -1) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_IMG_OPEN);

getError(ewf_error, error_string);
tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
": Error getting MD5 of image (%s)", a_images[0], error_string);
libewf_error_free(&ewf_error);

free(ewf_info);

if (tsk_verbose != 0) {
tsk_fprintf(stderr, "Error getting size of EWF file\n");
}
return (NULL);
}
ewf_info->md5hash_isset = result;

#else // V1 API

// Check the file signature before we call the library open
#if defined( TSK_WIN32 )
if (libewf_check_file_signature_wide(a_images[0]) != 1)
#else
if (libewf_check_file_signature(ewf_info->images[0]) == 0) {
if (libewf_check_file_signature(a_images[0]) != 1)
#endif
{
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_IMG_MAGIC);
tsk_error_set_errstr("ewf_open: Not an EWF file");
Expand All @@ -210,13 +410,13 @@ ewf_open(int a_num_img, const TSK_TCHAR * const a_images[],
return NULL;
}

#if defined (TSK_WIN32)
ewf_info->handle =
libewf_open_wide((wchar_t * const *) ewf_info->images,
ewf_info->num_imgs, LIBEWF_OPEN_READ);
#if defined( TSK_WIN32 )
ewf_info->handle = libewf_open_wide(
(wchar_t * const *) ewf_info->images, ewf_info->num_imgs,
LIBEWF_OPEN_READ);
#else
ewf_info->handle =
libewf_open((char *const *) ewf_info->images, ewf_info->num_imgs,
ewf_info->handle = libewf_open(
(char *const *) ewf_info->images, ewf_info->num_imgs,
LIBEWF_OPEN_READ);
#endif
if (ewf_info->handle == NULL) {
Expand All @@ -225,22 +425,22 @@ ewf_open(int a_num_img, const TSK_TCHAR * const a_images[],
tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
": Error opening", ewf_info->images[0]);
free(ewf_info);
if (tsk_verbose) {

if (tsk_verbose != 0) {
tsk_fprintf(stderr, "Error opening EWF file\n");
}
return NULL;
return (NULL);
}

// 2007 version
#if defined( LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5 )
// 2007 version
img_info->size = libewf_get_media_size(ewf_info->handle);

ewf_info->md5hash_isset = libewf_get_stored_md5_hash(ewf_info->handle,
ewf_info->md5hash, LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5);
// libewf-20080322 version
#else
// libewf-20080322 version
if (libewf_get_media_size(ewf_info->handle,
(size64_t *) & (img_info->size))
!= 1) {
(size64_t *) & (img_info->size)) != 1) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_IMG_OPEN);
tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
Expand All @@ -249,45 +449,53 @@ ewf_open(int a_num_img, const TSK_TCHAR * const a_images[],
if (tsk_verbose) {
tsk_fprintf(stderr, "Error getting size of EWF file\n");
}
return NULL;
return (NULL);
}

if (libewf_get_md5_hash(ewf_info->handle, md5_hash, 16) == 1) {
int md5_string_iterator = 0;
int md5_hash_iterator;
for (md5_hash_iterator = 0; md5_hash_iterator < 16;
md5_hash_iterator++) {
int md5_hash_iterator = 0;

for (md5_hash_iterator = 0;
md5_hash_iterator < 16; md5_hash_iterator++) {
int digit = md5_hash[md5_hash_iterator] / 16;
if (digit <= 9)
ewf_info->md5hash[md5_string_iterator++] = (char)
('0' + digit);
else
ewf_info->md5hash[md5_string_iterator++] = (char) ('a' +
(digit - 10));

if (digit <= 9) {
ewf_info->md5hash[md5_string_iterator++] =
'0' + (char) digit;
}
else {
ewf_info->md5hash[md5_string_iterator++] =
'a' + (char) (digit - 10);
}
digit = md5_hash[md5_hash_iterator] % 16;
if (digit <= 9)

if (digit <= 9) {
ewf_info->md5hash[md5_string_iterator++] =
'0' + (char) digit;
}
else {
ewf_info->md5hash[md5_string_iterator++] =
(char) ('0' + digit);
else
ewf_info->md5hash[md5_string_iterator++] = (char) ('a' +
(digit - 10));
'a' + (char) (digit - 10);
}
}
ewf_info->md5hash_isset = 1;
}
#endif
img_info->sector_size = 512;
if (a_ssize)
#endif /* defined( LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5 ) */
#endif /* defined( HAVE_LIBEWF_V2_API ) */
if (a_ssize != 0) {
img_info->sector_size = a_ssize;


}
else {
img_info->sector_size = 512;
}
img_info->itype = TSK_IMG_TYPE_EWF_EWF;
img_info->read = ewf_image_read;
img_info->close = ewf_image_close;
img_info->imgstat = ewf_image_imgstat;
img_info->read = &ewf_image_read;
img_info->close = &ewf_image_close;
img_info->imgstat = &ewf_image_imgstat;

// initialize the read lock
tsk_init_lock(&(ewf_info->read_lock));

return img_info;
return (img_info);
}
#endif
#endif /* HAVE_LIBEWF */
22 changes: 14 additions & 8 deletions tsk3/img/ewf.h
@@ -1,9 +1,9 @@
/*
* The Sleuth Kit - Add on for EWF image support
* Eye Witness Compression Format Support
* The Sleuth Kit - Add on for Expert Witness Compression Format (EWF) image support
*
* Joachim Metz <metz@studenten.net>
* Copyright (c) 2006 Joachim Metz. All rights reserved
* Copyright (c) 2006, 2011 Joachim Metz <jbmetz@users.sourceforge.net>
*
* This software is distributed under the Common Public License 1.0
*
* Based on raw image support of the Sleuth Kit from
* Brian Carrier.
Expand All @@ -13,8 +13,8 @@
* Header files for EWF-specific data structures and functions.
*/

#ifndef _EWF_H
#define _EWF_H
#ifndef _TSK_IMG_EWF_H
#define _TSK_IMG_EWF_H

#if HAVE_LIBEWF

Expand All @@ -25,6 +25,12 @@

#include <libewf.h>

// libewf version 2 no longer defines LIBEWF_HANDLE
#undef HAVE_LIBEWF_V2_API
#if !defined( LIBEWF_HANDLE )
#define HAVE_LIBEWF_V2_API
#endif

#ifdef __cplusplus
extern "C" {
#endif
Expand All @@ -34,13 +40,13 @@ extern "C" {

typedef struct {
TSK_IMG_INFO img_info;
LIBEWF_HANDLE *handle;
libewf_handle_t *handle;
char md5hash[33];
int md5hash_isset;
TSK_TCHAR **images;
int num_imgs;
uint8_t used_ewf_glob; // 1 if libewf_glob was used during open
tsk_lock_t read_lock; ///< Lock for reads since libewf is not thread safe -- only works if you have a single instance of EWF_INFO for all threads.
tsk_lock_t read_lock; ///< Lock for reads since libewf is not thread safe -- only works if you have a single instance of EWF_INFO for all threads.
} IMG_EWF_INFO;

#ifdef __cplusplus
Expand Down