* Routines for DCERPC packet disassembly
* Copyright 2001, Todd Sabin <tas@webspan.net>
*
- * $Id: packet-dcerpc.c,v 1.62 2002/06/22 01:30:53 guy Exp $
+ * $Id: packet-dcerpc.c,v 1.122 2003/05/15 01:59:23 tpot Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* Copyright 1998 Gerald Combs
- *
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "config.h"
#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
#include <string.h>
#include <ctype.h>
#include <epan/conversation.h>
#include "prefs.h"
#include "reassemble.h"
+#include "tap.h"
+#include "packet-frame.h"
+#include "packet-ntlmssp.h"
+#include "packet-dcerpc-nt.h"
+#include "packet-dcerpc-netlogon.h"
+
+static int dcerpc_tap = -1;
static const value_string pckt_vals[] = {
{ PDU_REQ, "Request"},
{ PDU_BIND_NAK, "Bind_nak"},
{ PDU_ALTER, "Alter_context"},
{ PDU_ALTER_ACK, "Alter_context_resp"},
- { PDU_AUTH3, "AUTH3?"},
+ { PDU_AUTH3, "AUTH3"},
{ PDU_SHUTDOWN, "Shutdown"},
{ PDU_CO_CANCEL, "Co_cancel"},
{ PDU_ORPHANED, "Orphaned"},
{ 0, NULL }
};
+#define DCE_RPC_DREP_FP_IEEE 0
+#define DCE_RPC_DREP_FP_VAX 1
+#define DCE_RPC_DREP_FP_CRAY 2
+#define DCE_RPC_DREP_FP_IBM 3
+
static const value_string drep_fp_vals[] = {
- { 0, "IEEE" },
- { 1, "VAX" },
- { 2, "Cray" },
- { 3, "IBM" },
+ { DCE_RPC_DREP_FP_IEEE, "IEEE" },
+ { DCE_RPC_DREP_FP_VAX, "VAX" },
+ { DCE_RPC_DREP_FP_CRAY, "Cray" },
+ { DCE_RPC_DREP_FP_IBM, "IBM" },
{ 0, NULL }
};
-static const true_false_string flags_set_truth = {
- "Set",
- "Not set"
-};
-
/*
* 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[] = {
- { 0, "None" },
- { 1, "Kerberos 5" },
+ { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
+ { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
+ { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
+ { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
+ { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN,"NETLOGON Secure Channel" },
{ 0, NULL }
};
/* field defines */
static int hf_dcerpc_request_in = -1;
+static int hf_dcerpc_time = -1;
static int hf_dcerpc_response_in = -1;
static int hf_dcerpc_ver = -1;
static int hf_dcerpc_ver_minor = -1;
static int hf_dcerpc_dg_seqnum = -1;
static int hf_dcerpc_dg_server_boot = -1;
static int hf_dcerpc_dg_if_ver = -1;
+static int hf_dcerpc_krb5_av_prot_level = -1;
+static int hf_dcerpc_krb5_av_key_vers_num = -1;
+static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
static int hf_dcerpc_dg_cancel_vers = -1;
static int hf_dcerpc_dg_cancel_id = -1;
static int hf_dcerpc_dg_server_accepting_cancels = -1;
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 int hf_dcerpc_sec_chan = -1;
+static int hf_dcerpc_sec_chan_sig = -1;
+static int hf_dcerpc_sec_chan_unk = -1;
+static int hf_dcerpc_sec_chan_seq = -1;
+static int hf_dcerpc_sec_chan_nonce = -1;
static gint ett_dcerpc = -1;
static gint ett_dcerpc_cn_flags = -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 gint ett_sec_chan = -1;
-fragment_items dcerpc_frag_items = {
+static dissector_handle_t ntlmssp_handle, ntlmssp_verf_handle,
+ ntlmssp_enc_payload_handle;
+static dissector_handle_t gssapi_handle, gssapi_verf_handle;
+
+static const fragment_items dcerpc_frag_items = {
&ett_dcerpc_fragments,
&ett_dcerpc_fragment,
&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;
+
/* try to desegment big DCE/RPC packets over TCP? */
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 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
*/
/* the registered subdissectors */
-static GHashTable *dcerpc_uuids;
-
-typedef struct _dcerpc_uuid_key {
- e_uuid_t uuid;
- guint16 ver;
-} dcerpc_uuid_key;
-
-typedef struct _dcerpc_uuid_value {
- int proto;
- int ett;
- gchar *name;
- dcerpc_sub_dissector *procs;
-} dcerpc_uuid_value;
+GHashTable *dcerpc_uuids=NULL;
static gint
dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
{
- dcerpc_uuid_key *key1 = (dcerpc_uuid_key *)k1;
- dcerpc_uuid_key *key2 = (dcerpc_uuid_key *)k2;
+ const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
+ const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
&& (key1->ver == key2->ver));
}
static guint
dcerpc_uuid_hash (gconstpointer k)
{
- dcerpc_uuid_key *key = (dcerpc_uuid_key *)k;
+ const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
/* This isn't perfect, but the Data1 part of these is almost always
unique. */
return key->uuid.Data1;
void
dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
- dcerpc_sub_dissector *procs)
+ dcerpc_sub_dissector *procs, int opnum_hf)
{
dcerpc_uuid_key *key = g_malloc (sizeof (*key));
dcerpc_uuid_value *value = g_malloc (sizeof (*value));
value->ett = ett;
value->name = proto_get_protocol_short_name (proto);
value->procs = procs;
+ value->opnum_hf = opnum_hf;
g_hash_table_insert (dcerpc_uuids, key, value);
}
+/* Function to find the name of a registered protocol
+ * or NULL if the protocol/version is not known to ethereal.
+ */
+char *
+dcerpc_get_proto_name(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 NULL;
+ }
+ return sub_proto->name;
+}
+
+/* Function to find the subdissector table of a registered protocol
+ * or NULL if the protocol/version is not known to ethereal.
+ */
+dcerpc_sub_dissector *
+dcerpc_get_proto_sub_dissector(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 NULL;
+ }
+ return sub_proto->procs;
+}
+
/*
* To keep track of ctx_id mappings.
static gint
dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
{
- dcerpc_bind_key *key1 = (dcerpc_bind_key *)k1;
- dcerpc_bind_key *key2 = (dcerpc_bind_key *)k2;
+ const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
+ const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
return (key1->conv == key2->conv
&& key1->ctx_id == key2->ctx_id
&& key1->smb_fid == key2->smb_fid);
static guint
dcerpc_bind_hash (gconstpointer k)
{
- dcerpc_bind_key *key = (dcerpc_bind_key *)k;
- return ((guint)key->conv) + key->ctx_id + key->smb_fid;
+ const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
+ return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
+
}
/*
static gint
dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
{
- dcerpc_call_key *key1 = (dcerpc_call_key *)k1;
- dcerpc_call_key *key2 = (dcerpc_call_key *)k2;
+ const dcerpc_call_key *key1 = (const dcerpc_call_key *)k1;
+ const dcerpc_call_key *key2 = (const dcerpc_call_key *)k2;
return (key1->conv == key2->conv
&& key1->call_id == key2->call_id
&& key1->smb_fid == key2->smb_fid);
static guint
dcerpc_call_hash (gconstpointer k)
{
- dcerpc_call_key *key = (dcerpc_call_key *)k;
+ const dcerpc_call_key *key = (const dcerpc_call_key *)k;
return ((guint32)key->conv) + key->call_id + key->smb_fid;
}
int
dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
- proto_tree *tree, char *drep,
+ proto_tree *tree, char *drep,
int hfindex, guint8 *pdata)
{
guint8 data;
int
dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
- proto_tree *tree, char *drep,
+ proto_tree *tree, char *drep,
int hfindex, guint16 *pdata)
{
guint16 data;
data = ((drep[0] & 0x10)
? tvb_get_letohs (tvb, offset)
: tvb_get_ntohs (tvb, offset));
-
+
if (tree) {
proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
}
int
dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
- proto_tree *tree, char *drep,
+ proto_tree *tree, char *drep,
int hfindex, guint32 *pdata)
{
guint32 data;
data = ((drep[0] & 0x10)
? tvb_get_letohl (tvb, offset)
: tvb_get_ntohl (tvb, offset));
-
+
if (tree) {
proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
}
return offset+4;
}
+/* handles 32 bit unix time_t */
+int
+dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
+ proto_tree *tree, char *drep,
+ int hfindex, guint32 *pdata)
+{
+ guint32 data;
+ nstime_t tv;
+
+ data = ((drep[0] & 0x10)
+ ? tvb_get_letohl (tvb, offset)
+ : tvb_get_ntohl (tvb, offset));
+
+ tv.secs=data;
+ tv.nsecs=0;
+ if (tree) {
+ proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
+ }
+ if (pdata)
+ *pdata = data;
+
+ return offset+4;
+}
+
int
dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
- proto_tree *tree, char *drep,
+ proto_tree *tree, char *drep,
int hfindex, unsigned char *pdata)
{
if(pdata){
return offset+8;
}
+
+int
+dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
+ proto_tree *tree, char *drep,
+ int hfindex, gfloat *pdata)
+{
+ gfloat data;
+
+
+ switch(drep[1]) {
+ case(DCE_RPC_DREP_FP_IEEE):
+ data = ((drep[0] & 0x10)
+ ? tvb_get_letohieee_float(tvb, offset)
+ : tvb_get_ntohieee_float(tvb, offset));
+ if (tree) {
+ proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
+ }
+ break;
+ case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
+ case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
+ case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
+ default:
+ /* ToBeDone: non IEEE floating formats */
+ /* Set data to a negative infinity value */
+ data = -1.0 * 1e100 * 1e100;
+ if (tree) {
+ proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
+ }
+ }
+ if (pdata)
+ *pdata = data;
+ return offset + 4;
+}
+
+
+int
+dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
+ proto_tree *tree, char *drep,
+ int hfindex, gdouble *pdata)
+{
+ gdouble data;
+
+
+ switch(drep[1]) {
+ case(DCE_RPC_DREP_FP_IEEE):
+ data = ((drep[0] & 0x10)
+ ? tvb_get_letohieee_double(tvb, offset)
+ : tvb_get_ntohieee_double(tvb, offset));
+ if (tree) {
+ proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
+ }
+ break;
+ case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
+ case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
+ case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
+ default:
+ /* ToBeDone: non IEEE double formats */
+ /* Set data to a negative infinity value */
+ data = -1.0 * 1e100 * 1e100;
+ if (tree) {
+ proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
+ }
+ }
+ if (pdata)
+ *pdata = data;
+ return offset + 8;
+}
+
+
/*
* a couple simpler things
*/
/* NDR arrays */
/* function to dissect a unidimensional conformant array */
-int
+int
dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
- proto_tree *tree, char *drep,
+ proto_tree *tree, char *drep,
dcerpc_dissect_fnct_t *fnct)
{
guint32 i;
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;
}
/* function to dissect a unidimensional conformant and varying array */
-int
+int
dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
- proto_tree *tree, char *drep,
+ proto_tree *tree, char *drep,
dcerpc_dissect_fnct_t *fnct)
{
guint32 i;
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 {
+ /*
+ * First, make sure the entire string is in the tvbuff, and throw
+ * an exception if it isn't. 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 = g_malloc(buffer_len + 1);
+ tvb_memcpy(tvb, s, 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
while(ndr_pointer_list){
ndr_pointer_data_t *npd;
-
+
npd=g_slist_nth_data(ndr_pointer_list, 0);
ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
if(npd){
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;
/* This is to check for any bugs in the dissectors.
*
* Basically, the NDR representation will store all
- * arrays in two blocks, one block with the dimension
+ * arrays in two blocks, one block with the dimension
* discreption, like size, number of elements and such,
* and another block that contains the actual data stored
* in the array.
- * If the array is embedded directly inside another,
+ * If the array is embedded directly inside another,
* encapsulating aggregate type, like a union or struct,
* then these two blocks will be stored at different places
* in the bytestream, with other data between the blocks.
* in which mode the dissector MUST NOT consume any data from
* the tvbuff (i.e. may not dissect anything) except the
* initial control block for arrays.
- * The second time the dissector is called, with
- * conformant_run==0, all other data for the type will be
+ * The second time the dissector is called, with
+ * conformant_run==0, all other data for the type will be
* dissected.
*
* All dissect_ndr_<type> dissectors are already prepared
* if(di->conformant_run){
* return offset;
* }
- *
+ *
* to make sure it makes the right thing.
* This assert will signal when someone has forgotten to
* make the dissector aware of this requirement.
/* 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;
}
}
return offset;
}
-
+
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;
}
} else {
/* if we havent seen the request bail out since we cant
- know whether this is the first non-NULL instance
+ know whether this is the first non-NULL instance
or not */
if(value->req_frame==0){
/* XXX THROW EXCEPTION */
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;
- ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
+ 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++;
}
{
ndr_pointer_data_t *npd;
int i,len;
-
+
len=g_slist_length(ndr_pointer_list);
for(i=0;i<len;i++){
npd=g_slist_nth_data(ndr_pointer_list, i);
}
}
}
-
+
return -1;
}
/* This function dissects an NDR pointer and stores the callback for later
- * deferred dissection.
+ * deferred dissection.
*
* fnct is the callback function for when we have reached this object in
- * the bytestream.
- *
+ * the bytestream.
+ *
* type is what type of pointer.
*
* this is text is what text we should put in any created tree node.
*
* 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,
+int
+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;
-
+
di=pinfo->private_data;
if(di->conformant_run){
/* this call was only for dissecting the header for any
proto_tree *tr;
/* we must find out a nice way to do the length here */
- item=proto_tree_add_text(tree, tvb, offset, 0,
+ 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, fnct, 0xffffffff, hf_index, levels);
+ add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
+ hf_index, callback, callback_args);
goto after_ref_id;
}
/* get the referent id */
offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
-
+
/* we got a NULL pointer */
if(id==0){
proto_tree_add_text(tree, tvb, offset-4, 4,
}
/* new pointer */
- item=proto_tree_add_text(tree, tvb, offset-4, 4,
+ 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, 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*/
/* get the referent id */
offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
-
+
/* we got a NULL pointer */
if(id==0){
proto_tree_add_text(tree, tvb, offset-4, 4,
}
/* new pointer */
- item=proto_tree_add_text(tree, tvb, offset-4, 4,
+ 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, fnct, 0xffffffff, hf_index, levels);
+ add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
+ hf_index, callback, callback_args);
goto after_ref_id;
}
/* get the referent id */
offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
-
+
/* new pointer */
- item=proto_tree_add_text(tree, tvb, offset-4, 4,
+ 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, fnct, 0xffffffff, hf_index, levels);
+ add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
+ hf_index, callback, callback_args);
goto after_ref_id;
}
/* get the referent id */
offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
-
+
/* we got a NULL pointer */
if(id==0){
proto_tree_add_text(tree, tvb, offset-4, 4,
}
/* new pointer */
- item=proto_tree_add_text(tree, tvb, offset-4, 4,
+ 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, fnct, 0xffffffff, hf_index, levels);
+ add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
+ hf_index, callback, callback_args);
goto after_ref_id;
}
/* get the referent id */
offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
-
+
/* we got a NULL pointer */
if(id==0){
proto_tree_add_text(tree, tvb, offset-4, 4,
}
/* new pointer */
- item=proto_tree_add_text(tree, tvb, offset-4, 4,
+ 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, 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)
+{
+ 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) {
+ 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,
+ "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,
- guint16 opnum, gboolean is_rqst,
char *drep, dcerpc_info *info,
- int auth_level)
+ dcerpc_auth_info *auth_info)
{
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 *sub_dissect;
- const char *saved_proto;
- void *saved_private_data;
+ dcerpc_dissect_fnct_t *volatile sub_dissect;
+ const char *volatile saved_proto;
+ void *volatile saved_private_data;
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.
+ */
+ show_stub_data (tvb, offset, dcerpc_tree, auth_info);
return -1;
}
for (proc = sub_proto->procs; proc->name; proc++) {
- if (proc->num == opnum) {
+ if (proc->num == info->call_data->opnum) {
name = proc->name;
break;
}
if (check_col (pinfo->cinfo, COL_INFO)) {
col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
- name, is_rqst ? "request" : "reply");
+ name, info->request ? "request" : "reply");
}
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, tvb, offset,
-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.
- *
- * XXX - the subdissectors should all have their own fields
- * for the opnum, so that you can filter on a particular
- * protocol and opnum value; the opnum value isn't, by itself,
- * very interesting, as its interpretation depends on the
- * subprotocol.
- *
- * That would also allow the field to have a value_string
- * table, giving names for operations, and letting you filter
- * by name.
- *
- * ONC RPC should do the same thing with the version and
- * procedure fields it puts into the subprotocol's tree.
*/
- proto_tree_add_uint_format (sub_tree, hf_dcerpc_op, tvb,
- 0, 0, opnum,
- "Operation: %s (%u)",
- name, opnum);
+
+ 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);
+ 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);
}
- /*
+ /*
* If the authentication level is DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
- * the stub data is encrypted, and we can't dissect it.
+ * the stub data is encrypted, and we'd have to decrypt it in
+ * order to dissect it.
*/
- if (auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
+ 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;
+
+ 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 = is_rqst ? proc->dissect_rqst : proc->dissect_resp;
+ 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->private_data = (void *)info;
init_ndr_pointer_list(pinfo);
- offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
+ /*
+ * Catch ReportedBoundsError, so that even if the stub
+ * data is bad, we still show the verifier.
+ */
+ TRY {
+ offset = sub_dissect (tvb, offset, pinfo, sub_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;
}
}
}
+ tap_queue_packet(dcerpc_tap, pinfo, info);
return 0;
}
static int
+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)
+{
+ int auth_offset;
+
+ 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;
+ }
+
+ case DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN: {
+ proto_item *vf = NULL;
+ proto_tree *volatile sec_chan_tree = NULL;
+ /*
+ * Create a new tree, and split into 4 components ...
+ */
+ vf = proto_tree_add_item(dcerpc_tree, hf_dcerpc_sec_chan, tvb,
+ auth_offset, -1, FALSE);
+ sec_chan_tree = proto_item_add_subtree(vf, ett_sec_chan);
+
+ proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_sig, tvb,
+ auth_offset, 8, FALSE);
+
+ proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_unk, tvb,
+ auth_offset + 8, 8, FALSE);
+
+ proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_seq, tvb,
+ auth_offset + 16, 8, FALSE);
+
+ proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_nonce, tvb,
+ auth_offset + 24, 8, FALSE);
+
+ break;
+ }
+
+ default:
+ proto_tree_add_text (dcerpc_tree, tvb, auth_offset, 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, int *auth_level_p)
+ e_dce_cn_common_hdr_t *hdr, gboolean are_credentials,
+ dcerpc_auth_info *auth_info)
{
int offset;
- guint8 auth_pad_len;
- guint8 auth_level;
/*
- * Initially set "*auth_level_p" to -1 to indicate that we haven't
+ * Initially set auth_level to -1 to indicate that we haven't
* yet seen any authentication level information.
*/
- if (auth_level_p != NULL)
- *auth_level_p = -1;
+ auth_info->auth_level = -1;
/*
* The authentication information is at the *end* of the PDU; in
&& (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, NULL);
+ hf_dcerpc_auth_type,
+ &auth_info->auth_type);
offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- hf_dcerpc_auth_level, &auth_level);
- if (auth_level_p != NULL)
- *auth_level_p = 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, &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);
offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_auth_ctx_id, NULL);
- proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len, "Auth Data");
+ /*
+ * Dissect the authentication data.
+ */
+ if (are_credentials) {
+ /*
+ * The authentication data are credentials.
+ */
+ switch (auth_info->auth_type) {
- /* figure out where the auth padding starts */
- offset = hdr->frag_len - (hdr->auth_len + 8 + auth_pad_len);
- if (offset > 0 && auth_pad_len) {
- proto_tree_add_text (dcerpc_tree, tvb, offset,
- auth_pad_len, "Auth padding");
- return hdr->auth_len + 8 + auth_pad_len;
- } else {
- return hdr->auth_len + 8;
- }
- } else {
- return 0;
- }
-}
+ 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);
-/* 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. */
+ 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;
+ }
+
+ case DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN: {
+ tvbuff_t *secchan_tvb;
+
+ secchan_tvb = tvb_new_subset(
+ tvb, offset, hdr->auth_len, hdr->auth_len);
+
+ switch(hdr->ptype) {
+ case PDU_BIND:
+ netlogon_dissect_secchan_bind_creds(
+ secchan_tvb, 0, pinfo, dcerpc_tree,
+ hdr->drep);
+ break;
+ case PDU_BIND_ACK:
+ netlogon_dissect_secchan_bind_ack_creds(
+ secchan_tvb, 0, pinfo, dcerpc_tree,
+ hdr->drep);
+ break;
+ default:
+ proto_tree_add_text(
+ dcerpc_tree, secchan_tvb, 0, hdr->auth_len,
+ "Secure Channel Credentials");
+ }
+ break;
+ }
+
+ default:
+ proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
+ "Auth Credentials");
+ }
+ }
+
+ /* 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;
+ }
+ } else {
+ auth_info->auth_size = 0;
+ }
+}
+
+
+/* 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. */
+
+static guint16 get_smb_fid (void *private_data)
+{
+ dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
-static guint16 get_smb_fid (void *private_data)
-{
- dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
-
if (!priv)
return 0; /* Nothing to see here */
*/
static void
-dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
- e_dce_cn_common_hdr_t *hdr)
+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;
e_uuid_t trans_id;
guint32 trans_ver;
guint16 if_ver, if_ver_minor;
- int offset = 16;
+ 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,
hf_dcerpc_cn_max_xmit, NULL);
offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_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) {
+ 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);
proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
- offset, 16, "HMMM",
- "Interface UUID: %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]);
+ offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
}
offset += 16;
}
if (check_col (pinfo->cinfo, COL_INFO)) {
- col_append_fstr (pinfo->cinfo, COL_INFO, " UUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
+ dcerpc_uuid_key key;
+ dcerpc_uuid_value *value;
+
+ key.uuid = if_id;
+ key.ver = if_ver;
+
+ if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
+ col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
+ else
+ 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],
}
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) {
+ 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_bind_trans_id, tvb,
- offset, 16, "HMMM",
- "Transfer Syntax: %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]);
+ offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
}
offset += 16;
* 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, NULL);
+ dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
}
static void
-dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
- e_dce_cn_common_hdr_t *hdr)
+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 sec_addr_len;
guint16 reason;
e_uuid_t trans_id;
guint32 trans_ver;
-
- int offset = 16;
+ 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,
hf_dcerpc_cn_max_xmit, &max_xmit);
offset += 3;
for (i = 0; i < num_results; i++) {
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_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, dcerpc_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, "HMMM",
- "Transfer Syntax: %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]);
+ offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
}
offset += 16;
offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_ack_trans_ver, &trans_ver);
}
-
+
/*
* 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, NULL);
+ dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
if (check_col (pinfo->cinfo, COL_INFO)) {
if (num_results != 0 && result == 0) {
}
static void
-dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
- e_dce_cn_common_hdr_t *hdr)
+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;
guint8 num_protocols;
guint i;
- int offset = 16;
-
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_cn_reject_reason,
&reason);
&num_protocols);
for (i = 0; i < num_protocols; i++) {
- offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_cn_protocol_ver_major,
NULL);
- offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
NULL);
}
}
}
+/* 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";
+}
+
+static void
+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,
+ guint32 frame)
+{
+ int length, reported_length, stub_length;
+ gboolean save_fragmented;
+ fragment_data *fd_head=NULL;
+ guint32 tot_len;
+
+
+ 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;
+
+ save_fragmented = pinfo->fragmented;
+
+ /* 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,
+ tvb_new_subset (tvb, offset, length, reported_length),
+ 0, 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
+ */
+ if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
+ dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
+ tvb_new_subset (tvb, offset, length,
+ reported_length),
+ 0, hdr->drep, di, auth_info);
+ goto end_cn_stub;
+ }
+
+ /* 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
+ */
+
+
+ /* we dont have the full fragment so we just have to abort and exit
+ */
+ if( !tvb_bytes_exist(tvb, offset, stub_length) ){
+ goto end_cn_stub;
+ }
+
+
+ /* 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.
+ */
+
+
+ /* if this is the first fragment we need to start reassembly
+ */
+ if(hdr->flags&PFC_FIRST_FRAG){
+ fragment_add(tvb, offset, pinfo, frame,
+ dcerpc_co_reassemble_table,
+ 0, stub_length, 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(tvb, offset, pinfo, frame,
+ dcerpc_co_reassemble_table,
+ tot_len-alloc_hint,
+ stub_length,
+ 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(tvb, offset, pinfo,
+ frame,
+ dcerpc_co_reassemble_table,
+ tot_len-alloc_hint,
+ stub_length,
+ 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(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 {
+ proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in, tvb, 0, 0, fd_head->reassembled_in);
+ if (check_col(pinfo->cinfo, COL_INFO)) {
+ col_append_fstr(pinfo->cinfo, COL_INFO,
+ " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
+ }
+ }
+ } else {
+ /* Reassembly not complete - some fragments
+ are missing */
+ 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;
+}
+
static void
-dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
- proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
+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)
{
conversation_t *conv;
guint16 ctx_id;
guint16 opnum;
e_uuid_t obj_id;
- int auth_sz = 0;
- int auth_level;
- int offset = 16;
+ dcerpc_auth_info auth_info;
guint32 alloc_hint;
+ char uuid_str[DCERPC_UUID_STR_LEN];
+ int uuid_str_len;
offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_alloc_hint, &alloc_hint);
}
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, "HMMM",
- "Object UUID: %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]);
+ offset, 16, uuid_str, "Object UUID: %s", uuid_str);
}
offset += 16;
}
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
- auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
- &auth_level);
+ dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
- if (!conv) {
-
- } else {
+ if (!conv)
+ show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
+ else {
dcerpc_call_value *value;
/* !!! we can NOT check flags.visited here since this will interact
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_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->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_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))){
+ g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, 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);
+ }
}
}
value=g_hash_table_lookup (dcerpc_matched, (void *)pinfo->fd->num);
if (value) {
- int length, reported_length, stub_length;
dcerpc_info di;
- gboolean save_fragmented;
/* handoff this call */
- length = tvb_length_remaining(tvb, offset);
- reported_length = tvb_reported_length_remaining(tvb, offset);
- stub_length = hdr->frag_len - offset - auth_sz;
- if (length > stub_length)
- length = stub_length;
- if (reported_length > stub_length)
- reported_length = stub_length;
di.conv = conv;
di.call_id = hdr->call_id;
di.smb_fid = get_smb_fid(pinfo->private_data);
di.call_data = value;
if(value->rep_frame!=0){
- proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
+ proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
tvb, 0, 0, value->rep_frame);
}
-
- 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, opnum, TRUE, hdr->drep, &di, auth_level);
- } else {
- /* PDU is fragmented and this isn't the first fragment */
- 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"));
- }
- }
- }
- } 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"));
- }
- }
- if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
- if( (!pinfo->fd->flags.visited) && value->req_frame ){
- fragment_add(tvb, offset, pinfo, value->req_frame,
- dcerpc_co_reassemble_table,
- 0,
- length,
- TRUE);
- fragment_set_tot_len(pinfo, value->req_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( value->req_frame ){
- fragment_data *fd_head;
- guint32 tot_len;
-
- tot_len = fragment_get_tot_len(pinfo, value->req_frame,
- dcerpc_co_reassemble_table);
- fd_head = fragment_add(tvb, offset, pinfo,
- value->req_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, opnum, TRUE, hdr->drep, &di,
- auth_level);
- } 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) && value->req_frame ){
- guint32 tot_len;
- tot_len = fragment_get_tot_len(pinfo, value->req_frame,
- dcerpc_co_reassemble_table);
- fragment_add(tvb, offset, pinfo, value->req_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]");
- }
- }
- }
- pinfo->fragmented = save_fragmented;
- }
+/*qqq request, broken*/
+ dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
+ hdr, &di, &auth_info, alloc_hint,
+ value->req_frame);
+ } else
+ show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
}
+
+ /* Decrypt the verifier, if present */
+ dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
}
static void
-dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
- proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
+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)
{
dcerpc_call_value *value = NULL;
conversation_t *conv;
guint16 ctx_id;
- int auth_sz = 0;
- int offset = 16;
- int auth_level;
+ dcerpc_auth_info auth_info;
guint32 alloc_hint;
offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
- auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
- &auth_level);
+ dissect_dcerpc_cn_auth (tvb, 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 */
+ show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
} else {
/* !!! we can NOT check flags.visited here since this will interact
}
}
- }
-
- value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
-
- if (value) {
- int length, reported_length, stub_length;
- dcerpc_info di;
- gboolean save_fragmented;
-
- /* handoff this call */
- length = tvb_length_remaining(tvb, offset);
- reported_length = tvb_reported_length_remaining(tvb, offset);
- stub_length = hdr->frag_len - offset - auth_sz;
- if (length > stub_length)
- length = stub_length;
- if (reported_length > stub_length)
- reported_length = stub_length;
- 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){
- proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
- tvb, 0, 0, value->req_frame);
- }
-
- 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, value->opnum, FALSE, hdr->drep, &di,
- auth_level);
- } else {
- /* PDU is fragmented and this isn't the first fragment */
- 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"));
- }
- }
- }
- } 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"));
- }
- }
- 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,
- 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,
- " [DCE/RPC fragment]");
- }
- } 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,
- value->rep_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, value->opnum, FALSE, hdr->drep, &di,
- auth_level);
- } 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) && 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,
- length,
- TRUE);
- }
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO,
- " [DCE/RPC fragment]");
- }
- }
+ }
+
+ value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
+
+ if (value) {
+ dcerpc_info 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;
+
+ proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
+ if(value->req_frame!=0){
+ nstime_t ns;
+ proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
+ tvb, 0, 0, value->req_frame);
+ 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--;
+ }
+ proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
}
- pinfo->fragmented = save_fragmented;
- }
+
+/*qqq response ok*/
+ dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
+ hdr, &di, &auth_info, alloc_hint,
+ value->rep_frame);
+ } else
+ show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
}
+
+ /* Decrypt the verifier, if present */
+ dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
}
static void
-dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo,
+dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
{
dcerpc_call_value *value = NULL;
conversation_t *conv;
guint16 ctx_id;
guint32 status;
- int auth_sz = 0;
- int offset = 16;
- int auth_level;
guint32 alloc_hint;
+ dcerpc_auth_info auth_info;
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?
*/
- auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
- &auth_level);
+ dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
if (value) {
int length, reported_length, stub_length;
dcerpc_info di;
- gboolean save_fragmented;
/* handoff this call */
- length = tvb_length_remaining(tvb, offset);
- reported_length = tvb_reported_length_remaining(tvb, offset);
- stub_length = hdr->frag_len - offset - auth_sz;
- if (length > stub_length)
- length = stub_length;
- if (reported_length > stub_length)
- reported_length = stub_length;
di.conv = conv;
di.call_id = hdr->call_id;
di.smb_fid = get_smb_fid(pinfo->private_data);
proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
if(value->req_frame!=0){
- proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
+ nstime_t ns;
+ proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
tvb, 0, 0, value->req_frame);
+ 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--;
+ }
+ proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
}
- save_fragmented = pinfo->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;
/* 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);
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(tvb, offset, pinfo,
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)) {
}
}
}
- pinfo->fragmented = save_fragmented;
}
}
}
proto_tree *cn_flags_tree = NULL;
proto_tree *drep_tree = NULL;
e_dce_cn_common_hdr_t hdr;
+ dcerpc_auth_info auth_info;
/*
* when done over nbt, dcerpc requests are padded with 4 bytes of null
if (hdr.ptype > 19)
return -1;
- 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.flags = tvb_get_guint8 (tvb, offset++);
tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
offset += sizeof (hdr.drep);
hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
offset += 4;
- offset = start_offset;
if (can_desegment && pinfo->can_desegment
- && hdr.frag_len > tvb_length_remaining (tvb, offset)) {
- pinfo->desegment_offset = offset;
- pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, 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 */
}
+ if (check_col (pinfo->cinfo, COL_PROTOCOL))
+ col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
if (check_col (pinfo->cinfo, COL_INFO))
- col_append_fstr (pinfo->cinfo, COL_INFO, ": call_id: %u", hdr.call_id);
+ col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
+ pckt_vals[hdr.ptype].strptr, hdr.call_id);
+
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);
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_first_frag, 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_cancel_pending, 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_mpx, 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_maybe, 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);
}
offset++;
offset += 4;
}
-
/*
* Packet type specific stuff is next.
*/
switch (hdr.ptype) {
case PDU_BIND:
case PDU_ALTER:
- dissect_dcerpc_cn_bind (tvb, pinfo, dcerpc_tree, &hdr);
+ dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr);
break;
case PDU_BIND_ACK:
case PDU_ALTER_ACK:
- dissect_dcerpc_cn_bind_ack (tvb, pinfo, dcerpc_tree, &hdr);
+ dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
+ break;
+
+ case PDU_AUTH3:
+ /*
+ * Nothing after the common header other than credentials.
+ */
+ dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, TRUE,
+ &auth_info);
break;
case PDU_REQ:
- dissect_dcerpc_cn_rqst (tvb, pinfo, dcerpc_tree, tree, &hdr);
+ dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
break;
case PDU_RESP:
- dissect_dcerpc_cn_resp (tvb, pinfo, dcerpc_tree, tree, &hdr);
+ dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
break;
case PDU_FAULT:
- dissect_dcerpc_cn_fault (tvb, pinfo, dcerpc_tree, &hdr);
+ dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
break;
case PDU_BIND_NAK:
- dissect_dcerpc_cn_bind_nak (tvb, pinfo, dcerpc_tree, &hdr);
+ dissect_dcerpc_cn_bind_nak (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, pinfo, dcerpc_tree, &hdr, NULL);
+ dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
+ &auth_info);
break;
case PDU_SHUTDOWN:
default:
/* might as well dissect the auth info */
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, NULL);
+ dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
+ &auth_info);
break;
}
return hdr.frag_len + padding;
dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
{
+ proto_item *ti = NULL;
+ proto_tree *auth_tree = NULL;
+ guint8 protection_level;
+
/*
* Initially set "*auth_level_p" to -1 to indicate that we haven't
* yet seen any authentication level information.
* packet body, then dissect the auth info.
*/
offset += hdr->frag_len;
- if (tvb_length_remaining(tvb, offset) > 0)
- proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Auth data");
+ if (tvb_length_remaining(tvb, offset) > 0) {
+ switch (hdr->auth_proto) {
+
+ 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);
+ protection_level = tvb_get_guint8 (tvb, offset);
+ if (auth_level_p != NULL)
+ *auth_level_p = protection_level;
+ proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
+ offset++;
+ proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
+ offset++;
+ if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
+ offset += 6; /* 6 bytes of padding */
+ else
+ offset += 2; /* 6 bytes of padding */
+ proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
+ offset += 16;
+ break;
+
+ default:
+ proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
+ break;
+ }
+ }
}
static void
{
guint32 version;
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_cancel_vers,
&version);
case 0:
/* The only version we know about */
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_cancel_id,
NULL);
- offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
NULL);
break;
{
guint32 version;
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_cancel_vers,
&version);
case 0:
/* The only version we know about */
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_cancel_id,
NULL);
/* XXX - are NDR booleans 32 bits? */
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
NULL);
break;
guint16 selack_len;
guint i;
- offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_fack_vers,
&version);
/* padding */
case 0: /* The only version documented in the DCE RPC 1.1 spec */
case 1: /* This appears to be the same */
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_fack_window_size,
NULL);
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
NULL);
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
NULL);
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_fack_serial_num,
&serial_num);
if (check_col (pinfo->cinfo, COL_INFO)) {
col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
serial_num);
}
- offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_fack_selack_len,
&selack_len);
for (i = 0; i < selack_len; i++) {
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_fack_selack,
NULL);
}
{
guint32 status;
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
hdr->drep, hf_dcerpc_dg_status,
&status);
}
static void
-dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
+dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *dcerpc_tree, proto_tree *tree,
- e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
+ e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
{
int length, reported_length, stub_length;
- dcerpc_info di;
- dcerpc_call_value *value, v;
gboolean save_fragmented;
fragment_data *fd_head;
- if(!(pinfo->fd->flags.visited)){
- dcerpc_call_value *call_value;
- dcerpc_call_key *call_key;
-
- call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
- call_key->conv=conv;
- call_key->call_id=hdr->seqnum;
- call_key->smb_fid=get_smb_fid(pinfo->private_data);
-
- call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
- call_value->uuid = hdr->if_id;
- call_value->ver = hdr->if_ver;
- call_value->opnum = hdr->opnum;
- call_value->req_frame=pinfo->fd->num;
- 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);
- }
-
- value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
- if (!value) {
- v.uuid = hdr->if_id;
- v.ver = hdr->if_ver;
- v.opnum = hdr->opnum;
- v.req_frame = pinfo->fd->num;
- v.rep_frame = 0;
- v.max_ptr = 0;
- v.private_data=NULL;
- value = &v;
- }
-
if (check_col (pinfo->cinfo, COL_INFO)) {
- col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u", hdr->opnum);
+ col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u",
+ di->call_data->opnum);
}
length = tvb_length_remaining (tvb, offset);
if (reported_length > stub_length)
reported_length = stub_length;
- di.conv = conv;
- di.call_id = hdr->seqnum;
- di.smb_fid = -1;
- di.request = TRUE;
- di.call_data = value;
-
save_fragmented = pinfo->fragmented;
/* If we don't have reassembly enabled, or this packet contains
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) {
/* First fragment, possibly the only fragment */
/*
- * XXX - authentication level?
+ * XXX - authentication info?
*/
- pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
- dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
- tvb_new_subset (tvb, offset, length,
+ pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
+ dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
+ tvb_new_subset (tvb, offset, length,
reported_length),
- 0, hdr->opnum, TRUE, hdr->drep, &di, 0);
+ 0, 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 {
/* Reassembly is enabled, the PDU is fragmented, and
we have all the data in the fragment; the first two
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;
dcerpc_tree, pinfo, next_tvb);
/*
- * XXX - authentication level?
+ * XXX - authentication info?
*/
pinfo->fragmented = FALSE;
dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
- 0, hdr->opnum, TRUE, hdr->drep, &di, 0);
+ 0, hdr->drep, di, NULL);
} else {
/* Reassembly isn't completed yet */
if (check_col(pinfo->cinfo, COL_INFO)) {
pinfo->fragmented = save_fragmented;
}
+static void
+dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *dcerpc_tree, proto_tree *tree,
+ e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
+{
+ dcerpc_info di;
+ dcerpc_call_value *value, v;
+
+ if(!(pinfo->fd->flags.visited)){
+ dcerpc_call_value *call_value;
+ dcerpc_call_key *call_key;
+
+ call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
+ call_key->conv=conv;
+ call_key->call_id=hdr->seqnum;
+ call_key->smb_fid=get_smb_fid(pinfo->private_data);
+
+ call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
+ call_value->uuid = hdr->if_id;
+ call_value->ver = hdr->if_ver;
+ 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->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);
+ }
+
+ value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
+ if (!value) {
+ v.uuid = hdr->if_id;
+ v.ver = hdr->if_ver;
+ v.opnum = hdr->opnum;
+ v.req_frame = pinfo->fd->num;
+ v.rep_frame = 0;
+ v.max_ptr = 0;
+ v.private_data=NULL;
+ value = &v;
+ }
+
+ 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);
+}
+
static void
dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_tree *dcerpc_tree, proto_tree *tree,
e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
{
- int length, reported_length, stub_length;
dcerpc_info di;
dcerpc_call_value *value, v;
- gboolean save_fragmented;
- fragment_data *fd_head;
if(!(pinfo->fd->flags.visited)){
dcerpc_call_value *call_value;
value = &v;
}
- if (check_col (pinfo->cinfo, COL_INFO)) {
- col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u", value->opnum);
- }
-
- length = tvb_length_remaining (tvb, offset);
- reported_length = tvb_reported_length_remaining (tvb, offset);
- stub_length = hdr->frag_len;
- if (length > stub_length)
- length = stub_length;
- if (reported_length > stub_length)
- reported_length = stub_length;
-
di.conv = conv;
- di.call_id = 0;
+ di.call_id = 0;
di.smb_fid = -1;
di.request = FALSE;
di.call_data = value;
- 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) || !(hdr->flags1 & PFCL1_FRAG) ||
- stub_length > length ) {
- if(hdr->frag_num == 0) {
- /* First fragment, possibly the only fragment */
-
- /*
- * XXX - authentication level?
- */
- pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
- dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
- tvb_new_subset (tvb, offset, length,
- reported_length),
- 0, value->opnum, FALSE, hdr->drep, &di, 0);
- } else {
- /* PDU is fragmented and this isn't the first fragment */
- 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"));
- }
- }
- }
- } 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"));
- }
- }
-
- fd_head = fragment_add_seq(tvb, offset, pinfo,
- hdr->seqnum, dcerpc_cl_reassemble_table,
- hdr->frag_num, 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");
- show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
- dcerpc_tree, pinfo, next_tvb);
-
- /*
- * XXX - authentication level?
- */
- pinfo->fragmented = FALSE;
- dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
- 0, value->opnum, FALSE, hdr->drep, &di, 0);
- } else {
- /* Reassembly isn't completed yet */
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
- }
+ if(value->req_frame!=0){
+ nstime_t ns;
+ proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
+ tvb, 0, 0, value->req_frame);
+ 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--;
}
+ proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
}
- pinfo->fragmented = save_fragmented;
+ dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
}
/*
e_dce_dg_common_hdr_t hdr;
int offset = 0;
conversation_t *conv;
+ int auth_level;
+ char uuid_str[DCERPC_UUID_STR_LEN];
+ int uuid_str_len;
/*
* Check if this looks like a CL DCERPC call. All dg packets
tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
if (dg_flags1_tree) {
- proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, 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_frag, tvb, offset, 1, hdr.flags1);
- proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
- proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
- proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
- proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
+ proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
+ proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
+ proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
+ proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
+ 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);
}
}
offset++;
tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
if (dg_flags2_tree) {
- proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, 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_04, tvb, offset, 1, hdr.flags2);
- proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
- proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
- proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
- proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
+ proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
+ proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
+ proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
+ proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
+ 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);
}
}
offset++;
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, "HMMM",
- "Object: %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]);
+ offset, 16, uuid_str, "Object 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.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, "HMMM",
- "Interface: %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]);
+ offset, 16, uuid_str, "Interface: %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, "HMMM",
- "Activity: %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]);
+ offset, 16, uuid_str, "Activity: %s", uuid_str);
}
offset += 16;
if (tree) {
/*
- * XXX - for Kerberos, we can get a protection level; if it's
+ * XXX - for Kerberos, we get a protection level; if it's
* DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
* stub data.
*/
- dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr, NULL);
+ dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
+ &auth_level);
}
- /*
+ /*
* keeping track of the conversation shouldn't really be necessary
* for connectionless packets, because everything we need to know
* to dissect is in the header for each packet. Unfortunately,
{
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,
+ { &hf_dcerpc_response_in,
+ { "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,
+ { &hf_dcerpc_referent_id,
{ "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
{ &hf_dcerpc_ver,
{ "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_dg_if_ver,
{ "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &hf_dcerpc_krb5_av_prot_level,
+ { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
+ { &hf_dcerpc_krb5_av_key_vers_num,
+ { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { &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 }},
{ &hf_dcerpc_dg_if_id,
{ "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_dg_act_id,
- { "Activitiy", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
+ { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_opnum,
{ "Opnum", "dcerpc.opnum", FT_UINT16, 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 }},
{ &hf_dcerpc_fragments,
- { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
+ { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
NULL, 0x0, "DCE/RPC Fragments", HFILL }},
{ &hf_dcerpc_fragment,
- { "DCE/RPC Fragment", "dcerpc.fragment", FT_NONE, BASE_NONE,
+ { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
NULL, 0x0, "DCE/RPC Fragment", HFILL }},
{ &hf_dcerpc_fragment_overlap,
{ "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_NONE, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", 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 }},
+ { &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 }},
+ { &hf_dcerpc_sec_chan,
+ { "Verifier", "verifier", FT_NONE, BASE_NONE, NULL, 0x0, "Verifier",
+ HFILL }},
+ { &hf_dcerpc_sec_chan_sig,
+ { "Signature", "dcerpc.sec_chan.sig", FT_BYTES, BASE_HEX, NULL,
+ 0x0, "Signature", HFILL }},
+ { &hf_dcerpc_sec_chan_unk,
+ { "Unknown", "dcerpc.sec_chan.unk", FT_BYTES, BASE_HEX, NULL,
+ 0x0, "Unknown", HFILL }},
+ { &hf_dcerpc_sec_chan_seq,
+ { "Sequence No", "dcerpc.sec_chan.seq", FT_BYTES, BASE_HEX, NULL,
+ 0x0, "Sequence No", HFILL }},
+ { &hf_dcerpc_sec_chan_nonce,
+ { "Nonce", "dcerpc.sec_chan.nonce", FT_BYTES, BASE_HEX, NULL,
+ 0x0, "Nonce", HFILL }},
+
+ };
static gint *ett[] = {
&ett_dcerpc,
&ett_dcerpc_cn_flags,
&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_sec_chan,
};
module_t *dcerpc_module;
&dcerpc_reassemble);
register_init_routine(dcerpc_reassemble_init);
dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
+ dcerpc_tap=register_tap("dcerpc");
}
void
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);
}