--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2012-2013 Sourcefire, Inc.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+/*
+** Author(s): Hui Cao <huica@cisco.com>
+**
+** NOTES
+** 9.25.2012 - Initial Source Code. Hui Cao
+*/
+
+#include "file_mime_paf.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "snort_types.h"
+#include "file_api.h"
+#include "file_mime_config.h"
+
+static const char* boundary_str = "boundary=";
+
+/*
+ * When the file ends (a MIME boundary detected), position are updated
+ */
+void finalize_mime_position(Flow* flow, void* decode_state, FilePosition* position)
+{
+ /* check to see if there are file data in the session or
+ * new decoding data waiting for processing */
+ if ( file_api->get_file_processed_size(flow) ||
+ (decode_state && ((Email_DecodeState*)decode_state)->decoded_bytes) )
+ finalFilePosition(position);
+}
+
+/* Save the bounday string into paf state*/
+static inline bool store_boundary(MimeDataPafInfo* data_info, uint8_t val)
+{
+ if (!data_info->boundary_search)
+ {
+ if ((val == '.') || isspace (val))
+ data_info->boundary_search = (char*)&boundary_str[0];
+ return 0;
+ }
+
+ if (*(data_info->boundary_search) == '=')
+ {
+ /*Skip spaces for the end of boundary*/
+ if (val == '=')
+ data_info->boundary_search++;
+ else if (!isspace(val))
+ data_info->boundary_search = NULL;
+ }
+ else if (*(data_info->boundary_search) == '\0')
+ {
+ /*get boundary string*/
+ if (isspace(val) || (val == '"'))
+ {
+ if (!data_info->boundary_len)
+ return 0;
+ else
+ {
+ /*Found boundary string*/
+ data_info->boundary[data_info->boundary_len] = '\0';
+ return 1;
+ }
+ }
+
+ if (data_info->boundary_len < (int)sizeof(data_info->boundary))
+ {
+ data_info->boundary[data_info->boundary_len++] = val;
+ }
+ else
+ {
+ /*Found boundary string*/
+ data_info->boundary[data_info->boundary_len -1] = '\0';
+ return 1;
+ }
+ }
+ else if ((val == *(data_info->boundary_search))
+ || (val == *(data_info->boundary_search) - 'a' + 'A'))
+ {
+ data_info->boundary_search++;
+ }
+ else
+ {
+ if ((val == '.') || isspace (val))
+ data_info->boundary_search = (char*)&boundary_str[0];
+ else
+ data_info->boundary_search = NULL;
+ }
+
+ return 0;
+}
+
+/* check the bounday string in the mail body*/
+static inline bool check_boundary(MimeDataPafInfo* data_info, uint8_t data)
+{
+ /* Search for boundary signature "--"*/
+ switch (data_info->boundary_state)
+ {
+ case MIME_PAF_BOUNDARY_UNKNOWN:
+ if (data == '\n')
+ data_info->boundary_state = MIME_PAF_BOUNDARY_LF;
+ break;
+
+ case MIME_PAF_BOUNDARY_LF:
+ if (data == '-')
+ data_info->boundary_state = MIME_PAF_BOUNDARY_HYPEN_FIRST;
+ else if (data != '\n')
+ data_info->boundary_state = MIME_PAF_BOUNDARY_UNKNOWN;
+ break;
+
+ case MIME_PAF_BOUNDARY_HYPEN_FIRST:
+ if (data == '-')
+ {
+ data_info->boundary_state = MIME_PAF_BOUNDARY_HYPEN_SECOND;
+ data_info->boundary_search = data_info->boundary;
+ }
+ else if (data == '\n')
+ data_info->boundary_state = MIME_PAF_BOUNDARY_LF;
+ else
+ data_info->boundary_state = MIME_PAF_BOUNDARY_UNKNOWN;
+ break;
+
+ case MIME_PAF_BOUNDARY_HYPEN_SECOND:
+ /* Compare with boundary string stored */
+ if (*(data_info->boundary_search) == '\0')
+ {
+ if (data == '\n')
+ {
+ /*reset boundary search etc.*/
+ data_info->boundary_state = MIME_PAF_BOUNDARY_UNKNOWN;
+ return 1;
+ }
+ else if ((data != '\r') && ((data != '-')))
+ data_info->boundary_state = MIME_PAF_BOUNDARY_UNKNOWN;
+ }
+ else if (*(data_info->boundary_search) == data)
+ data_info->boundary_search++;
+ else
+ data_info->boundary_state = MIME_PAF_BOUNDARY_UNKNOWN;
+
+ break;
+ }
+
+ return 0;
+}
+
+void reset_mime_paf_state(MimeDataPafInfo* data_info)
+{
+ data_info->boundary_search = NULL;
+ data_info->boundary_len = 0;
+ data_info->boundary[0] = '\0';
+ data_info->boundary_state = MIME_PAF_BOUNDARY_UNKNOWN;
+ data_info->data_state = MIME_PAF_FINDING_BOUNDARY_STATE;
+}
+
+/* Process data boundary and flush each file based on boundary*/
+bool process_mime_paf_data(MimeDataPafInfo* data_info, uint8_t data)
+{
+ switch (data_info->data_state)
+ {
+ case MIME_PAF_FINDING_BOUNDARY_STATE:
+ /* Search for boundary
+ Store bounday string in PAF state*/
+ if (store_boundary(data_info, data))
+ {
+ /* End of boundary, move to MIME_PAF_FOUND_BOUNDARY_STATE*/
+ DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Create boudary string: %s\n",
+ data_info->boundary); );
+ data_info->data_state = MIME_PAF_FOUND_BOUNDARY_STATE;
+ }
+
+ break;
+ case MIME_PAF_FOUND_BOUNDARY_STATE:
+ if (check_boundary(data_info, data))
+ {
+ /* End of boundary, move to MIME_PAF_FOUND_BOUNDARY_STATE*/
+ DEBUG_WRAP(DebugMessage(DEBUG_FILE, "Found Boudary string: %s\n",
+ data_info->boundary); );
+ return 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+bool check_data_end(void* data_end_state, uint8_t val)
+{
+ DataEndState state = *((DataEndState*)data_end_state);
+
+ switch (state)
+ {
+ case PAF_DATA_END_UNKNOWN:
+ if (val == '\n')
+ {
+ state = PAF_DATA_END_FIRST_LF;
+ }
+ break;
+
+ case PAF_DATA_END_FIRST_LF:
+ if (val == '.')
+ {
+ state = PAF_DATA_END_DOT;
+ }
+ else if ((val != '\r') && (val != '\n'))
+ {
+ state = PAF_DATA_END_UNKNOWN;
+ }
+ break;
+ case PAF_DATA_END_DOT:
+ if (val == '\n')
+ {
+ *((DataEndState*)data_end_state) = PAF_DATA_END_UNKNOWN;
+ return 1;
+ }
+ else if (val != '\r')
+ {
+ state = PAF_DATA_END_UNKNOWN;
+ }
+ break;
+
+ default:
+ state = PAF_DATA_END_UNKNOWN;
+ break;
+ }
+
+ *((DataEndState*)data_end_state) = state;
+ return 0;
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2012-2013 Sourcefire, Inc.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// file_mime_process.h author Hui Cao <huica@cisco.com>
+
+#ifndef FILE_MIME_PAF_H
+#define FILE_MIME_PAF_H
+
+// Provides list of MIME processing functions. Encoded file data will be decoded
+// and file name will be extracted from MIME header
+
+#include <pcre.h>
+#include "file_api/file_api.h"
+#include "file_api/file_mime_config.h"
+#include "utils/sf_email_attach_decode.h"
+
+
+/* State tracker for data */
+enum MimeDataState
+{
+ MIME_PAF_FINDING_BOUNDARY_STATE,
+ MIME_PAF_FOUND_BOUNDARY_STATE
+};
+
+/* State tracker for Boundary Signature */
+enum MimeBoundaryState
+{
+ MIME_PAF_BOUNDARY_UNKNOWN = 0, /* UNKNOWN */
+ MIME_PAF_BOUNDARY_LF, /* '\n' */
+ MIME_PAF_BOUNDARY_HYPEN_FIRST, /* First '-' */
+ MIME_PAF_BOUNDARY_HYPEN_SECOND /* Second '-' */
+};
+
+/* State tracker for end of pop/smtp command */
+enum DataEndState
+{
+ PAF_DATA_END_UNKNOWN, /* Start or UNKNOWN */
+ PAF_DATA_END_FIRST_CR, /* First '\r' */
+ PAF_DATA_END_FIRST_LF, /* First '\n' */
+ PAF_DATA_END_DOT, /* '.' */
+ PAF_DATA_END_SECOND_CR, /* Second '\r' */
+ PAF_DATA_END_SECOND_LF /* Second '\n' */
+};
+
+#define MAX_MIME_BOUNDARY_LEN 70 /* Max length of boundary string, defined in RFC 2046 */
+
+struct MimeDataPafInfo
+{
+ MimeDataState data_state;
+ char boundary[ MAX_MIME_BOUNDARY_LEN + 1]; /* MIME boundary string + '\0' */
+ int boundary_len;
+ char* boundary_search;
+ MimeBoundaryState boundary_state;
+};
+
+
+static inline bool scanning_boundary(MimeDataPafInfo* mime_info, uint32_t boundary_start,
+ uint32_t* fp)
+{
+ if (boundary_start &&
+ mime_info->data_state == MIME_PAF_FOUND_BOUNDARY_STATE &&
+ mime_info->boundary_state != MIME_PAF_BOUNDARY_UNKNOWN)
+ {
+ *fp = boundary_start;
+ return true;
+ }
+
+ return false;
+}
+
+
+void finalize_mime_position(Flow* flow, void* decode_state, FilePosition* position);
+void reset_mime_paf_state(MimeDataPafInfo *data_info);
+/* Process data boundary and flush each file based on boundary*/
+bool process_mime_paf_data(MimeDataPafInfo *data_info, uint8_t val);
+bool check_data_end(void *end_state, uint8_t val);
+
+#endif
+