Skip to content
Snippets Groups Projects
Commit 835cadcd authored by Richard Cordovano's avatar Richard Cordovano
Browse files

Hash db rework interim commit

parent 0a17dafe
No related branches found
No related tags found
No related merge requests found
/*
* The Sleuth Kit
*
* Brian Carrier [carrier <at> sleuthkit [dot] org]
* Copyright (c) 2003-2014 Brian Carrier. All rights reserved
*
*
* This software is distributed under the Common Public License 1.0
*/
#include "tsk_hashdb_i.h"
#include <assert.h>
#ifdef TSK_WIN32
#include <share.h>
#endif
/**
* \file hdb_open.c
* Contains the code to open and close all supported hash database types.
*/
// RJCTODO: Add internal comment
static FILE *
hdb_open_file(TSK_TCHAR *file_path)
{
FILE *file = NULL;
int fd = 0;
assert(NULL != file_path);
#ifdef TSK_WIN32
if (_wsopen_s(&fd, file_path, _O_RDONLY | _O_BINARY, _SH_DENYNO, 0)) {
file = _wfdopen(fd, L"rb");
}
#else
file = _wfdopen(fd, L"rb");
#endif
return file;
}
// RJCTODO: Add internal comment
static TSK_HDB_DBTYPE_ENUM
hdb_determine_db_type(FILE *hDb, const TSK_TCHAR *db_path)
{
const char *func_name = "hdb_determine_db_type";
TSK_HDB_DBTYPE_ENUM db_type = TSK_HDB_DBTYPE_INVALID_ID;
assert(NULL != hDb);
assert(NULL != db_path);
if (sqlite3_test(hDb)) {
fseeko(hDb, 0, SEEK_SET);
return TSK_HDB_DBTYPE_SQLITE_ID;
}
// Try each supported text-format database type to ensure a confident
// identification. Only one of the tests should succeed.
fseeko(hDb, 0, SEEK_SET);
if (nsrl_test(hDb)) {
db_type = TSK_HDB_DBTYPE_NSRL_ID;
}
fseeko(hDb, 0, SEEK_SET);
if (md5sum_test(hDb)) {
if (db_type != TSK_HDB_DBTYPE_INVALID_ID) {
fseeko(hDb, 0, SEEK_SET);
return TSK_HDB_DBTYPE_INVALID_ID;
}
db_type = TSK_HDB_DBTYPE_MD5SUM_ID;
}
fseeko(hDb, 0, SEEK_SET);
if (encase_test(hDb)) {
if (db_type != TSK_HDB_DBTYPE_INVALID_ID) {
fseeko(hDb, 0, SEEK_SET);
return TSK_HDB_DBTYPE_INVALID_ID;
}
db_type = TSK_HDB_DBTYPE_ENCASE_ID;
}
fseeko(hDb, 0, SEEK_SET);
if (hk_test(hDb)) {
if (db_type != TSK_HDB_DBTYPE_INVALID_ID) {
fseeko(hDb, 0, SEEK_SET);
return TSK_HDB_DBTYPE_INVALID_ID;
}
db_type = TSK_HDB_DBTYPE_HK_ID;
}
fseeko(hDb, 0, SEEK_SET);
return db_type;
}
/**
* \ingroup hashdblib
* Creates a new hash database.
* @param file_path Path for database to create.
* @return 0 on success, 1 otherwise
*/
uint8_t
tsk_hdb_create(TSK_TCHAR *file_path)
{
assert(NULL != file_path);
if (NULL == file_path) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr("tsk_hdb_create: NULL file path");
return 1;
}
// RJCTODO: Add enforcement of the .kdb extension here. Also to hfind.
return sqlite_hdb_create_db(file_path);
}
/**
* \ingroup hashdblib
* Opens an existing hash database.
* @param file_path Path to database or database index file.
* @param flags Flags for opening the database.
* @return Pointer to a struct representing the hash database or NULL on error.
*/
TSK_HDB_INFO *
tsk_hdb_open(TSK_TCHAR *file_path, TSK_HDB_OPEN_ENUM flags)
{
const char *func_name = "tsk_hdb_create";
uint8_t file_path_is_idx_path = 0;
TSK_TCHAR *db_path = NULL;
TSK_TCHAR *ext = NULL;
int fd = 0;
FILE *hDb = NULL;
FILE *hIdx = NULL;
TSK_HDB_DBTYPE_ENUM db_type = TSK_HDB_DBTYPE_INVALID_ID;
TSK_HDB_INFO *hdb_info = NULL;
assert(NULL != file_path);
if (NULL == file_path) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr("%s: NULL file path", func_name);
return NULL;
}
// Determine the hash database path using the given file path. Note that
// direct use of an external index file for a text-format hash database for
// simple yes/no lookups is both explicitly and implicitly supported. For
// such "index only" databases, the path to where the hash database is
// normally required to be is still needed because of the way the code for
// text-format hash databases has been written.
db_path = (TSK_TCHAR*)tsk_malloc((TSTRLEN(file_path) + 1) * sizeof(TSK_TCHAR));
if (NULL == db_path) {
return NULL;
}
ext = TSTRRCHR(file_path, _TSK_T('.'));
if ((NULL != ext) && (TSTRLEN(ext) >= 4) && (TSTRCMP(ext, _TSK_T(".idx")) == 0)) {
// The file path extension suggests the path is for an external index
// file generated by TSK for a text-format hash database. In this case,
// the database path should be the given file path sans the extension
// because the hash database, if it is available for lookups, is
// required to be be in the same directory as the external index file.
file_path_is_idx_path = 1;
TSTRNCPY(db_path, file_path, (ext - file_path));
}
else {
TSTRNCPY(db_path, file_path, TSTRLEN(file_path));
}
// Determine the database type.
if ((flags & TSK_HDB_OPEN_IDXONLY) == 0) {
hDb = hdb_open_file(db_path);
if (NULL != hDb) {
db_type = hdb_determine_db_type(hDb, db_path);
if (TSK_HDB_DBTYPE_INVALID_ID == db_type) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE);
tsk_error_set_errstr("%s: error determining hash database type of %"PRIttocTSK, func_name, db_path);
free(db_path);
return NULL;
}
}
else {
if (file_path_is_idx_path) {
db_type = TSK_HDB_DBTYPE_IDXONLY_ID;
}
else {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_OPEN);
tsk_error_set_errstr("%s: failed to open %"PRIttocTSK, func_name, db_path);
free(db_path);
return NULL;
}
}
}
else {
db_type = TSK_HDB_DBTYPE_IDXONLY_ID;
}
switch (db_type) {
case TSK_HDB_DBTYPE_NSRL_ID:
hdb_info = nsrl_open(hDb, db_path);
break;
case TSK_HDB_DBTYPE_MD5SUM_ID:
hdb_info = md5sum_open(hDb, db_path);
break;
case TSK_HDB_DBTYPE_ENCASE_ID:
hdb_info = encase_open(hDb, db_path);
break;
case TSK_HDB_DBTYPE_HK_ID:
hdb_info = hk_open(hDb, db_path);
break;
case TSK_HDB_DBTYPE_IDXONLY_ID:
hIdx = hdb_open_file(db_path);
if (NULL == hIdx) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_OPEN);
tsk_error_set_errstr("%s: database is index only, failed to open index %"PRIttocTSK, func_name, db_path);
free(db_path);
return NULL;
}
else {
fclose(hIdx);
}
hdb_info = idxonly_open(db_path);
break;
case TSK_HDB_DBTYPE_SQLITE_ID:
if (NULL != hDb) {
fclose(hDb);
}
hdb_info = sqlite_hdb_open(db_path);
break;
default:
assert(0);
}
if (NULL != db_path) {
free(db_path);
}
return hdb_info;
}
/**
* \ingroup hashdblib
* Determine if the open hash database has an index.
*
* @param hdb_info Hash database to consider
* @param htype Hash type that index should be of
*
* @return 1 if index exists and 0 if not
*/
uint8_t
tsk_hdb_has_idx(TSK_HDB_INFO * hdb_info, TSK_HDB_HTYPE_ENUM htype)
{
assert(hdb_info);
if (!hdb_info) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr("tsk_hdb_has_idx: NULL hdb_info");
return 0;
}
return (hdb_info->open_index(hdb_info, htype) == 0) ? 1 : 0;
}
/**
* \ingroup hashdblib
* Test for index only (legacy)
* Assumes that the db was opened using the TSK_HDB_OPEN_TRY option.
*
* @param hdb_info Hash database to consider
*
* @return 1 if there is only a legacy index AND no db, 0 otherwise
*/
uint8_t
tsk_hdb_is_idx_only(TSK_HDB_INFO *hdb_info)
{
assert(hdb_info);
if (!hdb_info) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr("tsk_hdb_is_idx_only: NULL hdb_info");
return 0; // RJCTODO: Not sure this is too helpful
}
return (hdb_info->db_type == TSK_HDB_DBTYPE_IDXONLY_ID);
}
/**
* \ingroup hashdblib
* Create an index for an open hash database.
* @param a_hdb_info Open hash database to index
* @param a_type Text of hash database type
* @returns 1 on error
*/
uint8_t
tsk_hdb_make_index(TSK_HDB_INFO *hdb_info, TSK_TCHAR *type)
{
assert(hdb_info);
if (!hdb_info) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr("tsk_hdb_make_index: NULL hdb_info");
return 1;
}
return hdb_info->make_index(hdb_info, type);
}
/**
* \ingroup hashdblib
* Search the index for a text/ASCII hash value
*
* @param hdb_info Open hash database (with index)
* @param hash Hash value to search for (NULL terminated string)
* @param flags Flags to use in lookup
* @param action Callback function to call for each hash db entry
* (not called if QUICK flag is given)
* @param ptr Pointer to data to pass to each callback
*
* @return -1 on error, 0 if hash value not found, and 1 if value was found.
*/
int8_t
tsk_hdb_lookup_str(TSK_HDB_INFO * hdb_info, const char *hash,
TSK_HDB_FLAG_ENUM flags, TSK_HDB_LOOKUP_FN action,
void *ptr)
{
TSK_HDB_HTYPE_ENUM htype;
assert(hdb_info);
if (!hdb_info) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr("tsk_hdb_lookup_str: NULL hdb_info");
return -1;
}
/* Sanity checks on the hash input */
if (strlen(hash) == TSK_HDB_HTYPE_MD5_LEN) {
htype = TSK_HDB_HTYPE_MD5_ID;
}
else if (strlen(hash) == TSK_HDB_HTYPE_SHA1_LEN) {
htype = TSK_HDB_HTYPE_SHA1_ID;
}
else {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr(
"tsk_hdb_lookup_str: invalid hash length: %s", hash);
return -1;
}
if (hdb_info->open_index(hdb_info, htype)) {
return -1;
}
return hdb_info->lookup_str(hdb_info, hash, flags, action, ptr);
}
/**
* \ingroup hashdblib
* Search the index for a text/ASCII hash value
*
* @param hdb_info Open hash database (with index)
* @param hash Hash value to search for (NULL terminated string)
* @param ptr Pointer to data to pass to each callback
*
* @return -1 on error, 0 if hash value not found, and the hash id if value was found.
*/
int64_t
tsk_hdb_lookup_str_id(TSK_HDB_INFO * hdb_info, const char *hash)
{
// RJCTODO: THIS MUST GO!
TSK_HDB_HTYPE_ENUM htype;
assert(hdb_info);
if (!hdb_info) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr("tsk_hdb_lookup_str_id: NULL hdb_info");
return -1;
}
/* Sanity checks on the hash input */
if (strlen(hash) == TSK_HDB_HTYPE_MD5_LEN) {
htype = TSK_HDB_HTYPE_MD5_ID;
}
else if (strlen(hash) == TSK_HDB_HTYPE_SHA1_LEN) {
htype = TSK_HDB_HTYPE_SHA1_ID;
}
else {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr(
"tsk_hdb_lookup_str_id: Invalid hash length: %s", hash);
return -1;
}
if (hdb_info->open_index(hdb_info, htype)) {
return -1;
}
// RJCTODO: This code is SQLite-specific, but probably worked due to a hack in the caller.
// Perhaps a flag and API indicatingf whether verbose lookup is supported is warranted.
// The caller is Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbLookupVerbose().
if (hdb_info->lookup_str(hdb_info, hash, TSK_HDB_FLAG_QUICK, NULL, NULL) == -1) {
return -1;
} else {
TSK_SQLITE_HDB_INFO *sqlite_hdb_info = (TSK_SQLITE_HDB_INFO*)hdb_info;
return sqlite_hdb_info->last_id;
}
}
/**
* \ingroup hashdblib
* Search the index for the given hash value given (in binary form).
*
* @param hdb_info Open hash database (with index)
* @param hash Array with binary hash value to search for
* @param len Number of bytes in binary hash value
* @param flags Flags to use in lookup
* @param action Callback function to call for each hash db entry
* (not called if QUICK flag is given)
* @param ptr Pointer to data to pass to each callback
*
* @return -1 on error, 0 if hash value not found, and 1 if value was found.
*/
int8_t
tsk_hdb_lookup_bin(TSK_HDB_INFO * hdb_info, uint8_t * hash, uint8_t len,
TSK_HDB_FLAG_ENUM flags,
TSK_HDB_LOOKUP_FN action, void *ptr)
{
TSK_HDB_HTYPE_ENUM htype;
assert(hdb_info);
if (!hdb_info) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr("tsk_hdb_lookup_raw: NULL hdb_info");
return -1;
}
/* Sanity checks on the hash input */
if (len/2 == TSK_HDB_HTYPE_MD5_LEN) {
htype = TSK_HDB_HTYPE_MD5_ID;
}
else if (len/2 == TSK_HDB_HTYPE_SHA1_LEN) {
htype = TSK_HDB_HTYPE_SHA1_ID;
}
else {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr(
"hdb_lookup_raw: Invalid hash length: %s", hash);
return -1;
}
if (hdb_info->open_index(hdb_info, htype)) {
return -1;
}
return hdb_info->lookup_raw(hdb_info, hash, len, flags, action, ptr);
}
uint8_t
tsk_hdb_has_verbose_lookup()
{
}
void *
tsk_hdb_lookup_verbose_str(TSK_HDB_INFO *hdb_info, const char *hash)
{
if (hdb_info->has_verbose_lookup()) {
return hdb_info->lookup_verbose_str(hdb_info, hash);
}
else {
// RJCTODO: Error stuff
}
}
/**
* \ingroup hashdblib
* Add a binary hash entry to the index
*
* @param hdb_info the hash database object
* @param filename Name of the file that was hashed (can be null)
* @param md5 Text of MD5 hash (can be null)
* @param sha1 Text of SHA1 hash (can be null)
* @param sha256 Text of SHA256 hash (can be null)
* @return 1 on error, 0 on success, -1 if not updateable
*/
int8_t
tsk_hdb_add_hash(TSK_HDB_INFO * hdb_info, const char *filename, const char *md5,
const char *sha1, const char *sha256, const char *comment)
{
int8_t ret = 0;
assert(hdb_info);
if (!hdb_info) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr("tsk_hdb_add_hash: NULL hdb_info");
return 1;
}
// RJCTODO: Make this right!
//if(hdb_info == NULL) {
// tsk_error_set_errstr2("tsk_hdb_add_str: null hdb_info");
// ret = 1; //error
//} else {
// uint8_t htype = TSK_HDB_HTYPE_MD5_ID;
// if (hdb_setupindex(hdb_info, htype)) {
// return 1; //error
// }
// // RJCTODO: Why is this calling SQLIte functions? Why is this not going through the proper function pointers?
// if(hdb_info->idx_info->updateable == 1) {
// ///@todo also allow use of other htypes
// char * hvalue = (char *)md5;
// if (hvalue == NULL) {
// tsk_error_set_errstr2("tsk_hdb_add_str: no hash value(s) provided");
// return 1; //error
// }
// // @todo Could set up a polymorphic mechanism like with finalize() but
// // we know it's going to be sqlite in this function.
// if (sqlite_v1_begin(hdb_info) == 1) {
// tsk_error_set_errstr2("tsk_hdb_add_str: sqlite_v1_begin failed");
// return 1; //error
// }
// // Attempt to add a new row to the hash index
// TSK_OFF_T offset = 0; //not needed since there might not be an original DB
// if (tsk_hdb_idxaddentry(hdb_info, hvalue, offset) != 0) {
// tsk_error_reset();
// tsk_error_set_errno(TSK_ERR_HDB_WRITE);
// tsk_error_set_errstr("tsk_hdb_add_str: adding entry failed");
// return 1; //error
// }
// // Add name and comment
// if (hdb_info->idx_info->idx_struct.idx_sqlite_v1->lastId != 0) {
// if ((filename != NULL) && (hdb_info->add_filename != NULL)) {
// hdb_info->add_filename(hdb_info, (char *)filename, hdb_info->idx_info->idx_struct.idx_sqlite_v1->lastId);
// }
// if ((comment != NULL) && (hdb_info->add_comment != NULL)) {
// hdb_info->add_comment(hdb_info, (char *)comment, hdb_info->idx_info->idx_struct.idx_sqlite_v1->lastId);
// }
// } else {
// ret = 1; //error
// }
// // Close the index
// if (tsk_hdb_idxfinalize(hdb_info) != 0) {
// tsk_error_reset();
// tsk_error_set_errno(TSK_ERR_HDB_WRITE);
// tsk_error_set_errstr("tsk_hdb_add_str: finalizing index failed");
// ret = 1; //error
// }
//
// } else {
// ret = -1; //not updateable
// }
//}
return ret;
}
/**
* \ingroup hashdblib
* Closes an open hash database.
* @param hdb_info database to close
*/
void
tsk_hdb_close(TSK_HDB_INFO *hdb_info)
{
assert(hdb_info);
if (!hdb_info) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr("tsk_hdb_close: NULL hdb_info");
return;
}
hdb_info->close_db(hdb_info);
}
......@@ -279,7 +279,7 @@ copy "$(LIBEWF_HOME)\msvscpp\x64\release\zlib.dll" "$(OutDir)"
<ClCompile Include="..\..\tsk\hashdb\idxonly.c" />
<ClCompile Include="..\..\tsk\hashdb\md5sum.c" />
<ClCompile Include="..\..\tsk\hashdb\nsrl.c" />
<ClCompile Include="..\..\tsk\hashdb\tsk_hashdb.c" />
<ClCompile Include="..\..\tsk\hashdb\tsk_hashdb.cpp" />
<ClCompile Include="..\..\tsk\hashdb\sqlite.cpp" />
<ClCompile Include="..\..\tsk\img\aff.c" />
<ClCompile Include="..\..\tsk\img\ewf.c" />
......
......@@ -274,7 +274,7 @@
<ClCompile Include="..\..\tsk\hashdb\text_fmt_base.c">
<Filter>hash</Filter>
</ClCompile>
<ClCompile Include="..\..\tsk\hashdb\tsk_hashdb.c">
<ClCompile Include="..\..\tsk\hashdb\tsk_hashdb.cpp">
<Filter>hash</Filter>
</ClCompile>
</ItemGroup>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment