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>
51 static int dcerpc_tap = -1;
54 static const value_string pckt_vals[] = {
55 { PDU_REQ, "Request"},
57 { PDU_RESP, "Response"},
58 { PDU_FAULT, "Fault"},
59 { PDU_WORKING, "Working"},
60 { PDU_NOCALL, "Nocall"},
61 { PDU_REJECT, "Reject"},
63 { PDU_CL_CANCEL, "Cl_cancel"},
65 { PDU_CANCEL_ACK, "Cancel_ack"},
67 { PDU_BIND_ACK, "Bind_ack"},
68 { PDU_BIND_NAK, "Bind_nak"},
69 { PDU_ALTER, "Alter_context"},
70 { PDU_ALTER_ACK, "Alter_context_resp"},
71 { PDU_AUTH3, "AUTH3"},
72 { PDU_SHUTDOWN, "Shutdown"},
73 { PDU_CO_CANCEL, "Co_cancel"},
74 { PDU_ORPHANED, "Orphaned"},
78 static const value_string drep_byteorder_vals[] = {
80 { 1, "Little-endian" },
84 static const value_string drep_character_vals[] = {
90 #define DCE_RPC_DREP_FP_IEEE 0
91 #define DCE_RPC_DREP_FP_VAX 1
92 #define DCE_RPC_DREP_FP_CRAY 2
93 #define DCE_RPC_DREP_FP_IBM 3
95 static const value_string drep_fp_vals[] = {
96 { DCE_RPC_DREP_FP_IEEE, "IEEE" },
97 { DCE_RPC_DREP_FP_VAX, "VAX" },
98 { DCE_RPC_DREP_FP_CRAY, "Cray" },
99 { DCE_RPC_DREP_FP_IBM, "IBM" },
104 * Authentication services.
106 static const value_string authn_protocol_vals[] = {
107 { DCE_C_RPC_AUTHN_PROTOCOL_NONE, "None" },
108 { DCE_C_RPC_AUTHN_PROTOCOL_KRB5, "Kerberos 5" },
109 { DCE_C_RPC_AUTHN_PROTOCOL_SPNEGO, "SPNEGO" },
110 { DCE_C_RPC_AUTHN_PROTOCOL_NTLMSSP, "NTLMSSP" },
111 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_SCHANNEL, "SCHANNEL SSP" },
112 { DCE_C_RPC_AUTHN_PROTOCOL_GSS_KERBEROS, "Kerberos SSP" },
113 { DCE_C_RPC_AUTHN_PROTOCOL_DPA,
114 "Distributed Password Authentication SSP"},
115 { DCE_C_RPC_AUTHN_PROTOCOL_MSN, "MSN SSP"},
116 { DCE_C_RPC_AUTHN_PROTOCOL_DIGEST, "Digest SSP"},
117 { DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN,"NETLOGON Secure Channel" },
118 { DCE_C_RPC_AUTHN_PROTOCOL_MQ, "MSMQ SSP"},
125 static const value_string authn_level_vals[] = {
126 { DCE_C_AUTHN_LEVEL_NONE, "None" },
127 { DCE_C_AUTHN_LEVEL_CONNECT, "Connect" },
128 { DCE_C_AUTHN_LEVEL_CALL, "Call" },
129 { DCE_C_AUTHN_LEVEL_PKT, "Packet" },
130 { DCE_C_AUTHN_LEVEL_PKT_INTEGRITY, "Packet integrity" },
131 { DCE_C_AUTHN_LEVEL_PKT_PRIVACY, "Packet privacy" },
136 * Flag bits in first flag field in connectionless PDU header.
138 #define PFCL1_RESERVED_01 0x01 /* Reserved for use by implementations */
139 #define PFCL1_LASTFRAG 0x02 /* If set, the PDU is the last
140 * fragment of a multi-PDU
142 #define PFCL1_FRAG 0x04 /* If set, the PDU is a fragment of
143 a multi-PDU transmission */
144 #define PFCL1_NOFACK 0x08 /* If set, the receiver is not
145 * requested to send a `fack' PDU
146 * for the fragment */
147 #define PFCL1_MAYBE 0x10 /* If set, the PDU is for a `maybe'
149 #define PFCL1_IDEMPOTENT 0x20 /* If set, the PDU is for an idempotent
151 #define PFCL1_BROADCAST 0x40 /* If set, the PDU is for a broadcast
153 #define PFCL1_RESERVED_80 0x80 /* Reserved for use by implementations */
156 * Flag bits in second flag field in connectionless PDU header.
158 #define PFCL2_RESERVED_01 0x01 /* Reserved for use by implementations */
159 #define PFCL2_CANCEL_PENDING 0x02 /* Cancel pending at the call end */
160 #define PFCL2_RESERVED_04 0x04 /* Reserved for future use */
161 #define PFCL2_RESERVED_08 0x08 /* Reserved for future use */
162 #define PFCL2_RESERVED_10 0x10 /* Reserved for future use */
163 #define PFCL2_RESERVED_20 0x20 /* Reserved for future use */
164 #define PFCL2_RESERVED_40 0x40 /* Reserved for future use */
165 #define PFCL2_RESERVED_80 0x80 /* Reserved for future use */
168 * Flag bits in connection-oriented PDU header.
170 #define PFC_FIRST_FRAG 0x01 /* First fragment */
171 #define PFC_LAST_FRAG 0x02 /* Last fragment */
172 #define PFC_PENDING_CANCEL 0x04 /* Cancel was pending at sender */
173 #define PFC_RESERVED_1 0x08
174 #define PFC_CONC_MPX 0x10 /* suports concurrent multiplexing
175 * of a single connection. */
176 #define PFC_DID_NOT_EXECUTE 0x20 /* only meaningful on `fault' packet;
177 * if true, guaranteed call did not
179 #define PFC_MAYBE 0x40 /* `maybe' call semantics requested */
180 #define PFC_OBJECT_UUID 0x80 /* if true, a non-nil object UUID
181 * was specified in the handle, and
182 * is present in the optional object
183 * field. If false, the object field
187 * Tests whether a connection-oriented PDU is fragmented; returns TRUE if
188 * it's not fragmented (i.e., this is both the first *and* last fragment),
189 * and FALSE otherwise.
191 #define PFC_NOT_FRAGMENTED(hdr) \
192 ((hdr->flags&(PFC_FIRST_FRAG|PFC_LAST_FRAG))==(PFC_FIRST_FRAG|PFC_LAST_FRAG))
195 * Presentation context negotiation result.
197 static const value_string p_cont_result_vals[] = {
199 { 1, "User rejection" },
200 { 2, "Provider rejection" },
205 * Presentation context negotiation rejection reasons.
207 static const value_string p_provider_reason_vals[] = {
208 { 0, "Reason not specified" },
209 { 1, "Abstract syntax not supported" },
210 { 2, "Proposed transfer syntaxes not supported" },
211 { 3, "Local limit exceeded" },
218 #define REASON_NOT_SPECIFIED 0
219 #define TEMPORARY_CONGESTION 1
220 #define LOCAL_LIMIT_EXCEEDED 2
221 #define CALLED_PADDR_UNKNOWN 3 /* not used */
222 #define PROTOCOL_VERSION_NOT_SUPPORTED 4
223 #define DEFAULT_CONTEXT_NOT_SUPPORTED 5 /* not used */
224 #define USER_DATA_NOT_READABLE 6 /* not used */
225 #define NO_PSAP_AVAILABLE 7 /* not used */
226 #define AUTH_TYPE_NOT_RECOGNIZED 8
227 #define INVALID_CHECKSUM 9
229 static const value_string reject_reason_vals[] = {
230 { REASON_NOT_SPECIFIED, "Reason not specified" },
231 { TEMPORARY_CONGESTION, "Temporary congestion" },
232 { LOCAL_LIMIT_EXCEEDED, "Local limit exceeded" },
233 { CALLED_PADDR_UNKNOWN, "Called paddr unknown" },
234 { PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported" },
235 { DEFAULT_CONTEXT_NOT_SUPPORTED, "Default context not supported" },
236 { USER_DATA_NOT_READABLE, "User data not readable" },
237 { NO_PSAP_AVAILABLE, "No PSAP available" },
238 { AUTH_TYPE_NOT_RECOGNIZED, "Authentication type not recognized" },
239 { INVALID_CHECKSUM, "Invalid checksum" },
244 * Reject status codes.
246 static const value_string reject_status_vals[] = {
247 { 0, "Stub-defined exception" },
248 { 0x00000001, "nca_s_fault_other" },
249 { 0x00000005, "nca_s_fault_access_denied" },
250 { 0x000006f7, "nca_s_fault_ndr" },
251 { 0x000006d8, "nca_s_fault_cant_perform" },
252 { 0x1c000001, "nca_s_fault_int_div_by_zero" },
253 { 0x1c000002, "nca_s_fault_addr_error" },
254 { 0x1c000003, "nca_s_fault_fp_div_zero" },
255 { 0x1c000004, "nca_s_fault_fp_underflow" },
256 { 0x1c000005, "nca_s_fault_fp_overflow" },
257 { 0x1c000006, "nca_s_fault_invalid_tag" },
258 { 0x1c000007, "nca_s_fault_invalid_bound" },
259 { 0x1c000008, "nca_rpc_version_mismatch" },
260 { 0x1c000009, "nca_unspec_reject" },
261 { 0x1c00000a, "nca_s_bad_actid" },
262 { 0x1c00000b, "nca_who_are_you_failed" },
263 { 0x1c00000c, "nca_manager_not_entered" },
264 { 0x1c00000d, "nca_s_fault_cancel" },
265 { 0x1c00000e, "nca_s_fault_ill_inst" },
266 { 0x1c00000f, "nca_s_fault_fp_error" },
267 { 0x1c000010, "nca_s_fault_int_overflow" },
268 { 0x1c000014, "nca_s_fault_pipe_empty" },
269 { 0x1c000015, "nca_s_fault_pipe_closed" },
270 { 0x1c000016, "nca_s_fault_pipe_order" },
271 { 0x1c000017, "nca_s_fault_pipe_discipline" },
272 { 0x1c000018, "nca_s_fault_pipe_comm_error" },
273 { 0x1c000019, "nca_s_fault_pipe_memory" },
274 { 0x1c00001a, "nca_s_fault_context_mismatch" },
275 { 0x1c00001b, "nca_s_fault_remote_no_memory" },
276 { 0x1c00001c, "nca_invalid_pres_context_id" },
277 { 0x1c00001d, "nca_unsupported_authn_level" },
278 { 0x1c00001f, "nca_invalid_checksum" },
279 { 0x1c000020, "nca_invalid_crc" },
280 { 0x1c000021, "ncs_s_fault_user_defined" },
281 { 0x1c000022, "nca_s_fault_tx_open_failed" },
282 { 0x1c000023, "nca_s_fault_codeset_conv_error" },
283 { 0x1c000024, "nca_s_fault_object_not_found" },
284 { 0x1c000025, "nca_s_fault_no_client_stub" },
285 { 0x1c010002, "nca_op_rng_error" },
286 { 0x1c010003, "nca_unk_if"},
287 { 0x1c010006, "nca_wrong_boot_time" },
288 { 0x1c010009, "nca_s_you_crashed" },
289 { 0x1c01000b, "nca_proto_error" },
290 { 0x1c010013, "nca_out_args_too_big" },
291 { 0x1c010014, "nca_server_too_busy" },
292 { 0x1c010017, "nca_unsupported_type" },
293 /* MS Windows specific values
294 * see: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__1700-3999_.asp
295 * and: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/common_hresult_values.asp
296 * and: http://www.megos.ch/support/doserrors.txt
298 * XXX - we might need a way to dynamically add entries here, as higher layer protocols use these values too,
299 * at least MS protocols (like DCOM) do it that way ... */
300 { 0x80004001, "E_NOTIMPL" },
301 { 0x80004003, "E_POINTER" },
302 { 0x80004004, "E_ABORT" },
303 { 0x8000FFFF, "E_UNEXPECTED" },
304 { 0x80010105, "RPC_E_SERVERFAULT" },
305 { 0x80010108, "RPC_E_DISCONNECTED" },
306 { 0x80010113, "RPC_E_INVALID_IPID" },
307 { 0x8001011F, "RPC_E_TIMEOUT" },
308 { 0x80020003, "DISP_E_MEMBERNOTFOUND" },
309 { 0x80020006, "DISP_E_UNKNOWNNAME" },
310 { 0x8002000E, "DISP_E_BADPARAMCOUNT" },
311 { 0x8004CB00, "CBA_E_MALFORMED" },
312 { 0x8004CB01, "CBA_E_UNKNOWNOBJECT" },
313 { 0x8004CB05, "CBA_E_INVALIDID" },
314 { 0x8004CB09, "CBA_E_INVALIDCOOKIE" },
315 { 0x8004CB0B, "CBA_E_QOSTYPEUNSUPPORTED" },
316 { 0x8004CB0C, "CBA_E_QOSVALUEUNSUPPORTED" },
317 { 0x8004CB0F, "CBA_E_NOTAPPLICABLE" },
318 { 0x8004CB12, "CBA_E_LIMITVIOLATION" },
319 { 0x8004CB13, "CBA_E_QOSTYPENOTAPPLICABLE" },
320 { 0x8004CB18, "CBA_E_OUTOFPARTNERACCOS" },
321 { 0x8004CB1C, "CBA_E_FLAGUNSUPPORTED" },
322 { 0x8004CB23, "CBA_E_FRAMECOUNTUNSUPPORTED" },
323 { 0x8004CB25, "CBA_E_MODECHANGE" },
324 { 0x8007000E, "E_OUTOFMEMORY" },
325 { 0x80070057, "E_INVALIDARG" },
326 { 0x800706d1, "RPC_S_PROCNUM_OUT_OF_RANGE" },
327 { 0x80070776, "OR_INVALID_OXID" },
332 /* we need to keep track of what transport were used, ie what handle we came
333 * in through so we know what kind of pinfo->dce_smb_fid was passed to us.
335 /* Value of -1 is reserved for "not DCE packet" in packet_info.dcetransporttype. */
336 #define DCE_TRANSPORT_UNKNOWN 0
337 #define DCE_CN_TRANSPORT_SMBPIPE 1
340 static int proto_dcerpc = -1;
343 static int hf_dcerpc_request_in = -1;
344 static int hf_dcerpc_time = -1;
345 static int hf_dcerpc_response_in = -1;
346 static int hf_dcerpc_ver = -1;
347 static int hf_dcerpc_ver_minor = -1;
348 static int hf_dcerpc_packet_type = -1;
349 static int hf_dcerpc_cn_flags = -1;
350 static int hf_dcerpc_cn_flags_first_frag = -1;
351 static int hf_dcerpc_cn_flags_last_frag = -1;
352 static int hf_dcerpc_cn_flags_cancel_pending = -1;
353 static int hf_dcerpc_cn_flags_reserved = -1;
354 static int hf_dcerpc_cn_flags_mpx = -1;
355 static int hf_dcerpc_cn_flags_dne = -1;
356 static int hf_dcerpc_cn_flags_maybe = -1;
357 static int hf_dcerpc_cn_flags_object = -1;
358 static int hf_dcerpc_drep = -1;
359 int hf_dcerpc_drep_byteorder = -1;
360 static int hf_dcerpc_drep_character = -1;
361 static int hf_dcerpc_drep_fp = -1;
362 static int hf_dcerpc_cn_frag_len = -1;
363 static int hf_dcerpc_cn_auth_len = -1;
364 static int hf_dcerpc_cn_call_id = -1;
365 static int hf_dcerpc_cn_max_xmit = -1;
366 static int hf_dcerpc_cn_max_recv = -1;
367 static int hf_dcerpc_cn_assoc_group = -1;
368 static int hf_dcerpc_cn_num_ctx_items = -1;
369 static int hf_dcerpc_cn_ctx_item = -1;
370 static int hf_dcerpc_cn_ctx_id = -1;
371 static int hf_dcerpc_cn_num_trans_items = -1;
372 static int hf_dcerpc_cn_bind_abstract_syntax = -1;
373 static int hf_dcerpc_cn_bind_if_id = -1;
374 static int hf_dcerpc_cn_bind_if_ver = -1;
375 static int hf_dcerpc_cn_bind_if_ver_minor = -1;
376 static int hf_dcerpc_cn_bind_trans_syntax = -1;
377 static int hf_dcerpc_cn_bind_trans_id = -1;
378 static int hf_dcerpc_cn_bind_trans_ver = -1;
379 static int hf_dcerpc_cn_alloc_hint = -1;
380 static int hf_dcerpc_cn_sec_addr_len = -1;
381 static int hf_dcerpc_cn_sec_addr = -1;
382 static int hf_dcerpc_cn_num_results = -1;
383 static int hf_dcerpc_cn_ack_result = -1;
384 static int hf_dcerpc_cn_ack_reason = -1;
385 static int hf_dcerpc_cn_ack_trans_id = -1;
386 static int hf_dcerpc_cn_ack_trans_ver = -1;
387 static int hf_dcerpc_cn_reject_reason = -1;
388 static int hf_dcerpc_cn_num_protocols = -1;
389 static int hf_dcerpc_cn_protocol_ver_major = -1;
390 static int hf_dcerpc_cn_protocol_ver_minor = -1;
391 static int hf_dcerpc_cn_cancel_count = -1;
392 static int hf_dcerpc_cn_status = -1;
393 static int hf_dcerpc_cn_deseg_req = -1;
394 static int hf_dcerpc_auth_type = -1;
395 static int hf_dcerpc_auth_level = -1;
396 static int hf_dcerpc_auth_pad_len = -1;
397 static int hf_dcerpc_auth_rsrvd = -1;
398 static int hf_dcerpc_auth_ctx_id = -1;
399 static int hf_dcerpc_dg_flags1 = -1;
400 static int hf_dcerpc_dg_flags1_rsrvd_01 = -1;
401 static int hf_dcerpc_dg_flags1_last_frag = -1;
402 static int hf_dcerpc_dg_flags1_frag = -1;
403 static int hf_dcerpc_dg_flags1_nofack = -1;
404 static int hf_dcerpc_dg_flags1_maybe = -1;
405 static int hf_dcerpc_dg_flags1_idempotent = -1;
406 static int hf_dcerpc_dg_flags1_broadcast = -1;
407 static int hf_dcerpc_dg_flags1_rsrvd_80 = -1;
408 static int hf_dcerpc_dg_flags2 = -1;
409 static int hf_dcerpc_dg_flags2_rsrvd_01 = -1;
410 static int hf_dcerpc_dg_flags2_cancel_pending = -1;
411 static int hf_dcerpc_dg_flags2_rsrvd_04 = -1;
412 static int hf_dcerpc_dg_flags2_rsrvd_08 = -1;
413 static int hf_dcerpc_dg_flags2_rsrvd_10 = -1;
414 static int hf_dcerpc_dg_flags2_rsrvd_20 = -1;
415 static int hf_dcerpc_dg_flags2_rsrvd_40 = -1;
416 static int hf_dcerpc_dg_flags2_rsrvd_80 = -1;
417 static int hf_dcerpc_dg_serial_hi = -1;
418 static int hf_dcerpc_obj_id = -1;
419 static int hf_dcerpc_dg_if_id = -1;
420 static int hf_dcerpc_dg_act_id = -1;
421 static int hf_dcerpc_dg_serial_lo = -1;
422 static int hf_dcerpc_dg_ahint = -1;
423 static int hf_dcerpc_dg_ihint = -1;
424 static int hf_dcerpc_dg_frag_len = -1;
425 static int hf_dcerpc_dg_frag_num = -1;
426 static int hf_dcerpc_dg_auth_proto = -1;
427 static int hf_dcerpc_opnum = -1;
428 static int hf_dcerpc_dg_seqnum = -1;
429 static int hf_dcerpc_dg_server_boot = -1;
430 static int hf_dcerpc_dg_if_ver = -1;
431 static int hf_dcerpc_krb5_av_prot_level = -1;
432 static int hf_dcerpc_krb5_av_key_vers_num = -1;
433 static int hf_dcerpc_krb5_av_key_auth_verifier = -1;
434 static int hf_dcerpc_dg_cancel_vers = -1;
435 static int hf_dcerpc_dg_cancel_id = -1;
436 static int hf_dcerpc_dg_server_accepting_cancels = -1;
437 static int hf_dcerpc_dg_fack_vers = -1;
438 static int hf_dcerpc_dg_fack_window_size = -1;
439 static int hf_dcerpc_dg_fack_max_tsdu = -1;
440 static int hf_dcerpc_dg_fack_max_frag_size = -1;
441 static int hf_dcerpc_dg_fack_serial_num = -1;
442 static int hf_dcerpc_dg_fack_selack_len = -1;
443 static int hf_dcerpc_dg_fack_selack = -1;
444 static int hf_dcerpc_dg_status = -1;
445 static int hf_dcerpc_array_max_count = -1;
446 static int hf_dcerpc_array_offset = -1;
447 static int hf_dcerpc_array_actual_count = -1;
448 static int hf_dcerpc_array_buffer = -1;
449 static int hf_dcerpc_op = -1;
450 static int hf_dcerpc_referent_id = -1;
451 static int hf_dcerpc_fragments = -1;
452 static int hf_dcerpc_fragment = -1;
453 static int hf_dcerpc_fragment_overlap = -1;
454 static int hf_dcerpc_fragment_overlap_conflict = -1;
455 static int hf_dcerpc_fragment_multiple_tails = -1;
456 static int hf_dcerpc_fragment_too_long_fragment = -1;
457 static int hf_dcerpc_fragment_error = -1;
458 static int hf_dcerpc_reassembled_in = -1;
459 static int hf_dcerpc_unknown_if_id = -1;
461 static gint ett_dcerpc = -1;
462 static gint ett_dcerpc_cn_flags = -1;
463 static gint ett_dcerpc_cn_ctx = -1;
464 static gint ett_dcerpc_cn_iface = -1;
465 static gint ett_dcerpc_cn_trans_syntax = -1;
466 static gint ett_dcerpc_drep = -1;
467 static gint ett_dcerpc_dg_flags1 = -1;
468 static gint ett_dcerpc_dg_flags2 = -1;
469 static gint ett_dcerpc_pointer_data = -1;
470 static gint ett_dcerpc_string = -1;
471 static gint ett_dcerpc_fragments = -1;
472 static gint ett_dcerpc_fragment = -1;
473 static gint ett_dcerpc_krb5_auth_verf = -1;
475 static const fragment_items dcerpc_frag_items = {
476 &ett_dcerpc_fragments,
477 &ett_dcerpc_fragment,
479 &hf_dcerpc_fragments,
481 &hf_dcerpc_fragment_overlap,
482 &hf_dcerpc_fragment_overlap_conflict,
483 &hf_dcerpc_fragment_multiple_tails,
484 &hf_dcerpc_fragment_too_long_fragment,
485 &hf_dcerpc_fragment_error,
491 /* list of hooks to be called when init_protocols is done */
492 GHookList dcerpc_hooks_init_protos;
497 static dcerpc_info di[20];
498 static int di_counter=0;
504 return &di[di_counter];
507 /* try to desegment big DCE/RPC packets over TCP? */
508 static gboolean dcerpc_cn_desegment = TRUE;
510 /* reassemble DCE/RPC fragments */
511 /* reassembly of cl dcerpc fragments will not work for the case where ONE frame
512 might contain multiple dcerpc fragments for different PDUs.
513 this case would be so unusual/weird so if you got captures like that:
516 reassembly of co dcerpc fragments will not work for the case where TCP/SMB frames
517 are coming in out of sequence, but that will hurt in a lot of other places as well.
519 static gboolean dcerpc_reassemble = TRUE;
520 static GHashTable *dcerpc_co_fragment_table = NULL;
521 static GHashTable *dcerpc_co_reassemble_table = NULL;
522 static GHashTable *dcerpc_cl_reassemble_table = NULL;
525 dcerpc_reassemble_init(void)
527 fragment_table_init(&dcerpc_co_fragment_table);
528 reassembled_table_init(&dcerpc_co_reassemble_table);
529 dcerpc_fragment_table_init(&dcerpc_cl_reassemble_table);
533 * Authentication subdissectors. Used to dissect authentication blobs in
534 * DCERPC binds, requests and responses.
537 typedef struct _dcerpc_auth_subdissector {
540 dcerpc_auth_subdissector_fns auth_fns;
541 } dcerpc_auth_subdissector;
543 static GSList *dcerpc_auth_subdissector_list;
545 static dcerpc_auth_subdissector_fns *get_auth_subdissector_fns(
546 guint8 auth_level, guint8 auth_type)
551 for (i = 0; (data = g_slist_nth_data(dcerpc_auth_subdissector_list, i)); i++) {
552 dcerpc_auth_subdissector *asd = (dcerpc_auth_subdissector *)data;
553 if (asd->auth_level == auth_level &&
554 asd->auth_type == auth_type)
555 return &asd->auth_fns;
561 void register_dcerpc_auth_subdissector(guint8 auth_level, guint8 auth_type,
562 dcerpc_auth_subdissector_fns *fns)
564 dcerpc_auth_subdissector *d;
566 if (get_auth_subdissector_fns(auth_level, auth_type))
569 d = (dcerpc_auth_subdissector *)g_malloc(sizeof(dcerpc_auth_subdissector));
571 d->auth_level = auth_level;
572 d->auth_type = auth_type;
573 memcpy(&d->auth_fns, fns, sizeof(dcerpc_auth_subdissector_fns));
575 dcerpc_auth_subdissector_list = g_slist_append(dcerpc_auth_subdissector_list, d);
578 /* Hand off verifier data to a registered dissector */
580 static void dissect_auth_verf(tvbuff_t *auth_tvb, packet_info *pinfo,
582 dcerpc_auth_subdissector_fns *auth_fns,
583 e_dce_cn_common_hdr_t *hdr,
584 dcerpc_auth_info *auth_info)
586 dcerpc_dissect_fnct_t *volatile fn = NULL;
588 switch (hdr->ptype) {
591 fn = auth_fns->bind_fn;
595 fn = auth_fns->bind_ack_fn;
598 fn = auth_fns->auth3_fn;
601 fn = auth_fns->req_verf_fn;
604 fn = auth_fns->resp_verf_fn;
607 /* Don't know how to handle authentication data in this
611 g_warning("attempt to dissect %s pdu authentication data",
612 val_to_str(hdr->ptype, pckt_vals, "Unknown (%u)"));
617 fn(auth_tvb, 0, pinfo, tree, hdr->drep);
619 tvb_ensure_bytes_exist(auth_tvb, 0, hdr->auth_len);
620 proto_tree_add_text(tree, auth_tvb, 0, hdr->auth_len,
622 val_to_str(auth_info->auth_type,
628 /* Hand off payload data to a registered dissector */
630 static tvbuff_t *decode_encrypted_data(tvbuff_t *data_tvb,
633 dcerpc_auth_subdissector_fns *auth_fns,
635 dcerpc_auth_info *auth_info)
637 dcerpc_decode_data_fnct_t *fn;
640 fn = auth_fns->req_data_fn;
642 fn = auth_fns->resp_data_fn;
645 return fn(data_tvb, auth_tvb, 0, pinfo, auth_info);
654 /* the registered subdissectors */
655 GHashTable *dcerpc_uuids=NULL;
658 dcerpc_uuid_equal (gconstpointer k1, gconstpointer k2)
660 const dcerpc_uuid_key *key1 = (const dcerpc_uuid_key *)k1;
661 const dcerpc_uuid_key *key2 = (const dcerpc_uuid_key *)k2;
662 return ((memcmp (&key1->uuid, &key2->uuid, sizeof (e_uuid_t)) == 0)
663 && (key1->ver == key2->ver));
667 dcerpc_uuid_hash (gconstpointer k)
669 const dcerpc_uuid_key *key = (const dcerpc_uuid_key *)k;
670 /* This isn't perfect, but the Data1 part of these is almost always
672 return key->uuid.Data1;
676 dcerpc_init_uuid (int proto, int ett, e_uuid_t *uuid, guint16 ver,
677 dcerpc_sub_dissector *procs, int opnum_hf)
679 dcerpc_uuid_key *key = g_malloc (sizeof (*key));
680 dcerpc_uuid_value *value = g_malloc (sizeof (*value));
681 header_field_info *hf_info;
682 module_t *samr_module;
683 const char *filter_name = proto_get_protocol_filter_name(proto);
688 value->proto = find_protocol_by_id(proto);
689 value->proto_id = proto;
691 value->name = proto_get_protocol_short_name (value->proto);
692 value->procs = procs;
693 value->opnum_hf = opnum_hf;
695 g_hash_table_insert (dcerpc_uuids, key, value);
697 hf_info = proto_registrar_get_nth(opnum_hf);
698 hf_info->strings = value_string_from_subdissectors(procs);
700 /* add this GUID to the global name resolving */
701 guids_add_uuid(uuid, proto_get_protocol_short_name (value->proto));
703 /* Register the samr.nt_password preference as obsolete */
704 /* This should be in packet-dcerpc-samr.c */
705 if (strcmp(filter_name, "samr") == 0) {
706 samr_module = prefs_register_protocol (proto, NULL);
707 prefs_register_obsolete_preference(samr_module, "nt_password");
711 /* Function to find the name of a registered protocol
712 * or NULL if the protocol/version is not known to wireshark.
715 dcerpc_get_proto_name(e_uuid_t *uuid, guint16 ver)
718 dcerpc_uuid_value *sub_proto;
722 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
725 return sub_proto->name;
728 /* Function to find the opnum hf-field of a registered protocol
729 * or -1 if the protocol/version is not known to wireshark.
732 dcerpc_get_proto_hf_opnum(e_uuid_t *uuid, guint16 ver)
735 dcerpc_uuid_value *sub_proto;
739 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
742 return sub_proto->opnum_hf;
745 /* Create a value_string consisting of DCERPC opnum and name from a
746 subdissector array. */
748 value_string *value_string_from_subdissectors(dcerpc_sub_dissector *sd)
750 value_string *vs = NULL;
754 for (i = 0; sd[i].name; i++) {
756 vs[i].value = sd[i].num;
757 vs[i].strptr = sd[i].name;
763 vs = g_malloc((num_sd + 1) * sizeof(value_string));
767 vs[num_sd].value = 0;
768 vs[num_sd].strptr = NULL;
773 /* Function to find the subdissector table of a registered protocol
774 * or NULL if the protocol/version is not known to wireshark.
776 dcerpc_sub_dissector *
777 dcerpc_get_proto_sub_dissector(e_uuid_t *uuid, guint16 ver)
780 dcerpc_uuid_value *sub_proto;
784 if(!(sub_proto = g_hash_table_lookup (dcerpc_uuids, &key))){
787 return sub_proto->procs;
792 * To keep track of ctx_id mappings.
794 * Everytime we see a bind call we update this table.
795 * Note that we always specify a SMB FID. For non-SMB transports this
798 static GHashTable *dcerpc_binds=NULL;
800 typedef struct _dcerpc_bind_key {
801 conversation_t *conv;
806 typedef struct _dcerpc_bind_value {
812 dcerpc_bind_equal (gconstpointer k1, gconstpointer k2)
814 const dcerpc_bind_key *key1 = (const dcerpc_bind_key *)k1;
815 const dcerpc_bind_key *key2 = (const dcerpc_bind_key *)k2;
816 return (key1->conv == key2->conv
817 && key1->ctx_id == key2->ctx_id
818 && key1->smb_fid == key2->smb_fid);
822 dcerpc_bind_hash (gconstpointer k)
824 const dcerpc_bind_key *key = (const dcerpc_bind_key *)k;
827 hash=GPOINTER_TO_UINT(key->conv) + key->ctx_id + key->smb_fid;
833 * To keep track of callid mappings. Should really use some generic
834 * conversation support instead.
836 static GHashTable *dcerpc_cn_calls=NULL;
837 static GHashTable *dcerpc_dg_calls=NULL;
839 typedef struct _dcerpc_cn_call_key {
840 conversation_t *conv;
843 } dcerpc_cn_call_key;
845 typedef struct _dcerpc_dg_call_key {
846 conversation_t *conv;
849 } dcerpc_dg_call_key;
853 dcerpc_cn_call_equal (gconstpointer k1, gconstpointer k2)
855 const dcerpc_cn_call_key *key1 = (const dcerpc_cn_call_key *)k1;
856 const dcerpc_cn_call_key *key2 = (const dcerpc_cn_call_key *)k2;
857 return (key1->conv == key2->conv
858 && key1->call_id == key2->call_id
859 && key1->smb_fid == key2->smb_fid);
863 dcerpc_dg_call_equal (gconstpointer k1, gconstpointer k2)
865 const dcerpc_dg_call_key *key1 = (const dcerpc_dg_call_key *)k1;
866 const dcerpc_dg_call_key *key2 = (const dcerpc_dg_call_key *)k2;
867 return (key1->conv == key2->conv
868 && key1->seqnum == key2->seqnum
869 && (memcmp (&key1->act_id, &key2->act_id, sizeof (e_uuid_t)) == 0));
873 dcerpc_cn_call_hash (gconstpointer k)
875 const dcerpc_cn_call_key *key = (const dcerpc_cn_call_key *)k;
876 return GPOINTER_TO_UINT(key->conv) + key->call_id + key->smb_fid;
880 dcerpc_dg_call_hash (gconstpointer k)
882 const dcerpc_dg_call_key *key = (const dcerpc_dg_call_key *)k;
883 return (GPOINTER_TO_UINT(key->conv) + key->seqnum + key->act_id.Data1
884 + (key->act_id.Data2 << 16) + key->act_id.Data3
885 + (key->act_id.Data4[0] << 24) + (key->act_id.Data4[1] << 16)
886 + (key->act_id.Data4[2] << 8) + (key->act_id.Data4[3] << 0)
887 + (key->act_id.Data4[4] << 24) + (key->act_id.Data4[5] << 16)
888 + (key->act_id.Data4[6] << 8) + (key->act_id.Data4[7] << 0));
892 /* to keep track of matched calls/responses
893 this one uses the same value struct as calls, but the key is the frame id
894 and call id; there can be more than one call in a frame.
896 XXX - why not just use the same keys as are used for calls?
899 static GHashTable *dcerpc_matched=NULL;
901 typedef struct _dcerpc_matched_key {
904 } dcerpc_matched_key;
907 dcerpc_matched_equal (gconstpointer k1, gconstpointer k2)
909 const dcerpc_matched_key *key1 = (const dcerpc_matched_key *)k1;
910 const dcerpc_matched_key *key2 = (const dcerpc_matched_key *)k2;
911 return (key1->frame == key2->frame
912 && key1->call_id == key2->call_id);
916 dcerpc_matched_hash (gconstpointer k)
918 const dcerpc_matched_key *key = (const dcerpc_matched_key *)k;
925 * Utility functions. Modeled after packet-rpc.c
929 dissect_dcerpc_uint8 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
930 proto_tree *tree, guint8 *drep,
931 int hfindex, guint8 *pdata)
935 data = tvb_get_guint8 (tvb, offset);
937 proto_tree_add_item (tree, hfindex, tvb, offset, 1, (drep[0] & 0x10));
945 dissect_dcerpc_uint16 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
946 proto_tree *tree, guint8 *drep,
947 int hfindex, guint16 *pdata)
951 data = ((drep[0] & 0x10)
952 ? tvb_get_letohs (tvb, offset)
953 : tvb_get_ntohs (tvb, offset));
956 proto_tree_add_item (tree, hfindex, tvb, offset, 2, (drep[0] & 0x10));
964 dissect_dcerpc_uint32 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
965 proto_tree *tree, guint8 *drep,
966 int hfindex, guint32 *pdata)
970 data = ((drep[0] & 0x10)
971 ? tvb_get_letohl (tvb, offset)
972 : tvb_get_ntohl (tvb, offset));
975 proto_tree_add_item (tree, hfindex, tvb, offset, 4, (drep[0] & 0x10));
982 /* handles 32 bit unix time_t */
984 dissect_dcerpc_time_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
985 proto_tree *tree, guint8 *drep,
986 int hfindex, guint32 *pdata)
991 data = ((drep[0] & 0x10)
992 ? tvb_get_letohl (tvb, offset)
993 : tvb_get_ntohl (tvb, offset));
998 if(data==0xffffffff){
999 /* special case, no time specified */
1000 proto_tree_add_time_format_value(tree, hfindex, tvb, offset, 4, &tv, "No time specified");
1002 proto_tree_add_time (tree, hfindex, tvb, offset, 4, &tv);
1012 dissect_dcerpc_uint64 (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1013 proto_tree *tree, guint8 *drep,
1014 int hfindex, guint64 *pdata)
1018 data = ((drep[0] & 0x10)
1019 ? tvb_get_letoh64 (tvb, offset)
1020 : tvb_get_ntoh64 (tvb, offset));
1023 proto_tree_add_item(tree, hfindex, tvb, offset, 8, (drep[0] & 0x10));
1032 dissect_dcerpc_float(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1033 proto_tree *tree, guint8 *drep,
1034 int hfindex, gfloat *pdata)
1040 case(DCE_RPC_DREP_FP_IEEE):
1041 data = ((drep[0] & 0x10)
1042 ? tvb_get_letohieee_float(tvb, offset)
1043 : tvb_get_ntohieee_float(tvb, offset));
1045 proto_tree_add_float(tree, hfindex, tvb, offset, 4, data);
1048 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1049 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1050 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1052 /* ToBeDone: non IEEE floating formats */
1053 /* Set data to a negative infinity value */
1056 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE floating formats currently not implemented (drep=%u)!", drep[1]);
1066 dissect_dcerpc_double(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1067 proto_tree *tree, guint8 *drep,
1068 int hfindex, gdouble *pdata)
1074 case(DCE_RPC_DREP_FP_IEEE):
1075 data = ((drep[0] & 0x10)
1076 ? tvb_get_letohieee_double(tvb, offset)
1077 : tvb_get_ntohieee_double(tvb, offset));
1079 proto_tree_add_double(tree, hfindex, tvb, offset, 8, data);
1082 case(DCE_RPC_DREP_FP_VAX): /* (fall trough) */
1083 case(DCE_RPC_DREP_FP_CRAY): /* (fall trough) */
1084 case(DCE_RPC_DREP_FP_IBM): /* (fall trough) */
1086 /* ToBeDone: non IEEE double formats */
1087 /* Set data to a negative infinity value */
1088 data = -G_MAXDOUBLE;
1090 proto_tree_add_debug_text(tree, "DCE RPC: dissection of non IEEE double formats currently not implemented (drep=%u)!", drep[1]);
1100 dissect_dcerpc_uuid_t (tvbuff_t *tvb, gint offset, packet_info *pinfo _U_,
1101 proto_tree *tree, guint8 *drep,
1102 int hfindex, e_uuid_t *pdata)
1107 if (drep[0] & 0x10) {
1108 tvb_get_letohguid (tvb, offset, (e_guid_t *) &uuid);
1110 tvb_get_ntohguid (tvb, offset, (e_guid_t *) &uuid);
1113 proto_tree_add_guid(tree, hfindex, tvb, offset, 16, (e_guid_t *) &uuid);
1123 * a couple simpler things
1126 dcerpc_tvb_get_ntohs (tvbuff_t *tvb, gint offset, guint8 *drep)
1128 if (drep[0] & 0x10) {
1129 return tvb_get_letohs (tvb, offset);
1131 return tvb_get_ntohs (tvb, offset);
1136 dcerpc_tvb_get_ntohl (tvbuff_t *tvb, gint offset, guint8 *drep)
1138 if (drep[0] & 0x10) {
1139 return tvb_get_letohl (tvb, offset);
1141 return tvb_get_ntohl (tvb, offset);
1146 dcerpc_tvb_get_uuid (tvbuff_t *tvb, gint offset, guint8 *drep, e_uuid_t *uuid)
1148 if (drep[0] & 0x10) {
1149 tvb_get_letohguid (tvb, offset, (e_guid_t *) uuid);
1151 tvb_get_ntohguid (tvb, offset, (e_guid_t *) uuid);
1157 /* function to dissect a unidimensional conformant array */
1159 dissect_ndr_ucarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1160 proto_tree *tree, guint8 *drep,
1161 dcerpc_dissect_fnct_t *fnct)
1167 di=pinfo->private_data;
1168 if(di->conformant_run){
1169 /* conformant run, just dissect the max_count header */
1171 di->conformant_run=0;
1172 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1173 hf_dcerpc_array_max_count, &di->array_max_count);
1174 di->array_max_count_offset=offset-4;
1175 di->conformant_run=1;
1176 di->conformant_eaten=offset-old_offset;
1178 /* we don't remember where in the bytestream this field was */
1179 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1181 /* real run, dissect the elements */
1182 for(i=0;i<di->array_max_count;i++){
1183 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1189 /* function to dissect a unidimensional conformant and varying array */
1191 dissect_ndr_ucvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1192 proto_tree *tree, guint8 *drep,
1193 dcerpc_dissect_fnct_t *fnct)
1199 di=pinfo->private_data;
1200 if(di->conformant_run){
1201 /* conformant run, just dissect the max_count header */
1203 di->conformant_run=0;
1204 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1205 hf_dcerpc_array_max_count, &di->array_max_count);
1206 di->array_max_count_offset=offset-4;
1207 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1208 hf_dcerpc_array_offset, &di->array_offset);
1209 di->array_offset_offset=offset-4;
1210 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1211 hf_dcerpc_array_actual_count, &di->array_actual_count);
1212 di->array_actual_count_offset=offset-4;
1213 di->conformant_run=1;
1214 di->conformant_eaten=offset-old_offset;
1216 /* we dont dont remember where in the bytestream these fields were */
1217 proto_tree_add_uint(tree, hf_dcerpc_array_max_count, tvb, di->array_max_count_offset, 4, di->array_max_count);
1218 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1219 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1221 /* real run, dissect the elements */
1222 for(i=0;i<di->array_actual_count;i++){
1223 old_offset = offset;
1224 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1225 if (offset <= old_offset)
1226 THROW(ReportedBoundsError);
1232 /* function to dissect a unidimensional varying array */
1234 dissect_ndr_uvarray(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1235 proto_tree *tree, guint8 *drep,
1236 dcerpc_dissect_fnct_t *fnct)
1242 di=pinfo->private_data;
1243 if(di->conformant_run){
1244 /* conformant run, just dissect the max_count header */
1246 di->conformant_run=0;
1247 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1248 hf_dcerpc_array_offset, &di->array_offset);
1249 di->array_offset_offset=offset-4;
1250 offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
1251 hf_dcerpc_array_actual_count, &di->array_actual_count);
1252 di->array_actual_count_offset=offset-4;
1253 di->conformant_run=1;
1254 di->conformant_eaten=offset-old_offset;
1256 /* we dont dont remember where in the bytestream these fields were */
1257 proto_tree_add_uint(tree, hf_dcerpc_array_offset, tvb, di->array_offset_offset, 4, di->array_offset);
1258 proto_tree_add_uint(tree, hf_dcerpc_array_actual_count, tvb, di->array_actual_count_offset, 4, di->array_actual_count);
1260 /* real run, dissect the elements */
1261 for(i=0;i<di->array_actual_count;i++){
1262 offset = (*fnct)(tvb, offset, pinfo, tree, drep);
1269 /* Dissect an string of bytes. This corresponds to
1270 IDL of the form '[string] byte *foo'.
1272 It can also be used for a conformant varying array of bytes if
1273 the contents of the array should be shown as a big blob, rather
1274 than showing each byte as an individual element.
1276 XXX - which of those is really the IDL type for, for example,
1277 the encrypted data in some MAPI packets? (Microsoft haven't
1280 XXX - does this need to do all the conformant array stuff that
1281 "dissect_ndr_ucvarray()" does? These are presumably for strings
1282 that are conformant and varying - they're stored like conformant
1283 varying arrays of bytes. */
1285 dissect_ndr_byte_array(tvbuff_t *tvb, int offset, packet_info *pinfo,
1286 proto_tree *tree, guint8 *drep)
1291 di=pinfo->private_data;
1292 if(di->conformant_run){
1293 /* just a run to handle conformant arrays, no scalars to dissect */
1297 /* NDR array header */
1299 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1300 hf_dcerpc_array_max_count, NULL);
1302 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1303 hf_dcerpc_array_offset, NULL);
1305 offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep,
1306 hf_dcerpc_array_actual_count, &len);
1309 tvb_ensure_bytes_exist(tvb, offset, len);
1310 proto_tree_add_item(tree, hf_dcerpc_array_buffer,
1311 tvb, offset, len, drep[0] & 0x10);
1319 /* For dissecting arrays that are to be interpreted as strings. */
1321 /* Dissect an NDR conformant varying string of elements.
1322 The length of each element is given by the 'size_is' parameter;
1323 the elements are assumed to be characters or wide characters.
1325 XXX - does this need to do all the conformant array stuff that
1326 "dissect_ndr_ucvarray()" does? */
1328 dissect_ndr_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1329 proto_tree *tree, guint8 *drep, int size_is,
1330 int hfindex, gboolean add_subtree, char **data)
1333 proto_item *string_item;
1334 proto_tree *string_tree;
1335 guint32 len, buffer_len;
1337 header_field_info *hfinfo;
1339 di=pinfo->private_data;
1340 if(di->conformant_run){
1341 /* just a run to handle conformant arrays, no scalars to dissect */
1346 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1347 proto_registrar_get_name(hfindex));
1348 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1354 /* NDR array header */
1356 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1357 hf_dcerpc_array_max_count, NULL);
1359 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1360 hf_dcerpc_array_offset, NULL);
1362 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1363 hf_dcerpc_array_actual_count, &len);
1364 buffer_len = size_is * len;
1365 hfinfo = proto_registrar_get_nth(hfindex);
1368 if (offset % size_is)
1369 offset += size_is - (offset % size_is);
1370 if (size_is == sizeof(guint16)) {
1371 /* XXX - use drep to determine the byte order? */
1372 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1374 * XXX - we don't support a string type with Unicode
1375 * characters, so if this is a string item, we make
1376 * its value be the "fake Unicode" string.
1378 if (tree && buffer_len) {
1379 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1380 if (hfinfo->type == FT_STRING) {
1381 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1384 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1385 buffer_len, drep[0] & 0x10);
1390 * "tvb_get_ephemeral_string()" throws an exception if the entire string
1391 * isn't in the tvbuff. If the length is bogus, this should
1392 * keep us from trying to allocate an immensely large buffer.
1393 * (It won't help if the length is *valid* but immensely large,
1394 * but that's another matter; in any case, that would happen only
1395 * if we had an immensely large tvbuff....)
1397 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1398 s = tvb_get_ephemeral_string(tvb, offset, buffer_len);
1399 if (tree && buffer_len)
1400 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1401 buffer_len, drep[0] & 0x10);
1404 if (string_item != NULL)
1405 proto_item_append_text(string_item, ": %s", s);
1410 offset += buffer_len;
1412 proto_item_set_end(string_item, tvb, offset);
1417 /* Dissect an conformant varying string of chars.
1418 This corresponds to IDL of the form '[string] char *foo'.
1420 XXX - at least according to the DCE RPC 1.1 spec, a string has
1421 a null terminator, which isn't necessary as a terminator for
1422 the transfer language (as there's a length), but is presumably
1423 there for the benefit of null-terminated-string languages
1424 such as C. Is this ever used for purely counted strings?
1425 (Not that it matters if it is.) */
1427 dissect_ndr_char_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1428 proto_tree *tree, guint8 *drep)
1431 di=pinfo->private_data;
1433 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1434 sizeof(guint8), di->hf_index,
1438 /* Dissect a conformant varying string of wchars (wide characters).
1439 This corresponds to IDL of the form '[string] wchar *foo'
1441 XXX - at least according to the DCE RPC 1.1 spec, a string has
1442 a null terminator, which isn't necessary as a terminator for
1443 the transfer language (as there's a length), but is presumably
1444 there for the benefit of null-terminated-string languages
1445 such as C. Is this ever used for purely counted strings?
1446 (Not that it matters if it is.) */
1448 dissect_ndr_wchar_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1449 proto_tree *tree, guint8 *drep)
1452 di=pinfo->private_data;
1454 return dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1455 sizeof(guint16), di->hf_index,
1459 /* This function is aimed for PIDL useage and dissects a UNIQUE pointer to
1463 PIDL_dissect_cvstring(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep, int chsize, int hfindex, guint32 param)
1467 gint levels = CB_STR_ITEM_LEVELS(param);
1469 di=pinfo->private_data;
1471 offset = dissect_ndr_cvstring(tvb, offset, pinfo, tree, drep,
1475 if(!di->conformant_run){
1476 /* Append string to COL_INFO */
1477 if (param & PIDL_SET_COL_INFO) {
1478 if (check_col(pinfo->cinfo, COL_INFO))
1479 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s);
1481 /* Save string to dcv->private_data */
1482 if((param & PIDL_STR_SAVE)
1483 && (!pinfo->fd->flags.visited)){
1484 dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data;
1485 dcv->private_data = se_strdup(s);
1487 /* Append string to upper-level proto_items */
1488 if (levels > 0 && tree && s && s[0]) {
1489 proto_item_append_text(tree, ": %s", s);
1490 tree = tree->parent;
1493 proto_item_append_text(tree, ": %s", s);
1494 tree = tree->parent;
1496 while (levels > 0) {
1497 proto_item_append_text(tree, " %s", s);
1498 tree = tree->parent;
1510 /* Dissect an NDR varying string of elements.
1511 The length of each element is given by the 'size_is' parameter;
1512 the elements are assumed to be characters or wide characters.
1515 dissect_ndr_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1516 proto_tree *tree, guint8 *drep, int size_is,
1517 int hfindex, gboolean add_subtree, char **data)
1520 proto_item *string_item;
1521 proto_tree *string_tree;
1522 guint32 len, buffer_len;
1524 header_field_info *hfinfo;
1526 di=pinfo->private_data;
1527 if(di->conformant_run){
1528 /* just a run to handle conformant arrays, no scalars to dissect */
1533 string_item = proto_tree_add_text(tree, tvb, offset, -1, "%s",
1534 proto_registrar_get_name(hfindex));
1535 string_tree = proto_item_add_subtree(string_item, ett_dcerpc_string);
1541 /* NDR array header */
1542 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1543 hf_dcerpc_array_offset, NULL);
1545 offset = dissect_ndr_uint32(tvb, offset, pinfo, string_tree, drep,
1546 hf_dcerpc_array_actual_count, &len);
1548 buffer_len = size_is * len;
1551 if (offset % size_is)
1552 offset += size_is - (offset % size_is);
1554 if (size_is == sizeof(guint16)) {
1555 /* XXX - use drep to determine the byte order? */
1556 s = tvb_fake_unicode(tvb, offset, buffer_len / 2, TRUE);
1558 * XXX - we don't support a string type with Unicode
1559 * characters, so if this is a string item, we make
1560 * its value be the "fake Unicode" string.
1562 if (tree && buffer_len) {
1563 hfinfo = proto_registrar_get_nth(hfindex);
1564 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1565 if (hfinfo->type == FT_STRING) {
1566 proto_tree_add_string(string_tree, hfindex, tvb, offset,
1569 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1570 buffer_len, drep[0] & 0x10);
1575 * "tvb_get_ephemeral_string()" throws an exception if the entire string
1576 * isn't in the tvbuff. If the length is bogus, this should
1577 * keep us from trying to allocate an immensely large buffer.
1578 * (It won't help if the length is *valid* but immensely large,
1579 * but that's another matter; in any case, that would happen only
1580 * if we had an immensely large tvbuff....)
1582 tvb_ensure_bytes_exist(tvb, offset, buffer_len);
1583 s = tvb_get_ephemeral_string(tvb, offset, buffer_len);
1584 if (tree && buffer_len)
1585 proto_tree_add_item(string_tree, hfindex, tvb, offset,
1586 buffer_len, drep[0] & 0x10);
1589 if (string_item != NULL)
1590 proto_item_append_text(string_item, ": %s", s);
1595 offset += buffer_len;
1597 proto_item_set_end(string_item, tvb, offset);
1602 /* Dissect an varying string of chars.
1603 This corresponds to IDL of the form '[string] char *foo'.
1605 XXX - at least according to the DCE RPC 1.1 spec, a string has
1606 a null terminator, which isn't necessary as a terminator for
1607 the transfer language (as there's a length), but is presumably
1608 there for the benefit of null-terminated-string languages
1609 such as C. Is this ever used for purely counted strings?
1610 (Not that it matters if it is.) */
1612 dissect_ndr_char_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1613 proto_tree *tree, guint8 *drep)
1616 di=pinfo->private_data;
1618 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1619 sizeof(guint8), di->hf_index,
1623 /* Dissect a varying string of wchars (wide characters).
1624 This corresponds to IDL of the form '[string] wchar *foo'
1626 XXX - at least according to the DCE RPC 1.1 spec, a string has
1627 a null terminator, which isn't necessary as a terminator for
1628 the transfer language (as there's a length), but is presumably
1629 there for the benefit of null-terminated-string languages
1630 such as C. Is this ever used for purely counted strings?
1631 (Not that it matters if it is.) */
1633 dissect_ndr_wchar_vstring(tvbuff_t *tvb, int offset, packet_info *pinfo,
1634 proto_tree *tree, guint8 *drep)
1637 di=pinfo->private_data;
1639 return dissect_ndr_vstring(tvb, offset, pinfo, tree, drep,
1640 sizeof(guint16), di->hf_index,
1645 /* ndr pointer handling */
1646 /* list of pointers encountered so far */
1647 static GSList *ndr_pointer_list = NULL;
1649 /* position where in the list to insert newly encountered pointers */
1650 static int ndr_pointer_list_pos=0;
1652 /* boolean controlling whether pointers are top-level or embedded */
1653 static gboolean pointers_are_top_level = TRUE;
1655 /* as a kludge, we represent all embedded reference pointers as id==-1
1656 hoping that his will not collide with any non-ref pointers */
1657 typedef struct ndr_pointer_data {
1659 proto_item *item; /* proto_item for pointer */
1660 proto_tree *tree; /* subtree of above item */
1661 dcerpc_dissect_fnct_t *fnct; /*if non-NULL, we have not called it yet*/
1663 dcerpc_callback_fnct_t *callback;
1664 void *callback_args;
1665 } ndr_pointer_data_t;
1668 init_ndr_pointer_list(packet_info *pinfo)
1672 di=pinfo->private_data;
1673 di->conformant_run=0;
1675 while(ndr_pointer_list){
1676 ndr_pointer_data_t *npd;
1678 npd=g_slist_nth_data(ndr_pointer_list, 0);
1679 ndr_pointer_list=g_slist_remove(ndr_pointer_list, npd);
1683 ndr_pointer_list=NULL;
1684 ndr_pointer_list_pos=0;
1685 pointers_are_top_level=TRUE;
1689 dissect_deferred_pointers(packet_info *pinfo, tvbuff_t *tvb, int offset, guint8 *drep)
1691 int found_new_pointer;
1697 di=pinfo->private_data;
1701 found_new_pointer=0;
1702 len=g_slist_length(ndr_pointer_list);
1703 for(i=next_pointer;i<len;i++){
1704 ndr_pointer_data_t *tnpd;
1705 tnpd=g_slist_nth_data(ndr_pointer_list, i);
1707 dcerpc_dissect_fnct_t *fnct;
1710 found_new_pointer=1;
1713 ndr_pointer_list_pos=i+1;
1714 di->hf_index=tnpd->hf_index;
1715 /* first a run to handle any conformant
1717 di->conformant_run=1;
1718 di->conformant_eaten=0;
1719 old_offset = offset;
1720 offset = (*(fnct))(tvb, offset, pinfo, NULL, drep);
1722 DISSECTOR_ASSERT((offset-old_offset)==di->conformant_eaten);
1723 /* This is to check for any bugs in the dissectors.
1725 * Basically, the NDR representation will store all
1726 * arrays in two blocks, one block with the dimension
1727 * discreption, like size, number of elements and such,
1728 * and another block that contains the actual data stored
1730 * If the array is embedded directly inside another,
1731 * encapsulating aggregate type, like a union or struct,
1732 * then these two blocks will be stored at different places
1733 * in the bytestream, with other data between the blocks.
1735 * For this reason, all pointers to types (both aggregate
1736 * and scalar, for simplicity no distinction is made)
1737 * will have its dissector called twice.
1738 * The dissector will first be called with conformant_run==1
1739 * in which mode the dissector MUST NOT consume any data from
1740 * the tvbuff (i.e. may not dissect anything) except the
1741 * initial control block for arrays.
1742 * The second time the dissector is called, with
1743 * conformant_run==0, all other data for the type will be
1746 * All dissect_ndr_<type> dissectors are already prepared
1747 * for this and knows when it should eat data from the tvb
1748 * and when not to, so implementors of dissectors will
1749 * normally not need to worry about this or even know about
1750 * it. However, if a dissector for an aggregate type calls
1751 * a subdissector from outside packet-dcerpc.c, such as
1752 * the dissector in packet-smb.c for NT Security Descriptors
1753 * as an example, then it is VERY important to encapsulate
1754 * this call to an external subdissector with the appropriate
1755 * test for conformant_run, i.e. it will need something like
1759 * di=pinfo->private_data;
1760 * if(di->conformant_run){
1764 * to make sure it makes the right thing.
1765 * This assert will signal when someone has forgotten to
1766 * make the dissector aware of this requirement.
1769 /* now we dissect the actual pointer */
1770 di->conformant_run=0;
1771 old_offset = offset;
1772 offset = (*(fnct))(tvb, offset, pinfo, tnpd->tree, drep);
1774 tnpd->callback(pinfo, tnpd->tree, tnpd->item, tvb, old_offset, offset, tnpd->callback_args);
1778 } while(found_new_pointer);
1785 add_pointer_to_list(packet_info *pinfo, proto_tree *tree, proto_item *item,
1786 dcerpc_dissect_fnct_t *fnct, guint32 id, int hf_index,
1787 dcerpc_callback_fnct_t *callback, void *callback_args)
1789 ndr_pointer_data_t *npd;
1791 /* check if this pointer is valid */
1794 dcerpc_call_value *value;
1796 di=pinfo->private_data;
1797 value=di->call_data;
1799 if(di->ptype == PDU_REQ){
1800 if(!(pinfo->fd->flags.visited)){
1801 if(id>value->max_ptr){
1806 /* if we havent seen the request bail out since we cant
1807 know whether this is the first non-NULL instance
1809 if(value->req_frame==0){
1810 /* XXX THROW EXCEPTION */
1813 /* We saw this one in the request frame, nothing to
1815 if(id<=value->max_ptr){
1821 npd=g_malloc(sizeof(ndr_pointer_data_t));
1826 npd->hf_index=hf_index;
1827 npd->callback=callback;
1828 npd->callback_args=callback_args;
1829 ndr_pointer_list = g_slist_insert(ndr_pointer_list, npd,
1830 ndr_pointer_list_pos);
1831 ndr_pointer_list_pos++;
1836 find_pointer_index(guint32 id)
1838 ndr_pointer_data_t *npd;
1841 len=g_slist_length(ndr_pointer_list);
1843 npd=g_slist_nth_data(ndr_pointer_list, i);
1854 /* This function dissects an NDR pointer and stores the callback for later
1855 * deferred dissection.
1857 * fnct is the callback function for when we have reached this object in
1860 * type is what type of pointer.
1862 * this is text is what text we should put in any created tree node.
1864 * hf_index is what hf value we want to pass to the callback function when
1865 * it is called, the callback can later pich this one up from di->hf_index.
1867 * callback is executed after the pointer has been dereferenced.
1869 * callback_args is passed as an argument to the callback function
1871 * See packet-dcerpc-samr.c for examples
1874 dissect_ndr_pointer_cb(tvbuff_t *tvb, gint offset, packet_info *pinfo,
1875 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
1876 int type, const char *text, int hf_index,
1877 dcerpc_callback_fnct_t *callback, void *callback_args)
1880 proto_tree *tr = NULL;
1881 gint start_offset = offset;
1883 di=pinfo->private_data;
1884 if(di->conformant_run){
1885 /* this call was only for dissecting the header for any
1886 embedded conformant array. we will not parse any
1887 pointers in this mode.
1891 /*TOP LEVEL REFERENCE POINTER*/
1892 if( pointers_are_top_level
1893 &&(type==NDR_POINTER_REF) ){
1896 /* we must find out a nice way to do the length here */
1897 item=proto_tree_add_text(tree, tvb, offset, 0,
1899 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1901 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1902 hf_index, callback, callback_args);
1906 /*TOP LEVEL FULL POINTER*/
1907 if( pointers_are_top_level
1908 && (type==NDR_POINTER_PTR) ){
1913 /* get the referent id */
1914 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1916 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1917 /* we got a NULL pointer */
1919 proto_tree_add_text(tree, tvb, offset-4, 4,
1920 "(NULL pointer) %s",text);
1924 /* see if we have seen this pointer before */
1925 idx=find_pointer_index(id);
1927 /* we have seen this pointer before */
1929 proto_tree_add_text(tree, tvb, offset-4, 4,
1930 "(duplicate PTR) %s",text);
1935 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1937 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1938 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1939 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
1940 callback, callback_args);
1943 /*TOP LEVEL UNIQUE POINTER*/
1944 if( pointers_are_top_level
1945 && (type==NDR_POINTER_UNIQUE) ){
1949 /* get the referent id */
1950 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1952 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1953 /* we got a NULL pointer */
1955 proto_tree_add_text(tree, tvb, offset-4, 4,
1956 "(NULL pointer) %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, 0xffffffff,
1966 hf_index, callback, callback_args);
1970 /*EMBEDDED REFERENCE POINTER*/
1971 if( (!pointers_are_top_level)
1972 && (type==NDR_POINTER_REF) ){
1976 /* get the referent id */
1977 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1979 tvb_ensure_bytes_exist(tvb, offset-4, 4);
1981 item=proto_tree_add_text(tree, tvb, offset-4, 4,
1983 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
1984 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
1985 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
1986 hf_index, callback, callback_args);
1990 /*EMBEDDED UNIQUE POINTER*/
1991 if( (!pointers_are_top_level)
1992 && (type==NDR_POINTER_UNIQUE) ){
1996 /* get the referent id */
1997 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
1999 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2000 /* we got a NULL pointer */
2002 proto_tree_add_text(tree, tvb, offset-4, 4,
2003 "(NULL pointer) %s", text);
2008 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2010 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2011 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2012 add_pointer_to_list(pinfo, tr, item, fnct, 0xffffffff,
2013 hf_index, callback, callback_args);
2017 /*EMBEDDED FULL POINTER*/
2018 if( (!pointers_are_top_level)
2019 && (type==NDR_POINTER_PTR) ){
2024 /* get the referent id */
2025 offset = dissect_ndr_uint32(tvb, offset, pinfo, NULL, drep, -1, &id);
2026 tvb_ensure_bytes_exist(tvb, offset-4, 4);
2027 /* we got a NULL pointer */
2029 proto_tree_add_text(tree, tvb, offset-4, 4,
2030 "(NULL pointer) %s",text);
2034 /* see if we have seen this pointer before */
2035 idx=find_pointer_index(id);
2037 /* we have seen this pointer before */
2039 proto_tree_add_text(tree, tvb, offset-4, 4,
2040 "(duplicate PTR) %s",text);
2045 item=proto_tree_add_text(tree, tvb, offset-4, 4,
2047 tr=proto_item_add_subtree(item,ett_dcerpc_pointer_data);
2048 proto_tree_add_uint(tr, hf_dcerpc_referent_id, tvb, offset-4, 4, id);
2049 add_pointer_to_list(pinfo, tr, item, fnct, id, hf_index,
2050 callback, callback_args);
2056 /* After each top level pointer we have dissected we have to
2057 dissect all deferrals before we move on to the next top level
2059 if(pointers_are_top_level==TRUE){
2060 pointers_are_top_level=FALSE;
2061 offset = dissect_deferred_pointers(pinfo, tvb, offset, drep);
2062 pointers_are_top_level=TRUE;
2065 /* Set the length for the new subtree */
2067 proto_item_set_len(tr, offset-start_offset);
2073 dissect_ndr_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2074 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2075 int type, const char *text, int hf_index)
2077 return dissect_ndr_pointer_cb(
2078 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2082 dissect_ndr_toplevel_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2083 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2084 int type, const char *text, int hf_index)
2088 pointers_are_top_level=TRUE;
2089 ret=dissect_ndr_pointer_cb(
2090 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2095 dissect_ndr_embedded_pointer(tvbuff_t *tvb, gint offset, packet_info *pinfo,
2096 proto_tree *tree, guint8 *drep, dcerpc_dissect_fnct_t *fnct,
2097 int type, const char *text, int hf_index)
2101 pointers_are_top_level=FALSE;
2102 ret=dissect_ndr_pointer_cb(
2103 tvb, offset, pinfo, tree, drep, fnct, type, text, hf_index,
2109 show_stub_data (tvbuff_t *tvb, gint offset, proto_tree *dcerpc_tree,
2110 dcerpc_auth_info *auth_info, gboolean is_encrypted)
2112 int length, plain_length, auth_pad_len;
2113 guint auth_pad_offset;
2116 * We don't show stub data unless we have some in the tvbuff;
2117 * however, in the protocol tree, we show, as the number of
2118 * bytes, the reported number of bytes, not the number of bytes
2119 * that happen to be in the tvbuff.
2121 if (tvb_length_remaining (tvb, offset) > 0) {
2122 auth_pad_len = auth_info?auth_info->auth_pad_len:0;
2123 length = tvb_reported_length_remaining (tvb, offset);
2125 /* if auth_pad_len is larger than length then we ignore auth_pad_len totally */
2126 plain_length = length - auth_pad_len;
2127 if (plain_length < 1) {
2128 plain_length = length;
2131 auth_pad_offset = offset + plain_length;
2132 if (auth_info != NULL &&
2133 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2135 tvb_ensure_bytes_exist(tvb, offset, length);
2136 proto_tree_add_text(dcerpc_tree, tvb, offset, length,
2137 "Encrypted stub data (%d byte%s)",
2138 length, plurality(length, "", "s"));
2139 /* is the padding is still inside the encrypted blob, don't display it explicit */
2143 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2144 proto_tree_add_text(dcerpc_tree, tvb, offset, plain_length,
2145 "Decrypted stub data (%d byte%s)",
2146 plain_length, plurality(plain_length, "", "s"));
2150 tvb_ensure_bytes_exist(tvb, offset, plain_length);
2151 proto_tree_add_text (dcerpc_tree, tvb, offset, plain_length,
2152 "Stub data (%d byte%s)", plain_length,
2153 plurality(plain_length, "", "s"));
2155 /* If there is auth padding at the end of the stub, display it */
2156 if (auth_pad_len != 0) {
2157 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2158 proto_tree_add_text (dcerpc_tree, tvb, auth_pad_offset,
2159 auth_pad_len, "Auth Padding (%u byte%s)",
2160 auth_pad_len, plurality(auth_pad_len, "", "s"));
2166 dcerpc_try_handoff (packet_info *pinfo, proto_tree *tree,
2167 proto_tree *dcerpc_tree,
2168 tvbuff_t *volatile tvb, tvbuff_t *decrypted_tvb,
2169 guint8 *drep, dcerpc_info *info,
2170 dcerpc_auth_info *auth_info)
2172 volatile gint offset = 0;
2173 dcerpc_uuid_key key;
2174 dcerpc_uuid_value *sub_proto;
2175 proto_tree *volatile sub_tree = NULL;
2176 dcerpc_sub_dissector *proc;
2177 const gchar *name = NULL;
2178 dcerpc_dissect_fnct_t *volatile sub_dissect;
2179 const char *volatile saved_proto;
2180 void *volatile saved_private_data;
2181 guint length = 0, reported_length = 0;
2182 tvbuff_t *volatile stub_tvb;
2183 volatile guint auth_pad_len;
2184 volatile int auth_pad_offset;
2185 proto_item *sub_item=NULL;
2186 proto_item *pi, *hidden_item;
2188 key.uuid = info->call_data->uuid;
2189 key.ver = info->call_data->ver;
2192 if ((sub_proto = g_hash_table_lookup (dcerpc_uuids, &key)) == NULL
2193 || !proto_is_protocol_enabled(sub_proto->proto)) {
2195 * We don't have a dissector for this UUID, or the protocol
2196 * for that UUID is disabled.
2199 hidden_item = proto_tree_add_boolean(dcerpc_tree, hf_dcerpc_unknown_if_id,
2200 tvb, offset, 0, TRUE);
2201 PROTO_ITEM_SET_HIDDEN(hidden_item);
2202 if (check_col (pinfo->cinfo, COL_INFO)) {
2203 col_append_fstr (pinfo->cinfo, COL_INFO, " %s V%u",
2204 guids_resolve_uuid_to_str(&info->call_data->uuid), info->call_data->ver);
2207 if (decrypted_tvb != NULL) {
2208 show_stub_data (decrypted_tvb, 0, dcerpc_tree, auth_info,
2211 show_stub_data (tvb, 0, dcerpc_tree, auth_info, TRUE);
2215 for (proc = sub_proto->procs; proc->name; proc++) {
2216 if (proc->num == info->call_data->opnum) {
2225 if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
2226 col_set_str (pinfo->cinfo, COL_PROTOCOL, sub_proto->name);
2229 if (check_col (pinfo->cinfo, COL_INFO)) {
2230 col_add_fstr (pinfo->cinfo, COL_INFO, "%s %s",
2231 name, (info->ptype == PDU_REQ) ? "request" : "response");
2234 sub_dissect = (info->ptype == PDU_REQ) ?
2235 proc->dissect_rqst : proc->dissect_resp;
2238 sub_item = proto_tree_add_item (tree, sub_proto->proto_id,
2239 (decrypted_tvb != NULL)?decrypted_tvb:tvb,
2243 sub_tree = proto_item_add_subtree (sub_item, sub_proto->ett);
2244 proto_item_append_text(sub_item, ", %s", name);
2248 * Put the operation number into the tree along with
2249 * the operation's name.
2251 if (sub_proto->opnum_hf != -1)
2252 proto_tree_add_uint_format(sub_tree, sub_proto->opnum_hf,
2253 tvb, 0, 0, info->call_data->opnum,
2254 "Operation: %s (%u)",
2255 name, info->call_data->opnum);
2257 proto_tree_add_uint_format(sub_tree, hf_dcerpc_op, tvb,
2258 0, 0, info->call_data->opnum,
2259 "Operation: %s (%u)",
2260 name, info->call_data->opnum);
2262 if(info->ptype == PDU_REQ && info->call_data->rep_frame!=0) {
2263 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_response_in,
2264 tvb, 0, 0, info->call_data->rep_frame);
2265 PROTO_ITEM_SET_GENERATED(pi);
2267 if(info->ptype == PDU_RESP && info->call_data->req_frame!=0) {
2268 pi = proto_tree_add_uint(sub_tree, hf_dcerpc_request_in,
2269 tvb, 0, 0, info->call_data->req_frame);
2270 PROTO_ITEM_SET_GENERATED(pi);
2274 if (decrypted_tvb != NULL) {
2275 /* Either there was no encryption or we successfully decrypted
2276 the encrypted payload. */
2278 /* We have a subdissector - call it. */
2279 saved_proto = pinfo->current_proto;
2280 saved_private_data = pinfo->private_data;
2281 pinfo->current_proto = sub_proto->name;
2282 pinfo->private_data = (void *)info;
2284 init_ndr_pointer_list(pinfo);
2286 length = tvb_length(decrypted_tvb);
2287 reported_length = tvb_reported_length(decrypted_tvb);
2290 * Remove the authentication padding from the stub data.
2292 if (auth_info != NULL && auth_info->auth_pad_len != 0) {
2293 if (reported_length >= auth_info->auth_pad_len) {
2295 * OK, the padding length isn't so big that it
2296 * exceeds the stub length. Trim the reported
2297 * length of the tvbuff.
2299 reported_length -= auth_info->auth_pad_len;
2302 * If that exceeds the actual amount of data in
2303 * the tvbuff (which means we have at least one
2304 * byte of authentication padding in the tvbuff),
2305 * trim the actual amount.
2307 if (length > reported_length)
2308 length = reported_length;
2310 stub_tvb = tvb_new_subset(decrypted_tvb, 0, length, reported_length);
2311 auth_pad_len = auth_info->auth_pad_len;
2312 auth_pad_offset = reported_length;
2315 * The padding length exceeds the stub length.
2316 * Don't bother dissecting the stub, trim the padding
2317 * length to what's in the stub data, and show the
2318 * entire stub as authentication padding.
2321 auth_pad_len = reported_length;
2322 auth_pad_offset = 0;
2324 reported_length = 0;
2328 * No authentication padding.
2330 stub_tvb = decrypted_tvb;
2332 auth_pad_offset = 0;
2336 proto_item_set_len(sub_item, length);
2339 if (stub_tvb != NULL) {
2341 * Catch all exceptions other than BoundsError, so that even
2342 * if the stub data is bad, we still show the authentication
2345 * If we get BoundsError, it means the frame was cut short
2346 * by a snapshot length, so there's nothing more to
2347 * dissect; just re-throw that exception.
2352 offset = sub_dissect (stub_tvb, 0, pinfo, sub_tree,
2355 /* If we have a subdissector and it didn't dissect all
2356 data in the tvb, make a note of it. */
2357 remaining = tvb_reported_length_remaining(stub_tvb, offset);
2358 if (remaining > 0) {
2359 proto_tree_add_text(sub_tree, stub_tvb, offset,
2361 "[Long frame (%d byte%s)]",
2363 plurality(remaining, "", "s"));
2364 if (check_col(pinfo->cinfo, COL_INFO))
2365 col_append_fstr(pinfo->cinfo, COL_INFO,
2366 "[Long frame (%d byte%s)]",
2368 plurality(remaining, "", "s"));
2371 } CATCH(BoundsError) {
2374 show_exception(stub_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
2378 /* If there is auth padding at the end of the stub, display it */
2379 if (auth_pad_len != 0) {
2380 tvb_ensure_bytes_exist(tvb, auth_pad_offset, auth_pad_len);
2381 proto_tree_add_text (sub_tree, decrypted_tvb, auth_pad_offset,
2383 "Auth Padding (%u byte%s)",
2385 plurality(auth_pad_len, "", "s"));
2388 pinfo->current_proto = saved_proto;
2389 pinfo->private_data = saved_private_data;
2391 /* No subdissector - show it as stub data. */
2393 show_stub_data (decrypted_tvb, 0, sub_tree, auth_info, FALSE);
2395 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2399 show_stub_data (tvb, 0, sub_tree, auth_info, TRUE);
2401 tap_queue_packet(dcerpc_tap, pinfo, info);
2406 dissect_dcerpc_verifier (tvbuff_t *tvb, packet_info *pinfo,
2407 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2408 dcerpc_auth_info *auth_info)
2412 auth_info->auth_data = NULL;
2414 if (auth_info->auth_size != 0) {
2415 dcerpc_auth_subdissector_fns *auth_fns;
2418 auth_offset = hdr->frag_len - hdr->auth_len;
2420 auth_tvb = tvb_new_subset(tvb, auth_offset, hdr->auth_len,
2423 auth_info->auth_data = auth_tvb;
2425 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2426 auth_info->auth_type))) {
2428 * Catch all exceptions, so that even if the verifier is bad
2429 * or we don't have all of it, we still show the stub data.
2432 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2435 show_exception(auth_tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2438 tvb_ensure_bytes_exist(tvb, 0, hdr->auth_len);
2439 proto_tree_add_text (dcerpc_tree, auth_tvb, 0, hdr->auth_len,
2444 return hdr->auth_len;
2448 dissect_dcerpc_cn_auth (tvbuff_t *tvb, int stub_offset, packet_info *pinfo,
2449 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr,
2450 gboolean are_credentials, dcerpc_auth_info *auth_info)
2452 volatile int offset;
2455 * Initially set auth_level and auth_type to zero to indicate that we
2456 * haven't yet seen any authentication level information.
2458 auth_info->auth_level = 0;
2459 auth_info->auth_type = 0;
2460 auth_info->auth_size = 0;
2461 auth_info->auth_pad_len = 0;
2464 * The authentication information is at the *end* of the PDU; in
2465 * request and response PDUs, the request and response stub data
2468 * Is there any authentication data (i.e., is the authentication length
2469 * non-zero), and is the authentication length valid (i.e., is it, plus
2470 * 8 bytes for the type/level/pad length/reserved/context id, less than
2471 * or equal to the fragment length minus the starting offset of the
2476 && (hdr->auth_len + 8 <= hdr->frag_len - stub_offset)) {
2479 * Yes, there is authentication data, and the length is valid.
2480 * Do we have all the bytes of stub data?
2481 * (If not, we'd throw an exception dissecting *that*, so don't
2482 * bother trying to dissect the authentication information and
2483 * throwing another exception there.)
2485 offset = hdr->frag_len - (hdr->auth_len + 8);
2486 if (offset == 0 || tvb_offset_exists(tvb, offset - 1)) {
2488 * Either there's no stub data, or the last byte of the stub
2489 * data is present in the captured data, so we shouldn't
2490 * get a BoundsError dissecting the stub data.
2492 * Try dissecting the authentication data.
2493 * Catch all exceptions, so that even if the auth info is bad
2494 * or we don't have all of it, we still show the stuff we
2495 * dissect after this, such as stub data.
2498 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2499 hf_dcerpc_auth_type,
2500 &auth_info->auth_type);
2501 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2502 hf_dcerpc_auth_level,
2503 &auth_info->auth_level);
2505 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2506 hf_dcerpc_auth_pad_len,
2507 &auth_info->auth_pad_len);
2508 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2509 hf_dcerpc_auth_rsrvd, NULL);
2510 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2511 hf_dcerpc_auth_ctx_id, NULL);
2514 * Dissect the authentication data.
2516 if (are_credentials) {
2518 dcerpc_auth_subdissector_fns *auth_fns;
2520 auth_tvb = tvb_new_subset(tvb, offset,
2521 MIN(hdr->auth_len,tvb_length_remaining(tvb, offset)),
2524 if ((auth_fns = get_auth_subdissector_fns(auth_info->auth_level,
2525 auth_info->auth_type)))
2526 dissect_auth_verf(auth_tvb, pinfo, dcerpc_tree, auth_fns,
2529 proto_tree_add_text (dcerpc_tree, tvb, offset, hdr->auth_len,
2530 "Auth Credentials");
2533 /* Compute the size of the auth block. Note that this should not
2534 include auth padding, since when NTLMSSP encryption is used, the
2535 padding is actually inside the encrypted stub */
2536 auth_info->auth_size = hdr->auth_len + 8;
2538 show_exception(tvb, pinfo, dcerpc_tree, EXCEPT_CODE, GET_MESSAGE);
2545 /* We need to hash in the SMB fid number to generate a unique hash table
2546 * key as DCERPC over SMB allows several pipes over the same TCP/IP
2548 * We pass this function the transport type here to make sure we only look
2549 * at this function if it came across an SMB pipe.
2550 * Other transports might need to mix in their own extra multiplexing data
2551 * as well in the future.
2554 guint16 dcerpc_get_transport_salt (packet_info *pinfo)
2556 switch(pinfo->dcetransporttype){
2557 case DCE_CN_TRANSPORT_SMBPIPE:
2558 /* DCERPC over smb */
2559 return pinfo->dcetransportsalt;
2562 /* Some other transport... */
2567 * Connection oriented packet types
2571 dissect_dcerpc_cn_bind (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2572 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2574 conversation_t *conv = NULL;
2575 guint8 num_ctx_items = 0;
2577 gboolean saw_ctx_item = FALSE;
2579 guint8 num_trans_items;
2584 guint16 if_ver, if_ver_minor;
2585 dcerpc_auth_info auth_info;
2587 const char *uuid_name = NULL;
2588 proto_item *iface_item = NULL;
2590 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2591 hf_dcerpc_cn_max_xmit, NULL);
2593 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2594 hf_dcerpc_cn_max_recv, NULL);
2596 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2597 hf_dcerpc_cn_assoc_group, NULL);
2599 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2600 hf_dcerpc_cn_num_ctx_items, &num_ctx_items);
2605 for (i = 0; i < num_ctx_items; i++) {
2606 proto_item *ctx_item = NULL;
2607 proto_tree *ctx_tree = NULL, *iface_tree = NULL;
2608 gint ctx_offset = offset;
2610 dissect_dcerpc_uint16 (tvb, offset, pinfo, NULL, hdr->drep,
2611 hf_dcerpc_cn_ctx_id, &ctx_id);
2613 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
2614 if(pinfo->dcectxid == 0) {
2615 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
2617 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
2618 * prepend a delimiter */
2619 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
2623 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
2624 /* (if we have multiple contexts, this might cause "decode as"
2625 * to behave unpredictably) */
2626 pinfo->dcectxid = ctx_id;
2629 ctx_item = proto_tree_add_item(dcerpc_tree, hf_dcerpc_cn_ctx_item,
2631 hdr->drep[0] & 0x10);
2632 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2635 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2636 hf_dcerpc_cn_ctx_id, &ctx_id);
2637 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2638 hf_dcerpc_cn_num_trans_items, &num_trans_items);
2641 proto_item_append_text(ctx_item, "[%u]: ID:%u", i+1, ctx_id);
2647 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &if_id);
2650 iface_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_abstract_syntax, tvb, offset, 0, FALSE);
2651 iface_tree = proto_item_add_subtree(iface_item, ett_dcerpc_cn_iface);
2653 uuid_str = guid_to_str((e_guid_t*)&if_id);
2654 uuid_name = guids_get_uuid_name(&if_id);
2656 proto_tree_add_guid_format (iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
2657 offset, 16, (e_guid_t *) &if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
2658 proto_item_append_text(iface_item, ": %s", uuid_name);
2660 proto_tree_add_guid_format (iface_tree, hf_dcerpc_cn_bind_if_id, tvb,
2661 offset, 16, (e_guid_t *) &if_id, "Interface UUID: %s", uuid_str);
2662 proto_item_append_text(iface_item, ": %s", uuid_str);
2667 if (hdr->drep[0] & 0x10) {
2668 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2669 hf_dcerpc_cn_bind_if_ver, &if_ver);
2670 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2671 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2673 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2674 hf_dcerpc_cn_bind_if_ver_minor, &if_ver_minor);
2675 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, iface_tree, hdr->drep,
2676 hf_dcerpc_cn_bind_if_ver, &if_ver);
2680 proto_item_append_text(iface_item, " V%u.%u", if_ver, if_ver_minor);
2681 proto_item_set_len(iface_item, 20);
2684 if (!saw_ctx_item) {
2685 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2686 pinfo->srcport, pinfo->destport, 0);
2688 fprintf(stderr,"Creating a new conv on packet %d\n",pinfo->fd->num);
2689 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
2690 pinfo->srcport, pinfo->destport, 0);
2694 /* if this is the first time we see this packet, we need to
2695 update the dcerpc_binds table so that any later calls can
2696 match to the interface.
2697 XXX We assume that BINDs will NEVER be fragmented.
2699 if(!(pinfo->fd->flags.visited)){
2700 dcerpc_bind_key *key;
2701 dcerpc_bind_value *value;
2703 key = se_alloc (sizeof (dcerpc_bind_key));
2705 key->ctx_id = ctx_id;
2706 key->smb_fid = dcerpc_get_transport_salt(pinfo);
2708 value = se_alloc (sizeof (dcerpc_bind_value));
2709 value->uuid = if_id;
2710 value->ver = if_ver;
2712 /* add this entry to the bind table, first removing any
2713 previous ones that are identical
2715 if(g_hash_table_lookup(dcerpc_binds, key)){
2716 g_hash_table_remove(dcerpc_binds, key);
2718 g_hash_table_insert (dcerpc_binds, key, value);
2721 if (check_col (pinfo->cinfo, COL_INFO)) {
2722 if (num_ctx_items > 1)
2723 col_append_fstr(pinfo->cinfo, COL_INFO, ", %u context items, 1st", num_ctx_items);
2725 col_append_fstr(pinfo->cinfo, COL_INFO, " %s V%u.%u",
2726 guids_resolve_uuid_to_str(&if_id), if_ver, if_ver_minor);
2728 saw_ctx_item = TRUE;
2731 for (j = 0; j < num_trans_items; j++) {
2732 proto_tree *trans_tree = NULL;
2733 proto_item *trans_item = NULL;
2735 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2738 trans_item = proto_tree_add_item(ctx_tree, hf_dcerpc_cn_bind_trans_syntax, tvb, offset, 0, FALSE);
2739 trans_tree = proto_item_add_subtree(trans_item, ett_dcerpc_cn_trans_syntax);
2741 uuid_str = guid_to_str((e_guid_t *) &trans_id);
2742 proto_tree_add_guid_format (trans_tree, hf_dcerpc_cn_bind_trans_id, tvb,
2743 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s", uuid_str);
2744 proto_item_append_text(trans_item, "[%u]: %s", j+1, uuid_str);
2748 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, trans_tree, hdr->drep,
2749 hf_dcerpc_cn_bind_trans_ver, &trans_ver);
2751 proto_item_set_len(trans_item, 20);
2752 proto_item_append_text(trans_item, " V%u", trans_ver);
2757 proto_item_set_len(ctx_item, offset - ctx_offset);
2762 * XXX - we should save the authentication type *if* we have
2763 * an authentication header, and associate it with an authentication
2764 * context, so subsequent PDUs can use that context.
2766 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2770 dissect_dcerpc_cn_bind_ack (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2771 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2773 guint16 max_xmit, max_recv;
2774 guint16 sec_addr_len;
2781 dcerpc_auth_info auth_info;
2783 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2784 hf_dcerpc_cn_max_xmit, &max_xmit);
2786 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2787 hf_dcerpc_cn_max_recv, &max_recv);
2789 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2790 hf_dcerpc_cn_assoc_group, NULL);
2792 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2793 hf_dcerpc_cn_sec_addr_len, &sec_addr_len);
2794 if (sec_addr_len != 0) {
2795 tvb_ensure_bytes_exist(tvb, offset, sec_addr_len);
2796 proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_sec_addr, tvb, offset,
2797 sec_addr_len, FALSE);
2798 offset += sec_addr_len;
2802 offset += 4 - offset % 4;
2805 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2806 hf_dcerpc_cn_num_results, &num_results);
2811 for (i = 0; i < num_results; i++) {
2812 proto_tree *ctx_tree = NULL;
2815 proto_item *ctx_item;
2816 ctx_item = proto_tree_add_text(dcerpc_tree, tvb, offset, 24, "Context ID[%u]", i+1);
2817 ctx_tree = proto_item_add_subtree(ctx_item, ett_dcerpc_cn_ctx);
2820 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
2821 hdr->drep, hf_dcerpc_cn_ack_result,
2824 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, ctx_tree,
2825 hdr->drep, hf_dcerpc_cn_ack_reason,
2829 * The reason for rejection isn't meaningful, and often isn't
2830 * set, when the syntax was accepted.
2835 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &trans_id);
2837 proto_tree_add_guid_format (ctx_tree, hf_dcerpc_cn_ack_trans_id, tvb,
2838 offset, 16, (e_guid_t *) &trans_id, "Transfer Syntax: %s",
2839 guid_to_str((e_guid_t *) &trans_id));
2843 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, ctx_tree, hdr->drep,
2844 hf_dcerpc_cn_ack_trans_ver, &trans_ver);
2848 * XXX - do we need to do anything with the authentication level
2849 * we get back from this?
2851 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, &auth_info);
2853 if (check_col (pinfo->cinfo, COL_INFO)) {
2854 if (num_results != 0 && result == 0) {
2855 /* XXX - only checks the last result */
2856 col_append_fstr (pinfo->cinfo, COL_INFO,
2857 " accept max_xmit: %u max_recv: %u",
2858 max_xmit, max_recv);
2860 /* XXX - only shows the last result and reason */
2861 col_append_fstr (pinfo->cinfo, COL_INFO, " %s, reason: %s",
2862 val_to_str(result, p_cont_result_vals,
2863 "Unknown result (%u)"),
2864 val_to_str(reason, p_provider_reason_vals,
2871 dissect_dcerpc_cn_bind_nak (tvbuff_t *tvb, gint offset, packet_info *pinfo,
2872 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
2875 guint8 num_protocols;
2878 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
2879 hdr->drep, hf_dcerpc_cn_reject_reason,
2882 if (check_col (pinfo->cinfo, COL_INFO)) {
2883 col_append_fstr (pinfo->cinfo, COL_INFO, " reason: %s",
2884 val_to_str(reason, reject_reason_vals, "Unknown (%u)"));
2887 if (reason == PROTOCOL_VERSION_NOT_SUPPORTED) {
2888 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
2889 hf_dcerpc_cn_num_protocols,
2892 for (i = 0; i < num_protocols; i++) {
2893 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2894 hdr->drep, hf_dcerpc_cn_protocol_ver_major,
2896 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
2897 hdr->drep, hf_dcerpc_cn_protocol_ver_minor,
2903 /* Return a string describing a DCE/RPC fragment as first, middle, or end
2906 #define PFC_FRAG_MASK 0x03
2909 fragment_type(guint8 flags)
2911 flags = flags & PFC_FRAG_MASK;
2913 if (flags == PFC_FIRST_FRAG)
2919 if (flags == PFC_LAST_FRAG)
2922 if (flags == (PFC_FIRST_FRAG | PFC_LAST_FRAG))
2928 /* Dissect stub data (payload) of a DCERPC packet. */
2931 dissect_dcerpc_cn_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
2932 proto_tree *dcerpc_tree, proto_tree *tree,
2933 e_dce_cn_common_hdr_t *hdr, dcerpc_info *di,
2934 dcerpc_auth_info *auth_info, guint32 alloc_hint _U_,
2937 gint length, reported_length;
2938 gboolean save_fragmented;
2939 fragment_data *fd_head=NULL;
2941 tvbuff_t *auth_tvb, *payload_tvb, *decrypted_tvb;
2943 proto_item *parent_pi;
2944 proto_item *dcerpc_tree_item;
2946 save_fragmented = pinfo->fragmented;
2947 length = tvb_length_remaining(tvb, offset);
2948 reported_length = tvb_reported_length_remaining(tvb, offset);
2949 if (reported_length < 0 ||
2950 (guint32)reported_length < auth_info->auth_size) {
2951 /* We don't even have enough bytes for the authentication
2955 reported_length -= auth_info->auth_size;
2956 if (length > reported_length)
2957 length = reported_length;
2958 payload_tvb = tvb_new_subset(tvb, offset, length, reported_length);
2961 /*dont bother if we dont have the entire tvb */
2962 /*XXX we should really make sure we calculate auth_info->auth_data
2963 *and use that one instead of this auth_tvb hack
2965 if(tvb_length(tvb)==tvb_reported_length(tvb)){
2966 if(tvb_length_remaining(tvb, offset+length)>8){
2967 auth_tvb = tvb_new_subset(tvb, offset+length+8, -1, -1);
2971 /* Decrypt the PDU if it is encrypted */
2973 if (auth_info->auth_type &&
2974 auth_info->auth_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY) {
2976 * We know the authentication type, and the authentication
2977 * level is "Packet privacy", meaning the payload is
2978 * encrypted; attempt to decrypt it.
2980 dcerpc_auth_subdissector_fns *auth_fns;
2982 /* Start out assuming we won't succeed in decrypting. */
2983 decrypted_tvb = NULL;
2984 /* Schannel needs informations into the footer (verifier) in order to setup decryptions keys
2985 * so we call it in order to have a chance to decypher the data
2987 if (DCE_C_RPC_AUTHN_PROTOCOL_SEC_CHAN == auth_info->auth_type) {
2988 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, TRUE, auth_info);
2991 if ((auth_fns = get_auth_subdissector_fns(
2992 auth_info->auth_level, auth_info->auth_type))) {
2994 result = decode_encrypted_data( payload_tvb, auth_tvb, pinfo, auth_fns,
2995 hdr->ptype == PDU_REQ, auth_info);
2998 proto_tree_add_text(dcerpc_tree, payload_tvb, 0, -1,
2999 "Encrypted stub data (%d byte%s)",
3000 tvb_reported_length(payload_tvb),
3001 plurality(tvb_length(payload_tvb), "", "s"));
3003 add_new_data_source(pinfo, result, "Decrypted stub data");
3005 decrypted_tvb = result;
3010 decrypted_tvb = payload_tvb;
3012 /* if this packet is not fragmented, just dissect it and exit */
3013 if(PFC_NOT_FRAGMENTED(hdr)) {
3014 pinfo->fragmented = FALSE;
3016 dcerpc_try_handoff( pinfo, tree, dcerpc_tree, payload_tvb,
3017 decrypted_tvb, hdr->drep, di, auth_info);
3019 pinfo->fragmented = save_fragmented;
3023 /* The packet is fragmented. */
3024 pinfo->fragmented = TRUE;
3026 /* debug output of essential fragment data. */
3027 /* leave it here for future debugging sessions */
3028 /*printf("DCE num:%u offset:%u frag_len:%u tvb_len:%u\n",
3029 pinfo->fd->num, offset, hdr->frag_len, tvb_length(decrypted_tvb));*/
3031 /* if we are not doing reassembly and this is the first fragment
3032 then just dissect it and exit
3033 XXX - if we're not doing reassembly, can we decrypt an
3036 if( (!dcerpc_reassemble) && hdr->flags&PFC_FIRST_FRAG ){
3039 pinfo, tree, dcerpc_tree, payload_tvb, decrypted_tvb,
3040 hdr->drep, di, auth_info);
3042 if (check_col(pinfo->cinfo, COL_INFO)) {
3043 col_append_fstr(pinfo->cinfo, COL_INFO,
3044 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3046 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3047 "%s fragment", fragment_type(hdr->flags));
3048 pinfo->fragmented = save_fragmented;
3052 /* if we have already seen this packet, see if it was reassembled
3053 and if so dissect the full pdu.
3056 if(pinfo->fd->flags.visited){
3057 fd_head=fragment_get_reassembled(pinfo, frame, dcerpc_co_reassemble_table);
3061 /* if we are not doing reassembly and it was neither a complete PDU
3062 nor the first fragment then there is nothing more we can do
3063 so we just have to exit
3065 if( !dcerpc_reassemble || (tvb_length(tvb)!=tvb_reported_length(tvb)) )
3068 /* if we didnt get 'frame' we dont know where the PDU started and thus
3069 it is pointless to continue
3074 /* from now on we must attempt to reassemble the PDU
3077 /* if we get here we know it is the first time we see the packet
3078 and we also know it is only a fragment and not a full PDU,
3079 thus we must reassemble it.
3082 /* Do we have any non-encrypted data to reassemble? */
3083 if (decrypted_tvb == NULL) {
3084 /* No. We can't even try to reassemble. */
3088 /* defragmentation is a bit tricky, as there's no offset of the fragment
3089 * in the protocol data.
3091 * just use fragment_add_seq_next() and hope that TCP/SMB segments coming
3092 * in with the correct sequence.
3094 fd_head = fragment_add_seq_next(decrypted_tvb, 0, pinfo, frame,
3095 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3096 tvb_length(decrypted_tvb),
3097 hdr->flags&PFC_LAST_FRAG ? FALSE : TRUE /* more_frags */);
3101 /* if reassembly is complete and this is the last fragment
3102 * (multiple fragments in one PDU are possible!)
3103 * dissect the full PDU
3105 if(fd_head && (fd_head->flags&FD_DEFRAGMENTED) ){
3107 if(pinfo->fd->num==fd_head->reassembled_in && (hdr->flags&PFC_LAST_FRAG) ){
3109 proto_item *frag_tree_item;
3111 next_tvb = tvb_new_child_real_data((decrypted_tvb)?decrypted_tvb:payload_tvb,
3112 fd_head->data, fd_head->len, fd_head->len);
3114 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3115 show_fragment_tree(fd_head, &dcerpc_frag_items,
3116 tree, pinfo, next_tvb, &frag_tree_item);
3117 /* the toplevel fragment subtree is now behind all desegmented data,
3118 * move it right behind the DCE/RPC tree */
3119 dcerpc_tree_item = proto_tree_get_parent(dcerpc_tree);
3120 if(frag_tree_item && dcerpc_tree_item) {
3121 proto_tree_move_item(tree, dcerpc_tree_item, frag_tree_item);
3124 pinfo->fragmented = FALSE;
3126 expert_add_info_format(pinfo, frag_tree_item, PI_REASSEMBLE, PI_CHAT,
3127 "%s fragment, reassembled",
3128 fragment_type(hdr->flags));
3130 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
3131 next_tvb, hdr->drep, di, auth_info);
3135 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3136 decrypted_tvb, 0, 0, fd_head->reassembled_in);
3138 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
3139 payload_tvb, 0, 0, fd_head->reassembled_in);
3141 PROTO_ITEM_SET_GENERATED(pi);
3142 parent_pi = proto_tree_get_parent(dcerpc_tree);
3143 if(parent_pi != NULL) {
3144 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
3146 if (check_col(pinfo->cinfo, COL_INFO)) {
3147 col_append_fstr(pinfo->cinfo, COL_INFO,
3148 " [DCE/RPC %s fragment, reas: #%u]", fragment_type(hdr->flags), fd_head->reassembled_in);
3150 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3151 "%s fragment, reassembled in #%u", fragment_type(hdr->flags), fd_head->reassembled_in);
3154 /* Reassembly not complete - some fragments
3155 are missing. Just show the stub data. */
3156 if (check_col(pinfo->cinfo, COL_INFO)) {
3157 col_append_fstr(pinfo->cinfo, COL_INFO,
3158 " [DCE/RPC %s fragment]", fragment_type(hdr->flags));
3160 expert_add_info_format(pinfo, NULL, PI_REASSEMBLE, PI_CHAT,
3161 "%s fragment", fragment_type(hdr->flags));
3164 show_stub_data (decrypted_tvb, 0, tree, auth_info, FALSE);
3166 show_stub_data (payload_tvb, 0, tree, auth_info, TRUE);
3170 pinfo->fragmented = save_fragmented;
3174 * Registers a conversation/UUID binding association, so that
3175 * we can invoke the proper sub-dissector for a given DCERPC
3178 * @param binding all values needed to create and bind a new conversation
3180 * @return Pointer to newly-added UUID/conversation binding.
3182 struct _dcerpc_bind_value *
3183 dcerpc_add_conv_to_bind_table(decode_dcerpc_bind_values_t *binding)
3185 dcerpc_bind_value *bind_value;
3186 dcerpc_bind_key *key;
3187 conversation_t *conv;
3189 conv = find_conversation (
3199 fprintf(stderr,"Creating a new conv on this bind packet \n");
3200 conv = conversation_new (
3210 bind_value = se_alloc (sizeof (dcerpc_bind_value));
3211 bind_value->uuid = binding->uuid;
3212 bind_value->ver = binding->ver;
3214 key = se_alloc(sizeof (dcerpc_bind_key));
3216 key->ctx_id = binding->ctx_id;
3217 key->smb_fid = binding->smb_fid;
3219 /* add this entry to the bind table, first removing any
3220 previous ones that are identical
3222 if(g_hash_table_lookup(dcerpc_binds, key)){
3223 g_hash_table_remove(dcerpc_binds, key);
3225 g_hash_table_insert(dcerpc_binds, key, bind_value);
3232 dissect_dcerpc_cn_rqst (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3233 proto_tree *dcerpc_tree, proto_tree *tree,
3234 e_dce_cn_common_hdr_t *hdr)
3236 conversation_t *conv;
3239 e_uuid_t obj_id = DCERPC_UUID_NULL;
3240 dcerpc_auth_info auth_info;
3243 proto_item *parent_pi;
3244 dcerpc_matched_key matched_key, *new_matched_key;
3245 dcerpc_call_value *value;
3247 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3248 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3250 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3251 hf_dcerpc_cn_ctx_id, &ctx_id);
3252 parent_pi = proto_tree_get_parent(dcerpc_tree);
3253 if(parent_pi != NULL) {
3254 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3257 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
3258 if(pinfo->dcectxid == 0) {
3259 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
3261 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3262 * prepend a delimiter */
3263 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
3266 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3267 hf_dcerpc_opnum, &opnum);
3269 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3270 pinfo->dcectxid = ctx_id;
3272 if (check_col (pinfo->cinfo, COL_INFO)) {
3273 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u ctx_id: %u",
3277 if (hdr->flags & PFC_OBJECT_UUID) {
3278 dcerpc_tvb_get_uuid (tvb, offset, hdr->drep, &obj_id);
3280 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3281 offset, 16, (e_guid_t *) &obj_id, "Object UUID: %s",
3282 guid_to_str((e_guid_t *) &obj_id));
3288 * XXX - what if this was set when the connection was set up,
3289 * and we just have a security context?
3291 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3292 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3293 pinfo->srcport, pinfo->destport, 0);
3295 /*conv = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3296 pinfo->srcport, pinfo->destport, 0);*/
3297 fprintf(stderr,"No conv showing raw stuf %d \n",pinfo->fd->num);
3298 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3301 /* !!! we can NOT check flags.visited here since this will interact
3302 badly with when SMB handles (i.e. calls the subdissector)
3303 and desegmented pdu's .
3304 Instead we check if this pdu is already in the matched table or not
3306 matched_key.frame = pinfo->fd->num;
3307 matched_key.call_id = hdr->call_id;
3308 value = g_hash_table_lookup(dcerpc_matched, &matched_key);
3310 dcerpc_bind_key bind_key;
3311 dcerpc_bind_value *bind_value;
3314 bind_key.ctx_id=ctx_id;
3315 bind_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3316 if((bind_value=g_hash_table_lookup(dcerpc_binds, &bind_key)) ){
3317 if(!(hdr->flags&PFC_FIRST_FRAG)){
3318 dcerpc_cn_call_key call_key;
3319 dcerpc_call_value *call_value;
3322 call_key.call_id=hdr->call_id;
3323 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3324 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3325 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3326 *new_matched_key = matched_key;
3327 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3332 dcerpc_cn_call_key *call_key;
3333 dcerpc_call_value *call_value;
3335 /* We found the binding and it is the first fragment
3336 (or a complete PDU) of a dcerpc pdu so just add
3337 the call to both the call table and the
3340 call_key=se_alloc (sizeof (dcerpc_cn_call_key));
3341 call_key->conv=conv;
3342 call_key->call_id=hdr->call_id;
3343 call_key->smb_fid=dcerpc_get_transport_salt(pinfo);
3345 /* if there is already a matching call in the table
3346 remove it so it is replaced with the new one */
3347 if(g_hash_table_lookup(dcerpc_cn_calls, call_key)){
3348 g_hash_table_remove(dcerpc_cn_calls, call_key);
3351 call_value=se_alloc (sizeof (dcerpc_call_value));
3352 call_value->uuid = bind_value->uuid;
3353 call_value->ver = bind_value->ver;
3354 call_value->object_uuid = obj_id;
3355 call_value->opnum = opnum;
3356 call_value->req_frame=pinfo->fd->num;
3357 call_value->req_time=pinfo->fd->abs_ts;
3358 call_value->rep_frame=0;
3359 call_value->max_ptr=0;
3360 call_value->se_data = NULL;
3361 call_value->private_data = NULL;
3362 call_value->pol = NULL;
3363 g_hash_table_insert (dcerpc_cn_calls, call_key, call_value);
3365 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3366 *new_matched_key = matched_key;
3367 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3375 /* handoff this call */
3377 di->call_id = hdr->call_id;
3378 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3379 di->ptype = PDU_REQ;
3380 di->call_data = value;
3383 if(value->rep_frame!=0){
3384 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
3385 tvb, 0, 0, value->rep_frame);
3386 PROTO_ITEM_SET_GENERATED(pi);
3387 if(parent_pi != NULL) {
3388 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
3391 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3392 hdr, di, &auth_info, alloc_hint,
3396 /* no bind information, simply show stub data */
3397 pi = proto_tree_add_text(dcerpc_tree, tvb, offset, 0, "No bind info for this interface Context ID - capture start too late?");
3398 PROTO_ITEM_SET_GENERATED(pi);
3399 expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u",
3401 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3404 /* Dissect the verifier */
3405 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3410 dissect_dcerpc_cn_resp (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3411 proto_tree *dcerpc_tree, proto_tree *tree,
3412 e_dce_cn_common_hdr_t *hdr)
3414 dcerpc_call_value *value = NULL;
3415 conversation_t *conv;
3417 dcerpc_auth_info auth_info;
3420 proto_item *parent_pi;
3421 e_uuid_t obj_id_null = DCERPC_UUID_NULL;
3423 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3424 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3426 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3427 hf_dcerpc_cn_ctx_id, &ctx_id);
3428 parent_pi = proto_tree_get_parent(dcerpc_tree);
3429 if(parent_pi != NULL) {
3430 proto_item_append_text(parent_pi, " Ctx: %u", ctx_id);
3433 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
3434 if(pinfo->dcectxid == 0) {
3435 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
3437 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3438 * prepend a delimiter */
3439 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
3444 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3445 pinfo->dcectxid = ctx_id;
3447 if (check_col (pinfo->cinfo, COL_INFO)) {
3448 col_append_fstr (pinfo->cinfo, COL_INFO, " ctx_id: %u", ctx_id);
3451 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3452 hf_dcerpc_cn_cancel_count, NULL);
3457 * XXX - what if this was set when the connection was set up,
3458 * and we just have a security context?
3460 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3462 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3463 pinfo->srcport, pinfo->destport, 0);
3466 /* no point in creating one here, really */
3467 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3469 dcerpc_matched_key matched_key, *new_matched_key;
3471 /* !!! we can NOT check flags.visited here since this will interact
3472 badly with when SMB handles (i.e. calls the subdissector)
3473 and desegmented pdu's .
3474 Instead we check if this pdu is already in the matched table or not
3476 matched_key.frame = pinfo->fd->num;
3477 matched_key.call_id = hdr->call_id;
3478 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3480 dcerpc_cn_call_key call_key;
3481 dcerpc_call_value *call_value;
3484 call_key.call_id=hdr->call_id;
3485 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3487 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3488 /* extra sanity check, only match them if the reply
3489 came after the request */
3490 if(call_value->req_frame<pinfo->fd->num){
3491 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3492 *new_matched_key = matched_key;
3493 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3495 if(call_value->rep_frame==0) {
3496 call_value->rep_frame=pinfo->fd->num;
3506 /* handoff this call */
3508 di->call_id = hdr->call_id;
3509 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3510 di->ptype = PDU_RESP;
3511 di->call_data = value;
3513 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3515 /* (optional) "Object UUID" from request */
3516 if (value && dcerpc_tree && memcmp(&value->object_uuid, &obj_id_null, sizeof(obj_id_null)) != 0) {
3517 pi = proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
3518 offset, 0, (e_guid_t *) &value->object_uuid, "Object UUID: %s",
3519 guid_to_str((e_guid_t *) &value->object_uuid));
3520 PROTO_ITEM_SET_GENERATED(pi);
3524 if(value->req_frame!=0) {
3526 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3527 tvb, 0, 0, value->req_frame);
3528 PROTO_ITEM_SET_GENERATED(pi);
3529 if(parent_pi != NULL) {
3530 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3532 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
3533 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
3534 PROTO_ITEM_SET_GENERATED(pi);
3536 pi = proto_tree_add_text(dcerpc_tree,
3537 tvb, 0, 0, "No request to this DCE/RPC call found");
3538 expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
3539 "No request to this DCE/RPC call found");
3542 dissect_dcerpc_cn_stub (tvb, offset, pinfo, dcerpc_tree, tree,
3543 hdr, di, &auth_info, alloc_hint,value->rep_frame);
3545 /* no bind information, simply show stub data */
3546 pi = proto_tree_add_text(dcerpc_tree, tvb, offset, 0, "No bind info for this interface Context ID - capture start too late?");
3547 PROTO_ITEM_SET_GENERATED(pi);
3548 expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_NOTE, "No bind info for interface Context ID:%u",ctx_id);
3549 show_stub_data (tvb, offset, dcerpc_tree, &auth_info, TRUE);
3552 /* Dissect the verifier */
3553 dissect_dcerpc_verifier (tvb, pinfo, dcerpc_tree, hdr, &auth_info);
3557 dissect_dcerpc_cn_fault (tvbuff_t *tvb, gint offset, packet_info *pinfo,
3558 proto_tree *dcerpc_tree, e_dce_cn_common_hdr_t *hdr)
3560 dcerpc_call_value *value = NULL;
3561 conversation_t *conv;
3565 dcerpc_auth_info auth_info;
3566 proto_item *pi = NULL;
3568 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3569 hf_dcerpc_cn_alloc_hint, &alloc_hint);
3571 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3572 hf_dcerpc_cn_ctx_id, &ctx_id);
3574 if (check_col (pinfo->cinfo, COL_DCE_CTX)) {
3575 if(pinfo->dcectxid == 0) {
3576 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "%u", ctx_id);
3578 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3579 * prepend a delimiter */
3580 col_append_fstr (pinfo->cinfo, COL_DCE_CTX, "#%u", ctx_id);
3584 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3585 hf_dcerpc_cn_cancel_count, NULL);
3589 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree, hdr->drep,
3590 hf_dcerpc_cn_status, &status);*/
3591 status = ((hdr->drep[0] & 0x10)
3592 ? tvb_get_letohl (tvb, offset)
3593 : tvb_get_ntohl (tvb, offset));
3596 pi = proto_tree_add_item (dcerpc_tree, hf_dcerpc_cn_status, tvb, offset, 4, (hdr->drep[0] & 0x10));
3600 expert_add_info_format(pinfo, pi, PI_RESPONSE_CODE, PI_NOTE, "Fault: %s",
3601 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
3603 /* save context ID for use with dcerpc_add_conv_to_bind_table() */
3604 pinfo->dcectxid = ctx_id;
3606 if (check_col (pinfo->cinfo, COL_INFO)) {
3607 col_append_fstr (pinfo->cinfo, COL_INFO,
3608 " ctx_id: %u status: %s", ctx_id,
3609 val_to_str(status, reject_status_vals,
3610 "Unknown (0x%08x)"));
3617 * XXX - what if this was set when the connection was set up,
3618 * and we just have a security context?
3620 dissect_dcerpc_cn_auth (tvb, offset, pinfo, dcerpc_tree, hdr, FALSE, &auth_info);
3622 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
3623 pinfo->srcport, pinfo->destport, 0);
3625 /* no point in creating one here, really */
3627 dcerpc_matched_key matched_key, *new_matched_key;
3629 /* !!! we can NOT check flags.visited here since this will interact
3630 badly with when SMB handles (i.e. calls the subdissector)
3631 and desegmented pdu's .
3632 Instead we check if this pdu is already in the matched table or not
3634 matched_key.frame = pinfo->fd->num;
3635 matched_key.call_id = hdr->call_id;
3636 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
3638 dcerpc_cn_call_key call_key;
3639 dcerpc_call_value *call_value;
3642 call_key.call_id=hdr->call_id;
3643 call_key.smb_fid=dcerpc_get_transport_salt(pinfo);
3645 if((call_value=g_hash_table_lookup(dcerpc_cn_calls, &call_key))){
3646 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
3647 *new_matched_key = matched_key;
3648 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
3650 if(call_value->rep_frame==0){
3651 call_value->rep_frame=pinfo->fd->num;
3658 int length, reported_length, stub_length;
3660 proto_item *parent_pi;
3663 /* handoff this call */
3665 di->call_id = hdr->call_id;
3666 di->smb_fid = dcerpc_get_transport_salt(pinfo);
3667 di->ptype = PDU_FAULT;
3668 di->call_data = value;
3670 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, 0, 0, value->opnum);
3671 if(value->req_frame!=0){
3673 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
3674 tvb, 0, 0, value->req_frame);
3675 PROTO_ITEM_SET_GENERATED(pi);
3676 parent_pi = proto_tree_get_parent(dcerpc_tree);
3677 if(parent_pi != NULL) {
3678 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
3680 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
3681 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
3682 PROTO_ITEM_SET_GENERATED(pi);
3684 pi = proto_tree_add_text(dcerpc_tree,
3685 tvb, 0, 0, "No request to this DCE/RPC call found");
3686 expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
3687 "No request to this DCE/RPC call found");
3690 length = tvb_length_remaining(tvb, offset);
3691 reported_length = tvb_reported_length_remaining(tvb, offset);
3692 /* as we now create a tvb in dissect_dcerpc_cn() containing only the
3693 * stub_data, the following calculation is no longer valid:
3694 * stub_length = hdr->frag_len - offset - auth_info.auth_size;
3695 * simply use the remaining length of the tvb instead.
3696 * XXX - or better use the reported_length?!?
3698 stub_length = length;
3699 if (length > stub_length)
3700 length = stub_length;
3701 if (reported_length > stub_length)
3702 reported_length = stub_length;
3704 /* If we don't have reassembly enabled, or this packet contains
3705 the entire PDU, or if we don't have all the data in this
3706 fragment, just call the handoff directly if this is the
3707 first fragment or the PDU isn't fragmented. */
3708 if( (!dcerpc_reassemble) || PFC_NOT_FRAGMENTED(hdr) ||
3709 !tvb_bytes_exist(tvb, offset, stub_length) ){
3710 if(hdr->flags&PFC_FIRST_FRAG){
3711 /* First fragment, possibly the only fragment */
3713 * XXX - should there be a third routine for each
3714 * function in an RPC subdissector, to handle
3715 * fault responses? The DCE RPC 1.1 spec says
3716 * three's "stub data" here, which I infer means
3717 * that it's protocol-specific and call-specific.
3719 * It should probably get passed the status code
3720 * as well, as that might be protocol-specific.
3723 if (stub_length > 0) {
3724 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3725 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3726 "Fault stub data (%d byte%s)",
3728 plurality(stub_length, "", "s"));
3732 /* PDU is fragmented and this isn't the first fragment */
3733 if (check_col(pinfo->cinfo, COL_INFO)) {
3734 col_append_str(pinfo->cinfo, COL_INFO,
3735 " [DCE/RPC fragment]");
3738 if (stub_length > 0) {
3739 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3740 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3741 "Fragment data (%d byte%s)",
3743 plurality(stub_length, "", "s"));
3748 /* Reassembly is enabled, the PDU is fragmented, and
3749 we have all the data in the fragment; the first two
3750 of those mean we should attempt reassembly, and the
3751 third means we can attempt reassembly. */
3754 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3755 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3756 "Fragment data (%d byte%s)",
3758 plurality(stub_length, "", "s"));
3761 if(hdr->flags&PFC_FIRST_FRAG){ /* FIRST fragment */
3762 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3763 fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
3764 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3768 if (check_col(pinfo->cinfo, COL_INFO)) {
3769 col_append_str(pinfo->cinfo, COL_INFO,
3770 " [DCE/RPC fragment]");
3772 } else if(hdr->flags&PFC_LAST_FRAG){ /* LAST fragment */
3773 if( value->rep_frame ){
3774 fragment_data *fd_head;
3776 fd_head = fragment_add_seq_next(tvb, offset, pinfo,
3778 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3783 /* We completed reassembly */
3785 proto_item *frag_tree_item;
3787 next_tvb = tvb_new_child_real_data(tvb, fd_head->data, fd_head->len, fd_head->len);
3788 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
3789 show_fragment_tree(fd_head, &dcerpc_frag_items,
3790 dcerpc_tree, pinfo, next_tvb, &frag_tree_item);
3793 * XXX - should there be a third routine for each
3794 * function in an RPC subdissector, to handle
3795 * fault responses? The DCE RPC 1.1 spec says
3796 * three's "stub data" here, which I infer means
3797 * that it's protocol-specific and call-specific.
3799 * It should probably get passed the status code
3800 * as well, as that might be protocol-specific.
3804 tvb_ensure_bytes_exist(tvb, offset, stub_length);
3805 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
3806 "Fault stub data (%d byte%s)",
3808 plurality(stub_length, "", "s"));
3812 /* Reassembly not complete - some fragments
3814 if (check_col(pinfo->cinfo, COL_INFO)) {
3815 col_append_str(pinfo->cinfo, COL_INFO,
3816 " [DCE/RPC fragment]");
3820 } else { /* MIDDLE fragment(s) */
3821 if( (!pinfo->fd->flags.visited) && value->rep_frame ){
3822 fragment_add_seq_next(tvb, offset, pinfo, value->rep_frame,
3823 dcerpc_co_fragment_table, dcerpc_co_reassemble_table,
3827 if (check_col(pinfo->cinfo, COL_INFO)) {
3828 col_append_str(pinfo->cinfo, COL_INFO,
3829 " [DCE/RPC fragment]");
3838 * DCERPC dissector for connection oriented calls.
3839 * We use transport type to later multiplex between what kind of
3840 * pinfo->private_data structure to expect.
3843 dissect_dcerpc_cn (tvbuff_t *tvb, int offset, packet_info *pinfo,
3844 proto_tree *tree, gboolean can_desegment, int *pkt_len)
3846 static const guint8 nulls[4] = { 0 };
3849 proto_item *ti = NULL;
3850 proto_item *tf = NULL;
3851 proto_tree *dcerpc_tree = NULL;
3852 proto_tree *cn_flags_tree = NULL;
3853 proto_tree *drep_tree = NULL;
3854 e_dce_cn_common_hdr_t hdr;
3855 dcerpc_auth_info auth_info;
3856 tvbuff_t *fragment_tvb;
3859 * when done over nbt, dcerpc requests are padded with 4 bytes of null
3860 * data for some reason.
3862 * XXX - if that's always the case, the right way to do this would
3863 * be to have a "dissect_dcerpc_cn_nb" routine which strips off
3864 * the 4 bytes of null padding, and make that the dissector
3865 * used for "netbios".
3867 if (tvb_memeql (tvb, offset, nulls, 4) == 0) {
3876 * Check if this looks like a C/O DCERPC call
3878 if (!tvb_bytes_exist (tvb, offset, sizeof (hdr))) {
3879 return FALSE; /* not enough information to check */
3881 start_offset = offset;
3882 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
3883 if (hdr.rpc_ver != 5)
3885 hdr.rpc_ver_minor = tvb_get_guint8 (tvb, offset++);
3886 if (hdr.rpc_ver_minor != 0 && hdr.rpc_ver_minor != 1)
3888 hdr.ptype = tvb_get_guint8 (tvb, offset++);
3892 hdr.flags = tvb_get_guint8 (tvb, offset++);
3893 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
3894 offset += sizeof (hdr.drep);
3896 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3898 hdr.auth_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
3900 hdr.call_id = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
3903 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
3904 if(pinfo->dcectxid == 0) {
3905 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.call_id);
3907 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3908 * prepend a delimiter */
3909 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "#%u", hdr.call_id);
3913 if (can_desegment && pinfo->can_desegment
3914 && !tvb_bytes_exist(tvb, start_offset, hdr.frag_len)) {
3915 pinfo->desegment_offset = start_offset;
3916 pinfo->desegment_len = hdr.frag_len - tvb_length_remaining (tvb, start_offset);
3917 *pkt_len = 0; /* desegmentation required */
3921 if (check_col (pinfo->cinfo, COL_PROTOCOL))
3922 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
3924 if (check_col (pinfo->cinfo, COL_INFO)) {
3925 if(pinfo->dcectxid != 0) {
3926 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU,
3927 * append a delimiter and set a column fence */
3928 col_append_str (pinfo->cinfo, COL_INFO, " # ");
3929 col_set_fence(pinfo->cinfo,COL_INFO);
3931 col_add_fstr (pinfo->cinfo, COL_INFO, "%s: call_id: %u",
3932 pckt_vals[hdr.ptype].strptr, hdr.call_id);
3935 if(pinfo->dcectxid != 0) {
3936 /* this is not the first DCE-RPC request/response in this (TCP?-)PDU */
3937 expert_add_info_format(pinfo, NULL, PI_SEQUENCE, PI_CHAT, "Multiple DCE/RPC fragments/PDU's in one packet");
3940 offset = start_offset;
3941 tvb_ensure_bytes_exist(tvb, offset, 16);
3943 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, offset, hdr.frag_len, FALSE);
3944 dcerpc_tree = proto_item_add_subtree (ti, ett_dcerpc);
3947 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
3950 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver_minor, tvb, offset, 1, hdr.rpc_ver_minor);
3953 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
3956 /* XXX - too much "output noise", removed for now
3957 if(hdr.ptype == PDU_BIND || hdr.ptype == PDU_ALTER ||
3958 hdr.ptype == PDU_BIND_ACK || hdr.ptype == PDU_ALTER_ACK)
3959 expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_CHAT, "Context change: %s",
3960 val_to_str(hdr.ptype, pckt_vals, "(0x%x)"));*/
3961 if(hdr.ptype == PDU_BIND_NAK)
3962 expert_add_info_format(pinfo, tf, PI_SEQUENCE, PI_WARN, "Bind not acknowledged");
3965 proto_item_append_text(ti, " %s, Fragment:", val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"));
3967 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_flags, tvb, offset, 1, hdr.flags);
3968 cn_flags_tree = proto_item_add_subtree (tf, ett_dcerpc_cn_flags);
3970 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_object, tvb, offset, 1, hdr.flags);
3971 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_maybe, tvb, offset, 1, hdr.flags);
3972 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_dne, tvb, offset, 1, hdr.flags);
3973 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_mpx, tvb, offset, 1, hdr.flags);
3974 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_reserved, tvb, offset, 1, hdr.flags);
3975 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_cancel_pending, tvb, offset, 1, hdr.flags);
3976 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_last_frag, tvb, offset, 1, hdr.flags);
3977 proto_tree_add_boolean (cn_flags_tree, hf_dcerpc_cn_flags_first_frag, tvb, offset, 1, hdr.flags);
3978 if( (hdr.flags & PFC_FIRST_FRAG) && (hdr.flags & PFC_LAST_FRAG) ) {
3979 proto_item_append_text(ti, " Single");
3981 if(hdr.flags & PFC_FIRST_FRAG) {
3982 proto_item_append_text(ti, " 1st");
3984 if(hdr.flags & PFC_LAST_FRAG) {
3985 proto_item_append_text(ti, " Last");
3987 if( !(hdr.flags & PFC_FIRST_FRAG) && !(hdr.flags & PFC_LAST_FRAG) ) {
3988 proto_item_append_text(ti, " Mid");
3994 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, 4, hdr.drep);
3995 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
3997 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
3998 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
3999 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4000 offset += sizeof (hdr.drep);
4002 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_frag_len, tvb, offset, 2, hdr.frag_len);
4005 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_auth_len, tvb, offset, 2, hdr.auth_len);
4008 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_cn_call_id, tvb, offset, 4, hdr.call_id);
4012 proto_item_append_text(ti, ", FragLen: %u, Call: %u", hdr.frag_len, hdr.call_id);
4016 * None of the stuff done above should throw an exception, because
4017 * we would have rejected this as "not DCE RPC" if we didn't have all
4018 * of it. (XXX - perhaps we should request reassembly if we have
4019 * enough of the header to consider it DCE RPC but not enough to
4020 * get the fragment length; in that case the stuff still wouldn't
4021 * throw an exception.)
4023 * The rest of the stuff might, so return the PDU length to our caller.
4024 * XXX - should we construct a tvbuff containing only the PDU and
4025 * use that? Or should we have separate "is this a DCE RPC PDU",
4026 * "how long is it", and "dissect it" routines - which might let us
4027 * do most of the work in "tcp_dissect_pdus()"?
4029 if (pkt_len != NULL)
4030 *pkt_len = hdr.frag_len + padding;
4032 /* The remaining bytes in the current tvb might contain multiple
4033 * DCE/RPC fragments, so create a new tvb subset for this fragment.
4034 * Only limit the end of the fragment, but not the offset start,
4035 * as the authentication function dissect_dcerpc_cn_auth() will fail
4036 * (and other functions might fail as well) computing the right start
4039 fragment_tvb = tvb_new_subset(tvb, 0,
4040 MIN((hdr.frag_len + (guint) start_offset), tvb_length(tvb)) /* length */,
4041 hdr.frag_len + start_offset /* reported_length */);
4044 * Packet type specific stuff is next.
4046 switch (hdr.ptype) {
4049 dissect_dcerpc_cn_bind (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4054 dissect_dcerpc_cn_bind_ack (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4059 * Nothing after the common header other than credentials.
4061 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, TRUE,
4066 dissect_dcerpc_cn_rqst (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4070 dissect_dcerpc_cn_resp (fragment_tvb, offset, pinfo, dcerpc_tree, tree, &hdr);
4074 dissect_dcerpc_cn_fault (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4078 dissect_dcerpc_cn_bind_nak (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr);
4084 * Nothing after the common header other than an authentication
4087 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4093 * Nothing after the common header, not even an authentication
4099 /* might as well dissect the auth info */
4100 dissect_dcerpc_cn_auth (fragment_tvb, offset, pinfo, dcerpc_tree, &hdr, FALSE,
4108 * DCERPC dissector for connection oriented calls over packet-oriented
4112 dissect_dcerpc_cn_pk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4115 * Only one PDU per transport packet, and only one transport
4118 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4119 if (!dissect_dcerpc_cn (tvb, 0, pinfo, tree, FALSE, NULL)) {
4121 * It wasn't a DCERPC PDU.
4133 * DCERPC dissector for connection oriented calls over byte-stream
4135 * we need to distinguish here between SMB and non-TCP (more in the future?)
4136 * to be able to know what kind of private_data structure to expect.
4139 dissect_dcerpc_cn_bs_body (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4141 volatile int offset = 0;
4143 volatile gboolean dcerpc_pdus = 0;
4144 volatile gboolean ret = FALSE;
4147 * There may be multiple PDUs per transport packet; keep
4150 while (tvb_reported_length_remaining(tvb, offset) != 0) {
4152 * Catch ReportedBoundsError, so that even if the stub data is bad,
4153 * we don't abort the full DCE RPC dissection - there might be more
4154 * than one DCE RPC PDU in the data being dissected.
4156 * If we get BoundsError, it means the frame was cut short by a
4157 * snapshot length, so there's nothing more to dissect; just
4158 * re-throw that exception.
4162 if(dissect_dcerpc_cn (tvb, offset, pinfo, tree,
4163 dcerpc_cn_desegment, &pdu_len)) {
4166 } CATCH(BoundsError) {
4168 } CATCH(ReportedBoundsError) {
4169 show_reported_bounds_error(tvb, pinfo, tree);
4171 * Presumably it looked enough like a DCE RPC PDU that we
4172 * dissected enough of it to throw an exception.
4185 * Well, we've seen at least one DCERPC PDU.
4189 /* if we had more than one Req/Resp in this PDU change the protocol column */
4190 /* this will formerly contain the last interface name, which may not be the same for all Req/Resp */
4191 if (dcerpc_pdus >= 2 && check_col (pinfo->cinfo, COL_PROTOCOL))
4192 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "%u*DCERPC", dcerpc_pdus);
4196 * Desegmentation required - bail now, but give the user a hint that desegmentation might be done later.
4198 proto_tree_add_uint_format(tree, hf_dcerpc_cn_deseg_req, tvb, offset,
4200 tvb_reported_length_remaining(tvb, offset),
4201 "[DCE RPC: %u byte%s left, desegmentation might follow]",
4202 tvb_reported_length_remaining(tvb, offset),
4203 plurality(tvb_reported_length_remaining(tvb, offset), "", "s"));
4208 * Step to the next PDU.
4216 dissect_dcerpc_cn_bs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4218 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4219 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4223 dissect_dcerpc_cn_smbpipe (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4225 pinfo->dcetransporttype=DCE_CN_TRANSPORT_SMBPIPE;
4226 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4230 dissect_dcerpc_cn_smb2 (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4232 pinfo->dcetransporttype=DCE_TRANSPORT_UNKNOWN;
4233 return dissect_dcerpc_cn_bs_body(tvb, pinfo, tree);
4239 dissect_dcerpc_dg_auth (tvbuff_t *tvb, int offset, proto_tree *dcerpc_tree,
4240 e_dce_dg_common_hdr_t *hdr, int *auth_level_p)
4242 proto_item *ti = NULL;
4243 proto_tree *auth_tree = NULL;
4244 guint8 protection_level;
4247 * Initially set "*auth_level_p" to -1 to indicate that we haven't
4248 * yet seen any authentication level information.
4250 if (auth_level_p != NULL)
4254 * The authentication information is at the *end* of the PDU; in
4255 * request and response PDUs, the request and response stub data
4258 * If the full packet is here, and there's data past the end of the
4259 * packet body, then dissect the auth info.
4261 offset += hdr->frag_len;
4262 if (tvb_length_remaining(tvb, offset) > 0) {
4263 switch (hdr->auth_proto) {
4265 case DCE_C_RPC_AUTHN_PROTOCOL_KRB5:
4266 ti = proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Kerberos authentication verifier");
4267 auth_tree = proto_item_add_subtree (ti, ett_dcerpc_krb5_auth_verf);
4268 protection_level = tvb_get_guint8 (tvb, offset);
4269 if (auth_level_p != NULL)
4270 *auth_level_p = protection_level;
4271 proto_tree_add_uint (auth_tree, hf_dcerpc_krb5_av_prot_level, tvb, offset, 1, protection_level);
4273 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_vers_num, tvb, offset, 1, FALSE);
4275 if (protection_level == DCE_C_AUTHN_LEVEL_PKT_PRIVACY)
4276 offset += 6; /* 6 bytes of padding */
4278 offset += 2; /* 6 bytes of padding */
4279 proto_tree_add_item (auth_tree, hf_dcerpc_krb5_av_key_auth_verifier, tvb, offset, 16, FALSE);
4284 proto_tree_add_text (dcerpc_tree, tvb, offset, -1, "Authentication verifier");
4291 dissect_dcerpc_dg_cancel_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4292 proto_tree *dcerpc_tree,
4293 e_dce_dg_common_hdr_t *hdr)
4297 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4298 hdr->drep, hf_dcerpc_dg_cancel_vers,
4304 /* The only version we know about */
4305 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4306 hdr->drep, hf_dcerpc_dg_cancel_id,
4308 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4309 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4316 dissect_dcerpc_dg_cancel (tvbuff_t *tvb, int offset, packet_info *pinfo,
4317 proto_tree *dcerpc_tree,
4318 e_dce_dg_common_hdr_t *hdr)
4322 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4323 hdr->drep, hf_dcerpc_dg_cancel_vers,
4329 /* The only version we know about */
4330 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4331 hdr->drep, hf_dcerpc_dg_cancel_id,
4333 /* XXX - are NDR booleans 32 bits? */
4335 /* XXX - the RPC reference in chapter: "the cancel PDU" doesn't mention
4336 the accepting_cancels field (it's only in the cancel_ack PDU)! */
4337 /*offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4338 hdr->drep, hf_dcerpc_dg_server_accepting_cancels,
4345 dissect_dcerpc_dg_fack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4346 proto_tree *dcerpc_tree,
4347 e_dce_dg_common_hdr_t *hdr)
4354 offset = dissect_dcerpc_uint8 (tvb, offset, pinfo, dcerpc_tree,
4355 hdr->drep, hf_dcerpc_dg_fack_vers,
4362 case 0: /* The only version documented in the DCE RPC 1.1 spec */
4363 case 1: /* This appears to be the same */
4364 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4365 hdr->drep, hf_dcerpc_dg_fack_window_size,
4367 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4368 hdr->drep, hf_dcerpc_dg_fack_max_tsdu,
4370 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4371 hdr->drep, hf_dcerpc_dg_fack_max_frag_size,
4373 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4374 hdr->drep, hf_dcerpc_dg_fack_serial_num,
4376 if (check_col (pinfo->cinfo, COL_INFO)) {
4377 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4380 offset = dissect_dcerpc_uint16 (tvb, offset, pinfo, dcerpc_tree,
4381 hdr->drep, hf_dcerpc_dg_fack_selack_len,
4383 for (i = 0; i < selack_len; i++) {
4384 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4385 hdr->drep, hf_dcerpc_dg_fack_selack,
4394 dissect_dcerpc_dg_reject_fault (tvbuff_t *tvb, int offset, packet_info *pinfo,
4395 proto_tree *dcerpc_tree,
4396 e_dce_dg_common_hdr_t *hdr)
4400 offset = dissect_dcerpc_uint32 (tvb, offset, pinfo, dcerpc_tree,
4401 hdr->drep, hf_dcerpc_dg_status,
4404 if (check_col (pinfo->cinfo, COL_INFO)) {
4405 col_append_fstr (pinfo->cinfo, COL_INFO,
4407 val_to_str(status, reject_status_vals, "Unknown (0x%08x)"));
4412 dissect_dcerpc_dg_stub (tvbuff_t *tvb, int offset, packet_info *pinfo,
4413 proto_tree *dcerpc_tree, proto_tree *tree,
4414 e_dce_dg_common_hdr_t *hdr, dcerpc_info *di)
4416 int length, reported_length, stub_length;
4417 gboolean save_fragmented;
4418 fragment_data *fd_head;
4421 proto_item *parent_pi;
4423 if (check_col (pinfo->cinfo, COL_INFO))
4424 col_append_fstr (pinfo->cinfo, COL_INFO, " opnum: %u len: %u",
4425 di->call_data->opnum, hdr->frag_len );
4427 length = tvb_length_remaining (tvb, offset);
4428 reported_length = tvb_reported_length_remaining (tvb, offset);
4429 stub_length = hdr->frag_len;
4430 if (length > stub_length)
4431 length = stub_length;
4432 if (reported_length > stub_length)
4433 reported_length = stub_length;
4435 save_fragmented = pinfo->fragmented;
4437 /* If we don't have reassembly enabled, or this packet contains
4438 the entire PDU, or if this is a short frame (or a frame
4439 not reassembled at a lower layer) that doesn't include all
4440 the data in the fragment, just call the handoff directly if
4441 this is the first fragment or the PDU isn't fragmented. */
4442 if( (!dcerpc_reassemble) || !(hdr->flags1 & PFCL1_FRAG) ||
4443 !tvb_bytes_exist(tvb, offset, stub_length) ){
4444 if(hdr->frag_num == 0) {
4447 /* First fragment, possibly the only fragment */
4450 * XXX - authentication info?
4452 pinfo->fragmented = (hdr->flags1 & PFCL1_FRAG);
4453 next_tvb = tvb_new_subset (tvb, offset, length,
4455 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4456 next_tvb, hdr->drep, di, NULL);
4458 /* PDU is fragmented and this isn't the first fragment */
4459 if (check_col(pinfo->cinfo, COL_INFO)) {
4460 col_append_str(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4464 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4465 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4466 "Fragment data (%d byte%s)",
4468 plurality(stub_length, "", "s"));
4473 /* Reassembly is enabled, the PDU is fragmented, and
4474 we have all the data in the fragment; the first two
4475 of those mean we should attempt reassembly, and the
4476 third means we can attempt reassembly. */
4479 tvb_ensure_bytes_exist(tvb, offset, stub_length);
4480 proto_tree_add_text (dcerpc_tree, tvb, offset, stub_length,
4481 "Fragment data (%d byte%s)", stub_length,
4482 plurality(stub_length, "", "s"));
4486 fd_head = fragment_add_dcerpc_dg(tvb, offset, pinfo,
4487 hdr->seqnum, &hdr->act_id, dcerpc_cl_reassemble_table,
4488 hdr->frag_num, stub_length,
4489 !(hdr->flags1 & PFCL1_LASTFRAG));
4490 if (fd_head != NULL) {
4491 /* We completed reassembly... */
4492 if(pinfo->fd->num==fd_head->reassembled_in) {
4493 /* ...and this is the reassembled RPC PDU */
4494 next_tvb = tvb_new_child_real_data(tvb, fd_head->data, fd_head->len, fd_head->len);
4495 add_new_data_source(pinfo, next_tvb, "Reassembled DCE/RPC");
4496 show_fragment_seq_tree(fd_head, &dcerpc_frag_items,
4497 tree, pinfo, next_tvb, &pi);
4500 * XXX - authentication info?
4502 pinfo->fragmented = FALSE;
4503 dcerpc_try_handoff (pinfo, tree, dcerpc_tree, next_tvb,
4504 next_tvb, hdr->drep, di, NULL);
4506 /* ...and this isn't the reassembled RPC PDU */
4507 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_reassembled_in,
4508 tvb, 0, 0, fd_head->reassembled_in);
4509 PROTO_ITEM_SET_GENERATED(pi);
4510 parent_pi = proto_tree_get_parent(dcerpc_tree);
4511 if(parent_pi != NULL) {
4512 proto_item_append_text(parent_pi, ", [Reas: #%u]", fd_head->reassembled_in);
4514 if (check_col(pinfo->cinfo, COL_INFO)) {
4515 col_append_fstr(pinfo->cinfo, COL_INFO,
4516 " [DCE/RPC fragment, reas: #%u]", fd_head->reassembled_in);
4520 /* Reassembly isn't completed yet */
4521 if (check_col(pinfo->cinfo, COL_INFO)) {
4522 col_append_str(pinfo->cinfo, COL_INFO, " [DCE/RPC fragment]");
4526 pinfo->fragmented = save_fragmented;
4530 dissect_dcerpc_dg_rqst (tvbuff_t *tvb, int offset, packet_info *pinfo,
4531 proto_tree *dcerpc_tree, proto_tree *tree,
4532 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4535 dcerpc_call_value *value, v;
4536 dcerpc_matched_key matched_key, *new_matched_key;
4538 proto_item *parent_pi;
4541 if(!(pinfo->fd->flags.visited)){
4542 dcerpc_call_value *call_value;
4543 dcerpc_dg_call_key *call_key;
4545 call_key=se_alloc (sizeof (dcerpc_dg_call_key));
4546 call_key->conv=conv;
4547 call_key->seqnum=hdr->seqnum;
4548 call_key->act_id=hdr->act_id;
4550 call_value=se_alloc (sizeof (dcerpc_call_value));
4551 call_value->uuid = hdr->if_id;
4552 call_value->ver = hdr->if_ver;
4553 call_value->object_uuid = hdr->obj_id;
4554 call_value->opnum = hdr->opnum;
4555 call_value->req_frame=pinfo->fd->num;
4556 call_value->req_time=pinfo->fd->abs_ts;
4557 call_value->rep_frame=0;
4558 call_value->max_ptr=0;
4559 call_value->se_data = NULL;
4560 call_value->private_data = NULL;
4561 call_value->pol = NULL;
4562 g_hash_table_insert (dcerpc_dg_calls, call_key, call_value);
4564 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
4565 new_matched_key->frame = pinfo->fd->num;
4566 new_matched_key->call_id = hdr->seqnum;
4567 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4570 matched_key.frame = pinfo->fd->num;
4571 matched_key.call_id = hdr->seqnum;
4572 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4574 v.uuid = hdr->if_id;
4575 v.ver = hdr->if_ver;
4576 v.object_uuid = hdr->obj_id;
4577 v.opnum = hdr->opnum;
4578 v.req_frame = pinfo->fd->num;
4582 v.private_data=NULL;
4587 di->call_id = hdr->seqnum;
4589 di->ptype = PDU_REQ;
4590 di->call_data = value;
4592 if(value->rep_frame!=0){
4593 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_response_in,
4594 tvb, 0, 0, value->rep_frame);
4595 PROTO_ITEM_SET_GENERATED(pi);
4596 parent_pi = proto_tree_get_parent(dcerpc_tree);
4597 if(parent_pi != NULL) {
4598 proto_item_append_text(parent_pi, ", [Resp: #%u]", value->rep_frame);
4601 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4605 dissect_dcerpc_dg_resp (tvbuff_t *tvb, int offset, packet_info *pinfo,
4606 proto_tree *dcerpc_tree, proto_tree *tree,
4607 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4610 dcerpc_call_value *value, v;
4611 dcerpc_matched_key matched_key, *new_matched_key;
4613 proto_item *parent_pi;
4616 if(!(pinfo->fd->flags.visited)){
4617 dcerpc_call_value *call_value;
4618 dcerpc_dg_call_key call_key;
4621 call_key.seqnum=hdr->seqnum;
4622 call_key.act_id=hdr->act_id;
4624 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4625 new_matched_key = se_alloc(sizeof (dcerpc_matched_key));
4626 new_matched_key->frame = pinfo->fd->num;
4627 new_matched_key->call_id = hdr->seqnum;
4628 g_hash_table_insert (dcerpc_matched, new_matched_key, call_value);
4629 if(call_value->rep_frame==0){
4630 call_value->rep_frame=pinfo->fd->num;
4635 matched_key.frame = pinfo->fd->num;
4636 matched_key.call_id = hdr->seqnum;
4637 value=g_hash_table_lookup(dcerpc_matched, &matched_key);
4639 v.uuid = hdr->if_id;
4640 v.ver = hdr->if_ver;
4641 v.object_uuid = hdr->obj_id;
4642 v.opnum = hdr->opnum;
4644 v.rep_frame=pinfo->fd->num;
4646 v.private_data=NULL;
4653 di->ptype = PDU_RESP;
4654 di->call_data = value;
4656 if(value->req_frame!=0){
4658 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4659 tvb, 0, 0, value->req_frame);
4660 PROTO_ITEM_SET_GENERATED(pi);
4661 parent_pi = proto_tree_get_parent(dcerpc_tree);
4662 if(parent_pi != NULL) {
4663 proto_item_append_text(parent_pi, ", [Req: #%u]", value->req_frame);
4665 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &value->req_time);
4666 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4667 PROTO_ITEM_SET_GENERATED(pi);
4669 pi = proto_tree_add_text(dcerpc_tree,
4670 tvb, 0, 0, "No request to this DCE/RPC call found");
4671 expert_add_info_format(pinfo, pi, PI_SEQUENCE, PI_NOTE,
4672 "No request to this DCE/RPC call found");
4674 dissect_dcerpc_dg_stub (tvb, offset, pinfo, dcerpc_tree, tree, hdr, di);
4678 dissect_dcerpc_dg_ping_ack (tvbuff_t *tvb, int offset, packet_info *pinfo,
4679 proto_tree *dcerpc_tree,
4680 e_dce_dg_common_hdr_t *hdr, conversation_t *conv)
4682 proto_item *parent_pi;
4683 /* if(!(pinfo->fd->flags.visited)){*/
4684 dcerpc_call_value *call_value;
4685 dcerpc_dg_call_key call_key;
4688 call_key.seqnum=hdr->seqnum;
4689 call_key.act_id=hdr->act_id;
4691 if((call_value=g_hash_table_lookup(dcerpc_dg_calls, &call_key))){
4695 pi = proto_tree_add_uint(dcerpc_tree, hf_dcerpc_request_in,
4696 tvb, 0, 0, call_value->req_frame);
4697 PROTO_ITEM_SET_GENERATED(pi);
4698 parent_pi = proto_tree_get_parent(dcerpc_tree);
4699 if(parent_pi != NULL) {
4700 proto_item_append_text(parent_pi, ", [Req: #%u]", call_value->req_frame);
4703 if (check_col (pinfo->cinfo, COL_INFO))
4704 col_append_fstr(pinfo->cinfo, COL_INFO, " [req: #%u]", call_value->req_frame);
4706 nstime_delta(&delta_ts, &pinfo->fd->abs_ts, &call_value->req_time);
4707 pi = proto_tree_add_time(dcerpc_tree, hf_dcerpc_time, tvb, offset, 0, &delta_ts);
4708 PROTO_ITEM_SET_GENERATED(pi);
4714 * DCERPC dissector for connectionless calls
4717 dissect_dcerpc_dg (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
4719 proto_item *ti = NULL;
4720 proto_item *tf = NULL;
4721 proto_tree *dcerpc_tree = NULL;
4722 proto_tree *dg_flags1_tree = NULL;
4723 proto_tree *dg_flags2_tree = NULL;
4724 proto_tree *drep_tree = NULL;
4725 e_dce_dg_common_hdr_t hdr;
4727 conversation_t *conv;
4730 const char *uuid_name = NULL;
4733 * Check if this looks like a CL DCERPC call. All dg packets
4734 * have an 80 byte header on them. Which starts with
4735 * version (4), pkt_type.
4737 if (tvb_length (tvb) < sizeof (hdr)) {
4741 /* Version must be 4 */
4742 hdr.rpc_ver = tvb_get_guint8 (tvb, offset++);
4743 if (hdr.rpc_ver != 4)
4746 /* Type must be <=19 or its not DCE/RPC */
4747 hdr.ptype = tvb_get_guint8 (tvb, offset++);
4751 /* flags1 has bit 1 and 8 as reserved so if any of them are set, it is
4752 probably not a DCE/RPC packet
4754 hdr.flags1 = tvb_get_guint8 (tvb, offset++);
4758 /* flags2 has all bits except bit 2 as reserved so if any of them are set
4759 it is probably not DCE/RPC.
4761 hdr.flags2 = tvb_get_guint8 (tvb, offset++);
4766 if (check_col (pinfo->cinfo, COL_PROTOCOL))
4767 col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCERPC");
4768 if (check_col (pinfo->cinfo, COL_INFO))
4769 col_add_str (pinfo->cinfo, COL_INFO, pckt_vals[hdr.ptype].strptr);
4771 tvb_memcpy (tvb, (guint8 *)hdr.drep, offset, sizeof (hdr.drep));
4772 offset += sizeof (hdr.drep);
4773 hdr.serial_hi = tvb_get_guint8 (tvb, offset++);
4774 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.obj_id);
4776 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.if_id);
4778 dcerpc_tvb_get_uuid (tvb, offset, hdr.drep, &hdr.act_id);
4780 hdr.server_boot = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4782 hdr.if_ver = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4784 hdr.seqnum = dcerpc_tvb_get_ntohl (tvb, offset, hdr.drep);
4786 hdr.opnum = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4788 hdr.ihint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4790 hdr.ahint = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4792 hdr.frag_len = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4794 hdr.frag_num = dcerpc_tvb_get_ntohs (tvb, offset, hdr.drep);
4796 hdr.auth_proto = tvb_get_guint8 (tvb, offset++);
4797 hdr.serial_lo = tvb_get_guint8 (tvb, offset++);
4800 ti = proto_tree_add_item (tree, proto_dcerpc, tvb, 0, -1, FALSE);
4802 dcerpc_tree = proto_item_add_subtree(ti, ett_dcerpc);
4803 proto_item_append_text(ti, " %s, Seq: %u, Serial: %u, Frag: %u, FragLen: %u",
4804 val_to_str(hdr.ptype, pckt_vals, "Unknown (0x%02x)"),
4805 hdr.seqnum, hdr.serial_hi*256+hdr.serial_lo,
4806 hdr.frag_num, hdr.frag_len);
4812 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_ver, tvb, offset, 1, hdr.rpc_ver);
4816 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_packet_type, tvb, offset, 1, hdr.ptype);
4820 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags1, tvb, offset, 1, hdr.flags1);
4821 dg_flags1_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags1);
4822 if (dg_flags1_tree) {
4823 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_80, tvb, offset, 1, hdr.flags1);
4824 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_broadcast, tvb, offset, 1, hdr.flags1);
4825 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_idempotent, tvb, offset, 1, hdr.flags1);
4826 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_maybe, tvb, offset, 1, hdr.flags1);
4827 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_nofack, tvb, offset, 1, hdr.flags1);
4828 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_frag, tvb, offset, 1, hdr.flags1);
4829 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_last_frag, tvb, offset, 1, hdr.flags1);
4830 proto_tree_add_boolean (dg_flags1_tree, hf_dcerpc_dg_flags1_rsrvd_01, tvb, offset, 1, hdr.flags1);
4832 proto_item_append_text(tf, " %s%s%s%s%s%s",
4833 (hdr.flags1 & PFCL1_BROADCAST) ? "\"Broadcast\" " : "",
4834 (hdr.flags1 & PFCL1_IDEMPOTENT) ? "\"Idempotent\" " : "",
4835 (hdr.flags1 & PFCL1_MAYBE) ? "\"Maybe\" " : "",
4836 (hdr.flags1 & PFCL1_NOFACK) ? "\"No Fack\" " : "",
4837 (hdr.flags1 & PFCL1_FRAG) ? "\"Fragment\" " : "",
4838 (hdr.flags1 & PFCL1_LASTFRAG) ? "\"Last Fragment\" " : "");
4845 tf = proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_flags2, tvb, offset, 1, hdr.flags2);
4846 dg_flags2_tree = proto_item_add_subtree (tf, ett_dcerpc_dg_flags2);
4847 if (dg_flags2_tree) {
4848 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_80, tvb, offset, 1, hdr.flags2);
4849 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_40, tvb, offset, 1, hdr.flags2);
4850 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_20, tvb, offset, 1, hdr.flags2);
4851 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_10, tvb, offset, 1, hdr.flags2);
4852 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_08, tvb, offset, 1, hdr.flags2);
4853 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_04, tvb, offset, 1, hdr.flags2);
4854 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_cancel_pending, tvb, offset, 1, hdr.flags2);
4855 proto_tree_add_boolean (dg_flags2_tree, hf_dcerpc_dg_flags2_rsrvd_01, tvb, offset, 1, hdr.flags2);
4857 proto_item_append_text(tf, " %s",
4858 (hdr.flags2 & PFCL2_CANCEL_PENDING) ? "\"Cancel Pending\" " : "");
4865 tf = proto_tree_add_bytes (dcerpc_tree, hf_dcerpc_drep, tvb, offset, sizeof (hdr.drep), hdr.drep);
4866 drep_tree = proto_item_add_subtree (tf, ett_dcerpc_drep);
4868 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, hdr.drep[0] >> 4);
4869 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_character, tvb, offset, 1, hdr.drep[0] & 0x0f);
4870 proto_tree_add_uint(drep_tree, hf_dcerpc_drep_fp, tvb, offset+1, 1, hdr.drep[1]);
4871 proto_item_append_text(tf, " (Order: %s, Char: %s, Float: %s)",
4872 val_to_str(hdr.drep[0] >> 4, drep_byteorder_vals, "Unknown"),
4873 val_to_str(hdr.drep[0] & 0x0f, drep_character_vals, "Unknown"),
4874 val_to_str(hdr.drep[1], drep_fp_vals, "Unknown"));
4877 offset += sizeof (hdr.drep);
4880 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_hi, tvb, offset, 1, hdr.serial_hi);
4884 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_obj_id, tvb,
4885 offset, 16, (e_guid_t *) &hdr.obj_id, "Object UUID: %s",
4886 guid_to_str((e_guid_t *) &hdr.obj_id));
4891 uuid_str = guid_to_str((e_guid_t*)&hdr.if_id);
4892 uuid_name = guids_get_uuid_name(&hdr.if_id);
4894 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4895 offset, 16, (e_guid_t *) &hdr.if_id, "Interface: %s UUID: %s", uuid_name, uuid_str);
4897 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_if_id, tvb,
4898 offset, 16, (e_guid_t *) &hdr.if_id, "Interface UUID: %s", uuid_str);
4904 proto_tree_add_guid_format (dcerpc_tree, hf_dcerpc_dg_act_id, tvb,
4905 offset, 16, (e_guid_t *) &hdr.act_id, "Activity: %s",
4906 guid_to_str((e_guid_t *) &hdr.act_id));
4911 nstime_t server_boot;
4913 server_boot.secs = hdr.server_boot;
4914 server_boot.nsecs = 0;
4916 if (hdr.server_boot == 0)
4917 proto_tree_add_time_format (dcerpc_tree, hf_dcerpc_dg_server_boot,
4918 tvb, offset, 4, &server_boot,
4919 "Server boot time: Unknown (0)");
4921 proto_tree_add_time (dcerpc_tree, hf_dcerpc_dg_server_boot,
4922 tvb, offset, 4, &server_boot);
4927 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_if_ver, tvb, offset, 4, hdr.if_ver);
4931 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_seqnum, tvb, offset, 4, hdr.seqnum);
4932 if (check_col (pinfo->cinfo, COL_INFO)) {
4933 col_append_fstr (pinfo->cinfo, COL_INFO, ": seq: %u", hdr.seqnum);
4935 if (check_col (pinfo->cinfo, COL_DCE_CALL)) {
4936 col_append_fstr (pinfo->cinfo, COL_DCE_CALL, "%u", hdr.seqnum);
4941 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_opnum, tvb, offset, 2, hdr.opnum);
4945 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ihint, tvb, offset, 2, hdr.ihint);
4949 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_ahint, tvb, offset, 2, hdr.ahint);
4953 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_len, tvb, offset, 2, hdr.frag_len);
4957 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_frag_num, tvb, offset, 2, hdr.frag_num);
4958 if (check_col (pinfo->cinfo, COL_INFO)) {
4959 if (hdr.flags1 & PFCL1_FRAG) {
4960 /* Fragmented - put the fragment number into the Info column */
4961 col_append_fstr (pinfo->cinfo, COL_INFO, " frag: %u",
4968 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_auth_proto, tvb, offset, 1, hdr.auth_proto);
4972 proto_tree_add_uint (dcerpc_tree, hf_dcerpc_dg_serial_lo, tvb, offset, 1, hdr.serial_lo);
4973 if (check_col (pinfo->cinfo, COL_INFO)) {
4974 if (hdr.flags1 & PFCL1_FRAG) {
4975 /* Fragmented - put the serial number into the Info column */
4976 col_append_fstr (pinfo->cinfo, COL_INFO, " serial: %u",
4977 (hdr.serial_hi << 8) | hdr.serial_lo);
4984 * XXX - for Kerberos, we get a protection level; if it's
4985 * DCE_C_AUTHN_LEVEL_PKT_PRIVACY, we can't dissect the
4988 dissect_dcerpc_dg_auth (tvb, offset, dcerpc_tree, &hdr,
4993 * keeping track of the conversation shouldn't really be necessary
4994 * for connectionless packets, because everything we need to know
4995 * to dissect is in the header for each packet. Unfortunately,
4996 * Microsoft's implementation is buggy and often puts the
4997 * completely wrong if_id in the header. go figure. So, keep
4998 * track of the seqnum and use that if possible. Note: that's not
4999 * completely correct. It should really be done based on both the
5000 * activity_id and seqnum. I haven't seen anywhere that it would
5001 * make a difference, but for future reference...
5003 conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
5004 pinfo->srcport, pinfo->destport, 0);
5006 fprintf(stderr,"Creating a new conv on packet %d\n",pinfo->fd->num);
5007 conv = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
5008 pinfo->srcport, pinfo->destport, 0);
5012 * Packet type specific stuff is next.
5015 switch (hdr.ptype) {
5017 case PDU_CANCEL_ACK:
5018 /* Body is optional */
5019 /* XXX - we assume "frag_len" is the length of the body */
5020 if (hdr.frag_len != 0)
5021 dissect_dcerpc_dg_cancel_ack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5026 * XXX - The DCE RPC 1.1 spec doesn't say the body is optional,
5027 * but in at least one capture none of the Cl_cancel PDUs had a
5030 /* XXX - we assume "frag_len" is the length of the body */
5031 if (hdr.frag_len != 0)
5032 dissect_dcerpc_dg_cancel (tvb, offset, pinfo, dcerpc_tree, &hdr);
5036 /* Body is optional; if present, it's the same as PDU_FACK */
5037 /* XXX - we assume "frag_len" is the length of the body */
5038 if (hdr.frag_len != 0)
5039 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5043 /* Body is optional */
5044 /* XXX - we assume "frag_len" is the length of the body */
5045 if (hdr.frag_len != 0)
5046 dissect_dcerpc_dg_fack (tvb, offset, pinfo, dcerpc_tree, &hdr);
5051 dissect_dcerpc_dg_reject_fault (tvb, offset, pinfo, dcerpc_tree, &hdr);
5055 dissect_dcerpc_dg_rqst (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5059 dissect_dcerpc_dg_resp (tvb, offset, pinfo, dcerpc_tree, tree, &hdr, conv);
5062 /* these requests have no body */
5065 dissect_dcerpc_dg_ping_ack (tvb, offset, pinfo, dcerpc_tree, &hdr, conv);
5076 dcerpc_init_protocol (void)
5078 /* structures and data for BIND */
5080 g_hash_table_destroy (dcerpc_binds);
5084 dcerpc_binds = g_hash_table_new (dcerpc_bind_hash, dcerpc_bind_equal);
5087 /* structures and data for CALL */
5088 if (dcerpc_cn_calls){
5089 g_hash_table_destroy (dcerpc_cn_calls);
5091 dcerpc_cn_calls = g_hash_table_new (dcerpc_cn_call_hash, dcerpc_cn_call_equal);
5092 if (dcerpc_dg_calls){
5093 g_hash_table_destroy (dcerpc_dg_calls);
5095 dcerpc_dg_calls = g_hash_table_new (dcerpc_dg_call_hash, dcerpc_dg_call_equal);
5097 /* structure and data for MATCHED */
5098 if (dcerpc_matched){
5099 g_hash_table_destroy (dcerpc_matched);
5101 dcerpc_matched = g_hash_table_new (dcerpc_matched_hash, dcerpc_matched_equal);
5103 /* call the registered hooks */
5104 g_hook_list_invoke(&dcerpc_hooks_init_protos, FALSE /* not may_recurse */);
5108 proto_register_dcerpc (void)
5110 static hf_register_info hf[] = {
5111 { &hf_dcerpc_request_in,
5112 { "Request in frame", "dcerpc.request_in", FT_FRAMENUM, BASE_NONE,
5113 NULL, 0, "This packet is a response to the packet with this number", HFILL }},
5114 { &hf_dcerpc_response_in,
5115 { "Response in frame", "dcerpc.response_in", FT_FRAMENUM, BASE_NONE,
5116 NULL, 0, "This packet will be responded in the packet with this number", HFILL }},
5117 { &hf_dcerpc_referent_id,
5118 { "Referent ID", "dcerpc.referent_id", FT_UINT32, BASE_HEX,
5119 NULL, 0, "Referent ID for this NDR encoded pointer", HFILL }},
5121 { "Version", "dcerpc.ver", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5122 { &hf_dcerpc_ver_minor,
5123 { "Version (minor)", "dcerpc.ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5124 { &hf_dcerpc_packet_type,
5125 { "Packet type", "dcerpc.pkt_type", FT_UINT8, BASE_DEC, VALS (pckt_vals), 0x0, NULL, HFILL }},
5126 { &hf_dcerpc_cn_flags,
5127 { "Packet Flags", "dcerpc.cn_flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5128 { &hf_dcerpc_cn_flags_first_frag,
5129 { "First Frag", "dcerpc.cn_flags.first_frag", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_FIRST_FRAG, NULL, HFILL }},
5130 { &hf_dcerpc_cn_flags_last_frag,
5131 { "Last Frag", "dcerpc.cn_flags.last_frag", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_LAST_FRAG, NULL, HFILL }},
5132 { &hf_dcerpc_cn_flags_cancel_pending,
5133 { "Cancel Pending", "dcerpc.cn_flags.cancel_pending", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_PENDING_CANCEL, NULL, HFILL }},
5134 { &hf_dcerpc_cn_flags_reserved,
5135 { "Reserved", "dcerpc.cn_flags.reserved", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_RESERVED_1, NULL, HFILL }},
5136 { &hf_dcerpc_cn_flags_mpx,
5137 { "Multiplex", "dcerpc.cn_flags.mpx", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_CONC_MPX, NULL, HFILL }},
5138 { &hf_dcerpc_cn_flags_dne,
5139 { "Did Not Execute", "dcerpc.cn_flags.dne", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_DID_NOT_EXECUTE, NULL, HFILL }},
5140 { &hf_dcerpc_cn_flags_maybe,
5141 { "Maybe", "dcerpc.cn_flags.maybe", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_MAYBE, NULL, HFILL }},
5142 { &hf_dcerpc_cn_flags_object,
5143 { "Object", "dcerpc.cn_flags.object", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFC_OBJECT_UUID, NULL, HFILL }},
5145 { "Data Representation", "dcerpc.drep", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5146 { &hf_dcerpc_drep_byteorder,
5147 { "Byte order", "dcerpc.drep.byteorder", FT_UINT8, BASE_DEC, VALS (drep_byteorder_vals), 0x0, NULL, HFILL }},
5148 { &hf_dcerpc_drep_character,
5149 { "Character", "dcerpc.drep.character", FT_UINT8, BASE_DEC, VALS (drep_character_vals), 0x0, NULL, HFILL }},
5150 { &hf_dcerpc_drep_fp,
5151 { "Floating-point", "dcerpc.drep.fp", FT_UINT8, BASE_DEC, VALS (drep_fp_vals), 0x0, NULL, HFILL }},
5152 { &hf_dcerpc_cn_frag_len,
5153 { "Frag Length", "dcerpc.cn_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5154 { &hf_dcerpc_cn_auth_len,
5155 { "Auth Length", "dcerpc.cn_auth_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5156 { &hf_dcerpc_cn_call_id,
5157 { "Call ID", "dcerpc.cn_call_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5158 { &hf_dcerpc_cn_max_xmit,
5159 { "Max Xmit Frag", "dcerpc.cn_max_xmit", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5160 { &hf_dcerpc_cn_max_recv,
5161 { "Max Recv Frag", "dcerpc.cn_max_recv", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5162 { &hf_dcerpc_cn_assoc_group,
5163 { "Assoc Group", "dcerpc.cn_assoc_group", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5164 { &hf_dcerpc_cn_num_ctx_items,
5165 { "Num Ctx Items", "dcerpc.cn_num_ctx_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5166 { &hf_dcerpc_cn_ctx_item,
5167 { "Ctx Item", "dcerpc.cn_ctx_item", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5168 { &hf_dcerpc_cn_ctx_id,
5169 { "Context ID", "dcerpc.cn_ctx_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5170 { &hf_dcerpc_cn_num_trans_items,
5171 { "Num Trans Items", "dcerpc.cn_num_trans_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5172 { &hf_dcerpc_cn_bind_abstract_syntax,
5173 { "Abstract Syntax", "dcerpc.cn_bind_abstract_syntax", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5174 { &hf_dcerpc_cn_bind_if_id,
5175 { "Interface UUID", "dcerpc.cn_bind_to_uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5176 { &hf_dcerpc_cn_bind_if_ver,
5177 { "Interface Ver", "dcerpc.cn_bind_if_ver", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5178 { &hf_dcerpc_cn_bind_if_ver_minor,
5179 { "Interface Ver Minor", "dcerpc.cn_bind_if_ver_minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5180 { &hf_dcerpc_cn_bind_trans_syntax,
5181 { "Transfer Syntax", "dcerpc.cn_bind_trans", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5182 { &hf_dcerpc_cn_bind_trans_id,
5183 { "ID", "dcerpc.cn_bind_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5184 { &hf_dcerpc_cn_bind_trans_ver,
5185 { "ver", "dcerpc.cn_bind_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5186 { &hf_dcerpc_cn_alloc_hint,
5187 { "Alloc hint", "dcerpc.cn_alloc_hint", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5188 { &hf_dcerpc_cn_sec_addr_len,
5189 { "Scndry Addr len", "dcerpc.cn_sec_addr_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5190 { &hf_dcerpc_cn_sec_addr,
5191 { "Scndry Addr", "dcerpc.cn_sec_addr", FT_STRINGZ, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5192 { &hf_dcerpc_cn_num_results,
5193 { "Num results", "dcerpc.cn_num_results", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5194 { &hf_dcerpc_cn_ack_result,
5195 { "Ack result", "dcerpc.cn_ack_result", FT_UINT16, BASE_DEC, VALS(p_cont_result_vals), 0x0, NULL, HFILL }},
5196 { &hf_dcerpc_cn_ack_reason,
5197 { "Ack reason", "dcerpc.cn_ack_reason", FT_UINT16, BASE_DEC, VALS(p_provider_reason_vals), 0x0, NULL, HFILL }},
5198 { &hf_dcerpc_cn_ack_trans_id,
5199 { "Transfer Syntax", "dcerpc.cn_ack_trans_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5200 { &hf_dcerpc_cn_ack_trans_ver,
5201 { "Syntax ver", "dcerpc.cn_ack_trans_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5202 { &hf_dcerpc_cn_reject_reason,
5203 { "Reject reason", "dcerpc.cn_reject_reason", FT_UINT16, BASE_DEC, VALS(reject_reason_vals), 0x0, NULL, HFILL }},
5204 { &hf_dcerpc_cn_num_protocols,
5205 { "Number of protocols", "dcerpc.cn_num_protocols", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5206 { &hf_dcerpc_cn_protocol_ver_major,
5207 { "Protocol major version", "dcerpc.cn_protocol_ver_major", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5208 { &hf_dcerpc_cn_protocol_ver_minor,
5209 { "Protocol minor version", "dcerpc.cn_protocol_ver_minor", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5210 { &hf_dcerpc_cn_cancel_count,
5211 { "Cancel count", "dcerpc.cn_cancel_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5212 { &hf_dcerpc_cn_status,
5213 { "Status", "dcerpc.cn_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
5214 { &hf_dcerpc_cn_deseg_req,
5215 { "Desegmentation Required", "dcerpc.cn_deseg_req", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5216 { &hf_dcerpc_auth_type,
5217 { "Auth type", "dcerpc.auth_type", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, NULL, HFILL }},
5218 { &hf_dcerpc_auth_level,
5219 { "Auth level", "dcerpc.auth_level", FT_UINT8, BASE_DEC, VALS (authn_level_vals), 0x0, NULL, HFILL }},
5220 { &hf_dcerpc_auth_pad_len,
5221 { "Auth pad len", "dcerpc.auth_pad_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5222 { &hf_dcerpc_auth_rsrvd,
5223 { "Auth Rsrvd", "dcerpc.auth_rsrvd", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5224 { &hf_dcerpc_auth_ctx_id,
5225 { "Auth Context ID", "dcerpc.auth_ctx_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5226 { &hf_dcerpc_dg_flags1,
5227 { "Flags1", "dcerpc.dg_flags1", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5228 { &hf_dcerpc_dg_flags1_rsrvd_01,
5229 { "Reserved", "dcerpc.dg_flags1_rsrvd_01", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_RESERVED_01, NULL, HFILL }},
5230 { &hf_dcerpc_dg_flags1_last_frag,
5231 { "Last Fragment", "dcerpc.dg_flags1_last_frag", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_LASTFRAG, NULL, HFILL }},
5232 { &hf_dcerpc_dg_flags1_frag,
5233 { "Fragment", "dcerpc.dg_flags1_frag", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_FRAG, NULL, HFILL }},
5234 { &hf_dcerpc_dg_flags1_nofack,
5235 { "No Fack", "dcerpc.dg_flags1_nofack", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_NOFACK, NULL, HFILL }},
5236 { &hf_dcerpc_dg_flags1_maybe,
5237 { "Maybe", "dcerpc.dg_flags1_maybe", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_MAYBE, NULL, HFILL }},
5238 { &hf_dcerpc_dg_flags1_idempotent,
5239 { "Idempotent", "dcerpc.dg_flags1_idempotent", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_IDEMPOTENT, NULL, HFILL }},
5240 { &hf_dcerpc_dg_flags1_broadcast,
5241 { "Broadcast", "dcerpc.dg_flags1_broadcast", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_BROADCAST, NULL, HFILL }},
5242 { &hf_dcerpc_dg_flags1_rsrvd_80,
5243 { "Reserved", "dcerpc.dg_flags1_rsrvd_80", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL1_RESERVED_80, NULL, HFILL }},
5244 { &hf_dcerpc_dg_flags2,
5245 { "Flags2", "dcerpc.dg_flags2", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5246 { &hf_dcerpc_dg_flags2_rsrvd_01,
5247 { "Reserved", "dcerpc.dg_flags2_rsrvd_01", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_01, NULL, HFILL }},
5248 { &hf_dcerpc_dg_flags2_cancel_pending,
5249 { "Cancel Pending", "dcerpc.dg_flags2_cancel_pending", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_CANCEL_PENDING, NULL, HFILL }},
5250 { &hf_dcerpc_dg_flags2_rsrvd_04,
5251 { "Reserved", "dcerpc.dg_flags2_rsrvd_04", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_04, NULL, HFILL }},
5252 { &hf_dcerpc_dg_flags2_rsrvd_08,
5253 { "Reserved", "dcerpc.dg_flags2_rsrvd_08", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_08, NULL, HFILL }},
5254 { &hf_dcerpc_dg_flags2_rsrvd_10,
5255 { "Reserved", "dcerpc.dg_flags2_rsrvd_10", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_10, NULL, HFILL }},
5256 { &hf_dcerpc_dg_flags2_rsrvd_20,
5257 { "Reserved", "dcerpc.dg_flags2_rsrvd_20", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_20, NULL, HFILL }},
5258 { &hf_dcerpc_dg_flags2_rsrvd_40,
5259 { "Reserved", "dcerpc.dg_flags2_rsrvd_40", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_40, NULL, HFILL }},
5260 { &hf_dcerpc_dg_flags2_rsrvd_80,
5261 { "Reserved", "dcerpc.dg_flags2_rsrvd_80", FT_BOOLEAN, 8, TFS (&tfs_set_notset), PFCL2_RESERVED_80, NULL, HFILL }},
5262 { &hf_dcerpc_dg_serial_lo,
5263 { "Serial Low", "dcerpc.dg_serial_lo", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5264 { &hf_dcerpc_dg_serial_hi,
5265 { "Serial High", "dcerpc.dg_serial_hi", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5266 { &hf_dcerpc_dg_ahint,
5267 { "Activity Hint", "dcerpc.dg_ahint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5268 { &hf_dcerpc_dg_ihint,
5269 { "Interface Hint", "dcerpc.dg_ihint", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5270 { &hf_dcerpc_dg_frag_len,
5271 { "Fragment len", "dcerpc.dg_frag_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5272 { &hf_dcerpc_dg_frag_num,
5273 { "Fragment num", "dcerpc.dg_frag_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5274 { &hf_dcerpc_dg_auth_proto,
5275 { "Auth proto", "dcerpc.dg_auth_proto", FT_UINT8, BASE_DEC, VALS (authn_protocol_vals), 0x0, NULL, HFILL }},
5276 { &hf_dcerpc_dg_seqnum,
5277 { "Sequence num", "dcerpc.dg_seqnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5278 { &hf_dcerpc_dg_server_boot,
5279 { "Server boot time", "dcerpc.dg_server_boot", FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5280 { &hf_dcerpc_dg_if_ver,
5281 { "Interface Ver", "dcerpc.dg_if_ver", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5282 { &hf_dcerpc_krb5_av_prot_level,
5283 { "Protection Level", "dcerpc.krb5_av.prot_level", FT_UINT8, BASE_DEC, VALS(authn_level_vals), 0x0, NULL, HFILL }},
5284 { &hf_dcerpc_krb5_av_key_vers_num,
5285 { "Key Version Number", "dcerpc.krb5_av.key_vers_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5286 { &hf_dcerpc_krb5_av_key_auth_verifier,
5287 { "Authentication Verifier", "dcerpc.krb5_av.auth_verifier", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5288 { &hf_dcerpc_obj_id,
5289 { "Object", "dcerpc.obj_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5290 { &hf_dcerpc_dg_if_id,
5291 { "Interface", "dcerpc.dg_if_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5292 { &hf_dcerpc_dg_act_id,
5293 { "Activity", "dcerpc.dg_act_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5295 { "Opnum", "dcerpc.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5297 { &hf_dcerpc_dg_cancel_vers,
5298 { "Cancel Version", "dcerpc.dg_cancel_vers", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5300 { &hf_dcerpc_dg_cancel_id,
5301 { "Cancel ID", "dcerpc.dg_cancel_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5303 { &hf_dcerpc_dg_server_accepting_cancels,
5304 { "Server accepting cancels", "dcerpc.server_accepting_cancels", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5306 { &hf_dcerpc_dg_fack_vers,
5307 { "FACK Version", "dcerpc.fack_vers", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5309 { &hf_dcerpc_dg_fack_window_size,
5310 { "Window Size", "dcerpc.fack_window_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5312 { &hf_dcerpc_dg_fack_max_tsdu,
5313 { "Max TSDU", "dcerpc.fack_max_tsdu", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5315 { &hf_dcerpc_dg_fack_max_frag_size,
5316 { "Max Frag Size", "dcerpc.fack_max_frag_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5318 { &hf_dcerpc_dg_fack_serial_num,
5319 { "Serial Num", "dcerpc.fack_serial_num", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5321 { &hf_dcerpc_dg_fack_selack_len,
5322 { "Selective ACK Len", "dcerpc.fack_selack_len", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5324 { &hf_dcerpc_dg_fack_selack,
5325 { "Selective ACK", "dcerpc.fack_selack", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
5327 { &hf_dcerpc_dg_status,
5328 { "Status", "dcerpc.dg_status", FT_UINT32, BASE_HEX, VALS(reject_status_vals), 0x0, NULL, HFILL }},
5330 { &hf_dcerpc_array_max_count,
5331 { "Max Count", "dcerpc.array.max_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum Count: Number of elements in the array", HFILL }},
5333 { &hf_dcerpc_array_offset,
5334 { "Offset", "dcerpc.array.offset", FT_UINT32, BASE_DEC, NULL, 0x0, "Offset for first element in array", HFILL }},
5336 { &hf_dcerpc_array_actual_count,
5337 { "Actual Count", "dcerpc.array.actual_count", FT_UINT32, BASE_DEC, NULL, 0x0, "Actual Count: Actual number of elements in the array", HFILL }},
5339 { &hf_dcerpc_array_buffer,
5340 { "Buffer", "dcerpc.array.buffer", FT_BYTES, BASE_NONE, NULL, 0x0, "Buffer: Buffer containing elements of the array", HFILL }},
5343 { "Operation", "dcerpc.op", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
5345 { &hf_dcerpc_fragments,
5346 { "Reassembled DCE/RPC Fragments", "dcerpc.fragments", FT_NONE, BASE_NONE,
5347 NULL, 0x0, "DCE/RPC Fragments", HFILL }},
5349 { &hf_dcerpc_fragment,
5350 { "DCE/RPC Fragment", "dcerpc.fragment", FT_FRAMENUM, BASE_NONE,
5351 NULL, 0x0, NULL, HFILL }},
5353 { &hf_dcerpc_fragment_overlap,
5354 { "Fragment overlap", "dcerpc.fragment.overlap", FT_BOOLEAN, BASE_NONE,
5355 NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
5357 { &hf_dcerpc_fragment_overlap_conflict,
5358 { "Conflicting data in fragment overlap", "dcerpc.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE,
5359 NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL }},
5361 { &hf_dcerpc_fragment_multiple_tails,
5362 { "Multiple tail fragments found", "dcerpc.fragment.multipletails", FT_BOOLEAN, BASE_NONE,
5363 NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL }},
5365 { &hf_dcerpc_fragment_too_long_fragment,
5366 { "Fragment too long", "dcerpc.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE,
5367 NULL, 0x0, "Fragment contained data past end of packet", HFILL }},
5369 { &hf_dcerpc_fragment_error,
5370 { "Defragmentation error", "dcerpc.fragment.error", FT_FRAMENUM, BASE_NONE,
5371 NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
5374 { "Time from request", "dcerpc.time", FT_RELATIVE_TIME, BASE_NONE,
5375 NULL, 0, "Time between Request and Response for DCE-RPC calls", HFILL }},
5377 { &hf_dcerpc_reassembled_in,
5378 { "Reassembled PDU in frame", "dcerpc.reassembled_in", FT_FRAMENUM, BASE_NONE,
5379 NULL, 0x0, "The DCE/RPC PDU is completely reassembled in the packet with this number", HFILL }},
5381 { &hf_dcerpc_unknown_if_id,
5382 { "Unknown DCERPC interface id", "dcerpc.unknown_if_id", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
5384 static gint *ett[] = {
5386 &ett_dcerpc_cn_flags,
5388 &ett_dcerpc_cn_iface,
5389 &ett_dcerpc_cn_trans_syntax,
5391 &ett_dcerpc_dg_flags1,
5392 &ett_dcerpc_dg_flags2,
5393 &ett_dcerpc_pointer_data,
5395 &ett_dcerpc_fragments,
5396 &ett_dcerpc_fragment,
5397 &ett_dcerpc_krb5_auth_verf,
5399 module_t *dcerpc_module;
5401 proto_dcerpc = proto_register_protocol ("DCE RPC", "DCERPC", "dcerpc");
5402 proto_register_field_array (proto_dcerpc, hf, array_length (hf));
5403 proto_register_subtree_array (ett, array_length (ett));
5404 register_init_routine (dcerpc_init_protocol);
5405 dcerpc_module = prefs_register_protocol (proto_dcerpc, NULL);
5406 prefs_register_bool_preference (dcerpc_module,
5408 "Reassemble DCE/RPC messages spanning multiple TCP segments",
5409 "Whether the DCE/RPC dissector should reassemble messages spanning multiple TCP segments."
5410 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
5411 &dcerpc_cn_desegment);
5412 prefs_register_bool_preference (dcerpc_module,
5413 "reassemble_dcerpc",
5414 "Reassemble DCE/RPC fragments",
5415 "Whether the DCE/RPC dissector should reassemble fragmented DCE/RPC PDUs",
5416 &dcerpc_reassemble);
5417 register_init_routine(dcerpc_reassemble_init);
5418 dcerpc_uuids = g_hash_table_new (dcerpc_uuid_hash, dcerpc_uuid_equal);
5419 dcerpc_tap=register_tap("dcerpc");
5421 g_hook_list_init(&dcerpc_hooks_init_protos, sizeof(GHook));
5425 proto_reg_handoff_dcerpc (void)
5427 heur_dissector_add ("tcp", dissect_dcerpc_cn_bs, proto_dcerpc);
5428 heur_dissector_add ("netbios", dissect_dcerpc_cn_pk, proto_dcerpc);
5429 heur_dissector_add ("udp", dissect_dcerpc_dg, proto_dcerpc);
5430 heur_dissector_add ("smb_transact", dissect_dcerpc_cn_smbpipe, proto_dcerpc);
5431 heur_dissector_add ("smb2_heur_subdissectors", dissect_dcerpc_cn_smb2, proto_dcerpc);
5432 heur_dissector_add ("http", dissect_dcerpc_cn_bs, proto_dcerpc);
5433 dcerpc_smb_init(proto_dcerpc);