diff --git a/Core/build.xml b/Core/build.xml index df8bf56464..7429307d43 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -134,8 +134,8 @@ - + release/modules/ext/spotbugs-annotations-4.6.0.jar - ext/sqlite-jdbc-3.42.0.1.jar - release/modules/ext/sqlite-jdbc-3.42.0.1.jar + ext/sqlite-jdbc-3.46.0.0.jar + release/modules/ext/sqlite-jdbc-3.46.0.0.jar ext/txw2-2.3.3.jar diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 1f9719688f..14465bba03 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -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 diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 3f9c440122..0923666a87 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -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).toString(), (ContentStreamProvider) null, APP_NAME); 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); @@ -2778,7 +2780,7 @@ public class Case { progressIndicator.progress(Bundle.Case_progressMessage_openingCaseDatabase()); try { String databaseName = metadata.getCaseDatabaseName(); - + ContentStreamProvider contentProvider = loadContentProvider(metadata.getContentProviderName()); if (StringUtils.isNotBlank(metadata.getContentProviderName()) && contentProvider == null) { if (metadata.getContentProviderName().trim().toUpperCase().startsWith(CT_PROVIDER_PREFIX.toUpperCase())) { @@ -2786,9 +2788,9 @@ public class Case { } throw new CaseActionException(Bundle.Case_exceptionMessage_contentProviderCouldNotBeFound()); } - + 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,7 +2802,42 @@ public class Case { } catch (UserPreferencesException ex) { throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotGetDbServerConnectionInfo(ex.getLocalizedMessage()), ex); } catch (TskCoreException ex) { - throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotOpenCaseDatabase(ex.getLocalizedMessage()), 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 == null) { + break; + } else if (curEx instanceof ConcurrentDbAccessException foundEx) { + concurrentEx = foundEx; + break; + } else { + 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); } } diff --git a/Core/src/org/sleuthkit/autopsy/core/Installer.java b/Core/src/org/sleuthkit/autopsy/core/Installer.java index 0cbafe987e..374d5b8ccb 100644 --- a/Core/src/org/sleuthkit/autopsy/core/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/core/Installer.java @@ -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_SUFFIX = "_temp"; + private static final String TSK_TEMP = "tsk.tmpdir"; + private final List 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 @@ -80,6 +86,25 @@ public class Installer extends ModuleInstall { // This will cause OpenCvLoader to load its library instead of 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 autopsyTempDir = StringUtils.defaultIfBlank(UserPreferences.getAppName(), "autopsy").replaceAll("[^a-zA-Z0-9_\\-]", "_") + AUTOPSY_TEMP_DIR_SUFFIX; + String tskTemp = Paths.get(StringUtils.defaultString(curTemp), autopsyTempDir).toString(); + 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() { /* @@ -551,11 +576,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 +587,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(); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED index 4d958cf39b..fb2079cccd 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED @@ -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=Another forensics application is running that uses The Sleuth Kit.
You must close that application before launching Autopsy.
If that application is Cyber Triage, then you should upgrade it so that it can run at the same time as Autopsy. +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 diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java b/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java index 323424efdf..311250eb88 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java @@ -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=Another forensics application is running that uses The Sleuth Kit.
You must close that application before launching Autopsy.
If that application is Cyber Triage, then you should upgrade it so that it can run at the same time as Autopsy." + }) @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); + } + + } } diff --git a/ImageGallery/nbproject/project.properties b/ImageGallery/nbproject/project.properties index d69f7d273a..2ea0f24c23 100644 --- a/ImageGallery/nbproject/project.properties +++ b/ImageGallery/nbproject/project.properties @@ -1,4 +1,4 @@ -file.reference.sqlite-jdbc-3.42.0.1.jar=release/modules/ext/sqlite-jdbc-3.42.0.1.jar +file.reference.sqlite-jdbc-3.46.0.0.jar=release/modules/ext/sqlite-jdbc-3.46.0.0.jar javac.source=17 javac.compilerargs=-Xlint -Xlint:-serial license.file=LICENSE-2.0.txt diff --git a/ImageGallery/nbproject/project.xml b/ImageGallery/nbproject/project.xml index 49221290cd..6941e4b187 100644 --- a/ImageGallery/nbproject/project.xml +++ b/ImageGallery/nbproject/project.xml @@ -142,8 +142,8 @@ - ext/sqlite-jdbc-3.42.0.1.jar - release/modules/ext/sqlite-jdbc-3.42.0.1.jar + ext/sqlite-jdbc-3.46.0.0.jar + release/modules/ext/sqlite-jdbc-3.46.0.0.jar diff --git a/RecentActivity/nbproject/project.properties b/RecentActivity/nbproject/project.properties index 430436bea9..8c106492c6 100644 --- a/RecentActivity/nbproject/project.properties +++ b/RecentActivity/nbproject/project.properties @@ -1,6 +1,6 @@ javac.source=17 file.reference.Rejistry-1.1-SNAPSHOT.jar=release/modules/ext/Rejistry-1.1-SNAPSHOT.jar -file.reference.sqlite-jdbc-3.42.0.1.jar=release/modules/ext/sqlite-jdbc-3.42.0.1.jar +file.reference.sqlite-jdbc-3.46.0.0.jar=release/modules/ext/sqlite-jdbc-3.46.0.0.jar javac.compilerargs=-Xlint -Xlint:-serial license.file=../LICENSE-2.0.txt nbm.homepage=http://www.sleuthkit.org/autopsy/ diff --git a/RecentActivity/nbproject/project.xml b/RecentActivity/nbproject/project.xml index 05745bb79a..bc1dd53aa8 100644 --- a/RecentActivity/nbproject/project.xml +++ b/RecentActivity/nbproject/project.xml @@ -88,8 +88,8 @@ release/modules/ext/Rejistry-1.1-SNAPSHOT.jar
- ext/sqlite-jdbc-3.42.0.1.jar - release/modules/ext/sqlite-jdbc-3.42.0.1.jar + ext/sqlite-jdbc-3.46.0.0.jar + release/modules/ext/sqlite-jdbc-3.46.0.0.jar diff --git a/docs/doxygen-dev/footer.html b/docs/doxygen-dev/footer.html index d648961fdc..fe4f9e42d1 100755 --- a/docs/doxygen-dev/footer.html +++ b/docs/doxygen-dev/footer.html @@ -1,5 +1,5 @@
-

Copyright © 2012-2022 Basis Technology. Generated on $date
+

Copyright © 2012-2024 Sleuth Kit Labs. Generated on $date
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.

diff --git a/docs/doxygen-user/footer.html b/docs/doxygen-user/footer.html index cfedffe82c..fe4f9e42d1 100644 --- a/docs/doxygen-user/footer.html +++ b/docs/doxygen-user/footer.html @@ -1,5 +1,5 @@
-

Copyright © 2012-2023 BasisTech. Generated on $date
+

Copyright © 2012-2024 Sleuth Kit Labs. Generated on $date
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.

diff --git a/docs/doxygen/footer.html b/docs/doxygen/footer.html index f9eb00590e..6d97889cc8 100644 --- a/docs/doxygen/footer.html +++ b/docs/doxygen/footer.html @@ -1,5 +1,5 @@
-

Copyright © 2012-2022 Basis Technology. Generated on: $date
+

Copyright © 2012-2024 Sleuth Kit Labs. Generated on: $date
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.