Autopsy  4.6.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.getOpenCase().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  knownStatus, comment);
197 
198  if (eamArtifact != null) {
199  // send update to Central Repository db
200  try {
201  dbManager.setArtifactInstanceKnownStatus(eamArtifact, knownStatus);
202  } catch (EamDbException ex) {
203  LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS
204  }
205  }
206  } // CONTENT_TAG_ADDED, CONTENT_TAG_DELETED
207  }
208 
209  private final class BlackboardTagTask implements Runnable {
210 
211  private final EamDb dbManager;
212  private final PropertyChangeEvent event;
213 
214  private BlackboardTagTask(EamDb db, PropertyChangeEvent evt) {
215  dbManager = db;
216  event = evt;
217  }
218 
219  @Override
220  public void run() {
221  if (!EamDb.isEnabled()) {
222  return;
223  }
224 
225  Content content;
226  BlackboardArtifact bbArtifact;
227  TskData.FileKnown knownStatus;
228  String comment;
229  if (Case.Events.valueOf(event.getPropertyName()) == Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED) {
230  // For added tags, we want to change the known status to BAD if the
231  // tag that was just added is in the list of central repo tags.
233  final BlackboardArtifactTag tagAdded = tagAddedEvent.getAddedTag();
234 
235  if (TagsManager.getNotableTagDisplayNames().contains(tagAdded.getName().getDisplayName())) {
236  content = tagAdded.getContent();
237  bbArtifact = tagAdded.getArtifact();
238  knownStatus = TskData.FileKnown.BAD;
239  comment = tagAdded.getComment();
240  } else {
241  // The added tag isn't flagged as bad in central repo, so do nothing
242  return;
243  }
244  } else { //BLACKBOARD_ARTIFACT_TAG_DELETED
245  Case openCase;
246  try {
247  openCase = Case.getOpenCase();
248  } catch (NoCurrentCaseException ex) {
249  LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
250  return;
251  }
252  // For deleted tags, we want to set the file status to UNKNOWN if:
253  // - The tag that was just removed is notable in central repo
254  // - There are no remaining tags that are notable
256  long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID();
257  long artifactID = tagDeletedEvent.getDeletedTagInfo().getArtifactID();
258 
259  String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName();
260  if (!TagsManager.getNotableTagDisplayNames().contains(tagName)) {
261  // If the tag that got removed isn't on the list of central repo tags, do nothing
262  return;
263  }
264 
265  try {
266  // Get the remaining tags on the artifact
267  content = openCase.getSleuthkitCase().getContentById(contentID);
268  bbArtifact = openCase.getSleuthkitCase().getBlackboardArtifact(artifactID);
269  TagsManager tagsManager = openCase.getServices().getTagsManager();
270  List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
271 
272  if (tags.stream()
273  .map(tag -> tag.getName().getDisplayName())
274  .filter(TagsManager.getNotableTagDisplayNames()::contains)
275  .collect(Collectors.toList())
276  .isEmpty()) {
277 
278  // There are no more bad tags on the object
279  knownStatus = TskData.FileKnown.UNKNOWN;
280  comment = "";
281 
282  } else {
283  // There's still at least one bad tag, so leave the known status as is
284  return;
285  }
286  } catch (TskCoreException ex) {
287  LOGGER.log(Level.SEVERE, "Failed to find content", ex);
288  return;
289  }
290  }
291 
292  if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) {
293  return;
294  }
295 
296  List<CorrelationAttribute> convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbArtifact, true, true);
297  for (CorrelationAttribute eamArtifact : convertedArtifacts) {
298  eamArtifact.getInstances().get(0).setComment(comment);
299  try {
300  dbManager.setArtifactInstanceKnownStatus(eamArtifact, knownStatus);
301  } catch (EamDbException ex) {
302  LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database while setting artifact known status.", ex); //NON-NLS
303  }
304  }
305  } // BLACKBOARD_ARTIFACT_TAG_ADDED, BLACKBOARD_ARTIFACT_TAG_DELETED
306 
307  }
308 
309  private final class TagDefinitionChangeTask implements Runnable {
310 
311  private final PropertyChangeEvent event;
312 
313  private TagDefinitionChangeTask(PropertyChangeEvent evt) {
314  event = evt;
315  }
316 
317  @Override
318  public void run() {
319  if (!EamDb.isEnabled()) {
320  return;
321  }
322  //get the display name of the tag that has had it's definition modified
323  String modifiedTagName = (String) event.getOldValue();
324 
325  /*
326  * Set knownBad status for all files/artifacts in the given case
327  * that are tagged with the given tag name.
328  */
329  try {
330  TagName tagName = Case.getOpenCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(modifiedTagName);
331  //First update the artifacts
332  //Get all BlackboardArtifactTags with this tag name
333  List<BlackboardArtifactTag> artifactTags = Case.getOpenCase().getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName);
334  for (BlackboardArtifactTag bbTag : artifactTags) {
335  //start with assumption that none of the other tags applied to this Correlation Attribute will prevent it's status from being changed
336  boolean hasTagWithConflictingKnownStatus = false;
337  // if the status of the tag has been changed to TskData.FileKnown.UNKNOWN
338  // we need to check the status of all other tags on this correlation attribute before changing
339  // the status of the correlation attribute in the central repository
340  if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) {
341  Content content = bbTag.getContent();
342  // If the content which this Blackboard Artifact Tag is linked to is an AbstractFile with KNOWN status then
343  // it's status in the central reporsitory should not be changed to UNKNOWN
344  if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) {
345  continue;
346  }
347  //Get the BlackboardArtifact which this BlackboardArtifactTag has been applied to.
348  BlackboardArtifact bbArtifact = bbTag.getArtifact();
350  List<BlackboardArtifactTag> tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
351  //get all tags which are on this blackboard artifact
352  for (BlackboardArtifactTag t : tags) {
353  //All instances of the modified tag name will be changed, they can not conflict with each other
354  if (t.getName().equals(tagName)) {
355  continue;
356  }
357  //if any other tags on this artifact are Notable in status then this artifact can not have its status changed
358  if (TskData.FileKnown.BAD == t.getName().getKnownStatus()) {
359  //a tag with a conflicting status has been found, the status of this correlation attribute can not be modified
360  hasTagWithConflictingKnownStatus = true;
361  break;
362  }
363  }
364  }
365  //if the Correlation Attribute will have no tags with a status which would prevent the current status from being changed
366  if (!hasTagWithConflictingKnownStatus) {
367  //Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed
368  //with the initial set of correlation attributes this should be a single correlation attribute
369  List<CorrelationAttribute> convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbTag.getArtifact(), true, true);
370  for (CorrelationAttribute eamArtifact : convertedArtifacts) {
371  EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
372  }
373  }
374  }
375  // Next update the files
376 
377  List<ContentTag> fileTags = Case.getOpenCase().getSleuthkitCase().getContentTagsByTagName(tagName);
378  //Get all ContentTags with this tag name
379  for (ContentTag contentTag : fileTags) {
380  //start with assumption that none of the other tags applied to this ContentTag will prevent it's status from being changed
381  boolean hasTagWithConflictingKnownStatus = false;
382  // if the status of the tag has been changed to TskData.FileKnown.UNKNOWN
383  // we need to check the status of all other tags on this file before changing
384  // the status of the file in the central repository
385  if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) {
386  Content content = contentTag.getContent();
388  List<ContentTag> tags = tagsManager.getContentTagsByContent(content);
389  //get all tags which are on this file
390  for (ContentTag t : tags) {
391  //All instances of the modified tag name will be changed, they can not conflict with each other
392  if (t.getName().equals(tagName)) {
393  continue;
394  }
395  //if any other tags on this file are Notable in status then this file can not have its status changed
396  if (TskData.FileKnown.BAD == t.getName().getKnownStatus()) {
397  //a tag with a conflicting status has been found, the status of this file can not be modified
398  hasTagWithConflictingKnownStatus = true;
399  break;
400  }
401  }
402  }
403  //if the file will have no tags with a status which would prevent the current status from being changed
404  if (!hasTagWithConflictingKnownStatus) {
405  final CorrelationAttribute eamArtifact = EamArtifactUtil.getCorrelationAttributeFromContent(contentTag.getContent(),
406  tagName.getKnownStatus(), "");
407  if (eamArtifact != null) {
408  EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
409  }
410  }
411  }
412  } catch (TskCoreException ex) {
413  LOGGER.log(Level.SEVERE, "Cannot update known status in central repository for tag: " + modifiedTagName, ex); //NON-NLS
414  } catch (EamDbException ex) {
415  LOGGER.log(Level.SEVERE, "Cannot get central repository for tag: " + modifiedTagName, ex); //NON-NLS
416  } catch (NoCurrentCaseException ex) {
417  LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
418  }
419  } //TAG_STATUS_CHANGED
420  }
421 
422  private final class DataSourceAddedTask implements Runnable {
423 
424  private final EamDb dbManager;
425  private final PropertyChangeEvent event;
426 
427  private DataSourceAddedTask(EamDb db, PropertyChangeEvent evt) {
428  dbManager = db;
429  event = evt;
430  }
431 
432  @Override
433  public void run() {
434  if (!EamDb.isEnabled()) {
435  return;
436  }
437  Case openCase;
438  try {
439  openCase = Case.getOpenCase();
440  } catch (NoCurrentCaseException ex) {
441  LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex);
442  return;
443  }
444 
445  final DataSourceAddedEvent dataSourceAddedEvent = (DataSourceAddedEvent) event;
446  Content newDataSource = dataSourceAddedEvent.getDataSource();
447 
448  try {
449  String deviceId = openCase.getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId();
450  CorrelationCase correlationCase = dbManager.getCase(openCase);
451  if (null == correlationCase) {
452  correlationCase = dbManager.newCase(openCase);
453  }
454  if (null == dbManager.getDataSource(correlationCase, deviceId)) {
455  dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource));
456  }
457  } catch (EamDbException ex) {
458  LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
459  } catch (TskCoreException | TskDataException ex) {
460  LOGGER.log(Level.SEVERE, "Error getting data source from DATA_SOURCE_ADDED event content.", ex); //NON-NLS
461  }
462  } // DATA_SOURCE_ADDED
463  }
464 
465  private final class CurrentCaseTask implements Runnable {
466 
467  private final EamDb dbManager;
468  private final PropertyChangeEvent event;
469 
470  private CurrentCaseTask(EamDb db, PropertyChangeEvent evt) {
471  dbManager = db;
472  event = evt;
473  }
474 
475  @Override
476  public void run() {
477  /*
478  * A case has been opened if evt.getOldValue() is null and
479  * evt.getNewValue() is a valid Case.
480  */
481  if ((null == event.getOldValue()) && (event.getNewValue() instanceof Case)) {
482  Case curCase = (Case) event.getNewValue();
483  IngestEventsListener.resetCeModuleInstanceCount();
484 
485  if (!EamDb.isEnabled()) {
486  return;
487  }
488 
489  try {
490  // NOTE: Cannot determine if the opened case is a new case or a reopened case,
491  // so check for existing name in DB and insert if missing.
492  if (dbManager.getCase(curCase) == null) {
493  dbManager.newCase(curCase);
494  }
495  } catch (EamDbException ex) {
496  LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
497  }
498  }
499  } // CURRENT_CASE
500  }
501 }
CorrelationDataSource getDataSource(CorrelationCase correlationCase, String dataSourceDeviceId)
static CorrelationAttribute getCorrelationAttributeFromContent(Content content, TskData.FileKnown knownStatus, String comment)
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)
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 May 7 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.