2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas@webspan.net>
4 * Copyright 2003, Tim Potter <tpot@samba.org>
6 * $Id: packet-dcerpc.c,v 1.142 2003/09/26 06:30:13 tpot Exp $
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@ethereal.com>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 #include <epan/packet.h>
36 #include "packet-dcerpc.h"
37 #include <epan/conversation.h>
39 #include "reassemble.h"
41 #include "packet-frame.h"
42 #include "packet-dcerpc-nt.h"
44 static int dcerpc_tap = -1;
47 static const value_string pckt_vals[] = {
48 { PDU_REQ, "Request"},
50 { PDU_RESP, "Response"},
51 { PDU_FAULT, "Fault"},
52 { PDU_WORKING, "Working"},
53 { PDU_NOCALL, "Nocall"},
54 { PDU_REJECT, "Reject"},
56 { PDU_CL_CANCEL, "Cl_cancel"},
58 { PDU_CANCEL_ACK, "Cancel_ack"},
60 { PDU_BIND_ACK, "Bind_ack"},
61 { PDU_BIND_NAK, "Bind_nak"},
62 { PDU_ALTER, "Alter_context"},
63 { PDU_ALTER_ACK, "Alter_context_resp"},
64 { PDU_AUTH3, "AUTH3"},
65 { PDU_SHUTDOWN, "Shutdown"},
66 { PDU_CO_CANCEL, "Co_cancel"},
67 { PDU_ORPHANED, "Orphaned"},
71 static const value_string drep_byteorder_vals[] = {
73 { 1, "Little-endian" },
77 static const value_string drep_character_vals[] = {
83 #define DCE_RPC_DREP_FP_IEEE 0
84 #define DCE_RPC_DREP_FP_VAX 1
85 #define DCE_RPC_DREP_FP_CRAY 2
86 #define DCE_RPC_DREP_FP_IBM 3
88 static const value_string drep_fp_vals[] = {
89 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
90 { DCE_RPC_DREP_FP_VAX, "VAX" },
91 { DCE_RPC_DREP_FP_CRAY, "Cray" },
92 { DCE_RPC_DREP_FP_IBM, "IBM" },
97 * Authentication services.
99 static const value_string authn_protocol_vals[] = {
100 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
101 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
102 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
103 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
104 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN,"NETLOGON Secure Channel" },
111 static const value_string authn_level_vals[] = {
112 { DCE_C_AUTHN_LEVEL_NONE, "None" },
113 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
114 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
115 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
116 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
117 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
122 * Flag bits in first flag field in connectionless PDU header.
124 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
125 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
126 * fragment of a multi-PDU
128 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
129 a multi-PDU transmission */
130 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
131 * requested to send a `fack' PDU
132 * for the fragment */
133 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
135 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
137 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
139 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
142 * Flag bits in second flag field in connectionless PDU header.
144 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
145 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
146 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
147 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
148 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
149 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
150 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
151 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
154 * Flag bits in connection-oriented PDU header.
156 #define PFC_FIRST_FRAG 0x01 /* First fragment */
157 #define PFC_LAST_FRAG 0x02 /* Last fragment */
158 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
159 #define PFC_RESERVED_1 0x08
160 #define PFC_CONC_MPX 0x10 /* suports concurrent multiplexing
161 * of a single connection. */
162 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
163 * if true, guaranteed call did not
165 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
166 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
167 * was specified in the handle, and
168 * is present in the optional object
169 * field. If false, the object field
173 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
174 * it's not fragmented (i.e., this is both the first *and* last fragment),
175 * and FALSE otherwise.
177 #define PFC_NOT_FRAGMENTED(hdr) \
178 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG))==(PFC_FIRST_FRAG|PFC_LAST_FRAG))
181 * Presentation context negotiation result.
183 static const value_string p_cont_result_vals[] = {
185 { 1, "User rejection" },
186 { 2, "Provider rejection" },
191 * Presentation context negotiation rejection reasons.
193 static const value_string p_provider_reason_vals[] = {
194 { 0, "Reason not specified" },
195 { 1, "Abstract syntax not supported" },
196 { 2, "Proposed transfer syntaxes not supported" },
197 { 3, "Local limit exceeded" },
204 #define REASON_NOT_SPECIFIED 0
205 #define TEMPORARY_CONGESTION 1
206 #define LOCAL_LIMIT_EXCEEDED 2
207 #define CALLED_PADDR_UNKNOWN 3 /* not used */
208 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
209 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
210 #define USER_DATA_NOT_READABLE 6 /* not used */
211 #define NO_PSAP_AVAILABLE 7 /* not used */
213 static const value_string reject_reason_vals[] = {
214 { REASON_NOT_SPECIFIED, "Reason not specified" },
215 { TEMPORARY_CONGESTION, "Temporary congestion" },
216 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
217 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
218 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
219 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
220 { USER_DATA_NOT_READABLE, "User data not readable" },
221 { NO_PSAP_AVAILABLE, "No PSAP available" },
226 * Reject status codes.
228 static const value_string reject_status_vals[] = {
229 { 0, "Stub-defined exception" },
230 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
231 { 0x1c000002, "nca_s_fault_addr_error" },
232 { 0x1c000003, "nca_s_fault_fp_div_zero" },
233 { 0x1c000004, "nca_s_fault_fp_underflow" },
234 { 0x1c000005, "nca_s_fault_fp_overflow" },
235 { 0x1c000006, "nca_s_fault_invalid_tag" },
236 { 0x1c000007, "nca_s_fault_invalid_bound" },
237 { 0x1c000008, "nca_rpc_version_mismatch" },
238 { 0x1c000009, "nca_unspec_reject" },
239 { 0x1c00000a, "nca_s_bad_actid" },
240 { 0x1c00000b, "nca_who_are_you_failed" },
241 { 0x1c00000c, "nca_manager_not_entered" },
242 { 0x1c00000d, "nca_s_fault_cancel" },
243 { 0x1c00000e, "nca_s_fault_ill_inst" },
244 { 0x1c00000f, "nca_s_fault_fp_error" },
245 { 0x1c000010, "nca_s_fault_int_overflow" },
246 { 0x1c000014, "nca_s_fault_pipe_empty" },
247 { 0x1c000015, "nca_s_fault_pipe_closed" },
248 { 0x1c000016, "nca_s_fault_pipe_order" },
249 { 0x1c000017, "nca_s_fault_pipe_discipline" },
250 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
251 { 0x1c000019, "nca_s_fault_pipe_memory" },
252 { 0x1c00001a, "nca_s_fault_context_mismatch" },
253 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
254 { 0x1c00001c, "nca_invalid_pres_context_id" },
255 { 0x1c00001d, "nca_unsupported_authn_level" },
256 { 0x1c00001f, "nca_invalid_checksum" },
257 { 0x1c000020, "nca_invalid_crc" },
258 { 0x1c000021, "ncs_s_fault_user_defined" },
259 { 0x1c000022, "nca_s_fault_tx_open_failed" },
260 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
261 { 0x1c000024, "nca_s_fault_object_not_found" },
262 { 0x1c000025, "nca_s_fault_no_client_stub" },
263 { 0x1c010002, "nca_op_rng_error" },
264 { 0x1c010003, "nca_unk_if"},
265 { 0x1c010006, "nca_wrong_boot_time" },
266 { 0x1c010009, "nca_s_you_crashed" },
267 { 0x1c01000b, "nca_proto_error" },
268 { 0x1c010013, "nca_out_args_too_big" },
269 { 0x1c010014, "nca_server_too_busy" },
270 { 0x1c010017, "nca_unsupported_type" },
274 static int proto_dcerpc = -1;
277 static int hf_dcerpc_request_in = -1;
278 static int hf_dcerpc_time = -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_krb5_av_prot_level = -1;
362 static int hf_dcerpc_krb5_av_key_vers_num = -1;
363 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
364 static int hf_dcerpc_dg_cancel_vers = -1;
365 static int hf_dcerpc_dg_cancel_id = -1;
366 static int hf_dcerpc_dg_server_accepting_cancels = -1;
367 static int hf_dcerpc_dg_fack_vers = -1;
368 static int hf_dcerpc_dg_fack_window_size = -1;
369 static int hf_dcerpc_dg_fack_max_tsdu = -1;
370 static int hf_dcerpc_dg_fack_max_frag_size = -1;
371 static int hf_dcerpc_dg_fack_serial_num = -1;
372 static int hf_dcerpc_dg_fack_selack_len = -1;
373 static int hf_dcerpc_dg_fack_selack = -1;
374 static int hf_dcerpc_dg_status = -1;
375 static int hf_dcerpc_array_max_count = -1;
376 static int hf_dcerpc_array_offset = -1;
377 static int hf_dcerpc_array_actual_count = -1;
378 static int hf_dcerpc_array_buffer = -1;
379 static int hf_dcerpc_op = -1;
380 static int hf_dcerpc_referent_id = -1;
381 static int hf_dcerpc_fragments = -1;
382 static int hf_dcerpc_fragment = -1;
383 static int hf_dcerpc_fragment_overlap = -1;
384 static int hf_dcerpc_fragment_overlap_conflict = -1;
385 static int hf_dcerpc_fragment_multiple_tails = -1;
386 static int hf_dcerpc_fragment_too_long_fragment = -1;
387 static int hf_dcerpc_fragment_error = -1;
388 static int hf_dcerpc_reassembled_in = -1;
390 static gint ett_dcerpc = -1;
391 static gint ett_dcerpc_cn_flags = -1;
392 static gint ett_dcerpc_cn_ctx = -1;
393 static gint ett_dcerpc_cn_iface = -1;
394 static gint ett_dcerpc_drep = -1;
395 static gint ett_dcerpc_dg_flags1 = -1;
396 static gint ett_dcerpc_dg_flags2 = -1;
397 static gint ett_dcerpc_pointer_data = -1;
398 static gint ett_dcerpc_string = -1;
399 static gint ett_dcerpc_fragments = -1;
400 static gint ett_dcerpc_fragment = -1;
401 static gint ett_dcerpc_krb5_auth_verf = -1;
403 static const fragment_items dcerpc_frag_items = {
404 &ett_dcerpc_fragments,
405 &ett_dcerpc_fragment,
407 &hf_dcerpc_fragments,
409 &hf_dcerpc_fragment_overlap,
410 &hf_dcerpc_fragment_overlap_conflict,
411 &hf_dcerpc_fragment_multiple_tails,
412 &hf_dcerpc_fragment_too_long_fragment,
413 &hf_dcerpc_fragment_error,
424 static dcerpc_info di[20];
425 static int di_counter=0;
431 return &di[di_counter];
434 /* try to desegment big DCE/RPC packets over TCP? */
435 static gboolean dcerpc_cn_desegment = TRUE;
437 /* reassemble DCE/RPC fragments */
438 /* reassembly of dcerpc fragments will not work for the case where ONE frame
439 might contain multiple dcerpc fragments for different PDUs.
440 this case would be so unusual/weird so if you got captures like that:
443 static gboolean dcerpc_reassemble = FALSE;
444 static GHashTable *dcerpc_co_reassemble_table = NULL;
445 static GHashTable *dcerpc_cl_reassemble_table = NULL;
448 dcerpc_reassemble_init(void)
450 fragment_table_init(&dcerpc_co_reassemble_table);
451 fragment_table_init(&dcerpc_cl_reassemble_table);
455 * Authentication subdissectors. Used to dissect authentication blobs in
456 * DCERPC binds, requests and responses.
459 typedef struct _dcerpc_auth_subdissector {
462 dcerpc_auth_subdissector_fns auth_fns;
463 } dcerpc_auth_subdissector;
465 static GSList *dcerpc_auth_subdissector_list;
467 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
468 guint8 auth_level, guint8 auth_type)
473 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
474 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
476 if (asd->auth_level == auth_level &&
477 asd->auth_type == auth_type)
478 return &asd->auth_fns;
484 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
485 dcerpc_auth_subdissector_fns *fns)
487 dcerpc_auth_subdissector *d;
489 if (get_auth_subdissector_fns(auth_level, auth_type))
492 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
494 d->auth_level = auth_level;
495 d->auth_type = auth_type;
496 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
498 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
501 /* Hand off verifier data to a registered dissector */
503 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
505 dcerpc_auth_subdissector_fns *auth_fns,
506 e_dce_cn_common_hdr_t *hdr,
507 dcerpc_auth_info *auth_info)
509 dcerpc_dissect_fnct_t *fn = NULL;
511 switch (hdr->ptype) {
514 fn = auth_fns->bind_fn;
518 fn = auth_fns->bind_ack_fn;
521 fn = auth_fns->auth3_fn;
524 fn = auth_fns->req_verf_fn;
527 fn = auth_fns->resp_verf_fn;
530 /* Don't know how to handle authentication data in this
534 g_warning("attempt to dissect %s pdu authentication data",
535 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
540 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
542 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
544 val_to_str(auth_info->auth_type,
549 /* Hand off payload data to a registered dissector */
551 static tvbuff_t *decode_encrypted_data(tvbuff_t *enc_tvb,
553 dcerpc_auth_subdissector_fns *auth_fns,
555 dcerpc_auth_info *auth_info)
557 dcerpc_decode_data_fnct_t *fn;
560 fn = auth_fns->req_data_fn;
562 fn = auth_fns->resp_data_fn;
565 return fn(enc_tvb, 0, pinfo, auth_info);
574 /* the registered subdissectors */
575 GHashTable *dcerpc_uuids=NULL;
578 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
580 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
581 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
582 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
583 && (key1->ver == key2->ver));
587 dcerpc_uuid_hash (gconstpointer k)
589 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
590 /* This isn't perfect, but the Data1 part of these is almost always
592 return key->uuid.Data1;
596 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
597 dcerpc_sub_dissector *procs, int opnum_hf)
599 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
600 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
601 header_field_info *hf_info;
606 value->proto = proto;
608 value->name = proto_get_protocol_short_name (proto);
609 value->procs = procs;
610 value->opnum_hf = opnum_hf;
612 g_hash_table_insert (dcerpc_uuids, key, value);
614 hf_info = proto_registrar_get_nth(opnum_hf);
615 hf_info->strings = value_string_from_subdissectors(procs);
618 /* Function to find the name of a registered protocol
619 * or NULL if the protocol/version is not known to ethereal.
622 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
625 dcerpc_uuid_value *sub_proto;
629 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
632 return sub_proto->name;
635 /* Create a value_string consisting of DCERPC opnum and name from a
636 subdissector array. */
638 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
640 value_string *vs = NULL;
644 for (i = 0; sd[i].name; i++) {
646 vs[i].value = sd[i].num;
647 vs[i].strptr = sd[i].name;
653 vs = g_malloc((num_sd + 1) * sizeof(value_string));
657 vs[num_sd].value = 0;
658 vs[num_sd].strptr = NULL;
663 /* Function to find the subdissector table of a registered protocol
664 * or NULL if the protocol/version is not known to ethereal.
666 dcerpc_sub_dissector *
667 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
670 dcerpc_uuid_value *sub_proto;
674 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
677 return sub_proto->procs;
682 * To keep track of ctx_id mappings.
684 * Everytime we see a bind call we update this table.
685 * Note that we always specify a SMB FID. For non-SMB transports this
688 static GHashTable *dcerpc_binds=NULL;
690 typedef struct _dcerpc_bind_key {
691 conversation_t *conv;
696 typedef struct _dcerpc_bind_value {
701 static GMemChunk *dcerpc_bind_key_chunk=NULL;
702 static GMemChunk *dcerpc_bind_value_chunk=NULL;
705 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
707 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
708 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
709 return (key1->conv == key2->conv
710 && key1->ctx_id == key2->ctx_id
711 && key1->smb_fid == key2->smb_fid);
715 dcerpc_bind_hash (gconstpointer k)
717 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
718 return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
723 * To keep track of callid mappings. Should really use some generic
724 * conversation support instead.
726 static GHashTable *dcerpc_calls=NULL;
728 typedef struct _dcerpc_call_key {
729 conversation_t *conv;
734 static GMemChunk *dcerpc_call_key_chunk=NULL;
736 static GMemChunk *dcerpc_call_value_chunk=NULL;
739 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
741 const dcerpc_call_key *key1 = (const dcerpc_call_key *)k1;
742 const dcerpc_call_key *key2 = (const dcerpc_call_key *)k2;
743 return (key1->conv == key2->conv
744 && key1->call_id == key2->call_id
745 && key1->smb_fid == key2->smb_fid);
749 dcerpc_call_hash (gconstpointer k)
751 const dcerpc_call_key *key = (const dcerpc_call_key *)k;
752 return ((guint32)key->conv) + key->call_id + key->smb_fid;
756 /* to keep track of matched calls/responses
757 this one uses the same value struct as calls, but the key is the frame id
758 and call id; there can be more than one call in a frame.
760 XXX - why not just use the same keys as are used for calls?
763 static GHashTable *dcerpc_matched=NULL;
765 typedef struct _dcerpc_matched_key {
768 } dcerpc_matched_key;
770 static GMemChunk *dcerpc_matched_key_chunk=NULL;
773 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
775 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
776 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
777 return (key1->frame == key2->frame
778 && key1->call_id == key2->call_id);
782 dcerpc_matched_hash (gconstpointer k)
784 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
791 * Utility functions. Modeled after packet-rpc.c
795 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
796 proto_tree *tree, char *drep,
797 int hfindex, guint8 *pdata)
801 data = tvb_get_guint8 (tvb, offset);
803 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
811 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
812 proto_tree *tree, char *drep,
813 int hfindex, guint16 *pdata)
817 data = ((drep[0] & 0x10)
818 ? tvb_get_letohs (tvb, offset)
819 : tvb_get_ntohs (tvb, offset));
822 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
830 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
831 proto_tree *tree, char *drep,
832 int hfindex, guint32 *pdata)
836 data = ((drep[0] & 0x10)
837 ? tvb_get_letohl (tvb, offset)
838 : tvb_get_ntohl (tvb, offset));
841 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
848 /* handles 32 bit unix time_t */
850 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
851 proto_tree *tree, char *drep,
852 int hfindex, guint32 *pdata)
857 data = ((drep[0] & 0x10)
858 ? tvb_get_letohl (tvb, offset)
859 : tvb_get_ntohl (tvb, offset));
864 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
873 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
874 proto_tree *tree, char *drep,
875 int hfindex, unsigned char *pdata)
878 tvb_memcpy(tvb, pdata, offset, 8);
879 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
881 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
882 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
883 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
884 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
889 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
897 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
898 proto_tree *tree, char *drep,
899 int hfindex, gfloat *pdata)
905 case(DCE_RPC_DREP_FP_IEEE):
906 data = ((drep[0] & 0x10)
907 ? tvb_get_letohieee_float(tvb, offset)
908 : tvb_get_ntohieee_float(tvb, offset));
910 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
913 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
914 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
915 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
917 /* ToBeDone: non IEEE floating formats */
918 /* Set data to a negative infinity value */
919 data = -1.0 * 1e100 * 1e100;
921 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
931 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
932 proto_tree *tree, char *drep,
933 int hfindex, gdouble *pdata)
939 case(DCE_RPC_DREP_FP_IEEE):
940 data = ((drep[0] & 0x10)
941 ? tvb_get_letohieee_double(tvb, offset)
942 : tvb_get_ntohieee_double(tvb, offset));
944 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
947 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
948 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
949 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
951 /* ToBeDone: non IEEE double formats */
952 /* Set data to a negative infinity value */
953 data = -1.0 * 1e100 * 1e100;
955 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
965 * a couple simpler things
968 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
970 if (drep[0] & 0x10) {
971 return tvb_get_letohs (tvb, offset);
973 return tvb_get_ntohs (tvb, offset);
978 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
980 if (drep[0] & 0x10) {
981 return tvb_get_letohl (tvb, offset);
983 return tvb_get_ntohl (tvb, offset);
988 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
991 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
992 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
993 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
995 for (i=0; i<sizeof (uuid->Data4); i++) {
996 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
1003 /* function to dissect a unidimensional conformant array */
1005 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1006 proto_tree *tree, char *drep,
1007 dcerpc_dissect_fnct_t *fnct)
1013 di=pinfo->private_data;
1014 if(di->conformant_run){
1015 /* conformant run, just dissect the max_count header */
1017 di->conformant_run=0;
1018 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1019 hf_dcerpc_array_max_count, &di->array_max_count);
1020 di->array_max_count_offset=offset-4;
1021 di->conformant_run=1;
1022 di->conformant_eaten=offset-old_offset;
1024 /* we don't remember where in the bytestream this field was */
1025 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1027 /* real run, dissect the elements */
1028 for(i=0;i<di->array_max_count;i++){
1029 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1035 /* function to dissect a unidimensional conformant and varying array */
1037 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1038 proto_tree *tree, char *drep,
1039 dcerpc_dissect_fnct_t *fnct)
1045 di=pinfo->private_data;
1046 if(di->conformant_run){
1047 /* conformant run, just dissect the max_count header */
1049 di->conformant_run=0;
1050 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1051 hf_dcerpc_array_max_count, &di->array_max_count);
1052 di->array_max_count_offset=offset-4;
1053 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1054 hf_dcerpc_array_offset, &di->array_offset);
1055 di->array_offset_offset=offset-4;
1056 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1057 hf_dcerpc_array_actual_count, &di->array_actual_count);
1058 di->array_actual_count_offset=offset-4;
1059 di->conformant_run=1;
1060 di->conformant_eaten=offset-old_offset;
1062 /* we dont dont remember where in the bytestream these fields were */
1063 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1064 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1065 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1067 /* real run, dissect the elements */
1068 for(i=0;i<di->array_actual_count;i++){
1069 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1076 /* Dissect an string of bytes. This corresponds to
1077 IDL of the form '[string] byte *foo'.
1079 It can also be used for a conformant varying array of bytes if
1080 the contents of the array should be shown as a big blob, rather
1081 than showing each byte as an individual element.
1083 XXX - which of those is really the IDL type for, for example,
1084 the encrypted data in some MAPI packets? (Microsoft haven't
1087 XXX - does this need to do all the conformant array stuff that
1088 "dissect_ndr_ucvarray()" does? These are presumably for strings
1089 that are conformant and varying - they're stored like conformant
1090 varying arrays of bytes. */
1092 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1093 proto_tree *tree, char *drep)
1098 di=pinfo->private_data;
1099 if(di->conformant_run){
1100 /* just a run to handle conformant arrays, no scalars to dissect */
1104 /* NDR array header */
1106 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1107 hf_dcerpc_array_max_count, NULL);
1109 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1110 hf_dcerpc_array_offset, NULL);
1112 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1113 hf_dcerpc_array_actual_count, &len);
1116 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1117 tvb, offset, len, drep[0] & 0x10);
1124 /* For dissecting arrays that are to be interpreted as strings. */
1126 /* Dissect an NDR conformant varying string of elements.
1127 The length of each element is given by the 'size_is' parameter;
1128 the elements are assumed to be characters or wide characters.
1130 XXX - does this need to do all the conformant array stuff that
1131 "dissect_ndr_ucvarray()" does? */
1133 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1134 proto_tree *tree, char *drep, int size_is,
1135 int hfindex, gboolean add_subtree, char **data)
1138 proto_item *string_item;
1139 proto_tree *string_tree;
1140 guint32 len, buffer_len;
1142 header_field_info *hfinfo;
1144 di=pinfo->private_data;
1145 if(di->conformant_run){
1146 /* just a run to handle conformant arrays, no scalars to dissect */
1151 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1152 proto_registrar_get_name(hfindex));
1153 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1159 /* NDR array header */
1161 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1162 hf_dcerpc_array_max_count, NULL);
1164 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1165 hf_dcerpc_array_offset, NULL);
1167 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1168 hf_dcerpc_array_actual_count, &len);
1170 buffer_len = size_is * len;
1173 if (offset % size_is)
1174 offset += size_is - (offset % size_is);
1176 if (size_is == sizeof(guint16)) {
1177 /* XXX - use drep to determine the byte order? */
1178 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1180 * XXX - we don't support a string type with Unicode
1181 * characters, so if this is a string item, we make
1182 * its value be the "fake Unicode" string.
1184 if (tree && buffer_len) {
1185 hfinfo = proto_registrar_get_nth(hfindex);
1186 if (hfinfo->type == FT_STRING) {
1187 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1190 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1191 buffer_len, drep[0] & 0x10);
1196 * "tvb_get_string()" throws an exception if the entire string
1197 * isn't in the tvbuff. If the length is bogus, this should
1198 * keep us from trying to allocate an immensely large buffer.
1199 * (It won't help if the length is *valid* but immensely large,
1200 * but that's another matter; in any case, that would happen only
1201 * if we had an immensely large tvbuff....)
1203 s = tvb_get_string(tvb, offset, buffer_len);
1204 if (tree && buffer_len)
1205 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1206 buffer_len, drep[0] & 0x10);
1209 if (string_item != NULL)
1210 proto_item_append_text(string_item, ": %s", s);
1217 offset += buffer_len;
1219 proto_item_set_end(string_item, tvb, offset);
1224 /* Dissect an conformant varying string of chars.
1225 This corresponds to IDL of the form '[string] char *foo'.
1227 XXX - at least according to the DCE RPC 1.1 spec, a string has
1228 a null terminator, which isn't necessary as a terminator for
1229 the transfer language (as there's a length), but is presumably
1230 there for the benefit of null-terminated-string languages
1231 such as C. Is this ever used for purely counted strings?
1232 (Not that it matters if it is.) */
1234 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1235 proto_tree *tree, char *drep)
1238 di=pinfo->private_data;
1240 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1241 sizeof(guint8), di->hf_index,
1245 /* Dissect a conformant varying string of wchars (wide characters).
1246 This corresponds to IDL of the form '[string] wchar *foo'
1248 XXX - at least according to the DCE RPC 1.1 spec, a string has
1249 a null terminator, which isn't necessary as a terminator for
1250 the transfer language (as there's a length), but is presumably
1251 there for the benefit of null-terminated-string languages
1252 such as C. Is this ever used for purely counted strings?
1253 (Not that it matters if it is.) */
1255 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1256 proto_tree *tree, char *drep)
1259 di=pinfo->private_data;
1261 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1262 sizeof(guint16), di->hf_index,
1266 /* ndr pointer handling */
1267 /* list of pointers encountered so far */
1268 static GSList *ndr_pointer_list = NULL;
1270 /* position where in the list to insert newly encountered pointers */
1271 static int ndr_pointer_list_pos=0;
1273 /* boolean controlling whether pointers are top-level or embedded */
1274 static gboolean pointers_are_top_level = TRUE;
1276 /* as a kludge, we represent all embedded reference pointers as id==-1
1277 hoping that his will not collide with any non-ref pointers */
1278 typedef struct ndr_pointer_data {
1280 proto_item *item; /* proto_item for pointer */
1281 proto_tree *tree; /* subtree of above item */
1282 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1284 dcerpc_callback_fnct_t *callback;
1285 void *callback_args;
1286 } ndr_pointer_data_t;
1289 init_ndr_pointer_list(packet_info *pinfo)
1293 di=pinfo->private_data;
1294 di->conformant_run=0;
1296 while(ndr_pointer_list){
1297 ndr_pointer_data_t *npd;
1299 npd=g_slist_nth_data(ndr_pointer_list, 0);
1300 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1306 ndr_pointer_list=NULL;
1307 ndr_pointer_list_pos=0;
1308 pointers_are_top_level=TRUE;
1312 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *drep)
1314 int found_new_pointer;
1318 di=pinfo->private_data;
1322 found_new_pointer=0;
1323 len=g_slist_length(ndr_pointer_list);
1325 ndr_pointer_data_t *tnpd;
1326 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1328 dcerpc_dissect_fnct_t *fnct;
1330 found_new_pointer=1;
1333 ndr_pointer_list_pos=i+1;
1334 di->hf_index=tnpd->hf_index;
1335 /* first a run to handle any conformant
1337 di->conformant_run=1;
1338 di->conformant_eaten=0;
1339 old_offset = offset;
1340 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1342 g_assert((offset-old_offset)==di->conformant_eaten);
1343 /* This is to check for any bugs in the dissectors.
1345 * Basically, the NDR representation will store all
1346 * arrays in two blocks, one block with the dimension
1347 * discreption, like size, number of elements and such,
1348 * and another block that contains the actual data stored
1350 * If the array is embedded directly inside another,
1351 * encapsulating aggregate type, like a union or struct,
1352 * then these two blocks will be stored at different places
1353 * in the bytestream, with other data between the blocks.
1355 * For this reason, all pointers to types (both aggregate
1356 * and scalar, for simplicity no distinction is made)
1357 * will have its dissector called twice.
1358 * The dissector will first be called with conformant_run==1
1359 * in which mode the dissector MUST NOT consume any data from
1360 * the tvbuff (i.e. may not dissect anything) except the
1361 * initial control block for arrays.
1362 * The second time the dissector is called, with
1363 * conformant_run==0, all other data for the type will be
1366 * All dissect_ndr_<type> dissectors are already prepared
1367 * for this and knows when it should eat data from the tvb
1368 * and when not to, so implementors of dissectors will
1369 * normally not need to worry about this or even know about
1370 * it. However, if a dissector for an aggregate type calls
1371 * a subdissector from outside packet-dcerpc.c, such as
1372 * the dissector in packet-smb.c for NT Security Descriptors
1373 * as an example, then it is VERY important to encapsulate
1374 * this call to an external subdissector with the appropriate
1375 * test for conformant_run, i.e. it will need something like
1379 * di=pinfo->private_data;
1380 * if(di->conformant_run){
1384 * to make sure it makes the right thing.
1385 * This assert will signal when someone has forgotten to
1386 * make the dissector aware of this requirement.
1389 /* now we dissect the actual pointer */
1390 di->conformant_run=0;
1391 old_offset = offset;
1392 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1394 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1398 } while(found_new_pointer);
1405 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1406 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1407 dcerpc_callback_fnct_t *callback, void *callback_args)
1409 ndr_pointer_data_t *npd;
1411 /* check if this pointer is valid */
1414 dcerpc_call_value *value;
1416 di=pinfo->private_data;
1417 value=di->call_data;
1420 if(!(pinfo->fd->flags.visited)){
1421 if(id>value->max_ptr){
1426 /* if we havent seen the request bail out since we cant
1427 know whether this is the first non-NULL instance
1429 if(value->req_frame==0){
1430 /* XXX THROW EXCEPTION */
1433 /* We saw this one in the request frame, nothing to
1435 if(id<=value->max_ptr){
1441 npd=g_malloc(sizeof(ndr_pointer_data_t));
1446 npd->hf_index=hf_index;
1447 npd->callback=callback;
1448 npd->callback_args=callback_args;
1449 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1450 ndr_pointer_list_pos);
1451 ndr_pointer_list_pos++;
1456 find_pointer_index(guint32 id)
1458 ndr_pointer_data_t *npd;
1461 len=g_slist_length(ndr_pointer_list);
1463 npd=g_slist_nth_data(ndr_pointer_list, i);
1474 /* This function dissects an NDR pointer and stores the callback for later
1475 * deferred dissection.
1477 * fnct is the callback function for when we have reached this object in
1480 * type is what type of pointer.
1482 * this is text is what text we should put in any created tree node.
1484 * hf_index is what hf value we want to pass to the callback function when
1485 * it is called, the callback can later pich this one up from di->hf_index.
1487 * callback is executed after the pointer has been dereferenced.
1489 * callback_args is passed as an argument to the callback function
1491 * See packet-dcerpc-samr.c for examples
1494 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1495 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1496 int type, char *text, int hf_index,
1497 dcerpc_callback_fnct_t *callback, void *callback_args)
1501 di=pinfo->private_data;
1502 if(di->conformant_run){
1503 /* this call was only for dissecting the header for any
1504 embedded conformant array. we will not parse any
1505 pointers in this mode.
1510 /*TOP LEVEL REFERENCE POINTER*/
1511 if( pointers_are_top_level
1512 &&(type==NDR_POINTER_REF) ){
1516 /* we must find out a nice way to do the length here */
1517 item=proto_tree_add_text(tree, tvb, offset, 0,
1519 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1521 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1522 hf_index, callback, callback_args);
1526 /*TOP LEVEL FULL POINTER*/
1527 if( pointers_are_top_level
1528 && (type==NDR_POINTER_PTR) ){
1534 /* get the referent id */
1535 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1537 /* we got a NULL pointer */
1539 proto_tree_add_text(tree, tvb, offset-4, 4,
1540 "(NULL pointer) %s",text);
1544 /* see if we have seen this pointer before */
1545 idx=find_pointer_index(id);
1547 /* we have seen this pointer before */
1549 proto_tree_add_text(tree, tvb, offset-4, 4,
1550 "(duplicate PTR) %s",text);
1555 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1557 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1558 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1559 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1560 callback, callback_args);
1563 /*TOP LEVEL UNIQUE POINTER*/
1564 if( pointers_are_top_level
1565 && (type==NDR_POINTER_UNIQUE) ){
1570 /* get the referent id */
1571 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1573 /* we got a NULL pointer */
1575 proto_tree_add_text(tree, tvb, offset-4, 4,
1576 "(NULL pointer) %s",text);
1581 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1583 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1584 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1585 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1586 hf_index, callback, callback_args);
1590 /*EMBEDDED REFERENCE POINTER*/
1591 if( (!pointers_are_top_level)
1592 && (type==NDR_POINTER_REF) ){
1597 /* get the referent id */
1598 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1601 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1603 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1604 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1605 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1606 hf_index, callback, callback_args);
1610 /*EMBEDDED UNIQUE POINTER*/
1611 if( (!pointers_are_top_level)
1612 && (type==NDR_POINTER_UNIQUE) ){
1617 /* get the referent id */
1618 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1620 /* we got a NULL pointer */
1622 proto_tree_add_text(tree, tvb, offset-4, 4,
1623 "(NULL pointer) %s", text);
1628 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1630 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1631 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1632 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1633 hf_index, callback, callback_args);
1637 /*EMBEDDED FULL POINTER*/
1638 if( (!pointers_are_top_level)
1639 && (type==NDR_POINTER_PTR) ){
1645 /* get the referent id */
1646 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1648 /* we got a NULL pointer */
1650 proto_tree_add_text(tree, tvb, offset-4, 4,
1651 "(NULL pointer) %s",text);
1655 /* see if we have seen this pointer before */
1656 idx=find_pointer_index(id);
1658 /* we have seen this pointer before */
1660 proto_tree_add_text(tree, tvb, offset-4, 4,
1661 "(duplicate PTR) %s",text);
1666 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1668 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1669 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1670 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1671 callback, callback_args);
1677 /* After each top level pointer we have dissected we have to
1678 dissect all deferrals before we move on to the next top level
1680 if(pointers_are_top_level==TRUE){
1681 pointers_are_top_level=FALSE;
1682 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
1683 pointers_are_top_level=TRUE;
1690 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1691 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1692 int type, char *text, int hf_index)
1694 return dissect_ndr_pointer_cb(
1695 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
1700 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
1701 dcerpc_auth_info *auth_info)
1706 * We don't show stub data unless we have some in the tvbuff;
1707 * however, in the protocol tree, we show, as the number of
1708 * bytes, the reported number of bytes, not the number of bytes
1709 * that happen to be in the tvbuff.
1711 if (tvb_length_remaining (tvb, offset) > 0) {
1712 length = tvb_reported_length_remaining (tvb, offset);
1713 if (auth_info != NULL &&
1714 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1715 proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
1716 "Encrypted stub data (%d byte%s)",
1717 length, plurality(length, "", "s"));
1719 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
1720 "Stub data (%d byte%s)", length,
1721 plurality(length, "", "s"));
1727 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
1728 proto_tree *dcerpc_tree,
1729 tvbuff_t *volatile tvb, volatile gint offset,
1730 char *drep, dcerpc_info *info,
1731 dcerpc_auth_info *auth_info)
1733 dcerpc_uuid_key key;
1734 dcerpc_uuid_value *sub_proto;
1736 proto_tree *volatile sub_tree = NULL;
1737 dcerpc_sub_dissector *proc;
1739 dcerpc_dissect_fnct_t *volatile sub_dissect;
1740 const char *volatile saved_proto;
1741 void *volatile saved_private_data;
1743 key.uuid = info->call_data->uuid;
1744 key.ver = info->call_data->ver;
1747 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1748 || !proto_is_protocol_enabled(sub_proto->proto)) {
1750 * We don't have a dissector for this UUID, or the protocol
1751 * for that UUID is disabled.
1753 show_stub_data (tvb, offset, dcerpc_tree, auth_info);
1757 for (proc = sub_proto->procs; proc->name; proc++) {
1758 if (proc->num == info->call_data->opnum) {
1767 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1768 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1771 if (check_col (pinfo->cinfo, COL_INFO)) {
1772 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1773 name, info->request ? "request" : "reply");
1777 proto_item *sub_item;
1778 sub_item = proto_tree_add_item (tree, sub_proto->proto, tvb, offset,
1782 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1786 * Put the operation number into the tree along with
1787 * the operation's name.
1790 if (sub_proto->opnum_hf != -1)
1791 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
1792 tvb, 0, 0, info->call_data->opnum,
1793 "Operation: %s (%u)",
1794 name, info->call_data->opnum);
1796 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
1797 0, 0, info->call_data->opnum,
1798 "Operation: %s (%u)",
1799 name, info->call_data->opnum);
1802 sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
1804 /* Call subdissector if we have a zero auth_level and no decrypted data,
1805 or non-zero auth_level and sucessfully decrypted data. */
1807 if (sub_dissect && ((!auth_info->auth_level && !pinfo->decrypted_data) ||
1808 (auth_info->auth_level && pinfo->decrypted_data))) {
1809 saved_proto = pinfo->current_proto;
1810 saved_private_data = pinfo->private_data;
1811 pinfo->current_proto = sub_proto->name;
1812 pinfo->private_data = (void *)info;
1814 init_ndr_pointer_list(pinfo);
1816 * Catch ReportedBoundsError, so that even if the stub
1817 * data is bad, we still show the verifier.
1820 offset = sub_dissect (tvb, offset, pinfo, sub_tree, drep);
1821 } CATCH(BoundsError) {
1823 } CATCH(ReportedBoundsError) {
1824 show_reported_bounds_error(tvb, pinfo, tree);
1827 /* If there is auth padding at the end of the stub, display it */
1828 if (auth_info != NULL && auth_info->auth_pad_len != 0) {
1829 proto_tree_add_text (sub_tree, tvb, offset,
1830 auth_info->auth_pad_len,
1831 "Auth Padding (%u byte%s)",
1832 auth_info->auth_pad_len,
1833 plurality(auth_info->auth_pad_len, "", "s"));
1834 offset += auth_info->auth_pad_len;
1837 /* If we have a subdissector and it didn't dissect all data in
1838 the tvb, make a note of it. */
1840 if (tvb_length_remaining(tvb, offset)) {
1841 if (check_col(pinfo->cinfo, COL_INFO))
1842 col_append_fstr(pinfo->cinfo, COL_INFO,
1843 "[Long frame (%d bytes)]",
1844 tvb_length_remaining(tvb, offset));
1847 pinfo->current_proto = saved_proto;
1848 pinfo->private_data = saved_private_data;
1850 length = tvb_length_remaining (tvb, offset);
1852 proto_tree_add_text (sub_tree, tvb, offset, length,
1853 "Stub data (%d byte%s)", length,
1854 plurality(length, "", "s"));
1858 tap_queue_packet(dcerpc_tap, pinfo, info);
1863 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
1864 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
1865 dcerpc_auth_info *auth_info)
1869 auth_info->auth_data = NULL;
1871 if (auth_info->auth_size != 0) {
1872 dcerpc_auth_subdissector_fns *auth_fns;
1875 auth_offset = hdr->frag_len - hdr->auth_len;
1877 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
1880 auth_info->auth_data = auth_tvb;
1882 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
1883 auth_info->auth_type)))
1884 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
1887 proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
1891 return hdr->auth_len;
1895 dissect_dcerpc_cn_auth (tvbuff_t *tvb, packet_info *pinfo, proto_tree *dcerpc_tree,
1896 e_dce_cn_common_hdr_t *hdr, gboolean are_credentials,
1897 dcerpc_auth_info *auth_info)
1902 * Initially set auth_level and auth_type to zero to indicate that we
1903 * haven't yet seen any authentication level information.
1905 auth_info->auth_level = 0;
1906 auth_info->auth_type = 0;
1909 * The authentication information is at the *end* of the PDU; in
1910 * request and response PDUs, the request and response stub data
1913 * If the full packet is here, and we've got an auth len, and it's
1914 * valid, then dissect the auth info.
1917 if (tvb_length (tvb) >= hdr->frag_len
1919 && (hdr->auth_len + 8 <= hdr->frag_len)) {
1921 offset = hdr->frag_len - (hdr->auth_len + 8);
1923 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1924 hf_dcerpc_auth_type,
1925 &auth_info->auth_type);
1926 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1927 hf_dcerpc_auth_level,
1928 &auth_info->auth_level);
1930 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1931 hf_dcerpc_auth_pad_len,
1932 &auth_info->auth_pad_len);
1933 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1934 hf_dcerpc_auth_rsrvd, NULL);
1935 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
1936 hf_dcerpc_auth_ctx_id, NULL);
1939 * Dissect the authentication data.
1941 if (are_credentials) {
1943 dcerpc_auth_subdissector_fns *auth_fns;
1945 auth_tvb = tvb_new_subset(
1946 tvb, offset, hdr->auth_len, hdr->auth_len);
1948 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
1949 auth_info->auth_type)))
1950 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
1953 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
1954 "Auth Credentials");
1957 /* Compute the size of the auth block. Note that this should not
1958 include auth padding, since when NTLMSSP encryption is used, the
1959 padding is actually inside the encrypted stub */
1960 auth_info->auth_size = hdr->auth_len + 8;
1962 auth_info->auth_size = 0;
1963 auth_info->auth_pad_len = 0;
1968 /* We need to hash in the SMB fid number to generate a unique hash table
1969 key as DCERPC over SMB allows several pipes over the same TCP/IP
1972 static guint16 get_smb_fid (void *private_data)
1974 dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
1977 return 0; /* Nothing to see here */
1979 /* DCERPC over smb */
1981 if (priv->transport_type == DCERPC_TRANSPORT_SMB)
1982 return priv->data.smb.fid;
1984 /* Some other transport... */
1990 * Connection oriented packet types
1994 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
1995 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
1997 conversation_t *conv = NULL;
1998 guint8 num_ctx_items;
2000 gboolean saw_ctx_item = FALSE;
2002 guint16 num_trans_items;
2007 guint16 if_ver, if_ver_minor;
2008 char uuid_str[DCERPC_UUID_STR_LEN];
2010 dcerpc_auth_info auth_info;
2012 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2013 hf_dcerpc_cn_max_xmit, NULL);
2015 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2016 hf_dcerpc_cn_max_recv, NULL);
2018 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2019 hf_dcerpc_cn_assoc_group, NULL);
2021 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2022 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2027 for (i = 0; i < num_ctx_items; i++) {
2028 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2030 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2031 hf_dcerpc_cn_ctx_id, &ctx_id);
2034 proto_item *ctx_item;
2036 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
2038 hdr->drep[0] & 0x10);
2040 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2043 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2044 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2046 /* XXX - use "dissect_ndr_uuid_t()"? */
2047 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2049 proto_item *iface_item;
2051 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2052 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2053 if_id.Data1, if_id.Data2, if_id.Data3,
2054 if_id.Data4[0], if_id.Data4[1],
2055 if_id.Data4[2], if_id.Data4[3],
2056 if_id.Data4[4], if_id.Data4[5],
2057 if_id.Data4[6], if_id.Data4[7]);
2059 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2060 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2062 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2063 offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2064 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2068 if (hdr->drep[0] & 0x10) {
2069 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2070 hf_dcerpc_cn_bind_if_ver, &if_ver);
2071 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2072 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2074 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2075 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2076 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2077 hf_dcerpc_cn_bind_if_ver, &if_ver);
2080 if (!saw_ctx_item) {
2081 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2082 pinfo->srcport, pinfo->destport, 0);
2084 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
2085 pinfo->srcport, pinfo->destport, 0);
2088 /* if this is the first time we see this packet, we need to
2089 update the dcerpc_binds table so that any later calls can
2090 match to the interface.
2091 XXX We assume that BINDs will NEVER be fragmented.
2093 if(!(pinfo->fd->flags.visited)){
2094 dcerpc_bind_key *key;
2095 dcerpc_bind_value *value;
2097 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
2099 key->ctx_id = ctx_id;
2100 key->smb_fid = get_smb_fid(pinfo->private_data);
2102 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2103 value->uuid = if_id;
2104 value->ver = if_ver;
2106 /* add this entry to the bind table, first removing any
2107 previous ones that are identical
2109 if(g_hash_table_lookup(dcerpc_binds, key)){
2110 g_hash_table_remove(dcerpc_binds, key);
2112 g_hash_table_insert (dcerpc_binds, key, value);
2115 if (check_col (pinfo->cinfo, COL_INFO)) {
2116 dcerpc_uuid_key key;
2117 dcerpc_uuid_value *value;
2122 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2123 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2125 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2126 if_id.Data1, if_id.Data2, if_id.Data3,
2127 if_id.Data4[0], if_id.Data4[1],
2128 if_id.Data4[2], if_id.Data4[3],
2129 if_id.Data4[4], if_id.Data4[5],
2130 if_id.Data4[6], if_id.Data4[7],
2131 if_ver, if_ver_minor);
2133 saw_ctx_item = TRUE;
2136 for (j = 0; j < num_trans_items; j++) {
2137 /* XXX - use "dissect_ndr_uuid_t()"? */
2138 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2140 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2141 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2142 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2143 trans_id.Data4[0], trans_id.Data4[1],
2144 trans_id.Data4[2], trans_id.Data4[3],
2145 trans_id.Data4[4], trans_id.Data4[5],
2146 trans_id.Data4[6], trans_id.Data4[7]);
2147 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2148 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2149 proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2150 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2154 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
2155 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2160 * XXX - we should save the authentication type *if* we have
2161 * an authentication header, and associate it with an authentication
2162 * context, so subsequent PDUs can use that context.
2164 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2168 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2169 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2171 guint16 max_xmit, max_recv;
2172 guint16 sec_addr_len;
2179 char uuid_str[DCERPC_UUID_STR_LEN];
2181 dcerpc_auth_info auth_info;
2183 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2184 hf_dcerpc_cn_max_xmit, &max_xmit);
2186 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2187 hf_dcerpc_cn_max_recv, &max_recv);
2189 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2190 hf_dcerpc_cn_assoc_group, NULL);
2192 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2193 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2194 if (sec_addr_len != 0) {
2195 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2196 sec_addr_len, FALSE);
2197 offset += sec_addr_len;
2201 offset += 4 - offset % 4;
2204 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2205 hf_dcerpc_cn_num_results, &num_results);
2210 for (i = 0; i < num_results; i++) {
2211 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2212 hdr->drep, hf_dcerpc_cn_ack_result,
2215 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2216 hdr->drep, hf_dcerpc_cn_ack_reason,
2220 * The reason for rejection isn't meaningful, and often isn't
2221 * set, when the syntax was accepted.
2226 /* XXX - use "dissect_ndr_uuid_t()"? */
2227 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2229 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2230 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2231 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2232 trans_id.Data4[0], trans_id.Data4[1],
2233 trans_id.Data4[2], trans_id.Data4[3],
2234 trans_id.Data4[4], trans_id.Data4[5],
2235 trans_id.Data4[6], trans_id.Data4[7]);
2236 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2237 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2238 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2239 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2243 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2244 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2248 * XXX - do we need to do anything with the authentication level
2249 * we get back from this?
2251 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2253 if (check_col (pinfo->cinfo, COL_INFO)) {
2254 if (num_results != 0 && result == 0) {
2255 /* XXX - only checks the last result */
2256 col_append_fstr (pinfo->cinfo, COL_INFO,
2257 " accept max_xmit: %u max_recv: %u",
2258 max_xmit, max_recv);
2260 /* XXX - only shows the last result and reason */
2261 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2262 val_to_str(result, p_cont_result_vals,
2263 "Unknown result (%u)"),
2264 val_to_str(reason, p_provider_reason_vals,
2271 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2272 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2275 guint8 num_protocols;
2278 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2279 hdr->drep, hf_dcerpc_cn_reject_reason,
2282 if (check_col (pinfo->cinfo, COL_INFO)) {
2283 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2284 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2287 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2288 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2289 hf_dcerpc_cn_num_protocols,
2292 for (i = 0; i < num_protocols; i++) {
2293 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2294 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2296 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2297 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2303 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2306 #define PFC_FRAG_MASK 0x03
2309 fragment_type(guint8 flags)
2311 flags = flags & PFC_FRAG_MASK;
2313 if (flags == PFC_FIRST_FRAG)
2319 if (flags == PFC_LAST_FRAG)
2322 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2328 /* Dissect stub data (payload) of a DCERPC packet. */
2331 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2332 proto_tree *dcerpc_tree, proto_tree *tree,
2333 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2334 dcerpc_auth_info *auth_info, guint32 alloc_hint,
2337 gboolean save_fragmented, payload_ok;
2338 fragment_data *fd_head=NULL;
2340 tvbuff_t *payload_tvb;
2342 save_fragmented = pinfo->fragmented;
2344 payload_tvb = tvb_new_subset(
2345 tvb, offset, tvb_length_remaining(tvb, offset) -
2346 auth_info->auth_size, tvb_length_remaining(tvb, offset) -
2347 auth_info->auth_size);
2351 /* Decrypt the PDU if it is encrypted */
2353 pinfo->decrypted_data = NULL;
2355 if (auth_info->auth_type) {
2356 dcerpc_auth_subdissector_fns *auth_fns;
2359 proto_tree_add_text(
2360 dcerpc_tree, payload_tvb, 0, -1,
2361 "Encrypted Stub Data (%d byte%s)",
2362 tvb_length(payload_tvb),
2363 plurality(tvb_length(payload_tvb), "", "s"));
2365 if ((auth_fns = get_auth_subdissector_fns(
2366 auth_info->auth_level, auth_info->auth_type))) {
2369 result = decode_encrypted_data(
2370 payload_tvb, pinfo, auth_fns,
2371 hdr->ptype == PDU_REQ, auth_info);
2374 int len = tvb_length(result);
2376 add_new_data_source(
2377 pinfo, result, "Decrypted Stub Data");
2379 pinfo->decrypted_data = result;
2381 proto_tree_add_text(
2382 dcerpc_tree, result, 0, len,
2383 "Decrypted Stub Data (%d byte%s)",
2384 len, plurality(len, "", "s"));
2390 /* if this packet is not fragmented, just dissect it and exit */
2391 if(PFC_NOT_FRAGMENTED(hdr)){
2392 pinfo->fragmented = FALSE;
2395 pinfo, tree, dcerpc_tree,
2396 pinfo->decrypted_data ? pinfo->decrypted_data : payload_tvb,
2397 0, hdr->drep, di, auth_info);
2399 pinfo->fragmented = save_fragmented;
2403 /* The packet is fragmented. */
2404 pinfo->fragmented = TRUE;
2406 /* if we are not doing reassembly and this is the first fragment
2407 then just dissect it and exit
2409 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
2412 pinfo, tree, dcerpc_tree,
2413 pinfo->decrypted_data ? pinfo->decrypted_data :
2414 payload_tvb, 0, hdr->drep, di, auth_info);
2416 if (check_col(pinfo->cinfo, COL_INFO)) {
2417 col_append_fstr(pinfo->cinfo, COL_INFO,
2418 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2420 pinfo->fragmented = save_fragmented;
2424 /* Replace encrypted payload with decrypted version for reassembly. */
2426 if (pinfo->decrypted_data)
2427 payload_tvb = (tvbuff_t *)pinfo->decrypted_data;
2429 /* if we have already seen this packet, see if it was reassembled
2430 and if so dissect the full pdu.
2433 if(pinfo->fd->flags.visited){
2434 fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
2438 /* if we are not doing reassembly and it was neither a complete PDU
2439 nor the first fragment then there is nothing more we can do
2440 so we just have to exit
2442 if( !dcerpc_reassemble )
2445 /* if we didnt get 'frame' we dont know where the PDU started and thus
2446 it is pointless to continue
2451 /* from now on we must attempt to reassemble the PDU
2454 /* if we get here we know it is the first time we see the packet
2455 and we also know it is only a fragment and not a full PDU,
2456 thus we must reassemble it.
2459 /* if this is the first fragment we need to start reassembly
2461 if(hdr->flags&PFC_FIRST_FRAG){
2462 fragment_add(payload_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
2463 0, tvb_length(payload_tvb), TRUE);
2464 fragment_set_tot_len(pinfo, frame,
2465 dcerpc_co_reassemble_table, alloc_hint);
2470 /* if this is a middle fragment, just add it and exit */
2471 if(!(hdr->flags&PFC_LAST_FRAG)){
2472 tot_len = fragment_get_tot_len(pinfo, frame,
2473 dcerpc_co_reassemble_table);
2474 fragment_add(payload_tvb, 0, pinfo, frame,
2475 dcerpc_co_reassemble_table,
2476 tot_len-alloc_hint, tvb_length(payload_tvb),
2482 /* this was the last fragment add it to reassembly
2484 tot_len = fragment_get_tot_len(pinfo, frame,
2485 dcerpc_co_reassemble_table);
2486 fd_head = fragment_add(payload_tvb, 0, pinfo,
2488 dcerpc_co_reassemble_table,
2489 tot_len-alloc_hint, tvb_length(payload_tvb),
2494 /* if reassembly is complete, dissect the full PDU
2496 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
2498 if(pinfo->fd->num==fd_head->reassembled_in){
2501 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2502 tvb_set_child_real_data_tvbuff(payload_tvb, next_tvb);
2503 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2504 show_fragment_tree(fd_head, &dcerpc_frag_items,
2505 dcerpc_tree, pinfo, next_tvb);
2507 pinfo->fragmented = FALSE;
2509 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
2510 0, hdr->drep, di, auth_info);
2513 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in, payload_tvb, 0, 0,
2514 fd_head->reassembled_in);
2515 if (check_col(pinfo->cinfo, COL_INFO)) {
2516 col_append_fstr(pinfo->cinfo, COL_INFO,
2517 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2521 /* Reassembly not complete - some fragments
2524 if (check_col(pinfo->cinfo, COL_INFO)) {
2525 col_append_fstr(pinfo->cinfo, COL_INFO,
2526 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2530 pinfo->fragmented = save_fragmented;
2534 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2535 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2537 conversation_t *conv;
2541 dcerpc_auth_info auth_info;
2543 char uuid_str[DCERPC_UUID_STR_LEN];
2546 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2547 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2549 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2550 hf_dcerpc_cn_ctx_id, &ctx_id);
2552 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2553 hf_dcerpc_opnum, &opnum);
2555 if (check_col (pinfo->cinfo, COL_INFO)) {
2556 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
2560 if (hdr->flags & PFC_OBJECT_UUID) {
2561 /* XXX - use "dissect_ndr_uuid_t()"? */
2562 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
2564 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2565 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2566 obj_id.Data1, obj_id.Data2, obj_id.Data3,
2575 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2576 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2577 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
2578 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
2584 * XXX - what if this was set when the connection was set up,
2585 * and we just have a security context?
2587 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2588 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2590 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2591 pinfo->srcport, pinfo->destport, 0);
2593 show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2595 dcerpc_matched_key matched_key, *new_matched_key;
2596 dcerpc_call_value *value;
2598 /* !!! we can NOT check flags.visited here since this will interact
2599 badly with when SMB handles (i.e. calls the subdissector)
2600 and desegmented pdu's .
2601 Instead we check if this pdu is already in the matched table or not
2603 matched_key.frame = pinfo->fd->num;
2604 matched_key.call_id = hdr->call_id;
2605 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
2607 dcerpc_bind_key bind_key;
2608 dcerpc_bind_value *bind_value;
2611 bind_key.ctx_id=ctx_id;
2612 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
2614 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
2615 if(!(hdr->flags&PFC_FIRST_FRAG)){
2616 dcerpc_call_key call_key;
2617 dcerpc_call_value *call_value;
2620 call_key.call_id=hdr->call_id;
2621 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2622 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2623 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2624 *new_matched_key = matched_key;
2625 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2629 dcerpc_call_key *call_key;
2630 dcerpc_call_value *call_value;
2632 /* We found the binding and it is the first fragment
2633 (or a complete PDU) of a dcerpc pdu so just add
2634 the call to both the call table and the
2637 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
2638 call_key->conv=conv;
2639 call_key->call_id=hdr->call_id;
2640 call_key->smb_fid=get_smb_fid(pinfo->private_data);
2642 /* if there is already a matching call in the table
2643 remove it so it is replaced with the new one */
2644 if(g_hash_table_lookup(dcerpc_calls, call_key)){
2645 g_hash_table_remove(dcerpc_calls, call_key);
2648 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2649 call_value->uuid = bind_value->uuid;
2650 call_value->ver = bind_value->ver;
2651 call_value->opnum = opnum;
2652 call_value->req_frame=pinfo->fd->num;
2653 call_value->req_time.secs=pinfo->fd->abs_secs;
2654 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
2655 call_value->rep_frame=0;
2656 call_value->max_ptr=0;
2657 call_value->private_data = NULL;
2658 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2660 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2661 *new_matched_key = matched_key;
2662 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2672 /* handoff this call */
2674 di->call_id = hdr->call_id;
2675 di->smb_fid = get_smb_fid(pinfo->private_data);
2677 di->call_data = value;
2680 if(value->rep_frame!=0){
2681 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
2682 tvb, 0, 0, value->rep_frame);
2685 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2686 hdr, di, &auth_info, alloc_hint,
2689 show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2694 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2695 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2697 dcerpc_call_value *value = NULL;
2698 conversation_t *conv;
2700 dcerpc_auth_info auth_info;
2703 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2704 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2706 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2707 hf_dcerpc_cn_ctx_id, &ctx_id);
2709 if (check_col (pinfo->cinfo, COL_INFO)) {
2710 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
2713 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2714 hf_dcerpc_cn_cancel_count, NULL);
2719 * XXX - what if this was set when the connection was set up,
2720 * and we just have a security context?
2722 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2723 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2725 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2726 pinfo->srcport, pinfo->destport, 0);
2729 /* no point in creating one here, really */
2730 show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2732 dcerpc_matched_key matched_key, *new_matched_key;
2734 /* !!! we can NOT check flags.visited here since this will interact
2735 badly with when SMB handles (i.e. calls the subdissector)
2736 and desegmented pdu's .
2737 Instead we check if this pdu is already in the matched table or not
2739 matched_key.frame = pinfo->fd->num;
2740 matched_key.call_id = hdr->call_id;
2741 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
2743 dcerpc_call_key call_key;
2744 dcerpc_call_value *call_value;
2747 call_key.call_id=hdr->call_id;
2748 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2750 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2751 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2752 *new_matched_key = matched_key;
2753 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2755 if(call_value->rep_frame==0){
2756 call_value->rep_frame=pinfo->fd->num;
2765 /* handoff this call */
2767 di->call_id = hdr->call_id;
2768 di->smb_fid = get_smb_fid(pinfo->private_data);
2769 di->request = FALSE;
2770 di->call_data = value;
2772 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2773 if(value->req_frame!=0){
2775 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2776 tvb, 0, 0, value->req_frame);
2777 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2778 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2780 ns.nsecs+=1000000000;
2783 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2786 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2787 hdr, di, &auth_info, alloc_hint,
2790 show_stub_data (tvb, offset, dcerpc_tree, &auth_info);
2795 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2796 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2798 dcerpc_call_value *value = NULL;
2799 conversation_t *conv;
2803 dcerpc_auth_info auth_info;
2805 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2806 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2808 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2809 hf_dcerpc_cn_ctx_id, &ctx_id);
2811 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2812 hf_dcerpc_cn_cancel_count, NULL);
2816 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2817 hf_dcerpc_cn_status, &status);
2819 if (check_col (pinfo->cinfo, COL_INFO)) {
2820 col_append_fstr (pinfo->cinfo, COL_INFO,
2821 " ctx_id: %u status: %s", ctx_id,
2822 val_to_str(status, reject_status_vals,
2823 "Unknown (0x%08x)"));
2830 * XXX - what if this was set when the connection was set up,
2831 * and we just have a security context?
2833 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2835 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2836 pinfo->srcport, pinfo->destport, 0);
2838 /* no point in creating one here, really */
2840 dcerpc_matched_key matched_key, *new_matched_key;
2842 /* !!! we can NOT check flags.visited here since this will interact
2843 badly with when SMB handles (i.e. calls the subdissector)
2844 and desegmented pdu's .
2845 Instead we check if this pdu is already in the matched table or not
2847 matched_key.frame = pinfo->fd->num;
2848 matched_key.call_id = hdr->call_id;
2849 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
2851 dcerpc_call_key call_key;
2852 dcerpc_call_value *call_value;
2855 call_key.call_id=hdr->call_id;
2856 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2858 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2859 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2860 *new_matched_key = matched_key;
2861 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2863 if(call_value->rep_frame==0){
2864 call_value->rep_frame=pinfo->fd->num;
2871 int length, reported_length, stub_length;
2875 /* handoff this call */
2877 di->call_id = hdr->call_id;
2878 di->smb_fid = get_smb_fid(pinfo->private_data);
2879 di->request = FALSE;
2880 di->call_data = value;
2882 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2883 if(value->req_frame!=0){
2885 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2886 tvb, 0, 0, value->req_frame);
2887 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2888 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2890 ns.nsecs+=1000000000;
2893 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2896 length = tvb_length_remaining(tvb, offset);
2897 reported_length = tvb_reported_length_remaining(tvb, offset);
2898 stub_length = hdr->frag_len - offset - auth_info.auth_size;
2899 if (length > stub_length)
2900 length = stub_length;
2901 if (reported_length > stub_length)
2902 reported_length = stub_length;
2904 /* If we don't have reassembly enabled, or this packet contains
2905 the entire PDU, or if we don't have all the data in this
2906 fragment, just call the handoff directly if this is the
2907 first fragment or the PDU isn't fragmented. */
2908 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
2909 !tvb_bytes_exist(tvb, offset, stub_length) ){
2910 if(hdr->flags&PFC_FIRST_FRAG){
2911 /* First fragment, possibly the only fragment */
2913 * XXX - should there be a third routine for each
2914 * function in an RPC subdissector, to handle
2915 * fault responses? The DCE RPC 1.1 spec says
2916 * three's "stub data" here, which I infer means
2917 * that it's protocol-specific and call-specific.
2919 * It should probably get passed the status code
2920 * as well, as that might be protocol-specific.
2923 if (stub_length > 0) {
2924 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2925 "Fault stub data (%d byte%s)",
2927 plurality(stub_length, "", "s"));
2931 /* PDU is fragmented and this isn't the first fragment */
2932 if (check_col(pinfo->cinfo, COL_INFO)) {
2933 col_append_fstr(pinfo->cinfo, COL_INFO,
2934 " [DCE/RPC fragment]");
2937 if (stub_length > 0) {
2938 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2939 "Fragment data (%d byte%s)",
2941 plurality(stub_length, "", "s"));
2946 /* Reassembly is enabled, the PDU is fragmented, and
2947 we have all the data in the fragment; the first two
2948 of those mean we should attempt reassembly, and the
2949 third means we can attempt reassembly. */
2952 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
2953 "Fragment data (%d byte%s)",
2955 plurality(stub_length, "", "s"));
2958 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
2959 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
2960 fragment_add(tvb, offset, pinfo, value->rep_frame,
2961 dcerpc_co_reassemble_table,
2965 fragment_set_tot_len(pinfo, value->rep_frame,
2966 dcerpc_co_reassemble_table, alloc_hint);
2968 if (check_col(pinfo->cinfo, COL_INFO)) {
2969 col_append_fstr(pinfo->cinfo, COL_INFO,
2970 " [DCE/RPC fragment]");
2972 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
2973 if( value->rep_frame ){
2974 fragment_data *fd_head;
2977 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
2978 dcerpc_co_reassemble_table);
2979 fd_head = fragment_add(tvb, offset, pinfo,
2981 dcerpc_co_reassemble_table,
2987 /* We completed reassembly */
2990 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2991 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
2992 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2993 show_fragment_tree(fd_head, &dcerpc_frag_items,
2994 dcerpc_tree, pinfo, next_tvb);
2997 * XXX - should there be a third routine for each
2998 * function in an RPC subdissector, to handle
2999 * fault responses? The DCE RPC 1.1 spec says
3000 * three's "stub data" here, which I infer means
3001 * that it's protocol-specific and call-specific.
3003 * It should probably get passed the status code
3004 * as well, as that might be protocol-specific.
3008 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3009 "Fault stub data (%d byte%s)",
3011 plurality(stub_length, "", "s"));
3015 /* Reassembly not complete - some fragments
3017 if (check_col(pinfo->cinfo, COL_INFO)) {
3018 col_append_fstr(pinfo->cinfo, COL_INFO,
3019 " [DCE/RPC fragment]");
3023 } else { /* MIDDLE fragment(s) */
3024 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3026 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3027 dcerpc_co_reassemble_table);
3028 fragment_add(tvb, offset, pinfo, value->rep_frame,
3029 dcerpc_co_reassemble_table,
3034 if (check_col(pinfo->cinfo, COL_INFO)) {
3035 col_append_fstr(pinfo->cinfo, COL_INFO,
3036 " [DCE/RPC fragment]");
3045 * DCERPC dissector for connection oriented calls
3048 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3049 proto_tree *tree, gboolean can_desegment)
3051 static char nulls[4] = { 0 };
3054 proto_item *ti = NULL;
3055 proto_item *tf = NULL;
3056 proto_tree *dcerpc_tree = NULL;
3057 proto_tree *cn_flags_tree = NULL;
3058 proto_tree *drep_tree = NULL;
3059 e_dce_cn_common_hdr_t hdr;
3060 dcerpc_auth_info auth_info;
3063 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3064 * data for some reason.
3066 * XXX - if that's always the case, the right way to do this would
3067 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3068 * the 4 bytes of null padding, and make that the dissector
3069 * used for "netbios".
3071 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3081 * Check if this looks like a C/O DCERPC call
3083 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3086 start_offset = offset;
3087 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3088 if (hdr.rpc_ver != 5)
3090 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3091 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3093 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3097 hdr.flags = tvb_get_guint8 (tvb, offset++);
3098 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3099 offset += sizeof (hdr.drep);
3101 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3103 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3105 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3108 if (can_desegment && pinfo->can_desegment
3109 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3110 pinfo->desegment_offset = start_offset;
3111 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3112 return 0; /* desegmentation required */
3115 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3116 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3117 if (check_col (pinfo->cinfo, COL_INFO))
3118 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3119 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3122 offset = start_offset;
3123 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3125 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3127 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
3128 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
3129 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
3130 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3131 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3132 if (cn_flags_tree) {
3133 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3134 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3135 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3136 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3137 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3138 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3139 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3140 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3144 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3145 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3147 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3148 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3149 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3151 offset += sizeof (hdr.drep);
3153 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3156 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3159 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3164 * Packet type specific stuff is next.
3166 switch (hdr.ptype) {
3169 dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr);
3174 dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3179 * Nothing after the common header other than credentials.
3181 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, TRUE,
3186 dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3190 dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3194 dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3198 dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
3204 * Nothing after the common header other than an authentication
3207 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
3213 * Nothing after the common header, not even an authentication
3219 /* might as well dissect the auth info */
3220 dissect_dcerpc_cn_auth (tvb, pinfo, dcerpc_tree, &hdr, FALSE,
3224 return hdr.frag_len + padding;
3228 * DCERPC dissector for connection oriented calls over packet-oriented
3232 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3235 * Only one PDU per transport packet, and only one transport
3238 if (dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE) == -1) {
3240 * It wasn't a DCERPC PDU.
3252 * DCERPC dissector for connection oriented calls over byte-stream
3256 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3260 gboolean ret = FALSE;
3263 * There may be multiple PDUs per transport packet; keep
3266 while (tvb_reported_length_remaining(tvb, offset) != 0) {
3267 pdu_len = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
3268 dcerpc_cn_desegment);
3269 if (pdu_len == -1) {
3277 * Well, we've seen at least one DCERPC PDU.
3283 * Desegmentation required - bail now.
3289 * Step to the next PDU.
3297 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
3298 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
3300 proto_item *ti = NULL;
3301 proto_tree *auth_tree = NULL;
3302 guint8 protection_level;
3305 * Initially set "*auth_level_p" to -1 to indicate that we haven't
3306 * yet seen any authentication level information.
3308 if (auth_level_p != NULL)
3312 * The authentication information is at the *end* of the PDU; in
3313 * request and response PDUs, the request and response stub data
3316 * If the full packet is here, and there's data past the end of the
3317 * packet body, then dissect the auth info.
3319 offset += hdr->frag_len;
3320 if (tvb_length_remaining(tvb, offset) > 0) {
3321 switch (hdr->auth_proto) {
3323 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
3324 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
3325 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
3326 protection_level = tvb_get_guint8 (tvb, offset);
3327 if (auth_level_p != NULL)
3328 *auth_level_p = protection_level;
3329 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
3331 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
3333 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
3334 offset += 6; /* 6 bytes of padding */
3336 offset += 2; /* 6 bytes of padding */
3337 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
3342 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
3349 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3350 proto_tree *dcerpc_tree,
3351 e_dce_dg_common_hdr_t *hdr)
3355 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3356 hdr->drep, hf_dcerpc_dg_cancel_vers,
3362 /* The only version we know about */
3363 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3364 hdr->drep, hf_dcerpc_dg_cancel_id,
3366 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3367 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3374 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
3375 proto_tree *dcerpc_tree,
3376 e_dce_dg_common_hdr_t *hdr)
3380 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3381 hdr->drep, hf_dcerpc_dg_cancel_vers,
3387 /* The only version we know about */
3388 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3389 hdr->drep, hf_dcerpc_dg_cancel_id,
3391 /* XXX - are NDR booleans 32 bits? */
3392 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3393 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3400 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3401 proto_tree *dcerpc_tree,
3402 e_dce_dg_common_hdr_t *hdr)
3409 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3410 hdr->drep, hf_dcerpc_dg_fack_vers,
3417 case 0: /* The only version documented in the DCE RPC 1.1 spec */
3418 case 1: /* This appears to be the same */
3419 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3420 hdr->drep, hf_dcerpc_dg_fack_window_size,
3422 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3423 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
3425 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3426 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
3428 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3429 hdr->drep, hf_dcerpc_dg_fack_serial_num,
3431 if (check_col (pinfo->cinfo, COL_INFO)) {
3432 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3435 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3436 hdr->drep, hf_dcerpc_dg_fack_selack_len,
3438 for (i = 0; i < selack_len; i++) {
3439 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3440 hdr->drep, hf_dcerpc_dg_fack_selack,
3449 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
3450 proto_tree *dcerpc_tree,
3451 e_dce_dg_common_hdr_t *hdr)
3455 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3456 hdr->drep, hf_dcerpc_dg_status,
3459 if (check_col (pinfo->cinfo, COL_INFO)) {
3460 col_append_fstr (pinfo->cinfo, COL_INFO,
3462 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3467 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
3468 proto_tree *dcerpc_tree, proto_tree *tree,
3469 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
3471 int length, reported_length, stub_length;
3472 gboolean save_fragmented;
3473 fragment_data *fd_head;
3475 if (check_col (pinfo->cinfo, COL_INFO)) {
3476 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u",
3477 di->call_data->opnum);
3480 length = tvb_length_remaining (tvb, offset);
3481 reported_length = tvb_reported_length_remaining (tvb, offset);
3482 stub_length = hdr->frag_len;
3483 if (length > stub_length)
3484 length = stub_length;
3485 if (reported_length > stub_length)
3486 reported_length = stub_length;
3488 save_fragmented = pinfo->fragmented;
3490 /* If we don't have reassembly enabled, or this packet contains
3491 the entire PDU, or if this is a short frame (or a frame
3492 not reassembled at a lower layer) that doesn't include all
3493 the data in the fragment, just call the handoff directly if
3494 this is the first fragment or the PDU isn't fragmented. */
3495 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
3496 !tvb_bytes_exist(tvb, offset, stub_length) ){
3497 if(hdr->frag_num == 0) {
3498 /* First fragment, possibly the only fragment */
3501 * XXX - authentication info?
3503 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
3504 dcerpc_try_handoff (pinfo, tree, dcerpc_tree,
3505 tvb_new_subset (tvb, offset, length,
3507 0, hdr->drep, di, NULL);
3509 /* PDU is fragmented and this isn't the first fragment */
3510 if (check_col(pinfo->cinfo, COL_INFO)) {
3511 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3515 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3516 "Fragment data (%d byte%s)",
3518 plurality(stub_length, "", "s"));
3523 /* Reassembly is enabled, the PDU is fragmented, and
3524 we have all the data in the fragment; the first two
3525 of those mean we should attempt reassembly, and the
3526 third means we can attempt reassembly. */
3529 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3530 "Fragment data (%d byte%s)", stub_length,
3531 plurality(stub_length, "", "s"));
3535 fd_head = fragment_add_seq(tvb, offset, pinfo,
3536 hdr->seqnum, dcerpc_cl_reassemble_table,
3537 hdr->frag_num, stub_length,
3538 !(hdr->flags1 & PFCL1_LASTFRAG));
3539 if (fd_head != NULL) {
3540 /* We completed reassembly */
3543 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3544 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3545 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3546 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
3547 dcerpc_tree, pinfo, next_tvb);
3550 * XXX - authentication info?
3552 pinfo->fragmented = FALSE;
3553 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3554 0, hdr->drep, di, NULL);
3556 /* Reassembly isn't completed yet */
3557 if (check_col(pinfo->cinfo, COL_INFO)) {
3558 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3562 pinfo->fragmented = save_fragmented;
3566 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
3567 proto_tree *dcerpc_tree, proto_tree *tree,
3568 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3571 dcerpc_call_value *value, v;
3572 dcerpc_matched_key matched_key, *new_matched_key;
3575 if(!(pinfo->fd->flags.visited)){
3576 dcerpc_call_value *call_value;
3577 dcerpc_call_key *call_key;
3579 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
3580 call_key->conv=conv;
3581 call_key->call_id=hdr->seqnum;
3582 call_key->smb_fid=get_smb_fid(pinfo->private_data);
3584 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
3585 call_value->uuid = hdr->if_id;
3586 call_value->ver = hdr->if_ver;
3587 call_value->opnum = hdr->opnum;
3588 call_value->req_frame=pinfo->fd->num;
3589 call_value->req_time.secs=pinfo->fd->abs_secs;
3590 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3591 call_value->rep_frame=0;
3592 call_value->max_ptr=0;
3593 call_value->private_data = NULL;
3594 g_hash_table_insert (dcerpc_calls, call_key, call_value);
3596 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3597 new_matched_key->frame = pinfo->fd->num;
3598 new_matched_key->call_id = hdr->seqnum;
3599 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3602 matched_key.frame = pinfo->fd->num;
3603 matched_key.call_id = hdr->seqnum;
3604 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3606 v.uuid = hdr->if_id;
3607 v.ver = hdr->if_ver;
3608 v.opnum = hdr->opnum;
3609 v.req_frame = pinfo->fd->num;
3612 v.private_data=NULL;
3617 di->call_id = hdr->seqnum;
3620 di->call_data = value;
3622 if(value->rep_frame!=0){
3623 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3624 tvb, 0, 0, value->rep_frame);
3626 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
3630 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
3631 proto_tree *dcerpc_tree, proto_tree *tree,
3632 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3635 dcerpc_call_value *value, v;
3636 dcerpc_matched_key matched_key, *new_matched_key;
3639 if(!(pinfo->fd->flags.visited)){
3640 dcerpc_call_value *call_value;
3641 dcerpc_call_key call_key;
3644 call_key.call_id=hdr->seqnum;
3645 call_key.smb_fid=get_smb_fid(pinfo->private_data);
3647 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
3648 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3649 new_matched_key->frame = pinfo->fd->num;
3650 new_matched_key->call_id = hdr->seqnum;
3651 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3652 if(call_value->rep_frame==0){
3653 call_value->rep_frame=pinfo->fd->num;
3658 matched_key.frame = pinfo->fd->num;
3659 matched_key.call_id = hdr->seqnum;
3660 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3662 v.uuid = hdr->if_id;
3663 v.ver = hdr->if_ver;
3664 v.opnum = hdr->opnum;
3666 v.rep_frame=pinfo->fd->num;
3667 v.private_data=NULL;
3674 di->request = FALSE;
3675 di->call_data = value;
3677 if(value->req_frame!=0){
3679 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3680 tvb, 0, 0, value->req_frame);
3681 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3682 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3684 ns.nsecs+=1000000000;
3687 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3689 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
3693 * DCERPC dissector for connectionless calls
3696 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3698 proto_item *ti = NULL;
3699 proto_item *tf = NULL;
3700 proto_tree *dcerpc_tree = NULL;
3701 proto_tree *dg_flags1_tree = NULL;
3702 proto_tree *dg_flags2_tree = NULL;
3703 proto_tree *drep_tree = NULL;
3704 e_dce_dg_common_hdr_t hdr;
3706 conversation_t *conv;
3708 char uuid_str[DCERPC_UUID_STR_LEN];
3712 * Check if this looks like a CL DCERPC call. All dg packets
3713 * have an 80 byte header on them. Which starts with
3714 * version (4), pkt_type.
3716 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
3719 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3720 if (hdr.rpc_ver != 4)
3722 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3726 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3727 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3728 if (check_col (pinfo->cinfo, COL_INFO))
3729 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
3731 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
3732 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
3733 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3734 offset += sizeof (hdr.drep);
3735 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
3736 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
3738 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
3740 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
3742 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3744 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3746 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3748 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3750 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3752 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3754 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3756 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3758 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
3759 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
3762 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
3764 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
3770 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3774 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3778 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
3779 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
3780 if (dg_flags1_tree) {
3781 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
3782 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
3783 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
3784 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
3785 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
3786 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
3787 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
3788 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
3794 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
3795 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
3796 if (dg_flags2_tree) {
3797 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
3798 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
3799 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
3800 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
3801 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
3802 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
3803 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
3804 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
3810 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
3811 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3813 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3814 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3815 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3818 offset += sizeof (hdr.drep);
3821 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
3825 /* XXX - use "dissect_ndr_uuid_t()"? */
3826 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3827 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3828 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
3829 hdr.obj_id.Data4[0],
3830 hdr.obj_id.Data4[1],
3831 hdr.obj_id.Data4[2],
3832 hdr.obj_id.Data4[3],
3833 hdr.obj_id.Data4[4],
3834 hdr.obj_id.Data4[5],
3835 hdr.obj_id.Data4[6],
3836 hdr.obj_id.Data4[7]);
3837 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3838 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3839 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3840 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
3845 /* XXX - use "dissect_ndr_uuid_t()"? */
3846 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3847 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3848 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
3856 hdr.if_id.Data4[7]);
3857 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3858 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3859 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
3860 offset, 16, uuid_str, "Interface: %s", uuid_str);
3865 /* XXX - use "dissect_ndr_uuid_t()"? */
3866 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3867 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3868 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
3869 hdr.act_id.Data4[0],
3870 hdr.act_id.Data4[1],
3871 hdr.act_id.Data4[2],
3872 hdr.act_id.Data4[3],
3873 hdr.act_id.Data4[4],
3874 hdr.act_id.Data4[5],
3875 hdr.act_id.Data4[6],
3876 hdr.act_id.Data4[7]);
3877 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
3878 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3879 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
3880 offset, 16, uuid_str, "Activity: %s", uuid_str);
3885 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
3889 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
3893 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
3894 if (check_col (pinfo->cinfo, COL_INFO)) {
3895 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq_num: %u", hdr.seqnum);
3900 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
3904 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
3908 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
3912 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
3916 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
3917 if (check_col (pinfo->cinfo, COL_INFO)) {
3918 if (hdr.flags1 & PFCL1_FRAG) {
3919 /* Fragmented - put the fragment number into the Info column */
3920 col_append_fstr (pinfo->cinfo, COL_INFO, " frag_num: %u",
3927 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
3931 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
3932 if (check_col (pinfo->cinfo, COL_INFO)) {
3933 if (hdr.flags1 & PFCL1_FRAG) {
3934 /* Fragmented - put the serial number into the Info column */
3935 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3936 (hdr.serial_hi << 8) | hdr.serial_lo);
3943 * XXX - for Kerberos, we get a protection level; if it's
3944 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
3947 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
3952 * keeping track of the conversation shouldn't really be necessary
3953 * for connectionless packets, because everything we need to know
3954 * to dissect is in the header for each packet. Unfortunately,
3955 * Microsoft's implementation is buggy and often puts the
3956 * completely wrong if_id in the header. go figure. So, keep
3957 * track of the seqnum and use that if possible. Note: that's not
3958 * completely correct. It should really be done based on both the
3959 * activity_id and seqnum. I haven't seen anywhere that it would
3960 * make a difference, but for future reference...
3962 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
3963 pinfo->srcport, pinfo->destport, 0);
3965 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
3966 pinfo->srcport, pinfo->destport, 0);
3970 * Packet type specific stuff is next.
3973 switch (hdr.ptype) {
3975 case PDU_CANCEL_ACK:
3976 /* Body is optional */
3977 /* XXX - we assume "frag_len" is the length of the body */
3978 if (hdr.frag_len != 0)
3979 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3984 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
3985 * but in at least one capture none of the Cl_cancel PDUs had a
3988 /* XXX - we assume "frag_len" is the length of the body */
3989 if (hdr.frag_len != 0)
3990 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
3994 /* Body is optional; if present, it's the same as PDU_FACK */
3995 /* XXX - we assume "frag_len" is the length of the body */
3996 if (hdr.frag_len != 0)
3997 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4001 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4006 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
4010 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4014 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4017 /* these requests have no body */
4029 dcerpc_init_protocol (void)
4031 /* structures and data for BIND */
4033 g_hash_table_destroy (dcerpc_binds);
4035 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
4037 if (dcerpc_bind_key_chunk){
4038 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
4040 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
4041 sizeof (dcerpc_bind_key),
4042 200 * sizeof (dcerpc_bind_key),
4044 if (dcerpc_bind_value_chunk){
4045 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
4047 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
4048 sizeof (dcerpc_bind_value),
4049 200 * sizeof (dcerpc_bind_value),
4051 /* structures and data for CALL */
4053 g_hash_table_destroy (dcerpc_calls);
4055 dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
4056 if (dcerpc_call_key_chunk){
4057 g_mem_chunk_destroy (dcerpc_call_key_chunk);
4059 dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
4060 sizeof (dcerpc_call_key),
4061 200 * sizeof (dcerpc_call_key),
4063 if (dcerpc_call_value_chunk){
4064 g_mem_chunk_destroy (dcerpc_call_value_chunk);
4066 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
4067 sizeof (dcerpc_call_value),
4068 200 * sizeof (dcerpc_call_value),
4071 /* structure and data for MATCHED */
4072 if (dcerpc_matched){
4073 g_hash_table_destroy (dcerpc_matched);
4075 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
4076 if (dcerpc_matched_key_chunk){
4077 g_mem_chunk_destroy (dcerpc_matched_key_chunk);
4079 dcerpc_matched_key_chunk = g_mem_chunk_new ("dcerpc_matched_key_chunk",
4080 sizeof (dcerpc_matched_key),
4081 200 * sizeof (dcerpc_matched_key),
4086 proto_register_dcerpc (void)
4088 static hf_register_info hf[] = {
4089 { &hf_dcerpc_request_in,
4090 { "Request in", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
4091 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
4092 { &hf_dcerpc_response_in,
4093 { "Response in", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
4094 NULL, 0, "The response to this packet is in this packet", HFILL }},
4095 { &hf_dcerpc_referent_id,
4096 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
4097 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
4099 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4100 { &hf_dcerpc_ver_minor,
4101 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4102 { &hf_dcerpc_packet_type,
4103 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
4104 { &hf_dcerpc_cn_flags,
4105 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4106 { &hf_dcerpc_cn_flags_first_frag,
4107 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
4108 { &hf_dcerpc_cn_flags_last_frag,
4109 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
4110 { &hf_dcerpc_cn_flags_cancel_pending,
4111 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
4112 { &hf_dcerpc_cn_flags_reserved,
4113 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
4114 { &hf_dcerpc_cn_flags_mpx,
4115 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
4116 { &hf_dcerpc_cn_flags_dne,
4117 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
4118 { &hf_dcerpc_cn_flags_maybe,
4119 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
4120 { &hf_dcerpc_cn_flags_object,
4121 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
4123 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
4124 { &hf_dcerpc_drep_byteorder,
4125 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
4126 { &hf_dcerpc_drep_character,
4127 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
4128 { &hf_dcerpc_drep_fp,
4129 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
4130 { &hf_dcerpc_cn_frag_len,
4131 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4132 { &hf_dcerpc_cn_auth_len,
4133 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4134 { &hf_dcerpc_cn_call_id,
4135 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4136 { &hf_dcerpc_cn_max_xmit,
4137 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4138 { &hf_dcerpc_cn_max_recv,
4139 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4140 { &hf_dcerpc_cn_assoc_group,
4141 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4142 { &hf_dcerpc_cn_num_ctx_items,
4143 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4144 { &hf_dcerpc_cn_ctx_id,
4145 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4146 { &hf_dcerpc_cn_num_trans_items,
4147 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4148 { &hf_dcerpc_cn_bind_if_id,
4149 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4150 { &hf_dcerpc_cn_bind_if_ver,
4151 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4152 { &hf_dcerpc_cn_bind_if_ver_minor,
4153 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4154 { &hf_dcerpc_cn_bind_trans_id,
4155 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4156 { &hf_dcerpc_cn_bind_trans_ver,
4157 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4158 { &hf_dcerpc_cn_alloc_hint,
4159 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4160 { &hf_dcerpc_cn_sec_addr_len,
4161 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4162 { &hf_dcerpc_cn_sec_addr,
4163 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
4164 { &hf_dcerpc_cn_num_results,
4165 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4166 { &hf_dcerpc_cn_ack_result,
4167 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
4168 { &hf_dcerpc_cn_ack_reason,
4169 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
4170 { &hf_dcerpc_cn_ack_trans_id,
4171 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4172 { &hf_dcerpc_cn_ack_trans_ver,
4173 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4174 { &hf_dcerpc_cn_reject_reason,
4175 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
4176 { &hf_dcerpc_cn_num_protocols,
4177 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4178 { &hf_dcerpc_cn_protocol_ver_major,
4179 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4180 { &hf_dcerpc_cn_protocol_ver_minor,
4181 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4182 { &hf_dcerpc_cn_cancel_count,
4183 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4184 { &hf_dcerpc_cn_status,
4185 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4186 { &hf_dcerpc_auth_type,
4187 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4188 { &hf_dcerpc_auth_level,
4189 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
4190 { &hf_dcerpc_auth_pad_len,
4191 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4192 { &hf_dcerpc_auth_rsrvd,
4193 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4194 { &hf_dcerpc_auth_ctx_id,
4195 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4196 { &hf_dcerpc_dg_flags1,
4197 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4198 { &hf_dcerpc_dg_flags1_rsrvd_01,
4199 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
4200 { &hf_dcerpc_dg_flags1_last_frag,
4201 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
4202 { &hf_dcerpc_dg_flags1_frag,
4203 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
4204 { &hf_dcerpc_dg_flags1_nofack,
4205 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
4206 { &hf_dcerpc_dg_flags1_maybe,
4207 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
4208 { &hf_dcerpc_dg_flags1_idempotent,
4209 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
4210 { &hf_dcerpc_dg_flags1_broadcast,
4211 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
4212 { &hf_dcerpc_dg_flags1_rsrvd_80,
4213 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
4214 { &hf_dcerpc_dg_flags2,
4215 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4216 { &hf_dcerpc_dg_flags2_rsrvd_01,
4217 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
4218 { &hf_dcerpc_dg_flags2_cancel_pending,
4219 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
4220 { &hf_dcerpc_dg_flags2_rsrvd_04,
4221 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
4222 { &hf_dcerpc_dg_flags2_rsrvd_08,
4223 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
4224 { &hf_dcerpc_dg_flags2_rsrvd_10,
4225 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
4226 { &hf_dcerpc_dg_flags2_rsrvd_20,
4227 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
4228 { &hf_dcerpc_dg_flags2_rsrvd_40,
4229 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
4230 { &hf_dcerpc_dg_flags2_rsrvd_80,
4231 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
4232 { &hf_dcerpc_dg_serial_lo,
4233 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4234 { &hf_dcerpc_dg_serial_hi,
4235 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4236 { &hf_dcerpc_dg_ahint,
4237 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4238 { &hf_dcerpc_dg_ihint,
4239 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4240 { &hf_dcerpc_dg_frag_len,
4241 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4242 { &hf_dcerpc_dg_frag_num,
4243 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4244 { &hf_dcerpc_dg_auth_proto,
4245 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4246 { &hf_dcerpc_dg_seqnum,
4247 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4248 { &hf_dcerpc_dg_server_boot,
4249 { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4250 { &hf_dcerpc_dg_if_ver,
4251 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4252 { &hf_dcerpc_krb5_av_prot_level,
4253 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
4254 { &hf_dcerpc_krb5_av_key_vers_num,
4255 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4256 { &hf_dcerpc_krb5_av_key_auth_verifier,
4257 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
4258 { &hf_dcerpc_obj_id,
4259 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4260 { &hf_dcerpc_dg_if_id,
4261 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4262 { &hf_dcerpc_dg_act_id,
4263 { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4265 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4267 { &hf_dcerpc_dg_cancel_vers,
4268 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4270 { &hf_dcerpc_dg_cancel_id,
4271 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4273 { &hf_dcerpc_dg_server_accepting_cancels,
4274 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
4276 { &hf_dcerpc_dg_fack_vers,
4277 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4279 { &hf_dcerpc_dg_fack_window_size,
4280 { "Window Size", "dcerpc.fack_window size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4282 { &hf_dcerpc_dg_fack_max_tsdu,
4283 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4285 { &hf_dcerpc_dg_fack_max_frag_size,
4286 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4288 { &hf_dcerpc_dg_fack_serial_num,
4289 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4291 { &hf_dcerpc_dg_fack_selack_len,
4292 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4294 { &hf_dcerpc_dg_fack_selack,
4295 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4297 { &hf_dcerpc_dg_status,
4298 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4300 { &hf_dcerpc_array_max_count,
4301 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
4303 { &hf_dcerpc_array_offset,
4304 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
4306 { &hf_dcerpc_array_actual_count,
4307 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
4309 { &hf_dcerpc_array_buffer,
4310 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
4313 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4315 { &hf_dcerpc_fragments,
4316 { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
4317 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
4319 { &hf_dcerpc_fragment,
4320 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
4321 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
4323 { &hf_dcerpc_fragment_overlap,
4324 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
4326 { &hf_dcerpc_fragment_overlap_conflict,
4327 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
4329 { &hf_dcerpc_fragment_multiple_tails,
4330 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
4332 { &hf_dcerpc_fragment_too_long_fragment,
4333 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
4335 { &hf_dcerpc_fragment_error,
4336 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
4339 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "Time between Request and Reply for DCE-RPC calls", HFILL }},
4340 { &hf_dcerpc_reassembled_in,
4341 { "This PDU is reassembled in", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "The DCE/RPC PDU is completely reassembled in this frame", HFILL }},
4343 static gint *ett[] = {
4345 &ett_dcerpc_cn_flags,
4347 &ett_dcerpc_cn_iface,
4349 &ett_dcerpc_dg_flags1,
4350 &ett_dcerpc_dg_flags2,
4351 &ett_dcerpc_pointer_data,
4353 &ett_dcerpc_fragments,
4354 &ett_dcerpc_fragment,
4355 &ett_dcerpc_krb5_auth_verf,
4357 module_t *dcerpc_module;
4359 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
4360 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
4361 proto_register_subtree_array (ett, array_length (ett));
4362 register_init_routine (dcerpc_init_protocol);
4363 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
4364 prefs_register_bool_preference (dcerpc_module,
4366 "Desegment all DCE/RPC over TCP",
4367 "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
4368 &dcerpc_cn_desegment);
4369 prefs_register_bool_preference (dcerpc_module,
4370 "reassemble_dcerpc",
4371 "Reassemble DCE/RPC fragments",
4372 "Whether the DCE/RPC dissector should reassemble all fragmented PDUs",
4373 &dcerpc_reassemble);
4374 register_init_routine(dcerpc_reassemble_init);
4375 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
4376 dcerpc_tap=register_tap("dcerpc");
4380 proto_reg_handoff_dcerpc (void)
4382 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
4383 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
4384 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
4385 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
4386 dcerpc_smb_init(proto_dcerpc);