diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.cpp b/bindings/java/jni/dataModel_SleuthkitJNI.cpp index 5ceffbe3bc0654c42c8c8f0226b1d89d6948b7bf..e4baa1abd4665b0489ddedd201111b767abd175d 100644 --- a/bindings/java/jni/dataModel_SleuthkitJNI.cpp +++ b/bindings/java/jni/dataModel_SleuthkitJNI.cpp @@ -3,7 +3,7 @@ ** The Sleuth Kit ** ** Brian Carrier [carrier <at> sleuthkit [dot] org] - ** Copyright (c) 2010-2013 Brian Carrier. All Rights reserved + ** Copyright (c) 2010-2014 Brian Carrier. All Rights reserved ** ** This software is distributed under the Common Public License 1.0 ** @@ -24,10 +24,8 @@ using std::string; using std::vector; using std::map; using std::stringstream; -using std::for_each; -static int m_nsrlHandle = -1; -static std::vector<TSK_HDB_INFO *> m_hashDbs; +static std::vector<TSK_HDB_INFO *> hashDbs; /* * JNI file handle structure encapsulates both @@ -257,7 +255,6 @@ JNIEXPORT void JNICALL return; } - /* * 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 @@ -267,25 +264,21 @@ JNIEXPORT void JNICALL */ JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbOpenNat(JNIEnv * env, - jclass obj, jstring pathJ) { - + jclass obj, jstring pathJ) +{ TSK_TCHAR pathT[1024]; toTCHAR(env, pathT, 1024, pathJ); - - ///@todo Check if the db_file passed in is really an index filename - - TSK_HDB_OPEN_ENUM flags = TSK_HDB_OPEN_NONE; - TSK_HDB_INFO * temp = tsk_hdb_open(pathT, flags); - - if(temp == NULL) + TSK_HDB_INFO *db = tsk_hdb_open(pathT, TSK_HDB_OPEN_NONE); + if(!db) { setThrowTskCoreError(env); return -1; } - - m_hashDbs.push_back(temp); - return m_hashDbs.size(); + // The index of the pointer in the vector is used as a handle for the + // database. + hashDbs.push_back(db); + return hashDbs.size(); } /* @@ -301,7 +294,6 @@ JNIEXPORT jint JNICALL { TSK_TCHAR pathT[1024]; toTCHAR(env, pathT, 1024, pathJ); - if (1 == tsk_hdb_create(pathT)) { setThrowTskCoreError(env); return -1; @@ -313,9 +305,10 @@ JNIEXPORT jint JNICALL return -1; } - m_hashDbs.push_back(db); - - return m_hashDbs.size(); + // The index of the pointer in the vector is used as a handle for the + // database. + hashDbs.push_back(db); + return hashDbs.size(); } /* @@ -334,12 +327,12 @@ JNIEXPORT jint JNICALL jclass obj, jstring filenameJ, jstring hashMd5J, jstring hashSha1J, jstring hashSha256J, jstring commentJ, jint dbHandle) { - if((size_t) dbHandle > m_hashDbs.size()) { + if((size_t) dbHandle > hashDbs.size()) { setThrowTskCoreError(env, "Invalid database handle"); return 1; } - TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1); + TSK_HDB_INFO * db = hashDbs.at(dbHandle-1); if(!db) { setThrowTskCoreError(env, "Invalid database handle"); return 1; @@ -357,7 +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_str(db, name, md5, sha1, sha256, comment); + int8_t retval = tsk_hdb_add_hash(db, name, md5, sha1, sha256, comment); if (retval == 1) { setThrowTskCoreError(env, "Failed to add records to hash database"); } @@ -396,18 +389,18 @@ JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbIsUpdateableNat(JNIEnv * env, jclass obj, jint dbHandle) { - bool retval = false; - - if((size_t) dbHandle > m_hashDbs.size()) { + if((size_t)dbHandle > hashDbs.size()) { setThrowTskCoreError(env, "Invalid database handle"); - } else { - TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1); + return (jboolean)false; + } - if(db != NULL) { - retval = (db->idx_info->updateable == 1) ? true : false; - } + TSK_HDB_INFO *db = hashDbs.at(dbHandle-1); + if (db == NULL) { + setThrowTskCoreError(env, "Invalid database handle"); + return (jboolean)false; } - return retval; + + return (jboolean)(db->updateable == 1); } /* @@ -418,23 +411,21 @@ JNIEXPORT jboolean JNICALL * @return true if db is allowed to be reindexed */ JNIEXPORT jboolean JNICALL - Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbIsReindexableNat(JNIEnv * env, + Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbUsesExternalIndexesNat(JNIEnv * env, jclass obj, jint dbHandle) { - bool retval = false; - - if((size_t) dbHandle > m_hashDbs.size()) { + if((size_t)dbHandle > hashDbs.size()) { setThrowTskCoreError(env, "Invalid database handle"); - } else { - TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1); + return (jboolean)false; + } - if(db != NULL) { - if (db->hDb != NULL) { - retval = true; - } - } + TSK_HDB_INFO *db = hashDbs.at(dbHandle-1); + if (db == NULL) { + setThrowTskCoreError(env, "Invalid database handle"); + return (jboolean)false; } - return retval; + + return (jboolean)(db->uses_external_indexes == 1); } /* @@ -449,112 +440,29 @@ JNIEXPORT jstring JNICALL jclass obj, jint dbHandle) { char cpath[1024]; - char * none = "None"; //on error or if no name is available + char *none = "None"; //on error or if no name is available // RJCTODO: Go back to using null if possible...or empty string - if((size_t) dbHandle > m_hashDbs.size()) { + if((size_t)dbHandle > hashDbs.size()) { setThrowTskCoreError(env, "Invalid database handle"); return env->NewStringUTF(none); - } else { - TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1); - - - // Index might not be set up yet - if(tsk_hdb_idxsetup(db, db->hash_type)) { - // If this is a Tsk SQLite db+index, then use index fname as db fname. - if ((db->db_type == TSK_HDB_DBTYPE_IDXONLY_ID) && - (db->idx_info->index_type == TSK_HDB_ITYPE_SQLITE_V1)) { - - snprintf(cpath, 1024, "%" PRIttocTSK, db->idx_info->idx_fname); - jstring jname = env->NewStringUTF(cpath); - return jname; - } - } - - // Otherwise, try using the db fname. - if((db != NULL) && (db->hDb != NULL)) { - snprintf(cpath, 1024, "%" PRIttocTSK, db->db_fname); - jstring jname = env->NewStringUTF(cpath); - return jname; - } else { - return env->NewStringUTF(none); - } - } -} - -/* - * Get index path. - * @param env pointer to java environment this was called from - * @param obj the java object this was called from - * @param dbHandle Which DB. - * @return path - */ -JNIEXPORT jstring JNICALL - Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbIndexPathNat(JNIEnv * env, - jclass obj, jint dbHandle) -{ - char cpath[1024]; - char * none = "None"; //on error or if no name is available - - if((size_t) dbHandle > m_hashDbs.size()) { + TSK_HDB_INFO *db = hashDbs.at(dbHandle-1); + if (db == NULL) { setThrowTskCoreError(env, "Invalid database handle"); return env->NewStringUTF(none); - } else { - TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1); - if (db == NULL) { - setThrowTskCoreError(env, "Invalid database"); - return env->NewStringUTF(none); - } - - ///@todo there isn't a db type for this (would be needed to get legacy index filename) - /*if(db->db_type == TSK_HDB_DBTYPE_NSRL_SHA1_ID) { - db->hash_type = TSK_HDB_HTYPE_SHA1_ID; - }*/ - //else { - db->hash_type = TSK_HDB_HTYPE_MD5_ID; - //} - - // Call setup to populate the idx_info struct so we can get the filename // RJCTODO: WTF? - tsk_hdb_idxsetup(db, db->hash_type); - - if(db->idx_info != NULL) { - snprintf(cpath, 1024, "%" PRIttocTSK, db->idx_info->idx_fname); - jstring jname = env->NewStringUTF(cpath); - return jname; - } else { - return env->NewStringUTF(none); - } - } -} - - -/* - * Test for index only (no original Db file) legacy (IDX format). - * @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 index only AND is legacy - */ -JNIEXPORT jboolean JNICALL - Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbIsIdxOnlyNat(JNIEnv * env, - jclass obj, jint dbHandle) -{ - bool retval = false; - - if((size_t) dbHandle > m_hashDbs.size()) { - setThrowTskCoreError(env, "Invalid database handle"); - } else { - TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1); + } - if(db != NULL) { - retval = (tsk_hdb_is_idxonly(db) == 1) ? true : false; - } + if((db->db_fname != NULL)) { + snprintf(cpath, 1024, "%" PRIttocTSK, db->db_fname); + jstring jname = env->NewStringUTF(cpath); + return jname; + } + else { + return env->NewStringUTF(none); } - return retval; } - /* * Get the name of the database pointed to by path * @param env pointer to java environment this was called from @@ -564,20 +472,22 @@ JNIEXPORT jboolean JNICALL JNIEXPORT jstring JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbGetName (JNIEnv * env, jclass obj, jint dbHandle) { - if((size_t) dbHandle > m_hashDbs.size()) { - setThrowTskCoreError(env, "Invalid database handle"); - return env->NewStringUTF("-1"); - } else { - TSK_HDB_INFO * temp = m_hashDbs.at(dbHandle-1); - if (temp == NULL) { - setThrowTskCoreError(env, "Error: database object is null"); - return env->NewStringUTF("-1"); - } - - - jstring jname = env->NewStringUTF(temp->db_name); - return jname; - } + // RJCTODO: Decide the fate of this + //if((size_t) dbHandle > hashDbs.size()) { + // setThrowTskCoreError(env, "Invalid database handle"); + // return env->NewStringUTF("-1"); + //} else { + // TSK_HDB_INFO * temp = hashDbs.at(dbHandle-1); + // if (temp == NULL) { + // setThrowTskCoreError(env, "Error: database object is null"); + // return env->NewStringUTF("-1"); + // } + + + // jstring jname = env->NewStringUTF(temp->db_name); + // return jname; + //} + return env->NewStringUTF("-1"); } /* @@ -589,13 +499,15 @@ JNIEXPORT jstring JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbGetNam */ JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbCloseAll(JNIEnv * env, - jclass obj) { - - for_each(m_hashDbs.begin(), m_hashDbs.end(), tsk_hdb_close); - - m_hashDbs.clear(); + jclass obj) +{ + for (std::vector<TSK_HDB_INFO *>::iterator it = hashDbs.begin(); it != hashDbs.end(); ++it) { + if (NULL != *it) { + tsk_hdb_close(*it); + } + } - m_nsrlHandle = -1; + hashDbs.clear(); } /* @@ -607,65 +519,60 @@ JNIEXPORT void JNICALL */ JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbClose(JNIEnv * env, - jclass obj, jint dbHandle) { - - if((size_t) dbHandle > m_hashDbs.size()) { + jclass obj, jint dbHandle) +{ + if((size_t)dbHandle > hashDbs.size()) { setThrowTskCoreError(env, "Invalid database handle"); - } else { - TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1); + return; + } - if(db != NULL) { - tsk_hdb_close(db); + TSK_HDB_INFO *db = hashDbs.at(dbHandle-1); + if (db == NULL) { + setThrowTskCoreError(env, "Invalid database handle"); + return; + } - // We do NOT erase the element because that would shift the indices, - // messing up the existing handles. - m_hashDbs.at(dbHandle-1) = NULL; + tsk_hdb_close(db); - if (m_nsrlHandle == dbHandle) { - m_nsrlHandle = -1; - } - } - } + // Do NOT erase the element because that would shift the indices, + // messing up the existing handles. + hashDbs.at(dbHandle-1) = NULL; } - /* * Class: org_sleuthkit_datamodel_SleuthkitJNI * Method: hashDbLookup * Signature: (Ljava/lang/String;)I */ JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbLookup -(JNIEnv * env, jclass obj, jstring hash, jint dbHandle) { +(JNIEnv * env, jclass obj, jstring hash, jint dbHandle) +{ + if((size_t)dbHandle > hashDbs.size()) { + setThrowTskCoreError(env, "Invalid database handle"); + return (jboolean)false; + } - if((size_t) dbHandle > m_hashDbs.size()) { + TSK_HDB_INFO *db = hashDbs.at(dbHandle-1); + if (db == NULL) { setThrowTskCoreError(env, "Invalid database handle"); - return -1; + return (jboolean)false; } jboolean isCopy; - const char *md5 = (const char *) env->GetStringUTFChars(hash, &isCopy); - //TSK_DB_FILES_KNOWN_ENUM file_known = TSK_DB_FILES_KNOWN_UNKNOWN; jboolean file_known = false; - - - TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1); - - if(db != NULL) { - int8_t retval = tsk_hdb_lookup_str(db, md5, TSK_HDB_FLAG_QUICK, NULL, NULL); - - if (retval == -1) { - setThrowTskCoreError(env); - } else if (retval) { - //file_known = TSK_DB_FILES_KNOWN_KNOWN_BAD; - file_known = true; - } + int8_t retval = tsk_hdb_lookup_str(db, md5, TSK_HDB_FLAG_QUICK, NULL, NULL); + if (retval == -1) { + setThrowTskCoreError(env); + } + else if (retval) { + file_known = true; } env->ReleaseStringUTFChars(hash, (const char *) md5); - return (int) file_known; + return file_known; } /* @@ -675,68 +582,75 @@ JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbLooku */ JNIEXPORT jobject JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbLookupVerbose (JNIEnv * env, jclass obj, jstring hash, jint dbHandle) { + + // RJCTODO: This is the troubling stuff that needs to be enhanced with + // a query to determine if verbose lookup is supported; there then needs + // to be a function ptr in the TSKDHB_INFO to handle this; + // need to check to see how Sam's new code is handling this for the sake of integration + // (or is there code in this code base in AbstractAbstractFileNode?) + jobject object = NULL; SQliteHashStruct * hdata = NULL; - if((size_t) dbHandle > m_hashDbs.size()) { - setThrowTskCoreError(env, "Invalid database handle"); - return NULL; - } - - jboolean isCopy; - const char *inputHash = (const char *) env->GetStringUTFChars(hash, &isCopy); - - TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1); - if (db != NULL) { - // tsk_hdb_lookup_str will also make sure the index struct is setup - int64_t hashId = tsk_hdb_lookup_str_id(db, inputHash); - - if ((hashId > 0) && (db->idx_info->getAllData != NULL)) { - // Find the data associated with this hash - hdata = (SQliteHashStruct *)(db->idx_info->getAllData(db, hashId)); - - // Build the Java version of the HashInfo object - jclass clazz; - clazz = env->FindClass("org/sleuthkit/datamodel/HashInfo"); - // get methods - jmethodID ctor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - jmethodID addName = env->GetMethodID(clazz, "addName", "(Ljava/lang/String;)V"); - jmethodID addComment = env->GetMethodID(clazz, "addComment", "(Ljava/lang/String;)V"); - - //convert hashes - const char *md5 = hdata->hashMd5.c_str(); - jstring md5j = env->NewStringUTF(md5); - - const char *sha1 = hdata->hashSha1.c_str(); - jstring sha1j = env->NewStringUTF(sha1); - - const char *sha256 = hdata->hashSha2_256.c_str(); - jstring sha256j = env->NewStringUTF(sha256); - - // make the object - object = env->NewObject(clazz, ctor, md5j, sha1j, sha256j); - - // finish populating the object - std::vector<std::string>::iterator name_it = hdata->names.begin(); - for (; name_it != hdata->names.end(); ++name_it) { - const char *name = name_it->c_str(); - jstring namej = env->NewStringUTF(name); - env->CallVoidMethod(object, addName, namej); - } - - std::vector<std::string>::iterator comment_it = hdata->comments.begin(); - for (; comment_it != hdata->comments.end(); ++comment_it) { - const char *comment = comment_it->c_str(); - jstring commentj = env->NewStringUTF(comment); - env->CallVoidMethod(object, addComment, commentj); - } - - } - } - - // Cleanup - env->ReleaseStringUTFChars(hash, (const char *) inputHash); - delete hdata; + //if((size_t) dbHandle > hashDbs.size()) { + // setThrowTskCoreError(env, "Invalid database handle"); + // return NULL; + //} + + //jboolean isCopy; + //const char *inputHash = (const char *) env->GetStringUTFChars(hash, &isCopy); + + //TSK_HDB_INFO * db = hashDbs.at(dbHandle-1); + //if (db != NULL) { + // // tsk_hdb_lookup_str will also make sure the index struct is setup + // int64_t hashId = tsk_hdb_lookup_str_id(db, inputHash); + + // if ((hashId > 0) && (db->idx_info->getAllData != NULL)) { + // // Find the data associated with this hash + // hdata = (SQliteHashStruct *)(db->idx_info->getAllData(db, hashId)); + + // // Build the Java version of the HashInfo object + // jclass clazz; + // clazz = env->FindClass("org/sleuthkit/datamodel/HashInfo"); + // // get methods + // jmethodID ctor = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + // jmethodID addName = env->GetMethodID(clazz, "addName", "(Ljava/lang/String;)V"); + // jmethodID addComment = env->GetMethodID(clazz, "addComment", "(Ljava/lang/String;)V"); + + // //convert hashes + // const char *md5 = hdata->hashMd5.c_str(); + // jstring md5j = env->NewStringUTF(md5); + // + // const char *sha1 = hdata->hashSha1.c_str(); + // jstring sha1j = env->NewStringUTF(sha1); + // + // const char *sha256 = hdata->hashSha2_256.c_str(); + // jstring sha256j = env->NewStringUTF(sha256); + + // // make the object + // object = env->NewObject(clazz, ctor, md5j, sha1j, sha256j); + + // // finish populating the object + // std::vector<std::string>::iterator name_it = hdata->names.begin(); + // for (; name_it != hdata->names.end(); ++name_it) { + // const char *name = name_it->c_str(); + // jstring namej = env->NewStringUTF(name); + // env->CallVoidMethod(object, addName, namej); + // } + + // std::vector<std::string>::iterator comment_it = hdata->comments.begin(); + // for (; comment_it != hdata->comments.end(); ++comment_it) { + // const char *comment = comment_it->c_str(); + // jstring commentj = env->NewStringUTF(comment); + // env->CallVoidMethod(object, addComment, commentj); + // } + + // } + //} + + //// Cleanup + //env->ReleaseStringUTFChars(hash, (const char *) inputHash); + //delete hdata; return object; } @@ -1651,7 +1565,6 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_startVerboseLoggingNat tsk_verbose++; } - /* * Create an index for the given database * @param env pointer to java environment this was called from @@ -1663,66 +1576,71 @@ JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbCreateIndexNat (JNIEnv * env, jclass obj, jint dbHandle, jboolean overwrite) { - if((size_t) dbHandle > m_hashDbs.size()) { + if((size_t)dbHandle > hashDbs.size()) { setThrowTskCoreError(env, "Invalid database handle"); return; - } else { - TSK_HDB_INFO * db = m_hashDbs.at(dbHandle-1); - if (db == NULL) { - setThrowTskCoreError(env, "Error: database object is null"); - return; - } + } - if (db->db_type == TSK_HDB_DBTYPE_IDXONLY_ID) { - setThrowTskCoreError(env, "Error: index only"); - return; - } + TSK_HDB_INFO *db = hashDbs.at(dbHandle-1); + if (db == NULL) { + setThrowTskCoreError(env, "Invalid database handle"); + return; + } - TSK_TCHAR dbType[1024]; + if (!db->uses_external_index) { + setThrowTskCoreError(env, "Database does not have an external index"); + return; + } - if(db->db_type == TSK_HDB_DBTYPE_MD5SUM_ID) { - TSNPRINTF(dbType, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_MD5SUM_STR); - } - else if(db->db_type == TSK_HDB_DBTYPE_HK_ID) { - TSNPRINTF(dbType, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_HK_STR); - } - else if(db->db_type == TSK_HDB_DBTYPE_ENCASE_ID) { - TSNPRINTF(dbType, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_ENCASE_STR); - } - else { - TSNPRINTF(dbType, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_NSRL_MD5_STR); - } + TSK_TCHAR idx_type[1024]; + if(db->db_type == TSK_HDB_DBTYPE_MD5SUM_ID) { + TSNPRINTF(idx_type, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_MD5SUM_STR); + } + else if(db->db_type == TSK_HDB_DBTYPE_HK_ID) { + TSNPRINTF(idx_type, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_HK_STR); + } + else if(db->db_type == TSK_HDB_DBTYPE_ENCASE_ID) { + TSNPRINTF(idx_type, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_ENCASE_STR); + } + else { + // The Java bindings only support the generation of md5 indexes for + // an NSRL hash database. + TSNPRINTF(idx_type, 1024, _TSK_T("%") PRIcTSK, TSK_HDB_DBTYPE_NSRL_MD5_STR); + } - // [Re]create the hash information and file - uint8_t err = tsk_hdb_regenerate_index(db, dbType, (overwrite ? 1 : 0)); - - // Make an error message - if (err > 0) { - char c_db_type[32]; - snprintf(c_db_type, 32, "%" PRIttocTSK, dbType); - std::string dbTypeStr(c_db_type); - - std::string msg("Error: index regeneration (db_type = " + dbTypeStr + "): "); - switch (err) { - case 1: - msg += "delete old failed."; - break; - case 2: - msg += "delete old (2nd pass) failed."; - break; - case 3: - msg += "tsk_hdb_makeindex failed."; - break; - } - setThrowTskCoreError(env, msg.c_str()); - return; - } - - // success - return; + if (tsk_hdb_makeindex(db, idx_type) != 0) { + setThrowTskCoreError(env); } -} + // RJCTODO: Remove this + //// [Re]create the hash information and file + //uint8_t err = tsk_hdb_regenerate_index(db, dbType, (overwrite ? 1 : 0)); + + //// Make an error message + //if (err > 0) { + // char c_db_type[32]; + // snprintf(c_db_type, 32, "%" PRIttocTSK, dbType); + // std::string dbTypeStr(c_db_type); + + // std::string msg("Error: index regeneration (db_type = " + dbTypeStr + "): "); + // switch (err) { + // case 1: + // msg += "delete old failed."; + // break; + // case 2: + // msg += "delete old (2nd pass) failed."; + // break; + // case 3: + // msg += "tsk_hdb_makeindex failed."; + // break; + // } + // setThrowTskCoreError(env, msg.c_str()); + // return; + //} + + //// success + //return; +} /* * Check if a lookup index exists for the given hash database. @@ -1732,20 +1650,18 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbCreateIndexNat (JNIEnv * env, */ JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbIndexExistsNat (JNIEnv * env, jclass obj, jint dbHandle) { - - if((size_t) dbHandle > m_hashDbs.size()) { + if((size_t)dbHandle > hashDbs.size()) { setThrowTskCoreError(env, "Invalid database handle"); - return (jboolean) false; - } else { - TSK_HDB_INFO * temp = m_hashDbs.at(dbHandle-1); - if (temp == NULL) { - return (jboolean) false; - } - - uint8_t retval = tsk_hdb_hasindex(temp, TSK_HDB_HTYPE_MD5_ID); + return (jboolean)false; + } - return (jboolean) retval == 1; + TSK_HDB_INFO *db = hashDbs.at(dbHandle-1); + if (db == NULL) { + setThrowTskCoreError(env, "Invalid database handle"); + return (jboolean)false; } + + return (jboolean)(db->has_index(db, TSK_HDB_HTYPE_MD5_ID) == 1); } /* diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.h b/bindings/java/jni/dataModel_SleuthkitJNI.h index 8f9061bfe558430f36bfe041cab4020571595096..10eb640b495dee453d3c29c47c15d45c4e0774cc 100644 --- a/bindings/java/jni/dataModel_SleuthkitJNI.h +++ b/bindings/java/jni/dataModel_SleuthkitJNI.h @@ -96,11 +96,11 @@ JNIEXPORT jboolean JNICALL /* * Class: org_sleuthkit_datamodel_SleuthkitJNI - * Method: hashDbIsReindexableNat + * Method: hashDbUsesExternalIndexesNat * Signature: */ JNIEXPORT jboolean JNICALL - Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbIsReindexableNat(JNIEnv * env, + Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbUsesExternalIndexesNat(JNIEnv * env, jclass obj, jint dbHandle); /* @@ -112,15 +112,6 @@ JNIEXPORT jstring JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbPathNat(JNIEnv * env, jclass obj, jint dbHandle); -/* - * Class: org_sleuthkit_datamodel_SleuthkitJNI - * Method: hashDbIndexPathNat - * Signature: - */ -JNIEXPORT jstring JNICALL - Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbIndexPathNat(JNIEnv * env, - jclass obj, jint dbHandle); - /* * Class: org_sleuthkit_datamodel_SleuthkitJNI * Method: hashDbGetName @@ -161,15 +152,6 @@ JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbLooku JNIEXPORT jobject JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbLookupVerbose (JNIEnv *, jclass, jstring, jint); -/* - * Class: org_sleuthkit_datamodel_SleuthkitJNI - * Method: getIndexSizeNat - * Signature: (Ljava/lang/String;)I - */ -//@deprecated -//JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getIndexSizeNat -// (JNIEnv *, jclass, jstring); - /* * Class: org_sleuthkit_datamodel_SleuthkitJNI * Method: initAddImgNat diff --git a/tsk/hashdb/encase.c b/tsk/hashdb/encase.c index 73b219b2f8ba27b5f768203fa15afb73408699f6..116d331f17b7ea212b637bd76396e52116463c7f 100644 --- a/tsk/hashdb/encase.c +++ b/tsk/hashdb/encase.c @@ -44,21 +44,20 @@ encase_test(FILE * hFile) * @param hdb_info the hash database object */ void -encase_name(TSK_HDB_INFO * hdb_info) +encase_name(TSK_HDB_INFO * hdb_info_base) { - TSK_TEXT_HDB_INFO *text_hdb_info = (TSK_TEXT_HDB_INFO*)hdb_info; - TSK_HDB_EXTERNAL_IDX_INFO *idx_info = (TSK_HDB_EXTERNAL_IDX_INFO*)text_hdb_info->idx; - FILE * hFile = text_hdb_info->hDb; + TSK_TEXT_HDB_INFO *hdb_info = (TSK_TEXT_HDB_INFO*)hdb_info_base; + FILE * hFile = hdb_info->hDb; wchar_t buf[40]; UTF16 *utf16; UTF8 *utf8; size_t ilen; - memset(idx_info->db_name, '\0', TSK_HDB_NAME_MAXLEN); + memset(hdb_info->db_name, '\0', TSK_HDB_NAME_MAXLEN); if(!hFile) { if (tsk_verbose) fprintf(stderr, "Error getting name from Encase hash db; using file name instead"); - tsk_hdb_name_from_path(hdb_info); + tsk_hdb_name_from_path(hdb_info_base); return; } @@ -69,14 +68,14 @@ encase_name(TSK_HDB_INFO * hdb_info) if (tsk_verbose) fprintf(stderr, "Error getting name from Encase hash db; using file name instead"); - tsk_hdb_name_from_path(hdb_info); + tsk_hdb_name_from_path(hdb_info_base); return; } // do some arithmetic on type sizes to be platform independent ilen = wcslen(buf) * (sizeof(wchar_t) / sizeof(UTF16)); - utf8 = (UTF8 *) idx_info->db_name; + utf8 = (UTF8 *) hdb_info->db_name; utf16 = (UTF16 *) buf; tsk_UTF16toUTF8(TSK_LIT_ENDIAN, @@ -258,37 +257,23 @@ encase_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_HDB_INFO *encase_open(FILE *hDb, const TSK_TCHAR *db_path) { TSK_TEXT_HDB_INFO *text_hdb_info = NULL; - size_t flen = 0; assert(NULL != hDb); assert(NULL != db_path); - if ((text_hdb_info = (TSK_TEXT_HDB_INFO*)tsk_malloc(sizeof(TSK_TEXT_HDB_INFO))) == NULL) { - return NULL; - } - - flen = TSTRLEN(db_path) + 8; // RJCTODO: Check this change from 32 (change was in DF code) with Brian; was change in older code? What is the point, anyway? - text_hdb_info->base.db_fname = (TSK_TCHAR*)tsk_malloc(flen * sizeof(TSK_TCHAR)); - if (NULL == text_hdb_info->base.db_fname) { + text_hdb_info = text_hdb_open(hDb, db_path); + if (NULL == text_hdb_info) { return NULL; } - TSTRNCPY(text_hdb_info->base.db_fname, db_path, flen); text_hdb_info->base.db_type = TSK_HDB_DBTYPE_ENCASE_ID; - text_hdb_info->base.updateable = 0; - text_hdb_info->base.uses_external_index = 1; - text_hdb_info->base.hash_type = TSK_HDB_HTYPE_INVALID_ID; // This will be set when the index is created/opened. - text_hdb_info->base.hash_len = 0; // This will be set when the index is created/opened. - tsk_init_lock(&text_hdb_info->base.lock); text_hdb_info->base.makeindex = encase_makeindex; + text_hdb_info->getentry = encase_getentry; text_hdb_info->base.add_comment = NULL; // RJCTODO: Consider making no-ops for these or moving them text_hdb_info->base.add_filename = NULL; // RJCTODO: Consider making no-ops for these or moving them - text_hdb_info->hDb = hDb; - text_hdb_info->getentry = encase_getentry; - // RJCTODO: Figure out when to do this - //md5sum_name((TSK_HDB_INFO*)hdb_info); + //encase_name((TSK_HDB_INFO*)hdb_info); return (TSK_HDB_INFO*)text_hdb_info; } diff --git a/tsk/hashdb/hashkeeper.c b/tsk/hashdb/hashkeeper.c index d461468b691b2efa8facafa4584d44508261ab14..720a1d73a438abbe86eaf84eaaf5f521e8e68c54 100644 --- a/tsk/hashdb/hashkeeper.c +++ b/tsk/hashdb/hashkeeper.c @@ -476,35 +476,21 @@ hk_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_OFF_T offset, TSK_HDB_INFO *hk_open(FILE *hDb, const TSK_TCHAR *db_path) { TSK_TEXT_HDB_INFO *text_hdb_info = NULL; - size_t flen = 0; assert(NULL != hDb); assert(NULL != db_path); - if ((text_hdb_info = (TSK_TEXT_HDB_INFO*)tsk_malloc(sizeof(TSK_TEXT_HDB_INFO))) == NULL) { + text_hdb_info = text_hdb_open(hDb, db_path); + if (NULL == text_hdb_info) { return NULL; } - flen = TSTRLEN(db_path) + 8; // RJCTODO: Check this change from 32 (change was in DF code) with Brian; was change in older code? What is the point, anyway? - text_hdb_info->base.db_fname = (TSK_TCHAR*)tsk_malloc(flen * sizeof(TSK_TCHAR)); - if (NULL == text_hdb_info->base.db_fname) { - return NULL; - } - - TSTRNCPY(text_hdb_info->base.db_fname, db_path, flen); text_hdb_info->base.db_type = TSK_HDB_DBTYPE_HK_ID; - text_hdb_info->base.updateable = 0; - text_hdb_info->base.uses_external_index = 1; - text_hdb_info->base.hash_type = TSK_HDB_HTYPE_INVALID_ID; // This will be set when the index is created/opened. - text_hdb_info->base.hash_len = 0; // This will be set when the index is created/opened. - tsk_init_lock(&text_hdb_info->base.lock); text_hdb_info->base.makeindex = hk_makeindex; + text_hdb_info->getentry = hk_getentry; text_hdb_info->base.add_comment = NULL; // RJCTODO: Consider making no-ops for these or moving them text_hdb_info->base.add_filename = NULL; // RJCTODO: Consider making no-ops for these or moving them - text_hdb_info->hDb = hDb; - text_hdb_info->getentry = hk_getentry; - // RJCTODO: Figure out when to do this //hk_name((TSK_HDB_INFO*)hdb_info); diff --git a/tsk/hashdb/hdb_index.cpp b/tsk/hashdb/hdb_index.cpp index b155ed62ac550d2e7e48f215424560a9e610caa6..3220df8085b513763702ddc49d9119a7f62c583d 100644 --- a/tsk/hashdb/hdb_index.cpp +++ b/tsk/hashdb/hdb_index.cpp @@ -737,44 +737,6 @@ tsk_hdb_makeindex(TSK_HDB_INFO * a_hdb_info, TSK_TCHAR * a_type) return a_hdb_info->makeindex(a_hdb_info, a_type); } -// RJCTODO: Remove this -///** -// * \ingroup hashdblib -// * Create a new hash database that can be written to. -// * @param db_file Filename. -// * @returns NULL on error -// */ -//TSK_HDB_INFO * -//tsk_hdb_newdb(TSK_TCHAR * db_file) -//{ -// // @@@ THis seems like a hack. We should probably pass in a "NEW/CREATE" flag into open to signal this use of the method. -// // though, I'm not sure what hdb_open is really doing of value in this case.... -// TSK_HDB_OPEN_ENUM flags = TSK_HDB_OPEN_IDXONLY; -// TSK_HDB_INFO * hdb_info = tsk_hdb_open(db_file, flags); -// -// if (hdb_info != NULL) { -// TSK_TCHAR * dbtype = NULL; //ignored for IDX only -// // @@@ This currently goes to idxonly_initidx, which makes the file. -// if (hdb_info->makeindex(hdb_info, dbtype) != 0) { -// tsk_hdb_close(hdb_info); -// hdb_info = NULL; -// tsk_error_reset(); -// tsk_error_set_errno(TSK_ERR_HDB_CREATE); -// tsk_error_set_errstr("tsk_hdb_new: making new index failed"); -// } -// else { -// if (tsk_hdb_idxfinalize(hdb_info) != 0) { -// tsk_hdb_close(hdb_info); -// hdb_info = NULL; -// tsk_error_reset(); -// tsk_error_set_errno(TSK_ERR_HDB_WRITE); -// tsk_error_set_errstr("tsk_hdb_new: finalizing new index failed"); -// } -// } -// } -// return hdb_info; -//} -// /** * \ingroup hashdblib * Add a binary hash entry to the index @@ -787,7 +749,7 @@ tsk_hdb_makeindex(TSK_HDB_INFO * a_hdb_info, TSK_TCHAR * a_type) * @return 1 on error, 0 on success, -1 if not updateable */ int8_t -tsk_hdb_add_str(TSK_HDB_INFO * hdb_info, +tsk_hdb_add_hash(TSK_HDB_INFO * hdb_info, const char * filename, const char * md5, const char * sha1, diff --git a/tsk/hashdb/hdb_open.cpp b/tsk/hashdb/hdb_open.cpp index 16a85894783bc4d143c9e2c9aae8d6cca01f4deb..f91c356aec5de90f1a5bcafa9380ff0540409b38 100644 --- a/tsk/hashdb/hdb_open.cpp +++ b/tsk/hashdb/hdb_open.cpp @@ -20,7 +20,7 @@ * Contains the code to open and close all supported hash database types. */ -static uint8_t +uint8_t hdb_file_exists(TSK_TCHAR *file_path) { #ifdef TSK_WIN32 @@ -150,7 +150,7 @@ tsk_hdb_open(TSK_TCHAR *file_path, TSK_HDB_OPEN_ENUM flags) assert(NULL != file_path); if (NULL == file_path) { tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_HDB_INVALID_PARAM); // RJCTODO: COnsider changing this to INVALID_PATH + tsk_error_set_errno(TSK_ERR_HDB_INVALID_PARAM); // RJCTODO: COnsider changing this to INVALID_PATH...actually, don't need this there is an ARG tsk_error_set_errstr("%s: NULL file path", func_name); return NULL; } diff --git a/tsk/hashdb/idxonly.c b/tsk/hashdb/idxonly.c index 6e6d4ac9db51dbe08f92eec53ca9ecacf77080cb..64a80f73a0b0a956a287b9dbb82dc0e34b6779f2 100644 --- a/tsk/hashdb/idxonly.c +++ b/tsk/hashdb/idxonly.c @@ -120,33 +120,20 @@ idxonly_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_HDB_INFO *idxonly_open(const TSK_TCHAR *db_path) { TSK_TEXT_HDB_INFO *text_hdb_info = NULL; - size_t flen = 0; assert(NULL != db_path); - if ((text_hdb_info = (TSK_TEXT_HDB_INFO*)tsk_malloc(sizeof(TSK_TEXT_HDB_INFO))) == NULL) { + text_hdb_info = text_hdb_open(NULL, db_path); + if (NULL == text_hdb_info) { return NULL; } - flen = TSTRLEN(db_path) + 8; // RJCTODO: Check this change from 32 (change was in DF code) with Brian; was change in older code? What is the point, anyway? - text_hdb_info->base.idx_fname = (TSK_TCHAR*)tsk_malloc(flen * sizeof(TSK_TCHAR)); - if (NULL == text_hdb_info->base.idx_fname) { - return NULL; - } - - TSTRNCPY(text_hdb_info->base.idx_fname, db_path, flen); text_hdb_info->base.db_type = TSK_HDB_DBTYPE_IDXONLY_ID; - text_hdb_info->base.updateable = 0; - text_hdb_info->base.uses_external_index = 1; - text_hdb_info->base.hash_type = TSK_HDB_HTYPE_INVALID_ID; // This will be set when the index is created/opened. - text_hdb_info->base.hash_len = 0; // This will be set when the index is created/opened. - tsk_init_lock(&text_hdb_info->base.lock); + text_hdb_info->getentry = idxonly_getentry; text_hdb_info->base.makeindex = idxonly_makeindex; text_hdb_info->base.add_comment = NULL; // RJCTODO: Consider making no-ops for these or moving them text_hdb_info->base.add_filename = NULL; // RJCTODO: Consider making no-ops for these or moving them - text_hdb_info->getentry = idxonly_getentry; - // RJCTODO: Figure out when to do this //idxonly_name((TSK_HDB_INFO*)hdb_info); diff --git a/tsk/hashdb/md5sum.c b/tsk/hashdb/md5sum.c index 625284b3a27a7fee174faeb0b458878a1992c067..45c87458b5682dfec4371a9f5b1d2ae607758d84 100644 --- a/tsk/hashdb/md5sum.c +++ b/tsk/hashdb/md5sum.c @@ -397,37 +397,23 @@ md5sum_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_HDB_INFO *md5sum_open(FILE *hDb, const TSK_TCHAR *db_path) { TSK_TEXT_HDB_INFO *text_hdb_info = NULL; - size_t flen = 0; assert(NULL != hDb); assert(NULL != db_path); - if ((text_hdb_info = (TSK_TEXT_HDB_INFO*)tsk_malloc(sizeof(TSK_TEXT_HDB_INFO))) == NULL) { + text_hdb_info = text_hdb_open(hDb, db_path); + if (NULL == text_hdb_info) { return NULL; } - flen = TSTRLEN(db_path) + 8; // RJCTODO: Check this change from 32 (change was in DF code) with Brian; was change in older code? What is the point, anyway? - text_hdb_info->base.db_fname = (TSK_TCHAR*)tsk_malloc(flen * sizeof(TSK_TCHAR)); - if (NULL == text_hdb_info->base.db_fname) { - return NULL; - } - - TSTRNCPY(text_hdb_info->base.db_fname, db_path, flen); text_hdb_info->base.db_type = TSK_HDB_DBTYPE_MD5SUM_ID; - text_hdb_info->base.updateable = 0; - text_hdb_info->base.uses_external_index = 1; - text_hdb_info->base.hash_type = TSK_HDB_HTYPE_INVALID_ID; // This will be set when the index is created/opened. - text_hdb_info->base.hash_len = 0; // This will be set when the index is created/opened. - tsk_init_lock(&text_hdb_info->base.lock); + text_hdb_info->getentry = md5sum_getentry; text_hdb_info->base.makeindex = md5sum_makeindex; text_hdb_info->base.add_comment = NULL; // RJCTODO: Consider making no-ops for these or moving them text_hdb_info->base.add_filename = NULL; // RJCTODO: Consider making no-ops for these or moving them - text_hdb_info->hDb = hDb; - text_hdb_info->getentry = md5sum_getentry; - // RJCTODO: Figure out when to do this - //encase_name((TSK_HDB_INFO*)hdb_info); + //md5sum_name((TSK_HDB_INFO*)hdb_info); return (TSK_HDB_INFO*)text_hdb_info; } \ No newline at end of file diff --git a/tsk/hashdb/nsrl.c b/tsk/hashdb/nsrl.c index a34948b8b0528424738a26e8a6e3d9f9dcd1a04b..9d7de5523a40f0b7002d9209a2ef30e8112751a2 100644 --- a/tsk/hashdb/nsrl.c +++ b/tsk/hashdb/nsrl.c @@ -2,7 +2,7 @@ * The Sleuth Kit * * Brian Carrier [carrier <at> sleuthkit [dot] org] - * Copyright (c) 2003-2011 Brian Carrier. All rights reserved + * Copyright (c) 2003-2014 Brian Carrier. All rights reserved * * * This software is distributed under the Common Public License 1.0 @@ -367,9 +367,6 @@ nsrl_parse_md5(char *str, char **md5, char **name, int ver) return 1; } - - - /** * Process the database to create a sorted index of it. Consecutive * entries with the same hash value are not added to the index, but @@ -381,9 +378,9 @@ nsrl_parse_md5(char *str, char **md5, char **name, int ver) * @return 1 on error and 0 on success. */ uint8_t -nsrl_makeindex(TSK_HDB_INFO * hdb_info, TSK_TCHAR * dbtype) +nsrl_makeindex(TSK_HDB_INFO * hdb_info_base, TSK_TCHAR * dbtype) { - TSK_TEXT_HDB_INFO *text_hdb_info = (TSK_TEXT_HDB_INFO*)hdb_info; + TSK_TEXT_HDB_INFO *hdb_info = (TSK_TEXT_HDB_INFO*)hdb_info_base; size_t i, len; char buf[TSK_HDB_MAXLEN]; char *hash = NULL, phash[TSK_HDB_HTYPE_SHA1_LEN + 1]; @@ -391,7 +388,7 @@ nsrl_makeindex(TSK_HDB_INFO * hdb_info, TSK_TCHAR * dbtype) int ver = 0; int db_cnt = 0, idx_cnt = 0, ig_cnt = 0; - if (tsk_hdb_idxinitialize(hdb_info, dbtype)) { + if (text_hdb_idx_init(hdb_info_base, dbtype)) { tsk_error_set_errstr2( "nsrl_makeindex"); return 1; } @@ -399,14 +396,14 @@ nsrl_makeindex(TSK_HDB_INFO * hdb_info, TSK_TCHAR * dbtype) /* Status */ if (tsk_verbose) TFPRINTF(stderr, _TSK_T("Extracting Data from Database (%s)\n"), - hdb_info->db_fname); + hdb_info_base->db_fname); /* Allocate a buffer for the previous hash value */ memset(phash, '0', TSK_HDB_HTYPE_SHA1_LEN + 1); /* read the file */ - fseek(text_hdb_info->hDb, 0, SEEK_SET); - for (i = 0; NULL != fgets(buf, TSK_HDB_MAXLEN, text_hdb_info->hDb); + fseek(hdb_info->hDb, 0, SEEK_SET); + for (i = 0; NULL != fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb); offset += len, i++) { len = strlen(buf); @@ -442,7 +439,7 @@ nsrl_makeindex(TSK_HDB_INFO * hdb_info, TSK_TCHAR * dbtype) } /* Add the entry to the index */ - if (tsk_hdb_idxaddentry(hdb_info, hash, offset)) { + if (text_hdb_idx_add_entry(hdb_info_base, hash, offset)) { tsk_error_set_errstr2( "nsrl_makeindex"); return 1; } @@ -464,7 +461,7 @@ nsrl_makeindex(TSK_HDB_INFO * hdb_info, TSK_TCHAR * dbtype) } /* Close and sort the index */ - if (tsk_hdb_idxfinalize(hdb_info)) { + if (text_hdb_idx_finalize(hdb_info_base)) { tsk_error_set_errstr2( "nsrl_makeindex"); return 1; } @@ -497,14 +494,14 @@ nsrl_makeindex(TSK_HDB_INFO * hdb_info, TSK_TCHAR * dbtype) * @return 1 on error and 0 on success */ uint8_t -nsrl_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_OFF_T offset, +nsrl_getentry(TSK_HDB_INFO * hdb_info_base, const char *hash, TSK_OFF_T offset, TSK_HDB_FLAG_ENUM flags, TSK_HDB_LOOKUP_FN action, void *cb_ptr) { + TSK_TEXT_HDB_INFO *hdb_info = (TSK_TEXT_HDB_INFO*)hdb_info_base; char buf[TSK_HDB_MAXLEN], *name, *cur_hash, pname[TSK_HDB_MAXLEN]; int found = 0; int ver; - TSK_TEXT_HDB_INFO *text_db_info = (TSK_TEXT_HDB_INFO*)hdb_info; if (tsk_verbose) fprintf(stderr, @@ -531,8 +528,8 @@ nsrl_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_OFF_T offset, } /* read the header line ... -- this should be done only once... */ - fseeko(text_db_info->hDb, 0, SEEK_SET); - if (NULL == fgets(buf, TSK_HDB_MAXLEN, text_db_info->hDb)) { + fseeko(hdb_info->hDb, 0, SEEK_SET); + if (NULL == fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_HDB_READDB); tsk_error_set_errstr( @@ -551,7 +548,7 @@ nsrl_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_OFF_T offset, while (1) { size_t len; - if (0 != fseeko(text_db_info->hDb, offset, SEEK_SET)) { + if (0 != fseeko(hdb_info->hDb, offset, SEEK_SET)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_HDB_READDB); tsk_error_set_errstr( @@ -560,8 +557,8 @@ nsrl_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_OFF_T offset, return 1; } - if (NULL == fgets(buf, TSK_HDB_MAXLEN, text_db_info->hDb)) { - if (feof(text_db_info->hDb)) + if (NULL == fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb)) { + if (feof(hdb_info->hDb)) break; tsk_error_reset(); @@ -611,7 +608,7 @@ nsrl_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_OFF_T offset, /* Check if this is the same name as the previous entry */ if (strcmp(name, pname) != 0) { int retval; - retval = action(hdb_info, hash, name, cb_ptr); + retval = action(hdb_info_base, hash, name, cb_ptr); if (retval == TSK_WALK_STOP) return 0; else if (retval == TSK_WALK_ERROR) @@ -640,36 +637,23 @@ nsrl_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_OFF_T offset, TSK_HDB_INFO *nsrl_open(FILE *hDb, const TSK_TCHAR *db_path) { TSK_TEXT_HDB_INFO *text_hdb_info = NULL; - size_t flen = 0; assert(NULL != hDb); assert(NULL != db_path); - if ((text_hdb_info = (TSK_TEXT_HDB_INFO*)tsk_malloc(sizeof(TSK_TEXT_HDB_INFO))) == NULL) { + text_hdb_info = text_hdb_open(hDb, db_path); + if (NULL == text_hdb_info) { return NULL; } - flen = TSTRLEN(db_path) + 8; // RJCTODO: Check this change from 32 (change was in DF code) with Brian; was change in older code? What is the point, anyway? - text_hdb_info->base.db_fname = (TSK_TCHAR*)tsk_malloc(flen * sizeof(TSK_TCHAR)); - if (NULL == text_hdb_info->base.db_fname) { - return NULL; - } - - TSTRNCPY(text_hdb_info->base.db_fname, db_path, flen); text_hdb_info->base.db_type = TSK_HDB_DBTYPE_NSRL_ID; - text_hdb_info->base.updateable = 0; - text_hdb_info->base.uses_external_index = 1; - text_hdb_info->base.hash_type = TSK_HDB_HTYPE_INVALID_ID; // This will be set when the index is created/opened. - text_hdb_info->base.hash_len = 0; // This will be set when the index is created/opened. - tsk_init_lock(&text_hdb_info->base.lock); text_hdb_info->base.makeindex = nsrl_makeindex; + text_hdb_info->getentry = nsrl_getentry; text_hdb_info->base.add_comment = NULL; // RJCTODO: Consider making no-ops for these or moving them text_hdb_info->base.add_filename = NULL; // RJCTODO: Consider making no-ops for these or moving them - text_hdb_info->hDb = hDb; - text_hdb_info->getentry = nsrl_getentry; - // RJCTODO: Figure out when to do this + // Looks like there can be a base open, with call out to set name and db type param //nsrl_name((TSK_HDB_INFO*)text_hdb_info); return (TSK_HDB_INFO*)text_hdb_info; diff --git a/tsk/hashdb/sqlite_index.cpp b/tsk/hashdb/sqlite_index.cpp index 293d804a86456423c89e9d989836b6fd5fa56be6..6219fe31db73b28b152d58192ddff51e80b92a90 100644 --- a/tsk/hashdb/sqlite_index.cpp +++ b/tsk/hashdb/sqlite_index.cpp @@ -184,34 +184,34 @@ uint8_t sqlite_hdb_create_db(TSK_TCHAR *db_file_path) // Are there prepared statements that are not finalized? // Why are the statements prepared on every round? This should be done on open, and finalization should happen on close. // This code is not really needed for index building now, but it is still probably worthwhile for add operations. -uint8_t -sqlite_v1_begin(TSK_HDB_INFO * hdb_info) -{ - TSK_SQLITE_HDB_INFO *sqlite_hdb_info = (TSK_SQLITE_HDB_INFO*)hdb_info; - char * insertStmt; - - if (hdb_info->hash_type == TSK_HDB_HTYPE_MD5_ID) { - insertStmt = "INSERT INTO hashes (md5, database_offset) VALUES (?, ?)"; - } else if (hdb_info->hash_type == TSK_HDB_HTYPE_SHA1_ID) { - insertStmt = "INSERT INTO hashes (sha1, database_offset) VALUES (?, ?)"; - } else { - return 1; - } - - prepare_stmt(insertStmt, &m_stmt, sqlite_hdb_info->db); - - if (begin_transaction(hdb_info)) { - return 1; - } else { - return 0; - } -} +//uint8_t +//sqlite_v1_begin(TSK_HDB_INFO * hdb_info) +//{ +// TSK_SQLITE_HDB_INFO *sqlite_hdb_info = (TSK_SQLITE_HDB_INFO*)hdb_info; +// char * insertStmt; +// +// if (hdb_info->hash_type == TSK_HDB_HTYPE_MD5_ID) { +// insertStmt = "INSERT INTO hashes (md5, database_offset) VALUES (?, ?)"; +// } else if (hdb_info->hash_type == TSK_HDB_HTYPE_SHA1_ID) { +// insertStmt = "INSERT INTO hashes (sha1, database_offset) VALUES (?, ?)"; +// } else { +// return 1; +// } +// +// prepare_stmt(insertStmt, &m_stmt, sqlite_hdb_info->db); +// +// if (begin_transaction(hdb_info)) { +// return 1; +// } else { +// return 0; +// } +//} /** * This function is a no-op for SQLite hash database. The index is "internal" to the RDBMS. * @return 1 on error and 0 on success */ -uint8_t sqlite_hdb_make_index(TSK_HDB_INFO * hdb_info, TSK_TCHAR * dbtype) +uint8_t sqlite_hdb_make_index(TSK_HDB_INFO * hdb_info, TSK_TCHAR * htype) { // RJCTODO: Add should not be called error stuff return 0; @@ -277,10 +277,10 @@ sqlite_hdb_add(TSK_HDB_INFO * hdb_info, const char * filename, const char * md5, * This function is a no-op for SQLite hash database. The index is "internal" to the RDBMS. * @return 1 on error and 0 on success */ -uint8_t -sqlite_v1_addentry_bin(TSK_HDB_INFO * hdb_info, uint8_t* hvalue, int hlen, - TSK_OFF_T offset) -{ +//uint8_t +//sqlite_v1_addentry_bin(TSK_HDB_INFO * hdb_info, uint8_t* hvalue, int hlen, +// TSK_OFF_T offset) +//{ // RJCTODO: This needs to go into a separate add to hash database function, as opposed to an add to index function // if (attempt(sqlite3_bind_blob(m_stmt, 1, hvalue, hlen, SQLITE_TRANSIENT), // SQLITE_OK, @@ -311,16 +311,16 @@ sqlite_v1_addentry_bin(TSK_HDB_INFO * hdb_info, uint8_t* hvalue, int hlen, // } // return 0; - return 0; -} +// return 0; +//} /** * This function is a no-op for SQLite hash database. The index is "internal" to the RDBMS. * @return 1 on error and 0 on success */ -uint8_t -addentry_text(TSK_HDB_INFO * hdb_info, char* hvalue, TSK_OFF_T offset) -{ +//uint8_t +//addentry_text(TSK_HDB_INFO * hdb_info, char* hvalue, TSK_OFF_T offset) +//{ // RJCTODO: This needs to go into a separate add to hash database function, as opposed to an add to index function // if (attempt(sqlite3_bind_text(m_stmt, 1, hvalue, strlen(hvalue), SQLITE_TRANSIENT), // SQLITE_OK, @@ -351,8 +351,8 @@ addentry_text(TSK_HDB_INFO * hdb_info, char* hvalue, TSK_OFF_T offset) // } // return 0; - return 0; -} +// return 0; +//} /** * Add new comment (e.g. the case name) @@ -402,9 +402,9 @@ sqlite_v1_addfilename(TSK_HDB_INFO * hdb_info, char* value, int64_t id) * This function is a no-op for SQLite hash database. The index is "internal" to the RDBMS. * @return 1 on error and 0 on success */ -uint8_t -sqlite_v1_finalize(TSK_HDB_INFO * hdb_info) -{ +//uint8_t +//sqlite_v1_finalize(TSK_HDB_INFO * hdb_info) +//{ // RJCTODO: Remove this after add to hash database function is made //if (end_transaction(hdb_info->idx_info)) { // tsk_error_reset(); @@ -427,8 +427,8 @@ sqlite_v1_finalize(TSK_HDB_INFO * hdb_info) // } else { // return 0; // } - return 0; -} +// return 0; +//} /** * \ingroup hashdblib @@ -783,48 +783,48 @@ void * sqlite_v1_getAllData(TSK_HDB_INFO * hdb_info, unsigned long hashId) * @param hdb_info Open hash database (with index) * @return -1 on error, 0 on success. */ -int8_t -sqlite_v1_get_properties(TSK_HDB_INFO * hdb_info) -{ - int8_t ret = 0; - sqlite3_stmt* stmt = NULL; - char selectStmt[1024]; - - tsk_take_lock(&hdb_info->lock); - - snprintf(selectStmt, 1024, "SELECT value from db_properties where name='%s'", IDX_HASHSET_UPDATEABLE); - prepare_stmt(selectStmt, &stmt, hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite); - - if (sqlite3_step(stmt) == SQLITE_ROW) { - const char* value = (const char *)sqlite3_column_text(stmt, 0); - - if (value == NULL) { - tsk_error_set_errstr2("sqlite_v1_get_properties: null value"); - ret = -1; - } else { - // Set the updateable flag - if (strcmp(value, "true") == 0) { - hdb_info->idx_info->updateable = 1; - } - } - } else { - tsk_error_set_errstr2("sqlite_v1_get_properties"); - ret = -1; - } - - sqlite3_reset(stmt); - - if (stmt) { - finalize_stmt(stmt); - } - - - ///@todo load db name property as well? - - tsk_release_lock(&hdb_info->lock); - - return ret; -} +//int8_t +//sqlite_v1_get_properties(TSK_HDB_INFO * hdb_info) +//{ +// int8_t ret = 0; +// sqlite3_stmt* stmt = NULL; +// char selectStmt[1024]; +// +// tsk_take_lock(&hdb_info->lock); +// +// snprintf(selectStmt, 1024, "SELECT value from db_properties where name='%s'", IDX_HASHSET_UPDATEABLE); +// prepare_stmt(selectStmt, &stmt, hdb_info->idx_info->idx_struct.idx_sqlite_v1->hIdx_sqlite); +// +// if (sqlite3_step(stmt) == SQLITE_ROW) { +// const char* value = (const char *)sqlite3_column_text(stmt, 0); +// +// if (value == NULL) { +// tsk_error_set_errstr2("sqlite_v1_get_properties: null value"); +// ret = -1; +// } else { +// // Set the updateable flag +// if (strcmp(value, "true") == 0) { +// hdb_info->idx_info->updateable = 1; +// } +// } +// } else { +// tsk_error_set_errstr2("sqlite_v1_get_properties"); +// ret = -1; +// } +// +// sqlite3_reset(stmt); +// +// if (stmt) { +// finalize_stmt(stmt); +// } +// +// +// ///@todo load db name property as well? +// +// tsk_release_lock(&hdb_info->lock); +// +// return ret; +//} /* * Close the sqlite index handle @@ -845,6 +845,8 @@ sqlite_hdb_close(TSK_HDB_INFO* hdb_info) if (db_info->db) { sqlite3_close(db_info->db); } + + // RJCTODO: Cleanup the base stuff... } /** @@ -875,21 +877,6 @@ sqlite3_test(FILE * hFile) return 0; } -// RJCTODO: Comment -uint8_t -sqlite_hdb_set_index_params(TSK_HDB_INFO *hdb_info, TSK_HDB_DBTYPE_ENUM hash_type) -{ - // The index is internal to the database, there is nothing to do. - return 0; -} - -// RJCTODO: Comment -uint8_t sqlite_hdb_make_index(TSK_HDB_INFO *hdb_info, TSK_HDB_DBTYPE_ENUM hash_type) -{ - // The index is internal to the database, there is nothing to do. - return 0; -} - // RJCTODO: Comment TSK_HDB_INFO *sqlite_hdb_open(TSK_TCHAR *db_path) { diff --git a/tsk/hashdb/text_db.c b/tsk/hashdb/text_db.c index f6cc96a7d548c0b477ae1e5f4d338c3cb7e9066d..aeb5641f9598439b787b8f4f552482fdeeaeed6d 100755 --- a/tsk/hashdb/text_db.c +++ b/tsk/hashdb/text_db.c @@ -16,6 +16,1132 @@ * Functions common to all text hash databases. */ +// RJCTODO: Fix up function names in error messages +// RJCTODO: Comment, etc. +TSK_TEXT_HDB_INFO *text_hdb_open_db(FILE *hDb, const TSK_TCHAR *db_path) +{ + TSK_TEXT_HDB_INFO *text_hdb_info = NULL; + size_t flen = 0; + + assert(NULL != db_path); + // RJCTODO: Add release build check + + if ((text_hdb_info = (TSK_TEXT_HDB_INFO*)tsk_malloc(sizeof(TSK_TEXT_HDB_INFO))) == NULL) { + return NULL; + } + + text_hdb_info->hDb = hDb; + + flen = TSTRLEN(db_path) + 8; // RJCTODO: Check this change from 32 (change was in DF code) with Brian; was change in older code? What is the point, anyway? + text_hdb_info->base.db_fname = (TSK_TCHAR*)tsk_malloc(flen * sizeof(TSK_TCHAR)); + if (NULL == text_hdb_info->base.db_fname) { + return NULL; + } + TSTRNCPY(text_hdb_info->base.db_fname, db_path, flen); + + text_hdb_info->base.updateable = 0; + text_hdb_info->base.uses_external_indexes = 1; + tsk_init_lock(&text_hdb_info->base.lock); + + // Some text hash database types support indexes for more than one hash + // type, so setting the hash type and length are deferred until the desired + // index is created/opened. + text_hdb_info->hash_type = TSK_HDB_HTYPE_INVALID_ID; + text_hdb_info->hash_len = 0; + + // The name, database type, and function pointers will need to be set + // by the "derived class" caller these things vary by database type. + text_hdb_info->base.db_type = TSK_HDB_DBTYPE_INVALID_ID; + text_hdb_info->base.makeindex = NULL; + text_hdb_info->getentry = NULL; + + return text_hdb_info; +} + +/** \internal + * Setup the hash-type specific information (such as length, index entry + * sizes, index name etc.) in the HDB_INFO structure. + * + * @param hdb_info Structure to fill in. + * @param htype Hash type being used + * @return 1 on error and 0 on success + */ +static uint8_t +text_hdb_init_idx_hash_type_info(TSK_HDB_INFO * hdb_info_base, TSK_HDB_HTYPE_ENUM htype) // RJCTODO: Change to enum +{ + TSK_TEXT_HDB_INFO *hdb_info = (TSK_TEXT_HDB_INFO*)hdb_info_base; + size_t flen = 0; + + if (hdb_info->hash_type != 0) { + return 0; + } + + /* Make the name for the index file */ + flen = TSTRLEN(hdb_info_base->db_fname) + 32; + hdb_info->idx_fname = + (TSK_TCHAR *) tsk_malloc(flen * sizeof(TSK_TCHAR)); + if (hdb_info->idx_fname == NULL) { + return 1; + } + + /* Get hash type specific information */ + switch (htype) { + case TSK_HDB_HTYPE_MD5_ID: + hdb_info->hash_type = htype; + hdb_info->hash_len = TSK_HDB_HTYPE_MD5_LEN; + hdb_info->idx_llen = TSK_HDB_IDX_LEN(htype); + TSNPRINTF(hdb_info->idx_fname, flen, + _TSK_T("%s-%") PRIcTSK _TSK_T(".idx"), + hdb_info_base->db_fname, TSK_HDB_HTYPE_MD5_STR); + return 0; + case TSK_HDB_HTYPE_SHA1_ID: + hdb_info->hash_type = htype; + hdb_info->hash_len = TSK_HDB_HTYPE_SHA1_LEN; + hdb_info->idx_llen = TSK_HDB_IDX_LEN(htype); + TSNPRINTF(hdb_info->idx_fname, flen, + _TSK_T("%s-%") PRIcTSK _TSK_T(".idx"), + hdb_info_base->db_fname, TSK_HDB_HTYPE_SHA1_STR); + return 0; + } + + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_ARG); + tsk_error_set_errstr( + "text_hdb_init_idx_hash_type_info: Invalid hash type as argument: %d", htype); + return 1; +} + +/** \internal + * Setup the internal variables to read an index. This + * opens the index and sets the needed size information. + * + * @param hdb_info Hash database to analyze + * @param hash The hash type that was used to make the index. + * + * @return 1 on error and 0 on success + */ +static uint8_t +text_hdb_open_idx(TSK_HDB_INFO * hdb_info_base, TSK_HDB_HTYPE_ENUM htype) +{ + TSK_TEXT_HDB_INFO *hdb_info = (TSK_TEXT_HDB_INFO*)hdb_info_base; + char head[TSK_HDB_MAXLEN]; + char head2[TSK_HDB_MAXLEN]; + char *ptr; + + // Lock for lazy load of hIdx and lazy alloc of idx_lbuf. + tsk_take_lock(&hdb_info_base->lock); + + if (hdb_info->hIdx != NULL) { + tsk_release_lock(&hdb_info_base->lock); + return 0; + } + + if ((htype != TSK_HDB_HTYPE_MD5_ID) + && (htype != TSK_HDB_HTYPE_SHA1_ID)) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_ARG); + tsk_error_set_errstr( + "text_hdb_open_idx: Invalid hash type : %d", htype); + return 1; + } + + if (text_hdb_init_idx_hash_type_info(hdb_info_base, htype)) { + tsk_release_lock(&hdb_info_base->lock); + return 1; + } + + /* Verify the index exists, get its size, and open it */ +#ifdef TSK_WIN32 + { + HANDLE hWin; + DWORD szLow, szHi; + + if (-1 == GetFileAttributes(hdb_info->idx_fname)) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_MISSING); + tsk_error_set_errstr( + "text_hdb_open_idx: Error finding index file: %"PRIttocTSK, + hdb_info->idx_fname); + return 1; + } + + if ((hWin = CreateFile(hdb_info->idx_fname, GENERIC_READ, + FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0)) == + INVALID_HANDLE_VALUE) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_OPEN); + tsk_error_set_errstr( + "text_hdb_open_idx: Error opening index file: %"PRIttocTSK, + hdb_info->idx_fname); + return 1; + } + hdb_info->hIdx = + _fdopen(_open_osfhandle((intptr_t) hWin, _O_RDONLY), "r"); + if (hdb_info->hIdx == NULL) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_OPEN); + tsk_error_set_errstr( + "text_hdb_open_idx: Error converting Windows handle to C handle"); + return 1; + } + + szLow = GetFileSize(hWin, &szHi); + if (szLow == 0xffffffff) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_OPEN); + tsk_error_set_errstr( + "text_hdb_open_idx: Error getting size of index file: %"PRIttocTSK" - %d", + hdb_info->idx_fname, (int)GetLastError()); + return 1; + } + hdb_info->idx_size = szLow | ((uint64_t) szHi << 32); + } + +#else + { + struct stat sb; + if (stat(hdb_info->idx_fname, &sb) < 0) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_MISSING); + tsk_error_set_errstr( + "text_hdb_open_idx: Error finding index file: %s", + hdb_info->idx_fname); + return 1; + } + hdb_info->idx_size = sb.st_size; + + if (NULL == (hdb_info->hIdx = fopen(hdb_info->idx_fname, "r"))) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_OPEN); + tsk_error_set_errstr( + "text_hdb_open_idx: Error opening index file: %s", + hdb_info->idx_fname); + return 1; + } + } +#endif + + /* Do some testing on the first line */ + if (NULL == fgets(head, TSK_HDB_MAXLEN, hdb_info->hIdx)) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_READIDX); + tsk_error_set_errstr( + "text_hdb_open_idx: Header line of index file"); + return 1; + } + + if (strncmp(head, TSK_HDB_IDX_HEAD_TYPE_STR, strlen(TSK_HDB_IDX_HEAD_TYPE_STR)) + != 0) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE); + tsk_error_set_errstr( + "text_hdb_open_idx: Invalid index file: Missing header line"); + return 1; + } + + /* Do some testing on the second line */ + if (NULL == fgets(head2, TSK_HDB_MAXLEN, hdb_info->hIdx)) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_READIDX); + tsk_error_set_errstr( + "text_hdb_open_idx: Error reading line 2 of index file"); + return 1; + } + + /* Set the offset to the start of the index entries */ + if (strncmp(head2, TSK_HDB_IDX_HEAD_NAME_STR, strlen(TSK_HDB_IDX_HEAD_NAME_STR)) + != 0) { + hdb_info->idx_off = (uint16_t) (strlen(head)); + } else { + hdb_info->idx_off = (uint16_t) (strlen(head) + strlen(head2)); + } + + + /* Skip the space */ + ptr = &head[strlen(TSK_HDB_IDX_HEAD_TYPE_STR) + 1]; + + ptr[strlen(ptr) - 1] = '\0'; + if ((ptr[strlen(ptr) - 1] == 10) || (ptr[strlen(ptr) - 1] == 13)) { + ptr[strlen(ptr) - 1] = '\0'; + hdb_info->idx_llen++; // make the expected index length longer to account for different cr/nl/etc. + } + + /* Verify the header value in the index */ + if (strcmp(ptr, TSK_HDB_DBTYPE_NSRL_STR) == 0) { + if ((hdb_info_base->db_type != TSK_HDB_DBTYPE_NSRL_ID) && + (hdb_info_base->db_type != TSK_HDB_DBTYPE_IDXONLY_ID)) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE); + tsk_error_set_errstr( + "hdb_indexsetup: DB detected as %s, index type has NSRL", + ptr); + return 1; + } + } + else if (strcmp(ptr, TSK_HDB_DBTYPE_MD5SUM_STR) == 0) { + if ((hdb_info_base->db_type != TSK_HDB_DBTYPE_MD5SUM_ID) && + (hdb_info_base->db_type != TSK_HDB_DBTYPE_IDXONLY_ID)) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE); + tsk_error_set_errstr( + "hdb_indexsetup: DB detected as %s, index type has MD5SUM", + ptr); + return 1; + } + } + else if (strcmp(ptr, TSK_HDB_DBTYPE_HK_STR) == 0) { + if ((hdb_info_base->db_type != TSK_HDB_DBTYPE_HK_ID) && + (hdb_info_base->db_type != TSK_HDB_DBTYPE_IDXONLY_ID)) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE); + tsk_error_set_errstr( + "hdb_indexsetup: DB detected as %s, index type has hashkeeper", + ptr); + return 1; + } + } + else if (strcmp(ptr, TSK_HDB_DBTYPE_ENCASE_STR) == 0) { + if ((hdb_info_base->db_type != TSK_HDB_DBTYPE_ENCASE_ID) && + (hdb_info_base->db_type != TSK_HDB_DBTYPE_IDXONLY_ID)) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE); + tsk_error_set_errstr( + "hdb_indexsetup: DB detected as %s, index type has EnCase", + ptr); + return 1; + } + } + else if (hdb_info_base->db_type != TSK_HDB_DBTYPE_IDXONLY_ID) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_UNKTYPE); + tsk_error_set_errstr( + "text_hdb_open_idx: Unknown Database Type in index header: %s", + ptr); + return 1; + } + + /* Do some sanity checking */ + if (((hdb_info->idx_size - hdb_info->idx_off) % hdb_info->idx_llen) != + 0) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_CORRUPT); + tsk_error_set_errstr( + "text_hdb_open_idx: Error, size of index file is not a multiple of row size"); + return 1; + } + + /* allocate a buffer for a row */ + if ((hdb_info->idx_lbuf = tsk_malloc(hdb_info->idx_llen + 1)) == NULL) { // RJCTODO: Fix the warning/err + tsk_release_lock(&hdb_info_base->lock); + return 1; + } + + tsk_release_lock(&hdb_info_base->lock); + + return 0; +} + +// RJCTODO: Put common open function for text hdbs here. + +/** + * \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 // RJCTODO: Consider changing to intb_t to allow for error code + */ +uint8_t +tsk_text_hdb_has_index(TSK_HDB_INFO *hdb_info, TSK_HDB_HTYPE_ENUM htype) +{ + uint8_t ret_val = 0; + size_t flen = 0; + TSK_TCHAR *idx_path = NULL; + + flen = TSTRLEN(hdb_info->db_fname) + 32; // RJCTODO: Here it is again... + idx_path = (TSK_TCHAR*)tsk_malloc(flen * sizeof(TSK_TCHAR)); + if (NULL == idx_path) { + return 0; + } + + switch (htype) { + case TSK_HDB_HTYPE_MD5_ID: + TSNPRINTF(idx_path, flen, + _TSK_T("%s-%") PRIcTSK _TSK_T(".idx"), + hdb_info->db_fname, TSK_HDB_HTYPE_MD5_STR); + break; + case TSK_HDB_HTYPE_SHA1_ID: + TSNPRINTF(idx_path, flen, + _TSK_T("%s-%") PRIcTSK _TSK_T(".idx"), + hdb_info->db_fname, TSK_HDB_HTYPE_SHA1_STR); + break; + default: + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_ARG); + tsk_error_set_errstr( + "tsk_text_hdb_has_index: Invalid hash type as argument: %d", htype); + return 0; + } + + ret_val = hdb_file_exists(idx_path); + free(idx_path); + return ret_val; +} + +// RJCTODO: Improve comment +/** Initialize the TSK hash DB index file. This creates the intermediate file, + * which will have entries added to it. This file must be sorted before the + * process is finished. + * + * @param hdb_info Hash database state structure + * @param htype String of index type to create + * + * @return 1 on error and 0 on success + * + */ +uint8_t +text_hdb_idx_init(TSK_HDB_INFO * hdb_info_base, TSK_TCHAR * htype) +{ + const char *func_name = "text_hdb_idx_init"; + TSK_TEXT_HDB_INFO *hdb_info = (TSK_TEXT_HDB_INFO*)hdb_info_base; + TSK_HDB_HTYPE_ENUM hash_type = TSK_HDB_HTYPE_INVALID_ID; + size_t flen = 0; + char dbtmp[32]; + int i = 0; + + /* Use the string of the index/hash type to figure out some + * settings */ + + // convert to char -- cheating way to deal with WCHARs.. + for (i = 0; i < 31 && htype[i] != '\0'; i++) { + dbtmp[i] = (char) htype[i]; + } + dbtmp[i] = '\0'; + + if (strcmp(dbtmp, TSK_HDB_DBTYPE_NSRL_MD5_STR) == 0) { + + if (hdb_info_base->db_type != TSK_HDB_DBTYPE_NSRL_ID) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_ARG); + tsk_error_set_errstr( + "%s: database detected as: %d index creation as: %d", + func_name, hdb_info_base->db_type, TSK_HDB_DBTYPE_NSRL_ID); + return 1; + } + hash_type = TSK_HDB_HTYPE_MD5_ID; + } + else if (strcmp(dbtmp, TSK_HDB_DBTYPE_NSRL_SHA1_STR) == 0) { + if (hdb_info_base->db_type != TSK_HDB_DBTYPE_NSRL_ID) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_ARG); + tsk_error_set_errstr( + "%s: database detected as: %d index creation as: %d", + func_name, hdb_info_base->db_type, TSK_HDB_DBTYPE_NSRL_ID); + return 1; + } + hash_type = TSK_HDB_HTYPE_SHA1_ID; + } + else if (strcmp(dbtmp, TSK_HDB_DBTYPE_MD5SUM_STR) == 0) { + if (hdb_info_base->db_type != TSK_HDB_DBTYPE_MD5SUM_ID) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_ARG); + tsk_error_set_errstr( + "%s: database detected as: %d index creation as: %d", + func_name, hdb_info_base->db_type, TSK_HDB_DBTYPE_MD5SUM_ID); + return 1; + } + hash_type = TSK_HDB_HTYPE_MD5_ID; + } + else if (strcmp(dbtmp, TSK_HDB_DBTYPE_HK_STR) == 0) { + if (hdb_info_base->db_type != TSK_HDB_DBTYPE_HK_ID) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_ARG); + tsk_error_set_errstr( + "%s: database detected as: %d index creation as: %d", + func_name, hdb_info_base->db_type, TSK_HDB_DBTYPE_HK_ID); + return 1; + } + hash_type = TSK_HDB_HTYPE_MD5_ID; + } + else if (strcmp(dbtmp, TSK_HDB_DBTYPE_ENCASE_STR) == 0) { + if (hdb_info_base->db_type != TSK_HDB_DBTYPE_ENCASE_ID) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_ARG); + tsk_error_set_errstr( + "%s: database detected as: %d index creation as: %d", + func_name, hdb_info_base->db_type, TSK_HDB_DBTYPE_ENCASE_ID); + return 1; + } + hash_type = TSK_HDB_HTYPE_MD5_ID; + } + else { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_ARG); + tsk_error_set_errstr( + "%s: Unknown database/hash type request: %s", + func_name, dbtmp); + return 1; + } + + /* Setup the internal hash information */ + if (text_hdb_init_idx_hash_type_info(hdb_info_base, hash_type = )) { + return 1; + } + + /* Make the name for the unsorted intermediate index file */ + flen = TSTRLEN(hdb_info_base->db_fname) + 32; + hdb_info->uns_fname = + (TSK_TCHAR *) tsk_malloc(flen * sizeof(TSK_TCHAR)); + if (hdb_info->uns_fname == NULL) { + return 1; + } + TSNPRINTF(hdb_info->uns_fname, flen, + _TSK_T("%s-%") PRIcTSK _TSK_T("-ns.idx"), hdb_info_base->db_fname, + TSK_HDB_HTYPE_STR(hdb_info->hash_type)); + + + /* Create temp unsorted file of offsets */ +#ifdef TSK_WIN32 + { + HANDLE hWin; + + if ((hWin = CreateFile(hdb_info->uns_fname, GENERIC_WRITE, + 0, 0, CREATE_ALWAYS, 0, 0)) == + INVALID_HANDLE_VALUE) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_CREATE); + tsk_error_set_errstr( + "%s: %"PRIttocTSK" GetFileSize: %d", + func_name, hdb_info->uns_fname, (int)GetLastError()); + return 1; + } + + hdb_info->hIdxTmp = + _fdopen(_open_osfhandle((intptr_t) hWin, _O_WRONLY), "wb"); + if (hdb_info->hIdxTmp == NULL) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_OPEN); + tsk_error_set_errstr( + "%s: Error converting Windows handle to C handle", func_name); + free(hdb_info); + return 1; + } + } +#else + if (NULL == (hdb_info->hIdxTmp = fopen(hdb_info->uns_fname, "w"))) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_CREATE); + tsk_error_set_errstr( + "%s: Error creating temp index file: %s", + func_name, hdb_info->uns_fname); + return 1; + } +#endif + + /* Print the header */ + fprintf(hdb_info->hIdxTmp, "%s|%s\n", TSK_HDB_IDX_HEAD_NAME_STR, + hdb_info->db_name); + switch (hdb_info_base->db_type) { + case TSK_HDB_DBTYPE_NSRL_ID: + fprintf(hdb_info->hIdxTmp, "%s|%s\n", TSK_HDB_IDX_HEAD_TYPE_STR, + TSK_HDB_DBTYPE_NSRL_STR); + break; + case TSK_HDB_DBTYPE_MD5SUM_ID: + fprintf(hdb_info->hIdxTmp, "%s|%s\n", TSK_HDB_IDX_HEAD_TYPE_STR, + TSK_HDB_DBTYPE_MD5SUM_STR); + break; + case TSK_HDB_DBTYPE_HK_ID: + fprintf(hdb_info->hIdxTmp, "%s|%s\n", TSK_HDB_IDX_HEAD_TYPE_STR, + TSK_HDB_DBTYPE_HK_STR); + break; + case TSK_HDB_DBTYPE_ENCASE_ID: + fprintf(hdb_info->hIdxTmp, "%s|%s\n", TSK_HDB_IDX_HEAD_TYPE_STR, + TSK_HDB_DBTYPE_ENCASE_STR); + break; + /* Used to stop warning messages about missing enum value */ + case TSK_HDB_DBTYPE_IDXONLY_ID: + default: + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_CREATE); + tsk_error_set_errstr("%s: Invalid db type", func_name); + return 1; + } + + return 0; +} + +/** + * Add a string entry to the intermediate index file. + * + * @param hdb_info Hash database state info + * @param hvalue String of hash value to add + * @param offset Byte offset of hash entry in original database. + * @return 1 on error and 0 on success + */ +uint8_t +text_hdb_idx_add_entry(TSK_HDB_INFO * hdb_info_base, char *hvalue, TSK_OFF_T offset) +{ + TSK_TEXT_HDB_INFO *hdb_info = (TSK_TEXT_HDB_INFO*)hdb_info_base; + int i; + + // make the hashes all upper case + for (i = 0; hvalue[i] != '\0'; i++) { + if (islower((int) hvalue[i])) + fprintf(hdb_info->hIdxTmp, "%c", toupper((int) hvalue[i])); + else + fprintf(hdb_info->hIdxTmp, "%c", hvalue[i]); + } + + /* Print the entry to the unsorted index file */ + fprintf(hdb_info->hIdxTmp, "|%.16llu\n", (unsigned long long) offset); + + return 0; +} + +/** + * Add a binary entry to the intermediate index file. + * + * @param hdb_info Hash database state info + * @param hvalue Array of integers of hash value to add + * @param hlen Number of bytes in hvalue + * @param offset Byte offset of hash entry in original database. + * @return 1 on error and 0 on success + */ +uint8_t +text_hdb_idx_add_entry_bin(TSK_HDB_INFO * hdb_info_base, unsigned char *hvalue, int hlen, TSK_OFF_T offset) +{ + TSK_TEXT_HDB_INFO *hdb_info = (TSK_TEXT_HDB_INFO*)hdb_info_base; + int i; + + for (i = 0; i < hlen; i++) { + fprintf(hdb_info->hIdxTmp, "%02X", hvalue[i]); + } + + /* Print the entry to the unsorted index file */ + fprintf(hdb_info->hIdxTmp, "|%.16llu\n", (unsigned long long) offset); + + return 0; +} + +/** + * Finalize index creation process by sorting the index and removing the + * intermediate temp file. + * + * @param hdb_info Hash database state info structure. + * @return 1 on error and 0 on success + */ +uint8_t +text_hdb_idx_finalize(TSK_HDB_INFO * hdb_info_base) +{ + TSK_TEXT_HDB_INFO *hdb_info = (TSK_TEXT_HDB_INFO*)hdb_info_base; + +#ifdef TSK_WIN32 + wchar_t buf[TSK_HDB_MAXLEN]; + /// @@ Expand this to be SYSTEM_ROOT -- GetWindowsDirectory() + wchar_t *sys32 = _TSK_T("C:\\WINDOWS\\System32\\sort.exe"); + DWORD stat; + STARTUPINFO myStartInfo; + PROCESS_INFORMATION pinfo; + + /* Close the unsorted file */ + fclose(hdb_info->hIdxTmp); + hdb_info->hIdxTmp = NULL; + + /* Close the existing index if it is open */ + if (hdb_info->hIdx) { + fclose(hdb_info->hIdx); + hdb_info->hIdx = NULL; + } + + if (tsk_verbose) + tsk_fprintf(stderr, "hdb_idxfinalize: Sorting index\n"); + + stat = GetFileAttributes(sys32); + if ((stat != -1) && ((stat & FILE_ATTRIBUTE_DIRECTORY) == 0)) { + TSNPRINTF(buf, TSK_HDB_MAXLEN, _TSK_T("%s /o \"%s\" \"%s\""), + sys32, hdb_info->idx_fname, hdb_info->uns_fname); + } + else { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_MISSING); + tsk_error_set_errstr("Cannot find sort executable"); + return 1; + } + + GetStartupInfo(&myStartInfo); + + if (FALSE == + CreateProcess(NULL, buf, NULL, NULL, FALSE, 0, NULL, NULL, + &myStartInfo, &pinfo)) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_PROC); + tsk_error_set_errstr( + "Error starting sorting index file using %S", buf); + return 1; + } + + if (WAIT_FAILED == WaitForSingleObject(pinfo.hProcess, INFINITE)) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_PROC); + tsk_error_set_errstr( + "Error (waiting) sorting index file using %S", buf); + return 1; + } + + if (FALSE == DeleteFile(hdb_info->uns_fname)) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_DELETE); + tsk_error_set_errstr( + "Error deleting temp file: %d", (int)GetLastError()); + return 1; + } +#else + char buf[TSK_HDB_MAXLEN]; + char *root = "/bin/sort"; + char *usr = "/usr/bin/sort"; + char *local = "/usr/local/bin/sort"; + struct stat stats; + + if (tsk_verbose) + tsk_fprintf(stderr, "hdb_idxfinalize: Sorting index\n"); + + /* Close the unsorted file */ + fclose(hdb_info->hIdxTmp); + hdb_info->hIdxTmp = NULL; + + /* Close the existing index if it is open */ + if (hdb_info->hIdx) { + fclose(hdb_info->hIdx); + hdb_info->hIdx = NULL; + } + + if (0 == stat(local, &stats)) { + snprintf(buf, TSK_HDB_MAXLEN, "%s -o %s %s", local, + hdb_info->idx_fname, hdb_info->uns_fname); + } + else if (0 == stat(usr, &stats)) { + snprintf(buf, TSK_HDB_MAXLEN, "%s -o \"%s\" \"%s\"", + usr, hdb_info->idx_fname, hdb_info->uns_fname); + } + else if (0 == stat(root, &stats)) { + snprintf(buf, TSK_HDB_MAXLEN, "%s -o \"%s\" \"%s\"", + root, hdb_info->idx_fname, hdb_info->uns_fname); + } + else { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_MISSING); + tsk_error_set_errstr("Cannot find sort executable"); + return 1; + } + + if (0 != system(buf)) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_PROC); + tsk_error_set_errstr( + "Error sorting index file using %s", buf); + return 1; + } + + unlink(hdb_info->uns_fname); +#endif + + return 0; +} + +/** + * \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_base, const char *hash, + TSK_HDB_FLAG_ENUM flags, TSK_HDB_LOOKUP_FN action, + void *ptr) +{ + TSK_TEXT_HDB_INFO *hdb_info = (TSK_TEXT_HDB_INFO*)hdb_info_base; + TSK_OFF_T poffset; + TSK_OFF_T up; // Offset of the first byte past the upper limit that we are looking in + TSK_OFF_T low; // offset of the first byte of the lower limit that we are looking in + int cmp; + uint8_t wasFound = 0; + size_t i; + uint8_t htype; + + + /* 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( + "hdb_lookup: Invalid hash length: %s", hash); + return -1; + } + + for (i = 0; i < strlen(hash); i++) { + if (isxdigit((int) hash[i]) == 0) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_ARG); + tsk_error_set_errstr( + "hdb_lookup: Invalid hash value (hex only): %s", + hash); + return -1; + } + } + + if (text_hdb_open_idx(hdb_info_base, htype)) + return -1; + + + /* Sanity check */ + if (hdb_info->hash_len != strlen(hash)) { + 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 %Zd)", + hdb_info->hash_len, strlen(hash)); + return -1; + } + + + low = hdb_info->idx_off; + up = hdb_info->idx_size; + + poffset = 0; + + // We have to lock access to idx_lbuf, but since we're in a loop, + // I'm assuming one lock up front is better than many inside. + tsk_take_lock(&hdb_info_base->lock); + + while (1) { + TSK_OFF_T offset; + + /* If top and bottom are the same, it's not there */ + if (up == low) { + tsk_release_lock(&hdb_info_base->lock); + return 0; + } + + /* Get the middle of the windows that we are looking at */ + offset = rounddown(((up - low) / 2), hdb_info->idx_llen); + + /* Sanity Check */ + if ((offset % hdb_info->idx_llen) != 0) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_CORRUPT); + tsk_error_set_errstr( + "hdb_lookup: Error, new offset is not a multiple of the line length"); + return -1; + } + + /* The middle offset is relative to the low offset, so add them */ + offset += low; + + /* If we didn't move, then it's not there */ + if (poffset == offset) { + tsk_release_lock(&hdb_info_base->lock); + return 0; + } + + /* Seek to the offset and read it */ + if (0 != fseeko(hdb_info->hIdx, offset, SEEK_SET)) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_READIDX); + tsk_error_set_errstr( + "hdb_lookup: Error seeking in search: %" PRIuOFF, + offset); + return -1; + } + + if (NULL == + fgets(hdb_info->idx_lbuf, (int) hdb_info->idx_llen + 1, + hdb_info->hIdx)) { + if (feof(hdb_info->hIdx)) { + tsk_release_lock(&hdb_info_base->lock); + return 0; + } + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_READIDX); + tsk_error_set_errstr( + "Error reading index file: %lu", + (unsigned long) offset); + return -1; + } + + /* Sanity Check */ + if ((strlen(hdb_info->idx_lbuf) < hdb_info->idx_llen) || + (hdb_info->idx_lbuf[hdb_info->hash_len] != '|')) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_CORRUPT); + tsk_error_set_errstr( + "Invalid line in index file: %lu (%s)", + (unsigned long) (offset / hdb_info->idx_llen), + hdb_info->idx_lbuf); + return -1; + } + + /* Set the delimter to NULL so we can treat the hash as a string */ + hdb_info->idx_lbuf[hdb_info->hash_len] = '\0'; + cmp = strcasecmp(hdb_info->idx_lbuf, hash); + + /* The one we just read is too small, so set the new lower bound + * at the start of the next row */ + if (cmp < 0) { + low = offset + hdb_info->idx_llen; + } + + /* The one we just read is too big, so set the upper bound at this + * entry */ + else if (cmp > 0) { + up = offset; + } + + /* We found it */ + else { + wasFound = 1; + + if ((flags & TSK_HDB_FLAG_QUICK) + || (hdb_info_base->db_type == TSK_HDB_DBTYPE_IDXONLY_ID)) { + tsk_release_lock(&hdb_info_base->lock); + return 1; + } + else { + TSK_OFF_T tmpoff, db_off; + +#ifdef TSK_WIN32 + db_off = + _atoi64(&hdb_info->idx_lbuf[hdb_info->hash_len + 1]); +#else + db_off = + strtoull(&hdb_info->idx_lbuf[hdb_info->hash_len + 1], + NULL, 10); +#endif + + /* Print the one that we found first */ + if (hdb_info-> + getentry(hdb_info_base, hash, db_off, flags, action, ptr)) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_set_errstr2( "hdb_lookup"); + return -1; + } + + + /* there could be additional entries both before and after + * this entry - but we can restrict ourselves to the up + * and low bounds from our previous hunting + */ + + tmpoff = offset - hdb_info->idx_llen; + while (tmpoff >= low) { + + /* Break if we are at the header */ + if (tmpoff <= 0) + break; + + if (0 != fseeko(hdb_info->hIdx, tmpoff, SEEK_SET)) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_READIDX); + tsk_error_set_errstr( + "hdb_lookup: Error seeking for prev entries: %" + PRIuOFF, tmpoff); + return -1; + } + + if (NULL == + fgets(hdb_info->idx_lbuf, + (int) hdb_info->idx_llen + 1, + hdb_info->hIdx)) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_READIDX); + tsk_error_set_errstr( + "Error reading index file (prev): %lu", + (unsigned long) tmpoff); + return -1; + } + else if (strlen(hdb_info->idx_lbuf) < + hdb_info->idx_llen) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_CORRUPT); + tsk_error_set_errstr( + "Invalid index file line (prev): %lu", + (unsigned long) tmpoff); + return -1; + } + + hdb_info->idx_lbuf[hdb_info->hash_len] = '\0'; + if (strcasecmp(hdb_info->idx_lbuf, hash) != 0) { + break; + } + +#ifdef TSK_WIN32 + db_off = + _atoi64(&hdb_info-> + idx_lbuf[hdb_info->hash_len + 1]); +#else + + db_off = + strtoull(&hdb_info-> + idx_lbuf[hdb_info->hash_len + 1], NULL, + 10); +#endif + if (hdb_info-> + getentry(hdb_info_base, hash, db_off, flags, action, + ptr)) { + tsk_release_lock(&hdb_info_base->lock); + return -1; + } + tmpoff -= hdb_info->idx_llen; + } + + /* next entries */ + tmpoff = offset + hdb_info->idx_llen; + while (tmpoff < up) { + + if (0 != fseeko(hdb_info->hIdx, tmpoff, SEEK_SET)) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_READIDX); + tsk_error_set_errstr( + "hdb_lookup: Error seeking for next entries: %" + PRIuOFF, tmpoff); + return -1; + } + + if (NULL == + fgets(hdb_info->idx_lbuf, + (int) hdb_info->idx_llen + 1, + hdb_info->hIdx)) { + if (feof(hdb_info->hIdx)) + break; + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_READIDX); + tsk_error_set_errstr( + "Error reading index file (next): %lu", + (unsigned long) tmpoff); + return -1; + } + else if (strlen(hdb_info->idx_lbuf) < + hdb_info->idx_llen) { + tsk_release_lock(&hdb_info_base->lock); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_CORRUPT); + tsk_error_set_errstr( + "Invalid index file line (next): %lu", + (unsigned long) tmpoff); + return -1; + } + + hdb_info->idx_lbuf[hdb_info->hash_len] = '\0'; + if (strcasecmp(hdb_info->idx_lbuf, hash) != 0) { + break; + } +#ifdef TSK_WIN32 + db_off = + _atoi64(&hdb_info-> + idx_lbuf[hdb_info->hash_len + 1]); +#else + db_off = + strtoull(&hdb_info-> + idx_lbuf[hdb_info->hash_len + 1], NULL, + 10); +#endif + if (hdb_info-> + getentry(hdb_info_base, hash, db_off, flags, action, + ptr)) { + tsk_release_lock(&hdb_info_base->lock); + return -1; + } + + tmpoff += hdb_info->idx_llen; + } + } + break; + } + poffset = offset; + } + tsk_release_lock(&hdb_info_base->lock); + + return wasFound; +} + +/** + * \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_raw(TSK_HDB_INFO * hdb_info, uint8_t * hash, uint8_t len, + TSK_HDB_FLAG_ENUM flags, + TSK_HDB_LOOKUP_FN action, void *ptr) +{ + char hashbuf[TSK_HDB_HTYPE_SHA1_LEN + 1]; + int i; + static const char hex[] = "0123456789abcdef"; + + if (2 * len > TSK_HDB_HTYPE_SHA1_LEN) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_HDB_ARG); + tsk_error_set_errstr( + "tsk_hdb_lookup_raw: hash value too long\n"); + return -1; + } + + for (i = 0; i < len; i++) { + hashbuf[2 * i] = hex[(hash[i] >> 4) & 0xf]; + hashbuf[2 * i + 1] = hex[hash[i] & 0xf]; + } + hashbuf[2 * len] = '\0'; + + return tsk_hdb_lookup_str(hdb_info, hashbuf, flags, action, ptr); +} + void text_db_close(TSK_HDB_INFO *hdb_info) { diff --git a/tsk/hashdb/tsk_hashdb.h b/tsk/hashdb/tsk_hashdb.h index 2d58efd4affa9c44f111caa45aefd4bb48096f7e..05f82c6b5c169e5a3817cab4559645a329cea5a5 100644 --- a/tsk/hashdb/tsk_hashdb.h +++ b/tsk/hashdb/tsk_hashdb.h @@ -2,7 +2,7 @@ * The Sleuth Kit * * Brian Carrier [carrier <at> sleuthkit [dot] org] - * Copyright (c) 2003-2011 Brian Carrier. All rights reserved + * Copyright (c) 2003-2014 Brian Carrier. All rights reserved */ /** @@ -116,26 +116,26 @@ extern "C" { const char *name, void *); - typedef struct TSK_HDB_EXTERNAL_IDX_INFO { - char db_name[TSK_HDB_NAME_MAXLEN]; ///< Name of the database // RJCTODO: This is probably only needed for an indexed db - uint8_t(*open)(TSK_HDB_INFO *, uint8_t); - uint8_t(*initialize)(TSK_HDB_INFO *, TSK_TCHAR *); - uint8_t(*addentry)(TSK_HDB_INFO *, char *, TSK_OFF_T); - uint8_t(*addentry_bin)(TSK_HDB_INFO *, unsigned char *, int, TSK_OFF_T); - uint8_t(*finalize)(TSK_HDB_INFO *); - void(*close)(TSK_HDB_INFO *); - } TSK_HDB_EXTERNAL_IDX_INFO; - - typedef struct TSK_HDB_BINSRCH_IDX_INFO { - TSK_HDB_EXTERNAL_IDX_INFO base; - FILE *hIdx; ///< File handle to index (only open during lookups) - FILE *hIdxTmp; ///< File handle to temp (unsorted) index file (only open during index creation) - TSK_TCHAR *uns_fname; ///< Name of unsorted index file - TSK_OFF_T idx_size; ///< Size of index file - uint16_t idx_off; ///< Offset in index file to first index entry - size_t idx_llen; ///< Length of each line in index - char *idx_lbuf; ///< Buffer to hold a line from the index (r/w shared - lock) - } TSK_HDB_BINSRCH_IDX_INFO; + //typedef struct TSK_HDB_EXTERNAL_IDX_INFO { + // char db_name[TSK_HDB_NAME_MAXLEN]; ///< Name of the database // RJCTODO: This is probably only needed for an indexed db + // uint8_t(*open)(TSK_HDB_INFO *, uint8_t); + // uint8_t(*initialize)(TSK_HDB_INFO *, TSK_TCHAR *); + // uint8_t(*addentry)(TSK_HDB_INFO *, char *, TSK_OFF_T); + // uint8_t(*addentry_bin)(TSK_HDB_INFO *, unsigned char *, int, TSK_OFF_T); + // uint8_t(*finalize)(TSK_HDB_INFO *); + // void(*close)(TSK_HDB_INFO *); + //} TSK_HDB_EXTERNAL_IDX_INFO; + + //typedef struct TSK_HDB_BINSRCH_IDX_INFO { + // TSK_HDB_EXTERNAL_IDX_INFO base; + // FILE *hIdx; ///< File handle to index (only open during lookups) + // FILE *hIdxTmp; ///< File handle to temp (unsorted) index file (only open during index creation) + // TSK_TCHAR *uns_fname; ///< Name of unsorted index file + // TSK_OFF_T idx_size; ///< Size of index file + // uint16_t idx_off; ///< Offset in index file to first index entry + // size_t idx_llen; ///< Length of each line in index + // char *idx_lbuf; ///< Buffer to hold a line from the index (r/w shared - lock) + //} TSK_HDB_BINSRCH_IDX_INFO; /** * Holds information about an open hash database. Created by @@ -143,13 +143,13 @@ extern "C" { */ struct TSK_HDB_INFO { TSK_TCHAR *db_fname; ///< Database file path, may be NULL for index only database - TSK_TCHAR *idx_fname; ///< Name of index file, may be NULL for database without external index TSK_HDB_DBTYPE_ENUM db_type; ///< Type of database uint8_t updateable; ///< Allow new entries to be added? // RJCTODO: Could be done by dbtype, as is also true for - uint8_t uses_external_index; - TSK_HDB_HTYPE_ENUM hash_type; ///< Type of hash used in index // RJCTODO: Not needed for SQLITE? - uint16_t hash_len; ///< Length of hash // RJCTODO: Not needed for SQLITE? + uint8_t uses_external_indexes; + //TSK_HDB_HTYPE_ENUM hash_type; ///< Type of hash used in index // RJCTODO: Not needed for SQLITE? + //uint16_t hash_len; ///< Length of hash // RJCTODO: Not needed for SQLITE? tsk_lock_t lock; ///< Lock for lazy loading and idx_lbuf + uint8_t(*has_index)(TSK_HDB_INFO *, TSK_HDB_HTYPE_ENUM); uint8_t(*makeindex)(TSK_HDB_INFO *, TSK_TCHAR *); ///< \internal Database-specific function to make index uint8_t(*set_index_params)(TSK_HDB_INFO *hdb_info, TSK_HDB_DBTYPE_ENUM htype); int8_t(*lookup_str)(TSK_HDB_INFO *, const char *, TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *); @@ -161,9 +161,20 @@ extern "C" { typedef struct TSK_TEXT_HDB_INFO { TSK_HDB_INFO base; + char db_name[TSK_HDB_NAME_MAXLEN]; ///< Name of the database // RJCTODO: This is probably only needed for an indexed db FILE *hDb; ///< File handle to database (always open) uint8_t(*getentry) (TSK_HDB_INFO *, const char *, TSK_OFF_T, TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *); ///< \internal Database-specific function to find entry at a given offset // RJCTODO: Text DB thing - TSK_HDB_EXTERNAL_IDX_INFO *idx; + //TSK_HDB_EXTERNAL_IDX_INFO *idx; + TSK_HDB_HTYPE_ENUM hash_type; ///< Type of hash used in index // RJCTODO: Not needed for SQLITE? + uint16_t hash_len; ///< Length of hash // RJCTODO: Not needed for SQLITE? + TSK_TCHAR *idx_fname; ///< Name of index file, may be NULL for database without external index + FILE *hIdx; ///< File handle to index (only open during lookups) + FILE *hIdxTmp; ///< File handle to temp (unsorted) index file (only open during index creation) + TSK_TCHAR *uns_fname; ///< Name of unsorted index file + TSK_OFF_T idx_size; ///< Size of index file + uint16_t idx_off; ///< Offset in index file to first index entry + size_t idx_llen; ///< Length of each line in index + char *idx_lbuf; ///< Buffer to hold a line from the index (r/w shared - lock) } TSK_TEXT_HDB_INFO; typedef struct TSK_SQLITE_HDB_INFO { @@ -188,7 +199,8 @@ extern "C" { extern void tsk_hdb_close(TSK_HDB_INFO * hdb_info); - extern uint8_t tsk_hdb_hasindex(TSK_HDB_INFO *, uint8_t htype); + extern uint8_t tsk_hdb_hasindex(TSK_HDB_INFO *, uint8_t htype); // RJCTODO: to go away + extern uint8_t tsk_text_hdb_has_index(TSK_HDB_INFO * hdb_info, TSK_HDB_HTYPE_ENUM htype); extern uint8_t tsk_set_index_params(TSK_HDB_INFO *hdb_info, TSK_HDB_DBTYPE_ENUM htype); @@ -200,7 +212,7 @@ extern "C" { extern uint8_t tsk_hdb_regenerate_index(TSK_HDB_INFO *, TSK_TCHAR *, uint8_t); - extern int8_t tsk_hdb_add_str(TSK_HDB_INFO * hdb_info, + extern int8_t tsk_hdb_add_hash(TSK_HDB_INFO * hdb_info, const char * filename, const char * md5, const char * sha1, diff --git a/tsk/hashdb/tsk_hashdb_i.h b/tsk/hashdb/tsk_hashdb_i.h index 895696c42e4a4e4e96ef484b897d06205d57aafb..1fd05d8d27dae2c702fafdd5b45c767f18091c5d 100644 --- a/tsk/hashdb/tsk_hashdb_i.h +++ b/tsk/hashdb/tsk_hashdb_i.h @@ -72,6 +72,9 @@ extern "C" { // Warning: changing the hash storage type changes the Db schema //#define IDX_SQLITE_STORE_TEXT + // Utils RJCTODO + extern uint8_t hdb_file_exists(TSK_TCHAR *file_path); + // "Generic" functions that apply to all types or delegate to hash database type-specific functions. extern uint8_t hdb_setupindex(TSK_HDB_INFO * hdb_info, uint8_t htype); // RJCTODO: Where is the tsk_ ? extern void tsk_idx_close(TSK_HDB_INFO * hdb_info); @@ -83,6 +86,11 @@ extern "C" { extern void tsk_hdb_name_from_path(TSK_HDB_INFO *); // Hash database functions common to all text hash databases. + extern TSK_TEXT_HDB_INFO *text_hdb_open(FILE *hDb, const TSK_TCHAR *db_path); + extern uint8_t text_hdb_idx_init(TSK_HDB_INFO *, TSK_TCHAR *); + extern uint8_t text_hdb_idx_add_entry(TSK_HDB_INFO *, char *, TSK_OFF_T); + extern uint8_t text_hdb_idx_finalize(TSK_HDB_INFO *); + extern void text_db_close(TSK_HDB_INFO *hdb_info) ; // Hash database functions for NSRL hash databases. @@ -121,7 +129,7 @@ extern "C" { TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *); - // Hash database functions for ASCII index files standing in for the original hash databases. + // Hash database functions for text index files standing in for the original hash databases. extern TSK_HDB_INFO *idxonly_open(const TSK_TCHAR *db_path); extern void idxonly_name(TSK_HDB_INFO *); extern uint8_t idxonly_makeindex(TSK_HDB_INFO *, TSK_TCHAR * htype); @@ -132,7 +140,7 @@ extern "C" { // Hash database functions for SQLite hash databases. extern TSK_HDB_INFO *sqlite_hdb_open(TSK_TCHAR *db_path); extern uint8_t sqlite_hdb_set_index_params(TSK_HDB_INFO *hdb_info, TSK_HDB_DBTYPE_ENUM hash_type); - extern uint8_t sqlite_hdb_make_index(TSK_HDB_INFO *hdb_info, TSK_HDB_DBTYPE_ENUM hash_type); // RJCTODO: Probably do not need type, set by above func + extern uint8_t sqlite_hdb_make_index(TSK_HDB_INFO *, TSK_TCHAR * htype); // Index functions for ASCII indexes for hash databases. extern uint8_t binsrch_open(TSK_HDB_INFO * hdb_info, uint8_t htype); @@ -151,21 +159,14 @@ extern "C" { extern int8_t binsrch_get_properties(TSK_HDB_INFO * hdb_info); // Hash database and index functions for SQLite hash databases. - extern uint8_t sqlite_hdb_make_index(TSK_HDB_INFO *, TSK_TCHAR * htype); extern uint8_t sqlite_hdb_get_entry(TSK_HDB_INFO *, const char *, TSK_OFF_T, TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *); extern uint8_t sqlite_hdb_create_db(TSK_TCHAR*); extern sqlite3 *sqlite_hdb_open_db(TSK_TCHAR*); extern void sqlite_hdb_close(TSK_HDB_INFO*); - extern uint8_t sqlite_v1_initialize(TSK_HDB_INFO *, TSK_TCHAR *); - extern uint8_t sqlite_v1_begin(TSK_HDB_INFO *); - extern uint8_t sqlite_v1_addentry(TSK_HDB_INFO *, char *, TSK_OFF_T); - extern uint8_t sqlite_v1_addentry_bin(TSK_HDB_INFO *, unsigned char *, int, TSK_OFF_T); - extern uint8_t sqlite_v1_finalize(TSK_HDB_INFO *); extern int8_t sqlite_v1_lookup_str(TSK_HDB_INFO *, const char *, TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *); extern int8_t sqlite_v1_lookup_raw(TSK_HDB_INFO *, uint8_t *, uint8_t, TSK_HDB_FLAG_ENUM, TSK_HDB_LOOKUP_FN, void *); extern void * sqlite_v1_getAllData(TSK_HDB_INFO *, unsigned long hashId); extern int8_t sqlite_v1_get_properties(TSK_HDB_INFO * hdb_info); - extern uint8_t sqlite3_test(FILE *); #ifdef __cplusplus } diff --git a/win32/libtsk/libtsk.vcxproj b/win32/libtsk/libtsk.vcxproj index d42284f753bf4589d1a372e3d1c608ec8b5233de..0eec65eb9ca2ee49d408ef5032222bba390a1cf5 100755 --- a/win32/libtsk/libtsk.vcxproj +++ b/win32/libtsk/libtsk.vcxproj @@ -293,6 +293,7 @@ copy "$(LIBEWF_HOME)\msvscpp\x64\release\zlib.dll" "$(OutDir)" <ClCompile Include="..\..\tsk\img\raw.c" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\..\tsk\hashdb\sqlite_index.h" /> <ClInclude Include="..\..\tsk\vs\tsk_bsd.h" /> <ClInclude Include="..\..\tsk\vs\tsk_dos.h" /> <ClInclude Include="..\..\tsk\vs\tsk_gpt.h" /> diff --git a/win32/libtsk/libtsk.vcxproj.filters b/win32/libtsk/libtsk.vcxproj.filters index 2c6324ccdb8ca1c8d8bf6d15ccf1bd54a8835df2..a798dcd7956a6e97eeae795ea2d147dc1987eabb 100755 --- a/win32/libtsk/libtsk.vcxproj.filters +++ b/win32/libtsk/libtsk.vcxproj.filters @@ -379,5 +379,8 @@ <Filter>img</Filter> </ClInclude> <ClInclude Include="..\..\tsk\fs\tsk_yaffs.h" /> + <ClInclude Include="..\..\tsk\hashdb\sqlite_index.h"> + <Filter>hash</Filter> + </ClInclude> </ItemGroup> </Project> \ No newline at end of file