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 f8dbebe224..12412aae20 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java @@ -62,6 +62,7 @@ import org.sleuthkit.autopsy.report.ReportProgressPanel; import org.sleuthkit.caseuco.CaseUcoExporter; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Account; +import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.Blackboard.BlackboardException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; @@ -69,12 +70,19 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.CaseDbAccessManager; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.DataArtifact; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.Host; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.LocalFilesDataSource; +import org.sleuthkit.datamodel.OsAccount; +import org.sleuthkit.datamodel.OsAccountManager; +import org.sleuthkit.datamodel.OsAccountManager.NotUserSIDException; +import org.sleuthkit.datamodel.OsAccountRealm; +import org.sleuthkit.datamodel.OsAccountRealmManager; import org.sleuthkit.datamodel.Pool; +import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction; import org.sleuthkit.datamodel.TagName; @@ -132,6 +140,12 @@ public class PortableCaseReportModule implements ReportModule { // Map of old artifact ID to new artifact private final Map oldArtifactIdToNewArtifact = new HashMap<>(); + + // Map of old OS account id to new OS account id + private final Map oldOsAccountIdToNewOsAccountId = new HashMap<>(); + + // Map of old OS account realm id to new OS account ream id + private final Map oldRealmIdToNewRealm = new HashMap<>(); public PortableCaseReportModule() { } @@ -392,8 +406,8 @@ public class PortableCaseReportModule implements ReportModule { // Copy interesting files and results if (!setNames.isEmpty()) { try { - List interestingFiles = currentCase.getSleuthkitCase().getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); - for (BlackboardArtifact art : interestingFiles) { + List interestingFiles = currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultsByType(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID()); + for (AnalysisResult art : interestingFiles) { // Check for cancellation if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { handleCancellation(progressPanel); @@ -411,8 +425,8 @@ public class PortableCaseReportModule implements ReportModule { } try { - List interestingResults = currentCase.getSleuthkitCase().getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); - for (BlackboardArtifact art : interestingResults) { + List interestingResults = currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultsByType(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()); + for (AnalysisResult art : interestingResults) { // Check for cancellation if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { handleCancellation(progressPanel); @@ -936,9 +950,6 @@ public class PortableCaseReportModule implements ReportModule { String.join(",", oldAssociatedAttribute.getSources()), newAssociatedArtifact.getArtifactID())); } - // Create the new artifact - int newArtifactTypeId = getNewArtifactTypeId(artifactToCopy); - BlackboardArtifact newArtifact = portableSkCase.newBlackboardArtifact(newArtifactTypeId, newContentId); List oldAttrs = artifactToCopy.getAttributes(); // Copy over each attribute, making sure the type is in the new case. @@ -977,8 +988,62 @@ public class PortableCaseReportModule implements ReportModule { throw new TskCoreException("Unexpected attribute value type found: " + oldAttr.getValueType().getLabel()); // NON-NLS } } - - newArtifact.addAttributes(newAttrs); + // Create the new artifact + int newArtifactTypeId = getNewArtifactTypeId(artifactToCopy); + BlackboardArtifact.Type newArtifactType = portableSkCase.getBlackboard().getArtifactType(newArtifactTypeId); + BlackboardArtifact newArtifact; + + // First, check if the artifact being copied is an AnalysisResult or a DataArtifact. If it + // is neither, attempt to reload it as the appropriate subclass. + if (!((artifactToCopy instanceof AnalysisResult) || (artifactToCopy instanceof DataArtifact))) { + try { + if (newArtifactType.getCategory().equals(BlackboardArtifact.Category.ANALYSIS_RESULT)) { + AnalysisResult ar = currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultById(artifactToCopy.getId()); + if (ar != null) { + artifactToCopy = ar; + } + } else { + DataArtifact da = currentCase.getSleuthkitCase().getBlackboard().getDataArtifactById(artifactToCopy.getId()); + if (da != null) { + artifactToCopy = da; + } + } + } catch (TskCoreException ex) { + // If the lookup failed, just use the orginal BlackboardArtifact + } + } + + try { + if (artifactToCopy instanceof AnalysisResult) { + AnalysisResult analysisResultToCopy = (AnalysisResult) artifactToCopy; + newArtifact = portableSkCase.getBlackboard().newAnalysisResult(newArtifactType, newContentId, + newIdToContent.get(newContentId).getDataSource().getId(), analysisResultToCopy.getScore(), + analysisResultToCopy.getConclusion(), analysisResultToCopy.getConfiguration(), + analysisResultToCopy.getJustification(), newAttrs).getAnalysisResult(); + } else if (artifactToCopy instanceof DataArtifact) { + DataArtifact dataArtifactToCopy = (DataArtifact) artifactToCopy; + Long newOsAccountId = null; + if (dataArtifactToCopy.getOsAccountObjectId().isPresent()) { + copyOsAccount(dataArtifactToCopy.getOsAccountObjectId().get()); + newOsAccountId = oldOsAccountIdToNewOsAccountId.get((dataArtifactToCopy.getOsAccountObjectId().get())); + } + newArtifact = portableSkCase.getBlackboard().newDataArtifact(newArtifactType, newContentId, + newIdToContent.get(newContentId).getDataSource().getId(), + newAttrs, newOsAccountId); + } else { + if (newArtifactType.getCategory().equals(BlackboardArtifact.Category.ANALYSIS_RESULT)) { + newArtifact = portableSkCase.getBlackboard().newAnalysisResult(newArtifactType, newContentId, + newIdToContent.get(newContentId).getDataSource().getId(), Score.SCORE_NONE, + null, null, null, newAttrs).getAnalysisResult(); + } else { + newArtifact = portableSkCase.getBlackboard().newDataArtifact(newArtifactType, newContentId, + newIdToContent.get(newContentId).getDataSource().getId(), + newAttrs, null); + } + } + } catch (BlackboardException ex) { + throw new TskCoreException("Error copying artifact with ID: " + artifactToCopy.getId()); + } oldArtifactIdToNewArtifact.put(artifactToCopy.getArtifactID(), newArtifact); return newArtifact; @@ -1088,6 +1153,14 @@ public class PortableCaseReportModule implements ReportModule { newHost = portableSkCase.getHostManager().newHost(oldHost.getName()); } + // Copy the associated OS account (if needed) before beginning transaction. + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile) content; + if (file.getOsAccountObjectId().isPresent()) { + copyOsAccount(file.getOsAccountObjectId().get()); + } + } + CaseDbTransaction trans = portableSkCase.beginTransaction(); try { if (content instanceof Image) { @@ -1140,10 +1213,16 @@ public class PortableCaseReportModule implements ReportModule { // Construct the relative path to the copied file String relativePath = FILE_FOLDER_NAME + File.separator + exportSubFolder + File.separator + fileName; + Long newOsAccountId = null; + if (abstractFile.getOsAccountObjectId().isPresent()) { + newOsAccountId = oldOsAccountIdToNewOsAccountId.get(abstractFile.getOsAccountObjectId().get()); + } + newContent = portableSkCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(), abstractFile.getCtime(), abstractFile.getCrtime(), abstractFile.getAtime(), abstractFile.getMtime(), abstractFile.getMd5Hash(), abstractFile.getSha256Hash(), abstractFile.getKnown(), abstractFile.getMIMEType(), - true, TskData.EncodingType.NONE, + true, TskData.EncodingType.NONE, + newOsAccountId, abstractFile.getOwnerUid().orElse(null), newParent, trans); } catch (IOException ex) { throw new TskCoreException("Error copying file " + abstractFile.getName() + " with original obj ID " @@ -1166,6 +1245,72 @@ public class PortableCaseReportModule implements ReportModule { newIdToContent.put(newContent.getId(), newContent); return oldIdToNewContent.get(content.getId()).getId(); } + + /** + * Copy an OS Account to the new case and add it to the oldOsAccountIdToNewOsAccountId map. + * Will also copy the associated realm. + * + * @param oldOsAccountId The OS account id in the current case. + */ + private void copyOsAccount(Long oldOsAccountId) throws TskCoreException { + // If it has already been copied, we're done. + if (oldOsAccountIdToNewOsAccountId.containsKey(oldOsAccountId)) { + return; + } + + // Load the OS account from the current case. + OsAccountManager oldOsAcctManager = currentCase.getSleuthkitCase().getOsAccountManager(); + OsAccount oldOsAccount = oldOsAcctManager.getOsAccountByObjectId(oldOsAccountId); + + // Load the realm associated with the OS account. + OsAccountRealmManager oldRealmManager = currentCase.getSleuthkitCase().getOsAccountRealmManager(); + OsAccountRealm oldRealm = oldRealmManager.getRealmByRealmId(oldOsAccount.getRealmId()); + + // Copy the realm to the portable case if necessary. + if (!oldRealmIdToNewRealm.containsKey(oldOsAccount.getRealmId())) { + OsAccountRealmManager newRealmManager = portableSkCase.getOsAccountRealmManager(); + + Host host = null; + if (oldRealm.getScopeHost().isPresent()) { + host = oldRealm.getScopeHost().get(); + } else { + if (oldRealm.getScope().equals(OsAccountRealm.RealmScope.DOMAIN)) { + // This is a workaround to get around needing a new method for copying the realm. + // The host won't be stored since it's a domain-scoped realm. + List hosts = portableSkCase.getHostManager().getAllHosts(); + if (hosts.isEmpty()) { + throw new TskCoreException("Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId() + " because there are no hosts in the case"); + } + host = hosts.get(0); + } else { + throw new TskCoreException("Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId() + " because it is non-domain scoped but has no scope host"); + } + } + + // We currently only support one realm name. + String realmName = null; + List names = oldRealm.getRealmNames(); + if (!names.isEmpty()) { + realmName = names.get(0); + } + + try { + OsAccountRealm newRealm = newRealmManager.newWindowsRealm(oldRealm.getRealmAddr().orElse(null), realmName, host, oldRealm.getScope()); + oldRealmIdToNewRealm.put(oldOsAccount.getRealmId(), newRealm); + } catch (NotUserSIDException ex) { + throw new TskCoreException("Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId(), ex); + } + } + + OsAccountManager newOsAcctManager = portableSkCase.getOsAccountManager(); + try { + OsAccount newOsAccount = newOsAcctManager.newWindowsOsAccount(oldOsAccount.getAddr().orElse(null), + oldOsAccount.getLoginName().orElse(null), oldRealmIdToNewRealm.get(oldOsAccount.getRealmId())); + oldOsAccountIdToNewOsAccountId.put(oldOsAccountId, newOsAccount.getId()); + } catch (NotUserSIDException ex) { + throw new TskCoreException("Failed to copy OsAccount with ID=" + oldOsAccount.getId(), ex); + } + } /** * Copy path ID attribute to new case along with the referenced file. @@ -1344,6 +1489,8 @@ public class PortableCaseReportModule implements ReportModule { oldArtTypeIdToNewArtTypeId.clear(); oldAttrTypeIdToNewAttrType.clear(); oldArtifactIdToNewArtifact.clear(); + oldOsAccountIdToNewOsAccountId.clear(); + oldRealmIdToNewRealm.clear(); closePortableCaseDatabase();