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());
 
  201                                 String password = inputs.get(CommandLineCommand.InputType.BITLOCKER_KEY.name());
 
  202                                 dataSource = 
new AutoIngestDataSource(UUID.randomUUID().toString(), Paths.get(dataSourcePath), password);
 
  205                                 String outputDirPath = getOutputDirPath(caseForJob);
 
  206                                 OutputGenerator.saveAddDataSourceOutput(caseForJob, dataSource, outputDirPath);
 
  208                                 String dataSourcePath = command.getInputs().get(CommandLineCommand.InputType.DATA_SOURCE_PATH.name());
 
  209                                 LOGGER.log(Level.SEVERE, 
"Error adding data source " + dataSourcePath, ex);
 
  210                                 System.out.println(
"Error adding data source " + dataSourcePath);
 
  212                                 errorCode = CL_RUN_FAILURE;
 
  218                                 LOGGER.log(Level.INFO, 
"Processing 'Run Ingest' command");
 
  219                                 System.out.println(
"Processing 'Run Ingest' command");
 
  220                                 Map<String, String> inputs = command.getInputs();
 
  223                                 if (caseForJob == null) {
 
  225                                     String baseCaseName = inputs.get(CommandLineCommand.InputType.CASE_NAME.name());
 
  226                                     String rootOutputDirectory = inputs.get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
 
  227                                     caseForJob = openExistingCase(baseCaseName, rootOutputDirectory);
 
  231                                 if (dataSource == null) {
 
  233                                     String dataSourceId = inputs.get(CommandLineCommand.InputType.DATA_SOURCE_ID.name());
 
  234                                     Long dataSourceObjId = Long.valueOf(dataSourceId);
 
  241                                         LOGGER.log(Level.SEVERE, 
"Exception while trying to find data source with object ID " + dataSourceId, ex);
 
  242                                         System.out.println(
"Exception while trying to find data source with object ID " + dataSourceId);
 
  244                                         errorCode = CL_RUN_FAILURE;
 
  248                                     if (content == null) {
 
  249                                         LOGGER.log(Level.SEVERE, 
"Unable to find data source with object ID {0}", dataSourceId);
 
  250                                         System.out.println(
"Unable to find data source with object ID " + dataSourceId);
 
  257                                     List<Content> contentList = Arrays.asList(
new Content[]{content});
 
  258                                     List<String> errorList = 
new ArrayList<>();
 
  263                                 String ingestProfile = inputs.get(CommandLineCommand.InputType.INGEST_PROFILE_NAME.name());
 
  264                                 analyze(dataSource, ingestProfile);
 
  266                                 String dataSourcePath = command.getInputs().get(CommandLineCommand.InputType.DATA_SOURCE_PATH.name());
 
  267                                 LOGGER.log(Level.SEVERE, 
"Error running ingest on data source " + dataSourcePath, ex);
 
  268                                 System.out.println(
"Error running ingest on data source " + dataSourcePath);
 
  270                                 errorCode = CL_RUN_FAILURE;
 
  275                             case LIST_ALL_DATA_SOURCES:
 
  277                                 LOGGER.log(Level.INFO, 
"Processing 'List All Data Sources' command");
 
  278                                 System.out.println(
"Processing 'List All Data Sources' command");
 
  279                                 Map<String, String> inputs = command.getInputs();
 
  282                                 if (caseForJob == null) {
 
  284                                     String baseCaseName = inputs.get(CommandLineCommand.InputType.CASE_NAME.name());
 
  285                                     String rootOutputDirectory = inputs.get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
 
  286                                     caseForJob = openExistingCase(baseCaseName, rootOutputDirectory);
 
  289                                 String outputDirPath = getOutputDirPath(caseForJob);
 
  290                                 OutputGenerator.listAllDataSources(caseForJob, outputDirPath);
 
  292                                 String baseCaseName = command.getInputs().get(CommandLineCommand.InputType.CASE_NAME.name());
 
  293                                 String rootOutputDirectory = command.getInputs().get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
 
  294                                 String msg = 
"Error opening case " + baseCaseName + 
" in directory: " + rootOutputDirectory;
 
  295                                 LOGGER.log(Level.SEVERE, msg, ex);
 
  296                                 System.out.println(msg);
 
  297                                 errorCode = CL_RUN_FAILURE;
 
  303                             case GENERATE_REPORTS:
 
  305                                 LOGGER.log(Level.INFO, 
"Processing 'Generate Reports' command");
 
  306                                 System.out.println(
"Processing 'Generate Reports' command");
 
  307                                 Map<String, String> inputs = command.getInputs();
 
  310                                 if (caseForJob == null) {
 
  312                                     String baseCaseName = inputs.get(CommandLineCommand.InputType.CASE_NAME.name());
 
  313                                     String rootOutputDirectory = inputs.get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
 
  314                                     caseForJob = openExistingCase(baseCaseName, rootOutputDirectory);
 
  317                                 String reportName = inputs.get(CommandLineCommand.InputType.REPORT_PROFILE_NAME.name());
 
  318                                 if (reportName == null) {
 
  327                                 String baseCaseName = command.getInputs().get(CommandLineCommand.InputType.CASE_NAME.name());
 
  328                                 String rootOutputDirectory = command.getInputs().get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
 
  329                                 String msg = 
"Error opening case " + baseCaseName + 
" in directory: " + rootOutputDirectory;
 
  330                                 LOGGER.log(Level.SEVERE, msg, ex);
 
  331                                 System.out.println(msg);
 
  332                                 errorCode = CL_RUN_FAILURE;
 
  335                             } 
catch (Exception ex) {
 
  336                                 String msg = 
"An exception occurred while generating report: " + ex.getMessage();
 
  337                                 LOGGER.log(Level.WARNING, msg, ex);
 
  338                                 System.out.println(msg);
 
  339                                 errorCode = CL_RUN_FAILURE;
 
  344                             case LIST_ALL_INGEST_PROFILES:
 
  346                                 GsonBuilder gb = 
new GsonBuilder();
 
  347                                 System.out.println(
"Listing ingest profiles");
 
  349                                     String jsonText = gb.create().toJson(profile);
 
  350                                     System.out.println(jsonText);
 
  352                                 System.out.println(
"Ingest profile list complete");
 
  358                 } 
catch (Throwable ex) {
 
  366                     LOGGER.log(Level.SEVERE, 
"Unexpected error", ex);
 
  367                     System.out.println(
"Unexpected error. Exiting...");
 
  368                     errorCode = CL_RUN_FAILURE;
 
  373                         LOGGER.log(Level.WARNING, 
"Exception while closing case", ex);
 
  374                         System.out.println(
"Exception while closing case");
 
  379                 LOGGER.log(Level.INFO, 
"Job processing task finished");
 
  380                 System.out.println(
"Job processing task finished");
 
  405             LOGGER.log(Level.INFO, 
"Adding data source {0} ", dataSource.
getPath().toString());
 
  408             List<AutoIngestDataSourceProcessor> validDataSourceProcessors;
 
  412                 LOGGER.log(Level.SEVERE, 
"Exception while determining best data source processor for {0}", dataSource.
getPath());
 
  418             if (validDataSourceProcessors.isEmpty()) {
 
  420                 LOGGER.log(Level.SEVERE, 
"Unsupported data source {0}", dataSource.
getPath());  
 
  428                     UUID taskId = UUID.randomUUID();
 
  432                     LOGGER.log(Level.INFO, 
"Identified data source type for {0} as {1}", 
new Object[]{dataSource.getPath(), selectedProcessor.getDataSourceType()});
 
  449                 LOGGER.log(Level.SEVERE, 
"All data source processors failed to process {0}", dataSource.
getPath());
 
  464             if (null != resultCode) {
 
  465                 switch (resultCode) {
 
  467                         LOGGER.log(Level.INFO, 
"Added data source to case");
 
  469                             LOGGER.log(Level.SEVERE, 
"Data source failed to produce content");
 
  473                     case NONCRITICAL_ERRORS:
 
  475                             LOGGER.log(Level.WARNING, 
"Non-critical error running data source processor for {0}: {1}", 
new Object[]{dataSource.getPath(), errorMessage});
 
  477                         LOGGER.log(Level.INFO, 
"Added data source to case");
 
  479                             LOGGER.log(Level.SEVERE, 
"Data source failed to produce content");
 
  483                     case CRITICAL_ERRORS:
 
  485                             LOGGER.log(Level.SEVERE, 
"Critical error running data source processor for {0}: {1}", 
new Object[]{dataSource.getPath(), errorMessage});
 
  487                         LOGGER.log(Level.SEVERE, 
"Failed to add data source to case");
 
  491                 LOGGER.log(Level.WARNING, 
"No result code for data source processor for {0}", dataSource.
getPath());
 
  514             LOGGER.log(Level.INFO, 
"Starting ingest modules analysis for {0} ", dataSource.
getPath());
 
  519             if (!ingestProfileName.isEmpty()) {
 
  521                 if (selectedProfile == null) {
 
  523                     LOGGER.log(Level.SEVERE, 
"Unable to find ingest profile: {0}. Ingest cancelled!", ingestProfileName);
 
  524                     System.out.println(
"Unable to find ingest profile: " + ingestProfileName + 
". Ingest cancelled!");
 
  525                     throw new AnalysisStartupException(
"Unable to find ingest profile: " + ingestProfileName + 
". Ingest cancelled!");
 
  530                 if (selectedFileSet == null) {
 
  532                     LOGGER.log(Level.SEVERE, 
"Unable to find file filter {0} for ingest profile: {1}. Ingest cancelled!", 
new Object[]{selectedProfile.getFileIngestFilter(), ingestProfileName});
 
  533                     System.out.println(
"Unable to find file filter " + selectedProfile.getFileIngestFilter() + 
" for ingest profile: " + ingestProfileName + 
". Ingest cancelled!");
 
  534                     throw new AnalysisStartupException(
"Unable to find file filter " + selectedProfile.getFileIngestFilter() + 
" for ingest profile: " + ingestProfileName + 
". Ingest cancelled!");
 
  543                     if (selectedProfile == null || selectedFileSet == null) {
 
  552                     List<String> settingsWarnings = ingestJobSettings.
getWarnings();
 
  553                     if (settingsWarnings.isEmpty()) {
 
  556                         if (null != ingestJob) {
 
  566                                 ingestLock.wait(60000);  
 
  569                             LOGGER.log(Level.INFO, 
"Finished ingest modules analysis for {0} ", dataSource.
getPath());
 
  572                             if (!snapshot.isCancelled()) {
 
  574                                 if (!cancelledModules.isEmpty()) {
 
  575                                     LOGGER.log(Level.WARNING, String.format(
"Ingest module(s) cancelled for %s", dataSource.
getPath()));
 
  576                                     for (String module : snapshot.getCancelledDataSourceIngestModules()) {
 
  577                                         LOGGER.log(Level.WARNING, String.format(
"%s ingest module cancelled for %s", module, dataSource.
getPath()));
 
  580                                 LOGGER.log(Level.INFO, 
"Analysis of data source completed");
 
  582                                 LOGGER.log(Level.WARNING, 
"Analysis of data source cancelled");
 
  585                                     throw new AnalysisStartupException(String.format(
"Analysis cancelled due to %s for %s", cancellationReason.getDisplayName(), dataSource.
getPath()));
 
  590                                 LOGGER.log(Level.SEVERE, String.format(
"%s ingest module startup error for %s", error.getModuleDisplayName(), dataSource.
getPath()), error.getThrowable());
 
  592                             LOGGER.log(Level.SEVERE, 
"Failed to analyze data source due to ingest job startup error");
 
  593                             throw new AnalysisStartupException(String.format(
"Error(s) during ingest module startup for %s", dataSource.
getPath()));
 
  595                             LOGGER.log(Level.SEVERE, String.format(
"Ingest manager ingest job start error for %s", dataSource.
getPath()), ingestJobStartResult.
getStartupException());
 
  596                             throw new AnalysisStartupException(
"Ingest manager error starting job", ingestJobStartResult.
getStartupException());
 
  599                         for (String warning : settingsWarnings) {
 
  600                             LOGGER.log(Level.SEVERE, 
"Ingest job settings error for {0}: {1}", 
new Object[]{dataSource.getPath(), warning});
 
  602                         LOGGER.log(Level.SEVERE, 
"Failed to analyze data source due to settings errors");
 
  603                         throw new AnalysisStartupException(
"Error(s) in ingest job settings");
 
  624                 if (profile.toString().equalsIgnoreCase(ingestProfileName)) {
 
  626                     selectedProfile = profile;
 
  630             return selectedProfile;
 
  646                     fileIngestFilters.put(fSet.getName(), fSet);
 
  648                 return fileIngestFilters.get(filterName);
 
  650                 LOGGER.log(Level.SEVERE, 
"Failed to get file ingest filter: " + filterName, ex); 
 
  676                     String eventType = 
event.getPropertyName();
 
  726         private final class AnalysisStartupException 
extends Exception {
 
  735                 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
 
Content getContentById(long id)
 
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()