Sleuth Kit Java Bindings (JNI)  4.10.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 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.ResultSet;
23 import java.sql.SQLException;
24 import java.sql.Statement;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Objects;
32 import java.util.Set;
33 import java.util.stream.Collectors;
34 
39 public final class Blackboard {
40 
41  private final SleuthkitCase caseDb;
42 
49  Blackboard(SleuthkitCase casedb) {
50  this.caseDb = Objects.requireNonNull(casedb, "Cannot create Blackboard for null SleuthkitCase");
51  }
52 
64  public void postArtifact(BlackboardArtifact artifact, String moduleName) throws BlackboardException {
65  postArtifacts(Collections.singleton(artifact), moduleName);
66  }
67 
83  public void postArtifacts(Collection<BlackboardArtifact> artifacts, String moduleName) throws BlackboardException {
84  /*
85  * For now this just processes them one by one, but in the future it
86  * could be smarter and use transactions, etc.
87  */
88  for (BlackboardArtifact artifact : artifacts) {
89  try {
90  caseDb.getTimelineManager().addArtifactEvents(artifact);
91  } catch (TskCoreException ex) {
92  throw new BlackboardException("Failed to add events for artifact: " + artifact, ex);
93  }
94  }
95 
96  caseDb.fireTSKEvent(new ArtifactsPostedEvent(artifacts, moduleName));
97  }
98 
111  public BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName) throws BlackboardException {
112 
113  try {
114  return caseDb.addBlackboardArtifactType(typeName, displayName);
115  } catch (TskDataException typeExistsEx) {
116  try {
117  return caseDb.getArtifactType(typeName);
118  } catch (TskCoreException ex) {
119  throw new BlackboardException("Failed to get or add artifact type", ex);
120  }
121  } catch (TskCoreException ex) {
122  throw new BlackboardException("Failed to get or add artifact type", ex);
123  }
124  }
125 
140 
141  try {
142  return caseDb.addArtifactAttributeType(typeName, valueType, displayName);
143  } catch (TskDataException typeExistsEx) {
144  try {
145  return caseDb.getAttributeType(typeName);
146  } catch (TskCoreException ex) {
147  throw new BlackboardException("Failed to get or add attribute type", ex);
148  }
149  } catch (TskCoreException ex) {
150  throw new BlackboardException("Failed to get or add attribute type", ex);
151  }
152  }
153 
165  public List<BlackboardArtifact.Type> getArtifactTypesInUse(long dataSourceObjId) throws TskCoreException {
166 
167  final String queryString = "SELECT DISTINCT arts.artifact_type_id AS artifact_type_id, "
168  + "types.type_name AS type_name, types.display_name AS display_name "
169  + "FROM blackboard_artifact_types AS types "
170  + "INNER JOIN blackboard_artifacts AS arts "
171  + "ON arts.artifact_type_id = types.artifact_type_id "
172  + "WHERE arts.data_source_obj_id = " + dataSourceObjId;
173 
175  try (SleuthkitCase.CaseDbConnection connection = caseDb.getConnection();
176  Statement statement = connection.createStatement();
177  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
178 
179  List<BlackboardArtifact.Type> uniqueArtifactTypes = new ArrayList<>();
180  while (resultSet.next()) {
181  uniqueArtifactTypes.add(new BlackboardArtifact.Type(resultSet.getInt("artifact_type_id"),
182  resultSet.getString("type_name"), resultSet.getString("display_name")));
183  }
184  return uniqueArtifactTypes;
185  } catch (SQLException ex) {
186  throw new TskCoreException("Error getting artifact types is use for data source." + ex.getMessage(), ex);
187  } finally {
189  }
190  }
191 
204  public long getArtifactsCount(int artifactTypeID, long dataSourceObjId) throws TskCoreException {
205  return getArtifactsCountHelper(artifactTypeID,
206  "blackboard_artifacts.data_source_obj_id = '" + dataSourceObjId + "';");
207  }
208 
221  public List<BlackboardArtifact> getArtifacts(int artifactTypeID, long dataSourceObjId) throws TskCoreException {
222  return caseDb.getArtifactsHelper("blackboard_artifacts.data_source_obj_id = " + dataSourceObjId
223  + " AND blackboard_artifact_types.artifact_type_id = " + artifactTypeID + ";");
224  }
225 
238  public List<BlackboardArtifact> getArtifacts(Collection<BlackboardArtifact.Type> artifactTypes,
239  Collection<Long> dataSourceObjIds) throws TskCoreException {
240 
241  if (artifactTypes.isEmpty() || dataSourceObjIds.isEmpty()) {
242  return new ArrayList<>();
243  }
244 
245  String typeQuery = "";
246  for (BlackboardArtifact.Type type : artifactTypes) {
247  if (!typeQuery.isEmpty()) {
248  typeQuery += " OR ";
249  }
250  typeQuery += "blackboard_artifact_types.artifact_type_id = " + type.getTypeID();
251  }
252 
253  String dsQuery = "";
254  for (long dsId : dataSourceObjIds) {
255  if (!dsQuery.isEmpty()) {
256  dsQuery += " OR ";
257  }
258  dsQuery += "blackboard_artifacts.data_source_obj_id = " + dsId;
259  }
260 
261  String fullQuery = "( " + typeQuery + " ) AND ( " + dsQuery + " );";
262 
263  return caseDb.getArtifactsHelper(fullQuery);
264  }
265 
278  private long getArtifactsCountHelper(int artifactTypeID, String whereClause) throws TskCoreException {
279  String queryString = "SELECT COUNT(*) AS count FROM blackboard_artifacts "
280  + "WHERE blackboard_artifacts.artifact_type_id = " + artifactTypeID
281  + " AND blackboard_artifacts.review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()
282  + " AND " + whereClause;
283 
285  try (SleuthkitCase.CaseDbConnection connection = caseDb.getConnection();
286  Statement statement = connection.createStatement();
287  ResultSet resultSet = connection.executeQuery(statement, queryString);) {
288  //NON-NLS
289  long count = 0;
290  if (resultSet.next()) {
291  count = resultSet.getLong("count");
292  }
293  return count;
294  } catch (SQLException ex) {
295  throw new TskCoreException("Error getting artifact types is use for data source." + ex.getMessage(), ex);
296  } finally {
298  }
299  }
300 
301  /*
302  * Determine if an artifact of a given type exists for given content with a
303  * specific list of attributes.
304  *
305  * @param content The content whose artifacts need to be looked at. @param
306  * artifactType The type of artifact to look for. @param attributesList The
307  * list of attributes to look for.
308  *
309  * @return True if the specific artifact exists; otherwise false.
310  *
311  * @throws TskCoreException If there is a problem getting artifacts or
312  * attributes.
313  */
314  public boolean artifactExists(Content content, BlackboardArtifact.ARTIFACT_TYPE artifactType,
315  Collection<BlackboardAttribute> attributesList) throws TskCoreException {
316 
317  ArrayList<BlackboardArtifact> artifactsList;
318 
319  /*
320  * Get the content's artifacts.
321  */
322  artifactsList = content.getArtifacts(artifactType);
323  if (artifactsList.isEmpty()) {
324  return false;
325  }
326 
327  /*
328  * Get each artifact's attributes and analyze them for matches.
329  */
330  for (BlackboardArtifact artifact : artifactsList) {
331  if (attributesMatch(artifact.getAttributes(), attributesList)) {
332  /*
333  * The exact artifact exists, so we don't need to look any
334  * further.
335  */
336  return true;
337  }
338  }
339 
340  /*
341  * None of the artifacts have the exact set of attribute type/value
342  * combinations. The provided content does not have the artifact being
343  * sought.
344  */
345  return false;
346  }
347 
357  private boolean attributesMatch(Collection<BlackboardAttribute> fileAttributesList, Collection<BlackboardAttribute> expectedAttributesList) {
358  for (BlackboardAttribute expectedAttribute : expectedAttributesList) {
359  boolean match = false;
360  for (BlackboardAttribute fileAttribute : fileAttributesList) {
361  BlackboardAttribute.Type attributeType = fileAttribute.getAttributeType();
362 
363  if (attributeType.getTypeID() != expectedAttribute.getAttributeType().getTypeID()) {
364  continue;
365  }
366 
367  Object fileAttributeValue;
368  Object expectedAttributeValue;
369  switch (attributeType.getValueType()) {
370  case BYTE:
371  fileAttributeValue = fileAttribute.getValueBytes();
372  expectedAttributeValue = expectedAttribute.getValueBytes();
373  break;
374  case DOUBLE:
375  fileAttributeValue = fileAttribute.getValueDouble();
376  expectedAttributeValue = expectedAttribute.getValueDouble();
377  break;
378  case INTEGER:
379  fileAttributeValue = fileAttribute.getValueInt();
380  expectedAttributeValue = expectedAttribute.getValueInt();
381  break;
382  case LONG: // Fall-thru
383  case DATETIME:
384  fileAttributeValue = fileAttribute.getValueLong();
385  expectedAttributeValue = expectedAttribute.getValueLong();
386  break;
387  case STRING: // Fall-thru
388  case JSON:
389  fileAttributeValue = fileAttribute.getValueString();
390  expectedAttributeValue = expectedAttribute.getValueString();
391  break;
392  default:
393  fileAttributeValue = fileAttribute.getDisplayString();
394  expectedAttributeValue = expectedAttribute.getDisplayString();
395  break;
396  }
397 
398  /*
399  * If the exact attribute was found, mark it as a match to
400  * continue looping through the expected attributes list.
401  */
402  if (fileAttributeValue instanceof byte[]) {
403  if (Arrays.equals((byte[]) fileAttributeValue, (byte[]) expectedAttributeValue)) {
404  match = true;
405  break;
406  }
407  } else if (fileAttributeValue.equals(expectedAttributeValue)) {
408  match = true;
409  break;
410  }
411  }
412  if (!match) {
413  /*
414  * The exact attribute type/value combination was not found.
415  */
416  return false;
417  }
418  }
419 
420  /*
421  * All attribute type/value combinations were found in the provided
422  * attributes list.
423  */
424  return true;
425 
426  }
427 
431  public static final class BlackboardException extends Exception {
432 
433  private static final long serialVersionUID = 1L;
434 
440  BlackboardException(String message) {
441  super(message);
442  }
443 
451  BlackboardException(String message, Throwable cause) {
452  super(message, cause);
453  }
454  }
455 
461  final public class ArtifactsPostedEvent {
462 
463  private final String moduleName;
464  private final ImmutableSet<BlackboardArtifact.Type> artifactTypes;
465  private final ImmutableSet<BlackboardArtifact> artifacts;
466 
467  private ArtifactsPostedEvent(Collection<BlackboardArtifact> artifacts, String moduleName) throws BlackboardException {
468  Set<Integer> typeIDS = artifacts.stream()
470  .collect(Collectors.toSet());
471  Set<BlackboardArtifact.Type> types = new HashSet<>();
472  for (Integer typeID : typeIDS) {
473  try {
474  types.add(caseDb.getArtifactType(typeID));
475  } catch (TskCoreException tskCoreException) {
476  throw new BlackboardException("Error getting artifact type by id.", tskCoreException);
477  }
478  }
479  artifactTypes = ImmutableSet.copyOf(types);
480  this.artifacts = ImmutableSet.copyOf(artifacts);
481  this.moduleName = moduleName;
482 
483  }
484 
485  public Collection<BlackboardArtifact> getArtifacts() {
486  return artifacts;
487  }
488 
489  public Collection<BlackboardArtifact> getArtifacts(BlackboardArtifact.Type artifactType) {
490  Set<BlackboardArtifact> tempSet = artifacts.stream()
491  .filter(artifact -> artifact.getArtifactTypeID() == artifactType.getTypeID())
492  .collect(Collectors.toSet());
493  return ImmutableSet.copyOf(tempSet);
494  }
495 
496  public String getModuleName() {
497  return moduleName;
498  }
499 
500  public Collection<BlackboardArtifact.Type> getArtifactTypes() {
501  return artifactTypes;
502  }
503  }
504 }
List< BlackboardArtifact > getArtifacts(Collection< BlackboardArtifact.Type > artifactTypes, Collection< Long > dataSourceObjIds)
void postArtifact(BlackboardArtifact artifact, String moduleName)
Definition: Blackboard.java:64
void postArtifacts(Collection< BlackboardArtifact > artifacts, String moduleName)
Definition: Blackboard.java:83
Collection< BlackboardArtifact > getArtifacts()
Collection< BlackboardArtifact > getArtifacts(BlackboardArtifact.Type artifactType)
BlackboardAttribute.Type addArtifactAttributeType(String attrTypeString, TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName)
BlackboardAttribute.Type getOrAddAttributeType(String typeName, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName)
List< BlackboardArtifact > getArtifacts(int artifactTypeID, long dataSourceObjId)
BlackboardAttribute.Type getAttributeType(String attrTypeName)
BlackboardArtifact.Type getArtifactType(String artTypeName)
boolean artifactExists(Content content, BlackboardArtifact.ARTIFACT_TYPE artifactType, Collection< BlackboardAttribute > attributesList)
Collection< BlackboardArtifact.Type > getArtifactTypes()
BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName)
long getArtifactsCount(int artifactTypeID, long dataSourceObjId)
List< BlackboardArtifact.Type > getArtifactTypesInUse(long dataSourceObjId)
BlackboardArtifact.Type addBlackboardArtifactType(String artifactTypeName, String displayName)

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