Autopsy  4.7.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
LocalFilesDSProcessor.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2018 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.casemodule;
20 
21 import java.io.File;
22 import java.io.IOException;
23 import java.nio.file.Path;
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.logging.Level;
30 import javax.swing.JPanel;
31 import javax.swing.filechooser.FileFilter;
32 import org.apache.commons.io.FilenameUtils;
33 import org.openide.modules.InstalledFileLocator;
34 import org.openide.util.NbBundle;
35 import org.openide.util.NbBundle.Messages;
36 import org.openide.util.lookup.ServiceProvider;
37 import org.openide.util.lookup.ServiceProviders;
45 
52 @ServiceProviders(value = {
53  @ServiceProvider(service = DataSourceProcessor.class),
54  @ServiceProvider(service = AutoIngestDataSourceProcessor.class)
55 })
56 @Messages({
57  "LocalFilesDSProcessor.logicalEvidenceFilter.desc=Logical Evidence Files (L01)"
58 })
60 
61  private static final String DATA_SOURCE_TYPE = NbBundle.getMessage(LocalFilesDSProcessor.class, "LocalFilesDSProcessor.dsType");
62  private static final Logger logger = Logger.getLogger(LocalFilesDSProcessor.class.getName());
63  private final LogicalFilesDspPanel configPanel;
64  private static final String L01_EXTRACTION_DIR = "L01";
65  private static final String UNIQUENESS_CONSTRAINT_SEPERATOR = "_";
66  private static final String EWFEXPORT_DIR = "ewfexport_exec"; // NON-NLS
67  private static final String EWFEXPORT_32_BIT_DIR = "32-bit"; // NON-NLS
68  private static final String EWFEXPORT_64_BIT_DIR = "64-bit"; // NON-NLS
69  private static final String EWFEXPORT_WINDOWS_EXE = "ewfexport.exe"; // NON-NLS
70  private static final String LOG_FILE_EXTENSION = ".txt";
71  private static final List<String> LOGICAL_EVIDENCE_EXTENSIONS = Arrays.asList(".l01");
72  private static final String LOGICAL_EVIDENCE_DESC = Bundle.LocalFilesDSProcessor_logicalEvidenceFilter_desc();
73  private static final GeneralFilter LOGICAL_EVIDENCE_FILTER = new GeneralFilter(LOGICAL_EVIDENCE_EXTENSIONS, LOGICAL_EVIDENCE_DESC);
74  /*
75  * TODO: Remove the setDataSourceOptionsCalled flag and the settings fields
76  * when the deprecated method setDataSourceOptions is removed.
77  */
78  private List<String> localFilePaths;
79  private boolean setDataSourceOptionsCalled;
80 
88  configPanel = LogicalFilesDspPanel.getDefault();
89  }
90 
98  public static String getType() {
99  return DATA_SOURCE_TYPE;
100  }
101 
109  @Override
110  public String getDataSourceType() {
111  return DATA_SOURCE_TYPE;
112  }
113 
122  @Override
123  public JPanel getPanel() {
124  configPanel.select();
125  return configPanel;
126  }
127 
135  @Override
136  public boolean isPanelValid() {
137  return configPanel.validatePanel();
138  }
139 
154  @Override
155  public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
156  if (!setDataSourceOptionsCalled) {
157  localFilePaths = configPanel.getContentPaths();
158  if (configPanel.subTypeIsLogicalEvidencePanel()) {
159  try {
160  //if the L01 option was chosen
161  localFilePaths = extractLogicalEvidenceFileContents(localFilePaths);
162  } catch (L01Exception ex) {
163  //contents of l01 could not be extracted don't add data source or run ingest
164  final List<String> errors = new ArrayList<>();
165  errors.add(ex.getMessage());
166  callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errors, new ArrayList<>());
167  return;
168  } catch (NoCurrentCaseException ex) {
169  logger.log(Level.WARNING, "Exception while getting open case.", ex);
170  return;
171  }
172  }
173  }
174  run(UUID.randomUUID().toString(), configPanel.getFileSetName(), localFilePaths, progressMonitor, callback);
175  }
176 
189  private List<String> extractLogicalEvidenceFileContents(final List<String> logicalEvidenceFilePaths) throws L01Exception, NoCurrentCaseException {
190  final List<String> extractedPaths = new ArrayList<>();
191  Path ewfexportPath;
192  ewfexportPath = locateEwfexportExecutable();
193  List<String> command = new ArrayList<>();
194  for (final String l01Path : logicalEvidenceFilePaths) {
195  command.clear();
196  command.add(ewfexportPath.toAbsolutePath().toString());
197  command.add("-f");
198  command.add("files");
199  command.add("-t");
200  File l01Dir = new File(Case.getCurrentCaseThrows().getModuleDirectory(), L01_EXTRACTION_DIR); //WJS-TODO change to getOpenCase() when that method exists
201  if (!l01Dir.exists()) {
202  l01Dir.mkdirs();
203  }
204  Path dirPath = Paths.get(FilenameUtils.getBaseName(l01Path) + UNIQUENESS_CONSTRAINT_SEPERATOR + System.currentTimeMillis());
205 
206  command.add(dirPath.toString());
207  command.add(l01Path);
208  ProcessBuilder processBuilder = new ProcessBuilder(command);
209  processBuilder.directory(l01Dir);
210  try {
211  //redirect ewfexport stdout and stderr to txt file
212  Path logFileName = Paths.get(l01Dir.toString(), dirPath.toString() + LOG_FILE_EXTENSION);
213  File logFile = new File(logFileName.toString());
214  Path errFileName = Paths.get(l01Dir.toString(), dirPath.toString() + LOG_FILE_EXTENSION);
215  File errFile = new File(errFileName.toString());
216  processBuilder.redirectError(ProcessBuilder.Redirect.appendTo(errFile));
217  processBuilder.redirectOutput(ProcessBuilder.Redirect.appendTo(logFile));
218  // open the file with ewfexport to extract its contents
219  ExecUtil.execute(processBuilder, new ExecUtil.TimedProcessTerminator());
220  if (l01Dir.toPath().resolve(dirPath).toFile().exists()) {
221  extractedPaths.add(l01Dir.toPath().resolve(dirPath).toString());
222  } else { //if we failed to extract anything let the user know the L01 file was unable to be processed
223  throw new L01Exception("Can not process the selected L01 file, ewfExport was unable to extract any files from it.");
224  }
225 
226  } catch (SecurityException ex) {
227  throw new L01Exception("Security exception occcured while trying to extract l01 contents", ex);
228  } catch (IOException ex) {
229  throw new L01Exception("IOException occcured while trying to extract l01 contents", ex);
230  }
231  }
232  return extractedPaths;
233  }
234 
240  static FileFilter getLogicalEvidenceFilter() {
241  return LOGICAL_EVIDENCE_FILTER;
242  }
243 
252  private Path locateEwfexportExecutable() throws L01Exception {
253  // Must be running under a Windows operating system.
254  if (!PlatformUtil.isWindowsOS()) {
255  throw new L01Exception("L01 files are only supported on windows currently");
256  }
257 
258  // Build the expected path to either the 32-bit or 64-bit version of the
259  // ewfexport executable.
260  final File ewfRoot = InstalledFileLocator.getDefault().locate(EWFEXPORT_DIR, LocalFilesDSProcessor.class.getPackage().getName(), false);
261 
262  Path executablePath;
263  if (PlatformUtil.is64BitOS()) {
264  executablePath = Paths.get(
265  ewfRoot.getAbsolutePath(),
266  EWFEXPORT_64_BIT_DIR,
267  EWFEXPORT_WINDOWS_EXE);
268  } else {
269  executablePath = Paths.get(
270  ewfRoot.getAbsolutePath(),
271  EWFEXPORT_32_BIT_DIR,
272  EWFEXPORT_WINDOWS_EXE);
273  }
274 
275  // Make sure the executable exists at the expected location and that it
276  // can be run.
277  final File ewfexport = executablePath.toFile();
278  if (null == ewfexport || !ewfexport.exists()) {
279  throw new LocalFilesDSProcessor.L01Exception("EWF export executable was not found");
280  }
281  if (!ewfexport.canExecute()) {
282  throw new LocalFilesDSProcessor.L01Exception("EWF export executable can not be executed");
283  }
284 
285  return executablePath;
286  }
287 
311  public void run(String deviceId, String rootVirtualDirectoryName, List<String> localFilePaths, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
312  new Thread(new AddLocalFilesTask(deviceId, rootVirtualDirectoryName, localFilePaths, progressMonitor, callback)).start();
313  }
314 
325  @Override
326  public void cancel() {
327  }
328 
333  @Override
334  public void reset() {
335  configPanel.select();
336  localFilePaths = null;
337  setDataSourceOptionsCalled = false;
338  }
339 
340  @Override
341  public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
342  // Local files DSP can process any file by simply adding it as a logical file.
343  // It should return lowest possible non-zero confidence level and be treated
344  // as the "option of last resort" for auto ingest purposes
345 
346  List<String> filePaths = Arrays.asList(new String[]{dataSourcePath.toString()});
347  //If there is only 1 file check if it is an L01 file and if it is extract the
348  //contents and replace the paths, if the contents can't be extracted return 0
349  if (filePaths.size() == 1) {
350  for (final String path : filePaths) {
351  if (new File(path).isFile() && LOGICAL_EVIDENCE_FILTER.accept(new File(path))) {
352  try {
353  //if the L01 option was chosen
354  filePaths = extractLogicalEvidenceFileContents(filePaths);
355  } catch (L01Exception ex) {
356  logger.log(Level.WARNING, "File extension was .l01 but contents of logical evidence file were unable to be extracted", ex);
357  //contents of l01 could not be extracted don't add data source or run ingest
358  return 0;
359  } catch (NoCurrentCaseException ex) {
360  logger.log(Level.WARNING, "Exception while getting open case.", ex);
361  return 0;
362  }
363  }
364  }
365  }
366  return 1;
367  }
368 
369  @Override
370  public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
371  List<String> filePaths = Arrays.asList(new String[]{dataSourcePath.toString()});
372  run(deviceId, deviceId, filePaths, progressMonitor, callBack);
373  }
374 
386  @Deprecated
387  public void setDataSourceOptions(String paths) {
388  // The LocalFilesPanel used to separate file paths with a comma and pass
389  // them as a string, but because file names are allowed to contain
390  // commas, this approach was buggy and replaced. We now pass a list of
391  // String paths.
392  this.localFilePaths = Arrays.asList(paths.split(","));
393  setDataSourceOptionsCalled = true;
394  }
395 
399  private final class L01Exception extends Exception {
400 
401  private static final long serialVersionUID = 1L;
402 
403  L01Exception(final String message) {
404  super(message);
405  }
406 
407  L01Exception(final String message, final Throwable cause) {
408  super(message, cause);
409  }
410  }
411 
412 }
void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback)
static int execute(ProcessBuilder processBuilder)
Definition: ExecUtil.java:118
void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack)
void done(DataSourceProcessorResult result, List< String > errList, List< Content > newDataSources)
List< String > extractLogicalEvidenceFileContents(final List< String > logicalEvidenceFilePaths)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
void run(String deviceId, String rootVirtualDirectoryName, List< String > localFilePaths, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback)

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