2 * Routines for DCERPC packet disassembly
3 * Copyright 2001, Todd Sabin <tas@webspan.net>
4 * Copyright 2003, Tim Potter <tpot@samba.org>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
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.
27 /* The DCE RPC specification can be found at:
28 * http://www.opengroup.org/dce/
39 #include <epan/packet.h>
40 #include <epan/dissectors/packet-dcerpc.h>
41 #include <epan/conversation.h>
42 #include <epan/prefs.h>
43 #include <epan/reassemble.h>
45 #include <epan/emem.h>
46 #include <epan/dissectors/packet-frame.h>
47 #include <epan/dissectors/packet-dcerpc-nt.h>
48 #include <epan/expert.h>
49 #include <epan/strutil.h>
55 static int dcerpc_tap = -1;
58 static const value_string pckt_vals[] = {
59 { PDU_REQ, "Request"},
61 { PDU_RESP, "Response"},
62 { PDU_FAULT, "Fault"},
63 { PDU_WORKING, "Working"},
64 { PDU_NOCALL, "Nocall"},
65 { PDU_REJECT, "Reject"},
67 { PDU_CL_CANCEL, "Cl_cancel"},
69 { PDU_CANCEL_ACK, "Cancel_ack"},
71 { PDU_BIND_ACK, "Bind_ack"},
72 { PDU_BIND_NAK, "Bind_nak"},
73 { PDU_ALTER, "Alter_context"},
74 { PDU_ALTER_ACK, "Alter_context_resp"},
75 { PDU_AUTH3, "AUTH3"},
76 { PDU_SHUTDOWN, "Shutdown"},
77 { PDU_CO_CANCEL, "Co_cancel"},
78 { PDU_ORPHANED, "Orphaned"},
82 static const value_string drep_byteorder_vals[] = {
84 { 1, "Little-endian" },
88 static const value_string drep_character_vals[] = {
94 #define DCE_RPC_DREP_FP_IEEE 0
95 #define DCE_RPC_DREP_FP_VAX 1
96 #define DCE_RPC_DREP_FP_CRAY 2
97 #define DCE_RPC_DREP_FP_IBM 3
99 static const value_string drep_fp_vals[] = {
100 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
101 { DCE_RPC_DREP_FP_VAX, "VAX" },
102 { DCE_RPC_DREP_FP_CRAY, "Cray" },
103 { DCE_RPC_DREP_FP_IBM, "IBM" },
108 * Authentication services.
110 static const value_string authn_protocol_vals[] = {
111 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
112 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
113 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
114 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
115 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
116 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
117 { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
118 "Distributed Password Authentication SSP"},
119 { DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
120 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
121 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN,"NETLOGON Secure Channel" },
122 { DCE_C_RPC_AUTHN_PROTOCOL_MQ, "MSMQ SSP"},
129 static const value_string authn_level_vals[] = {
130 { DCE_C_AUTHN_LEVEL_NONE, "None" },
131 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
132 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
133 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
134 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
135 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
140 * Flag bits in first flag field in connectionless PDU header.
142 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
143 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
144 * fragment of a multi-PDU
146 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
147 a multi-PDU transmission */
148 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
149 * requested to send a `fack' PDU
150 * for the fragment */
151 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
153 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
155 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
157 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
160 * Flag bits in second flag field in connectionless PDU header.
162 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
163 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
164 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
165 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
166 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
167 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
168 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
169 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
172 * Flag bits in connection-oriented PDU header.
174 #define PFC_FIRST_FRAG 0x01 /* First fragment */
175 #define PFC_LAST_FRAG 0x02 /* Last fragment */
176 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
177 #define PFC_RESERVED_1 0x08
178 #define PFC_CONC_MPX 0x10 /* suports concurrent multiplexing
179 * of a single connection. */
180 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
181 * if true, guaranteed call did not
183 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
184 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
185 * was specified in the handle, and
186 * is present in the optional object
187 * field. If false, the object field
191 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
192 * it's not fragmented (i.e., this is both the first *and* last fragment),
193 * and FALSE otherwise.
195 #define PFC_NOT_FRAGMENTED(hdr) \
196 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG))==(PFC_FIRST_FRAG|PFC_LAST_FRAG))
199 * Presentation context negotiation result.
201 static const value_string p_cont_result_vals[] = {
203 { 1, "User rejection" },
204 { 2, "Provider rejection" },
209 * Presentation context negotiation rejection reasons.
211 static const value_string p_provider_reason_vals[] = {
212 { 0, "Reason not specified" },
213 { 1, "Abstract syntax not supported" },
214 { 2, "Proposed transfer syntaxes not supported" },
215 { 3, "Local limit exceeded" },
222 #define REASON_NOT_SPECIFIED 0
223 #define TEMPORARY_CONGESTION 1
224 #define LOCAL_LIMIT_EXCEEDED 2
225 #define CALLED_PADDR_UNKNOWN 3 /* not used */
226 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
227 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
228 #define USER_DATA_NOT_READABLE 6 /* not used */
229 #define NO_PSAP_AVAILABLE 7 /* not used */
230 #define AUTH_TYPE_NOT_RECOGNIZED 8
231 #define INVALID_CHECKSUM 9
233 static const value_string reject_reason_vals[] = {
234 { REASON_NOT_SPECIFIED, "Reason not specified" },
235 { TEMPORARY_CONGESTION, "Temporary congestion" },
236 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
237 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
238 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
239 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
240 { USER_DATA_NOT_READABLE, "User data not readable" },
241 { NO_PSAP_AVAILABLE, "No PSAP available" },
242 { AUTH_TYPE_NOT_RECOGNIZED, "Authentication type not recognized" },
243 { INVALID_CHECKSUM, "Invalid checksum" },
248 * Reject status codes.
250 static const value_string reject_status_vals[] = {
251 { 0, "Stub-defined exception" },
252 { 0x00000001, "nca_s_fault_other" },
253 { 0x00000005, "nca_s_fault_access_denied" },
254 { 0x000006f7, "nca_s_fault_ndr" },
255 { 0x000006d8, "nca_s_fault_cant_perform" },
256 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
257 { 0x1c000002, "nca_s_fault_addr_error" },
258 { 0x1c000003, "nca_s_fault_fp_div_zero" },
259 { 0x1c000004, "nca_s_fault_fp_underflow" },
260 { 0x1c000005, "nca_s_fault_fp_overflow" },
261 { 0x1c000006, "nca_s_fault_invalid_tag" },
262 { 0x1c000007, "nca_s_fault_invalid_bound" },
263 { 0x1c000008, "nca_rpc_version_mismatch" },
264 { 0x1c000009, "nca_unspec_reject" },
265 { 0x1c00000a, "nca_s_bad_actid" },
266 { 0x1c00000b, "nca_who_are_you_failed" },
267 { 0x1c00000c, "nca_manager_not_entered" },
268 { 0x1c00000d, "nca_s_fault_cancel" },
269 { 0x1c00000e, "nca_s_fault_ill_inst" },
270 { 0x1c00000f, "nca_s_fault_fp_error" },
271 { 0x1c000010, "nca_s_fault_int_overflow" },
272 { 0x1c000014, "nca_s_fault_pipe_empty" },
273 { 0x1c000015, "nca_s_fault_pipe_closed" },
274 { 0x1c000016, "nca_s_fault_pipe_order" },
275 { 0x1c000017, "nca_s_fault_pipe_discipline" },
276 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
277 { 0x1c000019, "nca_s_fault_pipe_memory" },
278 { 0x1c00001a, "nca_s_fault_context_mismatch" },
279 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
280 { 0x1c00001c, "nca_invalid_pres_context_id" },
281 { 0x1c00001d, "nca_unsupported_authn_level" },
282 { 0x1c00001f, "nca_invalid_checksum" },
283 { 0x1c000020, "nca_invalid_crc" },
284 { 0x1c000021, "ncs_s_fault_user_defined" },
285 { 0x1c000022, "nca_s_fault_tx_open_failed" },
286 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
287 { 0x1c000024, "nca_s_fault_object_not_found" },
288 { 0x1c000025, "nca_s_fault_no_client_stub" },
289 { 0x1c010002, "nca_op_rng_error" },
290 { 0x1c010003, "nca_unk_if"},
291 { 0x1c010006, "nca_wrong_boot_time" },
292 { 0x1c010009, "nca_s_you_crashed" },
293 { 0x1c01000b, "nca_proto_error" },
294 { 0x1c010013, "nca_out_args_too_big" },
295 { 0x1c010014, "nca_server_too_busy" },
296 { 0x1c010017, "nca_unsupported_type" },
297 /* MS Windows specific values
298 * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp
299 * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp
300 * and: http://www.megos.ch/support/doserrors.txt
302 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
303 * at least MS protocols (like DCOM) do it that way ... */
304 { 0x80004001, "E_NOTIMPL" },
305 { 0x80004003, "E_POINTER" },
306 { 0x80004004, "E_ABORT" },
307 { 0x8000FFFF, "E_UNEXPECTED" },
308 { 0x80010105, "RPC_E_SERVERFAULT" },
309 { 0x80010108, "RPC_E_DISCONNECTED" },
310 { 0x80010113, "RPC_E_INVALID_IPID" },
311 { 0x8001011F, "RPC_E_TIMEOUT" },
312 { 0x80020003, "DISP_E_MEMBERNOTFOUND" },
313 { 0x80020006, "DISP_E_UNKNOWNNAME" },
314 { 0x8002000E, "DISP_E_BADPARAMCOUNT" },
315 { 0x8004CB00, "CBA_E_MALFORMED" },
316 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
317 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
318 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
319 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
320 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
321 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
322 { 0x8004CB13, "CBA_E_QOSTYPENOTAPPLICABLE" },
323 { 0x8004CB18, "CBA_E_OUTOFPARTNERACCOS" },
324 { 0x8004CB1C, "CBA_E_FLAGUNSUPPORTED" },
325 { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" },
326 { 0x8004CB25, "CBA_E_MODECHANGE" },
327 { 0x8007000E, "E_OUTOFMEMORY" },
328 { 0x80070057, "E_INVALIDARG" },
329 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
330 { 0x80070776, "OR_INVALID_OXID" },
335 /* we need to keep track of what transport were used, ie what handle we came
336 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
338 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
339 #define DCE_TRANSPORT_UNKNOWN 0
340 #define DCE_CN_TRANSPORT_SMBPIPE 1
343 static int proto_dcerpc = -1;
346 static int hf_dcerpc_request_in = -1;
347 static int hf_dcerpc_time = -1;
348 static int hf_dcerpc_response_in = -1;
349 static int hf_dcerpc_ver = -1;
350 static int hf_dcerpc_ver_minor = -1;
351 static int hf_dcerpc_packet_type = -1;
352 static int hf_dcerpc_cn_flags = -1;
353 static int hf_dcerpc_cn_flags_first_frag = -1;
354 static int hf_dcerpc_cn_flags_last_frag = -1;
355 static int hf_dcerpc_cn_flags_cancel_pending = -1;
356 static int hf_dcerpc_cn_flags_reserved = -1;
357 static int hf_dcerpc_cn_flags_mpx = -1;
358 static int hf_dcerpc_cn_flags_dne = -1;
359 static int hf_dcerpc_cn_flags_maybe = -1;
360 static int hf_dcerpc_cn_flags_object = -1;
361 static int hf_dcerpc_drep = -1;
362 static int hf_dcerpc_drep_byteorder = -1;
363 static int hf_dcerpc_drep_character = -1;
364 static int hf_dcerpc_drep_fp = -1;
365 static int hf_dcerpc_cn_frag_len = -1;
366 static int hf_dcerpc_cn_auth_len = -1;
367 static int hf_dcerpc_cn_call_id = -1;
368 static int hf_dcerpc_cn_max_xmit = -1;
369 static int hf_dcerpc_cn_max_recv = -1;
370 static int hf_dcerpc_cn_assoc_group = -1;
371 static int hf_dcerpc_cn_num_ctx_items = -1;
372 static int hf_dcerpc_cn_ctx_item = -1;
373 static int hf_dcerpc_cn_ctx_id = -1;
374 static int hf_dcerpc_cn_num_trans_items = -1;
375 static int hf_dcerpc_cn_bind_abstract_syntax = -1;
376 static int hf_dcerpc_cn_bind_if_id = -1;
377 static int hf_dcerpc_cn_bind_if_ver = -1;
378 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
379 static int hf_dcerpc_cn_bind_trans_syntax = -1;
380 static int hf_dcerpc_cn_bind_trans_id = -1;
381 static int hf_dcerpc_cn_bind_trans_ver = -1;
382 static int hf_dcerpc_cn_alloc_hint = -1;
383 static int hf_dcerpc_cn_sec_addr_len = -1;
384 static int hf_dcerpc_cn_sec_addr = -1;
385 static int hf_dcerpc_cn_num_results = -1;
386 static int hf_dcerpc_cn_ack_result = -1;
387 static int hf_dcerpc_cn_ack_reason = -1;
388 static int hf_dcerpc_cn_ack_trans_id = -1;
389 static int hf_dcerpc_cn_ack_trans_ver = -1;
390 static int hf_dcerpc_cn_reject_reason = -1;
391 static int hf_dcerpc_cn_num_protocols = -1;
392 static int hf_dcerpc_cn_protocol_ver_major = -1;
393 static int hf_dcerpc_cn_protocol_ver_minor = -1;
394 static int hf_dcerpc_cn_cancel_count = -1;
395 static int hf_dcerpc_cn_status = -1;
396 static int hf_dcerpc_cn_deseg_req = -1;
397 static int hf_dcerpc_auth_type = -1;
398 static int hf_dcerpc_auth_level = -1;
399 static int hf_dcerpc_auth_pad_len = -1;
400 static int hf_dcerpc_auth_rsrvd = -1;
401 static int hf_dcerpc_auth_ctx_id = -1;
402 static int hf_dcerpc_dg_flags1 = -1;
403 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
404 static int hf_dcerpc_dg_flags1_last_frag = -1;
405 static int hf_dcerpc_dg_flags1_frag = -1;
406 static int hf_dcerpc_dg_flags1_nofack = -1;
407 static int hf_dcerpc_dg_flags1_maybe = -1;
408 static int hf_dcerpc_dg_flags1_idempotent = -1;
409 static int hf_dcerpc_dg_flags1_broadcast = -1;
410 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
411 static int hf_dcerpc_dg_flags2 = -1;
412 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
413 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
414 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
415 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
416 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
417 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
418 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
419 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
420 static int hf_dcerpc_dg_serial_hi = -1;
421 static int hf_dcerpc_obj_id = -1;
422 static int hf_dcerpc_dg_if_id = -1;
423 static int hf_dcerpc_dg_act_id = -1;
424 static int hf_dcerpc_dg_serial_lo = -1;
425 static int hf_dcerpc_dg_ahint = -1;
426 static int hf_dcerpc_dg_ihint = -1;
427 static int hf_dcerpc_dg_frag_len = -1;
428 static int hf_dcerpc_dg_frag_num = -1;
429 static int hf_dcerpc_dg_auth_proto = -1;
430 static int hf_dcerpc_opnum = -1;
431 static int hf_dcerpc_dg_seqnum = -1;
432 static int hf_dcerpc_dg_server_boot = -1;
433 static int hf_dcerpc_dg_if_ver = -1;
434 static int hf_dcerpc_krb5_av_prot_level = -1;
435 static int hf_dcerpc_krb5_av_key_vers_num = -1;
436 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
437 static int hf_dcerpc_dg_cancel_vers = -1;
438 static int hf_dcerpc_dg_cancel_id = -1;
439 static int hf_dcerpc_dg_server_accepting_cancels = -1;
440 static int hf_dcerpc_dg_fack_vers = -1;
441 static int hf_dcerpc_dg_fack_window_size = -1;
442 static int hf_dcerpc_dg_fack_max_tsdu = -1;
443 static int hf_dcerpc_dg_fack_max_frag_size = -1;
444 static int hf_dcerpc_dg_fack_serial_num = -1;
445 static int hf_dcerpc_dg_fack_selack_len = -1;
446 static int hf_dcerpc_dg_fack_selack = -1;
447 static int hf_dcerpc_dg_status = -1;
448 static int hf_dcerpc_array_max_count = -1;
449 static int hf_dcerpc_array_offset = -1;
450 static int hf_dcerpc_array_actual_count = -1;
451 static int hf_dcerpc_array_buffer = -1;
452 static int hf_dcerpc_op = -1;
453 static int hf_dcerpc_referent_id = -1;
454 static int hf_dcerpc_fragments = -1;
455 static int hf_dcerpc_fragment = -1;
456 static int hf_dcerpc_fragment_overlap = -1;
457 static int hf_dcerpc_fragment_overlap_conflict = -1;
458 static int hf_dcerpc_fragment_multiple_tails = -1;
459 static int hf_dcerpc_fragment_too_long_fragment = -1;
460 static int hf_dcerpc_fragment_error = -1;
461 static int hf_dcerpc_reassembled_in = -1;
462 static int hf_dcerpc_unknown_if_id = -1;
464 static gint ett_dcerpc = -1;
465 static gint ett_dcerpc_cn_flags = -1;
466 static gint ett_dcerpc_cn_ctx = -1;
467 static gint ett_dcerpc_cn_iface = -1;
468 static gint ett_dcerpc_cn_trans_syntax = -1;
469 static gint ett_dcerpc_drep = -1;
470 static gint ett_dcerpc_dg_flags1 = -1;
471 static gint ett_dcerpc_dg_flags2 = -1;
472 static gint ett_dcerpc_pointer_data = -1;
473 static gint ett_dcerpc_string = -1;
474 static gint ett_dcerpc_fragments = -1;
475 static gint ett_dcerpc_fragment = -1;
476 static gint ett_dcerpc_krb5_auth_verf = -1;
478 static const fragment_items dcerpc_frag_items = {
479 &ett_dcerpc_fragments,
480 &ett_dcerpc_fragment,
482 &hf_dcerpc_fragments,
484 &hf_dcerpc_fragment_overlap,
485 &hf_dcerpc_fragment_overlap_conflict,
486 &hf_dcerpc_fragment_multiple_tails,
487 &hf_dcerpc_fragment_too_long_fragment,
488 &hf_dcerpc_fragment_error,
494 /* list of hooks to be called when init_protocols is done */
495 GHookList dcerpc_hooks_init_protos;
498 int ResolveWin32UUID(e_uuid_t if_id, char *uuid_name, int uuid_name_max_len)
500 TCHAR reg_uuid_name[MAX_PATH];
502 DWORD uuid_max_size = MAX_PATH;
503 TCHAR reg_uuid_str[MAX_PATH];
505 if(uuid_name_max_len < 2)
507 reg_uuid_name[0] = '\0';
508 _snwprintf(reg_uuid_str, MAX_PATH, _T("SOFTWARE\\Classes\\Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
509 if_id.Data1, if_id.Data2, if_id.Data3,
510 if_id.Data4[0], if_id.Data4[1],
511 if_id.Data4[2], if_id.Data4[3],
512 if_id.Data4[4], if_id.Data4[5],
513 if_id.Data4[6], if_id.Data4[7]);
514 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, reg_uuid_str, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
516 if (RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)reg_uuid_name, &uuid_max_size) == ERROR_SUCCESS && uuid_max_size <= MAX_PATH)
518 g_snprintf(uuid_name, uuid_name_max_len, "%s", utf_16to8(reg_uuid_name));
520 return strlen(uuid_name);
524 return 0; /* we didn't find anything anyhow. Please don't use the string! */
532 static dcerpc_info di[20];
533 static int di_counter=0;
539 return &di[di_counter];
542 /* try to desegment big DCE/RPC packets over TCP? */
543 static gboolean dcerpc_cn_desegment = TRUE;
545 /* reassemble DCE/RPC fragments */
546 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
547 might contain multiple dcerpc fragments for different PDUs.
548 this case would be so unusual/weird so if you got captures like that:
551 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
552 are coming in out of sequence, but that will hurt in a lot of other places as well.
554 static gboolean dcerpc_reassemble = TRUE;
555 static GHashTable *dcerpc_co_fragment_table = NULL;
556 static GHashTable *dcerpc_co_reassemble_table = NULL;
557 static GHashTable *dcerpc_cl_reassemble_table = NULL;
560 dcerpc_reassemble_init(void)
562 fragment_table_init(&dcerpc_co_fragment_table);
563 reassembled_table_init(&dcerpc_co_reassemble_table);
564 dcerpc_fragment_table_init(&dcerpc_cl_reassemble_table);
568 * Authentication subdissectors. Used to dissect authentication blobs in
569 * DCERPC binds, requests and responses.
572 typedef struct _dcerpc_auth_subdissector {
575 dcerpc_auth_subdissector_fns auth_fns;
576 } dcerpc_auth_subdissector;
578 static GSList *dcerpc_auth_subdissector_list;
580 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
581 guint8 auth_level, guint8 auth_type)
586 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
587 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
589 if (asd->auth_level == auth_level &&
590 asd->auth_type == auth_type)
591 return &asd->auth_fns;
597 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
598 dcerpc_auth_subdissector_fns *fns)
600 dcerpc_auth_subdissector *d;
602 if (get_auth_subdissector_fns(auth_level, auth_type))
605 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
607 d->auth_level = auth_level;
608 d->auth_type = auth_type;
609 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
611 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
614 /* Hand off verifier data to a registered dissector */
616 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
618 dcerpc_auth_subdissector_fns *auth_fns,
619 e_dce_cn_common_hdr_t *hdr,
620 dcerpc_auth_info *auth_info)
622 dcerpc_dissect_fnct_t *volatile fn = NULL;
624 switch (hdr->ptype) {
627 fn = auth_fns->bind_fn;
631 fn = auth_fns->bind_ack_fn;
634 fn = auth_fns->auth3_fn;
637 fn = auth_fns->req_verf_fn;
640 fn = auth_fns->resp_verf_fn;
643 /* Don't know how to handle authentication data in this
647 g_warning("attempt to dissect %s pdu authentication data",
648 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
653 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
655 tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
656 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
658 val_to_str(auth_info->auth_type,
664 /* Hand off payload data to a registered dissector */
666 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
669 dcerpc_auth_subdissector_fns *auth_fns,
671 dcerpc_auth_info *auth_info)
673 dcerpc_decode_data_fnct_t *fn;
676 fn = auth_fns->req_data_fn;
678 fn = auth_fns->resp_data_fn;
681 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
690 /* the registered subdissectors */
691 GHashTable *dcerpc_uuids=NULL;
694 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
696 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
697 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
698 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
699 && (key1->ver == key2->ver));
703 dcerpc_uuid_hash (gconstpointer k)
705 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
706 /* This isn't perfect, but the Data1 part of these is almost always
708 return key->uuid.Data1;
712 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
713 dcerpc_sub_dissector *procs, int opnum_hf)
715 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
716 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
717 header_field_info *hf_info;
722 value->proto = find_protocol_by_id(proto);
723 value->proto_id = proto;
725 value->name = proto_get_protocol_short_name (value->proto);
726 value->procs = procs;
727 value->opnum_hf = opnum_hf;
729 g_hash_table_insert (dcerpc_uuids, key, value);
731 hf_info = proto_registrar_get_nth(opnum_hf);
732 hf_info->strings = value_string_from_subdissectors(procs);
736 /* try to get registered name for this uuid */
737 const gchar *dcerpc_get_uuid_name(e_uuid_t *uuid, guint16 ver)
740 dcerpc_uuid_value *sub_proto;
743 /* try to get registered uuid "name" of if_id */
747 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) != NULL
748 && proto_is_protocol_enabled(sub_proto->proto)) {
750 return sub_proto->name;
757 /* Function to find the name of a registered protocol
758 * or NULL if the protocol/version is not known to wireshark.
761 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
764 dcerpc_uuid_value *sub_proto;
768 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
771 return sub_proto->name;
774 /* Function to find the opnum hf-field of a registered protocol
775 * or -1 if the protocol/version is not known to wireshark.
778 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
781 dcerpc_uuid_value *sub_proto;
785 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
788 return sub_proto->opnum_hf;
791 /* Create a value_string consisting of DCERPC opnum and name from a
792 subdissector array. */
794 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
796 value_string *vs = NULL;
800 for (i = 0; sd[i].name; i++) {
802 vs[i].value = sd[i].num;
803 vs[i].strptr = sd[i].name;
809 vs = g_malloc((num_sd + 1) * sizeof(value_string));
813 vs[num_sd].value = 0;
814 vs[num_sd].strptr = NULL;
819 /* Function to find the subdissector table of a registered protocol
820 * or NULL if the protocol/version is not known to wireshark.
822 dcerpc_sub_dissector *
823 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
826 dcerpc_uuid_value *sub_proto;
830 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
833 return sub_proto->procs;
838 * To keep track of ctx_id mappings.
840 * Everytime we see a bind call we update this table.
841 * Note that we always specify a SMB FID. For non-SMB transports this
844 static GHashTable *dcerpc_binds=NULL;
846 typedef struct _dcerpc_bind_key {
847 conversation_t *conv;
852 typedef struct _dcerpc_bind_value {
858 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
860 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
861 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
862 return (key1->conv == key2->conv
863 && key1->ctx_id == key2->ctx_id
864 && key1->smb_fid == key2->smb_fid);
868 dcerpc_bind_hash (gconstpointer k)
870 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
873 hash=GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
879 * To keep track of callid mappings. Should really use some generic
880 * conversation support instead.
882 static GHashTable *dcerpc_cn_calls=NULL;
883 static GHashTable *dcerpc_dg_calls=NULL;
885 typedef struct _dcerpc_cn_call_key {
886 conversation_t *conv;
889 } dcerpc_cn_call_key;
891 typedef struct _dcerpc_dg_call_key {
892 conversation_t *conv;
895 } dcerpc_dg_call_key;
899 dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2)
901 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
902 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
903 return (key1->conv == key2->conv
904 && key1->call_id == key2->call_id
905 && key1->smb_fid == key2->smb_fid);
909 dcerpc_dg_call_equal (gconstpointer k1, gconstpointer k2)
911 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
912 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
913 return (key1->conv == key2->conv
914 && key1->seqnum == key2->seqnum
915 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0));
919 dcerpc_cn_call_hash (gconstpointer k)
921 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
922 return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
926 dcerpc_dg_call_hash (gconstpointer k)
928 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
929 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
930 + (key->act_id.Data2 << 16) + key->act_id.Data3
931 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
932 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
933 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
934 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
937 /* to keep track of matched calls/responses
938 this one uses the same value struct as calls, but the key is the frame id
939 and call id; there can be more than one call in a frame.
941 XXX - why not just use the same keys as are used for calls?
944 static GHashTable *dcerpc_matched=NULL;
946 typedef struct _dcerpc_matched_key {
949 } dcerpc_matched_key;
952 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
954 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
955 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
956 return (key1->frame == key2->frame
957 && key1->call_id == key2->call_id);
961 dcerpc_matched_hash (gconstpointer k)
963 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
970 * Utility functions. Modeled after packet-rpc.c
974 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
975 proto_tree *tree, guint8 *drep,
976 int hfindex, guint8 *pdata)
980 data = tvb_get_guint8 (tvb, offset);
982 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
990 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
991 proto_tree *tree, guint8 *drep,
992 int hfindex, guint16 *pdata)
996 data = ((drep[0] & 0x10)
997 ? tvb_get_letohs (tvb, offset)
998 : tvb_get_ntohs (tvb, offset));
1001 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
1009 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1010 proto_tree *tree, guint8 *drep,
1011 int hfindex, guint32 *pdata)
1015 data = ((drep[0] & 0x10)
1016 ? tvb_get_letohl (tvb, offset)
1017 : tvb_get_ntohl (tvb, offset));
1020 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
1027 /* handles 32 bit unix time_t */
1029 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1030 proto_tree *tree, guint8 *drep,
1031 int hfindex, guint32 *pdata)
1036 data = ((drep[0] & 0x10)
1037 ? tvb_get_letohl (tvb, offset)
1038 : tvb_get_ntohl (tvb, offset));
1043 if(data==0xffffffff){
1044 /* special case, no time specified */
1045 proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
1047 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
1057 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1058 proto_tree *tree, guint8 *drep,
1059 int hfindex, guint64 *pdata)
1063 data = ((drep[0] & 0x10)
1064 ? tvb_get_letoh64 (tvb, offset)
1065 : tvb_get_ntoh64 (tvb, offset));
1068 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
1077 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1078 proto_tree *tree, guint8 *drep,
1079 int hfindex, gfloat *pdata)
1085 case(DCE_RPC_DREP_FP_IEEE):
1086 data = ((drep[0] & 0x10)
1087 ? tvb_get_letohieee_float(tvb, offset)
1088 : tvb_get_ntohieee_float(tvb, offset));
1090 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1093 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1094 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1095 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1097 /* ToBeDone: non IEEE floating formats */
1098 /* Set data to a negative infinity value */
1101 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1111 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1112 proto_tree *tree, guint8 *drep,
1113 int hfindex, gdouble *pdata)
1119 case(DCE_RPC_DREP_FP_IEEE):
1120 data = ((drep[0] & 0x10)
1121 ? tvb_get_letohieee_double(tvb, offset)
1122 : tvb_get_ntohieee_double(tvb, offset));
1124 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1127 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1128 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1129 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1131 /* ToBeDone: non IEEE double formats */
1132 /* Set data to a negative infinity value */
1133 data = -G_MAXDOUBLE;
1135 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1145 dissect_dcerpc_uuid_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1146 proto_tree *tree, guint8 *drep,
1147 int hfindex, e_uuid_t *pdata)
1151 header_field_info* hfi;
1156 dcerpc_tvb_get_uuid (tvb, offset, drep, &uuid);
1159 /* get name of protocol field to prepend it later */
1160 hfi = proto_registrar_get_nth(hfindex);
1162 /* XXX - get the name won't work correct, as we don't know the version of this uuid (if it has one) */
1163 /* look for a registered uuid name */
1164 uuid_name = dcerpc_get_uuid_name(&uuid, 0);
1167 /* we know the name of this uuid */
1168 proto_tree_add_string_format (tree, hfindex, tvb, offset, 16, "",
1169 "%s: %s (%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)",
1170 hfi->name, uuid_name,
1171 uuid.Data1, uuid.Data2, uuid.Data3,
1172 uuid.Data4[0], uuid.Data4[1],
1173 uuid.Data4[2], uuid.Data4[3],
1174 uuid.Data4[4], uuid.Data4[5],
1175 uuid.Data4[6], uuid.Data4[7]);
1178 /* GUID have changed from FT_STRING to FT_GUID
1179 (XXX - have we changed all dissectors?).
1181 proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
1194 * a couple simpler things
1197 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, guint8 *drep)
1199 if (drep[0] & 0x10) {
1200 return tvb_get_letohs (tvb, offset);
1202 return tvb_get_ntohs (tvb, offset);
1207 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, guint8 *drep)
1209 if (drep[0] & 0x10) {
1210 return tvb_get_letohl (tvb, offset);
1212 return tvb_get_ntohl (tvb, offset);
1217 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1219 if (drep[0] & 0x10) {
1220 tvb_get_letohguid (tvb, offset, (e_guid_t *) uuid);
1222 tvb_get_ntohguid (tvb, offset, (e_guid_t *) uuid);
1229 /* function to dissect a unidimensional conformant array */
1231 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1232 proto_tree *tree, guint8 *drep,
1233 dcerpc_dissect_fnct_t *fnct)
1239 di=pinfo->private_data;
1240 if(di->conformant_run){
1241 /* conformant run, just dissect the max_count header */
1243 di->conformant_run=0;
1244 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1245 hf_dcerpc_array_max_count, &di->array_max_count);
1246 di->array_max_count_offset=offset-4;
1247 di->conformant_run=1;
1248 di->conformant_eaten=offset-old_offset;
1250 /* we don't remember where in the bytestream this field was */
1251 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1253 /* real run, dissect the elements */
1254 for(i=0;i<di->array_max_count;i++){
1255 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1261 /* function to dissect a unidimensional conformant and varying array */
1263 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1264 proto_tree *tree, guint8 *drep,
1265 dcerpc_dissect_fnct_t *fnct)
1271 di=pinfo->private_data;
1272 if(di->conformant_run){
1273 /* conformant run, just dissect the max_count header */
1275 di->conformant_run=0;
1276 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1277 hf_dcerpc_array_max_count, &di->array_max_count);
1278 di->array_max_count_offset=offset-4;
1279 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1280 hf_dcerpc_array_offset, &di->array_offset);
1281 di->array_offset_offset=offset-4;
1282 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1283 hf_dcerpc_array_actual_count, &di->array_actual_count);
1284 di->array_actual_count_offset=offset-4;
1285 di->conformant_run=1;
1286 di->conformant_eaten=offset-old_offset;
1288 /* we dont dont remember where in the bytestream these fields were */
1289 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1290 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1291 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1293 /* real run, dissect the elements */
1294 for(i=0;i<di->array_actual_count;i++){
1295 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1301 /* function to dissect a unidimensional varying array */
1303 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1304 proto_tree *tree, guint8 *drep,
1305 dcerpc_dissect_fnct_t *fnct)
1311 di=pinfo->private_data;
1312 if(di->conformant_run){
1313 /* conformant run, just dissect the max_count header */
1315 di->conformant_run=0;
1316 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1317 hf_dcerpc_array_offset, &di->array_offset);
1318 di->array_offset_offset=offset-4;
1319 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1320 hf_dcerpc_array_actual_count, &di->array_actual_count);
1321 di->array_actual_count_offset=offset-4;
1322 di->conformant_run=1;
1323 di->conformant_eaten=offset-old_offset;
1325 /* we dont dont remember where in the bytestream these fields were */
1326 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1327 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1329 /* real run, dissect the elements */
1330 for(i=0;i<di->array_actual_count;i++){
1331 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1338 /* Dissect an string of bytes. This corresponds to
1339 IDL of the form '[string] byte *foo'.
1341 It can also be used for a conformant varying array of bytes if
1342 the contents of the array should be shown as a big blob, rather
1343 than showing each byte as an individual element.
1345 XXX - which of those is really the IDL type for, for example,
1346 the encrypted data in some MAPI packets? (Microsoft haven't
1349 XXX - does this need to do all the conformant array stuff that
1350 "dissect_ndr_ucvarray()" does? These are presumably for strings
1351 that are conformant and varying - they're stored like conformant
1352 varying arrays of bytes. */
1354 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1355 proto_tree *tree, guint8 *drep)
1360 di=pinfo->private_data;
1361 if(di->conformant_run){
1362 /* just a run to handle conformant arrays, no scalars to dissect */
1366 /* NDR array header */
1368 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1369 hf_dcerpc_array_max_count, NULL);
1371 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1372 hf_dcerpc_array_offset, NULL);
1374 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1375 hf_dcerpc_array_actual_count, &len);
1378 tvb_ensure_bytes_exist(tvb, offset, len);
1379 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1380 tvb, offset, len, drep[0] & 0x10);
1388 /* For dissecting arrays that are to be interpreted as strings. */
1390 /* Dissect an NDR conformant varying string of elements.
1391 The length of each element is given by the 'size_is' parameter;
1392 the elements are assumed to be characters or wide characters.
1394 XXX - does this need to do all the conformant array stuff that
1395 "dissect_ndr_ucvarray()" does? */
1397 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1398 proto_tree *tree, guint8 *drep, int size_is,
1399 int hfindex, gboolean add_subtree, char **data)
1402 proto_item *string_item;
1403 proto_tree *string_tree;
1404 guint32 len, buffer_len;
1406 header_field_info *hfinfo;
1408 di=pinfo->private_data;
1409 if(di->conformant_run){
1410 /* just a run to handle conformant arrays, no scalars to dissect */
1415 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1416 proto_registrar_get_name(hfindex));
1417 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1423 /* NDR array header */
1425 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1426 hf_dcerpc_array_max_count, NULL);
1428 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1429 hf_dcerpc_array_offset, NULL);
1431 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1432 hf_dcerpc_array_actual_count, &len);
1434 buffer_len = size_is * len;
1437 if (offset % size_is)
1438 offset += size_is - (offset % size_is);
1440 if (size_is == sizeof(guint16)) {
1441 /* XXX - use drep to determine the byte order? */
1442 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1444 * XXX - we don't support a string type with Unicode
1445 * characters, so if this is a string item, we make
1446 * its value be the "fake Unicode" string.
1448 if (tree && buffer_len) {
1449 hfinfo = proto_registrar_get_nth(hfindex);
1450 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1451 if (hfinfo->type == FT_STRING) {
1452 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1455 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1456 buffer_len, drep[0] & 0x10);
1461 * "tvb_get_string()" throws an exception if the entire string
1462 * isn't in the tvbuff. If the length is bogus, this should
1463 * keep us from trying to allocate an immensely large buffer.
1464 * (It won't help if the length is *valid* but immensely large,
1465 * but that's another matter; in any case, that would happen only
1466 * if we had an immensely large tvbuff....)
1468 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1469 s = tvb_get_string(tvb, offset, buffer_len);
1470 if (tree && buffer_len)
1471 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1472 buffer_len, drep[0] & 0x10);
1475 if (string_item != NULL)
1476 proto_item_append_text(string_item, ": %s", s);
1483 offset += buffer_len;
1485 proto_item_set_end(string_item, tvb, offset);
1490 /* Dissect an conformant varying string of chars.
1491 This corresponds to IDL of the form '[string] char *foo'.
1493 XXX - at least according to the DCE RPC 1.1 spec, a string has
1494 a null terminator, which isn't necessary as a terminator for
1495 the transfer language (as there's a length), but is presumably
1496 there for the benefit of null-terminated-string languages
1497 such as C. Is this ever used for purely counted strings?
1498 (Not that it matters if it is.) */
1500 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1501 proto_tree *tree, guint8 *drep)
1504 di=pinfo->private_data;
1506 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1507 sizeof(guint8), di->hf_index,
1511 /* Dissect a conformant varying string of wchars (wide characters).
1512 This corresponds to IDL of the form '[string] wchar *foo'
1514 XXX - at least according to the DCE RPC 1.1 spec, a string has
1515 a null terminator, which isn't necessary as a terminator for
1516 the transfer language (as there's a length), but is presumably
1517 there for the benefit of null-terminated-string languages
1518 such as C. Is this ever used for purely counted strings?
1519 (Not that it matters if it is.) */
1521 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1522 proto_tree *tree, guint8 *drep)
1525 di=pinfo->private_data;
1527 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1528 sizeof(guint16), di->hf_index,
1532 /* Dissect an NDR varying string of elements.
1533 The length of each element is given by the 'size_is' parameter;
1534 the elements are assumed to be characters or wide characters.
1537 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1538 proto_tree *tree, guint8 *drep, int size_is,
1539 int hfindex, gboolean add_subtree, char **data)
1542 proto_item *string_item;
1543 proto_tree *string_tree;
1544 guint32 len, buffer_len;
1546 header_field_info *hfinfo;
1548 di=pinfo->private_data;
1549 if(di->conformant_run){
1550 /* just a run to handle conformant arrays, no scalars to dissect */
1555 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1556 proto_registrar_get_name(hfindex));
1557 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1563 /* NDR array header */
1564 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1565 hf_dcerpc_array_offset, NULL);
1567 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1568 hf_dcerpc_array_actual_count, &len);
1570 buffer_len = size_is * len;
1573 if (offset % size_is)
1574 offset += size_is - (offset % size_is);
1576 if (size_is == sizeof(guint16)) {
1577 /* XXX - use drep to determine the byte order? */
1578 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1580 * XXX - we don't support a string type with Unicode
1581 * characters, so if this is a string item, we make
1582 * its value be the "fake Unicode" string.
1584 if (tree && buffer_len) {
1585 hfinfo = proto_registrar_get_nth(hfindex);
1586 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1587 if (hfinfo->type == FT_STRING) {
1588 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1591 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1592 buffer_len, drep[0] & 0x10);
1597 * "tvb_get_string()" throws an exception if the entire string
1598 * isn't in the tvbuff. If the length is bogus, this should
1599 * keep us from trying to allocate an immensely large buffer.
1600 * (It won't help if the length is *valid* but immensely large,
1601 * but that's another matter; in any case, that would happen only
1602 * if we had an immensely large tvbuff....)
1604 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1605 s = tvb_get_string(tvb, offset, buffer_len);
1606 if (tree && buffer_len)
1607 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1608 buffer_len, drep[0] & 0x10);
1611 if (string_item != NULL)
1612 proto_item_append_text(string_item, ": %s", s);
1619 offset += buffer_len;
1621 proto_item_set_end(string_item, tvb, offset);
1625 /* Dissect an varying string of chars.
1626 This corresponds to IDL of the form '[string] char *foo'.
1628 XXX - at least according to the DCE RPC 1.1 spec, a string has
1629 a null terminator, which isn't necessary as a terminator for
1630 the transfer language (as there's a length), but is presumably
1631 there for the benefit of null-terminated-string languages
1632 such as C. Is this ever used for purely counted strings?
1633 (Not that it matters if it is.) */
1635 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1636 proto_tree *tree, guint8 *drep)
1639 di=pinfo->private_data;
1641 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1642 sizeof(guint8), di->hf_index,
1646 /* Dissect a varying string of wchars (wide characters).
1647 This corresponds to IDL of the form '[string] wchar *foo'
1649 XXX - at least according to the DCE RPC 1.1 spec, a string has
1650 a null terminator, which isn't necessary as a terminator for
1651 the transfer language (as there's a length), but is presumably
1652 there for the benefit of null-terminated-string languages
1653 such as C. Is this ever used for purely counted strings?
1654 (Not that it matters if it is.) */
1656 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1657 proto_tree *tree, guint8 *drep)
1660 di=pinfo->private_data;
1662 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1663 sizeof(guint16), di->hf_index,
1668 /* ndr pointer handling */
1669 /* list of pointers encountered so far */
1670 static GSList *ndr_pointer_list = NULL;
1672 /* position where in the list to insert newly encountered pointers */
1673 static int ndr_pointer_list_pos=0;
1675 /* boolean controlling whether pointers are top-level or embedded */
1676 static gboolean pointers_are_top_level = TRUE;
1678 /* as a kludge, we represent all embedded reference pointers as id==-1
1679 hoping that his will not collide with any non-ref pointers */
1680 typedef struct ndr_pointer_data {
1682 proto_item *item; /* proto_item for pointer */
1683 proto_tree *tree; /* subtree of above item */
1684 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1686 dcerpc_callback_fnct_t *callback;
1687 void *callback_args;
1688 } ndr_pointer_data_t;
1691 init_ndr_pointer_list(packet_info *pinfo)
1695 di=pinfo->private_data;
1696 di->conformant_run=0;
1698 while(ndr_pointer_list){
1699 ndr_pointer_data_t *npd;
1701 npd=g_slist_nth_data(ndr_pointer_list, 0);
1702 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1708 ndr_pointer_list=NULL;
1709 ndr_pointer_list_pos=0;
1710 pointers_are_top_level=TRUE;
1714 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1716 int found_new_pointer;
1722 di=pinfo->private_data;
1726 found_new_pointer=0;
1727 len=g_slist_length(ndr_pointer_list);
1728 for(i=next_pointer;i<len;i++){
1729 ndr_pointer_data_t *tnpd;
1730 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1732 dcerpc_dissect_fnct_t *fnct;
1735 found_new_pointer=1;
1738 ndr_pointer_list_pos=i+1;
1739 di->hf_index=tnpd->hf_index;
1740 /* first a run to handle any conformant
1742 di->conformant_run=1;
1743 di->conformant_eaten=0;
1744 old_offset = offset;
1745 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1747 DISSECTOR_ASSERT((offset-old_offset)==di->conformant_eaten);
1748 /* This is to check for any bugs in the dissectors.
1750 * Basically, the NDR representation will store all
1751 * arrays in two blocks, one block with the dimension
1752 * discreption, like size, number of elements and such,
1753 * and another block that contains the actual data stored
1755 * If the array is embedded directly inside another,
1756 * encapsulating aggregate type, like a union or struct,
1757 * then these two blocks will be stored at different places
1758 * in the bytestream, with other data between the blocks.
1760 * For this reason, all pointers to types (both aggregate
1761 * and scalar, for simplicity no distinction is made)
1762 * will have its dissector called twice.
1763 * The dissector will first be called with conformant_run==1
1764 * in which mode the dissector MUST NOT consume any data from
1765 * the tvbuff (i.e. may not dissect anything) except the
1766 * initial control block for arrays.
1767 * The second time the dissector is called, with
1768 * conformant_run==0, all other data for the type will be
1771 * All dissect_ndr_<type> dissectors are already prepared
1772 * for this and knows when it should eat data from the tvb
1773 * and when not to, so implementors of dissectors will
1774 * normally not need to worry about this or even know about
1775 * it. However, if a dissector for an aggregate type calls
1776 * a subdissector from outside packet-dcerpc.c, such as
1777 * the dissector in packet-smb.c for NT Security Descriptors
1778 * as an example, then it is VERY important to encapsulate
1779 * this call to an external subdissector with the appropriate
1780 * test for conformant_run, i.e. it will need something like
1784 * di=pinfo->private_data;
1785 * if(di->conformant_run){
1789 * to make sure it makes the right thing.
1790 * This assert will signal when someone has forgotten to
1791 * make the dissector aware of this requirement.
1794 /* now we dissect the actual pointer */
1795 di->conformant_run=0;
1796 old_offset = offset;
1797 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1799 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1803 } while(found_new_pointer);
1810 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1811 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1812 dcerpc_callback_fnct_t *callback, void *callback_args)
1814 ndr_pointer_data_t *npd;
1816 /* check if this pointer is valid */
1819 dcerpc_call_value *value;
1821 di=pinfo->private_data;
1822 value=di->call_data;
1824 if(di->ptype == PDU_REQ){
1825 if(!(pinfo->fd->flags.visited)){
1826 if(id>value->max_ptr){
1831 /* if we havent seen the request bail out since we cant
1832 know whether this is the first non-NULL instance
1834 if(value->req_frame==0){
1835 /* XXX THROW EXCEPTION */
1838 /* We saw this one in the request frame, nothing to
1840 if(id<=value->max_ptr){
1846 npd=g_malloc(sizeof(ndr_pointer_data_t));
1851 npd->hf_index=hf_index;
1852 npd->callback=callback;
1853 npd->callback_args=callback_args;
1854 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1855 ndr_pointer_list_pos);
1856 ndr_pointer_list_pos++;
1861 find_pointer_index(guint32 id)
1863 ndr_pointer_data_t *npd;
1866 len=g_slist_length(ndr_pointer_list);
1868 npd=g_slist_nth_data(ndr_pointer_list, i);
1879 /* This function dissects an NDR pointer and stores the callback for later
1880 * deferred dissection.
1882 * fnct is the callback function for when we have reached this object in
1885 * type is what type of pointer.
1887 * this is text is what text we should put in any created tree node.
1889 * hf_index is what hf value we want to pass to the callback function when
1890 * it is called, the callback can later pich this one up from di->hf_index.
1892 * callback is executed after the pointer has been dereferenced.
1894 * callback_args is passed as an argument to the callback function
1896 * See packet-dcerpc-samr.c for examples
1899 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1900 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1901 int type, const char *text, int hf_index,
1902 dcerpc_callback_fnct_t *callback, void *callback_args)
1905 proto_tree *tr = NULL;
1906 gint start_offset = offset;
1908 di=pinfo->private_data;
1909 if(di->conformant_run){
1910 /* this call was only for dissecting the header for any
1911 embedded conformant array. we will not parse any
1912 pointers in this mode.
1917 /*TOP LEVEL REFERENCE POINTER*/
1918 if( pointers_are_top_level
1919 &&(type==NDR_POINTER_REF) ){
1922 /* we must find out a nice way to do the length here */
1923 item=proto_tree_add_text(tree, tvb, offset, 0,
1925 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1927 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1928 hf_index, callback, callback_args);
1932 /*TOP LEVEL FULL POINTER*/
1933 if( pointers_are_top_level
1934 && (type==NDR_POINTER_PTR) ){
1939 /* get the referent id */
1940 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1942 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1943 /* we got a NULL pointer */
1945 proto_tree_add_text(tree, tvb, offset-4, 4,
1946 "(NULL pointer) %s",text);
1950 /* see if we have seen this pointer before */
1951 idx=find_pointer_index(id);
1953 /* we have seen this pointer before */
1955 proto_tree_add_text(tree, tvb, offset-4, 4,
1956 "(duplicate PTR) %s",text);
1961 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1963 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1964 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1965 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1966 callback, callback_args);
1969 /*TOP LEVEL UNIQUE POINTER*/
1970 if( pointers_are_top_level
1971 && (type==NDR_POINTER_UNIQUE) ){
1975 /* get the referent id */
1976 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1978 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1979 /* we got a NULL pointer */
1981 proto_tree_add_text(tree, tvb, offset-4, 4,
1982 "(NULL pointer) %s",text);
1987 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1989 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1990 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1991 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1992 hf_index, callback, callback_args);
1996 /*EMBEDDED REFERENCE POINTER*/
1997 if( (!pointers_are_top_level)
1998 && (type==NDR_POINTER_REF) ){
2002 /* get the referent id */
2003 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2005 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2007 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2009 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2010 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2011 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
2012 hf_index, callback, callback_args);
2016 /*EMBEDDED UNIQUE POINTER*/
2017 if( (!pointers_are_top_level)
2018 && (type==NDR_POINTER_UNIQUE) ){
2022 /* get the referent id */
2023 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2025 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2026 /* we got a NULL pointer */
2028 proto_tree_add_text(tree, tvb, offset-4, 4,
2029 "(NULL pointer) %s", text);
2034 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2036 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2037 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2038 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
2039 hf_index, callback, callback_args);
2043 /*EMBEDDED FULL POINTER*/
2044 if( (!pointers_are_top_level)
2045 && (type==NDR_POINTER_PTR) ){
2050 /* get the referent id */
2051 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2053 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2054 /* we got a NULL pointer */
2056 proto_tree_add_text(tree, tvb, offset-4, 4,
2057 "(NULL pointer) %s",text);
2061 /* see if we have seen this pointer before */
2062 idx=find_pointer_index(id);
2064 /* we have seen this pointer before */
2066 proto_tree_add_text(tree, tvb, offset-4, 4,
2067 "(duplicate PTR) %s",text);
2072 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2074 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2075 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2076 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
2077 callback, callback_args);
2083 /* After each top level pointer we have dissected we have to
2084 dissect all deferrals before we move on to the next top level
2086 if(pointers_are_top_level==TRUE){
2087 pointers_are_top_level=FALSE;
2088 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
2089 pointers_are_top_level=TRUE;
2092 /* Set the length for the new subtree */
2094 proto_item_set_len(tr, offset-start_offset);
2100 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2101 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2102 int type, const char *text, int hf_index)
2104 return dissect_ndr_pointer_cb(
2105 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2109 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2110 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2111 int type, const char *text, int hf_index)
2115 pointers_are_top_level=TRUE;
2116 ret=dissect_ndr_pointer_cb(
2117 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2122 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2123 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2124 int type, const char *text, int hf_index)
2128 pointers_are_top_level=FALSE;
2129 ret=dissect_ndr_pointer_cb(
2130 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2136 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2137 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2139 int length, plain_length, auth_pad_len;
2140 guint auth_pad_offset;
2143 * We don't show stub data unless we have some in the tvbuff;
2144 * however, in the protocol tree, we show, as the number of
2145 * bytes, the reported number of bytes, not the number of bytes
2146 * that happen to be in the tvbuff.
2148 if (tvb_length_remaining (tvb, offset) > 0) {
2149 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2150 length = tvb_reported_length_remaining (tvb, offset);
2152 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2153 plain_length = length - auth_pad_len;
2154 if (plain_length < 1) {
2155 plain_length = length;
2158 auth_pad_offset = offset + plain_length;
2160 if (auth_info != NULL &&
2161 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2163 tvb_ensure_bytes_exist(tvb, offset, length);
2164 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2165 "Encrypted stub data (%d byte%s)",
2166 length, plurality(length, "", "s"));
2167 /* is the padding is still inside the encrypted blob, don't display it explicit */
2170 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2171 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2172 "Decrypted stub data (%d byte%s)",
2173 plain_length, plurality(plain_length, "", "s"));
2176 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2177 proto_tree_add_text (dcerpc_tree, tvb, offset, plain_length,
2178 "Stub data (%d byte%s)", plain_length,
2179 plurality(plain_length, "", "s"));
2181 /* If there is auth padding at the end of the stub, display it */
2182 if (auth_pad_len != 0) {
2183 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2184 proto_tree_add_text (dcerpc_tree, tvb, auth_pad_offset,
2186 "Auth Padding (%u byte%s)",
2188 plurality(auth_pad_len, "", "s"));
2194 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
2195 proto_tree *dcerpc_tree,
2196 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2197 guint8 *drep, dcerpc_info *info,
2198 dcerpc_auth_info *auth_info)
2200 volatile gint offset = 0;
2201 dcerpc_uuid_key key;
2202 dcerpc_uuid_value *sub_proto;
2203 proto_tree *volatile sub_tree = NULL;
2204 dcerpc_sub_dissector *proc;
2205 const gchar *name = NULL;
2206 dcerpc_dissect_fnct_t *volatile sub_dissect;
2207 const char *volatile saved_proto;
2208 void *volatile saved_private_data;
2209 guint length, reported_length;
2210 tvbuff_t *volatile stub_tvb;
2211 volatile guint auth_pad_len;
2212 volatile int auth_pad_offset;
2214 char uuid_name[MAX_PATH];
2216 proto_item *sub_item=NULL;
2219 key.uuid = info->call_data->uuid;
2220 key.ver = info->call_data->ver;
2223 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
2224 || !proto_is_protocol_enabled(sub_proto->proto)) {
2226 * We don't have a dissector for this UUID, or the protocol
2227 * for that UUID is disabled.
2230 proto_tree_add_boolean_hidden(dcerpc_tree, hf_dcerpc_unknown_if_id,
2231 tvb, offset, 0, TRUE);
2232 if (check_col (pinfo->cinfo, COL_INFO)) {
2234 if(ResolveWin32UUID(info->call_data->uuid, uuid_name, MAX_PATH))
2235 col_append_fstr (pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2236 uuid_name, info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2237 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2238 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2239 info->call_data->uuid.Data4[7], info->call_data->ver);
2242 col_append_fstr (pinfo->cinfo, COL_INFO, " UNKUUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x rpcver: %u",
2243 info->call_data->uuid.Data1, info->call_data->uuid.Data2, info->call_data->uuid.Data3, info->call_data->uuid.Data4[0],
2244 info->call_data->uuid.Data4[1], info->call_data->uuid.Data4[2], info->call_data->uuid.Data4[3],
2245 info->call_data->uuid.Data4[4], info->call_data->uuid.Data4[5], info->call_data->uuid.Data4[6],
2246 info->call_data->uuid.Data4[7], info->call_data->ver);
2249 if (decrypted_tvb != NULL) {
2250 show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
2253 show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
2257 for (proc = sub_proto->procs; proc->name; proc++) {
2258 if (proc->num == info->call_data->opnum) {
2267 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
2268 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2271 if (check_col (pinfo->cinfo, COL_INFO)) {
2272 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
2273 name, (info->ptype == PDU_REQ) ? "request" : "response");
2276 sub_dissect = (info->ptype == PDU_REQ) ?
2277 proc->dissect_rqst : proc->dissect_resp;
2280 sub_item = proto_tree_add_item (tree, sub_proto->proto_id, tvb, 0,
2284 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
2285 proto_item_append_text(sub_item, ", %s", name);
2289 * Put the operation number into the tree along with
2290 * the operation's name.
2292 if(sub_dissect == NULL)
2293 if (sub_proto->opnum_hf != -1)
2294 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2295 tvb, 0, 0, info->call_data->opnum,
2296 "Operation: %s (%u)",
2297 name, info->call_data->opnum);
2299 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
2300 0, 0, info->call_data->opnum,
2301 "Operation: %s (%u)",
2302 name, info->call_data->opnum);
2304 if(info->ptype == PDU_REQ && info->call_data->rep_frame!=0) {
2305 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
2306 tvb, 0, 0, info->call_data->rep_frame);
2307 PROTO_ITEM_SET_GENERATED(pi);
2309 if(info->ptype == PDU_RESP && info->call_data->req_frame!=0) {
2310 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
2311 tvb, 0, 0, info->call_data->req_frame);
2312 PROTO_ITEM_SET_GENERATED(pi);
2316 if (decrypted_tvb != NULL) {
2317 /* Either there was no encryption or we successfully decrypted
2318 the encrypted payload. */
2320 /* We have a subdissector - call it. */
2321 saved_proto = pinfo->current_proto;
2322 saved_private_data = pinfo->private_data;
2323 pinfo->current_proto = sub_proto->name;
2324 pinfo->private_data = (void *)info;
2326 init_ndr_pointer_list(pinfo);
2329 * Remove the authentication padding from the stub data.
2331 if (auth_info != NULL && auth_info->auth_pad_len != 0) {
2332 length = tvb_length(decrypted_tvb);
2333 reported_length = tvb_reported_length(decrypted_tvb);
2334 if (reported_length >= auth_info->auth_pad_len) {
2336 * OK, the padding length isn't so big that it
2337 * exceeds the stub length. Trim the reported
2338 * length of the tvbuff.
2340 reported_length -= auth_info->auth_pad_len;
2343 * If that exceeds the actual amount of data in
2344 * the tvbuff (which means we have at least one
2345 * byte of authentication padding in the tvbuff),
2346 * trim the actual amount.
2348 if (length > reported_length)
2349 length = reported_length;
2351 stub_tvb = tvb_new_subset(tvb, 0, length, reported_length);
2352 auth_pad_len = auth_info->auth_pad_len;
2353 auth_pad_offset = reported_length;
2356 * The padding length exceeds the stub length.
2357 * Don't bother dissecting the stub, trim the padding
2358 * length to what's in the stub data, and show the
2359 * entire stub as authentication padding.
2362 auth_pad_len = reported_length;
2363 auth_pad_offset = 0;
2367 * No authentication padding.
2369 stub_tvb = decrypted_tvb;
2371 auth_pad_offset = 0;
2374 if (stub_tvb != NULL) {
2376 * Catch all exceptions other than BoundsError, so that even
2377 * if the stub data is bad, we still show the authentication
2380 * If we get BoundsError, it means the frame was cut short
2381 * by a snapshot length, so there's nothing more to
2382 * dissect; just re-throw that exception.
2385 offset = sub_dissect (decrypted_tvb, 0, pinfo, sub_tree,
2388 proto_item_set_len(sub_item, offset);
2391 /* If we have a subdissector and it didn't dissect all
2392 data in the tvb, make a note of it. */
2393 /* XXX - don't do this, as this could be just another RPC Req./Resp. in this PDU */
2394 /*if (tvb_reported_length_remaining(stub_tvb, offset) > 0) {
2395 if (check_col(pinfo->cinfo, COL_INFO))
2396 col_append_fstr(pinfo->cinfo, COL_INFO,
2397 "[Long frame (%d bytes)]",
2398 tvb_reported_length_remaining(stub_tvb, offset));
2400 } CATCH(BoundsError) {
2403 show_exception(decrypted_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
2407 /* If there is auth padding at the end of the stub, display it */
2408 if (auth_pad_len != 0) {
2409 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2410 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
2412 "Auth Padding (%u byte%s)",
2414 plurality(auth_pad_len, "", "s"));
2417 pinfo->current_proto = saved_proto;
2418 pinfo->private_data = saved_private_data;
2420 /* No subdissector - show it as stub data. */
2422 show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2424 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2428 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2430 tap_queue_packet(dcerpc_tap, pinfo, info);
2435 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
2436 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2437 dcerpc_auth_info *auth_info)
2441 auth_info->auth_data = NULL;
2443 if (auth_info->auth_size != 0) {
2444 dcerpc_auth_subdissector_fns *auth_fns;
2447 auth_offset = hdr->frag_len - hdr->auth_len;
2449 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2452 auth_info->auth_data = auth_tvb;
2454 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2455 auth_info->auth_type))) {
2457 * Catch all exceptions, so that even if the verifier is bad
2458 * or we don't have all of it, we still show the stub data.
2461 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2464 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2467 tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
2468 proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2473 return hdr->auth_len;
2477 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2478 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2479 gboolean are_credentials, dcerpc_auth_info *auth_info)
2481 volatile int offset;
2484 * Initially set auth_level and auth_type to zero to indicate that we
2485 * haven't yet seen any authentication level information.
2487 auth_info->auth_level = 0;
2488 auth_info->auth_type = 0;
2489 auth_info->auth_size = 0;
2490 auth_info->auth_pad_len = 0;
2493 * The authentication information is at the *end* of the PDU; in
2494 * request and response PDUs, the request and response stub data
2497 * Is there any authentication data (i.e., is the authentication length
2498 * non-zero), and is the authentication length valid (i.e., is it, plus
2499 * 8 bytes for the type/level/pad length/reserved/context id, less than
2500 * or equal to the fragment length minus the starting offset of the
2505 && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2508 * Yes, there is authentication data, and the length is valid.
2509 * Do we have all the bytes of stub data?
2510 * (If not, we'd throw an exception dissecting *that*, so don't
2511 * bother trying to dissect the authentication information and
2512 * throwing another exception there.)
2514 offset = hdr->frag_len - (hdr->auth_len + 8);
2515 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2517 * Either there's no stub data, or the last byte of the stub
2518 * data is present in the captured data, so we shouldn't
2519 * get a BoundsError dissecting the stub data.
2521 * Try dissecting the authentication data.
2522 * Catch all exceptions, so that even if the auth info is bad
2523 * or we don't have all of it, we still show the stuff we
2524 * dissect after this, such as stub data.
2527 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2528 hf_dcerpc_auth_type,
2529 &auth_info->auth_type);
2530 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2531 hf_dcerpc_auth_level,
2532 &auth_info->auth_level);
2534 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2535 hf_dcerpc_auth_pad_len,
2536 &auth_info->auth_pad_len);
2537 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2538 hf_dcerpc_auth_rsrvd, NULL);
2539 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2540 hf_dcerpc_auth_ctx_id, NULL);
2543 * Dissect the authentication data.
2545 if (are_credentials) {
2547 dcerpc_auth_subdissector_fns *auth_fns;
2549 auth_tvb = tvb_new_subset(tvb, offset,
2550 MIN(hdr->auth_len,tvb_length_remaining(tvb, offset)),
2553 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2554 auth_info->auth_type)))
2555 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2558 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2559 "Auth Credentials");
2562 /* Compute the size of the auth block. Note that this should not
2563 include auth padding, since when NTLMSSP encryption is used, the
2564 padding is actually inside the encrypted stub */
2565 auth_info->auth_size = hdr->auth_len + 8;
2567 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2574 /* We need to hash in the SMB fid number to generate a unique hash table
2575 * key as DCERPC over SMB allows several pipes over the same TCP/IP
2577 * We pass this function the transport type here to make sure we only look
2578 * at this function if it came across an SMB pipe.
2579 * Other transports might need to mix in their own extra multiplexing data
2580 * as well in the future.
2583 guint16 dcerpc_get_transport_salt (packet_info *pinfo)
2585 switch(pinfo->dcetransporttype){
2586 case DCE_CN_TRANSPORT_SMBPIPE:
2587 /* DCERPC over smb */
2588 return pinfo->dcetransportsalt;
2591 /* Some other transport... */
2596 * Connection oriented packet types
2600 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2601 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2603 conversation_t *conv = NULL;
2604 guint8 num_ctx_items = 0;
2606 gboolean saw_ctx_item = FALSE;
2608 guint8 num_trans_items;
2613 guint16 if_ver, if_ver_minor;
2614 char uuid_str[DCERPC_UUID_STR_LEN];
2616 dcerpc_auth_info auth_info;
2617 char *uuid_name = NULL;
2619 char uuid_name2[MAX_PATH];
2621 proto_item *iface_item;
2623 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2624 hf_dcerpc_cn_max_xmit, NULL);
2626 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2627 hf_dcerpc_cn_max_recv, NULL);
2629 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2630 hf_dcerpc_cn_assoc_group, NULL);
2632 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2633 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2638 for (i = 0; i < num_ctx_items; i++) {
2639 proto_item *ctx_item;
2640 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2641 gint ctx_offset = offset;
2643 dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2644 hf_dcerpc_cn_ctx_id, &ctx_id);
2646 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
2647 if(pinfo->dcectxid == 0) {
2648 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
2650 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
2651 * prepend a delimiter */
2652 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
2656 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2657 /* (if we have multiple contexts, this might cause "decode as"
2658 * to behave unpredictably) */
2659 pinfo->dcectxid = ctx_id;
2662 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
2664 hdr->drep[0] & 0x10);
2665 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2668 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2669 hf_dcerpc_cn_ctx_id, &ctx_id);
2670 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2671 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2674 proto_item_append_text(ctx_item, "[%u]: ID:%u", i+1, ctx_id);
2680 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2683 iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, FALSE);
2684 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2686 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2687 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2688 if_id.Data1, if_id.Data2, if_id.Data3,
2689 if_id.Data4[0], if_id.Data4[1],
2690 if_id.Data4[2], if_id.Data4[3],
2691 if_id.Data4[4], if_id.Data4[5],
2692 if_id.Data4[6], if_id.Data4[7]);
2694 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
2695 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2698 if(ResolveWin32UUID(if_id, uuid_name2, MAX_PATH)) {
2699 uuid_name = uuid_name2;
2702 proto_tree_add_guid_format (iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
2703 offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
2704 proto_item_append_text(iface_item, "%s", uuid_name);
2707 proto_tree_add_guid_format (iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
2708 offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
2709 proto_item_append_text(iface_item, "%s", uuid_str);
2716 if (hdr->drep[0] & 0x10) {
2717 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2718 hf_dcerpc_cn_bind_if_ver, &if_ver);
2719 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2720 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2722 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2723 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2724 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2725 hf_dcerpc_cn_bind_if_ver, &if_ver);
2729 proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
2730 proto_item_set_len(iface_item, 20);
2733 if (!saw_ctx_item) {
2734 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2735 pinfo->srcport, pinfo->destport, 0);
2737 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2738 pinfo->srcport, pinfo->destport, 0);
2742 /* if this is the first time we see this packet, we need to
2743 update the dcerpc_binds table so that any later calls can
2744 match to the interface.
2745 XXX We assume that BINDs will NEVER be fragmented.
2747 if(!(pinfo->fd->flags.visited)){
2748 dcerpc_bind_key *key;
2749 dcerpc_bind_value *value;
2751 key = se_alloc (sizeof (dcerpc_bind_key));
2753 key->ctx_id = ctx_id;
2754 key->smb_fid = dcerpc_get_transport_salt(pinfo);
2756 value = se_alloc (sizeof (dcerpc_bind_value));
2757 value->uuid = if_id;
2758 value->ver = if_ver;
2760 /* add this entry to the bind table, first removing any
2761 previous ones that are identical
2763 if(g_hash_table_lookup(dcerpc_binds, key)){
2764 g_hash_table_remove(dcerpc_binds, key);
2766 g_hash_table_insert (dcerpc_binds, key, value);
2769 if (check_col (pinfo->cinfo, COL_INFO)) {
2770 dcerpc_uuid_key key;
2771 dcerpc_uuid_value *value;
2776 if (num_ctx_items > 1)
2777 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2779 if ((value = g_hash_table_lookup(dcerpc_uuids, &key)))
2780 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %s", value->name);
2783 if(ResolveWin32UUID(if_id, uuid_name2, MAX_PATH))
2784 col_append_fstr(pinfo->cinfo, COL_INFO, " [%s] UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2785 uuid_name2, if_id.Data1, if_id.Data2, if_id.Data3,
2786 if_id.Data4[0], if_id.Data4[1],
2787 if_id.Data4[2], if_id.Data4[3],
2788 if_id.Data4[4], if_id.Data4[5],
2789 if_id.Data4[6], if_id.Data4[7],
2790 if_ver, if_ver_minor);
2793 col_append_fstr(pinfo->cinfo, COL_INFO, " UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x ver %u.%u",
2794 if_id.Data1, if_id.Data2, if_id.Data3,
2795 if_id.Data4[0], if_id.Data4[1],
2796 if_id.Data4[2], if_id.Data4[3],
2797 if_id.Data4[4], if_id.Data4[5],
2798 if_id.Data4[6], if_id.Data4[7],
2799 if_ver, if_ver_minor);
2801 saw_ctx_item = TRUE;
2804 for (j = 0; j < num_trans_items; j++) {
2805 proto_tree *trans_tree = NULL;
2806 proto_item *trans_item = NULL;
2808 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2811 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, FALSE);
2812 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
2814 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2815 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2816 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2817 trans_id.Data4[0], trans_id.Data4[1],
2818 trans_id.Data4[2], trans_id.Data4[3],
2819 trans_id.Data4[4], trans_id.Data4[5],
2820 trans_id.Data4[6], trans_id.Data4[7]);
2821 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
2822 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2823 proto_tree_add_guid_format (trans_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2824 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s", uuid_str);
2825 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
2829 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, trans_tree, hdr->drep,
2830 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2832 proto_item_set_len(trans_item, 20);
2833 proto_item_append_text(trans_item, " V%u", trans_ver);
2838 proto_item_set_len(ctx_item, offset - ctx_offset);
2843 * XXX - we should save the authentication type *if* we have
2844 * an authentication header, and associate it with an authentication
2845 * context, so subsequent PDUs can use that context.
2847 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2851 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2852 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2854 guint16 max_xmit, max_recv;
2855 guint16 sec_addr_len;
2862 char uuid_str[DCERPC_UUID_STR_LEN];
2864 dcerpc_auth_info auth_info;
2866 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2867 hf_dcerpc_cn_max_xmit, &max_xmit);
2869 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2870 hf_dcerpc_cn_max_recv, &max_recv);
2872 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2873 hf_dcerpc_cn_assoc_group, NULL);
2875 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2876 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2877 if (sec_addr_len != 0) {
2878 tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
2879 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2880 sec_addr_len, FALSE);
2881 offset += sec_addr_len;
2885 offset += 4 - offset % 4;
2888 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2889 hf_dcerpc_cn_num_results, &num_results);
2894 for (i = 0; i < num_results; i++) {
2895 proto_tree *ctx_tree = NULL;
2898 proto_item *ctx_item;
2899 ctx_item = proto_tree_add_text(dcerpc_tree, tvb, offset, 24, "Context ID[%u]", i+1);
2900 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2903 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
2904 hdr->drep, hf_dcerpc_cn_ack_result,
2907 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
2908 hdr->drep, hf_dcerpc_cn_ack_reason,
2912 * The reason for rejection isn't meaningful, and often isn't
2913 * set, when the syntax was accepted.
2918 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2920 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
2921 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2922 trans_id.Data1, trans_id.Data2, trans_id.Data3,
2923 trans_id.Data4[0], trans_id.Data4[1],
2924 trans_id.Data4[2], trans_id.Data4[3],
2925 trans_id.Data4[4], trans_id.Data4[5],
2926 trans_id.Data4[6], trans_id.Data4[7]);
2927 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
2928 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
2929 proto_tree_add_guid_format (ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2930 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s", uuid_str);
2934 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2935 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2939 * XXX - do we need to do anything with the authentication level
2940 * we get back from this?
2942 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2944 if (check_col (pinfo->cinfo, COL_INFO)) {
2945 if (num_results != 0 && result == 0) {
2946 /* XXX - only checks the last result */
2947 col_append_fstr (pinfo->cinfo, COL_INFO,
2948 " accept max_xmit: %u max_recv: %u",
2949 max_xmit, max_recv);
2951 /* XXX - only shows the last result and reason */
2952 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2953 val_to_str(result, p_cont_result_vals,
2954 "Unknown result (%u)"),
2955 val_to_str(reason, p_provider_reason_vals,
2962 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2963 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2966 guint8 num_protocols;
2969 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2970 hdr->drep, hf_dcerpc_cn_reject_reason,
2973 if (check_col (pinfo->cinfo, COL_INFO)) {
2974 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2975 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2978 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2979 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2980 hf_dcerpc_cn_num_protocols,
2983 for (i = 0; i < num_protocols; i++) {
2984 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2985 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2987 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2988 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2994 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2997 #define PFC_FRAG_MASK 0x03
3000 fragment_type(guint8 flags)
3002 flags = flags & PFC_FRAG_MASK;
3004 if (flags == PFC_FIRST_FRAG)
3010 if (flags == PFC_LAST_FRAG)
3013 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
3019 /* Dissect stub data (payload) of a DCERPC packet. */
3022 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
3023 proto_tree *dcerpc_tree, proto_tree *tree,
3024 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
3025 dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
3028 gint length, reported_length;
3029 gboolean save_fragmented;
3030 fragment_data *fd_head=NULL;
3032 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
3034 proto_item *parent_pi;
3035 proto_item *dcerpc_tree_item;
3037 save_fragmented = pinfo->fragmented;
3039 length = tvb_length_remaining(tvb, offset);
3040 reported_length = tvb_reported_length_remaining(tvb, offset);
3041 if (reported_length < 0 ||
3042 (guint32)reported_length < auth_info->auth_size) {
3043 /* We don't even have enough bytes for the authentication
3047 reported_length -= auth_info->auth_size;
3048 if (length > reported_length)
3049 length = reported_length;
3050 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
3053 /*dont bother if we dont have the entire tvb */
3054 /*XXX we should really make sure we calculate auth_info->auth_data
3055 and use that one instead of this auth_tvb hack
3057 if(tvb_length(tvb)==tvb_reported_length(tvb)){
3058 if(tvb_length_remaining(tvb, offset+length)>8){
3059 auth_tvb = tvb_new_subset(tvb, offset+length+8, -1, -1);
3063 /* Decrypt the PDU if it is encrypted */
3065 if (auth_info->auth_type &&
3066 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
3068 * We know the authentication type, and the authentication
3069 * level is "Packet privacy", meaning the payload is
3070 * encrypted; attempt to decrypt it.
3072 dcerpc_auth_subdissector_fns *auth_fns;
3074 /* Start out assuming we won't succeed in decrypting. */
3075 decrypted_tvb = NULL;
3077 if ((auth_fns = get_auth_subdissector_fns(
3078 auth_info->auth_level, auth_info->auth_type))) {
3081 result = decode_encrypted_data(
3082 payload_tvb, auth_tvb, pinfo, auth_fns,
3083 hdr->ptype == PDU_REQ, auth_info);
3087 proto_tree_add_text(
3088 dcerpc_tree, payload_tvb, 0, -1,
3089 "Encrypted stub data (%d byte%s)",
3090 tvb_reported_length(payload_tvb),
3092 plurality(tvb_length(payload_tvb), "", "s"));
3094 add_new_data_source(
3095 pinfo, result, "Decrypted stub data");
3098 decrypted_tvb = result;
3102 decrypted_tvb = payload_tvb;
3104 /* if this packet is not fragmented, just dissect it and exit */
3105 if(PFC_NOT_FRAGMENTED(hdr)){
3106 pinfo->fragmented = FALSE;
3109 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3110 hdr->drep, di, auth_info);
3112 pinfo->fragmented = save_fragmented;
3116 /* The packet is fragmented. */
3117 pinfo->fragmented = TRUE;
3119 /* debug output of essential fragment data. */
3120 /* leave it here for future debugging sessions */
3121 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
3122 pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
3124 /* if we are not doing reassembly and this is the first fragment
3125 then just dissect it and exit
3126 XXX - if we're not doing reassembly, can we decrypt an
3129 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
3132 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3133 hdr->drep, di, auth_info);
3135 if (check_col(pinfo->cinfo, COL_INFO)) {
3136 col_append_fstr(pinfo->cinfo, COL_INFO,
3137 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3139 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3140 "%s fragment", fragment_type(hdr->flags));
3141 pinfo->fragmented = save_fragmented;
3145 /* if we have already seen this packet, see if it was reassembled
3146 and if so dissect the full pdu.
3149 if(pinfo->fd->flags.visited){
3150 fd_head=fragment_get_reassembled(pinfo, frame, dcerpc_co_reassemble_table);
3154 /* if we are not doing reassembly and it was neither a complete PDU
3155 nor the first fragment then there is nothing more we can do
3156 so we just have to exit
3158 if( !dcerpc_reassemble )
3161 /* if we didnt get 'frame' we dont know where the PDU started and thus
3162 it is pointless to continue
3167 /* from now on we must attempt to reassemble the PDU
3170 /* if we get here we know it is the first time we see the packet
3171 and we also know it is only a fragment and not a full PDU,
3172 thus we must reassemble it.
3175 /* Do we have any non-encrypted data to reassemble? */
3176 if (decrypted_tvb == NULL) {
3177 /* No. We can't even try to reassemble. */
3181 /* defragmentation is a bit tricky, as there's no offset of the fragment
3182 * in the protocol data.
3184 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
3185 * in with the correct sequence.
3187 fd_head = fragment_add_seq_next(decrypted_tvb, 0, pinfo, frame,
3188 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3189 tvb_length(decrypted_tvb),
3190 hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
3194 /* if reassembly is complete and this is the last fragment
3195 * (multiple fragments in one PDU are possible!)
3196 * dissect the full PDU
3198 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
3200 if(pinfo->fd->num==fd_head->reassembled_in && (hdr->flags&PFC_LAST_FRAG) ){
3202 proto_item *frag_tree_item;
3204 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3206 tvb_set_child_real_data_tvbuff(decrypted_tvb, next_tvb);
3208 tvb_set_child_real_data_tvbuff(payload_tvb, next_tvb);
3210 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3211 show_fragment_tree(fd_head, &dcerpc_frag_items,
3212 tree, pinfo, next_tvb, &frag_tree_item);
3213 /* the toplevel fragment subtree is now behind all desegmented data,
3214 * move it right behind the DCE/RPC tree */
3215 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
3216 if(frag_tree_item && dcerpc_tree_item) {
3217 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
3220 pinfo->fragmented = FALSE;
3222 expert_add_info_format(pinfo, frag_tree_item, PI_REASSEMBLE, PI_CHAT,
3223 "%s fragment, %u bytes reassembled here in #%u",
3224 fragment_type(hdr->flags), fd_head->len, fd_head->reassembled_in);
3226 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3227 next_tvb, hdr->drep, di, auth_info);
3231 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3232 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3234 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3235 payload_tvb, 0, 0, fd_head->reassembled_in);
3237 PROTO_ITEM_SET_GENERATED(pi);
3238 parent_pi = proto_tree_get_parent(dcerpc_tree);
3239 if(parent_pi != NULL) {
3240 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
3242 if (check_col(pinfo->cinfo, COL_INFO)) {
3243 col_append_fstr(pinfo->cinfo, COL_INFO,
3244 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3246 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3247 "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
3250 /* Reassembly not complete - some fragments
3251 are missing. Just show the stub data. */
3252 if (check_col(pinfo->cinfo, COL_INFO)) {
3253 col_append_fstr(pinfo->cinfo, COL_INFO,
3254 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3256 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3257 "%s fragment", fragment_type(hdr->flags));
3260 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
3262 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
3266 pinfo->fragmented = save_fragmented;
3270 * Registers a conversation/UUID binding association, so that
3271 * we can invoke the proper sub-dissector for a given DCERPC
3274 * @param binding all values needed to create and bind a new conversation
3276 * @return Pointer to newly-added UUID/conversation binding.
3278 struct _dcerpc_bind_value *
3279 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
3281 dcerpc_bind_value *bind_value;
3282 dcerpc_bind_key *key;
3283 conversation_t *conv;
3285 conv = find_conversation (
3295 conv = conversation_new (
3305 bind_value = se_alloc (sizeof (dcerpc_bind_value));
3306 bind_value->uuid = binding->uuid;
3307 bind_value->ver = binding->ver;
3309 key = se_alloc(sizeof (dcerpc_bind_key));
3311 key->ctx_id = binding->ctx_id;
3312 key->smb_fid = binding->smb_fid;
3314 /* add this entry to the bind table, first removing any
3315 previous ones that are identical
3317 if(g_hash_table_lookup(dcerpc_binds, key)){
3318 g_hash_table_remove(dcerpc_binds, key);
3320 g_hash_table_insert(dcerpc_binds, key, bind_value);
3327 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3328 proto_tree *dcerpc_tree, proto_tree *tree,
3329 e_dce_cn_common_hdr_t *hdr)
3331 conversation_t *conv;
3334 e_uuid_t obj_id = DCERPC_UUID_NULL;
3335 dcerpc_auth_info auth_info;
3337 char uuid_str[DCERPC_UUID_STR_LEN];
3340 proto_item *parent_pi;
3342 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3343 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3345 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3346 hf_dcerpc_cn_ctx_id, &ctx_id);
3347 parent_pi = proto_tree_get_parent(dcerpc_tree);
3348 if(parent_pi != NULL) {
3349 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3352 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
3353 if(pinfo->dcectxid == 0) {
3354 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
3356 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3357 * prepend a delimiter */
3358 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
3362 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3363 hf_dcerpc_opnum, &opnum);
3365 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3366 pinfo->dcectxid = ctx_id;
3368 if (check_col (pinfo->cinfo, COL_INFO)) {
3369 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
3373 if (hdr->flags & PFC_OBJECT_UUID) {
3374 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
3376 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3377 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3378 obj_id.Data1, obj_id.Data2, obj_id.Data3,
3387 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
3388 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3389 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3390 offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s", uuid_str);
3396 * XXX - what if this was set when the connection was set up,
3397 * and we just have a security context?
3399 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3401 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3402 pinfo->srcport, pinfo->destport, 0);
3404 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3406 dcerpc_matched_key matched_key, *new_matched_key;
3407 dcerpc_call_value *value;
3409 /* !!! we can NOT check flags.visited here since this will interact
3410 badly with when SMB handles (i.e. calls the subdissector)
3411 and desegmented pdu's .
3412 Instead we check if this pdu is already in the matched table or not
3414 matched_key.frame = pinfo->fd->num;
3415 matched_key.call_id = hdr->call_id;
3416 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
3418 dcerpc_bind_key bind_key;
3419 dcerpc_bind_value *bind_value;
3422 bind_key.ctx_id=ctx_id;
3423 bind_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3425 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
3426 if(!(hdr->flags&PFC_FIRST_FRAG)){
3427 dcerpc_cn_call_key call_key;
3428 dcerpc_call_value *call_value;
3431 call_key.call_id=hdr->call_id;
3432 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3433 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3434 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3435 *new_matched_key = matched_key;
3436 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3440 dcerpc_cn_call_key *call_key;
3441 dcerpc_call_value *call_value;
3443 /* We found the binding and it is the first fragment
3444 (or a complete PDU) of a dcerpc pdu so just add
3445 the call to both the call table and the
3448 call_key=se_alloc (sizeof (dcerpc_cn_call_key));
3449 call_key->conv=conv;
3450 call_key->call_id=hdr->call_id;
3451 call_key->smb_fid=dcerpc_get_transport_salt(pinfo);
3453 /* if there is already a matching call in the table
3454 remove it so it is replaced with the new one */
3455 if(g_hash_table_lookup(dcerpc_cn_calls, call_key)){
3456 g_hash_table_remove(dcerpc_cn_calls, call_key);
3459 call_value=se_alloc (sizeof (dcerpc_call_value));
3460 call_value->uuid = bind_value->uuid;
3461 call_value->ver = bind_value->ver;
3462 call_value->object_uuid = obj_id;
3463 call_value->opnum = opnum;
3464 call_value->req_frame=pinfo->fd->num;
3465 call_value->req_time=pinfo->fd->abs_ts;
3466 call_value->rep_frame=0;
3467 call_value->max_ptr=0;
3468 call_value->private_data = NULL;
3469 g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
3471 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3472 *new_matched_key = matched_key;
3473 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3483 /* handoff this call */
3485 di->call_id = hdr->call_id;
3486 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3487 di->ptype = PDU_REQ;
3488 di->call_data = value;
3491 if(value->rep_frame!=0){
3492 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3493 tvb, 0, 0, value->rep_frame);
3494 PROTO_ITEM_SET_GENERATED(pi);
3495 if(parent_pi != NULL) {
3496 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
3500 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3501 hdr, di, &auth_info, alloc_hint,
3504 /* no bind information, simply show stub data */
3505 pi = proto_tree_add_text(dcerpc_tree, tvb, offset, 0, "No bind info for this interface Context ID - capture start too late?");
3506 PROTO_ITEM_SET_GENERATED(pi);
3507 expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u (Call ID:%u)",
3508 ctx_id, hdr->call_id);
3509 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3513 /* Dissect the verifier */
3514 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3519 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3520 proto_tree *dcerpc_tree, proto_tree *tree,
3521 e_dce_cn_common_hdr_t *hdr)
3523 dcerpc_call_value *value = NULL;
3524 conversation_t *conv;
3526 dcerpc_auth_info auth_info;
3529 proto_item *parent_pi;
3530 char uuid_str[DCERPC_UUID_STR_LEN];
3532 e_uuid_t obj_id_null = DCERPC_UUID_NULL;
3534 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3535 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3537 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3538 hf_dcerpc_cn_ctx_id, &ctx_id);
3539 parent_pi = proto_tree_get_parent(dcerpc_tree);
3540 if(parent_pi != NULL) {
3541 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3544 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
3545 if(pinfo->dcectxid == 0) {
3546 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
3548 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3549 * prepend a delimiter */
3550 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
3555 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3556 pinfo->dcectxid = ctx_id;
3558 if (check_col (pinfo->cinfo, COL_INFO)) {
3559 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
3562 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3563 hf_dcerpc_cn_cancel_count, NULL);
3568 * XXX - what if this was set when the connection was set up,
3569 * and we just have a security context?
3571 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3573 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3574 pinfo->srcport, pinfo->destport, 0);
3577 /* no point in creating one here, really */
3578 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3580 dcerpc_matched_key matched_key, *new_matched_key;
3582 /* !!! we can NOT check flags.visited here since this will interact
3583 badly with when SMB handles (i.e. calls the subdissector)
3584 and desegmented pdu's .
3585 Instead we check if this pdu is already in the matched table or not
3587 matched_key.frame = pinfo->fd->num;
3588 matched_key.call_id = hdr->call_id;
3589 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3591 dcerpc_cn_call_key call_key;
3592 dcerpc_call_value *call_value;
3595 call_key.call_id=hdr->call_id;
3596 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3598 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3599 /* extra sanity check, only match them if the reply
3600 came after the request */
3601 if(call_value->req_frame<pinfo->fd->num){
3602 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3603 *new_matched_key = matched_key;
3604 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3606 if(call_value->rep_frame==0){
3607 call_value->rep_frame=pinfo->fd->num;
3617 /* handoff this call */
3619 di->call_id = hdr->call_id;
3620 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3621 di->ptype = PDU_RESP;
3622 di->call_data = value;
3624 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3626 /* (optional) "Object UUID" from request */
3627 if (value && dcerpc_tree && memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0) {
3628 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
3629 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
3630 value->object_uuid.Data1, value->object_uuid.Data2, value->object_uuid.Data3,
3631 value->object_uuid.Data4[0],
3632 value->object_uuid.Data4[1],
3633 value->object_uuid.Data4[2],
3634 value->object_uuid.Data4[3],
3635 value->object_uuid.Data4[4],
3636 value->object_uuid.Data4[5],
3637 value->object_uuid.Data4[6],
3638 value->object_uuid.Data4[7]);
3639 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
3640 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
3641 pi = proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3642 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s", uuid_str);
3643 PROTO_ITEM_SET_GENERATED(pi);
3647 if(value->req_frame!=0){
3649 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3650 tvb, 0, 0, value->req_frame);
3651 PROTO_ITEM_SET_GENERATED(pi);
3652 if(parent_pi != NULL) {
3653 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3655 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
3656 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
3657 PROTO_ITEM_SET_GENERATED(pi);
3659 pi = proto_tree_add_text(dcerpc_tree,
3660 tvb, 0, 0, "No request to this DCE/RPC call found");
3661 expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
3662 "No request to this DCE/RPC call found");
3665 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3666 hdr, di, &auth_info, alloc_hint,
3669 /* no bind information, simply show stub data */
3670 pi = proto_tree_add_text(dcerpc_tree, tvb, offset, 0, "No bind info for this interface Context ID - capture start too late?");
3671 PROTO_ITEM_SET_GENERATED(pi);
3672 expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u (Call ID:%u)",
3673 ctx_id, hdr->call_id);
3674 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3678 /* Dissect the verifier */
3679 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3683 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3684 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3686 dcerpc_call_value *value = NULL;
3687 conversation_t *conv;
3691 dcerpc_auth_info auth_info;
3692 proto_item *pi = NULL;
3694 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3695 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3697 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3698 hf_dcerpc_cn_ctx_id, &ctx_id);
3700 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
3701 if(pinfo->dcectxid == 0) {
3702 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
3704 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3705 * prepend a delimiter */
3706 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
3710 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3711 hf_dcerpc_cn_cancel_count, NULL);
3715 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3716 hf_dcerpc_cn_status, &status);*/
3717 status = ((hdr->drep[0] & 0x10)
3718 ? tvb_get_letohl (tvb, offset)
3719 : tvb_get_ntohl (tvb, offset));
3722 pi = proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, (hdr->drep[0] & 0x10));
3726 expert_add_info_format(pinfo, pi, PI_RESPONSE_CODE, PI_NOTE, "Fault: %s",
3727 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3729 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3730 pinfo->dcectxid = ctx_id;
3732 if (check_col (pinfo->cinfo, COL_INFO)) {
3733 col_append_fstr (pinfo->cinfo, COL_INFO,
3734 " ctx_id: %u status: %s", ctx_id,
3735 val_to_str(status, reject_status_vals,
3736 "Unknown (0x%08x)"));
3743 * XXX - what if this was set when the connection was set up,
3744 * and we just have a security context?
3746 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3748 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3749 pinfo->srcport, pinfo->destport, 0);
3751 /* no point in creating one here, really */
3753 dcerpc_matched_key matched_key, *new_matched_key;
3755 /* !!! we can NOT check flags.visited here since this will interact
3756 badly with when SMB handles (i.e. calls the subdissector)
3757 and desegmented pdu's .
3758 Instead we check if this pdu is already in the matched table or not
3760 matched_key.frame = pinfo->fd->num;
3761 matched_key.call_id = hdr->call_id;
3762 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3764 dcerpc_cn_call_key call_key;
3765 dcerpc_call_value *call_value;
3768 call_key.call_id=hdr->call_id;
3769 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3771 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3772 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3773 *new_matched_key = matched_key;
3774 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3776 if(call_value->rep_frame==0){
3777 call_value->rep_frame=pinfo->fd->num;
3784 int length, reported_length, stub_length;
3786 proto_item *parent_pi;
3789 /* handoff this call */
3791 di->call_id = hdr->call_id;
3792 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3793 di->ptype = PDU_FAULT;
3794 di->call_data = value;
3796 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3797 if(value->req_frame!=0){
3799 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3800 tvb, 0, 0, value->req_frame);
3801 PROTO_ITEM_SET_GENERATED(pi);
3802 parent_pi = proto_tree_get_parent(dcerpc_tree);
3803 if(parent_pi != NULL) {
3804 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3806 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
3807 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
3808 PROTO_ITEM_SET_GENERATED(pi);
3810 pi = proto_tree_add_text(dcerpc_tree,
3811 tvb, 0, 0, "No request to this DCE/RPC call found");
3812 expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
3813 "No request to this DCE/RPC call found");
3816 length = tvb_length_remaining(tvb, offset);
3817 reported_length = tvb_reported_length_remaining(tvb, offset);
3818 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
3819 * stub_data, the following calculation is no longer valid:
3820 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
3821 * simply use the remaining length of the tvb instead.
3822 * XXX - or better use the reported_length?!?
3824 stub_length = length;
3825 if (length > stub_length)
3826 length = stub_length;
3827 if (reported_length > stub_length)
3828 reported_length = stub_length;
3830 /* If we don't have reassembly enabled, or this packet contains
3831 the entire PDU, or if we don't have all the data in this
3832 fragment, just call the handoff directly if this is the
3833 first fragment or the PDU isn't fragmented. */
3834 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3835 !tvb_bytes_exist(tvb, offset, stub_length) ){
3836 if(hdr->flags&PFC_FIRST_FRAG){
3837 /* First fragment, possibly the only fragment */
3839 * XXX - should there be a third routine for each
3840 * function in an RPC subdissector, to handle
3841 * fault responses? The DCE RPC 1.1 spec says
3842 * three's "stub data" here, which I infer means
3843 * that it's protocol-specific and call-specific.
3845 * It should probably get passed the status code
3846 * as well, as that might be protocol-specific.
3849 if (stub_length > 0) {
3850 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3851 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3852 "Fault stub data (%d byte%s)",
3854 plurality(stub_length, "", "s"));
3858 /* PDU is fragmented and this isn't the first fragment */
3859 if (check_col(pinfo->cinfo, COL_INFO)) {
3860 col_append_fstr(pinfo->cinfo, COL_INFO,
3861 " [DCE/RPC fragment]");
3864 if (stub_length > 0) {
3865 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3866 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3867 "Fragment data (%d byte%s)",
3869 plurality(stub_length, "", "s"));
3874 /* Reassembly is enabled, the PDU is fragmented, and
3875 we have all the data in the fragment; the first two
3876 of those mean we should attempt reassembly, and the
3877 third means we can attempt reassembly. */
3880 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3881 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3882 "Fragment data (%d byte%s)",
3884 plurality(stub_length, "", "s"));
3887 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
3888 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3889 fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
3890 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3894 if (check_col(pinfo->cinfo, COL_INFO)) {
3895 col_append_fstr(pinfo->cinfo, COL_INFO,
3896 " [DCE/RPC fragment]");
3898 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
3899 if( value->rep_frame ){
3900 fragment_data *fd_head;
3902 fd_head = fragment_add_seq_next(tvb, offset, pinfo,
3904 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3909 /* We completed reassembly */
3911 proto_item *frag_tree_item;
3913 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
3914 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
3915 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3916 show_fragment_tree(fd_head, &dcerpc_frag_items,
3917 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
3920 * XXX - should there be a third routine for each
3921 * function in an RPC subdissector, to handle
3922 * fault responses? The DCE RPC 1.1 spec says
3923 * three's "stub data" here, which I infer means
3924 * that it's protocol-specific and call-specific.
3926 * It should probably get passed the status code
3927 * as well, as that might be protocol-specific.
3931 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3932 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3933 "Fault stub data (%d byte%s)",
3935 plurality(stub_length, "", "s"));
3939 /* Reassembly not complete - some fragments
3941 if (check_col(pinfo->cinfo, COL_INFO)) {
3942 col_append_fstr(pinfo->cinfo, COL_INFO,
3943 " [DCE/RPC fragment]");
3947 } else { /* MIDDLE fragment(s) */
3948 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3949 fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
3950 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3954 if (check_col(pinfo->cinfo, COL_INFO)) {
3955 col_append_fstr(pinfo->cinfo, COL_INFO,
3956 " [DCE/RPC fragment]");
3965 * DCERPC dissector for connection oriented calls.
3966 * We use transport type to later multiplex between what kind of
3967 * pinfo->private_data structure to expect.
3970 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3971 proto_tree *tree, gboolean can_desegment, int *pkt_len)
3973 static const guint8 nulls[4] = { 0 };
3976 proto_item *ti = NULL;
3977 proto_item *tf = NULL;
3978 proto_tree *dcerpc_tree = NULL;
3979 proto_tree *cn_flags_tree = NULL;
3980 proto_tree *drep_tree = NULL;
3981 e_dce_cn_common_hdr_t hdr;
3982 dcerpc_auth_info auth_info;
3983 tvbuff_t *fragment_tvb;
3986 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3987 * data for some reason.
3989 * XXX - if that's always the case, the right way to do this would
3990 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3991 * the 4 bytes of null padding, and make that the dissector
3992 * used for "netbios".
3994 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
4003 * Check if this looks like a C/O DCERPC call
4005 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
4006 return FALSE; /* not enough information to check */
4008 start_offset = offset;
4009 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
4010 if (hdr.rpc_ver != 5)
4012 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
4013 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
4015 hdr.ptype = tvb_get_guint8 (tvb, offset++);
4019 hdr.flags = tvb_get_guint8 (tvb, offset++);
4020 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4021 offset += sizeof (hdr.drep);
4023 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4025 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4027 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4030 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
4031 if(pinfo->dcectxid == 0) {
4032 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
4034 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4035 * prepend a delimiter */
4036 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
4040 if (can_desegment && pinfo->can_desegment
4041 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
4042 pinfo->desegment_offset = start_offset;
4043 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
4044 *pkt_len = 0; /* desegmentation required */
4048 if (check_col (pinfo->cinfo, COL_PROTOCOL))
4049 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4051 if (check_col (pinfo->cinfo, COL_INFO)) {
4052 if(pinfo->dcectxid != 0) {
4053 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
4054 * append a delimiter and set a column fence */
4055 col_append_str (pinfo->cinfo, COL_INFO, " # ");
4056 col_set_fence(pinfo->cinfo,COL_INFO);
4058 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
4059 pckt_vals[hdr.ptype].strptr, hdr.call_id);
4062 if(pinfo->dcectxid != 0) {
4063 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
4064 expert_add_info_format(pinfo, NULL, PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet");
4067 offset = start_offset;
4068 tvb_ensure_bytes_exist(tvb, offset, 16);
4070 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
4071 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
4074 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4077 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
4080 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4083 /* XXX - too much "output noise", removed for now
4084 if(hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
4085 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
4086 expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_CHAT, "Context change: %s",
4087 val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));*/
4088 if(hdr.ptype == PDU_BIND_NAK)
4089 expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_WARN, "Bind not acknowledged");
4092 proto_item_append_text(ti, " %s, Fragment:", val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"));
4094 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
4095 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
4097 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
4098 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
4099 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
4100 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
4101 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
4102 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
4103 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
4104 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
4105 if( (hdr.flags & PFC_FIRST_FRAG) && (hdr.flags & PFC_LAST_FRAG) ) {
4106 proto_item_append_text(ti, " Single");
4108 if(hdr.flags & PFC_FIRST_FRAG) {
4109 proto_item_append_text(ti, " 1st");
4111 if(hdr.flags & PFC_LAST_FRAG) {
4112 proto_item_append_text(ti, " Last");
4114 if( !(hdr.flags & PFC_FIRST_FRAG) && !(hdr.flags & PFC_LAST_FRAG) ) {
4115 proto_item_append_text(ti, " Mid");
4121 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
4122 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4124 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4125 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4126 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4127 offset += sizeof (hdr.drep);
4129 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
4132 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
4135 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
4139 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
4143 * None of the stuff done above should throw an exception, because
4144 * we would have rejected this as "not DCE RPC" if we didn't have all
4145 * of it. (XXX - perhaps we should request reassembly if we have
4146 * enough of the header to consider it DCE RPC but not enough to
4147 * get the fragment length; in that case the stuff still wouldn't
4148 * throw an exception.)
4150 * The rest of the stuff might, so return the PDU length to our caller.
4151 * XXX - should we construct a tvbuff containing only the PDU and
4152 * use that? Or should we have separate "is this a DCE RPC PDU",
4153 * "how long is it", and "dissect it" routines - which might let us
4154 * do most of the work in "tcp_dissect_pdus()"?
4156 if (pkt_len != NULL)
4157 *pkt_len = hdr.frag_len + padding;
4159 /* The remaining bytes in the current tvb might contain multiple
4160 * DCE/RPC fragments, so create a new tvb subset for this fragment.
4161 * Only limit the end of the fragment, but not the offset start,
4162 * as the authentication function dissect_dcerpc_cn_auth() will fail
4163 * (and other functions might fail as well) computing the right start
4166 fragment_tvb = tvb_new_subset(tvb, 0,
4167 MIN((hdr.frag_len + (guint) start_offset), tvb_length(tvb)) /* length */,
4168 hdr.frag_len + start_offset /* reported_length */);
4171 * Packet type specific stuff is next.
4173 switch (hdr.ptype) {
4176 dissect_dcerpc_cn_bind (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4181 dissect_dcerpc_cn_bind_ack (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4186 * Nothing after the common header other than credentials.
4188 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
4193 dissect_dcerpc_cn_rqst (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4197 dissect_dcerpc_cn_resp (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4201 dissect_dcerpc_cn_fault (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4205 dissect_dcerpc_cn_bind_nak (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4211 * Nothing after the common header other than an authentication
4214 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4220 * Nothing after the common header, not even an authentication
4226 /* might as well dissect the auth info */
4227 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4235 * DCERPC dissector for connection oriented calls over packet-oriented
4239 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4242 * Only one PDU per transport packet, and only one transport
4245 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4246 if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
4248 * It wasn't a DCERPC PDU.
4260 * DCERPC dissector for connection oriented calls over byte-stream
4262 * we need to distinguish here between SMB and non-TCP (more in the future?)
4263 * to be able to know what kind of private_data structure to expect.
4266 dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4268 volatile int offset = 0;
4270 volatile gboolean dcerpc_pdus = 0;
4271 volatile gboolean ret = FALSE;
4274 * There may be multiple PDUs per transport packet; keep
4277 while (tvb_reported_length_remaining(tvb, offset) != 0) {
4279 * Catch ReportedBoundsError, so that even if the stub data is bad,
4280 * we don't abort the full DCE RPC dissection - there might be more
4281 * than one DCE RPC PDU in the data being dissected.
4283 * If we get BoundsError, it means the frame was cut short by a
4284 * snapshot length, so there's nothing more to dissect; just
4285 * re-throw that exception.
4289 if(dissect_dcerpc_cn (tvb, offset, pinfo, tree,
4290 dcerpc_cn_desegment, &pdu_len)) {
4293 } CATCH(BoundsError) {
4295 } CATCH(ReportedBoundsError) {
4296 show_reported_bounds_error(tvb, pinfo, tree);
4298 * Presumably it looked enough like a DCE RPC PDU that we
4299 * dissected enough of it to throw an exception.
4312 * Well, we've seen at least one DCERPC PDU.
4316 /* if we had more than one Req/Resp in this PDU change the protocol column */
4317 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
4318 if (dcerpc_pdus >= 2 && check_col (pinfo->cinfo, COL_PROTOCOL))
4319 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
4323 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
4325 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
4327 tvb_reported_length_remaining(tvb, offset),
4328 "[DCE RPC: %u byte%s left, desegmentation might follow]",
4329 tvb_reported_length_remaining(tvb, offset),
4330 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
4335 * Step to the next PDU.
4343 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4345 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4346 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4350 dissect_dcerpc_cn_smbpipe (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4352 pinfo->dcetransporttype=DCE_CN_TRANSPORT_SMBPIPE;
4353 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4357 dissect_dcerpc_cn_smb2 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4359 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4360 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4366 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
4367 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
4369 proto_item *ti = NULL;
4370 proto_tree *auth_tree = NULL;
4371 guint8 protection_level;
4374 * Initially set "*auth_level_p" to -1 to indicate that we haven't
4375 * yet seen any authentication level information.
4377 if (auth_level_p != NULL)
4381 * The authentication information is at the *end* of the PDU; in
4382 * request and response PDUs, the request and response stub data
4385 * If the full packet is here, and there's data past the end of the
4386 * packet body, then dissect the auth info.
4388 offset += hdr->frag_len;
4389 if (tvb_length_remaining(tvb, offset) > 0) {
4390 switch (hdr->auth_proto) {
4392 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
4393 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
4394 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
4395 protection_level = tvb_get_guint8 (tvb, offset);
4396 if (auth_level_p != NULL)
4397 *auth_level_p = protection_level;
4398 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
4400 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
4402 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
4403 offset += 6; /* 6 bytes of padding */
4405 offset += 2; /* 6 bytes of padding */
4406 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
4411 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
4418 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4419 proto_tree *dcerpc_tree,
4420 e_dce_dg_common_hdr_t *hdr)
4424 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4425 hdr->drep, hf_dcerpc_dg_cancel_vers,
4431 /* The only version we know about */
4432 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4433 hdr->drep, hf_dcerpc_dg_cancel_id,
4435 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4436 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4443 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
4444 proto_tree *dcerpc_tree,
4445 e_dce_dg_common_hdr_t *hdr)
4449 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4450 hdr->drep, hf_dcerpc_dg_cancel_vers,
4456 /* The only version we know about */
4457 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4458 hdr->drep, hf_dcerpc_dg_cancel_id,
4460 /* XXX - are NDR booleans 32 bits? */
4462 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
4463 the accepting_cancels field (it's only in the cancel_ack PDU)! */
4464 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4465 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4472 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4473 proto_tree *dcerpc_tree,
4474 e_dce_dg_common_hdr_t *hdr)
4481 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4482 hdr->drep, hf_dcerpc_dg_fack_vers,
4489 case 0: /* The only version documented in the DCE RPC 1.1 spec */
4490 case 1: /* This appears to be the same */
4491 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4492 hdr->drep, hf_dcerpc_dg_fack_window_size,
4494 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4495 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
4497 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4498 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
4500 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4501 hdr->drep, hf_dcerpc_dg_fack_serial_num,
4503 if (check_col (pinfo->cinfo, COL_INFO)) {
4504 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4507 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4508 hdr->drep, hf_dcerpc_dg_fack_selack_len,
4510 for (i = 0; i < selack_len; i++) {
4511 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4512 hdr->drep, hf_dcerpc_dg_fack_selack,
4521 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
4522 proto_tree *dcerpc_tree,
4523 e_dce_dg_common_hdr_t *hdr)
4527 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4528 hdr->drep, hf_dcerpc_dg_status,
4531 if (check_col (pinfo->cinfo, COL_INFO)) {
4532 col_append_fstr (pinfo->cinfo, COL_INFO,
4534 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4539 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
4540 proto_tree *dcerpc_tree, proto_tree *tree,
4541 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
4543 int length, reported_length, stub_length;
4544 gboolean save_fragmented;
4545 fragment_data *fd_head;
4548 proto_item *parent_pi;
4550 if (check_col (pinfo->cinfo, COL_INFO))
4551 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
4552 di->call_data->opnum, hdr->frag_len );
4554 length = tvb_length_remaining (tvb, offset);
4555 reported_length = tvb_reported_length_remaining (tvb, offset);
4556 stub_length = hdr->frag_len;
4557 if (length > stub_length)
4558 length = stub_length;
4559 if (reported_length > stub_length)
4560 reported_length = stub_length;
4562 save_fragmented = pinfo->fragmented;
4564 /* If we don't have reassembly enabled, or this packet contains
4565 the entire PDU, or if this is a short frame (or a frame
4566 not reassembled at a lower layer) that doesn't include all
4567 the data in the fragment, just call the handoff directly if
4568 this is the first fragment or the PDU isn't fragmented. */
4569 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
4570 !tvb_bytes_exist(tvb, offset, stub_length) ){
4571 if(hdr->frag_num == 0) {
4574 /* First fragment, possibly the only fragment */
4577 * XXX - authentication info?
4579 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
4580 next_tvb = tvb_new_subset (tvb, offset, length,
4582 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4583 next_tvb, hdr->drep, di, NULL);
4585 /* PDU is fragmented and this isn't the first fragment */
4586 if (check_col(pinfo->cinfo, COL_INFO)) {
4587 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4591 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4592 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4593 "Fragment data (%d byte%s)",
4595 plurality(stub_length, "", "s"));
4600 /* Reassembly is enabled, the PDU is fragmented, and
4601 we have all the data in the fragment; the first two
4602 of those mean we should attempt reassembly, and the
4603 third means we can attempt reassembly. */
4606 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4607 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4608 "Fragment data (%d byte%s)", stub_length,
4609 plurality(stub_length, "", "s"));
4613 fd_head = fragment_add_dcerpc_dg(tvb, offset, pinfo,
4614 hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table,
4615 hdr->frag_num, stub_length,
4616 !(hdr->flags1 & PFCL1_LASTFRAG));
4617 if (fd_head != NULL) {
4618 /* We completed reassembly... */
4619 if(pinfo->fd->num==fd_head->reassembled_in) {
4620 /* ...and this is the reassembled RPC PDU */
4621 next_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
4622 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
4623 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4624 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
4625 tree, pinfo, next_tvb, &pi);
4628 * XXX - authentication info?
4630 pinfo->fragmented = FALSE;
4631 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4632 next_tvb, hdr->drep, di, NULL);
4634 /* ...and this isn't the reassembled RPC PDU */
4635 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4636 tvb, 0, 0, fd_head->reassembled_in);
4637 PROTO_ITEM_SET_GENERATED(pi);
4638 parent_pi = proto_tree_get_parent(dcerpc_tree);
4639 if(parent_pi != NULL) {
4640 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
4642 if (check_col(pinfo->cinfo, COL_INFO)) {
4643 col_append_fstr(pinfo->cinfo, COL_INFO,
4644 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
4648 /* Reassembly isn't completed yet */
4649 if (check_col(pinfo->cinfo, COL_INFO)) {
4650 col_append_fstr(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4654 pinfo->fragmented = save_fragmented;
4658 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
4659 proto_tree *dcerpc_tree, proto_tree *tree,
4660 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4663 dcerpc_call_value *value, v;
4664 dcerpc_matched_key matched_key, *new_matched_key;
4666 proto_item *parent_pi;
4669 if(!(pinfo->fd->flags.visited)){
4670 dcerpc_call_value *call_value;
4671 dcerpc_dg_call_key *call_key;
4673 call_key=se_alloc (sizeof (dcerpc_dg_call_key));
4674 call_key->conv=conv;
4675 call_key->seqnum=hdr->seqnum;
4676 call_key->act_id=hdr->act_id;
4678 call_value=se_alloc (sizeof (dcerpc_call_value));
4679 call_value->uuid = hdr->if_id;
4680 call_value->ver = hdr->if_ver;
4681 call_value->object_uuid = hdr->obj_id;
4682 call_value->opnum = hdr->opnum;
4683 call_value->req_frame=pinfo->fd->num;
4684 call_value->req_time=pinfo->fd->abs_ts;
4685 call_value->rep_frame=0;
4686 call_value->max_ptr=0;
4687 call_value->private_data = NULL;
4688 g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
4690 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
4691 new_matched_key->frame = pinfo->fd->num;
4692 new_matched_key->call_id = hdr->seqnum;
4693 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4696 matched_key.frame = pinfo->fd->num;
4697 matched_key.call_id = hdr->seqnum;
4698 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4700 v.uuid = hdr->if_id;
4701 v.ver = hdr->if_ver;
4702 v.object_uuid = hdr->obj_id;
4703 v.opnum = hdr->opnum;
4704 v.req_frame = pinfo->fd->num;
4707 v.private_data=NULL;
4712 di->call_id = hdr->seqnum;
4714 di->ptype = PDU_REQ;
4715 di->call_data = value;
4717 if(value->rep_frame!=0){
4718 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4719 tvb, 0, 0, value->rep_frame);
4720 PROTO_ITEM_SET_GENERATED(pi);
4721 parent_pi = proto_tree_get_parent(dcerpc_tree);
4722 if(parent_pi != NULL) {
4723 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
4726 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4730 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
4731 proto_tree *dcerpc_tree, proto_tree *tree,
4732 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4735 dcerpc_call_value *value, v;
4736 dcerpc_matched_key matched_key, *new_matched_key;
4738 proto_item *parent_pi;
4741 if(!(pinfo->fd->flags.visited)){
4742 dcerpc_call_value *call_value;
4743 dcerpc_dg_call_key call_key;
4746 call_key.seqnum=hdr->seqnum;
4747 call_key.act_id=hdr->act_id;
4749 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4750 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
4751 new_matched_key->frame = pinfo->fd->num;
4752 new_matched_key->call_id = hdr->seqnum;
4753 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4754 if(call_value->rep_frame==0){
4755 call_value->rep_frame=pinfo->fd->num;
4760 matched_key.frame = pinfo->fd->num;
4761 matched_key.call_id = hdr->seqnum;
4762 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4764 v.uuid = hdr->if_id;
4765 v.ver = hdr->if_ver;
4766 v.object_uuid = hdr->obj_id;
4767 v.opnum = hdr->opnum;
4769 v.rep_frame=pinfo->fd->num;
4770 v.private_data=NULL;
4777 di->ptype = PDU_RESP;
4778 di->call_data = value;
4780 if(value->req_frame!=0){
4782 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4783 tvb, 0, 0, value->req_frame);
4784 PROTO_ITEM_SET_GENERATED(pi);
4785 parent_pi = proto_tree_get_parent(dcerpc_tree);
4786 if(parent_pi != NULL) {
4787 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4789 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4790 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4791 PROTO_ITEM_SET_GENERATED(pi);
4793 pi = proto_tree_add_text(dcerpc_tree,
4794 tvb, 0, 0, "No request to this DCE/RPC call found");
4795 expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
4796 "No request to this DCE/RPC call found");
4798 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4802 dissect_dcerpc_dg_ping_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4803 proto_tree *dcerpc_tree,
4804 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4806 proto_item *parent_pi;
4807 /* if(!(pinfo->fd->flags.visited)){*/
4808 dcerpc_call_value *call_value;
4809 dcerpc_dg_call_key call_key;
4812 call_key.seqnum=hdr->seqnum;
4813 call_key.act_id=hdr->act_id;
4815 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4819 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4820 tvb, 0, 0, call_value->req_frame);
4821 PROTO_ITEM_SET_GENERATED(pi);
4822 parent_pi = proto_tree_get_parent(dcerpc_tree);
4823 if(parent_pi != NULL) {
4824 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
4827 if (check_col (pinfo->cinfo, COL_INFO))
4828 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
4830 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
4831 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4832 PROTO_ITEM_SET_GENERATED(pi);
4838 * DCERPC dissector for connectionless calls
4841 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4843 proto_item *ti = NULL;
4844 proto_item *tf = NULL;
4845 proto_tree *dcerpc_tree = NULL;
4846 proto_tree *dg_flags1_tree = NULL;
4847 proto_tree *dg_flags2_tree = NULL;
4848 proto_tree *drep_tree = NULL;
4849 e_dce_dg_common_hdr_t hdr;
4851 conversation_t *conv;
4853 char uuid_str[DCERPC_UUID_STR_LEN];
4857 * Check if this looks like a CL DCERPC call. All dg packets
4858 * have an 80 byte header on them. Which starts with
4859 * version (4), pkt_type.
4861 if (!tvb_bytes_exist (tvb, 0, sizeof (hdr))) {
4865 /* Version must be 4 */
4866 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
4867 if (hdr.rpc_ver != 4)
4870 /* Type must be <=19 or its not DCE/RPC */
4871 hdr.ptype = tvb_get_guint8 (tvb, offset++);
4875 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
4876 probably not a DCE/RPC packet
4878 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
4882 /* flags2 has all bits except bit 2 as reserved so if any of them are set
4883 it is probably not DCE/RPC.
4885 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
4890 if (check_col (pinfo->cinfo, COL_PROTOCOL))
4891 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4892 if (check_col (pinfo->cinfo, COL_INFO))
4893 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
4895 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4896 offset += sizeof (hdr.drep);
4897 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
4898 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
4900 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
4902 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
4904 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4906 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4908 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4910 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4912 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4914 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4916 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4918 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4920 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
4921 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
4924 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
4926 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4927 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
4928 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
4929 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
4930 hdr.frag_num, hdr.frag_len);
4936 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4940 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4944 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
4945 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
4946 if (dg_flags1_tree) {
4947 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
4948 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
4949 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
4950 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
4951 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
4952 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
4953 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
4954 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
4956 proto_item_append_text(tf, " %s%s%s%s%s%s",
4957 (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
4958 (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
4959 (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
4960 (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
4961 (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
4962 (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
4969 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
4970 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
4971 if (dg_flags2_tree) {
4972 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
4973 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
4974 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
4975 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
4976 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
4977 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
4978 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
4979 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
4981 proto_item_append_text(tf, " %s",
4982 (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
4989 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
4990 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4992 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4993 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4994 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4995 proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
4996 val_to_str(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
4997 val_to_str(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
4998 val_to_str(hdr.drep[1], drep_fp_vals, "Unknown"));
5001 offset += sizeof (hdr.drep);
5004 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
5008 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
5009 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
5010 hdr.obj_id.Data1, hdr.obj_id.Data2, hdr.obj_id.Data3,
5011 hdr.obj_id.Data4[0],
5012 hdr.obj_id.Data4[1],
5013 hdr.obj_id.Data4[2],
5014 hdr.obj_id.Data4[3],
5015 hdr.obj_id.Data4[4],
5016 hdr.obj_id.Data4[5],
5017 hdr.obj_id.Data4[6],
5018 hdr.obj_id.Data4[7]);
5019 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
5020 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
5021 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
5022 offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s", uuid_str);
5027 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
5028 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
5029 hdr.if_id.Data1, hdr.if_id.Data2, hdr.if_id.Data3,
5037 hdr.if_id.Data4[7]);
5038 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
5039 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
5040 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
5041 offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s", uuid_str);
5046 uuid_str_len = g_snprintf(uuid_str, DCERPC_UUID_STR_LEN,
5047 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
5048 hdr.act_id.Data1, hdr.act_id.Data2, hdr.act_id.Data3,
5049 hdr.act_id.Data4[0],
5050 hdr.act_id.Data4[1],
5051 hdr.act_id.Data4[2],
5052 hdr.act_id.Data4[3],
5053 hdr.act_id.Data4[4],
5054 hdr.act_id.Data4[5],
5055 hdr.act_id.Data4[6],
5056 hdr.act_id.Data4[7]);
5057 if (uuid_str_len == -1 || uuid_str_len >= DCERPC_UUID_STR_LEN)
5058 memset(uuid_str, 0, DCERPC_UUID_STR_LEN);
5059 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
5060 offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s", uuid_str);
5065 nstime_t server_boot;
5067 server_boot.secs = hdr.server_boot;
5068 server_boot.nsecs = 0;
5070 if (hdr.server_boot == 0)
5071 proto_tree_add_time_format (dcerpc_tree, hf_dcerpc_dg_server_boot,
5072 tvb, offset, 4, &server_boot,
5073 "Server boot time: Unknown (0)");
5075 proto_tree_add_time (dcerpc_tree, hf_dcerpc_dg_server_boot,
5076 tvb, offset, 4, &server_boot);
5081 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
5085 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
5086 if (check_col (pinfo->cinfo, COL_INFO)) {
5087 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
5089 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
5090 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
5095 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
5099 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
5103 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
5107 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
5111 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
5112 if (check_col (pinfo->cinfo, COL_INFO)) {
5113 if (hdr.flags1 & PFCL1_FRAG) {
5114 /* Fragmented - put the fragment number into the Info column */
5115 col_append_fstr (pinfo->cinfo, COL_INFO, " frag: %u",
5122 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
5126 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
5127 if (check_col (pinfo->cinfo, COL_INFO)) {
5128 if (hdr.flags1 & PFCL1_FRAG) {
5129 /* Fragmented - put the serial number into the Info column */
5130 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
5131 (hdr.serial_hi << 8) | hdr.serial_lo);
5138 * XXX - for Kerberos, we get a protection level; if it's
5139 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
5142 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
5147 * keeping track of the conversation shouldn't really be necessary
5148 * for connectionless packets, because everything we need to know
5149 * to dissect is in the header for each packet. Unfortunately,
5150 * Microsoft's implementation is buggy and often puts the
5151 * completely wrong if_id in the header. go figure. So, keep
5152 * track of the seqnum and use that if possible. Note: that's not
5153 * completely correct. It should really be done based on both the
5154 * activity_id and seqnum. I haven't seen anywhere that it would
5155 * make a difference, but for future reference...
5157 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
5158 pinfo->srcport, pinfo->destport, 0);
5160 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
5161 pinfo->srcport, pinfo->destport, 0);
5165 * Packet type specific stuff is next.
5168 switch (hdr.ptype) {
5170 case PDU_CANCEL_ACK:
5171 /* Body is optional */
5172 /* XXX - we assume "frag_len" is the length of the body */
5173 if (hdr.frag_len != 0)
5174 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5179 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
5180 * but in at least one capture none of the Cl_cancel PDUs had a
5183 /* XXX - we assume "frag_len" is the length of the body */
5184 if (hdr.frag_len != 0)
5185 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
5189 /* Body is optional; if present, it's the same as PDU_FACK */
5190 /* XXX - we assume "frag_len" is the length of the body */
5191 if (hdr.frag_len != 0)
5192 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5196 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5201 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
5205 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5209 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5212 /* these requests have no body */
5215 dissect_dcerpc_dg_ping_ack (tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
5226 dcerpc_init_protocol (void)
5228 /* structures and data for BIND */
5230 g_hash_table_destroy (dcerpc_binds);
5234 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
5237 /* structures and data for CALL */
5238 if (dcerpc_cn_calls){
5239 g_hash_table_destroy (dcerpc_cn_calls);
5241 dcerpc_cn_calls = g_hash_table_new (dcerpc_cn_call_hash, dcerpc_cn_call_equal);
5242 if (dcerpc_dg_calls){
5243 g_hash_table_destroy (dcerpc_dg_calls);
5245 dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal);
5247 /* structure and data for MATCHED */
5248 if (dcerpc_matched){
5249 g_hash_table_destroy (dcerpc_matched);
5251 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
5253 /* call the registered hooks */
5254 g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
5258 proto_register_dcerpc (void)
5260 static hf_register_info hf[] = {
5261 { &hf_dcerpc_request_in,
5262 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
5263 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
5264 { &hf_dcerpc_response_in,
5265 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
5266 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
5267 { &hf_dcerpc_referent_id,
5268 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
5269 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
5271 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5272 { &hf_dcerpc_ver_minor,
5273 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5274 { &hf_dcerpc_packet_type,
5275 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, "", HFILL }},
5276 { &hf_dcerpc_cn_flags,
5277 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5278 { &hf_dcerpc_cn_flags_first_frag,
5279 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_FIRST_FRAG, "", HFILL }},
5280 { &hf_dcerpc_cn_flags_last_frag,
5281 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_LAST_FRAG, "", HFILL }},
5282 { &hf_dcerpc_cn_flags_cancel_pending,
5283 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_PENDING_CANCEL, "", HFILL }},
5284 { &hf_dcerpc_cn_flags_reserved,
5285 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_RESERVED_1, "", HFILL }},
5286 { &hf_dcerpc_cn_flags_mpx,
5287 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_CONC_MPX, "", HFILL }},
5288 { &hf_dcerpc_cn_flags_dne,
5289 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_DID_NOT_EXECUTE, "", HFILL }},
5290 { &hf_dcerpc_cn_flags_maybe,
5291 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_MAYBE, "", HFILL }},
5292 { &hf_dcerpc_cn_flags_object,
5293 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFC_OBJECT_UUID, "", HFILL }},
5295 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_HEX, NULL, 0x0, "", HFILL }},
5296 { &hf_dcerpc_drep_byteorder,
5297 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, "", HFILL }},
5298 { &hf_dcerpc_drep_character,
5299 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, "", HFILL }},
5300 { &hf_dcerpc_drep_fp,
5301 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, "", HFILL }},
5302 { &hf_dcerpc_cn_frag_len,
5303 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5304 { &hf_dcerpc_cn_auth_len,
5305 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5306 { &hf_dcerpc_cn_call_id,
5307 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5308 { &hf_dcerpc_cn_max_xmit,
5309 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5310 { &hf_dcerpc_cn_max_recv,
5311 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5312 { &hf_dcerpc_cn_assoc_group,
5313 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
5314 { &hf_dcerpc_cn_num_ctx_items,
5315 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5316 { &hf_dcerpc_cn_ctx_item,
5317 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
5318 { &hf_dcerpc_cn_ctx_id,
5319 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5320 { &hf_dcerpc_cn_num_trans_items,
5321 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5322 { &hf_dcerpc_cn_bind_abstract_syntax,
5323 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
5324 { &hf_dcerpc_cn_bind_if_id,
5325 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, "", HFILL }},
5326 { &hf_dcerpc_cn_bind_if_ver,
5327 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5328 { &hf_dcerpc_cn_bind_if_ver_minor,
5329 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5330 { &hf_dcerpc_cn_bind_trans_syntax,
5331 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, "", HFILL }},
5332 { &hf_dcerpc_cn_bind_trans_id,
5333 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, "", HFILL }},
5334 { &hf_dcerpc_cn_bind_trans_ver,
5335 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5336 { &hf_dcerpc_cn_alloc_hint,
5337 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5338 { &hf_dcerpc_cn_sec_addr_len,
5339 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5340 { &hf_dcerpc_cn_sec_addr,
5341 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, "", HFILL }},
5342 { &hf_dcerpc_cn_num_results,
5343 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5344 { &hf_dcerpc_cn_ack_result,
5345 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, "", HFILL }},
5346 { &hf_dcerpc_cn_ack_reason,
5347 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, "", HFILL }},
5348 { &hf_dcerpc_cn_ack_trans_id,
5349 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, "", HFILL }},
5350 { &hf_dcerpc_cn_ack_trans_ver,
5351 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5352 { &hf_dcerpc_cn_reject_reason,
5353 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, "", HFILL }},
5354 { &hf_dcerpc_cn_num_protocols,
5355 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5356 { &hf_dcerpc_cn_protocol_ver_major,
5357 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5358 { &hf_dcerpc_cn_protocol_ver_minor,
5359 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5360 { &hf_dcerpc_cn_cancel_count,
5361 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5362 { &hf_dcerpc_cn_status,
5363 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
5364 { &hf_dcerpc_cn_deseg_req,
5365 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5366 { &hf_dcerpc_auth_type,
5367 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
5368 { &hf_dcerpc_auth_level,
5369 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, "", HFILL }},
5370 { &hf_dcerpc_auth_pad_len,
5371 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5372 { &hf_dcerpc_auth_rsrvd,
5373 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5374 { &hf_dcerpc_auth_ctx_id,
5375 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5376 { &hf_dcerpc_dg_flags1,
5377 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5378 { &hf_dcerpc_dg_flags1_rsrvd_01,
5379 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_01, "", HFILL }},
5380 { &hf_dcerpc_dg_flags1_last_frag,
5381 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_LASTFRAG, "", HFILL }},
5382 { &hf_dcerpc_dg_flags1_frag,
5383 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_FRAG, "", HFILL }},
5384 { &hf_dcerpc_dg_flags1_nofack,
5385 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_NOFACK, "", HFILL }},
5386 { &hf_dcerpc_dg_flags1_maybe,
5387 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_MAYBE, "", HFILL }},
5388 { &hf_dcerpc_dg_flags1_idempotent,
5389 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_IDEMPOTENT, "", HFILL }},
5390 { &hf_dcerpc_dg_flags1_broadcast,
5391 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_BROADCAST, "", HFILL }},
5392 { &hf_dcerpc_dg_flags1_rsrvd_80,
5393 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL1_RESERVED_80, "", HFILL }},
5394 { &hf_dcerpc_dg_flags2,
5395 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5396 { &hf_dcerpc_dg_flags2_rsrvd_01,
5397 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_01, "", HFILL }},
5398 { &hf_dcerpc_dg_flags2_cancel_pending,
5399 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_CANCEL_PENDING, "", HFILL }},
5400 { &hf_dcerpc_dg_flags2_rsrvd_04,
5401 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_04, "", HFILL }},
5402 { &hf_dcerpc_dg_flags2_rsrvd_08,
5403 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_08, "", HFILL }},
5404 { &hf_dcerpc_dg_flags2_rsrvd_10,
5405 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_10, "", HFILL }},
5406 { &hf_dcerpc_dg_flags2_rsrvd_20,
5407 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_20, "", HFILL }},
5408 { &hf_dcerpc_dg_flags2_rsrvd_40,
5409 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_40, "", HFILL }},
5410 { &hf_dcerpc_dg_flags2_rsrvd_80,
5411 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&flags_set_truth), PFCL2_RESERVED_80, "", HFILL }},
5412 { &hf_dcerpc_dg_serial_lo,
5413 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5414 { &hf_dcerpc_dg_serial_hi,
5415 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
5416 { &hf_dcerpc_dg_ahint,
5417 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5418 { &hf_dcerpc_dg_ihint,
5419 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
5420 { &hf_dcerpc_dg_frag_len,
5421 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5422 { &hf_dcerpc_dg_frag_num,
5423 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5424 { &hf_dcerpc_dg_auth_proto,
5425 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, "", HFILL }},
5426 { &hf_dcerpc_dg_seqnum,
5427 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5428 { &hf_dcerpc_dg_server_boot,
5429 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, "", HFILL }},
5430 { &hf_dcerpc_dg_if_ver,
5431 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5432 { &hf_dcerpc_krb5_av_prot_level,
5433 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, "", HFILL }},
5434 { &hf_dcerpc_krb5_av_key_vers_num,
5435 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5436 { &hf_dcerpc_krb5_av_key_auth_verifier,
5437 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL }},
5438 { &hf_dcerpc_obj_id,
5439 { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, "", HFILL }},
5440 { &hf_dcerpc_dg_if_id,
5441 { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, "", HFILL }},
5442 { &hf_dcerpc_dg_act_id,
5443 { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, "", HFILL }},
5445 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5447 { &hf_dcerpc_dg_cancel_vers,
5448 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5450 { &hf_dcerpc_dg_cancel_id,
5451 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5453 { &hf_dcerpc_dg_server_accepting_cancels,
5454 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5456 { &hf_dcerpc_dg_fack_vers,
5457 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
5459 { &hf_dcerpc_dg_fack_window_size,
5460 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5462 { &hf_dcerpc_dg_fack_max_tsdu,
5463 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5465 { &hf_dcerpc_dg_fack_max_frag_size,
5466 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
5468 { &hf_dcerpc_dg_fack_serial_num,
5469 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5471 { &hf_dcerpc_dg_fack_selack_len,
5472 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5474 { &hf_dcerpc_dg_fack_selack,
5475 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
5477 { &hf_dcerpc_dg_status,
5478 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, "", HFILL }},
5480 { &hf_dcerpc_array_max_count,
5481 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
5483 { &hf_dcerpc_array_offset,
5484 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
5486 { &hf_dcerpc_array_actual_count,
5487 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
5489 { &hf_dcerpc_array_buffer,
5490 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
5493 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
5495 { &hf_dcerpc_fragments,
5496 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
5497 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
5499 { &hf_dcerpc_fragment,
5500 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
5501 NULL, 0x0, "DCE/RPC Fragment", HFILL }},
5503 { &hf_dcerpc_fragment_overlap,
5504 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
5505 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
5507 { &hf_dcerpc_fragment_overlap_conflict,
5508 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
5509 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
5511 { &hf_dcerpc_fragment_multiple_tails,
5512 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
5513 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
5515 { &hf_dcerpc_fragment_too_long_fragment,
5516 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
5517 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
5519 { &hf_dcerpc_fragment_error,
5520 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
5521 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
5524 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
5525 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
5527 { &hf_dcerpc_reassembled_in,
5528 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
5529 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
5531 { &hf_dcerpc_unknown_if_id,
5532 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
5534 static gint *ett[] = {
5536 &ett_dcerpc_cn_flags,
5538 &ett_dcerpc_cn_iface,
5539 &ett_dcerpc_cn_trans_syntax,
5541 &ett_dcerpc_dg_flags1,
5542 &ett_dcerpc_dg_flags2,
5543 &ett_dcerpc_pointer_data,
5545 &ett_dcerpc_fragments,
5546 &ett_dcerpc_fragment,
5547 &ett_dcerpc_krb5_auth_verf,
5549 module_t *dcerpc_module;
5551 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
5552 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
5553 proto_register_subtree_array (ett, array_length (ett));
5554 register_init_routine (dcerpc_init_protocol);
5555 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
5556 prefs_register_bool_preference (dcerpc_module,
5558 "Reassemble DCE/RPC messages spanning multiple TCP segments",
5559 "Whether the DCE/RPC dissector should reassemble messages spanning multiple TCP segments."
5560 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
5561 &dcerpc_cn_desegment);
5562 prefs_register_bool_preference (dcerpc_module,
5563 "reassemble_dcerpc",
5564 "Reassemble DCE/RPC fragments",
5565 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
5566 &dcerpc_reassemble);
5567 register_init_routine(dcerpc_reassemble_init);
5568 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
5569 dcerpc_tap=register_tap("dcerpc");
5571 g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
5575 proto_reg_handoff_dcerpc (void)
5577 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
5578 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
5579 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
5580 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
5581 heur_dissector_add ("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2, proto_dcerpc);
5582 heur_dissector_add ("http", dissect_dcerpc_cn_bs, proto_dcerpc);
5583 dcerpc_smb_init(proto_dcerpc);