X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=packet-dcerpc.c;h=f48f45fc09169e085344fe176424e50c66603ff2;hb=602a62e38a8fb00544e637cc3d3f9c43b2f9b7bd;hp=a3b0fc773e60a7025ea5443f696ced05717635bb;hpb=5f8f311188d3cf0874adb1e33df1e4a96cd8c41d;p=metze%2Fwireshark%2Fwip.git diff --git a/packet-dcerpc.c b/packet-dcerpc.c index a3b0fc773e..f48f45fc09 100644 --- a/packet-dcerpc.c +++ b/packet-dcerpc.c @@ -2,22 +2,22 @@ * Routines for DCERPC packet disassembly * Copyright 2001, Todd Sabin * - * $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 * 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. @@ -27,10 +27,6 @@ #include "config.h" #endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif - #include #include @@ -40,6 +36,13 @@ #include #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"}, @@ -58,7 +61,7 @@ static const value_string pckt_vals[] = { { 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"}, @@ -77,25 +80,34 @@ static const value_string drep_character_vals[] = { { 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 } }; @@ -276,6 +288,7 @@ static int proto_dcerpc = -1; /* 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; @@ -358,6 +371,9 @@ static int hf_dcerpc_opnum = -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; @@ -372,6 +388,7 @@ static int hf_dcerpc_dg_status = -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; @@ -381,6 +398,12 @@ static int hf_dcerpc_fragment_overlap_conflict = -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; @@ -388,10 +411,17 @@ static gint ett_dcerpc_drep = -1; static gint ett_dcerpc_dg_flags1 = -1; static gint ett_dcerpc_dg_flags2 = -1; static gint ett_dcerpc_pointer_data = -1; +static gint ett_dcerpc_string = -1; static gint ett_dcerpc_fragments = -1; static gint ett_dcerpc_fragment = -1; +static gint ett_decrpc_krb5_auth_verf = -1; +static 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, @@ -402,15 +432,23 @@ fragment_items dcerpc_frag_items = { &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 @@ -431,25 +469,13 @@ dcerpc_reassemble_init(void) */ /* 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)); } @@ -457,7 +483,7 @@ dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2) 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; @@ -465,7 +491,7 @@ dcerpc_uuid_hash (gconstpointer k) 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)); @@ -477,10 +503,45 @@ dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver, 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. @@ -508,8 +569,8 @@ static GMemChunk *dcerpc_bind_value_chunk=NULL; 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); @@ -518,8 +579,9 @@ dcerpc_bind_equal (gconstpointer k1, gconstpointer k2) 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; + } /* @@ -541,8 +603,8 @@ static GMemChunk *dcerpc_call_value_chunk=NULL; 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); @@ -551,7 +613,7 @@ dcerpc_call_equal (gconstpointer k1, gconstpointer k2) 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; } @@ -580,7 +642,7 @@ dcerpc_matched_hash (gconstpointer k) 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; @@ -596,7 +658,7 @@ dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, 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; @@ -604,7 +666,7 @@ dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, 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)); } @@ -615,7 +677,7 @@ dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, 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; @@ -623,7 +685,7 @@ dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, 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)); } @@ -632,9 +694,33 @@ dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, 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){ @@ -655,6 +741,75 @@ dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, 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 */ @@ -695,9 +850,9 @@ dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid) /* 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; @@ -715,7 +870,7 @@ dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo, 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 */ @@ -727,9 +882,9 @@ dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo, 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; @@ -767,6 +922,197 @@ dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo, 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 */ @@ -782,10 +1128,12 @@ static gboolean pointers_are_top_level = TRUE; 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 @@ -798,7 +1146,7 @@ init_ndr_pointer_list(packet_info *pinfo) 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){ @@ -835,7 +1183,6 @@ dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *d 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; @@ -847,11 +1194,11 @@ dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *d /* 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. @@ -863,8 +1210,8 @@ dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *d * 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_ dissectors are already prepared @@ -884,7 +1231,7 @@ dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *d * 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. @@ -892,7 +1239,10 @@ dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *d /* 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; } } @@ -900,11 +1250,12 @@ dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *d 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; @@ -924,7 +1275,7 @@ add_pointer_to_list(packet_info *pinfo, proto_tree *tree, } } 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 */ @@ -941,10 +1292,12 @@ add_pointer_to_list(packet_info *pinfo, proto_tree *tree, 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++; } @@ -955,7 +1308,7 @@ find_pointer_index(guint32 id) { ndr_pointer_data_t *npd; int i,len; - + len=g_slist_length(ndr_pointer_list); for(i=0;ihf_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 @@ -1010,11 +1365,12 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, 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; } @@ -1028,7 +1384,7 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, /* 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, @@ -1047,11 +1403,12 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, } /* 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*/ @@ -1063,7 +1420,7 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, /* 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, @@ -1072,11 +1429,12 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, } /* 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; } @@ -1089,13 +1447,14 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, /* 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; } @@ -1108,7 +1467,7 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, /* 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, @@ -1117,11 +1476,12 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, } /* 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; } @@ -1135,7 +1495,7 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, /* 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, @@ -1154,11 +1514,12 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, } /* 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; } @@ -1176,47 +1537,76 @@ 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; } @@ -1231,54 +1621,96 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree, 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; @@ -1286,7 +1718,17 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree, 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; @@ -1299,23 +1741,92 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree, } } } + 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 @@ -1330,45 +1841,110 @@ dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr && (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 */ @@ -1387,8 +1963,8 @@ static guint16 get_smb_fid (void *private_data) */ 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; @@ -1401,7 +1977,9 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr 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); @@ -1425,16 +2003,20 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr 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; @@ -1486,7 +2068,16 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr } 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], @@ -1498,16 +2089,20 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr } 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; @@ -1521,12 +2116,12 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr * 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; @@ -1536,8 +2131,9 @@ dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerp 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); @@ -1567,11 +2163,11 @@ dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerp 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 { @@ -1582,28 +2178,32 @@ dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerp 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) { @@ -1623,16 +2223,14 @@ dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerp } 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); @@ -1647,28 +2245,219 @@ dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerp &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); @@ -1685,20 +2474,24 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr } 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; } @@ -1707,14 +2500,13 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr * 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 @@ -1730,53 +2522,60 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr 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); @@ -1784,136 +2583,29 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr 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, @@ -1935,13 +2627,13 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr * 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 @@ -1964,164 +2656,56 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr } } - } - - 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); @@ -2151,8 +2735,7 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo, * 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); @@ -2187,16 +2770,8 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo, 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); @@ -2205,19 +2780,32 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo, 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 */ /* @@ -2231,10 +2819,11 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo, * 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 { @@ -2244,10 +2833,11 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo, " [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")); } } } @@ -2258,9 +2848,10 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo, 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 */ @@ -2268,7 +2859,7 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo, 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); @@ -2284,11 +2875,11 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo, 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){ @@ -2313,9 +2904,10 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo, */ 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 { @@ -2335,7 +2927,7 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo, 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)) { @@ -2344,7 +2936,6 @@ dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo, } } } - pinfo->fragmented = save_fragmented; } } } @@ -2365,6 +2956,7 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, 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 @@ -2402,11 +2994,6 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, 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); @@ -2418,17 +3005,21 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, 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); @@ -2439,14 +3030,14 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, 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++; @@ -2469,35 +3060,42 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, 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: @@ -2506,7 +3104,8 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, * 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: @@ -2518,7 +3117,8 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, 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; @@ -2597,6 +3197,10 @@ static void 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. @@ -2613,8 +3217,32 @@ dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree, * 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 @@ -2624,7 +3252,7 @@ dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo, { 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); @@ -2632,10 +3260,10 @@ dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo, 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; @@ -2649,7 +3277,7 @@ dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo, { 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); @@ -2657,11 +3285,11 @@ dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo, 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; @@ -2678,7 +3306,7 @@ dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo, 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 */ @@ -2688,27 +3316,27 @@ dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo, 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); } @@ -2724,7 +3352,7 @@ dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo, { 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); @@ -2736,52 +3364,17 @@ dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo, } 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); @@ -2792,12 +3385,6 @@ dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo, 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 @@ -2806,18 +3393,18 @@ dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo, 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)) { @@ -2825,12 +3412,13 @@ dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo, } 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 @@ -2838,15 +3426,16 @@ dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo, 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; @@ -2858,11 +3447,11 @@ dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo, 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)) { @@ -2873,16 +3462,70 @@ dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo, 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; @@ -2911,97 +3554,25 @@ dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo, 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); } /* @@ -3019,6 +3590,9 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 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 @@ -3090,14 +3664,14 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 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++; @@ -3106,14 +3680,14 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 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++; @@ -3134,50 +3708,62 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 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; @@ -3240,14 +3826,15 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 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, @@ -3380,12 +3967,12 @@ proto_register_dcerpc (void) { static hf_register_info hf[] = { { &hf_dcerpc_request_in, - { "Request in", "dcerpc.request_in", FT_UINT32, BASE_DEC, + { "Request in", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE, NULL, 0, "This packet is a response to the packet in this frame", HFILL }}, - { &hf_dcerpc_response_in, - { "Response in", "dcerpc.response_in", FT_UINT32, BASE_DEC, + { &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, @@ -3542,12 +4129,18 @@ proto_register_dcerpc (void) { "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 }}, @@ -3593,15 +4186,18 @@ proto_register_dcerpc (void) { &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, @@ -3617,9 +4213,29 @@ proto_register_dcerpc (void) { "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, @@ -3627,8 +4243,11 @@ proto_register_dcerpc (void) &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; @@ -3649,6 +4268,7 @@ proto_register_dcerpc (void) &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 @@ -3658,4 +4278,10 @@ proto_reg_handoff_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); }