aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-multipart.c
diff options
context:
space:
mode:
authorGraeme Lunt <graeme.lunt@smhs.co.uk>2007-07-14 09:19:35 +0000
committerGraeme Lunt <graeme.lunt@smhs.co.uk>2007-07-14 09:19:35 +0000
commit7b1032f9b082e73149ebc542e6c1a1768658c218 (patch)
treeb8cdf12006248675e8ace6f9268920dd58051552 /epan/dissectors/packet-multipart.c
parentb1a3d8a5a00eece582f032713a160b1819c1c8e4 (diff)
downloadwireshark-7b1032f9b082e73149ebc542e6c1a1768658c218.tar.gz
wireshark-7b1032f9b082e73149ebc542e6c1a1768658c218.tar.bz2
wireshark-7b1032f9b082e73149ebc542e6c1a1768658c218.zip
Optional removal of any base64 content-transfer-encoding from a MIME
body before passing it to a sub-dissector. The decoded content is added as a new source, named with the filename or the content-type. svn path=/trunk/; revision=22311
Diffstat (limited to 'epan/dissectors/packet-multipart.c')
-rw-r--r--epan/dissectors/packet-multipart.c193
1 files changed, 148 insertions, 45 deletions
diff --git a/epan/dissectors/packet-multipart.c b/epan/dissectors/packet-multipart.c
index 52d063b54a..17f87efe48 100644
--- a/epan/dissectors/packet-multipart.c
+++ b/epan/dissectors/packet-multipart.c
@@ -66,10 +66,13 @@
#include <epan/prefs.h>
#include <glib.h>
#include <ctype.h>
+#include <epan/base64.h>
#include <epan/emem.h>
#include <epan/packet.h>
+#include "packet-imf.h"
+
/* Dissector table for media requiring special attention in multipart
* encapsulation. */
static dissector_table_t multipart_media_subdissector_table;
@@ -137,6 +140,7 @@ static dissector_handle_t media_handle;
* TODO improve to check for different content types ?
*/
static gboolean display_unknown_body_as_text = FALSE;
+static gboolean remove_base64_encoding = FALSE;
typedef struct {
@@ -167,6 +171,29 @@ index_of_char(const char *str, const char c);
char *
unfold_and_compact_mime_header(const char *lines, gint *first_colon_offset);
+
+/* Return a tvb that contains the binary representation of a base64
+ string */
+
+static tvbuff_t *
+base64_decode(packet_info *pinfo, tvbuff_t *b64_tvb, char *name)
+{
+ tvbuff_t *tvb;
+ char *data;
+ size_t len;
+
+ data = g_strdup(tvb_get_ephemeral_string(b64_tvb, 0, tvb_length_remaining(b64_tvb, 0)));
+
+ len = epan_base64_decode(data);
+ tvb = tvb_new_real_data((const guint8 *)data, len, len);
+
+ tvb_set_free_cb(tvb, g_free);
+
+ add_new_data_source(pinfo, tvb, name);
+
+ return tvb;
+}
+
/*
* Unfold and clean up a MIME-like header, and process LWS as follows:
* o Preserves LWS in quoted text
@@ -294,60 +321,36 @@ index_of_char(const char *str, const char c)
return -1;
}
-/* Retrieve the media information from pinfo->private_data,
- * and compute the boundary string and its length.
- * Return a pointer to a filled-in multipart_info_t, or NULL on failure.
- *
- * Boundary delimiters must not appear within the encapsulated material,
- * and must be no longer than 70 characters, not counting the two
- * leading hyphens. (quote from rfc2046)
- */
-static multipart_info_t *
-get_multipart_info(packet_info *pinfo)
+static char *find_parameter(char *parameters, const char *key, int *retlen)
{
- const char *start, *p;
- int len = 0;
- multipart_info_t *m_info = NULL;
- const char *type = pinfo->match_string;
- char *parameters;
- gint dummy;
+ char *start, *p;
+ int keylen = 0;
+ int len = 0;
- if ((type == NULL) || (pinfo->private_data == NULL)) {
- /*
- * We need both a content type AND parameters
- * for multipart dissection.
- */
+ if(!parameters || !*parameters || !key || !(keylen = strlen(key)))
+ /* we won't be able to find anything */
return NULL;
- }
- /* Clean up the parameters */
- parameters = unfold_and_compact_mime_header(pinfo->private_data, &dummy);
-
- /*
- * Process the private data
- * The parameters must contain the boundary string
- */
p = parameters;
+
while (*p) {
while ((*p) && isspace((guchar)*p))
p++; /* Skip white space */
- if (strncasecmp(p, "boundary=", 9) == 0)
+ if (strncasecmp(p, key, keylen) == 0)
break;
/* Skip to next parameter */
p = strchr(p, ';');
if (p == NULL)
{
- g_free(parameters);
return NULL;
}
p++; /* Skip semicolon */
}
- start = p + 9;
+ start = p + keylen;
if (start[0] == 0) {
- g_free(parameters);
return NULL;
}
@@ -356,7 +359,7 @@ get_multipart_info(packet_info *pinfo)
*/
if (start[0] == '"') {
/*
- * Boundary string is a quoted-string
+ * Parameter value is a quoted-string
*/
start++; /* Skip the quote */
len = index_of_char(start, '"');
@@ -364,7 +367,6 @@ get_multipart_info(packet_info *pinfo)
/*
* No closing quote
*/
- g_free(parameters);
return NULL;
}
} else {
@@ -379,6 +381,49 @@ get_multipart_info(packet_info *pinfo)
len++;
}
}
+
+ if(retlen)
+ (*retlen) = len;
+
+ return start;
+}
+
+/* Retrieve the media information from pinfo->private_data,
+ * and compute the boundary string and its length.
+ * Return a pointer to a filled-in multipart_info_t, or NULL on failure.
+ *
+ * Boundary delimiters must not appear within the encapsulated material,
+ * and must be no longer than 70 characters, not counting the two
+ * leading hyphens. (quote from rfc2046)
+ */
+static multipart_info_t *
+get_multipart_info(packet_info *pinfo)
+{
+ const char *start;
+ int len = 0;
+ multipart_info_t *m_info = NULL;
+ const char *type = pinfo->match_string;
+ char *parameters;
+ gint dummy;
+
+ if ((type == NULL) || (pinfo->private_data == NULL)) {
+ /*
+ * We need both a content type AND parameters
+ * for multipart dissection.
+ */
+ return NULL;
+ }
+
+ /* Clean up the parameters */
+ parameters = unfold_and_compact_mime_header(pinfo->private_data, &dummy);
+
+ start = find_parameter(parameters, "boundary=", &len);
+
+ if(!start) {
+ g_free(parameters);
+ return NULL;
+ }
+
/*
* There is a value for the boundary string
*/
@@ -553,11 +598,15 @@ process_body_part(proto_tree *tree, tvbuff_t *tvb, const guint8 *boundary,
proto_tree *subtree = NULL;
proto_item *ti = NULL;
gint offset = start, next_offset;
- gint line_len = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
char *parameters = NULL;
gint body_start, boundary_start, boundary_line_len;
char *content_type_str = NULL;
+ char *content_encoding_str = NULL;
+ char *filename = NULL;
+ char *typename = NULL;
+ int len = 0;
+ gboolean last_field = FALSE;
if (tree) {
ti = proto_tree_add_item(tree, hf_multipart_part, tvb, start, 0, FALSE);
@@ -567,12 +616,16 @@ process_body_part(proto_tree *tree, tvbuff_t *tvb, const guint8 *boundary,
* Process the MIME-part-headers
*/
- while (line_len > 0)
+ while (!last_field)
{
gint colon_offset;
- char *hdr_str = tvb_get_ephemeral_string(tvb, offset, next_offset - offset);
+ char *hdr_str;
char *header_str;
+ next_offset = imf_find_field_end(tvb, offset, tvb_length_remaining(tvb, offset), &last_field);
+
+ hdr_str = tvb_get_ephemeral_string(tvb, offset, next_offset - offset);
+
header_str = unfold_and_compact_mime_header(hdr_str, &colon_offset);
if (colon_offset <= 0) {
if (tree) {
@@ -626,9 +679,39 @@ process_body_part(proto_tree *tree, tvbuff_t *tvb, const guint8 *boundary,
#endif
/* Show content-type in root 'part' label */
proto_item_append_text(ti, " (%s)", content_type_str);
+
+ /* find the "name" parameter in case we don't find a content disposition "filename" */
+ if(typename = find_parameter(parameters, "name=", &len)) {
+ typename = g_strndup(typename, len);
+ }
}
+
+
break;
+ case POS_CONTENT_TRANSFER_ENCODING:
+ {
+ /* The Content-Transfeing starts at colon_offset + 1 */
+ gint cr_offset = index_of_char(value_str, '\r');
+ if (cr_offset > 0) {
+ value_str[cr_offset] = '\0';
+ }
+#if GLIB_MAJOR_VERSION < 2
+ content_encoding_str = g_strdup(value_str);
+ g_strdown(content_encoding_str);
+#else
+ content_encoding_str = g_ascii_strdown(value_str, -1);
+#endif
+ }
+ break;
+ case POS_CONTENT_DISPOSITION:
+ {
+ /* find the "filename" parameter */
+ if(filename = find_parameter(value_str, "filename=", &len)) {
+ filename = g_strndup(filename, len);
+ }
+ }
+ break;
default:
break;
}
@@ -636,14 +719,7 @@ process_body_part(proto_tree *tree, tvbuff_t *tvb, const guint8 *boundary,
}
g_free(header_str);
offset = next_offset;
- line_len = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
}
- if (line_len < 0) {
- /* ERROR */
- return -1;
- }
- proto_tree_add_text(subtree, tvb, offset, next_offset - offset,
- "%s", tvb_format_text(tvb, offset, next_offset - offset));
body_start = next_offset;
@@ -659,12 +735,26 @@ process_body_part(proto_tree *tree, tvbuff_t *tvb, const guint8 *boundary,
body_len, body_len);
if (content_type_str) {
+
/*
* subdissection
*/
void *save_private_data = pinfo->private_data;
gboolean dissected;
+ /*
+ * Try and remove any content transfer encoding so that each sub-dissector
+ * doesn't have to do it itself
+ *
+ */
+
+ if(content_encoding_str && remove_base64_encoding) {
+
+ if(!strncasecmp(content_encoding_str, "base64", 6))
+ tmp_tvb = base64_decode(pinfo, tmp_tvb, filename ? filename : (typename ? typename : content_type_str));
+
+ }
+
pinfo->private_data = parameters;
/*
* First try the dedicated multipart dissector table
@@ -707,6 +797,12 @@ process_body_part(proto_tree *tree, tvbuff_t *tvb, const guint8 *boundary,
boundary_line_len));
}
}
+
+ if(filename)
+ g_free(filename);
+ if(typename)
+ g_free(typename);
+
return boundary_start + boundary_line_len;
}
@@ -944,6 +1040,13 @@ proto_register_multipart(void)
" as raw text (may cause problems with binary data).",
&display_unknown_body_as_text);
+ prefs_register_bool_preference(multipart_module,
+ "remove_base64_encoding",
+ "Remove base64 encoding from bodies",
+ "Remove any base64 content-transfer encoding from bodies. "
+ "This supports export of the body and its further dissection.",
+ &remove_base64_encoding);
+
/*
* Dissectors requiring different behavior in cases where the media
* is contained in a multipart entity should register their multipart