2004-01-16 01:32:20 +00:00
/* packet-multipart.c
* Routines for multipart media encapsulation dissection
2004-03-08 22:03:59 +00:00
* Copyright 2004 , Anders Broman .
* Copyright 2004 , Olivier Biot .
2004-01-16 01:32:20 +00:00
*
2004-03-08 22:03:59 +00:00
* Refer to the AUTHORS file or the AUTHORS section in the man page
* for contacting the author ( s ) of this file .
2004-01-16 01:32:20 +00:00
*
2006-05-21 04:49:01 +00:00
* Wireshark - Network traffic analyzer
* By Gerald Combs < gerald @ wireshark . org >
2004-01-16 01:32:20 +00:00
* Copyright 1998 Gerald Combs
*
*
2018-02-12 11:23:27 +00:00
* SPDX - License - Identifier : GPL - 2.0 - or - later
2004-01-16 01:32:20 +00:00
*
* References for " media-type multipart/mixed :
2019-07-27 22:53:22 +00:00
* https : //www.iana.org/assignments/media-types/index.html
* https : //tools.ietf.org/html/rfc2045
* https : //tools.ietf.org/html/rfc2046
* https : //tools.ietf.org/html/rfc2047
* https : //tools.ietf.org/html/rfc2048
* https : //tools.ietf.org/html/rfc2049
2004-01-16 01:32:20 +00:00
*
* Part of the code is modeled from the SIP and HTTP dissectors
*
* General format of a MIME multipart document :
2013-01-26 19:09:15 +00:00
* [ preamble line - end ]
* dash - boundary transport - padding line - end
* body - part
* * encapsulation
* close - delimiter transport - padding
* [ line - end epilogue ]
2004-01-16 01:32:20 +00:00
*
* Where :
2013-01-26 19:09:15 +00:00
* dash - boundary : = " -- " boundary
* encapsulation : = delimiter transport - padding line - end body - part
* delimiter : = line - end body - part
* close - delimiter : = delimiter " -- "
* body - part : = MIME - part - headers [ line - end * OCTET ]
* transport - padding : = * LWSP - char
2011-06-19 19:13:26 +00:00
*
2004-01-16 01:32:20 +00:00
* Note that line - end is often a LF instead of a CRLF .
*/
# include "config.h"
# include <epan/packet.h>
2014-11-06 04:07:35 +00:00
# include <epan/expert.h>
2016-08-22 06:33:23 +00:00
# include <epan/media_params.h>
2012-05-15 19:23:35 +00:00
# include <epan/prefs.h>
2015-11-29 11:13:40 +00:00
# include <wsutil/str_util.h>
2007-07-14 09:19:35 +00:00
# include "packet-imf.h"
2015-11-29 11:13:40 +00:00
# include "packet-dcerpc.h"
# include "packet-gssapi.h"
2016-08-22 06:33:23 +00:00
# include "packet-http.h"
2015-11-29 11:13:40 +00:00
2013-12-14 16:09:57 +00:00
void proto_register_multipart ( void ) ;
void proto_reg_handoff_multipart ( void ) ;
2004-02-06 01:07:51 +00:00
/* Dissector table for media requiring special attention in multipart
* encapsulation . */
static dissector_table_t multipart_media_subdissector_table ;
2004-01-16 01:32:20 +00:00
/* Initialize the protocol and registered fields */
static int proto_multipart = - 1 ;
2014-11-06 04:07:35 +00:00
/* Generated from convert_proto_tree_add_text.pl */
static int hf_multipart_trailer = - 1 ;
static int hf_multipart_boundary = - 1 ;
static int hf_multipart_first_boundary = - 1 ;
static int hf_multipart_last_boundary = - 1 ;
static int hf_multipart_preamble = - 1 ;
2004-01-16 01:32:20 +00:00
/* Initialize the subtree pointers */
static gint ett_multipart = - 1 ;
static gint ett_multipart_main = - 1 ;
static gint ett_multipart_body = - 1 ;
2014-11-06 04:07:35 +00:00
/* Generated from convert_proto_tree_add_text.pl */
2015-11-29 11:13:40 +00:00
static expert_field ei_multipart_no_required_parameter = EI_INIT ;
static expert_field ei_multipart_decryption_not_possible = EI_INIT ;
2014-11-06 04:07:35 +00:00
2004-01-16 01:32:20 +00:00
/* Not sure that compact_name exists for multipart, but choose to keep
* the structure from SIP dissector , all the content - is also from SIP */
2005-01-20 01:26:34 +00:00
typedef struct {
2005-07-30 16:34:38 +00:00
const char * name ;
const char * compact_name ;
2005-01-20 01:26:34 +00:00
} multipart_header_t ;
static const multipart_header_t multipart_headers [ ] = {
2013-01-26 19:09:15 +00:00
{ " Unknown-header " , NULL } , /* Pad so that the real headers start at index 1 */
2016-02-15 14:15:11 +00:00
{ " Content-Description " , NULL } ,
2013-01-26 19:09:15 +00:00
{ " Content-Disposition " , NULL } ,
{ " Content-Encoding " , " e " } ,
{ " Content-Id " , NULL } ,
{ " Content-Language " , NULL } ,
{ " Content-Length " , " l " } ,
{ " Content-Transfer-Encoding " , NULL } ,
{ " Content-Type " , " c " } ,
2015-11-29 11:13:40 +00:00
{ " OriginalContent " , NULL }
2004-01-16 01:32:20 +00:00
} ;
2016-02-15 14:15:11 +00:00
# define POS_CONTENT_DESCRIPTION 1
# define POS_CONTENT_DISPOSITION 2
# define POS_CONTENT_ENCODING 3
# define POS_CONTENT_ID 4
# define POS_CONTENT_LANGUAGE 5
# define POS_CONTENT_LENGTH 6
# define POS_CONTENT_TRANSFER_ENCODING 7
# define POS_CONTENT_TYPE 8
# define POS_ORIGINALCONTENT 9
2004-01-16 01:32:20 +00:00
/* Initialize the header fields */
static gint hf_multipart_type = - 1 ;
2006-11-16 14:35:52 +00:00
static gint hf_multipart_part = - 1 ;
2015-11-29 11:13:40 +00:00
static gint hf_multipart_sec_token_len = - 1 ;
2006-11-16 14:35:52 +00:00
2004-01-16 01:32:20 +00:00
static gint hf_header_array [ ] = {
2013-01-26 19:09:15 +00:00
- 1 , /* "Unknown-header" - Pad so that the real headers start at index 1 */
2016-02-15 14:15:11 +00:00
- 1 , /* "Content-Description" */
2013-01-26 19:09:15 +00:00
- 1 , /* "Content-Disposition" */
- 1 , /* "Content-Encoding" */
- 1 , /* "Content-Id" */
- 1 , /* "Content-Language" */
- 1 , /* "Content-Length" */
- 1 , /* "Content-Transfer-Encoding" */
- 1 , /* "Content-Type" */
2015-11-29 11:13:40 +00:00
- 1 , /* "OriginalContent" */
2004-01-16 01:32:20 +00:00
} ;
/* Define media_type/Content type table */
static dissector_table_t media_type_dissector_table ;
2004-04-30 17:07:21 +00:00
/* Data and media dissector handles */
static dissector_handle_t media_handle ;
2015-11-29 11:13:40 +00:00
static dissector_handle_t gssapi_handle ;
2004-01-16 01:32:20 +00:00
2016-01-06 00:58:42 +00:00
/* Determines if bodies with no media type dissector should be displayed
2004-01-16 01:32:20 +00:00
* as raw text , may cause problems with images sound etc
* TODO improve to check for different content types ?
*/
static gboolean display_unknown_body_as_text = FALSE ;
2007-07-14 09:19:35 +00:00
static gboolean remove_base64_encoding = FALSE ;
2004-01-16 01:32:20 +00:00
typedef struct {
2013-01-26 19:09:15 +00:00
const char * type ; /* Type of multipart */
char * boundary ; /* Boundary string (enclosing quotes removed if any) */
guint boundary_length ; /* Length of the boundary string */
2015-11-29 11:13:40 +00:00
char * protocol ; /* Protocol string if encrypted multipart (enclosing quotes removed if any) */
guint protocol_length ; /* Length of the protocol string */
char * orig_content_type ; /* Content-Type of original message */
char * orig_parameters ; /* Parameters for Content-Type of original message */
2004-01-16 01:32:20 +00:00
} multipart_info_t ;
static gint
find_first_boundary ( tvbuff_t * tvb , gint start , const guint8 * boundary ,
2013-01-26 19:09:15 +00:00
gint boundary_len , gint * boundary_line_len , gboolean * last_boundary ) ;
2004-01-16 01:32:20 +00:00
static gint
find_next_boundary ( tvbuff_t * tvb , gint start , const guint8 * boundary ,
2013-01-26 19:09:15 +00:00
gint boundary_len , gint * boundary_line_len , gboolean * last_boundary ) ;
2004-01-16 01:32:20 +00:00
static gint
2015-11-29 11:13:40 +00:00
process_preamble ( proto_tree * tree , tvbuff_t * tvb , multipart_info_t * m_info ,
gboolean * last_boundary ) ;
2004-01-16 01:32:20 +00:00
static gint
2016-08-22 06:33:23 +00:00
process_body_part ( proto_tree * tree , tvbuff_t * tvb ,
http_message_info_t * input_message_info , multipart_info_t * m_info ,
2015-11-29 11:13:40 +00:00
packet_info * pinfo , gint start , gint idx ,
2013-01-26 19:09:15 +00:00
gboolean * last_boundary ) ;
2004-01-16 01:32:20 +00:00
static gint
is_known_multipart_header ( const char * header_str , guint len ) ;
2007-07-14 09:19:35 +00:00
/* 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 )
{
2013-01-26 19:09:15 +00:00
char * data ;
tvbuff_t * tvb ;
2014-11-21 14:54:59 +00:00
data = tvb_get_string_enc ( wmem_packet_scope ( ) , b64_tvb , 0 , tvb_reported_length ( b64_tvb ) , ENC_ASCII ) ;
2007-07-14 09:19:35 +00:00
2013-01-26 19:09:15 +00:00
tvb = base64_to_tvb ( b64_tvb , data ) ;
add_new_data_source ( pinfo , tvb , name ) ;
2007-07-14 09:19:35 +00:00
2013-01-26 19:09:15 +00:00
return tvb ;
2007-07-14 09:19:35 +00:00
}
2004-01-16 01:32:20 +00:00
/*
* Unfold and clean up a MIME - like header , and process LWS as follows :
2013-01-26 19:09:15 +00:00
* o Preserves LWS in quoted text
* o Remove LWS before and after a separator
* o Remove trailing LWS
* o Replace other LWS with a single space
2011-06-19 19:13:26 +00:00
* Set value to the start of the value
2004-01-16 01:32:20 +00:00
* Return the cleaned - up RFC2822 header ( buffer must be freed ) .
*/
2009-03-29 22:16:26 +00:00
static char *
2004-01-16 01:32:20 +00:00
unfold_and_compact_mime_header ( const char * lines , gint * first_colon_offset )
{
2013-01-26 19:09:15 +00:00
const char * p = lines ;
char c ;
char * ret , * q ;
char sep_seen = 0 ; /* Did we see a separator ":;," */
char lws = FALSE ; /* Did we see LWS (incl. folding) */
gint colon = - 1 ;
if ( ! lines ) return NULL ;
c = * p ;
2013-09-15 15:11:11 +00:00
ret = ( char * ) wmem_alloc ( wmem_packet_scope ( ) , strlen ( lines ) + 1 ) ;
2013-01-26 19:09:15 +00:00
q = ret ;
while ( c ) {
if ( c = = ' : ' ) {
lws = FALSE ; /* Prevent leading LWS from showing up */
if ( colon = = - 1 ) { /* First colon */
colon = ( gint ) ( q - ret ) ;
}
* ( q + + ) = sep_seen = c ;
p + + ;
} else if ( c = = ' ; ' | | c = = ' , ' | | c = = ' = ' ) {
lws = FALSE ; /* Prevent leading LWS from showing up */
* ( q + + ) = sep_seen = c ;
p + + ;
} else if ( c = = ' ' | | c = = ' \t ' ) {
lws = TRUE ;
p + + ;
} else if ( c = = ' \n ' ) {
lws = FALSE ; /* Skip trailing LWS */
if ( ( c = * ( p + 1 ) ) ) {
if ( c = = ' ' | | c = = ' \t ' ) { /* Header unfolding */
lws = TRUE ;
p + = 2 ;
} else {
* q = c = 0 ; /* Stop */
}
}
} else if ( c = = ' \r ' ) {
lws = FALSE ;
if ( ( c = * ( p + 1 ) ) ) {
if ( c = = ' \n ' ) {
if ( ( c = * ( p + 2 ) ) ) {
if ( c = = ' ' | | c = = ' \t ' ) { /* Header unfolding */
lws = TRUE ;
p + = 3 ;
} else {
* q = c = 0 ; /* Stop */
}
}
} else if ( c = = ' ' | | c = = ' \t ' ) { /* Header unfolding */
lws = TRUE ;
p + = 2 ;
} else {
* q = c = 0 ; /* Stop */
}
}
} else if ( c = = ' " ' ) { /* Start of quoted-string */
lws = FALSE ;
* ( q + + ) = c ;
while ( c ) {
c = * ( q + + ) = * ( + + p ) ;
2016-08-23 00:53:10 +00:00
if ( c = = ' \\ ' ) {
/* First part of a quoted-pair; copy the other part,
without checking if it ' s a quote */
c = * ( q + + ) = * ( + + p ) ;
} else {
if ( c = = ' " ' ) {
p + + ; /* Skip closing quote */
break ;
}
2013-01-26 19:09:15 +00:00
}
}
/* if already zero terminated now, rewind one char to avoid an "off by one" */
if ( c = = 0 ) {
q - - ;
}
} else { /* Regular character */
if ( sep_seen ) {
sep_seen = 0 ;
} else {
if ( lws ) {
* ( q + + ) = ' ' ;
}
}
lws = FALSE ;
* ( q + + ) = c ;
p + + ; /* OK */
}
if ( c ) {
c = * p ;
}
}
* q = 0 ;
* first_colon_offset = colon ;
return ( ret ) ;
2004-01-16 01:32:20 +00:00
}
2007-07-14 09:19:35 +00:00
/* 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 .
2011-06-19 19:13:26 +00:00
*
2007-07-14 09:19:35 +00:00
* 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 *
2016-08-22 06:33:23 +00:00
get_multipart_info ( packet_info * pinfo , http_message_info_t * message_info )
2007-07-14 09:19:35 +00:00
{
2016-08-23 00:53:10 +00:00
char * start_boundary , * start_protocol = NULL ;
2013-01-26 19:09:15 +00:00
multipart_info_t * m_info = NULL ;
const char * type = pinfo - > match_string ;
char * parameters ;
gint dummy ;
2016-08-22 06:33:23 +00:00
/*
* We need both a content type AND parameters
* for multipart dissection .
*/
if ( type = = NULL ) {
return NULL ;
}
if ( message_info = = NULL ) {
return NULL ;
}
if ( message_info - > media_str = = NULL ) {
2013-01-26 19:09:15 +00:00
return NULL ;
}
/* Clean up the parameters */
2016-08-22 06:33:23 +00:00
parameters = unfold_and_compact_mime_header ( message_info - > media_str , & dummy ) ;
2013-01-26 19:09:15 +00:00
2018-03-10 22:10:25 +00:00
start_boundary = ws_find_media_type_parameter ( wmem_packet_scope ( ) , parameters , " boundary " ) ;
2013-01-26 19:09:15 +00:00
2015-11-29 11:13:40 +00:00
if ( ! start_boundary ) {
2013-01-26 19:09:15 +00:00
return NULL ;
}
2015-11-29 11:13:40 +00:00
if ( strncmp ( type , " multipart/encrypted " , sizeof ( " multipart/encrypted " ) - 1 ) = = 0 ) {
2018-03-10 22:10:25 +00:00
start_protocol = ws_find_media_type_parameter ( wmem_packet_scope ( ) , parameters , " protocol " ) ;
2015-11-29 11:13:40 +00:00
if ( ! start_protocol ) {
2016-08-23 00:53:10 +00:00
g_free ( start_boundary ) ;
2015-11-29 11:13:40 +00:00
return NULL ;
}
}
2013-01-26 19:09:15 +00:00
/*
* There is a value for the boundary string
*/
2016-07-20 02:49:55 +00:00
m_info = wmem_new ( wmem_packet_scope ( ) , multipart_info_t ) ;
2013-01-26 19:09:15 +00:00
m_info - > type = type ;
2018-03-10 22:10:25 +00:00
m_info - > boundary = start_boundary ;
2016-08-23 00:53:10 +00:00
m_info - > boundary_length = ( guint ) strlen ( start_boundary ) ;
2015-11-29 11:13:40 +00:00
if ( start_protocol ) {
2018-03-10 22:10:25 +00:00
m_info - > protocol = start_protocol ;
2016-08-23 00:53:10 +00:00
m_info - > protocol_length = ( guint ) strlen ( start_protocol ) ;
2015-11-29 11:13:40 +00:00
} else {
m_info - > protocol = NULL ;
m_info - > protocol_length = - 1 ;
}
m_info - > orig_content_type = NULL ;
m_info - > orig_parameters = NULL ;
2013-01-26 19:09:15 +00:00
return m_info ;
2004-01-16 01:32:20 +00:00
}
/*
* The first boundary does not implicitly contain the leading
* line - end sequence .
*
* Return the offset to the 1 st byte of the boundary delimiter line .
* Set boundary_line_len to the length of the entire boundary delimiter .
* Set last_boundary to TRUE if we ' ve seen the last - boundary delimiter .
*/
static gint
find_first_boundary ( tvbuff_t * tvb , gint start , const guint8 * boundary ,
2013-01-26 19:09:15 +00:00
gint boundary_len , gint * boundary_line_len , gboolean * last_boundary )
2004-01-16 01:32:20 +00:00
{
2013-01-26 19:09:15 +00:00
gint offset = start , next_offset , line_len , boundary_start ;
2015-02-10 12:49:28 +00:00
while ( tvb_offset_exists ( tvb , offset + 2 + boundary_len ) ) {
2013-01-26 19:09:15 +00:00
boundary_start = offset ;
if ( ( ( tvb_strneql ( tvb , offset , ( const guint8 * ) " -- " , 2 ) = = 0 )
& & ( tvb_strneql ( tvb , offset + 2 , boundary , boundary_len ) = = 0 ) ) )
{
/* Boundary string; now check if last */
2014-11-21 14:54:59 +00:00
if ( ( tvb_reported_length_remaining ( tvb , offset + 2 + boundary_len + 2 ) > = 0 )
2013-01-26 19:09:15 +00:00
& & ( tvb_strneql ( tvb , offset + 2 + boundary_len ,
( const guint8 * ) " -- " , 2 ) = = 0 ) ) {
* last_boundary = TRUE ;
} else {
* last_boundary = FALSE ;
}
/* Look for line end of the boundary line */
line_len = tvb_find_line_end ( tvb , offset , - 1 , & offset , FALSE ) ;
if ( line_len = = - 1 ) {
* boundary_line_len = - 1 ;
} else {
* boundary_line_len = offset - boundary_start ;
}
return boundary_start ;
}
line_len = tvb_find_line_end ( tvb , offset , - 1 , & next_offset , FALSE ) ;
if ( line_len = = - 1 ) {
return - 1 ;
}
offset = next_offset ;
}
return - 1 ;
2004-01-16 01:32:20 +00:00
}
/*
* Unless the first boundary , subsequent boundaries include a line - end sequence
* before the dashed boundary string .
*
* Return the offset to the 1 st byte of the boundary delimiter line .
* Set boundary_line_len to the length of the entire boundary delimiter .
* Set last_boundary to TRUE if we ' ve seen the last - boundary delimiter .
*/
static gint
find_next_boundary ( tvbuff_t * tvb , gint start , const guint8 * boundary ,
2013-01-26 19:09:15 +00:00
gint boundary_len , gint * boundary_line_len , gboolean * last_boundary )
2004-01-16 01:32:20 +00:00
{
2013-01-26 19:09:15 +00:00
gint offset = start , next_offset , line_len , boundary_start ;
2015-02-10 12:49:28 +00:00
while ( tvb_offset_exists ( tvb , offset + 2 + boundary_len ) ) {
2013-01-26 19:09:15 +00:00
line_len = tvb_find_line_end ( tvb , offset , - 1 , & next_offset , FALSE ) ;
if ( line_len = = - 1 ) {
return - 1 ;
}
boundary_start = offset + line_len ;
if ( ( ( tvb_strneql ( tvb , next_offset , ( const guint8 * ) " -- " , 2 ) = = 0 )
& & ( tvb_strneql ( tvb , next_offset + 2 , boundary , boundary_len ) = = 0 ) ) )
{
/* Boundary string; now check if last */
2014-11-21 14:54:59 +00:00
if ( ( tvb_reported_length_remaining ( tvb , next_offset + 2 + boundary_len + 2 ) > = 0 )
2013-01-26 19:09:15 +00:00
& & ( tvb_strneql ( tvb , next_offset + 2 + boundary_len ,
( const guint8 * ) " -- " , 2 ) = = 0 ) ) {
* last_boundary = TRUE ;
} else {
* last_boundary = FALSE ;
}
/* Look for line end of the boundary line */
line_len = tvb_find_line_end ( tvb , next_offset , - 1 , & offset , FALSE ) ;
if ( line_len = = - 1 ) {
* boundary_line_len = - 1 ;
} else {
* boundary_line_len = offset - boundary_start ;
}
return boundary_start ;
2015-11-29 11:13:40 +00:00
/* check if last before CRLF; some ignore the standard, so there is no CRLF before the boundary */
} else if ( ( tvb_strneql ( tvb , boundary_start - 2 , ( const guint8 * ) " -- " , 2 ) = = 0 )
& & ( tvb_strneql ( tvb , boundary_start - ( 2 + boundary_len ) , boundary , boundary_len ) = = 0 )
& & ( tvb_strneql ( tvb , boundary_start - ( 2 + boundary_len + 2 ) ,
( const guint8 * ) " -- " , 2 ) = = 0 ) ) {
boundary_start - = 2 + boundary_len + 2 ;
* boundary_line_len = next_offset - boundary_start ;
* last_boundary = TRUE ;
return boundary_start ;
2013-01-26 19:09:15 +00:00
}
offset = next_offset ;
}
return - 1 ;
2004-01-16 01:32:20 +00:00
}
/*
* Process the multipart preamble :
2013-01-26 19:09:15 +00:00
* [ preamble line - end ] dashed - boundary transport - padding line - end
2004-01-16 01:32:20 +00:00
*
* Return the offset to the start of the first body - part .
*/
static gint
2015-11-29 11:13:40 +00:00
process_preamble ( proto_tree * tree , tvbuff_t * tvb , multipart_info_t * m_info ,
gboolean * last_boundary )
2004-01-16 01:32:20 +00:00
{
2013-01-26 19:09:15 +00:00
gint boundary_start , boundary_line_len ;
2015-11-29 11:13:40 +00:00
const guint8 * boundary = ( guint8 * ) m_info - > boundary ;
gint boundary_len = m_info - > boundary_length ;
2013-01-26 19:09:15 +00:00
boundary_start = find_first_boundary ( tvb , 0 , boundary , boundary_len ,
& boundary_line_len , last_boundary ) ;
if ( boundary_start = = 0 ) {
2014-11-06 04:07:35 +00:00
proto_tree_add_item ( tree , hf_multipart_first_boundary , tvb , boundary_start , boundary_line_len , ENC_NA | ENC_ASCII ) ;
2013-01-26 19:09:15 +00:00
return boundary_start + boundary_line_len ;
} else if ( boundary_start > 0 ) {
if ( boundary_line_len > 0 ) {
gint body_part_start = boundary_start + boundary_line_len ;
2014-12-01 13:47:02 +00:00
if ( boundary_start > 0 ) {
proto_tree_add_item ( tree , hf_multipart_preamble , tvb , 0 , boundary_start , ENC_NA ) ;
2013-01-26 19:09:15 +00:00
}
2014-11-06 04:07:35 +00:00
proto_tree_add_item ( tree , hf_multipart_first_boundary , tvb , boundary_start , boundary_line_len , ENC_NA | ENC_ASCII ) ;
2013-01-26 19:09:15 +00:00
return body_part_start ;
}
}
return - 1 ;
2004-01-16 01:32:20 +00:00
}
2015-11-29 11:13:40 +00:00
static void
dissect_kerberos_encrypted_message ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , gssapi_encrypt_info_t * encrypt )
{
tvbuff_t * kerberos_tvb ;
gint offset = 0 , len ;
guint8 * data ;
2016-02-05 13:21:22 +00:00
proto_tree_add_item ( tree , hf_multipart_sec_token_len , tvb , offset , 4 , ENC_LITTLE_ENDIAN ) ;
offset + = 4 ;
2015-11-29 11:13:40 +00:00
len = tvb_reported_length_remaining ( tvb , offset ) ;
DISSECTOR_ASSERT ( tvb_bytes_exist ( tvb , offset , len ) ) ;
2016-07-20 02:49:55 +00:00
data = ( guint8 * ) tvb_memdup ( pinfo - > pool , tvb , offset , len ) ;
2015-11-29 11:13:40 +00:00
kerberos_tvb = tvb_new_child_real_data ( tvb , data , len , len ) ;
add_new_data_source ( pinfo , kerberos_tvb , " Kerberos Data " ) ;
call_dissector_with_data ( gssapi_handle , kerberos_tvb , pinfo , tree , encrypt ) ;
}
2004-01-16 01:32:20 +00:00
/*
* Process a multipart body - part :
2013-01-26 19:09:15 +00:00
* MIME - part - headers [ line - end * OCTET ]
* line - end dashed - boundary transport - padding line - end
2004-01-16 01:32:20 +00:00
*
* If applicable , call a media subdissector .
*
* Return the offset to the start of the next body - part .
*/
static gint
2016-08-22 06:33:23 +00:00
process_body_part ( proto_tree * tree , tvbuff_t * tvb ,
http_message_info_t * input_message_info , multipart_info_t * m_info ,
2015-11-29 11:13:40 +00:00
packet_info * pinfo , gint start , gint idx ,
2013-01-26 19:09:15 +00:00
gboolean * last_boundary )
2004-01-16 01:32:20 +00:00
{
2014-03-25 20:37:46 +00:00
proto_tree * subtree ;
proto_item * ti ;
2013-01-26 19:09:15 +00:00
gint offset = start , next_offset = 0 ;
2019-01-21 15:41:53 +00:00
http_message_info_t message_info = { input_message_info - > type , NULL , NULL , NULL } ;
2013-01-26 19:09:15 +00:00
gint body_start , boundary_start , boundary_line_len ;
2014-03-25 20:29:56 +00:00
gchar * content_type_str = NULL ;
gchar * content_encoding_str = NULL ;
2013-01-26 19:09:15 +00:00
char * filename = NULL ;
2013-03-18 20:44:36 +00:00
char * mimetypename = NULL ;
2013-01-26 19:09:15 +00:00
gboolean last_field = FALSE ;
2015-11-29 11:13:40 +00:00
gboolean is_raw_data = FALSE ;
const guint8 * boundary = ( guint8 * ) m_info - > boundary ;
gint boundary_len = m_info - > boundary_length ;
2013-01-26 19:09:15 +00:00
2014-03-25 20:37:46 +00:00
ti = proto_tree_add_item ( tree , hf_multipart_part , tvb , start , 0 , ENC_ASCII | ENC_NA ) ;
subtree = proto_item_add_subtree ( ti , ett_multipart_body ) ;
2015-11-29 11:13:40 +00:00
/* find the next boundary to find the end of this body part */
boundary_start = find_next_boundary ( tvb , offset , boundary , boundary_len ,
& boundary_line_len , last_boundary ) ;
if ( boundary_start < = 0 ) {
return - 1 ;
}
2013-01-26 19:09:15 +00:00
/*
* Process the MIME - part - headers
*/
while ( ! last_field )
{
gint colon_offset ;
char * hdr_str ;
char * header_str ;
/* Look for the end of the header (denoted by cr)
* 3 : d argument to imf_find_field_end ( ) maxlen ; must be last offset in the tvb .
*/
2014-11-21 14:54:59 +00:00
next_offset = imf_find_field_end ( tvb , offset , tvb_reported_length_remaining ( tvb , offset ) + offset , & last_field ) ;
2015-11-29 11:13:40 +00:00
/* the following should never happen */
2013-01-26 19:09:15 +00:00
/* If cr not found, won't have advanced - get out to avoid infinite loop! */
2015-11-29 11:13:40 +00:00
/*
2013-01-26 19:09:15 +00:00
if ( next_offset = = offset ) {
break ;
}
2015-11-29 11:13:40 +00:00
*/
if ( last_field & & ( next_offset + 2 ) < = boundary_start ) {
2015-06-03 22:05:52 +00:00
/* Add the extra CRLF of the last field */
next_offset + = 2 ;
2015-11-29 11:13:40 +00:00
} else if ( ( next_offset - 2 ) = = boundary_start ) {
/* if CRLF is the start of next boundary it belongs to the boundary and not the field,
so it ' s the last field without CRLF */
last_field = TRUE ;
next_offset - = 2 ;
} else if ( next_offset > boundary_start ) {
/* if there is no CRLF between last field and next boundary - trim it! */
next_offset = boundary_start ;
2015-06-03 22:05:52 +00:00
}
2013-01-26 19:09:15 +00:00
2014-06-17 15:30:58 +00:00
hdr_str = tvb_get_string_enc ( wmem_packet_scope ( ) , tvb , offset , next_offset - offset , ENC_ASCII ) ;
2013-01-26 19:09:15 +00:00
2018-02-26 13:00:56 +00:00
colon_offset = 0 ;
2013-01-26 19:09:15 +00:00
header_str = unfold_and_compact_mime_header ( hdr_str , & colon_offset ) ;
if ( colon_offset < = 0 ) {
2015-11-29 11:13:40 +00:00
/* if there is no colon it's no header, so break and add complete line to the body */
next_offset = offset ;
break ;
2013-01-26 19:09:15 +00:00
} else {
gint hf_index ;
hf_index = is_known_multipart_header ( header_str , colon_offset ) ;
if ( hf_index = = - 1 ) {
2019-05-29 17:31:13 +00:00
if ( isprint_string ( header_str ) ) {
2015-11-29 11:13:40 +00:00
proto_tree_add_format_text ( subtree , tvb , offset , next_offset - offset ) ;
} else {
/* if the header name is unkown and not printable, break and add complete line to the body */
next_offset = offset ;
break ;
}
2013-01-26 19:09:15 +00:00
} else {
2018-03-10 22:10:25 +00:00
char * value_str = wmem_strdup ( wmem_packet_scope ( ) , header_str + colon_offset + 1 ) ;
2013-01-26 19:09:15 +00:00
2014-03-25 20:37:46 +00:00
proto_tree_add_string_format ( subtree ,
hf_header_array [ hf_index ] , tvb ,
offset , next_offset - offset ,
( const char * ) value_str , " %s " ,
tvb_format_text ( tvb , offset , next_offset - offset ) ) ;
2013-01-26 19:09:15 +00:00
switch ( hf_index ) {
2015-11-29 11:13:40 +00:00
case POS_ORIGINALCONTENT :
{
2016-08-23 00:53:10 +00:00
char * semicolonp ;
2015-11-29 11:13:40 +00:00
/* The Content-Type starts at colon_offset + 1 or after the type parameter */
2018-03-10 22:10:25 +00:00
char * type_str = ws_find_media_type_parameter ( wmem_packet_scope ( ) , value_str , " type " ) ;
2015-11-29 11:13:40 +00:00
if ( type_str ! = NULL ) {
value_str = type_str ;
}
2016-08-23 00:53:10 +00:00
semicolonp = strchr ( value_str , ' ; ' ) ;
2015-11-29 11:13:40 +00:00
2016-08-23 00:53:10 +00:00
if ( semicolonp ! = NULL ) {
* semicolonp = ' \0 ' ;
2015-11-29 11:13:40 +00:00
m_info - > orig_parameters = wmem_strdup ( wmem_packet_scope ( ) ,
2016-08-23 00:53:10 +00:00
semicolonp + 1 ) ;
2015-11-29 11:13:40 +00:00
}
m_info - > orig_content_type = wmem_ascii_strdown ( wmem_packet_scope ( ) , value_str , - 1 ) ;
}
break ;
2013-01-26 19:09:15 +00:00
case POS_CONTENT_TYPE :
{
/* The Content-Type starts at colon_offset + 1 */
2016-08-23 00:53:10 +00:00
char * semicolonp = strchr ( value_str , ' ; ' ) ;
2013-01-26 19:09:15 +00:00
2016-08-23 00:53:10 +00:00
if ( semicolonp ! = NULL ) {
* semicolonp = ' \0 ' ;
message_info . media_str = wmem_strdup ( wmem_packet_scope ( ) , semicolonp + 1 ) ;
2013-01-26 19:09:15 +00:00
} else {
2016-08-22 06:33:23 +00:00
message_info . media_str = NULL ;
2013-01-26 19:09:15 +00:00
}
2014-03-25 20:29:56 +00:00
content_type_str = wmem_ascii_strdown ( wmem_packet_scope ( ) , value_str , - 1 ) ;
2013-01-26 19:09:15 +00:00
/* 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" */
2018-03-10 22:10:25 +00:00
mimetypename = ws_find_media_type_parameter ( wmem_packet_scope ( ) , message_info . media_str , " name " ) ;
2013-01-26 19:09:15 +00:00
2015-11-29 11:13:40 +00:00
if ( strncmp ( content_type_str , " application/octet-stream " ,
sizeof ( " application/octet-stream " ) - 1 ) = = 0 ) {
is_raw_data = TRUE ;
}
2013-01-26 19:09:15 +00:00
2015-11-29 11:13:40 +00:00
/* there are only 2 body parts possible and each part has specific content types */
if ( m_info - > protocol & & idx = = 0
& & ( is_raw_data | | g_ascii_strncasecmp ( content_type_str , m_info - > protocol ,
strlen ( m_info - > protocol ) ) ! = 0 ) )
{
return - 1 ;
}
}
2013-01-26 19:09:15 +00:00
break ;
2019-05-28 18:03:11 +00:00
case POS_CONTENT_TRANSFER_ENCODING :
2013-01-26 19:09:15 +00:00
{
2016-01-06 00:58:42 +00:00
/* The Content-Transferring starts at colon_offset + 1 */
2016-08-23 00:53:10 +00:00
char * crp = strchr ( value_str , ' \r ' ) ;
2013-01-26 19:09:15 +00:00
2016-08-23 00:53:10 +00:00
if ( crp ! = NULL ) {
* crp = ' \0 ' ;
2013-01-26 19:09:15 +00:00
}
2014-03-25 20:29:56 +00:00
content_encoding_str = wmem_ascii_strdown ( wmem_packet_scope ( ) , value_str , - 1 ) ;
2013-01-26 19:09:15 +00:00
}
break ;
2019-05-28 18:03:11 +00:00
case POS_CONTENT_DISPOSITION :
2016-08-23 00:53:10 +00:00
{
2013-01-26 19:09:15 +00:00
/* find the "filename" parameter */
2018-03-10 22:10:25 +00:00
filename = ws_find_media_type_parameter ( wmem_packet_scope ( ) , value_str , " filename " ) ;
2013-01-26 19:09:15 +00:00
}
break ;
2019-05-28 18:03:11 +00:00
case POS_CONTENT_ID :
message_info . content_id = wmem_strdup ( wmem_packet_scope ( ) , value_str ) ;
break ;
2013-01-26 19:09:15 +00:00
default :
break ;
}
}
}
offset = next_offset ;
}
body_start = next_offset ;
/*
* Process the body
*/
2015-11-29 11:13:40 +00:00
{
2013-01-26 19:09:15 +00:00
gint body_len = boundary_start - body_start ;
2014-06-06 14:35:50 +00:00
tvbuff_t * tmp_tvb = tvb_new_subset_length ( tvb , body_start , body_len ) ;
2019-07-27 22:53:22 +00:00
/*
* If multipart subtype is encrypted the protcol string was set .
*
* See MS - WSMV section 2.2 .9 .1 .2 .1 " HTTP Headers " :
*
* https : //docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wsmv/b79927c2-96be-4801-aa68-180db95593f9
*
* There are only 2 body parts possible , and each part has specific
* content types .
*/
2015-11-29 11:13:40 +00:00
if ( m_info - > protocol & & idx = = 1 & & is_raw_data )
{
gssapi_encrypt_info_t encrypt ;
memset ( & encrypt , 0 , sizeof ( encrypt ) ) ;
encrypt . decrypt_gssapi_tvb = DECRYPT_GSSAPI_NORMAL ;
dissect_kerberos_encrypted_message ( tmp_tvb , pinfo , subtree , & encrypt ) ;
if ( encrypt . gssapi_decrypted_tvb ) {
tmp_tvb = encrypt . gssapi_decrypted_tvb ;
is_raw_data = FALSE ;
content_type_str = m_info - > orig_content_type ;
2016-08-22 06:33:23 +00:00
message_info . media_str = m_info - > orig_parameters ;
2015-11-29 11:13:40 +00:00
} else if ( encrypt . gssapi_encrypted_tvb ) {
tmp_tvb = encrypt . gssapi_encrypted_tvb ;
proto_tree_add_expert ( tree , pinfo , & ei_multipart_decryption_not_possible , tmp_tvb , 0 , - 1 ) ;
}
}
2013-01-26 19:09:15 +00:00
2015-11-29 11:13:40 +00:00
if ( ! is_raw_data & &
content_type_str ) {
2013-01-26 19:09:15 +00:00
/*
* subdissection
*/
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 ( ! g_ascii_strncasecmp ( content_encoding_str , " base64 " , 6 ) )
2013-03-18 20:44:36 +00:00
tmp_tvb = base64_decode ( pinfo , tmp_tvb , filename ? filename : ( mimetypename ? mimetypename : content_type_str ) ) ;
2013-01-26 19:09:15 +00:00
}
/*
* First try the dedicated multipart dissector table
*/
dissected = dissector_try_string ( multipart_media_subdissector_table ,
2016-08-22 06:33:23 +00:00
content_type_str , tmp_tvb , pinfo , subtree , & message_info ) ;
2013-01-26 19:09:15 +00:00
if ( ! dissected ) {
/*
* Fall back to the default media dissector table
*/
dissected = dissector_try_string ( media_type_dissector_table ,
2016-08-22 06:33:23 +00:00
content_type_str , tmp_tvb , pinfo , subtree , & message_info ) ;
2013-01-26 19:09:15 +00:00
}
if ( ! dissected ) {
const char * save_match_string = pinfo - > match_string ;
pinfo - > match_string = content_type_str ;
2016-08-22 06:33:23 +00:00
call_dissector_with_data ( media_handle , tmp_tvb , pinfo , subtree , & message_info ) ;
2013-01-26 19:09:15 +00:00
pinfo - > match_string = save_match_string ;
}
2016-08-22 06:33:23 +00:00
message_info . media_str = NULL ; /* Shares same memory as content_type_str */
2013-01-26 19:09:15 +00:00
} else {
2016-03-20 00:33:14 +00:00
call_data_dissector ( tmp_tvb , pinfo , subtree ) ;
2013-01-26 19:09:15 +00:00
}
2014-03-25 20:37:46 +00:00
proto_item_set_len ( ti , boundary_start - start ) ;
if ( * last_boundary = = TRUE ) {
2014-11-06 04:07:35 +00:00
proto_tree_add_item ( tree , hf_multipart_last_boundary , tvb , boundary_start , boundary_line_len , ENC_NA | ENC_ASCII ) ;
2014-03-25 20:37:46 +00:00
} else {
2014-11-06 04:07:35 +00:00
proto_tree_add_item ( tree , hf_multipart_boundary , tvb , boundary_start , boundary_line_len , ENC_NA | ENC_ASCII ) ;
2013-01-26 19:09:15 +00:00
}
return boundary_start + boundary_line_len ;
}
2004-01-16 01:32:20 +00:00
}
/*
* Call this method to actually dissect the multipart body .
* NOTE - Only do so if a boundary string has been found !
*/
2014-11-23 01:47:59 +00:00
static int dissect_multipart ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , void * data )
2004-01-16 01:32:20 +00:00
{
2014-03-25 20:37:46 +00:00
proto_tree * subtree ;
proto_item * ti ;
proto_item * type_ti ;
2016-08-22 06:33:23 +00:00
http_message_info_t * message_info = ( http_message_info_t * ) data ;
multipart_info_t * m_info = get_multipart_info ( pinfo , message_info ) ;
2013-01-26 19:09:15 +00:00
gint header_start = 0 ;
2015-11-29 11:13:40 +00:00
gint body_index = 0 ;
2013-01-26 19:09:15 +00:00
gboolean last_boundary = FALSE ;
if ( m_info = = NULL ) {
/*
* We can ' t get the required multipart information
*/
2015-11-29 11:13:40 +00:00
proto_tree_add_expert ( tree , pinfo , & ei_multipart_no_required_parameter , tvb , 0 , - 1 ) ;
2016-03-20 00:33:14 +00:00
call_data_dissector ( tvb , pinfo , tree ) ;
2014-11-21 14:54:59 +00:00
return tvb_reported_length ( tvb ) ;
2013-01-26 19:09:15 +00:00
}
/* Add stuff to the protocol tree */
2014-03-25 20:37:46 +00:00
ti = proto_tree_add_item ( tree , proto_multipart ,
tvb , 0 , - 1 , ENC_NA ) ;
subtree = proto_item_add_subtree ( ti , ett_multipart ) ;
proto_item_append_text ( ti , " , Type: %s, Boundary: \" %s \" " ,
m_info - > type , m_info - > boundary ) ;
/* Show multi-part type as a generated field */
type_ti = proto_tree_add_string ( subtree , hf_multipart_type ,
tvb , 0 , 0 , pinfo - > match_string ) ;
2019-04-03 21:32:30 +00:00
proto_item_set_generated ( type_ti ) ;
2013-01-26 19:09:15 +00:00
/*
* Make no entries in Protocol column and Info column on summary display ,
* but stop sub - dissectors from clearing entered text in summary display .
*/
col_set_fence ( pinfo - > cinfo , COL_INFO ) ;
/*
* Process the multipart preamble
*/
2015-11-29 11:13:40 +00:00
header_start = process_preamble ( subtree , tvb , m_info , & last_boundary ) ;
2013-01-26 19:09:15 +00:00
if ( header_start = = - 1 ) {
2016-03-20 00:33:14 +00:00
call_data_dissector ( tvb , pinfo , subtree ) ;
2014-11-21 14:54:59 +00:00
return tvb_reported_length ( tvb ) ;
2013-01-26 19:09:15 +00:00
}
/*
* Process the encapsulated bodies
*/
while ( last_boundary = = FALSE ) {
2016-08-22 06:33:23 +00:00
header_start = process_body_part ( subtree , tvb , message_info , m_info ,
2015-11-29 11:13:40 +00:00
pinfo , header_start , body_index + + , & last_boundary ) ;
2013-01-26 19:09:15 +00:00
if ( header_start = = - 1 ) {
2014-11-21 14:54:59 +00:00
return tvb_reported_length ( tvb ) ;
2013-01-26 19:09:15 +00:00
}
}
/*
* Process the multipart trailer
*/
2014-11-21 14:54:59 +00:00
if ( tvb_reported_length_remaining ( tvb , header_start ) > 0 ) {
2014-11-06 04:07:35 +00:00
proto_tree_add_item ( subtree , hf_multipart_trailer , tvb , header_start , - 1 , ENC_NA ) ;
2013-01-26 19:09:15 +00:00
}
2016-07-20 02:49:55 +00:00
2014-11-21 14:54:59 +00:00
return tvb_reported_length ( tvb ) ;
2004-01-16 01:32:20 +00:00
}
/* Returns index of method in multipart_headers */
static gint
is_known_multipart_header ( const char * header_str , guint len )
{
2013-01-26 19:09:15 +00:00
guint i ;
for ( i = 1 ; i < array_length ( multipart_headers ) ; i + + ) {
if ( len = = strlen ( multipart_headers [ i ] . name ) & &
g_ascii_strncasecmp ( header_str , multipart_headers [ i ] . name , len ) = = 0 )
return i ;
if ( multipart_headers [ i ] . compact_name ! = NULL & &
len = = strlen ( multipart_headers [ i ] . compact_name ) & &
g_ascii_strncasecmp ( header_str , multipart_headers [ i ] . compact_name , len ) = = 0 )
return i ;
}
return - 1 ;
2004-01-16 01:32:20 +00:00
}
/*
2006-05-21 04:49:01 +00:00
* Register the protocol with Wireshark .
2004-01-16 01:32:20 +00:00
*
* This format is required because a script is used to build the C function
* that calls all the protocol registration .
*/
void
proto_register_multipart ( void )
{
/* Setup list of header fields See Section 1.6.1 for details */
2013-01-26 19:09:15 +00:00
static hf_register_info hf [ ] = {
{ & hf_multipart_type ,
{ " Type " ,
" mime_multipart.type " ,
FT_STRING , BASE_NONE , NULL , 0x00 ,
" MIME multipart encapsulation type " , HFILL
}
} ,
{ & hf_multipart_part ,
{ " Encapsulated multipart part " ,
" mime_multipart.part " ,
FT_STRING , BASE_NONE , NULL , 0x00 ,
NULL , HFILL
}
} ,
2015-11-29 11:13:40 +00:00
{ & hf_multipart_sec_token_len ,
{ " Length of security token " ,
" mime_multipart.header.sectoken-length " ,
FT_UINT32 , BASE_DEC , NULL , 0x00 ,
" Length of the Kerberos BLOB which follows this token " , HFILL
}
} ,
2016-02-15 14:15:11 +00:00
{ & hf_header_array [ POS_CONTENT_DESCRIPTION ] ,
{ " Content-Description " ,
" mime_multipart.header.content-description " ,
FT_STRING , BASE_NONE , NULL , 0x00 ,
" Content-Description Header " , HFILL
}
} ,
2013-01-26 19:09:15 +00:00
{ & hf_header_array [ POS_CONTENT_DISPOSITION ] ,
{ " Content-Disposition " ,
" mime_multipart.header.content-disposition " ,
FT_STRING , BASE_NONE , NULL , 0x00 ,
" RFC 2183: Content-Disposition Header " , HFILL
}
} ,
{ & hf_header_array [ POS_CONTENT_ENCODING ] ,
{ " Content-Encoding " ,
" mime_multipart.header.content-encoding " ,
FT_STRING , BASE_NONE , NULL , 0x00 ,
" Content-Encoding Header " , HFILL
}
} ,
{ & hf_header_array [ POS_CONTENT_ID ] ,
{ " Content-Id " ,
" mime_multipart.header.content-id " ,
FT_STRING , BASE_NONE , NULL , 0x00 ,
" RFC 2045: Content-Id Header " , HFILL
}
} ,
{ & hf_header_array [ POS_CONTENT_LANGUAGE ] ,
{ " Content-Language " ,
" mime_multipart.header.content-language " ,
FT_STRING , BASE_NONE , NULL , 0x00 ,
" Content-Language Header " , HFILL
}
} ,
{ & hf_header_array [ POS_CONTENT_LENGTH ] ,
{ " Content-Length " ,
" mime_multipart.header.content-length " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
" Content-Length Header " , HFILL
}
} ,
{ & hf_header_array [ POS_CONTENT_TRANSFER_ENCODING ] ,
{ " Content-Transfer-Encoding " ,
" mime_multipart.header.content-transfer-encoding " ,
FT_STRING , BASE_NONE , NULL , 0x00 ,
" RFC 2045: Content-Transfer-Encoding Header " , HFILL
}
} ,
{ & hf_header_array [ POS_CONTENT_TYPE ] ,
{ " Content-Type " ,
" mime_multipart.header.content-type " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
" Content-Type Header " , HFILL
}
} ,
2015-11-29 11:13:40 +00:00
{ & hf_header_array [ POS_ORIGINALCONTENT ] ,
{ " OriginalContent " ,
" mime_multipart.header.originalcontent " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
" Original Content-Type Header " , HFILL
}
} ,
2014-11-06 04:07:35 +00:00
/* Generated from convert_proto_tree_add_text.pl */
{ & hf_multipart_first_boundary , { " First boundary " , " mime_multipart.first_boundary " , FT_STRING , BASE_NONE , NULL , 0x0 , NULL , HFILL } } ,
{ & hf_multipart_preamble , { " Preamble " , " mime_multipart.preamble " , FT_BYTES , BASE_NONE , NULL , 0x0 , NULL , HFILL } } ,
{ & hf_multipart_last_boundary , { " Last boundary " , " mime_multipart.last_boundary " , FT_STRING , BASE_NONE , NULL , 0x0 , NULL , HFILL } } ,
{ & hf_multipart_boundary , { " Boundary " , " mime_multipart.boundary " , FT_STRING , BASE_NONE , NULL , 0x0 , NULL , HFILL } } ,
{ & hf_multipart_trailer , { " Trailer " , " mime_multipart.trailer " , FT_BYTES , BASE_NONE , NULL , 0x0 , NULL , HFILL } } ,
2013-01-26 19:09:15 +00:00
} ;
/*
* Preferences
*/
module_t * multipart_module ;
2014-11-06 04:07:35 +00:00
expert_module_t * expert_multipart ;
2013-01-26 19:09:15 +00:00
/*
* Setup protocol subtree array
*/
static gint * ett [ ] = {
& ett_multipart ,
& ett_multipart_main ,
& ett_multipart_body ,
} ;
2014-11-06 04:07:35 +00:00
static ei_register_info ei [ ] = {
2015-11-29 11:13:40 +00:00
{ & ei_multipart_no_required_parameter , { " mime_multipart.no_required_parameter " , PI_PROTOCOL , PI_ERROR , " The multipart dissector could not find a required parameter. " , EXPFILL } } ,
{ & ei_multipart_decryption_not_possible , { " mime_multipart.decryption_not_possible " , PI_UNDECODED , PI_WARN , " The multipart dissector could not decrypt the message. " , EXPFILL } } ,
2014-11-06 04:07:35 +00:00
} ;
2013-01-26 19:09:15 +00:00
/*
* Register the protocol name and description
*/
proto_multipart = proto_register_protocol (
" MIME Multipart Media Encapsulation " ,
" MIME multipart " ,
" mime_multipart " ) ;
/*
* Required function calls to register
* the header fields and subtrees used .
*/
proto_register_field_array ( proto_multipart , hf , array_length ( hf ) ) ;
proto_register_subtree_array ( ett , array_length ( ett ) ) ;
2014-11-06 04:07:35 +00:00
expert_multipart = expert_register_protocol ( proto_multipart ) ;
expert_register_field_array ( expert_multipart , ei , array_length ( ei ) ) ;
2013-01-26 19:09:15 +00:00
multipart_module = prefs_register_protocol ( proto_multipart , NULL ) ;
prefs_register_bool_preference ( multipart_module ,
" display_unknown_body_as_text " ,
" Display bodies without media type as text " ,
" Display multipart bodies with no media type dissector "
" 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
* dissector in the dissector table below , which is similar to the
* " media_type " dissector table defined in the HTTP dissector code .
*/
multipart_media_subdissector_table = register_dissector_table (
" multipart_media_type " ,
" Internet media type (for multipart processing) " ,
2016-08-30 22:51:54 +00:00
proto_multipart , FT_STRING , BASE_NONE ) ;
2004-01-16 01:32:20 +00:00
}
/* If this dissector uses sub-dissector registration add a registration routine.
This format is required because a script is used to find these routines and
create the code that calls these routines .
*/
void
proto_reg_handoff_multipart ( void )
{
2013-01-26 19:09:15 +00:00
dissector_handle_t multipart_handle ;
/*
* When we cannot display the data , call the data dissector .
* When there is no dissector for the given media , call the media dissector .
*/
2016-03-16 13:02:52 +00:00
media_handle = find_dissector_add_dependency ( " media " , proto_multipart ) ;
gssapi_handle = find_dissector_add_dependency ( " gssapi " , proto_multipart ) ;
2013-01-26 19:09:15 +00:00
/*
* Get the content type and Internet media type table
*/
media_type_dissector_table = find_dissector_table ( " media_type " ) ;
/*
* Handle for multipart dissection
*/
2015-12-09 03:49:44 +00:00
multipart_handle = create_dissector_handle (
2013-01-26 19:09:15 +00:00
dissect_multipart , proto_multipart ) ;
dissector_add_string ( " media_type " ,
" multipart/mixed " , multipart_handle ) ;
dissector_add_string ( " media_type " ,
" multipart/related " , multipart_handle ) ;
dissector_add_string ( " media_type " ,
" multipart/alternative " , multipart_handle ) ;
dissector_add_string ( " media_type " ,
" multipart/form-data " , multipart_handle ) ;
dissector_add_string ( " media_type " ,
" multipart/report " , multipart_handle ) ;
2014-12-01 13:57:07 +00:00
dissector_add_string ( " media_type " ,
" multipart/signed " , multipart_handle ) ;
2015-11-29 11:13:40 +00:00
dissector_add_string ( " media_type " ,
" multipart/encrypted " , multipart_handle ) ;
2013-01-26 19:09:15 +00:00
/*
* Supply an entry to use for unknown multipart subtype .
* See RFC 2046 , section 5.1 .3
*/
dissector_add_string ( " media_type " ,
" multipart/ " , multipart_handle ) ;
2004-01-16 01:32:20 +00:00
}
2014-09-29 18:42:55 +00:00
/*
2019-07-26 18:43:17 +00:00
* Editor modelines - https : //www.wireshark.org/tools/modelines.html
2014-09-29 18:42:55 +00:00
*
* Local variables :
* c - basic - offset : 4
* tab - width : 8
* indent - tabs - mode : nil
* End :
*
* vi : set shiftwidth = 4 tabstop = 8 expandtab :
* : indentSize = 4 : tabSize = 8 : noTabs = true :
*/