Sleuth Kit Java Bindings (JNI)  4.10.2
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(" arts.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 arts.artifact_id AS artifact_id, " //NON-NLS
346  + " arts.obj_id AS obj_id, arts.artifact_obj_id AS artifact_obj_id, arts.data_source_obj_id AS data_source_obj_id, arts.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  + " arts.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 arts "
352  + " JOIN blackboard_artifact_types AS types " //NON-NLS
353  + " ON arts.artifact_type_id = types.artifact_type_id" //NON-NLS
354  + " LEFT JOIN tsk_analysis_results AS results "
355  + " ON arts.artifact_obj_id = results.artifact_obj_id " //NON-NLS
356  + " WHERE arts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() //NON-NLS
357  + " AND types.category_type = " + BlackboardArtifact.Category.ANALYSIS_RESULT.getID(); // NON-NLS
358 
359 
370  public List<AnalysisResult> getAnalysisResultsByType(int artifactTypeId) throws TskCoreException {
371  return getAnalysisResultsWhere(" arts.artifact_type_id = " + artifactTypeId);
372  }
373 
385  public List<AnalysisResult> getAnalysisResultsByType(int artifactTypeId, long dataSourceObjId) throws TskCoreException {
386  return getAnalysisResultsWhere(" arts.artifact_type_id = " + artifactTypeId + " AND arts.data_source_obj_id = " + dataSourceObjId);
387  }
388 
389 
400  public List<AnalysisResult> getAnalysisResults(long sourceObjId) throws TskCoreException {
401  return getAnalysisResultsWhere(" arts.obj_id = " + sourceObjId);
402  }
403 
404 
415  List<DataArtifact> getDataArtifactsBySource(long sourceObjId) throws TskCoreException {
417  try (CaseDbConnection connection = caseDb.getConnection()) {
418  return getDataArtifactsWhere(String.format(" artifacts.obj_id = " + sourceObjId), connection);
419  } finally {
421  }
422  }
423 
424 
431  public boolean hasDataArtifacts(long sourceObjId) throws TskCoreException {
432  return hasArtifactsOfCategory(BlackboardArtifact.Category.DATA_ARTIFACT, sourceObjId);
433  }
434 
441  public boolean hasAnalysisResults(long sourceObjId) throws TskCoreException {
442  return hasArtifactsOfCategory(BlackboardArtifact.Category.ANALYSIS_RESULT, sourceObjId);
443  }
444 
445 
453  private boolean hasArtifactsOfCategory(BlackboardArtifact.Category category, long sourceObjId) throws TskCoreException {
454  String queryString = "SELECT COUNT(*) AS count " //NON-NLS
455  + " FROM blackboard_artifacts AS arts "
456  + " JOIN blackboard_artifact_types AS types " //NON-NLS
457  + " ON arts.artifact_type_id = types.artifact_type_id" //NON-NLS
458  + " WHERE types.category_type = " + category.getID()
459  + " AND arts.obj_id = " + sourceObjId;
460 
462  try (SleuthkitCase.CaseDbConnection connection = caseDb.getConnection();
463  Statement statement = connection.createStatement();
464  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
465  if (resultSet.next()) {
466  return resultSet.getLong("count") > 0;
467  }
468  return false;
469  } catch (SQLException ex) {
470  throw new TskCoreException("Error getting artifact types is use for data source." + ex.getMessage(), ex);
471  } finally {
473  }
474  }
475 
476 
477 
478 
491  List<AnalysisResult> getAnalysisResults(long sourceObjId, CaseDbConnection connection) throws TskCoreException {
492  return getAnalysisResultsWhere(" arts.obj_id = " + sourceObjId, connection);
493  }
494 
506  public List<AnalysisResult> getAnalysisResults(long sourceObjId, int artifactTypeId) throws TskCoreException {
507  // Get the artifact type to check that it in the analysis result category.
508  BlackboardArtifact.Type artifactType = caseDb.getArtifactType(artifactTypeId);
509  if (artifactType.getCategory() != BlackboardArtifact.Category.ANALYSIS_RESULT) {
510  throw new TskCoreException(String.format("Artifact type id %d is not in analysis result catgeory.", artifactTypeId));
511  }
512 
513  String whereClause = " types.artifact_type_id = " + artifactTypeId
514  + " AND arts.obj_id = " + sourceObjId;
515  return getAnalysisResultsWhere(whereClause);
516  }
517 
529  public List<AnalysisResult> getAnalysisResultsWhere(String whereClause) throws TskCoreException {
531  try (CaseDbConnection connection = caseDb.getConnection()) {
532  return getAnalysisResultsWhere(whereClause, connection);
533  } finally {
535  }
536  }
537 
550  List<AnalysisResult> getAnalysisResultsWhere(String whereClause, CaseDbConnection connection) throws TskCoreException {
551 
552  final String queryString = ANALYSIS_RESULT_QUERY_STRING
553  + " AND " + whereClause;
554 
555  try (Statement statement = connection.createStatement();
556  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
557 
558  List<AnalysisResult> analysisResults = resultSetToAnalysisResults(resultSet);
559  return analysisResults;
560  } catch (SQLException ex) {
561  throw new TskCoreException(String.format("Error getting analysis results for WHERE clause = '%s'", whereClause), ex);
562  }
563  }
564 
574  public AnalysisResult getAnalysisResultById(long artifactObjId) throws TskCoreException {
575 
576  String whereClause = " arts.artifact_obj_id = " + artifactObjId;
577  List<AnalysisResult> results = getAnalysisResultsWhere(whereClause);
578 
579  if (results.isEmpty()) { // throw an error if no analysis result found by id.
580  throw new TskCoreException(String.format("Error getting analysis result with id = '%d'", artifactObjId));
581  }
582  if (results.size() > 1) { // should not happen - throw an error
583  throw new TskCoreException(String.format("Multiple analysis results found with id = '%d'", artifactObjId));
584  }
585 
586  return results.get(0);
587  }
588 
604  private List<AnalysisResult> resultSetToAnalysisResults(ResultSet resultSet) throws SQLException, TskCoreException {
605  ArrayList<AnalysisResult> analysisResults = new ArrayList<>();
606 
607  while (resultSet.next()) {
608  analysisResults.add(new AnalysisResult(caseDb, resultSet.getLong("artifact_id"), resultSet.getLong("obj_id"),
609  resultSet.getLong("artifact_obj_id"),
610  resultSet.getObject("data_source_obj_id") != null ? resultSet.getLong("data_source_obj_id") : null,
611  resultSet.getInt("artifact_type_id"), resultSet.getString("type_name"), resultSet.getString("display_name"),
612  BlackboardArtifact.ReviewStatus.withID(resultSet.getInt("review_status_id")),
613  new Score(Score.Significance.fromID(resultSet.getInt("significance")), Score.Priority.fromID(resultSet.getInt("priority"))),
614  resultSet.getString("conclusion"), resultSet.getString("configuration"), resultSet.getString("justification")));
615  } //end for each resultSet
616 
617  return analysisResults;
618  }
619 
620  private final static String DATA_ARTIFACT_QUERY_STRING = "SELECT DISTINCT artifacts.artifact_id AS artifact_id, " //NON-NLS
621  + "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
622  + " types.type_name AS type_name, types.display_name AS display_name, types.category_type as category_type,"//NON-NLS
623  + " artifacts.review_status_id AS review_status_id, " //NON-NLS
624  + " data_artifacts.os_account_obj_id as os_account_obj_id " //NON-NLS
625  + " FROM blackboard_artifacts AS artifacts "
626  + " JOIN blackboard_artifact_types AS types " //NON-NLS
627  + " ON artifacts.artifact_type_id = types.artifact_type_id" //NON-NLS
628  + " LEFT JOIN tsk_data_artifacts AS data_artifacts "
629  + " ON artifacts.artifact_obj_id = data_artifacts.artifact_obj_id " //NON-NLS
630  + " WHERE artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() //NON-NLS
631  + " AND types.category_type = " + BlackboardArtifact.Category.DATA_ARTIFACT.getID(); // NON-NLS
632 
644  public List<DataArtifact> getDataArtifacts(int artifactTypeID, long dataSourceObjId) throws TskCoreException {
645 
646  // Get the artifact type to check that it in the data artifact category.
647  BlackboardArtifact.Type artifactType = caseDb.getArtifactType(artifactTypeID);
648  if (artifactType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) {
649  throw new TskCoreException(String.format("Artifact type id %d is not in data artifact catgeory.", artifactTypeID));
650  }
651 
653  try (CaseDbConnection connection = caseDb.getConnection()) {
654  String whereClause = "artifacts.data_source_obj_id = " + dataSourceObjId
655  + " AND artifacts.artifact_type_id = " + artifactTypeID;
656 
657  return getDataArtifactsWhere(whereClause, connection);
658  } finally {
660  }
661  }
662 
673  public List<DataArtifact> getDataArtifacts(int artifactTypeID) throws TskCoreException {
674  // Get the artifact type to check that it in the data artifact category.
675  BlackboardArtifact.Type artifactType = caseDb.getArtifactType(artifactTypeID);
676  if (artifactType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) {
677  throw new TskCoreException(String.format("Artifact type id %d is not in data artifact catgeory.", artifactTypeID));
678  }
679 
681  try (CaseDbConnection connection = caseDb.getConnection()) {
682  String whereClause = " artifacts.artifact_type_id = " + artifactTypeID;
683 
684  return getDataArtifactsWhere(whereClause, connection);
685  } finally {
687  }
688  }
689 
700  public DataArtifact getDataArtifactById(long artifactObjId) throws TskCoreException {
702  try (CaseDbConnection connection = caseDb.getConnection()) {
703  String whereClause = " artifacts.artifact_obj_id = " + artifactObjId;
704 
705  List<DataArtifact> artifacts = getDataArtifactsWhere(whereClause, connection);
706  if (artifacts.isEmpty()) { // throw an error if no analysis result found by id.
707  throw new TskCoreException(String.format("Error getting data artifact with id = '%d'", artifactObjId));
708  }
709  if (artifacts.size() > 1) { // should not happen - throw an error
710  throw new TskCoreException(String.format("Multiple data artifacts found with id = '%d'", artifactObjId));
711  }
712 
713  return artifacts.get(0);
714  } finally {
716  }
717  }
718 
731  private List<DataArtifact> getDataArtifactsWhere(String whereClause, CaseDbConnection connection) throws TskCoreException {
732 
733  final String queryString = DATA_ARTIFACT_QUERY_STRING
734  + " AND ( " + whereClause + " )";
735 
736  try (Statement statement = connection.createStatement();
737  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
738 
739  List<DataArtifact> dataArtifacts = resultSetToDataArtifacts(resultSet, connection);
740  return dataArtifacts;
741  } catch (SQLException ex) {
742  throw new TskCoreException(String.format("Error getting data artifacts with queryString = %s", queryString), ex);
743  }
744  }
745 
762  private List<DataArtifact> resultSetToDataArtifacts(ResultSet resultSet, CaseDbConnection connection) throws SQLException, TskCoreException {
763  ArrayList<DataArtifact> dataArtifacts = new ArrayList<>();
764 
765  while (resultSet.next()) {
766 
767  Long osAccountObjId = resultSet.getLong("os_account_obj_id");
768  if (resultSet.wasNull()) {
769  osAccountObjId = null;
770  }
771 
772  dataArtifacts.add(new DataArtifact(caseDb, resultSet.getLong("artifact_id"), resultSet.getLong("obj_id"),
773  resultSet.getLong("artifact_obj_id"),
774  resultSet.getObject("data_source_obj_id") != null ? resultSet.getLong("data_source_obj_id") : null,
775  resultSet.getInt("artifact_type_id"), resultSet.getString("type_name"), resultSet.getString("display_name"),
776  BlackboardArtifact.ReviewStatus.withID(resultSet.getInt("review_status_id")), osAccountObjId, false));
777  } //end for each resultSet
778 
779  return dataArtifacts;
780  }
781 
794  return caseDb.getArtifactType(artTypeId);
795  }
796 
810  public BlackboardAttribute.Type getOrAddAttributeType(String typeName, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws BlackboardException {
811 
812  try {
813  return caseDb.addArtifactAttributeType(typeName, valueType, displayName);
814  } catch (TskDataException typeExistsEx) {
815  try {
816  return caseDb.getAttributeType(typeName);
817  } catch (TskCoreException ex) {
818  throw new BlackboardException("Failed to get or add attribute type", ex);
819  }
820  } catch (TskCoreException ex) {
821  throw new BlackboardException("Failed to get or add attribute type", ex);
822  }
823  }
824 
836  public List<BlackboardArtifact.Type> getArtifactTypesInUse(long dataSourceObjId) throws TskCoreException {
837 
838  final String queryString = "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
839  + "types.type_name AS type_name, "
840  + "types.display_name AS display_name, "
841  + "types.category_type AS category_type "
842  + "FROM blackboard_artifact_types AS types "
843  + "INNER JOIN blackboard_artifacts AS arts "
844  + "ON arts.artifact_type_id = types.artifact_type_id "
845  + "WHERE arts.data_source_obj_id = " + dataSourceObjId;
846 
848  try (SleuthkitCase.CaseDbConnection connection = caseDb.getConnection();
849  Statement statement = connection.createStatement();
850  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
851 
852  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<>();
853  while (resultSet.next()) {
854  uniqueArtifactTypes.add(new BlackboardArtifact.Type(resultSet.getInt("artifact_type_id"),
855  resultSet.getString("type_name"), resultSet.getString("display_name"),
856  BlackboardArtifact.Category.fromID(resultSet.getInt("category_type"))));
857  }
858  return uniqueArtifactTypes;
859  } catch (SQLException ex) {
860  throw new TskCoreException("Error getting artifact types is use for data source." + ex.getMessage(), ex);
861  } finally {
863  }
864  }
865 
878  public long getArtifactsCount(int artifactTypeID, long dataSourceObjId) throws TskCoreException {
879  return getArtifactsCountHelper(artifactTypeID,
880  "blackboard_artifacts.data_source_obj_id = '" + dataSourceObjId + "';");
881  }
882 
895  public List<BlackboardArtifact> getArtifacts(int artifactTypeID, long dataSourceObjId) throws TskCoreException {
896  return caseDb.getArtifactsHelper("blackboard_artifacts.data_source_obj_id = " + dataSourceObjId
897  + " AND blackboard_artifact_types.artifact_type_id = " + artifactTypeID + ";");
898  }
899 
912  public List<BlackboardArtifact> getArtifacts(Collection<BlackboardArtifact.Type> artifactTypes,
913  Collection<Long> dataSourceObjIds) throws TskCoreException {
914 
915  if (artifactTypes.isEmpty() || dataSourceObjIds.isEmpty()) {
916  return new ArrayList<>();
917  }
918 
919  String typeQuery = "";
920  for (BlackboardArtifact.Type type : artifactTypes) {
921  if (!typeQuery.isEmpty()) {
922  typeQuery += " OR ";
923  }
924  typeQuery += "blackboard_artifact_types.artifact_type_id = " + type.getTypeID();
925  }
926 
927  String dsQuery = "";
928  for (long dsId : dataSourceObjIds) {
929  if (!dsQuery.isEmpty()) {
930  dsQuery += " OR ";
931  }
932  dsQuery += "blackboard_artifacts.data_source_obj_id = " + dsId;
933  }
934 
935  String fullQuery = "( " + typeQuery + " ) AND ( " + dsQuery + " );";
936 
937  return caseDb.getArtifactsHelper(fullQuery);
938  }
939 
952  private long getArtifactsCountHelper(int artifactTypeID, String whereClause) throws TskCoreException {
953  String queryString = "SELECT COUNT(*) AS count FROM blackboard_artifacts "
954  + "WHERE blackboard_artifacts.artifact_type_id = " + artifactTypeID
955  + " AND blackboard_artifacts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()
956  + " AND " + whereClause;
957 
959  try (SleuthkitCase.CaseDbConnection connection = caseDb.getConnection();
960  Statement statement = connection.createStatement();
961  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
962  //NON-NLS
963  long count = 0;
964  if (resultSet.next()) {
965  count = resultSet.getLong("count");
966  }
967  return count;
968  } catch (SQLException ex) {
969  throw new TskCoreException("Error getting artifact types is use for data source." + ex.getMessage(), ex);
970  } finally {
972  }
973  }
974 
975  /*
976  * Determine if an artifact of a given type exists for given content with a
977  * specific list of attributes.
978  *
979  * @param content The content whose artifacts need to be looked at. @param
980  * artifactType The type of artifact to look for. @param attributesList The
981  * list of attributes to look for.
982  *
983  * @return True if the specific artifact exists; otherwise false.
984  *
985  * @throws TskCoreException If there is a problem getting artifacts or
986  * attributes.
987  */
988  public boolean artifactExists(Content content, BlackboardArtifact.ARTIFACT_TYPE artifactType,
989  Collection<BlackboardAttribute> attributesList) throws TskCoreException {
990 
991  ArrayList<BlackboardArtifact> artifactsList;
992 
993  /*
994  * Get the content's artifacts.
995  */
996  artifactsList = content.getArtifacts(artifactType);
997  if (artifactsList.isEmpty()) {
998  return false;
999  }
1000 
1001  /*
1002  * Get each artifact's attributes and analyze them for matches.
1003  */
1004  for (BlackboardArtifact artifact : artifactsList) {
1005  if (attributesMatch(artifact.getAttributes(), attributesList)) {
1006  /*
1007  * The exact artifact exists, so we don't need to look any
1008  * further.
1009  */
1010  return true;
1011  }
1012  }
1013 
1014  /*
1015  * None of the artifacts have the exact set of attribute type/value
1016  * combinations. The provided content does not have the artifact being
1017  * sought.
1018  */
1019  return false;
1020  }
1021 
1031  private boolean attributesMatch(Collection<BlackboardAttribute> fileAttributesList, Collection<BlackboardAttribute> expectedAttributesList) {
1032  for (BlackboardAttribute expectedAttribute : expectedAttributesList) {
1033  boolean match = false;
1034  for (BlackboardAttribute fileAttribute : fileAttributesList) {
1035  BlackboardAttribute.Type attributeType = fileAttribute.getAttributeType();
1036  if (attributeType.getTypeID() != expectedAttribute.getAttributeType().getTypeID()) {
1037  continue;
1038  }
1039 
1040  Object fileAttributeValue;
1041  Object expectedAttributeValue;
1042  switch (attributeType.getValueType()) {
1043  case BYTE:
1044  fileAttributeValue = fileAttribute.getValueBytes();
1045  expectedAttributeValue = expectedAttribute.getValueBytes();
1046  break;
1047  case DOUBLE:
1048  fileAttributeValue = fileAttribute.getValueDouble();
1049  expectedAttributeValue = expectedAttribute.getValueDouble();
1050  break;
1051  case INTEGER:
1052  fileAttributeValue = fileAttribute.getValueInt();
1053  expectedAttributeValue = expectedAttribute.getValueInt();
1054  break;
1055  case LONG: // Fall-thru
1056  case DATETIME:
1057  fileAttributeValue = fileAttribute.getValueLong();
1058  expectedAttributeValue = expectedAttribute.getValueLong();
1059  break;
1060  case STRING: // Fall-thru
1061  case JSON:
1062  fileAttributeValue = fileAttribute.getValueString();
1063  expectedAttributeValue = expectedAttribute.getValueString();
1064  break;
1065  default:
1066  fileAttributeValue = fileAttribute.getDisplayString();
1067  expectedAttributeValue = expectedAttribute.getDisplayString();
1068  break;
1069  }
1070 
1071  /*
1072  * If the exact attribute was found, mark it as a match to
1073  * continue looping through the expected attributes list.
1074  */
1075  if (fileAttributeValue instanceof byte[]) {
1076  if (Arrays.equals((byte[]) fileAttributeValue, (byte[]) expectedAttributeValue)) {
1077  match = true;
1078  break;
1079  }
1080  } else if (fileAttributeValue.equals(expectedAttributeValue)) {
1081  match = true;
1082  break;
1083  }
1084  }
1085  if (!match) {
1086  /*
1087  * The exact attribute type/value combination was not found.
1088  */
1089  return false;
1090  }
1091  }
1092 
1093  /*
1094  * All attribute type/value combinations were found in the provided
1095  * attributes list.
1096  */
1097  return true;
1098 
1099  }
1100 
1101 
1105  public static final class BlackboardException extends Exception {
1106 
1107  private static final long serialVersionUID = 1L;
1108 
1114  BlackboardException(String message) {
1115  super(message);
1116  }
1117 
1125  BlackboardException(String message, Throwable cause) {
1126  super(message, cause);
1127  }
1128  }
1129 
1146  public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId,
1147  Collection<BlackboardAttribute> attributes, Long osAccountId) throws TskCoreException {
1148 
1149  if (artifactType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) {
1150  throw new TskCoreException(String.format("Artifact type (name = %s) is not of Data Artifact category. ", artifactType.getTypeName()));
1151  }
1152 
1153  CaseDbTransaction transaction = caseDb.beginTransaction();
1154  try {
1155  DataArtifact dataArtifact = newDataArtifact(artifactType, sourceObjId, dataSourceObjId,
1156  attributes, osAccountId, transaction);
1157  transaction.commit();
1158  return dataArtifact;
1159  } catch (TskCoreException ex) {
1160  try {
1161  transaction.rollback();
1162  } catch (TskCoreException ex2) {
1163  LOGGER.log(Level.SEVERE, "Failed to rollback transaction after exception. "
1164  + "Error invoking newDataArtifact with dataSourceObjId: " + dataSourceObjId + ", sourceObjId: " + sourceObjId, ex2);
1165  }
1166  throw ex;
1167  }
1168  }
1169 
1190  public DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId,
1191  Collection<BlackboardAttribute> attributes, Long osAccountObjId, final CaseDbTransaction transaction) throws TskCoreException {
1192 
1193  if (artifactType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) {
1194  throw new TskCoreException(String.format("Artifact type (name = %s) is not of Data Artifact category. ", artifactType.getTypeName()));
1195  }
1196 
1197  try {
1198  CaseDbConnection connection = transaction.getConnection();
1199  long artifact_obj_id = caseDb.addObject(sourceObjId, TskData.ObjectType.ARTIFACT.getObjectType(), connection);
1200  PreparedStatement statement = caseDb.createInsertArtifactStatement(artifactType.getTypeID(), sourceObjId, artifact_obj_id, dataSourceObjId, connection);
1201 
1202  connection.executeUpdate(statement);
1203  try (ResultSet resultSet = statement.getGeneratedKeys()) {
1204  resultSet.next();
1205  DataArtifact dataArtifact = new DataArtifact(caseDb, resultSet.getLong(1), //last_insert_rowid()
1206  sourceObjId, artifact_obj_id, dataSourceObjId, artifactType.getTypeID(),
1207  artifactType.getTypeName(), artifactType.getDisplayName(), BlackboardArtifact.ReviewStatus.UNDECIDED,
1208  osAccountObjId, true);
1209 
1210  // Add a row in tsk_data_artifact if the os account is present
1211  if (osAccountObjId != null) {
1212  String insertDataArtifactSQL = "INSERT INTO tsk_data_artifacts (artifact_obj_id, os_account_obj_id) VALUES (?, ?)";
1213 
1214  statement = connection.getPreparedStatement(insertDataArtifactSQL, Statement.NO_GENERATED_KEYS);
1215  statement.clearParameters();
1216 
1217  statement.setLong(1, artifact_obj_id);
1218  statement.setLong(2, osAccountObjId);
1219  connection.executeUpdate(statement);
1220  }
1221 
1222  // if attributes are provided, add them to the artifact.
1223  if (Objects.nonNull(attributes) && !attributes.isEmpty()) {
1224  dataArtifact.addAttributes(attributes, transaction);
1225  }
1226 
1227  return dataArtifact;
1228  }
1229  } catch (SQLException ex) {
1230  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);
1231  }
1232  }
1233 
1239  final public class ArtifactsPostedEvent {
1240 
1241  private final String moduleName;
1242  private final ImmutableSet<BlackboardArtifact.Type> artifactTypes;
1243  private final ImmutableSet<BlackboardArtifact> artifacts;
1244 
1245  private ArtifactsPostedEvent(Collection<BlackboardArtifact> artifacts, String moduleName) throws BlackboardException {
1246  Set<Integer> typeIDS = artifacts.stream()
1248  .collect(Collectors.toSet());
1249  Set<BlackboardArtifact.Type> types = new HashSet<>();
1250  for (Integer typeID : typeIDS) {
1251  try {
1252  types.add(caseDb.getArtifactType(typeID));
1253  } catch (TskCoreException tskCoreException) {
1254  throw new BlackboardException("Error getting artifact type by id.", tskCoreException);
1255  }
1256  }
1257  artifactTypes = ImmutableSet.copyOf(types);
1258  this.artifacts = ImmutableSet.copyOf(artifacts);
1259  this.moduleName = moduleName;
1260 
1261  }
1262 
1263  public Collection<BlackboardArtifact> getArtifacts() {
1264  return ImmutableSet.copyOf(artifacts);
1265  }
1266 
1267  public Collection<BlackboardArtifact> getArtifacts(BlackboardArtifact.Type artifactType) {
1268  Set<BlackboardArtifact> tempSet = artifacts.stream()
1269  .filter(artifact -> artifact.getArtifactTypeID() == artifactType.getTypeID())
1270  .collect(Collectors.toSet());
1271  return ImmutableSet.copyOf(tempSet);
1272  }
1273 
1274  public String getModuleName() {
1275  return moduleName;
1276  }
1277 
1279  return ImmutableSet.copyOf(artifactTypes);
1280  }
1281  }
1282 }
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)
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.