2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas@webspan.net>
5 * $Id: packet-dcerpc.c,v 1.117 2003/04/20 11:36:13 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;
402 static gint ett_dcerpc = -1;
403 static gint ett_dcerpc_cn_flags = -1;
404 static gint ett_dcerpc_drep = -1;
405 static gint ett_dcerpc_dg_flags1 = -1;
406 static gint ett_dcerpc_dg_flags2 = -1;
407 static gint ett_dcerpc_pointer_data = -1;
408 static gint ett_dcerpc_string = -1;
409 static gint ett_dcerpc_fragments = -1;
410 static gint ett_dcerpc_fragment = -1;
411 static gint ett_decrpc_krb5_auth_verf = -1;
413 static dissector_handle_t ntlmssp_handle, ntlmssp_verf_handle,
414 ntlmssp_enc_payload_handle;
415 static dissector_handle_t gssapi_handle, gssapi_verf_handle;
417 static const fragment_items dcerpc_frag_items = {
418 &ett_dcerpc_fragments,
419 &ett_dcerpc_fragment,
421 &hf_dcerpc_fragments,
423 &hf_dcerpc_fragment_overlap,
424 &hf_dcerpc_fragment_overlap_conflict,
425 &hf_dcerpc_fragment_multiple_tails,
426 &hf_dcerpc_fragment_too_long_fragment,
427 &hf_dcerpc_fragment_error,
433 typedef struct _dcerpc_auth_info {
440 /* try to desegment big DCE/RPC packets over TCP? */
441 static gboolean dcerpc_cn_desegment = TRUE;
443 /* reassemble DCE/RPC fragments */
444 /* reassembly of dcerpc fragments will not work for the case where ONE frame
445 might contain multiple dcerpc fragments for different PDUs.
446 this case would be so unusual/weird so if you got captures like that:
449 static gboolean dcerpc_reassemble = FALSE;
450 static GHashTable *dcerpc_co_reassemble_table = NULL;
451 static GHashTable *dcerpc_cl_reassemble_table = NULL;
454 dcerpc_reassemble_init(void)
456 fragment_table_init(&dcerpc_co_reassemble_table);
457 fragment_table_init(&dcerpc_cl_reassemble_table);
464 /* the registered subdissectors */
465 GHashTable *dcerpc_uuids=NULL;
468 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
470 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
471 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
472 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
473 && (key1->ver == key2->ver));
477 dcerpc_uuid_hash (gconstpointer k)
479 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
480 /* This isn't perfect, but the Data1 part of these is almost always
482 return key->uuid.Data1;
486 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
487 dcerpc_sub_dissector *procs, int opnum_hf)
489 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
490 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
495 value->proto = proto;
497 value->name = proto_get_protocol_short_name (proto);
498 value->procs = procs;
499 value->opnum_hf = opnum_hf;
501 g_hash_table_insert (dcerpc_uuids, key, value);
504 /* Function to find the name of a registered protocol
505 * or NULL if the protocol/version is not known to ethereal.
508 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
511 dcerpc_uuid_value *sub_proto;
515 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
518 return sub_proto->name;
521 /* Function to find the subdissector table of a registered protocol
522 * or NULL if the protocol/version is not known to ethereal.
524 dcerpc_sub_dissector *
525 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
528 dcerpc_uuid_value *sub_proto;
532 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
535 return sub_proto->procs;
540 * To keep track of ctx_id mappings.
542 * Everytime we see a bind call we update this table.
543 * Note that we always specify a SMB FID. For non-SMB transports this
546 static GHashTable *dcerpc_binds=NULL;
548 typedef struct _dcerpc_bind_key {
549 conversation_t *conv;
554 typedef struct _dcerpc_bind_value {
559 static GMemChunk *dcerpc_bind_key_chunk=NULL;
560 static GMemChunk *dcerpc_bind_value_chunk=NULL;
563 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
565 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
566 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
567 return (key1->conv == key2->conv
568 && key1->ctx_id == key2->ctx_id
569 && key1->smb_fid == key2->smb_fid);
573 dcerpc_bind_hash (gconstpointer k)
575 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
576 return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
581 * To keep track of callid mappings. Should really use some generic
582 * conversation support instead.
584 static GHashTable *dcerpc_calls=NULL;
586 typedef struct _dcerpc_call_key {
587 conversation_t *conv;
592 static GMemChunk *dcerpc_call_key_chunk=NULL;
594 static GMemChunk *dcerpc_call_value_chunk=NULL;
597 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
599 const dcerpc_call_key *key1 = (const dcerpc_call_key *)k1;
600 const dcerpc_call_key *key2 = (const dcerpc_call_key *)k2;
601 return (key1->conv == key2->conv
602 && key1->call_id == key2->call_id
603 && key1->smb_fid == key2->smb_fid);
607 dcerpc_call_hash (gconstpointer k)
609 const dcerpc_call_key *key = (const dcerpc_call_key *)k;
610 return ((guint32)key->conv) + key->call_id + key->smb_fid;
614 /* to keep track of matched calls/responses
615 this one uses the same value struct as calls, but the key is the frame id
617 static GHashTable *dcerpc_matched=NULL;
619 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
621 return (guint32)k1 == (guint32)k2;
625 dcerpc_matched_hash (gconstpointer k)
633 * Utility functions. Modeled after packet-rpc.c
637 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
638 proto_tree *tree, char *drep,
639 int hfindex, guint8 *pdata)
643 data = tvb_get_guint8 (tvb, offset);
645 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
653 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
654 proto_tree *tree, char *drep,
655 int hfindex, guint16 *pdata)
659 data = ((drep[0] & 0x10)
660 ? tvb_get_letohs (tvb, offset)
661 : tvb_get_ntohs (tvb, offset));
664 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
672 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
673 proto_tree *tree, char *drep,
674 int hfindex, guint32 *pdata)
678 data = ((drep[0] & 0x10)
679 ? tvb_get_letohl (tvb, offset)
680 : tvb_get_ntohl (tvb, offset));
683 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
690 /* handles 32 bit unix time_t */
692 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
693 proto_tree *tree, char *drep,
694 int hfindex, guint32 *pdata)
699 data = ((drep[0] & 0x10)
700 ? tvb_get_letohl (tvb, offset)
701 : tvb_get_ntohl (tvb, offset));
706 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
715 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
716 proto_tree *tree, char *drep,
717 int hfindex, unsigned char *pdata)
720 tvb_memcpy(tvb, pdata, offset, 8);
721 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
723 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
724 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
725 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
726 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
731 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
739 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
740 proto_tree *tree, char *drep,
741 int hfindex, gfloat *pdata)
747 case(DCE_RPC_DREP_FP_IEEE):
748 data = ((drep[0] & 0x10)
749 ? tvb_get_letohieee_float(tvb, offset)
750 : tvb_get_ntohieee_float(tvb, offset));
752 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
755 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
756 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
757 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
759 /* ToBeDone: non IEEE floating formats */
760 /* Set data to a negative infinity value */
761 data = -1.0 * 1e100 * 1e100;
763 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
773 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
774 proto_tree *tree, char *drep,
775 int hfindex, gdouble *pdata)
781 case(DCE_RPC_DREP_FP_IEEE):
782 data = ((drep[0] & 0x10)
783 ? tvb_get_letohieee_double(tvb, offset)
784 : tvb_get_ntohieee_double(tvb, offset));
786 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
789 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
790 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
791 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
793 /* ToBeDone: non IEEE double formats */
794 /* Set data to a negative infinity value */
795 data = -1.0 * 1e100 * 1e100;
797 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
807 * a couple simpler things
810 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
812 if (drep[0] & 0x10) {
813 return tvb_get_letohs (tvb, offset);
815 return tvb_get_ntohs (tvb, offset);
820 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
822 if (drep[0] & 0x10) {
823 return tvb_get_letohl (tvb, offset);
825 return tvb_get_ntohl (tvb, offset);
830 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
833 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
834 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
835 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
837 for (i=0; i<sizeof (uuid->Data4); i++) {
838 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
845 /* function to dissect a unidimensional conformant array */
847 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
848 proto_tree *tree, char *drep,
849 dcerpc_dissect_fnct_t *fnct)
855 di=pinfo->private_data;
856 if(di->conformant_run){
857 /* conformant run, just dissect the max_count header */
859 di->conformant_run=0;
860 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
861 hf_dcerpc_array_max_count, &di->array_max_count);
862 di->array_max_count_offset=offset-4;
863 di->conformant_run=1;
864 di->conformant_eaten=offset-old_offset;
866 /* we don't remember where in the bytestream this field was */
867 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
869 /* real run, dissect the elements */
870 for(i=0;i<di->array_max_count;i++){
871 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
877 /* function to dissect a unidimensional conformant and varying array */
879 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
880 proto_tree *tree, char *drep,
881 dcerpc_dissect_fnct_t *fnct)
887 di=pinfo->private_data;
888 if(di->conformant_run){
889 /* conformant run, just dissect the max_count header */
891 di->conformant_run=0;
892 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
893 hf_dcerpc_array_max_count, &di->array_max_count);
894 di->array_max_count_offset=offset-4;
895 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
896 hf_dcerpc_array_offset, &di->array_offset);
897 di->array_offset_offset=offset-4;
898 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
899 hf_dcerpc_array_actual_count, &di->array_actual_count);
900 di->array_actual_count_offset=offset-4;
901 di->conformant_run=1;
902 di->conformant_eaten=offset-old_offset;
904 /* we dont dont remember where in the bytestream these fields were */
905 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
906 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
907 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
909 /* real run, dissect the elements */
910 for(i=0;i<di->array_actual_count;i++){
911 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
918 /* Dissect an string of bytes. This corresponds to
919 IDL of the form '[string] byte *foo'.
921 It can also be used for a conformant varying array of bytes if
922 the contents of the array should be shown as a big blob, rather
923 than showing each byte as an individual element.
925 XXX - which of those is really the IDL type for, for example,
926 the encrypted data in some MAPI packets? (Microsoft haven't
929 XXX - does this need to do all the conformant array stuff that
930 "dissect_ndr_ucvarray()" does? These are presumably for strings
931 that are conformant and varying - they're stored like conformant
932 varying arrays of bytes. */
934 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
935 proto_tree *tree, char *drep)
940 di=pinfo->private_data;
941 if(di->conformant_run){
942 /* just a run to handle conformant arrays, no scalars to dissect */
946 /* NDR array header */
948 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
949 hf_dcerpc_array_max_count, NULL);
951 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
952 hf_dcerpc_array_offset, NULL);
954 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
955 hf_dcerpc_array_actual_count, &len);
958 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
959 tvb, offset, len, drep[0] & 0x10);
966 /* For dissecting arrays that are to be interpreted as strings. */
968 /* Dissect an NDR conformant varying string of elements.
969 The length of each element is given by the 'size_is' parameter;
970 the elements are assumed to be characters or wide characters.
972 XXX - does this need to do all the conformant array stuff that
973 "dissect_ndr_ucvarray()" does? */
975 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
976 proto_tree *tree, char *drep, int size_is,
977 int hfindex, gboolean add_subtree, char **data)
980 proto_item *string_item;
981 proto_tree *string_tree;
982 guint32 len, buffer_len;
984 header_field_info *hfinfo;
986 di=pinfo->private_data;
987 if(di->conformant_run){
988 /* just a run to handle conformant arrays, no scalars to dissect */
993 string_item = proto_tree_add_text(tree, tvb, offset, 0, "%s",
994 proto_registrar_get_name(hfindex));
995 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1001 /* NDR array header */
1003 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1004 hf_dcerpc_array_max_count, NULL);
1006 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1007 hf_dcerpc_array_offset, NULL);
1009 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1010 hf_dcerpc_array_actual_count, &len);
1012 buffer_len = size_is * len;
1015 if (offset % size_is)
1016 offset += size_is - (offset % size_is);
1018 if (size_is == sizeof(guint16)) {
1019 /* XXX - use drep to determine the byte order? */
1020 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1022 * XXX - we don't support a string type with Unicode
1023 * characters, so if this is a string item, we make
1024 * its value be the "fake Unicode" string.
1026 if (tree && buffer_len) {
1027 hfinfo = proto_registrar_get_nth(hfindex);
1028 if (hfinfo->type == FT_STRING) {
1029 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1032 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1033 buffer_len, drep[0] & 0x10);
1037 s = g_malloc(buffer_len + 1);
1038 tvb_memcpy(tvb, s, offset, buffer_len);
1039 if (tree && buffer_len)
1040 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1041 buffer_len, drep[0] & 0x10);
1044 if (string_item != NULL)
1045 proto_item_append_text(string_item, ": %s", s);
1052 offset += buffer_len;
1057 /* Dissect an conformant varying string of chars.
1058 This corresponds to IDL of the form '[string] char *foo'.
1060 XXX - at least according to the DCE RPC 1.1 spec, a string has
1061 a null terminator, which isn't necessary as a terminator for
1062 the transfer language (as there's a length), but is presumably
1063 there for the benefit of null-terminated-string languages
1064 such as C. Is this ever used for purely counted strings?
1065 (Not that it matters if it is.) */
1067 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1068 proto_tree *tree, char *drep)
1071 di=pinfo->private_data;
1073 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1074 sizeof(guint8), di->hf_index,
1078 /* Dissect a conformant varying string of wchars (wide characters).
1079 This corresponds to IDL of the form '[string] wchar *foo'
1081 XXX - at least according to the DCE RPC 1.1 spec, a string has
1082 a null terminator, which isn't necessary as a terminator for
1083 the transfer language (as there's a length), but is presumably
1084 there for the benefit of null-terminated-string languages
1085 such as C. Is this ever used for purely counted strings?
1086 (Not that it matters if it is.) */
1088 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1089 proto_tree *tree, char *drep)
1092 di=pinfo->private_data;
1094 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1095 sizeof(guint16), di->hf_index,
1099 /* ndr pointer handling */
1100 /* list of pointers encountered so far */
1101 static GSList *ndr_pointer_list = NULL;
1103 /* position where in the list to insert newly encountered pointers */
1104 static int ndr_pointer_list_pos=0;
1106 /* boolean controlling whether pointers are top-level or embedded */
1107 static gboolean pointers_are_top_level = TRUE;
1109 /* as a kludge, we represent all embedded reference pointers as id==-1
1110 hoping that his will not collide with any non-ref pointers */
1111 typedef struct ndr_pointer_data {
1113 proto_item *item; /* proto_item for pointer */
1114 proto_tree *tree; /* subtree of above item */
1115 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1117 dcerpc_callback_fnct_t *callback;
1118 void *callback_args;
1119 } ndr_pointer_data_t;
1122 init_ndr_pointer_list(packet_info *pinfo)
1126 di=pinfo->private_data;
1127 di->conformant_run=0;
1129 while(ndr_pointer_list){
1130 ndr_pointer_data_t *npd;
1132 npd=g_slist_nth_data(ndr_pointer_list, 0);
1133 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1139 ndr_pointer_list=NULL;
1140 ndr_pointer_list_pos=0;
1141 pointers_are_top_level=TRUE;
1145 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *drep)
1147 int found_new_pointer;
1151 di=pinfo->private_data;
1155 found_new_pointer=0;
1156 len=g_slist_length(ndr_pointer_list);
1158 ndr_pointer_data_t *tnpd;
1159 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1161 dcerpc_dissect_fnct_t *fnct;
1163 found_new_pointer=1;
1166 ndr_pointer_list_pos=i+1;
1167 di->hf_index=tnpd->hf_index;
1168 /* first a run to handle any conformant
1170 di->conformant_run=1;
1171 di->conformant_eaten=0;
1172 old_offset = offset;
1173 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1175 g_assert((offset-old_offset)==di->conformant_eaten);
1176 /* This is to check for any bugs in the dissectors.
1178 * Basically, the NDR representation will store all
1179 * arrays in two blocks, one block with the dimension
1180 * discreption, like size, number of elements and such,
1181 * and another block that contains the actual data stored
1183 * If the array is embedded directly inside another,
1184 * encapsulating aggregate type, like a union or struct,
1185 * then these two blocks will be stored at different places
1186 * in the bytestream, with other data between the blocks.
1188 * For this reason, all pointers to types (both aggregate
1189 * and scalar, for simplicity no distinction is made)
1190 * will have its dissector called twice.
1191 * The dissector will first be called with conformant_run==1
1192 * in which mode the dissector MUST NOT consume any data from
1193 * the tvbuff (i.e. may not dissect anything) except the
1194 * initial control block for arrays.
1195 * The second time the dissector is called, with
1196 * conformant_run==0, all other data for the type will be
1199 * All dissect_ndr_<type> dissectors are already prepared
1200 * for this and knows when it should eat data from the tvb
1201 * and when not to, so implementors of dissectors will
1202 * normally not need to worry about this or even know about
1203 * it. However, if a dissector for an aggregate type calls
1204 * a subdissector from outside packet-dcerpc.c, such as
1205 * the dissector in packet-smb.c for NT Security Descriptors
1206 * as an example, then it is VERY important to encapsulate
1207 * this call to an external subdissector with the appropriate
1208 * test for conformant_run, i.e. it will need something like
1212 * di=pinfo->private_data;
1213 * if(di->conformant_run){
1217 * to make sure it makes the right thing.
1218 * This assert will signal when someone has forgotten to
1219 * make the dissector aware of this requirement.
1222 /* now we dissect the actual pointer */
1223 di->conformant_run=0;
1224 old_offset = offset;
1225 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1227 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1231 } while(found_new_pointer);
1238 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1239 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1240 dcerpc_callback_fnct_t *callback, void *callback_args)
1242 ndr_pointer_data_t *npd;
1244 /* check if this pointer is valid */
1247 dcerpc_call_value *value;
1249 di=pinfo->private_data;
1250 value=di->call_data;
1253 if(!(pinfo->fd->flags.visited)){
1254 if(id>value->max_ptr){
1259 /* if we havent seen the request bail out since we cant
1260 know whether this is the first non-NULL instance
1262 if(value->req_frame==0){
1263 /* XXX THROW EXCEPTION */
1266 /* We saw this one in the request frame, nothing to
1268 if(id<=value->max_ptr){
1274 npd=g_malloc(sizeof(ndr_pointer_data_t));
1279 npd->hf_index=hf_index;
1280 npd->callback=callback;
1281 npd->callback_args=callback_args;
1282 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1283 ndr_pointer_list_pos);
1284 ndr_pointer_list_pos++;
1289 find_pointer_index(guint32 id)
1291 ndr_pointer_data_t *npd;
1294 len=g_slist_length(ndr_pointer_list);
1296 npd=g_slist_nth_data(ndr_pointer_list, i);
1307 /* This function dissects an NDR pointer and stores the callback for later
1308 * deferred dissection.
1310 * fnct is the callback function for when we have reached this object in
1313 * type is what type of pointer.
1315 * this is text is what text we should put in any created tree node.
1317 * hf_index is what hf value we want to pass to the callback function when
1318 * it is called, the callback can later pich this one up from di->hf_index.
1320 * callback is executed after the pointer has been dereferenced.
1322 * callback_args is passed as an argument to the callback function
1324 * See packet-dcerpc-samr.c for examples
1327 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1328 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1329 int type, char *text, int hf_index,
1330 dcerpc_callback_fnct_t *callback, void *callback_args)
1334 di=pinfo->private_data;
1335 if(di->conformant_run){
1336 /* this call was only for dissecting the header for any
1337 embedded conformant array. we will not parse any
1338 pointers in this mode.
1343 /*TOP LEVEL REFERENCE POINTER*/
1344 if( pointers_are_top_level
1345 &&(type==NDR_POINTER_REF) ){
1349 /* we must find out a nice way to do the length here */
1350 item=proto_tree_add_text(tree, tvb, offset, 0,
1352 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1354 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1355 hf_index, callback, callback_args);
1359 /*TOP LEVEL FULL POINTER*/
1360 if( pointers_are_top_level
1361 && (type==NDR_POINTER_PTR) ){
1367 /* get the referent id */
1368 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1370 /* we got a NULL pointer */
1372 proto_tree_add_text(tree, tvb, offset-4, 4,
1373 "(NULL pointer) %s",text);
1377 /* see if we have seen this pointer before */
1378 idx=find_pointer_index(id);
1380 /* we have seen this pointer before */
1382 proto_tree_add_text(tree, tvb, offset-4, 4,
1383 "(duplicate PTR) %s",text);
1388 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1390 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1391 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1392 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1393 callback, callback_args);
1396 /*TOP LEVEL UNIQUE POINTER*/
1397 if( pointers_are_top_level
1398 && (type==NDR_POINTER_UNIQUE) ){
1403 /* get the referent id */
1404 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1406 /* we got a NULL pointer */
1408 proto_tree_add_text(tree, tvb, offset-4, 4,
1409 "(NULL pointer) %s",text);
1414 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1416 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1417 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1418 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1419 hf_index, callback, callback_args);
1423 /*EMBEDDED REFERENCE POINTER*/
1424 if( (!pointers_are_top_level)
1425 && (type==NDR_POINTER_REF) ){
1430 /* get the referent id */
1431 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1434 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1436 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1437 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1438 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1439 hf_index, callback, callback_args);
1443 /*EMBEDDED UNIQUE POINTER*/
1444 if( (!pointers_are_top_level)
1445 && (type==NDR_POINTER_UNIQUE) ){
1450 /* get the referent id */
1451 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1453 /* we got a NULL pointer */
1455 proto_tree_add_text(tree, tvb, offset-4, 4,
1456 "(NULL pointer) %s", text);
1461 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1463 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1464 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1465 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1466 hf_index, callback, callback_args);
1470 /*EMBEDDED FULL POINTER*/
1471 if( (!pointers_are_top_level)
1472 && (type==NDR_POINTER_PTR) ){
1478 /* get the referent id */
1479 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1481 /* we got a NULL pointer */
1483 proto_tree_add_text(tree, tvb, offset-4, 4,
1484 "(NULL pointer) %s",text);
1488 /* see if we have seen this pointer before */
1489 idx=find_pointer_index(id);
1491 /* we have seen this pointer before */
1493 proto_tree_add_text(tree, tvb, offset-4, 4,
1494 "(duplicate PTR) %s",text);
1499 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1501 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1502 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1503 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1504 callback, callback_args);
1510 /* After each top level pointer we have dissected we have to
1511 dissect all deferrals before we move on to the next top level
1513 if(pointers_are_top_level==TRUE){
1514 pointers_are_top_level=FALSE;
1515 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
1516 pointers_are_top_level=TRUE;
1523 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1524 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1525 int type, char *text, int hf_index)
1527 return dissect_ndr_pointer_cb(
1528 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
1533 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
1534 proto_tree *dcerpc_tree,
1535 tvbuff_t *tvb, gint offset,
1536 char *drep, dcerpc_info *info,
1537 dcerpc_auth_info *auth_info)
1539 dcerpc_uuid_key key;
1540 dcerpc_uuid_value *sub_proto;
1542 proto_tree *volatile sub_tree = NULL;
1543 dcerpc_sub_dissector *proc;
1545 dcerpc_dissect_fnct_t *volatile sub_dissect;
1546 const char *volatile saved_proto;
1547 void *volatile saved_private_data;
1549 key.uuid = info->call_data->uuid;
1550 key.ver = info->call_data->ver;
1553 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1554 || !proto_is_protocol_enabled(sub_proto->proto)) {
1556 * We don't have a dissector for this UUID, or the protocol
1557 * for that UUID is disabled.
1559 length = tvb_length_remaining (tvb, offset);
1561 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
1562 "Stub data (%d byte%s)", length,
1563 plurality(length, "", "s"));
1568 for (proc = sub_proto->procs; proc->name; proc++) {
1569 if (proc->num == info->call_data->opnum) {
1578 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1579 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1582 if (check_col (pinfo->cinfo, COL_INFO)) {
1583 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1584 name, info->request ? "request" : "reply");
1588 proto_item *sub_item;
1589 sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
1593 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1597 * Put the operation number into the tree along with
1598 * the operation's name.
1601 if (sub_proto->opnum_hf != -1)
1602 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
1603 tvb, 0, 0, info->call_data->opnum,
1604 "Operation: %s (%u)",
1605 name, info->call_data->opnum);
1607 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
1608 0, 0, info->call_data->opnum,
1609 "Operation: %s (%u)",
1610 name, info->call_data->opnum);
1614 * If the authentication level is DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
1615 * the stub data is encrypted, and we'd have to decrypt it in
1616 * order to dissect it.
1618 if (auth_info != NULL &&
1619 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1620 length = tvb_length_remaining (tvb, offset);
1622 proto_tree_add_text(sub_tree, tvb, offset, length,
1623 "Encrypted stub data (%d byte%s)",
1624 length, plurality(length, "", "s"));
1626 switch (auth_info->auth_type) {
1628 case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
1630 tvbuff_t *ntlmssp_tvb;
1631 ntlmssp_tvb = tvb_new_subset(tvb, offset, length, length);
1632 pinfo->decrypted_data=NULL;
1634 call_dissector(ntlmssp_enc_payload_handle, ntlmssp_tvb, pinfo,
1637 if(pinfo->decrypted_data){
1638 ntlmssp_decrypted_info_t *ndi=pinfo->decrypted_data;
1641 sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
1643 saved_proto = pinfo->current_proto;
1644 saved_private_data = pinfo->private_data;
1645 pinfo->current_proto = sub_proto->name;
1646 pinfo->private_data = (void *)info;
1648 init_ndr_pointer_list(pinfo);
1651 * Catch ReportedBoundsError, as that could
1652 * be due to the decryption being bad,
1653 * and doesn't mean that the tvbuff we were
1654 * handed has a malformed packet.
1657 offset = sub_dissect (ndi->decr_tvb, 0, pinfo, ndi->decr_tree, drep);
1658 } CATCH(BoundsError) {
1660 } CATCH(ReportedBoundsError) {
1661 show_reported_bounds_error(tvb, pinfo, tree);
1664 pinfo->current_proto = saved_proto;
1665 pinfo->private_data = saved_private_data;
1673 sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
1675 saved_proto = pinfo->current_proto;
1676 saved_private_data = pinfo->private_data;
1677 pinfo->current_proto = sub_proto->name;
1678 pinfo->private_data = (void *)info;
1680 init_ndr_pointer_list(pinfo);
1682 * Catch ReportedBoundsError, so that even if the stub
1683 * data is bad, we still show the verifier.
1686 offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
1687 } CATCH(BoundsError) {
1689 } CATCH(ReportedBoundsError) {
1690 show_reported_bounds_error(tvb, pinfo, tree);
1693 pinfo->current_proto = saved_proto;
1694 pinfo->private_data = saved_private_data;
1696 length = tvb_length_remaining (tvb, offset);
1698 proto_tree_add_text (sub_tree, tvb, offset, length,
1699 "Stub data (%d byte%s)", length,
1700 plurality(length, "", "s"));
1704 tap_queue_packet(dcerpc_tap, pinfo, info);
1709 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
1710 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
1711 dcerpc_auth_info *auth_info)
1715 if (auth_info->auth_size != 0) {
1716 auth_offset = hdr->frag_len - hdr->auth_len;
1717 switch (auth_info->auth_type) {
1719 case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
1721 tvbuff_t *ntlmssp_tvb;
1723 ntlmssp_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
1726 call_dissector(ntlmssp_verf_handle, ntlmssp_tvb, pinfo,
1732 case DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO: {
1733 /* SPNEGO (rfc2478) */
1734 tvbuff_t *gssapi_tvb;
1736 gssapi_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
1739 call_dissector(gssapi_verf_handle, gssapi_tvb, pinfo, dcerpc_tree);
1745 proto_tree_add_text (dcerpc_tree, tvb, auth_offset, hdr->auth_len,
1750 return hdr->auth_len;
1754 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1755 e_dce_cn_common_hdr_t *hdr, gboolean are_credentials,
1756 dcerpc_auth_info *auth_info)
1761 * Initially set auth_level to -1 to indicate that we haven't
1762 * yet seen any authentication level information.
1764 auth_info->auth_level = -1;
1767 * The authentication information is at the *end* of the PDU; in
1768 * request and response PDUs, the request and response stub data
1771 * If the full packet is here, and we've got an auth len, and it's
1772 * valid, then dissect the auth info.
1774 if (tvb_length (tvb) >= hdr->frag_len
1776 && (hdr->auth_len + 8 <= hdr->frag_len)) {
1778 offset = hdr->frag_len - (hdr->auth_len + 8);
1780 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1781 hf_dcerpc_auth_type,
1782 &auth_info->auth_type);
1783 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1784 hf_dcerpc_auth_level,
1785 &auth_info->auth_level);
1787 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1788 hf_dcerpc_auth_pad_len,
1789 &auth_info->auth_pad_len);
1790 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1791 hf_dcerpc_auth_rsrvd, NULL);
1792 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1793 hf_dcerpc_auth_ctx_id, NULL);
1796 * Dissect the authentication data.
1798 if (are_credentials) {
1800 * The authentication data are credentials.
1802 switch (auth_info->auth_type) {
1804 case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
1806 tvbuff_t *ntlmssp_tvb;
1808 ntlmssp_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
1811 call_dissector(ntlmssp_handle, ntlmssp_tvb, pinfo,
1817 case DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO: {
1818 /* SPNEGO (rfc2478) */
1819 tvbuff_t *gssapi_tvb;
1821 gssapi_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
1824 call_dissector(gssapi_handle, gssapi_tvb, pinfo, dcerpc_tree);
1830 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
1831 "Auth Credentials");
1835 /* figure out where the auth padding starts */
1836 offset = hdr->frag_len - (hdr->auth_len + 8 + auth_info->auth_pad_len);
1837 if (offset > 0 && auth_info->auth_pad_len) {
1838 proto_tree_add_text (dcerpc_tree, tvb, offset,
1839 auth_info->auth_pad_len, "Auth padding");
1840 auth_info->auth_size = hdr->auth_len + 8 + auth_info->auth_pad_len;
1842 auth_info->auth_size = hdr->auth_len + 8;
1845 auth_info->auth_size = 0;
1850 /* We need to hash in the SMB fid number to generate a unique hash table
1851 key as DCERPC over SMB allows several pipes over the same TCP/IP
1854 static guint16 get_smb_fid (void *private_data)
1856 dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
1859 return 0; /* Nothing to see here */
1861 /* DCERPC over smb */
1863 if (priv->transport_type == DCERPC_TRANSPORT_SMB)
1864 return priv->data.smb.fid;
1866 /* Some other transport... */
1872 * Connection oriented packet types
1876 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
1877 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
1879 conversation_t *conv = NULL;
1880 guint8 num_ctx_items;
1882 gboolean saw_ctx_item = FALSE;
1884 guint16 num_trans_items;
1889 guint16 if_ver, if_ver_minor;
1890 char uuid_str[DCERPC_UUID_STR_LEN];
1892 dcerpc_auth_info auth_info;
1894 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1895 hf_dcerpc_cn_max_xmit, NULL);
1897 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1898 hf_dcerpc_cn_max_recv, NULL);
1900 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1901 hf_dcerpc_cn_assoc_group, NULL);
1903 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1904 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
1909 for (i = 0; i < num_ctx_items; i++) {
1910 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1911 hf_dcerpc_cn_ctx_id, &ctx_id);
1913 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1914 hf_dcerpc_cn_num_trans_items, &num_trans_items);
1916 /* XXX - use "dissect_ndr_uuid_t()"? */
1917 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
1919 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
1920 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1921 if_id.Data1, if_id.Data2, if_id.Data3,
1922 if_id.Data4[0], if_id.Data4[1],
1923 if_id.Data4[2], if_id.Data4[3],
1924 if_id.Data4[4], if_id.Data4[5],
1925 if_id.Data4[6], if_id.Data4[7]);
1926 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
1927 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
1928 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
1929 offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
1933 if (hdr->drep[0] & 0x10) {
1934 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1935 hf_dcerpc_cn_bind_if_ver, &if_ver);
1936 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1937 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1939 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1940 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1941 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1942 hf_dcerpc_cn_bind_if_ver, &if_ver);
1945 if (!saw_ctx_item) {
1946 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1947 pinfo->srcport, pinfo->destport, 0);
1949 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
1950 pinfo->srcport, pinfo->destport, 0);
1953 /* if this is the first time we see this packet, we need to
1954 update the dcerpc_binds table so that any later calls can
1955 match to the interface.
1956 XXX We assume that BINDs will NEVER be fragmented.
1958 if(!(pinfo->fd->flags.visited)){
1959 dcerpc_bind_key *key;
1960 dcerpc_bind_value *value;
1962 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
1964 key->ctx_id = ctx_id;
1965 key->smb_fid = get_smb_fid(pinfo->private_data);
1967 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
1968 value->uuid = if_id;
1969 value->ver = if_ver;
1971 /* add this entry to the bind table, first removing any
1972 previous ones that are identical
1974 if(g_hash_table_lookup(dcerpc_binds, key)){
1975 g_hash_table_remove(dcerpc_binds, key);
1977 g_hash_table_insert (dcerpc_binds, key, value);
1980 if (check_col (pinfo->cinfo, COL_INFO)) {
1981 dcerpc_uuid_key key;
1982 dcerpc_uuid_value *value;
1987 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
1988 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
1990 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
1991 if_id.Data1, if_id.Data2, if_id.Data3,
1992 if_id.Data4[0], if_id.Data4[1],
1993 if_id.Data4[2], if_id.Data4[3],
1994 if_id.Data4[4], if_id.Data4[5],
1995 if_id.Data4[6], if_id.Data4[7],
1996 if_ver, if_ver_minor);
1998 saw_ctx_item = TRUE;
2001 for (j = 0; j < num_trans_items; j++) {
2002 /* XXX - use "dissect_ndr_uuid_t()"? */
2003 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2005 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2006 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2007 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2008 trans_id.Data4[0], trans_id.Data4[1],
2009 trans_id.Data4[2], trans_id.Data4[3],
2010 trans_id.Data4[4], trans_id.Data4[5],
2011 trans_id.Data4[6], trans_id.Data4[7]);
2012 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2013 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2014 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2015 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2019 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2020 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2025 * XXX - we should save the authentication type *if* we have
2026 * an authentication header, and associate it with an authentication
2027 * context, so subsequent PDUs can use that context.
2029 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2033 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2034 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2036 guint16 max_xmit, max_recv;
2037 guint16 sec_addr_len;
2044 char uuid_str[DCERPC_UUID_STR_LEN];
2046 dcerpc_auth_info auth_info;
2048 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2049 hf_dcerpc_cn_max_xmit, &max_xmit);
2051 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2052 hf_dcerpc_cn_max_recv, &max_recv);
2054 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2055 hf_dcerpc_cn_assoc_group, NULL);
2057 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2058 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2059 if (sec_addr_len != 0) {
2060 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2061 sec_addr_len, FALSE);
2062 offset += sec_addr_len;
2066 offset += 4 - offset % 4;
2069 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2070 hf_dcerpc_cn_num_results, &num_results);
2075 for (i = 0; i < num_results; i++) {
2076 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2077 hdr->drep, hf_dcerpc_cn_ack_result,
2080 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2081 hdr->drep, hf_dcerpc_cn_ack_reason,
2085 * The reason for rejection isn't meaningful, and often isn't
2086 * set, when the syntax was accepted.
2091 /* XXX - use "dissect_ndr_uuid_t()"? */
2092 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2094 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2095 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2096 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2097 trans_id.Data4[0], trans_id.Data4[1],
2098 trans_id.Data4[2], trans_id.Data4[3],
2099 trans_id.Data4[4], trans_id.Data4[5],
2100 trans_id.Data4[6], trans_id.Data4[7]);
2101 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2102 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2103 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2104 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2108 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2109 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2113 * XXX - do we need to do anything with the authentication level
2114 * we get back from this?
2116 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2118 if (check_col (pinfo->cinfo, COL_INFO)) {
2119 if (num_results != 0 && result == 0) {
2120 /* XXX - only checks the last result */
2121 col_append_fstr (pinfo->cinfo, COL_INFO,
2122 " accept max_xmit: %u max_recv: %u",
2123 max_xmit, max_recv);
2125 /* XXX - only shows the last result and reason */
2126 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2127 val_to_str(result, p_cont_result_vals,
2128 "Unknown result (%u)"),
2129 val_to_str(reason, p_provider_reason_vals,
2136 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2137 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2140 guint8 num_protocols;
2143 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2144 hdr->drep, hf_dcerpc_cn_reject_reason,
2147 if (check_col (pinfo->cinfo, COL_INFO)) {
2148 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2149 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2152 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2153 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2154 hf_dcerpc_cn_num_protocols,
2157 for (i = 0; i < num_protocols; i++) {
2158 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2159 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2161 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2162 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2169 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2170 proto_tree *dcerpc_tree, proto_tree *tree,
2171 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2172 dcerpc_auth_info *auth_info, guint32 alloc_hint,
2175 int length, reported_length, stub_length;
2176 gboolean save_fragmented;
2177 fragment_data *fd_head=NULL;
2181 length = tvb_length_remaining(tvb, offset);
2182 reported_length = tvb_reported_length_remaining(tvb, offset);
2183 stub_length = hdr->frag_len - offset - auth_info->auth_size;
2184 if (length > stub_length)
2185 length = stub_length;
2186 if (reported_length > stub_length)
2187 reported_length = stub_length;
2189 save_fragmented = pinfo->fragmented;
2191 /* if this packet is not fragmented, just dissect it and exit */
2192 if(PFC_NOT_FRAGMENTED(hdr)){
2193 pinfo->fragmented = FALSE;
2194 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2195 tvb_new_subset (tvb, offset, length, reported_length),
2196 0, hdr->drep, di, auth_info);
2198 pinfo->fragmented = save_fragmented;
2202 /* The packet is fragmented. */
2203 pinfo->fragmented = TRUE;
2205 /* if we are not doing reassembly and this is the first fragment
2206 then just dissect it and exit
2208 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
2209 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2210 tvb_new_subset (tvb, offset, length,
2212 0, hdr->drep, di, auth_info);
2216 /* if we have already seen this packet, see if it was reassembled
2217 and if so dissect the full pdu.
2220 if(pinfo->fd->flags.visited){
2221 fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
2227 /* if we are not doing reassembly and it was neither a complete PDU
2228 nor the first fragment then there is nothing more we can do
2229 so we just have to exit
2231 if( !dcerpc_reassemble ){
2235 /* if we didnt get 'frame' we dont know where the PDU started and thus
2236 it is pointless to continue
2243 /* from now on we must attempt to reassemble the PDU
2247 /* we dont have the full fragment so we just have to abort and exit
2249 if( !tvb_bytes_exist(tvb, offset, stub_length) ){
2254 /* if we get here we know it is the first time we see the packet
2255 and we also know it is only a fragment and not a full PDU,
2256 thus we must reassemble it.
2260 /* if this is the first fragment we need to start reassembly
2262 if(hdr->flags&PFC_FIRST_FRAG){
2263 fragment_add(tvb, offset, pinfo, frame,
2264 dcerpc_co_reassemble_table,
2265 0, stub_length, TRUE);
2266 fragment_set_tot_len(pinfo, frame,
2267 dcerpc_co_reassemble_table, alloc_hint);
2272 /* if this is a middle fragment, just add it and exit */
2273 if(!(hdr->flags&PFC_LAST_FRAG)){
2274 tot_len = fragment_get_tot_len(pinfo, frame,
2275 dcerpc_co_reassemble_table);
2276 fragment_add(tvb, offset, pinfo, frame,
2277 dcerpc_co_reassemble_table,
2285 /* this was the last fragment add it to reassembly
2287 tot_len = fragment_get_tot_len(pinfo, frame,
2288 dcerpc_co_reassemble_table);
2289 fd_head = fragment_add(tvb, offset, pinfo,
2291 dcerpc_co_reassemble_table,
2300 /* if reassembly is complete, dissect the full PDU
2302 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
2303 if(pinfo->fd->num==fd_head->reassembled_in){
2306 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2307 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2308 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2309 show_fragment_tree(fd_head, &dcerpc_frag_items,
2310 dcerpc_tree, pinfo, next_tvb);
2312 pinfo->fragmented = FALSE;
2313 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
2314 0, hdr->drep, di, auth_info);
2316 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in, tvb, 0, 0, fd_head->reassembled_in);
2317 if (check_col(pinfo->cinfo, COL_INFO)) {
2318 col_append_fstr(pinfo->cinfo, COL_INFO,
2319 " [DCE/RPC fragment]");
2323 /* Reassembly not complete - some fragments
2325 if (check_col(pinfo->cinfo, COL_INFO)) {
2326 col_append_fstr(pinfo->cinfo, COL_INFO,
2327 " [DCE/RPC fragment]");
2331 pinfo->fragmented = save_fragmented;
2335 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2336 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2338 conversation_t *conv;
2342 dcerpc_auth_info auth_info;
2345 char uuid_str[DCERPC_UUID_STR_LEN];
2348 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2349 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2351 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2352 hf_dcerpc_cn_ctx_id, &ctx_id);
2354 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2355 hf_dcerpc_opnum, &opnum);
2357 if (check_col (pinfo->cinfo, COL_INFO)) {
2358 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
2362 if (hdr->flags & PFC_OBJECT_UUID) {
2363 /* XXX - use "dissect_ndr_uuid_t()"? */
2364 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
2366 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2367 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2368 obj_id.Data1, obj_id.Data2, obj_id.Data3,
2377 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2378 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2379 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
2380 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
2386 * XXX - what if this was set when the connection was set up,
2387 * and we just have a security context?
2389 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2391 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2392 pinfo->srcport, pinfo->destport, 0);
2394 length = tvb_reported_length_remaining (tvb, offset);
2396 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
2397 "Stub data (%d byte%s)", length,
2398 plurality(length, "", "s"));
2401 dcerpc_call_value *value;
2403 /* !!! we can NOT check flags.visited here since this will interact
2404 badly with when SMB handles (i.e. calls the subdissector)
2405 and desegmented pdu's .
2406 Instead we check if this pdu is already in the matched table or not
2408 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
2409 dcerpc_bind_key bind_key;
2410 dcerpc_bind_value *bind_value;
2413 bind_key.ctx_id=ctx_id;
2414 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
2416 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
2417 if(!(hdr->flags&PFC_FIRST_FRAG)){
2418 dcerpc_call_key call_key;
2419 dcerpc_call_value *call_value;
2422 call_key.call_id=hdr->call_id;
2423 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2424 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2425 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2428 dcerpc_call_key *call_key;
2429 dcerpc_call_value *call_value;
2431 /* We found the binding and it is the first fragment
2432 (or a complete PDU) of a dcerpc pdu so just add
2433 the call to both the call table and the
2436 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
2437 call_key->conv=conv;
2438 call_key->call_id=hdr->call_id;
2439 call_key->smb_fid=get_smb_fid(pinfo->private_data);
2441 /* if there is already a matching call in the table
2442 remove it so it is replaced with the new one */
2443 if(g_hash_table_lookup(dcerpc_calls, call_key)){
2444 g_hash_table_remove(dcerpc_calls, call_key);
2447 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2448 call_value->uuid = bind_value->uuid;
2449 call_value->ver = bind_value->ver;
2450 call_value->opnum = opnum;
2451 call_value->req_frame=pinfo->fd->num;
2452 call_value->req_time.secs=pinfo->fd->abs_secs;
2453 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
2454 call_value->rep_frame=0;
2455 call_value->max_ptr=0;
2456 call_value->private_data = NULL;
2457 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2459 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2464 value=g_hash_table_lookup (dcerpc_matched, (void *)pinfo->fd->num);
2469 /* handoff this call */
2471 di.call_id = hdr->call_id;
2472 di.smb_fid = get_smb_fid(pinfo->private_data);
2474 di.call_data = value;
2476 if(value->rep_frame!=0){
2477 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
2478 tvb, 0, 0, value->rep_frame);
2480 /*qqq request, broken*/
2481 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2482 hdr, &di, &auth_info, alloc_hint,
2485 length = tvb_reported_length_remaining (tvb, offset);
2487 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
2488 "Stub data (%d byte%s)", length,
2489 plurality(length, "", "s"));
2494 /* Decrypt the verifier, if present */
2495 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2499 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2500 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2502 dcerpc_call_value *value = NULL;
2503 conversation_t *conv;
2505 dcerpc_auth_info auth_info;
2509 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2510 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2512 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2513 hf_dcerpc_cn_ctx_id, &ctx_id);
2515 if (check_col (pinfo->cinfo, COL_INFO)) {
2516 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
2519 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2520 hf_dcerpc_cn_cancel_count, NULL);
2525 * XXX - what if this was set when the connection was set up,
2526 * and we just have a security context?
2528 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2530 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2531 pinfo->srcport, pinfo->destport, 0);
2533 /* no point in creating one here, really */
2534 length = tvb_reported_length_remaining (tvb, offset);
2536 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
2537 "Stub data (%d byte%s)", length,
2538 plurality(length, "", "s"));
2542 /* !!! we can NOT check flags.visited here since this will interact
2543 badly with when SMB handles (i.e. calls the subdissector)
2544 and desegmented pdu's .
2545 Instead we check if this pdu is already in the matched table or not
2547 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
2548 dcerpc_call_key call_key;
2549 dcerpc_call_value *call_value;
2552 call_key.call_id=hdr->call_id;
2553 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2555 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2556 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2557 if(call_value->rep_frame==0){
2558 call_value->rep_frame=pinfo->fd->num;
2564 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2569 /* handoff this call */
2571 di.call_id = hdr->call_id;
2572 di.smb_fid = get_smb_fid(pinfo->private_data);
2574 di.call_data = value;
2576 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2577 if(value->req_frame!=0){
2579 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2580 tvb, 0, 0, value->req_frame);
2581 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2582 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2584 ns.nsecs+=1000000000;
2587 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2591 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2592 hdr, &di, &auth_info, alloc_hint,
2595 length = tvb_reported_length_remaining (tvb, offset);
2597 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
2598 "Stub data (%d byte%s)", length,
2599 plurality(length, "", "s"));
2604 /* Decrypt the verifier, if present */
2605 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2609 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2610 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2612 dcerpc_call_value *value = NULL;
2613 conversation_t *conv;
2617 dcerpc_auth_info auth_info;
2619 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2620 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2622 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2623 hf_dcerpc_cn_ctx_id, &ctx_id);
2625 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2626 hf_dcerpc_cn_cancel_count, NULL);
2630 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2631 hf_dcerpc_cn_status, &status);
2633 if (check_col (pinfo->cinfo, COL_INFO)) {
2634 col_append_fstr (pinfo->cinfo, COL_INFO,
2635 " ctx_id: %u status: %s", ctx_id,
2636 val_to_str(status, reject_status_vals,
2637 "Unknown (0x%08x)"));
2644 * XXX - what if this was set when the connection was set up,
2645 * and we just have a security context?
2647 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2649 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2650 pinfo->srcport, pinfo->destport, 0);
2652 /* no point in creating one here, really */
2655 /* !!! we can NOT check flags.visited here since this will interact
2656 badly with when SMB handles (i.e. calls the subdissector)
2657 and desegmented pdu's .
2658 Instead we check if this pdu is already in the matched table or not
2660 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
2661 dcerpc_call_key call_key;
2662 dcerpc_call_value *call_value;
2665 call_key.call_id=hdr->call_id;
2666 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2668 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2669 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2670 if(call_value->rep_frame==0){
2671 call_value->rep_frame=pinfo->fd->num;
2677 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2680 int length, reported_length, stub_length;
2683 /* handoff this call */
2685 di.call_id = hdr->call_id;
2686 di.smb_fid = get_smb_fid(pinfo->private_data);
2688 di.call_data = value;
2690 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2691 if(value->req_frame!=0){
2693 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2694 tvb, 0, 0, value->req_frame);
2695 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2696 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2698 ns.nsecs+=1000000000;
2701 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2704 length = tvb_length_remaining(tvb, offset);
2705 reported_length = tvb_reported_length_remaining(tvb, offset);
2706 stub_length = hdr->frag_len - offset - auth_info.auth_size;
2707 if (length > stub_length)
2708 length = stub_length;
2709 if (reported_length > stub_length)
2710 reported_length = stub_length;
2712 /* If we don't have reassembly enabled, or this packet contains
2713 the entire PDU, or if we don't have all the data in this
2714 fragment, just call the handoff directly if this is the
2715 first fragment or the PDU isn't fragmented. */
2716 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
2717 !tvb_bytes_exist(tvb, offset, stub_length) ){
2718 if(hdr->flags&PFC_FIRST_FRAG){
2719 /* First fragment, possibly the only fragment */
2721 * XXX - should there be a third routine for each
2722 * function in an RPC subdissector, to handle
2723 * fault responses? The DCE RPC 1.1 spec says
2724 * three's "stub data" here, which I infer means
2725 * that it's protocol-specific and call-specific.
2727 * It should probably get passed the status code
2728 * as well, as that might be protocol-specific.
2731 if (stub_length > 0) {
2732 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2733 "Fault stub data (%d byte%s)",
2735 plurality(stub_length, "", "s"));
2739 /* PDU is fragmented and this isn't the first fragment */
2740 if (check_col(pinfo->cinfo, COL_INFO)) {
2741 col_append_fstr(pinfo->cinfo, COL_INFO,
2742 " [DCE/RPC fragment]");
2745 if (stub_length > 0) {
2746 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2747 "Fragment data (%d byte%s)",
2749 plurality(stub_length, "", "s"));
2754 /* Reassembly is enabled, the PDU is fragmented, and
2755 we have all the data in the fragment; the first two
2756 of those mean we should attempt reassembly, and the
2757 third means we can attempt reassembly. */
2760 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2761 "Fragment data (%d byte%s)",
2763 plurality(stub_length, "", "s"));
2766 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
2767 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2768 fragment_add(tvb, offset, pinfo, value->rep_frame,
2769 dcerpc_co_reassemble_table,
2773 fragment_set_tot_len(pinfo, value->rep_frame,
2774 dcerpc_co_reassemble_table, alloc_hint);
2776 if (check_col(pinfo->cinfo, COL_INFO)) {
2777 col_append_fstr(pinfo->cinfo, COL_INFO,
2778 " [DCE/RPC fragment]");
2780 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
2781 if( value->rep_frame ){
2782 fragment_data *fd_head;
2785 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2786 dcerpc_co_reassemble_table);
2787 fd_head = fragment_add(tvb, offset, pinfo,
2789 dcerpc_co_reassemble_table,
2795 /* We completed reassembly */
2798 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2799 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2800 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2801 show_fragment_tree(fd_head, &dcerpc_frag_items,
2802 dcerpc_tree, pinfo, next_tvb);
2805 * XXX - should there be a third routine for each
2806 * function in an RPC subdissector, to handle
2807 * fault responses? The DCE RPC 1.1 spec says
2808 * three's "stub data" here, which I infer means
2809 * that it's protocol-specific and call-specific.
2811 * It should probably get passed the status code
2812 * as well, as that might be protocol-specific.
2816 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2817 "Fault stub data (%d byte%s)",
2819 plurality(stub_length, "", "s"));
2823 /* Reassembly not complete - some fragments
2825 if (check_col(pinfo->cinfo, COL_INFO)) {
2826 col_append_fstr(pinfo->cinfo, COL_INFO,
2827 " [DCE/RPC fragment]");
2831 } else { /* MIDDLE fragment(s) */
2832 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2834 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2835 dcerpc_co_reassemble_table);
2836 fragment_add(tvb, offset, pinfo, value->rep_frame,
2837 dcerpc_co_reassemble_table,
2842 if (check_col(pinfo->cinfo, COL_INFO)) {
2843 col_append_fstr(pinfo->cinfo, COL_INFO,
2844 " [DCE/RPC fragment]");
2853 * DCERPC dissector for connection oriented calls
2856 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
2857 proto_tree *tree, gboolean can_desegment)
2859 static char nulls[4] = { 0 };
2862 proto_item *ti = NULL;
2863 proto_item *tf = NULL;
2864 proto_tree *dcerpc_tree = NULL;
2865 proto_tree *cn_flags_tree = NULL;
2866 proto_tree *drep_tree = NULL;
2867 e_dce_cn_common_hdr_t hdr;
2868 dcerpc_auth_info auth_info;
2871 * when done over nbt, dcerpc requests are padded with 4 bytes of null
2872 * data for some reason.
2874 * XXX - if that's always the case, the right way to do this would
2875 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
2876 * the 4 bytes of null padding, and make that the dissector
2877 * used for "netbios".
2879 if (tvb_bytes_exist (tvb, offset, 4) &&
2880 tvb_memeql (tvb, offset, nulls, 4) == 0) {
2890 * Check if this looks like a C/O DCERPC call
2892 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
2895 start_offset = offset;
2896 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
2897 if (hdr.rpc_ver != 5)
2899 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
2900 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
2902 hdr.ptype = tvb_get_guint8 (tvb, offset++);
2906 hdr.flags = tvb_get_guint8 (tvb, offset++);
2907 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
2908 offset += sizeof (hdr.drep);
2910 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2912 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2914 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
2917 if (can_desegment && pinfo->can_desegment
2918 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
2919 pinfo->desegment_offset = start_offset;
2920 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
2921 return 0; /* desegmentation required */
2924 if (check_col (pinfo->cinfo, COL_PROTOCOL))
2925 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
2926 if (check_col (pinfo->cinfo, COL_INFO))
2927 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
2928 pckt_vals[hdr.ptype].strptr, hdr.call_id);
2931 offset = start_offset;
2932 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
2934 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
2936 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
2937 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
2938 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
2939 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
2940 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
2941 if (cn_flags_tree) {
2942 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
2943 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
2944 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
2945 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
2946 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
2947 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
2948 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
2949 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
2953 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
2954 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
2956 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
2957 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
2958 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
2960 offset += sizeof (hdr.drep);
2962 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
2965 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
2968 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
2973 * Packet type specific stuff is next.
2975 switch (hdr.ptype) {
2978 dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr);
2983 dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
2988 * Nothing after the common header other than credentials.
2990 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, TRUE,
2995 dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
2999 dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3003 dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3007 dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
3013 * Nothing after the common header other than an authentication
3016 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
3022 * Nothing after the common header, not even an authentication
3028 /* might as well dissect the auth info */
3029 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
3033 return hdr.frag_len + padding;
3037 * DCERPC dissector for connection oriented calls over packet-oriented
3041 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3044 * Only one PDU per transport packet, and only one transport
3047 if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
3049 * It wasn't a DCERPC PDU.
3061 * DCERPC dissector for connection oriented calls over byte-stream
3065 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3069 gboolean ret = FALSE;
3072 * There may be multiple PDUs per transport packet; keep
3075 while (tvb_reported_length_remaining(tvb, offset) != 0) {
3076 pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
3077 dcerpc_cn_desegment);
3078 if (pdu_len == -1) {
3086 * Well, we've seen at least one DCERPC PDU.
3092 * Desegmentation required - bail now.
3098 * Step to the next PDU.
3106 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
3107 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
3109 proto_item *ti = NULL;
3110 proto_tree *auth_tree = NULL;
3111 guint8 protection_level;
3114 * Initially set "*auth_level_p" to -1 to indicate that we haven't
3115 * yet seen any authentication level information.
3117 if (auth_level_p != NULL)
3121 * The authentication information is at the *end* of the PDU; in
3122 * request and response PDUs, the request and response stub data
3125 * If the full packet is here, and there's data past the end of the
3126 * packet body, then dissect the auth info.
3128 offset += hdr->frag_len;
3129 if (tvb_length_remaining(tvb, offset) > 0) {
3130 switch (hdr->auth_proto) {
3132 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
3133 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
3134 auth_tree = proto_item_add_subtree (ti, ett_decrpc_krb5_auth_verf);
3135 protection_level = tvb_get_guint8 (tvb, offset);
3136 if (auth_level_p != NULL)
3137 *auth_level_p = protection_level;
3138 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
3140 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
3142 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
3143 offset += 6; /* 6 bytes of padding */
3145 offset += 2; /* 6 bytes of padding */
3146 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
3151 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
3158 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3159 proto_tree *dcerpc_tree,
3160 e_dce_dg_common_hdr_t *hdr)
3164 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3165 hdr->drep, hf_dcerpc_dg_cancel_vers,
3171 /* The only version we know about */
3172 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3173 hdr->drep, hf_dcerpc_dg_cancel_id,
3175 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3176 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3183 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
3184 proto_tree *dcerpc_tree,
3185 e_dce_dg_common_hdr_t *hdr)
3189 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3190 hdr->drep, hf_dcerpc_dg_cancel_vers,
3196 /* The only version we know about */
3197 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3198 hdr->drep, hf_dcerpc_dg_cancel_id,
3200 /* XXX - are NDR booleans 32 bits? */
3201 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3202 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3209 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3210 proto_tree *dcerpc_tree,
3211 e_dce_dg_common_hdr_t *hdr)
3218 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3219 hdr->drep, hf_dcerpc_dg_fack_vers,
3226 case 0: /* The only version documented in the DCE RPC 1.1 spec */
3227 case 1: /* This appears to be the same */
3228 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3229 hdr->drep, hf_dcerpc_dg_fack_window_size,
3231 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3232 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
3234 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3235 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
3237 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3238 hdr->drep, hf_dcerpc_dg_fack_serial_num,
3240 if (check_col (pinfo->cinfo, COL_INFO)) {
3241 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3244 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3245 hdr->drep, hf_dcerpc_dg_fack_selack_len,
3247 for (i = 0; i < selack_len; i++) {
3248 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3249 hdr->drep, hf_dcerpc_dg_fack_selack,
3258 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
3259 proto_tree *dcerpc_tree,
3260 e_dce_dg_common_hdr_t *hdr)
3264 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3265 hdr->drep, hf_dcerpc_dg_status,
3268 if (check_col (pinfo->cinfo, COL_INFO)) {
3269 col_append_fstr (pinfo->cinfo, COL_INFO,
3271 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3276 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
3277 proto_tree *dcerpc_tree, proto_tree *tree,
3278 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
3280 int length, reported_length, stub_length;
3281 gboolean save_fragmented;
3282 fragment_data *fd_head;
3284 if (check_col (pinfo->cinfo, COL_INFO)) {
3285 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u",
3286 di->call_data->opnum);
3289 length = tvb_length_remaining (tvb, offset);
3290 reported_length = tvb_reported_length_remaining (tvb, offset);
3291 stub_length = hdr->frag_len;
3292 if (length > stub_length)
3293 length = stub_length;
3294 if (reported_length > stub_length)
3295 reported_length = stub_length;
3297 save_fragmented = pinfo->fragmented;
3299 /* If we don't have reassembly enabled, or this packet contains
3300 the entire PDU, or if this is a short frame (or a frame
3301 not reassembled at a lower layer) that doesn't include all
3302 the data in the fragment, just call the handoff directly if
3303 this is the first fragment or the PDU isn't fragmented. */
3304 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
3305 !tvb_bytes_exist(tvb, offset, stub_length) ){
3306 if(hdr->frag_num == 0) {
3307 /* First fragment, possibly the only fragment */
3310 * XXX - authentication info?
3312 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
3313 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
3314 tvb_new_subset (tvb, offset, length,
3316 0, hdr->drep, di, NULL);
3318 /* PDU is fragmented and this isn't the first fragment */
3319 if (check_col(pinfo->cinfo, COL_INFO)) {
3320 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3324 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3325 "Fragment data (%d byte%s)",
3327 plurality(stub_length, "", "s"));
3332 /* Reassembly is enabled, the PDU is fragmented, and
3333 we have all the data in the fragment; the first two
3334 of those mean we should attempt reassembly, and the
3335 third means we can attempt reassembly. */
3338 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3339 "Fragment data (%d byte%s)", stub_length,
3340 plurality(stub_length, "", "s"));
3344 fd_head = fragment_add_seq(tvb, offset, pinfo,
3345 hdr->seqnum, dcerpc_cl_reassemble_table,
3346 hdr->frag_num, stub_length,
3347 !(hdr->flags1 & PFCL1_LASTFRAG));
3348 if (fd_head != NULL) {
3349 /* We completed reassembly */
3352 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3353 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3354 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3355 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
3356 dcerpc_tree, pinfo, next_tvb);
3359 * XXX - authentication info?
3361 pinfo->fragmented = FALSE;
3362 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3363 0, hdr->drep, di, NULL);
3365 /* Reassembly isn't completed yet */
3366 if (check_col(pinfo->cinfo, COL_INFO)) {
3367 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3371 pinfo->fragmented = save_fragmented;
3375 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
3376 proto_tree *dcerpc_tree, proto_tree *tree,
3377 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3380 dcerpc_call_value *value, v;
3382 if(!(pinfo->fd->flags.visited)){
3383 dcerpc_call_value *call_value;
3384 dcerpc_call_key *call_key;
3386 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
3387 call_key->conv=conv;
3388 call_key->call_id=hdr->seqnum;
3389 call_key->smb_fid=get_smb_fid(pinfo->private_data);
3391 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
3392 call_value->uuid = hdr->if_id;
3393 call_value->ver = hdr->if_ver;
3394 call_value->opnum = hdr->opnum;
3395 call_value->req_frame=pinfo->fd->num;
3396 call_value->req_time.secs=pinfo->fd->abs_secs;
3397 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3398 call_value->rep_frame=0;
3399 call_value->max_ptr=0;
3400 call_value->private_data = NULL;
3401 g_hash_table_insert (dcerpc_calls, call_key, call_value);
3403 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
3406 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
3408 v.uuid = hdr->if_id;
3409 v.ver = hdr->if_ver;
3410 v.opnum = hdr->opnum;
3411 v.req_frame = pinfo->fd->num;
3414 v.private_data=NULL;
3419 di.call_id = hdr->seqnum;
3422 di.call_data = value;
3424 if(value->rep_frame!=0){
3425 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3426 tvb, 0, 0, value->rep_frame);
3428 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
3432 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
3433 proto_tree *dcerpc_tree, proto_tree *tree,
3434 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3437 dcerpc_call_value *value, v;
3439 if(!(pinfo->fd->flags.visited)){
3440 dcerpc_call_value *call_value;
3441 dcerpc_call_key call_key;
3444 call_key.call_id=hdr->seqnum;
3445 call_key.smb_fid=get_smb_fid(pinfo->private_data);
3447 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
3448 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
3449 if(call_value->rep_frame==0){
3450 call_value->rep_frame=pinfo->fd->num;
3455 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
3457 v.uuid = hdr->if_id;
3458 v.ver = hdr->if_ver;
3459 v.opnum = hdr->opnum;
3461 v.rep_frame=pinfo->fd->num;
3462 v.private_data=NULL;
3470 di.call_data = value;
3472 if(value->req_frame!=0){
3474 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3475 tvb, 0, 0, value->req_frame);
3476 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3477 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3479 ns.nsecs+=1000000000;
3482 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3484 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
3488 * DCERPC dissector for connectionless calls
3491 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3493 proto_item *ti = NULL;
3494 proto_item *tf = NULL;
3495 proto_tree *dcerpc_tree = NULL;
3496 proto_tree *dg_flags1_tree = NULL;
3497 proto_tree *dg_flags2_tree = NULL;
3498 proto_tree *drep_tree = NULL;
3499 e_dce_dg_common_hdr_t hdr;
3501 conversation_t *conv;
3503 char uuid_str[DCERPC_UUID_STR_LEN];
3507 * Check if this looks like a CL DCERPC call. All dg packets
3508 * have an 80 byte header on them. Which starts with
3509 * version (4), pkt_type.
3511 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
3514 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3515 if (hdr.rpc_ver != 4)
3517 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3521 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3522 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3523 if (check_col (pinfo->cinfo, COL_INFO))
3524 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
3526 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
3527 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
3528 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3529 offset += sizeof (hdr.drep);
3530 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
3531 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
3533 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
3535 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
3537 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3539 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3541 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3543 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3545 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3547 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3549 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3551 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3553 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
3554 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
3557 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
3559 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
3565 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3569 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3573 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
3574 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
3575 if (dg_flags1_tree) {
3576 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
3577 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
3578 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
3579 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
3580 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
3581 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
3582 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
3583 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
3589 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
3590 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
3591 if (dg_flags2_tree) {
3592 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
3593 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
3594 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
3595 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
3596 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
3597 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
3598 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
3599 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
3605 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
3606 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3608 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3609 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3610 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3613 offset += sizeof (hdr.drep);
3616 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
3620 /* XXX - use "dissect_ndr_uuid_t()"? */
3621 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3622 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3623 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
3624 hdr.obj_id.Data4[0],
3625 hdr.obj_id.Data4[1],
3626 hdr.obj_id.Data4[2],
3627 hdr.obj_id.Data4[3],
3628 hdr.obj_id.Data4[4],
3629 hdr.obj_id.Data4[5],
3630 hdr.obj_id.Data4[6],
3631 hdr.obj_id.Data4[7]);
3632 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3633 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3634 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3635 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
3640 /* XXX - use "dissect_ndr_uuid_t()"? */
3641 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3642 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3643 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
3651 hdr.if_id.Data4[7]);
3652 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3653 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3654 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
3655 offset, 16, uuid_str, "Interface: %s", uuid_str);
3660 /* XXX - use "dissect_ndr_uuid_t()"? */
3661 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3662 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3663 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
3664 hdr.act_id.Data4[0],
3665 hdr.act_id.Data4[1],
3666 hdr.act_id.Data4[2],
3667 hdr.act_id.Data4[3],
3668 hdr.act_id.Data4[4],
3669 hdr.act_id.Data4[5],
3670 hdr.act_id.Data4[6],
3671 hdr.act_id.Data4[7]);
3672 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3673 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3674 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
3675 offset, 16, uuid_str, "Activity: %s", uuid_str);
3680 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
3684 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
3688 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
3689 if (check_col (pinfo->cinfo, COL_INFO)) {
3690 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq_num: %u", hdr.seqnum);
3695 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
3699 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
3703 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
3707 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
3711 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
3712 if (check_col (pinfo->cinfo, COL_INFO)) {
3713 if (hdr.flags1 & PFCL1_FRAG) {
3714 /* Fragmented - put the fragment number into the Info column */
3715 col_append_fstr (pinfo->cinfo, COL_INFO, " frag_num: %u",
3722 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
3726 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
3727 if (check_col (pinfo->cinfo, COL_INFO)) {
3728 if (hdr.flags1 & PFCL1_FRAG) {
3729 /* Fragmented - put the serial number into the Info column */
3730 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3731 (hdr.serial_hi << 8) | hdr.serial_lo);
3738 * XXX - for Kerberos, we get a protection level; if it's
3739 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
3742 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
3747 * keeping track of the conversation shouldn't really be necessary
3748 * for connectionless packets, because everything we need to know
3749 * to dissect is in the header for each packet. Unfortunately,
3750 * Microsoft's implementation is buggy and often puts the
3751 * completely wrong if_id in the header. go figure. So, keep
3752 * track of the seqnum and use that if possible. Note: that's not
3753 * completely correct. It should really be done based on both the
3754 * activity_id and seqnum. I haven't seen anywhere that it would
3755 * make a difference, but for future reference...
3757 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
3758 pinfo->srcport, pinfo->destport, 0);
3760 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
3761 pinfo->srcport, pinfo->destport, 0);
3765 * Packet type specific stuff is next.
3768 switch (hdr.ptype) {
3770 case PDU_CANCEL_ACK:
3771 /* Body is optional */
3772 /* XXX - we assume "frag_len" is the length of the body */
3773 if (hdr.frag_len != 0)
3774 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3779 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
3780 * but in at least one capture none of the Cl_cancel PDUs had a
3783 /* XXX - we assume "frag_len" is the length of the body */
3784 if (hdr.frag_len != 0)
3785 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
3789 /* Body is optional; if present, it's the same as PDU_FACK */
3790 /* XXX - we assume "frag_len" is the length of the body */
3791 if (hdr.frag_len != 0)
3792 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3796 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3801 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3805 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
3809 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
3812 /* these requests have no body */
3824 dcerpc_init_protocol (void)
3826 /* structures and data for BIND */
3828 g_hash_table_destroy (dcerpc_binds);
3830 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
3832 if (dcerpc_bind_key_chunk){
3833 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
3835 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
3836 sizeof (dcerpc_bind_key),
3837 200 * sizeof (dcerpc_bind_key),
3839 if (dcerpc_bind_value_chunk){
3840 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
3842 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
3843 sizeof (dcerpc_bind_value),
3844 200 * sizeof (dcerpc_bind_value),
3846 /* structures and data for CALL */
3848 g_hash_table_destroy (dcerpc_calls);
3850 dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
3851 if (dcerpc_call_key_chunk){
3852 g_mem_chunk_destroy (dcerpc_call_key_chunk);
3854 dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
3855 sizeof (dcerpc_call_key),
3856 200 * sizeof (dcerpc_call_key),
3858 if (dcerpc_call_value_chunk){
3859 g_mem_chunk_destroy (dcerpc_call_value_chunk);
3861 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
3862 sizeof (dcerpc_call_value),
3863 200 * sizeof (dcerpc_call_value),
3866 /* structure and data for MATCHED */
3867 if (dcerpc_matched){
3868 g_hash_table_destroy (dcerpc_matched);
3870 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
3875 proto_register_dcerpc (void)
3877 static hf_register_info hf[] = {
3878 { &hf_dcerpc_request_in,
3879 { "Request in", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
3880 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
3881 { &hf_dcerpc_response_in,
3882 { "Response in", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
3883 NULL, 0, "The response to this packet is in this packet", HFILL }},
3884 { &hf_dcerpc_referent_id,
3885 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
3886 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
3888 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3889 { &hf_dcerpc_ver_minor,
3890 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3891 { &hf_dcerpc_packet_type,
3892 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
3893 { &hf_dcerpc_cn_flags,
3894 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3895 { &hf_dcerpc_cn_flags_first_frag,
3896 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
3897 { &hf_dcerpc_cn_flags_last_frag,
3898 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
3899 { &hf_dcerpc_cn_flags_cancel_pending,
3900 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
3901 { &hf_dcerpc_cn_flags_reserved,
3902 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
3903 { &hf_dcerpc_cn_flags_mpx,
3904 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
3905 { &hf_dcerpc_cn_flags_dne,
3906 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
3907 { &hf_dcerpc_cn_flags_maybe,
3908 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
3909 { &hf_dcerpc_cn_flags_object,
3910 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
3912 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
3913 { &hf_dcerpc_drep_byteorder,
3914 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
3915 { &hf_dcerpc_drep_character,
3916 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
3917 { &hf_dcerpc_drep_fp,
3918 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
3919 { &hf_dcerpc_cn_frag_len,
3920 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3921 { &hf_dcerpc_cn_auth_len,
3922 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3923 { &hf_dcerpc_cn_call_id,
3924 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3925 { &hf_dcerpc_cn_max_xmit,
3926 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3927 { &hf_dcerpc_cn_max_recv,
3928 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3929 { &hf_dcerpc_cn_assoc_group,
3930 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
3931 { &hf_dcerpc_cn_num_ctx_items,
3932 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3933 { &hf_dcerpc_cn_ctx_id,
3934 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3935 { &hf_dcerpc_cn_num_trans_items,
3936 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3937 { &hf_dcerpc_cn_bind_if_id,
3938 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3939 { &hf_dcerpc_cn_bind_if_ver,
3940 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3941 { &hf_dcerpc_cn_bind_if_ver_minor,
3942 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3943 { &hf_dcerpc_cn_bind_trans_id,
3944 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3945 { &hf_dcerpc_cn_bind_trans_ver,
3946 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3947 { &hf_dcerpc_cn_alloc_hint,
3948 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3949 { &hf_dcerpc_cn_sec_addr_len,
3950 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3951 { &hf_dcerpc_cn_sec_addr,
3952 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
3953 { &hf_dcerpc_cn_num_results,
3954 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3955 { &hf_dcerpc_cn_ack_result,
3956 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
3957 { &hf_dcerpc_cn_ack_reason,
3958 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
3959 { &hf_dcerpc_cn_ack_trans_id,
3960 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3961 { &hf_dcerpc_cn_ack_trans_ver,
3962 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3963 { &hf_dcerpc_cn_reject_reason,
3964 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
3965 { &hf_dcerpc_cn_num_protocols,
3966 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3967 { &hf_dcerpc_cn_protocol_ver_major,
3968 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3969 { &hf_dcerpc_cn_protocol_ver_minor,
3970 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3971 { &hf_dcerpc_cn_cancel_count,
3972 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3973 { &hf_dcerpc_cn_status,
3974 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
3975 { &hf_dcerpc_auth_type,
3976 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
3977 { &hf_dcerpc_auth_level,
3978 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
3979 { &hf_dcerpc_auth_pad_len,
3980 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3981 { &hf_dcerpc_auth_rsrvd,
3982 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3983 { &hf_dcerpc_auth_ctx_id,
3984 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3985 { &hf_dcerpc_dg_flags1,
3986 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3987 { &hf_dcerpc_dg_flags1_rsrvd_01,
3988 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
3989 { &hf_dcerpc_dg_flags1_last_frag,
3990 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
3991 { &hf_dcerpc_dg_flags1_frag,
3992 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
3993 { &hf_dcerpc_dg_flags1_nofack,
3994 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
3995 { &hf_dcerpc_dg_flags1_maybe,
3996 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
3997 { &hf_dcerpc_dg_flags1_idempotent,
3998 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
3999 { &hf_dcerpc_dg_flags1_broadcast,
4000 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
4001 { &hf_dcerpc_dg_flags1_rsrvd_80,
4002 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
4003 { &hf_dcerpc_dg_flags2,
4004 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4005 { &hf_dcerpc_dg_flags2_rsrvd_01,
4006 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
4007 { &hf_dcerpc_dg_flags2_cancel_pending,
4008 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
4009 { &hf_dcerpc_dg_flags2_rsrvd_04,
4010 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
4011 { &hf_dcerpc_dg_flags2_rsrvd_08,
4012 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
4013 { &hf_dcerpc_dg_flags2_rsrvd_10,
4014 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
4015 { &hf_dcerpc_dg_flags2_rsrvd_20,
4016 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
4017 { &hf_dcerpc_dg_flags2_rsrvd_40,
4018 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
4019 { &hf_dcerpc_dg_flags2_rsrvd_80,
4020 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
4021 { &hf_dcerpc_dg_serial_lo,
4022 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4023 { &hf_dcerpc_dg_serial_hi,
4024 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4025 { &hf_dcerpc_dg_ahint,
4026 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4027 { &hf_dcerpc_dg_ihint,
4028 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4029 { &hf_dcerpc_dg_frag_len,
4030 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4031 { &hf_dcerpc_dg_frag_num,
4032 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4033 { &hf_dcerpc_dg_auth_proto,
4034 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4035 { &hf_dcerpc_dg_seqnum,
4036 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4037 { &hf_dcerpc_dg_server_boot,
4038 { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4039 { &hf_dcerpc_dg_if_ver,
4040 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4041 { &hf_dcerpc_krb5_av_prot_level,
4042 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
4043 { &hf_dcerpc_krb5_av_key_vers_num,
4044 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4045 { &hf_dcerpc_krb5_av_key_auth_verifier,
4046 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
4047 { &hf_dcerpc_obj_id,
4048 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4049 { &hf_dcerpc_dg_if_id,
4050 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4051 { &hf_dcerpc_dg_act_id,
4052 { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4054 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4056 { &hf_dcerpc_dg_cancel_vers,
4057 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4059 { &hf_dcerpc_dg_cancel_id,
4060 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4062 { &hf_dcerpc_dg_server_accepting_cancels,
4063 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
4065 { &hf_dcerpc_dg_fack_vers,
4066 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4068 { &hf_dcerpc_dg_fack_window_size,
4069 { "Window Size", "dcerpc.fack_window size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4071 { &hf_dcerpc_dg_fack_max_tsdu,
4072 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4074 { &hf_dcerpc_dg_fack_max_frag_size,
4075 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4077 { &hf_dcerpc_dg_fack_serial_num,
4078 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4080 { &hf_dcerpc_dg_fack_selack_len,
4081 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4083 { &hf_dcerpc_dg_fack_selack,
4084 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4086 { &hf_dcerpc_dg_status,
4087 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4089 { &hf_dcerpc_array_max_count,
4090 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
4092 { &hf_dcerpc_array_offset,
4093 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
4095 { &hf_dcerpc_array_actual_count,
4096 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
4098 { &hf_dcerpc_array_buffer,
4099 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
4102 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4104 { &hf_dcerpc_fragments,
4105 { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
4106 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
4108 { &hf_dcerpc_fragment,
4109 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
4110 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
4112 { &hf_dcerpc_fragment_overlap,
4113 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
4115 { &hf_dcerpc_fragment_overlap_conflict,
4116 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
4118 { &hf_dcerpc_fragment_multiple_tails,
4119 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
4121 { &hf_dcerpc_fragment_too_long_fragment,
4122 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
4124 { &hf_dcerpc_fragment_error,
4125 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
4128 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "Time between Request and Reply for DCE-RPC calls", HFILL }},
4129 { &hf_dcerpc_reassembled_in,
4130 { "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 }}
4133 static gint *ett[] = {
4135 &ett_dcerpc_cn_flags,
4137 &ett_dcerpc_dg_flags1,
4138 &ett_dcerpc_dg_flags2,
4139 &ett_dcerpc_pointer_data,
4141 &ett_dcerpc_fragments,
4142 &ett_dcerpc_fragment,
4143 &ett_decrpc_krb5_auth_verf,
4145 module_t *dcerpc_module;
4147 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
4148 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
4149 proto_register_subtree_array (ett, array_length (ett));
4150 register_init_routine (dcerpc_init_protocol);
4151 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
4152 prefs_register_bool_preference (dcerpc_module,
4154 "Desegment all DCE/RPC over TCP",
4155 "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
4156 &dcerpc_cn_desegment);
4157 prefs_register_bool_preference (dcerpc_module,
4158 "reassemble_dcerpc",
4159 "Reassemble DCE/RPC fragments",
4160 "Whether the DCE/RPC dissector should reassemble all fragmented PDUs",
4161 &dcerpc_reassemble);
4162 register_init_routine(dcerpc_reassemble_init);
4163 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
4164 dcerpc_tap=register_tap("dcerpc");
4168 proto_reg_handoff_dcerpc (void)
4170 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
4171 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
4172 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
4173 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
4174 ntlmssp_handle = find_dissector("ntlmssp");
4175 ntlmssp_verf_handle = find_dissector("ntlmssp_verf");
4176 ntlmssp_enc_payload_handle = find_dissector("ntlmssp_encrypted_payload");
4177 gssapi_handle = find_dissector("gssapi");
4178 gssapi_verf_handle = find_dissector("gssapi_verf");
4179 dcerpc_smb_init(proto_dcerpc);