Autopsy  4.17.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
CentralRepoDbManager.java
Go to the documentation of this file.
1 /*
2  * Central Repository
3  *
4  * Copyright 2015-2020 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.autopsy.centralrepository.datamodel;
20 
21 import java.beans.PropertyChangeListener;
22 import java.beans.PropertyChangeSupport;
23 import java.io.File;
24 import java.sql.SQLException;
25 import java.util.logging.Level;
26 import org.openide.util.NbBundle;
31 
36 public class CentralRepoDbManager {
37 
38  private static final Logger logger = Logger.getLogger(CentralRepoDbManager.class.getName());
39 
40  private static final String CENTRAL_REPO_DB_NAME = "central_repository";
41  private static final String CENTRAL_REPOSITORY_SETTINGS_KEY = "CentralRepository";
42  private static final String DB_SELECTED_PLATFORM_KEY = "db.selectedPlatform";
43  private static final String DISABLED_DUE_TO_FAILURE_KEY = "disabledDueToFailure";
44 
45  private static volatile CentralRepoDbChoice savedChoice = null;
46 
47  private static final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(CentralRepoDbManager.class);
48 
49  private static final Object dbChoiceLock = new Object();
50  private static final Object disabledDueToFailureLock = new Object();
51 
61  return saveDbChoice(choice, true);
62  }
63 
73  public static CentralRepoDbChoice saveDbChoice(CentralRepoDbChoice choice, boolean clearDisabledDueToError) {
74  synchronized (dbChoiceLock) {
75  // clear disabling due to a failure
76  if (clearDisabledDueToError) {
78  }
79 
80  // change the settings
81  CentralRepoDbChoice newChoice = (choice == null) ? CentralRepoDbChoice.DISABLED : choice;
82  CentralRepoDbChoice oldChoice = savedChoice;
83  savedChoice = newChoice;
84  ModuleSettings.setConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DB_SELECTED_PLATFORM_KEY, newChoice.getSettingKey());
85  propertyChangeSupport.firePropertyChange("savedChoice", oldChoice, newChoice);
86  return newChoice;
87  }
88 
89  }
90 
97  public static boolean isPostgresMultiuserAllowed() {
98  // if multi user mode is not enabled, then this cannot be used
100  return false;
101  }
102  // also validate the connection as well
103  PostgresCentralRepoSettings multiUserSettings
105 
106  return multiUserSettings.testStatus() == DatabaseTestResult.TESTED_OK;
107  }
108 
114  synchronized (dbChoiceLock) {
115  if (savedChoice == null) {
116  String selectedPlatformString = ModuleSettings.getConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DB_SELECTED_PLATFORM_KEY); // NON-NLS
117  savedChoice = fromKey(selectedPlatformString);
118  }
119 
120  return savedChoice;
121  }
122  }
123 
130  public static void disableDueToFailure() {
133  }
134 
143  private static void setDisabledDueToFailure(boolean disabledDueToFailure) {
144  synchronized (disabledDueToFailureLock) {
145  boolean oldValue = isDisabledDueToFailure();
146  ModuleSettings.setConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DISABLED_DUE_TO_FAILURE_KEY, Boolean.toString(disabledDueToFailure));
147  propertyChangeSupport.firePropertyChange("disabledDueToFailure", oldValue, disabledDueToFailure);
148  }
149  }
150 
159  public static boolean isDisabledDueToFailure() {
160  synchronized (disabledDueToFailureLock) {
161  return Boolean.toString(true).equals(ModuleSettings.getConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DISABLED_DUE_TO_FAILURE_KEY));
162  }
163  }
164 
172  public static void addPropertyChangeListener(PropertyChangeListener listener) {
173  propertyChangeSupport.addPropertyChangeListener(listener);
174  }
175 
181  public static void removePropertyChangeListener(PropertyChangeListener listener) {
182  propertyChangeSupport.removePropertyChangeListener(listener);
183  }
184 
185  private static CentralRepoDbChoice fromKey(String keyName) {
186  for (CentralRepoDbChoice dbChoice : CentralRepoDbChoice.values()) {
187  if (dbChoice.getSettingKey().equalsIgnoreCase(keyName)) {
188  return dbChoice;
189  }
190  }
191 
193  }
194 
203  //get connection
204  try {
206  } catch (CentralRepoException ex) {
207  logger.log(Level.SEVERE, "Error updating central repository, unable to make connection", ex);
208  onUpgradeError("Error updating central repository, unable to make connection",
209  Bundle.EamDbUtil_centralRepoConnectionFailed_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
210  }
211 
212  // will never be reached
213  return null;
214  }
215 
226  try {
227  // This may return null if locking isn't supported, which is fine. It will
228  // throw an exception if locking is supported but we can't get the lock
229  // (meaning the database is in use by another user)
230  return db.getExclusiveMultiUserDbLock();
231  //perform upgrade
232  } catch (CentralRepoException ex) {
233  logger.log(Level.SEVERE, "Error updating central repository, unable to acquire exclusive lock", ex);
234  onUpgradeError("Error updating central repository, unable to acquire exclusive lock",
235  Bundle.EamDbUtil_exclusiveLockAquisitionFailure_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
236  }
237 
238  // will never be reached
239  return null;
240  }
241 
251  try {
252  db.upgradeSchema();
253  } catch (CentralRepoException ex) {
254  logger.log(Level.SEVERE, "Error updating central repository", ex);
255  onUpgradeError("Error updating central repository", ex.getUserMessage() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
256  } catch (SQLException ex) {
257  logger.log(Level.SEVERE, "Error updating central repository", ex);
258  onUpgradeError("Error updating central repository",
259  Bundle.EamDbUtil_centralRepoUpgradeFailed_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
260  } catch (IncompatibleCentralRepoException ex) {
261  logger.log(Level.SEVERE, "Error updating central repository", ex);
262  onUpgradeError("Error updating central repository",
263  ex.getMessage() + "\n\n" + Bundle.EamDbUtil_centralRepoUpgradeFailed_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
264  } finally {
265  if (lock != null) {
266  try {
267  lock.release();
269  logger.log(Level.SEVERE, "Error releasing database lock", ex);
270  }
271  }
272  }
273  }
274 
280  @NbBundle.Messages(value = {"EamDbUtil.centralRepoDisabled.message= The Central Repository has been disabled.", "EamDbUtil.centralRepoUpgradeFailed.message=Failed to upgrade Central Repository.", "EamDbUtil.centralRepoConnectionFailed.message=Unable to connect to Central Repository.", "EamDbUtil.exclusiveLockAquisitionFailure.message=Unable to acquire exclusive lock for Central Repository."})
281  public static void upgradeDatabase() throws CentralRepoException {
282  if (!CentralRepository.isEnabled()) {
283  return;
284  }
285 
287 
288  //get lock necessary for upgrade
289  if (db != null) {
291  updatedDbSchema(db, lock);
292  } else {
293  onUpgradeError("Unable to connect to database",
294  Bundle.EamDbUtil_centralRepoConnectionFailed_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), null);
295  }
296  }
297 
298  private static void onUpgradeError(String message, String desc, Exception innerException) throws CentralRepoException {
299  // Disable the central repo and clear the current settings.
300  try {
301  if (null != CentralRepository.getInstance()) {
303  }
304  } catch (CentralRepoException ex2) {
305  logger.log(Level.SEVERE, "Error shutting down central repo connection pool", ex2);
306  }
308  if (innerException == null) {
309  throw new CentralRepoException(message, desc);
310  } else {
311  throw new CentralRepoException(message, desc, innerException);
312  }
313  }
314 
317 
321 
322  private boolean configurationChanged = false;
323 
325  selectedDbChoice = getSavedDbChoice();
328  dbSettingsSqlite = new SqliteCentralRepoSettings();
329  }
330 
337  return dbSettingsMultiUser;
338  }
339 
346  return dbSettingsPostgres;
347  }
348 
356  return dbSettingsSqlite;
357  }
358 
365  // change in-memory settings to default sqlite
366  selectedDbChoice = CentralRepoDbChoice.SQLITE;
367  dbSettingsSqlite.setupDefaultSettings();
368 
369  // if db is not present, attempt to create it
370  DatabaseTestResult curStatus = testStatus();
371  if (curStatus == DatabaseTestResult.DB_DOES_NOT_EXIST) {
372  createDb();
373  curStatus = testStatus();
374  }
375 
376  // the only successful setup status is tested ok
377  if (curStatus != DatabaseTestResult.TESTED_OK) {
378  throw new CentralRepoException("Unable to successfully create sqlite database");
379  }
380 
381  // if successfully got here, then save the settings
384  }
385 
394  selectedDbChoice = choice;
395  DatabaseTestResult curStatus = testStatus();
396  if (curStatus == DatabaseTestResult.DB_DOES_NOT_EXIST) {
397  createDb();
398  curStatus = testStatus();
399  }
400 
401  // the only successful setup status is tested ok
402  if (curStatus != DatabaseTestResult.TESTED_OK) {
403  throw new CentralRepoException("Unable to successfully create postgres database. Test failed with: " + curStatus);
404  }
405 
406  // if successfully got here, then save the settings
409  }
410 
418  public boolean wasConfigurationChanged() {
419  return configurationChanged;
420  }
421 
423  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
424  return dbSettingsMultiUser;
425  }
426  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
427  return dbSettingsPostgres;
428  }
429  if (selectedDbChoice == CentralRepoDbChoice.SQLITE) {
430  return dbSettingsSqlite;
431  }
432  if (selectedDbChoice == CentralRepoDbChoice.DISABLED) {
433  return null;
434  }
435 
436  throw new CentralRepoException("Unknown database type: " + selectedDbChoice);
437  }
438 
440  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
441  return new RdbmsCentralRepoFactory(CentralRepoPlatforms.POSTGRESQL, dbSettingsMultiUser);
442  }
443  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
444  return new RdbmsCentralRepoFactory(CentralRepoPlatforms.POSTGRESQL, dbSettingsPostgres);
445  }
446  if (selectedDbChoice == CentralRepoDbChoice.SQLITE) {
447  return new RdbmsCentralRepoFactory(CentralRepoPlatforms.SQLITE, dbSettingsSqlite);
448  }
449  if (selectedDbChoice == CentralRepoDbChoice.DISABLED) {
450  return null;
451  }
452 
453  throw new CentralRepoException("Unknown database type: " + selectedDbChoice);
454  }
455 
463  public boolean createDb() throws CentralRepoException {
465  if (selectedDbSettings == null) {
466  throw new CentralRepoException("Unable to derive connectivity manager from settings: " + selectedDbChoice);
467  }
468 
469  boolean result = false;
470  boolean dbCreated = true;
471 
472  if (!selectedDbSettings.verifyDatabaseExists()) {
473  dbCreated = selectedDbSettings.createDatabase();
474  }
475  if (dbCreated) {
476  try {
477  RdbmsCentralRepoFactory centralRepoSchemaFactory = getDbFactory();
478 
479  result = centralRepoSchemaFactory.initializeDatabaseSchema()
480  && centralRepoSchemaFactory.insertDefaultDatabaseContent();
481  } catch (CentralRepoException ex) {
482  logger.log(Level.SEVERE, "Unable to create database for central repository with settings " + selectedDbSettings, ex);
483  throw ex;
484  }
485  }
486  if (!result) {
487  // Remove the incomplete database
488  if (dbCreated) {
489  selectedDbSettings.deleteDatabase();
490  }
491 
492  String schemaError = "Unable to initialize database schema or insert contents into central repository.";
493  logger.severe(schemaError);
494  throw new CentralRepoException(schemaError);
495  }
496 
497  testingStatus = DatabaseTestResult.TESTED_OK;
498  return true;
499  }
500 
504  @NbBundle.Messages({"CentralRepoDbManager.connectionErrorMsg.text=Failed to connect to central repository database."})
514  try {
515  CentralRepository previousDbManager = CentralRepository.getInstance();
516  if (null != previousDbManager) {
517  // NOTE: do not set/save the seleted platform before calling this.
519  }
520  } catch (CentralRepoException ex) {
521  logger.log(Level.SEVERE, "Failed to close database connections in previously selected platform.", ex); // NON-NLS
522  throw ex;
523  }
524 
525  // Even if we fail to close the existing connections, make sure that we
526  // save the new connection settings, so an Autopsy restart will correctly
527  // start with the new settings.
529  saveDbChoice(selectedDbChoice);
530 
532 
533  // save the new settings
534  selectedDbSettings.saveSettings();
535  // Load those newly saved settings into the postgres db manager instance
536  // in case we are still using the same instance.
537  if (selectedDbChoice != null && selectedDbChoice != CentralRepoDbChoice.DISABLED) {
538  try {
539  logger.info("Saving central repo settings for db: " + selectedDbSettings);
541  configurationChanged = true;
542  } catch (CentralRepoException ex) {
543  logger.log(Level.SEVERE, Bundle.CentralRepoDbManager_connectionErrorMsg_text(), ex); //NON-NLS
544  return;
545  }
546  }
547  }
548 
556  return testingStatus;
557  }
558 
566  return selectedDbChoice;
567  }
568 
572  public void clearStatus() {
573  testingStatus = DatabaseTestResult.UNTESTED;
574  }
575 
582  public void setSelctedDbChoice(CentralRepoDbChoice newSelected) {
583  selectedDbChoice = newSelected;
584  testingStatus = DatabaseTestResult.UNTESTED;
585  }
586 
594  String tbDbHostname, String tbDbPort, String tbDbUsername, String tfDatabasePath, String jpDbPassword) throws CentralRepoException, NumberFormatException {
595 
596  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
597  dbSettingsPostgres.setHost(tbDbHostname);
598  dbSettingsPostgres.setPort(Integer.parseInt(tbDbPort));
599  dbSettingsPostgres.setDbName(CENTRAL_REPO_DB_NAME);
600  dbSettingsPostgres.setUserName(tbDbUsername);
601  dbSettingsPostgres.setPassword(jpDbPassword);
602  } else if (selectedDbChoice == CentralRepoDbChoice.SQLITE) {
603  File databasePath = new File(tfDatabasePath);
605  dbSettingsSqlite.setDbDirectory(databasePath.getPath());
606  } else if (selectedDbChoice != CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
607  throw new IllegalStateException("Central Repo has an unknown selected platform: " + selectedDbChoice);
608  }
609 
610  return true;
611  }
612 
620  try {
622  if (manager != null) {
623  testingStatus = manager.testStatus();
624  }
625  } catch (CentralRepoException e) {
626  logger.log(Level.WARNING, "unable to test status of db connection in central repo", e);
627  }
628 
629  return testingStatus;
630  }
631 }
static synchronized String getConfigSetting(String moduleName, String settingName)
static CentralRepoDbChoice saveDbChoice(CentralRepoDbChoice choice, boolean clearDisabledDueToError)
static void onUpgradeError(String message, String desc, Exception innerException)
static void setUseCentralRepo(boolean centralRepoCheckBoxIsSelected)
static CentralRepoDbChoice saveDbChoice(CentralRepoDbChoice choice)
static CoordinationService.Lock obtainCentralRepoLock(CentralRepository db)
boolean testDatabaseSettingsAreValid(String tbDbHostname, String tbDbPort, String tbDbUsername, String tfDatabasePath, String jpDbPassword)
static synchronized void setConfigSetting(String moduleName, String settingName, String settingVal)
static void updatedDbSchema(CentralRepository db, CoordinationService.Lock lock)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

Copyright © 2012-2021 Basis Technology. Generated on: Tue Jan 19 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.