Autopsy  4.9.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
CaseEventListener.java
Go to the documentation of this file.
1 /*
2  * Central Repository
3  *
4  * Copyright 2015-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.autopsy.centralrepository.eventlisteners;
20 
21 import com.google.common.util.concurrent.ThreadFactoryBuilder;
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import java.util.List;
25 import java.util.concurrent.ExecutorService;
26 import java.util.concurrent.Executors;
27 import java.util.logging.Level;
28 import java.util.stream.Collectors;
29 import org.openide.util.NbBundle.Messages;
46 import org.sleuthkit.datamodel.AbstractFile;
47 import org.sleuthkit.datamodel.BlackboardArtifact;
48 import org.sleuthkit.datamodel.BlackboardArtifactTag;
49 import org.sleuthkit.datamodel.Content;
50 import org.sleuthkit.datamodel.ContentTag;
51 import org.sleuthkit.datamodel.TagName;
52 import org.sleuthkit.datamodel.TskCoreException;
53 import org.sleuthkit.datamodel.TskData;
54 import org.sleuthkit.datamodel.TskDataException;
55 
60 @Messages({"caseeventlistener.evidencetag=Evidence"})
61 final class CaseEventListener implements PropertyChangeListener {
62 
63  private static final Logger LOGGER = Logger.getLogger(CaseEventListener.class.getName());
64  private final ExecutorService jobProcessingExecutor;
65  private static final String CASE_EVENT_THREAD_NAME = "Case-Event-Listener-%d";
66 
67  CaseEventListener() {
68  jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(CASE_EVENT_THREAD_NAME).build());
69  }
70 
71  void shutdown() {
72  ThreadUtils.shutDownTaskExecutor(jobProcessingExecutor);
73  }
74 
75  @Override
76  public void propertyChange(PropertyChangeEvent evt) {
77  EamDb dbManager;
78  try {
79  dbManager = EamDb.getInstance();
80  } catch (EamDbException ex) {
81  LOGGER.log(Level.SEVERE, "Failed to get instance of db manager.", ex);
82  return;
83  }
84  switch (Case.Events.valueOf(evt.getPropertyName())) {
85  case CONTENT_TAG_ADDED:
86  case CONTENT_TAG_DELETED: {
87  jobProcessingExecutor.submit(new ContentTagTask(dbManager, evt));
88  }
89  break;
90 
91  case BLACKBOARD_ARTIFACT_TAG_DELETED:
92  case BLACKBOARD_ARTIFACT_TAG_ADDED: {
93  jobProcessingExecutor.submit(new BlackboardTagTask(dbManager, evt));
94  }
95  break;
96 
97  case DATA_SOURCE_ADDED: {
98  jobProcessingExecutor.submit(new DataSourceAddedTask(dbManager, evt));
99  }
100  break;
101  case TAG_DEFINITION_CHANGED: {
102  jobProcessingExecutor.submit(new TagDefinitionChangeTask(evt));
103  }
104  break;
105  case CURRENT_CASE: {
106  jobProcessingExecutor.submit(new CurrentCaseTask(dbManager, evt));
107  }
108  break;
109  }
110  }
111 
112  private final class ContentTagTask implements Runnable {
113 
114  private final EamDb dbManager;
115  private final PropertyChangeEvent event;
116 
117  private ContentTagTask(EamDb db, PropertyChangeEvent evt) {
118  dbManager = db;
119  event = evt;
120  }
121 
122  @Override
123  public void run() {
124  if (!EamDb.isEnabled()) {
125  return;
126  }
127 
128  AbstractFile af;
129  TskData.FileKnown knownStatus;
130  String comment;
131  if (Case.Events.valueOf(event.getPropertyName()) == Case.Events.CONTENT_TAG_ADDED) {
132  // For added tags, we want to change the known status to BAD if the
133  // tag that was just added is in the list of central repo tags.
134  final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) event;
135  final ContentTag tagAdded = tagAddedEvent.getAddedTag();
136 
137  if (TagsManager.getNotableTagDisplayNames().contains(tagAdded.getName().getDisplayName())) {
138  if (tagAdded.getContent() instanceof AbstractFile) {
139  af = (AbstractFile) tagAdded.getContent();
140  knownStatus = TskData.FileKnown.BAD;
141  comment = tagAdded.getComment();
142  } else {
143  LOGGER.log(Level.WARNING, "Error updating non-file object");
144  return;
145  }
146  } else {
147  // The added tag isn't flagged as bad in central repo, so do nothing
148  return;
149  }
150  } else { // CONTENT_TAG_DELETED
151  // For deleted tags, we want to set the file status to UNKNOWN if:
152  // - The tag that was just removed is notable in central repo
153  // - There are no remaining tags that are notable
154  final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) event;
155  long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID();
156 
157  String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName();
158  if (!TagsManager.getNotableTagDisplayNames().contains(tagName)) {
159  // If the tag that got removed isn't on the list of central repo tags, do nothing
160  return;
161  }
162 
163  try {
164  // Get the remaining tags on the content object
165  Content content = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(contentID);
167  List<ContentTag> tags = tagsManager.getContentTagsByContent(content);
168 
169  if (tags.stream()
170  .map(tag -> tag.getName().getDisplayName())
171  .filter(TagsManager.getNotableTagDisplayNames()::contains)
172  .collect(Collectors.toList())
173  .isEmpty()) {
174 
175  // There are no more bad tags on the object
176  if (content instanceof AbstractFile) {
177  af = (AbstractFile) content;
178  knownStatus = TskData.FileKnown.UNKNOWN;
179  comment = "";
180  } else {
181  LOGGER.log(Level.WARNING, "Error updating non-file object");
182  return;
183  }
184  } else {
185  // There's still at least one bad tag, so leave the known status as is
186  return;
187  }
188  } catch (TskCoreException | NoCurrentCaseException ex) {
189  LOGGER.log(Level.SEVERE, "Failed to find content", ex);
190  return;
191  }
192  }
193 
195 
196  if (eamArtifact != null) {
197  // send update to Central Repository db
198  try {
199  dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus);
200  } catch (EamDbException ex) {
201  LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS
202  }
203  }
204  } // CONTENT_TAG_ADDED, CONTENT_TAG_DELETED
205  }
206 
207  private final class BlackboardTagTask implements Runnable {
208 
209  private final EamDb dbManager;
210  private final PropertyChangeEvent event;
211 
212  private BlackboardTagTask(EamDb db, PropertyChangeEvent evt) {
213  dbManager = db;
214  event = evt;
215  }
216 
217  @Override
218  public void run() {
219  if (!EamDb.isEnabled()) {
220  return;
221  }
222 
223  Content content;
224  BlackboardArtifact bbArtifact;
225  TskData.FileKnown knownStatus;
226  String comment;
227  if (Case.Events.valueOf(event.getPropertyName()) == Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED) {
228  // For added tags, we want to change the known status to BAD if the
229  // tag that was just added is in the list of central repo tags.
231  final BlackboardArtifactTag tagAdded = tagAddedEvent.getAddedTag();
232 
233  if (TagsManager.getNotableTagDisplayNames().contains(tagAdded.getName().getDisplayName())) {
234  content = tagAdded.getContent();
235  bbArtifact = tagAdded.getArtifact();
236  knownStatus = TskData.FileKnown.BAD;
237  comment = tagAdded.getComment();
238  } else {
239  // The added tag isn't flagged as bad in central repo, so do nothing
240  return;
241  }
242  } else { //BLACKBOARD_ARTIFACT_TAG_DELETED
243  Case openCase;
244  try {
245  openCase = Case.getCurrentCaseThrows();
246  } catch (NoCurrentCaseException ex) {
247  LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
248  return;
249  }
250  // For deleted tags, we want to set the file status to UNKNOWN if:
251  // - The tag that was just removed is notable in central repo
252  // - There are no remaining tags that are notable
254  long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID();
255  long artifactID = tagDeletedEvent.getDeletedTagInfo().getArtifactID();
256 
257  String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName();
258  if (!TagsManager.getNotableTagDisplayNames().contains(tagName)) {
259  // If the tag that got removed isn't on the list of central repo tags, do nothing
260  return;
261  }
262 
263  try {
264  // Get the remaining tags on the artifact
265  content = openCase.getSleuthkitCase().getContentById(contentID);
266  bbArtifact = openCase.getSleuthkitCase().getBlackboardArtifact(artifactID);
267  TagsManager tagsManager = openCase.getServices().getTagsManager();
268  List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
269 
270  if (tags.stream()
271  .map(tag -> tag.getName().getDisplayName())
272  .filter(TagsManager.getNotableTagDisplayNames()::contains)
273  .collect(Collectors.toList())
274  .isEmpty()) {
275 
276  // There are no more bad tags on the object
277  knownStatus = TskData.FileKnown.UNKNOWN;
278  comment = "";
279 
280  } else {
281  // There's still at least one bad tag, so leave the known status as is
282  return;
283  }
284  } catch (TskCoreException ex) {
285  LOGGER.log(Level.SEVERE, "Failed to find content", ex);
286  return;
287  }
288  }
289 
290  if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) {
291  return;
292  }
293 
294  List<CorrelationAttributeInstance> convertedArtifacts = EamArtifactUtil.makeInstancesFromBlackboardArtifact(bbArtifact, true);
295  for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
296  eamArtifact.setComment(comment);
297  try {
298  dbManager.setAttributeInstanceKnownStatus(eamArtifact, knownStatus);
299  } catch (EamDbException ex) {
300  LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS
301  }
302  }
303  } // BLACKBOARD_ARTIFACT_TAG_ADDED, BLACKBOARD_ARTIFACT_TAG_DELETED
304 
305  }
306 
307  private final class TagDefinitionChangeTask implements Runnable {
308 
309  private final PropertyChangeEvent event;
310 
311  private TagDefinitionChangeTask(PropertyChangeEvent evt) {
312  event = evt;
313  }
314 
315  @Override
316  public void run() {
317  if (!EamDb.isEnabled()) {
318  return;
319  }
320  //get the display name of the tag that has had it's definition modified
321  String modifiedTagName = (String) event.getOldValue();
322 
323  /*
324  * Set knownBad status for all files/artifacts in the given case
325  * that are tagged with the given tag name.
326  */
327  try {
328  TagName tagName = Case.getCurrentCaseThrows().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(modifiedTagName);
329  //First update the artifacts
330  //Get all BlackboardArtifactTags with this tag name
331  List<BlackboardArtifactTag> artifactTags = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName);
332  for (BlackboardArtifactTag bbTag : artifactTags) {
333  //start with assumption that none of the other tags applied to this Correlation Attribute will prevent it's status from being changed
334  boolean hasTagWithConflictingKnownStatus = false;
335  // if the status of the tag has been changed to TskData.FileKnown.UNKNOWN
336  // we need to check the status of all other tags on this correlation attribute before changing
337  // the status of the correlation attribute in the central repository
338  if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) {
339  Content content = bbTag.getContent();
340  // If the content which this Blackboard Artifact Tag is linked to is an AbstractFile with KNOWN status then
341  // it's status in the central reporsitory should not be changed to UNKNOWN
342  if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) {
343  continue;
344  }
345  //Get the BlackboardArtifact which this BlackboardArtifactTag has been applied to.
346  BlackboardArtifact bbArtifact = bbTag.getArtifact();
348  List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
349  //get all tags which are on this blackboard artifact
350  for (BlackboardArtifactTag t : tags) {
351  //All instances of the modified tag name will be changed, they can not conflict with each other
352  if (t.getName().equals(tagName)) {
353  continue;
354  }
355  //if any other tags on this artifact are Notable in status then this artifact can not have its status changed
356  if (TskData.FileKnown.BAD == t.getName().getKnownStatus()) {
357  //a tag with a conflicting status has been found, the status of this correlation attribute can not be modified
358  hasTagWithConflictingKnownStatus = true;
359  break;
360  }
361  }
362  }
363  //if the Correlation Attribute will have no tags with a status which would prevent the current status from being changed
364  if (!hasTagWithConflictingKnownStatus) {
365  //Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed
366  //with the initial set of correlation attributes this should be a single correlation attribute
367  List<CorrelationAttributeInstance> convertedArtifacts = EamArtifactUtil.makeInstancesFromBlackboardArtifact(bbTag.getArtifact(), true);
368  for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
369  EamDb.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
370  }
371  }
372  }
373  // Next update the files
374 
375  List<ContentTag> fileTags = Case.getCurrentCaseThrows().getSleuthkitCase().getContentTagsByTagName(tagName);
376  //Get all ContentTags with this tag name
377  for (ContentTag contentTag : fileTags) {
378  //start with assumption that none of the other tags applied to this ContentTag will prevent it's status from being changed
379  boolean hasTagWithConflictingKnownStatus = false;
380  // if the status of the tag has been changed to TskData.FileKnown.UNKNOWN
381  // we need to check the status of all other tags on this file before changing
382  // the status of the file in the central repository
383  if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) {
384  Content content = contentTag.getContent();
386  List<ContentTag> tags = tagsManager.getContentTagsByContent(content);
387  //get all tags which are on this file
388  for (ContentTag t : tags) {
389  //All instances of the modified tag name will be changed, they can not conflict with each other
390  if (t.getName().equals(tagName)) {
391  continue;
392  }
393  //if any other tags on this file are Notable in status then this file can not have its status changed
394  if (TskData.FileKnown.BAD == t.getName().getKnownStatus()) {
395  //a tag with a conflicting status has been found, the status of this file can not be modified
396  hasTagWithConflictingKnownStatus = true;
397  break;
398  }
399  }
400  }
401  //if the file will have no tags with a status which would prevent the current status from being changed
402  if (!hasTagWithConflictingKnownStatus) {
403  final CorrelationAttributeInstance eamArtifact = EamArtifactUtil.makeInstanceFromContent(contentTag.getContent());
404  if (eamArtifact != null) {
406  }
407  }
408  }
409  } catch (TskCoreException ex) {
410  LOGGER.log(Level.SEVERE, "Cannot update known status in central repository for tag: " + modifiedTagName, ex); //NON-NLS
411  } catch (EamDbException ex) {
412  LOGGER.log(Level.SEVERE, "Cannot get central repository for tag: " + modifiedTagName, ex); //NON-NLS
413  } catch (NoCurrentCaseException ex) {
414  LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
415  }
416  } //TAG_STATUS_CHANGED
417  }
418 
419  private final class DataSourceAddedTask implements Runnable {
420 
421  private final EamDb dbManager;
422  private final PropertyChangeEvent event;
423 
424  private DataSourceAddedTask(EamDb db, PropertyChangeEvent evt) {
425  dbManager = db;
426  event = evt;
427  }
428 
429  @Override
430  public void run() {
431  if (!EamDb.isEnabled()) {
432  return;
433  }
434  Case openCase;
435  try {
436  openCase = Case.getCurrentCaseThrows();
437  } catch (NoCurrentCaseException ex) {
438  LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
439  return;
440  }
441 
442  final DataSourceAddedEvent dataSourceAddedEvent = (DataSourceAddedEvent) event;
443  Content newDataSource = dataSourceAddedEvent.getDataSource();
444 
445  try {
446  CorrelationCase correlationCase = dbManager.getCase(openCase);
447  if (null == correlationCase) {
448  correlationCase = dbManager.newCase(openCase);
449  }
450  if (null == dbManager.getDataSource(correlationCase, newDataSource.getId())) {
451  CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource);
452  }
453  } catch (EamDbException ex) {
454  LOGGER.log(Level.SEVERE, "Error adding new data source to the central repository", ex); //NON-NLS
455  }
456  } // DATA_SOURCE_ADDED
457  }
458 
459  private final class CurrentCaseTask implements Runnable {
460 
461  private final EamDb dbManager;
462  private final PropertyChangeEvent event;
463 
464  private CurrentCaseTask(EamDb db, PropertyChangeEvent evt) {
465  dbManager = db;
466  event = evt;
467  }
468 
469  @Override
470  public void run() {
471  /*
472  * A case has been opened if evt.getOldValue() is null and
473  * evt.getNewValue() is a valid Case.
474  */
475  if ((null == event.getOldValue()) && (event.getNewValue() instanceof Case)) {
476  Case curCase = (Case) event.getNewValue();
477  IngestEventsListener.resetCeModuleInstanceCount();
478 
479  if (!EamDb.isEnabled()) {
480  return;
481  }
482 
483  try {
484  // NOTE: Cannot determine if the opened case is a new case or a reopened case,
485  // so check for existing name in DB and insert if missing.
486  if (dbManager.getCase(curCase) == null) {
487  dbManager.newCase(curCase);
488  }
489  } catch (EamDbException ex) {
490  LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
491  }
492  }
493  } // CURRENT_CASE
494  }
495 }
static List< CorrelationAttributeInstance > makeInstancesFromBlackboardArtifact(BlackboardArtifact artifact, boolean checkEnabled)
CorrelationCase newCase(CorrelationCase eamCase)
static CorrelationDataSource fromTSKDataSource(CorrelationCase correlationCase, Content dataSource)
List< ContentTag > getContentTagsByContent(Content content)
static void shutDownTaskExecutor(ExecutorService executor)
CorrelationDataSource getDataSource(CorrelationCase correlationCase, Long caseDbDataSourceId)
void setAttributeInstanceKnownStatus(CorrelationAttributeInstance eamArtifact, TskData.FileKnown knownStatus)
static CorrelationAttributeInstance makeInstanceFromContent(Content content)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
List< BlackboardArtifactTag > getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact)

Copyright © 2012-2018 Basis Technology. Generated on: Tue Dec 18 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.