2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas@webspan.net>
5 * $Id: packet-dcerpc.c,v 1.78 2002/09/09 22:11:33 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 static const value_string pckt_vals[] = {
41 { PDU_REQ, "Request"},
43 { PDU_RESP, "Response"},
44 { PDU_FAULT, "Fault"},
45 { PDU_WORKING, "Working"},
46 { PDU_NOCALL, "Nocall"},
47 { PDU_REJECT, "Reject"},
49 { PDU_CL_CANCEL, "Cl_cancel"},
51 { PDU_CANCEL_ACK, "Cancel_ack"},
53 { PDU_BIND_ACK, "Bind_ack"},
54 { PDU_BIND_NAK, "Bind_nak"},
55 { PDU_ALTER, "Alter_context"},
56 { PDU_ALTER_ACK, "Alter_context_resp"},
57 { PDU_AUTH3, "AUTH3?"},
58 { PDU_SHUTDOWN, "Shutdown"},
59 { PDU_CO_CANCEL, "Co_cancel"},
60 { PDU_ORPHANED, "Orphaned"},
64 static const value_string drep_byteorder_vals[] = {
66 { 1, "Little-endian" },
70 static const value_string drep_character_vals[] = {
76 #define DCE_RPC_DREP_FP_IEEE 0
77 #define DCE_RPC_DREP_FP_VAX 1
78 #define DCE_RPC_DREP_FP_CRAY 2
79 #define DCE_RPC_DREP_FP_IBM 3
81 static const value_string drep_fp_vals[] = {
82 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
83 { DCE_RPC_DREP_FP_VAX, "VAX" },
84 { DCE_RPC_DREP_FP_CRAY, "Cray" },
85 { DCE_RPC_DREP_FP_IBM, "IBM" },
90 * Authentication services.
92 #define DCE_C_RPC_AUTHN_PROTOCOL_NONE 0
93 #define DCE_C_RPC_AUTHN_PROTOCOL_KRB5 1
94 #define DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO 9
95 #define DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP 10
96 #define DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN 68
98 static const value_string authn_protocol_vals[] = {
99 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
100 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
101 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
102 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
103 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN,"NETLOGON Secure Channel" },
110 #define DCE_C_AUTHN_LEVEL_NONE 1
111 #define DCE_C_AUTHN_LEVEL_CONNECT 2
112 #define DCE_C_AUTHN_LEVEL_CALL 3
113 #define DCE_C_AUTHN_LEVEL_PKT 4
114 #define DCE_C_AUTHN_LEVEL_PKT_INTEGRITY 5
115 #define DCE_C_AUTHN_LEVEL_PKT_PRIVACY 6
117 static const value_string authn_level_vals[] = {
118 { DCE_C_AUTHN_LEVEL_NONE, "None" },
119 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
120 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
121 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
122 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
123 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
128 * Flag bits in first flag field in connectionless PDU header.
130 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
131 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
132 * fragment of a multi-PDU
134 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
135 a multi-PDU transmission */
136 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
137 * requested to send a `fack' PDU
138 * for the fragment */
139 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
141 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
143 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
145 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
148 * Flag bits in second flag field in connectionless PDU header.
150 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
151 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
152 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
153 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
154 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
155 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
156 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
157 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
160 * Flag bits in connection-oriented PDU header.
162 #define PFC_FIRST_FRAG 0x01 /* First fragment */
163 #define PFC_LAST_FRAG 0x02 /* Last fragment */
164 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
165 #define PFC_RESERVED_1 0x08
166 #define PFC_CONC_MPX 0x10 /* suports concurrent multiplexing
167 * of a single connection. */
168 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
169 * if true, guaranteed call did not
171 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
172 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
173 * was specified in the handle, and
174 * is present in the optional object
175 * field. If false, the object field
179 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
180 * it's not fragmented (i.e., this is both the first *and* last fragment),
181 * and FALSE otherwise.
183 #define PFC_NOT_FRAGMENTED(hdr) \
184 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG))==(PFC_FIRST_FRAG|PFC_LAST_FRAG))
187 * Presentation context negotiation result.
189 static const value_string p_cont_result_vals[] = {
191 { 1, "User rejection" },
192 { 2, "Provider rejection" },
197 * Presentation context negotiation rejection reasons.
199 static const value_string p_provider_reason_vals[] = {
200 { 0, "Reason not specified" },
201 { 1, "Abstract syntax not supported" },
202 { 2, "Proposed transfer syntaxes not supported" },
203 { 3, "Local limit exceeded" },
210 #define REASON_NOT_SPECIFIED 0
211 #define TEMPORARY_CONGESTION 1
212 #define LOCAL_LIMIT_EXCEEDED 2
213 #define CALLED_PADDR_UNKNOWN 3 /* not used */
214 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
215 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
216 #define USER_DATA_NOT_READABLE 6 /* not used */
217 #define NO_PSAP_AVAILABLE 7 /* not used */
219 static const value_string reject_reason_vals[] = {
220 { REASON_NOT_SPECIFIED, "Reason not specified" },
221 { TEMPORARY_CONGESTION, "Temporary congestion" },
222 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
223 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
224 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
225 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
226 { USER_DATA_NOT_READABLE, "User data not readable" },
227 { NO_PSAP_AVAILABLE, "No PSAP available" },
232 * Reject status codes.
234 static const value_string reject_status_vals[] = {
235 { 0, "Stub-defined exception" },
236 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
237 { 0x1c000002, "nca_s_fault_addr_error" },
238 { 0x1c000003, "nca_s_fault_fp_div_zero" },
239 { 0x1c000004, "nca_s_fault_fp_underflow" },
240 { 0x1c000005, "nca_s_fault_fp_overflow" },
241 { 0x1c000006, "nca_s_fault_invalid_tag" },
242 { 0x1c000007, "nca_s_fault_invalid_bound" },
243 { 0x1c000008, "nca_rpc_version_mismatch" },
244 { 0x1c000009, "nca_unspec_reject" },
245 { 0x1c00000a, "nca_s_bad_actid" },
246 { 0x1c00000b, "nca_who_are_you_failed" },
247 { 0x1c00000c, "nca_manager_not_entered" },
248 { 0x1c00000d, "nca_s_fault_cancel" },
249 { 0x1c00000e, "nca_s_fault_ill_inst" },
250 { 0x1c00000f, "nca_s_fault_fp_error" },
251 { 0x1c000010, "nca_s_fault_int_overflow" },
252 { 0x1c000014, "nca_s_fault_pipe_empty" },
253 { 0x1c000015, "nca_s_fault_pipe_closed" },
254 { 0x1c000016, "nca_s_fault_pipe_order" },
255 { 0x1c000017, "nca_s_fault_pipe_discipline" },
256 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
257 { 0x1c000019, "nca_s_fault_pipe_memory" },
258 { 0x1c00001a, "nca_s_fault_context_mismatch" },
259 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
260 { 0x1c00001c, "nca_invalid_pres_context_id" },
261 { 0x1c00001d, "nca_unsupported_authn_level" },
262 { 0x1c00001f, "nca_invalid_checksum" },
263 { 0x1c000020, "nca_invalid_crc" },
264 { 0x1c000021, "ncs_s_fault_user_defined" },
265 { 0x1c000022, "nca_s_fault_tx_open_failed" },
266 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
267 { 0x1c000024, "nca_s_fault_object_not_found" },
268 { 0x1c000025, "nca_s_fault_no_client_stub" },
269 { 0x1c010002, "nca_op_rng_error" },
270 { 0x1c010003, "nca_unk_if"},
271 { 0x1c010006, "nca_wrong_boot_time" },
272 { 0x1c010009, "nca_s_you_crashed" },
273 { 0x1c01000b, "nca_proto_error" },
274 { 0x1c010013, "nca_out_args_too_big" },
275 { 0x1c010014, "nca_server_too_busy" },
276 { 0x1c010017, "nca_unsupported_type" },
280 static int proto_dcerpc = -1;
283 static int hf_dcerpc_request_in = -1;
284 static int hf_dcerpc_response_in = -1;
285 static int hf_dcerpc_ver = -1;
286 static int hf_dcerpc_ver_minor = -1;
287 static int hf_dcerpc_packet_type = -1;
288 static int hf_dcerpc_cn_flags = -1;
289 static int hf_dcerpc_cn_flags_first_frag = -1;
290 static int hf_dcerpc_cn_flags_last_frag = -1;
291 static int hf_dcerpc_cn_flags_cancel_pending = -1;
292 static int hf_dcerpc_cn_flags_reserved = -1;
293 static int hf_dcerpc_cn_flags_mpx = -1;
294 static int hf_dcerpc_cn_flags_dne = -1;
295 static int hf_dcerpc_cn_flags_maybe = -1;
296 static int hf_dcerpc_cn_flags_object = -1;
297 static int hf_dcerpc_drep = -1;
298 static int hf_dcerpc_drep_byteorder = -1;
299 static int hf_dcerpc_drep_character = -1;
300 static int hf_dcerpc_drep_fp = -1;
301 static int hf_dcerpc_cn_frag_len = -1;
302 static int hf_dcerpc_cn_auth_len = -1;
303 static int hf_dcerpc_cn_call_id = -1;
304 static int hf_dcerpc_cn_max_xmit = -1;
305 static int hf_dcerpc_cn_max_recv = -1;
306 static int hf_dcerpc_cn_assoc_group = -1;
307 static int hf_dcerpc_cn_num_ctx_items = -1;
308 static int hf_dcerpc_cn_ctx_id = -1;
309 static int hf_dcerpc_cn_num_trans_items = -1;
310 static int hf_dcerpc_cn_bind_if_id = -1;
311 static int hf_dcerpc_cn_bind_if_ver = -1;
312 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
313 static int hf_dcerpc_cn_bind_trans_id = -1;
314 static int hf_dcerpc_cn_bind_trans_ver = -1;
315 static int hf_dcerpc_cn_alloc_hint = -1;
316 static int hf_dcerpc_cn_sec_addr_len = -1;
317 static int hf_dcerpc_cn_sec_addr = -1;
318 static int hf_dcerpc_cn_num_results = -1;
319 static int hf_dcerpc_cn_ack_result = -1;
320 static int hf_dcerpc_cn_ack_reason = -1;
321 static int hf_dcerpc_cn_ack_trans_id = -1;
322 static int hf_dcerpc_cn_ack_trans_ver = -1;
323 static int hf_dcerpc_cn_reject_reason = -1;
324 static int hf_dcerpc_cn_num_protocols = -1;
325 static int hf_dcerpc_cn_protocol_ver_major = -1;
326 static int hf_dcerpc_cn_protocol_ver_minor = -1;
327 static int hf_dcerpc_cn_cancel_count = -1;
328 static int hf_dcerpc_cn_status = -1;
329 static int hf_dcerpc_auth_type = -1;
330 static int hf_dcerpc_auth_level = -1;
331 static int hf_dcerpc_auth_pad_len = -1;
332 static int hf_dcerpc_auth_rsrvd = -1;
333 static int hf_dcerpc_auth_ctx_id = -1;
334 static int hf_dcerpc_dg_flags1 = -1;
335 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
336 static int hf_dcerpc_dg_flags1_last_frag = -1;
337 static int hf_dcerpc_dg_flags1_frag = -1;
338 static int hf_dcerpc_dg_flags1_nofack = -1;
339 static int hf_dcerpc_dg_flags1_maybe = -1;
340 static int hf_dcerpc_dg_flags1_idempotent = -1;
341 static int hf_dcerpc_dg_flags1_broadcast = -1;
342 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
343 static int hf_dcerpc_dg_flags2 = -1;
344 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
345 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
346 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
347 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
348 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
349 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
350 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
351 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
352 static int hf_dcerpc_dg_serial_hi = -1;
353 static int hf_dcerpc_obj_id = -1;
354 static int hf_dcerpc_dg_if_id = -1;
355 static int hf_dcerpc_dg_act_id = -1;
356 static int hf_dcerpc_dg_serial_lo = -1;
357 static int hf_dcerpc_dg_ahint = -1;
358 static int hf_dcerpc_dg_ihint = -1;
359 static int hf_dcerpc_dg_frag_len = -1;
360 static int hf_dcerpc_dg_frag_num = -1;
361 static int hf_dcerpc_dg_auth_proto = -1;
362 static int hf_dcerpc_opnum = -1;
363 static int hf_dcerpc_dg_seqnum = -1;
364 static int hf_dcerpc_dg_server_boot = -1;
365 static int hf_dcerpc_dg_if_ver = -1;
366 static int hf_dcerpc_krb5_av_prot_level = -1;
367 static int hf_dcerpc_krb5_av_key_vers_num = -1;
368 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
369 static int hf_dcerpc_dg_cancel_vers = -1;
370 static int hf_dcerpc_dg_cancel_id = -1;
371 static int hf_dcerpc_dg_server_accepting_cancels = -1;
372 static int hf_dcerpc_dg_fack_vers = -1;
373 static int hf_dcerpc_dg_fack_window_size = -1;
374 static int hf_dcerpc_dg_fack_max_tsdu = -1;
375 static int hf_dcerpc_dg_fack_max_frag_size = -1;
376 static int hf_dcerpc_dg_fack_serial_num = -1;
377 static int hf_dcerpc_dg_fack_selack_len = -1;
378 static int hf_dcerpc_dg_fack_selack = -1;
379 static int hf_dcerpc_dg_status = -1;
380 static int hf_dcerpc_array_max_count = -1;
381 static int hf_dcerpc_array_offset = -1;
382 static int hf_dcerpc_array_actual_count = -1;
383 static int hf_dcerpc_op = -1;
384 static int hf_dcerpc_referent_id = -1;
385 static int hf_dcerpc_fragments = -1;
386 static int hf_dcerpc_fragment = -1;
387 static int hf_dcerpc_fragment_overlap = -1;
388 static int hf_dcerpc_fragment_overlap_conflict = -1;
389 static int hf_dcerpc_fragment_multiple_tails = -1;
390 static int hf_dcerpc_fragment_too_long_fragment = -1;
391 static int hf_dcerpc_fragment_error = -1;
393 static gint ett_dcerpc = -1;
394 static gint ett_dcerpc_cn_flags = -1;
395 static gint ett_dcerpc_drep = -1;
396 static gint ett_dcerpc_dg_flags1 = -1;
397 static gint ett_dcerpc_dg_flags2 = -1;
398 static gint ett_dcerpc_pointer_data = -1;
399 static gint ett_dcerpc_fragments = -1;
400 static gint ett_dcerpc_fragment = -1;
401 static gint ett_decrpc_krb5_auth_verf = -1;
403 static dissector_handle_t ntlmssp_handle, gssapi_handle;
405 fragment_items dcerpc_frag_items = {
406 &ett_dcerpc_fragments,
407 &ett_dcerpc_fragment,
409 &hf_dcerpc_fragments,
411 &hf_dcerpc_fragment_overlap,
412 &hf_dcerpc_fragment_overlap_conflict,
413 &hf_dcerpc_fragment_multiple_tails,
414 &hf_dcerpc_fragment_too_long_fragment,
415 &hf_dcerpc_fragment_error,
420 /* try to desegment big DCE/RPC packets over TCP? */
421 static gboolean dcerpc_cn_desegment = TRUE;
423 /* reassemble DCE/RPC fragments */
424 /* reassembly of dcerpc fragments will not work for the case where ONE frame
425 might contain multiple dcerpc fragments for different PDUs.
426 this case would be so unusual/weird so if you got captures like that:
429 static gboolean dcerpc_reassemble = FALSE;
430 static GHashTable *dcerpc_co_reassemble_table = NULL;
431 static GHashTable *dcerpc_cl_reassemble_table = NULL;
434 dcerpc_reassemble_init(void)
436 fragment_table_init(&dcerpc_co_reassemble_table);
437 fragment_table_init(&dcerpc_cl_reassemble_table);
444 /* the registered subdissectors */
445 static GHashTable *dcerpc_uuids;
447 typedef struct _dcerpc_uuid_key {
452 typedef struct _dcerpc_uuid_value {
456 dcerpc_sub_dissector *procs;
461 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
463 dcerpc_uuid_key *key1 = (dcerpc_uuid_key *)k1;
464 dcerpc_uuid_key *key2 = (dcerpc_uuid_key *)k2;
465 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
466 && (key1->ver == key2->ver));
470 dcerpc_uuid_hash (gconstpointer k)
472 dcerpc_uuid_key *key = (dcerpc_uuid_key *)k;
473 /* This isn't perfect, but the Data1 part of these is almost always
475 return key->uuid.Data1;
479 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
480 dcerpc_sub_dissector *procs, int opnum_hf)
482 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
483 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
488 value->proto = proto;
490 value->name = proto_get_protocol_short_name (proto);
491 value->procs = procs;
492 value->opnum_hf = opnum_hf;
494 g_hash_table_insert (dcerpc_uuids, key, value);
499 * To keep track of ctx_id mappings.
501 * Everytime we see a bind call we update this table.
502 * Note that we always specify a SMB FID. For non-SMB transports this
505 static GHashTable *dcerpc_binds=NULL;
507 typedef struct _dcerpc_bind_key {
508 conversation_t *conv;
513 typedef struct _dcerpc_bind_value {
518 static GMemChunk *dcerpc_bind_key_chunk=NULL;
519 static GMemChunk *dcerpc_bind_value_chunk=NULL;
522 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
524 dcerpc_bind_key *key1 = (dcerpc_bind_key *)k1;
525 dcerpc_bind_key *key2 = (dcerpc_bind_key *)k2;
526 return (key1->conv == key2->conv
527 && key1->ctx_id == key2->ctx_id
528 && key1->smb_fid == key2->smb_fid);
532 dcerpc_bind_hash (gconstpointer k)
534 dcerpc_bind_key *key = (dcerpc_bind_key *)k;
535 return ((guint)key->conv) + key->ctx_id + key->smb_fid;
539 * To keep track of callid mappings. Should really use some generic
540 * conversation support instead.
542 static GHashTable *dcerpc_calls=NULL;
544 typedef struct _dcerpc_call_key {
545 conversation_t *conv;
550 static GMemChunk *dcerpc_call_key_chunk=NULL;
552 static GMemChunk *dcerpc_call_value_chunk=NULL;
555 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
557 dcerpc_call_key *key1 = (dcerpc_call_key *)k1;
558 dcerpc_call_key *key2 = (dcerpc_call_key *)k2;
559 return (key1->conv == key2->conv
560 && key1->call_id == key2->call_id
561 && key1->smb_fid == key2->smb_fid);
565 dcerpc_call_hash (gconstpointer k)
567 dcerpc_call_key *key = (dcerpc_call_key *)k;
568 return ((guint32)key->conv) + key->call_id + key->smb_fid;
572 /* to keep track of matched calls/responses
573 this one uses the same value struct as calls, but the key is the frame id
575 static GHashTable *dcerpc_matched=NULL;
577 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
579 return (guint32)k1 == (guint32)k2;
583 dcerpc_matched_hash (gconstpointer k)
591 * Utility functions. Modeled after packet-rpc.c
595 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
596 proto_tree *tree, char *drep,
597 int hfindex, guint8 *pdata)
601 data = tvb_get_guint8 (tvb, offset);
603 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
611 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
612 proto_tree *tree, char *drep,
613 int hfindex, guint16 *pdata)
617 data = ((drep[0] & 0x10)
618 ? tvb_get_letohs (tvb, offset)
619 : tvb_get_ntohs (tvb, offset));
622 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
630 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
631 proto_tree *tree, char *drep,
632 int hfindex, guint32 *pdata)
636 data = ((drep[0] & 0x10)
637 ? tvb_get_letohl (tvb, offset)
638 : tvb_get_ntohl (tvb, offset));
641 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
649 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
650 proto_tree *tree, char *drep,
651 int hfindex, unsigned char *pdata)
654 tvb_memcpy(tvb, pdata, offset, 8);
655 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
657 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
658 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
659 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
660 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
665 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
673 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
674 proto_tree *tree, char *drep,
675 int hfindex, gfloat *pdata)
681 case(DCE_RPC_DREP_FP_IEEE):
682 data = ((drep[0] & 0x10)
683 ? tvb_get_letohieee_float(tvb, offset)
684 : tvb_get_ntohieee_float(tvb, offset));
686 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
689 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
690 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
691 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
693 /* ToBeDone: non IEEE floating formats */
694 /* Set data to a negative infinity value */
695 data = -1.0 * 1e100 * 1e100;
697 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
707 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
708 proto_tree *tree, char *drep,
709 int hfindex, gdouble *pdata)
715 case(DCE_RPC_DREP_FP_IEEE):
716 data = ((drep[0] & 0x10)
717 ? tvb_get_letohieee_double(tvb, offset)
718 : tvb_get_ntohieee_double(tvb, offset));
720 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
723 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
724 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
725 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
727 /* ToBeDone: non IEEE double formats */
728 /* Set data to a negative infinity value */
729 data = -1.0 * 1e100 * 1e100;
731 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
741 * a couple simpler things
744 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
746 if (drep[0] & 0x10) {
747 return tvb_get_letohs (tvb, offset);
749 return tvb_get_ntohs (tvb, offset);
754 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
756 if (drep[0] & 0x10) {
757 return tvb_get_letohl (tvb, offset);
759 return tvb_get_ntohl (tvb, offset);
764 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
767 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
768 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
769 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
771 for (i=0; i<sizeof (uuid->Data4); i++) {
772 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
779 /* function to dissect a unidimensional conformant array */
781 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
782 proto_tree *tree, char *drep,
783 dcerpc_dissect_fnct_t *fnct)
789 di=pinfo->private_data;
790 if(di->conformant_run){
791 /* conformant run, just dissect the max_count header */
793 di->conformant_run=0;
794 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
795 hf_dcerpc_array_max_count, &di->array_max_count);
796 di->array_max_count_offset=offset-4;
797 di->conformant_run=1;
798 di->conformant_eaten=offset-old_offset;
800 /* we dont dont remember where in the bytestream this fields was */
801 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
803 /* real run, dissect the elements */
804 for(i=0;i<di->array_max_count;i++){
805 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
811 /* function to dissect a unidimensional conformant and varying array */
813 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
814 proto_tree *tree, char *drep,
815 dcerpc_dissect_fnct_t *fnct)
821 di=pinfo->private_data;
822 if(di->conformant_run){
823 /* conformant run, just dissect the max_count header */
825 di->conformant_run=0;
826 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
827 hf_dcerpc_array_max_count, &di->array_max_count);
828 di->array_max_count_offset=offset-4;
829 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
830 hf_dcerpc_array_offset, &di->array_offset);
831 di->array_offset_offset=offset-4;
832 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
833 hf_dcerpc_array_actual_count, &di->array_actual_count);
834 di->array_actual_count_offset=offset-4;
835 di->conformant_run=1;
836 di->conformant_eaten=offset-old_offset;
838 /* we dont dont remember where in the bytestream these fields were */
839 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
840 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
841 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
843 /* real run, dissect the elements */
844 for(i=0;i<di->array_actual_count;i++){
845 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
853 /* ndr pointer handling */
854 /* list of pointers encountered so far */
855 static GSList *ndr_pointer_list = NULL;
857 /* position where in the list to insert newly encountered pointers */
858 static int ndr_pointer_list_pos=0;
860 /* boolean controlling whether pointers are top-level or embedded */
861 static gboolean pointers_are_top_level = TRUE;
863 /* as a kludge, we represent all embedded reference pointers as id==-1
864 hoping that his will not collide with any non-ref pointers */
865 typedef struct ndr_pointer_data {
868 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
871 } ndr_pointer_data_t;
874 init_ndr_pointer_list(packet_info *pinfo)
878 di=pinfo->private_data;
879 di->conformant_run=0;
881 while(ndr_pointer_list){
882 ndr_pointer_data_t *npd;
884 npd=g_slist_nth_data(ndr_pointer_list, 0);
885 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
891 ndr_pointer_list=NULL;
892 ndr_pointer_list_pos=0;
893 pointers_are_top_level=TRUE;
897 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *drep)
899 int found_new_pointer;
903 di=pinfo->private_data;
908 len=g_slist_length(ndr_pointer_list);
910 ndr_pointer_data_t *tnpd;
911 tnpd=g_slist_nth_data(ndr_pointer_list, i);
913 dcerpc_dissect_fnct_t *fnct;
918 ndr_pointer_list_pos=i+1;
919 di->hf_index=tnpd->hf_index;
920 di->levels=tnpd->levels;
921 /* first a run to handle any conformant
923 di->conformant_run=1;
924 di->conformant_eaten=0;
926 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
928 g_assert((offset-old_offset)==di->conformant_eaten);
929 /* This is to check for any bugs in the dissectors.
931 * Basically, the NDR representation will store all
932 * arrays in two blocks, one block with the dimension
933 * discreption, like size, number of elements and such,
934 * and another block that contains the actual data stored
936 * If the array is embedded directly inside another,
937 * encapsulating aggregate type, like a union or struct,
938 * then these two blocks will be stored at different places
939 * in the bytestream, with other data between the blocks.
941 * For this reason, all pointers to types (both aggregate
942 * and scalar, for simplicity no distinction is made)
943 * will have its dissector called twice.
944 * The dissector will first be called with conformant_run==1
945 * in which mode the dissector MUST NOT consume any data from
946 * the tvbuff (i.e. may not dissect anything) except the
947 * initial control block for arrays.
948 * The second time the dissector is called, with
949 * conformant_run==0, all other data for the type will be
952 * All dissect_ndr_<type> dissectors are already prepared
953 * for this and knows when it should eat data from the tvb
954 * and when not to, so implementors of dissectors will
955 * normally not need to worry about this or even know about
956 * it. However, if a dissector for an aggregate type calls
957 * a subdissector from outside packet-dcerpc.c, such as
958 * the dissector in packet-smb.c for NT Security Descriptors
959 * as an example, then it is VERY important to encapsulate
960 * this call to an external subdissector with the appropriate
961 * test for conformant_run, i.e. it will need something like
965 * di=pinfo->private_data;
966 * if(di->conformant_run){
970 * to make sure it makes the right thing.
971 * This assert will signal when someone has forgotten to
972 * make the dissector aware of this requirement.
975 /* now we dissect the actual pointer */
976 di->conformant_run=0;
977 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
981 } while(found_new_pointer);
988 add_pointer_to_list(packet_info *pinfo, proto_tree *tree,
989 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, int levels)
991 ndr_pointer_data_t *npd;
993 /* check if this pointer is valid */
996 dcerpc_call_value *value;
998 di=pinfo->private_data;
1002 if(!(pinfo->fd->flags.visited)){
1003 if(id>value->max_ptr){
1008 /* if we havent seen the request bail out since we cant
1009 know whether this is the first non-NULL instance
1011 if(value->req_frame==0){
1012 /* XXX THROW EXCEPTION */
1015 /* We saw this one in the request frame, nothing to
1017 if(id<=value->max_ptr){
1023 npd=g_malloc(sizeof(ndr_pointer_data_t));
1027 npd->hf_index=hf_index;
1029 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1030 ndr_pointer_list_pos);
1031 ndr_pointer_list_pos++;
1036 find_pointer_index(guint32 id)
1038 ndr_pointer_data_t *npd;
1041 len=g_slist_length(ndr_pointer_list);
1043 npd=g_slist_nth_data(ndr_pointer_list, i);
1054 /* This function dissects an NDR pointer and stores the callback for later
1055 * deferred dissection.
1057 * fnct is the callback function for when we have reached this object in
1060 * type is what type of pointer.
1062 * this is text is what text we should put in any created tree node.
1064 * hf_index is what hf value we want to pass to the callback function when
1065 * it is called, the callback can later pich this one up from di->hf_index.
1067 * levels is a generic int we want to pass to teh callback function. the
1068 * callback can later pick it up from di->levels
1070 * See packet-dcerpc-samr.c for examples
1073 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1074 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1075 int type, char *text, int hf_index, int levels)
1079 di=pinfo->private_data;
1080 if(di->conformant_run){
1081 /* this call was only for dissecting the header for any
1082 embedded conformant array. we will not parse any
1083 pointers in this mode.
1088 /*TOP LEVEL REFERENCE POINTER*/
1089 if( pointers_are_top_level
1090 &&(type==NDR_POINTER_REF) ){
1094 /* we must find out a nice way to do the length here */
1095 item=proto_tree_add_text(tree, tvb, offset, 0,
1097 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1099 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
1103 /*TOP LEVEL FULL POINTER*/
1104 if( pointers_are_top_level
1105 && (type==NDR_POINTER_PTR) ){
1111 /* get the referent id */
1112 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1114 /* we got a NULL pointer */
1116 proto_tree_add_text(tree, tvb, offset-4, 4,
1117 "(NULL pointer) %s",text);
1121 /* see if we have seen this pointer before */
1122 idx=find_pointer_index(id);
1124 /* we have seen this pointer before */
1126 proto_tree_add_text(tree, tvb, offset-4, 4,
1127 "(duplicate PTR) %s",text);
1132 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1134 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1135 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1136 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
1139 /*TOP LEVEL UNIQUE POINTER*/
1140 if( pointers_are_top_level
1141 && (type==NDR_POINTER_UNIQUE) ){
1146 /* get the referent id */
1147 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1149 /* we got a NULL pointer */
1151 proto_tree_add_text(tree, tvb, offset-4, 4,
1152 "(NULL pointer) %s",text);
1157 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1159 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1160 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1161 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
1165 /*EMBEDDED REFERENCE POINTER*/
1166 if( (!pointers_are_top_level)
1167 && (type==NDR_POINTER_REF) ){
1172 /* get the referent id */
1173 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1176 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1178 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1179 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1180 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
1184 /*EMBEDDED UNIQUE POINTER*/
1185 if( (!pointers_are_top_level)
1186 && (type==NDR_POINTER_UNIQUE) ){
1191 /* get the referent id */
1192 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1194 /* we got a NULL pointer */
1196 proto_tree_add_text(tree, tvb, offset-4, 4,
1197 "(NULL pointer) %s", text);
1202 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1204 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1205 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1206 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
1210 /*EMBEDDED FULL POINTER*/
1211 if( (!pointers_are_top_level)
1212 && (type==NDR_POINTER_PTR) ){
1218 /* get the referent id */
1219 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1221 /* we got a NULL pointer */
1223 proto_tree_add_text(tree, tvb, offset-4, 4,
1224 "(NULL pointer) %s",text);
1228 /* see if we have seen this pointer before */
1229 idx=find_pointer_index(id);
1231 /* we have seen this pointer before */
1233 proto_tree_add_text(tree, tvb, offset-4, 4,
1234 "(duplicate PTR) %s",text);
1239 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1241 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1242 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1243 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
1249 /* After each top level pointer we have dissected we have to
1250 dissect all deferrals before we move on to the next top level
1252 if(pointers_are_top_level==TRUE){
1253 pointers_are_top_level=FALSE;
1254 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
1255 pointers_are_top_level=TRUE;
1264 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
1265 proto_tree *dcerpc_tree,
1266 tvbuff_t *tvb, gint offset,
1267 char *drep, dcerpc_info *info,
1270 dcerpc_uuid_key key;
1271 dcerpc_uuid_value *sub_proto;
1273 proto_tree *sub_tree = NULL;
1274 dcerpc_sub_dissector *proc;
1276 dcerpc_dissect_fnct_t *sub_dissect;
1277 const char *saved_proto;
1278 void *saved_private_data;
1280 key.uuid = info->call_data->uuid;
1281 key.ver = info->call_data->ver;
1284 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1285 || !proto_is_protocol_enabled(sub_proto->proto)) {
1287 * We don't have a dissector for this UUID, or the protocol
1288 * for that UUID is disabled.
1290 length = tvb_length_remaining (tvb, offset);
1292 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
1293 "Stub data (%d byte%s)", length,
1294 plurality(length, "", "s"));
1299 for (proc = sub_proto->procs; proc->name; proc++) {
1300 if (proc->num == info->call_data->opnum) {
1309 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1310 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1313 if (check_col (pinfo->cinfo, COL_INFO)) {
1314 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1315 name, info->request ? "request" : "reply");
1319 proto_item *sub_item;
1320 sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
1324 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1328 * Put the operation number into the tree along with
1329 * the operation's name.
1332 if (sub_proto->opnum_hf != -1)
1333 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
1334 tvb, 0, 0, info->call_data->opnum,
1335 "Operation: %s (%u)",
1336 name, info->call_data->opnum);
1338 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
1339 0, 0, info->call_data->opnum,
1340 "Operation: %s (%u)",
1341 name, info->call_data->opnum);
1345 * If the authentication level is DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
1346 * the stub data is encrypted, and we can't dissect it.
1348 if (auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1349 length = tvb_length_remaining (tvb, offset);
1351 proto_tree_add_text(sub_tree, tvb, offset, length,
1352 "Encrypted stub data (%d byte%s)",
1353 length, plurality(length, "", "s"));
1356 sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
1358 saved_proto = pinfo->current_proto;
1359 saved_private_data = pinfo->private_data;
1360 pinfo->current_proto = sub_proto->name;
1361 pinfo->private_data = (void *)info;
1363 init_ndr_pointer_list(pinfo);
1364 offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
1366 pinfo->current_proto = saved_proto;
1367 pinfo->private_data = saved_private_data;
1369 length = tvb_length_remaining (tvb, offset);
1371 proto_tree_add_text (sub_tree, tvb, offset, length,
1372 "Stub data (%d byte%s)", length,
1373 plurality(length, "", "s"));
1381 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1382 e_dce_cn_common_hdr_t *hdr, int *auth_level_p)
1385 guint8 auth_pad_len;
1390 * Initially set "*auth_level_p" to -1 to indicate that we haven't
1391 * yet seen any authentication level information.
1393 if (auth_level_p != NULL)
1397 * The authentication information is at the *end* of the PDU; in
1398 * request and response PDUs, the request and response stub data
1401 * If the full packet is here, and we've got an auth len, and it's
1402 * valid, then dissect the auth info.
1404 if (tvb_length (tvb) >= hdr->frag_len
1406 && (hdr->auth_len + 8 <= hdr->frag_len)) {
1408 offset = hdr->frag_len - (hdr->auth_len + 8);
1410 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1411 hf_dcerpc_auth_type, &auth_type);
1412 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1413 hf_dcerpc_auth_level, &auth_level);
1414 if (auth_level_p != NULL)
1415 *auth_level_p = auth_level;
1416 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1417 hf_dcerpc_auth_pad_len, &auth_pad_len);
1418 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1419 hf_dcerpc_auth_rsrvd, NULL);
1420 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1421 hf_dcerpc_auth_ctx_id, NULL);
1423 /* Dissect the authentication data */
1429 case DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP: {
1430 tvbuff_t *ntlmssp_tvb;
1432 ntlmssp_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
1435 call_dissector(ntlmssp_handle, ntlmssp_tvb, pinfo,
1441 /* SPNEGO (rfc2478) */
1443 case DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO: {
1444 tvbuff_t *gssapi_tvb;
1446 gssapi_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
1449 call_dissector(gssapi_handle, gssapi_tvb, pinfo, dcerpc_tree);
1455 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
1459 /* figure out where the auth padding starts */
1460 offset = hdr->frag_len - (hdr->auth_len + 8 + auth_pad_len);
1461 if (offset > 0 && auth_pad_len) {
1462 proto_tree_add_text (dcerpc_tree, tvb, offset,
1463 auth_pad_len, "Auth padding");
1464 return hdr->auth_len + 8 + auth_pad_len;
1466 return hdr->auth_len + 8;
1474 /* We need to hash in the SMB fid number to generate a unique hash table
1475 key as DCERPC over SMB allows several pipes over the same TCP/IP
1478 static guint16 get_smb_fid (void *private_data)
1480 dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
1483 return 0; /* Nothing to see here */
1485 /* DCERPC over smb */
1487 if (priv->transport_type == DCERPC_TRANSPORT_SMB)
1488 return priv->data.smb.fid;
1490 /* Some other transport... */
1496 * Connection oriented packet types
1500 dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1501 e_dce_cn_common_hdr_t *hdr)
1503 conversation_t *conv = NULL;
1504 guint8 num_ctx_items;
1506 gboolean saw_ctx_item = FALSE;
1508 guint16 num_trans_items;
1513 guint16 if_ver, if_ver_minor;
1516 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1517 hf_dcerpc_cn_max_xmit, NULL);
1519 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1520 hf_dcerpc_cn_max_recv, NULL);
1522 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1523 hf_dcerpc_cn_assoc_group, NULL);
1525 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1526 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
1531 for (i = 0; i < num_ctx_items; i++) {
1532 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1533 hf_dcerpc_cn_ctx_id, &ctx_id);
1535 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1536 hf_dcerpc_cn_num_trans_items, &num_trans_items);
1538 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
1540 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
1542 "Interface UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1543 if_id.Data1, if_id.Data2, if_id.Data3,
1544 if_id.Data4[0], if_id.Data4[1],
1545 if_id.Data4[2], if_id.Data4[3],
1546 if_id.Data4[4], if_id.Data4[5],
1547 if_id.Data4[6], if_id.Data4[7]);
1551 if (hdr->drep[0] & 0x10) {
1552 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1553 hf_dcerpc_cn_bind_if_ver, &if_ver);
1554 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1555 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1557 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1558 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1559 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1560 hf_dcerpc_cn_bind_if_ver, &if_ver);
1563 if (!saw_ctx_item) {
1564 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1565 pinfo->srcport, pinfo->destport, 0);
1567 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
1568 pinfo->srcport, pinfo->destport, 0);
1571 /* if this is the first time we see this packet, we need to
1572 update the dcerpc_binds table so that any later calls can
1573 match to the interface.
1574 XXX We assume that BINDs will NEVER be fragmented.
1576 if(!(pinfo->fd->flags.visited)){
1577 dcerpc_bind_key *key;
1578 dcerpc_bind_value *value;
1580 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
1582 key->ctx_id = ctx_id;
1583 key->smb_fid = get_smb_fid(pinfo->private_data);
1585 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
1586 value->uuid = if_id;
1587 value->ver = if_ver;
1589 /* add this entry to the bind table, first removing any
1590 previous ones that are identical
1592 if(g_hash_table_lookup(dcerpc_binds, key)){
1593 g_hash_table_remove(dcerpc_binds, key);
1595 g_hash_table_insert (dcerpc_binds, key, value);
1598 if (check_col (pinfo->cinfo, COL_INFO)) {
1599 dcerpc_uuid_key key;
1600 dcerpc_uuid_value *value;
1605 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
1606 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
1608 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
1609 if_id.Data1, if_id.Data2, if_id.Data3,
1610 if_id.Data4[0], if_id.Data4[1],
1611 if_id.Data4[2], if_id.Data4[3],
1612 if_id.Data4[4], if_id.Data4[5],
1613 if_id.Data4[6], if_id.Data4[7],
1614 if_ver, if_ver_minor);
1616 saw_ctx_item = TRUE;
1619 for (j = 0; j < num_trans_items; j++) {
1620 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1622 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb,
1624 "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1625 trans_id.Data1, trans_id.Data2, trans_id.Data3,
1626 trans_id.Data4[0], trans_id.Data4[1],
1627 trans_id.Data4[2], trans_id.Data4[3],
1628 trans_id.Data4[4], trans_id.Data4[5],
1629 trans_id.Data4[6], trans_id.Data4[7]);
1633 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1634 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
1639 * XXX - we should save the authentication type *if* we have
1640 * an authentication header, and associate it with an authentication
1641 * context, so subsequent PDUs can use that context.
1643 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, NULL);
1647 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1648 e_dce_cn_common_hdr_t *hdr)
1650 guint16 max_xmit, max_recv;
1651 guint16 sec_addr_len;
1661 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1662 hf_dcerpc_cn_max_xmit, &max_xmit);
1664 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1665 hf_dcerpc_cn_max_recv, &max_recv);
1667 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1668 hf_dcerpc_cn_assoc_group, NULL);
1670 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1671 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
1672 if (sec_addr_len != 0) {
1673 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
1674 sec_addr_len, FALSE);
1675 offset += sec_addr_len;
1679 offset += 4 - offset % 4;
1682 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1683 hf_dcerpc_cn_num_results, &num_results);
1688 for (i = 0; i < num_results; i++) {
1689 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
1690 hdr->drep, hf_dcerpc_cn_ack_result,
1693 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
1694 hdr->drep, hf_dcerpc_cn_ack_reason,
1698 * The reason for rejection isn't meaningful, and often isn't
1699 * set, when the syntax was accepted.
1704 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1706 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
1708 "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1709 trans_id.Data1, trans_id.Data2, trans_id.Data3,
1710 trans_id.Data4[0], trans_id.Data4[1],
1711 trans_id.Data4[2], trans_id.Data4[3],
1712 trans_id.Data4[4], trans_id.Data4[5],
1713 trans_id.Data4[6], trans_id.Data4[7]);
1717 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1718 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
1722 * XXX - do we need to do anything with the authentication level
1723 * we get back from this?
1725 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, NULL);
1727 if (check_col (pinfo->cinfo, COL_INFO)) {
1728 if (num_results != 0 && result == 0) {
1729 /* XXX - only checks the last result */
1730 col_append_fstr (pinfo->cinfo, COL_INFO,
1731 " accept max_xmit: %u max_recv: %u",
1732 max_xmit, max_recv);
1734 /* XXX - only shows the last result and reason */
1735 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
1736 val_to_str(result, p_cont_result_vals,
1737 "Unknown result (%u)"),
1738 val_to_str(reason, p_provider_reason_vals,
1745 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1746 e_dce_cn_common_hdr_t *hdr)
1749 guint8 num_protocols;
1754 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
1755 hdr->drep, hf_dcerpc_cn_reject_reason,
1758 if (check_col (pinfo->cinfo, COL_INFO)) {
1759 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
1760 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
1763 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
1764 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1765 hf_dcerpc_cn_num_protocols,
1768 for (i = 0; i < num_protocols; i++) {
1769 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
1770 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
1772 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
1773 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
1780 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
1781 proto_tree *dcerpc_tree, proto_tree *tree,
1782 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
1783 int auth_sz, int auth_level, guint32 alloc_hint,
1786 int length, reported_length, stub_length;
1787 gboolean save_fragmented;
1789 length = tvb_length_remaining(tvb, offset);
1790 reported_length = tvb_reported_length_remaining(tvb, offset);
1791 stub_length = hdr->frag_len - offset - auth_sz;
1792 if (length > stub_length)
1793 length = stub_length;
1794 if (reported_length > stub_length)
1795 reported_length = stub_length;
1797 save_fragmented = pinfo->fragmented;
1799 /* If we don't have reassembly enabled, or this packet contains
1800 the entire PDU, or if this is a short frame (or a frame
1801 not reassembled at a lower layer) that doesn't include all
1802 the data in the fragment, just call the handoff directly if
1803 this is the first fragment or the PDU isn't fragmented. */
1804 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
1805 stub_length > length ){
1806 if(hdr->flags&PFC_FIRST_FRAG){
1807 /* First fragment, possibly the only fragment */
1808 pinfo->fragmented = !PFC_NOT_FRAGMENTED(hdr);
1809 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1810 tvb_new_subset (tvb, offset, length,
1812 0, hdr->drep, di, auth_level);
1814 /* PDU is fragmented and this isn't the first fragment */
1815 if (check_col(pinfo->cinfo, COL_INFO)) {
1816 col_append_fstr(pinfo->cinfo, COL_INFO,
1817 " [DCE/RPC fragment]");
1821 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
1822 "Fragment data (%d byte%s)", length,
1823 plurality(length, "", "s"));
1828 /* Reassembly is enabled, the PDU is fragmented, and
1829 we have all the data in the fragment; the first two
1830 of those mean we should attempt reassembly, and the
1831 third means we can attempt reassembly. */
1834 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
1835 "Fragment data (%d byte%s)", length,
1836 plurality(length, "", "s"));
1839 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
1840 if( (!pinfo->fd->flags.visited) && frame){
1841 fragment_add(tvb, offset, pinfo, frame,
1842 dcerpc_co_reassemble_table,
1846 fragment_set_tot_len(pinfo, frame,
1847 dcerpc_co_reassemble_table, alloc_hint);
1849 if (check_col(pinfo->cinfo, COL_INFO)) {
1850 col_append_fstr(pinfo->cinfo, COL_INFO,
1851 " [DCE/RPC fragment]");
1853 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
1855 fragment_data *fd_head;
1858 tot_len = fragment_get_tot_len(pinfo, frame,
1859 dcerpc_co_reassemble_table);
1860 fd_head = fragment_add(tvb, offset, pinfo,
1862 dcerpc_co_reassemble_table,
1868 /* We completed reassembly */
1871 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
1872 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1873 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
1874 show_fragment_tree(fd_head, &dcerpc_frag_items,
1875 dcerpc_tree, pinfo, next_tvb);
1877 pinfo->fragmented = FALSE;
1878 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
1879 0, hdr->drep, di, auth_level);
1881 /* Reassembly not complete - some fragments
1883 if (check_col(pinfo->cinfo, COL_INFO)) {
1884 col_append_fstr(pinfo->cinfo, COL_INFO,
1885 " [DCE/RPC fragment]");
1889 } else { /* MIDDLE fragment(s) */
1890 if( (!pinfo->fd->flags.visited) && frame ){
1892 tot_len = fragment_get_tot_len(pinfo, frame,
1893 dcerpc_co_reassemble_table);
1894 fragment_add(tvb, offset, pinfo, frame,
1895 dcerpc_co_reassemble_table,
1900 if (check_col(pinfo->cinfo, COL_INFO)) {
1901 col_append_fstr(pinfo->cinfo, COL_INFO,
1902 " [DCE/RPC fragment]");
1906 pinfo->fragmented = save_fragmented;
1910 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1911 proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
1913 conversation_t *conv;
1923 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1924 hf_dcerpc_cn_alloc_hint, &alloc_hint);
1926 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1927 hf_dcerpc_cn_ctx_id, &ctx_id);
1929 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1930 hf_dcerpc_opnum, &opnum);
1932 if (check_col (pinfo->cinfo, COL_INFO)) {
1933 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
1937 if (hdr->flags & PFC_OBJECT_UUID) {
1938 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
1940 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
1942 "Object UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1943 obj_id.Data1, obj_id.Data2, obj_id.Data3,
1957 * XXX - what if this was set when the connection was set up,
1958 * and we just have a security context?
1960 auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
1963 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1964 pinfo->srcport, pinfo->destport, 0);
1968 dcerpc_call_value *value;
1970 /* !!! we can NOT check flags.visited here since this will interact
1971 badly with when SMB handles (i.e. calls the subdissector)
1972 and desegmented pdu's .
1973 Instead we check if this pdu is already in the matched table or not
1975 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
1976 dcerpc_bind_key bind_key;
1977 dcerpc_bind_value *bind_value;
1980 bind_key.ctx_id=ctx_id;
1981 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
1983 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key))){
1984 dcerpc_call_key *call_key;
1985 dcerpc_call_value *call_value;
1987 /* We found the binding so just add the call
1988 to both the call table and the matched table
1990 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
1991 call_key->conv=conv;
1992 call_key->call_id=hdr->call_id;
1993 call_key->smb_fid=get_smb_fid(pinfo->private_data);
1995 /* if there is already a matching call in the table
1996 remove it so it is replaced with the new one */
1997 if(g_hash_table_lookup(dcerpc_calls, call_key)){
1998 g_hash_table_remove(dcerpc_calls, call_key);
2001 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2002 call_value->uuid = bind_value->uuid;
2003 call_value->ver = bind_value->ver;
2004 call_value->opnum = opnum;
2005 call_value->req_frame=pinfo->fd->num;
2006 call_value->rep_frame=0;
2007 call_value->max_ptr=0;
2008 call_value->private_data = NULL;
2009 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2011 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2015 value=g_hash_table_lookup (dcerpc_matched, (void *)pinfo->fd->num);
2020 /* handoff this call */
2022 di.call_id = hdr->call_id;
2023 di.smb_fid = get_smb_fid(pinfo->private_data);
2025 di.call_data = value;
2027 if(value->rep_frame!=0){
2028 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
2029 tvb, 0, 0, value->rep_frame);
2032 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2033 hdr, &di, auth_sz, auth_level, alloc_hint,
2036 length = tvb_length_remaining (tvb, offset);
2038 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2039 "Stub data (%d byte%s)", length,
2040 plurality(length, "", "s"));
2047 dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
2048 proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2050 dcerpc_call_value *value = NULL;
2051 conversation_t *conv;
2059 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2060 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2062 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2063 hf_dcerpc_cn_ctx_id, &ctx_id);
2065 if (check_col (pinfo->cinfo, COL_INFO)) {
2066 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
2069 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2070 hf_dcerpc_cn_cancel_count, NULL);
2075 * XXX - what if this was set when the connection was set up,
2076 * and we just have a security context?
2078 auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
2081 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2082 pinfo->srcport, pinfo->destport, 0);
2084 /* no point in creating one here, really */
2087 /* !!! we can NOT check flags.visited here since this will interact
2088 badly with when SMB handles (i.e. calls the subdissector)
2089 and desegmented pdu's .
2090 Instead we check if this pdu is already in the matched table or not
2092 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
2093 dcerpc_call_key call_key;
2094 dcerpc_call_value *call_value;
2097 call_key.call_id=hdr->call_id;
2098 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2100 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2101 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2102 if(call_value->rep_frame==0){
2103 call_value->rep_frame=pinfo->fd->num;
2109 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2114 /* handoff this call */
2116 di.call_id = hdr->call_id;
2117 di.smb_fid = get_smb_fid(pinfo->private_data);
2119 di.call_data = value;
2121 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2122 if(value->req_frame!=0){
2123 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2124 tvb, 0, 0, value->req_frame);
2127 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2128 hdr, &di, auth_sz, auth_level, alloc_hint,
2131 length = tvb_length_remaining (tvb, offset);
2133 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2134 "Stub data (%d byte%s)", length,
2135 plurality(length, "", "s"));
2142 dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo,
2143 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2145 dcerpc_call_value *value = NULL;
2146 conversation_t *conv;
2154 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2155 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2157 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2158 hf_dcerpc_cn_ctx_id, &ctx_id);
2160 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2161 hf_dcerpc_cn_cancel_count, NULL);
2165 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2166 hf_dcerpc_cn_status, &status);
2168 if (check_col (pinfo->cinfo, COL_INFO)) {
2169 col_append_fstr (pinfo->cinfo, COL_INFO,
2170 " ctx_id: %u status: %s", ctx_id,
2171 val_to_str(status, reject_status_vals,
2172 "Unknown (0x%08x)"));
2179 * XXX - what if this was set when the connection was set up,
2180 * and we just have a security context?
2182 auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
2185 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2186 pinfo->srcport, pinfo->destport, 0);
2188 /* no point in creating one here, really */
2191 /* !!! we can NOT check flags.visited here since this will interact
2192 badly with when SMB handles (i.e. calls the subdissector)
2193 and desegmented pdu's .
2194 Instead we check if this pdu is already in the matched table or not
2196 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
2197 dcerpc_call_key call_key;
2198 dcerpc_call_value *call_value;
2201 call_key.call_id=hdr->call_id;
2202 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2204 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2205 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2206 if(call_value->rep_frame==0){
2207 call_value->rep_frame=pinfo->fd->num;
2213 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2216 int length, reported_length, stub_length;
2219 /* handoff this call */
2221 di.call_id = hdr->call_id;
2222 di.smb_fid = get_smb_fid(pinfo->private_data);
2224 di.call_data = value;
2226 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2227 if(value->req_frame!=0){
2228 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2229 tvb, 0, 0, value->req_frame);
2232 length = tvb_length_remaining(tvb, offset);
2233 reported_length = tvb_reported_length_remaining(tvb, offset);
2234 stub_length = hdr->frag_len - offset - auth_sz;
2235 if (length > stub_length)
2236 length = stub_length;
2237 if (reported_length > stub_length)
2238 reported_length = stub_length;
2240 /* If we don't have reassembly enabled, or this packet contains
2241 the entire PDU, or if this is a short frame (or a frame
2242 not reassembled at a lower layer) that doesn't include all
2243 the data in the fragment, just call the handoff directly if
2244 this is the first fragment or the PDU isn't fragmented. */
2245 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
2246 stub_length > length ){
2247 if(hdr->flags&PFC_FIRST_FRAG){
2248 /* First fragment, possibly the only fragment */
2250 * XXX - should there be a third routine for each
2251 * function in an RPC subdissector, to handle
2252 * fault responses? The DCE RPC 1.1 spec says
2253 * three's "stub data" here, which I infer means
2254 * that it's protocol-specific and call-specific.
2256 * It should probably get passed the status code
2257 * as well, as that might be protocol-specific.
2261 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2262 "Fault stub data (%d byte%s)", length,
2263 plurality(length, "", "s"));
2267 /* PDU is fragmented and this isn't the first fragment */
2268 if (check_col(pinfo->cinfo, COL_INFO)) {
2269 col_append_fstr(pinfo->cinfo, COL_INFO,
2270 " [DCE/RPC fragment]");
2274 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2275 "Fragment data (%d byte%s)", length,
2276 plurality(length, "", "s"));
2281 /* Reassembly is enabled, the PDU is fragmented, and
2282 we have all the data in the fragment; the first two
2283 of those mean we should attempt reassembly, and the
2284 third means we can attempt reassembly. */
2287 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2288 "Fragment data (%d byte%s)", length,
2289 plurality(length, "", "s"));
2292 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
2293 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2294 fragment_add(tvb, offset, pinfo, value->rep_frame,
2295 dcerpc_co_reassemble_table,
2299 fragment_set_tot_len(pinfo, value->rep_frame,
2300 dcerpc_co_reassemble_table, alloc_hint);
2302 if (check_col(pinfo->cinfo, COL_INFO)) {
2303 col_append_fstr(pinfo->cinfo, COL_INFO,
2304 " [DCE/RPC fragment]");
2306 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
2307 if( value->rep_frame ){
2308 fragment_data *fd_head;
2311 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2312 dcerpc_co_reassemble_table);
2313 fd_head = fragment_add(tvb, offset, pinfo,
2315 dcerpc_co_reassemble_table,
2321 /* We completed reassembly */
2324 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2325 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2326 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2327 show_fragment_tree(fd_head, &dcerpc_frag_items,
2328 dcerpc_tree, pinfo, next_tvb);
2331 * XXX - should there be a third routine for each
2332 * function in an RPC subdissector, to handle
2333 * fault responses? The DCE RPC 1.1 spec says
2334 * three's "stub data" here, which I infer means
2335 * that it's protocol-specific and call-specific.
2337 * It should probably get passed the status code
2338 * as well, as that might be protocol-specific.
2342 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2343 "Fault stub data (%d byte%s)", length,
2344 plurality(length, "", "s"));
2348 /* Reassembly not complete - some fragments
2350 if (check_col(pinfo->cinfo, COL_INFO)) {
2351 col_append_fstr(pinfo->cinfo, COL_INFO,
2352 " [DCE/RPC fragment]");
2356 } else { /* MIDDLE fragment(s) */
2357 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2359 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2360 dcerpc_co_reassemble_table);
2361 fragment_add(tvb, offset, pinfo, value->rep_frame,
2362 dcerpc_co_reassemble_table,
2367 if (check_col(pinfo->cinfo, COL_INFO)) {
2368 col_append_fstr(pinfo->cinfo, COL_INFO,
2369 " [DCE/RPC fragment]");
2378 * DCERPC dissector for connection oriented calls
2381 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
2382 proto_tree *tree, gboolean can_desegment)
2384 static char nulls[4] = { 0 };
2387 proto_item *ti = NULL;
2388 proto_item *tf = NULL;
2389 proto_tree *dcerpc_tree = NULL;
2390 proto_tree *cn_flags_tree = NULL;
2391 proto_tree *drep_tree = NULL;
2392 e_dce_cn_common_hdr_t hdr;
2395 * when done over nbt, dcerpc requests are padded with 4 bytes of null
2396 * data for some reason.
2398 * XXX - if that's always the case, the right way to do this would
2399 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
2400 * the 4 bytes of null padding, and make that the dissector
2401 * used for "netbios".
2403 if (tvb_bytes_exist (tvb, offset, 4) &&
2404 tvb_memeql (tvb, offset, nulls, 4) == 0) {
2414 * Check if this looks like a C/O DCERPC call
2416 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
2419 start_offset = offset;
2420 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
2421 if (hdr.rpc_ver != 5)
2423 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
2424 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
2426 hdr.ptype = tvb_get_guint8 (tvb, offset++);
2430 if (check_col (pinfo->cinfo, COL_PROTOCOL))
2431 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
2432 if (check_col (pinfo->cinfo, COL_INFO))
2433 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
2435 hdr.flags = tvb_get_guint8 (tvb, offset++);
2436 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
2437 offset += sizeof (hdr.drep);
2439 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2441 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2443 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
2446 offset = start_offset;
2447 if (can_desegment && pinfo->can_desegment
2448 && hdr.frag_len > tvb_length_remaining (tvb, offset)) {
2449 pinfo->desegment_offset = offset;
2450 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, offset);
2451 return 0; /* desegmentation required */
2454 if (check_col (pinfo->cinfo, COL_INFO))
2455 col_append_fstr (pinfo->cinfo, COL_INFO, ": call_id: %u", hdr.call_id);
2457 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
2459 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
2461 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
2462 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
2463 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
2464 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
2465 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
2466 if (cn_flags_tree) {
2467 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
2468 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
2469 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
2470 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
2471 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
2472 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
2473 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
2474 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
2478 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
2479 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
2481 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
2482 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
2483 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
2485 offset += sizeof (hdr.drep);
2487 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
2490 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
2493 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
2499 * Packet type specific stuff is next.
2501 switch (hdr.ptype) {
2504 dissect_dcerpc_cn_bind (tvb, pinfo, dcerpc_tree, &hdr);
2509 dissect_dcerpc_cn_bind_ack (tvb, pinfo, dcerpc_tree, &hdr);
2513 dissect_dcerpc_cn_rqst (tvb, pinfo, dcerpc_tree, tree, &hdr);
2517 dissect_dcerpc_cn_resp (tvb, pinfo, dcerpc_tree, tree, &hdr);
2521 dissect_dcerpc_cn_fault (tvb, pinfo, dcerpc_tree, &hdr);
2525 dissect_dcerpc_cn_bind_nak (tvb, pinfo, dcerpc_tree, &hdr);
2531 * Nothing after the common header other than an authentication
2534 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, NULL);
2539 * Nothing after the common header, not even an authentication
2545 /* might as well dissect the auth info */
2546 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, NULL);
2549 return hdr.frag_len + padding;
2553 * DCERPC dissector for connection oriented calls over packet-oriented
2557 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2560 * Only one PDU per transport packet, and only one transport
2563 if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
2565 * It wasn't a DCERPC PDU.
2577 * DCERPC dissector for connection oriented calls over byte-stream
2581 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2585 gboolean ret = FALSE;
2588 * There may be multiple PDUs per transport packet; keep
2591 while (tvb_reported_length_remaining(tvb, offset) != 0) {
2592 pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
2593 dcerpc_cn_desegment);
2594 if (pdu_len == -1) {
2602 * Well, we've seen at least one DCERPC PDU.
2608 * Desegmentation required - bail now.
2614 * Step to the next PDU.
2622 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
2623 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
2625 proto_item *ti = NULL;
2626 proto_tree *auth_tree = NULL;
2627 guint8 protection_level;
2630 * Initially set "*auth_level_p" to -1 to indicate that we haven't
2631 * yet seen any authentication level information.
2633 if (auth_level_p != NULL)
2637 * The authentication information is at the *end* of the PDU; in
2638 * request and response PDUs, the request and response stub data
2641 * If the full packet is here, and there's data past the end of the
2642 * packet body, then dissect the auth info.
2644 offset += hdr->frag_len;
2645 if (tvb_length_remaining(tvb, offset) > 0) {
2646 switch (hdr->auth_proto) {
2648 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
2649 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
2650 auth_tree = proto_item_add_subtree (ti, ett_decrpc_krb5_auth_verf);
2651 protection_level = tvb_get_guint8 (tvb, offset);
2652 if (auth_level_p != NULL)
2653 *auth_level_p = protection_level;
2654 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
2656 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
2658 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
2659 offset += 6; /* 6 bytes of padding */
2661 offset += 2; /* 6 bytes of padding */
2662 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
2667 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
2674 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
2675 proto_tree *dcerpc_tree,
2676 e_dce_dg_common_hdr_t *hdr)
2680 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2681 hdr->drep, hf_dcerpc_dg_cancel_vers,
2687 /* The only version we know about */
2688 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2689 hdr->drep, hf_dcerpc_dg_cancel_id,
2691 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2692 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
2699 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
2700 proto_tree *dcerpc_tree,
2701 e_dce_dg_common_hdr_t *hdr)
2705 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2706 hdr->drep, hf_dcerpc_dg_cancel_vers,
2712 /* The only version we know about */
2713 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2714 hdr->drep, hf_dcerpc_dg_cancel_id,
2716 /* XXX - are NDR booleans 32 bits? */
2717 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2718 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
2725 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
2726 proto_tree *dcerpc_tree,
2727 e_dce_dg_common_hdr_t *hdr)
2734 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2735 hdr->drep, hf_dcerpc_dg_fack_vers,
2742 case 0: /* The only version documented in the DCE RPC 1.1 spec */
2743 case 1: /* This appears to be the same */
2744 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2745 hdr->drep, hf_dcerpc_dg_fack_window_size,
2747 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2748 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
2750 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2751 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
2753 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2754 hdr->drep, hf_dcerpc_dg_fack_serial_num,
2756 if (check_col (pinfo->cinfo, COL_INFO)) {
2757 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
2760 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2761 hdr->drep, hf_dcerpc_dg_fack_selack_len,
2763 for (i = 0; i < selack_len; i++) {
2764 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2765 hdr->drep, hf_dcerpc_dg_fack_selack,
2774 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
2775 proto_tree *dcerpc_tree,
2776 e_dce_dg_common_hdr_t *hdr)
2780 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2781 hdr->drep, hf_dcerpc_dg_status,
2784 if (check_col (pinfo->cinfo, COL_INFO)) {
2785 col_append_fstr (pinfo->cinfo, COL_INFO,
2787 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
2792 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2793 proto_tree *dcerpc_tree, proto_tree *tree,
2794 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
2796 int length, reported_length, stub_length;
2797 gboolean save_fragmented;
2798 fragment_data *fd_head;
2800 if (check_col (pinfo->cinfo, COL_INFO)) {
2801 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u",
2802 di->call_data->opnum);
2805 length = tvb_length_remaining (tvb, offset);
2806 reported_length = tvb_reported_length_remaining (tvb, offset);
2807 stub_length = hdr->frag_len;
2808 if (length > stub_length)
2809 length = stub_length;
2810 if (reported_length > stub_length)
2811 reported_length = stub_length;
2813 save_fragmented = pinfo->fragmented;
2815 /* If we don't have reassembly enabled, or this packet contains
2816 the entire PDU, or if this is a short frame (or a frame
2817 not reassembled at a lower layer) that doesn't include all
2818 the data in the fragment, just call the handoff directly if
2819 this is the first fragment or the PDU isn't fragmented. */
2820 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
2821 stub_length > length ) {
2822 if(hdr->frag_num == 0) {
2823 /* First fragment, possibly the only fragment */
2826 * XXX - authentication level?
2828 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
2829 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2830 tvb_new_subset (tvb, offset, length,
2832 0, hdr->drep, di, 0);
2834 /* PDU is fragmented and this isn't the first fragment */
2835 if (check_col(pinfo->cinfo, COL_INFO)) {
2836 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
2840 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2841 "Fragment data (%d byte%s)", length,
2842 plurality(length, "", "s"));
2847 /* Reassembly is enabled, the PDU is fragmented, and
2848 we have all the data in the fragment; the first two
2849 of those mean we should attempt reassembly, and the
2850 third means we can attempt reassembly. */
2853 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2854 "Fragment data (%d byte%s)", length,
2855 plurality(length, "", "s"));
2859 fd_head = fragment_add_seq(tvb, offset, pinfo,
2860 hdr->seqnum, dcerpc_cl_reassemble_table,
2861 hdr->frag_num, length, !(hdr->flags1 & PFCL1_LASTFRAG));
2862 if (fd_head != NULL) {
2863 /* We completed reassembly */
2866 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
2867 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2868 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2869 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
2870 dcerpc_tree, pinfo, next_tvb);
2873 * XXX - authentication level?
2875 pinfo->fragmented = FALSE;
2876 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
2877 0, hdr->drep, di, 0);
2879 /* Reassembly isn't completed yet */
2880 if (check_col(pinfo->cinfo, COL_INFO)) {
2881 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
2885 pinfo->fragmented = save_fragmented;
2889 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
2890 proto_tree *dcerpc_tree, proto_tree *tree,
2891 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
2894 dcerpc_call_value *value, v;
2896 if(!(pinfo->fd->flags.visited)){
2897 dcerpc_call_value *call_value;
2898 dcerpc_call_key *call_key;
2900 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
2901 call_key->conv=conv;
2902 call_key->call_id=hdr->seqnum;
2903 call_key->smb_fid=get_smb_fid(pinfo->private_data);
2905 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2906 call_value->uuid = hdr->if_id;
2907 call_value->ver = hdr->if_ver;
2908 call_value->opnum = hdr->opnum;
2909 call_value->req_frame=pinfo->fd->num;
2910 call_value->rep_frame=0;
2911 call_value->max_ptr=0;
2912 call_value->private_data = NULL;
2913 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2915 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2918 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2920 v.uuid = hdr->if_id;
2921 v.ver = hdr->if_ver;
2922 v.opnum = hdr->opnum;
2923 v.req_frame = pinfo->fd->num;
2926 v.private_data=NULL;
2931 di.call_id = hdr->seqnum;
2934 di.call_data = value;
2936 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
2940 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
2941 proto_tree *dcerpc_tree, proto_tree *tree,
2942 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
2945 dcerpc_call_value *value, v;
2947 if(!(pinfo->fd->flags.visited)){
2948 dcerpc_call_value *call_value;
2949 dcerpc_call_key call_key;
2952 call_key.call_id=hdr->seqnum;
2953 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2955 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2956 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2957 if(call_value->rep_frame==0){
2958 call_value->rep_frame=pinfo->fd->num;
2963 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2965 v.uuid = hdr->if_id;
2966 v.ver = hdr->if_ver;
2967 v.opnum = hdr->opnum;
2969 v.rep_frame=pinfo->fd->num;
2970 v.private_data=NULL;
2978 di.call_data = value;
2980 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, &di);
2984 * DCERPC dissector for connectionless calls
2987 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2989 proto_item *ti = NULL;
2990 proto_item *tf = NULL;
2991 proto_tree *dcerpc_tree = NULL;
2992 proto_tree *dg_flags1_tree = NULL;
2993 proto_tree *dg_flags2_tree = NULL;
2994 proto_tree *drep_tree = NULL;
2995 e_dce_dg_common_hdr_t hdr;
2997 conversation_t *conv;
3001 * Check if this looks like a CL DCERPC call. All dg packets
3002 * have an 80 byte header on them. Which starts with
3003 * version (4), pkt_type.
3005 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
3008 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3009 if (hdr.rpc_ver != 4)
3011 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3015 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3016 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3017 if (check_col (pinfo->cinfo, COL_INFO))
3018 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
3020 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
3021 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
3022 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3023 offset += sizeof (hdr.drep);
3024 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
3025 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
3027 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
3029 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
3031 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3033 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3035 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3037 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3039 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3041 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3043 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3045 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3047 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
3048 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
3051 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
3053 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
3059 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3063 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3067 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
3068 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
3069 if (dg_flags1_tree) {
3070 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
3071 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
3072 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
3073 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
3074 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
3075 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
3076 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
3077 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
3083 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
3084 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
3085 if (dg_flags2_tree) {
3086 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
3087 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
3088 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
3089 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
3090 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
3091 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
3092 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
3093 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
3099 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
3100 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3102 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3103 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3104 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3107 offset += sizeof (hdr.drep);
3110 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
3114 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3116 "Object: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3117 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
3118 hdr.obj_id.Data4[0],
3119 hdr.obj_id.Data4[1],
3120 hdr.obj_id.Data4[2],
3121 hdr.obj_id.Data4[3],
3122 hdr.obj_id.Data4[4],
3123 hdr.obj_id.Data4[5],
3124 hdr.obj_id.Data4[6],
3125 hdr.obj_id.Data4[7]);
3130 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
3132 "Interface: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3133 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
3141 hdr.if_id.Data4[7]);
3146 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
3148 "Activity: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3149 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
3150 hdr.act_id.Data4[0],
3151 hdr.act_id.Data4[1],
3152 hdr.act_id.Data4[2],
3153 hdr.act_id.Data4[3],
3154 hdr.act_id.Data4[4],
3155 hdr.act_id.Data4[5],
3156 hdr.act_id.Data4[6],
3157 hdr.act_id.Data4[7]);
3162 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
3166 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
3170 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
3171 if (check_col (pinfo->cinfo, COL_INFO)) {
3172 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq_num: %u", hdr.seqnum);
3177 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
3181 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
3185 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
3189 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
3193 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
3194 if (check_col (pinfo->cinfo, COL_INFO)) {
3195 if (hdr.flags1 & PFCL1_FRAG) {
3196 /* Fragmented - put the fragment number into the Info column */
3197 col_append_fstr (pinfo->cinfo, COL_INFO, " frag_num: %u",
3204 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
3208 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
3209 if (check_col (pinfo->cinfo, COL_INFO)) {
3210 if (hdr.flags1 & PFCL1_FRAG) {
3211 /* Fragmented - put the serial number into the Info column */
3212 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3213 (hdr.serial_hi << 8) | hdr.serial_lo);
3220 * XXX - for Kerberos, we get a protection level; if it's
3221 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
3224 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
3229 * keeping track of the conversation shouldn't really be necessary
3230 * for connectionless packets, because everything we need to know
3231 * to dissect is in the header for each packet. Unfortunately,
3232 * Microsoft's implementation is buggy and often puts the
3233 * completely wrong if_id in the header. go figure. So, keep
3234 * track of the seqnum and use that if possible. Note: that's not
3235 * completely correct. It should really be done based on both the
3236 * activity_id and seqnum. I haven't seen anywhere that it would
3237 * make a difference, but for future reference...
3239 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
3240 pinfo->srcport, pinfo->destport, 0);
3242 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
3243 pinfo->srcport, pinfo->destport, 0);
3247 * Packet type specific stuff is next.
3250 switch (hdr.ptype) {
3252 case PDU_CANCEL_ACK:
3253 /* Body is optional */
3254 /* XXX - we assume "frag_len" is the length of the body */
3255 if (hdr.frag_len != 0)
3256 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3261 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
3262 * but in at least one capture none of the Cl_cancel PDUs had a
3265 /* XXX - we assume "frag_len" is the length of the body */
3266 if (hdr.frag_len != 0)
3267 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
3271 /* Body is optional; if present, it's the same as PDU_FACK */
3272 /* XXX - we assume "frag_len" is the length of the body */
3273 if (hdr.frag_len != 0)
3274 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3278 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3283 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3287 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
3291 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
3294 /* these requests have no body */
3306 dcerpc_init_protocol (void)
3308 /* structures and data for BIND */
3310 g_hash_table_destroy (dcerpc_binds);
3312 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
3314 if (dcerpc_bind_key_chunk){
3315 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
3317 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
3318 sizeof (dcerpc_bind_key),
3319 200 * sizeof (dcerpc_bind_key),
3321 if (dcerpc_bind_value_chunk){
3322 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
3324 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
3325 sizeof (dcerpc_bind_value),
3326 200 * sizeof (dcerpc_bind_value),
3328 /* structures and data for CALL */
3330 g_hash_table_destroy (dcerpc_calls);
3332 dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
3333 if (dcerpc_call_key_chunk){
3334 g_mem_chunk_destroy (dcerpc_call_key_chunk);
3336 dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
3337 sizeof (dcerpc_call_key),
3338 200 * sizeof (dcerpc_call_key),
3340 if (dcerpc_call_value_chunk){
3341 g_mem_chunk_destroy (dcerpc_call_value_chunk);
3343 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
3344 sizeof (dcerpc_call_value),
3345 200 * sizeof (dcerpc_call_value),
3348 /* structure and data for MATCHED */
3349 if (dcerpc_matched){
3350 g_hash_table_destroy (dcerpc_matched);
3352 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
3357 proto_register_dcerpc (void)
3359 static hf_register_info hf[] = {
3360 { &hf_dcerpc_request_in,
3361 { "Request in", "dcerpc.request_in", FT_UINT32, BASE_DEC,
3362 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
3363 { &hf_dcerpc_response_in,
3364 { "Response in", "dcerpc.response_in", FT_UINT32, BASE_DEC,
3365 NULL, 0, "The response to this packet is in this packet", HFILL }},
3366 { &hf_dcerpc_referent_id,
3367 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
3368 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
3370 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3371 { &hf_dcerpc_ver_minor,
3372 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3373 { &hf_dcerpc_packet_type,
3374 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
3375 { &hf_dcerpc_cn_flags,
3376 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3377 { &hf_dcerpc_cn_flags_first_frag,
3378 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
3379 { &hf_dcerpc_cn_flags_last_frag,
3380 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
3381 { &hf_dcerpc_cn_flags_cancel_pending,
3382 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
3383 { &hf_dcerpc_cn_flags_reserved,
3384 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
3385 { &hf_dcerpc_cn_flags_mpx,
3386 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
3387 { &hf_dcerpc_cn_flags_dne,
3388 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
3389 { &hf_dcerpc_cn_flags_maybe,
3390 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
3391 { &hf_dcerpc_cn_flags_object,
3392 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
3394 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
3395 { &hf_dcerpc_drep_byteorder,
3396 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
3397 { &hf_dcerpc_drep_character,
3398 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
3399 { &hf_dcerpc_drep_fp,
3400 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
3401 { &hf_dcerpc_cn_frag_len,
3402 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3403 { &hf_dcerpc_cn_auth_len,
3404 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3405 { &hf_dcerpc_cn_call_id,
3406 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3407 { &hf_dcerpc_cn_max_xmit,
3408 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3409 { &hf_dcerpc_cn_max_recv,
3410 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3411 { &hf_dcerpc_cn_assoc_group,
3412 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
3413 { &hf_dcerpc_cn_num_ctx_items,
3414 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3415 { &hf_dcerpc_cn_ctx_id,
3416 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3417 { &hf_dcerpc_cn_num_trans_items,
3418 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3419 { &hf_dcerpc_cn_bind_if_id,
3420 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3421 { &hf_dcerpc_cn_bind_if_ver,
3422 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3423 { &hf_dcerpc_cn_bind_if_ver_minor,
3424 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3425 { &hf_dcerpc_cn_bind_trans_id,
3426 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3427 { &hf_dcerpc_cn_bind_trans_ver,
3428 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3429 { &hf_dcerpc_cn_alloc_hint,
3430 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3431 { &hf_dcerpc_cn_sec_addr_len,
3432 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3433 { &hf_dcerpc_cn_sec_addr,
3434 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
3435 { &hf_dcerpc_cn_num_results,
3436 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3437 { &hf_dcerpc_cn_ack_result,
3438 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
3439 { &hf_dcerpc_cn_ack_reason,
3440 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
3441 { &hf_dcerpc_cn_ack_trans_id,
3442 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3443 { &hf_dcerpc_cn_ack_trans_ver,
3444 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3445 { &hf_dcerpc_cn_reject_reason,
3446 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
3447 { &hf_dcerpc_cn_num_protocols,
3448 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3449 { &hf_dcerpc_cn_protocol_ver_major,
3450 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3451 { &hf_dcerpc_cn_protocol_ver_minor,
3452 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3453 { &hf_dcerpc_cn_cancel_count,
3454 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3455 { &hf_dcerpc_cn_status,
3456 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
3457 { &hf_dcerpc_auth_type,
3458 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
3459 { &hf_dcerpc_auth_level,
3460 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
3461 { &hf_dcerpc_auth_pad_len,
3462 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3463 { &hf_dcerpc_auth_rsrvd,
3464 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3465 { &hf_dcerpc_auth_ctx_id,
3466 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3467 { &hf_dcerpc_dg_flags1,
3468 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3469 { &hf_dcerpc_dg_flags1_rsrvd_01,
3470 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
3471 { &hf_dcerpc_dg_flags1_last_frag,
3472 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
3473 { &hf_dcerpc_dg_flags1_frag,
3474 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
3475 { &hf_dcerpc_dg_flags1_nofack,
3476 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
3477 { &hf_dcerpc_dg_flags1_maybe,
3478 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
3479 { &hf_dcerpc_dg_flags1_idempotent,
3480 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
3481 { &hf_dcerpc_dg_flags1_broadcast,
3482 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
3483 { &hf_dcerpc_dg_flags1_rsrvd_80,
3484 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
3485 { &hf_dcerpc_dg_flags2,
3486 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3487 { &hf_dcerpc_dg_flags2_rsrvd_01,
3488 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
3489 { &hf_dcerpc_dg_flags2_cancel_pending,
3490 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
3491 { &hf_dcerpc_dg_flags2_rsrvd_04,
3492 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
3493 { &hf_dcerpc_dg_flags2_rsrvd_08,
3494 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
3495 { &hf_dcerpc_dg_flags2_rsrvd_10,
3496 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
3497 { &hf_dcerpc_dg_flags2_rsrvd_20,
3498 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
3499 { &hf_dcerpc_dg_flags2_rsrvd_40,
3500 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
3501 { &hf_dcerpc_dg_flags2_rsrvd_80,
3502 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
3503 { &hf_dcerpc_dg_serial_lo,
3504 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3505 { &hf_dcerpc_dg_serial_hi,
3506 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3507 { &hf_dcerpc_dg_ahint,
3508 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
3509 { &hf_dcerpc_dg_ihint,
3510 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
3511 { &hf_dcerpc_dg_frag_len,
3512 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3513 { &hf_dcerpc_dg_frag_num,
3514 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3515 { &hf_dcerpc_dg_auth_proto,
3516 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
3517 { &hf_dcerpc_dg_seqnum,
3518 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3519 { &hf_dcerpc_dg_server_boot,
3520 { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
3521 { &hf_dcerpc_dg_if_ver,
3522 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3523 { &hf_dcerpc_krb5_av_prot_level,
3524 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
3525 { &hf_dcerpc_krb5_av_key_vers_num,
3526 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3527 { &hf_dcerpc_krb5_av_key_auth_verifier,
3528 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
3529 { &hf_dcerpc_obj_id,
3530 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3531 { &hf_dcerpc_dg_if_id,
3532 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3533 { &hf_dcerpc_dg_act_id,
3534 { "Activitiy", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3536 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3538 { &hf_dcerpc_dg_cancel_vers,
3539 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3541 { &hf_dcerpc_dg_cancel_id,
3542 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3544 { &hf_dcerpc_dg_server_accepting_cancels,
3545 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
3547 { &hf_dcerpc_dg_fack_vers,
3548 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3550 { &hf_dcerpc_dg_fack_window_size,
3551 { "Window Size", "dcerpc.fack_window size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3553 { &hf_dcerpc_dg_fack_max_tsdu,
3554 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3556 { &hf_dcerpc_dg_fack_max_frag_size,
3557 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3559 { &hf_dcerpc_dg_fack_serial_num,
3560 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3562 { &hf_dcerpc_dg_fack_selack_len,
3563 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3565 { &hf_dcerpc_dg_fack_selack,
3566 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
3568 { &hf_dcerpc_dg_status,
3569 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
3571 { &hf_dcerpc_array_max_count,
3572 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
3574 { &hf_dcerpc_array_offset,
3575 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
3577 { &hf_dcerpc_array_actual_count,
3578 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
3581 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3583 { &hf_dcerpc_fragments,
3584 { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
3585 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
3587 { &hf_dcerpc_fragment,
3588 { "DCE/RPC Fragment", "dcerpc.fragment", FT_NONE, BASE_NONE,
3589 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
3591 { &hf_dcerpc_fragment_overlap,
3592 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
3594 { &hf_dcerpc_fragment_overlap_conflict,
3595 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
3597 { &hf_dcerpc_fragment_multiple_tails,
3598 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
3600 { &hf_dcerpc_fragment_too_long_fragment,
3601 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
3603 { &hf_dcerpc_fragment_error,
3604 { "Defragmentation error", "dcerpc.fragment.error", FT_NONE, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
3607 static gint *ett[] = {
3609 &ett_dcerpc_cn_flags,
3611 &ett_dcerpc_dg_flags1,
3612 &ett_dcerpc_dg_flags2,
3613 &ett_dcerpc_pointer_data,
3614 &ett_dcerpc_fragments,
3615 &ett_dcerpc_fragment,
3616 &ett_decrpc_krb5_auth_verf,
3618 module_t *dcerpc_module;
3620 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
3621 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
3622 proto_register_subtree_array (ett, array_length (ett));
3623 register_init_routine (dcerpc_init_protocol);
3624 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
3625 prefs_register_bool_preference (dcerpc_module,
3627 "Desegment all DCE/RPC over TCP",
3628 "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
3629 &dcerpc_cn_desegment);
3630 prefs_register_bool_preference (dcerpc_module,
3631 "reassemble_dcerpc",
3632 "Reassemble DCE/RPC fragments",
3633 "Whether the DCE/RPC dissector should reassemble all fragmented PDUs",
3634 &dcerpc_reassemble);
3635 register_init_routine(dcerpc_reassemble_init);
3636 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
3640 proto_reg_handoff_dcerpc (void)
3642 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
3643 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
3644 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
3645 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
3646 ntlmssp_handle = find_dissector("ntlmssp");
3647 gssapi_handle = find_dissector("gssapi");