Autopsy  4.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ThunderbirdMboxFileIngestModule.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2014 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.thunderbirdparser;
20 
21 import java.io.File;
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.logging.Level;
26 import org.openide.util.NbBundle;
41 import org.sleuthkit.datamodel.AbstractFile;
42 import org.sleuthkit.datamodel.BlackboardArtifact;
43 import org.sleuthkit.datamodel.BlackboardAttribute;
44 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
45 import org.sleuthkit.datamodel.DerivedFile;
46 import org.sleuthkit.datamodel.TskCoreException;
47 import org.sleuthkit.datamodel.TskData;
48 import org.sleuthkit.datamodel.TskException;
49 
55 public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
56 
57  private static final Logger logger = Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName());
62 
64  }
65 
66  @Override
67  public void startUp(IngestJobContext context) throws IngestModuleException {
68  this.context = context;
69  fileManager = Case.getCurrentCase().getServices().getFileManager();
70  }
71 
72  @Override
73  public ProcessResult process(AbstractFile abstractFile) {
74 
75  blackboard = Case.getCurrentCase().getServices().getBlackboard();
76 
77  // skip known
78  if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) {
79  return ProcessResult.OK;
80  }
81 
82  //skip unalloc
83  if (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
84  return ProcessResult.OK;
85  }
86 
87  if ((abstractFile.isFile() == false)) {
88  return ProcessResult.OK;
89  }
90 
91  // check its signature
92  boolean isMbox = false;
93  try {
94  byte[] t = new byte[64];
95  if (abstractFile.getSize() > 64) {
96  int byteRead = abstractFile.read(t, 0, 64);
97  if (byteRead > 0) {
98  isMbox = MboxParser.isValidMimeTypeMbox(t);
99  }
100  }
101  } catch (TskException ex) {
102  logger.log(Level.WARNING, null, ex);
103  }
104 
105  if (isMbox) {
106  return processMBox(abstractFile);
107  }
108 
109  if (PstParser.isPstFile(abstractFile)) {
110  return processPst(abstractFile);
111  }
112 
113  return ProcessResult.OK;
114  }
115 
123  private ProcessResult processPst(AbstractFile abstractFile) {
124  String fileName = getTempPath() + File.separator + abstractFile.getName()
125  + "-" + String.valueOf(abstractFile.getId());
126  File file = new File(fileName);
127 
128  long freeSpace = services.getFreeDiskSpace();
129  if ((freeSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN) && (abstractFile.getSize() >= freeSpace)) {
130  logger.log(Level.WARNING, "Not enough disk space to write file to disk."); //NON-NLS
132  NbBundle.getMessage(this.getClass(),
133  "ThunderbirdMboxFileIngestModule.processPst.errMsg.outOfDiskSpace",
134  abstractFile.getName()));
135  services.postMessage(msg);
136  return ProcessResult.OK;
137  }
138 
139  try {
140  ContentUtils.writeToFile(abstractFile, file);
141  } catch (IOException ex) {
142  logger.log(Level.WARNING, "Failed writing pst file to disk.", ex); //NON-NLS
143  return ProcessResult.OK;
144  }
145 
146  PstParser parser = new PstParser(services);
147  PstParser.ParseResult result = parser.parse(file, abstractFile.getId());
148 
149  if (result == PstParser.ParseResult.OK) {
150  // parse success: Process email and add artifacts
151  processEmails(parser.getResults(), abstractFile);
152  } else if (result == PstParser.ParseResult.ENCRYPT) {
153  // encrypted pst: Add encrypted file artifact
154  try {
155  BlackboardArtifact artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
156  artifact.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, EmailParserModuleFactory.getModuleName(), NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.encryptionFileLevel")));
157 
158  try {
159  // index the artifact for keyword search
160  blackboard.indexArtifact(artifact);
161  } catch (Blackboard.BlackboardException ex) {
162  logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", artifact.getDisplayName()), ex); //NON-NLS
164  NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), artifact.getDisplayName());
165  }
166 
167  services.fireModuleDataEvent(new ModuleDataEvent(EmailParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED));
168  } catch (TskCoreException ex) {
169  logger.log(Level.INFO, "Failed to add encryption attribute to file: {0}", abstractFile.getName()); //NON-NLS
170  }
171  } else {
172  // parsing error: log message
173  postErrorMessage(
174  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg",
175  abstractFile.getName()),
176  NbBundle.getMessage(this.getClass(),
177  "ThunderbirdMboxFileIngestModule.processPst.errProcFile.details"));
178  logger.log(Level.INFO, "PSTParser failed to parse {0}", abstractFile.getName()); //NON-NLS
179  return ProcessResult.ERROR;
180  }
181 
182  if (file.delete() == false) {
183  logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
184  }
185 
186  String errors = parser.getErrors();
187  if (errors.isEmpty() == false) {
188  postErrorMessage(
189  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg2",
190  abstractFile.getName()), errors);
191  }
192 
193  return ProcessResult.OK;
194  }
195 
204  private ProcessResult processMBox(AbstractFile abstractFile) {
205  String mboxFileName = abstractFile.getName();
206  String mboxParentDir = abstractFile.getParentPath();
207  // use the local path to determine the e-mail folder structure
208  String emailFolder = "";
209  // email folder is everything after "Mail" or ImapMail
210  if (mboxParentDir.contains("/Mail/")) { //NON-NLS
211  emailFolder = mboxParentDir.substring(mboxParentDir.indexOf("/Mail/") + 5); //NON-NLS
212  } else if (mboxParentDir.contains("/ImapMail/")) { //NON-NLS
213  emailFolder = mboxParentDir.substring(mboxParentDir.indexOf("/ImapMail/") + 9); //NON-NLS
214  }
215  emailFolder = emailFolder + mboxFileName;
216  emailFolder = emailFolder.replaceAll(".sbd", ""); //NON-NLS
217 
218  String fileName = getTempPath() + File.separator + abstractFile.getName()
219  + "-" + String.valueOf(abstractFile.getId());
220  File file = new File(fileName);
221 
222  long freeSpace = services.getFreeDiskSpace();
223  if ((freeSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN) && (abstractFile.getSize() >= freeSpace)) {
224  logger.log(Level.WARNING, "Not enough disk space to write file to disk."); //NON-NLS
225  postErrorMessage(
226  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg",
227  abstractFile.getName()),
228  NbBundle.getMessage(this.getClass(),
229  "ThunderbirdMboxFileIngestModule.processMBox.errProfFile.details"));
230  return ProcessResult.OK;
231  }
232 
233  try {
234  ContentUtils.writeToFile(abstractFile, file);
235  } catch (IOException ex) {
236  logger.log(Level.WARNING, "Failed writing mbox file to disk.", ex); //NON-NLS
237  return ProcessResult.OK;
238  }
239 
240  MboxParser parser = new MboxParser(services, emailFolder);
241  List<EmailMessage> emails = parser.parse(file, abstractFile.getId());
242  processEmails(emails, abstractFile);
243 
244  if (file.delete() == false) {
245  logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
246  }
247 
248  String errors = parser.getErrors();
249  if (errors.isEmpty() == false) {
250  postErrorMessage(
251  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg2",
252  abstractFile.getName()), errors);
253  }
254 
255  return ProcessResult.OK;
256  }
257 
263  public static String getTempPath() {
264  String tmpDir = Case.getCurrentCase().getTempDirectory() + File.separator
265  + "EmailParser"; //NON-NLS
266  File dir = new File(tmpDir);
267  if (dir.exists() == false) {
268  dir.mkdirs();
269  }
270  return tmpDir;
271  }
272 
273  public static String getModuleOutputPath() {
274  String outDir = Case.getCurrentCase().getModuleDirectory() + File.separator
275  + EmailParserModuleFactory.getModuleName();
276  File dir = new File(outDir);
277  if (dir.exists() == false) {
278  dir.mkdirs();
279  }
280  return outDir;
281  }
282 
283  public static String getRelModuleOutputPath() {
284  return Case.getCurrentCase().getModuleOutputDirectoryRelativePath() + File.separator
285  + EmailParserModuleFactory.getModuleName();
286  }
287 
296  private void processEmails(List<EmailMessage> emails, AbstractFile abstractFile) {
297  List<AbstractFile> derivedFiles = new ArrayList<>();
298  for (EmailMessage email : emails) {
299  if (email.hasAttachment()) {
300  derivedFiles.addAll(handleAttachments(email.getAttachments(), abstractFile));
301  }
302  addArtifact(email, abstractFile);
303  }
304 
305  if (derivedFiles.isEmpty() == false) {
306  for (AbstractFile derived : derivedFiles) {
307  services.fireModuleContentEvent(new ModuleContentEvent(derived));
308  }
309  }
310  context.addFilesToJob(derivedFiles);
311  services.fireModuleDataEvent(new ModuleDataEvent(EmailParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG));
312  }
313 
323  private List<AbstractFile> handleAttachments(List<EmailMessage.Attachment> attachments, AbstractFile abstractFile) {
324  List<AbstractFile> files = new ArrayList<>();
325  for (EmailMessage.Attachment attach : attachments) {
326  String filename = attach.getName();
327  long crTime = attach.getCrTime();
328  long mTime = attach.getmTime();
329  long aTime = attach.getaTime();
330  long cTime = attach.getcTime();
331  String relPath = attach.getLocalPath();
332  long size = attach.getSize();
333 
334  try {
335  DerivedFile df = fileManager.addDerivedFile(filename, relPath,
336  size, cTime, crTime, aTime, mTime, true, abstractFile, "",
337  EmailParserModuleFactory.getModuleName(), EmailParserModuleFactory.getModuleVersion(), "");
338  files.add(df);
339  } catch (TskCoreException ex) {
340  postErrorMessage(
341  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.handleAttch.errMsg",
342  abstractFile.getName()),
343  NbBundle.getMessage(this.getClass(),
344  "ThunderbirdMboxFileIngestModule.handleAttch.errMsg.details", filename));
345  logger.log(Level.INFO, "", ex);
346  }
347  }
348  return files;
349  }
350 
357  private void addArtifact(EmailMessage email, AbstractFile abstractFile) {
358  List<BlackboardAttribute> bbattributes = new ArrayList<>();
359  String to = email.getRecipients();
360  String cc = email.getCc();
361  String bcc = email.getBcc();
362  String from = email.getSender();
363  long dateL = email.getSentDate();
364  String body = email.getTextBody();
365  String bodyHTML = email.getHtmlBody();
366  String rtf = email.getRtfBody();
367  String subject = email.getSubject();
368  long id = email.getId();
369  String localPath = email.getLocalPath();
370 
371  if (to.isEmpty() == false) {
372  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_TO, EmailParserModuleFactory.getModuleName(), to));
373  }
374  if (cc.isEmpty() == false) {
375  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CC, EmailParserModuleFactory.getModuleName(), cc));
376  }
377  if (bcc.isEmpty() == false) {
378  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_BCC, EmailParserModuleFactory.getModuleName(), bcc));
379  }
380  if (from.isEmpty() == false) {
381  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_FROM, EmailParserModuleFactory.getModuleName(), from));
382  }
383  if (dateL > 0) {
384  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_RCVD, EmailParserModuleFactory.getModuleName(), dateL));
385  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_SENT, EmailParserModuleFactory.getModuleName(), dateL));
386  }
387  if (body.isEmpty() == false) {
388  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN, EmailParserModuleFactory.getModuleName(), body));
389  }
390  if (bodyHTML.isEmpty() == false) {
391  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, EmailParserModuleFactory.getModuleName(), bodyHTML));
392  }
393  if (rtf.isEmpty() == false) {
394  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, EmailParserModuleFactory.getModuleName(), rtf));
395  }
396  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_MSG_ID, EmailParserModuleFactory.getModuleName(), ((id < 0L) ? NbBundle
397  .getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(id))));
398  if (subject.isEmpty() == false) {
399  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SUBJECT, EmailParserModuleFactory.getModuleName(), subject));
400  }
401  if (localPath.isEmpty() == false) {
402  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, EmailParserModuleFactory.getModuleName(), localPath));
403  } else {
404  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, EmailParserModuleFactory.getModuleName(), "/foo/bar")); //NON-NLS
405  }
406 
407  try {
408  BlackboardArtifact bbart;
409  bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
410  bbart.addAttributes(bbattributes);
411 
412  try {
413  // index the artifact for keyword search
414  blackboard.indexArtifact(bbart);
415  } catch (Blackboard.BlackboardException ex) {
416  logger.log(Level.SEVERE, NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.error.msg", bbart.getDisplayName()), ex); //NON-NLS
418  NbBundle.getMessage(Blackboard.class, "Blackboard.unableToIndexArtifact.exception.msg"), bbart.getDisplayName());
419  }
420  } catch (TskCoreException ex) {
421  logger.log(Level.WARNING, null, ex);
422  }
423  }
424 
425  void postErrorMessage(String subj, String details) {
426  IngestMessage ingestMessage = IngestMessage.createErrorMessage(EmailParserModuleFactory.getModuleVersion(), subj, details);
427  services.postMessage(ingestMessage);
428  }
429 
430  IngestServices getServices() {
431  return services;
432  }
433 
434  @Override
435  public void shutDown() {
436  }
437 }
void indexArtifact(BlackboardArtifact artifact)
Definition: Blackboard.java:45
static IngestMessage createErrorMessage(String source, String subject, String detailsHtml)
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
synchronized DerivedFile addDerivedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, AbstractFile parentFile, String rederiveDetails, String toolName, String toolVersion, String otherDetails)
void processEmails(List< EmailMessage > emails, AbstractFile abstractFile)
void addFilesToJob(List< AbstractFile > files)
void postMessage(final IngestMessage message)
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
void fireModuleContentEvent(ModuleContentEvent moduleContentEvent)
static void error(String title, String message)
synchronized static Logger getLogger(String name)
Definition: Logger.java:166
List< AbstractFile > handleAttachments(List< EmailMessage.Attachment > attachments, AbstractFile abstractFile)
static synchronized IngestServices getInstance()

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