diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java index 89b696c041..300cce64c7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java @@ -30,6 +30,7 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.event.ListSelectionEvent; import javax.swing.table.AbstractTableModel; @@ -125,12 +126,15 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { } } this.ingestJobTableModel = new IngestJobTableModel(); - this.ingestJobTable.setModel(ingestJobTableModel); - //if there were ingest jobs select the first one by default - if (!ingestJobsForSelectedDataSource.isEmpty()) { - ingestJobTable.setRowSelectionInterval(0, 0); - } - this.repaint(); + + SwingUtilities.invokeLater(() -> { + this.ingestJobTable.setModel(ingestJobTableModel); + //if there were ingest jobs select the first one by default + if (!ingestJobsForSelectedDataSource.isEmpty()) { + ingestJobTable.setRowSelectionInterval(0, 0); + } + this.repaint(); + }); } /** @@ -168,7 +172,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { } } catch (InterruptedException | ExecutionException ex) { logger.log(Level.WARNING, "Error getting results from Ingest Job Info Panel's refresh worker", ex); - } catch (CancellationException ignored){ + } catch (CancellationException ignored) { logger.log(Level.INFO, "The refreshing of the IngestJobInfoPanel was cancelled"); } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 9f6054ac58..354978f7e5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -42,6 +42,7 @@ import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.swing.Action; +import javax.swing.SwingUtilities; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.openide.nodes.Node; @@ -203,27 +204,7 @@ public class BlackboardArtifactNode extends AbstractContentNode( - Bundle.BlackboardArtifactNode_createSheet_score_name(), - Bundle.BlackboardArtifactNode_createSheet_score_displayName(), - scoData.getScoreAndDescription().getRight(), - scoData.getScoreAndDescription().getLeft())); - } - if (scoData.getComment() != null) { - updateSheet(new NodeProperty<>( - Bundle.BlackboardArtifactNode_createSheet_comment_name(), - Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), - NO_DESCR, scoData.getComment())); - } - if (scoData.getCountAndDescription() != null) { - updateSheet(new NodeProperty<>( - Bundle.BlackboardArtifactNode_createSheet_count_name(), - Bundle.BlackboardArtifactNode_createSheet_count_displayName(), - scoData.getCountAndDescription().getRight(), - scoData.getCountAndDescription().getLeft())); - } + updateSCOColumns((SCOData) evt.getNewValue()); } else if (eventType.equals(FileNameTransTask.getPropertyName())) { /* * Replace the value of the Source File property with the @@ -910,14 +891,25 @@ public class BlackboardArtifactNode extends AbstractContentNode( + Bundle.BlackboardArtifactNode_createSheet_srcFile_name(), + Bundle.BlackboardArtifactNode_createSheet_srcFile_displayName(), + NO_DESCR, + getDisplayName())); + } + if (TextTranslationService.getInstance().hasProvider() && UserPreferences.displayTranslatedFileNames()) { /* * If machine translation is configured, add the original name of @@ -937,8 +929,8 @@ public class BlackboardArtifactNode extends AbstractContentNode( + Bundle.BlackboardArtifactNode_analysisSheet_soureName_name(), + Bundle.BlackboardArtifactNode_analysisSheet_soureName_name(), + NO_DESCR, + getDisplayName())); + + GetSCOTask task = addSCOColumns(sheetSet); sheetSet.put(new NodeProperty<>( Bundle.BlackboardArtifactNode_analysisSheet_sourceType_name(), @@ -1452,9 +1452,11 @@ public class BlackboardArtifactNode extends AbstractContentNode(this), weakListener)); + return new GetSCOTask(new WeakReference<>(this), weakListener); } + return null; } /** @@ -1519,31 +1522,44 @@ public class BlackboardArtifactNode extends AbstractContentNode( + Bundle.BlackboardArtifactNode_createSheet_score_name(), + Bundle.BlackboardArtifactNode_createSheet_score_displayName(), + scoData.getScoreAndDescription().getRight(), + scoData.getScoreAndDescription().getLeft())); + } + if (scoData.getComment() != null) { + updateSheet(new NodeProperty<>( + Bundle.BlackboardArtifactNode_createSheet_comment_name(), + Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), + NO_DESCR, scoData.getComment())); + } + if (scoData.getCountAndDescription() != null) { + updateSheet(new NodeProperty<>( + Bundle.BlackboardArtifactNode_createSheet_count_name(), + Bundle.BlackboardArtifactNode_createSheet_count_displayName(), + scoData.getCountAndDescription().getRight(), + scoData.getCountAndDescription().getLeft())); + } + } + }); + } + + /** + * Sets the displayName of the node based on the source content. */ private void setDisplayNameBySourceContent() { if(srcContent instanceof BlackboardArtifact) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED index f5da7a8696..847e10b58d 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED @@ -356,6 +356,9 @@ OsAccounts_accountNameProperty_name=Name OsAccounts_accountRealmNameProperty_desc=OS Account Realm Name OsAccounts_accountRealmNameProperty_displayName=Realm Name OsAccounts_accountRealmNameProperty_name=RealmName +OsAccounts_accountScopeNameProperty_desc=OS Account Scope Name +OsAccounts_accountScopeNameProperty_displayName=Scope +OsAccounts_accountScopeNameProperty_name=ScopeName OsAccounts_createdTimeProperty_desc=OS Account Creation Time OsAccounts_createdTimeProperty_displayName=Creation Time OsAccounts_createdTimeProperty_name=creationTime diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java index 60ad65c83f..6277dbfb0f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/GetSCOTask.java @@ -23,6 +23,7 @@ import java.beans.PropertyChangeListener; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang3.tuple.Pair; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.core.UserPreferences; @@ -30,6 +31,8 @@ import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.datamodel.Tag; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil; +import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; +import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.Content; @@ -62,12 +65,14 @@ class GetSCOTask implements Runnable { } // get the SCO column values List tags = contentNode.getAllTagsFromDatabase(); - SCOData scoData = new SCOData(); - scoData.setScoreAndDescription(contentNode.getScorePropertyAndDescription(tags)); + Pair scoreAndDescription; + DataResultViewerTable.HasCommentStatus comment; + Pair countAndDescription = null; + + scoreAndDescription = contentNode.getScorePropertyAndDescription(tags); //getting the correlation attribute and setting the comment column is done before the eamdb isEnabled check //because the Comment column will reflect the presence of comments in the CR when the CR is enabled, but reflect tag comments regardless String description = Bundle.GetSCOTask_occurrences_defaultDescription(); - List listOfPossibleAttributes = new ArrayList<>(); Content contentFromNode = contentNode.getContent(); if (contentFromNode instanceof AbstractFile) { @@ -79,7 +84,7 @@ class GetSCOTask implements Runnable { } else { //JIRA-TODO : add code for Jira-7938 OsAccounts } - scoData.setComment(contentNode.getCommentProperty(tags, listOfPossibleAttributes)); + comment = contentNode.getCommentProperty(tags, listOfPossibleAttributes); CorrelationAttributeInstance corInstance = null; if (CentralRepository.isEnabled()) { if (listOfPossibleAttributes.size() > 1) { @@ -89,16 +94,19 @@ class GetSCOTask implements Runnable { //there should only be one item in the list corInstance = listOfPossibleAttributes.get(0); } - scoData.setCountAndDescription(contentNode.getCountPropertyAndDescription(corInstance, description)); + countAndDescription = contentNode.getCountPropertyAndDescription(corInstance, description); } + if(Thread.currentThread().isInterrupted()) { + return; + } + // signal SCO data is available. - if (listener - != null) { + if (listener != null) { listener.propertyChange(new PropertyChangeEvent( AutopsyEvent.SourceType.LOCAL.toString(), AbstractAbstractFileNode.NodeSpecificEvents.SCO_AVAILABLE.toString(), - null, scoData)); + null, new SCOData(scoreAndDescription, comment, countAndDescription))); } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java index e74275503b..060c8f19ba 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java @@ -31,6 +31,8 @@ import java.util.Optional; import java.util.logging.Level; import java.util.stream.Collectors; import javax.swing.Action; +import javax.swing.SwingUtilities; +import org.apache.commons.lang3.StringUtils; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; @@ -208,6 +210,8 @@ public final class OsAccounts implements AutopsyVisitableItem { && evt.getNewValue() instanceof AsynchOsAcctData && ((AsynchOsAcctData) evt.getNewValue()).getOsAccountId() == account.getId()) { + List> propertiesToUpdate = new ArrayList<>(); + AsynchOsAcctData osAcctData = (AsynchOsAcctData) evt.getNewValue(); List realmNames = osAcctData.getOsAcctRealm().getRealmNames(); @@ -215,31 +219,42 @@ public final class OsAccounts implements AutopsyVisitableItem { String realmNamesStr = realmNames.stream() .map(String::trim) .distinct() - .sorted((a,b) -> a.compareToIgnoreCase(b)) + .sorted((a, b) -> a.compareToIgnoreCase(b)) .collect(Collectors.joining(", ")); - updateSheet(new NodeProperty<>( + propertiesToUpdate.add(new NodeProperty<>( Bundle.OsAccounts_accountRealmNameProperty_name(), Bundle.OsAccounts_accountRealmNameProperty_displayName(), Bundle.OsAccounts_accountRealmNameProperty_desc(), realmNamesStr)); } + String scopeName = osAcctData.getOsAcctRealm().getScope().getName(); + if (StringUtils.isNotBlank(scopeName)) { + propertiesToUpdate.add(new NodeProperty<>( + Bundle.OsAccounts_accountScopeNameProperty_name(), + Bundle.OsAccounts_accountScopeNameProperty_displayName(), + Bundle.OsAccounts_accountScopeNameProperty_desc(), + scopeName)); + } + List hosts = osAcctData.getHosts(); if (!hosts.isEmpty()) { String hostsString = hosts.stream() .map(h -> h.getName().trim()) .distinct() - .sorted((a,b) -> a.compareToIgnoreCase(b)) + .sorted((a, b) -> a.compareToIgnoreCase(b)) .collect(Collectors.joining(", ")); - updateSheet(new NodeProperty<>( + propertiesToUpdate.add(new NodeProperty<>( Bundle.OsAccounts_accountHostNameProperty_name(), Bundle.OsAccounts_accountHostNameProperty_displayName(), Bundle.OsAccounts_accountHostNameProperty_desc(), hostsString)); } + SwingUtilities.invokeLater(() -> + updateSheet(propertiesToUpdate.toArray(new NodeProperty[propertiesToUpdate.size()]))); } } }; @@ -296,6 +311,9 @@ public final class OsAccounts implements AutopsyVisitableItem { "OsAccounts_accountHostNameProperty_name=HostName", "OsAccounts_accountHostNameProperty_displayName=Host", "OsAccounts_accountHostNameProperty_desc=OS Account Host Name", + "OsAccounts_accountScopeNameProperty_name=ScopeName", + "OsAccounts_accountScopeNameProperty_displayName=Scope", + "OsAccounts_accountScopeNameProperty_desc=OS Account Scope Name", "OsAccounts_createdTimeProperty_name=creationTime", "OsAccounts_createdTimeProperty_displayName=Creation Time", "OsAccounts_createdTimeProperty_desc=OS Account Creation Time", @@ -332,20 +350,25 @@ public final class OsAccounts implements AutopsyVisitableItem { Bundle.OsAccounts_loginNameProperty_displayName(), Bundle.OsAccounts_loginNameProperty_desc(), optional.isPresent() ? optional.get() : "")); - // Fill with empty string, fetch on background task. - String realmName = ""; - propertiesSet.put(new NodeProperty<>( - Bundle.OsAccounts_accountRealmNameProperty_name(), - Bundle.OsAccounts_accountRealmNameProperty_displayName(), - Bundle.OsAccounts_accountRealmNameProperty_desc(), - realmName)); - String hostName = ""; + // Fill with empty string, fetch on background task. propertiesSet.put(new NodeProperty<>( Bundle.OsAccounts_accountHostNameProperty_name(), Bundle.OsAccounts_accountHostNameProperty_displayName(), Bundle.OsAccounts_accountHostNameProperty_desc(), - hostName)); + "")); + + propertiesSet.put(new NodeProperty<>( + Bundle.OsAccounts_accountScopeNameProperty_name(), + Bundle.OsAccounts_accountScopeNameProperty_displayName(), + Bundle.OsAccounts_accountScopeNameProperty_desc(), + "")); + + propertiesSet.put(new NodeProperty<>( + Bundle.OsAccounts_accountRealmNameProperty_name(), + Bundle.OsAccounts_accountRealmNameProperty_displayName(), + Bundle.OsAccounts_accountRealmNameProperty_desc(), + "")); Optional creationTimeValue = account.getCreationTime(); String timeDisplayStr @@ -442,9 +465,10 @@ public final class OsAccounts implements AutopsyVisitableItem { /** * Main constructor. + * * @param osAccountId The id of the os account. * @param osAcctRealm The realm of the os account. - * @param hosts The hosts that the os account belongs to. + * @param hosts The hosts that the os account belongs to. */ AsynchOsAcctData(long osAccountId, OsAccountRealm osAcctRealm, List hosts) { this.osAccountId = osAccountId; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SCOData.java b/Core/src/org/sleuthkit/autopsy/datamodel/SCOData.java index ed9d232034..1d496e377b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SCOData.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SCOData.java @@ -28,10 +28,16 @@ import org.sleuthkit.datamodel.Score; */ class SCOData { - private Pair scoreAndDescription = null; - private DataResultViewerTable.HasCommentStatus comment = null; - private Pair countAndDescription = null; + private final Pair scoreAndDescription; + private final DataResultViewerTable.HasCommentStatus comment; + private final Pair countAndDescription; + SCOData (Pair scoreAndDescription, DataResultViewerTable.HasCommentStatus comment, Pair countAndDescription){ + this.scoreAndDescription = scoreAndDescription; + this.comment = comment; + this.countAndDescription = countAndDescription; + } + Pair getScoreAndDescription() { return scoreAndDescription; } @@ -43,15 +49,4 @@ class SCOData { Pair getCountAndDescription() { return countAndDescription; } - - void setScoreAndDescription(Pair scoreAndDescription) { - this.scoreAndDescription = scoreAndDescription; - } - void setComment(DataResultViewerTable.HasCommentStatus comment) { - this.comment = comment; - } - void setCountAndDescription(Pair countAndDescription) { - this.countAndDescription = countAndDescription; - } - } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index f51bcbd0f4..2a60f35d4f 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -61,6 +61,7 @@ import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -750,7 +751,7 @@ class ExtractRegistry extends Extract { try{ sid = userMap.getKey(); String userName = userMap.getValue(); - createOrUpdateOsAccount(regFile, sid, userName, null); + createOrUpdateOsAccount(regFile, sid, userName, null, null, OsAccountRealm.RealmScope.LOCAL); } catch(TskCoreException | TskDataException | NotUserSIDException ex) { logger.log(Level.WARNING, String.format("Failed to update Domain for existing OsAccount: %s, sid: %s", regFile.getId(), sid), ex); } @@ -862,9 +863,15 @@ class ExtractRegistry extends Extract { String homeDir = value; String sid = artnode.getAttribute("sid"); //NON-NLS String username = artnode.getAttribute("username"); //NON-NLS - + String domName = domainName; + OsAccountRealm.RealmScope scope = OsAccountRealm.RealmScope.DOMAIN; + if(knownMachineSID(sid)) { + domName = null; + scope = OsAccountRealm.RealmScope.LOCAL; + } + try{ - createOrUpdateOsAccount(regFile, sid, username, homeDir); + createOrUpdateOsAccount(regFile, sid, username, homeDir, domName, scope); } catch(TskCoreException | TskDataException | NotUserSIDException ex) { logger.log(Level.SEVERE, String.format("Failed to create OsAccount for file: %s, sid: %s", regFile.getId(), sid), ex); } @@ -1105,13 +1112,14 @@ class ExtractRegistry extends Extract { String sid = optional.get(); Map userInfo = userInfoMap.remove(sid); if(userInfo != null) { + addAccountInstance(accountMgr, osAccount, (DataSource)dataSource); updateOsAccount(osAccount, userInfo, groupMap.get(sid), regAbstractFile); } } //add remaining userinfos as accounts; for (Map userInfo : userInfoMap.values()) { - OsAccount osAccount = accountMgr.newWindowsOsAccount(userInfo.get(SID_KEY), null, domainName, host, domainName != null && !domainName.isEmpty() ? OsAccountRealm.RealmScope.DOMAIN : OsAccountRealm.RealmScope.UNKNOWN); + OsAccount osAccount = accountMgr.newWindowsOsAccount(userInfo.get(SID_KEY), null, null, host, OsAccountRealm.RealmScope.LOCAL); accountMgr.newOsAccountInstance(osAccount, (DataSource)dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED); updateOsAccount(osAccount, userInfo, groupMap.get(userInfo.get(SID_KEY)), regAbstractFile); } @@ -1724,6 +1732,42 @@ class ExtractRegistry extends Extract { return map; } + /** + * Strip the machine sid off of the osAccountSID. The returned string will + * include everything in the osAccountSID up to the last -. + * + * @param osAccountSID The SID of the os account. + * + * @return The Machine SID + */ + private String getMachineSID(String osAccountSID) { + int index = osAccountSID.lastIndexOf("-"); + return osAccountSID.substring(0, index); + } + + private final List machineSIDs = new ArrayList<>(); + /** + * Returns true if the machine part of the SID was seen prior + * to ExtractRegistry running. + * + * @param osAccountSID + * + * @return + */ + private boolean knownMachineSID(String osAccountSID) { + if (machineSIDs.isEmpty()) { + Map userMap = getUserNameMap(); + for (String str : userMap.keySet()) { + String temp = getMachineSID(str); + if (!machineSIDs.contains(temp)) { + machineSIDs.add(temp); + } + } + } + String machineSID = getMachineSID(osAccountSID); + return machineSIDs.contains(machineSID); + } + /** * Returns a mapping of user sids to user names. * @@ -1987,7 +2031,7 @@ class ExtractRegistry extends Extract { * @throws TskDataException * @throws OsAccountManager.NotUserSIDException */ - private void createOrUpdateOsAccount(AbstractFile file, String sid, String userName, String homeDir) throws TskCoreException, TskDataException, NotUserSIDException { + private void createOrUpdateOsAccount(AbstractFile file, String sid, String userName, String homeDir, String domainName, OsAccountRealm.RealmScope realmScope) throws TskCoreException, TskDataException, NotUserSIDException { OsAccountManager accountMgr = tskCase.getOsAccountManager(); HostManager hostMrg = tskCase.getHostManager(); Host host = hostMrg.getHostByDataSource((DataSource)dataSource); @@ -1995,13 +2039,14 @@ class ExtractRegistry extends Extract { Optional optional = accountMgr.getWindowsOsAccount(sid, null, null, host); OsAccount osAccount; if (!optional.isPresent()) { - osAccount = accountMgr.newWindowsOsAccount(sid, userName != null && userName.isEmpty() ? null : userName, domainName, host, domainName != null && !domainName.isEmpty()? OsAccountRealm.RealmScope.DOMAIN : OsAccountRealm.RealmScope.UNKNOWN); + osAccount = accountMgr.newWindowsOsAccount(sid, userName != null && userName.isEmpty() ? null : userName, domainName, host, realmScope); accountMgr.newOsAccountInstance(osAccount, (DataSource)dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED); } else { osAccount = optional.get(); - if (userName != null && !userName.isEmpty()) { - OsAccountUpdateResult updateResult= accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, userName, domainName.isEmpty() ? null : domainName, host); - osAccount = updateResult.getUpdatedAccount().orElse(osAccount); + addAccountInstance(accountMgr, osAccount, (DataSource)dataSource); + if (userName != null && !userName.isEmpty()) { + OsAccountUpdateResult updateResult= accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, userName, (domainName == null || domainName.isEmpty()) ? null : domainName, host); + osAccount = updateResult.getUpdatedAccount().orElse(osAccount); } } @@ -2192,7 +2237,7 @@ class ExtractRegistry extends Extract { accountMgr.addExtendedOsAccountAttributes(osAccount, attributes); // update the loginname - accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, loginName, domainName.isEmpty() ? null : domainName, host); + accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, loginName, null, host); // update other standard attributes - fullname, creationdate accountMgr.updateStandardOsAccountAttributes(osAccount, fullName, null, null, creationTime); @@ -2269,4 +2314,17 @@ class ExtractRegistry extends Extract { private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, Integer value, OsAccount osAccount, Host host, AbstractFile file) { return osAccount.new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file); } + + /** + * Adds an account instance for the given data source if one does not already + * exist. + * + * @param accountMgr + * @param osAccount + * @param dataSource + * @throws TskCoreException + */ + private void addAccountInstance(OsAccountManager accountMgr, OsAccount osAccount, DataSource dataSource) throws TskCoreException { + accountMgr.newOsAccountInstance(osAccount, dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED); + } }