From ade3855156fa9e0bfc6aff36ac704fc41f42d93c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 30 Aug 2023 15:33:57 -0400 Subject: [PATCH 01/25] remove physical drive mentions from case --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index eb279febe7..2b6eedb092 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -194,8 +194,6 @@ public class Case { private final SleuthkitEventListener sleuthkitEventListener; private CollaborationMonitor collaborationMonitor; private Services caseServices; - // matches something like '\\.\PHYSICALDRIVE0' - private static final String PLACEHOLDER_DS_PATH_REGEX = "^\\s*\\\\\\\\\\.\\\\PHYSICALDRIVE\\d*\\s*$"; private volatile boolean hasDataSource = false; private volatile boolean hasData = false; @@ -1307,13 +1305,6 @@ public class Case { String path = entry.getValue(); boolean fileExists = (new File(path).exists()|| DriveUtils.driveExists(path)); if (!fileExists) { - // CT-7336: ignore relocating datasources if file provider is present and placeholder path is used. - if (newCurrentCase.getMetadata() != null - && !StringUtils.isBlank(newCurrentCase.getMetadata().getContentProviderName()) - && (path == null || path.matches(PLACEHOLDER_DS_PATH_REGEX))) { - continue; - } - try { DataSource ds = newCurrentCase.getSleuthkitCase().getDataSource(obj_id); String hostName = StringUtils.defaultString(ds.getHost() == null ? "" : ds.getHost().getName()); From 18c5fecf30122c45e6fc5c94a30127bba9f37200 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 12 Sep 2023 11:49:12 -0400 Subject: [PATCH 02/25] include justification in AR tab --- .../analysisresults/AnalysisResultsViewModel.java | 5 ++++- .../contentviewers/analysisresults/Bundle.properties-MERGED | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java index e556c39e7d..8a3d08ea87 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java @@ -175,7 +175,8 @@ public class AnalysisResultsViewModel { "AnalysisResultsViewModel_displayAttributes_score=Score", "AnalysisResultsViewModel_displayAttributes_type=Type", "AnalysisResultsViewModel_displayAttributes_configuration=Configuration", - "AnalysisResultsViewModel_displayAttributes_conclusion=Conclusion" + "AnalysisResultsViewModel_displayAttributes_conclusion=Conclusion", + "AnalysisResultsViewModel_displayAttributes_justification=Justification" }) private ResultDisplayAttributes getDisplayAttributes(AnalysisResult analysisResult) { // The type of BlackboardArtifact.Type of the analysis result. @@ -188,6 +189,8 @@ public class AnalysisResultsViewModel { // The standard attributes to display (score, type, configuration, conclusion) Stream> baseAnalysisAttrs = Stream.of( + Pair.of(Bundle.AnalysisResultsViewModel_displayAttributes_justification(), + normalizeAttr(analysisResult.getJustification())), Pair.of(Bundle.AnalysisResultsViewModel_displayAttributes_score(), normalizeAttr(analysisResult.getScore().getSignificance().getDisplayName())), Pair.of(Bundle.AnalysisResultsViewModel_displayAttributes_type(), diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/Bundle.properties-MERGED index ae4d0b3b6b..fc4ba9ee8c 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/Bundle.properties-MERGED @@ -8,5 +8,6 @@ AnalysisResultsContentViewer_title=Analysis Results AnalysisResultsContentViewer_tooltip=Viewer for Analysis Results related to the selected node. AnalysisResultsViewModel_displayAttributes_conclusion=Conclusion AnalysisResultsViewModel_displayAttributes_configuration=Configuration +AnalysisResultsViewModel_displayAttributes_justification=Justification AnalysisResultsViewModel_displayAttributes_score=Score AnalysisResultsViewModel_displayAttributes_type=Type From 96fdc77f30f51efd05b4b698958df8057c6aa22a Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 12 Sep 2023 11:54:17 -0400 Subject: [PATCH 03/25] order change --- .../analysisresults/AnalysisResultsViewModel.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java index 8a3d08ea87..f1a707531a 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsViewModel.java @@ -189,8 +189,6 @@ public class AnalysisResultsViewModel { // The standard attributes to display (score, type, configuration, conclusion) Stream> baseAnalysisAttrs = Stream.of( - Pair.of(Bundle.AnalysisResultsViewModel_displayAttributes_justification(), - normalizeAttr(analysisResult.getJustification())), Pair.of(Bundle.AnalysisResultsViewModel_displayAttributes_score(), normalizeAttr(analysisResult.getScore().getSignificance().getDisplayName())), Pair.of(Bundle.AnalysisResultsViewModel_displayAttributes_type(), @@ -198,7 +196,9 @@ public class AnalysisResultsViewModel { Pair.of(Bundle.AnalysisResultsViewModel_displayAttributes_configuration(), normalizeAttr(analysisResult.getConfiguration())), Pair.of(Bundle.AnalysisResultsViewModel_displayAttributes_conclusion(), - normalizeAttr(analysisResult.getConclusion())) + normalizeAttr(analysisResult.getConclusion())), + Pair.of(Bundle.AnalysisResultsViewModel_displayAttributes_justification(), + normalizeAttr(analysisResult.getJustification())) ); // The BlackboardAttributes sorted by type display name. From 425d45324e8029243e5dbdacb9960425c8a54ed1 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 20 Sep 2023 16:20:37 -0400 Subject: [PATCH 04/25] fail if no provider and no image paths --- .../casemodule/Bundle.properties-MERGED | 3 ++ .../sleuthkit/autopsy/casemodule/Case.java | 38 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index ce1fb9aa70..1f9719688f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -107,6 +107,9 @@ Case.servicesException.notificationTitle={0} Error Case.servicesException.serviceResourcesCloseError=Could not close case resources for {0} service: {1} Case_caseType_multiUser=Multi-user case 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} 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 2b6eedb092..3f9c440122 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -41,6 +41,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; @@ -64,6 +65,7 @@ import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.ThreadSafe; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.openide.util.Lookup; import org.openide.util.NbBundle; @@ -2284,6 +2286,8 @@ public class Case { checkForCancellation(); openCommunicationChannels(progressIndicator); checkForCancellation(); + checkImagePaths(); + checkForCancellation(); openFileSystemsInBackground(); return null; @@ -2302,6 +2306,40 @@ public class Case { throw ex; } } + + /** + * Check if content provider is present, all images have paths, or throw an error. + * @throws CaseActionException + */ + @Messages({ + "# {0} - paths", + "Case_checkImagePaths_noPaths=The following images had no associated paths: {0}", + "Case_checkImagePaths_exceptionOccurred=An exception occurred while checking if image paths are present" + }) + private void checkImagePaths() throws CaseActionException { + // if there is a content provider, images don't necessarily need paths + if (StringUtils.isNotBlank(this.metadata.getContentProviderName())) { + return; + } + + // identify images without paths + try { + List noPathImages = new ArrayList<>(); + List images = this.caseDb.getImages(); + for (Image img: images) { + if (ArrayUtils.isEmpty(img.getPaths())) { + noPathImages.add(img); + } + } + + if (!noPathImages.isEmpty()) { + String imageListStr = noPathImages.stream().map(Image::getName).collect(Collectors.joining(", ")); + throw new CaseActionException(Bundle.Case_checkImagePaths_noPaths(imageListStr)); + } + } catch (TskCoreException ex) { + throw new CaseActionException(Bundle.Case_checkImagePaths_exceptionOccurred(), ex); + } + } /** * Starts a background task that reads a sector from each file system of From 82ef6a41d378d3028ec3da8621c8ab08cda53ca7 Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Wed, 3 Jan 2024 10:38:28 -0500 Subject: [PATCH 05/25] Revert "Merge branch 'develop' of https://github.com/markmckinnon/autopsy into develop" This reverts commit 109626e94fff0a62a97c6aa4c21276b3889e0282, reversing changes made to 83427184ce50bf477be85a013ffb8f6a8ce3f6d2. --- CoreLibs/ivy.xml | 2 +- CoreLibs/nbproject/project.properties | 4 ++-- CoreLibs/nbproject/project.xml | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CoreLibs/ivy.xml b/CoreLibs/ivy.xml index 3566041703..d60ce17600 100644 --- a/CoreLibs/ivy.xml +++ b/CoreLibs/ivy.xml @@ -62,7 +62,7 @@ - + diff --git a/CoreLibs/nbproject/project.properties b/CoreLibs/nbproject/project.properties index 9bd3153105..320a1e36e5 100644 --- a/CoreLibs/nbproject/project.properties +++ b/CoreLibs/nbproject/project.properties @@ -118,8 +118,8 @@ file.reference.jericho-html-3.4.jar=release/modules/ext/jericho-html-3.4.jar file.reference.jfxtras-common-17-r1.jar=release/modules/ext/jfxtras-common-17-r1.jar file.reference.jfxtras-controls-17-r1.jar=release/modules/ext/jfxtras-controls-17-r1.jar file.reference.jfxtras-fxml-17-r1.jar=release/modules/ext/jfxtras-fxml-17-r1.jar -file.reference.jna-5.14.0.jar=release/modules/ext/jna-5.14.0.jar -file.reference.jna-platform-5.14.0.jar=release/modules/ext/jna-platform-5.14.0.jar +file.reference.jna-5.13.0.jar=release/modules/ext/jna-5.13.0.jar +file.reference.jna-platform-5.13.0.jar=release/modules/ext/jna-platform-5.13.0.jar file.reference.joda-time-2.10.14.jar=release/modules/ext/joda-time-2.10.14.jar file.reference.jsr305-3.0.2.jar=release/modules/ext/jsr305-3.0.2.jar file.reference.LGoodDatePicker-11.2.1.jar=release/modules/ext/LGoodDatePicker-11.2.1.jar diff --git a/CoreLibs/nbproject/project.xml b/CoreLibs/nbproject/project.xml index 49cdfcd0c1..ff5e70f4e8 100644 --- a/CoreLibs/nbproject/project.xml +++ b/CoreLibs/nbproject/project.xml @@ -1041,12 +1041,12 @@ release/modules/ext/jfxtras-fxml-17-r1.jar - ext/jna-5.14.0.jar - release/modules/ext/jna-5.14.0.jar + ext/jna-5.13.0.jar + release/modules/ext/jna-5.13.0.jar - ext/jna-platform-5.14.0.jar - release/modules/ext/jna-platform-5.14.0.jar + ext/jna-platform-5.13.0.jar + release/modules/ext/jna-platform-5.13.0.jar ext/joda-time-2.10.14.jar From 24c81a822bad4bcd2c25c43e559725592ecc57e7 Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Wed, 3 Jan 2024 10:40:54 -0500 Subject: [PATCH 06/25] Revert "Revert "Merge branch 'develop' of https://github.com/markmckinnon/autopsy into develop"" This reverts commit 82ef6a41d378d3028ec3da8621c8ab08cda53ca7. --- CoreLibs/ivy.xml | 2 +- CoreLibs/nbproject/project.properties | 4 ++-- CoreLibs/nbproject/project.xml | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CoreLibs/ivy.xml b/CoreLibs/ivy.xml index d60ce17600..3566041703 100644 --- a/CoreLibs/ivy.xml +++ b/CoreLibs/ivy.xml @@ -62,7 +62,7 @@ - + diff --git a/CoreLibs/nbproject/project.properties b/CoreLibs/nbproject/project.properties index 320a1e36e5..9bd3153105 100644 --- a/CoreLibs/nbproject/project.properties +++ b/CoreLibs/nbproject/project.properties @@ -118,8 +118,8 @@ file.reference.jericho-html-3.4.jar=release/modules/ext/jericho-html-3.4.jar file.reference.jfxtras-common-17-r1.jar=release/modules/ext/jfxtras-common-17-r1.jar file.reference.jfxtras-controls-17-r1.jar=release/modules/ext/jfxtras-controls-17-r1.jar file.reference.jfxtras-fxml-17-r1.jar=release/modules/ext/jfxtras-fxml-17-r1.jar -file.reference.jna-5.13.0.jar=release/modules/ext/jna-5.13.0.jar -file.reference.jna-platform-5.13.0.jar=release/modules/ext/jna-platform-5.13.0.jar +file.reference.jna-5.14.0.jar=release/modules/ext/jna-5.14.0.jar +file.reference.jna-platform-5.14.0.jar=release/modules/ext/jna-platform-5.14.0.jar file.reference.joda-time-2.10.14.jar=release/modules/ext/joda-time-2.10.14.jar file.reference.jsr305-3.0.2.jar=release/modules/ext/jsr305-3.0.2.jar file.reference.LGoodDatePicker-11.2.1.jar=release/modules/ext/LGoodDatePicker-11.2.1.jar diff --git a/CoreLibs/nbproject/project.xml b/CoreLibs/nbproject/project.xml index ff5e70f4e8..49cdfcd0c1 100644 --- a/CoreLibs/nbproject/project.xml +++ b/CoreLibs/nbproject/project.xml @@ -1041,12 +1041,12 @@ release/modules/ext/jfxtras-fxml-17-r1.jar - ext/jna-5.13.0.jar - release/modules/ext/jna-5.13.0.jar + ext/jna-5.14.0.jar + release/modules/ext/jna-5.14.0.jar - ext/jna-platform-5.13.0.jar - release/modules/ext/jna-platform-5.13.0.jar + ext/jna-platform-5.14.0.jar + release/modules/ext/jna-platform-5.14.0.jar ext/joda-time-2.10.14.jar From 180932deeb44b72e51758de9707411f58f5fad3b Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 20 Mar 2024 17:28:20 -0400 Subject: [PATCH 07/25] update for TSK deps --- Core/build.xml | 8 ++++---- Core/nbproject/project.properties | 4 ++-- Core/nbproject/project.xml | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Core/build.xml b/Core/build.xml index 0c83b8158f..982b0636f1 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -136,12 +136,12 @@ tofile="${ext.dir}/sleuthkit-${TSK_VERSION}.jar"/> - + - + release/modules/ext/logback-core-1.2.10.jar - ext/mchange-commons-java-0.2.20.jar - release/modules/ext/mchange-commons-java-0.2.20.jar + ext/mchange-commons-java-00.3.0.jar + release/modules/ext/mchange-commons-java-00.3.0.jar ext/metadata-extractor-2.18.0.jar @@ -698,8 +698,8 @@ release/modules/ext/okio-1.6.0.jar - ext/postgresql-42.3.5.jar - release/modules/ext/postgresql-42.3.5.jar + ext/postgresql-42.7.3.jar + release/modules/ext/postgresql-42.7.3.jar ext/Rejistry-1.1-SNAPSHOT.jar From 72d4bd2b2e69c4106eb695e8f07390d596365411 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 20 Mar 2024 17:32:49 -0400 Subject: [PATCH 08/25] fix for typo --- Core/build.xml | 4 ++-- Core/nbproject/project.properties | 2 +- Core/nbproject/project.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/build.xml b/Core/build.xml index 982b0636f1..df8bf56464 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -140,8 +140,8 @@ tofile="${ext.dir}/postgresql-42.7.3.jar"/> - + release/modules/ext/logback-core-1.2.10.jar - ext/mchange-commons-java-00.3.0.jar + ext/mchange-commons-java-0.3.0.jar release/modules/ext/mchange-commons-java-00.3.0.jar From a2378ff326b342b2c1da3b4f75e77941993efc68 Mon Sep 17 00:00:00 2001 From: "eugene.livis" Date: Wed, 3 Apr 2024 10:17:24 -0400 Subject: [PATCH 09/25] First cut --- .../autopsy/actions/AddTagAction.java | 2 +- .../autopsy/actions/GetTagNameDialog.java | 6 +-- .../autopsy/actions/ReplaceTagAction.java | 2 +- .../services/TagNameDefinition.java | 45 +++++++++++-------- .../casemodule/services/TagNameDialog.java | 2 +- .../casemodule/services/TagOptionsPanel.java | 8 ++-- .../casemodule/services/TagsManager.java | 26 +++++------ .../application/OtherOccurrences.java | 4 +- .../datamodel/CentralRepoDbUtil.java | 2 +- .../eventlisteners/CaseEventListener.java | 14 +++--- .../infrastructure/ReportVisualPanel2.java | 2 +- .../infrastructure/TableReportGenerator.java | 10 ++--- .../report/modules/html/HTMLReport.java | 2 +- .../PortableCaseReportModule.java | 2 +- .../org/sleuthkit/autopsy/tags/TagUtils.java | 2 +- 15 files changed, 68 insertions(+), 61 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index ff3dc08e04..564499680c 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -239,7 +239,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { */ private JMenuItem createMenutItem(TagName tagName) { String tagDisplayName = tagName.getDisplayName(); - String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + String notableString = tagName.getTagType() == TskData.TagType.BAD ? TagsManager.getNotableTagLabel() : ""; JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString); if (tagDisplayName.equals(TagsManager.getBookmarkTagDisplayName())) { diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index 2617d08df3..c6b1e7b9c4 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -174,10 +174,10 @@ public class GetTagNameDialog extends JDialog { private final String name; private final String description; - private final TskData.FileKnown status; + private final TskData.TagType status; private final TagName.HTML_COLOR color; - AddTagNameWorker(String name, String description, TskData.FileKnown status, TagName.HTML_COLOR color) { + AddTagNameWorker(String name, String description, TskData.TagType status, TagName.HTML_COLOR color) { this.name = name; this.description = description; this.status = status; @@ -375,7 +375,7 @@ public class GetTagNameDialog extends JDialog { private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed String tagDisplayName = tagNameField.getText(); String userTagDescription = descriptionTextArea.getText(); - TskData.FileKnown status = notableCheckbox.isSelected() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN; + TskData.TagType status = notableCheckbox.isSelected() ? TskData.TagType.BAD : TskData.TagType.SUSPICIOUS; if (tagDisplayName.isEmpty()) { JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(), diff --git a/Core/src/org/sleuthkit/autopsy/actions/ReplaceTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/ReplaceTagAction.java index 34ed836e3e..1d263bc407 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/ReplaceTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/ReplaceTagAction.java @@ -226,7 +226,7 @@ abstract class ReplaceTagAction extends AbstractAction implements */ private JMenuItem createMenutItem(TagName tagName, Set tagNamesToDisable, Collection selectedTags) { String tagDisplayName = tagName.getDisplayName(); - String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + String notableString = tagName.getTagType() == TskData.TagType.BAD ? TagsManager.getNotableTagLabel() : ""; JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString); if (tagDisplayName.equals(TagsManager.getBookmarkTagDisplayName())) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java index 24f208f421..25345615b4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java @@ -59,15 +59,15 @@ final public class TagNameDefinition implements Comparable { private final String displayName; private final String description; private final TagName.HTML_COLOR color; - private final TskData.FileKnown knownStatus; + private final TskData.TagType tagType; private static final List STANDARD_TAGS_DEFINITIONS = new ArrayList<>(); private static final List PROJECT_VIC_NAMES_NO_LONGER_USED = new ArrayList<>(); static { - STANDARD_TAGS_DEFINITIONS.add(new TagNameDefinition(Bundle.TagNameDefinition_predefTagNames_bookmark_text(), "", TagName.HTML_COLOR.NONE, TskData.FileKnown.UNKNOWN)); - STANDARD_TAGS_DEFINITIONS.add(new TagNameDefinition(Bundle.TagNameDefinition_predefTagNames_followUp_text(), "", TagName.HTML_COLOR.NONE, TskData.FileKnown.UNKNOWN)); - STANDARD_TAGS_DEFINITIONS.add(new TagNameDefinition(Bundle.TagNameDefinition_predefTagNames_notableItem_text(), "", TagName.HTML_COLOR.NONE, TskData.FileKnown.BAD)); + STANDARD_TAGS_DEFINITIONS.add(new TagNameDefinition(Bundle.TagNameDefinition_predefTagNames_bookmark_text(), "", TagName.HTML_COLOR.NONE, TskData.TagType.SUSPICIOUS)); + STANDARD_TAGS_DEFINITIONS.add(new TagNameDefinition(Bundle.TagNameDefinition_predefTagNames_followUp_text(), "", TagName.HTML_COLOR.NONE, TskData.TagType.SUSPICIOUS)); + STANDARD_TAGS_DEFINITIONS.add(new TagNameDefinition(Bundle.TagNameDefinition_predefTagNames_notableItem_text(), "", TagName.HTML_COLOR.NONE, TskData.TagType.BAD)); PROJECT_VIC_NAMES_NO_LONGER_USED.add("CAT-1: Child Exploitation (Illegal)"); PROJECT_VIC_NAMES_NO_LONGER_USED.add("CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"); @@ -79,18 +79,25 @@ final public class TagNameDefinition implements Comparable { /** * Constructs a tag name definition consisting of a display name, - * description, color and knownStatus. + * description, color and tag type. * * @param displayName The display name for the tag name. * @param description The description for the tag name. * @param color The color for the tag name. * @param status The status denoted by the tag name. */ - public TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) { + /* ELTODO public TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) { this.displayName = displayName; this.description = description; this.color = color; - this.knownStatus = status; + this.tagType = status; + }*/ + + public TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.TagType status) { + this.displayName = displayName; + this.description = description; + this.color = color; + this.tagType = status; } static Collection getStandardTagNameDefinitions() { @@ -164,10 +171,10 @@ final public class TagNameDefinition implements Comparable { /** * The status which will be applied to items with this tag. * - * @return a value of TskData.FileKnown which is associated with this tag + * @return a value of TskData.TagType which is associated with this tag */ - public TskData.FileKnown getKnownStatus() { - return knownStatus; + public TskData.TagType getTagType() { + return tagType; } /** @@ -212,7 +219,7 @@ final public class TagNameDefinition implements Comparable { return false; } boolean sameName = this.getDisplayName().equals(((TagNameDefinition) obj).getDisplayName()); - boolean sameStatus = this.getKnownStatus().equals(((TagNameDefinition) obj).getKnownStatus()); + boolean sameStatus = this.getTagType().equals(((TagNameDefinition) obj).getTagType()); return sameName && sameStatus; } @@ -231,13 +238,13 @@ final public class TagNameDefinition implements Comparable { * that is used by the tags settings file. */ private String toSettingsFormat() { - return displayName + "," + description + "," + color.name() + "," + knownStatus.toString(); + return displayName + "," + description + "," + color.name() + "," + tagType.toString(); } TagName saveToCase(SleuthkitCase caseDb) { TagName tagName = null; try { - tagName = caseDb.getTaggingManager().addOrUpdateTagName(displayName, description, color, knownStatus); + tagName = caseDb.getTaggingManager().addOrUpdateTagName(displayName, description, color, tagType); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error saving tag name definition", ex); } @@ -251,7 +258,7 @@ final public class TagNameDefinition implements Comparable { * The currently custom tags properties are stored in one string property * value separated by ;. The properties of an individual tag are comma * separated in the format of: - * tag_name,tag_description,tag_color,known_status + * tag_name,tag_description,tag_color,tag_type * * In prior versions of autopsy the known_status was stored in the central * repository, therefore the properties file only had three values. @@ -279,7 +286,7 @@ final public class TagNameDefinition implements Comparable { String[] attributes = tagProps.split(","); definitions.add(new TagNameDefinition(attributes[0], attributes[1], - TagName.HTML_COLOR.valueOf(attributes[2]), TskData.FileKnown.valueOf(attributes[3]))); + TagName.HTML_COLOR.valueOf(attributes[2]), TskData.TagType.valueOf(attributes[3]))); } return definitions; @@ -332,18 +339,18 @@ final public class TagNameDefinition implements Comparable { List notableTagList = null; for (String tagProps : individualTags) { String[] attributes = tagProps.split(","); - TskData.FileKnown fileKnown = TskData.FileKnown.UNKNOWN; + TskData.TagType fileKnown = TskData.TagType.SUSPICIOUS; if (attributes.length == 3) { // If notableTagList is null load it from the CR. if (notableTagList == null) { - notableTagList = getCRNotableList(); + notableTagList = getCRNotableList(); // ELTODO handle backwards compatibility } else { if (notableTagList.contains(attributes[0])) { - fileKnown = TskData.FileKnown.BAD; + fileKnown = TskData.TagType.BAD; } } } else { - fileKnown = TskData.FileKnown.valueOf(attributes[3]); + fileKnown = TskData.TagType.valueOf(attributes[3]); } definitions.add(new TagNameDefinition(attributes[0], attributes[1], diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java index 79207aaaaa..dccd8ae38a 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java @@ -62,7 +62,7 @@ final class TagNameDialog extends javax.swing.JDialog { initComponents(); tagNameTextField.setText(tagNameToEdit.getDisplayName()); descriptionTextArea.setText(tagNameToEdit.getDescription()); - notableCheckbox.setSelected(tagNameToEdit.getKnownStatus() == TskData.FileKnown.BAD); + notableCheckbox.setSelected(tagNameToEdit.getTagType() == TskData.TagType.BAD); tagNameTextField.setEnabled(false); this.display(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java index 2ef9869adc..a0947b468b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java @@ -314,7 +314,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { TagNameDialog dialog = new TagNameDialog(); TagNameDialog.BUTTON_PRESSED result = dialog.getResult(); if (result == TagNameDialog.BUTTON_PRESSED.OK) { - TskData.FileKnown status = dialog.isTagNotable() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN; + TskData.TagType status = dialog.isTagNotable() ? TskData.TagType.BAD : TskData.TagType.SUSPICIOUS; TagNameDefinition newTagType = new TagNameDefinition(dialog.getTagName(), dialog.getTagDesciption(), DEFAULT_COLOR, status); /* * If tag name already exists, don't add the tag name. @@ -348,7 +348,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { TagNameDialog dialog = new TagNameDialog(originalTagName); TagNameDialog.BUTTON_PRESSED result = dialog.getResult(); if (result == TagNameDialog.BUTTON_PRESSED.OK) { - TskData.FileKnown status = dialog.isTagNotable() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN; + TskData.TagType status = dialog.isTagNotable() ? TskData.TagType.BAD : TskData.TagType.SUSPICIOUS; TagNameDefinition newTagType = new TagNameDefinition(dialog.getTagName(), dialog.getTagDesciption(), DEFAULT_COLOR, status); /* * If tag name already exists, don't add the tag name. @@ -359,7 +359,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { tagNamesList.setSelectedValue(newTagType, true); updatePanel(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - if (originalTagName.getKnownStatus() != newTagType.getKnownStatus() && Case.isCaseOpen()) { + if (originalTagName.getTagType() != newTagType.getTagType() && Case.isCaseOpen()) { updatedStatusTags.add(newTagType.getDisplayName()); } } @@ -449,7 +449,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { deleteTagNameButton.setEnabled(enableEdit); if (isSelected) { descriptionTextArea.setText(tagNamesList.getSelectedValue().getDescription()); - if (tagNamesList.getSelectedValue().getKnownStatus() == TskData.FileKnown.BAD) { + if (tagNamesList.getSelectedValue().getTagType() == TskData.TagType.BAD) { notableYesOrNoLabel.setText("Yes"); } else { notableYesOrNoLabel.setText("No"); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index a4bd51bcce..4f004884c5 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -188,7 +188,7 @@ public class TagsManager implements Closeable { } /** - * Gets the set of display names of notable (TskData.FileKnown.BAD) tag + * Gets the set of display names of notable (TskData.TagType.BAD) tag * types. If a case is not open the list will only include only the user * defined custom tags. Otherwise the list will include all notable tags. * @@ -197,7 +197,7 @@ public class TagsManager implements Closeable { public static List getNotableTagDisplayNames() { List tagDisplayNames = new ArrayList<>(); for (TagNameDefinition tagDef : TagNameDefinition.getTagNameDefinitions()) { - if (tagDef.getKnownStatus() == TskData.FileKnown.BAD) { + if (tagDef.getTagType() == TskData.TagType.BAD) { tagDisplayNames.add(tagDef.getDisplayName()); } } @@ -205,7 +205,7 @@ public class TagsManager implements Closeable { try { TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); for (TagName tagName : tagsManager.getAllTagNames()) { - if (tagName.getKnownStatus() == TskData.FileKnown.BAD + if (tagName.getTagType() == TskData.TagType.BAD && !tagDisplayNames.contains(tagName.getDisplayName())) { tagDisplayNames.add(tagName.getDisplayName()); } @@ -303,14 +303,14 @@ public class TagsManager implements Closeable { // add the standard tag names for (TagNameDefinition def : TagNameDefinition.getStandardTagNameDefinitions()) { - taggingMgr.addOrUpdateTagName(def.getDisplayName(), def.getDescription(), def.getColor(), def.getKnownStatus()); + taggingMgr.addOrUpdateTagName(def.getDisplayName(), def.getDescription(), def.getColor(), def.getTagType()); } //Assume new case and add all tag sets for (TagSetDefinition setDef : TagSetDefinition.readTagSetDefinitions()) { List tagNamesInSet = new ArrayList<>(); for (TagNameDefinition tagNameDef : setDef.getTagNameDefinitions()) { - tagNamesInSet.add(taggingMgr.addOrUpdateTagName(tagNameDef.getDisplayName(), tagNameDef.getDescription(), tagNameDef.getColor(), tagNameDef.getKnownStatus())); + tagNamesInSet.add(taggingMgr.addOrUpdateTagName(tagNameDef.getDisplayName(), tagNameDef.getDescription(), tagNameDef.getColor(), tagNameDef.getTagType())); } if (!tagNamesInSet.isEmpty()) { @@ -505,7 +505,7 @@ public class TagsManager implements Closeable { * name to the case database. */ public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException { - return addTagName(displayName, "", TagName.HTML_COLOR.NONE, TskData.FileKnown.UNKNOWN); + return addTagName(displayName, "", TagName.HTML_COLOR.NONE, TskData.TagType.SUSPICIOUS); } /** @@ -524,7 +524,7 @@ public class TagsManager implements Closeable { * name to the case database. */ public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException { - return addTagName(displayName, description, TagName.HTML_COLOR.NONE, TskData.FileKnown.UNKNOWN); + return addTagName(displayName, description, TagName.HTML_COLOR.NONE, TskData.TagType.SUSPICIOUS); } /** @@ -543,7 +543,7 @@ public class TagsManager implements Closeable { * name to the case database. */ public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { - return addTagName(displayName, description, color, TskData.FileKnown.UNKNOWN); + return addTagName(displayName, description, color, TskData.TagType.SUSPICIOUS); } /** @@ -553,8 +553,8 @@ public class TagsManager implements Closeable { * @param displayName The display name for the new tag type. * @param description The description for the new tag type. * @param color The color to associate with the new tag type. - * @param knownStatus The knownStatus to be used for the tag when - * correlating on the tagged item + * @param tagType The tagType to be used for the tag when + correlating on the tagged item * * @return A TagName object that can be used to add instances of the tag * type to the case database. @@ -563,12 +563,12 @@ public class TagsManager implements Closeable { * @throws TskCoreException If there is an error adding the tag * name to the case database. */ - public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TagNameAlreadyExistsException, TskCoreException { + public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.TagType tagType) throws TagNameAlreadyExistsException, TskCoreException { synchronized (lock) { try { - TagName tagName = caseDb.getTaggingManager().addOrUpdateTagName(displayName, description, color, knownStatus); + TagName tagName = caseDb.getTaggingManager().addOrUpdateTagName(displayName, description, color, tagType); Set customTypes = TagNameDefinition.getTagNameDefinitions(); - customTypes.add(new TagNameDefinition(displayName, description, color, knownStatus)); + customTypes.add(new TagNameDefinition(displayName, description, color, tagType)); TagNameDefinition.setTagNameDefinitions(customTypes); return tagName; } catch (TskCoreException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java b/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java index ae35d971bf..61997e8de2 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/application/OtherOccurrences.java @@ -167,8 +167,8 @@ public final class OtherOccurrences { if (newNode.getKnown() != TskData.FileKnown.BAD) { List fileMatchTags = autopsyCase.getServices().getTagsManager().getContentTagsByContent(newFile); for (ContentTag tag : fileMatchTags) { - TskData.FileKnown tagKnownStatus = tag.getName().getKnownStatus(); - if (tagKnownStatus.equals(TskData.FileKnown.BAD)) { + TskData.TagType tagType = tag.getName().getTagType(); + if (tagType.equals(TskData.TagType.BAD)) { newNode.updateKnown(TskData.FileKnown.BAD); break; } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDbUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDbUtil.java index 410e78e52d..8cc775192c 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDbUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDbUtil.java @@ -307,7 +307,7 @@ public class CentralRepoDbUtil { } /** - * Conver thte Type's DbTableName string to the *_instances table name. + * Convert the Type's DbTableName string to the *_instances table name. * * @param type Correlation Type * diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index 6610fcbd86..64a27e03de 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -482,10 +482,10 @@ public final class CaseEventListener implements PropertyChangeListener { for (BlackboardArtifactTag bbTag : artifactTags) { //start with assumption that none of the other tags applied to this Correlation Attribute will prevent it's status from being changed boolean hasTagWithConflictingKnownStatus = false; - // if the status of the tag has been changed to TskData.FileKnown.UNKNOWN + // if the status of the tag has been changed to TskData.TagType.UNKNOWN // we need to check the status of all other tags on this correlation attribute before changing // the status of the correlation attribute in the central repository - if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) { + if (tagName.getTagType() == TskData.TagType.UNKNOWN) { Content content = bbTag.getContent(); // If the content which this Blackboard Artifact Tag is linked to is an AbstractFile with KNOWN status then // it's status in the central reporsitory should not be changed to UNKNOWN @@ -503,7 +503,7 @@ public final class CaseEventListener implements PropertyChangeListener { continue; } //if any other tags on this artifact are Notable in status then this artifact can not have its status changed - if (TskData.FileKnown.BAD == t.getName().getKnownStatus()) { + if (TskData.TagType.BAD == t.getName().getTagType()) { //a tag with a conflicting status has been found, the status of this correlation attribute can not be modified hasTagWithConflictingKnownStatus = true; break; @@ -522,10 +522,10 @@ public final class CaseEventListener implements PropertyChangeListener { for (ContentTag contentTag : fileTags) { //start with assumption that none of the other tags applied to this ContentTag will prevent it's status from being changed boolean hasTagWithConflictingKnownStatus = false; - // if the status of the tag has been changed to TskData.FileKnown.UNKNOWN + // if the status of the tag has been changed to TskData.TagType.UNKNOWN // we need to check the status of all other tags on this file before changing // the status of the file in the central repository - if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) { + if (tagName.getTagType() == TskData.TagType.UNKNOWN) { Content content = contentTag.getContent(); TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); List tags = tagsManager.getContentTagsByContent(content); @@ -536,7 +536,7 @@ public final class CaseEventListener implements PropertyChangeListener { continue; } //if any other tags on this file are Notable in status then this file can not have its status changed - if (TskData.FileKnown.BAD == t.getName().getKnownStatus()) { + if (TskData.TagType.BAD == t.getName().getTagType()) { //a tag with a conflicting status has been found, the status of this file can not be modified hasTagWithConflictingKnownStatus = true; break; @@ -556,7 +556,7 @@ public final class CaseEventListener implements PropertyChangeListener { } } } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Cannot update known status in central repository for tag: " + modifiedTagName, ex); //NON-NLS + LOGGER.log(Level.SEVERE, "Cannot update tag type in central repository for tag: " + modifiedTagName, ex); //NON-NLS } catch (CentralRepoException ex) { LOGGER.log(Level.SEVERE, "Cannot get central repository for tag: " + modifiedTagName, ex); //NON-NLS } catch (NoCurrentCaseException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel2.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel2.java index 9a43174ae7..ddbfef840c 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/ReportVisualPanel2.java @@ -158,7 +158,7 @@ final class ReportVisualPanel2 extends JPanel { } for (TagName tagName : tagNamesInUse) { - String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + String notableString = tagName.getTagType() == TskData.TagType.BAD ? TagsManager.getNotableTagLabel() : ""; tagStates.put(tagName.getDisplayName() + notableString, Boolean.FALSE); } tags.addAll(tagStates.keySet()); diff --git a/Core/src/org/sleuthkit/autopsy/report/infrastructure/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/infrastructure/TableReportGenerator.java index 8a591d693e..96c2f58da0 100644 --- a/Core/src/org/sleuthkit/autopsy/report/infrastructure/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/infrastructure/TableReportGenerator.java @@ -94,7 +94,7 @@ class TableReportGenerator { String notableString = ""; for (TagName tagName : tagNamesInUse) { - notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + notableString = tagName.getTagType() == TskData.TagType.BAD ? TagsManager.getNotableTagLabel() : ""; tagNames.add(tagName.getDisplayName() + notableString); } tagNamesFilter = new HashSet<>(tagNames); @@ -369,7 +369,7 @@ class TableReportGenerator { } // skip tags that we are not reporting on - String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + String notableString = tag.getName().getTagType() == TskData.TagType.BAD ? TagsManager.getNotableTagLabel() : ""; if (passesTagNamesFilter(tag.getName().getDisplayName() + notableString) == false) { continue; } @@ -461,7 +461,7 @@ class TableReportGenerator { return; } - String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + String notableString = tag.getName().getTagType() == TskData.TagType.BAD ? TagsManager.getNotableTagLabel() : ""; if (passesTagNamesFilter(tag.getName().getDisplayName() + notableString) == false) { continue; } @@ -1193,7 +1193,7 @@ class TableReportGenerator { try { List contentTags = Case.getCurrentCaseThrows().getServices().getTagsManager().getContentTagsByContent(content); for (ContentTag ct : contentTags) { - String notableString = ct.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + String notableString = ct.getName().getTagType() == TskData.TagType.BAD ? TagsManager.getNotableTagLabel() : ""; allTags.add(ct.getName().getDisplayName() + notableString); } } catch (TskCoreException | NoCurrentCaseException ex) { @@ -1239,7 +1239,7 @@ class TableReportGenerator { List tags = Case.getCurrentCaseThrows().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact); HashSet uniqueTagNames = new HashSet<>(); for (BlackboardArtifactTag tag : tags) { - String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + String notableString = tag.getName().getTagType() == TskData.TagType.BAD ? TagsManager.getNotableTagLabel() : ""; uniqueTagNames.add(tag.getName().getDisplayName() + notableString); } if (failsTagFilter(uniqueTagNames, tagNamesFilter)) { diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/html/HTMLReport.java b/Core/src/org/sleuthkit/autopsy/report/modules/html/HTMLReport.java index 0d9ca80cb9..0f640885a4 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/html/HTMLReport.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/html/HTMLReport.java @@ -954,7 +954,7 @@ public class HTMLReport implements TableReportModule { } for (int i = 0; i < contentTags.size(); i++) { ContentTag tag = contentTags.get(i); - String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + String notableString = tag.getName().getTagType() == TskData.TagType.BAD ? TagsManager.getNotableTagLabel() : ""; linkToThumbnail.append(tag.getName().getDisplayName()).append(notableString); if (i != contentTags.size() - 1) { linkToThumbnail.append(", "); diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java index 1b022d069f..860739f91b 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java @@ -344,7 +344,7 @@ public class PortableCaseReportModule implements ReportModule { progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingTags()); try { for (TagName tagName : tagNames) { - TagName newTagName = portableSkCase.getTaggingManager().addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getKnownStatus()); + TagName newTagName = portableSkCase.getTaggingManager().addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getTagType()); oldTagNameToNewTagName.put(tagName, newTagName); } } catch (TskCoreException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/tags/TagUtils.java b/Core/src/org/sleuthkit/autopsy/tags/TagUtils.java index de93bed26e..aca445ea84 100755 --- a/Core/src/org/sleuthkit/autopsy/tags/TagUtils.java +++ b/Core/src/org/sleuthkit/autopsy/tags/TagUtils.java @@ -64,7 +64,7 @@ public final class TagUtils { logger.log(Level.SEVERE, String.format("Failed to get TagSet for TagName '%s' (ID=%d)", tagName.getDisplayName(), tagName.getId())); } - if (tagName.getKnownStatus() == TskData.FileKnown.BAD) { + if (tagName.getTagType() == TskData.TagType.BAD) { displayName += " (Notable)"; } From 2c4b795a46612b82adeac153f676fbb01ab8856f Mon Sep 17 00:00:00 2001 From: "eugene.livis" Date: Wed, 10 Apr 2024 15:36:08 -0400 Subject: [PATCH 10/25] Fixes --- .../services/TagNameDefinition.java | 29 ++++++++++++------- .../eventlisteners/CaseEventListener.java | 10 ++++--- .../imagegallery/ImageGalleryService.java | 12 ++++---- .../imagegallery/actions/AddTagAction.java | 2 +- .../imagegallery/actions/DeleteTagAction.java | 2 +- 5 files changed, 32 insertions(+), 23 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java index 25345615b4..c8f04560e9 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2011-2024 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -54,7 +54,7 @@ final public class TagNameDefinition implements Comparable { private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS private static final String TAG_SETTING_VERSION_KEY = "CustomTagNameVersion"; - private static final int TAG_SETTINGS_VERSION = 1; + private static final int TAG_SETTINGS_VERSION = 2; // Changed tag type from TskData.FileKnown to TskData.TagType private final String displayName; private final String description; @@ -85,13 +85,15 @@ final public class TagNameDefinition implements Comparable { * @param description The description for the tag name. * @param color The color for the tag name. * @param status The status denoted by the tag name. + * @deprecated TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.TagType status) should be used instead. */ - /* ELTODO public TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) { + @Deprecated + public TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) { this.displayName = displayName; this.description = description; this.color = color; - this.tagType = status; - }*/ + this.tagType = TskData.TagType.convertFileKnownToTagType(status); + } public TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.TagType status) { this.displayName = displayName; @@ -323,7 +325,7 @@ final public class TagNameDefinition implements Comparable { Integer version = getPropertyFileVersion(); List definitions = new ArrayList<>(); - if (version == null) { + if (version == null || version == 1) { String tagsProperty = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); if (tagsProperty == null || tagsProperty.isEmpty()) { ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_SETTING_VERSION_KEY, Integer.toString(TAG_SETTINGS_VERSION)); @@ -339,22 +341,27 @@ final public class TagNameDefinition implements Comparable { List notableTagList = null; for (String tagProps : individualTags) { String[] attributes = tagProps.split(","); - TskData.TagType fileKnown = TskData.TagType.SUSPICIOUS; + TskData.TagType tagType = TskData.TagType.SUSPICIOUS; if (attributes.length == 3) { // If notableTagList is null load it from the CR. if (notableTagList == null) { - notableTagList = getCRNotableList(); // ELTODO handle backwards compatibility + notableTagList = getCRNotableList(); } else { if (notableTagList.contains(attributes[0])) { - fileKnown = TskData.TagType.BAD; + tagType = TskData.TagType.BAD; } } } else { - fileKnown = TskData.TagType.valueOf(attributes[3]); + if (version == 1) { + // handle backwards compatibility + tagType = TskData.TagType.convertFileKnownToTagType(TskData.FileKnown.valueOf(attributes[3])); + } else { + tagType = TskData.TagType.valueOf(attributes[3]); + } } definitions.add(new TagNameDefinition(attributes[0], attributes[1], - TagName.HTML_COLOR.valueOf(attributes[2]), fileKnown)); + TagName.HTML_COLOR.valueOf(attributes[2]), tagType)); } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index 64a27e03de..c6f8b96275 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -482,10 +482,11 @@ public final class CaseEventListener implements PropertyChangeListener { for (BlackboardArtifactTag bbTag : artifactTags) { //start with assumption that none of the other tags applied to this Correlation Attribute will prevent it's status from being changed boolean hasTagWithConflictingKnownStatus = false; - // if the status of the tag has been changed to TskData.TagType.UNKNOWN + // if the status of the tag has been changed to TskData.TagType.UNKNOWN or TskData.TagType.SUSPICIOUS // we need to check the status of all other tags on this correlation attribute before changing // the status of the correlation attribute in the central repository - if (tagName.getTagType() == TskData.TagType.UNKNOWN) { + if (tagName.getTagType() == TskData.TagType.UNKNOWN + || tagName.getTagType() == TskData.TagType.SUSPICIOUS) { Content content = bbTag.getContent(); // If the content which this Blackboard Artifact Tag is linked to is an AbstractFile with KNOWN status then // it's status in the central reporsitory should not be changed to UNKNOWN @@ -522,10 +523,11 @@ public final class CaseEventListener implements PropertyChangeListener { for (ContentTag contentTag : fileTags) { //start with assumption that none of the other tags applied to this ContentTag will prevent it's status from being changed boolean hasTagWithConflictingKnownStatus = false; - // if the status of the tag has been changed to TskData.TagType.UNKNOWN + // if the status of the tag has been changed to TskData.TagType.UNKNOWN or TskData.TagType.SUSPICIOUS // we need to check the status of all other tags on this file before changing // the status of the file in the central repository - if (tagName.getTagType() == TskData.TagType.UNKNOWN) { + if (tagName.getTagType() == TskData.TagType.UNKNOWN + || tagName.getTagType() == TskData.TagType.SUSPICIOUS) { Content content = contentTag.getContent(); TagsManager tagsManager = Case.getCurrentCaseThrows().getServices().getTagsManager(); List tags = tagsManager.getContentTagsByContent(content); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryService.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryService.java index 897b50ae2b..ff17afbdf2 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryService.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryService.java @@ -65,11 +65,11 @@ public class ImageGalleryService implements AutopsyService { static { // NOTE: The colors here are what will be shown in the border - PROJECT_VIC_US_CATEGORIES.add(new TagNameDefinition(PV_US_CAT0, "", TagName.HTML_COLOR.GREEN, TskData.FileKnown.UNKNOWN)); - PROJECT_VIC_US_CATEGORIES.add(new TagNameDefinition(PV_US_CAT1, "", TagName.HTML_COLOR.RED, TskData.FileKnown.BAD)); - PROJECT_VIC_US_CATEGORIES.add(new TagNameDefinition(PV_US_CAT2, "", TagName.HTML_COLOR.YELLOW, TskData.FileKnown.BAD)); - PROJECT_VIC_US_CATEGORIES.add(new TagNameDefinition(PV_US_CAT3, "", TagName.HTML_COLOR.FUCHSIA, TskData.FileKnown.BAD)); - PROJECT_VIC_US_CATEGORIES.add(new TagNameDefinition(PV_US_CAT4, "", TagName.HTML_COLOR.BLUE, TskData.FileKnown.UNKNOWN)); + PROJECT_VIC_US_CATEGORIES.add(new TagNameDefinition(PV_US_CAT0, "", TagName.HTML_COLOR.GREEN, TskData.TagType.SUSPICIOUS)); + PROJECT_VIC_US_CATEGORIES.add(new TagNameDefinition(PV_US_CAT1, "", TagName.HTML_COLOR.RED, TskData.TagType.BAD)); + PROJECT_VIC_US_CATEGORIES.add(new TagNameDefinition(PV_US_CAT2, "", TagName.HTML_COLOR.YELLOW, TskData.TagType.BAD)); + PROJECT_VIC_US_CATEGORIES.add(new TagNameDefinition(PV_US_CAT3, "", TagName.HTML_COLOR.FUCHSIA, TskData.TagType.BAD)); + PROJECT_VIC_US_CATEGORIES.add(new TagNameDefinition(PV_US_CAT4, "", TagName.HTML_COLOR.BLUE, TskData.TagType.SUSPICIOUS)); } @Override @@ -149,7 +149,7 @@ public class ImageGalleryService implements AutopsyService { private void addProjetVicTagSet(Case currentCase) throws TskCoreException { List tagNames = new ArrayList<>(); for (TagNameDefinition def : PROJECT_VIC_US_CATEGORIES) { - tagNames.add(currentCase.getSleuthkitCase().getTaggingManager().addOrUpdateTagName(def.getDisplayName(), def.getDescription(), def.getColor(), def.getKnownStatus())); + tagNames.add(currentCase.getSleuthkitCase().getTaggingManager().addOrUpdateTagName(def.getDisplayName(), def.getDescription(), def.getColor(), def.getTagType())); } currentCase.getServices().getTagsManager().addTagSet(PROJECT_VIC_TAG_SET_NAME, tagNames); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index e6af400473..c75d6e5272 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -68,7 +68,7 @@ public class AddTagAction extends Action { this.selectedFileIDs = selectedFileIDs; this.tagName = tagName; setGraphic(controller.getTagsManager().getGraphic(tagName)); - String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + String notableString = tagName.getTagType() == TskData.TagType.BAD ? TagsManager.getNotableTagLabel() : ""; setText(tagName.getDisplayName() + notableString); setEventHandler(actionEvent -> addTagWithComment("")); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java index efe279bba3..c0ec387082 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java @@ -66,7 +66,7 @@ public class DeleteTagAction extends Action { this.tagName = tagName; this.contentTag = contentTag; setGraphic(controller.getTagsManager().getGraphic(tagName)); - String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : ""; + String notableString = tagName.getTagType() == TskData.TagType.BAD ? TagsManager.getNotableTagLabel() : ""; setText(tagName.getDisplayName() + notableString); setEventHandler(actionEvent -> deleteTag()); } From c84579f49f222d418bd2169e1b53b926ba8f1457 Mon Sep 17 00:00:00 2001 From: "eugene.livis" Date: Wed, 10 Apr 2024 15:44:20 -0400 Subject: [PATCH 11/25] Supporting legacy APIs --- .../casemodule/services/TagNameDefinition.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java index c8f04560e9..4dce91c0ba 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java @@ -178,6 +178,17 @@ final public class TagNameDefinition implements Comparable { public TskData.TagType getTagType() { return tagType; } + + /** + * The status which will be applied to items with this tag. + * + * @return a value of TskData.FileKnown which is associated with this tag + * @deprecated getTagType() should be used instead. + */ + @Deprecated + public TskData.FileKnown getKnownStatus() { + return TskData.TagType.convertTagTypeToFileKnown(tagType); + } /** * Compares this tag name definition with the specified tag name definition From 91fd4caee90534bd99d61b229ad4e91a5cf9b479 Mon Sep 17 00:00:00 2001 From: "eugene.livis" Date: Wed, 10 Apr 2024 16:00:39 -0400 Subject: [PATCH 12/25] Support legacy API --- .../autopsy/casemodule/services/TagsManager.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 4f004884c5..fc7a0fc9d8 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -545,6 +545,22 @@ public class TagsManager implements Closeable { public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, description, color, TskData.TagType.SUSPICIOUS); } + + /** + * + * @param displayName + * @param description + * @param color + * @param knownStatus + * @return + * @throws org.sleuthkit.autopsy.casemodule.services.TagsManager.TagNameAlreadyExistsException + * @throws TskCoreException + * @deprecated addTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.TagType tagType) should be used instead + */ + @Deprecated + public TagName addTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TagNameAlreadyExistsException, TskCoreException { + return addTagName(displayName, description, color, TskData.TagType.convertFileKnownToTagType(knownStatus)); + } /** * Adds a tag name entry to the case database and adds a corresponding tag From b2c674e6b302123e48065eabd7fb61defbc79fea Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 16 Apr 2024 17:58:55 -0400 Subject: [PATCH 13/25] set tsk temp directory --- .../org/sleuthkit/autopsy/core/Installer.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/core/Installer.java b/Core/src/org/sleuthkit/autopsy/core/Installer.java index 0cbafe987e..7ef296e0c2 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 = "autopsy_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,24 @@ 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 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() { /* From c913237966fb5b92d54ced9f3785e62f3b625ea4 Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Tue, 16 Apr 2024 21:10:04 -0400 Subject: [PATCH 14/25] Update Chromium.java Add base directory to profile. Fix NPE in bookmarks --- .../autopsy/recentactivity/Chromium.java | 104 +++++++++--------- 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chromium.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chromium.java index 7f1449c609..bc91d9b9a8 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chromium.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chromium.java @@ -320,6 +320,8 @@ class Chromium extends Extract { jProfile = jElement.get("profile").getAsJsonObject(); //NON-NLS jInfoCache = jProfile.get("info_cache").getAsJsonObject(); } else { + userProfiles.put(browserLocation, "Default"); + browserLocations.put(browserLocation, browser); continue; } } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) { @@ -854,60 +856,62 @@ class Chromium extends Extract { Set bookmarkKeys = jRoot.keySet(); for (String bookmarkKey : bookmarkKeys) { JsonObject jBookmark = jRoot.get(bookmarkKey).getAsJsonObject(); //NON-NLS - JsonArray jBookmarkArray = jBookmark.getAsJsonArray("children"); //NON-NLS - for (JsonElement result : jBookmarkArray) { - JsonObject address = result.getAsJsonObject(); - if (address == null) { - continue; - } - JsonElement urlEl = address.get("url"); //NON-NLS - String url; - if (urlEl != null) { - url = urlEl.getAsString(); - } else { - url = ""; - } - String name; - JsonElement nameEl = address.get("name"); //NON-NLS - if (nameEl != null) { - name = nameEl.getAsString(); - } else { - name = ""; - } - Long date; - JsonElement dateEl = address.get("date_added"); //NON-NLS - if (dateEl != null) { - date = dateEl.getAsLong(); - } else { - date = Long.valueOf(0); - } - String domain = NetworkUtils.extractDomain(url); - Collection bbattributes = new ArrayList<>(); - //TODO Revisit usage of deprecated constructor as per TSK-583 - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, - RecentActivityExtracterModuleFactory.getModuleName(), url)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE, - RecentActivityExtracterModuleFactory.getModuleName(), name)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, - RecentActivityExtracterModuleFactory.getModuleName(), (date / 1000000) - Long.valueOf("11644473600"))); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, - RecentActivityExtracterModuleFactory.getModuleName(), browserName)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, - RecentActivityExtracterModuleFactory.getModuleName(), domain)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME, - RecentActivityExtracterModuleFactory.getModuleName(), userName)); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT, - RecentActivityExtracterModuleFactory.getModuleName(), bookmarkKey)); + if (jBookmark.has("children")) { + JsonArray jBookmarkArray = jBookmark.getAsJsonArray("children"); //NON-NLS + for (JsonElement result : jBookmarkArray) { + JsonObject address = result.getAsJsonObject(); + if (address == null) { + continue; + } + JsonElement urlEl = address.get("url"); //NON-NLS + String url; + if (urlEl != null) { + url = urlEl.getAsString(); + } else { + url = ""; + } + String name; + JsonElement nameEl = address.get("name"); //NON-NLS + if (nameEl != null) { + name = nameEl.getAsString(); + } else { + name = ""; + } + Long date; + JsonElement dateEl = address.get("date_added"); //NON-NLS + if (dateEl != null) { + date = dateEl.getAsLong(); + } else { + date = Long.valueOf(0); + } + String domain = NetworkUtils.extractDomain(url); + Collection bbattributes = new ArrayList<>(); + //TODO Revisit usage of deprecated constructor as per TSK-583 + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, + RecentActivityExtracterModuleFactory.getModuleName(), url)); + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE, + RecentActivityExtracterModuleFactory.getModuleName(), name)); + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, + RecentActivityExtracterModuleFactory.getModuleName(), (date / 1000000) - Long.valueOf("11644473600"))); + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, + RecentActivityExtracterModuleFactory.getModuleName(), browserName)); + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, + RecentActivityExtracterModuleFactory.getModuleName(), domain)); + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME, + RecentActivityExtracterModuleFactory.getModuleName(), userName)); + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT, + RecentActivityExtracterModuleFactory.getModuleName(), bookmarkKey)); - try { - bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes)); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, String.format("Failed to create bookmark artifact for file (%d)", bookmarkFile.getId()), ex); - } + try { + bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes)); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Failed to create bookmark artifact for file (%d)", bookmarkFile.getId()), ex); + } + } } - } + } if (!context.dataSourceIngestIsCancelled()) { postArtifacts(bbartifacts); From e188f4644e8a807a4af3b8dd1a6269957e922706 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 18 Apr 2024 21:15:43 -0400 Subject: [PATCH 15/25] first draft of locking resources in autopsy --- .../sleuthkit/autopsy/casemodule/Case.java | 118 +++++++++++++++++- 1 file changed, 116 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 3f9c440122..4681083400 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -31,6 +31,8 @@ import java.awt.event.ActionListener; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; import java.lang.reflect.InvocationTargetException; import java.nio.file.InvalidPathException; import java.nio.file.Path; @@ -181,6 +183,7 @@ public class Case { private static final String CASE_RESOURCES_THREAD_NAME = "%s-manage-case-resources"; private static final String NO_NODE_ERROR_MSG_FRAGMENT = "KeeperErrorCode = NoNode"; private static final String CT_PROVIDER_PREFIX = "CTStandardContentProvider_"; + private static final String LOCK_FILE_NAME = "lock"; private static final Logger logger = Logger.getLogger(Case.class.getName()); private static final AutopsyEventPublisher eventPublisher = new AutopsyEventPublisher(); private static final Object caseActionSerializationLock = new Object(); @@ -197,6 +200,10 @@ public class Case { private CollaborationMonitor collaborationMonitor; private Services caseServices; + private RansomAccessFile lockFileRaf = null; + private FileChannel lockFileChannel = null; + private FileLock lockFileLock = null; + private volatile boolean hasDataSource = false; private volatile boolean hasData = false; @@ -769,6 +776,57 @@ public class Case { || caseName.contains("*") || caseName.contains("?") || caseName.contains("\"") || caseName.contains("<") || caseName.contains(">") || caseName.contains("|")); } + + + /** + * Try to acquire a lock to the lock file in the case directory. + * @param caseDir The case directory that the autopsy.db is in. + * @throws IllegalAccessException + * @throws IOException + */ + private void tryAcquireFileLock(String caseDir) throws ConcurrentDbAccessException, IOException { + File lockFile = new File(caseDir, LOCK_FILE_NAME); + lockFile.getParentFile().mkdirs(); + lockFileRaf = new RandomAccessFile(lockFile, "rw"); + lockFileChannel = lockFileRaf.getChannel(); + lockFileLock = lockFileChannel.tryLock(); + if (lockFileLock == null) { + String conflictingApplication = null; + try { + StringBuffer buffer = new StringBuffer(); + while (lockFileRaf.getFilePointer() < lockFileRaf.length()) { + buffer.append(lockFileRaf.readLine() + System.lineSeparator()); + } + conflictingApplication = buffer.toString(); + } finally { + throw new ConcurrentDbAccessException("Unable to acquire lock on " + lockFile, conflictingApplication); + } + } + } + + /** + * An exception thrown if the database is currently in use. + */ + private static class ConcurrentDbAccessException extends Exception { + private final String conflictingApplicationName; + + /** + * Constructor. + * @param message The exception message. + * @param conflictingApplicationName The conflicting application name (or null if unknown). + */ + public ConcurrentDbAccessException(String message, String conflictingApplicationName) { + super(message); + this.conflictingApplicationName = conflictingApplicationName; + } + + /** + * @return The conflicting application name (or null if unknown). + */ + public String getConflictingApplicationName() { + return conflictingApplicationName; + } + } /** * Creates a new case and makes it the current case. @@ -2725,7 +2783,11 @@ public class Case { "Case.progressMessage.creatingCaseDatabase=Creating case database...", "# {0} - exception message", "Case.exceptionMessage.couldNotGetDbServerConnectionInfo=Failed to get case database server conneciton info:\n{0}.", "# {0} - exception message", "Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database:\n{0}.", - "# {0} - exception message", "Case.exceptionMessage.couldNotSaveDbNameToMetadataFile=Failed to save case database name to case metadata file:\n{0}." + "# {0} - exception message", "Case.exceptionMessage.couldNotSaveDbNameToMetadataFile=Failed to save case database name to case metadata file:\n{0}.", + "Case_createCaseDatabase_fileLock_ioException=An error occurred while trying to get an exclusive lock on the case.", + "# {0} - appplicationName", + "Case_createCaseDatabase_fileLock_concurrentAccessException=The case is open in {0}. Please close it before attempting to open it in Autopsy.", + "Case_createCaseDatabase_fileLock_concurrentAccessException_defaultApp=another application" }) private void createCaseDatabase(ProgressIndicator progressIndicator) throws CaseActionException { progressIndicator.progress(Bundle.Case_progressMessage_creatingCaseDatabase()); @@ -2736,6 +2798,16 @@ public class Case { * with a standard name, physically located in the case * directory. */ + try { + tryAcquireFileLock(metadata.getCaseDirectory()); + } catch (IOException ex) { + throw new CaseActionException(Bundle.Case_createCaseDatabase_fileLock_ioException(), ex); + } catch (ConcurrentDbAccessException ex) { + throw new CaseActionException(Bundle.Case_createCaseDatabase_fileLock_concurrentAccessException( + StringUtils.defaultIfBlank(ex.getConflictingApplicationName(), + Bundle.Case_createCaseDatabase_fileLock_concurrentAccessException_defaultApp()) + ), ex); + } caseDb = SleuthkitCase.newCase(Paths.get(metadata.getCaseDirectory(), SINGLE_USER_CASE_DB_NAME).toString()); metadata.setCaseDatabaseName(SINGLE_USER_CASE_DB_NAME); } else { @@ -2772,7 +2844,11 @@ public class Case { "# {0} - exception message", "Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database:\n{0}.", "# {0} - exception message", "Case.exceptionMessage.unsupportedSchemaVersionMessage=Unsupported case database schema version:\n{0}.", "Case.exceptionMessage.contentProviderCouldNotBeFound=Content provider was specified for the case but could not be loaded.", - "Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. See Tools, Options, Multi-User." + "Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. See Tools, Options, Multi-User.", + "Case_openCaseDataBase_fileLock_ioException=An error occurred while trying to get an exclusive lock on the case.", + "# {0} - appplicationName", + "Case_openCaseDataBase_fileLock_concurrentAccessException=The case is open in {0}. Please close it before attempting to open it in Autopsy.", + "Case_openCaseDataBase_fileLock_concurrentAccessException_defaultApp=another application" }) private void openCaseDataBase(ProgressIndicator progressIndicator) throws CaseActionException { progressIndicator.progress(Bundle.Case_progressMessage_openingCaseDatabase()); @@ -2788,6 +2864,16 @@ public class Case { } if (CaseType.SINGLE_USER_CASE == metadata.getCaseType()) { + try { + tryAcquireFileLock(metadata.getCaseDirectory()); + } catch (IOException ex) { + throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_ioException(), ex); + } catch (ConcurrentDbAccessException ex) { + throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException( + StringUtils.defaultIfBlank(ex.getConflictingApplicationName(), + Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException_defaultApp()) + ), ex); + } caseDb = SleuthkitCase.openCase(metadata.getCaseDatabasePath(), contentProvider); } else if (UserPreferences.getIsMultiUserModeEnabled()) { caseDb = SleuthkitCase.openCase(databaseName, UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory(), contentProvider); @@ -3098,6 +3184,34 @@ public class Case { collaborationMonitor.shutdown(); } eventPublisher.closeRemoteEventChannel(); + } + + if (this.lockFileLock != null) { + try { + this.lockFileLock.close(); + this.lockFileLock = null; + } catch (Exception ex) { + logger.log(Level.WARNING, "There was an error closing the lock file lock", ex); + } + } + + if (this.lockFileChannel != null) { + try { + this.lockFileChannel.close(); + this.lockFileChannel = null; + } catch (Exception ex) { + logger.log(Level.WARNING, "There was an error closing the lock file channel", ex); + } + } + + + if (this.lockFileRaf != null) { + try { + this.lockFileRaf.close(); + this.lockFileRaf = null; + } catch (Exception ex) { + logger.log(Level.WARNING, "There was an error closing the lock file random access file", ex); + } } /* From 7b66af30a5d15e6c6cd1a0adb2d69e8b69241523 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Thu, 18 Apr 2024 21:19:18 -0400 Subject: [PATCH 16/25] fix --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 4681083400..cccd1dc856 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -801,6 +801,9 @@ public class Case { } finally { throw new ConcurrentDbAccessException("Unable to acquire lock on " + lockFile, conflictingApplication); } + } else { + lockFileRaf.setLength(0); + lockFileRaf.writeChars(APP_NAME); } } From 8ae984831bd76d14834124dc9df9d42b1301e6cf Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Fri, 19 Apr 2024 15:05:34 -0400 Subject: [PATCH 17/25] updates and fixes --- .../casemodule/Bundle.properties-MERGED | 8 + .../sleuthkit/autopsy/casemodule/Case.java | 106 ++---------- .../autopsy/casemodule/TskLockResources.java | 162 ++++++++++++++++++ 3 files changed, 186 insertions(+), 90 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/TskLockResources.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 1f9719688f..5dfaba3f43 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -110,6 +110,14 @@ 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_createCaseDatabase_fileLock_concurrentAccessException=The case is open in {0}. Please close it before attempting to open it in Autopsy. +Case_createCaseDatabase_fileLock_concurrentAccessException_defaultApp=another application +Case_createCaseDatabase_fileLock_ioException=An error occurred while trying to get an exclusive lock on the case. +# {0} - appplicationName +Case_openCaseDataBase_fileLock_concurrentAccessException=The case is open in {0}. Please close it before attempting to open it in Autopsy. +Case_openCaseDataBase_fileLock_concurrentAccessException_defaultApp=another application +Case_openCaseDataBase_fileLock_ioException=An error occurred while trying to get an exclusive lock on the case. 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 cccd1dc856..3e0a84e93f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -32,8 +32,8 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; import java.io.IOException; -import java.io.RandomAccessFile; import java.lang.reflect.InvocationTargetException; +import java.nio.channels.OverlappingFileLockException; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; @@ -78,6 +78,7 @@ import org.sleuthkit.autopsy.actions.OpenOutputFolderAction; import org.sleuthkit.autopsy.appservices.AutopsyService; import org.sleuthkit.autopsy.appservices.AutopsyService.CaseContext; import org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException; +import org.sleuthkit.autopsy.casemodule.TskLockResources.ConcurrentDbAccessException; import org.sleuthkit.autopsy.datasourcesummary.ui.DataSourceSummaryAction; import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent; import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent; @@ -183,7 +184,6 @@ public class Case { private static final String CASE_RESOURCES_THREAD_NAME = "%s-manage-case-resources"; private static final String NO_NODE_ERROR_MSG_FRAGMENT = "KeeperErrorCode = NoNode"; private static final String CT_PROVIDER_PREFIX = "CTStandardContentProvider_"; - private static final String LOCK_FILE_NAME = "lock"; private static final Logger logger = Logger.getLogger(Case.class.getName()); private static final AutopsyEventPublisher eventPublisher = new AutopsyEventPublisher(); private static final Object caseActionSerializationLock = new Object(); @@ -199,11 +199,8 @@ public class Case { private final SleuthkitEventListener sleuthkitEventListener; private CollaborationMonitor collaborationMonitor; private Services caseServices; - - private RansomAccessFile lockFileRaf = null; - private FileChannel lockFileChannel = null; - private FileLock lockFileLock = null; - + + private TskLockResources tskLockResources = null; private volatile boolean hasDataSource = false; private volatile boolean hasData = false; @@ -217,6 +214,7 @@ public class Case { mainFrame = WindowManager.getDefault().getMainWindow(); }); } + /** * An enumeration of case types. @@ -777,59 +775,6 @@ public class Case { || caseName.contains("<") || caseName.contains(">") || caseName.contains("|")); } - - /** - * Try to acquire a lock to the lock file in the case directory. - * @param caseDir The case directory that the autopsy.db is in. - * @throws IllegalAccessException - * @throws IOException - */ - private void tryAcquireFileLock(String caseDir) throws ConcurrentDbAccessException, IOException { - File lockFile = new File(caseDir, LOCK_FILE_NAME); - lockFile.getParentFile().mkdirs(); - lockFileRaf = new RandomAccessFile(lockFile, "rw"); - lockFileChannel = lockFileRaf.getChannel(); - lockFileLock = lockFileChannel.tryLock(); - if (lockFileLock == null) { - String conflictingApplication = null; - try { - StringBuffer buffer = new StringBuffer(); - while (lockFileRaf.getFilePointer() < lockFileRaf.length()) { - buffer.append(lockFileRaf.readLine() + System.lineSeparator()); - } - conflictingApplication = buffer.toString(); - } finally { - throw new ConcurrentDbAccessException("Unable to acquire lock on " + lockFile, conflictingApplication); - } - } else { - lockFileRaf.setLength(0); - lockFileRaf.writeChars(APP_NAME); - } - } - - /** - * An exception thrown if the database is currently in use. - */ - private static class ConcurrentDbAccessException extends Exception { - private final String conflictingApplicationName; - - /** - * Constructor. - * @param message The exception message. - * @param conflictingApplicationName The conflicting application name (or null if unknown). - */ - public ConcurrentDbAccessException(String message, String conflictingApplicationName) { - super(message); - this.conflictingApplicationName = conflictingApplicationName; - } - - /** - * @return The conflicting application name (or null if unknown). - */ - public String getConflictingApplicationName() { - return conflictingApplicationName; - } - } /** * Creates a new case and makes it the current case. @@ -2802,13 +2747,13 @@ public class Case { * directory. */ try { - tryAcquireFileLock(metadata.getCaseDirectory()); - } catch (IOException ex) { - throw new CaseActionException(Bundle.Case_createCaseDatabase_fileLock_ioException(), ex); + this.tskLockResources = TskLockResources.tryAcquireFileLock(metadata.getCaseDirectory(), UserPreferences.getAppName()); + } catch (IOException | OverlappingFileLockException ex) { + throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_ioException(), ex); } catch (ConcurrentDbAccessException ex) { - throw new CaseActionException(Bundle.Case_createCaseDatabase_fileLock_concurrentAccessException( + throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException( StringUtils.defaultIfBlank(ex.getConflictingApplicationName(), - Bundle.Case_createCaseDatabase_fileLock_concurrentAccessException_defaultApp()) + Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException_defaultApp()) ), ex); } caseDb = SleuthkitCase.newCase(Paths.get(metadata.getCaseDirectory(), SINGLE_USER_CASE_DB_NAME).toString()); @@ -2868,8 +2813,8 @@ public class Case { if (CaseType.SINGLE_USER_CASE == metadata.getCaseType()) { try { - tryAcquireFileLock(metadata.getCaseDirectory()); - } catch (IOException ex) { + this.tskLockResources = TskLockResources.tryAcquireFileLock(metadata.getCaseDirectory(), UserPreferences.getAppName()); + } catch (IOException | OverlappingFileLockException ex) { throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_ioException(), ex); } catch (ConcurrentDbAccessException ex) { throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException( @@ -3189,34 +3134,15 @@ public class Case { eventPublisher.closeRemoteEventChannel(); } - if (this.lockFileLock != null) { + if (this.tskLockResources != null) { try { - this.lockFileLock.close(); - this.lockFileLock = null; + this.tskLockResources.close(); + this.tskLockResources = null; } catch (Exception ex) { - logger.log(Level.WARNING, "There was an error closing the lock file lock", ex); + logger.log(Level.WARNING, "There was an error closing the TSK case lock resources", ex); } } - if (this.lockFileChannel != null) { - try { - this.lockFileChannel.close(); - this.lockFileChannel = null; - } catch (Exception ex) { - logger.log(Level.WARNING, "There was an error closing the lock file channel", ex); - } - } - - - if (this.lockFileRaf != null) { - try { - this.lockFileRaf.close(); - this.lockFileRaf = null; - } catch (Exception ex) { - logger.log(Level.WARNING, "There was an error closing the lock file random access file", ex); - } - } - /* * Allow all registered application services providers to close * resources related to the case. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/TskLockResources.java b/Core/src/org/sleuthkit/autopsy/casemodule/TskLockResources.java new file mode 100644 index 0000000000..78c36cd984 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/TskLockResources.java @@ -0,0 +1,162 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2024 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.casemodule; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.channels.OverlappingFileLockException; +import org.apache.commons.lang3.StringUtils; + +/** + * The resources associated with the file lock for the TSK database. + */ +class TskLockResources implements AutoCloseable { + + private static final String LOCK_FILE_NAME = "lock"; + + private File lockFile = null; + private RandomAccessFile lockFileRaf = null; + private FileChannel lockFileChannel = null; + private FileLock lockFileLock = null; + + /** + * Constructor. + * + * @param lockFile The lock file File reference. + * @param lockFileRef The lock file random access file reference. + * @param lockFileChannel The lock file file channel. + * @param lockFileLock The lock file file lock. + */ + TskLockResources(File lockFile, RandomAccessFile lockFileRaf, FileChannel lockFileChannel, FileLock lockFileLock) { + this.lockFile = lockFile; + this.lockFileRaf = lockFileRaf; + this.lockFileChannel = lockFileChannel; + this.lockFileLock = lockFileLock; + } + + /** + * Try to acquire a lock to the lock file in the case directory. + * + * @param caseDir The case directory that the autopsy.db is in. + * @return The lock file resources to be closed. + * @throws IllegalAccessException + * @throws IOException + */ + static TskLockResources tryAcquireFileLock(String caseDir, String applicationName) throws ConcurrentDbAccessException, IOException, OverlappingFileLockException { + // get the lock file path + File lockFile = new File(caseDir, LOCK_FILE_NAME); + // make directories leading up to that + lockFile.getParentFile().mkdirs(); + + // if the lock file exists + if (lockFile.isFile() && !lockFile.canWrite()) { + // get the random access file as read only + RandomAccessFile lockFileRaf = new RandomAccessFile(lockFile, "r"); + throw ConcurrentDbAccessException.createForFile(lockFile.getAbsolutePath(), lockFileRaf); + } else { + RandomAccessFile lockFileRaf = new RandomAccessFile(lockFile, "rw"); + FileChannel lockFileChannel = lockFileRaf.getChannel(); + FileLock lockFileLock = lockFileChannel == null + ? null + : lockFileChannel.tryLock(1024L, 1L, false); + + if (lockFileLock != null) { + lockFileRaf.setLength(0); + lockFileRaf.writeChars(applicationName); + return new TskLockResources(lockFile, lockFileRaf, lockFileChannel, lockFileLock); + } else { + throw ConcurrentDbAccessException.createForFile(lockFile.getAbsolutePath(), lockFileRaf); + } + } + } + + @Override + public void close() throws Exception { + // close lock file resources in reverse acquisition order + if (this.lockFileLock != null) { + this.lockFileLock.close(); + this.lockFileLock = null; + } + + if (this.lockFileChannel != null) { + this.lockFileChannel.close(); + this.lockFileChannel = null; + } + + if (this.lockFileRaf != null) { + this.lockFileRaf.close(); + this.lockFileRaf = null; + } + + if (this.lockFile != null) { + this.lockFile.delete(); + this.lockFile = null; + } + } + + /** + * An exception thrown if the database is currently in use. + */ + static class ConcurrentDbAccessException extends Exception { + + private final String conflictingApplicationName; + + /** + * Creates a ConcurrentDbAccessException from the lock file path and the + * random access file of that path whose contents are the application + * name. + * + * @param lockFilePath The lock file path. + * @param lockFileRaf The lock file random access file. + * @return The exception + * @throws IOException + */ + static ConcurrentDbAccessException createForFile(String lockFilePath, RandomAccessFile lockFileRaf) throws IOException { + StringBuffer buffer = new StringBuffer(); + while (lockFileRaf.getFilePointer() < lockFileRaf.length()) { + buffer.append(lockFileRaf.readLine() + System.lineSeparator()); + } + String conflictingApplication = buffer.toString().trim(); + String message = "Unable to acquire lock on " + lockFilePath + "." + (StringUtils.isNotBlank(conflictingApplication) ? (" Database is already open in " + conflictingApplication + ".") : ""); + return new ConcurrentDbAccessException(message, conflictingApplication); + } + + /** + * Constructor. + * + * @param message The exception message. + * @param conflictingApplicationName The conflicting application name + * (or null if unknown). + */ + ConcurrentDbAccessException(String message, String conflictingApplicationName) { + super(message); + this.conflictingApplicationName = conflictingApplicationName; + } + + /** + * @return The conflicting application name (or null if unknown). + */ + public String getConflictingApplicationName() { + return conflictingApplicationName; + } + } +} From bed99ecbf61a47a1a4b1bdbba751b0d6ecdbeb60 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 22 Apr 2024 13:48:51 -0400 Subject: [PATCH 18/25] fixes --- .../casemodule/Bundle.properties-MERGED | 9 +- .../sleuthkit/autopsy/casemodule/Case.java | 95 +++++----- .../autopsy/casemodule/TskLockResources.java | 162 ------------------ 3 files changed, 45 insertions(+), 221 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/TskLockResources.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED index 5dfaba3f43..14465bba03 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED @@ -111,13 +111,8 @@ Case_checkImagePaths_exceptionOccurred=An exception occurred while checking if i # {0} - paths Case_checkImagePaths_noPaths=The following images had no associated paths: {0} # {0} - appplicationName -Case_createCaseDatabase_fileLock_concurrentAccessException=The case is open in {0}. Please close it before attempting to open it in Autopsy. -Case_createCaseDatabase_fileLock_concurrentAccessException_defaultApp=another application -Case_createCaseDatabase_fileLock_ioException=An error occurred while trying to get an exclusive lock on the case. -# {0} - appplicationName -Case_openCaseDataBase_fileLock_concurrentAccessException=The case is open in {0}. Please close it before attempting to open it in Autopsy. -Case_openCaseDataBase_fileLock_concurrentAccessException_defaultApp=another application -Case_openCaseDataBase_fileLock_ioException=An error occurred while trying to get an exclusive lock on the case. +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 3e0a84e93f..50dcca3f6f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -31,9 +31,7 @@ import java.awt.event.ActionListener; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; -import java.io.IOException; import java.lang.reflect.InvocationTargetException; -import java.nio.channels.OverlappingFileLockException; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; @@ -78,7 +76,6 @@ import org.sleuthkit.autopsy.actions.OpenOutputFolderAction; import org.sleuthkit.autopsy.appservices.AutopsyService; import org.sleuthkit.autopsy.appservices.AutopsyService.CaseContext; import org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException; -import org.sleuthkit.autopsy.casemodule.TskLockResources.ConcurrentDbAccessException; import org.sleuthkit.autopsy.datasourcesummary.ui.DataSourceSummaryAction; import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent; import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent; @@ -148,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; @@ -199,8 +197,7 @@ public class Case { private final SleuthkitEventListener sleuthkitEventListener; private CollaborationMonitor collaborationMonitor; private Services caseServices; - - private TskLockResources tskLockResources = null; + private volatile boolean hasDataSource = false; private volatile boolean hasData = false; @@ -214,7 +211,6 @@ public class Case { mainFrame = WindowManager.getDefault().getMainWindow(); }); } - /** * An enumeration of case types. @@ -774,7 +770,6 @@ public class Case { || caseName.contains("*") || caseName.contains("?") || caseName.contains("\"") || caseName.contains("<") || caseName.contains(">") || caseName.contains("|")); } - /** * Creates a new case and makes it the current case. @@ -2731,11 +2726,7 @@ public class Case { "Case.progressMessage.creatingCaseDatabase=Creating case database...", "# {0} - exception message", "Case.exceptionMessage.couldNotGetDbServerConnectionInfo=Failed to get case database server conneciton info:\n{0}.", "# {0} - exception message", "Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database:\n{0}.", - "# {0} - exception message", "Case.exceptionMessage.couldNotSaveDbNameToMetadataFile=Failed to save case database name to case metadata file:\n{0}.", - "Case_createCaseDatabase_fileLock_ioException=An error occurred while trying to get an exclusive lock on the case.", - "# {0} - appplicationName", - "Case_createCaseDatabase_fileLock_concurrentAccessException=The case is open in {0}. Please close it before attempting to open it in Autopsy.", - "Case_createCaseDatabase_fileLock_concurrentAccessException_defaultApp=another application" + "# {0} - exception message", "Case.exceptionMessage.couldNotSaveDbNameToMetadataFile=Failed to save case database name to case metadata file:\n{0}." }) private void createCaseDatabase(ProgressIndicator progressIndicator) throws CaseActionException { progressIndicator.progress(Bundle.Case_progressMessage_creatingCaseDatabase()); @@ -2746,17 +2737,7 @@ public class Case { * with a standard name, physically located in the case * directory. */ - try { - this.tskLockResources = TskLockResources.tryAcquireFileLock(metadata.getCaseDirectory(), UserPreferences.getAppName()); - } catch (IOException | OverlappingFileLockException ex) { - throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_ioException(), ex); - } catch (ConcurrentDbAccessException ex) { - throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException( - StringUtils.defaultIfBlank(ex.getConflictingApplicationName(), - Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException_defaultApp()) - ), ex); - } - 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 { /* @@ -2768,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); @@ -2792,17 +2774,13 @@ public class Case { "# {0} - exception message", "Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database:\n{0}.", "# {0} - exception message", "Case.exceptionMessage.unsupportedSchemaVersionMessage=Unsupported case database schema version:\n{0}.", "Case.exceptionMessage.contentProviderCouldNotBeFound=Content provider was specified for the case but could not be loaded.", - "Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. See Tools, Options, Multi-User.", - "Case_openCaseDataBase_fileLock_ioException=An error occurred while trying to get an exclusive lock on the case.", - "# {0} - appplicationName", - "Case_openCaseDataBase_fileLock_concurrentAccessException=The case is open in {0}. Please close it before attempting to open it in Autopsy.", - "Case_openCaseDataBase_fileLock_concurrentAccessException_defaultApp=another application" + "Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. See Tools, Options, Multi-User." }) private void openCaseDataBase(ProgressIndicator progressIndicator) throws CaseActionException { 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())) { @@ -2810,19 +2788,9 @@ public class Case { } throw new CaseActionException(Bundle.Case_exceptionMessage_contentProviderCouldNotBeFound()); } - + if (CaseType.SINGLE_USER_CASE == metadata.getCaseType()) { - try { - this.tskLockResources = TskLockResources.tryAcquireFileLock(metadata.getCaseDirectory(), UserPreferences.getAppName()); - } catch (IOException | OverlappingFileLockException ex) { - throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_ioException(), ex); - } catch (ConcurrentDbAccessException ex) { - throw new CaseActionException(Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException( - StringUtils.defaultIfBlank(ex.getConflictingApplicationName(), - Bundle.Case_openCaseDataBase_fileLock_concurrentAccessException_defaultApp()) - ), ex); - } - 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 { @@ -2834,7 +2802,39 @@ 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 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); } } @@ -3132,17 +3132,8 @@ public class Case { collaborationMonitor.shutdown(); } eventPublisher.closeRemoteEventChannel(); - } - - if (this.tskLockResources != null) { - try { - this.tskLockResources.close(); - this.tskLockResources = null; - } catch (Exception ex) { - logger.log(Level.WARNING, "There was an error closing the TSK case lock resources", ex); - } } - + /* * Allow all registered application services providers to close * resources related to the case. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/TskLockResources.java b/Core/src/org/sleuthkit/autopsy/casemodule/TskLockResources.java deleted file mode 100644 index 78c36cd984..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/TskLockResources.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2024 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.casemodule; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; -import java.nio.channels.OverlappingFileLockException; -import org.apache.commons.lang3.StringUtils; - -/** - * The resources associated with the file lock for the TSK database. - */ -class TskLockResources implements AutoCloseable { - - private static final String LOCK_FILE_NAME = "lock"; - - private File lockFile = null; - private RandomAccessFile lockFileRaf = null; - private FileChannel lockFileChannel = null; - private FileLock lockFileLock = null; - - /** - * Constructor. - * - * @param lockFile The lock file File reference. - * @param lockFileRef The lock file random access file reference. - * @param lockFileChannel The lock file file channel. - * @param lockFileLock The lock file file lock. - */ - TskLockResources(File lockFile, RandomAccessFile lockFileRaf, FileChannel lockFileChannel, FileLock lockFileLock) { - this.lockFile = lockFile; - this.lockFileRaf = lockFileRaf; - this.lockFileChannel = lockFileChannel; - this.lockFileLock = lockFileLock; - } - - /** - * Try to acquire a lock to the lock file in the case directory. - * - * @param caseDir The case directory that the autopsy.db is in. - * @return The lock file resources to be closed. - * @throws IllegalAccessException - * @throws IOException - */ - static TskLockResources tryAcquireFileLock(String caseDir, String applicationName) throws ConcurrentDbAccessException, IOException, OverlappingFileLockException { - // get the lock file path - File lockFile = new File(caseDir, LOCK_FILE_NAME); - // make directories leading up to that - lockFile.getParentFile().mkdirs(); - - // if the lock file exists - if (lockFile.isFile() && !lockFile.canWrite()) { - // get the random access file as read only - RandomAccessFile lockFileRaf = new RandomAccessFile(lockFile, "r"); - throw ConcurrentDbAccessException.createForFile(lockFile.getAbsolutePath(), lockFileRaf); - } else { - RandomAccessFile lockFileRaf = new RandomAccessFile(lockFile, "rw"); - FileChannel lockFileChannel = lockFileRaf.getChannel(); - FileLock lockFileLock = lockFileChannel == null - ? null - : lockFileChannel.tryLock(1024L, 1L, false); - - if (lockFileLock != null) { - lockFileRaf.setLength(0); - lockFileRaf.writeChars(applicationName); - return new TskLockResources(lockFile, lockFileRaf, lockFileChannel, lockFileLock); - } else { - throw ConcurrentDbAccessException.createForFile(lockFile.getAbsolutePath(), lockFileRaf); - } - } - } - - @Override - public void close() throws Exception { - // close lock file resources in reverse acquisition order - if (this.lockFileLock != null) { - this.lockFileLock.close(); - this.lockFileLock = null; - } - - if (this.lockFileChannel != null) { - this.lockFileChannel.close(); - this.lockFileChannel = null; - } - - if (this.lockFileRaf != null) { - this.lockFileRaf.close(); - this.lockFileRaf = null; - } - - if (this.lockFile != null) { - this.lockFile.delete(); - this.lockFile = null; - } - } - - /** - * An exception thrown if the database is currently in use. - */ - static class ConcurrentDbAccessException extends Exception { - - private final String conflictingApplicationName; - - /** - * Creates a ConcurrentDbAccessException from the lock file path and the - * random access file of that path whose contents are the application - * name. - * - * @param lockFilePath The lock file path. - * @param lockFileRaf The lock file random access file. - * @return The exception - * @throws IOException - */ - static ConcurrentDbAccessException createForFile(String lockFilePath, RandomAccessFile lockFileRaf) throws IOException { - StringBuffer buffer = new StringBuffer(); - while (lockFileRaf.getFilePointer() < lockFileRaf.length()) { - buffer.append(lockFileRaf.readLine() + System.lineSeparator()); - } - String conflictingApplication = buffer.toString().trim(); - String message = "Unable to acquire lock on " + lockFilePath + "." + (StringUtils.isNotBlank(conflictingApplication) ? (" Database is already open in " + conflictingApplication + ".") : ""); - return new ConcurrentDbAccessException(message, conflictingApplication); - } - - /** - * Constructor. - * - * @param message The exception message. - * @param conflictingApplicationName The conflicting application name - * (or null if unknown). - */ - ConcurrentDbAccessException(String message, String conflictingApplicationName) { - super(message); - this.conflictingApplicationName = conflictingApplicationName; - } - - /** - * @return The conflicting application name (or null if unknown). - */ - public String getConflictingApplicationName() { - return conflictingApplicationName; - } - } -} From 8fa375f172928c85958d78c936848471366a790c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 23 Apr 2024 11:28:19 -0400 Subject: [PATCH 19/25] updates for tsk lib lock --- .../autopsy/datamodel/Installer.java | 50 +++++++++++++++++-- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java b/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java index 323424efdf..297c93ece3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.datamodel; import java.awt.Component; +import java.io.IOException; import java.util.logging.Level; import org.openide.util.NbBundle; @@ -26,6 +27,8 @@ 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.autopsy.datamodel.TskLibLock.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=It appears that an older version of an application that opens The Sleuth Kit databases is currently running on your system. Close this application before opening Autopsy, and consider upgrading in order to have a better user experience." + }) @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,17 @@ 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 { + try { + TskLibLock libLock = TskLibLock.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() : "")); + } + } catch (IOException ex) { + logger.log(Level.SEVERE, "An error occurred while acquiring the TSK lib lock", ex); + } + String skVersion = SleuthkitJNI.getVersion(); if (skVersion == null) { @@ -71,15 +90,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 +120,15 @@ public class Installer extends ModuleInstall { } } + + /** + * An exception when an older application (Autopsy + */ + static class OldAppLockException extends Exception { + + public OldAppLockException(String message) { + super(message); + } + + } } From 86fbba96590ff0bb8ea2be01574c885397318074 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 23 Apr 2024 11:29:56 -0400 Subject: [PATCH 20/25] updates for tsk lib lock --- .../autopsy/datamodel/TskLibLock.java | 283 ++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/TskLibLock.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TskLibLock.java b/Core/src/org/sleuthkit/autopsy/datamodel/TskLibLock.java new file mode 100644 index 0000000000..0ca02cc40a --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TskLibLock.java @@ -0,0 +1,283 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2024 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.datamodel; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.file.Paths; +import java.text.MessageFormat; +import java.util.Arrays; + +/** + * Creates a file lock at the old location (Autopsy LTE 4.21.0) of TSK + * libraries, and does so in such a way that newer versions can determine that + * it is a new application holding the lock. + */ +class TskLibLock implements AutoCloseable { + + private static final String DLL_EXT = "dll"; + private static final String DYLIB_EXT = "dylib"; + private static final String SO_EXT = "so"; + + private static final String LIBTSK_JNI_LIB = "libtsk_jni"; + + private static final String LIB_FILE_LOCK_TEXT = "lib_lock"; + + private static final String TMP_DIR_KEY = "java.io.tmpdir"; + private static final String USER_NAME_KEY = "user.name"; + + private static final byte[] UTF8_BOM = {(byte) 0XEF, (byte) 0xBB, (byte) 0XBF}; + + private static TskLibLock libLock = null; + + /** + * Attempts to acquire a file lock on the libtsk_jni library at the old + * location if there currently is no lock. + * + * @return The result of attempting to obtain the lock including the result + * type (lock held by new application, lock held by old application, lock + * acquired) and any resources if the lock is acquired. + * @throws IOException + */ + static TskLibLock acquireLibLock() throws IOException { + if (libLock == null) { + libLock = getLibLock(); + } + return libLock; + } + + /** + * Removes any library file lock present. + * + * @throws Exception If there is an error closing the lock resources. + */ + static void removeLibLock() throws Exception { + if (libLock != null) { + libLock.close(); + } + } + + /** + * Gets the lib lock for the libtsk_jni library at the old location. + * + * @return The result of attempting to obtain the lock including the result + * type (lock held by new application, lock held by old application, lock + * acquired) and any resources if the lock is acquired. + * @throws IOException + */ + private static TskLibLock getLibLock() throws IOException { + // TODO error handling cleanup + + String libExt = getLibExtension(); + File libTskJniFile = Paths.get( + System.getProperty(TMP_DIR_KEY, ""), + MessageFormat.format("{0}_{1}.{2}", + LIBTSK_JNI_LIB, + System.getProperty(USER_NAME_KEY, ""), + libExt)).toFile(); + + // if the lock file exists + if (libTskJniFile.isFile() && !libTskJniFile.canWrite()) { + // get the random access file as read only + try (RandomAccessFile lockFileRaf = new RandomAccessFile(libTskJniFile, "r")) { + LockState lockState = isNewLock(lockFileRaf) + ? LockState.HELD_BY_NEW + : LockState.HELD_BY_OLD; + + return new TskLibLock(lockState, libTskJniFile, lockFileRaf, null, null); + } + } else { + // make directories leading up to that + libTskJniFile.getParentFile().mkdirs(); + + // get file access to the file + RandomAccessFile lockFileRaf = new RandomAccessFile(libTskJniFile, "rw"); + FileChannel lockFileChannel = lockFileRaf.getChannel(); + FileLock lockFileLock = lockFileChannel == null + ? null + : lockFileChannel.tryLock(1024L, 1L, false); + + if (lockFileLock != null) { + lockFileRaf.setLength(0); + lockFileRaf.write(UTF8_BOM); + lockFileRaf.writeChars(LIB_FILE_LOCK_TEXT); + + return new TskLibLock(LockState.ACQUIRED, libTskJniFile, lockFileRaf, lockFileChannel, lockFileLock); + } else { + if (lockFileChannel != null) { + lockFileChannel.close(); + } + + if (lockFileRaf != null) { + lockFileRaf.close(); + } + + LockState lockState = isNewLock(lockFileRaf) + ? LockState.HELD_BY_NEW + : LockState.HELD_BY_OLD; + + return new TskLibLock(lockState, libTskJniFile, lockFileRaf, lockFileChannel, null); + } + } + } + + /** + * Returns true if the file is locked by a newer application (Autopsy GT + * 4.21.0). + * + * @param libRaf The random access file. + * @return True if lock held by a newer application. + * @throws IOException + */ + private static boolean isNewLock(RandomAccessFile libRaf) throws IOException { + libRaf.seek(0); + byte[] startFileArr = new byte[UTF8_BOM.length]; + int read = libRaf.read(startFileArr); + return read == startFileArr.length && Arrays.equals(UTF8_BOM, startFileArr); + + } + + private File libTskJniFile; + private RandomAccessFile lockFileRaf; + private FileChannel lockFileChannel; + private FileLock lockFileLock; + private LockState lockState; + + /** + * Constructor + * + * @param lockState The lock state. + * @param lockFile The lock file or null. + * @param lockFileRaf The lock file random access file or null. + * @param lockFileChannel The lock file channel or null. + * @param lockFileLock The lock file lock or null. + */ + private TskLibLock( + LockState lockState, + File lockFile, + RandomAccessFile lockFileRaf, + FileChannel lockFileChannel, + FileLock lockFileLock) { + + this.libTskJniFile = lockFile; + this.lockFileRaf = lockFileRaf; + this.lockFileChannel = lockFileChannel; + this.lockFileLock = lockFileLock; + this.lockState = lockState; + } + + /** + * @return The lock state result of attempting to lock the file. + */ + LockState getLockState() { + return lockState; + } + + /** + * @return The file path for the lib tsk jni file. + */ + File getLibTskJniFile() { + return libTskJniFile; + } + + @Override + public void close() throws Exception { + // close lock file resources in reverse acquisition order + if (this.lockFileLock != null) { + this.lockFileLock.close(); + this.lockFileLock = null; + } + + if (this.lockFileChannel != null) { + this.lockFileChannel.close(); + this.lockFileChannel = null; + } + + if (this.lockFileRaf != null) { + this.lockFileRaf.close(); + this.lockFileRaf = null; + } + + if (this.libTskJniFile != null) { + this.libTskJniFile.delete(); + this.libTskJniFile = null; + } + } + + /** + * @return The library extension based on the operating system. + */ + private static String getLibExtension() { + if (isWindows()) { + return DLL_EXT; + } else if (isMac()) { + return DYLIB_EXT; + } else { + return SO_EXT; + } + } + + /** + * Is the platform Windows? + * + * @return + */ + private static boolean isWindows() { + return System.getProperty("os.name", "").toLowerCase().contains("windows"); + } + + /** + * Is the platform Mac? + * + * @return + */ + private static boolean isMac() { + return System.getProperty("os.name", "").toLowerCase().contains("mac"); + } + + /** + * Is the platform Linux? + * + * @return + */ + private static boolean isLinux() { + return System.getProperty("os.name", "").toLowerCase().contains("linux"); + } + + /** + * The result of attempting to lock the libtsk_jni lib file. + */ + enum LockState { + /** + * If a lock on the library is held by a version of Autopsy LTE 4.21.0 + */ + HELD_BY_OLD, + /** + * If a lock on the library is held by a version of Autopsy GT 4.21.0 + */ + HELD_BY_NEW, + /** + * If the lock has been acquired. + */ + ACQUIRED + } +} From f5082ead119d04c552041ced79381242ce5d5784 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 23 Apr 2024 15:22:50 -0400 Subject: [PATCH 21/25] updates and fixes --- .../org/sleuthkit/autopsy/core/Installer.java | 10 ++-- .../datamodel/Bundle.properties-MERGED | 2 + .../autopsy/datamodel/Installer.java | 36 +++++++++--- .../autopsy/datamodel/TskLibLock.java | 56 ++++++++++--------- 4 files changed, 65 insertions(+), 39 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/Installer.java b/Core/src/org/sleuthkit/autopsy/core/Installer.java index 7ef296e0c2..e8b1c79196 100644 --- a/Core/src/org/sleuthkit/autopsy/core/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/core/Installer.java @@ -575,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 { @@ -591,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(); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED index 4d958cf39b..26df51a9ba 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=It appears that an older version of an application that opens The Sleuth Kit databases is currently running on your system.
Close this application before opening Autopsy, and consider upgrading in order to have a better user experience. +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 297c93ece3..74485e09ef 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.datamodel; import java.awt.Component; -import java.io.IOException; import java.util.logging.Level; import org.openide.util.NbBundle; @@ -51,7 +50,7 @@ public class Installer extends ModuleInstall { @Messages({ "Installer_validate_tskLibLock_title=Error calling Sleuth Kit library", - "Installer_validate_tskLibLock_description=It appears that an older version of an application that opens The Sleuth Kit databases is currently running on your system. Close this application before opening Autopsy, and consider upgrading in order to have a better user experience." + "Installer_validate_tskLibLock_description=It appears that an older version of an application that opens The Sleuth Kit databases is currently running on your system.
Close this application before opening Autopsy, and consider upgrading in order to have a better user experience." }) @Override public void validate() throws IllegalStateException { @@ -70,13 +69,9 @@ public class Installer extends ModuleInstall { Logger logger = Logger.getLogger(Installer.class.getName()); try { - try { - TskLibLock libLock = TskLibLock.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() : "")); - } - } catch (IOException ex) { - logger.log(Level.SEVERE, "An error occurred while acquiring the TSK lib lock", ex); + TskLibLock libLock = TskLibLock.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(); @@ -120,7 +115,30 @@ public class Installer extends ModuleInstall { } } + + @Override + public void close() { + try { + TskLibLock.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 { + TskLibLock.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 */ diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TskLibLock.java b/Core/src/org/sleuthkit/autopsy/datamodel/TskLibLock.java index 0ca02cc40a..484e2a81de 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TskLibLock.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TskLibLock.java @@ -26,6 +26,7 @@ import java.nio.channels.FileLock; import java.nio.file.Paths; import java.text.MessageFormat; import java.util.Arrays; +import java.util.logging.Level; /** * Creates a file lock at the old location (Autopsy LTE 4.21.0) of TSK @@ -58,7 +59,7 @@ class TskLibLock implements AutoCloseable { * acquired) and any resources if the lock is acquired. * @throws IOException */ - static TskLibLock acquireLibLock() throws IOException { + static TskLibLock acquireLibLock() { if (libLock == null) { libLock = getLibLock(); } @@ -84,7 +85,7 @@ class TskLibLock implements AutoCloseable { * acquired) and any resources if the lock is acquired. * @throws IOException */ - private static TskLibLock getLibLock() throws IOException { + private static TskLibLock getLibLock() { // TODO error handling cleanup String libExt = getLibExtension(); @@ -104,38 +105,43 @@ class TskLibLock implements AutoCloseable { : LockState.HELD_BY_OLD; return new TskLibLock(lockState, libTskJniFile, lockFileRaf, null, null); + } catch (IOException ex) { + // if there is an error getting read only access, then it is the old application dll + java.util.logging.Logger.getLogger(TskLibLock.class.getCanonicalName()).log(Level.WARNING, "An error occurred while acquiring the TSK lib lock", ex); + return new TskLibLock(LockState.HELD_BY_OLD, libTskJniFile, null, null, null); } } else { // make directories leading up to that libTskJniFile.getParentFile().mkdirs(); // get file access to the file - RandomAccessFile lockFileRaf = new RandomAccessFile(libTskJniFile, "rw"); - FileChannel lockFileChannel = lockFileRaf.getChannel(); - FileLock lockFileLock = lockFileChannel == null - ? null - : lockFileChannel.tryLock(1024L, 1L, false); + RandomAccessFile lockFileRaf = null; + FileChannel lockFileChannel = null; + FileLock lockFileLock = null; + try { + lockFileRaf = new RandomAccessFile(libTskJniFile, "rw"); + lockFileChannel = lockFileRaf.getChannel(); + lockFileLock = lockFileChannel == null + ? null + : lockFileChannel.tryLock(1024L, 1L, false); - if (lockFileLock != null) { - lockFileRaf.setLength(0); - lockFileRaf.write(UTF8_BOM); - lockFileRaf.writeChars(LIB_FILE_LOCK_TEXT); + if (lockFileLock != null) { + lockFileRaf.setLength(0); + lockFileRaf.write(UTF8_BOM); + lockFileRaf.writeChars(LIB_FILE_LOCK_TEXT); - return new TskLibLock(LockState.ACQUIRED, libTskJniFile, lockFileRaf, lockFileChannel, lockFileLock); - } else { - if (lockFileChannel != null) { - lockFileChannel.close(); + return new TskLibLock(LockState.ACQUIRED, libTskJniFile, lockFileRaf, lockFileChannel, lockFileLock); + } else { + LockState lockState = isNewLock(lockFileRaf) + ? LockState.HELD_BY_NEW + : LockState.HELD_BY_OLD; + + return new TskLibLock(lockState, libTskJniFile, lockFileRaf, lockFileChannel, null); } - - if (lockFileRaf != null) { - lockFileRaf.close(); - } - - LockState lockState = isNewLock(lockFileRaf) - ? LockState.HELD_BY_NEW - : LockState.HELD_BY_OLD; - - return new TskLibLock(lockState, libTskJniFile, lockFileRaf, lockFileChannel, null); + } catch (IOException ex) { + // if there is an error getting read only access, then it is the old application dll + java.util.logging.Logger.getLogger(TskLibLock.class.getCanonicalName()).log(Level.WARNING, "An error occurred while acquiring the TSK lib lock", ex); + return new TskLibLock(LockState.HELD_BY_OLD, libTskJniFile, lockFileRaf, lockFileChannel, lockFileLock); } } } From 67242e28e76784177a06fc96f9596d325de5faec Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 24 Apr 2024 12:11:58 -0400 Subject: [PATCH 22/25] message update --- .../org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED | 2 +- Core/src/org/sleuthkit/autopsy/datamodel/Installer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED index 26df51a9ba..fb2079cccd 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED @@ -169,7 +169,7 @@ 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=It appears that an older version of an application that opens The Sleuth Kit databases is currently running on your system.
Close this application before opening Autopsy, and consider upgrading in order to have a better user experience. +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 diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java b/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java index 74485e09ef..6906951493 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java @@ -50,7 +50,7 @@ public class Installer extends ModuleInstall { @Messages({ "Installer_validate_tskLibLock_title=Error calling Sleuth Kit library", - "Installer_validate_tskLibLock_description=It appears that an older version of an application that opens The Sleuth Kit databases is currently running on your system.
Close this application before opening Autopsy, and consider upgrading in order to have a better user experience." + "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 { From 25236a90b073fcb8ae4ec4702bddbd86c8694236 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 24 Apr 2024 20:32:22 -0400 Subject: [PATCH 23/25] library lock update --- .../autopsy/datamodel/Installer.java | 9 +- .../autopsy/datamodel/TskLibLock.java | 289 ------------------ 2 files changed, 5 insertions(+), 293 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/TskLibLock.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java b/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java index 6906951493..311250eb88 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Installer.java @@ -27,7 +27,8 @@ import javax.swing.JOptionPane; import org.openide.LifecycleManager; import org.openide.modules.ModuleInstall; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.datamodel.TskLibLock.LockState; +import org.sleuthkit.datamodel.LibraryLock; +import org.sleuthkit.datamodel.LibraryLock.LockState; import org.sleuthkit.datamodel.SleuthkitJNI; /** @@ -69,7 +70,7 @@ public class Installer extends ModuleInstall { Logger logger = Logger.getLogger(Installer.class.getName()); try { - TskLibLock libLock = TskLibLock.acquireLibLock(); + 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() : "")); } @@ -119,7 +120,7 @@ public class Installer extends ModuleInstall { @Override public void close() { try { - TskLibLock.removeLibLock(); + 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); @@ -129,7 +130,7 @@ public class Installer extends ModuleInstall { @Override public void uninstalled() { try { - TskLibLock.removeLibLock(); + 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); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TskLibLock.java b/Core/src/org/sleuthkit/autopsy/datamodel/TskLibLock.java deleted file mode 100644 index 484e2a81de..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TskLibLock.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2024 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.datamodel; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; -import java.nio.file.Paths; -import java.text.MessageFormat; -import java.util.Arrays; -import java.util.logging.Level; - -/** - * Creates a file lock at the old location (Autopsy LTE 4.21.0) of TSK - * libraries, and does so in such a way that newer versions can determine that - * it is a new application holding the lock. - */ -class TskLibLock implements AutoCloseable { - - private static final String DLL_EXT = "dll"; - private static final String DYLIB_EXT = "dylib"; - private static final String SO_EXT = "so"; - - private static final String LIBTSK_JNI_LIB = "libtsk_jni"; - - private static final String LIB_FILE_LOCK_TEXT = "lib_lock"; - - private static final String TMP_DIR_KEY = "java.io.tmpdir"; - private static final String USER_NAME_KEY = "user.name"; - - private static final byte[] UTF8_BOM = {(byte) 0XEF, (byte) 0xBB, (byte) 0XBF}; - - private static TskLibLock libLock = null; - - /** - * Attempts to acquire a file lock on the libtsk_jni library at the old - * location if there currently is no lock. - * - * @return The result of attempting to obtain the lock including the result - * type (lock held by new application, lock held by old application, lock - * acquired) and any resources if the lock is acquired. - * @throws IOException - */ - static TskLibLock acquireLibLock() { - if (libLock == null) { - libLock = getLibLock(); - } - return libLock; - } - - /** - * Removes any library file lock present. - * - * @throws Exception If there is an error closing the lock resources. - */ - static void removeLibLock() throws Exception { - if (libLock != null) { - libLock.close(); - } - } - - /** - * Gets the lib lock for the libtsk_jni library at the old location. - * - * @return The result of attempting to obtain the lock including the result - * type (lock held by new application, lock held by old application, lock - * acquired) and any resources if the lock is acquired. - * @throws IOException - */ - private static TskLibLock getLibLock() { - // TODO error handling cleanup - - String libExt = getLibExtension(); - File libTskJniFile = Paths.get( - System.getProperty(TMP_DIR_KEY, ""), - MessageFormat.format("{0}_{1}.{2}", - LIBTSK_JNI_LIB, - System.getProperty(USER_NAME_KEY, ""), - libExt)).toFile(); - - // if the lock file exists - if (libTskJniFile.isFile() && !libTskJniFile.canWrite()) { - // get the random access file as read only - try (RandomAccessFile lockFileRaf = new RandomAccessFile(libTskJniFile, "r")) { - LockState lockState = isNewLock(lockFileRaf) - ? LockState.HELD_BY_NEW - : LockState.HELD_BY_OLD; - - return new TskLibLock(lockState, libTskJniFile, lockFileRaf, null, null); - } catch (IOException ex) { - // if there is an error getting read only access, then it is the old application dll - java.util.logging.Logger.getLogger(TskLibLock.class.getCanonicalName()).log(Level.WARNING, "An error occurred while acquiring the TSK lib lock", ex); - return new TskLibLock(LockState.HELD_BY_OLD, libTskJniFile, null, null, null); - } - } else { - // make directories leading up to that - libTskJniFile.getParentFile().mkdirs(); - - // get file access to the file - RandomAccessFile lockFileRaf = null; - FileChannel lockFileChannel = null; - FileLock lockFileLock = null; - try { - lockFileRaf = new RandomAccessFile(libTskJniFile, "rw"); - lockFileChannel = lockFileRaf.getChannel(); - lockFileLock = lockFileChannel == null - ? null - : lockFileChannel.tryLock(1024L, 1L, false); - - if (lockFileLock != null) { - lockFileRaf.setLength(0); - lockFileRaf.write(UTF8_BOM); - lockFileRaf.writeChars(LIB_FILE_LOCK_TEXT); - - return new TskLibLock(LockState.ACQUIRED, libTskJniFile, lockFileRaf, lockFileChannel, lockFileLock); - } else { - LockState lockState = isNewLock(lockFileRaf) - ? LockState.HELD_BY_NEW - : LockState.HELD_BY_OLD; - - return new TskLibLock(lockState, libTskJniFile, lockFileRaf, lockFileChannel, null); - } - } catch (IOException ex) { - // if there is an error getting read only access, then it is the old application dll - java.util.logging.Logger.getLogger(TskLibLock.class.getCanonicalName()).log(Level.WARNING, "An error occurred while acquiring the TSK lib lock", ex); - return new TskLibLock(LockState.HELD_BY_OLD, libTskJniFile, lockFileRaf, lockFileChannel, lockFileLock); - } - } - } - - /** - * Returns true if the file is locked by a newer application (Autopsy GT - * 4.21.0). - * - * @param libRaf The random access file. - * @return True if lock held by a newer application. - * @throws IOException - */ - private static boolean isNewLock(RandomAccessFile libRaf) throws IOException { - libRaf.seek(0); - byte[] startFileArr = new byte[UTF8_BOM.length]; - int read = libRaf.read(startFileArr); - return read == startFileArr.length && Arrays.equals(UTF8_BOM, startFileArr); - - } - - private File libTskJniFile; - private RandomAccessFile lockFileRaf; - private FileChannel lockFileChannel; - private FileLock lockFileLock; - private LockState lockState; - - /** - * Constructor - * - * @param lockState The lock state. - * @param lockFile The lock file or null. - * @param lockFileRaf The lock file random access file or null. - * @param lockFileChannel The lock file channel or null. - * @param lockFileLock The lock file lock or null. - */ - private TskLibLock( - LockState lockState, - File lockFile, - RandomAccessFile lockFileRaf, - FileChannel lockFileChannel, - FileLock lockFileLock) { - - this.libTskJniFile = lockFile; - this.lockFileRaf = lockFileRaf; - this.lockFileChannel = lockFileChannel; - this.lockFileLock = lockFileLock; - this.lockState = lockState; - } - - /** - * @return The lock state result of attempting to lock the file. - */ - LockState getLockState() { - return lockState; - } - - /** - * @return The file path for the lib tsk jni file. - */ - File getLibTskJniFile() { - return libTskJniFile; - } - - @Override - public void close() throws Exception { - // close lock file resources in reverse acquisition order - if (this.lockFileLock != null) { - this.lockFileLock.close(); - this.lockFileLock = null; - } - - if (this.lockFileChannel != null) { - this.lockFileChannel.close(); - this.lockFileChannel = null; - } - - if (this.lockFileRaf != null) { - this.lockFileRaf.close(); - this.lockFileRaf = null; - } - - if (this.libTskJniFile != null) { - this.libTskJniFile.delete(); - this.libTskJniFile = null; - } - } - - /** - * @return The library extension based on the operating system. - */ - private static String getLibExtension() { - if (isWindows()) { - return DLL_EXT; - } else if (isMac()) { - return DYLIB_EXT; - } else { - return SO_EXT; - } - } - - /** - * Is the platform Windows? - * - * @return - */ - private static boolean isWindows() { - return System.getProperty("os.name", "").toLowerCase().contains("windows"); - } - - /** - * Is the platform Mac? - * - * @return - */ - private static boolean isMac() { - return System.getProperty("os.name", "").toLowerCase().contains("mac"); - } - - /** - * Is the platform Linux? - * - * @return - */ - private static boolean isLinux() { - return System.getProperty("os.name", "").toLowerCase().contains("linux"); - } - - /** - * The result of attempting to lock the libtsk_jni lib file. - */ - enum LockState { - /** - * If a lock on the library is held by a version of Autopsy LTE 4.21.0 - */ - HELD_BY_OLD, - /** - * If a lock on the library is held by a version of Autopsy GT 4.21.0 - */ - HELD_BY_NEW, - /** - * If the lock has been acquired. - */ - ACQUIRED - } -} From e36d6f83e9e5f4f1bd794ae6defe34e5aa223afe Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 8 May 2024 11:33:03 -0400 Subject: [PATCH 24/25] fix for NPE --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 50dcca3f6f..221acc3e68 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -2823,11 +2823,14 @@ public class Case { 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) { + if (curEx == null) { + break; + } else if (curEx instanceof ConcurrentDbAccessException foundEx) { concurrentEx = foundEx; break; + } else { + curEx = curEx.getCause(); } - curEx = curEx.getCause(); } if (concurrentEx != null) { From 1317b5e3a541e777b91f817103fe6223725d7217 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 8 May 2024 15:20:20 -0400 Subject: [PATCH 25/25] wrong call for newCase --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 221acc3e68..0923666a87 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -2737,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, APP_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 { /*