2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas@webspan.net>
5 * $Id: packet-dcerpc.c,v 1.63 2002/06/24 00:03:18 tpot Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
38 #include <epan/packet.h>
39 #include "packet-dcerpc.h"
40 #include <epan/conversation.h>
42 #include "reassemble.h"
44 static const value_string pckt_vals[] = {
45 { PDU_REQ, "Request"},
47 { PDU_RESP, "Response"},
48 { PDU_FAULT, "Fault"},
49 { PDU_WORKING, "Working"},
50 { PDU_NOCALL, "Nocall"},
51 { PDU_REJECT, "Reject"},
53 { PDU_CL_CANCEL, "Cl_cancel"},
55 { PDU_CANCEL_ACK, "Cancel_ack"},
57 { PDU_BIND_ACK, "Bind_ack"},
58 { PDU_BIND_NAK, "Bind_nak"},
59 { PDU_ALTER, "Alter_context"},
60 { PDU_ALTER_ACK, "Alter_context_resp"},
61 { PDU_AUTH3, "AUTH3?"},
62 { PDU_SHUTDOWN, "Shutdown"},
63 { PDU_CO_CANCEL, "Co_cancel"},
64 { PDU_ORPHANED, "Orphaned"},
68 static const value_string drep_byteorder_vals[] = {
70 { 1, "Little-endian" },
74 static const value_string drep_character_vals[] = {
80 static const value_string drep_fp_vals[] = {
88 static const true_false_string flags_set_truth = {
94 * Authentication services.
96 static const value_string authn_protocol_vals[] = {
105 #define DCE_C_AUTHN_LEVEL_NONE 1
106 #define DCE_C_AUTHN_LEVEL_CONNECT 2
107 #define DCE_C_AUTHN_LEVEL_CALL 3
108 #define DCE_C_AUTHN_LEVEL_PKT 4
109 #define DCE_C_AUTHN_LEVEL_PKT_INTEGRITY 5
110 #define DCE_C_AUTHN_LEVEL_PKT_PRIVACY 6
112 static const value_string authn_level_vals[] = {
113 { DCE_C_AUTHN_LEVEL_NONE, "None" },
114 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
115 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
116 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
117 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
118 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
123 * Flag bits in first flag field in connectionless PDU header.
125 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
126 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
127 * fragment of a multi-PDU
129 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
130 a multi-PDU transmission */
131 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
132 * requested to send a `fack' PDU
133 * for the fragment */
134 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
136 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
138 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
140 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
143 * Flag bits in second flag field in connectionless PDU header.
145 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
146 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
147 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
148 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
149 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
150 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
151 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
152 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
155 * Flag bits in connection-oriented PDU header.
157 #define PFC_FIRST_FRAG 0x01 /* First fragment */
158 #define PFC_LAST_FRAG 0x02 /* Last fragment */
159 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
160 #define PFC_RESERVED_1 0x08
161 #define PFC_CONC_MPX 0x10 /* suports concurrent multiplexing
162 * of a single connection. */
163 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
164 * if true, guaranteed call did not
166 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
167 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
168 * was specified in the handle, and
169 * is present in the optional object
170 * field. If false, the object field
174 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
175 * it's not fragmented (i.e., this is both the first *and* last fragment),
176 * and FALSE otherwise.
178 #define PFC_NOT_FRAGMENTED(hdr) \
179 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG))==(PFC_FIRST_FRAG|PFC_LAST_FRAG))
182 * Presentation context negotiation result.
184 static const value_string p_cont_result_vals[] = {
186 { 1, "User rejection" },
187 { 2, "Provider rejection" },
192 * Presentation context negotiation rejection reasons.
194 static const value_string p_provider_reason_vals[] = {
195 { 0, "Reason not specified" },
196 { 1, "Abstract syntax not supported" },
197 { 2, "Proposed transfer syntaxes not supported" },
198 { 3, "Local limit exceeded" },
205 #define REASON_NOT_SPECIFIED 0
206 #define TEMPORARY_CONGESTION 1
207 #define LOCAL_LIMIT_EXCEEDED 2
208 #define CALLED_PADDR_UNKNOWN 3 /* not used */
209 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
210 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
211 #define USER_DATA_NOT_READABLE 6 /* not used */
212 #define NO_PSAP_AVAILABLE 7 /* not used */
214 static const value_string reject_reason_vals[] = {
215 { REASON_NOT_SPECIFIED, "Reason not specified" },
216 { TEMPORARY_CONGESTION, "Temporary congestion" },
217 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
218 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
219 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
220 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
221 { USER_DATA_NOT_READABLE, "User data not readable" },
222 { NO_PSAP_AVAILABLE, "No PSAP available" },
227 * Reject status codes.
229 static const value_string reject_status_vals[] = {
230 { 0, "Stub-defined exception" },
231 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
232 { 0x1c000002, "nca_s_fault_addr_error" },
233 { 0x1c000003, "nca_s_fault_fp_div_zero" },
234 { 0x1c000004, "nca_s_fault_fp_underflow" },
235 { 0x1c000005, "nca_s_fault_fp_overflow" },
236 { 0x1c000006, "nca_s_fault_invalid_tag" },
237 { 0x1c000007, "nca_s_fault_invalid_bound" },
238 { 0x1c000008, "nca_rpc_version_mismatch" },
239 { 0x1c000009, "nca_unspec_reject" },
240 { 0x1c00000a, "nca_s_bad_actid" },
241 { 0x1c00000b, "nca_who_are_you_failed" },
242 { 0x1c00000c, "nca_manager_not_entered" },
243 { 0x1c00000d, "nca_s_fault_cancel" },
244 { 0x1c00000e, "nca_s_fault_ill_inst" },
245 { 0x1c00000f, "nca_s_fault_fp_error" },
246 { 0x1c000010, "nca_s_fault_int_overflow" },
247 { 0x1c000014, "nca_s_fault_pipe_empty" },
248 { 0x1c000015, "nca_s_fault_pipe_closed" },
249 { 0x1c000016, "nca_s_fault_pipe_order" },
250 { 0x1c000017, "nca_s_fault_pipe_discipline" },
251 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
252 { 0x1c000019, "nca_s_fault_pipe_memory" },
253 { 0x1c00001a, "nca_s_fault_context_mismatch" },
254 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
255 { 0x1c00001c, "nca_invalid_pres_context_id" },
256 { 0x1c00001d, "nca_unsupported_authn_level" },
257 { 0x1c00001f, "nca_invalid_checksum" },
258 { 0x1c000020, "nca_invalid_crc" },
259 { 0x1c000021, "ncs_s_fault_user_defined" },
260 { 0x1c000022, "nca_s_fault_tx_open_failed" },
261 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
262 { 0x1c000024, "nca_s_fault_object_not_found" },
263 { 0x1c000025, "nca_s_fault_no_client_stub" },
264 { 0x1c010002, "nca_op_rng_error" },
265 { 0x1c010003, "nca_unk_if"},
266 { 0x1c010006, "nca_wrong_boot_time" },
267 { 0x1c010009, "nca_s_you_crashed" },
268 { 0x1c01000b, "nca_proto_error" },
269 { 0x1c010013, "nca_out_args_too_big" },
270 { 0x1c010014, "nca_server_too_busy" },
271 { 0x1c010017, "nca_unsupported_type" },
275 static int proto_dcerpc = -1;
278 static int hf_dcerpc_request_in = -1;
279 static int hf_dcerpc_response_in = -1;
280 static int hf_dcerpc_ver = -1;
281 static int hf_dcerpc_ver_minor = -1;
282 static int hf_dcerpc_packet_type = -1;
283 static int hf_dcerpc_cn_flags = -1;
284 static int hf_dcerpc_cn_flags_first_frag = -1;
285 static int hf_dcerpc_cn_flags_last_frag = -1;
286 static int hf_dcerpc_cn_flags_cancel_pending = -1;
287 static int hf_dcerpc_cn_flags_reserved = -1;
288 static int hf_dcerpc_cn_flags_mpx = -1;
289 static int hf_dcerpc_cn_flags_dne = -1;
290 static int hf_dcerpc_cn_flags_maybe = -1;
291 static int hf_dcerpc_cn_flags_object = -1;
292 static int hf_dcerpc_drep = -1;
293 static int hf_dcerpc_drep_byteorder = -1;
294 static int hf_dcerpc_drep_character = -1;
295 static int hf_dcerpc_drep_fp = -1;
296 static int hf_dcerpc_cn_frag_len = -1;
297 static int hf_dcerpc_cn_auth_len = -1;
298 static int hf_dcerpc_cn_call_id = -1;
299 static int hf_dcerpc_cn_max_xmit = -1;
300 static int hf_dcerpc_cn_max_recv = -1;
301 static int hf_dcerpc_cn_assoc_group = -1;
302 static int hf_dcerpc_cn_num_ctx_items = -1;
303 static int hf_dcerpc_cn_ctx_id = -1;
304 static int hf_dcerpc_cn_num_trans_items = -1;
305 static int hf_dcerpc_cn_bind_if_id = -1;
306 static int hf_dcerpc_cn_bind_if_ver = -1;
307 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
308 static int hf_dcerpc_cn_bind_trans_id = -1;
309 static int hf_dcerpc_cn_bind_trans_ver = -1;
310 static int hf_dcerpc_cn_alloc_hint = -1;
311 static int hf_dcerpc_cn_sec_addr_len = -1;
312 static int hf_dcerpc_cn_sec_addr = -1;
313 static int hf_dcerpc_cn_num_results = -1;
314 static int hf_dcerpc_cn_ack_result = -1;
315 static int hf_dcerpc_cn_ack_reason = -1;
316 static int hf_dcerpc_cn_ack_trans_id = -1;
317 static int hf_dcerpc_cn_ack_trans_ver = -1;
318 static int hf_dcerpc_cn_reject_reason = -1;
319 static int hf_dcerpc_cn_num_protocols = -1;
320 static int hf_dcerpc_cn_protocol_ver_major = -1;
321 static int hf_dcerpc_cn_protocol_ver_minor = -1;
322 static int hf_dcerpc_cn_cancel_count = -1;
323 static int hf_dcerpc_cn_status = -1;
324 static int hf_dcerpc_auth_type = -1;
325 static int hf_dcerpc_auth_level = -1;
326 static int hf_dcerpc_auth_pad_len = -1;
327 static int hf_dcerpc_auth_rsrvd = -1;
328 static int hf_dcerpc_auth_ctx_id = -1;
329 static int hf_dcerpc_dg_flags1 = -1;
330 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
331 static int hf_dcerpc_dg_flags1_last_frag = -1;
332 static int hf_dcerpc_dg_flags1_frag = -1;
333 static int hf_dcerpc_dg_flags1_nofack = -1;
334 static int hf_dcerpc_dg_flags1_maybe = -1;
335 static int hf_dcerpc_dg_flags1_idempotent = -1;
336 static int hf_dcerpc_dg_flags1_broadcast = -1;
337 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
338 static int hf_dcerpc_dg_flags2 = -1;
339 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
340 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
341 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
342 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
343 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
344 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
345 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
346 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
347 static int hf_dcerpc_dg_serial_hi = -1;
348 static int hf_dcerpc_obj_id = -1;
349 static int hf_dcerpc_dg_if_id = -1;
350 static int hf_dcerpc_dg_act_id = -1;
351 static int hf_dcerpc_dg_serial_lo = -1;
352 static int hf_dcerpc_dg_ahint = -1;
353 static int hf_dcerpc_dg_ihint = -1;
354 static int hf_dcerpc_dg_frag_len = -1;
355 static int hf_dcerpc_dg_frag_num = -1;
356 static int hf_dcerpc_dg_auth_proto = -1;
357 static int hf_dcerpc_opnum = -1;
358 static int hf_dcerpc_dg_seqnum = -1;
359 static int hf_dcerpc_dg_server_boot = -1;
360 static int hf_dcerpc_dg_if_ver = -1;
361 static int hf_dcerpc_dg_cancel_vers = -1;
362 static int hf_dcerpc_dg_cancel_id = -1;
363 static int hf_dcerpc_dg_server_accepting_cancels = -1;
364 static int hf_dcerpc_dg_fack_vers = -1;
365 static int hf_dcerpc_dg_fack_window_size = -1;
366 static int hf_dcerpc_dg_fack_max_tsdu = -1;
367 static int hf_dcerpc_dg_fack_max_frag_size = -1;
368 static int hf_dcerpc_dg_fack_serial_num = -1;
369 static int hf_dcerpc_dg_fack_selack_len = -1;
370 static int hf_dcerpc_dg_fack_selack = -1;
371 static int hf_dcerpc_dg_status = -1;
372 static int hf_dcerpc_array_max_count = -1;
373 static int hf_dcerpc_array_offset = -1;
374 static int hf_dcerpc_array_actual_count = -1;
375 static int hf_dcerpc_op = -1;
376 static int hf_dcerpc_referent_id = -1;
377 static int hf_dcerpc_fragments = -1;
378 static int hf_dcerpc_fragment = -1;
379 static int hf_dcerpc_fragment_overlap = -1;
380 static int hf_dcerpc_fragment_overlap_conflict = -1;
381 static int hf_dcerpc_fragment_multiple_tails = -1;
382 static int hf_dcerpc_fragment_too_long_fragment = -1;
383 static int hf_dcerpc_fragment_error = -1;
385 static gint ett_dcerpc = -1;
386 static gint ett_dcerpc_cn_flags = -1;
387 static gint ett_dcerpc_drep = -1;
388 static gint ett_dcerpc_dg_flags1 = -1;
389 static gint ett_dcerpc_dg_flags2 = -1;
390 static gint ett_dcerpc_pointer_data = -1;
391 static gint ett_dcerpc_fragments = -1;
392 static gint ett_dcerpc_fragment = -1;
394 fragment_items dcerpc_frag_items = {
395 &ett_dcerpc_fragments,
396 &ett_dcerpc_fragment,
398 &hf_dcerpc_fragments,
400 &hf_dcerpc_fragment_overlap,
401 &hf_dcerpc_fragment_overlap_conflict,
402 &hf_dcerpc_fragment_multiple_tails,
403 &hf_dcerpc_fragment_too_long_fragment,
404 &hf_dcerpc_fragment_error,
409 /* try to desegment big DCE/RPC packets over TCP? */
410 static gboolean dcerpc_cn_desegment = TRUE;
412 /* reassemble DCE/RPC fragments */
413 /* reassembly of dcerpc fragments will not work for the case where ONE frame
414 might contain multiple dcerpc fragments for different PDUs.
415 this case would be so unusual/weird so if you got captures like that:
418 static gboolean dcerpc_reassemble = FALSE;
419 static GHashTable *dcerpc_co_reassemble_table = NULL;
420 static GHashTable *dcerpc_cl_reassemble_table = NULL;
423 dcerpc_reassemble_init(void)
425 fragment_table_init(&dcerpc_co_reassemble_table);
426 fragment_table_init(&dcerpc_cl_reassemble_table);
433 /* the registered subdissectors */
434 static GHashTable *dcerpc_uuids;
436 typedef struct _dcerpc_uuid_key {
441 typedef struct _dcerpc_uuid_value {
445 dcerpc_sub_dissector *procs;
450 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
452 dcerpc_uuid_key *key1 = (dcerpc_uuid_key *)k1;
453 dcerpc_uuid_key *key2 = (dcerpc_uuid_key *)k2;
454 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
455 && (key1->ver == key2->ver));
459 dcerpc_uuid_hash (gconstpointer k)
461 dcerpc_uuid_key *key = (dcerpc_uuid_key *)k;
462 /* This isn't perfect, but the Data1 part of these is almost always
464 return key->uuid.Data1;
468 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
469 dcerpc_sub_dissector *procs, int opnum_hf)
471 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
472 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
477 value->proto = proto;
479 value->name = proto_get_protocol_short_name (proto);
480 value->procs = procs;
481 value->opnum_hf = opnum_hf;
483 g_hash_table_insert (dcerpc_uuids, key, value);
488 * To keep track of ctx_id mappings.
490 * Everytime we see a bind call we update this table.
491 * Note that we always specify a SMB FID. For non-SMB transports this
494 static GHashTable *dcerpc_binds=NULL;
496 typedef struct _dcerpc_bind_key {
497 conversation_t *conv;
502 typedef struct _dcerpc_bind_value {
507 static GMemChunk *dcerpc_bind_key_chunk=NULL;
508 static GMemChunk *dcerpc_bind_value_chunk=NULL;
511 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
513 dcerpc_bind_key *key1 = (dcerpc_bind_key *)k1;
514 dcerpc_bind_key *key2 = (dcerpc_bind_key *)k2;
515 return (key1->conv == key2->conv
516 && key1->ctx_id == key2->ctx_id
517 && key1->smb_fid == key2->smb_fid);
521 dcerpc_bind_hash (gconstpointer k)
523 dcerpc_bind_key *key = (dcerpc_bind_key *)k;
524 return ((guint)key->conv) + key->ctx_id + key->smb_fid;
528 * To keep track of callid mappings. Should really use some generic
529 * conversation support instead.
531 static GHashTable *dcerpc_calls=NULL;
533 typedef struct _dcerpc_call_key {
534 conversation_t *conv;
539 static GMemChunk *dcerpc_call_key_chunk=NULL;
541 static GMemChunk *dcerpc_call_value_chunk=NULL;
544 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
546 dcerpc_call_key *key1 = (dcerpc_call_key *)k1;
547 dcerpc_call_key *key2 = (dcerpc_call_key *)k2;
548 return (key1->conv == key2->conv
549 && key1->call_id == key2->call_id
550 && key1->smb_fid == key2->smb_fid);
554 dcerpc_call_hash (gconstpointer k)
556 dcerpc_call_key *key = (dcerpc_call_key *)k;
557 return ((guint32)key->conv) + key->call_id + key->smb_fid;
561 /* to keep track of matched calls/responses
562 this one uses the same value struct as calls, but the key is the frame id
564 static GHashTable *dcerpc_matched=NULL;
566 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
568 return (guint32)k1 == (guint32)k2;
572 dcerpc_matched_hash (gconstpointer k)
580 * Utility functions. Modeled after packet-rpc.c
584 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
585 proto_tree *tree, char *drep,
586 int hfindex, guint8 *pdata)
590 data = tvb_get_guint8 (tvb, offset);
592 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
600 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
601 proto_tree *tree, char *drep,
602 int hfindex, guint16 *pdata)
606 data = ((drep[0] & 0x10)
607 ? tvb_get_letohs (tvb, offset)
608 : tvb_get_ntohs (tvb, offset));
611 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
619 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
620 proto_tree *tree, char *drep,
621 int hfindex, guint32 *pdata)
625 data = ((drep[0] & 0x10)
626 ? tvb_get_letohl (tvb, offset)
627 : tvb_get_ntohl (tvb, offset));
630 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
638 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
639 proto_tree *tree, char *drep,
640 int hfindex, unsigned char *pdata)
643 tvb_memcpy(tvb, pdata, offset, 8);
644 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
646 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
647 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
648 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
649 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
654 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
661 * a couple simpler things
664 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
666 if (drep[0] & 0x10) {
667 return tvb_get_letohs (tvb, offset);
669 return tvb_get_ntohs (tvb, offset);
674 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
676 if (drep[0] & 0x10) {
677 return tvb_get_letohl (tvb, offset);
679 return tvb_get_ntohl (tvb, offset);
684 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
687 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
688 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
689 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
691 for (i=0; i<sizeof (uuid->Data4); i++) {
692 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
699 /* function to dissect a unidimensional conformant array */
701 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
702 proto_tree *tree, char *drep,
703 dcerpc_dissect_fnct_t *fnct)
709 di=pinfo->private_data;
710 if(di->conformant_run){
711 /* conformant run, just dissect the max_count header */
713 di->conformant_run=0;
714 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
715 hf_dcerpc_array_max_count, &di->array_max_count);
716 di->array_max_count_offset=offset-4;
717 di->conformant_run=1;
718 di->conformant_eaten=offset-old_offset;
720 /* we dont dont remember where in the bytestream this fields was */
721 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
723 /* real run, dissect the elements */
724 for(i=0;i<di->array_max_count;i++){
725 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
731 /* function to dissect a unidimensional conformant and varying array */
733 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
734 proto_tree *tree, char *drep,
735 dcerpc_dissect_fnct_t *fnct)
741 di=pinfo->private_data;
742 if(di->conformant_run){
743 /* conformant run, just dissect the max_count header */
745 di->conformant_run=0;
746 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
747 hf_dcerpc_array_max_count, &di->array_max_count);
748 di->array_max_count_offset=offset-4;
749 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
750 hf_dcerpc_array_offset, &di->array_offset);
751 di->array_offset_offset=offset-4;
752 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
753 hf_dcerpc_array_actual_count, &di->array_actual_count);
754 di->array_actual_count_offset=offset-4;
755 di->conformant_run=1;
756 di->conformant_eaten=offset-old_offset;
758 /* we dont dont remember where in the bytestream these fields were */
759 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
760 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
761 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
763 /* real run, dissect the elements */
764 for(i=0;i<di->array_actual_count;i++){
765 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
773 /* ndr pointer handling */
774 /* list of pointers encountered so far */
775 static GSList *ndr_pointer_list = NULL;
777 /* position where in the list to insert newly encountered pointers */
778 static int ndr_pointer_list_pos=0;
780 /* boolean controlling whether pointers are top-level or embedded */
781 static gboolean pointers_are_top_level = TRUE;
783 /* as a kludge, we represent all embedded reference pointers as id==-1
784 hoping that his will not collide with any non-ref pointers */
785 typedef struct ndr_pointer_data {
788 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
791 } ndr_pointer_data_t;
794 init_ndr_pointer_list(packet_info *pinfo)
798 di=pinfo->private_data;
799 di->conformant_run=0;
801 while(ndr_pointer_list){
802 ndr_pointer_data_t *npd;
804 npd=g_slist_nth_data(ndr_pointer_list, 0);
805 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
811 ndr_pointer_list=NULL;
812 ndr_pointer_list_pos=0;
813 pointers_are_top_level=TRUE;
817 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *drep)
819 int found_new_pointer;
823 di=pinfo->private_data;
828 len=g_slist_length(ndr_pointer_list);
830 ndr_pointer_data_t *tnpd;
831 tnpd=g_slist_nth_data(ndr_pointer_list, i);
833 dcerpc_dissect_fnct_t *fnct;
838 ndr_pointer_list_pos=i+1;
839 di->hf_index=tnpd->hf_index;
840 di->levels=tnpd->levels;
841 /* first a run to handle any conformant
843 di->conformant_run=1;
844 di->conformant_eaten=0;
846 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
848 g_assert((offset-old_offset)==di->conformant_eaten);
849 /* This is to check for any bugs in the dissectors.
851 * Basically, the NDR representation will store all
852 * arrays in two blocks, one block with the dimension
853 * discreption, like size, number of elements and such,
854 * and another block that contains the actual data stored
856 * If the array is embedded directly inside another,
857 * encapsulating aggregate type, like a union or struct,
858 * then these two blocks will be stored at different places
859 * in the bytestream, with other data between the blocks.
861 * For this reason, all pointers to types (both aggregate
862 * and scalar, for simplicity no distinction is made)
863 * will have its dissector called twice.
864 * The dissector will first be called with conformant_run==1
865 * in which mode the dissector MUST NOT consume any data from
866 * the tvbuff (i.e. may not dissect anything) except the
867 * initial control block for arrays.
868 * The second time the dissector is called, with
869 * conformant_run==0, all other data for the type will be
872 * All dissect_ndr_<type> dissectors are already prepared
873 * for this and knows when it should eat data from the tvb
874 * and when not to, so implementors of dissectors will
875 * normally not need to worry about this or even know about
876 * it. However, if a dissector for an aggregate type calls
877 * a subdissector from outside packet-dcerpc.c, such as
878 * the dissector in packet-smb.c for NT Security Descriptors
879 * as an example, then it is VERY important to encapsulate
880 * this call to an external subdissector with the appropriate
881 * test for conformant_run, i.e. it will need something like
885 * di=pinfo->private_data;
886 * if(di->conformant_run){
890 * to make sure it makes the right thing.
891 * This assert will signal when someone has forgotten to
892 * make the dissector aware of this requirement.
895 /* now we dissect the actual pointer */
896 di->conformant_run=0;
897 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
901 } while(found_new_pointer);
908 add_pointer_to_list(packet_info *pinfo, proto_tree *tree,
909 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index, int levels)
911 ndr_pointer_data_t *npd;
913 /* check if this pointer is valid */
916 dcerpc_call_value *value;
918 di=pinfo->private_data;
922 if(!(pinfo->fd->flags.visited)){
923 if(id>value->max_ptr){
928 /* if we havent seen the request bail out since we cant
929 know whether this is the first non-NULL instance
931 if(value->req_frame==0){
932 /* XXX THROW EXCEPTION */
935 /* We saw this one in the request frame, nothing to
937 if(id<=value->max_ptr){
943 npd=g_malloc(sizeof(ndr_pointer_data_t));
947 npd->hf_index=hf_index;
949 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
950 ndr_pointer_list_pos);
951 ndr_pointer_list_pos++;
956 find_pointer_index(guint32 id)
958 ndr_pointer_data_t *npd;
961 len=g_slist_length(ndr_pointer_list);
963 npd=g_slist_nth_data(ndr_pointer_list, i);
974 /* This function dissects an NDR pointer and stores the callback for later
975 * deferred dissection.
977 * fnct is the callback function for when we have reached this object in
980 * type is what type of pointer.
982 * this is text is what text we should put in any created tree node.
984 * hf_index is what hf value we want to pass to the callback function when
985 * it is called, the callback can later pich this one up from di->hf_index.
987 * levels is a generic int we want to pass to teh callback function. the
988 * callback can later pick it up from di->levels
990 * See packet-dcerpc-samr.c for examples
993 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
994 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
995 int type, char *text, int hf_index, int levels)
999 di=pinfo->private_data;
1000 if(di->conformant_run){
1001 /* this call was only for dissecting the header for any
1002 embedded conformant array. we will not parse any
1003 pointers in this mode.
1008 /*TOP LEVEL REFERENCE POINTER*/
1009 if( pointers_are_top_level
1010 &&(type==NDR_POINTER_REF) ){
1014 /* we must find out a nice way to do the length here */
1015 item=proto_tree_add_text(tree, tvb, offset, 0,
1017 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1019 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
1023 /*TOP LEVEL FULL POINTER*/
1024 if( pointers_are_top_level
1025 && (type==NDR_POINTER_PTR) ){
1031 /* get the referent id */
1032 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1034 /* we got a NULL pointer */
1036 proto_tree_add_text(tree, tvb, offset-4, 4,
1037 "(NULL pointer) %s",text);
1041 /* see if we have seen this pointer before */
1042 idx=find_pointer_index(id);
1044 /* we have seen this pointer before */
1046 proto_tree_add_text(tree, tvb, offset-4, 4,
1047 "(duplicate PTR) %s",text);
1052 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1054 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1055 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1056 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
1059 /*TOP LEVEL UNIQUE POINTER*/
1060 if( pointers_are_top_level
1061 && (type==NDR_POINTER_UNIQUE) ){
1066 /* get the referent id */
1067 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1069 /* we got a NULL pointer */
1071 proto_tree_add_text(tree, tvb, offset-4, 4,
1072 "(NULL pointer) %s",text);
1077 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1079 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1080 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1081 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
1085 /*EMBEDDED REFERENCE POINTER*/
1086 if( (!pointers_are_top_level)
1087 && (type==NDR_POINTER_REF) ){
1092 /* get the referent id */
1093 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1096 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1098 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1099 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1100 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
1104 /*EMBEDDED UNIQUE POINTER*/
1105 if( (!pointers_are_top_level)
1106 && (type==NDR_POINTER_UNIQUE) ){
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);
1122 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1124 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1125 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1126 add_pointer_to_list(pinfo, tr, fnct, 0xffffffff, hf_index, levels);
1130 /*EMBEDDED FULL POINTER*/
1131 if( (!pointers_are_top_level)
1132 && (type==NDR_POINTER_PTR) ){
1138 /* get the referent id */
1139 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1141 /* we got a NULL pointer */
1143 proto_tree_add_text(tree, tvb, offset-4, 4,
1144 "(NULL pointer) %s",text);
1148 /* see if we have seen this pointer before */
1149 idx=find_pointer_index(id);
1151 /* we have seen this pointer before */
1153 proto_tree_add_text(tree, tvb, offset-4, 4,
1154 "(duplicate PTR) %s",text);
1159 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1161 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1162 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1163 add_pointer_to_list(pinfo, tr, fnct, id, hf_index, levels);
1169 /* After each top level pointer we have dissected we have to
1170 dissect all deferrals before we move on to the next top level
1172 if(pointers_are_top_level==TRUE){
1173 pointers_are_top_level=FALSE;
1174 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
1175 pointers_are_top_level=TRUE;
1184 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
1185 proto_tree *dcerpc_tree,
1186 tvbuff_t *tvb, gint offset,
1187 guint16 opnum, gboolean is_rqst,
1188 char *drep, dcerpc_info *info,
1191 dcerpc_uuid_key key;
1192 dcerpc_uuid_value *sub_proto;
1194 proto_tree *sub_tree = NULL;
1195 dcerpc_sub_dissector *proc;
1197 dcerpc_dissect_fnct_t *sub_dissect;
1198 const char *saved_proto;
1199 void *saved_private_data;
1201 key.uuid = info->call_data->uuid;
1202 key.ver = info->call_data->ver;
1205 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1206 || !proto_is_protocol_enabled(sub_proto->proto)) {
1208 * We don't have a dissector for this UUID, or the protocol
1209 * for that UUID is disabled.
1211 length = tvb_length_remaining (tvb, offset);
1213 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
1214 "Stub data (%d byte%s)", length,
1215 plurality(length, "", "s"));
1220 for (proc = sub_proto->procs; proc->name; proc++) {
1221 if (proc->num == opnum) {
1230 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1231 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1234 if (check_col (pinfo->cinfo, COL_INFO)) {
1235 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1236 name, is_rqst ? "request" : "reply");
1240 proto_item *sub_item;
1241 sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
1245 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1249 * Put the operation number into the tree along with
1250 * the operation's name.
1253 if (sub_proto->opnum_hf != -1)
1254 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
1256 "Operation: %s (%u)",
1259 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
1261 "Operation: %s (%u)",
1266 * If the authentication level is DCE_C_AUTHN_LEVEL_PKT_PRIVACY,
1267 * the stub data is encrypted, and we can't dissect it.
1269 if (auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1270 length = tvb_length_remaining (tvb, offset);
1272 proto_tree_add_text(sub_tree, tvb, offset, length,
1273 "Encrypted stub data (%d byte%s)",
1274 length, plurality(length, "", "s"));
1277 sub_dissect = is_rqst ? proc->dissect_rqst : proc->dissect_resp;
1279 saved_proto = pinfo->current_proto;
1280 saved_private_data = pinfo->private_data;
1281 pinfo->current_proto = sub_proto->name;
1282 pinfo->private_data = (void *)info;
1284 init_ndr_pointer_list(pinfo);
1285 offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
1287 pinfo->current_proto = saved_proto;
1288 pinfo->private_data = saved_private_data;
1290 length = tvb_length_remaining (tvb, offset);
1292 proto_tree_add_text (sub_tree, tvb, offset, length,
1293 "Stub data (%d byte%s)", length,
1294 plurality(length, "", "s"));
1302 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1303 e_dce_cn_common_hdr_t *hdr, int *auth_level_p)
1306 guint8 auth_pad_len;
1310 * Initially set "*auth_level_p" to -1 to indicate that we haven't
1311 * yet seen any authentication level information.
1313 if (auth_level_p != NULL)
1317 * The authentication information is at the *end* of the PDU; in
1318 * request and response PDUs, the request and response stub data
1321 * If the full packet is here, and we've got an auth len, and it's
1322 * valid, then dissect the auth info.
1324 if (tvb_length (tvb) >= hdr->frag_len
1326 && (hdr->auth_len + 8 <= hdr->frag_len)) {
1328 offset = hdr->frag_len - (hdr->auth_len + 8);
1330 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1331 hf_dcerpc_auth_type, NULL);
1332 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1333 hf_dcerpc_auth_level, &auth_level);
1334 if (auth_level_p != NULL)
1335 *auth_level_p = auth_level;
1336 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1337 hf_dcerpc_auth_pad_len, &auth_pad_len);
1338 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1339 hf_dcerpc_auth_rsrvd, NULL);
1340 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1341 hf_dcerpc_auth_ctx_id, NULL);
1343 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len, "Auth Data");
1345 /* figure out where the auth padding starts */
1346 offset = hdr->frag_len - (hdr->auth_len + 8 + auth_pad_len);
1347 if (offset > 0 && auth_pad_len) {
1348 proto_tree_add_text (dcerpc_tree, tvb, offset,
1349 auth_pad_len, "Auth padding");
1350 return hdr->auth_len + 8 + auth_pad_len;
1352 return hdr->auth_len + 8;
1360 /* We need to hash in the SMB fid number to generate a unique hash table
1361 key as DCERPC over SMB allows several pipes over the same TCP/IP
1364 static guint16 get_smb_fid (void *private_data)
1366 dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
1369 return 0; /* Nothing to see here */
1371 /* DCERPC over smb */
1373 if (priv->transport_type == DCERPC_TRANSPORT_SMB)
1374 return priv->data.smb.fid;
1376 /* Some other transport... */
1382 * Connection oriented packet types
1386 dissect_dcerpc_cn_bind (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1387 e_dce_cn_common_hdr_t *hdr)
1389 conversation_t *conv = NULL;
1390 guint8 num_ctx_items;
1392 gboolean saw_ctx_item = FALSE;
1394 guint16 num_trans_items;
1399 guint16 if_ver, if_ver_minor;
1402 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1403 hf_dcerpc_cn_max_xmit, NULL);
1405 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1406 hf_dcerpc_cn_max_recv, NULL);
1408 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1409 hf_dcerpc_cn_assoc_group, NULL);
1411 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1412 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
1417 for (i = 0; i < num_ctx_items; i++) {
1418 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1419 hf_dcerpc_cn_ctx_id, &ctx_id);
1421 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1422 hf_dcerpc_cn_num_trans_items, &num_trans_items);
1424 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
1426 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_if_id, tvb,
1428 "Interface UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1429 if_id.Data1, if_id.Data2, if_id.Data3,
1430 if_id.Data4[0], if_id.Data4[1],
1431 if_id.Data4[2], if_id.Data4[3],
1432 if_id.Data4[4], if_id.Data4[5],
1433 if_id.Data4[6], if_id.Data4[7]);
1437 if (hdr->drep[0] & 0x10) {
1438 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1439 hf_dcerpc_cn_bind_if_ver, &if_ver);
1440 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1441 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1443 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1444 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
1445 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1446 hf_dcerpc_cn_bind_if_ver, &if_ver);
1449 if (!saw_ctx_item) {
1450 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1451 pinfo->srcport, pinfo->destport, 0);
1453 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
1454 pinfo->srcport, pinfo->destport, 0);
1457 /* if this is the first time we see this packet, we need to
1458 update the dcerpc_binds table so that any later calls can
1459 match to the interface.
1460 XXX We assume that BINDs will NEVER be fragmented.
1462 if(!(pinfo->fd->flags.visited)){
1463 dcerpc_bind_key *key;
1464 dcerpc_bind_value *value;
1466 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
1468 key->ctx_id = ctx_id;
1469 key->smb_fid = get_smb_fid(pinfo->private_data);
1471 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
1472 value->uuid = if_id;
1473 value->ver = if_ver;
1475 /* add this entry to the bind table, first removing any
1476 previous ones that are identical
1478 if(g_hash_table_lookup(dcerpc_binds, key)){
1479 g_hash_table_remove(dcerpc_binds, key);
1481 g_hash_table_insert (dcerpc_binds, key, value);
1484 if (check_col (pinfo->cinfo, COL_INFO)) {
1485 col_append_fstr (pinfo->cinfo, COL_INFO, " UUID %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
1486 if_id.Data1, if_id.Data2, if_id.Data3,
1487 if_id.Data4[0], if_id.Data4[1],
1488 if_id.Data4[2], if_id.Data4[3],
1489 if_id.Data4[4], if_id.Data4[5],
1490 if_id.Data4[6], if_id.Data4[7],
1491 if_ver, if_ver_minor);
1493 saw_ctx_item = TRUE;
1496 for (j = 0; j < num_trans_items; j++) {
1497 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1499 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_bind_trans_id, tvb,
1501 "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1502 trans_id.Data1, trans_id.Data2, trans_id.Data3,
1503 trans_id.Data4[0], trans_id.Data4[1],
1504 trans_id.Data4[2], trans_id.Data4[3],
1505 trans_id.Data4[4], trans_id.Data4[5],
1506 trans_id.Data4[6], trans_id.Data4[7]);
1510 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1511 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
1516 * XXX - we should save the authentication type *if* we have
1517 * an authentication header, and associate it with an authentication
1518 * context, so subsequent PDUs can use that context.
1520 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, NULL);
1524 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1525 e_dce_cn_common_hdr_t *hdr)
1527 guint16 max_xmit, max_recv;
1528 guint16 sec_addr_len;
1538 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1539 hf_dcerpc_cn_max_xmit, &max_xmit);
1541 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1542 hf_dcerpc_cn_max_recv, &max_recv);
1544 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1545 hf_dcerpc_cn_assoc_group, NULL);
1547 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1548 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
1549 if (sec_addr_len != 0) {
1550 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
1551 sec_addr_len, FALSE);
1552 offset += sec_addr_len;
1556 offset += 4 - offset % 4;
1559 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1560 hf_dcerpc_cn_num_results, &num_results);
1565 for (i = 0; i < num_results; i++) {
1566 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
1567 hdr->drep, hf_dcerpc_cn_ack_result,
1570 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
1571 hdr->drep, hf_dcerpc_cn_ack_reason,
1575 * The reason for rejection isn't meaningful, and often isn't
1576 * set, when the syntax was accepted.
1581 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
1583 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
1585 "Transfer Syntax: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1586 trans_id.Data1, trans_id.Data2, trans_id.Data3,
1587 trans_id.Data4[0], trans_id.Data4[1],
1588 trans_id.Data4[2], trans_id.Data4[3],
1589 trans_id.Data4[4], trans_id.Data4[5],
1590 trans_id.Data4[6], trans_id.Data4[7]);
1594 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1595 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
1599 * XXX - do we need to do anything with the authentication level
1600 * we get back from this?
1602 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, NULL);
1604 if (check_col (pinfo->cinfo, COL_INFO)) {
1605 if (num_results != 0 && result == 0) {
1606 /* XXX - only checks the last result */
1607 col_append_fstr (pinfo->cinfo, COL_INFO,
1608 " accept max_xmit: %u max_recv: %u",
1609 max_xmit, max_recv);
1611 /* XXX - only shows the last result and reason */
1612 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
1613 val_to_str(result, p_cont_result_vals,
1614 "Unknown result (%u)"),
1615 val_to_str(reason, p_provider_reason_vals,
1622 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1623 e_dce_cn_common_hdr_t *hdr)
1626 guint8 num_protocols;
1631 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
1632 hdr->drep, hf_dcerpc_cn_reject_reason,
1635 if (check_col (pinfo->cinfo, COL_INFO)) {
1636 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
1637 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
1640 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
1641 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1642 hf_dcerpc_cn_num_protocols,
1645 for (i = 0; i < num_protocols; i++) {
1646 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
1647 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
1649 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
1650 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
1657 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1658 proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
1660 conversation_t *conv;
1669 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1670 hf_dcerpc_cn_alloc_hint, &alloc_hint);
1672 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1673 hf_dcerpc_cn_ctx_id, &ctx_id);
1675 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1676 hf_dcerpc_opnum, &opnum);
1678 if (check_col (pinfo->cinfo, COL_INFO)) {
1679 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
1683 if (hdr->flags & PFC_OBJECT_UUID) {
1684 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
1686 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
1688 "Object UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1689 obj_id.Data1, obj_id.Data2, obj_id.Data3,
1703 * XXX - what if this was set when the connection was set up,
1704 * and we just have a security context?
1706 auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
1709 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1710 pinfo->srcport, pinfo->destport, 0);
1714 dcerpc_call_value *value;
1716 /* !!! we can NOT check flags.visited here since this will interact
1717 badly with when SMB handles (i.e. calls the subdissector)
1718 and desegmented pdu's .
1719 Instead we check if this pdu is already in the matched table or not
1721 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
1722 dcerpc_bind_key bind_key;
1723 dcerpc_bind_value *bind_value;
1726 bind_key.ctx_id=ctx_id;
1727 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
1729 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key))){
1730 dcerpc_call_key *call_key;
1731 dcerpc_call_value *call_value;
1733 /* We found the binding so just add the call
1734 to both the call table and the matched table
1736 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
1737 call_key->conv=conv;
1738 call_key->call_id=hdr->call_id;
1739 call_key->smb_fid=get_smb_fid(pinfo->private_data);
1741 /* if there is already a matching call in the table
1742 remove it so it is replaced with the new one */
1743 if(g_hash_table_lookup(dcerpc_calls, call_key)){
1744 g_hash_table_remove(dcerpc_calls, call_key);
1747 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
1748 call_value->uuid = bind_value->uuid;
1749 call_value->ver = bind_value->ver;
1750 call_value->opnum = opnum;
1751 call_value->req_frame=pinfo->fd->num;
1752 call_value->rep_frame=0;
1753 call_value->max_ptr=0;
1754 call_value->private_data = NULL;
1755 g_hash_table_insert (dcerpc_calls, call_key, call_value);
1757 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1761 value=g_hash_table_lookup (dcerpc_matched, (void *)pinfo->fd->num);
1764 int length, reported_length, stub_length;
1766 gboolean save_fragmented;
1768 /* handoff this call */
1769 length = tvb_length_remaining(tvb, offset);
1770 reported_length = tvb_reported_length_remaining(tvb, offset);
1771 stub_length = hdr->frag_len - offset - auth_sz;
1772 if (length > stub_length)
1773 length = stub_length;
1774 if (reported_length > stub_length)
1775 reported_length = stub_length;
1777 di.call_id = hdr->call_id;
1778 di.smb_fid = get_smb_fid(pinfo->private_data);
1780 di.call_data = value;
1782 if(value->rep_frame!=0){
1783 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
1784 tvb, 0, 0, value->rep_frame);
1787 save_fragmented = pinfo->fragmented;
1789 /* If we don't have reassembly enabled, or this packet contains
1790 the entire PDU, or if this is a short frame (or a frame
1791 not reassembled at a lower layer) that doesn't include all
1792 the data in the fragment, just call the handoff directly if
1793 this is the first fragment or the PDU isn't fragmented. */
1794 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
1795 stub_length > length ){
1796 if(hdr->flags&PFC_FIRST_FRAG){
1797 /* First fragment, possibly the only fragment */
1798 pinfo->fragmented = !PFC_NOT_FRAGMENTED(hdr);
1799 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1800 tvb_new_subset (tvb, offset, length,
1802 0, opnum, TRUE, hdr->drep, &di, auth_level);
1804 /* PDU is fragmented and this isn't the first fragment */
1805 if (check_col(pinfo->cinfo, COL_INFO)) {
1806 col_append_fstr(pinfo->cinfo, COL_INFO,
1807 " [DCE/RPC fragment]");
1811 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
1812 "Fragment data (%d byte%s)", length,
1813 plurality(length, "", "s"));
1818 /* Reassembly is enabled, the PDU is fragmented, and
1819 we have all the data in the fragment; the first two
1820 of those mean we should attempt reassembly, and the
1821 third means we can attempt reassembly. */
1824 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
1825 "Fragment data (%d byte%s)", length,
1826 plurality(length, "", "s"));
1829 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
1830 if( (!pinfo->fd->flags.visited) && value->req_frame ){
1831 fragment_add(tvb, offset, pinfo, value->req_frame,
1832 dcerpc_co_reassemble_table,
1836 fragment_set_tot_len(pinfo, value->req_frame,
1837 dcerpc_co_reassemble_table, alloc_hint);
1839 if (check_col(pinfo->cinfo, COL_INFO)) {
1840 col_append_fstr(pinfo->cinfo, COL_INFO,
1841 " [DCE/RPC fragment]");
1843 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
1844 if( value->req_frame ){
1845 fragment_data *fd_head;
1848 tot_len = fragment_get_tot_len(pinfo, value->req_frame,
1849 dcerpc_co_reassemble_table);
1850 fd_head = fragment_add(tvb, offset, pinfo,
1852 dcerpc_co_reassemble_table,
1858 /* We completed reassembly */
1861 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
1862 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
1863 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
1864 show_fragment_tree(fd_head, &dcerpc_frag_items,
1865 dcerpc_tree, pinfo, next_tvb);
1867 pinfo->fragmented = FALSE;
1868 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
1870 0, opnum, TRUE, hdr->drep, &di,
1873 /* Reassembly not complete - some fragments
1875 if (check_col(pinfo->cinfo, COL_INFO)) {
1876 col_append_fstr(pinfo->cinfo, COL_INFO,
1877 "[DCE/RPC fragment]");
1881 } else { /* MIDDLE fragment(s) */
1882 if( (!pinfo->fd->flags.visited) && value->req_frame ){
1884 tot_len = fragment_get_tot_len(pinfo, value->req_frame,
1885 dcerpc_co_reassemble_table);
1886 fragment_add(tvb, offset, pinfo, value->req_frame,
1887 dcerpc_co_reassemble_table,
1892 if (check_col(pinfo->cinfo, COL_INFO)) {
1893 col_append_fstr(pinfo->cinfo, COL_INFO,
1894 "[DCE/RPC fragment]");
1898 pinfo->fragmented = save_fragmented;
1904 dissect_dcerpc_cn_resp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1905 proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
1907 dcerpc_call_value *value = NULL;
1908 conversation_t *conv;
1915 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1916 hf_dcerpc_cn_alloc_hint, &alloc_hint);
1918 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1919 hf_dcerpc_cn_ctx_id, &ctx_id);
1921 if (check_col (pinfo->cinfo, COL_INFO)) {
1922 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
1925 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1926 hf_dcerpc_cn_cancel_count, NULL);
1931 * XXX - what if this was set when the connection was set up,
1932 * and we just have a security context?
1934 auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
1937 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
1938 pinfo->srcport, pinfo->destport, 0);
1940 /* no point in creating one here, really */
1943 /* !!! we can NOT check flags.visited here since this will interact
1944 badly with when SMB handles (i.e. calls the subdissector)
1945 and desegmented pdu's .
1946 Instead we check if this pdu is already in the matched table or not
1948 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
1949 dcerpc_call_key call_key;
1950 dcerpc_call_value *call_value;
1953 call_key.call_id=hdr->call_id;
1954 call_key.smb_fid=get_smb_fid(pinfo->private_data);
1956 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
1957 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
1958 if(call_value->rep_frame==0){
1959 call_value->rep_frame=pinfo->fd->num;
1965 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
1968 int length, reported_length, stub_length;
1970 gboolean save_fragmented;
1972 /* handoff this call */
1973 length = tvb_length_remaining(tvb, offset);
1974 reported_length = tvb_reported_length_remaining(tvb, offset);
1975 stub_length = hdr->frag_len - offset - auth_sz;
1976 if (length > stub_length)
1977 length = stub_length;
1978 if (reported_length > stub_length)
1979 reported_length = stub_length;
1981 di.call_id = hdr->call_id;
1982 di.smb_fid = get_smb_fid(pinfo->private_data);
1984 di.call_data = value;
1986 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
1987 if(value->req_frame!=0){
1988 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
1989 tvb, 0, 0, value->req_frame);
1992 save_fragmented = pinfo->fragmented;
1994 /* If we don't have reassembly enabled, or this packet contains
1995 the entire PDU, or if this is a short frame (or a frame
1996 not reassembled at a lower layer) that doesn't include all
1997 the data in the fragment, just call the handoff directly if
1998 this is the first fragment or the PDU isn't fragmented. */
1999 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
2000 stub_length > length ){
2001 if(hdr->flags&PFC_FIRST_FRAG){
2002 /* First fragment, possibly the only fragment */
2003 pinfo->fragmented = !PFC_NOT_FRAGMENTED(hdr);
2004 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2005 tvb_new_subset (tvb, offset, length,
2007 0, value->opnum, FALSE, hdr->drep, &di,
2010 /* PDU is fragmented and this isn't the first fragment */
2011 if (check_col(pinfo->cinfo, COL_INFO)) {
2012 col_append_fstr(pinfo->cinfo, COL_INFO,
2013 " [DCE/RPC fragment]");
2017 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2018 "Fragment data (%d byte%s)", length,
2019 plurality(length, "", "s"));
2024 /* Reassembly is enabled, the PDU is fragmented, and
2025 we have all the data in the fragment; the first two
2026 of those mean we should attempt reassembly, and the
2027 third means we can attempt reassembly. */
2030 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2031 "Fragment data (%d byte%s)", length,
2032 plurality(length, "", "s"));
2035 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
2036 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2037 fragment_add(tvb, offset, pinfo, value->rep_frame,
2038 dcerpc_co_reassemble_table,
2042 fragment_set_tot_len(pinfo, value->rep_frame,
2043 dcerpc_co_reassemble_table, alloc_hint);
2045 if (check_col(pinfo->cinfo, COL_INFO)) {
2046 col_append_fstr(pinfo->cinfo, COL_INFO,
2047 " [DCE/RPC fragment]");
2049 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
2050 if( value->rep_frame ){
2051 fragment_data *fd_head;
2054 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2055 dcerpc_co_reassemble_table);
2056 fd_head = fragment_add(tvb, offset, pinfo,
2058 dcerpc_co_reassemble_table,
2064 /* We completed reassembly */
2067 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2068 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2069 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2070 show_fragment_tree(fd_head, &dcerpc_frag_items,
2071 dcerpc_tree, pinfo, next_tvb);
2073 pinfo->fragmented = FALSE;
2074 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2076 0, value->opnum, FALSE, hdr->drep, &di,
2079 /* Reassembly not complete - some fragments
2081 if (check_col(pinfo->cinfo, COL_INFO)) {
2082 col_append_fstr(pinfo->cinfo, COL_INFO,
2083 " [DCE/RPC fragment]");
2087 } else { /* MIDDLE fragment(s) */
2088 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2090 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2091 dcerpc_co_reassemble_table);
2092 fragment_add(tvb, offset, pinfo, value->rep_frame,
2093 dcerpc_co_reassemble_table,
2098 if (check_col(pinfo->cinfo, COL_INFO)) {
2099 col_append_fstr(pinfo->cinfo, COL_INFO,
2100 " [DCE/RPC fragment]");
2104 pinfo->fragmented = save_fragmented;
2110 dissect_dcerpc_cn_fault (tvbuff_t *tvb, packet_info *pinfo,
2111 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2113 dcerpc_call_value *value = NULL;
2114 conversation_t *conv;
2122 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2123 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2125 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2126 hf_dcerpc_cn_ctx_id, &ctx_id);
2128 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2129 hf_dcerpc_cn_cancel_count, NULL);
2133 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2134 hf_dcerpc_cn_status, &status);
2136 if (check_col (pinfo->cinfo, COL_INFO)) {
2137 col_append_fstr (pinfo->cinfo, COL_INFO,
2138 " ctx_id: %u status: %s", ctx_id,
2139 val_to_str(status, reject_status_vals,
2140 "Unknown (0x%08x)"));
2147 * XXX - what if this was set when the connection was set up,
2148 * and we just have a security context?
2150 auth_sz = dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr,
2153 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2154 pinfo->srcport, pinfo->destport, 0);
2156 /* no point in creating one here, really */
2159 /* !!! we can NOT check flags.visited here since this will interact
2160 badly with when SMB handles (i.e. calls the subdissector)
2161 and desegmented pdu's .
2162 Instead we check if this pdu is already in the matched table or not
2164 if(!g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num)){
2165 dcerpc_call_key call_key;
2166 dcerpc_call_value *call_value;
2169 call_key.call_id=hdr->call_id;
2170 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2172 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2173 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2174 if(call_value->rep_frame==0){
2175 call_value->rep_frame=pinfo->fd->num;
2181 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2184 int length, reported_length, stub_length;
2186 gboolean save_fragmented;
2188 /* handoff this call */
2189 length = tvb_length_remaining(tvb, offset);
2190 reported_length = tvb_reported_length_remaining(tvb, offset);
2191 stub_length = hdr->frag_len - offset - auth_sz;
2192 if (length > stub_length)
2193 length = stub_length;
2194 if (reported_length > stub_length)
2195 reported_length = stub_length;
2197 di.call_id = hdr->call_id;
2198 di.smb_fid = get_smb_fid(pinfo->private_data);
2200 di.call_data = value;
2202 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2203 if(value->req_frame!=0){
2204 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2205 tvb, 0, 0, value->req_frame);
2208 save_fragmented = pinfo->fragmented;
2210 /* If we don't have reassembly enabled, or this packet contains
2211 the entire PDU, or if this is a short frame (or a frame
2212 not reassembled at a lower layer) that doesn't include all
2213 the data in the fragment, just call the handoff directly if
2214 this is the first fragment or the PDU isn't fragmented. */
2215 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
2216 stub_length > length ){
2217 if(hdr->flags&PFC_FIRST_FRAG){
2218 /* First fragment, possibly the only fragment */
2220 * XXX - should there be a third routine for each
2221 * function in an RPC subdissector, to handle
2222 * fault responses? The DCE RPC 1.1 spec says
2223 * three's "stub data" here, which I infer means
2224 * that it's protocol-specific and call-specific.
2226 * It should probably get passed the status code
2227 * as well, as that might be protocol-specific.
2231 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2232 "Fault stub data (%d byte%s)", length,
2233 plurality(length, "", "s"));
2237 /* PDU is fragmented and this isn't the first fragment */
2238 if (check_col(pinfo->cinfo, COL_INFO)) {
2239 col_append_fstr(pinfo->cinfo, COL_INFO,
2240 " [DCE/RPC fragment]");
2244 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2245 "Fragment data (%d byte%s)", length,
2246 plurality(length, "", "s"));
2251 /* Reassembly is enabled, the PDU is fragmented, and
2252 we have all the data in the fragment; the first two
2253 of those mean we should attempt reassembly, and the
2254 third means we can attempt reassembly. */
2257 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2258 "Fragment data (%d byte%s)", length,
2259 plurality(length, "", "s"));
2262 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
2263 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2264 fragment_add(tvb, offset, pinfo, value->rep_frame,
2265 dcerpc_co_reassemble_table,
2269 fragment_set_tot_len(pinfo, value->rep_frame,
2270 dcerpc_co_reassemble_table, alloc_hint);
2272 if (check_col(pinfo->cinfo, COL_INFO)) {
2273 col_append_fstr(pinfo->cinfo, COL_INFO,
2274 " [DCE/RPC fragment]");
2276 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
2277 if( value->rep_frame ){
2278 fragment_data *fd_head;
2281 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2282 dcerpc_co_reassemble_table);
2283 fd_head = fragment_add(tvb, offset, pinfo,
2285 dcerpc_co_reassemble_table,
2291 /* We completed reassembly */
2294 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2295 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2296 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2297 show_fragment_tree(fd_head, &dcerpc_frag_items,
2298 dcerpc_tree, pinfo, next_tvb);
2301 * XXX - should there be a third routine for each
2302 * function in an RPC subdissector, to handle
2303 * fault responses? The DCE RPC 1.1 spec says
2304 * three's "stub data" here, which I infer means
2305 * that it's protocol-specific and call-specific.
2307 * It should probably get passed the status code
2308 * as well, as that might be protocol-specific.
2312 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2313 "Fault stub data (%d byte%s)", length,
2314 plurality(length, "", "s"));
2318 /* Reassembly not complete - some fragments
2320 if (check_col(pinfo->cinfo, COL_INFO)) {
2321 col_append_fstr(pinfo->cinfo, COL_INFO,
2322 " [DCE/RPC fragment]");
2326 } else { /* MIDDLE fragment(s) */
2327 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2329 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2330 dcerpc_co_reassemble_table);
2331 fragment_add(tvb, offset, pinfo, value->rep_frame,
2332 dcerpc_co_reassemble_table,
2337 if (check_col(pinfo->cinfo, COL_INFO)) {
2338 col_append_fstr(pinfo->cinfo, COL_INFO,
2339 " [DCE/RPC fragment]");
2343 pinfo->fragmented = save_fragmented;
2349 * DCERPC dissector for connection oriented calls
2352 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
2353 proto_tree *tree, gboolean can_desegment)
2355 static char nulls[4] = { 0 };
2358 proto_item *ti = NULL;
2359 proto_item *tf = NULL;
2360 proto_tree *dcerpc_tree = NULL;
2361 proto_tree *cn_flags_tree = NULL;
2362 proto_tree *drep_tree = NULL;
2363 e_dce_cn_common_hdr_t hdr;
2366 * when done over nbt, dcerpc requests are padded with 4 bytes of null
2367 * data for some reason.
2369 * XXX - if that's always the case, the right way to do this would
2370 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
2371 * the 4 bytes of null padding, and make that the dissector
2372 * used for "netbios".
2374 if (tvb_bytes_exist (tvb, offset, 4) &&
2375 tvb_memeql (tvb, offset, nulls, 4) == 0) {
2385 * Check if this looks like a C/O DCERPC call
2387 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
2390 start_offset = offset;
2391 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
2392 if (hdr.rpc_ver != 5)
2394 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
2395 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
2397 hdr.ptype = tvb_get_guint8 (tvb, offset++);
2401 if (check_col (pinfo->cinfo, COL_PROTOCOL))
2402 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
2403 if (check_col (pinfo->cinfo, COL_INFO))
2404 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
2406 hdr.flags = tvb_get_guint8 (tvb, offset++);
2407 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
2408 offset += sizeof (hdr.drep);
2410 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2412 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
2414 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
2417 offset = start_offset;
2418 if (can_desegment && pinfo->can_desegment
2419 && hdr.frag_len > tvb_length_remaining (tvb, offset)) {
2420 pinfo->desegment_offset = offset;
2421 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, offset);
2422 return 0; /* desegmentation required */
2425 if (check_col (pinfo->cinfo, COL_INFO))
2426 col_append_fstr (pinfo->cinfo, COL_INFO, ": call_id: %u", hdr.call_id);
2428 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
2430 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
2432 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
2433 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
2434 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
2435 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
2436 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
2437 if (cn_flags_tree) {
2438 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
2439 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
2440 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
2441 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
2442 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
2443 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
2444 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
2445 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
2449 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
2450 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
2452 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
2453 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
2454 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
2456 offset += sizeof (hdr.drep);
2458 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
2461 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
2464 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
2470 * Packet type specific stuff is next.
2472 switch (hdr.ptype) {
2475 dissect_dcerpc_cn_bind (tvb, pinfo, dcerpc_tree, &hdr);
2480 dissect_dcerpc_cn_bind_ack (tvb, pinfo, dcerpc_tree, &hdr);
2484 dissect_dcerpc_cn_rqst (tvb, pinfo, dcerpc_tree, tree, &hdr);
2488 dissect_dcerpc_cn_resp (tvb, pinfo, dcerpc_tree, tree, &hdr);
2492 dissect_dcerpc_cn_fault (tvb, pinfo, dcerpc_tree, &hdr);
2496 dissect_dcerpc_cn_bind_nak (tvb, pinfo, dcerpc_tree, &hdr);
2502 * Nothing after the common header other than an authentication
2505 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, NULL);
2510 * Nothing after the common header, not even an authentication
2516 /* might as well dissect the auth info */
2517 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, NULL);
2520 return hdr.frag_len + padding;
2524 * DCERPC dissector for connection oriented calls over packet-oriented
2528 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2531 * Only one PDU per transport packet, and only one transport
2534 if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
2536 * It wasn't a DCERPC PDU.
2548 * DCERPC dissector for connection oriented calls over byte-stream
2552 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2556 gboolean ret = FALSE;
2559 * There may be multiple PDUs per transport packet; keep
2562 while (tvb_reported_length_remaining(tvb, offset) != 0) {
2563 pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
2564 dcerpc_cn_desegment);
2565 if (pdu_len == -1) {
2573 * Well, we've seen at least one DCERPC PDU.
2579 * Desegmentation required - bail now.
2585 * Step to the next PDU.
2593 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
2594 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
2597 * Initially set "*auth_level_p" to -1 to indicate that we haven't
2598 * yet seen any authentication level information.
2600 if (auth_level_p != NULL)
2604 * The authentication information is at the *end* of the PDU; in
2605 * request and response PDUs, the request and response stub data
2608 * If the full packet is here, and there's data past the end of the
2609 * packet body, then dissect the auth info.
2611 offset += hdr->frag_len;
2612 if (tvb_length_remaining(tvb, offset) > 0)
2613 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Auth data");
2617 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
2618 proto_tree *dcerpc_tree,
2619 e_dce_dg_common_hdr_t *hdr)
2623 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2624 hdr->drep, hf_dcerpc_dg_cancel_vers,
2630 /* The only version we know about */
2631 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2632 hdr->drep, hf_dcerpc_dg_cancel_id,
2634 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2635 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
2642 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
2643 proto_tree *dcerpc_tree,
2644 e_dce_dg_common_hdr_t *hdr)
2648 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2649 hdr->drep, hf_dcerpc_dg_cancel_vers,
2655 /* The only version we know about */
2656 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2657 hdr->drep, hf_dcerpc_dg_cancel_id,
2659 /* XXX - are NDR booleans 32 bits? */
2660 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2661 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
2668 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
2669 proto_tree *dcerpc_tree,
2670 e_dce_dg_common_hdr_t *hdr)
2677 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2678 hdr->drep, hf_dcerpc_dg_fack_vers,
2685 case 0: /* The only version documented in the DCE RPC 1.1 spec */
2686 case 1: /* This appears to be the same */
2687 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2688 hdr->drep, hf_dcerpc_dg_fack_window_size,
2690 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2691 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
2693 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2694 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
2696 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2697 hdr->drep, hf_dcerpc_dg_fack_serial_num,
2699 if (check_col (pinfo->cinfo, COL_INFO)) {
2700 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
2703 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2704 hdr->drep, hf_dcerpc_dg_fack_selack_len,
2706 for (i = 0; i < selack_len; i++) {
2707 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2708 hdr->drep, hf_dcerpc_dg_fack_selack,
2717 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
2718 proto_tree *dcerpc_tree,
2719 e_dce_dg_common_hdr_t *hdr)
2723 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
2724 hdr->drep, hf_dcerpc_dg_status,
2727 if (check_col (pinfo->cinfo, COL_INFO)) {
2728 col_append_fstr (pinfo->cinfo, COL_INFO,
2730 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
2735 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
2736 proto_tree *dcerpc_tree, proto_tree *tree,
2737 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
2739 int length, reported_length, stub_length;
2741 dcerpc_call_value *value, v;
2742 gboolean save_fragmented;
2743 fragment_data *fd_head;
2745 if(!(pinfo->fd->flags.visited)){
2746 dcerpc_call_value *call_value;
2747 dcerpc_call_key *call_key;
2749 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
2750 call_key->conv=conv;
2751 call_key->call_id=hdr->seqnum;
2752 call_key->smb_fid=get_smb_fid(pinfo->private_data);
2754 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2755 call_value->uuid = hdr->if_id;
2756 call_value->ver = hdr->if_ver;
2757 call_value->opnum = hdr->opnum;
2758 call_value->req_frame=pinfo->fd->num;
2759 call_value->rep_frame=0;
2760 call_value->max_ptr=0;
2761 call_value->private_data = NULL;
2762 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2764 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2767 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2769 v.uuid = hdr->if_id;
2770 v.ver = hdr->if_ver;
2771 v.opnum = hdr->opnum;
2772 v.req_frame = pinfo->fd->num;
2775 v.private_data=NULL;
2779 if (check_col (pinfo->cinfo, COL_INFO)) {
2780 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u", hdr->opnum);
2783 length = tvb_length_remaining (tvb, offset);
2784 reported_length = tvb_reported_length_remaining (tvb, offset);
2785 stub_length = hdr->frag_len;
2786 if (length > stub_length)
2787 length = stub_length;
2788 if (reported_length > stub_length)
2789 reported_length = stub_length;
2792 di.call_id = hdr->seqnum;
2795 di.call_data = value;
2797 save_fragmented = pinfo->fragmented;
2799 /* If we don't have reassembly enabled, or this packet contains
2800 the entire PDU, or if this is a short frame (or a frame
2801 not reassembled at a lower layer) that doesn't include all
2802 the data in the fragment, just call the handoff directly if
2803 this is the first fragment or the PDU isn't fragmented. */
2804 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
2805 stub_length > length ) {
2806 if(hdr->frag_num == 0) {
2807 /* First fragment, possibly the only fragment */
2810 * XXX - authentication level?
2812 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
2813 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2814 tvb_new_subset (tvb, offset, length,
2816 0, hdr->opnum, TRUE, hdr->drep, &di, 0);
2818 /* PDU is fragmented and this isn't the first fragment */
2819 if (check_col(pinfo->cinfo, COL_INFO)) {
2820 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
2824 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2825 "Fragment data (%d byte%s)", length,
2826 plurality(length, "", "s"));
2831 /* Reassembly is enabled, the PDU is fragmented, and
2832 we have all the data in the fragment; the first two
2833 of those mean we should attempt reassembly, and the
2834 third means we can attempt reassembly. */
2837 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2838 "Fragment data (%d byte%s)", length,
2839 plurality(length, "", "s"));
2843 fd_head = fragment_add_seq(tvb, offset, pinfo,
2844 hdr->seqnum, dcerpc_cl_reassemble_table,
2845 hdr->frag_num, length, !(hdr->flags1 & PFCL1_LASTFRAG));
2846 if (fd_head != NULL) {
2847 /* We completed reassembly */
2850 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
2851 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2852 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2853 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
2854 dcerpc_tree, pinfo, next_tvb);
2857 * XXX - authentication level?
2859 pinfo->fragmented = FALSE;
2860 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
2861 0, hdr->opnum, TRUE, hdr->drep, &di, 0);
2863 /* Reassembly isn't completed yet */
2864 if (check_col(pinfo->cinfo, COL_INFO)) {
2865 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
2869 pinfo->fragmented = save_fragmented;
2873 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
2874 proto_tree *dcerpc_tree, proto_tree *tree,
2875 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
2877 int length, reported_length, stub_length;
2879 dcerpc_call_value *value, v;
2880 gboolean save_fragmented;
2881 fragment_data *fd_head;
2883 if(!(pinfo->fd->flags.visited)){
2884 dcerpc_call_value *call_value;
2885 dcerpc_call_key call_key;
2888 call_key.call_id=hdr->seqnum;
2889 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2891 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2892 g_hash_table_insert (dcerpc_matched, (void *)pinfo->fd->num, call_value);
2893 if(call_value->rep_frame==0){
2894 call_value->rep_frame=pinfo->fd->num;
2899 value=g_hash_table_lookup(dcerpc_matched, (void *)pinfo->fd->num);
2901 v.uuid = hdr->if_id;
2902 v.ver = hdr->if_ver;
2903 v.opnum = hdr->opnum;
2905 v.rep_frame=pinfo->fd->num;
2906 v.private_data=NULL;
2910 if (check_col (pinfo->cinfo, COL_INFO)) {
2911 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u", value->opnum);
2914 length = tvb_length_remaining (tvb, offset);
2915 reported_length = tvb_reported_length_remaining (tvb, offset);
2916 stub_length = hdr->frag_len;
2917 if (length > stub_length)
2918 length = stub_length;
2919 if (reported_length > stub_length)
2920 reported_length = stub_length;
2926 di.call_data = value;
2928 save_fragmented = pinfo->fragmented;
2930 /* If we don't have reassembly enabled, or this packet contains
2931 the entire PDU, or if this is a short frame (or a frame
2932 not reassembled at a lower layer) that doesn't include all
2933 the data in the fragment, just call the handoff directly if
2934 this is the first fragment or the PDU isn't fragmented. */
2935 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
2936 stub_length > length ) {
2937 if(hdr->frag_num == 0) {
2938 /* First fragment, possibly the only fragment */
2941 * XXX - authentication level?
2943 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
2944 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
2945 tvb_new_subset (tvb, offset, length,
2947 0, value->opnum, FALSE, hdr->drep, &di, 0);
2949 /* PDU is fragmented and this isn't the first fragment */
2950 if (check_col(pinfo->cinfo, COL_INFO)) {
2951 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
2955 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2956 "Fragment data (%d byte%s)", length,
2957 plurality(length, "", "s"));
2962 /* Reassembly is enabled, the PDU is fragmented, and
2963 we have all the data in the fragment; the first two
2964 of those mean we should attempt reassembly, and the
2965 third means we can attempt reassembly. */
2968 proto_tree_add_text (dcerpc_tree, tvb, offset, length,
2969 "Fragment data (%d byte%s)", length,
2970 plurality(length, "", "s"));
2974 fd_head = fragment_add_seq(tvb, offset, pinfo,
2975 hdr->seqnum, dcerpc_cl_reassemble_table,
2976 hdr->frag_num, length, !(hdr->flags1 & PFCL1_LASTFRAG));
2977 if (fd_head != NULL) {
2978 /* We completed reassembly */
2981 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
2982 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2983 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2984 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
2985 dcerpc_tree, pinfo, next_tvb);
2988 * XXX - authentication level?
2990 pinfo->fragmented = FALSE;
2991 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
2992 0, value->opnum, FALSE, hdr->drep, &di, 0);
2994 /* Reassembly isn't completed yet */
2995 if (check_col(pinfo->cinfo, COL_INFO)) {
2996 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3000 pinfo->fragmented = save_fragmented;
3004 * DCERPC dissector for connectionless calls
3007 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3009 proto_item *ti = NULL;
3010 proto_item *tf = NULL;
3011 proto_tree *dcerpc_tree = NULL;
3012 proto_tree *dg_flags1_tree = NULL;
3013 proto_tree *dg_flags2_tree = NULL;
3014 proto_tree *drep_tree = NULL;
3015 e_dce_dg_common_hdr_t hdr;
3017 conversation_t *conv;
3020 * Check if this looks like a CL DCERPC call. All dg packets
3021 * have an 80 byte header on them. Which starts with
3022 * version (4), pkt_type.
3024 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
3027 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3028 if (hdr.rpc_ver != 4)
3030 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3034 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3035 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3036 if (check_col (pinfo->cinfo, COL_INFO))
3037 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
3039 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
3040 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
3041 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3042 offset += sizeof (hdr.drep);
3043 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
3044 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
3046 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
3048 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
3050 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3052 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3054 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3056 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3058 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3060 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3062 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3064 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3066 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
3067 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
3070 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
3072 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
3078 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3082 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3086 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
3087 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
3088 if (dg_flags1_tree) {
3089 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
3090 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
3091 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
3092 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
3093 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
3094 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
3095 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
3096 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
3102 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
3103 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
3104 if (dg_flags2_tree) {
3105 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
3106 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
3107 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
3108 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
3109 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
3110 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
3111 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
3112 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
3118 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
3119 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3121 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3122 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3123 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3126 offset += sizeof (hdr.drep);
3129 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
3133 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3135 "Object: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3136 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
3137 hdr.obj_id.Data4[0],
3138 hdr.obj_id.Data4[1],
3139 hdr.obj_id.Data4[2],
3140 hdr.obj_id.Data4[3],
3141 hdr.obj_id.Data4[4],
3142 hdr.obj_id.Data4[5],
3143 hdr.obj_id.Data4[6],
3144 hdr.obj_id.Data4[7]);
3149 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
3151 "Interface: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3152 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
3160 hdr.if_id.Data4[7]);
3165 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
3167 "Activity: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3168 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
3169 hdr.act_id.Data4[0],
3170 hdr.act_id.Data4[1],
3171 hdr.act_id.Data4[2],
3172 hdr.act_id.Data4[3],
3173 hdr.act_id.Data4[4],
3174 hdr.act_id.Data4[5],
3175 hdr.act_id.Data4[6],
3176 hdr.act_id.Data4[7]);
3181 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
3185 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
3189 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
3190 if (check_col (pinfo->cinfo, COL_INFO)) {
3191 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq_num: %u", hdr.seqnum);
3196 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
3200 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
3204 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
3208 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
3212 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
3213 if (check_col (pinfo->cinfo, COL_INFO)) {
3214 if (hdr.flags1 & PFCL1_FRAG) {
3215 /* Fragmented - put the fragment number into the Info column */
3216 col_append_fstr (pinfo->cinfo, COL_INFO, " frag_num: %u",
3223 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
3227 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
3228 if (check_col (pinfo->cinfo, COL_INFO)) {
3229 if (hdr.flags1 & PFCL1_FRAG) {
3230 /* Fragmented - put the serial number into the Info column */
3231 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3232 (hdr.serial_hi << 8) | hdr.serial_lo);
3239 * XXX - for Kerberos, we can get a protection level; if it's
3240 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
3243 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr, NULL);
3247 * keeping track of the conversation shouldn't really be necessary
3248 * for connectionless packets, because everything we need to know
3249 * to dissect is in the header for each packet. Unfortunately,
3250 * Microsoft's implementation is buggy and often puts the
3251 * completely wrong if_id in the header. go figure. So, keep
3252 * track of the seqnum and use that if possible. Note: that's not
3253 * completely correct. It should really be done based on both the
3254 * activity_id and seqnum. I haven't seen anywhere that it would
3255 * make a difference, but for future reference...
3257 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
3258 pinfo->srcport, pinfo->destport, 0);
3260 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
3261 pinfo->srcport, pinfo->destport, 0);
3265 * Packet type specific stuff is next.
3268 switch (hdr.ptype) {
3270 case PDU_CANCEL_ACK:
3271 /* Body is optional */
3272 /* XXX - we assume "frag_len" is the length of the body */
3273 if (hdr.frag_len != 0)
3274 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3279 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
3280 * but in at least one capture none of the Cl_cancel PDUs had a
3283 /* XXX - we assume "frag_len" is the length of the body */
3284 if (hdr.frag_len != 0)
3285 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
3289 /* Body is optional; if present, it's the same as PDU_FACK */
3290 /* XXX - we assume "frag_len" is the length of the body */
3291 if (hdr.frag_len != 0)
3292 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3296 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3301 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3305 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
3309 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
3312 /* these requests have no body */
3324 dcerpc_init_protocol (void)
3326 /* structures and data for BIND */
3328 g_hash_table_destroy (dcerpc_binds);
3330 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
3332 if (dcerpc_bind_key_chunk){
3333 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
3335 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
3336 sizeof (dcerpc_bind_key),
3337 200 * sizeof (dcerpc_bind_key),
3339 if (dcerpc_bind_value_chunk){
3340 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
3342 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
3343 sizeof (dcerpc_bind_value),
3344 200 * sizeof (dcerpc_bind_value),
3346 /* structures and data for CALL */
3348 g_hash_table_destroy (dcerpc_calls);
3350 dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
3351 if (dcerpc_call_key_chunk){
3352 g_mem_chunk_destroy (dcerpc_call_key_chunk);
3354 dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
3355 sizeof (dcerpc_call_key),
3356 200 * sizeof (dcerpc_call_key),
3358 if (dcerpc_call_value_chunk){
3359 g_mem_chunk_destroy (dcerpc_call_value_chunk);
3361 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
3362 sizeof (dcerpc_call_value),
3363 200 * sizeof (dcerpc_call_value),
3366 /* structure and data for MATCHED */
3367 if (dcerpc_matched){
3368 g_hash_table_destroy (dcerpc_matched);
3370 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
3375 proto_register_dcerpc (void)
3377 static hf_register_info hf[] = {
3378 { &hf_dcerpc_request_in,
3379 { "Request in", "dcerpc.request_in", FT_UINT32, BASE_DEC,
3380 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
3381 { &hf_dcerpc_response_in,
3382 { "Response in", "dcerpc.response_in", FT_UINT32, BASE_DEC,
3383 NULL, 0, "The response to this packet is in this packet", HFILL }},
3384 { &hf_dcerpc_referent_id,
3385 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
3386 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
3388 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3389 { &hf_dcerpc_ver_minor,
3390 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3391 { &hf_dcerpc_packet_type,
3392 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
3393 { &hf_dcerpc_cn_flags,
3394 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3395 { &hf_dcerpc_cn_flags_first_frag,
3396 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
3397 { &hf_dcerpc_cn_flags_last_frag,
3398 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
3399 { &hf_dcerpc_cn_flags_cancel_pending,
3400 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
3401 { &hf_dcerpc_cn_flags_reserved,
3402 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
3403 { &hf_dcerpc_cn_flags_mpx,
3404 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
3405 { &hf_dcerpc_cn_flags_dne,
3406 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
3407 { &hf_dcerpc_cn_flags_maybe,
3408 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
3409 { &hf_dcerpc_cn_flags_object,
3410 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
3412 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
3413 { &hf_dcerpc_drep_byteorder,
3414 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
3415 { &hf_dcerpc_drep_character,
3416 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
3417 { &hf_dcerpc_drep_fp,
3418 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
3419 { &hf_dcerpc_cn_frag_len,
3420 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3421 { &hf_dcerpc_cn_auth_len,
3422 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3423 { &hf_dcerpc_cn_call_id,
3424 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3425 { &hf_dcerpc_cn_max_xmit,
3426 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3427 { &hf_dcerpc_cn_max_recv,
3428 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3429 { &hf_dcerpc_cn_assoc_group,
3430 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
3431 { &hf_dcerpc_cn_num_ctx_items,
3432 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3433 { &hf_dcerpc_cn_ctx_id,
3434 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3435 { &hf_dcerpc_cn_num_trans_items,
3436 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3437 { &hf_dcerpc_cn_bind_if_id,
3438 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3439 { &hf_dcerpc_cn_bind_if_ver,
3440 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3441 { &hf_dcerpc_cn_bind_if_ver_minor,
3442 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3443 { &hf_dcerpc_cn_bind_trans_id,
3444 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3445 { &hf_dcerpc_cn_bind_trans_ver,
3446 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3447 { &hf_dcerpc_cn_alloc_hint,
3448 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3449 { &hf_dcerpc_cn_sec_addr_len,
3450 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3451 { &hf_dcerpc_cn_sec_addr,
3452 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
3453 { &hf_dcerpc_cn_num_results,
3454 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3455 { &hf_dcerpc_cn_ack_result,
3456 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
3457 { &hf_dcerpc_cn_ack_reason,
3458 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
3459 { &hf_dcerpc_cn_ack_trans_id,
3460 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3461 { &hf_dcerpc_cn_ack_trans_ver,
3462 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3463 { &hf_dcerpc_cn_reject_reason,
3464 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
3465 { &hf_dcerpc_cn_num_protocols,
3466 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3467 { &hf_dcerpc_cn_protocol_ver_major,
3468 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3469 { &hf_dcerpc_cn_protocol_ver_minor,
3470 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3471 { &hf_dcerpc_cn_cancel_count,
3472 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3473 { &hf_dcerpc_cn_status,
3474 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
3475 { &hf_dcerpc_auth_type,
3476 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
3477 { &hf_dcerpc_auth_level,
3478 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
3479 { &hf_dcerpc_auth_pad_len,
3480 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3481 { &hf_dcerpc_auth_rsrvd,
3482 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3483 { &hf_dcerpc_auth_ctx_id,
3484 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3485 { &hf_dcerpc_dg_flags1,
3486 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3487 { &hf_dcerpc_dg_flags1_rsrvd_01,
3488 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
3489 { &hf_dcerpc_dg_flags1_last_frag,
3490 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
3491 { &hf_dcerpc_dg_flags1_frag,
3492 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
3493 { &hf_dcerpc_dg_flags1_nofack,
3494 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
3495 { &hf_dcerpc_dg_flags1_maybe,
3496 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
3497 { &hf_dcerpc_dg_flags1_idempotent,
3498 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
3499 { &hf_dcerpc_dg_flags1_broadcast,
3500 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
3501 { &hf_dcerpc_dg_flags1_rsrvd_80,
3502 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
3503 { &hf_dcerpc_dg_flags2,
3504 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3505 { &hf_dcerpc_dg_flags2_rsrvd_01,
3506 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
3507 { &hf_dcerpc_dg_flags2_cancel_pending,
3508 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
3509 { &hf_dcerpc_dg_flags2_rsrvd_04,
3510 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
3511 { &hf_dcerpc_dg_flags2_rsrvd_08,
3512 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
3513 { &hf_dcerpc_dg_flags2_rsrvd_10,
3514 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
3515 { &hf_dcerpc_dg_flags2_rsrvd_20,
3516 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
3517 { &hf_dcerpc_dg_flags2_rsrvd_40,
3518 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
3519 { &hf_dcerpc_dg_flags2_rsrvd_80,
3520 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
3521 { &hf_dcerpc_dg_serial_lo,
3522 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3523 { &hf_dcerpc_dg_serial_hi,
3524 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
3525 { &hf_dcerpc_dg_ahint,
3526 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
3527 { &hf_dcerpc_dg_ihint,
3528 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
3529 { &hf_dcerpc_dg_frag_len,
3530 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3531 { &hf_dcerpc_dg_frag_num,
3532 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3533 { &hf_dcerpc_dg_auth_proto,
3534 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
3535 { &hf_dcerpc_dg_seqnum,
3536 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3537 { &hf_dcerpc_dg_server_boot,
3538 { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
3539 { &hf_dcerpc_dg_if_ver,
3540 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3541 { &hf_dcerpc_obj_id,
3542 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3543 { &hf_dcerpc_dg_if_id,
3544 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3545 { &hf_dcerpc_dg_act_id,
3546 { "Activitiy", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
3548 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3550 { &hf_dcerpc_dg_cancel_vers,
3551 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3553 { &hf_dcerpc_dg_cancel_id,
3554 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3556 { &hf_dcerpc_dg_server_accepting_cancels,
3557 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
3559 { &hf_dcerpc_dg_fack_vers,
3560 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
3562 { &hf_dcerpc_dg_fack_window_size,
3563 { "Window Size", "dcerpc.fack_window size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3565 { &hf_dcerpc_dg_fack_max_tsdu,
3566 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3568 { &hf_dcerpc_dg_fack_max_frag_size,
3569 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
3571 { &hf_dcerpc_dg_fack_serial_num,
3572 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3574 { &hf_dcerpc_dg_fack_selack_len,
3575 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3577 { &hf_dcerpc_dg_fack_selack,
3578 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
3580 { &hf_dcerpc_dg_status,
3581 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
3583 { &hf_dcerpc_array_max_count,
3584 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
3586 { &hf_dcerpc_array_offset,
3587 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
3589 { &hf_dcerpc_array_actual_count,
3590 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
3593 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
3595 { &hf_dcerpc_fragments,
3596 { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
3597 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
3599 { &hf_dcerpc_fragment,
3600 { "DCE/RPC Fragment", "dcerpc.fragment", FT_NONE, BASE_NONE,
3601 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
3603 { &hf_dcerpc_fragment_overlap,
3604 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
3606 { &hf_dcerpc_fragment_overlap_conflict,
3607 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
3609 { &hf_dcerpc_fragment_multiple_tails,
3610 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
3612 { &hf_dcerpc_fragment_too_long_fragment,
3613 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
3615 { &hf_dcerpc_fragment_error,
3616 { "Defragmentation error", "dcerpc.fragment.error", FT_NONE, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
3619 static gint *ett[] = {
3621 &ett_dcerpc_cn_flags,
3623 &ett_dcerpc_dg_flags1,
3624 &ett_dcerpc_dg_flags2,
3625 &ett_dcerpc_pointer_data,
3626 &ett_dcerpc_fragments,
3627 &ett_dcerpc_fragment,
3629 module_t *dcerpc_module;
3631 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
3632 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
3633 proto_register_subtree_array (ett, array_length (ett));
3634 register_init_routine (dcerpc_init_protocol);
3635 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
3636 prefs_register_bool_preference (dcerpc_module,
3638 "Desegment all DCE/RPC over TCP",
3639 "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
3640 &dcerpc_cn_desegment);
3641 prefs_register_bool_preference (dcerpc_module,
3642 "reassemble_dcerpc",
3643 "Reassemble DCE/RPC fragments",
3644 "Whether the DCE/RPC dissector should reassemble all fragmented PDUs",
3645 &dcerpc_reassemble);
3646 register_init_routine(dcerpc_reassemble_init);
3647 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
3651 proto_reg_handoff_dcerpc (void)
3653 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
3654 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
3655 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
3656 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);