Sleuth Kit Java Bindings (JNI)  4.10.2
Java bindings for using The Sleuth Kit
OsAccountManager.java
Go to the documentation of this file.
1 /*
2  * Sleuth Kit Data Model
3  *
4  * Copyright 2020-2021 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.datamodel;
20 
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;
44 
49 public final class OsAccountManager {
50 
51  private final SleuthkitCase db;
52  private final Object osAcctInstancesCacheLock;
53  private final NavigableSet<OsAccountInstance> osAccountInstanceCache;
54 
62  db = skCase;
63  osAcctInstancesCacheLock = new Object();
64  osAccountInstanceCache = new ConcurrentSkipListSet<>();
65  }
66 
80  OsAccount newOsAccount(String uniqueAccountId, OsAccountRealm realm) throws TskCoreException {
81 
82  // ensure unique id is provided
83  if (Strings.isNullOrEmpty(uniqueAccountId)) {
84  throw new TskCoreException("Cannot create OS account with null uniqueId.");
85  }
86 
87  if (realm == null) {
88  throw new TskCoreException("Cannot create OS account without a realm.");
89  }
90 
92  try {
93 
94  // try to create account
95  try {
96  OsAccount account = newOsAccount(uniqueAccountId, null, realm, OsAccount.OsAccountStatus.UNKNOWN, trans);
97  trans.commit();
98  trans = null;
99  return account;
100  } catch (SQLException ex) {
101  // Close the transaction before moving on
102  trans.rollback();
103  trans = null;
104 
105  // Create may fail if an OsAccount already exists.
106  Optional<OsAccount> osAccount = this.getOsAccountByAddr(uniqueAccountId, realm);
107  if (osAccount.isPresent()) {
108  return osAccount.get();
109  }
110 
111  // create failed for some other reason, throw an exception
112  throw new TskCoreException(String.format("Error creating OsAccount with uniqueAccountId = %s in realm id = %d", uniqueAccountId, realm.getRealmId()), ex);
113  }
114  } finally {
115  if (trans != null) {
116  trans.rollback();
117  }
118  }
119  }
120 
145  public OsAccount newWindowsOsAccount(String sid, String loginName, String realmName, Host referringHost, OsAccountRealm.RealmScope realmScope) throws TskCoreException, NotUserSIDException {
146 
147  if (realmScope == null) {
148  throw new TskCoreException("RealmScope cannot be null. Use UNKNOWN if scope is not known.");
149  }
150  if (referringHost == null) {
151  throw new TskCoreException("A referring host is required to create an account.");
152  }
153 
154  // ensure at least one of the two is supplied - unique id or a login name
155  if (StringUtils.isBlank(sid) && StringUtils.isBlank(loginName)) {
156  throw new TskCoreException("Cannot create OS account with both uniqueId and loginName as null.");
157  }
158  // Realm name is required if the sid is null.
159  if (StringUtils.isBlank(sid) && StringUtils.isBlank(realmName)) {
160  throw new TskCoreException("Realm name or SID is required to create a Windows account.");
161  }
162 
163  if (!StringUtils.isBlank(sid) && !WindowsAccountUtils.isWindowsUserSid(sid)) {
164  throw new OsAccountManager.NotUserSIDException(String.format("SID = %s is not a user SID.", sid));
165  }
166 
167  // get the realm for the account, and update it if it is missing addr or name.
168  Optional<OsAccountRealm> realmOptional;
169  try (CaseDbConnection connection = db.getConnection()) {
170  realmOptional = db.getOsAccountRealmManager().getAndUpdateWindowsRealm(sid, realmName, referringHost, connection);
171  }
172  OsAccountRealm realm;
173  if (realmOptional.isPresent()) {
174  realm = realmOptional.get();
175  } else {
176  // realm was not found, create it.
177  realm = db.getOsAccountRealmManager().newWindowsRealm(sid, realmName, referringHost, realmScope);
178  }
179 
180  return newWindowsOsAccount(sid, loginName, realm);
181  }
182 
200  public OsAccount newWindowsOsAccount(String sid, String loginName, OsAccountRealm realm) throws TskCoreException, NotUserSIDException {
201 
202  // ensure at least one of the two is supplied - unique id or a login name
203  if (StringUtils.isBlank(sid) && StringUtils.isBlank(loginName)) {
204  throw new TskCoreException("Cannot create OS account with both uniqueId and loginName as null.");
205  }
206 
207  if (!StringUtils.isBlank(sid) && !WindowsAccountUtils.isWindowsUserSid(sid)) {
208  throw new OsAccountManager.NotUserSIDException(String.format("SID = %s is not a user SID.", sid));
209  }
210 
211  CaseDbTransaction trans = db.beginTransaction();
212  try {
213  // try to create account
214  try {
215  OsAccount account = newOsAccount(sid, loginName, realm, OsAccount.OsAccountStatus.UNKNOWN, trans);
216  trans.commit();
217  trans = null;
218  return account;
219  } catch (SQLException ex) {
220  // Rollback the transaction before proceeding
221  trans.rollback();
222  trans = null;
223 
224  // Create may fail if an OsAccount already exists.
225  Optional<OsAccount> osAccount;
226 
227  // First search for account by uniqueId
228  if (!Strings.isNullOrEmpty(sid)) {
229  osAccount = getOsAccountByAddr(sid, realm);
230  if (osAccount.isPresent()) {
231  return osAccount.get();
232  }
233  }
234 
235  // search by loginName
236  if (!Strings.isNullOrEmpty(loginName)) {
237  osAccount = getOsAccountByLoginName(loginName, realm);
238  if (osAccount.isPresent()) {
239  return osAccount.get();
240  }
241  }
242 
243  // create failed for some other reason, throw an exception
244  throw new TskCoreException(String.format("Error creating OsAccount with sid = %s, loginName = %s, realm = %s, referring host = %s",
245  (sid != null) ? sid : "Null",
246  (loginName != null) ? loginName : "Null",
247  (!realm.getRealmNames().isEmpty()) ? realm.getRealmNames().get(0) : "Null",
248  realm.getScopeHost().isPresent() ? realm.getScopeHost().get().getName() : "Null"), ex);
249 
250  }
251  } finally {
252  if (trans != null) {
253  trans.rollback();
254  }
255  }
256  }
257 
271  private OsAccount newOsAccount(String uniqueId, String loginName, OsAccountRealm realm, OsAccount.OsAccountStatus accountStatus, CaseDbTransaction trans) throws TskCoreException, SQLException {
272 
273  if (Objects.isNull(realm)) {
274  throw new TskCoreException("Cannot create an OS Account, realm is NULL.");
275  }
276 
277  String signature = getOsAccountSignature(uniqueId, loginName);
278  OsAccount account;
279 
280  CaseDbConnection connection = trans.getConnection();
281 
282  // first create a tsk_object for the OsAccount.
283  // RAMAN TODO: need to get the correct parent obj id.
284  // Create an Object Directory parent and used its id.
285  long parentObjId = 0;
286 
287  int objTypeId = TskData.ObjectType.OS_ACCOUNT.getObjectType();
288  long osAccountObjId = db.addObject(parentObjId, objTypeId, connection);
289 
290  String accountInsertSQL = "INSERT INTO tsk_os_accounts(os_account_obj_id, login_name, realm_id, addr, signature, status)"
291  + " VALUES (?, ?, ?, ?, ?, ?)"; // NON-NLS
292 
293  PreparedStatement preparedStatement = connection.getPreparedStatement(accountInsertSQL, Statement.NO_GENERATED_KEYS);
294  preparedStatement.clearParameters();
295 
296  preparedStatement.setLong(1, osAccountObjId);
297 
298  preparedStatement.setString(2, loginName);
299  preparedStatement.setLong(3, realm.getRealmId());
300 
301  preparedStatement.setString(4, uniqueId);
302  preparedStatement.setString(5, signature);
303  preparedStatement.setInt(6, accountStatus.getId());
304 
305  connection.executeUpdate(preparedStatement);
306 
307  account = new OsAccount(db, osAccountObjId, realm.getRealmId(), loginName, uniqueId, signature,
308  null, null, null, accountStatus, OsAccount.OsAccountDbStatus.ACTIVE);
309 
310  trans.registerAddedOsAccount(account);
311  return account;
312  }
313 
325  private Optional<OsAccount> getOsAccountByAddr(String addr, Host host) throws TskCoreException {
326 
327  try (CaseDbConnection connection = db.getConnection()) {
328  return getOsAccountByAddr(addr, host, connection);
329  }
330  }
331 
344  private Optional<OsAccount> getOsAccountByAddr(String uniqueId, Host host, CaseDbConnection connection) throws TskCoreException {
345 
346  String whereHostClause = (host == null)
347  ? " 1 = 1 "
348  : " ( realms.scope_host_id = " + host.getHostId() + " OR realms.scope_host_id IS NULL) ";
349 
350  String queryString = "SELECT accounts.os_account_obj_id as os_account_obj_id, accounts.login_name, accounts.full_name, "
351  + " accounts.realm_id, accounts.addr, accounts.signature, "
352  + " accounts.type, accounts.status, accounts.admin, accounts.created_date, accounts.db_status, "
353  + " 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 "
354  + " FROM tsk_os_accounts as accounts"
355  + " LEFT JOIN tsk_os_account_realms as realms"
356  + " ON accounts.realm_id = realms.id"
357  + " WHERE " + whereHostClause
358  + " AND accounts.db_status = " + OsAccount.OsAccountDbStatus.ACTIVE.getId()
359  + " AND LOWER(accounts.addr) = LOWER('" + uniqueId + "')";
360 
362  try (Statement s = connection.createStatement();
363  ResultSet rs = connection.executeQuery(s, queryString)) {
364 
365  if (!rs.next()) {
366  return Optional.empty(); // no match found
367  } else {
368  return Optional.of(osAccountFromResultSet(rs));
369  }
370  } catch (SQLException ex) {
371  throw new TskCoreException(String.format("Error getting OS account for unique id = %s and host = %s", uniqueId, (host != null ? host.getName() : "null")), ex);
372  } finally {
374  }
375  }
376 
388  Optional<OsAccount> getOsAccountByAddr(String uniqueId, OsAccountRealm realm) throws TskCoreException {
389 
390  String queryString = "SELECT * FROM tsk_os_accounts"
391  + " WHERE LOWER(addr) = LOWER('" + uniqueId + "')"
392  + " AND db_status = " + OsAccount.OsAccountDbStatus.ACTIVE.getId()
393  + " AND realm_id = " + realm.getRealmId();
394 
396  try (CaseDbConnection connection = this.db.getConnection();
397  Statement s = connection.createStatement();
398  ResultSet rs = connection.executeQuery(s, queryString)) {
399 
400  if (!rs.next()) {
401  return Optional.empty(); // no match found
402  } else {
403  return Optional.of(osAccountFromResultSet(rs));
404  }
405  } catch (SQLException ex) {
406  throw new TskCoreException(String.format("Error getting OS account for realm = %s and uniqueId = %s.", (realm != null) ? realm.getSignature() : "NULL", uniqueId), ex);
407  } finally {
409  }
410  }
411 
423  Optional<OsAccount> getOsAccountByLoginName(String loginName, OsAccountRealm realm) throws TskCoreException {
424 
425  String queryString = "SELECT * FROM tsk_os_accounts"
426  + " WHERE LOWER(login_name) = LOWER('" + loginName + "')"
427  + " AND db_status = " + OsAccount.OsAccountDbStatus.ACTIVE.getId()
428  + " AND realm_id = " + realm.getRealmId();
429 
431  try (CaseDbConnection connection = this.db.getConnection();
432  Statement s = connection.createStatement();
433  ResultSet rs = connection.executeQuery(s, queryString)) {
434 
435  if (!rs.next()) {
436  return Optional.empty(); // no match found
437  } else {
438  return Optional.of(osAccountFromResultSet(rs));
439  }
440  } catch (SQLException ex) {
441  throw new TskCoreException(String.format("Error getting OS account for realm = %s and loginName = %s.", (realm != null) ? realm.getSignature() : "NULL", loginName), ex);
442  } finally {
444  }
445  }
446 
456  public OsAccount getOsAccountByObjectId(long osAccountObjId) throws TskCoreException {
457 
458  try (CaseDbConnection connection = this.db.getConnection()) {
459  return getOsAccountByObjectId(osAccountObjId, connection);
460  }
461  }
462 
473  OsAccount getOsAccountByObjectId(long osAccountObjId, CaseDbConnection connection) throws TskCoreException {
474 
475  String queryString = "SELECT * FROM tsk_os_accounts"
476  + " WHERE os_account_obj_id = " + osAccountObjId;
477 
479  try (Statement s = connection.createStatement();
480  ResultSet rs = connection.executeQuery(s, queryString)) {
481 
482  if (!rs.next()) {
483  throw new TskCoreException(String.format("No account found with obj id = %d ", osAccountObjId));
484  } else {
485  return osAccountFromResultSet(rs);
486  }
487  } catch (SQLException ex) {
488  throw new TskCoreException(String.format("Error getting account with obj id = %d ", osAccountObjId), ex);
489  } finally {
491  }
492  }
493 
516  public void newOsAccountInstance(OsAccount osAccount, DataSource dataSource, OsAccountInstance.OsAccountInstanceType instanceType) throws TskCoreException {
517  if (osAccount == null) {
518  throw new TskCoreException("Cannot create account instance with null account.");
519  }
520  if (dataSource == null) {
521  throw new TskCoreException("Cannot create account instance with null data source.");
522  }
523 
524  /*
525  * Check the cache of OS account instances for an existing instance for
526  * this OS account and data source. Note that the account instance
527  * created here has a bogus instance ID. This is possible since the
528  * instance ID is not considered in the equals() and hashCode() methods
529  * of this class.
530  */
531  synchronized (osAcctInstancesCacheLock) {
532  if (osAccountInstanceCache.contains(new OsAccountInstance(db, 0, osAccount.getId(), dataSource.getId(), instanceType))) {
533  return;
534  }
535  }
536 
537  try (CaseDbConnection connection = this.db.getConnection()) {
538  newOsAccountInstance(osAccount.getId(), dataSource.getId(), instanceType, connection);
539  }
540  }
541 
555  void newOsAccountInstance(long osAccountId, long dataSourceObjId, OsAccountInstance.OsAccountInstanceType instanceType, CaseDbConnection connection) throws TskCoreException {
556  /*
557  * Check the cache of OS account instances for an existing instance for
558  * this OS account and data source. Note that the account instance
559  * created here has a bogus instance ID. This is possible since the
560  * instance ID is not considered in the equals() and hashCode() methods
561  * of this class.
562  */
563  synchronized (osAcctInstancesCacheLock) {
564  if (osAccountInstanceCache.contains(new OsAccountInstance(db, 0, osAccountId, dataSourceObjId, instanceType))) {
565  return;
566  }
567  }
568 
569  /*
570  * Create the OS account instance.
571  */
573  try {
574  String accountInsertSQL = db.getInsertOrIgnoreSQL("INTO tsk_os_account_instances(os_account_obj_id, data_source_obj_id, instance_type)"
575  + " VALUES (?, ?, ?)"); // NON-NLS
576  PreparedStatement preparedStatement = connection.getPreparedStatement(accountInsertSQL, Statement.RETURN_GENERATED_KEYS);
577  preparedStatement.clearParameters();
578  preparedStatement.setLong(1, osAccountId);
579  preparedStatement.setLong(2, dataSourceObjId);
580  preparedStatement.setInt(3, instanceType.getId());
581  connection.executeUpdate(preparedStatement);
582  try (ResultSet resultSet = preparedStatement.getGeneratedKeys();) {
583  if (resultSet.next()) {
584  OsAccountInstance accountInstance = new OsAccountInstance(db, resultSet.getLong(1), osAccountId, dataSourceObjId, instanceType);
585  synchronized (osAcctInstancesCacheLock) {
586  osAccountInstanceCache.add(accountInstance);
587  }
588  /*
589  * There is a potential issue here. The cache of OS account
590  * instances is an optimization and was not intended to be
591  * used as an authoritative indicator of whether or not a
592  * particular OS account instance was already added to the
593  * case. In fact, the entire cache is flushed during merge
594  * operations. But regardless, there is a check-then-act
595  * race condition for multi-user cases, with or without the
596  * cache. And although the case database schema and the SQL
597  * returned by getInsertOrIgnoreSQL() seamlessly prevents
598  * duplicates in the case database, a valid row ID is
599  * returned here even if the INSERT is not done. So the
600  * bottom line is that a redundant event may be published
601  * from time to time.
602  */
603  db.fireTSKEvent(new TskEvent.OsAcctInstancesAddedTskEvent(Collections.singletonList(accountInstance)));
604  }
605  }
606  } catch (SQLException ex) {
607  throw new TskCoreException(String.format("Error adding OS account instance for OS account object id = %d, data source object id = %d", osAccountId, dataSourceObjId), ex);
608  } finally {
610  }
611  }
612 
622  public List<OsAccount> getOsAccounts(Host host) throws TskCoreException {
623 
624  String queryString = "SELECT * FROM tsk_os_accounts as accounts "
625  + " JOIN tsk_os_account_instances as instances "
626  + " ON instances.os_account_obj_id = accounts.os_account_obj_id "
627  + " JOIN data_source_info as datasources "
628  + " ON datasources.obj_id = instances.data_source_obj_id "
629  + " WHERE datasources.host_id = " + host.getHostId()
630  + " AND accounts.db_status = " + OsAccount.OsAccountDbStatus.ACTIVE.getId();
631 
633  try (CaseDbConnection connection = this.db.getConnection();
634  Statement s = connection.createStatement();
635  ResultSet rs = connection.executeQuery(s, queryString)) {
636 
637  List<OsAccount> accounts = new ArrayList<>();
638  while (rs.next()) {
639  accounts.add(osAccountFromResultSet(rs));
640  }
641  return accounts;
642  } catch (SQLException ex) {
643  throw new TskCoreException(String.format("Error getting OS accounts for host id = %d", host.getHostId()), ex);
644  } finally {
646  }
647  }
648 
661  void mergeOsAccountsForRealms(OsAccountRealm sourceRealm, OsAccountRealm destRealm, CaseDbTransaction trans) throws TskCoreException {
662  List<OsAccount> destinationAccounts = getOsAccounts(destRealm, trans.getConnection());
663  List<OsAccount> sourceAccounts = getOsAccounts(sourceRealm, trans.getConnection());
664 
665  for (OsAccount sourceAccount : sourceAccounts) {
666 
667  // First a check for the case where the source account has both the login name and unique ID set and
668  // we have separate matches in the destination account for both. If we find this case, we need to first merge
669  // the two accounts in the destination realm. This will ensure that all source accounts match at most one
670  // destination account.
671  // Note that we only merge accounts based on login name if the unique ID is empty.
672  if (sourceAccount.getAddr().isPresent() && sourceAccount.getLoginName().isPresent()) {
673  List<OsAccount> duplicateDestAccounts = destinationAccounts.stream()
674  .filter(p -> p.getAddr().equals(sourceAccount.getAddr())
675  || (p.getLoginName().equals(sourceAccount.getLoginName()) && (!p.getAddr().isPresent())))
676  .collect(Collectors.toList());
677  if (duplicateDestAccounts.size() > 1) {
678  OsAccount combinedDestAccount = duplicateDestAccounts.get(0);
679  duplicateDestAccounts.remove(combinedDestAccount);
680  for (OsAccount dupeDestAccount : duplicateDestAccounts) {
681  mergeOsAccounts(dupeDestAccount, combinedDestAccount, trans);
682  }
683  }
684  }
685 
686  // Look for matching destination account
687  OsAccount matchingDestAccount = null;
688 
689  // First look for matching unique id
690  if (sourceAccount.getAddr().isPresent()) {
691  List<OsAccount> matchingDestAccounts = destinationAccounts.stream()
692  .filter(p -> p.getAddr().equals(sourceAccount.getAddr()))
693  .collect(Collectors.toList());
694  if (!matchingDestAccounts.isEmpty()) {
695  matchingDestAccount = matchingDestAccounts.get(0);
696  }
697  }
698 
699  // If a match wasn't found yet, look for a matching login name.
700  // We will merge only if:
701  // - We didn't already find a unique ID match
702  // - The source account has no unique ID OR the destination account has no unique ID
703  if (matchingDestAccount == null && sourceAccount.getLoginName().isPresent()) {
704  List<OsAccount> matchingDestAccounts = destinationAccounts.stream()
705  .filter(p -> (p.getLoginName().equals(sourceAccount.getLoginName())
706  && ((!sourceAccount.getAddr().isPresent()) || (!p.getAddr().isPresent()))))
707  .collect(Collectors.toList());
708  if (!matchingDestAccounts.isEmpty()) {
709  matchingDestAccount = matchingDestAccounts.get(0);
710  }
711  }
712 
713  // If we found a match, merge the accounts. Otherwise simply update the realm id
714  if (matchingDestAccount != null) {
715  mergeOsAccounts(sourceAccount, matchingDestAccount, trans);
716  } else {
717  String query = "UPDATE tsk_os_accounts SET realm_id = " + destRealm.getRealmId() + " WHERE os_account_obj_id = " + sourceAccount.getId();
718  try (Statement s = trans.getConnection().createStatement()) {
719  s.executeUpdate(query);
720  } catch (SQLException ex) {
721  throw new TskCoreException("Error executing SQL update: " + query, ex);
722  }
723  trans.registerChangedOsAccount(sourceAccount);
724  }
725  }
726  }
727 
742  private void mergeOsAccounts(OsAccount sourceAccount, OsAccount destAccount, CaseDbTransaction trans) throws TskCoreException {
743 
744  String query = "";
745  try (Statement s = trans.getConnection().createStatement()) {
746 
747  // Update all references
748  query = makeOsAccountUpdateQuery("tsk_os_account_attributes", sourceAccount, destAccount);
749  s.executeUpdate(query);
750 
751  // tsk_os_account_instances has a unique constraint on os_account_obj_id, data_source_obj_id, host_id,
752  // so delete any rows that would be duplicates.
753  query = "DELETE FROM tsk_os_account_instances "
754  + "WHERE id IN ( "
755  + "SELECT "
756  + " sourceAccountInstance.id "
757  + "FROM "
758  + " tsk_os_account_instances destAccountInstance "
759  + "INNER JOIN tsk_os_account_instances sourceAccountInstance ON destAccountInstance.data_source_obj_id = sourceAccountInstance.data_source_obj_id "
760  + "WHERE destAccountInstance.os_account_obj_id = " + destAccount.getId()
761  + " AND sourceAccountInstance.os_account_obj_id = " + sourceAccount.getId() + " )";
762  s.executeUpdate(query);
763 
764  query = makeOsAccountUpdateQuery("tsk_os_account_instances", sourceAccount, destAccount);
765  s.executeUpdate(query);
766  synchronized (osAcctInstancesCacheLock) {
767  osAccountInstanceCache.clear();
768  }
769 
770  query = makeOsAccountUpdateQuery("tsk_files", sourceAccount, destAccount);
771  s.executeUpdate(query);
772 
773  query = makeOsAccountUpdateQuery("tsk_data_artifacts", sourceAccount, destAccount);
774  s.executeUpdate(query);
775 
776  // Update the source account. Make a dummy signature to prevent problems with the unique constraint.
777  String mergedSignature = makeMergedOsAccountSignature();
778  query = "UPDATE tsk_os_accounts SET merged_into = " + destAccount.getId()
779  + ", db_status = " + OsAccount.OsAccountDbStatus.MERGED.getId()
780  + ", signature = '" + mergedSignature + "' "
781  + " WHERE os_account_obj_id = " + sourceAccount.getId();
782 
783  s.executeUpdate(query);
784  trans.registerDeletedOsAccount(sourceAccount.getId());
785 
786  // Merge and update the destination account. Note that this must be done after updating
787  // the source account to prevent conflicts when merging two accounts in the
788  // same realm.
789  mergeOsAccountObjectsAndUpdateDestAccount(sourceAccount, destAccount, trans);
790  } catch (SQLException ex) {
791  throw new TskCoreException("Error executing SQL update: " + query, ex);
792  }
793  }
794 
800  private String makeMergedOsAccountSignature() {
801  return "MERGED " + UUID.randomUUID().toString();
802  }
803 
813  private String makeOsAccountUpdateQuery(String tableName, OsAccount sourceAccount, OsAccount destAccount) {
814  return "UPDATE " + tableName + " SET os_account_obj_id = " + destAccount.getId() + " WHERE os_account_obj_id = " + sourceAccount.getId();
815  }
816 
828  private OsAccount mergeOsAccountObjectsAndUpdateDestAccount(OsAccount sourceAccount, OsAccount destAccount, CaseDbTransaction trans) throws TskCoreException {
829 
830  OsAccount mergedDestAccount = destAccount;
831 
832  String destLoginName = null;
833  String destAddr = null;
834 
835  // Copy any fields that aren't set in the destination to the value from the source account.
836  if (!destAccount.getLoginName().isPresent() && sourceAccount.getLoginName().isPresent()) {
837  destLoginName = sourceAccount.getLoginName().get();
838  }
839 
840  if (!destAccount.getAddr().isPresent() && sourceAccount.getAddr().isPresent()) {
841  destAddr = sourceAccount.getAddr().get();
842  }
843 
844  // update the dest account core
845  OsAccountUpdateResult updateStatus = this.updateOsAccountCore(destAccount, destAddr, destLoginName, trans);
846 
847  if (updateStatus.getUpdateStatusCode() == OsAccountUpdateStatus.UPDATED && updateStatus.getUpdatedAccount().isPresent()) {
848  mergedDestAccount = updateStatus.getUpdatedAccount().get();
849  }
850 
851  String destFullName = null;
852  Long destCreationTime = null;
853  if (!destAccount.getFullName().isPresent() && sourceAccount.getFullName().isPresent()) {
854  destFullName = sourceAccount.getFullName().get();
855  }
856 
857  if (!destAccount.getCreationTime().isPresent() && sourceAccount.getCreationTime().isPresent()) {
858  destCreationTime = sourceAccount.getCreationTime().get();
859  }
860 
861  // update the dest account properties
862  updateStatus = this.updateStandardOsAccountAttributes(destAccount, destFullName, null, null, destCreationTime, trans);
863 
864  if (updateStatus.getUpdateStatusCode() == OsAccountUpdateStatus.UPDATED && updateStatus.getUpdatedAccount().isPresent()) {
865  mergedDestAccount = updateStatus.getUpdatedAccount().get();
866  }
867 
868  return mergedDestAccount;
869  }
870 
881  private List<OsAccount> getOsAccounts(OsAccountRealm realm, CaseDbConnection connection) throws TskCoreException {
882  String queryString = "SELECT * FROM tsk_os_accounts"
883  + " WHERE realm_id = " + realm.getRealmId()
884  + " AND db_status = " + OsAccount.OsAccountDbStatus.ACTIVE.getId()
885  + " ORDER BY os_account_obj_id";
886 
887  try (Statement s = connection.createStatement();
888  ResultSet rs = connection.executeQuery(s, queryString)) {
889 
890  List<OsAccount> accounts = new ArrayList<>();
891  while (rs.next()) {
892  accounts.add(osAccountFromResultSet(rs));
893  }
894  return accounts;
895  } catch (SQLException ex) {
896  throw new TskCoreException(String.format("Error getting OS accounts for realm id = %d", realm.getRealmId()), ex);
897  }
898  }
899 
907  public List<OsAccount> getOsAccounts() throws TskCoreException {
908  String queryString = "SELECT * FROM tsk_os_accounts"
909  + " WHERE db_status = " + OsAccount.OsAccountDbStatus.ACTIVE.getId();
910 
912  try (CaseDbConnection connection = this.db.getConnection();
913  Statement s = connection.createStatement();
914  ResultSet rs = connection.executeQuery(s, queryString)) {
915 
916  List<OsAccount> accounts = new ArrayList<>();
917  while (rs.next()) {
918  accounts.add(osAccountFromResultSet(rs));
919  }
920  return accounts;
921  } catch (SQLException ex) {
922  throw new TskCoreException(String.format("Error getting OS accounts"), ex);
923  } finally {
925  }
926  }
927 
943  public Optional<OsAccount> getWindowsOsAccount(String sid, String loginName, String realmName, Host referringHost) throws TskCoreException, NotUserSIDException {
944 
945  if (referringHost == null) {
946  throw new TskCoreException("A referring host is required to get an account.");
947  }
948 
949  // ensure at least one of the two is supplied - sid or a login name
950  if (StringUtils.isBlank(sid) && StringUtils.isBlank(loginName)) {
951  throw new TskCoreException("Cannot get an OS account with both SID and loginName as null.");
952  }
953 
954  // first get the realm for the given sid
955  Optional<OsAccountRealm> realm = db.getOsAccountRealmManager().getWindowsRealm(sid, realmName, referringHost);
956  if (!realm.isPresent()) {
957  return Optional.empty();
958  }
959 
960  // search by SID
961  if (!Strings.isNullOrEmpty(sid)) {
962  if (!WindowsAccountUtils.isWindowsUserSid(sid)) {
963  throw new OsAccountManager.NotUserSIDException(String.format("SID = %s is not a user SID.", sid));
964  }
965 
966  return this.getOsAccountByAddr(sid, realm.get());
967  }
968 
969  // search by login name
970  return this.getOsAccountByLoginName(loginName, realm.get());
971  }
972 
982  public void addExtendedOsAccountAttributes(OsAccount account, List<OsAccountAttribute> accountAttributes) throws TskCoreException {
983 
984  synchronized (account) { // synchronized to prevent multiple threads trying to add osAccount attributes concurrently to the same osAccount.
986 
987  try (CaseDbConnection connection = db.getConnection()) {
988  for (OsAccountAttribute accountAttribute : accountAttributes) {
989 
990  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)"
991  + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; // NON-NLS
992 
993  PreparedStatement preparedStatement = connection.getPreparedStatement(attributeInsertSQL, Statement.RETURN_GENERATED_KEYS);
994  preparedStatement.clearParameters();
995 
996  preparedStatement.setLong(1, account.getId());
997  if (accountAttribute.getHostId().isPresent()) {
998  preparedStatement.setLong(2, accountAttribute.getHostId().get());
999  } else {
1000  preparedStatement.setNull(2, java.sql.Types.NULL);
1001  }
1002  if (accountAttribute.getSourceObjectId().isPresent()) {
1003  preparedStatement.setLong(3, accountAttribute.getSourceObjectId().get());
1004  } else {
1005  preparedStatement.setNull(3, java.sql.Types.NULL);
1006  }
1007 
1008  preparedStatement.setLong(4, accountAttribute.getAttributeType().getTypeID());
1009  preparedStatement.setLong(5, accountAttribute.getAttributeType().getValueType().getType());
1010 
1011  if (accountAttribute.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.BYTE) {
1012  preparedStatement.setBytes(6, accountAttribute.getValueBytes());
1013  } else {
1014  preparedStatement.setBytes(6, null);
1015  }
1016 
1017  if (accountAttribute.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING
1018  || accountAttribute.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.JSON) {
1019  preparedStatement.setString(7, accountAttribute.getValueString());
1020  } else {
1021  preparedStatement.setString(7, null);
1022  }
1023  if (accountAttribute.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.INTEGER) {
1024  preparedStatement.setInt(8, accountAttribute.getValueInt());
1025  } else {
1026  preparedStatement.setNull(8, java.sql.Types.NULL);
1027  }
1028 
1029  if (accountAttribute.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME
1030  || accountAttribute.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.LONG) {
1031  preparedStatement.setLong(9, accountAttribute.getValueLong());
1032  } else {
1033  preparedStatement.setNull(9, java.sql.Types.NULL);
1034  }
1035 
1036  if (accountAttribute.getAttributeType().getValueType() == TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DOUBLE) {
1037  preparedStatement.setDouble(10, accountAttribute.getValueDouble());
1038  } else {
1039  preparedStatement.setNull(10, java.sql.Types.NULL);
1040  }
1041 
1042  connection.executeUpdate(preparedStatement);
1043  }
1044  } catch (SQLException ex) {
1045  throw new TskCoreException(String.format("Error adding OS Account attribute for account id = %d", account.getId()), ex);
1046  } finally {
1048  }
1049  // set the atrribute list in account to the most current list from the database
1050  List<OsAccountAttribute> currentAttribsList = getOsAccountAttributes(account);
1051  account.setAttributesInternal(currentAttribsList);
1052  }
1053  fireChangeEvent(account);
1054  }
1055 
1065  List<OsAccountAttribute> getOsAccountAttributes(OsAccount account) throws TskCoreException {
1066 
1067  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, "
1068  + " attributes.attribute_type_id as attribute_type_id, attributes.value_type as value_type, attributes.value_byte as value_byte, "
1069  + " attributes.value_text as value_text, attributes.value_int32 as value_int32, attributes.value_int64 as value_int64, attributes.value_double as value_double, "
1070  + " hosts.id, hosts.name as host_name, hosts.db_status as host_status "
1071  + " FROM tsk_os_account_attributes as attributes"
1072  + " LEFT JOIN tsk_hosts as hosts "
1073  + " ON attributes.host_id = hosts.id "
1074  + " WHERE os_account_obj_id = " + account.getId();
1075 
1077  try (CaseDbConnection connection = this.db.getConnection();
1078  Statement s = connection.createStatement();
1079  ResultSet rs = connection.executeQuery(s, queryString)) {
1080 
1081  List<OsAccountAttribute> attributes = new ArrayList<>();
1082  while (rs.next()) {
1083 
1084  Host host = null;
1085  long hostId = rs.getLong("host_id");
1086  if (!rs.wasNull()) {
1087  host = new Host(hostId, rs.getString("host_name"), Host.HostDbStatus.fromID(rs.getInt("host_status")));
1088  }
1089 
1090  Content sourceContent = null;
1091  long sourceObjId = rs.getLong("source_obj_id");
1092  if (!rs.wasNull()) {
1093  sourceContent = this.db.getContentById(sourceObjId);
1094  }
1095  BlackboardAttribute.Type attributeType = db.getAttributeType(rs.getInt("attribute_type_id"));
1096  OsAccountAttribute attribute = account.new OsAccountAttribute(attributeType, rs.getInt("value_int32"), rs.getLong("value_int64"),
1097  rs.getDouble("value_double"), rs.getString("value_text"), rs.getBytes("value_byte"),
1098  db, account, host, sourceContent);
1099 
1100  attributes.add(attribute);
1101  }
1102  return attributes;
1103  } catch (SQLException ex) {
1104  throw new TskCoreException(String.format("Error getting OS account attributes for account obj id = %d", account.getId()), ex);
1105  } finally {
1107  }
1108  }
1109 
1119  List<OsAccountInstance> getOsAccountInstances(OsAccount account) throws TskCoreException {
1120  String whereClause = "tsk_os_account_instances.os_account_obj_id = " + account.getId();
1121  return getOsAccountInstances(whereClause);
1122  }
1123 
1134  public List<OsAccountInstance> getOsAccountInstances(List<Long> instanceIDs) throws TskCoreException {
1135  String instanceIds = instanceIDs.stream().map(id -> id.toString()).collect(Collectors.joining(","));
1136  String whereClause = "tsk_os_account_instances.id IN (" + instanceIds + ")";
1137  return getOsAccountInstances(whereClause);
1138  }
1139 
1150  private List<OsAccountInstance> getOsAccountInstances(String whereClause) throws TskCoreException {
1151  List<OsAccountInstance> osAcctInstances = new ArrayList<>();
1152  String querySQL = "SELECT * FROM tsk_os_account_instances WHERE " + whereClause;
1154  try (CaseDbConnection connection = db.getConnection();
1155  PreparedStatement preparedStatement = connection.getPreparedStatement(querySQL, Statement.NO_GENERATED_KEYS);
1156  ResultSet results = connection.executeQuery(preparedStatement)) {
1157  while (results.next()) {
1158  long instanceId = results.getLong("id");
1159  long osAccountObjID = results.getLong("os_account_obj_id");
1160  long dataSourceObjId = results.getLong("data_source_obj_id");
1161  int instanceType = results.getInt("instance_type");
1162  osAcctInstances.add(new OsAccountInstance(db, instanceId, osAccountObjID, dataSourceObjId, OsAccountInstance.OsAccountInstanceType.fromID(instanceType)));
1163  }
1164  } catch (SQLException ex) {
1165  throw new TskCoreException("Failed to get OsAccountInstances (SQL = " + querySQL + ")", ex);
1166  } finally {
1168  }
1169  return osAcctInstances;
1170  }
1171 
1188  public OsAccountUpdateResult updateStandardOsAccountAttributes(OsAccount osAccount, String fullName, OsAccountType accountType, OsAccountStatus accountStatus, Long creationTime) throws TskCoreException {
1189 
1190  CaseDbTransaction trans = db.beginTransaction();
1191  try {
1192  OsAccountUpdateResult updateStatus = updateStandardOsAccountAttributes(osAccount, fullName, accountType, accountStatus, creationTime, trans);
1193 
1194  trans.commit();
1195  trans = null;
1196 
1197  return updateStatus;
1198  } finally {
1199  if (trans != null) {
1200  trans.rollback();
1201  }
1202  }
1203  }
1204 
1222  OsAccountUpdateResult updateStandardOsAccountAttributes(OsAccount osAccount, String fullName, OsAccountType accountType, OsAccountStatus accountStatus, Long creationTime, CaseDbTransaction trans) throws TskCoreException {
1223 
1224  OsAccountUpdateStatus updateStatusCode = OsAccountUpdateStatus.NO_CHANGE;
1225 
1226  try {
1227  CaseDbConnection connection = trans.getConnection();
1228 
1229  if (!StringUtils.isBlank(fullName)) {
1230  updateAccountColumn(osAccount.getId(), "full_name", fullName, connection);
1231  updateStatusCode = OsAccountUpdateStatus.UPDATED;
1232  }
1233 
1234  if (Objects.nonNull(accountType)) {
1235  updateAccountColumn(osAccount.getId(), "type", accountType, connection);
1236  updateStatusCode = OsAccountUpdateStatus.UPDATED;
1237  }
1238 
1239  if (Objects.nonNull(accountStatus)) {
1240  updateAccountColumn(osAccount.getId(), "status", accountStatus, connection);
1241  updateStatusCode = OsAccountUpdateStatus.UPDATED;
1242  }
1243 
1244  if (Objects.nonNull(creationTime)) {
1245  updateAccountColumn(osAccount.getId(), "created_date", creationTime, connection);
1246  updateStatusCode = OsAccountUpdateStatus.UPDATED;
1247  }
1248 
1249  // if nothing has been changed, return
1250  if (updateStatusCode == OsAccountUpdateStatus.NO_CHANGE) {
1251  return new OsAccountUpdateResult(updateStatusCode, null);
1252  }
1253 
1254  // get the updated account from database
1255  OsAccount updatedAccount = getOsAccountByObjectId(osAccount.getId(), connection);
1256 
1257  // register the updated account with the transaction to fire off an event
1258  trans.registerChangedOsAccount(updatedAccount);
1259 
1260  return new OsAccountUpdateResult(updateStatusCode, updatedAccount);
1261 
1262  } catch (SQLException ex) {
1263  throw new TskCoreException(String.format("Error updating account with addr = %s, account id = %d", osAccount.getAddr().orElse("Unknown"), osAccount.getId()), ex);
1264  }
1265  }
1266 
1280  private <T> void updateAccountColumn(long accountObjId, String colName, T colValue, CaseDbConnection connection) throws SQLException, TskCoreException {
1281 
1282  String updateSQL = "UPDATE tsk_os_accounts "
1283  + " SET " + colName + " = ? "
1284  + " WHERE os_account_obj_id = ?";
1285 
1287  try {
1288  PreparedStatement preparedStatement = connection.getPreparedStatement(updateSQL, Statement.NO_GENERATED_KEYS);
1289  preparedStatement.clearParameters();
1290 
1291  if (Objects.isNull(colValue)) {
1292  preparedStatement.setNull(1, Types.NULL); // handle null value
1293  } else {
1294  if (colValue instanceof String) {
1295  preparedStatement.setString(1, (String) colValue);
1296  } else if (colValue instanceof Long) {
1297  preparedStatement.setLong(1, (Long) colValue);
1298  } else if (colValue instanceof Integer) {
1299  preparedStatement.setInt(1, (Integer) colValue);
1300  } else {
1301  throw new TskCoreException(String.format("Unhandled column data type received while updating the account (%d) ", accountObjId));
1302  }
1303  }
1304 
1305  preparedStatement.setLong(2, accountObjId);
1306 
1307  connection.executeUpdate(preparedStatement);
1308  } finally {
1310  }
1311  }
1312 
1323  private void updateAccountSignature(long accountObjId, String signature, CaseDbConnection connection) throws SQLException {
1324 
1325  String updateSQL = "UPDATE tsk_os_accounts SET "
1326  + " signature = "
1327  + " CASE WHEN db_status = " + OsAccount.OsAccountDbStatus.ACTIVE.getId() + " THEN ? ELSE signature END "
1328  + " WHERE os_account_obj_id = ?"; // 8
1329 
1330  PreparedStatement preparedStatement = connection.getPreparedStatement(updateSQL, Statement.NO_GENERATED_KEYS);
1331  preparedStatement.clearParameters();
1332 
1333  preparedStatement.setString(1, signature);
1334  preparedStatement.setLong(2, accountObjId);
1335 
1336  connection.executeUpdate(preparedStatement);
1337  }
1338 
1359  public OsAccountUpdateResult updateCoreWindowsOsAccountAttributes(OsAccount osAccount, String accountSid, String loginName, String realmName, Host referringHost) throws TskCoreException, NotUserSIDException {
1360  CaseDbTransaction trans = db.beginTransaction();
1361  try {
1362  OsAccountUpdateResult updateStatus = this.updateCoreWindowsOsAccountAttributes(osAccount, accountSid, loginName, realmName, referringHost, trans);
1363 
1364  trans.commit();
1365  trans = null;
1366  return updateStatus;
1367  } finally {
1368  if (trans != null) {
1369  trans.rollback();
1370  }
1371  }
1372  }
1373 
1393  private OsAccountUpdateResult updateCoreWindowsOsAccountAttributes(OsAccount osAccount, String accountSid, String loginName, String realmName, Host referringHost, CaseDbTransaction trans) throws TskCoreException, NotUserSIDException {
1394 
1395  // first get and update the realm - if we have the info to find the realm
1396  if (!StringUtils.isBlank(accountSid) || !StringUtils.isBlank(realmName)) {
1397  db.getOsAccountRealmManager().getAndUpdateWindowsRealm(accountSid, realmName, referringHost, trans.getConnection());
1398  }
1399 
1400  // now update the account core data
1401  OsAccountUpdateResult updateStatus = this.updateOsAccountCore(osAccount, accountSid, loginName, trans);
1402 
1403  return updateStatus;
1404  }
1405 
1428  private OsAccountUpdateResult updateOsAccountCore(OsAccount osAccount, String address, String loginName, CaseDbTransaction trans) throws TskCoreException {
1429 
1430  OsAccountUpdateStatus updateStatusCode = OsAccountUpdateStatus.NO_CHANGE;
1431  OsAccount updatedAccount;
1432 
1433  try {
1434  CaseDbConnection connection = trans.getConnection();
1435 
1436  // if a new addr is provided and the account already has an address, and they are not the same, throw an exception
1437  if (!StringUtils.isBlank(address) && !StringUtils.isBlank(osAccount.getAddr().orElse(null)) && !address.equalsIgnoreCase(osAccount.getAddr().orElse(""))) {
1438  throw new TskCoreException(String.format("Account (%d) already has an address (%s), address cannot be updated.", osAccount.getId(), osAccount.getAddr().orElse("NULL")));
1439  }
1440 
1441  // if a new login name is provided and the account already has a loginname and they are not the same, throw an exception
1442  if (!StringUtils.isBlank(loginName) && !StringUtils.isBlank(osAccount.getLoginName().orElse(null)) && !loginName.equalsIgnoreCase(osAccount.getLoginName().orElse(""))) {
1443  throw new TskCoreException(String.format("Account (%d) already has a login name (%s), login name cannot be updated.", osAccount.getId(), osAccount.getLoginName().orElse("NULL")));
1444  }
1445 
1446  if (StringUtils.isBlank(osAccount.getAddr().orElse(null)) && !StringUtils.isBlank(address)) {
1447  updateAccountColumn(osAccount.getId(), "addr", address, connection);
1448  updateStatusCode = OsAccountUpdateStatus.UPDATED;
1449  }
1450 
1451  if (StringUtils.isBlank(osAccount.getLoginName().orElse(null)) && !StringUtils.isBlank(loginName)) {
1452  updateAccountColumn(osAccount.getId(), "login_name", loginName, connection);
1453  updateStatusCode = OsAccountUpdateStatus.UPDATED;
1454  }
1455 
1456  // if nothing is changed, return
1457  if (updateStatusCode == OsAccountUpdateStatus.NO_CHANGE) {
1458  return new OsAccountUpdateResult(updateStatusCode, osAccount);
1459  }
1460 
1461  // update signature if needed, based on the most current addr/loginName
1462  OsAccount currAccount = getOsAccountByObjectId(osAccount.getId(), connection);
1463  String newAddress = currAccount.getAddr().orElse(null);
1464  String newLoginName = currAccount.getLoginName().orElse(null);
1465 
1466  String newSignature = getOsAccountSignature(newAddress, newLoginName);
1467  updateAccountSignature(osAccount.getId(), newSignature, connection);
1468 
1469  // get the updated account from database
1470  updatedAccount = getOsAccountByObjectId(osAccount.getId(), connection);
1471 
1472  // register the updated account with the transaction to fire off an event
1473  trans.registerChangedOsAccount(updatedAccount);
1474 
1475  return new OsAccountUpdateResult(updateStatusCode, updatedAccount);
1476 
1477  } catch (SQLException ex) {
1478  throw new TskCoreException(String.format("Error updating account with unique id = %s, account id = %d", osAccount.getAddr().orElse("Unknown"), osAccount.getId()), ex);
1479  }
1480  }
1481 
1491  public List<Host> getHosts(OsAccount account) throws TskCoreException {
1492  List<Host> hostList = new ArrayList<>();
1493 
1494  String query = "SELECT tsk_hosts.id AS hostId, name, db_status FROM tsk_hosts "
1495  + " JOIN data_source_info ON tsk_hosts.id = data_source_info.host_id"
1496  + " JOIN tsk_os_account_instances ON data_source_info.obj_id = tsk_os_account_instances.data_source_obj_id"
1497  + " WHERE os_account_obj_id = " + account.getId();
1498 
1500  try (CaseDbConnection connection = db.getConnection();
1501  Statement s = connection.createStatement();
1502  ResultSet rs = connection.executeQuery(s, query)) {
1503 
1504  while (rs.next()) {
1505  hostList.add(new Host(rs.getLong("hostId"), rs.getString("name"), Host.HostDbStatus.fromID(rs.getInt("db_status"))));
1506  }
1507 
1508  } catch (SQLException ex) {
1509  throw new TskCoreException(String.format("Failed to get host list for os account %d", account.getId()), ex);
1510  } finally {
1512  }
1513  return hostList;
1514  }
1515 
1527  private OsAccount osAccountFromResultSet(ResultSet rs) throws SQLException {
1528 
1529  OsAccountType accountType = null;
1530  int typeId = rs.getInt("type");
1531  if (!rs.wasNull()) {
1532  accountType = OsAccount.OsAccountType.fromID(typeId);
1533  }
1534 
1535  Long creationTime = rs.getLong("created_date"); // getLong returns 0 if value is null
1536  if (rs.wasNull()) {
1537  creationTime = null;
1538  }
1539 
1540  return new OsAccount(db, rs.getLong("os_account_obj_id"), rs.getLong("realm_id"), rs.getString("login_name"), rs.getString("addr"),
1541  rs.getString("signature"), rs.getString("full_name"), creationTime, accountType, OsAccount.OsAccountStatus.fromID(rs.getInt("status")),
1542  OsAccount.OsAccountDbStatus.fromID(rs.getInt("db_status")));
1543 
1544  }
1545 
1552  private void fireChangeEvent(OsAccount account) {
1553  db.fireTSKEvent(new OsAccountsUpdatedTskEvent(Collections.singletonList(account)));
1554  }
1555 
1570  static String getOsAccountSignature(String uniqueId, String loginName) throws TskCoreException {
1571  // Create a signature.
1572  String signature;
1573  if (Strings.isNullOrEmpty(uniqueId) == false) {
1574  signature = uniqueId;
1575  } else if (Strings.isNullOrEmpty(loginName) == false) {
1576  signature = loginName;
1577  } else {
1578  throw new TskCoreException("OS Account must have either a uniqueID or a login name.");
1579  }
1580  return signature;
1581  }
1582 
1587  public static class NotUserSIDException extends TskException {
1588 
1589  private static final long serialVersionUID = 1L;
1590 
1595  super("No error message available.");
1596  }
1597 
1603  public NotUserSIDException(String msg) {
1604  super(msg);
1605  }
1606 
1613  public NotUserSIDException(String msg, Exception ex) {
1614  super(msg, ex);
1615  }
1616  }
1617 
1622 
1625  MERGED
1626  }
1627 
1632  public final static class OsAccountUpdateResult {
1633 
1634  private final OsAccountUpdateStatus updateStatus;
1635  private final OsAccount updatedAccount;
1636 
1637  OsAccountUpdateResult(OsAccountUpdateStatus updateStatus, OsAccount updatedAccount) {
1638  this.updateStatus = updateStatus;
1639  this.updatedAccount = updatedAccount;
1640  }
1641 
1643  return updateStatus;
1644  }
1645 
1646  public Optional<OsAccount> getUpdatedAccount() {
1647  return Optional.ofNullable(updatedAccount);
1648  }
1649  }
1650 }
Optional< String > getAddr()
Definition: OsAccount.java:266
OsAccountRealm newWindowsRealm(String accountSid, String realmName, Host referringHost, OsAccountRealm.RealmScope realmScope)
List< Host > getHosts(OsAccount account)
OsAccount getOsAccountByObjectId(long osAccountObjId)
static OsAccountType fromID(int typeId)
Definition: OsAccount.java:193
void newOsAccountInstance(OsAccount osAccount, DataSource dataSource, OsAccountInstance.OsAccountInstanceType instanceType)
Optional< OsAccount > getWindowsOsAccount(String sid, String loginName, String realmName, Host referringHost)
OsAccountUpdateResult updateStandardOsAccountAttributes(OsAccount osAccount, String fullName, OsAccountType accountType, OsAccountStatus accountStatus, Long creationTime)
OsAccount newWindowsOsAccount(String sid, String loginName, OsAccountRealm realm)
List< OsAccount > getOsAccounts(Host host)
OsAccountRealmManager getOsAccountRealmManager()
Optional< OsAccountRealm > getWindowsRealm(String accountSid, String realmName, Host referringHost)
List< OsAccountInstance > getOsAccountInstances(List< Long > instanceIDs)
BlackboardAttribute.Type getAttributeType(String attrTypeName)
Optional< String > getLoginName()
Definition: OsAccount.java:286
void addExtendedOsAccountAttributes(OsAccount account, List< OsAccountAttribute > accountAttributes)
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)

Copyright © 2011-2021 Brian Carrier. (carrier -at- sleuthkit -dot- org)
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.