19 package org.sleuthkit.datamodel;
21 import com.google.common.base.Strings;
22 import org.apache.commons.lang3.StringUtils;
23 import java.sql.PreparedStatement;
24 import java.sql.ResultSet;
25 import java.sql.SQLException;
26 import java.sql.Statement;
27 import java.sql.Types;
28 import java.util.Collections;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.NavigableSet;
32 import java.util.Objects;
33 import java.util.Optional;
34 import java.util.UUID;
35 import java.util.concurrent.ConcurrentSkipListSet;
36 import java.util.stream.Collectors;
54 private final Object osAcctInstancesCacheLock;
55 private final NavigableSet<OsAccountInstance> osAccountInstanceCache;
65 osAcctInstancesCacheLock =
new Object();
66 osAccountInstanceCache =
new ConcurrentSkipListSet<>();
85 if (Strings.isNullOrEmpty(uniqueAccountId)) {
102 }
catch (SQLException ex) {
108 Optional<OsAccount> osAccount = this.getOsAccountByAddr(uniqueAccountId, realm);
109 if (osAccount.isPresent()) {
110 return osAccount.get();
114 throw new TskCoreException(String.format(
"Error creating OsAccount with uniqueAccountId = %s in realm id = %d", uniqueAccountId, realm.getRealmId()), ex);
149 if (realmScope == null) {
150 throw new TskCoreException(
"RealmScope cannot be null. Use UNKNOWN if scope is not known.");
152 if (referringHost == null) {
153 throw new TskCoreException(
"A referring host is required to create an account.");
157 if (StringUtils.isBlank(sid) && StringUtils.isBlank(loginName)) {
158 throw new TskCoreException(
"Cannot create OS account with both uniqueId and loginName as null.");
161 if (StringUtils.isBlank(sid) && StringUtils.isBlank(realmName)) {
162 throw new TskCoreException(
"Realm name or SID is required to create a Windows account.");
165 if (!StringUtils.isBlank(sid) && !WindowsAccountUtils.isWindowsUserSid(sid)) {
170 Optional<OsAccountRealm> realmOptional;
171 try (CaseDbConnection connection = db.getConnection()) {
175 if (realmOptional.isPresent()) {
176 realm = realmOptional.get();
205 if (StringUtils.isBlank(sid) && StringUtils.isBlank(loginName)) {
206 throw new TskCoreException(
"Cannot create OS account with both uniqueId and loginName as null.");
209 if (!StringUtils.isBlank(sid) && !WindowsAccountUtils.isWindowsUserSid(sid)) {
220 if (!StringUtils.isBlank(sid) && isWindowsSpecialSid(sid)) {
221 String fullName = getWindowsSpecialSidName(sid);
222 if (StringUtils.isNotBlank(fullName)) {
232 }
catch (SQLException ex) {
238 Optional<OsAccount> osAccount;
241 if (!Strings.isNullOrEmpty(sid)) {
242 osAccount = getOsAccountByAddr(sid, realm);
243 if (osAccount.isPresent()) {
244 return osAccount.get();
249 if (!Strings.isNullOrEmpty(loginName)) {
250 osAccount = getOsAccountByLoginName(loginName, realm);
251 if (osAccount.isPresent()) {
252 return osAccount.get();
257 throw new TskCoreException(String.format(
"Error creating OsAccount with sid = %s, loginName = %s, realm = %s, referring host = %s",
258 (sid != null) ? sid :
"Null",
259 (loginName != null) ? loginName :
"Null",
286 if (Objects.isNull(realm)) {
287 throw new TskCoreException(
"Cannot create an OS Account, realm is NULL.");
290 String signature = getOsAccountSignature(uniqueId, loginName);
293 CaseDbConnection connection = trans.getConnection();
298 long parentObjId = 0;
300 int objTypeId = TskData.ObjectType.OS_ACCOUNT.getObjectType();
301 long osAccountObjId = db.addObject(parentObjId, objTypeId, connection);
303 String accountInsertSQL =
"INSERT INTO tsk_os_accounts(os_account_obj_id, login_name, realm_id, addr, signature, status)"
304 +
" VALUES (?, ?, ?, ?, ?, ?)";
306 PreparedStatement preparedStatement = connection.getPreparedStatement(accountInsertSQL, Statement.NO_GENERATED_KEYS);
307 preparedStatement.clearParameters();
309 preparedStatement.setLong(1, osAccountObjId);
311 preparedStatement.setString(2, loginName);
312 preparedStatement.setLong(3, realm.getRealmId());
314 preparedStatement.setString(4, uniqueId);
315 preparedStatement.setString(5, signature);
316 preparedStatement.setInt(6, accountStatus.getId());
318 connection.executeUpdate(preparedStatement);
320 account =
new OsAccount(db, osAccountObjId, realm.getRealmId(), loginName, uniqueId, signature,
321 null, null, null, accountStatus, OsAccount.OsAccountDbStatus.ACTIVE);
323 trans.registerAddedOsAccount(account);
338 private Optional<OsAccount> getOsAccountByAddr(String addr, Host host)
throws TskCoreException {
340 try (CaseDbConnection connection = db.getConnection()) {
341 return getOsAccountByAddr(addr, host, connection);
357 private Optional<OsAccount> getOsAccountByAddr(String uniqueId, Host host, CaseDbConnection connection)
throws TskCoreException {
359 String whereHostClause = (host == null)
361 :
" ( realms.scope_host_id = " + host.getHostId() +
" OR realms.scope_host_id IS NULL) ";
363 String queryString =
"SELECT accounts.os_account_obj_id as os_account_obj_id, accounts.login_name, accounts.full_name, "
364 +
" accounts.realm_id, accounts.addr, accounts.signature, "
365 +
" accounts.type, accounts.status, accounts.admin, accounts.created_date, accounts.db_status, "
366 +
" realms.realm_name as realm_name, realms.realm_addr as realm_addr, realms.realm_signature, realms.scope_host_id, realms.scope_confidence, realms.db_status as realm_db_status "
367 +
" FROM tsk_os_accounts as accounts"
368 +
" LEFT JOIN tsk_os_account_realms as realms"
369 +
" ON accounts.realm_id = realms.id"
370 +
" WHERE " + whereHostClause
372 +
" AND LOWER(accounts.addr) = LOWER('" + uniqueId +
"')";
375 try (Statement s = connection.createStatement();
376 ResultSet rs = connection.executeQuery(s, queryString)) {
379 return Optional.empty();
381 return Optional.of(osAccountFromResultSet(rs));
383 }
catch (SQLException ex) {
384 throw new TskCoreException(String.format(
"Error getting OS account for unique id = %s and host = %s", uniqueId, (host != null ? host.getName() :
"null")), ex);
401 Optional<OsAccount> getOsAccountByAddr(String uniqueId, OsAccountRealm realm)
throws TskCoreException {
403 String queryString =
"SELECT * FROM tsk_os_accounts"
404 +
" WHERE LOWER(addr) = LOWER('" + uniqueId +
"')"
406 +
" AND realm_id = " + realm.getRealmId();
409 try (CaseDbConnection connection = this.db.getConnection();
410 Statement s = connection.createStatement();
411 ResultSet rs = connection.executeQuery(s, queryString)) {
414 return Optional.empty();
416 return Optional.of(osAccountFromResultSet(rs));
418 }
catch (SQLException ex) {
419 throw new TskCoreException(String.format(
"Error getting OS account for realm = %s and uniqueId = %s.", (realm != null) ? realm.getSignature() :
"NULL", uniqueId), ex);
436 Optional<OsAccount> getOsAccountByLoginName(String loginName, OsAccountRealm realm)
throws TskCoreException {
438 String queryString =
"SELECT * FROM tsk_os_accounts"
439 +
" WHERE LOWER(login_name) = LOWER('" + loginName +
"')"
441 +
" AND realm_id = " + realm.getRealmId();
444 try (CaseDbConnection connection = this.db.getConnection();
445 Statement s = connection.createStatement();
446 ResultSet rs = connection.executeQuery(s, queryString)) {
449 return Optional.empty();
451 return Optional.of(osAccountFromResultSet(rs));
453 }
catch (SQLException ex) {
454 throw new TskCoreException(String.format(
"Error getting OS account for realm = %s and loginName = %s.", (realm != null) ? realm.getSignature() :
"NULL", loginName), ex);
471 try (CaseDbConnection connection = this.db.getConnection()) {
488 String queryString =
"SELECT * FROM tsk_os_accounts"
489 +
" WHERE os_account_obj_id = " + osAccountObjId;
492 try (Statement s = connection.createStatement();
493 ResultSet rs = connection.executeQuery(s, queryString)) {
496 throw new TskCoreException(String.format(
"No account found with obj id = %d ", osAccountObjId));
498 return osAccountFromResultSet(rs);
500 }
catch (SQLException ex) {
501 throw new TskCoreException(String.format(
"Error getting account with obj id = %d ", osAccountObjId), ex);
532 if (osAccount == null) {
533 throw new TskCoreException(
"Cannot create account instance with null account.");
535 if (dataSource == null) {
536 throw new TskCoreException(
"Cannot create account instance with null data source.");
547 synchronized (osAcctInstancesCacheLock) {
548 if (osAccountInstanceCache.contains(bogus)) {
550 return osAccountInstanceCache.floor(bogus);
554 try (CaseDbConnection connection = this.db.getConnection()) {
583 synchronized (osAcctInstancesCacheLock) {
584 if (osAccountInstanceCache.contains(bogus)) {
586 return osAccountInstanceCache.floor(bogus);
595 String accountInsertSQL = db.getInsertOrIgnoreSQL(
"INTO tsk_os_account_instances(os_account_obj_id, data_source_obj_id, instance_type)"
596 +
" VALUES (?, ?, ?)");
597 PreparedStatement preparedStatement = connection.getPreparedStatement(accountInsertSQL, Statement.RETURN_GENERATED_KEYS);
598 preparedStatement.clearParameters();
599 preparedStatement.setLong(1, osAccountId);
600 preparedStatement.setLong(2, dataSourceObjId);
601 preparedStatement.setInt(3, instanceType.getId());
602 connection.executeUpdate(preparedStatement);
603 try (ResultSet resultSet = preparedStatement.getGeneratedKeys();) {
604 if (resultSet.next()) {
605 OsAccountInstance accountInstance =
new OsAccountInstance(db, resultSet.getLong(1), osAccountId, dataSourceObjId, instanceType);
606 synchronized (osAcctInstancesCacheLock) {
607 osAccountInstanceCache.add(accountInstance);
624 db.fireTSKEvent(
new TskEvent.OsAcctInstancesAddedTskEvent(Collections.singletonList(accountInstance)));
626 return accountInstance;
628 throw new TskCoreException(String.format(
"Could not get autogen key after row insert for OS account instance. OS account object id = %d, data source object id = %d", osAccountId, dataSourceObjId));
631 }
catch (SQLException ex) {
632 throw new TskCoreException(String.format(
"Error adding OS account instance for OS account object id = %d, data source object id = %d", osAccountId, dataSourceObjId), ex);
649 String queryString =
"SELECT * FROM tsk_os_accounts as accounts "
650 +
" JOIN tsk_os_account_instances as instances "
651 +
" ON instances.os_account_obj_id = accounts.os_account_obj_id "
652 +
" JOIN data_source_info as datasources "
653 +
" ON datasources.obj_id = instances.data_source_obj_id "
654 +
" WHERE datasources.host_id = " + host.getHostId()
658 try (CaseDbConnection connection = this.db.getConnection();
659 Statement s = connection.createStatement();
660 ResultSet rs = connection.executeQuery(s, queryString)) {
662 List<OsAccount> accounts =
new ArrayList<>();
664 accounts.add(osAccountFromResultSet(rs));
667 }
catch (SQLException ex) {
668 throw new TskCoreException(String.format(
"Error getting OS accounts for host id = %d", host.getHostId()), ex);
687 List<OsAccount> destinationAccounts =
getOsAccounts(destRealm, trans.getConnection());
688 List<OsAccount> sourceAccounts =
getOsAccounts(sourceRealm, trans.getConnection());
690 for (
OsAccount sourceAccount : sourceAccounts) {
697 if (sourceAccount.getAddr().isPresent() && sourceAccount.getLoginName().isPresent()) {
698 List<OsAccount> duplicateDestAccounts = destinationAccounts.stream()
699 .filter(p -> p.getAddr().equals(sourceAccount.getAddr())
700 || (p.getLoginName().equals(sourceAccount.getLoginName()) && (!p.getAddr().isPresent())))
701 .collect(Collectors.toList());
702 if (duplicateDestAccounts.size() > 1) {
703 OsAccount combinedDestAccount = duplicateDestAccounts.get(0);
704 duplicateDestAccounts.remove(combinedDestAccount);
705 for (
OsAccount dupeDestAccount : duplicateDestAccounts) {
706 mergeOsAccounts(dupeDestAccount, combinedDestAccount, trans);
712 OsAccount matchingDestAccount = null;
715 if (sourceAccount.getAddr().isPresent()) {
716 List<OsAccount> matchingDestAccounts = destinationAccounts.stream()
717 .filter(p -> p.getAddr().equals(sourceAccount.getAddr()))
718 .collect(Collectors.toList());
719 if (!matchingDestAccounts.isEmpty()) {
720 matchingDestAccount = matchingDestAccounts.get(0);
728 if (matchingDestAccount == null && sourceAccount.getLoginName().isPresent()) {
729 List<OsAccount> matchingDestAccounts = destinationAccounts.stream()
730 .filter(p -> (p.getLoginName().equals(sourceAccount.getLoginName())
731 && ((!sourceAccount.getAddr().isPresent()) || (!p.getAddr().isPresent()))))
732 .collect(Collectors.toList());
733 if (!matchingDestAccounts.isEmpty()) {
734 matchingDestAccount = matchingDestAccounts.get(0);
739 if (matchingDestAccount != null) {
740 mergeOsAccounts(sourceAccount, matchingDestAccount, trans);
742 String query =
"UPDATE tsk_os_accounts SET realm_id = " + destRealm.getRealmId() +
" WHERE os_account_obj_id = " + sourceAccount.getId();
743 try (Statement s = trans.getConnection().createStatement()) {
744 s.executeUpdate(query);
745 }
catch (SQLException ex) {
746 throw new TskCoreException(
"Error executing SQL update: " + query, ex);
748 trans.registerChangedOsAccount(sourceAccount);
767 private void mergeOsAccounts(OsAccount sourceAccount, OsAccount destAccount, CaseDbTransaction trans)
throws TskCoreException {
770 try (Statement s = trans.getConnection().createStatement()) {
773 query = makeOsAccountUpdateQuery(
"tsk_os_account_attributes", sourceAccount, destAccount);
774 s.executeUpdate(query);
778 query =
"DELETE FROM tsk_os_account_instances "
781 +
" sourceAccountInstance.id "
783 +
" tsk_os_account_instances destAccountInstance "
784 +
"INNER JOIN tsk_os_account_instances sourceAccountInstance ON destAccountInstance.data_source_obj_id = sourceAccountInstance.data_source_obj_id "
785 +
"WHERE destAccountInstance.os_account_obj_id = " + destAccount.getId()
786 +
" AND sourceAccountInstance.os_account_obj_id = " + sourceAccount.getId() +
" )";
787 s.executeUpdate(query);
789 query = makeOsAccountUpdateQuery(
"tsk_os_account_instances", sourceAccount, destAccount);
790 s.executeUpdate(query);
791 synchronized (osAcctInstancesCacheLock) {
792 osAccountInstanceCache.clear();
795 query = makeOsAccountUpdateQuery(
"tsk_files", sourceAccount, destAccount);
796 s.executeUpdate(query);
798 query = makeOsAccountUpdateQuery(
"tsk_data_artifacts", sourceAccount, destAccount);
799 s.executeUpdate(query);
802 String mergedSignature = makeMergedOsAccountSignature();
803 query =
"UPDATE tsk_os_accounts SET merged_into = " + destAccount.getId()
804 +
", db_status = " + OsAccount.OsAccountDbStatus.MERGED.getId()
805 +
", signature = '" + mergedSignature +
"' "
806 +
" WHERE os_account_obj_id = " + sourceAccount.getId();
808 s.executeUpdate(query);
809 trans.registerDeletedOsAccount(sourceAccount.getId());
814 mergeOsAccountObjectsAndUpdateDestAccount(sourceAccount, destAccount, trans);
815 }
catch (SQLException ex) {
816 throw new TskCoreException(
"Error executing SQL update: " + query, ex);
825 private String makeMergedOsAccountSignature() {
826 return "MERGED " + UUID.randomUUID().toString();
838 private String makeOsAccountUpdateQuery(String tableName, OsAccount sourceAccount, OsAccount destAccount) {
839 return "UPDATE " + tableName +
" SET os_account_obj_id = " + destAccount.getId() +
" WHERE os_account_obj_id = " + sourceAccount.getId();
853 private OsAccount mergeOsAccountObjectsAndUpdateDestAccount(OsAccount sourceAccount, OsAccount destAccount, CaseDbTransaction trans)
throws TskCoreException {
855 OsAccount mergedDestAccount = destAccount;
857 String destLoginName = null;
858 String destAddr = null;
861 if (!destAccount.getLoginName().isPresent() && sourceAccount.getLoginName().isPresent()) {
865 if (!destAccount.getAddr().isPresent() && sourceAccount.getAddr().isPresent()) {
866 destAddr = sourceAccount.getAddr().get();
870 OsAccountUpdateResult updateStatus = this.updateOsAccountCore(destAccount, destAddr, destLoginName, trans);
872 if (updateStatus.getUpdateStatusCode() == OsAccountUpdateStatus.UPDATED && updateStatus.getUpdatedAccount().isPresent()) {
873 mergedDestAccount = updateStatus.getUpdatedAccount().get();
876 String destFullName = null;
877 Long destCreationTime = null;
878 if (!destAccount.getFullName().isPresent() && sourceAccount.getFullName().isPresent()) {
879 destFullName = sourceAccount.getFullName().get();
882 if (!destAccount.getCreationTime().isPresent() && sourceAccount.getCreationTime().isPresent()) {
883 destCreationTime = sourceAccount.getCreationTime().get();
889 if (updateStatus.getUpdateStatusCode() == OsAccountUpdateStatus.UPDATED && updateStatus.getUpdatedAccount().isPresent()) {
890 mergedDestAccount = updateStatus.getUpdatedAccount().get();
893 return mergedDestAccount;
906 private List<OsAccount>
getOsAccounts(OsAccountRealm realm, CaseDbConnection connection)
throws TskCoreException {
907 String queryString =
"SELECT * FROM tsk_os_accounts"
908 +
" WHERE realm_id = " + realm.getRealmId()
909 +
" AND db_status = " + OsAccount.OsAccountDbStatus.ACTIVE.getId()
910 +
" ORDER BY os_account_obj_id";
912 try (Statement s = connection.createStatement();
913 ResultSet rs = connection.executeQuery(s, queryString)) {
915 List<OsAccount> accounts =
new ArrayList<>();
917 accounts.add(osAccountFromResultSet(rs));
920 }
catch (SQLException ex) {
921 throw new TskCoreException(String.format(
"Error getting OS accounts for realm id = %d", realm.getRealmId()), ex);
933 String queryString =
"SELECT * FROM tsk_os_accounts"
937 try (CaseDbConnection connection = this.db.getConnection();
938 Statement s = connection.createStatement();
939 ResultSet rs = connection.executeQuery(s, queryString)) {
941 List<OsAccount> accounts =
new ArrayList<>();
943 accounts.add(osAccountFromResultSet(rs));
946 }
catch (SQLException ex) {
947 throw new TskCoreException(String.format(
"Error getting OS accounts"), ex);
970 if (referringHost == null) {
971 throw new TskCoreException(
"A referring host is required to get an account.");
975 if (StringUtils.isBlank(sid) && StringUtils.isBlank(loginName)) {
976 throw new TskCoreException(
"Cannot get an OS account with both SID and loginName as null.");
981 if (!realm.isPresent()) {
982 return Optional.empty();
986 if (!Strings.isNullOrEmpty(sid)) {
987 if (!WindowsAccountUtils.isWindowsUserSid(sid)) {
991 Optional<OsAccount> account = this.getOsAccountByAddr(sid, realm.get());
992 if (account.isPresent()) {
998 return this.getOsAccountByLoginName(loginName, realm.get());
1012 synchronized (account) {
1015 try (CaseDbConnection connection = db.getConnection()) {
1018 String attributeInsertSQL =
"INSERT INTO tsk_os_account_attributes(os_account_obj_id, host_id, source_obj_id, attribute_type_id, value_type, value_byte, value_text, value_int32, value_int64, value_double)"
1019 +
" VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
1021 PreparedStatement preparedStatement = connection.getPreparedStatement(attributeInsertSQL, Statement.RETURN_GENERATED_KEYS);
1022 preparedStatement.clearParameters();
1024 preparedStatement.setLong(1, account.getId());
1025 if (accountAttribute.getHostId().isPresent()) {
1026 preparedStatement.setLong(2, accountAttribute.getHostId().get());
1028 preparedStatement.setNull(2, java.sql.Types.NULL);
1030 if (accountAttribute.getSourceObjectId().isPresent()) {
1031 preparedStatement.setLong(3, accountAttribute.getSourceObjectId().get());
1033 preparedStatement.setNull(3, java.sql.Types.NULL);
1036 preparedStatement.setLong(4, accountAttribute.getAttributeType().getTypeID());
1037 preparedStatement.setLong(5, accountAttribute.getAttributeType().getValueType().getType());
1040 preparedStatement.setBytes(6, accountAttribute.getValueBytes());
1042 preparedStatement.setBytes(6, null);
1047 preparedStatement.setString(7, accountAttribute.getValueString());
1049 preparedStatement.setString(7, null);
1052 preparedStatement.setInt(8, accountAttribute.getValueInt());
1054 preparedStatement.setNull(8, java.sql.Types.NULL);
1059 preparedStatement.setLong(9, accountAttribute.getValueLong());
1061 preparedStatement.setNull(9, java.sql.Types.NULL);
1065 preparedStatement.setDouble(10, accountAttribute.getValueDouble());
1067 preparedStatement.setNull(10, java.sql.Types.NULL);
1070 connection.executeUpdate(preparedStatement);
1072 }
catch (SQLException ex) {
1073 throw new TskCoreException(String.format(
"Error adding OS Account attribute for account id = %d", account.getId()), ex);
1078 List<OsAccountAttribute> currentAttribsList = getOsAccountAttributes(account);
1079 account.setAttributesInternal(currentAttribsList);
1081 fireChangeEvent(account);
1093 List<OsAccountAttribute> getOsAccountAttributes(
OsAccount account)
throws TskCoreException {
1095 String queryString =
"SELECT attributes.os_account_obj_id as os_account_obj_id, attributes.host_id as host_id, attributes.source_obj_id as source_obj_id, "
1096 +
" attributes.attribute_type_id as attribute_type_id, attributes.value_type as value_type, attributes.value_byte as value_byte, "
1097 +
" attributes.value_text as value_text, attributes.value_int32 as value_int32, attributes.value_int64 as value_int64, attributes.value_double as value_double, "
1098 +
" hosts.id, hosts.name as host_name, hosts.db_status as host_status "
1099 +
" FROM tsk_os_account_attributes as attributes"
1100 +
" LEFT JOIN tsk_hosts as hosts "
1101 +
" ON attributes.host_id = hosts.id "
1102 +
" WHERE os_account_obj_id = " + account.getId();
1105 try (CaseDbConnection connection = this.db.getConnection();
1106 Statement s = connection.createStatement();
1107 ResultSet rs = connection.executeQuery(s, queryString)) {
1109 List<OsAccountAttribute> attributes =
new ArrayList<>();
1113 long hostId = rs.getLong(
"host_id");
1114 if (!rs.wasNull()) {
1115 host =
new Host(hostId, rs.getString(
"host_name"),
Host.
HostDbStatus.fromID(rs.getInt(
"host_status")));
1118 Content sourceContent = null;
1119 long sourceObjId = rs.getLong(
"source_obj_id");
1120 if (!rs.wasNull()) {
1123 BlackboardAttribute.Type attributeType = db.
getAttributeType(rs.getInt(
"attribute_type_id"));
1124 OsAccountAttribute attribute = account.new OsAccountAttribute(attributeType, rs.getInt(
"value_int32"), rs.getLong(
"value_int64"),
1125 rs.getDouble(
"value_double"), rs.getString(
"value_text"), rs.getBytes(
"value_byte"),
1126 db, account, host, sourceContent);
1128 attributes.add(attribute);
1131 }
catch (SQLException ex) {
1132 throw new TskCoreException(String.format(
"Error getting OS account attributes for account obj id = %d", account.getId()), ex);
1147 List<OsAccountInstance> getOsAccountInstances(OsAccount account)
throws TskCoreException {
1148 String whereClause =
"tsk_os_account_instances.os_account_obj_id = " + account.getId();
1149 return getOsAccountInstances(whereClause);
1163 String instanceIds = instanceIDs.stream().map(
id ->
id.toString()).collect(Collectors.joining(
","));
1164 String whereClause =
"tsk_os_account_instances.id IN (" + instanceIds +
")";
1165 return getOsAccountInstances(whereClause);
1178 private List<OsAccountInstance> getOsAccountInstances(String whereClause)
throws TskCoreException {
1179 List<OsAccountInstance> osAcctInstances =
new ArrayList<>();
1180 String querySQL =
"SELECT * FROM tsk_os_account_instances WHERE " + whereClause;
1182 try (CaseDbConnection connection = db.getConnection();
1183 PreparedStatement preparedStatement = connection.getPreparedStatement(querySQL, Statement.NO_GENERATED_KEYS);
1184 ResultSet results = connection.executeQuery(preparedStatement)) {
1185 while (results.next()) {
1186 long instanceId = results.getLong(
"id");
1187 long osAccountObjID = results.getLong(
"os_account_obj_id");
1188 long dataSourceObjId = results.getLong(
"data_source_obj_id");
1189 int instanceType = results.getInt(
"instance_type");
1192 }
catch (SQLException ex) {
1193 throw new TskCoreException(
"Failed to get OsAccountInstances (SQL = " + querySQL +
")", ex);
1197 return osAcctInstances;
1225 return updateStatus;
1227 if (trans != null) {
1252 OsAccountUpdateStatus updateStatusCode = OsAccountUpdateStatus.NO_CHANGE;
1255 CaseDbConnection connection = trans.getConnection();
1257 if (!StringUtils.isBlank(fullName)) {
1258 updateAccountColumn(osAccount.getId(),
"full_name", fullName, connection);
1259 updateStatusCode = OsAccountUpdateStatus.UPDATED;
1262 if (Objects.nonNull(accountType)) {
1263 updateAccountColumn(osAccount.getId(),
"type", accountType, connection);
1264 updateStatusCode = OsAccountUpdateStatus.UPDATED;
1267 if (Objects.nonNull(accountStatus)) {
1268 updateAccountColumn(osAccount.getId(),
"status", accountStatus, connection);
1269 updateStatusCode = OsAccountUpdateStatus.UPDATED;
1272 if (Objects.nonNull(creationTime)) {
1273 updateAccountColumn(osAccount.getId(),
"created_date", creationTime, connection);
1274 updateStatusCode = OsAccountUpdateStatus.UPDATED;
1278 if (updateStatusCode == OsAccountUpdateStatus.NO_CHANGE) {
1279 return new OsAccountUpdateResult(updateStatusCode, null);
1286 trans.registerChangedOsAccount(updatedAccount);
1288 return new OsAccountUpdateResult(updateStatusCode, updatedAccount);
1290 }
catch (SQLException ex) {
1291 throw new TskCoreException(String.format(
"Error updating account with addr = %s, account id = %d", osAccount.getAddr().orElse(
"Unknown"), osAccount.getId()), ex);
1308 private <T>
void updateAccountColumn(
long accountObjId, String colName, T colValue, CaseDbConnection connection)
throws SQLException, TskCoreException {
1310 String updateSQL =
"UPDATE tsk_os_accounts "
1311 +
" SET " + colName +
" = ? "
1312 +
" WHERE os_account_obj_id = ?";
1316 PreparedStatement preparedStatement = connection.getPreparedStatement(updateSQL, Statement.NO_GENERATED_KEYS);
1317 preparedStatement.clearParameters();
1319 if (Objects.isNull(colValue)) {
1320 preparedStatement.setNull(1, Types.NULL);
1322 if (colValue instanceof String) {
1323 preparedStatement.setString(1, (String) colValue);
1324 }
else if (colValue instanceof Long) {
1325 preparedStatement.setLong(1, (Long) colValue);
1326 }
else if (colValue instanceof Integer) {
1327 preparedStatement.setInt(1, (Integer) colValue);
1329 throw new TskCoreException(String.format(
"Unhandled column data type received while updating the account (%d) ", accountObjId));
1333 preparedStatement.setLong(2, accountObjId);
1335 connection.executeUpdate(preparedStatement);
1351 private void updateAccountSignature(
long accountObjId, String signature, CaseDbConnection connection)
throws SQLException {
1353 String updateSQL =
"UPDATE tsk_os_accounts SET "
1355 +
" CASE WHEN db_status = " + OsAccount.OsAccountDbStatus.ACTIVE.getId() +
" THEN ? ELSE signature END "
1356 +
" WHERE os_account_obj_id = ?";
1358 PreparedStatement preparedStatement = connection.getPreparedStatement(updateSQL, Statement.NO_GENERATED_KEYS);
1359 preparedStatement.clearParameters();
1361 preparedStatement.setString(1, signature);
1362 preparedStatement.setLong(2, accountObjId);
1364 connection.executeUpdate(preparedStatement);
1394 return updateStatus;
1396 if (trans != null) {
1424 if (!StringUtils.isBlank(accountSid) || !StringUtils.isBlank(realmName)) {
1425 db.
getOsAccountRealmManager().getAndUpdateWindowsRealm(accountSid, realmName, referringHost, trans.getConnection());
1429 OsAccountUpdateResult updateStatus = this.updateOsAccountCore(osAccount, accountSid, loginName, trans);
1431 return updateStatus;
1456 private OsAccountUpdateResult updateOsAccountCore(OsAccount osAccount, String address, String loginName, CaseDbTransaction trans)
throws TskCoreException {
1458 OsAccountUpdateStatus updateStatusCode = OsAccountUpdateStatus.NO_CHANGE;
1459 OsAccount updatedAccount;
1462 CaseDbConnection connection = trans.getConnection();
1465 if (!StringUtils.isBlank(address) && !StringUtils.isBlank(osAccount.getAddr().orElse(null)) && !address.equalsIgnoreCase(osAccount.getAddr().orElse(
""))) {
1466 throw new TskCoreException(String.format(
"Account (%d) already has an address (%s), address cannot be updated.", osAccount.getId(), osAccount.getAddr().orElse(
"NULL")));
1469 if (StringUtils.isBlank(osAccount.getAddr().orElse(null)) && !StringUtils.isBlank(address)) {
1470 updateAccountColumn(osAccount.getId(),
"addr", address, connection);
1471 updateStatusCode = OsAccountUpdateStatus.UPDATED;
1474 if (StringUtils.isBlank(osAccount.getLoginName().orElse(null)) && !StringUtils.isBlank(loginName)) {
1475 updateAccountColumn(osAccount.getId(),
"login_name", loginName, connection);
1476 updateStatusCode = OsAccountUpdateStatus.UPDATED;
1480 if (updateStatusCode == OsAccountUpdateStatus.NO_CHANGE) {
1481 return new OsAccountUpdateResult(updateStatusCode, osAccount);
1486 String newAddress = currAccount.
getAddr().orElse(null);
1487 String newLoginName = currAccount.getLoginName().orElse(null);
1489 String newSignature = getOsAccountSignature(newAddress, newLoginName);
1490 updateAccountSignature(osAccount.getId(), newSignature, connection);
1496 trans.registerChangedOsAccount(updatedAccount);
1498 return new OsAccountUpdateResult(updateStatusCode, updatedAccount);
1500 }
catch (SQLException ex) {
1501 throw new TskCoreException(String.format(
"Error updating account with unique id = %s, account id = %d", osAccount.getAddr().orElse(
"Unknown"), osAccount.getId()), ex);
1515 List<Host> hostList =
new ArrayList<>();
1517 String query =
"SELECT tsk_hosts.id AS hostId, name, db_status FROM tsk_hosts "
1518 +
" JOIN data_source_info ON tsk_hosts.id = data_source_info.host_id"
1519 +
" JOIN tsk_os_account_instances ON data_source_info.obj_id = tsk_os_account_instances.data_source_obj_id"
1520 +
" WHERE os_account_obj_id = " + account.getId();
1523 try (CaseDbConnection connection = db.getConnection();
1524 Statement s = connection.createStatement();
1525 ResultSet rs = connection.executeQuery(s, query)) {
1528 hostList.add(
new Host(rs.getLong(
"hostId"), rs.getString(
"name"),
Host.
HostDbStatus.fromID(rs.getInt(
"db_status"))));
1531 }
catch (SQLException ex) {
1532 throw new TskCoreException(String.format(
"Failed to get host list for os account %d", account.getId()), ex);
1550 private OsAccount osAccountFromResultSet(ResultSet rs)
throws SQLException {
1553 int typeId = rs.getInt(
"type");
1554 if (!rs.wasNull()) {
1558 Long creationTime = rs.getLong(
"created_date");
1560 creationTime = null;
1563 return new OsAccount(db, rs.getLong(
"os_account_obj_id"), rs.getLong(
"realm_id"), rs.getString(
"login_name"), rs.getString(
"addr"),
1564 rs.getString(
"signature"), rs.getString(
"full_name"), creationTime, accountType, OsAccount.OsAccountStatus.
fromID(rs.getInt(
"status")),
1565 OsAccount.OsAccountDbStatus.
fromID(rs.getInt(
"db_status")));
1575 private void fireChangeEvent(OsAccount account) {
1576 db.fireTSKEvent(
new OsAccountsUpdatedTskEvent(Collections.singletonList(account)));
1593 static String getOsAccountSignature(String uniqueId, String loginName)
throws TskCoreException {
1596 if (Strings.isNullOrEmpty(uniqueId) ==
false) {
1597 signature = uniqueId;
1598 }
else if (Strings.isNullOrEmpty(loginName) ==
false) {
1599 signature = loginName;
1601 throw new TskCoreException(
"OS Account must have either a uniqueID or a login name.");
1612 private static final long serialVersionUID = 1L;
1618 super(
"No error message available.");
1661 this.updateStatus = updateStatus;
1662 this.updatedAccount = updatedAccount;
1666 return updateStatus;
1670 return Optional.ofNullable(updatedAccount);
NotUserSIDException(String msg, Exception ex)
List< OsAccount > getOsAccounts()
Optional< String > getAddr()
OsAccountRealm newWindowsRealm(String accountSid, String realmName, Host referringHost, OsAccountRealm.RealmScope realmScope)
CaseDbTransaction beginTransaction()
List< Host > getHosts(OsAccount account)
OsAccount getOsAccountByObjectId(long osAccountObjId)
static OsAccountType fromID(int typeId)
Optional< OsAccount > getWindowsOsAccount(String sid, String loginName, String realmName, Host referringHost)
OsAccountUpdateStatus getUpdateStatusCode()
OsAccountUpdateResult updateStandardOsAccountAttributes(OsAccount osAccount, String fullName, OsAccountType accountType, OsAccountStatus accountStatus, Long creationTime)
Content getContentById(long id)
OsAccount newWindowsOsAccount(String sid, String loginName, OsAccountRealm realm)
NotUserSIDException(String msg)
static OsAccountInstanceType fromID(int typeId)
List< OsAccount > getOsAccounts(Host host)
OsAccountRealmManager getOsAccountRealmManager()
void releaseSingleUserCaseReadLock()
Optional< OsAccountRealm > getWindowsRealm(String accountSid, String realmName, Host referringHost)
List< OsAccountInstance > getOsAccountInstances(List< Long > instanceIDs)
BlackboardAttribute.Type getAttributeType(String attrTypeName)
void acquireSingleUserCaseWriteLock()
OsAccountInstance newOsAccountInstance(OsAccount osAccount, DataSource dataSource, OsAccountInstance.OsAccountInstanceType instanceType)
void releaseSingleUserCaseWriteLock()
UPDATED
no change was made to account.
Optional< String > getLoginName()
Optional< Host > getScopeHost()
void acquireSingleUserCaseReadLock()
void addExtendedOsAccountAttributes(OsAccount account, List< OsAccountAttribute > accountAttributes)
Optional< OsAccount > getUpdatedAccount()
OsAccountUpdateResult updateCoreWindowsOsAccountAttributes(OsAccount osAccount, String accountSid, String loginName, String realmName, Host referringHost)
OsAccount newWindowsOsAccount(String sid, String loginName, String realmName, Host referringHost, OsAccountRealm.RealmScope realmScope)
List< String > getRealmNames()