2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas@webspan.net>
5 * $Id: packet-dcerpc.c,v 1.129 2003/06/12 08:33:29 guy 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 /* Function to find the subdissector table of a registered protocol
528 * or NULL if the protocol/version is not known to ethereal.
530 dcerpc_sub_dissector *
531 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
534 dcerpc_uuid_value *sub_proto;
538 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
541 return sub_proto->procs;
546 * To keep track of ctx_id mappings.
548 * Everytime we see a bind call we update this table.
549 * Note that we always specify a SMB FID. For non-SMB transports this
552 static GHashTable *dcerpc_binds=NULL;
554 typedef struct _dcerpc_bind_key {
555 conversation_t *conv;
560 typedef struct _dcerpc_bind_value {
565 static GMemChunk *dcerpc_bind_key_chunk=NULL;
566 static GMemChunk *dcerpc_bind_value_chunk=NULL;
569 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
571 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
572 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
573 return (key1->conv == key2->conv
574 && key1->ctx_id == key2->ctx_id
575 && key1->smb_fid == key2->smb_fid);
579 dcerpc_bind_hash (gconstpointer k)
581 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
582 return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
587 * To keep track of callid mappings. Should really use some generic
588 * conversation support instead.
590 static GHashTable *dcerpc_calls=NULL;
592 typedef struct _dcerpc_call_key {
593 conversation_t *conv;
598 static GMemChunk *dcerpc_call_key_chunk=NULL;
600 static GMemChunk *dcerpc_call_value_chunk=NULL;
603 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
605 const dcerpc_call_key *key1 = (const dcerpc_call_key *)k1;
606 const dcerpc_call_key *key2 = (const dcerpc_call_key *)k2;
607 return (key1->conv == key2->conv
608 && key1->call_id == key2->call_id
609 && key1->smb_fid == key2->smb_fid);
613 dcerpc_call_hash (gconstpointer k)
615 const dcerpc_call_key *key = (const dcerpc_call_key *)k;
616 return ((guint32)key->conv) + key->call_id + key->smb_fid;
620 /* to keep track of matched calls/responses
621 this one uses the same value struct as calls, but the key is the frame id
622 and call id; there can be more than one call in a frame.
624 XXX - why not just use the same keys as are used for calls?
627 static GHashTable *dcerpc_matched=NULL;
629 typedef struct _dcerpc_matched_key {
632 } dcerpc_matched_key;
634 static GMemChunk *dcerpc_matched_key_chunk=NULL;
637 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
639 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
640 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
641 return (key1->frame == key2->frame
642 && key1->call_id == key2->call_id);
646 dcerpc_matched_hash (gconstpointer k)
648 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
655 * Utility functions. Modeled after packet-rpc.c
659 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
660 proto_tree *tree, char *drep,
661 int hfindex, guint8 *pdata)
665 data = tvb_get_guint8 (tvb, offset);
667 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
675 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
676 proto_tree *tree, char *drep,
677 int hfindex, guint16 *pdata)
681 data = ((drep[0] & 0x10)
682 ? tvb_get_letohs (tvb, offset)
683 : tvb_get_ntohs (tvb, offset));
686 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
694 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
695 proto_tree *tree, char *drep,
696 int hfindex, guint32 *pdata)
700 data = ((drep[0] & 0x10)
701 ? tvb_get_letohl (tvb, offset)
702 : tvb_get_ntohl (tvb, offset));
705 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
712 /* handles 32 bit unix time_t */
714 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
715 proto_tree *tree, char *drep,
716 int hfindex, guint32 *pdata)
721 data = ((drep[0] & 0x10)
722 ? tvb_get_letohl (tvb, offset)
723 : tvb_get_ntohl (tvb, offset));
728 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
737 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
738 proto_tree *tree, char *drep,
739 int hfindex, unsigned char *pdata)
742 tvb_memcpy(tvb, pdata, offset, 8);
743 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
745 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
746 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
747 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
748 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
753 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
761 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
762 proto_tree *tree, char *drep,
763 int hfindex, gfloat *pdata)
769 case(DCE_RPC_DREP_FP_IEEE):
770 data = ((drep[0] & 0x10)
771 ? tvb_get_letohieee_float(tvb, offset)
772 : tvb_get_ntohieee_float(tvb, offset));
774 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
777 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
778 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
779 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
781 /* ToBeDone: non IEEE floating formats */
782 /* Set data to a negative infinity value */
783 data = -1.0 * 1e100 * 1e100;
785 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
795 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
796 proto_tree *tree, char *drep,
797 int hfindex, gdouble *pdata)
803 case(DCE_RPC_DREP_FP_IEEE):
804 data = ((drep[0] & 0x10)
805 ? tvb_get_letohieee_double(tvb, offset)
806 : tvb_get_ntohieee_double(tvb, offset));
808 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
811 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
812 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
813 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
815 /* ToBeDone: non IEEE double formats */
816 /* Set data to a negative infinity value */
817 data = -1.0 * 1e100 * 1e100;
819 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
829 * a couple simpler things
832 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
834 if (drep[0] & 0x10) {
835 return tvb_get_letohs (tvb, offset);
837 return tvb_get_ntohs (tvb, offset);
842 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
844 if (drep[0] & 0x10) {
845 return tvb_get_letohl (tvb, offset);
847 return tvb_get_ntohl (tvb, offset);
852 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
855 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
856 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
857 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
859 for (i=0; i<sizeof (uuid->Data4); i++) {
860 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
867 /* function to dissect a unidimensional conformant array */
869 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
870 proto_tree *tree, char *drep,
871 dcerpc_dissect_fnct_t *fnct)
877 di=pinfo->private_data;
878 if(di->conformant_run){
879 /* conformant run, just dissect the max_count header */
881 di->conformant_run=0;
882 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
883 hf_dcerpc_array_max_count, &di->array_max_count);
884 di->array_max_count_offset=offset-4;
885 di->conformant_run=1;
886 di->conformant_eaten=offset-old_offset;
888 /* we don't remember where in the bytestream this field was */
889 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
891 /* real run, dissect the elements */
892 for(i=0;i<di->array_max_count;i++){
893 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
899 /* function to dissect a unidimensional conformant and varying array */
901 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
902 proto_tree *tree, char *drep,
903 dcerpc_dissect_fnct_t *fnct)
909 di=pinfo->private_data;
910 if(di->conformant_run){
911 /* conformant run, just dissect the max_count header */
913 di->conformant_run=0;
914 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
915 hf_dcerpc_array_max_count, &di->array_max_count);
916 di->array_max_count_offset=offset-4;
917 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
918 hf_dcerpc_array_offset, &di->array_offset);
919 di->array_offset_offset=offset-4;
920 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
921 hf_dcerpc_array_actual_count, &di->array_actual_count);
922 di->array_actual_count_offset=offset-4;
923 di->conformant_run=1;
924 di->conformant_eaten=offset-old_offset;
926 /* we dont dont remember where in the bytestream these fields were */
927 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
928 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
929 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
931 /* real run, dissect the elements */
932 for(i=0;i<di->array_actual_count;i++){
933 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
940 /* Dissect an string of bytes. This corresponds to
941 IDL of the form '[string] byte *foo'.
943 It can also be used for a conformant varying array of bytes if
944 the contents of the array should be shown as a big blob, rather
945 than showing each byte as an individual element.
947 XXX - which of those is really the IDL type for, for example,
948 the encrypted data in some MAPI packets? (Microsoft haven't
951 XXX - does this need to do all the conformant array stuff that
952 "dissect_ndr_ucvarray()" does? These are presumably for strings
953 that are conformant and varying - they're stored like conformant
954 varying arrays of bytes. */
956 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
957 proto_tree *tree, char *drep)
962 di=pinfo->private_data;
963 if(di->conformant_run){
964 /* just a run to handle conformant arrays, no scalars to dissect */
968 /* NDR array header */
970 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
971 hf_dcerpc_array_max_count, NULL);
973 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
974 hf_dcerpc_array_offset, NULL);
976 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
977 hf_dcerpc_array_actual_count, &len);
980 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
981 tvb, offset, len, drep[0] & 0x10);
988 /* For dissecting arrays that are to be interpreted as strings. */
990 /* Dissect an NDR conformant varying string of elements.
991 The length of each element is given by the 'size_is' parameter;
992 the elements are assumed to be characters or wide characters.
994 XXX - does this need to do all the conformant array stuff that
995 "dissect_ndr_ucvarray()" does? */
997 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
998 proto_tree *tree, char *drep, int size_is,
999 int hfindex, gboolean add_subtree, char **data)
1002 proto_item *string_item;
1003 proto_tree *string_tree;
1004 guint32 len, buffer_len;
1006 header_field_info *hfinfo;
1008 di=pinfo->private_data;
1009 if(di->conformant_run){
1010 /* just a run to handle conformant arrays, no scalars to dissect */
1015 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1016 proto_registrar_get_name(hfindex));
1017 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1023 /* NDR array header */
1025 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1026 hf_dcerpc_array_max_count, NULL);
1028 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1029 hf_dcerpc_array_offset, NULL);
1031 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1032 hf_dcerpc_array_actual_count, &len);
1034 buffer_len = size_is * len;
1037 if (offset % size_is)
1038 offset += size_is - (offset % size_is);
1040 if (size_is == sizeof(guint16)) {
1041 /* XXX - use drep to determine the byte order? */
1042 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1044 * XXX - we don't support a string type with Unicode
1045 * characters, so if this is a string item, we make
1046 * its value be the "fake Unicode" string.
1048 if (tree && buffer_len) {
1049 hfinfo = proto_registrar_get_nth(hfindex);
1050 if (hfinfo->type == FT_STRING) {
1051 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1054 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1055 buffer_len, drep[0] & 0x10);
1060 * "tvb_get_string()" throws an exception if the entire string
1061 * isn't in the tvbuff. If the length is bogus, this should
1062 * keep us from trying to allocate an immensely large buffer.
1063 * (It won't help if the length is *valid* but immensely large,
1064 * but that's another matter; in any case, that would happen only
1065 * if we had an immensely large tvbuff....)
1067 s = tvb_get_string(tvb, offset, buffer_len);
1068 if (tree && buffer_len)
1069 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1070 buffer_len, drep[0] & 0x10);
1073 if (string_item != NULL)
1074 proto_item_append_text(string_item, ": %s", s);
1081 offset += buffer_len;
1083 proto_item_set_end(string_item, tvb, offset);
1088 /* Dissect an conformant varying string of chars.
1089 This corresponds to IDL of the form '[string] char *foo'.
1091 XXX - at least according to the DCE RPC 1.1 spec, a string has
1092 a null terminator, which isn't necessary as a terminator for
1093 the transfer language (as there's a length), but is presumably
1094 there for the benefit of null-terminated-string languages
1095 such as C. Is this ever used for purely counted strings?
1096 (Not that it matters if it is.) */
1098 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1099 proto_tree *tree, char *drep)
1102 di=pinfo->private_data;
1104 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1105 sizeof(guint8), di->hf_index,
1109 /* Dissect a conformant varying string of wchars (wide characters).
1110 This corresponds to IDL of the form '[string] wchar *foo'
1112 XXX - at least according to the DCE RPC 1.1 spec, a string has
1113 a null terminator, which isn't necessary as a terminator for
1114 the transfer language (as there's a length), but is presumably
1115 there for the benefit of null-terminated-string languages
1116 such as C. Is this ever used for purely counted strings?
1117 (Not that it matters if it is.) */
1119 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1120 proto_tree *tree, char *drep)
1123 di=pinfo->private_data;
1125 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1126 sizeof(guint16), di->hf_index,
1130 /* ndr pointer handling */
1131 /* list of pointers encountered so far */
1132 static GSList *ndr_pointer_list = NULL;
1134 /* position where in the list to insert newly encountered pointers */
1135 static int ndr_pointer_list_pos=0;
1137 /* boolean controlling whether pointers are top-level or embedded */
1138 static gboolean pointers_are_top_level = TRUE;
1140 /* as a kludge, we represent all embedded reference pointers as id==-1
1141 hoping that his will not collide with any non-ref pointers */
1142 typedef struct ndr_pointer_data {
1144 proto_item *item; /* proto_item for pointer */
1145 proto_tree *tree; /* subtree of above item */
1146 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1148 dcerpc_callback_fnct_t *callback;
1149 void *callback_args;
1150 } ndr_pointer_data_t;
1153 init_ndr_pointer_list(packet_info *pinfo)
1157 di=pinfo->private_data;
1158 di->conformant_run=0;
1160 while(ndr_pointer_list){
1161 ndr_pointer_data_t *npd;
1163 npd=g_slist_nth_data(ndr_pointer_list, 0);
1164 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1170 ndr_pointer_list=NULL;
1171 ndr_pointer_list_pos=0;
1172 pointers_are_top_level=TRUE;
1176 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *drep)
1178 int found_new_pointer;
1182 di=pinfo->private_data;
1186 found_new_pointer=0;
1187 len=g_slist_length(ndr_pointer_list);
1189 ndr_pointer_data_t *tnpd;
1190 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1192 dcerpc_dissect_fnct_t *fnct;
1194 found_new_pointer=1;
1197 ndr_pointer_list_pos=i+1;
1198 di->hf_index=tnpd->hf_index;
1199 /* first a run to handle any conformant
1201 di->conformant_run=1;
1202 di->conformant_eaten=0;
1203 old_offset = offset;
1204 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1206 g_assert((offset-old_offset)==di->conformant_eaten);
1207 /* This is to check for any bugs in the dissectors.
1209 * Basically, the NDR representation will store all
1210 * arrays in two blocks, one block with the dimension
1211 * discreption, like size, number of elements and such,
1212 * and another block that contains the actual data stored
1214 * If the array is embedded directly inside another,
1215 * encapsulating aggregate type, like a union or struct,
1216 * then these two blocks will be stored at different places
1217 * in the bytestream, with other data between the blocks.
1219 * For this reason, all pointers to types (both aggregate
1220 * and scalar, for simplicity no distinction is made)
1221 * will have its dissector called twice.
1222 * The dissector will first be called with conformant_run==1
1223 * in which mode the dissector MUST NOT consume any data from
1224 * the tvbuff (i.e. may not dissect anything) except the
1225 * initial control block for arrays.
1226 * The second time the dissector is called, with
1227 * conformant_run==0, all other data for the type will be
1230 * All dissect_ndr_<type> dissectors are already prepared
1231 * for this and knows when it should eat data from the tvb
1232 * and when not to, so implementors of dissectors will
1233 * normally not need to worry about this or even know about
1234 * it. However, if a dissector for an aggregate type calls
1235 * a subdissector from outside packet-dcerpc.c, such as
1236 * the dissector in packet-smb.c for NT Security Descriptors
1237 * as an example, then it is VERY important to encapsulate
1238 * this call to an external subdissector with the appropriate
1239 * test for conformant_run, i.e. it will need something like
1243 * di=pinfo->private_data;
1244 * if(di->conformant_run){
1248 * to make sure it makes the right thing.
1249 * This assert will signal when someone has forgotten to
1250 * make the dissector aware of this requirement.
1253 /* now we dissect the actual pointer */
1254 di->conformant_run=0;
1255 old_offset = offset;
1256 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1258 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1262 } while(found_new_pointer);
1269 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1270 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1271 dcerpc_callback_fnct_t *callback, void *callback_args)
1273 ndr_pointer_data_t *npd;
1275 /* check if this pointer is valid */
1278 dcerpc_call_value *value;
1280 di=pinfo->private_data;
1281 value=di->call_data;
1284 if(!(pinfo->fd->flags.visited)){
1285 if(id>value->max_ptr){
1290 /* if we havent seen the request bail out since we cant
1291 know whether this is the first non-NULL instance
1293 if(value->req_frame==0){
1294 /* XXX THROW EXCEPTION */
1297 /* We saw this one in the request frame, nothing to
1299 if(id<=value->max_ptr){
1305 npd=g_malloc(sizeof(ndr_pointer_data_t));
1310 npd->hf_index=hf_index;
1311 npd->callback=callback;
1312 npd->callback_args=callback_args;
1313 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1314 ndr_pointer_list_pos);
1315 ndr_pointer_list_pos++;
1320 find_pointer_index(guint32 id)
1322 ndr_pointer_data_t *npd;
1325 len=g_slist_length(ndr_pointer_list);
1327 npd=g_slist_nth_data(ndr_pointer_list, i);
1338 /* This function dissects an NDR pointer and stores the callback for later
1339 * deferred dissection.
1341 * fnct is the callback function for when we have reached this object in
1344 * type is what type of pointer.
1346 * this is text is what text we should put in any created tree node.
1348 * hf_index is what hf value we want to pass to the callback function when
1349 * it is called, the callback can later pich this one up from di->hf_index.
1351 * callback is executed after the pointer has been dereferenced.
1353 * callback_args is passed as an argument to the callback function
1355 * See packet-dcerpc-samr.c for examples
1358 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1359 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1360 int type, char *text, int hf_index,
1361 dcerpc_callback_fnct_t *callback, void *callback_args)
1365 di=pinfo->private_data;
1366 if(di->conformant_run){
1367 /* this call was only for dissecting the header for any
1368 embedded conformant array. we will not parse any
1369 pointers in this mode.
1374 /*TOP LEVEL REFERENCE POINTER*/
1375 if( pointers_are_top_level
1376 &&(type==NDR_POINTER_REF) ){
1380 /* we must find out a nice way to do the length here */
1381 item=proto_tree_add_text(tree, tvb, offset, 0,
1383 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1385 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1386 hf_index, callback, callback_args);
1390 /*TOP LEVEL FULL POINTER*/
1391 if( pointers_are_top_level
1392 && (type==NDR_POINTER_PTR) ){
1398 /* get the referent id */
1399 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1401 /* we got a NULL pointer */
1403 proto_tree_add_text(tree, tvb, offset-4, 4,
1404 "(NULL pointer) %s",text);
1408 /* see if we have seen this pointer before */
1409 idx=find_pointer_index(id);
1411 /* we have seen this pointer before */
1413 proto_tree_add_text(tree, tvb, offset-4, 4,
1414 "(duplicate PTR) %s",text);
1419 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1421 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1422 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1423 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1424 callback, callback_args);
1427 /*TOP LEVEL UNIQUE POINTER*/
1428 if( pointers_are_top_level
1429 && (type==NDR_POINTER_UNIQUE) ){
1434 /* get the referent id */
1435 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1437 /* we got a NULL pointer */
1439 proto_tree_add_text(tree, tvb, offset-4, 4,
1440 "(NULL pointer) %s",text);
1445 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1447 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1448 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1449 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1450 hf_index, callback, callback_args);
1454 /*EMBEDDED REFERENCE POINTER*/
1455 if( (!pointers_are_top_level)
1456 && (type==NDR_POINTER_REF) ){
1461 /* get the referent id */
1462 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1465 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1467 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1468 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1469 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1470 hf_index, callback, callback_args);
1474 /*EMBEDDED UNIQUE POINTER*/
1475 if( (!pointers_are_top_level)
1476 && (type==NDR_POINTER_UNIQUE) ){
1481 /* get the referent id */
1482 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1484 /* we got a NULL pointer */
1486 proto_tree_add_text(tree, tvb, offset-4, 4,
1487 "(NULL pointer) %s", text);
1492 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1494 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1495 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1496 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1497 hf_index, callback, callback_args);
1501 /*EMBEDDED FULL POINTER*/
1502 if( (!pointers_are_top_level)
1503 && (type==NDR_POINTER_PTR) ){
1509 /* get the referent id */
1510 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1512 /* we got a NULL pointer */
1514 proto_tree_add_text(tree, tvb, offset-4, 4,
1515 "(NULL pointer) %s",text);
1519 /* see if we have seen this pointer before */
1520 idx=find_pointer_index(id);
1522 /* we have seen this pointer before */
1524 proto_tree_add_text(tree, tvb, offset-4, 4,
1525 "(duplicate PTR) %s",text);
1530 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1532 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1533 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1534 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1535 callback, callback_args);
1541 /* After each top level pointer we have dissected we have to
1542 dissect all deferrals before we move on to the next top level
1544 if(pointers_are_top_level==TRUE){
1545 pointers_are_top_level=FALSE;
1546 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
1547 pointers_are_top_level=TRUE;
1554 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1555 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1556 int type, char *text, int hf_index)
1558 return dissect_ndr_pointer_cb(
1559 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
1564 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
1565 dcerpc_auth_info *auth_info)
1570 * We don't show stub data unless we have some in the tvbuff;
1571 * however, in the protocol tree, we show, as the number of
1572 * bytes, the reported number of bytes, not the number of bytes
1573 * that happen to be in the tvbuff.
1575 if (tvb_length_remaining (tvb, offset) > 0) {
1576 length = tvb_reported_length_remaining (tvb, offset);
1577 if (auth_info != NULL &&
1578 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1579 proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
1580 "Encrypted stub data (%d byte%s)",
1581 length, plurality(length, "", "s"));
1583 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
1584 "Stub data (%d byte%s)", length,
1585 plurality(length, "", "s"));
1591 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
1592 proto_tree *dcerpc_tree,
1593 tvbuff_t *tvb, gint offset,
1594 char *drep, dcerpc_info *info,
1595 dcerpc_auth_info *auth_info)
1597 dcerpc_uuid_key key;
1598 dcerpc_uuid_value *sub_proto;
1600 proto_tree *volatile sub_tree = NULL;
1601 dcerpc_sub_dissector *proc;
1603 dcerpc_dissect_fnct_t *volatile sub_dissect;
1604 const char *volatile saved_proto;
1605 void *volatile saved_private_data;
1607 key.uuid = info->call_data->uuid;
1608 key.ver = info->call_data->ver;
1611 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1612 || !proto_is_protocol_enabled(sub_proto->proto)) {
1614 * We don't have a dissector for this UUID, or the protocol
1615 * for that UUID is disabled.
1617 show_stub_data (tvb, offset, dcerpc_tree, auth_info);
1621 for (proc = sub_proto->procs; proc->name; proc++) {
1622 if (proc->num == info->call_data->opnum) {
1631 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1632 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1635 if (check_col (pinfo->cinfo, COL_INFO)) {
1636 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1637 name, info->request ? "request" : "reply");
1641 proto_item *sub_item;
1642 sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
1646 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1650 * Put the operation number into the tree along with
1651 * the operation's name.
1654 if (sub_proto->opnum_hf != -1)
1655 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
1656 tvb, 0, 0, info->call_data->opnum,
1657 "Operation: %s (%u)",
1658 name, info->call_data->opnum);
1660 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
1661 0, 0, info->call_data->opnum,
1662 "Operation: %s (%u)",
1663 name, info->call_data->opnum);
1667 * If the authentication level is DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
1668 * the stub data is encrypted, and we'd have to decrypt it in
1669 * order to dissect it.
1671 if (auth_info != NULL &&
1672 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1673 length = tvb_length_remaining (tvb, offset);
1675 proto_tree_add_text(sub_tree, tvb, offset, length,
1676 "Encrypted stub data (%d byte%s)",
1677 length, plurality(length, "", "s"));
1679 switch (auth_info->auth_type) {
1681 case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
1683 tvbuff_t *ntlmssp_tvb;
1684 ntlmssp_tvb = tvb_new_subset(tvb, offset, length, length);
1685 pinfo->decrypted_data=NULL;
1687 call_dissector(ntlmssp_enc_payload_handle, ntlmssp_tvb, pinfo,
1690 if(pinfo->decrypted_data){
1691 ntlmssp_decrypted_info_t *ndi=pinfo->decrypted_data;
1694 sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
1696 saved_proto = pinfo->current_proto;
1697 saved_private_data = pinfo->private_data;
1698 pinfo->current_proto = sub_proto->name;
1699 pinfo->private_data = (void *)info;
1701 init_ndr_pointer_list(pinfo);
1704 * Catch ReportedBoundsError, as that could
1705 * be due to the decryption being bad,
1706 * and doesn't mean that the tvbuff we were
1707 * handed has a malformed packet.
1710 offset = sub_dissect (ndi->decr_tvb, 0, pinfo, ndi->decr_tree, drep);
1711 } CATCH(BoundsError) {
1713 } CATCH(ReportedBoundsError) {
1714 show_reported_bounds_error(tvb, pinfo, tree);
1717 pinfo->current_proto = saved_proto;
1718 pinfo->private_data = saved_private_data;
1726 sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
1728 saved_proto = pinfo->current_proto;
1729 saved_private_data = pinfo->private_data;
1730 pinfo->current_proto = sub_proto->name;
1731 pinfo->private_data = (void *)info;
1733 init_ndr_pointer_list(pinfo);
1735 * Catch ReportedBoundsError, so that even if the stub
1736 * data is bad, we still show the verifier.
1739 offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
1740 } CATCH(BoundsError) {
1742 } CATCH(ReportedBoundsError) {
1743 show_reported_bounds_error(tvb, pinfo, tree);
1746 pinfo->current_proto = saved_proto;
1747 pinfo->private_data = saved_private_data;
1749 length = tvb_length_remaining (tvb, offset);
1751 proto_tree_add_text (sub_tree, tvb, offset, length,
1752 "Stub data (%d byte%s)", length,
1753 plurality(length, "", "s"));
1757 tap_queue_packet(dcerpc_tap, pinfo, info);
1762 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
1763 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
1764 dcerpc_auth_info *auth_info)
1768 if (auth_info->auth_size != 0) {
1769 auth_offset = hdr->frag_len - hdr->auth_len;
1770 switch (auth_info->auth_type) {
1772 case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
1774 tvbuff_t *ntlmssp_tvb;
1776 ntlmssp_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
1779 call_dissector(ntlmssp_verf_handle, ntlmssp_tvb, pinfo,
1785 case DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO: {
1786 /* SPNEGO (rfc2478) */
1787 tvbuff_t *gssapi_tvb;
1789 gssapi_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
1792 call_dissector(gssapi_verf_handle, gssapi_tvb, pinfo, dcerpc_tree);
1797 case DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN: {
1798 proto_item *vf = NULL;
1799 proto_tree *volatile sec_chan_tree = NULL;
1801 * Create a new tree, and split into 4 components ...
1803 vf = proto_tree_add_item(dcerpc_tree, hf_dcerpc_sec_chan, tvb,
1804 auth_offset, -1, FALSE);
1805 sec_chan_tree = proto_item_add_subtree(vf, ett_sec_chan);
1807 proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_sig, tvb,
1808 auth_offset, 8, FALSE);
1810 proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_unk, tvb,
1811 auth_offset + 8, 8, FALSE);
1813 proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_seq, tvb,
1814 auth_offset + 16, 8, FALSE);
1816 proto_tree_add_item(sec_chan_tree, hf_dcerpc_sec_chan_nonce, tvb,
1817 auth_offset + 24, 8, FALSE);
1823 proto_tree_add_text (dcerpc_tree, tvb, auth_offset, hdr->auth_len,
1828 return hdr->auth_len;
1832 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1833 e_dce_cn_common_hdr_t *hdr, gboolean are_credentials,
1834 dcerpc_auth_info *auth_info)
1839 * Initially set auth_level to -1 to indicate that we haven't
1840 * yet seen any authentication level information.
1842 auth_info->auth_level = -1;
1845 * The authentication information is at the *end* of the PDU; in
1846 * request and response PDUs, the request and response stub data
1849 * If the full packet is here, and we've got an auth len, and it's
1850 * valid, then dissect the auth info.
1852 if (tvb_length (tvb) >= hdr->frag_len
1854 && (hdr->auth_len + 8 <= hdr->frag_len)) {
1856 offset = hdr->frag_len - (hdr->auth_len + 8);
1858 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1859 hf_dcerpc_auth_type,
1860 &auth_info->auth_type);
1861 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1862 hf_dcerpc_auth_level,
1863 &auth_info->auth_level);
1865 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1866 hf_dcerpc_auth_pad_len,
1867 &auth_info->auth_pad_len);
1868 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1869 hf_dcerpc_auth_rsrvd, NULL);
1870 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1871 hf_dcerpc_auth_ctx_id, NULL);
1874 * Dissect the authentication data.
1876 if (are_credentials) {
1878 * The authentication data are credentials.
1880 switch (auth_info->auth_type) {
1882 case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
1884 tvbuff_t *ntlmssp_tvb;
1886 ntlmssp_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
1889 call_dissector(ntlmssp_handle, ntlmssp_tvb, pinfo,
1895 case DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO: {
1896 /* SPNEGO (rfc2478) */
1897 tvbuff_t *gssapi_tvb;
1899 gssapi_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
1902 call_dissector(gssapi_handle, gssapi_tvb, pinfo, dcerpc_tree);
1907 case DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN: {
1909 /* TODO: Fill me in when we know what goes here */
1911 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
1912 "Secure Channel Auth Credentials");
1917 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
1918 "Auth Credentials");
1922 /* figure out where the auth padding starts */
1923 offset = hdr->frag_len - (hdr->auth_len + 8 + auth_info->auth_pad_len);
1924 if (offset > 0 && auth_info->auth_pad_len) {
1925 proto_tree_add_text (dcerpc_tree, tvb, offset,
1926 auth_info->auth_pad_len, "Auth padding");
1927 auth_info->auth_size = hdr->auth_len + 8 + auth_info->auth_pad_len;
1929 auth_info->auth_size = hdr->auth_len + 8;
1932 auth_info->auth_size = 0;
1937 /* We need to hash in the SMB fid number to generate a unique hash table
1938 key as DCERPC over SMB allows several pipes over the same TCP/IP
1941 static guint16 get_smb_fid (void *private_data)
1943 dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
1946 return 0; /* Nothing to see here */
1948 /* DCERPC over smb */
1950 if (priv->transport_type == DCERPC_TRANSPORT_SMB)
1951 return priv->data.smb.fid;
1953 /* Some other transport... */
1959 * Connection oriented packet types
1963 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
1964 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
1966 conversation_t *conv = NULL;
1967 guint8 num_ctx_items;
1969 gboolean saw_ctx_item = FALSE;
1971 guint16 num_trans_items;
1976 guint16 if_ver, if_ver_minor;
1977 char uuid_str[DCERPC_UUID_STR_LEN];
1979 dcerpc_auth_info auth_info;
1981 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1982 hf_dcerpc_cn_max_xmit, NULL);
1984 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1985 hf_dcerpc_cn_max_recv, NULL);
1987 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1988 hf_dcerpc_cn_assoc_group, NULL);
1990 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1991 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
1996 for (i = 0; i < num_ctx_items; i++) {
1997 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1998 hf_dcerpc_cn_ctx_id, &ctx_id);
2000 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2001 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2003 /* XXX - use "dissect_ndr_uuid_t()"? */
2004 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2006 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2007 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2008 if_id.Data1, if_id.Data2, if_id.Data3,
2009 if_id.Data4[0], if_id.Data4[1],
2010 if_id.Data4[2], if_id.Data4[3],
2011 if_id.Data4[4], if_id.Data4[5],
2012 if_id.Data4[6], if_id.Data4[7]);
2013 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2014 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2015 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
2016 offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2020 if (hdr->drep[0] & 0x10) {
2021 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2022 hf_dcerpc_cn_bind_if_ver, &if_ver);
2023 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2024 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2026 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2027 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2028 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2029 hf_dcerpc_cn_bind_if_ver, &if_ver);
2032 if (!saw_ctx_item) {
2033 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2034 pinfo->srcport, pinfo->destport, 0);
2036 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
2037 pinfo->srcport, pinfo->destport, 0);
2040 /* if this is the first time we see this packet, we need to
2041 update the dcerpc_binds table so that any later calls can
2042 match to the interface.
2043 XXX We assume that BINDs will NEVER be fragmented.
2045 if(!(pinfo->fd->flags.visited)){
2046 dcerpc_bind_key *key;
2047 dcerpc_bind_value *value;
2049 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
2051 key->ctx_id = ctx_id;
2052 key->smb_fid = get_smb_fid(pinfo->private_data);
2054 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2055 value->uuid = if_id;
2056 value->ver = if_ver;
2058 /* add this entry to the bind table, first removing any
2059 previous ones that are identical
2061 if(g_hash_table_lookup(dcerpc_binds, key)){
2062 g_hash_table_remove(dcerpc_binds, key);
2064 g_hash_table_insert (dcerpc_binds, key, value);
2067 if (check_col (pinfo->cinfo, COL_INFO)) {
2068 dcerpc_uuid_key key;
2069 dcerpc_uuid_value *value;
2074 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2075 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2077 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2078 if_id.Data1, if_id.Data2, if_id.Data3,
2079 if_id.Data4[0], if_id.Data4[1],
2080 if_id.Data4[2], if_id.Data4[3],
2081 if_id.Data4[4], if_id.Data4[5],
2082 if_id.Data4[6], if_id.Data4[7],
2083 if_ver, if_ver_minor);
2085 saw_ctx_item = TRUE;
2088 for (j = 0; j < num_trans_items; j++) {
2089 /* XXX - use "dissect_ndr_uuid_t()"? */
2090 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2092 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2093 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2094 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2095 trans_id.Data4[0], trans_id.Data4[1],
2096 trans_id.Data4[2], trans_id.Data4[3],
2097 trans_id.Data4[4], trans_id.Data4[5],
2098 trans_id.Data4[6], trans_id.Data4[7]);
2099 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2100 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2101 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2102 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2106 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2107 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2112 * XXX - we should save the authentication type *if* we have
2113 * an authentication header, and associate it with an authentication
2114 * context, so subsequent PDUs can use that context.
2116 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2120 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2121 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2123 guint16 max_xmit, max_recv;
2124 guint16 sec_addr_len;
2131 char uuid_str[DCERPC_UUID_STR_LEN];
2133 dcerpc_auth_info auth_info;
2135 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2136 hf_dcerpc_cn_max_xmit, &max_xmit);
2138 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2139 hf_dcerpc_cn_max_recv, &max_recv);
2141 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2142 hf_dcerpc_cn_assoc_group, NULL);
2144 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2145 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2146 if (sec_addr_len != 0) {
2147 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2148 sec_addr_len, FALSE);
2149 offset += sec_addr_len;
2153 offset += 4 - offset % 4;
2156 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2157 hf_dcerpc_cn_num_results, &num_results);
2162 for (i = 0; i < num_results; i++) {
2163 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2164 hdr->drep, hf_dcerpc_cn_ack_result,
2167 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2168 hdr->drep, hf_dcerpc_cn_ack_reason,
2172 * The reason for rejection isn't meaningful, and often isn't
2173 * set, when the syntax was accepted.
2178 /* XXX - use "dissect_ndr_uuid_t()"? */
2179 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2181 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2182 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2183 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2184 trans_id.Data4[0], trans_id.Data4[1],
2185 trans_id.Data4[2], trans_id.Data4[3],
2186 trans_id.Data4[4], trans_id.Data4[5],
2187 trans_id.Data4[6], trans_id.Data4[7]);
2188 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2189 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2190 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2191 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2195 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2196 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2200 * XXX - do we need to do anything with the authentication level
2201 * we get back from this?
2203 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2205 if (check_col (pinfo->cinfo, COL_INFO)) {
2206 if (num_results != 0 && result == 0) {
2207 /* XXX - only checks the last result */
2208 col_append_fstr (pinfo->cinfo, COL_INFO,
2209 " accept max_xmit: %u max_recv: %u",
2210 max_xmit, max_recv);
2212 /* XXX - only shows the last result and reason */
2213 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2214 val_to_str(result, p_cont_result_vals,
2215 "Unknown result (%u)"),
2216 val_to_str(reason, p_provider_reason_vals,
2223 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2224 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2227 guint8 num_protocols;
2230 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2231 hdr->drep, hf_dcerpc_cn_reject_reason,
2234 if (check_col (pinfo->cinfo, COL_INFO)) {
2235 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2236 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2239 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2240 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2241 hf_dcerpc_cn_num_protocols,
2244 for (i = 0; i < num_protocols; i++) {
2245 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2246 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2248 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2249 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2255 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2258 #define PFC_FRAG_MASK 0x03
2261 fragment_type(guint8 flags)
2263 flags = flags & PFC_FRAG_MASK;
2265 if (flags == PFC_FIRST_FRAG)
2271 if (flags == PFC_LAST_FRAG)
2274 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2281 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2282 proto_tree *dcerpc_tree, proto_tree *tree,
2283 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2284 dcerpc_auth_info *auth_info, guint32 alloc_hint,
2287 int length, reported_length, stub_length;
2288 gboolean save_fragmented;
2289 fragment_data *fd_head=NULL;
2293 length = tvb_length_remaining(tvb, offset);
2294 reported_length = tvb_reported_length_remaining(tvb, offset);
2295 stub_length = hdr->frag_len - offset - auth_info->auth_size;
2296 if (length > stub_length)
2297 length = stub_length;
2298 if (reported_length > stub_length)
2299 reported_length = stub_length;
2301 save_fragmented = pinfo->fragmented;
2303 /* if this packet is not fragmented, just dissect it and exit */
2304 if(PFC_NOT_FRAGMENTED(hdr)){
2305 pinfo->fragmented = FALSE;
2306 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2307 tvb_new_subset (tvb, offset, length, reported_length),
2308 0, hdr->drep, di, auth_info);
2310 pinfo->fragmented = save_fragmented;
2314 /* The packet is fragmented. */
2315 pinfo->fragmented = TRUE;
2317 /* if we are not doing reassembly and this is the first fragment
2318 then just dissect it and exit
2320 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
2321 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2322 tvb_new_subset (tvb, offset, length,
2324 0, hdr->drep, di, auth_info);
2325 if (check_col(pinfo->cinfo, COL_INFO)) {
2326 col_append_fstr(pinfo->cinfo, COL_INFO,
2327 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2329 pinfo->fragmented = save_fragmented;
2333 /* if we have already seen this packet, see if it was reassembled
2334 and if so dissect the full pdu.
2337 if(pinfo->fd->flags.visited){
2338 fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
2344 /* if we are not doing reassembly and it was neither a complete PDU
2345 nor the first fragment then there is nothing more we can do
2346 so we just have to exit
2348 if( !dcerpc_reassemble ){
2352 /* if we didnt get 'frame' we dont know where the PDU started and thus
2353 it is pointless to continue
2360 /* from now on we must attempt to reassemble the PDU
2364 /* we dont have the full fragment so we just have to abort and exit
2366 if( !tvb_bytes_exist(tvb, offset, stub_length) ){
2371 /* if we get here we know it is the first time we see the packet
2372 and we also know it is only a fragment and not a full PDU,
2373 thus we must reassemble it.
2377 /* if this is the first fragment we need to start reassembly
2379 if(hdr->flags&PFC_FIRST_FRAG){
2380 fragment_add(tvb, offset, pinfo, frame,
2381 dcerpc_co_reassemble_table,
2382 0, stub_length, TRUE);
2383 fragment_set_tot_len(pinfo, frame,
2384 dcerpc_co_reassemble_table, alloc_hint);
2389 /* if this is a middle fragment, just add it and exit */
2390 if(!(hdr->flags&PFC_LAST_FRAG)){
2391 tot_len = fragment_get_tot_len(pinfo, frame,
2392 dcerpc_co_reassemble_table);
2393 fragment_add(tvb, offset, pinfo, frame,
2394 dcerpc_co_reassemble_table,
2402 /* this was the last fragment add it to reassembly
2404 tot_len = fragment_get_tot_len(pinfo, frame,
2405 dcerpc_co_reassemble_table);
2406 fd_head = fragment_add(tvb, offset, pinfo,
2408 dcerpc_co_reassemble_table,
2415 /* Show the fragment data. */
2418 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2419 "Fragment data (%d byte%s)",
2421 plurality(stub_length, "", "s"));
2425 /* if reassembly is complete, dissect the full PDU
2427 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
2428 if(pinfo->fd->num==fd_head->reassembled_in){
2431 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2432 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2433 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2434 show_fragment_tree(fd_head, &dcerpc_frag_items,
2435 dcerpc_tree, pinfo, next_tvb);
2437 pinfo->fragmented = FALSE;
2438 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
2439 0, hdr->drep, di, auth_info);
2441 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in, tvb, 0, 0, fd_head->reassembled_in);
2442 if (check_col(pinfo->cinfo, COL_INFO)) {
2443 col_append_fstr(pinfo->cinfo, COL_INFO,
2444 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2448 /* Reassembly not complete - some fragments
2450 if (check_col(pinfo->cinfo, COL_INFO)) {
2451 col_append_fstr(pinfo->cinfo, COL_INFO,
2452 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2456 pinfo->fragmented = save_fragmented;
2460 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2461 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2463 conversation_t *conv;
2467 dcerpc_auth_info auth_info;
2469 char uuid_str[DCERPC_UUID_STR_LEN];
2472 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2473 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2475 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2476 hf_dcerpc_cn_ctx_id, &ctx_id);
2478 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2479 hf_dcerpc_opnum, &opnum);
2481 if (check_col (pinfo->cinfo, COL_INFO)) {
2482 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
2486 if (hdr->flags & PFC_OBJECT_UUID) {
2487 /* XXX - use "dissect_ndr_uuid_t()"? */
2488 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
2490 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2491 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2492 obj_id.Data1, obj_id.Data2, obj_id.Data3,
2501 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2502 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2503 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
2504 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
2510 * XXX - what if this was set when the connection was set up,
2511 * and we just have a security context?
2513 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2515 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2516 pinfo->srcport, pinfo->destport, 0);
2518 show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2520 dcerpc_matched_key matched_key, *new_matched_key;
2521 dcerpc_call_value *value;
2523 /* !!! we can NOT check flags.visited here since this will interact
2524 badly with when SMB handles (i.e. calls the subdissector)
2525 and desegmented pdu's .
2526 Instead we check if this pdu is already in the matched table or not
2528 matched_key.frame = pinfo->fd->num;
2529 matched_key.call_id = hdr->call_id;
2530 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
2532 dcerpc_bind_key bind_key;
2533 dcerpc_bind_value *bind_value;
2536 bind_key.ctx_id=ctx_id;
2537 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
2539 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
2540 if(!(hdr->flags&PFC_FIRST_FRAG)){
2541 dcerpc_call_key call_key;
2542 dcerpc_call_value *call_value;
2545 call_key.call_id=hdr->call_id;
2546 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2547 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2548 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2549 *new_matched_key = matched_key;
2550 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2554 dcerpc_call_key *call_key;
2555 dcerpc_call_value *call_value;
2557 /* We found the binding and it is the first fragment
2558 (or a complete PDU) of a dcerpc pdu so just add
2559 the call to both the call table and the
2562 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
2563 call_key->conv=conv;
2564 call_key->call_id=hdr->call_id;
2565 call_key->smb_fid=get_smb_fid(pinfo->private_data);
2567 /* if there is already a matching call in the table
2568 remove it so it is replaced with the new one */
2569 if(g_hash_table_lookup(dcerpc_calls, call_key)){
2570 g_hash_table_remove(dcerpc_calls, call_key);
2573 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2574 call_value->uuid = bind_value->uuid;
2575 call_value->ver = bind_value->ver;
2576 call_value->opnum = opnum;
2577 call_value->req_frame=pinfo->fd->num;
2578 call_value->req_time.secs=pinfo->fd->abs_secs;
2579 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
2580 call_value->rep_frame=0;
2581 call_value->max_ptr=0;
2582 call_value->private_data = NULL;
2583 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2585 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2586 *new_matched_key = matched_key;
2587 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2596 /* handoff this call */
2598 di.call_id = hdr->call_id;
2599 di.smb_fid = get_smb_fid(pinfo->private_data);
2601 di.call_data = value;
2603 if(value->rep_frame!=0){
2604 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
2605 tvb, 0, 0, value->rep_frame);
2607 /*qqq request, broken*/
2608 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2609 hdr, &di, &auth_info, alloc_hint,
2612 show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2615 /* Decrypt the verifier, if present */
2616 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2620 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2621 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2623 dcerpc_call_value *value = NULL;
2624 conversation_t *conv;
2626 dcerpc_auth_info auth_info;
2629 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2630 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2632 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2633 hf_dcerpc_cn_ctx_id, &ctx_id);
2635 if (check_col (pinfo->cinfo, COL_INFO)) {
2636 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
2639 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2640 hf_dcerpc_cn_cancel_count, NULL);
2645 * XXX - what if this was set when the connection was set up,
2646 * and we just have a security context?
2648 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2650 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2651 pinfo->srcport, pinfo->destport, 0);
2653 /* no point in creating one here, really */
2654 show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2656 dcerpc_matched_key matched_key, *new_matched_key;
2658 /* !!! we can NOT check flags.visited here since this will interact
2659 badly with when SMB handles (i.e. calls the subdissector)
2660 and desegmented pdu's .
2661 Instead we check if this pdu is already in the matched table or not
2663 matched_key.frame = pinfo->fd->num;
2664 matched_key.call_id = hdr->call_id;
2665 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
2667 dcerpc_call_key call_key;
2668 dcerpc_call_value *call_value;
2671 call_key.call_id=hdr->call_id;
2672 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2674 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2675 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2676 *new_matched_key = matched_key;
2677 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2679 if(call_value->rep_frame==0){
2680 call_value->rep_frame=pinfo->fd->num;
2688 /* handoff this call */
2690 di.call_id = hdr->call_id;
2691 di.smb_fid = get_smb_fid(pinfo->private_data);
2693 di.call_data = value;
2695 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2696 if(value->req_frame!=0){
2698 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2699 tvb, 0, 0, value->req_frame);
2700 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2701 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2703 ns.nsecs+=1000000000;
2706 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2710 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2711 hdr, &di, &auth_info, alloc_hint,
2714 show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2717 /* Decrypt the verifier, if present */
2718 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2722 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2723 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2725 dcerpc_call_value *value = NULL;
2726 conversation_t *conv;
2730 dcerpc_auth_info auth_info;
2732 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2733 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2735 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2736 hf_dcerpc_cn_ctx_id, &ctx_id);
2738 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2739 hf_dcerpc_cn_cancel_count, NULL);
2743 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2744 hf_dcerpc_cn_status, &status);
2746 if (check_col (pinfo->cinfo, COL_INFO)) {
2747 col_append_fstr (pinfo->cinfo, COL_INFO,
2748 " ctx_id: %u status: %s", ctx_id,
2749 val_to_str(status, reject_status_vals,
2750 "Unknown (0x%08x)"));
2757 * XXX - what if this was set when the connection was set up,
2758 * and we just have a security context?
2760 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2762 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2763 pinfo->srcport, pinfo->destport, 0);
2765 /* no point in creating one here, really */
2767 dcerpc_matched_key matched_key, *new_matched_key;
2769 /* !!! we can NOT check flags.visited here since this will interact
2770 badly with when SMB handles (i.e. calls the subdissector)
2771 and desegmented pdu's .
2772 Instead we check if this pdu is already in the matched table or not
2774 matched_key.frame = pinfo->fd->num;
2775 matched_key.call_id = hdr->call_id;
2776 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
2778 dcerpc_call_key call_key;
2779 dcerpc_call_value *call_value;
2782 call_key.call_id=hdr->call_id;
2783 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2785 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2786 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2787 *new_matched_key = matched_key;
2788 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2790 if(call_value->rep_frame==0){
2791 call_value->rep_frame=pinfo->fd->num;
2798 int length, reported_length, stub_length;
2801 /* handoff this call */
2803 di.call_id = hdr->call_id;
2804 di.smb_fid = get_smb_fid(pinfo->private_data);
2806 di.call_data = value;
2808 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2809 if(value->req_frame!=0){
2811 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2812 tvb, 0, 0, value->req_frame);
2813 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2814 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2816 ns.nsecs+=1000000000;
2819 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2822 length = tvb_length_remaining(tvb, offset);
2823 reported_length = tvb_reported_length_remaining(tvb, offset);
2824 stub_length = hdr->frag_len - offset - auth_info.auth_size;
2825 if (length > stub_length)
2826 length = stub_length;
2827 if (reported_length > stub_length)
2828 reported_length = stub_length;
2830 /* If we don't have reassembly enabled, or this packet contains
2831 the entire PDU, or if we don't have all the data in this
2832 fragment, just call the handoff directly if this is the
2833 first fragment or the PDU isn't fragmented. */
2834 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
2835 !tvb_bytes_exist(tvb, offset, stub_length) ){
2836 if(hdr->flags&PFC_FIRST_FRAG){
2837 /* First fragment, possibly the only fragment */
2839 * XXX - should there be a third routine for each
2840 * function in an RPC subdissector, to handle
2841 * fault responses? The DCE RPC 1.1 spec says
2842 * three's "stub data" here, which I infer means
2843 * that it's protocol-specific and call-specific.
2845 * It should probably get passed the status code
2846 * as well, as that might be protocol-specific.
2849 if (stub_length > 0) {
2850 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2851 "Fault stub data (%d byte%s)",
2853 plurality(stub_length, "", "s"));
2857 /* PDU is fragmented and this isn't the first fragment */
2858 if (check_col(pinfo->cinfo, COL_INFO)) {
2859 col_append_fstr(pinfo->cinfo, COL_INFO,
2860 " [DCE/RPC fragment]");
2863 if (stub_length > 0) {
2864 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2865 "Fragment data (%d byte%s)",
2867 plurality(stub_length, "", "s"));
2872 /* Reassembly is enabled, the PDU is fragmented, and
2873 we have all the data in the fragment; the first two
2874 of those mean we should attempt reassembly, and the
2875 third means we can attempt reassembly. */
2878 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2879 "Fragment data (%d byte%s)",
2881 plurality(stub_length, "", "s"));
2884 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
2885 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2886 fragment_add(tvb, offset, pinfo, value->rep_frame,
2887 dcerpc_co_reassemble_table,
2891 fragment_set_tot_len(pinfo, value->rep_frame,
2892 dcerpc_co_reassemble_table, alloc_hint);
2894 if (check_col(pinfo->cinfo, COL_INFO)) {
2895 col_append_fstr(pinfo->cinfo, COL_INFO,
2896 " [DCE/RPC fragment]");
2898 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
2899 if( value->rep_frame ){
2900 fragment_data *fd_head;
2903 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2904 dcerpc_co_reassemble_table);
2905 fd_head = fragment_add(tvb, offset, pinfo,
2907 dcerpc_co_reassemble_table,
2913 /* We completed reassembly */
2916 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2917 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2918 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2919 show_fragment_tree(fd_head, &dcerpc_frag_items,
2920 dcerpc_tree, pinfo, next_tvb);
2923 * XXX - should there be a third routine for each
2924 * function in an RPC subdissector, to handle
2925 * fault responses? The DCE RPC 1.1 spec says
2926 * three's "stub data" here, which I infer means
2927 * that it's protocol-specific and call-specific.
2929 * It should probably get passed the status code
2930 * as well, as that might be protocol-specific.
2934 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2935 "Fault stub data (%d byte%s)",
2937 plurality(stub_length, "", "s"));
2941 /* Reassembly not complete - some fragments
2943 if (check_col(pinfo->cinfo, COL_INFO)) {
2944 col_append_fstr(pinfo->cinfo, COL_INFO,
2945 " [DCE/RPC fragment]");
2949 } else { /* MIDDLE fragment(s) */
2950 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2952 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2953 dcerpc_co_reassemble_table);
2954 fragment_add(tvb, offset, pinfo, value->rep_frame,
2955 dcerpc_co_reassemble_table,
2960 if (check_col(pinfo->cinfo, COL_INFO)) {
2961 col_append_fstr(pinfo->cinfo, COL_INFO,
2962 " [DCE/RPC fragment]");
2971 * DCERPC dissector for connection oriented calls
2974 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
2975 proto_tree *tree, gboolean can_desegment)
2977 static char nulls[4] = { 0 };
2980 proto_item *ti = NULL;
2981 proto_item *tf = NULL;
2982 proto_tree *dcerpc_tree = NULL;
2983 proto_tree *cn_flags_tree = NULL;
2984 proto_tree *drep_tree = NULL;
2985 e_dce_cn_common_hdr_t hdr;
2986 dcerpc_auth_info auth_info;
2989 * when done over nbt, dcerpc requests are padded with 4 bytes of null
2990 * data for some reason.
2992 * XXX - if that's always the case, the right way to do this would
2993 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
2994 * the 4 bytes of null padding, and make that the dissector
2995 * used for "netbios".
2997 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3007 * Check if this looks like a C/O DCERPC call
3009 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3012 start_offset = offset;
3013 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3014 if (hdr.rpc_ver != 5)
3016 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3017 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3019 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3023 hdr.flags = tvb_get_guint8 (tvb, offset++);
3024 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3025 offset += sizeof (hdr.drep);
3027 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3029 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3031 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3034 if (can_desegment && pinfo->can_desegment
3035 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3036 pinfo->desegment_offset = start_offset;
3037 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3038 return 0; /* desegmentation required */
3041 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3042 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3043 if (check_col (pinfo->cinfo, COL_INFO))
3044 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3045 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3048 offset = start_offset;
3049 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3051 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3053 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
3054 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
3055 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
3056 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3057 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3058 if (cn_flags_tree) {
3059 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3060 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3061 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3062 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3063 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3064 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3065 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3066 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3070 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3071 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3073 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3074 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3075 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3077 offset += sizeof (hdr.drep);
3079 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3082 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3085 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3090 * Packet type specific stuff is next.
3092 switch (hdr.ptype) {
3095 dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr);
3100 dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3105 * Nothing after the common header other than credentials.
3107 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, TRUE,
3112 dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3116 dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3120 dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3124 dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
3130 * Nothing after the common header other than an authentication
3133 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
3139 * Nothing after the common header, not even an authentication
3145 /* might as well dissect the auth info */
3146 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
3150 return hdr.frag_len + padding;
3154 * DCERPC dissector for connection oriented calls over packet-oriented
3158 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3161 * Only one PDU per transport packet, and only one transport
3164 if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
3166 * It wasn't a DCERPC PDU.
3178 * DCERPC dissector for connection oriented calls over byte-stream
3182 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3186 gboolean ret = FALSE;
3189 * There may be multiple PDUs per transport packet; keep
3192 while (tvb_reported_length_remaining(tvb, offset) != 0) {
3193 pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
3194 dcerpc_cn_desegment);
3195 if (pdu_len == -1) {
3203 * Well, we've seen at least one DCERPC PDU.
3209 * Desegmentation required - bail now.
3215 * Step to the next PDU.
3223 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
3224 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
3226 proto_item *ti = NULL;
3227 proto_tree *auth_tree = NULL;
3228 guint8 protection_level;
3231 * Initially set "*auth_level_p" to -1 to indicate that we haven't
3232 * yet seen any authentication level information.
3234 if (auth_level_p != NULL)
3238 * The authentication information is at the *end* of the PDU; in
3239 * request and response PDUs, the request and response stub data
3242 * If the full packet is here, and there's data past the end of the
3243 * packet body, then dissect the auth info.
3245 offset += hdr->frag_len;
3246 if (tvb_length_remaining(tvb, offset) > 0) {
3247 switch (hdr->auth_proto) {
3249 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
3250 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
3251 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
3252 protection_level = tvb_get_guint8 (tvb, offset);
3253 if (auth_level_p != NULL)
3254 *auth_level_p = protection_level;
3255 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
3257 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
3259 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
3260 offset += 6; /* 6 bytes of padding */
3262 offset += 2; /* 6 bytes of padding */
3263 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
3268 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
3275 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3276 proto_tree *dcerpc_tree,
3277 e_dce_dg_common_hdr_t *hdr)
3281 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3282 hdr->drep, hf_dcerpc_dg_cancel_vers,
3288 /* The only version we know about */
3289 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3290 hdr->drep, hf_dcerpc_dg_cancel_id,
3292 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3293 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3300 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
3301 proto_tree *dcerpc_tree,
3302 e_dce_dg_common_hdr_t *hdr)
3306 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3307 hdr->drep, hf_dcerpc_dg_cancel_vers,
3313 /* The only version we know about */
3314 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3315 hdr->drep, hf_dcerpc_dg_cancel_id,
3317 /* XXX - are NDR booleans 32 bits? */
3318 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3319 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3326 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3327 proto_tree *dcerpc_tree,
3328 e_dce_dg_common_hdr_t *hdr)
3335 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3336 hdr->drep, hf_dcerpc_dg_fack_vers,
3343 case 0: /* The only version documented in the DCE RPC 1.1 spec */
3344 case 1: /* This appears to be the same */
3345 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3346 hdr->drep, hf_dcerpc_dg_fack_window_size,
3348 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3349 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
3351 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3352 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
3354 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3355 hdr->drep, hf_dcerpc_dg_fack_serial_num,
3357 if (check_col (pinfo->cinfo, COL_INFO)) {
3358 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3361 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3362 hdr->drep, hf_dcerpc_dg_fack_selack_len,
3364 for (i = 0; i < selack_len; i++) {
3365 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3366 hdr->drep, hf_dcerpc_dg_fack_selack,
3375 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
3376 proto_tree *dcerpc_tree,
3377 e_dce_dg_common_hdr_t *hdr)
3381 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3382 hdr->drep, hf_dcerpc_dg_status,
3385 if (check_col (pinfo->cinfo, COL_INFO)) {
3386 col_append_fstr (pinfo->cinfo, COL_INFO,
3388 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3393 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
3394 proto_tree *dcerpc_tree, proto_tree *tree,
3395 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
3397 int length, reported_length, stub_length;
3398 gboolean save_fragmented;
3399 fragment_data *fd_head;
3401 if (check_col (pinfo->cinfo, COL_INFO)) {
3402 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u",
3403 di->call_data->opnum);
3406 length = tvb_length_remaining (tvb, offset);
3407 reported_length = tvb_reported_length_remaining (tvb, offset);
3408 stub_length = hdr->frag_len;
3409 if (length > stub_length)
3410 length = stub_length;
3411 if (reported_length > stub_length)
3412 reported_length = stub_length;
3414 save_fragmented = pinfo->fragmented;
3416 /* If we don't have reassembly enabled, or this packet contains
3417 the entire PDU, or if this is a short frame (or a frame
3418 not reassembled at a lower layer) that doesn't include all
3419 the data in the fragment, just call the handoff directly if
3420 this is the first fragment or the PDU isn't fragmented. */
3421 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
3422 !tvb_bytes_exist(tvb, offset, stub_length) ){
3423 if(hdr->frag_num == 0) {
3424 /* First fragment, possibly the only fragment */
3427 * XXX - authentication info?
3429 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
3430 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
3431 tvb_new_subset (tvb, offset, length,
3433 0, hdr->drep, di, NULL);
3435 /* PDU is fragmented and this isn't the first fragment */
3436 if (check_col(pinfo->cinfo, COL_INFO)) {
3437 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3441 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3442 "Fragment data (%d byte%s)",
3444 plurality(stub_length, "", "s"));
3449 /* Reassembly is enabled, the PDU is fragmented, and
3450 we have all the data in the fragment; the first two
3451 of those mean we should attempt reassembly, and the
3452 third means we can attempt reassembly. */
3455 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3456 "Fragment data (%d byte%s)", stub_length,
3457 plurality(stub_length, "", "s"));
3461 fd_head = fragment_add_seq(tvb, offset, pinfo,
3462 hdr->seqnum, dcerpc_cl_reassemble_table,
3463 hdr->frag_num, stub_length,
3464 !(hdr->flags1 & PFCL1_LASTFRAG));
3465 if (fd_head != NULL) {
3466 /* We completed reassembly */
3469 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3470 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3471 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3472 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
3473 dcerpc_tree, pinfo, next_tvb);
3476 * XXX - authentication info?
3478 pinfo->fragmented = FALSE;
3479 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3480 0, hdr->drep, di, NULL);
3482 /* Reassembly isn't completed yet */
3483 if (check_col(pinfo->cinfo, COL_INFO)) {
3484 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3488 pinfo->fragmented = save_fragmented;
3492 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
3493 proto_tree *dcerpc_tree, proto_tree *tree,
3494 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3497 dcerpc_call_value *value, v;
3498 dcerpc_matched_key matched_key, *new_matched_key;
3500 if(!(pinfo->fd->flags.visited)){
3501 dcerpc_call_value *call_value;
3502 dcerpc_call_key *call_key;
3504 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
3505 call_key->conv=conv;
3506 call_key->call_id=hdr->seqnum;
3507 call_key->smb_fid=get_smb_fid(pinfo->private_data);
3509 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
3510 call_value->uuid = hdr->if_id;
3511 call_value->ver = hdr->if_ver;
3512 call_value->opnum = hdr->opnum;
3513 call_value->req_frame=pinfo->fd->num;
3514 call_value->req_time.secs=pinfo->fd->abs_secs;
3515 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3516 call_value->rep_frame=0;
3517 call_value->max_ptr=0;
3518 call_value->private_data = NULL;
3519 g_hash_table_insert (dcerpc_calls, call_key, call_value);
3521 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3522 new_matched_key->frame = pinfo->fd->num;
3523 new_matched_key->call_id = hdr->seqnum;
3524 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3527 matched_key.frame = pinfo->fd->num;
3528 matched_key.call_id = hdr->seqnum;
3529 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3531 v.uuid = hdr->if_id;
3532 v.ver = hdr->if_ver;
3533 v.opnum = hdr->opnum;
3534 v.req_frame = pinfo->fd->num;
3537 v.private_data=NULL;
3542 di.call_id = hdr->seqnum;
3545 di.call_data = value;
3547 if(value->rep_frame!=0){
3548 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3549 tvb, 0, 0, value->rep_frame);
3551 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
3555 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
3556 proto_tree *dcerpc_tree, proto_tree *tree,
3557 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3560 dcerpc_call_value *value, v;
3561 dcerpc_matched_key matched_key, *new_matched_key;
3563 if(!(pinfo->fd->flags.visited)){
3564 dcerpc_call_value *call_value;
3565 dcerpc_call_key call_key;
3568 call_key.call_id=hdr->seqnum;
3569 call_key.smb_fid=get_smb_fid(pinfo->private_data);
3571 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
3572 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3573 new_matched_key->frame = pinfo->fd->num;
3574 new_matched_key->call_id = hdr->seqnum;
3575 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3576 if(call_value->rep_frame==0){
3577 call_value->rep_frame=pinfo->fd->num;
3582 matched_key.frame = pinfo->fd->num;
3583 matched_key.call_id = hdr->seqnum;
3584 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3586 v.uuid = hdr->if_id;
3587 v.ver = hdr->if_ver;
3588 v.opnum = hdr->opnum;
3590 v.rep_frame=pinfo->fd->num;
3591 v.private_data=NULL;
3599 di.call_data = value;
3601 if(value->req_frame!=0){
3603 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3604 tvb, 0, 0, value->req_frame);
3605 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3606 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3608 ns.nsecs+=1000000000;
3611 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3613 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
3617 * DCERPC dissector for connectionless calls
3620 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3622 proto_item *ti = NULL;
3623 proto_item *tf = NULL;
3624 proto_tree *dcerpc_tree = NULL;
3625 proto_tree *dg_flags1_tree = NULL;
3626 proto_tree *dg_flags2_tree = NULL;
3627 proto_tree *drep_tree = NULL;
3628 e_dce_dg_common_hdr_t hdr;
3630 conversation_t *conv;
3632 char uuid_str[DCERPC_UUID_STR_LEN];
3636 * Check if this looks like a CL DCERPC call. All dg packets
3637 * have an 80 byte header on them. Which starts with
3638 * version (4), pkt_type.
3640 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
3643 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3644 if (hdr.rpc_ver != 4)
3646 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3650 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3651 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3652 if (check_col (pinfo->cinfo, COL_INFO))
3653 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
3655 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
3656 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
3657 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3658 offset += sizeof (hdr.drep);
3659 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
3660 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
3662 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
3664 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
3666 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3668 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3670 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3672 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3674 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3676 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3678 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3680 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3682 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
3683 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
3686 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
3688 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
3694 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3698 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3702 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
3703 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
3704 if (dg_flags1_tree) {
3705 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
3706 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
3707 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
3708 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
3709 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
3710 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
3711 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
3712 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
3718 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
3719 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
3720 if (dg_flags2_tree) {
3721 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
3722 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
3723 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
3724 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
3725 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
3726 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
3727 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
3728 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
3734 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
3735 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3737 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3738 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3739 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3742 offset += sizeof (hdr.drep);
3745 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
3749 /* XXX - use "dissect_ndr_uuid_t()"? */
3750 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3751 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3752 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
3753 hdr.obj_id.Data4[0],
3754 hdr.obj_id.Data4[1],
3755 hdr.obj_id.Data4[2],
3756 hdr.obj_id.Data4[3],
3757 hdr.obj_id.Data4[4],
3758 hdr.obj_id.Data4[5],
3759 hdr.obj_id.Data4[6],
3760 hdr.obj_id.Data4[7]);
3761 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3762 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3763 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3764 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
3769 /* XXX - use "dissect_ndr_uuid_t()"? */
3770 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3771 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3772 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
3780 hdr.if_id.Data4[7]);
3781 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3782 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3783 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
3784 offset, 16, uuid_str, "Interface: %s", uuid_str);
3789 /* XXX - use "dissect_ndr_uuid_t()"? */
3790 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3791 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3792 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
3793 hdr.act_id.Data4[0],
3794 hdr.act_id.Data4[1],
3795 hdr.act_id.Data4[2],
3796 hdr.act_id.Data4[3],
3797 hdr.act_id.Data4[4],
3798 hdr.act_id.Data4[5],
3799 hdr.act_id.Data4[6],
3800 hdr.act_id.Data4[7]);
3801 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3802 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3803 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
3804 offset, 16, uuid_str, "Activity: %s", uuid_str);
3809 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
3813 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
3817 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
3818 if (check_col (pinfo->cinfo, COL_INFO)) {
3819 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq_num: %u", hdr.seqnum);
3824 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
3828 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
3832 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
3836 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
3840 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
3841 if (check_col (pinfo->cinfo, COL_INFO)) {
3842 if (hdr.flags1 & PFCL1_FRAG) {
3843 /* Fragmented - put the fragment number into the Info column */
3844 col_append_fstr (pinfo->cinfo, COL_INFO, " frag_num: %u",
3851 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
3855 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
3856 if (check_col (pinfo->cinfo, COL_INFO)) {
3857 if (hdr.flags1 & PFCL1_FRAG) {
3858 /* Fragmented - put the serial number into the Info column */
3859 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3860 (hdr.serial_hi << 8) | hdr.serial_lo);
3867 * XXX - for Kerberos, we get a protection level; if it's
3868 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
3871 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
3876 * keeping track of the conversation shouldn't really be necessary
3877 * for connectionless packets, because everything we need to know
3878 * to dissect is in the header for each packet. Unfortunately,
3879 * Microsoft's implementation is buggy and often puts the
3880 * completely wrong if_id in the header. go figure. So, keep
3881 * track of the seqnum and use that if possible. Note: that's not
3882 * completely correct. It should really be done based on both the
3883 * activity_id and seqnum. I haven't seen anywhere that it would
3884 * make a difference, but for future reference...
3886 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
3887 pinfo->srcport, pinfo->destport, 0);
3889 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
3890 pinfo->srcport, pinfo->destport, 0);
3894 * Packet type specific stuff is next.
3897 switch (hdr.ptype) {
3899 case PDU_CANCEL_ACK:
3900 /* Body is optional */
3901 /* XXX - we assume "frag_len" is the length of the body */
3902 if (hdr.frag_len != 0)
3903 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3908 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
3909 * but in at least one capture none of the Cl_cancel PDUs had a
3912 /* XXX - we assume "frag_len" is the length of the body */
3913 if (hdr.frag_len != 0)
3914 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
3918 /* Body is optional; if present, it's the same as PDU_FACK */
3919 /* XXX - we assume "frag_len" is the length of the body */
3920 if (hdr.frag_len != 0)
3921 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3925 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3930 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3934 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
3938 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
3941 /* these requests have no body */
3953 dcerpc_init_protocol (void)
3955 /* structures and data for BIND */
3957 g_hash_table_destroy (dcerpc_binds);
3959 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
3961 if (dcerpc_bind_key_chunk){
3962 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
3964 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
3965 sizeof (dcerpc_bind_key),
3966 200 * sizeof (dcerpc_bind_key),
3968 if (dcerpc_bind_value_chunk){
3969 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
3971 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
3972 sizeof (dcerpc_bind_value),
3973 200 * sizeof (dcerpc_bind_value),
3975 /* structures and data for CALL */
3977 g_hash_table_destroy (dcerpc_calls);
3979 dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
3980 if (dcerpc_call_key_chunk){
3981 g_mem_chunk_destroy (dcerpc_call_key_chunk);
3983 dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
3984 sizeof (dcerpc_call_key),
3985 200 * sizeof (dcerpc_call_key),
3987 if (dcerpc_call_value_chunk){
3988 g_mem_chunk_destroy (dcerpc_call_value_chunk);
3990 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
3991 sizeof (dcerpc_call_value),
3992 200 * sizeof (dcerpc_call_value),
3995 /* structure and data for MATCHED */
3996 if (dcerpc_matched){
3997 g_hash_table_destroy (dcerpc_matched);
3999 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
4000 if (dcerpc_matched_key_chunk){
4001 g_mem_chunk_destroy (dcerpc_matched_key_chunk);
4003 dcerpc_matched_key_chunk = g_mem_chunk_new ("dcerpc_matched_key_chunk",
4004 sizeof (dcerpc_matched_key),
4005 200 * sizeof (dcerpc_matched_key),
4010 proto_register_dcerpc (void)
4012 static hf_register_info hf[] = {
4013 { &hf_dcerpc_request_in,
4014 { "Request in", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
4015 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
4016 { &hf_dcerpc_response_in,
4017 { "Response in", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
4018 NULL, 0, "The response to this packet is in this packet", HFILL }},
4019 { &hf_dcerpc_referent_id,
4020 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
4021 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
4023 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4024 { &hf_dcerpc_ver_minor,
4025 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4026 { &hf_dcerpc_packet_type,
4027 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
4028 { &hf_dcerpc_cn_flags,
4029 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4030 { &hf_dcerpc_cn_flags_first_frag,
4031 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
4032 { &hf_dcerpc_cn_flags_last_frag,
4033 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
4034 { &hf_dcerpc_cn_flags_cancel_pending,
4035 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
4036 { &hf_dcerpc_cn_flags_reserved,
4037 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
4038 { &hf_dcerpc_cn_flags_mpx,
4039 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
4040 { &hf_dcerpc_cn_flags_dne,
4041 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
4042 { &hf_dcerpc_cn_flags_maybe,
4043 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
4044 { &hf_dcerpc_cn_flags_object,
4045 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
4047 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
4048 { &hf_dcerpc_drep_byteorder,
4049 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
4050 { &hf_dcerpc_drep_character,
4051 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
4052 { &hf_dcerpc_drep_fp,
4053 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
4054 { &hf_dcerpc_cn_frag_len,
4055 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4056 { &hf_dcerpc_cn_auth_len,
4057 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4058 { &hf_dcerpc_cn_call_id,
4059 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4060 { &hf_dcerpc_cn_max_xmit,
4061 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4062 { &hf_dcerpc_cn_max_recv,
4063 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4064 { &hf_dcerpc_cn_assoc_group,
4065 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4066 { &hf_dcerpc_cn_num_ctx_items,
4067 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4068 { &hf_dcerpc_cn_ctx_id,
4069 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4070 { &hf_dcerpc_cn_num_trans_items,
4071 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4072 { &hf_dcerpc_cn_bind_if_id,
4073 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4074 { &hf_dcerpc_cn_bind_if_ver,
4075 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4076 { &hf_dcerpc_cn_bind_if_ver_minor,
4077 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4078 { &hf_dcerpc_cn_bind_trans_id,
4079 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4080 { &hf_dcerpc_cn_bind_trans_ver,
4081 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4082 { &hf_dcerpc_cn_alloc_hint,
4083 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4084 { &hf_dcerpc_cn_sec_addr_len,
4085 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4086 { &hf_dcerpc_cn_sec_addr,
4087 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
4088 { &hf_dcerpc_cn_num_results,
4089 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4090 { &hf_dcerpc_cn_ack_result,
4091 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
4092 { &hf_dcerpc_cn_ack_reason,
4093 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
4094 { &hf_dcerpc_cn_ack_trans_id,
4095 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4096 { &hf_dcerpc_cn_ack_trans_ver,
4097 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4098 { &hf_dcerpc_cn_reject_reason,
4099 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
4100 { &hf_dcerpc_cn_num_protocols,
4101 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4102 { &hf_dcerpc_cn_protocol_ver_major,
4103 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4104 { &hf_dcerpc_cn_protocol_ver_minor,
4105 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4106 { &hf_dcerpc_cn_cancel_count,
4107 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4108 { &hf_dcerpc_cn_status,
4109 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4110 { &hf_dcerpc_auth_type,
4111 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4112 { &hf_dcerpc_auth_level,
4113 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
4114 { &hf_dcerpc_auth_pad_len,
4115 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4116 { &hf_dcerpc_auth_rsrvd,
4117 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4118 { &hf_dcerpc_auth_ctx_id,
4119 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4120 { &hf_dcerpc_dg_flags1,
4121 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4122 { &hf_dcerpc_dg_flags1_rsrvd_01,
4123 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
4124 { &hf_dcerpc_dg_flags1_last_frag,
4125 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
4126 { &hf_dcerpc_dg_flags1_frag,
4127 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
4128 { &hf_dcerpc_dg_flags1_nofack,
4129 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
4130 { &hf_dcerpc_dg_flags1_maybe,
4131 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
4132 { &hf_dcerpc_dg_flags1_idempotent,
4133 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
4134 { &hf_dcerpc_dg_flags1_broadcast,
4135 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
4136 { &hf_dcerpc_dg_flags1_rsrvd_80,
4137 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
4138 { &hf_dcerpc_dg_flags2,
4139 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4140 { &hf_dcerpc_dg_flags2_rsrvd_01,
4141 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
4142 { &hf_dcerpc_dg_flags2_cancel_pending,
4143 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
4144 { &hf_dcerpc_dg_flags2_rsrvd_04,
4145 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
4146 { &hf_dcerpc_dg_flags2_rsrvd_08,
4147 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
4148 { &hf_dcerpc_dg_flags2_rsrvd_10,
4149 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
4150 { &hf_dcerpc_dg_flags2_rsrvd_20,
4151 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
4152 { &hf_dcerpc_dg_flags2_rsrvd_40,
4153 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
4154 { &hf_dcerpc_dg_flags2_rsrvd_80,
4155 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
4156 { &hf_dcerpc_dg_serial_lo,
4157 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4158 { &hf_dcerpc_dg_serial_hi,
4159 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4160 { &hf_dcerpc_dg_ahint,
4161 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4162 { &hf_dcerpc_dg_ihint,
4163 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4164 { &hf_dcerpc_dg_frag_len,
4165 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4166 { &hf_dcerpc_dg_frag_num,
4167 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4168 { &hf_dcerpc_dg_auth_proto,
4169 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4170 { &hf_dcerpc_dg_seqnum,
4171 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4172 { &hf_dcerpc_dg_server_boot,
4173 { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4174 { &hf_dcerpc_dg_if_ver,
4175 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4176 { &hf_dcerpc_krb5_av_prot_level,
4177 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
4178 { &hf_dcerpc_krb5_av_key_vers_num,
4179 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4180 { &hf_dcerpc_krb5_av_key_auth_verifier,
4181 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
4182 { &hf_dcerpc_obj_id,
4183 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4184 { &hf_dcerpc_dg_if_id,
4185 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4186 { &hf_dcerpc_dg_act_id,
4187 { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4189 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4191 { &hf_dcerpc_dg_cancel_vers,
4192 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4194 { &hf_dcerpc_dg_cancel_id,
4195 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4197 { &hf_dcerpc_dg_server_accepting_cancels,
4198 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
4200 { &hf_dcerpc_dg_fack_vers,
4201 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4203 { &hf_dcerpc_dg_fack_window_size,
4204 { "Window Size", "dcerpc.fack_window size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4206 { &hf_dcerpc_dg_fack_max_tsdu,
4207 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4209 { &hf_dcerpc_dg_fack_max_frag_size,
4210 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4212 { &hf_dcerpc_dg_fack_serial_num,
4213 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4215 { &hf_dcerpc_dg_fack_selack_len,
4216 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4218 { &hf_dcerpc_dg_fack_selack,
4219 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4221 { &hf_dcerpc_dg_status,
4222 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4224 { &hf_dcerpc_array_max_count,
4225 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
4227 { &hf_dcerpc_array_offset,
4228 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
4230 { &hf_dcerpc_array_actual_count,
4231 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
4233 { &hf_dcerpc_array_buffer,
4234 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
4237 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4239 { &hf_dcerpc_fragments,
4240 { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
4241 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
4243 { &hf_dcerpc_fragment,
4244 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
4245 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
4247 { &hf_dcerpc_fragment_overlap,
4248 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
4250 { &hf_dcerpc_fragment_overlap_conflict,
4251 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
4253 { &hf_dcerpc_fragment_multiple_tails,
4254 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
4256 { &hf_dcerpc_fragment_too_long_fragment,
4257 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
4259 { &hf_dcerpc_fragment_error,
4260 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
4263 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "Time between Request and Reply for DCE-RPC calls", HFILL }},
4264 { &hf_dcerpc_reassembled_in,
4265 { "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 }},
4266 { &hf_dcerpc_sec_chan,
4267 { "Verifier", "verifier", FT_NONE, BASE_NONE, NULL, 0x0, "Verifier",
4269 { &hf_dcerpc_sec_chan_sig,
4270 { "Signature", "dcerpc.sec_chan.sig", FT_BYTES, BASE_HEX, NULL,
4271 0x0, "Signature", HFILL }},
4272 { &hf_dcerpc_sec_chan_unk,
4273 { "Unknown", "dcerpc.sec_chan.unk", FT_BYTES, BASE_HEX, NULL,
4274 0x0, "Unknown", HFILL }},
4275 { &hf_dcerpc_sec_chan_seq,
4276 { "Sequence No", "dcerpc.sec_chan.seq", FT_BYTES, BASE_HEX, NULL,
4277 0x0, "Sequence No", HFILL }},
4278 { &hf_dcerpc_sec_chan_nonce,
4279 { "Nonce", "dcerpc.sec_chan.nonce", FT_BYTES, BASE_HEX, NULL,
4280 0x0, "Nonce", HFILL }},
4283 static gint *ett[] = {
4285 &ett_dcerpc_cn_flags,
4287 &ett_dcerpc_dg_flags1,
4288 &ett_dcerpc_dg_flags2,
4289 &ett_dcerpc_pointer_data,
4291 &ett_dcerpc_fragments,
4292 &ett_dcerpc_fragment,
4293 &ett_dcerpc_krb5_auth_verf,
4296 module_t *dcerpc_module;
4298 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
4299 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
4300 proto_register_subtree_array (ett, array_length (ett));
4301 register_init_routine (dcerpc_init_protocol);
4302 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
4303 prefs_register_bool_preference (dcerpc_module,
4305 "Desegment all DCE/RPC over TCP",
4306 "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
4307 &dcerpc_cn_desegment);
4308 prefs_register_bool_preference (dcerpc_module,
4309 "reassemble_dcerpc",
4310 "Reassemble DCE/RPC fragments",
4311 "Whether the DCE/RPC dissector should reassemble all fragmented PDUs",
4312 &dcerpc_reassemble);
4313 register_init_routine(dcerpc_reassemble_init);
4314 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
4315 dcerpc_tap=register_tap("dcerpc");
4319 proto_reg_handoff_dcerpc (void)
4321 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
4322 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
4323 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
4324 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
4325 ntlmssp_handle = find_dissector("ntlmssp");
4326 ntlmssp_verf_handle = find_dissector("ntlmssp_verf");
4327 ntlmssp_enc_payload_handle = find_dissector("ntlmssp_encrypted_payload");
4328 gssapi_handle = find_dissector("gssapi");
4329 gssapi_verf_handle = find_dissector("gssapi_verf");
4330 dcerpc_smb_init(proto_dcerpc);