Autopsy  4.5.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
IngestModule.java
Go to the documentation of this file.
1 /*
2  * Central Repository
3  *
4  * Copyright 2011-2017 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.ingestmodule;
20 
23 import java.util.List;
24 import java.util.logging.Level;
25 import java.util.stream.Collectors;
26 import org.openide.util.NbBundle.Messages;
44 import org.sleuthkit.datamodel.AbstractFile;
45 import org.sleuthkit.datamodel.BlackboardArtifact;
46 import org.sleuthkit.datamodel.BlackboardAttribute;
47 import org.sleuthkit.datamodel.HashUtility;
48 import org.sleuthkit.datamodel.TskCoreException;
49 import org.sleuthkit.datamodel.TskData;
51 
56 @Messages({"IngestModule.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)",
57  "IngestModule.prevCaseComment.text=Previous Case: "})
58 class IngestModule implements FileIngestModule {
59 
60  private final static Logger LOGGER = Logger.getLogger(IngestModule.class.getName());
61  private final IngestServices services = IngestServices.getInstance();
62  private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
63  private static final IngestModuleReferenceCounter warningMsgRefCounter = new IngestModuleReferenceCounter();
64  private long jobId;
65  private CorrelationCase eamCase;
66  private CorrelationDataSource eamDataSource;
67  private Blackboard blackboard;
68  private CorrelationAttribute.Type filesType;
69 
70  @Override
71  public ProcessResult process(AbstractFile af) {
72  if (EamDb.isEnabled() == false) {
73  /*
74  * Not signaling an error for now. This is a workaround for the way
75  * all newly didscovered ingest modules are automatically anabled.
76  *
77  * TODO (JIRA-2731): Add isEnabled API for ingest modules.
78  */
79  return ProcessResult.OK;
80  }
81 
82  blackboard = Case.getCurrentCase().getServices().getBlackboard();
83 
85  return ProcessResult.OK;
86  }
87 
88  EamDb dbManager;
89  try {
90  dbManager = EamDb.getInstance();
91  } catch (EamDbException ex) {
92  LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex);
93  return ProcessResult.ERROR;
94  }
95 
96  // only continue if we are correlating filesType
97  if (!filesType.isEnabled()) {
98  return ProcessResult.OK;
99  }
100 
101  // get the hash because we're going to correlate it
102  String md5 = af.getMd5Hash();
103  if ((md5 == null) || (HashUtility.isNoDataMd5(md5))) {
104  return ProcessResult.OK;
105  }
106 
107  /* Search the central repo to see if this file was previously
108  * marked as being bad. Create artifact if it was. */
109  if (af.getKnown() != TskData.FileKnown.KNOWN) {
110  try {
111  List<String> caseDisplayNames = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5);
112  if (!caseDisplayNames.isEmpty()) {
113  postCorrelatedBadFileToBlackboard(af, caseDisplayNames);
114  }
115  } catch (EamDbException ex) {
116  LOGGER.log(Level.SEVERE, "Error searching database for artifact.", ex); // NON-NLS
117  return ProcessResult.ERROR;
118  }
119  }
120 
121  // insert this file into the central repository
122  try {
123  CorrelationAttribute eamArtifact = new CorrelationAttribute(filesType, md5);
125  eamCase,
126  eamDataSource,
127  af.getParentPath() + af.getName(),
128  null,
129  TskData.FileKnown.UNKNOWN // NOTE: Known status in the CR is based on tagging, not hashes like the Case Database.
130  );
131  eamArtifact.addInstance(cefi);
132  dbManager.prepareBulkArtifact(eamArtifact);
133  } catch (EamDbException ex) {
134  LOGGER.log(Level.SEVERE, "Error adding artifact to bulk artifacts.", ex); // NON-NLS
135  return ProcessResult.ERROR;
136  }
137 
138  return ProcessResult.OK;
139  }
140 
141  @Override
142  public void shutDown() {
144  if ((EamDb.isEnabled() == false) || (eamCase == null) || (eamDataSource == null)) {
145  return;
146  }
147  EamDb dbManager;
148  try {
149  dbManager = EamDb.getInstance();
150  } catch (EamDbException ex) {
151  LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex);
152  return;
153  }
154  try {
155  dbManager.bulkInsertArtifacts();
156  } catch (EamDbException ex) {
157  LOGGER.log(Level.SEVERE, "Error doing bulk insert of artifacts.", ex); // NON-NLS
158  }
159  try {
160  Long count = dbManager.getCountArtifactInstancesByCaseDataSource(eamCase.getCaseUUID(), eamDataSource.getDeviceID());
161  LOGGER.log(Level.INFO, "{0} artifacts in db for case: {1} ds:{2}", new Object[]{count, eamCase.getDisplayName(), eamDataSource.getName()}); // NON-NLS
162  } catch (EamDbException ex) {
163  LOGGER.log(Level.SEVERE, "Error counting artifacts.", ex); // NON-NLS
164  }
165 
166  // TODO: once we implement shared cache, if refCounter is 1, then submit data in bulk.
167  refCounter.decrementAndGet(jobId);
168  }
169 
170  // see ArtifactManagerTimeTester for details
171  @Messages({
172  "IngestModule.notfyBubble.title=Central Repository Not Initialized",
173  "IngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Correlation Engine ingest module."
174  })
175  @Override
176  public void startUp(IngestJobContext context) throws IngestModuleException {
178  if (EamDb.isEnabled() == false) {
179  /*
180  * Not throwing the customary exception for now. This is a
181  * workaround for the way all newly didscovered ingest modules are
182  * automatically anabled.
183  *
184  * TODO (JIRA-2731): Add isEnabled API for ingest modules.
185  */
187  if (1L == warningMsgRefCounter.incrementAndGet(jobId)) {
188  MessageNotifyUtil.Notify.warn(Bundle.IngestModule_notfyBubble_title(), Bundle.IngestModule_errorMessage_isNotEnabled());
189  }
190  }
191  return;
192  }
193  // Don't allow sqlite central repo databases to be used for multi user cases
196  LOGGER.log(Level.SEVERE, "Cannot run correlation engine on a multi-user case with a SQLite central repository.");
197  throw new IngestModuleException("Cannot run on a multi-user case with a SQLite central repository."); // NON-NLS
198  }
199  jobId = context.getJobId();
200 
201  EamDb centralRepoDb;
202  try {
203  centralRepoDb = EamDb.getInstance();
204  } catch (EamDbException ex) {
205  LOGGER.log(Level.SEVERE, "Error connecting to central repository database.", ex); // NON-NLS
206  throw new IngestModuleException("Error connecting to central repository database.", ex); // NON-NLS
207  }
208 
209  try {
210  filesType = centralRepoDb.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID);
211  } catch (EamDbException ex) {
212  LOGGER.log(Level.SEVERE, "Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS
213  throw new IngestModuleException("Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS
214  }
215  Case autopsyCase = Case.getCurrentCase();
216  try {
217  eamCase = centralRepoDb.getCase(autopsyCase);
218  } catch (EamDbException ex) {
219  throw new IngestModuleException("Unable to get case from central repository database ", ex);
220  }
221  if (eamCase == null) {
222  // ensure we have this case defined in the EAM DB
223  try {
224  eamCase = centralRepoDb.newCase(autopsyCase);
225  } catch (EamDbException ex) {
226  LOGGER.log(Level.SEVERE, "Error creating new case in ingest module start up.", ex); // NON-NLS
227  throw new IngestModuleException("Error creating new case in ingest module start up.", ex); // NON-NLS
228  }
229  }
230 
231  try {
232  eamDataSource = CorrelationDataSource.fromTSKDataSource(eamCase, context.getDataSource());
233  } catch (EamDbException ex) {
234  LOGGER.log(Level.SEVERE, "Error getting data source info.", ex); // NON-NLS
235  throw new IngestModuleException("Error getting data source info.", ex); // NON-NLS
236  }
237  // TODO: once we implement a shared cache, load/init it here w/ syncronized and define reference counter
238  // if we are the first thread / module for this job, then make sure the case
239  // and image exist in the DB before we associate artifacts with it.
240  if (refCounter.incrementAndGet(jobId)
241  == 1) {
242  // ensure we have this data source in the EAM DB
243  try {
244  if (null == centralRepoDb.getDataSource(eamCase, eamDataSource.getDeviceID())) {
245  centralRepoDb.newDataSource(eamDataSource);
246  }
247  } catch (EamDbException ex) {
248  LOGGER.log(Level.SEVERE, "Error adding data source to Central Repository.", ex); // NON-NLS
249  throw new IngestModuleException("Error adding data source to Central Repository.", ex); // NON-NLS
250  }
251 
252  }
253  }
254 
255  private void postCorrelatedBadFileToBlackboard(AbstractFile abstractFile, List<String> caseDisplayNames) {
256 
257  try {
258  String MODULE_NAME = IngestModuleFactory.getModuleName();
259  BlackboardArtifact tifArtifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
260  BlackboardAttribute att = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME,
261  Bundle.IngestModule_prevTaggedSet_text());
262  BlackboardAttribute att2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME,
263  Bundle.IngestModule_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(",", "", "")));
264  tifArtifact.addAttribute(att);
265  tifArtifact.addAttribute(att2);
266 
267  try {
268  // index the artifact for keyword search
269  blackboard.indexArtifact(tifArtifact);
270  } catch (Blackboard.BlackboardException ex) {
271  LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS
272  }
273 
274  // send inbox message
275  sendBadFileInboxMessage(tifArtifact, abstractFile.getName(), abstractFile.getMd5Hash());
276 
277  // fire event to notify UI of this new artifact
278  services.fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT));
279  } catch (TskCoreException ex) {
280  LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS
281  } catch (IllegalStateException ex) {
282  LOGGER.log(Level.SEVERE, "Failed to create BlackboardAttribute.", ex); // NON-NLS
283  }
284  }
285 
294  @Messages({"IngestModule.postToBB.fileName=File Name",
295  "IngestModule.postToBB.md5Hash=MD5 Hash",
296  "IngestModule.postToBB.hashSetSource=Source of Hash",
297  "IngestModule.postToBB.eamHit=Central Repository",
298  "# {0} - Name of file that is Notable",
299  "IngestModule.postToBB.knownBadMsg=Notable: {0}"})
300  public void sendBadFileInboxMessage(BlackboardArtifact artifact, String name, String md5Hash) {
301  StringBuilder detailsSb = new StringBuilder();
302  //details
303  detailsSb.append("<table border='0' cellpadding='4' width='280'>"); //NON-NLS
304  //hit
305  detailsSb.append("<tr>"); //NON-NLS
306  detailsSb.append("<th>") //NON-NLS
307  .append(Bundle.IngestModule_postToBB_fileName())
308  .append("</th>"); //NON-NLS
309  detailsSb.append("<td>") //NON-NLS
310  .append(name)
311  .append("</td>"); //NON-NLS
312  detailsSb.append("</tr>"); //NON-NLS
313 
314  detailsSb.append("<tr>"); //NON-NLS
315  detailsSb.append("<th>") //NON-NLS
316  .append(Bundle.IngestModule_postToBB_md5Hash())
317  .append("</th>"); //NON-NLS
318  detailsSb.append("<td>").append(md5Hash).append("</td>"); //NON-NLS
319  detailsSb.append("</tr>"); //NON-NLS
320 
321  detailsSb.append("<tr>"); //NON-NLS
322  detailsSb.append("<th>") //NON-NLS
323  .append(Bundle.IngestModule_postToBB_hashSetSource())
324  .append("</th>"); //NON-NLS
325  detailsSb.append("<td>").append(Bundle.IngestModule_postToBB_eamHit()).append("</td>"); //NON-NLS
326  detailsSb.append("</tr>"); //NON-NLS
327 
328  detailsSb.append("</table>"); //NON-NLS
329 
331  Bundle.IngestModule_postToBB_knownBadMsg(name),
332  detailsSb.toString(),
333  name + md5Hash,
334  artifact));
335  }
336 }
CorrelationDataSource getDataSource(CorrelationCase correlationCase, String dataSourceDeviceId)
CorrelationAttribute.Type getCorrelationTypeById(int typeId)
static IngestMessage createDataMessage(String source, String subject, String detailsHtml, String uniqueKey, BlackboardArtifact data)
void prepareBulkArtifact(CorrelationAttribute eamArtifact)
CorrelationCase newCase(CorrelationCase eamCase)
static CorrelationDataSource fromTSKDataSource(CorrelationCase correlationCase, Content dataSource)
List< String > getListCasesHavingArtifactInstancesKnownBad(CorrelationAttribute.Type aType, String value)
void addInstance(CorrelationAttributeInstance artifactInstance)
void postMessage(final IngestMessage message)
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
Long getCountArtifactInstancesByCaseDataSource(String caseUUID, String dataSourceID)
synchronized void indexArtifact(BlackboardArtifact artifact)
Definition: Blackboard.java:59
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void warn(String title, String message)
void newDataSource(CorrelationDataSource eamDataSource)
static synchronized IngestServices getInstance()

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