diff --git a/tsk/auto/auto.cpp b/tsk/auto/auto.cpp index 6c08103fb23f4e25cb84cb76eb8653703033c919..fc95317e234d14153a54749a07718e83ba59eff9 100755 --- a/tsk/auto/auto.cpp +++ b/tsk/auto/auto.cpp @@ -146,6 +146,10 @@ uint8_t TskAuto::openImageHandle(TSK_IMG_INFO * a_img_info) void TskAuto::closeImage() { + for (int i = 0; i < m_poolInfos.size(); i++) { + tsk_pool_close(m_poolInfos[i]); + } + if ((m_img_info) && (m_internalOpen)) { tsk_img_close(m_img_info); } @@ -493,7 +497,10 @@ TskAuto::findFilesInPool(TSK_OFF_T start, TSK_POOL_TYPE_ENUM ptype) registerError(); return TSK_ERR; } - pool->close(pool); + + // Store the pool_info for later use. It will be closed at the end of the add image process. + m_poolInfos.push_back(pool); + return TSK_OK; } diff --git a/tsk/auto/auto_db.cpp b/tsk/auto/auto_db.cpp index 43b84169e186b4603470bb4dbb7f1b41a38e8d00..0fdfdf67090eb6468ae72143481e4f75e3f48afe 100755 --- a/tsk/auto/auto_db.cpp +++ b/tsk/auto/auto_db.cpp @@ -315,6 +315,8 @@ TskAutoDb::filterPool(const TSK_POOL_INFO * pool_info) registerError(); return TSK_FILTER_STOP; } + // Save the parent obj ID for the pool + m_poolOffsetToParentId[pool_info->img_offset] = m_curVolId; } else { // pool doesn't live in a volume, use image as parent @@ -322,13 +324,81 @@ TskAutoDb::filterPool(const TSK_POOL_INFO * pool_info) registerError(); return TSK_FILTER_STOP; } + // Save the parent obj ID for the pool + m_poolOffsetToParentId[pool_info->img_offset] = m_curImgId; } - + // Store the volume system object ID for later use + m_poolOffsetToVsId[pool_info->img_offset] = m_curPoolVs; return TSK_FILTER_CONT; } +/** +* Adds unallocated pool blocks to a new volume. +* +* @param numPool Will be updated with the number of pools processed +* +* @return Returns 0 for success, 1 for failure +*/ +TSK_RETVAL_ENUM +TskAutoDb::addUnallocatedPoolBlocksToDb(size_t & numPool) { + + for (int i = 0; i < m_poolInfos.size(); i++) { + const TSK_POOL_INFO * pool_info = m_poolInfos[i]; + if (m_poolOffsetToVsId.find(pool_info->img_offset) == m_poolOffsetToVsId.end()) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_AUTO_DB); + tsk_error_set_errstr("Error addUnallocatedPoolBlocksToDb() - could not find volume system object ID for pool at offset %lld", pool_info->img_offset); + return TSK_ERR; + } + int64_t curPoolVs = m_poolOffsetToVsId[pool_info->img_offset]; + + /* Make sure the pool_info is still allocated */ + if (pool_info->tag != TSK_POOL_INFO_TAG) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_AUTO_DB); + tsk_error_set_errstr("Error addUnallocatedPoolBlocksToDb() - pool_info is not allocated"); + return TSK_ERR; + } + + /* Only APFS pools are currently supported */ + if (pool_info->ctype != TSK_POOL_TYPE_APFS) { + continue; + } + + /* Increment the count of pools found */ + numPool++; + + /* Create the volume */ + int64_t unallocVolObjId; + m_db->addUnallocatedPoolVolume(pool_info->num_vols, curPoolVs, unallocVolObjId); + + /* Create the unallocated space files */ + TSK_FS_ATTR_RUN * unalloc_runs = tsk_pool_unallocated_runs(pool_info); + TSK_FS_ATTR_RUN * current_run = unalloc_runs; + vector<TSK_DB_FILE_LAYOUT_RANGE> ranges; + while (current_run != NULL) { + + TSK_DB_FILE_LAYOUT_RANGE tempRange(current_run->addr * pool_info->block_size, current_run->len * pool_info->block_size, 0); + + ranges.push_back(tempRange); + int64_t fileObjId = 0; + if (m_db->addUnallocBlockFile(unallocVolObjId, NULL, current_run->len * pool_info->block_size, ranges, fileObjId, m_curImgId)) { + registerError(); + tsk_fs_attr_run_free(unalloc_runs); + return TSK_ERR; + } + + current_run = current_run->next; + ranges.clear(); + } + tsk_fs_attr_run_free(unalloc_runs); + } + + return TSK_OK; +} + TSK_FILTER_ENUM TskAutoDb::filterPoolVol(const TSK_POOL_VOLUME_INFO * pool_vol) { @@ -1032,7 +1102,7 @@ TSK_WALK_RET_ENUM TskAutoDb::fsWalkUnallocBlocksCb(const TSK_FS_BLOCK *a_block, */ TSK_RETVAL_ENUM TskAutoDb::addFsInfoUnalloc(const TSK_DB_FS_INFO & dbFsInfo) { - // Unalloc space is not yet implemented for APFS + // Unalloc space is handled separately for APFS if (dbFsInfo.fType == TSK_FS_TYPE_APFS) { return TSK_OK; } @@ -1103,18 +1173,20 @@ TSK_RETVAL_ENUM TskAutoDb::addUnallocSpaceToDb() { size_t numVsP = 0; size_t numFs = 0; + size_t numPool = 0; TSK_RETVAL_ENUM retFsSpace = addUnallocFsSpaceToDb(numFs); TSK_RETVAL_ENUM retVsSpace = addUnallocVsSpaceToDb(numVsP); + TSK_RETVAL_ENUM retPoolSpace = addUnallocatedPoolBlocksToDb(numPool); - //handle case when no fs and no vs partitions + //handle case when no fs and no vs partitions or pools TSK_RETVAL_ENUM retImgFile = TSK_OK; - if (numVsP == 0 && numFs == 0) { + if (numVsP == 0 && numFs == 0 && numPool == 0) { retImgFile = addUnallocImageSpaceToDb(); } - if (retFsSpace == TSK_ERR || retVsSpace == TSK_ERR || retImgFile == TSK_ERR) + if (retFsSpace == TSK_ERR || retVsSpace == TSK_ERR || retPoolSpace == TSK_ERR || retImgFile == TSK_ERR) return TSK_ERR; else return TSK_OK; @@ -1217,6 +1289,19 @@ TSK_RETVAL_ENUM TskAutoDb::addUnallocVsSpaceToDb(size_t & numVsP) { //skip processing this vspart continue; } + + // Check if the volume contains a pool + bool hasPool = false; + for (std::map<int64_t, int64_t>::iterator iter = m_poolOffsetToParentId.begin(); iter != m_poolOffsetToParentId.end(); ++iter) { + if (iter->second == vsPart.objId) { + hasPool = true; + } + } + if (hasPool) { + // Skip processing this vspart + continue; + } + } //end checking vspart flags //get sector size and image offset from parent vs info diff --git a/tsk/auto/db_postgresql.cpp b/tsk/auto/db_postgresql.cpp index 4afe0e00fa6e847e3ae87dca409565b229ca162a..b7bc126d7bcb8bff0cfb8f7140ac6a74cf621f07 100755 --- a/tsk/auto/db_postgresql.cpp +++ b/tsk/auto/db_postgresql.cpp @@ -1012,8 +1012,18 @@ int TskDbPostgreSQL::addImageName(int64_t objId, char const *imgName, int sequen return ret; } +/** +* Creates a new tsk_pool_info database entry and a new tsk_vs_info +* entry with the tsk_pool_info as its parent. +* +* @ param pool_info The pool to save to the database +* @ param parObjId The ID of the parent of the pool object +* @ param vsObjId Will be set to the object ID of the new volume system created as a child of +* the new pool. +* @returns 1 on error, 0 on success +*/ int -TskDbPostgreSQL::addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObjId, int64_t& objId) { +TskDbPostgreSQL::addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObjId, int64_t& vsObjId) { char stmt[1024]; @@ -1032,11 +1042,11 @@ TskDbPostgreSQL::addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObj } // Add volume system - if (addObject(TSK_DB_OBJECT_TYPE_VS, poolObjId, objId)) + if (addObject(TSK_DB_OBJECT_TYPE_VS, poolObjId, vsObjId)) return 1; snprintf(stmt, 1024, - "INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (%" PRId64 ", %d,%" PRIuDADDR ",%d)", objId, TSK_VS_TYPE_APFS, pool_info->img_offset, pool_info->block_size); + "INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (%" PRId64 ", %d,%" PRIuDADDR ",%d)", vsObjId, TSK_VS_TYPE_APFS, pool_info->img_offset, pool_info->block_size); return attempt_exec(stmt, "Error adding data to tsk_vs_info table: %s\n"); @@ -1044,6 +1054,11 @@ TskDbPostgreSQL::addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObj /** * Adds the sector addresses of the pool volumes into the db. +* +* @param pool_vol The pool volume to save to the DB +* @param parObjId The ID of the parent of the pool volume (should be a volume system) +* @param objId Will be set to the object ID of the new volume +* * @returns 1 on error, 0 on success */ int @@ -1073,6 +1088,41 @@ TskDbPostgreSQL::addPoolVolumeInfo(const TSK_POOL_VOLUME_INFO* pool_vol, return TSK_OK; } +/** +* Adds a fake volume that will hold the unallocated blocks for the pool. +* +* @param vol_index The index for the new volume (should be one higher than the number of pool volumes) +* @param parObjId The object ID of the parent volume system +* @param objId Will be set to the object ID of the new volume +* +* @returns 1 on error, 0 on success +*/ +int +TskDbPostgreSQL::addUnallocatedPoolVolume(int vol_index, int64_t parObjId, int64_t& objId) +{ + + char stmt[1024]; + + if (addObject(TSK_DB_OBJECT_TYPE_VOL, parObjId, objId)) + return 1; + + char *desc = "Unallocated Blocks"; + char *desc_sql = PQescapeLiteral(conn, desc, strlen(desc)); + + snprintf(stmt, 1024, + "INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags)" + "VALUES (%lld, %" PRIuPNUM ",%d, %d, %s, %d)", + objId, vol_index, 0, 0, desc_sql, 0); + + if (attempt_exec(stmt, "Error adding data to tsk_vs_parts table: %s\n")) { + PQfreemem(desc_sql); + return TSK_ERR; + } + + PQfreemem(desc_sql); + return TSK_OK; +} + /** * @returns 1 on error, 0 on success diff --git a/tsk/auto/db_sqlite.cpp b/tsk/auto/db_sqlite.cpp index 2f82aa51bff69cb0af9aec79938993790515de57..2a0e8868f9ef1d5eee4e4726627b772c27ba3655 100644 --- a/tsk/auto/db_sqlite.cpp +++ b/tsk/auto/db_sqlite.cpp @@ -754,17 +754,17 @@ TskDbSqlite::addVsInfo(const TSK_VS_INFO* vs_info, int64_t parObjId, } /** -* Creats a new tsk_pool_info database entry and a new tsk_vs_info +* Creates a new tsk_pool_info database entry and a new tsk_vs_info * entry with the tsk_pool_info as its parent. * * @ param pool_info The pool to save to the database * @ param parObjId The ID of the parent of the pool object -* @ param objId Will be set to the object ID of the new volume system created as a child of +* @ param vsObjId Will be set to the object ID of the new volume system created as a child of * the new pool. * @returns 1 on error, 0 on success */ int -TskDbSqlite::addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObjId, int64_t& objId) { +TskDbSqlite::addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObjId, int64_t& vsObjId) { char stmt[1024]; @@ -784,22 +784,54 @@ TskDbSqlite::addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObjId, } // Add volume system - if (addObject(TSK_DB_OBJECT_TYPE_VS, poolObjId, objId)) + if (addObject(TSK_DB_OBJECT_TYPE_VS, poolObjId, vsObjId)) return 1; snprintf(stmt, 1024, - "INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (%" PRId64 ", %d,%" PRIuDADDR ",%d)", objId, TSK_VS_TYPE_APFS, pool_info->img_offset, pool_info->block_size); // TODO - offset + "INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (%" PRId64 ", %d,%" PRIuDADDR ",%d)", vsObjId, TSK_VS_TYPE_APFS, pool_info->img_offset, pool_info->block_size); // TODO - offset return attempt_exec(stmt, "Error adding data to tsk_vs_info table: %s\n"); } /** -* Adds the sector addresses of the pool volumes into the db. +* Adds a fake volume that will hold the unallocated blocks for the pool. +* +* @param vol_index The index for the new volume (should be one higher than the number of pool volumes) +* @param parObjId The object ID of the parent volume system +* @param objId Will be set to the object ID of the new volume +* +* @returns 1 on error, 0 on success +*/ +int +TskDbSqlite::addUnallocatedPoolVolume(int vol_index, int64_t parObjId, int64_t& objId) +{ + char* zSQL; + int ret; + + if (addObject(TSK_DB_OBJECT_TYPE_VOL, parObjId, objId)) + return 1; + + char* desc = "Unallocated Blocks"; + zSQL = sqlite3_mprintf( + "INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags)" + "VALUES (%lld, %" PRIuPNUM ",%" PRIuDADDR ",%" PRIuDADDR ",'%q',%d)", + objId, vol_index, 0, 0, + desc, 0); + ret = attempt_exec(zSQL, + "Error adding data to tsk_vs_parts table: %s\n"); + sqlite3_free(zSQL); + return ret; +} + +/** +* Adds the sector addresses of the pool volumes into the db. +* * @param pool_vol The pool volume to save to the DB * @param parObjId The ID of the parent of the pool volume (should be a volume system) -* @param objId Will be set to the object ID of the new volume +* @param objId Will be set to the object ID of the new volume +* * @returns 1 on error, 0 on success */ int diff --git a/tsk/auto/tsk_auto.h b/tsk/auto/tsk_auto.h index 631625614cc14882b82ad74c572af82fa00d4cb7..028a95d82b7a37ced4054ffb3c2ec9bdbd4afe50 100644 --- a/tsk/auto/tsk_auto.h +++ b/tsk/auto/tsk_auto.h @@ -263,10 +263,11 @@ class TskAuto { protected: TSK_IMG_INFO * m_img_info; + std::vector<const TSK_POOL_INFO*> m_poolInfos; + bool m_internalOpen; ///< True if m_img_info was opened in TskAuto and false if passed in bool m_stopAllProcessing; ///< True if no further processing should occur - uint8_t isNtfsSystemFiles(TSK_FS_FILE * fs_file, const char *path); uint8_t isFATSystemFiles(TSK_FS_FILE * fs_file); uint8_t isDotDir(TSK_FS_FILE * fs_file); diff --git a/tsk/auto/tsk_case_db.h b/tsk/auto/tsk_case_db.h index eee845990c82acf2f44045eb540398e6f53ce6e3..422ca330d66ab1bac894d558d5fc433bb02413e9 100644 --- a/tsk/auto/tsk_case_db.h +++ b/tsk/auto/tsk_case_db.h @@ -154,6 +154,12 @@ class TskAutoDb:public TskAuto { bool m_foundStructure; ///< Set to true when we find either a volume or file system bool m_attributeAdded; ///< Set to true when an attribute was added by processAttributes + // These are used to write unallocated blocks for pools at the end of the add image + // process. We can't load the pool_info objects directly from the database so we will + // store info about them here. + std::map<int64_t, int64_t> m_poolOffsetToParentId; + std::map<int64_t, int64_t> m_poolOffsetToVsId; + // prevent copying until we add proper logic to handle it TskAutoDb(const TskAutoDb&); TskAutoDb & operator=(const TskAutoDb&); @@ -186,7 +192,7 @@ class TskAutoDb:public TskAuto { TSK_OFF_T offset, TSK_DADDR_T addr, char *buf, size_t size, TSK_FS_BLOCK_FLAG_ENUM a_flags, void *ptr); int md5HashAttr(unsigned char md5Hash[16], const TSK_FS_ATTR * fs_attr); - + TSK_RETVAL_ENUM addUnallocatedPoolBlocksToDb(size_t & numPool); static TSK_WALK_RET_ENUM fsWalkUnallocBlocksCb(const TSK_FS_BLOCK *a_block, void *a_ptr); TSK_RETVAL_ENUM addFsInfoUnalloc(const TSK_DB_FS_INFO & dbFsInfo); TSK_RETVAL_ENUM addUnallocFsSpaceToDb(size_t & numFs); diff --git a/tsk/auto/tsk_db.h b/tsk/auto/tsk_db.h index 291f0c30c821b66fc53deff128af666987e9d4d7..a95aaecc5fa95db67f4d3cb6146d7ac9d4ea51e8 100755 --- a/tsk/auto/tsk_db.h +++ b/tsk/auto/tsk_db.h @@ -180,9 +180,10 @@ class TskDb { virtual int addImageName(int64_t objId, char const *imgName, int sequence) = 0; virtual int addVsInfo(const TSK_VS_INFO * vs_info, int64_t parObjId, int64_t & objId) = 0; virtual int addVolumeInfo(const TSK_VS_PART_INFO * vs_part, int64_t parObjId, int64_t & objId) = 0; - virtual int addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObjId, int64_t& objId) = 0; + virtual int addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObjId, int64_t& vsObjId) = 0; virtual int addPoolVolumeInfo(const TSK_POOL_VOLUME_INFO* pool_vol, int64_t parObjId, int64_t& objId) = 0; + virtual int addUnallocatedPoolVolume(int vol_index, int64_t parObjId, int64_t& objId) = 0; virtual int addFsInfo(const TSK_FS_INFO * fs_info, int64_t parObjId, int64_t & objId) = 0; virtual int addFsFile(TSK_FS_FILE * fs_file, const TSK_FS_ATTR * fs_attr, const char *path, const unsigned char *const md5, diff --git a/tsk/auto/tsk_db_postgresql.h b/tsk/auto/tsk_db_postgresql.h index 873b142babca2158d569deeb9c580a089da15d79..c4cfa763158af9f356f828f9e31cb0b6f708debf 100755 --- a/tsk/auto/tsk_db_postgresql.h +++ b/tsk/auto/tsk_db_postgresql.h @@ -58,9 +58,10 @@ class TskDbPostgreSQL : public TskDb { int64_t & objId); int addFsInfo(const TSK_FS_INFO * fs_info, int64_t parObjId, int64_t & objId); - int addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObjId, int64_t& objId); + int addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObjId, int64_t& vsObjId); int addPoolVolumeInfo(const TSK_POOL_VOLUME_INFO* pool_vol, int64_t parObjId, int64_t& objId); + int addUnallocatedPoolVolume(int vol_index, int64_t parObjId, int64_t& objId); int addFsFile(TSK_FS_FILE * fs_file, const TSK_FS_ATTR * fs_attr, const char *path, const unsigned char *const md5, const TSK_DB_FILES_KNOWN_ENUM known, int64_t fsObjId, diff --git a/tsk/auto/tsk_db_sqlite.h b/tsk/auto/tsk_db_sqlite.h index 7fa3abae9a08da0c338145d9b6ce865a174720e6..13d55412167e0b8e77de117e7c35f0afce86a3ca 100755 --- a/tsk/auto/tsk_db_sqlite.h +++ b/tsk/auto/tsk_db_sqlite.h @@ -50,9 +50,10 @@ class TskDbSqlite : public TskDb { int addImageName(int64_t objId, char const *imgName, int sequence); int addVsInfo(const TSK_VS_INFO * vs_info, int64_t parObjId, int64_t & objId); - int addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObjId, int64_t& objId); + int addPoolInfoAndVS(const TSK_POOL_INFO *pool_info, int64_t parObjId, int64_t& vsObjId); int addPoolVolumeInfo(const TSK_POOL_VOLUME_INFO* pool_vol, int64_t parObjId, int64_t& objId); + int addUnallocatedPoolVolume(int vol_index, int64_t parObjId, int64_t& objId); int addVolumeInfo(const TSK_VS_PART_INFO * vs_part, int64_t parObjId, int64_t & objId); int addFsInfo(const TSK_FS_INFO * fs_info, int64_t parObjId,