uat: add a reset callback.
[metze/wireshark/wip.git] / epan / dissectors / packet-imf.c
index 2747c086c7f191070a7d6908aa8370828255a527..f4b518ea3849ace56bbd4d7b06a67c87a5971a65 100644 (file)
 #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"
@@ -41,6 +42,8 @@
 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"
@@ -152,8 +155,46 @@ static dissector_handle_t imf_handle;
 
 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 */
@@ -278,21 +319,21 @@ static guint num_header_fields = 0;
 
 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
@@ -301,10 +342,11 @@ header_fields_update_cb(void *r, const char **err)
   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 *
@@ -538,8 +580,9 @@ dissect_imf_siolabel(tvbuff_t *tvb, int offset, int length, proto_item *item, pa
     }
 
     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);
@@ -588,7 +631,7 @@ dissect_imf_siolabel(tvbuff_t *tvb, int offset, int length, proto_item *item, pa
 
 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;
@@ -611,22 +654,14 @@ dissect_imf_content_type(tvbuff_t *tvb, int offset, int length, proto_item *item
     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);
   }
 }
 
@@ -641,17 +676,25 @@ imf_find_field_end(tvbuff_t *tvb, int offset, gint max_length, gboolean *last_fi
     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  ' ':
@@ -665,7 +708,7 @@ imf_find_field_end(tvbuff_t *tvb, int offset, gint max_length, gboolean *last_fi
       }
     } else {
       /* couldn't find a CR - strange */
-      return offset;
+      break;
     }
 
   }
@@ -674,13 +717,14 @@ imf_find_field_end(tvbuff_t *tvb, int offset, gint max_length, gboolean *last_fi
 
 }
 
-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;
@@ -691,6 +735,14 @@ dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   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);
@@ -698,7 +750,7 @@ dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   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 */
 
@@ -778,6 +830,15 @@ dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
         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) {
@@ -786,6 +847,8 @@ dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
         dissect_imf_content_type(tvb, start_offset, end_offset - start_offset, item,
                                  &content_type_str, &parameters);
 
+      } 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 */
@@ -796,6 +859,11 @@ dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
     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;
   }
@@ -806,15 +874,21 @@ dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   /* 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 */
@@ -843,6 +917,16 @@ dissect_imf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
       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
@@ -850,7 +934,7 @@ free_imf_field (gpointer data)
 {
   struct imf_field *imffield = (struct imf_field *) data;
 
-  g_free ((char *) imffield->name);
+  g_free (imffield->name);
   g_free (imffield);
 }
 
@@ -865,9 +949,9 @@ header_fields_initialize_cb (void)
 
   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);
@@ -890,13 +974,13 @@ header_fields_initialize_cb (void)
       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;
@@ -1228,6 +1312,7 @@ proto_register_imf(void)
                                header_fields_update_cb,
                                header_fields_free_cb,
                                header_fields_initialize_cb,
+                               NULL,
                                attributes_flds);
 
   module_t *imf_module;
@@ -1256,6 +1341,9 @@ proto_register_imf(void)
   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 */