2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas@webspan.net>
5 * $Id: packet-dcerpc.c,v 1.114 2003/03/31 07:26:18 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;
401 static gint ett_dcerpc = -1;
402 static gint ett_dcerpc_cn_flags = -1;
403 static gint ett_dcerpc_drep = -1;
404 static gint ett_dcerpc_dg_flags1 = -1;
405 static gint ett_dcerpc_dg_flags2 = -1;
406 static gint ett_dcerpc_pointer_data = -1;
407 static gint ett_dcerpc_string = -1;
408 static gint ett_dcerpc_fragments = -1;
409 static gint ett_dcerpc_fragment = -1;
410 static gint ett_decrpc_krb5_auth_verf = -1;
412 static dissector_handle_t ntlmssp_handle, ntlmssp_verf_handle,
413 ntlmssp_enc_payload_handle;
414 static dissector_handle_t gssapi_handle, gssapi_verf_handle;
416 static const fragment_items dcerpc_frag_items = {
417 &ett_dcerpc_fragments,
418 &ett_dcerpc_fragment,
420 &hf_dcerpc_fragments,
422 &hf_dcerpc_fragment_overlap,
423 &hf_dcerpc_fragment_overlap_conflict,
424 &hf_dcerpc_fragment_multiple_tails,
425 &hf_dcerpc_fragment_too_long_fragment,
426 &hf_dcerpc_fragment_error,
431 typedef struct _dcerpc_auth_info {
438 /* try to desegment big DCE/RPC packets over TCP? */
439 static gboolean dcerpc_cn_desegment = TRUE;
441 /* reassemble DCE/RPC fragments */
442 /* reassembly of dcerpc fragments will not work for the case where ONE frame
443 might contain multiple dcerpc fragments for different PDUs.
444 this case would be so unusual/weird so if you got captures like that:
447 static gboolean dcerpc_reassemble = FALSE;
448 static GHashTable *dcerpc_co_reassemble_table = NULL;
449 static GHashTable *dcerpc_cl_reassemble_table = NULL;
452 dcerpc_reassemble_init(void)
454 fragment_table_init(&dcerpc_co_reassemble_table);
455 fragment_table_init(&dcerpc_cl_reassemble_table);
462 /* the registered subdissectors */
463 GHashTable *dcerpc_uuids=NULL;
466 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
468 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
469 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
470 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
471 && (key1->ver == key2->ver));
475 dcerpc_uuid_hash (gconstpointer k)
477 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
478 /* This isn't perfect, but the Data1 part of these is almost always
480 return key->uuid.Data1;
484 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
485 dcerpc_sub_dissector *procs, int opnum_hf)
487 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
488 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
493 value->proto = proto;
495 value->name = proto_get_protocol_short_name (proto);
496 value->procs = procs;
497 value->opnum_hf = opnum_hf;
499 g_hash_table_insert (dcerpc_uuids, key, value);
502 /* Function to find the name of a registered protocol
503 * or NULL if the protocol/version is not known to ethereal.
506 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
509 dcerpc_uuid_value *sub_proto;
513 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
516 return sub_proto->name;
519 /* Function to find the subdissector table of a registered protocol
520 * or NULL if the protocol/version is not known to ethereal.
522 dcerpc_sub_dissector *
523 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
526 dcerpc_uuid_value *sub_proto;
530 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
533 return sub_proto->procs;
538 * To keep track of ctx_id mappings.
540 * Everytime we see a bind call we update this table.
541 * Note that we always specify a SMB FID. For non-SMB transports this
544 static GHashTable *dcerpc_binds=NULL;
546 typedef struct _dcerpc_bind_key {
547 conversation_t *conv;
552 typedef struct _dcerpc_bind_value {
557 static GMemChunk *dcerpc_bind_key_chunk=NULL;
558 static GMemChunk *dcerpc_bind_value_chunk=NULL;
561 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
563 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
564 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
565 return (key1->conv == key2->conv
566 && key1->ctx_id == key2->ctx_id
567 && key1->smb_fid == key2->smb_fid);
571 dcerpc_bind_hash (gconstpointer k)
573 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
574 return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
579 * To keep track of callid mappings. Should really use some generic
580 * conversation support instead.
582 static GHashTable *dcerpc_calls=NULL;
584 typedef struct _dcerpc_call_key {
585 conversation_t *conv;
590 static GMemChunk *dcerpc_call_key_chunk=NULL;
592 static GMemChunk *dcerpc_call_value_chunk=NULL;
595 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
597 const dcerpc_call_key *key1 = (const dcerpc_call_key *)k1;
598 const dcerpc_call_key *key2 = (const dcerpc_call_key *)k2;
599 return (key1->conv == key2->conv
600 && key1->call_id == key2->call_id
601 && key1->smb_fid == key2->smb_fid);
605 dcerpc_call_hash (gconstpointer k)
607 const dcerpc_call_key *key = (const dcerpc_call_key *)k;
608 return ((guint32)key->conv) + key->call_id + key->smb_fid;
612 /* to keep track of matched calls/responses
613 this one uses the same value struct as calls, but the key is the frame id
615 static GHashTable *dcerpc_matched=NULL;
617 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
619 return (guint32)k1 == (guint32)k2;
623 dcerpc_matched_hash (gconstpointer k)
631 * Utility functions. Modeled after packet-rpc.c
635 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
636 proto_tree *tree, char *drep,
637 int hfindex, guint8 *pdata)
641 data = tvb_get_guint8 (tvb, offset);
643 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
651 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
652 proto_tree *tree, char *drep,
653 int hfindex, guint16 *pdata)
657 data = ((drep[0] & 0x10)
658 ? tvb_get_letohs (tvb, offset)
659 : tvb_get_ntohs (tvb, offset));
662 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
670 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
671 proto_tree *tree, char *drep,
672 int hfindex, guint32 *pdata)
676 data = ((drep[0] & 0x10)
677 ? tvb_get_letohl (tvb, offset)
678 : tvb_get_ntohl (tvb, offset));
681 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
688 /* handles 32 bit unix time_t */
690 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
691 proto_tree *tree, char *drep,
692 int hfindex, guint32 *pdata)
697 data = ((drep[0] & 0x10)
698 ? tvb_get_letohl (tvb, offset)
699 : tvb_get_ntohl (tvb, offset));
704 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
713 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
714 proto_tree *tree, char *drep,
715 int hfindex, unsigned char *pdata)
718 tvb_memcpy(tvb, pdata, offset, 8);
719 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
721 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
722 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
723 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
724 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
729 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
737 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
738 proto_tree *tree, char *drep,
739 int hfindex, gfloat *pdata)
745 case(DCE_RPC_DREP_FP_IEEE):
746 data = ((drep[0] & 0x10)
747 ? tvb_get_letohieee_float(tvb, offset)
748 : tvb_get_ntohieee_float(tvb, offset));
750 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
753 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
754 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
755 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
757 /* ToBeDone: non IEEE floating formats */
758 /* Set data to a negative infinity value */
759 data = -1.0 * 1e100 * 1e100;
761 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
771 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
772 proto_tree *tree, char *drep,
773 int hfindex, gdouble *pdata)
779 case(DCE_RPC_DREP_FP_IEEE):
780 data = ((drep[0] & 0x10)
781 ? tvb_get_letohieee_double(tvb, offset)
782 : tvb_get_ntohieee_double(tvb, offset));
784 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
787 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
788 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
789 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
791 /* ToBeDone: non IEEE double formats */
792 /* Set data to a negative infinity value */
793 data = -1.0 * 1e100 * 1e100;
795 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
805 * a couple simpler things
808 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
810 if (drep[0] & 0x10) {
811 return tvb_get_letohs (tvb, offset);
813 return tvb_get_ntohs (tvb, offset);
818 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
820 if (drep[0] & 0x10) {
821 return tvb_get_letohl (tvb, offset);
823 return tvb_get_ntohl (tvb, offset);
828 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
831 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
832 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
833 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
835 for (i=0; i<sizeof (uuid->Data4); i++) {
836 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
843 /* function to dissect a unidimensional conformant array */
845 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
846 proto_tree *tree, char *drep,
847 dcerpc_dissect_fnct_t *fnct)
853 di=pinfo->private_data;
854 if(di->conformant_run){
855 /* conformant run, just dissect the max_count header */
857 di->conformant_run=0;
858 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
859 hf_dcerpc_array_max_count, &di->array_max_count);
860 di->array_max_count_offset=offset-4;
861 di->conformant_run=1;
862 di->conformant_eaten=offset-old_offset;
864 /* we don't remember where in the bytestream this field was */
865 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
867 /* real run, dissect the elements */
868 for(i=0;i<di->array_max_count;i++){
869 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
875 /* function to dissect a unidimensional conformant and varying array */
877 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
878 proto_tree *tree, char *drep,
879 dcerpc_dissect_fnct_t *fnct)
885 di=pinfo->private_data;
886 if(di->conformant_run){
887 /* conformant run, just dissect the max_count header */
889 di->conformant_run=0;
890 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
891 hf_dcerpc_array_max_count, &di->array_max_count);
892 di->array_max_count_offset=offset-4;
893 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
894 hf_dcerpc_array_offset, &di->array_offset);
895 di->array_offset_offset=offset-4;
896 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
897 hf_dcerpc_array_actual_count, &di->array_actual_count);
898 di->array_actual_count_offset=offset-4;
899 di->conformant_run=1;
900 di->conformant_eaten=offset-old_offset;
902 /* we dont dont remember where in the bytestream these fields were */
903 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
904 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
905 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
907 /* real run, dissect the elements */
908 for(i=0;i<di->array_actual_count;i++){
909 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
916 /* Dissect an string of bytes. This corresponds to
917 IDL of the form '[string] byte *foo'.
919 It can also be used for a conformant varying array of bytes if
920 the contents of the array should be shown as a big blob, rather
921 than showing each byte as an individual element.
923 XXX - which of those is really the IDL type for, for example,
924 the encrypted data in some MAPI packets? (Microsoft haven't
927 XXX - does this need to do all the conformant array stuff that
928 "dissect_ndr_ucvarray()" does? These are presumably for strings
929 that are conformant and varying - they're stored like conformant
930 varying arrays of bytes. */
932 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
933 proto_tree *tree, char *drep)
938 di=pinfo->private_data;
939 if(di->conformant_run){
940 /* just a run to handle conformant arrays, no scalars to dissect */
944 /* NDR array header */
946 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
947 hf_dcerpc_array_max_count, NULL);
949 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
950 hf_dcerpc_array_offset, NULL);
952 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
953 hf_dcerpc_array_actual_count, &len);
956 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
957 tvb, offset, len, drep[0] & 0x10);
964 /* For dissecting arrays that are to be interpreted as strings. */
966 /* Dissect an NDR conformant varying string of elements.
967 The length of each element is given by the 'size_is' parameter;
968 the elements are assumed to be characters or wide characters.
970 XXX - does this need to do all the conformant array stuff that
971 "dissect_ndr_ucvarray()" does? */
973 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
974 proto_tree *tree, char *drep, int size_is,
975 int hfindex, gboolean add_subtree, char **data)
978 proto_item *string_item;
979 proto_tree *string_tree;
980 guint32 len, buffer_len;
982 header_field_info *hfinfo;
984 di=pinfo->private_data;
985 if(di->conformant_run){
986 /* just a run to handle conformant arrays, no scalars to dissect */
991 string_item = proto_tree_add_text(tree, tvb, offset, 0, "%s",
992 proto_registrar_get_name(hfindex));
993 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
999 /* NDR array header */
1001 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1002 hf_dcerpc_array_max_count, NULL);
1004 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1005 hf_dcerpc_array_offset, NULL);
1007 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1008 hf_dcerpc_array_actual_count, &len);
1010 buffer_len = size_is * len;
1013 if (offset % size_is)
1014 offset += size_is - (offset % size_is);
1016 if (size_is == sizeof(guint16)) {
1017 /* XXX - use drep to determine the byte order? */
1018 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1020 * XXX - we don't support a string type with Unicode
1021 * characters, so if this is a string item, we make
1022 * its value be the "fake Unicode" string.
1024 if (tree && buffer_len) {
1025 hfinfo = proto_registrar_get_nth(hfindex);
1026 if (hfinfo->type == FT_STRING) {
1027 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1030 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1031 buffer_len, drep[0] & 0x10);
1035 s = g_malloc(buffer_len + 1);
1036 tvb_memcpy(tvb, s, offset, buffer_len);
1037 if (tree && buffer_len)
1038 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1039 buffer_len, drep[0] & 0x10);
1042 if (string_item != NULL)
1043 proto_item_append_text(string_item, ": %s", s);
1050 offset += buffer_len;
1055 /* Dissect an conformant varying string of chars.
1056 This corresponds to IDL of the form '[string] char *foo'.
1058 XXX - at least according to the DCE RPC 1.1 spec, a string has
1059 a null terminator, which isn't necessary as a terminator for
1060 the transfer language (as there's a length), but is presumably
1061 there for the benefit of null-terminated-string languages
1062 such as C. Is this ever used for purely counted strings?
1063 (Not that it matters if it is.) */
1065 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1066 proto_tree *tree, char *drep)
1069 di=pinfo->private_data;
1071 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1072 sizeof(guint8), di->hf_index,
1076 /* Dissect a conformant varying string of wchars (wide characters).
1077 This corresponds to IDL of the form '[string] wchar *foo'
1079 XXX - at least according to the DCE RPC 1.1 spec, a string has
1080 a null terminator, which isn't necessary as a terminator for
1081 the transfer language (as there's a length), but is presumably
1082 there for the benefit of null-terminated-string languages
1083 such as C. Is this ever used for purely counted strings?
1084 (Not that it matters if it is.) */
1086 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1087 proto_tree *tree, char *drep)
1090 di=pinfo->private_data;
1092 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1093 sizeof(guint16), di->hf_index,
1097 /* ndr pointer handling */
1098 /* list of pointers encountered so far */
1099 static GSList *ndr_pointer_list = NULL;
1101 /* position where in the list to insert newly encountered pointers */
1102 static int ndr_pointer_list_pos=0;
1104 /* boolean controlling whether pointers are top-level or embedded */
1105 static gboolean pointers_are_top_level = TRUE;
1107 /* as a kludge, we represent all embedded reference pointers as id==-1
1108 hoping that his will not collide with any non-ref pointers */
1109 typedef struct ndr_pointer_data {
1111 proto_item *item; /* proto_item for pointer */
1112 proto_tree *tree; /* subtree of above item */
1113 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1115 dcerpc_callback_fnct_t *callback;
1116 void *callback_args;
1117 } ndr_pointer_data_t;
1120 init_ndr_pointer_list(packet_info *pinfo)
1124 di=pinfo->private_data;
1125 di->conformant_run=0;
1127 while(ndr_pointer_list){
1128 ndr_pointer_data_t *npd;
1130 npd=g_slist_nth_data(ndr_pointer_list, 0);
1131 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1137 ndr_pointer_list=NULL;
1138 ndr_pointer_list_pos=0;
1139 pointers_are_top_level=TRUE;
1143 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *drep)
1145 int found_new_pointer;
1149 di=pinfo->private_data;
1153 found_new_pointer=0;
1154 len=g_slist_length(ndr_pointer_list);
1156 ndr_pointer_data_t *tnpd;
1157 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1159 dcerpc_dissect_fnct_t *fnct;
1161 found_new_pointer=1;
1164 ndr_pointer_list_pos=i+1;
1165 di->hf_index=tnpd->hf_index;
1166 /* first a run to handle any conformant
1168 di->conformant_run=1;
1169 di->conformant_eaten=0;
1170 old_offset = offset;
1171 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1173 g_assert((offset-old_offset)==di->conformant_eaten);
1174 /* This is to check for any bugs in the dissectors.
1176 * Basically, the NDR representation will store all
1177 * arrays in two blocks, one block with the dimension
1178 * discreption, like size, number of elements and such,
1179 * and another block that contains the actual data stored
1181 * If the array is embedded directly inside another,
1182 * encapsulating aggregate type, like a union or struct,
1183 * then these two blocks will be stored at different places
1184 * in the bytestream, with other data between the blocks.
1186 * For this reason, all pointers to types (both aggregate
1187 * and scalar, for simplicity no distinction is made)
1188 * will have its dissector called twice.
1189 * The dissector will first be called with conformant_run==1
1190 * in which mode the dissector MUST NOT consume any data from
1191 * the tvbuff (i.e. may not dissect anything) except the
1192 * initial control block for arrays.
1193 * The second time the dissector is called, with
1194 * conformant_run==0, all other data for the type will be
1197 * All dissect_ndr_<type> dissectors are already prepared
1198 * for this and knows when it should eat data from the tvb
1199 * and when not to, so implementors of dissectors will
1200 * normally not need to worry about this or even know about
1201 * it. However, if a dissector for an aggregate type calls
1202 * a subdissector from outside packet-dcerpc.c, such as
1203 * the dissector in packet-smb.c for NT Security Descriptors
1204 * as an example, then it is VERY important to encapsulate
1205 * this call to an external subdissector with the appropriate
1206 * test for conformant_run, i.e. it will need something like
1210 * di=pinfo->private_data;
1211 * if(di->conformant_run){
1215 * to make sure it makes the right thing.
1216 * This assert will signal when someone has forgotten to
1217 * make the dissector aware of this requirement.
1220 /* now we dissect the actual pointer */
1221 di->conformant_run=0;
1222 old_offset = offset;
1223 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1225 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1229 } while(found_new_pointer);
1236 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1237 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1238 dcerpc_callback_fnct_t *callback, void *callback_args)
1240 ndr_pointer_data_t *npd;
1242 /* check if this pointer is valid */
1245 dcerpc_call_value *value;
1247 di=pinfo->private_data;
1248 value=di->call_data;
1251 if(!(pinfo->fd->flags.visited)){
1252 if(id>value->max_ptr){
1257 /* if we havent seen the request bail out since we cant
1258 know whether this is the first non-NULL instance
1260 if(value->req_frame==0){
1261 /* XXX THROW EXCEPTION */
1264 /* We saw this one in the request frame, nothing to
1266 if(id<=value->max_ptr){
1272 npd=g_malloc(sizeof(ndr_pointer_data_t));
1277 npd->hf_index=hf_index;
1278 npd->callback=callback;
1279 npd->callback_args=callback_args;
1280 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1281 ndr_pointer_list_pos);
1282 ndr_pointer_list_pos++;
1287 find_pointer_index(guint32 id)
1289 ndr_pointer_data_t *npd;
1292 len=g_slist_length(ndr_pointer_list);
1294 npd=g_slist_nth_data(ndr_pointer_list, i);
1305 /* This function dissects an NDR pointer and stores the callback for later
1306 * deferred dissection.
1308 * fnct is the callback function for when we have reached this object in
1311 * type is what type of pointer.
1313 * this is text is what text we should put in any created tree node.
1315 * hf_index is what hf value we want to pass to the callback function when
1316 * it is called, the callback can later pich this one up from di->hf_index.
1318 * callback is executed after the pointer has been dereferenced.
1320 * callback_args is passed as an argument to the callback function
1322 * See packet-dcerpc-samr.c for examples
1325 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1326 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1327 int type, char *text, int hf_index,
1328 dcerpc_callback_fnct_t *callback, void *callback_args)
1332 di=pinfo->private_data;
1333 if(di->conformant_run){
1334 /* this call was only for dissecting the header for any
1335 embedded conformant array. we will not parse any
1336 pointers in this mode.
1341 /*TOP LEVEL REFERENCE POINTER*/
1342 if( pointers_are_top_level
1343 &&(type==NDR_POINTER_REF) ){
1347 /* we must find out a nice way to do the length here */
1348 item=proto_tree_add_text(tree, tvb, offset, 0,
1350 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1352 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1353 hf_index, callback, callback_args);
1357 /*TOP LEVEL FULL POINTER*/
1358 if( pointers_are_top_level
1359 && (type==NDR_POINTER_PTR) ){
1365 /* get the referent id */
1366 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1368 /* we got a NULL pointer */
1370 proto_tree_add_text(tree, tvb, offset-4, 4,
1371 "(NULL pointer) %s",text);
1375 /* see if we have seen this pointer before */
1376 idx=find_pointer_index(id);
1378 /* we have seen this pointer before */
1380 proto_tree_add_text(tree, tvb, offset-4, 4,
1381 "(duplicate PTR) %s",text);
1386 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1388 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1389 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1390 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1391 callback, callback_args);
1394 /*TOP LEVEL UNIQUE POINTER*/
1395 if( pointers_are_top_level
1396 && (type==NDR_POINTER_UNIQUE) ){
1401 /* get the referent id */
1402 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1404 /* we got a NULL pointer */
1406 proto_tree_add_text(tree, tvb, offset-4, 4,
1407 "(NULL pointer) %s",text);
1412 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1414 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1415 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1416 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1417 hf_index, callback, callback_args);
1421 /*EMBEDDED REFERENCE POINTER*/
1422 if( (!pointers_are_top_level)
1423 && (type==NDR_POINTER_REF) ){
1428 /* get the referent id */
1429 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1432 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1434 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1435 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1436 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1437 hf_index, callback, callback_args);
1441 /*EMBEDDED UNIQUE POINTER*/
1442 if( (!pointers_are_top_level)
1443 && (type==NDR_POINTER_UNIQUE) ){
1448 /* get the referent id */
1449 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1451 /* we got a NULL pointer */
1453 proto_tree_add_text(tree, tvb, offset-4, 4,
1454 "(NULL pointer) %s", text);
1459 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1461 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1462 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1463 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1464 hf_index, callback, callback_args);
1468 /*EMBEDDED FULL POINTER*/
1469 if( (!pointers_are_top_level)
1470 && (type==NDR_POINTER_PTR) ){
1476 /* get the referent id */
1477 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1479 /* we got a NULL pointer */
1481 proto_tree_add_text(tree, tvb, offset-4, 4,
1482 "(NULL pointer) %s",text);
1486 /* see if we have seen this pointer before */
1487 idx=find_pointer_index(id);
1489 /* we have seen this pointer before */
1491 proto_tree_add_text(tree, tvb, offset-4, 4,
1492 "(duplicate PTR) %s",text);
1497 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1499 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1500 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1501 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1502 callback, callback_args);
1508 /* After each top level pointer we have dissected we have to
1509 dissect all deferrals before we move on to the next top level
1511 if(pointers_are_top_level==TRUE){
1512 pointers_are_top_level=FALSE;
1513 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
1514 pointers_are_top_level=TRUE;
1521 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1522 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1523 int type, char *text, int hf_index)
1525 return dissect_ndr_pointer_cb(
1526 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
1531 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
1532 proto_tree *dcerpc_tree,
1533 tvbuff_t *tvb, gint offset,
1534 char *drep, dcerpc_info *info,
1535 dcerpc_auth_info *auth_info)
1537 dcerpc_uuid_key key;
1538 dcerpc_uuid_value *sub_proto;
1540 proto_tree *volatile sub_tree = NULL;
1541 dcerpc_sub_dissector *proc;
1543 dcerpc_dissect_fnct_t *volatile sub_dissect;
1544 const char *volatile saved_proto;
1545 void *volatile saved_private_data;
1547 key.uuid = info->call_data->uuid;
1548 key.ver = info->call_data->ver;
1551 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1552 || !proto_is_protocol_enabled(sub_proto->proto)) {
1554 * We don't have a dissector for this UUID, or the protocol
1555 * for that UUID is disabled.
1557 length = tvb_length_remaining (tvb, offset);
1559 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
1560 "Stub data (%d byte%s)", length,
1561 plurality(length, "", "s"));
1566 for (proc = sub_proto->procs; proc->name; proc++) {
1567 if (proc->num == info->call_data->opnum) {
1576 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1577 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1580 if (check_col (pinfo->cinfo, COL_INFO)) {
1581 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1582 name, info->request ? "request" : "reply");
1586 proto_item *sub_item;
1587 sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
1591 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1595 * Put the operation number into the tree along with
1596 * the operation's name.
1599 if (sub_proto->opnum_hf != -1)
1600 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
1601 tvb, 0, 0, info->call_data->opnum,
1602 "Operation: %s (%u)",
1603 name, info->call_data->opnum);
1605 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
1606 0, 0, info->call_data->opnum,
1607 "Operation: %s (%u)",
1608 name, info->call_data->opnum);
1612 * If the authentication level is DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
1613 * the stub data is encrypted, and we'd have to decrypt it in
1614 * order to dissect it.
1616 if (auth_info != NULL &&
1617 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1618 length = tvb_length_remaining (tvb, offset);
1620 proto_tree_add_text(sub_tree, tvb, offset, length,
1621 "Encrypted stub data (%d byte%s)",
1622 length, plurality(length, "", "s"));
1624 switch (auth_info->auth_type) {
1626 case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
1628 tvbuff_t *ntlmssp_tvb;
1629 ntlmssp_tvb = tvb_new_subset(tvb, offset, length, length);
1630 pinfo->decrypted_data=NULL;
1632 call_dissector(ntlmssp_enc_payload_handle, ntlmssp_tvb, pinfo,
1635 if(pinfo->decrypted_data){
1636 ntlmssp_decrypted_info_t *ndi=pinfo->decrypted_data;
1639 sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
1641 saved_proto = pinfo->current_proto;
1642 saved_private_data = pinfo->private_data;
1643 pinfo->current_proto = sub_proto->name;
1644 pinfo->private_data = (void *)info;
1646 init_ndr_pointer_list(pinfo);
1649 * Catch ReportedBoundsError, as that could
1650 * be due to the decryption being bad,
1651 * and doesn't mean that the tvbuff we were
1652 * handed has a malformed packet.
1655 offset = sub_dissect (ndi->decr_tvb, 0, pinfo, ndi->decr_tree, drep);
1656 } CATCH(BoundsError) {
1658 } CATCH(ReportedBoundsError) {
1659 show_reported_bounds_error(tvb, pinfo, tree);
1662 pinfo->current_proto = saved_proto;
1663 pinfo->private_data = saved_private_data;
1671 sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
1673 saved_proto = pinfo->current_proto;
1674 saved_private_data = pinfo->private_data;
1675 pinfo->current_proto = sub_proto->name;
1676 pinfo->private_data = (void *)info;
1678 init_ndr_pointer_list(pinfo);
1680 * Catch ReportedBoundsError, so that even if the stub
1681 * data is bad, we still show the verifier.
1684 offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
1685 } CATCH(BoundsError) {
1687 } CATCH(ReportedBoundsError) {
1688 show_reported_bounds_error(tvb, pinfo, tree);
1691 pinfo->current_proto = saved_proto;
1692 pinfo->private_data = saved_private_data;
1694 length = tvb_length_remaining (tvb, offset);
1696 proto_tree_add_text (sub_tree, tvb, offset, length,
1697 "Stub data (%d byte%s)", length,
1698 plurality(length, "", "s"));
1702 tap_queue_packet(dcerpc_tap, pinfo, info);
1707 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
1708 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
1709 dcerpc_auth_info *auth_info)
1713 if (auth_info->auth_size != 0) {
1714 auth_offset = hdr->frag_len - hdr->auth_len;
1715 switch (auth_info->auth_type) {
1717 case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
1719 tvbuff_t *ntlmssp_tvb;
1721 ntlmssp_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
1724 call_dissector(ntlmssp_verf_handle, ntlmssp_tvb, pinfo,
1730 case DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO: {
1731 /* SPNEGO (rfc2478) */
1732 tvbuff_t *gssapi_tvb;
1734 gssapi_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
1737 call_dissector(gssapi_verf_handle, gssapi_tvb, pinfo, dcerpc_tree);
1743 proto_tree_add_text (dcerpc_tree, tvb, auth_offset, hdr->auth_len,
1748 return hdr->auth_len;
1752 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1753 e_dce_cn_common_hdr_t *hdr, gboolean are_credentials,
1754 dcerpc_auth_info *auth_info)
1759 * Initially set auth_level to -1 to indicate that we haven't
1760 * yet seen any authentication level information.
1762 auth_info->auth_level = -1;
1765 * The authentication information is at the *end* of the PDU; in
1766 * request and response PDUs, the request and response stub data
1769 * If the full packet is here, and we've got an auth len, and it's
1770 * valid, then dissect the auth info.
1772 if (tvb_length (tvb) >= hdr->frag_len
1774 && (hdr->auth_len + 8 <= hdr->frag_len)) {
1776 offset = hdr->frag_len - (hdr->auth_len + 8);
1778 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1779 hf_dcerpc_auth_type,
1780 &auth_info->auth_type);
1781 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1782 hf_dcerpc_auth_level,
1783 &auth_info->auth_level);
1785 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1786 hf_dcerpc_auth_pad_len,
1787 &auth_info->auth_pad_len);
1788 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1789 hf_dcerpc_auth_rsrvd, NULL);
1790 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1791 hf_dcerpc_auth_ctx_id, NULL);
1794 * Dissect the authentication data.
1796 if (are_credentials) {
1798 * The authentication data are credentials.
1800 switch (auth_info->auth_type) {
1802 case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
1804 tvbuff_t *ntlmssp_tvb;
1806 ntlmssp_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
1809 call_dissector(ntlmssp_handle, ntlmssp_tvb, pinfo,
1815 case DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO: {
1816 /* SPNEGO (rfc2478) */
1817 tvbuff_t *gssapi_tvb;
1819 gssapi_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
1822 call_dissector(gssapi_handle, gssapi_tvb, pinfo, dcerpc_tree);
1828 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
1829 "Auth Credentials");
1833 /* figure out where the auth padding starts */
1834 offset = hdr->frag_len - (hdr->auth_len + 8 + auth_info->auth_pad_len);
1835 if (offset > 0 && auth_info->auth_pad_len) {
1836 proto_tree_add_text (dcerpc_tree, tvb, offset,
1837 auth_info->auth_pad_len, "Auth padding");
1838 auth_info->auth_size = hdr->auth_len + 8 + auth_info->auth_pad_len;
1840 auth_info->auth_size = hdr->auth_len + 8;
1843 auth_info->auth_size = 0;
1848 /* We need to hash in the SMB fid number to generate a unique hash table
1849 key as DCERPC over SMB allows several pipes over the same TCP/IP
1852 static guint16 get_smb_fid (void *private_data)
1854 dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
1857 return 0; /* Nothing to see here */
1859 /* DCERPC over smb */
1861 if (priv->transport_type == DCERPC_TRANSPORT_SMB)
1862 return priv->data.smb.fid;
1864 /* Some other transport... */
1870 * Connection oriented packet types
1874 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
1875 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
1877 conversation_t *conv = NULL;
1878 guint8 num_ctx_items;
1880 gboolean saw_ctx_item = FALSE;
1882 guint16 num_trans_items;
1887 guint16 if_ver, if_ver_minor;
1888 char uuid_str[DCERPC_UUID_STR_LEN];
1890 dcerpc_auth_info auth_info;
1892 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1893 hf_dcerpc_cn_max_xmit, NULL);
1895 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1896 hf_dcerpc_cn_max_recv, NULL);
1898 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1899 hf_dcerpc_cn_assoc_group, NULL);
1901 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1902 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
1907 for (i = 0; i < num_ctx_items; i++) {
1908 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1909 hf_dcerpc_cn_ctx_id, &ctx_id);
1911 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1912 hf_dcerpc_cn_num_trans_items, &num_trans_items);
1914 /* XXX - use "dissect_ndr_uuid_t()"? */
1915 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
1917 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
1918 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1919 if_id.Data1, if_id.Data2, if_id.Data3,
1920 if_id.Data4[0], if_id.Data4[1],
1921 if_id.Data4[2], if_id.Data4[3],
1922 if_id.Data4[4], if_id.Data4[5],
1923 if_id.Data4[6], if_id.Data4[7]);
1924 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
1925 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
1926 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
1927 offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
1931 if (hdr->drep[0] & 0x10) {
1932 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1933 hf_dcerpc_cn_bind_if_ver, &if_ver);
1934 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1935 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1937 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1938 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, &if_ver);
1943 if (!saw_ctx_item) {
1944 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1945 pinfo->srcport, pinfo->destport, 0);
1947 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
1948 pinfo->srcport, pinfo->destport, 0);
1951 /* if this is the first time we see this packet, we need to
1952 update the dcerpc_binds table so that any later calls can
1953 match to the interface.
1954 XXX We assume that BINDs will NEVER be fragmented.
1956 if(!(pinfo->fd->flags.visited)){
1957 dcerpc_bind_key *key;
1958 dcerpc_bind_value *value;
1960 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
1962 key->ctx_id = ctx_id;
1963 key->smb_fid = get_smb_fid(pinfo->private_data);
1965 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
1966 value->uuid = if_id;
1967 value->ver = if_ver;
1969 /* add this entry to the bind table, first removing any
1970 previous ones that are identical
1972 if(g_hash_table_lookup(dcerpc_binds, key)){
1973 g_hash_table_remove(dcerpc_binds, key);
1975 g_hash_table_insert (dcerpc_binds, key, value);
1978 if (check_col (pinfo->cinfo, COL_INFO)) {
1979 dcerpc_uuid_key key;
1980 dcerpc_uuid_value *value;
1985 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
1986 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
1988 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
1989 if_id.Data1, if_id.Data2, if_id.Data3,
1990 if_id.Data4[0], if_id.Data4[1],
1991 if_id.Data4[2], if_id.Data4[3],
1992 if_id.Data4[4], if_id.Data4[5],
1993 if_id.Data4[6], if_id.Data4[7],
1994 if_ver, if_ver_minor);
1996 saw_ctx_item = TRUE;
1999 for (j = 0; j < num_trans_items; j++) {
2000 /* XXX - use "dissect_ndr_uuid_t()"? */
2001 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2003 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2004 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2005 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2006 trans_id.Data4[0], trans_id.Data4[1],
2007 trans_id.Data4[2], trans_id.Data4[3],
2008 trans_id.Data4[4], trans_id.Data4[5],
2009 trans_id.Data4[6], trans_id.Data4[7]);
2010 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2011 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2012 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2013 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2017 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2018 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2023 * XXX - we should save the authentication type *if* we have
2024 * an authentication header, and associate it with an authentication
2025 * context, so subsequent PDUs can use that context.
2027 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2031 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2032 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2034 guint16 max_xmit, max_recv;
2035 guint16 sec_addr_len;
2042 char uuid_str[DCERPC_UUID_STR_LEN];
2044 dcerpc_auth_info auth_info;
2046 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2047 hf_dcerpc_cn_max_xmit, &max_xmit);
2049 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2050 hf_dcerpc_cn_max_recv, &max_recv);
2052 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2053 hf_dcerpc_cn_assoc_group, NULL);
2055 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2056 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2057 if (sec_addr_len != 0) {
2058 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2059 sec_addr_len, FALSE);
2060 offset += sec_addr_len;
2064 offset += 4 - offset % 4;
2067 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2068 hf_dcerpc_cn_num_results, &num_results);
2073 for (i = 0; i < num_results; i++) {
2074 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2075 hdr->drep, hf_dcerpc_cn_ack_result,
2078 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2079 hdr->drep, hf_dcerpc_cn_ack_reason,
2083 * The reason for rejection isn't meaningful, and often isn't
2084 * set, when the syntax was accepted.
2089 /* XXX - use "dissect_ndr_uuid_t()"? */
2090 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2092 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2093 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2094 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2095 trans_id.Data4[0], trans_id.Data4[1],
2096 trans_id.Data4[2], trans_id.Data4[3],
2097 trans_id.Data4[4], trans_id.Data4[5],
2098 trans_id.Data4[6], trans_id.Data4[7]);
2099 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2100 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2101 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2102 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2106 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2107 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2111 * XXX - do we need to do anything with the authentication level
2112 * we get back from this?
2114 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2116 if (check_col (pinfo->cinfo, COL_INFO)) {
2117 if (num_results != 0 && result == 0) {
2118 /* XXX - only checks the last result */
2119 col_append_fstr (pinfo->cinfo, COL_INFO,
2120 " accept max_xmit: %u max_recv: %u",
2121 max_xmit, max_recv);
2123 /* XXX - only shows the last result and reason */
2124 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2125 val_to_str(result, p_cont_result_vals,
2126 "Unknown result (%u)"),
2127 val_to_str(reason, p_provider_reason_vals,
2134 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2135 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2138 guint8 num_protocols;
2141 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2142 hdr->drep, hf_dcerpc_cn_reject_reason,
2145 if (check_col (pinfo->cinfo, COL_INFO)) {
2146 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2147 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2150 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2151 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2152 hf_dcerpc_cn_num_protocols,
2155 for (i = 0; i < num_protocols; i++) {
2156 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2157 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2159 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2160 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2167 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2168 proto_tree *dcerpc_tree, proto_tree *tree,
2169 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2170 dcerpc_auth_info *auth_info, guint32 alloc_hint,
2173 int length, reported_length, stub_length;
2174 gboolean save_fragmented;
2176 length = tvb_length_remaining(tvb, offset);
2177 reported_length = tvb_reported_length_remaining(tvb, offset);
2178 stub_length = hdr->frag_len - offset - auth_info->auth_size;
2179 if (length > stub_length)
2180 length = stub_length;
2181 if (reported_length > stub_length)
2182 reported_length = stub_length;
2184 save_fragmented = pinfo->fragmented;
2186 /* If we don't have reassembly enabled, or this packet contains
2187 the entire PDU, or if this is a short frame (or a frame
2188 not reassembled at a lower layer) that doesn't include all
2189 the data in the fragment, just call the handoff directly if
2190 this is the first fragment or the PDU isn't fragmented. */
2191 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
2192 !tvb_bytes_exist(tvb, offset, stub_length) ){
2193 if(hdr->flags&PFC_FIRST_FRAG){
2194 /* First fragment, possibly the only fragment */
2195 pinfo->fragmented = !PFC_NOT_FRAGMENTED(hdr);
2196 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2197 tvb_new_subset (tvb, offset, length,
2199 0, hdr->drep, di, auth_info);
2201 /* PDU is fragmented and this isn't the first fragment */
2202 if (check_col(pinfo->cinfo, COL_INFO)) {
2203 col_append_fstr(pinfo->cinfo, COL_INFO,
2204 " [DCE/RPC fragment]");
2207 if (stub_length > 0) {
2208 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2209 "Fragment data (%d byte%s)", stub_length,
2210 plurality(stub_length, "", "s"));
2215 /* Reassembly is enabled, the PDU is fragmented, and
2216 we have all the data in the fragment; the first two
2217 of those mean we should attempt reassembly, and the
2218 third means we can attempt reassembly. */
2220 if (stub_length > 0) {
2221 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2222 "Fragment data (%d byte%s)", stub_length,
2223 plurality(stub_length, "", "s"));
2226 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
2227 if( (!pinfo->fd->flags.visited) && frame){
2228 fragment_add(tvb, offset, pinfo, frame,
2229 dcerpc_co_reassemble_table,
2233 fragment_set_tot_len(pinfo, frame,
2234 dcerpc_co_reassemble_table, alloc_hint);
2236 if (check_col(pinfo->cinfo, COL_INFO)) {
2237 col_append_fstr(pinfo->cinfo, COL_INFO,
2238 " [DCE/RPC fragment]");
2240 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
2242 fragment_data *fd_head;
2245 tot_len = fragment_get_tot_len(pinfo, frame,
2246 dcerpc_co_reassemble_table);
2247 fd_head = fragment_add(tvb, offset, pinfo,
2249 dcerpc_co_reassemble_table,
2255 /* We completed reassembly */
2258 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2259 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2260 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2261 show_fragment_tree(fd_head, &dcerpc_frag_items,
2262 dcerpc_tree, pinfo, next_tvb);
2264 pinfo->fragmented = FALSE;
2265 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
2266 0, hdr->drep, di, auth_info);
2268 /* Reassembly not complete - some fragments
2270 if (check_col(pinfo->cinfo, COL_INFO)) {
2271 col_append_fstr(pinfo->cinfo, COL_INFO,
2272 " [DCE/RPC fragment]");
2276 } else { /* MIDDLE fragment(s) */
2277 if( (!pinfo->fd->flags.visited) && frame ){
2279 tot_len = fragment_get_tot_len(pinfo, frame,
2280 dcerpc_co_reassemble_table);
2281 fragment_add(tvb, offset, pinfo, frame,
2282 dcerpc_co_reassemble_table,
2287 if (check_col(pinfo->cinfo, COL_INFO)) {
2288 col_append_fstr(pinfo->cinfo, COL_INFO,
2289 " [DCE/RPC fragment]");
2293 pinfo->fragmented = save_fragmented;
2297 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2298 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2300 conversation_t *conv;
2304 dcerpc_auth_info auth_info;
2307 char uuid_str[DCERPC_UUID_STR_LEN];
2310 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2311 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2313 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2314 hf_dcerpc_cn_ctx_id, &ctx_id);
2316 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2317 hf_dcerpc_opnum, &opnum);
2319 if (check_col (pinfo->cinfo, COL_INFO)) {
2320 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
2324 if (hdr->flags & PFC_OBJECT_UUID) {
2325 /* XXX - use "dissect_ndr_uuid_t()"? */
2326 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
2328 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2329 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2330 obj_id.Data1, obj_id.Data2, obj_id.Data3,
2339 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2340 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2341 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
2342 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
2348 * XXX - what if this was set when the connection was set up,
2349 * and we just have a security context?
2351 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2353 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2354 pinfo->srcport, pinfo->destport, 0);
2356 length = tvb_reported_length_remaining (tvb, offset);
2358 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
2359 "Stub data (%d byte%s)", length,
2360 plurality(length, "", "s"));
2363 dcerpc_call_value *value;
2365 /* !!! we can NOT check flags.visited here since this will interact
2366 badly with when SMB handles (i.e. calls the subdissector)
2367 and desegmented pdu's .
2368 Instead we check if this pdu is already in the matched table or not
2370 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
2371 dcerpc_bind_key bind_key;
2372 dcerpc_bind_value *bind_value;
2375 bind_key.ctx_id=ctx_id;
2376 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
2378 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key))){
2379 dcerpc_call_key *call_key;
2380 dcerpc_call_value *call_value;
2382 /* We found the binding so just add the call
2383 to both the call table and the matched table
2385 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
2386 call_key->conv=conv;
2387 call_key->call_id=hdr->call_id;
2388 call_key->smb_fid=get_smb_fid(pinfo->private_data);
2390 /* if there is already a matching call in the table
2391 remove it so it is replaced with the new one */
2392 if(g_hash_table_lookup(dcerpc_calls, call_key)){
2393 g_hash_table_remove(dcerpc_calls, call_key);
2396 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2397 call_value->uuid = bind_value->uuid;
2398 call_value->ver = bind_value->ver;
2399 call_value->opnum = opnum;
2400 call_value->req_frame=pinfo->fd->num;
2401 call_value->req_time.secs=pinfo->fd->abs_secs;
2402 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
2403 call_value->rep_frame=0;
2404 call_value->max_ptr=0;
2405 call_value->private_data = NULL;
2406 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2408 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2412 value=g_hash_table_lookup (dcerpc_matched, (void *)pinfo->fd->num);
2417 /* handoff this call */
2419 di.call_id = hdr->call_id;
2420 di.smb_fid = get_smb_fid(pinfo->private_data);
2422 di.call_data = value;
2424 if(value->rep_frame!=0){
2425 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
2426 tvb, 0, 0, value->rep_frame);
2429 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2430 hdr, &di, &auth_info, alloc_hint,
2433 length = tvb_reported_length_remaining (tvb, offset);
2435 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
2436 "Stub data (%d byte%s)", length,
2437 plurality(length, "", "s"));
2442 /* Decrypt the verifier, if present */
2443 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2447 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2448 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2450 dcerpc_call_value *value = NULL;
2451 conversation_t *conv;
2453 dcerpc_auth_info auth_info;
2457 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2458 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2460 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2461 hf_dcerpc_cn_ctx_id, &ctx_id);
2463 if (check_col (pinfo->cinfo, COL_INFO)) {
2464 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
2467 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2468 hf_dcerpc_cn_cancel_count, NULL);
2473 * XXX - what if this was set when the connection was set up,
2474 * and we just have a security context?
2476 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2478 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2479 pinfo->srcport, pinfo->destport, 0);
2481 /* no point in creating one here, really */
2482 length = tvb_reported_length_remaining (tvb, offset);
2484 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
2485 "Stub data (%d byte%s)", length,
2486 plurality(length, "", "s"));
2490 /* !!! we can NOT check flags.visited here since this will interact
2491 badly with when SMB handles (i.e. calls the subdissector)
2492 and desegmented pdu's .
2493 Instead we check if this pdu is already in the matched table or not
2495 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
2496 dcerpc_call_key call_key;
2497 dcerpc_call_value *call_value;
2500 call_key.call_id=hdr->call_id;
2501 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2503 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2504 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2505 if(call_value->rep_frame==0){
2506 call_value->rep_frame=pinfo->fd->num;
2512 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2517 /* handoff this call */
2519 di.call_id = hdr->call_id;
2520 di.smb_fid = get_smb_fid(pinfo->private_data);
2522 di.call_data = value;
2524 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2525 if(value->req_frame!=0){
2527 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2528 tvb, 0, 0, value->req_frame);
2529 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2530 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2532 ns.nsecs+=1000000000;
2535 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2538 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2539 hdr, &di, &auth_info, alloc_hint,
2542 length = tvb_reported_length_remaining (tvb, offset);
2544 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
2545 "Stub data (%d byte%s)", length,
2546 plurality(length, "", "s"));
2551 /* Decrypt the verifier, if present */
2552 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2556 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2557 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2559 dcerpc_call_value *value = NULL;
2560 conversation_t *conv;
2564 dcerpc_auth_info auth_info;
2566 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2567 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2569 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2570 hf_dcerpc_cn_ctx_id, &ctx_id);
2572 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2573 hf_dcerpc_cn_cancel_count, NULL);
2577 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2578 hf_dcerpc_cn_status, &status);
2580 if (check_col (pinfo->cinfo, COL_INFO)) {
2581 col_append_fstr (pinfo->cinfo, COL_INFO,
2582 " ctx_id: %u status: %s", ctx_id,
2583 val_to_str(status, reject_status_vals,
2584 "Unknown (0x%08x)"));
2591 * XXX - what if this was set when the connection was set up,
2592 * and we just have a security context?
2594 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2596 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2597 pinfo->srcport, pinfo->destport, 0);
2599 /* no point in creating one here, really */
2602 /* !!! we can NOT check flags.visited here since this will interact
2603 badly with when SMB handles (i.e. calls the subdissector)
2604 and desegmented pdu's .
2605 Instead we check if this pdu is already in the matched table or not
2607 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
2608 dcerpc_call_key call_key;
2609 dcerpc_call_value *call_value;
2612 call_key.call_id=hdr->call_id;
2613 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2615 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2616 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2617 if(call_value->rep_frame==0){
2618 call_value->rep_frame=pinfo->fd->num;
2624 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2627 int length, reported_length, stub_length;
2630 /* handoff this call */
2632 di.call_id = hdr->call_id;
2633 di.smb_fid = get_smb_fid(pinfo->private_data);
2635 di.call_data = value;
2637 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2638 if(value->req_frame!=0){
2640 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2641 tvb, 0, 0, value->req_frame);
2642 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2643 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2645 ns.nsecs+=1000000000;
2648 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2651 length = tvb_length_remaining(tvb, offset);
2652 reported_length = tvb_reported_length_remaining(tvb, offset);
2653 stub_length = hdr->frag_len - offset - auth_info.auth_size;
2654 if (length > stub_length)
2655 length = stub_length;
2656 if (reported_length > stub_length)
2657 reported_length = stub_length;
2659 /* If we don't have reassembly enabled, or this packet contains
2660 the entire PDU, or if we don't have all the data in this
2661 fragment, just call the handoff directly if this is the
2662 first fragment or the PDU isn't fragmented. */
2663 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
2664 !tvb_bytes_exist(tvb, offset, stub_length) ){
2665 if(hdr->flags&PFC_FIRST_FRAG){
2666 /* First fragment, possibly the only fragment */
2668 * XXX - should there be a third routine for each
2669 * function in an RPC subdissector, to handle
2670 * fault responses? The DCE RPC 1.1 spec says
2671 * three's "stub data" here, which I infer means
2672 * that it's protocol-specific and call-specific.
2674 * It should probably get passed the status code
2675 * as well, as that might be protocol-specific.
2678 if (stub_length > 0) {
2679 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2680 "Fault stub data (%d byte%s)",
2682 plurality(stub_length, "", "s"));
2686 /* PDU is fragmented and this isn't the first fragment */
2687 if (check_col(pinfo->cinfo, COL_INFO)) {
2688 col_append_fstr(pinfo->cinfo, COL_INFO,
2689 " [DCE/RPC fragment]");
2692 if (stub_length > 0) {
2693 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2694 "Fragment data (%d byte%s)",
2696 plurality(stub_length, "", "s"));
2701 /* Reassembly is enabled, the PDU is fragmented, and
2702 we have all the data in the fragment; the first two
2703 of those mean we should attempt reassembly, and the
2704 third means we can attempt reassembly. */
2707 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2708 "Fragment data (%d byte%s)",
2710 plurality(stub_length, "", "s"));
2713 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
2714 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2715 fragment_add(tvb, offset, pinfo, value->rep_frame,
2716 dcerpc_co_reassemble_table,
2720 fragment_set_tot_len(pinfo, value->rep_frame,
2721 dcerpc_co_reassemble_table, alloc_hint);
2723 if (check_col(pinfo->cinfo, COL_INFO)) {
2724 col_append_fstr(pinfo->cinfo, COL_INFO,
2725 " [DCE/RPC fragment]");
2727 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
2728 if( value->rep_frame ){
2729 fragment_data *fd_head;
2732 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2733 dcerpc_co_reassemble_table);
2734 fd_head = fragment_add(tvb, offset, pinfo,
2736 dcerpc_co_reassemble_table,
2742 /* We completed reassembly */
2745 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2746 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2747 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2748 show_fragment_tree(fd_head, &dcerpc_frag_items,
2749 dcerpc_tree, pinfo, next_tvb);
2752 * XXX - should there be a third routine for each
2753 * function in an RPC subdissector, to handle
2754 * fault responses? The DCE RPC 1.1 spec says
2755 * three's "stub data" here, which I infer means
2756 * that it's protocol-specific and call-specific.
2758 * It should probably get passed the status code
2759 * as well, as that might be protocol-specific.
2763 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2764 "Fault stub data (%d byte%s)",
2766 plurality(stub_length, "", "s"));
2770 /* Reassembly not complete - some fragments
2772 if (check_col(pinfo->cinfo, COL_INFO)) {
2773 col_append_fstr(pinfo->cinfo, COL_INFO,
2774 " [DCE/RPC fragment]");
2778 } else { /* MIDDLE fragment(s) */
2779 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2781 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2782 dcerpc_co_reassemble_table);
2783 fragment_add(tvb, offset, pinfo, value->rep_frame,
2784 dcerpc_co_reassemble_table,
2789 if (check_col(pinfo->cinfo, COL_INFO)) {
2790 col_append_fstr(pinfo->cinfo, COL_INFO,
2791 " [DCE/RPC fragment]");
2800 * DCERPC dissector for connection oriented calls
2803 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
2804 proto_tree *tree, gboolean can_desegment)
2806 static char nulls[4] = { 0 };
2809 proto_item *ti = NULL;
2810 proto_item *tf = NULL;
2811 proto_tree *dcerpc_tree = NULL;
2812 proto_tree *cn_flags_tree = NULL;
2813 proto_tree *drep_tree = NULL;
2814 e_dce_cn_common_hdr_t hdr;
2815 dcerpc_auth_info auth_info;
2818 * when done over nbt, dcerpc requests are padded with 4 bytes of null
2819 * data for some reason.
2821 * XXX - if that's always the case, the right way to do this would
2822 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
2823 * the 4 bytes of null padding, and make that the dissector
2824 * used for "netbios".
2826 if (tvb_bytes_exist (tvb, offset, 4) &&
2827 tvb_memeql (tvb, offset, nulls, 4) == 0) {
2837 * Check if this looks like a C/O DCERPC call
2839 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
2842 start_offset = offset;
2843 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
2844 if (hdr.rpc_ver != 5)
2846 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
2847 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
2849 hdr.ptype = tvb_get_guint8 (tvb, offset++);
2853 hdr.flags = tvb_get_guint8 (tvb, offset++);
2854 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
2855 offset += sizeof (hdr.drep);
2857 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2859 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2861 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
2864 if (can_desegment && pinfo->can_desegment
2865 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
2866 pinfo->desegment_offset = start_offset;
2867 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
2868 return 0; /* desegmentation required */
2871 if (check_col (pinfo->cinfo, COL_PROTOCOL))
2872 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
2873 if (check_col (pinfo->cinfo, COL_INFO))
2874 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
2875 pckt_vals[hdr.ptype].strptr, hdr.call_id);
2878 offset = start_offset;
2879 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
2881 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
2883 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
2884 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
2885 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
2886 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
2887 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
2888 if (cn_flags_tree) {
2889 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
2890 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
2891 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
2892 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
2893 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
2894 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
2895 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
2896 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
2900 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
2901 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
2903 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
2904 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
2905 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
2907 offset += sizeof (hdr.drep);
2909 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
2912 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
2915 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
2920 * Packet type specific stuff is next.
2922 switch (hdr.ptype) {
2925 dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr);
2930 dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
2935 * Nothing after the common header other than credentials.
2937 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, TRUE,
2942 dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
2946 dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
2950 dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
2954 dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
2960 * Nothing after the common header other than an authentication
2963 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
2969 * Nothing after the common header, not even an authentication
2975 /* might as well dissect the auth info */
2976 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
2980 return hdr.frag_len + padding;
2984 * DCERPC dissector for connection oriented calls over packet-oriented
2988 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2991 * Only one PDU per transport packet, and only one transport
2994 if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
2996 * It wasn't a DCERPC PDU.
3008 * DCERPC dissector for connection oriented calls over byte-stream
3012 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3016 gboolean ret = FALSE;
3019 * There may be multiple PDUs per transport packet; keep
3022 while (tvb_reported_length_remaining(tvb, offset) != 0) {
3023 pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
3024 dcerpc_cn_desegment);
3025 if (pdu_len == -1) {
3033 * Well, we've seen at least one DCERPC PDU.
3039 * Desegmentation required - bail now.
3045 * Step to the next PDU.
3053 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
3054 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
3056 proto_item *ti = NULL;
3057 proto_tree *auth_tree = NULL;
3058 guint8 protection_level;
3061 * Initially set "*auth_level_p" to -1 to indicate that we haven't
3062 * yet seen any authentication level information.
3064 if (auth_level_p != NULL)
3068 * The authentication information is at the *end* of the PDU; in
3069 * request and response PDUs, the request and response stub data
3072 * If the full packet is here, and there's data past the end of the
3073 * packet body, then dissect the auth info.
3075 offset += hdr->frag_len;
3076 if (tvb_length_remaining(tvb, offset) > 0) {
3077 switch (hdr->auth_proto) {
3079 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
3080 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
3081 auth_tree = proto_item_add_subtree (ti, ett_decrpc_krb5_auth_verf);
3082 protection_level = tvb_get_guint8 (tvb, offset);
3083 if (auth_level_p != NULL)
3084 *auth_level_p = protection_level;
3085 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
3087 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
3089 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
3090 offset += 6; /* 6 bytes of padding */
3092 offset += 2; /* 6 bytes of padding */
3093 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
3098 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
3105 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3106 proto_tree *dcerpc_tree,
3107 e_dce_dg_common_hdr_t *hdr)
3111 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3112 hdr->drep, hf_dcerpc_dg_cancel_vers,
3118 /* The only version we know about */
3119 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3120 hdr->drep, hf_dcerpc_dg_cancel_id,
3122 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3123 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3130 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
3131 proto_tree *dcerpc_tree,
3132 e_dce_dg_common_hdr_t *hdr)
3136 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3137 hdr->drep, hf_dcerpc_dg_cancel_vers,
3143 /* The only version we know about */
3144 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3145 hdr->drep, hf_dcerpc_dg_cancel_id,
3147 /* XXX - are NDR booleans 32 bits? */
3148 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3149 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3156 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3157 proto_tree *dcerpc_tree,
3158 e_dce_dg_common_hdr_t *hdr)
3165 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3166 hdr->drep, hf_dcerpc_dg_fack_vers,
3173 case 0: /* The only version documented in the DCE RPC 1.1 spec */
3174 case 1: /* This appears to be the same */
3175 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3176 hdr->drep, hf_dcerpc_dg_fack_window_size,
3178 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3179 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
3181 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3182 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
3184 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3185 hdr->drep, hf_dcerpc_dg_fack_serial_num,
3187 if (check_col (pinfo->cinfo, COL_INFO)) {
3188 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3191 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3192 hdr->drep, hf_dcerpc_dg_fack_selack_len,
3194 for (i = 0; i < selack_len; i++) {
3195 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3196 hdr->drep, hf_dcerpc_dg_fack_selack,
3205 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
3206 proto_tree *dcerpc_tree,
3207 e_dce_dg_common_hdr_t *hdr)
3211 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3212 hdr->drep, hf_dcerpc_dg_status,
3215 if (check_col (pinfo->cinfo, COL_INFO)) {
3216 col_append_fstr (pinfo->cinfo, COL_INFO,
3218 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3223 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
3224 proto_tree *dcerpc_tree, proto_tree *tree,
3225 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
3227 int length, reported_length, stub_length;
3228 gboolean save_fragmented;
3229 fragment_data *fd_head;
3231 if (check_col (pinfo->cinfo, COL_INFO)) {
3232 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u",
3233 di->call_data->opnum);
3236 length = tvb_length_remaining (tvb, offset);
3237 reported_length = tvb_reported_length_remaining (tvb, offset);
3238 stub_length = hdr->frag_len;
3239 if (length > stub_length)
3240 length = stub_length;
3241 if (reported_length > stub_length)
3242 reported_length = stub_length;
3244 save_fragmented = pinfo->fragmented;
3246 /* If we don't have reassembly enabled, or this packet contains
3247 the entire PDU, or if this is a short frame (or a frame
3248 not reassembled at a lower layer) that doesn't include all
3249 the data in the fragment, just call the handoff directly if
3250 this is the first fragment or the PDU isn't fragmented. */
3251 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
3252 !tvb_bytes_exist(tvb, offset, stub_length) ){
3253 if(hdr->frag_num == 0) {
3254 /* First fragment, possibly the only fragment */
3257 * XXX - authentication info?
3259 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
3260 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
3261 tvb_new_subset (tvb, offset, length,
3263 0, hdr->drep, di, NULL);
3265 /* PDU is fragmented and this isn't the first fragment */
3266 if (check_col(pinfo->cinfo, COL_INFO)) {
3267 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3271 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3272 "Fragment data (%d byte%s)",
3274 plurality(stub_length, "", "s"));
3279 /* Reassembly is enabled, the PDU is fragmented, and
3280 we have all the data in the fragment; the first two
3281 of those mean we should attempt reassembly, and the
3282 third means we can attempt reassembly. */
3285 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3286 "Fragment data (%d byte%s)", stub_length,
3287 plurality(stub_length, "", "s"));
3291 fd_head = fragment_add_seq(tvb, offset, pinfo,
3292 hdr->seqnum, dcerpc_cl_reassemble_table,
3293 hdr->frag_num, stub_length,
3294 !(hdr->flags1 & PFCL1_LASTFRAG));
3295 if (fd_head != NULL) {
3296 /* We completed reassembly */
3299 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3300 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3301 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3302 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
3303 dcerpc_tree, pinfo, next_tvb);
3306 * XXX - authentication info?
3308 pinfo->fragmented = FALSE;
3309 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3310 0, hdr->drep, di, NULL);
3312 /* Reassembly isn't completed yet */
3313 if (check_col(pinfo->cinfo, COL_INFO)) {
3314 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3318 pinfo->fragmented = save_fragmented;
3322 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
3323 proto_tree *dcerpc_tree, proto_tree *tree,
3324 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3327 dcerpc_call_value *value, v;
3329 if(!(pinfo->fd->flags.visited)){
3330 dcerpc_call_value *call_value;
3331 dcerpc_call_key *call_key;
3333 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
3334 call_key->conv=conv;
3335 call_key->call_id=hdr->seqnum;
3336 call_key->smb_fid=get_smb_fid(pinfo->private_data);
3338 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
3339 call_value->uuid = hdr->if_id;
3340 call_value->ver = hdr->if_ver;
3341 call_value->opnum = hdr->opnum;
3342 call_value->req_frame=pinfo->fd->num;
3343 call_value->req_time.secs=pinfo->fd->abs_secs;
3344 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3345 call_value->rep_frame=0;
3346 call_value->max_ptr=0;
3347 call_value->private_data = NULL;
3348 g_hash_table_insert (dcerpc_calls, call_key, call_value);
3350 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
3353 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
3355 v.uuid = hdr->if_id;
3356 v.ver = hdr->if_ver;
3357 v.opnum = hdr->opnum;
3358 v.req_frame = pinfo->fd->num;
3361 v.private_data=NULL;
3366 di.call_id = hdr->seqnum;
3369 di.call_data = value;
3371 if(value->rep_frame!=0){
3372 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3373 tvb, 0, 0, value->rep_frame);
3375 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
3379 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
3380 proto_tree *dcerpc_tree, proto_tree *tree,
3381 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3384 dcerpc_call_value *value, v;
3386 if(!(pinfo->fd->flags.visited)){
3387 dcerpc_call_value *call_value;
3388 dcerpc_call_key call_key;
3391 call_key.call_id=hdr->seqnum;
3392 call_key.smb_fid=get_smb_fid(pinfo->private_data);
3394 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
3395 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
3396 if(call_value->rep_frame==0){
3397 call_value->rep_frame=pinfo->fd->num;
3402 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
3404 v.uuid = hdr->if_id;
3405 v.ver = hdr->if_ver;
3406 v.opnum = hdr->opnum;
3408 v.rep_frame=pinfo->fd->num;
3409 v.private_data=NULL;
3417 di.call_data = value;
3419 if(value->req_frame!=0){
3421 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3422 tvb, 0, 0, value->req_frame);
3423 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3424 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3426 ns.nsecs+=1000000000;
3429 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3431 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
3435 * DCERPC dissector for connectionless calls
3438 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3440 proto_item *ti = NULL;
3441 proto_item *tf = NULL;
3442 proto_tree *dcerpc_tree = NULL;
3443 proto_tree *dg_flags1_tree = NULL;
3444 proto_tree *dg_flags2_tree = NULL;
3445 proto_tree *drep_tree = NULL;
3446 e_dce_dg_common_hdr_t hdr;
3448 conversation_t *conv;
3450 char uuid_str[DCERPC_UUID_STR_LEN];
3454 * Check if this looks like a CL DCERPC call. All dg packets
3455 * have an 80 byte header on them. Which starts with
3456 * version (4), pkt_type.
3458 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
3461 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3462 if (hdr.rpc_ver != 4)
3464 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3468 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3469 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3470 if (check_col (pinfo->cinfo, COL_INFO))
3471 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
3473 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
3474 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
3475 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3476 offset += sizeof (hdr.drep);
3477 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
3478 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
3480 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
3482 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
3484 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3486 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3488 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3490 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3492 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3494 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3496 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3498 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3500 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
3501 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
3504 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
3506 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
3512 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3516 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3520 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
3521 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
3522 if (dg_flags1_tree) {
3523 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
3524 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
3525 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
3526 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
3527 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
3528 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
3529 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
3530 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
3536 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
3537 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
3538 if (dg_flags2_tree) {
3539 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
3540 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
3541 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
3542 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
3543 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
3544 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
3545 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
3546 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
3552 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
3553 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3555 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3556 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3557 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3560 offset += sizeof (hdr.drep);
3563 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
3567 /* XXX - use "dissect_ndr_uuid_t()"? */
3568 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3569 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3570 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
3571 hdr.obj_id.Data4[0],
3572 hdr.obj_id.Data4[1],
3573 hdr.obj_id.Data4[2],
3574 hdr.obj_id.Data4[3],
3575 hdr.obj_id.Data4[4],
3576 hdr.obj_id.Data4[5],
3577 hdr.obj_id.Data4[6],
3578 hdr.obj_id.Data4[7]);
3579 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3580 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3581 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3582 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
3587 /* XXX - use "dissect_ndr_uuid_t()"? */
3588 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3589 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3590 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
3598 hdr.if_id.Data4[7]);
3599 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3600 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3601 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
3602 offset, 16, uuid_str, "Interface: %s", uuid_str);
3607 /* XXX - use "dissect_ndr_uuid_t()"? */
3608 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3609 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3610 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
3611 hdr.act_id.Data4[0],
3612 hdr.act_id.Data4[1],
3613 hdr.act_id.Data4[2],
3614 hdr.act_id.Data4[3],
3615 hdr.act_id.Data4[4],
3616 hdr.act_id.Data4[5],
3617 hdr.act_id.Data4[6],
3618 hdr.act_id.Data4[7]);
3619 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3620 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3621 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
3622 offset, 16, uuid_str, "Activity: %s", uuid_str);
3627 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
3631 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
3635 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
3636 if (check_col (pinfo->cinfo, COL_INFO)) {
3637 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq_num: %u", hdr.seqnum);
3642 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
3646 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
3650 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
3654 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
3658 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
3659 if (check_col (pinfo->cinfo, COL_INFO)) {
3660 if (hdr.flags1 & PFCL1_FRAG) {
3661 /* Fragmented - put the fragment number into the Info column */
3662 col_append_fstr (pinfo->cinfo, COL_INFO, " frag_num: %u",
3669 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
3673 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
3674 if (check_col (pinfo->cinfo, COL_INFO)) {
3675 if (hdr.flags1 & PFCL1_FRAG) {
3676 /* Fragmented - put the serial number into the Info column */
3677 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3678 (hdr.serial_hi << 8) | hdr.serial_lo);
3685 * XXX - for Kerberos, we get a protection level; if it's
3686 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
3689 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
3694 * keeping track of the conversation shouldn't really be necessary
3695 * for connectionless packets, because everything we need to know
3696 * to dissect is in the header for each packet. Unfortunately,
3697 * Microsoft's implementation is buggy and often puts the
3698 * completely wrong if_id in the header. go figure. So, keep
3699 * track of the seqnum and use that if possible. Note: that's not
3700 * completely correct. It should really be done based on both the
3701 * activity_id and seqnum. I haven't seen anywhere that it would
3702 * make a difference, but for future reference...
3704 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
3705 pinfo->srcport, pinfo->destport, 0);
3707 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
3708 pinfo->srcport, pinfo->destport, 0);
3712 * Packet type specific stuff is next.
3715 switch (hdr.ptype) {
3717 case PDU_CANCEL_ACK:
3718 /* Body is optional */
3719 /* XXX - we assume "frag_len" is the length of the body */
3720 if (hdr.frag_len != 0)
3721 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3726 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
3727 * but in at least one capture none of the Cl_cancel PDUs had a
3730 /* XXX - we assume "frag_len" is the length of the body */
3731 if (hdr.frag_len != 0)
3732 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
3736 /* Body is optional; if present, it's the same as PDU_FACK */
3737 /* XXX - we assume "frag_len" is the length of the body */
3738 if (hdr.frag_len != 0)
3739 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3743 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3748 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3752 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
3756 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
3759 /* these requests have no body */
3771 dcerpc_init_protocol (void)
3773 /* structures and data for BIND */
3775 g_hash_table_destroy (dcerpc_binds);
3777 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
3779 if (dcerpc_bind_key_chunk){
3780 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
3782 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
3783 sizeof (dcerpc_bind_key),
3784 200 * sizeof (dcerpc_bind_key),
3786 if (dcerpc_bind_value_chunk){
3787 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
3789 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
3790 sizeof (dcerpc_bind_value),
3791 200 * sizeof (dcerpc_bind_value),
3793 /* structures and data for CALL */
3795 g_hash_table_destroy (dcerpc_calls);
3797 dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
3798 if (dcerpc_call_key_chunk){
3799 g_mem_chunk_destroy (dcerpc_call_key_chunk);
3801 dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
3802 sizeof (dcerpc_call_key),
3803 200 * sizeof (dcerpc_call_key),
3805 if (dcerpc_call_value_chunk){
3806 g_mem_chunk_destroy (dcerpc_call_value_chunk);
3808 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
3809 sizeof (dcerpc_call_value),
3810 200 * sizeof (dcerpc_call_value),
3813 /* structure and data for MATCHED */
3814 if (dcerpc_matched){
3815 g_hash_table_destroy (dcerpc_matched);
3817 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
3822 proto_register_dcerpc (void)
3824 static hf_register_info hf[] = {
3825 { &hf_dcerpc_request_in,
3826 { "Request in", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
3827 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
3828 { &hf_dcerpc_response_in,
3829 { "Response in", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
3830 NULL, 0, "The response to this packet is in this packet", HFILL }},
3831 { &hf_dcerpc_referent_id,
3832 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
3833 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
3835 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3836 { &hf_dcerpc_ver_minor,
3837 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3838 { &hf_dcerpc_packet_type,
3839 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
3840 { &hf_dcerpc_cn_flags,
3841 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3842 { &hf_dcerpc_cn_flags_first_frag,
3843 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
3844 { &hf_dcerpc_cn_flags_last_frag,
3845 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
3846 { &hf_dcerpc_cn_flags_cancel_pending,
3847 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
3848 { &hf_dcerpc_cn_flags_reserved,
3849 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
3850 { &hf_dcerpc_cn_flags_mpx,
3851 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
3852 { &hf_dcerpc_cn_flags_dne,
3853 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
3854 { &hf_dcerpc_cn_flags_maybe,
3855 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
3856 { &hf_dcerpc_cn_flags_object,
3857 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
3859 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
3860 { &hf_dcerpc_drep_byteorder,
3861 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
3862 { &hf_dcerpc_drep_character,
3863 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
3864 { &hf_dcerpc_drep_fp,
3865 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
3866 { &hf_dcerpc_cn_frag_len,
3867 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3868 { &hf_dcerpc_cn_auth_len,
3869 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3870 { &hf_dcerpc_cn_call_id,
3871 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3872 { &hf_dcerpc_cn_max_xmit,
3873 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3874 { &hf_dcerpc_cn_max_recv,
3875 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3876 { &hf_dcerpc_cn_assoc_group,
3877 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
3878 { &hf_dcerpc_cn_num_ctx_items,
3879 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3880 { &hf_dcerpc_cn_ctx_id,
3881 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3882 { &hf_dcerpc_cn_num_trans_items,
3883 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3884 { &hf_dcerpc_cn_bind_if_id,
3885 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3886 { &hf_dcerpc_cn_bind_if_ver,
3887 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3888 { &hf_dcerpc_cn_bind_if_ver_minor,
3889 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3890 { &hf_dcerpc_cn_bind_trans_id,
3891 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3892 { &hf_dcerpc_cn_bind_trans_ver,
3893 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3894 { &hf_dcerpc_cn_alloc_hint,
3895 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3896 { &hf_dcerpc_cn_sec_addr_len,
3897 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3898 { &hf_dcerpc_cn_sec_addr,
3899 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
3900 { &hf_dcerpc_cn_num_results,
3901 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3902 { &hf_dcerpc_cn_ack_result,
3903 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
3904 { &hf_dcerpc_cn_ack_reason,
3905 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
3906 { &hf_dcerpc_cn_ack_trans_id,
3907 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3908 { &hf_dcerpc_cn_ack_trans_ver,
3909 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3910 { &hf_dcerpc_cn_reject_reason,
3911 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
3912 { &hf_dcerpc_cn_num_protocols,
3913 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3914 { &hf_dcerpc_cn_protocol_ver_major,
3915 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3916 { &hf_dcerpc_cn_protocol_ver_minor,
3917 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3918 { &hf_dcerpc_cn_cancel_count,
3919 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3920 { &hf_dcerpc_cn_status,
3921 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
3922 { &hf_dcerpc_auth_type,
3923 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
3924 { &hf_dcerpc_auth_level,
3925 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
3926 { &hf_dcerpc_auth_pad_len,
3927 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3928 { &hf_dcerpc_auth_rsrvd,
3929 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3930 { &hf_dcerpc_auth_ctx_id,
3931 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3932 { &hf_dcerpc_dg_flags1,
3933 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3934 { &hf_dcerpc_dg_flags1_rsrvd_01,
3935 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
3936 { &hf_dcerpc_dg_flags1_last_frag,
3937 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
3938 { &hf_dcerpc_dg_flags1_frag,
3939 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
3940 { &hf_dcerpc_dg_flags1_nofack,
3941 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
3942 { &hf_dcerpc_dg_flags1_maybe,
3943 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
3944 { &hf_dcerpc_dg_flags1_idempotent,
3945 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
3946 { &hf_dcerpc_dg_flags1_broadcast,
3947 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
3948 { &hf_dcerpc_dg_flags1_rsrvd_80,
3949 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
3950 { &hf_dcerpc_dg_flags2,
3951 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3952 { &hf_dcerpc_dg_flags2_rsrvd_01,
3953 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
3954 { &hf_dcerpc_dg_flags2_cancel_pending,
3955 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
3956 { &hf_dcerpc_dg_flags2_rsrvd_04,
3957 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
3958 { &hf_dcerpc_dg_flags2_rsrvd_08,
3959 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
3960 { &hf_dcerpc_dg_flags2_rsrvd_10,
3961 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
3962 { &hf_dcerpc_dg_flags2_rsrvd_20,
3963 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
3964 { &hf_dcerpc_dg_flags2_rsrvd_40,
3965 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
3966 { &hf_dcerpc_dg_flags2_rsrvd_80,
3967 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
3968 { &hf_dcerpc_dg_serial_lo,
3969 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3970 { &hf_dcerpc_dg_serial_hi,
3971 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3972 { &hf_dcerpc_dg_ahint,
3973 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
3974 { &hf_dcerpc_dg_ihint,
3975 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
3976 { &hf_dcerpc_dg_frag_len,
3977 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3978 { &hf_dcerpc_dg_frag_num,
3979 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3980 { &hf_dcerpc_dg_auth_proto,
3981 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
3982 { &hf_dcerpc_dg_seqnum,
3983 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3984 { &hf_dcerpc_dg_server_boot,
3985 { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
3986 { &hf_dcerpc_dg_if_ver,
3987 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3988 { &hf_dcerpc_krb5_av_prot_level,
3989 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
3990 { &hf_dcerpc_krb5_av_key_vers_num,
3991 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3992 { &hf_dcerpc_krb5_av_key_auth_verifier,
3993 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
3994 { &hf_dcerpc_obj_id,
3995 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3996 { &hf_dcerpc_dg_if_id,
3997 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3998 { &hf_dcerpc_dg_act_id,
3999 { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4001 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4003 { &hf_dcerpc_dg_cancel_vers,
4004 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4006 { &hf_dcerpc_dg_cancel_id,
4007 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4009 { &hf_dcerpc_dg_server_accepting_cancels,
4010 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
4012 { &hf_dcerpc_dg_fack_vers,
4013 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4015 { &hf_dcerpc_dg_fack_window_size,
4016 { "Window Size", "dcerpc.fack_window size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4018 { &hf_dcerpc_dg_fack_max_tsdu,
4019 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4021 { &hf_dcerpc_dg_fack_max_frag_size,
4022 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4024 { &hf_dcerpc_dg_fack_serial_num,
4025 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4027 { &hf_dcerpc_dg_fack_selack_len,
4028 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4030 { &hf_dcerpc_dg_fack_selack,
4031 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4033 { &hf_dcerpc_dg_status,
4034 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4036 { &hf_dcerpc_array_max_count,
4037 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
4039 { &hf_dcerpc_array_offset,
4040 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
4042 { &hf_dcerpc_array_actual_count,
4043 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
4045 { &hf_dcerpc_array_buffer,
4046 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
4049 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4051 { &hf_dcerpc_fragments,
4052 { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
4053 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
4055 { &hf_dcerpc_fragment,
4056 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
4057 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
4059 { &hf_dcerpc_fragment_overlap,
4060 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
4062 { &hf_dcerpc_fragment_overlap_conflict,
4063 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
4065 { &hf_dcerpc_fragment_multiple_tails,
4066 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
4068 { &hf_dcerpc_fragment_too_long_fragment,
4069 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
4071 { &hf_dcerpc_fragment_error,
4072 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
4075 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "Time between Request and Reply for DCE-RPC calls", HFILL }}
4078 static gint *ett[] = {
4080 &ett_dcerpc_cn_flags,
4082 &ett_dcerpc_dg_flags1,
4083 &ett_dcerpc_dg_flags2,
4084 &ett_dcerpc_pointer_data,
4086 &ett_dcerpc_fragments,
4087 &ett_dcerpc_fragment,
4088 &ett_decrpc_krb5_auth_verf,
4090 module_t *dcerpc_module;
4092 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
4093 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
4094 proto_register_subtree_array (ett, array_length (ett));
4095 register_init_routine (dcerpc_init_protocol);
4096 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
4097 prefs_register_bool_preference (dcerpc_module,
4099 "Desegment all DCE/RPC over TCP",
4100 "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
4101 &dcerpc_cn_desegment);
4102 prefs_register_bool_preference (dcerpc_module,
4103 "reassemble_dcerpc",
4104 "Reassemble DCE/RPC fragments",
4105 "Whether the DCE/RPC dissector should reassemble all fragmented PDUs",
4106 &dcerpc_reassemble);
4107 register_init_routine(dcerpc_reassemble_init);
4108 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
4109 dcerpc_tap=register_tap("dcerpc");
4113 proto_reg_handoff_dcerpc (void)
4115 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
4116 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
4117 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
4118 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
4119 ntlmssp_handle = find_dissector("ntlmssp");
4120 ntlmssp_verf_handle = find_dissector("ntlmssp_verf");
4121 ntlmssp_enc_payload_handle = find_dissector("ntlmssp_encrypted_payload");
4122 gssapi_handle = find_dissector("gssapi");
4123 gssapi_verf_handle = find_dissector("gssapi_verf");
4124 dcerpc_smb_init(proto_dcerpc);