19 package org.sleuthkit.autopsy.commandlineingest;
21 import com.google.gson.GsonBuilder;
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import java.nio.file.Paths;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.List;
28 import java.util.UUID;
29 import java.util.Collection;
30 import java.util.EnumSet;
31 import java.util.Iterator;
34 import java.util.logging.Level;
35 import org.netbeans.spi.sendopts.OptionProcessor;
36 import org.openide.LifecycleManager;
37 import org.openide.util.Lookup;
79 static final int CL_SUCCESS = 0;
80 static final int CL_RUN_FAILURE = -1;
81 static final int CL_PROCESS_FAILURE = -2;
94 void stop(
int errorCode) {
97 Case.closeCurrentCase();
98 }
catch (CaseActionException ex) {
99 LOGGER.log(Level.WARNING,
"Unable to close the case while shutting down command line ingest manager", ex);
103 if (errorCode == CL_SUCCESS) {
104 LifecycleManager.getDefault().exit();
106 LifecycleManager.getDefault().exit(errorCode);
115 ingestLock =
new Object();
118 LOGGER.log(Level.INFO,
"Set running with desktop GUI runtime property to false");
120 LOGGER.log(Level.SEVERE,
"Failed to set running with desktop GUI runtime property to false", ex);
130 LOGGER.log(Level.INFO,
"Job processing task started");
131 int errorCode = CL_SUCCESS;
135 LOGGER.log(Level.INFO,
"Autopsy is running from command line");
136 List<CommandLineCommand> commands = null;
139 Collection<? extends OptionProcessor> optionProcessors = Lookup.getDefault().lookupAll(OptionProcessor.class);
140 Iterator<? extends OptionProcessor> optionsIterator = optionProcessors.iterator();
141 while (optionsIterator.hasNext()) {
143 OptionProcessor processor = optionsIterator.next();
146 commands = ((CommandLineOptionProcessor) processor).getCommands();
150 if (commands == null || commands.isEmpty()) {
151 LOGGER.log(Level.SEVERE,
"No command line commands specified");
152 System.out.println(
"No command line commands specified");
153 errorCode = CL_RUN_FAILURE;
158 for (CommandLineCommand command : commands) {
159 CommandLineCommand.CommandType type = command.getType();
163 LOGGER.log(Level.INFO,
"Processing 'Create Case' command");
164 System.out.println(
"Processing 'Create Case' command");
165 Map<String, String> inputs = command.getInputs();
166 String baseCaseName = inputs.get(CommandLineCommand.InputType.CASE_NAME.name());
167 String rootOutputDirectory = inputs.get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
169 String caseTypeString = inputs.get(CommandLineCommand.InputType.CASE_TYPE.name());
173 caseForJob = createCase(baseCaseName, rootOutputDirectory, caseType);
175 String outputDirPath = getOutputDirPath(caseForJob);
176 OutputGenerator.saveCreateCaseOutput(caseForJob, outputDirPath, baseCaseName);
178 String baseCaseName = command.getInputs().get(CommandLineCommand.InputType.CASE_NAME.name());
179 LOGGER.log(Level.SEVERE,
"Error creating or opening case " + baseCaseName, ex);
180 System.out.println(
"Error creating or opening case " + baseCaseName);
182 errorCode = CL_RUN_FAILURE;
186 case ADD_DATA_SOURCE:
188 LOGGER.log(Level.INFO,
"Processing 'Add Data Source' command");
189 System.out.println(
"Processing 'Add Data Source' command");
190 Map<String, String> inputs = command.getInputs();
193 if (caseForJob == null) {
195 String baseCaseName = inputs.get(CommandLineCommand.InputType.CASE_NAME.name());
196 String rootOutputDirectory = inputs.get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
197 caseForJob = openExistingCase(baseCaseName, rootOutputDirectory);
200 String dataSourcePath = inputs.get(CommandLineCommand.InputType.DATA_SOURCE_PATH.name());
204 String outputDirPath = getOutputDirPath(caseForJob);
205 OutputGenerator.saveAddDataSourceOutput(caseForJob, dataSource, outputDirPath);
207 String dataSourcePath = command.getInputs().get(CommandLineCommand.InputType.DATA_SOURCE_PATH.name());
208 LOGGER.log(Level.SEVERE,
"Error adding data source " + dataSourcePath, ex);
209 System.out.println(
"Error adding data source " + dataSourcePath);
211 errorCode = CL_RUN_FAILURE;
217 LOGGER.log(Level.INFO,
"Processing 'Run Ingest' command");
218 System.out.println(
"Processing 'Run Ingest' command");
219 Map<String, String> inputs = command.getInputs();
222 if (caseForJob == null) {
224 String baseCaseName = inputs.get(CommandLineCommand.InputType.CASE_NAME.name());
225 String rootOutputDirectory = inputs.get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
226 caseForJob = openExistingCase(baseCaseName, rootOutputDirectory);
230 if (dataSource == null) {
232 String dataSourceId = inputs.get(CommandLineCommand.InputType.DATA_SOURCE_ID.name());
233 Long dataSourceObjId = Long.valueOf(dataSourceId);
236 Content content = null;
239 }
catch (TskCoreException ex) {
240 LOGGER.log(Level.SEVERE,
"Exception while trying to find data source with object ID " + dataSourceId, ex);
241 System.out.println(
"Exception while trying to find data source with object ID " + dataSourceId);
243 errorCode = CL_RUN_FAILURE;
247 if (content == null) {
248 LOGGER.log(Level.SEVERE,
"Unable to find data source with object ID {0}", dataSourceId);
249 System.out.println(
"Unable to find data source with object ID " + dataSourceId);
256 List<Content> contentList = Arrays.asList(
new Content[]{content});
257 List<String> errorList =
new ArrayList<>();
262 String ingestProfile = inputs.get(CommandLineCommand.InputType.INGEST_PROFILE_NAME.name());
263 analyze(dataSource, ingestProfile);
265 String dataSourcePath = command.getInputs().get(CommandLineCommand.InputType.DATA_SOURCE_PATH.name());
266 LOGGER.log(Level.SEVERE,
"Error running ingest on data source " + dataSourcePath, ex);
267 System.out.println(
"Error running ingest on data source " + dataSourcePath);
269 errorCode = CL_RUN_FAILURE;
274 case LIST_ALL_DATA_SOURCES:
276 LOGGER.log(Level.INFO,
"Processing 'List All Data Sources' command");
277 System.out.println(
"Processing 'List All Data Sources' command");
278 Map<String, String> inputs = command.getInputs();
281 if (caseForJob == null) {
283 String baseCaseName = inputs.get(CommandLineCommand.InputType.CASE_NAME.name());
284 String rootOutputDirectory = inputs.get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
285 caseForJob = openExistingCase(baseCaseName, rootOutputDirectory);
288 String outputDirPath = getOutputDirPath(caseForJob);
289 OutputGenerator.listAllDataSources(caseForJob, outputDirPath);
291 String baseCaseName = command.getInputs().get(CommandLineCommand.InputType.CASE_NAME.name());
292 String rootOutputDirectory = command.getInputs().get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
293 String msg =
"Error opening case " + baseCaseName +
" in directory: " + rootOutputDirectory;
294 LOGGER.log(Level.SEVERE, msg, ex);
295 System.out.println(msg);
296 errorCode = CL_RUN_FAILURE;
302 case GENERATE_REPORTS:
304 LOGGER.log(Level.INFO,
"Processing 'Generate Reports' command");
305 System.out.println(
"Processing 'Generate Reports' command");
306 Map<String, String> inputs = command.getInputs();
309 if (caseForJob == null) {
311 String baseCaseName = inputs.get(CommandLineCommand.InputType.CASE_NAME.name());
312 String rootOutputDirectory = inputs.get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
313 caseForJob = openExistingCase(baseCaseName, rootOutputDirectory);
316 String reportName = inputs.get(CommandLineCommand.InputType.REPORT_PROFILE_NAME.name());
317 if (reportName == null) {
326 String baseCaseName = command.getInputs().get(CommandLineCommand.InputType.CASE_NAME.name());
327 String rootOutputDirectory = command.getInputs().get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
328 String msg =
"Error opening case " + baseCaseName +
" in directory: " + rootOutputDirectory;
329 LOGGER.log(Level.SEVERE, msg, ex);
330 System.out.println(msg);
331 errorCode = CL_RUN_FAILURE;
334 }
catch (Exception ex) {
335 String msg =
"An exception occurred while generating report: " + ex.getMessage();
336 LOGGER.log(Level.WARNING, msg, ex);
337 System.out.println(msg);
338 errorCode = CL_RUN_FAILURE;
343 case LIST_ALL_INGEST_PROFILES:
345 GsonBuilder gb =
new GsonBuilder();
346 System.out.println(
"Listing ingest profiles");
348 String jsonText = gb.create().toJson(profile);
349 System.out.println(jsonText);
351 System.out.println(
"Ingest profile list complete");
357 }
catch (Throwable ex) {
365 LOGGER.log(Level.SEVERE,
"Unexpected error", ex);
366 System.out.println(
"Unexpected error. Exiting...");
367 errorCode = CL_RUN_FAILURE;
372 LOGGER.log(Level.WARNING,
"Exception while closing case", ex);
373 System.out.println(
"Exception while closing case");
378 LOGGER.log(Level.INFO,
"Job processing task finished");
379 System.out.println(
"Job processing task finished");
404 LOGGER.log(Level.INFO,
"Adding data source {0} ", dataSource.
getPath().toString());
407 List<AutoIngestDataSourceProcessor> validDataSourceProcessors;
411 LOGGER.log(Level.SEVERE,
"Exception while determining best data source processor for {0}", dataSource.
getPath());
417 if (validDataSourceProcessors.isEmpty()) {
419 LOGGER.log(Level.SEVERE,
"Unsupported data source {0}", dataSource.
getPath());
427 UUID taskId = UUID.randomUUID();
431 LOGGER.log(Level.INFO,
"Identified data source type for {0} as {1}",
new Object[]{dataSource.getPath(), selectedProcessor.getDataSourceType()});
432 selectedProcessor.process(dataSource.
getDeviceId(), dataSource.
getPath(), progressMonitor, callBack);
448 LOGGER.log(Level.SEVERE,
"All data source processors failed to process {0}", dataSource.
getPath());
463 if (null != resultCode) {
464 switch (resultCode) {
466 LOGGER.log(Level.INFO,
"Added data source to case");
468 LOGGER.log(Level.SEVERE,
"Data source failed to produce content");
472 case NONCRITICAL_ERRORS:
474 LOGGER.log(Level.WARNING,
"Non-critical error running data source processor for {0}: {1}",
new Object[]{dataSource.getPath(), errorMessage});
476 LOGGER.log(Level.INFO,
"Added data source to case");
478 LOGGER.log(Level.SEVERE,
"Data source failed to produce content");
482 case CRITICAL_ERRORS:
484 LOGGER.log(Level.SEVERE,
"Critical error running data source processor for {0}: {1}",
new Object[]{dataSource.getPath(), errorMessage});
486 LOGGER.log(Level.SEVERE,
"Failed to add data source to case");
490 LOGGER.log(Level.WARNING,
"No result code for data source processor for {0}", dataSource.
getPath());
513 LOGGER.log(Level.INFO,
"Starting ingest modules analysis for {0} ", dataSource.
getPath());
518 if (!ingestProfileName.isEmpty()) {
520 if (selectedProfile == null) {
522 LOGGER.log(Level.SEVERE,
"Unable to find ingest profile: {0}. Ingest cancelled!", ingestProfileName);
523 System.out.println(
"Unable to find ingest profile: " + ingestProfileName +
". Ingest cancelled!");
524 throw new AnalysisStartupException(
"Unable to find ingest profile: " + ingestProfileName +
". Ingest cancelled!");
529 if (selectedFileSet == null) {
531 LOGGER.log(Level.SEVERE,
"Unable to find file filter {0} for ingest profile: {1}. Ingest cancelled!",
new Object[]{selectedProfile.getFileIngestFilter(), ingestProfileName});
532 System.out.println(
"Unable to find file filter " + selectedProfile.getFileIngestFilter() +
" for ingest profile: " + ingestProfileName +
". Ingest cancelled!");
533 throw new AnalysisStartupException(
"Unable to find file filter " + selectedProfile.getFileIngestFilter() +
" for ingest profile: " + ingestProfileName +
". Ingest cancelled!");
542 if (selectedProfile == null || selectedFileSet == null) {
551 List<String> settingsWarnings = ingestJobSettings.
getWarnings();
552 if (settingsWarnings.isEmpty()) {
555 if (null != ingestJob) {
565 ingestLock.wait(60000);
568 LOGGER.log(Level.INFO,
"Finished ingest modules analysis for {0} ", dataSource.
getPath());
571 if (!snapshot.isCancelled()) {
573 if (!cancelledModules.isEmpty()) {
574 LOGGER.log(Level.WARNING, String.format(
"Ingest module(s) cancelled for %s", dataSource.
getPath()));
575 for (String module : snapshot.getCancelledDataSourceIngestModules()) {
576 LOGGER.log(Level.WARNING, String.format(
"%s ingest module cancelled for %s", module, dataSource.
getPath()));
579 LOGGER.log(Level.INFO,
"Analysis of data source completed");
581 LOGGER.log(Level.WARNING,
"Analysis of data source cancelled");
584 throw new AnalysisStartupException(String.format(
"Analysis cancelled due to %s for %s", cancellationReason.getDisplayName(), dataSource.
getPath()));
589 LOGGER.log(Level.SEVERE, String.format(
"%s ingest module startup error for %s", error.getModuleDisplayName(), dataSource.
getPath()), error.getThrowable());
591 LOGGER.log(Level.SEVERE,
"Failed to analyze data source due to ingest job startup error");
592 throw new AnalysisStartupException(String.format(
"Error(s) during ingest module startup for %s", dataSource.
getPath()));
594 LOGGER.log(Level.SEVERE, String.format(
"Ingest manager ingest job start error for %s", dataSource.
getPath()), ingestJobStartResult.
getStartupException());
595 throw new AnalysisStartupException(
"Ingest manager error starting job", ingestJobStartResult.
getStartupException());
598 for (String warning : settingsWarnings) {
599 LOGGER.log(Level.SEVERE,
"Ingest job settings error for {0}: {1}",
new Object[]{dataSource.getPath(), warning});
601 LOGGER.log(Level.SEVERE,
"Failed to analyze data source due to settings errors");
602 throw new AnalysisStartupException(
"Error(s) in ingest job settings");
623 if (profile.toString().equalsIgnoreCase(ingestProfileName)) {
625 selectedProfile = profile;
629 return selectedProfile;
645 fileIngestFilters.put(fSet.getName(), fSet);
647 return fileIngestFilters.get(filterName);
649 LOGGER.log(Level.SEVERE,
"Failed to get file ingest filter: " + filterName, ex);
675 String eventType =
event.getPropertyName();
725 private final class AnalysisStartupException
extends Exception {
734 super(message, cause);
synchronized List< String > getDataSourceProcessorErrorMessages()
static List< AutoIngestDataSourceProcessor > getOrderedListOfDataSourceProcessors(Path dataSourcePath)
void logDataSourceProcessorResult(AutoIngestDataSource dataSource)
List< String > getCancelledDataSourceIngestModules()
static synchronized IngestManager getInstance()
static List< FilesSet > getStandardFileIngestFilters()
static void closeCurrentCase()
IngestProfiles.IngestProfile getSelectedProfile(String ingestProfileName)
IngestJobStartResult beginIngestJob(Collection< Content > dataSources, IngestJobSettings settings)
AutoIngestDataSource dataSource
AnalysisStartupException(String message)
synchronized DataSourceProcessorResult getResultDataSourceProcessorResultCode()
CommandLineIngestManager()
boolean isIngestRunning()
static synchronized FilesSetsManager getInstance()
void runDataSourceProcessor(Case caseForJob, AutoIngestDataSource dataSource)
static final Set< IngestManager.IngestJobEvent > INGEST_JOB_EVENTS_OF_INTEREST
void propertyChange(PropertyChangeEvent event)
String getIngestProfilePrefix()
void removeIngestJobEventListener(final PropertyChangeListener listener)
Map< String, FilesSet > getCustomFileIngestFilters()
List< IngestModuleError > getModuleErrors()
static final Logger LOGGER
static final long serialVersionUID
void addIngestJobEventListener(final PropertyChangeListener listener)
void setFileFilter(FilesSet fileIngestFilter)
ProgressSnapshot getSnapshot()
static IngestProfilePaths getInstance()
void setProgressText(final String text)
static synchronized List< IngestProfile > getIngestProfiles()
AnalysisStartupException(String message, Throwable cause)
SleuthkitCase getSleuthkitCase()
FilesSet getSelectedFilter(String filterName)
void analyze(AutoIngestDataSource dataSource, String ingestProfileName)
static synchronized void setRunningWithGUI(boolean runningWithGUI)
List< String > getWarnings()
synchronized List< Content > getContent()
synchronized void setDataSourceProcessorOutput(DataSourceProcessorResult result, List< String > errorMessages, List< Content > content)
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
void setIndeterminate(final boolean indeterminate)
static String getCommandLineModeIngestModuleContextString()
void setProgress(final int progress)
void notifyAddingDataSource(UUID eventId)
static String getDefaultReportingConfigName()
IngestManager.IngestManagerException getStartupException()