Merge pull request #3482 from dgrove727/3437_ReadContentInputStreamError_1

3437 read content input stream error 1
This commit is contained in:
Richard Cordovano 2018-03-06 10:09:08 -05:00 committed by GitHub
commit f93bfe9965
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 219 additions and 119 deletions

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -44,6 +44,7 @@ import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.LocalFile; import org.sleuthkit.datamodel.LocalFile;
import org.sleuthkit.datamodel.LocalDirectory; import org.sleuthkit.datamodel.LocalDirectory;
import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.SlackFile;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.VirtualDirectory;
@ -69,18 +70,20 @@ public final class ContentUtils {
}); });
} }
// don't instantiate /**
* Don't instantiate
*/
private ContentUtils() { private ContentUtils() {
throw new AssertionError(); throw new AssertionError();
} }
/** /**
* Convert epoch seconds to a string value in the given time zone * Convert epoch seconds to a string value in the given time zone.
* *
* @param epochSeconds * @param epochSeconds Epoch seconds
* @param tzone * @param tzone Time zone
* *
* @return * @return The time
*/ */
public static String getStringTime(long epochSeconds, TimeZone tzone) { public static String getStringTime(long epochSeconds, TimeZone tzone) {
String time = "0000-00-00 00:00:00"; String time = "0000-00-00 00:00:00";
@ -93,6 +96,14 @@ public final class ContentUtils {
return time; return time;
} }
/**
* Convert epoch seconds to a string value (ISO8601) in the given time zone.
*
* @param epochSeconds Epoch seconds
* @param tzone Time zone
*
* @return The time
*/
public static String getStringTimeISO8601(long epochSeconds, TimeZone tzone) { public static String getStringTimeISO8601(long epochSeconds, TimeZone tzone) {
String time = "0000-00-00T00:00:00Z"; //NON-NLS String time = "0000-00-00T00:00:00Z"; //NON-NLS
if (epochSeconds != 0) { if (epochSeconds != 0) {
@ -109,12 +120,12 @@ public final class ContentUtils {
* Convert epoch seconds to a string value (convenience method) * Convert epoch seconds to a string value (convenience method)
* *
* @param epochSeconds * @param epochSeconds
* @param c * @param content
* *
* @return * @return
*/ */
public static String getStringTime(long epochSeconds, Content c) { public static String getStringTime(long epochSeconds, Content content) {
return getStringTime(epochSeconds, getTimeZone(c)); return getStringTime(epochSeconds, getTimeZone(content));
} }
/** /**
@ -130,13 +141,13 @@ public final class ContentUtils {
return getStringTimeISO8601(epochSeconds, getTimeZone(c)); return getStringTimeISO8601(epochSeconds, getTimeZone(c));
} }
public static TimeZone getTimeZone(Content c) { public static TimeZone getTimeZone(Content content) {
try { try {
if (!shouldDisplayTimesInLocalTime()) { if (!shouldDisplayTimesInLocalTime()) {
return TimeZone.getTimeZone("GMT"); return TimeZone.getTimeZone("GMT");
} else { } else {
final Content dataSource = c.getDataSource(); final Content dataSource = content.getDataSource();
if ((dataSource != null) && (dataSource instanceof Image)) { if ((dataSource != null) && (dataSource instanceof Image)) {
Image image = (Image) dataSource; Image image = (Image) dataSource;
return TimeZone.getTimeZone(image.getTimeZone()); return TimeZone.getTimeZone(image.getTimeZone());
@ -151,10 +162,21 @@ public final class ContentUtils {
} }
private static final SystemNameVisitor systemName = new SystemNameVisitor(); private static final SystemNameVisitor systemName = new SystemNameVisitor();
/**
* Get system name from content using SystemNameVisitor.
*
* @param content The content object.
*
* @return The system name.
*/
public static String getSystemName(Content content) { public static String getSystemName(Content content) {
return content.accept(systemName); return content.accept(systemName);
} }
/**
* Visitor designed to handle the system name (content name and ID
* appended).
*/
private static class SystemNameVisitor extends ContentVisitor.Default<String> { private static class SystemNameVisitor extends ContentVisitor.Default<String> {
SystemNameVisitor() { SystemNameVisitor() {
@ -220,6 +242,14 @@ public final class ContentUtils {
return totalRead; return totalRead;
} }
/**
* Write content to an output file.
*
* @param content The Content object.
* @param outputFile The output file.
*
* @throws IOException If the file could not be written.
*/
public static void writeToFile(Content content, java.io.File outputFile) throws IOException { public static void writeToFile(Content content, java.io.File outputFile) throws IOException {
writeToFile(content, outputFile, null, null, false); writeToFile(content, outputFile, null, null, false);
} }
@ -233,7 +263,9 @@ public final class ContentUtils {
* if it does * if it does
* @param cancelCheck A function used to check if the file write process * @param cancelCheck A function used to check if the file write process
* should be terminated. * should be terminated.
*
* @return number of bytes extracted * @return number of bytes extracted
*
* @throws IOException if file could not be written * @throws IOException if file could not be written
*/ */
public static long writeToFile(Content content, java.io.File outputFile, public static long writeToFile(Content content, java.io.File outputFile,
@ -260,7 +292,9 @@ public final class ContentUtils {
/** /**
* Helper to ignore the '.' and '..' directories * Helper to ignore the '.' and '..' directories
* @param dir the directory to check *
* @param dir the directory to check
*
* @return true if dir is a '.' or '..' directory, false otherwise * @return true if dir is a '.' or '..' directory, false otherwise
*/ */
public static boolean isDotDirectory(AbstractFile dir) { public static boolean isDotDirectory(AbstractFile dir) {
@ -313,61 +347,81 @@ public final class ContentUtils {
} }
@Override @Override
public Void visit(File f) { public Void visit(File file) {
try { try {
ContentUtils.writeToFile(f, dest, progress, worker, source); ContentUtils.writeToFile(file, dest, progress, worker, source);
} catch (ReadContentInputStreamException ex) {
logger.log(Level.WARNING,
String.format("Error reading file '%s' (id=%d).",
file.getName(), file.getId()), ex); //NON-NLS
} catch (IOException ex) { } catch (IOException ex) {
logger.log(Level.SEVERE, logger.log(Level.SEVERE,
"Trouble extracting file to " + dest.getAbsolutePath(), //NON-NLS String.format("Error extracting file '%s' (id=%d) to '%s'.",
ex); file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
} }
return null; return null;
} }
@Override @Override
public Void visit(LayoutFile f) { public Void visit(LayoutFile file) {
try { try {
ContentUtils.writeToFile(f, dest, progress, worker, source); ContentUtils.writeToFile(file, dest, progress, worker, source);
} catch (ReadContentInputStreamException ex) {
logger.log(Level.WARNING,
String.format("Error reading file '%s' (id=%d).",
file.getName(), file.getId()), ex); //NON-NLS
} catch (IOException ex) { } catch (IOException ex) {
logger.log(Level.SEVERE, logger.log(Level.SEVERE,
"Trouble extracting unallocated content file to " + dest.getAbsolutePath(), //NON-NLS String.format("Error extracting unallocated content file '%s' (id=%d) to '%s'.",
ex); file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
} }
return null; return null;
} }
@Override @Override
public Void visit(DerivedFile df) { public Void visit(DerivedFile file) {
try { try {
ContentUtils.writeToFile(df, dest, progress, worker, source); ContentUtils.writeToFile(file, dest, progress, worker, source);
} catch (ReadContentInputStreamException ex) {
logger.log(Level.WARNING,
String.format("Error reading file '%s' (id=%d).",
file.getName(), file.getId()), ex); //NON-NLS
} catch (IOException ex) { } catch (IOException ex) {
logger.log(Level.SEVERE, logger.log(Level.SEVERE,
"Error extracting derived file to " + dest.getAbsolutePath(), //NON-NLS String.format("Error extracting derived file '%s' (id=%d) to '%s'.",
ex); file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
} }
return null; return null;
} }
@Override @Override
public Void visit(LocalFile lf) { public Void visit(LocalFile file) {
try { try {
ContentUtils.writeToFile(lf, dest, progress, worker, source); ContentUtils.writeToFile(file, dest, progress, worker, source);
} catch (ReadContentInputStreamException ex) {
logger.log(Level.WARNING,
String.format("Error reading file '%s' (id=%d).",
file.getName(), file.getId()), ex); //NON-NLS
} catch (IOException ex) { } catch (IOException ex) {
logger.log(Level.SEVERE, logger.log(Level.SEVERE,
"Error extracting local file to " + dest.getAbsolutePath(), //NON-NLS String.format("Error extracting local file '%s' (id=%d) to '%s'.",
ex); file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
} }
return null; return null;
} }
@Override @Override
public Void visit(SlackFile f) { public Void visit(SlackFile file) {
try { try {
ContentUtils.writeToFile(f, dest, progress, worker, source); ContentUtils.writeToFile(file, dest, progress, worker, source);
} catch (ReadContentInputStreamException ex) {
logger.log(Level.WARNING,
String.format("Error reading file '%s' (id=%d).",
file.getName(), file.getId()), ex); //NON-NLS
} catch (IOException ex) { } catch (IOException ex) {
logger.log(Level.SEVERE, logger.log(Level.SEVERE,
"Trouble extracting slack file to " + dest.getAbsolutePath(), //NON-NLS String.format("Error extracting slack file '%s' (id=%d) to '%s'.",
ex); file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
} }
return null; return null;
} }
@ -387,9 +441,9 @@ public final class ContentUtils {
return visitDir(dir); return visitDir(dir);
} }
private java.io.File getFsContentDest(Content fsc) { private java.io.File getFsContentDest(Content content) {
String path = dest.getAbsolutePath() + java.io.File.separator String path = dest.getAbsolutePath() + java.io.File.separator
+ fsc.getName(); + content.getName();
return new java.io.File(path); return new java.io.File(path);
} }
@ -406,7 +460,7 @@ public final class ContentUtils {
int numProcessed = 0; int numProcessed = 0;
// recurse on children // recurse on children
for (Content child : dir.getChildren()) { for (Content child : dir.getChildren()) {
if (child instanceof AbstractFile){ //ensure the directory's artifact children are ignored if (child instanceof AbstractFile) { //ensure the directory's artifact children are ignored
java.io.File childFile = getFsContentDest(child); java.io.File childFile = getFsContentDest(child);
ExtractFscContentVisitor<T, V> childVisitor ExtractFscContentVisitor<T, V> childVisitor
= new ExtractFscContentVisitor<>(childFile, progress, worker, false); = new ExtractFscContentVisitor<>(childFile, progress, worker, false);
@ -414,10 +468,10 @@ public final class ContentUtils {
// will have a progress and worker, and will keep track // will have a progress and worker, and will keep track
// of the progress bar's progress // of the progress bar's progress
if (worker != null && worker.isCancelled()) { if (worker != null && worker.isCancelled()) {
break; break;
} }
if (progress != null && source) { if (progress != null && source) {
progress.progress(child.getName(), numProcessed); progress.progress(child.getName(), numProcessed);
} }
child.accept(childVisitor); child.accept(childVisitor);
numProcessed++; numProcessed++;

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2014 Basis Technology Corp. * Copyright 2014-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -37,10 +37,14 @@ import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
class CallLogAnalyzer { /**
* Look for call logs and allow resulting blackboard artifacts to be generated.
*/
final class CallLogAnalyzer {
private Connection connection = null; private Connection connection = null;
private ResultSet resultSet = null; private ResultSet resultSet = null;
@ -48,10 +52,15 @@ class CallLogAnalyzer {
private String dbPath = ""; private String dbPath = "";
private long fileId = 0; private long fileId = 0;
private java.io.File jFile = null; private java.io.File jFile = null;
private String moduleName = iOSModuleFactory.getModuleName(); private final String moduleName = iOSModuleFactory.getModuleName();
private static final Logger logger = Logger.getLogger(CallLogAnalyzer.class.getName()); private static final Logger logger = Logger.getLogger(CallLogAnalyzer.class.getName());
private Blackboard blackboard; private Blackboard blackboard;
/**
* Find call logs given an ingest job context and index the results.
*
* @param context The ingest job context.
*/
public void findCallLogs(IngestJobContext context) { public void findCallLogs(IngestJobContext context) {
blackboard = Case.getCurrentCase().getServices().getBlackboard(); blackboard = Case.getCurrentCase().getServices().getBlackboard();
List<AbstractFile> absFiles; List<AbstractFile> absFiles;
@ -61,15 +70,17 @@ class CallLogAnalyzer {
if (absFiles.isEmpty()) { if (absFiles.isEmpty()) {
return; return;
} }
for (AbstractFile AF : absFiles) { for (AbstractFile file : absFiles) {
try { try {
jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), AF.getName().replaceAll("[<>%|\"/:*\\\\]", "")); jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), file.getName().replaceAll("[<>%|\"/:*\\\\]", ""));
ContentUtils.writeToFile(AF, jFile, context::dataSourceIngestIsCancelled);
dbPath = jFile.toString(); //path of file as string dbPath = jFile.toString(); //path of file as string
fileId = AF.getId(); fileId = file.getId();
ContentUtils.writeToFile(file, jFile, context::dataSourceIngestIsCancelled);
findCallLogsInDB(dbPath, fileId); findCallLogsInDB(dbPath, fileId);
} catch (Exception e) { } catch (ReadContentInputStreamException ex) {
logger.log(Level.SEVERE, "Error parsing Call logs", e); //NON-NLS logger.log(Level.WARNING, String.format("Error reading content from file '%s' (id=%d).", file.getName(), fileId), ex); //NON-NLS
} catch (Exception ex) {
logger.log(Level.SEVERE, String.format("Error writing content from file '%s' (id=%d) to '%s'.", file.getName(), fileId, dbPath), ex); //NON-NLS
} }
} }
} catch (TskCoreException e) { } catch (TskCoreException e) {
@ -77,8 +88,14 @@ class CallLogAnalyzer {
} }
} }
/**
* Index results for call logs found in the database.
*
* @param DatabasePath The path to the database.
* @param fileId The ID of the file associated with artifacts.
*/
@Messages({"CallLogAnalyzer.indexError.message=Failed to index call log artifact for keyword search."}) @Messages({"CallLogAnalyzer.indexError.message=Failed to index call log artifact for keyword search."})
private void findCallLogsInDB(String DatabasePath, long fId) { private void findCallLogsInDB(String DatabasePath, long fileId) {
if (DatabasePath == null || DatabasePath.isEmpty()) { if (DatabasePath == null || DatabasePath.isEmpty()) {
return; return;
} }
@ -93,9 +110,9 @@ class CallLogAnalyzer {
Case currentCase = Case.getCurrentCase(); Case currentCase = Case.getCurrentCase();
SleuthkitCase skCase = currentCase.getSleuthkitCase(); SleuthkitCase skCase = currentCase.getSleuthkitCase();
try { try {
AbstractFile f = skCase.getAbstractFileById(fId); AbstractFile file = skCase.getAbstractFileById(fileId);
if (f == null) { if (file == null) {
logger.log(Level.SEVERE, "Error getting abstract file " + fId); //NON-NLS logger.log(Level.SEVERE, "Error getting abstract file {0}", fileId); //NON-NLS
return; return;
} }
@ -117,7 +134,7 @@ class CallLogAnalyzer {
date = resultSet.getString("date"); //NON-NLS date = resultSet.getString("date"); //NON-NLS
type = resultSet.getString("type"); //NON-NLS type = resultSet.getString("type"); //NON-NLS
bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG); //create a call log and then add attributes from result set. bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG); //create a call log and then add attributes from result set.
Collection<BlackboardAttribute> attributes = new ArrayList<>(); Collection<BlackboardAttribute> attributes = new ArrayList<>();
if (type.equalsIgnoreCase("outgoing")) { //NON-NLS if (type.equalsIgnoreCase("outgoing")) { //NON-NLS
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, moduleName, number)); attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, moduleName, number));

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2014 Basis Technology Corp. * Copyright 2014-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -43,10 +43,14 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
class ContactAnalyzer { /**
* Look for call logs and allow resulting blackboard artifacts to be generated.
*/
final class ContactAnalyzer {
private Connection connection = null; private Connection connection = null;
private ResultSet resultSet = null; private ResultSet resultSet = null;
@ -54,10 +58,15 @@ class ContactAnalyzer {
private String dbPath = ""; private String dbPath = "";
private long fileId = 0; private long fileId = 0;
private java.io.File jFile = null; private java.io.File jFile = null;
private String moduleName = iOSModuleFactory.getModuleName(); private final String moduleName = iOSModuleFactory.getModuleName();
private static final Logger logger = Logger.getLogger(ContactAnalyzer.class.getName()); private static final Logger logger = Logger.getLogger(ContactAnalyzer.class.getName());
private Blackboard blackboard; private Blackboard blackboard;
/**
* Find contacts given an ingest job context and index the results.
*
* @param context The ingest job context.
*/
public void findContacts(IngestJobContext context) { public void findContacts(IngestJobContext context) {
blackboard = Case.getCurrentCase().getServices().getBlackboard(); blackboard = Case.getCurrentCase().getServices().getBlackboard();
@ -68,18 +77,16 @@ class ContactAnalyzer {
if (absFiles.isEmpty()) { if (absFiles.isEmpty()) {
return; return;
} }
for (AbstractFile AF : absFiles) { for (AbstractFile file : absFiles) {
try { try {
jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), AF.getName().replaceAll("[<>%|\"/:*\\\\]", "")); jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), file.getName().replaceAll("[<>%|\"/:*\\\\]", ""));
//jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), i+".txt");
ContentUtils.writeToFile(AF, jFile, context::dataSourceIngestIsCancelled);
//copyFileUsingStreams(AF,jFile);
//copyFileUsingStream(AF,jFile);
dbPath = jFile.toString(); //path of file as string dbPath = jFile.toString(); //path of file as string
fileId = AF.getId(); fileId = file.getId();
//findContactsInDB(dbPath, fileId); ContentUtils.writeToFile(file, jFile, context::dataSourceIngestIsCancelled);
} catch (Exception e) { } catch (ReadContentInputStreamException ex) {
logger.log(Level.SEVERE, "Error parsing Contacts", e); //NON-NLS logger.log(Level.WARNING, String.format("Error reading content from file '%s' (id=%d).", file.getName(), fileId), ex); //NON-NLS
} catch (Exception ex) {
logger.log(Level.SEVERE, String.format("Error writing content from file '%s' (id=%d) to '%s'.", file.getName(), fileId, dbPath), ex); //NON-NLS
} }
} }
} catch (TskCoreException e) { } catch (TskCoreException e) {
@ -88,14 +95,14 @@ class ContactAnalyzer {
} }
/** /**
* Create blackboard artifacts and index results for call logs found in the
* database.
* *
* @param DatabasePath * @param DatabasePath The path to the database.
* @param fId Will create artifact from a database given by the * @param fileId The ID of the file associated with artifacts.
* path The fileId will be the Abstract file associated
* with the artifacts
*/ */
@Messages({"ContactAnalyzer.indexError.message=Failed to index contact artifact for keyword search."}) @Messages({"ContactAnalyzer.indexError.message=Failed to index contact artifact for keyword search."})
private void findContactsInDB(String DatabasePath, long fId) { private void findContactsInDB(String DatabasePath, long fileId) {
if (DatabasePath == null || DatabasePath.isEmpty()) { if (DatabasePath == null || DatabasePath.isEmpty()) {
return; return;
} }
@ -110,9 +117,9 @@ class ContactAnalyzer {
Case currentCase = Case.getCurrentCase(); Case currentCase = Case.getCurrentCase();
SleuthkitCase skCase = currentCase.getSleuthkitCase(); SleuthkitCase skCase = currentCase.getSleuthkitCase();
try { try {
AbstractFile f = skCase.getAbstractFileById(fId); AbstractFile file = skCase.getAbstractFileById(fileId);
if (f == null) { if (file == null) {
logger.log(Level.SEVERE, "Error getting abstract file " + fId); //NON-NLS logger.log(Level.SEVERE, "Error getting abstract file {0}", fileId); //NON-NLS
return; return;
} }
@ -129,7 +136,7 @@ class ContactAnalyzer {
+ "ORDER BY name_raw_contact.display_name ASC;"); //NON-NLS + "ORDER BY name_raw_contact.display_name ASC;"); //NON-NLS
BlackboardArtifact bba; BlackboardArtifact bba;
bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT); bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT);
Collection<BlackboardAttribute> attributes = new ArrayList<>(); Collection<BlackboardAttribute> attributes = new ArrayList<>();
String name; String name;
String oldName = ""; String oldName = "";

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2014 Basis Technology Corp. * Copyright 2014-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -38,9 +38,14 @@ import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/**
* Look for text messages and allow resulting blackboard artifacts to be
* generated.
*/
class TextMessageAnalyzer { class TextMessageAnalyzer {
private Connection connection = null; private Connection connection = null;
@ -50,10 +55,15 @@ class TextMessageAnalyzer {
private long fileId = 0; private long fileId = 0;
private java.io.File jFile = null; private java.io.File jFile = null;
List<AbstractFile> absFiles; List<AbstractFile> absFiles;
private String moduleName = iOSModuleFactory.getModuleName(); private final String moduleName = iOSModuleFactory.getModuleName();
private static final Logger logger = Logger.getLogger(TextMessageAnalyzer.class.getName()); private static final Logger logger = Logger.getLogger(TextMessageAnalyzer.class.getName());
private Blackboard blackboard; private Blackboard blackboard;
/**
* Find text messages given an ingest job context and index the results.
*
* @param context The ingest job context.
*/
void findTexts(IngestJobContext context) { void findTexts(IngestJobContext context) {
blackboard = Case.getCurrentCase().getServices().getBlackboard(); blackboard = Case.getCurrentCase().getServices().getBlackboard();
try { try {
@ -62,15 +72,17 @@ class TextMessageAnalyzer {
if (absFiles.isEmpty()) { if (absFiles.isEmpty()) {
return; return;
} }
for (AbstractFile AF : absFiles) { for (AbstractFile file : absFiles) {
try { try {
jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), AF.getName().replaceAll("[<>%|\"/:*\\\\]", "")); jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), file.getName().replaceAll("[<>%|\"/:*\\\\]", ""));
ContentUtils.writeToFile(AF, jFile, context::dataSourceIngestIsCancelled);
dbPath = jFile.toString(); //path of file as string dbPath = jFile.toString(); //path of file as string
fileId = AF.getId(); fileId = file.getId();
ContentUtils.writeToFile(file, jFile, context::dataSourceIngestIsCancelled);
findTextsInDB(dbPath, fileId); findTextsInDB(dbPath, fileId);
} catch (Exception e) { } catch (ReadContentInputStream.ReadContentInputStreamException ex) {
logger.log(Level.SEVERE, "Error parsing text messages", e); //NON-NLS logger.log(Level.WARNING, String.format("Error reading content from file '%s' (id=%d).", file.getName(), fileId), ex); //NON-NLS
} catch (Exception ex) {
logger.log(Level.SEVERE, String.format("Error writing content from file '%s' (id=%d) to '%s'.", file.getName(), fileId, dbPath), ex); //NON-NLS
} }
} }
} catch (TskCoreException e) { } catch (TskCoreException e) {
@ -78,8 +90,15 @@ class TextMessageAnalyzer {
} }
} }
/**
* Create blackboard artifacts and index results for text messages found in
* the database.
*
* @param DatabasePath The path to the database.
* @param fileId The ID of the file associated with artifacts.
*/
@Messages({"TextMessageAnalyzer.indexError.message=Failed to index text message artifact for keyword search."}) @Messages({"TextMessageAnalyzer.indexError.message=Failed to index text message artifact for keyword search."})
private void findTextsInDB(String DatabasePath, long fId) { private void findTextsInDB(String DatabasePath, long fileId) {
if (DatabasePath == null || DatabasePath.isEmpty()) { if (DatabasePath == null || DatabasePath.isEmpty()) {
return; return;
} }
@ -94,9 +113,9 @@ class TextMessageAnalyzer {
Case currentCase = Case.getCurrentCase(); Case currentCase = Case.getCurrentCase();
SleuthkitCase skCase = currentCase.getSleuthkitCase(); SleuthkitCase skCase = currentCase.getSleuthkitCase();
try { try {
AbstractFile f = skCase.getAbstractFileById(fId); AbstractFile file = skCase.getAbstractFileById(fileId);
if (f == null) { if (file == null) {
logger.log(Level.SEVERE, "Error getting abstract file " + fId); //NON-NLS logger.log(Level.SEVERE, "Error getting abstract file {0}", fileId); //NON-NLS
return; return;
} }
@ -117,7 +136,7 @@ class TextMessageAnalyzer {
subject = resultSet.getString("subject"); //NON-NLS subject = resultSet.getString("subject"); //NON-NLS
body = resultSet.getString("body"); //NON-NLS body = resultSet.getString("body"); //NON-NLS
bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); //create Message artifact and then add attributes from result set. bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); //create Message artifact and then add attributes from result set.
Collection<BlackboardAttribute> attributes = new ArrayList<>(); Collection<BlackboardAttribute> attributes = new ArrayList<>();
// @@@ NEed to put into more specific TO or FROM // @@@ NEed to put into more specific TO or FROM
if (type.equals("1")) { if (type.equals("1")) {

View File

@ -43,6 +43,7 @@ import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter; import org.jdom2.output.XMLOutputter;
import org.jdom2.CDATA; import org.jdom2.CDATA;
import org.openide.filesystems.FileUtil; import org.openide.filesystems.FileUtil;
import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
/** /**
* Generates a KML file based on geospatial information from the BlackBoard. * Generates a KML file based on geospatial information from the BlackBoard.
@ -67,7 +68,7 @@ class ReportKML implements GeneralReportModule {
PURPLE("style.kml#purpleFeature"), PURPLE("style.kml#purpleFeature"),
WHITE("style.kml#whiteFeature"), WHITE("style.kml#whiteFeature"),
YELLOW("style.kml#yellowFeature"); YELLOW("style.kml#yellowFeature");
private String color; private final String color;
FeatureColor(String color) { FeatureColor(String color) {
this.color = color; this.color = color;
@ -197,6 +198,8 @@ class ReportKML implements GeneralReportModule {
*/ */
try { try {
for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)) { for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)) {
String fileName = "";
long fileId = 0;
try { try {
Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED); Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED);
String desc = getDescriptionFromArtifact(artifact, "EXIF Metadata With Locations"); //NON-NLS String desc = getDescriptionFromArtifact(artifact, "EXIF Metadata With Locations"); //NON-NLS
@ -206,7 +209,9 @@ class ReportKML implements GeneralReportModule {
if (lat != null && lat != 0.0 && lon != null && lon != 0.0) { if (lat != null && lat != 0.0 && lon != null && lon != 0.0) {
AbstractFile abstractFile = artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID()); AbstractFile abstractFile = artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID());
Path path = null; fileName = abstractFile.getName();
fileId = abstractFile.getId();
Path path;
copyFileUsingStream(abstractFile, Paths.get(baseReportDir, abstractFile.getName()).toFile()); copyFileUsingStream(abstractFile, Paths.get(baseReportDir, abstractFile.getName()).toFile());
try { try {
path = Paths.get(removeLeadingImgAndVol(abstractFile.getUniquePath())); path = Paths.get(removeLeadingImgAndVol(abstractFile.getUniquePath()));
@ -219,6 +224,8 @@ class ReportKML implements GeneralReportModule {
} }
gpsExifMetadataFolder.addContent(makePlacemarkWithPicture(abstractFile.getName(), FeatureColor.RED, desc, timestamp, point, path, formattedCoordinates)); gpsExifMetadataFolder.addContent(makePlacemarkWithPicture(abstractFile.getName(), FeatureColor.RED, desc, timestamp, point, path, formattedCoordinates));
} }
} catch (ReadContentInputStreamException ex) {
logger.log(Level.WARNING, String.format("Error reading file '%s' (id=%d).", fileName, fileId), ex);
} catch (Exception ex) { } catch (Exception ex) {
logger.log(Level.SEVERE, "Could not extract photo information.", ex); //NON-NLS logger.log(Level.SEVERE, "Could not extract photo information.", ex); //NON-NLS
result = ReportProgressPanel.ReportStatus.ERROR; result = ReportProgressPanel.ReportStatus.ERROR;
@ -404,9 +411,7 @@ class ReportKML implements GeneralReportModule {
BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type)); BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
if (bba != null) { if (bba != null) {
Double value = bba.getValueDouble(); Double value = bba.getValueDouble();
if (value != null) { returnValue = value;
returnValue = value;
}
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting Double value: " + type.toString(), ex); //NON-NLS logger.log(Level.SEVERE, "Error getting Double value: " + type.toString(), ex); //NON-NLS
@ -428,9 +433,7 @@ class ReportKML implements GeneralReportModule {
BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type)); BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
if (bba != null) { if (bba != null) {
Long value = bba.getValueLong(); Long value = bba.getValueLong();
if (value != null) { returnValue = value;
returnValue = value;
}
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting Long value: " + type.toString(), ex); //NON-NLS logger.log(Level.SEVERE, "Error getting Long value: " + type.toString(), ex); //NON-NLS
@ -452,9 +455,7 @@ class ReportKML implements GeneralReportModule {
BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type)); BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
if (bba != null) { if (bba != null) {
Integer value = bba.getValueInt(); Integer value = bba.getValueInt();
if (value != null) { returnValue = value;
returnValue = value;
}
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting Integer value: " + type.toString(), ex); //NON-NLS logger.log(Level.SEVERE, "Error getting Integer value: " + type.toString(), ex); //NON-NLS
@ -662,11 +663,11 @@ class ReportKML implements GeneralReportModule {
if (altitude != 0) { if (altitude != 0) {
/* /*
Though we are including a non-zero altitude, clamp it to the * Though we are including a non-zero altitude, clamp it to the
ground because inaccuracies from the GPS data can cause the terrain * ground because inaccuracies from the GPS data can cause the
to occlude points when zoomed in otherwise. Show the altitude, but * terrain to occlude points when zoomed in otherwise. Show the
keep the point clamped to the ground. We may change this later for * altitude, but keep the point clamped to the ground. We may change
flying GPS sensors. * this later for flying GPS sensors.
*/ */
Element altitudeMode = new Element("altitudeMode", ns).addContent("clampToGround"); //NON-NLS Element altitudeMode = new Element("altitudeMode", ns).addContent("clampToGround"); //NON-NLS
point.addContent(altitudeMode); point.addContent(altitudeMode);
@ -811,9 +812,11 @@ class ReportKML implements GeneralReportModule {
* @param inputFile The input AbstractFile to copy * @param inputFile The input AbstractFile to copy
* @param outputFile the output file * @param outputFile the output file
* *
* @throws IOException * @throws ReadContentInputStreamException When a read error occurs.
* @throws IOException When a general file exception
* occurs.
*/ */
private void copyFileUsingStream(AbstractFile inputFile, File outputFile) throws IOException { private void copyFileUsingStream(AbstractFile inputFile, File outputFile) throws ReadContentInputStreamException, IOException {
byte[] buffer = new byte[65536]; byte[] buffer = new byte[65536];
int length; int length;
outputFile.createNewFile(); outputFile.createNewFile();