From d7932a066a43cffcd7cda23c926a1635537ab1a9 Mon Sep 17 00:00:00 2001 From: apriestman <apriestman@basistech.com> Date: Fri, 29 Jan 2021 11:15:10 -0500 Subject: [PATCH] Add support for storing hosts in the data_source_info table. Added new methods to HostManager. --- bindings/java/jni/auto_db_java.cpp | 8 +- bindings/java/jni/auto_db_java.h | 3 + bindings/java/jni/dataModel_SleuthkitJNI.cpp | 11 +- bindings/java/jni/dataModel_SleuthkitJNI.h | 8 +- .../datamodel/CaseDatabaseFactory.java | 2 + .../org/sleuthkit/datamodel/DataSource.java | 9 ++ .../org/sleuthkit/datamodel/HostManager.java | 78 ++++++++++++ .../src/org/sleuthkit/datamodel/Image.java | 18 +++ .../datamodel/LocalFilesDataSource.java | 18 +++ .../sleuthkit/datamodel/SleuthkitCase.java | 116 +++++++++++++++--- .../org/sleuthkit/datamodel/SleuthkitJNI.java | 89 ++++++++++++-- .../sleuthkit/datamodel/TskCaseDbBridge.java | 12 +- 12 files changed, 337 insertions(+), 35 deletions(-) diff --git a/bindings/java/jni/auto_db_java.cpp b/bindings/java/jni/auto_db_java.cpp index 7cc3888cf..68c69a3c2 100644 --- a/bindings/java/jni/auto_db_java.cpp +++ b/bindings/java/jni/auto_db_java.cpp @@ -79,7 +79,7 @@ TskAutoDbJava::initializeJni(JNIEnv * jniEnv, jobject jobj) { } m_callbackClass = (jclass)m_jniEnv->NewGlobalRef(localCallbackClass); - m_addImageMethodID = m_jniEnv->GetMethodID(m_callbackClass, "addImageInfo", "(IJLjava/lang/String;JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)J"); + m_addImageMethodID = m_jniEnv->GetMethodID(m_callbackClass, "addImageInfo", "(IJLjava/lang/String;JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J[Ljava/lang/String;)J"); if (m_addImageMethodID == NULL) { return TSK_ERR; } @@ -216,7 +216,7 @@ TskAutoDbJava::addImageInfo(int type, TSK_OFF_T ssize, int64_t & objId, const st } jlong objIdj = m_jniEnv->CallLongMethod(m_javaDbObj, m_addImageMethodID, - type, ssize, tzj, size, md5j, sha1j, sha256j, devIdj, collj, imgNamesj); + type, ssize, tzj, size, md5j, sha1j, sha256j, devIdj, collj, m_hostId, imgNamesj); objId = (int64_t)objIdj; if (objId < 0) { @@ -936,6 +936,10 @@ int64_t TskAutoDbJava::getImageID() { return m_curImgId; } +void TskAutoDbJava::setHostId(long hostId) { + m_hostId = hostId; +} + void TskAutoDbJava::closeImage() { TskAuto::closeImage(); } diff --git a/bindings/java/jni/auto_db_java.h b/bindings/java/jni/auto_db_java.h index b324a71c4..ae11e6a58 100644 --- a/bindings/java/jni/auto_db_java.h +++ b/bindings/java/jni/auto_db_java.h @@ -111,6 +111,8 @@ class TskAutoDbJava :public TskAuto { int64_t getImageID(); + void setHostId(long hostId); + TSK_RETVAL_ENUM initializeJni(JNIEnv *, jobject); private: @@ -137,6 +139,7 @@ class TskAutoDbJava :public TskAuto { int64_t m_maxChunkSize; ///< Max number of unalloc bytes to process before writing to the database, even if there is no natural break. -1 for no chunking 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 + int64_t m_hostId; ///< ID of host for this image (already in database) // 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 diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.cpp b/bindings/java/jni/dataModel_SleuthkitJNI.cpp index f4da3b4b6..0688cae46 100644 --- a/bindings/java/jni/dataModel_SleuthkitJNI.cpp +++ b/bindings/java/jni/dataModel_SleuthkitJNI.cpp @@ -805,13 +805,14 @@ JNIEXPORT jobject JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbLookup * @param timeZone The time zone for the image. * @param addUnallocSpace Pass true to create virtual files for unallocated space. Ignored if addFileSystems is false. * @param skipFatFsOrphans Pass true to skip processing of orphan files for FAT file systems. Ignored if addFileSystems is false. + * @param hostId Id of the host (already in the database). * * @return A pointer to the process (TskAutoDbJava object) or NULL on error. */ JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_initAddImgNat(JNIEnv * env, - jclass obj, jobject callbackObj, jstring timeZone, jboolean addUnallocSpace, jboolean skipFatFsOrphans) { - return Java_org_sleuthkit_datamodel_SleuthkitJNI_initializeAddImgNat(env, obj, callbackObj, timeZone, true, addUnallocSpace, skipFatFsOrphans); + jclass obj, jobject callbackObj, jstring timeZone, jboolean addUnallocSpace, jboolean skipFatFsOrphans, jlong hostId) { + return Java_org_sleuthkit_datamodel_SleuthkitJNI_initializeAddImgNat(env, obj, callbackObj, timeZone, true, addUnallocSpace, skipFatFsOrphans, hostId); } /* @@ -823,12 +824,13 @@ JNIEXPORT jlong JNICALL * @param addFileSystems Pass true to attempt to add file systems within the image to the case database. * @param addUnallocSpace Pass true to create virtual files for unallocated space. Ignored if addFileSystems is false. * @param skipFatFsOrphans Pass true to skip processing of orphan files for FAT file systems. Ignored if addFileSystems is false. + * @param hostId The ID of the host (already in database). * * @return A pointer to the process (TskAutoDbJava object) or NULL on error. */ JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_initializeAddImgNat(JNIEnv * env, jclass obj, - jobject callbackObj, jstring timeZone, jboolean addFileSystems, jboolean addUnallocSpace, jboolean skipFatFsOrphans) { + jobject callbackObj, jstring timeZone, jboolean addFileSystems, jboolean addUnallocSpace, jboolean skipFatFsOrphans, jlong hostId) { jboolean isCopy; if (env->GetStringUTFLength(timeZone) > 0) { @@ -864,6 +866,9 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_initializeAddImgNat(JNIEnv * env, jcla return 0; } + // Save the host ID + tskAutoJava->setHostId(hostId); + // set the options flags tskAutoJava->setAddFileSystems(addFileSystems?true:false); if (addFileSystems) { diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.h b/bindings/java/jni/dataModel_SleuthkitJNI.h index 418db7457..c1808c422 100644 --- a/bindings/java/jni/dataModel_SleuthkitJNI.h +++ b/bindings/java/jni/dataModel_SleuthkitJNI.h @@ -170,18 +170,18 @@ JNIEXPORT jobject JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_hashDbLookup /* * Class: org_sleuthkit_datamodel_SleuthkitJNI * Method: initAddImgNat - * Signature: (Lorg/sleuthkit/datamodel/TskCaseDbBridge;Ljava/lang/String;ZZ)J + * Signature: (Lorg/sleuthkit/datamodel/TskCaseDbBridge;Ljava/lang/String;ZZJ)J */ JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_initAddImgNat - (JNIEnv *, jclass, jobject, jstring, jboolean, jboolean); + (JNIEnv *, jclass, jobject, jstring, jboolean, jboolean, jlong); /* * Class: org_sleuthkit_datamodel_SleuthkitJNI * Method: initializeAddImgNat - * Signature: (Lorg/sleuthkit/datamodel/TskCaseDbBridge;Ljava/lang/String;ZZZ)J + * Signature: (Lorg/sleuthkit/datamodel/TskCaseDbBridge;Ljava/lang/String;ZZZJ)J */ JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_initializeAddImgNat - (JNIEnv *, jclass, jobject, jstring, jboolean, jboolean, jboolean); + (JNIEnv *, jclass, jobject, jstring, jboolean, jboolean, jboolean, jlong); /* * Class: org_sleuthkit_datamodel_SleuthkitJNI diff --git a/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java b/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java index 8497dc775..0ab4ae702 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java +++ b/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java @@ -187,6 +187,8 @@ private void createFileTables(Statement stmt) throws SQLException { stmt.execute("CREATE TABLE data_source_info (obj_id " + dbQueryHelper.getBigIntType() + " PRIMARY KEY, device_id TEXT NOT NULL, " + "time_zone TEXT NOT NULL, acquisition_details TEXT, added_date_time "+ dbQueryHelper.getBigIntType() + ", " + "acquisition_tool_settings TEXT, acquisition_tool_name TEXT, acquisition_tool_version TEXT, " + + "host_id " + dbQueryHelper.getBigIntType() + ", " + + "FOREIGN KEY(host_id) REFERENCES tsk_hosts(id), " + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE)"); stmt.execute("CREATE TABLE tsk_fs_info (obj_id " + dbQueryHelper.getPrimaryKey() + " PRIMARY KEY, " diff --git a/bindings/java/src/org/sleuthkit/datamodel/DataSource.java b/bindings/java/src/org/sleuthkit/datamodel/DataSource.java index 3136038e1..416abfa3f 100755 --- a/bindings/java/src/org/sleuthkit/datamodel/DataSource.java +++ b/bindings/java/src/org/sleuthkit/datamodel/DataSource.java @@ -131,4 +131,13 @@ public interface DataSource extends Content { * @throws TskCoreException Thrown if the data can not be read */ Long getDateAdded() throws TskCoreException; + + /** + * Gets the host for this data source. + * + * @return The host + * + * @throws TskCoreException + */ + Host getHost() throws TskCoreException; } diff --git a/bindings/java/src/org/sleuthkit/datamodel/HostManager.java b/bindings/java/src/org/sleuthkit/datamodel/HostManager.java index f1fe3f49b..cad1ef8ba 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/HostManager.java +++ b/bindings/java/src/org/sleuthkit/datamodel/HostManager.java @@ -51,6 +51,54 @@ public final class HostManager { this.db = skCase; } + /** + * APTODO : using for testing - might be able to remove if desired + * Get or create host with specified name. + * + * @param name Host name. + * + * @return Host with the specified name. + * + * @throws TskCoreException + */ + public Host getOrCreateHost(String name) throws TskCoreException { + CaseDbTransaction trans = db.beginTransaction(); + try { + Host host = getOrCreateHost(name, trans); + trans.commit(); + return host; + } catch (TskCoreException ex) { + trans.rollback(); + throw ex; + } + } + + /** + * Get all data sources associated with a given host. + * + * @param host The host. + * + * @return The list of data sources corresponding to the host. + * + * @throws TskCoreException + */ + public Set<DataSource> getDataSourcesForHost(Host host) throws TskCoreException { + String queryString = "SELECT * FROM data_source_info WHERE host_id = " + host.getId(); + + Set<DataSource> dataSources = new HashSet<>(); + try (CaseDbConnection connection = this.db.getConnection(); + Statement s = connection.createStatement(); + ResultSet rs = connection.executeQuery(s, queryString)) { + + while (rs.next()) { + dataSources.add(db.getDataSource(rs.getLong("obj_id"))); + } + + return dataSources; + } catch (SQLException | TskDataException ex) { + throw new TskCoreException(String.format("Error getting data sources for host " + host.getName()), ex); + } + } /** * Get or create host with specified name. @@ -168,4 +216,34 @@ Set<Host> getHosts() throws TskCoreException { throw new TskCoreException(String.format("Error getting hosts"), ex); } } + + /** + * Get host for the given data source. + * + * @param dataSource The data source to look up the host for. + * + * @return Optional with host. Optional.empty if no matching host is found. + * + * @throws TskCoreException + */ + Host getHost(DataSource dataSource) throws TskCoreException { + + String queryString = "SELECT tsk_hosts.id AS hostId, tsk_hosts.name AS name, tsk_hosts.status AS status FROM \n" + + "tsk_hosts INNER JOIN data_source_info \n" + + "ON tsk_hosts.id = data_source_info.host_id \n" + + "WHERE data_source_info.obj_id = " + dataSource.getId(); + + try (CaseDbConnection connection = this.db.getConnection(); + Statement s = connection.createStatement(); + ResultSet rs = connection.executeQuery(s, queryString)) { + + if (!rs.next()) { + throw new TskCoreException(String.format("Host not found for data source with ID = %d", dataSource.getId())); + } else { + return new Host(rs.getLong("hostId"), rs.getString("name"), Host.HostStatus.fromID(rs.getInt("status"))); + } + } catch (SQLException ex) { + throw new TskCoreException(String.format("Error getting host for data source with ID = %d", dataSource.getId()), ex); + } + } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/Image.java b/bindings/java/src/org/sleuthkit/datamodel/Image.java index 0f71f7cca..57284faf6 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/Image.java +++ b/bindings/java/src/org/sleuthkit/datamodel/Image.java @@ -43,6 +43,7 @@ public class Image extends AbstractContent implements DataSource { private long size; private final String[] paths; private volatile long imageHandle = 0; + private volatile Host host = null; private final String deviceId, timezone; private String md5, sha1, sha256; private static ResourceBundle bundle = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle"); @@ -597,6 +598,23 @@ public Long getDateAdded() throws TskCoreException { public String getAcquisitionDetails() throws TskCoreException { return getSleuthkitCase().getAcquisitionDetails(this); } + + /** + * Gets the host for this data source. + * + * @return The host + * + * @throws TskCoreException + */ + @Override + public Host getHost() throws TskCoreException { + // This is a check-then-act race condition that may occasionally result + // in additional processing but is safer than using locks. + if (host == null) { + host = getSleuthkitCase().getHostManager().getHost(this); + } + return host; + } /** * Updates the image's total size and sector size.This function may be used diff --git a/bindings/java/src/org/sleuthkit/datamodel/LocalFilesDataSource.java b/bindings/java/src/org/sleuthkit/datamodel/LocalFilesDataSource.java index e54430c08..f85c55c4d 100755 --- a/bindings/java/src/org/sleuthkit/datamodel/LocalFilesDataSource.java +++ b/bindings/java/src/org/sleuthkit/datamodel/LocalFilesDataSource.java @@ -39,6 +39,7 @@ public class LocalFilesDataSource extends VirtualDirectory implements DataSource private final long objectId; private final String deviceId; private final String timezone; + private volatile Host host; private static final Logger LOGGER = Logger.getLogger(LocalFilesDataSource.class.getName()); @@ -254,6 +255,23 @@ public String getAcquisitionToolName() throws TskCoreException { public String getAcquisitionToolVersion() throws TskCoreException{ return getSleuthkitCase().getDataSourceInfoString(this, "acquisition_tool_version"); } + + /** + * Gets the host for this data source. + * + * @return The host + * + * @throws TskCoreException + */ + @Override + public Host getHost() throws TskCoreException { + // This is a check-then-act race condition that may occasionally result + // in additional processing but is safer than using locks. + if (host == null) { + host = getSleuthkitCase().getHostManager().getHost(this); + } + return host; + } /** * Gets the added date field from the case database. diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java index 802f95d13..d44661eb6 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java @@ -6162,19 +6162,50 @@ public LocalDirectory addLocalDirectory(long parentId, String directoryName, Cas * @throws TskCoreException if there is an error adding the data source. */ public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction) throws TskCoreException { + return addLocalFilesDataSource(deviceId, rootDirectoryName, timeZone, null, transaction); + } + + /** + * Adds a local/logical files and/or directories data source. + * + * @param deviceId An ASCII-printable identifier for the device + * associated with the data source that is intended + * to be unique across multiple cases (e.g., a + * UUID). + * @param rootDirectoryName The name for the root virtual directory for the + * data source. + * @param timeZone The time zone used to process the data source, + * may be the empty string. + * @param host The host for the data source (may be null) + * @param transaction A transaction in the scope of which the + * operation is to be performed, managed by the + * caller. + * + * @return The new local files data source. + * + * @throws TskCoreException if there is an error adding the data source. + */ + public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, Host host, CaseDbTransaction transaction) throws TskCoreException { acquireSingleUserCaseWriteLock(); Statement statement = null; try { + CaseDbConnection connection = transaction.getConnection(); + // Insert a row for the root virtual directory of the data source // into the tsk_objects table. - CaseDbConnection connection = transaction.getConnection(); long newObjId = addObject(0, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection); + // If no host was supplied, make one + if (host == null) { + // APTODO review name + host = getHostManager().getOrCreateHost("LogicalFileSet_" + newObjId + " Host", transaction); + } + // Insert a row for the virtual directory of the data source into // the data_source_info table. statement = connection.createStatement(); - statement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone) " - + "VALUES(" + newObjId + ", '" + deviceId + "', '" + timeZone + "');"); + statement.executeUpdate("INSERT INTO data_source_info (obj_id, device_id, time_zone, host_id) " + + "VALUES(" + newObjId + ", '" + deviceId + "', '" + timeZone + "', " + host.getId() + ");"); // Insert a row for the root virtual directory of the data source // into the tsk_files table. Note that its data source object id is @@ -6247,6 +6278,33 @@ public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size String timezone, String md5, String sha1, String sha256, String deviceId, CaseDbTransaction transaction) throws TskCoreException { + return addImage(type, sectorSize, size, displayName, imagePaths, timezone, md5, sha1, sha256, deviceId, null, transaction); + } + + /** + * Add an image to the database. + * + * @param type Type of image + * @param sectorSize Sector size + * @param size Image size + * @param displayName Display name for the image + * @param imagePaths Image path(s) + * @param timezone Time zone + * @param md5 MD5 hash + * @param sha1 SHA1 hash + * @param sha256 SHA256 hash + * @param deviceId Device ID + * @param host Host + * @param transaction Case DB transaction + * + * @return the newly added Image + * + * @throws TskCoreException + */ + public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List<String> imagePaths, + String timezone, String md5, String sha1, String sha256, + String deviceId, Host host, + CaseDbTransaction transaction) throws TskCoreException { acquireSingleUserCaseWriteLock(); Statement statement = null; try { @@ -6280,6 +6338,26 @@ public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size preparedStatement.setLong(3, i); connection.executeUpdate(preparedStatement); } + + // Create the display name + String name = displayName; + if (name == null || name.isEmpty()) { + if (imagePaths.size() > 0) { + String path = imagePaths.get(0); + name = (new java.io.File(path)).getName(); + } else { + name = ""; + } + } + + // Create a host if needed + if (host == null) { + if (name.isEmpty()) { + getHostManager().getOrCreateHost("Image_" + newObjId + " Host", transaction); + } else { + getHostManager().getOrCreateHost(name + " Host", transaction); + } + } // Add a row to data_source_info preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_DATA_SOURCE_INFO); @@ -6288,18 +6366,10 @@ public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size preparedStatement.setString(2, deviceId); preparedStatement.setString(3, timezone); preparedStatement.setLong(4, new Date().getTime()); + preparedStatement.setLong(5, host.getId()); connection.executeUpdate(preparedStatement); // Create the new Image object - String name = displayName; - if (name == null || name.isEmpty()) { - if (imagePaths.size() > 0) { - String path = imagePaths.get(0); - name = (new java.io.File(path)).getName(); - } else { - name = ""; - } - } return new Image(this, newObjId, type.getValue(), deviceId, sectorSize, name, imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, savedSize); } catch (SQLException ex) { @@ -8690,7 +8760,25 @@ List<Long> getVolumeChildrenIds(Volume vol) throws TskCoreException { * database. */ public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone) throws TskCoreException { - long imageId = this.caseHandle.addImageInfo(deviceObjId, imageFilePaths, timeZone, this); + return addImageInfo(deviceObjId, imageFilePaths, timeZone, null); + } + + /** + * Adds an image to the case database. + * + * @param deviceObjId The object id of the device associated with the + * image. + * @param imageFilePaths The image file paths. + * @param timeZone The time zone for the image. + * @param host The host for this image. + * + * @return An Image object. + * + * @throws TskCoreException if there is an error adding the image to case + * database. + */ + public Image addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone, Host host) throws TskCoreException { + long imageId = this.caseHandle.addImageInfo(deviceObjId, imageFilePaths, timeZone, host, this); return getImageById(imageId); } @@ -11834,7 +11922,7 @@ private enum PREPARED_STATEMENT { INSERT_IMAGE_NAME("INSERT INTO tsk_image_names (obj_id, name, sequence) VALUES (?, ?, ?)"), INSERT_IMAGE_INFO("INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, sha1, sha256, display_name)" + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"), - INSERT_DATA_SOURCE_INFO("INSERT INTO data_source_info (obj_id, device_id, time_zone, added_date_time) VALUES (?, ?, ?, ?)"), + INSERT_DATA_SOURCE_INFO("INSERT INTO data_source_info (obj_id, device_id, time_zone, added_date_time, host_id) VALUES (?, ?, ?, ?, ?)"), INSERT_VS_INFO("INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (?, ?, ?, ?)"), INSERT_VS_PART_SQLITE("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, desc, flags) VALUES (?, ?, ?, ?, ?, ?)"), INSERT_VS_PART_POSTGRESQL("INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags) VALUES (?, ?, ?, ?, ?, ?)"), diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java index fbdec24d6..908ad509c 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java @@ -438,10 +438,21 @@ void free() throws TskCoreException { * @throws TskCoreException if there is an error adding the image to * case database. */ - long addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone, SleuthkitCase skCase) throws TskCoreException { + long addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone, Host host, SleuthkitCase skCase) throws TskCoreException { TskCaseDbBridge dbHelper = new TskCaseDbBridge(skCase, new DefaultAddDataSourceCallbacks()); try { - long tskAutoDbPointer = initializeAddImgNat(dbHelper, timezoneLongToShort(timeZone), false, false, false); + if (host == null) { + String hostName; + if (imageFilePaths.size() > 0) { + String path = imageFilePaths.get(0); + hostName = (new java.io.File(path)).getName() + " Host"; + } else { + hostName = "Image_" + deviceObjId + " Host"; + } + host = skCase.getHostManager().getOrCreateHost(hostName); + } + + long tskAutoDbPointer = initializeAddImgNat(dbHelper, timezoneLongToShort(timeZone), false, false, false, host.getId()); runOpenAndAddImgNat(tskAutoDbPointer, UUID.randomUUID().toString(), imageFilePaths.toArray(new String[0]), imageFilePaths.size(), timeZone); long id = finishAddImgNat(tskAutoDbPointer); dbHelper.finish(); @@ -532,7 +543,7 @@ public void run(String deviceId, String[] imageFilePaths, int sectorSize) throws Image img = addImageToDatabase(skCase, imageFilePaths, sectorSize, "", "", "", "", deviceId); run(deviceId, img, sectorSize, new DefaultAddDataSourceCallbacks()); } - + /** * Starts the process of adding an image to the case database. * @@ -551,7 +562,35 @@ public void run(String deviceId, String[] imageFilePaths, int sectorSize) throws * the process) */ public void run(String deviceId, Image image, int sectorSize, - AddDataSourceCallbacks addDataSourceCallbacks) throws TskCoreException, TskDataException { + AddDataSourceCallbacks addDataSourceCallbacks) throws TskCoreException, TskDataException { + run(deviceId, image, sectorSize, null, addDataSourceCallbacks); + } + + /** + * Starts the process of adding an image to the case database. + * + * @param deviceId An ASCII-printable identifier for the + * device associated with the image that + * should be unique across multiple cases + * (e.g., a UUID). + * @param image The image object (has already been added to the database) + * @param sectorSize The sector size (no longer used). + * @param host The host for this image (may be null). + * @param addDataSourceCallbacks The callbacks to use to send data to ingest (may do nothing). + * + * @throws TskCoreException if a critical error occurs within the + * SleuthKit. + * @throws TskDataException if a non-critical error occurs within + * the SleuthKit (should be OK to continue + * the process) + */ + public void run(String deviceId, Image image, int sectorSize, Host host, + AddDataSourceCallbacks addDataSourceCallbacks) throws TskCoreException, TskDataException { + + if (host == null) { + host = skCase.getHostManager().getOrCreateHost(image.getName() + " Host"); + } + dbHelper = new TskCaseDbBridge(skCase, addDataSourceCallbacks); getTSKReadLock(); try { @@ -562,7 +601,7 @@ public void run(String deviceId, Image image, int sectorSize, } if (!isCanceled) { //with isCanceled being guarded by this it will have the same value everywhere in this synchronized block imageHandle = image.getImageHandle(); - tskAutoDbPointer = initAddImgNat(dbHelper, timezoneLongToShort(timeZone), addUnallocSpace, skipFatFsOrphans); + tskAutoDbPointer = initAddImgNat(dbHelper, timezoneLongToShort(timeZone), addUnallocSpace, skipFatFsOrphans, host.getId()); } if (0 == tskAutoDbPointer) { throw new TskCoreException("initAddImgNat returned a NULL TskAutoDb pointer"); @@ -940,6 +979,29 @@ private static void cacheImageHandle(SleuthkitCase skCase, List<String> imagePat public static Image addImageToDatabase(SleuthkitCase skCase, String[] imagePaths, int sectorSize, String timeZone, String md5fromSettings, String sha1fromSettings, String sha256fromSettings, String deviceId) throws TskCoreException { + return addImageToDatabase(skCase, imagePaths, sectorSize, timeZone, md5fromSettings, sha1fromSettings, sha256fromSettings, deviceId, null); + } + + /** + * Add an image to the database and return the open image. + * + * @param skCase The current case. + * @param imagePaths The path(s) to the image (will just be the first for .e01, .001, etc). + * @param sectorSize The sector size (0 for auto-detect). + * @param timeZone The time zone. + * @param md5fromSettings MD5 hash (if known). + * @param sha1fromSettings SHA1 hash (if known). + * @param sha256fromSettings SHA256 hash (if known). + * @param deviceId Device ID. + * @param host Host. + * + * @return The Image object. + * + * @throws TskCoreException + */ + public static Image addImageToDatabase(SleuthkitCase skCase, String[] imagePaths, int sectorSize, + String timeZone, String md5fromSettings, String sha1fromSettings, String sha256fromSettings, String deviceId, Host host) throws TskCoreException { + // Open the image long imageHandle = openImgNat(imagePaths, 1, sectorSize); @@ -967,10 +1029,21 @@ public static Image addImageToDatabase(SleuthkitCase skCase, String[] imagePaths // Now save to database CaseDbTransaction transaction = skCase.beginTransaction(); try { + if (host == null) { + String hostName; + if (computedPaths.size() > 0) { + String path = computedPaths.get(0); + hostName = (new java.io.File(path)).getName() + " Host"; + } else { + hostName = "Image_" + deviceId + " Host"; + } + host = skCase.getHostManager().getOrCreateHost(hostName, transaction); + } + Image img = skCase.addImage(TskData.TSK_IMG_TYPE_ENUM.valueOf(type), computedSectorSize, size, null, computedPaths, timeZone, md5, sha1, sha256, - deviceId, transaction); + deviceId, host, transaction); if (!StringUtils.isEmpty(collectionDetails)) { skCase.setAcquisitionDetails(img, collectionDetails); } @@ -2096,9 +2169,9 @@ public static long openFile(long fsHandle, long fileId, TSK_FS_ATTR_TYPE_ENUM at private static native HashHitInfo hashDbLookupVerbose(String hash, int dbHandle) throws TskCoreException; - private static native long initAddImgNat(TskCaseDbBridge dbHelperObj, String timezone, boolean addUnallocSpace, boolean skipFatFsOrphans) throws TskCoreException; + private static native long initAddImgNat(TskCaseDbBridge dbHelperObj, String timezone, boolean addUnallocSpace, boolean skipFatFsOrphans, long hostId) throws TskCoreException; - private static native long initializeAddImgNat(TskCaseDbBridge dbHelperObj, String timezone, boolean addFileSystems, boolean addUnallocSpace, boolean skipFatFsOrphans) throws TskCoreException; + private static native long initializeAddImgNat(TskCaseDbBridge dbHelperObj, String timezone, boolean addFileSystems, boolean addUnallocSpace, boolean skipFatFsOrphans, long hostId) throws TskCoreException; private static native void runOpenAndAddImgNat(long process, String deviceId, String[] imgPath, int splits, String timezone) throws TskCoreException, TskDataException; diff --git a/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java b/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java index cee51945a..36cc1d257 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java +++ b/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java @@ -123,16 +123,18 @@ void finish() { * @param sha256 SHA256 hash. * @param deviceId Device ID. * @param collectionDetails The collection details. + * @param hostId Host ID. + * @param paths Data source path(s) * * @return The object ID of the new image or -1 if an error occurred */ long addImageInfo(int type, long ssize, String timezone, long size, String md5, String sha1, String sha256, String deviceId, - String collectionDetails, String[] paths) { + String collectionDetails, long hostId, String[] paths) { try { beginTransaction(); long objId = addImageToDb(TskData.TSK_IMG_TYPE_ENUM.valueOf(type), ssize, size, - timezone, md5, sha1, sha256, deviceId, collectionDetails, trans); + timezone, md5, sha1, sha256, deviceId, collectionDetails, hostId, trans); for (int i = 0;i < paths.length;i++) { addImageNameToDb(objId, paths[i], i, trans); } @@ -913,6 +915,7 @@ private long addFileToDb(long parentObjId, * @param sha256 SHA256 hash. * @param deviceId Device ID. * @param collectionDetails Collection details. + * @param hostId The ID of a host already in the database. * @param transaction Case DB transaction. * * @return The newly added Image object ID. @@ -921,7 +924,7 @@ private long addFileToDb(long parentObjId, */ private long addImageToDb(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String timezone, String md5, String sha1, String sha256, - String deviceId, String collectionDetails, + String deviceId, String collectionDetails, long hostId, CaseDbTransaction transaction) throws TskCoreException { try { // Insert a row for the Image into the tsk_objects table. @@ -948,13 +951,14 @@ private long addImageToDb(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long connection.executeUpdate(preparedStatement); // Add a row to data_source_info - String dataSourceInfoSql = "INSERT INTO data_source_info (obj_id, device_id, time_zone, acquisition_details) VALUES (?, ?, ?, ?)"; // NON-NLS + String dataSourceInfoSql = "INSERT INTO data_source_info (obj_id, device_id, time_zone, acquisition_details, host_id) VALUES (?, ?, ?, ?, ?)"; // NON-NLS preparedStatement = connection.getPreparedStatement(dataSourceInfoSql, Statement.NO_GENERATED_KEYS); preparedStatement.clearParameters(); preparedStatement.setLong(1, newObjId); preparedStatement.setString(2, deviceId); preparedStatement.setString(3, timezone); preparedStatement.setString(4, collectionDetails); + preparedStatement.setLong(5, hostId); connection.executeUpdate(preparedStatement); return newObjId; -- GitLab