/** * \ingroup hashdblib * Sets hash database name in hdb_info based on database file path. * @param hdb_info Struct representation of an open hash database. */ void hdb_base_db_name_from_path(TSK_HDB_INFO *hdb_info) { #ifdef TSK_WIN32 const char PATH_CHAR = '\\'; #else const char PATH_CHAR = '/'; #endif TSK_TCHAR * begin; TSK_TCHAR * end; int i; hdb_info->db_name[0] = '\0'; begin = TSTRRCHR(hdb_info->db_fname, PATH_CHAR); #ifdef TSK_WIN32 // cygwin can have forward slashes, so try that too on Windows if (!begin) { begin = TSTRRCHR(hdb_info->db_fname, '/'); } #endif if (!begin) { begin = hdb_info->db_fname; } else { // unlikely since this means that the dbname is "/" if (TSTRLEN(begin) == 1) return; else begin++; } // end points to the byte after the last one we want to use if ((TSTRLEN(hdb_info->db_fname) > 4) && (TSTRICMP(&hdb_info->db_fname[TSTRLEN(hdb_info->db_fname)-4], _TSK_T(".idx")) == 0)) end = &hdb_info->db_fname[TSTRLEN(hdb_info->db_fname)-4]; else end = begin + TSTRLEN(begin); // @@@ This only works for file names with Latin characters. It may need // to be fixed some day. Leave it be for now. for(i = 0; i < (end-begin); i++) { hdb_info->db_name[i] = (char) begin[i]; } hdb_info->db_name[i] = '\0'; }
/** * @param db_path Path to DB, which probably does not exist. But it gets passed in because we need * it in a bunch of places. * @param idx_path Path to index file (should be superset of db_path) */ TSK_HDB_INFO *idxonly_open(const TSK_TCHAR *db_path, const TSK_TCHAR *idx_path) { TSK_HDB_BINSRCH_INFO *hdb_binsrch_info = NULL; TSK_TCHAR *ext; TSK_HDB_HTYPE_ENUM htype; hdb_binsrch_info = hdb_binsrch_open(NULL, db_path); if (NULL == hdb_binsrch_info) { return NULL; } hdb_binsrch_info->base.db_type = TSK_HDB_DBTYPE_IDXONLY_ID; // open the index ext = TSTRRCHR(idx_path, _TSK_T('-')); if (ext == NULL) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_HDB_ARG); tsk_error_set_errstr("idxonly_open: invalid file name (no extension): %" PRIttocTSK, idx_path); return NULL; } else if ((TSTRLEN(ext) == 8) && (TSTRICMP(ext, _TSK_T("-md5.idx")) == 0)) { htype = TSK_HDB_HTYPE_MD5_ID; } else if ((TSTRLEN(ext) == 9) && (TSTRICMP(ext, _TSK_T("-sha1.idx")) == 0)) { htype = TSK_HDB_HTYPE_SHA1_ID; } else { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_HDB_ARG); tsk_error_set_errstr("idxonly_open: invalid file name (unknown extension): %" PRIttocTSK, idx_path); return NULL; } if (hdb_binsrch_open_idx((TSK_HDB_INFO*)hdb_binsrch_info, htype)) { return NULL; } if (idxonly_name(hdb_binsrch_info)) { hdb_binsrch_close((TSK_HDB_INFO*)hdb_binsrch_info); return NULL; } hdb_binsrch_info->base.get_db_path = idxonly_get_db_path; hdb_binsrch_info->get_entry = idxonly_getentry; // Before returning, do one final check that we'll be able to open // the index file if (hdb_binsrch_open_idx((TSK_HDB_INFO*)hdb_binsrch_info, hdb_binsrch_info->hash_type)) { hdb_binsrch_close((TSK_HDB_INFO*)hdb_binsrch_info); return NULL; } return (TSK_HDB_INFO*)hdb_binsrch_info; }
/** * \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) { TSK_TCHAR *ext = NULL; 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; } ext = TSTRRCHR(file_path, _TSK_T('.')); if ((NULL != ext) && (TSTRLEN(ext) >= 4) && (TSTRCMP(ext, _TSK_T(".kdb")) == 0)) { return sqlite_hdb_create_db(file_path); } else { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_HDB_ARG); tsk_error_set_errstr("tsk_hdb_create: path must end in .kdb extension"); return 1; } }
/** * \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_open"; uint8_t file_path_is_idx_path = 0; TSK_TCHAR *db_path = NULL; TSK_TCHAR *ext = NULL; FILE *hDb = NULL; FILE *hIdx = NULL; TSK_HDB_DBTYPE_ENUM db_type = TSK_HDB_DBTYPE_INVALID_ID; TSK_HDB_INFO *hdb_info = NULL; 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) == 8 || TSTRLEN(ext) == 9) && ((TSTRCMP(ext, _TSK_T("-md5.idx")) == 0) || TSTRCMP(ext, _TSK_T("-sha1.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(file_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; // included to prevent compiler warnings that it is not used case TSK_HDB_DBTYPE_INVALID_ID: break; } if (NULL != db_path) { free(db_path); } return hdb_info; }
int main(int argc, char ** argv1) { int ch; TSK_TCHAR *idx_type = NULL; TSK_TCHAR *db_file = NULL; TSK_TCHAR *lookup_file = NULL; unsigned int flags = 0; TSK_HDB_INFO *hdb_info; TSK_TCHAR **argv; bool create = false; bool addHash = false; #ifdef TSK_WIN32 // On Windows, get the wide arguments (mingw doesn't support wmain) argv = CommandLineToArgvW(GetCommandLineW(), &argc); if( argv == NULL) { tsk_fprintf(stderr, "Error getting wide arguments\n"); exit(1); } #else argv = (TSK_TCHAR **)argv1; #endif progname = argv[0]; setlocale(LC_ALL, ""); while ((ch = GETOPT(argc, argv, _TSK_T("cef:i:aqV"))) > 0) { switch (ch) { case _TSK_T('e'): flags |= TSK_HDB_FLAG_EXT; break; case _TSK_T('f'): lookup_file = OPTARG; break; case _TSK_T('i'): idx_type = OPTARG; break; case _TSK_T('c'): create = true; break; case _TSK_T('a'): addHash = true; break; case _TSK_T('q'): flags |= TSK_HDB_FLAG_QUICK; break; case _TSK_T('V'): tsk_version_print(stdout); exit(0); default: usage(); } } if ((addHash) && ((idx_type != NULL) || (create))) { tsk_fprintf(stderr, "-a cannot be specified with -c or -i\n"); usage(); } if (OPTIND + 1 > argc) { tsk_fprintf(stderr, "Error: You must provide the source hash database location\n"); usage(); } db_file = argv[OPTIND++]; // Running in create mode (-c option). Make a new hash database and exit. if (create) { if (idx_type != NULL) { tsk_fprintf(stderr, "-c and -i cannot be specified at same time\n"); usage(); } TSK_TCHAR *ext = TSTRRCHR(db_file, _TSK_T('.')); if ((NULL != ext) && (TSTRLEN(ext) >= 4) && (TSTRCMP(ext, _TSK_T(".kdb")) == 0)) { if (0 == tsk_hdb_create(db_file)) { tsk_fprintf(stdout, "New database %" PRIttocTSK" created\n", db_file); return 0; } else { tsk_fprintf(stderr, "Failed to create new database %" PRIttocTSK"\n", db_file); return 1; } } else { tsk_fprintf(stderr, "New database path must end in .kdb extension\n"); return 1; } } // Opening an existing database. if ((hdb_info = tsk_hdb_open(db_file, TSK_HDB_OPEN_NONE)) == NULL) { tsk_error_print(stderr); return 1; } // Now that the database is open and its type is known, if running in add hashes mode (-a option) // see if it takes updates. if (addHash && !tsk_hdb_accepts_updates(hdb_info)) { tsk_fprintf(stderr, "-a option specified, but the specified database does not allow hashes to be added\n"); usage(); } // Running in indexing mode (-i option). Create an index file and exit. if (idx_type != NULL) { if (lookup_file != NULL) { tsk_fprintf(stderr, "'-f' flag can't be used with '-i'\n"); usage(); } if (flags & TSK_HDB_FLAG_QUICK) { tsk_fprintf(stderr, "'-q' flag can't be used with '-i'\n"); usage(); } if (flags & TSK_HDB_FLAG_EXT) { tsk_fprintf(stderr, "'-e' flag can't be used with '-i'\n"); usage(); } if (!tsk_hdb_uses_external_indexes(hdb_info)) { tsk_fprintf(stderr, "Database does not use external indexes, can't be used with '-i'\n"); } if (tsk_hdb_is_idx_only(hdb_info)) { tsk_fprintf(stderr, "Database is index only, can be used for look ups, but can't be used with '-i'\n"); } if (tsk_hdb_make_index(hdb_info, idx_type)) { tsk_error_print(stderr); tsk_hdb_close(hdb_info); return 1; } tsk_fprintf(stdout, "Index created\n"); tsk_hdb_close(hdb_info); return 0; } /* Either lookup hash values or add them to DB. * Check if the values were passed on the command line or via a file */ if (OPTIND < argc) { if ((OPTIND + 1 < argc) && (flags & TSK_HDB_FLAG_QUICK)) { fprintf(stderr, "Error: Only one hash can be given with quick option\n"); usage(); } if ((flags & TSK_HDB_FLAG_EXT) && (flags & TSK_HDB_FLAG_QUICK)) { fprintf(stderr, "'-e' flag can't be used with '-q'\n"); usage(); } if (lookup_file != NULL) { fprintf(stderr, "Error: -f can't be used when hashes are also given\n"); usage(); } /* Loop through all provided hash values */ while (OPTIND < argc) { char htmp[128]; int i; int retval; // convert to char -- lazy way to deal with WCHARs.. for (i = 0; i < 127 && argv[OPTIND][i] != '\0'; i++) { htmp[i] = (char) argv[OPTIND][i]; } htmp[i] = '\0'; if (addHash) { // Write a new hash to the database/index, if it's updateable //@todo support sha1 and sha2-256 retval = tsk_hdb_add_entry(hdb_info, NULL, (const char *)htmp, NULL, NULL, NULL); if (retval == 1) { printf("There was an error adding the hash.\n"); tsk_error_print(stderr); return 1; } else if (retval == 0) { printf("Hash %s added.\n", htmp); } } else { /* Perform lookup */ retval = tsk_hdb_lookup_str(hdb_info, (const char *)htmp, (TSK_HDB_FLAG_ENUM)flags, lookup_act, NULL); if (retval == -1) { tsk_error_print(stderr); return 1; } if (flags & TSK_HDB_FLAG_QUICK) { printf("%d\n", retval); } else if (retval == 0) { print_notfound(htmp); } } OPTIND++; } } /* Hash were given from stdin or a file */ else { char buf[100]; /* If the file was specified, use that - otherwise stdin */ #ifdef TSK_WIN32 HANDLE handle = NULL; if (lookup_file != NULL) { if ((handle = CreateFile(lookup_file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) { TFPRINTF(stderr, _TSK_T("Error opening hash file: %s\n"), lookup_file); exit(1); } } else { handle = GetStdHandle(STD_INPUT_HANDLE); } #else FILE *handle = NULL; if (lookup_file != NULL) { handle = fopen(lookup_file, "r"); if (!handle) { fprintf(stderr, "Error opening hash file: %s\n", lookup_file); exit(1); } } else { handle = stdin; } #endif while (1) { int retval; memset(buf, 0, 100); #ifdef TSK_WIN32 int done = 0; // win32 doesn't have a fgets equivalent, so we make an equivalent one for (int i = 0; i < 100; i++) { DWORD nread; if (FALSE == ReadFile(handle, &buf[i], (DWORD) 1, &nread, NULL)) { done = 1; break; } // skip the windows CR else if (buf[i] == '\r') { buf[i] = '\0'; i--; continue; } else if (buf[i] == '\n') { break; } } if (done) break; #else if (NULL == fgets(buf, 100, handle)) { break; } #endif /* Remove the newline */ buf[strlen(buf) - 1] = '\0'; retval = tsk_hdb_lookup_str(hdb_info, (const char *)buf, (TSK_HDB_FLAG_ENUM)flags, lookup_act, NULL); if (retval == -1) { tsk_error_print(stderr); return 1; } if (flags & TSK_HDB_FLAG_QUICK) { printf("%d\n", retval); break; } else if (retval == 0) { print_notfound(buf); } } #ifdef TSK_WIN32 if (lookup_file != NULL) CloseHandle(handle); #else if (lookup_file != NULL) fclose(handle); #endif } tsk_hdb_close(hdb_info); return 0; }