2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas@webspan.net>
5 * $Id: packet-dcerpc.c,v 1.133 2003/06/26 04:30:31 tpot Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #include <epan/packet.h>
35 #include "packet-dcerpc.h"
36 #include <epan/conversation.h>
38 #include "reassemble.h"
40 #include "packet-frame.h"
41 #include "packet-ntlmssp.h"
42 #include "packet-dcerpc-nt.h"
44 static int dcerpc_tap = -1;
46 static const value_string pckt_vals[] = {
47 { PDU_REQ, "Request"},
49 { PDU_RESP, "Response"},
50 { PDU_FAULT, "Fault"},
51 { PDU_WORKING, "Working"},
52 { PDU_NOCALL, "Nocall"},
53 { PDU_REJECT, "Reject"},
55 { PDU_CL_CANCEL, "Cl_cancel"},
57 { PDU_CANCEL_ACK, "Cancel_ack"},
59 { PDU_BIND_ACK, "Bind_ack"},
60 { PDU_BIND_NAK, "Bind_nak"},
61 { PDU_ALTER, "Alter_context"},
62 { PDU_ALTER_ACK, "Alter_context_resp"},
63 { PDU_AUTH3, "AUTH3"},
64 { PDU_SHUTDOWN, "Shutdown"},
65 { PDU_CO_CANCEL, "Co_cancel"},
66 { PDU_ORPHANED, "Orphaned"},
70 static const value_string drep_byteorder_vals[] = {
72 { 1, "Little-endian" },
76 static const value_string drep_character_vals[] = {
82 #define DCE_RPC_DREP_FP_IEEE 0
83 #define DCE_RPC_DREP_FP_VAX 1
84 #define DCE_RPC_DREP_FP_CRAY 2
85 #define DCE_RPC_DREP_FP_IBM 3
87 static const value_string drep_fp_vals[] = {
88 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
89 { DCE_RPC_DREP_FP_VAX, "VAX" },
90 { DCE_RPC_DREP_FP_CRAY, "Cray" },
91 { DCE_RPC_DREP_FP_IBM, "IBM" },
96 * Authentication services.
98 #define DCE_C_RPC_AUTHN_PROTOCOL_NONE 0
99 #define DCE_C_RPC_AUTHN_PROTOCOL_KRB5 1
100 #define DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO 9
101 #define DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP 10
102 #define DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN 68
104 static const value_string authn_protocol_vals[] = {
105 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
106 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
107 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
108 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
109 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN,"NETLOGON Secure Channel" },
116 #define DCE_C_AUTHN_LEVEL_NONE 1
117 #define DCE_C_AUTHN_LEVEL_CONNECT 2
118 #define DCE_C_AUTHN_LEVEL_CALL 3
119 #define DCE_C_AUTHN_LEVEL_PKT 4
120 #define DCE_C_AUTHN_LEVEL_PKT_INTEGRITY 5
121 #define DCE_C_AUTHN_LEVEL_PKT_PRIVACY 6
123 static const value_string authn_level_vals[] = {
124 { DCE_C_AUTHN_LEVEL_NONE, "None" },
125 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
126 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
127 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
128 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
129 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
134 * Flag bits in first flag field in connectionless PDU header.
136 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
137 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
138 * fragment of a multi-PDU
140 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
141 a multi-PDU transmission */
142 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
143 * requested to send a `fack' PDU
144 * for the fragment */
145 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
147 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
149 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
151 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
154 * Flag bits in second flag field in connectionless PDU header.
156 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
157 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
158 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
159 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
160 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
161 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
162 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
163 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
166 * Flag bits in connection-oriented PDU header.
168 #define PFC_FIRST_FRAG 0x01 /* First fragment */
169 #define PFC_LAST_FRAG 0x02 /* Last fragment */
170 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
171 #define PFC_RESERVED_1 0x08
172 #define PFC_CONC_MPX 0x10 /* suports concurrent multiplexing
173 * of a single connection. */
174 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
175 * if true, guaranteed call did not
177 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
178 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
179 * was specified in the handle, and
180 * is present in the optional object
181 * field. If false, the object field
185 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
186 * it's not fragmented (i.e., this is both the first *and* last fragment),
187 * and FALSE otherwise.
189 #define PFC_NOT_FRAGMENTED(hdr) \
190 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG))==(PFC_FIRST_FRAG|PFC_LAST_FRAG))
193 * Presentation context negotiation result.
195 static const value_string p_cont_result_vals[] = {
197 { 1, "User rejection" },
198 { 2, "Provider rejection" },
203 * Presentation context negotiation rejection reasons.
205 static const value_string p_provider_reason_vals[] = {
206 { 0, "Reason not specified" },
207 { 1, "Abstract syntax not supported" },
208 { 2, "Proposed transfer syntaxes not supported" },
209 { 3, "Local limit exceeded" },
216 #define REASON_NOT_SPECIFIED 0
217 #define TEMPORARY_CONGESTION 1
218 #define LOCAL_LIMIT_EXCEEDED 2
219 #define CALLED_PADDR_UNKNOWN 3 /* not used */
220 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
221 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
222 #define USER_DATA_NOT_READABLE 6 /* not used */
223 #define NO_PSAP_AVAILABLE 7 /* not used */
225 static const value_string reject_reason_vals[] = {
226 { REASON_NOT_SPECIFIED, "Reason not specified" },
227 { TEMPORARY_CONGESTION, "Temporary congestion" },
228 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
229 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
230 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
231 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
232 { USER_DATA_NOT_READABLE, "User data not readable" },
233 { NO_PSAP_AVAILABLE, "No PSAP available" },
238 * Reject status codes.
240 static const value_string reject_status_vals[] = {
241 { 0, "Stub-defined exception" },
242 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
243 { 0x1c000002, "nca_s_fault_addr_error" },
244 { 0x1c000003, "nca_s_fault_fp_div_zero" },
245 { 0x1c000004, "nca_s_fault_fp_underflow" },
246 { 0x1c000005, "nca_s_fault_fp_overflow" },
247 { 0x1c000006, "nca_s_fault_invalid_tag" },
248 { 0x1c000007, "nca_s_fault_invalid_bound" },
249 { 0x1c000008, "nca_rpc_version_mismatch" },
250 { 0x1c000009, "nca_unspec_reject" },
251 { 0x1c00000a, "nca_s_bad_actid" },
252 { 0x1c00000b, "nca_who_are_you_failed" },
253 { 0x1c00000c, "nca_manager_not_entered" },
254 { 0x1c00000d, "nca_s_fault_cancel" },
255 { 0x1c00000e, "nca_s_fault_ill_inst" },
256 { 0x1c00000f, "nca_s_fault_fp_error" },
257 { 0x1c000010, "nca_s_fault_int_overflow" },
258 { 0x1c000014, "nca_s_fault_pipe_empty" },
259 { 0x1c000015, "nca_s_fault_pipe_closed" },
260 { 0x1c000016, "nca_s_fault_pipe_order" },
261 { 0x1c000017, "nca_s_fault_pipe_discipline" },
262 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
263 { 0x1c000019, "nca_s_fault_pipe_memory" },
264 { 0x1c00001a, "nca_s_fault_context_mismatch" },
265 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
266 { 0x1c00001c, "nca_invalid_pres_context_id" },
267 { 0x1c00001d, "nca_unsupported_authn_level" },
268 { 0x1c00001f, "nca_invalid_checksum" },
269 { 0x1c000020, "nca_invalid_crc" },
270 { 0x1c000021, "ncs_s_fault_user_defined" },
271 { 0x1c000022, "nca_s_fault_tx_open_failed" },
272 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
273 { 0x1c000024, "nca_s_fault_object_not_found" },
274 { 0x1c000025, "nca_s_fault_no_client_stub" },
275 { 0x1c010002, "nca_op_rng_error" },
276 { 0x1c010003, "nca_unk_if"},
277 { 0x1c010006, "nca_wrong_boot_time" },
278 { 0x1c010009, "nca_s_you_crashed" },
279 { 0x1c01000b, "nca_proto_error" },
280 { 0x1c010013, "nca_out_args_too_big" },
281 { 0x1c010014, "nca_server_too_busy" },
282 { 0x1c010017, "nca_unsupported_type" },
286 static int proto_dcerpc = -1;
289 static int hf_dcerpc_request_in = -1;
290 static int hf_dcerpc_time = -1;
291 static int hf_dcerpc_response_in = -1;
292 static int hf_dcerpc_ver = -1;
293 static int hf_dcerpc_ver_minor = -1;
294 static int hf_dcerpc_packet_type = -1;
295 static int hf_dcerpc_cn_flags = -1;
296 static int hf_dcerpc_cn_flags_first_frag = -1;
297 static int hf_dcerpc_cn_flags_last_frag = -1;
298 static int hf_dcerpc_cn_flags_cancel_pending = -1;
299 static int hf_dcerpc_cn_flags_reserved = -1;
300 static int hf_dcerpc_cn_flags_mpx = -1;
301 static int hf_dcerpc_cn_flags_dne = -1;
302 static int hf_dcerpc_cn_flags_maybe = -1;
303 static int hf_dcerpc_cn_flags_object = -1;
304 static int hf_dcerpc_drep = -1;
305 static int hf_dcerpc_drep_byteorder = -1;
306 static int hf_dcerpc_drep_character = -1;
307 static int hf_dcerpc_drep_fp = -1;
308 static int hf_dcerpc_cn_frag_len = -1;
309 static int hf_dcerpc_cn_auth_len = -1;
310 static int hf_dcerpc_cn_call_id = -1;
311 static int hf_dcerpc_cn_max_xmit = -1;
312 static int hf_dcerpc_cn_max_recv = -1;
313 static int hf_dcerpc_cn_assoc_group = -1;
314 static int hf_dcerpc_cn_num_ctx_items = -1;
315 static int hf_dcerpc_cn_ctx_id = -1;
316 static int hf_dcerpc_cn_num_trans_items = -1;
317 static int hf_dcerpc_cn_bind_if_id = -1;
318 static int hf_dcerpc_cn_bind_if_ver = -1;
319 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
320 static int hf_dcerpc_cn_bind_trans_id = -1;
321 static int hf_dcerpc_cn_bind_trans_ver = -1;
322 static int hf_dcerpc_cn_alloc_hint = -1;
323 static int hf_dcerpc_cn_sec_addr_len = -1;
324 static int hf_dcerpc_cn_sec_addr = -1;
325 static int hf_dcerpc_cn_num_results = -1;
326 static int hf_dcerpc_cn_ack_result = -1;
327 static int hf_dcerpc_cn_ack_reason = -1;
328 static int hf_dcerpc_cn_ack_trans_id = -1;
329 static int hf_dcerpc_cn_ack_trans_ver = -1;
330 static int hf_dcerpc_cn_reject_reason = -1;
331 static int hf_dcerpc_cn_num_protocols = -1;
332 static int hf_dcerpc_cn_protocol_ver_major = -1;
333 static int hf_dcerpc_cn_protocol_ver_minor = -1;
334 static int hf_dcerpc_cn_cancel_count = -1;
335 static int hf_dcerpc_cn_status = -1;
336 static int hf_dcerpc_auth_type = -1;
337 static int hf_dcerpc_auth_level = -1;
338 static int hf_dcerpc_auth_pad_len = -1;
339 static int hf_dcerpc_auth_rsrvd = -1;
340 static int hf_dcerpc_auth_ctx_id = -1;
341 static int hf_dcerpc_dg_flags1 = -1;
342 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
343 static int hf_dcerpc_dg_flags1_last_frag = -1;
344 static int hf_dcerpc_dg_flags1_frag = -1;
345 static int hf_dcerpc_dg_flags1_nofack = -1;
346 static int hf_dcerpc_dg_flags1_maybe = -1;
347 static int hf_dcerpc_dg_flags1_idempotent = -1;
348 static int hf_dcerpc_dg_flags1_broadcast = -1;
349 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
350 static int hf_dcerpc_dg_flags2 = -1;
351 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
352 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
353 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
354 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
355 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
356 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
357 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
358 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
359 static int hf_dcerpc_dg_serial_hi = -1;
360 static int hf_dcerpc_obj_id = -1;
361 static int hf_dcerpc_dg_if_id = -1;
362 static int hf_dcerpc_dg_act_id = -1;
363 static int hf_dcerpc_dg_serial_lo = -1;
364 static int hf_dcerpc_dg_ahint = -1;
365 static int hf_dcerpc_dg_ihint = -1;
366 static int hf_dcerpc_dg_frag_len = -1;
367 static int hf_dcerpc_dg_frag_num = -1;
368 static int hf_dcerpc_dg_auth_proto = -1;
369 static int hf_dcerpc_opnum = -1;
370 static int hf_dcerpc_dg_seqnum = -1;
371 static int hf_dcerpc_dg_server_boot = -1;
372 static int hf_dcerpc_dg_if_ver = -1;
373 static int hf_dcerpc_krb5_av_prot_level = -1;
374 static int hf_dcerpc_krb5_av_key_vers_num = -1;
375 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
376 static int hf_dcerpc_dg_cancel_vers = -1;
377 static int hf_dcerpc_dg_cancel_id = -1;
378 static int hf_dcerpc_dg_server_accepting_cancels = -1;
379 static int hf_dcerpc_dg_fack_vers = -1;
380 static int hf_dcerpc_dg_fack_window_size = -1;
381 static int hf_dcerpc_dg_fack_max_tsdu = -1;
382 static int hf_dcerpc_dg_fack_max_frag_size = -1;
383 static int hf_dcerpc_dg_fack_serial_num = -1;
384 static int hf_dcerpc_dg_fack_selack_len = -1;
385 static int hf_dcerpc_dg_fack_selack = -1;
386 static int hf_dcerpc_dg_status = -1;
387 static int hf_dcerpc_array_max_count = -1;
388 static int hf_dcerpc_array_offset = -1;
389 static int hf_dcerpc_array_actual_count = -1;
390 static int hf_dcerpc_array_buffer = -1;
391 static int hf_dcerpc_op = -1;
392 static int hf_dcerpc_referent_id = -1;
393 static int hf_dcerpc_fragments = -1;
394 static int hf_dcerpc_fragment = -1;
395 static int hf_dcerpc_fragment_overlap = -1;
396 static int hf_dcerpc_fragment_overlap_conflict = -1;
397 static int hf_dcerpc_fragment_multiple_tails = -1;
398 static int hf_dcerpc_fragment_too_long_fragment = -1;
399 static int hf_dcerpc_fragment_error = -1;
400 static int hf_dcerpc_reassembled_in = -1;
401 static int hf_dcerpc_sec_chan = -1;
402 static int hf_dcerpc_sec_chan_sig = -1;
403 static int hf_dcerpc_sec_chan_unk = -1;
404 static int hf_dcerpc_sec_chan_seq = -1;
405 static int hf_dcerpc_sec_chan_nonce = -1;
407 static gint ett_dcerpc = -1;
408 static gint ett_dcerpc_cn_flags = -1;
409 static gint ett_dcerpc_drep = -1;
410 static gint ett_dcerpc_dg_flags1 = -1;
411 static gint ett_dcerpc_dg_flags2 = -1;
412 static gint ett_dcerpc_pointer_data = -1;
413 static gint ett_dcerpc_string = -1;
414 static gint ett_dcerpc_fragments = -1;
415 static gint ett_dcerpc_fragment = -1;
416 static gint ett_dcerpc_krb5_auth_verf = -1;
417 static gint ett_sec_chan = -1;
419 static dissector_handle_t ntlmssp_handle, ntlmssp_verf_handle,
420 ntlmssp_enc_payload_handle;
421 static dissector_handle_t gssapi_handle, gssapi_verf_handle;
423 static const fragment_items dcerpc_frag_items = {
424 &ett_dcerpc_fragments,
425 &ett_dcerpc_fragment,
427 &hf_dcerpc_fragments,
429 &hf_dcerpc_fragment_overlap,
430 &hf_dcerpc_fragment_overlap_conflict,
431 &hf_dcerpc_fragment_multiple_tails,
432 &hf_dcerpc_fragment_too_long_fragment,
433 &hf_dcerpc_fragment_error,
439 typedef struct _dcerpc_auth_info {
446 /* try to desegment big DCE/RPC packets over TCP? */
447 static gboolean dcerpc_cn_desegment = TRUE;
449 /* reassemble DCE/RPC fragments */
450 /* reassembly of dcerpc fragments will not work for the case where ONE frame
451 might contain multiple dcerpc fragments for different PDUs.
452 this case would be so unusual/weird so if you got captures like that:
455 static gboolean dcerpc_reassemble = FALSE;
456 static GHashTable *dcerpc_co_reassemble_table = NULL;
457 static GHashTable *dcerpc_cl_reassemble_table = NULL;
460 dcerpc_reassemble_init(void)
462 fragment_table_init(&dcerpc_co_reassemble_table);
463 fragment_table_init(&dcerpc_cl_reassemble_table);
470 /* the registered subdissectors */
471 GHashTable *dcerpc_uuids=NULL;
474 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
476 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
477 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
478 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
479 && (key1->ver == key2->ver));
483 dcerpc_uuid_hash (gconstpointer k)
485 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
486 /* This isn't perfect, but the Data1 part of these is almost always
488 return key->uuid.Data1;
492 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
493 dcerpc_sub_dissector *procs, int opnum_hf)
495 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
496 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
501 value->proto = proto;
503 value->name = proto_get_protocol_short_name (proto);
504 value->procs = procs;
505 value->opnum_hf = opnum_hf;
507 g_hash_table_insert (dcerpc_uuids, key, value);
510 /* Function to find the name of a registered protocol
511 * or NULL if the protocol/version is not known to ethereal.
514 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
517 dcerpc_uuid_value *sub_proto;
521 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
524 return sub_proto->name;
527 /* Create a value_string consisting of DCERPC opnum and name from a
528 subdissector array. */
530 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd,
536 vs = g_malloc((num_sds + 1) * sizeof(value_string));
538 for (i = 0; i < num_sds; i++) {
539 vs[i].value = sd[i].num;
540 vs[i].strptr = sd[i].name;
543 vs[num_sds].value = 0;
544 vs[num_sds].strptr = NULL;
549 /* Function to find the subdissector table of a registered protocol
550 * or NULL if the protocol/version is not known to ethereal.
552 dcerpc_sub_dissector *
553 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
556 dcerpc_uuid_value *sub_proto;
560 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
563 return sub_proto->procs;
568 * To keep track of ctx_id mappings.
570 * Everytime we see a bind call we update this table.
571 * Note that we always specify a SMB FID. For non-SMB transports this
574 static GHashTable *dcerpc_binds=NULL;
576 typedef struct _dcerpc_bind_key {
577 conversation_t *conv;
582 typedef struct _dcerpc_bind_value {
587 static GMemChunk *dcerpc_bind_key_chunk=NULL;
588 static GMemChunk *dcerpc_bind_value_chunk=NULL;
591 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
593 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
594 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
595 return (key1->conv == key2->conv
596 && key1->ctx_id == key2->ctx_id
597 && key1->smb_fid == key2->smb_fid);
601 dcerpc_bind_hash (gconstpointer k)
603 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
604 return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
609 * To keep track of callid mappings. Should really use some generic
610 * conversation support instead.
612 static GHashTable *dcerpc_calls=NULL;
614 typedef struct _dcerpc_call_key {
615 conversation_t *conv;
620 static GMemChunk *dcerpc_call_key_chunk=NULL;
622 static GMemChunk *dcerpc_call_value_chunk=NULL;
625 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
627 const dcerpc_call_key *key1 = (const dcerpc_call_key *)k1;
628 const dcerpc_call_key *key2 = (const dcerpc_call_key *)k2;
629 return (key1->conv == key2->conv
630 && key1->call_id == key2->call_id
631 && key1->smb_fid == key2->smb_fid);
635 dcerpc_call_hash (gconstpointer k)
637 const dcerpc_call_key *key = (const dcerpc_call_key *)k;
638 return ((guint32)key->conv) + key->call_id + key->smb_fid;
642 /* to keep track of matched calls/responses
643 this one uses the same value struct as calls, but the key is the frame id
644 and call id; there can be more than one call in a frame.
646 XXX - why not just use the same keys as are used for calls?
649 static GHashTable *dcerpc_matched=NULL;
651 typedef struct _dcerpc_matched_key {
654 } dcerpc_matched_key;
656 static GMemChunk *dcerpc_matched_key_chunk=NULL;
659 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
661 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
662 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
663 return (key1->frame == key2->frame
664 && key1->call_id == key2->call_id);
668 dcerpc_matched_hash (gconstpointer k)
670 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
677 * Utility functions. Modeled after packet-rpc.c
681 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
682 proto_tree *tree, char *drep,
683 int hfindex, guint8 *pdata)
687 data = tvb_get_guint8 (tvb, offset);
689 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
697 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
698 proto_tree *tree, char *drep,
699 int hfindex, guint16 *pdata)
703 data = ((drep[0] & 0x10)
704 ? tvb_get_letohs (tvb, offset)
705 : tvb_get_ntohs (tvb, offset));
708 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
716 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
717 proto_tree *tree, char *drep,
718 int hfindex, guint32 *pdata)
722 data = ((drep[0] & 0x10)
723 ? tvb_get_letohl (tvb, offset)
724 : tvb_get_ntohl (tvb, offset));
727 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
734 /* handles 32 bit unix time_t */
736 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
737 proto_tree *tree, char *drep,
738 int hfindex, guint32 *pdata)
743 data = ((drep[0] & 0x10)
744 ? tvb_get_letohl (tvb, offset)
745 : tvb_get_ntohl (tvb, offset));
750 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
759 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
760 proto_tree *tree, char *drep,
761 int hfindex, unsigned char *pdata)
764 tvb_memcpy(tvb, pdata, offset, 8);
765 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
767 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
768 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
769 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
770 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
775 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
783 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
784 proto_tree *tree, char *drep,
785 int hfindex, gfloat *pdata)
791 case(DCE_RPC_DREP_FP_IEEE):
792 data = ((drep[0] & 0x10)
793 ? tvb_get_letohieee_float(tvb, offset)
794 : tvb_get_ntohieee_float(tvb, offset));
796 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
799 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
800 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
801 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
803 /* ToBeDone: non IEEE floating formats */
804 /* Set data to a negative infinity value */
805 data = -1.0 * 1e100 * 1e100;
807 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
817 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
818 proto_tree *tree, char *drep,
819 int hfindex, gdouble *pdata)
825 case(DCE_RPC_DREP_FP_IEEE):
826 data = ((drep[0] & 0x10)
827 ? tvb_get_letohieee_double(tvb, offset)
828 : tvb_get_ntohieee_double(tvb, offset));
830 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
833 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
834 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
835 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
837 /* ToBeDone: non IEEE double formats */
838 /* Set data to a negative infinity value */
839 data = -1.0 * 1e100 * 1e100;
841 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
851 * a couple simpler things
854 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
856 if (drep[0] & 0x10) {
857 return tvb_get_letohs (tvb, offset);
859 return tvb_get_ntohs (tvb, offset);
864 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
866 if (drep[0] & 0x10) {
867 return tvb_get_letohl (tvb, offset);
869 return tvb_get_ntohl (tvb, offset);
874 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
877 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
878 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
879 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
881 for (i=0; i<sizeof (uuid->Data4); i++) {
882 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
889 /* function to dissect a unidimensional conformant array */
891 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
892 proto_tree *tree, char *drep,
893 dcerpc_dissect_fnct_t *fnct)
899 di=pinfo->private_data;
900 if(di->conformant_run){
901 /* conformant run, just dissect the max_count header */
903 di->conformant_run=0;
904 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
905 hf_dcerpc_array_max_count, &di->array_max_count);
906 di->array_max_count_offset=offset-4;
907 di->conformant_run=1;
908 di->conformant_eaten=offset-old_offset;
910 /* we don't remember where in the bytestream this field was */
911 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
913 /* real run, dissect the elements */
914 for(i=0;i<di->array_max_count;i++){
915 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
921 /* function to dissect a unidimensional conformant and varying array */
923 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
924 proto_tree *tree, char *drep,
925 dcerpc_dissect_fnct_t *fnct)
931 di=pinfo->private_data;
932 if(di->conformant_run){
933 /* conformant run, just dissect the max_count header */
935 di->conformant_run=0;
936 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
937 hf_dcerpc_array_max_count, &di->array_max_count);
938 di->array_max_count_offset=offset-4;
939 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
940 hf_dcerpc_array_offset, &di->array_offset);
941 di->array_offset_offset=offset-4;
942 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
943 hf_dcerpc_array_actual_count, &di->array_actual_count);
944 di->array_actual_count_offset=offset-4;
945 di->conformant_run=1;
946 di->conformant_eaten=offset-old_offset;
948 /* we dont dont remember where in the bytestream these fields were */
949 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
950 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
951 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
953 /* real run, dissect the elements */
954 for(i=0;i<di->array_actual_count;i++){
955 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
962 /* Dissect an string of bytes. This corresponds to
963 IDL of the form '[string] byte *foo'.
965 It can also be used for a conformant varying array of bytes if
966 the contents of the array should be shown as a big blob, rather
967 than showing each byte as an individual element.
969 XXX - which of those is really the IDL type for, for example,
970 the encrypted data in some MAPI packets? (Microsoft haven't
973 XXX - does this need to do all the conformant array stuff that
974 "dissect_ndr_ucvarray()" does? These are presumably for strings
975 that are conformant and varying - they're stored like conformant
976 varying arrays of bytes. */
978 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
979 proto_tree *tree, char *drep)
984 di=pinfo->private_data;
985 if(di->conformant_run){
986 /* just a run to handle conformant arrays, no scalars to dissect */
990 /* NDR array header */
992 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
993 hf_dcerpc_array_max_count, NULL);
995 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
996 hf_dcerpc_array_offset, NULL);
998 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
999 hf_dcerpc_array_actual_count, &len);
1002 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1003 tvb, offset, len, drep[0] & 0x10);
1010 /* For dissecting arrays that are to be interpreted as strings. */
1012 /* Dissect an NDR conformant varying string of elements.
1013 The length of each element is given by the 'size_is' parameter;
1014 the elements are assumed to be characters or wide characters.
1016 XXX - does this need to do all the conformant array stuff that
1017 "dissect_ndr_ucvarray()" does? */
1019 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1020 proto_tree *tree, char *drep, int size_is,
1021 int hfindex, gboolean add_subtree, char **data)
1024 proto_item *string_item;
1025 proto_tree *string_tree;
1026 guint32 len, buffer_len;
1028 header_field_info *hfinfo;
1030 di=pinfo->private_data;
1031 if(di->conformant_run){
1032 /* just a run to handle conformant arrays, no scalars to dissect */
1037 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1038 proto_registrar_get_name(hfindex));
1039 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1045 /* NDR array header */
1047 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1048 hf_dcerpc_array_max_count, NULL);
1050 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1051 hf_dcerpc_array_offset, NULL);
1053 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1054 hf_dcerpc_array_actual_count, &len);
1056 buffer_len = size_is * len;
1059 if (offset % size_is)
1060 offset += size_is - (offset % size_is);
1062 if (size_is == sizeof(guint16)) {
1063 /* XXX - use drep to determine the byte order? */
1064 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1066 * XXX - we don't support a string type with Unicode
1067 * characters, so if this is a string item, we make
1068 * its value be the "fake Unicode" string.
1070 if (tree && buffer_len) {
1071 hfinfo = proto_registrar_get_nth(hfindex);
1072 if (hfinfo->type == FT_STRING) {
1073 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1076 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1077 buffer_len, drep[0] & 0x10);
1082 * "tvb_get_string()" throws an exception if the entire string
1083 * isn't in the tvbuff. If the length is bogus, this should
1084 * keep us from trying to allocate an immensely large buffer.
1085 * (It won't help if the length is *valid* but immensely large,
1086 * but that's another matter; in any case, that would happen only
1087 * if we had an immensely large tvbuff....)
1089 s = tvb_get_string(tvb, offset, buffer_len);
1090 if (tree && buffer_len)
1091 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1092 buffer_len, drep[0] & 0x10);
1095 if (string_item != NULL)
1096 proto_item_append_text(string_item, ": %s", s);
1103 offset += buffer_len;
1105 proto_item_set_end(string_item, tvb, offset);
1110 /* Dissect an conformant varying string of chars.
1111 This corresponds to IDL of the form '[string] char *foo'.
1113 XXX - at least according to the DCE RPC 1.1 spec, a string has
1114 a null terminator, which isn't necessary as a terminator for
1115 the transfer language (as there's a length), but is presumably
1116 there for the benefit of null-terminated-string languages
1117 such as C. Is this ever used for purely counted strings?
1118 (Not that it matters if it is.) */
1120 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1121 proto_tree *tree, char *drep)
1124 di=pinfo->private_data;
1126 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1127 sizeof(guint8), di->hf_index,
1131 /* Dissect a conformant varying string of wchars (wide characters).
1132 This corresponds to IDL of the form '[string] wchar *foo'
1134 XXX - at least according to the DCE RPC 1.1 spec, a string has
1135 a null terminator, which isn't necessary as a terminator for
1136 the transfer language (as there's a length), but is presumably
1137 there for the benefit of null-terminated-string languages
1138 such as C. Is this ever used for purely counted strings?
1139 (Not that it matters if it is.) */
1141 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1142 proto_tree *tree, char *drep)
1145 di=pinfo->private_data;
1147 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1148 sizeof(guint16), di->hf_index,
1152 /* ndr pointer handling */
1153 /* list of pointers encountered so far */
1154 static GSList *ndr_pointer_list = NULL;
1156 /* position where in the list to insert newly encountered pointers */
1157 static int ndr_pointer_list_pos=0;
1159 /* boolean controlling whether pointers are top-level or embedded */
1160 static gboolean pointers_are_top_level = TRUE;
1162 /* as a kludge, we represent all embedded reference pointers as id==-1
1163 hoping that his will not collide with any non-ref pointers */
1164 typedef struct ndr_pointer_data {
1166 proto_item *item; /* proto_item for pointer */
1167 proto_tree *tree; /* subtree of above item */
1168 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1170 dcerpc_callback_fnct_t *callback;
1171 void *callback_args;
1172 } ndr_pointer_data_t;
1175 init_ndr_pointer_list(packet_info *pinfo)
1179 di=pinfo->private_data;
1180 di->conformant_run=0;
1182 while(ndr_pointer_list){
1183 ndr_pointer_data_t *npd;
1185 npd=g_slist_nth_data(ndr_pointer_list, 0);
1186 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1192 ndr_pointer_list=NULL;
1193 ndr_pointer_list_pos=0;
1194 pointers_are_top_level=TRUE;
1198 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *drep)
1200 int found_new_pointer;
1204 di=pinfo->private_data;
1208 found_new_pointer=0;
1209 len=g_slist_length(ndr_pointer_list);
1211 ndr_pointer_data_t *tnpd;
1212 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1214 dcerpc_dissect_fnct_t *fnct;
1216 found_new_pointer=1;
1219 ndr_pointer_list_pos=i+1;
1220 di->hf_index=tnpd->hf_index;
1221 /* first a run to handle any conformant
1223 di->conformant_run=1;
1224 di->conformant_eaten=0;
1225 old_offset = offset;
1226 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1228 g_assert((offset-old_offset)==di->conformant_eaten);
1229 /* This is to check for any bugs in the dissectors.
1231 * Basically, the NDR representation will store all
1232 * arrays in two blocks, one block with the dimension
1233 * discreption, like size, number of elements and such,
1234 * and another block that contains the actual data stored
1236 * If the array is embedded directly inside another,
1237 * encapsulating aggregate type, like a union or struct,
1238 * then these two blocks will be stored at different places
1239 * in the bytestream, with other data between the blocks.
1241 * For this reason, all pointers to types (both aggregate
1242 * and scalar, for simplicity no distinction is made)
1243 * will have its dissector called twice.
1244 * The dissector will first be called with conformant_run==1
1245 * in which mode the dissector MUST NOT consume any data from
1246 * the tvbuff (i.e. may not dissect anything) except the
1247 * initial control block for arrays.
1248 * The second time the dissector is called, with
1249 * conformant_run==0, all other data for the type will be
1252 * All dissect_ndr_<type> dissectors are already prepared
1253 * for this and knows when it should eat data from the tvb
1254 * and when not to, so implementors of dissectors will
1255 * normally not need to worry about this or even know about
1256 * it. However, if a dissector for an aggregate type calls
1257 * a subdissector from outside packet-dcerpc.c, such as
1258 * the dissector in packet-smb.c for NT Security Descriptors
1259 * as an example, then it is VERY important to encapsulate
1260 * this call to an external subdissector with the appropriate
1261 * test for conformant_run, i.e. it will need something like
1265 * di=pinfo->private_data;
1266 * if(di->conformant_run){
1270 * to make sure it makes the right thing.
1271 * This assert will signal when someone has forgotten to
1272 * make the dissector aware of this requirement.
1275 /* now we dissect the actual pointer */
1276 di->conformant_run=0;
1277 old_offset = offset;
1278 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1280 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1284 } while(found_new_pointer);
1291 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1292 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1293 dcerpc_callback_fnct_t *callback, void *callback_args)
1295 ndr_pointer_data_t *npd;
1297 /* check if this pointer is valid */
1300 dcerpc_call_value *value;
1302 di=pinfo->private_data;
1303 value=di->call_data;
1306 if(!(pinfo->fd->flags.visited)){
1307 if(id>value->max_ptr){
1312 /* if we havent seen the request bail out since we cant
1313 know whether this is the first non-NULL instance
1315 if(value->req_frame==0){
1316 /* XXX THROW EXCEPTION */
1319 /* We saw this one in the request frame, nothing to
1321 if(id<=value->max_ptr){
1327 npd=g_malloc(sizeof(ndr_pointer_data_t));
1332 npd->hf_index=hf_index;
1333 npd->callback=callback;
1334 npd->callback_args=callback_args;
1335 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1336 ndr_pointer_list_pos);
1337 ndr_pointer_list_pos++;
1342 find_pointer_index(guint32 id)
1344 ndr_pointer_data_t *npd;
1347 len=g_slist_length(ndr_pointer_list);
1349 npd=g_slist_nth_data(ndr_pointer_list, i);
1360 /* This function dissects an NDR pointer and stores the callback for later
1361 * deferred dissection.
1363 * fnct is the callback function for when we have reached this object in
1366 * type is what type of pointer.
1368 * this is text is what text we should put in any created tree node.
1370 * hf_index is what hf value we want to pass to the callback function when
1371 * it is called, the callback can later pich this one up from di->hf_index.
1373 * callback is executed after the pointer has been dereferenced.
1375 * callback_args is passed as an argument to the callback function
1377 * See packet-dcerpc-samr.c for examples
1380 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1381 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1382 int type, char *text, int hf_index,
1383 dcerpc_callback_fnct_t *callback, void *callback_args)
1387 di=pinfo->private_data;
1388 if(di->conformant_run){
1389 /* this call was only for dissecting the header for any
1390 embedded conformant array. we will not parse any
1391 pointers in this mode.
1396 /*TOP LEVEL REFERENCE POINTER*/
1397 if( pointers_are_top_level
1398 &&(type==NDR_POINTER_REF) ){
1402 /* we must find out a nice way to do the length here */
1403 item=proto_tree_add_text(tree, tvb, offset, 0,
1405 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1407 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1408 hf_index, callback, callback_args);
1412 /*TOP LEVEL FULL POINTER*/
1413 if( pointers_are_top_level
1414 && (type==NDR_POINTER_PTR) ){
1420 /* get the referent id */
1421 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1423 /* we got a NULL pointer */
1425 proto_tree_add_text(tree, tvb, offset-4, 4,
1426 "(NULL pointer) %s",text);
1430 /* see if we have seen this pointer before */
1431 idx=find_pointer_index(id);
1433 /* we have seen this pointer before */
1435 proto_tree_add_text(tree, tvb, offset-4, 4,
1436 "(duplicate PTR) %s",text);
1441 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1443 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1444 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1445 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1446 callback, callback_args);
1449 /*TOP LEVEL UNIQUE POINTER*/
1450 if( pointers_are_top_level
1451 && (type==NDR_POINTER_UNIQUE) ){
1456 /* get the referent id */
1457 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1459 /* we got a NULL pointer */
1461 proto_tree_add_text(tree, tvb, offset-4, 4,
1462 "(NULL pointer) %s",text);
1467 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1469 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1470 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1471 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1472 hf_index, callback, callback_args);
1476 /*EMBEDDED REFERENCE POINTER*/
1477 if( (!pointers_are_top_level)
1478 && (type==NDR_POINTER_REF) ){
1483 /* get the referent id */
1484 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1487 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1489 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1490 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1491 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1492 hf_index, callback, callback_args);
1496 /*EMBEDDED UNIQUE POINTER*/
1497 if( (!pointers_are_top_level)
1498 && (type==NDR_POINTER_UNIQUE) ){
1503 /* get the referent id */
1504 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1506 /* we got a NULL pointer */
1508 proto_tree_add_text(tree, tvb, offset-4, 4,
1509 "(NULL pointer) %s", text);
1514 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1516 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1517 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1518 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1519 hf_index, callback, callback_args);
1523 /*EMBEDDED FULL POINTER*/
1524 if( (!pointers_are_top_level)
1525 && (type==NDR_POINTER_PTR) ){
1531 /* get the referent id */
1532 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1534 /* we got a NULL pointer */
1536 proto_tree_add_text(tree, tvb, offset-4, 4,
1537 "(NULL pointer) %s",text);
1541 /* see if we have seen this pointer before */
1542 idx=find_pointer_index(id);
1544 /* we have seen this pointer before */
1546 proto_tree_add_text(tree, tvb, offset-4, 4,
1547 "(duplicate PTR) %s",text);
1552 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1554 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1555 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1556 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1557 callback, callback_args);
1563 /* After each top level pointer we have dissected we have to
1564 dissect all deferrals before we move on to the next top level
1566 if(pointers_are_top_level==TRUE){
1567 pointers_are_top_level=FALSE;
1568 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
1569 pointers_are_top_level=TRUE;
1576 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1577 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1578 int type, char *text, int hf_index)
1580 return dissect_ndr_pointer_cb(
1581 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
1586 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
1587 dcerpc_auth_info *auth_info)
1592 * We don't show stub data unless we have some in the tvbuff;
1593 * however, in the protocol tree, we show, as the number of
1594 * bytes, the reported number of bytes, not the number of bytes
1595 * that happen to be in the tvbuff.
1597 if (tvb_length_remaining (tvb, offset) > 0) {
1598 length = tvb_reported_length_remaining (tvb, offset);
1599 if (auth_info != NULL &&
1600 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1601 proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
1602 "Encrypted stub data (%d byte%s)",
1603 length, plurality(length, "", "s"));
1605 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
1606 "Stub data (%d byte%s)", length,
1607 plurality(length, "", "s"));
1613 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
1614 proto_tree *dcerpc_tree,
1615 tvbuff_t *tvb, volatile gint offset,
1616 char *drep, dcerpc_info *info,
1617 dcerpc_auth_info *auth_info)
1619 dcerpc_uuid_key key;
1620 dcerpc_uuid_value *sub_proto;
1622 proto_tree *volatile sub_tree = NULL;
1623 dcerpc_sub_dissector *proc;
1625 dcerpc_dissect_fnct_t *volatile sub_dissect;
1626 const char *volatile saved_proto;
1627 void *volatile saved_private_data;
1629 key.uuid = info->call_data->uuid;
1630 key.ver = info->call_data->ver;
1633 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1634 || !proto_is_protocol_enabled(sub_proto->proto)) {
1636 * We don't have a dissector for this UUID, or the protocol
1637 * for that UUID is disabled.
1639 show_stub_data (tvb, offset, dcerpc_tree, auth_info);
1643 for (proc = sub_proto->procs; proc->name; proc++) {
1644 if (proc->num == info->call_data->opnum) {
1653 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1654 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1657 if (check_col (pinfo->cinfo, COL_INFO)) {
1658 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1659 name, info->request ? "request" : "reply");
1663 proto_item *sub_item;
1664 sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
1668 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1672 * Put the operation number into the tree along with
1673 * the operation's name.
1676 if (sub_proto->opnum_hf != -1)
1677 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
1678 tvb, 0, 0, info->call_data->opnum,
1679 "Operation: %s (%u)",
1680 name, info->call_data->opnum);
1682 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
1683 0, 0, info->call_data->opnum,
1684 "Operation: %s (%u)",
1685 name, info->call_data->opnum);
1689 * If the authentication level is DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
1690 * the stub data is encrypted, and we'd have to decrypt it in
1691 * order to dissect it.
1693 if (auth_info != NULL &&
1694 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1695 length = tvb_length_remaining (tvb, offset);
1697 proto_tree_add_text(sub_tree, tvb, offset, length,
1698 "Encrypted stub data (%d byte%s)",
1699 length, plurality(length, "", "s"));
1701 switch (auth_info->auth_type) {
1703 case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
1705 tvbuff_t *ntlmssp_tvb;
1706 ntlmssp_tvb = tvb_new_subset(tvb, offset, length, length);
1707 pinfo->decrypted_data=NULL;
1709 call_dissector(ntlmssp_enc_payload_handle, ntlmssp_tvb, pinfo,
1712 if(pinfo->decrypted_data){
1713 ntlmssp_decrypted_info_t *ndi=pinfo->decrypted_data;
1716 sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
1718 saved_proto = pinfo->current_proto;
1719 saved_private_data = pinfo->private_data;
1720 pinfo->current_proto = sub_proto->name;
1721 pinfo->private_data = (void *)info;
1723 init_ndr_pointer_list(pinfo);
1726 * Catch ReportedBoundsError, as that could
1727 * be due to the decryption being bad,
1728 * and doesn't mean that the tvbuff we were
1729 * handed has a malformed packet.
1732 offset = sub_dissect (ndi->decr_tvb, 0, pinfo, ndi->decr_tree, drep);
1733 } CATCH(BoundsError) {
1735 } CATCH(ReportedBoundsError) {
1736 show_reported_bounds_error(tvb, pinfo, tree);
1739 pinfo->current_proto = saved_proto;
1740 pinfo->private_data = saved_private_data;
1748 sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
1750 saved_proto = pinfo->current_proto;
1751 saved_private_data = pinfo->private_data;
1752 pinfo->current_proto = sub_proto->name;
1753 pinfo->private_data = (void *)info;
1755 init_ndr_pointer_list(pinfo);
1757 * Catch ReportedBoundsError, so that even if the stub
1758 * data is bad, we still show the verifier.
1761 offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
1762 } CATCH(BoundsError) {
1764 } CATCH(ReportedBoundsError) {
1765 show_reported_bounds_error(tvb, pinfo, tree);
1769 /* If we have a subdissector and it didn't dissect all data in
1770 the tvb, make a note of it. */
1772 if (tvb_length_remaining(tvb, offset)) {
1773 if (check_col(pinfo->cinfo, COL_INFO))
1774 col_append_fstr(pinfo->cinfo, COL_INFO,
1775 "[Long frame (%d bytes)]",
1776 tvb_length_remaining(tvb, offset));
1779 pinfo->current_proto = saved_proto;
1780 pinfo->private_data = saved_private_data;
1782 length = tvb_length_remaining (tvb, offset);
1784 proto_tree_add_text (sub_tree, tvb, offset, length,
1785 "Stub data (%d byte%s)", length,
1786 plurality(length, "", "s"));
1790 tap_queue_packet(dcerpc_tap, pinfo, info);
1795 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
1796 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
1797 dcerpc_auth_info *auth_info)
1801 if (auth_info->auth_size != 0) {
1802 auth_offset = hdr->frag_len - hdr->auth_len;
1803 switch (auth_info->auth_type) {
1805 case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
1807 tvbuff_t *ntlmssp_tvb;
1809 ntlmssp_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
1812 call_dissector(ntlmssp_verf_handle, ntlmssp_tvb, pinfo,
1818 case DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO: {
1819 /* SPNEGO (rfc2478) */
1820 tvbuff_t *gssapi_tvb;
1822 gssapi_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
1825 call_dissector(gssapi_verf_handle, gssapi_tvb, pinfo, dcerpc_tree);
1830 case DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN: {
1831 proto_item *vf = NULL;
1832 proto_tree *volatile sec_chan_tree = NULL;
1834 * Create a new tree, and split into 4 components ...
1836 vf = proto_tree_add_item(dcerpc_tree, hf_dcerpc_sec_chan, tvb,
1837 auth_offset, -1, FALSE);
1838 sec_chan_tree = proto_item_add_subtree(vf, ett_sec_chan);
1840 proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_sig, tvb,
1841 auth_offset, 8, FALSE);
1843 proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_unk, tvb,
1844 auth_offset + 8, 8, FALSE);
1846 proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_seq, tvb,
1847 auth_offset + 16, 8, FALSE);
1849 proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_nonce, tvb,
1850 auth_offset + 24, 8, FALSE);
1856 proto_tree_add_text (dcerpc_tree, tvb, auth_offset, hdr->auth_len,
1861 return hdr->auth_len;
1865 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1866 e_dce_cn_common_hdr_t *hdr, gboolean are_credentials,
1867 dcerpc_auth_info *auth_info)
1872 * Initially set auth_level to -1 to indicate that we haven't
1873 * yet seen any authentication level information.
1875 auth_info->auth_level = -1;
1878 * The authentication information is at the *end* of the PDU; in
1879 * request and response PDUs, the request and response stub data
1882 * If the full packet is here, and we've got an auth len, and it's
1883 * valid, then dissect the auth info.
1885 if (tvb_length (tvb) >= hdr->frag_len
1887 && (hdr->auth_len + 8 <= hdr->frag_len)) {
1889 offset = hdr->frag_len - (hdr->auth_len + 8);
1891 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1892 hf_dcerpc_auth_type,
1893 &auth_info->auth_type);
1894 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1895 hf_dcerpc_auth_level,
1896 &auth_info->auth_level);
1898 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1899 hf_dcerpc_auth_pad_len,
1900 &auth_info->auth_pad_len);
1901 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1902 hf_dcerpc_auth_rsrvd, NULL);
1903 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1904 hf_dcerpc_auth_ctx_id, NULL);
1907 * Dissect the authentication data.
1909 if (are_credentials) {
1911 * The authentication data are credentials.
1913 switch (auth_info->auth_type) {
1915 case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
1917 tvbuff_t *ntlmssp_tvb;
1919 ntlmssp_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
1922 call_dissector(ntlmssp_handle, ntlmssp_tvb, pinfo,
1928 case DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO: {
1929 /* SPNEGO (rfc2478) */
1930 tvbuff_t *gssapi_tvb;
1932 gssapi_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
1935 call_dissector(gssapi_handle, gssapi_tvb, pinfo, dcerpc_tree);
1940 case DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN: {
1942 /* TODO: Fill me in when we know what goes here */
1944 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
1945 "Secure Channel Auth Credentials");
1950 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
1951 "Auth Credentials");
1955 /* figure out where the auth padding starts */
1956 offset = hdr->frag_len - (hdr->auth_len + 8 + auth_info->auth_pad_len);
1957 if (offset > 0 && auth_info->auth_pad_len) {
1958 proto_tree_add_text (dcerpc_tree, tvb, offset,
1959 auth_info->auth_pad_len, "Auth padding");
1960 auth_info->auth_size = hdr->auth_len + 8 + auth_info->auth_pad_len;
1962 auth_info->auth_size = hdr->auth_len + 8;
1965 auth_info->auth_size = 0;
1970 /* We need to hash in the SMB fid number to generate a unique hash table
1971 key as DCERPC over SMB allows several pipes over the same TCP/IP
1974 static guint16 get_smb_fid (void *private_data)
1976 dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
1979 return 0; /* Nothing to see here */
1981 /* DCERPC over smb */
1983 if (priv->transport_type == DCERPC_TRANSPORT_SMB)
1984 return priv->data.smb.fid;
1986 /* Some other transport... */
1992 * Connection oriented packet types
1996 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
1997 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
1999 conversation_t *conv = NULL;
2000 guint8 num_ctx_items;
2002 gboolean saw_ctx_item = FALSE;
2004 guint16 num_trans_items;
2009 guint16 if_ver, if_ver_minor;
2010 char uuid_str[DCERPC_UUID_STR_LEN];
2012 dcerpc_auth_info auth_info;
2014 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2015 hf_dcerpc_cn_max_xmit, NULL);
2017 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2018 hf_dcerpc_cn_max_recv, NULL);
2020 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2021 hf_dcerpc_cn_assoc_group, NULL);
2023 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2024 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2029 for (i = 0; i < num_ctx_items; i++) {
2030 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2031 hf_dcerpc_cn_ctx_id, &ctx_id);
2033 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2034 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2036 /* XXX - use "dissect_ndr_uuid_t()"? */
2037 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2039 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2040 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2041 if_id.Data1, if_id.Data2, if_id.Data3,
2042 if_id.Data4[0], if_id.Data4[1],
2043 if_id.Data4[2], if_id.Data4[3],
2044 if_id.Data4[4], if_id.Data4[5],
2045 if_id.Data4[6], if_id.Data4[7]);
2046 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2047 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2048 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
2049 offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2053 if (hdr->drep[0] & 0x10) {
2054 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2055 hf_dcerpc_cn_bind_if_ver, &if_ver);
2056 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2057 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2059 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2060 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2061 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2062 hf_dcerpc_cn_bind_if_ver, &if_ver);
2065 if (!saw_ctx_item) {
2066 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2067 pinfo->srcport, pinfo->destport, 0);
2069 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
2070 pinfo->srcport, pinfo->destport, 0);
2073 /* if this is the first time we see this packet, we need to
2074 update the dcerpc_binds table so that any later calls can
2075 match to the interface.
2076 XXX We assume that BINDs will NEVER be fragmented.
2078 if(!(pinfo->fd->flags.visited)){
2079 dcerpc_bind_key *key;
2080 dcerpc_bind_value *value;
2082 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
2084 key->ctx_id = ctx_id;
2085 key->smb_fid = get_smb_fid(pinfo->private_data);
2087 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2088 value->uuid = if_id;
2089 value->ver = if_ver;
2091 /* add this entry to the bind table, first removing any
2092 previous ones that are identical
2094 if(g_hash_table_lookup(dcerpc_binds, key)){
2095 g_hash_table_remove(dcerpc_binds, key);
2097 g_hash_table_insert (dcerpc_binds, key, value);
2100 if (check_col (pinfo->cinfo, COL_INFO)) {
2101 dcerpc_uuid_key key;
2102 dcerpc_uuid_value *value;
2107 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2108 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2110 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2111 if_id.Data1, if_id.Data2, if_id.Data3,
2112 if_id.Data4[0], if_id.Data4[1],
2113 if_id.Data4[2], if_id.Data4[3],
2114 if_id.Data4[4], if_id.Data4[5],
2115 if_id.Data4[6], if_id.Data4[7],
2116 if_ver, if_ver_minor);
2118 saw_ctx_item = TRUE;
2121 for (j = 0; j < num_trans_items; j++) {
2122 /* XXX - use "dissect_ndr_uuid_t()"? */
2123 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2125 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2126 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2127 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2128 trans_id.Data4[0], trans_id.Data4[1],
2129 trans_id.Data4[2], trans_id.Data4[3],
2130 trans_id.Data4[4], trans_id.Data4[5],
2131 trans_id.Data4[6], trans_id.Data4[7]);
2132 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2133 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2134 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2135 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2139 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2140 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2145 * XXX - we should save the authentication type *if* we have
2146 * an authentication header, and associate it with an authentication
2147 * context, so subsequent PDUs can use that context.
2149 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2153 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2154 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2156 guint16 max_xmit, max_recv;
2157 guint16 sec_addr_len;
2164 char uuid_str[DCERPC_UUID_STR_LEN];
2166 dcerpc_auth_info auth_info;
2168 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2169 hf_dcerpc_cn_max_xmit, &max_xmit);
2171 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2172 hf_dcerpc_cn_max_recv, &max_recv);
2174 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2175 hf_dcerpc_cn_assoc_group, NULL);
2177 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2178 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2179 if (sec_addr_len != 0) {
2180 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2181 sec_addr_len, FALSE);
2182 offset += sec_addr_len;
2186 offset += 4 - offset % 4;
2189 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2190 hf_dcerpc_cn_num_results, &num_results);
2195 for (i = 0; i < num_results; i++) {
2196 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2197 hdr->drep, hf_dcerpc_cn_ack_result,
2200 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2201 hdr->drep, hf_dcerpc_cn_ack_reason,
2205 * The reason for rejection isn't meaningful, and often isn't
2206 * set, when the syntax was accepted.
2211 /* XXX - use "dissect_ndr_uuid_t()"? */
2212 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2214 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2215 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2216 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2217 trans_id.Data4[0], trans_id.Data4[1],
2218 trans_id.Data4[2], trans_id.Data4[3],
2219 trans_id.Data4[4], trans_id.Data4[5],
2220 trans_id.Data4[6], trans_id.Data4[7]);
2221 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2222 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2223 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2224 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2228 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2229 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2233 * XXX - do we need to do anything with the authentication level
2234 * we get back from this?
2236 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2238 if (check_col (pinfo->cinfo, COL_INFO)) {
2239 if (num_results != 0 && result == 0) {
2240 /* XXX - only checks the last result */
2241 col_append_fstr (pinfo->cinfo, COL_INFO,
2242 " accept max_xmit: %u max_recv: %u",
2243 max_xmit, max_recv);
2245 /* XXX - only shows the last result and reason */
2246 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2247 val_to_str(result, p_cont_result_vals,
2248 "Unknown result (%u)"),
2249 val_to_str(reason, p_provider_reason_vals,
2256 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2257 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2260 guint8 num_protocols;
2263 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2264 hdr->drep, hf_dcerpc_cn_reject_reason,
2267 if (check_col (pinfo->cinfo, COL_INFO)) {
2268 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2269 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2272 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2273 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2274 hf_dcerpc_cn_num_protocols,
2277 for (i = 0; i < num_protocols; i++) {
2278 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2279 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2281 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2282 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2288 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2291 #define PFC_FRAG_MASK 0x03
2294 fragment_type(guint8 flags)
2296 flags = flags & PFC_FRAG_MASK;
2298 if (flags == PFC_FIRST_FRAG)
2304 if (flags == PFC_LAST_FRAG)
2307 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2314 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2315 proto_tree *dcerpc_tree, proto_tree *tree,
2316 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2317 dcerpc_auth_info *auth_info, guint32 alloc_hint,
2320 int length, reported_length, stub_length;
2321 gboolean save_fragmented;
2322 fragment_data *fd_head=NULL;
2326 length = tvb_length_remaining(tvb, offset);
2327 reported_length = tvb_reported_length_remaining(tvb, offset);
2328 stub_length = hdr->frag_len - offset - auth_info->auth_size;
2329 if (length > stub_length)
2330 length = stub_length;
2331 if (reported_length > stub_length)
2332 reported_length = stub_length;
2334 save_fragmented = pinfo->fragmented;
2336 /* if this packet is not fragmented, just dissect it and exit */
2337 if(PFC_NOT_FRAGMENTED(hdr)){
2338 pinfo->fragmented = FALSE;
2339 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2340 tvb_new_subset (tvb, offset, length, reported_length),
2341 0, hdr->drep, di, auth_info);
2343 pinfo->fragmented = save_fragmented;
2347 /* The packet is fragmented. */
2348 pinfo->fragmented = TRUE;
2350 /* if we are not doing reassembly and this is the first fragment
2351 then just dissect it and exit
2353 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
2354 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2355 tvb_new_subset (tvb, offset, length,
2357 0, hdr->drep, di, auth_info);
2358 if (check_col(pinfo->cinfo, COL_INFO)) {
2359 col_append_fstr(pinfo->cinfo, COL_INFO,
2360 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2362 pinfo->fragmented = save_fragmented;
2366 /* if we have already seen this packet, see if it was reassembled
2367 and if so dissect the full pdu.
2370 if(pinfo->fd->flags.visited){
2371 fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
2377 /* if we are not doing reassembly and it was neither a complete PDU
2378 nor the first fragment then there is nothing more we can do
2379 so we just have to exit
2381 if( !dcerpc_reassemble ){
2385 /* if we didnt get 'frame' we dont know where the PDU started and thus
2386 it is pointless to continue
2393 /* from now on we must attempt to reassemble the PDU
2397 /* we dont have the full fragment so we just have to abort and exit
2399 if( !tvb_bytes_exist(tvb, offset, stub_length) ){
2404 /* if we get here we know it is the first time we see the packet
2405 and we also know it is only a fragment and not a full PDU,
2406 thus we must reassemble it.
2410 /* if this is the first fragment we need to start reassembly
2412 if(hdr->flags&PFC_FIRST_FRAG){
2413 fragment_add(tvb, offset, pinfo, frame,
2414 dcerpc_co_reassemble_table,
2415 0, stub_length, TRUE);
2416 fragment_set_tot_len(pinfo, frame,
2417 dcerpc_co_reassemble_table, alloc_hint);
2422 /* if this is a middle fragment, just add it and exit */
2423 if(!(hdr->flags&PFC_LAST_FRAG)){
2424 tot_len = fragment_get_tot_len(pinfo, frame,
2425 dcerpc_co_reassemble_table);
2426 fragment_add(tvb, offset, pinfo, frame,
2427 dcerpc_co_reassemble_table,
2435 /* this was the last fragment add it to reassembly
2437 tot_len = fragment_get_tot_len(pinfo, frame,
2438 dcerpc_co_reassemble_table);
2439 fd_head = fragment_add(tvb, offset, pinfo,
2441 dcerpc_co_reassemble_table,
2448 /* Show the fragment data. */
2451 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2452 "Fragment data (%d byte%s)",
2454 plurality(stub_length, "", "s"));
2458 /* if reassembly is complete, dissect the full PDU
2460 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
2461 if(pinfo->fd->num==fd_head->reassembled_in){
2464 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2465 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2466 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2467 show_fragment_tree(fd_head, &dcerpc_frag_items,
2468 dcerpc_tree, pinfo, next_tvb);
2470 pinfo->fragmented = FALSE;
2471 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
2472 0, hdr->drep, di, auth_info);
2474 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in, tvb, 0, 0, fd_head->reassembled_in);
2475 if (check_col(pinfo->cinfo, COL_INFO)) {
2476 col_append_fstr(pinfo->cinfo, COL_INFO,
2477 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2481 /* Reassembly not complete - some fragments
2483 if (check_col(pinfo->cinfo, COL_INFO)) {
2484 col_append_fstr(pinfo->cinfo, COL_INFO,
2485 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2489 pinfo->fragmented = save_fragmented;
2493 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2494 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2496 conversation_t *conv;
2500 dcerpc_auth_info auth_info;
2502 char uuid_str[DCERPC_UUID_STR_LEN];
2505 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2506 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2508 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2509 hf_dcerpc_cn_ctx_id, &ctx_id);
2511 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2512 hf_dcerpc_opnum, &opnum);
2514 if (check_col (pinfo->cinfo, COL_INFO)) {
2515 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
2519 if (hdr->flags & PFC_OBJECT_UUID) {
2520 /* XXX - use "dissect_ndr_uuid_t()"? */
2521 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
2523 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2524 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2525 obj_id.Data1, obj_id.Data2, obj_id.Data3,
2534 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2535 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2536 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
2537 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
2543 * XXX - what if this was set when the connection was set up,
2544 * and we just have a security context?
2546 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2548 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2549 pinfo->srcport, pinfo->destport, 0);
2551 show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2553 dcerpc_matched_key matched_key, *new_matched_key;
2554 dcerpc_call_value *value;
2556 /* !!! we can NOT check flags.visited here since this will interact
2557 badly with when SMB handles (i.e. calls the subdissector)
2558 and desegmented pdu's .
2559 Instead we check if this pdu is already in the matched table or not
2561 matched_key.frame = pinfo->fd->num;
2562 matched_key.call_id = hdr->call_id;
2563 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
2565 dcerpc_bind_key bind_key;
2566 dcerpc_bind_value *bind_value;
2569 bind_key.ctx_id=ctx_id;
2570 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
2572 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
2573 if(!(hdr->flags&PFC_FIRST_FRAG)){
2574 dcerpc_call_key call_key;
2575 dcerpc_call_value *call_value;
2578 call_key.call_id=hdr->call_id;
2579 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2580 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2581 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2582 *new_matched_key = matched_key;
2583 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2587 dcerpc_call_key *call_key;
2588 dcerpc_call_value *call_value;
2590 /* We found the binding and it is the first fragment
2591 (or a complete PDU) of a dcerpc pdu so just add
2592 the call to both the call table and the
2595 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
2596 call_key->conv=conv;
2597 call_key->call_id=hdr->call_id;
2598 call_key->smb_fid=get_smb_fid(pinfo->private_data);
2600 /* if there is already a matching call in the table
2601 remove it so it is replaced with the new one */
2602 if(g_hash_table_lookup(dcerpc_calls, call_key)){
2603 g_hash_table_remove(dcerpc_calls, call_key);
2606 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2607 call_value->uuid = bind_value->uuid;
2608 call_value->ver = bind_value->ver;
2609 call_value->opnum = opnum;
2610 call_value->req_frame=pinfo->fd->num;
2611 call_value->req_time.secs=pinfo->fd->abs_secs;
2612 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
2613 call_value->rep_frame=0;
2614 call_value->max_ptr=0;
2615 call_value->private_data = NULL;
2616 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2618 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2619 *new_matched_key = matched_key;
2620 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2629 /* handoff this call */
2631 di.call_id = hdr->call_id;
2632 di.smb_fid = get_smb_fid(pinfo->private_data);
2634 di.call_data = value;
2637 if(value->rep_frame!=0){
2638 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
2639 tvb, 0, 0, value->rep_frame);
2641 /*qqq request, broken*/
2642 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2643 hdr, &di, &auth_info, alloc_hint,
2646 show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2649 /* Decrypt the verifier, if present */
2650 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2654 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2655 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2657 dcerpc_call_value *value = NULL;
2658 conversation_t *conv;
2660 dcerpc_auth_info auth_info;
2663 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2664 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2666 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2667 hf_dcerpc_cn_ctx_id, &ctx_id);
2669 if (check_col (pinfo->cinfo, COL_INFO)) {
2670 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
2673 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2674 hf_dcerpc_cn_cancel_count, NULL);
2679 * XXX - what if this was set when the connection was set up,
2680 * and we just have a security context?
2682 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2684 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2685 pinfo->srcport, pinfo->destport, 0);
2687 /* no point in creating one here, really */
2688 show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2690 dcerpc_matched_key matched_key, *new_matched_key;
2692 /* !!! we can NOT check flags.visited here since this will interact
2693 badly with when SMB handles (i.e. calls the subdissector)
2694 and desegmented pdu's .
2695 Instead we check if this pdu is already in the matched table or not
2697 matched_key.frame = pinfo->fd->num;
2698 matched_key.call_id = hdr->call_id;
2699 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
2701 dcerpc_call_key call_key;
2702 dcerpc_call_value *call_value;
2705 call_key.call_id=hdr->call_id;
2706 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2708 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2709 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2710 *new_matched_key = matched_key;
2711 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2713 if(call_value->rep_frame==0){
2714 call_value->rep_frame=pinfo->fd->num;
2722 /* handoff this call */
2724 di.call_id = hdr->call_id;
2725 di.smb_fid = get_smb_fid(pinfo->private_data);
2727 di.call_data = value;
2729 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2730 if(value->req_frame!=0){
2732 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2733 tvb, 0, 0, value->req_frame);
2734 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2735 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2737 ns.nsecs+=1000000000;
2740 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2744 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2745 hdr, &di, &auth_info, alloc_hint,
2748 show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2751 /* Decrypt the verifier, if present */
2752 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2756 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2757 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2759 dcerpc_call_value *value = NULL;
2760 conversation_t *conv;
2764 dcerpc_auth_info auth_info;
2766 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2767 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2769 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2770 hf_dcerpc_cn_ctx_id, &ctx_id);
2772 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2773 hf_dcerpc_cn_cancel_count, NULL);
2777 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2778 hf_dcerpc_cn_status, &status);
2780 if (check_col (pinfo->cinfo, COL_INFO)) {
2781 col_append_fstr (pinfo->cinfo, COL_INFO,
2782 " ctx_id: %u status: %s", ctx_id,
2783 val_to_str(status, reject_status_vals,
2784 "Unknown (0x%08x)"));
2791 * XXX - what if this was set when the connection was set up,
2792 * and we just have a security context?
2794 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2796 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2797 pinfo->srcport, pinfo->destport, 0);
2799 /* no point in creating one here, really */
2801 dcerpc_matched_key matched_key, *new_matched_key;
2803 /* !!! we can NOT check flags.visited here since this will interact
2804 badly with when SMB handles (i.e. calls the subdissector)
2805 and desegmented pdu's .
2806 Instead we check if this pdu is already in the matched table or not
2808 matched_key.frame = pinfo->fd->num;
2809 matched_key.call_id = hdr->call_id;
2810 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
2812 dcerpc_call_key call_key;
2813 dcerpc_call_value *call_value;
2816 call_key.call_id=hdr->call_id;
2817 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2819 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2820 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2821 *new_matched_key = matched_key;
2822 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2824 if(call_value->rep_frame==0){
2825 call_value->rep_frame=pinfo->fd->num;
2832 int length, reported_length, stub_length;
2835 /* handoff this call */
2837 di.call_id = hdr->call_id;
2838 di.smb_fid = get_smb_fid(pinfo->private_data);
2840 di.call_data = value;
2842 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2843 if(value->req_frame!=0){
2845 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2846 tvb, 0, 0, value->req_frame);
2847 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2848 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2850 ns.nsecs+=1000000000;
2853 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2856 length = tvb_length_remaining(tvb, offset);
2857 reported_length = tvb_reported_length_remaining(tvb, offset);
2858 stub_length = hdr->frag_len - offset - auth_info.auth_size;
2859 if (length > stub_length)
2860 length = stub_length;
2861 if (reported_length > stub_length)
2862 reported_length = stub_length;
2864 /* If we don't have reassembly enabled, or this packet contains
2865 the entire PDU, or if we don't have all the data in this
2866 fragment, just call the handoff directly if this is the
2867 first fragment or the PDU isn't fragmented. */
2868 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
2869 !tvb_bytes_exist(tvb, offset, stub_length) ){
2870 if(hdr->flags&PFC_FIRST_FRAG){
2871 /* First fragment, possibly the only fragment */
2873 * XXX - should there be a third routine for each
2874 * function in an RPC subdissector, to handle
2875 * fault responses? The DCE RPC 1.1 spec says
2876 * three's "stub data" here, which I infer means
2877 * that it's protocol-specific and call-specific.
2879 * It should probably get passed the status code
2880 * as well, as that might be protocol-specific.
2883 if (stub_length > 0) {
2884 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2885 "Fault stub data (%d byte%s)",
2887 plurality(stub_length, "", "s"));
2891 /* PDU is fragmented and this isn't the first fragment */
2892 if (check_col(pinfo->cinfo, COL_INFO)) {
2893 col_append_fstr(pinfo->cinfo, COL_INFO,
2894 " [DCE/RPC fragment]");
2897 if (stub_length > 0) {
2898 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2899 "Fragment data (%d byte%s)",
2901 plurality(stub_length, "", "s"));
2906 /* Reassembly is enabled, the PDU is fragmented, and
2907 we have all the data in the fragment; the first two
2908 of those mean we should attempt reassembly, and the
2909 third means we can attempt reassembly. */
2912 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2913 "Fragment data (%d byte%s)",
2915 plurality(stub_length, "", "s"));
2918 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
2919 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2920 fragment_add(tvb, offset, pinfo, value->rep_frame,
2921 dcerpc_co_reassemble_table,
2925 fragment_set_tot_len(pinfo, value->rep_frame,
2926 dcerpc_co_reassemble_table, alloc_hint);
2928 if (check_col(pinfo->cinfo, COL_INFO)) {
2929 col_append_fstr(pinfo->cinfo, COL_INFO,
2930 " [DCE/RPC fragment]");
2932 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
2933 if( value->rep_frame ){
2934 fragment_data *fd_head;
2937 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2938 dcerpc_co_reassemble_table);
2939 fd_head = fragment_add(tvb, offset, pinfo,
2941 dcerpc_co_reassemble_table,
2947 /* We completed reassembly */
2950 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2951 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2952 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2953 show_fragment_tree(fd_head, &dcerpc_frag_items,
2954 dcerpc_tree, pinfo, next_tvb);
2957 * XXX - should there be a third routine for each
2958 * function in an RPC subdissector, to handle
2959 * fault responses? The DCE RPC 1.1 spec says
2960 * three's "stub data" here, which I infer means
2961 * that it's protocol-specific and call-specific.
2963 * It should probably get passed the status code
2964 * as well, as that might be protocol-specific.
2968 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2969 "Fault stub data (%d byte%s)",
2971 plurality(stub_length, "", "s"));
2975 /* Reassembly not complete - some fragments
2977 if (check_col(pinfo->cinfo, COL_INFO)) {
2978 col_append_fstr(pinfo->cinfo, COL_INFO,
2979 " [DCE/RPC fragment]");
2983 } else { /* MIDDLE fragment(s) */
2984 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2986 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2987 dcerpc_co_reassemble_table);
2988 fragment_add(tvb, offset, pinfo, value->rep_frame,
2989 dcerpc_co_reassemble_table,
2994 if (check_col(pinfo->cinfo, COL_INFO)) {
2995 col_append_fstr(pinfo->cinfo, COL_INFO,
2996 " [DCE/RPC fragment]");
3005 * DCERPC dissector for connection oriented calls
3008 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3009 proto_tree *tree, gboolean can_desegment)
3011 static char nulls[4] = { 0 };
3014 proto_item *ti = NULL;
3015 proto_item *tf = NULL;
3016 proto_tree *dcerpc_tree = NULL;
3017 proto_tree *cn_flags_tree = NULL;
3018 proto_tree *drep_tree = NULL;
3019 e_dce_cn_common_hdr_t hdr;
3020 dcerpc_auth_info auth_info;
3023 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3024 * data for some reason.
3026 * XXX - if that's always the case, the right way to do this would
3027 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3028 * the 4 bytes of null padding, and make that the dissector
3029 * used for "netbios".
3031 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3041 * Check if this looks like a C/O DCERPC call
3043 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3046 start_offset = offset;
3047 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3048 if (hdr.rpc_ver != 5)
3050 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3051 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3053 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3057 hdr.flags = tvb_get_guint8 (tvb, offset++);
3058 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3059 offset += sizeof (hdr.drep);
3061 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3063 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3065 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3068 if (can_desegment && pinfo->can_desegment
3069 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3070 pinfo->desegment_offset = start_offset;
3071 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3072 return 0; /* desegmentation required */
3075 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3076 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3077 if (check_col (pinfo->cinfo, COL_INFO))
3078 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3079 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3082 offset = start_offset;
3083 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3085 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3087 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
3088 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
3089 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
3090 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3091 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3092 if (cn_flags_tree) {
3093 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3094 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3095 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3096 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3097 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3098 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3099 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3100 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3104 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3105 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3107 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3108 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3109 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3111 offset += sizeof (hdr.drep);
3113 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3116 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3119 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3124 * Packet type specific stuff is next.
3126 switch (hdr.ptype) {
3129 dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr);
3134 dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3139 * Nothing after the common header other than credentials.
3141 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, TRUE,
3146 dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3150 dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3154 dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3158 dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
3164 * Nothing after the common header other than an authentication
3167 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
3173 * Nothing after the common header, not even an authentication
3179 /* might as well dissect the auth info */
3180 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
3184 return hdr.frag_len + padding;
3188 * DCERPC dissector for connection oriented calls over packet-oriented
3192 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3195 * Only one PDU per transport packet, and only one transport
3198 if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
3200 * It wasn't a DCERPC PDU.
3212 * DCERPC dissector for connection oriented calls over byte-stream
3216 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3220 gboolean ret = FALSE;
3223 * There may be multiple PDUs per transport packet; keep
3226 while (tvb_reported_length_remaining(tvb, offset) != 0) {
3227 pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
3228 dcerpc_cn_desegment);
3229 if (pdu_len == -1) {
3237 * Well, we've seen at least one DCERPC PDU.
3243 * Desegmentation required - bail now.
3249 * Step to the next PDU.
3257 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
3258 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
3260 proto_item *ti = NULL;
3261 proto_tree *auth_tree = NULL;
3262 guint8 protection_level;
3265 * Initially set "*auth_level_p" to -1 to indicate that we haven't
3266 * yet seen any authentication level information.
3268 if (auth_level_p != NULL)
3272 * The authentication information is at the *end* of the PDU; in
3273 * request and response PDUs, the request and response stub data
3276 * If the full packet is here, and there's data past the end of the
3277 * packet body, then dissect the auth info.
3279 offset += hdr->frag_len;
3280 if (tvb_length_remaining(tvb, offset) > 0) {
3281 switch (hdr->auth_proto) {
3283 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
3284 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
3285 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
3286 protection_level = tvb_get_guint8 (tvb, offset);
3287 if (auth_level_p != NULL)
3288 *auth_level_p = protection_level;
3289 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
3291 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
3293 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
3294 offset += 6; /* 6 bytes of padding */
3296 offset += 2; /* 6 bytes of padding */
3297 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
3302 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
3309 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3310 proto_tree *dcerpc_tree,
3311 e_dce_dg_common_hdr_t *hdr)
3315 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3316 hdr->drep, hf_dcerpc_dg_cancel_vers,
3322 /* The only version we know about */
3323 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3324 hdr->drep, hf_dcerpc_dg_cancel_id,
3326 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3327 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3334 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
3335 proto_tree *dcerpc_tree,
3336 e_dce_dg_common_hdr_t *hdr)
3340 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3341 hdr->drep, hf_dcerpc_dg_cancel_vers,
3347 /* The only version we know about */
3348 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3349 hdr->drep, hf_dcerpc_dg_cancel_id,
3351 /* XXX - are NDR booleans 32 bits? */
3352 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3353 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3360 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3361 proto_tree *dcerpc_tree,
3362 e_dce_dg_common_hdr_t *hdr)
3369 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3370 hdr->drep, hf_dcerpc_dg_fack_vers,
3377 case 0: /* The only version documented in the DCE RPC 1.1 spec */
3378 case 1: /* This appears to be the same */
3379 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3380 hdr->drep, hf_dcerpc_dg_fack_window_size,
3382 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3383 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
3385 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3386 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
3388 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3389 hdr->drep, hf_dcerpc_dg_fack_serial_num,
3391 if (check_col (pinfo->cinfo, COL_INFO)) {
3392 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3395 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3396 hdr->drep, hf_dcerpc_dg_fack_selack_len,
3398 for (i = 0; i < selack_len; i++) {
3399 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3400 hdr->drep, hf_dcerpc_dg_fack_selack,
3409 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
3410 proto_tree *dcerpc_tree,
3411 e_dce_dg_common_hdr_t *hdr)
3415 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3416 hdr->drep, hf_dcerpc_dg_status,
3419 if (check_col (pinfo->cinfo, COL_INFO)) {
3420 col_append_fstr (pinfo->cinfo, COL_INFO,
3422 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3427 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
3428 proto_tree *dcerpc_tree, proto_tree *tree,
3429 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
3431 int length, reported_length, stub_length;
3432 gboolean save_fragmented;
3433 fragment_data *fd_head;
3435 if (check_col (pinfo->cinfo, COL_INFO)) {
3436 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u",
3437 di->call_data->opnum);
3440 length = tvb_length_remaining (tvb, offset);
3441 reported_length = tvb_reported_length_remaining (tvb, offset);
3442 stub_length = hdr->frag_len;
3443 if (length > stub_length)
3444 length = stub_length;
3445 if (reported_length > stub_length)
3446 reported_length = stub_length;
3448 save_fragmented = pinfo->fragmented;
3450 /* If we don't have reassembly enabled, or this packet contains
3451 the entire PDU, or if this is a short frame (or a frame
3452 not reassembled at a lower layer) that doesn't include all
3453 the data in the fragment, just call the handoff directly if
3454 this is the first fragment or the PDU isn't fragmented. */
3455 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
3456 !tvb_bytes_exist(tvb, offset, stub_length) ){
3457 if(hdr->frag_num == 0) {
3458 /* First fragment, possibly the only fragment */
3461 * XXX - authentication info?
3463 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
3464 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
3465 tvb_new_subset (tvb, offset, length,
3467 0, hdr->drep, di, NULL);
3469 /* PDU is fragmented and this isn't the first fragment */
3470 if (check_col(pinfo->cinfo, COL_INFO)) {
3471 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3475 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3476 "Fragment data (%d byte%s)",
3478 plurality(stub_length, "", "s"));
3483 /* Reassembly is enabled, the PDU is fragmented, and
3484 we have all the data in the fragment; the first two
3485 of those mean we should attempt reassembly, and the
3486 third means we can attempt reassembly. */
3489 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3490 "Fragment data (%d byte%s)", stub_length,
3491 plurality(stub_length, "", "s"));
3495 fd_head = fragment_add_seq(tvb, offset, pinfo,
3496 hdr->seqnum, dcerpc_cl_reassemble_table,
3497 hdr->frag_num, stub_length,
3498 !(hdr->flags1 & PFCL1_LASTFRAG));
3499 if (fd_head != NULL) {
3500 /* We completed reassembly */
3503 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3504 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3505 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3506 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
3507 dcerpc_tree, pinfo, next_tvb);
3510 * XXX - authentication info?
3512 pinfo->fragmented = FALSE;
3513 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3514 0, hdr->drep, di, NULL);
3516 /* Reassembly isn't completed yet */
3517 if (check_col(pinfo->cinfo, COL_INFO)) {
3518 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3522 pinfo->fragmented = save_fragmented;
3526 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
3527 proto_tree *dcerpc_tree, proto_tree *tree,
3528 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3531 dcerpc_call_value *value, v;
3532 dcerpc_matched_key matched_key, *new_matched_key;
3534 if(!(pinfo->fd->flags.visited)){
3535 dcerpc_call_value *call_value;
3536 dcerpc_call_key *call_key;
3538 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
3539 call_key->conv=conv;
3540 call_key->call_id=hdr->seqnum;
3541 call_key->smb_fid=get_smb_fid(pinfo->private_data);
3543 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
3544 call_value->uuid = hdr->if_id;
3545 call_value->ver = hdr->if_ver;
3546 call_value->opnum = hdr->opnum;
3547 call_value->req_frame=pinfo->fd->num;
3548 call_value->req_time.secs=pinfo->fd->abs_secs;
3549 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3550 call_value->rep_frame=0;
3551 call_value->max_ptr=0;
3552 call_value->private_data = NULL;
3553 g_hash_table_insert (dcerpc_calls, call_key, call_value);
3555 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3556 new_matched_key->frame = pinfo->fd->num;
3557 new_matched_key->call_id = hdr->seqnum;
3558 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3561 matched_key.frame = pinfo->fd->num;
3562 matched_key.call_id = hdr->seqnum;
3563 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3565 v.uuid = hdr->if_id;
3566 v.ver = hdr->if_ver;
3567 v.opnum = hdr->opnum;
3568 v.req_frame = pinfo->fd->num;
3571 v.private_data=NULL;
3576 di.call_id = hdr->seqnum;
3579 di.call_data = value;
3581 if(value->rep_frame!=0){
3582 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3583 tvb, 0, 0, value->rep_frame);
3585 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
3589 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
3590 proto_tree *dcerpc_tree, proto_tree *tree,
3591 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3594 dcerpc_call_value *value, v;
3595 dcerpc_matched_key matched_key, *new_matched_key;
3597 if(!(pinfo->fd->flags.visited)){
3598 dcerpc_call_value *call_value;
3599 dcerpc_call_key call_key;
3602 call_key.call_id=hdr->seqnum;
3603 call_key.smb_fid=get_smb_fid(pinfo->private_data);
3605 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
3606 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3607 new_matched_key->frame = pinfo->fd->num;
3608 new_matched_key->call_id = hdr->seqnum;
3609 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3610 if(call_value->rep_frame==0){
3611 call_value->rep_frame=pinfo->fd->num;
3616 matched_key.frame = pinfo->fd->num;
3617 matched_key.call_id = hdr->seqnum;
3618 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3620 v.uuid = hdr->if_id;
3621 v.ver = hdr->if_ver;
3622 v.opnum = hdr->opnum;
3624 v.rep_frame=pinfo->fd->num;
3625 v.private_data=NULL;
3633 di.call_data = value;
3635 if(value->req_frame!=0){
3637 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3638 tvb, 0, 0, value->req_frame);
3639 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3640 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3642 ns.nsecs+=1000000000;
3645 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3647 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
3651 * DCERPC dissector for connectionless calls
3654 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3656 proto_item *ti = NULL;
3657 proto_item *tf = NULL;
3658 proto_tree *dcerpc_tree = NULL;
3659 proto_tree *dg_flags1_tree = NULL;
3660 proto_tree *dg_flags2_tree = NULL;
3661 proto_tree *drep_tree = NULL;
3662 e_dce_dg_common_hdr_t hdr;
3664 conversation_t *conv;
3666 char uuid_str[DCERPC_UUID_STR_LEN];
3670 * Check if this looks like a CL DCERPC call. All dg packets
3671 * have an 80 byte header on them. Which starts with
3672 * version (4), pkt_type.
3674 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
3677 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3678 if (hdr.rpc_ver != 4)
3680 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3684 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3685 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3686 if (check_col (pinfo->cinfo, COL_INFO))
3687 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
3689 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
3690 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
3691 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3692 offset += sizeof (hdr.drep);
3693 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
3694 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
3696 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
3698 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
3700 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3702 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3704 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3706 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3708 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3710 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3712 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3714 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3716 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
3717 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
3720 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
3722 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
3728 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3732 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3736 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
3737 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
3738 if (dg_flags1_tree) {
3739 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
3740 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
3741 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
3742 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
3743 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
3744 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
3745 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
3746 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
3752 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
3753 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
3754 if (dg_flags2_tree) {
3755 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
3756 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
3757 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
3758 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
3759 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
3760 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
3761 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
3762 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
3768 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
3769 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3771 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3772 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3773 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3776 offset += sizeof (hdr.drep);
3779 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
3783 /* XXX - use "dissect_ndr_uuid_t()"? */
3784 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3785 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3786 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
3787 hdr.obj_id.Data4[0],
3788 hdr.obj_id.Data4[1],
3789 hdr.obj_id.Data4[2],
3790 hdr.obj_id.Data4[3],
3791 hdr.obj_id.Data4[4],
3792 hdr.obj_id.Data4[5],
3793 hdr.obj_id.Data4[6],
3794 hdr.obj_id.Data4[7]);
3795 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3796 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3797 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3798 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
3803 /* XXX - use "dissect_ndr_uuid_t()"? */
3804 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3805 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3806 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
3814 hdr.if_id.Data4[7]);
3815 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3816 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3817 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
3818 offset, 16, uuid_str, "Interface: %s", uuid_str);
3823 /* XXX - use "dissect_ndr_uuid_t()"? */
3824 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3825 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3826 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
3827 hdr.act_id.Data4[0],
3828 hdr.act_id.Data4[1],
3829 hdr.act_id.Data4[2],
3830 hdr.act_id.Data4[3],
3831 hdr.act_id.Data4[4],
3832 hdr.act_id.Data4[5],
3833 hdr.act_id.Data4[6],
3834 hdr.act_id.Data4[7]);
3835 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3836 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3837 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
3838 offset, 16, uuid_str, "Activity: %s", uuid_str);
3843 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
3847 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
3851 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
3852 if (check_col (pinfo->cinfo, COL_INFO)) {
3853 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq_num: %u", hdr.seqnum);
3858 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
3862 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
3866 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
3870 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
3874 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
3875 if (check_col (pinfo->cinfo, COL_INFO)) {
3876 if (hdr.flags1 & PFCL1_FRAG) {
3877 /* Fragmented - put the fragment number into the Info column */
3878 col_append_fstr (pinfo->cinfo, COL_INFO, " frag_num: %u",
3885 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
3889 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
3890 if (check_col (pinfo->cinfo, COL_INFO)) {
3891 if (hdr.flags1 & PFCL1_FRAG) {
3892 /* Fragmented - put the serial number into the Info column */
3893 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3894 (hdr.serial_hi << 8) | hdr.serial_lo);
3901 * XXX - for Kerberos, we get a protection level; if it's
3902 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
3905 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
3910 * keeping track of the conversation shouldn't really be necessary
3911 * for connectionless packets, because everything we need to know
3912 * to dissect is in the header for each packet. Unfortunately,
3913 * Microsoft's implementation is buggy and often puts the
3914 * completely wrong if_id in the header. go figure. So, keep
3915 * track of the seqnum and use that if possible. Note: that's not
3916 * completely correct. It should really be done based on both the
3917 * activity_id and seqnum. I haven't seen anywhere that it would
3918 * make a difference, but for future reference...
3920 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
3921 pinfo->srcport, pinfo->destport, 0);
3923 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
3924 pinfo->srcport, pinfo->destport, 0);
3928 * Packet type specific stuff is next.
3931 switch (hdr.ptype) {
3933 case PDU_CANCEL_ACK:
3934 /* Body is optional */
3935 /* XXX - we assume "frag_len" is the length of the body */
3936 if (hdr.frag_len != 0)
3937 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3942 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
3943 * but in at least one capture none of the Cl_cancel PDUs had a
3946 /* XXX - we assume "frag_len" is the length of the body */
3947 if (hdr.frag_len != 0)
3948 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
3952 /* Body is optional; if present, it's the same as PDU_FACK */
3953 /* XXX - we assume "frag_len" is the length of the body */
3954 if (hdr.frag_len != 0)
3955 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3959 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3964 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3968 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
3972 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
3975 /* these requests have no body */
3987 dcerpc_init_protocol (void)
3989 /* structures and data for BIND */
3991 g_hash_table_destroy (dcerpc_binds);
3993 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
3995 if (dcerpc_bind_key_chunk){
3996 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
3998 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
3999 sizeof (dcerpc_bind_key),
4000 200 * sizeof (dcerpc_bind_key),
4002 if (dcerpc_bind_value_chunk){
4003 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
4005 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
4006 sizeof (dcerpc_bind_value),
4007 200 * sizeof (dcerpc_bind_value),
4009 /* structures and data for CALL */
4011 g_hash_table_destroy (dcerpc_calls);
4013 dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
4014 if (dcerpc_call_key_chunk){
4015 g_mem_chunk_destroy (dcerpc_call_key_chunk);
4017 dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
4018 sizeof (dcerpc_call_key),
4019 200 * sizeof (dcerpc_call_key),
4021 if (dcerpc_call_value_chunk){
4022 g_mem_chunk_destroy (dcerpc_call_value_chunk);
4024 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
4025 sizeof (dcerpc_call_value),
4026 200 * sizeof (dcerpc_call_value),
4029 /* structure and data for MATCHED */
4030 if (dcerpc_matched){
4031 g_hash_table_destroy (dcerpc_matched);
4033 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
4034 if (dcerpc_matched_key_chunk){
4035 g_mem_chunk_destroy (dcerpc_matched_key_chunk);
4037 dcerpc_matched_key_chunk = g_mem_chunk_new ("dcerpc_matched_key_chunk",
4038 sizeof (dcerpc_matched_key),
4039 200 * sizeof (dcerpc_matched_key),
4044 proto_register_dcerpc (void)
4046 static hf_register_info hf[] = {
4047 { &hf_dcerpc_request_in,
4048 { "Request in", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
4049 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
4050 { &hf_dcerpc_response_in,
4051 { "Response in", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
4052 NULL, 0, "The response to this packet is in this packet", HFILL }},
4053 { &hf_dcerpc_referent_id,
4054 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
4055 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
4057 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4058 { &hf_dcerpc_ver_minor,
4059 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4060 { &hf_dcerpc_packet_type,
4061 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
4062 { &hf_dcerpc_cn_flags,
4063 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4064 { &hf_dcerpc_cn_flags_first_frag,
4065 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
4066 { &hf_dcerpc_cn_flags_last_frag,
4067 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
4068 { &hf_dcerpc_cn_flags_cancel_pending,
4069 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
4070 { &hf_dcerpc_cn_flags_reserved,
4071 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
4072 { &hf_dcerpc_cn_flags_mpx,
4073 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
4074 { &hf_dcerpc_cn_flags_dne,
4075 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
4076 { &hf_dcerpc_cn_flags_maybe,
4077 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
4078 { &hf_dcerpc_cn_flags_object,
4079 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
4081 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
4082 { &hf_dcerpc_drep_byteorder,
4083 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
4084 { &hf_dcerpc_drep_character,
4085 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
4086 { &hf_dcerpc_drep_fp,
4087 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
4088 { &hf_dcerpc_cn_frag_len,
4089 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4090 { &hf_dcerpc_cn_auth_len,
4091 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4092 { &hf_dcerpc_cn_call_id,
4093 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4094 { &hf_dcerpc_cn_max_xmit,
4095 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4096 { &hf_dcerpc_cn_max_recv,
4097 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4098 { &hf_dcerpc_cn_assoc_group,
4099 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4100 { &hf_dcerpc_cn_num_ctx_items,
4101 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4102 { &hf_dcerpc_cn_ctx_id,
4103 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4104 { &hf_dcerpc_cn_num_trans_items,
4105 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4106 { &hf_dcerpc_cn_bind_if_id,
4107 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4108 { &hf_dcerpc_cn_bind_if_ver,
4109 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4110 { &hf_dcerpc_cn_bind_if_ver_minor,
4111 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4112 { &hf_dcerpc_cn_bind_trans_id,
4113 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4114 { &hf_dcerpc_cn_bind_trans_ver,
4115 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4116 { &hf_dcerpc_cn_alloc_hint,
4117 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4118 { &hf_dcerpc_cn_sec_addr_len,
4119 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4120 { &hf_dcerpc_cn_sec_addr,
4121 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
4122 { &hf_dcerpc_cn_num_results,
4123 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4124 { &hf_dcerpc_cn_ack_result,
4125 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
4126 { &hf_dcerpc_cn_ack_reason,
4127 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
4128 { &hf_dcerpc_cn_ack_trans_id,
4129 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4130 { &hf_dcerpc_cn_ack_trans_ver,
4131 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4132 { &hf_dcerpc_cn_reject_reason,
4133 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
4134 { &hf_dcerpc_cn_num_protocols,
4135 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4136 { &hf_dcerpc_cn_protocol_ver_major,
4137 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4138 { &hf_dcerpc_cn_protocol_ver_minor,
4139 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4140 { &hf_dcerpc_cn_cancel_count,
4141 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4142 { &hf_dcerpc_cn_status,
4143 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4144 { &hf_dcerpc_auth_type,
4145 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4146 { &hf_dcerpc_auth_level,
4147 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
4148 { &hf_dcerpc_auth_pad_len,
4149 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4150 { &hf_dcerpc_auth_rsrvd,
4151 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4152 { &hf_dcerpc_auth_ctx_id,
4153 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4154 { &hf_dcerpc_dg_flags1,
4155 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4156 { &hf_dcerpc_dg_flags1_rsrvd_01,
4157 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
4158 { &hf_dcerpc_dg_flags1_last_frag,
4159 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
4160 { &hf_dcerpc_dg_flags1_frag,
4161 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
4162 { &hf_dcerpc_dg_flags1_nofack,
4163 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
4164 { &hf_dcerpc_dg_flags1_maybe,
4165 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
4166 { &hf_dcerpc_dg_flags1_idempotent,
4167 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
4168 { &hf_dcerpc_dg_flags1_broadcast,
4169 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
4170 { &hf_dcerpc_dg_flags1_rsrvd_80,
4171 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
4172 { &hf_dcerpc_dg_flags2,
4173 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4174 { &hf_dcerpc_dg_flags2_rsrvd_01,
4175 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
4176 { &hf_dcerpc_dg_flags2_cancel_pending,
4177 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
4178 { &hf_dcerpc_dg_flags2_rsrvd_04,
4179 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
4180 { &hf_dcerpc_dg_flags2_rsrvd_08,
4181 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
4182 { &hf_dcerpc_dg_flags2_rsrvd_10,
4183 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
4184 { &hf_dcerpc_dg_flags2_rsrvd_20,
4185 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
4186 { &hf_dcerpc_dg_flags2_rsrvd_40,
4187 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
4188 { &hf_dcerpc_dg_flags2_rsrvd_80,
4189 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
4190 { &hf_dcerpc_dg_serial_lo,
4191 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4192 { &hf_dcerpc_dg_serial_hi,
4193 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4194 { &hf_dcerpc_dg_ahint,
4195 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4196 { &hf_dcerpc_dg_ihint,
4197 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4198 { &hf_dcerpc_dg_frag_len,
4199 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4200 { &hf_dcerpc_dg_frag_num,
4201 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4202 { &hf_dcerpc_dg_auth_proto,
4203 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4204 { &hf_dcerpc_dg_seqnum,
4205 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4206 { &hf_dcerpc_dg_server_boot,
4207 { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4208 { &hf_dcerpc_dg_if_ver,
4209 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4210 { &hf_dcerpc_krb5_av_prot_level,
4211 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
4212 { &hf_dcerpc_krb5_av_key_vers_num,
4213 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4214 { &hf_dcerpc_krb5_av_key_auth_verifier,
4215 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
4216 { &hf_dcerpc_obj_id,
4217 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4218 { &hf_dcerpc_dg_if_id,
4219 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4220 { &hf_dcerpc_dg_act_id,
4221 { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4223 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4225 { &hf_dcerpc_dg_cancel_vers,
4226 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4228 { &hf_dcerpc_dg_cancel_id,
4229 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4231 { &hf_dcerpc_dg_server_accepting_cancels,
4232 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
4234 { &hf_dcerpc_dg_fack_vers,
4235 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4237 { &hf_dcerpc_dg_fack_window_size,
4238 { "Window Size", "dcerpc.fack_window size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4240 { &hf_dcerpc_dg_fack_max_tsdu,
4241 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4243 { &hf_dcerpc_dg_fack_max_frag_size,
4244 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4246 { &hf_dcerpc_dg_fack_serial_num,
4247 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4249 { &hf_dcerpc_dg_fack_selack_len,
4250 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4252 { &hf_dcerpc_dg_fack_selack,
4253 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4255 { &hf_dcerpc_dg_status,
4256 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4258 { &hf_dcerpc_array_max_count,
4259 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
4261 { &hf_dcerpc_array_offset,
4262 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
4264 { &hf_dcerpc_array_actual_count,
4265 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
4267 { &hf_dcerpc_array_buffer,
4268 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
4271 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4273 { &hf_dcerpc_fragments,
4274 { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
4275 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
4277 { &hf_dcerpc_fragment,
4278 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
4279 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
4281 { &hf_dcerpc_fragment_overlap,
4282 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
4284 { &hf_dcerpc_fragment_overlap_conflict,
4285 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
4287 { &hf_dcerpc_fragment_multiple_tails,
4288 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
4290 { &hf_dcerpc_fragment_too_long_fragment,
4291 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
4293 { &hf_dcerpc_fragment_error,
4294 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
4297 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "Time between Request and Reply for DCE-RPC calls", HFILL }},
4298 { &hf_dcerpc_reassembled_in,
4299 { "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 }},
4300 { &hf_dcerpc_sec_chan,
4301 { "Verifier", "verifier", FT_NONE, BASE_NONE, NULL, 0x0, "Verifier",
4303 { &hf_dcerpc_sec_chan_sig,
4304 { "Signature", "dcerpc.sec_chan.sig", FT_BYTES, BASE_HEX, NULL,
4305 0x0, "Signature", HFILL }},
4306 { &hf_dcerpc_sec_chan_unk,
4307 { "Unknown", "dcerpc.sec_chan.unk", FT_BYTES, BASE_HEX, NULL,
4308 0x0, "Unknown", HFILL }},
4309 { &hf_dcerpc_sec_chan_seq,
4310 { "Sequence No", "dcerpc.sec_chan.seq", FT_BYTES, BASE_HEX, NULL,
4311 0x0, "Sequence No", HFILL }},
4312 { &hf_dcerpc_sec_chan_nonce,
4313 { "Nonce", "dcerpc.sec_chan.nonce", FT_BYTES, BASE_HEX, NULL,
4314 0x0, "Nonce", HFILL }},
4317 static gint *ett[] = {
4319 &ett_dcerpc_cn_flags,
4321 &ett_dcerpc_dg_flags1,
4322 &ett_dcerpc_dg_flags2,
4323 &ett_dcerpc_pointer_data,
4325 &ett_dcerpc_fragments,
4326 &ett_dcerpc_fragment,
4327 &ett_dcerpc_krb5_auth_verf,
4330 module_t *dcerpc_module;
4332 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
4333 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
4334 proto_register_subtree_array (ett, array_length (ett));
4335 register_init_routine (dcerpc_init_protocol);
4336 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
4337 prefs_register_bool_preference (dcerpc_module,
4339 "Desegment all DCE/RPC over TCP",
4340 "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
4341 &dcerpc_cn_desegment);
4342 prefs_register_bool_preference (dcerpc_module,
4343 "reassemble_dcerpc",
4344 "Reassemble DCE/RPC fragments",
4345 "Whether the DCE/RPC dissector should reassemble all fragmented PDUs",
4346 &dcerpc_reassemble);
4347 register_init_routine(dcerpc_reassemble_init);
4348 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
4349 dcerpc_tap=register_tap("dcerpc");
4353 proto_reg_handoff_dcerpc (void)
4355 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
4356 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
4357 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
4358 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
4359 ntlmssp_handle = find_dissector("ntlmssp");
4360 ntlmssp_verf_handle = find_dissector("ntlmssp_verf");
4361 ntlmssp_enc_payload_handle = find_dissector("ntlmssp_encrypted_payload");
4362 gssapi_handle = find_dissector("gssapi");
4363 gssapi_verf_handle = find_dissector("gssapi_verf");
4364 dcerpc_smb_init(proto_dcerpc);