* Copyright 2001, Todd Sabin <tas@webspan.net>
* Copyright 2003, Tim Potter <tpot@samba.org>
*
- * $Id: packet-dcerpc.c,v 1.145 2003/10/14 00:45:54 guy Exp $
+ * $Id: packet-dcerpc.c,v 1.158 2003/12/08 20:58:01 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
e_dce_cn_common_hdr_t *hdr,
dcerpc_auth_info *auth_info)
{
- dcerpc_dissect_fnct_t *fn = NULL;
+ dcerpc_dissect_fnct_t *volatile fn = NULL;
switch (hdr->ptype) {
case PDU_BIND:
key->uuid = *uuid;
key->ver = ver;
- value->proto = proto;
+ value->proto = find_protocol_by_id(proto);
+ value->proto_id = proto;
value->ett = ett;
- value->name = proto_get_protocol_short_name (proto);
+ value->name = proto_get_protocol_short_name (value->proto);
value->procs = procs;
value->opnum_hf = opnum_hf;
static void
show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
- dcerpc_auth_info *auth_info)
+ dcerpc_auth_info *auth_info, gboolean is_encrypted)
{
int length;
length = tvb_reported_length_remaining (tvb, offset);
if (auth_info != NULL &&
auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
- proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
- "Encrypted stub data (%d byte%s)",
- length, plurality(length, "", "s"));
+ if (is_encrypted) {
+ proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
+ "Encrypted stub data (%d byte%s)",
+ length, plurality(length, "", "s"));
+ } else {
+ proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
+ "Decrypted stub data (%d byte%s)",
+ length, plurality(length, "", "s"));
+ }
} else {
proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
"Stub data (%d byte%s)", length,
static int
dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
proto_tree *dcerpc_tree,
- tvbuff_t *volatile tvb, volatile gint offset,
+ tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
char *drep, dcerpc_info *info,
dcerpc_auth_info *auth_info)
{
+ volatile gint offset = 0;
dcerpc_uuid_key key;
dcerpc_uuid_value *sub_proto;
- int length;
proto_tree *volatile sub_tree = NULL;
dcerpc_sub_dissector *proc;
gchar *name = NULL;
dcerpc_dissect_fnct_t *volatile sub_dissect;
const char *volatile saved_proto;
void *volatile saved_private_data;
+ guint length, reported_length;
+ tvbuff_t *volatile stub_tvb;
+ volatile guint auth_pad_len;
+ volatile int auth_pad_offset;
key.uuid = info->call_data->uuid;
key.ver = info->call_data->ver;
* We don't have a dissector for this UUID, or the protocol
* for that UUID is disabled.
*/
- show_stub_data (tvb, offset, dcerpc_tree, auth_info);
+ if (decrypted_tvb != NULL) {
+ show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
+ FALSE);
+ } else
+ show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
return -1;
}
if (tree) {
proto_item *sub_item;
- sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
+ sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
-1, FALSE);
if (sub_item) {
*/
if (sub_proto->opnum_hf != -1)
- proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
- tvb, 0, 0, info->call_data->opnum,
- "Operation: %s (%u)",
- name, info->call_data->opnum);
+ proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
+ tvb, 0, 0, info->call_data->opnum,
+ "Operation: %s (%u)",
+ name, info->call_data->opnum);
else
- proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
- 0, 0, info->call_data->opnum,
- "Operation: %s (%u)",
- name, info->call_data->opnum);
+ proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
+ 0, 0, info->call_data->opnum,
+ "Operation: %s (%u)",
+ name, info->call_data->opnum);
}
sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
- /* Call subdissector if we have no auth info, or a zero auth_level and
- no decrypted data, or non-zero auth_level and sucessfully decrypted
- data. */
-
- if (sub_dissect && (auth_info == NULL ||
- (!auth_info->auth_level && !pinfo->decrypted_data) ||
- (auth_info->auth_level && pinfo->decrypted_data))) {
+ if (decrypted_tvb != NULL) {
+ /* Either there was no encryption or we successfully decrypted
+ the entrypted payload. */
+ if (sub_dissect) {
+ /* We have a subdissector - call it. */
saved_proto = pinfo->current_proto;
saved_private_data = pinfo->private_data;
pinfo->current_proto = sub_proto->name;
pinfo->private_data = (void *)info;
init_ndr_pointer_list(pinfo);
+
/*
- * Catch ReportedBoundsError, so that even if the stub
- * data is bad, we still show the verifier.
+ * Remove the authentication padding from the stub data.
*/
- TRY {
- offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
- } CATCH(BoundsError) {
- RETHROW;
- } CATCH(ReportedBoundsError) {
- show_reported_bounds_error(tvb, pinfo, tree);
- } ENDTRY;
-
- /* If there is auth padding at the end of the stub, display it */
if (auth_info != NULL && auth_info->auth_pad_len != 0) {
- proto_tree_add_text (sub_tree, tvb, offset,
- auth_info->auth_pad_len,
- "Auth Padding (%u byte%s)",
- auth_info->auth_pad_len,
- plurality(auth_info->auth_pad_len, "", "s"));
- offset += auth_info->auth_pad_len;
+ length = tvb_length(decrypted_tvb);
+ reported_length = tvb_reported_length(decrypted_tvb);
+ if (reported_length >= auth_info->auth_pad_len) {
+ /*
+ * OK, the padding length isn't so big that it
+ * exceeds the stub length. Trim the reported
+ * length of the tvbuff.
+ */
+ reported_length -= auth_info->auth_pad_len;
+
+ /*
+ * If that exceeds the actual amount of data in
+ * the tvbuff (which means we have at least one
+ * byte of authentication padding in the tvbuff),
+ * trim the actual amount.
+ */
+ if (length > reported_length)
+ length = reported_length;
+
+ stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
+ auth_pad_len = auth_info->auth_pad_len;
+ auth_pad_offset = reported_length;
+ } else {
+ /*
+ * The padding length exceeds the stub length.
+ * Don't bother dissecting the stub, trim the padding
+ * length to what's in the stub data, and show the
+ * entire stub as authentication padding.
+ */
+ stub_tvb = NULL;
+ auth_pad_len = reported_length;
+ auth_pad_offset = 0;
+ }
+ } else {
+ /*
+ * No authentication padding.
+ */
+ stub_tvb = decrypted_tvb;
+ auth_pad_len = 0;
+ auth_pad_offset = 0;
}
- /* If we have a subdissector and it didn't dissect all data in
- the tvb, make a note of it. */
+ if (stub_tvb != NULL) {
+ /*
+ * Catch all exceptions other than BoundsError, so that even
+ * if the stub data is bad, we still show the authentication
+ * padding, if any.
+ *
+ * If we get BoundsError, it means the frame was cut short
+ * by a snapshot length, so there's nothing more to
+ * dissect; just re-throw that exception.
+ */
+ TRY {
+ offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
+ drep);
+
+ /* If we have a subdissector and it didn't dissect all
+ data in the tvb, make a note of it. */
+
+ if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr(pinfo->cinfo, COL_INFO,
+ "[Long frame (%d bytes)]",
+ tvb_reported_length_remaining(stub_tvb, offset));
+ }
+ } CATCH(BoundsError) {
+ RETHROW;
+ } CATCH_ALL {
+ show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE);
+ } ENDTRY;
+ }
- if (tvb_length_remaining(tvb, offset)) {
- if (check_col(pinfo->cinfo, COL_INFO))
- col_append_fstr(pinfo->cinfo, COL_INFO,
- "[Long frame (%d bytes)]",
- tvb_length_remaining(tvb, offset));
- }
+ /* If there is auth padding at the end of the stub, display it */
+ if (auth_pad_len != 0) {
+ proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
+ auth_pad_len,
+ "Auth Padding (%u byte%s)",
+ auth_pad_len,
+ plurality(auth_pad_len, "", "s"));
+ }
pinfo->current_proto = saved_proto;
pinfo->private_data = saved_private_data;
} else {
- length = tvb_length_remaining (tvb, offset);
- if (length > 0) {
- proto_tree_add_text (sub_tree, tvb, offset, length,
- "Stub data (%d byte%s)", length,
- plurality(length, "", "s"));
+ /* No subdissector - show it as stub data. */
+ if(decrypted_tvb){
+ show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
+ } else {
+ show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
}
}
+ } else
+ show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
tap_queue_packet(dcerpc_tap, pinfo, info);
return 0;
auth_info->auth_data = NULL;
if (auth_info->auth_size != 0) {
- dcerpc_auth_subdissector_fns *auth_fns;
- tvbuff_t *auth_tvb;
+ dcerpc_auth_subdissector_fns *auth_fns;
+ tvbuff_t *auth_tvb;
- auth_offset = hdr->frag_len - hdr->auth_len;
+ auth_offset = hdr->frag_len - hdr->auth_len;
- auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
- hdr->auth_len);
+ auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
+ hdr->auth_len);
- auth_info->auth_data = auth_tvb;
+ auth_info->auth_data = auth_tvb;
- 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, auth_tvb, 0, hdr->auth_len,
- "Auth Verifier");
+ if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
+ auth_info->auth_type))) {
+ /*
+ * Catch all exceptions, so that even if the verifier is bad
+ * or we don't have all of it, we still show the stub data.
+ */
+ TRY {
+ dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
+ hdr, auth_info);
+ } CATCH_ALL {
+ show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
+ } ENDTRY;
+ } else {
+ proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
+ "Auth Verifier");
+ }
}
return hdr->auth_len;
}
static void
-dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
- e_dce_cn_common_hdr_t *hdr, gboolean are_credentials,
- dcerpc_auth_info *auth_info)
+dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
+ proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
+ gboolean are_credentials, dcerpc_auth_info *auth_info)
{
- int offset;
+ volatile int offset;
/*
* Initially set auth_level and auth_type to zero to indicate that we
*/
auth_info->auth_level = 0;
auth_info->auth_type = 0;
+ auth_info->auth_size = 0;
+ auth_info->auth_pad_len = 0;
/*
* The authentication information is at the *end* of the PDU; in
* request and response PDUs, the request and response stub data
* come before it.
*
- * If the full packet is here, and we've got an auth len, and it's
- * valid, then dissect the auth info.
+ * Is there any authentication data (i.e., is the authentication length
+ * non-zero), and is the authentication length valid (i.e., is it, plus
+ * 8 bytes for the type/level/pad length/reserved/context id, less than
+ * or equal to the fragment length minus the starting offset of the
+ * stub data?)
*/
- if (tvb_length (tvb) >= hdr->frag_len
- && hdr->auth_len
- && (hdr->auth_len + 8 <= hdr->frag_len)) {
+ if (hdr->auth_len
+ && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
+ /*
+ * Yes, there is authentication data, and the length is valid.
+ * Do we have all the bytes of stub data?
+ * (If not, we'd throw an exception dissecting *that*, so don't
+ * bother trying to dissect the authentication information and
+ * throwing another exception there.)
+ */
offset = hdr->frag_len - (hdr->auth_len + 8);
-
- offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- hf_dcerpc_auth_type,
- &auth_info->auth_type);
- offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- hf_dcerpc_auth_level,
- &auth_info->auth_level);
-
- offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- hf_dcerpc_auth_pad_len,
- &auth_info->auth_pad_len);
- offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- hf_dcerpc_auth_rsrvd, NULL);
- offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
- hf_dcerpc_auth_ctx_id, NULL);
-
- /*
- * Dissect the authentication data.
- */
- if (are_credentials) {
- tvbuff_t *auth_tvb;
- dcerpc_auth_subdissector_fns *auth_fns;
-
- auth_tvb = tvb_new_subset(
- tvb, offset, hdr->auth_len, hdr->auth_len);
-
- if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
- auth_info->auth_type)))
- dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
- hdr, auth_info);
- else
- proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
- "Auth Credentials");
- }
+ if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
+ /*
+ * Either there's no stub data, or the last byte of the stub
+ * data is present in the captured data, so we shouldn't
+ * get a BoundsError dissecting the stub data.
+ *
+ * Try dissecting the authentication data.
+ * Catch all exceptions, so that even if the auth info is bad
+ * or we don't have all of it, we still show the stuff we
+ * dissect after this, such as stub data.
+ */
+ TRY {
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ hf_dcerpc_auth_type,
+ &auth_info->auth_type);
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ hf_dcerpc_auth_level,
+ &auth_info->auth_level);
+
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ hf_dcerpc_auth_pad_len,
+ &auth_info->auth_pad_len);
+ offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ hf_dcerpc_auth_rsrvd, NULL);
+ offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
+ hf_dcerpc_auth_ctx_id, NULL);
+
+ /*
+ * Dissect the authentication data.
+ */
+ if (are_credentials) {
+ tvbuff_t *auth_tvb;
+ dcerpc_auth_subdissector_fns *auth_fns;
+
+ auth_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
+ hdr->auth_len);
+
+ if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
+ auth_info->auth_type)))
+ dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
+ hdr, auth_info);
+ else
+ proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
+ "Auth Credentials");
+ }
- /* Compute the size of the auth block. Note that this should not
- include auth padding, since when NTLMSSP encryption is used, the
- padding is actually inside the encrypted stub */
- auth_info->auth_size = hdr->auth_len + 8;
- } else {
- auth_info->auth_size = 0;
- auth_info->auth_pad_len = 0;
+ /* Compute the size of the auth block. Note that this should not
+ include auth padding, since when NTLMSSP encryption is used, the
+ padding is actually inside the encrypted stub */
+ auth_info->auth_size = hdr->auth_len + 8;
+ } CATCH_ALL {
+ show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
+ } ENDTRY;
+ }
}
}
proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
{
conversation_t *conv = NULL;
- guint8 num_ctx_items;
+ guint8 num_ctx_items = 0;
guint i;
gboolean saw_ctx_item = FALSE;
guint16 ctx_id;
key.uuid = if_id;
key.ver = if_ver;
+ if (num_ctx_items > 1)
+ col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
+
if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
else
* an authentication header, and associate it with an authentication
* context, so subsequent PDUs can use that context.
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
}
static void
* XXX - do we need to do anything with the authentication level
* we get back from this?
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
if (check_col (pinfo->cinfo, COL_INFO)) {
if (num_results != 0 && result == 0) {
dcerpc_auth_info *auth_info, guint32 alloc_hint,
guint32 frame)
{
- gboolean save_fragmented, payload_ok;
+ gboolean save_fragmented;
fragment_data *fd_head=NULL;
guint32 tot_len;
- tvbuff_t *payload_tvb;
+ tvbuff_t *payload_tvb, *decrypted_tvb;
save_fragmented = pinfo->fragmented;
auth_info->auth_size, tvb_length_remaining(tvb, offset) -
auth_info->auth_size);
- payload_ok = TRUE;
-
/* Decrypt the PDU if it is encrypted */
- pinfo->decrypted_data = NULL;
-
- if (auth_info->auth_type) {
+ 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;
- if (dcerpc_tree)
- proto_tree_add_text(
- dcerpc_tree, payload_tvb, 0, -1,
- "Encrypted Stub Data (%d byte%s)",
- tvb_length(payload_tvb),
- plurality(tvb_length(payload_tvb), "", "s"));
+ /* Start out assuming we won't succeed in decrypting. */
+ decrypted_tvb = NULL;
if ((auth_fns = get_auth_subdissector_fns(
auth_info->auth_level, auth_info->auth_type))) {
hdr->ptype == PDU_REQ, auth_info);
if (result) {
- int len = tvb_length(result);
+ if (dcerpc_tree)
+ proto_tree_add_text(
+ dcerpc_tree, payload_tvb, 0, -1,
+ "Encrypted stub data (%d byte%s)",
+ tvb_reported_length(payload_tvb),
+
+ plurality(tvb_length(payload_tvb), "", "s"));
add_new_data_source(
- pinfo, result, "Decrypted Stub Data");
+ pinfo, result, "Decrypted stub data");
- pinfo->decrypted_data = result;
-
- proto_tree_add_text(
- dcerpc_tree, result, 0, len,
- "Decrypted Stub Data (%d byte%s)",
- len, plurality(len, "", "s"));
- } else
- payload_ok = FALSE;
+ /* We succeeded. */
+ decrypted_tvb = result;
+ }
}
- }
+ } else
+ decrypted_tvb = payload_tvb;
/* if this packet is not fragmented, just dissect it and exit */
if(PFC_NOT_FRAGMENTED(hdr)){
pinfo->fragmented = FALSE;
dcerpc_try_handoff(
- pinfo, tree, dcerpc_tree,
- pinfo->decrypted_data ? pinfo->decrypted_data : payload_tvb,
- 0, hdr->drep, di, auth_info);
+ pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
+ hdr->drep, di, auth_info);
pinfo->fragmented = save_fragmented;
return;
/* if we are not doing reassembly and this is the first fragment
then just dissect it and exit
+ XXX - if we're not doing reassembly, can we decrypt an
+ encrypted stub?
*/
if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
dcerpc_try_handoff(
- pinfo, tree, dcerpc_tree,
- pinfo->decrypted_data ? pinfo->decrypted_data :
- payload_tvb, 0, hdr->drep, di, auth_info);
+ pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
+ hdr->drep, di, auth_info);
if (check_col(pinfo->cinfo, COL_INFO)) {
col_append_fstr(pinfo->cinfo, COL_INFO,
return;
}
- /* Replace encrypted payload with decrypted version for reassembly. */
-
- if (pinfo->decrypted_data)
- payload_tvb = (tvbuff_t *)pinfo->decrypted_data;
-
/* if we have already seen this packet, see if it was reassembled
and if so dissect the full pdu.
then exit
thus we must reassemble it.
*/
+ /* Do we have any non-encrypted data to reassemble? */
+ if (decrypted_tvb == NULL) {
+ /* No. We can't even try to reassemble. */
+ goto end_cn_stub;
+ }
+
/* if this is the first fragment we need to start reassembly
*/
if(hdr->flags&PFC_FIRST_FRAG){
- fragment_add(payload_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
- 0, tvb_length(payload_tvb), TRUE);
+ fragment_add(decrypted_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
+ 0, tvb_length(decrypted_tvb), TRUE);
fragment_set_tot_len(pinfo, frame,
dcerpc_co_reassemble_table, alloc_hint);
if(!(hdr->flags&PFC_LAST_FRAG)){
tot_len = fragment_get_tot_len(pinfo, frame,
dcerpc_co_reassemble_table);
- fragment_add(payload_tvb, 0, pinfo, frame,
+ fragment_add(decrypted_tvb, 0, pinfo, frame,
dcerpc_co_reassemble_table,
- tot_len-alloc_hint, tvb_length(payload_tvb),
+ tot_len-alloc_hint, tvb_length(decrypted_tvb),
TRUE);
goto end_cn_stub;
*/
tot_len = fragment_get_tot_len(pinfo, frame,
dcerpc_co_reassemble_table);
- fd_head = fragment_add(payload_tvb, 0, pinfo,
+ fd_head = fragment_add(decrypted_tvb, 0, pinfo,
frame,
dcerpc_co_reassemble_table,
- tot_len-alloc_hint, tvb_length(payload_tvb),
+ tot_len-alloc_hint, tvb_length(decrypted_tvb),
TRUE);
end_cn_stub:
tvbuff_t *next_tvb;
next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
- tvb_set_child_real_data_tvbuff(payload_tvb, next_tvb);
+ tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
show_fragment_tree(fd_head, &dcerpc_frag_items,
dcerpc_tree, pinfo, next_tvb);
pinfo->fragmented = FALSE;
dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
- 0, hdr->drep, di, auth_info);
+ next_tvb, hdr->drep, di, auth_info);
} else {
- proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in, payload_tvb, 0, 0,
- fd_head->reassembled_in);
+ proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
+ decrypted_tvb, 0, 0, fd_head->reassembled_in);
if (check_col(pinfo->cinfo, COL_INFO)) {
col_append_fstr(pinfo->cinfo, COL_INFO,
" [DCE/RPC %s fragment]", fragment_type(hdr->flags));
}
} else {
/* Reassembly not complete - some fragments
- are missing */
+ are missing. Just show the stub data. */
if (check_col(pinfo->cinfo, COL_INFO)) {
col_append_fstr(pinfo->cinfo, COL_INFO,
" [DCE/RPC %s fragment]", fragment_type(hdr->flags));
}
+
+ if(decrypted_tvb){
+ show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
+ } else {
+ show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
+ }
}
pinfo->fragmented = save_fragmented;
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
if (!conv)
- show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
+ show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
else {
dcerpc_matched_key matched_key, *new_matched_key;
dcerpc_call_value *value;
hdr, di, &auth_info, alloc_hint,
value->req_frame);
} else
- show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
+ show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
}
}
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
if (!conv) {
/* no point in creating one here, really */
- show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
+ show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
} else {
dcerpc_matched_key matched_key, *new_matched_key;
hdr, di, &auth_info, alloc_hint,
value->rep_frame);
} else
- show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
+ show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
}
}
* XXX - what if this was set when the connection was set up,
* and we just have a security context?
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
/*
* DCERPC dissector for connection oriented calls
*/
-static int
+static gboolean
dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
- proto_tree *tree, gboolean can_desegment)
+ proto_tree *tree, gboolean can_desegment, int *pkt_len)
{
static char nulls[4] = { 0 };
int start_offset;
* Check if this looks like a C/O DCERPC call
*/
if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
- return -1;
+ return FALSE; /* not enough information to check */
}
start_offset = offset;
hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
if (hdr.rpc_ver != 5)
- return -1;
+ return FALSE;
hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
- return -1;
+ return FALSE;
hdr.ptype = tvb_get_guint8 (tvb, offset++);
if (hdr.ptype > 19)
- return -1;
+ return FALSE;
hdr.flags = tvb_get_guint8 (tvb, offset++);
tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
&& !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
pinfo->desegment_offset = start_offset;
pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
- return 0; /* desegmentation required */
+ *pkt_len = 0; /* desegmentation required */
+ return TRUE;
}
if (check_col (pinfo->cinfo, COL_PROTOCOL))
pckt_vals[hdr.ptype].strptr, hdr.call_id);
if (tree) {
- offset = start_offset;
+ offset = start_offset;
ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
if (ti) {
dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
offset += 4;
}
+ /*
+ * None of the stuff done above should throw an exception, because
+ * we would have rejected this as "not DCE RPC" if we didn't have all
+ * of it. (XXX - perhaps we should request reassembly if we have
+ * enough of the header to consider it DCE RPC but not enough to
+ * get the fragment length; in that case the stuff still wouldn't
+ * throw an exception.)
+ *
+ * The rest of the stuff might, so return the PDU length to our caller.
+ * XXX - should we construct a tvbuff containing only the PDU and
+ * use that? Or should we have separate "is this a DCE RPC PDU",
+ * "how long is it", and "dissect it" routines - which might let us
+ * do most of the work in "tcp_dissect_pdus()"?
+ */
+ if (pkt_len != NULL)
+ *pkt_len = hdr.frag_len + padding;
+
/*
* Packet type specific stuff is next.
*/
/*
* Nothing after the common header other than credentials.
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, TRUE,
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
&auth_info);
break;
* Nothing after the common header other than an authentication
* verifier.
*/
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
&auth_info);
break;
default:
/* might as well dissect the auth info */
- dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
+ dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
&auth_info);
break;
}
- return hdr.frag_len + padding;
+ return TRUE;
}
/*
* Only one PDU per transport packet, and only one transport
* packet per PDU.
*/
- if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
+ if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
/*
* It wasn't a DCERPC PDU.
*/
static gboolean
dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- int offset = 0;
+ volatile int offset = 0;
int pdu_len;
- gboolean ret = FALSE;
+ volatile gboolean is_dcerpc_pdu;
+ volatile gboolean ret = FALSE;
/*
* There may be multiple PDUs per transport packet; keep
* processing them.
*/
while (tvb_reported_length_remaining(tvb, offset) != 0) {
- pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
- dcerpc_cn_desegment);
- if (pdu_len == -1) {
+ /*
+ * Catch ReportedBoundsError, so that even if the stub data is bad,
+ * we don't abort the full DCE RPC dissection - there might be more
+ * than one DCE RPC PDU in the data being dissected.
+ *
+ * If we get BoundsError, it means the frame was cut short by a
+ * snapshot length, so there's nothing more to dissect; just
+ * re-throw that exception.
+ */
+ is_dcerpc_pdu = FALSE;
+ TRY {
+ is_dcerpc_pdu = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
+ dcerpc_cn_desegment, &pdu_len);
+ } CATCH(BoundsError) {
+ RETHROW;
+ } CATCH(ReportedBoundsError) {
+ show_reported_bounds_error(tvb, pinfo, tree);
+ } ENDTRY;
+
+ if (!is_dcerpc_pdu) {
/*
* Not a DCERPC PDU.
*/
int length, reported_length, stub_length;
gboolean save_fragmented;
fragment_data *fd_head;
+ tvbuff_t *next_tvb;
- if (check_col (pinfo->cinfo, COL_INFO)) {
- col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u",
- di->call_data->opnum);
- }
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u", di->call_data->opnum );
length = tvb_length_remaining (tvb, offset);
reported_length = tvb_reported_length_remaining (tvb, offset);
if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
!tvb_bytes_exist(tvb, offset, stub_length) ){
if(hdr->frag_num == 0) {
+
+
+ if (check_col (pinfo->cinfo, COL_INFO))
+ col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
+ di->call_data->uuid.Data1, di->call_data->uuid.Data2, di->call_data->uuid.Data3, di->call_data->uuid.Data4[0],
+ di->call_data->uuid.Data4[1], di->call_data->uuid.Data4[2], di->call_data->uuid.Data4[3],
+ di->call_data->uuid.Data4[4], di->call_data->uuid.Data4[5], di->call_data->uuid.Data4[6],
+ di->call_data->uuid.Data4[7], di->call_data->ver);
+
+
/* First fragment, possibly the only fragment */
/*
* XXX - authentication info?
*/
pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
- dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
- tvb_new_subset (tvb, offset, length,
- reported_length),
- 0, hdr->drep, di, NULL);
+ next_tvb = tvb_new_subset (tvb, offset, length,
+ reported_length);
+ dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
+ next_tvb, hdr->drep, di, NULL);
} else {
/* PDU is fragmented and this isn't the first fragment */
if (check_col(pinfo->cinfo, COL_INFO)) {
!(hdr->flags1 & PFCL1_LASTFRAG));
if (fd_head != NULL) {
/* We completed reassembly */
- tvbuff_t *next_tvb;
-
next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
tvb_set_child_real_data_tvbuff(tvb, next_tvb);
add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
*/
pinfo->fragmented = FALSE;
dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
- 0, hdr->drep, di, NULL);
+ next_tvb, hdr->drep, di, NULL);
} else {
/* Reassembly isn't completed yet */
if (check_col(pinfo->cinfo, COL_INFO)) {
{ "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_dg_fack_window_size,
- { "Window Size", "dcerpc.fack_window size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
+ { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
{ &hf_dcerpc_dg_fack_max_tsdu,
{ "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},