diff options
-rw-r--r-- | epan/dissectors/packet-dcerpc-netlogon.c | 15 | ||||
-rw-r--r-- | epan/dissectors/packet-ositp.c | 77 | ||||
-rw-r--r-- | epan/dissectors/packet-rdp.c | 378 | ||||
-rw-r--r-- | epan/proto.c | 225 | ||||
-rw-r--r-- | epan/proto.h | 88 |
5 files changed, 616 insertions, 167 deletions
diff --git a/epan/dissectors/packet-dcerpc-netlogon.c b/epan/dissectors/packet-dcerpc-netlogon.c index 4ba49b5720..bf94f802bf 100644 --- a/epan/dissectors/packet-dcerpc-netlogon.c +++ b/epan/dissectors/packet-dcerpc-netlogon.c @@ -7383,7 +7383,8 @@ static int dissect_secchan_nl_auth_message(tvbuff_t *tvb, int offset, { proto_item *item = NULL; proto_tree *subtree = NULL; - guint32 messagetype, messageflags; + guint32 messagetype; + guint64 messageflags; static const int *flag_fields[] = { &hf_netlogon_secchan_nl_message_flags_nb_domain, &hf_netlogon_secchan_nl_message_flags_nb_host, @@ -7410,10 +7411,14 @@ static int dissect_secchan_nl_auth_message(tvbuff_t *tvb, int offset, hf_netlogon_secchan_nl_message_type, &messagetype); /* Flags */ - proto_tree_add_bitmask(subtree, tvb, offset, hf_netlogon_secchan_nl_message_flags, ett_secchan_nl_auth_message_flags, flag_fields, (drep[0] & DREP_LITTLE_ENDIAN)); - messageflags = ((drep[0] & DREP_LITTLE_ENDIAN) - ? tvb_get_letohl (tvb, offset) - : tvb_get_ntohl (tvb, offset)); + proto_tree_add_bitmask_ret_uint64(subtree, tvb, offset, + hf_netlogon_secchan_nl_message_flags, + ett_secchan_nl_auth_message_flags, + flag_fields, + (drep[0] & DREP_LITTLE_ENDIAN) ? + ENC_LITTLE_ENDIAN : + ENC_BIG_ENDIAN, + &messageflags); offset += 4; diff --git a/epan/dissectors/packet-ositp.c b/epan/dissectors/packet-ositp.c index 47f3851883..72f05db85f 100644 --- a/epan/dissectors/packet-ositp.c +++ b/epan/dissectors/packet-ositp.c @@ -146,6 +146,8 @@ static const fragment_items cotp_frag_items = { "segments" }; +static dissector_handle_t rdp_cr_handle; +static dissector_handle_t rdp_cc_handle; static dissector_handle_t data_handle; /* @@ -325,6 +327,10 @@ static int hf_cotp_vp_dst_tsap_bytes = -1; /* global variables */ +/* List of dissectors to call for the variable part of CR PDUs. */ +static heur_dissector_list_t cotp_cr_heur_subdissector_list; +/* List of dissectors to call for the variable part of CC PDUs. */ +static heur_dissector_list_t cotp_cc_heur_subdissector_list; /* List of dissectors to call for COTP packets put atop the Inactive Subset of CLNP. */ static heur_dissector_list_t cotp_is_heur_subdissector_list; @@ -1496,10 +1502,10 @@ static int ositp_decode_RJ(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, } /* ositp_decode_RJ */ -static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, - packet_info *pinfo, proto_tree *tree, - gboolean uses_inactive_subset, - gboolean *subdissector_found) +static int ositp_decode_CR_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, + packet_info *pinfo, proto_tree *tree, + gboolean uses_inactive_subset, + gboolean *subdissector_found) { /* note: in the ATN the user is up to chose between 3 different checksums: * standard OSI, 2 or 4 octet extended checksum. @@ -1567,37 +1573,33 @@ static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, offset += 1; li -= 1; - /* Microsoft runs their Remote Desktop Protocol atop ISO COTP - atop TPKT, and does some weird stuff in the CR packet: - - http://msdn.microsoft.com/en-us/library/cc240470 - - where they might stuff a string that begins with "Cookie: ", - possibly followed by an RDP Negotiation Request, into the - variable part of the CR packet. (See also - - http://download.microsoft.com/download/5/B/C/5BC37A4E-6304-45AB-8C2D-AE712526E7F7/TS_Session_Directory.pdf - - a/k/a "[MSFT-SDLBTS]", as linked to, under the name "Session - Directory and Load Balancing Using Terminal Server", on - - http://msdn.microsoft.com/en-us/library/E4BD6494-06AD-4aed-9823-445E921C9624 - - which indicates that the routingToken is a string of the form - "Cookie: msts=...".) + if (li > 0) { + /* There's more data left, so we have the variable part. - They also may stuff an RDP Negotiation Response into the CC - packet. + Microsoft's RDP hijacks the variable part of CR and CC PDUs + for their own user data (RDP runs atop Class 0, which doesn't + support user data). - XXX - have TPKT know that a given session is an RDP session, - and let us know, so we know whether to check for this stuff. */ - ositp_decode_var_part(tvb, offset, li, class_option, tpdu_len , pinfo, - cotp_tree); - offset += li; + Try what heuristic dissectors we have. */ + next_tvb = tvb_new_subset_length(tvb, offset, li); + if (dissector_try_heuristic((tpdu == CR_TPDU) ? + cotp_cr_heur_subdissector_list : + cotp_cc_heur_subdissector_list, + next_tvb, pinfo, tree, &hdtbl_entry, NULL)) { + /* A subdissector claimed this, so it really belongs to them. */ + *subdissector_found = TRUE; + } else { + /* No heuristic dissector claimed it, so dissect it as a regular + variable part. */ + ositp_decode_var_part(tvb, offset, li, class_option, tpdu_len, pinfo, + cotp_tree); + } + offset += li; + } /* - * XXX - tell the subdissector that this is user data in a CC or - * CR packet rather than a DT packet? + * XXX - tell the subdissector that this is user data in a CR or + * CC packet rather than a DT packet? */ next_tvb = tvb_new_subset_remaining(tvb, offset); if (!uses_inactive_subset){ @@ -1615,7 +1617,7 @@ static int ositp_decode_CC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, return offset; -} /* ositp_decode_CC */ +} /* ositp_decode_CR_CC */ static int ositp_decode_DC(tvbuff_t *tvb, int offset, guint8 li, guint8 tpdu, packet_info *pinfo, proto_tree *tree) @@ -2138,8 +2140,8 @@ static gint dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo, switch (tpdu) { case CC_TPDU : case CR_TPDU : - new_offset = ositp_decode_CC(tvb, offset, li, tpdu, pinfo, tree, - uses_inactive_subset, &subdissector_found); + new_offset = ositp_decode_CR_CC(tvb, offset, li, tpdu, pinfo, tree, + uses_inactive_subset, &subdissector_found); break; case DR_TPDU : new_offset = ositp_decode_DR(tvb, offset, li, tpdu, pinfo, tree); @@ -2420,6 +2422,10 @@ void proto_register_cotp(void) "transport PDUs\" in the CLNP protocol " "settings.", &cotp_decode_atn); + /* For handling protocols hijacking the variable part of CR or CC PDUs */ + cotp_cr_heur_subdissector_list = register_heur_dissector_list("cotp_cr"); + cotp_cc_heur_subdissector_list = register_heur_dissector_list("cotp_cc"); + /* subdissector code in inactive subset */ cotp_is_heur_subdissector_list = register_heur_dissector_list("cotp_is"); @@ -2464,6 +2470,8 @@ proto_reg_handoff_cotp(void) dissector_add_uint("ip.proto", IP_PROTO_TP, ositp_handle); data_handle = find_dissector("data"); + rdp_cr_handle = find_dissector("rdp_cr"); + rdp_cc_handle = find_dissector("rdp_cc"); proto_clnp = proto_get_id_by_filter_name("clnp"); } @@ -2480,4 +2488,3 @@ proto_reg_handoff_cotp(void) * vi: set shiftwidth=2 tabstop=8 expandtab: * :indentSize=2:tabSize=8:noTabs=true: */ - diff --git a/epan/dissectors/packet-rdp.c b/epan/dissectors/packet-rdp.c index 4ca94747ca..92d4c5f7bd 100644 --- a/epan/dissectors/packet-rdp.c +++ b/epan/dissectors/packet-rdp.c @@ -22,7 +22,7 @@ */ /* - * See: "[MS -RDPBCGR] Remote Desktop Protocol: Basic Connectivity and Graphics Remoting" + * See: "[MS-RDPBCGR] Remote Desktop Protocol: Basic Connectivity and Graphics Remoting" */ #include "config.h" @@ -31,6 +31,7 @@ #include <epan/prefs.h> #include <epan/conversation.h> #include <epan/asn1.h> +#include <epan/expert.h> #include "packet-ssl.h" #include "packet-t124.h" @@ -49,6 +50,13 @@ static void prefs_register_rdp(void); static int proto_rdp = -1; static int ett_rdp = -1; + +static int ett_negReq_flags = -1; +static int ett_requestedProtocols = -1; + +static int ett_negRsp_flags = -1; +static int ett_selectedProtocol = -1; + static int ett_rdp_SendData = -1; static int ett_rdp_ClientData = -1; @@ -88,6 +96,32 @@ static int ett_rdp_StandardDate = -1; static int ett_rdp_DaylightDate = -1; static int ett_rdp_clientTimeZone = -1; +static expert_field ei_rdp_neg_len_invalid = EI_INIT; +static expert_field ei_rdp_not_correlation_info = EI_INIT; + +static int hf_rdp_rt_cookie = -1; +static int hf_rdp_neg_type = -1; +static int hf_rdp_negReq_flags = -1; +static int hf_rdp_negReq_flag_restricted_admin_mode_req = -1; +static int hf_rdp_negReq_flag_correlation_info_present = -1; +static int hf_rdp_neg_length = -1; +static int hf_rdp_requestedProtocols = -1; +static int hf_rdp_requestedProtocols_flag_ssl = -1; +static int hf_rdp_requestedProtocols_flag_hybrid = -1; +static int hf_rdp_requestedProtocols_flag_hybrid_ex = -1; +static int hf_rdp_correlationInfo_flags; +static int hf_rdp_correlationId = -1; +static int hf_rdp_correlationInfo_reserved = -1; +static int hf_rdp_negRsp_flags = -1; +static int hf_rdp_negRsp_flag_extended_client_data_supported = -1; +static int hf_rdp_negRsp_flag_dynvc_gfx_protocol_supported = -1; +static int hf_rdp_negRsp_flag_restricted_admin_mode_supported = -1; +static int hf_rdp_selectedProtocol = -1; +static int hf_rdp_selectedProtocol_flag_ssl = -1; +static int hf_rdp_selectedProtocol_flag_hybrid = -1; +static int hf_rdp_selectedProtocol_flag_hybrid_ex = -1; +static int hf_rdp_negFailure_failureCode = -1; + static int hf_rdp_ClientData = -1; static int hf_rdp_SendData = -1; static int hf_rdp_clientCoreData = -1; @@ -334,6 +368,32 @@ static int hf_rdp_DaylightBias = -1; static int hf_rdp_unused = -1; +#define TYPE_RDP_NEG_REQ 0x01 +#define TYPE_RDP_NEG_RSP 0x02 +#define TYPE_RDP_NEG_FAILURE 0x03 +#define TYPE_RDP_CORRELATION_INFO 0x06 + +static const value_string neg_type_vals[] = { + { TYPE_RDP_NEG_REQ, "RDP Negotiation Request" }, + { TYPE_RDP_NEG_RSP, "RDP Negotiation Response" }, + { TYPE_RDP_NEG_FAILURE, "RDP Negotiation Failure" }, + { TYPE_RDP_CORRELATION_INFO, "RDP Correlation Info" }, + { 0, NULL } +}; + +#define RESTRICTED_ADMIN_MODE_REQUIRED 0x01 +#define CORRELATION_INFO_PRESENT 0x08 + +static const value_string failure_code_vals[] = { + { 0x00000001, "TLS required by server" }, + { 0x00000002, "TLS not allowed by server" }, + { 0x00000003, "TLS certificate not on server" }, + { 0x00000004, "Inconsistent flags" }, + { 0x00000005, "Server requires Enhanced RDP Security with CredSSP" }, + { 0x00000006, "Server requires Enhanced RDP Security with TLS and certificate-based client authentication" }, + { 0, NULL } +}; + #define CS_CORE 0xC001 #define CS_SECURITY 0xC002 #define CS_NET 0xC003 @@ -1991,12 +2051,314 @@ dissect_rdp_ServerData(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void return tvb_captured_length(tvb); } +/* Dissect extra data in a CR PDU */ +static int +dissect_rdpCorrelationInfo(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { + guint32 type; + guint32 length; + proto_item *type_item, *length_item; + + type_item = proto_tree_add_item_ret_uint(tree, hf_rdp_neg_type, tvb, offset, 1, ENC_NA, &type); + offset += 1; + if (type != TYPE_RDP_CORRELATION_INFO) { + expert_add_info(pinfo, type_item, &ei_rdp_not_correlation_info); + return offset; + } + proto_tree_add_item(tree, hf_rdp_correlationInfo_flags, tvb, offset, 1, ENC_NA); + offset += 1; + length_item = proto_tree_add_item_ret_uint(tree, hf_rdp_neg_length, tvb, offset, 1, ENC_LITTLE_ENDIAN, &length); + offset += 2; + if (length != 36) { + expert_add_info_format(pinfo, length_item, &ei_rdp_neg_len_invalid, "RDP Correlation Info length is %u, not 36", length); + return offset; + } + proto_tree_add_item(tree, hf_rdp_correlationId, tvb, offset, 16, ENC_NA); + offset += 16; + proto_tree_add_item(tree, hf_rdp_correlationInfo_reserved, tvb, offset, 16, ENC_NA); + offset += 16; + return offset; +} + +static int +dissect_rdpNegReq(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { + guint64 flags; + guint32 length; + proto_item *length_item; + static const int *flag_bits[] = { + &hf_rdp_negReq_flag_restricted_admin_mode_req, + &hf_rdp_negReq_flag_correlation_info_present, + NULL + }; + static const int *requestedProtocols_bits[] = { + &hf_rdp_requestedProtocols_flag_ssl, + &hf_rdp_requestedProtocols_flag_hybrid, + &hf_rdp_requestedProtocols_flag_hybrid_ex, + NULL + }; + + proto_tree_add_item(tree, hf_rdp_neg_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_bitmask_ret_uint64(tree, tvb, offset, hf_rdp_negReq_flags, + ett_negReq_flags, flag_bits, + ENC_LITTLE_ENDIAN, &flags); + offset += 1; + length_item = proto_tree_add_item_ret_uint(tree, hf_rdp_neg_length, tvb, offset, 1, ENC_LITTLE_ENDIAN, &length); + offset += 2; + if (length != 8) { + expert_add_info_format(pinfo, length_item, &ei_rdp_neg_len_invalid, "RDP Negotiate Request length is %u, not 8", length); + return offset; + } + proto_tree_add_bitmask(tree, tvb, offset, hf_rdp_requestedProtocols, + ett_requestedProtocols, requestedProtocols_bits, + ENC_LITTLE_ENDIAN); + offset += 4; + if (flags & CORRELATION_INFO_PRESENT) + offset = dissect_rdpCorrelationInfo(tvb, offset, pinfo, tree); + return offset; +} + +static int +dissect_rdp_cr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_) +{ + int offset = 0; + gboolean have_cookie = FALSE; + gboolean have_rdpNegRequest = FALSE; + proto_item *item; + proto_tree *tree; + gint linelen, next_offset; + + /* + * routingToken or cookie? Both begin with "Cookie: ". + */ + if (tvb_memeql(tvb, offset, "Cookie: ", 8) == 0) { + /* Looks like a routing token or cookie */ + have_cookie = TRUE; + } else if (tvb_bytes_exist(tvb, offset, 4) && + tvb_get_guint8(tvb, offset) == TYPE_RDP_NEG_REQ && + tvb_get_letohs(tvb, offset + 2) == 8) { + /* Looks like a Negotiate Request (TYPE_RDP_NEG_REQ, length 8) */ + have_rdpNegRequest = TRUE; + } + if (!have_cookie && !have_rdpNegRequest) { + /* Doesn't look like our data */ + return 0; + } + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "RDP"); + col_clear(pinfo->cinfo, COL_INFO); + + item = proto_tree_add_item(parent_tree, proto_rdp, tvb, 0, -1, ENC_NA); + tree = proto_item_add_subtree(item, ett_rdp); + + if (have_cookie) { + /* XXX - distinguish between routing token and cookie? */ + linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, TRUE); + proto_tree_add_item(tree, hf_rdp_rt_cookie, tvb, offset, linelen, ENC_ASCII|ENC_NA); + offset = (linelen == -1) ? tvb_captured_length(tvb) : next_offset; + } + /* + * rdpNegRequest? + */ + if (tvb_reported_length_remaining(tvb, offset) > 0) + offset = dissect_rdpNegReq(tvb, offset, pinfo, tree); + return offset; /* returns 0 if nothing was dissected, which is what we want */ +} + +/* Dissect extra data in a CC PDU */ +static int +dissect_rdpNegRsp(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { + guint32 length; + proto_item *length_item; + static const int *flag_bits[] = { + &hf_rdp_negRsp_flag_extended_client_data_supported, + &hf_rdp_negRsp_flag_dynvc_gfx_protocol_supported, + &hf_rdp_negRsp_flag_restricted_admin_mode_supported, + NULL + }; + static const int *selectedProtocol_bits[] = { + &hf_rdp_selectedProtocol_flag_ssl, + &hf_rdp_selectedProtocol_flag_hybrid, + &hf_rdp_selectedProtocol_flag_hybrid_ex, + NULL + }; + + proto_tree_add_item(tree, hf_rdp_neg_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_bitmask(tree, tvb, offset, hf_rdp_negRsp_flags, + ett_negRsp_flags, flag_bits, + ENC_LITTLE_ENDIAN); + offset += 1; + length_item = proto_tree_add_item_ret_uint(tree, hf_rdp_neg_length, tvb, offset, 1, ENC_LITTLE_ENDIAN, &length); + offset += 2; + if (length != 8) { + expert_add_info_format(pinfo, length_item, &ei_rdp_neg_len_invalid, "RDP Negotiate Response length is %u, not 8", length); + return offset; + } + proto_tree_add_bitmask(tree, tvb, offset, hf_rdp_selectedProtocol, + ett_selectedProtocol, selectedProtocol_bits, + ENC_LITTLE_ENDIAN); + offset += 4; + return offset; +} + +static int +dissect_rdpNegFailure(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { + guint32 length; + proto_item *length_item; + + proto_tree_add_item(tree, hf_rdp_neg_type, tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(tree, hf_rdp_negReq_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + length_item = proto_tree_add_item_ret_uint(tree, hf_rdp_neg_length, tvb, offset, 1, ENC_LITTLE_ENDIAN, &length); + offset += 2; + if (length != 8) { + expert_add_info_format(pinfo, length_item, &ei_rdp_neg_len_invalid, "RDP Negotiate Failure length is %u, not 8", length); + return offset; + } + proto_tree_add_item(tree, hf_rdp_negFailure_failureCode, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + return offset; +} + +static int +dissect_rdp_cc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_) +{ + int offset = 0; + guint8 type; + guint16 length; + gboolean ours = FALSE; + proto_item *item; + proto_tree *tree; + + if (tvb_bytes_exist(tvb, offset, 4)) { + type = tvb_get_guint8(tvb, offset); + length = tvb_get_letohs(tvb, offset + 2); + if ((type == TYPE_RDP_NEG_RSP || type == TYPE_RDP_NEG_FAILURE) && + length == 8) { + /* Looks like a Negotiate Response (TYPE_RDP_NEG_RSP, length 8) + or a Negotaiate Failure (TYPE_RDP_NEG_FAILURE, length 8) */ + ours = TRUE; + } + } + if (!ours) { + /* Doesn't look like our data */ + return 0; + } + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "RDP"); + col_clear(pinfo->cinfo, COL_INFO); + + item = proto_tree_add_item(parent_tree, proto_rdp, tvb, 0, -1, ENC_NA); + tree = proto_item_add_subtree(item, ett_rdp); + + switch (type) { + + case TYPE_RDP_NEG_RSP: + offset = dissect_rdpNegRsp(tvb, offset, pinfo, tree); + break; + + case TYPE_RDP_NEG_FAILURE: + offset = dissect_rdpNegFailure(tvb, offset, pinfo, tree); + break; + } + return offset; +} + /*--- proto_register_rdp -------------------------------------------*/ void proto_register_rdp(void) { /* List of fields */ static hf_register_info hf[] = { + { &hf_rdp_rt_cookie, + { "Routing Token/Cookie", "rdp.rt_cookie", + FT_STRING, BASE_NONE, NULL, 0, + NULL, HFILL }}, + { &hf_rdp_neg_type, + { "Type", "rdp.neg_type", + FT_UINT8, BASE_HEX, VALS(neg_type_vals), 0, + NULL, HFILL }}, + { &hf_rdp_negReq_flags, + { "Flags", "rdp.negReq.flags", + FT_UINT8, BASE_HEX, NULL, 0, + NULL, HFILL }}, + { &hf_rdp_negReq_flag_restricted_admin_mode_req, + { "Restricted admin mode required", "rdp.negReq.flags.restricted_admin_mode_req", + FT_BOOLEAN, 8, NULL, RESTRICTED_ADMIN_MODE_REQUIRED, + NULL, HFILL }}, + { &hf_rdp_negReq_flag_correlation_info_present, + { "Correlation info present", "rdp.negReq.flags.correlation_info_present", + FT_BOOLEAN, 8, NULL, CORRELATION_INFO_PRESENT, + NULL, HFILL }}, + { &hf_rdp_neg_length, + { "Length", "rdp.neg_length", + FT_UINT16, BASE_DEC, NULL, 0, + NULL, HFILL }}, + { &hf_rdp_requestedProtocols, + { "requestedProtocols", "rdp.negReq.requestedProtocols", + FT_UINT32, BASE_HEX, NULL, 0, + NULL, HFILL }}, + { &hf_rdp_requestedProtocols_flag_ssl, + { "TLS security supported", "rdp.negReq.requestedProtocols.ssl", + FT_BOOLEAN, 32, NULL, 0x00000001, + NULL, HFILL }}, + { &hf_rdp_requestedProtocols_flag_hybrid, + { "CredSSP supported", "rdp.negReq.requestedProtocols.hybrid", + FT_BOOLEAN, 32, NULL, 0x00000002, + NULL, HFILL }}, + { &hf_rdp_requestedProtocols_flag_hybrid_ex, + { "Early User Authorization Result PDU supported", "rdp.negReq.requestedProtocols.hybrid_ex", + FT_BOOLEAN, 32, NULL, 0x00000008, + NULL, HFILL }}, + { &hf_rdp_correlationInfo_flags, + { "Flags", "rdp.correlationInfo.flags", + FT_UINT8, BASE_HEX, NULL, 0, + NULL, HFILL }}, + { &hf_rdp_correlationId, + { "correlationId", "rdp.correlationInfo.correlationId", + FT_BYTES, BASE_NONE, NULL, 0, + NULL, HFILL }}, + { &hf_rdp_correlationInfo_reserved, + { "Reserved", "rdp.correlationInfo.reserved", + FT_BYTES, BASE_NONE, NULL, 0, + NULL, HFILL }}, + { &hf_rdp_negRsp_flags, + { "Flags", "rdp.negRsp.flags", + FT_UINT8, BASE_HEX, NULL, 0, + NULL, HFILL }}, + { &hf_rdp_negRsp_flag_extended_client_data_supported, + { "Extended Client Data Blocks supported", "rdp.negRsp.flags.extended_client_data_supported", + FT_BOOLEAN, 8, NULL, 0x01, + NULL, HFILL }}, + { &hf_rdp_negRsp_flag_dynvc_gfx_protocol_supported, + { "Graphics Pipeline Extension Protocol supported", "rdp.negRsp.flags.dynvc_gfx_protocol_supported", + FT_BOOLEAN, 8, NULL, 0x02, + NULL, HFILL }}, + { &hf_rdp_negRsp_flag_restricted_admin_mode_supported, + { "Restricted admin mode supported", "rdp.negRsp.flags.restricted_admin_mode_supported", + FT_BOOLEAN, 8, NULL, 0x08, + NULL, HFILL }}, + { &hf_rdp_selectedProtocol, + { "selectedProtocol", "rdp.negReq.selectedProtocol", + FT_UINT32, BASE_HEX, NULL, 0, + NULL, HFILL }}, + { &hf_rdp_selectedProtocol_flag_ssl, + { "TLS security selected", "rdp.negReq.selectedProtocol.ssl", + FT_BOOLEAN, 32, NULL, 0x00000001, + NULL, HFILL }}, + { &hf_rdp_selectedProtocol_flag_hybrid, + { "CredSSP selected", "rdp.negReq.selectedProtocol.hybrid", + FT_BOOLEAN, 32, NULL, 0x00000002, + NULL, HFILL }}, + { &hf_rdp_selectedProtocol_flag_hybrid_ex, + { "Early User Authorization Result PDU selected", "rdp.negReq.selectedProtocol.hybrid_ex", + FT_BOOLEAN, 32, NULL, 0x00000008, + NULL, HFILL }}, + { &hf_rdp_negFailure_failureCode, + { "failureCode", "rdp.negFailure.failureCode", + FT_UINT32, BASE_HEX, VALS(failure_code_vals), 0, + NULL, HFILL }}, { &hf_rdp_ClientData, { "ClientData", "rdp.clientData", FT_NONE, BASE_NONE, NULL, 0, @@ -2876,6 +3238,10 @@ proto_register_rdp(void) { /* List of subtrees */ static gint *ett[] = { &ett_rdp, + &ett_negReq_flags, + &ett_requestedProtocols, + &ett_negRsp_flags, + &ett_selectedProtocol, &ett_rdp_ClientData, &ett_rdp_ServerData, &ett_rdp_SendData, @@ -2913,13 +3279,20 @@ proto_register_rdp(void) { &ett_rdp_DaylightDate, &ett_rdp_clientTimeZone, }; + static ei_register_info ei[] = { + { &ei_rdp_neg_len_invalid, { "rdp.neg_len.invalid", PI_PROTOCOL, PI_ERROR, "Invalid length", EXPFILL }}, + { &ei_rdp_not_correlation_info, { "rdp.not_correlation_info", PI_PROTOCOL, PI_ERROR, "What follows RDP Negotiation Request is not an RDP Correlation Info", EXPFILL }}, + }; module_t *rdp_module; + expert_module_t* expert_rdp; /* Register protocol */ proto_rdp = proto_register_protocol(PNAME, PSNAME, PFNAME); /* Register fields and subtrees */ proto_register_field_array(proto_rdp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); + expert_rdp = expert_register_protocol(proto_rdp); + expert_register_field_array(expert_rdp, ei, array_length(ei)); /* register_dissector("rdp", dissect_rdp, proto_rdp); */ @@ -2941,6 +3314,9 @@ proto_reg_handoff_rdp(void) /* remember the tpkt handler for change in preferences */ tpkt_handle = find_dissector("tpkt"); + heur_dissector_add("cotp_cr", dissect_rdp_cr, "RDP", "rdp_cr", proto_rdp, HEURISTIC_ENABLE); + heur_dissector_add("cotp_cc", dissect_rdp_cc, "RDP", "rdp_cc", proto_rdp, HEURISTIC_ENABLE); + prefs_register_rdp(); register_t124_ns_dissector("Duca", dissect_rdp_ClientData, proto_rdp); diff --git a/epan/proto.c b/epan/proto.c index 0100c06cba..7c7c4b9891 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -1367,12 +1367,6 @@ get_uint_value(proto_tree *tree, tvbuff_t *tvb, gint offset, gint length, const return value; } -/* - * NOTE: to support code written when proto_tree_add_item() took a - * gboolean as its last argument, with FALSE meaning "big-endian" - * and TRUE meaning "little-endian", we treat any non-zero value of - * "encoding" as meaning "little-endian". - */ static inline guint64 get_uint64_value(proto_tree *tree, tvbuff_t *tvb, gint offset, guint length, const guint encoding) { @@ -1435,12 +1429,6 @@ get_uint64_value(proto_tree *tree, tvbuff_t *tvb, gint offset, guint length, con return value; } -/* - * NOTE: to support code written when proto_tree_add_item() took a - * gboolean as its last argument, with FALSE meaning "big-endian" - * and TRUE meaning "little-endian", we treat any non-zero value of - * "encoding" as meaning "little-endian". - */ static gint32 get_int_value(proto_tree *tree, tvbuff_t *tvb, gint offset, gint length, const guint encoding) { @@ -8716,71 +8704,25 @@ proto_construct_match_selected_string(field_info *finfo, epan_dissect_t *edt) return filter; } -/* This function is common code for both proto_tree_add_bitmask() and - * proto_tree_add_bitmask_text() functions. +/* This function is common code for all proto_tree_add_bitmask... functions. */ -/* NOTE: to support code written when proto_tree_add_bitmask() and - * proto_tree_add_bitmask_text took a - * gboolean as its last argument, with FALSE meaning "big-endian" - * and TRUE meaning "little-endian", we treat any non-zero value of - * "encoding" as meaning "little-endian". - */ static gboolean proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, const int offset, const int len, const gint ett, const int **fields, - const guint encoding, const int flags, - gboolean first, gboolean use_parent_tree, gboolean use_value, + const int flags, gboolean first, + gboolean use_parent_tree, proto_tree* tree, guint64 value) { + guint bitshift; guint64 available_bits = 0; guint64 tmpval; header_field_info *hf; - switch (len) { - case 1: - if (use_value == FALSE) - value = tvb_get_guint8(tvb, offset); - available_bits = 0xFF; - break; - case 2: - if (use_value == FALSE) - value = encoding ? tvb_get_letohs(tvb, offset) : tvb_get_ntohs(tvb, offset); - available_bits = 0xFFFF; - break; - case 3: - if (use_value == FALSE) - value = encoding ? tvb_get_letoh24(tvb, offset) : tvb_get_ntoh24(tvb, offset); - available_bits = 0xFFFFFF; - break; - case 4: - if (use_value == FALSE) - value = encoding ? tvb_get_letohl(tvb, offset) : tvb_get_ntohl(tvb, offset); - available_bits = 0xFFFFFFFF; - break; - case 5: - if (use_value == FALSE) - value = encoding ? tvb_get_letoh40(tvb, offset) : tvb_get_ntoh40(tvb, offset); - available_bits = G_GUINT64_CONSTANT(0xFFFFFFFFFF); - break; - case 6: - if (use_value == FALSE) - value = encoding ? tvb_get_letoh48(tvb, offset) : tvb_get_ntoh48(tvb, offset); - available_bits = G_GUINT64_CONSTANT(0xFFFFFFFFFFFF); - break; - case 7: - if (use_value == FALSE) - value = encoding ? tvb_get_letoh56(tvb, offset) : tvb_get_ntoh56(tvb, offset); - available_bits = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFF); - break; - case 8: - if (use_value == FALSE) - value = encoding ? tvb_get_letoh64(tvb, offset) : tvb_get_ntoh64(tvb, offset); - available_bits = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF); - break; - default: - g_assert_not_reached(); - } + if (len <= 0 || len > 8) + g_assert_not_reached(); + bitshift = (8 - (guint)len)*8; + available_bits = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF) >> bitshift; if (use_parent_tree == FALSE) tree = proto_item_add_subtree(item, ett); @@ -8797,43 +8739,36 @@ proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, const int offset, continue; } - if (use_value) - { - switch (hf->type) { - case FT_INT8: - case FT_UINT8: - case FT_INT16: - case FT_UINT16: - case FT_INT24: - case FT_UINT24: - case FT_INT32: - case FT_UINT32: - proto_tree_add_uint(tree, **fields, tvb, offset, len, (guint32)value); - break; + switch (hf->type) { + case FT_INT8: + case FT_UINT8: + case FT_INT16: + case FT_UINT16: + case FT_INT24: + case FT_UINT24: + case FT_INT32: + case FT_UINT32: + proto_tree_add_uint(tree, **fields, tvb, offset, len, (guint32)value); + break; - case FT_INT40: - case FT_UINT40: - case FT_INT48: - case FT_UINT48: - case FT_INT56: - case FT_UINT56: - case FT_INT64: - case FT_UINT64: - proto_tree_add_uint64(tree, **fields, tvb, offset, len, value); - break; + case FT_INT40: + case FT_UINT40: + case FT_INT48: + case FT_UINT48: + case FT_INT56: + case FT_UINT56: + case FT_INT64: + case FT_UINT64: + proto_tree_add_uint64(tree, **fields, tvb, offset, len, value); + break; - case FT_BOOLEAN: - proto_tree_add_boolean64(tree, **fields, tvb, offset, len, value); - break; + case FT_BOOLEAN: + proto_tree_add_boolean64(tree, **fields, tvb, offset, len, value); + break; - default: - DISSECTOR_ASSERT_NOT_REACHED(); - break; - } - } - else - { - proto_tree_add_item(tree, **fields, tvb, offset, len, encoding); + default: + DISSECTOR_ASSERT_NOT_REACHED(); + break; } if (flags & BMT_NO_APPEND) { fields++; @@ -8921,11 +8856,38 @@ proto_item_add_bitmask_tree(proto_item *item, tvbuff_t *tvb, const int offset, } /* This function will dissect a sequence of bytes that describe a + * bitmask and supply the value of that sequence through a pointer. + * hf_hdr is a 8/16/24/32/40/48/56/64 bit integer that describes the bitmask + * to be dissected. + * This field will form an expansion under which the individual fields of the + * bitmask is dissected and displayed. + * This field must be of the type FT_[U]INT{8|16|24|32|40|48|56|64}. + * + * fields is an array of pointers to int that lists all the fields of the + * bitmask. These fields can be either of the type FT_BOOLEAN for flags + * or another integer of the same type/size as hf_hdr with a mask specified. + * This array is terminated by a NULL entry. + * + * FT_BOOLEAN bits that are set to 1 will have the name added to the expansion. + * FT_integer fields that have a value_string attached will have the + * matched string displayed on the expansion line. + */ +proto_item * +proto_tree_add_bitmask_ret_uint64(proto_tree *parent_tree, tvbuff_t *tvb, + const guint offset, const int hf_hdr, + const gint ett, const int **fields, + const guint encoding, guint64 *retval) +{ + return proto_tree_add_bitmask_with_flags_ret_uint64(parent_tree, tvb, offset, hf_hdr, ett, fields, encoding, BMT_NO_INT|BMT_NO_TFS, retval); +} + +/* This function will dissect a sequence of bytes that describe a * bitmask. - * hf_hdr is a 8/16/24/32 bit integer that describes the bitmask to be dissected. + * hf_hdr is a 8/16/24/32/40/48/56/64 bit integer that describes the bitmask + * to be dissected. * This field will form an expansion under which the individual fields of the * bitmask is dissected and displayed. - * This field must be of the type FT_[U]INT{8|16|24|32}. + * This field must be of the type FT_[U]INT{8|16|24|32|40|48|56|64}. * * fields is an array of pointers to int that lists all the fields of the * bitmask. These fields can be either of the type FT_BOOLEAN for flags @@ -8945,7 +8907,35 @@ proto_tree_add_bitmask(proto_tree *parent_tree, tvbuff_t *tvb, return proto_tree_add_bitmask_with_flags(parent_tree, tvb, offset, hf_hdr, ett, fields, encoding, BMT_NO_INT|BMT_NO_TFS); } -/* The same as proto_tree_add_bitmask(), but uses user-supplied flags to determine +/* The same as proto_tree_add_bitmask_ret_uint64(), but uses user-supplied flags to determine + * what data is appended to the header. + */ +proto_item * +proto_tree_add_bitmask_with_flags_ret_uint64(proto_tree *parent_tree, tvbuff_t *tvb, const guint offset, + const int hf_hdr, const gint ett, const int **fields, const guint encoding, const int flags, + guint64 *retval) +{ + proto_item *item = NULL; + header_field_info *hf; + int len; + guint64 value; + + PROTO_REGISTRAR_GET_NTH(hf_hdr,hf); + DISSECTOR_ASSERT_FIELD_TYPE_IS_INTEGRAL(hf); + len = ftype_length(hf->type); + value = get_uint64_value(parent_tree, tvb, offset, len, encoding); + + if (parent_tree) { + item = proto_tree_add_item(parent_tree, hf_hdr, tvb, offset, len, encoding); + proto_item_add_bitmask_tree(item, tvb, offset, len, ett, fields, + flags, FALSE, FALSE, NULL, value); + } + + *retval = value; + return item; +} + +/* The same as proto_tree_add_bitmask_ret_uint64(), but uses user-supplied flags to determine * what data is appended to the header. */ proto_item * @@ -8955,15 +8945,17 @@ proto_tree_add_bitmask_with_flags(proto_tree *parent_tree, tvbuff_t *tvb, const proto_item *item = NULL; header_field_info *hf; int len; + guint64 value; PROTO_REGISTRAR_GET_NTH(hf_hdr,hf); DISSECTOR_ASSERT_FIELD_TYPE_IS_INTEGRAL(hf); - len = ftype_length(hf->type); if (parent_tree) { + len = ftype_length(hf->type); item = proto_tree_add_item(parent_tree, hf_hdr, tvb, offset, len, encoding); - proto_item_add_bitmask_tree(item, tvb, offset, len, ett, fields, encoding, - flags, FALSE, FALSE, FALSE, NULL, 0); + value = get_uint64_value(parent_tree, tvb, offset, len, encoding); + proto_item_add_bitmask_tree(item, tvb, offset, len, ett, fields, + flags, FALSE, FALSE, NULL, value); } return item; @@ -8999,8 +8991,7 @@ proto_tree_add_bitmask_value_with_flags(proto_tree *parent_tree, tvbuff_t *tvb, item = proto_tree_add_uint64(parent_tree, hf_hdr, tvb, offset, len, value); proto_item_add_bitmask_tree(item, tvb, offset, len, ett, fields, - 0, flags, FALSE, FALSE, TRUE, NULL, value); - + flags, FALSE, FALSE, NULL, value); } return item; @@ -9011,9 +9002,13 @@ void proto_tree_add_bitmask_list(proto_tree *tree, tvbuff_t *tvb, const guint offset, const int len, const int **fields, const guint encoding) { - if (tree) + guint64 value; + + if (tree) { + value = get_uint64_value(tree, tvb, offset, len, encoding); proto_item_add_bitmask_tree(NULL, tvb, offset, len, -1, fields, - encoding, BMT_NO_APPEND, FALSE, TRUE, FALSE, tree, 0); + BMT_NO_APPEND, FALSE, TRUE, tree, value); + } } @@ -9039,6 +9034,7 @@ proto_tree_add_bitmask_len(proto_tree *parent_tree, tvbuff_t *tvb, guint decodable_len; guint decodable_offset; guint32 decodable_value; + guint64 value; PROTO_REGISTRAR_GET_NTH(hf_hdr, hf); DISSECTOR_ASSERT_FIELD_TYPE_IS_INTEGRAL(hf); @@ -9070,8 +9066,9 @@ proto_tree_add_bitmask_len(proto_tree *parent_tree, tvbuff_t *tvb, } if (item) { + value = get_uint64_value(parent_tree, tvb, decodable_offset, decodable_len, encoding); proto_item_add_bitmask_tree(item, tvb, decodable_offset, decodable_len, - ett, fields, encoding, BMT_NO_INT|BMT_NO_TFS, FALSE, FALSE, FALSE, NULL, 0); + ett, fields, BMT_NO_INT|BMT_NO_TFS, FALSE, FALSE, NULL, value); } return item; @@ -9086,11 +9083,13 @@ proto_tree_add_bitmask_text(proto_tree *parent_tree, tvbuff_t *tvb, const guint encoding, const int flags) { proto_item *item = NULL; + guint64 value; if (parent_tree) { item = proto_tree_add_text_internal(parent_tree, tvb, offset, len, "%s", name ? name : ""); - if (proto_item_add_bitmask_tree(item, tvb, offset, len, ett, fields, encoding, - flags, TRUE, FALSE, FALSE, NULL, 0) && fallback) { + value = get_uint64_value(parent_tree, tvb, offset, len, encoding); + if (proto_item_add_bitmask_tree(item, tvb, offset, len, ett, fields, + flags, TRUE, FALSE, NULL, value) && fallback) { /* Still at first item - append 'fallback' text if any */ proto_item_append_text(item, "%s", fallback); } diff --git a/epan/proto.h b/epan/proto.h index b31cf23a8f..93bcc9ccee 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -1048,8 +1048,8 @@ Integers of 8, 16, 24 and 32 bits can be retrieved with these functions. @param start start of data in tvb (cannot be negative) @param length length of data in tvb (for strings can be -1 for remaining) @param encoding data encoding (e.g, ENC_LITTLE_ENDIAN, ENC_BIG_ENDIAN, ENC_ASCII|ENC_STRING, etc.) -@param[out] retval points to a gint/guint 8/16/32/64 or gfloat/gdouble which will be set -@return the newly created item, and value is set to the decoded value +@param[out] retval points to a gint32 or guint32 which will be set +@return the newly created item, and *retval is set to the decoded value */ WS_DLL_PUBLIC proto_item * proto_tree_add_item_ret_int(proto_tree *tree, int hfindex, tvbuff_t *tvb, @@ -2349,10 +2349,11 @@ proto_find_undecoded_data(proto_tree *tree, guint length); @param tree the tree to append this item to @param tvb the tv buffer of the current data @param offset start of data in tvb - @param hf_hdr an 8/16/24/32 bit integer that describes the bitmask to be dissected. - This field will form an expansion under which the individual fields of the - bitmask is dissected and displayed. - This field must be of the type FT_[U]INT{8|16|24|32}. + @param hf_hdr an 8/16/24/32/40/48/56/64 bit integer that describes the + bitmask to be dissected. + This field will form an expansion under which the individual fields + of the bitmask are dissected and displayed. + This field must be of the type FT_[U]INT{8|16|24|32|40|48|56|64}. @param ett subtree index @param fields an array of pointers to int that lists all the fields of the bitmask. These fields can be either of the type FT_BOOLEAN for flags @@ -2368,16 +2369,45 @@ proto_tree_add_bitmask(proto_tree *tree, tvbuff_t *tvb, const guint offset, const int hf_hdr, const gint ett, const int **fields, const guint encoding); /** This function will dissect a sequence of bytes that describe a bitmask. -* This has "filterable" bitmask header functionality of proto_tree_add_bitmask -* with the ability to control what data is appended to the header like -* proto_tree_add_bitmask_text + The value of the integer containing the bitmask is returned through + a pointer. @param tree the tree to append this item to @param tvb the tv buffer of the current data @param offset start of data in tvb - @param hf_hdr an 8/16/24/32 bit integer that describes the bitmask to be dissected. - This field will form an expansion under which the individual fields of the - bitmask is dissected and displayed. - This field must be of the type FT_[U]INT{8|16|24|32}. + @param hf_hdr an 8/16/24/32/40/48/56/64 bit integer that describes the + bitmask to be dissected. + This field will form an expansion under which the individual fields + of the bitmask are dissected and displayed. + This field must be of the type FT_[U]INT{8|16|24|32|40|48|56|64}. + @param ett subtree index + @param fields an array of pointers to int that lists all the fields of the + bitmask. These fields can be either of the type FT_BOOLEAN for flags + or another integer of the same type/size as hf_hdr with a mask specified. + This array is terminated by a NULL entry. + FT_BOOLEAN bits that are set to 1 will have the name added to the expansion. + FT_integer fields that have a value_string attached will have the + matched string displayed on the expansion line. + @param encoding big or little endian byte representation (ENC_BIG_ENDIAN/ENC_LITTLE_ENDIAN/ENC_HOST_ENDIAN) + @param[out] retval points to a guint64 which will be set + @return the newly created item, and *retval is set to the decoded value + */ +WS_DLL_PUBLIC proto_item * +proto_tree_add_bitmask_ret_uint64(proto_tree *tree, tvbuff_t *tvb, const guint offset, + const int hf_hdr, const gint ett, const int **fields, + const guint encoding, guint64 *retval); + +/** This function will dissect a sequence of bytes that describe a bitmask. + This has "filterable" bitmask header functionality of proto_tree_add_bitmask + with the ability to control what data is appended to the header like + proto_tree_add_bitmask_text + @param tree the tree to append this item to + @param tvb the tv buffer of the current data + @param offset start of data in tvb + @param hf_hdr an 8/16/24/32/40/48/56/64 bit integer that describes the + bitmask to be dissected. + This field will form an expansion under which the individual fields + of the bitmask are dissected and displayed. + This field must be of the type FT_[U]INT{8|16|24|32|40|48|56|64}. @param ett subtree index @param fields an array of pointers to int that lists all the fields of the bitmask. These fields can be either of the type FT_BOOLEAN for flags @@ -2393,6 +2423,38 @@ WS_DLL_PUBLIC proto_item * proto_tree_add_bitmask_with_flags(proto_tree *tree, tvbuff_t *tvb, const guint offset, const int hf_hdr, const gint ett, const int **fields, const guint encoding, const int flags); +/** This function will dissect a sequence of bytes that describe a bitmask. + This has "filterable" bitmask header functionality of proto_tree_add_bitmask + with the ability to control what data is appended to the header like + proto_tree_add_bitmask_text + The value of the integer containing the bitmask is returned through + a pointer. + @param tree the tree to append this item to + @param tvb the tv buffer of the current data + @param offset start of data in tvb + @param hf_hdr an 8/16/24/32/40/48/56/64 bit integer that describes the + bitmask to be dissected. + This field will form an expansion under which the individual fields + of the bitmask are dissected and displayed. + This field must be of the type FT_[U]INT{8|16|24|32|40|48|56|64}. + @param ett subtree index + @param fields an array of pointers to int that lists all the fields of the + bitmask. These fields can be either of the type FT_BOOLEAN for flags + or another integer of the same type/size as hf_hdr with a mask specified. + This array is terminated by a NULL entry. + FT_BOOLEAN bits that are set to 1 will have the name added to the expansion. + FT_integer fields that have a value_string attached will have the + matched string displayed on the expansion line. + @param encoding big or little endian byte representation (ENC_BIG_ENDIAN/ENC_LITTLE_ENDIAN/ENC_HOST_ENDIAN) + @param flags bitmask field using BMT_NO_* flags to determine behavior + @param[out] retval points to a guint64 which will be set + @return the newly created item, and *retval is set to the decoded value + */ +WS_DLL_PUBLIC proto_item * +proto_tree_add_bitmask_with_flags_ret_uint64(proto_tree *tree, tvbuff_t *tvb, const guint offset, + const int hf_hdr, const gint ett, const int **fields, + const guint encoding, const int flags, guint64 *retval); + /** This function will dissect a value that describe a bitmask. Similar to proto_tree_add_bitmask(), but with a passed in value (presumably because it can't be retrieved directly from tvb) @param tree the tree to append this item to |