Autopsy  4.19.3
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;
32 
37 public class CentralRepoDbManager {
38 
39  private static final Logger logger = Logger.getLogger(CentralRepoDbManager.class.getName());
40 
41  private static final String CENTRAL_REPO_DB_NAME = "central_repository";
43  private static final String DB_SELECTED_PLATFORM_KEY = "db.selectedPlatform";
44  private static final String DISABLED_DUE_TO_FAILURE_KEY = "disabledDueToFailure";
45 
46  private static volatile CentralRepoDbChoice savedChoice = null;
47 
48  private static final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(CentralRepoDbManager.class);
49 
50  private static final Object dbChoiceLock = new Object();
51  private static final Object disabledDueToFailureLock = new Object();
52 
62  return saveDbChoice(choice, true);
63  }
64 
74  public static CentralRepoDbChoice saveDbChoice(CentralRepoDbChoice choice, boolean clearDisabledDueToError) {
75  synchronized (dbChoiceLock) {
76  // clear disabling due to a failure
77  if (clearDisabledDueToError) {
79  }
80 
81  // change the settings
82  CentralRepoDbChoice newChoice = (choice == null) ? CentralRepoDbChoice.DISABLED : choice;
83  CentralRepoDbChoice oldChoice = savedChoice;
84  savedChoice = newChoice;
85  ModuleSettings.setConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DB_SELECTED_PLATFORM_KEY, newChoice.getSettingKey());
86  propertyChangeSupport.firePropertyChange("savedChoice", oldChoice, newChoice);
87  return newChoice;
88  }
89 
90  }
91 
98  public static boolean isPostgresMultiuserAllowed() {
99  // if multi user mode is not enabled, then this cannot be used
101  return false;
102  }
103  // also validate the connection as well
104  PostgresCentralRepoSettings multiUserSettings
106 
107  return multiUserSettings.testStatus() == DatabaseTestResult.TESTED_OK;
108  }
109 
115  synchronized (dbChoiceLock) {
116  if (savedChoice == null) {
117  String selectedPlatformString = ModuleSettings.getConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DB_SELECTED_PLATFORM_KEY); // NON-NLS
118  savedChoice = fromKey(selectedPlatformString);
119  }
120 
121  return savedChoice;
122  }
123  }
124 
131  public static void disableDueToFailure() {
134  }
135 
144  private static void setDisabledDueToFailure(boolean disabledDueToFailure) {
145  synchronized (disabledDueToFailureLock) {
146  boolean oldValue = isDisabledDueToFailure();
147  ModuleSettings.setConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DISABLED_DUE_TO_FAILURE_KEY, Boolean.toString(disabledDueToFailure));
148  propertyChangeSupport.firePropertyChange("disabledDueToFailure", oldValue, disabledDueToFailure);
149  }
150  }
151 
160  public static boolean isDisabledDueToFailure() {
161  synchronized (disabledDueToFailureLock) {
162  return Boolean.toString(true).equals(ModuleSettings.getConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DISABLED_DUE_TO_FAILURE_KEY));
163  }
164  }
165 
173  public static void addPropertyChangeListener(PropertyChangeListener listener) {
174  propertyChangeSupport.addPropertyChangeListener(listener);
175  }
176 
182  public static void removePropertyChangeListener(PropertyChangeListener listener) {
183  propertyChangeSupport.removePropertyChangeListener(listener);
184  }
185 
186  private static CentralRepoDbChoice fromKey(String keyName) {
187  for (CentralRepoDbChoice dbChoice : CentralRepoDbChoice.values()) {
188  if (dbChoice.getSettingKey().equalsIgnoreCase(keyName)) {
189  return dbChoice;
190  }
191  }
192 
194  }
195 
204  //get connection
205  try {
207  } catch (CentralRepoException ex) {
208  logger.log(Level.SEVERE, "Error updating central repository, unable to make connection", ex);
209  onUpgradeError("Error updating central repository, unable to make connection",
210  Bundle.EamDbUtil_centralRepoConnectionFailed_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
211  }
212 
213  // will never be reached
214  return null;
215  }
216 
227  try {
228  // This may return null if locking isn't supported, which is fine. It will
229  // throw an exception if locking is supported but we can't get the lock
230  // (meaning the database is in use by another user)
231  return db.getExclusiveMultiUserDbLock();
232  //perform upgrade
233  } catch (CentralRepoException ex) {
234  logger.log(Level.SEVERE, "Error updating central repository, unable to acquire exclusive lock", ex);
235  onUpgradeError("Error updating central repository, unable to acquire exclusive lock",
236  Bundle.EamDbUtil_exclusiveLockAquisitionFailure_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
237  }
238 
239  // will never be reached
240  return null;
241  }
242 
252  try {
253  db.upgradeSchema();
254  } catch (CentralRepoException ex) {
255  logger.log(Level.SEVERE, "Error updating central repository", ex);
256  onUpgradeError("Error updating central repository", ex.getUserMessage() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
257  } catch (SQLException ex) {
258  logger.log(Level.SEVERE, "Error updating central repository", ex);
259  onUpgradeError("Error updating central repository",
260  Bundle.EamDbUtil_centralRepoUpgradeFailed_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
261  } catch (IncompatibleCentralRepoException ex) {
262  logger.log(Level.SEVERE, "Error updating central repository", ex);
263  onUpgradeError("Error updating central repository",
264  ex.getMessage() + "\n\n" + Bundle.EamDbUtil_centralRepoUpgradeFailed_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
265  } finally {
266  if (lock != null) {
267  try {
268  lock.release();
270  logger.log(Level.SEVERE, "Error releasing database lock", ex);
271  }
272  }
273  }
274  }
275 
281  @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."})
282  public static void upgradeDatabase() throws CentralRepoException {
283  if (!CentralRepository.isEnabled()) {
284  return;
285  }
286 
288 
289  //get lock necessary for upgrade
290  if (db != null) {
292  updatedDbSchema(db, lock);
293  } else {
294  onUpgradeError("Unable to connect to database",
295  Bundle.EamDbUtil_centralRepoConnectionFailed_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), null);
296  }
297  }
298 
299  private static void onUpgradeError(String message, String desc, Exception innerException) throws CentralRepoException {
300  // Disable the central repo and clear the current settings.
301  try {
302  if (null != CentralRepository.getInstance()) {
304  }
305  } catch (CentralRepoException ex2) {
306  logger.log(Level.SEVERE, "Error shutting down central repo connection pool", ex2);
307  }
309  if (innerException == null) {
310  throw new CentralRepoException(message, desc);
311  } else {
312  throw new CentralRepoException(message, desc, innerException);
313  }
314  }
315 
318 
322 
323  private boolean configurationChanged = false;
324 
326  selectedDbChoice = getSavedDbChoice();
329  dbSettingsSqlite = new SqliteCentralRepoSettings();
330  }
331 
338  return dbSettingsMultiUser;
339  }
340 
347  return dbSettingsPostgres;
348  }
349 
357  return dbSettingsSqlite;
358  }
359 
366  // change in-memory settings to default sqlite
367  selectedDbChoice = CentralRepoDbChoice.SQLITE;
368  dbSettingsSqlite.setupDefaultSettings();
369 
370  // if db is not present, attempt to create it
371  DatabaseTestResult curStatus = testStatus();
372  if (curStatus == DatabaseTestResult.DB_DOES_NOT_EXIST) {
373  createDb();
374  curStatus = testStatus();
375  }
376 
377  // the only successful setup status is tested ok
378  if (curStatus != DatabaseTestResult.TESTED_OK) {
379  throw new CentralRepoException("Unable to successfully create sqlite database");
380  }
381 
382  // if successfully got here, then save the settings
385  }
386 
395  selectedDbChoice = choice;
396  DatabaseTestResult curStatus = testStatus();
397  if (curStatus == DatabaseTestResult.DB_DOES_NOT_EXIST) {
398  createDb();
399  curStatus = testStatus();
400  }
401 
402  // the only successful setup status is tested ok
403  if (curStatus != DatabaseTestResult.TESTED_OK) {
404  throw new CentralRepoException("Unable to successfully create postgres database. Test failed with: " + curStatus);
405  }
406 
407  // if successfully got here, then save the settings
410  }
411 
419  public boolean wasConfigurationChanged() {
420  return configurationChanged;
421  }
422 
424  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
425  return dbSettingsMultiUser;
426  }
427  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
428  return dbSettingsPostgres;
429  }
430  if (selectedDbChoice == CentralRepoDbChoice.SQLITE) {
431  return dbSettingsSqlite;
432  }
433  if (selectedDbChoice == CentralRepoDbChoice.DISABLED) {
434  return null;
435  }
436 
437  throw new CentralRepoException("Unknown database type: " + selectedDbChoice);
438  }
439 
441  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
442  return new RdbmsCentralRepoFactory(CentralRepoPlatforms.POSTGRESQL, dbSettingsMultiUser);
443  }
444  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
445  return new RdbmsCentralRepoFactory(CentralRepoPlatforms.POSTGRESQL, dbSettingsPostgres);
446  }
447  if (selectedDbChoice == CentralRepoDbChoice.SQLITE) {
448  return new RdbmsCentralRepoFactory(CentralRepoPlatforms.SQLITE, dbSettingsSqlite);
449  }
450  if (selectedDbChoice == CentralRepoDbChoice.DISABLED) {
451  return null;
452  }
453 
454  throw new CentralRepoException("Unknown database type: " + selectedDbChoice);
455  }
456 
464  public boolean createDb() throws CentralRepoException {
466  if (selectedDbSettings == null) {
467  throw new CentralRepoException("Unable to derive connectivity manager from settings: " + selectedDbChoice);
468  }
469 
470  boolean result = false;
471  boolean dbCreated = true;
472 
473  if (!selectedDbSettings.verifyDatabaseExists()) {
474  dbCreated = selectedDbSettings.createDatabase();
475  }
476  if (dbCreated) {
477  try {
478  RdbmsCentralRepoFactory centralRepoSchemaFactory = getDbFactory();
479 
480  result = centralRepoSchemaFactory.initializeDatabaseSchema()
481  && centralRepoSchemaFactory.insertDefaultDatabaseContent();
482  } catch (CentralRepoException ex) {
483  logger.log(Level.SEVERE, "Unable to create database for central repository with settings " + selectedDbSettings, ex);
484  throw ex;
485  }
486  }
487  if (!result) {
488  // Remove the incomplete database
489  if (dbCreated) {
490  selectedDbSettings.deleteDatabase();
491  }
492 
493  String schemaError = "Unable to initialize database schema or insert contents into central repository.";
494  logger.severe(schemaError);
495  throw new CentralRepoException(schemaError);
496  }
497 
498  testingStatus = DatabaseTestResult.TESTED_OK;
499  return true;
500  }
501 
505  @NbBundle.Messages({"CentralRepoDbManager.connectionErrorMsg.text=Failed to connect to central repository database."})
515  try {
516  CentralRepository previousDbManager = CentralRepository.getInstance();
517  if (null != previousDbManager) {
518  // NOTE: do not set/save the seleted platform before calling this.
520  }
521  } catch (CentralRepoException ex) {
522  logger.log(Level.SEVERE, "Failed to close database connections in previously selected platform.", ex); // NON-NLS
523  throw ex;
524  }
525 
526  // Even if we fail to close the existing connections, make sure that we
527  // save the new connection settings, so an Autopsy restart will correctly
528  // start with the new settings.
530  saveDbChoice(selectedDbChoice);
531 
533 
534  // save the new settings
535  selectedDbSettings.saveSettings();
536  // Load those newly saved settings into the postgres db manager instance
537  // in case we are still using the same instance.
538  if (selectedDbChoice != null && selectedDbChoice != CentralRepoDbChoice.DISABLED) {
539  try {
540  logger.info("Saving central repo settings for db: " + selectedDbSettings);
542  configurationChanged = true;
543  } catch (CentralRepoException ex) {
544  logger.log(Level.SEVERE, Bundle.CentralRepoDbManager_connectionErrorMsg_text(), ex); //NON-NLS
545  return;
546  }
547  }
548  }
549 
557  return testingStatus;
558  }
559 
567  return selectedDbChoice;
568  }
569 
573  public void clearStatus() {
574  testingStatus = DatabaseTestResult.UNTESTED;
575  }
576 
583  public void setSelctedDbChoice(CentralRepoDbChoice newSelected) {
584  selectedDbChoice = newSelected;
585  testingStatus = DatabaseTestResult.UNTESTED;
586  }
587 
595  String tbDbHostname, String tbDbPort, String tbDbUsername, String tfDatabasePath, String jpDbPassword) throws CentralRepoException, NumberFormatException {
596 
597  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
598  dbSettingsPostgres.setHost(tbDbHostname);
599  dbSettingsPostgres.setPort(Integer.parseInt(tbDbPort));
600  dbSettingsPostgres.setDbName(CENTRAL_REPO_DB_NAME);
601  dbSettingsPostgres.setUserName(tbDbUsername);
602  dbSettingsPostgres.setPassword(jpDbPassword);
603  } else if (selectedDbChoice == CentralRepoDbChoice.SQLITE) {
604  File databasePath = new File(tfDatabasePath);
606  dbSettingsSqlite.setDbDirectory(databasePath.getPath());
607  } else if (selectedDbChoice != CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
608  throw new IllegalStateException("Central Repo has an unknown selected platform: " + selectedDbChoice);
609  }
610 
611  return true;
612  }
613 
621  try {
623  if (manager != null) {
624  testingStatus = manager.testStatus();
625  }
626  } catch (CentralRepoException e) {
627  logger.log(Level.WARNING, "unable to test status of db connection in central repo", e);
628  }
629 
630  return testingStatus;
631  }
632 }
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-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.