Sleuth Kit Java Bindings (JNI)  4.11.0
Java bindings for using The Sleuth Kit
Blackboard.java
Go to the documentation of this file.
1 /*
2  * Sleuth Kit Data Model
3  *
4  * Copyright 2018-2021 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.datamodel;
20 
21 import com.google.common.collect.ImmutableSet;
22 import java.sql.PreparedStatement;
23 import java.sql.ResultSet;
24 import java.sql.SQLException;
25 import java.sql.Statement;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Objects;
33 import java.util.Set;
34 import java.util.logging.Level;
35 import java.util.logging.Logger;
36 import java.util.stream.Collectors;
39 
44 public final class Blackboard {
45 
46  private static final Logger LOGGER = Logger.getLogger(Blackboard.class.getName());
47 
48  private final SleuthkitCase caseDb;
49 
56  Blackboard(SleuthkitCase casedb) {
57  this.caseDb = Objects.requireNonNull(casedb, "Cannot create Blackboard for null SleuthkitCase");
58  }
59 
71  public void postArtifact(BlackboardArtifact artifact, String moduleName) throws BlackboardException {
72  postArtifacts(Collections.singleton(artifact), moduleName);
73  }
74 
90  public void postArtifacts(Collection<BlackboardArtifact> artifacts, String moduleName) throws BlackboardException {
91  /*
92  * For now this just processes them one by one, but in the future it
93  * could be smarter and use transactions, etc.
94  */
95  for (BlackboardArtifact artifact : artifacts) {
96  try {
97  caseDb.getTimelineManager().addArtifactEvents(artifact);
98  } catch (TskCoreException ex) {
99  throw new BlackboardException("Failed to add events for artifact: " + artifact, ex);
100  }
101  }
102 
103  caseDb.fireTSKEvent(new ArtifactsPostedEvent(artifacts, moduleName));
104  }
105 
120  public BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName) throws BlackboardException {
121 
122  return getOrAddArtifactType(typeName, displayName, BlackboardArtifact.Category.DATA_ARTIFACT);
123  }
124 
138  public BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName, BlackboardArtifact.Category category) throws BlackboardException {
139  if (category == null) {
140  throw new BlackboardException("Category provided must be non-null");
141  }
142 
143  try {
144  return caseDb.addBlackboardArtifactType(typeName, displayName, category);
145  } catch (TskDataException typeExistsEx) {
146  try {
147  return caseDb.getArtifactType(typeName);
148  } catch (TskCoreException ex) {
149  throw new BlackboardException("Failed to get or add artifact type", ex);
150  }
151  } catch (TskCoreException ex) {
152  throw new BlackboardException("Failed to get or add artifact type", ex);
153  }
154  }
155 
178  public AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score,
179  String conclusion, String configuration, String justification, Collection<BlackboardAttribute> attributesList)
181 
182  if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
183  throw new BlackboardException(String.format("Artifact type (name = %s) is not of Analysis Result category. ", artifactType.getTypeName()));
184  }
185 
186  CaseDbTransaction transaction = caseDb.beginTransaction();
187  try {
188  AnalysisResultAdded analysisResult = newAnalysisResult(artifactType, objId, dataSourceObjId, score,
189  conclusion, configuration, justification, attributesList, transaction);
190  transaction.commit();
191  return analysisResult;
192  } catch (TskCoreException | BlackboardException ex) {
193  try {
194  transaction.rollback();
195  } catch (TskCoreException ex2) {
196  LOGGER.log(Level.SEVERE, "Failed to rollback transaction after exception. "
197  + "Error invoking newAnalysisResult with dataSourceObjId: "
198  + (dataSourceObjId == null ? "<null>" : dataSourceObjId)
199  + ", sourceObjId: " + objId, ex2);
200  }
201  throw ex;
202  }
203  }
204 
227  public AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score,
228  String conclusion, String configuration, String justification, Collection<BlackboardAttribute> attributesList, CaseDbTransaction transaction) throws BlackboardException {
229 
230  if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
231  throw new BlackboardException(String.format("Artifact type (name = %s) is not of Analysis Result category. ", artifactType.getTypeName()));
232  }
233 
234  try {
235  // add analysis result
236  AnalysisResult analysisResult = caseDb.newAnalysisResult(artifactType, objId, dataSourceObjId, score, conclusion, configuration, justification, transaction.getConnection());
237 
238  // add the given attributes
239  if (attributesList != null && !attributesList.isEmpty()) {
240  analysisResult.addAttributes(attributesList, transaction);
241  }
242 
243  // update the final score for the object
244  Score aggregateScore = caseDb.getScoringManager().updateAggregateScoreAfterAddition(objId, dataSourceObjId, analysisResult.getScore(), transaction);
245 
246  // return the analysis result and the current aggregate score.
247  return new AnalysisResultAdded(analysisResult, aggregateScore);
248 
249  } catch (TskCoreException ex) {
250  throw new BlackboardException("Failed to add analysis result.", ex);
251  }
252  }
253 
269 
270  CaseDbTransaction transaction = this.caseDb.beginTransaction();
271  try {
272  Score score = deleteAnalysisResult(analysisResult, transaction);
273  transaction.commit();
274  transaction = null;
275 
276  return score;
277  } finally {
278  if (transaction != null) {
279  transaction.rollback();
280  }
281  }
282  }
283 
297  public Score deleteAnalysisResult(long artifactObjId, CaseDbTransaction transaction) throws TskCoreException {
298 
299  List<AnalysisResult> analysisResults = getAnalysisResultsWhere(" artifacts.artifact_obj_id = " + artifactObjId, transaction.getConnection());
300 
301  if (analysisResults.isEmpty()) {
302  throw new TskCoreException(String.format("Analysis Result not found for artifact obj id %d", artifactObjId));
303  }
304 
305  return deleteAnalysisResult(analysisResults.get(0), transaction);
306  }
307 
321  private Score deleteAnalysisResult(AnalysisResult analysisResult, CaseDbTransaction transaction) throws TskCoreException {
322 
323  try {
324  CaseDbConnection connection = transaction.getConnection();
325 
326  // delete the blackboard artifacts row. This will also delete the tsk_analysis_result row
327  String deleteSQL = "DELETE FROM blackboard_artifacts WHERE artifact_obj_id = ?";
328 
329  PreparedStatement deleteStatement = connection.getPreparedStatement(deleteSQL, Statement.RETURN_GENERATED_KEYS);
330  deleteStatement.clearParameters();
331  deleteStatement.setLong(1, analysisResult.getId());
332 
333  deleteStatement.executeUpdate();
334 
335  // register the deleted result with the transaction so an event can be fired for it.
336  transaction.registerDeletedAnalysisResult(analysisResult.getObjectID());
337 
338  return caseDb.getScoringManager().updateAggregateScoreAfterDeletion(analysisResult.getObjectID(), analysisResult.getDataSourceObjectID(), transaction);
339 
340  } catch (SQLException ex) {
341  throw new TskCoreException(String.format("Error deleting analysis result with artifact obj id %d", analysisResult.getId()), ex);
342  }
343  }
344 
345  private final static String ANALYSIS_RESULT_QUERY_STRING = "SELECT DISTINCT artifacts.artifact_id AS artifact_id, " //NON-NLS
346  + " artifacts.obj_id AS obj_id, artifacts.artifact_obj_id AS artifact_obj_id, artifacts.data_source_obj_id AS data_source_obj_id, artifacts.artifact_type_id AS artifact_type_id, "
347  + " types.type_name AS type_name, types.display_name AS display_name, types.category_type as category_type,"//NON-NLS
348  + " artifacts.review_status_id AS review_status_id, " //NON-NLS
349  + " results.conclusion AS conclusion, results.significance AS significance, results.priority AS priority, "
350  + " results.configuration AS configuration, results.justification AS justification "
351  + " FROM blackboard_artifacts AS artifacts "
352  + " JOIN blackboard_artifact_types AS types " //NON-NLS
353  + " ON artifacts.artifact_type_id = types.artifact_type_id" //NON-NLS
354  + " LEFT JOIN tsk_analysis_results AS results "
355  + " ON artifacts.artifact_obj_id = results.artifact_obj_id " //NON-NLS
356  + " WHERE artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() //NON-NLS
357  + " AND types.category_type = " + BlackboardArtifact.Category.ANALYSIS_RESULT.getID(); // NON-NLS
358 
369  public List<AnalysisResult> getAnalysisResultsByType(int artifactTypeId) throws TskCoreException {
370  return getAnalysisResultsWhere(" artifacts.artifact_type_id = " + artifactTypeId);
371  }
372 
384  public List<AnalysisResult> getAnalysisResultsByType(int artifactTypeId, long dataSourceObjId) throws TskCoreException {
385  return getAnalysisResultsWhere(" artifacts.artifact_type_id = " + artifactTypeId + " AND artifacts.data_source_obj_id = " + dataSourceObjId);
386  }
387 
398  public List<AnalysisResult> getAnalysisResults(long sourceObjId) throws TskCoreException {
399  return getAnalysisResultsWhere(" artifacts.obj_id = " + sourceObjId);
400  }
401 
412  List<DataArtifact> getDataArtifactsBySource(long sourceObjId) throws TskCoreException {
414  try (CaseDbConnection connection = caseDb.getConnection()) {
415  return getDataArtifactsWhere(String.format(" artifacts.obj_id = %d", sourceObjId), connection);
416  } finally {
418  }
419  }
420 
430  public boolean hasDataArtifacts(long sourceObjId) throws TskCoreException {
431  return hasArtifactsOfCategory(BlackboardArtifact.Category.DATA_ARTIFACT, sourceObjId);
432  }
433 
444  public boolean hasAnalysisResults(long sourceObjId) throws TskCoreException {
445  return hasArtifactsOfCategory(BlackboardArtifact.Category.ANALYSIS_RESULT, sourceObjId);
446  }
447 
460  private boolean hasArtifactsOfCategory(BlackboardArtifact.Category category, long sourceObjId) throws TskCoreException {
461  String queryString = "SELECT COUNT(*) AS count " //NON-NLS
462  + " FROM blackboard_artifacts AS arts "
463  + " JOIN blackboard_artifact_types AS types " //NON-NLS
464  + " ON arts.artifact_type_id = types.artifact_type_id" //NON-NLS
465  + " WHERE types.category_type = " + category.getID()
466  + " AND arts.obj_id = " + sourceObjId;
467 
469  try (SleuthkitCase.CaseDbConnection connection = caseDb.getConnection();
470  Statement statement = connection.createStatement();
471  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
472  if (resultSet.next()) {
473  return resultSet.getLong("count") > 0;
474  }
475  return false;
476  } catch (SQLException ex) {
477  throw new TskCoreException("Error getting artifact types is use for data source." + ex.getMessage(), ex);
478  } finally {
480  }
481  }
482 
495  List<AnalysisResult> getAnalysisResults(long sourceObjId, CaseDbConnection connection) throws TskCoreException {
496  return getAnalysisResultsWhere(" artifacts.obj_id = " + sourceObjId, connection);
497  }
498 
510  public List<AnalysisResult> getAnalysisResults(long sourceObjId, int artifactTypeId) throws TskCoreException {
511  // Get the artifact type to check that it in the analysis result category.
512  BlackboardArtifact.Type artifactType = caseDb.getArtifactType(artifactTypeId);
513  if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
514  throw new TskCoreException(String.format("Artifact type id %d is not in analysis result catgeory.", artifactTypeId));
515  }
516 
517  String whereClause = " types.artifact_type_id = " + artifactTypeId
518  + " AND artifacts.obj_id = " + sourceObjId;
519  return getAnalysisResultsWhere(whereClause);
520  }
521 
533  public List<AnalysisResult> getAnalysisResultsWhere(String whereClause) throws TskCoreException {
535  try (CaseDbConnection connection = caseDb.getConnection()) {
536  return getAnalysisResultsWhere(whereClause, connection);
537  } finally {
539  }
540  }
541 
554  List<AnalysisResult> getAnalysisResultsWhere(String whereClause, CaseDbConnection connection) throws TskCoreException {
555 
556  final String queryString = ANALYSIS_RESULT_QUERY_STRING
557  + " AND " + whereClause;
558 
559  try (Statement statement = connection.createStatement();
560  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
561 
562  List<AnalysisResult> analysisResults = resultSetToAnalysisResults(resultSet);
563  return analysisResults;
564  } catch (SQLException ex) {
565  throw new TskCoreException(String.format("Error getting analysis results for WHERE clause = '%s'", whereClause), ex);
566  }
567  }
568 
578  public AnalysisResult getAnalysisResultById(long artifactObjId) throws TskCoreException {
579 
580  String whereClause = " artifacts.artifact_obj_id = " + artifactObjId;
581  List<AnalysisResult> results = getAnalysisResultsWhere(whereClause);
582 
583  if (results.isEmpty()) { // throw an error if no analysis result found by id.
584  throw new TskCoreException(String.format("Error getting analysis result with id = '%d'", artifactObjId));
585  }
586  if (results.size() > 1) { // should not happen - throw an error
587  throw new TskCoreException(String.format("Multiple analysis results found with id = '%d'", artifactObjId));
588  }
589 
590  return results.get(0);
591  }
592 
608  private List<AnalysisResult> resultSetToAnalysisResults(ResultSet resultSet) throws SQLException, TskCoreException {
609  ArrayList<AnalysisResult> analysisResults = new ArrayList<>();
610 
611  while (resultSet.next()) {
612  analysisResults.add(new AnalysisResult(caseDb, resultSet.getLong("artifact_id"), resultSet.getLong("obj_id"),
613  resultSet.getLong("artifact_obj_id"),
614  resultSet.getObject("data_source_obj_id") != null ? resultSet.getLong("data_source_obj_id") : null,
615  resultSet.getInt("artifact_type_id"), resultSet.getString("type_name"), resultSet.getString("display_name"),
616  BlackboardArtifact.ReviewStatus.withID(resultSet.getInt("review_status_id")),
617  new Score(Score.Significance.fromID(resultSet.getInt("significance")), Score.Priority.fromID(resultSet.getInt("priority"))),
618  resultSet.getString("conclusion"), resultSet.getString("configuration"), resultSet.getString("justification")));
619  } //end for each resultSet
620 
621  return analysisResults;
622  }
623 
624  private final static String DATA_ARTIFACT_QUERY_STRING = "SELECT DISTINCT artifacts.artifact_id AS artifact_id, " //NON-NLS
625  + "artifacts.obj_id AS obj_id, artifacts.artifact_obj_id AS artifact_obj_id, artifacts.data_source_obj_id AS data_source_obj_id, artifacts.artifact_type_id AS artifact_type_id, " //NON-NLS
626  + " types.type_name AS type_name, types.display_name AS display_name, types.category_type as category_type,"//NON-NLS
627  + " artifacts.review_status_id AS review_status_id, " //NON-NLS
628  + " data_artifacts.os_account_obj_id as os_account_obj_id " //NON-NLS
629  + " FROM blackboard_artifacts AS artifacts "
630  + " JOIN blackboard_artifact_types AS types " //NON-NLS
631  + " ON artifacts.artifact_type_id = types.artifact_type_id" //NON-NLS
632  + " LEFT JOIN tsk_data_artifacts AS data_artifacts "
633  + " ON artifacts.artifact_obj_id = data_artifacts.artifact_obj_id " //NON-NLS
634  + " WHERE artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() //NON-NLS
635  + " AND types.category_type = " + BlackboardArtifact.Category.DATA_ARTIFACT.getID(); // NON-NLS
636 
649  public List<DataArtifact> getDataArtifacts(long dataSourceObjId, Integer artifactTypeID) throws TskCoreException {
651  try (CaseDbConnection connection = caseDb.getConnection()) {
652  String whereClause = " artifacts.data_source_obj_id = " + dataSourceObjId;
653  if (artifactTypeID != null) {
654  whereClause += " AND artifacts.artifact_type_id = " + artifactTypeID;
655  }
656  return getDataArtifactsWhere(whereClause, connection);
657  } finally {
659  }
660  }
661 
673  public List<DataArtifact> getDataArtifacts(int artifactTypeID, long dataSourceObjId) throws TskCoreException {
674 
675  // Get the artifact type to check that it in the data artifact category.
676  BlackboardArtifact.Type artifactType = caseDb.getArtifactType(artifactTypeID);
677  if (artifactType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) {
678  throw new TskCoreException(String.format("Artifact type id %d is not in data artifact catgeory.", artifactTypeID));
679  }
680 
682  try (CaseDbConnection connection = caseDb.getConnection()) {
683  String whereClause = "artifacts.data_source_obj_id = " + dataSourceObjId
684  + " AND artifacts.artifact_type_id = " + artifactTypeID;
685 
686  return getDataArtifactsWhere(whereClause, connection);
687  } finally {
689  }
690  }
691 
702  public List<DataArtifact> getDataArtifacts(int artifactTypeID) throws TskCoreException {
703  // Get the artifact type to check that it in the data artifact category.
704  BlackboardArtifact.Type artifactType = caseDb.getArtifactType(artifactTypeID);
705  if (artifactType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) {
706  throw new TskCoreException(String.format("Artifact type id %d is not in data artifact catgeory.", artifactTypeID));
707  }
708 
710  try (CaseDbConnection connection = caseDb.getConnection()) {
711  String whereClause = " artifacts.artifact_type_id = " + artifactTypeID;
712 
713  return getDataArtifactsWhere(whereClause, connection);
714  } finally {
716  }
717  }
718 
729  public DataArtifact getDataArtifactById(long artifactObjId) throws TskCoreException {
731  try (CaseDbConnection connection = caseDb.getConnection()) {
732  String whereClause = " artifacts.artifact_obj_id = " + artifactObjId;
733 
734  List<DataArtifact> artifacts = getDataArtifactsWhere(whereClause, connection);
735  if (artifacts.isEmpty()) { // throw an error if no analysis result found by id.
736  throw new TskCoreException(String.format("Error getting data artifact with id = '%d'", artifactObjId));
737  }
738  if (artifacts.size() > 1) { // should not happen - throw an error
739  throw new TskCoreException(String.format("Multiple data artifacts found with id = '%d'", artifactObjId));
740  }
741 
742  return artifacts.get(0);
743  } finally {
745  }
746  }
747 
758  List<DataArtifact> getDataArtifactsWhere(String whereClause) throws TskCoreException {
760  try (CaseDbConnection connection = caseDb.getConnection()) {
761  return getDataArtifactsWhere(whereClause, connection);
762  } finally {
764  }
765  }
766 
779  List<DataArtifact> getDataArtifactsWhere(String whereClause, CaseDbConnection connection) throws TskCoreException {
780 
781  final String queryString = DATA_ARTIFACT_QUERY_STRING
782  + " AND ( " + whereClause + " )";
783 
784  try (Statement statement = connection.createStatement();
785  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
786 
787  List<DataArtifact> dataArtifacts = resultSetToDataArtifacts(resultSet, connection);
788  return dataArtifacts;
789  } catch (SQLException ex) {
790  throw new TskCoreException(String.format("Error getting data artifacts with queryString = %s", queryString), ex);
791  }
792  }
793 
810  private List<DataArtifact> resultSetToDataArtifacts(ResultSet resultSet, CaseDbConnection connection) throws SQLException, TskCoreException {
811  ArrayList<DataArtifact> dataArtifacts = new ArrayList<>();
812 
813  while (resultSet.next()) {
814 
815  Long osAccountObjId = resultSet.getLong("os_account_obj_id");
816  if (resultSet.wasNull()) {
817  osAccountObjId = null;
818  }
819 
820  dataArtifacts.add(new DataArtifact(caseDb, resultSet.getLong("artifact_id"), resultSet.getLong("obj_id"),
821  resultSet.getLong("artifact_obj_id"),
822  resultSet.getObject("data_source_obj_id") != null ? resultSet.getLong("data_source_obj_id") : null,
823  resultSet.getInt("artifact_type_id"), resultSet.getString("type_name"), resultSet.getString("display_name"),
824  BlackboardArtifact.ReviewStatus.withID(resultSet.getInt("review_status_id")), osAccountObjId, false));
825  } //end for each resultSet
826 
827  return dataArtifacts;
828  }
829 
842  return caseDb.getArtifactType(artTypeId);
843  }
844 
858  public BlackboardAttribute.Type getOrAddAttributeType(String typeName, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws BlackboardException {
859 
860  try {
861  return caseDb.addArtifactAttributeType(typeName, valueType, displayName);
862  } catch (TskDataException typeExistsEx) {
863  try {
864  return caseDb.getAttributeType(typeName);
865  } catch (TskCoreException ex) {
866  throw new BlackboardException("Failed to get or add attribute type", ex);
867  }
868  } catch (TskCoreException ex) {
869  throw new BlackboardException("Failed to get or add attribute type", ex);
870  }
871  }
872 
884  public List<BlackboardArtifact.Type> getArtifactTypesInUse(long dataSourceObjId) throws TskCoreException {
885 
886  final String queryString = "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
887  + "types.type_name AS type_name, "
888  + "types.display_name AS display_name, "
889  + "types.category_type AS category_type "
890  + "FROM blackboard_artifact_types AS types "
891  + "INNER JOIN blackboard_artifacts AS arts "
892  + "ON arts.artifact_type_id = types.artifact_type_id "
893  + "WHERE arts.data_source_obj_id = " + dataSourceObjId;
894 
896  try (SleuthkitCase.CaseDbConnection connection = caseDb.getConnection();
897  Statement statement = connection.createStatement();
898  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
899 
900  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<>();
901  while (resultSet.next()) {
902  uniqueArtifactTypes.add(new BlackboardArtifact.Type(resultSet.getInt("artifact_type_id"),
903  resultSet.getString("type_name"), resultSet.getString("display_name"),
904  BlackboardArtifact.Category.fromID(resultSet.getInt("category_type"))));
905  }
906  return uniqueArtifactTypes;
907  } catch (SQLException ex) {
908  throw new TskCoreException("Error getting artifact types is use for data source." + ex.getMessage(), ex);
909  } finally {
911  }
912  }
913 
926  public long getArtifactsCount(int artifactTypeID, long dataSourceObjId) throws TskCoreException {
927  return getArtifactsCountHelper(artifactTypeID,
928  "blackboard_artifacts.data_source_obj_id = '" + dataSourceObjId + "';");
929  }
930 
943  public List<BlackboardArtifact> getArtifacts(int artifactTypeID, long dataSourceObjId) throws TskCoreException {
944  String whereClause = String.format("artifacts.data_source_obj_id = %d", dataSourceObjId);
945  return getArtifactsWhere(caseDb.getArtifactType(artifactTypeID), whereClause);
946  }
947 
960  public List<BlackboardArtifact> getArtifacts(Collection<BlackboardArtifact.Type> artifactTypes,
961  Collection<Long> dataSourceObjIds) throws TskCoreException {
962 
963  if (artifactTypes.isEmpty() || dataSourceObjIds.isEmpty()) {
964  return new ArrayList<>();
965  }
966 
967  String analysisResultQuery = "";
968  String dataArtifactQuery = "";
969 
970  for (BlackboardArtifact.Type type : artifactTypes) {
971  if (type.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
972  if (!analysisResultQuery.isEmpty()) {
973  analysisResultQuery += " OR ";
974  }
975  analysisResultQuery += "types.artifact_type_id = " + type.getTypeID();
976  } else {
977  if (!dataArtifactQuery.isEmpty()) {
978  dataArtifactQuery += " OR ";
979  }
980  dataArtifactQuery += "types.artifact_type_id = " + type.getTypeID();
981  }
982  }
983 
984  String dsQuery = "";
985  for (long dsId : dataSourceObjIds) {
986  if (!dsQuery.isEmpty()) {
987  dsQuery += " OR ";
988  }
989  dsQuery += "artifacts.data_source_obj_id = " + dsId;
990  }
991 
992  List<BlackboardArtifact> artifacts = new ArrayList<>();
993 
994  if (!analysisResultQuery.isEmpty()) {
995  String fullQuery = "( " + analysisResultQuery + " ) AND (" + dsQuery + ") ";
996  artifacts.addAll(this.getAnalysisResultsWhere(fullQuery));
997  }
998 
999  if (!dataArtifactQuery.isEmpty()) {
1000  String fullQuery = "( " + dataArtifactQuery + " ) AND (" + dsQuery + ") ";
1001  artifacts.addAll(this.getDataArtifactsWhere(fullQuery));
1002  }
1003 
1004  return artifacts;
1005  }
1006 
1019  private long getArtifactsCountHelper(int artifactTypeID, String whereClause) throws TskCoreException {
1020  String queryString = "SELECT COUNT(*) AS count FROM blackboard_artifacts "
1021  + "WHERE blackboard_artifacts.artifact_type_id = " + artifactTypeID
1022  + " AND blackboard_artifacts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()
1023  + " AND " + whereClause;
1024 
1026  try (SleuthkitCase.CaseDbConnection connection = caseDb.getConnection();
1027  Statement statement = connection.createStatement();
1028  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
1029  //NON-NLS
1030  long count = 0;
1031  if (resultSet.next()) {
1032  count = resultSet.getLong("count");
1033  }
1034  return count;
1035  } catch (SQLException ex) {
1036  throw new TskCoreException("Error getting artifact types is use for data source." + ex.getMessage(), ex);
1037  } finally {
1039  }
1040  }
1041 
1042  /*
1043  * Determine if an artifact of a given type exists for given content with a
1044  * specific list of attributes.
1045  *
1046  * @param content The content whose artifacts need to be looked at. @param
1047  * artifactType The type of artifact to look for. @param attributesList The
1048  * list of attributes to look for.
1049  *
1050  * @return True if the specific artifact exists; otherwise false.
1051  *
1052  * @throws TskCoreException If there is a problem getting artifacts or
1053  * attributes.
1054  */
1055  public boolean artifactExists(Content content, BlackboardArtifact.ARTIFACT_TYPE artifactType,
1056  Collection<BlackboardAttribute> attributesList) throws TskCoreException {
1057 
1058  ArrayList<BlackboardArtifact> artifactsList;
1059 
1060  /*
1061  * Get the content's artifacts.
1062  */
1063  artifactsList = content.getArtifacts(artifactType);
1064  if (artifactsList.isEmpty()) {
1065  return false;
1066  }
1067 
1068  /*
1069  * Get each artifact's attributes and analyze them for matches.
1070  */
1071  for (BlackboardArtifact artifact : artifactsList) {
1072  if (attributesMatch(artifact.getAttributes(), attributesList)) {
1073  /*
1074  * The exact artifact exists, so we don't need to look any
1075  * further.
1076  */
1077  return true;
1078  }
1079  }
1080 
1081  /*
1082  * None of the artifacts have the exact set of attribute type/value
1083  * combinations. The provided content does not have the artifact being
1084  * sought.
1085  */
1086  return false;
1087  }
1088 
1098  private boolean attributesMatch(Collection<BlackboardAttribute> fileAttributesList, Collection<BlackboardAttribute> expectedAttributesList) {
1099  for (BlackboardAttribute expectedAttribute : expectedAttributesList) {
1100  boolean match = false;
1101  for (BlackboardAttribute fileAttribute : fileAttributesList) {
1102  BlackboardAttribute.Type attributeType = fileAttribute.getAttributeType();
1103  if (attributeType.getTypeID() != expectedAttribute.getAttributeType().getTypeID()) {
1104  continue;
1105  }
1106 
1107  Object fileAttributeValue;
1108  Object expectedAttributeValue;
1109  switch (attributeType.getValueType()) {
1110  case BYTE:
1111  fileAttributeValue = fileAttribute.getValueBytes();
1112  expectedAttributeValue = expectedAttribute.getValueBytes();
1113  break;
1114  case DOUBLE:
1115  fileAttributeValue = fileAttribute.getValueDouble();
1116  expectedAttributeValue = expectedAttribute.getValueDouble();
1117  break;
1118  case INTEGER:
1119  fileAttributeValue = fileAttribute.getValueInt();
1120  expectedAttributeValue = expectedAttribute.getValueInt();
1121  break;
1122  case LONG: // Fall-thru
1123  case DATETIME:
1124  fileAttributeValue = fileAttribute.getValueLong();
1125  expectedAttributeValue = expectedAttribute.getValueLong();
1126  break;
1127  case STRING: // Fall-thru
1128  case JSON:
1129  fileAttributeValue = fileAttribute.getValueString();
1130  expectedAttributeValue = expectedAttribute.getValueString();
1131  break;
1132  default:
1133  fileAttributeValue = fileAttribute.getDisplayString();
1134  expectedAttributeValue = expectedAttribute.getDisplayString();
1135  break;
1136  }
1137 
1138  /*
1139  * If the exact attribute was found, mark it as a match to
1140  * continue looping through the expected attributes list.
1141  */
1142  if (fileAttributeValue instanceof byte[]) {
1143  if (Arrays.equals((byte[]) fileAttributeValue, (byte[]) expectedAttributeValue)) {
1144  match = true;
1145  break;
1146  }
1147  } else if (fileAttributeValue.equals(expectedAttributeValue)) {
1148  match = true;
1149  break;
1150  }
1151  }
1152  if (!match) {
1153  /*
1154  * The exact attribute type/value combination was not found.
1155  */
1156  return false;
1157  }
1158  }
1159 
1160  /*
1161  * All attribute type/value combinations were found in the provided
1162  * attributes list.
1163  */
1164  return true;
1165 
1166  }
1167 
1171  public static final class BlackboardException extends Exception {
1172 
1173  private static final long serialVersionUID = 1L;
1174 
1180  BlackboardException(String message) {
1181  super(message);
1182  }
1183 
1191  BlackboardException(String message, Throwable cause) {
1192  super(message, cause);
1193  }
1194  }
1195 
1212  public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId,
1213  Collection<BlackboardAttribute> attributes, Long osAccountId) throws TskCoreException {
1214 
1215  if (artifactType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) {
1216  throw new TskCoreException(String.format("Artifact type (name = %s) is not of Data Artifact category. ", artifactType.getTypeName()));
1217  }
1218 
1219  CaseDbTransaction transaction = caseDb.beginTransaction();
1220  try {
1221  DataArtifact dataArtifact = newDataArtifact(artifactType, sourceObjId, dataSourceObjId,
1222  attributes, osAccountId, transaction);
1223  transaction.commit();
1224  return dataArtifact;
1225  } catch (TskCoreException ex) {
1226  try {
1227  transaction.rollback();
1228  } catch (TskCoreException ex2) {
1229  LOGGER.log(Level.SEVERE, "Failed to rollback transaction after exception. "
1230  + "Error invoking newDataArtifact with dataSourceObjId: " + dataSourceObjId + ", sourceObjId: " + sourceObjId, ex2);
1231  }
1232  throw ex;
1233  }
1234  }
1235 
1256  public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId,
1257  Collection<BlackboardAttribute> attributes, Long osAccountObjId, final CaseDbTransaction transaction) throws TskCoreException {
1258 
1259  if (artifactType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) {
1260  throw new TskCoreException(String.format("Artifact type (name = %s) is not of Data Artifact category. ", artifactType.getTypeName()));
1261  }
1262 
1263  try {
1264  CaseDbConnection connection = transaction.getConnection();
1265  long artifact_obj_id = caseDb.addObject(sourceObjId, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
1266  PreparedStatement statement = caseDb.createInsertArtifactStatement(artifactType.getTypeID(), sourceObjId, artifact_obj_id, dataSourceObjId, connection);
1267 
1268  connection.executeUpdate(statement);
1269  try (ResultSet resultSet = statement.getGeneratedKeys()) {
1270  resultSet.next();
1271  DataArtifact dataArtifact = new DataArtifact(caseDb, resultSet.getLong(1), //last_insert_rowid()
1272  sourceObjId, artifact_obj_id, dataSourceObjId, artifactType.getTypeID(),
1273  artifactType.getTypeName(), artifactType.getDisplayName(), BlackboardArtifact.ReviewStatus.UNDECIDED,
1274  osAccountObjId, true);
1275 
1276  // Add a row in tsk_data_artifact if the os account is present
1277  if (osAccountObjId != null) {
1278  String insertDataArtifactSQL = "INSERT INTO tsk_data_artifacts (artifact_obj_id, os_account_obj_id) VALUES (?, ?)";
1279 
1280  statement = connection.getPreparedStatement(insertDataArtifactSQL, Statement.NO_GENERATED_KEYS);
1281  statement.clearParameters();
1282 
1283  statement.setLong(1, artifact_obj_id);
1284  statement.setLong(2, osAccountObjId);
1285  connection.executeUpdate(statement);
1286  }
1287 
1288  // if attributes are provided, add them to the artifact.
1289  if (Objects.nonNull(attributes) && !attributes.isEmpty()) {
1290  dataArtifact.addAttributes(attributes, transaction);
1291  }
1292 
1293  return dataArtifact;
1294  }
1295  } catch (SQLException ex) {
1296  throw new TskCoreException(String.format("Error creating a data artifact with type id = %d, objId = %d, and data source oj id = %d ", artifactType.getTypeID(), sourceObjId, dataSourceObjId), ex);
1297  }
1298  }
1299 
1311  List<BlackboardArtifact> getArtifactsBySourceId(BlackboardArtifact.Type artifactType, long sourceObjId) throws TskCoreException {
1312  String whereClause = String.format("artifacts.obj_id = %d", sourceObjId);
1313  return getArtifactsWhere(artifactType, whereClause);
1314  }
1315 
1325  List<BlackboardArtifact> getArtifactsByType(BlackboardArtifact.Type artifactType) throws TskCoreException {
1326  List<BlackboardArtifact> artifacts = new ArrayList<>();
1327  if (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
1328  artifacts.addAll(getAnalysisResultsByType(artifactType.getTypeID()));
1329  } else {
1330  artifacts.addAll(getDataArtifacts(artifactType.getTypeID()));
1331  }
1332  return artifacts;
1333  }
1334 
1352  private List<BlackboardArtifact> getArtifactsWhere(BlackboardArtifact.Type artifactType, String whereClause) throws TskCoreException {
1353  List<BlackboardArtifact> artifacts = new ArrayList<>();
1354  String whereWithType = whereClause + " AND artifacts.artifact_type_id = " + artifactType.getTypeID();
1355 
1356  if (artifactType.getCategory() == BlackboardArtifact.Category.ANALYSIS_RESULT) {
1357  artifacts.addAll(getAnalysisResultsWhere(whereWithType));
1358  } else {
1359  artifacts.addAll(getDataArtifactsWhere(whereWithType));
1360  }
1361 
1362  return artifacts;
1363  }
1364 
1370  final public class ArtifactsPostedEvent {
1371 
1372  private final String moduleName;
1373  private final ImmutableSet<BlackboardArtifact.Type> artifactTypes;
1374  private final ImmutableSet<BlackboardArtifact> artifacts;
1375 
1376  private ArtifactsPostedEvent(Collection<BlackboardArtifact> artifacts, String moduleName) throws BlackboardException {
1377  Set<Integer> typeIDS = artifacts.stream()
1379  .collect(Collectors.toSet());
1380  Set<BlackboardArtifact.Type> types = new HashSet<>();
1381  for (Integer typeID : typeIDS) {
1382  try {
1383  types.add(caseDb.getArtifactType(typeID));
1384  } catch (TskCoreException tskCoreException) {
1385  throw new BlackboardException("Error getting artifact type by id.", tskCoreException);
1386  }
1387  }
1388  artifactTypes = ImmutableSet.copyOf(types);
1389  this.artifacts = ImmutableSet.copyOf(artifacts);
1390  this.moduleName = moduleName;
1391 
1392  }
1393 
1394  public Collection<BlackboardArtifact> getArtifacts() {
1395  return ImmutableSet.copyOf(artifacts);
1396  }
1397 
1398  public Collection<BlackboardArtifact> getArtifacts(BlackboardArtifact.Type artifactType) {
1399  Set<BlackboardArtifact> tempSet = artifacts.stream()
1400  .filter(artifact -> artifact.getArtifactTypeID() == artifactType.getTypeID())
1401  .collect(Collectors.toSet());
1402  return ImmutableSet.copyOf(tempSet);
1403  }
1404 
1405  public String getModuleName() {
1406  return moduleName;
1407  }
1408 
1410  return ImmutableSet.copyOf(artifactTypes);
1411  }
1412  }
1413 }
static Priority fromID(int id)
Definition: Score.java:184
List< BlackboardArtifact > getArtifacts(Collection< BlackboardArtifact.Type > artifactTypes, Collection< Long > dataSourceObjIds)
static Significance fromID(int id)
Definition: Score.java:118
AnalysisResult getAnalysisResultById(long artifactObjId)
void postArtifact(BlackboardArtifact artifact, String moduleName)
Definition: Blackboard.java:71
List< DataArtifact > getDataArtifacts(int artifactTypeID, long dataSourceObjId)
List< DataArtifact > getDataArtifacts(long dataSourceObjId, Integer artifactTypeID)
boolean hasAnalysisResults(long sourceObjId)
void postArtifacts(Collection< BlackboardArtifact > artifacts, String moduleName)
Definition: Blackboard.java:90
void addAttributes(Collection< BlackboardAttribute > attributes)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId, Collection< BlackboardAttribute > attributes, Long osAccountId)
DataArtifact getDataArtifactById(long artifactObjId)
Collection< BlackboardArtifact > getArtifacts()
BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName, BlackboardArtifact.Category category)
Score deleteAnalysisResult(AnalysisResult analysisResult)
List< AnalysisResult > getAnalysisResults(long sourceObjId)
Collection< BlackboardArtifact > getArtifacts(BlackboardArtifact.Type artifactType)
BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName)
List< DataArtifact > getDataArtifacts(int artifactTypeID)
AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, Collection< BlackboardAttribute > attributesList, CaseDbTransaction transaction)
List< AnalysisResult > getAnalysisResultsWhere(String whereClause)
BlackboardAttribute.Type getOrAddAttributeType(String typeName, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName)
List< BlackboardArtifact > getArtifacts(int artifactTypeID, long dataSourceObjId)
Score deleteAnalysisResult(long artifactObjId, CaseDbTransaction transaction)
BlackboardAttribute.Type getAttributeType(String attrTypeName)
List< AnalysisResult > getAnalysisResults(long sourceObjId, int artifactTypeId)
BlackboardArtifact.Type getArtifactType(String artTypeName)
boolean artifactExists(Content content, BlackboardArtifact.ARTIFACT_TYPE artifactType, Collection< BlackboardAttribute > attributesList)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId, Collection< BlackboardAttribute > attributes, Long osAccountObjId, final CaseDbTransaction transaction)
List< AnalysisResult > getAnalysisResultsByType(int artifactTypeId, long dataSourceObjId)
Collection< BlackboardArtifact.Type > getArtifactTypes()
AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, Collection< BlackboardAttribute > attributesList)
BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName)
boolean hasDataArtifacts(long sourceObjId)
long getArtifactsCount(int artifactTypeID, long dataSourceObjId)
List< BlackboardArtifact.Type > getArtifactTypesInUse(long dataSourceObjId)
BlackboardArtifact.Type getArtifactType(int artTypeId)
BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName)
List< AnalysisResult > getAnalysisResultsByType(int artifactTypeId)

Copyright © 2011-2021 Brian Carrier. (carrier -at- sleuthkit -dot- org)
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.