use hostname in UNC paths for photorec

This commit is contained in:
Karl Mortensen 2015-07-28 12:30:08 -04:00
parent e8779a86fb
commit 428d0bd90a
2 changed files with 219 additions and 22 deletions

View File

@ -0,0 +1,198 @@
/*
* 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.concurrent.TimeUnit;
import java.util.logging.Level;
public class HandleUNC {
private static HandleUNC instance = null;
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 int MAX_LINE_SCANS = 500;
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;
/**
* Access method for singleton
*
* @return HandleUNC singleton object
*/
public synchronized static HandleUNC getInstance() {
if (instance == null) {
instance = new HandleUNC();
}
return instance;
}
/**
* Private constructor for singleton
*/
private HandleUNC() {
drives = getMappedDrives();
}
/**
* Try to substitute in the path for a UNC string.
*
* @param path the path to substitute.
* @return returns the original string if unsuccessful, the substituted
* string if successful.
*/
public String attemptUNCSubstitution(String path) {
return attemptUNCSubstitution(Paths.get(path)).toString();
}
/**
* Try to substitute in the path for a UNC string.
*
* @param path the path to substitute.
* @return returns the original string if unsuccessful, the substituted
* string if successful.
*/
public Path attemptUNCSubstitution(Path path) {
String uncPath = path.toString();
if (false == isUNC(path)) {
try {
String currentDrive = path.getRoot().toString().substring(STARTING_OFFSET, REPLACEMENT_SIZE);
String uncMapping = drives.get(currentDrive);
if (uncMapping != null) {
uncPath = uncMapping + uncPath.substring(REPLACEMENT_SIZE, uncPath.length());
}
} catch (Exception ex) {
// Didn't work. Skip it.
}
}
return Paths.get(uncPath);
}
/**
* Takes a UNC path that may have an IP address in it and converts it to
* hostname, if it can.
*
* @param inputPath the path to convert to a hostname UNC path
* @return the path that was passed in if it was hostname before, the
* converted path if it was successfully converted
*/
public Path ipToHostName(Path inputPath) {
return Paths.get(ipToHostName(inputPath.toString()));
}
/**
* Takes a UNC path that may have an IP address in it and converts it to
* hostname, if it can.
*
* @param inputPath the path to convert to a hostname UNC path
* @return the path that was passed in if it was hostname before, the
* converted path if it was successfully converted
*/
public String ipToHostName(String inputPath) {
String result = inputPath;
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) {
// We didn't find a hostname for this potential IP address. Move on.
}
return result;
}
/**
* Test if a String is UNC
*
* @param inputPath
* @return true if UNC, false otherwise
*/
public static boolean isUNC(Path inputPath) {
return isUNC(inputPath.toString());
}
/**
* Test if a Path is UNC
*
* @param inputPath
* @return true if UNC, false otherwise
*/
public static boolean isUNC(String inputPath) {
return inputPath.startsWith(UNC_PATH_START);
}
/**
* Populate the mapped drives
*
* @return the hashmap
*/
private static Map<String, String> getMappedDrives() {
Map<String, String> driveMap = new HashMap<>();
try {
File mappedDrive = new File(MAPPED_DRIVES);
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)) {
int safetyCount = 0;
// scan past the header information until we find trigger
while (scanner.hasNext() && !scanner.nextLine().equals(DATA_TRIGGER)) {
if (++safetyCount > MAX_LINE_SCANS) {
break;
}
}
// parse the data and place it in the hashmap
while (scanner.hasNext()) {
String entry1 = scanner.next();
String entry2 = scanner.next();
String entry3 = scanner.next();
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
}
}
}
Files.deleteIfExists(mappedDrive.toPath());
} catch (IOException | InterruptedException ex) {
// if we couldn't do it, no big deal
Logger.getLogger(HandleUNC.class.getName()).log(Level.WARNING, "Unable to parse 'net use' output", ex); //NON-NLS
}
return driveMap;
}
}

View File

@ -58,6 +58,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.HandleUNC;
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 +68,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 {
@ -122,8 +124,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 +233,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 +265,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 +291,23 @@ 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 static Path createModuleOutputDirectoryForCase() throws IngestModule.IngestModuleException {
Path path = Paths.get(Case.getCurrentCase().getModuleDirectory(), PhotoRecCarverIngestModuleFactory.getModuleName()); Path path = Paths.get(Case.getCurrentCase().getModuleDirectory(), PhotoRecCarverIngestModuleFactory.getModuleName());
if (HandleUNC.isUNC(path)) {
// if the UNC path is using an IP address, convert to hostname
path = HandleUNC.getInstance().ipToHostName(path);
}
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 +331,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;