X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=packet-dcerpc.c;h=f48f45fc09169e085344fe176424e50c66603ff2;hb=602a62e38a8fb00544e637cc3d3f9c43b2f9b7bd;hp=6e7d21d3aa91eadcb5a29f712a7d6fdfc6939b9e;hpb=392a7dfc04475dd440efa70ea4b786a96f282c19;p=metze%2Fwireshark%2Fwip.git diff --git a/packet-dcerpc.c b/packet-dcerpc.c index 6e7d21d3aa..f48f45fc09 100644 --- a/packet-dcerpc.c +++ b/packet-dcerpc.c @@ -2,22 +2,22 @@ * Routines for DCERPC packet disassembly * Copyright 2001, Todd Sabin * - * $Id: packet-dcerpc.c,v 1.53 2002/06/04 07:03:44 guy Exp $ + * $Id: packet-dcerpc.c,v 1.122 2003/05/15 01:59:23 tpot Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. @@ -27,10 +27,6 @@ #include "config.h" #endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif - #include #include @@ -40,29 +36,36 @@ #include #include "prefs.h" #include "reassemble.h" +#include "tap.h" +#include "packet-frame.h" +#include "packet-ntlmssp.h" +#include "packet-dcerpc-nt.h" +#include "packet-dcerpc-netlogon.h" + +static int dcerpc_tap = -1; static const value_string pckt_vals[] = { - { 0, "Request"}, - { 1, "Ping"}, - { 2, "Response"}, - { 3, "Fault"}, - { 4, "Working"}, - { 5, "Nocall"}, - { 6, "Reject"}, - { 7, "Ack"}, - { 8, "Cl_cancel"}, - { 9, "Fack"}, - { 10, "Cancel_ack"}, - { 11, "Bind"}, - { 12, "Bind_ack"}, - { 13, "Bind_nak"}, - { 14, "Alter_context"}, - { 15, "Alter_context_resp"}, - { 16, "AUTH3?"}, - { 17, "Shutdown"}, - { 18, "Co_cancel"}, - { 19, "Orphaned"}, - { 0, NULL } + { PDU_REQ, "Request"}, + { PDU_PING, "Ping"}, + { PDU_RESP, "Response"}, + { PDU_FAULT, "Fault"}, + { PDU_WORKING, "Working"}, + { PDU_NOCALL, "Nocall"}, + { PDU_REJECT, "Reject"}, + { PDU_ACK, "Ack"}, + { PDU_CL_CANCEL, "Cl_cancel"}, + { PDU_FACK, "Fack"}, + { PDU_CANCEL_ACK, "Cancel_ack"}, + { PDU_BIND, "Bind"}, + { PDU_BIND_ACK, "Bind_ack"}, + { PDU_BIND_NAK, "Bind_nak"}, + { PDU_ALTER, "Alter_context"}, + { PDU_ALTER_ACK, "Alter_context_resp"}, + { PDU_AUTH3, "AUTH3"}, + { PDU_SHUTDOWN, "Shutdown"}, + { PDU_CO_CANCEL, "Co_cancel"}, + { PDU_ORPHANED, "Orphaned"}, + { 0, NULL } }; static const value_string drep_byteorder_vals[] = { @@ -77,25 +80,34 @@ static const value_string drep_character_vals[] = { { 0, NULL } }; +#define DCE_RPC_DREP_FP_IEEE 0 +#define DCE_RPC_DREP_FP_VAX 1 +#define DCE_RPC_DREP_FP_CRAY 2 +#define DCE_RPC_DREP_FP_IBM 3 + static const value_string drep_fp_vals[] = { - { 0, "IEEE" }, - { 1, "VAX" }, - { 2, "Cray" }, - { 3, "IBM" }, + { DCE_RPC_DREP_FP_IEEE, "IEEE" }, + { DCE_RPC_DREP_FP_VAX, "VAX" }, + { DCE_RPC_DREP_FP_CRAY, "Cray" }, + { DCE_RPC_DREP_FP_IBM, "IBM" }, { 0, NULL } }; -static const true_false_string flags_set_truth = { - "Set", - "Not set" -}; - /* * Authentication services. */ +#define DCE_C_RPC_AUTHN_PROTOCOL_NONE 0 +#define DCE_C_RPC_AUTHN_PROTOCOL_KRB5 1 +#define DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO 9 +#define DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP 10 +#define DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN 68 + static const value_string authn_protocol_vals[] = { - { 0, "None" }, - { 1, "Kerberos 5" }, + { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" }, + { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" }, + { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" }, + { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" }, + { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN,"NETLOGON Secure Channel" }, { 0, NULL } }; @@ -119,10 +131,164 @@ static const value_string authn_level_vals[] = { { 0, NULL } }; +/* + * Flag bits in first flag field in connectionless PDU header. + */ +#define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */ +#define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last + * fragment of a multi-PDU + * transmission */ +#define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of + a multi-PDU transmission */ +#define PFCL1_NOFACK 0x08 /* If set, the receiver is not + * requested to send a `fack' PDU + * for the fragment */ +#define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe' + * request */ +#define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent + * request */ +#define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast + * request */ +#define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */ + +/* + * Flag bits in second flag field in connectionless PDU header. + */ +#define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */ +#define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */ +#define PFCL2_RESERVED_04 0x04 /* Reserved for future use */ +#define PFCL2_RESERVED_08 0x08 /* Reserved for future use */ +#define PFCL2_RESERVED_10 0x10 /* Reserved for future use */ +#define PFCL2_RESERVED_20 0x20 /* Reserved for future use */ +#define PFCL2_RESERVED_40 0x40 /* Reserved for future use */ +#define PFCL2_RESERVED_80 0x80 /* Reserved for future use */ + +/* + * Flag bits in connection-oriented PDU header. + */ +#define PFC_FIRST_FRAG 0x01 /* First fragment */ +#define PFC_LAST_FRAG 0x02 /* Last fragment */ +#define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */ +#define PFC_RESERVED_1 0x08 +#define PFC_CONC_MPX 0x10 /* suports concurrent multiplexing + * of a single connection. */ +#define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet; + * if true, guaranteed call did not + * execute. */ +#define PFC_MAYBE 0x40 /* `maybe' call semantics requested */ +#define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID + * was specified in the handle, and + * is present in the optional object + * field. If false, the object field + * is omitted. */ + +/* + * Tests whether a connection-oriented PDU is fragmented; returns TRUE if + * it's not fragmented (i.e., this is both the first *and* last fragment), + * and FALSE otherwise. + */ +#define PFC_NOT_FRAGMENTED(hdr) \ + ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG))==(PFC_FIRST_FRAG|PFC_LAST_FRAG)) + +/* + * Presentation context negotiation result. + */ +static const value_string p_cont_result_vals[] = { + { 0, "Acceptance" }, + { 1, "User rejection" }, + { 2, "Provider rejection" }, + { 0, NULL } +}; + +/* + * Presentation context negotiation rejection reasons. + */ +static const value_string p_provider_reason_vals[] = { + { 0, "Reason not specified" }, + { 1, "Abstract syntax not supported" }, + { 2, "Proposed transfer syntaxes not supported" }, + { 3, "Local limit exceeded" }, + { 0, NULL } +}; + +/* + * Reject reasons. + */ +#define REASON_NOT_SPECIFIED 0 +#define TEMPORARY_CONGESTION 1 +#define LOCAL_LIMIT_EXCEEDED 2 +#define CALLED_PADDR_UNKNOWN 3 /* not used */ +#define PROTOCOL_VERSION_NOT_SUPPORTED 4 +#define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */ +#define USER_DATA_NOT_READABLE 6 /* not used */ +#define NO_PSAP_AVAILABLE 7 /* not used */ + +static const value_string reject_reason_vals[] = { + { REASON_NOT_SPECIFIED, "Reason not specified" }, + { TEMPORARY_CONGESTION, "Temporary congestion" }, + { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" }, + { CALLED_PADDR_UNKNOWN, "Called paddr unknown" }, + { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" }, + { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" }, + { USER_DATA_NOT_READABLE, "User data not readable" }, + { NO_PSAP_AVAILABLE, "No PSAP available" }, + { 0, NULL } +}; + +/* + * Reject status codes. + */ +static const value_string reject_status_vals[] = { + { 0, "Stub-defined exception" }, + { 0x1c000001, "nca_s_fault_int_div_by_zero" }, + { 0x1c000002, "nca_s_fault_addr_error" }, + { 0x1c000003, "nca_s_fault_fp_div_zero" }, + { 0x1c000004, "nca_s_fault_fp_underflow" }, + { 0x1c000005, "nca_s_fault_fp_overflow" }, + { 0x1c000006, "nca_s_fault_invalid_tag" }, + { 0x1c000007, "nca_s_fault_invalid_bound" }, + { 0x1c000008, "nca_rpc_version_mismatch" }, + { 0x1c000009, "nca_unspec_reject" }, + { 0x1c00000a, "nca_s_bad_actid" }, + { 0x1c00000b, "nca_who_are_you_failed" }, + { 0x1c00000c, "nca_manager_not_entered" }, + { 0x1c00000d, "nca_s_fault_cancel" }, + { 0x1c00000e, "nca_s_fault_ill_inst" }, + { 0x1c00000f, "nca_s_fault_fp_error" }, + { 0x1c000010, "nca_s_fault_int_overflow" }, + { 0x1c000014, "nca_s_fault_pipe_empty" }, + { 0x1c000015, "nca_s_fault_pipe_closed" }, + { 0x1c000016, "nca_s_fault_pipe_order" }, + { 0x1c000017, "nca_s_fault_pipe_discipline" }, + { 0x1c000018, "nca_s_fault_pipe_comm_error" }, + { 0x1c000019, "nca_s_fault_pipe_memory" }, + { 0x1c00001a, "nca_s_fault_context_mismatch" }, + { 0x1c00001b, "nca_s_fault_remote_no_memory" }, + { 0x1c00001c, "nca_invalid_pres_context_id" }, + { 0x1c00001d, "nca_unsupported_authn_level" }, + { 0x1c00001f, "nca_invalid_checksum" }, + { 0x1c000020, "nca_invalid_crc" }, + { 0x1c000021, "ncs_s_fault_user_defined" }, + { 0x1c000022, "nca_s_fault_tx_open_failed" }, + { 0x1c000023, "nca_s_fault_codeset_conv_error" }, + { 0x1c000024, "nca_s_fault_object_not_found" }, + { 0x1c000025, "nca_s_fault_no_client_stub" }, + { 0x1c010002, "nca_op_rng_error" }, + { 0x1c010003, "nca_unk_if"}, + { 0x1c010006, "nca_wrong_boot_time" }, + { 0x1c010009, "nca_s_you_crashed" }, + { 0x1c01000b, "nca_proto_error" }, + { 0x1c010013, "nca_out_args_too_big" }, + { 0x1c010014, "nca_server_too_busy" }, + { 0x1c010017, "nca_unsupported_type" }, + { 0, NULL } +}; + static int proto_dcerpc = -1; /* field defines */ static int hf_dcerpc_request_in = -1; +static int hf_dcerpc_time = -1; static int hf_dcerpc_response_in = -1; static int hf_dcerpc_ver = -1; static int hf_dcerpc_ver_minor = -1; @@ -162,7 +328,12 @@ static int hf_dcerpc_cn_ack_result = -1; static int hf_dcerpc_cn_ack_reason = -1; static int hf_dcerpc_cn_ack_trans_id = -1; static int hf_dcerpc_cn_ack_trans_ver = -1; +static int hf_dcerpc_cn_reject_reason = -1; +static int hf_dcerpc_cn_num_protocols = -1; +static int hf_dcerpc_cn_protocol_ver_major = -1; +static int hf_dcerpc_cn_protocol_ver_minor = -1; static int hf_dcerpc_cn_cancel_count = -1; +static int hf_dcerpc_cn_status = -1; static int hf_dcerpc_auth_type = -1; static int hf_dcerpc_auth_level = -1; static int hf_dcerpc_auth_pad_len = -1; @@ -200,9 +371,24 @@ static int hf_dcerpc_opnum = -1; static int hf_dcerpc_dg_seqnum = -1; static int hf_dcerpc_dg_server_boot = -1; static int hf_dcerpc_dg_if_ver = -1; +static int hf_dcerpc_krb5_av_prot_level = -1; +static int hf_dcerpc_krb5_av_key_vers_num = -1; +static int hf_dcerpc_krb5_av_key_auth_verifier = -1; +static int hf_dcerpc_dg_cancel_vers = -1; +static int hf_dcerpc_dg_cancel_id = -1; +static int hf_dcerpc_dg_server_accepting_cancels = -1; +static int hf_dcerpc_dg_fack_vers = -1; +static int hf_dcerpc_dg_fack_window_size = -1; +static int hf_dcerpc_dg_fack_max_tsdu = -1; +static int hf_dcerpc_dg_fack_max_frag_size = -1; +static int hf_dcerpc_dg_fack_serial_num = -1; +static int hf_dcerpc_dg_fack_selack_len = -1; +static int hf_dcerpc_dg_fack_selack = -1; +static int hf_dcerpc_dg_status = -1; static int hf_dcerpc_array_max_count = -1; static int hf_dcerpc_array_offset = -1; static int hf_dcerpc_array_actual_count = -1; +static int hf_dcerpc_array_buffer = -1; static int hf_dcerpc_op = -1; static int hf_dcerpc_referent_id = -1; static int hf_dcerpc_fragments = -1; @@ -212,6 +398,12 @@ static int hf_dcerpc_fragment_overlap_conflict = -1; static int hf_dcerpc_fragment_multiple_tails = -1; static int hf_dcerpc_fragment_too_long_fragment = -1; static int hf_dcerpc_fragment_error = -1; +static int hf_dcerpc_reassembled_in = -1; +static int hf_dcerpc_sec_chan = -1; +static int hf_dcerpc_sec_chan_sig = -1; +static int hf_dcerpc_sec_chan_unk = -1; +static int hf_dcerpc_sec_chan_seq = -1; +static int hf_dcerpc_sec_chan_nonce = -1; static gint ett_dcerpc = -1; static gint ett_dcerpc_cn_flags = -1; @@ -219,25 +411,57 @@ static gint ett_dcerpc_drep = -1; static gint ett_dcerpc_dg_flags1 = -1; static gint ett_dcerpc_dg_flags2 = -1; static gint ett_dcerpc_pointer_data = -1; +static gint ett_dcerpc_string = -1; static gint ett_dcerpc_fragments = -1; static gint ett_dcerpc_fragment = -1; +static gint ett_decrpc_krb5_auth_verf = -1; +static gint ett_sec_chan = -1; + +static dissector_handle_t ntlmssp_handle, ntlmssp_verf_handle, + ntlmssp_enc_payload_handle; +static dissector_handle_t gssapi_handle, gssapi_verf_handle; + +static const fragment_items dcerpc_frag_items = { + &ett_dcerpc_fragments, + &ett_dcerpc_fragment, + + &hf_dcerpc_fragments, + &hf_dcerpc_fragment, + &hf_dcerpc_fragment_overlap, + &hf_dcerpc_fragment_overlap_conflict, + &hf_dcerpc_fragment_multiple_tails, + &hf_dcerpc_fragment_too_long_fragment, + &hf_dcerpc_fragment_error, + NULL, + + "fragments" +}; + +typedef struct _dcerpc_auth_info { + guint8 auth_pad_len; + guint8 auth_level; + guint8 auth_type; + guint32 auth_size; +} dcerpc_auth_info; /* try to desegment big DCE/RPC packets over TCP? */ static gboolean dcerpc_cn_desegment = TRUE; /* reassemble DCE/RPC fragments */ -/* reassembly of dcerpc fragments will not work for the case where ONE frame +/* reassembly of dcerpc fragments will not work for the case where ONE frame might contain multiple dcerpc fragments for different PDUs. this case would be so unusual/weird so if you got captures like that: too bad */ static gboolean dcerpc_reassemble = FALSE; -static GHashTable *dcerpc_reassemble_table = NULL; +static GHashTable *dcerpc_co_reassemble_table = NULL; +static GHashTable *dcerpc_cl_reassemble_table = NULL; static void dcerpc_reassemble_init(void) { - fragment_table_init(&dcerpc_reassemble_table); + fragment_table_init(&dcerpc_co_reassemble_table); + fragment_table_init(&dcerpc_cl_reassemble_table); } /* @@ -245,25 +469,13 @@ dcerpc_reassemble_init(void) */ /* the registered subdissectors */ -static GHashTable *dcerpc_uuids; - -typedef struct _dcerpc_uuid_key { - e_uuid_t uuid; - guint16 ver; -} dcerpc_uuid_key; - -typedef struct _dcerpc_uuid_value { - int proto; - int ett; - gchar *name; - dcerpc_sub_dissector *procs; -} dcerpc_uuid_value; +GHashTable *dcerpc_uuids=NULL; static gint dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2) { - dcerpc_uuid_key *key1 = (dcerpc_uuid_key *)k1; - dcerpc_uuid_key *key2 = (dcerpc_uuid_key *)k2; + const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1; + const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2; return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0) && (key1->ver == key2->ver)); } @@ -271,7 +483,7 @@ dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2) static guint dcerpc_uuid_hash (gconstpointer k) { - dcerpc_uuid_key *key = (dcerpc_uuid_key *)k; + const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k; /* This isn't perfect, but the Data1 part of these is almost always unique. */ return key->uuid.Data1; @@ -279,7 +491,7 @@ dcerpc_uuid_hash (gconstpointer k) void dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver, - dcerpc_sub_dissector *procs) + dcerpc_sub_dissector *procs, int opnum_hf) { dcerpc_uuid_key *key = g_malloc (sizeof (*key)); dcerpc_uuid_value *value = g_malloc (sizeof (*value)); @@ -291,10 +503,45 @@ dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver, value->ett = ett; value->name = proto_get_protocol_short_name (proto); value->procs = procs; + value->opnum_hf = opnum_hf; g_hash_table_insert (dcerpc_uuids, key, value); } +/* Function to find the name of a registered protocol + * or NULL if the protocol/version is not known to ethereal. + */ +char * +dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver) +{ + dcerpc_uuid_key key; + dcerpc_uuid_value *sub_proto; + + key.uuid = *uuid; + key.ver = ver; + if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){ + return NULL; + } + return sub_proto->name; +} + +/* Function to find the subdissector table of a registered protocol + * or NULL if the protocol/version is not known to ethereal. + */ +dcerpc_sub_dissector * +dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver) +{ + dcerpc_uuid_key key; + dcerpc_uuid_value *sub_proto; + + key.uuid = *uuid; + key.ver = ver; + if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){ + return NULL; + } + return sub_proto->procs; +} + /* * To keep track of ctx_id mappings. @@ -322,8 +569,8 @@ static GMemChunk *dcerpc_bind_value_chunk=NULL; static gint dcerpc_bind_equal (gconstpointer k1, gconstpointer k2) { - dcerpc_bind_key *key1 = (dcerpc_bind_key *)k1; - dcerpc_bind_key *key2 = (dcerpc_bind_key *)k2; + const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1; + const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2; return (key1->conv == key2->conv && key1->ctx_id == key2->ctx_id && key1->smb_fid == key2->smb_fid); @@ -332,8 +579,9 @@ dcerpc_bind_equal (gconstpointer k1, gconstpointer k2) static guint dcerpc_bind_hash (gconstpointer k) { - dcerpc_bind_key *key = (dcerpc_bind_key *)k; - return ((guint)key->conv) + key->ctx_id + key->smb_fid; + const dcerpc_bind_key *key = (const dcerpc_bind_key *)k; + return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid; + } /* @@ -355,8 +603,8 @@ static GMemChunk *dcerpc_call_value_chunk=NULL; static gint dcerpc_call_equal (gconstpointer k1, gconstpointer k2) { - dcerpc_call_key *key1 = (dcerpc_call_key *)k1; - dcerpc_call_key *key2 = (dcerpc_call_key *)k2; + const dcerpc_call_key *key1 = (const dcerpc_call_key *)k1; + const dcerpc_call_key *key2 = (const dcerpc_call_key *)k2; return (key1->conv == key2->conv && key1->call_id == key2->call_id && key1->smb_fid == key2->smb_fid); @@ -365,7 +613,7 @@ dcerpc_call_equal (gconstpointer k1, gconstpointer k2) static guint dcerpc_call_hash (gconstpointer k) { - dcerpc_call_key *key = (dcerpc_call_key *)k; + const dcerpc_call_key *key = (const dcerpc_call_key *)k; return ((guint32)key->conv) + key->call_id + key->smb_fid; } @@ -394,7 +642,7 @@ dcerpc_matched_hash (gconstpointer k) int dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, - proto_tree *tree, char *drep, + proto_tree *tree, char *drep, int hfindex, guint8 *pdata) { guint8 data; @@ -410,7 +658,7 @@ dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, int dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, - proto_tree *tree, char *drep, + proto_tree *tree, char *drep, int hfindex, guint16 *pdata) { guint16 data; @@ -418,7 +666,7 @@ dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, data = ((drep[0] & 0x10) ? tvb_get_letohs (tvb, offset) : tvb_get_ntohs (tvb, offset)); - + if (tree) { proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10)); } @@ -429,7 +677,7 @@ dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, int dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, - proto_tree *tree, char *drep, + proto_tree *tree, char *drep, int hfindex, guint32 *pdata) { guint32 data; @@ -437,7 +685,7 @@ dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, data = ((drep[0] & 0x10) ? tvb_get_letohl (tvb, offset) : tvb_get_ntohl (tvb, offset)); - + if (tree) { proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10)); } @@ -446,9 +694,33 @@ dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, return offset+4; } +/* handles 32 bit unix time_t */ +int +dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, + proto_tree *tree, char *drep, + int hfindex, guint32 *pdata) +{ + guint32 data; + nstime_t tv; + + data = ((drep[0] & 0x10) + ? tvb_get_letohl (tvb, offset) + : tvb_get_ntohl (tvb, offset)); + + tv.secs=data; + tv.nsecs=0; + if (tree) { + proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv); + } + if (pdata) + *pdata = data; + + return offset+4; +} + int dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, - proto_tree *tree, char *drep, + proto_tree *tree, char *drep, int hfindex, unsigned char *pdata) { if(pdata){ @@ -469,6 +741,75 @@ dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, return offset+8; } + +int +dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, + proto_tree *tree, char *drep, + int hfindex, gfloat *pdata) +{ + gfloat data; + + + switch(drep[1]) { + case(DCE_RPC_DREP_FP_IEEE): + data = ((drep[0] & 0x10) + ? tvb_get_letohieee_float(tvb, offset) + : tvb_get_ntohieee_float(tvb, offset)); + if (tree) { + proto_tree_add_float(tree, hfindex, tvb, offset, 4, data); + } + break; + case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */ + case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */ + case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */ + default: + /* ToBeDone: non IEEE floating formats */ + /* Set data to a negative infinity value */ + data = -1.0 * 1e100 * 1e100; + if (tree) { + proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]); + } + } + if (pdata) + *pdata = data; + return offset + 4; +} + + +int +dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, + proto_tree *tree, char *drep, + int hfindex, gdouble *pdata) +{ + gdouble data; + + + switch(drep[1]) { + case(DCE_RPC_DREP_FP_IEEE): + data = ((drep[0] & 0x10) + ? tvb_get_letohieee_double(tvb, offset) + : tvb_get_ntohieee_double(tvb, offset)); + if (tree) { + proto_tree_add_double(tree, hfindex, tvb, offset, 8, data); + } + break; + case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */ + case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */ + case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */ + default: + /* ToBeDone: non IEEE double formats */ + /* Set data to a negative infinity value */ + data = -1.0 * 1e100 * 1e100; + if (tree) { + proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]); + } + } + if (pdata) + *pdata = data; + return offset + 8; +} + + /* * a couple simpler things */ @@ -509,9 +850,9 @@ dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid) /* NDR arrays */ /* function to dissect a unidimensional conformant array */ -int +int dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo, - proto_tree *tree, char *drep, + proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct) { guint32 i; @@ -529,7 +870,7 @@ dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo, di->conformant_run=1; di->conformant_eaten=offset-old_offset; } else { - /* we dont dont remember where in the bytestream this fields was */ + /* we don't remember where in the bytestream this field was */ proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count); /* real run, dissect the elements */ @@ -541,9 +882,9 @@ dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo, return offset; } /* function to dissect a unidimensional conformant and varying array */ -int +int dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo, - proto_tree *tree, char *drep, + proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct) { guint32 i; @@ -581,6 +922,197 @@ dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo, return offset; } +/* Dissect an string of bytes. This corresponds to + IDL of the form '[string] byte *foo'. + + It can also be used for a conformant varying array of bytes if + the contents of the array should be shown as a big blob, rather + than showing each byte as an individual element. + + XXX - which of those is really the IDL type for, for example, + the encrypted data in some MAPI packets? (Microsoft haven't + released that IDL.) + + XXX - does this need to do all the conformant array stuff that + "dissect_ndr_ucvarray()" does? These are presumably for strings + that are conformant and varying - they're stored like conformant + varying arrays of bytes. */ +int +dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, char *drep) +{ + dcerpc_info *di; + guint32 len; + + di=pinfo->private_data; + if(di->conformant_run){ + /* just a run to handle conformant arrays, no scalars to dissect */ + return offset; + } + + /* NDR array header */ + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_dcerpc_array_max_count, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_dcerpc_array_offset, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, + hf_dcerpc_array_actual_count, &len); + + if (tree && len) + proto_tree_add_item(tree, hf_dcerpc_array_buffer, + tvb, offset, len, drep[0] & 0x10); + + offset += len; + + return offset; +} + +/* For dissecting arrays that are to be interpreted as strings. */ + +/* Dissect an NDR conformant varying string of elements. + The length of each element is given by the 'size_is' parameter; + the elements are assumed to be characters or wide characters. + + XXX - does this need to do all the conformant array stuff that + "dissect_ndr_ucvarray()" does? */ +int +dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, char *drep, int size_is, + int hfindex, gboolean add_subtree, char **data) +{ + dcerpc_info *di; + proto_item *string_item; + proto_tree *string_tree; + guint32 len, buffer_len; + char *s; + header_field_info *hfinfo; + + di=pinfo->private_data; + if(di->conformant_run){ + /* just a run to handle conformant arrays, no scalars to dissect */ + return offset; + } + + if (add_subtree) { + string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s", + proto_registrar_get_name(hfindex)); + string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string); + } else { + string_item = NULL; + string_tree = tree; + } + + /* NDR array header */ + + offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep, + hf_dcerpc_array_max_count, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep, + hf_dcerpc_array_offset, NULL); + + offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep, + hf_dcerpc_array_actual_count, &len); + + buffer_len = size_is * len; + + /* Adjust offset */ + if (offset % size_is) + offset += size_is - (offset % size_is); + + if (size_is == sizeof(guint16)) { + /* XXX - use drep to determine the byte order? */ + s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE); + /* + * XXX - we don't support a string type with Unicode + * characters, so if this is a string item, we make + * its value be the "fake Unicode" string. + */ + if (tree && buffer_len) { + hfinfo = proto_registrar_get_nth(hfindex); + if (hfinfo->type == FT_STRING) { + proto_tree_add_string(string_tree, hfindex, tvb, offset, + buffer_len, s); + } else { + proto_tree_add_item(string_tree, hfindex, tvb, offset, + buffer_len, drep[0] & 0x10); + } + } + } else { + /* + * First, make sure the entire string is in the tvbuff, and throw + * an exception if it isn't. If the length is bogus, this should + * keep us from trying to allocate an immensely large buffer. + * (It won't help if the length is *valid* but immensely large, + * but that's another matter; in any case, that would happen only + * if we had an immensely large tvbuff....) + */ + tvb_ensure_bytes_exist(tvb, offset, buffer_len); + s = g_malloc(buffer_len + 1); + tvb_memcpy(tvb, s, offset, buffer_len); + if (tree && buffer_len) + proto_tree_add_item(string_tree, hfindex, tvb, offset, + buffer_len, drep[0] & 0x10); + } + + if (string_item != NULL) + proto_item_append_text(string_item, ": %s", s); + + if (data) + *data = s; + else + g_free(s); + + offset += buffer_len; + + proto_item_set_end(string_item, tvb, offset); + + return offset; +} + +/* Dissect an conformant varying string of chars. + This corresponds to IDL of the form '[string] char *foo'. + + XXX - at least according to the DCE RPC 1.1 spec, a string has + a null terminator, which isn't necessary as a terminator for + the transfer language (as there's a length), but is presumably + there for the benefit of null-terminated-string languages + such as C. Is this ever used for purely counted strings? + (Not that it matters if it is.) */ +int +dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, char *drep) +{ + dcerpc_info *di; + di=pinfo->private_data; + + return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep, + sizeof(guint8), di->hf_index, + FALSE, NULL); +} + +/* Dissect a conformant varying string of wchars (wide characters). + This corresponds to IDL of the form '[string] wchar *foo' + + XXX - at least according to the DCE RPC 1.1 spec, a string has + a null terminator, which isn't necessary as a terminator for + the transfer language (as there's a length), but is presumably + there for the benefit of null-terminated-string languages + such as C. Is this ever used for purely counted strings? + (Not that it matters if it is.) */ +int +dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *tree, char *drep) +{ + dcerpc_info *di; + di=pinfo->private_data; + + return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep, + sizeof(guint16), di->hf_index, + FALSE, NULL); +} /* ndr pointer handling */ /* list of pointers encountered so far */ @@ -596,10 +1128,12 @@ static gboolean pointers_are_top_level = TRUE; hoping that his will not collide with any non-ref pointers */ typedef struct ndr_pointer_data { guint32 id; - proto_tree *tree; + proto_item *item; /* proto_item for pointer */ + proto_tree *tree; /* subtree of above item */ dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/ int hf_index; - int levels; + dcerpc_callback_fnct_t *callback; + void *callback_args; } ndr_pointer_data_t; static void @@ -612,7 +1146,7 @@ init_ndr_pointer_list(packet_info *pinfo) while(ndr_pointer_list){ ndr_pointer_data_t *npd; - + npd=g_slist_nth_data(ndr_pointer_list, 0); ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd); if(npd){ @@ -649,7 +1183,6 @@ dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *d tnpd->fnct=NULL; ndr_pointer_list_pos=i+1; di->hf_index=tnpd->hf_index; - di->levels=tnpd->levels; /* first a run to handle any conformant array headers */ di->conformant_run=1; @@ -661,11 +1194,11 @@ dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *d /* This is to check for any bugs in the dissectors. * * Basically, the NDR representation will store all - * arrays in two blocks, one block with the dimension + * arrays in two blocks, one block with the dimension * discreption, like size, number of elements and such, * and another block that contains the actual data stored * in the array. - * If the array is embedded directly inside another, + * If the array is embedded directly inside another, * encapsulating aggregate type, like a union or struct, * then these two blocks will be stored at different places * in the bytestream, with other data between the blocks. @@ -677,8 +1210,8 @@ dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *d * in which mode the dissector MUST NOT consume any data from * the tvbuff (i.e. may not dissect anything) except the * initial control block for arrays. - * The second time the dissector is called, with - * conformant_run==0, all other data for the type will be + * The second time the dissector is called, with + * conformant_run==0, all other data for the type will be * dissected. * * All dissect_ndr_ dissectors are already prepared @@ -698,7 +1231,7 @@ dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *d * if(di->conformant_run){ * return offset; * } - * + * * to make sure it makes the right thing. * This assert will signal when someone has forgotten to * make the dissector aware of this requirement. @@ -706,7 +1239,10 @@ dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *d /* now we dissect the actual pointer */ di->conformant_run=0; + old_offset = offset; offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep); + if (tnpd->callback) + tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args); break; } } @@ -714,11 +1250,12 @@ dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *d return offset; } - + static void -add_pointer_to_list(packet_info *pinfo, proto_tree *tree, - dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, int levels) +add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item, + dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, + dcerpc_callback_fnct_t *callback, void *callback_args) { ndr_pointer_data_t *npd; @@ -738,7 +1275,7 @@ add_pointer_to_list(packet_info *pinfo, proto_tree *tree, } } else { /* if we havent seen the request bail out since we cant - know whether this is the first non-NULL instance + know whether this is the first non-NULL instance or not */ if(value->req_frame==0){ /* XXX THROW EXCEPTION */ @@ -755,10 +1292,12 @@ add_pointer_to_list(packet_info *pinfo, proto_tree *tree, npd=g_malloc(sizeof(ndr_pointer_data_t)); npd->id=id; npd->tree=tree; + npd->item=item; npd->fnct=fnct; npd->hf_index=hf_index; - npd->levels=levels; - ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd, + npd->callback=callback; + npd->callback_args=callback_args; + ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd, ndr_pointer_list_pos); ndr_pointer_list_pos++; } @@ -769,7 +1308,7 @@ find_pointer_index(guint32 id) { ndr_pointer_data_t *npd; int i,len; - + len=g_slist_length(ndr_pointer_list); for(i=0;ihf_index. - * - * levels is a generic int we want to pass to teh callback function. the - * callback can later pick it up from di->levels + * + * callback is executed after the pointer has been dereferenced. + * + * callback_args is passed as an argument to the callback function * * See packet-dcerpc-samr.c for examples */ -int -dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, +int +dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct, - int type, char *text, int hf_index, int levels) + int type, char *text, int hf_index, + dcerpc_callback_fnct_t *callback, void *callback_args) { dcerpc_info *di; - + di=pinfo->private_data; if(di->conformant_run){ /* this call was only for dissecting the header for any @@ -824,11 +1365,12 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *tr; /* we must find out a nice way to do the length here */ - item=proto_tree_add_text(tree, tvb, offset, 0, + item=proto_tree_add_text(tree, tvb, offset, 0, "%s", text); tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data); - add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels); + add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, + hf_index, callback, callback_args); goto after_ref_id; } @@ -842,7 +1384,7 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, /* get the referent id */ offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id); - + /* we got a NULL pointer */ if(id==0){ proto_tree_add_text(tree, tvb, offset-4, 4, @@ -861,11 +1403,12 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, } /* new pointer */ - item=proto_tree_add_text(tree, tvb, offset-4, 4, + item=proto_tree_add_text(tree, tvb, offset-4, 4, "%s", text); tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data); proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id); - add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels); + add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index, + callback, callback_args); goto after_ref_id; } /*TOP LEVEL UNIQUE POINTER*/ @@ -877,7 +1420,7 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, /* get the referent id */ offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id); - + /* we got a NULL pointer */ if(id==0){ proto_tree_add_text(tree, tvb, offset-4, 4, @@ -886,11 +1429,12 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, } /* new pointer */ - item=proto_tree_add_text(tree, tvb, offset-4, 4, + item=proto_tree_add_text(tree, tvb, offset-4, 4, "%s", text); tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data); proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id); - add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels); + add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, + hf_index, callback, callback_args); goto after_ref_id; } @@ -903,13 +1447,14 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, /* get the referent id */ offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id); - + /* new pointer */ - item=proto_tree_add_text(tree, tvb, offset-4, 4, + item=proto_tree_add_text(tree, tvb, offset-4, 4, "%s",text); tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data); proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id); - add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels); + add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, + hf_index, callback, callback_args); goto after_ref_id; } @@ -922,7 +1467,7 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, /* get the referent id */ offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id); - + /* we got a NULL pointer */ if(id==0){ proto_tree_add_text(tree, tvb, offset-4, 4, @@ -931,11 +1476,12 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, } /* new pointer */ - item=proto_tree_add_text(tree, tvb, offset-4, 4, + item=proto_tree_add_text(tree, tvb, offset-4, 4, "%s",text); tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data); proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id); - add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels); + add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff, + hf_index, callback, callback_args); goto after_ref_id; } @@ -949,7 +1495,7 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, /* get the referent id */ offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id); - + /* we got a NULL pointer */ if(id==0){ proto_tree_add_text(tree, tvb, offset-4, 4, @@ -968,11 +1514,12 @@ dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, } /* new pointer */ - item=proto_tree_add_text(tree, tvb, offset-4, 4, + item=proto_tree_add_text(tree, tvb, offset-4, 4, "%s", text); tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data); proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id); - add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels); + add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index, + callback, callback_args); goto after_ref_id; } @@ -990,47 +1537,76 @@ after_ref_id: return offset; } +int +dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct, + int type, char *text, int hf_index) +{ + return dissect_ndr_pointer_cb( + tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index, + NULL, NULL); +} + +static void +show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree, + dcerpc_auth_info *auth_info) +{ + int length; + /* + * We don't show stub data unless we have some in the tvbuff; + * however, in the protocol tree, we show, as the number of + * bytes, the reported number of bytes, not the number of bytes + * that happen to be in the tvbuff. + */ + if (tvb_length_remaining (tvb, offset) > 0) { + length = tvb_reported_length_remaining (tvb, offset); + if (auth_info != NULL && + auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) { + proto_tree_add_text(dcerpc_tree, tvb, offset, -1, + "Encrypted stub data (%d byte%s)", + length, plurality(length, "", "s")); + } else { + proto_tree_add_text (dcerpc_tree, tvb, offset, -1, + "Stub data (%d byte%s)", length, + plurality(length, "", "s")); + } + } +} static int dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree, proto_tree *dcerpc_tree, tvbuff_t *tvb, gint offset, - guint16 opnum, gboolean is_rqst, char *drep, dcerpc_info *info, - int auth_level) + dcerpc_auth_info *auth_info) { dcerpc_uuid_key key; dcerpc_uuid_value *sub_proto; int length; - proto_tree *sub_tree = NULL; + proto_tree *volatile sub_tree = NULL; dcerpc_sub_dissector *proc; gchar *name = NULL; - dcerpc_dissect_fnct_t *sub_dissect; - const char *saved_proto; - void *saved_private_data; + dcerpc_dissect_fnct_t *volatile sub_dissect; + const char *volatile saved_proto; + void *volatile saved_private_data; key.uuid = info->call_data->uuid; key.ver = info->call_data->ver; - + if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL || !proto_is_protocol_enabled(sub_proto->proto)) { - /* - * We don't have a dissector for this UUID, or the protocol - * for that UUID is disabled. - */ - length = tvb_length_remaining (tvb, offset); - if (length > 0) { - proto_tree_add_text (dcerpc_tree, tvb, offset, length, - "Stub data (%d byte%s)", length, - plurality(length, "", "s")); - } + /* + * We don't have a dissector for this UUID, or the protocol + * for that UUID is disabled. + */ + show_stub_data (tvb, offset, dcerpc_tree, auth_info); return -1; } for (proc = sub_proto->procs; proc->name; proc++) { - if (proc->num == opnum) { + if (proc->num == info->call_data->opnum) { name = proc->name; break; } @@ -1045,54 +1621,96 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree, if (check_col (pinfo->cinfo, COL_INFO)) { col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s", - name, is_rqst ? "request" : "reply"); + name, info->request ? "request" : "reply"); } if (tree) { proto_item *sub_item; - sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset, + sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset, -1, FALSE); if (sub_item) { sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett); } - + /* * Put the operation number into the tree along with * the operation's name. - * - * XXX - the subdissectors should all have their own fields - * for the opnum, so that you can filter on a particular - * protocol and opnum value; the opnum value isn't, by itself, - * very interesting, as its interpretation depends on the - * subprotocol. - * - * That would also allow the field to have a value_string - * table, giving names for operations, and letting you filter - * by name. - * - * ONC RPC should do the same thing with the version and - * procedure fields it puts into the subprotocol's tree. */ - proto_tree_add_uint_format (sub_tree, hf_dcerpc_op, tvb, - 0, 0, opnum, - "Operation: %s (%u)", - name, opnum); + + if (sub_proto->opnum_hf != -1) + proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf, + tvb, 0, 0, info->call_data->opnum, + "Operation: %s (%u)", + name, info->call_data->opnum); + else + proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb, + 0, 0, info->call_data->opnum, + "Operation: %s (%u)", + name, info->call_data->opnum); } - /* + /* * If the authentication level is DCE_C_AUTHN_LEVEL_PKT_PRIVACY, - * the stub data is encrypted, and we can't dissect it. + * the stub data is encrypted, and we'd have to decrypt it in + * order to dissect it. */ - if (auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) { + if (auth_info != NULL && + auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) { length = tvb_length_remaining (tvb, offset); if (length > 0) { proto_tree_add_text(sub_tree, tvb, offset, length, "Encrypted stub data (%d byte%s)", length, plurality(length, "", "s")); + + switch (auth_info->auth_type) { + + case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: { + /* NTLMSSP */ + tvbuff_t *ntlmssp_tvb; + ntlmssp_tvb = tvb_new_subset(tvb, offset, length, length); + pinfo->decrypted_data=NULL; + + call_dissector(ntlmssp_enc_payload_handle, ntlmssp_tvb, pinfo, + sub_tree); + + if(pinfo->decrypted_data){ + ntlmssp_decrypted_info_t *ndi=pinfo->decrypted_data; + + + sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp; + if (sub_dissect) { + saved_proto = pinfo->current_proto; + saved_private_data = pinfo->private_data; + pinfo->current_proto = sub_proto->name; + pinfo->private_data = (void *)info; + + init_ndr_pointer_list(pinfo); + + /* + * Catch ReportedBoundsError, as that could + * be due to the decryption being bad, + * and doesn't mean that the tvbuff we were + * handed has a malformed packet. + */ + TRY { + offset = sub_dissect (ndi->decr_tvb, 0, pinfo, ndi->decr_tree, drep); + } CATCH(BoundsError) { + RETHROW; + } CATCH(ReportedBoundsError) { + show_reported_bounds_error(tvb, pinfo, tree); + } ENDTRY; + + pinfo->current_proto = saved_proto; + pinfo->private_data = saved_private_data; + } + } + break; + } + } } } else { - sub_dissect = is_rqst ? proc->dissect_rqst : proc->dissect_resp; + sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp; if (sub_dissect) { saved_proto = pinfo->current_proto; saved_private_data = pinfo->private_data; @@ -1100,7 +1718,17 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree, pinfo->private_data = (void *)info; init_ndr_pointer_list(pinfo); - offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep); + /* + * Catch ReportedBoundsError, so that even if the stub + * data is bad, we still show the verifier. + */ + TRY { + offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep); + } CATCH(BoundsError) { + RETHROW; + } CATCH(ReportedBoundsError) { + show_reported_bounds_error(tvb, pinfo, tree); + } ENDTRY; pinfo->current_proto = saved_proto; pinfo->private_data = saved_private_data; @@ -1113,64 +1741,198 @@ dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree, } } } + tap_queue_packet(dcerpc_tap, pinfo, info); return 0; } static int -dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree, - e_dce_cn_common_hdr_t *hdr, int *auth_level_p) +dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo, + proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr, + dcerpc_auth_info *auth_info) { - int offset; - guint8 auth_pad_len; - guint8 auth_level; - - /* - * Initially set "*auth_level_p" to -1 to indicate that we haven't - * yet seen any authentication level information. - */ - if (auth_level_p != NULL) - *auth_level_p = -1; + int auth_offset; - /* - * 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. - */ - if (tvb_length (tvb) >= hdr->frag_len - && hdr->auth_len + if (auth_info->auth_size != 0) { + auth_offset = hdr->frag_len - hdr->auth_len; + switch (auth_info->auth_type) { + + case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: { + /* NTLMSSP */ + tvbuff_t *ntlmssp_tvb; + + ntlmssp_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len, + hdr->auth_len); + + call_dissector(ntlmssp_verf_handle, ntlmssp_tvb, pinfo, + dcerpc_tree); + + break; + } + + case DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO: { + /* SPNEGO (rfc2478) */ + tvbuff_t *gssapi_tvb; + + gssapi_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len, + hdr->auth_len); + + call_dissector(gssapi_verf_handle, gssapi_tvb, pinfo, dcerpc_tree); + + break; + } + + case DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN: { + proto_item *vf = NULL; + proto_tree *volatile sec_chan_tree = NULL; + /* + * Create a new tree, and split into 4 components ... + */ + vf = proto_tree_add_item(dcerpc_tree, hf_dcerpc_sec_chan, tvb, + auth_offset, -1, FALSE); + sec_chan_tree = proto_item_add_subtree(vf, ett_sec_chan); + + proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_sig, tvb, + auth_offset, 8, FALSE); + + proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_unk, tvb, + auth_offset + 8, 8, FALSE); + + proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_seq, tvb, + auth_offset + 16, 8, FALSE); + + proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_nonce, tvb, + auth_offset + 24, 8, FALSE); + + break; + } + + default: + proto_tree_add_text (dcerpc_tree, tvb, auth_offset, hdr->auth_len, + "Auth Verifier"); + } + } + + return hdr->auth_len; +} + +static void +dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree, + e_dce_cn_common_hdr_t *hdr, gboolean are_credentials, + dcerpc_auth_info *auth_info) +{ + int offset; + + /* + * Initially set auth_level to -1 to indicate that we haven't + * yet seen any authentication level information. + */ + auth_info->auth_level = -1; + + /* + * 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. + */ + if (tvb_length (tvb) >= hdr->frag_len + && hdr->auth_len && (hdr->auth_len + 8 <= hdr->frag_len)) { offset = hdr->frag_len - (hdr->auth_len + 8); - + offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, - hf_dcerpc_auth_type, NULL); + hf_dcerpc_auth_type, + &auth_info->auth_type); offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, - hf_dcerpc_auth_level, &auth_level); - if (auth_level_p != NULL) - *auth_level_p = auth_level; + hf_dcerpc_auth_level, + &auth_info->auth_level); + offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, - hf_dcerpc_auth_pad_len, &auth_pad_len); + hf_dcerpc_auth_pad_len, + &auth_info->auth_pad_len); offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, hf_dcerpc_auth_rsrvd, NULL); offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, hf_dcerpc_auth_ctx_id, NULL); - proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len, "Auth Data"); + /* + * Dissect the authentication data. + */ + if (are_credentials) { + /* + * The authentication data are credentials. + */ + switch (auth_info->auth_type) { + + case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: { + /* NTLMSSP */ + tvbuff_t *ntlmssp_tvb; + + ntlmssp_tvb = tvb_new_subset(tvb, offset, hdr->auth_len, + hdr->auth_len); + + call_dissector(ntlmssp_handle, ntlmssp_tvb, pinfo, + dcerpc_tree); + + break; + } + + case DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO: { + /* SPNEGO (rfc2478) */ + tvbuff_t *gssapi_tvb; + + gssapi_tvb = tvb_new_subset(tvb, offset, hdr->auth_len, + hdr->auth_len); + + call_dissector(gssapi_handle, gssapi_tvb, pinfo, dcerpc_tree); + + break; + } + + case DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN: { + tvbuff_t *secchan_tvb; + + secchan_tvb = tvb_new_subset( + tvb, offset, hdr->auth_len, hdr->auth_len); + + switch(hdr->ptype) { + case PDU_BIND: + netlogon_dissect_secchan_bind_creds( + secchan_tvb, 0, pinfo, dcerpc_tree, + hdr->drep); + break; + case PDU_BIND_ACK: + netlogon_dissect_secchan_bind_ack_creds( + secchan_tvb, 0, pinfo, dcerpc_tree, + hdr->drep); + break; + default: + proto_tree_add_text( + dcerpc_tree, secchan_tvb, 0, hdr->auth_len, + "Secure Channel Credentials"); + } + break; + } + + default: + proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len, + "Auth Credentials"); + } + } /* figure out where the auth padding starts */ - offset = hdr->frag_len - (hdr->auth_len + 8 + auth_pad_len); - if (offset > 0 && auth_pad_len) { - proto_tree_add_text (dcerpc_tree, tvb, offset, - auth_pad_len, "Auth padding"); - return hdr->auth_len + 8 + auth_pad_len; + offset = hdr->frag_len - (hdr->auth_len + 8 + auth_info->auth_pad_len); + if (offset > 0 && auth_info->auth_pad_len) { + proto_tree_add_text (dcerpc_tree, tvb, offset, + auth_info->auth_pad_len, "Auth padding"); + auth_info->auth_size = hdr->auth_len + 8 + auth_info->auth_pad_len; } else { - return hdr->auth_len + 8; + auth_info->auth_size = hdr->auth_len + 8; } } else { - return 0; + auth_info->auth_size = 0; } } @@ -1182,7 +1944,7 @@ dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr static guint16 get_smb_fid (void *private_data) { dcerpc_private_info *priv = (dcerpc_private_info *)private_data; - + if (!priv) return 0; /* Nothing to see here */ @@ -1201,8 +1963,8 @@ static guint16 get_smb_fid (void *private_data) */ static void -dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree, - e_dce_cn_common_hdr_t *hdr) +dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr) { conversation_t *conv = NULL; guint8 num_ctx_items; @@ -1215,7 +1977,9 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr e_uuid_t trans_id; guint32 trans_ver; guint16 if_ver, if_ver_minor; - int offset = 16; + char uuid_str[DCERPC_UUID_STR_LEN]; + int uuid_str_len; + dcerpc_auth_info auth_info; offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, hf_dcerpc_cn_max_xmit, NULL); @@ -1239,16 +2003,20 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, hf_dcerpc_cn_num_trans_items, &num_trans_items); + /* XXX - use "dissect_ndr_uuid_t()"? */ dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id); if (dcerpc_tree) { + uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + if_id.Data1, if_id.Data2, if_id.Data3, + if_id.Data4[0], if_id.Data4[1], + if_id.Data4[2], if_id.Data4[3], + if_id.Data4[4], if_id.Data4[5], + if_id.Data4[6], if_id.Data4[7]); + if (uuid_str_len >= DCERPC_UUID_STR_LEN) + memset(uuid_str, 0, DCERPC_UUID_STR_LEN); proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb, - offset, 16, "HMMM", - "Interface UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - if_id.Data1, if_id.Data2, if_id.Data3, - if_id.Data4[0], if_id.Data4[1], - if_id.Data4[2], if_id.Data4[3], - if_id.Data4[4], if_id.Data4[5], - if_id.Data4[6], if_id.Data4[7]); + offset, 16, uuid_str, "Interface UUID: %s", uuid_str); } offset += 16; @@ -1300,29 +2068,41 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr } if (check_col (pinfo->cinfo, COL_INFO)) { - col_add_fstr (pinfo->cinfo, COL_INFO, "%s: UUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %d.%d", - hdr->ptype == PDU_BIND ? "Bind" : "Alter Ctx", - if_id.Data1, if_id.Data2, if_id.Data3, - if_id.Data4[0], if_id.Data4[1], - if_id.Data4[2], if_id.Data4[3], - if_id.Data4[4], if_id.Data4[5], - if_id.Data4[6], if_id.Data4[7], - if_ver, if_ver_minor); + dcerpc_uuid_key key; + dcerpc_uuid_value *value; + + key.uuid = if_id; + key.ver = if_ver; + + if ((value = g_hash_table_lookup(dcerpc_uuids, &key))) + col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name); + else + col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u", + if_id.Data1, if_id.Data2, if_id.Data3, + if_id.Data4[0], if_id.Data4[1], + if_id.Data4[2], if_id.Data4[3], + if_id.Data4[4], if_id.Data4[5], + if_id.Data4[6], if_id.Data4[7], + if_ver, if_ver_minor); } saw_ctx_item = TRUE; } for (j = 0; j < num_trans_items; j++) { + /* XXX - use "dissect_ndr_uuid_t()"? */ dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id); if (dcerpc_tree) { + uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + trans_id.Data1, trans_id.Data2, trans_id.Data3, + trans_id.Data4[0], trans_id.Data4[1], + trans_id.Data4[2], trans_id.Data4[3], + trans_id.Data4[4], trans_id.Data4[5], + trans_id.Data4[6], trans_id.Data4[7]); + if (uuid_str_len >= DCERPC_UUID_STR_LEN) + memset(uuid_str, 0, DCERPC_UUID_STR_LEN); proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb, - offset, 16, "HMMM", - "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - trans_id.Data1, trans_id.Data2, trans_id.Data3, - trans_id.Data4[0], trans_id.Data4[1], - trans_id.Data4[2], trans_id.Data4[3], - trans_id.Data4[4], trans_id.Data4[5], - trans_id.Data4[6], trans_id.Data4[7]); + offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str); } offset += 16; @@ -1336,12 +2116,12 @@ dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr * an authentication header, and associate it with an authentication * context, so subsequent PDUs can use that context. */ - dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, NULL); + dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info); } static void -dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree, - e_dce_cn_common_hdr_t *hdr) +dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr) { guint16 max_xmit, max_recv; guint16 sec_addr_len; @@ -1351,8 +2131,9 @@ dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerp guint16 reason; e_uuid_t trans_id; guint32 trans_ver; - - int offset = 16; + char uuid_str[DCERPC_UUID_STR_LEN]; + int uuid_str_len; + dcerpc_auth_info auth_info; offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, hf_dcerpc_cn_max_xmit, &max_xmit); @@ -1382,64 +2163,301 @@ dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerp offset += 3; for (i = 0; i < num_results; i++) { - offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, hf_dcerpc_cn_ack_result, &result); - offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, - hdr->drep, hf_dcerpc_cn_ack_reason, - &reason); + if (result != 0) { + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_cn_ack_reason, + &reason); + } else { + /* + * The reason for rejection isn't meaningful, and often isn't + * set, when the syntax was accepted. + */ + offset += 2; + } + /* XXX - use "dissect_ndr_uuid_t()"? */ dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id); if (dcerpc_tree) { + uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + trans_id.Data1, trans_id.Data2, trans_id.Data3, + trans_id.Data4[0], trans_id.Data4[1], + trans_id.Data4[2], trans_id.Data4[3], + trans_id.Data4[4], trans_id.Data4[5], + trans_id.Data4[6], trans_id.Data4[7]); + if (uuid_str_len >= DCERPC_UUID_STR_LEN) + memset(uuid_str, 0, DCERPC_UUID_STR_LEN); proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb, - offset, 16, "HMMM", - "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - trans_id.Data1, trans_id.Data2, trans_id.Data3, - trans_id.Data4[0], trans_id.Data4[1], - trans_id.Data4[2], trans_id.Data4[3], - trans_id.Data4[4], trans_id.Data4[5], - trans_id.Data4[6], trans_id.Data4[7]); + offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str); } offset += 16; offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, hf_dcerpc_cn_ack_trans_ver, &trans_ver); } - + /* * XXX - do we need to do anything with the authentication level * we get back from this? */ - dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, NULL); + dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info); if (check_col (pinfo->cinfo, COL_INFO)) { if (num_results != 0 && result == 0) { - col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: accept max_xmit: %d max_recv: %d", - hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx", - max_xmit, max_recv); + /* XXX - only checks the last result */ + col_append_fstr (pinfo->cinfo, COL_INFO, + " accept max_xmit: %u max_recv: %u", + max_xmit, max_recv); } else { - /* FIXME: should put in reason */ - col_add_fstr (pinfo->cinfo, COL_INFO, "%s ack: %s", - hdr->ptype == PDU_BIND_ACK ? "Bind" : "Alter ctx", - result == 1 ? "User reject" : - result == 2 ? "Provider reject" : - "Unknown"); + /* XXX - only shows the last result and reason */ + col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s", + val_to_str(result, p_cont_result_vals, + "Unknown result (%u)"), + val_to_str(reason, p_provider_reason_vals, + "Unknown (%u)")); } } } static void -dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree, - proto_tree *tree, e_dce_cn_common_hdr_t *hdr) +dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr) +{ + guint16 reason; + guint8 num_protocols; + guint i; + + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_cn_reject_reason, + &reason); + + if (check_col (pinfo->cinfo, COL_INFO)) { + col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s", + val_to_str(reason, reject_reason_vals, "Unknown (%u)")); + } + + if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) { + offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_num_protocols, + &num_protocols); + + for (i = 0; i < num_protocols; i++) { + offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_cn_protocol_ver_major, + NULL); + offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_cn_protocol_ver_minor, + NULL); + } + } +} + +/* Return a string describing a DCE/RPC fragment as first, middle, or end + fragment. */ + +#define PFC_FRAG_MASK 0x03 + +static char * +fragment_type(guint8 flags) +{ + flags = flags & PFC_FRAG_MASK; + + if (flags == PFC_FIRST_FRAG) + return "first"; + + if (flags == 0) + return "middle"; + + if (flags == PFC_LAST_FRAG) + return "last"; + + if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG)) + return "whole"; + + return "unknown"; +} + +static void +dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *dcerpc_tree, proto_tree *tree, + e_dce_cn_common_hdr_t *hdr, dcerpc_info *di, + dcerpc_auth_info *auth_info, guint32 alloc_hint, + guint32 frame) +{ + int length, reported_length, stub_length; + gboolean save_fragmented; + fragment_data *fd_head=NULL; + guint32 tot_len; + + + length = tvb_length_remaining(tvb, offset); + reported_length = tvb_reported_length_remaining(tvb, offset); + stub_length = hdr->frag_len - offset - auth_info->auth_size; + if (length > stub_length) + length = stub_length; + if (reported_length > stub_length) + reported_length = stub_length; + + save_fragmented = pinfo->fragmented; + + /* if this packet is not fragmented, just dissect it and exit */ + if(PFC_NOT_FRAGMENTED(hdr)){ + pinfo->fragmented = FALSE; + dcerpc_try_handoff (pinfo, tree, dcerpc_tree, + tvb_new_subset (tvb, offset, length, reported_length), + 0, hdr->drep, di, auth_info); + + pinfo->fragmented = save_fragmented; + return; + } + + /* The packet is fragmented. */ + pinfo->fragmented = TRUE; + + /* if we are not doing reassembly and this is the first fragment + then just dissect it and exit + */ + if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){ + dcerpc_try_handoff (pinfo, tree, dcerpc_tree, + tvb_new_subset (tvb, offset, length, + reported_length), + 0, hdr->drep, di, auth_info); + goto end_cn_stub; + } + + /* if we have already seen this packet, see if it was reassembled + and if so dissect the full pdu. + then exit + */ + if(pinfo->fd->flags.visited){ + fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table); + + goto end_cn_stub; + } + + + /* if we are not doing reassembly and it was neither a complete PDU + nor the first fragment then there is nothing more we can do + so we just have to exit + */ + if( !dcerpc_reassemble ){ + goto end_cn_stub; + } + + /* if we didnt get 'frame' we dont know where the PDU started and thus + it is pointless to continue + */ + if(!frame){ + goto end_cn_stub; + } + + + /* from now on we must attempt to reassemble the PDU + */ + + + /* we dont have the full fragment so we just have to abort and exit + */ + if( !tvb_bytes_exist(tvb, offset, stub_length) ){ + goto end_cn_stub; + } + + + /* if we get here we know it is the first time we see the packet + and we also know it is only a fragment and not a full PDU, + thus we must reassemble it. + */ + + + /* if this is the first fragment we need to start reassembly + */ + if(hdr->flags&PFC_FIRST_FRAG){ + fragment_add(tvb, offset, pinfo, frame, + dcerpc_co_reassemble_table, + 0, stub_length, TRUE); + fragment_set_tot_len(pinfo, frame, + dcerpc_co_reassemble_table, alloc_hint); + + goto end_cn_stub; + } + + /* if this is a middle fragment, just add it and exit */ + if(!(hdr->flags&PFC_LAST_FRAG)){ + tot_len = fragment_get_tot_len(pinfo, frame, + dcerpc_co_reassemble_table); + fragment_add(tvb, offset, pinfo, frame, + dcerpc_co_reassemble_table, + tot_len-alloc_hint, + stub_length, + TRUE); + + goto end_cn_stub; + } + + /* this was the last fragment add it to reassembly + */ + tot_len = fragment_get_tot_len(pinfo, frame, + dcerpc_co_reassemble_table); + fd_head = fragment_add(tvb, offset, pinfo, + frame, + dcerpc_co_reassemble_table, + tot_len-alloc_hint, + stub_length, + TRUE); + + + +end_cn_stub: + + /* if reassembly is complete, dissect the full PDU + */ + if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){ + if(pinfo->fd->num==fd_head->reassembled_in){ + tvbuff_t *next_tvb; + + next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen); + tvb_set_child_real_data_tvbuff(tvb, next_tvb); + add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC"); + show_fragment_tree(fd_head, &dcerpc_frag_items, + dcerpc_tree, pinfo, next_tvb); + + pinfo->fragmented = FALSE; + dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb, + 0, hdr->drep, di, auth_info); + } else { + proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in, tvb, 0, 0, fd_head->reassembled_in); + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, + " [DCE/RPC %s fragment]", fragment_type(hdr->flags)); + } + } + } else { + /* Reassembly not complete - some fragments + are missing */ + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, + " [DCE/RPC %s fragment]", fragment_type(hdr->flags)); + } + } + + pinfo->fragmented = save_fragmented; +} + +static void +dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr) { conversation_t *conv; guint16 ctx_id; guint16 opnum; e_uuid_t obj_id; - int auth_sz = 0; - int auth_level; - int offset = 16; + dcerpc_auth_info auth_info; guint32 alloc_hint; + char uuid_str[DCERPC_UUID_STR_LEN]; + int uuid_str_len; offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, hf_dcerpc_cn_alloc_hint, &alloc_hint); @@ -1451,25 +2469,29 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr hf_dcerpc_opnum, &opnum); if (check_col (pinfo->cinfo, COL_INFO)) { - col_add_fstr (pinfo->cinfo, COL_INFO, "Request: opnum: %d ctx_id:%d", + col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u", opnum, ctx_id); } - if (hdr->flags & 0x80) { + if (hdr->flags & PFC_OBJECT_UUID) { + /* XXX - use "dissect_ndr_uuid_t()"? */ dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id); if (dcerpc_tree) { + uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + obj_id.Data1, obj_id.Data2, obj_id.Data3, + obj_id.Data4[0], + obj_id.Data4[1], + obj_id.Data4[2], + obj_id.Data4[3], + obj_id.Data4[4], + obj_id.Data4[5], + obj_id.Data4[6], + obj_id.Data4[7]); + if (uuid_str_len >= DCERPC_UUID_STR_LEN) + memset(uuid_str, 0, DCERPC_UUID_STR_LEN); proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb, - offset, 16, "HMMM", - "Object UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - obj_id.Data1, obj_id.Data2, obj_id.Data3, - obj_id.Data4[0], - obj_id.Data4[1], - obj_id.Data4[2], - obj_id.Data4[3], - obj_id.Data4[4], - obj_id.Data4[5], - obj_id.Data4[6], - obj_id.Data4[7]); + offset, 16, uuid_str, "Object UUID: %s", uuid_str); } offset += 16; } @@ -1478,17 +2500,14 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr * XXX - what if this was set when the connection was set up, * and we just have a security context? */ - auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, - &auth_level); + dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info); conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); - if (!conv) { - - } else { + if (!conv) + show_stub_data (tvb, offset, dcerpc_tree, &auth_info); + else { dcerpc_call_value *value; - int length, reported_length, stub_length; - dcerpc_info di; /* !!! we can NOT check flags.visited here since this will interact badly with when SMB handles (i.e. calls the subdissector) @@ -1503,51 +2522,60 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr bind_key.ctx_id=ctx_id; bind_key.smb_fid=get_smb_fid(pinfo->private_data); - if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key))){ - dcerpc_call_key *call_key; - dcerpc_call_value *call_value; - - /* We found the binding so just add the call - to both the call table and the matched table - */ - call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk); - call_key->conv=conv; - call_key->call_id=hdr->call_id; - call_key->smb_fid=get_smb_fid(pinfo->private_data); - - /* if there is already a matching call in the table - remove it so it is replaced with the new one */ - if(g_hash_table_lookup(dcerpc_calls, call_key)){ - g_hash_table_remove(dcerpc_calls, call_key); - } + if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){ + if(!(hdr->flags&PFC_FIRST_FRAG)){ + dcerpc_call_key call_key; + dcerpc_call_value *call_value; - call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk); - call_value->uuid = bind_value->uuid; - call_value->ver = bind_value->ver; - call_value->opnum = opnum; - call_value->req_frame=pinfo->fd->num; - call_value->rep_frame=0; - call_value->max_ptr=0; - call_value->private_data = NULL; - g_hash_table_insert (dcerpc_calls, call_key, call_value); - - g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value); + call_key.conv=conv; + call_key.call_id=hdr->call_id; + call_key.smb_fid=get_smb_fid(pinfo->private_data); + if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){ + g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value); + } + } else { + dcerpc_call_key *call_key; + dcerpc_call_value *call_value; + + /* We found the binding and it is the first fragment + (or a complete PDU) of a dcerpc pdu so just add + the call to both the call table and the + matched table + */ + call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk); + call_key->conv=conv; + call_key->call_id=hdr->call_id; + call_key->smb_fid=get_smb_fid(pinfo->private_data); + + /* if there is already a matching call in the table + remove it so it is replaced with the new one */ + if(g_hash_table_lookup(dcerpc_calls, call_key)){ + g_hash_table_remove(dcerpc_calls, call_key); + } + + call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk); + call_value->uuid = bind_value->uuid; + call_value->ver = bind_value->ver; + call_value->opnum = opnum; + call_value->req_frame=pinfo->fd->num; + call_value->req_time.secs=pinfo->fd->abs_secs; + call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000; + call_value->rep_frame=0; + call_value->max_ptr=0; + call_value->private_data = NULL; + g_hash_table_insert (dcerpc_calls, call_key, call_value); + + g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value); + } } } value=g_hash_table_lookup (dcerpc_matched, (void *)pinfo->fd->num); - if (value) { + dcerpc_info di; /* handoff this call */ - length = tvb_length_remaining(tvb, offset); - reported_length = tvb_reported_length_remaining(tvb, offset); - stub_length = hdr->frag_len - offset - auth_sz; - if (length > stub_length) - length = stub_length; - if (reported_length > stub_length) - reported_length = stub_length; di.conv = conv; di.call_id = hdr->call_id; di.smb_fid = get_smb_fid(pinfo->private_data); @@ -1555,154 +2583,129 @@ dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr di.call_data = value; if(value->rep_frame!=0){ - proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in, + proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in, tvb, 0, 0, value->rep_frame); } +/*qqq request, broken*/ + dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree, + hdr, &di, &auth_info, alloc_hint, + value->req_frame); + } else + show_stub_data (tvb, offset, dcerpc_tree, &auth_info); + } + + /* Decrypt the verifier, if present */ + dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info); +} + +static void +dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr) +{ + dcerpc_call_value *value = NULL; + conversation_t *conv; + guint16 ctx_id; + dcerpc_auth_info auth_info; + guint32 alloc_hint; + + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_alloc_hint, &alloc_hint); + + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_ctx_id, &ctx_id); + + if (check_col (pinfo->cinfo, COL_INFO)) { + col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id); + } + + offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_cancel_count, NULL); + /* padding */ + offset++; + + /* + * 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); + + conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype, + pinfo->srcport, pinfo->destport, 0); + if (!conv) { + /* no point in creating one here, really */ + show_stub_data (tvb, offset, dcerpc_tree, &auth_info); + } else { + + /* !!! we can NOT check flags.visited here since this will interact + badly with when SMB handles (i.e. calls the subdissector) + and desegmented pdu's . + Instead we check if this pdu is already in the matched table or not + */ + if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){ + dcerpc_call_key call_key; + dcerpc_call_value *call_value; + + call_key.conv=conv; + call_key.call_id=hdr->call_id; + call_key.smb_fid=get_smb_fid(pinfo->private_data); + + if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){ + g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value); + if(call_value->rep_frame==0){ + call_value->rep_frame=pinfo->fd->num; + } - /* If we dont have reassembly enabled, or this packet contains the - entire PDU, just call the handoff directly */ - if( (!dcerpc_reassemble) - || ((hdr->flags&0x03)==0x03) ){ - if(hdr->flags&0x01){ - dcerpc_try_handoff (pinfo, tree, dcerpc_tree, - tvb_new_subset (tvb, offset, length, - reported_length), - 0, opnum, TRUE, hdr->drep, &di, auth_level); - } else { - if (check_col(pinfo->cinfo, COL_INFO)) { - col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]"); - } - } - } else if(dcerpc_reassemble){ - /*OK we need to do reassembly */ - /* handle first fragment */ - if((hdr->flags&0x03)==0x01){ /* FIRST fragment */ - if( (!pinfo->fd->flags.visited) && value->req_frame ){ - fragment_add(tvb, offset, pinfo, value->req_frame, - dcerpc_reassemble_table, - 0, - length, - TRUE); - fragment_set_tot_len(pinfo, value->req_frame, - dcerpc_reassemble_table, alloc_hint); - } - if (check_col(pinfo->cinfo, COL_INFO)) { - col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]"); - } - } - if((hdr->flags&0x03)==0x00){ /* MIDDLE fragment(s) */ - if( (!pinfo->fd->flags.visited) && value->req_frame ){ - guint32 tot_len; - tot_len = fragment_get_tot_len(pinfo, value->req_frame, - dcerpc_reassemble_table); - fragment_add(tvb, offset, pinfo, value->req_frame, - dcerpc_reassemble_table, - tot_len-alloc_hint, - length, - TRUE); - } - if (check_col(pinfo->cinfo, COL_INFO)) { - col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]"); - } } - if((hdr->flags&0x03)==0x02){ /* LAST fragment */ - if( value->req_frame ){ - fragment_data *ipfd_head; - guint32 tot_len; - tot_len = fragment_get_tot_len(pinfo, value->req_frame, - dcerpc_reassemble_table); - ipfd_head = fragment_add(tvb, offset, pinfo, - value->req_frame, - dcerpc_reassemble_table, - tot_len-alloc_hint, - length, - TRUE); + } - if(ipfd_head){ - fragment_data *ipfd; - proto_tree *ft=NULL; - proto_item *fi=NULL; - tvbuff_t *next_tvb; + value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num); - next_tvb = tvb_new_real_data(ipfd_head->data, ipfd_head->datalen, ipfd_head->datalen); - tvb_set_child_real_data_tvbuff(tvb, next_tvb); - add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC"); - pinfo->fragmented=FALSE; - fi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragments, next_tvb, 0, -1, FALSE); - ft = proto_item_add_subtree(fi, ett_dcerpc_fragments); - for (ipfd=ipfd_head->next; ipfd; ipfd=ipfd->next){ - if (ipfd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { - proto_tree *fet=NULL; - proto_item *fei=NULL; - int hf; - - if (ipfd->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { - hf = hf_dcerpc_fragment_error; - } else { - hf = hf_dcerpc_fragment; - } - fei = proto_tree_add_none_format(ft, hf, - next_tvb, ipfd->offset, ipfd->len, - "Frame:%u payload:%u-%u", - ipfd->frame, - ipfd->offset, - ipfd->offset+ipfd->len-1); - fet = proto_item_add_subtree(fei, ett_dcerpc_fragment); - if (ipfd->flags&FD_OVERLAP) { - proto_tree_add_boolean(fet, hf_dcerpc_fragment_overlap, next_tvb, 0, 0, TRUE); - } - if (ipfd->flags&FD_OVERLAPCONFLICT) { - proto_tree_add_boolean(fet, hf_dcerpc_fragment_overlap_conflict, next_tvb, 0, 0, TRUE); - } - if (ipfd->flags&FD_MULTIPLETAILS) { - proto_tree_add_boolean(fet, hf_dcerpc_fragment_multiple_tails, next_tvb, 0, 0, TRUE); - } - if (ipfd->flags&FD_TOOLONGFRAGMENT) { - proto_tree_add_boolean(fet, hf_dcerpc_fragment_too_long_fragment, next_tvb, 0, 0, TRUE); - } - } else { - proto_tree_add_none_format(ft, hf_dcerpc_fragment, - next_tvb, ipfd->offset, ipfd->len, - "Frame:%u payload:%u-%u", - ipfd->frame, - ipfd->offset, - ipfd->offset+ipfd->len-1 - ); - } - } - if (ipfd_head->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { - if (check_col(pinfo->cinfo, COL_INFO)) { - col_set_str(pinfo->cinfo, COL_INFO, "[Illegal fragments]"); - } - } - dcerpc_try_handoff (pinfo, tree, dcerpc_tree, - next_tvb, - 0, opnum, TRUE, hdr->drep, &di, - auth_level); - } else { - if (check_col(pinfo->cinfo, COL_INFO)) { - col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]"); - } - } + if (value) { + dcerpc_info di; - } + /* handoff this call */ + di.conv = conv; + di.call_id = hdr->call_id; + di.smb_fid = get_smb_fid(pinfo->private_data); + di.request = FALSE; + di.call_data = value; + + proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum); + if(value->req_frame!=0){ + nstime_t ns; + proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in, + tvb, 0, 0, value->req_frame); + ns.secs= pinfo->fd->abs_secs-value->req_time.secs; + ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs; + if(ns.nsecs<0){ + ns.nsecs+=1000000000; + ns.secs--; } + proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns); } - } + +/*qqq response ok*/ + dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree, + hdr, &di, &auth_info, alloc_hint, + value->rep_frame); + } else + show_stub_data (tvb, offset, dcerpc_tree, &auth_info); } + + /* Decrypt the verifier, if present */ + dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info); } static void -dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree, - proto_tree *tree, e_dce_cn_common_hdr_t *hdr) +dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo, + proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr) { dcerpc_call_value *value = NULL; conversation_t *conv; guint16 ctx_id; - int auth_sz = 0; - int offset = 16; - int auth_level; + guint32 status; guint32 alloc_hint; + dcerpc_auth_info auth_info; offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, hf_dcerpc_cn_alloc_hint, &alloc_hint); @@ -1710,22 +2713,29 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, hf_dcerpc_cn_ctx_id, &ctx_id); - if (check_col (pinfo->cinfo, COL_INFO)) { - col_add_fstr (pinfo->cinfo, COL_INFO, "Response: call_id: %d ctx_id:%d", - hdr->call_id, ctx_id); - } - offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, hf_dcerpc_cn_cancel_count, NULL); /* padding */ offset++; + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep, + hf_dcerpc_cn_status, &status); + + if (check_col (pinfo->cinfo, COL_INFO)) { + col_append_fstr (pinfo->cinfo, COL_INFO, + " ctx_id: %u status: %s", ctx_id, + val_to_str(status, reject_status_vals, + "Unknown (0x%08x)")); + } + + /* padding */ + offset += 4; + /* * XXX - what if this was set when the connection was set up, * and we just have a security context? */ - auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, - &auth_level); + dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info); conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); @@ -1758,17 +2768,10 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num); if (value) { - int length, reported_length, stub_length; + int length, reported_length, stub_length; dcerpc_info di; /* handoff this call */ - length = tvb_length_remaining(tvb, offset); - reported_length = tvb_reported_length_remaining(tvb, offset); - stub_length = hdr->frag_len - offset - auth_sz; - if (length > stub_length) - length = stub_length; - if (reported_length > stub_length) - reported_length = stub_length; di.conv = conv; di.call_id = hdr->call_id; di.smb_fid = get_smb_fid(pinfo->private_data); @@ -1777,140 +2780,162 @@ dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tr proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum); if(value->req_frame!=0){ - proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in, + nstime_t ns; + proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in, tvb, 0, 0, value->req_frame); + ns.secs= pinfo->fd->abs_secs-value->req_time.secs; + ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs; + if(ns.nsecs<0){ + ns.nsecs+=1000000000; + ns.secs--; + } + proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns); } - /* If we dont have reassembly enabled, or this packet contains the - entire PDU, just call the handoff directly */ - if( (!dcerpc_reassemble) - || ((hdr->flags&0x03)==0x03) ){ - if(hdr->flags&0x01){ - dcerpc_try_handoff (pinfo, tree, dcerpc_tree, - tvb_new_subset (tvb, offset, length, - reported_length), - 0, value->opnum, FALSE, hdr->drep, &di, - auth_level); + length = tvb_length_remaining(tvb, offset); + reported_length = tvb_reported_length_remaining(tvb, offset); + stub_length = hdr->frag_len - offset - auth_info.auth_size; + if (length > stub_length) + length = stub_length; + if (reported_length > stub_length) + reported_length = stub_length; + + /* If we don't have reassembly enabled, or this packet contains + the entire PDU, or if we don't have all the data in this + fragment, just call the handoff directly if this is the + first fragment or the PDU isn't fragmented. */ + if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) || + !tvb_bytes_exist(tvb, offset, stub_length) ){ + if(hdr->flags&PFC_FIRST_FRAG){ + /* First fragment, possibly the only fragment */ + /* + * XXX - should there be a third routine for each + * function in an RPC subdissector, to handle + * fault responses? The DCE RPC 1.1 spec says + * three's "stub data" here, which I infer means + * that it's protocol-specific and call-specific. + * + * It should probably get passed the status code + * as well, as that might be protocol-specific. + */ + if (dcerpc_tree) { + if (stub_length > 0) { + proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length, + "Fault stub data (%d byte%s)", + stub_length, + plurality(stub_length, "", "s")); + } + } } else { + /* PDU is fragmented and this isn't the first fragment */ if (check_col(pinfo->cinfo, COL_INFO)) { - col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]"); + col_append_fstr(pinfo->cinfo, COL_INFO, + " [DCE/RPC fragment]"); } - } - } else if(dcerpc_reassemble){ - /*OK we need to do reassembly */ - /* handle first fragment */ - if((hdr->flags&0x03)==0x01){ /* FIRST fragment */ - if( (!pinfo->fd->flags.visited) && value->rep_frame ){ - fragment_add(tvb, offset, pinfo, value->rep_frame, - dcerpc_reassemble_table, - 0, - length, - TRUE); - fragment_set_tot_len(pinfo, value->rep_frame, - dcerpc_reassemble_table, alloc_hint); + if (dcerpc_tree) { + if (stub_length > 0) { + proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length, + "Fragment data (%d byte%s)", + stub_length, + plurality(stub_length, "", "s")); + } } - if (check_col(pinfo->cinfo, COL_INFO)) { - col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]"); + } + } else { + /* Reassembly is enabled, the PDU is fragmented, and + we have all the data in the fragment; the first two + of those mean we should attempt reassembly, and the + third means we can attempt reassembly. */ + if (dcerpc_tree) { + if (length > 0) { + proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length, + "Fragment data (%d byte%s)", + stub_length, + plurality(stub_length, "", "s")); } } - if((hdr->flags&0x03)==0x00){ /* MIDDLE fragment(s) */ + if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */ if( (!pinfo->fd->flags.visited) && value->rep_frame ){ - guint32 tot_len; - tot_len = fragment_get_tot_len(pinfo, value->rep_frame, - dcerpc_reassemble_table); fragment_add(tvb, offset, pinfo, value->rep_frame, - dcerpc_reassemble_table, - tot_len-alloc_hint, - length, + dcerpc_co_reassemble_table, + 0, + stub_length, TRUE); + fragment_set_tot_len(pinfo, value->rep_frame, + dcerpc_co_reassemble_table, alloc_hint); } if (check_col(pinfo->cinfo, COL_INFO)) { - col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]"); + col_append_fstr(pinfo->cinfo, COL_INFO, + " [DCE/RPC fragment]"); } - } - if((hdr->flags&0x03)==0x02){ /* LAST fragment */ + } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */ if( value->rep_frame ){ - fragment_data *ipfd_head; + fragment_data *fd_head; guint32 tot_len; + tot_len = fragment_get_tot_len(pinfo, value->rep_frame, - dcerpc_reassemble_table); - ipfd_head = fragment_add(tvb, offset, pinfo, + dcerpc_co_reassemble_table); + fd_head = fragment_add(tvb, offset, pinfo, value->rep_frame, - dcerpc_reassemble_table, + dcerpc_co_reassemble_table, tot_len-alloc_hint, - length, + stub_length, TRUE); - if(ipfd_head){ - fragment_data *ipfd; - proto_tree *ft=NULL; - proto_item *fi=NULL; + if(fd_head){ + /* We completed reassembly */ tvbuff_t *next_tvb; - next_tvb = tvb_new_real_data(ipfd_head->data, ipfd_head->datalen, ipfd_head->datalen); + next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen); tvb_set_child_real_data_tvbuff(tvb, next_tvb); add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC"); - pinfo->fragmented=FALSE; - fi = proto_tree_add_item(dcerpc_tree, hf_dcerpc_fragments, next_tvb, 0, -1, FALSE); - ft = proto_item_add_subtree(fi, ett_dcerpc_fragments); - for (ipfd=ipfd_head->next; ipfd; ipfd=ipfd->next){ - if (ipfd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { - proto_tree *fet=NULL; - proto_item *fei=NULL; - int hf; - - if (ipfd->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { - hf = hf_dcerpc_fragment_error; - } else { - hf = hf_dcerpc_fragment; - } - fei = proto_tree_add_none_format(ft, hf, - next_tvb, ipfd->offset, ipfd->len, - "Frame:%u payload:%u-%u", - ipfd->frame, - ipfd->offset, - ipfd->offset+ipfd->len-1); - fet = proto_item_add_subtree(fei, ett_dcerpc_fragment); - if (ipfd->flags&FD_OVERLAP) { - proto_tree_add_boolean(fet, hf_dcerpc_fragment_overlap, next_tvb, 0, 0, TRUE); - } - if (ipfd->flags&FD_OVERLAPCONFLICT) { - proto_tree_add_boolean(fet, hf_dcerpc_fragment_overlap_conflict, next_tvb, 0, 0, TRUE); - } - if (ipfd->flags&FD_MULTIPLETAILS) { - proto_tree_add_boolean(fet, hf_dcerpc_fragment_multiple_tails, next_tvb, 0, 0, TRUE); - } - if (ipfd->flags&FD_TOOLONGFRAGMENT) { - proto_tree_add_boolean(fet, hf_dcerpc_fragment_too_long_fragment, next_tvb, 0, 0, TRUE); - } - } else { - proto_tree_add_none_format(ft, hf_dcerpc_fragment, - next_tvb, ipfd->offset, ipfd->len, - "Frame:%u payload:%u-%u", - ipfd->frame, - ipfd->offset, - ipfd->offset+ipfd->len-1 - ); - } - } - if (ipfd_head->flags & (FD_OVERLAPCONFLICT|FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) { - if (check_col(pinfo->cinfo, COL_INFO)) { - col_set_str(pinfo->cinfo, COL_INFO, "[Illegal fragments]"); + show_fragment_tree(fd_head, &dcerpc_frag_items, + dcerpc_tree, pinfo, next_tvb); + + /* + * XXX - should there be a third routine for each + * function in an RPC subdissector, to handle + * fault responses? The DCE RPC 1.1 spec says + * three's "stub data" here, which I infer means + * that it's protocol-specific and call-specific. + * + * It should probably get passed the status code + * as well, as that might be protocol-specific. + */ + if (dcerpc_tree) { + if (length > 0) { + proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length, + "Fault stub data (%d byte%s)", + stub_length, + plurality(stub_length, "", "s")); } } - dcerpc_try_handoff (pinfo, tree, dcerpc_tree, - next_tvb, - 0, value->opnum, FALSE, hdr->drep, &di, - auth_level); } else { + /* Reassembly not complete - some fragments + are missing */ if (check_col(pinfo->cinfo, COL_INFO)) { - col_add_fstr(pinfo->cinfo, COL_INFO, "[DCE/RPC fragment]"); + col_append_fstr(pinfo->cinfo, COL_INFO, + " [DCE/RPC fragment]"); } } } + } else { /* MIDDLE fragment(s) */ + if( (!pinfo->fd->flags.visited) && value->rep_frame ){ + guint32 tot_len; + tot_len = fragment_get_tot_len(pinfo, value->rep_frame, + dcerpc_co_reassemble_table); + fragment_add(tvb, offset, pinfo, value->rep_frame, + dcerpc_co_reassemble_table, + tot_len-alloc_hint, + stub_length, + TRUE); + } + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, + " [DCE/RPC fragment]"); + } } } - } } } @@ -1931,6 +2956,7 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *cn_flags_tree = NULL; proto_tree *drep_tree = NULL; e_dce_cn_common_hdr_t hdr; + dcerpc_auth_info auth_info; /* * when done over nbt, dcerpc requests are padded with 4 bytes of null @@ -1968,11 +2994,6 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, if (hdr.ptype > 19) return -1; - if (check_col (pinfo->cinfo, COL_PROTOCOL)) - col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC"); - if (check_col (pinfo->cinfo, COL_INFO)) - col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr); - hdr.flags = tvb_get_guint8 (tvb, offset++); tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep)); offset += sizeof (hdr.drep); @@ -1984,15 +3005,21 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep); offset += 4; - offset = start_offset; if (can_desegment && pinfo->can_desegment - && hdr.frag_len > tvb_length_remaining (tvb, offset)) { - pinfo->desegment_offset = offset; - pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, offset); + && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) { + pinfo->desegment_offset = start_offset; + pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset); return 0; /* desegmentation required */ } + if (check_col (pinfo->cinfo, COL_PROTOCOL)) + col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC"); + if (check_col (pinfo->cinfo, COL_INFO)) + col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u", + pckt_vals[hdr.ptype].strptr, hdr.call_id); + if (tree) { + offset = start_offset; ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE); if (ti) { dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc); @@ -2002,15 +3029,15 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype); tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags); cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags); - if (cn_flags_tree) { - proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags); - proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags); - proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags); - proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags); - proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags); - proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags); - proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags); + if (cn_flags_tree) { proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags); + proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags); + proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags); + proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags); + proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags); + proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags); + proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags); + proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags); } offset++; @@ -2033,32 +3060,65 @@ dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo, offset += 4; } - /* * Packet type specific stuff is next. */ switch (hdr.ptype) { case PDU_BIND: case PDU_ALTER: - dissect_dcerpc_cn_bind (tvb, pinfo, dcerpc_tree, &hdr); + dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr); break; case PDU_BIND_ACK: case PDU_ALTER_ACK: - dissect_dcerpc_cn_bind_ack (tvb, pinfo, dcerpc_tree, &hdr); + dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr); + break; + + case PDU_AUTH3: + /* + * Nothing after the common header other than credentials. + */ + dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, TRUE, + &auth_info); break; case PDU_REQ: - dissect_dcerpc_cn_rqst (tvb, pinfo, dcerpc_tree, tree, &hdr); + dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr); break; case PDU_RESP: - dissect_dcerpc_cn_resp (tvb, pinfo, dcerpc_tree, tree, &hdr); + dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr); + break; + + case PDU_FAULT: + dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr); + break; + + case PDU_BIND_NAK: + dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr); + break; + + case PDU_CO_CANCEL: + case PDU_ORPHANED: + /* + * Nothing after the common header other than an authentication + * verifier. + */ + dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE, + &auth_info); + break; + + case PDU_SHUTDOWN: + /* + * Nothing after the common header, not even an authentication + * verifier. + */ break; default: /* might as well dissect the auth info */ - dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, NULL); + dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE, + &auth_info); break; } return hdr.frag_len + padding; @@ -2134,10 +3194,12 @@ dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } static void -dissect_dcerpc_dg_auth (tvbuff_t *tvb, proto_tree *dcerpc_tree, +dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree, e_dce_dg_common_hdr_t *hdr, int *auth_level_p) { - int offset; + proto_item *ti = NULL; + proto_tree *auth_tree = NULL; + guint8 protection_level; /* * Initially set "*auth_level_p" to -1 to indicate that we haven't @@ -2154,11 +3216,363 @@ dissect_dcerpc_dg_auth (tvbuff_t *tvb, proto_tree *dcerpc_tree, * If the full packet is here, and there's data past the end of the * packet body, then dissect the auth info. */ - if (tvb_length (tvb) >= hdr->frag_len) { - offset = hdr->frag_len; - - proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Auth data"); + offset += hdr->frag_len; + if (tvb_length_remaining(tvb, offset) > 0) { + switch (hdr->auth_proto) { + + case DCE_C_RPC_AUTHN_PROTOCOL_KRB5: + ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier"); + auth_tree = proto_item_add_subtree (ti, ett_decrpc_krb5_auth_verf); + protection_level = tvb_get_guint8 (tvb, offset); + if (auth_level_p != NULL) + *auth_level_p = protection_level; + proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level); + offset++; + proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE); + offset++; + if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) + offset += 6; /* 6 bytes of padding */ + else + offset += 2; /* 6 bytes of padding */ + proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE); + offset += 16; + break; + + default: + proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier"); + break; + } + } +} + +static void +dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *dcerpc_tree, + e_dce_dg_common_hdr_t *hdr) +{ + guint32 version; + + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_cancel_vers, + &version); + + switch (version) { + + case 0: + /* The only version we know about */ + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_cancel_id, + NULL); + offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_server_accepting_cancels, + NULL); + break; + } +} + +static void +dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *dcerpc_tree, + e_dce_dg_common_hdr_t *hdr) +{ + guint32 version; + + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_cancel_vers, + &version); + + switch (version) { + + case 0: + /* The only version we know about */ + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_cancel_id, + NULL); + /* XXX - are NDR booleans 32 bits? */ + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_server_accepting_cancels, + NULL); + break; + } +} + +static void +dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *dcerpc_tree, + e_dce_dg_common_hdr_t *hdr) +{ + guint8 version; + guint16 serial_num; + guint16 selack_len; + guint i; + + offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_fack_vers, + &version); + /* padding */ + offset++; + + switch (version) { + + case 0: /* The only version documented in the DCE RPC 1.1 spec */ + case 1: /* This appears to be the same */ + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_fack_window_size, + NULL); + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_fack_max_tsdu, + NULL); + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_fack_max_frag_size, + NULL); + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_fack_serial_num, + &serial_num); + if (check_col (pinfo->cinfo, COL_INFO)) { + col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u", + serial_num); + } + offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_fack_selack_len, + &selack_len); + for (i = 0; i < selack_len; i++) { + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_fack_selack, + NULL); + } + + break; + } +} + +static void +dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *dcerpc_tree, + e_dce_dg_common_hdr_t *hdr) +{ + guint32 status; + + offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, + hdr->drep, hf_dcerpc_dg_status, + &status); + + if (check_col (pinfo->cinfo, COL_INFO)) { + col_append_fstr (pinfo->cinfo, COL_INFO, + ": status: %s", + val_to_str(status, reject_status_vals, "Unknown (0x%08x)")); + } +} + +static void +dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *dcerpc_tree, proto_tree *tree, + e_dce_dg_common_hdr_t *hdr, dcerpc_info *di) +{ + int length, reported_length, stub_length; + gboolean save_fragmented; + fragment_data *fd_head; + + 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); + stub_length = hdr->frag_len; + if (length > stub_length) + length = stub_length; + if (reported_length > stub_length) + reported_length = stub_length; + + save_fragmented = pinfo->fragmented; + + /* If we don't have reassembly enabled, or this packet contains + the entire PDU, or if this is a short frame (or a frame + not reassembled at a lower layer) that doesn't include all + the data in the fragment, just call the handoff directly if + this is the first fragment or the PDU isn't fragmented. */ + if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) || + !tvb_bytes_exist(tvb, offset, stub_length) ){ + if(hdr->frag_num == 0) { + /* 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); + } else { + /* PDU is fragmented and this isn't the first fragment */ + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]"); + } + if (dcerpc_tree) { + if (length > 0) { + proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length, + "Fragment data (%d byte%s)", + stub_length, + plurality(stub_length, "", "s")); + } + } + } + } else { + /* Reassembly is enabled, the PDU is fragmented, and + we have all the data in the fragment; the first two + of those mean we should attempt reassembly, and the + third means we can attempt reassembly. */ + if (dcerpc_tree) { + if (length > 0) { + proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length, + "Fragment data (%d byte%s)", stub_length, + plurality(stub_length, "", "s")); + } + } + + fd_head = fragment_add_seq(tvb, offset, pinfo, + hdr->seqnum, dcerpc_cl_reassemble_table, + hdr->frag_num, stub_length, + !(hdr->flags1 & PFCL1_LASTFRAG)); + if (fd_head != NULL) { + /* We completed reassembly */ + tvbuff_t *next_tvb; + + next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len); + tvb_set_child_real_data_tvbuff(tvb, next_tvb); + add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC"); + show_fragment_seq_tree(fd_head, &dcerpc_frag_items, + dcerpc_tree, pinfo, next_tvb); + + /* + * XXX - authentication info? + */ + pinfo->fragmented = FALSE; + dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb, + 0, hdr->drep, di, NULL); + } else { + /* Reassembly isn't completed yet */ + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]"); + } + } + } + pinfo->fragmented = save_fragmented; +} + +static void +dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *dcerpc_tree, proto_tree *tree, + e_dce_dg_common_hdr_t *hdr, conversation_t *conv) +{ + dcerpc_info di; + dcerpc_call_value *value, v; + + if(!(pinfo->fd->flags.visited)){ + dcerpc_call_value *call_value; + dcerpc_call_key *call_key; + + call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk); + call_key->conv=conv; + call_key->call_id=hdr->seqnum; + call_key->smb_fid=get_smb_fid(pinfo->private_data); + + call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk); + call_value->uuid = hdr->if_id; + call_value->ver = hdr->if_ver; + call_value->opnum = hdr->opnum; + call_value->req_frame=pinfo->fd->num; + call_value->req_time.secs=pinfo->fd->abs_secs; + call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000; + call_value->rep_frame=0; + call_value->max_ptr=0; + call_value->private_data = NULL; + g_hash_table_insert (dcerpc_calls, call_key, call_value); + + g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value); + } + + value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num); + if (!value) { + v.uuid = hdr->if_id; + v.ver = hdr->if_ver; + v.opnum = hdr->opnum; + v.req_frame = pinfo->fd->num; + v.rep_frame = 0; + v.max_ptr = 0; + v.private_data=NULL; + value = &v; + } + + di.conv = conv; + di.call_id = hdr->seqnum; + di.smb_fid = -1; + di.request = TRUE; + di.call_data = value; + + if(value->rep_frame!=0){ + proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in, + tvb, 0, 0, value->rep_frame); + } + dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di); +} + +static void +dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo, + proto_tree *dcerpc_tree, proto_tree *tree, + e_dce_dg_common_hdr_t *hdr, conversation_t *conv) +{ + dcerpc_info di; + dcerpc_call_value *value, v; + + if(!(pinfo->fd->flags.visited)){ + dcerpc_call_value *call_value; + dcerpc_call_key call_key; + + call_key.conv=conv; + call_key.call_id=hdr->seqnum; + call_key.smb_fid=get_smb_fid(pinfo->private_data); + + if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){ + g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value); + if(call_value->rep_frame==0){ + call_value->rep_frame=pinfo->fd->num; + } + } + } + + value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num); + if (!value) { + v.uuid = hdr->if_id; + v.ver = hdr->if_ver; + v.opnum = hdr->opnum; + v.req_frame=0; + v.rep_frame=pinfo->fd->num; + v.private_data=NULL; + value = &v; + } + + di.conv = conv; + di.call_id = 0; + di.smb_fid = -1; + di.request = FALSE; + di.call_data = value; + + if(value->req_frame!=0){ + nstime_t ns; + proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in, + tvb, 0, 0, value->req_frame); + ns.secs= pinfo->fd->abs_secs-value->req_time.secs; + ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs; + if(ns.nsecs<0){ + ns.nsecs+=1000000000; + ns.secs--; + } + proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns); } + dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di); } /* @@ -2176,6 +3590,9 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) e_dce_dg_common_hdr_t hdr; int offset = 0; conversation_t *conv; + int auth_level; + char uuid_str[DCERPC_UUID_STR_LEN]; + int uuid_str_len; /* * Check if this looks like a CL DCERPC call. All dg packets @@ -2195,7 +3612,7 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) if (check_col (pinfo->cinfo, COL_PROTOCOL)) col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC"); if (check_col (pinfo->cinfo, COL_INFO)) - col_set_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr); + col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr); hdr.flags1 = tvb_get_guint8 (tvb, offset++); hdr.flags2 = tvb_get_guint8 (tvb, offset++); @@ -2232,39 +3649,50 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) if (ti) { dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc); } - offset = 0; - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver); + } + offset = 0; - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype); + if (tree) + proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver); + offset++; + + if (tree) + proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype); + offset++; + if (tree) { tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1); dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1); if (dg_flags1_tree) { - proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1); - proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1); - proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1); - proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1); - proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1); - proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1); - proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1); proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1); + proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1); + proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1); + proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1); + proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1); + proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1); + proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1); + proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1); } - offset++; + } + offset++; + if (tree) { tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2); dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2); if (dg_flags2_tree) { - proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2); - proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2); - proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2); - proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2); - proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2); - proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2); - proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2); proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2); + proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2); + proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2); + proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2); + proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2); + proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2); + proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2); + proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2); } - offset++; + } + offset++; + if (tree) { tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep); drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep); if (drep_tree) { @@ -2272,90 +3700,141 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f); proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]); } - offset += sizeof (hdr.drep); + } + offset += sizeof (hdr.drep); - proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset++, 1, hdr.serial_hi); + if (tree) + proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi); + offset++; + if (tree) { + /* XXX - use "dissect_ndr_uuid_t()"? */ + uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3, + hdr.obj_id.Data4[0], + hdr.obj_id.Data4[1], + hdr.obj_id.Data4[2], + hdr.obj_id.Data4[3], + hdr.obj_id.Data4[4], + hdr.obj_id.Data4[5], + hdr.obj_id.Data4[6], + hdr.obj_id.Data4[7]); + if (uuid_str_len >= DCERPC_UUID_STR_LEN) + memset(uuid_str, 0, DCERPC_UUID_STR_LEN); proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb, - offset, 16, "HMMM", - "Object: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3, - hdr.obj_id.Data4[0], - hdr.obj_id.Data4[1], - hdr.obj_id.Data4[2], - hdr.obj_id.Data4[3], - hdr.obj_id.Data4[4], - hdr.obj_id.Data4[5], - hdr.obj_id.Data4[6], - hdr.obj_id.Data4[7]); - offset += 16; + offset, 16, uuid_str, "Object UUID: %s", uuid_str); + } + offset += 16; + if (tree) { + /* XXX - use "dissect_ndr_uuid_t()"? */ + uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3, + hdr.if_id.Data4[0], + hdr.if_id.Data4[1], + hdr.if_id.Data4[2], + hdr.if_id.Data4[3], + hdr.if_id.Data4[4], + hdr.if_id.Data4[5], + hdr.if_id.Data4[6], + hdr.if_id.Data4[7]); + if (uuid_str_len >= DCERPC_UUID_STR_LEN) + memset(uuid_str, 0, DCERPC_UUID_STR_LEN); proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb, - offset, 16, "HMMM", - "Interface: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3, - hdr.if_id.Data4[0], - hdr.if_id.Data4[1], - hdr.if_id.Data4[2], - hdr.if_id.Data4[3], - hdr.if_id.Data4[4], - hdr.if_id.Data4[5], - hdr.if_id.Data4[6], - hdr.if_id.Data4[7]); - offset += 16; + offset, 16, uuid_str, "Interface: %s", uuid_str); + } + offset += 16; + if (tree) { + /* XXX - use "dissect_ndr_uuid_t()"? */ + uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3, + hdr.act_id.Data4[0], + hdr.act_id.Data4[1], + hdr.act_id.Data4[2], + hdr.act_id.Data4[3], + hdr.act_id.Data4[4], + hdr.act_id.Data4[5], + hdr.act_id.Data4[6], + hdr.act_id.Data4[7]); + if (uuid_str_len >= DCERPC_UUID_STR_LEN) + memset(uuid_str, 0, DCERPC_UUID_STR_LEN); proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb, - offset, 16, "HMMM", - "Activity: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3, - hdr.act_id.Data4[0], - hdr.act_id.Data4[1], - hdr.act_id.Data4[2], - hdr.act_id.Data4[3], - hdr.act_id.Data4[4], - hdr.act_id.Data4[5], - hdr.act_id.Data4[6], - hdr.act_id.Data4[7]); - offset += 16; + offset, 16, uuid_str, "Activity: %s", uuid_str); + } + offset += 16; + if (tree) proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot); - offset += 4; + offset += 4; + if (tree) proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver); - offset += 4; + offset += 4; + if (tree) proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum); - offset += 4; + if (check_col (pinfo->cinfo, COL_INFO)) { + col_append_fstr (pinfo->cinfo, COL_INFO, ": seq_num: %u", hdr.seqnum); + } + offset += 4; + if (tree) proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum); - offset += 2; + offset += 2; + if (tree) proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint); - offset += 2; + offset += 2; + if (tree) proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint); - offset += 2; + offset += 2; + if (tree) proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len); - offset += 2; + offset += 2; + if (tree) proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num); - offset += 2; + if (check_col (pinfo->cinfo, COL_INFO)) { + if (hdr.flags1 & PFCL1_FRAG) { + /* Fragmented - put the fragment number into the Info column */ + col_append_fstr (pinfo->cinfo, COL_INFO, " frag_num: %u", + hdr.frag_num); + } + } + offset += 2; + if (tree) proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto); - offset++; + offset++; + if (tree) proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo); - offset++; + if (check_col (pinfo->cinfo, COL_INFO)) { + if (hdr.flags1 & PFCL1_FRAG) { + /* Fragmented - put the serial number into the Info column */ + col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u", + (hdr.serial_hi << 8) | hdr.serial_lo); + } + } + offset++; + if (tree) { /* - * XXX - for Kerberos, we can get a protection level; if it's + * XXX - for Kerberos, we get a protection level; if it's * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the * stub data. */ - dissect_dcerpc_dg_auth (tvb, dcerpc_tree, &hdr, NULL); + dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr, + &auth_level); } - /* + + /* * keeping track of the conversation shouldn't really be necessary * for connectionless packets, because everything we need to know * to dissect is in the header for each packet. Unfortunately, @@ -2378,117 +3857,54 @@ dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) */ switch (hdr.ptype) { - int length, reported_length, stub_length; - dcerpc_info di; - dcerpc_call_value *value, v; - - case PDU_REQ: - - if(!(pinfo->fd->flags.visited)){ - dcerpc_call_value *call_value; - dcerpc_call_key *call_key; - - call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk); - call_key->conv=conv; - call_key->call_id=hdr.seqnum; - call_key->smb_fid=get_smb_fid(pinfo->private_data); - - call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk); - call_value->uuid = hdr.if_id; - call_value->ver = hdr.if_ver; - call_value->opnum = hdr.opnum; - call_value->req_frame=pinfo->fd->num; - call_value->rep_frame=0; - call_value->max_ptr=0; - call_value->private_data = NULL; - g_hash_table_insert (dcerpc_calls, call_key, call_value); - - g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value); - } - value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num); - if (!value) { - v.uuid = hdr.if_id; - v.ver = hdr.if_ver; - v.opnum = hdr.opnum; - v.req_frame = pinfo->fd->num; - v.rep_frame = 0; - v.max_ptr = 0; - v.private_data=NULL; - value = &v; - } - - length = tvb_length_remaining (tvb, offset); - reported_length = tvb_reported_length_remaining (tvb, offset); - stub_length = hdr.frag_len; - if (length > stub_length) - length = stub_length; - if (reported_length > stub_length) - reported_length = stub_length; - - di.conv = conv; - di.call_id = hdr.seqnum; - di.smb_fid = -1; - di.request = TRUE; - di.call_data = value; + case PDU_CANCEL_ACK: + /* Body is optional */ + /* XXX - we assume "frag_len" is the length of the body */ + if (hdr.frag_len != 0) + dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr); + break; + case PDU_CL_CANCEL: /* - * XXX - authentication level? + * XXX - The DCE RPC 1.1 spec doesn't say the body is optional, + * but in at least one capture none of the Cl_cancel PDUs had a + * body. */ - dcerpc_try_handoff (pinfo, tree, dcerpc_tree, - tvb_new_subset (tvb, offset, length, - reported_length), - 0, hdr.opnum, TRUE, hdr.drep, &di, 0); + /* XXX - we assume "frag_len" is the length of the body */ + if (hdr.frag_len != 0) + dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr); break; - case PDU_RESP: - if(!(pinfo->fd->flags.visited)){ - dcerpc_call_value *call_value; - dcerpc_call_key call_key; - call_key.conv=conv; - call_key.call_id=hdr.seqnum; - call_key.smb_fid=get_smb_fid(pinfo->private_data); + case PDU_NOCALL: + /* Body is optional; if present, it's the same as PDU_FACK */ + /* XXX - we assume "frag_len" is the length of the body */ + if (hdr.frag_len != 0) + dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr); + break; - if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){ - g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value); - if(call_value->rep_frame==0){ - call_value->rep_frame=pinfo->fd->num; - } - } - } + case PDU_FACK: + dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr); + break; - value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num); - if (!value) { - v.uuid = hdr.if_id; - v.ver = hdr.if_ver; - v.opnum = hdr.opnum; - v.req_frame=0; - v.rep_frame=pinfo->fd->num; - v.private_data=NULL; - value = &v; - } + case PDU_REJECT: + case PDU_FAULT: + dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr); + break; - length = tvb_length_remaining (tvb, offset); - reported_length = tvb_reported_length_remaining (tvb, offset); - stub_length = hdr.frag_len; - if (length > stub_length) - length = stub_length; - if (reported_length > stub_length) - reported_length = stub_length; - - di.conv = conv; - di.call_id = 0; - di.smb_fid = -1; - di.request = FALSE; - di.call_data = value; + case PDU_REQ: + dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv); + break; - /* - * XXX - authentication level? - */ - dcerpc_try_handoff (pinfo, tree, dcerpc_tree, - tvb_new_subset (tvb, offset, length, - reported_length), - 0, value->opnum, FALSE, hdr.drep, &di, 0); + case PDU_RESP: + dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv); + break; + + /* these requests have no body */ + case PDU_ACK: + case PDU_PING: + case PDU_WORKING: + default: break; } @@ -2551,12 +3967,12 @@ proto_register_dcerpc (void) { static hf_register_info hf[] = { { &hf_dcerpc_request_in, - { "Request in", "dcerpc.request_in", FT_UINT32, BASE_DEC, + { "Request in", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE, NULL, 0, "This packet is a response to the packet in this frame", HFILL }}, - { &hf_dcerpc_response_in, - { "Response in", "dcerpc.response_in", FT_UINT32, BASE_DEC, + { &hf_dcerpc_response_in, + { "Response in", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE, NULL, 0, "The response to this packet is in this packet", HFILL }}, - { &hf_dcerpc_referent_id, + { &hf_dcerpc_referent_id, { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX, NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }}, { &hf_dcerpc_ver, @@ -2564,25 +3980,25 @@ proto_register_dcerpc (void) { &hf_dcerpc_ver_minor, { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_packet_type, - { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_HEX, VALS (pckt_vals), 0x0, "", HFILL }}, + { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }}, { &hf_dcerpc_cn_flags, { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_cn_flags_first_frag, - { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x1, "", HFILL }}, + { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }}, { &hf_dcerpc_cn_flags_last_frag, - { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x2, "", HFILL }}, + { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }}, { &hf_dcerpc_cn_flags_cancel_pending, - { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x4, "", HFILL }}, + { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }}, { &hf_dcerpc_cn_flags_reserved, - { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x8, "", HFILL }}, + { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }}, { &hf_dcerpc_cn_flags_mpx, - { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }}, + { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }}, { &hf_dcerpc_cn_flags_dne, - { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }}, + { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }}, { &hf_dcerpc_cn_flags_maybe, - { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }}, + { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }}, { &hf_dcerpc_cn_flags_object, - { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }}, + { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }}, { &hf_dcerpc_drep, { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_drep_byteorder, @@ -2628,15 +4044,25 @@ proto_register_dcerpc (void) { &hf_dcerpc_cn_num_results, { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_cn_ack_result, - { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, + { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }}, { &hf_dcerpc_cn_ack_reason, - { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, + { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }}, { &hf_dcerpc_cn_ack_trans_id, { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_cn_ack_trans_ver, { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_dcerpc_cn_reject_reason, + { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }}, + { &hf_dcerpc_cn_num_protocols, + { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_dcerpc_cn_protocol_ver_major, + { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_dcerpc_cn_protocol_ver_minor, + { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_cn_cancel_count, { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_dcerpc_cn_status, + { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }}, { &hf_dcerpc_auth_type, { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }}, { &hf_dcerpc_auth_level, @@ -2650,39 +4076,39 @@ proto_register_dcerpc (void) { &hf_dcerpc_dg_flags1, { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_dg_flags1_rsrvd_01, - { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }}, + { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }}, { &hf_dcerpc_dg_flags1_last_frag, - { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }}, + { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }}, { &hf_dcerpc_dg_flags1_frag, - { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }}, + { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }}, { &hf_dcerpc_dg_flags1_nofack, - { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }}, + { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }}, { &hf_dcerpc_dg_flags1_maybe, - { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }}, + { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }}, { &hf_dcerpc_dg_flags1_idempotent, - { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }}, + { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }}, { &hf_dcerpc_dg_flags1_broadcast, - { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }}, + { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }}, { &hf_dcerpc_dg_flags1_rsrvd_80, - { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }}, + { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }}, { &hf_dcerpc_dg_flags2, { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_dg_flags2_rsrvd_01, - { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x01, "", HFILL }}, + { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }}, { &hf_dcerpc_dg_flags2_cancel_pending, - { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x02, "", HFILL }}, + { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }}, { &hf_dcerpc_dg_flags2_rsrvd_04, - { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x04, "", HFILL }}, + { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }}, { &hf_dcerpc_dg_flags2_rsrvd_08, - { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x08, "", HFILL }}, + { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }}, { &hf_dcerpc_dg_flags2_rsrvd_10, - { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x10, "", HFILL }}, + { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }}, { &hf_dcerpc_dg_flags2_rsrvd_20, - { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x20, "", HFILL }}, + { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }}, { &hf_dcerpc_dg_flags2_rsrvd_40, - { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x40, "", HFILL }}, + { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }}, { &hf_dcerpc_dg_flags2_rsrvd_80, - { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), 0x80, "", HFILL }}, + { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }}, { &hf_dcerpc_dg_serial_lo, { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_dg_serial_hi, @@ -2698,19 +4124,59 @@ proto_register_dcerpc (void) { &hf_dcerpc_dg_auth_proto, { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }}, { &hf_dcerpc_dg_seqnum, - { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }}, + { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_dg_server_boot, { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_dg_if_ver, { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_dcerpc_krb5_av_prot_level, + { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }}, + { &hf_dcerpc_krb5_av_key_vers_num, + { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }}, + { &hf_dcerpc_krb5_av_key_auth_verifier, + { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_obj_id, { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_dg_if_id, { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_dg_act_id, - { "Activitiy", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}, + { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_opnum, { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, + + { &hf_dcerpc_dg_cancel_vers, + { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, + + { &hf_dcerpc_dg_cancel_id, + { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, + + { &hf_dcerpc_dg_server_accepting_cancels, + { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }}, + + { &hf_dcerpc_dg_fack_vers, + { "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 }}, + + { &hf_dcerpc_dg_fack_max_tsdu, + { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, + + { &hf_dcerpc_dg_fack_max_frag_size, + { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }}, + + { &hf_dcerpc_dg_fack_serial_num, + { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, + + { &hf_dcerpc_dg_fack_selack_len, + { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, + + { &hf_dcerpc_dg_fack_selack, + { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }}, + + { &hf_dcerpc_dg_status, + { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }}, + { &hf_dcerpc_array_max_count, { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }}, @@ -2720,15 +4186,18 @@ proto_register_dcerpc (void) { &hf_dcerpc_array_actual_count, { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }}, + { &hf_dcerpc_array_buffer, + { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }}, + { &hf_dcerpc_op, { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_dcerpc_fragments, - { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE, + { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE, NULL, 0x0, "DCE/RPC Fragments", HFILL }}, { &hf_dcerpc_fragment, - { "DCE/RPC Fragment", "dcerpc.fragment", FT_NONE, BASE_NONE, + { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "DCE/RPC Fragment", HFILL }}, { &hf_dcerpc_fragment_overlap, @@ -2744,9 +4213,29 @@ proto_register_dcerpc (void) { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }}, { &hf_dcerpc_fragment_error, - { "Defragmentation error", "dcerpc.fragment.error", FT_NONE, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }}, - - }; + { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }}, + + { &hf_dcerpc_time, + { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "Time between Request and Reply for DCE-RPC calls", HFILL }}, + { &hf_dcerpc_reassembled_in, + { "This PDU is reassembled in", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "The DCE/RPC PDU is completely reassembled in this frame", HFILL }}, + { &hf_dcerpc_sec_chan, + { "Verifier", "verifier", FT_NONE, BASE_NONE, NULL, 0x0, "Verifier", + HFILL }}, + { &hf_dcerpc_sec_chan_sig, + { "Signature", "dcerpc.sec_chan.sig", FT_BYTES, BASE_HEX, NULL, + 0x0, "Signature", HFILL }}, + { &hf_dcerpc_sec_chan_unk, + { "Unknown", "dcerpc.sec_chan.unk", FT_BYTES, BASE_HEX, NULL, + 0x0, "Unknown", HFILL }}, + { &hf_dcerpc_sec_chan_seq, + { "Sequence No", "dcerpc.sec_chan.seq", FT_BYTES, BASE_HEX, NULL, + 0x0, "Sequence No", HFILL }}, + { &hf_dcerpc_sec_chan_nonce, + { "Nonce", "dcerpc.sec_chan.nonce", FT_BYTES, BASE_HEX, NULL, + 0x0, "Nonce", HFILL }}, + + }; static gint *ett[] = { &ett_dcerpc, &ett_dcerpc_cn_flags, @@ -2754,8 +4243,11 @@ proto_register_dcerpc (void) &ett_dcerpc_dg_flags1, &ett_dcerpc_dg_flags2, &ett_dcerpc_pointer_data, + &ett_dcerpc_string, &ett_dcerpc_fragments, &ett_dcerpc_fragment, + &ett_decrpc_krb5_auth_verf, + &ett_sec_chan, }; module_t *dcerpc_module; @@ -2776,6 +4268,7 @@ proto_register_dcerpc (void) &dcerpc_reassemble); register_init_routine(dcerpc_reassemble_init); dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal); + dcerpc_tap=register_tap("dcerpc"); } void @@ -2785,4 +4278,10 @@ proto_reg_handoff_dcerpc (void) heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc); heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc); heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc); + ntlmssp_handle = find_dissector("ntlmssp"); + ntlmssp_verf_handle = find_dissector("ntlmssp_verf"); + ntlmssp_enc_payload_handle = find_dissector("ntlmssp_encrypted_payload"); + gssapi_handle = find_dissector("gssapi"); + gssapi_verf_handle = find_dissector("gssapi_verf"); + dcerpc_smb_init(proto_dcerpc); }