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.162 2004/02/21 09:57:15 guy 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;
389 static int hf_dcerpc_unknown_if_id = -1;
391 static gint ett_dcerpc = -1;
392 static gint ett_dcerpc_cn_flags = -1;
393 static gint ett_dcerpc_cn_ctx = -1;
394 static gint ett_dcerpc_cn_iface = -1;
395 static gint ett_dcerpc_drep = -1;
396 static gint ett_dcerpc_dg_flags1 = -1;
397 static gint ett_dcerpc_dg_flags2 = -1;
398 static gint ett_dcerpc_pointer_data = -1;
399 static gint ett_dcerpc_string = -1;
400 static gint ett_dcerpc_fragments = -1;
401 static gint ett_dcerpc_fragment = -1;
402 static gint ett_dcerpc_krb5_auth_verf = -1;
404 static const fragment_items dcerpc_frag_items = {
405 &ett_dcerpc_fragments,
406 &ett_dcerpc_fragment,
408 &hf_dcerpc_fragments,
410 &hf_dcerpc_fragment_overlap,
411 &hf_dcerpc_fragment_overlap_conflict,
412 &hf_dcerpc_fragment_multiple_tails,
413 &hf_dcerpc_fragment_too_long_fragment,
414 &hf_dcerpc_fragment_error,
425 static dcerpc_info di[20];
426 static int di_counter=0;
432 return &di[di_counter];
435 /* try to desegment big DCE/RPC packets over TCP? */
436 static gboolean dcerpc_cn_desegment = TRUE;
438 /* reassemble DCE/RPC fragments */
439 /* reassembly of dcerpc fragments will not work for the case where ONE frame
440 might contain multiple dcerpc fragments for different PDUs.
441 this case would be so unusual/weird so if you got captures like that:
444 static gboolean dcerpc_reassemble = FALSE;
445 static GHashTable *dcerpc_co_reassemble_table = NULL;
446 static GHashTable *dcerpc_cl_reassemble_table = NULL;
449 dcerpc_reassemble_init(void)
451 fragment_table_init(&dcerpc_co_reassemble_table);
452 fragment_table_init(&dcerpc_cl_reassemble_table);
456 * Authentication subdissectors. Used to dissect authentication blobs in
457 * DCERPC binds, requests and responses.
460 typedef struct _dcerpc_auth_subdissector {
463 dcerpc_auth_subdissector_fns auth_fns;
464 } dcerpc_auth_subdissector;
466 static GSList *dcerpc_auth_subdissector_list;
468 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
469 guint8 auth_level, guint8 auth_type)
474 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
475 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
477 if (asd->auth_level == auth_level &&
478 asd->auth_type == auth_type)
479 return &asd->auth_fns;
485 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
486 dcerpc_auth_subdissector_fns *fns)
488 dcerpc_auth_subdissector *d;
490 if (get_auth_subdissector_fns(auth_level, auth_type))
493 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
495 d->auth_level = auth_level;
496 d->auth_type = auth_type;
497 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
499 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
502 /* Hand off verifier data to a registered dissector */
504 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
506 dcerpc_auth_subdissector_fns *auth_fns,
507 e_dce_cn_common_hdr_t *hdr,
508 dcerpc_auth_info *auth_info)
510 dcerpc_dissect_fnct_t *volatile fn = NULL;
512 switch (hdr->ptype) {
515 fn = auth_fns->bind_fn;
519 fn = auth_fns->bind_ack_fn;
522 fn = auth_fns->auth3_fn;
525 fn = auth_fns->req_verf_fn;
528 fn = auth_fns->resp_verf_fn;
531 /* Don't know how to handle authentication data in this
535 g_warning("attempt to dissect %s pdu authentication data",
536 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
541 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
543 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
545 val_to_str(auth_info->auth_type,
550 /* Hand off payload data to a registered dissector */
552 static tvbuff_t *decode_encrypted_data(tvbuff_t *enc_tvb,
554 dcerpc_auth_subdissector_fns *auth_fns,
556 dcerpc_auth_info *auth_info)
558 dcerpc_decode_data_fnct_t *fn;
561 fn = auth_fns->req_data_fn;
563 fn = auth_fns->resp_data_fn;
566 return fn(enc_tvb, 0, pinfo, auth_info);
575 /* the registered subdissectors */
576 GHashTable *dcerpc_uuids=NULL;
579 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
581 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
582 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
583 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
584 && (key1->ver == key2->ver));
588 dcerpc_uuid_hash (gconstpointer k)
590 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
591 /* This isn't perfect, but the Data1 part of these is almost always
593 return key->uuid.Data1;
597 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
598 dcerpc_sub_dissector *procs, int opnum_hf)
600 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
601 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
602 header_field_info *hf_info;
607 value->proto = find_protocol_by_id(proto);
608 value->proto_id = proto;
610 value->name = proto_get_protocol_short_name (value->proto);
611 value->procs = procs;
612 value->opnum_hf = opnum_hf;
614 g_hash_table_insert (dcerpc_uuids, key, value);
616 hf_info = proto_registrar_get_nth(opnum_hf);
617 hf_info->strings = value_string_from_subdissectors(procs);
620 /* Function to find the name of a registered protocol
621 * or NULL if the protocol/version is not known to ethereal.
624 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
627 dcerpc_uuid_value *sub_proto;
631 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
634 return sub_proto->name;
637 /* Function to find the opnum hf-field of a registered protocol
638 * or -1 if the protocol/version is not known to ethereal.
641 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
644 dcerpc_uuid_value *sub_proto;
648 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
651 return sub_proto->opnum_hf;
654 /* Create a value_string consisting of DCERPC opnum and name from a
655 subdissector array. */
657 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
659 value_string *vs = NULL;
663 for (i = 0; sd[i].name; i++) {
665 vs[i].value = sd[i].num;
666 vs[i].strptr = sd[i].name;
672 vs = g_malloc((num_sd + 1) * sizeof(value_string));
676 vs[num_sd].value = 0;
677 vs[num_sd].strptr = NULL;
682 /* Function to find the subdissector table of a registered protocol
683 * or NULL if the protocol/version is not known to ethereal.
685 dcerpc_sub_dissector *
686 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
689 dcerpc_uuid_value *sub_proto;
693 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
696 return sub_proto->procs;
701 * To keep track of ctx_id mappings.
703 * Everytime we see a bind call we update this table.
704 * Note that we always specify a SMB FID. For non-SMB transports this
707 static GHashTable *dcerpc_binds=NULL;
709 typedef struct _dcerpc_bind_key {
710 conversation_t *conv;
715 typedef struct _dcerpc_bind_value {
720 static GMemChunk *dcerpc_bind_key_chunk=NULL;
721 static GMemChunk *dcerpc_bind_value_chunk=NULL;
724 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
726 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
727 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
728 return (key1->conv == key2->conv
729 && key1->ctx_id == key2->ctx_id
730 && key1->smb_fid == key2->smb_fid);
734 dcerpc_bind_hash (gconstpointer k)
736 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
737 return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
742 * To keep track of callid mappings. Should really use some generic
743 * conversation support instead.
745 static GHashTable *dcerpc_calls=NULL;
747 typedef struct _dcerpc_call_key {
748 conversation_t *conv;
753 static GMemChunk *dcerpc_call_key_chunk=NULL;
755 static GMemChunk *dcerpc_call_value_chunk=NULL;
758 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
760 const dcerpc_call_key *key1 = (const dcerpc_call_key *)k1;
761 const dcerpc_call_key *key2 = (const dcerpc_call_key *)k2;
762 return (key1->conv == key2->conv
763 && key1->call_id == key2->call_id
764 && key1->smb_fid == key2->smb_fid);
768 dcerpc_call_hash (gconstpointer k)
770 const dcerpc_call_key *key = (const dcerpc_call_key *)k;
771 return ((guint32)key->conv) + key->call_id + key->smb_fid;
775 /* to keep track of matched calls/responses
776 this one uses the same value struct as calls, but the key is the frame id
777 and call id; there can be more than one call in a frame.
779 XXX - why not just use the same keys as are used for calls?
782 static GHashTable *dcerpc_matched=NULL;
784 typedef struct _dcerpc_matched_key {
787 } dcerpc_matched_key;
789 static GMemChunk *dcerpc_matched_key_chunk=NULL;
792 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
794 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
795 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
796 return (key1->frame == key2->frame
797 && key1->call_id == key2->call_id);
801 dcerpc_matched_hash (gconstpointer k)
803 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
810 * Utility functions. Modeled after packet-rpc.c
814 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
815 proto_tree *tree, guint8 *drep,
816 int hfindex, guint8 *pdata)
820 data = tvb_get_guint8 (tvb, offset);
822 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
830 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
831 proto_tree *tree, guint8 *drep,
832 int hfindex, guint16 *pdata)
836 data = ((drep[0] & 0x10)
837 ? tvb_get_letohs (tvb, offset)
838 : tvb_get_ntohs (tvb, offset));
841 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
849 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
850 proto_tree *tree, guint8 *drep,
851 int hfindex, guint32 *pdata)
855 data = ((drep[0] & 0x10)
856 ? tvb_get_letohl (tvb, offset)
857 : tvb_get_ntohl (tvb, offset));
860 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
867 /* handles 32 bit unix time_t */
869 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
870 proto_tree *tree, guint8 *drep,
871 int hfindex, guint32 *pdata)
876 data = ((drep[0] & 0x10)
877 ? tvb_get_letohl (tvb, offset)
878 : tvb_get_ntohl (tvb, offset));
883 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
892 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
893 proto_tree *tree, guint8 *drep,
894 int hfindex, unsigned char *pdata)
897 tvb_memcpy(tvb, pdata, offset, 8);
898 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
900 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
901 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
902 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
903 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
908 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
916 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
917 proto_tree *tree, guint8 *drep,
918 int hfindex, gfloat *pdata)
924 case(DCE_RPC_DREP_FP_IEEE):
925 data = ((drep[0] & 0x10)
926 ? tvb_get_letohieee_float(tvb, offset)
927 : tvb_get_ntohieee_float(tvb, offset));
929 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
932 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
933 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
934 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
936 /* ToBeDone: non IEEE floating formats */
937 /* Set data to a negative infinity value */
940 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
950 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
951 proto_tree *tree, guint8 *drep,
952 int hfindex, gdouble *pdata)
958 case(DCE_RPC_DREP_FP_IEEE):
959 data = ((drep[0] & 0x10)
960 ? tvb_get_letohieee_double(tvb, offset)
961 : tvb_get_ntohieee_double(tvb, offset));
963 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
966 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
967 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
968 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
970 /* ToBeDone: non IEEE double formats */
971 /* Set data to a negative infinity value */
974 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
984 * a couple simpler things
987 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, guint8 *drep)
989 if (drep[0] & 0x10) {
990 return tvb_get_letohs (tvb, offset);
992 return tvb_get_ntohs (tvb, offset);
997 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, guint8 *drep)
999 if (drep[0] & 0x10) {
1000 return tvb_get_letohl (tvb, offset);
1002 return tvb_get_ntohl (tvb, offset);
1007 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1010 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
1011 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
1012 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
1014 for (i=0; i<sizeof (uuid->Data4); i++) {
1015 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
1022 /* function to dissect a unidimensional conformant array */
1024 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1025 proto_tree *tree, guint8 *drep,
1026 dcerpc_dissect_fnct_t *fnct)
1032 di=pinfo->private_data;
1033 if(di->conformant_run){
1034 /* conformant run, just dissect the max_count header */
1036 di->conformant_run=0;
1037 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1038 hf_dcerpc_array_max_count, &di->array_max_count);
1039 di->array_max_count_offset=offset-4;
1040 di->conformant_run=1;
1041 di->conformant_eaten=offset-old_offset;
1043 /* we don't remember where in the bytestream this field was */
1044 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1046 /* real run, dissect the elements */
1047 for(i=0;i<di->array_max_count;i++){
1048 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1054 /* function to dissect a unidimensional conformant and varying array */
1056 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1057 proto_tree *tree, guint8 *drep,
1058 dcerpc_dissect_fnct_t *fnct)
1064 di=pinfo->private_data;
1065 if(di->conformant_run){
1066 /* conformant run, just dissect the max_count header */
1068 di->conformant_run=0;
1069 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1070 hf_dcerpc_array_max_count, &di->array_max_count);
1071 di->array_max_count_offset=offset-4;
1072 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1073 hf_dcerpc_array_offset, &di->array_offset);
1074 di->array_offset_offset=offset-4;
1075 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1076 hf_dcerpc_array_actual_count, &di->array_actual_count);
1077 di->array_actual_count_offset=offset-4;
1078 di->conformant_run=1;
1079 di->conformant_eaten=offset-old_offset;
1081 /* we dont dont remember where in the bytestream these fields were */
1082 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1083 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1084 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1086 /* real run, dissect the elements */
1087 for(i=0;i<di->array_actual_count;i++){
1088 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1095 /* Dissect an string of bytes. This corresponds to
1096 IDL of the form '[string] byte *foo'.
1098 It can also be used for a conformant varying array of bytes if
1099 the contents of the array should be shown as a big blob, rather
1100 than showing each byte as an individual element.
1102 XXX - which of those is really the IDL type for, for example,
1103 the encrypted data in some MAPI packets? (Microsoft haven't
1106 XXX - does this need to do all the conformant array stuff that
1107 "dissect_ndr_ucvarray()" does? These are presumably for strings
1108 that are conformant and varying - they're stored like conformant
1109 varying arrays of bytes. */
1111 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1112 proto_tree *tree, guint8 *drep)
1117 di=pinfo->private_data;
1118 if(di->conformant_run){
1119 /* just a run to handle conformant arrays, no scalars to dissect */
1123 /* NDR array header */
1125 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1126 hf_dcerpc_array_max_count, NULL);
1128 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1129 hf_dcerpc_array_offset, NULL);
1131 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1132 hf_dcerpc_array_actual_count, &len);
1135 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1136 tvb, offset, len, drep[0] & 0x10);
1143 /* For dissecting arrays that are to be interpreted as strings. */
1145 /* Dissect an NDR conformant varying string of elements.
1146 The length of each element is given by the 'size_is' parameter;
1147 the elements are assumed to be characters or wide characters.
1149 XXX - does this need to do all the conformant array stuff that
1150 "dissect_ndr_ucvarray()" does? */
1152 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1153 proto_tree *tree, guint8 *drep, int size_is,
1154 int hfindex, gboolean add_subtree, char **data)
1157 proto_item *string_item;
1158 proto_tree *string_tree;
1159 guint32 len, buffer_len;
1161 header_field_info *hfinfo;
1163 di=pinfo->private_data;
1164 if(di->conformant_run){
1165 /* just a run to handle conformant arrays, no scalars to dissect */
1170 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1171 proto_registrar_get_name(hfindex));
1172 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1178 /* NDR array header */
1180 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1181 hf_dcerpc_array_max_count, NULL);
1183 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1184 hf_dcerpc_array_offset, NULL);
1186 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1187 hf_dcerpc_array_actual_count, &len);
1189 buffer_len = size_is * len;
1192 if (offset % size_is)
1193 offset += size_is - (offset % size_is);
1195 if (size_is == sizeof(guint16)) {
1196 /* XXX - use drep to determine the byte order? */
1197 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1199 * XXX - we don't support a string type with Unicode
1200 * characters, so if this is a string item, we make
1201 * its value be the "fake Unicode" string.
1203 if (tree && buffer_len) {
1204 hfinfo = proto_registrar_get_nth(hfindex);
1205 if (hfinfo->type == FT_STRING) {
1206 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1209 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1210 buffer_len, drep[0] & 0x10);
1215 * "tvb_get_string()" throws an exception if the entire string
1216 * isn't in the tvbuff. If the length is bogus, this should
1217 * keep us from trying to allocate an immensely large buffer.
1218 * (It won't help if the length is *valid* but immensely large,
1219 * but that's another matter; in any case, that would happen only
1220 * if we had an immensely large tvbuff....)
1222 s = tvb_get_string(tvb, offset, buffer_len);
1223 if (tree && buffer_len)
1224 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1225 buffer_len, drep[0] & 0x10);
1228 if (string_item != NULL)
1229 proto_item_append_text(string_item, ": %s", s);
1236 offset += buffer_len;
1238 proto_item_set_end(string_item, tvb, offset);
1243 /* Dissect an conformant varying string of chars.
1244 This corresponds to IDL of the form '[string] char *foo'.
1246 XXX - at least according to the DCE RPC 1.1 spec, a string has
1247 a null terminator, which isn't necessary as a terminator for
1248 the transfer language (as there's a length), but is presumably
1249 there for the benefit of null-terminated-string languages
1250 such as C. Is this ever used for purely counted strings?
1251 (Not that it matters if it is.) */
1253 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1254 proto_tree *tree, guint8 *drep)
1257 di=pinfo->private_data;
1259 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1260 sizeof(guint8), di->hf_index,
1264 /* Dissect a conformant varying string of wchars (wide characters).
1265 This corresponds to IDL of the form '[string] wchar *foo'
1267 XXX - at least according to the DCE RPC 1.1 spec, a string has
1268 a null terminator, which isn't necessary as a terminator for
1269 the transfer language (as there's a length), but is presumably
1270 there for the benefit of null-terminated-string languages
1271 such as C. Is this ever used for purely counted strings?
1272 (Not that it matters if it is.) */
1274 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1275 proto_tree *tree, guint8 *drep)
1278 di=pinfo->private_data;
1280 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1281 sizeof(guint16), di->hf_index,
1285 /* ndr pointer handling */
1286 /* list of pointers encountered so far */
1287 static GSList *ndr_pointer_list = NULL;
1289 /* position where in the list to insert newly encountered pointers */
1290 static int ndr_pointer_list_pos=0;
1292 /* boolean controlling whether pointers are top-level or embedded */
1293 static gboolean pointers_are_top_level = TRUE;
1295 /* as a kludge, we represent all embedded reference pointers as id==-1
1296 hoping that his will not collide with any non-ref pointers */
1297 typedef struct ndr_pointer_data {
1299 proto_item *item; /* proto_item for pointer */
1300 proto_tree *tree; /* subtree of above item */
1301 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1303 dcerpc_callback_fnct_t *callback;
1304 void *callback_args;
1305 } ndr_pointer_data_t;
1308 init_ndr_pointer_list(packet_info *pinfo)
1312 di=pinfo->private_data;
1313 di->conformant_run=0;
1315 while(ndr_pointer_list){
1316 ndr_pointer_data_t *npd;
1318 npd=g_slist_nth_data(ndr_pointer_list, 0);
1319 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1325 ndr_pointer_list=NULL;
1326 ndr_pointer_list_pos=0;
1327 pointers_are_top_level=TRUE;
1331 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1333 int found_new_pointer;
1339 di=pinfo->private_data;
1343 found_new_pointer=0;
1344 len=g_slist_length(ndr_pointer_list);
1345 for(i=next_pointer;i<len;i++){
1346 ndr_pointer_data_t *tnpd;
1347 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1349 dcerpc_dissect_fnct_t *fnct;
1352 found_new_pointer=1;
1355 ndr_pointer_list_pos=i+1;
1356 di->hf_index=tnpd->hf_index;
1357 /* first a run to handle any conformant
1359 di->conformant_run=1;
1360 di->conformant_eaten=0;
1361 old_offset = offset;
1362 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1364 g_assert((offset-old_offset)==di->conformant_eaten);
1365 /* This is to check for any bugs in the dissectors.
1367 * Basically, the NDR representation will store all
1368 * arrays in two blocks, one block with the dimension
1369 * discreption, like size, number of elements and such,
1370 * and another block that contains the actual data stored
1372 * If the array is embedded directly inside another,
1373 * encapsulating aggregate type, like a union or struct,
1374 * then these two blocks will be stored at different places
1375 * in the bytestream, with other data between the blocks.
1377 * For this reason, all pointers to types (both aggregate
1378 * and scalar, for simplicity no distinction is made)
1379 * will have its dissector called twice.
1380 * The dissector will first be called with conformant_run==1
1381 * in which mode the dissector MUST NOT consume any data from
1382 * the tvbuff (i.e. may not dissect anything) except the
1383 * initial control block for arrays.
1384 * The second time the dissector is called, with
1385 * conformant_run==0, all other data for the type will be
1388 * All dissect_ndr_<type> dissectors are already prepared
1389 * for this and knows when it should eat data from the tvb
1390 * and when not to, so implementors of dissectors will
1391 * normally not need to worry about this or even know about
1392 * it. However, if a dissector for an aggregate type calls
1393 * a subdissector from outside packet-dcerpc.c, such as
1394 * the dissector in packet-smb.c for NT Security Descriptors
1395 * as an example, then it is VERY important to encapsulate
1396 * this call to an external subdissector with the appropriate
1397 * test for conformant_run, i.e. it will need something like
1401 * di=pinfo->private_data;
1402 * if(di->conformant_run){
1406 * to make sure it makes the right thing.
1407 * This assert will signal when someone has forgotten to
1408 * make the dissector aware of this requirement.
1411 /* now we dissect the actual pointer */
1412 di->conformant_run=0;
1413 old_offset = offset;
1414 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1416 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1420 } while(found_new_pointer);
1427 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1428 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1429 dcerpc_callback_fnct_t *callback, void *callback_args)
1431 ndr_pointer_data_t *npd;
1433 /* check if this pointer is valid */
1436 dcerpc_call_value *value;
1438 di=pinfo->private_data;
1439 value=di->call_data;
1442 if(!(pinfo->fd->flags.visited)){
1443 if(id>value->max_ptr){
1448 /* if we havent seen the request bail out since we cant
1449 know whether this is the first non-NULL instance
1451 if(value->req_frame==0){
1452 /* XXX THROW EXCEPTION */
1455 /* We saw this one in the request frame, nothing to
1457 if(id<=value->max_ptr){
1463 npd=g_malloc(sizeof(ndr_pointer_data_t));
1468 npd->hf_index=hf_index;
1469 npd->callback=callback;
1470 npd->callback_args=callback_args;
1471 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1472 ndr_pointer_list_pos);
1473 ndr_pointer_list_pos++;
1478 find_pointer_index(guint32 id)
1480 ndr_pointer_data_t *npd;
1483 len=g_slist_length(ndr_pointer_list);
1485 npd=g_slist_nth_data(ndr_pointer_list, i);
1496 /* This function dissects an NDR pointer and stores the callback for later
1497 * deferred dissection.
1499 * fnct is the callback function for when we have reached this object in
1502 * type is what type of pointer.
1504 * this is text is what text we should put in any created tree node.
1506 * hf_index is what hf value we want to pass to the callback function when
1507 * it is called, the callback can later pich this one up from di->hf_index.
1509 * callback is executed after the pointer has been dereferenced.
1511 * callback_args is passed as an argument to the callback function
1513 * See packet-dcerpc-samr.c for examples
1516 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1517 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1518 int type, char *text, int hf_index,
1519 dcerpc_callback_fnct_t *callback, void *callback_args)
1523 di=pinfo->private_data;
1524 if(di->conformant_run){
1525 /* this call was only for dissecting the header for any
1526 embedded conformant array. we will not parse any
1527 pointers in this mode.
1532 /*TOP LEVEL REFERENCE POINTER*/
1533 if( pointers_are_top_level
1534 &&(type==NDR_POINTER_REF) ){
1538 /* we must find out a nice way to do the length here */
1539 item=proto_tree_add_text(tree, tvb, offset, 0,
1541 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1543 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1544 hf_index, callback, callback_args);
1548 /*TOP LEVEL FULL POINTER*/
1549 if( pointers_are_top_level
1550 && (type==NDR_POINTER_PTR) ){
1556 /* get the referent id */
1557 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1559 /* we got a NULL pointer */
1561 proto_tree_add_text(tree, tvb, offset-4, 4,
1562 "(NULL pointer) %s",text);
1566 /* see if we have seen this pointer before */
1567 idx=find_pointer_index(id);
1569 /* we have seen this pointer before */
1571 proto_tree_add_text(tree, tvb, offset-4, 4,
1572 "(duplicate PTR) %s",text);
1577 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1579 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1580 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1581 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1582 callback, callback_args);
1585 /*TOP LEVEL UNIQUE POINTER*/
1586 if( pointers_are_top_level
1587 && (type==NDR_POINTER_UNIQUE) ){
1592 /* get the referent id */
1593 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1595 /* we got a NULL pointer */
1597 proto_tree_add_text(tree, tvb, offset-4, 4,
1598 "(NULL pointer) %s",text);
1603 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1605 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1606 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1607 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1608 hf_index, callback, callback_args);
1612 /*EMBEDDED REFERENCE POINTER*/
1613 if( (!pointers_are_top_level)
1614 && (type==NDR_POINTER_REF) ){
1619 /* get the referent id */
1620 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1623 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1625 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1626 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1627 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1628 hf_index, callback, callback_args);
1632 /*EMBEDDED UNIQUE POINTER*/
1633 if( (!pointers_are_top_level)
1634 && (type==NDR_POINTER_UNIQUE) ){
1639 /* get the referent id */
1640 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1642 /* we got a NULL pointer */
1644 proto_tree_add_text(tree, tvb, offset-4, 4,
1645 "(NULL pointer) %s", text);
1650 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1652 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1653 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1654 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1655 hf_index, callback, callback_args);
1659 /*EMBEDDED FULL POINTER*/
1660 if( (!pointers_are_top_level)
1661 && (type==NDR_POINTER_PTR) ){
1667 /* get the referent id */
1668 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1670 /* we got a NULL pointer */
1672 proto_tree_add_text(tree, tvb, offset-4, 4,
1673 "(NULL pointer) %s",text);
1677 /* see if we have seen this pointer before */
1678 idx=find_pointer_index(id);
1680 /* we have seen this pointer before */
1682 proto_tree_add_text(tree, tvb, offset-4, 4,
1683 "(duplicate PTR) %s",text);
1688 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1690 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1691 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1692 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1693 callback, callback_args);
1699 /* After each top level pointer we have dissected we have to
1700 dissect all deferrals before we move on to the next top level
1702 if(pointers_are_top_level==TRUE){
1703 pointers_are_top_level=FALSE;
1704 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
1705 pointers_are_top_level=TRUE;
1712 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1713 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1714 int type, char *text, int hf_index)
1716 return dissect_ndr_pointer_cb(
1717 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
1722 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
1723 dcerpc_auth_info *auth_info, gboolean is_encrypted)
1728 * We don't show stub data unless we have some in the tvbuff;
1729 * however, in the protocol tree, we show, as the number of
1730 * bytes, the reported number of bytes, not the number of bytes
1731 * that happen to be in the tvbuff.
1733 if (tvb_length_remaining (tvb, offset) > 0) {
1734 length = tvb_reported_length_remaining (tvb, offset);
1735 if (auth_info != NULL &&
1736 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1738 proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
1739 "Encrypted stub data (%d byte%s)",
1740 length, plurality(length, "", "s"));
1742 proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
1743 "Decrypted stub data (%d byte%s)",
1744 length, plurality(length, "", "s"));
1747 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
1748 "Stub data (%d byte%s)", length,
1749 plurality(length, "", "s"));
1755 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
1756 proto_tree *dcerpc_tree,
1757 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
1758 guint8 *drep, dcerpc_info *info,
1759 dcerpc_auth_info *auth_info)
1761 volatile gint offset = 0;
1762 dcerpc_uuid_key key;
1763 dcerpc_uuid_value *sub_proto;
1764 proto_tree *volatile sub_tree = NULL;
1765 dcerpc_sub_dissector *proc;
1767 dcerpc_dissect_fnct_t *volatile sub_dissect;
1768 const char *volatile saved_proto;
1769 void *volatile saved_private_data;
1770 guint length, reported_length;
1771 tvbuff_t *volatile stub_tvb;
1772 volatile guint auth_pad_len;
1773 volatile int auth_pad_offset;
1775 key.uuid = info->call_data->uuid;
1776 key.ver = info->call_data->ver;
1779 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1780 || !proto_is_protocol_enabled(sub_proto->proto)) {
1782 * We don't have a dissector for this UUID, or the protocol
1783 * for that UUID is disabled.
1786 proto_tree_add_boolean_hidden(dcerpc_tree, hf_dcerpc_unknown_if_id,
1787 tvb, offset, 0, TRUE);
1788 if (check_col (pinfo->cinfo, COL_INFO)) {
1789 col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
1790 info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
1791 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
1792 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
1793 info->call_data->uuid.Data4[7], info->call_data->ver);
1796 if (decrypted_tvb != NULL) {
1797 show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
1800 show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
1804 for (proc = sub_proto->procs; proc->name; proc++) {
1805 if (proc->num == info->call_data->opnum) {
1814 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1815 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1818 if (check_col (pinfo->cinfo, COL_INFO)) {
1819 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1820 name, info->request ? "request" : "response");
1824 proto_item *sub_item;
1825 sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
1829 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1833 * Put the operation number into the tree along with
1834 * the operation's name.
1837 if (sub_proto->opnum_hf != -1)
1838 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
1839 tvb, 0, 0, info->call_data->opnum,
1840 "Operation: %s (%u)",
1841 name, info->call_data->opnum);
1843 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
1844 0, 0, info->call_data->opnum,
1845 "Operation: %s (%u)",
1846 name, info->call_data->opnum);
1849 sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
1851 if (decrypted_tvb != NULL) {
1852 /* Either there was no encryption or we successfully decrypted
1853 the entrypted payload. */
1855 /* We have a subdissector - call it. */
1856 saved_proto = pinfo->current_proto;
1857 saved_private_data = pinfo->private_data;
1858 pinfo->current_proto = sub_proto->name;
1859 pinfo->private_data = (void *)info;
1861 init_ndr_pointer_list(pinfo);
1864 * Remove the authentication padding from the stub data.
1866 if (auth_info != NULL && auth_info->auth_pad_len != 0) {
1867 length = tvb_length(decrypted_tvb);
1868 reported_length = tvb_reported_length(decrypted_tvb);
1869 if (reported_length >= auth_info->auth_pad_len) {
1871 * OK, the padding length isn't so big that it
1872 * exceeds the stub length. Trim the reported
1873 * length of the tvbuff.
1875 reported_length -= auth_info->auth_pad_len;
1878 * If that exceeds the actual amount of data in
1879 * the tvbuff (which means we have at least one
1880 * byte of authentication padding in the tvbuff),
1881 * trim the actual amount.
1883 if (length > reported_length)
1884 length = reported_length;
1886 stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
1887 auth_pad_len = auth_info->auth_pad_len;
1888 auth_pad_offset = reported_length;
1891 * The padding length exceeds the stub length.
1892 * Don't bother dissecting the stub, trim the padding
1893 * length to what's in the stub data, and show the
1894 * entire stub as authentication padding.
1897 auth_pad_len = reported_length;
1898 auth_pad_offset = 0;
1902 * No authentication padding.
1904 stub_tvb = decrypted_tvb;
1906 auth_pad_offset = 0;
1909 if (stub_tvb != NULL) {
1911 * Catch all exceptions other than BoundsError, so that even
1912 * if the stub data is bad, we still show the authentication
1915 * If we get BoundsError, it means the frame was cut short
1916 * by a snapshot length, so there's nothing more to
1917 * dissect; just re-throw that exception.
1920 offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
1923 /* If we have a subdissector and it didn't dissect all
1924 data in the tvb, make a note of it. */
1926 if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
1927 if (check_col(pinfo->cinfo, COL_INFO))
1928 col_append_fstr(pinfo->cinfo, COL_INFO,
1929 "[Long frame (%d bytes)]",
1930 tvb_reported_length_remaining(stub_tvb, offset));
1932 } CATCH(BoundsError) {
1935 show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE);
1939 /* If there is auth padding at the end of the stub, display it */
1940 if (auth_pad_len != 0) {
1941 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
1943 "Auth Padding (%u byte%s)",
1945 plurality(auth_pad_len, "", "s"));
1948 pinfo->current_proto = saved_proto;
1949 pinfo->private_data = saved_private_data;
1951 /* No subdissector - show it as stub data. */
1953 show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
1955 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
1959 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
1961 tap_queue_packet(dcerpc_tap, pinfo, info);
1966 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
1967 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
1968 dcerpc_auth_info *auth_info)
1972 auth_info->auth_data = NULL;
1974 if (auth_info->auth_size != 0) {
1975 dcerpc_auth_subdissector_fns *auth_fns;
1978 auth_offset = hdr->frag_len - hdr->auth_len;
1980 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
1983 auth_info->auth_data = auth_tvb;
1985 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
1986 auth_info->auth_type))) {
1988 * Catch all exceptions, so that even if the verifier is bad
1989 * or we don't have all of it, we still show the stub data.
1992 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
1995 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
1998 proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2003 return hdr->auth_len;
2007 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2008 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2009 gboolean are_credentials, dcerpc_auth_info *auth_info)
2011 volatile int offset;
2014 * Initially set auth_level and auth_type to zero to indicate that we
2015 * haven't yet seen any authentication level information.
2017 auth_info->auth_level = 0;
2018 auth_info->auth_type = 0;
2019 auth_info->auth_size = 0;
2020 auth_info->auth_pad_len = 0;
2023 * The authentication information is at the *end* of the PDU; in
2024 * request and response PDUs, the request and response stub data
2027 * Is there any authentication data (i.e., is the authentication length
2028 * non-zero), and is the authentication length valid (i.e., is it, plus
2029 * 8 bytes for the type/level/pad length/reserved/context id, less than
2030 * or equal to the fragment length minus the starting offset of the
2035 && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2038 * Yes, there is authentication data, and the length is valid.
2039 * Do we have all the bytes of stub data?
2040 * (If not, we'd throw an exception dissecting *that*, so don't
2041 * bother trying to dissect the authentication information and
2042 * throwing another exception there.)
2044 offset = hdr->frag_len - (hdr->auth_len + 8);
2045 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2047 * Either there's no stub data, or the last byte of the stub
2048 * data is present in the captured data, so we shouldn't
2049 * get a BoundsError dissecting the stub data.
2051 * Try dissecting the authentication data.
2052 * Catch all exceptions, so that even if the auth info is bad
2053 * or we don't have all of it, we still show the stuff we
2054 * dissect after this, such as stub data.
2057 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2058 hf_dcerpc_auth_type,
2059 &auth_info->auth_type);
2060 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2061 hf_dcerpc_auth_level,
2062 &auth_info->auth_level);
2064 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2065 hf_dcerpc_auth_pad_len,
2066 &auth_info->auth_pad_len);
2067 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2068 hf_dcerpc_auth_rsrvd, NULL);
2069 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2070 hf_dcerpc_auth_ctx_id, NULL);
2073 * Dissect the authentication data.
2075 if (are_credentials) {
2077 dcerpc_auth_subdissector_fns *auth_fns;
2079 auth_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
2082 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2083 auth_info->auth_type)))
2084 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2087 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2088 "Auth Credentials");
2091 /* Compute the size of the auth block. Note that this should not
2092 include auth padding, since when NTLMSSP encryption is used, the
2093 padding is actually inside the encrypted stub */
2094 auth_info->auth_size = hdr->auth_len + 8;
2096 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
2103 /* We need to hash in the SMB fid number to generate a unique hash table
2104 key as DCERPC over SMB allows several pipes over the same TCP/IP
2107 static guint16 get_smb_fid (void *private_data)
2109 dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
2112 return 0; /* Nothing to see here */
2114 /* DCERPC over smb */
2116 if (priv->transport_type == DCERPC_TRANSPORT_SMB)
2117 return priv->data.smb.fid;
2119 /* Some other transport... */
2125 * Connection oriented packet types
2129 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2130 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2132 conversation_t *conv = NULL;
2133 guint8 num_ctx_items = 0;
2135 gboolean saw_ctx_item = FALSE;
2137 guint16 num_trans_items;
2142 guint16 if_ver, if_ver_minor;
2143 char uuid_str[DCERPC_UUID_STR_LEN];
2145 dcerpc_auth_info auth_info;
2147 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2148 hf_dcerpc_cn_max_xmit, NULL);
2150 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2151 hf_dcerpc_cn_max_recv, NULL);
2153 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2154 hf_dcerpc_cn_assoc_group, NULL);
2156 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2157 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2162 for (i = 0; i < num_ctx_items; i++) {
2163 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2165 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2166 hf_dcerpc_cn_ctx_id, &ctx_id);
2169 proto_item *ctx_item;
2171 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
2173 hdr->drep[0] & 0x10);
2175 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2178 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2179 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2181 /* XXX - use "dissect_ndr_uuid_t()"? */
2182 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2184 proto_item *iface_item;
2186 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2187 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2188 if_id.Data1, if_id.Data2, if_id.Data3,
2189 if_id.Data4[0], if_id.Data4[1],
2190 if_id.Data4[2], if_id.Data4[3],
2191 if_id.Data4[4], if_id.Data4[5],
2192 if_id.Data4[6], if_id.Data4[7]);
2194 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2195 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2197 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2198 offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2199 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2203 if (hdr->drep[0] & 0x10) {
2204 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2205 hf_dcerpc_cn_bind_if_ver, &if_ver);
2206 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2207 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2209 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2210 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2211 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2212 hf_dcerpc_cn_bind_if_ver, &if_ver);
2215 if (!saw_ctx_item) {
2216 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2217 pinfo->srcport, pinfo->destport, 0);
2219 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
2220 pinfo->srcport, pinfo->destport, 0);
2223 /* if this is the first time we see this packet, we need to
2224 update the dcerpc_binds table so that any later calls can
2225 match to the interface.
2226 XXX We assume that BINDs will NEVER be fragmented.
2228 if(!(pinfo->fd->flags.visited)){
2229 dcerpc_bind_key *key;
2230 dcerpc_bind_value *value;
2232 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
2234 key->ctx_id = ctx_id;
2235 key->smb_fid = get_smb_fid(pinfo->private_data);
2237 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2238 value->uuid = if_id;
2239 value->ver = if_ver;
2241 /* add this entry to the bind table, first removing any
2242 previous ones that are identical
2244 if(g_hash_table_lookup(dcerpc_binds, key)){
2245 g_hash_table_remove(dcerpc_binds, key);
2247 g_hash_table_insert (dcerpc_binds, key, value);
2250 if (check_col (pinfo->cinfo, COL_INFO)) {
2251 dcerpc_uuid_key key;
2252 dcerpc_uuid_value *value;
2257 if (num_ctx_items > 1)
2258 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2260 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2261 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2263 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2264 if_id.Data1, if_id.Data2, if_id.Data3,
2265 if_id.Data4[0], if_id.Data4[1],
2266 if_id.Data4[2], if_id.Data4[3],
2267 if_id.Data4[4], if_id.Data4[5],
2268 if_id.Data4[6], if_id.Data4[7],
2269 if_ver, if_ver_minor);
2271 saw_ctx_item = TRUE;
2274 for (j = 0; j < num_trans_items; j++) {
2275 /* XXX - use "dissect_ndr_uuid_t()"? */
2276 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2278 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2279 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2280 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2281 trans_id.Data4[0], trans_id.Data4[1],
2282 trans_id.Data4[2], trans_id.Data4[3],
2283 trans_id.Data4[4], trans_id.Data4[5],
2284 trans_id.Data4[6], trans_id.Data4[7]);
2285 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2286 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2287 proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2288 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2292 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
2293 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2298 * XXX - we should save the authentication type *if* we have
2299 * an authentication header, and associate it with an authentication
2300 * context, so subsequent PDUs can use that context.
2302 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2306 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2307 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2309 guint16 max_xmit, max_recv;
2310 guint16 sec_addr_len;
2317 char uuid_str[DCERPC_UUID_STR_LEN];
2319 dcerpc_auth_info auth_info;
2321 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2322 hf_dcerpc_cn_max_xmit, &max_xmit);
2324 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2325 hf_dcerpc_cn_max_recv, &max_recv);
2327 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2328 hf_dcerpc_cn_assoc_group, NULL);
2330 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2331 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2332 if (sec_addr_len != 0) {
2333 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2334 sec_addr_len, FALSE);
2335 offset += sec_addr_len;
2339 offset += 4 - offset % 4;
2342 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2343 hf_dcerpc_cn_num_results, &num_results);
2348 for (i = 0; i < num_results; i++) {
2349 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2350 hdr->drep, hf_dcerpc_cn_ack_result,
2353 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2354 hdr->drep, hf_dcerpc_cn_ack_reason,
2358 * The reason for rejection isn't meaningful, and often isn't
2359 * set, when the syntax was accepted.
2364 /* XXX - use "dissect_ndr_uuid_t()"? */
2365 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2367 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2368 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2369 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2370 trans_id.Data4[0], trans_id.Data4[1],
2371 trans_id.Data4[2], trans_id.Data4[3],
2372 trans_id.Data4[4], trans_id.Data4[5],
2373 trans_id.Data4[6], trans_id.Data4[7]);
2374 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2375 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2376 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2377 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2381 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2382 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2386 * XXX - do we need to do anything with the authentication level
2387 * we get back from this?
2389 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2391 if (check_col (pinfo->cinfo, COL_INFO)) {
2392 if (num_results != 0 && result == 0) {
2393 /* XXX - only checks the last result */
2394 col_append_fstr (pinfo->cinfo, COL_INFO,
2395 " accept max_xmit: %u max_recv: %u",
2396 max_xmit, max_recv);
2398 /* XXX - only shows the last result and reason */
2399 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2400 val_to_str(result, p_cont_result_vals,
2401 "Unknown result (%u)"),
2402 val_to_str(reason, p_provider_reason_vals,
2409 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2410 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2413 guint8 num_protocols;
2416 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2417 hdr->drep, hf_dcerpc_cn_reject_reason,
2420 if (check_col (pinfo->cinfo, COL_INFO)) {
2421 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2422 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2425 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2426 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2427 hf_dcerpc_cn_num_protocols,
2430 for (i = 0; i < num_protocols; i++) {
2431 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2432 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2434 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2435 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2441 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2444 #define PFC_FRAG_MASK 0x03
2447 fragment_type(guint8 flags)
2449 flags = flags & PFC_FRAG_MASK;
2451 if (flags == PFC_FIRST_FRAG)
2457 if (flags == PFC_LAST_FRAG)
2460 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2466 /* Dissect stub data (payload) of a DCERPC packet. */
2469 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2470 proto_tree *dcerpc_tree, proto_tree *tree,
2471 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2472 dcerpc_auth_info *auth_info, guint32 alloc_hint,
2475 gboolean save_fragmented;
2476 fragment_data *fd_head=NULL;
2478 tvbuff_t *payload_tvb, *decrypted_tvb;
2480 save_fragmented = pinfo->fragmented;
2482 payload_tvb = tvb_new_subset(
2483 tvb, offset, tvb_length_remaining(tvb, offset) -
2484 auth_info->auth_size, tvb_length_remaining(tvb, offset) -
2485 auth_info->auth_size);
2487 /* Decrypt the PDU if it is encrypted */
2489 if (auth_info->auth_type &&
2490 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2492 * We know the authentication type, and the authentication
2493 * level is "Packet privacy", meaning the payload is
2494 * encrypted; attempt to decrypt it.
2496 dcerpc_auth_subdissector_fns *auth_fns;
2498 /* Start out assuming we won't succeed in decrypting. */
2499 decrypted_tvb = NULL;
2501 if ((auth_fns = get_auth_subdissector_fns(
2502 auth_info->auth_level, auth_info->auth_type))) {
2505 result = decode_encrypted_data(
2506 payload_tvb, pinfo, auth_fns,
2507 hdr->ptype == PDU_REQ, auth_info);
2511 proto_tree_add_text(
2512 dcerpc_tree, payload_tvb, 0, -1,
2513 "Encrypted stub data (%d byte%s)",
2514 tvb_reported_length(payload_tvb),
2516 plurality(tvb_length(payload_tvb), "", "s"));
2518 add_new_data_source(
2519 pinfo, result, "Decrypted stub data");
2522 decrypted_tvb = result;
2526 decrypted_tvb = payload_tvb;
2528 /* if this packet is not fragmented, just dissect it and exit */
2529 if(PFC_NOT_FRAGMENTED(hdr)){
2530 pinfo->fragmented = FALSE;
2533 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2534 hdr->drep, di, auth_info);
2536 pinfo->fragmented = save_fragmented;
2540 /* The packet is fragmented. */
2541 pinfo->fragmented = TRUE;
2543 /* if we are not doing reassembly and this is the first fragment
2544 then just dissect it and exit
2545 XXX - if we're not doing reassembly, can we decrypt an
2548 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
2551 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2552 hdr->drep, di, auth_info);
2554 if (check_col(pinfo->cinfo, COL_INFO)) {
2555 col_append_fstr(pinfo->cinfo, COL_INFO,
2556 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2558 pinfo->fragmented = save_fragmented;
2562 /* if we have already seen this packet, see if it was reassembled
2563 and if so dissect the full pdu.
2566 if(pinfo->fd->flags.visited){
2567 fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
2571 /* if we are not doing reassembly and it was neither a complete PDU
2572 nor the first fragment then there is nothing more we can do
2573 so we just have to exit
2575 if( !dcerpc_reassemble )
2578 /* if we didnt get 'frame' we dont know where the PDU started and thus
2579 it is pointless to continue
2584 /* from now on we must attempt to reassemble the PDU
2587 /* if we get here we know it is the first time we see the packet
2588 and we also know it is only a fragment and not a full PDU,
2589 thus we must reassemble it.
2592 /* Do we have any non-encrypted data to reassemble? */
2593 if (decrypted_tvb == NULL) {
2594 /* No. We can't even try to reassemble. */
2598 /* if this is the first fragment we need to start reassembly
2600 if(hdr->flags&PFC_FIRST_FRAG){
2601 fragment_add(decrypted_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
2602 0, tvb_length(decrypted_tvb), TRUE);
2603 fragment_set_tot_len(pinfo, frame,
2604 dcerpc_co_reassemble_table, alloc_hint);
2609 /* if this is a middle fragment, just add it and exit */
2610 if(!(hdr->flags&PFC_LAST_FRAG)){
2611 tot_len = fragment_get_tot_len(pinfo, frame,
2612 dcerpc_co_reassemble_table);
2613 fragment_add(decrypted_tvb, 0, pinfo, frame,
2614 dcerpc_co_reassemble_table,
2615 tot_len-alloc_hint, tvb_length(decrypted_tvb),
2621 /* this was the last fragment add it to reassembly
2623 tot_len = fragment_get_tot_len(pinfo, frame,
2624 dcerpc_co_reassemble_table);
2625 fd_head = fragment_add(decrypted_tvb, 0, pinfo,
2627 dcerpc_co_reassemble_table,
2628 tot_len-alloc_hint, tvb_length(decrypted_tvb),
2633 /* if reassembly is complete, dissect the full PDU
2635 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
2637 if(pinfo->fd->num==fd_head->reassembled_in){
2640 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2641 tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
2642 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2643 show_fragment_tree(fd_head, &dcerpc_frag_items,
2644 dcerpc_tree, pinfo, next_tvb);
2646 pinfo->fragmented = FALSE;
2648 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
2649 next_tvb, hdr->drep, di, auth_info);
2652 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
2653 decrypted_tvb, 0, 0, fd_head->reassembled_in);
2654 if (check_col(pinfo->cinfo, COL_INFO)) {
2655 col_append_fstr(pinfo->cinfo, COL_INFO,
2656 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2660 /* Reassembly not complete - some fragments
2661 are missing. Just show the stub data. */
2663 if (check_col(pinfo->cinfo, COL_INFO)) {
2664 col_append_fstr(pinfo->cinfo, COL_INFO,
2665 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2669 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
2671 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
2675 pinfo->fragmented = save_fragmented;
2679 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2680 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2682 conversation_t *conv;
2686 dcerpc_auth_info auth_info;
2688 char uuid_str[DCERPC_UUID_STR_LEN];
2691 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2692 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2694 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2695 hf_dcerpc_cn_ctx_id, &ctx_id);
2697 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2698 hf_dcerpc_opnum, &opnum);
2700 if (check_col (pinfo->cinfo, COL_INFO)) {
2701 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
2705 if (hdr->flags & PFC_OBJECT_UUID) {
2706 /* XXX - use "dissect_ndr_uuid_t()"? */
2707 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
2709 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2710 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2711 obj_id.Data1, obj_id.Data2, obj_id.Data3,
2720 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2721 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2722 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
2723 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
2729 * XXX - what if this was set when the connection was set up,
2730 * and we just have a security context?
2732 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2733 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2735 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2736 pinfo->srcport, pinfo->destport, 0);
2738 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
2740 dcerpc_matched_key matched_key, *new_matched_key;
2741 dcerpc_call_value *value;
2743 /* !!! we can NOT check flags.visited here since this will interact
2744 badly with when SMB handles (i.e. calls the subdissector)
2745 and desegmented pdu's .
2746 Instead we check if this pdu is already in the matched table or not
2748 matched_key.frame = pinfo->fd->num;
2749 matched_key.call_id = hdr->call_id;
2750 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
2752 dcerpc_bind_key bind_key;
2753 dcerpc_bind_value *bind_value;
2756 bind_key.ctx_id=ctx_id;
2757 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
2759 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
2760 if(!(hdr->flags&PFC_FIRST_FRAG)){
2761 dcerpc_call_key call_key;
2762 dcerpc_call_value *call_value;
2765 call_key.call_id=hdr->call_id;
2766 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2767 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2768 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2769 *new_matched_key = matched_key;
2770 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2774 dcerpc_call_key *call_key;
2775 dcerpc_call_value *call_value;
2777 /* We found the binding and it is the first fragment
2778 (or a complete PDU) of a dcerpc pdu so just add
2779 the call to both the call table and the
2782 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
2783 call_key->conv=conv;
2784 call_key->call_id=hdr->call_id;
2785 call_key->smb_fid=get_smb_fid(pinfo->private_data);
2787 /* if there is already a matching call in the table
2788 remove it so it is replaced with the new one */
2789 if(g_hash_table_lookup(dcerpc_calls, call_key)){
2790 g_hash_table_remove(dcerpc_calls, call_key);
2793 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2794 call_value->uuid = bind_value->uuid;
2795 call_value->ver = bind_value->ver;
2796 call_value->opnum = opnum;
2797 call_value->req_frame=pinfo->fd->num;
2798 call_value->req_time.secs=pinfo->fd->abs_secs;
2799 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
2800 call_value->rep_frame=0;
2801 call_value->max_ptr=0;
2802 call_value->private_data = NULL;
2803 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2805 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2806 *new_matched_key = matched_key;
2807 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2817 /* handoff this call */
2819 di->call_id = hdr->call_id;
2820 di->smb_fid = get_smb_fid(pinfo->private_data);
2822 di->call_data = value;
2825 if(value->rep_frame!=0){
2826 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
2827 tvb, 0, 0, value->rep_frame);
2830 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2831 hdr, di, &auth_info, alloc_hint,
2834 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
2839 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2840 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2842 dcerpc_call_value *value = NULL;
2843 conversation_t *conv;
2845 dcerpc_auth_info auth_info;
2848 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2849 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2851 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2852 hf_dcerpc_cn_ctx_id, &ctx_id);
2854 if (check_col (pinfo->cinfo, COL_INFO)) {
2855 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
2858 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2859 hf_dcerpc_cn_cancel_count, NULL);
2864 * XXX - what if this was set when the connection was set up,
2865 * and we just have a security context?
2867 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2868 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2870 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2871 pinfo->srcport, pinfo->destport, 0);
2874 /* no point in creating one here, really */
2875 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
2877 dcerpc_matched_key matched_key, *new_matched_key;
2879 /* !!! we can NOT check flags.visited here since this will interact
2880 badly with when SMB handles (i.e. calls the subdissector)
2881 and desegmented pdu's .
2882 Instead we check if this pdu is already in the matched table or not
2884 matched_key.frame = pinfo->fd->num;
2885 matched_key.call_id = hdr->call_id;
2886 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
2888 dcerpc_call_key call_key;
2889 dcerpc_call_value *call_value;
2892 call_key.call_id=hdr->call_id;
2893 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2895 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2896 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2897 *new_matched_key = matched_key;
2898 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2900 if(call_value->rep_frame==0){
2901 call_value->rep_frame=pinfo->fd->num;
2910 /* handoff this call */
2912 di->call_id = hdr->call_id;
2913 di->smb_fid = get_smb_fid(pinfo->private_data);
2914 di->request = FALSE;
2915 di->call_data = value;
2917 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2918 if(value->req_frame!=0){
2920 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2921 tvb, 0, 0, value->req_frame);
2922 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2923 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2925 ns.nsecs+=1000000000;
2928 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2931 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2932 hdr, di, &auth_info, alloc_hint,
2935 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
2940 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2941 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2943 dcerpc_call_value *value = NULL;
2944 conversation_t *conv;
2948 dcerpc_auth_info auth_info;
2950 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2951 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2953 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2954 hf_dcerpc_cn_ctx_id, &ctx_id);
2956 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2957 hf_dcerpc_cn_cancel_count, NULL);
2961 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2962 hf_dcerpc_cn_status, &status);
2964 if (check_col (pinfo->cinfo, COL_INFO)) {
2965 col_append_fstr (pinfo->cinfo, COL_INFO,
2966 " ctx_id: %u status: %s", ctx_id,
2967 val_to_str(status, reject_status_vals,
2968 "Unknown (0x%08x)"));
2975 * XXX - what if this was set when the connection was set up,
2976 * and we just have a security context?
2978 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2980 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2981 pinfo->srcport, pinfo->destport, 0);
2983 /* no point in creating one here, really */
2985 dcerpc_matched_key matched_key, *new_matched_key;
2987 /* !!! we can NOT check flags.visited here since this will interact
2988 badly with when SMB handles (i.e. calls the subdissector)
2989 and desegmented pdu's .
2990 Instead we check if this pdu is already in the matched table or not
2992 matched_key.frame = pinfo->fd->num;
2993 matched_key.call_id = hdr->call_id;
2994 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
2996 dcerpc_call_key call_key;
2997 dcerpc_call_value *call_value;
3000 call_key.call_id=hdr->call_id;
3001 call_key.smb_fid=get_smb_fid(pinfo->private_data);
3003 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
3004 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3005 *new_matched_key = matched_key;
3006 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3008 if(call_value->rep_frame==0){
3009 call_value->rep_frame=pinfo->fd->num;
3016 int length, reported_length, stub_length;
3020 /* handoff this call */
3022 di->call_id = hdr->call_id;
3023 di->smb_fid = get_smb_fid(pinfo->private_data);
3024 di->request = FALSE;
3025 di->call_data = value;
3027 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3028 if(value->req_frame!=0){
3030 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3031 tvb, 0, 0, value->req_frame);
3032 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3033 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3035 ns.nsecs+=1000000000;
3038 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3041 length = tvb_length_remaining(tvb, offset);
3042 reported_length = tvb_reported_length_remaining(tvb, offset);
3043 stub_length = hdr->frag_len - offset - auth_info.auth_size;
3044 if (length > stub_length)
3045 length = stub_length;
3046 if (reported_length > stub_length)
3047 reported_length = stub_length;
3049 /* If we don't have reassembly enabled, or this packet contains
3050 the entire PDU, or if we don't have all the data in this
3051 fragment, just call the handoff directly if this is the
3052 first fragment or the PDU isn't fragmented. */
3053 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3054 !tvb_bytes_exist(tvb, offset, stub_length) ){
3055 if(hdr->flags&PFC_FIRST_FRAG){
3056 /* First fragment, possibly the only fragment */
3058 * XXX - should there be a third routine for each
3059 * function in an RPC subdissector, to handle
3060 * fault responses? The DCE RPC 1.1 spec says
3061 * three's "stub data" here, which I infer means
3062 * that it's protocol-specific and call-specific.
3064 * It should probably get passed the status code
3065 * as well, as that might be protocol-specific.
3068 if (stub_length > 0) {
3069 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3070 "Fault stub data (%d byte%s)",
3072 plurality(stub_length, "", "s"));
3076 /* PDU is fragmented and this isn't the first fragment */
3077 if (check_col(pinfo->cinfo, COL_INFO)) {
3078 col_append_fstr(pinfo->cinfo, COL_INFO,
3079 " [DCE/RPC fragment]");
3082 if (stub_length > 0) {
3083 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3084 "Fragment data (%d byte%s)",
3086 plurality(stub_length, "", "s"));
3091 /* Reassembly is enabled, the PDU is fragmented, and
3092 we have all the data in the fragment; the first two
3093 of those mean we should attempt reassembly, and the
3094 third means we can attempt reassembly. */
3097 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3098 "Fragment data (%d byte%s)",
3100 plurality(stub_length, "", "s"));
3103 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
3104 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3105 fragment_add(tvb, offset, pinfo, value->rep_frame,
3106 dcerpc_co_reassemble_table,
3110 fragment_set_tot_len(pinfo, value->rep_frame,
3111 dcerpc_co_reassemble_table, alloc_hint);
3113 if (check_col(pinfo->cinfo, COL_INFO)) {
3114 col_append_fstr(pinfo->cinfo, COL_INFO,
3115 " [DCE/RPC fragment]");
3117 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
3118 if( value->rep_frame ){
3119 fragment_data *fd_head;
3122 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3123 dcerpc_co_reassemble_table);
3124 fd_head = fragment_add(tvb, offset, pinfo,
3126 dcerpc_co_reassemble_table,
3132 /* We completed reassembly */
3135 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
3136 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3137 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3138 show_fragment_tree(fd_head, &dcerpc_frag_items,
3139 dcerpc_tree, pinfo, next_tvb);
3142 * XXX - should there be a third routine for each
3143 * function in an RPC subdissector, to handle
3144 * fault responses? The DCE RPC 1.1 spec says
3145 * three's "stub data" here, which I infer means
3146 * that it's protocol-specific and call-specific.
3148 * It should probably get passed the status code
3149 * as well, as that might be protocol-specific.
3153 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3154 "Fault stub data (%d byte%s)",
3156 plurality(stub_length, "", "s"));
3160 /* Reassembly not complete - some fragments
3162 if (check_col(pinfo->cinfo, COL_INFO)) {
3163 col_append_fstr(pinfo->cinfo, COL_INFO,
3164 " [DCE/RPC fragment]");
3168 } else { /* MIDDLE fragment(s) */
3169 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3171 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3172 dcerpc_co_reassemble_table);
3173 fragment_add(tvb, offset, pinfo, value->rep_frame,
3174 dcerpc_co_reassemble_table,
3179 if (check_col(pinfo->cinfo, COL_INFO)) {
3180 col_append_fstr(pinfo->cinfo, COL_INFO,
3181 " [DCE/RPC fragment]");
3190 * DCERPC dissector for connection oriented calls
3193 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3194 proto_tree *tree, gboolean can_desegment, int *pkt_len)
3196 static const guint8 nulls[4] = { 0 };
3199 proto_item *ti = NULL;
3200 proto_item *tf = NULL;
3201 proto_tree *dcerpc_tree = NULL;
3202 proto_tree *cn_flags_tree = NULL;
3203 proto_tree *drep_tree = NULL;
3204 e_dce_cn_common_hdr_t hdr;
3205 dcerpc_auth_info auth_info;
3208 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3209 * data for some reason.
3211 * XXX - if that's always the case, the right way to do this would
3212 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3213 * the 4 bytes of null padding, and make that the dissector
3214 * used for "netbios".
3216 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3226 * Check if this looks like a C/O DCERPC call
3228 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3229 return FALSE; /* not enough information to check */
3231 start_offset = offset;
3232 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3233 if (hdr.rpc_ver != 5)
3235 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3236 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3238 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3242 hdr.flags = tvb_get_guint8 (tvb, offset++);
3243 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3244 offset += sizeof (hdr.drep);
3246 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3248 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3250 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3253 if (can_desegment && pinfo->can_desegment
3254 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3255 pinfo->desegment_offset = start_offset;
3256 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3257 *pkt_len = 0; /* desegmentation required */
3261 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3262 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3263 if (check_col (pinfo->cinfo, COL_INFO))
3264 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3265 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3268 offset = start_offset;
3269 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3271 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3273 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
3274 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
3275 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
3276 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3277 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3278 if (cn_flags_tree) {
3279 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3280 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3281 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3282 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3283 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3284 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3285 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3286 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3290 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3291 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3293 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3294 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3295 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3297 offset += sizeof (hdr.drep);
3299 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3302 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3305 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3310 * None of the stuff done above should throw an exception, because
3311 * we would have rejected this as "not DCE RPC" if we didn't have all
3312 * of it. (XXX - perhaps we should request reassembly if we have
3313 * enough of the header to consider it DCE RPC but not enough to
3314 * get the fragment length; in that case the stuff still wouldn't
3315 * throw an exception.)
3317 * The rest of the stuff might, so return the PDU length to our caller.
3318 * XXX - should we construct a tvbuff containing only the PDU and
3319 * use that? Or should we have separate "is this a DCE RPC PDU",
3320 * "how long is it", and "dissect it" routines - which might let us
3321 * do most of the work in "tcp_dissect_pdus()"?
3323 if (pkt_len != NULL)
3324 *pkt_len = hdr.frag_len + padding;
3327 * Packet type specific stuff is next.
3329 switch (hdr.ptype) {
3332 dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr);
3337 dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3342 * Nothing after the common header other than credentials.
3344 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
3349 dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3353 dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3357 dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3361 dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
3367 * Nothing after the common header other than an authentication
3370 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
3376 * Nothing after the common header, not even an authentication
3382 /* might as well dissect the auth info */
3383 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
3391 * DCERPC dissector for connection oriented calls over packet-oriented
3395 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3398 * Only one PDU per transport packet, and only one transport
3401 if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
3403 * It wasn't a DCERPC PDU.
3415 * DCERPC dissector for connection oriented calls over byte-stream
3419 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3421 volatile int offset = 0;
3423 volatile gboolean is_dcerpc_pdu;
3424 volatile gboolean ret = FALSE;
3427 * There may be multiple PDUs per transport packet; keep
3430 while (tvb_reported_length_remaining(tvb, offset) != 0) {
3432 * Catch ReportedBoundsError, so that even if the stub data is bad,
3433 * we don't abort the full DCE RPC dissection - there might be more
3434 * than one DCE RPC PDU in the data being dissected.
3436 * If we get BoundsError, it means the frame was cut short by a
3437 * snapshot length, so there's nothing more to dissect; just
3438 * re-throw that exception.
3440 is_dcerpc_pdu = FALSE;
3442 is_dcerpc_pdu = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
3443 dcerpc_cn_desegment, &pdu_len);
3444 } CATCH(BoundsError) {
3446 } CATCH(ReportedBoundsError) {
3447 show_reported_bounds_error(tvb, pinfo, tree);
3450 if (!is_dcerpc_pdu) {
3458 * Well, we've seen at least one DCERPC PDU.
3464 * Desegmentation required - bail now.
3470 * Step to the next PDU.
3478 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
3479 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
3481 proto_item *ti = NULL;
3482 proto_tree *auth_tree = NULL;
3483 guint8 protection_level;
3486 * Initially set "*auth_level_p" to -1 to indicate that we haven't
3487 * yet seen any authentication level information.
3489 if (auth_level_p != NULL)
3493 * The authentication information is at the *end* of the PDU; in
3494 * request and response PDUs, the request and response stub data
3497 * If the full packet is here, and there's data past the end of the
3498 * packet body, then dissect the auth info.
3500 offset += hdr->frag_len;
3501 if (tvb_length_remaining(tvb, offset) > 0) {
3502 switch (hdr->auth_proto) {
3504 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
3505 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
3506 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
3507 protection_level = tvb_get_guint8 (tvb, offset);
3508 if (auth_level_p != NULL)
3509 *auth_level_p = protection_level;
3510 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
3512 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
3514 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
3515 offset += 6; /* 6 bytes of padding */
3517 offset += 2; /* 6 bytes of padding */
3518 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
3523 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
3530 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3531 proto_tree *dcerpc_tree,
3532 e_dce_dg_common_hdr_t *hdr)
3536 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3537 hdr->drep, hf_dcerpc_dg_cancel_vers,
3543 /* The only version we know about */
3544 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3545 hdr->drep, hf_dcerpc_dg_cancel_id,
3547 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3548 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3555 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
3556 proto_tree *dcerpc_tree,
3557 e_dce_dg_common_hdr_t *hdr)
3561 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3562 hdr->drep, hf_dcerpc_dg_cancel_vers,
3568 /* The only version we know about */
3569 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3570 hdr->drep, hf_dcerpc_dg_cancel_id,
3572 /* XXX - are NDR booleans 32 bits? */
3573 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3574 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3581 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3582 proto_tree *dcerpc_tree,
3583 e_dce_dg_common_hdr_t *hdr)
3590 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3591 hdr->drep, hf_dcerpc_dg_fack_vers,
3598 case 0: /* The only version documented in the DCE RPC 1.1 spec */
3599 case 1: /* This appears to be the same */
3600 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3601 hdr->drep, hf_dcerpc_dg_fack_window_size,
3603 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3604 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
3606 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3607 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
3609 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3610 hdr->drep, hf_dcerpc_dg_fack_serial_num,
3612 if (check_col (pinfo->cinfo, COL_INFO)) {
3613 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3616 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3617 hdr->drep, hf_dcerpc_dg_fack_selack_len,
3619 for (i = 0; i < selack_len; i++) {
3620 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3621 hdr->drep, hf_dcerpc_dg_fack_selack,
3630 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
3631 proto_tree *dcerpc_tree,
3632 e_dce_dg_common_hdr_t *hdr)
3636 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3637 hdr->drep, hf_dcerpc_dg_status,
3640 if (check_col (pinfo->cinfo, COL_INFO)) {
3641 col_append_fstr (pinfo->cinfo, COL_INFO,
3643 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3648 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
3649 proto_tree *dcerpc_tree, proto_tree *tree,
3650 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
3652 int length, reported_length, stub_length;
3653 gboolean save_fragmented;
3654 fragment_data *fd_head;
3657 if (check_col (pinfo->cinfo, COL_INFO))
3658 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u", di->call_data->opnum );
3660 length = tvb_length_remaining (tvb, offset);
3661 reported_length = tvb_reported_length_remaining (tvb, offset);
3662 stub_length = hdr->frag_len;
3663 if (length > stub_length)
3664 length = stub_length;
3665 if (reported_length > stub_length)
3666 reported_length = stub_length;
3668 save_fragmented = pinfo->fragmented;
3670 /* If we don't have reassembly enabled, or this packet contains
3671 the entire PDU, or if this is a short frame (or a frame
3672 not reassembled at a lower layer) that doesn't include all
3673 the data in the fragment, just call the handoff directly if
3674 this is the first fragment or the PDU isn't fragmented. */
3675 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
3676 !tvb_bytes_exist(tvb, offset, stub_length) ){
3677 if(hdr->frag_num == 0) {
3680 /* First fragment, possibly the only fragment */
3683 * XXX - authentication info?
3685 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
3686 next_tvb = tvb_new_subset (tvb, offset, length,
3688 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3689 next_tvb, hdr->drep, di, NULL);
3691 /* PDU is fragmented and this isn't the first fragment */
3692 if (check_col(pinfo->cinfo, COL_INFO)) {
3693 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3697 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3698 "Fragment data (%d byte%s)",
3700 plurality(stub_length, "", "s"));
3705 /* Reassembly is enabled, the PDU is fragmented, and
3706 we have all the data in the fragment; the first two
3707 of those mean we should attempt reassembly, and the
3708 third means we can attempt reassembly. */
3711 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3712 "Fragment data (%d byte%s)", stub_length,
3713 plurality(stub_length, "", "s"));
3717 fd_head = fragment_add_seq(tvb, offset, pinfo,
3718 hdr->seqnum, dcerpc_cl_reassemble_table,
3719 hdr->frag_num, stub_length,
3720 !(hdr->flags1 & PFCL1_LASTFRAG));
3721 if (fd_head != NULL) {
3722 /* We completed reassembly */
3723 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3724 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3725 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3726 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
3727 dcerpc_tree, pinfo, next_tvb);
3730 * XXX - authentication info?
3732 pinfo->fragmented = FALSE;
3733 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3734 next_tvb, hdr->drep, di, NULL);
3736 /* Reassembly isn't completed yet */
3737 if (check_col(pinfo->cinfo, COL_INFO)) {
3738 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3742 pinfo->fragmented = save_fragmented;
3746 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
3747 proto_tree *dcerpc_tree, proto_tree *tree,
3748 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3751 dcerpc_call_value *value, v;
3752 dcerpc_matched_key matched_key, *new_matched_key;
3755 if(!(pinfo->fd->flags.visited)){
3756 dcerpc_call_value *call_value;
3757 dcerpc_call_key *call_key;
3759 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
3760 call_key->conv=conv;
3761 call_key->call_id=hdr->seqnum;
3762 call_key->smb_fid=get_smb_fid(pinfo->private_data);
3764 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
3765 call_value->uuid = hdr->if_id;
3766 call_value->ver = hdr->if_ver;
3767 call_value->opnum = hdr->opnum;
3768 call_value->req_frame=pinfo->fd->num;
3769 call_value->req_time.secs=pinfo->fd->abs_secs;
3770 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3771 call_value->rep_frame=0;
3772 call_value->max_ptr=0;
3773 call_value->private_data = NULL;
3774 g_hash_table_insert (dcerpc_calls, call_key, call_value);
3776 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3777 new_matched_key->frame = pinfo->fd->num;
3778 new_matched_key->call_id = hdr->seqnum;
3779 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3782 matched_key.frame = pinfo->fd->num;
3783 matched_key.call_id = hdr->seqnum;
3784 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3786 v.uuid = hdr->if_id;
3787 v.ver = hdr->if_ver;
3788 v.opnum = hdr->opnum;
3789 v.req_frame = pinfo->fd->num;
3792 v.private_data=NULL;
3797 di->call_id = hdr->seqnum;
3800 di->call_data = value;
3802 if(value->rep_frame!=0){
3803 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3804 tvb, 0, 0, value->rep_frame);
3806 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
3810 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
3811 proto_tree *dcerpc_tree, proto_tree *tree,
3812 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3815 dcerpc_call_value *value, v;
3816 dcerpc_matched_key matched_key, *new_matched_key;
3819 if(!(pinfo->fd->flags.visited)){
3820 dcerpc_call_value *call_value;
3821 dcerpc_call_key call_key;
3824 call_key.call_id=hdr->seqnum;
3825 call_key.smb_fid=get_smb_fid(pinfo->private_data);
3827 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
3828 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3829 new_matched_key->frame = pinfo->fd->num;
3830 new_matched_key->call_id = hdr->seqnum;
3831 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3832 if(call_value->rep_frame==0){
3833 call_value->rep_frame=pinfo->fd->num;
3838 matched_key.frame = pinfo->fd->num;
3839 matched_key.call_id = hdr->seqnum;
3840 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3842 v.uuid = hdr->if_id;
3843 v.ver = hdr->if_ver;
3844 v.opnum = hdr->opnum;
3846 v.rep_frame=pinfo->fd->num;
3847 v.private_data=NULL;
3854 di->request = FALSE;
3855 di->call_data = value;
3857 if(value->req_frame!=0){
3859 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3860 tvb, 0, 0, value->req_frame);
3861 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3862 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3864 ns.nsecs+=1000000000;
3867 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3869 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
3873 * DCERPC dissector for connectionless calls
3876 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3878 proto_item *ti = NULL;
3879 proto_item *tf = NULL;
3880 proto_tree *dcerpc_tree = NULL;
3881 proto_tree *dg_flags1_tree = NULL;
3882 proto_tree *dg_flags2_tree = NULL;
3883 proto_tree *drep_tree = NULL;
3884 e_dce_dg_common_hdr_t hdr;
3886 conversation_t *conv;
3888 char uuid_str[DCERPC_UUID_STR_LEN];
3892 * Check if this looks like a CL DCERPC call. All dg packets
3893 * have an 80 byte header on them. Which starts with
3894 * version (4), pkt_type.
3896 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
3899 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3900 if (hdr.rpc_ver != 4)
3902 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3906 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3907 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3908 if (check_col (pinfo->cinfo, COL_INFO))
3909 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
3911 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
3912 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
3913 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3914 offset += sizeof (hdr.drep);
3915 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
3916 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
3918 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
3920 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
3922 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3924 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3926 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3928 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3930 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3932 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3934 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3936 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3938 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
3939 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
3942 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
3944 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
3950 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3954 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3958 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
3959 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
3960 if (dg_flags1_tree) {
3961 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
3962 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
3963 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
3964 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
3965 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
3966 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
3967 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
3968 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
3974 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
3975 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
3976 if (dg_flags2_tree) {
3977 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
3978 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
3979 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
3980 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
3981 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
3982 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
3983 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
3984 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
3990 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
3991 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3993 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3994 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3995 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3998 offset += sizeof (hdr.drep);
4001 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
4005 /* XXX - use "dissect_ndr_uuid_t()"? */
4006 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4007 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4008 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
4009 hdr.obj_id.Data4[0],
4010 hdr.obj_id.Data4[1],
4011 hdr.obj_id.Data4[2],
4012 hdr.obj_id.Data4[3],
4013 hdr.obj_id.Data4[4],
4014 hdr.obj_id.Data4[5],
4015 hdr.obj_id.Data4[6],
4016 hdr.obj_id.Data4[7]);
4017 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4018 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4019 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
4020 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
4025 /* XXX - use "dissect_ndr_uuid_t()"? */
4026 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4027 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4028 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
4036 hdr.if_id.Data4[7]);
4037 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4038 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4039 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4040 offset, 16, uuid_str, "Interface: %s", uuid_str);
4045 /* XXX - use "dissect_ndr_uuid_t()"? */
4046 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4047 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4048 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
4049 hdr.act_id.Data4[0],
4050 hdr.act_id.Data4[1],
4051 hdr.act_id.Data4[2],
4052 hdr.act_id.Data4[3],
4053 hdr.act_id.Data4[4],
4054 hdr.act_id.Data4[5],
4055 hdr.act_id.Data4[6],
4056 hdr.act_id.Data4[7]);
4057 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4058 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4059 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
4060 offset, 16, uuid_str, "Activity: %s", uuid_str);
4065 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
4069 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
4073 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
4074 if (check_col (pinfo->cinfo, COL_INFO)) {
4075 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq_num: %u", hdr.seqnum);
4080 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
4084 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
4088 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
4092 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
4096 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
4097 if (check_col (pinfo->cinfo, COL_INFO)) {
4098 if (hdr.flags1 & PFCL1_FRAG) {
4099 /* Fragmented - put the fragment number into the Info column */
4100 col_append_fstr (pinfo->cinfo, COL_INFO, " frag_num: %u",
4107 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
4111 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
4112 if (check_col (pinfo->cinfo, COL_INFO)) {
4113 if (hdr.flags1 & PFCL1_FRAG) {
4114 /* Fragmented - put the serial number into the Info column */
4115 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
4116 (hdr.serial_hi << 8) | hdr.serial_lo);
4123 * XXX - for Kerberos, we get a protection level; if it's
4124 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
4127 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
4132 * keeping track of the conversation shouldn't really be necessary
4133 * for connectionless packets, because everything we need to know
4134 * to dissect is in the header for each packet. Unfortunately,
4135 * Microsoft's implementation is buggy and often puts the
4136 * completely wrong if_id in the header. go figure. So, keep
4137 * track of the seqnum and use that if possible. Note: that's not
4138 * completely correct. It should really be done based on both the
4139 * activity_id and seqnum. I haven't seen anywhere that it would
4140 * make a difference, but for future reference...
4142 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
4143 pinfo->srcport, pinfo->destport, 0);
4145 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
4146 pinfo->srcport, pinfo->destport, 0);
4150 * Packet type specific stuff is next.
4153 switch (hdr.ptype) {
4155 case PDU_CANCEL_ACK:
4156 /* Body is optional */
4157 /* XXX - we assume "frag_len" is the length of the body */
4158 if (hdr.frag_len != 0)
4159 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4164 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
4165 * but in at least one capture none of the Cl_cancel PDUs had a
4168 /* XXX - we assume "frag_len" is the length of the body */
4169 if (hdr.frag_len != 0)
4170 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
4174 /* Body is optional; if present, it's the same as PDU_FACK */
4175 /* XXX - we assume "frag_len" is the length of the body */
4176 if (hdr.frag_len != 0)
4177 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4181 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4186 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
4190 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4194 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4197 /* these requests have no body */
4209 dcerpc_init_protocol (void)
4211 /* structures and data for BIND */
4213 g_hash_table_destroy (dcerpc_binds);
4215 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
4217 if (dcerpc_bind_key_chunk){
4218 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
4220 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
4221 sizeof (dcerpc_bind_key),
4222 200 * sizeof (dcerpc_bind_key),
4224 if (dcerpc_bind_value_chunk){
4225 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
4227 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
4228 sizeof (dcerpc_bind_value),
4229 200 * sizeof (dcerpc_bind_value),
4231 /* structures and data for CALL */
4233 g_hash_table_destroy (dcerpc_calls);
4235 dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
4236 if (dcerpc_call_key_chunk){
4237 g_mem_chunk_destroy (dcerpc_call_key_chunk);
4239 dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
4240 sizeof (dcerpc_call_key),
4241 200 * sizeof (dcerpc_call_key),
4243 if (dcerpc_call_value_chunk){
4244 g_mem_chunk_destroy (dcerpc_call_value_chunk);
4246 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
4247 sizeof (dcerpc_call_value),
4248 200 * sizeof (dcerpc_call_value),
4251 /* structure and data for MATCHED */
4252 if (dcerpc_matched){
4253 g_hash_table_destroy (dcerpc_matched);
4255 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
4256 if (dcerpc_matched_key_chunk){
4257 g_mem_chunk_destroy (dcerpc_matched_key_chunk);
4259 dcerpc_matched_key_chunk = g_mem_chunk_new ("dcerpc_matched_key_chunk",
4260 sizeof (dcerpc_matched_key),
4261 200 * sizeof (dcerpc_matched_key),
4266 proto_register_dcerpc (void)
4268 static hf_register_info hf[] = {
4269 { &hf_dcerpc_request_in,
4270 { "Request in", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
4271 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
4272 { &hf_dcerpc_response_in,
4273 { "Response in", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
4274 NULL, 0, "The response to this packet is in this packet", HFILL }},
4275 { &hf_dcerpc_referent_id,
4276 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
4277 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
4279 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4280 { &hf_dcerpc_ver_minor,
4281 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4282 { &hf_dcerpc_packet_type,
4283 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
4284 { &hf_dcerpc_cn_flags,
4285 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4286 { &hf_dcerpc_cn_flags_first_frag,
4287 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
4288 { &hf_dcerpc_cn_flags_last_frag,
4289 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
4290 { &hf_dcerpc_cn_flags_cancel_pending,
4291 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
4292 { &hf_dcerpc_cn_flags_reserved,
4293 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
4294 { &hf_dcerpc_cn_flags_mpx,
4295 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
4296 { &hf_dcerpc_cn_flags_dne,
4297 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
4298 { &hf_dcerpc_cn_flags_maybe,
4299 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
4300 { &hf_dcerpc_cn_flags_object,
4301 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
4303 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
4304 { &hf_dcerpc_drep_byteorder,
4305 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
4306 { &hf_dcerpc_drep_character,
4307 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
4308 { &hf_dcerpc_drep_fp,
4309 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
4310 { &hf_dcerpc_cn_frag_len,
4311 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4312 { &hf_dcerpc_cn_auth_len,
4313 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4314 { &hf_dcerpc_cn_call_id,
4315 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4316 { &hf_dcerpc_cn_max_xmit,
4317 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4318 { &hf_dcerpc_cn_max_recv,
4319 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4320 { &hf_dcerpc_cn_assoc_group,
4321 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4322 { &hf_dcerpc_cn_num_ctx_items,
4323 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4324 { &hf_dcerpc_cn_ctx_id,
4325 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4326 { &hf_dcerpc_cn_num_trans_items,
4327 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4328 { &hf_dcerpc_cn_bind_if_id,
4329 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4330 { &hf_dcerpc_cn_bind_if_ver,
4331 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4332 { &hf_dcerpc_cn_bind_if_ver_minor,
4333 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4334 { &hf_dcerpc_cn_bind_trans_id,
4335 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4336 { &hf_dcerpc_cn_bind_trans_ver,
4337 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4338 { &hf_dcerpc_cn_alloc_hint,
4339 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4340 { &hf_dcerpc_cn_sec_addr_len,
4341 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4342 { &hf_dcerpc_cn_sec_addr,
4343 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
4344 { &hf_dcerpc_cn_num_results,
4345 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4346 { &hf_dcerpc_cn_ack_result,
4347 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
4348 { &hf_dcerpc_cn_ack_reason,
4349 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
4350 { &hf_dcerpc_cn_ack_trans_id,
4351 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4352 { &hf_dcerpc_cn_ack_trans_ver,
4353 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4354 { &hf_dcerpc_cn_reject_reason,
4355 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
4356 { &hf_dcerpc_cn_num_protocols,
4357 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4358 { &hf_dcerpc_cn_protocol_ver_major,
4359 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4360 { &hf_dcerpc_cn_protocol_ver_minor,
4361 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4362 { &hf_dcerpc_cn_cancel_count,
4363 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4364 { &hf_dcerpc_cn_status,
4365 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4366 { &hf_dcerpc_auth_type,
4367 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4368 { &hf_dcerpc_auth_level,
4369 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
4370 { &hf_dcerpc_auth_pad_len,
4371 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4372 { &hf_dcerpc_auth_rsrvd,
4373 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4374 { &hf_dcerpc_auth_ctx_id,
4375 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4376 { &hf_dcerpc_dg_flags1,
4377 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4378 { &hf_dcerpc_dg_flags1_rsrvd_01,
4379 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
4380 { &hf_dcerpc_dg_flags1_last_frag,
4381 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
4382 { &hf_dcerpc_dg_flags1_frag,
4383 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
4384 { &hf_dcerpc_dg_flags1_nofack,
4385 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
4386 { &hf_dcerpc_dg_flags1_maybe,
4387 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
4388 { &hf_dcerpc_dg_flags1_idempotent,
4389 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
4390 { &hf_dcerpc_dg_flags1_broadcast,
4391 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
4392 { &hf_dcerpc_dg_flags1_rsrvd_80,
4393 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
4394 { &hf_dcerpc_dg_flags2,
4395 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4396 { &hf_dcerpc_dg_flags2_rsrvd_01,
4397 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
4398 { &hf_dcerpc_dg_flags2_cancel_pending,
4399 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
4400 { &hf_dcerpc_dg_flags2_rsrvd_04,
4401 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
4402 { &hf_dcerpc_dg_flags2_rsrvd_08,
4403 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
4404 { &hf_dcerpc_dg_flags2_rsrvd_10,
4405 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
4406 { &hf_dcerpc_dg_flags2_rsrvd_20,
4407 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
4408 { &hf_dcerpc_dg_flags2_rsrvd_40,
4409 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
4410 { &hf_dcerpc_dg_flags2_rsrvd_80,
4411 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
4412 { &hf_dcerpc_dg_serial_lo,
4413 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4414 { &hf_dcerpc_dg_serial_hi,
4415 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4416 { &hf_dcerpc_dg_ahint,
4417 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4418 { &hf_dcerpc_dg_ihint,
4419 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4420 { &hf_dcerpc_dg_frag_len,
4421 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4422 { &hf_dcerpc_dg_frag_num,
4423 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4424 { &hf_dcerpc_dg_auth_proto,
4425 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4426 { &hf_dcerpc_dg_seqnum,
4427 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4428 { &hf_dcerpc_dg_server_boot,
4429 { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4430 { &hf_dcerpc_dg_if_ver,
4431 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4432 { &hf_dcerpc_krb5_av_prot_level,
4433 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
4434 { &hf_dcerpc_krb5_av_key_vers_num,
4435 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4436 { &hf_dcerpc_krb5_av_key_auth_verifier,
4437 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
4438 { &hf_dcerpc_obj_id,
4439 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4440 { &hf_dcerpc_dg_if_id,
4441 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4442 { &hf_dcerpc_dg_act_id,
4443 { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4445 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4447 { &hf_dcerpc_dg_cancel_vers,
4448 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4450 { &hf_dcerpc_dg_cancel_id,
4451 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4453 { &hf_dcerpc_dg_server_accepting_cancels,
4454 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
4456 { &hf_dcerpc_dg_fack_vers,
4457 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4459 { &hf_dcerpc_dg_fack_window_size,
4460 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4462 { &hf_dcerpc_dg_fack_max_tsdu,
4463 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4465 { &hf_dcerpc_dg_fack_max_frag_size,
4466 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4468 { &hf_dcerpc_dg_fack_serial_num,
4469 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4471 { &hf_dcerpc_dg_fack_selack_len,
4472 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4474 { &hf_dcerpc_dg_fack_selack,
4475 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4477 { &hf_dcerpc_dg_status,
4478 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4480 { &hf_dcerpc_array_max_count,
4481 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
4483 { &hf_dcerpc_array_offset,
4484 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
4486 { &hf_dcerpc_array_actual_count,
4487 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
4489 { &hf_dcerpc_array_buffer,
4490 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
4493 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4495 { &hf_dcerpc_fragments,
4496 { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
4497 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
4499 { &hf_dcerpc_fragment,
4500 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
4501 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
4503 { &hf_dcerpc_fragment_overlap,
4504 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
4506 { &hf_dcerpc_fragment_overlap_conflict,
4507 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
4509 { &hf_dcerpc_fragment_multiple_tails,
4510 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
4512 { &hf_dcerpc_fragment_too_long_fragment,
4513 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
4515 { &hf_dcerpc_fragment_error,
4516 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
4519 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
4521 { &hf_dcerpc_reassembled_in,
4522 { "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 }},
4524 { &hf_dcerpc_unknown_if_id,
4525 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
4527 static gint *ett[] = {
4529 &ett_dcerpc_cn_flags,
4531 &ett_dcerpc_cn_iface,
4533 &ett_dcerpc_dg_flags1,
4534 &ett_dcerpc_dg_flags2,
4535 &ett_dcerpc_pointer_data,
4537 &ett_dcerpc_fragments,
4538 &ett_dcerpc_fragment,
4539 &ett_dcerpc_krb5_auth_verf,
4541 module_t *dcerpc_module;
4543 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
4544 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
4545 proto_register_subtree_array (ett, array_length (ett));
4546 register_init_routine (dcerpc_init_protocol);
4547 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
4548 prefs_register_bool_preference (dcerpc_module,
4550 "Desegment all DCE/RPC over TCP",
4551 "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
4552 &dcerpc_cn_desegment);
4553 prefs_register_bool_preference (dcerpc_module,
4554 "reassemble_dcerpc",
4555 "Reassemble DCE/RPC fragments",
4556 "Whether the DCE/RPC dissector should reassemble all fragmented PDUs",
4557 &dcerpc_reassemble);
4558 register_init_routine(dcerpc_reassemble_init);
4559 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
4560 dcerpc_tap=register_tap("dcerpc");
4564 proto_reg_handoff_dcerpc (void)
4566 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
4567 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
4568 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
4569 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
4570 dcerpc_smb_init(proto_dcerpc);