/* packet-dcerpc.c
* Routines for DCERPC packet disassembly
* Copyright 2001, Todd Sabin <tas@webspan.net>
+ * Copyright 2003, Tim Potter <tpot@samba.org>
*
- * $Id: packet-dcerpc.c,v 1.96 2003/01/14 22:03:33 guy Exp $
+ * $Id: packet-dcerpc.c,v 1.158 2003/12/08 20:58:01 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
#include "reassemble.h"
#include "tap.h"
#include "packet-frame.h"
-#include "packet-ntlmssp.h"
+#include "packet-dcerpc-nt.h"
static int dcerpc_tap = -1;
+
static const value_string pckt_vals[] = {
{ PDU_REQ, "Request"},
{ PDU_PING, "Ping"},
/*
* Authentication services.
*/
-#define DCE_C_RPC_AUTHN_PROTOCOL_NONE 0
-#define DCE_C_RPC_AUTHN_PROTOCOL_KRB5 1
-#define DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO 9
-#define DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP 10
-#define DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN 68
-
static const value_string authn_protocol_vals[] = {
{ DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
{ DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
/*
* Protection levels.
*/
-#define DCE_C_AUTHN_LEVEL_NONE 1
-#define DCE_C_AUTHN_LEVEL_CONNECT 2
-#define DCE_C_AUTHN_LEVEL_CALL 3
-#define DCE_C_AUTHN_LEVEL_PKT 4
-#define DCE_C_AUTHN_LEVEL_PKT_INTEGRITY 5
-#define DCE_C_AUTHN_LEVEL_PKT_PRIVACY 6
-
static const value_string authn_level_vals[] = {
{ DCE_C_AUTHN_LEVEL_NONE, "None" },
{ DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
static int hf_dcerpc_array_max_count = -1;
static int hf_dcerpc_array_offset = -1;
static int hf_dcerpc_array_actual_count = -1;
+static int hf_dcerpc_array_buffer = -1;
static int hf_dcerpc_op = -1;
static int hf_dcerpc_referent_id = -1;
static int hf_dcerpc_fragments = -1;
static int hf_dcerpc_fragment_multiple_tails = -1;
static int hf_dcerpc_fragment_too_long_fragment = -1;
static int hf_dcerpc_fragment_error = -1;
+static int hf_dcerpc_reassembled_in = -1;
static gint ett_dcerpc = -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_drep = -1;
static gint ett_dcerpc_dg_flags1 = -1;
static gint ett_dcerpc_dg_flags2 = -1;
static gint ett_dcerpc_pointer_data = -1;
+static gint ett_dcerpc_string = -1;
static gint ett_dcerpc_fragments = -1;
static gint ett_dcerpc_fragment = -1;
-static gint ett_decrpc_krb5_auth_verf = -1;
-
-static dissector_handle_t ntlmssp_handle, ntlmssp_verf_handle,
- ntlmssp_enc_payload_handle;
-static dissector_handle_t gssapi_handle, gssapi_verf_handle;
+static gint ett_dcerpc_krb5_auth_verf = -1;
static const fragment_items dcerpc_frag_items = {
&ett_dcerpc_fragments,
&hf_dcerpc_fragment_multiple_tails,
&hf_dcerpc_fragment_too_long_fragment,
&hf_dcerpc_fragment_error,
+ NULL,
"fragments"
};
-typedef struct _dcerpc_auth_info {
- guint8 auth_pad_len;
- guint8 auth_level;
- guint8 auth_type;
- guint32 auth_size;
-} dcerpc_auth_info;
+
+
+static dcerpc_info *
+get_next_di(void)
+{
+ static dcerpc_info di[20];
+ static int di_counter=0;
+
+ di_counter++;
+ if(di_counter>=20){
+ di_counter=0;
+ }
+ return &di[di_counter];
+}
/* try to desegment big DCE/RPC packets over TCP? */
static gboolean dcerpc_cn_desegment = TRUE;
fragment_table_init(&dcerpc_cl_reassemble_table);
}
+/*
+ * Authentication subdissectors. Used to dissect authentication blobs in
+ * DCERPC binds, requests and responses.
+ */
+
+typedef struct _dcerpc_auth_subdissector {
+ guint8 auth_level;
+ guint8 auth_type;
+ dcerpc_auth_subdissector_fns auth_fns;
+} dcerpc_auth_subdissector;
+
+static GSList *dcerpc_auth_subdissector_list;
+
+static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
+ guint8 auth_level, guint8 auth_type)
+{
+ gpointer data;
+ int i;
+
+ 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 &&
+ asd->auth_type == auth_type)
+ return &asd->auth_fns;
+ }
+
+ return NULL;
+}
+
+void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
+ dcerpc_auth_subdissector_fns *fns)
+{
+ dcerpc_auth_subdissector *d;
+
+ if (get_auth_subdissector_fns(auth_level, auth_type))
+ return;
+
+ d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
+
+ d->auth_level = auth_level;
+ d->auth_type = auth_type;
+ memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
+
+ dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
+}
+
+/* Hand off verifier data to a registered dissector */
+
+static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
+ proto_tree *tree,
+ dcerpc_auth_subdissector_fns *auth_fns,
+ e_dce_cn_common_hdr_t *hdr,
+ dcerpc_auth_info *auth_info)
+{
+ dcerpc_dissect_fnct_t *volatile fn = NULL;
+
+ switch (hdr->ptype) {
+ case PDU_BIND:
+ case PDU_ALTER:
+ fn = auth_fns->bind_fn;
+ break;
+ case PDU_BIND_ACK:
+ case PDU_ALTER_ACK:
+ fn = auth_fns->bind_ack_fn;
+ break;
+ case PDU_AUTH3:
+ fn = auth_fns->auth3_fn;
+ break;
+ case PDU_REQ:
+ fn = auth_fns->req_verf_fn;
+ break;
+ case PDU_RESP:
+ fn = auth_fns->resp_verf_fn;
+ break;
+
+ /* Don't know how to handle authentication data in this
+ pdu type. */
+
+ default:
+ g_warning("attempt to dissect %s pdu authentication data",
+ val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
+ break;
+ }
+
+ if (fn)
+ fn(auth_tvb, 0, pinfo, tree, hdr->drep);
+ else
+ proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
+ "%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,
+ packet_info *pinfo,
+ dcerpc_auth_subdissector_fns *auth_fns,
+ gboolean is_request,
+ dcerpc_auth_info *auth_info)
+{
+ dcerpc_decode_data_fnct_t *fn;
+
+ if (is_request)
+ fn = auth_fns->req_data_fn;
+ else
+ fn = auth_fns->resp_data_fn;
+
+ if (fn)
+ return fn(enc_tvb, 0, pinfo, auth_info);
+
+ return NULL;
+}
+
/*
* Subdissectors
*/
{
dcerpc_uuid_key *key = g_malloc (sizeof (*key));
dcerpc_uuid_value *value = g_malloc (sizeof (*value));
+ header_field_info *hf_info;
key->uuid = *uuid;
key->ver = ver;
- value->proto = proto;
+ value->proto = find_protocol_by_id(proto);
+ value->proto_id = proto;
value->ett = ett;
- value->name = proto_get_protocol_short_name (proto);
+ value->name = proto_get_protocol_short_name (value->proto);
value->procs = procs;
value->opnum_hf = opnum_hf;
g_hash_table_insert (dcerpc_uuids, key, value);
+
+ hf_info = proto_registrar_get_nth(opnum_hf);
+ hf_info->strings = value_string_from_subdissectors(procs);
}
/* Function to find the name of a registered protocol
return sub_proto->name;
}
+/* Function to find the opnum hf-field of a registered protocol
+ * or -1 if the protocol/version is not known to ethereal.
+ */
+int
+dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
+{
+ dcerpc_uuid_key key;
+ dcerpc_uuid_value *sub_proto;
+
+ key.uuid = *uuid;
+ key.ver = ver;
+ if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
+ return -1;
+ }
+ return sub_proto->opnum_hf;
+}
+
+/* Create a value_string consisting of DCERPC opnum and name from a
+ subdissector array. */
+
+value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
+{
+ value_string *vs = NULL;
+ int i, num_sd = 0;
+
+ again:
+ for (i = 0; sd[i].name; i++) {
+ if (vs) {
+ vs[i].value = sd[i].num;
+ vs[i].strptr = sd[i].name;
+ } else
+ num_sd++;
+ }
+
+ if (!vs) {
+ vs = g_malloc((num_sd + 1) * sizeof(value_string));
+ goto again;
+ }
+
+ vs[num_sd].value = 0;
+ vs[num_sd].strptr = NULL;
+
+ return vs;
+}
+
/* Function to find the subdissector table of a registered protocol
* or NULL if the protocol/version is not known to ethereal.
*/
dcerpc_bind_hash (gconstpointer k)
{
const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
- return ((guint)key->conv) + key->ctx_id + key->smb_fid;
+ return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
+
}
/*
/* to keep track of matched calls/responses
this one uses the same value struct as calls, but the key is the frame id
+ and call id; there can be more than one call in a frame.
+
+ XXX - why not just use the same keys as are used for calls?
*/
+
static GHashTable *dcerpc_matched=NULL;
+
+typedef struct _dcerpc_matched_key {
+ guint32 frame;
+ guint32 call_id;
+} dcerpc_matched_key;
+
+static GMemChunk *dcerpc_matched_key_chunk=NULL;
+
static gint
dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
{
- return (guint32)k1 == (guint32)k2;
+ const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
+ const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
+ return (key1->frame == key2->frame
+ && key1->call_id == key2->call_id);
}
static guint
dcerpc_matched_hash (gconstpointer k)
{
- return (guint32)k;
+ const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
+ return key->frame;
}
di->conformant_run=1;
di->conformant_eaten=offset-old_offset;
} else {
- /* we dont dont remember where in the bytestream this fields was */
+ /* we don't remember where in the bytestream this field was */
proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
/* real run, dissect the elements */
return offset;
}
+/* Dissect an string of bytes. This corresponds to
+ IDL of the form '[string] byte *foo'.
+
+ It can also be used for a conformant varying array of bytes if
+ the contents of the array should be shown as a big blob, rather
+ than showing each byte as an individual element.
+
+ XXX - which of those is really the IDL type for, for example,
+ the encrypted data in some MAPI packets? (Microsoft haven't
+ released that IDL.)
+
+ XXX - does this need to do all the conformant array stuff that
+ "dissect_ndr_ucvarray()" does? These are presumably for strings
+ 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,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di;
+ guint32 len;
+
+ di=pinfo->private_data;
+ if(di->conformant_run){
+ /* just a run to handle conformant arrays, no scalars to dissect */
+ return offset;
+ }
+
+ /* NDR array header */
+
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
+ hf_dcerpc_array_max_count, NULL);
+
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
+ hf_dcerpc_array_offset, NULL);
+
+ offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
+ hf_dcerpc_array_actual_count, &len);
+
+ if (tree && len)
+ proto_tree_add_item(tree, hf_dcerpc_array_buffer,
+ tvb, offset, len, drep[0] & 0x10);
+
+ offset += len;
+
+ return offset;
+}
+
+/* For dissecting arrays that are to be interpreted as strings. */
+
+/* Dissect an NDR conformant 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.
+
+ 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,
+ proto_tree *tree, char *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_max_count, NULL);
+
+ 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);
+ 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....)
+ */
+ 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 conformant 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_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di;
+ di=pinfo->private_data;
+
+ return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
+ sizeof(guint8), di->hf_index,
+ FALSE, NULL);
+}
+
+/* Dissect a conformant 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_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, char *drep)
+{
+ dcerpc_info *di;
+ di=pinfo->private_data;
+
+ return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
+ sizeof(guint16), di->hf_index,
+ FALSE, NULL);
+}
/* ndr pointer handling */
/* list of pointers encountered so far */
hoping that his will not collide with any non-ref pointers */
typedef struct ndr_pointer_data {
guint32 id;
- proto_tree *tree;
+ proto_item *item; /* proto_item for pointer */
+ proto_tree *tree; /* subtree of above item */
dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
int hf_index;
- int levels;
+ dcerpc_callback_fnct_t *callback;
+ void *callback_args;
} ndr_pointer_data_t;
static void
int found_new_pointer;
dcerpc_info *di;
int old_offset;
+ int next_pointer;
+ next_pointer=0;
di=pinfo->private_data;
do{
int i, len;
found_new_pointer=0;
len=g_slist_length(ndr_pointer_list);
- for(i=0;i<len;i++){
+ for(i=next_pointer;i<len;i++){
ndr_pointer_data_t *tnpd;
tnpd=g_slist_nth_data(ndr_pointer_list, i);
if(tnpd->fnct){
dcerpc_dissect_fnct_t *fnct;
+ next_pointer=i+1;
found_new_pointer=1;
fnct=tnpd->fnct;
tnpd->fnct=NULL;
ndr_pointer_list_pos=i+1;
di->hf_index=tnpd->hf_index;
- di->levels=tnpd->levels;
/* first a run to handle any conformant
array headers */
di->conformant_run=1;
/* now we dissect the actual pointer */
di->conformant_run=0;
+ old_offset = offset;
offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
+ if (tnpd->callback)
+ tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
break;
}
}
static void
-add_pointer_to_list(packet_info *pinfo, proto_tree *tree,
- dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, int levels)
+add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
+ dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
+ dcerpc_callback_fnct_t *callback, void *callback_args)
{
ndr_pointer_data_t *npd;
npd=g_malloc(sizeof(ndr_pointer_data_t));
npd->id=id;
npd->tree=tree;
+ npd->item=item;
npd->fnct=fnct;
npd->hf_index=hf_index;
- npd->levels=levels;
+ npd->callback=callback;
+ npd->callback_args=callback_args;
ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
ndr_pointer_list_pos);
ndr_pointer_list_pos++;
* hf_index is what hf value we want to pass to the callback function when
* it is called, the callback can later pich this one up from di->hf_index.
*
- * levels is a generic int we want to pass to teh callback function. the
- * callback can later pick it up from di->levels
+ * callback is executed after the pointer has been dereferenced.
+ *
+ * callback_args is passed as an argument to the callback function
*
* See packet-dcerpc-samr.c for examples
*/
int
-dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
+dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
- int type, char *text, int hf_index, int levels)
+ int type, char *text, int hf_index,
+ dcerpc_callback_fnct_t *callback, void *callback_args)
{
dcerpc_info *di;
"%s", text);
tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
- add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
+ add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
+ hf_index, callback, callback_args);
goto after_ref_id;
}
"%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, fnct, id, hf_index, levels);
+ add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
+ callback, callback_args);
goto after_ref_id;
}
/*TOP LEVEL UNIQUE POINTER*/
"%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, fnct, 0xffffffff, hf_index, levels);
+ add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
+ hf_index, callback, callback_args);
goto after_ref_id;
}
"%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, fnct, 0xffffffff, hf_index, levels);
+ add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
+ hf_index, callback, callback_args);
goto after_ref_id;
}
"%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, fnct, 0xffffffff, hf_index, levels);
+ add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
+ hf_index, callback, callback_args);
goto after_ref_id;
}
"%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, fnct, id, hf_index, levels);
+ add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
+ callback, callback_args);
goto after_ref_id;
}
return offset;
}
+int
+dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
+ proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
+ int type, char *text, int hf_index)
+{
+ return dissect_ndr_pointer_cb(
+ tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
+ NULL, NULL);
+}
+static void
+show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
+ dcerpc_auth_info *auth_info, gboolean is_encrypted)
+{
+ int length;
+
+ /*
+ * We don't show stub data unless we have some in the tvbuff;
+ * however, in the protocol tree, we show, as the number of
+ * bytes, the reported number of bytes, not the number of bytes
+ * that happen to be in the tvbuff.
+ */
+ if (tvb_length_remaining (tvb, offset) > 0) {
+ length = tvb_reported_length_remaining (tvb, offset);
+ 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,
+ "Encrypted stub data (%d byte%s)",
+ length, plurality(length, "", "s"));
+ } else {
+ proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
+ "Decrypted stub data (%d byte%s)",
+ length, plurality(length, "", "s"));
+ }
+ } else {
+ proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
+ "Stub data (%d byte%s)", length,
+ plurality(length, "", "s"));
+ }
+ }
+}
static int
dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
proto_tree *dcerpc_tree,
- tvbuff_t *tvb, gint offset,
+ tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
char *drep, dcerpc_info *info,
dcerpc_auth_info *auth_info)
{
+ volatile gint offset = 0;
dcerpc_uuid_key key;
dcerpc_uuid_value *sub_proto;
- int length;
- proto_tree *sub_tree = NULL;
+ proto_tree *volatile sub_tree = NULL;
dcerpc_sub_dissector *proc;
gchar *name = NULL;
dcerpc_dissect_fnct_t *volatile sub_dissect;
const char *volatile saved_proto;
void *volatile saved_private_data;
+ guint length, reported_length;
+ tvbuff_t *volatile stub_tvb;
+ volatile guint auth_pad_len;
+ volatile int auth_pad_offset;
key.uuid = info->call_data->uuid;
key.ver = info->call_data->ver;
if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
|| !proto_is_protocol_enabled(sub_proto->proto)) {
- /*
- * We don't have a dissector for this UUID, or the protocol
- * for that UUID is disabled.
- */
- length = tvb_length_remaining (tvb, offset);
- if (length > 0) {
- proto_tree_add_text (dcerpc_tree, tvb, offset, length,
- "Stub data (%d byte%s)", length,
- plurality(length, "", "s"));
- }
+ /*
+ * We don't have a dissector for this UUID, or the protocol
+ * for that UUID is disabled.
+ */
+ if (decrypted_tvb != NULL) {
+ show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
+ FALSE);
+ } else
+ show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
return -1;
}
if (tree) {
proto_item *sub_item;
- sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
+ sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
-1, FALSE);
if (sub_item) {
*/
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);
+ 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 the authentication level is DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
- * the stub data is encrypted, and we'd have to decrypt it in
- * order to dissect it.
- */
- if (auth_info != NULL &&
- auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
- length = tvb_length_remaining (tvb, offset);
- if (length > 0) {
- proto_tree_add_text(sub_tree, tvb, offset, length,
- "Encrypted stub data (%d byte%s)",
- length, plurality(length, "", "s"));
-
- switch (auth_info->auth_type) {
-
- case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
- /* NTLMSSP */
- tvbuff_t *ntlmssp_tvb;
- ntlmssp_tvb = tvb_new_subset(tvb, offset, length, length);
- pinfo->decrypted_data=NULL;
+ sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
- call_dissector(ntlmssp_enc_payload_handle, ntlmssp_tvb, pinfo,
- sub_tree);
-
- if(pinfo->decrypted_data){
- ntlmssp_decrypted_info_t *ndi=pinfo->decrypted_data;
-
-
- sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
- if (sub_dissect) {
- 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);
-
- /*
- * Catch ReportedBoundsError, as that could
- * be due to the decryption being bad,
- * and doesn't mean that the tvbuff we were
- * handed has a malformed packet.
- */
- TRY {
- offset = sub_dissect (ndi->decr_tvb, 0, pinfo, ndi->decr_tree, drep);
- } CATCH(BoundsError) {
- RETHROW;
- } CATCH(ReportedBoundsError) {
- show_reported_bounds_error(tvb, pinfo, tree);
- } ENDTRY;
-
- pinfo->current_proto = saved_proto;
- pinfo->private_data = saved_private_data;
- }
- }
- break;
- }
- }
- }
- } else {
- sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
+ if (decrypted_tvb != NULL) {
+ /* Either there was no encryption or we successfully decrypted
+ the entrypted 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);
- offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
+
+ /*
+ * 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
+ * exceeds the stub length. Trim the reported
+ * length of the tvbuff.
+ */
+ reported_length -= auth_info->auth_pad_len;
+
+ /*
+ * If that exceeds the actual amount of data in
+ * the tvbuff (which means we have at least one
+ * byte of authentication padding in the tvbuff),
+ * trim the actual amount.
+ */
+ if (length > reported_length)
+ length = reported_length;
+
+ stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
+ auth_pad_len = auth_info->auth_pad_len;
+ auth_pad_offset = reported_length;
+ } else {
+ /*
+ * The padding length exceeds the stub length.
+ * Don't bother dissecting the stub, trim the padding
+ * length to what's in the stub data, and show the
+ * entire stub as authentication padding.
+ */
+ stub_tvb = NULL;
+ auth_pad_len = reported_length;
+ auth_pad_offset = 0;
+ }
+ } else {
+ /*
+ * No authentication padding.
+ */
+ stub_tvb = decrypted_tvb;
+ auth_pad_len = 0;
+ auth_pad_offset = 0;
+ }
+
+ if (stub_tvb != NULL) {
+ /*
+ * Catch all exceptions other than BoundsError, so that even
+ * if the stub data is bad, we still show the authentication
+ * padding, if any.
+ *
+ * If we get BoundsError, it means the frame was cut short
+ * by a snapshot length, so there's nothing more to
+ * dissect; just re-throw that exception.
+ */
+ TRY {
+ offset = sub_dissect (decrypted_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) {
+ 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));
+ }
+ } CATCH(BoundsError) {
+ RETHROW;
+ } CATCH_ALL {
+ show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE);
+ } ENDTRY;
+ }
+
+ /* If there is auth padding at the end of the stub, display it */
+ if (auth_pad_len != 0) {
+ proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
+ auth_pad_len,
+ "Auth Padding (%u byte%s)",
+ auth_pad_len,
+ plurality(auth_pad_len, "", "s"));
+ }
pinfo->current_proto = saved_proto;
pinfo->private_data = saved_private_data;
} else {
- length = tvb_length_remaining (tvb, offset);
- if (length > 0) {
- proto_tree_add_text (sub_tree, tvb, offset, length,
- "Stub data (%d byte%s)", length,
- plurality(length, "", "s"));
+ /* No subdissector - show it as stub data. */
+ if(decrypted_tvb){
+ show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
+ } else {
+ show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
}
}
- }
+ } else
+ show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
+
tap_queue_packet(dcerpc_tap, pinfo, info);
return 0;
}
{
int auth_offset;
+ auth_info->auth_data = NULL;
+
if (auth_info->auth_size != 0) {
- auth_offset = hdr->frag_len - hdr->auth_len;
- switch (auth_info->auth_type) {
-
- case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
- /* NTLMSSP */
- tvbuff_t *ntlmssp_tvb;
-
- ntlmssp_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
- hdr->auth_len);
-
- call_dissector(ntlmssp_verf_handle, ntlmssp_tvb, pinfo,
- dcerpc_tree);
-
- break;
- }
-
- case DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO: {
- /* SPNEGO (rfc2478) */
- tvbuff_t *gssapi_tvb;
-
- gssapi_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
- hdr->auth_len);
-
- call_dissector(gssapi_verf_handle, gssapi_tvb, pinfo, dcerpc_tree);
-
- break;
- }
-
- default:
- proto_tree_add_text (dcerpc_tree, tvb, auth_offset, hdr->auth_len,
- "Auth Verifier");
- }
+ dcerpc_auth_subdissector_fns *auth_fns;
+ tvbuff_t *auth_tvb;
+
+ auth_offset = hdr->frag_len - hdr->auth_len;
+
+ auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
+ hdr->auth_len);
+
+ auth_info->auth_data = auth_tvb;
+
+ if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
+ auth_info->auth_type))) {
+ /*
+ * Catch all exceptions, so that even if the verifier is bad
+ * or we don't have all of it, we still show the stub data.
+ */
+ TRY {
+ dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
+ hdr, auth_info);
+ } CATCH_ALL {
+ show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
+ } ENDTRY;
+ } else {
+ proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
+ "Auth Verifier");
+ }
}
return hdr->auth_len;
}
static void
-dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
- e_dce_cn_common_hdr_t *hdr, gboolean are_credentials,
- dcerpc_auth_info *auth_info)
+dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
+ proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
+ gboolean are_credentials, dcerpc_auth_info *auth_info)
{
- int offset;
+ volatile int offset;
/*
- * Initially set auth_level to -1 to indicate that we haven't
- * yet seen any authentication level information.
+ * 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 = -1;
-
+ 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
* come before it.
*
- * If the full packet is here, and we've got an auth len, and it's
- * valid, then dissect the auth info.
+ * Is there any authentication data (i.e., is the authentication length
+ * non-zero), and is the authentication length valid (i.e., is it, plus
+ * 8 bytes for the type/level/pad length/reserved/context id, less than
+ * or equal to the fragment length minus the starting offset of the
+ * stub data?)
*/
- if (tvb_length (tvb) >= hdr->frag_len
- && hdr->auth_len
- && (hdr->auth_len + 8 <= hdr->frag_len)) {
-
- offset = hdr->frag_len - (hdr->auth_len + 8);
-
- offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- hf_dcerpc_auth_type,
- &auth_info->auth_type);
- offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- hf_dcerpc_auth_level,
- &auth_info->auth_level);
-
- offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- 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);
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- hf_dcerpc_auth_ctx_id, NULL);
-
- /*
- * Dissect the authentication data.
- */
- if (are_credentials) {
- /*
- * The authentication data are credentials.
- */
- switch (auth_info->auth_type) {
-
- case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
- /* NTLMSSP */
- tvbuff_t *ntlmssp_tvb;
-
- ntlmssp_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
- hdr->auth_len);
-
- call_dissector(ntlmssp_handle, ntlmssp_tvb, pinfo,
- dcerpc_tree);
-
- break;
- }
-
- case DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO: {
- /* SPNEGO (rfc2478) */
- tvbuff_t *gssapi_tvb;
-
- gssapi_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
- hdr->auth_len);
-
- call_dissector(gssapi_handle, gssapi_tvb, pinfo, dcerpc_tree);
-
- break;
- }
- default:
- proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
- "Auth Credentials");
- }
- }
+ if (hdr->auth_len
+ && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
- /*
- * XXX - sometimes the padding is a multiple of 4 and greater
- * than 3, meaning it's not padding to put the authentication
- * data on a 4-byte boundary.
- *
- * For now, we take its value mod 4.
- *
- * XXX - what is going on there?
- */
- auth_info->auth_pad_len %= 4;
-
- /* figure out where the auth padding starts */
- offset = hdr->frag_len - (hdr->auth_len + 8 + auth_info->auth_pad_len);
- if (offset > 0 && auth_info->auth_pad_len) {
- proto_tree_add_text (dcerpc_tree, tvb, offset,
- auth_info->auth_pad_len, "Auth padding");
- auth_info->auth_size = hdr->auth_len + 8 + auth_info->auth_pad_len;
- } else {
- auth_info->auth_size = hdr->auth_len + 8;
+ /*
+ * Yes, there is authentication data, and the length is valid.
+ * Do we have all the bytes of stub data?
+ * (If not, we'd throw an exception dissecting *that*, so don't
+ * bother trying to dissect the authentication information and
+ * throwing another exception there.)
+ */
+ offset = hdr->frag_len - (hdr->auth_len + 8);
+ if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
+ /*
+ * Either there's no stub data, or the last byte of the stub
+ * data is present in the captured data, so we shouldn't
+ * get a BoundsError dissecting the stub data.
+ *
+ * Try dissecting the authentication data.
+ * Catch all exceptions, so that even if the auth info is bad
+ * or we don't have all of it, we still show the stuff we
+ * dissect after this, such as stub data.
+ */
+ TRY {
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ hf_dcerpc_auth_type,
+ &auth_info->auth_type);
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ hf_dcerpc_auth_level,
+ &auth_info->auth_level);
+
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ 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);
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ hf_dcerpc_auth_ctx_id, NULL);
+
+ /*
+ * Dissect the authentication data.
+ */
+ if (are_credentials) {
+ tvbuff_t *auth_tvb;
+ dcerpc_auth_subdissector_fns *auth_fns;
+
+ auth_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
+ 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,
+ 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
+ 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);
+ } ENDTRY;
}
- } else {
- auth_info->auth_size = 0;
}
}
proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
{
conversation_t *conv = NULL;
- guint8 num_ctx_items;
+ guint8 num_ctx_items = 0;
guint i;
gboolean saw_ctx_item = FALSE;
guint16 ctx_id;
offset += 3;
for (i = 0; i < num_ctx_items; i++) {
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ proto_tree *ctx_tree = NULL, *iface_tree = NULL;
+
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
hf_dcerpc_cn_ctx_id, &ctx_id);
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ if (dcerpc_tree) {
+ proto_item *ctx_item;
+
+ ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
+ tvb, offset - 2, 2,
+ 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_num_trans_items, &num_trans_items);
/* XXX - use "dissect_ndr_uuid_t()"? */
dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
- if (dcerpc_tree) {
+ 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[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);
- proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
+
+ 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_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
}
offset += 16;
if (hdr->drep[0] & 0x10) {
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
hf_dcerpc_cn_bind_if_ver, &if_ver);
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
} else {
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
hf_dcerpc_cn_bind_if_ver, &if_ver);
}
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
for (j = 0; j < num_trans_items; j++) {
/* XXX - use "dissect_ndr_uuid_t()"? */
dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
- if (dcerpc_tree) {
+ 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[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_bind_trans_id, tvb,
+ proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
}
offset += 16;
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
hf_dcerpc_cn_bind_trans_ver, &trans_ver);
}
}
* an authentication header, and associate it with an authentication
* context, so subsequent PDUs can use that context.
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
}
static void
* XXX - do we need to do anything with the authentication level
* we get back from this?
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
if (check_col (pinfo->cinfo, COL_INFO)) {
if (num_results != 0 && result == 0) {
}
}
+/* Return a string describing a DCE/RPC fragment as first, middle, or end
+ fragment. */
+
+#define PFC_FRAG_MASK 0x03
+
+static char *
+fragment_type(guint8 flags)
+{
+ flags = flags & PFC_FRAG_MASK;
+
+ if (flags == PFC_FIRST_FRAG)
+ return "first";
+
+ if (flags == 0)
+ return "middle";
+
+ if (flags == PFC_LAST_FRAG)
+ return "last";
+
+ if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
+ return "whole";
+
+ return "unknown";
+}
+
+/* Dissect stub data (payload) of a DCERPC packet. */
+
static void
dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *dcerpc_tree, proto_tree *tree,
dcerpc_auth_info *auth_info, guint32 alloc_hint,
guint32 frame)
{
- int length, reported_length, stub_length;
gboolean save_fragmented;
-
- length = tvb_length_remaining(tvb, offset);
- reported_length = tvb_reported_length_remaining(tvb, offset);
- stub_length = hdr->frag_len - offset - auth_info->auth_size;
- if (length > stub_length)
- length = stub_length;
- if (reported_length > stub_length)
- reported_length = stub_length;
+ fragment_data *fd_head=NULL;
+ guint32 tot_len;
+ tvbuff_t *payload_tvb, *decrypted_tvb;
save_fragmented = pinfo->fragmented;
- /* If we don't have reassembly enabled, or this packet contains
- the entire PDU, or if this is a short frame (or a frame
- not reassembled at a lower layer) that doesn't include all
- the data in the fragment, just call the handoff directly if
- this is the first fragment or the PDU isn't fragmented. */
- if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
- stub_length > length ){
- if(hdr->flags&PFC_FIRST_FRAG){
- /* First fragment, possibly the only fragment */
- pinfo->fragmented = !PFC_NOT_FRAGMENTED(hdr);
- dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
- tvb_new_subset (tvb, offset, length,
- reported_length),
- 0, hdr->drep, di, auth_info);
+ payload_tvb = tvb_new_subset(
+ tvb, offset, tvb_length_remaining(tvb, offset) -
+ auth_info->auth_size, tvb_length_remaining(tvb, offset) -
+ auth_info->auth_size);
+
+ /* Decrypt the PDU if it is encrypted */
+
+ if (auth_info->auth_type &&
+ auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
+ /*
+ * We know the authentication type, and the authentication
+ * level is "Packet privacy", meaning the payload is
+ * 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);
+
+ if (result) {
+ if (dcerpc_tree)
+ proto_tree_add_text(
+ dcerpc_tree, payload_tvb, 0, -1,
+ "Encrypted stub data (%d byte%s)",
+ tvb_reported_length(payload_tvb),
+
+ plurality(tvb_length(payload_tvb), "", "s"));
+
+ add_new_data_source(
+ pinfo, result, "Decrypted stub data");
+
+ /* We succeeded. */
+ decrypted_tvb = result;
+ }
+ }
+ } else
+ decrypted_tvb = payload_tvb;
+
+ /* if this packet is not fragmented, just dissect it and exit */
+ if(PFC_NOT_FRAGMENTED(hdr)){
+ pinfo->fragmented = FALSE;
+
+ 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;
+
+ /* 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
+ encrypted stub?
+ */
+ if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
+
+ 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));
+ }
+ 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
+ */
+ if(pinfo->fd->flags.visited){
+ fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
+ goto end_cn_stub;
+ }
+
+ /* if we are not doing reassembly and it was neither a complete PDU
+ nor the first fragment then there is nothing more we can do
+ so we just have to exit
+ */
+ if( !dcerpc_reassemble )
+ goto end_cn_stub;
+
+ /* if we didnt get 'frame' we dont know where the PDU started and thus
+ it is pointless to continue
+ */
+ if(!frame)
+ goto end_cn_stub;
+
+ /* 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
+ and we also know it is only a fragment and not a full PDU,
+ thus we must reassemble it.
+ */
+
+ /* Do we have any non-encrypted data to reassemble? */
+ if (decrypted_tvb == NULL) {
+ /* No. We can't even try to reassemble. */
+ 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);
+
+end_cn_stub:
+
+ /* if reassembly is complete, dissect the full PDU
+ */
+ if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
+
+ if(pinfo->fd->num==fd_head->reassembled_in){
+ tvbuff_t *next_tvb;
+
+ 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);
+ add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
+ show_fragment_tree(fd_head, &dcerpc_frag_items,
+ dcerpc_tree, pinfo, next_tvb);
+
+ pinfo->fragmented = FALSE;
+
+ dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
+ next_tvb, hdr->drep, di, auth_info);
+
} else {
- /* PDU is fragmented and this isn't the first fragment */
+ proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
+ decrypted_tvb, 0, 0, fd_head->reassembled_in);
if (check_col(pinfo->cinfo, COL_INFO)) {
col_append_fstr(pinfo->cinfo, COL_INFO,
- " [DCE/RPC fragment]");
- }
- if (dcerpc_tree) {
- if (length > 0) {
- proto_tree_add_text (dcerpc_tree, tvb, offset, length,
- "Fragment data (%d byte%s)", length,
- plurality(length, "", "s"));
- }
+ " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
}
}
} else {
- /* Reassembly is enabled, the PDU is fragmented, and
- we have all the data in the fragment; the first two
- of those mean we should attempt reassembly, and the
- third means we can attempt reassembly. */
- if (dcerpc_tree) {
- if (length > 0) {
- proto_tree_add_text (dcerpc_tree, tvb, offset, length,
- "Fragment data (%d byte%s)", length,
- plurality(length, "", "s"));
- }
+ /* 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));
}
- if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
- if( (!pinfo->fd->flags.visited) && frame){
- fragment_add(tvb, offset, pinfo, frame,
- dcerpc_co_reassemble_table,
- 0,
- length,
- TRUE);
- fragment_set_tot_len(pinfo, frame,
- dcerpc_co_reassemble_table, alloc_hint);
- }
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO,
- " [DCE/RPC fragment]");
- }
- } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
- if( frame ){
- fragment_data *fd_head;
- guint32 tot_len;
-
- tot_len = fragment_get_tot_len(pinfo, frame,
- dcerpc_co_reassemble_table);
- fd_head = fragment_add(tvb, offset, pinfo,
- frame,
- dcerpc_co_reassemble_table,
- tot_len-alloc_hint,
- length,
- TRUE);
-
- if(fd_head){
- /* We completed reassembly */
- tvbuff_t *next_tvb;
-
- next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
- 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);
-
- pinfo->fragmented = FALSE;
- dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
- 0, hdr->drep, di, auth_info);
- } else {
- /* Reassembly not complete - some fragments
- are missing */
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO,
- " [DCE/RPC fragment]");
- }
- }
- }
- } else { /* MIDDLE fragment(s) */
- if( (!pinfo->fd->flags.visited) && frame ){
- guint32 tot_len;
- tot_len = fragment_get_tot_len(pinfo, frame,
- dcerpc_co_reassemble_table);
- fragment_add(tvb, offset, pinfo, frame,
- dcerpc_co_reassemble_table,
- tot_len-alloc_hint,
- length,
- TRUE);
- }
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO,
- " [DCE/RPC fragment]");
- }
+
+ if(decrypted_tvb){
+ show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
+ } else {
+ show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
}
}
+
pinfo->fragmented = save_fragmented;
}
e_uuid_t obj_id;
dcerpc_auth_info auth_info;
guint32 alloc_hint;
- int length;
char uuid_str[DCERPC_UUID_STR_LEN];
int uuid_str_len;
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+ dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
- if (!conv) {
- length = tvb_length_remaining (tvb, offset);
- if (length > 0) {
- proto_tree_add_text (dcerpc_tree, tvb, offset, length,
- "Stub data (%d byte%s)", length,
- plurality(length, "", "s"));
- }
- } else {
+ if (!conv)
+ show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
+ else {
+ dcerpc_matched_key matched_key, *new_matched_key;
dcerpc_call_value *value;
/* !!! we can NOT check flags.visited here since this will interact
and desegmented pdu's .
Instead we check if this pdu is already in the matched table or not
*/
- if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
+ matched_key.frame = pinfo->fd->num;
+ matched_key.call_id = hdr->call_id;
+ value = g_hash_table_lookup(dcerpc_matched, &matched_key);
+ if(!value){
dcerpc_bind_key bind_key;
dcerpc_bind_value *bind_value;
bind_key.ctx_id=ctx_id;
bind_key.smb_fid=get_smb_fid(pinfo->private_data);
- if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key))){
- dcerpc_call_key *call_key;
- dcerpc_call_value *call_value;
-
- /* We found the binding so just add the call
- to both the call table and the matched table
- */
- call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
- call_key->conv=conv;
- call_key->call_id=hdr->call_id;
- call_key->smb_fid=get_smb_fid(pinfo->private_data);
-
- /* if there is already a matching call in the table
- remove it so it is replaced with the new one */
- if(g_hash_table_lookup(dcerpc_calls, call_key)){
- g_hash_table_remove(dcerpc_calls, call_key);
- }
+ if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
+ if(!(hdr->flags&PFC_FIRST_FRAG)){
+ dcerpc_call_key call_key;
+ dcerpc_call_value *call_value;
+
+ call_key.conv=conv;
+ call_key.call_id=hdr->call_id;
+ call_key.smb_fid=get_smb_fid(pinfo->private_data);
+ if((call_value=g_hash_table_lookup(dcerpc_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;
+ }
+ } else {
+ dcerpc_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
+ matched table
+ */
+ call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
+ call_key->conv=conv;
+ call_key->call_id=hdr->call_id;
+ call_key->smb_fid=get_smb_fid(pinfo->private_data);
+
+ /* if there is already a matching call in the table
+ remove it so it is replaced with the new one */
+ if(g_hash_table_lookup(dcerpc_calls, call_key)){
+ g_hash_table_remove(dcerpc_calls, call_key);
+ }
- call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
- call_value->uuid = bind_value->uuid;
- call_value->ver = bind_value->ver;
- 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->rep_frame=0;
- call_value->max_ptr=0;
- call_value->private_data = NULL;
- g_hash_table_insert (dcerpc_calls, call_key, call_value);
-
- g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
+ call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
+ call_value->uuid = bind_value->uuid;
+ call_value->ver = bind_value->ver;
+ 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->rep_frame=0;
+ call_value->max_ptr=0;
+ call_value->private_data = NULL;
+ g_hash_table_insert (dcerpc_calls, call_key, call_value);
+
+ 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;
+ }
}
}
- value=g_hash_table_lookup (dcerpc_matched, (void *)pinfo->fd->num);
-
if (value) {
- dcerpc_info di;
+ dcerpc_info *di;
+ di=get_next_di();
/* handoff this call */
- di.conv = conv;
- di.call_id = hdr->call_id;
- di.smb_fid = get_smb_fid(pinfo->private_data);
- di.request = TRUE;
- di.call_data = value;
+ di->conv = conv;
+ di->call_id = hdr->call_id;
+ di->smb_fid = get_smb_fid(pinfo->private_data);
+ di->request = TRUE;
+ di->call_data = value;
+ di->hf_index = -1;
if(value->rep_frame!=0){
proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
}
dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
- hdr, &di, &auth_info, alloc_hint,
+ hdr, di, &auth_info, alloc_hint,
value->req_frame);
- } else {
- length = tvb_length_remaining (tvb, offset);
- if (length > 0) {
- proto_tree_add_text (dcerpc_tree, tvb, offset, length,
- "Stub data (%d byte%s)", length,
- plurality(length, "", "s"));
- }
- }
+ } else
+ show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
}
-
- /* Decrypt the verifier, if present */
- dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
}
static void
guint16 ctx_id;
dcerpc_auth_info auth_info;
guint32 alloc_hint;
- int length;
offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_alloc_hint, &alloc_hint);
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+ dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
+
if (!conv) {
/* no point in creating one here, really */
- length = tvb_length_remaining (tvb, offset);
- if (length > 0) {
- proto_tree_add_text (dcerpc_tree, tvb, offset, length,
- "Stub data (%d byte%s)", length,
- plurality(length, "", "s"));
- }
+ show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
} else {
+ dcerpc_matched_key matched_key, *new_matched_key;
/* !!! we can NOT check flags.visited here since this will interact
badly with when SMB handles (i.e. calls the subdissector)
and desegmented pdu's .
Instead we check if this pdu is already in the matched table or not
*/
- if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
+ matched_key.frame = pinfo->fd->num;
+ matched_key.call_id = hdr->call_id;
+ value=g_hash_table_lookup(dcerpc_matched, &matched_key);
+ if(!value){
dcerpc_call_key call_key;
dcerpc_call_value *call_value;
call_key.smb_fid=get_smb_fid(pinfo->private_data);
if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
- g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
+ 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;
}
-
}
}
- value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
-
if (value) {
- dcerpc_info di;
+ dcerpc_info *di;
+ di=get_next_di();
/* handoff this call */
- di.conv = conv;
- di.call_id = hdr->call_id;
- di.smb_fid = get_smb_fid(pinfo->private_data);
- di.request = FALSE;
- di.call_data = value;
+ di->conv = conv;
+ di->call_id = hdr->call_id;
+ di->smb_fid = get_smb_fid(pinfo->private_data);
+ di->request = FALSE;
+ di->call_data = value;
proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
if(value->req_frame!=0){
}
dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
- hdr, &di, &auth_info, alloc_hint,
+ hdr, di, &auth_info, alloc_hint,
value->rep_frame);
- } else {
- length = tvb_length_remaining (tvb, offset);
- if (length > 0) {
- proto_tree_add_text (dcerpc_tree, tvb, offset, length,
- "Stub data (%d byte%s)", length,
- plurality(length, "", "s"));
- }
- }
+ } else
+ show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
}
-
- /* Decrypt the verifier, if present */
- dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
}
static void
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
if (!conv) {
/* no point in creating one here, really */
} else {
+ dcerpc_matched_key matched_key, *new_matched_key;
/* !!! we can NOT check flags.visited here since this will interact
badly with when SMB handles (i.e. calls the subdissector)
and desegmented pdu's .
Instead we check if this pdu is already in the matched table or not
*/
- if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
+ matched_key.frame = pinfo->fd->num;
+ matched_key.call_id = hdr->call_id;
+ value=g_hash_table_lookup(dcerpc_matched, &matched_key);
+ if(!value){
dcerpc_call_key call_key;
dcerpc_call_value *call_value;
call_key.smb_fid=get_smb_fid(pinfo->private_data);
if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
- g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
+ 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;
}
}
}
- value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
-
if (value) {
int length, reported_length, stub_length;
- dcerpc_info di;
+ dcerpc_info *di;
+ di=get_next_di();
/* handoff this call */
- di.conv = conv;
- di.call_id = hdr->call_id;
- di.smb_fid = get_smb_fid(pinfo->private_data);
- di.request = FALSE;
- di.call_data = value;
+ di->conv = conv;
+ di->call_id = hdr->call_id;
+ di->smb_fid = get_smb_fid(pinfo->private_data);
+ di->request = FALSE;
+ di->call_data = value;
proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
if(value->req_frame!=0){
reported_length = stub_length;
/* If we don't have reassembly enabled, or this packet contains
- the entire PDU, or if this is a short frame (or a frame
- not reassembled at a lower layer) that doesn't include all
- the data in the fragment, just call the handoff directly if
- this is the first fragment or the PDU isn't fragmented. */
+ the entire PDU, or if we don't have all the data in this
+ fragment, just call the handoff directly if this is the
+ first fragment or the PDU isn't fragmented. */
if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
- stub_length > length ){
+ !tvb_bytes_exist(tvb, offset, stub_length) ){
if(hdr->flags&PFC_FIRST_FRAG){
/* First fragment, possibly the only fragment */
/*
* as well, as that might be protocol-specific.
*/
if (dcerpc_tree) {
- if (length > 0) {
- proto_tree_add_text (dcerpc_tree, tvb, offset, length,
- "Fault stub data (%d byte%s)", length,
- plurality(length, "", "s"));
+ if (stub_length > 0) {
+ proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
+ "Fault stub data (%d byte%s)",
+ stub_length,
+ plurality(stub_length, "", "s"));
}
}
} else {
" [DCE/RPC fragment]");
}
if (dcerpc_tree) {
- if (length > 0) {
- proto_tree_add_text (dcerpc_tree, tvb, offset, length,
- "Fragment data (%d byte%s)", length,
- plurality(length, "", "s"));
+ if (stub_length > 0) {
+ proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
+ "Fragment data (%d byte%s)",
+ stub_length,
+ plurality(stub_length, "", "s"));
}
}
}
third means we can attempt reassembly. */
if (dcerpc_tree) {
if (length > 0) {
- proto_tree_add_text (dcerpc_tree, tvb, offset, length,
- "Fragment data (%d byte%s)", length,
- plurality(length, "", "s"));
+ proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
+ "Fragment data (%d byte%s)",
+ stub_length,
+ plurality(stub_length, "", "s"));
}
}
if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
fragment_add(tvb, offset, pinfo, value->rep_frame,
dcerpc_co_reassemble_table,
0,
- length,
+ stub_length,
TRUE);
fragment_set_tot_len(pinfo, value->rep_frame,
dcerpc_co_reassemble_table, alloc_hint);
value->rep_frame,
dcerpc_co_reassemble_table,
tot_len-alloc_hint,
- length,
+ stub_length,
TRUE);
if(fd_head){
*/
if (dcerpc_tree) {
if (length > 0) {
- proto_tree_add_text (dcerpc_tree, tvb, offset, length,
- "Fault stub data (%d byte%s)", length,
- plurality(length, "", "s"));
+ proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
+ "Fault stub data (%d byte%s)",
+ stub_length,
+ plurality(stub_length, "", "s"));
}
}
} else {
fragment_add(tvb, offset, pinfo, value->rep_frame,
dcerpc_co_reassemble_table,
tot_len-alloc_hint,
- length,
+ stub_length,
TRUE);
}
if (check_col(pinfo->cinfo, COL_INFO)) {
/*
* DCERPC dissector for connection oriented calls
*/
-static int
+static gboolean
dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
- proto_tree *tree, gboolean can_desegment)
+ proto_tree *tree, gboolean can_desegment, int *pkt_len)
{
static char nulls[4] = { 0 };
int start_offset;
* the 4 bytes of null padding, and make that the dissector
* used for "netbios".
*/
- if (tvb_bytes_exist (tvb, offset, 4) &&
- tvb_memeql (tvb, offset, nulls, 4) == 0) {
+ if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
/*
* Skip the padding.
* Check if this looks like a C/O DCERPC call
*/
if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
- return -1;
+ return FALSE; /* not enough information to check */
}
start_offset = offset;
hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
if (hdr.rpc_ver != 5)
- return -1;
+ return FALSE;
hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
- return -1;
+ return FALSE;
hdr.ptype = tvb_get_guint8 (tvb, offset++);
if (hdr.ptype > 19)
- return -1;
+ return FALSE;
hdr.flags = tvb_get_guint8 (tvb, offset++);
tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
offset += 4;
if (can_desegment && pinfo->can_desegment
- && hdr.frag_len > tvb_length_remaining (tvb, start_offset)) {
+ && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
pinfo->desegment_offset = start_offset;
pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
- return 0; /* desegmentation required */
+ *pkt_len = 0; /* desegmentation required */
+ return TRUE;
}
if (check_col (pinfo->cinfo, COL_PROTOCOL))
pckt_vals[hdr.ptype].strptr, hdr.call_id);
if (tree) {
- offset = start_offset;
+ 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);
offset += 4;
}
+ /*
+ * None of the stuff done above should throw an exception, because
+ * we would have rejected this as "not DCE RPC" if we didn't have all
+ * of it. (XXX - perhaps we should request reassembly if we have
+ * enough of the header to consider it DCE RPC but not enough to
+ * get the fragment length; in that case the stuff still wouldn't
+ * throw an exception.)
+ *
+ * The rest of the stuff might, so return the PDU length to our caller.
+ * XXX - should we construct a tvbuff containing only the PDU and
+ * use that? Or should we have separate "is this a DCE RPC PDU",
+ * "how long is it", and "dissect it" routines - which might let us
+ * do most of the work in "tcp_dissect_pdus()"?
+ */
+ if (pkt_len != NULL)
+ *pkt_len = hdr.frag_len + padding;
+
/*
* Packet type specific stuff is next.
*/
/*
* Nothing after the common header other than credentials.
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, TRUE,
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
&auth_info);
break;
* Nothing after the common header other than an authentication
* verifier.
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
&auth_info);
break;
default:
/* might as well dissect the auth info */
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
&auth_info);
break;
}
- return hdr.frag_len + padding;
+ return TRUE;
}
/*
* Only one PDU per transport packet, and only one transport
* packet per PDU.
*/
- if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
+ if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
/*
* It wasn't a DCERPC PDU.
*/
static gboolean
dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- int offset = 0;
+ volatile int offset = 0;
int pdu_len;
- gboolean ret = FALSE;
+ volatile gboolean is_dcerpc_pdu;
+ volatile gboolean ret = FALSE;
/*
* There may be multiple PDUs per transport packet; keep
* processing them.
*/
while (tvb_reported_length_remaining(tvb, offset) != 0) {
- pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
- dcerpc_cn_desegment);
- if (pdu_len == -1) {
+ /*
+ * Catch ReportedBoundsError, so that even if the stub data is bad,
+ * we don't abort the full DCE RPC dissection - there might be more
+ * than one DCE RPC PDU in the data being dissected.
+ *
+ * If we get BoundsError, it means the frame was cut short by a
+ * 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);
+ } CATCH(BoundsError) {
+ RETHROW;
+ } CATCH(ReportedBoundsError) {
+ show_reported_bounds_error(tvb, pinfo, tree);
+ } ENDTRY;
+
+ if (!is_dcerpc_pdu) {
/*
* Not a DCERPC PDU.
*/
case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
- auth_tree = proto_item_add_subtree (ti, ett_decrpc_krb5_auth_verf);
+ auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
protection_level = tvb_get_guint8 (tvb, offset);
if (auth_level_p != NULL)
*auth_level_p = protection_level;
int length, reported_length, stub_length;
gboolean save_fragmented;
fragment_data *fd_head;
+ tvbuff_t *next_tvb;
- if (check_col (pinfo->cinfo, COL_INFO)) {
- col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u",
- di->call_data->opnum);
- }
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u", di->call_data->opnum );
length = tvb_length_remaining (tvb, offset);
reported_length = tvb_reported_length_remaining (tvb, offset);
the data in the fragment, just call the handoff directly if
this is the first fragment or the PDU isn't fragmented. */
if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
- stub_length > length ) {
+ !tvb_bytes_exist(tvb, offset, stub_length) ){
if(hdr->frag_num == 0) {
+
+
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
+ di->call_data->uuid.Data1, di->call_data->uuid.Data2, di->call_data->uuid.Data3, di->call_data->uuid.Data4[0],
+ di->call_data->uuid.Data4[1], di->call_data->uuid.Data4[2], di->call_data->uuid.Data4[3],
+ di->call_data->uuid.Data4[4], di->call_data->uuid.Data4[5], di->call_data->uuid.Data4[6],
+ di->call_data->uuid.Data4[7], di->call_data->ver);
+
+
/* First fragment, possibly the only fragment */
/*
* XXX - authentication info?
*/
pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
- dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
- tvb_new_subset (tvb, offset, length,
- reported_length),
- 0, hdr->drep, di, NULL);
+ next_tvb = tvb_new_subset (tvb, offset, length,
+ reported_length);
+ dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
+ next_tvb, hdr->drep, di, NULL);
} else {
/* PDU is fragmented and this isn't the first fragment */
if (check_col(pinfo->cinfo, COL_INFO)) {
}
if (dcerpc_tree) {
if (length > 0) {
- proto_tree_add_text (dcerpc_tree, tvb, offset, length,
- "Fragment data (%d byte%s)", length,
- plurality(length, "", "s"));
- }
+ proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
+ "Fragment data (%d byte%s)",
+ stub_length,
+ plurality(stub_length, "", "s"));
+ }
}
}
} else {
third means we can attempt reassembly. */
if (dcerpc_tree) {
if (length > 0) {
- proto_tree_add_text (dcerpc_tree, tvb, offset, length,
- "Fragment data (%d byte%s)", length,
- plurality(length, "", "s"));
+ 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_seq(tvb, offset, pinfo,
hdr->seqnum, dcerpc_cl_reassemble_table,
- hdr->frag_num, length, !(hdr->flags1 & PFCL1_LASTFRAG));
+ hdr->frag_num, stub_length,
+ !(hdr->flags1 & PFCL1_LASTFRAG));
if (fd_head != NULL) {
/* We completed reassembly */
- tvbuff_t *next_tvb;
-
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");
*/
pinfo->fragmented = FALSE;
dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
- 0, hdr->drep, di, NULL);
+ next_tvb, hdr->drep, di, NULL);
} else {
/* Reassembly isn't completed yet */
if (check_col(pinfo->cinfo, COL_INFO)) {
proto_tree *dcerpc_tree, proto_tree *tree,
e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
{
- dcerpc_info di;
+ dcerpc_info *di;
dcerpc_call_value *value, v;
+ dcerpc_matched_key matched_key, *new_matched_key;
+ di=get_next_di();
if(!(pinfo->fd->flags.visited)){
dcerpc_call_value *call_value;
dcerpc_call_key *call_key;
call_value->private_data = NULL;
g_hash_table_insert (dcerpc_calls, call_key, call_value);
- g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
+ new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
+ 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);
}
- value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
+ matched_key.frame = pinfo->fd->num;
+ matched_key.call_id = hdr->seqnum;
+ value=g_hash_table_lookup(dcerpc_matched, &matched_key);
if (!value) {
v.uuid = hdr->if_id;
v.ver = hdr->if_ver;
value = &v;
}
- di.conv = conv;
- di.call_id = hdr->seqnum;
- di.smb_fid = -1;
- di.request = TRUE;
- di.call_data = value;
+ di->conv = conv;
+ di->call_id = hdr->seqnum;
+ di->smb_fid = -1;
+ di->request = TRUE;
+ di->call_data = value;
if(value->rep_frame!=0){
proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
tvb, 0, 0, value->rep_frame);
}
- dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
+ dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
}
static void
proto_tree *dcerpc_tree, proto_tree *tree,
e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
{
- dcerpc_info di;
+ dcerpc_info *di;
dcerpc_call_value *value, v;
+ dcerpc_matched_key matched_key, *new_matched_key;
+ di=get_next_di();
if(!(pinfo->fd->flags.visited)){
dcerpc_call_value *call_value;
dcerpc_call_key call_key;
call_key.smb_fid=get_smb_fid(pinfo->private_data);
if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
- g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
+ new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
+ 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(call_value->rep_frame==0){
call_value->rep_frame=pinfo->fd->num;
}
}
}
- value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
+ matched_key.frame = pinfo->fd->num;
+ matched_key.call_id = hdr->seqnum;
+ value=g_hash_table_lookup(dcerpc_matched, &matched_key);
if (!value) {
v.uuid = hdr->if_id;
v.ver = hdr->if_ver;
value = &v;
}
- di.conv = conv;
- di.call_id = 0;
- di.smb_fid = -1;
- di.request = FALSE;
- di.call_data = value;
+ di->conv = conv;
+ di->call_id = 0;
+ di->smb_fid = -1;
+ di->request = FALSE;
+ di->call_data = value;
if(value->req_frame!=0){
nstime_t ns;
}
proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
}
- dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
+ dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
}
/*
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);
}
void
{
static hf_register_info hf[] = {
{ &hf_dcerpc_request_in,
- { "Request in", "dcerpc.request_in", FT_UINT32, BASE_DEC,
+ { "Request in", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
{ &hf_dcerpc_response_in,
- { "Response in", "dcerpc.response_in", FT_UINT32, BASE_DEC,
+ { "Response in", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
NULL, 0, "The response to this packet is in this packet", HFILL }},
{ &hf_dcerpc_referent_id,
{ "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
{ "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_dg_fack_window_size,
- { "Window Size", "dcerpc.fack_window size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_dg_fack_max_tsdu,
{ "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_array_actual_count,
{ "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", 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 }},
{ "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, NULL, 0, "Time between Request and Reply for DCE-RPC calls", HFILL }}
-
+ { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "Time between Request and Reply for DCE-RPC calls", HFILL }},
+ { &hf_dcerpc_reassembled_in,
+ { "This PDU is reassembled in", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "The DCE/RPC PDU is completely reassembled in this frame", HFILL }},
};
static gint *ett[] = {
&ett_dcerpc,
&ett_dcerpc_cn_flags,
+ &ett_dcerpc_cn_ctx,
+ &ett_dcerpc_cn_iface,
&ett_dcerpc_drep,
&ett_dcerpc_dg_flags1,
&ett_dcerpc_dg_flags2,
&ett_dcerpc_pointer_data,
+ &ett_dcerpc_string,
&ett_dcerpc_fragments,
&ett_dcerpc_fragment,
- &ett_decrpc_krb5_auth_verf,
+ &ett_dcerpc_krb5_auth_verf,
};
module_t *dcerpc_module;
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_bs, proto_dcerpc);
- ntlmssp_handle = find_dissector("ntlmssp");
- ntlmssp_verf_handle = find_dissector("ntlmssp_verf");
- ntlmssp_enc_payload_handle = find_dissector("ntlmssp_encrypted_payload");
- gssapi_handle = find_dissector("gssapi");
- gssapi_verf_handle = find_dissector("gssapi_verf");
+ dcerpc_smb_init(proto_dcerpc);
}