Merge pull request #7897 from gdicristofaro/CT-8367e_lockOldFileLoc

CT-8367 simultaneous CT/Autopsy
This commit is contained in:
Mark McKinnon 2024-05-06 15:04:06 -04:00 committed by GitHub
commit 1e9028d0be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 137 additions and 15 deletions

View File

@ -110,6 +110,9 @@ Case_caseType_singleUser=Single-user case
Case_checkImagePaths_exceptionOccurred=An exception occurred while checking if image paths are present
# {0} - paths
Case_checkImagePaths_noPaths=The following images had no associated paths: {0}
# {0} - appplicationName
Case_throwIfConcurrentDbAccessException_fileLock_concurrentAccessException=The case is open in {0}. Please close it before attempting to open it in Autopsy.
Case_throwIfConcurrentDbAccessException_fileLock_concurrentAccessException_defaultApp=another application
CaseDetailsPanel.casePanel.border.title=Case
CaseDetailsPanel.examinerLabel.text=Name:
CaseDetailsPanel.examinerPanel.border.title=Examiner

View File

@ -145,6 +145,7 @@ import org.sleuthkit.autopsy.timeline.OpenTimelineAction;
import org.sleuthkit.autopsy.timeline.events.TimelineEventAddedEvent;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
import org.sleuthkit.datamodel.ConcurrentDbAccessException;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentStreamProvider;
import org.sleuthkit.datamodel.ContentTag;
@ -2736,7 +2737,7 @@ public class Case {
* with a standard name, physically located in the case
* directory.
*/
caseDb = SleuthkitCase.newCase(Paths.get(metadata.getCaseDirectory(), SINGLE_USER_CASE_DB_NAME).toString());
caseDb = SleuthkitCase.newCase(Paths.get(metadata.getCaseDirectory(), SINGLE_USER_CASE_DB_NAME, APP_NAME).toString());
metadata.setCaseDatabaseName(SINGLE_USER_CASE_DB_NAME);
} else {
/*
@ -2748,6 +2749,7 @@ public class Case {
metadata.setCaseDatabaseName(caseDb.getDatabaseName());
}
} catch (TskCoreException ex) {
throwIfConcurrentDbAccessException(ex);
throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseDatabase(ex.getLocalizedMessage()), ex);
} catch (UserPreferencesException ex) {
throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotGetDbServerConnectionInfo(ex.getLocalizedMessage()), ex);
@ -2788,7 +2790,7 @@ public class Case {
}
if (CaseType.SINGLE_USER_CASE == metadata.getCaseType()) {
caseDb = SleuthkitCase.openCase(metadata.getCaseDatabasePath(), contentProvider);
caseDb = SleuthkitCase.openCase(metadata.getCaseDatabasePath(), contentProvider, APP_NAME);
} else if (UserPreferences.getIsMultiUserModeEnabled()) {
caseDb = SleuthkitCase.openCase(databaseName, UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory(), contentProvider);
} else {
@ -2800,11 +2802,43 @@ public class Case {
} catch (UserPreferencesException ex) {
throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotGetDbServerConnectionInfo(ex.getLocalizedMessage()), ex);
} catch (TskCoreException ex) {
throwIfConcurrentDbAccessException(ex);
throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotOpenCaseDatabase(ex.getLocalizedMessage()), ex);
}
}
/**
* Throws a CaseActionException if the exception or any nested exception is a ConcurrentDbAccessException (max depth of 10)
* @param ex The exception.
* @throws CaseActionException Thrown if there is a concurrent db access exception.
*/
@Messages({
"# {0} - appplicationName",
"Case_throwIfConcurrentDbAccessException_fileLock_concurrentAccessException=The case is open in {0}. Please close it before attempting to open it in Autopsy.",
"Case_throwIfConcurrentDbAccessException_fileLock_concurrentAccessException_defaultApp=another application"
})
private void throwIfConcurrentDbAccessException(Exception ex) throws CaseActionException {
ConcurrentDbAccessException concurrentEx = null;
Throwable curEx = ex;
// max depth search for a concurrent db access exception will be 10
for (int i = 0; i < 10; i++) {
if (curEx instanceof ConcurrentDbAccessException foundEx) {
concurrentEx = foundEx;
break;
}
curEx = curEx.getCause();
}
if (concurrentEx != null) {
throw new CaseActionException(Bundle.Case_throwIfConcurrentDbAccessException_fileLock_concurrentAccessException(
StringUtils.defaultIfBlank(concurrentEx.getConflictingApplicationName(),
Bundle.Case_throwIfConcurrentDbAccessException_fileLock_concurrentAccessException_defaultApp())
), concurrentEx);
}
}
/**
* Attempts to load a content provider for the provided arguments. Returns
* null if no content provider for the arguments can be identified.

View File

@ -66,11 +66,17 @@ public class Installer extends ModuleInstall {
private static final long serialVersionUID = 1L;
private static final String JAVA_TEMP = "java.io.tmpdir";
private static final String AUTOPSY_TEMP_DIR = "autopsy_temp";
private static final String TSK_TEMP = "tsk.tmpdir";
private final List<ModuleInstall> packageInstallers;
private static final Logger logger = Logger.getLogger(Installer.class.getName());
private static volatile boolean javaFxInit = false;
static {
setTskTemp();
loadDynLibraries();
// This call was moved from MediaViewImagePanel so that it is
@ -81,6 +87,24 @@ public class Installer extends ModuleInstall {
OpenCvLoader.openCvIsLoaded();
}
/**
* Set TSK temp directory to de-conflict with other programs using TSK libs.
*/
private static void setTskTemp() {
try {
String curTemp = System.getProperty(JAVA_TEMP, "");
String tskTemp = curTemp + (curTemp.endsWith(File.separator) ? "" : File.separator) + AUTOPSY_TEMP_DIR;
System.setProperty(TSK_TEMP, tskTemp);
File tskTempDir = new File(tskTemp);
tskTempDir.mkdirs();
if (!tskTempDir.isDirectory()) {
throw new IOException("Unable to create directory at " + tskTemp);
}
} catch (Exception ex) {
logger.log(Level.WARNING, "There was an error setting up tsk temp directory", ex);
}
}
private static void loadDynLibraries() {
/*
* On Windows, we distribute dlls that libtsk_jni depend on. If
@ -551,11 +575,6 @@ public class Installer extends ModuleInstall {
logger.log(Level.INFO, "close()"); //NON-NLS
//exit JavaFx plat
if (javaFxInit) {
Platform.exit();
}
for (ModuleInstall mi : packageInstallers) {
logger.log(Level.INFO, "{0} close()", mi.getClass().getName()); //NON-NLS
try {
@ -567,5 +586,10 @@ public class Installer extends ModuleInstall {
for (Handler h : logger.getHandlers()) {
h.close(); //must call h.close or a .LCK file will remain.
}
//exit JavaFx plat
if (javaFxInit) {
Platform.exit();
}
}
}

View File

@ -169,6 +169,8 @@ ImageNode.createSheet.type.displayName=Type
ImageNode.createSheet.type.name=Type
ImageNode.createSheet.type.text=Image
ImageNode.getActions.openFileSearchByAttr.text=Open File Search by Attributes
Installer_validate_tskLibLock_description=<html>Another forensics application is running that uses The Sleuth Kit.<br/>You must close that application before launching Autopsy.<br/>If that application is Cyber Triage, then you should upgrade it so that it can run at the same time as Autopsy.</html>
Installer_validate_tskLibLock_title=Error calling Sleuth Kit library
KeyValueNode.menuItemText.viewFileInDir=View Source File in Directory
KeywordHits.createNodeForKey.accessTime.desc=Access Time
KeywordHits.createNodeForKey.accessTime.displayName=Access Time

View File

@ -26,6 +26,9 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JOptionPane;
import org.openide.LifecycleManager;
import org.openide.modules.ModuleInstall;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.datamodel.LibraryLock;
import org.sleuthkit.datamodel.LibraryLock.LockState;
import org.sleuthkit.datamodel.SleuthkitJNI;
/**
@ -46,8 +49,14 @@ public class Installer extends ModuleInstall {
super();
}
@Messages({
"Installer_validate_tskLibLock_title=Error calling Sleuth Kit library",
"Installer_validate_tskLibLock_description=<html>Another forensics application is running that uses The Sleuth Kit.<br/>You must close that application before launching Autopsy.<br/>If that application is Cyber Triage, then you should upgrade it so that it can run at the same time as Autopsy.</html>"
})
@Override
public void validate() throws IllegalStateException {
/*
* The NetBeans API specifies that a module should throw an
* IllegalStateException if it can't be initalized, but NetBeans doesn't
@ -59,7 +68,13 @@ public class Installer extends ModuleInstall {
// Check that the the Sleuth Kit JNI is working by getting the Sleuth Kit version number
Logger logger = Logger.getLogger(Installer.class.getName());
try {
LibraryLock libLock = LibraryLock.acquireLibLock();
if (libLock != null && libLock.getLockState() == LockState.HELD_BY_OLD) {
throw new OldAppLockException("A lock on the libtsk_jni lib is already held by an old application. " + (libLock.getLibTskJniFile() != null ? libLock.getLibTskJniFile().getAbsolutePath() : ""));
}
String skVersion = SleuthkitJNI.getVersion();
if (skVersion == null) {
@ -71,15 +86,25 @@ public class Installer extends ModuleInstall {
}
} catch (Exception | UnsatisfiedLinkError e) {
logger.log(Level.SEVERE, "Error calling Sleuth Kit library (test call failed)", e); //NON-NLS
logger.log(Level.SEVERE, "Is Autopsy or Cyber Triage already running?)", e); //NON-NLS
// Normal error box log handler won't be loaded yet, so show error here.
final Component parentComponent = null; // Use default window frame.
final String message = NbBundle.getMessage(this.getClass(), "Installer.tskLibErr.msg", e.toString());
final String title = NbBundle.getMessage(this.getClass(), "Installer.tskLibErr.err");
final int messageType = JOptionPane.ERROR_MESSAGE;
final String message;
final String title;
if (e instanceof OldAppLockException ex) {
logger.log(Level.SEVERE, "An older application already holds a lock on the libtsk_jni lib", ex);
message = Bundle.Installer_validate_tskLibLock_description();
title = Bundle.Installer_validate_tskLibLock_title();
} else {
logger.log(Level.SEVERE, "Error calling Sleuth Kit library (test call failed)", e); //NON-NLS
logger.log(Level.SEVERE, "Is Autopsy or Cyber Triage already running?)", e); //NON-NLS
message = NbBundle.getMessage(this.getClass(), "Installer.tskLibErr.msg", e.toString());
title = NbBundle.getMessage(this.getClass(), "Installer.tskLibErr.err");
}
JOptionPane.showMessageDialog(
parentComponent,
message,
@ -91,4 +116,38 @@ public class Installer extends ModuleInstall {
}
}
@Override
public void close() {
try {
LibraryLock.removeLibLock();
} catch (Exception ex) {
Logger logger = Logger.getLogger(Installer.class.getName());
logger.log(Level.WARNING, "There was an error removing the TSK lib lock.", ex);
}
}
@Override
public void uninstalled() {
try {
LibraryLock.removeLibLock();
} catch (Exception ex) {
Logger logger = Logger.getLogger(Installer.class.getName());
logger.log(Level.WARNING, "There was an error removing the TSK lib lock.", ex);
}
}
/**
* An exception when an older application (Autopsy
*/
static class OldAppLockException extends Exception {
public OldAppLockException(String message) {
super(message);
}
}
}