Refactor DCE/RPC dissection to include a real dissector table.

This is hopefully just the first step in getting DCE/RPC dissection to use "standard" APIs instead of homegrown ones.
For starters, it allows Decode As functionality to be less hacky (although incomplete in Qt)

Change-Id: Ia0923a3d8d514ab7acce32e26ee7e08f6e24feca
Reviewed-on: https://code.wireshark.org/review/11468
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
This commit is contained in:
Michael Mann 2015-10-31 22:35:06 -04:00
parent 74541a9596
commit e0e574d167
8 changed files with 331 additions and 321 deletions

View File

@ -191,7 +191,6 @@ libwireshark.so.0 libwireshark0 #MINVER#
crc6_compute_tvb@Base 1.99.0
create_dissector_handle@Base 1.9.1
data_out_file@Base 1.9.1
dcerpc_get_proto_hf_opnum@Base 1.9.1
dcerpc_get_proto_name@Base 1.9.1
dcerpc_get_proto_sub_dissector@Base 1.9.1
dcerpc_get_transport_salt@Base 1.9.1

View File

@ -854,7 +854,7 @@ 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;
/*dcerpc_uuid_key *k = key;*/
/*guid_key *k = key;*/
dcerpc_uuid_value *v = (dcerpc_uuid_value *)value;
if (strcmp(v->name, "(none)"))
@ -929,11 +929,11 @@ dcerpc_decode_as_change(const char *name, const gpointer pattern, gpointer handl
{
decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t*)pattern;
decode_dcerpc_bind_values_t *stored_binding;
dcerpc_uuid_key *key = *((dcerpc_uuid_key**)handle);
guid_key *key = *((guid_key**)handle);
binding->ifname = g_string_new(list_name);
binding->uuid = key->uuid;
binding->uuid = key->guid;
binding->ver = key->ver;
/* remove a probably existing old binding */
@ -1255,42 +1255,293 @@ static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
return NULL;
}
typedef struct _dcerpc_dissector_data
{
dcerpc_uuid_value *sub_proto;
dcerpc_info *info;
gboolean decrypted;
dcerpc_auth_info *auth_info;
guint8 *drep;
} 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_guid_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 void
show_stub_data(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);
}
} else {
proto_tree_add_item(dcerpc_tree, hf_dcerpc_stub_data, tvb, offset, plain_length, ENC_NA);
}
/* 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;
dcerpc_dissect_fnct_t *sub_dissect = NULL;
proto_item *pi, *sub_item;
proto_tree *sub_tree;
guint length, reported_length;
volatile gint offset = 0;
tvbuff_t *volatile stub_tvb;
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(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 {
int remaining;
offset = sub_dissect(stub_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 (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_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);
@ -1305,6 +1556,10 @@ dcerpc_init_uuid(int proto, int ett, e_guid_t *uuid, guint16 ver,
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 = new_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));
@ -1322,15 +1577,12 @@ dcerpc_init_uuid(int proto, int ett, e_guid_t *uuid, guint16 ver,
const char *
dcerpc_get_proto_name(e_guid_t *uuid, guint16 ver)
{
dcerpc_uuid_key key;
dcerpc_uuid_value *sub_proto;
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))) {
return NULL;
}
return sub_proto->name;
return dissector_handle_get_short_name(dissector_get_guid_handle(uuid_dissector_table, &key));
}
/* Function to find the opnum hf-field of a registered protocol
@ -1339,10 +1591,10 @@ dcerpc_get_proto_name(e_guid_t *uuid, guint16 ver)
int
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;
@ -1385,10 +1637,10 @@ again:
dcerpc_sub_dissector *
dcerpc_get_proto_sub_dissector(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 NULL;
@ -2973,78 +3225,32 @@ dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
return ret;
}
static void
show_stub_data(tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
dcerpc_auth_info *auth_info, gboolean is_encrypted)
{
int length, 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);
}
} else {
proto_tree_add_item(dcerpc_tree, hf_dcerpc_stub_data, tvb, offset, plain_length, ENC_NA);
}
/* 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
dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
proto_tree *dcerpc_tree,
tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
tvbuff_t *volatile tvb, gboolean decrypted,
guint8 *drep, dcerpc_info *info,
dcerpc_auth_info *auth_info)
{
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;
guid_key key;
dcerpc_dissector_data_t dissector_data;
proto_item *hidden_item;
dcerpc_dissect_fnct_t *volatile sub_dissect;
key.uuid = info->call_data->uuid;
/* 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;
if ((sub_proto = (dcerpc_uuid_value *)g_hash_table_lookup(dcerpc_uuids, &key)) == NULL
|| !proto_is_protocol_enabled(sub_proto->proto)) {
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;
/* 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.
@ -3056,198 +3262,10 @@ dcerpc_try_handoff(packet_info *pinfo, proto_tree *tree,
col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u",
guids_resolve_guid_to_str(&info->call_data->uuid), info->call_data->ver);
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);
show_stub_data(tvb, 0, dcerpc_tree, auth_info, !decrypted);
return -1;
}
for (proc = sub_proto->procs; proc->name; proc++) {
if (proc->num == info->call_data->opnum) {
name = proc->name;
break;
}
}
col_set_str(pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
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");
sub_dissect = (info->ptype == PDU_REQ) ?
proc->dissect_rqst : proc->dissect_resp;
if (tree) {
sub_item = proto_tree_add_item(tree, sub_proto->proto_id,
(decrypted_tvb != NULL)?decrypted_tvb:tvb,
0, -1, ENC_NA);
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);
}
/*
* 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);
if ((info->ptype == PDU_REQ) && (info->call_data->rep_frame != 0)) {
pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
tvb, 0, 0, info->call_data->rep_frame);
PROTO_ITEM_SET_GENERATED(pi);
}
if ((info->ptype == PDU_RESP) && (info->call_data->req_frame != 0)) {
pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
tvb, 0, 0, info->call_data->req_frame);
PROTO_ITEM_SET_GENERATED(pi);
}
} /* tree */
if (decrypted_tvb != NULL) {
/* Either there was no encryption or we successfully decrypted
the encrypted payload. */
if (sub_dissect) {
/* We have a subdissector - call it. */
saved_proto = pinfo->current_proto;
pinfo->current_proto = sub_proto->name;
init_ndr_pointer_list(info);
length = tvb_captured_length(decrypted_tvb);
reported_length = tvb_reported_length(decrypted_tvb);
/*
* Remove the authentication padding from the stub data.
*/
if ((auth_info != NULL) && (auth_info->auth_pad_len != 0)) {
if (reported_length >= auth_info->auth_pad_len) {
/*
* OK, the padding length isn't so big that it
* exceeds the stub length. Trim the reported
* length of the tvbuff.
*/
reported_length -= auth_info->auth_pad_len;
/*
* If that exceeds the actual amount of data in
* the tvbuff (which means we have at least one
* byte of authentication padding in the tvbuff),
* trim the actual amount.
*/
if (length > reported_length)
length = reported_length;
stub_tvb = tvb_new_subset(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;
}
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 {
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_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(dcerpc_tree, hf_dcerpc_auth_padding, decrypted_tvb, auth_pad_offset, auth_pad_len, ENC_NA);
}
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);
}
}
} else
show_stub_data(tvb, 0, sub_tree, auth_info, TRUE);
tap_queue_packet(dcerpc_tap, pinfo, info);
return 0;
}
@ -3797,10 +3815,11 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
gboolean save_fragmented;
fragment_head *fd_head = NULL;
tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb = NULL;
proto_item *pi;
proto_item *parent_pi;
proto_item *dcerpc_tree_item;
gboolean decrypted = FALSE;
save_fragmented = pinfo->fragmented;
@ -3840,7 +3859,7 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
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
*/
@ -3857,8 +3876,8 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
hdr->ptype == PDU_REQ, auth_info);
if (result) {
if (dcerpc_tree)
proto_tree_add_item(dcerpc_tree, hf_dcerpc_encrypted_stub_data, payload_tvb, 0, -1, ENC_NA);
decrypted = TRUE;
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");
@ -3874,8 +3893,7 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
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,
hdr->drep, di, auth_info);
pinfo->fragmented = save_fragmented;
@ -3897,8 +3915,7 @@ dissect_dcerpc_cn_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
*/
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,
hdr->drep, di, auth_info);
expert_add_info_format(pinfo, NULL, &ei_dcerpc_fragment, "%s fragment", fragment_type(hdr->flags));
@ -3983,8 +4000,7 @@ end_cn_stub:
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) {
@ -5549,8 +5565,7 @@ dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
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 (length > 0) {
@ -5584,8 +5599,7 @@ dissect_dcerpc_dg_stub(tvbuff_t *tvb, int offset, packet_info *pinfo,
* 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,
@ -6524,10 +6538,7 @@ proto_register_dcerpc(void)
/* 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",
/* XXX - DCE/RPC doesn't have a true (sub)dissector table, so
provide a "fake" one to fit the Decode As algorithm */
"dcerpc.fake",
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};
@ -6540,6 +6551,8 @@ proto_register_dcerpc(void)
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", FT_GUID, BASE_HEX);
register_init_routine(dcerpc_init_protocol);
register_cleanup_routine(dcerpc_cleanup_protocol);
dcerpc_module = prefs_register_protocol(proto_dcerpc, NULL);

View File

@ -411,16 +411,11 @@ WS_DLL_PUBLIC void decode_dcerpc_add_show_list(decode_add_show_list_func func, g
/* the registered subdissectors. With MSVC and a
* libwireshark.dll, we need a special declaration.
*/
/* Key: dcerpc_uuid_key *
/* Key: guid_key *
* Value: dcerpc_uuid_value *
*/
WS_DLL_PUBLIC GHashTable *dcerpc_uuids;
typedef struct _dcerpc_uuid_key {
e_guid_t uuid;
guint16 ver;
} dcerpc_uuid_key;
typedef struct _dcerpc_uuid_value {
protocol_t *proto;
int proto_id;

View File

@ -290,9 +290,9 @@ static e_guid_t *dcerpc_uuid_program;
static guint16 dcerpc_version;
static GtkWidget *dlg = NULL;
static GtkWidget *filter_entry;
static dcerpc_uuid_key *current_uuid_key;
static guid_key *current_uuid_key;
static dcerpc_uuid_value *current_uuid_value;
static dcerpc_uuid_key *new_uuid_key;
static guid_key *new_uuid_key;
static dcerpc_uuid_value *new_uuid_value;
static void
@ -328,7 +328,7 @@ dcerpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
static void
dcerpcstat_version_select(GtkWidget *vers_combo_box, gpointer user_data _U_)
{
dcerpc_uuid_key *k;
guid_key *k;
if (! ws_combo_box_get_active_pointer(GTK_COMBO_BOX(vers_combo_box), (gpointer *)&k)) {
g_assert_not_reached(); /* Programming error: somehow no active item */
@ -340,11 +340,11 @@ dcerpcstat_version_select(GtkWidget *vers_combo_box, gpointer user_data _U_)
static void
dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer user_data)
{
dcerpc_uuid_key *k = (dcerpc_uuid_key *)key;
guid_key *k = (guid_key *)key;
GtkWidget *vers_combo_box = (GtkWidget *)user_data;
char vs[5];
if(guid_cmp(&(k->uuid), dcerpc_uuid_program)){
if(guid_cmp(&(k->guid), dcerpc_uuid_program)){
return;
}
g_snprintf(vs, sizeof(vs), "%u", k->ver);
@ -354,7 +354,7 @@ dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer user_data)
static void
dcerpcstat_program_select(GtkWidget *prog_combo_box, gpointer user_data)
{
dcerpc_uuid_key *k;
guid_key *k;
GtkWidget *vers_combo_box;
vers_combo_box = (GtkWidget *)user_data;
@ -368,7 +368,7 @@ dcerpcstat_program_select(GtkWidget *prog_combo_box, gpointer user_data)
/* dcerpc_stat: invalid selection... somehow selected top level ?? */
g_assert(k != NULL);
dcerpc_uuid_program = &(k->uuid);
dcerpc_uuid_program = &(k->guid);
/* re-create version menu */
g_signal_handlers_disconnect_by_func(vers_combo_box, G_CALLBACK(dcerpcstat_version_select), NULL );
@ -382,7 +382,7 @@ dcerpcstat_program_select(GtkWidget *prog_combo_box, gpointer user_data)
}
static GtkTreeIter
dcerpcstat_add_program_to_menu(dcerpc_uuid_key *k, dcerpc_uuid_value *v, GtkWidget *prog_combo_box, int program_item_index)
dcerpcstat_add_program_to_menu(guid_key *k, dcerpc_uuid_value *v, GtkWidget *prog_combo_box, int program_item_index)
{
static GtkTreeIter iter;
char str[64];
@ -405,7 +405,7 @@ dcerpcstat_add_program_to_menu(dcerpc_uuid_key *k, dcerpc_uuid_value *v, GtkWidg
static void
dcerpcstat_find_next_program(gpointer *key, gpointer *value, gpointer *user_data _U_)
{
dcerpc_uuid_key *k = (dcerpc_uuid_key *)key;
guid_key *k = (guid_key *)key;
dcerpc_uuid_value *v = (dcerpc_uuid_value *)value;
/* first time called, just set new_uuid to this one */

View File

@ -1327,8 +1327,7 @@ decode_add_notebook (GtkWidget *format_hb)
entry = (decode_as_t *)list_entry->data;
if (!strcmp(proto_name, entry->name))
{
if ((find_dissector_table(entry->table_name) != NULL) ||
(!strcmp(proto_name, "dcerpc")))
if (find_dissector_table(entry->table_name) != NULL)
{
page = decode_add_simple_page(entry);
label = gtk_label_new(entry->title);

View File

@ -163,6 +163,10 @@ QString DecodeAsDialog::entryString(const gchar *table_name, gpointer value)
entry_str = (char *)value;
break;
case FT_GUID:
//TODO: DCE/RPC dissector table
break;
default:
g_assert_not_reached();
break;

View File

@ -61,7 +61,7 @@ dce_rpc_add_program(gpointer key_ptr, gpointer value_ptr, gpointer rsrtd_ptr)
RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
if (!rsrt_dlg) return;
dcerpc_uuid_key *key = (dcerpc_uuid_key *)key_ptr;
guid_key *key = (guid_key *)key_ptr;
dcerpc_uuid_value *value = (dcerpc_uuid_value *)value_ptr;
rsrt_dlg->addDceRpcProgram(key, value);
@ -73,7 +73,7 @@ dce_rpc_find_versions(gpointer key_ptr, gpointer, gpointer rsrtd_ptr)
RpcServiceResponseTimeDialog *rsrt_dlg = dynamic_cast<RpcServiceResponseTimeDialog *>((RpcServiceResponseTimeDialog *)rsrtd_ptr);
if (!rsrt_dlg) return;
dcerpc_uuid_key *key = (dcerpc_uuid_key *)key_ptr;
guid_key *key = (guid_key *)key_ptr;
rsrt_dlg->addDceRpcProgramVersion(key);
}
@ -240,14 +240,14 @@ TapParameterDialog *RpcServiceResponseTimeDialog::createOncRpcSrtDialog(QWidget
return onc_rpc_dlg;
}
void RpcServiceResponseTimeDialog::addDceRpcProgram(_dcerpc_uuid_key *key, _dcerpc_uuid_value *value)
void RpcServiceResponseTimeDialog::addDceRpcProgram(_guid_key *key, _dcerpc_uuid_value *value)
{
dce_name_to_uuid_key_.insert(value->name, key);
}
void RpcServiceResponseTimeDialog::addDceRpcProgramVersion(_dcerpc_uuid_key *key)
void RpcServiceResponseTimeDialog::addDceRpcProgramVersion(_guid_key *key)
{
if (guid_cmp(&(dce_name_to_uuid_key_[program_combo_->currentText()]->uuid), &(key->uuid))) return;
if (guid_cmp(&(dce_name_to_uuid_key_[program_combo_->currentText()]->guid), &(key->guid))) return;
versions_ << key->ver;
std::sort(versions_.begin(), versions_.end());
@ -286,7 +286,7 @@ void RpcServiceResponseTimeDialog::setDceRpcUuidAndVersion(_e_guid_t *uuid, int
{
bool found = false;
for (int pi = 0; pi < program_combo_->count(); pi++) {
if (guid_cmp(uuid, &(dce_name_to_uuid_key_[program_combo_->itemText(pi)]->uuid)) == 0) {
if (guid_cmp(uuid, &(dce_name_to_uuid_key_[program_combo_->itemText(pi)]->guid)) == 0) {
program_combo_->setCurrentIndex(pi);
for (int vi = 0; vi < version_combo_->count(); vi++) {
@ -394,13 +394,13 @@ void RpcServiceResponseTimeDialog::fillTree()
{
if (!dce_name_to_uuid_key_.contains(program_name)) return;
dcerpc_uuid_key *dkey = dce_name_to_uuid_key_[program_name];
guid_key *dkey = dce_name_to_uuid_key_[program_name];
dcerpcstat_tap_data_t *dtap_data = g_new0(dcerpcstat_tap_data_t, 1);
dtap_data->uuid = dkey->uuid;
dtap_data->uuid = dkey->guid;
dtap_data->prog = program_name_cptr;
dtap_data->ver = (guint16) version_combo_->itemData(version_combo_->currentIndex()).toUInt();
dcerpc_sub_dissector *procs = dcerpc_get_proto_sub_dissector(&(dkey->uuid), dtap_data->ver);
dcerpc_sub_dissector *procs = dcerpc_get_proto_sub_dissector(&(dkey->guid), dtap_data->ver);
for (int i = 0; procs[i].name; i++) {
if (procs[i].num > max_procs) max_procs = procs[i].num;
}

View File

@ -26,7 +26,7 @@
class QComboBox;
struct _dcerpc_uuid_key;
struct _guid_key;
struct _dcerpc_uuid_value;
struct _e_guid_t;
struct _rpc_prog_info_value;
@ -45,8 +45,8 @@ public:
static TapParameterDialog *createDceRpcSrtDialog(QWidget &parent, const QString, const QString opt_arg, CaptureFile &cf);
static TapParameterDialog *createOncRpcSrtDialog(QWidget &parent, const QString, const QString opt_arg, CaptureFile &cf);
void addDceRpcProgram(_dcerpc_uuid_key *key, struct _dcerpc_uuid_value *value);
void addDceRpcProgramVersion(_dcerpc_uuid_key *key);
void addDceRpcProgram(_guid_key *key, struct _dcerpc_uuid_value *value);
void addDceRpcProgramVersion(_guid_key *key);
void addOncRpcProgram(guint32 program, struct _rpc_prog_info_value *value);
void addOncRpcProgramVersion(guint32 program, guint32 version);
void updateOncRpcProcedureCount(guint32 program, guint32 version, int procedure);
@ -69,7 +69,7 @@ private:
QList<unsigned> versions_;
// DCE-RPC
QMap<QString, struct _dcerpc_uuid_key *> dce_name_to_uuid_key_;
QMap<QString, struct _guid_key *> dce_name_to_uuid_key_;
// ONC-RPC
QMap<QString, guint32> onc_name_to_program_;