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

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