diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.cpp b/bindings/java/jni/dataModel_SleuthkitJNI.cpp index 4d53b523d6bf4745dabe4255e6bb62e82725bbc8..e9c8e16af4be76155b4f0719d3580f43e47c7608 100644 --- a/bindings/java/jni/dataModel_SleuthkitJNI.cpp +++ b/bindings/java/jni/dataModel_SleuthkitJNI.cpp @@ -282,14 +282,20 @@ JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_newCaseDbMulti TSK_TCHAR dbPathT[1024]; toTCHAR(env, dbPathT, 1024, dbName); - CaseDbConnectionInfo info(env->GetStringUTFChars(host, false), - env->GetStringUTFChars(port, false), - env->GetStringUTFChars(user, false), - env->GetStringUTFChars(pass, false), - (CaseDbConnectionInfo::DbType)dbType); + const char* host_utf8 = env->GetStringUTFChars(host, NULL); + const char* port_utf8 = env->GetStringUTFChars(port, NULL); + const char* user_utf8 = env->GetStringUTFChars(user, NULL); + const char* pass_utf8 = env->GetStringUTFChars(pass, NULL); + CaseDbConnectionInfo info(host_utf8, port_utf8, user_utf8, pass_utf8, (CaseDbConnectionInfo::DbType)dbType); TskCaseDb *tskCase = TskCaseDb::newDb(dbPathT, &info); + // free memory allocated by env->GetStringUTFChars() + env->ReleaseStringUTFChars(host, host_utf8); + env->ReleaseStringUTFChars(port, port_utf8); + env->ReleaseStringUTFChars(user, user_utf8); + env->ReleaseStringUTFChars(pass, pass_utf8); + if (tskCase == NULL) { setThrowTskCoreError(env); return 0; @@ -317,14 +323,20 @@ JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_openCaseDbMult TSK_TCHAR dbPathT[1024]; toTCHAR(env, dbPathT, 1024, dbName); - CaseDbConnectionInfo info(env->GetStringUTFChars(host, false), - env->GetStringUTFChars(port, false), - env->GetStringUTFChars(user, false), - env->GetStringUTFChars(pass, false), - (CaseDbConnectionInfo::DbType)dbType); + const char* host_utf8 = env->GetStringUTFChars(host, NULL); + const char* port_utf8 = env->GetStringUTFChars(port, NULL); + const char* user_utf8 = env->GetStringUTFChars(user, NULL); + const char* pass_utf8 = env->GetStringUTFChars(pass, NULL); + CaseDbConnectionInfo info(host_utf8, port_utf8, user_utf8, pass_utf8, (CaseDbConnectionInfo::DbType)dbType); TskCaseDb *tskCase = TskCaseDb::openDb(dbPathT, &info); + // free memory allocated by env->GetStringUTFChars() + env->ReleaseStringUTFChars(host, host_utf8); + env->ReleaseStringUTFChars(port, port_utf8); + env->ReleaseStringUTFChars(user, user_utf8); + env->ReleaseStringUTFChars(pass, pass_utf8); + if (tskCase == NULL) { setThrowTskCoreError(env); return 0; @@ -623,8 +635,8 @@ JNIEXPORT jboolean JNICALL return (jboolean)false; } - return (jboolean)((tsk_hdb_uses_external_indexes(db) == static_cast<uint8_t>(1)) && - (!tsk_hdb_is_idx_only(db) == static_cast<uint8_t>(1))); + return (jboolean)((tsk_hdb_uses_external_indexes(db) == 1) && + (tsk_hdb_is_idx_only(db) == 0)); } /** diff --git a/bindings/java/src/org/sleuthkit/datamodel/BlackboardArtifact.java b/bindings/java/src/org/sleuthkit/datamodel/BlackboardArtifact.java index 9bbb6da187e1657d04b1f4b400e594c8695766f1..612256a0bd4e005d6d9bb93e8b3820a76536a871 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/BlackboardArtifact.java +++ b/bindings/java/src/org/sleuthkit/datamodel/BlackboardArtifact.java @@ -1,7 +1,7 @@ /* * Sleuth Kit Data Model * - * Copyright 2011-2014 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier <at> sleuthkit <dot> org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/bindings/java/src/org/sleuthkit/datamodel/Bundle.properties b/bindings/java/src/org/sleuthkit/datamodel/Bundle.properties index 5337405dbc38e2d41c80d527dc400de30feebd76..1ee3ae2c7716b76574c43d6b74b0639a4ef12bcd 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/Bundle.properties +++ b/bindings/java/src/org/sleuthkit/datamodel/Bundle.properties @@ -215,4 +215,9 @@ DatabaseConnectionCheck.Installation=Issue with installation. JDBC driver not fo DatabaseConnectionCheck.MissingHostname=Missing hostname. DatabaseConnectionCheck.MissingPort=Missing port number. DatabaseConnectionCheck.MissingUsername=Missing username. -DatabaseConnectionCheck.MissingPassword=Missing password. \ No newline at end of file +DatabaseConnectionCheck.MissingPassword=Missing password. +IngestJobInfo.IngestJobStatusType.Started.displayName=Started +IngestJobInfo.IngestJobStatusType.Cancelled.displayName=Cancelled +IngestJobInfo.IngestJobStatusType.Completed.displayName=Completed +IngestModuleInfo.IngestModuleType.FileLevel.displayName=File Level +IngestModuleInfo.IngestModuleType.DataSourceLevel.displayName=Data Source Level \ No newline at end of file diff --git a/bindings/java/src/org/sleuthkit/datamodel/IngestJobInfo.java b/bindings/java/src/org/sleuthkit/datamodel/IngestJobInfo.java new file mode 100755 index 0000000000000000000000000000000000000000..ef052021ef32816fe3054b8160044b50f29555e7 --- /dev/null +++ b/bindings/java/src/org/sleuthkit/datamodel/IngestJobInfo.java @@ -0,0 +1,211 @@ +/* + * Sleuth Kit Data Model + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier <at> sleuthkit <dot> org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.datamodel; + +import java.util.Date; +import java.util.List; +import java.util.ResourceBundle; + +/** + * Represents information for an ingest job. + */ +public final class IngestJobInfo { + + private static final ResourceBundle bundle = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle"); + + public enum IngestJobStatusType { + + //DO NOT CHANGE ORDER + STARTED(bundle.getString("IngestJobInfo.IngestJobStatusType.Started.displayName")), + CANCELLED(bundle.getString("IngestJobInfo.IngestJobStatusType.Cancelled.displayName")), + COMPLETED(bundle.getString("IngestJobInfo.IngestJobStatusType.Completed.displayName")); + + private String displayName; + + private IngestJobStatusType(String displayName) { + this.displayName = displayName; + } + + public static IngestJobStatusType fromID(int typeId) { + for (IngestJobStatusType statusType : IngestJobStatusType.values()) { + if (statusType.ordinal() == typeId) { + return statusType; + } + } + return null; + } + + /** + * @return the displayName + */ + public String getDisplayName() { + return displayName; + } + } + + private final long ingestJobId; + private final long objectId; + private final String hostName; + private final Date startDateTime; + private Date endDateTime = new Date(0); + private final String settingsDir; + private final List<IngestModuleInfo> ingestModuleInfo; + private final SleuthkitCase skCase; + private IngestJobStatusType status; + + /** + * Constructs an IngestJobInfo that has not ended + * + * @param ingestJobId The id of the ingest job + * @param objectId The data source the job is being run on + * @param hostName The host on which the job was executed + * @param startDateTime The date time the job was started + * @param settingsDir The directory of the job settings + * @param ingestModuleInfo The ingest modules being run for this job + * @param skCase A reference to sleuthkit case + */ + IngestJobInfo(long ingestJobId, long objectId, String hostName, Date startDateTime, String settingsDir, List<IngestModuleInfo> ingestModuleInfo, SleuthkitCase skCase) { + this.ingestJobId = ingestJobId; + this.objectId = objectId; + this.hostName = hostName; + this.startDateTime = startDateTime; + this.settingsDir = settingsDir; + this.skCase = skCase; + this.ingestModuleInfo = ingestModuleInfo; + this.status = IngestJobStatusType.STARTED; + } + + /** + * Constructs an IngestJobInfo that has already ended + * + * @param ingestJobId The id of the ingest job + * @param dataSourceId The data source the job is being run on + * @param hostName The host on which the job was executed + * @param startDateTime The date time the job was started + * @param endDateTime The date time the job was ended (if it ended) + * @param status The status of the job + * @param settingsDir The directory of the job settings + * @param ingestModuleInfo The ingest modules being run for this job + * @param skCase A reference to sleuthkit case + */ + IngestJobInfo(long ingestJobId, long dataSourceId, String hostName, Date startDateTime, Date endDateTime, IngestJobStatusType status, String settingsDir, List<IngestModuleInfo> ingestModuleInfo, SleuthkitCase skCase) { + this.ingestJobId = ingestJobId; + this.objectId = dataSourceId; + this.hostName = hostName; + this.startDateTime = startDateTime; + this.endDateTime = endDateTime; + this.settingsDir = settingsDir; + this.skCase = skCase; + this.ingestModuleInfo = ingestModuleInfo; + this.status = status; + } + + /** + * @return the end date time of the job (equal to the epoch if it has not + * been set yet). + */ + public Date getEndDateTime() { + return endDateTime; + } + + /** + * Sets the end date for the ingest job info, and updates the database. + * + * @param endDateTime the endDateTime to set + * + * @throws org.sleuthkit.datamodel.TskCoreException + */ + public void setEndDateTime(Date endDateTime) throws TskCoreException { + Date oldDate = this.endDateTime; + this.endDateTime = endDateTime; + try { + skCase.setIngestJobEndDateTime(getIngestJobId(), endDateTime.getTime()); + } catch (TskCoreException ex) { + this.endDateTime = oldDate; + throw ex; + } + } + + /** + * Sets the ingest status for the ingest job info, and updates the database. + * + * @param status The new status + * + * @throws TskCoreException + */ + public void setIngestJobStatus(IngestJobStatusType status) throws TskCoreException { + IngestJobStatusType oldStatus = this.getStatus(); + this.status = status; + try { + skCase.setIngestJobStatus(getIngestJobId(), status); + } catch (TskCoreException ex) { + this.status = oldStatus; + throw ex; + } + } + + /** + * @return the ingestJobId + */ + public long getIngestJobId() { + return ingestJobId; + } + + /** + * @return the objectId + */ + public long getObjectId() { + return objectId; + } + + /** + * @return the hostName + */ + public String getHostName() { + return hostName; + } + + /** + * @return the startDateTime + */ + public Date getStartDateTime() { + return startDateTime; + } + + /** + * @return the settingsDir + */ + public String getSettingsDir() { + return settingsDir; + } + + /** + * @return the ingestModuleInfo + */ + public List<IngestModuleInfo> getIngestModuleInfo() { + return ingestModuleInfo; + } + + /** + * @return the status + */ + public IngestJobStatusType getStatus() { + return status; + } +} diff --git a/bindings/java/src/org/sleuthkit/datamodel/IngestModuleInfo.java b/bindings/java/src/org/sleuthkit/datamodel/IngestModuleInfo.java new file mode 100755 index 0000000000000000000000000000000000000000..bec082446464559c1b1c4b89aababacb46e3f919 --- /dev/null +++ b/bindings/java/src/org/sleuthkit/datamodel/IngestModuleInfo.java @@ -0,0 +1,120 @@ +/* + * Sleuth Kit Data Model + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier <at> sleuthkit <dot> org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.datamodel; + +import java.util.ResourceBundle; + +/** + * Class representing information about an ingest module, used in ingest job + * info to show which ingest modules were run. + */ +public final class IngestModuleInfo { + + private static final ResourceBundle bundle = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle"); + + /** + * Used to keep track of the module types + */ + public static enum IngestModuleType { + //DO NOT CHANGE ORDER + DATA_SOURCE_LEVEL(bundle.getString("IngestModuleInfo.IngestModuleType.DataSourceLevel.displayName")), + FILE_LEVEL(bundle.getString("IngestModuleInfo.IngestModuleType.FileLevel.displayName")); + + private String displayName; + + private IngestModuleType(String displayName) { + this.displayName = displayName; + } + + public static IngestModuleType fromID(int typeId) { + for (IngestModuleType moduleType : IngestModuleType.values()) { + if (moduleType.ordinal() == typeId) { + return moduleType; + } + } + return null; + } + + /** + * @return the displayName + */ + public String getDisplayName() { + return displayName; + } + + } + + private final long ingestModuleId; + private final String displayName; + private final String uniqueName; + private final IngestModuleType type; + private final String version; + + /** + * + * @param ingestModuleId The id of the ingest module + * @param displayName The display name of the ingest module + * @param uniqueName The unique name of the ingest module. + * @param type The ingest module type of the module. + * @param version The version number of the module. + */ + IngestModuleInfo(long ingestModuleId, String displayName, String uniqueName, IngestModuleType type, String version) { + this.ingestModuleId = ingestModuleId; + this.displayName = displayName; + this.uniqueName = uniqueName; + this.type = type; + this.version = version; + } + + /** + * @return the ingestModuleId + */ + public long getIngestModuleId() { + return ingestModuleId; + } + + /** + * @return the displayName + */ + public String getDisplayName() { + return displayName; + } + + /** + * @return the uniqueName + */ + public String getUniqueName() { + return uniqueName; + } + + /** + * @return the typeID + */ + public IngestModuleType getType() { + return type; + } + + /** + * @return the version + */ + public String getVersion() { + return version; + } + +} diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java old mode 100644 new mode 100755 index 48390752e5e0fb5e2660150d5bdcd57ccb92c0a3..7e6701df4d12df7dac0a4e4b8c2938410f6344ff --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java @@ -42,6 +42,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.EnumMap; import java.util.HashMap; import java.util.LinkedHashMap; @@ -59,6 +60,8 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE; +import org.sleuthkit.datamodel.IngestJobInfo.IngestJobStatusType; +import org.sleuthkit.datamodel.IngestModuleInfo.IngestModuleType; import org.sleuthkit.datamodel.SleuthkitJNI.CaseDbHandle.AddImageProcess; import org.sleuthkit.datamodel.TskData.DbType; import org.sleuthkit.datamodel.TskData.FileKnown; @@ -200,6 +203,13 @@ private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbTyp this.connections = new SQLiteConnections(dbPath); init(caseHandle); updateDatabaseSchema(dbPath); + // Initializing ingest module types is done here because it is possible + // the table is not there when init is called. It must be there after + // the schema update. + CaseDbConnection connection = connections.getConnection(); + this.initIngestModuleTypes(connection); + this.initIngestStatusTypes(connection); + connection.close(); logSQLiteJDBCDriverInfo(); } @@ -227,6 +237,13 @@ private SleuthkitCase(String host, int port, String dbName, String userName, Str this.connections = new PostgreSQLConnections(host, port, dbName, userName, password); init(caseHandle); updateDatabaseSchema(null); + // Initializing ingest module types is done here because it is possible + // the table is not there when init is called. It must be there after + // the schema update. + CaseDbConnection connection = connections.getConnection(); + this.initIngestModuleTypes(connection); + this.initIngestStatusTypes(connection); + connection.close(); } private void init(SleuthkitJNI.CaseDbHandle caseHandle) throws Exception { @@ -335,6 +352,48 @@ private void initNextArtifactId() throws TskCoreException, SQLException { } } + private void initIngestModuleTypes(CaseDbConnection connection) throws TskCoreException { + Statement s = null; + ResultSet rs = null; + try { + s = connection.createStatement(); + for (IngestModuleType type : IngestModuleType.values()) { + rs = connection.executeQuery(s, "SELECT type_id FROM ingest_module_types WHERE type_id=" + type.ordinal() + ";"); + if (!rs.next()) { + s.execute("INSERT INTO ingest_module_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); + } + rs.close(); + rs = null; + } + } catch (SQLException ex) { + throw new TskCoreException("Error adding ingest module types to table.", ex); + } finally { + closeResultSet(rs); + closeStatement(s); + } + } + + private void initIngestStatusTypes(CaseDbConnection connection) throws TskCoreException { + Statement s = null; + ResultSet rs = null; + try { + s = connection.createStatement(); + for (IngestJobStatusType type : IngestJobStatusType.values()) { + rs = connection.executeQuery(s, "SELECT type_id FROM ingest_job_status_types WHERE type_id=" + type.ordinal() + ";"); + if (!rs.next()) { + s.execute("INSERT INTO ingest_job_status_types (type_id, type_name) VALUES (" + type.ordinal() + ", '" + type.toString() + "');"); + } + rs.close(); + rs = null; + } + } catch (SQLException ex) { + throw new TskCoreException("Error adding ingest module types to table.", ex); + } finally { + closeResultSet(rs); + closeStatement(s); + } + } + /** * Modify the case database to bring it up-to-date with the current version * of the database schema. @@ -686,6 +745,19 @@ private int updateFromSchema3toSchema4(int schemaVersionNumber, CaseDbConnection updateStatement.executeUpdate("UPDATE tsk_files SET data_source_obj_id = " + dataSourceId + " WHERE obj_id = " + fileId + ";"); } resultSet.close(); + statement.execute("CREATE TABLE ingest_module_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS + statement.execute("CREATE TABLE ingest_job_status_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)"); //NON-NLS + if (this.dbType.equals(DbType.SQLITE)) { + statement.execute("CREATE TABLE ingest_modules (ingest_module_id INTEGER PRIMARY KEY, display_name TEXT NOT NULL, unique_name TEXT UNIQUE NOT NULL, type_id INTEGER NOT NULL, version TEXT NOT NULL, FOREIGN KEY(type_id) REFERENCES ingest_module_types(type_id));"); //NON-NLS + statement.execute("CREATE TABLE ingest_jobs (ingest_job_id INTEGER PRIMARY KEY, obj_id BIGINT NOT NULL, host_name TEXT NOT NULL, start_date_time BIGINT NOT NULL, end_date_time BIGINT NOT NULL, status_id INTEGER NOT NULL, settings_dir TEXT, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id), FOREIGN KEY(status_id) REFERENCES ingest_job_status_types(type_id));"); //NON-NLS + } else { + statement.execute("CREATE TABLE ingest_modules (ingest_module_id BIGSERIAL PRIMARY KEY, display_name TEXT NOT NULL, unique_name TEXT UNIQUE NOT NULL, type_id INTEGER NOT NULL, version TEXT NOT NULL, FOREIGN KEY(type_id) REFERENCES ingest_module_types(type_id));"); //NON-NLS + statement.execute("CREATE TABLE ingest_jobs (ingest_job_id BIGSERIAL PRIMARY KEY, obj_id BIGINT NOT NULL, host_name TEXT NOT NULL, start_date_time BIGINT NOT NULL, end_date_time BIGINT NOT NULL, status_id INTEGER NOT NULL, settings_dir TEXT, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id), FOREIGN KEY(status_id) REFERENCES ingest_job_status_types(type_id));"); //NON-NLS + } + + statement.execute("CREATE TABLE ingest_job_modules (ingest_job_id INTEGER, ingest_module_id INTEGER, pipeline_position INTEGER, PRIMARY KEY(ingest_job_id, ingest_module_id), FOREIGN KEY(ingest_job_id) REFERENCES ingest_jobs(ingest_job_id), FOREIGN KEY(ingest_module_id) REFERENCES ingest_modules(ingest_module_id));"); //NON-NLS + initIngestModuleTypes(connection); + initIngestStatusTypes(connection); return 4; @@ -5857,7 +5929,7 @@ public void deleteReport(Report report) throws TskCoreException { acquireSharedLock(); try { PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.DELETE_REPORT); - statement.setString(1, String.valueOf(report.getId())); + statement.setLong(1, report.getId()); connection.executeUpdate(statement); } catch (SQLException ex) { throw new TskCoreException("Error querying reports table", ex); @@ -5887,6 +5959,213 @@ private static void closeStatement(Statement statement) { } } + /** + * Sets the end date for the given ingest job + * + * @param ingestJobId The ingest job to set the end date for + * @param endDateTime The end date + * + * @throws TskCoreException If inserting into the database fails + */ + void setIngestJobEndDateTime(long ingestJobId, long endDateTime) throws TskCoreException { + CaseDbConnection connection = connections.getConnection(); + acquireSharedLock(); + try { + Statement statement = connection.createStatement(); + statement.executeUpdate("UPDATE ingest_jobs SET end_date_time=" + endDateTime + " WHERE ingest_job_id=" + ingestJobId + ";"); + } catch (SQLException ex) { + throw new TskCoreException("Error updating the end date (ingest_job_id = " + ingestJobId + ".", ex); + } finally { + connection.close(); + releaseSharedLock(); + } + } + + void setIngestJobStatus(long ingestJobId, IngestJobStatusType status) throws TskCoreException { + CaseDbConnection connection = connections.getConnection(); + acquireSharedLock(); + try { + Statement statement = connection.createStatement(); + statement.executeUpdate("UPDATE ingest_jobs SET status_id=" + status.ordinal() + " WHERE ingest_job_id=" + ingestJobId + ";"); + } catch (SQLException ex) { + throw new TskCoreException("Error ingest job status (ingest_job_id = " + ingestJobId + ".", ex); + } finally { + connection.close(); + releaseSharedLock(); + } + } + + /** + * + * @param dataSource The datasource the ingest job is being run on + * @param hostName The name of the host + * @param ingestModules The ingest modules being run during the ingest job. + * Should be in pipeline order. + * @param jobStart The time the job started + * @param jobEnd The time the job ended + * @param status The ingest job status + * @param settingsDir The directory of the job's settings + * + * @return An information object representing the ingest job added to the + * database. + * + * @throws TskCoreException If adding the job to the database fails. + */ + public final IngestJobInfo addIngestJob(Content dataSource, String hostName, List<IngestModuleInfo> ingestModules, Date jobStart, Date jobEnd, IngestJobStatusType status, String settingsDir) throws TskCoreException { + CaseDbConnection connection = connections.getConnection(); + acquireSharedLock(); + ResultSet resultSet = null; + Statement statement = null; + try { + connection.beginTransaction(); + statement = connection.createStatement(); + PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_JOB, Statement.RETURN_GENERATED_KEYS); + insertStatement.setLong(1, dataSource.getId()); + insertStatement.setString(2, hostName); + insertStatement.setLong(3, jobStart.getTime()); + insertStatement.setLong(4, jobEnd.getTime()); + insertStatement.setInt(5, status.ordinal()); + insertStatement.setString(6, settingsDir); + connection.executeUpdate(insertStatement); + resultSet = insertStatement.getGeneratedKeys(); + resultSet.next(); + long id = resultSet.getLong(1); + for (int i = 0; i < ingestModules.size(); i++) { + IngestModuleInfo ingestModule = ingestModules.get(i); + statement.executeUpdate("INSERT INTO ingest_job_modules (ingest_job_id, ingest_module_id, pipeline_position) " + + "VALUES (" + id + ", " + ingestModule.getIngestModuleId() + ", " + i + ");"); + } + resultSet.close(); + resultSet = null; + connection.commitTransaction(); + return new IngestJobInfo(id, dataSource.getId(), hostName, jobStart, "", ingestModules, this); + } catch (SQLException ex) { + connection.rollbackTransaction(); + throw new TskCoreException("Error adding the ingest job.", ex); + } finally { + closeResultSet(resultSet); + connection.close(); + releaseSharedLock(); + } + } + + /** + * Adds the given ingest module to the database. + * + * @param displayName The display name of the module + * @param uniqueName The factory class name of the module. + * @param type The type of the module. + * @param version The version of the module. + * + * @return An ingest module info object representing the module added to the + * db. + * + * @throws TskCoreException When the ingest module cannot be added. + */ + public final IngestModuleInfo addIngestModule(String displayName, String factoryClassName, IngestModuleType type, String version) throws TskCoreException { + CaseDbConnection connection = connections.getConnection(); + ResultSet resultSet = null; + Statement statement = null; + String uniqueName = factoryClassName + "-" + displayName + "-" + type.toString() + "-" + version; + try { + statement = connection.createStatement(); + resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'"); + if (!resultSet.next()) { + resultSet.close(); + resultSet = null; + PreparedStatement insertStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_INGEST_MODULE, Statement.RETURN_GENERATED_KEYS); + insertStatement.setString(1, displayName); + insertStatement.setString(2, uniqueName); + insertStatement.setInt(3, type.ordinal()); + insertStatement.setString(4, version); + connection.executeUpdate(insertStatement); + resultSet = statement.getGeneratedKeys(); + resultSet.next(); + long id = resultSet.getLong(1); + resultSet.close(); + resultSet = null; + return new IngestModuleInfo(id, displayName, uniqueName, type, version); + } else { + return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"), resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version")); + } + } catch (SQLException ex) { + try { + resultSet = statement.executeQuery("SELECT * FROM ingest_modules WHERE unique_name = '" + uniqueName + "'"); + if (resultSet.next()) { + return new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"), uniqueName, IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version")); + } else { + throw new TskCoreException("Couldn't add new module to database.", ex); + } + } catch (SQLException ex1) { + throw new TskCoreException("Couldn't add new module to database.", ex1); + } + } finally { + closeResultSet(resultSet); + closeStatement(statement); + connection.close(); + } + } + + /** + * Gets all of the ingest jobs that have been run. + * + * @return The information about the ingest jobs that have been run + * + * @throws TskCoreException If there is a problem getting the ingest jobs + */ + public final List<IngestJobInfo> getIngestJobs() throws TskCoreException { + CaseDbConnection connection = connections.getConnection(); + ResultSet resultSet = null; + Statement statement = null; + List<IngestJobInfo> ingestJobs = new ArrayList<IngestJobInfo>(); + try { + statement = connection.createStatement(); + resultSet = statement.executeQuery("SELECT * FROM ingest_jobs"); + while (resultSet.next()) { + ingestJobs.add(new IngestJobInfo(resultSet.getInt("ingest_job_id"), resultSet.getLong("obj_id"), resultSet.getString("host_name"), new Date(resultSet.getLong("start_date_time")), new Date(resultSet.getLong("end_date_time")), IngestJobStatusType.fromID(resultSet.getInt("status_id")), resultSet.getString("settings_dir"), this.getIngestModules(resultSet.getInt("ingest_job_id"), connection), this)); + } + return ingestJobs; + } catch (SQLException ex) { + throw new TskCoreException("Couldn't get the ingest jobs.", ex); + } finally { + closeResultSet(resultSet); + closeStatement(statement); + connection.close(); + } + } + + /** + * Gets the ingest modules associated with the ingest job + * + * @param ingestJobId The id of the ingest job to get ingest modules for + * @param connection The database connection + * + * @return The ingest modules of the job + * + * @throws SQLException If it fails to get the modules from the db. + */ + private List<IngestModuleInfo> getIngestModules(int ingestJobId, CaseDbConnection connection) throws SQLException { + ResultSet resultSet = null; + Statement statement = null; + List<IngestModuleInfo> ingestModules = new ArrayList<IngestModuleInfo>(); + try { + statement = connection.createStatement(); + resultSet = statement.executeQuery("SELECT ingest_job_modules.ingest_module_id, ingest_job_modules.pipeline_position, ingest_modules.display_name, ingest_modules.unique_name, " + + "ingest_modules.type_id, ingest_modules.version " + + "FROM ingest_job_modules, ingest_modules " + + "WHERE ingest_job_modules.ingest_job_id = " + ingestJobId + " " + + "AND ingest_modules.ingest_module_id = ingest_job_modules.ingest_module_id " + + "ORDER BY (ingest_job_modules.pipeline_position);"); + while (resultSet.next()) { + ingestModules.add(new IngestModuleInfo(resultSet.getInt("ingest_module_id"), resultSet.getString("display_name"), resultSet.getString("unique_name"), IngestModuleType.fromID(resultSet.getInt("type_id")), resultSet.getString("version"))); + } + return ingestModules; + } finally { + closeResultSet(resultSet); + closeStatement(statement); + } + } + /** * Notifies observers of errors in the SleuthkitCase. */ @@ -6019,7 +6298,9 @@ private enum PREPARED_STATEMENT { SELECT_ARTIFACT_TAGS_BY_ARTIFACT("SELECT * FROM blackboard_artifact_tags INNER JOIN tag_names ON blackboard_artifact_tags.tag_name_id = tag_names.tag_name_id WHERE blackboard_artifact_tags.artifact_id = ?"), //NON-NLS SELECT_REPORTS("SELECT * FROM reports"), //NON-NLS INSERT_REPORT("INSERT INTO reports (path, crtime, src_module_name, report_name) VALUES (?, ?, ?, ?)"), //NON-NLS - DELETE_REPORT("DELETE FROM reports WHERE reports.report_id = ?"); //NON-NLS + DELETE_REPORT("DELETE FROM reports WHERE reports.report_id = ?"), //NON-NLS + INSERT_INGEST_JOB("INSERT INTO ingest_jobs (obj_id, host_name, start_date_time, end_date_time, status_id, settings_dir) VALUES (?, ?, ?, ?, ?, ?)"), //NON-NLS + INSERT_INGEST_MODULE("INSERT INTO ingest_modules (display_name, unique_name, type_id, version) VALUES(?, ?, ?, ?)"); //NON-NLS private final String sql; diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java index b8ad7d998d11ed7f5f2a1552ace1a6aa28875179..338f58ae18908961ea50ffeb0b83ec6db369f33b 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java @@ -154,6 +154,8 @@ public class SleuthkitJNI { private SleuthkitJNI() { } + + /** * Handle to TSK Case database diff --git a/tsk/auto/db_postgresql.cpp b/tsk/auto/db_postgresql.cpp index edb795805545293458c5f9ceae94116608b158ea..8def8e00ab24531ac0c0e2c0ad6219785c73de21 100755 --- a/tsk/auto/db_postgresql.cpp +++ b/tsk/auto/db_postgresql.cpp @@ -560,6 +560,26 @@ int TskDbPostgreSQL::initialize() { attempt_exec ("CREATE TABLE tsk_vs_parts (obj_id BIGSERIAL PRIMARY KEY, addr BIGINT NOT NULL, start BIGINT NOT NULL, length BIGINT NOT NULL, descr TEXT, flags INTEGER NOT NULL, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id));", "Error creating tsk_vol_info table: %s\n") + || + attempt_exec + ("CREATE TABLE ingest_module_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)", + "Error creating ingest_module_types table: %s\n") + || + attempt_exec + ("CREATE TABLE ingest_job_status_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)", + "Error creating ingest_job_status_types table: %s\n") + || + attempt_exec + ("CREATE TABLE ingest_modules (ingest_module_id BIGSERIAL PRIMARY KEY, display_name TEXT NOT NULL, unique_name TEXT UNIQUE NOT NULL, type_id INTEGER NOT NULL, version TEXT NOT NULL, FOREIGN KEY(type_id) REFERENCES ingest_module_types(type_id));", + "Error creating ingest_modules table: %s\n") + || + attempt_exec + ("CREATE TABLE ingest_jobs (ingest_job_id BIGSERIAL PRIMARY KEY, obj_id BIGINT NOT NULL, host_name TEXT NOT NULL, start_date_time BIGINT NOT NULL, end_date_time BIGINT NOT NULL, status_id INTEGER NOT NULL, settings_dir TEXT, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id), FOREIGN KEY(status_id) REFERENCES ingest_job_status_types(type_id));", + "Error creating ingest_jobs table: %s\n") + || + attempt_exec + ("CREATE TABLE ingest_job_modules (ingest_job_id INTEGER, ingest_module_id INTEGER, pipeline_position INTEGER, PRIMARY KEY(ingest_job_id, ingest_module_id), FOREIGN KEY(ingest_job_id) REFERENCES ingest_jobs(ingest_job_id), FOREIGN KEY(ingest_module_id) REFERENCES ingest_modules(ingest_module_id));", + "Error creating ingest_job_modules table: %s\n") || attempt_exec ("CREATE TABLE reports (report_id BIGSERIAL PRIMARY KEY, path TEXT NOT NULL, crtime INTEGER NOT NULL, src_module_name TEXT NOT NULL, report_name TEXT NOT NULL)","Error creating reports table: %s\n")) { diff --git a/tsk/auto/db_sqlite.cpp b/tsk/auto/db_sqlite.cpp index 6c42eef7edbf4d08ece6e5a3e93af8a4af499d16..bea0b9732c6a442998af0adcf2bc9567b97e1975 100755 --- a/tsk/auto/db_sqlite.cpp +++ b/tsk/auto/db_sqlite.cpp @@ -321,6 +321,26 @@ int attempt_exec ("CREATE TABLE blackboard_attribute_types (attribute_type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL, display_name TEXT, value_type INTEGER NOT NULL)", "Error creating blackboard_attribute_types table: %s\n") + || + attempt_exec + ("CREATE TABLE ingest_module_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)", + "Error creating ingest_module_types table: %s\n") + || + attempt_exec + ("CREATE TABLE ingest_job_status_types (type_id INTEGER PRIMARY KEY, type_name TEXT NOT NULL)", + "Error creating ingest_job_status_types table: %s\n") + || + attempt_exec + ("CREATE TABLE ingest_modules (ingest_module_id INTEGER PRIMARY KEY, display_name TEXT NOT NULL, unique_name TEXT UNIQUE NOT NULL, type_id INTEGER NOT NULL, version TEXT NOT NULL, FOREIGN KEY(type_id) REFERENCES ingest_module_types(type_id));", + "Error creating ingest_modules table: %s\n") + || + attempt_exec + ("CREATE TABLE ingest_jobs (ingest_job_id INTEGER PRIMARY KEY, obj_id INTEGER NOT NULL, host_name TEXT NOT NULL, start_date_time INTEGER NOT NULL, end_date_time INTEGER NOT NULL, status_id INTEGER NOT NULL, settings_dir TEXT, FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id), FOREIGN KEY(status_id) REFERENCES ingest_job_status_types(type_id));", + "Error creating ingest_jobs table: %s\n") + || + attempt_exec + ("CREATE TABLE ingest_job_modules (ingest_job_id INTEGER, ingest_module_id INTEGER, pipeline_position INTEGER, PRIMARY KEY(ingest_job_id, ingest_module_id), FOREIGN KEY(ingest_job_id) REFERENCES ingest_jobs(ingest_job_id), FOREIGN KEY(ingest_module_id) REFERENCES ingest_modules(ingest_module_id));", + "Error creating ingest_job_modules table: %s\n") || attempt_exec ("CREATE TABLE reports (report_id INTEGER PRIMARY KEY, path TEXT NOT NULL, crtime INTEGER NOT NULL, src_module_name TEXT NOT NULL, report_name TEXT NOT NULL)", diff --git a/tsk/auto/guid.cpp b/tsk/auto/guid.cpp index 3e1f029cb26a12bbe775fb6cc4e989d96c803488..1525f7802f34a481ba263126369ec06217299d50 100755 --- a/tsk/auto/guid.cpp +++ b/tsk/auto/guid.cpp @@ -124,7 +124,7 @@ Guid::Guid(const string &fromString) else { charTwo = ch; - auto byte = hexPairToChar(charOne, charTwo); + unsigned char byte = hexPairToChar(charOne, charTwo); _bytes.push_back(byte); lookingForFirstChar = true; } @@ -178,8 +178,8 @@ Guid GuidGenerator::newGuid() #ifdef GUID_CFUUID Guid GuidGenerator::newGuid() { - auto newId = CFUUIDCreate(NULL); - auto bytes = CFUUIDGetUUIDBytes(newId); + CFUUIDRef newId = CFUUIDCreate(NULL); + CFUUIDBytes bytes = CFUUIDGetUUIDBytes(newId); CFRelease(newId); const unsigned char byteArray[16] = diff --git a/tsk/fs/exfatfs_dent.c b/tsk/fs/exfatfs_dent.c index 11c6ce8904de0418688656a41a8bcce0204536e1..789a3f6e124680df9fe74976e686ba2650f32d33 100755 --- a/tsk/fs/exfatfs_dent.c +++ b/tsk/fs/exfatfs_dent.c @@ -401,10 +401,6 @@ exfats_parse_special_file_dentry(EXFATFS_FS_NAME_INFO *a_name_info, FATFS_DENTRY assert(a_name_info->fs_name->name_size == FATFS_MAXNAMLEN_UTF8); assert(a_name_info->fs_dir != NULL); assert(a_dentry != NULL); - assert(exfatfs_get_enum_from_type(a_dentry->data[0]) == EXFATFS_DIR_ENTRY_TYPE_VOLUME_GUID || - exfatfs_get_enum_from_type(a_dentry->data[0]) == EXFATFS_DIR_ENTRY_TYPE_ALLOC_BITMAP || - exfatfs_get_enum_from_type(a_dentry->data[0]) == EXFATFS_DIR_ENTRY_TYPE_UPCASE_TABLE || - exfatfs_get_enum_from_type(a_dentry->data[0]) == EXFATFS_DIR_ENTRY_TYPE_ACT); assert(fatfs_inum_is_in_range(a_name_info->fatfs, a_inum)); /* Starting parse of a new name, save the previous name, if any. */ @@ -441,6 +437,8 @@ exfats_parse_special_file_dentry(EXFATFS_FS_NAME_INFO *a_name_info, FATFS_DENTRY case EXFATFS_DIR_ENTRY_TYPE_FILE: case EXFATFS_DIR_ENTRY_TYPE_FILE_STREAM: case EXFATFS_DIR_ENTRY_TYPE_FILE_NAME: + default: + a_name_info->fs_name->name[0] = '\0'; break; }