Merge pull request #1468 from karlmortensen/hostname_not_ip

use hostname in UNC paths for photorec
This commit is contained in:
Richard Cordovano 2015-07-30 14:31:29 -04:00
commit 6a0a4fd4cb
9 changed files with 381 additions and 69 deletions

View File

@ -244,16 +244,16 @@ CollaborationMonitor.addingDataSourceStatus.msg={0} adding data source
CollaborationMonitor.analyzingDataSourceStatus.msg={0} analyzing {1} CollaborationMonitor.analyzingDataSourceStatus.msg={0} analyzing {1}
MissingImageDialog.lbWarning.text= MissingImageDialog.lbWarning.text=
MissingImageDialog.lbWarning.toolTipText= MissingImageDialog.lbWarning.toolTipText=
CaseConverter.AlreadyMultiUser=Case is already multi-user! SingleUserCaseImporter.AlreadyMultiUser=Case is already multi-user!
CaseConverter.FinishedConverting=Finished converting SingleUserCaseImporter.FinishedConverting=Finished converting
CaseConverter.To= to SingleUserCaseImporter.To=to
CaseConverter.BadCaseSourceFolder=Case source folder does not exist! SingleUserCaseImporter.BadCaseSourceFolder=Case source folder does not exist!
CaseConverter.BadImageSourceFolder=Image source folder does not exist! SingleUserCaseImporter.BadImageSourceFolder=Image source folder does not exist!
CaseConverter.BadDatabaseFileName=Database file does not exist! SingleUserCaseImporter.BadDatabaseFileName=Database file does not exist!
CaseConverter.NonUniqueOutputFolder=Output folder not unique. Skipping SingleUserCaseImporter.NonUniqueOutputFolder=Output folder not unique. Skipping
CaseConverter.NonUniqueDatabaseName=Database name not unique. Skipping. SingleUserCaseImporter.NonUniqueDatabaseName=Database name not unique. Skipping.
CaseConverter.PotentiallyNonUniqueDatabaseName=Unclear if database name unique. Moving ahead. SingleUserCaseImporter.PotentiallyNonUniqueDatabaseName=Unclear if database name unique. Moving ahead.
CaseConverter.ConvertedToMultiUser=This case was converted to a Multi-user collaborative case on SingleUserCaseImporter.ConvertedToMultiUser=This case was converted to a Multi-user collaborative case on
CaseConverter.UnableToCopySourceImages=Unable to copy source images SingleUserCaseImporter.UnableToCopySourceImages=Unable to copy source images
CaseConverter.ConversionSuccessful=. Conversion successful: SingleUserCaseImporter.ConversionSuccessful=. Conversion successful:
CaseConverter.DeletingCase=Deleting original case folder SingleUserCaseImporter.DeletingCase=Deleting original case folder

View File

@ -255,7 +255,7 @@ public class Case {
private final static String CACHE_FOLDER = "Cache"; //NON-NLS private final static String CACHE_FOLDER = "Cache"; //NON-NLS
private final static String EXPORT_FOLDER = "Export"; //NON-NLS private final static String EXPORT_FOLDER = "Export"; //NON-NLS
private final static String LOG_FOLDER = "Log"; //NON-NLS private final static String LOG_FOLDER = "Log"; //NON-NLS
private final static String MODULE_FOLDER = "ModuleOutput"; //NON-NLS final static String MODULE_FOLDER = "ModuleOutput"; //NON-NLS
private final static String REPORTS_FOLDER = "Reports"; //NON-NLS private final static String REPORTS_FOLDER = "Reports"; //NON-NLS
private final static String TEMP_FOLDER = "Temp"; //NON-NLS private final static String TEMP_FOLDER = "Temp"; //NON-NLS

View File

@ -44,6 +44,7 @@ import org.apache.commons.io.FileUtils;
import org.openide.util.Exceptions; import org.openide.util.Exceptions;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.Case.CaseType;
import static org.sleuthkit.autopsy.casemodule.Case.MODULE_FOLDER;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.CaseDbConnectionInfo; import org.sleuthkit.datamodel.CaseDbConnectionInfo;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
@ -59,9 +60,10 @@ public class SingleUserCaseImporter implements Runnable {
private static final String DOTAUT = ".aut"; //NON-NLS private static final String DOTAUT = ".aut"; //NON-NLS
public static final String CASE_CONVERSION_LOG_FILE = "case_import_log.txt"; //NON-NLS public static final String CASE_CONVERSION_LOG_FILE = "case_import_log.txt"; //NON-NLS
private static final String logDateFormat = "yyyy/MM/dd HH:mm:ss"; //NON-NLS private static final String logDateFormat = "yyyy/MM/dd HH:mm:ss"; //NON-NLS
//If TIMELINE_FOLDER changes, also update TIMELINE in EventsRepository
private static final String TIMELINE_FOLDER = "Timeline"; //NON-NLS private static final String TIMELINE_FOLDER = "Timeline"; //NON-NLS
//If TIMELINE_FILE changes, also update TIMELINE_FILE in EventDB
private final static String TIMELINE_FILE = "events.db"; //NON-NLS private final static String TIMELINE_FILE = "events.db"; //NON-NLS
private static final String MODULE_FOLDER = "ModuleOutput"; //NON-NLS
private final static String AIM_LOG_FILE_NAME = "auto_ingest_log.txt"; //NON-NLS private final static String AIM_LOG_FILE_NAME = "auto_ingest_log.txt"; //NON-NLS
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(logDateFormat); private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(logDateFormat);
private static final int MAX_DB_NAME_LENGTH = 63; private static final int MAX_DB_NAME_LENGTH = 63;
@ -79,7 +81,7 @@ public class SingleUserCaseImporter implements Runnable {
private XMLCaseManagement newXmlCaseManagement; private XMLCaseManagement newXmlCaseManagement;
/** /**
* CaseConverter constructor * SingleUserCaseImporter constructor
* *
* @param caseInput the folder to start our case search from. Will find * @param caseInput the folder to start our case search from. Will find
* valid cases from this folder down, and process them. * valid cases from this folder down, and process them.
@ -138,7 +140,7 @@ public class SingleUserCaseImporter implements Runnable {
// read old xml config // read old xml config
oldXmlCaseManagement.open(input.resolve(oldCaseName + DOTAUT).toString()); oldXmlCaseManagement.open(input.resolve(oldCaseName + DOTAUT).toString());
if (oldXmlCaseManagement.getCaseType() == CaseType.MULTI_USER_CASE) { if (oldXmlCaseManagement.getCaseType() == CaseType.MULTI_USER_CASE) {
throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.AlreadyMultiUser")); throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.AlreadyMultiUser"));
} }
String newCaseFolder = prepareOutput(caseOutputFolder, oldCaseFolder); String newCaseFolder = prepareOutput(caseOutputFolder, oldCaseFolder);
@ -177,12 +179,12 @@ public class SingleUserCaseImporter implements Runnable {
// and database in the given directory so the user shouldn't be able to accidently blow away // and database in the given directory so the user shouldn't be able to accidently blow away
// their C drive. // their C drive.
if (deleteCase) { if (deleteCase) {
log(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.DeletingCase") + " " + input); log(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.DeletingCase") + " " + input);
FileUtils.deleteDirectory(input.toFile()); FileUtils.deleteDirectory(input.toFile());
} }
log(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.FinishedConverting") log(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.FinishedConverting")
+ input.toString() + NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.To") + input.toString() + " " + NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.To")
+ caseOutputFolder + File.separatorChar + newCaseFolder); + caseOutputFolder + File.separatorChar + newCaseFolder);
} catch (Exception exp) { } catch (Exception exp) {
/// clean up here /// clean up here
@ -202,13 +204,13 @@ public class SingleUserCaseImporter implements Runnable {
*/ */
private void checkInput(File caseInput, File imageInput) throws Exception { private void checkInput(File caseInput, File imageInput) throws Exception {
if (false == caseInput.exists()) { if (false == caseInput.exists()) {
throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.BadCaseSourceFolder")); throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.BadCaseSourceFolder"));
} else if ((imageInput != null) && (false == imageInput.exists())) { } else if ((imageInput != null) && (false == imageInput.exists())) {
throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.BadImageSourceFolder")); throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.BadImageSourceFolder"));
} }
Path path = Paths.get(caseInput.toString(), AUTOPSY_DB_FILE); Path path = Paths.get(caseInput.toString(), AUTOPSY_DB_FILE);
if (false == path.toFile().exists()) { if (false == path.toFile().exists()) {
throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.BadDatabaseFileName")); throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.BadDatabaseFileName"));
} }
} }
@ -236,7 +238,7 @@ public class SingleUserCaseImporter implements Runnable {
while (specificOutputFolder.exists()) { while (specificOutputFolder.exists()) {
if (number == Integer.MAX_VALUE) { if (number == Integer.MAX_VALUE) {
// oops. it never became unique. give up. // oops. it never became unique. give up.
throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.NonUniqueOutputFolder") + caseFolder); throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.NonUniqueOutputFolder") + caseFolder);
} }
temp = sanitizedCaseName + "_" + Integer.toString(number) + timeStamp; //NON-NLS temp = sanitizedCaseName + "_" + Integer.toString(number) + timeStamp; //NON-NLS
specificOutputFolder = Paths.get(caseOutputFolder, temp).toFile(); specificOutputFolder = Paths.get(caseOutputFolder, temp).toFile();
@ -280,7 +282,7 @@ public class SingleUserCaseImporter implements Runnable {
destination = Paths.get(caseOutputFolder, newCaseFolder, AIM_LOG_FILE_NAME); destination = Paths.get(caseOutputFolder, newCaseFolder, AIM_LOG_FILE_NAME);
FileUtils.copyFile(source.toFile(), destination.toFile()); FileUtils.copyFile(source.toFile(), destination.toFile());
try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(destination.toString(), true)))) { try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(destination.toString(), true)))) {
out.println(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.ConvertedToMultiUser") + new Date()); out.println(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.ConvertedToMultiUser") + new Date());
} catch (IOException e) { } catch (IOException e) {
// if unable to log it, no problem // if unable to log it, no problem
} }
@ -959,7 +961,7 @@ public class SingleUserCaseImporter implements Runnable {
// not unique. add numbers before dbName. // not unique. add numbers before dbName.
if (number == Integer.MAX_VALUE) { if (number == Integer.MAX_VALUE) {
// oops. it never became unique. give up. // oops. it never became unique. give up.
throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.NonUniqueDatabaseName")); throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.NonUniqueDatabaseName"));
} }
sanitizedDbName = "_" + Integer.toString(number) + "_" + baseDbName; //NON-NLS sanitizedDbName = "_" + Integer.toString(number) + "_" + baseDbName; //NON-NLS
@ -974,7 +976,7 @@ public class SingleUserCaseImporter implements Runnable {
} else { } else {
// Could be caused by database credentials, using user accounts that // Could be caused by database credentials, using user accounts that
// can not check if other databases exist, so allow it to continue // can not check if other databases exist, so allow it to continue
log(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.PotentiallyNonUniqueDatabaseName")); log(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.PotentiallyNonUniqueDatabaseName"));
} }
return sanitizedDbName; return sanitizedDbName;
@ -1007,7 +1009,7 @@ public class SingleUserCaseImporter implements Runnable {
if (chosenInput != null && chosenInput.exists()) { if (chosenInput != null && chosenInput.exists()) {
FileUtils.copyDirectory(chosenInput, output); FileUtils.copyDirectory(chosenInput, output);
} else { } else {
log(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.UnableToCopySourceImages")); log(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.UnableToCopySourceImages"));
} }
return chosenInput; return chosenInput;
} }
@ -1195,11 +1197,11 @@ public class SingleUserCaseImporter implements Runnable {
* not. True if all was successful, false otherwise. * not. True if all was successful, false otherwise.
*/ */
private void closeLog(boolean result) { private void closeLog(boolean result) {
log(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.FinishedConverting") log(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.FinishedConverting")
+ caseInputFolder + caseInputFolder + " "
+ NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.To") + NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.To")
+ caseOutputFolder + caseOutputFolder
+ NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.ConversionSuccessful") + NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.ConversionSuccessful")
+ result); + result);
if (writer != null) { if (writer != null) {

View File

@ -0,0 +1,299 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.coreutils;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
public class UNCPathUtilities {
private static Map<String, String> drives;
private static final String MAPPED_DRIVES = "_mapped_drives.txt"; //NON-NLS
private static final String DATA_TRIGGER = "----------"; //NON-NLS
private static final String OK_TXT = "OK"; //NON-NLS
private static final String COLON = ":"; //NON-NLS
private static final String UNC_PATH_START = "\\\\"; //NON-NLS
private static final String C_DRIVE = "C:"; //NON-NLS
private static final int DRIVE_LEN = 2;
private static final int STARTING_OFFSET = 0;
private static final int REPLACEMENT_SIZE = 2;
private static final int FIRST_ITEM = 0;
private final String nameString;
/**
* Constructor
*/
public UNCPathUtilities() {
// get UUID for this instance
this.nameString = UUID.randomUUID().toString();
drives = getMappedDrives();
}
/**
* This method converts a passed in path to UNC if it is not already UNC.
* The UNC path will end up in one of the following two forms:
* \\hostname\somefolder\otherfolder or \\IP_ADDRESS\somefolder\otherfolder
*
* This is accomplished by checking the mapped drives list the operating
* system maintains and substituting where required. If the drive of the
* path passed in does not exist in the cached mapped drives list, you can
* force a rescan of the mapped drives list with rescanDrives(), then call
* this method again. This would be of use if the end user added a mapped
* drive while your dialog was up, for example.
*
* @param inputPath a String of the path to convert
* @return returns a successfully converted inputPath or null if unable to
* find a matching drive and convert it to UNC
*/
synchronized public String mappedDriveToUNC(String inputPath) {
if (inputPath != null) {
// If it is a C:, do not attempt to convert. This is for the single-user case.
if (inputPath.toUpperCase().startsWith(C_DRIVE)) {
return null;
}
if (false == isUNC(inputPath)) {
String uncPath = null;
try {
String currentDrive = Paths.get(inputPath).getRoot().toString().substring(STARTING_OFFSET, REPLACEMENT_SIZE);
String uncMapping = drives.get(currentDrive);
if (uncMapping != null) {
uncPath = uncMapping + inputPath.substring(REPLACEMENT_SIZE, inputPath.length());
}
} catch (Exception ex) {
// Didn't work. Skip it.
}
return uncPath;
} else {
return inputPath;
}
} else {
return null;
}
}
/**
* This method converts a passed in path to UNC if it is not already UNC.
* The UNC path will end up in one of the following two forms:
* \\hostname\somefolder\otherfolder or \\IP_ADDRESS\somefolder\otherfolder
*
* This is accomplished by checking the mapped drives list the operating
* system maintains and substituting where required. If the drive of the
* path passed in does not exist in the cached mapped drives list, you can
* force a rescan of the mapped drives list with rescanDrives(), then call
* this method again. This would be of use if the end user added a mapped
* drive while your dialog was up, for example.
*
* @param inputPath the path to convert
* @return returns a successfully converted inputPath or null if unable to
* find a matching drive and convert it to UNC
*/
synchronized public Path mappedDriveToUNC(Path inputPath) {
if (inputPath != null) {
String uncPath = UNCPathUtilities.this.mappedDriveToUNC(inputPath.toString());
if (uncPath == null) {
return null;
} else {
return Paths.get(uncPath);
}
} else {
return null;
}
}
/**
* Tests if the drive in the passed in path is a mapped drive.
*
* @param inputPath the Path to test.
* @return true if the passed in drive is mapped, false otherwise
*/
synchronized public boolean isDriveMapped(Path inputPath) {
if (inputPath != null) {
return isDriveMapped(inputPath.toString());
} else {
return false;
}
}
/**
* Tests if the drive in the passed in path is a mapped drive.
*
* @param inputPath the Path to test.
* @return true if the passed in drive is mapped, false otherwise
*/
synchronized public boolean isDriveMapped(String inputPath) {
if (inputPath != null) {
String shortenedPath = inputPath.substring(STARTING_OFFSET, DRIVE_LEN);
for (String s : drives.keySet()) {
if (shortenedPath.equals(s)) {
return true;
}
}
}
return false;
}
/**
* Takes a UNC path that may have an IP address in it and converts it to
* hostname, if it can resolve the hostname. Given
* \\10.11.12.13\some\folder, the result will be \\TEDS_COMPUTER\some\folder
* if the IP address 10.11.12.13 belongs to a machine with the hostname
* TEDS_COMPUTER and the local machine is able to resolve the hostname.
*
* @param inputPath the path to convert to a hostname UNC path
* @return the successfully converted path or null if unable to resolve
*/
synchronized public Path ipToHostName(Path inputPath) {
if (inputPath != null) {
return Paths.get(ipToHostName(inputPath.toString()));
} else {
return null;
}
}
/**
* Takes a UNC path that may have an IP address in it and converts it to
* hostname, if it can resolve the hostname. Given
* \\10.11.12.13\some\folder, the result will be \\TEDS_COMPUTER\some\folder
* if the IP address 10.11.12.13 belongs to a machine with the hostname
* TEDS_COMPUTER and the local machine is able to resolve the hostname.
*
* @param inputPath a String of the path to convert to a hostname UNC path
* @return the successfully converted path or null if unable to resolve
*/
synchronized public String ipToHostName(String inputPath) {
if (inputPath != null) {
String result = null;
try {
if (isUNC(Paths.get(inputPath))) {
String potentialIP = Paths.get(inputPath.substring(REPLACEMENT_SIZE)).getName(FIRST_ITEM).toString();
String hostname = InetAddress.getByName(potentialIP).getHostName();
result = inputPath.replaceAll(potentialIP, hostname);
}
} catch (Exception ex) {
// Could not resolve hostname for IP address, return null result
}
return result;
} else {
return null;
}
}
/**
* Test if a Path is UNC. It is considered UNC if it begins with \\
*
* @param inputPath the path to check
* @return true if the passed in Path is UNC, false otherwise
*/
synchronized public static boolean isUNC(Path inputPath) {
if (inputPath != null) {
return isUNC(inputPath.toString());
} else {
return false;
}
}
/**
* Test if a String path is UNC. It is considered UNC if it begins with \\
*
* @param inputPath the String of the path to check
* @return true if the passed in Path is UNC, false otherwise
*/
synchronized public static boolean isUNC(String inputPath) {
if (inputPath != null) {
return inputPath.startsWith(UNC_PATH_START);
} else {
return false;
}
}
/**
* Updates the list of mapped drives this class contains. This list is used
* to resolve mappedDriveToUNC and isDriveMapped calls. This is useful to
* call if the user has potentially added mapped drives to their system
* after the module calling mappedDriveToUNC has already begun running. Note
* this uses system I/O, so call it with some care.
*
*/
synchronized public void rescanDrives() {
drives = getMappedDrives();
}
/**
* Populates the list of mapped drives this class contains. The list is used
* to resolve mappedDriveToUNC and isDriveMapped calls. Note this uses
* system I/O, so call it with some care.
*
* @return the hashmap
*/
synchronized private Map<String, String> getMappedDrives() {
Map<String, String> driveMap = new HashMap<>();
File mappedDrive = new File(nameString + MAPPED_DRIVES);
try {
Files.deleteIfExists(mappedDrive.toPath());
ProcessBuilder builder = new ProcessBuilder("cmd", "/c", "net", "use"); //NON-NLS
builder.redirectOutput(mappedDrive);
builder.redirectError(mappedDrive);
Process p = builder.start(); // throws IOException
p.waitFor(10, TimeUnit.SECONDS);
try (Scanner scanner = new Scanner(mappedDrive)) {
// parse the data and place it in the hashmap
while (scanner.hasNext()) {
String entry1 = scanner.next();
if (entry1.startsWith(DATA_TRIGGER)) {
continue;
}
String entry2 = scanner.next();
if (entry2.startsWith(DATA_TRIGGER)) {
continue;
}
String entry3 = scanner.next();
if (entry3.startsWith(DATA_TRIGGER)) {
continue;
}
scanner.nextLine();
if (entry1.length() == DRIVE_LEN && !entry1.equals(OK_TXT) && entry1.endsWith(COLON)) {
driveMap.put(entry1, entry2); // if there was no leading status, populate drive
} else if (entry2.length() == DRIVE_LEN && entry2.endsWith(COLON)) {
driveMap.put(entry2, entry3); // if there was a leading status, populate drive
}
}
}
} catch (IOException | InterruptedException ex) {
// if we couldn't do it, no big deal
Logger.getLogger(UNCPathUtilities.class.getName()).log(Level.WARNING, "Unable to parse 'net use' output", ex); //NON-NLS
} finally {
try {
Files.deleteIfExists(mappedDrive.toPath());
} catch (IOException ex) {
// if we couldn't do it, no big deal
}
}
return driveMap;
}
}

View File

@ -10,6 +10,7 @@ unsupportedOS.message=PhotoRec Module is supported only on Windows platforms
missingExecutable.message=Unable to locate PhotoRec executable. missingExecutable.message=Unable to locate PhotoRec executable.
cannotRunExecutable.message=Unable to execute PhotoRec cannotRunExecutable.message=Unable to execute PhotoRec
cannotCreateOutputDir.message=Unable to create output directory: {0} cannotCreateOutputDir.message=Unable to create output directory: {0}
PhotoRecIngestModule.nonHostnameUNCPathUsed=Photorec cannot operate on a UNC path containing IP addresses
PhotoRecIngestModule.processTerminated=PhotoRec Carver ingest module was terminated due to exceeding max allowable run time when scanning PhotoRecIngestModule.processTerminated=PhotoRec Carver ingest module was terminated due to exceeding max allowable run time when scanning
PhotoRecIngestModule.moduleError=PhotoRec Carver Module Error PhotoRecIngestModule.moduleError=PhotoRec Carver Module Error
PhotoRecIngestModule.UnableToCarve=Unable to carve file: {0} PhotoRecIngestModule.UnableToCarve=Unable to carve file: {0}

View File

@ -38,18 +38,12 @@ import org.openide.modules.InstalledFileLocator;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.ExecUtil; import org.sleuthkit.autopsy.coreutils.ExecUtil;
import org.sleuthkit.autopsy.coreutils.FileUtil;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.FileIngestModuleProcessTerminator;
import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.ingest.IngestModule; import org.sleuthkit.autopsy.ingest.IngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.Image;
@ -58,6 +52,7 @@ import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.Volume; import org.sleuthkit.datamodel.Volume;
import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.FileUtil;
import org.sleuthkit.autopsy.coreutils.UNCPathUtilities;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.ingest.ProcTerminationCode; import org.sleuthkit.autopsy.ingest.ProcTerminationCode;
@ -67,7 +62,8 @@ import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
/** /**
* A file ingest module that runs the Unallocated Carver executable with unallocated space files as input. * A file ingest module that runs the Unallocated Carver executable with
* unallocated space files as input.
*/ */
final class PhotoRecCarverFileIngestModule implements FileIngestModule { final class PhotoRecCarverFileIngestModule implements FileIngestModule {
@ -85,6 +81,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule {
private Path rootOutputDirPath; private Path rootOutputDirPath;
private File executableFile; private File executableFile;
private IngestServices services; private IngestServices services;
private UNCPathUtilities uncPathUtilities = new UNCPathUtilities();
/** /**
* @inheritDoc * @inheritDoc
@ -102,7 +99,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule {
throw new IngestModule.IngestModuleException(NbBundle.getMessage(this.getClass(), "unallocatedSpaceProcessingSettingsError.message")); throw new IngestModule.IngestModuleException(NbBundle.getMessage(this.getClass(), "unallocatedSpaceProcessingSettingsError.message"));
} }
this.rootOutputDirPath = PhotoRecCarverFileIngestModule.createModuleOutputDirectoryForCase(); this.rootOutputDirPath = createModuleOutputDirectoryForCase();
Path execName = Paths.get(PHOTOREC_DIRECTORY, PHOTOREC_EXECUTABLE); Path execName = Paths.get(PHOTOREC_DIRECTORY, PHOTOREC_EXECUTABLE);
executableFile = locateExecutable(execName.toString()); executableFile = locateExecutable(execName.toString());
@ -122,8 +119,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule {
// Save the directories for the current job. // Save the directories for the current job.
PhotoRecCarverFileIngestModule.pathsByJob.put(this.context.getJobId(), new WorkingPaths(outputDirPath, tempDirPath)); PhotoRecCarverFileIngestModule.pathsByJob.put(this.context.getJobId(), new WorkingPaths(outputDirPath, tempDirPath));
} } catch (SecurityException | IOException | UnsupportedOperationException ex) {
catch (SecurityException | IOException | UnsupportedOperationException ex) {
throw new IngestModule.IngestModuleException(NbBundle.getMessage(this.getClass(), "cannotCreateOutputDir.message", ex.getLocalizedMessage())); throw new IngestModule.IngestModuleException(NbBundle.getMessage(this.getClass(), "cannotCreateOutputDir.message", ex.getLocalizedMessage()));
} }
} }
@ -232,13 +228,10 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule {
context.addFilesToJob(new ArrayList<>(theList)); context.addFilesToJob(new ArrayList<>(theList));
services.fireModuleContentEvent(new ModuleContentEvent(theList.get(0))); // fire an event to update the tree services.fireModuleContentEvent(new ModuleContentEvent(theList.get(0))); // fire an event to update the tree
} }
} } catch (IOException ex) {
catch (IOException ex) {
logger.log(Level.SEVERE, "Error processing " + file.getName() + " with PhotoRec carver", ex); // NON-NLS logger.log(Level.SEVERE, "Error processing " + file.getName() + " with PhotoRec carver", ex); // NON-NLS
return IngestModule.ProcessResult.ERROR; return IngestModule.ProcessResult.ERROR;
} } finally {
finally {
if (null != tempFilePath && Files.exists(tempFilePath)) { if (null != tempFilePath && Files.exists(tempFilePath)) {
// Get rid of the unallocated space file. // Get rid of the unallocated space file.
tempFilePath.toFile().delete(); tempFilePath.toFile().delete();
@ -267,8 +260,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule {
// the working paths map entry for the job and deletes the temp dir. // the working paths map entry for the job and deletes the temp dir.
WorkingPaths paths = PhotoRecCarverFileIngestModule.pathsByJob.remove(this.context.getJobId()); WorkingPaths paths = PhotoRecCarverFileIngestModule.pathsByJob.remove(this.context.getJobId());
FileUtil.deleteDir(new File(paths.getTempDirPath().toString())); FileUtil.deleteDir(new File(paths.getTempDirPath().toString()));
} } catch (SecurityException ex) {
catch (SecurityException ex) {
logger.log(Level.SEVERE, "Error shutting down PhotoRec carver module", ex); // NON-NLS logger.log(Level.SEVERE, "Error shutting down PhotoRec carver module", ex); // NON-NLS
} }
} }
@ -294,20 +286,26 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule {
} }
/** /**
* Creates the output directory for this module for the current case, if it does not already exist. * Creates the output directory for this module for the current case, if it
* does not already exist.
* *
* @return The absolute path of the output directory. * @return The absolute path of the output directory.
* @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException * @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException
*/ */
synchronized static Path createModuleOutputDirectoryForCase() throws IngestModule.IngestModuleException { synchronized Path createModuleOutputDirectoryForCase() throws IngestModule.IngestModuleException {
Path path = Paths.get(Case.getCurrentCase().getModuleDirectory(), PhotoRecCarverIngestModuleFactory.getModuleName()); Path path = Paths.get(Case.getCurrentCase().getModuleDirectory(), PhotoRecCarverIngestModuleFactory.getModuleName());
if (UNCPathUtilities.isUNC(path)) {
// if the UNC path is using an IP address, convert to hostname
path = uncPathUtilities.ipToHostName(path);
if (path == null) {
throw new IngestModule.IngestModuleException(NbBundle.getMessage(PhotoRecCarverFileIngestModule.class, "PhotoRecIngestModule.nonHostnameUNCPathUsed"));
}
}
try { try {
Files.createDirectory(path); Files.createDirectory(path);
} } catch (FileAlreadyExistsException ex) {
catch (FileAlreadyExistsException ex) {
// No worries. // No worries.
} } catch (IOException | SecurityException | UnsupportedOperationException ex) {
catch (IOException | SecurityException | UnsupportedOperationException ex) {
throw new IngestModule.IngestModuleException(NbBundle.getMessage(PhotoRecCarverFileIngestModule.class, "cannotCreateOutputDir.message", ex.getLocalizedMessage())); throw new IngestModule.IngestModuleException(NbBundle.getMessage(PhotoRecCarverFileIngestModule.class, "cannotCreateOutputDir.message", ex.getLocalizedMessage()));
} }
return path; return path;
@ -331,8 +329,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule {
} }
parent = parent.getParent(); parent = parent.getParent();
} }
} } catch (TskCoreException ex) {
catch (TskCoreException ex) {
logger.log(Level.SEVERE, "PhotoRec carver exception while trying to get parent of AbstractFile.", ex); //NON-NLS logger.log(Level.SEVERE, "PhotoRec carver exception while trying to get parent of AbstractFile.", ex); //NON-NLS
} }
return id; return id;

View File

@ -108,6 +108,9 @@ public class EventDB {
private static final String WAS_INGEST_RUNNING_KEY = "was_ingest_running"; // NON-NLS private static final String WAS_INGEST_RUNNING_KEY = "was_ingest_running"; // NON-NLS
//If EVENTS_DATABASE changes, also update TIMELINE_FILE in SingleUserCaseImporter
private static final String TIMELINE_FILE = "events.db"; // NON-NLS
static { static {
//make sure sqlite driver is loaded // possibly redundant //make sure sqlite driver is loaded // possibly redundant
try { try {
@ -128,7 +131,7 @@ public class EventDB {
*/ */
public static EventDB getEventDB(String dbPath) { public static EventDB getEventDB(String dbPath) {
try { try {
EventDB eventDB = new EventDB(dbPath + File.separator + "events.db"); // NON-NLS EventDB eventDB = new EventDB(dbPath + File.separator + TIMELINE_FILE); // NON-NLS
return eventDB; return eventDB;
} catch (SQLException ex) { } catch (SQLException ex) {

View File

@ -94,6 +94,7 @@ public class EventsRepository {
private final LoadingCache<ZoomParams, List<AggregateEvent>> aggregateEventsCache; private final LoadingCache<ZoomParams, List<AggregateEvent>> aggregateEventsCache;
//If TIMELINE changes, also update TIMELINE_FOLDER in SingleUserCaseImporter
private static final String TIMELINE = "Timeline"; private static final String TIMELINE = "Timeline";
public Interval getBoundingEventsInterval(Interval timeRange, Filter filter) { public Interval getBoundingEventsInterval(Interval timeRange, Filter filter) {

View File

@ -63,6 +63,7 @@ import org.apache.solr.client.solrj.response.CoreAdminResponse;
import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.Case.CaseType;
import org.sleuthkit.autopsy.coreutils.UNCPathUtilities;
import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
@ -167,6 +168,7 @@ public class Server {
private int currentSolrServerPort = 0; private int currentSolrServerPort = 0;
private int currentSolrStopPort = 0; private int currentSolrStopPort = 0;
private static final boolean DEBUG = false;//(Version.getBuildType() == Version.Type.DEVELOPMENT); private static final boolean DEBUG = false;//(Version.getBuildType() == Version.Type.DEVELOPMENT);
private final UNCPathUtilities uncPathUtilities = new UNCPathUtilities();
public enum CORE_EVT_STATES { public enum CORE_EVT_STATES {
@ -650,10 +652,17 @@ public class Server {
* @return absolute path to index dir * @return absolute path to index dir
*/ */
String getIndexDirPath(Case theCase) { String getIndexDirPath(Case theCase) {
String indexDir = theCase.getModuleDirectory() + String indexDir = theCase.getModuleDirectory() + File.separator + "keywordsearch" + File.separator + "data"; //NON-NLS
File.separator + "keywordsearch" + File.separator + "data"; //NON-NLS String result = uncPathUtilities.mappedDriveToUNC(indexDir);
if (result == null) {
uncPathUtilities.rescanDrives();
result = uncPathUtilities.mappedDriveToUNC(indexDir);
}
if (result == null) {
return indexDir; return indexDir;
} }
return result;
}
/** /**
* ** end single-case specific methods *** * ** end single-case specific methods ***