Autopsy  4.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
HashDbManager.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011 - 2014 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.modules.hashdatabase;
20 
21 import java.beans.PropertyChangeEvent;
22 import java.io.File;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Set;
28 import javax.swing.JFileChooser;
29 import javax.swing.filechooser.FileNameExtensionFilter;
30 import javax.xml.parsers.DocumentBuilder;
31 import javax.xml.parsers.DocumentBuilderFactory;
32 import javax.xml.parsers.ParserConfigurationException;
33 import org.openide.util.NbBundle;
36 import org.w3c.dom.Document;
37 import org.w3c.dom.Element;
38 import org.w3c.dom.NodeList;
39 import java.beans.PropertyChangeListener;
40 import java.beans.PropertyChangeSupport;
41 import java.util.concurrent.ExecutionException;
42 import java.util.logging.Level;
43 import javax.swing.JOptionPane;
44 import javax.swing.SwingWorker;
45 import org.apache.commons.io.FilenameUtils;
46 import org.apache.commons.io.FileUtils;
47 import org.netbeans.api.progress.ProgressHandle;
48 import org.netbeans.api.progress.ProgressHandleFactory;
50 import org.sleuthkit.datamodel.AbstractFile;
51 import org.sleuthkit.datamodel.Content;
52 import org.sleuthkit.datamodel.HashHitInfo;
53 import org.sleuthkit.datamodel.HashEntry;
54 import org.sleuthkit.datamodel.SleuthkitJNI;
55 import org.sleuthkit.datamodel.TskCoreException;
57 
59 
64 public class HashDbManager implements PropertyChangeListener {
65 
66  private static final String ROOT_ELEMENT = "hash_sets"; //NON-NLS
67  private static final String SET_ELEMENT = "hash_set"; //NON-NLS
68  private static final String SET_NAME_ATTRIBUTE = "name"; //NON-NLS
69  private static final String SET_TYPE_ATTRIBUTE = "type"; //NON-NLS
70  private static final String SEARCH_DURING_INGEST_ATTRIBUTE = "use_for_ingest"; //NON-NLS
71  private static final String SEND_INGEST_MESSAGES_ATTRIBUTE = "show_inbox_messages"; //NON-NLS
72  private static final String PATH_ELEMENT = "hash_set_path"; //NON-NLS
73  private static final String LEGACY_PATH_NUMBER_ATTRIBUTE = "number"; //NON-NLS
74  private static final String CONFIG_FILE_NAME = "hashsets.xml"; //NON-NLS
75  private static final String XSD_FILE_NAME = "HashsetsSchema.xsd"; //NON-NLS
76  private static final String ENCODING = "UTF-8"; //NON-NLS
77  private static final String HASH_DATABASE_FILE_EXTENSON = "kdb"; //NON-NLS
78  private static HashDbManager instance = null;
79  private final String configFilePath = PlatformUtil.getUserConfigDirectory() + File.separator + CONFIG_FILE_NAME;
80  private List<HashDb> knownHashSets = new ArrayList<>();
81  private List<HashDb> knownBadHashSets = new ArrayList<>();
82  private Set<String> hashSetNames = new HashSet<>();
83  private Set<String> hashSetPaths = new HashSet<>();
84  PropertyChangeSupport changeSupport = new PropertyChangeSupport(HashDbManager.class);
85  private static final Logger logger = Logger.getLogger(HashDbManager.class.getName());
86 
92  public enum SetEvt {
93 
94  DB_ADDED, DB_DELETED, DB_INDEXED
95  };
96 
100  public static synchronized HashDbManager getInstance() {
101  if (instance == null) {
102  instance = new HashDbManager();
103  }
104  return instance;
105  }
106 
107  public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
108  changeSupport.addPropertyChangeListener(listener);
109  }
110 
111  private HashDbManager() {
114  }
115  }
116 
122  static String getHashDatabaseFileExtension() {
124  }
125 
126  public class HashDbManagerException extends Exception {
127 
128  private HashDbManagerException(String message) {
129  super(message);
130  }
131  }
132 
152  public HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException {
153  HashDb hashDb = null;
154  try {
155  addExistingHashDatabaseInternal(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType);
156  } catch (TskCoreException ex) {
157  throw new HashDbManagerException(ex.getMessage());
158  }
159 
160  // Save the configuration
161  if (!save()) {
162  throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.saveErrorExceptionMsg"));
163  }
164 
165  return hashDb;
166  }
167 
189  synchronized HashDb addExistingHashDatabaseInternal(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException, TskCoreException {
190  if (!new File(path).exists()) {
191  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.hashDbDoesNotExistExceptionMsg", path));
192  }
193 
194  if (hashSetPaths.contains(path)) {
195  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.hashDbAlreadyAddedExceptionMsg", path));
196  }
197 
198  if (hashSetNames.contains(hashSetName)) {
199  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName));
200  }
201 
202  return addHashDatabase(SleuthkitJNI.openHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
203  }
204 
223  public HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages,
224  HashDb.KnownFilesType knownFilesType) throws HashDbManagerException {
225 
226  HashDb hashDb = null;
227  try {
228  hashDb = addNewHashDatabaseInternal(hashSetName, path, searchDuringIngest, sendIngestMessages, knownFilesType);
229  } catch (TskCoreException ex) {
230  throw new HashDbManagerException(ex.getMessage());
231  }
232 
233  // Save the configuration
234  if (!save()) {
235  throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.saveErrorExceptionMsg"));
236  }
237 
238  return hashDb;
239  }
240 
261  synchronized HashDb addNewHashDatabaseInternal(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws HashDbManagerException, TskCoreException {
262  File file = new File(path);
263  if (file.exists()) {
264  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.hashDbFileExistsExceptionMsg", path));
265  }
266  if (!FilenameUtils.getExtension(file.getName()).equalsIgnoreCase(HASH_DATABASE_FILE_EXTENSON)) {
267  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.illegalHashDbFileNameExtensionMsg",
268  getHashDatabaseFileExtension()));
269  }
270 
271  if (hashSetPaths.contains(path)) {
272  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.hashDbAlreadyAddedExceptionMsg", path));
273  }
274 
275  if (hashSetNames.contains(hashSetName)) {
276  throw new HashDbManagerException(NbBundle.getMessage(HashDbManager.class, "HashDbManager.duplicateHashSetNameExceptionMsg", hashSetName));
277  }
278 
279  return addHashDatabase(SleuthkitJNI.createHashDatabase(path), hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
280  }
281 
282  private HashDb addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType) throws TskCoreException {
283  // Wrap an object around the handle.
284  HashDb hashDb = new HashDb(handle, hashSetName, searchDuringIngest, sendIngestMessages, knownFilesType);
285 
286  // Get the indentity data before updating the collections since the
287  // accessor methods may throw.
288  String databasePath = hashDb.getDatabasePath();
289  String indexPath = hashDb.getIndexPath();
290 
291  // Update the collections used to ensure that hash set names are unique
292  // and the same database is not added to the configuration more than once.
293  hashSetNames.add(hashDb.getHashSetName());
294  if (!databasePath.equals("None")) { //NON-NLS
295  hashSetPaths.add(databasePath);
296  }
297  if (!indexPath.equals("None")) { //NON-NLS
298  hashSetPaths.add(indexPath);
299  }
300 
301  // Add the hash database to the appropriate collection for its type.
302  if (hashDb.getKnownFilesType() == HashDb.KnownFilesType.KNOWN) {
303  knownHashSets.add(hashDb);
304  } else {
305  knownBadHashSets.add(hashDb);
306  }
307 
308  // Let any external listeners know that there's a new set
309  try {
310  changeSupport.firePropertyChange(SetEvt.DB_ADDED.toString(), null, hashSetName);
311  } catch (Exception e) {
312  logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS
314  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErr"),
315  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErrorListeningToUpdatesMsg"),
317  }
318  return hashDb;
319  }
320 
321  synchronized void indexHashDatabase(HashDb hashDb) {
322  hashDb.addPropertyChangeListener(this);
323  HashDbIndexer creator = new HashDbIndexer(hashDb);
324  creator.execute();
325  }
326 
327  @Override
328  public void propertyChange(PropertyChangeEvent event) {
329  if (event.getPropertyName().equals(HashDb.Event.INDEXING_DONE.name())) {
330  HashDb hashDb = (HashDb) event.getNewValue();
331  if (null != hashDb) {
332  try {
333  String indexPath = hashDb.getIndexPath();
334  if (!indexPath.equals("None")) { //NON-NLS
335  hashSetPaths.add(indexPath);
336  }
337  } catch (TskCoreException ex) {
338  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDb.getHashSetName() + " hash database after indexing", ex); //NON-NLS
339  }
340  }
341  }
342  }
343 
352  public synchronized void removeHashDatabase(HashDb hashDb) throws HashDbManagerException {
353  // Don't remove a database if ingest is running
354  boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning();
355  if (ingestIsRunning) {
356  throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.ingestRunningExceptionMsg"));
357  }
358  removeHashDatabaseInternal(hashDb);
359  if (!save()) {
360  throw new HashDbManagerException(NbBundle.getMessage(this.getClass(), "HashDbManager.saveErrorExceptionMsg"));
361  }
362  }
363 
372  synchronized void removeHashDatabaseInternal(HashDb hashDb) {
373  // Remove the database from whichever hash set list it occupies,
374  // and remove its hash set name from the hash set used to ensure unique
375  // hash set names are used, before undertaking These operations will succeed and constitute
376  // a mostly effective removal, even if the subsequent operations fail.
377  String hashSetName = hashDb.getHashSetName();
378  knownHashSets.remove(hashDb);
379  knownBadHashSets.remove(hashDb);
380  hashSetNames.remove(hashSetName);
381 
382  // Now undertake the operations that could throw.
383  try {
384  hashSetPaths.remove(hashDb.getIndexPath());
385  } catch (TskCoreException ex) {
386  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting index path of " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS
387  }
388  try {
389  if (!hashDb.hasIndexOnly()) {
390  hashSetPaths.remove(hashDb.getDatabasePath());
391  }
392  } catch (TskCoreException ex) {
393  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting database path of " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS
394  }
395  try {
396  hashDb.close();
397  } catch (TskCoreException ex) {
398  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + hashDb.getHashSetName() + " hash database when removing the database", ex); //NON-NLS
399  }
400 
401  // Let any external listeners know that a set has been deleted
402  try {
403  changeSupport.firePropertyChange(SetEvt.DB_DELETED.toString(), null, hashSetName);
404  } catch (Exception e) {
405  logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS
406  MessageNotifyUtil.Notify.show(
407  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErr"),
408  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErrorListeningToUpdatesMsg"),
409  MessageNotifyUtil.MessageType.ERROR);
410  }
411  }
412 
419  public synchronized List<HashDb> getAllHashSets() {
420  List<HashDb> hashDbs = new ArrayList<>();
421  hashDbs.addAll(knownHashSets);
422  hashDbs.addAll(knownBadHashSets);
423  return hashDbs;
424  }
425 
431  public synchronized List<HashDb> getKnownFileHashSets() {
432  List<HashDb> hashDbs = new ArrayList<>();
433  hashDbs.addAll(knownHashSets);
434  return hashDbs;
435  }
436 
442  public synchronized List<HashDb> getKnownBadFileHashSets() {
443  List<HashDb> hashDbs = new ArrayList<>();
444  hashDbs.addAll(knownBadHashSets);
445  return hashDbs;
446  }
447 
453  public synchronized List<HashDb> getUpdateableHashSets() {
454  List<HashDb> updateableDbs = getUpdateableHashSets(knownHashSets);
455  updateableDbs.addAll(getUpdateableHashSets(knownBadHashSets));
456  return updateableDbs;
457  }
458 
459  private List<HashDb> getUpdateableHashSets(List<HashDb> hashDbs) {
460  ArrayList<HashDb> updateableDbs = new ArrayList<>();
461  for (HashDb db : hashDbs) {
462  try {
463  if (db.isUpdateable()) {
464  updateableDbs.add(db);
465  }
466  } catch (TskCoreException ex) {
467  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error checking updateable status of " + db.getHashSetName() + " hash database", ex); //NON-NLS
468  }
469  }
470  return updateableDbs;
471  }
472 
479  synchronized boolean save() {
481  }
482 
487  public synchronized void loadLastSavedConfiguration() {
488  closeHashDatabases(knownHashSets);
489  closeHashDatabases(knownBadHashSets);
490  hashSetNames.clear();
491  hashSetPaths.clear();
492 
495  }
496  }
497 
498  private void closeHashDatabases(List<HashDb> hashDatabases) {
499  for (HashDb database : hashDatabases) {
500  try {
501  database.close();
502  } catch (TskCoreException ex) {
503  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error closing " + database.getHashSetName() + " hash database", ex); //NON-NLS
504  }
505  }
506  hashDatabases.clear();
507  }
508 
510  boolean success = false;
511  DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
512  try {
513  DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
514  Document doc = docBuilder.newDocument();
515  Element rootEl = doc.createElement(ROOT_ELEMENT);
516  doc.appendChild(rootEl);
517 
518  writeHashDbsToDisk(doc, rootEl, knownHashSets);
519  writeHashDbsToDisk(doc, rootEl, knownBadHashSets);
520 
521  success = XMLUtil.saveDoc(HashDbManager.class, configFilePath, ENCODING, doc);
522  } catch (ParserConfigurationException ex) {
523  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error saving hash databases", ex); //NON-NLS
524  }
525  return success;
526  }
527 
528  private static void writeHashDbsToDisk(Document doc, Element rootEl, List<HashDb> hashDbs) {
529  for (HashDb db : hashDbs) {
530  // Get the path for the hash database before writing anything, in
531  // case an exception is thrown.
532  String path;
533  try {
534  if (db.hasIndexOnly()) {
535  path = db.getIndexPath();
536  } else {
537  path = db.getDatabasePath();
538  }
539  } catch (TskCoreException ex) {
540  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error getting path of hash database " + db.getHashSetName() + ", discarding from hash database configuration", ex); //NON-NLS
541  continue;
542  }
543 
544  Element setElement = doc.createElement(SET_ELEMENT);
545  setElement.setAttribute(SET_NAME_ATTRIBUTE, db.getHashSetName());
546  setElement.setAttribute(SET_TYPE_ATTRIBUTE, db.getKnownFilesType().toString());
547  setElement.setAttribute(SEARCH_DURING_INGEST_ATTRIBUTE, Boolean.toString(db.getSearchDuringIngest()));
548  setElement.setAttribute(SEND_INGEST_MESSAGES_ATTRIBUTE, Boolean.toString(db.getSendIngestMessages()));
549  Element pathElement = doc.createElement(PATH_ELEMENT);
550  pathElement.setTextContent(path);
551  setElement.appendChild(pathElement);
552  rootEl.appendChild(setElement);
553  }
554  }
555 
557  File f = new File(configFilePath);
558  return f.exists() && f.canRead() && f.canWrite();
559  }
560 
562  boolean updatedSchema = false;
563 
564  // Open the XML document that implements the configuration file.
565  final Document doc = XMLUtil.loadDoc(HashDbManager.class, configFilePath);
566  if (doc == null) {
567  return false;
568  }
569 
570  // Get the root element.
571  Element root = doc.getDocumentElement();
572  if (root == null) {
573  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error loading hash sets: invalid file format."); //NON-NLS
574  return false;
575  }
576 
577  // Get the hash set elements.
578  NodeList setsNList = root.getElementsByTagName(SET_ELEMENT);
579  int numSets = setsNList.getLength();
580  if (numSets == 0) {
581  Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, "No element hash_set exists."); //NON-NLS
582  }
583 
584  // Create HashDb objects for each hash set element. Skip to the next hash database if the definition of
585  // a particular hash database is not well-formed.
586  String attributeErrorMessage = " attribute was not set for hash_set at index {0}, cannot make instance of HashDb class"; //NON-NLS
587  String elementErrorMessage = " element was not set for hash_set at index {0}, cannot make instance of HashDb class"; //NON-NLS
588  for (int i = 0; i < numSets; ++i) {
589  Element setEl = (Element) setsNList.item(i);
590 
591  String hashSetName = setEl.getAttribute(SET_NAME_ATTRIBUTE);
592  if (hashSetName.isEmpty()) {
593  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, SET_NAME_ATTRIBUTE + attributeErrorMessage, i);
594  continue;
595  }
596 
597  // Handle configurations saved before duplicate hash set names were not permitted.
598  if (hashSetNames.contains(hashSetName)) {
599  int suffix = 0;
600  String newHashSetName;
601  do {
602  ++suffix;
603  newHashSetName = hashSetName + suffix;
604  } while (hashSetNames.contains(newHashSetName));
605  JOptionPane.showMessageDialog(null,
606  NbBundle.getMessage(this.getClass(),
607  "HashDbManager.replacingDuplicateHashsetNameMsg",
608  hashSetName, newHashSetName),
609  NbBundle.getMessage(this.getClass(), "HashDbManager.openHashDbErr"),
610  JOptionPane.ERROR_MESSAGE);
611  hashSetName = newHashSetName;
612  }
613 
614  String knownFilesType = setEl.getAttribute(SET_TYPE_ATTRIBUTE);
615  if (knownFilesType.isEmpty()) {
616  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, SET_TYPE_ATTRIBUTE + attributeErrorMessage, i);
617  continue;
618  }
619 
620  // Handle legacy known files types.
621  if (knownFilesType.equals("NSRL")) { //NON-NLS
622  knownFilesType = HashDb.KnownFilesType.KNOWN.toString();
623  updatedSchema = true;
624  }
625 
626  final String searchDuringIngest = setEl.getAttribute(SEARCH_DURING_INGEST_ATTRIBUTE);
627  if (searchDuringIngest.isEmpty()) {
628  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, SEARCH_DURING_INGEST_ATTRIBUTE + attributeErrorMessage, i);
629  continue;
630  }
631  Boolean seearchDuringIngestFlag = Boolean.parseBoolean(searchDuringIngest);
632 
633  final String sendIngestMessages = setEl.getAttribute(SEND_INGEST_MESSAGES_ATTRIBUTE);
634  if (searchDuringIngest.isEmpty()) {
635  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, SEND_INGEST_MESSAGES_ATTRIBUTE + attributeErrorMessage, i);
636  continue;
637  }
638  Boolean sendIngestMessagesFlag = Boolean.parseBoolean(sendIngestMessages);
639 
640  String dbPath;
641  NodeList pathsNList = setEl.getElementsByTagName(PATH_ELEMENT);
642  if (pathsNList.getLength() > 0) {
643  Element pathEl = (Element) pathsNList.item(0); // Shouldn't be more than one.
644 
645  // Check for legacy path number attribute.
646  String legacyPathNumber = pathEl.getAttribute(LEGACY_PATH_NUMBER_ATTRIBUTE);
647  if (null != legacyPathNumber && !legacyPathNumber.isEmpty()) {
648  updatedSchema = true;
649  }
650 
651  dbPath = pathEl.getTextContent();
652  if (dbPath.isEmpty()) {
653  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, PATH_ELEMENT + elementErrorMessage, i);
654  continue;
655  }
656  } else {
657  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, PATH_ELEMENT + elementErrorMessage, i);
658  continue;
659  }
660  dbPath = getValidFilePath(hashSetName, dbPath);
661 
662  if (null != dbPath) {
663  try {
664  addExistingHashDatabaseInternal(hashSetName, dbPath, seearchDuringIngestFlag, sendIngestMessagesFlag, HashDb.KnownFilesType.valueOf(knownFilesType));
665  } catch (HashDbManagerException | TskCoreException ex) {
666  Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); //NON-NLS
667  JOptionPane.showMessageDialog(null,
668  NbBundle.getMessage(this.getClass(),
669  "HashDbManager.unableToOpenHashDbMsg", dbPath),
670  NbBundle.getMessage(this.getClass(), "HashDbManager.openHashDbErr"),
671  JOptionPane.ERROR_MESSAGE);
672  }
673  } else {
674  Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, "No valid path for hash_set at index {0}, cannot make instance of HashDb class", i); //NON-NLS
675  }
676  }
677 
678  if (updatedSchema) {
679  String backupFilePath = configFilePath + ".v1_backup"; //NON-NLS
680  String messageBoxTitle = NbBundle.getMessage(this.getClass(),
681  "HashDbManager.msgBoxTitle.confFileFmtChanged");
682  String baseMessage = NbBundle.getMessage(this.getClass(),
683  "HashDbManager.baseMessage.updatedFormatHashDbConfig");
684  try {
685  FileUtils.copyFile(new File(configFilePath), new File(backupFilePath));
686  JOptionPane.showMessageDialog(null,
687  NbBundle.getMessage(this.getClass(),
688  "HashDbManager.savedBackupOfOldConfigMsg",
689  baseMessage, backupFilePath),
690  messageBoxTitle,
691  JOptionPane.INFORMATION_MESSAGE);
692  } catch (IOException ex) {
693  Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, "Failed to save backup of old format configuration file to " + backupFilePath, ex); //NON-NLS
694  JOptionPane.showMessageDialog(null, baseMessage, messageBoxTitle, JOptionPane.INFORMATION_MESSAGE);
695  }
696 
698  }
699 
700  return true;
701  }
702 
703  private String getValidFilePath(String hashSetName, String configuredPath) {
704  // Check the configured path.
705  File database = new File(configuredPath);
706  if (database.exists()) {
707  return configuredPath;
708  }
709 
710  // Give the user an opportunity to find the desired file.
711  String newPath = null;
712  if (JOptionPane.showConfirmDialog(null,
713  NbBundle.getMessage(this.getClass(), "HashDbManager.dlgMsg.dbNotFoundAtLoc",
714  hashSetName, configuredPath),
715  NbBundle.getMessage(this.getClass(), "HashDbManager.dlgTitle.MissingDb"),
716  JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
717  newPath = searchForFile();
718  if (null != newPath && !newPath.isEmpty()) {
719  database = new File(newPath);
720  if (!database.exists()) {
721  newPath = null;
722  }
723  }
724  }
725  return newPath;
726  }
727 
728  private String searchForFile() {
729  String filePath = null;
730  JFileChooser fc = new JFileChooser();
731  fc.setDragEnabled(false);
732  fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
733  String[] EXTENSION = new String[]{"txt", "idx", "hash", "Hash", "kdb"}; //NON-NLS
734  FileNameExtensionFilter filter = new FileNameExtensionFilter(
735  NbBundle.getMessage(this.getClass(), "HashDbManager.fileNameExtensionFilter.title"), EXTENSION);
736  fc.setFileFilter(filter);
737  fc.setMultiSelectionEnabled(false);
738  if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
739  File f = fc.getSelectedFile();
740  try {
741  filePath = f.getCanonicalPath();
742  } catch (IOException ex) {
743  Logger.getLogger(HashDbManager.class.getName()).log(Level.WARNING, "Couldn't get selected file path", ex); //NON-NLS
744  }
745  }
746  return filePath;
747  }
748 
753  public static class HashDb {
754 
759  public enum KnownFilesType {
760 
761  KNOWN(NbBundle.getMessage(HashDbManager.class, "HashDbManager.known.text")),
762  KNOWN_BAD(NbBundle.getMessage(HashDbManager.class, "HashDbManager.knownBad.text"));
763  private String displayName;
764 
765  private KnownFilesType(String displayName) {
766  this.displayName = displayName;
767  }
768 
769  public String getDisplayName() {
770  return this.displayName;
771  }
772  }
773 
777  public enum Event {
778 
779  INDEXING_DONE
780  }
781  private int handle;
782  private String hashSetName;
783  private boolean searchDuringIngest;
784  private boolean sendIngestMessages;
786  private boolean indexing;
787  private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
788 
789  private HashDb(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) {
790  this.handle = handle;
791  this.hashSetName = hashSetName;
792  this.searchDuringIngest = useForIngest;
793  this.sendIngestMessages = sendHitMessages;
794  this.knownFilesType = knownFilesType;
795  this.indexing = false;
796  }
797 
801  public void addPropertyChangeListener(PropertyChangeListener pcl) {
802  propertyChangeSupport.addPropertyChangeListener(pcl);
803  }
804 
808  public void removePropertyChangeListener(PropertyChangeListener pcl) {
809  propertyChangeSupport.removePropertyChangeListener(pcl);
810  }
811 
812  public String getHashSetName() {
813  return hashSetName;
814  }
815 
816  public String getDatabasePath() throws TskCoreException {
817  return SleuthkitJNI.getHashDatabasePath(handle);
818  }
819 
820  public String getIndexPath() throws TskCoreException {
821  return SleuthkitJNI.getHashDatabaseIndexPath(handle);
822  }
823 
825  return knownFilesType;
826  }
827 
828  public boolean getSearchDuringIngest() {
829  return searchDuringIngest;
830  }
831 
832  void setSearchDuringIngest(boolean useForIngest) {
833  this.searchDuringIngest = useForIngest;
834  }
835 
836  public boolean getSendIngestMessages() {
837  return sendIngestMessages;
838  }
839 
840  void setSendIngestMessages(boolean showInboxMessages) {
841  this.sendIngestMessages = showInboxMessages;
842  }
843 
849  public boolean isUpdateable() throws TskCoreException {
850  return SleuthkitJNI.isUpdateableHashDatabase(this.handle);
851  }
852 
861  public void addHashes(Content content) throws TskCoreException {
862  addHashes(content, null);
863  }
864 
875  public void addHashes(Content content, String comment) throws TskCoreException {
876  // This only works for AbstractFiles and MD5 hashes at present.
877  assert content instanceof AbstractFile;
878  if (content instanceof AbstractFile) {
879  AbstractFile file = (AbstractFile) content;
880  if (null != file.getMd5Hash()) {
881  SleuthkitJNI.addToHashDatabase(null, file.getMd5Hash(), null, null, comment, handle);
882  }
883  }
884  }
885 
893  public void addHashes(List<HashEntry> hashes) throws TskCoreException {
894  SleuthkitJNI.addToHashDatabase(hashes, handle);
895  }
896 
906  public boolean lookupMD5Quick(Content content) throws TskCoreException {
907  boolean result = false;
908  assert content instanceof AbstractFile;
909  if (content instanceof AbstractFile) {
910  AbstractFile file = (AbstractFile) content;
911  if (null != file.getMd5Hash()) {
912  result = SleuthkitJNI.lookupInHashDatabase(file.getMd5Hash(), handle);
913  }
914  }
915  return result;
916  }
917 
927  public HashHitInfo lookupMD5(Content content) throws TskCoreException {
928  HashHitInfo result = null;
929  // This only works for AbstractFiles and MD5 hashes at present.
930  assert content instanceof AbstractFile;
931  if (content instanceof AbstractFile) {
932  AbstractFile file = (AbstractFile) content;
933  if (null != file.getMd5Hash()) {
934  result = SleuthkitJNI.lookupInHashDatabaseVerbose(file.getMd5Hash(), handle);
935  }
936  }
937  return result;
938  }
939 
940  boolean hasIndex() throws TskCoreException {
941  return SleuthkitJNI.hashDatabaseHasLookupIndex(handle);
942  }
943 
944  boolean hasIndexOnly() throws TskCoreException {
945  return SleuthkitJNI.hashDatabaseIsIndexOnly(handle);
946  }
947 
948  boolean canBeReIndexed() throws TskCoreException {
949  return SleuthkitJNI.hashDatabaseCanBeReindexed(handle);
950  }
951 
952  boolean isIndexing() {
953  return indexing;
954  }
955 
956  private void close() throws TskCoreException {
957  SleuthkitJNI.closeHashDatabase(handle);
958  }
959  }
960 
964  private class HashDbIndexer extends SwingWorker<Object, Void> {
965 
966  private ProgressHandle progress = null;
967  private HashDb hashDb = null;
968 
969  HashDbIndexer(HashDb hashDb) {
970  this.hashDb = hashDb;
971  }
972 
973  ;
974 
975  @Override
976  protected Object doInBackground() {
977  hashDb.indexing = true;
978  progress = ProgressHandleFactory.createHandle(
979  NbBundle.getMessage(this.getClass(), "HashDbManager.progress.indexingHashSet", hashDb.hashSetName));
980  progress.start();
981  progress.switchToIndeterminate();
982  try {
983  SleuthkitJNI.createLookupIndexForHashDatabase(hashDb.handle);
984  } catch (TskCoreException ex) {
985  Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error indexing hash database", ex); //NON-NLS
986  JOptionPane.showMessageDialog(null,
987  NbBundle.getMessage(this.getClass(),
988  "HashDbManager.dlgMsg.errorIndexingHashSet",
989  hashDb.getHashSetName()),
990  NbBundle.getMessage(this.getClass(), "HashDbManager.hashDbIndexingErr"),
991  JOptionPane.ERROR_MESSAGE);
992  }
993  return null;
994  }
995 
996  @Override
997  protected void done() {
998  hashDb.indexing = false;
999  progress.finish();
1000 
1001  // see if we got any errors
1002  try {
1003  get();
1004  } catch (InterruptedException | ExecutionException ex) {
1005  logger.log(Level.SEVERE, "Error creating index", ex); //NON-NLS
1007  NbBundle.getMessage(this.getClass(), "HashDbManager.errCreatingIndex.title"),
1008  NbBundle.getMessage(this.getClass(), "HashDbManager.errCreatingIndex.msg", ex.getMessage()),
1010  } // catch and ignore if we were cancelled
1011  catch (java.util.concurrent.CancellationException ex) {
1012  }
1013 
1014  try {
1015  hashDb.propertyChangeSupport.firePropertyChange(HashDb.Event.INDEXING_DONE.toString(), null, hashDb);
1016  hashDb.propertyChangeSupport.firePropertyChange(HashDbManager.SetEvt.DB_INDEXED.toString(), null, hashDb.getHashSetName());
1017  } catch (Exception e) {
1018  logger.log(Level.SEVERE, "HashDbManager listener threw exception", e); //NON-NLS
1020  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErr"),
1021  NbBundle.getMessage(this.getClass(), "HashDbManager.moduleErrorListeningToUpdatesMsg"),
1023  }
1024  }
1025  }
1026 }
static synchronized IngestManager getInstance()
static< T > Document loadDoc(Class< T > clazz, String xmlPath)
Definition: XMLUtil.java:230
synchronized void addPropertyChangeListener(PropertyChangeListener listener)
HashDb addExistingHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
HashDb addHashDatabase(int handle, String hashSetName, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
static void writeHashDbsToDisk(Document doc, Element rootEl, List< HashDb > hashDbs)
List< HashDb > getUpdateableHashSets(List< HashDb > hashDbs)
HashDb addNewHashDatabase(String hashSetName, String path, boolean searchDuringIngest, boolean sendIngestMessages, HashDb.KnownFilesType knownFilesType)
String getValidFilePath(String hashSetName, String configuredPath)
void closeHashDatabases(List< HashDb > hashDatabases)
synchronized static Logger getLogger(String name)
Definition: Logger.java:166
static void show(String title, String message, MessageType type, ActionListener actionListener)
HashDb(int handle, String hashSetName, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType)
static< T > boolean saveDoc(Class< T > clazz, String xmlPath, String encoding, final Document doc)
Definition: XMLUtil.java:272

Copyright © 2012-2015 Basis Technology. Generated on: Wed Apr 6 2016
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.