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_INTERESTING_FILE_HIT;
53 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT;
54 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME;
65 @Messages({
"CentralRepoIngestModule.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)",
66 "CentralRepoIngestModule.prevCaseComment.text=Previous Case: "})
67 final class CentralRepoIngestModule implements FileIngestModule {
69 private static final String MODULE_NAME = CentralRepoIngestModuleFactory.getModuleName();
70 static final boolean DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS =
false;
71 static final boolean DEFAULT_FLAG_PREVIOUS_DEVICES =
false;
72 static final boolean DEFAULT_CREATE_CR_PROPERTIES =
true;
74 private final static Logger logger = Logger.getLogger(CentralRepoIngestModule.class.getName());
75 private final IngestServices services = IngestServices.getInstance();
76 private static final IngestModuleReferenceCounter refCounter =
new IngestModuleReferenceCounter();
77 private static final IngestModuleReferenceCounter warningMsgRefCounter =
new IngestModuleReferenceCounter();
79 private CorrelationCase eamCase;
80 private CorrelationDataSource eamDataSource;
81 private CorrelationAttributeInstance.Type filesType;
82 private final boolean flagTaggedNotableItems;
83 private final boolean flagPreviouslySeenDevices;
84 private Blackboard blackboard;
85 private final boolean createCorrelationProperties;
92 CentralRepoIngestModule(IngestSettings settings) {
93 flagTaggedNotableItems = settings.isFlagTaggedNotableItems();
94 flagPreviouslySeenDevices = settings.isFlagPreviousDevices();
95 createCorrelationProperties = settings.shouldCreateCorrelationProperties();
99 public ProcessResult process(AbstractFile abstractFile) {
100 if (CentralRepository.isEnabled() ==
false) {
107 return ProcessResult.OK;
111 blackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard();
112 }
catch (NoCurrentCaseException ex) {
113 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
114 return ProcessResult.ERROR;
117 if (!CorrelationAttributeUtil.isSupportedAbstractFileType(abstractFile)) {
118 return ProcessResult.OK;
121 if (abstractFile.getKnown() == TskData.FileKnown.KNOWN) {
122 return ProcessResult.OK;
125 CentralRepository dbManager;
127 dbManager = CentralRepository.getInstance();
128 }
catch (CentralRepoException ex) {
129 logger.log(Level.SEVERE,
"Error connecting to Central Repository database.", ex);
130 return ProcessResult.ERROR;
134 if (!filesType.isEnabled()) {
135 return ProcessResult.OK;
139 String md5 = abstractFile.getMd5Hash();
140 if ((md5 == null) || (HashUtility.isNoDataMd5(md5))) {
141 return ProcessResult.OK;
148 if (abstractFile.getKnown() != TskData.FileKnown.KNOWN && flagTaggedNotableItems) {
150 TimingMetric timingMetric = HealthMonitor.getTimingMetric(
"Central Repository: Notable artifact query");
151 List<String> caseDisplayNamesList = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5);
152 HealthMonitor.submitTimingMetric(timingMetric);
153 if (!caseDisplayNamesList.isEmpty()) {
154 postCorrelatedBadFileToBlackboard(abstractFile, caseDisplayNamesList);
156 }
catch (CentralRepoException ex) {
157 logger.log(Level.SEVERE,
"Error searching database for artifact.", ex);
158 return ProcessResult.ERROR;
159 }
catch (CorrelationAttributeNormalizationException ex) {
160 logger.log(Level.INFO,
"Error searching database for artifact.", ex);
161 return ProcessResult.ERROR;
166 if (createCorrelationProperties) {
168 CorrelationAttributeInstance cefi =
new CorrelationAttributeInstance(
173 abstractFile.getParentPath() + abstractFile.getName(),
175 TskData.FileKnown.UNKNOWN
177 abstractFile.getId());
178 dbManager.addAttributeInstanceBulk(cefi);
179 }
catch (CentralRepoException ex) {
180 logger.log(Level.SEVERE,
"Error adding artifact to bulk artifacts.", ex);
181 return ProcessResult.ERROR;
182 }
catch (CorrelationAttributeNormalizationException ex) {
183 logger.log(Level.INFO,
"Error adding artifact to bulk artifacts.", ex);
184 return ProcessResult.ERROR;
187 return ProcessResult.OK;
191 public void shutDown() {
192 IngestEventsListener.decrementCorrelationEngineModuleCount();
194 if ((CentralRepository.isEnabled() ==
false) || (eamCase == null) || (eamDataSource == null)) {
197 CentralRepository dbManager;
199 dbManager = CentralRepository.getInstance();
200 }
catch (CentralRepoException ex) {
201 logger.log(Level.SEVERE,
"Error connecting to Central Repository database.", ex);
205 dbManager.commitAttributeInstancesBulk();
206 }
catch (CentralRepoException ex) {
207 logger.log(Level.SEVERE,
"Error doing bulk insert of artifacts.", ex);
210 Long count = dbManager.getCountArtifactInstancesByCaseDataSource(eamDataSource);
211 logger.log(Level.INFO,
"{0} artifacts in db for case: {1} ds:{2}",
new Object[]{count, eamCase.getDisplayName(), eamDataSource.getName()});
212 }
catch (CentralRepoException ex) {
213 logger.log(Level.SEVERE,
"Error counting artifacts.", ex);
217 refCounter.decrementAndGet(jobId);
222 "CentralRepoIngestModule.notfyBubble.title=Central Repository Not Initialized",
223 "CentralRepoIngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Central Repository ingest module."
226 public void startUp(IngestJobContext context)
throws IngestModuleException {
227 IngestEventsListener.incrementCorrelationEngineModuleCount();
243 if (IngestEventsListener.getCeModuleInstanceCount() == 1 || !IngestEventsListener.isFlagNotableItems()) {
244 IngestEventsListener.setFlagNotableItems(flagTaggedNotableItems);
246 if (IngestEventsListener.getCeModuleInstanceCount() == 1 || !IngestEventsListener.isFlagSeenDevices()) {
247 IngestEventsListener.setFlagSeenDevices(flagPreviouslySeenDevices);
249 if (IngestEventsListener.getCeModuleInstanceCount() == 1 || !IngestEventsListener.shouldCreateCrProperties()) {
250 IngestEventsListener.setCreateCrProperties(createCorrelationProperties);
253 if (CentralRepository.isEnabled() ==
false) {
261 if (RuntimeProperties.runningWithGUI()) {
262 if (1L == warningMsgRefCounter.incrementAndGet(jobId)) {
263 MessageNotifyUtil.Notify.warn(Bundle.CentralRepoIngestModule_notfyBubble_title(), Bundle.CentralRepoIngestModule_errorMessage_isNotEnabled());
270 autopsyCase = Case.getCurrentCaseThrows();
271 }
catch (NoCurrentCaseException ex) {
272 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
273 throw new IngestModuleException(
"Exception while getting open case.", ex);
277 if ((autopsyCase.getCaseType() == Case.CaseType.MULTI_USER_CASE)
278 && (CentralRepoDbManager.getSavedDbChoice().getDbPlatform() == CentralRepoPlatforms.SQLITE)) {
279 logger.log(Level.SEVERE,
"Cannot run Central Repository ingest module on a multi-user case with a SQLite central repository.");
280 throw new IngestModuleException(
"Cannot run on a multi-user case with a SQLite central repository.");
282 jobId = context.getJobId();
284 CentralRepository centralRepoDb;
286 centralRepoDb = CentralRepository.getInstance();
287 }
catch (CentralRepoException ex) {
288 logger.log(Level.SEVERE,
"Error connecting to central repository database.", ex);
289 throw new IngestModuleException(
"Error connecting to central repository database.", ex);
293 filesType = centralRepoDb.getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID);
294 }
catch (CentralRepoException ex) {
295 logger.log(Level.SEVERE,
"Error getting correlation type FILES in ingest module start up.", ex);
296 throw new IngestModuleException(
"Error getting correlation type FILES in ingest module start up.", ex);
300 eamCase = centralRepoDb.getCase(autopsyCase);
301 }
catch (CentralRepoException ex) {
302 throw new IngestModuleException(
"Unable to get case from central repository database ", ex);
306 eamDataSource = CorrelationDataSource.fromTSKDataSource(eamCase, context.getDataSource());
307 }
catch (CentralRepoException ex) {
308 logger.log(Level.SEVERE,
"Error getting data source info.", ex);
309 throw new IngestModuleException(
"Error getting data source info.", ex);
314 if (refCounter.incrementAndGet(jobId)
318 if (null == centralRepoDb.getDataSource(eamCase, eamDataSource.getDataSourceObjectID())) {
319 centralRepoDb.newDataSource(eamDataSource);
321 }
catch (CentralRepoException ex) {
322 logger.log(Level.SEVERE,
"Error adding data source to Central Repository.", ex);
323 throw new IngestModuleException(
"Error adding data source to Central Repository.", ex);
335 private void postCorrelatedBadFileToBlackboard(AbstractFile abstractFile, List<String> caseDisplayNames) {
336 Collection<BlackboardAttribute> attributes = Arrays.asList(
337 new BlackboardAttribute(
338 TSK_SET_NAME, MODULE_NAME,
339 Bundle.CentralRepoIngestModule_prevTaggedSet_text()),
340 new BlackboardAttribute(
341 TSK_COMMENT, MODULE_NAME,
342 Bundle.CentralRepoIngestModule_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(
","))));
346 if (!blackboard.artifactExists(abstractFile, TSK_INTERESTING_FILE_HIT, attributes)) {
347 BlackboardArtifact tifArtifact = abstractFile.newAnalysisResult(
348 BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT, Score.SCORE_LIKELY_NOTABLE,
349 null, Bundle.CentralRepoIngestModule_prevTaggedSet_text(), null, attributes)
350 .getAnalysisResult();
353 blackboard.postArtifact(tifArtifact, MODULE_NAME);
354 }
catch (Blackboard.BlackboardException ex) {
355 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex);
358 sendBadFileInboxMessage(tifArtifact, abstractFile.getName(), abstractFile.getMd5Hash(), caseDisplayNames);
360 }
catch (TskCoreException ex) {
361 logger.log(Level.SEVERE,
"Failed to create BlackboardArtifact.", ex);
362 }
catch (IllegalStateException ex) {
363 logger.log(Level.SEVERE,
"Failed to create BlackboardAttribute.", ex);
368 "CentralRepoIngestModule_notable_message_header=<html>A file in this data source was previously seen and tagged as Notable.<br>",
369 "CentralRepoIngestModel_name_header=Name:<br>",
370 "CentralRepoIngestModel_previous_case_header=<br>Previous Cases:<br>",
371 "# {0} - Name of file that is Notable",
372 "CentralRepoIngestModule_postToBB_knownBadMsg=Notable: {0}"
384 private void sendBadFileInboxMessage(BlackboardArtifact artifact, String name, String md5Hash, List<String> caseDisplayNames) {
385 StringBuilder detailsSb =
new StringBuilder(1024);
387 detailsSb.append(Bundle.CentralRepoIngestModule_notable_message_header()).append(Bundle.CentralRepoIngestModel_name_header());
388 detailsSb.append(name).append(Bundle.CentralRepoIngestModel_previous_case_header());
389 for (String str : caseDisplayNames) {
390 detailsSb.append(str).append(
"<br>");
392 detailsSb.append(
"</html>");
393 services.postMessage(IngestMessage.createDataMessage(CentralRepoIngestModuleFactory.getModuleName(),
394 Bundle.CentralRepoIngestModule_postToBB_knownBadMsg(name),
395 detailsSb.toString(),