Autopsy  4.1
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;
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 {
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 
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);
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 body = email.getTextBody();
367  String bodyHTML = email.getHtmlBody();
368  String rtf = email.getRtfBody();
369  String subject = email.getSubject();
370  long id = email.getId();
371  String localPath = email.getLocalPath();
372 
373  if (to.isEmpty() == false) {
374  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_TO, EmailParserModuleFactory.getModuleName(), to));
375  }
376  if (cc.isEmpty() == false) {
377  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CC, EmailParserModuleFactory.getModuleName(), cc));
378  }
379  if (bcc.isEmpty() == false) {
380  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_BCC, EmailParserModuleFactory.getModuleName(), bcc));
381  }
382  if (from.isEmpty() == false) {
383  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_FROM, EmailParserModuleFactory.getModuleName(), from));
384  }
385  if (dateL > 0) {
386  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_RCVD, EmailParserModuleFactory.getModuleName(), dateL));
387  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_SENT, EmailParserModuleFactory.getModuleName(), dateL));
388  }
389  if (body.isEmpty() == false) {
390  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN, EmailParserModuleFactory.getModuleName(), body));
391  }
392  if (bodyHTML.isEmpty() == false) {
393  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, EmailParserModuleFactory.getModuleName(), bodyHTML));
394  }
395  if (rtf.isEmpty() == false) {
396  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, EmailParserModuleFactory.getModuleName(), rtf));
397  }
398  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_MSG_ID, EmailParserModuleFactory.getModuleName(), ((id < 0L) ? NbBundle
399  .getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(id))));
400  if (subject.isEmpty() == false) {
401  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SUBJECT, EmailParserModuleFactory.getModuleName(), subject));
402  }
403  if (localPath.isEmpty() == false) {
404  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, EmailParserModuleFactory.getModuleName(), localPath));
405  } else {
406  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, EmailParserModuleFactory.getModuleName(), "/foo/bar")); //NON-NLS
407  }
408 
409  try {
410  BlackboardArtifact bbart;
412  bbart.addAttributes(bbattributes);
413 
414  try {
415  // index the artifact for keyword search
416  blackboard.indexArtifact(bbart);
417  } catch (Blackboard.BlackboardException ex) {
418  logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bbart.getArtifactID(), ex); //NON-NLS
419  MessageNotifyUtil.Notify.error(Bundle.ThunderbirdMboxFileIngestModule_addArtifact_indexError_message(), bbart.getDisplayName());
420  }
421  } catch (TskCoreException ex) {
422  logger.log(Level.WARNING, null, ex);
423  }
424  }
425 
426  void postErrorMessage(String subj, String details) {
427  IngestMessage ingestMessage = IngestMessage.createErrorMessage(EmailParserModuleFactory.getModuleVersion(), subj, details);
428  services.postMessage(ingestMessage);
429  }
430 
431  IngestServices getServices() {
432  return services;
433  }
434 
435  @Override
436  public void shutDown() {
437  }
438 }
static IngestMessage createErrorMessage(String source, String subject, String detailsHtml)
void addAttributes(Collection< BlackboardAttribute > attributes)
TskData.TSK_DB_FILES_TYPE_ENUM getType()
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 addAttribute(BlackboardAttribute attr)
void addFilesToJob(List< AbstractFile > files)
void postMessage(final IngestMessage message)
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
BlackboardArtifact newArtifact(int artifactTypeID)
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)
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)
final int read(byte[] buf, long offset, long len)
static synchronized IngestServices getInstance()

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