Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
RdbmsCentralRepo.java
Go to the documentation of this file.
1/*
2 * Central Repository
3 *
4 * Copyright 2015-2021 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 */
19package org.sleuthkit.autopsy.centralrepository.datamodel;
20
21import com.google.common.cache.Cache;
22import com.google.common.cache.CacheBuilder;
23import com.google.common.cache.CacheLoader;
24import java.net.UnknownHostException;
25import java.util.ArrayList;
26import java.util.List;
27import java.util.Collection;
28import java.util.LinkedHashSet;
29import java.util.stream.Collectors;
30import java.sql.Connection;
31import java.sql.PreparedStatement;
32import java.sql.ResultSet;
33import java.sql.SQLException;
34import java.sql.Statement;
35import java.sql.Types;
36import java.time.LocalDate;
37import java.util.Arrays;
38import java.util.HashMap;
39import java.util.Map;
40import java.util.Optional;
41import java.util.Set;
42import java.util.concurrent.ExecutionException;
43import java.util.concurrent.TimeUnit;
44import java.util.logging.Level;
45import org.apache.commons.lang3.tuple.Pair;
46import org.openide.util.NbBundle.Messages;
47import org.sleuthkit.autopsy.casemodule.Case;
48import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.CentralRepoAccountType;
49import static org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil.updateSchemaVersion;
50import org.sleuthkit.autopsy.coreutils.Logger;
51import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
52import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
53import org.sleuthkit.datamodel.Account;
54import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
55import org.sleuthkit.datamodel.HashHitInfo;
56import org.sleuthkit.datamodel.InvalidAccountIDException;
57import org.sleuthkit.datamodel.SleuthkitCase;
58import org.sleuthkit.datamodel.TskData;
59
65abstract class RdbmsCentralRepo implements CentralRepository {
66
67 private final static Logger logger = Logger.getLogger(RdbmsCentralRepo.class.getName());
68 static final String SCHEMA_MAJOR_VERSION_KEY = "SCHEMA_VERSION";
69 static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
70 static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION";
71 static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION";
72 static final CaseDbSchemaVersionNumber SOFTWARE_CR_DB_SCHEMA_VERSION = new CaseDbSchemaVersionNumber(1, 6);
73
74 protected final List<CorrelationAttributeInstance.Type> defaultCorrelationTypes;
75
76 private int bulkArtifactsCount;
77 protected int bulkArtifactsThreshold;
78 private final Map<String, Collection<CorrelationAttributeInstance>> bulkArtifacts;
79 private static final int CASE_CACHE_TIMEOUT = 5;
80 private static final int DATA_SOURCE_CACHE_TIMEOUT = 5;
81 private static final int ACCOUNTS_CACHE_TIMEOUT = 5;
82 private static final Cache<String, Optional<CentralRepoAccountType>> accountTypesCache = CacheBuilder.newBuilder().build();
83 private static final Cache<Pair<CentralRepoAccountType, String>, CentralRepoAccount> accountsCache = CacheBuilder.newBuilder()
84 .expireAfterWrite(ACCOUNTS_CACHE_TIMEOUT, TimeUnit.MINUTES).
85 build();
86
87 private boolean isCRTypeCacheInitialized;
88 private static final Cache<Integer, CorrelationAttributeInstance.Type> typeCache = CacheBuilder.newBuilder().build();
89 private static final Cache<String, CorrelationCase> caseCacheByUUID = CacheBuilder.newBuilder()
90 .expireAfterWrite(CASE_CACHE_TIMEOUT, TimeUnit.MINUTES).
91 build();
92 private static final Cache<Integer, CorrelationCase> caseCacheById = CacheBuilder.newBuilder()
93 .expireAfterWrite(CASE_CACHE_TIMEOUT, TimeUnit.MINUTES).
94 build();
95 private static final Cache<String, CorrelationDataSource> dataSourceCacheByDsObjectId = CacheBuilder.newBuilder()
96 .expireAfterWrite(DATA_SOURCE_CACHE_TIMEOUT, TimeUnit.MINUTES).
97 build();
98 private static final Cache<String, CorrelationDataSource> dataSourceCacheById = CacheBuilder.newBuilder()
99 .expireAfterWrite(DATA_SOURCE_CACHE_TIMEOUT, TimeUnit.MINUTES).
100 build();
101 // Maximum length for the value column in the instance tables
102 static final int MAX_VALUE_LENGTH = 256;
103
104 // number of instances to keep in bulk queue before doing an insert.
105 // Update Test code if this changes. It's hard coded there.
106 static final int DEFAULT_BULK_THRESHHOLD = 1000;
107
108 private static final int QUERY_STR_MAX_LEN = 1000;
109
115 protected RdbmsCentralRepo() throws CentralRepoException {
116 isCRTypeCacheInitialized = false;
117 bulkArtifactsCount = 0;
118 bulkArtifacts = new HashMap<>();
119
120 defaultCorrelationTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes();
121 defaultCorrelationTypes.forEach((type) -> {
122 bulkArtifacts.put(CentralRepoDbUtil.correlationTypeToInstanceTableName(type), new ArrayList<>());
123 });
124 }
125
129 protected abstract Connection connect(boolean foreignKeys) throws CentralRepoException;
130
134 protected abstract Connection connect() throws CentralRepoException;
135
139 protected abstract Connection getEphemeralConnection();
140
149 @Override
150 public void newDbInfo(String name, String value) throws CentralRepoException {
151 Connection conn = connect();
152
153 PreparedStatement preparedStatement = null;
154 String sql = "INSERT INTO db_info (name, value) VALUES (?, ?) "
155 + getConflictClause();
156 try {
157 preparedStatement = conn.prepareStatement(sql);
158 preparedStatement.setString(1, name);
159 preparedStatement.setString(2, value);
160 preparedStatement.executeUpdate();
161 } catch (SQLException ex) {
162 throw new CentralRepoException("Error adding new name/value pair to db_info.", ex);
163 } finally {
164 CentralRepoDbUtil.closeStatement(preparedStatement);
165 CentralRepoDbUtil.closeConnection(conn);
166 }
167
168 }
169
170 @Override
171 public void addDataSourceObjectId(int rowId, long dataSourceObjectId) throws CentralRepoException {
172 Connection conn = connect();
173 PreparedStatement preparedStatement = null;
174 String sql = "UPDATE data_sources SET datasource_obj_id=? WHERE id=?";
175 try {
176 preparedStatement = conn.prepareStatement(sql);
177 preparedStatement.setLong(1, dataSourceObjectId);
178 preparedStatement.setInt(2, rowId);
179 preparedStatement.executeUpdate();
180 } catch (SQLException ex) {
181 throw new CentralRepoException("Error updating data source object id for data_sources row " + rowId, ex);
182 } finally {
183 CentralRepoDbUtil.closeStatement(preparedStatement);
184 CentralRepoDbUtil.closeConnection(conn);
185 }
186 }
187
197 @Override
198 public String getDbInfo(String name) throws CentralRepoException {
199 Connection conn = connect();
200
201 PreparedStatement preparedStatement = null;
202 ResultSet resultSet = null;
203 String value = null;
204 String sql = "SELECT value FROM db_info WHERE name=?";
205 try {
206 preparedStatement = conn.prepareStatement(sql);
207 preparedStatement.setString(1, name);
208 resultSet = preparedStatement.executeQuery();
209 if (resultSet.next()) {
210 value = resultSet.getString("value");
211 }
212 } catch (SQLException ex) {
213 throw new CentralRepoException("Error getting value for name.", ex);
214 } finally {
215 CentralRepoDbUtil.closeResultSet(resultSet);
216 CentralRepoDbUtil.closeStatement(preparedStatement);
217 CentralRepoDbUtil.closeConnection(conn);
218 }
219
220 return value;
221 }
222
226 public final void clearCaches() {
227 synchronized (typeCache) {
228 typeCache.invalidateAll();
229 isCRTypeCacheInitialized = false;
230 }
231 caseCacheByUUID.invalidateAll();
232 caseCacheById.invalidateAll();
233 dataSourceCacheByDsObjectId.invalidateAll();
234 dataSourceCacheById.invalidateAll();
235 accountsCache.invalidateAll();
236 }
237
246 @Override
247 public void updateDbInfo(String name, String value) throws CentralRepoException {
248 Connection conn = connect();
249
250 PreparedStatement preparedStatement = null;
251 String sql = "UPDATE db_info SET value=? WHERE name=?";
252 try {
253 preparedStatement = conn.prepareStatement(sql);
254 preparedStatement.setString(1, value);
255 preparedStatement.setString(2, name);
256 preparedStatement.executeUpdate();
257 } catch (SQLException ex) {
258 throw new CentralRepoException("Error updating value for name.", ex);
259 } finally {
260 CentralRepoDbUtil.closeStatement(preparedStatement);
261 CentralRepoDbUtil.closeConnection(conn);
262 }
263 }
264
274 @Override
275 public synchronized CorrelationCase newCase(CorrelationCase eamCase) throws CentralRepoException {
276
277 if (eamCase.getCaseUUID() == null) {
278 throw new CentralRepoException("Case UUID is null");
279 }
280
281 // check if there is already an existing CorrelationCase for this Case
282 CorrelationCase cRCase = getCaseByUUID(eamCase.getCaseUUID());
283 if (cRCase != null) {
284 return cRCase;
285 }
286
287 Connection conn = connect();
288 PreparedStatement preparedStatement = null;
289
290 String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
291 + "examiner_name, examiner_email, examiner_phone, notes) "
292 + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
293 + getConflictClause();
294 ResultSet resultSet = null;
295 try {
296 preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
297
298 preparedStatement.setString(1, eamCase.getCaseUUID());
299 if (null == eamCase.getOrg()) {
300 preparedStatement.setNull(2, Types.INTEGER);
301 } else {
302 preparedStatement.setInt(2, eamCase.getOrg().getOrgID());
303 }
304 preparedStatement.setString(3, eamCase.getDisplayName());
305 preparedStatement.setString(4, eamCase.getCreationDate());
306 if ("".equals(eamCase.getCaseNumber())) {
307 preparedStatement.setNull(5, Types.INTEGER);
308 } else {
309 preparedStatement.setString(5, eamCase.getCaseNumber());
310 }
311 if ("".equals(eamCase.getExaminerName())) {
312 preparedStatement.setNull(6, Types.INTEGER);
313 } else {
314 preparedStatement.setString(6, eamCase.getExaminerName());
315 }
316 if ("".equals(eamCase.getExaminerEmail())) {
317 preparedStatement.setNull(7, Types.INTEGER);
318 } else {
319 preparedStatement.setString(7, eamCase.getExaminerEmail());
320 }
321 if ("".equals(eamCase.getExaminerPhone())) {
322 preparedStatement.setNull(8, Types.INTEGER);
323 } else {
324 preparedStatement.setString(8, eamCase.getExaminerPhone());
325 }
326 if ("".equals(eamCase.getNotes())) {
327 preparedStatement.setNull(9, Types.INTEGER);
328 } else {
329 preparedStatement.setString(9, eamCase.getNotes());
330 }
331
332 preparedStatement.executeUpdate();
333 //update the case in the caches
334 resultSet = preparedStatement.getGeneratedKeys();
335 if (!resultSet.next()) {
336 throw new CentralRepoException(String.format("Failed to INSERT case %s in central repo", eamCase.getCaseUUID()));
337 }
338 int caseID = resultSet.getInt(1); //last_insert_rowid()
339 CorrelationCase correlationCase = new CorrelationCase(caseID, eamCase.getCaseUUID(), eamCase.getOrg(),
340 eamCase.getDisplayName(), eamCase.getCreationDate(), eamCase.getCaseNumber(), eamCase.getExaminerName(),
341 eamCase.getExaminerEmail(), eamCase.getExaminerPhone(), eamCase.getNotes());
342 caseCacheByUUID.put(eamCase.getCaseUUID(), correlationCase);
343 caseCacheById.put(caseID, correlationCase);
344 } catch (SQLException ex) {
345 throw new CentralRepoException("Error inserting new case.", ex); // NON-NLS
346 } finally {
347 CentralRepoDbUtil.closeResultSet(resultSet);
348 CentralRepoDbUtil.closeStatement(preparedStatement);
349 CentralRepoDbUtil.closeConnection(conn);
350 }
351
352 // get a new version with the updated ID
353 return getCaseByUUID(eamCase.getCaseUUID());
354 }
355
361 @Override
362 public CorrelationCase newCase(Case autopsyCase) throws CentralRepoException {
363 if (autopsyCase == null) {
364 throw new CentralRepoException("Case is null");
365 }
366
367 CorrelationCase curCeCase = new CorrelationCase(
368 -1,
369 autopsyCase.getName(), // unique case ID
370 CentralRepoOrganization.getDefault(),
371 autopsyCase.getDisplayName(),
372 autopsyCase.getCreatedDate(),
373 autopsyCase.getNumber(),
374 autopsyCase.getExaminer(),
375 autopsyCase.getExaminerEmail(),
376 autopsyCase.getExaminerPhone(),
377 autopsyCase.getCaseNotes());
378 return newCase(curCeCase);
379 }
380
381 @Override
382 public CorrelationCase getCase(Case autopsyCase) throws CentralRepoException {
383 return getCaseByUUID(autopsyCase.getName());
384 }
385
391 @Override
392 public void updateCase(CorrelationCase eamCase) throws CentralRepoException {
393 if (eamCase == null) {
394 throw new CentralRepoException("Correlation case is null");
395 }
396
397 Connection conn = connect();
398
399 PreparedStatement preparedStatement = null;
400 String sql = "UPDATE cases "
401 + "SET org_id=?, case_name=?, creation_date=?, case_number=?, examiner_name=?, examiner_email=?, examiner_phone=?, notes=? "
402 + "WHERE case_uid=?";
403
404 try {
405 preparedStatement = conn.prepareStatement(sql);
406
407 if (null == eamCase.getOrg()) {
408 preparedStatement.setNull(1, Types.INTEGER);
409 } else {
410 preparedStatement.setInt(1, eamCase.getOrg().getOrgID());
411 }
412 preparedStatement.setString(2, eamCase.getDisplayName());
413 preparedStatement.setString(3, eamCase.getCreationDate());
414
415 if ("".equals(eamCase.getCaseNumber())) {
416 preparedStatement.setNull(4, Types.INTEGER);
417 } else {
418 preparedStatement.setString(4, eamCase.getCaseNumber());
419 }
420 if ("".equals(eamCase.getExaminerName())) {
421 preparedStatement.setNull(5, Types.INTEGER);
422 } else {
423 preparedStatement.setString(5, eamCase.getExaminerName());
424 }
425 if ("".equals(eamCase.getExaminerEmail())) {
426 preparedStatement.setNull(6, Types.INTEGER);
427 } else {
428 preparedStatement.setString(6, eamCase.getExaminerEmail());
429 }
430 if ("".equals(eamCase.getExaminerPhone())) {
431 preparedStatement.setNull(7, Types.INTEGER);
432 } else {
433 preparedStatement.setString(7, eamCase.getExaminerPhone());
434 }
435 if ("".equals(eamCase.getNotes())) {
436 preparedStatement.setNull(8, Types.INTEGER);
437 } else {
438 preparedStatement.setString(8, eamCase.getNotes());
439 }
440
441 preparedStatement.setString(9, eamCase.getCaseUUID());
442
443 preparedStatement.executeUpdate();
444 //update the case in the cache
445 caseCacheById.put(eamCase.getID(), eamCase);
446 caseCacheByUUID.put(eamCase.getCaseUUID(), eamCase);
447 } catch (SQLException ex) {
448 throw new CentralRepoException("Error updating case.", ex); // NON-NLS
449 } finally {
450 CentralRepoDbUtil.closeStatement(preparedStatement);
451 CentralRepoDbUtil.closeConnection(conn);
452 }
453 }
454
462 @Override
463 public CorrelationCase getCaseByUUID(String caseUUID) throws CentralRepoException {
464 try {
465 return caseCacheByUUID.get(caseUUID, () -> getCaseByUUIDFromCr(caseUUID));
466 } catch (CacheLoader.InvalidCacheLoadException ignored) {
467 //lambda valueloader returned a null value and cache can not store null values this is normal if the case does not exist in the central repo yet
468 return null;
469 } catch (ExecutionException ex) {
470 throw new CentralRepoException("Error getting autopsy case from Central repo", ex);
471 }
472 }
473
481 private CorrelationCase getCaseByUUIDFromCr(String caseUUID) throws CentralRepoException {
482 Connection conn = connect();
483
484 CorrelationCase eamCaseResult = null;
485 PreparedStatement preparedStatement = null;
486 ResultSet resultSet = null;
487
488 String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
489 + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
490 + "FROM cases "
491 + "LEFT JOIN organizations ON cases.org_id=organizations.id "
492 + "WHERE case_uid=?";
493
494 try {
495 preparedStatement = conn.prepareStatement(sql);
496 preparedStatement.setString(1, caseUUID);
497 resultSet = preparedStatement.executeQuery();
498 if (resultSet.next()) {
499 eamCaseResult = getEamCaseFromResultSet(resultSet);
500 }
501 if (eamCaseResult != null) {
502 //Update the version in the other cache
503 caseCacheById.put(eamCaseResult.getID(), eamCaseResult);
504 }
505 } catch (SQLException ex) {
506 throw new CentralRepoException("Error getting case details.", ex); // NON-NLS
507 } finally {
508 CentralRepoDbUtil.closeResultSet(resultSet);
509 CentralRepoDbUtil.closeStatement(preparedStatement);
510 CentralRepoDbUtil.closeConnection(conn);
511 }
512
513 return eamCaseResult;
514 }
515
523 @Override
524 public CorrelationCase getCaseById(int caseId) throws CentralRepoException {
525 try {
526 return caseCacheById.get(caseId, () -> getCaseByIdFromCr(caseId));
527 } catch (CacheLoader.InvalidCacheLoadException ignored) {
528 //lambda valueloader returned a null value and cache can not store null values this is normal if the case does not exist in the central repo yet
529 return null;
530 } catch (ExecutionException ex) {
531 throw new CentralRepoException("Error getting autopsy case from Central repo", ex);
532 }
533 }
534
542 private CorrelationCase getCaseByIdFromCr(int caseId) throws CentralRepoException {
543 Connection conn = connect();
544
545 CorrelationCase eamCaseResult = null;
546 PreparedStatement preparedStatement = null;
547 ResultSet resultSet = null;
548
549 String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
550 + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
551 + "FROM cases "
552 + "LEFT JOIN organizations ON cases.org_id=organizations.id "
553 + "WHERE cases.id=?";
554 try {
555 preparedStatement = conn.prepareStatement(sql);
556 preparedStatement.setInt(1, caseId);
557 resultSet = preparedStatement.executeQuery();
558 if (resultSet.next()) {
559 eamCaseResult = getEamCaseFromResultSet(resultSet);
560 }
561 if (eamCaseResult != null) {
562 //Update the version in the other cache
563 caseCacheByUUID.put(eamCaseResult.getCaseUUID(), eamCaseResult);
564 }
565 } catch (SQLException ex) {
566 throw new CentralRepoException("Error getting case details.", ex); // NON-NLS
567 } finally {
568 CentralRepoDbUtil.closeResultSet(resultSet);
569 CentralRepoDbUtil.closeStatement(preparedStatement);
570 CentralRepoDbUtil.closeConnection(conn);
571 }
572
573 return eamCaseResult;
574 }
575
581 @Override
582 public List<CorrelationCase> getCases() throws CentralRepoException {
583 Connection conn = connect();
584
585 List<CorrelationCase> cases = new ArrayList<>();
586 CorrelationCase eamCaseResult;
587 PreparedStatement preparedStatement = null;
588 ResultSet resultSet = null;
589
590 String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
591 + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
592 + "FROM cases "
593 + "LEFT JOIN organizations ON cases.org_id=organizations.id";
594
595 try {
596 preparedStatement = conn.prepareStatement(sql);
597 resultSet = preparedStatement.executeQuery();
598 while (resultSet.next()) {
599 eamCaseResult = getEamCaseFromResultSet(resultSet);
600 cases.add(eamCaseResult);
601 }
602 } catch (SQLException ex) {
603 throw new CentralRepoException("Error getting all cases.", ex); // NON-NLS
604 } finally {
605 CentralRepoDbUtil.closeResultSet(resultSet);
606 CentralRepoDbUtil.closeStatement(preparedStatement);
607 CentralRepoDbUtil.closeConnection(conn);
608 }
609
610 return cases;
611 }
612
623 private static String getDataSourceByDSObjectIdCacheKey(int caseId, Long dataSourceObjectId) {
624 return "Case" + caseId + "DsObjectId" + dataSourceObjectId; //NON-NLS
625 }
626
636 private static String getDataSourceByIdCacheKey(int caseId, int dataSourceId) {
637 return "Case" + caseId + "Id" + dataSourceId; //NON-NLS
638 }
639
645 @Override
646 public CorrelationDataSource newDataSource(CorrelationDataSource eamDataSource) throws CentralRepoException {
647 if (eamDataSource.getCaseID() == -1) {
648 throw new CentralRepoException("Case ID is -1");
649 }
650 if (eamDataSource.getDeviceID() == null) {
651 throw new CentralRepoException("Device ID is null");
652 }
653 if (eamDataSource.getName() == null) {
654 throw new CentralRepoException("Name is null");
655 }
656 if (eamDataSource.getID() != -1) {
657 // This data source is already in the central repo
658 return eamDataSource;
659 }
660
661 Connection conn = connect();
662
663 PreparedStatement preparedStatement = null;
664 //The conflict clause exists in case multiple nodes are trying to add the data source because it did not exist at the same time
665 String sql = "INSERT INTO data_sources(device_id, case_id, name, datasource_obj_id, md5, sha1, sha256) VALUES (?, ?, ?, ?, ?, ?, ?) "
666 + getConflictClause();
667 ResultSet resultSet = null;
668 try {
669 preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
670
671 preparedStatement.setString(1, eamDataSource.getDeviceID());
672 preparedStatement.setInt(2, eamDataSource.getCaseID());
673 preparedStatement.setString(3, eamDataSource.getName());
674 preparedStatement.setLong(4, eamDataSource.getDataSourceObjectID());
675 preparedStatement.setString(5, eamDataSource.getMd5());
676 preparedStatement.setString(6, eamDataSource.getSha1());
677 preparedStatement.setString(7, eamDataSource.getSha256());
678
679 preparedStatement.executeUpdate();
680 resultSet = preparedStatement.getGeneratedKeys();
681 if (!resultSet.next()) {
682 /*
683 * If nothing was inserted, then return the data source that
684 * exists in the Central Repository.
685 *
686 * This is expected to occur with PostgreSQL Central Repository
687 * databases.
688 */
689 try {
690 return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(
691 eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()),
692 () -> getDataSourceFromCr(eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()));
693 } catch (CacheLoader.InvalidCacheLoadException | ExecutionException getException) {
694 throw new CentralRepoException(String.format("Unable to to INSERT or get data source %s in central repo:", eamDataSource.getName()), getException);
695 }
696 } else {
697 //if a new data source was added to the central repository update the caches to include it and return it
698 int dataSourceId = resultSet.getInt(1); //last_insert_rowid()
699 CorrelationDataSource dataSource = new CorrelationDataSource(eamDataSource.getCaseID(), dataSourceId, eamDataSource.getDeviceID(), eamDataSource.getName(), eamDataSource.getDataSourceObjectID(), eamDataSource.getMd5(), eamDataSource.getSha1(), eamDataSource.getSha256());
700 dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(dataSource.getCaseID(), dataSource.getDataSourceObjectID()), dataSource);
701 dataSourceCacheById.put(getDataSourceByIdCacheKey(dataSource.getCaseID(), dataSource.getID()), dataSource);
702 return dataSource;
703 }
704
705 } catch (SQLException insertException) {
706 /*
707 * If an exception was thrown causing us to not return a new data
708 * source, attempt to get an existing data source with the same case
709 * ID and data source object ID.
710 *
711 * This exception block is expected to occur with SQLite Central
712 * Repository databases.
713 */
714 try {
715 return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(
716 eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()),
717 () -> getDataSourceFromCr(eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()));
718 } catch (CacheLoader.InvalidCacheLoadException | ExecutionException getException) {
719 throw new CentralRepoException(String.format("Unable to to INSERT or get data source %s in central repo, insert failed due to Exception: %s", eamDataSource.getName(), insertException.getMessage()), getException);
720 }
721 } finally {
722 CentralRepoDbUtil.closeResultSet(resultSet);
723 CentralRepoDbUtil.closeStatement(preparedStatement);
724 CentralRepoDbUtil.closeConnection(conn);
725 }
726 }
727
739 @Override
740 public CorrelationDataSource getDataSource(CorrelationCase correlationCase, Long dataSourceObjectId) throws CentralRepoException {
741
742 if (correlationCase == null) {
743 throw new CentralRepoException("Correlation case is null");
744 }
745 try {
746 return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(correlationCase.getID(), dataSourceObjectId), () -> getDataSourceFromCr(correlationCase.getID(), dataSourceObjectId));
747 } catch (CacheLoader.InvalidCacheLoadException ignored) {
748 //lambda valueloader returned a null value and cache can not store null values this is normal if the dataSource does not exist in the central repo yet
749 return null;
750 } catch (ExecutionException ex) {
751 throw new CentralRepoException("Error getting data source from central repository", ex);
752 }
753 }
754
767 private CorrelationDataSource getDataSourceFromCr(int correlationCaseId, Long dataSourceObjectId) throws CentralRepoException {
768 Connection conn = connect();
769
770 CorrelationDataSource eamDataSourceResult = null;
771 PreparedStatement preparedStatement = null;
772 ResultSet resultSet = null;
773
774 String sql = "SELECT * FROM data_sources WHERE datasource_obj_id=? AND case_id=?"; // NON-NLS
775
776 try {
777 preparedStatement = conn.prepareStatement(sql);
778 preparedStatement.setLong(1, dataSourceObjectId);
779 preparedStatement.setInt(2, correlationCaseId);
780 resultSet = preparedStatement.executeQuery();
781 if (resultSet.next()) {
782 eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
783 }
784 if (eamDataSourceResult != null) {
785 dataSourceCacheById.put(getDataSourceByIdCacheKey(correlationCaseId, eamDataSourceResult.getID()), eamDataSourceResult);
786 }
787 } catch (SQLException ex) {
788 throw new CentralRepoException("Error getting data source.", ex); // NON-NLS
789 } finally {
790 CentralRepoDbUtil.closeResultSet(resultSet);
791 CentralRepoDbUtil.closeStatement(preparedStatement);
792 CentralRepoDbUtil.closeConnection(conn);
793 }
794
795 return eamDataSourceResult;
796 }
797
807 @Override
808 public CorrelationDataSource getDataSourceById(CorrelationCase correlationCase, int dataSourceId) throws CentralRepoException {
809 if (correlationCase == null) {
810 throw new CentralRepoException("Correlation case is null");
811 }
812 try {
813 return dataSourceCacheById.get(getDataSourceByIdCacheKey(correlationCase.getID(), dataSourceId), () -> getDataSourceByIdFromCr(correlationCase, dataSourceId));
814 } catch (CacheLoader.InvalidCacheLoadException ignored) {
815 //lambda valueloader returned a null value and cache can not store null values this is normal if the dataSource does not exist in the central repo yet
816 return null;
817 } catch (ExecutionException ex) {
818 throw new CentralRepoException("Error getting data source from central repository", ex);
819 }
820 }
821
831 private CorrelationDataSource getDataSourceByIdFromCr(CorrelationCase correlationCase, int dataSourceId) throws CentralRepoException {
832 Connection conn = connect();
833
834 CorrelationDataSource eamDataSourceResult = null;
835 PreparedStatement preparedStatement = null;
836 ResultSet resultSet = null;
837
838 String sql = "SELECT * FROM data_sources WHERE id=? AND case_id=?"; // NON-NLS
839
840 try {
841 preparedStatement = conn.prepareStatement(sql);
842 preparedStatement.setInt(1, dataSourceId);
843 preparedStatement.setInt(2, correlationCase.getID());
844 resultSet = preparedStatement.executeQuery();
845 if (resultSet.next()) {
846 eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
847 }
848 if (eamDataSourceResult != null) {
849 dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(correlationCase.getID(), eamDataSourceResult.getDataSourceObjectID()), eamDataSourceResult);
850 }
851 } catch (SQLException ex) {
852 throw new CentralRepoException("Error getting data source.", ex); // NON-NLS
853 } finally {
854 CentralRepoDbUtil.closeResultSet(resultSet);
855 CentralRepoDbUtil.closeStatement(preparedStatement);
856 CentralRepoDbUtil.closeConnection(conn);
857 }
858
859 return eamDataSourceResult;
860 }
861
867 @Override
868 public List<CorrelationDataSource> getDataSources() throws CentralRepoException {
869 Connection conn = connect();
870
871 List<CorrelationDataSource> dataSources = new ArrayList<>();
872 CorrelationDataSource eamDataSourceResult;
873 PreparedStatement preparedStatement = null;
874 ResultSet resultSet = null;
875
876 String sql = "SELECT * FROM data_sources";
877
878 try {
879 preparedStatement = conn.prepareStatement(sql);
880 resultSet = preparedStatement.executeQuery();
881 while (resultSet.next()) {
882 eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
883 dataSources.add(eamDataSourceResult);
884 }
885 } catch (SQLException ex) {
886 throw new CentralRepoException("Error getting all data sources.", ex); // NON-NLS
887 } finally {
888 CentralRepoDbUtil.closeResultSet(resultSet);
889 CentralRepoDbUtil.closeStatement(preparedStatement);
890 CentralRepoDbUtil.closeConnection(conn);
891 }
892
893 return dataSources;
894 }
895
901 @Override
902 public void updateDataSourceMd5Hash(CorrelationDataSource eamDataSource) throws CentralRepoException {
903 updateDataSourceStringValue(eamDataSource, "md5", eamDataSource.getMd5());
904 }
905
911 @Override
912 public void updateDataSourceSha1Hash(CorrelationDataSource eamDataSource) throws CentralRepoException {
913 updateDataSourceStringValue(eamDataSource, "sha1", eamDataSource.getSha1());
914 }
915
922 @Override
923 public void updateDataSourceSha256Hash(CorrelationDataSource eamDataSource) throws CentralRepoException {
924 updateDataSourceStringValue(eamDataSource, "sha256", eamDataSource.getSha256());
925 }
926
934 private void updateDataSourceStringValue(CorrelationDataSource eamDataSource, String column, String value) throws CentralRepoException {
935 if (eamDataSource == null) {
936 throw new CentralRepoException("Correlation data source is null");
937 }
938
939 Connection conn = connect();
940
941 PreparedStatement preparedStatement = null;
942 String sql = "UPDATE data_sources "
943 + "SET " + column + "=? "
944 + "WHERE id=?";
945
946 try {
947 preparedStatement = conn.prepareStatement(sql);
948
949 preparedStatement.setString(1, value);
950 preparedStatement.setInt(2, eamDataSource.getID());
951
952 preparedStatement.executeUpdate();
953 //update the case in the cache
954 dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()), eamDataSource);
955 dataSourceCacheById.put(getDataSourceByIdCacheKey(eamDataSource.getCaseID(), eamDataSource.getID()), eamDataSource);
956 } catch (SQLException ex) {
957 throw new CentralRepoException(String.format("Error updating data source (obj_id=%d).", eamDataSource.getDataSourceObjectID()), ex); // NON-NLS
958 } finally {
959 CentralRepoDbUtil.closeStatement(preparedStatement);
960 CentralRepoDbUtil.closeConnection(conn);
961 }
962 }
963
972 @Override
973 public void updateDataSourceName(CorrelationDataSource eamDataSource, String newName) throws CentralRepoException {
974
975 Connection conn = connect();
976
977 PreparedStatement preparedStatement = null;
978
979 String sql = "UPDATE data_sources SET name = ? WHERE id = ?";
980
981 try {
982 preparedStatement = conn.prepareStatement(sql);
983 preparedStatement.setString(1, newName);
984 preparedStatement.setInt(2, eamDataSource.getID());
985 preparedStatement.executeUpdate();
986
987 CorrelationDataSource updatedDataSource = new CorrelationDataSource(
988 eamDataSource.getCaseID(),
989 eamDataSource.getID(),
990 eamDataSource.getDeviceID(),
991 newName,
992 eamDataSource.getDataSourceObjectID(),
993 eamDataSource.getMd5(),
994 eamDataSource.getSha1(),
995 eamDataSource.getSha256());
996
997 dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(updatedDataSource.getCaseID(), updatedDataSource.getDataSourceObjectID()), updatedDataSource);
998 dataSourceCacheById.put(getDataSourceByIdCacheKey(updatedDataSource.getCaseID(), updatedDataSource.getID()), updatedDataSource);
999 } catch (SQLException ex) {
1000 throw new CentralRepoException("Error updating name of data source with ID " + eamDataSource.getDataSourceObjectID()
1001 + " to " + newName, ex); // NON-NLS
1002 } finally {
1003 CentralRepoDbUtil.closeStatement(preparedStatement);
1004 CentralRepoDbUtil.closeConnection(conn);
1005 }
1006 }
1007
1014 @Override
1015 public void addArtifactInstance(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1016 checkAddArtifactInstanceNulls(eamArtifact);
1017
1018 // @@@ We should cache the case and data source IDs in memory
1019 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1020 boolean artifactHasAnAccount = CentralRepoDbUtil.correlationAttribHasAnAccount(eamArtifact.getCorrelationType());
1021
1022 String sql;
1023 // _instance table for accounts have an additional account_id column
1024 if (artifactHasAnAccount) {
1025 sql = "INSERT INTO "
1026 + tableName
1027 + "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id, account_id) "
1028 + "VALUES (?, ?, ?, ?, ?, ?, ?, ?) "
1029 + getConflictClause();
1030 } else {
1031 sql = "INSERT INTO "
1032 + tableName
1033 + "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
1034 + "VALUES (?, ?, ?, ?, ?, ?, ?) "
1035 + getConflictClause();
1036 }
1037
1038 try (Connection conn = connect();
1039 PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
1040
1041 if (!eamArtifact.getCorrelationValue().isEmpty()) {
1042 preparedStatement.setInt(1, eamArtifact.getCorrelationCase().getID());
1043 preparedStatement.setInt(2, eamArtifact.getCorrelationDataSource().getID());
1044 preparedStatement.setString(3, eamArtifact.getCorrelationValue());
1045 preparedStatement.setString(4, eamArtifact.getFilePath().toLowerCase());
1046 preparedStatement.setByte(5, eamArtifact.getKnownStatus().getFileKnownValue());
1047
1048 if ("".equals(eamArtifact.getComment())) {
1049 preparedStatement.setNull(6, Types.INTEGER);
1050 } else {
1051 preparedStatement.setString(6, eamArtifact.getComment());
1052 }
1053 preparedStatement.setLong(7, eamArtifact.getFileObjectId());
1054
1055 // set in the accountId only for artifacts that represent accounts
1056 if (artifactHasAnAccount) {
1057 if (eamArtifact.getAccountId() >= 0) {
1058 preparedStatement.setLong(8, eamArtifact.getAccountId());
1059 } else {
1060 preparedStatement.setNull(8, Types.INTEGER);
1061 }
1062 }
1063
1064 preparedStatement.executeUpdate();
1065 }
1066
1067 } catch (SQLException ex) {
1068 throw new CentralRepoException("Error inserting new artifact into artifacts table.", ex); // NON-NLS
1069 }
1070 }
1071
1084 @Override
1085 public CentralRepoAccount getOrCreateAccount(CentralRepoAccountType crAccountType, String accountUniqueID) throws InvalidAccountIDException, CentralRepoException {
1086 // Get the account fom the accounts table
1087 String normalizedAccountID = CentralRepoAccount.normalizeAccountIdentifier(crAccountType, accountUniqueID);
1088
1089 // insert the account. If there is a conflict, ignore it.
1090 String insertSQL;
1091 switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
1092 case POSTGRESQL:
1093 insertSQL = "INSERT INTO accounts (account_type_id, account_unique_identifier) VALUES (?, ?) " + getConflictClause(); //NON-NLS
1094 break;
1095 case SQLITE:
1096 insertSQL = "INSERT OR IGNORE INTO accounts (account_type_id, account_unique_identifier) VALUES (?, ?) "; //NON-NLS
1097 break;
1098 default:
1099 throw new CentralRepoException(String.format("Cannot add account to currently selected CR database platform %s", CentralRepoDbManager.getSavedDbChoice().getDbPlatform())); //NON-NLS
1100 }
1101
1102 try (Connection connection = connect();
1103 PreparedStatement preparedStatement = connection.prepareStatement(insertSQL);) {
1104
1105 preparedStatement.setInt(1, crAccountType.getAccountTypeId());
1106 preparedStatement.setString(2, normalizedAccountID);
1107
1108 preparedStatement.executeUpdate();
1109
1110 // get the account from the db - should exist now.
1111 return getAccount(crAccountType, normalizedAccountID);
1112 } catch (SQLException ex) {
1113 throw new CentralRepoException("Error adding an account to CR database.", ex);
1114 }
1115 }
1116
1117 @Override
1118 public Optional<CentralRepoAccountType> getAccountTypeByName(String accountTypeName) throws CentralRepoException {
1119 try {
1120 return accountTypesCache.get(accountTypeName, () -> getCRAccountTypeFromDb(accountTypeName));
1121 } catch (CacheLoader.InvalidCacheLoadException | ExecutionException ex) {
1122 throw new CentralRepoException("Error looking up CR account type in cache.", ex);
1123 }
1124 }
1125
1126 @Override
1127 public Collection<CentralRepoAccountType> getAllAccountTypes() throws CentralRepoException {
1128
1129 Collection<CentralRepoAccountType> accountTypes = new ArrayList<>();
1130
1131 String sql = "SELECT * FROM account_types";
1132 try (Connection conn = connect();
1133 PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
1134
1135 try (ResultSet resultSet = preparedStatement.executeQuery();) {
1136 while (resultSet.next()) {
1137 Account.Type acctType = new Account.Type(resultSet.getString("type_name"), resultSet.getString("display_name"));
1138 CentralRepoAccountType crAccountType = new CentralRepoAccountType(resultSet.getInt("id"), acctType, resultSet.getInt("correlation_type_id"));
1139
1140 accountTypes.add(crAccountType);
1141 }
1142 }
1143 } catch (SQLException ex) {
1144 throw new CentralRepoException("Error getting account types from central repository.", ex); // NON-NLS
1145 }
1146 return accountTypes;
1147 }
1148
1158 private Optional<CentralRepoAccountType> getCRAccountTypeFromDb(String accountTypeName) throws CentralRepoException {
1159
1160 String sql = "SELECT * FROM account_types WHERE type_name = ?";
1161 try (Connection conn = connect();
1162 PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
1163
1164 preparedStatement.setString(1, accountTypeName);
1165 try (ResultSet resultSet = preparedStatement.executeQuery();) {
1166 if (resultSet.next()) {
1167 Account.Type acctType = new Account.Type(accountTypeName, resultSet.getString("display_name"));
1168 CentralRepoAccountType crAccountType = new CentralRepoAccountType(resultSet.getInt("id"), acctType, resultSet.getInt("correlation_type_id"));
1169 accountTypesCache.put(accountTypeName, Optional.of(crAccountType));
1170 return Optional.of(crAccountType);
1171 } else {
1172 accountTypesCache.put(accountTypeName, Optional.empty());
1173 return Optional.empty();
1174 }
1175 }
1176 } catch (SQLException ex) {
1177 throw new CentralRepoException("Error getting correlation type by id.", ex); // NON-NLS
1178 }
1179 }
1180
1199 @Override
1200 public CentralRepoAccount getAccount(CentralRepoAccountType crAccountType, String accountUniqueID) throws InvalidAccountIDException, CentralRepoException {
1201 String normalizedAccountID = CentralRepoAccount.normalizeAccountIdentifier(crAccountType, accountUniqueID);
1202 CentralRepoAccount crAccount = accountsCache.getIfPresent(Pair.of(crAccountType, normalizedAccountID));
1203 if (crAccount == null) {
1204 crAccount = getCRAccountFromDb(crAccountType, normalizedAccountID);
1205 if (crAccount != null) {
1206 accountsCache.put(Pair.of(crAccountType, normalizedAccountID), crAccount);
1207 }
1208 }
1209
1210 return crAccount;
1211 }
1212
1225 private CentralRepoAccount getCRAccountFromDb(CentralRepoAccountType crAccountType, String accountUniqueID) throws CentralRepoException {
1226
1227 CentralRepoAccount account = null;
1228
1229 String sql = "SELECT * FROM accounts WHERE account_type_id = ? AND account_unique_identifier = ?";
1230 try (Connection connection = connect();
1231 PreparedStatement preparedStatement = connection.prepareStatement(sql);) {
1232
1233 preparedStatement.setInt(1, crAccountType.getAccountTypeId());
1234 preparedStatement.setString(2, accountUniqueID);
1235
1236 try (ResultSet resultSet = preparedStatement.executeQuery();) {
1237 if (resultSet.next()) {
1238 account = new CentralRepoAccount(resultSet.getInt("id"), crAccountType, resultSet.getString("account_unique_identifier")); //NON-NLS
1239 }
1240 }
1241 } catch (SQLException ex) {
1242 throw new CentralRepoException("Error getting account type id", ex);
1243 }
1244
1245 return account;
1246 }
1247
1248 private void checkAddArtifactInstanceNulls(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1249 if (eamArtifact == null) {
1250 throw new CentralRepoException("CorrelationAttribute is null");
1251 }
1252 if (eamArtifact.getCorrelationType() == null) {
1253 throw new CentralRepoException("Correlation type is null");
1254 }
1255 if (eamArtifact.getCorrelationValue() == null) {
1256 throw new CentralRepoException("Correlation value is null");
1257 }
1258 if (eamArtifact.getCorrelationValue().length() >= MAX_VALUE_LENGTH) {
1259 throw new CentralRepoException("Artifact value too long for central repository."
1260 + "\nCorrelationArtifact ID: " + eamArtifact.getID()
1261 + "\nCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1262 + "\nCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1263
1264 }
1265 if (eamArtifact.getCorrelationCase() == null) {
1266 throw new CentralRepoException("CorrelationAttributeInstance case is null");
1267 }
1268 if (eamArtifact.getCorrelationDataSource() == null) {
1269 throw new CentralRepoException("CorrelationAttributeInstance data source is null");
1270 }
1271 if (eamArtifact.getKnownStatus() == null) {
1272 throw new CentralRepoException("CorrelationAttributeInstance known status is null");
1273 }
1274 }
1275
1276 @Override
1277 public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
1278 if (value == null) {
1279 throw new CentralRepoException("Cannot get artifact instances for null value");
1280 }
1281 return getArtifactInstancesByTypeValues(aType, Arrays.asList(value));
1282 }
1283
1284 @Override
1285 public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValues(CorrelationAttributeInstance.Type aType, List<String> values) throws CentralRepoException, CorrelationAttributeNormalizationException {
1286 if (aType == null) {
1287 throw new CentralRepoException("Cannot get artifact instances for null type");
1288 }
1289 if (values == null || values.isEmpty()) {
1290 throw new CentralRepoException("Cannot get artifact instances without specified values");
1291 }
1292 return getCorrAttrInstances(prepareGetInstancesSql(aType, values), aType);
1293 }
1294
1295 @Override
1296 public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValuesAndCases(CorrelationAttributeInstance.Type aType, List<String> values, List<Integer> caseIds) throws CentralRepoException, CorrelationAttributeNormalizationException {
1297 if (aType == null) {
1298 throw new CentralRepoException("Cannot get artifact instances for null type");
1299 }
1300 if (values == null || values.isEmpty()) {
1301 throw new CentralRepoException("Cannot get artifact instances without specified values");
1302 }
1303 if (caseIds == null || caseIds.isEmpty()) {
1304 throw new CentralRepoException("Cannot get artifact instances without specified cases");
1305 }
1306 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1307 String sql
1308 = " and "
1309 + tableName
1310 + ".case_id in ('";
1311 StringBuilder inValuesBuilder = new StringBuilder(prepareGetInstancesSql(aType, values));
1312 inValuesBuilder.append(sql);
1313 inValuesBuilder.append(caseIds.stream().map(String::valueOf).collect(Collectors.joining("', '")));
1314 inValuesBuilder.append("')");
1315 return getCorrAttrInstances(inValuesBuilder.toString(), aType);
1316 }
1317
1330 private String prepareGetInstancesSql(CorrelationAttributeInstance.Type aType, List<String> values) throws CorrelationAttributeNormalizationException, CentralRepoException {
1331 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1332 String sql
1333 = "SELECT "
1334 + tableName
1335 + ".id as instance_id,"
1336 + tableName
1337 + ".value,"
1338 + tableName
1339 + ".file_obj_id,"
1340 + " cases.*, organizations.org_name, organizations.poc_name, organizations.poc_email, organizations.poc_phone, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, data_sources.datasource_obj_id, data_sources.md5, data_sources.sha1, data_sources.sha256 FROM "
1341 + tableName
1342 + " LEFT JOIN cases ON "
1343 + tableName
1344 + ".case_id=cases.id"
1345 + " LEFT JOIN organizations ON cases.org_id=organizations.id"
1346 + " LEFT JOIN data_sources ON "
1347 + tableName
1348 + ".data_source_id=data_sources.id"
1349 + " WHERE value IN (";
1350 StringBuilder inValuesBuilder = new StringBuilder(sql);
1351 for (String value : values) {
1352 if (value != null) {
1353 inValuesBuilder.append("'");
1354 inValuesBuilder.append(CorrelationAttributeNormalizer.normalize(aType, value));
1355 inValuesBuilder.append("',");
1356 }
1357 }
1358 inValuesBuilder.deleteCharAt(inValuesBuilder.length() - 1); //delete last comma
1359 inValuesBuilder.append(")");
1360 return inValuesBuilder.toString();
1361 }
1362
1382 private List<CorrelationAttributeInstance> getCorrAttrInstances(String sql, CorrelationAttributeInstance.Type attrType) throws CorrelationAttributeNormalizationException, CentralRepoException {
1383 List<CorrelationAttributeInstance> corrAttrs = new ArrayList<>();
1384 Connection conn = connect();
1385 PreparedStatement preparedStatement = null;
1386 ResultSet resultSet = null;
1387 try {
1388 preparedStatement = conn.prepareStatement(sql);
1389 resultSet = preparedStatement.executeQuery();
1390 while (resultSet.next()) {
1391 CorrelationAttributeInstance corrAttr = getCorrAttrFromResultSet(resultSet, attrType);
1392 corrAttrs.add(corrAttr);
1393 }
1394 } catch (SQLException ex) {
1395 throw new CentralRepoException(String.format("Error getting correlation attributes using query %s", sql), ex); // NON-NLS
1396 } finally {
1397 CentralRepoDbUtil.closeResultSet(resultSet);
1398 CentralRepoDbUtil.closeStatement(preparedStatement);
1399 CentralRepoDbUtil.closeConnection(conn);
1400 }
1401 return corrAttrs;
1402 }
1403
1414 @Override
1415 public Long getCountArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
1416 String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1417
1418 Connection conn = connect();
1419
1420 Long instanceCount = 0L;
1421 PreparedStatement preparedStatement = null;
1422 ResultSet resultSet = null;
1423
1424 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1425 String sql
1426 = "SELECT count(*) FROM "
1427 + tableName
1428 + " WHERE value=?";
1429
1430 try {
1431 preparedStatement = conn.prepareStatement(sql);
1432 preparedStatement.setString(1, normalizedValue);
1433 resultSet = preparedStatement.executeQuery();
1434 resultSet.next();
1435 instanceCount = resultSet.getLong(1);
1436 } catch (SQLException ex) {
1437 throw new CentralRepoException("Error getting count of artifact instances by artifactType and artifactValue.", ex); // NON-NLS
1438 } finally {
1439 CentralRepoDbUtil.closeResultSet(resultSet);
1440 CentralRepoDbUtil.closeStatement(preparedStatement);
1441 CentralRepoDbUtil.closeConnection(conn);
1442 }
1443
1444 return instanceCount;
1445 }
1446
1447 @Override
1448 public int getFrequencyPercentage(CorrelationAttributeInstance corAttr) throws CentralRepoException, CorrelationAttributeNormalizationException {
1449 if (corAttr == null) {
1450 throw new CentralRepoException("CorrelationAttribute is null");
1451 }
1452 Double uniqueTypeValueTuples = getCountUniqueCaseDataSourceTuplesHavingTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).doubleValue();
1453 Double uniqueCaseDataSourceTuples = getCountUniqueDataSources().doubleValue();
1454 Double commonalityPercentage = uniqueTypeValueTuples / uniqueCaseDataSourceTuples * 100;
1455 return commonalityPercentage.intValue();
1456 }
1457
1468 @Override
1469 public Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
1470 String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1471
1472 Connection conn = connect();
1473
1474 Long instanceCount = 0L;
1475 PreparedStatement preparedStatement = null;
1476 ResultSet resultSet = null;
1477
1478 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1479 String sql
1480 = "SELECT count(*) FROM (SELECT DISTINCT case_id, data_source_id FROM "
1481 + tableName
1482 + " WHERE value=?) AS "
1483 + tableName
1484 + "_distinct_case_data_source_tuple";
1485
1486 try {
1487 preparedStatement = conn.prepareStatement(sql);
1488 preparedStatement.setString(1, normalizedValue);
1489 resultSet = preparedStatement.executeQuery();
1490 resultSet.next();
1491 instanceCount = resultSet.getLong(1);
1492 } catch (SQLException ex) {
1493 throw new CentralRepoException("Error counting unique caseDisplayName/dataSource tuples having artifactType and artifactValue.", ex); // NON-NLS
1494 } finally {
1495 CentralRepoDbUtil.closeResultSet(resultSet);
1496 CentralRepoDbUtil.closeStatement(preparedStatement);
1497 CentralRepoDbUtil.closeConnection(conn);
1498 }
1499
1500 return instanceCount;
1501 }
1502
1503 @Override
1504 public Long getCountCasesWithOtherInstances(CorrelationAttributeInstance instance) throws CentralRepoException, CorrelationAttributeNormalizationException {
1505 Long instanceCount = 0L;
1506 if (instance != null) {
1507 Long sourceObjID = instance.getFileObjectId();
1508 //The CorrelationAttributeInstance will have a CorrelationCase, however that correlation case's ID will be null if the case is not in the CR.
1509 int correlationCaseId = instance.getCorrelationCase().getID();
1510 int correlationDataSourceId = instance.getCorrelationDataSource().getID();
1511 String normalizedValue = CorrelationAttributeNormalizer.normalize(instance.getCorrelationType(), instance.getCorrelationValue());
1512 Connection conn = connect();
1513 PreparedStatement preparedStatement = null;
1514 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(instance.getCorrelationType());
1515 ResultSet resultSet = null;
1516
1517 try {
1518 if (correlationCaseId > 0 && sourceObjID != null && correlationDataSourceId > 0) {
1519 //The CorrelationCase is in the Central repository.
1520 String sql
1521 = "SELECT count(*) FROM (SELECT DISTINCT case_id FROM " //Get distinct cases with a matching value in the corresponding table from the central repository.
1522 + tableName
1523 + " WHERE value=? AND NOT (file_obj_id=? AND case_id=? AND data_source_id=?)) AS " //Check the file_obj_id AND case_id to ensure we ignore the currently selected instance.
1524 + tableName
1525 + "_other_case_count";
1526 preparedStatement = conn.prepareStatement(sql);
1527 preparedStatement.setString(1, normalizedValue);
1528 preparedStatement.setLong(2, sourceObjID);
1529 preparedStatement.setInt(3, correlationCaseId);
1530 preparedStatement.setInt(4, correlationDataSourceId);
1531 } else {
1532 //The CorrelationCase is NOT in the central repository.
1533 String sql
1534 = "SELECT count(*) FROM (SELECT DISTINCT case_id FROM " //Get all distinct cases with a matching value in the corresponding table from the central repository.
1535 + tableName
1536 + " WHERE value=? AS "
1537 + tableName
1538 + "_other_case_count";
1539 preparedStatement = conn.prepareStatement(sql);
1540 preparedStatement.setString(1, normalizedValue);
1541 }
1542 resultSet = preparedStatement.executeQuery();
1543 resultSet.next();
1544 instanceCount = resultSet.getLong(1);
1545 } catch (SQLException ex) {
1546 throw new CentralRepoException("Error counting unique caseDisplayName/dataSource tuples having artifactType and artifactValue.", ex); // NON-NLS
1547 } finally {
1548 CentralRepoDbUtil.closeResultSet(resultSet);
1549 CentralRepoDbUtil.closeStatement(preparedStatement);
1550 CentralRepoDbUtil.closeConnection(conn);
1551 }
1552 }
1553
1554 return instanceCount;
1555 }
1556
1557 @Override
1558 public Long getCountUniqueDataSources() throws CentralRepoException {
1559 Connection conn = connect();
1560
1561 Long instanceCount = 0L;
1562 PreparedStatement preparedStatement = null;
1563 ResultSet resultSet = null;
1564
1565 String stmt = "SELECT count(*) FROM data_sources";
1566
1567 try {
1568 preparedStatement = conn.prepareStatement(stmt);
1569 resultSet = preparedStatement.executeQuery();
1570 resultSet.next();
1571 instanceCount = resultSet.getLong(1);
1572 } catch (SQLException ex) {
1573 throw new CentralRepoException("Error counting data sources.", ex); // NON-NLS
1574 } finally {
1575 CentralRepoDbUtil.closeResultSet(resultSet);
1576 CentralRepoDbUtil.closeStatement(preparedStatement);
1577 CentralRepoDbUtil.closeConnection(conn);
1578 }
1579
1580 return instanceCount;
1581 }
1582
1594 @Override
1595 public Long getCountArtifactInstancesByCaseDataSource(CorrelationDataSource correlationDataSource) throws CentralRepoException {
1596 Connection conn = connect();
1597
1598 Long instanceCount = 0L;
1599 List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
1600 PreparedStatement preparedStatement = null;
1601 ResultSet resultSet = null;
1602
1603 //Create query to get count of all instances in the database for the specified case specific data source
1604 String sql = "SELECT 0 ";
1605
1606 for (CorrelationAttributeInstance.Type type : artifactTypes) {
1607 String table_name = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
1608 sql
1609 += "+ (SELECT count(*) FROM "
1610 + table_name
1611 + " WHERE data_source_id=" + correlationDataSource.getID() + ")";
1612 }
1613 try {
1614 preparedStatement = conn.prepareStatement(sql);
1615
1616 resultSet = preparedStatement.executeQuery();
1617 resultSet.next();
1618 instanceCount = resultSet.getLong(1);
1619 } catch (SQLException ex) {
1620 throw new CentralRepoException("Error counting artifact instances by caseName/dataSource.", ex); // NON-NLS
1621 } finally {
1622 CentralRepoDbUtil.closeResultSet(resultSet);
1623 CentralRepoDbUtil.closeStatement(preparedStatement);
1624 CentralRepoDbUtil.closeConnection(conn);
1625 }
1626
1627 return instanceCount;
1628 }
1629
1637 @Override
1638 public void addAttributeInstanceBulk(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1639
1640 if (eamArtifact.getCorrelationType() == null) {
1641 throw new CentralRepoException("Correlation type is null");
1642 }
1643
1644 synchronized (bulkArtifacts) {
1645 if (bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())) == null) {
1646 bulkArtifacts.put(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType()), new ArrayList<>());
1647 }
1648 bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())).add(eamArtifact);
1649 bulkArtifactsCount++;
1650
1651 if (bulkArtifactsCount >= bulkArtifactsThreshold) {
1653 }
1654 }
1655 }
1656
1662 protected abstract String getConflictClause();
1663
1668 @Override
1669 public void commitAttributeInstancesBulk() throws CentralRepoException {
1670 List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
1671
1672 Connection conn = connect();
1673 PreparedStatement bulkPs = null;
1674
1675 try {
1676 synchronized (bulkArtifacts) {
1677 if (bulkArtifactsCount == 0) {
1678 return;
1679 }
1680
1681 for (String tableName : bulkArtifacts.keySet()) {
1682
1683 String sql
1684 = "INSERT INTO "
1685 + tableName
1686 + " (case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
1687 + "VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), "
1688 + "(SELECT id FROM data_sources WHERE datasource_obj_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?, ?) "
1689 + getConflictClause();
1690
1691 bulkPs = conn.prepareStatement(sql);
1692
1693 Collection<CorrelationAttributeInstance> eamArtifacts = bulkArtifacts.get(tableName);
1694 for (CorrelationAttributeInstance eamArtifact : eamArtifacts) {
1695
1696 if (!eamArtifact.getCorrelationValue().isEmpty()) {
1697
1698 if (eamArtifact.getCorrelationCase() == null) {
1699 throw new CentralRepoException("CorrelationAttributeInstance case is null for: "
1700 + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1701 + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1702 + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1703 }
1704 if (eamArtifact.getCorrelationDataSource() == null) {
1705 throw new CentralRepoException("CorrelationAttributeInstance data source is null for: "
1706 + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1707 + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1708 + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1709 }
1710 if (eamArtifact.getKnownStatus() == null) {
1711 throw new CentralRepoException("CorrelationAttributeInstance known status is null for: "
1712 + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1713 + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1714 + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue()
1715 + "\n\tEam Instance: "
1716 + "\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
1717 + "\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID());
1718 }
1719
1720 if (eamArtifact.getCorrelationValue().length() < MAX_VALUE_LENGTH) {
1721 bulkPs.setString(1, eamArtifact.getCorrelationCase().getCaseUUID());
1722 bulkPs.setLong(2, eamArtifact.getCorrelationDataSource().getDataSourceObjectID());
1723 bulkPs.setInt(3, eamArtifact.getCorrelationDataSource().getCaseID());
1724 bulkPs.setString(4, eamArtifact.getCorrelationValue());
1725 bulkPs.setString(5, eamArtifact.getFilePath());
1726 bulkPs.setByte(6, eamArtifact.getKnownStatus().getFileKnownValue());
1727 if ("".equals(eamArtifact.getComment())) {
1728 bulkPs.setNull(7, Types.INTEGER);
1729 } else {
1730 bulkPs.setString(7, eamArtifact.getComment());
1731 }
1732 bulkPs.setLong(8, eamArtifact.getFileObjectId());
1733 bulkPs.addBatch();
1734 } else {
1735 logger.log(Level.WARNING, ("Artifact value too long for central repository."
1736 + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1737 + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1738 + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue())
1739 + "\n\tEam Instance: "
1740 + "\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
1741 + "\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID()
1742 + "\n\t\tFilePath: " + eamArtifact.getFilePath());
1743 }
1744 }
1745
1746 }
1747
1748 bulkPs.executeBatch();
1749 bulkArtifacts.get(tableName).clear();
1750 }
1751
1752 TimingMetric timingMetric = HealthMonitor.getTimingMetric("Central Repository: Bulk insert");
1753 HealthMonitor.submitTimingMetric(timingMetric);
1754
1755 // Reset state
1756 bulkArtifactsCount = 0;
1757 }
1758 } catch (SQLException ex) {
1759 throw new CentralRepoException("Error inserting bulk artifacts.", ex); // NON-NLS
1760 } finally {
1761 CentralRepoDbUtil.closeStatement(bulkPs);
1762 CentralRepoDbUtil.closeConnection(conn);
1763 }
1764 }
1765
1769 @Override
1770 public void bulkInsertCases(List<CorrelationCase> cases) throws CentralRepoException {
1771 if (cases == null) {
1772 throw new CentralRepoException("cases argument is null");
1773 }
1774
1775 if (cases.isEmpty()) {
1776 return;
1777 }
1778
1779 Connection conn = connect();
1780
1781 int counter = 0;
1782 PreparedStatement bulkPs = null;
1783 try {
1784 String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
1785 + "examiner_name, examiner_email, examiner_phone, notes) "
1786 + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
1787 + getConflictClause();
1788 bulkPs = conn.prepareStatement(sql);
1789
1790 for (CorrelationCase eamCase : cases) {
1791 bulkPs.setString(1, eamCase.getCaseUUID());
1792 if (null == eamCase.getOrg()) {
1793 bulkPs.setNull(2, Types.INTEGER);
1794 } else {
1795 bulkPs.setInt(2, eamCase.getOrg().getOrgID());
1796 }
1797 bulkPs.setString(3, eamCase.getDisplayName());
1798 bulkPs.setString(4, eamCase.getCreationDate());
1799
1800 if ("".equals(eamCase.getCaseNumber())) {
1801 bulkPs.setNull(5, Types.INTEGER);
1802 } else {
1803 bulkPs.setString(5, eamCase.getCaseNumber());
1804 }
1805 if ("".equals(eamCase.getExaminerName())) {
1806 bulkPs.setNull(6, Types.INTEGER);
1807 } else {
1808 bulkPs.setString(6, eamCase.getExaminerName());
1809 }
1810 if ("".equals(eamCase.getExaminerEmail())) {
1811 bulkPs.setNull(7, Types.INTEGER);
1812 } else {
1813 bulkPs.setString(7, eamCase.getExaminerEmail());
1814 }
1815 if ("".equals(eamCase.getExaminerPhone())) {
1816 bulkPs.setNull(8, Types.INTEGER);
1817 } else {
1818 bulkPs.setString(8, eamCase.getExaminerPhone());
1819 }
1820 if ("".equals(eamCase.getNotes())) {
1821 bulkPs.setNull(9, Types.INTEGER);
1822 } else {
1823 bulkPs.setString(9, eamCase.getNotes());
1824 }
1825
1826 bulkPs.addBatch();
1827
1828 counter++;
1829
1830 // limit a batch's max size to bulkArtifactsThreshold
1831 if (counter >= bulkArtifactsThreshold) {
1832 bulkPs.executeBatch();
1833 counter = 0;
1834 }
1835 }
1836 // send the remaining batch records
1837 bulkPs.executeBatch();
1838 } catch (SQLException ex) {
1839 throw new CentralRepoException("Error inserting bulk cases.", ex); // NON-NLS
1840 } finally {
1841 CentralRepoDbUtil.closeStatement(bulkPs);
1842 CentralRepoDbUtil.closeConnection(conn);
1843 }
1844 }
1845
1855 @Override
1856 public void updateAttributeInstanceComment(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1857
1858 if (eamArtifact == null) {
1859 throw new CentralRepoException("CorrelationAttributeInstance is null");
1860 }
1861 if (eamArtifact.getCorrelationCase() == null) {
1862 throw new CentralRepoException("Correlation case is null");
1863 }
1864 if (eamArtifact.getCorrelationDataSource() == null) {
1865 throw new CentralRepoException("Correlation data source is null");
1866 }
1867 Connection conn = connect();
1868 PreparedStatement preparedQuery = null;
1869 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1870 String sqlUpdate
1871 = "UPDATE "
1872 + tableName
1873 + " SET comment=? "
1874 + "WHERE case_id=? "
1875 + "AND data_source_id=? "
1876 + "AND value=? "
1877 + "AND file_path=?";
1878
1879 try {
1880 preparedQuery = conn.prepareStatement(sqlUpdate);
1881 preparedQuery.setString(1, eamArtifact.getComment());
1882 preparedQuery.setInt(2, eamArtifact.getCorrelationCase().getID());
1883 preparedQuery.setInt(3, eamArtifact.getCorrelationDataSource().getID());
1884 preparedQuery.setString(4, eamArtifact.getCorrelationValue());
1885 preparedQuery.setString(5, eamArtifact.getFilePath().toLowerCase());
1886 preparedQuery.executeUpdate();
1887 } catch (SQLException ex) {
1888 throw new CentralRepoException("Error getting/setting artifact instance comment=" + eamArtifact.getComment(), ex); // NON-NLS
1889 } finally {
1890 CentralRepoDbUtil.closeStatement(preparedQuery);
1891 CentralRepoDbUtil.closeConnection(conn);
1892 }
1893 }
1894
1909 @Override
1910 public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
1911 CorrelationDataSource correlationDataSource, long objectID) throws CentralRepoException, CorrelationAttributeNormalizationException {
1912
1913 if (correlationCase == null) {
1914 throw new CentralRepoException("Correlation case is null");
1915 }
1916
1917 Connection conn = connect();
1918
1919 PreparedStatement preparedStatement = null;
1920 ResultSet resultSet = null;
1921 CorrelationAttributeInstance correlationAttributeInstance = null;
1922
1923 try {
1924
1925 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
1926 String sql
1927 = "SELECT id, value, file_path, known_status, comment FROM "
1928 + tableName
1929 + " WHERE case_id=?"
1930 + " AND file_obj_id=?";
1931
1932 preparedStatement = conn.prepareStatement(sql);
1933 preparedStatement.setInt(1, correlationCase.getID());
1934 preparedStatement.setInt(2, (int) objectID);
1935 resultSet = preparedStatement.executeQuery();
1936 if (resultSet.next()) {
1937 int instanceId = resultSet.getInt(1);
1938 String value = resultSet.getString(2);
1939 String filePath = resultSet.getString(3);
1940 int knownStatus = resultSet.getInt(4);
1941 String comment = resultSet.getString(5);
1942
1943 correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
1944 instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), objectID);
1945 }
1946 } catch (SQLException ex) {
1947 throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
1948 } finally {
1949 CentralRepoDbUtil.closeResultSet(resultSet);
1950 CentralRepoDbUtil.closeStatement(preparedStatement);
1951 CentralRepoDbUtil.closeConnection(conn);
1952 }
1953
1954 return correlationAttributeInstance;
1955 }
1956
1971 @Override
1972 public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
1973 CorrelationDataSource correlationDataSource, String value, String filePath) throws CentralRepoException, CorrelationAttributeNormalizationException {
1974
1975 if (correlationCase == null) {
1976 throw new CentralRepoException("Correlation case is null");
1977 }
1978 if (correlationDataSource == null) {
1979 throw new CentralRepoException("Correlation data source is null");
1980 }
1981 if (filePath == null) {
1982 throw new CentralRepoException("Correlation file path is null");
1983 }
1984
1985 Connection conn = connect();
1986
1987 PreparedStatement preparedStatement = null;
1988 ResultSet resultSet = null;
1989 CorrelationAttributeInstance correlationAttributeInstance = null;
1990
1991 try {
1992 String normalizedValue = CorrelationAttributeNormalizer.normalize(type, value);
1993
1994 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
1995 String sql
1996 = "SELECT id, known_status, comment FROM "
1997 + tableName
1998 + " WHERE case_id=?"
1999 + " AND data_source_id=?"
2000 + " AND value=?"
2001 + " AND file_path=?";
2002
2003 preparedStatement = conn.prepareStatement(sql);
2004 preparedStatement.setInt(1, correlationCase.getID());
2005 preparedStatement.setInt(2, correlationDataSource.getID());
2006 preparedStatement.setString(3, normalizedValue);
2007 preparedStatement.setString(4, filePath.toLowerCase());
2008 resultSet = preparedStatement.executeQuery();
2009 if (resultSet.next()) {
2010 int instanceId = resultSet.getInt(1);
2011 int knownStatus = resultSet.getInt(2);
2012 String comment = resultSet.getString(3);
2013 //null objectId used because we only fall back to using this method when objectID was not available
2014 correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
2015 instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), null);
2016 }
2017 } catch (SQLException ex) {
2018 throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
2019 } finally {
2020 CentralRepoDbUtil.closeResultSet(resultSet);
2021 CentralRepoDbUtil.closeStatement(preparedStatement);
2022 CentralRepoDbUtil.closeConnection(conn);
2023 }
2024
2025 return correlationAttributeInstance;
2026 }
2027
2038 @Override
2039 public void setAttributeInstanceKnownStatus(CorrelationAttributeInstance eamArtifact, TskData.FileKnown knownStatus) throws CentralRepoException {
2040 if (eamArtifact == null) {
2041 throw new CentralRepoException("CorrelationAttribute is null");
2042 }
2043 if (knownStatus == null) {
2044 throw new CentralRepoException("Known status is null");
2045 }
2046
2047 if (eamArtifact.getCorrelationCase() == null) {
2048 throw new CentralRepoException("Correlation case is null");
2049 }
2050 if (eamArtifact.getCorrelationDataSource() == null) {
2051 throw new CentralRepoException("Correlation data source is null");
2052 }
2053
2054 Connection conn = connect();
2055
2056 PreparedStatement preparedUpdate = null;
2057 PreparedStatement preparedQuery = null;
2058 ResultSet resultSet = null;
2059
2060 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
2061
2062 String sqlQuery
2063 = "SELECT id FROM "
2064 + tableName
2065 + " WHERE case_id=? "
2066 + "AND data_source_id=? "
2067 + "AND value=? "
2068 + "AND file_path=?";
2069
2070 String sqlUpdate
2071 = "UPDATE "
2072 + tableName
2073 + " SET known_status=? WHERE id=?";
2074
2075 try {
2076 preparedQuery = conn.prepareStatement(sqlQuery);
2077 preparedQuery.setInt(1, eamArtifact.getCorrelationCase().getID());
2078 preparedQuery.setInt(2, eamArtifact.getCorrelationDataSource().getID());
2079 preparedQuery.setString(3, eamArtifact.getCorrelationValue());
2080 preparedQuery.setString(4, eamArtifact.getFilePath());
2081 resultSet = preparedQuery.executeQuery();
2082 if (resultSet.next()) {
2083 int instance_id = resultSet.getInt("id");
2084 preparedUpdate = conn.prepareStatement(sqlUpdate);
2085
2086 preparedUpdate.setByte(1, knownStatus.getFileKnownValue());
2087 preparedUpdate.setInt(2, instance_id);
2088
2089 preparedUpdate.executeUpdate();
2090 } else {
2091 // In this case, the user is tagging something that isn't in the database,
2092 // which means the case and/or datasource may also not be in the database.
2093 // We could improve effiency by keeping a list of all datasources and cases
2094 // in the database, but we don't expect the user to be tagging large numbers
2095 // of items (that didn't have the CE ingest module run on them) at once.
2096 CorrelationCase correlationCaseWithId = getCaseByUUID(eamArtifact.getCorrelationCase().getCaseUUID());
2097 if (null == getDataSource(correlationCaseWithId, eamArtifact.getCorrelationDataSource().getDataSourceObjectID())) {
2098 newDataSource(eamArtifact.getCorrelationDataSource());
2099 }
2100 eamArtifact.setKnownStatus(knownStatus);
2101 addArtifactInstance(eamArtifact);
2102 }
2103
2104 } catch (SQLException ex) {
2105 throw new CentralRepoException("Error getting/setting artifact instance knownStatus=" + knownStatus.getName(), ex); // NON-NLS
2106 } finally {
2107 CentralRepoDbUtil.closeResultSet(resultSet);
2108 CentralRepoDbUtil.closeStatement(preparedUpdate);
2109 CentralRepoDbUtil.closeStatement(preparedQuery);
2110 CentralRepoDbUtil.closeConnection(conn);
2111 }
2112 }
2113
2122 @Override
2123 public Long getCountArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2124
2125 String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2126
2127 Connection conn = connect();
2128
2129 Long badInstances = 0L;
2130 PreparedStatement preparedStatement = null;
2131 ResultSet resultSet = null;
2132
2133 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
2134 String sql
2135 = "SELECT count(*) FROM "
2136 + tableName
2137 + " WHERE value=? AND known_status=?";
2138
2139 try {
2140 preparedStatement = conn.prepareStatement(sql);
2141 preparedStatement.setString(1, normalizedValue);
2142 preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2143 resultSet = preparedStatement.executeQuery();
2144 resultSet.next();
2145 badInstances = resultSet.getLong(1);
2146 } catch (SQLException ex) {
2147 throw new CentralRepoException("Error getting count of notable artifact instances.", ex); // NON-NLS
2148 } finally {
2149 CentralRepoDbUtil.closeResultSet(resultSet);
2150 CentralRepoDbUtil.closeStatement(preparedStatement);
2151 CentralRepoDbUtil.closeConnection(conn);
2152 }
2153
2154 return badInstances;
2155 }
2156
2169 @Override
2170 public List<String> getListCasesHavingArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2171
2172 String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2173
2174 Connection conn = connect();
2175
2176 Collection<String> caseNames = new LinkedHashSet<>();
2177
2178 PreparedStatement preparedStatement = null;
2179 ResultSet resultSet = null;
2180
2181 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
2182 String sql
2183 = "SELECT DISTINCT case_name FROM "
2184 + tableName
2185 + " INNER JOIN cases ON "
2186 + tableName
2187 + ".case_id=cases.id WHERE "
2188 + tableName
2189 + ".value=? AND "
2190 + tableName
2191 + ".known_status=?";
2192
2193 try {
2194 preparedStatement = conn.prepareStatement(sql);
2195 preparedStatement.setString(1, normalizedValue);
2196 preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2197 resultSet = preparedStatement.executeQuery();
2198 while (resultSet.next()) {
2199 caseNames.add(resultSet.getString("case_name"));
2200 }
2201 } catch (SQLException ex) {
2202 throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
2203 } finally {
2204 CentralRepoDbUtil.closeResultSet(resultSet);
2205 CentralRepoDbUtil.closeStatement(preparedStatement);
2206 CentralRepoDbUtil.closeConnection(conn);
2207 }
2208
2209 return caseNames.stream().collect(Collectors.toList());
2210 }
2211
2224 @Override
2225 public List<String> getListCasesHavingArtifactInstances(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2226
2227 String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2228
2229 Connection conn = connect();
2230
2231 Collection<String> caseNames = new LinkedHashSet<>();
2232
2233 PreparedStatement preparedStatement = null;
2234 ResultSet resultSet = null;
2235
2236 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
2237 String sql
2238 = "SELECT DISTINCT case_name FROM "
2239 + tableName
2240 + " INNER JOIN cases ON "
2241 + tableName
2242 + ".case_id=cases.id WHERE "
2243 + tableName
2244 + ".value=? ";
2245
2246 try {
2247 preparedStatement = conn.prepareStatement(sql);
2248 preparedStatement.setString(1, normalizedValue);
2249 resultSet = preparedStatement.executeQuery();
2250 while (resultSet.next()) {
2251 caseNames.add(resultSet.getString("case_name"));
2252 }
2253 } catch (SQLException ex) {
2254 throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
2255 } finally {
2256 CentralRepoDbUtil.closeResultSet(resultSet);
2257 CentralRepoDbUtil.closeStatement(preparedStatement);
2258 CentralRepoDbUtil.closeConnection(conn);
2259 }
2260
2261 return caseNames.stream().collect(Collectors.toList());
2262 }
2263
2271 @Override
2272 public void deleteReferenceSet(int referenceSetID) throws CentralRepoException {
2273 deleteReferenceSetEntries(referenceSetID);
2274 deleteReferenceSetEntry(referenceSetID);
2275 }
2276
2284 private void deleteReferenceSetEntry(int referenceSetID) throws CentralRepoException {
2285 Connection conn = connect();
2286
2287 PreparedStatement preparedStatement = null;
2288 String sql = "DELETE FROM reference_sets WHERE id=?";
2289
2290 try {
2291 preparedStatement = conn.prepareStatement(sql);
2292 preparedStatement.setInt(1, referenceSetID);
2293 preparedStatement.executeUpdate();
2294 } catch (SQLException ex) {
2295 throw new CentralRepoException("Error deleting reference set " + referenceSetID, ex); // NON-NLS
2296 } finally {
2297 CentralRepoDbUtil.closeStatement(preparedStatement);
2298 CentralRepoDbUtil.closeConnection(conn);
2299 }
2300 }
2301
2310 private void deleteReferenceSetEntries(int referenceSetID) throws CentralRepoException {
2311 Connection conn = connect();
2312
2313 PreparedStatement preparedStatement = null;
2314 String sql = "DELETE FROM %s WHERE reference_set_id=?";
2315
2316 // When other reference types are added, this will need to loop over all the tables
2317 String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
2318
2319 try {
2320 preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2321 preparedStatement.setInt(1, referenceSetID);
2322 preparedStatement.executeUpdate();
2323 } catch (SQLException ex) {
2324 throw new CentralRepoException("Error deleting files from reference set " + referenceSetID, ex); // NON-NLS
2325 } finally {
2326 CentralRepoDbUtil.closeStatement(preparedStatement);
2327 CentralRepoDbUtil.closeConnection(conn);
2328 }
2329 }
2330
2344 @Override
2345 public boolean referenceSetIsValid(int referenceSetID, String setName, String version) throws CentralRepoException {
2346 CentralRepoFileSet refSet = this.getReferenceSetByID(referenceSetID);
2347 if (refSet == null) {
2348 return false;
2349 }
2350
2351 return (refSet.getSetName().equals(setName) && refSet.getVersion().equals(version));
2352 }
2353
2365 @Override
2366 public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException {
2367 return isValueInReferenceSet(hash, referenceSetID, CorrelationAttributeInstance.FILES_TYPE_ID);
2368 }
2369
2370 @Override
2371 public HashHitInfo lookupHash(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException {
2372 int correlationTypeID = CorrelationAttributeInstance.FILES_TYPE_ID;
2373 String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), hash);
2374
2375 Connection conn = connect();
2376
2377 PreparedStatement preparedStatement = null;
2378 ResultSet resultSet = null;
2379 String sql = "SELECT value,comment FROM %s WHERE value=? AND reference_set_id=?";
2380
2381 String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
2382
2383 try {
2384 preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2385 preparedStatement.setString(1, normalizeValued);
2386 preparedStatement.setInt(2, referenceSetID);
2387 resultSet = preparedStatement.executeQuery();
2388 if (resultSet.next()) {
2389 String comment = resultSet.getString("comment");
2390 String hashFound = resultSet.getString("value");
2391 HashHitInfo found = new HashHitInfo(hashFound, "", "");
2392 found.addComment(comment);
2393 return found;
2394 } else {
2395 return null;
2396 }
2397 } catch (SQLException ex) {
2398 throw new CentralRepoException("Error determining if value (" + normalizeValued + ") is in reference set " + referenceSetID, ex); // NON-NLS
2399 } finally {
2400 CentralRepoDbUtil.closeResultSet(resultSet);
2401 CentralRepoDbUtil.closeStatement(preparedStatement);
2402 CentralRepoDbUtil.closeConnection(conn);
2403 }
2404 }
2405
2415 @Override
2416 public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws CentralRepoException, CorrelationAttributeNormalizationException {
2417
2418 String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), value);
2419
2420 Connection conn = connect();
2421
2422 Long matchingInstances = 0L;
2423 PreparedStatement preparedStatement = null;
2424 ResultSet resultSet = null;
2425 String sql = "SELECT count(*) FROM %s WHERE value=? AND reference_set_id=?";
2426
2427 String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
2428
2429 try {
2430 preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2431 preparedStatement.setString(1, normalizeValued);
2432 preparedStatement.setInt(2, referenceSetID);
2433 resultSet = preparedStatement.executeQuery();
2434 resultSet.next();
2435 matchingInstances = resultSet.getLong(1);
2436 } catch (SQLException ex) {
2437 throw new CentralRepoException("Error determining if value (" + normalizeValued + ") is in reference set " + referenceSetID, ex); // NON-NLS
2438 } finally {
2439 CentralRepoDbUtil.closeResultSet(resultSet);
2440 CentralRepoDbUtil.closeStatement(preparedStatement);
2441 CentralRepoDbUtil.closeConnection(conn);
2442 }
2443
2444 return 0 < matchingInstances;
2445 }
2446
2455 @Override
2456 public boolean isArtifactKnownBadByReference(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2457
2458 //this should be done here so that we can be certain that aType and value are valid before we proceed
2459 String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, value);
2460
2461 // TEMP: Only support file correlation type
2462 if (aType.getId() != CorrelationAttributeInstance.FILES_TYPE_ID) {
2463 return false;
2464 }
2465
2466 Connection conn = connect();
2467
2468 Long badInstances = 0L;
2469 PreparedStatement preparedStatement = null;
2470 ResultSet resultSet = null;
2471 String sql = "SELECT count(*) FROM %s WHERE value=? AND known_status=?";
2472
2473 try {
2474 preparedStatement = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(aType)));
2475 preparedStatement.setString(1, normalizeValued);
2476 preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2477 resultSet = preparedStatement.executeQuery();
2478 resultSet.next();
2479 badInstances = resultSet.getLong(1);
2480 } catch (SQLException ex) {
2481 throw new CentralRepoException("Error determining if artifact is notable by reference.", ex); // NON-NLS
2482 } finally {
2483 CentralRepoDbUtil.closeResultSet(resultSet);
2484 CentralRepoDbUtil.closeStatement(preparedStatement);
2485 CentralRepoDbUtil.closeConnection(conn);
2486 }
2487
2488 return 0 < badInstances;
2489 }
2490
2499 @Override
2500 public void processInstanceTable(CorrelationAttributeInstance.Type type, InstanceTableCallback instanceTableCallback) throws CentralRepoException {
2501 if (type == null) {
2502 throw new CentralRepoException("Correlation type is null");
2503 }
2504
2505 if (instanceTableCallback == null) {
2506 throw new CentralRepoException("Callback interface is null");
2507 }
2508
2509 Connection conn = connect();
2510 PreparedStatement preparedStatement = null;
2511 ResultSet resultSet = null;
2512 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
2513 StringBuilder sql = new StringBuilder();
2514 sql.append("select * from ");
2515 sql.append(tableName);
2516
2517 try {
2518 preparedStatement = conn.prepareStatement(sql.toString());
2519 resultSet = preparedStatement.executeQuery();
2520 instanceTableCallback.process(resultSet);
2521 } catch (SQLException ex) {
2522 throw new CentralRepoException("Error getting all artifact instances from instances table", ex);
2523 } finally {
2524 CentralRepoDbUtil.closeResultSet(resultSet);
2525 CentralRepoDbUtil.closeStatement(preparedStatement);
2526 CentralRepoDbUtil.closeConnection(conn);
2527 }
2528 }
2529
2539 @Override
2540 public void processInstanceTableWhere(CorrelationAttributeInstance.Type type, String whereClause, InstanceTableCallback instanceTableCallback) throws CentralRepoException {
2541 if (type == null) {
2542 throw new CentralRepoException("Correlation type is null");
2543 }
2544
2545 if (instanceTableCallback == null) {
2546 throw new CentralRepoException("Callback interface is null");
2547 }
2548
2549 if (whereClause == null) {
2550 throw new CentralRepoException("Where clause is null");
2551 }
2552
2553 Connection conn = connect();
2554 PreparedStatement preparedStatement = null;
2555 ResultSet resultSet = null;
2556 String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
2557 StringBuilder sql = new StringBuilder(300);
2558 sql.append("select * from ")
2559 .append(tableName)
2560 .append(" WHERE ")
2561 .append(whereClause);
2562
2563 try {
2564 preparedStatement = conn.prepareStatement(sql.toString());
2565 resultSet = preparedStatement.executeQuery();
2566 instanceTableCallback.process(resultSet);
2567 } catch (SQLException ex) {
2568 throw new CentralRepoException("Error getting all artifact instances from instances table", ex);
2569 } finally {
2570 CentralRepoDbUtil.closeResultSet(resultSet);
2571 CentralRepoDbUtil.closeStatement(preparedStatement);
2572 CentralRepoDbUtil.closeConnection(conn);
2573 }
2574 }
2575
2584 @Override
2585 public void processSelectClause(String selectClause, InstanceTableCallback instanceTableCallback) throws CentralRepoException {
2586
2587 if (instanceTableCallback == null) {
2588 throw new CentralRepoException("Callback interface is null");
2589 }
2590
2591 if (selectClause == null) {
2592 throw new CentralRepoException("Select clause is null");
2593 }
2594
2595 Connection conn = connect();
2596 PreparedStatement preparedStatement = null;
2597 ResultSet resultSet = null;
2598 StringBuilder sql = new StringBuilder(300);
2599 sql.append("select ")
2600 .append(selectClause);
2601
2602 try {
2603 preparedStatement = conn.prepareStatement(sql.toString());
2604 resultSet = preparedStatement.executeQuery();
2605 instanceTableCallback.process(resultSet);
2606 } catch (SQLException ex) {
2607 throw new CentralRepoException("Error running query", ex);
2608 } finally {
2609 CentralRepoDbUtil.closeResultSet(resultSet);
2610 CentralRepoDbUtil.closeStatement(preparedStatement);
2611 CentralRepoDbUtil.closeConnection(conn);
2612 }
2613 }
2614
2615 @Override
2616 public void executeCommand(String sql, List<Object> params) throws CentralRepoException {
2617
2618 try (Connection conn = connect();) {
2619
2620 PreparedStatement preparedStatement = conn.prepareStatement(sql);
2621
2622 // Fill in the params
2623 if (params != null) {
2624 int paramIndex = 1;
2625 for (Object param : params) {
2626 preparedStatement.setObject(paramIndex, param);
2627 paramIndex += 1;
2628 }
2629 }
2630 // execute the prepared statement
2631 preparedStatement.executeUpdate();
2632 } catch (SQLException ex) {
2633 throw new CentralRepoException(String.format("Error executing prepared statement for SQL %s", sql), ex);
2634 }
2635 }
2636
2637 @Override
2638 public void executeQuery(String sql, List<Object> params, CentralRepositoryDbQueryCallback queryCallback) throws CentralRepoException {
2639 if (queryCallback == null) {
2640 throw new CentralRepoException("Query callback is null");
2641 }
2642
2643 try (Connection conn = connect();) {
2644 PreparedStatement preparedStatement = conn.prepareStatement(sql);
2645
2646 // fill in the params
2647 if (params != null) {
2648 int paramIndex = 1;
2649 for (Object param : params) {
2650 preparedStatement.setObject(paramIndex, param);
2651 paramIndex += 1;
2652 }
2653 }
2654 // execute query, and the callback to process result
2655 try (ResultSet resultSet = preparedStatement.executeQuery();) {
2656 queryCallback.process(resultSet);
2657 }
2658 } catch (SQLException ex) {
2659 throw new CentralRepoException(String.format("Error executing prepared statement for SQL query %s", sql), ex);
2660 }
2661 }
2662
2663 @Override
2664 public CentralRepoOrganization newOrganization(CentralRepoOrganization eamOrg) throws CentralRepoException {
2665 if (eamOrg == null) {
2666 throw new CentralRepoException("EamOrganization is null");
2667 } else if (eamOrg.getOrgID() != -1) {
2668 throw new CentralRepoException("EamOrganization already has an ID");
2669 }
2670
2671 Connection conn = connect();
2672 ResultSet generatedKeys = null;
2673 PreparedStatement preparedStatement = null;
2674 String sql = "INSERT INTO organizations(org_name, poc_name, poc_email, poc_phone) VALUES (?, ?, ?, ?) "
2675 + getConflictClause();
2676
2677 try {
2678 preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
2679 preparedStatement.setString(1, eamOrg.getName());
2680 preparedStatement.setString(2, eamOrg.getPocName());
2681 preparedStatement.setString(3, eamOrg.getPocEmail());
2682 preparedStatement.setString(4, eamOrg.getPocPhone());
2683
2684 preparedStatement.executeUpdate();
2685 generatedKeys = preparedStatement.getGeneratedKeys();
2686 if (generatedKeys.next()) {
2687 eamOrg.setOrgID((int) generatedKeys.getLong(1));
2688 return eamOrg;
2689 } else {
2690 throw new SQLException("Creating user failed, no ID obtained.");
2691 }
2692 } catch (SQLException ex) {
2693 throw new CentralRepoException("Error inserting new organization.", ex); // NON-NLS
2694 } finally {
2695 CentralRepoDbUtil.closeResultSet(generatedKeys);
2696 CentralRepoDbUtil.closeStatement(preparedStatement);
2697 CentralRepoDbUtil.closeConnection(conn);
2698 }
2699 }
2700
2708 @Override
2709 public List<CentralRepoOrganization> getOrganizations() throws CentralRepoException {
2710 Connection conn = connect();
2711
2712 List<CentralRepoOrganization> orgs = new ArrayList<>();
2713 PreparedStatement preparedStatement = null;
2714 ResultSet resultSet = null;
2715 String sql = "SELECT * FROM organizations";
2716
2717 try {
2718 preparedStatement = conn.prepareStatement(sql);
2719 resultSet = preparedStatement.executeQuery();
2720 while (resultSet.next()) {
2721 orgs.add(getEamOrganizationFromResultSet(resultSet));
2722 }
2723 return orgs;
2724
2725 } catch (SQLException ex) {
2726 throw new CentralRepoException("Error getting all organizations.", ex); // NON-NLS
2727 } finally {
2728 CentralRepoDbUtil.closeResultSet(resultSet);
2729 CentralRepoDbUtil.closeStatement(preparedStatement);
2730 CentralRepoDbUtil.closeConnection(conn);
2731 }
2732 }
2733
2743 @Override
2744 public CentralRepoOrganization getOrganizationByID(int orgID) throws CentralRepoException {
2745 Connection conn = connect();
2746
2747 PreparedStatement preparedStatement = null;
2748 ResultSet resultSet = null;
2749 String sql = "SELECT * FROM organizations WHERE id=?";
2750
2751 try {
2752 preparedStatement = conn.prepareStatement(sql);
2753 preparedStatement.setInt(1, orgID);
2754 resultSet = preparedStatement.executeQuery();
2755 resultSet.next();
2756 return getEamOrganizationFromResultSet(resultSet);
2757
2758 } catch (SQLException ex) {
2759 throw new CentralRepoException("Error getting organization by id.", ex); // NON-NLS
2760 } finally {
2761 CentralRepoDbUtil.closeResultSet(resultSet);
2762 CentralRepoDbUtil.closeStatement(preparedStatement);
2763 CentralRepoDbUtil.closeConnection(conn);
2764 }
2765 }
2766
2776 @Override
2777 public CentralRepoOrganization getReferenceSetOrganization(int referenceSetID) throws CentralRepoException {
2778
2779 CentralRepoFileSet globalSet = getReferenceSetByID(referenceSetID);
2780 if (globalSet == null) {
2781 throw new CentralRepoException("Reference set with ID " + referenceSetID + " not found");
2782 }
2783 return (getOrganizationByID(globalSet.getOrgID()));
2784 }
2785
2793 private void testArgument(CentralRepoOrganization org) throws CentralRepoException {
2794 if (org == null) {
2795 throw new CentralRepoException("EamOrganization is null");
2796 } else if (org.getOrgID() == -1) {
2797 throw new CentralRepoException("Organization has -1 row ID");
2798 }
2799 }
2800
2812 @Override
2813 public CentralRepoExaminer getOrInsertExaminer(String examinerLoginName) throws CentralRepoException {
2814
2815 String querySQL = "SELECT * FROM examiners WHERE login_name = '" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "'";
2816 try (Connection connection = connect();
2817 Statement statement = connection.createStatement();
2818 ResultSet resultSet = statement.executeQuery(querySQL);) {
2819
2820 if (resultSet.next()) {
2821 return new CentralRepoExaminer(resultSet.getLong("id"), resultSet.getString("login_name"));
2822 } else {
2823 // Could not find this user in the Examiner table, add a row for it.
2824 try {
2825 String insertSQL;
2826 switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
2827 case POSTGRESQL:
2828 insertSQL = "INSERT INTO examiners (login_name) VALUES ('" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "')" + getConflictClause(); //NON-NLS
2829 break;
2830 case SQLITE:
2831 insertSQL = "INSERT OR IGNORE INTO examiners (login_name) VALUES ('" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "')"; //NON-NLS
2832 break;
2833 default:
2834 throw new CentralRepoException(String.format("Cannot add examiner to currently selected CR database platform %s", CentralRepoDbManager.getSavedDbChoice().getDbPlatform())); //NON-NLS
2835 }
2836 statement.execute(insertSQL);
2837
2838 // Query the table again to get the row for the user
2839 try (ResultSet resultSet2 = statement.executeQuery(querySQL)) {
2840 if (resultSet2.next()) {
2841 return new CentralRepoExaminer(resultSet2.getLong("id"), resultSet2.getString("login_name"));
2842 } else {
2843 throw new CentralRepoException("Error getting examiner for name = " + examinerLoginName);
2844 }
2845 }
2846
2847 } catch (SQLException ex) {
2848 throw new CentralRepoException("Error inserting row in examiners", ex);
2849 }
2850 }
2851
2852 } catch (SQLException ex) {
2853 throw new CentralRepoException("Error getting examiner for name = " + examinerLoginName, ex);
2854 }
2855 }
2856
2865 @Override
2866 public void updateOrganization(CentralRepoOrganization updatedOrganization) throws CentralRepoException {
2867 testArgument(updatedOrganization);
2868
2869 Connection conn = connect();
2870 PreparedStatement preparedStatement = null;
2871 String sql = "UPDATE organizations SET org_name = ?, poc_name = ?, poc_email = ?, poc_phone = ? WHERE id = ?";
2872 try {
2873 preparedStatement = conn.prepareStatement(sql);
2874 preparedStatement.setString(1, updatedOrganization.getName());
2875 preparedStatement.setString(2, updatedOrganization.getPocName());
2876 preparedStatement.setString(3, updatedOrganization.getPocEmail());
2877 preparedStatement.setString(4, updatedOrganization.getPocPhone());
2878 preparedStatement.setInt(5, updatedOrganization.getOrgID());
2879 preparedStatement.executeUpdate();
2880 } catch (SQLException ex) {
2881 throw new CentralRepoException("Error updating organization.", ex); // NON-NLS
2882 } finally {
2883 CentralRepoDbUtil.closeStatement(preparedStatement);
2884 CentralRepoDbUtil.closeConnection(conn);
2885 }
2886 }
2887
2888 @Override
2889 public void deleteOrganization(CentralRepoOrganization organizationToDelete) throws CentralRepoException {
2890 testArgument(organizationToDelete);
2891
2892 Connection conn = connect();
2893 PreparedStatement checkIfUsedStatement = null;
2894 ResultSet resultSet = null;
2895 String checkIfUsedSql = "SELECT (select count(*) FROM cases WHERE org_id=?) + (select count(*) FROM reference_sets WHERE org_id=?)";
2896 PreparedStatement deleteOrgStatement = null;
2897 String deleteOrgSql = "DELETE FROM organizations WHERE id=?";
2898 try {
2899 checkIfUsedStatement = conn.prepareStatement(checkIfUsedSql);
2900 checkIfUsedStatement.setInt(1, organizationToDelete.getOrgID());
2901 checkIfUsedStatement.setInt(2, organizationToDelete.getOrgID());
2902 resultSet = checkIfUsedStatement.executeQuery();
2903 resultSet.next();
2904 if (resultSet.getLong(1) > 0) {
2905 throw new CentralRepoException("Can not delete organization which is currently in use by a case or reference set in the central repository.");
2906 }
2907 deleteOrgStatement = conn.prepareStatement(deleteOrgSql);
2908 deleteOrgStatement.setInt(1, organizationToDelete.getOrgID());
2909 deleteOrgStatement.executeUpdate();
2910 } catch (SQLException ex) {
2911 throw new CentralRepoException("Error executing query when attempting to delete organization by id.", ex); // NON-NLS
2912 } finally {
2913 CentralRepoDbUtil.closeResultSet(resultSet);
2914 CentralRepoDbUtil.closeStatement(checkIfUsedStatement);
2915 CentralRepoDbUtil.closeStatement(deleteOrgStatement);
2916 CentralRepoDbUtil.closeConnection(conn);
2917 }
2918 }
2919
2929 @Override
2930 public int newReferenceSet(CentralRepoFileSet eamGlobalSet) throws CentralRepoException {
2931 if (eamGlobalSet == null) {
2932 throw new CentralRepoException("EamGlobalSet is null");
2933 }
2934
2935 if (eamGlobalSet.getFileKnownStatus() == null) {
2936 throw new CentralRepoException("File known status on the EamGlobalSet is null");
2937 }
2938
2939 if (eamGlobalSet.getType() == null) {
2940 throw new CentralRepoException("Type on the EamGlobalSet is null");
2941 }
2942
2943 Connection conn = connect();
2944
2945 PreparedStatement preparedStatement1 = null;
2946 PreparedStatement preparedStatement2 = null;
2947 ResultSet resultSet = null;
2948 String sql1 = "INSERT INTO reference_sets(org_id, set_name, version, known_status, read_only, type, import_date) VALUES (?, ?, ?, ?, ?, ?, ?) "
2949 + getConflictClause();
2950 String sql2 = "SELECT id FROM reference_sets WHERE org_id=? AND set_name=? AND version=? AND import_date=? LIMIT 1";
2951
2952 try {
2953 preparedStatement1 = conn.prepareStatement(sql1);
2954 preparedStatement1.setInt(1, eamGlobalSet.getOrgID());
2955 preparedStatement1.setString(2, eamGlobalSet.getSetName());
2956 preparedStatement1.setString(3, eamGlobalSet.getVersion());
2957 preparedStatement1.setInt(4, eamGlobalSet.getFileKnownStatus().getFileKnownValue());
2958 preparedStatement1.setBoolean(5, eamGlobalSet.isReadOnly());
2959 preparedStatement1.setInt(6, eamGlobalSet.getType().getId());
2960 preparedStatement1.setString(7, eamGlobalSet.getImportDate().toString());
2961
2962 preparedStatement1.executeUpdate();
2963
2964 preparedStatement2 = conn.prepareStatement(sql2);
2965 preparedStatement2.setInt(1, eamGlobalSet.getOrgID());
2966 preparedStatement2.setString(2, eamGlobalSet.getSetName());
2967 preparedStatement2.setString(3, eamGlobalSet.getVersion());
2968 preparedStatement2.setString(4, eamGlobalSet.getImportDate().toString());
2969
2970 resultSet = preparedStatement2.executeQuery();
2971 resultSet.next();
2972 return resultSet.getInt("id");
2973
2974 } catch (SQLException ex) {
2975 throw new CentralRepoException("Error inserting new global set.", ex); // NON-NLS
2976 } finally {
2977 CentralRepoDbUtil.closeResultSet(resultSet);
2978 CentralRepoDbUtil.closeStatement(preparedStatement1);
2979 CentralRepoDbUtil.closeStatement(preparedStatement2);
2980 CentralRepoDbUtil.closeConnection(conn);
2981 }
2982 }
2983
2993 @Override
2994 public CentralRepoFileSet getReferenceSetByID(int referenceSetID) throws CentralRepoException {
2995 Connection conn = connect();
2996
2997 PreparedStatement preparedStatement1 = null;
2998 ResultSet resultSet = null;
2999 String sql1 = "SELECT * FROM reference_sets WHERE id=?";
3000
3001 try {
3002 preparedStatement1 = conn.prepareStatement(sql1);
3003 preparedStatement1.setInt(1, referenceSetID);
3004 resultSet = preparedStatement1.executeQuery();
3005 if (resultSet.next()) {
3006 return getEamGlobalSetFromResultSet(resultSet);
3007 } else {
3008 return null;
3009 }
3010
3011 } catch (SQLException ex) {
3012 throw new CentralRepoException("Error getting reference set by id.", ex); // NON-NLS
3013 } finally {
3014 CentralRepoDbUtil.closeResultSet(resultSet);
3015 CentralRepoDbUtil.closeStatement(preparedStatement1);
3016 CentralRepoDbUtil.closeConnection(conn);
3017 }
3018 }
3019
3029 @Override
3030 public List<CentralRepoFileSet> getAllReferenceSets(CorrelationAttributeInstance.Type correlationType) throws CentralRepoException {
3031
3032 if (correlationType == null) {
3033 throw new CentralRepoException("Correlation type is null");
3034 }
3035
3036 List<CentralRepoFileSet> results = new ArrayList<>();
3037 Connection conn = connect();
3038
3039 PreparedStatement preparedStatement1 = null;
3040 ResultSet resultSet = null;
3041 String sql1 = "SELECT * FROM reference_sets WHERE type=" + correlationType.getId();
3042
3043 try {
3044 preparedStatement1 = conn.prepareStatement(sql1);
3045 resultSet = preparedStatement1.executeQuery();
3046 while (resultSet.next()) {
3047 results.add(getEamGlobalSetFromResultSet(resultSet));
3048 }
3049
3050 } catch (SQLException ex) {
3051 throw new CentralRepoException("Error getting reference sets.", ex); // NON-NLS
3052 } finally {
3053 CentralRepoDbUtil.closeResultSet(resultSet);
3054 CentralRepoDbUtil.closeStatement(preparedStatement1);
3055 CentralRepoDbUtil.closeConnection(conn);
3056 }
3057 return results;
3058 }
3059
3069 @Override
3070 public void addReferenceInstance(CentralRepoFileInstance eamGlobalFileInstance, CorrelationAttributeInstance.Type correlationType) throws CentralRepoException {
3071 if (eamGlobalFileInstance.getKnownStatus() == null) {
3072 throw new CentralRepoException("Known status of EamGlobalFileInstance is null");
3073 }
3074 if (correlationType == null) {
3075 throw new CentralRepoException("Correlation type is null");
3076 }
3077
3078 Connection conn = connect();
3079
3080 PreparedStatement preparedStatement = null;
3081
3082 String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
3083 + getConflictClause();
3084
3085 try {
3086 preparedStatement = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(correlationType)));
3087 preparedStatement.setInt(1, eamGlobalFileInstance.getGlobalSetID());
3088 preparedStatement.setString(2, eamGlobalFileInstance.getMD5Hash());
3089 preparedStatement.setByte(3, eamGlobalFileInstance.getKnownStatus().getFileKnownValue());
3090 preparedStatement.setString(4, eamGlobalFileInstance.getComment());
3091 preparedStatement.executeUpdate();
3092 } catch (SQLException ex) {
3093 throw new CentralRepoException("Error inserting new reference instance into reference_ table.", ex); // NON-NLS
3094 } finally {
3095 CentralRepoDbUtil.closeStatement(preparedStatement);
3096 CentralRepoDbUtil.closeConnection(conn);
3097 }
3098 }
3099
3112 @Override
3113 public boolean referenceSetExists(String referenceSetName, String version) throws CentralRepoException {
3114 Connection conn = connect();
3115
3116 PreparedStatement preparedStatement1 = null;
3117 ResultSet resultSet = null;
3118 String sql1 = "SELECT * FROM reference_sets WHERE set_name=? AND version=?";
3119
3120 try {
3121 preparedStatement1 = conn.prepareStatement(sql1);
3122 preparedStatement1.setString(1, referenceSetName);
3123 preparedStatement1.setString(2, version);
3124 resultSet = preparedStatement1.executeQuery();
3125 return (resultSet.next());
3126
3127 } catch (SQLException ex) {
3128 throw new CentralRepoException("Error testing whether reference set exists (name: " + referenceSetName
3129 + " version: " + version, ex); // NON-NLS
3130 } finally {
3131 CentralRepoDbUtil.closeResultSet(resultSet);
3132 CentralRepoDbUtil.closeStatement(preparedStatement1);
3133 CentralRepoDbUtil.closeConnection(conn);
3134 }
3135 }
3136
3142 @Override
3143 public void bulkInsertReferenceTypeEntries(Set<CentralRepoFileInstance> globalInstances, CorrelationAttributeInstance.Type contentType) throws CentralRepoException {
3144 if (contentType == null) {
3145 throw new CentralRepoException("Correlation type is null");
3146 }
3147 if (globalInstances == null) {
3148 throw new CentralRepoException("Null set of EamGlobalFileInstance");
3149 }
3150
3151 Connection conn = connect();
3152
3153 PreparedStatement bulkPs = null;
3154 try {
3155 conn.setAutoCommit(false);
3156
3157 // FUTURE: have a separate global_files table for each Type.
3158 String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
3159 + getConflictClause();
3160
3161 bulkPs = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(contentType)));
3162
3163 for (CentralRepoFileInstance globalInstance : globalInstances) {
3164 if (globalInstance.getKnownStatus() == null) {
3165 throw new CentralRepoException("EamGlobalFileInstance with value " + globalInstance.getMD5Hash() + " has null known status");
3166 }
3167
3168 bulkPs.setInt(1, globalInstance.getGlobalSetID());
3169 bulkPs.setString(2, globalInstance.getMD5Hash());
3170 bulkPs.setByte(3, globalInstance.getKnownStatus().getFileKnownValue());
3171 bulkPs.setString(4, globalInstance.getComment());
3172 bulkPs.addBatch();
3173 }
3174
3175 bulkPs.executeBatch();
3176 conn.commit();
3177 } catch (SQLException | CentralRepoException ex) {
3178 try {
3179 conn.rollback();
3180 } catch (SQLException ex2) {
3181 // We're alredy in an error state
3182 }
3183 throw new CentralRepoException("Error inserting bulk artifacts.", ex); // NON-NLS
3184 } finally {
3185 CentralRepoDbUtil.closeStatement(bulkPs);
3186 CentralRepoDbUtil.closeConnection(conn);
3187 }
3188 }
3189
3200 @Override
3201 public List<CentralRepoFileInstance> getReferenceInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String aValue) throws CentralRepoException, CorrelationAttributeNormalizationException {
3202 String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, aValue);
3203
3204 Connection conn = connect();
3205
3206 List<CentralRepoFileInstance> globalFileInstances = new ArrayList<>();
3207 PreparedStatement preparedStatement1 = null;
3208 ResultSet resultSet = null;
3209 String sql1 = "SELECT * FROM %s WHERE value=?";
3210
3211 try {
3212 preparedStatement1 = conn.prepareStatement(String.format(sql1, CentralRepoDbUtil.correlationTypeToReferenceTableName(aType)));
3213 preparedStatement1.setString(1, normalizeValued);
3214 resultSet = preparedStatement1.executeQuery();
3215 while (resultSet.next()) {
3216 globalFileInstances.add(getEamGlobalFileInstanceFromResultSet(resultSet));
3217 }
3218
3219 } catch (SQLException ex) {
3220 throw new CentralRepoException("Error getting reference instances by type and value.", ex); // NON-NLS
3221 } finally {
3222 CentralRepoDbUtil.closeResultSet(resultSet);
3223 CentralRepoDbUtil.closeStatement(preparedStatement1);
3224 CentralRepoDbUtil.closeConnection(conn);
3225 }
3226
3227 return globalFileInstances;
3228 }
3229
3239 @Override
3240 public int newCorrelationType(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
3241 if (newType == null) {
3242 throw new CentralRepoException("Correlation type is null");
3243 }
3244 int typeId;
3245 if (-1 == newType.getId()) {
3246 typeId = newCorrelationTypeNotKnownId(newType);
3247 } else {
3248 typeId = newCorrelationTypeKnownId(newType);
3249 }
3250
3251 synchronized (typeCache) {
3252 typeCache.put(newType.getId(), newType);
3253 }
3254 return typeId;
3255 }
3256
3267 public int newCorrelationTypeNotKnownId(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
3268 Connection conn = connect();
3269
3270 PreparedStatement preparedStatement = null;
3271 PreparedStatement preparedStatementQuery = null;
3272 ResultSet resultSet = null;
3273 int typeId = 0;
3274 String insertSql;
3275 String querySql;
3276 // if we have a known ID, use it, if not (is -1) let the db assign it.
3277 insertSql = "INSERT INTO correlation_types(display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?) " + getConflictClause();
3278
3279 querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
3280
3281 try {
3282 preparedStatement = conn.prepareStatement(insertSql);
3283
3284 preparedStatement.setString(1, newType.getDisplayName());
3285 preparedStatement.setString(2, newType.getDbTableName());
3286 preparedStatement.setInt(3, newType.isSupported() ? 1 : 0);
3287 preparedStatement.setInt(4, newType.isEnabled() ? 1 : 0);
3288
3289 preparedStatement.executeUpdate();
3290
3291 preparedStatementQuery = conn.prepareStatement(querySql);
3292 preparedStatementQuery.setString(1, newType.getDisplayName());
3293 preparedStatementQuery.setString(2, newType.getDbTableName());
3294
3295 resultSet = preparedStatementQuery.executeQuery();
3296 if (resultSet.next()) {
3297 CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
3298 typeId = correlationType.getId();
3299 }
3300 } catch (SQLException ex) {
3301 throw new CentralRepoException("Error inserting new correlation type.", ex); // NON-NLS
3302 } finally {
3303 CentralRepoDbUtil.closeResultSet(resultSet);
3304 CentralRepoDbUtil.closeStatement(preparedStatement);
3305 CentralRepoDbUtil.closeStatement(preparedStatementQuery);
3306 CentralRepoDbUtil.closeConnection(conn);
3307 }
3308 return typeId;
3309 }
3310
3320 private int newCorrelationTypeKnownId(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
3321 Connection conn = connect();
3322
3323 PreparedStatement preparedStatement = null;
3324 PreparedStatement preparedStatementQuery = null;
3325 ResultSet resultSet = null;
3326 int typeId = 0;
3327 String insertSql;
3328 String querySql;
3329 // if we have a known ID, use it, if not (is -1) let the db assign it.
3330 insertSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause();
3331
3332 querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
3333
3334 try {
3335 preparedStatement = conn.prepareStatement(insertSql);
3336
3337 preparedStatement.setInt(1, newType.getId());
3338 preparedStatement.setString(2, newType.getDisplayName());
3339 preparedStatement.setString(3, newType.getDbTableName());
3340 preparedStatement.setInt(4, newType.isSupported() ? 1 : 0);
3341 preparedStatement.setInt(5, newType.isEnabled() ? 1 : 0);
3342
3343 preparedStatement.executeUpdate();
3344
3345 preparedStatementQuery = conn.prepareStatement(querySql);
3346 preparedStatementQuery.setString(1, newType.getDisplayName());
3347 preparedStatementQuery.setString(2, newType.getDbTableName());
3348
3349 resultSet = preparedStatementQuery.executeQuery();
3350 if (resultSet.next()) {
3351 CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
3352 typeId = correlationType.getId();
3353 }
3354 } catch (SQLException ex) {
3355 throw new CentralRepoException("Error inserting new correlation type.", ex); // NON-NLS
3356 } finally {
3357 CentralRepoDbUtil.closeResultSet(resultSet);
3358 CentralRepoDbUtil.closeStatement(preparedStatement);
3359 CentralRepoDbUtil.closeStatement(preparedStatementQuery);
3360 CentralRepoDbUtil.closeConnection(conn);
3361 }
3362 return typeId;
3363 }
3364
3365 @Override
3366 public List<CorrelationAttributeInstance.Type> getDefinedCorrelationTypes() throws CentralRepoException {
3367
3368 synchronized (typeCache) {
3369 if (isCRTypeCacheInitialized == false) {
3370 getCorrelationTypesFromCr();
3371 }
3372 return new ArrayList<>(typeCache.asMap().values());
3373 }
3374 }
3375
3385 @Override
3386 public List<CorrelationAttributeInstance.Type> getEnabledCorrelationTypes() throws CentralRepoException {
3387 Connection conn = connect();
3388
3389 List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
3390 PreparedStatement preparedStatement = null;
3391 ResultSet resultSet = null;
3392 String sql = "SELECT * FROM correlation_types WHERE enabled=1";
3393
3394 try {
3395 preparedStatement = conn.prepareStatement(sql);
3396 resultSet = preparedStatement.executeQuery();
3397 while (resultSet.next()) {
3398 aTypes.add(getCorrelationTypeFromResultSet(resultSet));
3399 }
3400 return aTypes;
3401
3402 } catch (SQLException ex) {
3403 throw new CentralRepoException("Error getting enabled correlation types.", ex); // NON-NLS
3404 } finally {
3405 CentralRepoDbUtil.closeResultSet(resultSet);
3406 CentralRepoDbUtil.closeStatement(preparedStatement);
3407 CentralRepoDbUtil.closeConnection(conn);
3408 }
3409 }
3410
3420 @Override
3421 public List<CorrelationAttributeInstance.Type> getSupportedCorrelationTypes() throws CentralRepoException {
3422 Connection conn = connect();
3423
3424 List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
3425 PreparedStatement preparedStatement = null;
3426 ResultSet resultSet = null;
3427 String sql = "SELECT * FROM correlation_types WHERE supported=1";
3428
3429 try {
3430 preparedStatement = conn.prepareStatement(sql);
3431 resultSet = preparedStatement.executeQuery();
3432 while (resultSet.next()) {
3433 aTypes.add(getCorrelationTypeFromResultSet(resultSet));
3434 }
3435 return aTypes;
3436
3437 } catch (SQLException ex) {
3438 throw new CentralRepoException("Error getting supported correlation types.", ex); // NON-NLS
3439 } finally {
3440 CentralRepoDbUtil.closeResultSet(resultSet);
3441 CentralRepoDbUtil.closeStatement(preparedStatement);
3442 CentralRepoDbUtil.closeConnection(conn);
3443 }
3444 }
3445
3453 @Override
3454 public void updateCorrelationType(CorrelationAttributeInstance.Type aType) throws CentralRepoException {
3455 Connection conn = connect();
3456
3457 PreparedStatement preparedStatement = null;
3458 String sql = "UPDATE correlation_types SET display_name=?, db_table_name=?, supported=?, enabled=? WHERE id=?";
3459
3460 try {
3461 preparedStatement = conn.prepareStatement(sql);
3462 preparedStatement.setString(1, aType.getDisplayName());
3463 preparedStatement.setString(2, aType.getDbTableName());
3464 preparedStatement.setInt(3, aType.isSupported() ? 1 : 0);
3465 preparedStatement.setInt(4, aType.isEnabled() ? 1 : 0);
3466 preparedStatement.setInt(5, aType.getId());
3467 preparedStatement.executeUpdate();
3468 synchronized (typeCache) {
3469 typeCache.put(aType.getId(), aType);
3470 }
3471 } catch (SQLException ex) {
3472 throw new CentralRepoException("Error updating correlation type.", ex); // NON-NLS
3473 } finally {
3474 CentralRepoDbUtil.closeStatement(preparedStatement);
3475 CentralRepoDbUtil.closeConnection(conn);
3476 }
3477
3478 }
3479
3489 @Override
3490 public CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId) throws CentralRepoException {
3491 try {
3492 synchronized (typeCache) {
3493 return typeCache.get(typeId, () -> getCorrelationTypeByIdFromCr(typeId));
3494 }
3495 } catch (CacheLoader.InvalidCacheLoadException ignored) {
3496 //lambda valueloader returned a null value and cache can not store null values this is normal if the correlation type does not exist in the central repo yet
3497 return null;
3498 } catch (ExecutionException ex) {
3499 throw new CentralRepoException("Error getting correlation type", ex);
3500 }
3501 }
3502
3512 private CorrelationAttributeInstance.Type getCorrelationTypeByIdFromCr(int typeId) throws CentralRepoException {
3513 Connection conn = connect();
3514
3515 CorrelationAttributeInstance.Type aType;
3516 PreparedStatement preparedStatement = null;
3517 ResultSet resultSet = null;
3518 String sql = "SELECT * FROM correlation_types WHERE id=?";
3519
3520 try {
3521 preparedStatement = conn.prepareStatement(sql);
3522 preparedStatement.setInt(1, typeId);
3523 resultSet = preparedStatement.executeQuery();
3524 if (resultSet.next()) {
3525 aType = getCorrelationTypeFromResultSet(resultSet);
3526 return aType;
3527 } else {
3528 throw new CentralRepoException("Failed to find entry for correlation type ID = " + typeId);
3529 }
3530
3531 } catch (SQLException ex) {
3532 throw new CentralRepoException("Error getting correlation type by id.", ex); // NON-NLS
3533 } finally {
3534 CentralRepoDbUtil.closeResultSet(resultSet);
3535 CentralRepoDbUtil.closeStatement(preparedStatement);
3536 CentralRepoDbUtil.closeConnection(conn);
3537 }
3538 }
3539
3546 private void getCorrelationTypesFromCr() throws CentralRepoException {
3547
3548 // clear out the cache
3549 synchronized (typeCache) {
3550 typeCache.invalidateAll();
3551 isCRTypeCacheInitialized = false;
3552 }
3553
3554 String sql = "SELECT * FROM correlation_types";
3555 try (Connection conn = connect();
3556 PreparedStatement preparedStatement = conn.prepareStatement(sql);
3557 ResultSet resultSet = preparedStatement.executeQuery();) {
3558
3559 synchronized (typeCache) {
3560 while (resultSet.next()) {
3561 CorrelationAttributeInstance.Type aType = getCorrelationTypeFromResultSet(resultSet);
3562 typeCache.put(aType.getId(), aType);
3563 }
3564 isCRTypeCacheInitialized = true;
3565 }
3566 } catch (SQLException ex) {
3567 throw new CentralRepoException("Error getting correlation types.", ex); // NON-NLS
3568 }
3569 }
3570
3581 private CorrelationCase getEamCaseFromResultSet(ResultSet resultSet) throws SQLException {
3582 if (null == resultSet) {
3583 return null;
3584 }
3585
3586 CentralRepoOrganization eamOrg = null;
3587
3588 resultSet.getInt("org_id");
3589 if (!resultSet.wasNull()) {
3590
3591 eamOrg = new CentralRepoOrganization(resultSet.getInt("org_id"),
3592 resultSet.getString("org_name"),
3593 resultSet.getString("poc_name"),
3594 resultSet.getString("poc_email"),
3595 resultSet.getString("poc_phone"));
3596 }
3597
3598 CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
3599 resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
3600 resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes"));
3601
3602 return eamCase;
3603 }
3604
3605 private CorrelationDataSource getEamDataSourceFromResultSet(ResultSet resultSet) throws SQLException {
3606 if (null == resultSet) {
3607 return null;
3608 }
3609
3610 CorrelationDataSource eamDataSource = new CorrelationDataSource(
3611 resultSet.getInt("case_id"),
3612 resultSet.getInt("id"),
3613 resultSet.getString("device_id"),
3614 resultSet.getString("name"),
3615 resultSet.getLong("datasource_obj_id"),
3616 resultSet.getString("md5"),
3617 resultSet.getString("sha1"),
3618 resultSet.getString("sha256")
3619 );
3620
3621 return eamDataSource;
3622 }
3623
3624 private CorrelationAttributeInstance.Type getCorrelationTypeFromResultSet(ResultSet resultSet) throws CentralRepoException, SQLException {
3625 if (null == resultSet) {
3626 return null;
3627 }
3628
3629 CorrelationAttributeInstance.Type eamArtifactType = new CorrelationAttributeInstance.Type(
3630 resultSet.getInt("id"),
3631 resultSet.getString("display_name"),
3632 resultSet.getString("db_table_name"),
3633 resultSet.getBoolean("supported"),
3634 resultSet.getBoolean("enabled")
3635 );
3636
3637 return eamArtifactType;
3638 }
3639
3650 private CorrelationAttributeInstance getCorrAttrFromResultSet(ResultSet resultSet, CorrelationAttributeInstance.Type aType) throws SQLException, CentralRepoException, CorrelationAttributeNormalizationException {
3651 if (null == resultSet) {
3652 return null;
3653 }
3654
3655 CentralRepoOrganization eamOrg = new CentralRepoOrganization(resultSet.getInt("org_id"),
3656 resultSet.getString("org_name"),
3657 resultSet.getString("poc_name"),
3658 resultSet.getString("poc_email"),
3659 resultSet.getString("poc_phone"));
3660
3661 return new CorrelationAttributeInstance(
3662 aType,
3663 resultSet.getString("value"),
3664 resultSet.getInt("instance_id"),
3665 new CorrelationCase(resultSet.getInt("id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
3666 resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
3667 resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes")),
3668 new CorrelationDataSource(
3669 resultSet.getInt("id"), resultSet.getInt("data_source_id"), resultSet.getString("device_id"), resultSet.getString("name"),
3670 resultSet.getLong("datasource_obj_id"), resultSet.getString("md5"), resultSet.getString("sha1"), resultSet.getString("sha256")),
3671 resultSet.getString("file_path"),
3672 resultSet.getString("comment"),
3673 TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3674 resultSet.getLong("file_obj_id"));
3675 }
3676
3677 private CentralRepoOrganization getEamOrganizationFromResultSet(ResultSet resultSet) throws SQLException {
3678 if (null == resultSet) {
3679 return null;
3680 }
3681
3682 return new CentralRepoOrganization(
3683 resultSet.getInt("id"),
3684 resultSet.getString("org_name"),
3685 resultSet.getString("poc_name"),
3686 resultSet.getString("poc_email"),
3687 resultSet.getString("poc_phone")
3688 );
3689 }
3690
3691 private CentralRepoFileSet getEamGlobalSetFromResultSet(ResultSet resultSet) throws SQLException, CentralRepoException {
3692 if (null == resultSet) {
3693 return null;
3694 }
3695
3696 return new CentralRepoFileSet(
3697 resultSet.getInt("id"),
3698 resultSet.getInt("org_id"),
3699 resultSet.getString("set_name"),
3700 resultSet.getString("version"),
3701 TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3702 resultSet.getBoolean("read_only"),
3703 CentralRepository.getInstance().getCorrelationTypeById(resultSet.getInt("type")),
3704 LocalDate.parse(resultSet.getString("import_date"))
3705 );
3706 }
3707
3708 private CentralRepoFileInstance getEamGlobalFileInstanceFromResultSet(ResultSet resultSet) throws SQLException, CentralRepoException, CorrelationAttributeNormalizationException {
3709 if (null == resultSet) {
3710 return null;
3711 }
3712
3713 return new CentralRepoFileInstance(
3714 resultSet.getInt("id"),
3715 resultSet.getInt("reference_set_id"),
3716 resultSet.getString("value"),
3717 TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3718 resultSet.getString("comment")
3719 );
3720 }
3721
3722 private String getPlatformSpecificInsertSQL(String sql) throws CentralRepoException {
3723
3724 switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
3725 case POSTGRESQL:
3726 return "INSERT " + sql + " ON CONFLICT DO NOTHING"; //NON-NLS
3727 case SQLITE:
3728 return "INSERT OR IGNORE " + sql;
3729
3730 default:
3731 throw new CentralRepoException("Unknown Central Repo DB platform" + CentralRepoDbManager.getSavedDbChoice().getDbPlatform());
3732 }
3733 }
3734
3745 abstract boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException;
3746
3752 @Messages({"AbstractSqlEamDb.upgradeSchema.incompatible=The selected Central Repository is not compatible with the current version of the application, please upgrade the application if you wish to use this Central Repository.",
3753 "# {0} - minorVersion",
3754 "AbstractSqlEamDb.badMinorSchema.message=Bad value for schema minor version ({0}) - database is corrupt.",
3755 "AbstractSqlEamDb.failedToReadMinorVersion.message=Failed to read schema minor version for Central Repository.",
3756 "# {0} - majorVersion",
3757 "AbstractSqlEamDb.badMajorSchema.message=Bad value for schema version ({0}) - database is corrupt.",
3758 "AbstractSqlEamDb.failedToReadMajorVersion.message=Failed to read schema version for Central Repository.",
3759 "# {0} - platformName",
3760 "AbstractSqlEamDb.cannotUpgrage.message=Currently selected database platform \"{0}\" can not be upgraded."})
3761 @Override
3762 public void upgradeSchema() throws CentralRepoException, SQLException, IncompatibleCentralRepoException {
3763
3764 ResultSet resultSet = null;
3765 Statement statement = null;
3766 PreparedStatement preparedStatement = null;
3767 Connection conn = null;
3768 CentralRepoPlatforms selectedPlatform = null;
3769 try {
3770
3771 conn = connect(false);
3772 conn.setAutoCommit(false);
3773 statement = conn.createStatement();
3774 selectedPlatform = CentralRepoDbManager.getSavedDbChoice().getDbPlatform();
3775 int minorVersion = 0;
3776 String minorVersionStr = null;
3777 resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "'");
3778 if (resultSet.next()) {
3779 minorVersionStr = resultSet.getString("value");
3780 try {
3781 minorVersion = Integer.parseInt(minorVersionStr);
3782 } catch (NumberFormatException ex) {
3783 throw new CentralRepoException("Bad value for schema minor version (" + minorVersionStr + ") - database is corrupt", Bundle.AbstractSqlEamDb_badMinorSchema_message(minorVersionStr), ex);
3784 }
3785 } else {
3786 throw new CentralRepoException("Failed to read schema minor version from db_info table", Bundle.AbstractSqlEamDb_failedToReadMinorVersion_message());
3787 }
3788
3789 int majorVersion = 0;
3790 String majorVersionStr = null;
3791 resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "'");
3792 if (resultSet.next()) {
3793 majorVersionStr = resultSet.getString("value");
3794 try {
3795 majorVersion = Integer.parseInt(majorVersionStr);
3796 } catch (NumberFormatException ex) {
3797 throw new CentralRepoException("Bad value for schema version (" + majorVersionStr + ") - database is corrupt", Bundle.AbstractSqlEamDb_badMajorSchema_message(majorVersionStr), ex);
3798 }
3799 } else {
3800 throw new CentralRepoException("Failed to read schema major version from db_info table", Bundle.AbstractSqlEamDb_failedToReadMajorVersion_message());
3801 }
3802
3803 /*
3804 * IMPORTANT: The code that follows had a bug in it prior to Autopsy
3805 * 4.10.0. The consequence of the bug is that the schema version
3806 * number is always reset to 1.0 or 1.1 if a Central Repository is
3807 * opened by an Autopsy 4.9.1 or earlier client. To cope with this,
3808 * there is an effort in updates to 1.2 and greater to not retry
3809 * schema updates that may already have been done once.
3810 */
3811 CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(majorVersion, minorVersion);
3812
3813 //compare the major versions for compatability
3814 //we can not use the CaseDbSchemaVersionNumber.isCompatible method
3815 //because it is specific to case db schema versions only supporting major versions greater than 1
3816 if (SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() < dbSchemaVersion.getMajor()) {
3817 throw new IncompatibleCentralRepoException(Bundle.AbstractSqlEamDb_upgradeSchema_incompatible());
3818 }
3819 if (dbSchemaVersion.equals(SOFTWARE_CR_DB_SCHEMA_VERSION)) {
3820 logger.log(Level.INFO, "Central Repository is up to date");
3821 return;
3822 }
3823 if (dbSchemaVersion.compareTo(SOFTWARE_CR_DB_SCHEMA_VERSION) > 0) {
3824 logger.log(Level.INFO, "Central Repository is of newer version than software creates");
3825 return;
3826 }
3827
3828 /*
3829 * Update to 1.1
3830 */
3831 if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
3832 statement.execute("ALTER TABLE reference_sets ADD COLUMN known_status INTEGER;"); //NON-NLS
3833 statement.execute("ALTER TABLE reference_sets ADD COLUMN read_only BOOLEAN;"); //NON-NLS
3834 statement.execute("ALTER TABLE reference_sets ADD COLUMN type INTEGER;"); //NON-NLS
3835
3836 // There's an outide chance that the user has already made an organization with the default name,
3837 // and the default org being missing will not impact any database operations, so continue on
3838 // regardless of whether this succeeds.
3839 CentralRepoDbUtil.insertDefaultOrganization(conn);
3840 }
3841
3842 /*
3843 * Update to 1.2
3844 */
3845 if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) {
3846 final String addIntegerColumnTemplate = "ALTER TABLE %s ADD COLUMN %s INTEGER;"; //NON-NLS
3847
3848 final String addSsidTableTemplate = RdbmsCentralRepoFactory.getCreateArtifactInstancesTableTemplate(selectedPlatform);
3849 final String addCaseIdIndexTemplate = RdbmsCentralRepoFactory.getAddCaseIdIndexTemplate();
3850 final String addDataSourceIdIndexTemplate = RdbmsCentralRepoFactory.getAddDataSourceIdIndexTemplate();
3851 final String addValueIndexTemplate = RdbmsCentralRepoFactory.getAddValueIndexTemplate();
3852 final String addKnownStatusIndexTemplate = RdbmsCentralRepoFactory.getAddKnownStatusIndexTemplate();
3853 final String addObjectIdIndexTemplate = RdbmsCentralRepoFactory.getAddObjectIdIndexTemplate();
3854
3855 final String addAttributeSql;
3856 //get the data base specific code for creating a new _instance table
3857 switch (selectedPlatform) {
3858 case POSTGRESQL:
3859 addAttributeSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause(); //NON-NLS
3860 break;
3861 case SQLITE:
3862 addAttributeSql = "INSERT OR IGNORE INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)"; //NON-NLS
3863 break;
3864 default:
3865 throw new CentralRepoException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
3866 }
3867
3868 final String dataSourcesTableName = "data_sources";
3869 final String dataSourceObjectIdColumnName = "datasource_obj_id";
3870 if (!doesColumnExist(conn, dataSourcesTableName, dataSourceObjectIdColumnName)) {
3871 statement.execute(String.format(addIntegerColumnTemplate, dataSourcesTableName, dataSourceObjectIdColumnName)); //NON-NLS
3872 }
3873 final String dataSourceObjectIdIndexTemplate = "CREATE INDEX IF NOT EXISTS datasource_object_id ON data_sources (%s)";
3874 statement.execute(String.format(dataSourceObjectIdIndexTemplate, dataSourceObjectIdColumnName));
3875 List<String> instaceTablesToAdd = new ArrayList<>();
3876 //update central repository to be able to store new correlation attributes
3877 final String wirelessNetworksDbTableName = "wireless_networks";
3878 instaceTablesToAdd.add(wirelessNetworksDbTableName + "_instances");
3879 final String macAddressDbTableName = "mac_address";
3880 instaceTablesToAdd.add(macAddressDbTableName + "_instances");
3881 final String imeiNumberDbTableName = "imei_number";
3882 instaceTablesToAdd.add(imeiNumberDbTableName + "_instances");
3883 final String iccidNumberDbTableName = "iccid_number";
3884 instaceTablesToAdd.add(iccidNumberDbTableName + "_instances");
3885 final String imsiNumberDbTableName = "imsi_number";
3886 instaceTablesToAdd.add(imsiNumberDbTableName + "_instances");
3887
3888 //add the wireless_networks attribute to the correlation_types table
3889 preparedStatement = conn.prepareStatement(addAttributeSql);
3890 preparedStatement.setInt(1, CorrelationAttributeInstance.SSID_TYPE_ID);
3891 preparedStatement.setString(2, Bundle.CorrelationType_SSID_displayName());
3892 preparedStatement.setString(3, wirelessNetworksDbTableName);
3893 preparedStatement.setInt(4, 1);
3894 preparedStatement.setInt(5, 1);
3895 preparedStatement.execute();
3896
3897 //add the mac_address attribute to the correlation_types table
3898 preparedStatement = conn.prepareStatement(addAttributeSql);
3899 preparedStatement.setInt(1, CorrelationAttributeInstance.MAC_TYPE_ID);
3900 preparedStatement.setString(2, Bundle.CorrelationType_MAC_displayName());
3901 preparedStatement.setString(3, macAddressDbTableName);
3902 preparedStatement.setInt(4, 1);
3903 preparedStatement.setInt(5, 1);
3904 preparedStatement.execute();
3905
3906 //add the imei_number attribute to the correlation_types table
3907 preparedStatement = conn.prepareStatement(addAttributeSql);
3908 preparedStatement.setInt(1, CorrelationAttributeInstance.IMEI_TYPE_ID);
3909 preparedStatement.setString(2, Bundle.CorrelationType_IMEI_displayName());
3910 preparedStatement.setString(3, imeiNumberDbTableName);
3911 preparedStatement.setInt(4, 1);
3912 preparedStatement.setInt(5, 1);
3913 preparedStatement.execute();
3914
3915 //add the imsi_number attribute to the correlation_types table
3916 preparedStatement = conn.prepareStatement(addAttributeSql);
3917 preparedStatement.setInt(1, CorrelationAttributeInstance.IMSI_TYPE_ID);
3918 preparedStatement.setString(2, Bundle.CorrelationType_IMSI_displayName());
3919 preparedStatement.setString(3, imsiNumberDbTableName);
3920 preparedStatement.setInt(4, 1);
3921 preparedStatement.setInt(5, 1);
3922 preparedStatement.execute();
3923
3924 //add the iccid_number attribute to the correlation_types table
3925 preparedStatement = conn.prepareStatement(addAttributeSql);
3926 preparedStatement.setInt(1, CorrelationAttributeInstance.ICCID_TYPE_ID);
3927 preparedStatement.setString(2, Bundle.CorrelationType_ICCID_displayName());
3928 preparedStatement.setString(3, iccidNumberDbTableName);
3929 preparedStatement.setInt(4, 1);
3930 preparedStatement.setInt(5, 1);
3931 preparedStatement.execute();
3932
3933 //create a new _instances tables and add indexes for their columns
3934 for (String tableName : instaceTablesToAdd) {
3935 statement.execute(String.format(addSsidTableTemplate, tableName, tableName));
3936 statement.execute(String.format(addCaseIdIndexTemplate, tableName, tableName));
3937 statement.execute(String.format(addDataSourceIdIndexTemplate, tableName, tableName));
3938 statement.execute(String.format(addValueIndexTemplate, tableName, tableName));
3939 statement.execute(String.format(addKnownStatusIndexTemplate, tableName, tableName));
3940 }
3941
3942 //add file_obj_id column to _instances table which do not already have it
3943 String instance_type_dbname;
3944 final String objectIdColumnName = "file_obj_id";
3945 for (CorrelationAttributeInstance.Type type : CorrelationAttributeInstance.getDefaultCorrelationTypes()) {
3946 instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
3947 if (!doesColumnExist(conn, instance_type_dbname, objectIdColumnName)) {
3948 statement.execute(String.format(addIntegerColumnTemplate, instance_type_dbname, objectIdColumnName)); //NON-NLS
3949 }
3950 statement.execute(String.format(addObjectIdIndexTemplate, instance_type_dbname, instance_type_dbname));
3951 }
3952
3953 /*
3954 * Add hash columns to the data_sources table.
3955 */
3956 if (!doesColumnExist(conn, dataSourcesTableName, "md5")) {
3957 statement.execute("ALTER TABLE data_sources ADD COLUMN md5 TEXT DEFAULT NULL");
3958 }
3959 if (!doesColumnExist(conn, dataSourcesTableName, "sha1")) {
3960 statement.execute("ALTER TABLE data_sources ADD COLUMN sha1 TEXT DEFAULT NULL");
3961 }
3962 if (!doesColumnExist(conn, dataSourcesTableName, "sha256")) {
3963 statement.execute("ALTER TABLE data_sources ADD COLUMN sha256 TEXT DEFAULT NULL");
3964 }
3965
3966 /*
3967 * Drop the db_info table and add it back in with the name
3968 * column having a UNIQUE constraint. The name column could now
3969 * be used as the primary key, but the essentially useless id
3970 * column is retained for the sake of backwards compatibility.
3971 * Note that the creation schema version number is set to 0.0 to
3972 * indicate that it is unknown.
3973 */
3974 String creationMajorVer;
3975 resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "'");
3976 if (resultSet.next()) {
3977 creationMajorVer = resultSet.getString("value");
3978 } else {
3979 creationMajorVer = "0";
3980 }
3981 String creationMinorVer;
3982 resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "'");
3983 if (resultSet.next()) {
3984 creationMinorVer = resultSet.getString("value");
3985 } else {
3986 creationMinorVer = "0";
3987 }
3988 statement.execute("DROP TABLE db_info");
3989 if (selectedPlatform == CentralRepoPlatforms.POSTGRESQL) {
3990 statement.execute("CREATE TABLE db_info (id SERIAL, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3991 } else {
3992 statement.execute("CREATE TABLE db_info (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3993 }
3994 statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "','" + majorVersionStr + "')");
3995 statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "','" + minorVersionStr + "')");
3996 statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "','" + creationMajorVer + "')");
3997 statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "','" + creationMinorVer + "')");
3998 }
3999 /*
4000 * Update to 1.3
4001 */
4002 if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 3)) < 0) {
4003 switch (selectedPlatform) {
4004 case POSTGRESQL:
4005 statement.execute("ALTER TABLE data_sources DROP CONSTRAINT datasource_unique");
4006 //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
4007 statement.execute("ALTER TABLE data_sources ADD CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id)");
4008
4009 break;
4010 case SQLITE:
4011 statement.execute("DROP INDEX IF EXISTS data_sources_name");
4012 statement.execute("DROP INDEX IF EXISTS data_sources_object_id");
4013 statement.execute("ALTER TABLE data_sources RENAME TO old_data_sources");
4014 //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
4015 statement.execute("CREATE TABLE IF NOT EXISTS data_sources (id integer primary key autoincrement NOT NULL,"
4016 + "case_id integer NOT NULL,device_id text NOT NULL,name text NOT NULL,datasource_obj_id integer,"
4017 + "md5 text DEFAULT NULL,sha1 text DEFAULT NULL,sha256 text DEFAULT NULL,"
4018 + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,"
4019 + "CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id))");
4020 statement.execute(RdbmsCentralRepoFactory.getAddDataSourcesNameIndexStatement());
4021 statement.execute(RdbmsCentralRepoFactory.getAddDataSourcesObjectIdIndexStatement());
4022 statement.execute("INSERT INTO data_sources SELECT * FROM old_data_sources");
4023 statement.execute("DROP TABLE old_data_sources");
4024 break;
4025 default:
4026 throw new CentralRepoException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
4027 }
4028 }
4029
4030 // Upgrade to 1.4
4031 (new CentralRepoDbUpgrader13To14()).upgradeSchema(dbSchemaVersion, conn);
4032
4033 // Upgrade to 1.5
4034 (new CentralRepoDbUpgrader14To15()).upgradeSchema(dbSchemaVersion, conn);
4035
4036 // Upgrade to 1.6
4037 (new CentralRepoDbUpgrader15To16()).upgradeSchema(dbSchemaVersion, conn);
4038
4039 updateSchemaVersion(conn);
4040 conn.commit();
4041 logger.log(Level.INFO, String.format("Central Repository schema updated to version %s", SOFTWARE_CR_DB_SCHEMA_VERSION));
4042 } catch (SQLException | CentralRepoException ex) {
4043 try {
4044 if (conn != null) {
4045 conn.rollback();
4046 }
4047 } catch (SQLException ex2) {
4048 logger.log(Level.SEVERE, String.format("Central Repository rollback of failed schema update to %s failed", SOFTWARE_CR_DB_SCHEMA_VERSION), ex2);
4049 }
4050 throw ex;
4051 } finally {
4052 CentralRepoDbUtil.closeResultSet(resultSet);
4053 CentralRepoDbUtil.closeStatement(preparedStatement);
4054 CentralRepoDbUtil.closeStatement(statement);
4055 CentralRepoDbUtil.closeConnection(conn);
4056 }
4057 }
4058
4059}
List< CorrelationAttributeInstance.Type > getEnabledCorrelationTypes()
List< CorrelationAttributeInstance.Type > getSupportedCorrelationTypes()
List< CorrelationAttributeInstance.Type > getDefinedCorrelationTypes()

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.