Autopsy  4.14.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 
35 public class CentralRepoDbManager {
36 
37  private static final Logger logger = Logger.getLogger(CentralRepoDbManager.class.getName());
38 
39  private static final String CENTRAL_REPO_DB_NAME = "central_repository";
40  private static final String CENTRAL_REPOSITORY_SETTINGS_KEY = "CentralRepository";
41  private static final String DB_SELECTED_PLATFORM_KEY = "db.selectedPlatform";
42  private static final String DISABLED_DUE_TO_FAILURE_KEY = "disabledDueToFailure";
43 
44  private static volatile CentralRepoDbChoice savedChoice = null;
45 
46  private static final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(CentralRepoDbManager.class);
47 
48  private static final Object dbChoiceLock = new Object();
49  private static final Object disabledDueToFailureLock = new Object();
50 
51 
52 
59  return saveDbChoice(choice, true);
60  }
61 
68  public static CentralRepoDbChoice saveDbChoice(CentralRepoDbChoice choice, boolean clearDisabledDueToError) {
69  synchronized(dbChoiceLock) {
70  // clear disabling due to a failure
71  if (clearDisabledDueToError)
73 
74  // change the settings
75  CentralRepoDbChoice newChoice = (choice == null) ? CentralRepoDbChoice.DISABLED : choice;
76  CentralRepoDbChoice oldChoice = savedChoice;
77  savedChoice = newChoice;
78  ModuleSettings.setConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DB_SELECTED_PLATFORM_KEY, newChoice.getSettingKey());
79  propertyChangeSupport.firePropertyChange("savedChoice", oldChoice, newChoice);
80  return newChoice;
81  }
82 
83  }
84 
89  public static boolean isPostgresMultiuserAllowed() {
90  // if multi user mode is not enabled, then this cannot be used
92  return false;
93 
94  // also validate the connection as well
95  PostgresCentralRepoSettings multiUserSettings =
97 
98  return multiUserSettings.testStatus() == DatabaseTestResult.TESTED_OK;
99  }
100 
101 
106  synchronized(dbChoiceLock) {
107  if (savedChoice == null) {
108  String selectedPlatformString = ModuleSettings.getConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DB_SELECTED_PLATFORM_KEY); // NON-NLS
109  savedChoice = fromKey(selectedPlatformString);
110  }
111 
112  return savedChoice;
113  }
114  }
115 
120  public static void disableDueToFailure() {
123  }
124 
131  private static void setDisabledDueToFailure(boolean disabledDueToFailure) {
132  synchronized(disabledDueToFailureLock) {
133  boolean oldValue = isDisabledDueToFailure();
134  ModuleSettings.setConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DISABLED_DUE_TO_FAILURE_KEY, Boolean.toString(disabledDueToFailure));
135  propertyChangeSupport.firePropertyChange("disabledDueToFailure", oldValue, disabledDueToFailure);
136  }
137  }
138 
145  public static boolean isDisabledDueToFailure() {
146  synchronized(disabledDueToFailureLock) {
147  return Boolean.toString(true).equals(ModuleSettings.getConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DISABLED_DUE_TO_FAILURE_KEY));
148  }
149  }
150 
157  public static void addPropertyChangeListener(PropertyChangeListener listener) {
158  propertyChangeSupport.addPropertyChangeListener(listener);
159  }
160 
165  public static void removePropertyChangeListener(PropertyChangeListener listener) {
166  propertyChangeSupport.removePropertyChangeListener(listener);
167  }
168 
169 
170 
171  private static CentralRepoDbChoice fromKey(String keyName) {
172  for (CentralRepoDbChoice dbChoice : CentralRepoDbChoice.values()) {
173  if (dbChoice.getSettingKey().equalsIgnoreCase(keyName)) {
174  return dbChoice;
175  }
176  }
177 
179  }
180 
181 
182 
190  //get connection
191  try {
193  } catch (CentralRepoException ex) {
194  logger.log(Level.SEVERE, "Error updating central repository, unable to make connection", ex);
195  onUpgradeError("Error updating central repository, unable to make connection",
196  Bundle.EamDbUtil_centralRepoConnectionFailed_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
197  }
198 
199  // will never be reached
200  return null;
201  }
202 
211  try {
212  // This may return null if locking isn't supported, which is fine. It will
213  // throw an exception if locking is supported but we can't get the lock
214  // (meaning the database is in use by another user)
215  return db.getExclusiveMultiUserDbLock();
216  //perform upgrade
217  } catch (CentralRepoException ex) {
218  logger.log(Level.SEVERE, "Error updating central repository, unable to acquire exclusive lock", ex);
219  onUpgradeError("Error updating central repository, unable to acquire exclusive lock",
220  Bundle.EamDbUtil_exclusiveLockAquisitionFailure_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
221  }
222 
223  // will never be reached
224  return null;
225  }
226 
235  try {
236  db.upgradeSchema();
237  } catch (CentralRepoException ex) {
238  logger.log(Level.SEVERE, "Error updating central repository", ex);
239  onUpgradeError("Error updating central repository", ex.getUserMessage() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
240  } catch (SQLException ex) {
241  logger.log(Level.SEVERE, "Error updating central repository", ex);
242  onUpgradeError("Error updating central repository",
243  Bundle.EamDbUtil_centralRepoUpgradeFailed_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
244  } catch (IncompatibleCentralRepoException ex) {
245  logger.log(Level.SEVERE, "Error updating central repository", ex);
246  onUpgradeError("Error updating central repository",
247  ex.getMessage() + "\n\n" + Bundle.EamDbUtil_centralRepoUpgradeFailed_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), ex);
248  } finally {
249  if (lock != null) {
250  try {
251  lock.release();
253  logger.log(Level.SEVERE, "Error releasing database lock", ex);
254  }
255  }
256  }
257  }
258 
264  @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."})
265  public static void upgradeDatabase() throws CentralRepoException {
266  if (!CentralRepository.isEnabled()) {
267  return;
268  }
269 
271 
272  //get lock necessary for upgrade
273  if (db != null) {
275  updatedDbSchema(db, lock);
276  } else {
277  onUpgradeError("Unable to connect to database",
278  Bundle.EamDbUtil_centralRepoConnectionFailed_message() + Bundle.EamDbUtil_centralRepoDisabled_message(), null);
279  }
280  }
281 
282  private static void onUpgradeError(String message, String desc, Exception innerException) throws CentralRepoException {
283  // Disable the central repo and clear the current settings.
284  try {
285  if (null != CentralRepository.getInstance()) {
287  }
288  } catch (CentralRepoException ex2) {
289  logger.log(Level.SEVERE, "Error shutting down central repo connection pool", ex2);
290  }
292  if (innerException == null) {
293  throw new CentralRepoException(message, desc);
294  } else {
295  throw new CentralRepoException(message, desc, innerException);
296  }
297  }
298 
299 
300 
303 
307 
308  private boolean configurationChanged = false;
309 
311  selectedDbChoice = getSavedDbChoice();
314  dbSettingsSqlite = new SqliteCentralRepoSettings();
315  }
316 
317 
323  return dbSettingsMultiUser;
324  }
325 
331  return dbSettingsPostgres;
332  }
333 
339  return dbSettingsSqlite;
340  }
341 
347  // change in-memory settings to default sqlite
348  selectedDbChoice = CentralRepoDbChoice.SQLITE;
349  dbSettingsSqlite.setupDefaultSettings();
350 
351  // if db is not present, attempt to create it
352  DatabaseTestResult curStatus = testStatus();
353  if (curStatus == DatabaseTestResult.DB_DOES_NOT_EXIST) {
354  createDb();
355  curStatus = testStatus();
356  }
357 
358  // the only successful setup status is tested ok
359  if (curStatus != DatabaseTestResult.TESTED_OK) {
360  throw new CentralRepoException("Unable to successfully create sqlite database");
361  }
362 
363  // if successfully got here, then save the settings
366  }
367 
375  public boolean wasConfigurationChanged() {
376  return configurationChanged;
377  }
378 
380  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_MULTIUSER)
381  return dbSettingsMultiUser;
382  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM)
383  return dbSettingsPostgres;
384  if (selectedDbChoice == CentralRepoDbChoice.SQLITE)
385  return dbSettingsSqlite;
386  if (selectedDbChoice == CentralRepoDbChoice.DISABLED)
387  return null;
388 
389  throw new CentralRepoException("Unknown database type: " + selectedDbChoice);
390  }
391 
393  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_MULTIUSER)
394  return new RdbmsCentralRepoFactory(CentralRepoPlatforms.POSTGRESQL, dbSettingsMultiUser);
395  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM)
396  return new RdbmsCentralRepoFactory(CentralRepoPlatforms.POSTGRESQL, dbSettingsPostgres);
397  if (selectedDbChoice == CentralRepoDbChoice.SQLITE)
398  return new RdbmsCentralRepoFactory(CentralRepoPlatforms.SQLITE, dbSettingsSqlite);
399  if (selectedDbChoice == CentralRepoDbChoice.DISABLED)
400  return null;
401 
402  throw new CentralRepoException("Unknown database type: " + selectedDbChoice);
403  }
404 
410  public boolean createDb() throws CentralRepoException {
412  if (selectedDbSettings == null)
413  throw new CentralRepoException("Unable to derive connectivity manager from settings: " + selectedDbChoice);
414 
415  boolean result = false;
416  boolean dbCreated = true;
417 
418  if (!selectedDbSettings.verifyDatabaseExists()) {
419  dbCreated = selectedDbSettings.createDatabase();
420  }
421  if (dbCreated) {
422  try {
423  RdbmsCentralRepoFactory centralRepoSchemaFactory = getDbFactory();
424 
425  result = centralRepoSchemaFactory.initializeDatabaseSchema()
426  && centralRepoSchemaFactory.insertDefaultDatabaseContent();
427  } catch (CentralRepoException ex) {
428  logger.log(Level.SEVERE, "Unable to create database for central repository with settings " + selectedDbSettings, ex);
429  throw ex;
430  }
431  }
432  if (!result) {
433  // Remove the incomplete database
434  if (dbCreated) {
435  selectedDbSettings.deleteDatabase();
436  }
437 
438  String schemaError = "Unable to initialize database schema or insert contents into central repository.";
439  logger.severe(schemaError);
440  throw new CentralRepoException(schemaError);
441  }
442 
443  testingStatus = DatabaseTestResult.TESTED_OK;
444  return true;
445  }
446 
450  @NbBundle.Messages({"CentralRepoDbManager.connectionErrorMsg.text=Failed to connect to central repository database."})
460  try {
461  CentralRepository previousDbManager = CentralRepository.getInstance();
462  if (null != previousDbManager) {
463  // NOTE: do not set/save the seleted platform before calling this.
465  }
466  } catch (CentralRepoException ex) {
467  logger.log(Level.SEVERE, "Failed to close database connections in previously selected platform.", ex); // NON-NLS
468  throw ex;
469  }
470 
471  // Even if we fail to close the existing connections, make sure that we
472  // save the new connection settings, so an Autopsy restart will correctly
473  // start with the new settings.
475  saveDbChoice(selectedDbChoice);
476 
478 
479  // save the new settings
480  selectedDbSettings.saveSettings();
481  // Load those newly saved settings into the postgres db manager instance
482  // in case we are still using the same instance.
483  if (selectedDbChoice != null && selectedDbChoice != CentralRepoDbChoice.DISABLED) {
484  try {
485  logger.info("Saving central repo settings for db: " + selectedDbSettings);
487  configurationChanged = true;
488  } catch (CentralRepoException ex) {
489  logger.log(Level.SEVERE, Bundle.CentralRepoDbManager_connectionErrorMsg_text(), ex); //NON-NLS
490  return;
491  }
492  }
493  }
494 
501  return testingStatus;
502  }
503 
510  return selectedDbChoice;
511  }
512 
516  public void clearStatus() {
517  testingStatus = DatabaseTestResult.UNTESTED;
518  }
519 
524  public void setSelctedDbChoice(CentralRepoDbChoice newSelected) {
525  selectedDbChoice = newSelected;
526  testingStatus = DatabaseTestResult.UNTESTED;
527  }
528 
536  String tbDbHostname, String tbDbPort, String tbDbUsername, String tfDatabasePath, String jpDbPassword) throws CentralRepoException, NumberFormatException {
537 
538  if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
539  dbSettingsPostgres.setHost(tbDbHostname);
540  dbSettingsPostgres.setPort(Integer.parseInt(tbDbPort));
541  dbSettingsPostgres.setDbName(CENTRAL_REPO_DB_NAME);
542  dbSettingsPostgres.setUserName(tbDbUsername);
543  dbSettingsPostgres.setPassword(jpDbPassword);
544  }
545  else if (selectedDbChoice == CentralRepoDbChoice.SQLITE) {
546  File databasePath = new File(tfDatabasePath);
548  dbSettingsSqlite.setDbDirectory(databasePath.getPath());
549  }
550  else if (selectedDbChoice != CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
551  throw new IllegalStateException("Central Repo has an unknown selected platform: " + selectedDbChoice);
552  }
553 
554  return true;
555  }
556 
562  try {
564  if (manager != null)
565  testingStatus = manager.testStatus();
566  }
567  catch (CentralRepoException e) {
568  logger.log(Level.WARNING, "unable to test status of db connection in central repo", e);
569  }
570 
571  return testingStatus;
572  }
573 }
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: Wed Apr 8 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.