From 428d0bd90ae65f8ca235edfdd2a19f40967da450 Mon Sep 17 00:00:00 2001 From: Karl Mortensen Date: Tue, 28 Jul 2015 12:30:08 -0400 Subject: [PATCH 1/6] use hostname in UNC paths for photorec --- .../autopsy/coreutils/HandleUNC.java | 198 ++++++++++++++++++ .../PhotoRecCarverFileIngestModule.java | 43 ++-- 2 files changed, 219 insertions(+), 22 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/coreutils/HandleUNC.java diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/HandleUNC.java b/Core/src/org/sleuthkit/autopsy/coreutils/HandleUNC.java new file mode 100644 index 0000000000..69fae50e8c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/coreutils/HandleUNC.java @@ -0,0 +1,198 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit 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 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 getMappedDrives() { + Map 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; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java index dc7cd0eeff..98a9c3fef8 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java @@ -58,6 +58,7 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.Volume; import org.sleuthkit.autopsy.coreutils.FileUtil; +import org.sleuthkit.autopsy.coreutils.HandleUNC; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.ingest.ProcTerminationCode; @@ -67,7 +68,8 @@ import org.sleuthkit.autopsy.ingest.IngestServices; 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 { @@ -85,7 +87,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { private Path rootOutputDirPath; private File executableFile; private IngestServices services; - + /** * @inheritDoc */ @@ -122,8 +124,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { // Save the directories for the current job. 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())); } } @@ -188,10 +189,10 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { processAndSettings.environment().put("__COMPAT_LAYER", "RunAsInvoker"); //NON-NLS processAndSettings.redirectErrorStream(true); processAndSettings.redirectOutput(Redirect.appendTo(log)); - + FileIngestModuleProcessTerminator terminator = new FileIngestModuleProcessTerminator(this.context, true); int exitValue = ExecUtil.execute(processAndSettings, terminator); - + if (this.context.fileIngestIsCancelled() == true) { // if it was cancelled by the user, result is OK cleanup(outputDirPath, tempFilePath); @@ -224,7 +225,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { } } } - + // Now that we've cleaned up the folders and data files, parse the xml output file to add carved items into the database PhotoRecCarverOutputParser parser = new PhotoRecCarverOutputParser(outputDirPath); List theList = parser.parse(newAuditFile, id, file); @@ -232,13 +233,10 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { context.addFilesToJob(new ArrayList<>(theList)); 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 return IngestModule.ProcessResult.ERROR; - } - - finally { + } finally { if (null != tempFilePath && Files.exists(tempFilePath)) { // Get rid of the unallocated space file. tempFilePath.toFile().delete(); @@ -247,7 +245,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { return IngestModule.ProcessResult.OK; } - + private void cleanup(Path outputDirPath, Path tempFilePath) { // cleanup the output path FileUtil.deleteDir(new File(outputDirPath.toString())); @@ -267,8 +265,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { // the working paths map entry for the job and deletes the temp dir. WorkingPaths paths = PhotoRecCarverFileIngestModule.pathsByJob.remove(this.context.getJobId()); 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 } } @@ -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. * @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException */ synchronized static Path createModuleOutputDirectoryForCase() throws IngestModule.IngestModuleException { 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 { Files.createDirectory(path); - } - catch (FileAlreadyExistsException ex) { + } catch (FileAlreadyExistsException ex) { // No worries. - } - catch (IOException | SecurityException | UnsupportedOperationException ex) { + } catch (IOException | SecurityException | UnsupportedOperationException ex) { throw new IngestModule.IngestModuleException(NbBundle.getMessage(PhotoRecCarverFileIngestModule.class, "cannotCreateOutputDir.message", ex.getLocalizedMessage())); } return path; @@ -331,8 +331,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { } 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 } return id; From d1473d0addc764b189b780f97bf8882207352fa1 Mon Sep 17 00:00:00 2001 From: Karl Mortensen Date: Tue, 28 Jul 2015 12:35:54 -0400 Subject: [PATCH 2/6] Solr now tries to use UNC path if it can when opening Solr cores --- .../src/org/sleuthkit/autopsy/keywordsearch/Server.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java index 5ff73f4f98..89e5d05f10 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java @@ -63,6 +63,7 @@ import org.apache.solr.client.solrj.response.CoreAdminResponse; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrException; import org.sleuthkit.autopsy.casemodule.Case.CaseType; +import org.sleuthkit.autopsy.coreutils.HandleUNC; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -652,6 +653,7 @@ public class Server { String getIndexDirPath(Case theCase) { String indexDir = theCase.getModuleDirectory() + File.separator + "keywordsearch" + File.separator + "data"; //NON-NLS + indexDir=HandleUNC.getInstance().attemptUNCSubstitution(indexDir); return indexDir; } From 5d1d3953b90646e6f7f4391fe93a0dd0075a2c94 Mon Sep 17 00:00:00 2001 From: Karl Mortensen Date: Thu, 30 Jul 2015 10:14:35 -0400 Subject: [PATCH 3/6] UNC utilities --- .../autopsy/casemodule/Bundle.properties | 2 +- .../sleuthkit/autopsy/casemodule/Case.java | 2 +- .../casemodule/SingleUserCaseImporter.java | 12 +- .../autopsy/coreutils/HandleUNC.java | 198 ------------ .../autopsy/coreutils/UNCPathUtilities.java | 294 ++++++++++++++++++ .../modules/photoreccarver/Bundle.properties | 1 + .../PhotoRecCarverFileIngestModule.java | 20 +- .../autopsy/timeline/events/db/EventDB.java | 5 +- .../timeline/events/db/EventsRepository.java | 1 + .../autopsy/keywordsearch/Server.java | 19 +- 10 files changed, 331 insertions(+), 223 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/coreutils/HandleUNC.java create mode 100644 Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index c3cfeb9b7a..3ae21a7b9f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -246,7 +246,7 @@ MissingImageDialog.lbWarning.text= MissingImageDialog.lbWarning.toolTipText= CaseConverter.AlreadyMultiUser=Case is already multi-user! CaseConverter.FinishedConverting=Finished converting -CaseConverter.To= to +CaseConverter.To=to CaseConverter.BadCaseSourceFolder=Case source folder does not exist! CaseConverter.BadImageSourceFolder=Image source folder does not exist! CaseConverter.BadDatabaseFileName=Database file does not exist! diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index af785d02e2..ccc23952c4 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -255,7 +255,7 @@ public class Case { private final static String CACHE_FOLDER = "Cache"; //NON-NLS private final static String EXPORT_FOLDER = "Export"; //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 TEMP_FOLDER = "Temp"; //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseImporter.java b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseImporter.java index 41fa68894a..e9b00545ee 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseImporter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseImporter.java @@ -44,6 +44,7 @@ import org.apache.commons.io.FileUtils; import org.openide.util.Exceptions; import org.openide.util.NbBundle; 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.datamodel.CaseDbConnectionInfo; import org.sleuthkit.datamodel.SleuthkitCase; @@ -59,9 +60,10 @@ public class SingleUserCaseImporter implements Runnable { private static final String DOTAUT = ".aut"; //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 + //If TIMELINE_FOLDER changes, also update TIMELINE in EventsRepository 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 static final String MODULE_FOLDER = "ModuleOutput"; //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 int MAX_DB_NAME_LENGTH = 63; @@ -182,7 +184,7 @@ public class SingleUserCaseImporter implements Runnable { } log(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.FinishedConverting") - + input.toString() + NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.To") + + input.toString() + " " + NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.To") + caseOutputFolder + File.separatorChar + newCaseFolder); } catch (Exception exp) { /// clean up here @@ -263,7 +265,7 @@ public class SingleUserCaseImporter implements Runnable { String hostName = NetworkUtils.getLocalHostName(); Path destination; Path source; - + if (input.toFile().exists()) { destination = Paths.get(caseOutputFolder, newCaseFolder, hostName); FileUtils.copyDirectory(input.toFile(), destination.toFile()); @@ -285,7 +287,7 @@ public class SingleUserCaseImporter implements Runnable { // if unable to log it, no problem } } - + // Remove the single-user .aut file, database, Timeline database and log File oldDatabaseFile = Paths.get(caseOutputFolder, newCaseFolder, hostName, caseName + DOTAUT).toFile(); if (oldDatabaseFile.exists()) { @@ -1196,7 +1198,7 @@ public class SingleUserCaseImporter implements Runnable { */ private void closeLog(boolean result) { log(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.FinishedConverting") - + caseInputFolder + + caseInputFolder + " " + NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.To") + caseOutputFolder + NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.ConversionSuccessful") diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/HandleUNC.java b/Core/src/org/sleuthkit/autopsy/coreutils/HandleUNC.java deleted file mode 100644 index 69fae50e8c..0000000000 --- a/Core/src/org/sleuthkit/autopsy/coreutils/HandleUNC.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 Basis Technology Corp. - * Contact: carrier sleuthkit 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 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 getMappedDrives() { - Map 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; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java b/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java new file mode 100644 index 0000000000..8760219d43 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java @@ -0,0 +1,294 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit 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 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 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 (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 = 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 getMappedDrives() { + Map 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; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties index 41acbcf61d..c925bc9c47 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties @@ -10,6 +10,7 @@ unsupportedOS.message=PhotoRec Module is supported only on Windows platforms missingExecutable.message=Unable to locate PhotoRec executable. cannotRunExecutable.message=Unable to execute PhotoRec 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.moduleError=PhotoRec Carver Module Error PhotoRecIngestModule.UnableToCarve=Unable to carve file: {0} diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java index 98a9c3fef8..1aff083373 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java @@ -38,18 +38,12 @@ import org.openide.modules.InstalledFileLocator; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.ExecUtil; -import org.sleuthkit.autopsy.coreutils.FileUtil; 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.ingest.FileIngestModule; -import org.sleuthkit.autopsy.ingest.FileIngestModuleProcessTerminator; import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestModule; 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.Content; import org.sleuthkit.datamodel.Image; @@ -58,7 +52,7 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.Volume; import org.sleuthkit.autopsy.coreutils.FileUtil; -import org.sleuthkit.autopsy.coreutils.HandleUNC; +import org.sleuthkit.autopsy.coreutils.UNCPathUtilities; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.ingest.ProcTerminationCode; @@ -87,6 +81,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { private Path rootOutputDirPath; private File executableFile; private IngestServices services; + private UNCPathUtilities uncPathUtilities = new UNCPathUtilities(); /** * @inheritDoc @@ -104,7 +99,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { 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); executableFile = locateExecutable(execName.toString()); @@ -297,11 +292,14 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { * @return The absolute path of the output directory. * @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()); - if (HandleUNC.isUNC(path)) { + if (UNCPathUtilities.isUNC(path)) { // if the UNC path is using an IP address, convert to hostname - path = HandleUNC.getInstance().ipToHostName(path); + path = uncPathUtilities.ipToHostName(path); + if (path == null) { + throw new IngestModule.IngestModuleException(NbBundle.getMessage(PhotoRecCarverFileIngestModule.class, "PhotoRecIngestModule.nonHostnameUNCPathUsed")); + } } try { Files.createDirectory(path); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/events/db/EventDB.java b/Core/src/org/sleuthkit/autopsy/timeline/events/db/EventDB.java index f5c20036a2..f9c7db11dc 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/events/db/EventDB.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/events/db/EventDB.java @@ -108,6 +108,9 @@ public class EventDB { 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 { //make sure sqlite driver is loaded // possibly redundant try { @@ -128,7 +131,7 @@ public class EventDB { */ public static EventDB getEventDB(String dbPath) { 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; } catch (SQLException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/timeline/events/db/EventsRepository.java b/Core/src/org/sleuthkit/autopsy/timeline/events/db/EventsRepository.java index d07824c96f..ba46e03ad1 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/events/db/EventsRepository.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/events/db/EventsRepository.java @@ -94,6 +94,7 @@ public class EventsRepository { private final LoadingCache> aggregateEventsCache; + //If TIMELINE changes, also update TIMELINE_FOLDER in SingleUserCaseImporter private static final String TIMELINE = "Timeline"; public Interval getBoundingEventsInterval(Interval timeRange, Filter filter) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java index 89e5d05f10..82d3ac37ab 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java @@ -63,7 +63,7 @@ import org.apache.solr.client.solrj.response.CoreAdminResponse; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrException; import org.sleuthkit.autopsy.casemodule.Case.CaseType; -import org.sleuthkit.autopsy.coreutils.HandleUNC; +import org.sleuthkit.autopsy.coreutils.UNCPathUtilities; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -168,7 +168,8 @@ public class Server { private int currentSolrServerPort = 0; private int currentSolrStopPort = 0; private static final boolean DEBUG = false;//(Version.getBuildType() == Version.Type.DEVELOPMENT); - + private final UNCPathUtilities uncPathUtilities = new UNCPathUtilities(); + public enum CORE_EVT_STATES { STOPPED, STARTED @@ -651,10 +652,16 @@ public class Server { * @return absolute path to index dir */ String getIndexDirPath(Case theCase) { - String indexDir = theCase.getModuleDirectory() + - File.separator + "keywordsearch" + File.separator + "data"; //NON-NLS - indexDir=HandleUNC.getInstance().attemptUNCSubstitution(indexDir); - return indexDir; + String indexDir = theCase.getModuleDirectory() + 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 result; } /** From e0afc0c29a4ac7cd57e4f7fdabca1228d9d40f2a Mon Sep 17 00:00:00 2001 From: Karl Mortensen Date: Thu, 30 Jul 2015 12:45:27 -0400 Subject: [PATCH 4/6] lowercamcelcase method names --- .../autopsy/coreutils/UNCPathUtilities.java | 24 +++++++++---------- .../autopsy/keywordsearch/Server.java | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java b/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java index 8760219d43..619022e454 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java @@ -70,7 +70,7 @@ public class UNCPathUtilities { * @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) { + synchronized public String mappedDriveToUNC(String inputPath) { if (inputPath != null) { if (false == isUNC(inputPath)) { String uncPath = null; @@ -108,9 +108,9 @@ public class UNCPathUtilities { * @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) { + synchronized public Path mappedDriveToUNC(Path inputPath) { if (inputPath != null) { - String uncPath = MappedDriveToUNC(inputPath.toString()); + String uncPath = UNCPathUtilities.this.mappedDriveToUNC(inputPath.toString()); if (uncPath == null) { return null; } else { @@ -127,9 +127,9 @@ public class UNCPathUtilities { * @param inputPath the Path to test. * @return true if the passed in drive is mapped, false otherwise */ - synchronized public boolean IsDriveMapped(Path inputPath) { + synchronized public boolean isDriveMapped(Path inputPath) { if (inputPath != null) { - return IsDriveMapped(inputPath.toString()); + return isDriveMapped(inputPath.toString()); } else { return false; } @@ -141,7 +141,7 @@ public class UNCPathUtilities { * @param inputPath the Path to test. * @return true if the passed in drive is mapped, false otherwise */ - synchronized public boolean IsDriveMapped(String inputPath) { + synchronized public boolean isDriveMapped(String inputPath) { if (inputPath != null) { String shortenedPath = inputPath.substring(STARTING_OFFSET, DRIVE_LEN); for (String s : drives.keySet()) { @@ -229,10 +229,10 @@ public class UNCPathUtilities { /** * 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. + 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() { @@ -241,8 +241,8 @@ public class UNCPathUtilities { /** * 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. + to resolve mappedDriveToUNC and isDriveMapped calls. Note this uses + system I/O, so call it with some care. * * @return the hashmap */ diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java index 82d3ac37ab..f1b9eb315d 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java @@ -653,10 +653,10 @@ public class Server { */ String getIndexDirPath(Case theCase) { String indexDir = theCase.getModuleDirectory() + File.separator + "keywordsearch" + File.separator + "data"; //NON-NLS - String result = uncPathUtilities.MappedDriveToUNC(indexDir); + String result = uncPathUtilities.mappedDriveToUNC(indexDir); if (result == null) { uncPathUtilities.rescanDrives(); - result = uncPathUtilities.MappedDriveToUNC(indexDir); + result = uncPathUtilities.mappedDriveToUNC(indexDir); } if (result == null) { return indexDir; From 252619bd3b6b90ca4f7fc1668af6ee088077d1a3 Mon Sep 17 00:00:00 2001 From: Karl Mortensen Date: Thu, 30 Jul 2015 13:32:06 -0400 Subject: [PATCH 5/6] rename to SingleUserCaseImporter --- .../autopsy/casemodule/Bundle.properties | 26 +++++++-------- .../casemodule/SingleUserCaseImporter.java | 32 +++++++++---------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 3ae21a7b9f..56db39bd55 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -244,16 +244,16 @@ CollaborationMonitor.addingDataSourceStatus.msg={0} adding data source CollaborationMonitor.analyzingDataSourceStatus.msg={0} analyzing {1} MissingImageDialog.lbWarning.text= MissingImageDialog.lbWarning.toolTipText= -CaseConverter.AlreadyMultiUser=Case is already multi-user! -CaseConverter.FinishedConverting=Finished converting -CaseConverter.To=to -CaseConverter.BadCaseSourceFolder=Case source folder does not exist! -CaseConverter.BadImageSourceFolder=Image source folder does not exist! -CaseConverter.BadDatabaseFileName=Database file does not exist! -CaseConverter.NonUniqueOutputFolder=Output folder not unique. Skipping -CaseConverter.NonUniqueDatabaseName=Database name not unique. Skipping. -CaseConverter.PotentiallyNonUniqueDatabaseName=Unclear if database name unique. Moving ahead. -CaseConverter.ConvertedToMultiUser=This case was converted to a Multi-user collaborative case on -CaseConverter.UnableToCopySourceImages=Unable to copy source images -CaseConverter.ConversionSuccessful=. Conversion successful: -CaseConverter.DeletingCase=Deleting original case folder +SingleUserCaseImporter.AlreadyMultiUser=Case is already multi-user! +SingleUserCaseImporter.FinishedConverting=Finished converting +SingleUserCaseImporter.To=to +SingleUserCaseImporter.BadCaseSourceFolder=Case source folder does not exist! +SingleUserCaseImporter.BadImageSourceFolder=Image source folder does not exist! +SingleUserCaseImporter.BadDatabaseFileName=Database file does not exist! +SingleUserCaseImporter.NonUniqueOutputFolder=Output folder not unique. Skipping +SingleUserCaseImporter.NonUniqueDatabaseName=Database name not unique. Skipping. +SingleUserCaseImporter.PotentiallyNonUniqueDatabaseName=Unclear if database name unique. Moving ahead. +SingleUserCaseImporter.ConvertedToMultiUser=This case was converted to a Multi-user collaborative case on +SingleUserCaseImporter.UnableToCopySourceImages=Unable to copy source images +SingleUserCaseImporter.ConversionSuccessful=. Conversion successful: +SingleUserCaseImporter.DeletingCase=Deleting original case folder diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseImporter.java b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseImporter.java index e9b00545ee..55c1f7bce7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseImporter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseImporter.java @@ -81,7 +81,7 @@ public class SingleUserCaseImporter implements Runnable { private XMLCaseManagement newXmlCaseManagement; /** - * CaseConverter constructor + * SingleUserCaseImporter constructor * * @param caseInput the folder to start our case search from. Will find * valid cases from this folder down, and process them. @@ -140,7 +140,7 @@ public class SingleUserCaseImporter implements Runnable { // read old xml config oldXmlCaseManagement.open(input.resolve(oldCaseName + DOTAUT).toString()); 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); @@ -179,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 // their C drive. if (deleteCase) { - log(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.DeletingCase") + " " + input); + log(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.DeletingCase") + " " + input); FileUtils.deleteDirectory(input.toFile()); } - log(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.FinishedConverting") - + input.toString() + " " + NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.To") + log(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.FinishedConverting") + + input.toString() + " " + NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.To") + caseOutputFolder + File.separatorChar + newCaseFolder); } catch (Exception exp) { /// clean up here @@ -204,13 +204,13 @@ public class SingleUserCaseImporter implements Runnable { */ private void checkInput(File caseInput, File imageInput) throws Exception { 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())) { - 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); if (false == path.toFile().exists()) { - throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.BadDatabaseFileName")); + throw new Exception(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.BadDatabaseFileName")); } } @@ -238,7 +238,7 @@ public class SingleUserCaseImporter implements Runnable { while (specificOutputFolder.exists()) { if (number == Integer.MAX_VALUE) { // 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 specificOutputFolder = Paths.get(caseOutputFolder, temp).toFile(); @@ -282,7 +282,7 @@ public class SingleUserCaseImporter implements Runnable { destination = Paths.get(caseOutputFolder, newCaseFolder, AIM_LOG_FILE_NAME); FileUtils.copyFile(source.toFile(), destination.toFile()); 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) { // if unable to log it, no problem } @@ -961,7 +961,7 @@ public class SingleUserCaseImporter implements Runnable { // not unique. add numbers before dbName. if (number == Integer.MAX_VALUE) { // 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 @@ -976,7 +976,7 @@ public class SingleUserCaseImporter implements Runnable { } else { // Could be caused by database credentials, using user accounts that // 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; @@ -1009,7 +1009,7 @@ public class SingleUserCaseImporter implements Runnable { if (chosenInput != null && chosenInput.exists()) { FileUtils.copyDirectory(chosenInput, output); } else { - log(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.UnableToCopySourceImages")); + log(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.UnableToCopySourceImages")); } return chosenInput; } @@ -1197,11 +1197,11 @@ public class SingleUserCaseImporter implements Runnable { * not. True if all was successful, false otherwise. */ private void closeLog(boolean result) { - log(NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.FinishedConverting") + log(NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.FinishedConverting") + caseInputFolder + " " - + NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.To") + + NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.To") + caseOutputFolder - + NbBundle.getMessage(SingleUserCaseImporter.class, "CaseConverter.ConversionSuccessful") + + NbBundle.getMessage(SingleUserCaseImporter.class, "SingleUserCaseImporter.ConversionSuccessful") + result); if (writer != null) { From 25bebee8d933ecaf7236af925dc535d751d6c1c9 Mon Sep 17 00:00:00 2001 From: Karl Mortensen Date: Thu, 30 Jul 2015 14:13:17 -0400 Subject: [PATCH 6/6] ignore C: for single user case --- .../autopsy/coreutils/UNCPathUtilities.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java b/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java index 619022e454..dcc6c6b0ae 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/UNCPathUtilities.java @@ -39,6 +39,7 @@ public class UNCPathUtilities { 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; @@ -72,6 +73,10 @@ public class UNCPathUtilities { */ 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 { @@ -229,10 +234,10 @@ public class UNCPathUtilities { /** * 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. + * 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() { @@ -241,8 +246,8 @@ public class UNCPathUtilities { /** * 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. + * to resolve mappedDriveToUNC and isDriveMapped calls. Note this uses + * system I/O, so call it with some care. * * @return the hashmap */