From fe139e03b23e1a22956bfb84372a5c669f0a07b5 Mon Sep 17 00:00:00 2001 From: apriestman <apriestman@basistech.com> Date: Tue, 19 Sep 2023 13:14:52 -0400 Subject: [PATCH] Support simple OS account creation for Linux --- .../sleuthkit/datamodel/OsAccountManager.java | 125 ++++++++++++++++++ .../datamodel/OsAccountRealmManager.java | 48 +++++++ 2 files changed, 173 insertions(+) diff --git a/bindings/java/src/org/sleuthkit/datamodel/OsAccountManager.java b/bindings/java/src/org/sleuthkit/datamodel/OsAccountManager.java index 19d10064b..89f3789fa 100755 --- a/bindings/java/src/org/sleuthkit/datamodel/OsAccountManager.java +++ b/bindings/java/src/org/sleuthkit/datamodel/OsAccountManager.java @@ -19,6 +19,7 @@ package org.sleuthkit.datamodel; import com.google.common.base.Strings; +import com.google.common.annotations.Beta; import org.apache.commons.lang3.StringUtils; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -331,6 +332,84 @@ public OsAccount newWindowsOsAccount(String sid, String loginName, OsAccountReal } } } + + /** + * Creates a local OS account with Linux-specific data. If an account already + * exists with the given id or realm/login, then the existing OS account is + * returned. + * + * @param uid Account uid, can be null if loginName is supplied. + * @param loginName Login name, can be null if uid is supplied. + * @param referringHost The associated host. + * + * @return OsAccount. + * + * @throws TskCoreException If there is an error in + * creating the OSAccount. + * + */ + @Beta + public OsAccount newLocalLinuxOsAccount(String uid, String loginName, Host referringHost) throws TskCoreException { + + if (referringHost == null) { + throw new TskCoreException("A referring host is required to create a local OS account."); + } + + // Ensure at least one of the two is supplied - a non-null unique id or a login name + if (StringUtils.isBlank(uid) && StringUtils.isBlank(loginName)) { + throw new TskCoreException("Cannot create OS account with both uniqueId and loginName as null."); + } + + OsAccountRealm localRealm = db.getOsAccountRealmManager().newLocalLinuxRealm(referringHost); + + CaseDbTransaction trans = db.beginTransaction(); + try { + + // try to create account + try { + OsAccount account = newOsAccount(uid, loginName, localRealm, OsAccount.OsAccountStatus.UNKNOWN, trans); + trans.commit(); + trans = null; + return account; + } catch (SQLException ex) { + // Rollback the transaction before proceeding + trans.rollback(); + trans = null; + + // Create may fail if an OsAccount already exists. + Optional<OsAccount> osAccount; + + // First search for account by uniqueId + if (!Strings.isNullOrEmpty(uid)) { + osAccount = getOsAccountByAddr(uid, localRealm); + if (osAccount.isPresent()) { + return osAccount.get(); + } + } + + // search by loginName + if (!Strings.isNullOrEmpty(loginName)) { + osAccount = getOsAccountByLoginName(loginName, localRealm); + if (osAccount.isPresent()) { + return osAccount.get(); + } + } + + // create failed for some other reason, throw an exception + throw new TskCoreException(String.format("Error creating OsAccount with uid = %s, loginName = %s, realm = %s, referring host = %s", + (uid != null) ? uid : "Null", + (loginName != null) ? loginName : "Null", + (!localRealm.getRealmNames().isEmpty()) ? localRealm.getRealmNames().get(0) : "Null", + localRealm.getScopeHost().isPresent() ? localRealm.getScopeHost().get().getName() : "Null"), ex); + + } + } finally { + if (trans != null) { + trans.rollback(); + } + } + } + /** * Creates a OS account with the given uid, name, and realm. @@ -1212,6 +1291,52 @@ public Optional<OsAccount> getWindowsOsAccount(String sid, String loginName, Str } } + /** + * Gets an OS account using Linux-specific data. + * + * @param uid Account UID, maybe null if loginName is supplied. + * @param loginName Login name, maybe null if sid is supplied. + * @param referringHost Host referring the account. + * + * @return Optional with OsAccount, Optional.empty if no matching OsAccount + * is found. + * + * @throws TskCoreException If there is an error getting the account. + */ + @Beta + public Optional<OsAccount> getLocalLinuxOsAccount(String uid, String loginName, Host referringHost) throws TskCoreException { + + if (referringHost == null) { + throw new TskCoreException("A referring host is required to get an account."); + } + + // ensure at least one of the two is supplied - a non-null uid or a login name + if (StringUtils.isBlank(uid) && StringUtils.isBlank(loginName)) { + throw new TskCoreException("Cannot get an OS account with both UID and loginName as null."); + } + + // First get the local realm + Optional<OsAccountRealm> realm = db.getOsAccountRealmManager().getLocalLinuxRealm(referringHost); + if (!realm.isPresent()) { + return Optional.empty(); + } + + // Search by UID + if (!Strings.isNullOrEmpty(uid)) { + Optional<OsAccount> account = this.getOsAccountByAddr(uid, realm.get()); + if (account.isPresent()) { + return account; + } + } + + // Search by login name + if (!Strings.isNullOrEmpty(loginName)) { + return this.getOsAccountByLoginName(loginName, realm.get()); + } else { + return Optional.empty(); + } + } + /** * Adds a rows to the tsk_os_account_attributes table for the given set of * attribute. diff --git a/bindings/java/src/org/sleuthkit/datamodel/OsAccountRealmManager.java b/bindings/java/src/org/sleuthkit/datamodel/OsAccountRealmManager.java index 959eb1cc8..2b75c410a 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/OsAccountRealmManager.java +++ b/bindings/java/src/org/sleuthkit/datamodel/OsAccountRealmManager.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.datamodel; +import com.google.common.annotations.Beta; import com.google.common.base.Strings; import org.apache.commons.lang3.StringUtils; import java.sql.PreparedStatement; @@ -43,6 +44,7 @@ public final class OsAccountRealmManager { private static final Logger LOGGER = Logger.getLogger(OsAccountRealmManager.class.getName()); + private static final String LOCAL_REALM_NAME = "local"; private final SleuthkitCase db; @@ -148,6 +150,52 @@ public OsAccountRealm newWindowsRealm(String accountSid, String realmName, Host return newRealm(resolvedRealmName, realmAddr, signature, scopeHost, scopeConfidence); } + /** + * Create local realm to use for Linux accounts. + * + * @param referringHost Host where realm reference is found. + * + * @return OsAccountRealm. + * + * @throws TskCoreException If there is an error + * creating the realm. + */ + @Beta + public OsAccountRealm newLocalLinuxRealm(Host referringHost) throws TskCoreException { + + if (referringHost == null) { + throw new TskCoreException("A referring host is required to create a realm."); + } + + String realmName = LOCAL_REALM_NAME; + OsAccountRealm.ScopeConfidence scopeConfidence = OsAccountRealm.ScopeConfidence.KNOWN; + String signature = makeRealmSignature("", realmName, referringHost); + + // create a realm + return newRealm(realmName, "", signature, referringHost, scopeConfidence); + } + + /** + * Get local realm to use for Linux accounts. + * + * @param referringHost Host where realm reference is found. + * + * @return OsAccountRealm. + * + * @throws TskCoreException If there is an error + * creating the realm. + */ + @Beta + public Optional<OsAccountRealm> getLocalLinuxRealm(Host referringHost) throws TskCoreException { + if (referringHost == null) { + throw new TskCoreException("A referring host is required get a realm."); + } + + try (CaseDbConnection connection = this.db.getConnection()) { + return getRealmByName(LOCAL_REALM_NAME, referringHost, connection); + } + } + /** * Get a windows realm by the account SID, or the domain name. The input SID * is an user/group account SID. The domain SID is extracted from this -- GitLab