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()