* Copyright 2003, Tim Potter <tpot[AT]samba.org>
* Copyright 2010, Julien Kerihuel <j.kerihuel[AT]openchange.org>
*
- * $Id$
- *
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
#include "config.h"
-#include <string.h>
-
-#include <glib.h>
-
+#include <stdio.h>
#include <epan/packet.h>
#include <epan/exceptions.h>
-#include <epan/conversation.h>
#include <epan/prefs.h>
#include <epan/reassemble.h>
#include <epan/tap.h>
-#include <epan/wmem/wmem.h>
+#include <epan/srt_table.h>
#include <epan/expert.h>
-#include <epan/strutil.h>
#include <epan/addr_resolv.h>
#include <epan/show_exception.h>
-#include <epan/dissectors/packet-dcerpc.h>
-#include <epan/dissectors/packet-dcerpc-nt.h>
+#include <epan/decode_as.h>
+#include <epan/proto_data.h>
+
+#include <wsutil/str_util.h>
+#include "packet-tcp.h"
+#include "packet-dcerpc.h"
+#include "packet-dcerpc-nt.h"
+
+void proto_register_dcerpc(void);
+void proto_reg_handoff_dcerpc(void);
static int dcerpc_tap = -1;
/* 32bit Network Data Representation, see DCE/RPC Appendix I */
-static e_uuid_t uuid_data_repr_proto = { 0x8a885d04, 0x1ceb, 0x11c9,
+static e_guid_t uuid_data_repr_proto = { 0x8a885d04, 0x1ceb, 0x11c9,
{ 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60 } };
/* 64bit Network Data Representation, introduced in Windows Server 2008 */
-static e_uuid_t uuid_ndr64 = { 0x71710533, 0xbeba, 0x4937,
+static e_guid_t uuid_ndr64 = { 0x71710533, 0xbeba, 0x4937,
{ 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 } };
-/* Bind Time Feature Negotiation, see [MS-RPCE] 3.3.1.5.3 */
-static e_uuid_t uuid_bind_time_feature_nego_00 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
-static e_uuid_t uuid_bind_time_feature_nego_01 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
-static e_uuid_t uuid_bind_time_feature_nego_02 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
-static e_uuid_t uuid_bind_time_feature_nego_03 = { 0x6cb71c2c, 0x9812, 0x4540, { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
-
/* see [MS-OXRPC] Appendix A: Full IDL, http://msdn.microsoft.com/en-us/library/ee217991%28v=exchg.80%29.aspx */
-static e_uuid_t uuid_asyncemsmdb = { 0x5261574a, 0x4572, 0x206e,
+static e_guid_t uuid_asyncemsmdb = { 0x5261574a, 0x4572, 0x206e,
{ 0xb2, 0x68, 0x6b, 0x19, 0x92, 0x13, 0xb4, 0xe4 } };
static const value_string pckt_vals[] = {
{ 0x00000005, "nca_s_fault_access_denied" },
{ 0x000006f7, "nca_s_fault_ndr" },
{ 0x000006d8, "nca_s_fault_cant_perform" },
+ { 0x00000721, "nca_s_fault_sec_pkg_error" },
{ 0x1c000001, "nca_s_fault_int_div_by_zero" },
{ 0x1c000002, "nca_s_fault_addr_error" },
{ 0x1c000003, "nca_s_fault_fp_div_zero" },
static int hf_dcerpc_cn_flags_object = -1;
static int hf_dcerpc_drep = -1;
int hf_dcerpc_drep_byteorder = -1;
+ int hf_dcerpc_ndr_padding = -1;
static int hf_dcerpc_drep_character = -1;
static int hf_dcerpc_drep_fp = -1;
static int hf_dcerpc_cn_frag_len = -1;
static int hf_dcerpc_cn_bind_trans_syntax = -1;
static int hf_dcerpc_cn_bind_trans_id = -1;
static int hf_dcerpc_cn_bind_trans_ver = -1;
+static int hf_dcerpc_cn_bind_trans_btfn = -1;
static int hf_dcerpc_cn_bind_trans_btfn_01 = -1;
static int hf_dcerpc_cn_bind_trans_btfn_02 = -1;
static int hf_dcerpc_cn_alloc_hint = -1;
static int hf_dcerpc_cn_ack_reason = -1;
static int hf_dcerpc_cn_ack_trans_id = -1;
static int hf_dcerpc_cn_ack_trans_ver = -1;
-static int hf_dcerpc_cn_ack_btfn = -1;
static int hf_dcerpc_cn_reject_reason = -1;
static int hf_dcerpc_cn_num_protocols = -1;
static int hf_dcerpc_cn_protocol_ver_major = -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_referent_id32 = -1;
+static int hf_dcerpc_referent_id64 = -1;
+static int hf_dcerpc_null_pointer = -1;
static int hf_dcerpc_fragments = -1;
static int hf_dcerpc_fragment = -1;
static int hf_dcerpc_fragment_overlap = -1;
static int hf_dcerpc_reassembled_in = -1;
static int hf_dcerpc_reassembled_length = -1;
static int hf_dcerpc_unknown_if_id = -1;
+static int hf_dcerpc_sec_vt_signature = -1;
+static int hf_dcerpc_sec_vt_command = -1;
+static int hf_dcerpc_sec_vt_command_cmd = -1;
+static int hf_dcerpc_sec_vt_command_end = -1;
+static int hf_dcerpc_sec_vt_command_must = -1;
+static int hf_dcerpc_sec_vt_command_length = -1;
+static int hf_dcerpc_sec_vt_bitmask = -1;
+static int hf_dcerpc_sec_vt_bitmask_sign = -1;
+static int hf_dcerpc_sec_vt_pcontext_uuid = -1;
+static int hf_dcerpc_sec_vt_pcontext_ver = -1;
+
+static const int *sec_vt_command_fields[] = {
+ &hf_dcerpc_sec_vt_command_cmd,
+ &hf_dcerpc_sec_vt_command_end,
+ &hf_dcerpc_sec_vt_command_must,
+ NULL
+};
+static int hf_dcerpc_reserved = -1;
+static int hf_dcerpc_unknown = -1;
+static int hf_dcerpc_missalign = -1;
+
+/* Generated from convert_proto_tree_add_text.pl */
+static int hf_dcerpc_duplicate_ptr = -1;
+static int hf_dcerpc_encrypted_stub_data = -1;
+static int hf_dcerpc_decrypted_stub_data = -1;
+static int hf_dcerpc_payload_stub_data = -1;
+static int hf_dcerpc_stub_data_with_sec_vt = -1;
+static int hf_dcerpc_stub_data = -1;
+static int hf_dcerpc_auth_padding = -1;
+static int hf_dcerpc_auth_verifier = -1;
+static int hf_dcerpc_auth_info = -1;
+static int hf_dcerpc_auth_credentials = -1;
+static int hf_dcerpc_fault_stub_data = -1;
+static int hf_dcerpc_fragment_data = -1;
+static int hf_dcerpc_cmd_client_ipv4 = -1;
+static int hf_dcerpc_cmd_client_ipv6 = -1;
+static int hf_dcerpc_authentication_verifier = -1;
+
+static const int *dcerpc_cn_bind_trans_btfn_fields[] = {
+ &hf_dcerpc_cn_bind_trans_btfn_01,
+ &hf_dcerpc_cn_bind_trans_btfn_02,
+ NULL
+};
+
+static const int *sec_vt_bitmask_fields[] = {
+ &hf_dcerpc_sec_vt_bitmask_sign,
+ NULL
+};
+
+static const value_string sec_vt_command_cmd_vals[] = {
+ {1, "BITMASK_1"},
+ {2, "PCONTEXT"},
+ {3, "HEADER2"},
+ {0, NULL}
+};
static gint ett_dcerpc = -1;
static gint ett_dcerpc_cn_flags = -1;
static gint ett_dcerpc_cn_iface = -1;
static gint ett_dcerpc_cn_trans_syntax = -1;
static gint ett_dcerpc_cn_trans_btfn = -1;
+static gint ett_dcerpc_cn_bind_trans_btfn = -1;
static gint ett_dcerpc_cn_rts_flags = -1;
static gint ett_dcerpc_cn_rts_command = -1;
static gint ett_dcerpc_cn_rts_pdu = -1;
static gint ett_dcerpc_fragments = -1;
static gint ett_dcerpc_fragment = -1;
static gint ett_dcerpc_krb5_auth_verf = -1;
+static gint ett_dcerpc_auth_info = -1;
+static gint ett_dcerpc_verification_trailer = -1;
+static gint ett_dcerpc_sec_vt_command = -1;
+static gint ett_dcerpc_sec_vt_bitmask = -1;
+static gint ett_dcerpc_sec_vt_pcontext = -1;
+static gint ett_dcerpc_sec_vt_header = -1;
+static gint ett_dcerpc_complete_stub_data = -1;
static expert_field ei_dcerpc_fragment_multiple = EI_INIT;
static expert_field ei_dcerpc_cn_status = EI_INIT;
static expert_field ei_dcerpc_context_change = EI_INIT;
static expert_field ei_dcerpc_cn_ctx_id_no_bind = EI_INIT;
static expert_field ei_dcerpc_bind_not_acknowledged = EI_INIT;
+static expert_field ei_dcerpc_verifier_unavailable = EI_INIT;
+static expert_field ei_dcerpc_invalid_pdu_authentication_attempt = EI_INIT;
+/* Generated from convert_proto_tree_add_text.pl */
+static expert_field ei_dcerpc_long_frame = EI_INIT;
+static expert_field ei_dcerpc_cn_rts_command = EI_INIT;
+
+static const guint8 TRAILER_SIGNATURE[] = {0x8a, 0xe3, 0x13, 0x71, 0x02, 0xf4, 0x36, 0x71};
+static tvbuff_t *tvb_trailer_signature = NULL;
+
+static GSList *decode_dcerpc_bindings = NULL;
+/*
+ * To keep track of ctx_id mappings.
+ *
+ * Every time we see a bind call we update this table.
+ * Note that we always specify a SMB FID. For non-SMB transports this
+ * value is 0.
+ */
+static GHashTable *dcerpc_binds = NULL;
+
+typedef struct _dcerpc_bind_key {
+ conversation_t *conv;
+ guint16 ctx_id;
+ guint64 transport_salt;
+} dcerpc_bind_key;
+
+typedef struct _dcerpc_bind_value {
+ e_guid_t uuid;
+ guint16 ver;
+ e_guid_t transport;
+} dcerpc_bind_value;
+
+/* Extra data for DCERPC handling and tracking of context ids */
+typedef struct _dcerpc_decode_as_data {
+ guint16 dcectxid; /**< Context ID (DCERPC-specific) */
+ int dcetransporttype; /**< Transport type
+ * Value -1 means "not a DCERPC packet"
+ */
+ guint64 dcetransportsalt; /**< fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */
+} dcerpc_decode_as_data;
+
+static dcerpc_decode_as_data*
+dcerpc_get_decode_data(packet_info* pinfo)
+{
+ dcerpc_decode_as_data* data = (dcerpc_decode_as_data*)p_get_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0);
+ if (data == NULL)
+ {
+ data = wmem_new0(pinfo->pool, dcerpc_decode_as_data);
+ data->dcetransporttype = -1;
+ p_add_proto_data(pinfo->pool, pinfo, proto_dcerpc, 0, data);
+ }
+
+ return data;
+}
+
+/**
+ * Registers a conversation/UUID binding association, so that
+ * we can invoke the proper sub-dissector for a given DCERPC
+ * conversation.
+ *
+ * @param binding all values needed to create and bind a new conversation
+ *
+ * @return Pointer to newly-added UUID/conversation binding.
+ */
+static struct _dcerpc_bind_value *
+dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
+{
+ dcerpc_bind_value *bind_value;
+ dcerpc_bind_key *key;
+ conversation_t *conv;
+
+ conv = find_conversation(
+ 0,
+ &binding->addr_a,
+ &binding->addr_b,
+ binding->ptype,
+ binding->port_a,
+ binding->port_b,
+ 0);
+
+ if (!conv) {
+ conv = conversation_new(
+ 0,
+ &binding->addr_a,
+ &binding->addr_b,
+ binding->ptype,
+ binding->port_a,
+ binding->port_b,
+ 0);
+ }
+
+ bind_value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
+ bind_value->uuid = binding->uuid;
+ bind_value->ver = binding->ver;
+ /* For now, assume all DCE/RPC we pick from "decode as" is using
+ standard ndr and not ndr64.
+ We should make this selectable from the dialog in the future
+ */
+ bind_value->transport = uuid_data_repr_proto;
+
+ key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
+ key->conv = conv;
+ key->ctx_id = binding->ctx_id;
+ key->transport_salt = binding->transport_salt;
+
+ /* add this entry to the bind table */
+ g_hash_table_insert(dcerpc_binds, key, bind_value);
+
+ return bind_value;
+
+}
+
+/* inject one of our bindings into the dcerpc binding table */
+static void
+decode_dcerpc_inject_binding(gpointer data, gpointer user_data _U_)
+{
+ dcerpc_add_conv_to_bind_table((decode_dcerpc_bind_values_t *) data);
+}
+
+/* inject all of our bindings into the dcerpc binding table */
+static void
+decode_dcerpc_inject_bindings(void) {
+ g_slist_foreach(decode_dcerpc_bindings, decode_dcerpc_inject_binding, NULL /* user_data */);
+}
+
+/* free a binding */
+static void
+decode_dcerpc_binding_free(void *binding_in)
+{
+ decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)binding_in;
+
+ free_address(&binding->addr_a);
+ free_address(&binding->addr_b);
+ if (binding->ifname)
+ g_string_free(binding->ifname, TRUE);
+ g_free(binding);
+}
+
+static void
+dcerpc_decode_as_free(gpointer value)
+{
+ decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)value;
+ if (binding != NULL)
+ decode_dcerpc_binding_free(binding);
+}
+
+/* removes all bindings */
+void
+decode_dcerpc_reset_all(void)
+{
+ decode_dcerpc_bind_values_t *binding;
+
+ while (decode_dcerpc_bindings) {
+ binding = (decode_dcerpc_bind_values_t *)decode_dcerpc_bindings->data;
+
+ decode_dcerpc_binding_free(binding);
+ decode_dcerpc_bindings = g_slist_remove(
+ decode_dcerpc_bindings,
+ decode_dcerpc_bindings->data);
+ }
+}
+
+
+void
+decode_dcerpc_add_show_list(decode_add_show_list_func func, gpointer user_data)
+{
+ g_slist_foreach(decode_dcerpc_bindings, func, user_data);
+}
+
+static void
+dcerpc_prompt(packet_info *pinfo, gchar* result)
+{
+ GString *str = g_string_new("Replace binding between:\r\n"),
+ *address_str = g_string_new("");
+ dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+ switch (pinfo->ptype) {
+ case(PT_TCP):
+ g_string_append(address_str, "Address: ToBeDone TCP port");
+ break;
+ case(PT_UDP):
+ g_string_append(address_str, "Address: ToBeDone UDP port");
+ break;
+ default:
+ g_string_append(address_str, "Address: ToBeDone Unknown port type");
+ }
+
+ g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->srcport);
+ g_string_append(str, "&\r\n");
+ g_string_append_printf(str, "%s: %u\r\n", address_str->str, pinfo->destport);
+ g_string_append_printf(str, "&\r\nContext ID: %u\r\n", decode_data->dcectxid);
+ g_string_append_printf(str, "&\r\nSMB FID: %"G_GINT64_MODIFIER"u\r\n",
+ dcerpc_get_transport_salt(pinfo));
+ g_string_append(str, "with:\r\n");
+
+ g_strlcpy(result, str->str, MAX_DECODE_AS_PROMPT_LEN);
+ g_string_free(str, TRUE);
+ g_string_free(address_str, TRUE);
+}
+
+static gpointer
+dcerpc_value(packet_info *pinfo)
+{
+ decode_dcerpc_bind_values_t *binding;
+ dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+ /* clone binding */
+ binding = g_new(decode_dcerpc_bind_values_t,1);
+ copy_address(&binding->addr_a, &pinfo->src);
+ copy_address(&binding->addr_b, &pinfo->dst);
+ binding->ptype = pinfo->ptype;
+ binding->port_a = pinfo->srcport;
+ binding->port_b = pinfo->destport;
+ binding->ctx_id = decode_data->dcectxid;
+ binding->transport_salt = dcerpc_get_transport_salt(pinfo);
+ binding->ifname = NULL;
+ /*binding->uuid = NULL;*/
+ binding->ver = 0;
+
+ return binding;
+}
+
+struct dcerpc_decode_as_populate
+{
+ decode_as_add_to_list_func add_to_list;
+ gpointer ui_element;
+};
+
+static void
+decode_dcerpc_add_to_list(gpointer key, gpointer value, gpointer user_data)
+{
+ struct dcerpc_decode_as_populate* populate = (struct dcerpc_decode_as_populate*)user_data;
+
+ /*guid_key *k = key;*/
+ dcerpc_uuid_value *v = (dcerpc_uuid_value *)value;
+
+ if (strcmp(v->name, "(none)"))
+ populate->add_to_list("DCE-RPC", v->name, key, populate->ui_element);
+}
+
+static void
+dcerpc_populate_list(const gchar *table_name _U_, decode_as_add_to_list_func add_to_list, gpointer ui_element)
+{
+ struct dcerpc_decode_as_populate populate;
+
+ populate.add_to_list = add_to_list;
+ populate.ui_element = ui_element;
+
+ g_hash_table_foreach(dcerpc_uuids, decode_dcerpc_add_to_list, &populate);
+}
+
+/* compare two bindings (except the interface related things, e.g. uuid) */
+static gint
+decode_dcerpc_binding_cmp(gconstpointer a, gconstpointer b)
+{
+ const decode_dcerpc_bind_values_t *binding_a = (const decode_dcerpc_bind_values_t *)a;
+ const decode_dcerpc_bind_values_t *binding_b = (const decode_dcerpc_bind_values_t *)b;
+
+
+ /* don't compare uuid and ver! */
+ if (
+ addresses_equal(&binding_a->addr_a, &binding_b->addr_a) &&
+ addresses_equal(&binding_a->addr_b, &binding_b->addr_b) &&
+ binding_a->ptype == binding_b->ptype &&
+ binding_a->port_a == binding_b->port_a &&
+ binding_a->port_b == binding_b->port_b &&
+ binding_a->ctx_id == binding_b->ctx_id &&
+ binding_a->transport_salt == binding_b->transport_salt)
+ {
+ /* equal */
+ return 0;
+ }
+
+ /* unequal */
+ return 1;
+}
+
+/* remove a binding (looking the same way as the given one) */
+static gboolean
+decode_dcerpc_binding_reset(const char *name _U_, gconstpointer pattern)
+{
+ const decode_dcerpc_bind_values_t *binding = (const decode_dcerpc_bind_values_t *)pattern;
+ GSList *le;
+ decode_dcerpc_bind_values_t *old_binding;
+
+ /* find the old binding (if it exists) */
+ le = g_slist_find_custom(decode_dcerpc_bindings,
+ binding,
+ decode_dcerpc_binding_cmp);
+ if (le == NULL)
+ return FALSE;
+
+ old_binding = (decode_dcerpc_bind_values_t *)le->data;
+
+ decode_dcerpc_bindings = g_slist_remove(decode_dcerpc_bindings, le->data);
+
+ free_address(&old_binding->addr_a);
+ free_address(&old_binding->addr_b);
+ g_string_free(old_binding->ifname, TRUE);
+ g_free(old_binding);
+ return FALSE;
+}
+
+static gboolean
+dcerpc_decode_as_change(const char *name, gconstpointer pattern, gpointer handle, gchar* list_name)
+{
+ decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
+ decode_dcerpc_bind_values_t *stored_binding;
+ guid_key *key = *((guid_key**)handle);
+
+
+ binding->ifname = g_string_new(list_name);
+ binding->uuid = key->guid;
+ binding->ver = key->ver;
+
+ /* remove a probably existing old binding */
+ decode_dcerpc_binding_reset(name, binding);
+
+ /* clone the new binding and append it to the list */
+ stored_binding = g_new(decode_dcerpc_bind_values_t,1);
+ *stored_binding = *binding;
+ copy_address(&stored_binding->addr_a, &binding->addr_a);
+ copy_address(&stored_binding->addr_b, &binding->addr_b);
+ stored_binding->ifname = g_string_new(binding->ifname->str);
+
+ decode_dcerpc_bindings = g_slist_append (decode_dcerpc_bindings, stored_binding);
+
+ return FALSE;
+}
static const fragment_items dcerpc_frag_items = {
&ett_dcerpc_fragments,
/* list of hooks to be called when init_protocols is done */
GHookList dcerpc_hooks_init_protos;
-static dcerpc_info *
-get_next_di(void)
-{
- static dcerpc_info di[20];
- static int di_counter = 0;
-
- di_counter++;
- if (di_counter >= 20) {
- di_counter = 0;
- }
-
- memset(&di[di_counter], 0, sizeof(dcerpc_info));
-
- return &di[di_counter];
-}
-
/* try to desegment big DCE/RPC packets over TCP? */
static gboolean dcerpc_cn_desegment = TRUE;
static reassembly_table dcerpc_cl_reassembly_table;
typedef struct _dcerpc_fragment_key {
- address src;
- address dst;
- guint32 id;
- e_uuid_t act_id;
+ address src;
+ address dst;
+ guint32 id;
+ e_guid_t act_id;
} dcerpc_fragment_key;
static guint
dcerpc_fragment_hash(gconstpointer k)
{
- const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
- guint hash_val;
+ const dcerpc_fragment_key* key = (const dcerpc_fragment_key*) k;
+ guint hash_val;
- hash_val = 0;
+ hash_val = 0;
- hash_val += key->id;
- hash_val += key->act_id.Data1;
- hash_val += key->act_id.Data2 << 16;
- hash_val += key->act_id.Data3;
+ hash_val += key->id;
+ hash_val += key->act_id.data1;
+ hash_val += key->act_id.data2 << 16;
+ hash_val += key->act_id.data3;
- return hash_val;
+ return hash_val;
}
static gint
dcerpc_fragment_equal(gconstpointer k1, gconstpointer k2)
{
- const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1;
- const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2;
-
- /*key.id is the first item to compare since item is most
- likely to differ between sessions, thus shortcircuiting
- the comparison of addresses.
- */
- return (((key1->id == key2->id)
- && (ADDRESSES_EQUAL(&key1->src, &key2->src))
- && (ADDRESSES_EQUAL(&key1->dst, &key2->dst))
- && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0))
- ? TRUE : FALSE);
+ const dcerpc_fragment_key* key1 = (const dcerpc_fragment_key*) k1;
+ const dcerpc_fragment_key* key2 = (const dcerpc_fragment_key*) k2;
+
+ /*key.id is the first item to compare since item is most
+ likely to differ between sessions, thus shortcircuiting
+ the comparison of addresses.
+ */
+ return (((key1->id == key2->id)
+ && (addresses_equal(&key1->src, &key2->src))
+ && (addresses_equal(&key1->dst, &key2->dst))
+ && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_guid_t)) == 0))
+ ? TRUE : FALSE);
}
/* allocate a persistent dcerpc fragment key to insert in the hash */
dcerpc_fragment_temporary_key(const packet_info *pinfo, const guint32 id,
const void *data)
{
- dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
- e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
+ dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
+ const e_dce_dg_common_hdr_t *hdr = (const e_dce_dg_common_hdr_t *)data;
- key->src = pinfo->src;
- key->dst = pinfo->dst;
- key->id = id;
- key->act_id = hdr->act_id;
+ copy_address_shallow(&key->src, &pinfo->src);
+ copy_address_shallow(&key->dst, &pinfo->dst);
+ key->id = id;
+ key->act_id = hdr->act_id;
- return key;
+ return key;
}
/* allocate a persistent dcerpc fragment key to insert in the hash */
dcerpc_fragment_persistent_key(const packet_info *pinfo, const guint32 id,
const void *data)
{
- dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
- e_dce_dg_common_hdr_t *hdr = (e_dce_dg_common_hdr_t *)data;
+ dcerpc_fragment_key *key = g_slice_new(dcerpc_fragment_key);
+ const e_dce_dg_common_hdr_t *hdr = (const e_dce_dg_common_hdr_t *)data;
- COPY_ADDRESS(&key->src, &pinfo->src);
- COPY_ADDRESS(&key->dst, &pinfo->dst);
- key->id = id;
- key->act_id = hdr->act_id;
+ copy_address(&key->src, &pinfo->src);
+ copy_address(&key->dst, &pinfo->dst);
+ key->id = id;
+ key->act_id = hdr->act_id;
- return key;
+ return key;
}
static void
dcerpc_fragment_free_temporary_key(gpointer ptr)
{
- dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
+ dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
- if(key)
- g_slice_free(dcerpc_fragment_key, key);
+ if (key)
+ g_slice_free(dcerpc_fragment_key, key);
}
static void
dcerpc_fragment_free_persistent_key(gpointer ptr)
{
- dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
+ dcerpc_fragment_key *key = (dcerpc_fragment_key *)ptr;
- if(key){
- /*
- * Free up the copies of the addresses from the old key.
- */
- g_free((gpointer)key->src.data);
- g_free((gpointer)key->dst.data);
+ if (key) {
+ /*
+ * Free up the copies of the addresses from the old key.
+ */
+ free_address(&key->src);
+ free_address(&key->dst);
- g_slice_free(dcerpc_fragment_key, key);
- }
+ g_slice_free(dcerpc_fragment_key, key);
+ }
}
static const reassembly_table_functions dcerpc_cl_reassembly_table_functions = {
- dcerpc_fragment_hash,
- dcerpc_fragment_equal,
- dcerpc_fragment_temporary_key,
- dcerpc_fragment_persistent_key,
- dcerpc_fragment_free_temporary_key,
- dcerpc_fragment_free_persistent_key
+ dcerpc_fragment_hash,
+ dcerpc_fragment_equal,
+ dcerpc_fragment_temporary_key,
+ dcerpc_fragment_persistent_key,
+ dcerpc_fragment_free_temporary_key,
+ dcerpc_fragment_free_persistent_key
};
static void
/* Hand off verifier data to a registered dissector */
-static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
- proto_tree *tree,
- dcerpc_auth_subdissector_fns *auth_fns,
+static void dissect_auth_verf(packet_info *pinfo,
e_dce_cn_common_hdr_t *hdr,
dcerpc_auth_info *auth_info)
{
- dcerpc_dissect_fnct_t *volatile fn = NULL;
+ dcerpc_dissect_fnct_t *fn = NULL;
/* XXX - "stub" a fake DCERPC INFO STRUCTURE
If a dcerpc_info is really needed, update
the call stacks to include it
*/
FAKE_DCERPC_INFO_STRUCTURE
+ if (auth_info == NULL) {
+ return;
+ }
+
+ if (auth_info->auth_fns == NULL) {
+ return;
+ }
+
switch (hdr->ptype) {
case PDU_BIND:
case PDU_ALTER:
- fn = auth_fns->bind_fn;
+ fn = auth_info->auth_fns->bind_fn;
break;
case PDU_BIND_ACK:
case PDU_ALTER_ACK:
- fn = auth_fns->bind_ack_fn;
+ fn = auth_info->auth_fns->bind_ack_fn;
break;
case PDU_AUTH3:
- fn = auth_fns->auth3_fn;
+ fn = auth_info->auth_fns->auth3_fn;
break;
case PDU_REQ:
- fn = auth_fns->req_verf_fn;
+ case PDU_CO_CANCEL:
+ case PDU_ORPHANED:
+ fn = auth_info->auth_fns->req_verf_fn;
break;
case PDU_RESP:
- fn = auth_fns->resp_verf_fn;
+ case PDU_FAULT:
+ fn = auth_info->auth_fns->resp_verf_fn;
break;
+ default:
/* Don't know how to handle authentication data in this
pdu type. */
-
- default:
- g_warning("attempt to dissect %s pdu authentication data",
- val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
+ proto_tree_add_expert_format(auth_info->auth_tree, pinfo,
+ &ei_dcerpc_invalid_pdu_authentication_attempt,
+ auth_info->auth_tvb, 0, 0,
+ "Don't know how to dissect authentication data for %s pdu type",
+ val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
+ return;
break;
}
if (fn)
- fn(auth_tvb, 0, pinfo, tree, &di, hdr->drep);
- else {
- tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
- proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
- "%s Verifier",
- val_to_str(auth_info->auth_type,
- authn_protocol_vals,
- "Unknown (%u)"));
- }
+ fn(auth_info->auth_tvb, 0, pinfo, auth_info->auth_tree, &di, hdr->drep);
+ else
+ proto_tree_add_expert_format(auth_info->auth_tree, pinfo,
+ &ei_dcerpc_verifier_unavailable,
+ auth_info->auth_tvb, 0, hdr->auth_len,
+ "%s Verifier unavailable",
+ val_to_str(auth_info->auth_type,
+ authn_protocol_vals,
+ "Unknown (%u)"));
+}
+
+static proto_item*
+proto_tree_add_dcerpc_drep(proto_tree *tree, tvbuff_t *tvb, int offset, guint8 drep[], int drep_len)
+{
+ const guint8 byteorder = drep[0] >> 4;
+ const guint8 character = drep[0] & 0x0f;
+ const guint8 fp = drep[1];
+ proto_item *ti = proto_tree_add_bytes(tree, hf_dcerpc_drep, tvb, offset, drep_len, drep);
+ proto_tree *tr = proto_item_add_subtree(ti, ett_dcerpc_drep);
+
+ proto_tree_add_uint(tr, hf_dcerpc_drep_byteorder, tvb, offset, 1, byteorder);
+ proto_tree_add_uint(tr, hf_dcerpc_drep_character, tvb, offset, 1, character);
+ proto_tree_add_uint(tr, hf_dcerpc_drep_fp, tvb, offset+1, 1, fp);
+
+ proto_item_append_text(ti, " (Order: %s, Char: %s, Float: %s)",
+ val_to_str(byteorder, drep_byteorder_vals, "Unknown (%u)"),
+ val_to_str(character, drep_character_vals, "Unknown (%u)"),
+ val_to_str(fp, drep_fp_vals, "Unknown (%u)"));
+ return ti;
}
/* Hand off payload data to a registered dissector */
static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
- tvbuff_t *auth_tvb,
packet_info *pinfo,
- dcerpc_auth_subdissector_fns *auth_fns,
- gboolean is_request,
+ e_dce_cn_common_hdr_t *hdr,
dcerpc_auth_info *auth_info)
{
- dcerpc_decode_data_fnct_t *fn;
+ dcerpc_decode_data_fnct_t *fn = NULL;
- if (is_request)
- fn = auth_fns->req_data_fn;
- else
- fn = auth_fns->resp_data_fn;
+ if (auth_info == NULL)
+ return NULL;
+
+ if (auth_info->auth_fns == NULL)
+ return NULL;
+
+ switch (hdr->ptype) {
+ case PDU_REQ:
+ fn = auth_info->auth_fns->req_data_fn;
+ break;
+ case PDU_RESP:
+ case PDU_FAULT:
+ fn = auth_info->auth_fns->resp_data_fn;
+ break;
+ }
if (fn)
- return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
+ return fn(data_tvb, auth_info->auth_tvb, 0, pinfo, auth_info);
return NULL;
}
+typedef struct _dcerpc_dissector_data
+{
+ dcerpc_uuid_value *sub_proto;
+ dcerpc_info *info;
+ gboolean decrypted;
+ dcerpc_auth_info *auth_info;
+ guint8 *drep;
+ proto_tree *dcerpc_tree;
+} dcerpc_dissector_data_t;
+
/*
* Subdissectors
*/
+dissector_table_t uuid_dissector_table;
+
/* the registered subdissectors */
GHashTable *dcerpc_uuids = NULL;
static gint
dcerpc_uuid_equal(gconstpointer k1, gconstpointer 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)
+ const guid_key *key1 = (const guid_key *)k1;
+ const guid_key *key2 = (const guid_key *)k2;
+ return ((memcmp(&key1->guid, &key2->guid, sizeof (e_guid_t)) == 0)
&& (key1->ver == key2->ver));
}
static guint
dcerpc_uuid_hash(gconstpointer k)
{
- const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
+ const guid_key *key = (const guid_key *)k;
/* This isn't perfect, but the Data1 part of these is almost always
unique. */
- return key->uuid.Data1;
+ return key->guid.data1;
+}
+
+
+static int
+dissect_verification_trailer(packet_info *pinfo, tvbuff_t *tvb, int stub_offset,
+ proto_tree *parent_tree, int *signature_offset);
+
+static void
+show_stub_data(packet_info *pinfo, tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
+ dcerpc_auth_info *auth_info, gboolean is_encrypted)
+{
+ int length, plain_length, auth_pad_len;
+ guint auth_pad_offset;
+
+ /*
+ * 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_reported_length_remaining(tvb, offset) > 0) {
+ auth_pad_len = auth_info?auth_info->auth_pad_len:0;
+ length = tvb_reported_length_remaining(tvb, offset);
+
+ /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
+ plain_length = length - auth_pad_len;
+ if (plain_length < 1) {
+ plain_length = length;
+ auth_pad_len = 0;
+ }
+ auth_pad_offset = offset + plain_length;
+
+ if ((auth_info != NULL) &&
+ (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
+ if (is_encrypted) {
+ proto_tree_add_item(dcerpc_tree, hf_dcerpc_encrypted_stub_data, tvb, offset, length, ENC_NA);
+ /* is the padding is still inside the encrypted blob, don't display it explicit */
+ auth_pad_len = 0;
+ } else {
+ proto_tree_add_item(dcerpc_tree, hf_dcerpc_decrypted_stub_data, tvb, offset, plain_length, ENC_NA);
+ dissect_verification_trailer(pinfo, tvb, offset, dcerpc_tree, NULL);
+ }
+ } else {
+ proto_tree_add_item(dcerpc_tree, hf_dcerpc_stub_data, tvb, offset, plain_length, ENC_NA);
+ dissect_verification_trailer(pinfo, tvb, offset, dcerpc_tree, NULL);
+ }
+ /* If there is auth padding at the end of the stub, display it */
+ if (auth_pad_len != 0) {
+ proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_padding, tvb, auth_pad_offset, auth_pad_len, ENC_NA);
+ }
+ }
+}
+
+static int
+dissect_dcerpc_guid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+ dcerpc_dissector_data_t* dissector_data = (dcerpc_dissector_data_t*)data;
+ const gchar *name = NULL;
+ dcerpc_sub_dissector *proc;
+ int (*volatile sub_dissect)(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, dcerpc_info *di, guint8 *drep) = NULL;
+ proto_item *pi, *sub_item;
+ proto_tree *sub_tree;
+ volatile guint length;
+ guint reported_length;
+ volatile gint offset = 0;
+ tvbuff_t *volatile stub_tvb;
+ tvbuff_t *volatile payload_tvb = NULL;
+ volatile guint auth_pad_len;
+ volatile int auth_pad_offset;
+ const char *volatile saved_proto;
+
+ for (proc = dissector_data->sub_proto->procs; proc->name; proc++) {
+ if (proc->num == dissector_data->info->call_data->opnum) {
+ name = proc->name;
+ break;
+ }
+ }
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, dissector_data->sub_proto->name);
+
+ if (!name)
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown operation %u %s",
+ dissector_data->info->call_data->opnum,
+ (dissector_data->info->ptype == PDU_REQ) ? "request" : "response");
+ else
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
+ name, (dissector_data->info->ptype == PDU_REQ) ? "request" : "response");
+
+ sub_dissect = (dissector_data->info->ptype == PDU_REQ) ?
+ proc->dissect_rqst : proc->dissect_resp;
+
+ sub_item = proto_tree_add_item(tree, dissector_data->sub_proto->proto_id,
+ tvb,//(decrypted_tvb != NULL)?decrypted_tvb:tvb,
+ 0, -1, ENC_NA);
+ sub_tree = proto_item_add_subtree(sub_item, dissector_data->sub_proto->ett);
+ if (!name)
+ proto_item_append_text(sub_item, ", unknown operation %u",
+ dissector_data->info->call_data->opnum);
+ else
+ proto_item_append_text(sub_item, ", %s", name);
+
+ if (tree) {
+ /*
+ * Put the operation number into the tree along with
+ * the operation's name.
+ */
+ if (dissector_data->sub_proto->opnum_hf != -1)
+ proto_tree_add_uint_format(sub_tree, dissector_data->sub_proto->opnum_hf,
+ tvb, 0, 0, dissector_data->info->call_data->opnum,
+ "Operation: %s (%u)",
+ name ? name : "Unknown operation",
+ dissector_data->info->call_data->opnum);
+ else
+ proto_tree_add_uint_format_value(sub_tree, hf_dcerpc_op, tvb,
+ 0, 0, dissector_data->info->call_data->opnum,
+ "%s (%u)",
+ name ? name : "Unknown operation",
+ dissector_data->info->call_data->opnum);
+
+ if ((dissector_data->info->ptype == PDU_REQ) && (dissector_data->info->call_data->rep_frame != 0)) {
+ pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
+ tvb, 0, 0, dissector_data->info->call_data->rep_frame);
+ PROTO_ITEM_SET_GENERATED(pi);
+ }
+ if ((dissector_data->info->ptype == PDU_RESP) && (dissector_data->info->call_data->req_frame != 0)) {
+ pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
+ tvb, 0, 0, dissector_data->info->call_data->req_frame);
+ PROTO_ITEM_SET_GENERATED(pi);
+ }
+ } /* tree */
+
+ if (!dissector_data->decrypted || (sub_dissect == NULL))
+ {
+ show_stub_data(pinfo, tvb, 0, sub_tree, dissector_data->auth_info, !dissector_data->decrypted);
+ return tvb_captured_length(tvb);
+ }
+
+ /* Either there was no encryption or we successfully decrypted
+ the encrypted payload. */
+
+ /* We have a subdissector - call it. */
+ saved_proto = pinfo->current_proto;
+ pinfo->current_proto = dissector_data->sub_proto->name;
+
+ init_ndr_pointer_list(dissector_data->info);
+
+ length = tvb_captured_length(tvb);
+ reported_length = tvb_reported_length(tvb);
+
+ /*
+ * Remove the authentication padding from the stub data.
+ */
+ if ((dissector_data->auth_info != NULL) && (dissector_data->auth_info->auth_pad_len != 0)) {
+ if (reported_length >= dissector_data->auth_info->auth_pad_len) {
+ /*
+ * OK, the padding length isn't so big that it
+ * exceeds the stub length. Trim the reported
+ * length of the tvbuff.
+ */
+ reported_length -= dissector_data->auth_info->auth_pad_len;
+
+ /*
+ * If that exceeds the actual amount of data in
+ * the tvbuff (which means we have at least one
+ * byte of authentication padding in the tvbuff),
+ * trim the actual amount.
+ */
+ if (length > reported_length)
+ length = reported_length;
+
+ stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
+ auth_pad_len = dissector_data->auth_info->auth_pad_len;
+ auth_pad_offset = reported_length;
+ } else {
+ /*
+ * The padding length exceeds the stub length.
+ * Don't bother dissecting the stub, trim the padding
+ * length to what's in the stub data, and show the
+ * entire stub as authentication padding.
+ */
+ stub_tvb = NULL;
+ auth_pad_len = reported_length;
+ auth_pad_offset = 0;
+ length = 0;
+ }
+ } else {
+ /*
+ * No authentication padding.
+ */
+ stub_tvb = tvb;
+ auth_pad_len = 0;
+ auth_pad_offset = 0;
+ }
+
+ if (sub_item) {
+ proto_item_set_len(sub_item, length);
+ }
+
+ if (stub_tvb != NULL) {
+ /*
+ * Catch all exceptions other than BoundsError, so that even
+ * if the stub data is bad, we still show the authentication
+ * padding, if any.
+ *
+ * If we get BoundsError, it means the frame was cut short
+ * by a snapshot length, so there's nothing more to
+ * dissect; just re-throw that exception.
+ */
+ TRY {
+ proto_tree *stub_tree = NULL;
+ int remaining;
+ int trailer_start_offset = -1;
+ int trailer_end_offset = -1;
+
+ stub_tree = proto_tree_add_subtree_format(dissector_data->dcerpc_tree,
+ stub_tvb, 0, length,
+ ett_dcerpc_complete_stub_data, NULL,
+ "Complete stub data (%d byte%s)", length,
+ plurality(length, "", "s"));
+ trailer_end_offset = dissect_verification_trailer(pinfo,
+ stub_tvb, 0,
+ stub_tree,
+ &trailer_start_offset);
+
+ if (trailer_end_offset != -1) {
+ remaining = tvb_captured_length_remaining(stub_tvb,
+ trailer_start_offset);
+ length -= remaining;
+
+ if (sub_item) {
+ proto_item_set_len(sub_item, length);
+ }
+ } else {
+ proto_item *payload_item;
+
+ payload_item = proto_tree_add_item(stub_tree,
+ hf_dcerpc_payload_stub_data,
+ stub_tvb, 0, length, ENC_NA);
+ proto_item_append_text(payload_item, " (%d byte%s)",
+ length, plurality(length, "", "s"));
+ }
+
+ payload_tvb = tvb_new_subset(stub_tvb, 0, length, length);
+ offset = sub_dissect(payload_tvb, 0, pinfo, sub_tree,
+ dissector_data->info, dissector_data->drep);
+
+ /* If we have a subdissector and it didn't dissect all
+ data in the tvb, make a note of it. */
+ remaining = tvb_reported_length_remaining(stub_tvb, offset);
+
+ if (trailer_end_offset != -1) {
+ if (offset > trailer_start_offset) {
+ remaining = offset - trailer_start_offset;
+ proto_tree_add_item(sub_tree, hf_dcerpc_stub_data_with_sec_vt,
+ stub_tvb, trailer_start_offset, remaining, ENC_NA);
+ col_append_fstr(pinfo->cinfo, COL_INFO,
+ "[Payload with Verification Trailer (%d byte%s)]",
+ remaining,
+ plurality(remaining, "", "s"));
+ remaining = 0;
+ } else {
+ remaining = trailer_start_offset - offset;
+ }
+ }
+
+ if (remaining > 0) {
+ proto_tree_add_expert(sub_tree, pinfo, &ei_dcerpc_long_frame, stub_tvb, offset, remaining);
+ col_append_fstr(pinfo->cinfo, COL_INFO,
+ "[Long frame (%d byte%s)]",
+ remaining,
+ plurality(remaining, "", "s"));
+ }
+ } CATCH_NONFATAL_ERRORS {
+ /*
+ * Somebody threw an exception that means that there
+ * was a problem dissecting the payload; that means
+ * that a dissector was found, so we don't need to
+ * dissect the payload as data or update the protocol
+ * or info columns.
+ *
+ * Just show the exception and then drive on to show
+ * the authentication padding.
+ */
+ show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
+ } ENDTRY;
+ }
+
+ /* If there is auth padding at the end of the stub, display it */
+ if (auth_pad_len != 0) {
+ proto_tree_add_item(sub_tree, hf_dcerpc_auth_padding, tvb, auth_pad_offset, auth_pad_len, ENC_NA);
+ }
+
+ pinfo->current_proto = saved_proto;
+
+ return tvb_captured_length(tvb);
}
void
-dcerpc_init_uuid(int proto, int ett, e_uuid_t *uuid, guint16 ver,
+dcerpc_init_uuid(int proto, int ett, e_guid_t *uuid, guint16 ver,
dcerpc_sub_dissector *procs, int opnum_hf)
{
- dcerpc_uuid_key *key = (dcerpc_uuid_key *)g_malloc(sizeof (*key));
+ guid_key *key = (guid_key *)g_malloc(sizeof (*key));
dcerpc_uuid_value *value = (dcerpc_uuid_value *)g_malloc(sizeof (*value));
header_field_info *hf_info;
module_t *samr_module;
const char *filter_name = proto_get_protocol_filter_name(proto);
+ dissector_handle_t guid_handle;
- key->uuid = *uuid;
+ key->guid = *uuid;
key->ver = ver;
value->proto = find_protocol_by_id(proto);
hf_info = proto_registrar_get_nth(opnum_hf);
hf_info->strings = value_string_from_subdissectors(procs);
+ /* Register the GUID with the dissector table */
+ guid_handle = create_dissector_handle( dissect_dcerpc_guid, proto);
+ dissector_add_guid( "dcerpc.uuid", key, guid_handle );
+
/* add this GUID to the global name resolving */
guids_add_uuid(uuid, proto_get_protocol_short_name(value->proto));
* or NULL if the protocol/version is not known to wireshark.
*/
const char *
-dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
+dcerpc_get_proto_name(e_guid_t *uuid, guint16 ver)
{
- dcerpc_uuid_key key;
- dcerpc_uuid_value *sub_proto;
+ dissector_handle_t handle;
+ guid_key key;
- key.uuid = *uuid;
+ key.guid = *uuid;
key.ver = ver;
- if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
+
+ handle = dissector_get_guid_handle(uuid_dissector_table, &key);
+ if (handle == NULL) {
return NULL;
}
- return sub_proto->name;
+
+ return dissector_handle_get_short_name(handle);
}
/* Function to find the opnum hf-field of a registered protocol
* or -1 if the protocol/version is not known to wireshark.
*/
int
-dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
+dcerpc_get_proto_hf_opnum(e_guid_t *uuid, guint16 ver)
{
- dcerpc_uuid_key key;
+ guid_key key;
dcerpc_uuid_value *sub_proto;
- key.uuid = *uuid;
+ key.guid = *uuid;
key.ver = ver;
if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
return -1;
* or NULL if the protocol/version is not known to wireshark.
*/
dcerpc_sub_dissector *
-dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
+dcerpc_get_proto_sub_dissector(e_guid_t *uuid, guint16 ver)
{
- dcerpc_uuid_key key;
- dcerpc_uuid_value *sub_proto;
-
- key.uuid = *uuid;
- key.ver = ver;
- if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
- return NULL;
- }
- return sub_proto->procs;
-}
-
-
-/*
- * To keep track of ctx_id mappings.
- *
- * Every time we see a bind call we update this table.
- * Note that we always specify a SMB FID. For non-SMB transports this
- * value is 0.
- */
-static GHashTable *dcerpc_binds = NULL;
+ guid_key key;
+ dcerpc_uuid_value *sub_proto;
+
+ key.guid = *uuid;
+ key.ver = ver;
+ if (!(sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key))) {
+ return NULL;
+ }
+ return sub_proto->procs;
+}
-typedef struct _dcerpc_bind_key {
- conversation_t *conv;
- guint16 ctx_id;
- guint16 smb_fid;
-} dcerpc_bind_key;
-typedef struct _dcerpc_bind_value {
- e_uuid_t uuid;
- guint16 ver;
- e_uuid_t transport;
-} dcerpc_bind_value;
static gint
dcerpc_bind_equal(gconstpointer k1, gconstpointer k2)
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));
+ && (key1->transport_salt == key2->transport_salt));
}
static guint
const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
guint hash;
- hash = GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
- return hash;
+ hash = GPOINTER_TO_UINT(key->conv);
+ hash += key->ctx_id;
+ /* sizeof(guint) might be smaller than sizeof(guint64) */
+ hash += (guint)key->transport_salt;
+ hash += (guint)(key->transport_salt << sizeof(guint));
+ return hash;
}
/*
typedef struct _dcerpc_cn_call_key {
conversation_t *conv;
guint32 call_id;
- guint16 smb_fid;
+ guint64 transport_salt;
} dcerpc_cn_call_key;
typedef struct _dcerpc_dg_call_key {
conversation_t *conv;
guint32 seqnum;
- e_uuid_t act_id ;
+ e_guid_t act_id ;
} dcerpc_dg_call_key;
const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
return ((key1->conv == key2->conv)
&& (key1->call_id == key2->call_id)
- && (key1->smb_fid == key2->smb_fid));
+ && (key1->transport_salt == key2->transport_salt));
}
static gint
const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
return ((key1->conv == key2->conv)
&& (key1->seqnum == key2->seqnum)
- && ((memcmp(&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0)));
+ && ((memcmp(&key1->act_id, &key2->act_id, sizeof (e_guid_t)) == 0)));
}
static guint
dcerpc_cn_call_hash(gconstpointer k)
{
const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
- return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
+ guint hash;
+
+ hash = GPOINTER_TO_UINT(key->conv);
+ hash += key->call_id;
+ /* sizeof(guint) might be smaller than sizeof(guint64) */
+ hash += (guint)key->transport_salt;
+ hash += (guint)(key->transport_salt << sizeof(guint));
+
+ return hash;
}
static guint
dcerpc_dg_call_hash(gconstpointer k)
{
const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
- return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
- + (key->act_id.Data2 << 16) + key->act_id.Data3
- + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
- + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
- + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
- + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
+ return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.data1
+ + (key->act_id.data2 << 16) + key->act_id.data3
+ + (key->act_id.data4[0] << 24) + (key->act_id.data4[1] << 16)
+ + (key->act_id.data4[2] << 8) + (key->act_id.data4[3] << 0)
+ + (key->act_id.data4[4] << 24) + (key->act_id.data4[5] << 16)
+ + (key->act_id.data4[6] << 8) + (key->act_id.data4[7] << 0));
}
/* to keep track of matched calls/responses
return key->frame;
}
+static gboolean
+uuid_equal(e_guid_t *uuid1, e_guid_t *uuid2)
+{
+ if( (uuid1->data1 != uuid2->data1)
+ ||(uuid1->data2 != uuid2->data2)
+ ||(uuid1->data3 != uuid2->data3)
+ ||(uuid1->data4[0] != uuid2->data4[0])
+ ||(uuid1->data4[1] != uuid2->data4[1])
+ ||(uuid1->data4[2] != uuid2->data4[2])
+ ||(uuid1->data4[3] != uuid2->data4[3])
+ ||(uuid1->data4[4] != uuid2->data4[4])
+ ||(uuid1->data4[5] != uuid2->data4[5])
+ ||(uuid1->data4[6] != uuid2->data4[6])
+ ||(uuid1->data4[7] != uuid2->data4[7]) ){
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+dcerpcstat_init(struct register_srt* srt, GArray* srt_array, srt_gui_init_cb gui_callback, void* gui_data)
+{
+ dcerpcstat_tap_data_t* tap_data = (dcerpcstat_tap_data_t*)get_srt_table_param_data(srt);
+ srt_stat_table *dcerpc_srt_table;
+ int i, hf_opnum;
+ dcerpc_sub_dissector *procs;
+
+ DISSECTOR_ASSERT(tap_data);
+
+ hf_opnum = dcerpc_get_proto_hf_opnum(&tap_data->uuid, tap_data->ver);
+ procs = dcerpc_get_proto_sub_dissector(&tap_data->uuid, tap_data->ver);
+
+ if(hf_opnum != -1){
+ dcerpc_srt_table = init_srt_table(tap_data->prog, NULL, srt_array, tap_data->num_procedures, NULL, proto_registrar_get_nth(hf_opnum)->abbrev, gui_callback, gui_data, tap_data);
+ } else {
+ dcerpc_srt_table = init_srt_table(tap_data->prog, NULL, srt_array, tap_data->num_procedures, NULL, NULL, gui_callback, gui_data, tap_data);
+ }
+
+ for(i=0;i<tap_data->num_procedures;i++){
+ int j;
+ const char *proc_name;
+
+ proc_name = "unknown";
+ for(j=0;procs[j].name;j++)
+ {
+ if (procs[j].num == i)
+ {
+ proc_name = procs[j].name;
+ }
+ }
+
+ init_srt_table_row(dcerpc_srt_table, i, proc_name);
+ }
+}
+
+static int
+dcerpcstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *prv)
+{
+ guint i = 0;
+ srt_stat_table *dcerpc_srt_table;
+ srt_data_t *data = (srt_data_t *)pss;
+ const dcerpc_info *ri = (const dcerpc_info *)prv;
+ dcerpcstat_tap_data_t* tap_data;
+
+ dcerpc_srt_table = g_array_index(data->srt_array, srt_stat_table*, i);
+ tap_data = (dcerpcstat_tap_data_t*)dcerpc_srt_table->table_specific_data;
+
+ if(!ri->call_data){
+ return 0;
+ }
+ if(!ri->call_data->req_frame){
+ /* we have not seen the request so we don't know the delta*/
+ return 0;
+ }
+ if(ri->call_data->opnum >= tap_data->num_procedures){
+ /* don't handle this since it's outside of known table */
+ return 0;
+ }
+
+ /* we are only interested in reply packets */
+ if(ri->ptype != PDU_RESP){
+ return 0;
+ }
+
+ /* we are only interested in certain program/versions */
+ if( (!uuid_equal( (&ri->call_data->uuid), (&tap_data->uuid)))
+ ||(ri->call_data->ver != tap_data->ver)){
+ return 0;
+ }
+
+ add_srt_table_data(dcerpc_srt_table, ri->call_data->opnum, &ri->call_data->req_time, pinfo);
+
+ return 1;
+}
+
+static guint
+dcerpcstat_param(register_srt_t* srt, const char* opt_arg, char** err)
+{
+ int pos = 0;
+ guint32 i, max_procs;
+ dcerpcstat_tap_data_t* tap_data;
+ guint d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
+ int major, minor;
+ guint16 ver;
+ dcerpc_sub_dissector *procs;
+
+ if (sscanf(opt_arg, ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d%n",
+ &d1,&d2,&d3,&d40,&d41,&d42,&d43,&d44,&d45,&d46,&d47,&major,&minor,&pos) == 13)
+ {
+ if ((major < 0) || (major > 65535)) {
+ *err = g_strdup_printf("dcerpcstat_init() Major version number %d is invalid - must be positive and <= 65535", major);
+ return pos;
+ }
+ if ((minor < 0) || (minor > 65535)) {
+ *err = g_strdup_printf("dcerpcstat_init() Minor version number %d is invalid - must be positive and <= 65535", minor);
+ return pos;
+ }
+ ver = major;
+
+ tap_data = g_new0(dcerpcstat_tap_data_t, 1);
+
+ tap_data->uuid.data1 = d1;
+ tap_data->uuid.data2 = d2;
+ tap_data->uuid.data3 = d3;
+ tap_data->uuid.data4[0] = d40;
+ tap_data->uuid.data4[1] = d41;
+ tap_data->uuid.data4[2] = d42;
+ tap_data->uuid.data4[3] = d43;
+ tap_data->uuid.data4[4] = d44;
+ tap_data->uuid.data4[5] = d45;
+ tap_data->uuid.data4[6] = d46;
+ tap_data->uuid.data4[7] = d47;
+
+ procs = dcerpc_get_proto_sub_dissector(&tap_data->uuid, ver);
+ tap_data->prog = dcerpc_get_proto_name(&tap_data->uuid, ver);
+ tap_data->ver = ver;
+
+ for(i=0,max_procs=0;procs[i].name;i++)
+ {
+ if(procs[i].num>max_procs)
+ {
+ max_procs = procs[i].num;
+ }
+ }
+ tap_data->num_procedures = max_procs+1;
+
+ set_srt_table_param_data(srt, tap_data);
+ }
+ else
+ {
+ *err = g_strdup_printf("<uuid>,<major version>.<minor version>[,<filter>]");
+ }
+
+ return pos;
+}
/*
* Utility functions. Modeled after packet-rpc.c
*/
+int
+dissect_dcerpc_char(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
+ proto_tree *tree, guint8 *drep,
+ int hfindex, guint8 *pdata)
+{
+ guint8 data;
+
+ /*
+ * XXX - fix to handle EBCDIC if we ever support EBCDIC FT_CHAR.
+ */
+ data = tvb_get_guint8(tvb, offset);
+ if (hfindex != -1) {
+ proto_tree_add_item(tree, hfindex, tvb, offset, 1, ENC_ASCII|DREP_ENC_INTEGER(drep));
+ }
+ if (pdata)
+ *pdata = data;
+ tvb_ensure_bytes_exist(tvb, offset, 1);
+ return offset + 1;
+}
+
int
dissect_dcerpc_uint8(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
proto_tree *tree, guint8 *drep,
guint8 data;
data = tvb_get_guint8(tvb, offset);
- if (tree) {
+ if (hfindex != -1) {
proto_tree_add_item(tree, hfindex, tvb, offset, 1, DREP_ENC_INTEGER(drep));
}
if (pdata)
*pdata = data;
+ tvb_ensure_bytes_exist(tvb, offset, 1);
return offset + 1;
}
? tvb_get_letohs(tvb, offset)
: tvb_get_ntohs(tvb, offset));
- if (tree) {
+ if (hfindex != -1) {
proto_tree_add_item(tree, hfindex, tvb, offset, 2, DREP_ENC_INTEGER(drep));
}
if (pdata)
*pdata = data;
+ tvb_ensure_bytes_exist(tvb, offset, 2);
return offset + 2;
}
? tvb_get_letohl(tvb, offset)
: tvb_get_ntohl(tvb, offset));
- if (tree) {
+ if (hfindex != -1) {
proto_tree_add_item(tree, hfindex, tvb, offset, 4, DREP_ENC_INTEGER(drep));
}
if (pdata)
*pdata = data;
+ tvb_ensure_bytes_exist(tvb, offset, 4);
return offset+4;
}
tv.secs = data;
tv.nsecs = 0;
- if (tree) {
+ if (hfindex != -1) {
if (data == 0xffffffff) {
/* special case, no time specified */
proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
if (pdata)
*pdata = data;
+ tvb_ensure_bytes_exist(tvb, offset, 4);
return offset+4;
}
int
dissect_dcerpc_uint64(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
- proto_tree *tree, guint8 *drep,
+ proto_tree *tree, dcerpc_info *di, guint8 *drep,
int hfindex, guint64 *pdata)
{
guint64 data;
? tvb_get_letoh64(tvb, offset)
: tvb_get_ntoh64(tvb, offset));
- if (tree) {
+ if (hfindex != -1) {
header_field_info *hfinfo;
/* This might be a field that is either 32bit, in NDR or
proto_tree_add_int64(tree, hfindex, tvb, offset, 8, data);
break;
default:
- DISSECTOR_ASSERT(data <= G_MAXUINT32);
+ /* The value is truncated to 32bits. 64bit values have only been
+ seen on fuzz-tested files */
+ DISSECTOR_ASSERT((di->call_data->flags & DCERPC_IS_NDR64) || (data <= G_MAXUINT32));
proto_tree_add_uint(tree, hfindex, tvb, offset, 8, (guint32)data);
}
}
if (pdata)
*pdata = data;
+ tvb_ensure_bytes_exist(tvb, offset, 8);
return offset+8;
}
data = ((drep[0] & DREP_LITTLE_ENDIAN)
? tvb_get_letohieee_float(tvb, offset)
: tvb_get_ntohieee_float(tvb, offset));
- if (tree) {
+ if (tree && hfindex != -1) {
proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
}
break;
/* ToBeDone: non IEEE floating formats */
/* Set data to a negative infinity value */
data = -G_MAXFLOAT;
- if (tree) {
+ if (tree && hfindex != -1) {
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;
+ tvb_ensure_bytes_exist(tvb, offset, 4);
return offset + 4;
}
data = ((drep[0] & DREP_LITTLE_ENDIAN)
? tvb_get_letohieee_double(tvb, offset)
: tvb_get_ntohieee_double(tvb, offset));
- if (tree) {
+ if (tree && hfindex != -1) {
proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
}
break;
/* ToBeDone: non IEEE double formats */
/* Set data to a negative infinity value */
data = -G_MAXDOUBLE;
- if (tree) {
+ if (tree && hfindex != -1) {
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;
+ tvb_ensure_bytes_exist(tvb, offset, 8);
return offset + 8;
}
int
dissect_dcerpc_uuid_t(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
proto_tree *tree, guint8 *drep,
- int hfindex, e_uuid_t *pdata)
+ int hfindex, e_guid_t *pdata)
{
- e_uuid_t uuid;
+ e_guid_t uuid;
if (drep[0] & DREP_LITTLE_ENDIAN) {
} else {
tvb_get_ntohguid(tvb, offset, (e_guid_t *) &uuid);
}
- if (tree) {
+ if (tree && hfindex != -1) {
proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
}
if (pdata) {
}
void
-dcerpc_tvb_get_uuid(tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
+dcerpc_tvb_get_uuid(tvbuff_t *tvb, gint offset, guint8 *drep, e_guid_t *uuid)
{
if (drep[0] & DREP_LITTLE_ENDIAN) {
tvb_get_letohguid(tvb, offset, (e_guid_t *) uuid);
/* NDR arrays */
/* function to dissect a unidimensional conformant array */
-int
-dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
+static int
+dissect_ndr_ucarray_core(tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *tree, dcerpc_info *di, guint8 *drep,
- dcerpc_dissect_fnct_t *fnct)
+ dcerpc_dissect_fnct_t *fnct_bytes,
+ dcerpc_dissect_fnct_blk_t *fnct_block)
{
guint32 i;
int old_offset;
int conformance_size = 4;
+ /* ensure that just one pointer is set in the call */
+ DISSECTOR_ASSERT((fnct_bytes && !fnct_block) || (!fnct_bytes && fnct_block));
+
if (di->call_data->flags & DCERPC_IS_NDR64) {
conformance_size = 8;
}
proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, conformance_size, di->array_max_count);
/* real run, dissect the elements */
- for(i=0; i<di->array_max_count; i++) {
- offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
+ if (fnct_block) {
+ offset = (*fnct_block)(tvb, offset, di->array_max_count,
+ pinfo, tree, di, drep);
+ } else {
+ for (i=0 ;i<di->array_max_count; i++) {
+ offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
+ }
}
}
return offset;
}
+int
+dissect_ndr_ucarray_block(tvbuff_t *tvb, gint offset, packet_info *pinfo,
+ proto_tree *tree, dcerpc_info *di, guint8 *drep,
+ dcerpc_dissect_fnct_blk_t *fnct)
+{
+ return dissect_ndr_ucarray_core(tvb, offset, pinfo, tree, di, drep, NULL, fnct);
+}
+
+int
+dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
+ proto_tree *tree, dcerpc_info *di, guint8 *drep,
+ dcerpc_dissect_fnct_t *fnct)
+{
+ return dissect_ndr_ucarray_core(tvb, offset, pinfo, tree, di, drep, fnct, NULL);
+}
+
/* function to dissect a unidimensional conformant and varying array
* depending on the dissection function passed as a parameter,
* content of the array will be dissected as a block or byte by byte
/* real run, dissect the elements */
if (fnct_block) {
- offset = (*fnct_block)(tvb, offset, di->array_actual_count, pinfo, tree, drep);
- } else {
- for(i=0 ;i<di->array_actual_count; i++) {
+ offset = (*fnct_block)(tvb, offset, di->array_actual_count,
+ pinfo, tree, di, drep);
+ } else if (fnct_bytes) {
+ for (i=0 ;i<di->array_actual_count; i++) {
old_offset = offset;
offset = (*fnct_bytes)(tvb, offset, pinfo, tree, di, drep);
- if (offset <= old_offset)
- THROW(ReportedBoundsError);
+ /* Make sure we're moving forward */
+ if (old_offset >= offset)
+ break;
}
}
}
proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, conformance_size, di->array_actual_count);
/* real run, dissect the elements */
- for(i=0; i<di->array_actual_count; i++) {
+ for (i=0; i<di->array_actual_count; i++) {
offset = (*fnct)(tvb, offset, pinfo, tree, di, drep);
}
}
hf_dcerpc_array_actual_count, &len);
DISSECTOR_ASSERT(len <= G_MAXUINT32);
- if (tree && len) {
- tvb_ensure_bytes_exist(tvb, offset, (guint32)len);
- proto_tree_add_item(tree, hf_dcerpc_array_buffer,
- tvb, offset, (guint32)len, ENC_NA);
+ if (len) {
+ proto_tree_add_item(tree, di->hf_index, tvb, offset, (guint32)len,
+ ENC_NA);
}
offset += (guint32)len;
proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
int hfindex, gboolean add_subtree, char **data)
{
+ header_field_info *hfinfo;
proto_item *string_item;
proto_tree *string_tree;
guint64 len;
guint32 buffer_len;
char *s;
- header_field_info *hfinfo;
+
+ /* Make sure this really is a string field. */
+ hfinfo = proto_registrar_get_nth(hfindex);
+ DISSECTOR_ASSERT(hfinfo->type == FT_STRING);
if (di->conformant_run) {
/* just a run to handle conformant arrays, no scalars to dissect */
}
if (add_subtree) {
- string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
+ string_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_dcerpc_string, &string_item,
proto_registrar_get_name(hfindex));
- string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
} else {
string_item = NULL;
string_tree = tree;
offset = dissect_ndr_uint3264(tvb, offset, pinfo, string_tree, di, drep,
hf_dcerpc_array_actual_count, &len);
- DISSECTOR_ASSERT(len <= G_MAXUINT32);
+ /* The value is truncated to 32bits. 64bit values have only been
+ seen on fuzztested files */
buffer_len = size_is * (guint32)len;
/* Adjust offset */
if (!di->no_align && (offset % size_is))
offset += size_is - (offset % size_is);
+ /*
+ * "tvb_get_string_enc()" throws an exception if the entire string
+ * isn't in the tvbuff. If the length is bogus, this should
+ * keep us from trying to allocate an immensely large buffer.
+ * (It won't help if the length is *valid* but immensely large,
+ * but that's another matter; in any case, that would happen only
+ * if we had an immensely large tvbuff....)
+ *
+ * XXX - so why are we doing tvb_ensure_bytes_exist()?
+ */
+ tvb_ensure_bytes_exist(tvb, offset, buffer_len);
if (size_is == sizeof(guint16)) {
- /* XXX - use drep to determine the byte order? */
- /* XXX - once we have an ENC_ value for UTF-16, just use
- proto_tree_add_item() with the appropriate ENC_ value? */
- /* XXX - should this ever be used with something that's *not*
- an FT_STRING? */
- s = tvb_get_unicode_string(wmem_packet_scope(), tvb, offset, buffer_len, ENC_LITTLE_ENDIAN);
- if (tree && buffer_len) {
- hfinfo = proto_registrar_get_nth(hfindex);
- tvb_ensure_bytes_exist(tvb, offset, buffer_len);
- if (hfinfo->type == FT_STRING) {
- proto_tree_add_string(string_tree, hfindex, tvb, offset,
- buffer_len, s);
- } else {
- proto_tree_add_item(string_tree, hfindex, tvb, offset,
- buffer_len, DREP_ENC_INTEGER(drep));
- }
- }
-
- } else {
/*
- * "tvb_get_string()" throws an exception if the entire string
- * isn't in the tvbuff. If the length is bogus, this should
- * keep us from trying to allocate an immensely large buffer.
- * (It won't help if the length is *valid* but immensely large,
- * but that's another matter; in any case, that would happen only
- * if we had an immensely large tvbuff....)
+ * Assume little-endian UTF-16.
*
- * XXX - if this is an octet string, does the byte order
- * matter? Will this ever be anything *other* than an
- * octet string? What if size_is is neither 1 nor 2?
+ * XXX - is this always little-endian?
+ */
+ s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
+ ENC_UTF_16|ENC_LITTLE_ENDIAN);
+ } else {
+ /*
+ * XXX - what if size_is is neither 1 nor 2?
*/
- tvb_ensure_bytes_exist(tvb, offset, buffer_len);
- s = tvb_get_string(wmem_packet_scope(), tvb, offset, buffer_len);
- if (tree && buffer_len)
- proto_tree_add_item(string_tree, hfindex, tvb, offset,
- buffer_len, DREP_ENC_INTEGER(drep));
+ s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
+ DREP_ENC_CHAR(drep));
}
+ if (tree && buffer_len)
+ proto_tree_add_string(string_tree, hfindex, tvb, offset,
+ buffer_len, s);
if (string_item != NULL)
proto_item_append_text(string_item, ": %s", s);
proto_tree *tree, dcerpc_info *di, guint8 *drep, int size_is,
int hfindex, gboolean add_subtree, char **data)
{
+ header_field_info *hfinfo;
proto_item *string_item;
proto_tree *string_tree;
guint64 len;
guint32 buffer_len;
char *s;
- header_field_info *hfinfo;
+
+ /* Make sure this really is a string field. */
+ hfinfo = proto_registrar_get_nth(hfindex);
+ DISSECTOR_ASSERT(hfinfo->type == FT_STRING);
if (di->conformant_run) {
/* just a run to handle conformant arrays, no scalars to dissect */
}
if (add_subtree) {
- string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
+ string_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_dcerpc_string, &string_item,
proto_registrar_get_name(hfindex));
- string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
} else {
string_item = NULL;
string_tree = tree;
if (!di->no_align && (offset % size_is))
offset += size_is - (offset % size_is);
+ /*
+ * "tvb_get_string_enc()" throws an exception if the entire string
+ * isn't in the tvbuff. If the length is bogus, this should
+ * keep us from trying to allocate an immensely large buffer.
+ * (It won't help if the length is *valid* but immensely large,
+ * but that's another matter; in any case, that would happen only
+ * if we had an immensely large tvbuff....)
+ *
+ * XXX - so why are we doing tvb_ensure_bytes_exist()?
+ */
+ tvb_ensure_bytes_exist(tvb, offset, buffer_len);
if (size_is == sizeof(guint16)) {
- /* XXX - use drep to determine the byte order? */
- /* XXX - once we have an ENC_ value for UTF-16, just use
- proto_tree_add_item() with the appropriate ENC_ value? */
- /* XXX - should this ever be used with something that's *not*
- an FT_STRING? */
- s = tvb_get_unicode_string(wmem_packet_scope(), tvb, offset, buffer_len, ENC_LITTLE_ENDIAN);
- if (tree && buffer_len) {
- hfinfo = proto_registrar_get_nth(hfindex);
- tvb_ensure_bytes_exist(tvb, offset, buffer_len);
- if (hfinfo->type == FT_STRING) {
- proto_tree_add_string(string_tree, hfindex, tvb, offset,
- buffer_len, s);
- } else {
- proto_tree_add_item(string_tree, hfindex, tvb, offset,
- buffer_len, DREP_ENC_INTEGER(drep));
- }
- }
-
- } else {
/*
- * "tvb_get_string()" throws an exception if the entire string
- * isn't in the tvbuff. If the length is bogus, this should
- * keep us from trying to allocate an immensely large buffer.
- * (It won't help if the length is *valid* but immensely large,
- * but that's another matter; in any case, that would happen only
- * if we had an immensely large tvbuff....)
+ * Assume little-endian UTF-16.
*
- * XXX - if this is an octet string, does the byte order
- * matter? Will this ever be anything *other* than an
- * octet string? What if size_is is neither 1 nor 2?
+ * XXX - is this always little-endian?
*/
- tvb_ensure_bytes_exist(tvb, offset, buffer_len);
- s = tvb_get_string(wmem_packet_scope(), tvb, offset, buffer_len);
- if (tree && buffer_len)
- proto_tree_add_item(string_tree, hfindex, tvb, offset,
- buffer_len, DREP_ENC_INTEGER(drep));
+ s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
+ ENC_UTF_16|ENC_LITTLE_ENDIAN);
+ } else {
+ /*
+ * XXX - what if size_is is neither 1 nor 2?
+ */
+ s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, buffer_len,
+ DREP_ENC_CHAR(drep));
}
+ if (tree && buffer_len)
+ proto_tree_add_string(string_tree, hfindex, tvb, offset,
+ buffer_len, s);
if (string_item != NULL)
proto_item_append_text(string_item, ": %s", s);
found_new_pointer = 0;
len = g_slist_length(ndr_pointer_list);
- for(i=next_pointer; i<len; i++) {
+ for (i=next_pointer; i<len; i++) {
ndr_pointer_data_t *tnpd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
if (tnpd->fnct) {
dcerpc_dissect_fnct_t *fnct;
}
}
} else {
- /* if we haven't seen the request bail out since we cant
+ /* if we haven't seen the request bail out since we can't
know whether this is the first non-NULL instance
or not */
if (value->req_frame == 0) {
int i,len;
len = g_slist_length(ndr_pointer_list);
- for(i=0; i<len; i++) {
+ for (i=0; i<len; i++) {
npd = (ndr_pointer_data_t *)g_slist_nth_data(ndr_pointer_list, i);
if (npd) {
if (npd->id == id) {
proto_item *item;
/* we must find out a nice way to do the length here */
- item = proto_tree_add_text(tree, tvb, offset, 0,
- "%s", text);
- tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
+ tr = proto_tree_add_subtree(tree, tvb, offset, 0,
+ ett_dcerpc_pointer_data, &item, text);
add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
hf_index, callback, callback_args);
/* get the referent id */
offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
- tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
/* we got a NULL pointer */
if (id == 0) {
- proto_tree_add_text(tree, tvb, offset-pointer_size,
- pointer_size,
- "(NULL pointer) %s",text);
+ proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
+ pointer_size, NULL, "%s", text);
goto after_ref_id;
}
- /* see if we have seen this pointer before */
- DISSECTOR_ASSERT(id <= G_MAXUINT32);
+ /* see if we have seen this pointer before
+ The value is truncated to 32bits. 64bit values have only been
+ seen on fuzz-tested files */
idx = find_pointer_index((guint32)id);
/* we have seen this pointer before */
if (idx >= 0) {
- proto_tree_add_text(tree, tvb, offset-pointer_size,
- pointer_size,
- "(duplicate PTR) %s",text);
+ proto_tree_add_string(tree, hf_dcerpc_duplicate_ptr, tvb, offset-pointer_size, pointer_size, text);
goto after_ref_id;
}
/* new pointer */
- item = proto_tree_add_text(tree, tvb, offset-pointer_size,
- pointer_size,
- "%s", text);
- tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
- proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
- offset-pointer_size, pointer_size, (guint32)id);
+ tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
+ pointer_size, ett_dcerpc_pointer_data, &item, text);
+ if (di->call_data->flags & DCERPC_IS_NDR64) {
+ proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
+ offset-pointer_size, pointer_size, id);
+ } else {
+ proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
+ offset-pointer_size, pointer_size, (guint32)id);
+ }
add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
callback, callback_args);
goto after_ref_id;
/* get the referent id */
offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
- tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
/* we got a NULL pointer */
if (id == 0) {
- proto_tree_add_text(tree, tvb, offset-pointer_size,
- pointer_size,
- "(NULL pointer) %s",text);
+ proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
+ pointer_size, NULL, "%s",text);
goto after_ref_id;
}
/* new pointer */
- DISSECTOR_ASSERT(id <= G_MAXUINT32);
- item = proto_tree_add_text(tree, tvb, offset-pointer_size,
+ tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
pointer_size,
- "%s", text);
- tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
- proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
+ ett_dcerpc_pointer_data, &item, text);
+ if (di->call_data->flags & DCERPC_IS_NDR64) {
+ proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
+ offset-pointer_size, pointer_size, id);
+ } else {
+ proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
offset-pointer_size, pointer_size, (guint32)id);
+ }
add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
hf_index, callback, callback_args);
goto after_ref_id;
/* get the referent id */
offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
- tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
/* new pointer */
- item = proto_tree_add_text(tree, tvb, offset-pointer_size,
+ tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
pointer_size,
- "%s",text);
- tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
- DISSECTOR_ASSERT(id <= G_MAXUINT32);
- proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
+ ett_dcerpc_pointer_data,&item,text);
+ if (di->call_data->flags & DCERPC_IS_NDR64) {
+ proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
+ offset-pointer_size, pointer_size, id);
+ } else {
+ proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
offset-pointer_size, pointer_size, (guint32)id);
+ }
add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
hf_index, callback, callback_args);
goto after_ref_id;
/* get the referent id */
offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
- tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
/* we got a NULL pointer */
if (id == 0) {
- proto_tree_add_text(tree, tvb, offset-pointer_size,
- pointer_size,
- "(NULL pointer) %s", text);
+ proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
+ pointer_size, NULL, "%s",text);
goto after_ref_id;
}
/* new pointer */
- item = proto_tree_add_text(tree, tvb, offset-pointer_size,
+ tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
pointer_size,
- "%s",text);
- tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
- DISSECTOR_ASSERT(id <= G_MAXUINT32);
- proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
+ ett_dcerpc_pointer_data,&item,text);
+ if (di->call_data->flags & DCERPC_IS_NDR64) {
+ proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
+ offset-pointer_size, pointer_size, id);
+ } else {
+ proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
offset-pointer_size, pointer_size, (guint32)id);
+ }
add_pointer_to_list(pinfo, tr, item, di, fnct, 0xffffffff,
hf_index, callback, callback_args);
goto after_ref_id;
/* get the referent id */
offset = dissect_ndr_uint3264(tvb, offset, pinfo, NULL, di, drep, -1, &id);
- tvb_ensure_bytes_exist(tvb, offset-pointer_size, pointer_size);
/* we got a NULL pointer */
if (id == 0) {
- proto_tree_add_text(tree, tvb, offset-pointer_size,
- pointer_size,
- "(NULL pointer) %s",text);
+ proto_tree_add_bytes_format_value(tree, hf_dcerpc_null_pointer, tvb, offset-pointer_size,
+ pointer_size, NULL, "%s",text);
goto after_ref_id;
}
- /* see if we have seen this pointer before */
- DISSECTOR_ASSERT(id <= G_MAXUINT32);
+ /* see if we have seen this pointer before
+ The value is truncated to 32bits. 64bit values have only been
+ seen on fuzztested files */
idx = find_pointer_index((guint32)id);
/* we have seen this pointer before */
if (idx >= 0) {
- proto_tree_add_text(tree, tvb, offset-pointer_size,
- pointer_size,
- "(duplicate PTR) %s",text);
+ proto_tree_add_string(tree, hf_dcerpc_duplicate_ptr, tvb, offset-pointer_size, pointer_size, text);
goto after_ref_id;
}
/* new pointer */
- item = proto_tree_add_text(tree, tvb, offset-pointer_size,
+ tr = proto_tree_add_subtree(tree, tvb, offset-pointer_size,
pointer_size,
- "%s", text);
- tr = proto_item_add_subtree(item,ett_dcerpc_pointer_data);
- proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb,
+ ett_dcerpc_pointer_data, &item, text);
+ if (di->call_data->flags & DCERPC_IS_NDR64) {
+ proto_tree_add_uint64(tr, hf_dcerpc_referent_id64, tvb,
+ offset-pointer_size, pointer_size, id);
+ } else {
+ proto_tree_add_uint(tr, hf_dcerpc_referent_id32, tvb,
offset-pointer_size, pointer_size, (guint32)id);
+ }
add_pointer_to_list(pinfo, tr, item, di, fnct, (guint32)id, hf_index,
callback, callback_args);
goto after_ref_id;
}
static void
-show_stub_data(tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
- dcerpc_auth_info *auth_info, gboolean is_encrypted)
+dissect_sec_vt_bitmask(proto_tree *tree, tvbuff_t *tvb)
{
- int length, plain_length, auth_pad_len;
- guint auth_pad_offset;
-
- /*
- * 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) {
- auth_pad_len = auth_info?auth_info->auth_pad_len:0;
- length = tvb_reported_length_remaining(tvb, offset);
-
- /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
- plain_length = length - auth_pad_len;
- if (plain_length < 1) {
- plain_length = length;
- auth_pad_len = 0;
- }
- auth_pad_offset = offset + plain_length;
-
- if ((auth_info != NULL) &&
- (auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
- if (is_encrypted) {
- tvb_ensure_bytes_exist(tvb, offset, length);
- proto_tree_add_text(dcerpc_tree, tvb, offset, length,
- "Encrypted stub data (%d byte%s)",
- length, plurality(length, "", "s"));
- /* is the padding is still inside the encrypted blob, don't display it explicit */
- auth_pad_len = 0;
- } else {
- tvb_ensure_bytes_exist(tvb, offset, plain_length);
- proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
- "Decrypted stub data (%d byte%s)",
- plain_length, plurality(plain_length, "", "s"));
- }
- } else {
- tvb_ensure_bytes_exist(tvb, offset, plain_length);
- proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
- "Stub data (%d byte%s)", plain_length,
- plurality(plain_length, "", "s"));
- }
- /* If there is auth padding at the end of the stub, display it */
- if (auth_pad_len != 0) {
- tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
- proto_tree_add_text(dcerpc_tree, tvb, auth_pad_offset,
- auth_pad_len,
- "Auth Padding (%u byte%s)",
- auth_pad_len,
- plurality(auth_pad_len, "", "s"));
- }
- }
+ proto_tree_add_bitmask(tree, tvb, 0,
+ hf_dcerpc_sec_vt_bitmask,
+ ett_dcerpc_sec_vt_bitmask,
+ sec_vt_bitmask_fields,
+ ENC_LITTLE_ENDIAN);
}
-static int
-dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
- proto_tree *dcerpc_tree,
- tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
- guint8 *drep, dcerpc_info *info,
- dcerpc_auth_info *auth_info)
+static void
+dissect_sec_vt_pcontext(proto_tree *tree, tvbuff_t *tvb)
{
- volatile gint offset = 0;
- dcerpc_uuid_key key;
- dcerpc_uuid_value *sub_proto;
- proto_tree *volatile sub_tree = NULL;
- dcerpc_sub_dissector *proc;
- const gchar *name = NULL;
- const char *volatile saved_proto;
- guint length = 0, reported_length = 0;
- tvbuff_t *volatile stub_tvb;
- volatile guint auth_pad_len;
- volatile int auth_pad_offset;
- proto_item *sub_item = NULL;
- proto_item *pi, *hidden_item;
+ int offset = 0;
+ proto_item *ti = NULL;
+ proto_tree *tr = proto_tree_add_subtree(tree, tvb, offset, -1,
+ ett_dcerpc_sec_vt_pcontext,
+ &ti, "pcontext");
+ e_guid_t uuid;
+ const char *uuid_name;
+
+ tvb_get_letohguid(tvb, offset, &uuid);
+ uuid_name = guids_get_uuid_name(&uuid);
+ if (!uuid_name) {
+ uuid_name = guid_to_str(wmem_packet_scope(), &uuid);
+ }
- dcerpc_dissect_fnct_t *volatile sub_dissect;
+ proto_tree_add_guid_format(tr, hf_dcerpc_sec_vt_pcontext_uuid, tvb,
+ offset, 16, &uuid, "Abstract Syntax: %s", uuid_name);
+ offset += 16;
- key.uuid = info->call_data->uuid;
- key.ver = info->call_data->ver;
+ proto_tree_add_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
+ tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
- if ((sub_proto = (dcerpc_uuid_value *)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.
- */
+ tvb_get_letohguid(tvb, offset, &uuid);
+ uuid_name = guids_get_uuid_name(&uuid);
+ if (!uuid_name) {
+ uuid_name = guid_to_str(wmem_packet_scope(), &uuid);
+ }
- hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
- tvb, offset, 0, TRUE);
- PROTO_ITEM_SET_HIDDEN(hidden_item);
- col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
- guids_resolve_uuid_to_str(&info->call_data->uuid), info->call_data->ver);
+ proto_tree_add_guid_format(tr, hf_dcerpc_sec_vt_pcontext_uuid, tvb,
+ offset, 16, &uuid, "Transfer Syntax: %s", uuid_name);
+ offset += 16;
- if (decrypted_tvb != NULL) {
- show_stub_data(decrypted_tvb, 0, dcerpc_tree, auth_info,
- FALSE);
- } else
- show_stub_data(tvb, 0, dcerpc_tree, auth_info, TRUE);
- return -1;
- }
+ proto_tree_add_item(tr, hf_dcerpc_sec_vt_pcontext_ver,
+ tvb, offset, 4, ENC_LITTLE_ENDIAN);
+ offset += 4;
- for (proc = sub_proto->procs; proc->name; proc++) {
- if (proc->num == info->call_data->opnum) {
- name = proc->name;
- break;
- }
- }
+ proto_item_set_len(ti, offset);
+}
- col_set_str(pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
+static void
+dissect_sec_vt_header(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb)
+{
+ int offset = 0;
+ proto_item *ti = NULL;
+ proto_tree *tr = proto_tree_add_subtree(tree, tvb, offset, -1,
+ ett_dcerpc_sec_vt_header,
+ &ti, "header2");
+ guint8 drep[4];
+ guint8 ptype = tvb_get_guint8(tvb, offset);
- if (!name)
- col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown operation %u %s",
- info->call_data->opnum,
- (info->ptype == PDU_REQ) ? "request" : "response");
- else
- col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
- name, (info->ptype == PDU_REQ) ? "request" : "response");
+ proto_tree_add_uint(tr, hf_dcerpc_packet_type, tvb, offset, 1, ptype);
+ offset += 1;
- sub_dissect = (info->ptype == PDU_REQ) ?
- proc->dissect_rqst : proc->dissect_resp;
+ proto_tree_add_item(tr, hf_dcerpc_reserved, tvb, offset, 1, ENC_NA);
+ offset += 1;
- if (tree) {
- sub_item = proto_tree_add_item(tree, sub_proto->proto_id,
- (decrypted_tvb != NULL)?decrypted_tvb:tvb,
- 0, -1, ENC_NA);
+ proto_tree_add_item(tr, hf_dcerpc_reserved, tvb, offset, 2, ENC_NA);
+ offset += 2;
- if (sub_item) {
- sub_tree = proto_item_add_subtree(sub_item, sub_proto->ett);
- if (!name)
- proto_item_append_text(sub_item, ", unknown operation %u",
- info->call_data->opnum);
- else
- proto_item_append_text(sub_item, ", %s", name);
- }
+ tvb_memcpy(tvb, drep, offset, 4);
+ proto_tree_add_dcerpc_drep(tr, tvb, offset, drep, 4);
+ offset += 4;
- /*
- * Put the operation number into the tree along with
- * the operation's name.
- */
- if (sub_proto->opnum_hf != -1)
- proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
- tvb, 0, 0, info->call_data->opnum,
- "Operation: %s (%u)",
- name ? name : "Unknown operation",
- info->call_data->opnum);
- else
- proto_tree_add_uint_format_value(sub_tree, hf_dcerpc_op, tvb,
- 0, 0, info->call_data->opnum,
- "%s (%u)",
- name ? name : "Unknown operation",
- info->call_data->opnum);
+ offset = dissect_dcerpc_uint32(tvb, offset, pinfo, tr, drep,
+ hf_dcerpc_cn_call_id, NULL);
- if ((info->ptype == PDU_REQ) && (info->call_data->rep_frame != 0)) {
- pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
- tvb, 0, 0, info->call_data->rep_frame);
- PROTO_ITEM_SET_GENERATED(pi);
- }
- if ((info->ptype == PDU_RESP) && (info->call_data->req_frame != 0)) {
- pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
- tvb, 0, 0, info->call_data->req_frame);
- PROTO_ITEM_SET_GENERATED(pi);
- }
- } /* tree */
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tr, drep,
+ hf_dcerpc_cn_ctx_id, NULL);
- if (decrypted_tvb != NULL) {
- /* Either there was no encryption or we successfully decrypted
- the encrypted payload. */
- if (sub_dissect) {
- /* We have a subdissector - call it. */
- saved_proto = pinfo->current_proto;
- pinfo->current_proto = sub_proto->name;
+ offset = dissect_dcerpc_uint16(tvb, offset, pinfo, tr, drep,
+ hf_dcerpc_opnum, NULL);
- init_ndr_pointer_list(info);
+ proto_item_set_len(ti, offset);
+}
- length = tvb_length(decrypted_tvb);
- reported_length = tvb_reported_length(decrypted_tvb);
+static int
+dissect_verification_trailer_impl(packet_info *pinfo, tvbuff_t *tvb, int stub_offset,
+ proto_tree *parent_tree, int *signature_offset)
+{
+ int remaining = tvb_captured_length_remaining(tvb, stub_offset);
+ int offset;
+ gint signature_start;
+ gint payload_length;
+ typedef enum {
+ SEC_VT_COMMAND_BITMASK_1 = 0x0001,
+ SEC_VT_COMMAND_PCONTEXT = 0x0002,
+ SEC_VT_COMMAND_HEADER2 = 0x0003,
+ SEC_VT_COMMAND_END = 0x4000,
+ SEC_VT_MUST_PROCESS_COMMAND = 0x8000,
+ SEC_VT_COMMAND_MASK = 0x3fff,
+ } sec_vt_command;
+ proto_item *payload_item;
+ proto_item *item;
+ proto_tree *tree;
+
+ if (signature_offset != NULL) {
+ *signature_offset = -1;
+ }
- /*
- * Remove the authentication padding from the stub data.
- */
- if ((auth_info != NULL) && (auth_info->auth_pad_len != 0)) {
- if (reported_length >= auth_info->auth_pad_len) {
- /*
- * OK, the padding length isn't so big that it
- * exceeds the stub length. Trim the reported
- * length of the tvbuff.
- */
- reported_length -= auth_info->auth_pad_len;
+ /* We need at least signature + the header of one command */
+ if (remaining < (int)(sizeof(TRAILER_SIGNATURE) + 4)) {
+ return -1;
+ }
- /*
- * If that exceeds the actual amount of data in
- * the tvbuff (which means we have at least one
- * byte of authentication padding in the tvbuff),
- * trim the actual amount.
- */
- if (length > reported_length)
- length = reported_length;
+ /* We only scan the last 512 bytes for a possible trailer */
+ if (remaining > 512) {
+ offset = remaining - 512;
+ remaining = 512;
+ } else {
+ offset = 0;
+ }
+ offset += stub_offset;
- stub_tvb = tvb_new_subset(decrypted_tvb, 0, length, reported_length);
- auth_pad_len = auth_info->auth_pad_len;
- auth_pad_offset = reported_length;
- } else {
- /*
- * The padding length exceeds the stub length.
- * Don't bother dissecting the stub, trim the padding
- * length to what's in the stub data, and show the
- * entire stub as authentication padding.
- */
- stub_tvb = NULL;
- auth_pad_len = reported_length;
- auth_pad_offset = 0;
- length = 0;
- }
- } else {
- /*
- * No authentication padding.
- */
- stub_tvb = decrypted_tvb;
- auth_pad_len = 0;
- auth_pad_offset = 0;
- }
+ signature_start = tvb_find_tvb(tvb, tvb_trailer_signature, offset);
+ if (signature_start == -1) {
+ return -1;
+ }
+ payload_length = signature_start - stub_offset;
+ payload_item = proto_tree_add_item(parent_tree,
+ hf_dcerpc_payload_stub_data,
+ tvb, stub_offset, payload_length, ENC_NA);
+ proto_item_append_text(payload_item, " (%d byte%s)",
+ payload_length, plurality(payload_length, "", "s"));
+
+ if (signature_offset != NULL) {
+ *signature_offset = signature_start;
+ }
+ remaining -= (signature_start - offset);
+ offset = signature_start;
+
+ tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1,
+ ett_dcerpc_verification_trailer,
+ &item, "Verification Trailer");
+
+ proto_tree_add_item(tree, hf_dcerpc_sec_vt_signature,
+ tvb, offset, sizeof(TRAILER_SIGNATURE), ENC_NA);
+ offset += (int)sizeof(TRAILER_SIGNATURE);
+ remaining -= (int)sizeof(TRAILER_SIGNATURE);
+
+ while (remaining >= 4) {
+ sec_vt_command cmd;
+ guint16 len, len_missalign;
+ gboolean cmd_end, cmd_must;
+ proto_item *ti;
+ proto_tree *tr;
+ tvbuff_t *cmd_tvb = NULL;
+
+ cmd = (sec_vt_command)tvb_get_letohs(tvb, offset);
+ len = tvb_get_letohs(tvb, offset + 2);
+ cmd_end = cmd & SEC_VT_COMMAND_END;
+ cmd_must = cmd & SEC_VT_MUST_PROCESS_COMMAND;
+ cmd = (sec_vt_command)(cmd & SEC_VT_COMMAND_MASK);
+
+ tr = proto_tree_add_subtree_format(tree, tvb, offset, 4 + len,
+ ett_dcerpc_sec_vt_pcontext,
+ &ti, "Command: %s",
+ val_to_str(cmd, sec_vt_command_cmd_vals,
+ "Unknown (0x%04x)"));
+
+ if (cmd_must) {
+ proto_item_append_text(ti, "!!!");
+ }
+ if (cmd_end) {
+ proto_item_append_text(ti, ", END");
+ }
- if (sub_item) {
- proto_item_set_len(sub_item, length);
- }
+ proto_tree_add_bitmask(tr, tvb, offset,
+ hf_dcerpc_sec_vt_command,
+ ett_dcerpc_sec_vt_command,
+ sec_vt_command_fields,
+ ENC_LITTLE_ENDIAN);
+ offset += 2;
+
+ proto_tree_add_item(tr, hf_dcerpc_sec_vt_command_length, tvb,
+ offset, 2, ENC_LITTLE_ENDIAN);
+ offset += 2;
+
+ cmd_tvb = tvb_new_subset_length(tvb, offset, len);
+ switch (cmd) {
+ case SEC_VT_COMMAND_BITMASK_1:
+ dissect_sec_vt_bitmask(tr, cmd_tvb);
+ break;
+ case SEC_VT_COMMAND_PCONTEXT:
+ dissect_sec_vt_pcontext(tr, cmd_tvb);
+ break;
+ case SEC_VT_COMMAND_HEADER2:
+ dissect_sec_vt_header(pinfo, tr, cmd_tvb);
+ break;
+ default:
+ proto_tree_add_item(tr, hf_dcerpc_unknown, cmd_tvb, 0, len, ENC_NA);
+ break;
+ }
- if (stub_tvb != NULL) {
- /*
- * Catch all exceptions other than BoundsError, so that even
- * if the stub data is bad, we still show the authentication
- * padding, if any.
- *
- * If we get BoundsError, it means the frame was cut short
- * by a snapshot length, so there's nothing more to
- * dissect; just re-throw that exception.
- */
- TRY {
- int remaining;
-
- offset = sub_dissect(stub_tvb, 0, pinfo, sub_tree,
- info, drep);
-
- /* If we have a subdissector and it didn't dissect all
- data in the tvb, make a note of it. */
- remaining = tvb_reported_length_remaining(stub_tvb, offset);
- if (remaining > 0) {
- proto_tree_add_text(sub_tree, stub_tvb, offset,
- remaining,
- "[Long frame (%d byte%s)]",
- remaining,
- plurality(remaining, "", "s"));
- col_append_fstr(pinfo->cinfo, COL_INFO,
- "[Long frame (%d byte%s)]",
- remaining,
- plurality(remaining, "", "s"));
+ offset += len;
+ remaining -= (4 + len);
- }
- } CATCH_NONFATAL_ERRORS {
- /*
- * Somebody threw an exception that means that there
- * was a problem dissecting the payload; that means
- * that a dissector was found, so we don't need to
- * dissect the payload as data or update the protocol
- * or info columns.
- *
- * Just show the exception and then drive on to show
- * the authentication padding.
- */
- show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
- } ENDTRY;
- }
+ len_missalign = len & 1;
- /* If there is auth padding at the end of the stub, display it */
- if (auth_pad_len != 0) {
- tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
- proto_tree_add_text(sub_tree, decrypted_tvb, auth_pad_offset,
- auth_pad_len,
- "Auth Padding (%u byte%s)",
- auth_pad_len,
- plurality(auth_pad_len, "", "s"));
- }
+ if (len_missalign) {
+ int l = 2-len_missalign;
+ proto_tree_add_item(tr, hf_dcerpc_missalign, tvb, offset, l, ENC_NA);
+ offset += l;
+ remaining -= l;
+ }
- pinfo->current_proto = saved_proto;
- } else {
- /* No subdissector - show it as stub data. */
- if (decrypted_tvb) {
- show_stub_data(decrypted_tvb, 0, sub_tree, auth_info, FALSE);
- } else {
- show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
- }
+ if (cmd_end) {
+ break;
}
- } else
- show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
+ }
- tap_queue_packet(dcerpc_tap, pinfo, info);
- return 0;
+ proto_item_set_end(item, tvb, offset);
+ return offset;
}
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)
+dissect_verification_trailer(packet_info *pinfo, tvbuff_t *tvb, int stub_offset,
+ proto_tree *parent_tree, int *signature_offset)
{
- int auth_offset;
-
- auth_info->auth_data = NULL;
+ volatile int ret = -1;
+ TRY {
+ /*
+ * Even if we found a signature we can't be sure to have a
+ * valid verification trailer, we're only relatively sure
+ * if we manage to dissect it completely, otherwise it
+ * may be part of the real payload. That's why we have
+ * a try/catch block here.
+ */
+ ret = dissect_verification_trailer_impl(pinfo, tvb, stub_offset, parent_tree, signature_offset);
+ } CATCH_NONFATAL_ERRORS {
+ } ENDTRY;
+ return ret;
+}
- if (auth_info->auth_size != 0) {
- dcerpc_auth_subdissector_fns *auth_fns;
- tvbuff_t *auth_tvb;
+static int
+dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
+ proto_tree *dcerpc_tree,
+ tvbuff_t *volatile tvb, gboolean decrypted,
+ guint8 *drep, dcerpc_info *info,
+ dcerpc_auth_info *auth_info)
+{
+ volatile gint offset = 0;
+ guid_key key;
+ dcerpc_dissector_data_t dissector_data;
+ proto_item *hidden_item;
- auth_offset = hdr->frag_len - hdr->auth_len;
+ /* GUID and UUID are same size, but compiler complains about structure "name" differences */
+ memcpy(&key.guid, &info->call_data->uuid, sizeof(key.guid));
+ key.ver = info->call_data->ver;
- auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
- hdr->auth_len);
+ dissector_data.sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key);
+ dissector_data.info = info;
+ dissector_data.decrypted = decrypted;
+ dissector_data.auth_info = auth_info;
+ dissector_data.drep = drep;
+ dissector_data.dcerpc_tree = dcerpc_tree;
+
+ /* Check the dissector table before the hash table. Hopefully the hash table entries can
+ all be converted to use dissector table */
+ if ((dissector_data.sub_proto == NULL) ||
+ (!dissector_try_guid_new(uuid_dissector_table, &key, tvb, pinfo, tree, FALSE, &dissector_data))) {
+ /*
+ * We don't have a dissector for this UUID, or the protocol
+ * for that UUID is disabled.
+ */
- auth_info->auth_data = auth_tvb;
+ hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
+ tvb, offset, 0, TRUE);
+ PROTO_ITEM_SET_HIDDEN(hidden_item);
+ col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
+ guids_resolve_guid_to_str(&info->call_data->uuid), info->call_data->ver);
- if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
- auth_info->auth_type))) {
- /*
- * Catch all bounds-error exceptions, so that even if the
- * verifier is bad or we don't have all of it, we still
- * show the stub data.
- */
- TRY {
- dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
- hdr, auth_info);
- } CATCH_BOUNDS_ERRORS {
- show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
- } ENDTRY;
- } else {
- tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
- proto_tree_add_text(dcerpc_tree, auth_tvb, 0, hdr->auth_len,
- "Auth Verifier");
- }
+ show_stub_data(pinfo, tvb, 0, dcerpc_tree, auth_info, !decrypted);
+ return -1;
}
- return hdr->auth_len;
+ tap_queue_packet(dcerpc_tap, pinfo, info);
+ return 0;
}
static void
dissect_dcerpc_cn_auth(tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
- gboolean are_credentials, dcerpc_auth_info *auth_info)
+ dcerpc_auth_info *auth_info)
{
volatile int offset;
* Initially set auth_level and auth_type to zero to indicate that we
* haven't yet seen any authentication level information.
*/
- auth_info->auth_level = 0;
- auth_info->auth_type = 0;
- auth_info->auth_size = 0;
- auth_info->auth_pad_len = 0;
+ auth_info->auth_type = 0;
+ auth_info->auth_level = 0;
+ auth_info->auth_context_id = 0;
+ auth_info->auth_pad_len = 0;
+ auth_info->auth_size = 0;
+ auth_info->auth_fns = NULL;
+ auth_info->auth_tvb = NULL;
+ auth_info->auth_item = NULL;
+ auth_info->auth_tree = NULL;
/*
* The authentication information is at the *end* of the PDU; in
*/
offset = hdr->frag_len - (hdr->auth_len + 8);
if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
+ /* Compute the size of the auth block. Note that this should not
+ include auth padding, since when NTLMSSP encryption is used, the
+ padding is actually inside the encrypted stub */
+ auth_info->auth_size = hdr->auth_len + 8;
+
+ auth_info->auth_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_auth_info,
+ tvb, offset, auth_info->auth_size, ENC_NA);
+ auth_info->auth_tree = proto_item_add_subtree(auth_info->auth_item, ett_dcerpc_auth_info);
+
/*
* Either there's no stub data, or the last byte of the stub
* data is present in the captured data, so we shouldn't
* dissect after this, such as stub data.
*/
TRY {
- offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
hf_dcerpc_auth_type,
&auth_info->auth_type);
- offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
hf_dcerpc_auth_level,
&auth_info->auth_level);
- offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
hf_dcerpc_auth_pad_len,
&auth_info->auth_pad_len);
- offset = dissect_dcerpc_uint8(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ offset = dissect_dcerpc_uint8(tvb, offset, pinfo, auth_info->auth_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);
+ offset = dissect_dcerpc_uint32(tvb, offset, pinfo, auth_info->auth_tree, hdr->drep,
+ hf_dcerpc_auth_ctx_id,
+ &auth_info->auth_context_id);
+
+ proto_item_append_text(auth_info->auth_item,
+ ": %s, %s, AuthContextId(%d)",
+ val_to_str(auth_info->auth_type,
+ authn_protocol_vals,
+ "AuthType(%u)"),
+ val_to_str(auth_info->auth_level,
+ authn_level_vals,
+ "AuthLevel(%u)"),
+ auth_info->auth_context_id);
/*
* Dissect the authentication data.
*/
- if (are_credentials) {
- tvbuff_t *auth_tvb;
- dcerpc_auth_subdissector_fns *auth_fns;
-
- auth_tvb = tvb_new_subset(tvb, offset,
- MIN(hdr->auth_len,tvb_length_remaining(tvb, offset)),
+ auth_info->auth_tvb = tvb_new_subset(tvb, offset,
+ MIN(hdr->auth_len,tvb_reported_length_remaining(tvb, offset)),
hdr->auth_len);
- if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
- auth_info->auth_type)))
- dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
- hdr, auth_info);
- else
- proto_tree_add_text(dcerpc_tree, tvb, offset, hdr->auth_len,
- "Auth Credentials");
- }
+ auth_info->auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
+ auth_info->auth_type);
+ if (auth_info->auth_fns != NULL)
+ dissect_auth_verf(pinfo, hdr, auth_info);
+ else
+ proto_tree_add_item(auth_info->auth_tree,
+ hf_dcerpc_auth_credentials,
+ auth_info->auth_tvb, 0,
+ hdr->auth_len, ENC_NA);
- /* Compute the size of the auth block. Note that this should not
- include auth padding, since when NTLMSSP encryption is used, the
- padding is actually inside the encrypted stub */
- auth_info->auth_size = hdr->auth_len + 8;
} CATCH_BOUNDS_ERRORS {
show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
} ENDTRY;
* as well in the future.
*/
-guint16 dcerpc_get_transport_salt(packet_info *pinfo)
+guint64
+dcerpc_get_transport_salt(packet_info *pinfo)
{
- switch (pinfo->dcetransporttype) {
+ dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+ switch (decode_data->dcetransporttype) {
case DCE_CN_TRANSPORT_SMBPIPE:
/* DCERPC over smb */
- return pinfo->dcetransportsalt;
+ return decode_data->dcetransportsalt;
}
/* Some other transport... */
return 0;
}
+void
+dcerpc_set_transport_salt(guint64 dcetransportsalt, packet_info *pinfo)
+{
+ dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+ decode_data->dcetransportsalt = dcetransportsalt;
+}
+
/*
* Connection oriented packet types
*/
guint16 ctx_id;
guint8 num_trans_items;
guint j;
- e_uuid_t if_id;
- e_uuid_t trans_id;
+ e_guid_t if_id;
+ e_guid_t trans_id;
guint32 trans_ver;
guint16 if_ver, if_ver_minor;
dcerpc_auth_info auth_info;
char *uuid_str;
const char *uuid_name = NULL;
proto_item *iface_item = NULL;
+ dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_max_xmit, NULL);
/* save context ID for use with dcerpc_add_conv_to_bind_table() */
/* (if we have multiple contexts, this might cause "decode as"
* to behave unpredictably) */
- pinfo->dcectxid = ctx_id;
+ decode_data->dcectxid = ctx_id;
if (dcerpc_tree) {
ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, ENC_NA);
iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
- uuid_str = guid_to_str((e_guid_t*)&if_id);
+ uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t*)&if_id);
uuid_name = guids_get_uuid_name(&if_id);
if (uuid_name) {
proto_tree_add_guid_format(iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
for (j = 0; j < num_trans_items; j++) {
proto_tree *trans_tree = NULL;
proto_item *trans_item = NULL;
- proto_item *uuid_item = NULL;
dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
if (ctx_tree) {
trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, ENC_NA);
trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
- uuid_str = guid_to_str((e_guid_t *) &trans_id);
+ uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t *) &trans_id);
uuid_name = guids_get_uuid_name(&trans_id);
- if (uuid_name) {
- uuid_item = proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id, tvb, offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s UUID:%s", uuid_name, uuid_str);
+ /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
+ if (trans_id.data1 == 0x6cb71c2c && trans_id.data2 == 0x9812 && trans_id.data3 == 0x4540) {
+ proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
+ tvb, offset, 16, (e_guid_t *) &trans_id,
+ "Transfer Syntax: Bind Time Feature Negotiation UUID:%s",
+ uuid_str);
+ proto_tree_add_bitmask(trans_tree, tvb, offset + 8,
+ hf_dcerpc_cn_bind_trans_btfn,
+ ett_dcerpc_cn_bind_trans_btfn,
+ dcerpc_cn_bind_trans_btfn_fields,
+ ENC_LITTLE_ENDIAN);
+ proto_item_append_text(trans_item, "[%u]: Bind Time Feature Negotiation", j+1);
+ proto_item_append_text(ctx_item, ", Bind Time Feature Negotiation");
+ } else if (uuid_name) {
+ proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
+ tvb, offset, 16, (e_guid_t *) &trans_id,
+ "Transfer Syntax: %s UUID:%s", uuid_name, uuid_str);
proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_name);
proto_item_append_text(ctx_item, ", %s", uuid_name);
} else {
- uuid_item = proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id, tvb, offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s", uuid_str);
+ proto_tree_add_guid_format(trans_tree, hf_dcerpc_cn_bind_trans_id,
+ tvb, offset, 16, (e_guid_t *) &trans_id,
+ "Transfer Syntax: %s", uuid_str);
proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
proto_item_append_text(ctx_item, ", %s", uuid_str);
}
- /* check for [MS-RPCE] 3.3.1.5.3 Bind Time Feature Negotiation */
- if (trans_id.Data1 == 0x6cb71c2c && trans_id.Data2 == 0x9812 && trans_id.Data3 == 0x4540) {
- proto_tree *uuid_tree = proto_item_add_subtree(uuid_item, ett_dcerpc_cn_trans_btfn);
- proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, offset+8, 1, trans_id.Data4[0]);
- proto_tree_add_boolean(uuid_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, offset+8, 1, trans_id.Data4[0]);
- }
}
offset += 16;
key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
key->conv = conv;
key->ctx_id = ctx_id;
- key->smb_fid = dcerpc_get_transport_salt(pinfo);
+ key->transport_salt = dcerpc_get_transport_salt(pinfo);
value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
value->uuid = if_id;
if (i > 0)
col_append_fstr(pinfo->cinfo, COL_INFO, ",");
col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u (%s)",
- guids_resolve_uuid_to_str(&if_id), if_ver, if_ver_minor,
- guids_resolve_uuid_to_str(&trans_id));
+ guids_resolve_guid_to_str(&if_id), if_ver, if_ver_minor,
+ guids_resolve_guid_to_str(&trans_id));
if (ctx_tree) {
proto_item_set_len(ctx_item, offset - ctx_offset);
* an authentication header, and associate it with an authentication
* context, so subsequent PDUs can use that context.
*/
- dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
+ dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
}
static void
guint i;
guint16 result = 0;
guint16 reason = 0;
- e_uuid_t trans_id;
+ e_guid_t trans_id;
guint32 trans_ver;
dcerpc_auth_info auth_info;
const char *uuid_name = NULL;
offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
if (sec_addr_len != 0) {
- tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
sec_addr_len, ENC_ASCII|ENC_NA);
offset += sec_addr_len;
proto_item *ctx_item = NULL;
if (dcerpc_tree) {
- ctx_item = proto_tree_add_text(dcerpc_tree, tvb, offset, 24, "Ctx Item[%u]:", i+1);
- ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
+ ctx_tree = proto_tree_add_subtree_format(dcerpc_tree, tvb, offset, 24, ett_dcerpc_cn_ctx, &ctx_item, "Ctx Item[%u]:", i+1);
}
offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
/* [MS-RPCE] 3.3.1.5.3 check if this Ctx Item is the response to a Bind Time Feature Negotiation request */
if (result == 3) {
- const int old_offset = offset;
- offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree, hdr->drep, hf_dcerpc_cn_ack_btfn, &reason);
- proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_01, tvb, old_offset, 1, reason);
- proto_tree_add_boolean(ctx_tree, hf_dcerpc_cn_bind_trans_btfn_02, tvb, old_offset, 1, reason);
+ proto_tree_add_bitmask(ctx_tree, tvb, offset,
+ hf_dcerpc_cn_bind_trans_btfn,
+ ett_dcerpc_cn_bind_trans_btfn,
+ dcerpc_cn_bind_trans_btfn_fields,
+ ENC_LITTLE_ENDIAN);
+ offset += 2;
} else if (result != 0) {
offset = dissect_dcerpc_uint16(tvb, offset, pinfo, ctx_tree,
hdr->drep, hf_dcerpc_cn_ack_reason,
dcerpc_tvb_get_uuid(tvb, offset, hdr->drep, &trans_id);
uuid_name = guids_get_uuid_name(&trans_id);
if (! uuid_name) {
- uuid_name = guid_to_str((e_guid_t *) &trans_id);
+ uuid_name = guid_to_str(wmem_packet_scope(), (e_guid_t *) &trans_id);
}
proto_tree_add_guid_format(ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
* XXX - do we need to do anything with the authentication level
* we get back from this?
*/
- dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
+ dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
}
static void
gboolean save_fragmented;
fragment_head *fd_head = NULL;
- tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
+ tvbuff_t *payload_tvb, *decrypted_tvb = NULL;
proto_item *pi;
proto_item *parent_pi;
proto_item *dcerpc_tree_item;
save_fragmented = pinfo->fragmented;
- length = tvb_length_remaining(tvb, offset);
+ length = tvb_reported_length_remaining(tvb, offset);
reported_length = tvb_reported_length_remaining(tvb, offset);
if (reported_length < 0 ||
(guint32)reported_length < auth_info->auth_size) {
length = reported_length;
payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
- auth_tvb = NULL;
- /*don't bother if we don't have the entire tvb */
- /*XXX we should really make sure we calculate auth_info->auth_data
- and use that one instead of this auth_tvb hack
- */
- if (tvb_length(tvb) == tvb_reported_length(tvb)) {
- if (tvb_length_remaining(tvb, offset+length) > 8) {
- auth_tvb = tvb_new_subset_remaining(tvb, offset+length+8);
- }
- }
-
/* Decrypt the PDU if it is encrypted */
if (auth_info->auth_type &&
(auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)) {
- /*
- * We know the authentication type, and the authentication
- * level is "Packet privacy", meaning the payload is
- * encrypted; attempt to decrypt it.
- */
- dcerpc_auth_subdissector_fns *auth_fns;
/* Start out assuming we won't succeed in decrypting. */
- decrypted_tvb = NULL;
- /* Schannel needs information into the footer (verifier) in order to setup decryption keys
- * so we call it in order to have a chance to decipher the data
- */
- if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN == auth_info->auth_type) {
- dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, auth_info);
- }
- if ((auth_fns = get_auth_subdissector_fns(
- auth_info->auth_level, auth_info->auth_type))) {
+ if (auth_info->auth_fns != NULL) {
tvbuff_t *result;
- result = decode_encrypted_data(
- payload_tvb, auth_tvb, pinfo, auth_fns,
- hdr->ptype == PDU_REQ, auth_info);
-
+ result = decode_encrypted_data(payload_tvb, pinfo, hdr, auth_info);
if (result) {
- if (dcerpc_tree)
- proto_tree_add_text(
- dcerpc_tree, payload_tvb, 0, -1,
- "Encrypted stub data (%d byte%s)",
- tvb_reported_length(payload_tvb),
-
- plurality(tvb_length(payload_tvb), "", "s"));
+ proto_tree_add_item(dcerpc_tree, hf_dcerpc_encrypted_stub_data, payload_tvb, 0, -1, ENC_NA);
add_new_data_source(
pinfo, result, "Decrypted stub data");
if (PFC_NOT_FRAGMENTED(hdr)) {
pinfo->fragmented = FALSE;
- dcerpc_try_handoff(
- pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
+ dcerpc_try_handoff(pinfo, tree, dcerpc_tree,
+ ((decrypted_tvb != NULL) ? decrypted_tvb : payload_tvb),
+ ((decrypted_tvb != NULL) ? TRUE : FALSE),
hdr->drep, di, auth_info);
pinfo->fragmented = save_fragmented;
/* debug output of essential fragment data. */
/* leave it here for future debugging sessions */
/*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
- pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
+ pinfo->num, offset, hdr->frag_len, tvb_reported_length(decrypted_tvb));*/
/* 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, payload_tvb, decrypted_tvb,
+ dcerpc_try_handoff(pinfo, tree, dcerpc_tree,
+ ((decrypted_tvb != NULL) ? decrypted_tvb : payload_tvb),
+ ((decrypted_tvb != NULL) ? TRUE : FALSE),
hdr->drep, di, auth_info);
expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
nor the first fragment then there is nothing more we can do
so we just have to exit
*/
- if ( !dcerpc_reassemble || (tvb_length(tvb) != tvb_reported_length(tvb)) )
+ if ( !dcerpc_reassemble || (tvb_captured_length(tvb) != tvb_reported_length(tvb)) )
goto end_cn_stub;
/* if we didn't get 'frame' we don't know where the PDU started and thus
*/
fd_head = fragment_add_seq_next(&dcerpc_co_reassembly_table,
decrypted_tvb, 0, pinfo, frame, NULL,
- tvb_length(decrypted_tvb),
+ tvb_reported_length(decrypted_tvb),
hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
end_cn_stub:
*/
if (fd_head && (fd_head->flags & FD_DEFRAGMENTED) ) {
- if ((pinfo->fd->num == fd_head->reassembled_in) && (hdr->flags & PFC_LAST_FRAG) ) {
+ if ((pinfo->num == fd_head->reassembled_in) && (hdr->flags & PFC_LAST_FRAG) ) {
tvbuff_t *next_tvb;
proto_item *frag_tree_item;
expert_add_info_format(pinfo, frag_tree_item, &ei_dcerpc_fragment_reassembled, "%s fragment, reassembled", fragment_type(hdr->flags));
- dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
- next_tvb, hdr->drep, di, auth_info);
+ dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, TRUE, hdr->drep, di, auth_info);
} else {
if (decrypted_tvb) {
expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
if (decrypted_tvb) {
- show_stub_data(decrypted_tvb, 0, tree, auth_info, FALSE);
+ show_stub_data(pinfo, decrypted_tvb, 0, tree, auth_info, FALSE);
} else {
- show_stub_data(payload_tvb, 0, tree, auth_info, TRUE);
+ show_stub_data(pinfo, payload_tvb, 0, tree, auth_info, TRUE);
}
}
pinfo->fragmented = save_fragmented;
}
-/**
- * Registers a conversation/UUID binding association, so that
- * we can invoke the proper sub-dissector for a given DCERPC
- * conversation.
- *
- * @param binding all values needed to create and bind a new conversation
- *
- * @return Pointer to newly-added UUID/conversation binding.
- */
-struct _dcerpc_bind_value *
-dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
-{
- dcerpc_bind_value *bind_value;
- dcerpc_bind_key *key;
- conversation_t *conv;
-
- conv = find_conversation(
- 0,
- &binding->addr_a,
- &binding->addr_b,
- binding->ptype,
- binding->port_a,
- binding->port_b,
- 0);
-
- if (!conv) {
- conv = conversation_new(
- 0,
- &binding->addr_a,
- &binding->addr_b,
- binding->ptype,
- binding->port_a,
- binding->port_b,
- 0);
- }
-
- bind_value = (dcerpc_bind_value *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_value));
- bind_value->uuid = binding->uuid;
- bind_value->ver = binding->ver;
- /* For now, assume all DCE/RPC we pick from "decode as" is using
- standard ndr and not ndr64.
- We should make this selectable from the dialog in the future
- */
- bind_value->transport = uuid_data_repr_proto;
-
- key = (dcerpc_bind_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_bind_key));
- key->conv = conv;
- key->ctx_id = binding->ctx_id;
- key->smb_fid = binding->smb_fid;
-
- /* add this entry to the bind table */
- g_hash_table_insert(dcerpc_binds, key, bind_value);
-
- return bind_value;
-
-}
-
static void
dissect_dcerpc_cn_rqst(tvbuff_t *tvb, gint offset, packet_info *pinfo,
proto_tree *dcerpc_tree, proto_tree *tree,
conversation_t *conv;
guint16 ctx_id;
guint16 opnum;
- e_uuid_t obj_id = DCERPC_UUID_NULL;
+ e_guid_t obj_id = DCERPC_UUID_NULL;
dcerpc_auth_info auth_info;
guint32 alloc_hint;
proto_item *pi;
proto_item *parent_pi;
+ dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_alloc_hint, &alloc_hint);
hf_dcerpc_opnum, &opnum);
/* save context ID for use with dcerpc_add_conv_to_bind_table() */
- pinfo->dcectxid = ctx_id;
+ decode_data->dcectxid = ctx_id;
col_append_fstr(pinfo->cinfo, COL_INFO, ", opnum: %u, Ctx: %u",
opnum, ctx_id);
if (dcerpc_tree) {
proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
- guid_to_str((e_guid_t *) &obj_id));
+ guid_to_str(wmem_packet_scope(), (e_guid_t *) &obj_id));
}
offset += 16;
}
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
- dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+ dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
- conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+ conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
if (!conv)
- show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
+ show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
else {
dcerpc_matched_key matched_key, *new_matched_key;
dcerpc_call_value *value;
and desegmented pdu's .
Instead we check if this pdu is already in the matched table or not
*/
- matched_key.frame = pinfo->fd->num;
+ matched_key.frame = pinfo->num;
matched_key.call_id = hdr->call_id;
value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
if (!value) {
bind_key.conv = conv;
bind_key.ctx_id = ctx_id;
- bind_key.smb_fid = dcerpc_get_transport_salt(pinfo);
+ bind_key.transport_salt = dcerpc_get_transport_salt(pinfo);
if ((bind_value = (dcerpc_bind_value *)g_hash_table_lookup(dcerpc_binds, &bind_key)) ) {
if (!(hdr->flags&PFC_FIRST_FRAG)) {
call_key.conv = conv;
call_key.call_id = hdr->call_id;
- call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
+ call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
*new_matched_key = matched_key;
call_key = (dcerpc_cn_call_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_cn_call_key));
call_key->conv = conv;
call_key->call_id = hdr->call_id;
- call_key->smb_fid = dcerpc_get_transport_salt(pinfo);
+ call_key->transport_salt = dcerpc_get_transport_salt(pinfo);
/* if there is already a matching call in the table
remove it so it is replaced with the new one */
call_value->ver = bind_value->ver;
call_value->object_uuid = obj_id;
call_value->opnum = opnum;
- call_value->req_frame = pinfo->fd->num;
- call_value->req_time = pinfo->fd->abs_ts;
+ call_value->req_frame = pinfo->num;
+ call_value->req_time = pinfo->abs_ts;
call_value->rep_frame = 0;
call_value->max_ptr = 0;
call_value->se_data = NULL;
if (value) {
dcerpc_info *di;
- di = get_next_di();
+ di = wmem_new0(wmem_packet_scope(), dcerpc_info);
/* handoff this call */
+ di->dcerpc_procedure_name = "";
di->conv = conv;
di->call_id = hdr->call_id;
- di->smb_fid = dcerpc_get_transport_salt(pinfo);
+ di->transport_salt = dcerpc_get_transport_salt(pinfo);
di->ptype = PDU_REQ;
di->call_data = value;
di->hf_index = -1;
} else {
/* no bind information, simply show stub data */
proto_tree_add_expert_format(dcerpc_tree, pinfo, &ei_dcerpc_cn_ctx_id_no_bind, tvb, offset, 0, "No bind info for interface Context ID %u - capture start too late?", ctx_id);
- show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
+ show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
}
}
-
- /* Dissect the verifier */
- dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
-
}
static void
guint32 alloc_hint;
proto_item *pi;
proto_item *parent_pi;
- e_uuid_t obj_id_null = DCERPC_UUID_NULL;
+ e_guid_t obj_id_null = DCERPC_UUID_NULL;
+ dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_alloc_hint, &alloc_hint);
}
/* save context ID for use with dcerpc_add_conv_to_bind_table() */
- pinfo->dcectxid = ctx_id;
+ decode_data->dcectxid = ctx_id;
col_append_fstr(pinfo->cinfo, COL_INFO, ", Ctx: %u", ctx_id);
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
- dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+ dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
- conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+ conv = find_conversation(pinfo->num, &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, TRUE);
+ show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
} else {
dcerpc_matched_key matched_key, *new_matched_key;
and desegmented pdu's .
Instead we check if this pdu is already in the matched table or not
*/
- matched_key.frame = pinfo->fd->num;
+ matched_key.frame = pinfo->num;
matched_key.call_id = hdr->call_id;
value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
if (!value) {
call_key.conv = conv;
call_key.call_id = hdr->call_id;
- call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
+ call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
/* extra sanity check, only match them if the reply
came after the request */
- if (call_value->req_frame<pinfo->fd->num) {
+ if (call_value->req_frame<pinfo->num) {
new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
*new_matched_key = matched_key;
g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
value = call_value;
if (call_value->rep_frame == 0) {
- call_value->rep_frame = pinfo->fd->num;
+ call_value->rep_frame = pinfo->num;
}
}
}
if (value) {
dcerpc_info *di;
- di = get_next_di();
+ di = wmem_new0(wmem_packet_scope(), dcerpc_info);
/* handoff this call */
+ di->dcerpc_procedure_name = "";
di->conv = conv;
di->call_id = hdr->call_id;
- di->smb_fid = dcerpc_get_transport_salt(pinfo);
+ di->transport_salt = dcerpc_get_transport_salt(pinfo);
di->ptype = PDU_RESP;
di->call_data = value;
- proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
+ pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
+ PROTO_ITEM_SET_GENERATED(pi);
/* (optional) "Object UUID" from request */
if (dcerpc_tree && (memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0)) {
pi = proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
- guid_to_str((e_guid_t *) &value->object_uuid));
+ guid_to_str(wmem_packet_scope(), (e_guid_t *) &value->object_uuid));
PROTO_ITEM_SET_GENERATED(pi);
}
if (parent_pi != NULL) {
proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
}
- nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
+ nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
PROTO_ITEM_SET_GENERATED(pi);
} else {
} else {
/* no bind information, simply show stub data */
proto_tree_add_expert_format(dcerpc_tree, pinfo, &ei_dcerpc_cn_ctx_id_no_bind, tvb, offset, 0, "No bind info for interface Context ID %u - capture start too late?", ctx_id);
- show_stub_data(tvb, offset, dcerpc_tree, &auth_info, TRUE);
+ show_stub_data(pinfo, tvb, offset, dcerpc_tree, &auth_info, TRUE);
}
}
-
- /* Dissect the verifier */
- dissect_dcerpc_verifier(tvb, pinfo, dcerpc_tree, hdr, &auth_info);
}
static void
guint32 alloc_hint;
dcerpc_auth_info auth_info;
proto_item *pi = NULL;
+ dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
offset = dissect_dcerpc_uint32(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_alloc_hint, &alloc_hint);
expert_add_info_format(pinfo, pi, &ei_dcerpc_cn_status, "Fault: %s", val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
/* save context ID for use with dcerpc_add_conv_to_bind_table() */
- pinfo->dcectxid = ctx_id;
+ decode_data->dcectxid = ctx_id;
col_append_fstr(pinfo->cinfo, COL_INFO,
", Ctx: %u, status: %s", ctx_id,
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
- dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+ dissect_dcerpc_cn_auth(tvb, offset, pinfo, dcerpc_tree, hdr, &auth_info);
- conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
+ conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
if (!conv) {
/* no point in creating one here, really */
and desegmented pdu's .
Instead we check if this pdu is already in the matched table or not
*/
- matched_key.frame = pinfo->fd->num;
+ matched_key.frame = pinfo->num;
matched_key.call_id = hdr->call_id;
value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
if (!value) {
call_key.conv = conv;
call_key.call_id = hdr->call_id;
- call_key.smb_fid = dcerpc_get_transport_salt(pinfo);
+ call_key.transport_salt = dcerpc_get_transport_salt(pinfo);
if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_cn_calls, &call_key))) {
new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
value = call_value;
if (call_value->rep_frame == 0) {
- call_value->rep_frame = pinfo->fd->num;
+ call_value->rep_frame = pinfo->num;
}
}
dcerpc_info *di;
proto_item *parent_pi;
- di = get_next_di();
+ di = wmem_new0(wmem_packet_scope(), dcerpc_info);
/* handoff this call */
+ di->dcerpc_procedure_name = "";
di->conv = conv;
di->call_id = hdr->call_id;
- di->smb_fid = dcerpc_get_transport_salt(pinfo);
+ di->transport_salt = dcerpc_get_transport_salt(pinfo);
di->ptype = PDU_FAULT;
di->call_data = value;
- proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
+ pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
+ PROTO_ITEM_SET_GENERATED(pi);
if (value->req_frame != 0) {
nstime_t delta_ts;
pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
if (parent_pi != NULL) {
proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
}
- nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
+ nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
PROTO_ITEM_SET_GENERATED(pi);
} else {
proto_tree_add_expert(dcerpc_tree, pinfo, &ei_dcerpc_no_request_found, tvb, 0, 0);
}
- length = tvb_length_remaining(tvb, offset);
+ length = tvb_reported_length_remaining(tvb, offset);
/* as we now create a tvb in dissect_dcerpc_cn() containing only the
* stub_data, the following calculation is no longer valid:
* stub_length = hdr->frag_len - offset - auth_info.auth_size;
* It should probably get passed the status code
* as well, as that might be protocol-specific.
*/
- if (dcerpc_tree) {
- if (stub_length > 0) {
- tvb_ensure_bytes_exist(tvb, offset, stub_length);
- proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
- "Fault stub data (%d byte%s)",
- stub_length,
- plurality(stub_length, "", "s"));
- }
+ if (stub_length > 0) {
+ proto_tree_add_item(dcerpc_tree, hf_dcerpc_fault_stub_data, tvb, offset, stub_length, ENC_NA);
}
} else {
/* PDU is fragmented and this isn't the first fragment */
- if (dcerpc_tree) {
- if (stub_length > 0) {
- tvb_ensure_bytes_exist(tvb, offset, stub_length);
- proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
- "Fragment data (%d byte%s)",
- stub_length,
- plurality(stub_length, "", "s"));
- }
+ if (stub_length > 0) {
+ proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
}
}
} else {
third means we can attempt reassembly. */
if (dcerpc_tree) {
if (length > 0) {
- tvb_ensure_bytes_exist(tvb, offset, stub_length);
- proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
- "Fragment data (%d byte%s)",
- stub_length,
- plurality(stub_length, "", "s"));
+ proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
}
}
if (hdr->flags&PFC_FIRST_FRAG) { /* FIRST fragment */
*/
if (dcerpc_tree) {
if (length > 0) {
- tvb_ensure_bytes_exist(tvb, offset, stub_length);
- proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
- "Fault stub data (%d byte%s)",
- stub_length,
- plurality(stub_length, "", "s"));
+ proto_tree_add_item(dcerpc_tree, hf_dcerpc_stub_data, tvb, offset, stub_length, ENC_NA);
}
}
}
guint32 *cmd;
guint32 i;
const char *info_str = NULL;
+ static const int * flags[] = {
+ &hf_dcerpc_cn_rts_flags_none,
+ &hf_dcerpc_cn_rts_flags_ping,
+ &hf_dcerpc_cn_rts_flags_other_cmd,
+ &hf_dcerpc_cn_rts_flags_recycle_channel,
+ &hf_dcerpc_cn_rts_flags_in_channel,
+ &hf_dcerpc_cn_rts_flags_out_channel,
+ &hf_dcerpc_cn_rts_flags_eof,
+ NULL
+ };
/* Dissect specific RTS header */
rts_flags = dcerpc_tvb_get_ntohs(tvb, offset, hdr->drep);
- if (dcerpc_tree) {
- proto_tree *cn_rts_flags_tree;
-
- tf = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_rts_flags, tvb, offset, 2, rts_flags);
- cn_rts_flags_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_flags);
- proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_none, tvb, offset, 1, rts_flags);
- proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_ping, tvb, offset, 1, rts_flags);
- proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_other_cmd, tvb, offset, 1, rts_flags);
- proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_recycle_channel, tvb, offset, 1, rts_flags);
- proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_in_channel, tvb, offset, 1, rts_flags);
- proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_out_channel, tvb, offset, 1, rts_flags);
- proto_tree_add_boolean(cn_rts_flags_tree, hf_dcerpc_cn_rts_flags_eof, tvb, offset, 1, rts_flags);
- }
+ proto_tree_add_bitmask_value_with_flags(dcerpc_tree, tvb, offset, hf_dcerpc_cn_rts_flags,
+ ett_dcerpc_cn_rts_flags, flags, rts_flags, BMT_NO_APPEND);
offset += 2;
offset = dissect_dcerpc_uint16(tvb, offset, pinfo, dcerpc_tree, hdr->drep,
hf_dcerpc_cn_rts_commands_nb, &commands_nb);
/* Create the RTS PDU tree - we do not yet know its name */
- tf = proto_tree_add_text(dcerpc_tree, tvb, offset, tvb_length_remaining(tvb, offset), "RTS PDU: %u commands", commands_nb);
- cn_rts_pdu_tree = proto_item_add_subtree(tf, ett_dcerpc_cn_rts_pdu);
+ cn_rts_pdu_tree = proto_tree_add_subtree_format(dcerpc_tree, tvb, offset, -1, ett_dcerpc_cn_rts_pdu, &tf, "RTS PDU: %u commands", commands_nb);
cmd = (guint32 *)wmem_alloc(wmem_packet_scope(), sizeof (guint32) * (commands_nb + 1));
const guint32 conformance_count = dcerpc_tvb_get_ntohl(tvb, offset, hdr->drep);
proto_tree_add_uint(cn_rts_command_tree, hf_dcerpc_cn_rts_command_conformancecount, tvb, offset, 4, conformance_count);
offset += 4;
- padding = (guint8 *)tvb_memdup(NULL, tvb, offset, conformance_count);
+ padding = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, offset, conformance_count);
proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, conformance_count, padding);
offset += conformance_count;
} break;
switch (addrtype) {
case RTS_IPV4: {
const guint32 addr4 = tvb_get_ipv4(tvb, offset);
- proto_tree_add_text(cn_rts_command_tree, tvb, offset, 4, "%s", get_hostname(addr4));
+ proto_tree_add_ipv4_format_value(cn_rts_command_tree, hf_dcerpc_cmd_client_ipv4, tvb, offset, 4, addr4, "%s", get_hostname(addr4));
offset += 4;
} break;
case RTS_IPV6: {
struct e_in6_addr addr6;
tvb_get_ipv6(tvb, offset, &addr6);
- proto_tree_add_text(cn_rts_command_tree, tvb, offset, 16, "%s", get_hostname6(&addr6));
+ proto_tree_add_ipv6_format_value(cn_rts_command_tree, hf_dcerpc_cmd_client_ipv6, tvb, offset, 16, &addr6, "%s", get_hostname6(&addr6));
offset += 16;
} break;
}
- padding = (guint8 *)tvb_memdup(NULL, tvb, offset, 12);
+ padding = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, offset, 12);
proto_tree_add_bytes(cn_rts_command_tree, hf_dcerpc_cn_rts_command_padding, tvb, offset, 12, padding);
offset += 12;
} break;
offset = dissect_dcerpc_uint32(tvb, offset, pinfo, cn_rts_command_tree, hdr->drep, hf_dcerpc_cn_rts_command_pingtrafficsentnotify, NULL);
break;
default:
- proto_tree_add_text(cn_rts_command_tree, tvb, offset, 0, "unknown RTS command number");
+ expert_add_info(pinfo, tf, &ei_dcerpc_cn_rts_command);
break;
}
}
default:
break;
}
+ break;
case RTS_FLAG_IN_CHANNEL:
switch (commands_nb) {
case 7:
default:
break;
}
+ break;
case RTS_FLAG_OUT_CHANNEL|RTS_FLAG_RECYCLE_CHANNEL:
switch (commands_nb) {
case 7:
default:
break;
}
+ break;
case RTS_FLAG_EOF:
switch (commands_nb) {
case 1:
}
}
+static gboolean
+is_dcerpc(tvbuff_t *tvb, int offset, packet_info *pinfo _U_)
+{
+ guint8 rpc_ver;
+ guint8 rpc_ver_minor;
+ guint8 ptype;
+
+ if (!tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t)))
+ return FALSE; /* not enough information to check */
+
+ rpc_ver = tvb_get_guint8(tvb, offset++);
+ if (rpc_ver != 5)
+ return FALSE;
+ rpc_ver_minor = tvb_get_guint8(tvb, offset++);
+ if ((rpc_ver_minor != 0) && (rpc_ver_minor != 1))
+ return FALSE;
+ ptype = tvb_get_guint8(tvb, offset++);
+ if (ptype > PDU_RTS)
+ return FALSE;
+
+ return TRUE;
+}
+
/*
* DCERPC dissector for connection oriented calls.
- * We use transport type to later multiplex between what kind of
- * pinfo->private_data structure to expect.
*/
static gboolean
dissect_dcerpc_cn(tvbuff_t *tvb, int offset, packet_info *pinfo,
proto_item *ti = NULL;
proto_item *tf = NULL;
proto_tree *dcerpc_tree = NULL;
- proto_tree *cn_flags_tree = NULL;
- proto_tree *drep_tree = NULL;
e_dce_cn_common_hdr_t hdr;
dcerpc_auth_info auth_info;
tvbuff_t *fragment_tvb;
+ dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+ static const int * hdr_flags[] = {
+ &hf_dcerpc_cn_flags_object,
+ &hf_dcerpc_cn_flags_maybe,
+ &hf_dcerpc_cn_flags_dne,
+ &hf_dcerpc_cn_flags_mpx,
+ &hf_dcerpc_cn_flags_reserved,
+ &hf_dcerpc_cn_flags_cancel_pending,
+ &hf_dcerpc_cn_flags_last_frag,
+ &hf_dcerpc_cn_flags_first_frag,
+ NULL
+ };
/*
* when done over nbt, dcerpc requests are padded with 4 bytes of null
/*
* Check if this looks like a C/O DCERPC call
*/
- if (!tvb_bytes_exist(tvb, offset, sizeof (hdr))) {
- return FALSE; /* not enough information to check */
- }
+ if (!is_dcerpc(tvb, offset, pinfo))
+ return FALSE;
+
start_offset = offset;
hdr.rpc_ver = tvb_get_guint8(tvb, offset++);
- if (hdr.rpc_ver != 5)
- return FALSE;
hdr.rpc_ver_minor = tvb_get_guint8(tvb, offset++);
- if ((hdr.rpc_ver_minor != 0) && (hdr.rpc_ver_minor != 1))
- return FALSE;
hdr.ptype = tvb_get_guint8(tvb, offset++);
- if (hdr.ptype > PDU_RTS)
- return FALSE;
hdr.flags = tvb_get_guint8(tvb, offset++);
tvb_memcpy(tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
hdr.call_id = dcerpc_tvb_get_ntohl(tvb, offset, hdr.drep);
/*offset += 4;*/
- if (pinfo->dcectxid == 0) {
+ if (decode_data->dcectxid == 0) {
col_append_fstr(pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
} else {
/* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
if (can_desegment && pinfo->can_desegment
&& !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);
+ pinfo->desegment_len = hdr.frag_len - tvb_reported_length_remaining(tvb, start_offset);
*pkt_len = 0; /* desegmentation required */
return TRUE;
}
col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCERPC");
- if (pinfo->dcectxid != 0) {
+ if (decode_data->dcectxid != 0) {
/* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
* append a delimiter and set a column fence */
col_append_str(pinfo->cinfo, COL_INFO, " # ");
col_add_fstr(pinfo->cinfo, COL_INFO, "%s: call_id: %u",
pckt_vals[hdr.ptype].strptr, hdr.call_id);
- if (pinfo->dcectxid != 0) {
+ if (decode_data->dcectxid != 0) {
/* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
expert_add_info(pinfo, NULL, &ei_dcerpc_fragment_multiple);
}
proto_item_append_text(ti, " %s, Fragment: %s",
val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
fragment_type(hdr.flags));
+ }
- 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);
- }
- proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
- proto_tree_add_boolean(cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
+ proto_tree_add_bitmask_value_with_flags(dcerpc_tree, tvb, offset, hf_dcerpc_cn_flags,
+ ett_dcerpc_cn_flags, hdr_flags, hdr.flags, BMT_NO_APPEND);
offset++;
col_append_fstr(pinfo->cinfo, COL_INFO, ", Fragment: %s", fragment_type(hdr.flags));
- if (dcerpc_tree) {
- tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
- drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
- }
- proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
- proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
- proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
+ proto_tree_add_dcerpc_drep(dcerpc_tree, tvb, offset, hdr.drep, (int)sizeof (hdr.drep));
offset += (int)sizeof (hdr.drep);
proto_tree_add_uint(dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
* (and other functions might fail as well) computing the right start
* offset otherwise.
*/
- subtvb_len = MIN(hdr.frag_len, tvb_length(tvb));
+ subtvb_len = MIN(hdr.frag_len, tvb_reported_length(tvb));
fragment_tvb = tvb_new_subset(tvb, start_offset,
subtvb_len /* length */,
hdr.frag_len /* reported_length */);
/*
* Nothing after the common header other than credentials.
*/
- dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, TRUE,
+ dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
&auth_info);
break;
* Nothing after the common header other than an authentication
* verifier.
*/
- dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
+ dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
&auth_info);
break;
default:
/* might as well dissect the auth info */
- dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr, FALSE,
+ dissect_dcerpc_cn_auth(fragment_tvb, MIN(offset - start_offset, subtvb_len), pinfo, dcerpc_tree, &hdr,
&auth_info);
break;
}
static gboolean
dissect_dcerpc_cn_pk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
+ dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
/*
* Only one PDU per transport packet, and only one transport
* packet per PDU.
*/
- pinfo->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
+ decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
if (!dissect_dcerpc_cn(tvb, 0, pinfo, tree, FALSE, NULL)) {
/*
* It wasn't a DCERPC PDU.
gboolean try_desegment = FALSE;
if (dcerpc_cn_desegment && pinfo->can_desegment &&
!tvb_bytes_exist(tvb, offset, sizeof(e_dce_cn_common_hdr_t))) {
- /* look for a previous occurence of the DCE-RPC protocol */
+ /* look for a previous occurrence of the DCE-RPC protocol */
wmem_list_frame_t *cur;
cur = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
while (cur != NULL) {
* it was just too short to tell and ask the TCP layer for more
* data. */
pinfo->desegment_offset = offset;
- pinfo->desegment_len = (guint32)(sizeof(e_dce_cn_common_hdr_t) - tvb_length_remaining(tvb, offset));
+ pinfo->desegment_len = (guint32)(sizeof(e_dce_cn_common_hdr_t) - tvb_reported_length_remaining(tvb, offset));
} else {
/* Really not DCE-RPC */
break;
static gboolean
dissect_dcerpc_cn_bs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
- pinfo->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
+ dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+ decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
}
+static guint
+get_dcerpc_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb,
+ int offset _U_, void *data _U_)
+{
+ guint8 drep[4];
+ guint16 frag_len;
+
+ /* XXX: why does htis not take offset into account? */
+ tvb_memcpy(tvb, (guint8 *)drep, 4, sizeof(drep));
+ frag_len = dcerpc_tvb_get_ntohs(tvb, 8, drep);
+
+ return frag_len;
+}
+
+static int
+dissect_dcerpc_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ int pdu_len = 0;
+ dissect_dcerpc_cn(tvb, 0, pinfo, tree,
+ /* Desegment is already handled by TCP, don't confuse it */
+ FALSE,
+ &pdu_len);
+ return pdu_len;
+}
+
+static gboolean
+dissect_dcerpc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
+{
+ dcerpc_decode_as_data* decode_data;
+
+ if (!is_dcerpc(tvb, 0, pinfo))
+ return 0;
+
+ decode_data = dcerpc_get_decode_data(pinfo);
+ decode_data->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
+
+ tcp_dissect_pdus(tvb, pinfo, tree, dcerpc_cn_desegment, 10, get_dcerpc_pdu_len, dissect_dcerpc_pdu, data);
+ return TRUE;
+}
+
static gboolean
dissect_dcerpc_cn_smbpipe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
- pinfo->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
+ dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+ decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
}
static gboolean
dissect_dcerpc_cn_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
- pinfo->dcetransporttype = DCE_TRANSPORT_UNKNOWN;
+ dcerpc_decode_as_data* decode_data = dcerpc_get_decode_data(pinfo);
+
+ decode_data->dcetransporttype = DCE_CN_TRANSPORT_SMBPIPE;
return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
}
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;
* packet body, then dissect the auth info.
*/
offset += hdr->frag_len;
- if (tvb_length_remaining(tvb, offset) > 0) {
+ if (tvb_reported_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_dcerpc_krb5_auth_verf);
+ auth_tree = proto_tree_add_subtree(dcerpc_tree, tvb, offset, -1, ett_dcerpc_krb5_auth_verf, NULL, "Kerberos authentication verifier");
protection_level = tvb_get_guint8(tvb, offset);
if (auth_level_p != NULL)
*auth_level_p = protection_level;
break;
default:
- proto_tree_add_text(dcerpc_tree, tvb, offset, -1, "Authentication verifier");
+ proto_tree_add_item(dcerpc_tree, hf_dcerpc_authentication_verifier, tvb, offset, -1, ENC_NA);
break;
}
}
col_append_fstr(pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
di->call_data->opnum, hdr->frag_len );
- length = tvb_length_remaining(tvb, offset);
+ length = tvb_reported_length_remaining(tvb, offset);
reported_length = tvb_reported_length_remaining(tvb, offset);
stub_length = hdr->frag_len;
if (length > stub_length)
pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
next_tvb = tvb_new_subset(tvb, offset, length,
reported_length);
- dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
- next_tvb, hdr->drep, di, NULL);
+ dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, TRUE, hdr->drep, di, NULL);
} else {
/* PDU is fragmented and this isn't the first fragment */
- if (dcerpc_tree) {
- if (length > 0) {
- tvb_ensure_bytes_exist(tvb, offset, stub_length);
- proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
- "Fragment data (%d byte%s)",
- stub_length,
- plurality(stub_length, "", "s"));
- }
+ if (length > 0) {
+ proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
}
}
} else {
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) {
- tvb_ensure_bytes_exist(tvb, offset, stub_length);
- proto_tree_add_text(dcerpc_tree, tvb, offset, stub_length,
- "Fragment data (%d byte%s)", stub_length,
- plurality(stub_length, "", "s"));
- }
+ if (length > 0) {
+ proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragment_data, tvb, offset, stub_length, ENC_NA);
}
fd_head = fragment_add_seq(&dcerpc_cl_reassembly_table,
!(hdr->flags1 & PFCL1_LASTFRAG), 0);
if (fd_head != NULL) {
/* We completed reassembly... */
- if (pinfo->fd->num == fd_head->reassembled_in) {
+ if (pinfo->num == fd_head->reassembled_in) {
/* ...and this is the reassembled RPC PDU */
next_tvb = tvb_new_chain(tvb, fd_head->tvb_data);
add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
* XXX - authentication info?
*/
pinfo->fragmented = FALSE;
- dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb,
- next_tvb, hdr->drep, di, NULL);
+ dcerpc_try_handoff(pinfo, tree, dcerpc_tree, next_tvb, TRUE, hdr->drep, di, NULL);
} else {
/* ...and this isn't the reassembled RPC PDU */
pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
{
dcerpc_info *di;
- dcerpc_call_value *value, v;
+ dcerpc_call_value *value;
dcerpc_matched_key matched_key, *new_matched_key;
proto_item *pi;
proto_item *parent_pi;
- di = get_next_di();
if (!(pinfo->fd->flags.visited)) {
dcerpc_call_value *call_value;
dcerpc_dg_call_key *call_key;
call_value->ver = hdr->if_ver;
call_value->object_uuid = hdr->obj_id;
call_value->opnum = hdr->opnum;
- call_value->req_frame = pinfo->fd->num;
- call_value->req_time = pinfo->fd->abs_ts;
+ call_value->req_frame = pinfo->num;
+ call_value->req_time = pinfo->abs_ts;
call_value->rep_frame = 0;
call_value->max_ptr = 0;
call_value->se_data = NULL;
g_hash_table_insert(dcerpc_dg_calls, call_key, call_value);
new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof(dcerpc_matched_key));
- new_matched_key->frame = pinfo->fd->num;
+ new_matched_key->frame = pinfo->num;
new_matched_key->call_id = hdr->seqnum;
g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
}
- matched_key.frame = pinfo->fd->num;
+ matched_key.frame = pinfo->num;
matched_key.call_id = hdr->seqnum;
value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
if (!value) {
- v.uuid = hdr->if_id;
- v.ver = hdr->if_ver;
- v.object_uuid = hdr->obj_id;
- v.opnum = hdr->opnum;
- v.req_frame = pinfo->fd->num;
- v.rep_frame = 0;
- v.max_ptr = 0;
- v.se_data = NULL;
- v.private_data = NULL;
- value = &v;
+ value = wmem_new(wmem_packet_scope(), dcerpc_call_value);
+ value->uuid = hdr->if_id;
+ value->ver = hdr->if_ver;
+ value->object_uuid = hdr->obj_id;
+ value->opnum = hdr->opnum;
+ value->req_frame = pinfo->num;
+ value->rep_frame = 0;
+ value->max_ptr = 0;
+ value->se_data = NULL;
+ value->private_data = NULL;
}
+ di = wmem_new0(wmem_packet_scope(), dcerpc_info);
+ di->dcerpc_procedure_name = "";
di->conv = conv;
di->call_id = hdr->seqnum;
- di->smb_fid = -1;
+ di->transport_salt = -1;
di->ptype = PDU_REQ;
di->call_data = value;
e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
{
dcerpc_info *di;
- dcerpc_call_value *value, v;
+ dcerpc_call_value *value;
dcerpc_matched_key matched_key, *new_matched_key;
proto_item *pi;
proto_item *parent_pi;
- di = get_next_di();
if (!(pinfo->fd->flags.visited)) {
dcerpc_call_value *call_value;
dcerpc_dg_call_key call_key;
if ((call_value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_dg_calls, &call_key))) {
new_matched_key = (dcerpc_matched_key *)wmem_alloc(wmem_file_scope(), sizeof (dcerpc_matched_key));
- new_matched_key->frame = pinfo->fd->num;
+ new_matched_key->frame = pinfo->num;
new_matched_key->call_id = hdr->seqnum;
g_hash_table_insert(dcerpc_matched, new_matched_key, call_value);
if (call_value->rep_frame == 0) {
- call_value->rep_frame = pinfo->fd->num;
+ call_value->rep_frame = pinfo->num;
}
}
}
- matched_key.frame = pinfo->fd->num;
+ matched_key.frame = pinfo->num;
matched_key.call_id = hdr->seqnum;
value = (dcerpc_call_value *)g_hash_table_lookup(dcerpc_matched, &matched_key);
if (!value) {
- v.uuid = hdr->if_id;
- v.ver = hdr->if_ver;
- v.object_uuid = hdr->obj_id;
- v.opnum = hdr->opnum;
- v.req_frame = 0;
- v.rep_frame = pinfo->fd->num;
- v.se_data = NULL;
- v.private_data = NULL;
- value = &v;
+ value = wmem_new0(wmem_packet_scope(), dcerpc_call_value);
+ value->uuid = hdr->if_id;
+ value->ver = hdr->if_ver;
+ value->object_uuid = hdr->obj_id;
+ value->opnum = hdr->opnum;
+ value->rep_frame = pinfo->num;
}
+ di = wmem_new0(wmem_packet_scope(), dcerpc_info);
+ di->dcerpc_procedure_name = "";
di->conv = conv;
- di->call_id = 0;
- di->smb_fid = -1;
+ di->transport_salt = -1;
di->ptype = PDU_RESP;
di->call_data = value;
if (parent_pi != NULL) {
proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
}
- nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
+ nstime_delta(&delta_ts, &pinfo->abs_ts, &value->req_time);
pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
PROTO_ITEM_SET_GENERATED(pi);
} else {
col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
- nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
+ nstime_delta(&delta_ts, &pinfo->abs_ts, &call_value->req_time);
pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
PROTO_ITEM_SET_GENERATED(pi);
/* }*/
dissect_dcerpc_dg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
proto_item *ti = NULL;
- proto_item *tf = NULL;
proto_tree *dcerpc_tree = NULL;
- proto_tree *dg_flags1_tree = NULL;
- proto_tree *dg_flags2_tree = NULL;
- proto_tree *drep_tree = NULL;
e_dce_dg_common_hdr_t hdr;
int offset = 0;
conversation_t *conv;
int auth_level;
char *uuid_str;
const char *uuid_name = NULL;
+ static const int * hdr_flags1[] = {
+ &hf_dcerpc_dg_flags1_rsrvd_80,
+ &hf_dcerpc_dg_flags1_broadcast,
+ &hf_dcerpc_dg_flags1_idempotent,
+ &hf_dcerpc_dg_flags1_maybe,
+ &hf_dcerpc_dg_flags1_nofack,
+ &hf_dcerpc_dg_flags1_frag,
+ &hf_dcerpc_dg_flags1_last_frag,
+ &hf_dcerpc_dg_flags1_rsrvd_01,
+ NULL
+ };
+
+ static const int * hdr_flags2[] = {
+ &hf_dcerpc_dg_flags2_rsrvd_80,
+ &hf_dcerpc_dg_flags2_rsrvd_40,
+ &hf_dcerpc_dg_flags2_rsrvd_20,
+ &hf_dcerpc_dg_flags2_rsrvd_10,
+ &hf_dcerpc_dg_flags2_rsrvd_08,
+ &hf_dcerpc_dg_flags2_rsrvd_04,
+ &hf_dcerpc_dg_flags2_cancel_pending,
+ &hf_dcerpc_dg_flags2_rsrvd_01,
+ NULL
+ };
/*
* Check if this looks like a CL DCERPC call. All dg packets
* have an 80 byte header on them. Which starts with
* version (4), pkt_type.
*/
- if (tvb_length(tvb) < sizeof (hdr)) {
+ if (tvb_reported_length(tvb) < sizeof (hdr)) {
return FALSE;
}
}
offset = 0;
- if (tree)
- proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
+ proto_tree_add_uint(dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
offset++;
- if (tree)
- proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
+ proto_tree_add_uint(dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
offset++;
- if (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_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);
- if (hdr.flags1) {
- proto_item_append_text(tf, " %s%s%s%s%s%s",
- (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
- (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
- (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
- (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
- (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
- (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
- }
- }
- }
+ proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags1,
+ ett_dcerpc_dg_flags1, hdr_flags1, hdr.flags1);
offset++;
- if (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_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);
- if (hdr.flags2) {
- proto_item_append_text(tf, " %s",
- (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
- }
- }
- }
+ proto_tree_add_bitmask_value(dcerpc_tree, tvb, offset, hf_dcerpc_dg_flags2,
+ ett_dcerpc_dg_flags2, hdr_flags2, hdr.flags2);
offset++;
if (tree) {
- tf = proto_tree_add_bytes(dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
- drep_tree = proto_item_add_subtree(tf, ett_dcerpc_drep);
- if (drep_tree) {
- proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
- proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
- proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
- proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
- val_to_str_const(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
- val_to_str_const(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
- val_to_str_const(hdr.drep[1], drep_fp_vals, "Unknown"));
- }
+ proto_tree_add_dcerpc_drep(dcerpc_tree, tvb, offset, hdr.drep, (int)sizeof (hdr.drep));
}
offset += (int)sizeof (hdr.drep);
if (tree) {
proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_obj_id, tvb,
offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
- guid_to_str((e_guid_t *) &hdr.obj_id));
+ guid_to_str(wmem_packet_scope(), (e_guid_t *) &hdr.obj_id));
}
offset += 16;
if (tree) {
- uuid_str = guid_to_str((e_guid_t*)&hdr.if_id);
+ uuid_str = guid_to_str(wmem_packet_scope(), (e_guid_t*)&hdr.if_id);
uuid_name = guids_get_uuid_name(&hdr.if_id);
if (uuid_name) {
proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
if (tree) {
proto_tree_add_guid_format(dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
- guid_to_str((e_guid_t *) &hdr.act_id));
+ guid_to_str(wmem_packet_scope(), (e_guid_t *) &hdr.act_id));
}
offset += 16;
dcerpc_init_protocol(void)
{
/* structures and data for BIND */
- if (dcerpc_binds) {
- g_hash_table_destroy(dcerpc_binds);
- dcerpc_binds = NULL;
- }
- if (!dcerpc_binds) {
- dcerpc_binds = g_hash_table_new(dcerpc_bind_hash, dcerpc_bind_equal);
- }
+ dcerpc_binds = g_hash_table_new(dcerpc_bind_hash, dcerpc_bind_equal);
/* structures and data for CALL */
- if (dcerpc_cn_calls) {
- g_hash_table_destroy(dcerpc_cn_calls);
- }
dcerpc_cn_calls = g_hash_table_new(dcerpc_cn_call_hash, dcerpc_cn_call_equal);
- if (dcerpc_dg_calls) {
- g_hash_table_destroy(dcerpc_dg_calls);
- }
dcerpc_dg_calls = g_hash_table_new(dcerpc_dg_call_hash, dcerpc_dg_call_equal);
/* structure and data for MATCHED */
- if (dcerpc_matched) {
- g_hash_table_destroy(dcerpc_matched);
- }
dcerpc_matched = g_hash_table_new(dcerpc_matched_hash, dcerpc_matched_equal);
+ decode_dcerpc_inject_bindings();
+}
- /* call the registered hooks */
- g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
+static void
+dcerpc_cleanup_protocol(void)
+{
+ g_hash_table_destroy(dcerpc_binds);
+ g_hash_table_destroy(dcerpc_cn_calls);
+ g_hash_table_destroy(dcerpc_dg_calls);
+ g_hash_table_destroy(dcerpc_matched);
}
void
{ &hf_dcerpc_response_in,
{ "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
- { &hf_dcerpc_referent_id,
+ { &hf_dcerpc_referent_id32,
{ "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
+ { &hf_dcerpc_referent_id64,
+ { "Referent ID", "dcerpc.referent_id64", FT_UINT64, BASE_HEX,
+ NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
{ &hf_dcerpc_ver,
{ "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
{ &hf_dcerpc_ver_minor,
{ "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_dcerpc_drep_byteorder,
{ "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS(drep_byteorder_vals), 0x0, NULL, HFILL }},
+ { &hf_dcerpc_ndr_padding,
+ { "NDR-Padding", "dcerpc.ndr_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_dcerpc_drep_character,
{ "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS(drep_character_vals), 0x0, NULL, HFILL }},
{ &hf_dcerpc_drep_fp,
{ "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_dcerpc_cn_bind_trans_ver,
{ "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
- { &hf_dcerpc_cn_bind_trans_btfn_01, /* [MS-RPCE] 2.2.2.14 */
- { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x01, NULL, HFILL }},
+ { &hf_dcerpc_cn_bind_trans_btfn, /* [MS-RPCE] 2.2.2.14 */
+ {"Bind Time Features", "dcerpc.cn_bind_trans_btfn", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_dcerpc_cn_bind_trans_btfn_01,
+ { "Security Context Multiplexing Supported", "dcerpc.cn_bind_trans_btfn.01", FT_BOOLEAN, 16, NULL, 0x01, NULL, HFILL }},
{ &hf_dcerpc_cn_bind_trans_btfn_02,
- { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x02, NULL, HFILL }},
+ { "Keep Connection On Orphan Supported", "dcerpc.cn_bind_trans_btfn.02", FT_BOOLEAN, 16, NULL, 0x02, NULL, HFILL }},
{ &hf_dcerpc_cn_alloc_hint,
{ "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
{ &hf_dcerpc_cn_sec_addr_len,
{ "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
{ &hf_dcerpc_cn_ack_trans_ver,
{ "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
- { &hf_dcerpc_cn_ack_btfn,
- { "Bind Time Feature Negotiation Bitmask", "dcerpc.cn_ack_btfn", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
{ &hf_dcerpc_cn_reject_reason,
{ "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
{ &hf_dcerpc_cn_num_protocols,
{ &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, NULL, HFILL }},
+ { &hf_dcerpc_null_pointer,
+ { "NULL Pointer", "dcerpc.null_pointer", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+
{ &hf_dcerpc_fragments,
{ "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
NULL, 0x0, "DCE/RPC Fragments", HFILL }},
{"Forward Destination", "dcerpc.cn_rts_command.forwarddestination", FT_UINT32, BASE_DEC, VALS(rts_forward_destination_vals), 0x0, NULL, HFILL }},
{ &hf_dcerpc_cn_rts_command_pingtrafficsentnotify,
{"Ping Traffic Sent Notify", "dcerpc.cn_rts_command.pingtrafficsentnotify", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_sec_vt_signature,
+ {"SEC_VT_SIGNATURE", "dcerpc.rpc_sec_vt.signature", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_sec_vt_command_end,
+ {"SEC_VT_COMMAND_END", "dcerpc.rpc_sec_vt.command.end", FT_BOOLEAN, 16, NULL, 0x4000, NULL, HFILL }},
+ { &hf_dcerpc_sec_vt_command_must,
+ {"SEC_VT_MUST_PROCESS_COMMAND", "dcerpc.rpc_sec_vt.command.must_process", FT_BOOLEAN, 16, NULL, 0x8000, NULL, HFILL }},
+ { &hf_dcerpc_sec_vt_command_cmd,
+ {"Cmd", "dcerpc.rpc_sec_vt.command.cmd", FT_UINT16, BASE_HEX, VALS(sec_vt_command_cmd_vals), 0x3fff, NULL, HFILL }},
+ { &hf_dcerpc_sec_vt_command,
+ {"Command", "dcerpc.rpc_sec_vt.command", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_dcerpc_sec_vt_command_length,
+ {"Length", "dcerpc.rpc_sec_vt.command.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL}},
+ { &hf_dcerpc_sec_vt_bitmask,
+ {"rpc_sec_vt_bitmask", "dcerpc.rpc_sec_vt.bitmask", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_dcerpc_sec_vt_bitmask_sign,
+ {"CLIENT_SUPPORT_HEADER_SIGNING", "dcerpc.rpc_sec_vt.bitmask.sign", FT_BOOLEAN, 32, NULL, 0x1, NULL, HFILL }},
+ { &hf_dcerpc_sec_vt_pcontext_uuid,
+ {"UUID", "dcerpc.rpc_sec_vt.pcontext.interface.uuid", FT_GUID, BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_dcerpc_sec_vt_pcontext_ver,
+ {"Version", "dcerpc.rpc_sec_vt.pcontext.interface.ver", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
+ { &hf_dcerpc_reserved,
+ {"Reserved", "dcerpc.reserved", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_dcerpc_unknown,
+ {"Unknown", "dcerpc.unknown", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_dcerpc_missalign,
+ {"missalign", "dcerpc.missalign", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
+ /* Generated from convert_proto_tree_add_text.pl */
+ { &hf_dcerpc_duplicate_ptr, { "duplicate PTR", "dcerpc.duplicate_ptr", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_encrypted_stub_data, { "Encrypted stub data", "dcerpc.encrypted_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_decrypted_stub_data, { "Decrypted stub data", "dcerpc.decrypted_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_payload_stub_data, { "Payload stub data", "dcerpc.payload_stub_data", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_stub_data_with_sec_vt, { "Stub data with rpc_sec_verification_trailer", "dcerpc.stub_data_with_sec_vt", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_stub_data, { "Stub data", "dcerpc.stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_auth_padding, { "Auth Padding", "dcerpc.auth_padding", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_auth_info, { "Auth Info", "dcerpc.auth_info", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_auth_verifier, { "Auth Verifier", "dcerpc.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_auth_credentials, { "Auth Credentials", "dcerpc.auth_credentials", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_fault_stub_data, { "Fault stub data", "dcerpc.fault_stub_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_fragment_data, { "Fragment data", "dcerpc.fragment_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_cmd_client_ipv4, { "RTS Client address", "dcerpc.cmd_client_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_cmd_client_ipv6, { "RTS Client address", "dcerpc.cmd_client_ipv6", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_dcerpc_authentication_verifier, { "Authentication verifier", "dcerpc.authentication_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
};
static gint *ett[] = {
&ett_dcerpc,
&ett_dcerpc_cn_iface,
&ett_dcerpc_cn_trans_syntax,
&ett_dcerpc_cn_trans_btfn,
+ &ett_dcerpc_cn_bind_trans_btfn,
&ett_dcerpc_cn_rts_flags,
&ett_dcerpc_cn_rts_command,
&ett_dcerpc_cn_rts_pdu,
&ett_dcerpc_fragments,
&ett_dcerpc_fragment,
&ett_dcerpc_krb5_auth_verf,
+ &ett_dcerpc_auth_info,
+ &ett_dcerpc_verification_trailer,
+ &ett_dcerpc_sec_vt_command,
+ &ett_dcerpc_sec_vt_bitmask,
+ &ett_dcerpc_sec_vt_pcontext,
+ &ett_dcerpc_sec_vt_header,
+ &ett_dcerpc_complete_stub_data,
};
static ei_register_info ei[] = {
- { &ei_dcerpc_fragment, { "dcerpc.fragment", PI_REASSEMBLE, PI_CHAT, "%s fragment", EXPFILL }},
+ { &ei_dcerpc_fragment, { "dcerpc.fragment.reassemble", PI_REASSEMBLE, PI_CHAT, "%s fragment", EXPFILL }},
{ &ei_dcerpc_fragment_reassembled, { "dcerpc.fragment_reassembled", PI_REASSEMBLE, PI_CHAT, "%s fragment, reassembled", EXPFILL }},
{ &ei_dcerpc_cn_ctx_id_no_bind, { "dcerpc.cn_ctx_id.no_bind", PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID %u - capture start too late?", EXPFILL }},
{ &ei_dcerpc_no_request_found, { "dcerpc.no_request_found", PI_SEQUENCE, PI_NOTE, "No request to this DCE/RPC call found", EXPFILL }},
{ &ei_dcerpc_fragment_multiple, { "dcerpc.fragment_multiple", PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet", EXPFILL }},
{ &ei_dcerpc_context_change, { "dcerpc.context_change", PI_SEQUENCE, PI_CHAT, "Context change: %s", EXPFILL }},
{ &ei_dcerpc_bind_not_acknowledged, { "dcerpc.bind_not_acknowledged", PI_SEQUENCE, PI_WARN, "Bind not acknowledged", EXPFILL }},
+ { &ei_dcerpc_verifier_unavailable, { "dcerpc.verifier_unavailable", PI_UNDECODED, PI_WARN, NULL, EXPFILL }},
+ { &ei_dcerpc_invalid_pdu_authentication_attempt, { "dcerpc.invalid_pdu_authentication_attempt", PI_UNDECODED, PI_WARN, NULL, EXPFILL }},
+ /* Generated from convert_proto_tree_add_text.pl */
+ { &ei_dcerpc_long_frame, { "dcerpc.long_frame", PI_PROTOCOL, PI_WARN, "Long frame", EXPFILL }},
+ { &ei_dcerpc_cn_rts_command, { "dcerpc.cn_rts_command.unknown", PI_PROTOCOL, PI_WARN, "unknown RTS command number", EXPFILL }},
};
+ /* Decode As handling */
+ static build_valid_func dcerpc_da_build_value[1] = {dcerpc_value};
+ static decode_as_value_t dcerpc_da_values = {dcerpc_prompt, 1, dcerpc_da_build_value};
+ static decode_as_t dcerpc_da = {"dcerpc", "DCE-RPC", "dcerpc.uuid",
+ 1, 0, &dcerpc_da_values, NULL, NULL,
+ dcerpc_populate_list, decode_dcerpc_binding_reset, dcerpc_decode_as_change, dcerpc_decode_as_free};
+
module_t *dcerpc_module;
expert_module_t* expert_dcerpc;
expert_dcerpc = expert_register_protocol(proto_dcerpc);
expert_register_field_array(expert_dcerpc, ei, array_length(ei));
+ uuid_dissector_table = register_dissector_table("dcerpc.uuid", "DCE/RPC UUIDs", proto_dcerpc, FT_GUID, BASE_HEX);
+
register_init_routine(dcerpc_init_protocol);
+ register_cleanup_routine(dcerpc_cleanup_protocol);
dcerpc_module = prefs_register_protocol(proto_dcerpc, NULL);
prefs_register_bool_preference(dcerpc_module,
"desegment_dcerpc",
dcerpc_uuids = g_hash_table_new(dcerpc_uuid_hash, dcerpc_uuid_equal);
dcerpc_tap = register_tap("dcerpc");
- g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
+ register_decode_as(&dcerpc_da);
+
+ register_srt_table(proto_dcerpc, NULL, 1, dcerpcstat_packet, dcerpcstat_init, dcerpcstat_param);
+
+ tvb_trailer_signature = tvb_new_real_data(TRAILER_SIGNATURE,
+ sizeof(TRAILER_SIGNATURE),
+ sizeof(TRAILER_SIGNATURE));
}
void
proto_reg_handoff_dcerpc(void)
{
- heur_dissector_add("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
- heur_dissector_add("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
- heur_dissector_add("udp", dissect_dcerpc_dg, proto_dcerpc);
- heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
- heur_dissector_add("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2, proto_dcerpc);
- heur_dissector_add("http", dissect_dcerpc_cn_bs, proto_dcerpc);
+ heur_dissector_add("tcp", dissect_dcerpc_tcp, "DCE/RPC over TCP", "dcerpc_tcp", proto_dcerpc, HEURISTIC_ENABLE);
+ heur_dissector_add("netbios", dissect_dcerpc_cn_pk, "DCE/RPC over NetBios", "dcerpc_netbios", proto_dcerpc, HEURISTIC_ENABLE);
+ heur_dissector_add("udp", dissect_dcerpc_dg, "DCE/RPC over UDP", "dcerpc_udp", proto_dcerpc, HEURISTIC_ENABLE);
+ heur_dissector_add("smb_transact", dissect_dcerpc_cn_smbpipe, "DCE/RPC over SMB", "dcerpc_smb_transact", proto_dcerpc, HEURISTIC_ENABLE);
+ heur_dissector_add("smb2_pipe_subdissectors", dissect_dcerpc_cn_smb2, "DCE/RPC over SMB2", "dcerpc_smb2", proto_dcerpc, HEURISTIC_ENABLE);
+ heur_dissector_add("http", dissect_dcerpc_cn_bs, "DCE/RPC over HTTP", "dcerpc_http", proto_dcerpc, HEURISTIC_ENABLE);
dcerpc_smb_init(proto_dcerpc);
guids_add_uuid(&uuid_data_repr_proto, "32bit NDR");
guids_add_uuid(&uuid_ndr64, "64bit NDR");
- guids_add_uuid(&uuid_bind_time_feature_nego_00, "bind time feature negotiation");
- guids_add_uuid(&uuid_bind_time_feature_nego_01, "bind time feature negotiation");
- guids_add_uuid(&uuid_bind_time_feature_nego_02, "bind time feature negotiation");
- guids_add_uuid(&uuid_bind_time_feature_nego_03, "bind time feature negotiation");
guids_add_uuid(&uuid_asyncemsmdb, "async MAPI");
}