#include "config.h"
#include <epan/packet.h>
-#include <epan/addr_resolv.h>
#include <epan/prefs.h>
#include <epan/uat.h>
#include <epan/expert.h>
-#include <epan/wmem/wmem.h>
-
#include <wsutil/str_util.h>
+#include <epan/tap.h>
+#include <epan/export_object.h>
+
#include "packet-ber.h"
+#include "packet-http.h"
#include "packet-imf.h"
#include "packet-ess.h"
#include "packet-p1.h"
void proto_register_imf(void);
void proto_reg_handoff_imf(void);
+static int imf_eo_tap = -1;
+
#define PNAME "Internet Message Format"
#define PSNAME "IMF"
#define PFNAME "imf"
static expert_field ei_imf_unknown_param = EI_INIT;
+
+static gboolean
+imf_eo_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data)
+{
+ export_object_list_t *object_list = (export_object_list_t *)tapdata;
+ const imf_eo_t *eo_info = (const imf_eo_t *)data;
+ export_object_entry_t *entry;
+
+ if(eo_info) { /* We have data waiting for us */
+ /* These values will be freed when the Export Object window
+ * is closed. */
+ entry = g_new(export_object_entry_t, 1);
+
+ gchar *start = g_strrstr_len(eo_info->sender_data, -1, "<");
+ gchar *stop = g_strrstr_len(eo_info->sender_data, -1, ">");
+ /* Only include the string inside of the "<>" brackets. If there is nothing between
+ the two brackets use the sender_data string */
+ if(start && stop && stop > start && (stop - start) > 2){
+ entry->hostname = g_strdup_printf("%.*s", (int) (stop - start - 1), start + 1);
+ } else {
+ entry->hostname = g_strdup(eo_info->sender_data);
+ }
+
+ entry->pkt_num = pinfo->num;
+ entry->content_type = g_strdup("EML file");
+ entry->filename = g_strdup_printf("%s.eml", eo_info->subject_data);
+ entry->payload_len = eo_info->payload_len;
+ entry->payload_data = (guint8 *)g_memdup(eo_info->payload_data, eo_info->payload_len);
+
+ object_list->add_entry(object_list->gui_data, entry);
+
+ return TRUE; /* State changed - window should be redrawn */
+ } else {
+ return FALSE; /* State unchanged - no window updates needed */
+ }
+}
+
+
struct imf_field {
- const char *name; /* field name - in lower case for matching purposes */
+ char *name; /* field name - in lower case for matching purposes */
int *hf_id; /* wireshark field */
void (*subdissector)(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo);
gboolean add_to_col_info; /* add field to column info */
static GHashTable *custom_field_table = NULL;
-static void
-header_fields_update_cb(void *r, const char **err)
+static gboolean
+header_fields_update_cb(void *r, char **err)
{
header_field_t *rec = (header_field_t *)r;
char c;
if (rec->header_name == NULL) {
*err = g_strdup("Header name can't be empty");
- return;
+ return FALSE;
}
g_strstrip(rec->header_name);
if (rec->header_name[0] == 0) {
*err = g_strdup("Header name can't be empty");
- return;
+ return FALSE;
}
/* Check for invalid characters (to avoid asserting out when
c = proto_check_field_name(rec->header_name);
if (c) {
*err = g_strdup_printf("Header name can't contain '%c'", c);
- return;
+ return FALSE;
}
*err = NULL;
+ return TRUE;
}
static void *
}
if (tvb_strneql(tvb, item_offset, "marking", 7) == 0) {
- proto_item_append_text(item, ": %s", tvb_get_string_enc(wmem_packet_scope(), tvb, value_offset, value_length, ENC_ASCII));
- proto_tree_add_item(tree, hf_imf_siolabel_marking, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
+ const guint8* marking;
+ proto_tree_add_item_ret_string(tree, hf_imf_siolabel_marking, tvb, value_offset, value_length, ENC_ASCII|ENC_NA, wmem_packet_scope(), &marking);
+ proto_item_append_text(item, ": %s", marking);
} else if (tvb_strneql(tvb, item_offset, "fgcolor", 7) == 0) {
proto_tree_add_item(tree, hf_imf_siolabel_fgcolor, tvb, value_offset, value_length, ENC_ASCII|ENC_NA);
static void
dissect_imf_content_type(tvbuff_t *tvb, int offset, int length, proto_item *item,
- char **type, char **parameters)
+ const guint8 **type, const guint8 **parameters)
{
int first_colon;
int end_offset;
ct_tree = proto_item_add_subtree(item, ett_imf_content_type);
len = first_colon - offset;
- proto_tree_add_item(ct_tree, hf_imf_content_type_type, tvb, offset, len, ENC_ASCII|ENC_NA);
- if(type) {
- /* This string will be automatically freed */
- (*type) = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, len, ENC_ASCII);
- }
+ proto_tree_add_item_ret_string(ct_tree, hf_imf_content_type_type, tvb, offset, len, ENC_ASCII|ENC_NA, wmem_packet_scope(), type);
end_offset = imf_find_field_end (tvb, first_colon + 1, offset + length, NULL);
if (end_offset == -1) {
/* No end found */
return;
}
len = end_offset - (first_colon + 1) - 2; /* Do not include the last CRLF */
- proto_tree_add_item(ct_tree, hf_imf_content_type_parameters, tvb, first_colon + 1, len, ENC_ASCII|ENC_NA);
- if(parameters) {
- /* This string will be automatically freed */
- (*parameters) = tvb_get_string_enc(wmem_packet_scope(), tvb, first_colon + 1, len, ENC_ASCII);
- }
+ proto_tree_add_item_ret_string(ct_tree, hf_imf_content_type_parameters, tvb, first_colon + 1, len, ENC_ASCII|ENC_NA, wmem_packet_scope(), parameters);
}
}
offset = tvb_find_guint8(tvb, offset, max_length - offset, '\r');
if(offset != -1) {
- if(tvb_get_guint8(tvb, ++offset) == '\n') {
+ /* protect against buffer overrun and only then look for next char */
+ if (++offset < max_length && tvb_get_guint8(tvb, offset) == '\n') {
/* OK - so we have found CRLF */
+ if (++offset >= max_length) {
+ /* end of buffer and also end of fields */
+ if (last_field) {
+ *last_field = TRUE;
+ }
+ /* caller expects that there is CRLF after returned offset, if last_field is set */
+ return offset - 2;
+ }
/* peek the next character */
- switch(tvb_get_guint8(tvb, ++offset)) {
+ switch(tvb_get_guint8(tvb, offset)) {
case '\r':
/* probably end of the fields */
- if(tvb_get_guint8(tvb, ++offset) == '\n') {
- offset++;
- }
- if(last_field) {
- *last_field = TRUE;
+ if ((offset + 1) < max_length && tvb_get_guint8(tvb, offset + 1) == '\n') {
+ if(last_field) {
+ *last_field = TRUE;
+ }
}
return offset;
case ' ':
}
} else {
/* couldn't find a CR - strange */
- return offset;
+ break;
}
}
}
-static void
-dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+static int
+dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
proto_item *item;
proto_tree *unknown_tree, *text_tree;
- char *content_type_str = NULL;
- char *parameters = NULL;
+ const guint8 *content_type_str = NULL;
+ char *content_encoding_str = NULL;
+ const guint8 *parameters = NULL;
int hf_id;
gint start_offset = 0;
gint value_offset = 0;
gboolean last_field = FALSE;
tvbuff_t *next_tvb;
struct imf_field *f_info;
+ imf_eo_t *eo_info = NULL;
+
+ if (have_tap_listener(imf_eo_tap)) {
+ eo_info = wmem_new(wmem_packet_scope(), imf_eo_t);
+ /* initialize the eo_info fields in case they are missing later */
+ eo_info->sender_data = "";
+ eo_info->subject_data = "";
+ }
col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
col_clear(pinfo->cinfo, COL_INFO);
item = proto_tree_add_item(tree, proto_imf, tvb, 0, -1, ENC_NA);
tree = proto_item_add_subtree(item, ett_imf);
- max_length = tvb_length(tvb);
+ max_length = tvb_captured_length(tvb);
/* first go through the tvb until we find a blank line and extract the content type if
we find one */
col_append_fstr(pinfo->cinfo, COL_INFO, "%s: %s, ", f_info->name,
tvb_format_text(tvb, value_offset, end_offset - value_offset - 2));
+
+ /* if sender or subject, store for sending to the tap */
+ if (eo_info && have_tap_listener(imf_eo_tap)) {
+ if (*f_info->hf_id == hf_imf_from) {
+ eo_info->sender_data = tvb_get_string_enc(wmem_packet_scope(), tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA);
+ } else if(*f_info->hf_id == hf_imf_subject) {
+ eo_info->subject_data = tvb_get_string_enc(wmem_packet_scope(), tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII|ENC_NA);
+ }
+ }
}
if(hf_id == hf_imf_content_type) {
dissect_imf_content_type(tvb, start_offset, end_offset - start_offset, item,
&content_type_str, ¶meters);
+ } else if (hf_id == hf_imf_content_transfer_encoding) {
+ content_encoding_str = tvb_get_string_enc (wmem_packet_scope(), tvb, value_offset, end_offset - value_offset - 2, ENC_ASCII);
} else if(f_info->subdissector) {
/* we have a subdissector */
start_offset = end_offset;
}
+ if (last_field) {
+ /* Remove the extra CRLF after all the fields */
+ end_offset += 2;
+ }
+
if (end_offset == -1) {
end_offset = 0;
}
/* now dissect the MIME based upon the content type */
if(content_type_str && media_type_dissector_table) {
- void* pd_save;
- pd_save = pinfo->private_data;
- pinfo->private_data = parameters;
+ http_message_info_t message_info;
- next_tvb = tvb_new_subset_remaining(tvb, end_offset);
+ col_set_fence(pinfo->cinfo, COL_INFO);
- dissector_try_string(media_type_dissector_table, content_type_str, next_tvb, pinfo, tree, NULL);
+ if(content_encoding_str && !g_ascii_strncasecmp(content_encoding_str, "base64", 6)) {
+ char *string_data = tvb_get_string_enc(wmem_packet_scope(), tvb, end_offset, tvb_reported_length(tvb) - end_offset, ENC_ASCII);
+ next_tvb = base64_to_tvb(tvb, string_data);
+ add_new_data_source(pinfo, next_tvb, content_encoding_str);
+ } else {
+ next_tvb = tvb_new_subset_remaining(tvb, end_offset);
+ }
- pinfo->private_data = pd_save;
+ message_info.type = HTTP_OTHERS;
+ message_info.media_str = parameters;
+ dissector_try_string(media_type_dissector_table, content_type_str, next_tvb, pinfo, tree, (void*)&message_info);
} else {
/* just show the lines or highlight the rest of the buffer as message text */
start_offset = end_offset;
}
}
+
+ if (eo_info && have_tap_listener(imf_eo_tap)) {
+ /* Set payload info */
+ eo_info->payload_len = max_length;
+ eo_info->payload_data = (gchar *) tvb_memdup(wmem_packet_scope(), tvb, 0, max_length);
+
+ /* Send to tap */
+ tap_queue_packet(imf_eo_tap, pinfo, eo_info);
+ }
+ return tvb_captured_length(tvb);
}
static void
{
struct imf_field *imffield = (struct imf_field *) data;
- g_free ((char *) imffield->name);
+ g_free (imffield->name);
g_free (imffield);
}
if (custom_field_table && hf) {
guint hf_size = g_hash_table_size (custom_field_table);
- /* Unregister all fields */
+ /* Deregister all fields */
for (i = 0; i < hf_size; i++) {
- proto_unregister_field (proto_imf, *(hf[i].p_id));
+ proto_deregister_field (proto_imf, *(hf[i].p_id));
g_free (hf[i].p_id);
}
g_hash_table_destroy (custom_field_table);
hf[i].hfinfo.type = FT_STRING;
hf[i].hfinfo.display = BASE_NONE;
hf[i].hfinfo.strings = NULL;
+ hf[i].hfinfo.bitmask = 0;
hf[i].hfinfo.blurb = g_strdup (header_fields[i].description);
- hf[i].hfinfo.same_name_prev_id = -1;
- hf[i].hfinfo.same_name_next = NULL;
+ HFILL_INIT(hf[i]);
imffield = (struct imf_field *)g_malloc (sizeof (struct imf_field));
imffield->hf_id = hf_id;
- imffield->name = ascii_strdown_inplace (g_strdup (header_name));
+ imffield->name = g_ascii_strdown(header_name, -1);
switch (header_fields[i].header_format) {
case FORMAT_UNSTRUCTURED:
imffield->subdissector = NO_SUBDISSECTION;
header_fields_update_cb,
header_fields_free_cb,
header_fields_initialize_cb,
+ NULL,
attributes_flds);
module_t *imf_module;
for(f = imf_fields; f->name; f++)
g_hash_table_insert(imf_field_table, (gpointer)f->name, (gpointer)f);
+ /* Register for tapping */
+ imf_eo_tap = register_export_object(proto_imf, imf_eo_packet, NULL);
+
}
/* The registration hand-off routine */