Autopsy  4.4
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;
27 import org.openide.util.NbBundle.Messages;
42 import org.sleuthkit.datamodel.AbstractFile;
43 import org.sleuthkit.datamodel.BlackboardArtifact;
44 import org.sleuthkit.datamodel.BlackboardAttribute;
45 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
46 import org.sleuthkit.datamodel.DerivedFile;
47 import org.sleuthkit.datamodel.TskCoreException;
48 import org.sleuthkit.datamodel.TskData;
49 import org.sleuthkit.datamodel.TskException;
50 
56 public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
57 
58  private static final Logger logger = Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName());
63 
65  }
66 
67  @Override
68  public void startUp(IngestJobContext context) throws IngestModuleException {
69  this.context = context;
70  fileManager = Case.getCurrentCase().getServices().getFileManager();
71  }
72 
73  @Override
74  public ProcessResult process(AbstractFile abstractFile) {
75 
76  blackboard = Case.getCurrentCase().getServices().getBlackboard();
77 
78  // skip known
79  if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) {
80  return ProcessResult.OK;
81  }
82 
83  //skip unalloc
84  if ((abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) ||
85  (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) {
86  return ProcessResult.OK;
87  }
88 
89  if ((abstractFile.isFile() == false)) {
90  return ProcessResult.OK;
91  }
92 
93  // check its signature
94  boolean isMbox = false;
95  try {
96  byte[] t = new byte[64];
97  if (abstractFile.getSize() > 64) {
98  int byteRead = abstractFile.read(t, 0, 64);
99  if (byteRead > 0) {
100  isMbox = MboxParser.isValidMimeTypeMbox(t);
101  }
102  }
103  } catch (TskException ex) {
104  logger.log(Level.WARNING, null, ex);
105  }
106 
107  if (isMbox) {
108  return processMBox(abstractFile);
109  }
110 
111  if (PstParser.isPstFile(abstractFile)) {
112  return processPst(abstractFile);
113  }
114 
115  return ProcessResult.OK;
116  }
117 
125  @Messages({"ThunderbirdMboxFileIngestModule.processPst.indexError.message=Failed to index encryption detected artifact for keyword search."})
126  private ProcessResult processPst(AbstractFile abstractFile) {
127  String fileName = getTempPath() + File.separator + abstractFile.getName()
128  + "-" + String.valueOf(abstractFile.getId());
129  File file = new File(fileName);
130 
131  long freeSpace = services.getFreeDiskSpace();
132  if ((freeSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN) && (abstractFile.getSize() >= freeSpace)) {
133  logger.log(Level.WARNING, "Not enough disk space to write file to disk."); //NON-NLS
135  NbBundle.getMessage(this.getClass(),
136  "ThunderbirdMboxFileIngestModule.processPst.errMsg.outOfDiskSpace",
137  abstractFile.getName()));
138  services.postMessage(msg);
139  return ProcessResult.OK;
140  }
141 
142  try {
143  ContentUtils.writeToFile(abstractFile, file, context::fileIngestIsCancelled);
144  } catch (IOException ex) {
145  logger.log(Level.WARNING, "Failed writing pst file to disk.", ex); //NON-NLS
146  return ProcessResult.OK;
147  }
148 
149  PstParser parser = new PstParser(services);
150  PstParser.ParseResult result = parser.parse(file, abstractFile.getId());
151 
152  if (result == PstParser.ParseResult.OK) {
153  // parse success: Process email and add artifacts
154  processEmails(parser.getResults(), abstractFile);
155  } else if (result == PstParser.ParseResult.ENCRYPT) {
156  // encrypted pst: Add encrypted file artifact
157  try {
158  BlackboardArtifact artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
159  artifact.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, EmailParserModuleFactory.getModuleName(), NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.encryptionFileLevel")));
160 
161  try {
162  // index the artifact for keyword search
163  blackboard.indexArtifact(artifact);
164  } catch (Blackboard.BlackboardException ex) {
165  MessageNotifyUtil.Notify.error(Bundle.ThunderbirdMboxFileIngestModule_processPst_indexError_message(), artifact.getDisplayName());
166  logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex); //NON-NLS
167  }
168 
169  services.fireModuleDataEvent(new ModuleDataEvent(EmailParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED));
170  } catch (TskCoreException ex) {
171  logger.log(Level.INFO, "Failed to add encryption attribute to file: {0}", abstractFile.getName()); //NON-NLS
172  }
173  } else {
174  // parsing error: log message
175  postErrorMessage(
176  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg",
177  abstractFile.getName()),
178  NbBundle.getMessage(this.getClass(),
179  "ThunderbirdMboxFileIngestModule.processPst.errProcFile.details"));
180  logger.log(Level.INFO, "PSTParser failed to parse {0}", abstractFile.getName()); //NON-NLS
181  return ProcessResult.ERROR;
182  }
183 
184  if (file.delete() == false) {
185  logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
186  }
187 
188  String errors = parser.getErrors();
189  if (errors.isEmpty() == false) {
190  postErrorMessage(
191  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg2",
192  abstractFile.getName()), errors);
193  }
194 
195  return ProcessResult.OK;
196  }
197 
205  private ProcessResult processMBox(AbstractFile abstractFile) {
206  String mboxFileName = abstractFile.getName();
207  String mboxParentDir = abstractFile.getParentPath();
208  // use the local path to determine the e-mail folder structure
209  String emailFolder = "";
210  // email folder is everything after "Mail" or ImapMail
211  if (mboxParentDir.contains("/Mail/")) { //NON-NLS
212  emailFolder = mboxParentDir.substring(mboxParentDir.indexOf("/Mail/") + 5); //NON-NLS
213  } else if (mboxParentDir.contains("/ImapMail/")) { //NON-NLS
214  emailFolder = mboxParentDir.substring(mboxParentDir.indexOf("/ImapMail/") + 9); //NON-NLS
215  }
216  emailFolder = emailFolder + mboxFileName;
217  emailFolder = emailFolder.replaceAll(".sbd", ""); //NON-NLS
218 
219  String fileName = getTempPath() + File.separator + abstractFile.getName()
220  + "-" + String.valueOf(abstractFile.getId());
221  File file = new File(fileName);
222 
223  long freeSpace = services.getFreeDiskSpace();
224  if ((freeSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN) && (abstractFile.getSize() >= freeSpace)) {
225  logger.log(Level.WARNING, "Not enough disk space to write file to disk."); //NON-NLS
226  postErrorMessage(
227  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg",
228  abstractFile.getName()),
229  NbBundle.getMessage(this.getClass(),
230  "ThunderbirdMboxFileIngestModule.processMBox.errProfFile.details"));
231  return ProcessResult.OK;
232  }
233 
234  try {
235  ContentUtils.writeToFile(abstractFile, file, context::fileIngestIsCancelled);
236  } catch (IOException ex) {
237  logger.log(Level.WARNING, "Failed writing mbox file to disk.", ex); //NON-NLS
238  return ProcessResult.OK;
239  }
240 
241  MboxParser parser = new MboxParser(services, emailFolder);
242  List<EmailMessage> emails = parser.parse(file, abstractFile.getId());
243  processEmails(emails, abstractFile);
244 
245  if (file.delete() == false) {
246  logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
247  }
248 
249  String errors = parser.getErrors();
250  if (errors.isEmpty() == false) {
251  postErrorMessage(
252  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg2",
253  abstractFile.getName()), errors);
254  }
255 
256  return ProcessResult.OK;
257  }
258 
264  public static String getTempPath() {
265  String tmpDir = Case.getCurrentCase().getTempDirectory() + File.separator
266  + "EmailParser"; //NON-NLS
267  File dir = new File(tmpDir);
268  if (dir.exists() == false) {
269  dir.mkdirs();
270  }
271  return tmpDir;
272  }
273 
274  public static String getModuleOutputPath() {
275  String outDir = Case.getCurrentCase().getModuleDirectory() + File.separator
276  + EmailParserModuleFactory.getModuleName();
277  File dir = new File(outDir);
278  if (dir.exists() == false) {
279  dir.mkdirs();
280  }
281  return outDir;
282  }
283 
284  public static String getRelModuleOutputPath() {
285  return Case.getCurrentCase().getModuleOutputDirectoryRelativePath() + File.separator
286  + EmailParserModuleFactory.getModuleName();
287  }
288 
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  TskData.EncodingType encodingType = attach.getEncodingType();
334 
335  try {
336  DerivedFile df = fileManager.addDerivedFile(filename, relPath,
337  size, cTime, crTime, aTime, mTime, true, abstractFile, "",
338  EmailParserModuleFactory.getModuleName(), EmailParserModuleFactory.getModuleVersion(), "", encodingType);
339  files.add(df);
340  } catch (TskCoreException ex) {
341  postErrorMessage(
342  NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.handleAttch.errMsg",
343  abstractFile.getName()),
344  NbBundle.getMessage(this.getClass(),
345  "ThunderbirdMboxFileIngestModule.handleAttch.errMsg.details", filename));
346  logger.log(Level.INFO, "", ex);
347  }
348  }
349  return files;
350  }
351 
358  @Messages({"ThunderbirdMboxFileIngestModule.addArtifact.indexError.message=Failed to index email message detected artifact for keyword search."})
359  private void addArtifact(EmailMessage email, AbstractFile abstractFile) {
360  List<BlackboardAttribute> bbattributes = new ArrayList<>();
361  String to = email.getRecipients();
362  String cc = email.getCc();
363  String bcc = email.getBcc();
364  String from = email.getSender();
365  long dateL = email.getSentDate();
366  String headers = email.getHeaders();
367  String body = email.getTextBody();
368  String bodyHTML = email.getHtmlBody();
369  String rtf = email.getRtfBody();
370  String subject = email.getSubject();
371  long id = email.getId();
372  String localPath = email.getLocalPath();
373 
374  if (headers.isEmpty() == false) {
375  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HEADERS, EmailParserModuleFactory.getModuleName(), headers));
376  }
377  if (from.isEmpty() == false) {
378  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_FROM, EmailParserModuleFactory.getModuleName(), from));
379  }
380  if (to.isEmpty() == false) {
381  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_TO, EmailParserModuleFactory.getModuleName(), to));
382  }
383  if (subject.isEmpty() == false) {
384  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SUBJECT, EmailParserModuleFactory.getModuleName(), subject));
385  }
386 
387  if (dateL > 0) {
388  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_RCVD, EmailParserModuleFactory.getModuleName(), dateL));
389  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_SENT, EmailParserModuleFactory.getModuleName(), dateL));
390  }
391  if (body.isEmpty() == false) {
392  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN, EmailParserModuleFactory.getModuleName(), body));
393  }
394 
395  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_MSG_ID, EmailParserModuleFactory.getModuleName(), ((id < 0L) ? NbBundle
396  .getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(id))));
397 
398  if (localPath.isEmpty() == false) {
399  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, EmailParserModuleFactory.getModuleName(), localPath));
400  } else {
401  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, EmailParserModuleFactory.getModuleName(), "/foo/bar")); //NON-NLS
402  }
403 
404  if (cc.isEmpty() == false) {
405  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CC, EmailParserModuleFactory.getModuleName(), cc));
406  }
407  if (bcc.isEmpty() == false) {
408  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_BCC, EmailParserModuleFactory.getModuleName(), bcc));
409  }
410 
411  if (bodyHTML.isEmpty() == false) {
412  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, EmailParserModuleFactory.getModuleName(), bodyHTML));
413  }
414  if (rtf.isEmpty() == false) {
415  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, EmailParserModuleFactory.getModuleName(), rtf));
416  }
417 
418 
419 
420 
421  try {
422  BlackboardArtifact bbart;
423  bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
424  bbart.addAttributes(bbattributes);
425 
426  try {
427  // index the artifact for keyword search
428  blackboard.indexArtifact(bbart);
429  } catch (Blackboard.BlackboardException ex) {
430  logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bbart.getArtifactID(), ex); //NON-NLS
431  MessageNotifyUtil.Notify.error(Bundle.ThunderbirdMboxFileIngestModule_addArtifact_indexError_message(), bbart.getDisplayName());
432  }
433  } catch (TskCoreException ex) {
434  logger.log(Level.WARNING, null, ex);
435  }
436  }
437 
438  void postErrorMessage(String subj, String details) {
439  IngestMessage ingestMessage = IngestMessage.createErrorMessage(EmailParserModuleFactory.getModuleVersion(), subj, details);
440  services.postMessage(ingestMessage);
441  }
442 
443  IngestServices getServices() {
444  return services;
445  }
446 
447  @Override
448  public void shutDown() {
449  }
450 }
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)
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)
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, TskData.EncodingType encodingType)
static void error(String title, String message)
synchronized void indexArtifact(BlackboardArtifact artifact)
Definition: Blackboard.java:59
synchronized static Logger getLogger(String name)
Definition: Logger.java:161
List< AbstractFile > handleAttachments(List< EmailMessage.Attachment > attachments, AbstractFile abstractFile)
static synchronized IngestServices getInstance()

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