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

Hash db rework interim commit

parent 91746004
Branches
Tags
No related merge requests found
......@@ -10,7 +10,7 @@
*/
#include "tsk/tsk_tools_i.h"
#include "tsk/auto/tsk_case_db.h"
#include "tsk/hashdb/sqlite_index.h"
#include "tsk/hashdb/lookup_result.h"
#include "jni.h"
#include "dataModel_SleuthkitJNI.h"
#include <locale.h>
......@@ -256,11 +256,11 @@ JNIEXPORT void JNICALL
}
/*
* Open a hash database to use for hash lookups. It's added to the list.
* @param env pointer to java environment this was called from
* @param obj the java object this was called from
* @param pathJ the path to the database
* @return a handle for the known bad database
* Opens a hash database to use for hash lookups.
* @param env Pointer to Java environment from which this method was called
* @param obj The Java object from which this method was called
* @param pathJ The path to the hash database
* @return A handle for the hash database
*/
JNIEXPORT jint JNICALL
Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbOpenNat(JNIEnv * env,
......@@ -282,11 +282,11 @@ JNIEXPORT jint JNICALL
}
/*
* Create a new hash db.
* @param env pointer to java environment this was called from
* @param obj the java object this was called from
* @param pathJ the path to the database
* @return a handle for the database
* Creates a new hash database.
* @param env Pointer to Java environment from which this method was called
* @param obj The Java object from which this method was called
* @param pathJ The path to the hash database.
* @return A handle for the hash database.
*/
JNIEXPORT jint JNICALL
Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbNewNat(JNIEnv * env,
......@@ -294,7 +294,7 @@ JNIEXPORT jint JNICALL
{
TSK_TCHAR pathT[1024];
toTCHAR(env, pathT, 1024, pathJ);
if (1 == tsk_hdb_create(pathT)) {
if (tsk_hdb_create(pathT)) {
setThrowTskCoreError(env);
return -1;
}
......@@ -312,14 +312,14 @@ JNIEXPORT jint JNICALL
}
/*
* Add entry to hash db.
* @param env pointer to java environment this was called from
* @param obj the java object this was called from
* @param filenameJ Name of the file that was hashed (can be empty)
* @param hashMd5J Text of MD5 hash (can be empty)
* @param hashSha1J Text of SHA1 hash (can be empty)
* @param hashSha256J Text of SHA256 hash (can be empty)
* @param dbHandle Which DB.
* Adds data to a hash database.
* @param env Pointer to Java environment from which this method was called.
* @param obj The Java object from which this method was called
* @param filenameJ Name of the file that was hashed (can be null)
* @param hashMd5J Text of MD5 hash (can be null)
* @param hashSha1J Text of SHA1 hash (can be null)
* @param hashSha256J Text of SHA256 hash (can be null)
* @param dbHandle A handle for the hash database
* @return 1 on error and 0 on success
*/
JNIEXPORT jint JNICALL
......@@ -350,8 +350,7 @@ JNIEXPORT jint JNICALL
const char * sha256 = hashSha256J ? (const char *) env->GetStringUTFChars(hashSha256J, &isCopy) : NULL;
const char * comment = commentJ ? (const char *) env->GetStringUTFChars(commentJ, &isCopy) : NULL;
int8_t retval = tsk_hdb_add_hash(db, name, md5, sha1, sha256, comment);
if (retval == 1) {
if (tsk_hdb_add_hash(db, name, md5, sha1, sha256, comment)) {
setThrowTskCoreError(env, "Failed to add records to hash database");
}
......@@ -375,15 +374,15 @@ JNIEXPORT jint JNICALL
env->ReleaseStringUTFChars(commentJ, (const char *) comment);
}
return retval;
return 0;
}
/*
* Get updateable state.
* @param env pointer to java environment this was called from
* @param obj the java object this was called from
* @param dbHandle Which DB.
* @return true if db can be updated
* Queries whether or not a hash database accepts updates.
* @param env Pointer to Java environment from which this method was called.
* @param obj The Java object from which this method was called
* @param dbHandle A handle for the hash database
* @return True if hash database can be updated
*/
JNIEXPORT jboolean JNICALL
Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbIsUpdateableNat(JNIEnv * env,
......@@ -404,14 +403,14 @@ JNIEXPORT jboolean JNICALL
}
/*
* Get reindexable state.
* @param env pointer to java environment this was called from
* @param obj the java object this was called from
* @param dbHandle Which DB.
* @return true if db is allowed to be reindexed
* Queries whether or not a hash database can be indexed.
* @param env Pointer to Java environment from which this method was called.
* @param obj The Java object from which this method was called
* @param dbHandle A handle for the hash database
* @return True if hash database can be updated
*/
JNIEXPORT jboolean JNICALL
Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbUsesExternalIndexesNat(JNIEnv * env,
Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbIsReindexableNat(JNIEnv * env,
jclass obj, jint dbHandle)
{
if((size_t)dbHandle > hashDbs.size()) {
......
......@@ -72,6 +72,7 @@ TSK_HDB_INFO *idxonly_open(const TSK_TCHAR *db_path)
hdb_info->base.db_type = TSK_HDB_DBTYPE_IDXONLY_ID;
idxonly_name(hdb_info);
hdb_info->base.uses_external_indexes = 0; // Override the "base class" setting
hdb_info->get_entry = idxonly_getentry;
hdb_info->base.make_index = idxonly_makeindex;
......
......@@ -22,7 +22,7 @@
#include <string>
#include <vector>
struct HashLookupResult
struct TskHashLookupResult
{
std::string hashMd5;
std::string hashSha1;
......
......@@ -481,13 +481,13 @@ sqlite_hdb_lookup_str(TSK_HDB_INFO * hdb_info_base, const char* hvalue,
{
int8_t ret = 0;
TSK_SQLITE_HDB_INFO *hdb_info = (TSK_SQLITE_HDB_INFO*)hdb_info_base;
hdb_info->last_id = 0;
hdb_info->last_id = 0; // RJCTODO: I don't like this...
const size_t len = strlen(hvalue)/2;
uint8_t * hashBlob = (uint8_t *) tsk_malloc(len+1);
const char * pos = hvalue;
size_t count = 0;
// Convert the string into a binary blob.
for(count = 0; count < len; count++) {
sscanf(pos, "%2hx", (short unsigned int *) &(hashBlob[count]));
pos += 2 * sizeof(char);
......@@ -521,103 +521,85 @@ sqlite_hdb_lookup_str(TSK_HDB_INFO * hdb_info_base, const char* hvalue,
* @return -1 on error, 0 if hash value not found, and 1 if value was found.
*/
int8_t
sqlite_hdb_lookup_bin(TSK_HDB_INFO * hdb_info_base, uint8_t * hvalue, uint8_t len,
TSK_HDB_FLAG_ENUM flags,
TSK_HDB_LOOKUP_FN action, void *ptr)
sqlite_hdb_lookup_bin(TSK_HDB_INFO * hdb_info_base, uint8_t * hvalue,
uint8_t len, TSK_HDB_FLAG_ENUM flags, TSK_HDB_LOOKUP_FN action, void *ptr)
{
TSK_SQLITE_HDB_INFO *hdb_info = (TSK_SQLITE_HDB_INFO*)hdb_info_base;
char hashbuf[TSK_HDB_HTYPE_SHA2_256_LEN + 1];
int8_t ret = 0;
int i;
TSK_OFF_T offset;
char * selectStmt;
sqlite3_stmt* stmt = NULL;
tsk_take_lock(&hdb_info_base->lock);
// RJCTODO: So this code depends on the hash length and type stuff...
/* Sanity check */
if ((hdb_info_base->hash_len)/2 != len) {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr("hdb_lookup: Hash passed is different size than expected: %d vs %d",
tsk_error_set_errstr("sqlite_hdb_lookup_bin: Hash passed is different size than expected: %d vs %d",
hdb_info_base->hash_len, (len * 2));
ret = -1;
} else {
if (hdb_info_base->hash_type == TSK_HDB_HTYPE_MD5_ID) {
selectStmt = "SELECT md5,database_offset,id from hashes where md5=? limit 1";
} else if (hdb_info_base->hash_type == TSK_HDB_HTYPE_SHA1_ID) {
selectStmt = "SELECT sha1,database_offset,id from hashes where sha1=? limit 1";
} else {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr("Unknown hash type: %d\n", hdb_info_base->hash_type);
ret = -1;
}
tsk_release_lock(&hdb_info_base->lock);
return -1;
}
if (hdb_info_base->hash_type == TSK_HDB_HTYPE_MD5_ID) {
selectStmt = "SELECT md5,database_offset,id from hashes where md5=? limit 1";
}
else if (hdb_info_base->hash_type == TSK_HDB_HTYPE_SHA1_ID) {
selectStmt = "SELECT sha1,database_offset,id from hashes where sha1=? limit 1";
}
else {
tsk_error_reset();
tsk_error_set_errno(TSK_ERR_HDB_ARG);
tsk_error_set_errstr("Unknown hash type: %d\n", hdb_info_base->hash_type);
tsk_release_lock(&hdb_info_base->lock);
return -1;
}
if (ret != -1) {
prepare_stmt(selectStmt, &stmt, hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite);
// RJCTODO: Why prepare a staement if it is not going to be reused?
prepare_stmt(selectStmt, &stmt, hdb_info->db);
if (attempt(sqlite3_bind_blob(stmt, 1, hvalue, len, free),
SQLITE_OK,
"Error binding binary blob: %s\n",
hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite)) {
ret = -1;
} else {
// Found a match
if (sqlite3_step(stmt) == SQLITE_ROW) {
// save id
hdb_info->idx_info->idx_struct.idx_sqlite_v1->lastId = sqlite3_column_int64(stmt, 2);
if (attempt(sqlite3_bind_blob(stmt, 1, hvalue, len, free), SQLITE_OK, "Error binding binary blob: %s\n", hdb_info->db)) {
ret = -1;
}
else {
// Found a match
if (sqlite3_step(stmt) == SQLITE_ROW) {
// RJCTODO: I do not like this at all
// save id
hdb_info->last_id = sqlite3_column_int64(stmt, 2);
if ((flags & TSK_HDB_FLAG_QUICK)
|| (hdb_info->db_type == TSK_HDB_DBTYPE_IDXONLY_ID)) {
// There is just an index, so no other info to get
///@todo Look up a name in the sqlite db
ret = 1;
} else {
// Use offset to get more info
for (i = 0; i < len; i++) {
hashbuf[2 * i] = hex[(hvalue[i] >> 4) & 0xf];
hashbuf[2 * i + 1] = hex[hvalue[i] & 0xf];
}
hashbuf[2 * len] = '\0';
offset = sqlite3_column_int64(stmt, 1);
if (hdb_info->getentry(hdb_info, hashbuf, offset, flags, action, ptr)) {
tsk_error_set_errstr2("hdb_lookup");
ret = -1;
} else {
ret = 1;
}
}
}
}
if (flags & TSK_HDB_FLAG_QUICK) {
ret = 1;
}
else {
// RJCTODO: Should have code to do the callback, if set up correctly. This code must be here, due to the delegation
// Also, the callback seems to be the motivation for the name field.
// This suggests that the name field shoudl be at the top level and the name API should be supported
}
}
}
sqlite3_reset(stmt);
// RJCTODO: This probably only needs top be done if the stmt is reused; see above.
sqlite3_reset(stmt);
if (stmt) {
finalize_stmt(stmt);
}
}
if (stmt) {
finalize_stmt(stmt);
}
tsk_release_lock(&hdb_info->lock);
tsk_release_lock(&hdb_info_base->lock);
return ret;
}
int8_t
getStrings(TSK_HDB_INFO * hdb_info, const char* selectStmt, std::vector<std::string>& out)
getStrings(sqlite3 *db, const char *selectStmt, std::vector<std::string> &out)
{
int8_t ret = 0;
sqlite3_stmt* stmt = NULL;
int len = strlen(selectStmt);
tsk_take_lock(&hdb_info->lock);
prepare_stmt(selectStmt, &stmt, hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite);
prepare_stmt(selectStmt, &stmt, db);
while (sqlite3_step(stmt) == SQLITE_ROW) {
const char* value = (const char *)sqlite3_column_text(stmt, 0);
......@@ -633,8 +615,6 @@ getStrings(TSK_HDB_INFO * hdb_info, const char* selectStmt, std::vector<std::str
finalize_stmt(stmt);
}
tsk_release_lock(&hdb_info->lock);
return ret;
}
......@@ -672,47 +652,62 @@ std::string blobToText(std::string binblob)
*
* @return -1 on error, 0 if hash value not found, and 1 if value was found.
*/
void * sqlite_v1_getAllData(TSK_HDB_INFO * hdb_info, unsigned long hashId)
void * sqlite_hdb_lookup_verbose_str(TSK_HDB_INFO *hdb_info_base, const char *hash)
{
SQliteHashStruct * h = new SQliteHashStruct();
TSK_SQLITE_HDB_INFO *hdb_info = (TSK_SQLITE_HDB_INFO*)hdb_info_base;
// RJCTODO: Need to take and release the lock here
tsk_take_lock(&hdb_info_base->lock);
// RJCTODO: Need some sanity checking here.
// RJCTODO: Need to construct some SQL that gets all of the fields,
// e.g., SELECT * FROM hashes WHERE <hash> = <value>
// And need to convert the string into a blob
// RJCTODO: Why are each of these done with separate selects?
TskHashLookupResult *result = new TskHashLookupResult(); // RJCTODO: This should be a malloc
{
std::vector<std::string> temp;
char selectStmt[1024];
snprintf(selectStmt, 1024, "SELECT md5 from hashes where id=%d", hashId);
getStrings(hdb_info, selectStmt, temp);
snprintf(selectStmt, 1024, "SELECT md5 from hashes where id=%d", hash);
getStrings(hdb_info->db, selectStmt, temp);
if (temp.size() > 0) {
h->hashMd5 = blobToText(temp.at(0));
result->hashMd5 = blobToText(temp.at(0));
}
}
{
std::vector<std::string> temp;
char selectStmt[1024];
snprintf(selectStmt, 1024, "SELECT sha1 from hashes where id=%d", hashId);
getStrings(hdb_info, selectStmt, temp);
snprintf(selectStmt, 1024, "SELECT sha1 from hashes where id=%d", hash);
getStrings(hdb_info->db, selectStmt, temp);
if (temp.size() > 0) {
h->hashSha1 = blobToText(temp.at(0));
result->hashSha1 = blobToText(temp.at(0));
}
}
{
std::vector<std::string> temp;
char selectStmt[1024];
snprintf(selectStmt, 1024, "SELECT sha2_256 from hashes where id=%d", hashId);
getStrings(hdb_info, selectStmt, temp);
snprintf(selectStmt, 1024, "SELECT sha2_256 from hashes where id=%d", hash);
getStrings(hdb_info->db, selectStmt, temp);
if (temp.size() > 0) {
h->hashSha2_256 = blobToText(temp.at(0));
result->hashSha2_256 = blobToText(temp.at(0));
}
}
{
char selectStmt[1024];
snprintf(selectStmt, 1024, "SELECT name from file_names where hash_id=%d", hashId);
getStrings(hdb_info, selectStmt, h->names);
snprintf(selectStmt, 1024, "SELECT name from file_names where hash_id=%d", hash);
getStrings(hdb_info->db, selectStmt, result->names);
}
{
char selectStmt[1024];
snprintf(selectStmt, 1024, "SELECT comment from comments where hash_id=%d", hashId);
getStrings(hdb_info, selectStmt, h->comments);
snprintf(selectStmt, 1024, "SELECT comment from comments where hash_id=%d", hash);
getStrings(hdb_info->db, selectStmt, result->comments);
}
return h;
tsk_release_lock(&hdb_info_base->lock);
return (void*)result; // RJCTODO: Need to be sure that the struct is freed
}
/*
......
/*
* 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: Should check for empty strings?
// 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);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment