*
* $Id$
*
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+/* The DCE RPC specification can be found at:
+ * http://www.opengroup.org/dce/
+ */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <epan/packet.h>
#include <epan/dissectors/packet-dcerpc.h>
#include <epan/conversation.h>
-#include "prefs.h"
-#include "reassemble.h"
-#include "tap.h"
+#include <epan/prefs.h>
+#include <epan/reassemble.h>
+#include <epan/tap.h>
+#include <epan/emem.h>
#include <epan/dissectors/packet-frame.h>
#include <epan/dissectors/packet-dcerpc-nt.h>
+#include <epan/expert.h>
+#include <epan/strutil.h>
static int dcerpc_tap = -1;
{ DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
{ DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
{ DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
- { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
+ { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
"Distributed Password Authentication SSP"},
{ DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
{ DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
#define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
#define USER_DATA_NOT_READABLE 6 /* not used */
#define NO_PSAP_AVAILABLE 7 /* not used */
+#define AUTH_TYPE_NOT_RECOGNIZED 8
+#define INVALID_CHECKSUM 9
static const value_string reject_reason_vals[] = {
{ REASON_NOT_SPECIFIED, "Reason not specified" },
{ DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
{ USER_DATA_NOT_READABLE, "User data not readable" },
{ NO_PSAP_AVAILABLE, "No PSAP available" },
+ { AUTH_TYPE_NOT_RECOGNIZED, "Authentication type not recognized" },
+ { INVALID_CHECKSUM, "Invalid checksum" },
{ 0, NULL }
};
*/
static const value_string reject_status_vals[] = {
{ 0, "Stub-defined exception" },
+ { 0x00000001, "nca_s_fault_other" },
+ { 0x00000005, "nca_s_fault_access_denied" },
+ { 0x000006f7, "nca_s_fault_ndr" },
+ { 0x000006d8, "nca_s_fault_cant_perform" },
{ 0x1c000001, "nca_s_fault_int_div_by_zero" },
{ 0x1c000002, "nca_s_fault_addr_error" },
{ 0x1c000003, "nca_s_fault_fp_div_zero" },
{ 0x1c010013, "nca_out_args_too_big" },
{ 0x1c010014, "nca_server_too_busy" },
{ 0x1c010017, "nca_unsupported_type" },
+ /* MS Windows specific values
+ * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp
+ * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp
+ * and: http://www.megos.ch/support/doserrors.txt
+ *
+ * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
+ * at least MS protocols (like DCOM) do it that way ... */
+ { 0x80004001, "E_NOTIMPL" },
+ { 0x80004003, "E_POINTER" },
+ { 0x80004004, "E_ABORT" },
+ { 0x8000FFFF, "E_UNEXPECTED" },
+ { 0x80010105, "RPC_E_SERVERFAULT" },
+ { 0x80010108, "RPC_E_DISCONNECTED" },
+ { 0x80010113, "RPC_E_INVALID_IPID" },
+ { 0x8001011F, "RPC_E_TIMEOUT" },
+ { 0x80020003, "DISP_E_MEMBERNOTFOUND" },
+ { 0x80020006, "DISP_E_UNKNOWNNAME" },
+ { 0x8002000E, "DISP_E_BADPARAMCOUNT" },
+ { 0x8004CB00, "CBA_E_MALFORMED" },
+ { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
+ { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
+ { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
+ { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
+ { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
+ { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
+ { 0x8004CB13, "CBA_E_QOSTYPENOTAPPLICABLE" },
+ { 0x8004CB18, "CBA_E_OUTOFPARTNERACCOS" },
+ { 0x8004CB1C, "CBA_E_FLAGUNSUPPORTED" },
+ { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" },
+ { 0x8004CB25, "CBA_E_MODECHANGE" },
+ { 0x8007000E, "E_OUTOFMEMORY" },
+ { 0x80070057, "E_INVALIDARG" },
+ { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
+ { 0x80070776, "OR_INVALID_OXID" },
{ 0, NULL }
};
/* we need to keep track of what transport were used, ie what handle we came
- * in through so we know what kind of pinfo->private_data was passed to us.
+ * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
*/
/* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
#define DCE_TRANSPORT_UNKNOWN 0
static int hf_dcerpc_cn_max_recv = -1;
static int hf_dcerpc_cn_assoc_group = -1;
static int hf_dcerpc_cn_num_ctx_items = -1;
+static int hf_dcerpc_cn_ctx_item = -1;
static int hf_dcerpc_cn_ctx_id = -1;
static int hf_dcerpc_cn_num_trans_items = -1;
+static int hf_dcerpc_cn_bind_abstract_syntax = -1;
static int hf_dcerpc_cn_bind_if_id = -1;
static int hf_dcerpc_cn_bind_if_ver = -1;
static int hf_dcerpc_cn_bind_if_ver_minor = -1;
+static int hf_dcerpc_cn_bind_trans_syntax = -1;
static int hf_dcerpc_cn_bind_trans_id = -1;
static int hf_dcerpc_cn_bind_trans_ver = -1;
static int hf_dcerpc_cn_alloc_hint = -1;
static int hf_dcerpc_cn_protocol_ver_minor = -1;
static int hf_dcerpc_cn_cancel_count = -1;
static int hf_dcerpc_cn_status = -1;
+static int hf_dcerpc_cn_deseg_req = -1;
static int hf_dcerpc_auth_type = -1;
static int hf_dcerpc_auth_level = -1;
static int hf_dcerpc_auth_pad_len = -1;
static gint ett_dcerpc_cn_flags = -1;
static gint ett_dcerpc_cn_ctx = -1;
static gint ett_dcerpc_cn_iface = -1;
+static gint ett_dcerpc_cn_trans_syntax = -1;
static gint ett_dcerpc_drep = -1;
static gint ett_dcerpc_dg_flags1 = -1;
static gint ett_dcerpc_dg_flags2 = -1;
/* list of hooks to be called when init_protocols is done */
GHookList dcerpc_hooks_init_protos;
-#ifdef _WIN32
-int ResolveWin32UUID(e_uuid_t if_id, char *UUID_NAME, int UUID_NAME_MAX_LEN)
-{
- char REG_UUID_NAME[MAX_PATH];
- HKEY hKey = NULL;
- DWORD UUID_MAX_SIZE = MAX_PATH;
- char REG_UUID_STR[MAX_PATH];
-
- if(UUID_NAME_MAX_LEN < 2)
- return 0;
- REG_UUID_NAME[0] = '\0';
- snprintf(REG_UUID_STR, MAX_PATH, "SOFTWARE\\Classes\\Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
- if_id.Data1, if_id.Data2, if_id.Data3,
- if_id.Data4[0], if_id.Data4[1],
- if_id.Data4[2], if_id.Data4[3],
- if_id.Data4[4], if_id.Data4[5],
- if_id.Data4[6], if_id.Data4[7]);
- if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)REG_UUID_STR, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
- {
- if (RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)REG_UUID_NAME, &UUID_MAX_SIZE) == ERROR_SUCCESS && UUID_MAX_SIZE <= MAX_PATH)
- {
- snprintf(UUID_NAME, UUID_NAME_MAX_LEN, "%s", REG_UUID_NAME);
- RegCloseKey(hKey);
- return strlen(REG_UUID_NAME);
- }
- RegCloseKey(hKey);
- }
- return 0; /* we didn't find anything anyhow. Please don't use the string! */
-
-}
-#endif
-
static dcerpc_info *
get_next_di(void)
{
static gboolean dcerpc_cn_desegment = TRUE;
/* reassemble DCE/RPC fragments */
-/* reassembly of dcerpc fragments will not work for the case where ONE frame
+/* reassembly of cl dcerpc fragments will not work for the case where ONE frame
might contain multiple dcerpc fragments for different PDUs.
this case would be so unusual/weird so if you got captures like that:
too bad
+
+ reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
+ are coming in out of sequence, but that will hurt in a lot of other places as well.
*/
-static gboolean dcerpc_reassemble = FALSE;
+static gboolean dcerpc_reassemble = TRUE;
+static GHashTable *dcerpc_co_fragment_table = NULL;
static GHashTable *dcerpc_co_reassemble_table = NULL;
static GHashTable *dcerpc_cl_reassemble_table = NULL;
static void
dcerpc_reassemble_init(void)
{
- fragment_table_init(&dcerpc_co_reassemble_table);
+ fragment_table_init(&dcerpc_co_fragment_table);
+ reassembled_table_init(&dcerpc_co_reassemble_table);
dcerpc_fragment_table_init(&dcerpc_cl_reassemble_table);
}
for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
- if (asd->auth_level == auth_level &&
+ if (asd->auth_level == auth_level &&
asd->auth_type == auth_type)
return &asd->auth_fns;
}
/* Hand off verifier data to a registered dissector */
static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
- proto_tree *tree,
+ proto_tree *tree,
dcerpc_auth_subdissector_fns *auth_fns,
- e_dce_cn_common_hdr_t *hdr,
+ e_dce_cn_common_hdr_t *hdr,
dcerpc_auth_info *auth_info)
{
dcerpc_dissect_fnct_t *volatile fn = NULL;
fn = auth_fns->resp_verf_fn;
break;
- /* Don't know how to handle authentication data in this
+ /* Don't know how to handle authentication data in this
pdu type. */
default:
if (fn)
fn(auth_tvb, 0, pinfo, tree, hdr->drep);
- else
+ else {
+ tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
- "%s Verifier",
- val_to_str(auth_info->auth_type,
+ "%s Verifier",
+ val_to_str(auth_info->auth_type,
authn_protocol_vals,
"Unknown (%u)"));
+ }
}
/* Hand off payload data to a registered dissector */
-static tvbuff_t *decode_encrypted_data(tvbuff_t *enc_tvb,
+static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
+ tvbuff_t *auth_tvb,
packet_info *pinfo,
dcerpc_auth_subdissector_fns *auth_fns,
- gboolean is_request,
+ gboolean is_request,
dcerpc_auth_info *auth_info)
{
dcerpc_decode_data_fnct_t *fn;
fn = auth_fns->resp_data_fn;
if (fn)
- return fn(enc_tvb, 0, pinfo, auth_info);
+ return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
return NULL;
}
hf_info = proto_registrar_get_nth(opnum_hf);
hf_info->strings = value_string_from_subdissectors(procs);
+
+ /* add this GUID to the global name resolving */
+ guids_add_uuid(uuid, proto_get_protocol_short_name (value->proto));
}
/* Function to find the name of a registered protocol
- * or NULL if the protocol/version is not known to ethereal.
+ * or NULL if the protocol/version is not known to wireshark.
*/
-char *
+const char *
dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
{
dcerpc_uuid_key key;
}
/* Function to find the opnum hf-field of a registered protocol
- * or -1 if the protocol/version is not known to ethereal.
+ * or -1 if the protocol/version is not known to wireshark.
*/
int
dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
}
/* Function to find the subdissector table of a registered protocol
- * or NULL if the protocol/version is not known to ethereal.
+ * or NULL if the protocol/version is not known to wireshark.
*/
dcerpc_sub_dissector *
dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
guint16 ver;
} dcerpc_bind_value;
-static GMemChunk *dcerpc_bind_key_chunk=NULL;
-static GMemChunk *dcerpc_bind_value_chunk=NULL;
-
static gint
dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
{
dcerpc_bind_hash (gconstpointer k)
{
const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
- return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
+ guint hash;
+
+ hash=GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
+ return hash;
}
e_uuid_t act_id ;
} dcerpc_dg_call_key;
-static GMemChunk *dcerpc_cn_call_key_chunk=NULL;
-
-static GMemChunk *dcerpc_dg_call_key_chunk=NULL;
-
-static GMemChunk *dcerpc_call_value_chunk=NULL;
-
static gint
dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2)
dcerpc_cn_call_hash (gconstpointer k)
{
const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
- return ((guint32)key->conv) + key->call_id + key->smb_fid;
+ return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
}
static guint
dcerpc_dg_call_hash (gconstpointer k)
{
const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
- return (((guint32)key->conv) + key->seqnum + key->act_id.Data1
+ return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
+ (key->act_id.Data2 << 16) + key->act_id.Data3
+ (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
+ (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
guint32 call_id;
} dcerpc_matched_key;
-static GMemChunk *dcerpc_matched_key_chunk=NULL;
-
static gint
dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
{
if (tree) {
if(data==0xffffffff){
/* special case, no time specified */
- proto_tree_add_time_format(tree, hfindex, tvb, offset, 4, &tv, "%s: No time specified", proto_registrar_get_nth(hfindex)->name);
+ proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
} else {
proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
}
int
dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
proto_tree *tree, guint8 *drep,
- int hfindex, unsigned char *pdata)
+ int hfindex, guint64 *pdata)
{
- if(pdata){
- tvb_memcpy(tvb, pdata, offset, 8);
- if(drep[0] & 0x10){/* XXX this might be the wrong way around */
- unsigned char data;
- data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
- data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
- data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
- data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
- }
- }
+ guint64 data;
+
+ data = ((drep[0] & 0x10)
+ ? tvb_get_letoh64 (tvb, offset)
+ : tvb_get_ntoh64 (tvb, offset));
if (tree) {
proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
}
-
+ if (pdata)
+ *pdata = data;
return offset+8;
}
int
dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
- proto_tree *tree, guint8 *drep,
+ proto_tree *tree, guint8 *drep,
int hfindex, gfloat *pdata)
{
gfloat data;
int
dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
- proto_tree *tree, guint8 *drep,
+ proto_tree *tree, guint8 *drep,
int hfindex, gdouble *pdata)
{
gdouble data;
}
+int
+dissect_dcerpc_uuid_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
+ proto_tree *tree, guint8 *drep,
+ int hfindex, e_uuid_t *pdata)
+{
+ e_uuid_t uuid;
+
+
+ if (drep[0] & 0x10) {
+ tvb_get_letohguid (tvb, offset, (e_guid_t *) &uuid);
+ } else {
+ tvb_get_ntohguid (tvb, offset, (e_guid_t *) &uuid);
+ }
+ if (tree) {
+ proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
+ }
+ if (pdata) {
+ *pdata = uuid;
+ }
+ return offset + 16;
+}
+
+
/*
* a couple simpler things
*/
void
dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
{
- unsigned int i;
- uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
- uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
- uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
-
- for (i=0; i<sizeof (uuid->Data4); i++) {
- uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
+ if (drep[0] & 0x10) {
+ tvb_get_letohguid (tvb, offset, (e_guid_t *) uuid);
+ } else {
+ tvb_get_ntohguid (tvb, offset, (e_guid_t *) uuid);
}
}
-
/* NDR arrays */
/* function to dissect a unidimensional conformant array */
int
proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
+ /* real run, dissect the elements */
+ for(i=0;i<di->array_actual_count;i++){
+ old_offset = offset;
+ offset = (*fnct)(tvb, offset, pinfo, tree, drep);
+ if (offset <= old_offset)
+ THROW(ReportedBoundsError);
+ }
+ }
+
+ return offset;
+}
+/* function to dissect a unidimensional varying array */
+int
+dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
+ proto_tree *tree, guint8 *drep,
+ dcerpc_dissect_fnct_t *fnct)
+{
+ guint32 i;
+ dcerpc_info *di;
+ int old_offset;
+
+ di=pinfo->private_data;
+ if(di->conformant_run){
+ /* conformant run, just dissect the max_count header */
+ old_offset=offset;
+ di->conformant_run=0;
+ offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
+ hf_dcerpc_array_offset, &di->array_offset);
+ di->array_offset_offset=offset-4;
+ offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
+ hf_dcerpc_array_actual_count, &di->array_actual_count);
+ di->array_actual_count_offset=offset-4;
+ di->conformant_run=1;
+ di->conformant_eaten=offset-old_offset;
+ } else {
+ /* we dont dont remember where in the bytestream these fields were */
+ proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
+ proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
+
/* real run, dissect the elements */
for(i=0;i<di->array_actual_count;i++){
offset = (*fnct)(tvb, offset, pinfo, tree, drep);
that are conformant and varying - they're stored like conformant
varying arrays of bytes. */
int
-dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
+dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *tree, guint8 *drep)
{
dcerpc_info *di;
offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
hf_dcerpc_array_actual_count, &len);
- if (tree && len)
+ if (tree && len) {
+ tvb_ensure_bytes_exist(tvb, offset, len);
proto_tree_add_item(tree, hf_dcerpc_array_buffer,
tvb, offset, len, drep[0] & 0x10);
+ }
offset += len;
XXX - does this need to do all the conformant array stuff that
"dissect_ndr_ucvarray()" does? */
int
-dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
+dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *tree, guint8 *drep, int size_is,
int hfindex, gboolean add_subtree, char **data)
{
*/
if (tree && buffer_len) {
hfinfo = proto_registrar_get_nth(hfindex);
+ tvb_ensure_bytes_exist(tvb, offset, buffer_len);
if (hfinfo->type == FT_STRING) {
proto_tree_add_string(string_tree, hfindex, tvb, offset,
buffer_len, s);
* but that's another matter; in any case, that would happen only
* if we had an immensely large tvbuff....)
*/
+ tvb_ensure_bytes_exist(tvb, offset, buffer_len);
s = tvb_get_string(tvb, offset, buffer_len);
if (tree && buffer_len)
proto_tree_add_item(string_tree, hfindex, tvb, offset,
*data = s;
else
g_free(s);
-
+
offset += buffer_len;
proto_item_set_end(string_item, tvb, offset);
such as C. Is this ever used for purely counted strings?
(Not that it matters if it is.) */
int
-dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
+dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *tree, guint8 *drep)
{
dcerpc_info *di;
such as C. Is this ever used for purely counted strings?
(Not that it matters if it is.) */
int
-dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
+dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *tree, guint8 *drep)
{
dcerpc_info *di;
FALSE, NULL);
}
+/* Dissect an NDR varying string of elements.
+ The length of each element is given by the 'size_is' parameter;
+ the elements are assumed to be characters or wide characters.
+*/
+int
+dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, guint8 *drep, int size_is,
+ int hfindex, gboolean add_subtree, char **data)
+{
+ dcerpc_info *di;
+ proto_item *string_item;
+ proto_tree *string_tree;
+ guint32 len, buffer_len;
+ char *s;
+ header_field_info *hfinfo;
+
+ di=pinfo->private_data;
+ if(di->conformant_run){
+ /* just a run to handle conformant arrays, no scalars to dissect */
+ return offset;
+ }
+
+ if (add_subtree) {
+ string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
+ proto_registrar_get_name(hfindex));
+ string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
+ } else {
+ string_item = NULL;
+ string_tree = tree;
+ }
+
+ /* NDR array header */
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
+ hf_dcerpc_array_offset, NULL);
+
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
+ hf_dcerpc_array_actual_count, &len);
+
+ buffer_len = size_is * len;
+
+ /* Adjust offset */
+ if (offset % size_is)
+ offset += size_is - (offset % size_is);
+
+ if (size_is == sizeof(guint16)) {
+ /* XXX - use drep to determine the byte order? */
+ s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
+ /*
+ * XXX - we don't support a string type with Unicode
+ * characters, so if this is a string item, we make
+ * its value be the "fake Unicode" string.
+ */
+ if (tree && buffer_len) {
+ hfinfo = proto_registrar_get_nth(hfindex);
+ tvb_ensure_bytes_exist(tvb, offset, buffer_len);
+ if (hfinfo->type == FT_STRING) {
+ proto_tree_add_string(string_tree, hfindex, tvb, offset,
+ buffer_len, s);
+ } else {
+ proto_tree_add_item(string_tree, hfindex, tvb, offset,
+ buffer_len, drep[0] & 0x10);
+ }
+ }
+ } else {
+ /*
+ * "tvb_get_string()" throws an exception if the entire string
+ * isn't in the tvbuff. If the length is bogus, this should
+ * keep us from trying to allocate an immensely large buffer.
+ * (It won't help if the length is *valid* but immensely large,
+ * but that's another matter; in any case, that would happen only
+ * if we had an immensely large tvbuff....)
+ */
+ tvb_ensure_bytes_exist(tvb, offset, buffer_len);
+ s = tvb_get_string(tvb, offset, buffer_len);
+ if (tree && buffer_len)
+ proto_tree_add_item(string_tree, hfindex, tvb, offset,
+ buffer_len, drep[0] & 0x10);
+ }
+
+ if (string_item != NULL)
+ proto_item_append_text(string_item, ": %s", s);
+
+ if (data)
+ *data = s;
+ else
+ g_free(s);
+
+ offset += buffer_len;
+
+ proto_item_set_end(string_item, tvb, offset);
+
+ return offset;
+}
+/* Dissect an varying string of chars.
+ This corresponds to IDL of the form '[string] char *foo'.
+
+ XXX - at least according to the DCE RPC 1.1 spec, a string has
+ a null terminator, which isn't necessary as a terminator for
+ the transfer language (as there's a length), but is presumably
+ there for the benefit of null-terminated-string languages
+ such as C. Is this ever used for purely counted strings?
+ (Not that it matters if it is.) */
+int
+dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, guint8 *drep)
+{
+ dcerpc_info *di;
+ di=pinfo->private_data;
+
+ return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
+ sizeof(guint8), di->hf_index,
+ FALSE, NULL);
+}
+
+/* Dissect a varying string of wchars (wide characters).
+ This corresponds to IDL of the form '[string] wchar *foo'
+
+ XXX - at least according to the DCE RPC 1.1 spec, a string has
+ a null terminator, which isn't necessary as a terminator for
+ the transfer language (as there's a length), but is presumably
+ there for the benefit of null-terminated-string languages
+ such as C. Is this ever used for purely counted strings?
+ (Not that it matters if it is.) */
+int
+dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, guint8 *drep)
+{
+ dcerpc_info *di;
+ di=pinfo->private_data;
+
+ return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
+ sizeof(guint16), di->hf_index,
+ FALSE, NULL);
+}
+
+
/* ndr pointer handling */
/* list of pointers encountered so far */
static GSList *ndr_pointer_list = NULL;
pointers_are_top_level=TRUE;
}
-static int
+int
dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
{
int found_new_pointer;
old_offset = offset;
offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
- g_assert((offset-old_offset)==di->conformant_eaten);
+ DISSECTOR_ASSERT((offset-old_offset)==di->conformant_eaten);
/* This is to check for any bugs in the dissectors.
*
* Basically, the NDR representation will store all
static void
add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
- dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
+ dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
dcerpc_callback_fnct_t *callback, void *callback_args)
{
ndr_pointer_data_t *npd;
int
dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
- int type, char *text, int hf_index,
+ int type, const char *text, int hf_index,
dcerpc_callback_fnct_t *callback, void *callback_args)
{
dcerpc_info *di;
+ proto_tree *tr = NULL;
+ gint start_offset = offset;
di=pinfo->private_data;
if(di->conformant_run){
if( pointers_are_top_level
&&(type==NDR_POINTER_REF) ){
proto_item *item;
- proto_tree *tr;
/* we must find out a nice way to do the length here */
item=proto_tree_add_text(tree, tvb, offset, 0,
"%s", text);
tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
- add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
+ add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
hf_index, callback, callback_args);
goto after_ref_id;
}
int idx;
guint32 id;
proto_item *item;
- proto_tree *tr;
/* get the referent id */
offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
+ tvb_ensure_bytes_exist(tvb, offset-4, 4);
/* we got a NULL pointer */
if(id==0){
proto_tree_add_text(tree, tvb, offset-4, 4,
"%s", text);
tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
- add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
+ add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
callback, callback_args);
goto after_ref_id;
}
&& (type==NDR_POINTER_UNIQUE) ){
guint32 id;
proto_item *item;
- proto_tree *tr;
/* get the referent id */
offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
+ tvb_ensure_bytes_exist(tvb, offset-4, 4);
/* we got a NULL pointer */
if(id==0){
proto_tree_add_text(tree, tvb, offset-4, 4,
"%s", text);
tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
- add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
+ add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
hf_index, callback, callback_args);
goto after_ref_id;
}
&& (type==NDR_POINTER_REF) ){
guint32 id;
proto_item *item;
- proto_tree *tr;
/* get the referent id */
offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
+ tvb_ensure_bytes_exist(tvb, offset-4, 4);
/* new pointer */
item=proto_tree_add_text(tree, tvb, offset-4, 4,
"%s",text);
tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
- add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
+ add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
hf_index, callback, callback_args);
goto after_ref_id;
}
&& (type==NDR_POINTER_UNIQUE) ){
guint32 id;
proto_item *item;
- proto_tree *tr;
/* get the referent id */
offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
+ tvb_ensure_bytes_exist(tvb, offset-4, 4);
/* we got a NULL pointer */
if(id==0){
proto_tree_add_text(tree, tvb, offset-4, 4,
"%s",text);
tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
- add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
+ add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
hf_index, callback, callback_args);
goto after_ref_id;
}
int idx;
guint32 id;
proto_item *item;
- proto_tree *tr;
/* get the referent id */
offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
+ tvb_ensure_bytes_exist(tvb, offset-4, 4);
/* we got a NULL pointer */
if(id==0){
proto_tree_add_text(tree, tvb, offset-4, 4,
"%s", text);
tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
- add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
+ add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
callback, callback_args);
goto after_ref_id;
}
pointers_are_top_level=TRUE;
}
+ /* Set the length for the new subtree */
+ if (tr){
+ proto_item_set_len(tr, offset-start_offset);
+ }
return offset;
}
int
dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
- int type, char *text, int hf_index)
+ int type, const char *text, int hf_index)
{
return dissect_ndr_pointer_cb(
tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
NULL, NULL);
}
+int
+dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
+ proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
+ int type, const char *text, int hf_index)
+{
+ int ret;
+
+ pointers_are_top_level=TRUE;
+ ret=dissect_ndr_pointer_cb(
+ tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
+ NULL, NULL);
+ return ret;
+}
+int
+dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
+ proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
+ int type, const char *text, int hf_index)
+{
+ int ret;
+
+ pointers_are_top_level=FALSE;
+ ret=dissect_ndr_pointer_cb(
+ tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
+ NULL, NULL);
+ return ret;
+}
static void
show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
dcerpc_auth_info *auth_info, gboolean is_encrypted)
{
- int length;
+ int length, plain_length, auth_pad_len;
+ guint auth_pad_offset;
/*
* We don't show stub data unless we have some in the tvbuff;
* that happen to be in the tvbuff.
*/
if (tvb_length_remaining (tvb, offset) > 0) {
+ auth_pad_len = auth_info?auth_info->auth_pad_len:0;
length = tvb_reported_length_remaining (tvb, offset);
+
+ /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
+ plain_length = length - auth_pad_len;
+ if (plain_length < 1) {
+ plain_length = length;
+ auth_pad_len = 0;
+ }
+ auth_pad_offset = offset + plain_length;
+
if (auth_info != NULL &&
auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
if (is_encrypted) {
- proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
+ tvb_ensure_bytes_exist(tvb, offset, length);
+ proto_tree_add_text(dcerpc_tree, tvb, offset, length,
"Encrypted stub data (%d byte%s)",
length, plurality(length, "", "s"));
+ /* is the padding is still inside the encrypted blob, don't display it explicit */
+ auth_pad_len = 0;
} else {
- proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
+ tvb_ensure_bytes_exist(tvb, offset, plain_length);
+ proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
"Decrypted stub data (%d byte%s)",
- length, plurality(length, "", "s"));
+ plain_length, plurality(plain_length, "", "s"));
}
} else {
- proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
- "Stub data (%d byte%s)", length,
- plurality(length, "", "s"));
+ tvb_ensure_bytes_exist(tvb, offset, plain_length);
+ proto_tree_add_text (dcerpc_tree, tvb, offset, plain_length,
+ "Stub data (%d byte%s)", plain_length,
+ plurality(plain_length, "", "s"));
}
+ /* If there is auth padding at the end of the stub, display it */
+ if (auth_pad_len != 0) {
+ tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
+ proto_tree_add_text (dcerpc_tree, tvb, auth_pad_offset,
+ auth_pad_len,
+ "Auth Padding (%u byte%s)",
+ auth_pad_len,
+ plurality(auth_pad_len, "", "s"));
+ }
}
}
dcerpc_uuid_value *sub_proto;
proto_tree *volatile sub_tree = NULL;
dcerpc_sub_dissector *proc;
- gchar *name = NULL;
+ const gchar *name = NULL;
dcerpc_dissect_fnct_t *volatile sub_dissect;
const char *volatile saved_proto;
void *volatile saved_private_data;
- guint length, reported_length;
+ guint length = 0, reported_length = 0;
tvbuff_t *volatile stub_tvb;
volatile guint auth_pad_len;
volatile int auth_pad_offset;
-#ifdef _WIN32
- char UUID_NAME[MAX_PATH];
-#endif
+ proto_item *sub_item=NULL;
+ proto_item *pi;
key.uuid = info->call_data->uuid;
key.ver = info->call_data->ver;
proto_tree_add_boolean_hidden(dcerpc_tree, hf_dcerpc_unknown_if_id,
tvb, offset, 0, TRUE);
if (check_col (pinfo->cinfo, COL_INFO)) {
-#ifdef _WIN32
- if(ResolveWin32UUID(info->call_data->uuid, UUID_NAME, MAX_PATH))
- col_append_fstr (pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
- UUID_NAME, info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
- info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
- info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
- info->call_data->uuid.Data4[7], info->call_data->ver);
-else
-#endif
- col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
- info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
- info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
- info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
- info->call_data->uuid.Data4[7], info->call_data->ver);
+ col_append_fstr (pinfo->cinfo, COL_INFO, " %s V%u",
+ guids_resolve_uuid_to_str(&info->call_data->uuid), info->call_data->ver);
}
if (decrypted_tvb != NULL) {
name, (info->ptype == PDU_REQ) ? "request" : "response");
}
+ sub_dissect = (info->ptype == PDU_REQ) ?
+ proc->dissect_rqst : proc->dissect_resp;
+
if (tree) {
- proto_item *sub_item;
- sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
- -1, FALSE);
+ sub_item = proto_tree_add_item (tree, sub_proto->proto_id,
+ (decrypted_tvb != NULL)?decrypted_tvb:tvb,
+ 0, -1, FALSE);
if (sub_item) {
sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
* Put the operation number into the tree along with
* the operation's name.
*/
-
if (sub_proto->opnum_hf != -1)
- proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
- tvb, 0, 0, info->call_data->opnum,
- "Operation: %s (%u)",
- name, info->call_data->opnum);
+ proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
+ tvb, 0, 0, info->call_data->opnum,
+ "Operation: %s (%u)",
+ name, info->call_data->opnum);
else
- proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
- 0, 0, info->call_data->opnum,
- "Operation: %s (%u)",
- name, info->call_data->opnum);
- }
-
- sub_dissect = (info->ptype == PDU_REQ) ?
- proc->dissect_rqst : proc->dissect_resp;
+ proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
+ 0, 0, info->call_data->opnum,
+ "Operation: %s (%u)",
+ name, info->call_data->opnum);
+
+ if(info->ptype == PDU_REQ && info->call_data->rep_frame!=0) {
+ pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
+ tvb, 0, 0, info->call_data->rep_frame);
+ PROTO_ITEM_SET_GENERATED(pi);
+ }
+ if(info->ptype == PDU_RESP && info->call_data->req_frame!=0) {
+ pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
+ tvb, 0, 0, info->call_data->req_frame);
+ PROTO_ITEM_SET_GENERATED(pi);
+ }
+ } /* tree */
if (decrypted_tvb != NULL) {
/* Either there was no encryption or we successfully decrypted
- the entrypted payload. */
+ the encrypted payload. */
if (sub_dissect) {
/* We have a subdissector - call it. */
saved_proto = pinfo->current_proto;
saved_private_data = pinfo->private_data;
pinfo->current_proto = sub_proto->name;
pinfo->private_data = (void *)info;
-
+
init_ndr_pointer_list(pinfo);
+ length = tvb_length(decrypted_tvb);
+ reported_length = tvb_reported_length(decrypted_tvb);
+
/*
* Remove the authentication padding from the stub data.
*/
if (auth_info != NULL && auth_info->auth_pad_len != 0) {
- length = tvb_length(decrypted_tvb);
- reported_length = tvb_reported_length(decrypted_tvb);
if (reported_length >= auth_info->auth_pad_len) {
/*
* OK, the padding length isn't so big that it
if (length > reported_length)
length = reported_length;
- stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
+ stub_tvb = tvb_new_subset(decrypted_tvb, 0, length, reported_length);
auth_pad_len = auth_info->auth_pad_len;
auth_pad_offset = reported_length;
} else {
stub_tvb = NULL;
auth_pad_len = reported_length;
auth_pad_offset = 0;
+ length = 0;
+ reported_length = 0;
}
} else {
/*
auth_pad_offset = 0;
}
+ if (sub_item) {
+ proto_item_set_len(sub_item, length);
+ }
+
if (stub_tvb != NULL) {
/*
* Catch all exceptions other than BoundsError, so that even
* dissect; just re-throw that exception.
*/
TRY {
- offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
+ int remaining;
+
+ offset = sub_dissect (stub_tvb, 0, pinfo, sub_tree,
drep);
/* If we have a subdissector and it didn't dissect all
data in the tvb, make a note of it. */
-
- if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
+ remaining = tvb_reported_length_remaining(stub_tvb, offset);
+ if (remaining > 0) {
+ proto_tree_add_text(sub_tree, stub_tvb, offset,
+ remaining,
+ "[Long frame (%d byte%s)]",
+ remaining,
+ plurality(remaining, "", "s"));
if (check_col(pinfo->cinfo, COL_INFO))
col_append_fstr(pinfo->cinfo, COL_INFO,
- "[Long frame (%d bytes)]",
- tvb_reported_length_remaining(stub_tvb, offset));
+ "[Long frame (%d byte%s)]",
+ remaining,
+ plurality(remaining, "", "s"));
+
}
} CATCH(BoundsError) {
RETHROW;
} CATCH_ALL {
- show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE);
+ show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
} ENDTRY;
}
/* If there is auth padding at the end of the stub, display it */
if (auth_pad_len != 0) {
+ tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
auth_pad_len,
"Auth Padding (%u byte%s)",
}
static int
-dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
+dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
dcerpc_auth_info *auth_info)
{
dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
hdr, auth_info);
} CATCH_ALL {
- show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
+ show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
} ENDTRY;
} else {
+ tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
"Auth Verifier");
}
volatile int offset;
/*
- * Initially set auth_level and auth_type to zero to indicate that we
+ * Initially set auth_level and auth_type to zero to indicate that we
* haven't yet seen any authentication level information.
*/
auth_info->auth_level = 0;
auth_info->auth_type = 0;
auth_info->auth_size = 0;
auth_info->auth_pad_len = 0;
-
+
/*
* The authentication information is at the *end* of the PDU; in
* request and response PDUs, the request and response stub data
*/
TRY {
offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- hf_dcerpc_auth_type,
+ hf_dcerpc_auth_type,
&auth_info->auth_type);
offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- hf_dcerpc_auth_level,
+ hf_dcerpc_auth_level,
&auth_info->auth_level);
offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- hf_dcerpc_auth_pad_len,
+ hf_dcerpc_auth_pad_len,
&auth_info->auth_pad_len);
offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_auth_rsrvd, NULL);
tvbuff_t *auth_tvb;
dcerpc_auth_subdissector_fns *auth_fns;
- auth_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
- hdr->auth_len);
+ auth_tvb = tvb_new_subset(tvb, offset,
+ MIN(hdr->auth_len,tvb_length_remaining(tvb, offset)),
+ hdr->auth_len);
if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
auth_info->auth_type)))
- dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
+ dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
hdr, auth_info);
else
proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
"Auth Credentials");
}
-
- /* Compute the size of the auth block. Note that this should not
+
+ /* Compute the size of the auth block. Note that this should not
include auth padding, since when NTLMSSP encryption is used, the
padding is actually inside the encrypted stub */
auth_info->auth_size = hdr->auth_len + 8;
} CATCH_ALL {
- show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
+ show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
} ENDTRY;
}
}
/* We need to hash in the SMB fid number to generate a unique hash table
* key as DCERPC over SMB allows several pipes over the same TCP/IP
- * socket.
+ * socket.
* We pass this function the transport type here to make sure we only look
* at this function if it came across an SMB pipe.
* Other transports might need to mix in their own extra multiplexing data
* as well in the future.
*/
-guint16 dcerpc_get_transport_salt (packet_info *pinfo, int transport_type)
+guint16 dcerpc_get_transport_salt (packet_info *pinfo)
{
- dcerpc_private_info *priv = (dcerpc_private_info *)pinfo->private_data;
-
- if (!priv)
- return 0; /* Nothing to see here */
-
- switch(transport_type){
+ switch(pinfo->dcetransporttype){
case DCE_CN_TRANSPORT_SMBPIPE:
/* DCERPC over smb */
- return priv->fid;
+ return pinfo->dcetransportsalt;
}
/* Some other transport... */
*/
static void
-dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
- proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
- int transport_type)
+dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
+ proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
{
conversation_t *conv = NULL;
guint8 num_ctx_items = 0;
guint i;
gboolean saw_ctx_item = FALSE;
guint16 ctx_id;
- guint16 num_trans_items;
+ guint8 num_trans_items;
guint j;
e_uuid_t if_id;
e_uuid_t trans_id;
guint32 trans_ver;
guint16 if_ver, if_ver_minor;
- char uuid_str[DCERPC_UUID_STR_LEN];
- int uuid_str_len;
dcerpc_auth_info auth_info;
-#ifdef _WIN32
- char UUID_NAME[MAX_PATH];
-#endif
+ char *uuid_str;
+ const char *uuid_name = NULL;
+ proto_item *iface_item;
offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_max_xmit, NULL);
offset += 3;
for (i = 0; i < num_ctx_items; i++) {
+ proto_item *ctx_item;
proto_tree *ctx_tree = NULL, *iface_tree = NULL;
+ gint ctx_offset = offset;
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
+ dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
hf_dcerpc_cn_ctx_id, &ctx_id);
+ if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
+ if(pinfo->dcectxid == 0) {
+ col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
+ } else {
+ /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
+ * prepend a delimiter */
+ col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
+ }
+ }
+
/* save context ID for use with dcerpc_add_conv_to_bind_table() */
/* (if we have multiple contexts, this might cause "decode as"
* to behave unpredictably) */
pinfo->dcectxid = ctx_id;
- pinfo->dcetransporttype = transport_type;
if (dcerpc_tree) {
- proto_item *ctx_item;
-
- ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
- tvb, offset - 2, 2,
+ ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
+ tvb, offset, 0,
hdr->drep[0] & 0x10);
-
ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
}
offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree, hdr->drep,
+ hf_dcerpc_cn_ctx_id, &ctx_id);
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
hf_dcerpc_cn_num_trans_items, &num_trans_items);
- /* XXX - use "dissect_ndr_uuid_t()"? */
+ if(dcerpc_tree) {
+ proto_item_append_text(ctx_item, "[%u]: ID:%u", i+1, ctx_id);
+ }
+
+ /* padding */
+ offset += 1;
+
dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
if (ctx_tree) {
- proto_item *iface_item;
-
- uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
- "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- if_id.Data1, if_id.Data2, if_id.Data3,
- if_id.Data4[0], if_id.Data4[1],
- if_id.Data4[2], if_id.Data4[3],
- if_id.Data4[4], if_id.Data4[5],
- if_id.Data4[6], if_id.Data4[7]);
-
- if (uuid_str_len >= DCERPC_UUID_STR_LEN)
- memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
-#ifdef _WIN32
- if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
- iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
- offset, 16, uuid_str, "Interface [%s] UUID: %s", UUID_NAME, uuid_str);
- else
-#endif
- iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
- offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
+
+ iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, FALSE);
iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
+
+ uuid_str = guid_to_str((e_guid_t*)&if_id);
+ uuid_name = guids_get_uuid_name(&if_id);
+ if(uuid_name) {
+ proto_tree_add_guid_format (iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
+ offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
+ proto_item_append_text(iface_item, ": %s", uuid_name);
+ } else {
+ proto_tree_add_guid_format (iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
+ offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
+ proto_item_append_text(iface_item, ": %s", uuid_str);
+ }
}
offset += 16;
hf_dcerpc_cn_bind_if_ver, &if_ver);
}
+ if (ctx_tree) {
+ proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
+ proto_item_set_len(iface_item, 20);
+ }
+
if (!saw_ctx_item) {
- conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
+ conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
if (conv == NULL) {
- conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
+ conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
}
dcerpc_bind_key *key;
dcerpc_bind_value *value;
- key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
+ key = se_alloc (sizeof (dcerpc_bind_key));
key->conv = conv;
key->ctx_id = ctx_id;
- key->smb_fid = dcerpc_get_transport_salt(pinfo, transport_type);
+ key->smb_fid = dcerpc_get_transport_salt(pinfo);
- value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
+ value = se_alloc (sizeof (dcerpc_bind_value));
value->uuid = if_id;
value->ver = if_ver;
}
if (check_col (pinfo->cinfo, COL_INFO)) {
- dcerpc_uuid_key key;
- dcerpc_uuid_value *value;
-
- key.uuid = if_id;
- key.ver = if_ver;
-
if (num_ctx_items > 1)
col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
-
- if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
- col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
- else
-#ifdef _WIN32
- if(ResolveWin32UUID(if_id, UUID_NAME, MAX_PATH))
- col_append_fstr(pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
- UUID_NAME, if_id.Data1, if_id.Data2, if_id.Data3,
- if_id.Data4[0], if_id.Data4[1],
- if_id.Data4[2], if_id.Data4[3],
- if_id.Data4[4], if_id.Data4[5],
- if_id.Data4[6], if_id.Data4[7],
- if_ver, if_ver_minor);
- else
-#endif
- col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
- if_id.Data1, if_id.Data2, if_id.Data3,
- if_id.Data4[0], if_id.Data4[1],
- if_id.Data4[2], if_id.Data4[3],
- if_id.Data4[4], if_id.Data4[5],
- if_id.Data4[6], if_id.Data4[7],
- if_ver, if_ver_minor);
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u",
+ guids_resolve_uuid_to_str(&if_id), if_ver, if_ver_minor);
}
saw_ctx_item = TRUE;
}
for (j = 0; j < num_trans_items; j++) {
- /* XXX - use "dissect_ndr_uuid_t()"? */
+ proto_tree *trans_tree = NULL;
+ proto_item *trans_item = NULL;
+
dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
- if (iface_tree) {
- uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
- "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- trans_id.Data1, trans_id.Data2, trans_id.Data3,
- trans_id.Data4[0], trans_id.Data4[1],
- trans_id.Data4[2], trans_id.Data4[3],
- trans_id.Data4[4], trans_id.Data4[5],
- trans_id.Data4[6], trans_id.Data4[7]);
- if (uuid_str_len >= DCERPC_UUID_STR_LEN)
- memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
- proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
- offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
+ if (ctx_tree) {
+
+ trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, FALSE);
+ trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
+
+ uuid_str = guid_to_str((e_guid_t *) &trans_id);
+ proto_tree_add_guid_format (trans_tree, hf_dcerpc_cn_bind_trans_id, tvb,
+ offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s", uuid_str);
+ proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
}
offset += 16;
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, trans_tree, hdr->drep,
hf_dcerpc_cn_bind_trans_ver, &trans_ver);
+ if (ctx_tree) {
+ proto_item_set_len(trans_item, 20);
+ proto_item_append_text(trans_item, " V%u", trans_ver);
+ }
+ }
+
+ if(ctx_tree) {
+ proto_item_set_len(ctx_item, offset - ctx_offset);
}
}
}
static void
-dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
+dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
{
guint16 max_xmit, max_recv;
guint16 reason;
e_uuid_t trans_id;
guint32 trans_ver;
- char uuid_str[DCERPC_UUID_STR_LEN];
- int uuid_str_len;
dcerpc_auth_info auth_info;
offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
if (sec_addr_len != 0) {
+ tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
sec_addr_len, FALSE);
offset += sec_addr_len;
offset += 3;
for (i = 0; i < num_results; i++) {
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
+ proto_tree *ctx_tree = NULL;
+
+ if(dcerpc_tree){
+ proto_item *ctx_item;
+ ctx_item = proto_tree_add_text(dcerpc_tree, tvb, offset, 24, "Context ID[%u]", i+1);
+ ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
+ }
+
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
hdr->drep, hf_dcerpc_cn_ack_result,
&result);
if (result != 0) {
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
hdr->drep, hf_dcerpc_cn_ack_reason,
&reason);
} else {
offset += 2;
}
- /* XXX - use "dissect_ndr_uuid_t()"? */
dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
- if (dcerpc_tree) {
- uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
- "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- trans_id.Data1, trans_id.Data2, trans_id.Data3,
- trans_id.Data4[0], trans_id.Data4[1],
- trans_id.Data4[2], trans_id.Data4[3],
- trans_id.Data4[4], trans_id.Data4[5],
- trans_id.Data4[6], trans_id.Data4[7]);
- if (uuid_str_len >= DCERPC_UUID_STR_LEN)
- memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
- proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
- offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
+ if (ctx_tree) {
+ proto_tree_add_guid_format (ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
+ offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
+ guid_to_str((e_guid_t *) &trans_id));
}
offset += 16;
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, ctx_tree, hdr->drep,
hf_dcerpc_cn_ack_trans_ver, &trans_ver);
}
}
static void
-dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
+dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
{
guint16 reason;
#define PFC_FRAG_MASK 0x03
-static char *
+static const char *
fragment_type(guint8 flags)
{
flags = flags & PFC_FRAG_MASK;
dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *dcerpc_tree, proto_tree *tree,
e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
- dcerpc_auth_info *auth_info, guint32 alloc_hint,
+ dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
guint32 frame)
{
gint length, reported_length;
gboolean save_fragmented;
fragment_data *fd_head=NULL;
- guint32 tot_len;
- tvbuff_t *payload_tvb, *decrypted_tvb;
+
+ tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
proto_item *pi;
+ proto_item *parent_pi;
+ proto_item *dcerpc_tree_item;
save_fragmented = pinfo->fragmented;
length = reported_length;
payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
+ auth_tvb=NULL;
+ /*dont bother if we dont have the entire tvb */
+ /*XXX we should really make sure we calculate auth_info->auth_data
+ and use that one instead of this auth_tvb hack
+ */
+ if(tvb_length(tvb)==tvb_reported_length(tvb)){
+ if(tvb_length_remaining(tvb, offset+length)>8){
+ auth_tvb = tvb_new_subset(tvb, offset+length+8, -1, -1);
+ }
+ }
+
/* Decrypt the PDU if it is encrypted */
if (auth_info->auth_type &&
* encrypted; attempt to decrypt it.
*/
dcerpc_auth_subdissector_fns *auth_fns;
-
+
/* Start out assuming we won't succeed in decrypting. */
decrypted_tvb = NULL;
if ((auth_fns = get_auth_subdissector_fns(
auth_info->auth_level, auth_info->auth_type))) {
tvbuff_t *result;
-
+
result = decode_encrypted_data(
- payload_tvb, pinfo, auth_fns,
- hdr->ptype == PDU_REQ, auth_info);
-
+ payload_tvb, auth_tvb, pinfo, auth_fns,
+ hdr->ptype == PDU_REQ, auth_info);
+
if (result) {
if (dcerpc_tree)
proto_tree_add_text(
add_new_data_source(
pinfo, result, "Decrypted stub data");
-
+
/* We succeeded. */
decrypted_tvb = result;
}
dcerpc_try_handoff(
pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
hdr->drep, di, auth_info);
-
+
pinfo->fragmented = save_fragmented;
return;
}
/* The packet is fragmented. */
pinfo->fragmented = TRUE;
+ /* debug output of essential fragment data. */
+ /* leave it here for future debugging sessions */
+ /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
+ pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
+
/* if we are not doing reassembly and this is the first fragment
then just dissect it and exit
XXX - if we're not doing reassembly, can we decrypt an
dcerpc_try_handoff(
pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
hdr->drep, di, auth_info);
-
+
if (check_col(pinfo->cinfo, COL_INFO)) {
col_append_fstr(pinfo->cinfo, COL_INFO,
" [DCE/RPC %s fragment]", fragment_type(hdr->flags));
}
+ expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
+ "%s fragment", fragment_type(hdr->flags));
pinfo->fragmented = save_fragmented;
return;
}
/* if we have already seen this packet, see if it was reassembled
and if so dissect the full pdu.
- then exit
+ then exit
*/
if(pinfo->fd->flags.visited){
- fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
+ fd_head=fragment_get_reassembled(pinfo, frame, dcerpc_co_reassemble_table);
goto end_cn_stub;
}
nor the first fragment then there is nothing more we can do
so we just have to exit
*/
- if( !dcerpc_reassemble )
+ if( !dcerpc_reassemble || (tvb_length(tvb)!=tvb_reported_length(tvb)) )
goto end_cn_stub;
/* if we didnt get 'frame' we dont know where the PDU started and thus
- it is pointless to continue
+ it is pointless to continue
*/
if(!frame)
goto end_cn_stub;
- /* from now on we must attempt to reassemble the PDU
+ /* from now on we must attempt to reassemble the PDU
*/
/* if we get here we know it is the first time we see the packet
goto end_cn_stub;
}
- /* if this is the first fragment we need to start reassembly
- */
- if(hdr->flags&PFC_FIRST_FRAG){
- fragment_add(decrypted_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
- 0, tvb_length(decrypted_tvb), TRUE);
- fragment_set_tot_len(pinfo, frame,
- dcerpc_co_reassemble_table, alloc_hint);
-
- goto end_cn_stub;
- }
-
- /* if this is a middle fragment, just add it and exit */
- if(!(hdr->flags&PFC_LAST_FRAG)){
- tot_len = fragment_get_tot_len(pinfo, frame,
- dcerpc_co_reassemble_table);
- fragment_add(decrypted_tvb, 0, pinfo, frame,
- dcerpc_co_reassemble_table,
- tot_len-alloc_hint, tvb_length(decrypted_tvb),
- TRUE);
-
- goto end_cn_stub;
- }
-
- /* this was the last fragment add it to reassembly
- */
- tot_len = fragment_get_tot_len(pinfo, frame,
- dcerpc_co_reassemble_table);
- fd_head = fragment_add(decrypted_tvb, 0, pinfo,
- frame,
- dcerpc_co_reassemble_table,
- tot_len-alloc_hint, tvb_length(decrypted_tvb),
- TRUE);
+ /* defragmentation is a bit tricky, as there's no offset of the fragment
+ * in the protocol data.
+ *
+ * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
+ * in with the correct sequence.
+ */
+ fd_head = fragment_add_seq_next(decrypted_tvb, 0, pinfo, frame,
+ dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
+ tvb_length(decrypted_tvb),
+ hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
end_cn_stub:
- /* if reassembly is complete, dissect the full PDU
- */
+ /* if reassembly is complete and this is the last fragment
+ * (multiple fragments in one PDU are possible!)
+ * dissect the full PDU
+ */
if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
- if(pinfo->fd->num==fd_head->reassembled_in){
+ if(pinfo->fd->num==fd_head->reassembled_in && (hdr->flags&PFC_LAST_FRAG) ){
tvbuff_t *next_tvb;
+ proto_item *frag_tree_item;
- next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
- tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
+ next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
+ if(decrypted_tvb){
+ tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
+ } else {
+ tvb_set_child_real_data_tvbuff(payload_tvb, next_tvb);
+ }
add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
show_fragment_tree(fd_head, &dcerpc_frag_items,
- dcerpc_tree, pinfo, next_tvb);
+ tree, pinfo, next_tvb, &frag_tree_item);
+ /* the toplevel fragment subtree is now behind all desegmented data,
+ * move it right behind the DCE/RPC tree */
+ dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
+ if(frag_tree_item && dcerpc_tree_item) {
+ proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
+ }
pinfo->fragmented = FALSE;
+ expert_add_info_format(pinfo, frag_tree_item, PI_REASSEMBLE, PI_CHAT,
+ "%s fragment, reassembled",
+ fragment_type(hdr->flags));
+
dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
next_tvb, hdr->drep, di, auth_info);
} else {
- pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
+ if(decrypted_tvb){
+ pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
decrypted_tvb, 0, 0, fd_head->reassembled_in);
+ } else {
+ pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
+ payload_tvb, 0, 0, fd_head->reassembled_in);
+ }
PROTO_ITEM_SET_GENERATED(pi);
+ parent_pi = proto_tree_get_parent(dcerpc_tree);
+ if(parent_pi != NULL) {
+ proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
+ }
if (check_col(pinfo->cinfo, COL_INFO)) {
col_append_fstr(pinfo->cinfo, COL_INFO,
" [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
}
+ expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
+ "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
}
} else {
/* Reassembly not complete - some fragments
are missing. Just show the stub data. */
-
if (check_col(pinfo->cinfo, COL_INFO)) {
col_append_fstr(pinfo->cinfo, COL_INFO,
" [DCE/RPC %s fragment]", fragment_type(hdr->flags));
}
+ expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
+ "%s fragment", fragment_type(hdr->flags));
if(decrypted_tvb){
show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
* Registers a conversation/UUID binding association, so that
* we can invoke the proper sub-dissector for a given DCERPC
* conversation.
- *
+ *
* @param binding all values needed to create and bind a new conversation
- *
+ *
* @return Pointer to newly-added UUID/conversation binding.
*/
struct _dcerpc_bind_value *
conversation_t *conv;
conv = find_conversation (
- &binding->addr_a,
- &binding->addr_b,
- binding->ptype,
- binding->port_a,
- binding->port_b,
+ 0,
+ &binding->addr_a,
+ &binding->addr_b,
+ binding->ptype,
+ binding->port_a,
+ binding->port_b,
0);
-
+
if (!conv) {
conv = conversation_new (
- &binding->addr_a,
- &binding->addr_b,
- binding->ptype,
- binding->port_a,
- binding->port_b,
+ 0,
+ &binding->addr_a,
+ &binding->addr_b,
+ binding->ptype,
+ binding->port_a,
+ binding->port_b,
0);
}
- bind_value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
+ bind_value = se_alloc (sizeof (dcerpc_bind_value));
bind_value->uuid = binding->uuid;
bind_value->ver = binding->ver;
- key = g_mem_chunk_alloc(dcerpc_bind_key_chunk);
+ key = se_alloc(sizeof (dcerpc_bind_key));
key->conv = conv;
key->ctx_id = binding->ctx_id;
key->smb_fid = binding->smb_fid;
-
+
/* add this entry to the bind table, first removing any
previous ones that are identical
*/
}
static void
-dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
+dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *dcerpc_tree, proto_tree *tree,
- e_dce_cn_common_hdr_t *hdr, int transport_type)
+ e_dce_cn_common_hdr_t *hdr)
{
conversation_t *conv;
guint16 ctx_id;
guint16 opnum;
- e_uuid_t obj_id;
+ e_uuid_t obj_id = DCERPC_UUID_NULL;
dcerpc_auth_info auth_info;
guint32 alloc_hint;
- char uuid_str[DCERPC_UUID_STR_LEN];
- int uuid_str_len;
proto_item *pi;
+ proto_item *parent_pi;
offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_alloc_hint, &alloc_hint);
offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_ctx_id, &ctx_id);
+ parent_pi = proto_tree_get_parent(dcerpc_tree);
+ if(parent_pi != NULL) {
+ proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
+ }
+
+ if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
+ if(pinfo->dcectxid == 0) {
+ col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
+ } else {
+ /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
+ * prepend a delimiter */
+ col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
+ }
+ }
offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_opnum, &opnum);
/* save context ID for use with dcerpc_add_conv_to_bind_table() */
pinfo->dcectxid = ctx_id;
- pinfo->dcetransporttype = transport_type;
if (check_col (pinfo->cinfo, COL_INFO)) {
col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
}
if (hdr->flags & PFC_OBJECT_UUID) {
- /* XXX - use "dissect_ndr_uuid_t()"? */
dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
if (dcerpc_tree) {
- uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
- "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- obj_id.Data1, obj_id.Data2, obj_id.Data3,
- obj_id.Data4[0],
- obj_id.Data4[1],
- obj_id.Data4[2],
- obj_id.Data4[3],
- obj_id.Data4[4],
- obj_id.Data4[5],
- obj_id.Data4[6],
- obj_id.Data4[7]);
- if (uuid_str_len >= DCERPC_UUID_STR_LEN)
- memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
- proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
- offset, 16, uuid_str, "Object UUID: %s", uuid_str);
+ proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
+ offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
+ guid_to_str((e_guid_t *) &obj_id));
}
offset += 16;
}
*/
dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
- conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
+ conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
if (!conv)
show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
bind_key.conv=conv;
bind_key.ctx_id=ctx_id;
- bind_key.smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
+ bind_key.smb_fid=dcerpc_get_transport_salt(pinfo);
if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
if(!(hdr->flags&PFC_FIRST_FRAG)){
call_key.conv=conv;
call_key.call_id=hdr->call_id;
- call_key.smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
+ call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
- new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
+ new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
*new_matched_key = matched_key;
g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
value = call_value;
dcerpc_cn_call_key *call_key;
dcerpc_call_value *call_value;
- /* We found the binding and it is the first fragment
- (or a complete PDU) of a dcerpc pdu so just add
- the call to both the call table and the
+ /* We found the binding and it is the first fragment
+ (or a complete PDU) of a dcerpc pdu so just add
+ the call to both the call table and the
matched table
*/
- call_key=g_mem_chunk_alloc (dcerpc_cn_call_key_chunk);
+ call_key=se_alloc (sizeof (dcerpc_cn_call_key));
call_key->conv=conv;
call_key->call_id=hdr->call_id;
- call_key->smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
+ call_key->smb_fid=dcerpc_get_transport_salt(pinfo);
/* if there is already a matching call in the table
remove it so it is replaced with the new one */
g_hash_table_remove(dcerpc_cn_calls, call_key);
}
- call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
+ call_value=se_alloc (sizeof (dcerpc_call_value));
call_value->uuid = bind_value->uuid;
call_value->ver = bind_value->ver;
+ call_value->object_uuid = obj_id;
call_value->opnum = opnum;
call_value->req_frame=pinfo->fd->num;
- call_value->req_time.secs=pinfo->fd->abs_secs;
- call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
+ call_value->req_time=pinfo->fd->abs_ts;
call_value->rep_frame=0;
call_value->max_ptr=0;
+ call_value->se_data = NULL;
call_value->private_data = NULL;
g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
- new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
+ new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
*new_matched_key = matched_key;
g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
value = call_value;
/* handoff this call */
di->conv = conv;
di->call_id = hdr->call_id;
- di->smb_fid = dcerpc_get_transport_salt(pinfo, transport_type);
+ di->smb_fid = dcerpc_get_transport_salt(pinfo);
di->ptype = PDU_REQ;
di->call_data = value;
di->hf_index = -1;
pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
tvb, 0, 0, value->rep_frame);
PROTO_ITEM_SET_GENERATED(pi);
+ if(parent_pi != NULL) {
+ proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
+ }
}
dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
hdr, di, &auth_info, alloc_hint,
value->req_frame);
- } else
+ } else {
+ /* no bind information, simply show stub data */
+ pi = proto_tree_add_text(dcerpc_tree, tvb, offset, 0, "No bind info for this interface Context ID - capture start too late?");
+ PROTO_ITEM_SET_GENERATED(pi);
+ expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u",
+ ctx_id);
show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
+ }
}
/* Dissect the verifier */
static void
dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *dcerpc_tree, proto_tree *tree,
- e_dce_cn_common_hdr_t *hdr, int transport_type)
+ e_dce_cn_common_hdr_t *hdr)
{
dcerpc_call_value *value = NULL;
conversation_t *conv;
dcerpc_auth_info auth_info;
guint32 alloc_hint;
proto_item *pi;
+ proto_item *parent_pi;
+ e_uuid_t obj_id_null = DCERPC_UUID_NULL;
offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_alloc_hint, &alloc_hint);
offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_ctx_id, &ctx_id);
+ parent_pi = proto_tree_get_parent(dcerpc_tree);
+ if(parent_pi != NULL) {
+ proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
+ }
+
+ if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
+ if(pinfo->dcectxid == 0) {
+ col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
+ } else {
+ /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
+ * prepend a delimiter */
+ col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
+ }
+ }
+
/* save context ID for use with dcerpc_add_conv_to_bind_table() */
pinfo->dcectxid = ctx_id;
- pinfo->dcetransporttype = transport_type;
if (check_col (pinfo->cinfo, COL_INFO)) {
col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
*/
dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
- conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
+ conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
if (!conv) {
call_key.conv=conv;
call_key.call_id=hdr->call_id;
- call_key.smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
+ call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
- new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
- *new_matched_key = matched_key;
- g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
- value = call_value;
- if(call_value->rep_frame==0){
- call_value->rep_frame=pinfo->fd->num;
+ /* extra sanity check, only match them if the reply
+ came after the request */
+ if(call_value->req_frame<pinfo->fd->num){
+ new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
+ *new_matched_key = matched_key;
+ g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
+ value = call_value;
+ if(call_value->rep_frame==0){
+ call_value->rep_frame=pinfo->fd->num;
+ }
}
}
}
/* handoff this call */
di->conv = conv;
di->call_id = hdr->call_id;
- di->smb_fid = dcerpc_get_transport_salt(pinfo, transport_type);
+ di->smb_fid = dcerpc_get_transport_salt(pinfo);
di->ptype = PDU_RESP;
di->call_data = value;
proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
+
+ /* (optional) "Object UUID" from request */
+ if (value && dcerpc_tree && memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0) {
+ pi = proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
+ offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
+ guid_to_str((e_guid_t *) &value->object_uuid));
+ PROTO_ITEM_SET_GENERATED(pi);
+ }
+
+ /* request in */
if(value->req_frame!=0){
- nstime_t ns;
+ nstime_t delta_ts;
pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
tvb, 0, 0, value->req_frame);
PROTO_ITEM_SET_GENERATED(pi);
- ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
- ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
- if(ns.nsecs<0){
- ns.nsecs+=1000000000;
- ns.secs--;
- }
- pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
+ if(parent_pi != NULL) {
+ proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
+ }
+ nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
+ pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
PROTO_ITEM_SET_GENERATED(pi);
+ } else {
+ pi = proto_tree_add_text(dcerpc_tree,
+ tvb, 0, 0, "No request to this DCE/RPC call found");
+ expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
+ "No request to this DCE/RPC call found");
}
dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
hdr, di, &auth_info, alloc_hint,
value->rep_frame);
- } else
+ } else {
+ /* no bind information, simply show stub data */
+ pi = proto_tree_add_text(dcerpc_tree, tvb, offset, 0, "No bind info for this interface Context ID - capture start too late?");
+ PROTO_ITEM_SET_GENERATED(pi);
+ expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u",
+ ctx_id);
show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
+ }
}
/* Dissect the verifier */
static void
dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
- proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
- int transport_type)
+ proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
{
dcerpc_call_value *value = NULL;
conversation_t *conv;
guint32 status;
guint32 alloc_hint;
dcerpc_auth_info auth_info;
- proto_item *pi;
+ proto_item *pi = NULL;
offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_alloc_hint, &alloc_hint);
offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_ctx_id, &ctx_id);
+ if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
+ if(pinfo->dcectxid == 0) {
+ col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
+ } else {
+ /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
+ * prepend a delimiter */
+ col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
+ }
+ }
+
offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_cancel_count, NULL);
/* padding */
offset++;
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- hf_dcerpc_cn_status, &status);
+ /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ hf_dcerpc_cn_status, &status);*/
+ status = ((hdr->drep[0] & 0x10)
+ ? tvb_get_letohl (tvb, offset)
+ : tvb_get_ntohl (tvb, offset));
+
+ if (dcerpc_tree) {
+ pi = proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, (hdr->drep[0] & 0x10));
+ }
+ offset+=4;
+
+ expert_add_info_format(pinfo, pi, PI_RESPONSE_CODE, PI_NOTE, "Fault: %s",
+ val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
/* save context ID for use with dcerpc_add_conv_to_bind_table() */
pinfo->dcectxid = ctx_id;
- pinfo->dcetransporttype = transport_type;
if (check_col (pinfo->cinfo, COL_INFO)) {
col_append_fstr (pinfo->cinfo, COL_INFO,
*/
dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
- conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
+ conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
if (!conv) {
/* no point in creating one here, really */
call_key.conv=conv;
call_key.call_id=hdr->call_id;
- call_key.smb_fid=dcerpc_get_transport_salt(pinfo, transport_type);
+ call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
- new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
+ new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
*new_matched_key = matched_key;
g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
value = call_value;
if (value) {
int length, reported_length, stub_length;
dcerpc_info *di;
+ proto_item *parent_pi;
di=get_next_di();
/* handoff this call */
di->conv = conv;
di->call_id = hdr->call_id;
- di->smb_fid = dcerpc_get_transport_salt(pinfo, transport_type);
+ di->smb_fid = dcerpc_get_transport_salt(pinfo);
di->ptype = PDU_FAULT;
di->call_data = value;
proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
if(value->req_frame!=0){
- nstime_t ns;
+ nstime_t delta_ts;
pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
tvb, 0, 0, value->req_frame);
PROTO_ITEM_SET_GENERATED(pi);
- ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
- ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
- if(ns.nsecs<0){
- ns.nsecs+=1000000000;
- ns.secs--;
- }
- pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
+ parent_pi = proto_tree_get_parent(dcerpc_tree);
+ if(parent_pi != NULL) {
+ proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
+ }
+ nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
+ pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
PROTO_ITEM_SET_GENERATED(pi);
+ } else {
+ pi = proto_tree_add_text(dcerpc_tree,
+ tvb, 0, 0, "No request to this DCE/RPC call found");
+ expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
+ "No request to this DCE/RPC call found");
}
length = tvb_length_remaining(tvb, offset);
reported_length = tvb_reported_length_remaining(tvb, offset);
- stub_length = hdr->frag_len - offset - auth_info.auth_size;
+ /* as we now create a tvb in dissect_dcerpc_cn() containing only the
+ * stub_data, the following calculation is no longer valid:
+ * stub_length = hdr->frag_len - offset - auth_info.auth_size;
+ * simply use the remaining length of the tvb instead.
+ * XXX - or better use the reported_length?!?
+ */
+ stub_length = length;
if (length > stub_length)
length = stub_length;
if (reported_length > stub_length)
*/
if (dcerpc_tree) {
if (stub_length > 0) {
+ tvb_ensure_bytes_exist(tvb, offset, stub_length);
proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
"Fault stub data (%d byte%s)",
stub_length,
}
if (dcerpc_tree) {
if (stub_length > 0) {
+ tvb_ensure_bytes_exist(tvb, offset, stub_length);
proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
"Fragment data (%d byte%s)",
stub_length,
third means we can attempt reassembly. */
if (dcerpc_tree) {
if (length > 0) {
+ tvb_ensure_bytes_exist(tvb, offset, stub_length);
proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
"Fragment data (%d byte%s)",
stub_length,
}
if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
if( (!pinfo->fd->flags.visited) && value->rep_frame ){
- fragment_add(tvb, offset, pinfo, value->rep_frame,
- dcerpc_co_reassemble_table,
- 0,
+ fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
+ dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
stub_length,
TRUE);
- fragment_set_tot_len(pinfo, value->rep_frame,
- dcerpc_co_reassemble_table, alloc_hint);
}
if (check_col(pinfo->cinfo, COL_INFO)) {
col_append_fstr(pinfo->cinfo, COL_INFO,
} else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
if( value->rep_frame ){
fragment_data *fd_head;
- guint32 tot_len;
- tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
- dcerpc_co_reassemble_table);
- fd_head = fragment_add(tvb, offset, pinfo,
+ fd_head = fragment_add_seq_next(tvb, offset, pinfo,
value->rep_frame,
- dcerpc_co_reassemble_table,
- tot_len-alloc_hint,
+ dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
stub_length,
TRUE);
if(fd_head){
/* We completed reassembly */
tvbuff_t *next_tvb;
+ proto_item *frag_tree_item;
- next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
+ next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
tvb_set_child_real_data_tvbuff(tvb, next_tvb);
add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
show_fragment_tree(fd_head, &dcerpc_frag_items,
- dcerpc_tree, pinfo, next_tvb);
+ dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
/*
* XXX - should there be a third routine for each
*/
if (dcerpc_tree) {
if (length > 0) {
+ tvb_ensure_bytes_exist(tvb, offset, stub_length);
proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
"Fault stub data (%d byte%s)",
stub_length,
}
} else { /* MIDDLE fragment(s) */
if( (!pinfo->fd->flags.visited) && value->rep_frame ){
- guint32 tot_len;
- tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
- dcerpc_co_reassemble_table);
- fragment_add(tvb, offset, pinfo, value->rep_frame,
- dcerpc_co_reassemble_table,
- tot_len-alloc_hint,
+ fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
+ dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
stub_length,
TRUE);
}
*/
static gboolean
dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
- proto_tree *tree, gboolean can_desegment, int *pkt_len,
- int transport_type)
+ proto_tree *tree, gboolean can_desegment, int *pkt_len)
{
static const guint8 nulls[4] = { 0 };
int start_offset;
proto_tree *drep_tree = NULL;
e_dce_cn_common_hdr_t hdr;
dcerpc_auth_info auth_info;
+ tvbuff_t *fragment_tvb;
/*
* when done over nbt, dcerpc requests are padded with 4 bytes of null
offset += 4;
padding += 4;
}
-
/*
* Check if this looks like a C/O DCERPC call
*/
hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
offset += 4;
+ if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
+ if(pinfo->dcectxid == 0) {
+ col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
+ } else {
+ /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
+ * prepend a delimiter */
+ col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
+ }
+ }
+
if (can_desegment && pinfo->can_desegment
&& !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
pinfo->desegment_offset = start_offset;
if (check_col (pinfo->cinfo, COL_PROTOCOL))
col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
- if (check_col (pinfo->cinfo, COL_INFO))
+
+ if (check_col (pinfo->cinfo, COL_INFO)) {
+ if(pinfo->dcectxid != 0) {
+ /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
+ * append a delimiter and set a column fence */
+ col_append_str (pinfo->cinfo, COL_INFO, " # ");
+ col_set_fence(pinfo->cinfo,COL_INFO);
+ }
col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
- pckt_vals[hdr.ptype].strptr, hdr.call_id);
+ pckt_vals[hdr.ptype].strptr, hdr.call_id);
+ }
+
+ if(pinfo->dcectxid != 0) {
+ /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
+ expert_add_info_format(pinfo, NULL, PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet");
+ }
+ offset = start_offset;
+ tvb_ensure_bytes_exist(tvb, offset, 16);
if (tree) {
- offset = start_offset;
ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
- if (ti) {
- dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
- }
- proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
- proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
- proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
+ dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
+ }
+
+ proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
+ offset++;
+
+ proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
+ offset++;
+
+ tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
+ offset++;
+
+ /* XXX - too much "output noise", removed for now
+ if(hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
+ hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
+ expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_CHAT, "Context change: %s",
+ val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));*/
+ if(hdr.ptype == PDU_BIND_NAK)
+ expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_WARN, "Bind not acknowledged");
+
+ if (tree) {
+ proto_item_append_text(ti, " %s, Fragment:", val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"));
+
tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
- if (cn_flags_tree) {
- proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
+ }
+ proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
+ proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
+ proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
+ proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
+ proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
+ proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
+ proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
+ proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
+ if( (hdr.flags & PFC_FIRST_FRAG) && (hdr.flags & PFC_LAST_FRAG) ) {
+ proto_item_append_text(ti, " Single");
+ } else {
+ if(hdr.flags & PFC_FIRST_FRAG) {
+ proto_item_append_text(ti, " 1st");
+ }
+ if(hdr.flags & PFC_LAST_FRAG) {
+ proto_item_append_text(ti, " Last");
}
- offset++;
+ if( !(hdr.flags & PFC_FIRST_FRAG) && !(hdr.flags & PFC_LAST_FRAG) ) {
+ proto_item_append_text(ti, " Mid");
+ }
+ }
+ offset++;
+ if(dcerpc_tree){
tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
- if (drep_tree) {
- proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
- proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
- proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
- }
- offset += sizeof (hdr.drep);
+ }
+ proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
+ proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
+ proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
+ offset += sizeof (hdr.drep);
+
+ proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
+ offset += 2;
- proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
- offset += 2;
+ proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
+ offset += 2;
- proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
- offset += 2;
+ proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
+ offset += 4;
- proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
- offset += 4;
+ if(ti){
+ proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
}
/*
if (pkt_len != NULL)
*pkt_len = hdr.frag_len + padding;
+ /* The remaining bytes in the current tvb might contain multiple
+ * DCE/RPC fragments, so create a new tvb subset for this fragment.
+ * Only limit the end of the fragment, but not the offset start,
+ * as the authentication function dissect_dcerpc_cn_auth() will fail
+ * (and other functions might fail as well) computing the right start
+ * offset otherwise.
+ */
+ fragment_tvb = tvb_new_subset(tvb, 0,
+ MIN((hdr.frag_len + (guint) start_offset), tvb_length(tvb)) /* length */,
+ hdr.frag_len + start_offset /* reported_length */);
+
/*
* Packet type specific stuff is next.
*/
switch (hdr.ptype) {
case PDU_BIND:
case PDU_ALTER:
- dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr, transport_type);
+ dissect_dcerpc_cn_bind (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
break;
case PDU_BIND_ACK:
case PDU_ALTER_ACK:
- dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
+ dissect_dcerpc_cn_bind_ack (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
break;
case PDU_AUTH3:
/*
* Nothing after the common header other than credentials.
*/
- dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
+ dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
&auth_info);
break;
case PDU_REQ:
- dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, transport_type);
+ dissect_dcerpc_cn_rqst (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
break;
case PDU_RESP:
- dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, transport_type);
+ dissect_dcerpc_cn_resp (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
break;
case PDU_FAULT:
- dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr, transport_type);
+ dissect_dcerpc_cn_fault (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
break;
case PDU_BIND_NAK:
- dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
+ dissect_dcerpc_cn_bind_nak (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
break;
case PDU_CO_CANCEL:
* Nothing after the common header other than an authentication
* verifier.
*/
- dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
+ dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
&auth_info);
break;
default:
/* might as well dissect the auth info */
- dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
+ dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
&auth_info);
break;
}
* Only one PDU per transport packet, and only one transport
* packet per PDU.
*/
- if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL, DCE_TRANSPORT_UNKNOWN)) {
+ pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
+ if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
/*
* It wasn't a DCERPC PDU.
*/
* to be able to know what kind of private_data structure to expect.
*/
static gboolean
-dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int transport_type)
+dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
volatile int offset = 0;
int pdu_len;
- volatile gboolean is_dcerpc_pdu;
+ volatile gboolean dcerpc_pdus = 0;
volatile gboolean ret = FALSE;
/*
* snapshot length, so there's nothing more to dissect; just
* re-throw that exception.
*/
- is_dcerpc_pdu = FALSE;
TRY {
- is_dcerpc_pdu = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
- dcerpc_cn_desegment, &pdu_len,
- transport_type);
+ pdu_len = 0;
+ if(dissect_dcerpc_cn (tvb, offset, pinfo, tree,
+ dcerpc_cn_desegment, &pdu_len)) {
+ dcerpc_pdus++;
+ }
} CATCH(BoundsError) {
RETHROW;
} CATCH(ReportedBoundsError) {
show_reported_bounds_error(tvb, pinfo, tree);
+ /*
+ * Presumably it looked enough like a DCE RPC PDU that we
+ * dissected enough of it to throw an exception.
+ */
+ dcerpc_pdus++;
} ENDTRY;
- if (!is_dcerpc_pdu) {
+ if (!dcerpc_pdus) {
/*
* Not a DCERPC PDU.
*/
*/
ret = TRUE;
+ /* if we had more than one Req/Resp in this PDU change the protocol column */
+ /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
+ if (dcerpc_pdus >= 2 && check_col (pinfo->cinfo, COL_PROTOCOL))
+ col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
+
if (pdu_len == 0) {
/*
- * Desegmentation required - bail now.
+ * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
*/
+ proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
+ 0,
+ tvb_reported_length_remaining(tvb, offset),
+ "[DCE RPC: %u byte%s left, desegmentation might follow]",
+ tvb_reported_length_remaining(tvb, offset),
+ plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
break;
}
static gboolean
dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree, DCE_TRANSPORT_UNKNOWN);
+ pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
+ return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
}
static gboolean
dissect_dcerpc_cn_smbpipe (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree, DCE_CN_TRANSPORT_SMBPIPE);
+ pinfo->dcetransporttype=DCE_CN_TRANSPORT_SMBPIPE;
+ return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
+}
+
+static gboolean
+dissect_dcerpc_cn_smb2 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
+ return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
}
fragment_data *fd_head;
tvbuff_t *next_tvb;
proto_item *pi;
+ proto_item *parent_pi;
if (check_col (pinfo->cinfo, COL_INFO))
- col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
+ col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
di->call_data->opnum, hdr->frag_len );
length = tvb_length_remaining (tvb, offset);
}
if (dcerpc_tree) {
if (length > 0) {
+ tvb_ensure_bytes_exist(tvb, offset, stub_length);
proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
"Fragment data (%d byte%s)",
stub_length,
third means we can attempt reassembly. */
if (dcerpc_tree) {
if (length > 0) {
+ tvb_ensure_bytes_exist(tvb, offset, stub_length);
proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
"Fragment data (%d byte%s)", stub_length,
plurality(stub_length, "", "s"));
}
}
- fd_head = fragment_add_dcerpc(tvb, offset, pinfo,
+ fd_head = fragment_add_dcerpc_dg(tvb, offset, pinfo,
hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table,
hdr->frag_num, stub_length,
!(hdr->flags1 & PFCL1_LASTFRAG));
- if (fd_head != NULL) {
+ if (fd_head != NULL) {
/* We completed reassembly... */
if(pinfo->fd->num==fd_head->reassembled_in) {
/* ...and this is the reassembled RPC PDU */
- next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
- tvb_set_child_real_data_tvbuff(tvb, next_tvb);
- add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
- show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
- dcerpc_tree, pinfo, next_tvb);
-
- /*
- * XXX - authentication info?
- */
- pinfo->fragmented = FALSE;
- dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
- next_tvb, hdr->drep, di, NULL);
- } else {
+ next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
+ tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+ add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
+ show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
+ tree, pinfo, next_tvb, &pi);
+
+ /*
+ * XXX - authentication info?
+ */
+ pinfo->fragmented = FALSE;
+ dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
+ next_tvb, hdr->drep, di, NULL);
+ } else {
/* ...and this isn't the reassembled RPC PDU */
pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
tvb, 0, 0, fd_head->reassembled_in);
PROTO_ITEM_SET_GENERATED(pi);
+ parent_pi = proto_tree_get_parent(dcerpc_tree);
+ if(parent_pi != NULL) {
+ proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
+ }
if (check_col(pinfo->cinfo, COL_INFO)) {
col_append_fstr(pinfo->cinfo, COL_INFO,
" [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
dcerpc_call_value *value, v;
dcerpc_matched_key matched_key, *new_matched_key;
proto_item *pi;
+ proto_item *parent_pi;
di=get_next_di();
if(!(pinfo->fd->flags.visited)){
dcerpc_call_value *call_value;
dcerpc_dg_call_key *call_key;
- call_key=g_mem_chunk_alloc (dcerpc_dg_call_key_chunk);
+ call_key=se_alloc (sizeof (dcerpc_dg_call_key));
call_key->conv=conv;
call_key->seqnum=hdr->seqnum;
call_key->act_id=hdr->act_id;
- call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
+ call_value=se_alloc (sizeof (dcerpc_call_value));
call_value->uuid = hdr->if_id;
call_value->ver = hdr->if_ver;
+ call_value->object_uuid = hdr->obj_id;
call_value->opnum = hdr->opnum;
call_value->req_frame=pinfo->fd->num;
- call_value->req_time.secs=pinfo->fd->abs_secs;
- call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
+ call_value->req_time=pinfo->fd->abs_ts;
call_value->rep_frame=0;
call_value->max_ptr=0;
+ call_value->se_data = NULL;
call_value->private_data = NULL;
g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
- new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
+ new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
new_matched_key->frame = pinfo->fd->num;
new_matched_key->call_id = hdr->seqnum;
g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
if (!value) {
v.uuid = hdr->if_id;
v.ver = hdr->if_ver;
+ v.object_uuid = hdr->obj_id;
v.opnum = hdr->opnum;
v.req_frame = pinfo->fd->num;
v.rep_frame = 0;
v.max_ptr = 0;
+ v.se_data=NULL;
v.private_data=NULL;
value = &v;
}
pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
tvb, 0, 0, value->rep_frame);
PROTO_ITEM_SET_GENERATED(pi);
+ parent_pi = proto_tree_get_parent(dcerpc_tree);
+ if(parent_pi != NULL) {
+ proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
+ }
}
dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
}
dcerpc_call_value *value, v;
dcerpc_matched_key matched_key, *new_matched_key;
proto_item *pi;
+ proto_item *parent_pi;
di=get_next_di();
if(!(pinfo->fd->flags.visited)){
call_key.act_id=hdr->act_id;
if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
- new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
+ new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
new_matched_key->frame = pinfo->fd->num;
new_matched_key->call_id = hdr->seqnum;
g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
if (!value) {
v.uuid = hdr->if_id;
v.ver = hdr->if_ver;
+ v.object_uuid = hdr->obj_id;
v.opnum = hdr->opnum;
v.req_frame=0;
v.rep_frame=pinfo->fd->num;
+ v.se_data=NULL;
v.private_data=NULL;
value = &v;
}
di->call_data = value;
if(value->req_frame!=0){
- nstime_t ns;
+ nstime_t delta_ts;
pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
tvb, 0, 0, value->req_frame);
PROTO_ITEM_SET_GENERATED(pi);
- ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
- ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
- if(ns.nsecs<0){
- ns.nsecs+=1000000000;
- ns.secs--;
- }
- pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
+ parent_pi = proto_tree_get_parent(dcerpc_tree);
+ if(parent_pi != NULL) {
+ proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
+ }
+ nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
+ pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
PROTO_ITEM_SET_GENERATED(pi);
+ } else {
+ pi = proto_tree_add_text(dcerpc_tree,
+ tvb, 0, 0, "No request to this DCE/RPC call found");
+ expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
+ "No request to this DCE/RPC call found");
}
dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
}
+static void
+dissect_dcerpc_dg_ping_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *dcerpc_tree,
+ e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
+{
+ proto_item *parent_pi;
+/* if(!(pinfo->fd->flags.visited)){*/
+ dcerpc_call_value *call_value;
+ dcerpc_dg_call_key call_key;
+
+ call_key.conv=conv;
+ call_key.seqnum=hdr->seqnum;
+ call_key.act_id=hdr->act_id;
+
+ if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
+ proto_item *pi;
+ nstime_t delta_ts;
+
+ pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
+ tvb, 0, 0, call_value->req_frame);
+ PROTO_ITEM_SET_GENERATED(pi);
+ parent_pi = proto_tree_get_parent(dcerpc_tree);
+ if(parent_pi != NULL) {
+ proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
+ }
+
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
+
+ nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
+ pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
+ PROTO_ITEM_SET_GENERATED(pi);
+/* }*/
+ }
+}
+
/*
* DCERPC dissector for connectionless calls
*/
int offset = 0;
conversation_t *conv;
int auth_level;
- char uuid_str[DCERPC_UUID_STR_LEN];
- int uuid_str_len;
+ char *uuid_str;
+ const char *uuid_name = NULL;
/*
* Check if this looks like a CL DCERPC call. All dg packets
if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
return FALSE;
}
+
+ /* Version must be 4 */
hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
if (hdr.rpc_ver != 4)
return FALSE;
+
+ /* Type must be <=19 or its not DCE/RPC */
hdr.ptype = tvb_get_guint8 (tvb, offset++);
if (hdr.ptype > 19)
return FALSE;
+ /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
+ probably not a DCE/RPC packet
+ */
+ hdr.flags1 = tvb_get_guint8 (tvb, offset++);
+ if(hdr.flags1&0x81)
+ return FALSE;
+
+ /* flags2 has all bits except bit 2 as reserved so if any of them are set
+ it is probably not DCE/RPC.
+ */
+ hdr.flags2 = tvb_get_guint8 (tvb, offset++);
+ if(hdr.flags2&0xfd)
+ return FALSE;
+
+
if (check_col (pinfo->cinfo, COL_PROTOCOL))
col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
if (check_col (pinfo->cinfo, COL_INFO))
col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
- hdr.flags1 = tvb_get_guint8 (tvb, offset++);
- hdr.flags2 = tvb_get_guint8 (tvb, offset++);
tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
offset += sizeof (hdr.drep);
hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
if (ti) {
dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
+ proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
+ val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
+ hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
+ hdr.frag_num, hdr.frag_len);
}
}
offset = 0;
proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
+ if(hdr.flags1) {
+ proto_item_append_text(tf, " %s%s%s%s%s%s",
+ (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
+ (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
+ (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
+ (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
+ (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
+ (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
+ }
}
}
offset++;
proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
+ if(hdr.flags2) {
+ proto_item_append_text(tf, " %s",
+ (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
+ }
}
}
offset++;
proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
+ proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
+ val_to_str(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
+ val_to_str(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
+ val_to_str(hdr.drep[1], drep_fp_vals, "Unknown"));
}
}
offset += sizeof (hdr.drep);
offset++;
if (tree) {
- /* XXX - use "dissect_ndr_uuid_t()"? */
- uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
- "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
- hdr.obj_id.Data4[0],
- hdr.obj_id.Data4[1],
- hdr.obj_id.Data4[2],
- hdr.obj_id.Data4[3],
- hdr.obj_id.Data4[4],
- hdr.obj_id.Data4[5],
- hdr.obj_id.Data4[6],
- hdr.obj_id.Data4[7]);
- if (uuid_str_len >= DCERPC_UUID_STR_LEN)
- memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
- proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
- offset, 16, uuid_str, "Object UUID: %s", uuid_str);
+ proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
+ offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
+ guid_to_str((e_guid_t *) &hdr.obj_id));
}
offset += 16;
if (tree) {
- /* XXX - use "dissect_ndr_uuid_t()"? */
- uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
- "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
- hdr.if_id.Data4[0],
- hdr.if_id.Data4[1],
- hdr.if_id.Data4[2],
- hdr.if_id.Data4[3],
- hdr.if_id.Data4[4],
- hdr.if_id.Data4[5],
- hdr.if_id.Data4[6],
- hdr.if_id.Data4[7]);
- if (uuid_str_len >= DCERPC_UUID_STR_LEN)
- memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
- proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
- offset, 16, uuid_str, "Interface: %s", uuid_str);
+ uuid_str = guid_to_str((e_guid_t*)&hdr.if_id);
+ uuid_name = guids_get_uuid_name(&hdr.if_id);
+ if(uuid_name) {
+ proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
+ offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
+ } else {
+ proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
+ offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
+ }
}
offset += 16;
if (tree) {
- /* XXX - use "dissect_ndr_uuid_t()"? */
- uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
- "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
- hdr.act_id.Data4[0],
- hdr.act_id.Data4[1],
- hdr.act_id.Data4[2],
- hdr.act_id.Data4[3],
- hdr.act_id.Data4[4],
- hdr.act_id.Data4[5],
- hdr.act_id.Data4[6],
- hdr.act_id.Data4[7]);
- if (uuid_str_len >= DCERPC_UUID_STR_LEN)
- memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
- proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
- offset, 16, uuid_str, "Activity: %s", uuid_str);
+ proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
+ offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
+ guid_to_str((e_guid_t *) &hdr.act_id));
}
offset += 16;
if (check_col (pinfo->cinfo, COL_INFO)) {
col_append_fstr (pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
}
+ if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
+ col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
+ }
offset += 4;
if (tree)
* activity_id and seqnum. I haven't seen anywhere that it would
* make a difference, but for future reference...
*/
- conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
+ conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
if (!conv) {
- conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
+ conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
}
break;
case PDU_FACK:
- dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
+ /* Body is optional */
+ /* XXX - we assume "frag_len" is the length of the body */
+ if (hdr.frag_len != 0)
+ dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
break;
case PDU_REJECT:
/* these requests have no body */
case PDU_ACK:
case PDU_PING:
+ dissect_dcerpc_dg_ping_ack (tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
+ break;
case PDU_WORKING:
default:
break;
/* structures and data for BIND */
if (dcerpc_binds){
g_hash_table_destroy (dcerpc_binds);
+ dcerpc_binds=NULL;
}
- dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
-
- if (dcerpc_bind_key_chunk){
- g_mem_chunk_destroy (dcerpc_bind_key_chunk);
- }
- dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
- sizeof (dcerpc_bind_key),
- 200 * sizeof (dcerpc_bind_key),
- G_ALLOC_ONLY);
- if (dcerpc_bind_value_chunk){
- g_mem_chunk_destroy (dcerpc_bind_value_chunk);
+ if(!dcerpc_binds){
+ dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
}
- dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
- sizeof (dcerpc_bind_value),
- 200 * sizeof (dcerpc_bind_value),
- G_ALLOC_ONLY);
+
/* structures and data for CALL */
if (dcerpc_cn_calls){
g_hash_table_destroy (dcerpc_cn_calls);
g_hash_table_destroy (dcerpc_dg_calls);
}
dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal);
- if (dcerpc_cn_call_key_chunk){
- g_mem_chunk_destroy (dcerpc_cn_call_key_chunk);
- }
- dcerpc_cn_call_key_chunk = g_mem_chunk_new ("dcerpc_cn_call_key_chunk",
- sizeof (dcerpc_cn_call_key),
- 200 * sizeof (dcerpc_cn_call_key),
- G_ALLOC_ONLY);
- if (dcerpc_dg_call_key_chunk){
- g_mem_chunk_destroy (dcerpc_dg_call_key_chunk);
- }
- dcerpc_dg_call_key_chunk = g_mem_chunk_new ("dcerpc_dg_call_key_chunk",
- sizeof (dcerpc_dg_call_key),
- 200 * sizeof (dcerpc_dg_call_key),
- G_ALLOC_ONLY);
-
- if (dcerpc_call_value_chunk){
- g_mem_chunk_destroy (dcerpc_call_value_chunk);
- }
- dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
- sizeof (dcerpc_call_value),
- 200 * sizeof (dcerpc_call_value),
- G_ALLOC_ONLY);
/* structure and data for MATCHED */
if (dcerpc_matched){
g_hash_table_destroy (dcerpc_matched);
}
dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
- if (dcerpc_matched_key_chunk){
- g_mem_chunk_destroy (dcerpc_matched_key_chunk);
- }
- dcerpc_matched_key_chunk = g_mem_chunk_new ("dcerpc_matched_key_chunk",
- sizeof (dcerpc_matched_key),
- 200 * sizeof (dcerpc_matched_key),
- G_ALLOC_ONLY);
/* call the registered hooks */
g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
{ "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_cn_num_ctx_items,
{ "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_dcerpc_cn_ctx_item,
+ { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_cn_ctx_id,
{ "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_cn_num_trans_items,
- { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_dcerpc_cn_bind_abstract_syntax,
+ { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_cn_bind_if_id,
- { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_cn_bind_if_ver,
{ "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_cn_bind_if_ver_minor,
{ "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_dcerpc_cn_bind_trans_syntax,
+ { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_cn_bind_trans_id,
- { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_cn_bind_trans_ver,
- { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_cn_alloc_hint,
{ "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_cn_sec_addr_len,
{ &hf_dcerpc_cn_ack_reason,
{ "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
{ &hf_dcerpc_cn_ack_trans_id,
- { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_cn_ack_trans_ver,
{ "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_cn_reject_reason,
{ "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_cn_status,
{ "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
+ { &hf_dcerpc_cn_deseg_req,
+ { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_auth_type,
{ "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
{ &hf_dcerpc_auth_level,
{ &hf_dcerpc_krb5_av_key_auth_verifier,
{ "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_obj_id,
- { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_dg_if_id,
- { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_dg_act_id,
- { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_opnum,
{ "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_array_buffer,
{ "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
-
+
{ &hf_dcerpc_op,
{ "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_fragments,
- { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
+ { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
NULL, 0x0, "DCE/RPC Fragments", HFILL }},
{ &hf_dcerpc_fragment,
NULL, 0x0, "DCE/RPC Fragment", HFILL }},
{ &hf_dcerpc_fragment_overlap,
- { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
+ { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
{ &hf_dcerpc_fragment_overlap_conflict,
- { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
+ { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
{ &hf_dcerpc_fragment_multiple_tails,
- { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
+ { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
{ &hf_dcerpc_fragment_too_long_fragment,
- { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
+ { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
{ &hf_dcerpc_fragment_error,
- { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
+ { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
- { &hf_dcerpc_time,
- { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
+ { &hf_dcerpc_time,
+ { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
{ &hf_dcerpc_reassembled_in,
- { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
+ { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
- { &hf_dcerpc_unknown_if_id,
+ { &hf_dcerpc_unknown_if_id,
{ "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
};
static gint *ett[] = {
&ett_dcerpc_cn_flags,
&ett_dcerpc_cn_ctx,
&ett_dcerpc_cn_iface,
+ &ett_dcerpc_cn_trans_syntax,
&ett_dcerpc_drep,
&ett_dcerpc_dg_flags1,
&ett_dcerpc_dg_flags2,
register_init_routine(dcerpc_reassemble_init);
dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
dcerpc_tap=register_tap("dcerpc");
-
+
g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
}
heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
heur_dissector_add ("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
+ heur_dissector_add ("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2, proto_dcerpc);
+ heur_dissector_add ("http", dissect_dcerpc_cn_bs, proto_dcerpc);
dcerpc_smb_init(proto_dcerpc);
}