Autopsy  4.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
SingleUserCaseConverter.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2015 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.casemodule;
20 
21 import java.io.File;
22 import java.io.IOException;
23 import java.nio.file.Path;
24 import java.nio.file.Paths;
25 import java.sql.Connection;
26 import java.sql.DriverManager;
27 import java.sql.PreparedStatement;
28 import java.sql.ResultSet;
29 import java.sql.ResultSetMetaData;
30 import java.sql.SQLException;
31 import java.sql.Statement;
32 import java.text.SimpleDateFormat;
33 import java.util.Date;
34 import org.apache.commons.io.FileUtils;
35 import org.openide.util.NbBundle;
37 import static org.sleuthkit.autopsy.casemodule.Case.MODULE_FOLDER;
40 import org.sleuthkit.datamodel.CaseDbConnectionInfo;
41 import org.sleuthkit.datamodel.SleuthkitCase;
43 import org.sleuthkit.datamodel.TskData;
44 
49 
50  private static final String AUTOPSY_DB_FILE = "autopsy.db"; //NON-NLS
51  private static final String DOTAUT = CaseMetadata.getFileExtension(); //NON-NLS
52  private static final String TIMELINE_FOLDER = "Timeline"; //NON-NLS
53  private static final String TIMELINE_FILE = "events.db"; //NON-NLS
54  private static final String POSTGRES_DEFAULT_DB_NAME = "postgres"; //NON-NLS
55  private static final int MAX_DB_NAME_LENGTH = 63;
56 
57  public class ImportCaseData {
58 
59  private final Path imageInputFolder;
60  private final Path caseInputFolder;
61  private final Path imageOutputFolder;
62  private final Path caseOutputFolder;
63  private final String oldCaseName;
64  private final String newCaseName;
65  private final boolean copySourceImages;
66  private final boolean deleteCase;
67  private String postgreSQLDbName;
68  private final String autFileName;
69  private final String rawFolderName;
70  private final CaseDbConnectionInfo db;
71 
73  Path imageInput,
74  Path caseInput,
75  Path imageOutput,
76  Path caseOutput,
77  String oldCaseName,
78  String newCaseName,
79  String autFileName,
80  String rawFolderName,
81  boolean copySourceImages,
82  boolean deleteCase) throws UserPreferencesException {
83 
84  this.imageInputFolder = imageInput;
85  this.caseInputFolder = caseInput;
86  this.imageOutputFolder = imageOutput;
87  this.caseOutputFolder = caseOutput;
88  this.oldCaseName = oldCaseName;
89  this.newCaseName = newCaseName;
90  this.autFileName = autFileName;
91  this.rawFolderName = rawFolderName;
92  this.copySourceImages = copySourceImages;
93  this.deleteCase = deleteCase;
95  }
96 
97  public Path getCaseInputFolder() {
98  return this.caseInputFolder;
99  }
100 
101  public Path getCaseOutputFolder() {
102  return this.caseOutputFolder;
103  }
104 
105  Path getImageInputFolder() {
106  return this.imageInputFolder;
107  }
108 
109  Path getImageOutputFolder() {
110  return this.imageOutputFolder;
111  }
112 
113  String getOldCaseName() {
114  return this.oldCaseName;
115  }
116 
117  String getNewCaseName() {
118  return this.newCaseName;
119  }
120 
121  boolean getCopySourceImages() {
122  return this.copySourceImages;
123  }
124 
125  boolean getDeleteCase() {
126  return this.deleteCase;
127  }
128 
129  String getPostgreSQLDbName() {
130  return this.postgreSQLDbName;
131  }
132 
133  String getAutFileName() {
134  return this.autFileName;
135  }
136 
137  String getRawFolderName() {
138  return this.rawFolderName;
139  }
140 
141  CaseDbConnectionInfo getDb() {
142  return this.db;
143  }
144 
145  void setPostgreSQLDbName(String dbName) {
146  this.postgreSQLDbName = dbName;
147  }
148  }
149 
159  public static void importCase(ImportCaseData icd) throws Exception {
160 
161  Class.forName("org.postgresql.Driver"); //NON-NLS
162 
163  // Make sure there is a SQLite databse file
164  Path oldDatabasePath = icd.getCaseInputFolder().resolve(AUTOPSY_DB_FILE);
165  if (false == oldDatabasePath.toFile().exists()) {
166  throw new Exception(NbBundle.getMessage(SingleUserCaseConverter.class, "SingleUserCaseConverter.BadDatabaseFileName")); //NON-NLS
167  }
168 
169  // Read old xml config
170  CaseMetadata oldCaseMetadata = new CaseMetadata(icd.getCaseInputFolder().resolve(icd.getAutFileName()));
171  if (oldCaseMetadata.getCaseType() == CaseType.MULTI_USER_CASE) {
172  throw new Exception(NbBundle.getMessage(SingleUserCaseConverter.class, "SingleUserCaseConverter.AlreadyMultiUser")); //NON-NLS
173  }
174 
175  // Create sanitized names for PostgreSQL and Solr
176  SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); //NON-NLS
177  Date date = new Date();
178  String dbName = Case.sanitizeCaseName(icd.getNewCaseName()) + "_" + dateFormat.format(date); //NON-NLS
179  String solrName = dbName;
180  icd.setPostgreSQLDbName(dbName);
181 
182  // Copy items to new hostname folder structure
183  copyResults(icd);
184 
185  // Convert from SQLite to PostgreSQL
186  importDb(icd);
187 
188  // Update paths inside databse
189  fixPaths(icd);
190 
191  // Copy images
192  copyImages(icd);
193 
194  // Create new .aut file
195  CaseMetadata newCaseMetadata = new CaseMetadata(icd.getCaseOutputFolder().toString(),
197  icd.getNewCaseName(),
198  oldCaseMetadata.getCaseNumber(),
199  oldCaseMetadata.getExaminer(),
200  dbName, solrName);
201  // Set created date. This calls writefile, no need to call it again
202  newCaseMetadata.setCreatedDate(oldCaseMetadata.getCreatedDate());
203  newCaseMetadata.setCreatedByVersion(oldCaseMetadata.getCreatedByVersion());
204 
205  // At this point the import has been finished successfully so we can delete the original case
206  // (if requested). This *should* be fairly safe - at this point we know there was an autopsy file
207  // and database in the given directory so the user shouldn't be able to accidently blow away
208  // their C drive.
209  if (icd.getDeleteCase()) {
210  FileUtils.deleteDirectory(icd.getCaseInputFolder().toFile());
211  }
212  }
213 
221  private static File findInputFolder(ImportCaseData icd) {
222 
223  File thePath = icd.getImageInputFolder().resolve(icd.getOldCaseName()).toFile();
224  if (thePath.isDirectory()) {
226  return thePath;
227  }
228  thePath = icd.getImageInputFolder().resolve(icd.getRawFolderName()).toFile();
229  if (thePath.isDirectory()) {
231  return thePath;
232  }
233  return icd.getImageInputFolder().toFile();
234  }
235 
244  private static void copyResults(ImportCaseData icd) throws IOException {
246  String hostName = NetworkUtils.getLocalHostName();
247 
248  Path destination;
249  Path source = icd.getCaseInputFolder();
250  if (source.toFile().exists()) {
251  destination = icd.getCaseOutputFolder().resolve(hostName);
252  FileUtils.copyDirectory(source.toFile(), destination.toFile());
253  }
254 
255  source = icd.getCaseInputFolder().resolve(TIMELINE_FILE);
256  if (source.toFile().exists()) {
257  destination = Paths.get(icd.getCaseOutputFolder().toString(), hostName, MODULE_FOLDER, TIMELINE_FOLDER, TIMELINE_FILE);
258  FileUtils.copyFile(source.toFile(), destination.toFile());
259  }
260 
261  // Remove the single-user .aut file from the multi-user folder
262  File oldAutopsyFile = Paths.get(icd.getCaseOutputFolder().toString(), hostName, icd.getOldCaseName() + DOTAUT).toFile();
263  if (oldAutopsyFile.exists()) {
264  oldAutopsyFile.delete();
265  }
266 
267  // Remove the single-user database file from the multi-user folder
268  File oldDatabaseFile = Paths.get(icd.getCaseOutputFolder().toString(), hostName, AUTOPSY_DB_FILE).toFile();
269  if (oldDatabaseFile.exists()) {
270  oldDatabaseFile.delete();
271  }
272 
273  // Remove the single-user Timeline file from the multi-user folder
274  File oldTimelineFile = Paths.get(icd.getCaseOutputFolder().toString(), hostName, TIMELINE_FILE).toFile();
275  if (oldTimelineFile.exists()) {
276  oldTimelineFile.delete();
277  }
278  }
279 
291  private static void importDb(ImportCaseData icd) throws SQLException, ClassNotFoundException, Exception {
292  // deconflict the database name
294 
295  // Create a new database via SleuthkitCase
296  SleuthkitCase newCase = SleuthkitCase.newCase(icd.getPostgreSQLDbName(), icd.getDb(), icd.getCaseOutputFolder().toString());
297  newCase.close();
298 
300  Class.forName("org.sqlite.JDBC"); //NON-NLS
301  Connection sqliteConnection = getSQLiteConnection(icd);
302  Connection postgreSQLConnection = getPostgreSQLConnection(icd);
303 
304  // blackboard_artifact_types
305  Statement inputStatement = sqliteConnection.createStatement();
306  ResultSet inputResultSet = inputStatement.executeQuery("SELECT * FROM blackboard_artifact_types"); //NON-NLS
307  Statement outputStatement;
308  Statement numberingPK;
309  long biggestPK = 0;
310 
311  while (inputResultSet.next()) {
312  try {
313  long value = inputResultSet.getLong(1);
314  if (value > biggestPK) {
315  biggestPK = value;
316  }
317  Statement check = postgreSQLConnection.createStatement();
318  ResultSet checkResult = check.executeQuery("SELECT * FROM blackboard_artifact_types WHERE artifact_type_id=" + value + " AND type_name LIKE '" + inputResultSet.getString(2) + "' AND display_name LIKE '" + inputResultSet.getString(3) + "'"); //NON-NLS
319  if (!checkResult.isBeforeFirst()) { // only insert if it doesn't exist
320  String sql = "INSERT INTO blackboard_artifact_types (artifact_type_id, type_name, display_name) VALUES (" //NON-NLS
321  + value + ", '"
322  + SleuthkitCase.escapeSingleQuotes(inputResultSet.getString(2)) + "',"
323  + " ? )"; //NON-NLS
324  PreparedStatement pst = postgreSQLConnection.prepareStatement(sql);
325  populateNullableString(pst, inputResultSet, 3, 1);
326  pst.executeUpdate();
327  }
328  } catch (SQLException ex) {
329  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
330  throw new SQLException(ex);
331  }
332  }
333  }
334  numberingPK = postgreSQLConnection.createStatement();
335  numberingPK.execute("ALTER SEQUENCE blackboard_artifact_types_artifact_type_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
336 
337  // blackboard_attribute_types
338  biggestPK = 0;
339  inputStatement = sqliteConnection.createStatement();
340  inputResultSet = inputStatement.executeQuery("SELECT * FROM blackboard_attribute_types"); //NON-NLS
341 
342  while (inputResultSet.next()) {
343  try {
344  long value = inputResultSet.getLong(1);
345  if (value > biggestPK) {
346  biggestPK = value;
347  }
348  Statement check = postgreSQLConnection.createStatement();
349  ResultSet checkResult = check.executeQuery("SELECT * FROM blackboard_attribute_types WHERE attribute_type_id=" + value + " AND type_name LIKE '" + inputResultSet.getString(2) + "' AND display_name LIKE '" + inputResultSet.getString(3) + "'"); //NON-NLS
350  if (!checkResult.isBeforeFirst()) { // only insert if it doesn't exist
351  String sql = "INSERT INTO blackboard_attribute_types (attribute_type_id, type_name, display_name) VALUES (" //NON-NLS
352  + value + ", '"
353  + SleuthkitCase.escapeSingleQuotes(inputResultSet.getString(2)) + "',"
354  + " ? )"; //NON-NLS
355 
356  PreparedStatement pst = postgreSQLConnection.prepareStatement(sql);
357  populateNullableString(pst, inputResultSet, 3, 1);
358  pst.executeUpdate();
359  }
360  } catch (SQLException ex) {
361  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
362  throw new SQLException(ex);
363  }
364  }
365  }
366  numberingPK = postgreSQLConnection.createStatement();
367  numberingPK.execute("ALTER SEQUENCE blackboard_attribute_types_attribute_type_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
368 
369  // tsk_objects
370  biggestPK = 0;
371  inputStatement = sqliteConnection.createStatement();
372  inputResultSet = inputStatement.executeQuery("SELECT * FROM tsk_objects"); //NON-NLS
373 
374  while (inputResultSet.next()) {
375  outputStatement = postgreSQLConnection.createStatement();
376  try {
377  long value = inputResultSet.getLong(1);
378  if (value > biggestPK) {
379  biggestPK = value;
380  }
381  outputStatement.executeUpdate("INSERT INTO tsk_objects (obj_id, par_obj_id, type) VALUES (" //NON-NLS
382  + value + ","
383  + getNullableLong(inputResultSet, 2) + ","
384  + inputResultSet.getInt(3) + ")"); //NON-NLS
385  } catch (SQLException ex) {
386  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
387  throw new SQLException(ex);
388  }
389  }
390  }
391  numberingPK = postgreSQLConnection.createStatement();
392  numberingPK.execute("ALTER SEQUENCE tsk_objects_obj_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
393 
394  // tsk_image_names, no primary key
395  inputStatement = sqliteConnection.createStatement();
396  inputResultSet = inputStatement.executeQuery("SELECT * FROM tsk_image_names"); //NON-NLS
397 
398  while (inputResultSet.next()) {
399  outputStatement = postgreSQLConnection.createStatement();
400  try {
401  outputStatement.executeUpdate("INSERT INTO tsk_image_names (obj_id, name, sequence) VALUES (" //NON-NLS
402  + inputResultSet.getLong(1) + ",'"
403  + inputResultSet.getString(2) + "',"
404  + inputResultSet.getInt(3) + ")"); //NON-NLS
405  } catch (SQLException ex) {
406  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
407  throw new SQLException(ex);
408  }
409  }
410  }
411 
412  // tsk_image_info
413  biggestPK = 0;
414  inputStatement = sqliteConnection.createStatement();
415  inputResultSet = inputStatement.executeQuery("SELECT * FROM tsk_image_info"); //NON-NLS
416 
417  while (inputResultSet.next()) {
418  try {
419  long value = inputResultSet.getLong(1);
420  if (value > biggestPK) {
421  biggestPK = value;
422  }
423  String sql = "INSERT INTO tsk_image_info (obj_id, type, ssize, tzone, size, md5, display_name) VALUES (" //NON-NLS
424  + value + ","
425  + getNullableInt(inputResultSet, 2) + ","
426  + getNullableInt(inputResultSet, 3) + ","
427  + " ? ,"
428  + getNullableLong(inputResultSet, 5) + ","
429  + " ? ,"
430  + " ? )"; //NON-NLS
431 
432  PreparedStatement pst = postgreSQLConnection.prepareStatement(sql);
433  populateNullableString(pst, inputResultSet, 4, 1);
434  populateNullableString(pst, inputResultSet, 6, 2);
435  populateNullableString(pst, inputResultSet, 7, 3);
436  pst.executeUpdate();
437 
438  } catch (SQLException ex) {
439  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
440  throw new SQLException(ex);
441  }
442  }
443  }
444  numberingPK = postgreSQLConnection.createStatement();
445  numberingPK.execute("ALTER SEQUENCE tsk_image_info_obj_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
446 
447  // tsk_fs_info
448  biggestPK = 0;
449  inputStatement = sqliteConnection.createStatement();
450  inputResultSet = inputStatement.executeQuery("SELECT * FROM tsk_fs_info"); //NON-NLS
451 
452  while (inputResultSet.next()) {
453  try {
454  long value = inputResultSet.getLong(1);
455  if (value > biggestPK) {
456  biggestPK = value;
457  }
458  String sql = "INSERT INTO tsk_fs_info (obj_id, img_offset, fs_type, block_size, block_count, root_inum, first_inum, last_inum, display_name) VALUES (" //NON-NLS
459  + value + ","
460  + inputResultSet.getLong(2) + ","
461  + inputResultSet.getInt(3) + ","
462  + inputResultSet.getLong(4) + ","
463  + inputResultSet.getLong(5) + ","
464  + inputResultSet.getLong(6) + ","
465  + inputResultSet.getLong(7) + ","
466  + inputResultSet.getLong(8) + ","
467  + " ? )"; //NON-NLS
468 
469  PreparedStatement pst = postgreSQLConnection.prepareStatement(sql);
470  populateNullableString(pst, inputResultSet, 9, 1);
471  pst.executeUpdate();
472 
473  } catch (SQLException ex) {
474  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
475  throw new SQLException(ex);
476  }
477  }
478  }
479  numberingPK = postgreSQLConnection.createStatement();
480  numberingPK.execute("ALTER SEQUENCE tsk_fs_info_obj_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
481 
482  // tsk_files_path
483  biggestPK = 0;
484  inputStatement = sqliteConnection.createStatement();
485  inputResultSet = inputStatement.executeQuery("SELECT * FROM tsk_files_path"); //NON-NLS
486 
487  while (inputResultSet.next()) {
488  outputStatement = postgreSQLConnection.createStatement();
489  try {
490  long value = inputResultSet.getLong(1);
491  if (value > biggestPK) {
492  biggestPK = value;
493  }
494 
495  // If the entry contains an encoding type, copy it. Otherwise use NONE.
496  // The test on column count can be removed if we upgrade the database before conversion.
497  int encoding = TskData.EncodingType.NONE.getType();
498  ResultSetMetaData rsMetaData = inputResultSet.getMetaData();
499  if(rsMetaData.getColumnCount() == 3){
500  encoding = inputResultSet.getInt(3);
501  }
502  outputStatement.executeUpdate("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (" //NON-NLS
503  + value + ", '"
504  + SleuthkitCase.escapeSingleQuotes(inputResultSet.getString(2)) + "', "
505  + encoding + ")"); //NON-NLS
506  } catch (SQLException ex) {
507  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
508  throw new SQLException(ex);
509  }
510  }
511  }
512  numberingPK = postgreSQLConnection.createStatement();
513  numberingPK.execute("ALTER SEQUENCE tsk_files_path_obj_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
514 
515  // tsk_files
516  biggestPK = 0;
517  inputStatement = sqliteConnection.createStatement();
518  inputResultSet = inputStatement.executeQuery("SELECT * FROM tsk_files"); //NON-NLS
519 
520  while (inputResultSet.next()) {
521  try {
522  long value = inputResultSet.getLong(1);
523  if (value > biggestPK) {
524  biggestPK = value;
525  }
526  String sql = "INSERT INTO tsk_files (obj_id, fs_obj_id, attr_type, attr_id, name, meta_addr, meta_seq, type, has_layout, has_path, dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime, atime, mtime, mode, uid, gid, md5, known, parent_path) VALUES (" //NON-NLS
527  + value + ","
528  + getNullableLong(inputResultSet, 2) + ","
529  + getNullableInt(inputResultSet, 3) + ","
530  + getNullableInt(inputResultSet, 4) + ",'"
531  + SleuthkitCase.escapeSingleQuotes(inputResultSet.getString(5)) + "',"
532  + getNullableLong(inputResultSet, 6) + ","
533  + getNullableLong(inputResultSet, 7) + ","
534  + getNullableInt(inputResultSet, 8) + ","
535  + getNullableInt(inputResultSet, 9) + ","
536  + getNullableInt(inputResultSet, 10) + ","
537  + getNullableInt(inputResultSet, 11) + ","
538  + getNullableInt(inputResultSet, 12) + ","
539  + getNullableInt(inputResultSet, 13) + ","
540  + getNullableInt(inputResultSet, 14) + ","
541  + getNullableLong(inputResultSet, 15) + ","
542  + getNullableLong(inputResultSet, 16) + ","
543  + getNullableLong(inputResultSet, 17) + ","
544  + getNullableLong(inputResultSet, 18) + ","
545  + getNullableLong(inputResultSet, 19) + ","
546  + getNullableInt(inputResultSet, 20) + ","
547  + getNullableInt(inputResultSet, 21) + ","
548  + getNullableInt(inputResultSet, 22) + ","
549  + " ? ,"
550  + getNullableInt(inputResultSet, 24) + ","
551  + " ? )"; //NON-NLS
552 
553  PreparedStatement pst = postgreSQLConnection.prepareStatement(sql);
554  populateNullableString(pst, inputResultSet, 23, 1);
555  populateNullableString(pst, inputResultSet, 25, 2);
556  pst.executeUpdate();
557 
558  } catch (SQLException ex) {
559  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
560  throw new SQLException(ex);
561  }
562  }
563  }
564  numberingPK = postgreSQLConnection.createStatement();
565  numberingPK.execute("ALTER SEQUENCE tsk_files_obj_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
566 
567  // tsk_file_layout, no primary key
568  inputStatement = sqliteConnection.createStatement();
569  inputResultSet = inputStatement.executeQuery("SELECT * FROM tsk_file_layout"); //NON-NLS
570 
571  while (inputResultSet.next()) {
572  outputStatement = postgreSQLConnection.createStatement();
573  try {
574  outputStatement.executeUpdate("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) VALUES (" //NON-NLS
575  + inputResultSet.getLong(1) + ","
576  + inputResultSet.getLong(2) + ","
577  + inputResultSet.getLong(3) + ","
578  + inputResultSet.getInt(4) + ")"); //NON-NLS
579  } catch (SQLException ex) {
580  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
581  throw new SQLException(ex);
582  }
583  }
584  }
585 
586  // tsk_db_info, no primary key
587  inputStatement = sqliteConnection.createStatement();
588  inputResultSet = inputStatement.executeQuery("SELECT * FROM tsk_db_info"); //NON-NLS
589 
590  while (inputResultSet.next()) {
591  outputStatement = postgreSQLConnection.createStatement();
592  try {
593  Statement check = postgreSQLConnection.createStatement();
594  ResultSet checkResult = check.executeQuery("SELECT * FROM tsk_db_info WHERE schema_ver=" + inputResultSet.getInt(1) + " AND tsk_ver=" + inputResultSet.getInt(2)); //NON-NLS
595  if (!checkResult.isBeforeFirst()) { // only insert if it doesn't exist
596  outputStatement.executeUpdate("INSERT INTO tsk_db_info (schema_ver, tsk_ver) VALUES (" //NON-NLS
597  + getNullableInt(inputResultSet, 1) + ","
598  + getNullableInt(inputResultSet, 2) + ")"); //NON-NLS
599  }
600  } catch (SQLException ex) {
601  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
602  throw new SQLException(ex);
603  }
604  }
605  }
606 
607  // tag_names
608  biggestPK = 0;
609  inputStatement = sqliteConnection.createStatement();
610  inputResultSet = inputStatement.executeQuery("SELECT * FROM tag_names"); //NON-NLS
611 
612  while (inputResultSet.next()) {
613  try {
614  long value = inputResultSet.getLong(1);
615  if (value > biggestPK) {
616  biggestPK = value;
617  }
618  String sql = "INSERT INTO tag_names (tag_name_id, display_name, description, color) VALUES (" //NON-NLS
619  + value + ","
620  + " ? ,'"
621  + SleuthkitCase.escapeSingleQuotes(inputResultSet.getString(3)) + "','"
622  + SleuthkitCase.escapeSingleQuotes(inputResultSet.getString(4)) + "')"; //NON-NLS
623 
624  PreparedStatement pst = postgreSQLConnection.prepareStatement(sql);
625  populateNullableString(pst, inputResultSet, 2, 1);
626  pst.executeUpdate();
627 
628  } catch (SQLException ex) {
629  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
630  throw new SQLException(ex);
631  }
632  }
633  }
634  numberingPK = postgreSQLConnection.createStatement();
635  numberingPK.execute("ALTER SEQUENCE tag_names_tag_name_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
636 
637  // reports
638  biggestPK = 0;
639  inputStatement = sqliteConnection.createStatement();
640  inputResultSet = inputStatement.executeQuery("SELECT * FROM reports"); //NON-NLS
641 
642  while (inputResultSet.next()) {
643  outputStatement = postgreSQLConnection.createStatement();
644  try {
645  long value = inputResultSet.getLong(1);
646  if (value > biggestPK) {
647  biggestPK = value;
648  }
649  outputStatement.executeUpdate("INSERT INTO reports (report_id, path, crtime, src_module_name, report_name) VALUES (" //NON-NLS
650  + value + ", '"
651  + SleuthkitCase.escapeSingleQuotes(inputResultSet.getString(2)) + "',"
652  + inputResultSet.getInt(3) + ",'"
653  + SleuthkitCase.escapeSingleQuotes(inputResultSet.getString(4)) + "','"
654  + SleuthkitCase.escapeSingleQuotes(inputResultSet.getString(5)) + "')"); //NON-NLS
655 
656  } catch (SQLException ex) {
657  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
658  throw new SQLException(ex);
659  }
660  }
661  }
662  numberingPK = postgreSQLConnection.createStatement();
663  numberingPK.execute("ALTER SEQUENCE reports_report_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
664 
665  // blackboard_artifacts
666  biggestPK = Long.MIN_VALUE; // This table uses very large negative primary key values, so start at Long.MIN_VALUE
667  inputStatement = sqliteConnection.createStatement();
668  inputResultSet = inputStatement.executeQuery("SELECT * FROM blackboard_artifacts"); //NON-NLS
669 
670  while (inputResultSet.next()) {
671  outputStatement = postgreSQLConnection.createStatement();
672  try {
673  long value = inputResultSet.getLong(1);
674  if (value > biggestPK) {
675  biggestPK = value;
676  }
677  outputStatement.executeUpdate("INSERT INTO blackboard_artifacts (artifact_id, obj_id, artifact_type_id) VALUES (" //NON-NLS
678  + value + ","
679  + inputResultSet.getLong(2) + ","
680  + inputResultSet.getLong(3) + ")"); //NON-NLS
681 
682  } catch (SQLException ex) {
683  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
684  throw new SQLException(ex);
685  }
686  }
687  }
688  numberingPK = postgreSQLConnection.createStatement();
689  numberingPK.execute("ALTER SEQUENCE blackboard_artifacts_artifact_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
690 
691  // blackboard_attributes, no primary key
692  inputStatement = sqliteConnection.createStatement();
693  inputResultSet = inputStatement.executeQuery("SELECT * FROM blackboard_attributes"); //NON-NLS
694 
695  while (inputResultSet.next()) {
696  try {
697  String sql = "INSERT INTO blackboard_attributes (artifact_id, artifact_type_id, source, context, attribute_type_id, value_type, value_byte, value_text, value_int32, value_int64, value_double) VALUES (" //NON-NLS
698  + inputResultSet.getLong(1) + ","
699  + inputResultSet.getLong(2) + ","
700  + " ? ,"
701  + " ? ,"
702  + inputResultSet.getLong(5) + ","
703  + inputResultSet.getInt(6) + ","
704  + " ? ,"
705  + " ? ,"
706  + getNullableInt(inputResultSet, 9) + ","
707  + getNullableLong(inputResultSet, 10) + ","
708  + " ? )"; //NON-NLS
709  PreparedStatement pst = postgreSQLConnection.prepareStatement(sql);
710  populateNullableString(pst, inputResultSet, 3, 1);
711  populateNullableString(pst, inputResultSet, 4, 2);
712  populateNullableByteArray(pst, inputResultSet, 7, 3);
713  populateNullableString(pst, inputResultSet, 8, 4);
714  populateNullableNumeric(pst, inputResultSet, 11, 5);
715  pst.executeUpdate();
716 
717  } catch (SQLException ex) {
718  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
719  throw new SQLException(ex);
720  }
721  }
722  }
723 
724  // tsk_vs_parts
725  biggestPK = 0;
726  inputStatement = sqliteConnection.createStatement();
727  inputResultSet = inputStatement.executeQuery("SELECT * FROM tsk_vs_parts"); //NON-NLS
728 
729  while (inputResultSet.next()) {
730  try {
731  long value = inputResultSet.getLong(1);
732  if (value > biggestPK) {
733  biggestPK = value;
734  }
735  String sql = "INSERT INTO tsk_vs_parts (obj_id, addr, start, length, descr, flags) VALUES (" //NON-NLS
736  + value + ","
737  + inputResultSet.getLong(2) + ","
738  + inputResultSet.getLong(3) + ","
739  + inputResultSet.getLong(4) + ","
740  + " ? ,"
741  + inputResultSet.getInt(6) + ")"; //NON-NLS
742  PreparedStatement pst = postgreSQLConnection.prepareStatement(sql);
743  populateNullableString(pst, inputResultSet, 5, 1);
744  pst.executeUpdate();
745 
746  } catch (SQLException ex) {
747  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
748  throw new SQLException(ex);
749  }
750  }
751  }
752  numberingPK = postgreSQLConnection.createStatement();
753  numberingPK.execute("ALTER SEQUENCE tsk_vs_parts_obj_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
754 
755  // tsk_vs_info
756  biggestPK = 0;
757  inputStatement = sqliteConnection.createStatement();
758  inputResultSet = inputStatement.executeQuery("SELECT * FROM tsk_vs_info"); //NON-NLS
759 
760  while (inputResultSet.next()) {
761  outputStatement = postgreSQLConnection.createStatement();
762  try {
763  long value = inputResultSet.getLong(1);
764  if (value > biggestPK) {
765  biggestPK = value;
766  }
767  outputStatement.executeUpdate("INSERT INTO tsk_vs_info (obj_id, vs_type, img_offset, block_size) VALUES (" //NON-NLS
768  + value + ","
769  + inputResultSet.getInt(2) + ","
770  + inputResultSet.getLong(3) + ","
771  + inputResultSet.getLong(4) + ")"); //NON-NLS
772 
773  } catch (SQLException ex) {
774  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
775  throw new SQLException(ex);
776  }
777  }
778  }
779  numberingPK = postgreSQLConnection.createStatement();
780  numberingPK.execute("ALTER SEQUENCE tsk_vs_info_obj_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
781 
782  // tsk_files_derived
783  biggestPK = 0;
784  inputStatement = sqliteConnection.createStatement();
785  inputResultSet = inputStatement.executeQuery("SELECT * FROM tsk_files_derived"); //NON-NLS
786 
787  while (inputResultSet.next()) {
788  try {
789  long value = inputResultSet.getLong(1);
790  if (value > biggestPK) {
791  biggestPK = value;
792  }
793  String sql = "INSERT INTO tsk_files_derived (obj_id, derived_id, rederive) VALUES (" //NON-NLS
794  + value + ","
795  + inputResultSet.getLong(2) + ","
796  + " ? )"; //NON-NLS
797  PreparedStatement pst = postgreSQLConnection.prepareStatement(sql);
798  populateNullableString(pst, inputResultSet, 3, 1);
799  pst.executeUpdate();
800 
801  } catch (SQLException ex) {
802  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
803  throw new SQLException(ex);
804  }
805  }
806  }
807  numberingPK = postgreSQLConnection.createStatement();
808  numberingPK.execute("ALTER SEQUENCE tsk_files_derived_obj_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
809 
810  // tsk_files_derived_method
811  biggestPK = 0;
812  inputStatement = sqliteConnection.createStatement();
813  inputResultSet = inputStatement.executeQuery("SELECT * FROM tsk_files_derived_method"); //NON-NLS
814 
815  while (inputResultSet.next()) {
816  try {
817  long value = inputResultSet.getLong(1);
818  if (value > biggestPK) {
819  biggestPK = value;
820  }
821  String sql = "INSERT INTO tsk_files_derived_method (derived_id, tool_name, tool_version, other) VALUES (" //NON-NLS
822  + value + ", '"
823  + inputResultSet.getString(2) + "','"
824  + inputResultSet.getString(3) + "',"
825  + " ? )"; //NON-NLS
826  PreparedStatement pst = postgreSQLConnection.prepareStatement(sql);
827  populateNullableString(pst, inputResultSet, 4, 1);
828  pst.executeUpdate();
829 
830  } catch (SQLException ex) {
831  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
832  throw new SQLException(ex);
833  }
834  }
835  }
836  numberingPK = postgreSQLConnection.createStatement();
837  numberingPK.execute("ALTER SEQUENCE tsk_files_derived_method_derived_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
838 
839  // content_tags
840  biggestPK = 0;
841  inputStatement = sqliteConnection.createStatement();
842  inputResultSet = inputStatement.executeQuery("SELECT * FROM content_tags"); //NON-NLS
843 
844  while (inputResultSet.next()) {
845  outputStatement = postgreSQLConnection.createStatement();
846  try {
847  long value = inputResultSet.getLong(1);
848  if (value > biggestPK) {
849  biggestPK = value;
850  }
851  outputStatement.executeUpdate("INSERT INTO content_tags (tag_id, obj_id, tag_name_id, comment, begin_byte_offset, end_byte_offset) VALUES (" //NON-NLS
852  + value + ","
853  + inputResultSet.getLong(2) + ","
854  + inputResultSet.getLong(3) + ",'"
855  + inputResultSet.getString(4) + "',"
856  + inputResultSet.getLong(5) + ","
857  + inputResultSet.getLong(6) + ")"); //NON-NLS
858 
859  } catch (SQLException ex) {
860  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
861  throw new SQLException(ex);
862  }
863  }
864  }
865  numberingPK = postgreSQLConnection.createStatement();
866  numberingPK.execute("ALTER SEQUENCE content_tags_tag_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
867 
868  // blackboard_artifact_tags
869  biggestPK = 0;
870  inputStatement = sqliteConnection.createStatement();
871  inputResultSet = inputStatement.executeQuery("SELECT * FROM blackboard_artifact_tags"); //NON-NLS
872 
873  while (inputResultSet.next()) {
874  outputStatement = postgreSQLConnection.createStatement();
875  try {
876  long value = inputResultSet.getLong(1);
877  if (value > biggestPK) {
878  biggestPK = value;
879  }
880  outputStatement.executeUpdate("INSERT INTO blackboard_artifact_tags (tag_id, artifact_id, tag_name_id, comment) VALUES (" //NON-NLS
881  + value + ","
882  + inputResultSet.getLong(2) + ","
883  + inputResultSet.getLong(3) + ",'"
884  + inputResultSet.getString(4) + "')"); //NON-NLS
885 
886  } catch (SQLException ex) {
887  if (ex.getErrorCode() != 0) { // 0 if the entry already exists
888  throw new SQLException(ex);
889  }
890  }
891  }
892  numberingPK = postgreSQLConnection.createStatement();
893  numberingPK.execute("ALTER SEQUENCE blackboard_artifact_tags_tag_id_seq RESTART WITH " + (biggestPK + 1)); //NON-NLS
894 
895  sqliteConnection.close();
896  postgreSQLConnection.close();
897  }
898 
910  private static void deconflictDatabaseName(ImportCaseData icd) throws ClassNotFoundException, SQLException, Exception {
911 
912  Connection postgreSQLConnection = getPostgreSQLConnection(icd, POSTGRES_DEFAULT_DB_NAME);
913 
914  int number = 1;
915  boolean unique = false;
916  String sanitizedDbName = icd.getPostgreSQLDbName();
917  if (sanitizedDbName.length() > MAX_DB_NAME_LENGTH) {
918  sanitizedDbName = sanitizedDbName.substring(0, MAX_DB_NAME_LENGTH);
919  }
920 
921  if (postgreSQLConnection != null) {
922  while (unique == false) {
923  Statement st = postgreSQLConnection.createStatement();
924  ResultSet answer = st.executeQuery("SELECT datname FROM pg_catalog.pg_database WHERE LOWER(datname) LIKE LOWER('" + sanitizedDbName + "%')"); //NON-NLS
925 
926  if (!answer.next()) {
927  unique = true;
928  } else {
929  // not unique. add numbers to db name.
930  if (number == Integer.MAX_VALUE) {
931  // oops. it never became unique. give up.
932  throw new Exception(NbBundle.getMessage(SingleUserCaseConverter.class, "SingleUserCaseConverter.NonUniqueDatabaseName")); //NON-NLS
933  }
934  sanitizedDbName = "db_" + Integer.toString(number) + "_" + icd.getPostgreSQLDbName(); //NON-NLS
935 
936  // Chop full db name to 63 characters (max for PostgreSQL)
937  if (sanitizedDbName.length() > MAX_DB_NAME_LENGTH) {
938  sanitizedDbName = sanitizedDbName.substring(0, MAX_DB_NAME_LENGTH);
939  }
940  ++number;
941  }
942  }
943  postgreSQLConnection.close();
944  } else {
945  // Could be caused by database credentials, using user accounts that
946  // can not check if other databases exist, so allow it to continue
947  }
948 
949  icd.setPostgreSQLDbName(sanitizedDbName);
950  }
951 
960  private static void copyImages(ImportCaseData icd) throws Exception {
961  if (icd.getCopySourceImages()) {
962  File imageSource = findInputFolder(icd); // Find the folder for the input images
963  File imageDestination = new File(icd.getImageOutputFolder().toString());
964 
965  // If we can find the input images, copy if needed.
966  if (imageSource.exists()) {
967  FileUtils.copyDirectory(imageSource, imageDestination);
968 
969  } else {
970  throw new Exception(NbBundle.getMessage(SingleUserCaseConverter.class, "SingleUserCaseConverter.UnableToCopySourceImages")); //NON-NLS
971  }
972  }
973  }
974 
984  private static void fixPaths(ImportCaseData icd) throws SQLException, Exception {
986 
987  String input = icd.getImageInputFolder().toString();
988  String output = icd.getImageOutputFolder().toString();
989 
990  Connection postgresqlConnection = getPostgreSQLConnection(icd);
991 
992  if (postgresqlConnection != null) {
993  String hostName = NetworkUtils.getLocalHostName();
994 
995  // add hostname to reports
996  Statement updateStatement = postgresqlConnection.createStatement();
997  updateStatement.executeUpdate("UPDATE reports SET path=CONCAT('" + hostName + "/', path) WHERE path IS NOT NULL AND path != ''"); //NON-NLS
998 
999  // add hostname to tsk_files_path
1000  updateStatement = postgresqlConnection.createStatement();
1001  updateStatement.executeUpdate("UPDATE tsk_files_path SET path=CONCAT('" + hostName + "\\', path) WHERE path IS NOT NULL AND path != ''"); //NON-NLS
1002 
1003  String caseName = icd.getRawFolderName().toLowerCase();
1004 
1005  if (icd.getCopySourceImages()) {
1006  // update path for images
1007  Statement inputStatement = postgresqlConnection.createStatement();
1008  ResultSet inputResultSet = inputStatement.executeQuery("SELECT * FROM tsk_image_names"); //NON-NLS
1009 
1010  while (inputResultSet.next()) {
1011  Path oldPath = Paths.get(inputResultSet.getString(2));
1012 
1013  for (int x = 0; x < oldPath.getNameCount(); ++x) {
1014  if (oldPath.getName(x).toString().toLowerCase().equals(caseName)) {
1015  Path newPath = Paths.get(output, oldPath.subpath(x + 1, oldPath.getNameCount()).toString());
1016  updateStatement = postgresqlConnection.createStatement();
1017  updateStatement.executeUpdate("UPDATE tsk_image_names SET name='" + newPath.toString() + "' WHERE obj_id = " + inputResultSet.getInt(1)); //NON-NLS
1018  break;
1019  }
1020  }
1021  }
1022  }
1023  postgresqlConnection.close();
1024  } else {
1025  throw new Exception(NbBundle.getMessage(SingleUserCaseConverter.class, "SingleUserCaseConverter.CanNotOpenDatabase")); //NON-NLS
1026  }
1027  }
1028 
1040  private static String getNullableInt(ResultSet rs, int index) throws SQLException {
1041  int value = rs.getInt(index);
1042  if (rs.wasNull()) {
1043  return "NULL"; //NON-NLS
1044  } else {
1045  return Integer.toString(value);
1046  }
1047  }
1048 
1060  private static String getNullableLong(ResultSet rs, int index) throws SQLException {
1061  long value = rs.getLong(index);
1062  if (rs.wasNull()) {
1063  return "NULL"; //NON-NLS
1064  } else {
1065  return Long.toString(value);
1066  }
1067  }
1068 
1080  private static void populateNullableString(PreparedStatement pst, ResultSet rs, int rsIndex, int psIndex) throws SQLException {
1081  String nullableString = rs.getString(rsIndex);
1082  if (rs.wasNull()) {
1083  pst.setNull(psIndex, java.sql.Types.NULL);
1084  } else {
1085  pst.setString(psIndex, SleuthkitCase.escapeSingleQuotes(nullableString));
1086  }
1087  }
1088 
1100  private static void populateNullableByteArray(PreparedStatement pst, ResultSet rs, int rsIndex, int psIndex) throws SQLException {
1101  byte[] nullableBytes = rs.getBytes(rsIndex);
1102  if (rs.wasNull()) {
1103  pst.setNull(psIndex, java.sql.Types.NULL);
1104  } else {
1105  pst.setBytes(psIndex, nullableBytes);
1106  }
1107  }
1108 
1120  private static void populateNullableNumeric(PreparedStatement pst, ResultSet rs, int rsIndex, int psIndex) throws SQLException {
1121  double nullableNumeric = rs.getDouble(rsIndex);
1122  if (rs.wasNull()) {
1123  pst.setNull(psIndex, java.sql.Types.NULL);
1124  } else {
1125  pst.setDouble(psIndex, nullableNumeric);
1126  }
1127  }
1128 
1138  private static Connection getPostgreSQLConnection(ImportCaseData icd) throws SQLException {
1139  return getPostgreSQLConnection(icd, icd.getPostgreSQLDbName());
1140  }
1141 
1152  private static Connection getPostgreSQLConnection(ImportCaseData icd, String dbName) throws SQLException {
1153  return DriverManager.getConnection("jdbc:postgresql://" //NON-NLS
1154  + icd.getDb().getHost() + ":"
1155  + icd.getDb().getPort() + "/"
1156  + dbName,
1157  icd.getDb().getUserName(),
1158  icd.getDb().getPassword()); //NON-NLS
1159  }
1160 
1170  private static Connection getSQLiteConnection(ImportCaseData icd) throws SQLException {
1171  return DriverManager.getConnection("jdbc:sqlite:" + icd.getCaseInputFolder().resolve(AUTOPSY_DB_FILE).toString(), "", ""); //NON-NLS
1172  }
1173 
1174 }
static void populateNullableNumeric(PreparedStatement pst, ResultSet rs, int rsIndex, int psIndex)
ImportCaseData(Path imageInput, Path caseInput, Path imageOutput, Path caseOutput, String oldCaseName, String newCaseName, String autFileName, String rawFolderName, boolean copySourceImages, boolean deleteCase)
static CaseDbConnectionInfo getDatabaseConnectionInfo()
static void populateNullableString(PreparedStatement pst, ResultSet rs, int rsIndex, int psIndex)
static void populateNullableByteArray(PreparedStatement pst, ResultSet rs, int rsIndex, int psIndex)
static Connection getPostgreSQLConnection(ImportCaseData icd, String dbName)

Copyright © 2012-2016 Basis Technology. Generated on: Mon Jan 2 2017
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.