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.158 2003/12/08 20:58:01 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;
390 static gint ett_dcerpc = -1;
391 static gint ett_dcerpc_cn_flags = -1;
392 static gint ett_dcerpc_cn_ctx = -1;
393 static gint ett_dcerpc_cn_iface = -1;
394 static gint ett_dcerpc_drep = -1;
395 static gint ett_dcerpc_dg_flags1 = -1;
396 static gint ett_dcerpc_dg_flags2 = -1;
397 static gint ett_dcerpc_pointer_data = -1;
398 static gint ett_dcerpc_string = -1;
399 static gint ett_dcerpc_fragments = -1;
400 static gint ett_dcerpc_fragment = -1;
401 static gint ett_dcerpc_krb5_auth_verf = -1;
403 static const fragment_items dcerpc_frag_items = {
404 &ett_dcerpc_fragments,
405 &ett_dcerpc_fragment,
407 &hf_dcerpc_fragments,
409 &hf_dcerpc_fragment_overlap,
410 &hf_dcerpc_fragment_overlap_conflict,
411 &hf_dcerpc_fragment_multiple_tails,
412 &hf_dcerpc_fragment_too_long_fragment,
413 &hf_dcerpc_fragment_error,
424 static dcerpc_info di[20];
425 static int di_counter=0;
431 return &di[di_counter];
434 /* try to desegment big DCE/RPC packets over TCP? */
435 static gboolean dcerpc_cn_desegment = TRUE;
437 /* reassemble DCE/RPC fragments */
438 /* reassembly of dcerpc fragments will not work for the case where ONE frame
439 might contain multiple dcerpc fragments for different PDUs.
440 this case would be so unusual/weird so if you got captures like that:
443 static gboolean dcerpc_reassemble = FALSE;
444 static GHashTable *dcerpc_co_reassemble_table = NULL;
445 static GHashTable *dcerpc_cl_reassemble_table = NULL;
448 dcerpc_reassemble_init(void)
450 fragment_table_init(&dcerpc_co_reassemble_table);
451 fragment_table_init(&dcerpc_cl_reassemble_table);
455 * Authentication subdissectors. Used to dissect authentication blobs in
456 * DCERPC binds, requests and responses.
459 typedef struct _dcerpc_auth_subdissector {
462 dcerpc_auth_subdissector_fns auth_fns;
463 } dcerpc_auth_subdissector;
465 static GSList *dcerpc_auth_subdissector_list;
467 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
468 guint8 auth_level, guint8 auth_type)
473 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
474 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
476 if (asd->auth_level == auth_level &&
477 asd->auth_type == auth_type)
478 return &asd->auth_fns;
484 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
485 dcerpc_auth_subdissector_fns *fns)
487 dcerpc_auth_subdissector *d;
489 if (get_auth_subdissector_fns(auth_level, auth_type))
492 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
494 d->auth_level = auth_level;
495 d->auth_type = auth_type;
496 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
498 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
501 /* Hand off verifier data to a registered dissector */
503 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
505 dcerpc_auth_subdissector_fns *auth_fns,
506 e_dce_cn_common_hdr_t *hdr,
507 dcerpc_auth_info *auth_info)
509 dcerpc_dissect_fnct_t *volatile fn = NULL;
511 switch (hdr->ptype) {
514 fn = auth_fns->bind_fn;
518 fn = auth_fns->bind_ack_fn;
521 fn = auth_fns->auth3_fn;
524 fn = auth_fns->req_verf_fn;
527 fn = auth_fns->resp_verf_fn;
530 /* Don't know how to handle authentication data in this
534 g_warning("attempt to dissect %s pdu authentication data",
535 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
540 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
542 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
544 val_to_str(auth_info->auth_type,
549 /* Hand off payload data to a registered dissector */
551 static tvbuff_t *decode_encrypted_data(tvbuff_t *enc_tvb,
553 dcerpc_auth_subdissector_fns *auth_fns,
555 dcerpc_auth_info *auth_info)
557 dcerpc_decode_data_fnct_t *fn;
560 fn = auth_fns->req_data_fn;
562 fn = auth_fns->resp_data_fn;
565 return fn(enc_tvb, 0, pinfo, auth_info);
574 /* the registered subdissectors */
575 GHashTable *dcerpc_uuids=NULL;
578 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
580 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
581 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
582 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
583 && (key1->ver == key2->ver));
587 dcerpc_uuid_hash (gconstpointer k)
589 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
590 /* This isn't perfect, but the Data1 part of these is almost always
592 return key->uuid.Data1;
596 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
597 dcerpc_sub_dissector *procs, int opnum_hf)
599 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
600 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
601 header_field_info *hf_info;
606 value->proto = find_protocol_by_id(proto);
607 value->proto_id = proto;
609 value->name = proto_get_protocol_short_name (value->proto);
610 value->procs = procs;
611 value->opnum_hf = opnum_hf;
613 g_hash_table_insert (dcerpc_uuids, key, value);
615 hf_info = proto_registrar_get_nth(opnum_hf);
616 hf_info->strings = value_string_from_subdissectors(procs);
619 /* Function to find the name of a registered protocol
620 * or NULL if the protocol/version is not known to ethereal.
623 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
626 dcerpc_uuid_value *sub_proto;
630 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
633 return sub_proto->name;
636 /* Function to find the opnum hf-field of a registered protocol
637 * or -1 if the protocol/version is not known to ethereal.
640 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
643 dcerpc_uuid_value *sub_proto;
647 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
650 return sub_proto->opnum_hf;
653 /* Create a value_string consisting of DCERPC opnum and name from a
654 subdissector array. */
656 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
658 value_string *vs = NULL;
662 for (i = 0; sd[i].name; i++) {
664 vs[i].value = sd[i].num;
665 vs[i].strptr = sd[i].name;
671 vs = g_malloc((num_sd + 1) * sizeof(value_string));
675 vs[num_sd].value = 0;
676 vs[num_sd].strptr = NULL;
681 /* Function to find the subdissector table of a registered protocol
682 * or NULL if the protocol/version is not known to ethereal.
684 dcerpc_sub_dissector *
685 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
688 dcerpc_uuid_value *sub_proto;
692 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
695 return sub_proto->procs;
700 * To keep track of ctx_id mappings.
702 * Everytime we see a bind call we update this table.
703 * Note that we always specify a SMB FID. For non-SMB transports this
706 static GHashTable *dcerpc_binds=NULL;
708 typedef struct _dcerpc_bind_key {
709 conversation_t *conv;
714 typedef struct _dcerpc_bind_value {
719 static GMemChunk *dcerpc_bind_key_chunk=NULL;
720 static GMemChunk *dcerpc_bind_value_chunk=NULL;
723 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
725 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
726 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
727 return (key1->conv == key2->conv
728 && key1->ctx_id == key2->ctx_id
729 && key1->smb_fid == key2->smb_fid);
733 dcerpc_bind_hash (gconstpointer k)
735 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
736 return GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
741 * To keep track of callid mappings. Should really use some generic
742 * conversation support instead.
744 static GHashTable *dcerpc_calls=NULL;
746 typedef struct _dcerpc_call_key {
747 conversation_t *conv;
752 static GMemChunk *dcerpc_call_key_chunk=NULL;
754 static GMemChunk *dcerpc_call_value_chunk=NULL;
757 dcerpc_call_equal (gconstpointer k1, gconstpointer k2)
759 const dcerpc_call_key *key1 = (const dcerpc_call_key *)k1;
760 const dcerpc_call_key *key2 = (const dcerpc_call_key *)k2;
761 return (key1->conv == key2->conv
762 && key1->call_id == key2->call_id
763 && key1->smb_fid == key2->smb_fid);
767 dcerpc_call_hash (gconstpointer k)
769 const dcerpc_call_key *key = (const dcerpc_call_key *)k;
770 return ((guint32)key->conv) + key->call_id + key->smb_fid;
774 /* to keep track of matched calls/responses
775 this one uses the same value struct as calls, but the key is the frame id
776 and call id; there can be more than one call in a frame.
778 XXX - why not just use the same keys as are used for calls?
781 static GHashTable *dcerpc_matched=NULL;
783 typedef struct _dcerpc_matched_key {
786 } dcerpc_matched_key;
788 static GMemChunk *dcerpc_matched_key_chunk=NULL;
791 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
793 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
794 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
795 return (key1->frame == key2->frame
796 && key1->call_id == key2->call_id);
800 dcerpc_matched_hash (gconstpointer k)
802 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
809 * Utility functions. Modeled after packet-rpc.c
813 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
814 proto_tree *tree, char *drep,
815 int hfindex, guint8 *pdata)
819 data = tvb_get_guint8 (tvb, offset);
821 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
829 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
830 proto_tree *tree, char *drep,
831 int hfindex, guint16 *pdata)
835 data = ((drep[0] & 0x10)
836 ? tvb_get_letohs (tvb, offset)
837 : tvb_get_ntohs (tvb, offset));
840 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
848 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
849 proto_tree *tree, char *drep,
850 int hfindex, guint32 *pdata)
854 data = ((drep[0] & 0x10)
855 ? tvb_get_letohl (tvb, offset)
856 : tvb_get_ntohl (tvb, offset));
859 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
866 /* handles 32 bit unix time_t */
868 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
869 proto_tree *tree, char *drep,
870 int hfindex, guint32 *pdata)
875 data = ((drep[0] & 0x10)
876 ? tvb_get_letohl (tvb, offset)
877 : tvb_get_ntohl (tvb, offset));
882 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
891 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
892 proto_tree *tree, char *drep,
893 int hfindex, unsigned char *pdata)
896 tvb_memcpy(tvb, pdata, offset, 8);
897 if(drep[0] & 0x10){/* XXX this might be the wrong way around */
899 data=pdata[0];pdata[0]=pdata[7];pdata[7]=data;
900 data=pdata[1];pdata[1]=pdata[6];pdata[6]=data;
901 data=pdata[2];pdata[2]=pdata[5];pdata[5]=data;
902 data=pdata[3];pdata[3]=pdata[4];pdata[4]=data;
907 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
915 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
916 proto_tree *tree, char *drep,
917 int hfindex, gfloat *pdata)
923 case(DCE_RPC_DREP_FP_IEEE):
924 data = ((drep[0] & 0x10)
925 ? tvb_get_letohieee_float(tvb, offset)
926 : tvb_get_ntohieee_float(tvb, offset));
928 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
931 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
932 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
933 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
935 /* ToBeDone: non IEEE floating formats */
936 /* Set data to a negative infinity value */
937 data = -1.0 * 1e100 * 1e100;
939 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
949 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
950 proto_tree *tree, char *drep,
951 int hfindex, gdouble *pdata)
957 case(DCE_RPC_DREP_FP_IEEE):
958 data = ((drep[0] & 0x10)
959 ? tvb_get_letohieee_double(tvb, offset)
960 : tvb_get_ntohieee_double(tvb, offset));
962 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
965 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
966 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
967 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
969 /* ToBeDone: non IEEE double formats */
970 /* Set data to a negative infinity value */
971 data = -1.0 * 1e100 * 1e100;
973 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
983 * a couple simpler things
986 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, char *drep)
988 if (drep[0] & 0x10) {
989 return tvb_get_letohs (tvb, offset);
991 return tvb_get_ntohs (tvb, offset);
996 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, char *drep)
998 if (drep[0] & 0x10) {
999 return tvb_get_letohl (tvb, offset);
1001 return tvb_get_ntohl (tvb, offset);
1006 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, char *drep, e_uuid_t *uuid)
1009 uuid->Data1 = dcerpc_tvb_get_ntohl (tvb, offset, drep);
1010 uuid->Data2 = dcerpc_tvb_get_ntohs (tvb, offset+4, drep);
1011 uuid->Data3 = dcerpc_tvb_get_ntohs (tvb, offset+6, drep);
1013 for (i=0; i<sizeof (uuid->Data4); i++) {
1014 uuid->Data4[i] = tvb_get_guint8 (tvb, offset+8+i);
1021 /* function to dissect a unidimensional conformant array */
1023 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1024 proto_tree *tree, char *drep,
1025 dcerpc_dissect_fnct_t *fnct)
1031 di=pinfo->private_data;
1032 if(di->conformant_run){
1033 /* conformant run, just dissect the max_count header */
1035 di->conformant_run=0;
1036 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1037 hf_dcerpc_array_max_count, &di->array_max_count);
1038 di->array_max_count_offset=offset-4;
1039 di->conformant_run=1;
1040 di->conformant_eaten=offset-old_offset;
1042 /* we don't remember where in the bytestream this field was */
1043 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1045 /* real run, dissect the elements */
1046 for(i=0;i<di->array_max_count;i++){
1047 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1053 /* function to dissect a unidimensional conformant and varying array */
1055 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1056 proto_tree *tree, char *drep,
1057 dcerpc_dissect_fnct_t *fnct)
1063 di=pinfo->private_data;
1064 if(di->conformant_run){
1065 /* conformant run, just dissect the max_count header */
1067 di->conformant_run=0;
1068 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1069 hf_dcerpc_array_max_count, &di->array_max_count);
1070 di->array_max_count_offset=offset-4;
1071 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1072 hf_dcerpc_array_offset, &di->array_offset);
1073 di->array_offset_offset=offset-4;
1074 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1075 hf_dcerpc_array_actual_count, &di->array_actual_count);
1076 di->array_actual_count_offset=offset-4;
1077 di->conformant_run=1;
1078 di->conformant_eaten=offset-old_offset;
1080 /* we dont dont remember where in the bytestream these fields were */
1081 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1082 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1083 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1085 /* real run, dissect the elements */
1086 for(i=0;i<di->array_actual_count;i++){
1087 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1094 /* Dissect an string of bytes. This corresponds to
1095 IDL of the form '[string] byte *foo'.
1097 It can also be used for a conformant varying array of bytes if
1098 the contents of the array should be shown as a big blob, rather
1099 than showing each byte as an individual element.
1101 XXX - which of those is really the IDL type for, for example,
1102 the encrypted data in some MAPI packets? (Microsoft haven't
1105 XXX - does this need to do all the conformant array stuff that
1106 "dissect_ndr_ucvarray()" does? These are presumably for strings
1107 that are conformant and varying - they're stored like conformant
1108 varying arrays of bytes. */
1110 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1111 proto_tree *tree, char *drep)
1116 di=pinfo->private_data;
1117 if(di->conformant_run){
1118 /* just a run to handle conformant arrays, no scalars to dissect */
1122 /* NDR array header */
1124 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1125 hf_dcerpc_array_max_count, NULL);
1127 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1128 hf_dcerpc_array_offset, NULL);
1130 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1131 hf_dcerpc_array_actual_count, &len);
1134 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1135 tvb, offset, len, drep[0] & 0x10);
1142 /* For dissecting arrays that are to be interpreted as strings. */
1144 /* Dissect an NDR conformant varying string of elements.
1145 The length of each element is given by the 'size_is' parameter;
1146 the elements are assumed to be characters or wide characters.
1148 XXX - does this need to do all the conformant array stuff that
1149 "dissect_ndr_ucvarray()" does? */
1151 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1152 proto_tree *tree, char *drep, int size_is,
1153 int hfindex, gboolean add_subtree, char **data)
1156 proto_item *string_item;
1157 proto_tree *string_tree;
1158 guint32 len, buffer_len;
1160 header_field_info *hfinfo;
1162 di=pinfo->private_data;
1163 if(di->conformant_run){
1164 /* just a run to handle conformant arrays, no scalars to dissect */
1169 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1170 proto_registrar_get_name(hfindex));
1171 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1177 /* NDR array header */
1179 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1180 hf_dcerpc_array_max_count, NULL);
1182 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1183 hf_dcerpc_array_offset, NULL);
1185 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1186 hf_dcerpc_array_actual_count, &len);
1188 buffer_len = size_is * len;
1191 if (offset % size_is)
1192 offset += size_is - (offset % size_is);
1194 if (size_is == sizeof(guint16)) {
1195 /* XXX - use drep to determine the byte order? */
1196 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1198 * XXX - we don't support a string type with Unicode
1199 * characters, so if this is a string item, we make
1200 * its value be the "fake Unicode" string.
1202 if (tree && buffer_len) {
1203 hfinfo = proto_registrar_get_nth(hfindex);
1204 if (hfinfo->type == FT_STRING) {
1205 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1208 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1209 buffer_len, drep[0] & 0x10);
1214 * "tvb_get_string()" throws an exception if the entire string
1215 * isn't in the tvbuff. If the length is bogus, this should
1216 * keep us from trying to allocate an immensely large buffer.
1217 * (It won't help if the length is *valid* but immensely large,
1218 * but that's another matter; in any case, that would happen only
1219 * if we had an immensely large tvbuff....)
1221 s = tvb_get_string(tvb, offset, buffer_len);
1222 if (tree && buffer_len)
1223 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1224 buffer_len, drep[0] & 0x10);
1227 if (string_item != NULL)
1228 proto_item_append_text(string_item, ": %s", s);
1235 offset += buffer_len;
1237 proto_item_set_end(string_item, tvb, offset);
1242 /* Dissect an conformant varying string of chars.
1243 This corresponds to IDL of the form '[string] char *foo'.
1245 XXX - at least according to the DCE RPC 1.1 spec, a string has
1246 a null terminator, which isn't necessary as a terminator for
1247 the transfer language (as there's a length), but is presumably
1248 there for the benefit of null-terminated-string languages
1249 such as C. Is this ever used for purely counted strings?
1250 (Not that it matters if it is.) */
1252 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1253 proto_tree *tree, char *drep)
1256 di=pinfo->private_data;
1258 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1259 sizeof(guint8), di->hf_index,
1263 /* Dissect a conformant varying string of wchars (wide characters).
1264 This corresponds to IDL of the form '[string] wchar *foo'
1266 XXX - at least according to the DCE RPC 1.1 spec, a string has
1267 a null terminator, which isn't necessary as a terminator for
1268 the transfer language (as there's a length), but is presumably
1269 there for the benefit of null-terminated-string languages
1270 such as C. Is this ever used for purely counted strings?
1271 (Not that it matters if it is.) */
1273 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1274 proto_tree *tree, char *drep)
1277 di=pinfo->private_data;
1279 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1280 sizeof(guint16), di->hf_index,
1284 /* ndr pointer handling */
1285 /* list of pointers encountered so far */
1286 static GSList *ndr_pointer_list = NULL;
1288 /* position where in the list to insert newly encountered pointers */
1289 static int ndr_pointer_list_pos=0;
1291 /* boolean controlling whether pointers are top-level or embedded */
1292 static gboolean pointers_are_top_level = TRUE;
1294 /* as a kludge, we represent all embedded reference pointers as id==-1
1295 hoping that his will not collide with any non-ref pointers */
1296 typedef struct ndr_pointer_data {
1298 proto_item *item; /* proto_item for pointer */
1299 proto_tree *tree; /* subtree of above item */
1300 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1302 dcerpc_callback_fnct_t *callback;
1303 void *callback_args;
1304 } ndr_pointer_data_t;
1307 init_ndr_pointer_list(packet_info *pinfo)
1311 di=pinfo->private_data;
1312 di->conformant_run=0;
1314 while(ndr_pointer_list){
1315 ndr_pointer_data_t *npd;
1317 npd=g_slist_nth_data(ndr_pointer_list, 0);
1318 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1324 ndr_pointer_list=NULL;
1325 ndr_pointer_list_pos=0;
1326 pointers_are_top_level=TRUE;
1330 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, char *drep)
1332 int found_new_pointer;
1338 di=pinfo->private_data;
1342 found_new_pointer=0;
1343 len=g_slist_length(ndr_pointer_list);
1344 for(i=next_pointer;i<len;i++){
1345 ndr_pointer_data_t *tnpd;
1346 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1348 dcerpc_dissect_fnct_t *fnct;
1351 found_new_pointer=1;
1354 ndr_pointer_list_pos=i+1;
1355 di->hf_index=tnpd->hf_index;
1356 /* first a run to handle any conformant
1358 di->conformant_run=1;
1359 di->conformant_eaten=0;
1360 old_offset = offset;
1361 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1363 g_assert((offset-old_offset)==di->conformant_eaten);
1364 /* This is to check for any bugs in the dissectors.
1366 * Basically, the NDR representation will store all
1367 * arrays in two blocks, one block with the dimension
1368 * discreption, like size, number of elements and such,
1369 * and another block that contains the actual data stored
1371 * If the array is embedded directly inside another,
1372 * encapsulating aggregate type, like a union or struct,
1373 * then these two blocks will be stored at different places
1374 * in the bytestream, with other data between the blocks.
1376 * For this reason, all pointers to types (both aggregate
1377 * and scalar, for simplicity no distinction is made)
1378 * will have its dissector called twice.
1379 * The dissector will first be called with conformant_run==1
1380 * in which mode the dissector MUST NOT consume any data from
1381 * the tvbuff (i.e. may not dissect anything) except the
1382 * initial control block for arrays.
1383 * The second time the dissector is called, with
1384 * conformant_run==0, all other data for the type will be
1387 * All dissect_ndr_<type> dissectors are already prepared
1388 * for this and knows when it should eat data from the tvb
1389 * and when not to, so implementors of dissectors will
1390 * normally not need to worry about this or even know about
1391 * it. However, if a dissector for an aggregate type calls
1392 * a subdissector from outside packet-dcerpc.c, such as
1393 * the dissector in packet-smb.c for NT Security Descriptors
1394 * as an example, then it is VERY important to encapsulate
1395 * this call to an external subdissector with the appropriate
1396 * test for conformant_run, i.e. it will need something like
1400 * di=pinfo->private_data;
1401 * if(di->conformant_run){
1405 * to make sure it makes the right thing.
1406 * This assert will signal when someone has forgotten to
1407 * make the dissector aware of this requirement.
1410 /* now we dissect the actual pointer */
1411 di->conformant_run=0;
1412 old_offset = offset;
1413 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1415 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1419 } while(found_new_pointer);
1426 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1427 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1428 dcerpc_callback_fnct_t *callback, void *callback_args)
1430 ndr_pointer_data_t *npd;
1432 /* check if this pointer is valid */
1435 dcerpc_call_value *value;
1437 di=pinfo->private_data;
1438 value=di->call_data;
1441 if(!(pinfo->fd->flags.visited)){
1442 if(id>value->max_ptr){
1447 /* if we havent seen the request bail out since we cant
1448 know whether this is the first non-NULL instance
1450 if(value->req_frame==0){
1451 /* XXX THROW EXCEPTION */
1454 /* We saw this one in the request frame, nothing to
1456 if(id<=value->max_ptr){
1462 npd=g_malloc(sizeof(ndr_pointer_data_t));
1467 npd->hf_index=hf_index;
1468 npd->callback=callback;
1469 npd->callback_args=callback_args;
1470 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1471 ndr_pointer_list_pos);
1472 ndr_pointer_list_pos++;
1477 find_pointer_index(guint32 id)
1479 ndr_pointer_data_t *npd;
1482 len=g_slist_length(ndr_pointer_list);
1484 npd=g_slist_nth_data(ndr_pointer_list, i);
1495 /* This function dissects an NDR pointer and stores the callback for later
1496 * deferred dissection.
1498 * fnct is the callback function for when we have reached this object in
1501 * type is what type of pointer.
1503 * this is text is what text we should put in any created tree node.
1505 * hf_index is what hf value we want to pass to the callback function when
1506 * it is called, the callback can later pich this one up from di->hf_index.
1508 * callback is executed after the pointer has been dereferenced.
1510 * callback_args is passed as an argument to the callback function
1512 * See packet-dcerpc-samr.c for examples
1515 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1516 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1517 int type, char *text, int hf_index,
1518 dcerpc_callback_fnct_t *callback, void *callback_args)
1522 di=pinfo->private_data;
1523 if(di->conformant_run){
1524 /* this call was only for dissecting the header for any
1525 embedded conformant array. we will not parse any
1526 pointers in this mode.
1531 /*TOP LEVEL REFERENCE POINTER*/
1532 if( pointers_are_top_level
1533 &&(type==NDR_POINTER_REF) ){
1537 /* we must find out a nice way to do the length here */
1538 item=proto_tree_add_text(tree, tvb, offset, 0,
1540 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1542 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1543 hf_index, callback, callback_args);
1547 /*TOP LEVEL FULL POINTER*/
1548 if( pointers_are_top_level
1549 && (type==NDR_POINTER_PTR) ){
1555 /* get the referent id */
1556 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1558 /* we got a NULL pointer */
1560 proto_tree_add_text(tree, tvb, offset-4, 4,
1561 "(NULL pointer) %s",text);
1565 /* see if we have seen this pointer before */
1566 idx=find_pointer_index(id);
1568 /* we have seen this pointer before */
1570 proto_tree_add_text(tree, tvb, offset-4, 4,
1571 "(duplicate PTR) %s",text);
1576 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1578 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1579 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1580 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1581 callback, callback_args);
1584 /*TOP LEVEL UNIQUE POINTER*/
1585 if( pointers_are_top_level
1586 && (type==NDR_POINTER_UNIQUE) ){
1591 /* get the referent id */
1592 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1594 /* we got a NULL pointer */
1596 proto_tree_add_text(tree, tvb, offset-4, 4,
1597 "(NULL pointer) %s",text);
1602 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1604 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1605 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1606 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1607 hf_index, callback, callback_args);
1611 /*EMBEDDED REFERENCE POINTER*/
1612 if( (!pointers_are_top_level)
1613 && (type==NDR_POINTER_REF) ){
1618 /* get the referent id */
1619 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1622 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1624 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1625 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1626 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1627 hf_index, callback, callback_args);
1631 /*EMBEDDED UNIQUE POINTER*/
1632 if( (!pointers_are_top_level)
1633 && (type==NDR_POINTER_UNIQUE) ){
1638 /* get the referent id */
1639 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1641 /* we got a NULL pointer */
1643 proto_tree_add_text(tree, tvb, offset-4, 4,
1644 "(NULL pointer) %s", text);
1649 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1651 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1652 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1653 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1654 hf_index, callback, callback_args);
1658 /*EMBEDDED FULL POINTER*/
1659 if( (!pointers_are_top_level)
1660 && (type==NDR_POINTER_PTR) ){
1666 /* get the referent id */
1667 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1669 /* we got a NULL pointer */
1671 proto_tree_add_text(tree, tvb, offset-4, 4,
1672 "(NULL pointer) %s",text);
1676 /* see if we have seen this pointer before */
1677 idx=find_pointer_index(id);
1679 /* we have seen this pointer before */
1681 proto_tree_add_text(tree, tvb, offset-4, 4,
1682 "(duplicate PTR) %s",text);
1687 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1689 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1690 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1691 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1692 callback, callback_args);
1698 /* After each top level pointer we have dissected we have to
1699 dissect all deferrals before we move on to the next top level
1701 if(pointers_are_top_level==TRUE){
1702 pointers_are_top_level=FALSE;
1703 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
1704 pointers_are_top_level=TRUE;
1711 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1712 proto_tree *tree, char *drep, dcerpc_dissect_fnct_t *fnct,
1713 int type, char *text, int hf_index)
1715 return dissect_ndr_pointer_cb(
1716 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
1721 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
1722 dcerpc_auth_info *auth_info, gboolean is_encrypted)
1727 * We don't show stub data unless we have some in the tvbuff;
1728 * however, in the protocol tree, we show, as the number of
1729 * bytes, the reported number of bytes, not the number of bytes
1730 * that happen to be in the tvbuff.
1732 if (tvb_length_remaining (tvb, offset) > 0) {
1733 length = tvb_reported_length_remaining (tvb, offset);
1734 if (auth_info != NULL &&
1735 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
1737 proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
1738 "Encrypted stub data (%d byte%s)",
1739 length, plurality(length, "", "s"));
1741 proto_tree_add_text(dcerpc_tree, tvb, offset, -1,
1742 "Decrypted stub data (%d byte%s)",
1743 length, plurality(length, "", "s"));
1746 proto_tree_add_text (dcerpc_tree, tvb, offset, -1,
1747 "Stub data (%d byte%s)", length,
1748 plurality(length, "", "s"));
1754 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
1755 proto_tree *dcerpc_tree,
1756 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
1757 char *drep, dcerpc_info *info,
1758 dcerpc_auth_info *auth_info)
1760 volatile gint offset = 0;
1761 dcerpc_uuid_key key;
1762 dcerpc_uuid_value *sub_proto;
1763 proto_tree *volatile sub_tree = NULL;
1764 dcerpc_sub_dissector *proc;
1766 dcerpc_dissect_fnct_t *volatile sub_dissect;
1767 const char *volatile saved_proto;
1768 void *volatile saved_private_data;
1769 guint length, reported_length;
1770 tvbuff_t *volatile stub_tvb;
1771 volatile guint auth_pad_len;
1772 volatile int auth_pad_offset;
1774 key.uuid = info->call_data->uuid;
1775 key.ver = info->call_data->ver;
1778 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
1779 || !proto_is_protocol_enabled(sub_proto->proto)) {
1781 * We don't have a dissector for this UUID, or the protocol
1782 * for that UUID is disabled.
1784 if (decrypted_tvb != NULL) {
1785 show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
1788 show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
1792 for (proc = sub_proto->procs; proc->name; proc++) {
1793 if (proc->num == info->call_data->opnum) {
1802 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
1803 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
1806 if (check_col (pinfo->cinfo, COL_INFO)) {
1807 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
1808 name, info->request ? "request" : "reply");
1812 proto_item *sub_item;
1813 sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
1817 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
1821 * Put the operation number into the tree along with
1822 * the operation's name.
1825 if (sub_proto->opnum_hf != -1)
1826 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
1827 tvb, 0, 0, info->call_data->opnum,
1828 "Operation: %s (%u)",
1829 name, info->call_data->opnum);
1831 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
1832 0, 0, info->call_data->opnum,
1833 "Operation: %s (%u)",
1834 name, info->call_data->opnum);
1837 sub_dissect = info->request ? proc->dissect_rqst : proc->dissect_resp;
1839 if (decrypted_tvb != NULL) {
1840 /* Either there was no encryption or we successfully decrypted
1841 the entrypted payload. */
1843 /* We have a subdissector - call it. */
1844 saved_proto = pinfo->current_proto;
1845 saved_private_data = pinfo->private_data;
1846 pinfo->current_proto = sub_proto->name;
1847 pinfo->private_data = (void *)info;
1849 init_ndr_pointer_list(pinfo);
1852 * Remove the authentication padding from the stub data.
1854 if (auth_info != NULL && auth_info->auth_pad_len != 0) {
1855 length = tvb_length(decrypted_tvb);
1856 reported_length = tvb_reported_length(decrypted_tvb);
1857 if (reported_length >= auth_info->auth_pad_len) {
1859 * OK, the padding length isn't so big that it
1860 * exceeds the stub length. Trim the reported
1861 * length of the tvbuff.
1863 reported_length -= auth_info->auth_pad_len;
1866 * If that exceeds the actual amount of data in
1867 * the tvbuff (which means we have at least one
1868 * byte of authentication padding in the tvbuff),
1869 * trim the actual amount.
1871 if (length > reported_length)
1872 length = reported_length;
1874 stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
1875 auth_pad_len = auth_info->auth_pad_len;
1876 auth_pad_offset = reported_length;
1879 * The padding length exceeds the stub length.
1880 * Don't bother dissecting the stub, trim the padding
1881 * length to what's in the stub data, and show the
1882 * entire stub as authentication padding.
1885 auth_pad_len = reported_length;
1886 auth_pad_offset = 0;
1890 * No authentication padding.
1892 stub_tvb = decrypted_tvb;
1894 auth_pad_offset = 0;
1897 if (stub_tvb != NULL) {
1899 * Catch all exceptions other than BoundsError, so that even
1900 * if the stub data is bad, we still show the authentication
1903 * If we get BoundsError, it means the frame was cut short
1904 * by a snapshot length, so there's nothing more to
1905 * dissect; just re-throw that exception.
1908 offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
1911 /* If we have a subdissector and it didn't dissect all
1912 data in the tvb, make a note of it. */
1914 if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
1915 if (check_col(pinfo->cinfo, COL_INFO))
1916 col_append_fstr(pinfo->cinfo, COL_INFO,
1917 "[Long frame (%d bytes)]",
1918 tvb_reported_length_remaining(stub_tvb, offset));
1920 } CATCH(BoundsError) {
1923 show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE);
1927 /* If there is auth padding at the end of the stub, display it */
1928 if (auth_pad_len != 0) {
1929 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
1931 "Auth Padding (%u byte%s)",
1933 plurality(auth_pad_len, "", "s"));
1936 pinfo->current_proto = saved_proto;
1937 pinfo->private_data = saved_private_data;
1939 /* No subdissector - show it as stub data. */
1941 show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
1943 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
1947 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
1949 tap_queue_packet(dcerpc_tap, pinfo, info);
1954 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
1955 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
1956 dcerpc_auth_info *auth_info)
1960 auth_info->auth_data = NULL;
1962 if (auth_info->auth_size != 0) {
1963 dcerpc_auth_subdissector_fns *auth_fns;
1966 auth_offset = hdr->frag_len - hdr->auth_len;
1968 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
1971 auth_info->auth_data = auth_tvb;
1973 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
1974 auth_info->auth_type))) {
1976 * Catch all exceptions, so that even if the verifier is bad
1977 * or we don't have all of it, we still show the stub data.
1980 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
1983 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
1986 proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
1991 return hdr->auth_len;
1995 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
1996 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
1997 gboolean are_credentials, dcerpc_auth_info *auth_info)
1999 volatile int offset;
2002 * Initially set auth_level and auth_type to zero to indicate that we
2003 * haven't yet seen any authentication level information.
2005 auth_info->auth_level = 0;
2006 auth_info->auth_type = 0;
2007 auth_info->auth_size = 0;
2008 auth_info->auth_pad_len = 0;
2011 * The authentication information is at the *end* of the PDU; in
2012 * request and response PDUs, the request and response stub data
2015 * Is there any authentication data (i.e., is the authentication length
2016 * non-zero), and is the authentication length valid (i.e., is it, plus
2017 * 8 bytes for the type/level/pad length/reserved/context id, less than
2018 * or equal to the fragment length minus the starting offset of the
2023 && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2026 * Yes, there is authentication data, and the length is valid.
2027 * Do we have all the bytes of stub data?
2028 * (If not, we'd throw an exception dissecting *that*, so don't
2029 * bother trying to dissect the authentication information and
2030 * throwing another exception there.)
2032 offset = hdr->frag_len - (hdr->auth_len + 8);
2033 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2035 * Either there's no stub data, or the last byte of the stub
2036 * data is present in the captured data, so we shouldn't
2037 * get a BoundsError dissecting the stub data.
2039 * Try dissecting the authentication data.
2040 * Catch all exceptions, so that even if the auth info is bad
2041 * or we don't have all of it, we still show the stuff we
2042 * dissect after this, such as stub data.
2045 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2046 hf_dcerpc_auth_type,
2047 &auth_info->auth_type);
2048 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2049 hf_dcerpc_auth_level,
2050 &auth_info->auth_level);
2052 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2053 hf_dcerpc_auth_pad_len,
2054 &auth_info->auth_pad_len);
2055 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2056 hf_dcerpc_auth_rsrvd, NULL);
2057 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2058 hf_dcerpc_auth_ctx_id, NULL);
2061 * Dissect the authentication data.
2063 if (are_credentials) {
2065 dcerpc_auth_subdissector_fns *auth_fns;
2067 auth_tvb = tvb_new_subset(tvb, offset, hdr->auth_len,
2070 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2071 auth_info->auth_type)))
2072 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2075 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2076 "Auth Credentials");
2079 /* Compute the size of the auth block. Note that this should not
2080 include auth padding, since when NTLMSSP encryption is used, the
2081 padding is actually inside the encrypted stub */
2082 auth_info->auth_size = hdr->auth_len + 8;
2084 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE);
2091 /* We need to hash in the SMB fid number to generate a unique hash table
2092 key as DCERPC over SMB allows several pipes over the same TCP/IP
2095 static guint16 get_smb_fid (void *private_data)
2097 dcerpc_private_info *priv = (dcerpc_private_info *)private_data;
2100 return 0; /* Nothing to see here */
2102 /* DCERPC over smb */
2104 if (priv->transport_type == DCERPC_TRANSPORT_SMB)
2105 return priv->data.smb.fid;
2107 /* Some other transport... */
2113 * Connection oriented packet types
2117 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2118 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2120 conversation_t *conv = NULL;
2121 guint8 num_ctx_items = 0;
2123 gboolean saw_ctx_item = FALSE;
2125 guint16 num_trans_items;
2130 guint16 if_ver, if_ver_minor;
2131 char uuid_str[DCERPC_UUID_STR_LEN];
2133 dcerpc_auth_info auth_info;
2135 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2136 hf_dcerpc_cn_max_xmit, NULL);
2138 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2139 hf_dcerpc_cn_max_recv, NULL);
2141 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2142 hf_dcerpc_cn_assoc_group, NULL);
2144 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2145 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2150 for (i = 0; i < num_ctx_items; i++) {
2151 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2153 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2154 hf_dcerpc_cn_ctx_id, &ctx_id);
2157 proto_item *ctx_item;
2159 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_id,
2161 hdr->drep[0] & 0x10);
2163 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2166 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2167 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2169 /* XXX - use "dissect_ndr_uuid_t()"? */
2170 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2172 proto_item *iface_item;
2174 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2175 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2176 if_id.Data1, if_id.Data2, if_id.Data3,
2177 if_id.Data4[0], if_id.Data4[1],
2178 if_id.Data4[2], if_id.Data4[3],
2179 if_id.Data4[4], if_id.Data4[5],
2180 if_id.Data4[6], if_id.Data4[7]);
2182 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2183 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2185 iface_item = proto_tree_add_string_format (ctx_tree, hf_dcerpc_cn_bind_if_id, tvb,
2186 offset, 16, uuid_str, "Interface UUID: %s", uuid_str);
2187 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2191 if (hdr->drep[0] & 0x10) {
2192 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2193 hf_dcerpc_cn_bind_if_ver, &if_ver);
2194 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2195 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2197 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2198 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2199 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2200 hf_dcerpc_cn_bind_if_ver, &if_ver);
2203 if (!saw_ctx_item) {
2204 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2205 pinfo->srcport, pinfo->destport, 0);
2207 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
2208 pinfo->srcport, pinfo->destport, 0);
2211 /* if this is the first time we see this packet, we need to
2212 update the dcerpc_binds table so that any later calls can
2213 match to the interface.
2214 XXX We assume that BINDs will NEVER be fragmented.
2216 if(!(pinfo->fd->flags.visited)){
2217 dcerpc_bind_key *key;
2218 dcerpc_bind_value *value;
2220 key = g_mem_chunk_alloc (dcerpc_bind_key_chunk);
2222 key->ctx_id = ctx_id;
2223 key->smb_fid = get_smb_fid(pinfo->private_data);
2225 value = g_mem_chunk_alloc (dcerpc_bind_value_chunk);
2226 value->uuid = if_id;
2227 value->ver = if_ver;
2229 /* add this entry to the bind table, first removing any
2230 previous ones that are identical
2232 if(g_hash_table_lookup(dcerpc_binds, key)){
2233 g_hash_table_remove(dcerpc_binds, key);
2235 g_hash_table_insert (dcerpc_binds, key, value);
2238 if (check_col (pinfo->cinfo, COL_INFO)) {
2239 dcerpc_uuid_key key;
2240 dcerpc_uuid_value *value;
2245 if (num_ctx_items > 1)
2246 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2248 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2249 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2251 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2252 if_id.Data1, if_id.Data2, if_id.Data3,
2253 if_id.Data4[0], if_id.Data4[1],
2254 if_id.Data4[2], if_id.Data4[3],
2255 if_id.Data4[4], if_id.Data4[5],
2256 if_id.Data4[6], if_id.Data4[7],
2257 if_ver, if_ver_minor);
2259 saw_ctx_item = TRUE;
2262 for (j = 0; j < num_trans_items; j++) {
2263 /* XXX - use "dissect_ndr_uuid_t()"? */
2264 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2266 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2267 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2268 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2269 trans_id.Data4[0], trans_id.Data4[1],
2270 trans_id.Data4[2], trans_id.Data4[3],
2271 trans_id.Data4[4], trans_id.Data4[5],
2272 trans_id.Data4[6], trans_id.Data4[7]);
2273 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2274 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2275 proto_tree_add_string_format (iface_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2276 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2280 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, iface_tree, hdr->drep,
2281 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2286 * XXX - we should save the authentication type *if* we have
2287 * an authentication header, and associate it with an authentication
2288 * context, so subsequent PDUs can use that context.
2290 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2294 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2295 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2297 guint16 max_xmit, max_recv;
2298 guint16 sec_addr_len;
2305 char uuid_str[DCERPC_UUID_STR_LEN];
2307 dcerpc_auth_info auth_info;
2309 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2310 hf_dcerpc_cn_max_xmit, &max_xmit);
2312 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2313 hf_dcerpc_cn_max_recv, &max_recv);
2315 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2316 hf_dcerpc_cn_assoc_group, NULL);
2318 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2319 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2320 if (sec_addr_len != 0) {
2321 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2322 sec_addr_len, FALSE);
2323 offset += sec_addr_len;
2327 offset += 4 - offset % 4;
2330 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2331 hf_dcerpc_cn_num_results, &num_results);
2336 for (i = 0; i < num_results; i++) {
2337 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2338 hdr->drep, hf_dcerpc_cn_ack_result,
2341 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2342 hdr->drep, hf_dcerpc_cn_ack_reason,
2346 * The reason for rejection isn't meaningful, and often isn't
2347 * set, when the syntax was accepted.
2352 /* XXX - use "dissect_ndr_uuid_t()"? */
2353 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2355 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2356 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2357 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2358 trans_id.Data4[0], trans_id.Data4[1],
2359 trans_id.Data4[2], trans_id.Data4[3],
2360 trans_id.Data4[4], trans_id.Data4[5],
2361 trans_id.Data4[6], trans_id.Data4[7]);
2362 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2363 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2364 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2365 offset, 16, uuid_str, "Transfer Syntax: %s", uuid_str);
2369 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2370 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2374 * XXX - do we need to do anything with the authentication level
2375 * we get back from this?
2377 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2379 if (check_col (pinfo->cinfo, COL_INFO)) {
2380 if (num_results != 0 && result == 0) {
2381 /* XXX - only checks the last result */
2382 col_append_fstr (pinfo->cinfo, COL_INFO,
2383 " accept max_xmit: %u max_recv: %u",
2384 max_xmit, max_recv);
2386 /* XXX - only shows the last result and reason */
2387 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2388 val_to_str(result, p_cont_result_vals,
2389 "Unknown result (%u)"),
2390 val_to_str(reason, p_provider_reason_vals,
2397 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2398 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2401 guint8 num_protocols;
2404 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2405 hdr->drep, hf_dcerpc_cn_reject_reason,
2408 if (check_col (pinfo->cinfo, COL_INFO)) {
2409 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2410 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2413 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2414 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2415 hf_dcerpc_cn_num_protocols,
2418 for (i = 0; i < num_protocols; i++) {
2419 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2420 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2422 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2423 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2429 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2432 #define PFC_FRAG_MASK 0x03
2435 fragment_type(guint8 flags)
2437 flags = flags & PFC_FRAG_MASK;
2439 if (flags == PFC_FIRST_FRAG)
2445 if (flags == PFC_LAST_FRAG)
2448 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2454 /* Dissect stub data (payload) of a DCERPC packet. */
2457 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2458 proto_tree *dcerpc_tree, proto_tree *tree,
2459 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2460 dcerpc_auth_info *auth_info, guint32 alloc_hint,
2463 gboolean save_fragmented;
2464 fragment_data *fd_head=NULL;
2466 tvbuff_t *payload_tvb, *decrypted_tvb;
2468 save_fragmented = pinfo->fragmented;
2470 payload_tvb = tvb_new_subset(
2471 tvb, offset, tvb_length_remaining(tvb, offset) -
2472 auth_info->auth_size, tvb_length_remaining(tvb, offset) -
2473 auth_info->auth_size);
2475 /* Decrypt the PDU if it is encrypted */
2477 if (auth_info->auth_type &&
2478 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2480 * We know the authentication type, and the authentication
2481 * level is "Packet privacy", meaning the payload is
2482 * encrypted; attempt to decrypt it.
2484 dcerpc_auth_subdissector_fns *auth_fns;
2486 /* Start out assuming we won't succeed in decrypting. */
2487 decrypted_tvb = NULL;
2489 if ((auth_fns = get_auth_subdissector_fns(
2490 auth_info->auth_level, auth_info->auth_type))) {
2493 result = decode_encrypted_data(
2494 payload_tvb, pinfo, auth_fns,
2495 hdr->ptype == PDU_REQ, auth_info);
2499 proto_tree_add_text(
2500 dcerpc_tree, payload_tvb, 0, -1,
2501 "Encrypted stub data (%d byte%s)",
2502 tvb_reported_length(payload_tvb),
2504 plurality(tvb_length(payload_tvb), "", "s"));
2506 add_new_data_source(
2507 pinfo, result, "Decrypted stub data");
2510 decrypted_tvb = result;
2514 decrypted_tvb = payload_tvb;
2516 /* if this packet is not fragmented, just dissect it and exit */
2517 if(PFC_NOT_FRAGMENTED(hdr)){
2518 pinfo->fragmented = FALSE;
2521 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2522 hdr->drep, di, auth_info);
2524 pinfo->fragmented = save_fragmented;
2528 /* The packet is fragmented. */
2529 pinfo->fragmented = TRUE;
2531 /* if we are not doing reassembly and this is the first fragment
2532 then just dissect it and exit
2533 XXX - if we're not doing reassembly, can we decrypt an
2536 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
2539 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
2540 hdr->drep, di, auth_info);
2542 if (check_col(pinfo->cinfo, COL_INFO)) {
2543 col_append_fstr(pinfo->cinfo, COL_INFO,
2544 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2546 pinfo->fragmented = save_fragmented;
2550 /* if we have already seen this packet, see if it was reassembled
2551 and if so dissect the full pdu.
2554 if(pinfo->fd->flags.visited){
2555 fd_head=fragment_get(pinfo, frame, dcerpc_co_reassemble_table);
2559 /* if we are not doing reassembly and it was neither a complete PDU
2560 nor the first fragment then there is nothing more we can do
2561 so we just have to exit
2563 if( !dcerpc_reassemble )
2566 /* if we didnt get 'frame' we dont know where the PDU started and thus
2567 it is pointless to continue
2572 /* from now on we must attempt to reassemble the PDU
2575 /* if we get here we know it is the first time we see the packet
2576 and we also know it is only a fragment and not a full PDU,
2577 thus we must reassemble it.
2580 /* Do we have any non-encrypted data to reassemble? */
2581 if (decrypted_tvb == NULL) {
2582 /* No. We can't even try to reassemble. */
2586 /* if this is the first fragment we need to start reassembly
2588 if(hdr->flags&PFC_FIRST_FRAG){
2589 fragment_add(decrypted_tvb, 0, pinfo, frame, dcerpc_co_reassemble_table,
2590 0, tvb_length(decrypted_tvb), TRUE);
2591 fragment_set_tot_len(pinfo, frame,
2592 dcerpc_co_reassemble_table, alloc_hint);
2597 /* if this is a middle fragment, just add it and exit */
2598 if(!(hdr->flags&PFC_LAST_FRAG)){
2599 tot_len = fragment_get_tot_len(pinfo, frame,
2600 dcerpc_co_reassemble_table);
2601 fragment_add(decrypted_tvb, 0, pinfo, frame,
2602 dcerpc_co_reassemble_table,
2603 tot_len-alloc_hint, tvb_length(decrypted_tvb),
2609 /* this was the last fragment add it to reassembly
2611 tot_len = fragment_get_tot_len(pinfo, frame,
2612 dcerpc_co_reassemble_table);
2613 fd_head = fragment_add(decrypted_tvb, 0, pinfo,
2615 dcerpc_co_reassemble_table,
2616 tot_len-alloc_hint, tvb_length(decrypted_tvb),
2621 /* if reassembly is complete, dissect the full PDU
2623 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
2625 if(pinfo->fd->num==fd_head->reassembled_in){
2628 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
2629 tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
2630 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
2631 show_fragment_tree(fd_head, &dcerpc_frag_items,
2632 dcerpc_tree, pinfo, next_tvb);
2634 pinfo->fragmented = FALSE;
2636 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
2637 next_tvb, hdr->drep, di, auth_info);
2640 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
2641 decrypted_tvb, 0, 0, fd_head->reassembled_in);
2642 if (check_col(pinfo->cinfo, COL_INFO)) {
2643 col_append_fstr(pinfo->cinfo, COL_INFO,
2644 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2648 /* Reassembly not complete - some fragments
2649 are missing. Just show the stub data. */
2651 if (check_col(pinfo->cinfo, COL_INFO)) {
2652 col_append_fstr(pinfo->cinfo, COL_INFO,
2653 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
2657 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
2659 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
2663 pinfo->fragmented = save_fragmented;
2667 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2668 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2670 conversation_t *conv;
2674 dcerpc_auth_info auth_info;
2676 char uuid_str[DCERPC_UUID_STR_LEN];
2679 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2680 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2682 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2683 hf_dcerpc_cn_ctx_id, &ctx_id);
2685 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2686 hf_dcerpc_opnum, &opnum);
2688 if (check_col (pinfo->cinfo, COL_INFO)) {
2689 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
2693 if (hdr->flags & PFC_OBJECT_UUID) {
2694 /* XXX - use "dissect_ndr_uuid_t()"? */
2695 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
2697 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2698 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2699 obj_id.Data1, obj_id.Data2, obj_id.Data3,
2708 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
2709 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2710 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
2711 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
2717 * XXX - what if this was set when the connection was set up,
2718 * and we just have a security context?
2720 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2721 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2723 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2724 pinfo->srcport, pinfo->destport, 0);
2726 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
2728 dcerpc_matched_key matched_key, *new_matched_key;
2729 dcerpc_call_value *value;
2731 /* !!! we can NOT check flags.visited here since this will interact
2732 badly with when SMB handles (i.e. calls the subdissector)
2733 and desegmented pdu's .
2734 Instead we check if this pdu is already in the matched table or not
2736 matched_key.frame = pinfo->fd->num;
2737 matched_key.call_id = hdr->call_id;
2738 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
2740 dcerpc_bind_key bind_key;
2741 dcerpc_bind_value *bind_value;
2744 bind_key.ctx_id=ctx_id;
2745 bind_key.smb_fid=get_smb_fid(pinfo->private_data);
2747 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
2748 if(!(hdr->flags&PFC_FIRST_FRAG)){
2749 dcerpc_call_key call_key;
2750 dcerpc_call_value *call_value;
2753 call_key.call_id=hdr->call_id;
2754 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2755 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2756 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2757 *new_matched_key = matched_key;
2758 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2762 dcerpc_call_key *call_key;
2763 dcerpc_call_value *call_value;
2765 /* We found the binding and it is the first fragment
2766 (or a complete PDU) of a dcerpc pdu so just add
2767 the call to both the call table and the
2770 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
2771 call_key->conv=conv;
2772 call_key->call_id=hdr->call_id;
2773 call_key->smb_fid=get_smb_fid(pinfo->private_data);
2775 /* if there is already a matching call in the table
2776 remove it so it is replaced with the new one */
2777 if(g_hash_table_lookup(dcerpc_calls, call_key)){
2778 g_hash_table_remove(dcerpc_calls, call_key);
2781 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
2782 call_value->uuid = bind_value->uuid;
2783 call_value->ver = bind_value->ver;
2784 call_value->opnum = opnum;
2785 call_value->req_frame=pinfo->fd->num;
2786 call_value->req_time.secs=pinfo->fd->abs_secs;
2787 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
2788 call_value->rep_frame=0;
2789 call_value->max_ptr=0;
2790 call_value->private_data = NULL;
2791 g_hash_table_insert (dcerpc_calls, call_key, call_value);
2793 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2794 *new_matched_key = matched_key;
2795 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2805 /* handoff this call */
2807 di->call_id = hdr->call_id;
2808 di->smb_fid = get_smb_fid(pinfo->private_data);
2810 di->call_data = value;
2813 if(value->rep_frame!=0){
2814 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
2815 tvb, 0, 0, value->rep_frame);
2818 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2819 hdr, di, &auth_info, alloc_hint,
2822 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
2827 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2828 proto_tree *dcerpc_tree, proto_tree *tree, e_dce_cn_common_hdr_t *hdr)
2830 dcerpc_call_value *value = NULL;
2831 conversation_t *conv;
2833 dcerpc_auth_info auth_info;
2836 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2837 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2839 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2840 hf_dcerpc_cn_ctx_id, &ctx_id);
2842 if (check_col (pinfo->cinfo, COL_INFO)) {
2843 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
2846 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2847 hf_dcerpc_cn_cancel_count, NULL);
2852 * XXX - what if this was set when the connection was set up,
2853 * and we just have a security context?
2855 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2856 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
2858 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2859 pinfo->srcport, pinfo->destport, 0);
2862 /* no point in creating one here, really */
2863 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
2865 dcerpc_matched_key matched_key, *new_matched_key;
2867 /* !!! we can NOT check flags.visited here since this will interact
2868 badly with when SMB handles (i.e. calls the subdissector)
2869 and desegmented pdu's .
2870 Instead we check if this pdu is already in the matched table or not
2872 matched_key.frame = pinfo->fd->num;
2873 matched_key.call_id = hdr->call_id;
2874 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
2876 dcerpc_call_key call_key;
2877 dcerpc_call_value *call_value;
2880 call_key.call_id=hdr->call_id;
2881 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2883 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2884 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2885 *new_matched_key = matched_key;
2886 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2888 if(call_value->rep_frame==0){
2889 call_value->rep_frame=pinfo->fd->num;
2898 /* handoff this call */
2900 di->call_id = hdr->call_id;
2901 di->smb_fid = get_smb_fid(pinfo->private_data);
2902 di->request = FALSE;
2903 di->call_data = value;
2905 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
2906 if(value->req_frame!=0){
2908 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
2909 tvb, 0, 0, value->req_frame);
2910 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
2911 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
2913 ns.nsecs+=1000000000;
2916 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
2919 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
2920 hdr, di, &auth_info, alloc_hint,
2923 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
2928 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2929 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2931 dcerpc_call_value *value = NULL;
2932 conversation_t *conv;
2936 dcerpc_auth_info auth_info;
2938 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2939 hf_dcerpc_cn_alloc_hint, &alloc_hint);
2941 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2942 hf_dcerpc_cn_ctx_id, &ctx_id);
2944 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2945 hf_dcerpc_cn_cancel_count, NULL);
2949 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2950 hf_dcerpc_cn_status, &status);
2952 if (check_col (pinfo->cinfo, COL_INFO)) {
2953 col_append_fstr (pinfo->cinfo, COL_INFO,
2954 " ctx_id: %u status: %s", ctx_id,
2955 val_to_str(status, reject_status_vals,
2956 "Unknown (0x%08x)"));
2963 * XXX - what if this was set when the connection was set up,
2964 * and we just have a security context?
2966 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
2968 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
2969 pinfo->srcport, pinfo->destport, 0);
2971 /* no point in creating one here, really */
2973 dcerpc_matched_key matched_key, *new_matched_key;
2975 /* !!! we can NOT check flags.visited here since this will interact
2976 badly with when SMB handles (i.e. calls the subdissector)
2977 and desegmented pdu's .
2978 Instead we check if this pdu is already in the matched table or not
2980 matched_key.frame = pinfo->fd->num;
2981 matched_key.call_id = hdr->call_id;
2982 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
2984 dcerpc_call_key call_key;
2985 dcerpc_call_value *call_value;
2988 call_key.call_id=hdr->call_id;
2989 call_key.smb_fid=get_smb_fid(pinfo->private_data);
2991 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
2992 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
2993 *new_matched_key = matched_key;
2994 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
2996 if(call_value->rep_frame==0){
2997 call_value->rep_frame=pinfo->fd->num;
3004 int length, reported_length, stub_length;
3008 /* handoff this call */
3010 di->call_id = hdr->call_id;
3011 di->smb_fid = get_smb_fid(pinfo->private_data);
3012 di->request = FALSE;
3013 di->call_data = value;
3015 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3016 if(value->req_frame!=0){
3018 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3019 tvb, 0, 0, value->req_frame);
3020 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3021 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3023 ns.nsecs+=1000000000;
3026 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3029 length = tvb_length_remaining(tvb, offset);
3030 reported_length = tvb_reported_length_remaining(tvb, offset);
3031 stub_length = hdr->frag_len - offset - auth_info.auth_size;
3032 if (length > stub_length)
3033 length = stub_length;
3034 if (reported_length > stub_length)
3035 reported_length = stub_length;
3037 /* If we don't have reassembly enabled, or this packet contains
3038 the entire PDU, or if we don't have all the data in this
3039 fragment, just call the handoff directly if this is the
3040 first fragment or the PDU isn't fragmented. */
3041 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3042 !tvb_bytes_exist(tvb, offset, stub_length) ){
3043 if(hdr->flags&PFC_FIRST_FRAG){
3044 /* First fragment, possibly the only fragment */
3046 * XXX - should there be a third routine for each
3047 * function in an RPC subdissector, to handle
3048 * fault responses? The DCE RPC 1.1 spec says
3049 * three's "stub data" here, which I infer means
3050 * that it's protocol-specific and call-specific.
3052 * It should probably get passed the status code
3053 * as well, as that might be protocol-specific.
3056 if (stub_length > 0) {
3057 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3058 "Fault stub data (%d byte%s)",
3060 plurality(stub_length, "", "s"));
3064 /* PDU is fragmented and this isn't the first fragment */
3065 if (check_col(pinfo->cinfo, COL_INFO)) {
3066 col_append_fstr(pinfo->cinfo, COL_INFO,
3067 " [DCE/RPC fragment]");
3070 if (stub_length > 0) {
3071 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3072 "Fragment data (%d byte%s)",
3074 plurality(stub_length, "", "s"));
3079 /* Reassembly is enabled, the PDU is fragmented, and
3080 we have all the data in the fragment; the first two
3081 of those mean we should attempt reassembly, and the
3082 third means we can attempt reassembly. */
3085 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3086 "Fragment data (%d byte%s)",
3088 plurality(stub_length, "", "s"));
3091 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
3092 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3093 fragment_add(tvb, offset, pinfo, value->rep_frame,
3094 dcerpc_co_reassemble_table,
3098 fragment_set_tot_len(pinfo, value->rep_frame,
3099 dcerpc_co_reassemble_table, alloc_hint);
3101 if (check_col(pinfo->cinfo, COL_INFO)) {
3102 col_append_fstr(pinfo->cinfo, COL_INFO,
3103 " [DCE/RPC fragment]");
3105 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
3106 if( value->rep_frame ){
3107 fragment_data *fd_head;
3110 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3111 dcerpc_co_reassemble_table);
3112 fd_head = fragment_add(tvb, offset, pinfo,
3114 dcerpc_co_reassemble_table,
3120 /* We completed reassembly */
3123 next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen, fd_head->datalen);
3124 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3125 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3126 show_fragment_tree(fd_head, &dcerpc_frag_items,
3127 dcerpc_tree, pinfo, next_tvb);
3130 * XXX - should there be a third routine for each
3131 * function in an RPC subdissector, to handle
3132 * fault responses? The DCE RPC 1.1 spec says
3133 * three's "stub data" here, which I infer means
3134 * that it's protocol-specific and call-specific.
3136 * It should probably get passed the status code
3137 * as well, as that might be protocol-specific.
3141 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3142 "Fault stub data (%d byte%s)",
3144 plurality(stub_length, "", "s"));
3148 /* Reassembly not complete - some fragments
3150 if (check_col(pinfo->cinfo, COL_INFO)) {
3151 col_append_fstr(pinfo->cinfo, COL_INFO,
3152 " [DCE/RPC fragment]");
3156 } else { /* MIDDLE fragment(s) */
3157 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3159 tot_len = fragment_get_tot_len(pinfo, value->rep_frame,
3160 dcerpc_co_reassemble_table);
3161 fragment_add(tvb, offset, pinfo, value->rep_frame,
3162 dcerpc_co_reassemble_table,
3167 if (check_col(pinfo->cinfo, COL_INFO)) {
3168 col_append_fstr(pinfo->cinfo, COL_INFO,
3169 " [DCE/RPC fragment]");
3178 * DCERPC dissector for connection oriented calls
3181 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3182 proto_tree *tree, gboolean can_desegment, int *pkt_len)
3184 static char nulls[4] = { 0 };
3187 proto_item *ti = NULL;
3188 proto_item *tf = NULL;
3189 proto_tree *dcerpc_tree = NULL;
3190 proto_tree *cn_flags_tree = NULL;
3191 proto_tree *drep_tree = NULL;
3192 e_dce_cn_common_hdr_t hdr;
3193 dcerpc_auth_info auth_info;
3196 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3197 * data for some reason.
3199 * XXX - if that's always the case, the right way to do this would
3200 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3201 * the 4 bytes of null padding, and make that the dissector
3202 * used for "netbios".
3204 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3214 * Check if this looks like a C/O DCERPC call
3216 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3217 return FALSE; /* not enough information to check */
3219 start_offset = offset;
3220 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3221 if (hdr.rpc_ver != 5)
3223 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3224 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3226 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3230 hdr.flags = tvb_get_guint8 (tvb, offset++);
3231 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3232 offset += sizeof (hdr.drep);
3234 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3236 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3238 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3241 if (can_desegment && pinfo->can_desegment
3242 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3243 pinfo->desegment_offset = start_offset;
3244 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3245 *pkt_len = 0; /* desegmentation required */
3249 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3250 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3251 if (check_col (pinfo->cinfo, COL_INFO))
3252 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3253 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3256 offset = start_offset;
3257 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3259 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3261 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset++, 1, hdr.rpc_ver);
3262 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset++, 1, hdr.rpc_ver_minor);
3263 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset++, 1, hdr.ptype);
3264 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3265 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3266 if (cn_flags_tree) {
3267 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3268 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3269 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3270 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3271 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3272 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3273 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3274 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3278 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3279 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3281 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3282 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3283 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3285 offset += sizeof (hdr.drep);
3287 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
3290 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
3293 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
3298 * None of the stuff done above should throw an exception, because
3299 * we would have rejected this as "not DCE RPC" if we didn't have all
3300 * of it. (XXX - perhaps we should request reassembly if we have
3301 * enough of the header to consider it DCE RPC but not enough to
3302 * get the fragment length; in that case the stuff still wouldn't
3303 * throw an exception.)
3305 * The rest of the stuff might, so return the PDU length to our caller.
3306 * XXX - should we construct a tvbuff containing only the PDU and
3307 * use that? Or should we have separate "is this a DCE RPC PDU",
3308 * "how long is it", and "dissect it" routines - which might let us
3309 * do most of the work in "tcp_dissect_pdus()"?
3311 if (pkt_len != NULL)
3312 *pkt_len = hdr.frag_len + padding;
3315 * Packet type specific stuff is next.
3317 switch (hdr.ptype) {
3320 dissect_dcerpc_cn_bind (tvb, offset, pinfo, dcerpc_tree, &hdr);
3325 dissect_dcerpc_cn_bind_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
3330 * Nothing after the common header other than credentials.
3332 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
3337 dissect_dcerpc_cn_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3341 dissect_dcerpc_cn_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
3345 dissect_dcerpc_cn_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
3349 dissect_dcerpc_cn_bind_nak (tvb, offset, pinfo, dcerpc_tree, &hdr);
3355 * Nothing after the common header other than an authentication
3358 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
3364 * Nothing after the common header, not even an authentication
3370 /* might as well dissect the auth info */
3371 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
3379 * DCERPC dissector for connection oriented calls over packet-oriented
3383 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3386 * Only one PDU per transport packet, and only one transport
3389 if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
3391 * It wasn't a DCERPC PDU.
3403 * DCERPC dissector for connection oriented calls over byte-stream
3407 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3409 volatile int offset = 0;
3411 volatile gboolean is_dcerpc_pdu;
3412 volatile gboolean ret = FALSE;
3415 * There may be multiple PDUs per transport packet; keep
3418 while (tvb_reported_length_remaining(tvb, offset) != 0) {
3420 * Catch ReportedBoundsError, so that even if the stub data is bad,
3421 * we don't abort the full DCE RPC dissection - there might be more
3422 * than one DCE RPC PDU in the data being dissected.
3424 * If we get BoundsError, it means the frame was cut short by a
3425 * snapshot length, so there's nothing more to dissect; just
3426 * re-throw that exception.
3428 is_dcerpc_pdu = FALSE;
3430 is_dcerpc_pdu = dissect_dcerpc_cn (tvb, offset, pinfo, tree,
3431 dcerpc_cn_desegment, &pdu_len);
3432 } CATCH(BoundsError) {
3434 } CATCH(ReportedBoundsError) {
3435 show_reported_bounds_error(tvb, pinfo, tree);
3438 if (!is_dcerpc_pdu) {
3446 * Well, we've seen at least one DCERPC PDU.
3452 * Desegmentation required - bail now.
3458 * Step to the next PDU.
3466 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
3467 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
3469 proto_item *ti = NULL;
3470 proto_tree *auth_tree = NULL;
3471 guint8 protection_level;
3474 * Initially set "*auth_level_p" to -1 to indicate that we haven't
3475 * yet seen any authentication level information.
3477 if (auth_level_p != NULL)
3481 * The authentication information is at the *end* of the PDU; in
3482 * request and response PDUs, the request and response stub data
3485 * If the full packet is here, and there's data past the end of the
3486 * packet body, then dissect the auth info.
3488 offset += hdr->frag_len;
3489 if (tvb_length_remaining(tvb, offset) > 0) {
3490 switch (hdr->auth_proto) {
3492 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
3493 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
3494 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
3495 protection_level = tvb_get_guint8 (tvb, offset);
3496 if (auth_level_p != NULL)
3497 *auth_level_p = protection_level;
3498 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
3500 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
3502 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
3503 offset += 6; /* 6 bytes of padding */
3505 offset += 2; /* 6 bytes of padding */
3506 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
3511 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
3518 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3519 proto_tree *dcerpc_tree,
3520 e_dce_dg_common_hdr_t *hdr)
3524 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3525 hdr->drep, hf_dcerpc_dg_cancel_vers,
3531 /* The only version we know about */
3532 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3533 hdr->drep, hf_dcerpc_dg_cancel_id,
3535 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3536 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3543 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
3544 proto_tree *dcerpc_tree,
3545 e_dce_dg_common_hdr_t *hdr)
3549 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3550 hdr->drep, hf_dcerpc_dg_cancel_vers,
3556 /* The only version we know about */
3557 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3558 hdr->drep, hf_dcerpc_dg_cancel_id,
3560 /* XXX - are NDR booleans 32 bits? */
3561 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3562 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
3569 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
3570 proto_tree *dcerpc_tree,
3571 e_dce_dg_common_hdr_t *hdr)
3578 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
3579 hdr->drep, hf_dcerpc_dg_fack_vers,
3586 case 0: /* The only version documented in the DCE RPC 1.1 spec */
3587 case 1: /* This appears to be the same */
3588 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3589 hdr->drep, hf_dcerpc_dg_fack_window_size,
3591 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3592 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
3594 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3595 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
3597 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3598 hdr->drep, hf_dcerpc_dg_fack_serial_num,
3600 if (check_col (pinfo->cinfo, COL_INFO)) {
3601 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
3604 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
3605 hdr->drep, hf_dcerpc_dg_fack_selack_len,
3607 for (i = 0; i < selack_len; i++) {
3608 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3609 hdr->drep, hf_dcerpc_dg_fack_selack,
3618 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
3619 proto_tree *dcerpc_tree,
3620 e_dce_dg_common_hdr_t *hdr)
3624 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
3625 hdr->drep, hf_dcerpc_dg_status,
3628 if (check_col (pinfo->cinfo, COL_INFO)) {
3629 col_append_fstr (pinfo->cinfo, COL_INFO,
3631 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3636 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
3637 proto_tree *dcerpc_tree, proto_tree *tree,
3638 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
3640 int length, reported_length, stub_length;
3641 gboolean save_fragmented;
3642 fragment_data *fd_head;
3645 if (check_col (pinfo->cinfo, COL_INFO))
3646 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u", di->call_data->opnum );
3648 length = tvb_length_remaining (tvb, offset);
3649 reported_length = tvb_reported_length_remaining (tvb, offset);
3650 stub_length = hdr->frag_len;
3651 if (length > stub_length)
3652 length = stub_length;
3653 if (reported_length > stub_length)
3654 reported_length = stub_length;
3656 save_fragmented = pinfo->fragmented;
3658 /* If we don't have reassembly enabled, or this packet contains
3659 the entire PDU, or if this is a short frame (or a frame
3660 not reassembled at a lower layer) that doesn't include all
3661 the data in the fragment, just call the handoff directly if
3662 this is the first fragment or the PDU isn't fragmented. */
3663 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
3664 !tvb_bytes_exist(tvb, offset, stub_length) ){
3665 if(hdr->frag_num == 0) {
3668 if (check_col (pinfo->cinfo, COL_INFO))
3669 col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
3670 di->call_data->uuid.Data1, di->call_data->uuid.Data2, di->call_data->uuid.Data3, di->call_data->uuid.Data4[0],
3671 di->call_data->uuid.Data4[1], di->call_data->uuid.Data4[2], di->call_data->uuid.Data4[3],
3672 di->call_data->uuid.Data4[4], di->call_data->uuid.Data4[5], di->call_data->uuid.Data4[6],
3673 di->call_data->uuid.Data4[7], di->call_data->ver);
3676 /* First fragment, possibly the only fragment */
3679 * XXX - authentication info?
3681 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
3682 next_tvb = tvb_new_subset (tvb, offset, length,
3684 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3685 next_tvb, hdr->drep, di, NULL);
3687 /* PDU is fragmented and this isn't the first fragment */
3688 if (check_col(pinfo->cinfo, COL_INFO)) {
3689 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3693 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3694 "Fragment data (%d byte%s)",
3696 plurality(stub_length, "", "s"));
3701 /* Reassembly is enabled, the PDU is fragmented, and
3702 we have all the data in the fragment; the first two
3703 of those mean we should attempt reassembly, and the
3704 third means we can attempt reassembly. */
3707 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3708 "Fragment data (%d byte%s)", stub_length,
3709 plurality(stub_length, "", "s"));
3713 fd_head = fragment_add_seq(tvb, offset, pinfo,
3714 hdr->seqnum, dcerpc_cl_reassemble_table,
3715 hdr->frag_num, stub_length,
3716 !(hdr->flags1 & PFCL1_LASTFRAG));
3717 if (fd_head != NULL) {
3718 /* We completed reassembly */
3719 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3720 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3721 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3722 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
3723 dcerpc_tree, pinfo, next_tvb);
3726 * XXX - authentication info?
3728 pinfo->fragmented = FALSE;
3729 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3730 next_tvb, hdr->drep, di, NULL);
3732 /* Reassembly isn't completed yet */
3733 if (check_col(pinfo->cinfo, COL_INFO)) {
3734 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
3738 pinfo->fragmented = save_fragmented;
3742 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
3743 proto_tree *dcerpc_tree, proto_tree *tree,
3744 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3747 dcerpc_call_value *value, v;
3748 dcerpc_matched_key matched_key, *new_matched_key;
3751 if(!(pinfo->fd->flags.visited)){
3752 dcerpc_call_value *call_value;
3753 dcerpc_call_key *call_key;
3755 call_key=g_mem_chunk_alloc (dcerpc_call_key_chunk);
3756 call_key->conv=conv;
3757 call_key->call_id=hdr->seqnum;
3758 call_key->smb_fid=get_smb_fid(pinfo->private_data);
3760 call_value=g_mem_chunk_alloc (dcerpc_call_value_chunk);
3761 call_value->uuid = hdr->if_id;
3762 call_value->ver = hdr->if_ver;
3763 call_value->opnum = hdr->opnum;
3764 call_value->req_frame=pinfo->fd->num;
3765 call_value->req_time.secs=pinfo->fd->abs_secs;
3766 call_value->req_time.nsecs=pinfo->fd->abs_usecs*1000;
3767 call_value->rep_frame=0;
3768 call_value->max_ptr=0;
3769 call_value->private_data = NULL;
3770 g_hash_table_insert (dcerpc_calls, call_key, call_value);
3772 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3773 new_matched_key->frame = pinfo->fd->num;
3774 new_matched_key->call_id = hdr->seqnum;
3775 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3778 matched_key.frame = pinfo->fd->num;
3779 matched_key.call_id = hdr->seqnum;
3780 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3782 v.uuid = hdr->if_id;
3783 v.ver = hdr->if_ver;
3784 v.opnum = hdr->opnum;
3785 v.req_frame = pinfo->fd->num;
3788 v.private_data=NULL;
3793 di->call_id = hdr->seqnum;
3796 di->call_data = value;
3798 if(value->rep_frame!=0){
3799 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3800 tvb, 0, 0, value->rep_frame);
3802 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
3806 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
3807 proto_tree *dcerpc_tree, proto_tree *tree,
3808 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
3811 dcerpc_call_value *value, v;
3812 dcerpc_matched_key matched_key, *new_matched_key;
3815 if(!(pinfo->fd->flags.visited)){
3816 dcerpc_call_value *call_value;
3817 dcerpc_call_key call_key;
3820 call_key.call_id=hdr->seqnum;
3821 call_key.smb_fid=get_smb_fid(pinfo->private_data);
3823 if((call_value=g_hash_table_lookup(dcerpc_calls, &call_key))){
3824 new_matched_key = g_mem_chunk_alloc(dcerpc_matched_key_chunk);
3825 new_matched_key->frame = pinfo->fd->num;
3826 new_matched_key->call_id = hdr->seqnum;
3827 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3828 if(call_value->rep_frame==0){
3829 call_value->rep_frame=pinfo->fd->num;
3834 matched_key.frame = pinfo->fd->num;
3835 matched_key.call_id = hdr->seqnum;
3836 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3838 v.uuid = hdr->if_id;
3839 v.ver = hdr->if_ver;
3840 v.opnum = hdr->opnum;
3842 v.rep_frame=pinfo->fd->num;
3843 v.private_data=NULL;
3850 di->request = FALSE;
3851 di->call_data = value;
3853 if(value->req_frame!=0){
3855 proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3856 tvb, 0, 0, value->req_frame);
3857 ns.secs= pinfo->fd->abs_secs-value->req_time.secs;
3858 ns.nsecs=pinfo->fd->abs_usecs*1000-value->req_time.nsecs;
3860 ns.nsecs+=1000000000;
3863 proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &ns);
3865 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
3869 * DCERPC dissector for connectionless calls
3872 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3874 proto_item *ti = NULL;
3875 proto_item *tf = NULL;
3876 proto_tree *dcerpc_tree = NULL;
3877 proto_tree *dg_flags1_tree = NULL;
3878 proto_tree *dg_flags2_tree = NULL;
3879 proto_tree *drep_tree = NULL;
3880 e_dce_dg_common_hdr_t hdr;
3882 conversation_t *conv;
3884 char uuid_str[DCERPC_UUID_STR_LEN];
3888 * Check if this looks like a CL DCERPC call. All dg packets
3889 * have an 80 byte header on them. Which starts with
3890 * version (4), pkt_type.
3892 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
3895 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3896 if (hdr.rpc_ver != 4)
3898 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3902 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3903 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3904 if (check_col (pinfo->cinfo, COL_INFO))
3905 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
3907 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
3908 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
3909 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3910 offset += sizeof (hdr.drep);
3911 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
3912 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
3914 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
3916 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
3918 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3920 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3922 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3924 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3926 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3928 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3930 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3932 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3934 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
3935 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
3938 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
3940 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
3946 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3950 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3954 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
3955 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
3956 if (dg_flags1_tree) {
3957 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
3958 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
3959 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
3960 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
3961 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
3962 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
3963 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
3964 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
3970 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
3971 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
3972 if (dg_flags2_tree) {
3973 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
3974 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
3975 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
3976 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
3977 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
3978 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
3979 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
3980 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
3986 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
3987 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3989 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3990 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3991 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
3994 offset += sizeof (hdr.drep);
3997 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
4001 /* XXX - use "dissect_ndr_uuid_t()"? */
4002 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4003 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4004 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
4005 hdr.obj_id.Data4[0],
4006 hdr.obj_id.Data4[1],
4007 hdr.obj_id.Data4[2],
4008 hdr.obj_id.Data4[3],
4009 hdr.obj_id.Data4[4],
4010 hdr.obj_id.Data4[5],
4011 hdr.obj_id.Data4[6],
4012 hdr.obj_id.Data4[7]);
4013 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4014 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4015 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
4016 offset, 16, uuid_str, "Object UUID: %s", uuid_str);
4021 /* XXX - use "dissect_ndr_uuid_t()"? */
4022 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4023 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4024 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
4032 hdr.if_id.Data4[7]);
4033 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4034 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4035 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4036 offset, 16, uuid_str, "Interface: %s", uuid_str);
4041 /* XXX - use "dissect_ndr_uuid_t()"? */
4042 uuid_str_len = snprintf(uuid_str, DCERPC_UUID_STR_LEN,
4043 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
4044 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
4045 hdr.act_id.Data4[0],
4046 hdr.act_id.Data4[1],
4047 hdr.act_id.Data4[2],
4048 hdr.act_id.Data4[3],
4049 hdr.act_id.Data4[4],
4050 hdr.act_id.Data4[5],
4051 hdr.act_id.Data4[6],
4052 hdr.act_id.Data4[7]);
4053 if (uuid_str_len >= DCERPC_UUID_STR_LEN)
4054 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
4055 proto_tree_add_string_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
4056 offset, 16, uuid_str, "Activity: %s", uuid_str);
4061 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_server_boot, tvb, offset, 4, hdr.server_boot);
4065 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
4069 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
4070 if (check_col (pinfo->cinfo, COL_INFO)) {
4071 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq_num: %u", hdr.seqnum);
4076 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
4080 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
4084 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
4088 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
4092 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
4093 if (check_col (pinfo->cinfo, COL_INFO)) {
4094 if (hdr.flags1 & PFCL1_FRAG) {
4095 /* Fragmented - put the fragment number into the Info column */
4096 col_append_fstr (pinfo->cinfo, COL_INFO, " frag_num: %u",
4103 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
4107 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
4108 if (check_col (pinfo->cinfo, COL_INFO)) {
4109 if (hdr.flags1 & PFCL1_FRAG) {
4110 /* Fragmented - put the serial number into the Info column */
4111 col_append_fstr (pinfo->cinfo, COL_INFO, " serial_num: %u",
4112 (hdr.serial_hi << 8) | hdr.serial_lo);
4119 * XXX - for Kerberos, we get a protection level; if it's
4120 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
4123 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
4128 * keeping track of the conversation shouldn't really be necessary
4129 * for connectionless packets, because everything we need to know
4130 * to dissect is in the header for each packet. Unfortunately,
4131 * Microsoft's implementation is buggy and often puts the
4132 * completely wrong if_id in the header. go figure. So, keep
4133 * track of the seqnum and use that if possible. Note: that's not
4134 * completely correct. It should really be done based on both the
4135 * activity_id and seqnum. I haven't seen anywhere that it would
4136 * make a difference, but for future reference...
4138 conv = find_conversation (&pinfo->src, &pinfo->dst, pinfo->ptype,
4139 pinfo->srcport, pinfo->destport, 0);
4141 conv = conversation_new (&pinfo->src, &pinfo->dst, pinfo->ptype,
4142 pinfo->srcport, pinfo->destport, 0);
4146 * Packet type specific stuff is next.
4149 switch (hdr.ptype) {
4151 case PDU_CANCEL_ACK:
4152 /* Body is optional */
4153 /* XXX - we assume "frag_len" is the length of the body */
4154 if (hdr.frag_len != 0)
4155 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4160 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
4161 * but in at least one capture none of the Cl_cancel PDUs had a
4164 /* XXX - we assume "frag_len" is the length of the body */
4165 if (hdr.frag_len != 0)
4166 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
4170 /* Body is optional; if present, it's the same as PDU_FACK */
4171 /* XXX - we assume "frag_len" is the length of the body */
4172 if (hdr.frag_len != 0)
4173 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4177 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
4182 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
4186 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4190 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
4193 /* these requests have no body */
4205 dcerpc_init_protocol (void)
4207 /* structures and data for BIND */
4209 g_hash_table_destroy (dcerpc_binds);
4211 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
4213 if (dcerpc_bind_key_chunk){
4214 g_mem_chunk_destroy (dcerpc_bind_key_chunk);
4216 dcerpc_bind_key_chunk = g_mem_chunk_new ("dcerpc_bind_key_chunk",
4217 sizeof (dcerpc_bind_key),
4218 200 * sizeof (dcerpc_bind_key),
4220 if (dcerpc_bind_value_chunk){
4221 g_mem_chunk_destroy (dcerpc_bind_value_chunk);
4223 dcerpc_bind_value_chunk = g_mem_chunk_new ("dcerpc_bind_value_chunk",
4224 sizeof (dcerpc_bind_value),
4225 200 * sizeof (dcerpc_bind_value),
4227 /* structures and data for CALL */
4229 g_hash_table_destroy (dcerpc_calls);
4231 dcerpc_calls = g_hash_table_new (dcerpc_call_hash, dcerpc_call_equal);
4232 if (dcerpc_call_key_chunk){
4233 g_mem_chunk_destroy (dcerpc_call_key_chunk);
4235 dcerpc_call_key_chunk = g_mem_chunk_new ("dcerpc_call_key_chunk",
4236 sizeof (dcerpc_call_key),
4237 200 * sizeof (dcerpc_call_key),
4239 if (dcerpc_call_value_chunk){
4240 g_mem_chunk_destroy (dcerpc_call_value_chunk);
4242 dcerpc_call_value_chunk = g_mem_chunk_new ("dcerpc_call_value_chunk",
4243 sizeof (dcerpc_call_value),
4244 200 * sizeof (dcerpc_call_value),
4247 /* structure and data for MATCHED */
4248 if (dcerpc_matched){
4249 g_hash_table_destroy (dcerpc_matched);
4251 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
4252 if (dcerpc_matched_key_chunk){
4253 g_mem_chunk_destroy (dcerpc_matched_key_chunk);
4255 dcerpc_matched_key_chunk = g_mem_chunk_new ("dcerpc_matched_key_chunk",
4256 sizeof (dcerpc_matched_key),
4257 200 * sizeof (dcerpc_matched_key),
4262 proto_register_dcerpc (void)
4264 static hf_register_info hf[] = {
4265 { &hf_dcerpc_request_in,
4266 { "Request in", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
4267 NULL, 0, "This packet is a response to the packet in this frame", HFILL }},
4268 { &hf_dcerpc_response_in,
4269 { "Response in", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
4270 NULL, 0, "The response to this packet is in this packet", HFILL }},
4271 { &hf_dcerpc_referent_id,
4272 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
4273 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
4275 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4276 { &hf_dcerpc_ver_minor,
4277 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4278 { &hf_dcerpc_packet_type,
4279 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
4280 { &hf_dcerpc_cn_flags,
4281 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4282 { &hf_dcerpc_cn_flags_first_frag,
4283 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
4284 { &hf_dcerpc_cn_flags_last_frag,
4285 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
4286 { &hf_dcerpc_cn_flags_cancel_pending,
4287 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
4288 { &hf_dcerpc_cn_flags_reserved,
4289 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
4290 { &hf_dcerpc_cn_flags_mpx,
4291 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
4292 { &hf_dcerpc_cn_flags_dne,
4293 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
4294 { &hf_dcerpc_cn_flags_maybe,
4295 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
4296 { &hf_dcerpc_cn_flags_object,
4297 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
4299 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
4300 { &hf_dcerpc_drep_byteorder,
4301 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
4302 { &hf_dcerpc_drep_character,
4303 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
4304 { &hf_dcerpc_drep_fp,
4305 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
4306 { &hf_dcerpc_cn_frag_len,
4307 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4308 { &hf_dcerpc_cn_auth_len,
4309 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4310 { &hf_dcerpc_cn_call_id,
4311 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4312 { &hf_dcerpc_cn_max_xmit,
4313 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4314 { &hf_dcerpc_cn_max_recv,
4315 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4316 { &hf_dcerpc_cn_assoc_group,
4317 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4318 { &hf_dcerpc_cn_num_ctx_items,
4319 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4320 { &hf_dcerpc_cn_ctx_id,
4321 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4322 { &hf_dcerpc_cn_num_trans_items,
4323 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4324 { &hf_dcerpc_cn_bind_if_id,
4325 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4326 { &hf_dcerpc_cn_bind_if_ver,
4327 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4328 { &hf_dcerpc_cn_bind_if_ver_minor,
4329 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4330 { &hf_dcerpc_cn_bind_trans_id,
4331 { "Transfer Syntax", "dcerpc.cn_bind_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4332 { &hf_dcerpc_cn_bind_trans_ver,
4333 { "Syntax ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4334 { &hf_dcerpc_cn_alloc_hint,
4335 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4336 { &hf_dcerpc_cn_sec_addr_len,
4337 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4338 { &hf_dcerpc_cn_sec_addr,
4339 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
4340 { &hf_dcerpc_cn_num_results,
4341 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4342 { &hf_dcerpc_cn_ack_result,
4343 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
4344 { &hf_dcerpc_cn_ack_reason,
4345 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
4346 { &hf_dcerpc_cn_ack_trans_id,
4347 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4348 { &hf_dcerpc_cn_ack_trans_ver,
4349 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4350 { &hf_dcerpc_cn_reject_reason,
4351 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
4352 { &hf_dcerpc_cn_num_protocols,
4353 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4354 { &hf_dcerpc_cn_protocol_ver_major,
4355 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4356 { &hf_dcerpc_cn_protocol_ver_minor,
4357 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4358 { &hf_dcerpc_cn_cancel_count,
4359 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4360 { &hf_dcerpc_cn_status,
4361 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4362 { &hf_dcerpc_auth_type,
4363 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4364 { &hf_dcerpc_auth_level,
4365 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
4366 { &hf_dcerpc_auth_pad_len,
4367 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4368 { &hf_dcerpc_auth_rsrvd,
4369 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4370 { &hf_dcerpc_auth_ctx_id,
4371 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4372 { &hf_dcerpc_dg_flags1,
4373 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4374 { &hf_dcerpc_dg_flags1_rsrvd_01,
4375 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
4376 { &hf_dcerpc_dg_flags1_last_frag,
4377 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
4378 { &hf_dcerpc_dg_flags1_frag,
4379 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
4380 { &hf_dcerpc_dg_flags1_nofack,
4381 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
4382 { &hf_dcerpc_dg_flags1_maybe,
4383 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
4384 { &hf_dcerpc_dg_flags1_idempotent,
4385 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
4386 { &hf_dcerpc_dg_flags1_broadcast,
4387 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
4388 { &hf_dcerpc_dg_flags1_rsrvd_80,
4389 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
4390 { &hf_dcerpc_dg_flags2,
4391 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4392 { &hf_dcerpc_dg_flags2_rsrvd_01,
4393 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
4394 { &hf_dcerpc_dg_flags2_cancel_pending,
4395 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
4396 { &hf_dcerpc_dg_flags2_rsrvd_04,
4397 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
4398 { &hf_dcerpc_dg_flags2_rsrvd_08,
4399 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
4400 { &hf_dcerpc_dg_flags2_rsrvd_10,
4401 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
4402 { &hf_dcerpc_dg_flags2_rsrvd_20,
4403 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
4404 { &hf_dcerpc_dg_flags2_rsrvd_40,
4405 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
4406 { &hf_dcerpc_dg_flags2_rsrvd_80,
4407 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
4408 { &hf_dcerpc_dg_serial_lo,
4409 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4410 { &hf_dcerpc_dg_serial_hi,
4411 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
4412 { &hf_dcerpc_dg_ahint,
4413 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4414 { &hf_dcerpc_dg_ihint,
4415 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
4416 { &hf_dcerpc_dg_frag_len,
4417 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4418 { &hf_dcerpc_dg_frag_num,
4419 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4420 { &hf_dcerpc_dg_auth_proto,
4421 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
4422 { &hf_dcerpc_dg_seqnum,
4423 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4424 { &hf_dcerpc_dg_server_boot,
4425 { "Server boot time", "dcerpc.dg_server_boot", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4426 { &hf_dcerpc_dg_if_ver,
4427 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4428 { &hf_dcerpc_krb5_av_prot_level,
4429 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
4430 { &hf_dcerpc_krb5_av_key_vers_num,
4431 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4432 { &hf_dcerpc_krb5_av_key_auth_verifier,
4433 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
4434 { &hf_dcerpc_obj_id,
4435 { "Object", "dcerpc.obj_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4436 { &hf_dcerpc_dg_if_id,
4437 { "Interface", "dcerpc.dg_if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4438 { &hf_dcerpc_dg_act_id,
4439 { "Activity", "dcerpc.dg_act_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
4441 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4443 { &hf_dcerpc_dg_cancel_vers,
4444 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4446 { &hf_dcerpc_dg_cancel_id,
4447 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4449 { &hf_dcerpc_dg_server_accepting_cancels,
4450 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
4452 { &hf_dcerpc_dg_fack_vers,
4453 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
4455 { &hf_dcerpc_dg_fack_window_size,
4456 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4458 { &hf_dcerpc_dg_fack_max_tsdu,
4459 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4461 { &hf_dcerpc_dg_fack_max_frag_size,
4462 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
4464 { &hf_dcerpc_dg_fack_serial_num,
4465 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4467 { &hf_dcerpc_dg_fack_selack_len,
4468 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4470 { &hf_dcerpc_dg_fack_selack,
4471 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
4473 { &hf_dcerpc_dg_status,
4474 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
4476 { &hf_dcerpc_array_max_count,
4477 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
4479 { &hf_dcerpc_array_offset,
4480 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
4482 { &hf_dcerpc_array_actual_count,
4483 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
4485 { &hf_dcerpc_array_buffer,
4486 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
4489 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
4491 { &hf_dcerpc_fragments,
4492 { "DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
4493 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
4495 { &hf_dcerpc_fragment,
4496 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
4497 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
4499 { &hf_dcerpc_fragment_overlap,
4500 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
4502 { &hf_dcerpc_fragment_overlap_conflict,
4503 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
4505 { &hf_dcerpc_fragment_multiple_tails,
4506 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
4508 { &hf_dcerpc_fragment_too_long_fragment,
4509 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
4511 { &hf_dcerpc_fragment_error,
4512 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
4515 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0, "Time between Request and Reply for DCE-RPC calls", HFILL }},
4516 { &hf_dcerpc_reassembled_in,
4517 { "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 }},
4519 static gint *ett[] = {
4521 &ett_dcerpc_cn_flags,
4523 &ett_dcerpc_cn_iface,
4525 &ett_dcerpc_dg_flags1,
4526 &ett_dcerpc_dg_flags2,
4527 &ett_dcerpc_pointer_data,
4529 &ett_dcerpc_fragments,
4530 &ett_dcerpc_fragment,
4531 &ett_dcerpc_krb5_auth_verf,
4533 module_t *dcerpc_module;
4535 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
4536 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
4537 proto_register_subtree_array (ett, array_length (ett));
4538 register_init_routine (dcerpc_init_protocol);
4539 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
4540 prefs_register_bool_preference (dcerpc_module,
4542 "Desegment all DCE/RPC over TCP",
4543 "Whether the DCE/RPC dissector should desegment all DCE/RPC over TCP",
4544 &dcerpc_cn_desegment);
4545 prefs_register_bool_preference (dcerpc_module,
4546 "reassemble_dcerpc",
4547 "Reassemble DCE/RPC fragments",
4548 "Whether the DCE/RPC dissector should reassemble all fragmented PDUs",
4549 &dcerpc_reassemble);
4550 register_init_routine(dcerpc_reassemble_init);
4551 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
4552 dcerpc_tap=register_tap("dcerpc");
4556 proto_reg_handoff_dcerpc (void)
4558 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
4559 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
4560 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
4561 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_bs, proto_dcerpc);
4562 dcerpc_smb_init(proto_dcerpc);