Autopsy  4.16.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 
393  public boolean wasConfigurationChanged() {
394  return configurationChanged;
395  }
396 
398  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
399  return dbSettingsMultiUser;
400  }
401  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
402  return dbSettingsPostgres;
403  }
404  if (selectedDbChoice == CentralRepoDbChoice.SQLITE) {
405  return dbSettingsSqlite;
406  }
407  if (selectedDbChoice == CentralRepoDbChoice.DISABLED) {
408  return null;
409  }
410 
411  throw new CentralRepoException("Unknown database type: " + selectedDbChoice);
412  }
413 
415  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
416  return new RdbmsCentralRepoFactory(CentralRepoPlatforms.POSTGRESQL, dbSettingsMultiUser);
417  }
418  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
419  return new RdbmsCentralRepoFactory(CentralRepoPlatforms.POSTGRESQL, dbSettingsPostgres);
420  }
421  if (selectedDbChoice == CentralRepoDbChoice.SQLITE) {
422  return new RdbmsCentralRepoFactory(CentralRepoPlatforms.SQLITE, dbSettingsSqlite);
423  }
424  if (selectedDbChoice == CentralRepoDbChoice.DISABLED) {
425  return null;
426  }
427 
428  throw new CentralRepoException("Unknown database type: " + selectedDbChoice);
429  }
430 
438  public boolean createDb() throws CentralRepoException {
440  if (selectedDbSettings == null) {
441  throw new CentralRepoException("Unable to derive connectivity manager from settings: " + selectedDbChoice);
442  }
443 
444  boolean result = false;
445  boolean dbCreated = true;
446 
447  if (!selectedDbSettings.verifyDatabaseExists()) {
448  dbCreated = selectedDbSettings.createDatabase();
449  }
450  if (dbCreated) {
451  try {
452  RdbmsCentralRepoFactory centralRepoSchemaFactory = getDbFactory();
453 
454  result = centralRepoSchemaFactory.initializeDatabaseSchema()
455  && centralRepoSchemaFactory.insertDefaultDatabaseContent();
456  } catch (CentralRepoException ex) {
457  logger.log(Level.SEVERE, "Unable to create database for central repository with settings " + selectedDbSettings, ex);
458  throw ex;
459  }
460  }
461  if (!result) {
462  // Remove the incomplete database
463  if (dbCreated) {
464  selectedDbSettings.deleteDatabase();
465  }
466 
467  String schemaError = "Unable to initialize database schema or insert contents into central repository.";
468  logger.severe(schemaError);
469  throw new CentralRepoException(schemaError);
470  }
471 
472  testingStatus = DatabaseTestResult.TESTED_OK;
473  return true;
474  }
475 
479  @NbBundle.Messages({"CentralRepoDbManager.connectionErrorMsg.text=Failed to connect to central repository database."})
489  try {
490  CentralRepository previousDbManager = CentralRepository.getInstance();
491  if (null != previousDbManager) {
492  // NOTE: do not set/save the seleted platform before calling this.
494  }
495  } catch (CentralRepoException ex) {
496  logger.log(Level.SEVERE, "Failed to close database connections in previously selected platform.", ex); // NON-NLS
497  throw ex;
498  }
499 
500  // Even if we fail to close the existing connections, make sure that we
501  // save the new connection settings, so an Autopsy restart will correctly
502  // start with the new settings.
504  saveDbChoice(selectedDbChoice);
505 
507 
508  // save the new settings
509  selectedDbSettings.saveSettings();
510  // Load those newly saved settings into the postgres db manager instance
511  // in case we are still using the same instance.
512  if (selectedDbChoice != null && selectedDbChoice != CentralRepoDbChoice.DISABLED) {
513  try {
514  logger.info("Saving central repo settings for db: " + selectedDbSettings);
516  configurationChanged = true;
517  } catch (CentralRepoException ex) {
518  logger.log(Level.SEVERE, Bundle.CentralRepoDbManager_connectionErrorMsg_text(), ex); //NON-NLS
519  return;
520  }
521  }
522  }
523 
531  return testingStatus;
532  }
533 
541  return selectedDbChoice;
542  }
543 
547  public void clearStatus() {
548  testingStatus = DatabaseTestResult.UNTESTED;
549  }
550 
557  public void setSelctedDbChoice(CentralRepoDbChoice newSelected) {
558  selectedDbChoice = newSelected;
559  testingStatus = DatabaseTestResult.UNTESTED;
560  }
561 
569  String tbDbHostname, String tbDbPort, String tbDbUsername, String tfDatabasePath, String jpDbPassword) throws CentralRepoException, NumberFormatException {
570 
571  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
572  dbSettingsPostgres.setHost(tbDbHostname);
573  dbSettingsPostgres.setPort(Integer.parseInt(tbDbPort));
574  dbSettingsPostgres.setDbName(CENTRAL_REPO_DB_NAME);
575  dbSettingsPostgres.setUserName(tbDbUsername);
576  dbSettingsPostgres.setPassword(jpDbPassword);
577  } else if (selectedDbChoice == CentralRepoDbChoice.SQLITE) {
578  File databasePath = new File(tfDatabasePath);
580  dbSettingsSqlite.setDbDirectory(databasePath.getPath());
581  } else if (selectedDbChoice != CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
582  throw new IllegalStateException("Central Repo has an unknown selected platform: " + selectedDbChoice);
583  }
584 
585  return true;
586  }
587 
595  try {
597  if (manager != null) {
598  testingStatus = manager.testStatus();
599  }
600  } catch (CentralRepoException e) {
601  logger.log(Level.WARNING, "unable to test status of db connection in central repo", e);
602  }
603 
604  return testingStatus;
605  }
606 }
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-2020 Basis Technology. Generated on: Tue Sep 22 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.