19 package org.sleuthkit.autopsy.centralrepository.ingestmodule;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.List;
24 import java.util.logging.Level;
25 import java.util.stream.Collectors;
26 import org.openide.util.NbBundle.Messages;
51 import static org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_PREVIOUSLY_NOTABLE;
53 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME;
54 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_TYPE;
55 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CORRELATION_VALUE;
56 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_OTHER_CASES;
67 @Messages({
"CentralRepoIngestModule.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)",
68 "CentralRepoIngestModule.prevCaseComment.text=Previous Case: "})
69 final class CentralRepoIngestModule implements FileIngestModule {
71 private static final String MODULE_NAME = CentralRepoIngestModuleFactory.getModuleName();
72 static final boolean DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS =
false;
73 static final boolean DEFAULT_FLAG_PREVIOUS_DEVICES =
false;
74 static final boolean DEFAULT_FLAG_UNIQUE_DEVICES =
false;
75 static final boolean DEFAULT_CREATE_CR_PROPERTIES =
true;
77 private final static Logger logger = Logger.getLogger(CentralRepoIngestModule.class.getName());
78 private final IngestServices services = IngestServices.getInstance();
79 private static final IngestModuleReferenceCounter refCounter =
new IngestModuleReferenceCounter();
80 private static final IngestModuleReferenceCounter warningMsgRefCounter =
new IngestModuleReferenceCounter();
82 private CorrelationCase eamCase;
83 private CorrelationDataSource eamDataSource;
84 private CorrelationAttributeInstance.Type filesType;
85 private final boolean flagTaggedNotableItems;
86 private final boolean flagPreviouslySeenDevices;
87 private Blackboard blackboard;
88 private final boolean createCorrelationProperties;
89 private final boolean flagUniqueArtifacts;
96 CentralRepoIngestModule(IngestSettings settings) {
97 flagTaggedNotableItems = settings.isFlagTaggedNotableItems();
98 flagPreviouslySeenDevices = settings.isFlagPreviousDevices();
99 createCorrelationProperties = settings.shouldCreateCorrelationProperties();
100 flagUniqueArtifacts = settings.isFlagUniqueArtifacts();
104 public ProcessResult process(AbstractFile abstractFile) {
105 if (CentralRepository.isEnabled() ==
false) {
112 return ProcessResult.OK;
116 blackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard();
117 }
catch (NoCurrentCaseException ex) {
118 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
119 return ProcessResult.ERROR;
122 if (!CorrelationAttributeUtil.isSupportedAbstractFileType(abstractFile)) {
123 return ProcessResult.OK;
126 if (abstractFile.getKnown() == TskData.FileKnown.KNOWN) {
127 return ProcessResult.OK;
130 CentralRepository dbManager;
132 dbManager = CentralRepository.getInstance();
133 }
catch (CentralRepoException ex) {
134 logger.log(Level.SEVERE,
"Error connecting to Central Repository database.", ex);
135 return ProcessResult.ERROR;
139 if (!filesType.isEnabled()) {
140 return ProcessResult.OK;
144 String md5 = abstractFile.getMd5Hash();
145 if ((md5 == null) || (HashUtility.isNoDataMd5(md5))) {
146 return ProcessResult.OK;
153 if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) {
155 TimingMetric timingMetric = HealthMonitor.getTimingMetric(
"Central Repository: Notable artifact query");
156 List<String> caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5);
157 HealthMonitor.submitTimingMetric(timingMetric);
158 if (!caseDisplayNamesList.isEmpty()) {
159 postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList, filesType, md5);
161 }
catch (CentralRepoException ex) {
162 logger.log(Level.SEVERE,
"Error searching database for artifact.", ex);
163 return ProcessResult.ERROR;
164 }
catch (CorrelationAttributeNormalizationException ex) {
165 logger.log(Level.INFO,
"Error searching database for artifact.", ex);
166 return ProcessResult.ERROR;
171 if (createCorrelationProperties) {
173 CorrelationAttributeInstance cefi =
new CorrelationAttributeInstance(
178 abstractFile.getParentPath() + abstractFile.getName(),
180 TskData.FileKnown.UNKNOWN
182 abstractFile.getId());
183 dbManager.addAttributeInstanceBulk(cefi);
184 }
catch (CentralRepoException ex) {
185 logger.log(Level.SEVERE,
"Error adding artifact to bulk artifacts.", ex);
186 return ProcessResult.ERROR;
187 }
catch (CorrelationAttributeNormalizationException ex) {
188 logger.log(Level.INFO,
"Error adding artifact to bulk artifacts.", ex);
189 return ProcessResult.ERROR;
192 return ProcessResult.OK;
196 public void shutDown() {
197 IngestEventsListener.decrementCorrelationEngineModuleCount();
199 if ((CentralRepository.isEnabled() ==
false) || (eamCase == null) || (eamDataSource == null)) {
202 CentralRepository dbManager;
204 dbManager = CentralRepository.getInstance();
205 }
catch (CentralRepoException ex) {
206 logger.log(Level.SEVERE,
"Error connecting to Central Repository database.", ex);
210 dbManager.commitAttributeInstancesBulk();
211 }
catch (CentralRepoException ex) {
212 logger.log(Level.SEVERE,
"Error doing bulk insert of artifacts.", ex);
215 Long count = dbManager.getCountArtifactInstancesByCaseDataSource(eamDataSource);
216 logger.log(Level.INFO,
"{0} artifacts in db for case: {1} ds:{2}",
new Object[]{count, eamCase.getDisplayName(), eamDataSource.getName()});
217 }
catch (CentralRepoException ex) {
218 logger.log(Level.SEVERE,
"Error counting artifacts.", ex);
222 refCounter.decrementAndGet(jobId);
227 "CentralRepoIngestModule.notfyBubble.title=Central Repository Not Initialized",
228 "CentralRepoIngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Central Repository ingest module."
231 public void startUp(IngestJobContext context)
throws IngestModuleException {
232 IngestEventsListener.incrementCorrelationEngineModuleCount();
248 if (IngestEventsListener.getCeModuleInstanceCount() == 1 || !IngestEventsListener.isFlagNotableItems()) {
249 IngestEventsListener.setFlagNotableItems(flagTaggedNotableItems);
251 if (IngestEventsListener.getCeModuleInstanceCount() == 1 || !IngestEventsListener.isFlagSeenDevices()) {
252 IngestEventsListener.setFlagSeenDevices(flagPreviouslySeenDevices);
254 if (IngestEventsListener.getCeModuleInstanceCount() == 1 || !IngestEventsListener.shouldCreateCrProperties()) {
255 IngestEventsListener.setCreateCrProperties(createCorrelationProperties);
257 if (IngestEventsListener.getCeModuleInstanceCount() == 1 || !IngestEventsListener.isFlagUniqueArtifacts()) {
258 IngestEventsListener.setFlagUniqueArtifacts(flagUniqueArtifacts);
261 if (CentralRepository.isEnabled() ==
false) {
269 if (RuntimeProperties.runningWithGUI()) {
270 if (1L == warningMsgRefCounter.incrementAndGet(jobId)) {
271 MessageNotifyUtil.Notify.warn(Bundle.CentralRepoIngestModule_notfyBubble_title(), Bundle.CentralRepoIngestModule_errorMessage_isNotEnabled());
278 autopsyCase = Case.getCurrentCaseThrows();
279 }
catch (NoCurrentCaseException ex) {
280 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
281 throw new IngestModuleException(
"Exception while getting open case.", ex);
285 if ((autopsyCase.getCaseType() == Case.CaseType.MULTI_USER_CASE)
286 && (CentralRepoDbManager.getSavedDbChoice().getDbPlatform() == CentralRepoPlatforms.SQLITE)) {
287 logger.log(Level.SEVERE,
"Cannot run Central Repository ingest module on a multi-user case with a SQLite central repository.");
288 throw new IngestModuleException(
"Cannot run on a multi-user case with a SQLite central repository.");
290 jobId = context.getJobId();
292 CentralRepository centralRepoDb;
294 centralRepoDb = CentralRepository.getInstance();
295 }
catch (CentralRepoException ex) {
296 logger.log(Level.SEVERE,
"Error connecting to central repository database.", ex);
297 throw new IngestModuleException(
"Error connecting to central repository database.", ex);
301 filesType = centralRepoDb.getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID);
302 }
catch (CentralRepoException ex) {
303 logger.log(Level.SEVERE,
"Error getting correlation type FILES in ingest module start up.", ex);
304 throw new IngestModuleException(
"Error getting correlation type FILES in ingest module start up.", ex);
308 eamCase = centralRepoDb.getCase(autopsyCase);
309 }
catch (CentralRepoException ex) {
310 throw new IngestModuleException(
"Unable to get case from central repository database ", ex);
314 eamDataSource = CorrelationDataSource.fromTSKDataSource(eamCase, context.getDataSource());
315 }
catch (CentralRepoException ex) {
316 logger.log(Level.SEVERE,
"Error getting data source info.", ex);
317 throw new IngestModuleException(
"Error getting data source info.", ex);
322 if (refCounter.incrementAndGet(jobId)
326 if (null == centralRepoDb.getDataSource(eamCase, eamDataSource.getDataSourceObjectID())) {
327 centralRepoDb.newDataSource(eamDataSource);
329 }
catch (CentralRepoException ex) {
330 logger.log(Level.SEVERE,
"Error adding data source to Central Repository.", ex);
331 throw new IngestModuleException(
"Error adding data source to Central Repository.", ex);
343 private void postCorrelatedBadFileToBlackboard(AbstractFile abstractFile, List<String> caseDisplayNames, CorrelationAttributeInstance.Type aType, String value) {
344 String prevCases = caseDisplayNames.stream().distinct().collect(Collectors.joining(
","));
345 String justification =
"Previously marked as notable in cases " + prevCases;
346 Collection<BlackboardAttribute> attributes = Arrays.asList(
347 new BlackboardAttribute(
348 TSK_SET_NAME, MODULE_NAME,
349 Bundle.CentralRepoIngestModule_prevTaggedSet_text()),
350 new BlackboardAttribute(
351 TSK_CORRELATION_TYPE, MODULE_NAME,
352 aType.getDisplayName()),
353 new BlackboardAttribute(
354 TSK_CORRELATION_VALUE, MODULE_NAME,
356 new BlackboardAttribute(
357 TSK_OTHER_CASES, MODULE_NAME,
361 if (!blackboard.artifactExists(abstractFile, TSK_PREVIOUSLY_NOTABLE, attributes)) {
362 BlackboardArtifact tifArtifact = abstractFile.newAnalysisResult(
363 BlackboardArtifact.Type.TSK_PREVIOUSLY_NOTABLE, Score.SCORE_NOTABLE,
364 null, Bundle.CentralRepoIngestModule_prevTaggedSet_text(), justification, attributes)
365 .getAnalysisResult();
368 blackboard.postArtifact(tifArtifact, MODULE_NAME);
369 }
catch (Blackboard.BlackboardException ex) {
370 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex);
373 sendBadFileInboxMessage(tifArtifact, abstractFile.getName(), abstractFile.getMd5Hash(), caseDisplayNames);
375 }
catch (TskCoreException ex) {
376 logger.log(Level.SEVERE,
"Failed to create BlackboardArtifact.", ex);
377 }
catch (IllegalStateException ex) {
378 logger.log(Level.SEVERE,
"Failed to create BlackboardAttribute.", ex);
383 "CentralRepoIngestModule_notable_message_header=<html>A file in this data source was previously seen and tagged as Notable.<br>",
384 "CentralRepoIngestModel_name_header=Name:<br>",
385 "CentralRepoIngestModel_previous_case_header=<br>Previous Cases:<br>",
386 "# {0} - Name of file that is Notable",
387 "CentralRepoIngestModule_postToBB_knownBadMsg=Notable: {0}"
399 private void sendBadFileInboxMessage(BlackboardArtifact artifact, String name, String md5Hash, List<String> caseDisplayNames) {
400 StringBuilder detailsSb =
new StringBuilder(1024);
402 detailsSb.append(Bundle.CentralRepoIngestModule_notable_message_header()).append(Bundle.CentralRepoIngestModel_name_header());
403 detailsSb.append(name).append(Bundle.CentralRepoIngestModel_previous_case_header());
404 for (String str : caseDisplayNames) {
405 detailsSb.append(str).append(
"<br>");
407 detailsSb.append(
"</html>");
408 services.postMessage(IngestMessage.createDataMessage(CentralRepoIngestModuleFactory.getModuleName(),
409 Bundle.CentralRepoIngestModule_postToBB_knownBadMsg(name),
410 detailsSb.toString(),